cpu.cc (2732:d2443ce353d2) cpu.cc (2734:af0d50755df7)
1/*
2 * Copyright (c) 2006 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Kevin Lim
29 */
30
31#include <list>
32#include <string>
33
34#include "base/refcnt.hh"
35#include "cpu/base.hh"
36#include "cpu/base_dyn_inst.hh"
37#include "cpu/checker/cpu.hh"
38#include "cpu/simple_thread.hh"
39#include "cpu/thread_context.hh"
40#include "cpu/static_inst.hh"
41#include "mem/packet_impl.hh"
42#include "sim/byteswap.hh"
43#include "sim/sim_object.hh"
44#include "sim/stats.hh"
45
46#include "cpu/o3/alpha_dyn_inst.hh"
47#include "cpu/o3/alpha_impl.hh"
48
49//#include "cpu/ozone/dyn_inst.hh"
50//#include "cpu/ozone/ozone_impl.hh"
51//#include "cpu/ozone/simple_impl.hh"
52
53#if FULL_SYSTEM
54#include "sim/system.hh"
55#include "arch/vtophys.hh"
56#endif // FULL_SYSTEM
57
58using namespace std;
59//The CheckerCPU does alpha only
60using namespace AlphaISA;
61
62void
63CheckerCPU::init()
64{
65}
66
67CheckerCPU::CheckerCPU(Params *p)
68 : BaseCPU(p), thread(NULL), tc(NULL)
69{
70 memReq = NULL;
71
72 numInst = 0;
73 startNumInst = 0;
74 numLoad = 0;
75 startNumLoad = 0;
76 youngestSN = 0;
77
78 changedPC = willChangePC = changedNextPC = false;
79
80 exitOnError = p->exitOnError;
81 warnOnlyOnLoadError = p->warnOnlyOnLoadError;
82#if FULL_SYSTEM
83 itb = p->itb;
84 dtb = p->dtb;
85 systemPtr = NULL;
86#else
87 process = p->process;
88#endif
89
90 result.integer = 0;
91}
92
93CheckerCPU::~CheckerCPU()
94{
95}
96
97void
98CheckerCPU::setMemory(MemObject *mem)
99{
100#if !FULL_SYSTEM
101 memPtr = mem;
102 thread = new SimpleThread(this, /* thread_num */ 0, process,
103 /* asid */ 0, mem);
104
105 thread->setStatus(ThreadContext::Suspended);
106 tc = thread->getTC();
107 threadContexts.push_back(tc);
108#endif
109}
110
111void
112CheckerCPU::setSystem(System *system)
113{
114#if FULL_SYSTEM
115 systemPtr = system;
116
117 thread = new SimpleThread(this, 0, systemPtr, itb, dtb, false);
118
119 thread->setStatus(ThreadContext::Suspended);
120 tc = thread->getTC();
121 threadContexts.push_back(tc);
122 delete thread->kernelStats;
123 thread->kernelStats = NULL;
124#endif
125}
126
127void
128CheckerCPU::setIcachePort(Port *icache_port)
129{
130 icachePort = icache_port;
131}
132
133void
134CheckerCPU::setDcachePort(Port *dcache_port)
135{
136 dcachePort = dcache_port;
137}
138
139void
140CheckerCPU::serialize(ostream &os)
141{
142/*
143 BaseCPU::serialize(os);
144 SERIALIZE_SCALAR(inst);
145 nameOut(os, csprintf("%s.xc", name()));
146 thread->serialize(os);
147 cacheCompletionEvent.serialize(os);
148*/
149}
150
151void
152CheckerCPU::unserialize(Checkpoint *cp, const string &section)
153{
154/*
155 BaseCPU::unserialize(cp, section);
156 UNSERIALIZE_SCALAR(inst);
157 thread->unserialize(cp, csprintf("%s.xc", section));
158*/
159}
160
161Fault
162CheckerCPU::copySrcTranslate(Addr src)
163{
164 panic("Unimplemented!");
165}
166
167Fault
168CheckerCPU::copy(Addr dest)
169{
170 panic("Unimplemented!");
171}
172
173template <class T>
174Fault
175CheckerCPU::read(Addr addr, T &data, unsigned flags)
176{
177 // need to fill in CPU & thread IDs here
178 memReq = new Request();
179
180 memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC());
181
182 // translate to physical address
183 translateDataReadReq(memReq);
184
185 Packet *pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast);
186
187 pkt->dataStatic(&data);
188
189 if (!(memReq->getFlags() & UNCACHEABLE)) {
190 // Access memory to see if we have the same data
191 dcachePort->sendFunctional(pkt);
192 } else {
193 // Assume the data is correct if it's an uncached access
194 memcpy(&data, &unverifiedResult.integer, sizeof(T));
195 }
196
197 delete pkt;
198
199 return NoFault;
200}
201
202#ifndef DOXYGEN_SHOULD_SKIP_THIS
203
204template
205Fault
206CheckerCPU::read(Addr addr, uint64_t &data, unsigned flags);
207
208template
209Fault
210CheckerCPU::read(Addr addr, uint32_t &data, unsigned flags);
211
212template
213Fault
214CheckerCPU::read(Addr addr, uint16_t &data, unsigned flags);
215
216template
217Fault
218CheckerCPU::read(Addr addr, uint8_t &data, unsigned flags);
219
220#endif //DOXYGEN_SHOULD_SKIP_THIS
221
222template<>
223Fault
224CheckerCPU::read(Addr addr, double &data, unsigned flags)
225{
226 return read(addr, *(uint64_t*)&data, flags);
227}
228
229template<>
230Fault
231CheckerCPU::read(Addr addr, float &data, unsigned flags)
232{
233 return read(addr, *(uint32_t*)&data, flags);
234}
235
236template<>
237Fault
238CheckerCPU::read(Addr addr, int32_t &data, unsigned flags)
239{
240 return read(addr, (uint32_t&)data, flags);
241}
242
243template <class T>
244Fault
245CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
246{
247 // need to fill in CPU & thread IDs here
248 memReq = new Request();
249
250 memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC());
251
252 // translate to physical address
253 thread->translateDataWriteReq(memReq);
254
255 // Can compare the write data and result only if it's cacheable,
256 // not a store conditional, or is a store conditional that
257 // succeeded.
258 // @todo: Verify that actual memory matches up with these values.
259 // Right now it only verifies that the instruction data is the
260 // same as what was in the request that got sent to memory; there
261 // is no verification that it is the same as what is in memory.
262 // This is because the LSQ would have to be snooped in the CPU to
263 // verify this data.
264 if (unverifiedReq &&
265 !(unverifiedReq->getFlags() & UNCACHEABLE) &&
266 (!(unverifiedReq->getFlags() & LOCKED) ||
267 ((unverifiedReq->getFlags() & LOCKED) &&
268 unverifiedReq->getScResult() == 1))) {
269 T inst_data;
270/*
271 // This code would work if the LSQ allowed for snooping.
272 Packet *pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast);
273 pkt.dataStatic(&inst_data);
274
275 dcachePort->sendFunctional(pkt);
276
277 delete pkt;
278*/
279 memcpy(&inst_data, unverifiedMemData, sizeof(T));
280
281 if (data != inst_data) {
282 warn("%lli: Store value does not match value in memory! "
283 "Instruction: %#x, memory: %#x",
284 curTick, inst_data, data);
285 handleError();
286 }
287 }
288
289 // Assume the result was the same as the one passed in. This checker
290 // doesn't check if the SC should succeed or fail, it just checks the
291 // value.
292 if (res && unverifiedReq->scResultValid())
293 *res = unverifiedReq->getScResult();
294
295 return NoFault;
296}
297
298
299#ifndef DOXYGEN_SHOULD_SKIP_THIS
300template
301Fault
302CheckerCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res);
303
304template
305Fault
306CheckerCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res);
307
308template
309Fault
310CheckerCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res);
311
312template
313Fault
314CheckerCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res);
315
316#endif //DOXYGEN_SHOULD_SKIP_THIS
317
318template<>
319Fault
320CheckerCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
321{
322 return write(*(uint64_t*)&data, addr, flags, res);
323}
324
325template<>
326Fault
327CheckerCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
328{
329 return write(*(uint32_t*)&data, addr, flags, res);
330}
331
332template<>
333Fault
334CheckerCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
335{
336 return write((uint32_t)data, addr, flags, res);
337}
338
339
340#if FULL_SYSTEM
341Addr
342CheckerCPU::dbg_vtophys(Addr addr)
343{
344 return vtophys(tc, addr);
345}
346#endif // FULL_SYSTEM
347
348bool
349CheckerCPU::translateInstReq(Request *req)
350{
351#if FULL_SYSTEM
352 return (thread->translateInstReq(req) == NoFault);
353#else
354 thread->translateInstReq(req);
355 return true;
356#endif
357}
358
359void
360CheckerCPU::translateDataReadReq(Request *req)
361{
362 thread->translateDataReadReq(req);
363
364 if (req->getVaddr() != unverifiedReq->getVaddr()) {
365 warn("%lli: Request virtual addresses do not match! Inst: %#x, "
366 "checker: %#x",
367 curTick, unverifiedReq->getVaddr(), req->getVaddr());
368 handleError();
369 }
370 req->setPaddr(unverifiedReq->getPaddr());
371
372 if (checkFlags(req)) {
373 warn("%lli: Request flags do not match! Inst: %#x, checker: %#x",
374 curTick, unverifiedReq->getFlags(), req->getFlags());
375 handleError();
376 }
377}
378
379void
380CheckerCPU::translateDataWriteReq(Request *req)
381{
382 thread->translateDataWriteReq(req);
383
384 if (req->getVaddr() != unverifiedReq->getVaddr()) {
385 warn("%lli: Request virtual addresses do not match! Inst: %#x, "
386 "checker: %#x",
387 curTick, unverifiedReq->getVaddr(), req->getVaddr());
388 handleError();
389 }
390 req->setPaddr(unverifiedReq->getPaddr());
391
392 if (checkFlags(req)) {
393 warn("%lli: Request flags do not match! Inst: %#x, checker: %#x",
394 curTick, unverifiedReq->getFlags(), req->getFlags());
395 handleError();
396 }
397}
398
399bool
400CheckerCPU::checkFlags(Request *req)
401{
402 // Remove any dynamic flags that don't have to do with the request itself.
403 unsigned flags = unverifiedReq->getFlags();
404 unsigned mask = LOCKED | PHYSICAL | VPTE | ALTMODE | UNCACHEABLE | NO_FAULT;
405 flags = flags & (mask);
406 if (flags == req->getFlags()) {
407 return false;
408 } else {
409 return true;
410 }
411}
412
413void
414CheckerCPU::dumpAndExit()
415{
416 warn("%lli: Checker PC:%#x, next PC:%#x",
417 curTick, thread->readPC(), thread->readNextPC());
418 panic("Checker found an error!");
419}
420
421template <class DynInstPtr>
422void
423Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
424{
425 DynInstPtr inst;
426
427 // Either check this instruction, or add it to a list of
428 // instructions waiting to be checked. Instructions must be
429 // checked in program order, so if a store has committed yet not
430 // completed, there may be some instructions that are waiting
431 // behind it that have completed and must be checked.
432 if (!instList.empty()) {
433 if (youngestSN < completed_inst->seqNum) {
434 DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n",
435 completed_inst->seqNum, completed_inst->readPC());
436 instList.push_back(completed_inst);
437 youngestSN = completed_inst->seqNum;
438 }
439
440 if (!instList.front()->isCompleted()) {
441 return;
442 } else {
443 inst = instList.front();
444 instList.pop_front();
445 }
446 } else {
447 if (!completed_inst->isCompleted()) {
448 if (youngestSN < completed_inst->seqNum) {
449 DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n",
450 completed_inst->seqNum, completed_inst->readPC());
451 instList.push_back(completed_inst);
452 youngestSN = completed_inst->seqNum;
453 }
454 return;
455 } else {
456 if (youngestSN < completed_inst->seqNum) {
457 inst = completed_inst;
458 youngestSN = completed_inst->seqNum;
459 } else {
460 return;
461 }
462 }
463 }
464
465 // Try to check all instructions that are completed, ending if we
466 // run out of instructions to check or if an instruction is not
467 // yet completed.
468 while (1) {
469 DPRINTF(Checker, "Processing instruction [sn:%lli] PC:%#x.\n",
470 inst->seqNum, inst->readPC());
471 unverifiedResult.integer = inst->readIntResult();
472 unverifiedReq = inst->req;
473 unverifiedMemData = inst->memData;
474 numCycles++;
475
476 Fault fault = NoFault;
477
478 // maintain $r0 semantics
479 thread->setIntReg(ZeroReg, 0);
480#ifdef TARGET_ALPHA
481 thread->setFloatRegDouble(ZeroReg, 0.0);
482#endif // TARGET_ALPHA
483
484 // Check if any recent PC changes match up with anything we
485 // expect to happen. This is mostly to check if traps or
486 // PC-based events have occurred in both the checker and CPU.
487 if (changedPC) {
488 DPRINTF(Checker, "Changed PC recently to %#x\n",
489 thread->readPC());
490 if (willChangePC) {
491 if (newPC == thread->readPC()) {
492 DPRINTF(Checker, "Changed PC matches expected PC\n");
493 } else {
494 warn("%lli: Changed PC does not match expected PC, "
495 "changed: %#x, expected: %#x",
496 curTick, thread->readPC(), newPC);
497 CheckerCPU::handleError();
498 }
499 willChangePC = false;
500 }
501 changedPC = false;
502 }
503 if (changedNextPC) {
504 DPRINTF(Checker, "Changed NextPC recently to %#x\n",
505 thread->readNextPC());
506 changedNextPC = false;
507 }
508
509 // Try to fetch the instruction
510
511#if FULL_SYSTEM
512#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0
513#else
514#define IFETCH_FLAGS(pc) 0
515#endif
516
517 uint64_t fetch_PC = thread->readPC() & ~3;
518
519 // set up memory request for instruction fetch
520 memReq = new Request(inst->threadNumber, fetch_PC,
521 sizeof(uint32_t),
522 IFETCH_FLAGS(thread->readPC()),
523 fetch_PC, thread->readCpuId(), inst->threadNumber);
524
525 bool succeeded = translateInstReq(memReq);
526
527 if (!succeeded) {
528 if (inst->getFault() == NoFault) {
529 // In this case the instruction was not a dummy
530 // instruction carrying an ITB fault. In the single
531 // threaded case the ITB should still be able to
532 // translate this instruction; in the SMT case it's
533 // possible that its ITB entry was kicked out.
534 warn("%lli: Instruction PC %#x was not found in the ITB!",
535 curTick, thread->readPC());
536 handleError(inst);
537
538 // go to the next instruction
539 thread->setPC(thread->readNextPC());
540 thread->setNextPC(thread->readNextPC() + sizeof(MachInst));
541
542 return;
543 } else {
544 // The instruction is carrying an ITB fault. Handle
545 // the fault and see if our results match the CPU on
546 // the next tick().
547 fault = inst->getFault();
548 }
549 }
550
551 if (fault == NoFault) {
552 Packet *pkt = new Packet(memReq, Packet::ReadReq,
553 Packet::Broadcast);
554
555 pkt->dataStatic(&machInst);
556
557 icachePort->sendFunctional(pkt);
558
559 delete pkt;
560
561 // keep an instruction count
562 numInst++;
563
564 // decode the instruction
565 machInst = gtoh(machInst);
566 // Checks that the instruction matches what we expected it to be.
567 // Checks both the machine instruction and the PC.
568 validateInst(inst);
569
570 curStaticInst = StaticInst::decode(makeExtMI(machInst,
571 thread->readPC()));
572
573#if FULL_SYSTEM
574 thread->setInst(machInst);
575#endif // FULL_SYSTEM
576
577 fault = inst->getFault();
578 }
579
580 // Discard fetch's memReq.
581 delete memReq;
582 memReq = NULL;
583
584 // Either the instruction was a fault and we should process the fault,
585 // or we should just go ahead execute the instruction. This assumes
586 // that the instruction is properly marked as a fault.
587 if (fault == NoFault) {
588
589 thread->funcExeInst++;
590
591 fault = curStaticInst->execute(this, NULL);
592
593 // Checks to make sure instrution results are correct.
594 validateExecution(inst);
595
596 if (curStaticInst->isLoad()) {
597 ++numLoad;
598 }
599 }
600
601 if (fault != NoFault) {
602#if FULL_SYSTEM
603 fault->invoke(tc);
604 willChangePC = true;
605 newPC = thread->readPC();
606 DPRINTF(Checker, "Fault, PC is now %#x\n", newPC);
607#else // !FULL_SYSTEM
608 fatal("fault (%d) detected @ PC 0x%08p", fault, thread->readPC());
609#endif // FULL_SYSTEM
610 } else {
611#if THE_ISA != MIPS_ISA
612 // go to the next instruction
613 thread->setPC(thread->readNextPC());
614 thread->setNextPC(thread->readNextPC() + sizeof(MachInst));
615#else
616 // go to the next instruction
617 thread->setPC(thread->readNextPC());
618 thread->setNextPC(thread->readNextNPC());
619 thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst));
620#endif
621
622 }
623
624#if FULL_SYSTEM
625 // @todo: Determine if these should happen only if the
626 // instruction hasn't faulted. In the SimpleCPU case this may
627 // not be true, but in the O3 or Ozone case this may be true.
628 Addr oldpc;
629 int count = 0;
630 do {
631 oldpc = thread->readPC();
632 system->pcEventQueue.service(tc);
633 count++;
634 } while (oldpc != thread->readPC());
635 if (count > 1) {
636 willChangePC = true;
637 newPC = thread->readPC();
638 DPRINTF(Checker, "PC Event, PC is now %#x\n", newPC);
639 }
640#endif
641
642 // @todo: Optionally can check all registers. (Or just those
643 // that have been modified).
644 validateState();
645
646 if (memReq) {
647 delete memReq;
648 memReq = NULL;
649 }
650
651 // Continue verifying instructions if there's another completed
652 // instruction waiting to be verified.
653 if (instList.empty()) {
654 break;
655 } else if (instList.front()->isCompleted()) {
656 inst = instList.front();
657 instList.pop_front();
658 } else {
659 break;
660 }
661 }
662}
663
664template <class DynInstPtr>
665void
666Checker<DynInstPtr>::switchOut(Sampler *s)
667{
668 instList.clear();
669}
670
671template <class DynInstPtr>
672void
673Checker<DynInstPtr>::takeOverFrom(BaseCPU *oldCPU)
674{
675}
676
677template <class DynInstPtr>
678void
679Checker<DynInstPtr>::validateInst(DynInstPtr &inst)
680{
681 if (inst->readPC() != thread->readPC()) {
682 warn("%lli: PCs do not match! Inst: %#x, checker: %#x",
683 curTick, inst->readPC(), thread->readPC());
684 if (changedPC) {
685 warn("%lli: Changed PCs recently, may not be an error",
686 curTick);
687 } else {
688 handleError(inst);
689 }
690 }
691
692 MachInst mi = static_cast<MachInst>(inst->staticInst->machInst);
693
694 if (mi != machInst) {
695 warn("%lli: Binary instructions do not match! Inst: %#x, "
696 "checker: %#x",
697 curTick, mi, machInst);
698 handleError(inst);
699 }
700}
701
702template <class DynInstPtr>
703void
704Checker<DynInstPtr>::validateExecution(DynInstPtr &inst)
705{
706 bool result_mismatch = false;
707 if (inst->numDestRegs()) {
708 // @todo: Support more destination registers.
709 if (inst->isUnverifiable()) {
710 // Unverifiable instructions assume they were executed
711 // properly by the CPU. Grab the result from the
712 // instruction and write it to the register.
713 copyResult(inst);
714 } else if (result.integer != inst->readIntResult()) {
715 result_mismatch = true;
716 }
717 }
718
719 if (result_mismatch) {
720 warn("%lli: Instruction results do not match! (Values may not "
721 "actually be integers) Inst: %#x, checker: %#x",
722 curTick, inst->readIntResult(), result.integer);
723
724 // It's useful to verify load values from memory, but in MP
725 // systems the value obtained at execute may be different than
726 // the value obtained at completion. Similarly DMA can
727 // present the same problem on even UP systems. Thus there is
728 // the option to only warn on loads having a result error.
729 if (inst->isLoad() && warnOnlyOnLoadError) {
730 copyResult(inst);
731 } else {
732 handleError(inst);
733 }
734 }
735
736 if (inst->readNextPC() != thread->readNextPC()) {
737 warn("%lli: Instruction next PCs do not match! Inst: %#x, "
738 "checker: %#x",
739 curTick, inst->readNextPC(), thread->readNextPC());
740 handleError(inst);
741 }
742
743 // Checking side effect registers can be difficult if they are not
744 // checked simultaneously with the execution of the instruction.
745 // This is because other valid instructions may have modified
746 // these registers in the meantime, and their values are not
747 // stored within the DynInst.
748 while (!miscRegIdxs.empty()) {
749 int misc_reg_idx = miscRegIdxs.front();
750 miscRegIdxs.pop();
751
752 if (inst->tcBase()->readMiscReg(misc_reg_idx) !=
753 thread->readMiscReg(misc_reg_idx)) {
754 warn("%lli: Misc reg idx %i (side effect) does not match! "
755 "Inst: %#x, checker: %#x",
756 curTick, misc_reg_idx,
757 inst->tcBase()->readMiscReg(misc_reg_idx),
758 thread->readMiscReg(misc_reg_idx));
759 handleError(inst);
760 }
761 }
762}
763
764template <class DynInstPtr>
765void
766Checker<DynInstPtr>::validateState()
767{
768}
769
770template <class DynInstPtr>
771void
772Checker<DynInstPtr>::copyResult(DynInstPtr &inst)
773{
774 RegIndex idx = inst->destRegIdx(0);
775 if (idx < TheISA::FP_Base_DepTag) {
776 thread->setIntReg(idx, inst->readIntResult());
777 } else if (idx < TheISA::Fpcr_DepTag) {
778 thread->setFloatRegBits(idx, inst->readIntResult());
779 } else {
780 thread->setMiscReg(idx, inst->readIntResult());
781 }
782}
783
784template <class DynInstPtr>
785void
786Checker<DynInstPtr>::dumpAndExit(DynInstPtr &inst)
787{
788 cprintf("Error detected, instruction information:\n");
789 cprintf("PC:%#x, nextPC:%#x\n[sn:%lli]\n[tid:%i]\n"
790 "Completed:%i\n",
791 inst->readPC(),
792 inst->readNextPC(),
793 inst->seqNum,
794 inst->threadNumber,
795 inst->isCompleted());
796 inst->dump();
797 CheckerCPU::dumpAndExit();
798}
799
800template <class DynInstPtr>
801void
802Checker<DynInstPtr>::dumpInsts()
803{
804 int num = 0;
805
806 InstListIt inst_list_it = --(instList.end());
807
808 cprintf("Inst list size: %i\n", instList.size());
809
810 while (inst_list_it != instList.end())
811 {
812 cprintf("Instruction:%i\n",
813 num);
814
815 cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
816 "Completed:%i\n",
817 (*inst_list_it)->readPC(),
818 (*inst_list_it)->seqNum,
819 (*inst_list_it)->threadNumber,
820 (*inst_list_it)->isCompleted());
821
822 cprintf("\n");
823
824 inst_list_it--;
825 ++num;
826 }
827
828}
829
830//template
831//class Checker<RefCountingPtr<OzoneDynInst<OzoneImpl> > >;
1/*
2 * Copyright (c) 2006 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Kevin Lim
29 */
30
31#include <list>
32#include <string>
33
34#include "base/refcnt.hh"
35#include "cpu/base.hh"
36#include "cpu/base_dyn_inst.hh"
37#include "cpu/checker/cpu.hh"
38#include "cpu/simple_thread.hh"
39#include "cpu/thread_context.hh"
40#include "cpu/static_inst.hh"
41#include "mem/packet_impl.hh"
42#include "sim/byteswap.hh"
43#include "sim/sim_object.hh"
44#include "sim/stats.hh"
45
46#include "cpu/o3/alpha_dyn_inst.hh"
47#include "cpu/o3/alpha_impl.hh"
48
49//#include "cpu/ozone/dyn_inst.hh"
50//#include "cpu/ozone/ozone_impl.hh"
51//#include "cpu/ozone/simple_impl.hh"
52
53#if FULL_SYSTEM
54#include "sim/system.hh"
55#include "arch/vtophys.hh"
56#endif // FULL_SYSTEM
57
58using namespace std;
59//The CheckerCPU does alpha only
60using namespace AlphaISA;
61
62void
63CheckerCPU::init()
64{
65}
66
67CheckerCPU::CheckerCPU(Params *p)
68 : BaseCPU(p), thread(NULL), tc(NULL)
69{
70 memReq = NULL;
71
72 numInst = 0;
73 startNumInst = 0;
74 numLoad = 0;
75 startNumLoad = 0;
76 youngestSN = 0;
77
78 changedPC = willChangePC = changedNextPC = false;
79
80 exitOnError = p->exitOnError;
81 warnOnlyOnLoadError = p->warnOnlyOnLoadError;
82#if FULL_SYSTEM
83 itb = p->itb;
84 dtb = p->dtb;
85 systemPtr = NULL;
86#else
87 process = p->process;
88#endif
89
90 result.integer = 0;
91}
92
93CheckerCPU::~CheckerCPU()
94{
95}
96
97void
98CheckerCPU::setMemory(MemObject *mem)
99{
100#if !FULL_SYSTEM
101 memPtr = mem;
102 thread = new SimpleThread(this, /* thread_num */ 0, process,
103 /* asid */ 0, mem);
104
105 thread->setStatus(ThreadContext::Suspended);
106 tc = thread->getTC();
107 threadContexts.push_back(tc);
108#endif
109}
110
111void
112CheckerCPU::setSystem(System *system)
113{
114#if FULL_SYSTEM
115 systemPtr = system;
116
117 thread = new SimpleThread(this, 0, systemPtr, itb, dtb, false);
118
119 thread->setStatus(ThreadContext::Suspended);
120 tc = thread->getTC();
121 threadContexts.push_back(tc);
122 delete thread->kernelStats;
123 thread->kernelStats = NULL;
124#endif
125}
126
127void
128CheckerCPU::setIcachePort(Port *icache_port)
129{
130 icachePort = icache_port;
131}
132
133void
134CheckerCPU::setDcachePort(Port *dcache_port)
135{
136 dcachePort = dcache_port;
137}
138
139void
140CheckerCPU::serialize(ostream &os)
141{
142/*
143 BaseCPU::serialize(os);
144 SERIALIZE_SCALAR(inst);
145 nameOut(os, csprintf("%s.xc", name()));
146 thread->serialize(os);
147 cacheCompletionEvent.serialize(os);
148*/
149}
150
151void
152CheckerCPU::unserialize(Checkpoint *cp, const string &section)
153{
154/*
155 BaseCPU::unserialize(cp, section);
156 UNSERIALIZE_SCALAR(inst);
157 thread->unserialize(cp, csprintf("%s.xc", section));
158*/
159}
160
161Fault
162CheckerCPU::copySrcTranslate(Addr src)
163{
164 panic("Unimplemented!");
165}
166
167Fault
168CheckerCPU::copy(Addr dest)
169{
170 panic("Unimplemented!");
171}
172
173template <class T>
174Fault
175CheckerCPU::read(Addr addr, T &data, unsigned flags)
176{
177 // need to fill in CPU & thread IDs here
178 memReq = new Request();
179
180 memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC());
181
182 // translate to physical address
183 translateDataReadReq(memReq);
184
185 Packet *pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast);
186
187 pkt->dataStatic(&data);
188
189 if (!(memReq->getFlags() & UNCACHEABLE)) {
190 // Access memory to see if we have the same data
191 dcachePort->sendFunctional(pkt);
192 } else {
193 // Assume the data is correct if it's an uncached access
194 memcpy(&data, &unverifiedResult.integer, sizeof(T));
195 }
196
197 delete pkt;
198
199 return NoFault;
200}
201
202#ifndef DOXYGEN_SHOULD_SKIP_THIS
203
204template
205Fault
206CheckerCPU::read(Addr addr, uint64_t &data, unsigned flags);
207
208template
209Fault
210CheckerCPU::read(Addr addr, uint32_t &data, unsigned flags);
211
212template
213Fault
214CheckerCPU::read(Addr addr, uint16_t &data, unsigned flags);
215
216template
217Fault
218CheckerCPU::read(Addr addr, uint8_t &data, unsigned flags);
219
220#endif //DOXYGEN_SHOULD_SKIP_THIS
221
222template<>
223Fault
224CheckerCPU::read(Addr addr, double &data, unsigned flags)
225{
226 return read(addr, *(uint64_t*)&data, flags);
227}
228
229template<>
230Fault
231CheckerCPU::read(Addr addr, float &data, unsigned flags)
232{
233 return read(addr, *(uint32_t*)&data, flags);
234}
235
236template<>
237Fault
238CheckerCPU::read(Addr addr, int32_t &data, unsigned flags)
239{
240 return read(addr, (uint32_t&)data, flags);
241}
242
243template <class T>
244Fault
245CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
246{
247 // need to fill in CPU & thread IDs here
248 memReq = new Request();
249
250 memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC());
251
252 // translate to physical address
253 thread->translateDataWriteReq(memReq);
254
255 // Can compare the write data and result only if it's cacheable,
256 // not a store conditional, or is a store conditional that
257 // succeeded.
258 // @todo: Verify that actual memory matches up with these values.
259 // Right now it only verifies that the instruction data is the
260 // same as what was in the request that got sent to memory; there
261 // is no verification that it is the same as what is in memory.
262 // This is because the LSQ would have to be snooped in the CPU to
263 // verify this data.
264 if (unverifiedReq &&
265 !(unverifiedReq->getFlags() & UNCACHEABLE) &&
266 (!(unverifiedReq->getFlags() & LOCKED) ||
267 ((unverifiedReq->getFlags() & LOCKED) &&
268 unverifiedReq->getScResult() == 1))) {
269 T inst_data;
270/*
271 // This code would work if the LSQ allowed for snooping.
272 Packet *pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast);
273 pkt.dataStatic(&inst_data);
274
275 dcachePort->sendFunctional(pkt);
276
277 delete pkt;
278*/
279 memcpy(&inst_data, unverifiedMemData, sizeof(T));
280
281 if (data != inst_data) {
282 warn("%lli: Store value does not match value in memory! "
283 "Instruction: %#x, memory: %#x",
284 curTick, inst_data, data);
285 handleError();
286 }
287 }
288
289 // Assume the result was the same as the one passed in. This checker
290 // doesn't check if the SC should succeed or fail, it just checks the
291 // value.
292 if (res && unverifiedReq->scResultValid())
293 *res = unverifiedReq->getScResult();
294
295 return NoFault;
296}
297
298
299#ifndef DOXYGEN_SHOULD_SKIP_THIS
300template
301Fault
302CheckerCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res);
303
304template
305Fault
306CheckerCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res);
307
308template
309Fault
310CheckerCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res);
311
312template
313Fault
314CheckerCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res);
315
316#endif //DOXYGEN_SHOULD_SKIP_THIS
317
318template<>
319Fault
320CheckerCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
321{
322 return write(*(uint64_t*)&data, addr, flags, res);
323}
324
325template<>
326Fault
327CheckerCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
328{
329 return write(*(uint32_t*)&data, addr, flags, res);
330}
331
332template<>
333Fault
334CheckerCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
335{
336 return write((uint32_t)data, addr, flags, res);
337}
338
339
340#if FULL_SYSTEM
341Addr
342CheckerCPU::dbg_vtophys(Addr addr)
343{
344 return vtophys(tc, addr);
345}
346#endif // FULL_SYSTEM
347
348bool
349CheckerCPU::translateInstReq(Request *req)
350{
351#if FULL_SYSTEM
352 return (thread->translateInstReq(req) == NoFault);
353#else
354 thread->translateInstReq(req);
355 return true;
356#endif
357}
358
359void
360CheckerCPU::translateDataReadReq(Request *req)
361{
362 thread->translateDataReadReq(req);
363
364 if (req->getVaddr() != unverifiedReq->getVaddr()) {
365 warn("%lli: Request virtual addresses do not match! Inst: %#x, "
366 "checker: %#x",
367 curTick, unverifiedReq->getVaddr(), req->getVaddr());
368 handleError();
369 }
370 req->setPaddr(unverifiedReq->getPaddr());
371
372 if (checkFlags(req)) {
373 warn("%lli: Request flags do not match! Inst: %#x, checker: %#x",
374 curTick, unverifiedReq->getFlags(), req->getFlags());
375 handleError();
376 }
377}
378
379void
380CheckerCPU::translateDataWriteReq(Request *req)
381{
382 thread->translateDataWriteReq(req);
383
384 if (req->getVaddr() != unverifiedReq->getVaddr()) {
385 warn("%lli: Request virtual addresses do not match! Inst: %#x, "
386 "checker: %#x",
387 curTick, unverifiedReq->getVaddr(), req->getVaddr());
388 handleError();
389 }
390 req->setPaddr(unverifiedReq->getPaddr());
391
392 if (checkFlags(req)) {
393 warn("%lli: Request flags do not match! Inst: %#x, checker: %#x",
394 curTick, unverifiedReq->getFlags(), req->getFlags());
395 handleError();
396 }
397}
398
399bool
400CheckerCPU::checkFlags(Request *req)
401{
402 // Remove any dynamic flags that don't have to do with the request itself.
403 unsigned flags = unverifiedReq->getFlags();
404 unsigned mask = LOCKED | PHYSICAL | VPTE | ALTMODE | UNCACHEABLE | NO_FAULT;
405 flags = flags & (mask);
406 if (flags == req->getFlags()) {
407 return false;
408 } else {
409 return true;
410 }
411}
412
413void
414CheckerCPU::dumpAndExit()
415{
416 warn("%lli: Checker PC:%#x, next PC:%#x",
417 curTick, thread->readPC(), thread->readNextPC());
418 panic("Checker found an error!");
419}
420
421template <class DynInstPtr>
422void
423Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
424{
425 DynInstPtr inst;
426
427 // Either check this instruction, or add it to a list of
428 // instructions waiting to be checked. Instructions must be
429 // checked in program order, so if a store has committed yet not
430 // completed, there may be some instructions that are waiting
431 // behind it that have completed and must be checked.
432 if (!instList.empty()) {
433 if (youngestSN < completed_inst->seqNum) {
434 DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n",
435 completed_inst->seqNum, completed_inst->readPC());
436 instList.push_back(completed_inst);
437 youngestSN = completed_inst->seqNum;
438 }
439
440 if (!instList.front()->isCompleted()) {
441 return;
442 } else {
443 inst = instList.front();
444 instList.pop_front();
445 }
446 } else {
447 if (!completed_inst->isCompleted()) {
448 if (youngestSN < completed_inst->seqNum) {
449 DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n",
450 completed_inst->seqNum, completed_inst->readPC());
451 instList.push_back(completed_inst);
452 youngestSN = completed_inst->seqNum;
453 }
454 return;
455 } else {
456 if (youngestSN < completed_inst->seqNum) {
457 inst = completed_inst;
458 youngestSN = completed_inst->seqNum;
459 } else {
460 return;
461 }
462 }
463 }
464
465 // Try to check all instructions that are completed, ending if we
466 // run out of instructions to check or if an instruction is not
467 // yet completed.
468 while (1) {
469 DPRINTF(Checker, "Processing instruction [sn:%lli] PC:%#x.\n",
470 inst->seqNum, inst->readPC());
471 unverifiedResult.integer = inst->readIntResult();
472 unverifiedReq = inst->req;
473 unverifiedMemData = inst->memData;
474 numCycles++;
475
476 Fault fault = NoFault;
477
478 // maintain $r0 semantics
479 thread->setIntReg(ZeroReg, 0);
480#ifdef TARGET_ALPHA
481 thread->setFloatRegDouble(ZeroReg, 0.0);
482#endif // TARGET_ALPHA
483
484 // Check if any recent PC changes match up with anything we
485 // expect to happen. This is mostly to check if traps or
486 // PC-based events have occurred in both the checker and CPU.
487 if (changedPC) {
488 DPRINTF(Checker, "Changed PC recently to %#x\n",
489 thread->readPC());
490 if (willChangePC) {
491 if (newPC == thread->readPC()) {
492 DPRINTF(Checker, "Changed PC matches expected PC\n");
493 } else {
494 warn("%lli: Changed PC does not match expected PC, "
495 "changed: %#x, expected: %#x",
496 curTick, thread->readPC(), newPC);
497 CheckerCPU::handleError();
498 }
499 willChangePC = false;
500 }
501 changedPC = false;
502 }
503 if (changedNextPC) {
504 DPRINTF(Checker, "Changed NextPC recently to %#x\n",
505 thread->readNextPC());
506 changedNextPC = false;
507 }
508
509 // Try to fetch the instruction
510
511#if FULL_SYSTEM
512#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0
513#else
514#define IFETCH_FLAGS(pc) 0
515#endif
516
517 uint64_t fetch_PC = thread->readPC() & ~3;
518
519 // set up memory request for instruction fetch
520 memReq = new Request(inst->threadNumber, fetch_PC,
521 sizeof(uint32_t),
522 IFETCH_FLAGS(thread->readPC()),
523 fetch_PC, thread->readCpuId(), inst->threadNumber);
524
525 bool succeeded = translateInstReq(memReq);
526
527 if (!succeeded) {
528 if (inst->getFault() == NoFault) {
529 // In this case the instruction was not a dummy
530 // instruction carrying an ITB fault. In the single
531 // threaded case the ITB should still be able to
532 // translate this instruction; in the SMT case it's
533 // possible that its ITB entry was kicked out.
534 warn("%lli: Instruction PC %#x was not found in the ITB!",
535 curTick, thread->readPC());
536 handleError(inst);
537
538 // go to the next instruction
539 thread->setPC(thread->readNextPC());
540 thread->setNextPC(thread->readNextPC() + sizeof(MachInst));
541
542 return;
543 } else {
544 // The instruction is carrying an ITB fault. Handle
545 // the fault and see if our results match the CPU on
546 // the next tick().
547 fault = inst->getFault();
548 }
549 }
550
551 if (fault == NoFault) {
552 Packet *pkt = new Packet(memReq, Packet::ReadReq,
553 Packet::Broadcast);
554
555 pkt->dataStatic(&machInst);
556
557 icachePort->sendFunctional(pkt);
558
559 delete pkt;
560
561 // keep an instruction count
562 numInst++;
563
564 // decode the instruction
565 machInst = gtoh(machInst);
566 // Checks that the instruction matches what we expected it to be.
567 // Checks both the machine instruction and the PC.
568 validateInst(inst);
569
570 curStaticInst = StaticInst::decode(makeExtMI(machInst,
571 thread->readPC()));
572
573#if FULL_SYSTEM
574 thread->setInst(machInst);
575#endif // FULL_SYSTEM
576
577 fault = inst->getFault();
578 }
579
580 // Discard fetch's memReq.
581 delete memReq;
582 memReq = NULL;
583
584 // Either the instruction was a fault and we should process the fault,
585 // or we should just go ahead execute the instruction. This assumes
586 // that the instruction is properly marked as a fault.
587 if (fault == NoFault) {
588
589 thread->funcExeInst++;
590
591 fault = curStaticInst->execute(this, NULL);
592
593 // Checks to make sure instrution results are correct.
594 validateExecution(inst);
595
596 if (curStaticInst->isLoad()) {
597 ++numLoad;
598 }
599 }
600
601 if (fault != NoFault) {
602#if FULL_SYSTEM
603 fault->invoke(tc);
604 willChangePC = true;
605 newPC = thread->readPC();
606 DPRINTF(Checker, "Fault, PC is now %#x\n", newPC);
607#else // !FULL_SYSTEM
608 fatal("fault (%d) detected @ PC 0x%08p", fault, thread->readPC());
609#endif // FULL_SYSTEM
610 } else {
611#if THE_ISA != MIPS_ISA
612 // go to the next instruction
613 thread->setPC(thread->readNextPC());
614 thread->setNextPC(thread->readNextPC() + sizeof(MachInst));
615#else
616 // go to the next instruction
617 thread->setPC(thread->readNextPC());
618 thread->setNextPC(thread->readNextNPC());
619 thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst));
620#endif
621
622 }
623
624#if FULL_SYSTEM
625 // @todo: Determine if these should happen only if the
626 // instruction hasn't faulted. In the SimpleCPU case this may
627 // not be true, but in the O3 or Ozone case this may be true.
628 Addr oldpc;
629 int count = 0;
630 do {
631 oldpc = thread->readPC();
632 system->pcEventQueue.service(tc);
633 count++;
634 } while (oldpc != thread->readPC());
635 if (count > 1) {
636 willChangePC = true;
637 newPC = thread->readPC();
638 DPRINTF(Checker, "PC Event, PC is now %#x\n", newPC);
639 }
640#endif
641
642 // @todo: Optionally can check all registers. (Or just those
643 // that have been modified).
644 validateState();
645
646 if (memReq) {
647 delete memReq;
648 memReq = NULL;
649 }
650
651 // Continue verifying instructions if there's another completed
652 // instruction waiting to be verified.
653 if (instList.empty()) {
654 break;
655 } else if (instList.front()->isCompleted()) {
656 inst = instList.front();
657 instList.pop_front();
658 } else {
659 break;
660 }
661 }
662}
663
664template <class DynInstPtr>
665void
666Checker<DynInstPtr>::switchOut(Sampler *s)
667{
668 instList.clear();
669}
670
671template <class DynInstPtr>
672void
673Checker<DynInstPtr>::takeOverFrom(BaseCPU *oldCPU)
674{
675}
676
677template <class DynInstPtr>
678void
679Checker<DynInstPtr>::validateInst(DynInstPtr &inst)
680{
681 if (inst->readPC() != thread->readPC()) {
682 warn("%lli: PCs do not match! Inst: %#x, checker: %#x",
683 curTick, inst->readPC(), thread->readPC());
684 if (changedPC) {
685 warn("%lli: Changed PCs recently, may not be an error",
686 curTick);
687 } else {
688 handleError(inst);
689 }
690 }
691
692 MachInst mi = static_cast<MachInst>(inst->staticInst->machInst);
693
694 if (mi != machInst) {
695 warn("%lli: Binary instructions do not match! Inst: %#x, "
696 "checker: %#x",
697 curTick, mi, machInst);
698 handleError(inst);
699 }
700}
701
702template <class DynInstPtr>
703void
704Checker<DynInstPtr>::validateExecution(DynInstPtr &inst)
705{
706 bool result_mismatch = false;
707 if (inst->numDestRegs()) {
708 // @todo: Support more destination registers.
709 if (inst->isUnverifiable()) {
710 // Unverifiable instructions assume they were executed
711 // properly by the CPU. Grab the result from the
712 // instruction and write it to the register.
713 copyResult(inst);
714 } else if (result.integer != inst->readIntResult()) {
715 result_mismatch = true;
716 }
717 }
718
719 if (result_mismatch) {
720 warn("%lli: Instruction results do not match! (Values may not "
721 "actually be integers) Inst: %#x, checker: %#x",
722 curTick, inst->readIntResult(), result.integer);
723
724 // It's useful to verify load values from memory, but in MP
725 // systems the value obtained at execute may be different than
726 // the value obtained at completion. Similarly DMA can
727 // present the same problem on even UP systems. Thus there is
728 // the option to only warn on loads having a result error.
729 if (inst->isLoad() && warnOnlyOnLoadError) {
730 copyResult(inst);
731 } else {
732 handleError(inst);
733 }
734 }
735
736 if (inst->readNextPC() != thread->readNextPC()) {
737 warn("%lli: Instruction next PCs do not match! Inst: %#x, "
738 "checker: %#x",
739 curTick, inst->readNextPC(), thread->readNextPC());
740 handleError(inst);
741 }
742
743 // Checking side effect registers can be difficult if they are not
744 // checked simultaneously with the execution of the instruction.
745 // This is because other valid instructions may have modified
746 // these registers in the meantime, and their values are not
747 // stored within the DynInst.
748 while (!miscRegIdxs.empty()) {
749 int misc_reg_idx = miscRegIdxs.front();
750 miscRegIdxs.pop();
751
752 if (inst->tcBase()->readMiscReg(misc_reg_idx) !=
753 thread->readMiscReg(misc_reg_idx)) {
754 warn("%lli: Misc reg idx %i (side effect) does not match! "
755 "Inst: %#x, checker: %#x",
756 curTick, misc_reg_idx,
757 inst->tcBase()->readMiscReg(misc_reg_idx),
758 thread->readMiscReg(misc_reg_idx));
759 handleError(inst);
760 }
761 }
762}
763
764template <class DynInstPtr>
765void
766Checker<DynInstPtr>::validateState()
767{
768}
769
770template <class DynInstPtr>
771void
772Checker<DynInstPtr>::copyResult(DynInstPtr &inst)
773{
774 RegIndex idx = inst->destRegIdx(0);
775 if (idx < TheISA::FP_Base_DepTag) {
776 thread->setIntReg(idx, inst->readIntResult());
777 } else if (idx < TheISA::Fpcr_DepTag) {
778 thread->setFloatRegBits(idx, inst->readIntResult());
779 } else {
780 thread->setMiscReg(idx, inst->readIntResult());
781 }
782}
783
784template <class DynInstPtr>
785void
786Checker<DynInstPtr>::dumpAndExit(DynInstPtr &inst)
787{
788 cprintf("Error detected, instruction information:\n");
789 cprintf("PC:%#x, nextPC:%#x\n[sn:%lli]\n[tid:%i]\n"
790 "Completed:%i\n",
791 inst->readPC(),
792 inst->readNextPC(),
793 inst->seqNum,
794 inst->threadNumber,
795 inst->isCompleted());
796 inst->dump();
797 CheckerCPU::dumpAndExit();
798}
799
800template <class DynInstPtr>
801void
802Checker<DynInstPtr>::dumpInsts()
803{
804 int num = 0;
805
806 InstListIt inst_list_it = --(instList.end());
807
808 cprintf("Inst list size: %i\n", instList.size());
809
810 while (inst_list_it != instList.end())
811 {
812 cprintf("Instruction:%i\n",
813 num);
814
815 cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
816 "Completed:%i\n",
817 (*inst_list_it)->readPC(),
818 (*inst_list_it)->seqNum,
819 (*inst_list_it)->threadNumber,
820 (*inst_list_it)->isCompleted());
821
822 cprintf("\n");
823
824 inst_list_it--;
825 ++num;
826 }
827
828}
829
830//template
831//class Checker<RefCountingPtr<OzoneDynInst<OzoneImpl> > >;
832
832// Manually instantiate checker
833template
834class Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >;
833template
834class Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >;