/*
* 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 "base/fast_alloc.hh"
#include "base/trace.hh"
#include "config/full_system.hh"
+#include "config/the_isa.hh"
#include "cpu/o3/comm.hh"
#include "cpu/exetrace.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"
/**
* @file
template <class T>
Fault read(Addr addr, T &data, unsigned flags);
+ Fault readBytes(Addr addr, uint8_t *data, unsigned size, unsigned flags);
+
/**
* Does a write to a given address.
* @param data The data to be written.
* @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);
+
+ Fault writeBytes(uint8_t *data, unsigned size,
+ Addr addr, unsigned flags, uint64_t *res);
+
+ /** Splits a request in two if it crosses a dcache block. */
+ void splitRequest(RequestPtr req, RequestPtr &sreqLow,
+ RequestPtr &sreqHigh);
+
+ /** Initiate a DTB address translation. */
+ void initiateTranslation(RequestPtr req, RequestPtr sreqLow,
+ RequestPtr sreqHigh, 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);
std::bitset<NumStatus> status;
/** The thread this instruction is from. */
- short threadNumber;
+ ThreadID threadNumber;
/** data address space ID, for loads & stores. */
short asid;
void setASID(short addr_space_id) { asid = addr_space_id; }
/** Sets the thread id. */
- void setTid(unsigned tid) { threadNumber = tid; }
+ void setTid(ThreadID tid) { threadNumber = tid; }
/** Sets the pointer to the thread state. */
void setThreadState(ImplState *state) { thread = state; }
};
template<class Impl>
-template<class T>
-inline Fault
-BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags)
+Fault
+BaseDynInst<Impl>::readBytes(Addr addr, uint8_t *data,
+ unsigned size, unsigned flags)
{
reqMade = true;
- Request *req = new Request();
- req->setVirt(asid, addr, sizeof(T), flags, this->PC);
- req->setThreadContext(thread->contextId(), threadNumber);
+ Request *req = new Request(asid, addr, size, flags, this->PC,
+ thread->contextId(), threadNumber);
- fault = cpu->dtb->translate(req, thread->getTC(), false);
+ Request *sreqLow = NULL;
+ Request *sreqHigh = NULL;
- if (req->isUncacheable())
- isUncacheable = true;
+ // Only split the request if the ISA supports unaligned accesses.
+ if (TheISA::HasUnalignedMemAcc) {
+ splitRequest(req, sreqLow, sreqHigh);
+ }
+ initiateTranslation(req, sreqLow, sreqHigh, 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
+ fault = cpu->read(req, sreqLow, sreqHigh, 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) {
traceData->setAddr(addr);
- traceData->setData(data);
}
return fault;
template<class Impl>
template<class T>
inline Fault
-BaseDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res)
+BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags)
{
+ Fault fault = readBytes(addr, (uint8_t *)&data, sizeof(T), flags);
+
+ if (fault != NoFault) {
+ // Return a fixed value to keep simulation deterministic even
+ // along misspeculated paths.
+ data = (T)-1;
+ }
+ data = TheISA::gtoh(data);
+
if (traceData) {
- traceData->setAddr(addr);
traceData->setData(data);
}
+ return fault;
+}
+
+template<class Impl>
+Fault
+BaseDynInst<Impl>::writeBytes(uint8_t *data, unsigned size,
+ Addr addr, unsigned flags, uint64_t *res)
+{
+ if (traceData) {
+ traceData->setAddr(addr);
+ }
+
reqMade = true;
- Request *req = new Request();
- req->setVirt(asid, addr, sizeof(T), flags, this->PC);
- req->setThreadContext(thread->contextId(), threadNumber);
+ Request *req = new Request(asid, addr, size, flags, this->PC,
+ thread->contextId(), threadNumber);
- fault = cpu->dtb->translate(req, thread->getTC(), true);
+ Request *sreqLow = NULL;
+ Request *sreqHigh = NULL;
- if (req->isUncacheable())
- isUncacheable = true;
+ // Only split the request if the ISA supports unaligned accesses.
+ if (TheISA::HasUnalignedMemAcc) {
+ splitRequest(req, sreqLow, sreqHigh);
+ }
+ initiateTranslation(req, sreqLow, sreqHigh, res, BaseTLB::Write);
if (fault == NoFault) {
effAddr = req->getVaddr();
effAddrValid = true;
- physEffAddr = req->getPaddr();
- memReqFlags = req->getFlags();
+ fault = cpu->write(req, sreqLow, sreqHigh, 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);
- }
-#else
- fault = cpu->write(req, data, sqIdx);
-#endif
+ return fault;
+}
+
+template<class Impl>
+template<class T>
+inline Fault
+BaseDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res)
+{
+ if (traceData) {
+ traceData->setData(data);
+ }
+ data = TheISA::htog(data);
+ return writeBytes((uint8_t *)&data, sizeof(T), addr, flags, res);
+}
+
+template<class Impl>
+inline void
+BaseDynInst<Impl>::splitRequest(RequestPtr req, RequestPtr &sreqLow,
+ RequestPtr &sreqHigh)
+{
+ // Check to see if the request crosses the next level block boundary.
+ unsigned block_size = cpu->getDcachePort()->peerBlockSize();
+ Addr addr = req->getVaddr();
+ Addr split_addr = roundDown(addr + req->getSize() - 1, block_size);
+ assert(split_addr <= addr || split_addr - addr < block_size);
+
+ // Spans two blocks.
+ if (split_addr > addr) {
+ req->splitOnVaddr(split_addr, sreqLow, sreqHigh);
+ }
+}
+
+template<class Impl>
+inline void
+BaseDynInst<Impl>::initiateTranslation(RequestPtr req, RequestPtr sreqLow,
+ RequestPtr sreqHigh, uint64_t *res,
+ BaseTLB::Mode mode)
+{
+ if (!TheISA::HasUnalignedMemAcc || sreqLow == NULL) {
+ WholeTranslationState *state =
+ new WholeTranslationState(req, NULL, res, mode);
+
+ // One translation if the request isn't split.
+ DataTranslation<BaseDynInst<Impl> > *trans =
+ new DataTranslation<BaseDynInst<Impl> >(this, state);
+ cpu->dtb->translateTiming(req, thread->getTC(), trans, mode);
} else {
- delete req;
+ WholeTranslationState *state =
+ new WholeTranslationState(req, sreqLow, sreqHigh, NULL, res, mode);
+
+ // Two translations when the request is split.
+ DataTranslation<BaseDynInst<Impl> > *stransLow =
+ new DataTranslation<BaseDynInst<Impl> >(this, state, 0);
+ DataTranslation<BaseDynInst<Impl> > *stransHigh =
+ new DataTranslation<BaseDynInst<Impl> >(this, state, 1);
+
+ cpu->dtb->translateTiming(sreqLow, thread->getTC(), stransLow, mode);
+ cpu->dtb->translateTiming(sreqHigh, thread->getTC(), stransHigh, mode);
}
+}
- return fault;
+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 {
+ state->deleteReqs();
+ }
+ delete state;
}
#endif // __CPU_BASE_DYN_INST_HH__