cpu_impl.hh revision 10426
19243SN/A/* 210889Sandreas.hansson@arm.com * Copyright (c) 2011 ARM Limited 39243SN/A * Copyright (c) 2013 Advanced Micro Devices, Inc. 49243SN/A * All rights reserved 59243SN/A * 69243SN/A * The license below extends only to copyright in the software and shall 79243SN/A * not be construed as granting a license to any other intellectual 89243SN/A * property including but not limited to intellectual property relating 99243SN/A * to a hardware implementation of the functionality of the software 109243SN/A * licensed hereunder. You may use the software subject to the license 119243SN/A * terms below provided that you ensure that this notice is replicated 129243SN/A * unmodified and in its entirety in all distributions of the software, 139243SN/A * modified or unmodified, in source code or in binary form. 149831SN/A * 159831SN/A * Copyright (c) 2006 The Regents of The University of Michigan 169831SN/A * All rights reserved. 179243SN/A * 189243SN/A * Redistribution and use in source and binary forms, with or without 199243SN/A * modification, are permitted provided that the following conditions are 209243SN/A * met: redistributions of source code must retain the above copyright 219243SN/A * notice, this list of conditions and the following disclaimer; 229243SN/A * redistributions in binary form must reproduce the above copyright 239243SN/A * notice, this list of conditions and the following disclaimer in the 249243SN/A * documentation and/or other materials provided with the distribution; 259243SN/A * neither the name of the copyright holders nor the names of its 269243SN/A * contributors may be used to endorse or promote products derived from 279243SN/A * this software without specific prior written permission. 289243SN/A * 299243SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 309243SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 319243SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 329243SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 339243SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 349243SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 359243SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 369243SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 379243SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 389243SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 399243SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 409243SN/A * 419243SN/A * Authors: Kevin Lim 429967SN/A * Geoffrey Blake 4310618SOmar.Naji@arm.com */ 449243SN/A 459243SN/A#ifndef __CPU_CHECKER_CPU_IMPL_HH__ 4610146Sandreas.hansson@arm.com#define __CPU_CHECKER_CPU_IMPL_HH__ 479356SN/A 4810146Sandreas.hansson@arm.com#include <list> 4910247Sandreas.hansson@arm.com#include <string> 5010208Sandreas.hansson@arm.com 519352SN/A#include "arch/isa_traits.hh" 5210146Sandreas.hansson@arm.com#include "arch/vtophys.hh" 539814SN/A#include "base/refcnt.hh" 549243SN/A#include "config/the_isa.hh" 559243SN/A#include "cpu/base_dyn_inst.hh" 5610432SOmar.Naji@arm.com#include "cpu/exetrace.hh" 579243SN/A#include "cpu/reg_class.hh" 5810146Sandreas.hansson@arm.com#include "cpu/simple_thread.hh" 599243SN/A#include "cpu/static_inst.hh" 6010619Sandreas.hansson@arm.com#include "cpu/thread_context.hh" 619243SN/A#include "cpu/checker/cpu.hh" 6210211Sandreas.hansson@arm.com#include "debug/Checker.hh" 6310618SOmar.Naji@arm.com#include "sim/full_system.hh" 6410489SOmar.Naji@arm.com#include "sim/sim_object.hh" 659831SN/A#include "sim/stats.hh" 669831SN/A 679831SN/Ausing namespace std; 689831SN/Ausing namespace TheISA; 699831SN/A 7010140SN/Atemplate <class Impl> 7110646Sandreas.hansson@arm.comvoid 729243SN/AChecker<Impl>::advancePC(const Fault &fault) 7310394Swendy.elsasser@arm.com{ 7410394Swendy.elsasser@arm.com if (fault != NoFault) { 759566SN/A curMacroStaticInst = StaticInst::nullStaticInstPtr; 769243SN/A fault->invoke(tc, curStaticInst); 779243SN/A thread->decoder.reset(); 7810140SN/A } else { 7910140SN/A if (curStaticInst) { 8010147Sandreas.hansson@arm.com if (curStaticInst->isLastMicroop()) 8110147Sandreas.hansson@arm.com curMacroStaticInst = StaticInst::nullStaticInstPtr; 8210393Swendy.elsasser@arm.com TheISA::PCState pcState = thread->pcState(); 8310394Swendy.elsasser@arm.com TheISA::advancePC(pcState, curStaticInst); 8410394Swendy.elsasser@arm.com thread->pcState(pcState); 8510394Swendy.elsasser@arm.com DPRINTF(Checker, "Advancing PC to %s.\n", thread->pcState()); 869243SN/A } 879243SN/A } 8810141SN/A} 899726SN/A////////////////////////////////////////////////// 909726SN/A 9110618SOmar.Naji@arm.comtemplate <class Impl> 9210618SOmar.Naji@arm.comvoid 939243SN/AChecker<Impl>::handlePendingInt() 9410620Sandreas.hansson@arm.com{ 9510620Sandreas.hansson@arm.com DPRINTF(Checker, "IRQ detected at PC: %s with %d insts in buffer\n", 9610620Sandreas.hansson@arm.com thread->pcState(), instList.size()); 9710620Sandreas.hansson@arm.com DynInstPtr boundaryInst = NULL; 9810620Sandreas.hansson@arm.com if (!instList.empty()) { 9910889Sandreas.hansson@arm.com // Set the instructions as completed and verify as much as possible. 10010889Sandreas.hansson@arm.com DynInstPtr inst; 10110889Sandreas.hansson@arm.com typename std::list<DynInstPtr>::iterator itr; 10210618SOmar.Naji@arm.com 10310618SOmar.Naji@arm.com for (itr = instList.begin(); itr != instList.end(); itr++) { 10410618SOmar.Naji@arm.com (*itr)->setCompleted(); 10510432SOmar.Naji@arm.com } 10610618SOmar.Naji@arm.com 10710618SOmar.Naji@arm.com inst = instList.front(); 10810618SOmar.Naji@arm.com boundaryInst = instList.back(); 10910432SOmar.Naji@arm.com verify(inst); // verify the instructions 11010246Sandreas.hansson@arm.com inst = NULL; 11110618SOmar.Naji@arm.com } 11210561SOmar.Naji@arm.com if ((!boundaryInst && curMacroStaticInst && 11310561SOmar.Naji@arm.com curStaticInst->isDelayedCommit() && 11410561SOmar.Naji@arm.com !curStaticInst->isLastMicroop()) || 11510394Swendy.elsasser@arm.com (boundaryInst && boundaryInst->isDelayedCommit() && 11610394Swendy.elsasser@arm.com !boundaryInst->isLastMicroop())) { 11710394Swendy.elsasser@arm.com panic("%lli: Trying to take an interrupt in middle of " 11810394Swendy.elsasser@arm.com "a non-interuptable instruction!", curTick()); 11910394Swendy.elsasser@arm.com } 12010394Swendy.elsasser@arm.com boundaryInst = NULL; 12110394Swendy.elsasser@arm.com thread->decoder.reset(); 12210394Swendy.elsasser@arm.com curMacroStaticInst = StaticInst::nullStaticInstPtr; 12310618SOmar.Naji@arm.com} 12410394Swendy.elsasser@arm.com 12510394Swendy.elsasser@arm.comtemplate <class Impl> 12610618SOmar.Naji@arm.comvoid 12710394Swendy.elsasser@arm.comChecker<Impl>::verify(DynInstPtr &completed_inst) 12810246Sandreas.hansson@arm.com{ 12910246Sandreas.hansson@arm.com DynInstPtr inst; 13010246Sandreas.hansson@arm.com 13110140SN/A // Make sure serializing instructions are actually 13210140SN/A // seen as serializing to commit. instList should be 13310140SN/A // empty in these cases. 13410140SN/A if ((completed_inst->isSerializing() || 13510140SN/A completed_inst->isSerializeBefore()) && 1369243SN/A (!instList.empty() ? 1379243SN/A (instList.front()->seqNum != completed_inst->seqNum) : 0)) { 1389567SN/A panic("%lli: Instruction sn:%lli at PC %s is serializing before but is" 1399243SN/A " entering instList with other instructions\n", curTick(), 14010489SOmar.Naji@arm.com completed_inst->seqNum, completed_inst->pcState()); 14110489SOmar.Naji@arm.com } 14210489SOmar.Naji@arm.com 14310489SOmar.Naji@arm.com // Either check this instruction, or add it to a list of 14410489SOmar.Naji@arm.com // instructions waiting to be checked. Instructions must be 14510489SOmar.Naji@arm.com // checked in program order, so if a store has committed yet not 14610489SOmar.Naji@arm.com // completed, there may be some instructions that are waiting 14710489SOmar.Naji@arm.com // behind it that have completed and must be checked. 14810489SOmar.Naji@arm.com if (!instList.empty()) { 14910489SOmar.Naji@arm.com if (youngestSN < completed_inst->seqNum) { 1509243SN/A DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%s to list\n", 1519243SN/A completed_inst->seqNum, completed_inst->pcState()); 1529831SN/A instList.push_back(completed_inst); 1539831SN/A youngestSN = completed_inst->seqNum; 1549831SN/A } 1559831SN/A 1569831SN/A if (!instList.front()->isCompleted()) { 1579243SN/A return; 15810207Sandreas.hansson@arm.com } else { 15910207Sandreas.hansson@arm.com inst = instList.front(); 16010207Sandreas.hansson@arm.com instList.pop_front(); 16110207Sandreas.hansson@arm.com } 16210207Sandreas.hansson@arm.com } else { 16310394Swendy.elsasser@arm.com if (!completed_inst->isCompleted()) { 16410394Swendy.elsasser@arm.com if (youngestSN < completed_inst->seqNum) { 16510394Swendy.elsasser@arm.com DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%s to list\n", 16610394Swendy.elsasser@arm.com completed_inst->seqNum, completed_inst->pcState()); 16710394Swendy.elsasser@arm.com instList.push_back(completed_inst); 16810394Swendy.elsasser@arm.com youngestSN = completed_inst->seqNum; 16910394Swendy.elsasser@arm.com } 17010394Swendy.elsasser@arm.com return; 17110394Swendy.elsasser@arm.com } else { 17210394Swendy.elsasser@arm.com if (youngestSN < completed_inst->seqNum) { 17310394Swendy.elsasser@arm.com inst = completed_inst; 17410394Swendy.elsasser@arm.com youngestSN = completed_inst->seqNum; 17510394Swendy.elsasser@arm.com } else { 17610394Swendy.elsasser@arm.com return; 17710394Swendy.elsasser@arm.com } 17810394Swendy.elsasser@arm.com } 17910394Swendy.elsasser@arm.com } 18010394Swendy.elsasser@arm.com 18110394Swendy.elsasser@arm.com // Make sure a serializing instruction is actually seen as 18210394Swendy.elsasser@arm.com // serializing. instList should be empty here 18310394Swendy.elsasser@arm.com if (inst->isSerializeAfter() && !instList.empty()) { 18410394Swendy.elsasser@arm.com panic("%lli: Instruction sn:%lli at PC %s is serializing after but is" 18510561SOmar.Naji@arm.com " exiting instList with other instructions\n", curTick(), 18610561SOmar.Naji@arm.com completed_inst->seqNum, completed_inst->pcState()); 18710394Swendy.elsasser@arm.com } 18810394Swendy.elsasser@arm.com unverifiedInst = inst; 18910394Swendy.elsasser@arm.com inst = NULL; 19010394Swendy.elsasser@arm.com 19110394Swendy.elsasser@arm.com // Try to check all instructions that are completed, ending if we 19210394Swendy.elsasser@arm.com // run out of instructions to check or if an instruction is not 1939243SN/A // yet completed. 1949243SN/A while (1) { 1959243SN/A DPRINTF(Checker, "Processing instruction [sn:%lli] PC:%s.\n", 19610146Sandreas.hansson@arm.com unverifiedInst->seqNum, unverifiedInst->pcState()); 19710140SN/A unverifiedReq = NULL; 19810466Sandreas.hansson@arm.com unverifiedReq = unverifiedInst->reqToVerify; 19910466Sandreas.hansson@arm.com unverifiedMemData = unverifiedInst->memData; 20010466Sandreas.hansson@arm.com // Make sure results queue is empty 20110146Sandreas.hansson@arm.com while (!result.empty()) { 20210140SN/A result.pop(); 20310140SN/A } 20410140SN/A numCycles++; 20510646Sandreas.hansson@arm.com 20610646Sandreas.hansson@arm.com Fault fault = NoFault; 20710646Sandreas.hansson@arm.com 20810646Sandreas.hansson@arm.com // maintain $r0 semantics 20910646Sandreas.hansson@arm.com thread->setIntReg(ZeroReg, 0); 21010646Sandreas.hansson@arm.com#if THE_ISA == ALPHA_ISA 21110646Sandreas.hansson@arm.com thread->setFloatReg(ZeroReg, 0.0); 21210646Sandreas.hansson@arm.com#endif 21310646Sandreas.hansson@arm.com 21410646Sandreas.hansson@arm.com // Check if any recent PC changes match up with anything we 21510646Sandreas.hansson@arm.com // expect to happen. This is mostly to check if traps or 21610646Sandreas.hansson@arm.com // PC-based events have occurred in both the checker and CPU. 21710646Sandreas.hansson@arm.com if (changedPC) { 21810646Sandreas.hansson@arm.com DPRINTF(Checker, "Changed PC recently to %s\n", 21910646Sandreas.hansson@arm.com thread->pcState()); 22010646Sandreas.hansson@arm.com if (willChangePC) { 22110646Sandreas.hansson@arm.com if (newPCState == thread->pcState()) { 22210646Sandreas.hansson@arm.com DPRINTF(Checker, "Changed PC matches expected PC\n"); 22310646Sandreas.hansson@arm.com } else { 22410646Sandreas.hansson@arm.com warn("%lli: Changed PC does not match expected PC, " 22510646Sandreas.hansson@arm.com "changed: %s, expected: %s", 22610646Sandreas.hansson@arm.com curTick(), thread->pcState(), newPCState); 22710646Sandreas.hansson@arm.com CheckerCPU::handleError(); 22810646Sandreas.hansson@arm.com } 22910646Sandreas.hansson@arm.com willChangePC = false; 23010646Sandreas.hansson@arm.com } 23110646Sandreas.hansson@arm.com changedPC = false; 23210646Sandreas.hansson@arm.com } 23310646Sandreas.hansson@arm.com 23410646Sandreas.hansson@arm.com // Try to fetch the instruction 23510646Sandreas.hansson@arm.com uint64_t fetchOffset = 0; 23610646Sandreas.hansson@arm.com bool fetchDone = false; 23710646Sandreas.hansson@arm.com 23810646Sandreas.hansson@arm.com while (!fetchDone) { 23910646Sandreas.hansson@arm.com Addr fetch_PC = thread->instAddr(); 24010646Sandreas.hansson@arm.com fetch_PC = (fetch_PC & PCMask) + fetchOffset; 24110646Sandreas.hansson@arm.com 24210646Sandreas.hansson@arm.com MachInst machInst; 24310646Sandreas.hansson@arm.com 24410646Sandreas.hansson@arm.com // If not in the middle of a macro instruction 24510140SN/A if (!curMacroStaticInst) { 24610140SN/A // set up memory request for instruction fetch 24710140SN/A memReq = new Request(unverifiedInst->threadNumber, fetch_PC, 24810146Sandreas.hansson@arm.com sizeof(MachInst), 2499243SN/A 0, 25010619Sandreas.hansson@arm.com masterId, 25110619Sandreas.hansson@arm.com fetch_PC, thread->contextId(), 25210618SOmar.Naji@arm.com unverifiedInst->threadNumber); 25310619Sandreas.hansson@arm.com memReq->setVirt(0, fetch_PC, sizeof(MachInst), 25410619Sandreas.hansson@arm.com Request::INST_FETCH, masterId, thread->instAddr()); 25510619Sandreas.hansson@arm.com 25610619Sandreas.hansson@arm.com 25710619Sandreas.hansson@arm.com fault = itb->translateFunctional(memReq, tc, BaseTLB::Execute); 25810619Sandreas.hansson@arm.com 25910619Sandreas.hansson@arm.com if (fault != NoFault) { 26010619Sandreas.hansson@arm.com if (unverifiedInst->getFault() == NoFault) { 26110619Sandreas.hansson@arm.com // In this case the instruction was not a dummy 26210619Sandreas.hansson@arm.com // instruction carrying an ITB fault. In the single 26310619Sandreas.hansson@arm.com // threaded case the ITB should still be able to 26410619Sandreas.hansson@arm.com // translate this instruction; in the SMT case it's 26510619Sandreas.hansson@arm.com // possible that its ITB entry was kicked out. 26610619Sandreas.hansson@arm.com warn("%lli: Instruction PC %s was not found in the " 26710619Sandreas.hansson@arm.com "ITB!", curTick(), thread->pcState()); 26810618SOmar.Naji@arm.com handleError(unverifiedInst); 2699243SN/A 2709243SN/A // go to the next instruction 2719243SN/A advancePC(NoFault); 27210146Sandreas.hansson@arm.com 2739243SN/A // Give up on an ITB fault.. 2749243SN/A delete memReq; 2759243SN/A unverifiedInst = NULL; 2769243SN/A return; 2779243SN/A } else { 2789243SN/A // The instruction is carrying an ITB fault. Handle 2799243SN/A // the fault and see if our results match the CPU on 2809243SN/A // the next tick(). 2819243SN/A fault = unverifiedInst->getFault(); 2829243SN/A delete memReq; 2839243SN/A break; 2849243SN/A } 2859243SN/A } else { 2869243SN/A PacketPtr pkt = new Packet(memReq, MemCmd::ReadReq); 2879243SN/A 2889243SN/A pkt->dataStatic(&machInst); 28910146Sandreas.hansson@arm.com icachePort->sendFunctional(pkt); 2909243SN/A machInst = gtoh(machInst); 2919831SN/A 2929831SN/A delete memReq; 2939831SN/A delete pkt; 2949243SN/A } 2959831SN/A } 2969831SN/A 2979243SN/A if (fault == NoFault) { 2989243SN/A TheISA::PCState pcState = thread->pcState(); 2999243SN/A 30010146Sandreas.hansson@arm.com if (isRomMicroPC(pcState.microPC())) { 3019243SN/A fetchDone = true; 3029831SN/A curStaticInst = 3039831SN/A microcodeRom.fetchMicroop(pcState.microPC(), NULL); 3049831SN/A } else if (!curMacroStaticInst) { 3059243SN/A //We're not in the middle of a macro instruction 3069243SN/A StaticInstPtr instPtr = nullptr; 30710146Sandreas.hansson@arm.com 30810146Sandreas.hansson@arm.com //Predecode, ie bundle up an ExtMachInst 30910143SN/A //If more fetch data is needed, pass it in. 3109243SN/A Addr fetchPC = (pcState.instAddr() & PCMask) + fetchOffset; 3119669SN/A thread->decoder.moreBytes(pcState, fetchPC, machInst); 31210136SN/A 31310136SN/A //If an instruction is ready, decode it. 3149243SN/A //Otherwise, we'll have to fetch beyond the 3159967SN/A //MachInst at the current pc. 31610245Sandreas.hansson@arm.com if (thread->decoder.instReady()) { 31710245Sandreas.hansson@arm.com fetchDone = true; 31810245Sandreas.hansson@arm.com instPtr = thread->decoder.decode(pcState); 3199243SN/A thread->pcState(pcState); 32010286Sandreas.hansson@arm.com } else { 32110286Sandreas.hansson@arm.com fetchDone = false; 3229831SN/A fetchOffset += sizeof(TheISA::MachInst); 3239243SN/A } 3249491SN/A 3259831SN/A //If we decoded an instruction and it's microcoded, 32610136SN/A //start pulling out micro ops 3279491SN/A if (instPtr && instPtr->isMacroop()) { 3289491SN/A curMacroStaticInst = instPtr; 3299831SN/A curStaticInst = 3309243SN/A instPtr->fetchMicroop(pcState.microPC()); 3319669SN/A } else { 3329566SN/A curStaticInst = instPtr; 3339566SN/A } 3349669SN/A } else { 3359669SN/A // Read the next micro op from the macro-op 3369669SN/A curStaticInst = 3379669SN/A curMacroStaticInst->fetchMicroop(pcState.microPC()); 3389669SN/A fetchDone = true; 3399669SN/A } 3409669SN/A } 3419669SN/A } 3429669SN/A // reset decoder on Checker 3439669SN/A thread->decoder.reset(); 34411189Sandreas.hansson@arm.com 3459669SN/A // Check Checker and CPU get same instruction, and record 34610136SN/A // any faults the CPU may have had. 34710286Sandreas.hansson@arm.com Fault unverifiedFault; 34810286Sandreas.hansson@arm.com if (fault == NoFault) { 34910286Sandreas.hansson@arm.com unverifiedFault = unverifiedInst->getFault(); 3509669SN/A 3519669SN/A // Checks that the instruction matches what we expected it to be. 3529669SN/A // Checks both the machine instruction and the PC. 35310286Sandreas.hansson@arm.com validateInst(unverifiedInst); 35410286Sandreas.hansson@arm.com } 3559669SN/A 3569669SN/A // keep an instruction count 3579491SN/A numInst++; 3589243SN/A 3599243SN/A 3609243SN/A // Either the instruction was a fault and we should process the fault, 3619491SN/A // or we should just go ahead execute the instruction. This assumes 3629491SN/A // that the instruction is properly marked as a fault. 3639243SN/A if (fault == NoFault) { 3649243SN/A // Execute Checker instruction and trace 3659243SN/A if (!unverifiedInst->isUnverifiable()) { 36611189Sandreas.hansson@arm.com Trace::InstRecord *traceData = tracer->getInstRecord(curTick(), 3679243SN/A tc, 36810136SN/A curStaticInst, 3699491SN/A pcState(), 3709491SN/A curMacroStaticInst); 3719491SN/A fault = curStaticInst->execute(this, traceData); 37210286Sandreas.hansson@arm.com if (traceData) { 37310286Sandreas.hansson@arm.com traceData->dump(); 37410286Sandreas.hansson@arm.com delete traceData; 3759566SN/A } 3769566SN/A } 3779566SN/A 3789566SN/A if (fault == NoFault && unverifiedFault == NoFault) { 3799566SN/A thread->funcExeInst++; 3809491SN/A // Checks to make sure instrution results are correct. 3819491SN/A validateExecution(unverifiedInst); 3829243SN/A 3839243SN/A if (curStaticInst->isLoad()) { 3849243SN/A ++numLoad; 3859491SN/A } 3869243SN/A } else if (fault != NoFault && unverifiedFault == NoFault) { 3879243SN/A panic("%lli: sn: %lli at PC: %s took a fault in checker " 3889243SN/A "but not in driver CPU\n", curTick(), 38910286Sandreas.hansson@arm.com unverifiedInst->seqNum, unverifiedInst->pcState()); 39010286Sandreas.hansson@arm.com } else if (fault == NoFault && unverifiedFault != NoFault) { 3919243SN/A panic("%lli: sn: %lli at PC: %s took a fault in driver " 39211189Sandreas.hansson@arm.com "CPU but not in checker\n", curTick(), 3939243SN/A unverifiedInst->seqNum, unverifiedInst->pcState()); 3949243SN/A } 3959243SN/A } 3969243SN/A 3979243SN/A // Take any faults here 3989243SN/A if (fault != NoFault) { 3999243SN/A if (FullSystem) { 40010245Sandreas.hansson@arm.com fault->invoke(tc, curStaticInst); 4019243SN/A willChangePC = true; 4029243SN/A newPCState = thread->pcState(); 4039831SN/A DPRINTF(Checker, "Fault, PC is now %s\n", newPCState); 4049243SN/A curMacroStaticInst = StaticInst::nullStaticInstPtr; 4059243SN/A } 4069567SN/A } else { 4079567SN/A advancePC(fault); 4089967SN/A } 4099967SN/A 41010618SOmar.Naji@arm.com if (FullSystem) { 4119243SN/A // @todo: Determine if these should happen only if the 4129243SN/A // instruction hasn't faulted. In the SimpleCPU case this may 4139243SN/A // not be true, but in the O3 case this may be true. 41410146Sandreas.hansson@arm.com Addr oldpc; 4159243SN/A int count = 0; 4169243SN/A do { 4179243SN/A oldpc = thread->instAddr(); 4189243SN/A system->pcEventQueue.service(tc); 4199243SN/A count++; 4209831SN/A } while (oldpc != thread->instAddr()); 4219831SN/A if (count > 1) { 4229831SN/A willChangePC = true; 4239831SN/A newPCState = thread->pcState(); 4249831SN/A DPRINTF(Checker, "PC Event, PC is now %s\n", newPCState); 4259831SN/A } 4269831SN/A } 4279831SN/A 4289243SN/A // @todo: Optionally can check all registers. (Or just those 4299831SN/A // that have been modified). 4309831SN/A validateState(); 4319831SN/A 4329831SN/A // Continue verifying instructions if there's another completed 4339831SN/A // instruction waiting to be verified. 4349831SN/A if (instList.empty()) { 4359831SN/A break; 4369243SN/A } else if (instList.front()->isCompleted()) { 4379831SN/A unverifiedInst = NULL; 4389831SN/A unverifiedInst = instList.front(); 4399831SN/A instList.pop_front(); 44010889Sandreas.hansson@arm.com } else { 44110889Sandreas.hansson@arm.com break; 44210889Sandreas.hansson@arm.com } 44310889Sandreas.hansson@arm.com } 44410889Sandreas.hansson@arm.com unverifiedInst = NULL; 44510889Sandreas.hansson@arm.com} 44610889Sandreas.hansson@arm.com 44710889Sandreas.hansson@arm.comtemplate <class Impl> 44810889Sandreas.hansson@arm.comvoid 44910889Sandreas.hansson@arm.comChecker<Impl>::switchOut() 45010889Sandreas.hansson@arm.com{ 45110889Sandreas.hansson@arm.com instList.clear(); 45210889Sandreas.hansson@arm.com} 45310889Sandreas.hansson@arm.com 45410889Sandreas.hansson@arm.comtemplate <class Impl> 45510889Sandreas.hansson@arm.comvoid 4569831SN/AChecker<Impl>::takeOverFrom(BaseCPU *oldCPU) 4579243SN/A{ 4589831SN/A} 4599831SN/A 4609831SN/Atemplate <class Impl> 4619831SN/Avoid 4629831SN/AChecker<Impl>::validateInst(DynInstPtr &inst) 4639831SN/A{ 4649831SN/A if (inst->instAddr() != thread->instAddr()) { 4659831SN/A warn("%lli: PCs do not match! Inst: %s, checker: %s", 4669831SN/A curTick(), inst->pcState(), thread->pcState()); 4679831SN/A if (changedPC) { 4689831SN/A warn("%lli: Changed PCs recently, may not be an error", 4699831SN/A curTick()); 4709966SN/A } else { 4719831SN/A handleError(inst); 4729831SN/A } 4739831SN/A } 4749831SN/A 4759831SN/A if (curStaticInst != inst->staticInst) { 4769831SN/A warn("%lli: StaticInstPtrs don't match. (%s, %s).\n", curTick(), 4779831SN/A curStaticInst->getName(), inst->staticInst->getName()); 4789831SN/A } 4799831SN/A} 4809831SN/A 4819831SN/Atemplate <class Impl> 4829831SN/Avoid 4839831SN/AChecker<Impl>::validateExecution(DynInstPtr &inst) 4849831SN/A{ 4859831SN/A uint64_t checker_val; 4869243SN/A uint64_t inst_val; 4879243SN/A int idx = -1; 4889831SN/A bool result_mismatch = false; 4899831SN/A 4909831SN/A if (inst->isUnverifiable()) { 4919831SN/A // Unverifiable instructions assume they were executed 4929831SN/A // properly by the CPU. Grab the result from the 4939243SN/A // instruction and write it to the register. 4949831SN/A copyResult(inst, 0, idx); 4959831SN/A } else if (inst->numDestRegs() > 0 && !result.empty()) { 4969831SN/A DPRINTF(Checker, "Dest regs %d, number of checker dest regs %d\n", 4979243SN/A inst->numDestRegs(), result.size()); 49810206Sandreas.hansson@arm.com for (int i = 0; i < inst->numDestRegs() && !result.empty(); i++) { 49910206Sandreas.hansson@arm.com result.front().get(checker_val); 50010206Sandreas.hansson@arm.com result.pop(); 5019567SN/A inst_val = 0; 5029567SN/A inst->template popResult<uint64_t>(inst_val); 5039243SN/A if (checker_val != inst_val) { 5049243SN/A result_mismatch = true; 5059243SN/A idx = i; 5069243SN/A break; 50710146Sandreas.hansson@arm.com } 5089243SN/A } 5099243SN/A } // Checker CPU checks all the saved results in the dyninst passed by 5109243SN/A // the cpu model being checked against the saved results present in 5119243SN/A // the static inst executed in the Checker. Sometimes the number 5129243SN/A // of saved results differs between the dyninst and static inst, but 5139831SN/A // this is ok and not a bug. May be worthwhile to try and correct this. 5149831SN/A 5159831SN/A if (result_mismatch) { 5169831SN/A warn("%lli: Instruction results do not match! (Values may not " 5179831SN/A "actually be integers) Inst: %#x, checker: %#x", 5189831SN/A curTick(), inst_val, checker_val); 5199831SN/A 5209831SN/A // It's useful to verify load values from memory, but in MP 5219243SN/A // systems the value obtained at execute may be different than 5229832SN/A // the value obtained at completion. Similarly DMA can 52310889Sandreas.hansson@arm.com // present the same problem on even UP systems. Thus there is 52410889Sandreas.hansson@arm.com // the option to only warn on loads having a result error. 52510889Sandreas.hansson@arm.com // The load/store queue in Detailed CPU can also cause problems 5269243SN/A // if load/store forwarding is allowed. 5279832SN/A if (inst->isLoad() && warnOnlyOnLoadError) { 5289832SN/A copyResult(inst, inst_val, idx); 5299832SN/A } else { 5309966SN/A handleError(inst); 5319243SN/A } 5329832SN/A } 5339832SN/A 5349243SN/A if (inst->nextInstAddr() != thread->nextInstAddr()) { 5359832SN/A warn("%lli: Instruction next PCs do not match! Inst: %#x, " 5369831SN/A "checker: %#x", 5379832SN/A curTick(), inst->nextInstAddr(), thread->nextInstAddr()); 53810889Sandreas.hansson@arm.com handleError(inst); 53910889Sandreas.hansson@arm.com } 5409831SN/A 5419832SN/A // Checking side effect registers can be difficult if they are not 5429832SN/A // checked simultaneously with the execution of the instruction. 5439977SN/A // This is because other valid instructions may have modified 54410889Sandreas.hansson@arm.com // these registers in the meantime, and their values are not 54510889Sandreas.hansson@arm.com // stored within the DynInst. 5469977SN/A while (!miscRegIdxs.empty()) { 5479977SN/A int misc_reg_idx = miscRegIdxs.front(); 5489977SN/A miscRegIdxs.pop(); 5499832SN/A 5509832SN/A if (inst->tcBase()->readMiscRegNoEffect(misc_reg_idx) != 5519831SN/A thread->readMiscRegNoEffect(misc_reg_idx)) { 5529831SN/A warn("%lli: Misc reg idx %i (side effect) does not match! " 5539831SN/A "Inst: %#x, checker: %#x", 5549243SN/A curTick(), misc_reg_idx, 5559243SN/A inst->tcBase()->readMiscRegNoEffect(misc_reg_idx), 5569243SN/A thread->readMiscRegNoEffect(misc_reg_idx)); 5579243SN/A handleError(inst); 5589831SN/A } 5599831SN/A } 5609726SN/A} 5619243SN/A 56210206Sandreas.hansson@arm.com 56310206Sandreas.hansson@arm.com// This function is weird, if it is called it means the Checker and 56410206Sandreas.hansson@arm.com// O3 have diverged, so panic is called for now. It may be useful 56510206Sandreas.hansson@arm.com// to resynch states and continue if the divergence is a false positive 56610206Sandreas.hansson@arm.comtemplate <class Impl> 5679243SN/Avoid 5689243SN/AChecker<Impl>::validateState() 5699243SN/A{ 5709243SN/A if (updateThisCycle) { 57110146Sandreas.hansson@arm.com // Change this back to warn if divergences end up being false positives 5729243SN/A panic("%lli: Instruction PC %#x results didn't match up, copying all " 5739833SN/A "registers from main CPU", curTick(), unverifiedInst->instAddr()); 5749243SN/A 5759243SN/A // Terribly convoluted way to make sure O3 model does not implode 5769243SN/A bool no_squash_from_TC = unverifiedInst->thread->noSquashFromTC; 5779833SN/A unverifiedInst->thread->noSquashFromTC = true; 5789243SN/A 5799243SN/A // Heavy-weight copying of all registers 5809243SN/A thread->copyArchRegs(unverifiedInst->tcBase()); 5819833SN/A unverifiedInst->thread->noSquashFromTC = no_squash_from_TC; 5829243SN/A 5839243SN/A // Set curStaticInst to unverifiedInst->staticInst 5849243SN/A curStaticInst = unverifiedInst->staticInst; 5859243SN/A // Also advance the PC. Hopefully no PC-based events happened. 5869243SN/A advancePC(NoFault); 58710146Sandreas.hansson@arm.com updateThisCycle = false; 5889243SN/A } 5899243SN/A} 5909567SN/A 5919831SN/Atemplate <class Impl> 5929243SN/Avoid 59310883Sali.jafri@arm.comChecker<Impl>::copyResult(DynInstPtr &inst, uint64_t mismatch_val, 59410883Sali.jafri@arm.com int start_idx) 59510883Sali.jafri@arm.com{ 59610883Sali.jafri@arm.com // We've already popped one dest off the queue, 59711190Sandreas.hansson@arm.com // so do the fix-up then start with the next dest reg; 5989567SN/A if (start_idx >= 0) { 5999567SN/A RegIndex idx = inst->destRegIdx(start_idx); 6009243SN/A switch (regIdxToClass(idx)) { 6019243SN/A case IntRegClass: 6029243SN/A thread->setIntReg(idx, mismatch_val); 6039243SN/A break; 6049243SN/A case FloatRegClass: 6059243SN/A thread->setFloatRegBits(idx - TheISA::FP_Reg_Base, mismatch_val); 6069243SN/A break; 6079831SN/A case CCRegClass: 6089831SN/A thread->setCCReg(idx - TheISA::CC_Reg_Base, mismatch_val); 6099831SN/A break; 6109831SN/A case MiscRegClass: 6119831SN/A thread->setMiscReg(idx - TheISA::Misc_Reg_Base, 6129243SN/A mismatch_val); 6139831SN/A break; 6149831SN/A } 6159243SN/A } 6169243SN/A start_idx++; 6179243SN/A uint64_t res = 0; 6189567SN/A for (int i = start_idx; i < inst->numDestRegs(); i++) { 6199831SN/A RegIndex idx = inst->destRegIdx(i); 6209567SN/A inst->template popResult<uint64_t>(res); 6219243SN/A switch (regIdxToClass(idx)) { 6229243SN/A case IntRegClass: 6239243SN/A thread->setIntReg(idx, res); 6249243SN/A break; 6259243SN/A case FloatRegClass: 6269831SN/A thread->setFloatRegBits(idx - TheISA::FP_Reg_Base, res); 6279243SN/A break; 6289977SN/A case CCRegClass: 6299243SN/A thread->setCCReg(idx - TheISA::CC_Reg_Base, res); 6309243SN/A break; 6319567SN/A case MiscRegClass: 6329831SN/A // Try to get the proper misc register index for ARM here... 6339567SN/A thread->setMiscReg(idx - TheISA::Misc_Reg_Base, res); 6349243SN/A break; 6359243SN/A // else Register is out of range... 6369243SN/A } 6379243SN/A } 6389243SN/A} 6399831SN/A 6409243SN/Atemplate <class Impl> 6419977SN/Avoid 6429243SN/AChecker<Impl>::dumpAndExit(DynInstPtr &inst) 6439243SN/A{ 6449243SN/A cprintf("Error detected, instruction information:\n"); 6459243SN/A cprintf("PC:%s, nextPC:%#x\n[sn:%lli]\n[tid:%i]\n" 6469726SN/A "Completed:%i\n", 6479243SN/A inst->pcState(), 6489243SN/A inst->nextInstAddr(), 6499243SN/A inst->seqNum, 6509243SN/A inst->threadNumber, 6519243SN/A inst->isCompleted()); 6529243SN/A inst->dump(); 65310146Sandreas.hansson@arm.com CheckerCPU::dumpAndExit(); 6549243SN/A} 6559243SN/A 6569243SN/Atemplate <class Impl> 6579243SN/Avoid 6589831SN/AChecker<Impl>::dumpInsts() 6599243SN/A{ 6609831SN/A int num = 0; 6619831SN/A 6629831SN/A InstListIt inst_list_it = --(instList.end()); 6639831SN/A 66410143SN/A cprintf("Inst list size: %i\n", instList.size()); 6659831SN/A 6669831SN/A while (inst_list_it != instList.end()) 6679831SN/A { 6689831SN/A cprintf("Instruction:%i\n", 6699831SN/A num); 6709831SN/A 6719831SN/A cprintf("PC:%s\n[sn:%lli]\n[tid:%i]\n" 6729831SN/A "Completed:%i\n", 6739831SN/A (*inst_list_it)->pcState(), 6749831SN/A (*inst_list_it)->seqNum, 6759831SN/A (*inst_list_it)->threadNumber, 6769831SN/A (*inst_list_it)->isCompleted()); 6779243SN/A 6789831SN/A cprintf("\n"); 6799831SN/A 6809243SN/A inst_list_it--; 6819831SN/A ++num; 6829831SN/A } 6839831SN/A 6849831SN/A} 6859831SN/A 6869831SN/A#endif//__CPU_CHECKER_CPU_IMPL_HH__ 68710913Sandreas.sandberg@arm.com