/*
* 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
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Kevin Lim
+ * Timothy M. Jones
*/
#ifndef __CPU_BASE_DYN_INST_HH__
#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"
* @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);
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;
// Commit will have to clean up whatever happened. Set this
// instruction as executed.
this->setExecuted();
- delete req;
}
if (traceData) {
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__
/** Executes a syscall specified by the callnum. */
void syscall(int64_t callnum);
#endif
+
+ /** Finish a DTB address translation. */
+ void finishTranslation(WholeTranslationState *state);
};
}
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);
}
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)) {
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);
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) {
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);
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) {
}
+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()
{
#define __CPU_SIMPLE_TIMING_HH__
#include "cpu/simple/base.hh"
+#include "cpu/translation.hh"
#include "params/TimingSimpleCPU.hh"
};
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);
*/
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;
--- /dev/null
+/*
+ * 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__