summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cpu/simple/timing.cc277
-rw-r--r--src/cpu/simple/timing.hh10
-rw-r--r--src/mem/request.hh19
3 files changed, 138 insertions, 168 deletions
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<uint8_t>(data);
+ pkt1->dataStatic<uint8_t>(data);
+ pkt2->dataStatic<uint8_t>(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 <class T>
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<T>(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>((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>((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<SplitFragmentSenderState *>(pkt1->senderState);
+ send_state->clearFromParent();
+ if (handleReadPacket(pkt2)) {
+ send_state =
+ dynamic_cast<SplitFragmentSenderState *>(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<T>(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<T>(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>((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>((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<SplitFragmentSenderState *>(pkt1->senderState);
+ send_state->clearFromParent();
+ dcache_pkt = pkt2;
+ if (handleReadPacket(pkt2)) {
+ send_state =
+ dynamic_cast<SplitFragmentSenderState *>(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"
@@ -233,6 +234,24 @@ class Request : public FastAlloc
}
/**
+ * 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.
*/
Addr