summaryrefslogtreecommitdiff
path: root/src/cpu/simple/timing.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu/simple/timing.cc')
-rw-r--r--src/cpu/simple/timing.cc606
1 files changed, 394 insertions, 212 deletions
diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc
index a76824ff3..a8f86f8d2 100644
--- a/src/cpu/simple/timing.cc
+++ b/src/cpu/simple/timing.cc
@@ -57,13 +57,12 @@ void
TimingSimpleCPU::init()
{
BaseCPU::init();
- cpuId = tc->readCpuId();
#if FULL_SYSTEM
for (int i = 0; i < threadContexts.size(); ++i) {
ThreadContext *tc = threadContexts[i];
// initialize CPU, including PC
- TheISA::initCPU(tc, cpuId);
+ TheISA::initCPU(tc, _cpuId);
}
#endif
}
@@ -101,11 +100,12 @@ void
TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t)
{
pkt = _pkt;
- Event::schedule(t);
+ cpu->schedule(this, t);
}
-TimingSimpleCPU::TimingSimpleCPU(Params *p)
- : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock)
+TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p)
+ : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this, p->clock),
+ dcachePort(this, p->clock), fetchEvent(this)
{
_status = Idle;
@@ -114,7 +114,6 @@ TimingSimpleCPU::TimingSimpleCPU(Params *p)
ifetch_pkt = dcache_pkt = NULL;
drainEvent = NULL;
- fetchEvent = NULL;
previousTick = 0;
changeState(SimObject::Running);
}
@@ -145,7 +144,7 @@ TimingSimpleCPU::drain(Event *drain_event)
{
// TimingSimpleCPU is ready to drain if it's not waiting for
// an access to complete.
- if (status() == Idle || status() == Running || status() == SwitchedOut) {
+ if (_status == Idle || _status == Running || _status == SwitchedOut) {
changeState(SimObject::Drained);
return 0;
} else {
@@ -162,15 +161,10 @@ TimingSimpleCPU::resume()
if (_status != SwitchedOut && _status != Idle) {
assert(system->getMemoryMode() == Enums::timing);
- // Delete the old event if it existed.
- if (fetchEvent) {
- if (fetchEvent->scheduled())
- fetchEvent->deschedule();
+ if (fetchEvent.scheduled())
+ deschedule(fetchEvent);
- delete fetchEvent;
- }
-
- fetchEvent = new FetchEvent(this, nextCycle());
+ schedule(fetchEvent, nextCycle());
}
changeState(SimObject::Running);
@@ -179,14 +173,14 @@ TimingSimpleCPU::resume()
void
TimingSimpleCPU::switchOut()
{
- assert(status() == Running || status() == Idle);
+ assert(_status == Running || _status == Idle);
_status = SwitchedOut;
numCycles += tickToCycles(curTick - previousTick);
// If we've been scheduled to resume but are then told to switch out,
// we'll need to cancel it.
- if (fetchEvent && fetchEvent->scheduled())
- fetchEvent->deschedule();
+ if (fetchEvent.scheduled())
+ deschedule(fetchEvent);
}
@@ -209,7 +203,6 @@ TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
_status = Idle;
}
assert(threadContexts.size() == 1);
- cpuId = tc->readCpuId();
previousTick = curTick;
}
@@ -228,7 +221,7 @@ TimingSimpleCPU::activateContext(int thread_num, int delay)
_status = Running;
// kick things off by initiating the fetch of the next instruction
- fetchEvent = new FetchEvent(this, nextCycle(curTick + ticks(delay)));
+ schedule(fetchEvent, nextCycle(curTick + ticks(delay)));
}
@@ -249,74 +242,239 @@ TimingSimpleCPU::suspendContext(int thread_num)
_status = Idle;
}
+bool
+TimingSimpleCPU::handleReadPacket(PacketPtr pkt)
+{
+ RequestPtr req = pkt->req;
+ if (req->isMmapedIpr()) {
+ Tick delay;
+ delay = TheISA::handleIprRead(thread->getTC(), pkt);
+ new IprEvent(pkt, this, nextCycle(curTick + delay));
+ _status = DcacheWaitResponse;
+ dcache_pkt = NULL;
+ } else if (!dcachePort.sendTiming(pkt)) {
+ _status = DcacheRetry;
+ dcache_pkt = pkt;
+ } else {
+ _status = DcacheWaitResponse;
+ // memory system takes ownership of packet
+ dcache_pkt = NULL;
+ }
+ return dcache_pkt == NULL;
+}
-template <class T>
-Fault
-TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
+void
+TimingSimpleCPU::sendData(Fault fault, RequestPtr req,
+ uint8_t *data, uint64_t *res, bool read)
{
- Request *req =
- new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
- cpuId, /* thread ID */ 0);
+ _status = Running;
+ if (fault != NoFault) {
+ delete data;
+ delete req;
- if (traceData) {
- traceData->setAddr(req->getVaddr());
+ translationFault(fault);
+ return;
}
+ PacketPtr pkt;
+ buildPacket(pkt, req, read);
+ pkt->dataDynamic<uint8_t>(data);
+ if (req->getFlags().isSet(Request::NO_ACCESS)) {
+ assert(!dcache_pkt);
+ pkt->makeResponse();
+ completeDataAccess(pkt);
+ } else if (read) {
+ handleReadPacket(pkt);
+ } else {
+ bool do_access = true; // flag to suppress cache access
- // translate to physical address
- Fault fault = thread->translateDataReadReq(req);
+ if (req->isLocked()) {
+ do_access = TheISA::handleLockedWrite(thread, req);
+ } else if (req->isCondSwap()) {
+ assert(res);
+ req->setExtraData(*res);
+ }
- // Now do the access.
- if (fault == NoFault) {
- PacketPtr pkt =
- new Packet(req,
- (req->isLocked() ?
- MemCmd::LoadLockedReq : MemCmd::ReadReq),
- Packet::Broadcast);
- pkt->dataDynamic<T>(new T);
-
- if (req->isMmapedIpr()) {
- Tick delay;
- delay = TheISA::handleIprRead(thread->getTC(), pkt);
- new IprEvent(pkt, this, nextCycle(curTick + delay));
- _status = DcacheWaitResponse;
- dcache_pkt = NULL;
- } else if (!dcachePort.sendTiming(pkt)) {
- _status = DcacheRetry;
+ if (do_access) {
dcache_pkt = pkt;
+ handleWritePacket();
} else {
_status = DcacheWaitResponse;
- // memory system takes ownership of packet
- dcache_pkt = NULL;
+ completeDataAccess(pkt);
}
+ }
+}
- // This will need a new way to tell if it has a dcache attached.
- if (req->isUncacheable())
- recordEvent("Uncached Read");
+void
+TimingSimpleCPU::sendSplitData(Fault fault1, Fault fault2,
+ RequestPtr req1, RequestPtr req2, RequestPtr req,
+ uint8_t *data, bool read)
+{
+ _status = Running;
+ if (fault1 != NoFault || fault2 != NoFault) {
+ delete data;
+ delete req1;
+ delete req2;
+ if (fault1 != NoFault)
+ translationFault(fault1);
+ else if (fault2 != NoFault)
+ translationFault(fault2);
+ return;
+ }
+ PacketPtr pkt1, pkt2;
+ buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read);
+ if (req->getFlags().isSet(Request::NO_ACCESS)) {
+ assert(!dcache_pkt);
+ pkt1->makeResponse();
+ completeDataAccess(pkt1);
+ } else if (read) {
+ 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 {
- delete req;
+ dcache_pkt = pkt1;
+ if (handleWritePacket()) {
+ SplitFragmentSenderState * send_state =
+ dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState);
+ send_state->clearFromParent();
+ dcache_pkt = pkt2;
+ if (handleWritePacket()) {
+ send_state = dynamic_cast<SplitFragmentSenderState *>(
+ pkt1->senderState);
+ send_state->clearFromParent();
+ }
+ }
+ }
+}
+
+void
+TimingSimpleCPU::translationFault(Fault fault)
+{
+ numCycles += tickToCycles(curTick - previousTick);
+ previousTick = curTick;
+
+ if (traceData) {
+ // Since there was a fault, we shouldn't trace this instruction.
+ delete traceData;
+ traceData = NULL;
}
- return fault;
+ postExecute();
+
+ if (getState() == SimObject::Draining) {
+ advancePC(fault);
+ completeDrain();
+ } else {
+ advanceInst(fault);
+ }
}
+void
+TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr req, bool read)
+{
+ MemCmd cmd;
+ 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);
+}
+
+void
+TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2,
+ RequestPtr req1, RequestPtr req2, RequestPtr req,
+ uint8_t *data, bool read)
+{
+ pkt1 = pkt2 = NULL;
+
+ assert(!req1->isMmapedIpr() && !req2->isMmapedIpr());
+
+ if (req->getFlags().isSet(Request::NO_ACCESS)) {
+ buildPacket(pkt1, req, read);
+ return;
+ }
+
+ buildPacket(pkt1, req1, read);
+ buildPacket(pkt2, req2, read);
+
+ 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);
+}
+
+template <class T>
Fault
-TimingSimpleCPU::translateDataReadAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags)
+TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
{
- Request *req =
- new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0);
+ Fault fault;
+ const int asid = 0;
+ const int thread_id = 0;
+ const Addr pc = thread->readPC();
+ int block_size = dcachePort.peerBlockSize();
+ int data_size = sizeof(T);
+
+ 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);
+
+
+ _status = DTBWaitResponse;
+ if (split_addr > addr) {
+ RequestPtr req1, req2;
+ assert(!req->isLocked() && !req->isSwap());
+ req->splitOnVaddr(split_addr, req1, req2);
+
+ typedef SplitDataTranslation::WholeTranslationState WholeState;
+ WholeState *state = new WholeState(req1, req2, req,
+ (uint8_t *)(new T), true);
+ thread->dtb->translateTiming(req1, tc,
+ new SplitDataTranslation(this, 0, state), false);
+ thread->dtb->translateTiming(req2, tc,
+ new SplitDataTranslation(this, 1, state), false);
+ } else {
+ thread->dtb->translateTiming(req, tc,
+ new DataTranslation(this, (uint8_t *)(new T), NULL, true),
+ false);
+ }
if (traceData) {
- traceData->setAddr(vaddr);
+ traceData->setData(data);
+ traceData->setAddr(addr);
}
- Fault fault = thread->translateDataWriteReq(req);
+ // This will need a new way to tell if it has a dcache attached.
+ if (req->isUncacheable())
+ recordEvent("Uncached Read");
- if (fault == NoFault)
- paddr = req->getPaddr();
-
- delete req;
- return fault;
+ return NoFault;
}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
@@ -369,92 +527,75 @@ TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
return read(addr, (uint32_t&)data, flags);
}
+bool
+TimingSimpleCPU::handleWritePacket()
+{
+ RequestPtr req = dcache_pkt->req;
+ if (req->isMmapedIpr()) {
+ Tick delay;
+ delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt);
+ new IprEvent(dcache_pkt, this, nextCycle(curTick + delay));
+ _status = DcacheWaitResponse;
+ dcache_pkt = NULL;
+ } else if (!dcachePort.sendTiming(dcache_pkt)) {
+ _status = DcacheRetry;
+ } else {
+ _status = DcacheWaitResponse;
+ // memory system takes ownership of packet
+ dcache_pkt = NULL;
+ }
+ return dcache_pkt == NULL;
+}
template <class T>
Fault
TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
{
- Request *req =
- new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
- cpuId, /* thread ID */ 0);
+ const int asid = 0;
+ const int thread_id = 0;
+ const Addr pc = thread->readPC();
+ int block_size = dcachePort.peerBlockSize();
+ int data_size = sizeof(T);
+
+ 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);
+
+ T *dataP = new T;
+ *dataP = TheISA::htog(data);
+ _status = DTBWaitResponse;
+ if (split_addr > addr) {
+ RequestPtr req1, req2;
+ assert(!req->isLocked() && !req->isSwap());
+ req->splitOnVaddr(split_addr, req1, req2);
+
+ typedef SplitDataTranslation::WholeTranslationState WholeState;
+ WholeState *state = new WholeState(req1, req2, req,
+ (uint8_t *)dataP, false);
+ thread->dtb->translateTiming(req1, tc,
+ new SplitDataTranslation(this, 0, state), true);
+ thread->dtb->translateTiming(req2, tc,
+ new SplitDataTranslation(this, 1, state), true);
+ } else {
+ thread->dtb->translateTiming(req, tc,
+ new DataTranslation(this, (uint8_t *)dataP, res, false),
+ true);
+ }
if (traceData) {
traceData->setAddr(req->getVaddr());
+ traceData->setData(data);
}
- // translate to physical address
- Fault fault = thread->translateDataWriteReq(req);
-
- // Now do the access.
- if (fault == NoFault) {
- MemCmd cmd = MemCmd::WriteReq; // default
- bool do_access = true; // flag to suppress cache access
-
- 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);
- }
- }
-
- // 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();
- dcache_pkt->set(data);
-
- if (do_access) {
- if (req->isMmapedIpr()) {
- Tick delay;
- dcache_pkt->set(htog(data));
- delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt);
- new IprEvent(dcache_pkt, this, nextCycle(curTick + delay));
- _status = DcacheWaitResponse;
- dcache_pkt = NULL;
- } else if (!dcachePort.sendTiming(dcache_pkt)) {
- _status = DcacheRetry;
- } else {
- _status = DcacheWaitResponse;
- // memory system takes ownership of packet
- dcache_pkt = NULL;
- }
- }
- // This will need a new way to tell if it's hooked up to a cache or not.
- if (req->isUncacheable())
- recordEvent("Uncached Write");
- } else {
- delete req;
- }
-
+ // This will need a new way to tell if it's hooked up to a cache or not.
+ if (req->isUncacheable())
+ recordEvent("Uncached Write");
// If the write needs to have a fault on the access, consider calling
// changeStatus() and changing it to "bad addr write" or something.
- return fault;
-}
-
-Fault
-TimingSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags)
-{
- Request *req =
- new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0);
-
- if (traceData) {
- traceData->setAddr(vaddr);
- }
-
- Fault fault = thread->translateDataWriteReq(req);
-
- if (fault == NoFault)
- paddr = req->getPaddr();
-
- delete req;
- return fault;
+ return NoFault;
}
@@ -524,14 +665,31 @@ TimingSimpleCPU::fetch()
checkPcEventQueue();
- Request *ifetch_req = new Request();
- ifetch_req->setThreadContext(cpuId, /* thread ID */ 0);
- Fault fault = setupFetchRequest(ifetch_req);
+ bool fromRom = isRomMicroPC(thread->readMicroPC());
- ifetch_pkt = new Packet(ifetch_req, MemCmd::ReadReq, Packet::Broadcast);
- ifetch_pkt->dataStatic(&inst);
+ if (!fromRom && !curMacroStaticInst) {
+ Request *ifetch_req = new Request();
+ ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0);
+ setupFetchRequest(ifetch_req);
+ thread->itb->translateTiming(ifetch_req, tc,
+ &fetchTranslation);
+ } else {
+ _status = IcacheWaitResponse;
+ completeIfetch(NULL);
+ numCycles += tickToCycles(curTick - previousTick);
+ previousTick = curTick;
+ }
+}
+
+
+void
+TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc)
+{
if (fault == NoFault) {
+ ifetch_pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast);
+ ifetch_pkt->dataStatic(&inst);
+
if (!icachePort.sendTiming(ifetch_pkt)) {
// Need to wait for retry
_status = IcacheRetry;
@@ -542,8 +700,7 @@ TimingSimpleCPU::fetch()
ifetch_pkt = NULL;
}
} else {
- delete ifetch_req;
- delete ifetch_pkt;
+ delete req;
// fetch fault: advance directly to next instruction (fault handler)
advanceInst(fault);
}
@@ -556,7 +713,8 @@ TimingSimpleCPU::fetch()
void
TimingSimpleCPU::advanceInst(Fault fault)
{
- advancePC(fault);
+ if (fault != NoFault || !stayAtPC)
+ advancePC(fault);
if (_status == Running) {
// kick off fetch of next instruction... callback from icache
@@ -574,7 +732,8 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt)
// received a response from the icache: execute the received
// instruction
- assert(!pkt->isError());
+
+ assert(!pkt || !pkt->isError());
assert(_status == IcacheWaitResponse);
_status = Running;
@@ -583,41 +742,27 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt)
previousTick = curTick;
if (getState() == SimObject::Draining) {
- delete pkt->req;
- delete pkt;
+ if (pkt) {
+ delete pkt->req;
+ delete pkt;
+ }
completeDrain();
return;
}
preExecute();
- if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) {
+ if (curStaticInst &&
+ curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) {
// load or store: just send to dcache
Fault fault = curStaticInst->initiateAcc(this, traceData);
if (_status != Running) {
// instruction will complete in dcache response callback
- assert(_status == DcacheWaitResponse || _status == DcacheRetry);
+ assert(_status == DcacheWaitResponse ||
+ _status == DcacheRetry || DTBWaitResponse);
assert(fault == NoFault);
} else {
- if (fault == NoFault) {
- // Note that ARM can have NULL packets if the instruction gets
- // squashed due to predication
- // early fail on store conditional: complete now
- assert(dcache_pkt != NULL || THE_ISA == ARM_ISA);
-
- fault = curStaticInst->completeAcc(dcache_pkt, this,
- traceData);
- if (dcache_pkt != NULL)
- {
- delete dcache_pkt->req;
- delete dcache_pkt;
- dcache_pkt = NULL;
- }
-
- // keep an instruction count
- if (fault == NoFault)
- countInst();
- } else if (traceData) {
+ if (fault != NoFault && traceData) {
// If there was a fault, we shouldn't trace this instruction.
delete traceData;
traceData = NULL;
@@ -630,7 +775,7 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt)
instCnt++;
advanceInst(fault);
}
- } else {
+ } else if (curStaticInst) {
// non-memory instruction: execute completely now
Fault fault = curStaticInst->execute(this, traceData);
@@ -649,10 +794,14 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt)
curStaticInst->isFirstMicroop()))
instCnt++;
advanceInst(fault);
+ } else {
+ advanceInst(NoFault);
}
- delete pkt->req;
- delete pkt;
+ if (pkt) {
+ delete pkt->req;
+ delete pkt;
+ }
}
void
@@ -707,12 +856,38 @@ TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
// received a response from the dcache: complete the load or store
// instruction
assert(!pkt->isError());
- assert(_status == DcacheWaitResponse);
- _status = Running;
numCycles += tickToCycles(curTick - previousTick);
previousTick = curTick;
+ if (pkt->senderState) {
+ SplitFragmentSenderState * send_state =
+ dynamic_cast<SplitFragmentSenderState *>(pkt->senderState);
+ assert(send_state);
+ delete pkt->req;
+ delete pkt;
+ PacketPtr big_pkt = send_state->bigPkt;
+ delete send_state;
+
+ SplitMainSenderState * main_send_state =
+ dynamic_cast<SplitMainSenderState *>(big_pkt->senderState);
+ assert(main_send_state);
+ // Record the fact that this packet is no longer outstanding.
+ assert(main_send_state->outstanding != 0);
+ main_send_state->outstanding--;
+
+ if (main_send_state->outstanding) {
+ return;
+ } else {
+ delete main_send_state;
+ big_pkt->senderState = NULL;
+ pkt = big_pkt;
+ }
+ }
+
+ assert(_status == DcacheWaitResponse || _status == DTBWaitResponse);
+ _status = Running;
+
Fault fault = curStaticInst->completeAcc(pkt, this, traceData);
// keep an instruction count
@@ -724,7 +899,9 @@ TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
traceData = NULL;
}
- if (pkt->isRead() && pkt->isLocked()) {
+ // the locked flag may be cleared on the response packet, so check
+ // pkt->req and not pkt to see if it was a load-locked
+ if (pkt->isRead() && pkt->req->isLocked()) {
TheISA::handleLockedRead(thread, pkt->req);
}
@@ -760,7 +937,7 @@ TimingSimpleCPU::DcachePort::setPeer(Port *port)
#if FULL_SYSTEM
// Update the ThreadContext's memory ports (Functional/Virtual
// Ports)
- cpu->tcBase()->connectMemPorts();
+ cpu->tcBase()->connectMemPorts(cpu->tcBase());
#endif
}
@@ -771,10 +948,11 @@ TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
// delay processing of returned data until next CPU clock edge
Tick next_tick = cpu->nextCycle(curTick);
- if (next_tick == curTick)
+ if (next_tick == curTick) {
cpu->completeDataAccess(pkt);
- else
+ } else {
tickEvent.schedule(pkt, next_tick);
+ }
return true;
}
@@ -804,17 +982,47 @@ TimingSimpleCPU::DcachePort::recvRetry()
assert(cpu->dcache_pkt != NULL);
assert(cpu->_status == DcacheRetry);
PacketPtr tmp = cpu->dcache_pkt;
- if (sendTiming(tmp)) {
+ if (tmp->senderState) {
+ // This is a packet from a split access.
+ SplitFragmentSenderState * send_state =
+ dynamic_cast<SplitFragmentSenderState *>(tmp->senderState);
+ assert(send_state);
+ PacketPtr big_pkt = send_state->bigPkt;
+
+ SplitMainSenderState * main_send_state =
+ dynamic_cast<SplitMainSenderState *>(big_pkt->senderState);
+ assert(main_send_state);
+
+ if (sendTiming(tmp)) {
+ // If we were able to send without retrying, record that fact
+ // and try sending the other fragment.
+ send_state->clearFromParent();
+ int other_index = main_send_state->getPendingFragment();
+ if (other_index > 0) {
+ tmp = main_send_state->fragments[other_index];
+ cpu->dcache_pkt = tmp;
+ if ((big_pkt->isRead() && cpu->handleReadPacket(tmp)) ||
+ (big_pkt->isWrite() && cpu->handleWritePacket())) {
+ main_send_state->fragments[other_index] = NULL;
+ }
+ } else {
+ cpu->_status = DcacheWaitResponse;
+ // memory system takes ownership of packet
+ cpu->dcache_pkt = NULL;
+ }
+ }
+ } else if (sendTiming(tmp)) {
cpu->_status = DcacheWaitResponse;
// memory system takes ownership of packet
cpu->dcache_pkt = NULL;
}
}
-TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, Tick t)
- : Event(&mainEventQueue), pkt(_pkt), cpu(_cpu)
+TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu,
+ Tick t)
+ : pkt(_pkt), cpu(_cpu)
{
- schedule(t);
+ cpu->schedule(this, t);
}
void
@@ -844,36 +1052,10 @@ TimingSimpleCPU::printAddr(Addr a)
TimingSimpleCPU *
TimingSimpleCPUParams::create()
{
- TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params();
- params->name = name;
- params->numberOfThreads = 1;
- params->max_insts_any_thread = max_insts_any_thread;
- params->max_insts_all_threads = max_insts_all_threads;
- params->max_loads_any_thread = max_loads_any_thread;
- params->max_loads_all_threads = max_loads_all_threads;
- params->progress_interval = progress_interval;
- params->deferRegistration = defer_registration;
- params->clock = clock;
- params->phase = phase;
- params->functionTrace = function_trace;
- params->functionTraceStart = function_trace_start;
- params->system = system;
- params->cpu_id = cpu_id;
- params->tracer = tracer;
-
- params->itb = itb;
- params->dtb = dtb;
-#if FULL_SYSTEM
- params->profile = profile;
- params->do_quiesce = do_quiesce;
- params->do_checkpoint_insts = do_checkpoint_insts;
- params->do_statistics_insts = do_statistics_insts;
-#else
+ numThreads = 1;
+#if !FULL_SYSTEM
if (workload.size() != 1)
panic("only one workload allowed");
- params->process = workload[0];
#endif
-
- TimingSimpleCPU *cpu = new TimingSimpleCPU(params);
- return cpu;
+ return new TimingSimpleCPU(this);
}