diff options
author | Gabe Black <gblack@eecs.umich.edu> | 2010-08-13 06:16:02 -0700 |
---|---|---|
committer | Gabe Black <gblack@eecs.umich.edu> | 2010-08-13 06:16:02 -0700 |
commit | aa8c6e9c959eab4d516bc07593bea20ade9ad80c (patch) | |
tree | 3e0112e567da5dc1aa019f85458fbd9e37ad0cf2 /src/cpu/simple | |
parent | 65dbcc6ea170e05ca2370a9a265a61668250fa98 (diff) | |
download | gem5-aa8c6e9c959eab4d516bc07593bea20ade9ad80c.tar.xz |
CPU: Add readBytes and writeBytes functions to the exec contexts.
Diffstat (limited to 'src/cpu/simple')
-rw-r--r-- | src/cpu/simple/atomic.cc | 86 | ||||
-rw-r--r-- | src/cpu/simple/atomic.hh | 5 | ||||
-rw-r--r-- | src/cpu/simple/timing.cc | 59 | ||||
-rw-r--r-- | src/cpu/simple/timing.hh | 10 |
4 files changed, 110 insertions, 50 deletions
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; |