diff options
132 files changed, 1717 insertions, 907 deletions
diff --git a/SConstruct b/SConstruct index 4ea8ad788..62d90b359 100755 --- a/SConstruct +++ b/SConstruct @@ -473,7 +473,8 @@ CXX_V = readCommand([main['CXX'],'-V'], exception=False) main['GCC'] = CXX_version and CXX_version.find('g++') >= 0 main['SUNCC'] = CXX_V and CXX_V.find('Sun C++') >= 0 main['ICC'] = CXX_V and CXX_V.find('Intel') >= 0 -if main['GCC'] + main['SUNCC'] + main['ICC'] > 1: +main['CLANG'] = CXX_V and CXX_V.find('clang') >= 0 +if main['GCC'] + main['SUNCC'] + main['ICC'] + main['CLANG'] > 1: print 'Error: How can we have two at the same time?' Exit(1) @@ -501,6 +502,24 @@ elif main['SUNCC']: main.Append(CCFLAGS=['-library=stlport4']) main.Append(CCFLAGS=['-xar']) #main.Append(CCFLAGS=['-instances=semiexplicit']) +elif main['CLANG']: + clang_version_re = re.compile(".* version (\d+\.\d+)") + clang_version_match = clang_version_re.match(CXX_version) + if (clang_version_match): + clang_version = clang_version_match.groups()[0] + if compareVersions(clang_version, "2.9") < 0: + print 'Error: clang version 2.9 or newer required.' + print ' Installed version:', clang_version + Exit(1) + else: + print 'Error: Unable to determine clang version.' + Exit(1) + + main.Append(CCFLAGS=['-pipe']) + main.Append(CCFLAGS=['-fno-strict-aliasing']) + main.Append(CCFLAGS=['-Wall', '-Wno-sign-compare', '-Wundef']) + main.Append(CCFLAGS=['-Wno-tautological-compare']) + main.Append(CCFLAGS=['-Wno-self-assign']) else: print 'Error: Don\'t know what compiler options to use for your compiler.' print ' Please fix SConstruct and src/SConscript and try again.' diff --git a/ext/libelf/SConscript b/ext/libelf/SConscript index 7f33990d8..5e92fe08b 100644 --- a/ext/libelf/SConscript +++ b/ext/libelf/SConscript @@ -94,6 +94,8 @@ if m4env['GCC']: major,minor,dot = [int(x) for x in m4env['GCC_VERSION'].split('.')] if major >= 4: m4env.Append(CCFLAGS=['-Wno-pointer-sign']) +if m4env['CLANG']: + m4env.Append(CCFLAGS=['-Wno-initializer-overrides', '-Wno-pointer-sign']) m4env.Append(CCFLAGS=['-Wno-implicit']) del m4env['CPPPATH'] diff --git a/src/SConscript b/src/SConscript index 7fb03e821..679403020 100755 --- a/src/SConscript +++ b/src/SConscript @@ -854,6 +854,9 @@ def makeEnv(label, objsfx, strip = False, **kwargs): swig_env.Append(CCFLAGS='-Wno-unused-label') if compareVersions(env['GCC_VERSION'], '4.6.0') != -1: swig_env.Append(CCFLAGS='-Wno-unused-but-set-variable') + if env['CLANG']: + swig_env.Append(CCFLAGS=['-Wno-unused-label']) + werror_env = new_env.Clone() werror_env.Append(CCFLAGS='-Werror') @@ -928,7 +931,7 @@ def makeEnv(label, objsfx, strip = False, **kwargs): # Debug binary ccflags = {} -if env['GCC']: +if env['GCC'] or env['CLANG']: if sys.platform == 'sunos5': ccflags['debug'] = '-gstabs+' else: diff --git a/src/arch/alpha/tlb.cc b/src/arch/alpha/tlb.cc index 623eafb8a..f1199b9b6 100644 --- a/src/arch/alpha/tlb.cc +++ b/src/arch/alpha/tlb.cc @@ -64,7 +64,7 @@ TLB::TLB(const Params *p) : BaseTLB(p), size(p->size), nlu(0) { table = new TlbEntry[size]; - memset(table, 0, sizeof(TlbEntry[size])); + memset(table, 0, sizeof(TlbEntry) * size); flushCache(); } @@ -280,7 +280,7 @@ void TLB::flushAll() { DPRINTF(TLB, "flushAll\n"); - memset(table, 0, sizeof(TlbEntry[size])); + memset(table, 0, sizeof(TlbEntry) * size); flushCache(); lookupTable.clear(); nlu = 0; diff --git a/src/arch/alpha/tlb.hh b/src/arch/alpha/tlb.hh index b6261769f..1d4b6c6f8 100644 --- a/src/arch/alpha/tlb.hh +++ b/src/arch/alpha/tlb.hh @@ -49,7 +49,7 @@ class ThreadContext; namespace AlphaISA { -class TlbEntry; +struct TlbEntry; class TLB : public BaseTLB { diff --git a/src/arch/arm/insts/static_inst.hh b/src/arch/arm/insts/static_inst.hh index d65555822..c36024ecd 100644 --- a/src/arch/arm/insts/static_inst.hh +++ b/src/arch/arm/insts/static_inst.hh @@ -46,6 +46,7 @@ #include "arch/arm/utility.hh" #include "base/trace.hh" #include "cpu/static_inst.hh" +#include "sim/byteswap.hh" #include "sim/full_system.hh" namespace ArmISA diff --git a/src/arch/arm/insts/vfp.hh b/src/arch/arm/insts/vfp.hh index 57b74d040..b3582a351 100644 --- a/src/arch/arm/insts/vfp.hh +++ b/src/arch/arm/insts/vfp.hh @@ -107,6 +107,9 @@ enum VfpRoundingMode VfpRoundZero = 3 }; +static inline float bitsToFp(uint64_t, float); +static inline uint32_t fpToBits(float); + template <class fpType> static inline bool flushToZero(fpType &op) diff --git a/src/arch/arm/isa.cc b/src/arch/arm/isa.cc index b504550a1..5c2478946 100644 --- a/src/arch/arm/isa.cc +++ b/src/arch/arm/isa.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010-2011 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -39,12 +39,17 @@ */ #include "arch/arm/isa.hh" +#include "config/use_checker.hh" #include "debug/Arm.hh" #include "debug/MiscRegs.hh" #include "sim/faults.hh" #include "sim/stat_control.hh" #include "sim/system.hh" +#if USE_CHECKER +#include "cpu/checker/cpu.hh" +#endif + namespace ArmISA { @@ -279,7 +284,11 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc) PCState pc = tc->pcState(); pc.nextThumb(cpsr.t); pc.nextJazelle(cpsr.j); +#if USE_CHECKER + tc->pcStateNoRecord(pc); +#else tc->pcState(pc); +#endif //USE_CHECKER } else if (misc_reg >= MISCREG_CP15_UNIMP_START && misc_reg < MISCREG_CP15_END) { panic("Unimplemented CP15 register %s wrote with %#x.\n", @@ -382,6 +391,14 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc) oc = sys->getThreadContext(x); oc->getDTBPtr()->allCpusCaching(); oc->getITBPtr()->allCpusCaching(); +#if USE_CHECKER + CheckerCPU *checker = + dynamic_cast<CheckerCPU*>(oc->getCheckerCpuPtr()); + if (checker) { + checker->getDTBPtr()->allCpusCaching(); + checker->getITBPtr()->allCpusCaching(); + } +#endif } return; } @@ -399,6 +416,14 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc) assert(oc->getITBPtr() && oc->getDTBPtr()); oc->getITBPtr()->flushAll(); oc->getDTBPtr()->flushAll(); +#if USE_CHECKER + CheckerCPU *checker = + dynamic_cast<CheckerCPU*>(oc->getCheckerCpuPtr()); + if (checker) { + checker->getITBPtr()->flushAll(); + checker->getDTBPtr()->flushAll(); + } +#endif } return; case MISCREG_ITLBIALL: @@ -417,6 +442,16 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc) bits(newVal, 7,0)); oc->getDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12), bits(newVal, 7,0)); +#if USE_CHECKER + CheckerCPU *checker = + dynamic_cast<CheckerCPU*>(oc->getCheckerCpuPtr()); + if (checker) { + checker->getITBPtr()->flushMvaAsid(mbits(newVal, 31, 12), + bits(newVal, 7,0)); + checker->getDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12), + bits(newVal, 7,0)); + } +#endif } return; case MISCREG_TLBIASIDIS: @@ -427,6 +462,14 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc) assert(oc->getITBPtr() && oc->getDTBPtr()); oc->getITBPtr()->flushAsid(bits(newVal, 7,0)); oc->getDTBPtr()->flushAsid(bits(newVal, 7,0)); +#if USE_CHECKER + CheckerCPU *checker = + dynamic_cast<CheckerCPU*>(oc->getCheckerCpuPtr()); + if (checker) { + checker->getITBPtr()->flushAsid(bits(newVal, 7,0)); + checker->getDTBPtr()->flushAsid(bits(newVal, 7,0)); + } +#endif } return; case MISCREG_TLBIMVAAIS: @@ -437,6 +480,14 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc) assert(oc->getITBPtr() && oc->getDTBPtr()); oc->getITBPtr()->flushMva(mbits(newVal, 31,12)); oc->getDTBPtr()->flushMva(mbits(newVal, 31,12)); +#if USE_CHECKER + CheckerCPU *checker = + dynamic_cast<CheckerCPU*>(oc->getCheckerCpuPtr()); + if (checker) { + checker->getITBPtr()->flushMva(mbits(newVal, 31,12)); + checker->getDTBPtr()->flushMva(mbits(newVal, 31,12)); + } +#endif } return; case MISCREG_ITLBIMVA: diff --git a/src/arch/arm/isa/formats/m5ops.isa b/src/arch/arm/isa/formats/m5ops.isa index 3b08acad7..1eb7d3f65 100644 --- a/src/arch/arm/isa/formats/m5ops.isa +++ b/src/arch/arm/isa/formats/m5ops.isa @@ -59,6 +59,7 @@ def format M5ops() {{ case 0x41: return new Dumpstats(machInst); case 0x42: return new Dumpresetstats(machInst); case 0x43: return new M5checkpoint(machInst); + case 0x4F: return new M5writefile(machInst); case 0x50: return new M5readfile(machInst); case 0x51: return new M5break(machInst); case 0x52: return new M5switchcpu(machInst); diff --git a/src/arch/arm/isa/insts/m5ops.isa b/src/arch/arm/isa/insts/m5ops.isa index da2e10886..a32bf6dfc 100644 --- a/src/arch/arm/isa/insts/m5ops.isa +++ b/src/arch/arm/isa/insts/m5ops.isa @@ -243,7 +243,7 @@ let {{ m5checkpointIop = InstObjParams("m5checkpoint", "M5checkpoint", "PredOp", { "code": m5checkpoint_code, "predicate_test": predicateTest }, - ["IsNonSpeculative"]) + ["IsNonSpeculative", "IsUnverifiable"]) header_output += BasicDeclare.subst(m5checkpointIop) decoder_output += BasicConstructor.subst(m5checkpointIop) exec_output += PredOpExecute.subst(m5checkpointIop) @@ -256,11 +256,27 @@ let {{ m5readfileIop = InstObjParams("m5readfile", "M5readfile", "PredOp", { "code": m5readfileCode, "predicate_test": predicateTest }, - ["IsNonSpeculative"]) + ["IsNonSpeculative", "IsUnverifiable"]) header_output += BasicDeclare.subst(m5readfileIop) decoder_output += BasicConstructor.subst(m5readfileIop) exec_output += PredOpExecute.subst(m5readfileIop) + m5writefileCode = ''' + int n = 4; + uint64_t offset = getArgument(xc->tcBase(), n, sizeof(uint64_t), false); + n = 6; + Addr filenameAddr = getArgument(xc->tcBase(), n, sizeof(Addr), false); + R0 = PseudoInst::writefile(xc->tcBase(), R0, join32to64(R3,R2), offset, + filenameAddr); + ''' + m5writefileIop = InstObjParams("m5writefile", "M5writefile", "PredOp", + { "code": m5writefileCode, + "predicate_test": predicateTest }, + ["IsNonSpeculative"]) + header_output += BasicDeclare.subst(m5writefileIop) + decoder_output += BasicConstructor.subst(m5writefileIop) + exec_output += PredOpExecute.subst(m5writefileIop) + m5breakIop = InstObjParams("m5break", "M5break", "PredOp", { "code": "PseudoInst::debugbreak(xc->tcBase());", "predicate_test": predicateTest }, diff --git a/src/arch/arm/isa/insts/misc.isa b/src/arch/arm/isa/insts/misc.isa index b671843cf..d8ee5e88d 100644 --- a/src/arch/arm/isa/insts/misc.isa +++ b/src/arch/arm/isa/insts/misc.isa @@ -521,7 +521,8 @@ let {{ { "code" : wfeCode, "pred_fixup" : wfePredFixUpCode, "predicate_test" : predicateTest }, - ["IsNonSpeculative", "IsQuiesce", "IsSerializeAfter"]) + ["IsNonSpeculative", "IsQuiesce", + "IsSerializeAfter", "IsUnverifiable"]) header_output += BasicDeclare.subst(wfeIop) decoder_output += BasicConstructor.subst(wfeIop) exec_output += QuiescePredOpExecuteWithFixup.subst(wfeIop) @@ -536,7 +537,8 @@ let {{ ''' wfiIop = InstObjParams("wfi", "WfiInst", "PredOp", \ { "code" : wfiCode, "predicate_test" : predicateTest }, - ["IsNonSpeculative", "IsQuiesce", "IsSerializeAfter"]) + ["IsNonSpeculative", "IsQuiesce", + "IsSerializeAfter", "IsUnverifiable"]) header_output += BasicDeclare.subst(wfiIop) decoder_output += BasicConstructor.subst(wfiIop) exec_output += QuiescePredOpExecute.subst(wfiIop) @@ -557,7 +559,7 @@ let {{ ''' sevIop = InstObjParams("sev", "SevInst", "PredOp", \ { "code" : sevCode, "predicate_test" : predicateTest }, - ["IsNonSpeculative", "IsSquashAfter"]) + ["IsNonSpeculative", "IsSquashAfter", "IsUnverifiable"]) header_output += BasicDeclare.subst(sevIop) decoder_output += BasicConstructor.subst(sevIop) exec_output += PredOpExecute.subst(sevIop) diff --git a/src/arch/arm/isa/templates/basic.isa b/src/arch/arm/isa/templates/basic.isa index 0728b66e3..b3878b89a 100644 --- a/src/arch/arm/isa/templates/basic.isa +++ b/src/arch/arm/isa/templates/basic.isa @@ -49,7 +49,7 @@ def template BasicDeclare {{ // Basic instruction class constructor template. def template BasicConstructor {{ - inline %(class_name)s::%(class_name)s(ExtMachInst machInst) : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) + %(class_name)s::%(class_name)s(ExtMachInst machInst) : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) { %(constructor)s; if (!(condCode == COND_AL || condCode == COND_UC)) { diff --git a/src/arch/arm/miscregs.cc b/src/arch/arm/miscregs.cc index db097c653..c31818377 100644 --- a/src/arch/arm/miscregs.cc +++ b/src/arch/arm/miscregs.cc @@ -411,7 +411,7 @@ decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2) } break; case 11: - if (opc1 >= 0 && opc1 <=7) { + if (opc1 <=7) { switch (crm) { case 0: case 1: diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc index b2ab010c0..9c92ebdf6 100644 --- a/src/arch/arm/table_walker.cc +++ b/src/arch/arm/table_walker.cc @@ -107,8 +107,9 @@ TableWalker::getPort(const std::string &if_name, int idx) Fault TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode _mode, - TLB::Translation *_trans, bool _timing) + TLB::Translation *_trans, bool _timing, bool _functional) { + assert(!(_functional && _timing)); if (!currState) { // For atomic mode, a new WalkerState instance should be only created // once per TLB. For timing mode, a new instance is generated for every @@ -136,6 +137,7 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode _ currState->fault = NoFault; currState->contextId = _cid; currState->timing = _timing; + currState->functional = _functional; currState->mode = _mode; /** @todo These should be cached or grabbed from cached copies in @@ -230,12 +232,21 @@ TableWalker::processWalk() stateQueueL1.size()); stateQueueL1.push_back(currState); currState = NULL; - } else { + } else if (!currState->functional) { port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t), NULL, (uint8_t*)&currState->l1Desc.data, currState->tc->getCpuPtr()->ticks(1), flag); doL1Descriptor(); f = currState->fault; + } else { + RequestPtr req = new Request(l1desc_addr, sizeof(uint32_t), flag); + PacketPtr pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast); + pkt->dataStatic((uint8_t*)&currState->l1Desc.data); + port->sendFunctional(pkt); + doL1Descriptor(); + delete req; + delete pkt; + f = currState->fault; } return f; @@ -566,11 +577,19 @@ TableWalker::doL1Descriptor() port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t), &doL2DescEvent, (uint8_t*)&currState->l2Desc.data, currState->tc->getCpuPtr()->ticks(1)); - } else { + } else if (!currState->functional) { port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t), NULL, (uint8_t*)&currState->l2Desc.data, currState->tc->getCpuPtr()->ticks(1)); doL2Descriptor(); + } else { + RequestPtr req = new Request(l2desc_addr, sizeof(uint32_t), 0); + PacketPtr pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast); + pkt->dataStatic((uint8_t*)&currState->l2Desc.data); + port->sendFunctional(pkt); + doL2Descriptor(); + delete req; + delete pkt; } return; default: diff --git a/src/arch/arm/table_walker.hh b/src/arch/arm/table_walker.hh index 85db1fa77..d4a2e87b5 100644 --- a/src/arch/arm/table_walker.hh +++ b/src/arch/arm/table_walker.hh @@ -294,6 +294,9 @@ class TableWalker : public MemObject /** If the mode is timing or atomic */ bool timing; + /** If the atomic mode should be functional */ + bool functional; + /** Save mode for use in delayed response */ BaseTLB::Mode mode; @@ -354,7 +357,7 @@ class TableWalker : public MemObject virtual Port *getPort(const std::string &if_name, int idx = -1); Fault walk(RequestPtr req, ThreadContext *tc, uint8_t cid, TLB::Mode mode, - TLB::Translation *_trans, bool timing); + TLB::Translation *_trans, bool timing, bool functional = false); void setTlb(TLB *_tlb) { tlb = _tlb; } void memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr, diff --git a/src/arch/arm/tlb.cc b/src/arch/arm/tlb.cc index b19ad5265..0b003e9fb 100644 --- a/src/arch/arm/tlb.cc +++ b/src/arch/arm/tlb.cc @@ -443,8 +443,11 @@ TLB::walkTrickBoxCheck(Addr pa, Addr va, Addr sz, bool is_exec, Fault TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode, - Translation *translation, bool &delay, bool timing) + Translation *translation, bool &delay, bool timing, bool functional) { + // No such thing as a functional timing access + assert(!(timing && functional)); + if (!miscRegValid) { updateMiscReg(tc); DPRINTF(TLBVerbose, "TLB variables changed!\n"); @@ -531,7 +534,7 @@ TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode, DPRINTF(TLB, "TLB Miss: Starting hardware table walker for %#x(%d)\n", vaddr, contextId); fault = tableWalker->walk(req, tc, contextId, mode, translation, - timing); + timing, functional); if (timing && fault == NoFault) { delay = true; // for timing mode, return and wait for table walk @@ -687,6 +690,19 @@ TLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode) } Fault +TLB::translateFunctional(RequestPtr req, ThreadContext *tc, Mode mode) +{ + bool delay = false; + Fault fault; + if (FullSystem) + fault = translateFs(req, tc, mode, NULL, delay, false, true); + else + fault = translateSe(req, tc, mode, NULL, delay, false); + assert(!delay); + return fault; +} + +Fault TLB::translateTiming(RequestPtr req, ThreadContext *tc, Translation *translation, Mode mode) { diff --git a/src/arch/arm/tlb.hh b/src/arch/arm/tlb.hh index 0bf13fe83..daf59f01d 100644 --- a/src/arch/arm/tlb.hh +++ b/src/arch/arm/tlb.hh @@ -180,6 +180,12 @@ class TLB : public BaseTLB */ bool translateFunctional(ThreadContext *tc, Addr vaddr, Addr &paddr); + /** + * Do a functional lookup on the TLB (for checker cpu) that + * behaves like a normal lookup without modifying any page table state. + */ + Fault translateFunctional(RequestPtr req, ThreadContext *tc, Mode mode); + /** Accessor functions for memory attributes for last accessed TLB entry */ void @@ -194,7 +200,8 @@ class TLB : public BaseTLB } Fault translateFs(RequestPtr req, ThreadContext *tc, Mode mode, - Translation *translation, bool &delay, bool timing); + Translation *translation, bool &delay, + bool timing, bool functional = false); Fault translateSe(RequestPtr req, ThreadContext *tc, Mode mode, Translation *translation, bool &delay, bool timing); Fault translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode); diff --git a/src/arch/arm/utility.cc b/src/arch/arm/utility.cc index ac81c7db6..0527e135f 100644 --- a/src/arch/arm/utility.cc +++ b/src/arch/arm/utility.cc @@ -43,6 +43,7 @@ #include "arch/arm/tlb.hh" #include "arch/arm/utility.hh" #include "arch/arm/vtophys.hh" +#include "config/use_checker.hh" #include "cpu/thread_context.hh" #include "mem/fs_translating_port_proxy.hh" #include "sim/full_system.hh" @@ -113,7 +114,11 @@ skipFunction(ThreadContext *tc) { TheISA::PCState newPC = tc->pcState(); newPC.set(tc->readIntReg(ReturnAddressReg) & ~ULL(1)); +#if USE_CHECKER + tc->pcStateNoRecord(newPC); +#else tc->pcState(newPC); +#endif } void diff --git a/src/arch/generic/memhelpers.hh b/src/arch/generic/memhelpers.hh index c753aaf2a..f7bbfa269 100644 --- a/src/arch/generic/memhelpers.hh +++ b/src/arch/generic/memhelpers.hh @@ -64,7 +64,7 @@ readMemAtomic(XC *xc, Trace::InstRecord *traceData, Addr addr, MemT &mem, memset(&mem, 0, sizeof(mem)); Fault fault = readMemTiming(xc, traceData, addr, mem, flags); if (fault == NoFault) { - mem = gtoh(mem); + mem = TheISA::gtoh(mem); if (traceData) traceData->setData(mem); } @@ -92,7 +92,7 @@ writeMemAtomic(XC *xc, Trace::InstRecord *traceData, const MemT &mem, { Fault fault = writeMemTiming(xc, traceData, mem, addr, flags, res); if (fault == NoFault && res != NULL) { - *res = gtoh((MemT)*res); + *res = TheISA::gtoh((MemT)*res); } return fault; } diff --git a/src/arch/mips/faults.cc b/src/arch/mips/faults.cc index 3076e0afe..3697601dc 100644 --- a/src/arch/mips/faults.cc +++ b/src/arch/mips/faults.cc @@ -95,7 +95,7 @@ template <> FaultVals MipsFault<TlbInvalidFault>::vals = template <> FaultVals MipsFault<TlbRefillFault>::vals = { "TLB Refill Exception", 0x180, ExcCodeDummy }; -template <> FaultVals MipsFault<TlbModifiedFault>::vals = +template <> MipsFaultBase::FaultVals MipsFault<TlbModifiedFault>::vals = { "TLB Modified Exception", 0x180, ExcCodeMod }; void diff --git a/src/arch/mips/faults.hh b/src/arch/mips/faults.hh index b90c38e99..98638ac9a 100644 --- a/src/arch/mips/faults.hh +++ b/src/arch/mips/faults.hh @@ -300,7 +300,7 @@ class TlbModifiedFault : public TlbFault<TlbModifiedFault> TlbFault<TlbModifiedFault>(asid, vaddr, vpn, false) {} - ExcCode code() const { return vals.code; } + ExcCode code() const { return MipsFault<TlbModifiedFault>::code(); } }; } // namespace MipsISA diff --git a/src/arch/x86/bios/acpi.hh b/src/arch/x86/bios/acpi.hh index 5040c434c..b10b18092 100644 --- a/src/arch/x86/bios/acpi.hh +++ b/src/arch/x86/bios/acpi.hh @@ -48,11 +48,11 @@ class Port; -class X86ACPIRSDPParams; +struct X86ACPIRSDPParams; -class X86ACPISysDescTableParams; -class X86ACPIRSDTParams; -class X86ACPIXSDTParams; +struct X86ACPISysDescTableParams; +struct X86ACPIRSDTParams; +struct X86ACPIXSDTParams; namespace X86ISA { diff --git a/src/arch/x86/bios/intelmp.cc b/src/arch/x86/bios/intelmp.cc index 974af28a5..4c9c61adb 100644 --- a/src/arch/x86/bios/intelmp.cc +++ b/src/arch/x86/bios/intelmp.cc @@ -72,7 +72,7 @@ template<class T> uint8_t writeOutField(PortProxy* proxy, Addr addr, T val) { - T guestVal = X86ISA::htog(val); + uint64_t guestVal = X86ISA::htog(val); proxy->writeBlob(addr, (uint8_t *)(&guestVal), sizeof(T)); uint8_t checkSum = 0; diff --git a/src/arch/x86/bios/intelmp.hh b/src/arch/x86/bios/intelmp.hh index 0ddb62b8d..4b730ad4b 100644 --- a/src/arch/x86/bios/intelmp.hh +++ b/src/arch/x86/bios/intelmp.hh @@ -54,24 +54,24 @@ class PortProxy; // Config entry types -class X86IntelMPBaseConfigEntryParams; -class X86IntelMPExtConfigEntryParams; +struct X86IntelMPBaseConfigEntryParams; +struct X86IntelMPExtConfigEntryParams; // General table structures -class X86IntelMPConfigTableParams; -class X86IntelMPFloatingPointerParams; +struct X86IntelMPConfigTableParams; +struct X86IntelMPFloatingPointerParams; // Base entry types -class X86IntelMPBusParams; -class X86IntelMPIOAPICParams; -class X86IntelMPIOIntAssignmentParams; -class X86IntelMPLocalIntAssignmentParams; -class X86IntelMPProcessorParams; +struct X86IntelMPBusParams; +struct X86IntelMPIOAPICParams; +struct X86IntelMPIOIntAssignmentParams; +struct X86IntelMPLocalIntAssignmentParams; +struct X86IntelMPProcessorParams; // Extended entry types -class X86IntelMPAddrSpaceMappingParams; -class X86IntelMPBusHierarchyParams; -class X86IntelMPCompatAddrSpaceModParams; +struct X86IntelMPAddrSpaceMappingParams; +struct X86IntelMPBusHierarchyParams; +struct X86IntelMPCompatAddrSpaceModParams; namespace X86ISA { diff --git a/src/arch/x86/bios/smbios.hh b/src/arch/x86/bios/smbios.hh index 9fa6cd6dc..805b03fbb 100644 --- a/src/arch/x86/bios/smbios.hh +++ b/src/arch/x86/bios/smbios.hh @@ -52,9 +52,9 @@ #include "sim/sim_object.hh" class PortProxy; -class X86SMBiosBiosInformationParams; -class X86SMBiosSMBiosStructureParams; -class X86SMBiosSMBiosTableParams; +struct X86SMBiosBiosInformationParams; +struct X86SMBiosSMBiosStructureParams; +struct X86SMBiosSMBiosTableParams; namespace X86ISA { diff --git a/src/base/fast_alloc.cc b/src/base/fast_alloc.cc index 0736d26e2..d370b93e8 100644 --- a/src/base/fast_alloc.cc +++ b/src/base/fast_alloc.cc @@ -40,10 +40,6 @@ #if USE_FAST_ALLOC -#ifdef __GNUC__ -#pragma implementation -#endif - void *FastAlloc::freeLists[Num_Buckets]; #if FAST_ALLOC_STATS diff --git a/src/base/output.hh b/src/base/output.hh index b86e68856..68d9daf85 100644 --- a/src/base/output.hh +++ b/src/base/output.hh @@ -73,6 +73,13 @@ class OutputDirectory */ std::ostream *checkForStdio(const std::string &name) const; + public: + /** Constructor. */ + OutputDirectory(); + + /** Destructor. */ + ~OutputDirectory(); + /** Opens a file (optionally compressed). * * Will open a file as a compressed stream if filename ends in .gz. @@ -84,13 +91,6 @@ class OutputDirectory std::ostream *openFile(const std::string &filename, std::ios_base::openmode mode = std::ios::trunc); - public: - /** Constructor. */ - OutputDirectory(); - - /** Destructor. */ - ~OutputDirectory(); - /** * Sets name of this directory. * @param dir name of this directory diff --git a/src/base/range_map.hh b/src/base/range_map.hh index 7714a0049..5d6547f9b 100644 --- a/src/base/range_map.hh +++ b/src/base/range_map.hh @@ -215,7 +215,7 @@ class range_multimap { std::pair<iterator,iterator> p; p = find(r); - if (p.first->first.start == r.start && p.first->first.end == r.end || + if ((p.first->first.start == r.start && p.first->first.end == r.end) || p.first == tree.end()) return tree.insert(std::make_pair<Range<T>,V>(r, d)); else diff --git a/src/base/remote_gdb.hh b/src/base/remote_gdb.hh index 899c7c29e..15a725438 100644 --- a/src/base/remote_gdb.hh +++ b/src/base/remote_gdb.hh @@ -204,7 +204,7 @@ class BaseRemoteGDB public: HardBreakpoint(BaseRemoteGDB *_gdb, Addr addr); - std::string name() { return gdb->name() + ".hwbkpt"; } + const std::string name() const { return gdb->name() + ".hwbkpt"; } virtual void process(ThreadContext *tc); }; diff --git a/src/base/stl_helpers.hh b/src/base/stl_helpers.hh index a34ca7bb6..689cb626b 100644 --- a/src/base/stl_helpers.hh +++ b/src/base/stl_helpers.hh @@ -72,7 +72,7 @@ class ContainerPrint // Treat all objects in an stl container as pointers to heap objects, // calling delete on each one and zeroing the pointers along the way -template <typename T, template <typename T, typename A> class C, typename A> +template <template <typename T, typename A> class C, typename T, typename A> void deletePointers(C<T,A> &container) { @@ -81,7 +81,7 @@ deletePointers(C<T,A> &container) // Write out all elements in an stl container as a space separated // list enclosed in square brackets -template <typename T, template <typename T, typename A> class C, typename A> +template <template <typename T, typename A> class C, typename T, typename A> std::ostream & operator<<(std::ostream& out, const C<T,A> &vec) { diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py index 19464acbc..fda0a3bc8 100644 --- a/src/cpu/BaseCPU.py +++ b/src/cpu/BaseCPU.py @@ -164,7 +164,6 @@ class BaseCPU(MemObject): self.connectUncachedPorts(uncached_bus) def addPrivateSplitL1Caches(self, ic, dc, iwc = None, dwc = None): - assert(len(self._cached_ports) < 7) self.icache = ic self.dcache = dc self.icache_port = ic.cpu_side @@ -180,6 +179,11 @@ class BaseCPU(MemObject): "dtb_walker_cache.mem_side"] else: self._cached_ports += ["itb.walker.port", "dtb.walker.port"] + # Checker doesn't need its own tlb caches because it does + # functional accesses only + if buildEnv['USE_CHECKER']: + self._cached_ports += ["checker.itb.walker.port", \ + "checker.dtb.walker.port"] def addTwoLevelCacheHierarchy(self, ic, dc, l2c, iwc = None, dwc = None): self.addPrivateSplitL1Caches(ic, dc, iwc, dwc) diff --git a/src/cpu/CheckerCPU.py b/src/cpu/CheckerCPU.py index 132254413..c144c4678 100644 --- a/src/cpu/CheckerCPU.py +++ b/src/cpu/CheckerCPU.py @@ -35,7 +35,7 @@ class CheckerCPU(BaseCPU): exitOnError = Param.Bool(False, "Exit on an error") updateOnError = Param.Bool(False, "Update the checker with the main CPU's state on an error") - warnOnlyOnLoadError = Param.Bool(False, + warnOnlyOnLoadError = Param.Bool(True, "If a load result is incorrect, only print a warning and do not exit") function_trace = Param.Bool(False, "Enable function trace") function_trace_start = Param.Tick(0, "Cycle to start function trace") diff --git a/src/cpu/DummyChecker.py b/src/cpu/DummyChecker.py new file mode 100644 index 000000000..3c276e1d2 --- /dev/null +++ b/src/cpu/DummyChecker.py @@ -0,0 +1,42 @@ +# Copyright (c) 2010-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. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Geoffrey Blake + +from m5.params import * +from BaseCPU import BaseCPU + +class DummyChecker(BaseCPU): + type = 'DummyChecker' diff --git a/src/cpu/SConscript b/src/cpu/SConscript index ff731336a..de59dcc24 100644 --- a/src/cpu/SConscript +++ b/src/cpu/SConscript @@ -134,7 +134,9 @@ if env['TARGET_ISA'] == 'sparc': Source('legiontrace.cc') if env['USE_CHECKER']: + SimObject('DummyChecker.py') Source('checker/cpu.cc') + Source('dummy_checker_builder.cc') DebugFlag('Checker') checker_supports = False for i in CheckerSupportedCPUList: diff --git a/src/cpu/base.cc b/src/cpu/base.cc index d174995a9..977769126 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -53,6 +53,7 @@ #include "base/misc.hh" #include "base/output.hh" #include "base/trace.hh" +#include "config/use_checker.hh" #include "cpu/base.hh" #include "cpu/cpuevent.hh" #include "cpu/profile.hh" @@ -65,6 +66,10 @@ #include "sim/sim_exit.hh" #include "sim/system.hh" +#if USE_CHECKER +#include "cpu/checker/cpu.hh" +#endif + // Hack #include "sim/stat_control.hh" @@ -212,7 +217,10 @@ BaseCPU::BaseCPU(Params *p) schedule(event, p->function_trace_start); } } - interrupts->setCPU(this); + // Check if CPU model has interrupts connected. The CheckerCPU + // cannot take interrupts directly for example. + if (interrupts) + interrupts->setCPU(this); if (FullSystem) { profileEvent = NULL; @@ -351,8 +359,10 @@ BaseCPU::switchOut() } void -BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc) +BaseCPU::takeOverFrom(BaseCPU *oldCPU) { + Port *ic = getPort("icache_port"); + Port *dc = getPort("dcache_port"); assert(threadContexts.size() == oldCPU->threadContexts.size()); _cpuId = oldCPU->cpuId(); @@ -396,6 +406,35 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc) new_dtb_port->setPeer(peer); peer->setPeer(new_dtb_port); } + +#if USE_CHECKER + Port *old_checker_itb_port, *old_checker_dtb_port; + Port *new_checker_itb_port, *new_checker_dtb_port; + + CheckerCPU *oldChecker = + dynamic_cast<CheckerCPU*>(oldTC->getCheckerCpuPtr()); + CheckerCPU *newChecker = + dynamic_cast<CheckerCPU*>(newTC->getCheckerCpuPtr()); + old_checker_itb_port = oldChecker->getITBPtr()->getPort(); + old_checker_dtb_port = oldChecker->getDTBPtr()->getPort(); + new_checker_itb_port = newChecker->getITBPtr()->getPort(); + new_checker_dtb_port = newChecker->getDTBPtr()->getPort(); + + // Move over any table walker ports if they exist for checker + if (new_checker_itb_port && !new_checker_itb_port->isConnected()) { + assert(old_checker_itb_port); + Port *peer = old_checker_itb_port->getPeer();; + new_checker_itb_port->setPeer(peer); + peer->setPeer(new_checker_itb_port); + } + if (new_checker_dtb_port && !new_checker_dtb_port->isConnected()) { + assert(old_checker_dtb_port); + Port *peer = old_checker_dtb_port->getPeer();; + new_checker_dtb_port->setPeer(peer); + peer->setPeer(new_checker_dtb_port); + } +#endif + } interrupts = oldCPU->interrupts; diff --git a/src/cpu/base.hh b/src/cpu/base.hh index 41c79dff6..8250338cc 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -237,16 +237,16 @@ class BaseCPU : public MemObject /// Notify the CPU that the indicated context is now active. The /// delay parameter indicates the number of ticks to wait before /// executing (typically 0 or 1). - virtual void activateContext(int thread_num, int delay) {} + virtual void activateContext(ThreadID thread_num, int delay) {} /// Notify the CPU that the indicated context is now suspended. - virtual void suspendContext(int thread_num) {} + virtual void suspendContext(ThreadID thread_num) {} /// Notify the CPU that the indicated context is now deallocated. - virtual void deallocateContext(int thread_num) {} + virtual void deallocateContext(ThreadID thread_num) {} /// Notify the CPU that the indicated context is now halted. - virtual void haltContext(int thread_num) {} + virtual void haltContext(ThreadID thread_num) {} /// Given a Thread Context pointer return the thread num int findContext(ThreadContext *tc); @@ -275,7 +275,7 @@ class BaseCPU : public MemObject /// Take over execution from the given CPU. Used for warm-up and /// sampling. - virtual void takeOverFrom(BaseCPU *, Port *ic, Port *dc); + virtual void takeOverFrom(BaseCPU *); /** * Number of threads we're actually simulating (<= SMT_MAX_THREADS). diff --git a/src/cpu/base_dyn_inst.hh b/src/cpu/base_dyn_inst.hh index 9089d1069..2b0e26cd2 100644 --- a/src/cpu/base_dyn_inst.hh +++ b/src/cpu/base_dyn_inst.hh @@ -48,12 +48,14 @@ #include <bitset> #include <list> #include <string> +#include <queue> #include "arch/faults.hh" #include "arch/utility.hh" #include "base/fast_alloc.hh" #include "base/trace.hh" #include "config/the_isa.hh" +#include "config/use_checker.hh" #include "cpu/o3/comm.hh" #include "cpu/exetrace.hh" #include "cpu/inst_seq.hh" @@ -175,6 +177,11 @@ class BaseDynInst : public FastAlloc, public RefCounted RequestPtr savedSreqLow; RequestPtr savedSreqHigh; +#if USE_CHECKER + // Need a copy of main request pointer to verify on writes. + RequestPtr reqToVerify; +#endif //USE_CHECKER + /** @todo: Consider making this private. */ public: /** The sequence number of the instruction. */ @@ -247,14 +254,17 @@ class BaseDynInst : public FastAlloc, public RefCounted union Result { uint64_t integer; -// float fp; double dbl; + void set(uint64_t i) { integer = i; } + void set(double d) { dbl = d; } + void get(uint64_t& i) { i = integer; } + void get(double& d) { d = dbl; } }; - /** The result of the instruction; assumes for now that there's only one - * destination register. + /** The result of the instruction; assumes an instruction can have many + * destination registers. */ - Result instResult; + std::queue<Result> instResult; /** Records changes to result? */ bool recordResult; @@ -557,56 +567,68 @@ class BaseDynInst : public FastAlloc, public RefCounted /** Returns the logical register index of the i'th source register. */ RegIndex srcRegIdx(int i) const { return staticInst->srcRegIdx(i); } - /** Returns the result of an integer instruction. */ - uint64_t readIntResult() { return instResult.integer; } + /** Pops a result off the instResult queue */ + template <class T> + void popResult(T& t) + { + if (!instResult.empty()) { + instResult.front().get(t); + instResult.pop(); + } + } - /** Returns the result of a floating point instruction. */ - float readFloatResult() { return (float)instResult.dbl; } + /** Read the most recent result stored by this instruction */ + template <class T> + void readResult(T& t) + { + instResult.back().get(t); + } - /** Returns the result of a floating point (double) instruction. */ - double readDoubleResult() { return instResult.dbl; } + /** Pushes a result onto the instResult queue */ + template <class T> + void setResult(T t) + { + if (recordResult) { + Result instRes; + instRes.set(t); + instResult.push(instRes); + } + } /** Records an integer register being set to a value. */ void setIntRegOperand(const StaticInst *si, int idx, uint64_t val) { - if (recordResult) - instResult.integer = val; + setResult<uint64_t>(val); } /** Records an fp register being set to a value. */ void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val, int width) { - if (recordResult) { - if (width == 32) - instResult.dbl = (double)val; - else if (width == 64) - instResult.dbl = val; - else - panic("Unsupported width!"); + if (width == 32 || width == 64) { + setResult<double>(val); + } else { + panic("Unsupported width!"); } } /** Records an fp register being set to a value. */ void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val) { - if (recordResult) - instResult.dbl = (double)val; + setResult<double>(val); } /** Records an fp register being set to an integer value. */ void setFloatRegOperandBits(const StaticInst *si, int idx, uint64_t val, int width) { - if (recordResult) - instResult.integer = val; + setResult<uint64_t>(val); } /** Records an fp register being set to an integer value. */ void setFloatRegOperandBits(const StaticInst *si, int idx, uint64_t val) { - if (recordResult) - instResult.integer = val; + setResult<uint64_t>(val); } /** Records that one of the source registers is ready. */ @@ -871,6 +893,12 @@ BaseDynInst<Impl>::readMem(Addr addr, uint8_t *data, effAddr = req->getVaddr(); effSize = size; effAddrValid = true; +#if USE_CHECKER + if (reqToVerify != NULL) { + delete reqToVerify; + } + reqToVerify = new Request(*req); +#endif //USE_CHECKER fault = cpu->read(req, sreqLow, sreqHigh, data, lqIdx); } else { // Commit will have to clean up whatever happened. Set this @@ -926,6 +954,12 @@ BaseDynInst<Impl>::writeMem(uint8_t *data, unsigned size, effAddr = req->getVaddr(); effSize = size; effAddrValid = true; +#if USE_CHECKER + if (reqToVerify != NULL) { + delete reqToVerify; + } + reqToVerify = new Request(*req); +#endif // USE_CHECKER fault = cpu->write(req, sreqLow, sreqHigh, data, sqIdx); } diff --git a/src/cpu/base_dyn_inst_impl.hh b/src/cpu/base_dyn_inst_impl.hh index a37ec5e25..d2ecd01ff 100644 --- a/src/cpu/base_dyn_inst_impl.hh +++ b/src/cpu/base_dyn_inst_impl.hh @@ -48,6 +48,7 @@ #include "base/cprintf.hh" #include "base/trace.hh" #include "config/the_isa.hh" +#include "config/use_checker.hh" #include "cpu/base_dyn_inst.hh" #include "cpu/exetrace.hh" #include "debug/DynInst.hh" @@ -117,7 +118,6 @@ BaseDynInst<Impl>::initVars() reqMade = false; readyRegs = 0; - instResult.integer = 0; recordResult = true; status.reset(); @@ -157,6 +157,10 @@ BaseDynInst<Impl>::initVars() #ifdef DEBUG cpu->snList.insert(seqNum); #endif + +#if USE_CHECKER + reqToVerify = NULL; +#endif } template <class Impl> @@ -182,6 +186,11 @@ BaseDynInst<Impl>::~BaseDynInst() #ifdef DEBUG cpu->snList.erase(seqNum); #endif + +#if USE_CHECKER + if (reqToVerify) + delete reqToVerify; +#endif // USE_CHECKER } #ifdef DEBUG diff --git a/src/cpu/checker/cpu.cc b/src/cpu/checker/cpu.cc index ec4496eb4..c905c62eb 100644 --- a/src/cpu/checker/cpu.cc +++ b/src/cpu/checker/cpu.cc @@ -1,4 +1,16 @@ /* + * 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. + * * Copyright (c) 2006 The Regents of The University of Michigan * All rights reserved. * @@ -26,6 +38,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Kevin Lim + * Geoffrey Blake */ #include <list> @@ -38,10 +51,11 @@ #include "cpu/simple_thread.hh" #include "cpu/static_inst.hh" #include "cpu/thread_context.hh" +#include "params/CheckerCPU.hh" +#include "sim/tlb.hh" using namespace std; -//The CheckerCPU does alpha only -using namespace AlphaISA; +using namespace TheISA; void CheckerCPU::init() @@ -52,6 +66,8 @@ CheckerCPU::CheckerCPU(Params *p) : BaseCPU(p), thread(NULL), tc(NULL) { memReq = NULL; + curStaticInst = NULL; + curMacroStaticInst = NULL; numInst = 0; startNumInst = 0; @@ -66,13 +82,14 @@ CheckerCPU::CheckerCPU(Params *p) itb = p->itb; dtb = p->dtb; systemPtr = NULL; - process = p->process; - thread = new SimpleThread(this, /* thread_num */ 0, process); + workload = p->workload; + // XXX: This is a hack to get this to work some + thread = new SimpleThread(this, /* thread_num */ 0, workload[0], itb, dtb); tc = thread->getTC(); threadContexts.push_back(tc); - result.integer = 0; + updateOnError = true; } CheckerCPU::~CheckerCPU() @@ -107,216 +124,224 @@ CheckerCPU::setDcachePort(Port *dcache_port) void CheckerCPU::serialize(ostream &os) { -/* - BaseCPU::serialize(os); - SERIALIZE_SCALAR(inst); - nameOut(os, csprintf("%s.xc", name())); - thread->serialize(os); - cacheCompletionEvent.serialize(os); -*/ } void CheckerCPU::unserialize(Checkpoint *cp, const string §ion) { -/* - BaseCPU::unserialize(cp, section); - UNSERIALIZE_SCALAR(inst); - thread->unserialize(cp, csprintf("%s.xc", section)); -*/ } -template <class T> Fault -CheckerCPU::read(Addr addr, T &data, unsigned flags) +CheckerCPU::readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags) { - // need to fill in CPU & thread IDs here - memReq = new Request(); + Fault fault = NoFault; + unsigned blockSize = dcachePort->peerBlockSize(); + int fullSize = size; + Addr secondAddr = roundDown(addr + size - 1, blockSize); + bool checked_flags = false; + bool flags_match = true; + Addr pAddr = 0x0; + + + if (secondAddr > addr) + size = secondAddr - addr; + + // Need to account for multiple accesses like the Atomic and TimingSimple + while (1) { + memReq = new Request(); + memReq->setVirt(0, addr, size, flags, thread->pcState().instAddr()); + + // translate to physical address + fault = dtb->translateFunctional(memReq, tc, BaseTLB::Read); + + if (!checked_flags && fault == NoFault && unverifiedReq) { + flags_match = checkFlags(unverifiedReq, memReq->getVaddr(), + memReq->getPaddr(), memReq->getFlags()); + pAddr = memReq->getPaddr(); + checked_flags = true; + } - memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC()); + // Now do the access + if (fault == NoFault && + !memReq->getFlags().isSet(Request::NO_ACCESS)) { + PacketPtr pkt = new Packet(memReq, + memReq->isLLSC() ? + MemCmd::LoadLockedReq : MemCmd::ReadReq, + Packet::Broadcast); + + pkt->dataStatic(data); + + if (!(memReq->isUncacheable() || memReq->isMmappedIpr())) { + // Access memory to see if we have the same data + dcachePort->sendFunctional(pkt); + } else { + // Assume the data is correct if it's an uncached access + memcpy(data, unverifiedMemData, size); + } + + delete memReq; + memReq = NULL; + delete pkt; + } - // translate to physical address - dtb->translateAtomic(memReq, tc, false); + if (fault != NoFault) { + if (memReq->isPrefetch()) { + fault = NoFault; + } + delete memReq; + memReq = NULL; + break; + } - PacketPtr pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast); + if (memReq != NULL) { + delete memReq; + } - pkt->dataStatic(&data); + //If we don't need to access a second cache line, stop now. + if (secondAddr <= addr) + { + break; + } - if (!(memReq->isUncacheable())) { - // Access memory to see if we have the same data - dcachePort->sendFunctional(pkt); - } else { - // Assume the data is correct if it's an uncached access - memcpy(&data, &unverifiedResult.integer, sizeof(T)); + // Setup for accessing next cache line + data += size; + unverifiedMemData += size; + size = addr + fullSize - secondAddr; + addr = secondAddr; } - delete pkt; + if (!flags_match) { + warn("%lli: Flags do not match CPU:%#x %#x %#x Checker:%#x %#x %#x\n", + curTick(), unverifiedReq->getVaddr(), unverifiedReq->getPaddr(), + unverifiedReq->getFlags(), addr, pAddr, flags); + handleError(); + } - return NoFault; + return fault; } -#ifndef DOXYGEN_SHOULD_SKIP_THIS - -template -Fault -CheckerCPU::read(Addr addr, uint64_t &data, unsigned flags); - -template -Fault -CheckerCPU::read(Addr addr, uint32_t &data, unsigned flags); - -template Fault -CheckerCPU::read(Addr addr, uint16_t &data, unsigned flags); - -template -Fault -CheckerCPU::read(Addr addr, uint8_t &data, unsigned flags); - -#endif //DOXYGEN_SHOULD_SKIP_THIS - -template<> -Fault -CheckerCPU::read(Addr addr, double &data, unsigned flags) +CheckerCPU::writeMem(uint8_t *data, unsigned size, + Addr addr, unsigned flags, uint64_t *res) { - return read(addr, *(uint64_t*)&data, flags); -} + Fault fault = NoFault; + bool checked_flags = false; + bool flags_match = true; + Addr pAddr = 0x0; -template<> -Fault -CheckerCPU::read(Addr addr, float &data, unsigned flags) -{ - return read(addr, *(uint32_t*)&data, flags); -} + unsigned blockSize = dcachePort->peerBlockSize(); + int fullSize = size; -template<> -Fault -CheckerCPU::read(Addr addr, int32_t &data, unsigned flags) -{ - return read(addr, (uint32_t&)data, flags); -} + Addr secondAddr = roundDown(addr + size - 1, blockSize); -template <class T> -Fault -CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) -{ - // need to fill in CPU & thread IDs here - memReq = new Request(); - - memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC()); - - // translate to physical address - dtb->translateAtomic(memReq, tc, true); - - // Can compare the write data and result only if it's cacheable, - // not a store conditional, or is a store conditional that - // succeeded. - // @todo: Verify that actual memory matches up with these values. - // Right now it only verifies that the instruction data is the - // same as what was in the request that got sent to memory; there - // is no verification that it is the same as what is in memory. - // This is because the LSQ would have to be snooped in the CPU to - // verify this data. - if (unverifiedReq && - !(unverifiedReq->isUncacheable()) && - (!(unverifiedReq->isLLSC()) || - ((unverifiedReq->isLLSC()) && - unverifiedReq->getExtraData() == 1))) { - T inst_data; -/* - // This code would work if the LSQ allowed for snooping. - PacketPtr pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast); - pkt.dataStatic(&inst_data); + if (secondAddr > addr) + size = secondAddr - addr; - dcachePort->sendFunctional(pkt); + // Need to account for a multiple access like Atomic and Timing CPUs + while (1) { + memReq = new Request(); + memReq->setVirt(0, addr, size, flags, thread->pcState().instAddr()); - delete pkt; -*/ - memcpy(&inst_data, unverifiedMemData, sizeof(T)); + // translate to physical address + fault = dtb->translateFunctional(memReq, tc, BaseTLB::Write); - if (data != inst_data) { - warn("%lli: Store value does not match value in memory! " - "Instruction: %#x, memory: %#x", - curTick(), inst_data, data); - handleError(); + if (!checked_flags && fault == NoFault && unverifiedReq) { + flags_match = checkFlags(unverifiedReq, memReq->getVaddr(), + memReq->getPaddr(), memReq->getFlags()); + pAddr = memReq->getPaddr(); + checked_flags = true; } - } - - // Assume the result was the same as the one passed in. This checker - // doesn't check if the SC should succeed or fail, it just checks the - // value. - if (res && unverifiedReq->scResultValid()) - *res = unverifiedReq->getExtraData(); - - return NoFault; -} - - -#ifndef DOXYGEN_SHOULD_SKIP_THIS -template -Fault -CheckerCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res); - -template -Fault -CheckerCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res); - -template -Fault -CheckerCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res); - -template -Fault -CheckerCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res); - -#endif //DOXYGEN_SHOULD_SKIP_THIS -template<> -Fault -CheckerCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) -{ - return write(*(uint64_t*)&data, addr, flags, res); -} - -template<> -Fault -CheckerCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) -{ - return write(*(uint32_t*)&data, addr, flags, res); -} + /* + * We don't actually check memory for the store because there + * is no guarantee it has left the lsq yet, and therefore we + * can't verify the memory on stores without lsq snooping + * enabled. This is left as future work for the Checker: LSQ snooping + * and memory validation after stores have committed. + */ + + delete memReq; + + //If we don't need to access a second cache line, stop now. + if (fault != NoFault || secondAddr <= addr) + { + if (fault != NoFault && memReq->isPrefetch()) { + fault = NoFault; + } + break; + } -template<> -Fault -CheckerCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) -{ - return write((uint32_t)data, addr, flags, res); + //Update size and access address + size = addr + fullSize - secondAddr; + //And access the right address. + addr = secondAddr; + } + + if (!flags_match) { + warn("%lli: Flags do not match CPU:%#x %#x Checker:%#x %#x %#x\n", + curTick(), unverifiedReq->getVaddr(), unverifiedReq->getPaddr(), + unverifiedReq->getFlags(), addr, pAddr, flags); + handleError(); + } + + // Assume the result was the same as the one passed in. This checker + // doesn't check if the SC should succeed or fail, it just checks the + // value. + if (unverifiedReq && res && unverifiedReq->extraDataValid()) + *res = unverifiedReq->getExtraData(); + + // Entire purpose here is to make sure we are getting the + // same data to send to the mem system as the CPU did. + // Cannot check this is actually what went to memory because + // there stores can be in ld/st queue or coherent operations + // overwriting values. + bool extraData; + if (unverifiedReq) { + extraData = unverifiedReq->extraDataValid() ? + unverifiedReq->getExtraData() : 1; + } + + if (unverifiedReq && unverifiedMemData && + memcmp(data, unverifiedMemData, fullSize) && extraData) { + warn("%lli: Store value does not match value sent to memory!\ + data: %#x inst_data: %#x", curTick(), data, + unverifiedMemData); + handleError(); + } + + return fault; } - Addr CheckerCPU::dbg_vtophys(Addr addr) { return vtophys(tc, addr); } +/** + * Checks if the flags set by the Checker and Checkee match. + */ bool -CheckerCPU::checkFlags(Request *req) +CheckerCPU::checkFlags(Request *unverified_req, Addr vAddr, + Addr pAddr, int flags) { - // Remove any dynamic flags that don't have to do with the request itself. - unsigned flags = unverifiedReq->getFlags(); - unsigned mask = LOCKED | PHYSICAL | VPTE | ALTMODE | UNCACHEABLE | PREFETCH; - flags = flags & (mask); - if (flags == req->getFlags()) { + Addr unverifiedVAddr = unverified_req->getVaddr(); + Addr unverifiedPAddr = unverified_req->getPaddr(); + int unverifiedFlags = unverified_req->getFlags(); + + if (unverifiedVAddr != vAddr || + unverifiedPAddr != pAddr || + unverifiedFlags != flags) { return false; - } else { - return true; } + + return true; } void CheckerCPU::dumpAndExit() { - warn("%lli: Checker PC:%#x, next PC:%#x", - curTick(), thread->readPC(), thread->readNextPC()); + warn("%lli: Checker PC:%s", + curTick(), thread->pcState()); panic("Checker found an error!"); } diff --git a/src/cpu/checker/cpu.hh b/src/cpu/checker/cpu.hh index a3e95137d..6f5125625 100644 --- a/src/cpu/checker/cpu.hh +++ b/src/cpu/checker/cpu.hh @@ -1,4 +1,16 @@ /* + * 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. + * * Copyright (c) 2006 The Regents of The University of Michigan * All rights reserved. * @@ -35,6 +47,7 @@ #include <map> #include <queue> +#include "arch/predecoder.hh" #include "arch/types.hh" #include "base/statistics.hh" #include "cpu/base.hh" @@ -42,6 +55,8 @@ #include "cpu/pc_event.hh" #include "cpu/simple_thread.hh" #include "cpu/static_inst.hh" +#include "debug/Checker.hh" +#include "params/CheckerCPU.hh" #include "sim/eventq.hh" // forward declarations @@ -52,12 +67,6 @@ namespace TheISA template <class> class BaseDynInst; -class CheckerCPUParams; -class Checkpoint; -class MemInterface; -class PhysicalMemory; -class Process; -class Processor; class ThreadContext; class Request; @@ -90,11 +99,11 @@ class CheckerCPU : public BaseCPU public: typedef CheckerCPUParams Params; const Params *params() const - { return reinterpret_cast<const Params *>(_params); } + { return reinterpret_cast<const Params *>(_params); } CheckerCPU(Params *p); virtual ~CheckerCPU(); - Process *process; + std::vector<Process*> workload; void setSystem(System *system); @@ -127,19 +136,25 @@ class CheckerCPU : public BaseCPU union Result { uint64_t integer; -// float fp; double dbl; + void set(uint64_t i) { integer = i; } + void set(double d) { dbl = d; } + void get(uint64_t& i) { i = integer; } + void get(double& d) { d = dbl; } }; - Result result; + // ISAs like ARM can have multiple destination registers to check, + // keep them all in a std::queue + std::queue<Result> result; // current instruction - MachInst machInst; + TheISA::MachInst machInst; // Pointer to the one memory request. RequestPtr memReq; StaticInstPtr curStaticInst; + StaticInstPtr curMacroStaticInst; // number of simulated instructions Counter numInst; @@ -147,6 +162,9 @@ class CheckerCPU : public BaseCPU std::queue<int> miscRegIdxs; + TheISA::TLB* getITBPtr() { return itb; } + TheISA::TLB* getDTBPtr() { return dtb; } + virtual Counter totalInstructions() const { return 0; @@ -159,12 +177,6 @@ class CheckerCPU : public BaseCPU virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); - template <class T> - Fault read(Addr addr, T &data, unsigned flags); - - template <class T> - Fault write(T data, Addr addr, unsigned flags, uint64_t *res); - // These functions are only used in CPU models that split // effective address computation from the actual memory access. void setEA(Addr EA) { panic("SimpleCPU::setEA() not implemented\n"); } @@ -198,17 +210,25 @@ class CheckerCPU : public BaseCPU return thread->readFloatRegBits(reg_idx); } + template <class T> + void setResult(T t) + { + Result instRes; + instRes.set(t); + result.push(instRes); + } + void setIntRegOperand(const StaticInst *si, int idx, uint64_t val) { thread->setIntReg(si->destRegIdx(idx), val); - result.integer = val; + setResult<uint64_t>(val); } void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val) { int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; thread->setFloatReg(reg_idx, val); - result.dbl = (double)val; + setResult<double>(val); } void setFloatRegOperandBits(const StaticInst *si, int idx, @@ -216,12 +236,26 @@ class CheckerCPU : public BaseCPU { int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; thread->setFloatRegBits(reg_idx, val); - result.integer = val; + setResult<uint64_t>(val); } - uint64_t instAddr() { return thread->instAddr(); } + bool readPredicate() { return thread->readPredicate(); } + void setPredicate(bool val) + { + thread->setPredicate(val); + } - uint64_t nextInstAddr() { return thread->nextInstAddr(); } + TheISA::PCState pcState() { return thread->pcState(); } + void pcState(const TheISA::PCState &val) + { + DPRINTF(Checker, "Changing PC to %s, old PC %s.\n", + val, thread->pcState()); + thread->pcState(val); + } + Addr instAddr() { return thread->instAddr(); } + Addr nextInstAddr() { return thread->nextInstAddr(); } + MicroPC microPC() { return thread->microPC(); } + ////////////////////////////////////////// MiscReg readMiscRegNoEffect(int misc_reg) { @@ -235,7 +269,6 @@ class CheckerCPU : public BaseCPU void setMiscRegNoEffect(int misc_reg, const MiscReg &val) { - result.integer = val; miscRegIdxs.push(misc_reg); return thread->setMiscRegNoEffect(misc_reg, val); } @@ -246,8 +279,25 @@ class CheckerCPU : public BaseCPU return thread->setMiscReg(misc_reg, val); } - void recordPCChange(uint64_t val) { changedPC = true; newPC = val; } - void recordNextPCChange(uint64_t val) { changedNextPC = true; } + MiscReg readMiscRegOperand(const StaticInst *si, int idx) + { + int reg_idx = si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag; + return thread->readMiscReg(reg_idx); + } + + void setMiscRegOperand( + const StaticInst *si, int idx, const MiscReg &val) + { + int reg_idx = si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag; + return thread->setMiscReg(reg_idx, val); + } + ///////////////////////////////////////// + + void recordPCChange(const TheISA::PCState &val) + { + changedPC = true; + newPCState = val; + } void demapPage(Addr vaddr, uint64_t asn) { @@ -265,8 +315,17 @@ class CheckerCPU : public BaseCPU this->dtb->demapPage(vaddr, asn); } + Fault readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags); + Fault writeMem(uint8_t *data, unsigned size, + Addr addr, unsigned flags, uint64_t *res); + + void setStCondFailures(unsigned sc_failures) + {} + ///////////////////////////////////////////////////// + Fault hwrei() { return thread->hwrei(); } bool simPalCheck(int palFunc) { return thread->simPalCheck(palFunc); } + void wakeup() { } // Assume that the normal CPU's call to syscall was successful. // The checker's state would have already been updated by the syscall. void syscall(uint64_t callnum) { } @@ -277,7 +336,8 @@ class CheckerCPU : public BaseCPU dumpAndExit(); } - bool checkFlags(Request *req); + bool checkFlags(Request *unverified_req, Addr vAddr, + Addr pAddr, int flags); void dumpAndExit(); @@ -290,7 +350,7 @@ class CheckerCPU : public BaseCPU bool changedPC; bool willChangePC; - uint64_t newPC; + TheISA::PCState newPCState; bool changedNextPC; bool exitOnError; bool updateOnError; @@ -305,24 +365,31 @@ class CheckerCPU : public BaseCPU * template instantiations of the Checker must be placed at the bottom * of checker/cpu.cc. */ -template <class DynInstPtr> +template <class Impl> class Checker : public CheckerCPU { + private: + typedef typename Impl::DynInstPtr DynInstPtr; + public: Checker(Params *p) - : CheckerCPU(p), updateThisCycle(false), unverifiedInst(NULL) + : CheckerCPU(p), updateThisCycle(false), unverifiedInst(NULL), + predecoder(NULL) { } void switchOut(); void takeOverFrom(BaseCPU *oldCPU); + void advancePC(Fault fault); + void verify(DynInstPtr &inst); void validateInst(DynInstPtr &inst); void validateExecution(DynInstPtr &inst); void validateState(); - void copyResult(DynInstPtr &inst); + void copyResult(DynInstPtr &inst, uint64_t mismatch_val, int start_idx); + void handlePendingInt(); private: void handleError(DynInstPtr &inst) @@ -339,6 +406,7 @@ class Checker : public CheckerCPU bool updateThisCycle; DynInstPtr unverifiedInst; + TheISA::Predecoder predecoder; std::list<DynInstPtr> instList; typedef typename std::list<DynInstPtr>::iterator InstListIt; diff --git a/src/cpu/checker/cpu_impl.hh b/src/cpu/checker/cpu_impl.hh index 7d8cc8a19..7a99feb06 100644 --- a/src/cpu/checker/cpu_impl.hh +++ b/src/cpu/checker/cpu_impl.hh @@ -1,4 +1,16 @@ /* + * 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. + * * Copyright (c) 2006 The Regents of The University of Michigan * All rights reserved. * @@ -26,6 +38,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Kevin Lim + * Geoffrey Blake */ #include <list> @@ -34,25 +47,93 @@ #include "arch/vtophys.hh" #include "base/refcnt.hh" #include "config/the_isa.hh" -#include "cpu/checker/cpu.hh" #include "cpu/base_dyn_inst.hh" +#include "cpu/exetrace.hh" #include "cpu/simple_thread.hh" #include "cpu/static_inst.hh" #include "cpu/thread_context.hh" +#include "cpu/checker/cpu.hh" +#include "debug/Checker.hh" #include "sim/full_system.hh" #include "sim/sim_object.hh" #include "sim/stats.hh" using namespace std; -//The CheckerCPU does alpha only -using namespace AlphaISA; +using namespace TheISA; + +template <class Impl> +void +Checker<Impl>::advancePC(Fault fault) +{ + 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 DynInstPtr> +template <class Impl> void -Checker<DynInstPtr>::verify(DynInstPtr &completed_inst) +Checker<Impl>::verify(DynInstPtr &completed_inst) { DynInstPtr inst; + // 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()); + } + // Either check this instruction, or add it to a list of // instructions waiting to be checked. Instructions must be // checked in program order, so if a store has committed yet not @@ -60,8 +141,8 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst) // behind it that have completed and must be checked. if (!instList.empty()) { if (youngestSN < completed_inst->seqNum) { - 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()); instList.push_back(completed_inst); youngestSN = completed_inst->seqNum; } @@ -75,8 +156,8 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst) } else { if (!completed_inst->isCompleted()) { if (youngestSN < completed_inst->seqNum) { - 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()); instList.push_back(completed_inst); youngestSN = completed_inst->seqNum; } @@ -91,17 +172,29 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst) } } + // 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()); + } unverifiedInst = inst; + inst = NULL; // Try to check all instructions that are completed, ending if we // run out of instructions to check or if an instruction is not // yet completed. while (1) { - 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(); + } numCycles++; Fault fault = NoFault; @@ -116,15 +209,15 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst) // expect to happen. This is mostly to check if traps or // PC-based events have occurred in both the checker and CPU. if (changedPC) { - DPRINTF(Checker, "Changed PC recently to %#x\n", - thread->readPC()); + DPRINTF(Checker, "Changed PC recently to %s\n", + thread->pcState()); if (willChangePC) { - if (newPC == thread->readPC()) { + if (newPCState == thread->pcState()) { DPRINTF(Checker, "Changed PC matches expected PC\n"); } else { warn("%lli: Changed PC does not match expected PC, " - "changed: %#x, expected: %#x", - curTick(), thread->readPC(), newPC); + "changed: %s, expected: %s", + curTick(), thread->pcState(), newPCState); CheckerCPU::handleError(); } willChangePC = false; @@ -133,118 +226,186 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst) } if (changedNextPC) { DPRINTF(Checker, "Changed NextPC recently to %#x\n", - thread->readNextPC()); + thread->nextInstAddr()); changedNextPC = false; } // Try to fetch the instruction + uint64_t fetchOffset = 0; + bool fetchDone = false; + + while (!fetchDone) { + Addr fetch_PC = thread->instAddr(); + fetch_PC = (fetch_PC & PCMask) + fetchOffset; + + // 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()); + + + fault = itb->translateFunctional(memReq, tc, BaseTLB::Execute); + + 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); + + // go to the next instruction + advancePC(NoFault); + + // 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); -#define IFETCH_FLAGS(pc) (FullSystem ? 0 : ((pc) & 1) ? PHYSICAL : 0) - - uint64_t fetch_PC = thread->readPC() & ~3; - - // 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); - - bool succeeded = itb->translateAtomic(memReq, thread); - - 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); + pkt->dataStatic(&machInst); + icachePort->sendFunctional(pkt); + machInst = gtoh(machInst); - // go to the next instruction - thread->setPC(thread->readNextPC()); - thread->setNextPC(thread->readNextPC() + sizeof(MachInst)); + delete memReq; + delete pkt; + } + } - 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(); + if (fault == NoFault) { + TheISA::PCState pcState = thread->pcState(); + + 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; + + //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); + + //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); + } + + //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(); + // Check Checker and CPU get same instruction, and record + // any faults the CPU may have had. + Fault unverifiedFault; if (fault == NoFault) { - PacketPtr pkt = new Packet(memReq, Packet::ReadReq, - Packet::Broadcast); - - pkt->dataStatic(&machInst); - - icachePort->sendFunctional(pkt); - - delete pkt; - - // keep an instruction count - numInst++; + unverifiedFault = unverifiedInst->getFault(); - // decode the instruction - machInst = gtoh(machInst); // Checks that the instruction matches what we expected it to be. // Checks both the machine instruction and the PC. - 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); } - // Discard fetch's memReq. - delete memReq; - memReq = NULL; + // keep an instruction count + numInst++; + // Either the instruction was a fault and we should process the fault, // or we should just go ahead execute the instruction. This assumes // that the instruction is properly marked as a fault. if (fault == NoFault) { + // 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; + } + } - thread->funcExeInst++; - - if (!inst->isUnverifiable()) - fault = curStaticInst->execute(this, NULL); - - // Checks to make sure instrution results are correct. - validateExecution(inst); + if (fault == NoFault && unverifiedFault == NoFault) { + thread->funcExeInst++; + // Checks to make sure instrution results are correct. + validateExecution(unverifiedInst); - 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()); } } + // Take any faults here if (fault != NoFault) { fault->invoke(tc, curStaticInst); willChangePC = true; - 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; } else { -#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); } if (FullSystem) { @@ -254,14 +415,14 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst) Addr oldpc; int count = 0; do { - oldpc = thread->readPC(); + oldpc = thread->instAddr(); system->pcEventQueue.service(tc); count++; - } while (oldpc != thread->readPC()); + } while (oldpc != thread->instAddr()); if (count > 1) { willChangePC = true; - 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); } } @@ -269,17 +430,13 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst) // that have been modified). validateState(); - if (memReq) { - delete memReq; - memReq = NULL; - } - // Continue verifying instructions if there's another completed // instruction waiting to be verified. if (instList.empty()) { break; } else if (instList.front()->isCompleted()) { - inst = instList.front(); + unverifiedInst = NULL; + unverifiedInst = instList.front(); instList.pop_front(); } else { break; @@ -288,26 +445,26 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst) unverifiedInst = NULL; } -template <class DynInstPtr> +template <class Impl> void -Checker<DynInstPtr>::switchOut() +Checker<Impl>::switchOut() { instList.clear(); } -template <class DynInstPtr> +template <class Impl> void -Checker<DynInstPtr>::takeOverFrom(BaseCPU *oldCPU) +Checker<Impl>::takeOverFrom(BaseCPU *oldCPU) { } -template <class DynInstPtr> +template <class Impl> void -Checker<DynInstPtr>::validateInst(DynInstPtr &inst) +Checker<Impl>::validateInst(DynInstPtr &inst) { - 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()); if (changedPC) { warn("%lli: Changed PCs recently, may not be an error", curTick()); @@ -319,51 +476,70 @@ Checker<DynInstPtr>::validateInst(DynInstPtr &inst) MachInst mi = static_cast<MachInst>(inst->staticInst->machInst); if (mi != machInst) { - warn("%lli: Binary instructions do not match! Inst: %#x, " + panic("%lli: Binary instructions do not match! Inst: %#x, " "checker: %#x", curTick(), mi, machInst); handleError(inst); } } -template <class DynInstPtr> +template <class Impl> void -Checker<DynInstPtr>::validateExecution(DynInstPtr &inst) +Checker<Impl>::validateExecution(DynInstPtr &inst) { + uint64_t checker_val; + uint64_t inst_val; + int idx = -1; bool result_mismatch = false; - 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; + } } - } + } // 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. if (result_mismatch) { warn("%lli: Instruction results do not match! (Values may not " "actually be integers) Inst: %#x, checker: %#x", - curTick(), inst->readIntResult(), result.integer); + curTick(), inst_val, checker_val); // It's useful to verify load values from memory, but in MP // systems the value obtained at execute may be different than // the value obtained at completion. Similarly DMA can // present the same problem on even UP systems. Thus there is // the option to only warn on loads having a result error. + // The load/store queue in Detailed CPU can also cause problems + // if load/store forwarding is allowed. if (inst->isLoad() && warnOnlyOnLoadError) { - copyResult(inst); + copyResult(inst, inst_val, idx); } else { handleError(inst); } } - if (inst->readNextPC() != thread->readNextPC()) { + if (inst->nextInstAddr() != thread->nextInstAddr()) { warn("%lli: Instruction next PCs do not match! Inst: %#x, " "checker: %#x", - curTick(), inst->readNextPC(), thread->readNextPC()); + curTick(), inst->nextInstAddr(), thread->nextInstAddr()); handleError(inst); } @@ -388,53 +564,78 @@ Checker<DynInstPtr>::validateExecution(DynInstPtr &inst) } } -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> void -Checker<DynInstPtr>::validateState() +Checker<Impl>::validateState() { if (updateThisCycle) { - 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; + // Heavy-weight copying of all registers thread->copyArchRegs(unverifiedInst->tcBase()); + unverifiedInst->thread->inSyscall = inSyscall; + + // Set curStaticInst to unverifiedInst->staticInst + curStaticInst = unverifiedInst->staticInst; // Also advance the PC. Hopefully no PC-based events happened. -#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); updateThisCycle = false; } } -template <class DynInstPtr> +template <class Impl> void -Checker<DynInstPtr>::copyResult(DynInstPtr &inst) +Checker<Impl>::copyResult(DynInstPtr &inst, uint64_t mismatch_val, + int start_idx) { - 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); + } + } + 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... } } -template <class DynInstPtr> +template <class Impl> void -Checker<DynInstPtr>::dumpAndExit(DynInstPtr &inst) +Checker<Impl>::dumpAndExit(DynInstPtr &inst) { cprintf("Error detected, instruction information:\n"); - cprintf("PC:%#x, nextPC:%#x\n[sn:%lli]\n[tid:%i]\n" + cprintf("PC:%s, nextPC:%#x\n[sn:%lli]\n[tid:%i]\n" "Completed:%i\n", - inst->readPC(), - inst->readNextPC(), + inst->pcState(), + inst->nextInstAddr(), inst->seqNum, inst->threadNumber, inst->isCompleted()); @@ -442,9 +643,9 @@ Checker<DynInstPtr>::dumpAndExit(DynInstPtr &inst) CheckerCPU::dumpAndExit(); } -template <class DynInstPtr> +template <class Impl> void -Checker<DynInstPtr>::dumpInsts() +Checker<Impl>::dumpInsts() { int num = 0; @@ -457,9 +658,9 @@ Checker<DynInstPtr>::dumpInsts() cprintf("Instruction:%i\n", num); - cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" + cprintf("PC:%s\n[sn:%lli]\n[tid:%i]\n" "Completed:%i\n", - (*inst_list_it)->readPC(), + (*inst_list_it)->pcState(), (*inst_list_it)->seqNum, (*inst_list_it)->threadNumber, (*inst_list_it)->isCompleted()); diff --git a/src/cpu/checker/thread_context.hh b/src/cpu/checker/thread_context.hh index 178ded80e..d21de9f53 100644 --- a/src/cpu/checker/thread_context.hh +++ b/src/cpu/checker/thread_context.hh @@ -1,4 +1,16 @@ /* + * 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. + * * Copyright (c) 2006 The Regents of The University of Michigan * All rights reserved. * @@ -36,6 +48,7 @@ #include "cpu/checker/cpu.hh" #include "cpu/simple_thread.hh" #include "cpu/thread_context.hh" +#include "debug/Checker.hh" class EndQuiesceEvent; namespace TheISA { @@ -77,18 +90,32 @@ class CheckerThreadContext : public ThreadContext BaseCPU *getCpuPtr() { return actualTC->getCpuPtr(); } - void setCpuId(int id) + int cpuId() { return actualTC->cpuId(); } + + int contextId() { return actualTC->contextId(); } + + void setContextId(int id) { - actualTC->setCpuId(id); - checkerTC->setCpuId(id); + actualTC->setContextId(id); + checkerTC->setContextId(id); } - int cpuId() { return actualTC->cpuId(); } + /** Returns this thread's ID number. */ + int threadId() { return actualTC->threadId(); } + void setThreadId(int id) + { + checkerTC->setThreadId(id); + actualTC->setThreadId(id); + } TheISA::TLB *getITBPtr() { return actualTC->getITBPtr(); } TheISA::TLB *getDTBPtr() { return actualTC->getDTBPtr(); } + BaseCPU *getCheckerCpuPtr() { return checkerTC->getCpuPtr(); } + + Decoder *getDecoderPtr() { return actualTC->getDecoderPtr(); } + System *getSystemPtr() { return actualTC->getSystemPtr(); } PhysicalMemory *getPhysMemPtr() { return actualTC->getPhysMemPtr(); } @@ -103,8 +130,21 @@ class CheckerThreadContext : public ThreadContext FSTranslatingPortProxy* getVirtProxy() { return actualTC->getVirtProxy(); } + //XXX: How does this work now? + void initMemProxies(ThreadContext *tc) + { actualTC->initMemProxies(tc); } + + void connectMemPorts(ThreadContext *tc) + { + actualTC->connectMemPorts(tc); + } + SETranslatingPortProxy* getMemProxy() { return actualTC->getMemProxy(); } + /** Executes a syscall in SE mode. */ + void syscall(int64_t callnum) + { return actualTC->syscall(callnum); } + Status status() const { return actualTC->status(); } void setStatus(Status new_status) @@ -118,10 +158,10 @@ class CheckerThreadContext : public ThreadContext void activate(int delay = 1) { actualTC->activate(delay); } /// Set the status to Suspended. - void suspend() { actualTC->suspend(); } + void suspend(int delay) { actualTC->suspend(delay); } /// Set the status to Halted. - void halt() { actualTC->halt(); } + void halt(int delay) { actualTC->halt(delay); } void dumpFuncProfile() { actualTC->dumpFuncProfile(); } @@ -131,7 +171,11 @@ class CheckerThreadContext : public ThreadContext checkerTC->copyState(oldContext); } - void regStats(const std::string &name) { actualTC->regStats(name); } + void regStats(const std::string &name) + { + actualTC->regStats(name); + checkerTC->regStats(name); + } void serialize(std::ostream &os) { actualTC->serialize(os); } void unserialize(Checkpoint *cp, const std::string §ion) @@ -145,8 +189,6 @@ class CheckerThreadContext : public ThreadContext void profileClear() { return actualTC->profileClear(); } void profileSample() { return actualTC->profileSample(); } - int threadId() { return actualTC->threadId(); } - // @todo: Do I need this? void copyArchRegs(ThreadContext *tc) { @@ -190,32 +232,36 @@ class CheckerThreadContext : public ThreadContext checkerTC->setFloatRegBits(reg_idx, val); } - uint64_t readPC() { return actualTC->readPC(); } + /** Reads this thread's PC state. */ + TheISA::PCState pcState() + { return actualTC->pcState(); } - void setPC(uint64_t val) + /** Sets this thread's PC state. */ + void pcState(const TheISA::PCState &val) { - actualTC->setPC(val); - checkerTC->setPC(val); + DPRINTF(Checker, "Changing PC to %s, old PC %s\n", + val, checkerTC->pcState()); + checkerTC->pcState(val); checkerCPU->recordPCChange(val); + return actualTC->pcState(val); } - uint64_t readNextPC() { return actualTC->readNextPC(); } - - void setNextPC(uint64_t val) + void pcStateNoRecord(const TheISA::PCState &val) { - actualTC->setNextPC(val); - checkerTC->setNextPC(val); - checkerCPU->recordNextPCChange(val); + return actualTC->pcState(val); } - uint64_t readNextNPC() { return actualTC->readNextNPC(); } + /** Reads this thread's PC. */ + Addr instAddr() + { return actualTC->instAddr(); } - void setNextNPC(uint64_t val) - { - actualTC->setNextNPC(val); - checkerTC->setNextNPC(val); - checkerCPU->recordNextPCChange(val); - } + /** Reads this thread's next PC. */ + Addr nextInstAddr() + { return actualTC->nextInstAddr(); } + + /** Reads this thread's next PC. */ + MicroPC microPC() + { return actualTC->microPC(); } MiscReg readMiscRegNoEffect(int misc_reg) { return actualTC->readMiscRegNoEffect(misc_reg); } @@ -225,22 +271,28 @@ class CheckerThreadContext : public ThreadContext void setMiscRegNoEffect(int misc_reg, const MiscReg &val) { + DPRINTF(Checker, "Setting misc reg with no effect: %d to both Checker" + " and O3..\n", misc_reg); checkerTC->setMiscRegNoEffect(misc_reg, val); actualTC->setMiscRegNoEffect(misc_reg, val); } void setMiscReg(int misc_reg, const MiscReg &val) { + DPRINTF(Checker, "Setting misc reg with effect: %d to both Checker" + " and O3..\n", misc_reg); checkerTC->setMiscReg(misc_reg, val); actualTC->setMiscReg(misc_reg, val); } + int flattenIntIndex(int reg) { return actualTC->flattenIntIndex(reg); } + int flattenFloatIndex(int reg) { return actualTC->flattenFloatIndex(reg); } + unsigned readStCondFailures() { return actualTC->readStCondFailures(); } void setStCondFailures(unsigned sc_failures) { - checkerTC->setStCondFailures(sc_failures); actualTC->setStCondFailures(sc_failures); } diff --git a/src/cpu/dummy_checker_builder.cc b/src/cpu/dummy_checker_builder.cc new file mode 100644 index 000000000..0c83dabd0 --- /dev/null +++ b/src/cpu/dummy_checker_builder.cc @@ -0,0 +1,97 @@ +/* + * 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. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Geoffrey Blake + */ + +#include <string> + +#include "cpu/checker/cpu.hh" +#include "cpu/inst_seq.hh" +#include "params/DummyChecker.hh" +#include "sim/process.hh" +#include "sim/sim_object.hh" + +class MemObject; + +/** + * Specific non-templated derived class used for SimObject configuration. + */ +class DummyChecker : public CheckerCPU +{ + public: + DummyChecker(Params *p) + : CheckerCPU(p) + { } +}; + +//////////////////////////////////////////////////////////////////////// +// +// DummyChecker Simulation Object +// +DummyChecker * +DummyCheckerParams::create() +{ + DummyChecker::Params *params = new DummyChecker::Params(); + params->name = name; + params->numThreads = numThreads; + params->max_insts_any_thread = 0; + params->max_insts_all_threads = 0; + params->max_loads_any_thread = 0; + params->max_loads_all_threads = 0; + params->clock = clock; + // Hack to touch all parameters. Consider not deriving Checker + // from BaseCPU..it's not really a CPU in the end. + Counter temp; + temp = max_insts_any_thread; + temp = max_insts_all_threads; + temp = max_loads_any_thread; + temp = max_loads_all_threads; + Tick temp2 = progress_interval; + params->progress_interval = 0; + temp2++; + + params->itb = itb; + params->dtb = dtb; + params->system = system; + params->cpu_id = cpu_id; + params->profile = profile; + params->interrupts = NULL; + params->workload = workload; + + DummyChecker *cpu = new DummyChecker(params); + return cpu; +} diff --git a/src/cpu/func_unit.hh b/src/cpu/func_unit.hh index 59c5ee8a0..3745bb7d1 100644 --- a/src/cpu/func_unit.hh +++ b/src/cpu/func_unit.hh @@ -47,8 +47,9 @@ // // -struct OpDesc : public SimObject +class OpDesc : public SimObject { + public: OpClass opClass; unsigned opLat; unsigned issueLat; @@ -58,8 +59,9 @@ struct OpDesc : public SimObject issueLat(p->issueLat) {}; }; -struct FUDesc : public SimObject +class FUDesc : public SimObject { + public: std::vector<OpDesc *> opDescList; unsigned number; diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc index 5a14e92a7..62d48e89e 100644 --- a/src/cpu/inorder/cpu.cc +++ b/src/cpu/inorder/cpu.cc @@ -81,7 +81,7 @@ InOrderCPU::TickEvent::process() const char * -InOrderCPU::TickEvent::description() +InOrderCPU::TickEvent::description() const { return "InOrderCPU tick event"; } @@ -165,7 +165,7 @@ InOrderCPU::CPUEvent::process() const char * -InOrderCPU::CPUEvent::description() +InOrderCPU::CPUEvent::description() const { return "InOrderCPU event"; } @@ -1156,11 +1156,11 @@ InOrderCPU::activateNextReadyContext(int delay) } void -InOrderCPU::haltContext(ThreadID tid, int delay) +InOrderCPU::haltContext(ThreadID tid) { DPRINTF(InOrderCPU, "[tid:%i]: Calling Halt Context...\n", tid); - scheduleCpuEvent(HaltThread, NoFault, tid, dummyInst[tid], delay); + scheduleCpuEvent(HaltThread, NoFault, tid, dummyInst[tid]); activityRec.activity(); } @@ -1181,9 +1181,9 @@ InOrderCPU::haltThread(ThreadID tid) } void -InOrderCPU::suspendContext(ThreadID tid, int delay) +InOrderCPU::suspendContext(ThreadID tid) { - scheduleCpuEvent(SuspendThread, NoFault, tid, dummyInst[tid], delay); + scheduleCpuEvent(SuspendThread, NoFault, tid, dummyInst[tid]); } void diff --git a/src/cpu/inorder/cpu.hh b/src/cpu/inorder/cpu.hh index 7d22bc902..4abcb05b4 100644 --- a/src/cpu/inorder/cpu.hh +++ b/src/cpu/inorder/cpu.hh @@ -147,7 +147,7 @@ class InOrderCPU : public BaseCPU void process(); /** Returns the description of the tick event. */ - const char *description(); + const char *description() const; }; /** The tick event used for scheduling CPU ticks. */ @@ -229,7 +229,7 @@ class InOrderCPU : public BaseCPU void process(); /** Returns the description of the CPU event. */ - const char *description(); + const char *description() const; /** Schedule Event */ void scheduleEvent(int delay); @@ -469,13 +469,13 @@ class InOrderCPU : public BaseCPU void deactivateThread(ThreadID tid); /** Schedule a thread suspension on the CPU */ - void suspendContext(ThreadID tid, int delay = 0); + void suspendContext(ThreadID tid); /** Suspend Thread, Remove from Active Threads List, Add to Suspend List */ void suspendThread(ThreadID tid); /** Schedule a thread halt on the CPU */ - void haltContext(ThreadID tid, int delay = 0); + void haltContext(ThreadID tid); /** Halt Thread, Remove from Active Thread List, Place Thread on Halted * Threads List diff --git a/src/cpu/inorder/resource.cc b/src/cpu/inorder/resource.cc index d2327795e..2ddce13c3 100644 --- a/src/cpu/inorder/resource.cc +++ b/src/cpu/inorder/resource.cc @@ -512,7 +512,7 @@ ResourceEvent::process() } const char * -ResourceEvent::description() +ResourceEvent::description() const { string desc = resource->name() + "-event:slot[" + to_string(slotIdx) + "]"; diff --git a/src/cpu/inorder/resource.hh b/src/cpu/inorder/resource.hh index 78e5af5de..972925d94 100644 --- a/src/cpu/inorder/resource.hh +++ b/src/cpu/inorder/resource.hh @@ -51,6 +51,9 @@ class ResourceRequest; typedef ResourceRequest ResReq; typedef ResourceRequest* ResReqPtr; +class CacheRequest; +typedef CacheRequest* CacheReqPtr; + class Resource { public: typedef ThePipeline::DynInstPtr DynInstPtr; @@ -154,8 +157,9 @@ class Resource { * if instruction is actually in resource before * trying to do access.Needs to be defined for derived units. */ - virtual Fault doCacheAccess(DynInstPtr inst, uint64_t *res=NULL) - { panic("doCacheAccess undefined for %s", name()); return NoFault; } + virtual void doCacheAccess(DynInstPtr inst, uint64_t *write_result = NULL, + CacheReqPtr split_req = NULL) + { panic("doCacheAccess undefined for %s", name()); } /** Setup Squash to be sent out to pipeline and resource pool */ void setupSquash(DynInstPtr inst, int stage_num, ThreadID tid); @@ -283,7 +287,7 @@ class ResourceEvent : public Event virtual void process(); /** Returns the description of the resource event. */ - const char *description(); + const char *description() const; /** Set slot idx for event */ void setSlot(int slot) { slotIdx = slot; } @@ -320,7 +324,7 @@ class ResourceRequest int reqID; - virtual void setRequest(DynInstPtr _inst, int stage_num, + void setRequest(DynInstPtr _inst, int stage_num, int res_idx, int slot_num, unsigned _cmd); virtual void clearRequest(); diff --git a/src/cpu/inorder/resource_pool.cc b/src/cpu/inorder/resource_pool.cc index 0e89a7650..50d667ea7 100644 --- a/src/cpu/inorder/resource_pool.cc +++ b/src/cpu/inorder/resource_pool.cc @@ -485,7 +485,7 @@ ResourcePool::ResPoolEvent::process() const char * -ResourcePool::ResPoolEvent::description() +ResourcePool::ResPoolEvent::description() const { return "Resource Pool event"; } diff --git a/src/cpu/inorder/resource_pool.hh b/src/cpu/inorder/resource_pool.hh index e892d750a..4f05494c4 100644 --- a/src/cpu/inorder/resource_pool.hh +++ b/src/cpu/inorder/resource_pool.hh @@ -118,7 +118,7 @@ class ResourcePool { void process(); /** Returns the description of the resource event. */ - const char *description(); + const char *description() const; /** Schedule Event */ void scheduleEvent(int delay); diff --git a/src/cpu/inorder/resources/cache_unit.hh b/src/cpu/inorder/resources/cache_unit.hh index 2155c920c..416cb76d1 100644 --- a/src/cpu/inorder/resources/cache_unit.hh +++ b/src/cpu/inorder/resources/cache_unit.hh @@ -49,9 +49,6 @@ #include "params/InOrderCPU.hh" #include "sim/sim_object.hh" -class CacheRequest; -typedef CacheRequest* CacheReqPtr; - class CacheReqPacket; typedef CacheReqPacket* CacheReqPktPtr; diff --git a/src/cpu/inorder/thread_context.cc b/src/cpu/inorder/thread_context.cc index acfcf0939..1a7ac0890 100644 --- a/src/cpu/inorder/thread_context.cc +++ b/src/cpu/inorder/thread_context.cc @@ -122,7 +122,7 @@ InOrderThreadContext::suspend(int delay) return; thread->setStatus(ThreadContext::Suspended); - cpu->suspendContext(thread->threadId(), delay); + cpu->suspendContext(thread->threadId()); } void @@ -135,7 +135,7 @@ InOrderThreadContext::halt(int delay) return; thread->setStatus(ThreadContext::Halted); - cpu->haltContext(thread->threadId(), delay); + cpu->haltContext(thread->threadId()); } diff --git a/src/cpu/nativetrace.hh b/src/cpu/nativetrace.hh index 9869853c4..f6bf63d76 100644 --- a/src/cpu/nativetrace.hh +++ b/src/cpu/nativetrace.hh @@ -108,7 +108,7 @@ class NativeTrace : public ExeTracer { size_t soFar = 0; while (soFar < size) { - size_t res = ::read(fd, (uint8_t *)ptr + soFar, size - soFar); + ssize_t res = ::read(fd, (uint8_t *)ptr + soFar, size - soFar); if (res < 0) panic("Read call failed! %s\n", strerror(errno)); else diff --git a/src/cpu/o3/O3CPU.py b/src/cpu/o3/O3CPU.py index c3e561cd9..acc7a9056 100644 --- a/src/cpu/o3/O3CPU.py +++ b/src/cpu/o3/O3CPU.py @@ -40,11 +40,15 @@ class DerivO3CPU(BaseCPU): activity = Param.Unsigned(0, "Initial count") if buildEnv['USE_CHECKER']: - checker = Param.BaseCPU(O3Checker(workload=Parent.workload, + # FIXME: Shouldn't need to derefernce Parent.workload + # Somewhere in the param parsing code + # src/python/m5/params.py is and error that + # has trouble converting the workload parameter properly. + checker = Param.BaseCPU(O3Checker(workload=Parent.workload[0], exitOnError=False, updateOnError=True, - warnOnlyOnLoadError=False), - "checker") + warnOnlyOnLoadError=True), + "checker") checker.itb = Parent.itb checker.dtb = Parent.dtb diff --git a/src/cpu/o3/O3Checker.py b/src/cpu/o3/O3Checker.py index d0c4ce537..d53e5e527 100644 --- a/src/cpu/o3/O3Checker.py +++ b/src/cpu/o3/O3Checker.py @@ -34,7 +34,7 @@ class O3Checker(BaseCPU): exitOnError = Param.Bool(False, "Exit on an error") updateOnError = Param.Bool(False, "Update the checker with the main CPU's state on an error") - warnOnlyOnLoadError = Param.Bool(False, + warnOnlyOnLoadError = Param.Bool(True, "If a load result is incorrect, only print a warning and do not exit") function_trace = Param.Bool(False, "Enable function trace") function_trace_start = Param.Tick(0, "Cycle to start function trace") diff --git a/src/cpu/o3/bpred_unit.hh b/src/cpu/o3/bpred_unit.hh index 84f2dc8c1..8dbba9085 100644 --- a/src/cpu/o3/bpred_unit.hh +++ b/src/cpu/o3/bpred_unit.hh @@ -41,7 +41,7 @@ #include "cpu/pred/tournament.hh" #include "cpu/inst_seq.hh" -class DerivO3CPUParams; +struct DerivO3CPUParams; /** * Basically a wrapper class to hold both the branch predictor diff --git a/src/cpu/o3/checker_builder.cc b/src/cpu/o3/checker_builder.cc index b34613f68..72b50d104 100644 --- a/src/cpu/o3/checker_builder.cc +++ b/src/cpu/o3/checker_builder.cc @@ -1,4 +1,16 @@ /* + * 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. + * * Copyright (c) 2006 The Regents of The University of Michigan * All rights reserved. * @@ -31,8 +43,8 @@ #include <string> #include "cpu/checker/cpu_impl.hh" -#include "cpu/o3/alpha/dyn_inst.hh" -#include "cpu/o3/alpha/impl.hh" +#include "cpu/o3/dyn_inst.hh" +#include "cpu/o3/impl.hh" #include "cpu/inst_seq.hh" #include "params/O3Checker.hh" #include "sim/process.hh" @@ -41,16 +53,16 @@ class MemObject; template -class Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >; +class Checker<O3CPUImpl>; /** * Specific non-templated derived class used for SimObject configuration. */ -class O3Checker : public Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > > +class O3Checker : public Checker<O3CPUImpl> { public: O3Checker(Params *p) - : Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >(p) + : Checker<O3CPUImpl>(p) { } }; @@ -63,7 +75,7 @@ O3CheckerParams::create() { O3Checker::Params *params = new O3Checker::Params(); params->name = name; - params->numberOfThreads = 1; + params->numThreads = numThreads; params->max_insts_any_thread = 0; params->max_insts_all_threads = 0; params->max_loads_any_thread = 0; @@ -71,10 +83,8 @@ O3CheckerParams::create() params->exitOnError = exitOnError; params->updateOnError = updateOnError; params->warnOnlyOnLoadError = warnOnlyOnLoadError; - params->deferRegistration = defer_registration; - params->functionTrace = function_trace; - params->functionTraceStart = function_trace_start; params->clock = clock; + params->tracer = tracer; // Hack to touch all parameters. Consider not deriving Checker // from BaseCPU..it's not really a CPU in the end. Counter temp; @@ -91,7 +101,8 @@ O3CheckerParams::create() params->system = system; params->cpu_id = cpu_id; params->profile = profile; - params->process = workload; + params->interrupts = NULL; + params->workload = workload; O3Checker *cpu = new O3Checker(params); return cpu; diff --git a/src/cpu/o3/commit.hh b/src/cpu/o3/commit.hh index b45d37df9..f35928b08 100644 --- a/src/cpu/o3/commit.hh +++ b/src/cpu/o3/commit.hh @@ -51,10 +51,10 @@ #include "cpu/inst_seq.hh" #include "cpu/timebuf.hh" -class DerivO3CPUParams; +struct DerivO3CPUParams; template <class> -class O3ThreadState; +struct O3ThreadState; /** * DefaultCommit handles single threaded and SMT commit. Its width is diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh index b6a4c0387..edf7e861b 100644 --- a/src/cpu/o3/commit_impl.hh +++ b/src/cpu/o3/commit_impl.hh @@ -725,6 +725,12 @@ DefaultCommit<Impl>::handleInterrupt() assert(!thread[0]->inSyscall); thread[0]->inSyscall = true; +#if USE_CHECKER + if (cpu->checker) { + cpu->checker->handlePendingInt(); + } +#endif + // CPU will handle interrupt. cpu->processInterrupts(interrupt); @@ -769,8 +775,8 @@ void DefaultCommit<Impl>::commit() { if (FullSystem) { - // Check for any interrupt that we've already squashed for and start - // processing it. + // Check for any interrupt that we've already squashed for and + // start processing it. if (interrupt != NoFault) handleInterrupt(); @@ -1128,7 +1134,8 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num) head_inst->setCompleted(); #if USE_CHECKER - if (cpu->checker && head_inst->isStore()) { + if (cpu->checker) { + // Need to check the instruction before its fault is processed cpu->checker->verify(head_inst); } #endif diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index ef08c96f4..d16270943 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -65,6 +65,7 @@ #if USE_CHECKER #include "cpu/checker/cpu.hh" +#include "cpu/checker/thread_context.hh" #endif #if THE_ISA == ALPHA_ISA @@ -72,7 +73,7 @@ #include "debug/Activity.hh" #endif -class BaseCPUParams; +struct BaseCPUParams; using namespace TheISA; using namespace std; @@ -265,7 +266,7 @@ FullO3CPU<Impl>::FullO3CPU(DerivO3CPUParams *params) #if USE_CHECKER if (params->checker) { BaseCPU *temp_checker = params->checker; - checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker); + checker = dynamic_cast<Checker<Impl> *>(temp_checker); checker->setIcachePort(&icachePort); checker->setSystem(params->system); } else { @@ -759,7 +760,8 @@ FullO3CPU<Impl>::activateContext(ThreadID tid, int delay) template <class Impl> bool -FullO3CPU<Impl>::deallocateContext(ThreadID tid, bool remove, int delay) +FullO3CPU<Impl>::scheduleDeallocateContext(ThreadID tid, bool remove, + int delay) { // Schedule removal of thread data from CPU if (delay){ @@ -780,7 +782,7 @@ void FullO3CPU<Impl>::suspendContext(ThreadID tid) { DPRINTF(O3CPU,"[tid: %i]: Suspending Thread Context.\n", tid); - bool deallocated = deallocateContext(tid, false, 1); + bool deallocated = scheduleDeallocateContext(tid, false, 1); // If this was the last thread then unschedule the tick event. if ((activeThreads.size() == 1 && !deallocated) || activeThreads.size() == 0) @@ -797,7 +799,7 @@ FullO3CPU<Impl>::haltContext(ThreadID tid) { //For now, this is the same as deallocate DPRINTF(O3CPU,"[tid:%i]: Halt Context called. Deallocating", tid); - deallocateContext(tid, true, 1); + scheduleDeallocateContext(tid, true, 1); } template <class Impl> @@ -1216,7 +1218,7 @@ FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU) activityRec.reset(); - BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort); + BaseCPU::takeOverFrom(oldCPU); fetch.takeOverFrom(); decode.takeOverFrom(); diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index 165144c1b..94c0a873b 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -78,7 +78,7 @@ class Checkpoint; class MemObject; class Process; -class BaseCPUParams; +struct BaseCPUParams; class BaseO3CPU : public BaseCPU { @@ -400,7 +400,7 @@ class FullO3CPU : public BaseO3CPU /** Remove Thread from Active Threads List && * Possibly Remove Thread Context from CPU. */ - bool deallocateContext(ThreadID tid, bool remove, int delay = 1); + bool scheduleDeallocateContext(ThreadID tid, bool remove, int delay = 1); /** Remove Thread from Active Threads List && * Remove Thread Context from CPU. @@ -725,7 +725,7 @@ class FullO3CPU : public BaseO3CPU * instruction results at run time. This can be set to NULL if it * is not being used. */ - Checker<DynInstPtr> *checker; + Checker<Impl> *checker; #endif /** Pointer to the system. */ diff --git a/src/cpu/o3/decode.hh b/src/cpu/o3/decode.hh index 482b4b7fc..663831254 100644 --- a/src/cpu/o3/decode.hh +++ b/src/cpu/o3/decode.hh @@ -36,7 +36,7 @@ #include "base/statistics.hh" #include "cpu/timebuf.hh" -class DerivO3CPUParams; +struct DerivO3CPUParams; /** * DefaultDecode class handles both single threaded and SMT diff --git a/src/cpu/o3/decode_impl.hh b/src/cpu/o3/decode_impl.hh index 985e92826..60bca1041 100644 --- a/src/cpu/o3/decode_impl.hh +++ b/src/cpu/o3/decode_impl.hh @@ -38,7 +38,9 @@ #include "params/DerivO3CPU.hh" #include "sim/full_system.hh" -using namespace std; +// clang complains about std::set being overloaded with Packet::set if +// we open up the entire namespace std +using std::list; template<class Impl> DefaultDecode<Impl>::DefaultDecode(O3CPU *_cpu, DerivO3CPUParams *params) diff --git a/src/cpu/o3/dyn_inst_impl.hh b/src/cpu/o3/dyn_inst_impl.hh index 76a456ee3..ed1e374e8 100644 --- a/src/cpu/o3/dyn_inst_impl.hh +++ b/src/cpu/o3/dyn_inst_impl.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010-2011 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -41,6 +41,7 @@ */ #include "base/cp_annotate.hh" +#include "config/use_checker.hh" #include "cpu/o3/dyn_inst.hh" #include "sim/full_system.hh" @@ -137,6 +138,11 @@ BaseO3DynInst<Impl>::completeAcc(PacketPtr pkt) bool in_syscall = this->thread->inSyscall; this->thread->inSyscall = true; +#if USE_CHECKER + if (this->isStoreConditional()) { + this->reqToVerify->setExtraData(pkt->req->getExtraData()); + } +#endif this->fault = this->staticInst->completeAcc(pkt, this, this->traceData); this->thread->inSyscall = in_syscall; diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh index f5d275593..b61ae2c7b 100644 --- a/src/cpu/o3/fetch.hh +++ b/src/cpu/o3/fetch.hh @@ -56,7 +56,7 @@ #include "mem/port.hh" #include "sim/eventq.hh" -class DerivO3CPUParams; +struct DerivO3CPUParams; /** * DefaultFetch class handles both single threaded and SMT fetch. Its diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh index 1b82f8a4c..553198980 100644 --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -43,6 +43,9 @@ #include <algorithm> #include <cstring> +#include <list> +#include <map> +#include <queue> #include "arch/isa_traits.hh" #include "arch/tlb.hh" @@ -52,7 +55,6 @@ #include "config/the_isa.hh" #include "config/use_checker.hh" #include "cpu/base.hh" -#include "cpu/checker/cpu.hh" #include "cpu/o3/fetch.hh" #include "cpu/exetrace.hh" #include "debug/Activity.hh" @@ -66,6 +68,10 @@ #include "sim/full_system.hh" #include "sim/system.hh" +#if USE_CHECKER +#include "cpu/checker/cpu.hh" +#endif // USE_CHECKER + using namespace std; template<class Impl> diff --git a/src/cpu/o3/fu_pool.cc b/src/cpu/o3/fu_pool.cc index b7c972b09..3f0e46543 100644 --- a/src/cpu/o3/fu_pool.cc +++ b/src/cpu/o3/fu_pool.cc @@ -252,7 +252,7 @@ FUPool::switchOut() } void -FUPool::takeOverFrom() +FUPool::takeOver() { for (int i = 0; i < numFU; i++) { unitBusy[i] = false; diff --git a/src/cpu/o3/fu_pool.hh b/src/cpu/o3/fu_pool.hh index ea4b53e1a..66804b534 100644 --- a/src/cpu/o3/fu_pool.hh +++ b/src/cpu/o3/fu_pool.hh @@ -37,7 +37,6 @@ #include <vector> #include "cpu/op_class.hh" -#include "cpu/sched_list.hh" #include "params/FUPool.hh" #include "sim/sim_object.hh" @@ -162,7 +161,7 @@ class FUPool : public SimObject void switchOut(); /** Takes over from another CPU's thread. */ - void takeOverFrom(); + void takeOver(); }; #endif // __CPU_O3_FU_POOL_HH__ diff --git a/src/cpu/o3/iew.hh b/src/cpu/o3/iew.hh index 0d7e0f68f..adb797525 100644 --- a/src/cpu/o3/iew.hh +++ b/src/cpu/o3/iew.hh @@ -53,7 +53,7 @@ #include "cpu/timebuf.hh" #include "debug/IEW.hh" -class DerivO3CPUParams; +struct DerivO3CPUParams; class FUPool; /** @@ -93,9 +93,6 @@ class DefaultIEW typedef typename CPUPol::RenameStruct RenameStruct; typedef typename CPUPol::IssueStruct IssueStruct; - friend class Impl::O3CPU; - friend class CPUPol::IQ; - public: /** Overall IEW stage status. Used to determine if the CPU can * deschedule itself due to a lack of activity. diff --git a/src/cpu/o3/iew_impl.hh b/src/cpu/o3/iew_impl.hh index 92c8875e4..97b41ad9f 100644 --- a/src/cpu/o3/iew_impl.hh +++ b/src/cpu/o3/iew_impl.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010-2011 ARM Limited * All rights reserved. * * The license below extends only to copyright in the software and shall @@ -48,6 +48,7 @@ #include "arch/utility.hh" #include "config/the_isa.hh" +#include "config/use_checker.hh" #include "cpu/o3/fu_pool.hh" #include "cpu/o3/iew.hh" #include "cpu/timebuf.hh" @@ -56,6 +57,10 @@ #include "debug/IEW.hh" #include "params/DerivO3CPU.hh" +#if USE_CHECKER +#include "cpu/checker/cpu.hh" +#endif // USE_CHECKER + using namespace std; template<class Impl> @@ -294,6 +299,13 @@ DefaultIEW<Impl>::initStage() ldstQueue.numFreeEntries(tid); } +// Initialize the checker's dcache port here +#if USE_CHECKER + if (cpu->checker) { + cpu->checker->setDcachePort(cpu->getDcachePort()); + } +#endif + cpu->activateStage(O3CPU::IEWIdx); } @@ -400,7 +412,7 @@ DefaultIEW<Impl>::takeOverFrom() instQueue.takeOverFrom(); ldstQueue.takeOverFrom(); - fuPool->takeOverFrom(); + fuPool->takeOver(); initStage(); cpu->activityThisCycle(); diff --git a/src/cpu/o3/inst_queue.hh b/src/cpu/o3/inst_queue.hh index eb35fd285..9ceab1525 100644 --- a/src/cpu/o3/inst_queue.hh +++ b/src/cpu/o3/inst_queue.hh @@ -56,7 +56,7 @@ #include "cpu/timebuf.hh" #include "sim/eventq.hh" -class DerivO3CPUParams; +struct DerivO3CPUParams; class FUPool; class MemInterface; @@ -93,8 +93,6 @@ class InstructionQueue // Typedef of iterator through the list of instructions. typedef typename std::list<DynInstPtr>::iterator ListIt; - friend class Impl::O3CPU; - /** FU completion event class. */ class FUCompletion : public Event { private: diff --git a/src/cpu/o3/inst_queue_impl.hh b/src/cpu/o3/inst_queue_impl.hh index b2016cc9c..2c0779a03 100644 --- a/src/cpu/o3/inst_queue_impl.hh +++ b/src/cpu/o3/inst_queue_impl.hh @@ -51,7 +51,9 @@ #include "params/DerivO3CPU.hh" #include "sim/core.hh" -using namespace std; +// clang complains about std::set being overloaded with Packet::set if +// we open up the entire namespace std +using std::list; template <class Impl> InstructionQueue<Impl>::FUCompletion::FUCompletion(DynInstPtr &_inst, diff --git a/src/cpu/o3/lsq.hh b/src/cpu/o3/lsq.hh index db127a2da..b821dd3f9 100644 --- a/src/cpu/o3/lsq.hh +++ b/src/cpu/o3/lsq.hh @@ -51,7 +51,7 @@ #include "mem/port.hh" #include "sim/sim_object.hh" -class DerivO3CPUParams; +struct DerivO3CPUParams; template <class Impl> class LSQ { diff --git a/src/cpu/o3/lsq_unit.hh b/src/cpu/o3/lsq_unit.hh index 3c1a4eda3..4247c3796 100644 --- a/src/cpu/o3/lsq_unit.hh +++ b/src/cpu/o3/lsq_unit.hh @@ -51,7 +51,7 @@ #include "mem/packet.hh" #include "mem/port.hh" -class DerivO3CPUParams; +struct DerivO3CPUParams; /** * Class that implements the actual LQ and SQ for each specific diff --git a/src/cpu/o3/lsq_unit_impl.hh b/src/cpu/o3/lsq_unit_impl.hh index d0db6f6fe..facd88597 100644 --- a/src/cpu/o3/lsq_unit_impl.hh +++ b/src/cpu/o3/lsq_unit_impl.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010-2011 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -45,7 +45,6 @@ #include "arch/locked_mem.hh" #include "base/str.hh" #include "config/the_isa.hh" -#include "config/use_checker.hh" #include "cpu/o3/lsq.hh" #include "cpu/o3/lsq_unit.hh" #include "debug/Activity.hh" @@ -246,12 +245,6 @@ void LSQUnit<Impl>::setDcachePort(Port *dcache_port) { dcachePort = dcache_port; - -#if USE_CHECKER - if (cpu->checker) { - cpu->checker->setDcachePort(dcachePort); - } -#endif } template<class Impl> @@ -878,6 +871,11 @@ LSQUnit<Impl>::writebackStores() inst->seqNum); WritebackEvent *wb = new WritebackEvent(inst, data_pkt, this); cpu->schedule(wb, curTick() + 1); +#if USE_CHECKER + // Make sure to set the LLSC data for verification + inst->reqToVerify->setExtraData(0); + inst->completeAcc(data_pkt); +#endif completeStore(storeWBIdx); incrStIdx(storeWBIdx); continue; diff --git a/src/cpu/o3/mem_dep_unit.cc b/src/cpu/o3/mem_dep_unit.cc index ac0db4784..234a6f9c4 100644 --- a/src/cpu/o3/mem_dep_unit.cc +++ b/src/cpu/o3/mem_dep_unit.cc @@ -32,10 +32,6 @@ #include "cpu/o3/mem_dep_unit_impl.hh" #include "cpu/o3/store_set.hh" -// Force instantation of memory dependency unit using store sets and -// O3CPUImpl. -template class MemDepUnit<StoreSet, O3CPUImpl>; - #ifdef DEBUG template <> int @@ -47,3 +43,7 @@ template <> int MemDepUnit<StoreSet, O3CPUImpl>::MemDepEntry::memdep_erase = 0; #endif + +// Force instantation of memory dependency unit using store sets and +// O3CPUImpl. +template class MemDepUnit<StoreSet, O3CPUImpl>; diff --git a/src/cpu/o3/mem_dep_unit.hh b/src/cpu/o3/mem_dep_unit.hh index 7d00369d3..ce5a62ef8 100644 --- a/src/cpu/o3/mem_dep_unit.hh +++ b/src/cpu/o3/mem_dep_unit.hh @@ -49,7 +49,7 @@ struct SNHash { } }; -class DerivO3CPUParams; +struct DerivO3CPUParams; template <class Impl> class InstructionQueue; diff --git a/src/cpu/o3/rename.hh b/src/cpu/o3/rename.hh index e2472a62d..a5c83dfea 100644 --- a/src/cpu/o3/rename.hh +++ b/src/cpu/o3/rename.hh @@ -37,7 +37,7 @@ #include "config/the_isa.hh" #include "cpu/timebuf.hh" -class DerivO3CPUParams; +struct DerivO3CPUParams; /** * DefaultRename handles both single threaded and SMT rename. Its diff --git a/src/cpu/o3/sat_counter.hh b/src/cpu/o3/sat_counter.hh index 7dd840f31..17ff8546b 100644 --- a/src/cpu/o3/sat_counter.hh +++ b/src/cpu/o3/sat_counter.hh @@ -65,7 +65,8 @@ class SatCounter * @param initial_val Starting value for each counter. */ SatCounter(unsigned bits, uint8_t initial_val) - : initialVal(initialVal), maxVal((1 << bits) - 1), counter(initial_val) + : initialVal(initial_val), maxVal((1 << bits) - 1), + counter(initial_val) { // Check to make sure initial value doesn't exceed the max // counter value. diff --git a/src/cpu/o3/thread_context.hh b/src/cpu/o3/thread_context.hh index ffe828c94..c2096fab2 100755 --- a/src/cpu/o3/thread_context.hh +++ b/src/cpu/o3/thread_context.hh @@ -1,4 +1,16 @@ /* + * 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. + * * Copyright (c) 2004-2006 The Regents of The University of Michigan * All rights reserved. * @@ -32,6 +44,7 @@ #define __CPU_O3_THREAD_CONTEXT_HH__ #include "config/the_isa.hh" +#include "config/use_checker.hh" #include "cpu/o3/isa_specific.hh" #include "cpu/thread_context.hh" @@ -71,6 +84,10 @@ class O3ThreadContext : public ThreadContext /** Returns a pointer to the DTB. */ TheISA::TLB *getDTBPtr() { return cpu->dtb; } +#if USE_CHECKER + BaseCPU *getCheckerCpuPtr() { return NULL; } +#endif + Decoder *getDecoderPtr() { return &cpu->fetch.decoder; } /** Returns a pointer to this CPU. */ @@ -177,6 +194,10 @@ class O3ThreadContext : public ThreadContext /** Sets this thread's PC state. */ virtual void pcState(const TheISA::PCState &val); +#if USE_CHECKER + virtual void pcStateNoRecord(const TheISA::PCState &val); +#endif + /** Reads this thread's PC. */ virtual Addr instAddr() { return cpu->instAddr(thread->threadId()); } diff --git a/src/cpu/o3/thread_context_impl.hh b/src/cpu/o3/thread_context_impl.hh index 5ba454458..2ea39f3eb 100755 --- a/src/cpu/o3/thread_context_impl.hh +++ b/src/cpu/o3/thread_context_impl.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010-2011 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -44,6 +44,7 @@ #include "arch/kernel_stats.hh" #include "arch/registers.hh" #include "config/the_isa.hh" +#include "config/use_checker.hh" #include "cpu/o3/thread_context.hh" #include "cpu/quiesce_event.hh" #include "debug/O3CPU.hh" @@ -296,6 +297,20 @@ O3ThreadContext<Impl>::pcState(const TheISA::PCState &val) } } +#if USE_CHECKER +template <class Impl> +void +O3ThreadContext<Impl>::pcStateNoRecord(const TheISA::PCState &val) +{ + cpu->pcState(val, thread->threadId()); + + // Squash if we're not already in a state update mode. + if (!thread->trapPending && !thread->inSyscall) { + cpu->squashFromTC(thread->threadId()); + } +} +#endif + template <class Impl> int O3ThreadContext<Impl>::flattenIntIndex(int reg) diff --git a/src/cpu/quiesce_event.hh b/src/cpu/quiesce_event.hh index 85c88ab32..74db27481 100644 --- a/src/cpu/quiesce_event.hh +++ b/src/cpu/quiesce_event.hh @@ -36,8 +36,9 @@ class ThreadContext; /** Event for timing out quiesce instruction */ -struct EndQuiesceEvent : public Event +class EndQuiesceEvent : public Event { + public: /** A pointer to the thread context that is quiesced */ ThreadContext *tc; diff --git a/src/cpu/sched_list.hh b/src/cpu/sched_list.hh deleted file mode 100644 index 4d3b0dd71..000000000 --- a/src/cpu/sched_list.hh +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2002-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Authors: Steve Raasch - */ - -#ifndef SCHED_LIST_HH -#define SCHED_LIST_HH - -#include <list> - -#include "base/intmath.hh" -#include "base/misc.hh" - -// Any types you use this class for must be covered here... -namespace { - void ClearEntry(int &i) { i = 0; }; - void ClearEntry(unsigned &i) { i = 0; }; - void ClearEntry(double &i) { i = 0; }; - template <class T> void ClearEntry(std::list<T> &l) { l.clear(); }; -}; - - -// -// this is a special list type that allows the user to insert elements at a -// specified positive offset from the "current" element, but only allow them -// be extracted from the "current" element -// - - -template <class T> -class SchedList -{ - T *data_array; - unsigned position; - unsigned size; - unsigned mask; - - public: - SchedList(unsigned size); - SchedList(void); - - void init(unsigned size); - - T &operator[](unsigned offset); - - void advance(void); - - void clear(void); -}; - - - -// -// Constructor -// -template<class T> -SchedList<T>::SchedList(unsigned _size) -{ - size = _size; - - // size must be a power of two - if (!isPowerOf2(size)) { - panic("SchedList: size must be a power of two"); - } - - if (size < 2) { - panic("SchedList: you don't want a list that small"); - } - - // calculate the bit mask for the modulo operation - mask = size - 1; - - data_array = new T[size]; - - if (!data_array) { - panic("SchedList: could not allocate memory"); - } - - clear(); -} - -template<class T> -SchedList<T>::SchedList(void) -{ - data_array = 0; - size = 0; -} - - -template<class T> void -SchedList<T>::init(unsigned _size) -{ - size = _size; - - if (!data_array) { - // size must be a power of two - if (size & (size-1)) { - panic("SchedList: size must be a power of two"); - } - - if (size < 2) { - panic("SchedList: you don't want a list that small"); - } - - // calculate the bit mask for the modulo operation - mask = size - 1; - - data_array = new T[size]; - - if (!data_array) { - panic("SchedList: could not allocate memory"); - } - - clear(); - } -} - - -template<class T> void -SchedList<T>::advance(void) -{ - ClearEntry(data_array[position]); - - // position = (++position % size); - position = ++position & mask; -} - - -template<class T> void -SchedList<T>::clear(void) -{ - for (unsigned i=0; i<size; ++i) { - ClearEntry(data_array[i]); - } - - position = 0; -} - - -template<class T> T& -SchedList<T>::operator[](unsigned offset) -{ - if (offset >= size) { - panic("SchedList: can't access element beyond current pointer"); - } - - // unsigned p = (position + offset) % size; - unsigned p = (position + offset) & mask; - - return data_array[p]; -} - - - -#endif diff --git a/src/cpu/simple/BaseSimpleCPU.py b/src/cpu/simple/BaseSimpleCPU.py index 9f528bc20..ea2c642e6 100644 --- a/src/cpu/simple/BaseSimpleCPU.py +++ b/src/cpu/simple/BaseSimpleCPU.py @@ -26,9 +26,18 @@ # # Authors: Gabe Black +from m5.defines import buildEnv from m5.params import * from BaseCPU import BaseCPU +if buildEnv['USE_CHECKER']: + from DummyChecker import DummyChecker + class BaseSimpleCPU(BaseCPU): type = 'BaseSimpleCPU' abstract = True + + if buildEnv['USE_CHECKER']: + checker = Param.BaseCPU(DummyChecker(), "checker") + checker.itb = BaseCPU.itb + checker.dtb = BaseCPU.dtb diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index 2c12b244b..24e2f1eb8 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -175,7 +175,7 @@ AtomicSimpleCPU::switchOut() void AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU) { - BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort); + BaseCPU::takeOverFrom(oldCPU); assert(!tickEvent.scheduled()); @@ -201,7 +201,7 @@ AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU) void -AtomicSimpleCPU::activateContext(int thread_num, int delay) +AtomicSimpleCPU::activateContext(ThreadID thread_num, int delay) { DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay); @@ -221,7 +221,7 @@ AtomicSimpleCPU::activateContext(int thread_num, int delay) void -AtomicSimpleCPU::suspendContext(int thread_num) +AtomicSimpleCPU::suspendContext(ThreadID thread_num) { DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num); diff --git a/src/cpu/simple/atomic.hh b/src/cpu/simple/atomic.hh index 77a9d6b0d..f677ed49b 100644 --- a/src/cpu/simple/atomic.hh +++ b/src/cpu/simple/atomic.hh @@ -112,8 +112,8 @@ class AtomicSimpleCPU : public BaseSimpleCPU void switchOut(); void takeOverFrom(BaseCPU *oldCPU); - virtual void activateContext(int thread_num, int delay); - virtual void suspendContext(int thread_num); + virtual void activateContext(ThreadID thread_num, int delay); + virtual void suspendContext(ThreadID thread_num); Fault readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags); diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index 610cc6b89..97ce3264a 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010-2011 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -56,6 +56,7 @@ #include "base/trace.hh" #include "base/types.hh" #include "config/the_isa.hh" +#include "config/use_checker.hh" #include "cpu/simple/base.hh" #include "cpu/base.hh" #include "cpu/exetrace.hh" @@ -79,6 +80,11 @@ #include "sim/stats.hh" #include "sim/system.hh" +#if USE_CHECKER +#include "cpu/checker/cpu.hh" +#include "cpu/checker/thread_context.hh" +#endif + using namespace std; using namespace TheISA; @@ -95,6 +101,19 @@ BaseSimpleCPU::BaseSimpleCPU(BaseSimpleCPUParams *p) tc = thread->getTC(); +#if USE_CHECKER + if (p->checker) { + BaseCPU *temp_checker = p->checker; + checker = dynamic_cast<CheckerCPU *>(temp_checker); + checker->setSystem(p->system); + // Manipulate thread context + ThreadContext *cpu_tc = tc; + tc = new CheckerThreadContext<ThreadContext>(cpu_tc, this->checker); + } else { + checker = NULL; + } +#endif + numInst = 0; startNumInst = 0; numLoad = 0; @@ -114,7 +133,7 @@ BaseSimpleCPU::~BaseSimpleCPU() } void -BaseSimpleCPU::deallocateContext(int thread_num) +BaseSimpleCPU::deallocateContext(ThreadID thread_num) { // for now, these are equivalent suspendContext(thread_num); @@ -122,7 +141,7 @@ BaseSimpleCPU::deallocateContext(int thread_num) void -BaseSimpleCPU::haltContext(int thread_num) +BaseSimpleCPU::haltContext(ThreadID thread_num) { // for now, these are equivalent suspendContext(thread_num); diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh index 0e5526040..55dec5d53 100644 --- a/src/cpu/simple/base.hh +++ b/src/cpu/simple/base.hh @@ -1,4 +1,16 @@ /* + * 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. + * * Copyright (c) 2002-2005 The Regents of The University of Michigan * All rights reserved. * @@ -36,6 +48,7 @@ #include "arch/predecoder.hh" #include "base/statistics.hh" #include "config/the_isa.hh" +#include "config/use_checker.hh" #include "cpu/base.hh" #include "cpu/decode.hh" #include "cpu/pc_event.hh" @@ -48,6 +61,10 @@ #include "sim/full_system.hh" #include "sim/system.hh" +#if USE_CHECKER +#include "cpu/checker/cpu.hh" +#endif + // forward declarations class Checkpoint; class MemObject; @@ -66,7 +83,7 @@ namespace Trace { class InstRecord; } -class BaseSimpleCPUParams; +struct BaseSimpleCPUParams; class BaseSimpleCPU : public BaseCPU @@ -111,6 +128,10 @@ class BaseSimpleCPU : public BaseCPU * objects to modify this thread's state. */ ThreadContext *tc; + +#if USE_CHECKER + CheckerCPU *checker; +#endif protected: enum Status { @@ -157,8 +178,8 @@ class BaseSimpleCPU : public BaseCPU void postExecute(); void advancePC(Fault fault); - virtual void deallocateContext(int thread_num); - virtual void haltContext(int thread_num); + virtual void deallocateContext(ThreadID thread_num); + virtual void haltContext(ThreadID thread_num); // statistics virtual void regStats(); diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index fd02e8300..6cf7c582c 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -176,7 +176,7 @@ TimingSimpleCPU::switchOut() void TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) { - BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort); + BaseCPU::takeOverFrom(oldCPU); // if any of this CPU's ThreadContexts are active, mark the CPU as // running and schedule its tick event. @@ -197,7 +197,7 @@ TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) void -TimingSimpleCPU::activateContext(int thread_num, int delay) +TimingSimpleCPU::activateContext(ThreadID thread_num, int delay) { DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay); @@ -215,7 +215,7 @@ TimingSimpleCPU::activateContext(int thread_num, int delay) void -TimingSimpleCPU::suspendContext(int thread_num) +TimingSimpleCPU::suspendContext(ThreadID thread_num) { DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num); diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh index dce3c58ff..ed91524cf 100644 --- a/src/cpu/simple/timing.hh +++ b/src/cpu/simple/timing.hh @@ -244,8 +244,8 @@ class TimingSimpleCPU : public BaseSimpleCPU void switchOut(); void takeOverFrom(BaseCPU *oldCPU); - virtual void activateContext(int thread_num, int delay); - virtual void suspendContext(int thread_num); + virtual void activateContext(ThreadID thread_num, int delay); + virtual void suspendContext(ThreadID thread_num); Fault readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags); diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc index a12ab8e8a..e193b1273 100644 --- a/src/cpu/simple_thread.cc +++ b/src/cpu/simple_thread.cc @@ -47,14 +47,13 @@ #include "cpu/quiesce_event.hh" #include "cpu/simple_thread.hh" #include "cpu/thread_context.hh" -#include "params/BaseCPU.hh" #include "mem/fs_translating_port_proxy.hh" #include "mem/se_translating_port_proxy.hh" +#include "params/BaseCPU.hh" #include "sim/full_system.hh" #include "sim/process.hh" #include "sim/serialize.hh" #include "sim/sim_exit.hh" -#include "sim/process.hh" #include "sim/system.hh" using namespace std; @@ -62,8 +61,7 @@ using namespace std; // constructor SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, Process *_process, TheISA::TLB *_itb, TheISA::TLB *_dtb) - : ThreadState(_cpu, _thread_num, _process), - cpu(_cpu), itb(_itb), dtb(_dtb) + : ThreadState(_cpu, _thread_num, _process), itb(_itb), dtb(_dtb) { clearArchRegs(); tc = new ProxyThreadContext<SimpleThread>(this); @@ -71,9 +69,7 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, Process *_process, SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys, TheISA::TLB *_itb, TheISA::TLB *_dtb, bool use_kernel_stats) - : ThreadState(_cpu, _thread_num, NULL), - cpu(_cpu), system(_sys), itb(_itb), dtb(_dtb) - + : ThreadState(_cpu, _thread_num, NULL), system(_sys), itb(_itb), dtb(_dtb) { tc = new ProxyThreadContext<SimpleThread>(this); @@ -81,7 +77,7 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys, clearArchRegs(); - if (cpu->params()->profile) { + if (baseCpu->params()->profile) { profile = new FunctionProfile(system->kernelSymtab); Callback *cb = new MakeCallback<SimpleThread, @@ -183,7 +179,7 @@ SimpleThread::serialize(ostream &os) // // Now must serialize all the ISA dependent state // - isa.serialize(cpu, os); + isa.serialize(baseCpu, os); } @@ -199,13 +195,14 @@ SimpleThread::unserialize(Checkpoint *cp, const std::string §ion) // // Now must unserialize all the ISA dependent state // - isa.unserialize(cpu, cp, section); + isa.unserialize(baseCpu, cp, section); } void SimpleThread::dumpFuncProfile() { - std::ostream *os = simout.create(csprintf("profile.%s.dat", cpu->name())); + std::ostream *os = simout.create(csprintf("profile.%s.dat", + baseCpu->name())); profile->dump(tc, *os); } @@ -225,7 +222,7 @@ SimpleThread::activate(int delay) _status = ThreadContext::Active; // status() == Suspended - cpu->activateContext(_threadId, delay); + baseCpu->activateContext(_threadId, delay); } void @@ -237,7 +234,7 @@ SimpleThread::suspend() lastActivate = curTick(); lastSuspend = curTick(); _status = ThreadContext::Suspended; - cpu->suspendContext(_threadId); + baseCpu->suspendContext(_threadId); } @@ -248,7 +245,7 @@ SimpleThread::halt() return; _status = ThreadContext::Halted; - cpu->haltContext(_threadId); + baseCpu->haltContext(_threadId); } diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh index 97964c0e8..39cb96c3a 100644 --- a/src/cpu/simple_thread.hh +++ b/src/cpu/simple_thread.hh @@ -1,4 +1,16 @@ /* + * 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. + * * Copyright (c) 2001-2006 The Regents of The University of Michigan * All rights reserved. * @@ -39,6 +51,7 @@ #include "arch/types.hh" #include "base/types.hh" #include "config/the_isa.hh" +#include "config/use_checker.hh" #include "cpu/decode.hh" #include "cpu/thread_context.hh" #include "cpu/thread_state.hh" @@ -106,12 +119,9 @@ class SimpleThread : public ThreadState public: std::string name() const { - return csprintf("%s.[tid:%i]", cpu->name(), tc->threadId()); + return csprintf("%s.[tid:%i]", baseCpu->name(), tc->threadId()); } - // pointer to CPU associated with this SimpleThread - BaseCPU *cpu; - ProxyThreadContext<SimpleThread> *tc; System *system; @@ -182,12 +192,16 @@ class SimpleThread : public ThreadState * ThreadContext interface functions. ******************************************/ - BaseCPU *getCpuPtr() { return cpu; } + BaseCPU *getCpuPtr() { return baseCpu; } TheISA::TLB *getITBPtr() { return itb; } TheISA::TLB *getDTBPtr() { return dtb; } +#if USE_CHECKER + BaseCPU *getCheckerCpuPtr() { return NULL; } +#endif + Decoder *getDecoderPtr() { return &decoder; } System *getSystemPtr() { return system; } @@ -281,7 +295,10 @@ class SimpleThread : public ThreadState { int flatIndex = isa.flattenFloatIndex(reg_idx); assert(flatIndex < TheISA::NumFloatRegs); - floatRegs.i[flatIndex] = val; + // XXX: Fix array out of bounds compiler error for gem5.fast + // when checkercpu enabled + if (flatIndex < TheISA::NumFloatRegs) + floatRegs.i[flatIndex] = val; DPRINTF(FloatRegs, "Setting float reg %d (%d) bits to %#x, %#f.\n", reg_idx, flatIndex, val, floatRegs.f[flatIndex]); } @@ -298,6 +315,14 @@ class SimpleThread : public ThreadState _pcState = val; } +#if USE_CHECKER + void + pcStateNoRecord(const TheISA::PCState &val) + { + _pcState = val; + } +#endif + Addr instAddr() { diff --git a/src/cpu/static_inst.hh b/src/cpu/static_inst.hh index adda82c49..7c5fcaa3a 100644 --- a/src/cpu/static_inst.hh +++ b/src/cpu/static_inst.hh @@ -52,7 +52,7 @@ class ThreadContext; class DynInst; class Packet; -class O3CPUImpl; +struct O3CPUImpl; template <class Impl> class BaseO3DynInst; typedef BaseO3DynInst<O3CPUImpl> O3DynInst; template <class Impl> class OzoneDynInst; diff --git a/src/cpu/thread_context.hh b/src/cpu/thread_context.hh index 261ace7cf..2f2e5b02b 100644 --- a/src/cpu/thread_context.hh +++ b/src/cpu/thread_context.hh @@ -1,4 +1,16 @@ /* + * 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. + * * Copyright (c) 2006 The Regents of The University of Michigan * All rights reserved. * @@ -38,6 +50,7 @@ #include "arch/types.hh" #include "base/types.hh" #include "config/the_isa.hh" +#include "config/use_checker.hh" // @todo: Figure out a more architecture independent way to obtain the ITB and // DTB pointers. @@ -120,6 +133,10 @@ class ThreadContext virtual TheISA::TLB *getDTBPtr() = 0; +#if USE_CHECKER + virtual BaseCPU *getCheckerCpuPtr() = 0; +#endif + virtual Decoder *getDecoderPtr() = 0; virtual System *getSystemPtr() = 0; @@ -198,6 +215,10 @@ class ThreadContext virtual void pcState(const TheISA::PCState &val) = 0; +#if USE_CHECKER + virtual void pcStateNoRecord(const TheISA::PCState &val) = 0; +#endif + virtual Addr instAddr() = 0; virtual Addr nextInstAddr() = 0; @@ -287,6 +308,10 @@ class ProxyThreadContext : public ThreadContext TheISA::TLB *getDTBPtr() { return actualTC->getDTBPtr(); } +#if USE_CHECKER + BaseCPU *getCheckerCpuPtr() { return actualTC->getCheckerCpuPtr(); } +#endif + Decoder *getDecoderPtr() { return actualTC->getDecoderPtr(); } System *getSystemPtr() { return actualTC->getSystemPtr(); } @@ -367,6 +392,10 @@ class ProxyThreadContext : public ThreadContext void pcState(const TheISA::PCState &val) { actualTC->pcState(val); } +#if USE_CHECKER + void pcStateNoRecord(const TheISA::PCState &val) { actualTC->pcState(val); } +#endif + Addr instAddr() { return actualTC->instAddr(); } Addr nextInstAddr() { return actualTC->nextInstAddr(); } MicroPC microPC() { return actualTC->microPC(); } diff --git a/src/cpu/thread_state.hh b/src/cpu/thread_state.hh index 30bb64ed7..3622ed37f 100644 --- a/src/cpu/thread_state.hh +++ b/src/cpu/thread_state.hh @@ -64,7 +64,7 @@ struct ThreadState { ThreadState(BaseCPU *cpu, ThreadID _tid, Process *_process); - ~ThreadState(); + virtual ~ThreadState(); void serialize(std::ostream &os); diff --git a/src/dev/alpha/tsunami_cchip.cc b/src/dev/alpha/tsunami_cchip.cc index 74f769c86..0960c71ab 100644 --- a/src/dev/alpha/tsunami_cchip.cc +++ b/src/dev/alpha/tsunami_cchip.cc @@ -53,7 +53,6 @@ #include "params/TsunamiCChip.hh" #include "sim/system.hh" -using namespace std; //Should this be AlphaISA? using namespace TheISA; diff --git a/src/dev/alpha/tsunami_io.cc b/src/dev/alpha/tsunami_io.cc index 0c1937a32..bccdddf85 100644 --- a/src/dev/alpha/tsunami_io.cc +++ b/src/dev/alpha/tsunami_io.cc @@ -54,7 +54,11 @@ #include "mem/port.hh" #include "sim/system.hh" -using namespace std; +// clang complains about std::set being overloaded with Packet::set if +// we open up the entire namespace std +using std::string; +using std::ostream; + //Should this be AlphaISA? using namespace TheISA; diff --git a/src/dev/arm/pl111.cc b/src/dev/arm/pl111.cc index 263a3b620..d416ab31f 100644 --- a/src/dev/arm/pl111.cc +++ b/src/dev/arm/pl111.cc @@ -50,6 +50,10 @@ #include "mem/packet.hh" #include "mem/packet_access.hh" +// clang complains about std::set being overloaded with Packet::set if +// we open up the entire namespace std +using std::vector; + using namespace AmbaDev; // initialize clcd registers @@ -69,11 +73,12 @@ Pl111::Pl111(const Params *p) pic = simout.create(csprintf("%s.framebuffer.bmp", sys->name()), true); - dmaBuffer = new uint8_t[LcdMaxWidth * LcdMaxHeight * sizeof(uint32_t)]; + const int buffer_size = LcdMaxWidth * LcdMaxHeight * sizeof(uint32_t); + dmaBuffer = new uint8_t[buffer_size]; memset(lcdPalette, 0, sizeof(lcdPalette)); memset(cursorImage, 0, sizeof(cursorImage)); - memset(dmaBuffer, 0, sizeof(dmaBuffer)); + memset(dmaBuffer, 0, buffer_size); if (vncserver) vncserver->setFramebufferAddr(dmaBuffer); diff --git a/src/dev/arm/pl111.hh b/src/dev/arm/pl111.hh index b2dc1f640..e0a03641c 100644 --- a/src/dev/arm/pl111.hh +++ b/src/dev/arm/pl111.hh @@ -53,8 +53,6 @@ #include "params/Pl111.hh" #include "sim/serialize.hh" -using namespace std; - class Gic; class VncServer; class Bitmap; @@ -304,7 +302,7 @@ class Pl111: public AmbaDmaDevice EventWrapper<Pl111, &Pl111::fillFifo> fillFifoEvent; /** DMA done event */ - vector<EventWrapper<Pl111, &Pl111::dmaDone> > dmaDoneEvent; + std::vector<EventWrapper<Pl111, &Pl111::dmaDone> > dmaDoneEvent; /** Wrapper to create an event out of the interrupt */ EventWrapper<Pl111, &Pl111::generateInterrupt> intEvent; diff --git a/src/dev/copy_engine.cc b/src/dev/copy_engine.cc index 361d4db1b..33994cfde 100644 --- a/src/dev/copy_engine.cc +++ b/src/dev/copy_engine.cc @@ -45,7 +45,6 @@ #include "sim/system.hh" using namespace CopyEngineReg; -using namespace std; CopyEngine::CopyEngine(const Params *p) : PciDev(p) diff --git a/src/dev/disk_image.cc b/src/dev/disk_image.cc index 4c770fbcd..c9defb605 100644 --- a/src/dev/disk_image.cc +++ b/src/dev/disk_image.cc @@ -170,12 +170,12 @@ CowDiskImage::CowDiskImage(const Params *p) : DiskImage(p), filename(p->image_file), child(p->child), table(NULL) { if (filename.empty()) { - init(p->table_size); + initSectorTable(p->table_size); } else { if (!open(filename)) { if (p->read_only) fatal("could not open read-only file"); - init(p->table_size); + initSectorTable(p->table_size); } if (!p->read_only) @@ -270,7 +270,7 @@ CowDiskImage::open(const string &file) } void -CowDiskImage::init(int hash_size) +CowDiskImage::initSectorTable(int hash_size) { table = new SectorTable(hash_size); diff --git a/src/dev/disk_image.hh b/src/dev/disk_image.hh index 3865562a0..1b846522f 100644 --- a/src/dev/disk_image.hh +++ b/src/dev/disk_image.hh @@ -121,7 +121,7 @@ class CowDiskImage : public DiskImage CowDiskImage(const Params *p); ~CowDiskImage(); - void init(int hash_size); + void initSectorTable(int hash_size); bool open(const std::string &file); void save(); void save(const std::string &file); diff --git a/src/dev/ide_ctrl.cc b/src/dev/ide_ctrl.cc index 5a663bac9..f33d603af 100644 --- a/src/dev/ide_ctrl.cc +++ b/src/dev/ide_ctrl.cc @@ -32,7 +32,6 @@ #include <string> -#include "base/trace.hh" #include "cpu/intr_control.hh" #include "debug/IdeCtrl.hh" #include "dev/ide_ctrl.hh" @@ -42,7 +41,9 @@ #include "params/IdeController.hh" #include "sim/byteswap.hh" -using namespace std; +// clang complains about std::set being overloaded with Packet::set if +// we open up the entire namespace std +using std::string; // Bus master IDE registers enum BMIRegOffset { diff --git a/src/dev/ns_gige.cc b/src/dev/ns_gige.cc index eb6eb6353..4dc4aeae9 100644 --- a/src/dev/ns_gige.cc +++ b/src/dev/ns_gige.cc @@ -50,6 +50,12 @@ #include "params/NSGigE.hh" #include "sim/system.hh" +// clang complains about std::set being overloaded with Packet::set if +// we open up the entire namespace std +using std::min; +using std::ostream; +using std::string; + const char *NsRxStateStrings[] = { "rxIdle", @@ -81,7 +87,6 @@ const char *NsDmaState[] = "dmaWriteWaiting" }; -using namespace std; using namespace Net; using namespace TheISA; @@ -479,12 +484,12 @@ NSGigE::write(PacketPtr pkt) // all these #if 0's are because i don't THINK the kernel needs to // have these implemented. if there is a problem relating to one of // these, you may need to add functionality in. + +// grouped together and #if 0'ed to avoid empty if body and make clang happy +#if 0 if (reg & CFGR_TBI_EN) ; if (reg & CFGR_MODE_1000) ; - if (reg & CFGR_AUTO_1000) - panic("CFGR_AUTO_1000 not implemented!\n"); - if (reg & CFGR_PINT_DUPSTS || reg & CFGR_PINT_LNKSTS || reg & CFGR_PINT_SPDSTS) @@ -494,22 +499,11 @@ NSGigE::write(PacketPtr pkt) if (reg & CFGR_MRM_DIS) ; if (reg & CFGR_MWI_DIS) ; - if (reg & CFGR_T64ADDR) ; - // panic("CFGR_T64ADDR is read only register!\n"); - - if (reg & CFGR_PCI64_DET) - panic("CFGR_PCI64_DET is read only register!\n"); - if (reg & CFGR_DATA64_EN) ; if (reg & CFGR_M64ADDR) ; if (reg & CFGR_PHY_RST) ; if (reg & CFGR_PHY_DIS) ; - if (reg & CFGR_EXTSTS_EN) - extstsEnable = true; - else - extstsEnable = false; - if (reg & CFGR_REQALG) ; if (reg & CFGR_SB) ; if (reg & CFGR_POW) ; @@ -518,6 +512,20 @@ NSGigE::write(PacketPtr pkt) if (reg & CFGR_BROM_DIS) ; if (reg & CFGR_EXT_125) ; if (reg & CFGR_BEM) ; + + if (reg & CFGR_T64ADDR) ; + // panic("CFGR_T64ADDR is read only register!\n"); +#endif + if (reg & CFGR_AUTO_1000) + panic("CFGR_AUTO_1000 not implemented!\n"); + + if (reg & CFGR_PCI64_DET) + panic("CFGR_PCI64_DET is read only register!\n"); + + if (reg & CFGR_EXTSTS_EN) + extstsEnable = true; + else + extstsEnable = false; break; case MEAR: @@ -541,9 +549,13 @@ NSGigE::write(PacketPtr pkt) eepromClk = reg & MEAR_EECLK; // since phy is completely faked, MEAR_MD* don't matter + +// grouped together and #if 0'ed to avoid empty if body and make clang happy +#if 0 if (reg & MEAR_MDIO) ; if (reg & MEAR_MDDIR) ; if (reg & MEAR_MDC) ; +#endif break; case PTSCR: diff --git a/src/dev/pciconfigall.cc b/src/dev/pciconfigall.cc index e7130e11d..320f45543 100644 --- a/src/dev/pciconfigall.cc +++ b/src/dev/pciconfigall.cc @@ -43,8 +43,6 @@ #include "params/PciConfigAll.hh" #include "sim/system.hh" -using namespace std; - PciConfigAll::PciConfigAll(const Params *p) : PioDevice(p) { diff --git a/src/dev/pcidev.cc b/src/dev/pcidev.cc index 42c803553..cb27f8b3d 100644 --- a/src/dev/pcidev.cc +++ b/src/dev/pcidev.cc @@ -52,8 +52,6 @@ #include "sim/byteswap.hh" #include "sim/core.hh" -using namespace std; - PciDev::PciConfigPort::PciConfigPort(PciDev *dev, int busid, int devid, int funcid, Platform *p) @@ -341,7 +339,7 @@ PciDev::writeConfig(PacketPtr pkt) } void -PciDev::serialize(ostream &os) +PciDev::serialize(std::ostream &os) { SERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); SERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); diff --git a/src/mem/bus.cc b/src/mem/bus.cc index a20f90108..dfe4be3cc 100644 --- a/src/mem/bus.cc +++ b/src/mem/bus.cc @@ -436,7 +436,8 @@ Bus::recvFunctional(PacketPtr pkt) pkt->setSrc(src_id); } - // If the snooping hasn't found what we were looking for, keep going. + // If the snooping hasn't found what we were looking for and it is not + // a forwarded snoop from below, keep going. if (!pkt->isResponse() && port_id != pkt->getSrc()) { port->sendFunctional(pkt); } diff --git a/src/mem/cache/base.cc b/src/mem/cache/base.cc index 2b7fa4b9f..b0fb3bc6c 100644 --- a/src/mem/cache/base.cc +++ b/src/mem/cache/base.cc @@ -45,8 +45,7 @@ using namespace std; BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache, const std::string &_label) : SimpleTimingPort(_name, _cache), cache(_cache), - label(_label), otherPort(NULL), - blocked(false), mustSendRetry(false) + label(_label), blocked(false), mustSendRetry(false) { } @@ -70,12 +69,6 @@ BaseCache::BaseCache(const Params *p) { } -void -BaseCache::CachePort::recvRangeChange() const -{ - otherPort->sendRangeChange(); -} - bool BaseCache::CachePort::checkFunctional(PacketPtr pkt) diff --git a/src/mem/cache/base.hh b/src/mem/cache/base.hh index fded6fca6..3aaed4455 100644 --- a/src/mem/cache/base.hh +++ b/src/mem/cache/base.hh @@ -73,6 +73,7 @@ class BaseCache : public MemObject MSHRQueue_WriteBuffer }; + public: /** * Reasons for caches to be blocked. */ @@ -83,7 +84,6 @@ class BaseCache : public MemObject NUM_BLOCKED_CAUSES }; - public: /** * Reasons for cache to request a bus. */ @@ -94,7 +94,7 @@ class BaseCache : public MemObject NUM_REQUEST_CAUSES }; - private: + protected: class CachePort : public SimpleTimingPort { @@ -105,8 +105,6 @@ class BaseCache : public MemObject CachePort(const std::string &_name, BaseCache *_cache, const std::string &_label); - virtual void recvRangeChange() const; - virtual unsigned deviceBlockSize() const; bool recvRetryCommon(); @@ -117,16 +115,12 @@ class BaseCache : public MemObject const std::string label; public: - void setOtherPort(CachePort *_otherPort) { otherPort = _otherPort; } - void setBlocked(); void clearBlocked(); bool checkFunctional(PacketPtr pkt); - CachePort *otherPort; - bool blocked; bool mustSendRetry; @@ -144,7 +138,6 @@ class BaseCache : public MemObject } }; - public: //Made public so coherence can get at it. CachePort *cpuSidePort; CachePort *memSidePort; diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh index 13484eb79..2ef53e040 100644 --- a/src/mem/cache/cache_impl.hh +++ b/src/mem/cache/cache_impl.hh @@ -77,8 +77,6 @@ Cache<TagStore>::Cache(const Params *p, TagStore *tags, BasePrefetcher *pf) "CpuSidePort"); memSidePort = new MemSidePort(p->name + "-mem_side_port", this, "MemSidePort"); - cpuSidePort->setOtherPort(memSidePort); - memSidePort->setOtherPort(cpuSidePort); tags->setCache(this); if (prefetcher) diff --git a/src/mem/cache/tags/iic.cc b/src/mem/cache/tags/iic.cc index 71c3ba48c..acce3ffc8 100644 --- a/src/mem/cache/tags/iic.cc +++ b/src/mem/cache/tags/iic.cc @@ -187,7 +187,7 @@ IIC::regStats(const string &name) .flags(pdf) ; - repl->regStats(name); + repl->regStatsWithSuffix(name); if (PROFILE_IIC) setAccess diff --git a/src/mem/cache/tags/iic_repl/gen.cc b/src/mem/cache/tags/iic_repl/gen.cc index 7a1e7a110..137130b27 100644 --- a/src/mem/cache/tags/iic_repl/gen.cc +++ b/src/mem/cache/tags/iic_repl/gen.cc @@ -184,7 +184,7 @@ GenRepl::add(unsigned long tag_index) } void -GenRepl::regStats(const string name) +GenRepl::regStatsWithSuffix(const string name) { using namespace Stats; diff --git a/src/mem/cache/tags/iic_repl/gen.hh b/src/mem/cache/tags/iic_repl/gen.hh index fe105d95a..cbd15a6fd 100644 --- a/src/mem/cache/tags/iic_repl/gen.hh +++ b/src/mem/cache/tags/iic_repl/gen.hh @@ -209,7 +209,7 @@ class GenRepl : public Repl * Register statistics. * @param name The name to prepend to statistic descriptions. */ - virtual void regStats(const std::string name); + virtual void regStatsWithSuffix(const std::string name); /** * Update the tag pointer to when the tag moves. diff --git a/src/mem/cache/tags/iic_repl/repl.hh b/src/mem/cache/tags/iic_repl/repl.hh index 994af5164..51d8169e9 100644 --- a/src/mem/cache/tags/iic_repl/repl.hh +++ b/src/mem/cache/tags/iic_repl/repl.hh @@ -102,7 +102,7 @@ class Repl : public SimObject * Register statistics. * @param name The name to prepend to statistic descriptions. */ - virtual void regStats(const std::string name) = 0; + virtual void regStatsWithSuffix(const std::string name) = 0; /** * Update the tag pointer to when the tag moves. diff --git a/src/mem/packet.hh b/src/mem/packet.hh index e49ce7577..ce5748c24 100644 --- a/src/mem/packet.hh +++ b/src/mem/packet.hh @@ -53,7 +53,7 @@ #include "mem/request.hh" #include "sim/core.hh" -struct Packet; +class Packet; typedef Packet *PacketPtr; typedef uint8_t* PacketDataPtr; typedef std::list<PacketPtr> PacketList; diff --git a/src/mem/ruby/network/garnet/fixed-pipeline/GarnetNetwork_d.cc b/src/mem/ruby/network/garnet/fixed-pipeline/GarnetNetwork_d.cc index aee05b696..126c5c811 100644 --- a/src/mem/ruby/network/garnet/fixed-pipeline/GarnetNetwork_d.cc +++ b/src/mem/ruby/network/garnet/fixed-pipeline/GarnetNetwork_d.cc @@ -104,11 +104,12 @@ GarnetNetwork_d::init() for (vector<Router_d*>::const_iterator i= m_router_ptr_vector.begin(); i != m_router_ptr_vector.end(); ++i) { Router_d* router = safe_cast<Router_d*>(*i); - int router_id=fault_model->declare_router(router->get_num_inports(), - router->get_num_outports(), - router->get_vc_per_vnet(), - getBuffersPerDataVC(), - getBuffersPerCtrlVC()); + int router_id M5_VAR_USED = + fault_model->declare_router(router->get_num_inports(), + router->get_num_outports(), + router->get_vc_per_vnet(), + getBuffersPerDataVC(), + getBuffersPerCtrlVC()); assert(router_id == router->get_id()); router->printAggregateFaultProbability(cout); router->printFaultVector(cout); diff --git a/src/mem/ruby/system/Sequencer.hh b/src/mem/ruby/system/Sequencer.hh index e262e32e8..296258994 100644 --- a/src/mem/ruby/system/Sequencer.hh +++ b/src/mem/ruby/system/Sequencer.hh @@ -41,7 +41,7 @@ class DataBlock; class CacheMemory; -class RubySequencerParams; +struct RubySequencerParams; struct SequencerRequest { diff --git a/src/python/m5/SimObject.py b/src/python/m5/SimObject.py index 84d70d663..c45867c85 100644 --- a/src/python/m5/SimObject.py +++ b/src/python/m5/SimObject.py @@ -477,7 +477,7 @@ struct PyObject; #include <string> -struct EventQueue; +class EventQueue; ''') for param in params: param.cxx_predecls(code) diff --git a/src/sim/core.hh b/src/sim/core.hh index a529ff17b..4f842ab48 100644 --- a/src/sim/core.hh +++ b/src/sim/core.hh @@ -95,7 +95,7 @@ void setClockFrequency(Tick ticksPerSecond); void setOutputDir(const std::string &dir); -struct Callback; +class Callback; void registerExitCallback(Callback *callback); void doExitCleanup(); diff --git a/src/sim/process.cc b/src/sim/process.cc index 45362fe1b..8f3b3be79 100644 --- a/src/sim/process.cc +++ b/src/sim/process.cc @@ -86,8 +86,8 @@ AuxVector<IntType>::AuxVector(IntType type, IntType val) a_val = TheISA::htog(val); } -template class AuxVector<uint32_t>; -template class AuxVector<uint64_t>; +template struct AuxVector<uint32_t>; +template struct AuxVector<uint64_t>; Process::Process(ProcessParams * params) : SimObject(params), system(params->system), diff --git a/src/sim/process.hh b/src/sim/process.hh index 3896492b7..17b530ab8 100644 --- a/src/sim/process.hh +++ b/src/sim/process.hh @@ -43,8 +43,8 @@ #include "sim/syscallreturn.hh" class PageTable; -class ProcessParams; -class LiveProcessParams; +struct ProcessParams; +struct LiveProcessParams; class SyscallDesc; class System; class ThreadContext; diff --git a/src/sim/process_impl.hh b/src/sim/process_impl.hh index 401e16f52..0fb827498 100644 --- a/src/sim/process_impl.hh +++ b/src/sim/process_impl.hh @@ -47,7 +47,7 @@ copyStringArray(std::vector<std::string> &strings, { AddrType data_ptr_swap; for (std::vector<std::string>::size_type i = 0; i < strings.size(); ++i) { - data_ptr_swap = htog(data_ptr); + data_ptr_swap = TheISA::htog(data_ptr); memProxy->writeBlob(array_ptr, (uint8_t*)&data_ptr_swap, sizeof(AddrType)); memProxy->writeString(data_ptr, strings[i].c_str()); diff --git a/src/sim/pseudo_inst.cc b/src/sim/pseudo_inst.cc index b72fdca4a..8a7f0c469 100644 --- a/src/sim/pseudo_inst.cc +++ b/src/sim/pseudo_inst.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010-2011 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -51,6 +51,7 @@ #include "arch/kernel_stats.hh" #include "arch/vtophys.hh" #include "base/debug.hh" +#include "base/output.hh" #include "config/the_isa.hh" #include "cpu/base.hh" #include "cpu/quiesce_event.hh" @@ -387,6 +388,48 @@ readfile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset) return result; } +uint64_t +writefile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset, + Addr filename_addr) +{ + ostream *os; + + // copy out target filename + char fn[100]; + std::string filename; + CopyStringOut(tc, fn, filename_addr, 100); + filename = std::string(fn); + + if (offset == 0) { + // create a new file (truncate) + os = simout.create(filename, true); + } else { + // do not truncate file if offset is non-zero + // (ios::in flag is required as well to keep the existing data + // intact, otherwise existing data will be zeroed out.) + os = simout.openFile(simout.directory() + filename, + ios::in | ios::out | ios::binary); + } + if (!os) + panic("could not open file %s\n", filename); + + // seek to offset + os->seekp(offset); + + // copy out data and write to file + char *buf = new char[len]; + CopyOut(tc, buf, vaddr, len); + os->write(buf, len); + if (os->fail() || os->bad()) + panic("Error while doing writefile!\n"); + + simout.close(os); + + delete [] buf; + + return len; +} + void debugbreak(ThreadContext *tc) { diff --git a/src/sim/pseudo_inst.hh b/src/sim/pseudo_inst.hh index 399c88a4f..27d3b19d4 100644 --- a/src/sim/pseudo_inst.hh +++ b/src/sim/pseudo_inst.hh @@ -53,6 +53,8 @@ void quiesceCycles(ThreadContext *tc, uint64_t cycles); uint64_t quiesceTime(ThreadContext *tc); uint64_t readfile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset); +uint64_t writefile(ThreadContext *tc, Addr vaddr, uint64_t len, + uint64_t offset, Addr filenameAddr); void loadsymbol(ThreadContext *xc); void addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr); uint64_t initParam(ThreadContext *xc); diff --git a/src/sim/serialize.cc b/src/sim/serialize.cc index 03f900837..30655e692 100644 --- a/src/sim/serialize.cc +++ b/src/sim/serialize.cc @@ -438,7 +438,7 @@ class Globals : public Serializable public: const string name() const; void serialize(ostream &os); - void unserialize(Checkpoint *cp); + void unserialize(Checkpoint *cp, const std::string §ion); }; /// The one and only instance of the Globals class. @@ -461,9 +461,8 @@ Globals::serialize(ostream &os) } void -Globals::unserialize(Checkpoint *cp) +Globals::unserialize(Checkpoint *cp, const std::string §ion) { - const string §ion = name(); Tick tick; paramIn(cp, section, "curTick", tick); curTick(tick); @@ -510,7 +509,7 @@ Serializable::serializeAll(const string &cpt_dir) void Serializable::unserializeGlobals(Checkpoint *cp) { - globals.unserialize(cp); + globals.unserialize(cp, globals.name()); } void diff --git a/src/sim/sim_object.cc b/src/sim/sim_object.cc index 9ac0b7fff..95bc6bf84 100644 --- a/src/sim/sim_object.cc +++ b/src/sim/sim_object.cc @@ -169,7 +169,7 @@ SimObject::resume() } void -SimObject::setMemoryMode(State new_mode) +SimObject::setMemoryMode(Enums::MemoryMode new_mode) { panic("setMemoryMode() should only be called on systems"); } diff --git a/src/sim/sim_object.hh b/src/sim/sim_object.hh index 995431845..4388ff584 100644 --- a/src/sim/sim_object.hh +++ b/src/sim/sim_object.hh @@ -43,6 +43,7 @@ #include <string> #include <vector> +#include "enums/MemoryMode.hh" #include "params/SimObject.hh" #include "sim/eventq.hh" #include "sim/serialize.hh" @@ -146,7 +147,7 @@ class SimObject : public EventManager, public Serializable // before the object will be done draining. Normally this should be 1 virtual unsigned int drain(Event *drain_event); virtual void resume(); - virtual void setMemoryMode(State new_mode); + virtual void setMemoryMode(Enums::MemoryMode new_mode); virtual void switchOut(); virtual void takeOverFrom(BaseCPU *cpu); diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh index 45c87f0ab..ad00f6e3d 100644 --- a/src/sim/syscall_emul.hh +++ b/src/sim/syscall_emul.hh @@ -401,41 +401,41 @@ convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) tgt->st_dev = 0xA; else tgt->st_dev = host->st_dev; - tgt->st_dev = htog(tgt->st_dev); + tgt->st_dev = TheISA::htog(tgt->st_dev); tgt->st_ino = host->st_ino; - tgt->st_ino = htog(tgt->st_ino); + tgt->st_ino = TheISA::htog(tgt->st_ino); tgt->st_mode = host->st_mode; if (fakeTTY) { // Claim to be a character device tgt->st_mode &= ~S_IFMT; // Clear S_IFMT tgt->st_mode |= S_IFCHR; // Set S_IFCHR } - tgt->st_mode = htog(tgt->st_mode); + tgt->st_mode = TheISA::htog(tgt->st_mode); tgt->st_nlink = host->st_nlink; - tgt->st_nlink = htog(tgt->st_nlink); + tgt->st_nlink = TheISA::htog(tgt->st_nlink); tgt->st_uid = host->st_uid; - tgt->st_uid = htog(tgt->st_uid); + tgt->st_uid = TheISA::htog(tgt->st_uid); tgt->st_gid = host->st_gid; - tgt->st_gid = htog(tgt->st_gid); + tgt->st_gid = TheISA::htog(tgt->st_gid); if (fakeTTY) tgt->st_rdev = 0x880d; else tgt->st_rdev = host->st_rdev; - tgt->st_rdev = htog(tgt->st_rdev); + tgt->st_rdev = TheISA::htog(tgt->st_rdev); tgt->st_size = host->st_size; - tgt->st_size = htog(tgt->st_size); + tgt->st_size = TheISA::htog(tgt->st_size); tgt->st_atimeX = host->st_atime; - tgt->st_atimeX = htog(tgt->st_atimeX); + tgt->st_atimeX = TheISA::htog(tgt->st_atimeX); tgt->st_mtimeX = host->st_mtime; - tgt->st_mtimeX = htog(tgt->st_mtimeX); + tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX); tgt->st_ctimeX = host->st_ctime; - tgt->st_ctimeX = htog(tgt->st_ctimeX); + tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX); // Force the block size to be 8k. This helps to ensure buffered io works // consistently across different hosts. tgt->st_blksize = 0x2000; - tgt->st_blksize = htog(tgt->st_blksize); + tgt->st_blksize = TheISA::htog(tgt->st_blksize); tgt->st_blocks = host->st_blocks; - tgt->st_blocks = htog(tgt->st_blocks); + tgt->st_blocks = TheISA::htog(tgt->st_blocks); } // Same for stat64 @@ -449,11 +449,11 @@ convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); #if defined(STAT_HAVE_NSEC) tgt->st_atime_nsec = host->st_atime_nsec; - tgt->st_atime_nsec = htog(tgt->st_atime_nsec); + tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec); tgt->st_mtime_nsec = host->st_mtime_nsec; - tgt->st_mtime_nsec = htog(tgt->st_mtime_nsec); + tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec); tgt->st_ctime_nsec = host->st_ctime_nsec; - tgt->st_ctime_nsec = htog(tgt->st_ctime_nsec); + tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec); #else tgt->st_atime_nsec = 0; tgt->st_mtime_nsec = 0; @@ -967,9 +967,9 @@ writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process, p->readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); - hiov[i].iov_len = gtoh(tiov.iov_len); + hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); hiov[i].iov_base = new char [hiov[i].iov_len]; - p->readBlob(gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, + p->readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, hiov[i].iov_len); } @@ -1085,15 +1085,15 @@ getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, case OS::TGT_RLIMIT_STACK: // max stack size in bytes: make up a number (8MB for now) rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; - rlp->rlim_cur = htog(rlp->rlim_cur); - rlp->rlim_max = htog(rlp->rlim_max); + rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); + rlp->rlim_max = TheISA::htog(rlp->rlim_max); break; case OS::TGT_RLIMIT_DATA: // max data segment size in bytes: make up a number rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; - rlp->rlim_cur = htog(rlp->rlim_cur); - rlp->rlim_max = htog(rlp->rlim_max); + rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); + rlp->rlim_max = TheISA::htog(rlp->rlim_max); break; default: @@ -1148,8 +1148,8 @@ utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, struct timeval hostTimeval[2]; for (int i = 0; i < 2; ++i) { - hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec); - hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec); + hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); + hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); } // Adjust path for current working directory @@ -1194,8 +1194,8 @@ getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process, switch (who) { case OS::TGT_RUSAGE_SELF: getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); - rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec); - rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec); + rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); + rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); break; case OS::TGT_RUSAGE_CHILDREN: @@ -1231,7 +1231,7 @@ timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, bufp->tms_cstime = 0; // Convert to host endianness - bufp->tms_utime = htog(bufp->tms_utime); + bufp->tms_utime = TheISA::htog(bufp->tms_utime); // Write back bufp.copyOut(tc->getMemProxy()); @@ -1254,7 +1254,7 @@ timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process, Addr taddr = (Addr)process->getSyscallArg(tc, index); if(taddr != 0) { typename OS::time_t t = sec; - t = htog(t); + t = TheISA::htog(t); SETranslatingPortProxy *p = tc->getMemProxy(); p->writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); } diff --git a/util/m5/m5.c b/util/m5/m5.c index 40328bc38..a0ce9b3ec 100644 --- a/util/m5/m5.c +++ b/util/m5/m5.c @@ -88,6 +88,33 @@ read_file(int dest_fid) } } +int +write_file(const char *filename) +{ + fprintf(stderr, "opening %s\n", filename); + int src_fid = open(filename, O_RDONLY); + + if (src_fid < 0) { + fprintf(stderr, "error opening %s\n", filename); + return; + } + + char buf[256*1024]; + int offset = 0; + int len; + int bytes = 0; + + memset(buf, 0, sizeof(buf)); + + while ((len = read(src_fid, buf, sizeof(buf))) > 0) { + bytes += m5_writefile(buf, len, offset, filename); + offset += len; + } + fprintf(stderr, "written %d bytes\n", bytes); + + close(src_fid); +} + void do_exit(int argc, char *argv[]) { @@ -131,6 +158,17 @@ do_read_file(int argc, char *argv[]) } void +do_write_file(int argc, char *argv[]) +{ + if (argc != 1) + usage(); + + const char *filename = argv[0]; + + write_file(filename); +} + +void do_exec_file(int argc, char *argv[]) { if (argc > 0) @@ -227,8 +265,9 @@ struct MainFunc mainfuncs[] = { { "resetstats", do_reset_stats, "[delay [period]]" }, { "dumpstats", do_dump_stats, "[delay [period]]" }, { "dumpresetstats", do_dump_reset_stats, "[delay [period]]" }, - { "readfile", do_read_file, "[filename]" }, - { "execfile", do_exec_file, "<filename>" }, + { "readfile", do_read_file, "" }, + { "writefile", do_write_file, "<filename>" }, + { "execfile", do_exec_file, "" }, { "checkpoint", do_checkpoint, "[delay [period]]" }, { "loadsymbol", do_load_symbol, "<address> <symbol>" }, { "initparam", do_initparam, "" }, diff --git a/util/m5/m5op.h b/util/m5/m5op.h index 38815e3c3..4e1d0b638 100644 --- a/util/m5/m5op.h +++ b/util/m5/m5op.h @@ -49,6 +49,7 @@ void m5_reset_stats(uint64_t ns_delay, uint64_t ns_period); void m5_dump_stats(uint64_t ns_delay, uint64_t ns_period); void m5_dumpreset_stats(uint64_t ns_delay, uint64_t ns_period); uint64_t m5_readfile(void *buffer, uint64_t len, uint64_t offset); +uint64_t m5_writefile(void *buffer, uint64_t len, uint64_t offset, const char *filename); void m5_debugbreak(void); void m5_switchcpu(void); void m5_addsymbol(uint64_t addr, char *symbol); diff --git a/util/m5/m5op_arm.S b/util/m5/m5op_arm.S index b9557ee9d..8cdf5c62d 100644 --- a/util/m5/m5op_arm.S +++ b/util/m5/m5op_arm.S @@ -80,6 +80,7 @@ func: #define DUMPRST_STATS INST(m5_op, 0, 0, dumprststats_func) #define CHECKPOINT INST(m5_op, 0, 0, ckpt_func) #define READFILE INST(m5_op, 0, 0, readfile_func) +#define WRITEFILE INST(m5_op, 0, 0, writefile_func) #define DEBUGBREAK INST(m5_op, 0, 0, debugbreak_func) #define SWITCHCPU INST(m5_op, 0, 0, switchcpu_func) #define ADDSYMBOL INST(m5_op, 0, 0, addsymbol_func) @@ -121,6 +122,7 @@ SIMPLE_OP(m5_dump_stats, DUMP_STATS) SIMPLE_OP(m5_dumpreset_stats, DUMPRST_STATS) SIMPLE_OP(m5_checkpoint, CHECKPOINT) SIMPLE_OP(m5_readfile, READFILE) +SIMPLE_OP(m5_writefile, WRITEFILE) SIMPLE_OP(m5_debugbreak, DEBUGBREAK) SIMPLE_OP(m5_switchcpu, SWITCHCPU) SIMPLE_OP(m5_addsymbol, ADDSYMBOL) diff --git a/util/m5/m5ops.h b/util/m5/m5ops.h index bc2ae06be..f08524014 100644 --- a/util/m5/m5ops.h +++ b/util/m5/m5ops.h @@ -46,6 +46,7 @@ #define dumpstats_func 0x41 #define dumprststats_func 0x42 #define ckpt_func 0x43 +#define writefile_func 0x4F #define readfile_func 0x50 #define debugbreak_func 0x51 #define switchcpu_func 0x52 |