1a2,13
> * Copyright (c) 2011 ARM Limited
> * All rights reserved
> *
> * The license below extends only to copyright in the software and shall
> * not be construed as granting a license to any other intellectual
> * property including but not limited to intellectual property relating
> * to a hardware implementation of the functionality of the software
> * licensed hereunder. You may use the software subject to the license
> * terms below provided that you ensure that this notice is replicated
> * unmodified and in its entirety in all distributions of the software,
> * modified or unmodified, in source code or in binary form.
> *
28a41
> * Geoffrey Blake
36d48
< #include "cpu/checker/cpu.hh"
37a50
> #include "cpu/exetrace.hh"
40a54,55
> #include "cpu/checker/cpu.hh"
> #include "debug/Checker.hh"
49,50c64
< //The CheckerCPU does alpha only
< using namespace AlphaISA;
---
> using namespace TheISA;
52c66
< template <class DynInstPtr>
---
> template <class Impl>
54c68
< Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
---
> Checker<Impl>::advancePC(Fault fault)
55a70,124
> if (fault != NoFault) {
> curMacroStaticInst = StaticInst::nullStaticInstPtr;
> fault->invoke(tc, curStaticInst);
> predecoder.reset();
> } else {
> if (curStaticInst) {
> if (curStaticInst->isLastMicroop())
> curMacroStaticInst = StaticInst::nullStaticInstPtr;
> TheISA::PCState pcState = thread->pcState();
> TheISA::advancePC(pcState, curStaticInst);
> thread->pcState(pcState);
> DPRINTF(Checker, "Advancing PC to %s.\n", thread->pcState());
> }
> }
> }
> //////////////////////////////////////////////////
>
> template <class Impl>
> void
> Checker<Impl>::handlePendingInt()
> {
> DPRINTF(Checker, "IRQ detected at PC: %s with %d insts in buffer\n",
> thread->pcState(), instList.size());
> DynInstPtr boundaryInst = NULL;
> if (!instList.empty()) {
> // Set the instructions as completed and verify as much as possible.
> DynInstPtr inst;
> typename std::list<DynInstPtr>::iterator itr;
>
> for (itr = instList.begin(); itr != instList.end(); itr++) {
> (*itr)->setCompleted();
> }
>
> inst = instList.front();
> boundaryInst = instList.back();
> verify(inst); // verify the instructions
> inst = NULL;
> }
> if ((!boundaryInst && curMacroStaticInst &&
> curStaticInst->isDelayedCommit() &&
> !curStaticInst->isLastMicroop()) ||
> (boundaryInst && boundaryInst->isDelayedCommit() &&
> !boundaryInst->isLastMicroop())) {
> panic("%lli: Trying to take an interrupt in middle of "
> "a non-interuptable instruction!", curTick());
> }
> boundaryInst = NULL;
> predecoder.reset();
> curMacroStaticInst = StaticInst::nullStaticInstPtr;
> }
>
> template <class Impl>
> void
> Checker<Impl>::verify(DynInstPtr &completed_inst)
> {
57a127,138
> // Make sure serializing instructions are actually
> // seen as serializing to commit. instList should be
> // empty in these cases.
> if ((completed_inst->isSerializing() ||
> completed_inst->isSerializeBefore()) &&
> (!instList.empty() ?
> (instList.front()->seqNum != completed_inst->seqNum) : 0)) {
> panic("%lli: Instruction sn:%lli at PC %s is serializing before but is"
> " entering instList with other instructions\n", curTick(),
> completed_inst->seqNum, completed_inst->pcState());
> }
>
65,66c146,147
< DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n",
< completed_inst->seqNum, completed_inst->readPC());
---
> DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%s to list\n",
> completed_inst->seqNum, completed_inst->pcState());
80,81c161,162
< DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n",
< completed_inst->seqNum, completed_inst->readPC());
---
> DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%s to list\n",
> completed_inst->seqNum, completed_inst->pcState());
95a177,183
> // Make sure a serializing instruction is actually seen as
> // serializing. instList should be empty here
> if (inst->isSerializeAfter() && !instList.empty()) {
> panic("%lli: Instruction sn:%lli at PC %s is serializing after but is"
> " exiting instList with other instructions\n", curTick(),
> completed_inst->seqNum, completed_inst->pcState());
> }
96a185
> inst = NULL;
102,106c191,199
< DPRINTF(Checker, "Processing instruction [sn:%lli] PC:%#x.\n",
< inst->seqNum, inst->readPC());
< unverifiedResult.integer = inst->readIntResult();
< unverifiedReq = inst->req;
< unverifiedMemData = inst->memData;
---
> DPRINTF(Checker, "Processing instruction [sn:%lli] PC:%s.\n",
> unverifiedInst->seqNum, unverifiedInst->pcState());
> unverifiedReq = NULL;
> unverifiedReq = unverifiedInst->reqToVerify;
> unverifiedMemData = unverifiedInst->memData;
> // Make sure results queue is empty
> while (!result.empty()) {
> result.pop();
> }
121,122c214,215
< DPRINTF(Checker, "Changed PC recently to %#x\n",
< thread->readPC());
---
> DPRINTF(Checker, "Changed PC recently to %s\n",
> thread->pcState());
124c217
< if (newPC == thread->readPC()) {
---
> if (newPCState == thread->pcState()) {
128,129c221,222
< "changed: %#x, expected: %#x",
< curTick(), thread->readPC(), newPC);
---
> "changed: %s, expected: %s",
> curTick(), thread->pcState(), newPCState);
138c231
< thread->readNextPC());
---
> thread->nextInstAddr());
142a236,237
> uint64_t fetchOffset = 0;
> bool fetchDone = false;
144,148c239,241
< #if FULL_SYSTEM
< #define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0
< #else
< #define IFETCH_FLAGS(pc) 0
< #endif
---
> while (!fetchDone) {
> Addr fetch_PC = thread->instAddr();
> fetch_PC = (fetch_PC & PCMask) + fetchOffset;
150c243,252
< uint64_t fetch_PC = thread->readPC() & ~3;
---
> // If not in the middle of a macro instruction
> if (!curMacroStaticInst) {
> // set up memory request for instruction fetch
> memReq = new Request(unverifiedInst->threadNumber, fetch_PC,
> sizeof(MachInst),
> 0,
> fetch_PC, thread->contextId(),
> unverifiedInst->threadNumber);
> memReq->setVirt(0, fetch_PC, sizeof(MachInst),
> Request::INST_FETCH, thread->instAddr());
152,157d253
< // set up memory request for instruction fetch
< memReq = new Request(inst->threadNumber, fetch_PC,
< sizeof(uint32_t),
< IFETCH_FLAGS(thread->readPC()),
< fetch_PC, thread->contextId(),
< inst->threadNumber);
159c255
< bool succeeded = itb->translateAtomic(memReq, thread);
---
> fault = itb->translateFunctional(memReq, tc, BaseTLB::Execute);
161,170c257,266
< if (!succeeded) {
< if (inst->getFault() == NoFault) {
< // In this case the instruction was not a dummy
< // instruction carrying an ITB fault. In the single
< // threaded case the ITB should still be able to
< // translate this instruction; in the SMT case it's
< // possible that its ITB entry was kicked out.
< warn("%lli: Instruction PC %#x was not found in the ITB!",
< curTick(), thread->readPC());
< handleError(inst);
---
> if (fault != NoFault) {
> if (unverifiedInst->getFault() == NoFault) {
> // In this case the instruction was not a dummy
> // instruction carrying an ITB fault. In the single
> // threaded case the ITB should still be able to
> // translate this instruction; in the SMT case it's
> // possible that its ITB entry was kicked out.
> warn("%lli: Instruction PC %s was not found in the "
> "ITB!", curTick(), thread->pcState());
> handleError(unverifiedInst);
172,174c268,269
< // go to the next instruction
< thread->setPC(thread->readNextPC());
< thread->setNextPC(thread->readNextPC() + sizeof(MachInst));
---
> // go to the next instruction
> advancePC(NoFault);
176,181c271,294
< break;
< } else {
< // The instruction is carrying an ITB fault. Handle
< // the fault and see if our results match the CPU on
< // the next tick().
< fault = inst->getFault();
---
> // Give up on an ITB fault..
> delete memReq;
> unverifiedInst = NULL;
> return;
> } else {
> // The instruction is carrying an ITB fault. Handle
> // the fault and see if our results match the CPU on
> // the next tick().
> fault = unverifiedInst->getFault();
> delete memReq;
> break;
> }
> } else {
> PacketPtr pkt = new Packet(memReq,
> MemCmd::ReadReq,
> Packet::Broadcast);
>
> pkt->dataStatic(&machInst);
> icachePort->sendFunctional(pkt);
> machInst = gtoh(machInst);
>
> delete memReq;
> delete pkt;
> }
183d295
< }
185,187c297,298
< if (fault == NoFault) {
< PacketPtr pkt = new Packet(memReq, Packet::ReadReq,
< Packet::Broadcast);
---
> if (fault == NoFault) {
> TheISA::PCState pcState = thread->pcState();
189c300,306
< pkt->dataStatic(&machInst);
---
> if (isRomMicroPC(pcState.microPC())) {
> fetchDone = true;
> curStaticInst =
> microcodeRom.fetchMicroop(pcState.microPC(), NULL);
> } else if (!curMacroStaticInst) {
> //We're not in the middle of a macro instruction
> StaticInstPtr instPtr = NULL;
191c308,312
< icachePort->sendFunctional(pkt);
---
> //Predecode, ie bundle up an ExtMachInst
> predecoder.setTC(thread->getTC());
> //If more fetch data is needed, pass it in.
> Addr fetchPC = (pcState.instAddr() & PCMask) + fetchOffset;
> predecoder.moreBytes(pcState, fetchPC, machInst);
193c314,328
< delete pkt;
---
> //If an instruction is ready, decode it.
> //Otherwise, we'll have to fetch beyond the
> //MachInst at the current pc.
> if (predecoder.extMachInstReady()) {
> fetchDone = true;
> ExtMachInst newMachInst =
> predecoder.getExtMachInst(pcState);
> thread->pcState(pcState);
> instPtr = thread->decoder.decode(newMachInst,
> pcState.instAddr());
> machInst = newMachInst;
> } else {
> fetchDone = false;
> fetchOffset += sizeof(TheISA::MachInst);
> }
195,196c330,348
< // keep an instruction count
< numInst++;
---
> //If we decoded an instruction and it's microcoded,
> //start pulling out micro ops
> if (instPtr && instPtr->isMacroop()) {
> curMacroStaticInst = instPtr;
> curStaticInst =
> instPtr->fetchMicroop(pcState.microPC());
> } else {
> curStaticInst = instPtr;
> }
> } else {
> // Read the next micro op from the macro-op
> curStaticInst =
> curMacroStaticInst->fetchMicroop(pcState.microPC());
> fetchDone = true;
> }
> }
> }
> // reset predecoder on Checker
> predecoder.reset();
198,199c350,355
< // decode the instruction
< machInst = gtoh(machInst);
---
> // Check Checker and CPU get same instruction, and record
> // any faults the CPU may have had.
> Fault unverifiedFault;
> if (fault == NoFault) {
> unverifiedFault = unverifiedInst->getFault();
>
202,212c358
< validateInst(inst);
<
< #if THE_ISA == ALPHA_ISA
< curStaticInst = StaticInst::decode(makeExtMI(machInst,
< thread->readPC()));
< #elif THE_ISA == SPARC_ISA
< curStaticInst = StaticInst::decode(makeExtMI(machInst,
< thread->getTC()));
< #endif
<
< fault = inst->getFault();
---
> validateInst(unverifiedInst);
215,217c361,362
< // Discard fetch's memReq.
< delete memReq;
< memReq = NULL;
---
> // keep an instruction count
> numInst++;
218a364
>
222a369,381
> // Execute Checker instruction and trace
> if (!unverifiedInst->isUnverifiable()) {
> Trace::InstRecord *traceData = tracer->getInstRecord(curTick(),
> tc,
> curStaticInst,
> pcState(),
> curMacroStaticInst);
> fault = curStaticInst->execute(this, traceData);
> if (traceData) {
> traceData->dump();
> delete traceData;
> }
> }
224c383,386
< thread->funcExeInst++;
---
> if (fault == NoFault && unverifiedFault == NoFault) {
> thread->funcExeInst++;
> // Checks to make sure instrution results are correct.
> validateExecution(unverifiedInst);
226,233c388,398
< if (!inst->isUnverifiable())
< fault = curStaticInst->execute(this, NULL);
<
< // Checks to make sure instrution results are correct.
< validateExecution(inst);
<
< if (curStaticInst->isLoad()) {
< ++numLoad;
---
> if (curStaticInst->isLoad()) {
> ++numLoad;
> }
> } else if (fault != NoFault && unverifiedFault == NoFault) {
> panic("%lli: sn: %lli at PC: %s took a fault in checker "
> "but not in driver CPU\n", curTick(),
> unverifiedInst->seqNum, unverifiedInst->pcState());
> } else if (fault == NoFault && unverifiedFault != NoFault) {
> panic("%lli: sn: %lli at PC: %s took a fault in driver "
> "CPU but not in checker\n", curTick(),
> unverifiedInst->seqNum, unverifiedInst->pcState());
236a402
> // Take any faults here
241,242c407,409
< newPC = thread->readPC();
< DPRINTF(Checker, "Fault, PC is now %#x\n", newPC);
---
> newPCState = thread->pcState();
> DPRINTF(Checker, "Fault, PC is now %s\n", newPCState);
> curMacroStaticInst = StaticInst::nullStaticInstPtr;
245,255c412
< #if THE_ISA != MIPS_ISA
< // go to the next instruction
< thread->setPC(thread->readNextPC());
< thread->setNextPC(thread->readNextPC() + sizeof(MachInst));
< #else
< // go to the next instruction
< thread->setPC(thread->readNextPC());
< thread->setNextPC(thread->readNextNPC());
< thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst));
< #endif
<
---
> advancePC(fault);
265c422
< oldpc = thread->readPC();
---
> oldpc = thread->instAddr();
268c425
< } while (oldpc != thread->readPC());
---
> } while (oldpc != thread->instAddr());
271,272c428,429
< newPC = thread->readPC();
< DPRINTF(Checker, "PC Event, PC is now %#x\n", newPC);
---
> newPCState = thread->pcState();
> DPRINTF(Checker, "PC Event, PC is now %s\n", newPCState);
280,284d436
< if (memReq) {
< delete memReq;
< memReq = NULL;
< }
<
290c442,443
< inst = instList.front();
---
> unverifiedInst = NULL;
> unverifiedInst = instList.front();
299c452
< template <class DynInstPtr>
---
> template <class Impl>
301c454
< Checker<DynInstPtr>::switchOut()
---
> Checker<Impl>::switchOut()
306c459
< template <class DynInstPtr>
---
> template <class Impl>
308c461
< Checker<DynInstPtr>::takeOverFrom(BaseCPU *oldCPU)
---
> Checker<Impl>::takeOverFrom(BaseCPU *oldCPU)
312c465
< template <class DynInstPtr>
---
> template <class Impl>
314c467
< Checker<DynInstPtr>::validateInst(DynInstPtr &inst)
---
> Checker<Impl>::validateInst(DynInstPtr &inst)
316,318c469,471
< if (inst->readPC() != thread->readPC()) {
< warn("%lli: PCs do not match! Inst: %#x, checker: %#x",
< curTick(), inst->readPC(), thread->readPC());
---
> if (inst->instAddr() != thread->instAddr()) {
> warn("%lli: PCs do not match! Inst: %s, checker: %s",
> curTick(), inst->pcState(), thread->pcState());
330c483
< warn("%lli: Binary instructions do not match! Inst: %#x, "
---
> panic("%lli: Binary instructions do not match! Inst: %#x, "
337c490
< template <class DynInstPtr>
---
> template <class Impl>
339c492
< Checker<DynInstPtr>::validateExecution(DynInstPtr &inst)
---
> Checker<Impl>::validateExecution(DynInstPtr &inst)
340a494,496
> uint64_t checker_val;
> uint64_t inst_val;
> int idx = -1;
342,350c498,516
< if (inst->numDestRegs()) {
< // @todo: Support more destination registers.
< if (inst->isUnverifiable()) {
< // Unverifiable instructions assume they were executed
< // properly by the CPU. Grab the result from the
< // instruction and write it to the register.
< copyResult(inst);
< } else if (result.integer != inst->readIntResult()) {
< result_mismatch = true;
---
>
> if (inst->isUnverifiable()) {
> // Unverifiable instructions assume they were executed
> // properly by the CPU. Grab the result from the
> // instruction and write it to the register.
> copyResult(inst, 0, idx);
> } else if (inst->numDestRegs() > 0 && !result.empty()) {
> DPRINTF(Checker, "Dest regs %d, number of checker dest regs %d\n",
> inst->numDestRegs(), result.size());
> for (int i = 0; i < inst->numDestRegs() && !result.empty(); i++) {
> result.front().get(checker_val);
> result.pop();
> inst_val = 0;
> inst->template popResult<uint64_t>(inst_val);
> if (checker_val != inst_val) {
> result_mismatch = true;
> idx = i;
> break;
> }
352c518,522
< }
---
> } // Checker CPU checks all the saved results in the dyninst passed by
> // the cpu model being checked against the saved results present in
> // the static inst executed in the Checker. Sometimes the number
> // of saved results differs between the dyninst and static inst, but
> // this is ok and not a bug. May be worthwhile to try and correct this.
357c527
< curTick(), inst->readIntResult(), result.integer);
---
> curTick(), inst_val, checker_val);
363a534,535
> // The load/store queue in Detailed CPU can also cause problems
> // if load/store forwarding is allowed.
365c537
< copyResult(inst);
---
> copyResult(inst, inst_val, idx);
371c543
< if (inst->readNextPC() != thread->readNextPC()) {
---
> if (inst->nextInstAddr() != thread->nextInstAddr()) {
374c546
< curTick(), inst->readNextPC(), thread->readNextPC());
---
> curTick(), inst->nextInstAddr(), thread->nextInstAddr());
399c571,575
< template <class DynInstPtr>
---
>
> // This function is weird, if it is called it means the Checker and
> // O3 have diverged, so panic is called for now. It may be useful
> // to resynch states and continue if the divergence is a false positive
> template <class Impl>
401c577
< Checker<DynInstPtr>::validateState()
---
> Checker<Impl>::validateState()
404,405c580,587
< warn("%lli: Instruction PC %#x results didn't match up, copying all "
< "registers from main CPU", curTick(), unverifiedInst->readPC());
---
> // Change this back to warn if divergences end up being false positives
> panic("%lli: Instruction PC %#x results didn't match up, copying all "
> "registers from main CPU", curTick(), unverifiedInst->instAddr());
>
> // Terribly convoluted way to make sure O3 model does not implode
> bool inSyscall = unverifiedInst->thread->inSyscall;
> unverifiedInst->thread->inSyscall = true;
>
407a590,593
> unverifiedInst->thread->inSyscall = inSyscall;
>
> // Set curStaticInst to unverifiedInst->staticInst
> curStaticInst = unverifiedInst->staticInst;
409,418c595
< #if THE_ISA != MIPS_ISA
< // go to the next instruction
< thread->setPC(thread->readNextPC());
< thread->setNextPC(thread->readNextPC() + sizeof(MachInst));
< #else
< // go to the next instruction
< thread->setPC(thread->readNextPC());
< thread->setNextPC(thread->readNextNPC());
< thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst));
< #endif
---
> advancePC(NoFault);
423c600
< template <class DynInstPtr>
---
> template <class Impl>
425c602,603
< Checker<DynInstPtr>::copyResult(DynInstPtr &inst)
---
> Checker<Impl>::copyResult(DynInstPtr &inst, uint64_t mismatch_val,
> int start_idx)
427,433c605,616
< RegIndex idx = inst->destRegIdx(0);
< if (idx < TheISA::FP_Base_DepTag) {
< thread->setIntReg(idx, inst->readIntResult());
< } else if (idx < TheISA::Fpcr_DepTag) {
< thread->setFloatRegBits(idx, inst->readIntResult());
< } else {
< thread->setMiscRegNoEffect(idx, inst->readIntResult());
---
> // We've already popped one dest off the queue,
> // so do the fix-up then start with the next dest reg;
> if (start_idx >= 0) {
> RegIndex idx = inst->destRegIdx(start_idx);
> if (idx < TheISA::FP_Base_DepTag) {
> thread->setIntReg(idx, mismatch_val);
> } else if (idx < TheISA::Ctrl_Base_DepTag) {
> thread->setFloatRegBits(idx, mismatch_val);
> } else if (idx < TheISA::Max_DepTag) {
> thread->setMiscReg(idx - TheISA::Ctrl_Base_DepTag,
> mismatch_val);
> }
434a618,631
> start_idx++;
> uint64_t res = 0;
> for (int i = start_idx; i < inst->numDestRegs(); i++) {
> RegIndex idx = inst->destRegIdx(i);
> inst->template popResult<uint64_t>(res);
> if (idx < TheISA::FP_Base_DepTag) {
> thread->setIntReg(idx, res);
> } else if (idx < TheISA::Ctrl_Base_DepTag) {
> thread->setFloatRegBits(idx, res);
> } else if (idx < TheISA::Max_DepTag) {
> // Try to get the proper misc register index for ARM here...
> thread->setMiscReg(idx - TheISA::Ctrl_Base_DepTag, res);
> } // else Register is out of range...
> }
437c634
< template <class DynInstPtr>
---
> template <class Impl>
439c636
< Checker<DynInstPtr>::dumpAndExit(DynInstPtr &inst)
---
> Checker<Impl>::dumpAndExit(DynInstPtr &inst)
442c639
< cprintf("PC:%#x, nextPC:%#x\n[sn:%lli]\n[tid:%i]\n"
---
> cprintf("PC:%s, nextPC:%#x\n[sn:%lli]\n[tid:%i]\n"
444,445c641,642
< inst->readPC(),
< inst->readNextPC(),
---
> inst->pcState(),
> inst->nextInstAddr(),
453c650
< template <class DynInstPtr>
---
> template <class Impl>
455c652
< Checker<DynInstPtr>::dumpInsts()
---
> Checker<Impl>::dumpInsts()
468c665
< cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
---
> cprintf("PC:%s\n[sn:%lli]\n[tid:%i]\n"
470c667
< (*inst_list_it)->readPC(),
---
> (*inst_list_it)->pcState(),