misc: BaseCPU using ArchMMU instead of ArchDTB/ArchITB
[gem5.git] / src / cpu / checker / cpu.hh
1 /*
2 * Copyright (c) 2011, 2016-2018, 2020 ARM Limited
3 * Copyright (c) 2013 Advanced Micro Devices, Inc.
4 * All rights reserved
5 *
6 * The license below extends only to copyright in the software and shall
7 * not be construed as granting a license to any other intellectual
8 * property including but not limited to intellectual property relating
9 * to a hardware implementation of the functionality of the software
10 * licensed hereunder. You may use the software subject to the license
11 * terms below provided that you ensure that this notice is replicated
12 * unmodified and in its entirety in all distributions of the software,
13 * modified or unmodified, in source code or in binary form.
14 *
15 * Copyright (c) 2006 The Regents of The University of Michigan
16 * All rights reserved.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions are
20 * met: redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer;
22 * redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution;
25 * neither the name of the copyright holders nor the names of its
26 * contributors may be used to endorse or promote products derived from
27 * this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 */
41
42 #ifndef __CPU_CHECKER_CPU_HH__
43 #define __CPU_CHECKER_CPU_HH__
44
45 #include <list>
46 #include <map>
47 #include <queue>
48
49 #include "arch/types.hh"
50 #include "base/statistics.hh"
51 #include "cpu/base.hh"
52 #include "cpu/base_dyn_inst.hh"
53 #include "cpu/exec_context.hh"
54 #include "cpu/inst_res.hh"
55 #include "cpu/pc_event.hh"
56 #include "cpu/simple_thread.hh"
57 #include "cpu/static_inst.hh"
58 #include "debug/Checker.hh"
59 #include "mem/request.hh"
60 #include "params/CheckerCPU.hh"
61 #include "sim/eventq.hh"
62
63 class BaseTLB;
64 template <class>
65 class BaseDynInst;
66 class ThreadContext;
67 class Request;
68
69 /**
70 * CheckerCPU class. Dynamically verifies instructions as they are
71 * completed by making sure that the instruction and its results match
72 * the independent execution of the benchmark inside the checker. The
73 * checker verifies instructions in order, regardless of the order in
74 * which instructions complete. There are certain results that can
75 * not be verified, specifically the result of a store conditional or
76 * the values of uncached accesses. In these cases, and with
77 * instructions marked as "IsUnverifiable", the checker assumes that
78 * the value from the main CPU's execution is correct and simply
79 * copies that value. It provides a CheckerThreadContext (see
80 * checker/thread_context.hh) that provides hooks for updating the
81 * Checker's state through any ThreadContext accesses. This allows the
82 * checker to be able to correctly verify instructions, even with
83 * external accesses to the ThreadContext that change state.
84 */
85 class CheckerCPU : public BaseCPU, public ExecContext
86 {
87 protected:
88 typedef TheISA::MachInst MachInst;
89 using VecRegContainer = TheISA::VecRegContainer;
90
91 /** id attached to all issued requests */
92 RequestorID requestorId;
93 public:
94 void init() override;
95
96 typedef CheckerCPUParams Params;
97 CheckerCPU(const Params &p);
98 virtual ~CheckerCPU();
99
100 void setSystem(System *system);
101
102 void setIcachePort(RequestPort *icache_port);
103
104 void setDcachePort(RequestPort *dcache_port);
105
106 Port &
107 getDataPort() override
108 {
109 // the checker does not have ports on its own so return the
110 // data port of the actual CPU core
111 assert(dcachePort);
112 return *dcachePort;
113 }
114
115 Port &
116 getInstPort() override
117 {
118 // the checker does not have ports on its own so return the
119 // data port of the actual CPU core
120 assert(icachePort);
121 return *icachePort;
122 }
123
124 protected:
125
126 std::vector<Process*> workload;
127
128 System *systemPtr;
129
130 RequestPort *icachePort;
131 RequestPort *dcachePort;
132
133 ThreadContext *tc;
134
135 BaseMMU *mmu;
136
137 // ISAs like ARM can have multiple destination registers to check,
138 // keep them all in a std::queue
139 std::queue<InstResult> result;
140
141 StaticInstPtr curStaticInst;
142 StaticInstPtr curMacroStaticInst;
143
144 // number of simulated instructions
145 Counter numInst;
146 Counter startNumInst;
147
148 std::queue<int> miscRegIdxs;
149
150 public:
151
152 // Primary thread being run.
153 SimpleThread *thread;
154
155 BaseTLB* getITBPtr() { return mmu->itb; }
156 BaseTLB* getDTBPtr() { return mmu->dtb; }
157
158 BaseMMU* getMMUPtr() { return mmu; }
159
160 virtual Counter totalInsts() const override
161 {
162 return 0;
163 }
164
165 virtual Counter totalOps() const override
166 {
167 return 0;
168 }
169
170 // number of simulated loads
171 Counter numLoad;
172 Counter startNumLoad;
173
174 void serialize(CheckpointOut &cp) const override;
175 void unserialize(CheckpointIn &cp) override;
176
177 // The register accessor methods provide the index of the
178 // instruction's operand (e.g., 0 or 1), not the architectural
179 // register index, to simplify the implementation of register
180 // renaming. We find the architectural register index by indexing
181 // into the instruction's own operand index table. Note that a
182 // raw pointer to the StaticInst is provided instead of a
183 // ref-counted StaticInstPtr to redice overhead. This is fine as
184 // long as these methods don't copy the pointer into any long-term
185 // storage (which is pretty hard to imagine they would have reason
186 // to do).
187
188 RegVal
189 readIntRegOperand(const StaticInst *si, int idx) override
190 {
191 const RegId& reg = si->srcRegIdx(idx);
192 assert(reg.isIntReg());
193 return thread->readIntReg(reg.index());
194 }
195
196 RegVal
197 readFloatRegOperandBits(const StaticInst *si, int idx) override
198 {
199 const RegId& reg = si->srcRegIdx(idx);
200 assert(reg.isFloatReg());
201 return thread->readFloatReg(reg.index());
202 }
203
204 /**
205 * Read source vector register operand.
206 */
207 const VecRegContainer &
208 readVecRegOperand(const StaticInst *si, int idx) const override
209 {
210 const RegId& reg = si->srcRegIdx(idx);
211 assert(reg.isVecReg());
212 return thread->readVecReg(reg);
213 }
214
215 /**
216 * Read destination vector register operand for modification.
217 */
218 VecRegContainer &
219 getWritableVecRegOperand(const StaticInst *si, int idx) override
220 {
221 const RegId& reg = si->destRegIdx(idx);
222 assert(reg.isVecReg());
223 return thread->getWritableVecReg(reg);
224 }
225
226 /** Vector Register Lane Interfaces. */
227 /** @{ */
228 /** Reads source vector 8bit operand. */
229 virtual ConstVecLane8
230 readVec8BitLaneOperand(const StaticInst *si, int idx) const override
231 {
232 const RegId& reg = si->destRegIdx(idx);
233 assert(reg.isVecReg());
234 return thread->readVec8BitLaneReg(reg);
235 }
236
237 /** Reads source vector 16bit operand. */
238 virtual ConstVecLane16
239 readVec16BitLaneOperand(const StaticInst *si, int idx) const override
240 {
241 const RegId& reg = si->destRegIdx(idx);
242 assert(reg.isVecReg());
243 return thread->readVec16BitLaneReg(reg);
244 }
245
246 /** Reads source vector 32bit operand. */
247 virtual ConstVecLane32
248 readVec32BitLaneOperand(const StaticInst *si, int idx) const override
249 {
250 const RegId& reg = si->destRegIdx(idx);
251 assert(reg.isVecReg());
252 return thread->readVec32BitLaneReg(reg);
253 }
254
255 /** Reads source vector 64bit operand. */
256 virtual ConstVecLane64
257 readVec64BitLaneOperand(const StaticInst *si, int idx) const override
258 {
259 const RegId& reg = si->destRegIdx(idx);
260 assert(reg.isVecReg());
261 return thread->readVec64BitLaneReg(reg);
262 }
263
264 /** Write a lane of the destination vector operand. */
265 template <typename LD>
266 void
267 setVecLaneOperandT(const StaticInst *si, int idx, const LD& val)
268 {
269 const RegId& reg = si->destRegIdx(idx);
270 assert(reg.isVecReg());
271 return thread->setVecLane(reg, val);
272 }
273 virtual void
274 setVecLaneOperand(const StaticInst *si, int idx,
275 const LaneData<LaneSize::Byte>& val) override
276 {
277 setVecLaneOperandT(si, idx, val);
278 }
279 virtual void
280 setVecLaneOperand(const StaticInst *si, int idx,
281 const LaneData<LaneSize::TwoByte>& val) override
282 {
283 setVecLaneOperandT(si, idx, val);
284 }
285 virtual void
286 setVecLaneOperand(const StaticInst *si, int idx,
287 const LaneData<LaneSize::FourByte>& val) override
288 {
289 setVecLaneOperandT(si, idx, val);
290 }
291 virtual void
292 setVecLaneOperand(const StaticInst *si, int idx,
293 const LaneData<LaneSize::EightByte>& val) override
294 {
295 setVecLaneOperandT(si, idx, val);
296 }
297 /** @} */
298
299 VecElem
300 readVecElemOperand(const StaticInst *si, int idx) const override
301 {
302 const RegId& reg = si->srcRegIdx(idx);
303 return thread->readVecElem(reg);
304 }
305
306 const VecPredRegContainer&
307 readVecPredRegOperand(const StaticInst *si, int idx) const override
308 {
309 const RegId& reg = si->srcRegIdx(idx);
310 assert(reg.isVecPredReg());
311 return thread->readVecPredReg(reg);
312 }
313
314 VecPredRegContainer&
315 getWritableVecPredRegOperand(const StaticInst *si, int idx) override
316 {
317 const RegId& reg = si->destRegIdx(idx);
318 assert(reg.isVecPredReg());
319 return thread->getWritableVecPredReg(reg);
320 }
321
322 RegVal
323 readCCRegOperand(const StaticInst *si, int idx) override
324 {
325 const RegId& reg = si->srcRegIdx(idx);
326 assert(reg.isCCReg());
327 return thread->readCCReg(reg.index());
328 }
329
330 template<typename T>
331 void
332 setScalarResult(T&& t)
333 {
334 result.push(InstResult(std::forward<T>(t),
335 InstResult::ResultType::Scalar));
336 }
337
338 template<typename T>
339 void
340 setVecResult(T&& t)
341 {
342 result.push(InstResult(std::forward<T>(t),
343 InstResult::ResultType::VecReg));
344 }
345
346 template<typename T>
347 void
348 setVecElemResult(T&& t)
349 {
350 result.push(InstResult(std::forward<T>(t),
351 InstResult::ResultType::VecElem));
352 }
353
354 template<typename T>
355 void
356 setVecPredResult(T&& t)
357 {
358 result.push(InstResult(std::forward<T>(t),
359 InstResult::ResultType::VecPredReg));
360 }
361
362 void
363 setIntRegOperand(const StaticInst *si, int idx, RegVal val) override
364 {
365 const RegId& reg = si->destRegIdx(idx);
366 assert(reg.isIntReg());
367 thread->setIntReg(reg.index(), val);
368 setScalarResult(val);
369 }
370
371 void
372 setFloatRegOperandBits(const StaticInst *si, int idx, RegVal val) override
373 {
374 const RegId& reg = si->destRegIdx(idx);
375 assert(reg.isFloatReg());
376 thread->setFloatReg(reg.index(), val);
377 setScalarResult(val);
378 }
379
380 void
381 setCCRegOperand(const StaticInst *si, int idx, RegVal val) override
382 {
383 const RegId& reg = si->destRegIdx(idx);
384 assert(reg.isCCReg());
385 thread->setCCReg(reg.index(), val);
386 setScalarResult((uint64_t)val);
387 }
388
389 void
390 setVecRegOperand(const StaticInst *si, int idx,
391 const VecRegContainer& val) override
392 {
393 const RegId& reg = si->destRegIdx(idx);
394 assert(reg.isVecReg());
395 thread->setVecReg(reg, val);
396 setVecResult(val);
397 }
398
399 void
400 setVecElemOperand(const StaticInst *si, int idx,
401 const VecElem val) override
402 {
403 const RegId& reg = si->destRegIdx(idx);
404 assert(reg.isVecElem());
405 thread->setVecElem(reg, val);
406 setVecElemResult(val);
407 }
408
409 void setVecPredRegOperand(const StaticInst *si, int idx,
410 const VecPredRegContainer& val) override
411 {
412 const RegId& reg = si->destRegIdx(idx);
413 assert(reg.isVecPredReg());
414 thread->setVecPredReg(reg, val);
415 setVecPredResult(val);
416 }
417
418 bool readPredicate() const override { return thread->readPredicate(); }
419
420 void
421 setPredicate(bool val) override
422 {
423 thread->setPredicate(val);
424 }
425
426 bool
427 readMemAccPredicate() const override
428 {
429 return thread->readMemAccPredicate();
430 }
431
432 void
433 setMemAccPredicate(bool val) override
434 {
435 thread->setMemAccPredicate(val);
436 }
437
438 uint64_t
439 getHtmTransactionUid() const override
440 {
441 panic("not yet supported!");
442 return 0;
443 };
444
445 uint64_t
446 newHtmTransactionUid() const override
447 {
448 panic("not yet supported!");
449 return 0;
450 };
451
452 Fault
453 initiateHtmCmd(Request::Flags flags) override
454 {
455 panic("not yet supported!");
456 return NoFault;
457 }
458
459 bool
460 inHtmTransactionalState() const override
461 {
462 panic("not yet supported!");
463 return false;
464 }
465
466 uint64_t
467 getHtmTransactionalDepth() const override
468 {
469 panic("not yet supported!");
470 return 0;
471 }
472
473 TheISA::PCState pcState() const override { return thread->pcState(); }
474 void
475 pcState(const TheISA::PCState &val) override
476 {
477 DPRINTF(Checker, "Changing PC to %s, old PC %s.\n",
478 val, thread->pcState());
479 thread->pcState(val);
480 }
481 Addr instAddr() { return thread->instAddr(); }
482 Addr nextInstAddr() { return thread->nextInstAddr(); }
483 MicroPC microPC() { return thread->microPC(); }
484 //////////////////////////////////////////
485
486 RegVal
487 readMiscRegNoEffect(int misc_reg) const
488 {
489 return thread->readMiscRegNoEffect(misc_reg);
490 }
491
492 RegVal
493 readMiscReg(int misc_reg) override
494 {
495 return thread->readMiscReg(misc_reg);
496 }
497
498 void
499 setMiscRegNoEffect(int misc_reg, RegVal val)
500 {
501 DPRINTF(Checker, "Setting misc reg %d with no effect to check later\n",
502 misc_reg);
503 miscRegIdxs.push(misc_reg);
504 return thread->setMiscRegNoEffect(misc_reg, val);
505 }
506
507 void
508 setMiscReg(int misc_reg, RegVal val) override
509 {
510 DPRINTF(Checker, "Setting misc reg %d with effect to check later\n",
511 misc_reg);
512 miscRegIdxs.push(misc_reg);
513 return thread->setMiscReg(misc_reg, val);
514 }
515
516 RegVal
517 readMiscRegOperand(const StaticInst *si, int idx) override
518 {
519 const RegId& reg = si->srcRegIdx(idx);
520 assert(reg.isMiscReg());
521 return thread->readMiscReg(reg.index());
522 }
523
524 void
525 setMiscRegOperand(const StaticInst *si, int idx, RegVal val) override
526 {
527 const RegId& reg = si->destRegIdx(idx);
528 assert(reg.isMiscReg());
529 return this->setMiscReg(reg.index(), val);
530 }
531
532 /////////////////////////////////////////
533
534 void
535 recordPCChange(const TheISA::PCState &val)
536 {
537 changedPC = true;
538 newPCState = val;
539 }
540
541 void
542 demapPage(Addr vaddr, uint64_t asn) override
543 {
544 mmu->demapPage(vaddr, asn);
545 }
546
547 // monitor/mwait funtions
548 void armMonitor(Addr address) override { BaseCPU::armMonitor(0, address); }
549 bool mwait(PacketPtr pkt) override { return BaseCPU::mwait(0, pkt); }
550
551 void
552 mwaitAtomic(ThreadContext *tc) override
553 {
554 return BaseCPU::mwaitAtomic(0, tc, thread->mmu);
555 }
556
557 AddressMonitor *getAddrMonitor() override
558 { return BaseCPU::getCpuAddrMonitor(0); }
559
560 void
561 demapInstPage(Addr vaddr, uint64_t asn)
562 {
563 mmu->itb->demapPage(vaddr, asn);
564 }
565
566 void
567 demapDataPage(Addr vaddr, uint64_t asn)
568 {
569 mmu->dtb->demapPage(vaddr, asn);
570 }
571
572 /**
573 * Helper function used to generate the request for a single fragment of a
574 * memory access.
575 *
576 * Takes care of setting up the appropriate byte-enable mask for the
577 * fragment, given the mask for the entire memory access.
578 *
579 * @param frag_addr Start address of the fragment.
580 * @param size Total size of the memory access in bytes.
581 * @param flags Request flags.
582 * @param byte_enable Byte-enable mask for the entire memory access.
583 * @param[out] frag_size Fragment size.
584 * @param[in,out] size_left Size left to be processed in the memory access.
585 * @return Pointer to the allocated Request, nullptr if the byte-enable
586 * mask is all-false for the fragment.
587 */
588 RequestPtr genMemFragmentRequest(Addr frag_addr, int size,
589 Request::Flags flags,
590 const std::vector<bool>& byte_enable,
591 int& frag_size, int& size_left) const;
592
593 Fault readMem(Addr addr, uint8_t *data, unsigned size,
594 Request::Flags flags,
595 const std::vector<bool>& byte_enable)
596 override;
597
598 Fault writeMem(uint8_t *data, unsigned size, Addr addr,
599 Request::Flags flags, uint64_t *res,
600 const std::vector<bool>& byte_enable)
601 override;
602
603 Fault amoMem(Addr addr, uint8_t* data, unsigned size,
604 Request::Flags flags, AtomicOpFunctorPtr amo_op) override
605 {
606 panic("AMO is not supported yet in CPU checker\n");
607 }
608
609 unsigned int
610 readStCondFailures() const override {
611 return thread->readStCondFailures();
612 }
613
614 void setStCondFailures(unsigned int sc_failures) override {}
615 /////////////////////////////////////////////////////
616
617 void wakeup(ThreadID tid) override { }
618
619 void
620 handleError()
621 {
622 if (exitOnError)
623 dumpAndExit();
624 }
625
626 bool checkFlags(const RequestPtr &unverified_req, Addr vAddr,
627 Addr pAddr, int flags);
628
629 void dumpAndExit();
630
631 ThreadContext *tcBase() const override { return tc; }
632 SimpleThread *threadBase() { return thread; }
633
634 InstResult unverifiedResult;
635 RequestPtr unverifiedReq;
636 uint8_t *unverifiedMemData;
637
638 bool changedPC;
639 bool willChangePC;
640 TheISA::PCState newPCState;
641 bool exitOnError;
642 bool updateOnError;
643 bool warnOnlyOnLoadError;
644
645 InstSeqNum youngestSN;
646 };
647
648 /**
649 * Templated Checker class. This Checker class is templated on the
650 * DynInstPtr of the instruction type that will be verified. Proper
651 * template instantiations of the Checker must be placed at the bottom
652 * of checker/cpu.cc.
653 */
654 template <class Impl>
655 class Checker : public CheckerCPU
656 {
657 private:
658 typedef typename Impl::DynInstPtr DynInstPtr;
659
660 public:
661 Checker(const Params &p)
662 : CheckerCPU(p), updateThisCycle(false), unverifiedInst(NULL)
663 { }
664
665 void switchOut();
666 void takeOverFrom(BaseCPU *oldCPU);
667
668 void advancePC(const Fault &fault);
669
670 void verify(const DynInstPtr &inst);
671
672 void validateInst(const DynInstPtr &inst);
673 void validateExecution(const DynInstPtr &inst);
674 void validateState();
675
676 void copyResult(const DynInstPtr &inst, const InstResult& mismatch_val,
677 int start_idx);
678 void handlePendingInt();
679
680 private:
681 void handleError(const DynInstPtr &inst)
682 {
683 if (exitOnError) {
684 dumpAndExit(inst);
685 } else if (updateOnError) {
686 updateThisCycle = true;
687 }
688 }
689
690 void dumpAndExit(const DynInstPtr &inst);
691
692 bool updateThisCycle;
693
694 DynInstPtr unverifiedInst;
695
696 std::list<DynInstPtr> instList;
697 typedef typename std::list<DynInstPtr>::iterator InstListIt;
698 void dumpInsts();
699 };
700
701 #endif // __CPU_CHECKER_CPU_HH__