summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabe Black <gblack@eecs.umich.edu>2010-08-13 06:16:02 -0700
committerGabe Black <gblack@eecs.umich.edu>2010-08-13 06:16:02 -0700
commitaa8c6e9c959eab4d516bc07593bea20ade9ad80c (patch)
tree3e0112e567da5dc1aa019f85458fbd9e37ad0cf2
parent65dbcc6ea170e05ca2370a9a265a61668250fa98 (diff)
downloadgem5-aa8c6e9c959eab4d516bc07593bea20ade9ad80c.tar.xz
CPU: Add readBytes and writeBytes functions to the exec contexts.
-rw-r--r--src/cpu/base_dyn_inst.hh57
-rw-r--r--src/cpu/exec_context.hh5
-rw-r--r--src/cpu/inorder/cpu.cc122
-rw-r--r--src/cpu/inorder/cpu.hh9
-rw-r--r--src/cpu/inorder/inorder_dyn_inst.cc35
-rw-r--r--src/cpu/inorder/inorder_dyn_inst.hh7
-rw-r--r--src/cpu/inorder/resources/cache_unit.cc170
-rw-r--r--src/cpu/inorder/resources/cache_unit.hh9
-rw-r--r--src/cpu/o3/cpu.hh6
-rw-r--r--src/cpu/o3/lsq.hh12
-rw-r--r--src/cpu/o3/lsq_unit.hh27
-rw-r--r--src/cpu/simple/atomic.cc86
-rw-r--r--src/cpu/simple/atomic.hh5
-rw-r--r--src/cpu/simple/timing.cc59
-rw-r--r--src/cpu/simple/timing.hh10
15 files changed, 253 insertions, 366 deletions
diff --git a/src/cpu/base_dyn_inst.hh b/src/cpu/base_dyn_inst.hh
index a9ba12958..3ecec0f0c 100644
--- a/src/cpu/base_dyn_inst.hh
+++ b/src/cpu/base_dyn_inst.hh
@@ -120,6 +120,8 @@ class BaseDynInst : public FastAlloc, public RefCounted
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.
@@ -131,6 +133,9 @@ class BaseDynInst : public FastAlloc, public RefCounted
template <class T>
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);
@@ -867,12 +872,12 @@ class BaseDynInst : public FastAlloc, public RefCounted
};
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(asid, addr, sizeof(T), flags, this->PC,
+ Request *req = new Request(asid, addr, size, flags, this->PC,
thread->contextId(), threadNumber);
Request *sreqLow = NULL;
@@ -889,11 +894,6 @@ BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags)
effAddrValid = true;
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();
@@ -901,7 +901,6 @@ BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags)
if (traceData) {
traceData->setAddr(addr);
- traceData->setData(data);
}
return fault;
@@ -910,15 +909,35 @@ BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags)
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(asid, addr, sizeof(T), flags, this->PC,
+ Request *req = new Request(asid, addr, size, flags, this->PC,
thread->contextId(), threadNumber);
Request *sreqLow = NULL;
@@ -940,6 +959,18 @@ BaseDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res)
}
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)
diff --git a/src/cpu/exec_context.hh b/src/cpu/exec_context.hh
index c930b5cce..22dffea1c 100644
--- a/src/cpu/exec_context.hh
+++ b/src/cpu/exec_context.hh
@@ -111,12 +111,17 @@ class ExecContext {
template <class T>
Fault read(Addr addr, T &data, unsigned flags);
+ Fault readBytes(Addr addr, uint8_t *data, unsigned size, unsigned flags);
+
/** Writes to an address, creating a memory request with the given
* flags. Writes data to memory. For store conditionals, returns
* the result of the store in res. */
template <class T>
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);
+
/** Prefetches an address, creating a memory request with the
* given flags. */
void prefetch(Addr addr, unsigned flags);
diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc
index 75873d97d..059996b07 100644
--- a/src/cpu/inorder/cpu.cc
+++ b/src/cpu/inorder/cpu.cc
@@ -1518,135 +1518,25 @@ InOrderCPU::getDTBPtr()
return dtb_res->tlb();
}
-template <class T>
Fault
-InOrderCPU::read(DynInstPtr inst, Addr addr, T &data, unsigned flags)
+InOrderCPU::read(DynInstPtr inst, Addr addr,
+ uint8_t *data, unsigned size, unsigned flags)
{
//@TODO: Generalize name "CacheUnit" to "MemUnit" just in case
// you want to run w/out caches?
CacheUnit *cache_res =
dynamic_cast<CacheUnit*>(resPool->getResource(dataPortIdx));
- return cache_res->read(inst, addr, data, flags);
+ return cache_res->read(inst, addr, data, size, flags);
}
-#ifndef DOXYGEN_SHOULD_SKIP_THIS
-
-template
-Fault
-InOrderCPU::read(DynInstPtr inst, Addr addr, Twin32_t &data, unsigned flags);
-
-template
-Fault
-InOrderCPU::read(DynInstPtr inst, Addr addr, Twin64_t &data, unsigned flags);
-
-template
-Fault
-InOrderCPU::read(DynInstPtr inst, Addr addr, uint64_t &data, unsigned flags);
-
-template
-Fault
-InOrderCPU::read(DynInstPtr inst, Addr addr, uint32_t &data, unsigned flags);
-
-template
-Fault
-InOrderCPU::read(DynInstPtr inst, Addr addr, uint16_t &data, unsigned flags);
-
-template
-Fault
-InOrderCPU::read(DynInstPtr inst, Addr addr, uint8_t &data, unsigned flags);
-
-#endif //DOXYGEN_SHOULD_SKIP_THIS
-
-template<>
-Fault
-InOrderCPU::read(DynInstPtr inst, Addr addr, double &data, unsigned flags)
-{
- return read(inst, addr, *(uint64_t*)&data, flags);
-}
-
-template<>
-Fault
-InOrderCPU::read(DynInstPtr inst, Addr addr, float &data, unsigned flags)
-{
- return read(inst, addr, *(uint32_t*)&data, flags);
-}
-
-
-template<>
-Fault
-InOrderCPU::read(DynInstPtr inst, Addr addr, int32_t &data, unsigned flags)
-{
- return read(inst, addr, (uint32_t&)data, flags);
-}
-
-template <class T>
Fault
-InOrderCPU::write(DynInstPtr inst, T data, Addr addr, unsigned flags,
- uint64_t *write_res)
+InOrderCPU::write(DynInstPtr inst, uint8_t *data, unsigned size,
+ Addr addr, unsigned flags, uint64_t *write_res)
{
//@TODO: Generalize name "CacheUnit" to "MemUnit" just in case
// you want to run w/out caches?
CacheUnit *cache_res =
dynamic_cast<CacheUnit*>(resPool->getResource(dataPortIdx));
- return cache_res->write(inst, data, addr, flags, write_res);
-}
-
-#ifndef DOXYGEN_SHOULD_SKIP_THIS
-
-template
-Fault
-InOrderCPU::write(DynInstPtr inst, Twin32_t data, Addr addr,
- unsigned flags, uint64_t *res);
-
-template
-Fault
-InOrderCPU::write(DynInstPtr inst, Twin64_t data, Addr addr,
- unsigned flags, uint64_t *res);
-
-template
-Fault
-InOrderCPU::write(DynInstPtr inst, uint64_t data, Addr addr,
- unsigned flags, uint64_t *res);
-
-template
-Fault
-InOrderCPU::write(DynInstPtr inst, uint32_t data, Addr addr,
- unsigned flags, uint64_t *res);
-
-template
-Fault
-InOrderCPU::write(DynInstPtr inst, uint16_t data, Addr addr,
- unsigned flags, uint64_t *res);
-
-template
-Fault
-InOrderCPU::write(DynInstPtr inst, uint8_t data, Addr addr,
- unsigned flags, uint64_t *res);
-
-#endif //DOXYGEN_SHOULD_SKIP_THIS
-
-template<>
-Fault
-InOrderCPU::write(DynInstPtr inst, double data, Addr addr, unsigned flags,
- uint64_t *res)
-{
- return write(inst, *(uint64_t*)&data, addr, flags, res);
-}
-
-template<>
-Fault
-InOrderCPU::write(DynInstPtr inst, float data, Addr addr, unsigned flags,
- uint64_t *res)
-{
- return write(inst, *(uint32_t*)&data, addr, flags, res);
-}
-
-
-template<>
-Fault
-InOrderCPU::write(DynInstPtr inst, int32_t data, Addr addr, unsigned flags,
- uint64_t *res)
-{
- return write(inst, (uint32_t)data, addr, flags, res);
+ return cache_res->write(inst, data, size, addr, flags, write_res);
}
diff --git a/src/cpu/inorder/cpu.hh b/src/cpu/inorder/cpu.hh
index 6676d78cf..450829e64 100644
--- a/src/cpu/inorder/cpu.hh
+++ b/src/cpu/inorder/cpu.hh
@@ -523,15 +523,14 @@ class InOrderCPU : public BaseCPU
/** Forwards an instruction read to the appropriate data
* resource (indexes into Resource Pool thru "dataPortIdx")
*/
- template <class T>
- Fault read(DynInstPtr inst, Addr addr, T &data, unsigned flags);
+ Fault read(DynInstPtr inst, Addr addr,
+ uint8_t *data, unsigned size, unsigned flags);
/** Forwards an instruction write. to the appropriate data
* resource (indexes into Resource Pool thru "dataPortIdx")
*/
- template <class T>
- Fault write(DynInstPtr inst, T data, Addr addr, unsigned flags,
- uint64_t *write_res = NULL);
+ Fault write(DynInstPtr inst, uint8_t *data, unsigned size,
+ Addr addr, unsigned flags, uint64_t *write_res = NULL);
/** Forwards an instruction prefetch to the appropriate data
* resource (indexes into Resource Pool thru "dataPortIdx")
diff --git a/src/cpu/inorder/inorder_dyn_inst.cc b/src/cpu/inorder/inorder_dyn_inst.cc
index 13ec7a3ff..5486dedee 100644
--- a/src/cpu/inorder/inorder_dyn_inst.cc
+++ b/src/cpu/inorder/inorder_dyn_inst.cc
@@ -610,6 +610,13 @@ InOrderDynInst::deallocateContext(int thread_num)
this->cpu->deallocateContext(thread_num);
}
+Fault
+InOrderDynInst::readBytes(Addr addr, uint8_t *data,
+ unsigned size, unsigned flags)
+{
+ return cpu->read(this, addr, data, size, flags);
+}
+
template<class T>
inline Fault
InOrderDynInst::read(Addr addr, T &data, unsigned flags)
@@ -618,8 +625,11 @@ InOrderDynInst::read(Addr addr, T &data, unsigned flags)
traceData->setAddr(addr);
traceData->setData(data);
}
-
- return cpu->read(this, addr, data, flags);
+ Fault fault = readBytes(addr, (uint8_t *)&data, sizeof(T), flags);
+ data = TheISA::gtoh(data);
+ if (traceData)
+ traceData->setData(data);
+ return fault;
}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
@@ -663,20 +673,29 @@ InOrderDynInst::read(Addr addr, int32_t &data, unsigned flags)
return read(addr, (uint32_t&)data, flags);
}
+Fault
+InOrderDynInst::writeBytes(uint8_t *data, unsigned size,
+ Addr addr, unsigned flags, uint64_t *res)
+{
+ assert(sizeof(storeData) >= size);
+ memcpy(&storeData, data, size);
+ return cpu->write(this, (uint8_t *)&storeData, size, addr, flags, res);
+}
+
template<class T>
inline Fault
InOrderDynInst::write(T data, Addr addr, unsigned flags, uint64_t *res)
{
- if (traceData) {
- traceData->setAddr(addr);
- traceData->setData(data);
- }
-
storeData = data;
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Setting store data to %#x.\n",
threadNumber, seqNum, storeData);
- return cpu->write(this, data, addr, flags, res);
+ if (traceData) {
+ traceData->setAddr(addr);
+ traceData->setData(data);
+ }
+ storeData = TheISA::htog(data);
+ return writeBytes((uint8_t*)&data, sizeof(T), addr, flags, res);
}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
diff --git a/src/cpu/inorder/inorder_dyn_inst.hh b/src/cpu/inorder/inorder_dyn_inst.hh
index ffb795e1e..0d42f4696 100644
--- a/src/cpu/inorder/inorder_dyn_inst.hh
+++ b/src/cpu/inorder/inorder_dyn_inst.hh
@@ -334,7 +334,7 @@ class InOrderDynInst : public FastAlloc, public RefCounted
PacketDataPtr splitMemData;
RequestPtr splitMemReq;
- int splitTotalSize;
+ int totalSize;
int split2ndSize;
Addr split2ndAddr;
bool split2ndAccess;
@@ -637,6 +637,8 @@ class InOrderDynInst : public FastAlloc, public RefCounted
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.
@@ -649,6 +651,9 @@ class InOrderDynInst : public FastAlloc, public RefCounted
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);
+
/** Initiates a memory access - Calculate Eff. Addr & Initiate Memory
* Access Only valid for memory operations.
*/
diff --git a/src/cpu/inorder/resources/cache_unit.cc b/src/cpu/inorder/resources/cache_unit.cc
index 2ab9e889e..4d21f527e 100644
--- a/src/cpu/inorder/resources/cache_unit.cc
+++ b/src/cpu/inorder/resources/cache_unit.cc
@@ -443,9 +443,9 @@ CacheUnit::doTLBAccess(DynInstPtr inst, CacheReqPtr cache_req, int acc_size,
return cache_req->fault;
}
-template <class T>
Fault
-CacheUnit::read(DynInstPtr inst, Addr addr, T &data, unsigned flags)
+CacheUnit::read(DynInstPtr inst, Addr addr,
+ uint8_t *data, unsigned size, unsigned flags)
{
CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(findRequest(inst));
assert(cache_req && "Can't Find Instruction for Read!");
@@ -454,14 +454,15 @@ CacheUnit::read(DynInstPtr inst, Addr addr, T &data, unsigned flags)
unsigned blockSize = this->cachePort->peerBlockSize();
//The size of the data we're trying to read.
- int dataSize = sizeof(T);
+ int fullSize = size;
+ inst->totalSize = size;
if (inst->traceData) {
inst->traceData->setAddr(addr);
}
if (inst->split2ndAccess) {
- dataSize = inst->split2ndSize;
+ size = inst->split2ndSize;
cache_req->splitAccess = true;
cache_req->split2ndAccess = true;
@@ -473,7 +474,7 @@ CacheUnit::read(DynInstPtr inst, Addr addr, T &data, unsigned flags)
//The address of the second part of this access if it needs to be split
//across a cache line boundary.
- Addr secondAddr = roundDown(addr + dataSize - 1, blockSize);
+ Addr secondAddr = roundDown(addr + size - 1, blockSize);
if (secondAddr > addr && !inst->split2ndAccess) {
@@ -483,8 +484,7 @@ CacheUnit::read(DynInstPtr inst, Addr addr, T &data, unsigned flags)
// Save All "Total" Split Information
// ==============================
inst->splitInst = true;
- inst->splitMemData = new uint8_t[dataSize];
- inst->splitTotalSize = dataSize;
+ inst->splitMemData = new uint8_t[size];
if (!inst->splitInstSked) {
// Schedule Split Read/Complete for Instruction
@@ -517,22 +517,22 @@ CacheUnit::read(DynInstPtr inst, Addr addr, T &data, unsigned flags)
// Split Information for First Access
// ==============================
- dataSize = secondAddr - addr;
+ size = secondAddr - addr;
cache_req->splitAccess = true;
// Split Information for Second Access
// ==============================
- inst->split2ndSize = addr + sizeof(T) - secondAddr;
+ inst->split2ndSize = addr + fullSize - secondAddr;
inst->split2ndAddr = secondAddr;
- inst->split2ndDataPtr = inst->splitMemData + dataSize;
+ inst->split2ndDataPtr = inst->splitMemData + size;
inst->split2ndFlags = flags;
}
- doTLBAccess(inst, cache_req, dataSize, flags, TheISA::TLB::Read);
+ doTLBAccess(inst, cache_req, size, flags, TheISA::TLB::Read);
if (cache_req->fault == NoFault) {
if (!cache_req->splitAccess) {
- cache_req->reqData = new uint8_t[dataSize];
+ cache_req->reqData = new uint8_t[size];
doCacheAccess(inst, NULL);
} else {
if (!inst->split2ndAccess) {
@@ -548,10 +548,9 @@ CacheUnit::read(DynInstPtr inst, Addr addr, T &data, unsigned flags)
return cache_req->fault;
}
-template <class T>
Fault
-CacheUnit::write(DynInstPtr inst, T data, Addr addr, unsigned flags,
- uint64_t *write_res)
+CacheUnit::write(DynInstPtr inst, uint8_t *data, unsigned size,
+ Addr addr, unsigned flags, uint64_t *write_res)
{
CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(findRequest(inst));
assert(cache_req && "Can't Find Instruction for Write!");
@@ -559,16 +558,16 @@ CacheUnit::write(DynInstPtr inst, T data, Addr addr, unsigned flags,
// The block size of our peer
unsigned blockSize = this->cachePort->peerBlockSize();
- //The size of the data we're trying to read.
- int dataSize = sizeof(T);
+ //The size of the data we're trying to write.
+ int fullSize = size;
+ inst->totalSize = size;
if (inst->traceData) {
inst->traceData->setAddr(addr);
- inst->traceData->setData(data);
}
if (inst->split2ndAccess) {
- dataSize = inst->split2ndSize;
+ size = inst->split2ndSize;
cache_req->splitAccess = true;
cache_req->split2ndAccess = true;
@@ -579,7 +578,7 @@ CacheUnit::write(DynInstPtr inst, T data, Addr addr, unsigned flags,
//The address of the second part of this access if it needs to be split
//across a cache line boundary.
- Addr secondAddr = roundDown(addr + dataSize - 1, blockSize);
+ Addr secondAddr = roundDown(addr + size - 1, blockSize);
if (secondAddr > addr && !inst->split2ndAccess) {
@@ -589,7 +588,6 @@ CacheUnit::write(DynInstPtr inst, T data, Addr addr, unsigned flags,
// Save All "Total" Split Information
// ==============================
inst->splitInst = true;
- inst->splitTotalSize = dataSize;
if (!inst->splitInstSked) {
// Schedule Split Read/Complete for Instruction
@@ -624,25 +622,25 @@ CacheUnit::write(DynInstPtr inst, T data, Addr addr, unsigned flags,
// Split Information for First Access
// ==============================
- dataSize = secondAddr - addr;
+ size = secondAddr - addr;
cache_req->splitAccess = true;
// Split Information for Second Access
// ==============================
- inst->split2ndSize = addr + sizeof(T) - secondAddr;
+ inst->split2ndSize = addr + fullSize - secondAddr;
inst->split2ndAddr = secondAddr;
inst->split2ndStoreDataPtr = &cache_req->inst->storeData;
- inst->split2ndStoreDataPtr += dataSize;
+ inst->split2ndStoreDataPtr += size;
inst->split2ndFlags = flags;
inst->splitInstSked = true;
}
- doTLBAccess(inst, cache_req, dataSize, flags, TheISA::TLB::Write);
+ doTLBAccess(inst, cache_req, size, flags, TheISA::TLB::Write);
if (cache_req->fault == NoFault) {
if (!cache_req->splitAccess) {
// Remove this line since storeData is saved in INST?
- cache_req->reqData = new uint8_t[dataSize];
+ cache_req->reqData = new uint8_t[size];
doCacheAccess(inst, write_res);
} else {
doCacheAccess(inst, write_res, cache_req);
@@ -729,8 +727,8 @@ CacheUnit::execute(int slot_num)
cache_req->inst->split2ndAddr);
inst->split2ndAccess = true;
assert(inst->split2ndAddr != 0);
- read(inst, inst->split2ndAddr, inst->split2ndData,
- inst->split2ndFlags);
+ read(inst, inst->split2ndAddr, &inst->split2ndData,
+ inst->totalSize, inst->split2ndFlags);
break;
case InitSecondSplitWrite:
@@ -741,8 +739,8 @@ CacheUnit::execute(int slot_num)
inst->split2ndAccess = true;
assert(inst->split2ndAddr != 0);
- write(inst, inst->split2ndAddr, inst->split2ndData,
- inst->split2ndFlags, NULL);
+ write(inst, &inst->split2ndData, inst->totalSize,
+ inst->split2ndAddr, inst->split2ndFlags, NULL);
break;
@@ -1075,7 +1073,7 @@ CacheUnit::processCacheCompletion(PacketPtr pkt)
if (inst->splitFinishCnt == 2) {
cache_req->memReq->setVirt(0/*inst->tid*/,
inst->getMemAddr(),
- inst->splitTotalSize,
+ inst->totalSize,
0,
0);
@@ -1301,113 +1299,3 @@ CacheUnit::squash(DynInstPtr inst, int stage_num,
freeSlot(slot_remove_list[i]);
}
-// Extra Template Definitions
-#ifndef DOXYGEN_SHOULD_SKIP_THIS
-
-template
-Fault
-CacheUnit::read(DynInstPtr inst, Addr addr, Twin32_t &data, unsigned flags);
-
-template
-Fault
-CacheUnit::read(DynInstPtr inst, Addr addr, Twin64_t &data, unsigned flags);
-
-template
-Fault
-CacheUnit::read(DynInstPtr inst, Addr addr, uint64_t &data, unsigned flags);
-
-template
-Fault
-CacheUnit::read(DynInstPtr inst, Addr addr, uint32_t &data, unsigned flags);
-
-template
-Fault
-CacheUnit::read(DynInstPtr inst, Addr addr, uint16_t &data, unsigned flags);
-
-template
-Fault
-CacheUnit::read(DynInstPtr inst, Addr addr, uint8_t &data, unsigned flags);
-
-#endif //DOXYGEN_SHOULD_SKIP_THIS
-
-template<>
-Fault
-CacheUnit::read(DynInstPtr inst, Addr addr, double &data, unsigned flags)
-{
- return read(inst, addr, *(uint64_t*)&data, flags);
-}
-
-template<>
-Fault
-CacheUnit::read(DynInstPtr inst, Addr addr, float &data, unsigned flags)
-{
- return read(inst, addr, *(uint32_t*)&data, flags);
-}
-
-
-template<>
-Fault
-CacheUnit::read(DynInstPtr inst, Addr addr, int32_t &data, unsigned flags)
-{
- return read(inst, addr, (uint32_t&)data, flags);
-}
-
-#ifndef DOXYGEN_SHOULD_SKIP_THIS
-
-template
-Fault
-CacheUnit::write(DynInstPtr inst, Twin32_t data, Addr addr,
- unsigned flags, uint64_t *res);
-
-template
-Fault
-CacheUnit::write(DynInstPtr inst, Twin64_t data, Addr addr,
- unsigned flags, uint64_t *res);
-
-template
-Fault
-CacheUnit::write(DynInstPtr inst, uint64_t data, Addr addr,
- unsigned flags, uint64_t *res);
-
-template
-Fault
-CacheUnit::write(DynInstPtr inst, uint32_t data, Addr addr,
- unsigned flags, uint64_t *res);
-
-template
-Fault
-CacheUnit::write(DynInstPtr inst, uint16_t data, Addr addr,
- unsigned flags, uint64_t *res);
-
-template
-Fault
-CacheUnit::write(DynInstPtr inst, uint8_t data, Addr addr,
- unsigned flags, uint64_t *res);
-
-#endif //DOXYGEN_SHOULD_SKIP_THIS
-
-template<>
-Fault
-CacheUnit::write(DynInstPtr inst, double data, Addr addr, unsigned flags,
- uint64_t *res)
-{
- return write(inst, *(uint64_t*)&data, addr, flags, res);
-}
-
-template<>
-Fault
-CacheUnit::write(DynInstPtr inst, float data, Addr addr, unsigned flags,
- uint64_t *res)
-{
- return write(inst, *(uint32_t*)&data, addr, flags, res);
-}
-
-
-template<>
-Fault
-CacheUnit::write(DynInstPtr inst, int32_t data, Addr addr, unsigned flags,
- uint64_t *res)
-{
- return write(inst, (uint32_t)data, addr, flags, res);
-}
-
diff --git a/src/cpu/inorder/resources/cache_unit.hh b/src/cpu/inorder/resources/cache_unit.hh
index 177f81559..2f369db7c 100644
--- a/src/cpu/inorder/resources/cache_unit.hh
+++ b/src/cpu/inorder/resources/cache_unit.hh
@@ -161,12 +161,11 @@ class CacheUnit : public Resource
/** Returns a specific port. */
Port *getPort(const std::string &if_name, int idx);
- template <class T>
- Fault read(DynInstPtr inst, Addr addr, T &data, unsigned flags);
+ Fault read(DynInstPtr inst, Addr addr,
+ uint8_t *data, unsigned size, unsigned flags);
- template <class T>
- Fault write(DynInstPtr inst, T data, Addr addr, unsigned flags,
- uint64_t *res);
+ Fault write(DynInstPtr inst, uint8_t *data, unsigned size,
+ Addr addr, unsigned flags, uint64_t *res);
Fault doTLBAccess(DynInstPtr inst, CacheReqPtr cache_req, int acc_size,
int flags, TheISA::TLB::Mode tlb_mode);
diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh
index 82d4ca25b..a102a21f5 100644
--- a/src/cpu/o3/cpu.hh
+++ b/src/cpu/o3/cpu.hh
@@ -702,18 +702,16 @@ class FullO3CPU : public BaseO3CPU
std::vector<ThreadID> tids;
/** CPU read function, forwards read to LSQ. */
- template <class T>
Fault read(RequestPtr &req, RequestPtr &sreqLow, RequestPtr &sreqHigh,
- T &data, int load_idx)
+ uint8_t *data, int load_idx)
{
return this->iew.ldstQueue.read(req, sreqLow, sreqHigh,
data, load_idx);
}
/** CPU write function, forwards write to LSQ. */
- template <class T>
Fault write(RequestPtr &req, RequestPtr &sreqLow, RequestPtr &sreqHigh,
- T &data, int store_idx)
+ uint8_t *data, int store_idx)
{
return this->iew.ldstQueue.write(req, sreqLow, sreqHigh,
data, store_idx);
diff --git a/src/cpu/o3/lsq.hh b/src/cpu/o3/lsq.hh
index 7a7ea917f..0ad5d51c2 100644
--- a/src/cpu/o3/lsq.hh
+++ b/src/cpu/o3/lsq.hh
@@ -273,16 +273,14 @@ class LSQ {
/** Executes a read operation, using the load specified at the load
* index.
*/
- template <class T>
Fault read(RequestPtr req, RequestPtr sreqLow, RequestPtr sreqHigh,
- T &data, int load_idx);
+ uint8_t *data, int load_idx);
/** Executes a store operation, using the store specified at the store
* index.
*/
- template <class T>
Fault write(RequestPtr req, RequestPtr sreqLow, RequestPtr sreqHigh,
- T &data, int store_idx);
+ uint8_t *data, int store_idx);
/** The CPU pointer. */
O3CPU *cpu;
@@ -371,10 +369,9 @@ class LSQ {
};
template <class Impl>
-template <class T>
Fault
LSQ<Impl>::read(RequestPtr req, RequestPtr sreqLow, RequestPtr sreqHigh,
- T &data, int load_idx)
+ uint8_t *data, int load_idx)
{
ThreadID tid = req->threadId();
@@ -382,10 +379,9 @@ LSQ<Impl>::read(RequestPtr req, RequestPtr sreqLow, RequestPtr sreqHigh,
}
template <class Impl>
-template <class T>
Fault
LSQ<Impl>::write(RequestPtr req, RequestPtr sreqLow, RequestPtr sreqHigh,
- T &data, int store_idx)
+ uint8_t *data, int store_idx)
{
ThreadID tid = req->threadId();
diff --git a/src/cpu/o3/lsq_unit.hh b/src/cpu/o3/lsq_unit.hh
index c19a368d1..10b1ed11a 100644
--- a/src/cpu/o3/lsq_unit.hh
+++ b/src/cpu/o3/lsq_unit.hh
@@ -474,14 +474,12 @@ class LSQUnit {
public:
/** Executes the load at the given index. */
- template <class T>
- Fault read(Request *req, Request *sreqLow, Request *sreqHigh, T &data,
- int load_idx);
+ Fault read(Request *req, Request *sreqLow, Request *sreqHigh,
+ uint8_t *data, int load_idx);
/** Executes the store at the given index. */
- template <class T>
- Fault write(Request *req, Request *sreqLow, Request *sreqHigh, T &data,
- int store_idx);
+ Fault write(Request *req, Request *sreqLow, Request *sreqHigh,
+ uint8_t *data, int store_idx);
/** Returns the index of the head load instruction. */
int getLoadHead() { return loadHead; }
@@ -514,10 +512,9 @@ class LSQUnit {
};
template <class Impl>
-template <class T>
Fault
LSQUnit<Impl>::read(Request *req, Request *sreqLow, Request *sreqHigh,
- T &data, int load_idx)
+ uint8_t *data, int load_idx)
{
DynInstPtr load_inst = loadQueue[load_idx];
@@ -605,7 +602,8 @@ LSQUnit<Impl>::read(Request *req, Request *sreqLow, Request *sreqHigh,
// Get shift amount for offset into the store's data.
int shift_amt = req->getVaddr() & (store_size - 1);
- memcpy(&data, storeQueue[store_idx].data + shift_amt, sizeof(T));
+ memcpy(data, storeQueue[store_idx].data + shift_amt,
+ req->getSize());
assert(!load_inst->memData);
load_inst->memData = new uint8_t[64];
@@ -809,10 +807,9 @@ LSQUnit<Impl>::read(Request *req, Request *sreqLow, Request *sreqHigh,
}
template <class Impl>
-template <class T>
Fault
LSQUnit<Impl>::write(Request *req, Request *sreqLow, Request *sreqHigh,
- T &data, int store_idx)
+ uint8_t *data, int store_idx)
{
assert(storeQueue[store_idx].inst);
@@ -824,17 +821,17 @@ LSQUnit<Impl>::write(Request *req, Request *sreqLow, Request *sreqHigh,
storeQueue[store_idx].req = req;
storeQueue[store_idx].sreqLow = sreqLow;
storeQueue[store_idx].sreqHigh = sreqHigh;
- storeQueue[store_idx].size = sizeof(T);
+ unsigned size = req->getSize();
+ storeQueue[store_idx].size = size;
+ assert(size <= sizeof(storeQueue[store_idx].data));
// Split stores can only occur in ISAs with unaligned memory accesses. If
// a store request has been split, sreqLow and sreqHigh will be non-null.
if (TheISA::HasUnalignedMemAcc && sreqLow) {
storeQueue[store_idx].isSplit = true;
}
- assert(sizeof(T) <= sizeof(storeQueue[store_idx].data));
- T gData = htog(data);
- memcpy(storeQueue[store_idx].data, &gData, sizeof(T));
+ memcpy(storeQueue[store_idx].data, data, size);
// This function only writes the data to the store queue, so no fault
// can happen here.
diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc
index f8819c734..8ee91758f 100644
--- a/src/cpu/simple/atomic.cc
+++ b/src/cpu/simple/atomic.cc
@@ -294,9 +294,9 @@ AtomicSimpleCPU::suspendContext(int thread_num)
}
-template <class T>
Fault
-AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
+AtomicSimpleCPU::readBytes(Addr addr, uint8_t * data,
+ unsigned size, unsigned flags)
{
// use the CPU's statically allocated read request and packet objects
Request *req = &data_read_req;
@@ -308,21 +308,19 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
//The block size of our peer.
unsigned blockSize = dcachePort.peerBlockSize();
//The size of the data we're trying to read.
- int dataSize = sizeof(T);
-
- uint8_t * dataPtr = (uint8_t *)&data;
+ int fullSize = size;
//The address of the second part of this access if it needs to be split
//across a cache line boundary.
- Addr secondAddr = roundDown(addr + dataSize - 1, blockSize);
+ Addr secondAddr = roundDown(addr + size - 1, blockSize);
- if(secondAddr > addr)
- dataSize = secondAddr - addr;
+ if (secondAddr > addr)
+ size = secondAddr - addr;
dcache_latency = 0;
- while(1) {
- req->setVirt(0, addr, dataSize, flags, thread->readPC());
+ while (1) {
+ req->setVirt(0, addr, size, flags, thread->readPC());
// translate to physical address
Fault fault = thread->dtb->translateAtomic(req, tc, BaseTLB::Read);
@@ -332,7 +330,7 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
Packet pkt = Packet(req,
req->isLLSC() ? MemCmd::LoadLockedReq : MemCmd::ReadReq,
Packet::Broadcast);
- pkt.dataStatic(dataPtr);
+ pkt.dataStatic(data);
if (req->isMmapedIpr())
dcache_latency += TheISA::handleIprRead(thread->getTC(), &pkt);
@@ -363,10 +361,6 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
//If we don't need to access a second cache line, stop now.
if (secondAddr <= addr)
{
- data = gtoh(data);
- if (traceData) {
- traceData->setData(data);
- }
if (req->isLocked() && fault == NoFault) {
assert(!locked);
locked = true;
@@ -379,14 +373,30 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
*/
//Move the pointer we're reading into to the correct location.
- dataPtr += dataSize;
+ data += size;
//Adjust the size to get the remaining bytes.
- dataSize = addr + sizeof(T) - secondAddr;
+ size = addr + fullSize - secondAddr;
//And access the right address.
addr = secondAddr;
}
}
+
+template <class T>
+Fault
+AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
+{
+ uint8_t *dataPtr = (uint8_t *)&data;
+ memset(dataPtr, 0, sizeof(data));
+ Fault fault = readBytes(addr, dataPtr, sizeof(data), flags);
+ if (fault == NoFault) {
+ data = gtoh(data);
+ if (traceData)
+ traceData->setData(data);
+ }
+ return fault;
+}
+
#ifndef DOXYGEN_SHOULD_SKIP_THIS
template
@@ -438,38 +448,33 @@ AtomicSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
}
-template <class T>
Fault
-AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
+AtomicSimpleCPU::writeBytes(uint8_t *data, unsigned size,
+ Addr addr, unsigned flags, uint64_t *res)
{
// use the CPU's statically allocated write request and packet objects
Request *req = &data_write_req;
if (traceData) {
traceData->setAddr(addr);
- traceData->setData(data);
}
- data = htog(data);
-
//The block size of our peer.
unsigned blockSize = dcachePort.peerBlockSize();
//The size of the data we're trying to read.
- int dataSize = sizeof(T);
-
- uint8_t * dataPtr = (uint8_t *)&data;
+ int fullSize = size;
//The address of the second part of this access if it needs to be split
//across a cache line boundary.
- Addr secondAddr = roundDown(addr + dataSize - 1, blockSize);
+ Addr secondAddr = roundDown(addr + size - 1, blockSize);
if(secondAddr > addr)
- dataSize = secondAddr - addr;
+ size = secondAddr - addr;
dcache_latency = 0;
while(1) {
- req->setVirt(0, addr, dataSize, flags, thread->readPC());
+ req->setVirt(0, addr, size, flags, thread->readPC());
// translate to physical address
Fault fault = thread->dtb->translateAtomic(req, tc, BaseTLB::Write);
@@ -492,7 +497,7 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
if (do_access && !req->getFlags().isSet(Request::NO_ACCESS)) {
Packet pkt = Packet(req, cmd, Packet::Broadcast);
- pkt.dataStatic(dataPtr);
+ pkt.dataStatic(data);
if (req->isMmapedIpr()) {
dcache_latency +=
@@ -508,7 +513,7 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
if (req->isSwap()) {
assert(res);
- *res = pkt.get<T>();
+ memcpy(res, pkt.getPtr<uint8_t>(), fullSize);
}
}
@@ -537,15 +542,32 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
*/
//Move the pointer we're reading into to the correct location.
- dataPtr += dataSize;
+ data += size;
//Adjust the size to get the remaining bytes.
- dataSize = addr + sizeof(T) - secondAddr;
+ size = addr + fullSize - secondAddr;
//And access the right address.
addr = secondAddr;
}
}
+template <class T>
+Fault
+AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
+{
+ uint8_t *dataPtr = (uint8_t *)&data;
+ if (traceData)
+ traceData->setData(data);
+ data = htog(data);
+
+ Fault fault = writeBytes(dataPtr, sizeof(data), addr, flags, res);
+ if (fault == NoFault && data_write_req.isSwap()) {
+ *res = gtoh((T)*res);
+ }
+ return fault;
+}
+
+
#ifndef DOXYGEN_SHOULD_SKIP_THIS
template
diff --git a/src/cpu/simple/atomic.hh b/src/cpu/simple/atomic.hh
index 2a66e9341..5ec1970e7 100644
--- a/src/cpu/simple/atomic.hh
+++ b/src/cpu/simple/atomic.hh
@@ -134,9 +134,14 @@ class AtomicSimpleCPU : public BaseSimpleCPU
template <class T>
Fault read(Addr addr, T &data, unsigned flags);
+ Fault readBytes(Addr addr, uint8_t *data, unsigned size, unsigned flags);
+
template <class T>
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);
+
/**
* Print state of address in memory system via PrintReq (for
* debugging).
diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc
index b8fc5ab84..1670cb066 100644
--- a/src/cpu/simple/timing.cc
+++ b/src/cpu/simple/timing.cc
@@ -414,26 +414,25 @@ TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2,
pkt2->senderState = new SplitFragmentSenderState(pkt, 1);
}
-template <class T>
Fault
-TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
+TimingSimpleCPU::readBytes(Addr addr, uint8_t *data,
+ unsigned size, unsigned flags)
{
Fault fault;
const int asid = 0;
const ThreadID tid = 0;
const Addr pc = thread->readPC();
unsigned block_size = dcachePort.peerBlockSize();
- int data_size = sizeof(T);
BaseTLB::Mode mode = BaseTLB::Read;
if (traceData) {
traceData->setAddr(addr);
}
- RequestPtr req = new Request(asid, addr, data_size,
+ RequestPtr req = new Request(asid, addr, size,
flags, pc, _cpuId, tid);
- Addr split_addr = roundDown(addr + data_size - 1, block_size);
+ Addr split_addr = roundDown(addr + size - 1, block_size);
assert(split_addr <= addr || split_addr - addr < block_size);
_status = DTBWaitResponse;
@@ -443,7 +442,7 @@ TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
req->splitOnVaddr(split_addr, req1, req2);
WholeTranslationState *state =
- new WholeTranslationState(req, req1, req2, (uint8_t *)(new T),
+ new WholeTranslationState(req, req1, req2, new uint8_t[size],
NULL, mode);
DataTranslation<TimingSimpleCPU> *trans1 =
new DataTranslation<TimingSimpleCPU>(this, state, 0);
@@ -454,7 +453,7 @@ TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
thread->dtb->translateTiming(req2, tc, trans2, mode);
} else {
WholeTranslationState *state =
- new WholeTranslationState(req, (uint8_t *)(new T), NULL, mode);
+ new WholeTranslationState(req, new uint8_t[size], NULL, mode);
DataTranslation<TimingSimpleCPU> *translation
= new DataTranslation<TimingSimpleCPU>(this, state);
thread->dtb->translateTiming(req, tc, translation, mode);
@@ -463,6 +462,13 @@ TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
return NoFault;
}
+template <class T>
+Fault
+TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
+{
+ return readBytes(addr, (uint8_t *)&data, sizeof(T), flags);
+}
+
#ifndef DOXYGEN_SHOULD_SKIP_THIS
template
@@ -532,30 +538,26 @@ TimingSimpleCPU::handleWritePacket()
return dcache_pkt == NULL;
}
-template <class T>
Fault
-TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
+TimingSimpleCPU::writeTheseBytes(uint8_t *data, unsigned size,
+ Addr addr, unsigned flags, uint64_t *res)
{
const int asid = 0;
const ThreadID tid = 0;
const Addr pc = thread->readPC();
unsigned block_size = dcachePort.peerBlockSize();
- int data_size = sizeof(T);
BaseTLB::Mode mode = BaseTLB::Write;
if (traceData) {
traceData->setAddr(addr);
- traceData->setData(data);
}
- RequestPtr req = new Request(asid, addr, data_size,
+ RequestPtr req = new Request(asid, addr, size,
flags, pc, _cpuId, tid);
- Addr split_addr = roundDown(addr + data_size - 1, block_size);
+ Addr split_addr = roundDown(addr + size - 1, block_size);
assert(split_addr <= addr || split_addr - addr < block_size);
- T *dataP = new T;
- *dataP = TheISA::htog(data);
_status = DTBWaitResponse;
if (split_addr > addr) {
RequestPtr req1, req2;
@@ -563,8 +565,7 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
req->splitOnVaddr(split_addr, req1, req2);
WholeTranslationState *state =
- new WholeTranslationState(req, req1, req2, (uint8_t *)dataP,
- res, mode);
+ new WholeTranslationState(req, req1, req2, data, res, mode);
DataTranslation<TimingSimpleCPU> *trans1 =
new DataTranslation<TimingSimpleCPU>(this, state, 0);
DataTranslation<TimingSimpleCPU> *trans2 =
@@ -574,7 +575,7 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
thread->dtb->translateTiming(req2, tc, trans2, mode);
} else {
WholeTranslationState *state =
- new WholeTranslationState(req, (uint8_t *)dataP, res, mode);
+ new WholeTranslationState(req, data, res, mode);
DataTranslation<TimingSimpleCPU> *translation =
new DataTranslation<TimingSimpleCPU>(this, state);
thread->dtb->translateTiming(req, tc, translation, mode);
@@ -584,6 +585,28 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
return NoFault;
}
+Fault
+TimingSimpleCPU::writeBytes(uint8_t *data, unsigned size,
+ Addr addr, unsigned flags, uint64_t *res)
+{
+ uint8_t *newData = new uint8_t[size];
+ memcpy(newData, data, size);
+ return writeTheseBytes(newData, size, addr, flags, res);
+}
+
+template <class T>
+Fault
+TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
+{
+ if (traceData) {
+ traceData->setData(data);
+ }
+ T *dataP = new T;
+ *dataP = TheISA::htog(data);
+
+ return writeTheseBytes((uint8_t *)dataP, sizeof(T), addr, flags, res);
+}
+
#ifndef DOXYGEN_SHOULD_SKIP_THIS
template
diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh
index 62c105418..65cbe3098 100644
--- a/src/cpu/simple/timing.hh
+++ b/src/cpu/simple/timing.hh
@@ -251,9 +251,14 @@ class TimingSimpleCPU : public BaseSimpleCPU
template <class T>
Fault read(Addr addr, T &data, unsigned flags);
+ Fault readBytes(Addr addr, uint8_t *data, unsigned size, unsigned flags);
+
template <class T>
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);
+
void fetch();
void sendFetch(Fault fault, RequestPtr req, ThreadContext *tc);
void completeIfetch(PacketPtr );
@@ -274,6 +279,11 @@ class TimingSimpleCPU : public BaseSimpleCPU
private:
+ // The backend for writeBytes and write. It's the same as writeBytes, but
+ // doesn't make a copy of data.
+ Fault writeTheseBytes(uint8_t *data, unsigned size,
+ Addr addr, unsigned flags, uint64_t *res);
+
typedef EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch> FetchEvent;
FetchEvent fetchEvent;