From 6ed47e94644f854baa33d1e9f367cc9eebd99abf Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Wed, 25 Feb 2009 10:16:15 -0800 Subject: CPU: Implement translateTiming which defers to translateAtomic, and convert the timing simple CPU to use it. --- src/cpu/simple/atomic.cc | 6 +- src/cpu/simple/base.cc | 6 +- src/cpu/simple/base.hh | 4 +- src/cpu/simple/timing.cc | 364 ++++++++++++++++++++++++++--------------------- src/cpu/simple/timing.hh | 114 ++++++++++++++- 5 files changed, 321 insertions(+), 173 deletions(-) (limited to 'src/cpu/simple') 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); /** -- cgit v1.2.3