From: Gabe Black Date: Fri, 14 Nov 2008 07:30:37 +0000 (-0800) Subject: CPU: Refactor read/write in the simple timing CPU. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=7a4d75bae31cfe2064fe0718c7f982f769659b3c;p=gem5.git CPU: Refactor read/write in the simple timing CPU. --- diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index 5d37fa620..5da08db47 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -262,6 +262,72 @@ TimingSimpleCPU::handleReadPacket(PacketPtr pkt) return dcache_pkt == NULL; } +Fault +TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, + RequestPtr &req, Addr split_addr, uint8_t *data, bool read) +{ + Fault fault; + RequestPtr req1, req2; + assert(!req->isLocked() && !req->isSwap()); + req->splitOnVaddr(split_addr, req1, req2); + + pkt1 = pkt2 = NULL; + if ((fault = buildPacket(pkt1, req1, read)) != NoFault || + (fault = buildPacket(pkt2, req2, read)) != NoFault) { + delete req; + delete pkt1; + req = NULL; + pkt1 = NULL; + return fault; + } + + assert(!req1->isMmapedIpr() && !req2->isMmapedIpr()); + + req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags()); + PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(), + Packet::Broadcast); + + pkt->dataDynamic(data); + pkt1->dataStatic(data); + pkt2->dataStatic(data + req1->getSize()); + + SplitMainSenderState * main_send_state = new SplitMainSenderState; + pkt->senderState = main_send_state; + main_send_state->fragments[0] = pkt1; + main_send_state->fragments[1] = pkt2; + main_send_state->outstanding = 2; + pkt1->senderState = new SplitFragmentSenderState(pkt, 0); + pkt2->senderState = new SplitFragmentSenderState(pkt, 1); + return fault; +} + +Fault +TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr &req, bool read) +{ + Fault fault = read ? thread->translateDataReadReq(req) : + thread->translateDataWriteReq(req); + MemCmd cmd; + if (fault != NoFault) { + delete req; + req = NULL; + pkt = NULL; + return fault; + } else if (read) { + cmd = MemCmd::ReadReq; + if (req->isLocked()) + cmd = MemCmd::LoadLockedReq; + } else { + cmd = MemCmd::WriteReq; + if (req->isLocked()) { + cmd = MemCmd::StoreCondReq; + } else if (req->isSwap()) { + cmd = MemCmd::SwapReq; + } + } + pkt = new Packet(req, cmd, Packet::Broadcast); + return NoFault; +} + template Fault TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) @@ -270,91 +336,35 @@ TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) const int asid = 0; const int thread_id = 0; const Addr pc = thread->readPC(); - - PacketPtr pkt; - RequestPtr req; - int block_size = dcachePort.peerBlockSize(); int data_size = sizeof(T); - Addr second_addr = roundDown(addr + data_size - 1, block_size); - - if (second_addr > addr) { - Addr first_size = second_addr - addr; - Addr second_size = data_size - first_size; - // Make sure we'll only need two accesses. - assert(roundDown(second_addr + second_size - 1, block_size) == - second_addr); - - /* - * Do the translations. If something isn't going to work, find out - * before we waste time setting up anything else. - */ - req = new Request(asid, addr, first_size, - flags, pc, _cpuId, thread_id); - fault = thread->translateDataReadReq(req); - if (fault != NoFault) { - delete req; - return fault; - } - Request *second_req = - new Request(asid, second_addr, second_size, - flags, pc, _cpuId, thread_id); - fault = thread->translateDataReadReq(second_req); - if (fault != NoFault) { - delete req; - delete second_req; - return fault; - } - - T * data_ptr = new T; - - /* - * This is the big packet that will hold the data we've gotten so far, - * if any, and also act as the response we actually give to the - * instruction. - */ - Request *orig_req = - new Request(asid, addr, data_size, flags, pc, _cpuId, thread_id); - orig_req->setPhys(req->getPaddr(), data_size, flags); - PacketPtr big_pkt = - new Packet(orig_req, MemCmd::ReadResp, Packet::Broadcast); - big_pkt->dataDynamic(data_ptr); - SplitMainSenderState * main_send_state = new SplitMainSenderState; - big_pkt->senderState = main_send_state; - main_send_state->outstanding = 2; - - // This is the packet we'll process now. - pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast); - pkt->dataStatic((uint8_t *)data_ptr); - pkt->senderState = new SplitFragmentSenderState(big_pkt, 0); - - // This is the second half of the access we'll deal with later. - PacketPtr second_pkt = - new Packet(second_req, MemCmd::ReadReq, Packet::Broadcast); - second_pkt->dataStatic((uint8_t *)data_ptr + first_size); - second_pkt->senderState = new SplitFragmentSenderState(big_pkt, 1); - if (!handleReadPacket(pkt)) { - main_send_state->fragments[1] = second_pkt; - } else { - handleReadPacket(second_pkt); + PacketPtr pkt; + RequestPtr req = new Request(asid, addr, data_size, + flags, pc, _cpuId, thread_id); + + Addr split_addr = roundDown(addr + data_size - 1, block_size); + assert(split_addr <= addr || split_addr - addr < block_size); + + if (split_addr > addr) { + PacketPtr pkt1, pkt2; + this->buildSplitPacket(pkt1, pkt2, req, + split_addr, (uint8_t *)(new T), true); + if (handleReadPacket(pkt1)) { + SplitFragmentSenderState * send_state = + dynamic_cast(pkt1->senderState); + send_state->clearFromParent(); + if (handleReadPacket(pkt2)) { + send_state = + dynamic_cast(pkt1->senderState); + send_state->clearFromParent(); + } } } else { - req = new Request(asid, addr, data_size, - flags, pc, _cpuId, thread_id); - - // translate to physical address - Fault fault = thread->translateDataReadReq(req); - + Fault fault = buildPacket(pkt, req, true); if (fault != NoFault) { - delete req; return fault; } - - pkt = new Packet(req, - (req->isLocked() ? - MemCmd::LoadLockedReq : MemCmd::ReadReq), - Packet::Broadcast); pkt->dataDynamic(new T); handleReadPacket(pkt); @@ -468,107 +478,50 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) { const int asid = 0; const int thread_id = 0; - bool do_access = true; // flag to suppress cache access const Addr pc = thread->readPC(); - - RequestPtr req; - int block_size = dcachePort.peerBlockSize(); int data_size = sizeof(T); - Addr second_addr = roundDown(addr + data_size - 1, block_size); + RequestPtr req = new Request(asid, addr, data_size, + flags, pc, _cpuId, thread_id); - if (second_addr > addr) { - Fault fault; - Addr first_size = second_addr - addr; - Addr second_size = data_size - first_size; - // Make sure we'll only need two accesses. - assert(roundDown(second_addr + second_size - 1, block_size) == - second_addr); + Addr split_addr = roundDown(addr + data_size - 1, block_size); + assert(split_addr <= addr || split_addr - addr < block_size); - req = new Request(asid, addr, first_size, - flags, pc, _cpuId, thread_id); - fault = thread->translateDataWriteReq(req); - if (fault != NoFault) { - delete req; - return fault; - } - RequestPtr second_req = new Request(asid, second_addr, second_size, - flags, pc, _cpuId, thread_id); - fault = thread->translateDataWriteReq(second_req); - if (fault != NoFault) { - delete req; - delete second_req; + if (split_addr > addr) { + PacketPtr pkt1, pkt2; + T *dataP = new T; + *dataP = data; + Fault fault = this->buildSplitPacket(pkt1, pkt2, req, split_addr, + (uint8_t *)dataP, false); + if (fault != NoFault) return fault; - } - - if (req->isLocked() || req->isSwap() || - second_req->isLocked() || second_req->isSwap()) { - panic("LL/SCs and swaps can't be split."); - } - - T * data_ptr = new T; - - /* - * This is the big packet that will hold the data we've gotten so far, - * if any, and also act as the response we actually give to the - * instruction. - */ - RequestPtr orig_req = - new Request(asid, addr, data_size, flags, pc, _cpuId, thread_id); - orig_req->setPhys(req->getPaddr(), data_size, flags); - PacketPtr big_pkt = - new Packet(orig_req, MemCmd::WriteResp, Packet::Broadcast); - big_pkt->dataDynamic(data_ptr); - big_pkt->set(data); - SplitMainSenderState * main_send_state = new SplitMainSenderState; - big_pkt->senderState = main_send_state; - main_send_state->outstanding = 2; - - assert(dcache_pkt == NULL); - // This is the packet we'll process now. - dcache_pkt = new Packet(req, MemCmd::WriteReq, Packet::Broadcast); - dcache_pkt->dataStatic((uint8_t *)data_ptr); - dcache_pkt->senderState = new SplitFragmentSenderState(big_pkt, 0); - - // This is the second half of the access we'll deal with later. - PacketPtr second_pkt = - new Packet(second_req, MemCmd::WriteReq, Packet::Broadcast); - second_pkt->dataStatic((uint8_t *)data_ptr + first_size); - second_pkt->senderState = new SplitFragmentSenderState(big_pkt, 1); - if (!handleWritePacket()) { - main_send_state->fragments[1] = second_pkt; - } else { - dcache_pkt = second_pkt; - handleWritePacket(); + dcache_pkt = pkt1; + if (handleWritePacket()) { + SplitFragmentSenderState * send_state = + dynamic_cast(pkt1->senderState); + send_state->clearFromParent(); + dcache_pkt = pkt2; + if (handleReadPacket(pkt2)) { + send_state = + dynamic_cast(pkt1->senderState); + send_state->clearFromParent(); + } } } else { - req = new Request(asid, addr, data_size, flags, pc, _cpuId, thread_id); + bool do_access = true; // flag to suppress cache access - // translate to physical address - Fault fault = thread->translateDataWriteReq(req); - if (fault != NoFault) { - delete req; + Fault fault = buildPacket(dcache_pkt, req, false); + if (fault != NoFault) return fault; - } - - MemCmd cmd = MemCmd::WriteReq; // default if (req->isLocked()) { - cmd = MemCmd::StoreCondReq; do_access = TheISA::handleLockedWrite(thread, req); - } else if (req->isSwap()) { - cmd = MemCmd::SwapReq; - if (req->isCondSwap()) { - assert(res); - req->setExtraData(*res); - } + } else if (req->isCondSwap()) { + assert(res); + req->setExtraData(*res); } - // Note: need to allocate dcache_pkt even if do_access is - // false, as it's used unconditionally to call completeAcc(). - assert(dcache_pkt == NULL); - dcache_pkt = new Packet(req, cmd, Packet::Broadcast); dcache_pkt->allocate(); if (req->isMmapedIpr()) dcache_pkt->set(htog(data)); diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh index b641b1302..c305d0361 100644 --- a/src/cpu/simple/timing.hh +++ b/src/cpu/simple/timing.hh @@ -65,12 +65,6 @@ class TimingSimpleCPU : public BaseSimpleCPU int outstanding; PacketPtr fragments[2]; - SplitMainSenderState() - { - fragments[0] = NULL; - fragments[1] = NULL; - } - int getPendingFragment() { @@ -102,6 +96,10 @@ class TimingSimpleCPU : public BaseSimpleCPU } }; + Fault buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, RequestPtr &req, + Addr split_addr, uint8_t *data, bool read); + Fault buildPacket(PacketPtr &pkt, RequestPtr &req, bool read); + bool handleReadPacket(PacketPtr pkt); // This function always implicitly uses dcache_pkt. bool handleWritePacket(); diff --git a/src/mem/request.hh b/src/mem/request.hh index c3a523d9b..007c33acf 100644 --- a/src/mem/request.hh +++ b/src/mem/request.hh @@ -43,6 +43,7 @@ #include "base/fast_alloc.hh" #include "base/flags.hh" +#include "base/misc.hh" #include "sim/host.hh" #include "sim/core.hh" @@ -232,6 +233,24 @@ class Request : public FastAlloc flags.set(VALID_PADDR); } + /** + * Generate two requests as if this request had been split into two + * pieces. The original request can't have been translated already. + */ + void splitOnVaddr(Addr split_addr, RequestPtr &req1, RequestPtr &req2) + { + assert(flags.any(VALID_VADDR)); + assert(flags.none(VALID_PADDR)); + assert(split_addr > vaddr && split_addr < vaddr + size); + req1 = new Request; + *req1 = *this; + req2 = new Request; + *req2 = *this; + req1->size = split_addr - vaddr; + req2->vaddr = split_addr; + req2->size = size - req1->size; + } + /** * Accessor for paddr. */