* Authors: Kevin Lim
*/
-#include "arch/isa_traits.hh"
+#include "arch/faults.hh"
#include "base/str.hh"
+#include "config/the_isa.hh"
+#include "config/use_checker.hh"
#include "cpu/ozone/lw_lsq.hh"
#include "cpu/checker/cpu.hh"
-template <class Impl>
-OzoneLWLSQ<Impl>::StoreCompletionEvent::StoreCompletionEvent(DynInstPtr &_inst,
- BackEnd *_be,
- Event *wb_event,
- OzoneLWLSQ<Impl> *lsq_ptr)
- : Event(&mainEventQueue),
- inst(_inst),
- be(_be),
- wbEvent(wb_event),
- miss(false),
- lsqPtr(lsq_ptr)
+template<class Impl>
+OzoneLWLSQ<Impl>::WritebackEvent::WritebackEvent(DynInstPtr &_inst, PacketPtr _pkt,
+ OzoneLWLSQ *lsq_ptr)
+ : Event(&mainEventQueue), inst(_inst), pkt(_pkt), lsqPtr(lsq_ptr)
{
this->setFlags(Event::AutoDelete);
}
-template <class Impl>
+template<class Impl>
void
-OzoneLWLSQ<Impl>::StoreCompletionEvent::process()
+OzoneLWLSQ<Impl>::WritebackEvent::process()
{
- DPRINTF(OzoneLSQ, "Cache miss complete for store [sn:%lli]\n",
- inst->seqNum);
+ if (!lsqPtr->isSwitchedOut()) {
+ lsqPtr->writeback(inst, pkt);
+ }
+ delete pkt;
+}
- //lsqPtr->removeMSHR(lsqPtr->storeQueue[storeIdx].inst->seqNum);
+template<class Impl>
+const char *
+OzoneLWLSQ<Impl>::WritebackEvent::description() const
+{
+ return "Store writeback";
+}
-// lsqPtr->cpu->wakeCPU();
- if (lsqPtr->isSwitchedOut()) {
- if (wbEvent)
- delete wbEvent;
+template <class Impl>
+Tick
+OzoneLWLSQ<Impl>::DcachePort::recvAtomic(PacketPtr pkt)
+{
+ panic("O3CPU model does not work with atomic mode!");
+ return curTick;
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::DcachePort::recvFunctional(PacketPtr pkt)
+{
+ warn("O3CPU doesn't update things on a recvFunctional");
+}
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::DcachePort::recvStatusChange(Status status)
+{
+ if (status == RangeChange)
return;
- }
- if (wbEvent) {
- wbEvent->process();
- delete wbEvent;
- }
+ panic("O3CPU doesn't expect recvStatusChange callback!");
+}
- lsqPtr->completeStore(inst->sqIdx);
- if (miss)
- be->removeDcacheMiss(inst);
+template <class Impl>
+bool
+OzoneLWLSQ<Impl>::DcachePort::recvTiming(PacketPtr pkt)
+{
+ lsq->completeDataAccess(pkt);
+ return true;
}
template <class Impl>
-const char *
-OzoneLWLSQ<Impl>::StoreCompletionEvent::description()
+void
+OzoneLWLSQ<Impl>::DcachePort::recvRetry()
+{
+ lsq->recvRetry();
+}
+
+template<class Impl>
+void
+OzoneLWLSQ<Impl>::completeDataAccess(PacketPtr pkt)
{
- return "LSQ store completion event";
+ LSQSenderState *state = dynamic_cast<LSQSenderState *>(pkt->senderState);
+ DynInstPtr inst = state->inst;
+ DPRINTF(IEW, "Writeback event [sn:%lli]\n", inst->seqNum);
+ DPRINTF(Activity, "Activity: Writeback event [sn:%lli]\n", inst->seqNum);
+
+ //iewStage->ldstQueue.removeMSHR(inst->threadNumber,inst->seqNum);
+
+ if (isSwitchedOut() || inst->isSquashed()) {
+ delete state;
+ delete pkt;
+ return;
+ } else {
+ if (!state->noWB) {
+ writeback(inst, pkt);
+ }
+
+ if (inst->isStore()) {
+ completeStore(inst);
+ }
+ }
+
+ delete state;
+ delete pkt;
}
template <class Impl>
OzoneLWLSQ<Impl>::OzoneLWLSQ()
- : loads(0), stores(0), storesToWB(0), stalled(false), isLoadBlocked(false),
- loadBlockedHandled(false)
+ : switchedOut(false), dcachePort(this), loads(0), stores(0),
+ storesToWB(0), storesInFlight(0), stalled(false), isStoreBlocked(false),
+ isLoadBlocked(false), loadBlockedHandled(false)
{
}
usedPorts = 0;
cachePorts = params->cachePorts;
- dcacheInterface = params->dcacheInterface;
-
loadFaultInst = storeFaultInst = memDepViolator = NULL;
blockedLoadSeqNum = 0;
return "lsqunit";
}
+template<class Impl>
+void
+OzoneLWLSQ<Impl>::regStats()
+{
+ lsqMemOrderViolation
+ .name(name() + ".memOrderViolation")
+ .desc("Number of memory ordering violations");
+}
+
+template<class Impl>
+void
+OzoneLWLSQ<Impl>::setCPU(OzoneCPU *cpu_ptr)
+{
+ cpu = cpu_ptr;
+ dcachePort.setName(this->name() + "-dport");
+
+#if USE_CHECKER
+ if (cpu->checker) {
+ cpu->checker->setDcachePort(&dcachePort);
+ }
+#endif
+}
+
template<class Impl>
void
OzoneLWLSQ<Impl>::clearLQ()
OzoneLWLSQ<Impl>::numFreeEntries()
{
unsigned free_lq_entries = LQEntries - loads;
- unsigned free_sq_entries = SQEntries - stores;
+ unsigned free_sq_entries = SQEntries - (stores + storesInFlight);
// Both the LQ and SQ entries have an extra dummy entry to differentiate
// empty/full conditions. Subtract 1 from the free entries.
// Actually probably want the oldest faulting load
if (load_fault != NoFault) {
DPRINTF(OzoneLSQ, "Load [sn:%lli] has a fault\n", inst->seqNum);
+ if (!(inst->req->isUncacheable() && !inst->isAtCommit())) {
+ inst->setExecuted();
+ }
// Maybe just set it as can commit here, although that might cause
// some other problems with sending traps to the ROB too quickly.
be->instToCommit(inst);
// A load incorrectly passed this store. Squash and refetch.
// For now return a fault to show that it was unsuccessful.
memDepViolator = (*lq_it);
+ ++lsqMemOrderViolation;
return TheISA::genMachineCheckFault();
}
(*sq_it).canWB &&
usedPorts < cachePorts) {
+ if (isStoreBlocked) {
+ DPRINTF(OzoneLSQ, "Unable to write back any more stores, cache"
+ " is blocked!\n");
+ break;
+ }
+
DynInstPtr inst = (*sq_it).inst;
if ((*sq_it).size == 0 && !(*sq_it).completed) {
sq_it--;
- completeStore(inst->sqIdx);
-
+ removeStore(inst->sqIdx);
+ completeStore(inst);
continue;
}
continue;
}
- if (dcacheInterface && dcacheInterface->isBlocked()) {
- DPRINTF(OzoneLSQ, "Unable to write back any more stores, cache"
- " is blocked!\n");
- break;
- }
-
++usedPorts;
assert((*sq_it).req);
assert(!(*sq_it).committed);
+ Request *req = (*sq_it).req;
(*sq_it).committed = true;
- MemReqPtr req = (*sq_it).req;
+ assert(!inst->memData);
+ inst->memData = new uint8_t[64];
+ memcpy(inst->memData, (uint8_t *)&(*sq_it).data,
+ req->getSize());
- req->cmd = Write;
- req->completionEvent = NULL;
- req->time = curTick;
+ MemCmd command =
+ req->isSwap() ? MemCmd::SwapReq :
+ (req->isLLSC() ? MemCmd::WriteReq : MemCmd::StoreCondReq);
+ PacketPtr data_pkt = new Packet(req, command, Packet::Broadcast);
+ data_pkt->dataStatic(inst->memData);
- switch((*sq_it).size) {
- case 1:
- cpu->write(req, (uint8_t &)(*sq_it).data);
- break;
- case 2:
- cpu->write(req, (uint16_t &)(*sq_it).data);
- break;
- case 4:
- cpu->write(req, (uint32_t &)(*sq_it).data);
- break;
- case 8:
- cpu->write(req, (uint64_t &)(*sq_it).data);
- break;
- default:
- panic("Unexpected store size!\n");
- }
- if (!(req->flags & LOCKED)) {
- (*sq_it).inst->setCompleted();
- if (cpu->checker) {
- cpu->checker->tick((*sq_it).inst);
+ LSQSenderState *state = new LSQSenderState;
+ state->isLoad = false;
+ state->idx = inst->sqIdx;
+ state->inst = inst;
+ data_pkt->senderState = state;
+
+ DPRINTF(OzoneLSQ, "D-Cache: Writing back store PC:%#x "
+ "to Addr:%#x, data:%#x [sn:%lli]\n",
+ (*sq_it).inst->readPC(),
+ req->getPaddr(), *(inst->memData),
+ inst->seqNum);
+
+ // @todo: Remove this SC hack once the memory system handles it.
+ if (req->isLLSC()) {
+ if (req->isUncacheable()) {
+ req->setExtraData(2);
+ } else {
+ if (cpu->lockFlag) {
+ req->setExtraData(1);
+ } else {
+ req->setExtraData(0);
+ // Hack: Instantly complete this store.
+ completeDataAccess(data_pkt);
+ --sq_it;
+ continue;
+ }
}
+ } else {
+ // Non-store conditionals do not need a writeback.
+ state->noWB = true;
}
+ if (!dcachePort.sendTiming(data_pkt)) {
+ // Need to handle becoming blocked on a store.
+ isStoreBlocked = true;
+ assert(retryPkt == NULL);
+ retryPkt = data_pkt;
+ } else {
+ storePostSend(data_pkt, inst);
+ --sq_it;
+ }
+/*
DPRINTF(OzoneLSQ, "D-Cache: Writing back store idx:%i PC:%#x "
"to Addr:%#x, data:%#x [sn:%lli]\n",
inst->sqIdx,inst->readPC(),
req->paddr, *(req->data),
inst->seqNum);
+ DPRINTF(OzoneLSQ, "StoresInFlight: %i\n",
+ storesInFlight + 1);
if (dcacheInterface) {
assert(!req->completionEvent);
if (result != MA_HIT && dcacheInterface->doEvents()) {
store_event->miss = true;
typename BackEnd::LdWritebackEvent *wb = NULL;
- if (req->flags & LOCKED) {
+ if (req->isLLSC()) {
wb = new typename BackEnd::LdWritebackEvent(inst,
be);
store_event->wbEvent = wb;
// DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n",
// inst->seqNum);
- if (req->flags & LOCKED) {
+ if (req->isLLSC()) {
// Stx_C does not generate a system port
// transaction in the 21264, but that might be
// hard to accomplish in this model.
}
sq_it--;
}
+ ++storesInFlight;
+// removeStore(inst->sqIdx);
} else {
panic("Must HAVE DCACHE!!!!!\n");
}
+*/
}
// Not sure this should set it to 0.
OzoneLWLSQ<Impl>::squash(const InstSeqNum &squashed_num)
{
DPRINTF(OzoneLSQ, "Squashing until [sn:%lli]!"
- "(Loads:%i Stores:%i)\n",squashed_num,loads,stores);
+ "(Loads:%i Stores:%i)\n",squashed_num,loads,stores+storesInFlight);
LQIt lq_it = loadQueue.begin();
SQIndices.push((*sq_it).inst->sqIdx);
(*sq_it).inst = NULL;
(*sq_it).canWB = 0;
-
- if ((*sq_it).req) {
- assert(!(*sq_it).req->completionEvent);
- }
(*sq_it).req = NULL;
--stores;
storeQueue.erase(sq_it++);
template <class Impl>
void
-OzoneLWLSQ<Impl>::completeStore(int store_idx)
+OzoneLWLSQ<Impl>::storePostSend(PacketPtr pkt, DynInstPtr &inst)
+{
+ if (isStalled() &&
+ inst->seqNum == stallingStoreIsn) {
+ DPRINTF(OzoneLSQ, "Unstalling, stalling store [sn:%lli] "
+ "load [sn:%lli]\n",
+ stallingStoreIsn, (*stallingLoad)->seqNum);
+ stalled = false;
+ stallingStoreIsn = 0;
+ be->replayMemInst((*stallingLoad));
+ }
+
+ if (!inst->isStoreConditional()) {
+ // The store is basically completed at this time. This
+ // only works so long as the checker doesn't try to
+ // verify the value in memory for stores.
+ inst->setCompleted();
+#if USE_CHECKER
+ if (cpu->checker) {
+ cpu->checker->verify(inst);
+ }
+#endif
+ }
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::writeback(DynInstPtr &inst, PacketPtr pkt)
+{
+ // Squashed instructions do not need to complete their access.
+ if (inst->isSquashed()) {
+ assert(!inst->isStore());
+ return;
+ }
+
+ if (!inst->isExecuted()) {
+ inst->setExecuted();
+
+ // Complete access to copy data to proper place.
+ inst->completeAcc(pkt);
+ }
+
+ // Need to insert instruction into queue to commit
+ be->instToCommit(inst);
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::removeStore(int store_idx)
{
SQHashIt sq_hash_it = SQItHash.find(store_idx);
assert(sq_hash_it != SQItHash.end());
(*sq_it).completed = true;
DynInstPtr inst = (*sq_it).inst;
- --storesToWB;
-
if (isStalled() &&
inst->seqNum == stallingStoreIsn) {
DPRINTF(OzoneLSQ, "Unstalling, stalling store [sn:%lli] "
SQItHash.erase(sq_hash_it);
SQIndices.push(inst->sqIdx);
storeQueue.erase(sq_it);
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::completeStore(DynInstPtr &inst)
+{
+ --storesToWB;
--stores;
inst->setCompleted();
+#if USE_CHECKER
if (cpu->checker) {
- cpu->checker->tick(inst);
+ cpu->checker->verify(inst);
}
+#endif
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::recvRetry()
+{
+ panic("Unimplemented!");
}
template <class Impl>
{
assert(storesToWB == 0);
switchedOut = true;
- SQIt sq_it = --(storeQueue.end());
- while (storesToWB > 0 &&
- sq_it != storeQueue.end() &&
- (*sq_it).inst &&
- (*sq_it).canWB) {
-
- DynInstPtr inst = (*sq_it).inst;
-
- if ((*sq_it).size == 0 && !(*sq_it).completed) {
- sq_it--;
- continue;
- }
-
- // Store conditionals don't complete until *after* they have written
- // back. If it's here and not yet sent to memory, then don't bother
- // as it's not part of committed state.
- if (inst->isDataPrefetch() || (*sq_it).committed) {
- sq_it--;
- continue;
- } else if ((*sq_it).req->flags & LOCKED) {
- sq_it--;
- assert(!(*sq_it).canWB ||
- ((*sq_it).canWB && (*sq_it).req->flags & LOCKED));
- continue;
- }
-
- assert((*sq_it).req);
- assert(!(*sq_it).committed);
-
- MemReqPtr req = (*sq_it).req;
- (*sq_it).committed = true;
-
- req->cmd = Write;
- req->completionEvent = NULL;
- req->time = curTick;
- assert(!req->data);
- req->data = new uint8_t[64];
- memcpy(req->data, (uint8_t *)&(*sq_it).data, req->size);
-
- DPRINTF(OzoneLSQ, "Switching out : Writing back store idx:%i PC:%#x "
- "to Addr:%#x, data:%#x directly to memory [sn:%lli]\n",
- inst->sqIdx,inst->readPC(),
- req->paddr, *(req->data),
- inst->seqNum);
-
- switch((*sq_it).size) {
- case 1:
- cpu->write(req, (uint8_t &)(*sq_it).data);
- break;
- case 2:
- cpu->write(req, (uint16_t &)(*sq_it).data);
- break;
- case 4:
- cpu->write(req, (uint32_t &)(*sq_it).data);
- break;
- case 8:
- cpu->write(req, (uint64_t &)(*sq_it).data);
- break;
- default:
- panic("Unexpected store size!\n");
- }
- }
// Clear the queue to free up resources
+ assert(stores == 0);
+ assert(storeQueue.empty());
+ assert(loads == 0);
+ assert(loadQueue.empty());
+ assert(storesInFlight == 0);
storeQueue.clear();
loadQueue.clear();
- loads = stores = storesToWB = 0;
+ loads = stores = storesToWB = storesInFlight = 0;
}
template <class Impl>