diff options
Diffstat (limited to 'src/cpu')
-rw-r--r-- | src/cpu/base_dyn_inst.hh | 93 | ||||
-rw-r--r-- | src/cpu/exec_context.hh | 3 | ||||
-rw-r--r-- | src/cpu/simple/timing.cc | 113 | ||||
-rw-r--r-- | src/cpu/simple/timing.hh | 99 | ||||
-rw-r--r-- | src/cpu/translation.hh | 179 |
5 files changed, 305 insertions, 182 deletions
diff --git a/src/cpu/base_dyn_inst.hh b/src/cpu/base_dyn_inst.hh index 31206c81e..7732b71f8 100644 --- a/src/cpu/base_dyn_inst.hh +++ b/src/cpu/base_dyn_inst.hh @@ -1,5 +1,6 @@ /* * Copyright (c) 2004-2006 The Regents of The University of Michigan + * Copyright (c) 2009 The University of Edinburgh * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,6 +27,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Kevin Lim + * Timothy M. Jones */ #ifndef __CPU_BASE_DYN_INST_HH__ @@ -45,6 +47,7 @@ #include "cpu/inst_seq.hh" #include "cpu/op_class.hh" #include "cpu/static_inst.hh" +#include "cpu/translation.hh" #include "mem/packet.hh" #include "sim/system.hh" #include "sim/tlb.hh" @@ -126,8 +129,14 @@ class BaseDynInst : public FastAlloc, public RefCounted * @return Returns any fault due to the write. */ template <class T> - Fault write(T data, Addr addr, unsigned flags, - uint64_t *res); + Fault write(T data, Addr addr, unsigned flags, uint64_t *res); + + /** Initiate a DTB address translation. */ + void initiateTranslation(RequestPtr req, uint64_t *res, + BaseTLB::Mode mode); + + /** Finish a DTB address translation. */ + void finishTranslation(WholeTranslationState *state); void prefetch(Addr addr, unsigned flags); void writeHint(Addr addr, int size, unsigned flags); @@ -861,29 +870,14 @@ BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags) Request *req = new Request(asid, addr, sizeof(T), flags, this->PC, thread->contextId(), threadNumber); - fault = cpu->dtb->translateAtomic(req, thread->getTC(), BaseTLB::Read); - - if (req->isUncacheable()) - isUncacheable = true; + initiateTranslation(req, NULL, BaseTLB::Read); if (fault == NoFault) { effAddr = req->getVaddr(); effAddrValid = true; - physEffAddr = req->getPaddr(); - memReqFlags = req->getFlags(); - -#if 0 - if (cpu->system->memctrl->badaddr(physEffAddr)) { - fault = TheISA::genMachineCheckFault(); - data = (T)-1; - this->setExecuted(); - } else { - fault = cpu->read(req, data, lqIdx); - } -#else - fault = cpu->read(req, data, lqIdx); -#endif + cpu->read(req, data, lqIdx); } else { + // Return a fixed value to keep simulation deterministic even // along misspeculated paths. data = (T)-1; @@ -891,7 +885,6 @@ BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags) // Commit will have to clean up whatever happened. Set this // instruction as executed. this->setExecuted(); - delete req; } if (traceData) { @@ -916,35 +909,51 @@ BaseDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res) Request *req = new Request(asid, addr, sizeof(T), flags, this->PC, thread->contextId(), threadNumber); - fault = cpu->dtb->translateAtomic(req, thread->getTC(), BaseTLB::Write); - - if (req->isUncacheable()) - isUncacheable = true; + initiateTranslation(req, res, BaseTLB::Write); if (fault == NoFault) { effAddr = req->getVaddr(); effAddrValid = true; - physEffAddr = req->getPaddr(); - memReqFlags = req->getFlags(); + cpu->write(req, data, sqIdx); + } - if (req->isCondSwap()) { - assert(res); - req->setExtraData(*res); - } -#if 0 - if (cpu->system->memctrl->badaddr(physEffAddr)) { - fault = TheISA::genMachineCheckFault(); - } else { - fault = cpu->write(req, data, sqIdx); + return fault; +} + +template<class Impl> +inline void +BaseDynInst<Impl>::initiateTranslation(RequestPtr req, uint64_t *res, + BaseTLB::Mode mode) +{ + WholeTranslationState *state = + new WholeTranslationState(req, NULL, res, mode); + DataTranslation<BaseDynInst<Impl> > *trans = + new DataTranslation<BaseDynInst<Impl> >(this, state); + cpu->dtb->translateTiming(req, thread->getTC(), trans, mode); +} + +template<class Impl> +inline void +BaseDynInst<Impl>::finishTranslation(WholeTranslationState *state) +{ + fault = state->getFault(); + + if (state->isUncacheable()) + isUncacheable = true; + + if (fault == NoFault) { + physEffAddr = state->getPaddr(); + memReqFlags = state->getFlags(); + + if (state->mainReq->isCondSwap()) { + assert(state->res); + state->mainReq->setExtraData(*state->res); } -#else - fault = cpu->write(req, data, sqIdx); -#endif + } else { - delete req; + state->deleteReqs(); } - - return fault; + delete state; } #endif // __CPU_BASE_DYN_INST_HH__ diff --git a/src/cpu/exec_context.hh b/src/cpu/exec_context.hh index 3d07e95f3..c930b5cce 100644 --- a/src/cpu/exec_context.hh +++ b/src/cpu/exec_context.hh @@ -140,4 +140,7 @@ class ExecContext { /** Executes a syscall specified by the callnum. */ void syscall(int64_t callnum); #endif + + /** Finish a DTB address translation. */ + void finishTranslation(WholeTranslationState *state); }; diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index 6b22d2fcf..db972d030 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -268,19 +268,9 @@ TimingSimpleCPU::handleReadPacket(PacketPtr pkt) } void -TimingSimpleCPU::sendData(Fault fault, RequestPtr req, - uint8_t *data, uint64_t *res, bool read) +TimingSimpleCPU::sendData(RequestPtr req, uint8_t *data, uint64_t *res, + bool read) { - _status = Running; - if (fault != NoFault) { - if (req->isPrefetch()) - fault = NoFault; - delete data; - delete req; - - translationFault(fault); - return; - } PacketPtr pkt; buildPacket(pkt, req, read); pkt->dataDynamic<uint8_t>(data); @@ -311,25 +301,9 @@ TimingSimpleCPU::sendData(Fault fault, RequestPtr req, } void -TimingSimpleCPU::sendSplitData(Fault fault1, Fault fault2, - RequestPtr req1, RequestPtr req2, RequestPtr req, - uint8_t *data, bool read) +TimingSimpleCPU::sendSplitData(RequestPtr req1, RequestPtr req2, + RequestPtr req, uint8_t *data, bool read) { - _status = Running; - if (fault1 != NoFault || fault2 != NoFault) { - if (req1->isPrefetch()) - fault1 = NoFault; - if (req2->isPrefetch()) - fault2 = NoFault; - delete data; - delete req1; - delete req2; - 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)) { @@ -450,6 +424,7 @@ TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) const Addr pc = thread->readPC(); unsigned block_size = dcachePort.peerBlockSize(); int data_size = sizeof(T); + BaseTLB::Mode mode = BaseTLB::Read; RequestPtr req = new Request(asid, addr, data_size, flags, pc, _cpuId, tid); @@ -457,24 +432,28 @@ TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 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) { RequestPtr req1, req2; assert(!req->isLLSC() && !req->isSwap()); req->splitOnVaddr(split_addr, req1, req2); - typedef SplitDataTranslation::WholeTranslationState WholeState; - WholeState *state = new WholeState(req1, req2, req, - (uint8_t *)(new T), BaseTLB::Read); - thread->dtb->translateTiming(req1, tc, - new SplitDataTranslation(this, 0, state), BaseTLB::Read); - thread->dtb->translateTiming(req2, tc, - new SplitDataTranslation(this, 1, state), BaseTLB::Read); + WholeTranslationState *state = + new WholeTranslationState(req, req1, req2, (uint8_t *)(new T), + NULL, mode); + DataTranslation<TimingSimpleCPU> *trans1 = + new DataTranslation<TimingSimpleCPU>(this, state, 0); + DataTranslation<TimingSimpleCPU> *trans2 = + new DataTranslation<TimingSimpleCPU>(this, state, 1); + + thread->dtb->translateTiming(req1, tc, trans1, mode); + thread->dtb->translateTiming(req2, tc, trans2, mode); } else { - DataTranslation *translation = - new DataTranslation(this, (uint8_t *)(new T), NULL, BaseTLB::Read); - thread->dtb->translateTiming(req, tc, translation, BaseTLB::Read); + WholeTranslationState *state = + new WholeTranslationState(req, (uint8_t *)(new T), NULL, mode); + DataTranslation<TimingSimpleCPU> *translation + = new DataTranslation<TimingSimpleCPU>(this, state); + thread->dtb->translateTiming(req, tc, translation, mode); } if (traceData) { @@ -568,6 +547,7 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) const Addr pc = thread->readPC(); unsigned block_size = dcachePort.peerBlockSize(); int data_size = sizeof(T); + BaseTLB::Mode mode = BaseTLB::Write; RequestPtr req = new Request(asid, addr, data_size, flags, pc, _cpuId, tid); @@ -583,17 +563,22 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) assert(!req->isLLSC() && !req->isSwap()); req->splitOnVaddr(split_addr, req1, req2); - typedef SplitDataTranslation::WholeTranslationState WholeState; - WholeState *state = new WholeState(req1, req2, req, - (uint8_t *)dataP, BaseTLB::Write); - thread->dtb->translateTiming(req1, tc, - new SplitDataTranslation(this, 0, state), BaseTLB::Write); - thread->dtb->translateTiming(req2, tc, - new SplitDataTranslation(this, 1, state), BaseTLB::Write); + WholeTranslationState *state = + new WholeTranslationState(req, req1, req2, (uint8_t *)dataP, + res, mode); + DataTranslation<TimingSimpleCPU> *trans1 = + new DataTranslation<TimingSimpleCPU>(this, state, 0); + DataTranslation<TimingSimpleCPU> *trans2 = + new DataTranslation<TimingSimpleCPU>(this, state, 1); + + thread->dtb->translateTiming(req1, tc, trans1, mode); + thread->dtb->translateTiming(req2, tc, trans2, mode); } else { - DataTranslation *translation = - new DataTranslation(this, (uint8_t *)dataP, res, BaseTLB::Write); - thread->dtb->translateTiming(req, tc, translation, BaseTLB::Write); + WholeTranslationState *state = + new WholeTranslationState(req, (uint8_t *)dataP, res, mode); + DataTranslation<TimingSimpleCPU> *translation = + new DataTranslation<TimingSimpleCPU>(this, state); + thread->dtb->translateTiming(req, tc, translation, mode); } if (traceData) { @@ -668,6 +653,32 @@ TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) void +TimingSimpleCPU::finishTranslation(WholeTranslationState *state) +{ + _status = Running; + + if (state->getFault() != NoFault) { + if (state->isPrefetch()) { + state->setNoFault(); + } + delete state->data; + state->deleteReqs(); + translationFault(state->getFault()); + } else { + if (!state->isSplit) { + sendData(state->mainReq, state->data, state->res, + state->mode == BaseTLB::Read); + } else { + sendSplitData(state->sreqLow, state->sreqHigh, state->mainReq, + state->data, state->mode == BaseTLB::Read); + } + } + + delete state; +} + + +void TimingSimpleCPU::fetch() { DPRINTF(SimpleCPU, "Fetch\n"); diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh index 6f6b02bb7..62c105418 100644 --- a/src/cpu/simple/timing.hh +++ b/src/cpu/simple/timing.hh @@ -32,6 +32,7 @@ #define __CPU_SIMPLE_TIMING_HH__ #include "cpu/simple/base.hh" +#include "cpu/translation.hh" #include "params/TimingSimpleCPU.hh" @@ -115,95 +116,9 @@ class TimingSimpleCPU : public BaseSimpleCPU }; FetchTranslation fetchTranslation; - class DataTranslation : public BaseTLB::Translation - { - protected: - TimingSimpleCPU *cpu; - uint8_t *data; - uint64_t *res; - BaseTLB::Mode mode; - - public: - DataTranslation(TimingSimpleCPU *_cpu, - uint8_t *_data, uint64_t *_res, BaseTLB::Mode _mode) - : cpu(_cpu), data(_data), res(_res), mode(_mode) - { - assert(mode == BaseTLB::Read || mode == BaseTLB::Write); - } - - void - finish(Fault fault, RequestPtr req, ThreadContext *tc, - BaseTLB::Mode mode) - { - assert(mode == this->mode); - cpu->sendData(fault, req, data, res, mode == BaseTLB::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; - BaseTLB::Mode mode; - - WholeTranslationState(RequestPtr req1, RequestPtr req2, - RequestPtr main, uint8_t *data, BaseTLB::Mode mode) - { - assert(mode == BaseTLB::Read || mode == BaseTLB::Write); - - outstanding = 2; - requests[0] = req1; - requests[1] = req2; - mainReq = main; - faults[0] = faults[1] = NoFault; - this->data = data; - this->mode = mode; - } - }; - - 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, - BaseTLB::Mode mode) - { - 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->mode == BaseTLB::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 sendData(RequestPtr req, uint8_t *data, uint64_t *res, bool read); + void sendSplitData(RequestPtr req1, RequestPtr req2, RequestPtr req, + uint8_t *data, bool read); void translationFault(Fault fault); @@ -351,6 +266,12 @@ class TimingSimpleCPU : public BaseSimpleCPU */ void printAddr(Addr a); + /** + * Finish a DTB translation. + * @param state The DTB translation state. + */ + void finishTranslation(WholeTranslationState *state); + private: typedef EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch> FetchEvent; diff --git a/src/cpu/translation.hh b/src/cpu/translation.hh new file mode 100644 index 000000000..33e810710 --- /dev/null +++ b/src/cpu/translation.hh @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * Copyright (c) 2009 The University of Edinburgh + * 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: Gabe Black + * Timothy M. Jones + */ + +#ifndef __CPU_TRANSLATION_HH__ +#define __CPU_TRANSLATION_HH__ + +#include "sim/tlb.hh" + +class WholeTranslationState +{ + protected: + int outstanding; + Fault faults[2]; + + public: + bool isSplit; + RequestPtr mainReq; + RequestPtr sreqLow; + RequestPtr sreqHigh; + uint8_t *data; + uint64_t *res; + BaseTLB::Mode mode; + + /** Single translation state. */ + WholeTranslationState(RequestPtr _req, uint8_t *_data, uint64_t *_res, + BaseTLB::Mode _mode) + : outstanding(1), isSplit(false), mainReq(_req), sreqLow(NULL), + sreqHigh(NULL), data(_data), res(_res), mode(_mode) + { + faults[0] = faults[1] = NoFault; + assert(mode == BaseTLB::Read || mode == BaseTLB::Write); + } + + /** Split translation state. */ + WholeTranslationState(RequestPtr _req, RequestPtr _sreqLow, + RequestPtr _sreqHigh, uint8_t *_data, uint64_t *_res, + BaseTLB::Mode _mode) + : outstanding(2), isSplit(true), mainReq(_req), sreqLow(_sreqLow), + sreqHigh(_sreqHigh), data(_data), res(_res), mode(_mode) + { + faults[0] = faults[1] = NoFault; + assert(mode == BaseTLB::Read || mode == BaseTLB::Write); + } + + bool + finish(Fault fault, int index) + { + assert(outstanding); + faults[index] = fault; + outstanding--; + if (isSplit && outstanding == 0) { + + // For ease later, we copy some state to the main request. + if (faults[0] == NoFault) { + mainReq->setPaddr(sreqLow->getPaddr()); + } + mainReq->setFlags(sreqLow->getFlags()); + mainReq->setFlags(sreqHigh->getFlags()); + } + return outstanding == 0; + } + + Fault + getFault() const + { + if (!isSplit) + return faults[0]; + else if (faults[0] != NoFault) + return faults[0]; + else if (faults[1] != NoFault) + return faults[1]; + else + return NoFault; + } + + void + setNoFault() + { + faults[0] = faults[1] = NoFault; + } + + bool + isUncacheable() const + { + return mainReq->isUncacheable(); + } + + bool + isPrefetch() const + { + return mainReq->isPrefetch(); + } + + Addr + getPaddr() const + { + return mainReq->getPaddr(); + } + + unsigned + getFlags() + { + return mainReq->getFlags(); + } + + void + deleteReqs() + { + delete mainReq; + if (isSplit) { + delete sreqLow; + delete sreqHigh; + } + } +}; + +template <class ExecContext> +class DataTranslation : public BaseTLB::Translation +{ + protected: + ExecContext *xc; + WholeTranslationState *state; + int index; + + public: + DataTranslation(ExecContext *_xc, WholeTranslationState* _state) + : xc(_xc), state(_state), index(0) + { + } + + DataTranslation(ExecContext *_xc, WholeTranslationState* _state, + int _index) + : xc(_xc), state(_state), index(_index) + { + } + + void + finish(Fault fault, RequestPtr req, ThreadContext *tc, + BaseTLB::Mode mode) + { + assert(state); + assert(mode == state->mode); + if (state->finish(fault, index)) { + xc->finishTranslation(state); + } + delete this; + } +}; + +#endif // __CPU_TRANSLATION_HH__ |