From: Gabe Black Date: Wed, 25 Feb 2009 18:16:15 +0000 (-0800) Subject: CPU: Implement translateTiming which defers to translateAtomic, and convert the timin... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=6ed47e94644f854baa33d1e9f367cc9eebd99abf;p=gem5.git CPU: Implement translateTiming which defers to translateAtomic, and convert the timing simple CPU to use it. --- diff --git a/src/arch/alpha/tlb.cc b/src/arch/alpha/tlb.cc index 82d410987..2b0afacfe 100644 --- a/src/arch/alpha/tlb.cc +++ b/src/arch/alpha/tlb.cc @@ -317,7 +317,7 @@ ITB::regStats() } Fault -ITB::translateAtomic(RequestPtr &req, ThreadContext *tc) +ITB::translateAtomic(RequestPtr req, ThreadContext *tc) { //If this is a pal pc, then set PHYSICAL if (FULL_SYSTEM && PcPAL(req->getPC())) @@ -401,6 +401,14 @@ ITB::translateAtomic(RequestPtr &req, ThreadContext *tc) } +void +ITB::translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation) +{ + assert(translation); + translation->finish(translateAtomic(req, tc), req, tc, false); +} + /////////////////////////////////////////////////////////////////////// // // Alpha DTB @@ -479,7 +487,7 @@ DTB::regStats() } Fault -DTB::translateAtomic(RequestPtr &req, ThreadContext *tc, bool write) +DTB::translateAtomic(RequestPtr req, ThreadContext *tc, bool write) { Addr pc = tc->readPC(); @@ -616,6 +624,14 @@ DTB::translateAtomic(RequestPtr &req, ThreadContext *tc, bool write) return checkCacheability(req); } +void +DTB::translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write) +{ + assert(translation); + translation->finish(translateAtomic(req, tc, write), req, tc, write); +} + TlbEntry & TLB::index(bool advance) { diff --git a/src/arch/alpha/tlb.hh b/src/arch/alpha/tlb.hh index f5d2dbca9..877533797 100644 --- a/src/arch/alpha/tlb.hh +++ b/src/arch/alpha/tlb.hh @@ -131,7 +131,9 @@ class ITB : public TLB ITB(const Params *p); virtual void regStats(); - Fault translateAtomic(RequestPtr &req, ThreadContext *tc); + Fault translateAtomic(RequestPtr req, ThreadContext *tc); + void translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation); }; class DTB : public TLB @@ -155,7 +157,9 @@ class DTB : public TLB DTB(const Params *p); virtual void regStats(); - Fault translateAtomic(RequestPtr &req, ThreadContext *tc, bool write); + Fault translateAtomic(RequestPtr req, ThreadContext *tc, bool write); + void translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write); }; } // namespace AlphaISA diff --git a/src/arch/mips/tlb.cc b/src/arch/mips/tlb.cc index db21c7919..eac44eba8 100644 --- a/src/arch/mips/tlb.cc +++ b/src/arch/mips/tlb.cc @@ -310,7 +310,7 @@ TLB::regStats() } Fault -ITB::translateAtomic(RequestPtr &req, ThreadContext *tc) +ITB::translateAtomic(RequestPtr req, ThreadContext *tc) { #if !FULL_SYSTEM Process * p = tc->getProcessPtr(); @@ -426,8 +426,16 @@ ITB::translateAtomic(RequestPtr &req, ThreadContext *tc) #endif } +void +ITB::translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation) +{ + assert(translation); + translation->finish(translateAtomic(req, tc), req, tc, false); +} + Fault -DTB::translateAtomic(RequestPtr &req, ThreadContext *tc, bool write) +DTB::translateAtomic(RequestPtr req, ThreadContext *tc, bool write) { #if !FULL_SYSTEM Process * p = tc->getProcessPtr(); @@ -564,6 +572,14 @@ DTB::translateAtomic(RequestPtr &req, ThreadContext *tc, bool write) #endif } +void +DTB::translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write) +{ + assert(translation); + translation->finish(translateAtomic(req, tc, write), req, tc, write); +} + /////////////////////////////////////////////////////////////////////// // // Mips ITB diff --git a/src/arch/mips/tlb.hh b/src/arch/mips/tlb.hh index acb393116..1ab9d77e5 100644 --- a/src/arch/mips/tlb.hh +++ b/src/arch/mips/tlb.hh @@ -145,7 +145,9 @@ class ITB : public TLB { typedef MipsTLBParams Params; ITB(const Params *p); - Fault translateAtomic(RequestPtr &req, ThreadContext *tc); + Fault translateAtomic(RequestPtr req, ThreadContext *tc); + void translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation); }; class DTB : public TLB { @@ -153,8 +155,10 @@ class DTB : public TLB { typedef MipsTLBParams Params; DTB(const Params *p); - Fault translateAtomic(RequestPtr &req, ThreadContext *tc, + Fault translateAtomic(RequestPtr req, ThreadContext *tc, bool write = false); + void translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write = false); }; class UTB : public ITB, public DTB { diff --git a/src/arch/sparc/tlb.cc b/src/arch/sparc/tlb.cc index 683d916df..95ad0229e 100644 --- a/src/arch/sparc/tlb.cc +++ b/src/arch/sparc/tlb.cc @@ -436,7 +436,7 @@ DTB::writeSfsr(Addr a, bool write, ContextType ct, } Fault -ITB::translateAtomic(RequestPtr &req, ThreadContext *tc) +ITB::translateAtomic(RequestPtr req, ThreadContext *tc) { uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA); @@ -548,8 +548,16 @@ ITB::translateAtomic(RequestPtr &req, ThreadContext *tc) return NoFault; } +void +ITB::translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation) +{ + assert(translation); + translation->finish(translateAtomic(req, tc), req, tc, false); +} + Fault -DTB::translateAtomic(RequestPtr &req, ThreadContext *tc, bool write) +DTB::translateAtomic(RequestPtr req, ThreadContext *tc, bool write) { /* * @todo this could really use some profiling and fixing to make @@ -847,6 +855,14 @@ handleMmuRegAccess: return NoFault; }; +void +DTB::translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write) +{ + assert(translation); + translation->finish(translateAtomic(req, tc, write), req, tc, write); +} + #if FULL_SYSTEM Tick diff --git a/src/arch/sparc/tlb.hh b/src/arch/sparc/tlb.hh index d563772e6..4fe532d4a 100644 --- a/src/arch/sparc/tlb.hh +++ b/src/arch/sparc/tlb.hh @@ -177,7 +177,9 @@ class ITB : public TLB cacheEntry = NULL; } - Fault translateAtomic(RequestPtr &req, ThreadContext *tc); + Fault translateAtomic(RequestPtr req, ThreadContext *tc); + void translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation); private: void writeSfsr(bool write, ContextType ct, bool se, FaultTypes ft, int asi); @@ -199,7 +201,10 @@ class DTB : public TLB cacheEntry[1] = NULL; } - Fault translateAtomic(RequestPtr &req, ThreadContext *tc, bool write); + Fault translateAtomic(RequestPtr req, + ThreadContext *tc, bool write=false); + void translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write=false); #if FULL_SYSTEM Tick doMmuRegRead(ThreadContext *tc, Packet *pkt); Tick doMmuRegWrite(ThreadContext *tc, Packet *pkt); diff --git a/src/arch/x86/tlb.cc b/src/arch/x86/tlb.cc index 33017a6aa..a34922b44 100644 --- a/src/arch/x86/tlb.cc +++ b/src/arch/x86/tlb.cc @@ -190,7 +190,7 @@ TLB::demapPage(Addr va, uint64_t asn) template Fault -TLB::translateAtomic(RequestPtr &req, ThreadContext *tc, +TLB::translateAtomic(RequestPtr req, ThreadContext *tc, bool write, bool execute) { Addr vaddr = req->getVaddr(); @@ -663,17 +663,33 @@ TLB::translateAtomic(RequestPtr &req, ThreadContext *tc, }; Fault -DTB::translateAtomic(RequestPtr &req, ThreadContext *tc, bool write) +DTB::translateAtomic(RequestPtr req, ThreadContext *tc, bool write) { return TLB::translateAtomic(req, tc, write, false); } +void +DTB::translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write) +{ + assert(translation); + translation->finish(translateAtomic(req, tc, write), req, tc, write); +} + Fault -ITB::translateAtomic(RequestPtr &req, ThreadContext *tc) +ITB::translateAtomic(RequestPtr req, ThreadContext *tc) { return TLB::translateAtomic(req, tc, false, true); } +void +ITB::translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation) +{ + assert(translation); + translation->finish(translateAtomic(req, tc), req, tc, false); +} + #if FULL_SYSTEM Tick diff --git a/src/arch/x86/tlb.hh b/src/arch/x86/tlb.hh index 91bb4a761..56730983a 100644 --- a/src/arch/x86/tlb.hh +++ b/src/arch/x86/tlb.hh @@ -138,8 +138,10 @@ namespace X86ISA EntryList entryList; template - Fault translateAtomic(RequestPtr &req, ThreadContext *tc, + Fault translateAtomic(RequestPtr req, ThreadContext *tc, bool write, bool execute); + void translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write, bool execute); public: @@ -159,7 +161,9 @@ namespace X86ISA _allowNX = false; } - Fault translateAtomic(RequestPtr &req, ThreadContext *tc); + Fault translateAtomic(RequestPtr req, ThreadContext *tc); + void translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation); friend class DTB; }; @@ -172,7 +176,9 @@ namespace X86ISA { _allowNX = true; } - Fault translateAtomic(RequestPtr &req, ThreadContext *tc, bool write); + Fault translateAtomic(RequestPtr req, ThreadContext *tc, bool write); + void translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write); #if FULL_SYSTEM Tick doMmuRegRead(ThreadContext *tc, Packet *pkt); Tick doMmuRegWrite(ThreadContext *tc, Packet *pkt); diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index 7a1cf71c4..2ada12b8d 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -607,8 +607,10 @@ AtomicSimpleCPU::tick() Fault fault = NoFault; bool fromRom = isRomMicroPC(thread->readMicroPC()); - if (!fromRom) - fault = setupFetchRequest(&ifetch_req); + if (!fromRom) { + setupFetchRequest(&ifetch_req); + fault = thread->itb->translateAtomic(&ifetch_req, tc); + } if (fault == NoFault) { Tick icache_latency = 0; diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index ddeb9a7c8..9372ff43d 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -330,7 +330,7 @@ BaseSimpleCPU::checkForInterrupts() } -Fault +void BaseSimpleCPU::setupFetchRequest(Request *req) { Addr threadPC = thread->readPC(); @@ -346,10 +346,6 @@ BaseSimpleCPU::setupFetchRequest(Request *req) Addr fetchPC = (threadPC & PCMask) + fetchOffset; req->setVirt(0, fetchPC, sizeof(MachInst), 0, threadPC); - - Fault fault = thread->itb->translateAtomic(req, tc); - - return fault; } diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh index 34d0f5954..d2ccc0ff1 100644 --- a/src/cpu/simple/base.hh +++ b/src/cpu/simple/base.hh @@ -125,9 +125,11 @@ class BaseSimpleCPU : public BaseCPU enum Status { Idle, Running, + ITBWaitResponse, IcacheRetry, IcacheWaitResponse, IcacheWaitSwitch, + DTBWaitResponse, DcacheRetry, DcacheWaitResponse, DcacheWaitSwitch, @@ -160,7 +162,7 @@ class BaseSimpleCPU : public BaseCPU bool stayAtPC; void checkForInterrupts(); - Fault setupFetchRequest(Request *req); + void setupFetchRequest(Request *req); void preExecute(); void postExecute(); void advancePC(Fault fault); diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index 65222266e..3f5778138 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -104,7 +104,8 @@ TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) } TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) - : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock), fetchEvent(this) + : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this, p->clock), + dcachePort(this, p->clock), fetchEvent(this) { _status = Idle; @@ -262,66 +263,123 @@ TimingSimpleCPU::handleReadPacket(PacketPtr pkt) return dcache_pkt == NULL; } -Fault -TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, - RequestPtr &req, Addr split_addr, uint8_t *data, bool read) +void +TimingSimpleCPU::sendData(Fault fault, RequestPtr req, + uint8_t *data, uint64_t *res, bool read) { - Fault fault; - RequestPtr req1, req2; - assert(!req->isLocked() && !req->isSwap()); - req->splitOnVaddr(split_addr, req1, req2); - - pkt1 = pkt2 = NULL; - if ((fault = buildPacket(pkt1, req1, read)) != NoFault || - (fault = buildPacket(pkt2, req2, read)) != NoFault) { + _status = Running; + if (fault != NoFault) { + delete data; delete req; - delete req1; - delete pkt1; - req = NULL; - pkt1 = NULL; - return fault; + + translationFault(fault); + return; } + PacketPtr pkt; + buildPacket(pkt, req, read); + pkt->dataDynamic(data); + if (req->getFlags().isSet(Request::NO_ACCESS)) { + assert(!dcache_pkt); + pkt->makeResponse(); + completeDataAccess(pkt); + } else if (read) { + handleReadPacket(pkt); + } else { + bool do_access = true; // flag to suppress cache access - assert(!req1->isMmapedIpr() && !req2->isMmapedIpr()); + if (req->isLocked()) { + do_access = TheISA::handleLockedWrite(thread, req); + } else if (req->isCondSwap()) { + assert(res); + req->setExtraData(*res); + } - req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags()); - PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(), - Packet::Broadcast); - if (req->getFlags().isSet(Request::NO_ACCESS)) { + if (do_access) { + dcache_pkt = pkt; + handleWritePacket(); + } else { + _status = DcacheWaitResponse; + completeDataAccess(pkt); + } + } +} + +void +TimingSimpleCPU::sendSplitData(Fault fault1, Fault fault2, + RequestPtr req1, RequestPtr req2, RequestPtr req, + uint8_t *data, bool read) +{ + _status = Running; + if (fault1 != NoFault || fault2 != NoFault) { + delete data; delete req1; - delete pkt1; delete req2; - delete pkt2; - pkt1 = pkt; - pkt2 = NULL; - return NoFault; + if (fault1 != NoFault) + translationFault(fault1); + else if (fault2 != NoFault) + translationFault(fault2); + return; + } + PacketPtr pkt1, pkt2; + buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read); + if (req->getFlags().isSet(Request::NO_ACCESS)) { + assert(!dcache_pkt); + pkt1->makeResponse(); + completeDataAccess(pkt1); + } else if (read) { + if (handleReadPacket(pkt1)) { + SplitFragmentSenderState * send_state = + dynamic_cast(pkt1->senderState); + send_state->clearFromParent(); + if (handleReadPacket(pkt2)) { + send_state = dynamic_cast( + pkt1->senderState); + send_state->clearFromParent(); + } + } + } else { + dcache_pkt = pkt1; + if (handleWritePacket()) { + SplitFragmentSenderState * send_state = + dynamic_cast(pkt1->senderState); + send_state->clearFromParent(); + dcache_pkt = pkt2; + if (handleWritePacket()) { + send_state = dynamic_cast( + pkt1->senderState); + send_state->clearFromParent(); + } + } } +} - pkt->dataDynamic(data); - pkt1->dataStatic(data); - pkt2->dataStatic(data + req1->getSize()); +void +TimingSimpleCPU::translationFault(Fault fault) +{ + numCycles += tickToCycles(curTick - previousTick); + previousTick = curTick; - SplitMainSenderState * main_send_state = new SplitMainSenderState; - pkt->senderState = main_send_state; - main_send_state->fragments[0] = pkt1; - main_send_state->fragments[1] = pkt2; - main_send_state->outstanding = 2; - pkt1->senderState = new SplitFragmentSenderState(pkt, 0); - pkt2->senderState = new SplitFragmentSenderState(pkt, 1); - return fault; + if (traceData) { + // Since there was a fault, we shouldn't trace this instruction. + delete traceData; + traceData = NULL; + } + + postExecute(); + + if (getState() == SimObject::Draining) { + advancePC(fault); + completeDrain(); + } else { + advanceInst(fault); + } } -Fault -TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr &req, bool read) +void +TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr req, bool read) { - Fault fault = thread->dtb->translateAtomic(req, tc, !read); MemCmd cmd; - if (fault != NoFault) { - delete req; - req = NULL; - pkt = NULL; - return fault; - } else if (read) { + if (read) { cmd = MemCmd::ReadReq; if (req->isLocked()) cmd = MemCmd::LoadLockedReq; @@ -334,7 +392,40 @@ TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr &req, bool read) } } pkt = new Packet(req, cmd, Packet::Broadcast); - return NoFault; +} + +void +TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, + RequestPtr req1, RequestPtr req2, RequestPtr req, + uint8_t *data, bool read) +{ + pkt1 = pkt2 = NULL; + + assert(!req1->isMmapedIpr() && !req2->isMmapedIpr()); + + if (req->getFlags().isSet(Request::NO_ACCESS)) { + buildPacket(pkt1, req, read); + return; + } + + buildPacket(pkt1, req1, read); + buildPacket(pkt2, req2, read); + + req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags()); + PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(), + Packet::Broadcast); + + pkt->dataDynamic(data); + pkt1->dataStatic(data); + pkt2->dataStatic(data + req1->getSize()); + + SplitMainSenderState * main_send_state = new SplitMainSenderState; + pkt->senderState = main_send_state; + main_send_state->fragments[0] = pkt1; + main_send_state->fragments[1] = pkt2; + main_send_state->outstanding = 2; + pkt1->senderState = new SplitFragmentSenderState(pkt, 0); + pkt2->senderState = new SplitFragmentSenderState(pkt, 1); } template @@ -348,42 +439,30 @@ TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) int block_size = dcachePort.peerBlockSize(); int data_size = sizeof(T); - PacketPtr pkt; RequestPtr req = new Request(asid, addr, data_size, flags, pc, _cpuId, thread_id); Addr split_addr = roundDown(addr + data_size - 1, block_size); assert(split_addr <= addr || split_addr - addr < block_size); + + _status = DTBWaitResponse; if (split_addr > addr) { - PacketPtr pkt1, pkt2; - Fault fault = this->buildSplitPacket(pkt1, pkt2, req, - split_addr, (uint8_t *)(new T), true); - if (fault != NoFault) - return fault; - if (req->getFlags().isSet(Request::NO_ACCESS)) { - dcache_pkt = pkt1; - } else if (handleReadPacket(pkt1)) { - SplitFragmentSenderState * send_state = - dynamic_cast(pkt1->senderState); - send_state->clearFromParent(); - if (handleReadPacket(pkt2)) { - send_state = - dynamic_cast(pkt1->senderState); - send_state->clearFromParent(); - } - } + RequestPtr req1, req2; + assert(!req->isLocked() && !req->isSwap()); + req->splitOnVaddr(split_addr, req1, req2); + + typedef SplitDataTranslation::WholeTranslationState WholeState; + WholeState *state = new WholeState(req1, req2, req, + (uint8_t *)(new T), true); + thread->dtb->translateTiming(req1, tc, + new SplitDataTranslation(this, 0, state), false); + thread->dtb->translateTiming(req2, tc, + new SplitDataTranslation(this, 1, state), false); } else { - Fault fault = buildPacket(pkt, req, true); - if (fault != NoFault) { - return fault; - } - if (req->getFlags().isSet(Request::NO_ACCESS)) { - dcache_pkt = pkt; - } else { - pkt->dataDynamic(new T); - handleReadPacket(pkt); - } + thread->dtb->translateTiming(req, tc, + new DataTranslation(this, (uint8_t *)(new T), NULL, true), + false); } if (traceData) { @@ -484,54 +563,25 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) Addr split_addr = roundDown(addr + data_size - 1, block_size); assert(split_addr <= addr || split_addr - addr < block_size); + T *dataP = new T; + *dataP = TheISA::gtoh(data); + _status = DTBWaitResponse; if (split_addr > addr) { - PacketPtr pkt1, pkt2; - T *dataP = new T; - *dataP = data; - Fault fault = this->buildSplitPacket(pkt1, pkt2, req, split_addr, - (uint8_t *)dataP, false); - if (fault != NoFault) - return fault; - dcache_pkt = pkt1; - if (!req->getFlags().isSet(Request::NO_ACCESS)) { - if (handleWritePacket()) { - SplitFragmentSenderState * send_state = - dynamic_cast( - pkt1->senderState); - send_state->clearFromParent(); - dcache_pkt = pkt2; - if (handleReadPacket(pkt2)) { - send_state = - dynamic_cast( - pkt1->senderState); - send_state->clearFromParent(); - } - } - } + RequestPtr req1, req2; + assert(!req->isLocked() && !req->isSwap()); + req->splitOnVaddr(split_addr, req1, req2); + + typedef SplitDataTranslation::WholeTranslationState WholeState; + WholeState *state = new WholeState(req1, req2, req, + (uint8_t *)dataP, false); + thread->dtb->translateTiming(req1, tc, + new SplitDataTranslation(this, 0, state), true); + thread->dtb->translateTiming(req2, tc, + new SplitDataTranslation(this, 1, state), true); } else { - bool do_access = true; // flag to suppress cache access - - Fault fault = buildPacket(dcache_pkt, req, false); - if (fault != NoFault) - return fault; - - if (!req->getFlags().isSet(Request::NO_ACCESS)) { - if (req->isLocked()) { - do_access = TheISA::handleLockedWrite(thread, req); - } else if (req->isCondSwap()) { - assert(res); - req->setExtraData(*res); - } - - dcache_pkt->allocate(); - if (req->isMmapedIpr()) - dcache_pkt->set(htog(data)); - else - dcache_pkt->set(data); - - if (do_access) - handleWritePacket(); - } + thread->dtb->translateTiming(req, tc, + new DataTranslation(this, (uint8_t *)dataP, res, false), + true); } if (traceData) { @@ -620,30 +670,39 @@ TimingSimpleCPU::fetch() if (!fromRom) { Request *ifetch_req = new Request(); ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0); - Fault fault = setupFetchRequest(ifetch_req); + setupFetchRequest(ifetch_req); + thread->itb->translateTiming(ifetch_req, tc, + &fetchTranslation); + } else { + _status = IcacheWaitResponse; + completeIfetch(NULL); - ifetch_pkt = new Packet(ifetch_req, MemCmd::ReadReq, Packet::Broadcast); + numCycles += tickToCycles(curTick - previousTick); + previousTick = curTick; + } +} + + +void +TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc) +{ + if (fault == NoFault) { + ifetch_pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast); ifetch_pkt->dataStatic(&inst); - if (fault == NoFault) { - if (!icachePort.sendTiming(ifetch_pkt)) { - // Need to wait for retry - _status = IcacheRetry; - } else { - // Need to wait for cache to respond - _status = IcacheWaitResponse; - // ownership of packet transferred to memory system - ifetch_pkt = NULL; - } + if (!icachePort.sendTiming(ifetch_pkt)) { + // Need to wait for retry + _status = IcacheRetry; } else { - delete ifetch_req; - delete ifetch_pkt; - // fetch fault: advance directly to next instruction (fault handler) - advanceInst(fault); + // Need to wait for cache to respond + _status = IcacheWaitResponse; + // ownership of packet transferred to memory system + ifetch_pkt = NULL; } } else { - _status = IcacheWaitResponse; - completeIfetch(NULL); + delete req; + // fetch fault: advance directly to next instruction (fault handler) + advanceInst(fault); } numCycles += tickToCycles(curTick - previousTick); @@ -699,28 +758,11 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt) Fault fault = curStaticInst->initiateAcc(this, traceData); if (_status != Running) { // instruction will complete in dcache response callback - assert(_status == DcacheWaitResponse || _status == DcacheRetry); + assert(_status == DcacheWaitResponse || + _status == DcacheRetry || DTBWaitResponse); assert(fault == NoFault); } else { - if (fault == NoFault) { - // Note that ARM can have NULL packets if the instruction gets - // squashed due to predication - // early fail on store conditional: complete now - assert(dcache_pkt != NULL || THE_ISA == ARM_ISA); - - fault = curStaticInst->completeAcc(dcache_pkt, this, - traceData); - if (dcache_pkt != NULL) - { - delete dcache_pkt->req; - delete dcache_pkt; - dcache_pkt = NULL; - } - - // keep an instruction count - if (fault == NoFault) - countInst(); - } else if (traceData) { + if (fault != NoFault && traceData) { // If there was a fault, we shouldn't trace this instruction. delete traceData; traceData = NULL; @@ -843,7 +885,7 @@ TimingSimpleCPU::completeDataAccess(PacketPtr pkt) } } - assert(_status == DcacheWaitResponse); + assert(_status == DcacheWaitResponse || _status == DTBWaitResponse); _status = Running; Fault fault = curStaticInst->completeAcc(pkt, this, traceData); diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh index 0a639a627..a02ec48c9 100644 --- a/src/cpu/simple/timing.hh +++ b/src/cpu/simple/timing.hh @@ -96,9 +96,114 @@ class TimingSimpleCPU : public BaseSimpleCPU } }; - Fault buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, RequestPtr &req, - Addr split_addr, uint8_t *data, bool read); - Fault buildPacket(PacketPtr &pkt, RequestPtr &req, bool read); + class FetchTranslation : public BaseTLB::Translation + { + protected: + TimingSimpleCPU *cpu; + + public: + FetchTranslation(TimingSimpleCPU *_cpu) : cpu(_cpu) + {} + + void finish(Fault fault, RequestPtr req, + ThreadContext *tc, bool write) + { + cpu->sendFetch(fault, req, tc); + } + }; + FetchTranslation fetchTranslation; + + class DataTranslation : public BaseTLB::Translation + { + protected: + TimingSimpleCPU *cpu; + uint8_t *data; + uint64_t *res; + bool read; + + public: + DataTranslation(TimingSimpleCPU *_cpu, + uint8_t *_data, uint64_t *_res, bool _read) : + cpu(_cpu), data(_data), res(_res), read(_read) + {} + + void + finish(Fault fault, RequestPtr req, + ThreadContext *tc, bool write) + { + cpu->sendData(fault, req, data, res, read); + delete this; + } + }; + + class SplitDataTranslation : public BaseTLB::Translation + { + public: + struct WholeTranslationState + { + public: + int outstanding; + RequestPtr requests[2]; + RequestPtr mainReq; + Fault faults[2]; + uint8_t *data; + bool read; + + WholeTranslationState(RequestPtr req1, RequestPtr req2, + RequestPtr main, uint8_t *_data, bool _read) + { + outstanding = 2; + requests[0] = req1; + requests[1] = req2; + mainReq = main; + faults[0] = faults[1] = NoFault; + data = _data; + read = _read; + } + }; + + TimingSimpleCPU *cpu; + int index; + WholeTranslationState *state; + + SplitDataTranslation(TimingSimpleCPU *_cpu, int _index, + WholeTranslationState *_state) : + cpu(_cpu), index(_index), state(_state) + {} + + void + finish(Fault fault, RequestPtr req, + ThreadContext *tc, bool write) + { + assert(state); + assert(state->outstanding); + state->faults[index] = fault; + if (--state->outstanding == 0) { + cpu->sendSplitData(state->faults[0], + state->faults[1], + state->requests[0], + state->requests[1], + state->mainReq, + state->data, + state->read); + delete state; + } + delete this; + } + }; + + void sendData(Fault fault, RequestPtr req, + uint8_t *data, uint64_t *res, bool read); + void sendSplitData(Fault fault1, Fault fault2, + RequestPtr req1, RequestPtr req2, RequestPtr req, + uint8_t *data, bool read); + + void translationFault(Fault fault); + + void buildPacket(PacketPtr &pkt, RequestPtr req, bool read); + void buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, + RequestPtr req1, RequestPtr req2, RequestPtr req, + uint8_t *data, bool read); bool handleReadPacket(PacketPtr pkt); // This function always implicitly uses dcache_pkt. @@ -228,8 +333,9 @@ class TimingSimpleCPU : public BaseSimpleCPU Fault write(T data, Addr addr, unsigned flags, uint64_t *res); void fetch(); + void sendFetch(Fault fault, RequestPtr req, ThreadContext *tc); void completeIfetch(PacketPtr ); - void completeDataAccess(PacketPtr ); + void completeDataAccess(PacketPtr pkt); void advanceInst(Fault fault); /** diff --git a/src/sim/tlb.cc b/src/sim/tlb.cc index f7b57cbbc..e82e4f277 100644 --- a/src/sim/tlb.cc +++ b/src/sim/tlb.cc @@ -49,6 +49,14 @@ GenericTLB::translateAtomic(RequestPtr req, ThreadContext * tc, bool) #endif } +void +GenericTLB::translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool write) +{ + assert(translation); + translation->finish(translateAtomic(req, tc, write), req, tc, write); +} + void GenericTLB::demapPage(Addr vaddr, uint64_t asn) { diff --git a/src/sim/tlb.hh b/src/sim/tlb.hh index 8429c0df5..8893f8c97 100644 --- a/src/sim/tlb.hh +++ b/src/sim/tlb.hh @@ -47,6 +47,21 @@ class BaseTLB : public SimObject public: virtual void demapPage(Addr vaddr, uint64_t asn) = 0; + + class Translation + { + public: + virtual ~Translation() + {} + + /* + * The memory for this object may be dynamically allocated, and it may + * be responsible for cleaning itself up which will happen in this + * function. Once it's called, the object is no longer valid. + */ + virtual void finish(Fault fault, RequestPtr req, + ThreadContext *tc, bool write=false) = 0; + }; }; class GenericTLB : public BaseTLB @@ -59,6 +74,8 @@ class GenericTLB : public BaseTLB void demapPage(Addr vaddr, uint64_t asn); Fault translateAtomic(RequestPtr req, ThreadContext *tc, bool=false); + void translateTiming(RequestPtr req, ThreadContext *tc, + Translation *translation, bool=false); }; #endif // __ARCH_SPARC_TLB_HH__