#include "cpu/pc_event.hh"
#include "cpu/static_inst.hh"
#include "mem/mem_interface.hh"
-#include "mem/page_table.hh"
#include "sim/eventq.hh"
// forward declarations
#else
-class PageTable;
class Process;
#endif // FULL_SYSTEM
// L1 data cache
MemInterface *dcacheInterface;
-#if !FULL_SYSTEM
- PageTable *pTable;
-#endif
+ /** Pointer to memory. */
+ FunctionalMemory *mem;
FrontEnd *frontEnd;
int getInstAsid() { return thread.asid; }
int getDataAsid() { return thread.asid; }
+ Fault dummyTranslation(MemReqPtr &req)
+ {
+#if 0
+ assert((req->vaddr >> 48 & 0xffff) == 0);
+#endif
+
+ // put the asid in the upper 16 bits of the paddr
+ req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16);
+ req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16;
+ return NoFault;
+ }
+
/** Translates instruction requestion in syscall emulation mode. */
Fault translateInstReq(MemReqPtr &req)
{
- return this->pTable->translate(req);
+ return dummyTranslation(req);
}
/** Translates data read request in syscall emulation mode. */
Fault translateDataReadReq(MemReqPtr &req)
{
- return this->pTable->translate(req);
+ return dummyTranslation(req);
}
/** Translates data write request in syscall emulation mode. */
Fault translateDataWriteReq(MemReqPtr &req)
{
- return this->pTable->translate(req);
+ return dummyTranslation(req);
}
#endif
+
+ /** Old CPU read from memory function. No longer used. */
+ template <class T>
+ Fault read(MemReqPtr &req, T &data)
+ {
+// panic("CPU READ NOT IMPLEMENTED W/NEW MEMORY\n");
+#if 0
+#if FULL_SYSTEM && defined(TARGET_ALPHA)
+ if (req->flags & LOCKED) {
+ req->xc->setMiscReg(TheISA::Lock_Addr_DepTag, req->paddr);
+ req->xc->setMiscReg(TheISA::Lock_Flag_DepTag, true);
+ }
+#endif
+#endif
+ Fault error;
+ if (req->flags & LOCKED) {
+// lockAddr = req->paddr;
+ lockFlag = true;
+ }
+
+ error = this->mem->read(req, data);
+ data = gtoh(data);
+ return error;
+ }
+
+
/** CPU read function, forwards read to LSQ. */
template <class T>
Fault read(MemReqPtr &req, T &data, int load_idx)
return backEnd->read(req, data, load_idx);
}
+ /** Old CPU write to memory function. No longer used. */
+ template <class T>
+ Fault write(MemReqPtr &req, T &data)
+ {
+#if 0
+#if FULL_SYSTEM && defined(TARGET_ALPHA)
+ ExecContext *xc;
+
+ // If this is a store conditional, act appropriately
+ if (req->flags & LOCKED) {
+ xc = req->xc;
+
+ if (req->flags & UNCACHEABLE) {
+ // Don't update result register (see stq_c in isa_desc)
+ req->result = 2;
+ xc->setStCondFailures(0);//Needed? [RGD]
+ } else {
+ bool lock_flag = xc->readMiscReg(TheISA::Lock_Flag_DepTag);
+ Addr lock_addr = xc->readMiscReg(TheISA::Lock_Addr_DepTag);
+ req->result = lock_flag;
+ if (!lock_flag ||
+ ((lock_addr & ~0xf) != (req->paddr & ~0xf))) {
+ xc->setMiscReg(TheISA::Lock_Flag_DepTag, false);
+ xc->setStCondFailures(xc->readStCondFailures() + 1);
+ if (((xc->readStCondFailures()) % 100000) == 0) {
+ std::cerr << "Warning: "
+ << xc->readStCondFailures()
+ << " consecutive store conditional failures "
+ << "on cpu " << req->xc->readCpuId()
+ << std::endl;
+ }
+ return NoFault;
+ }
+ else xc->setStCondFailures(0);
+ }
+ }
+
+ // Need to clear any locked flags on other proccessors for
+ // this address. Only do this for succsful Store Conditionals
+ // and all other stores (WH64?). Unsuccessful Store
+ // Conditionals would have returned above, and wouldn't fall
+ // through.
+ for (int i = 0; i < this->system->execContexts.size(); i++){
+ xc = this->system->execContexts[i];
+ if ((xc->readMiscReg(TheISA::Lock_Addr_DepTag) & ~0xf) ==
+ (req->paddr & ~0xf)) {
+ xc->setMiscReg(TheISA::Lock_Flag_DepTag, false);
+ }
+ }
+
+#endif
+#endif
+
+ if (req->flags & LOCKED) {
+ if (req->flags & UNCACHEABLE) {
+ req->result = 2;
+ } else {
+ if (this->lockFlag/* && this->lockAddr == req->paddr*/) {
+ req->result = 1;
+ } else {
+ req->result = 0;
+ return NoFault;
+ }
+ }
+ }
+
+ return this->mem->write(req, (T)htog(data));
+ }
+
/** CPU write function, forwards write to LSQ. */
template <class T>
Fault write(MemReqPtr &req, T &data, int store_idx)
bool stall;
};
TimeBuffer<CommStruct> comm;
+
+ bool lockFlag;
};
#endif // __CPU_OZONE_CPU_HH__
template <class Impl>
OzoneCPU<Impl>::OzoneCPU(Params *p)
#if FULL_SYSTEM
- : BaseCPU(p), thread(this, 0, p->mem), tickEvent(this, p->width),
+ : BaseCPU(p), thread(this, 0, p->mem), tickEvent(this, p->width), mem(p->mem),
#else
: BaseCPU(p), thread(this, 0, p->workload[0], 0), tickEvent(this, p->width),
+ mem(p->workload[0]->getMemory()),
#endif
comm(5, 5)
{
+
frontEnd = new FrontEnd(p);
backEnd = new BackEnd(p);
globalSeqNum = 1;
checkInterrupts = false;
-/*
- fetchRedirBranch = true;
- fetchRedirExcp = true;
-
- // Need to initialize the rename maps, and the head and tail pointers.
- robHeadPtr = new DynInst(this);
- robTailPtr = new DynInst(this);
-
- robHeadPtr->setNextInst(robTailPtr);
-// robHeadPtr->setPrevInst(NULL);
-// robTailPtr->setNextInst(NULL);
- robTailPtr->setPrevInst(robHeadPtr);
-
- robHeadPtr->setCompleted();
- robTailPtr->setCompleted();
-
- for (int i = 0; i < ISA::TotalNumRegs; ++i) {
- renameTable[i] = new DynInst(this);
- commitTable[i] = new DynInst(this);
- renameTable[i]->setCompleted();
- commitTable[i]->setCompleted();
- }
-
-#if FULL_SYSTEM
- for (int i = 0; i < ISA::NumIntRegs; ++i) {
- palShadowTable[i] = new DynInst(this);
- palShadowTable[i]->setCompleted();
- }
-#endif
-
- // Size of cache block.
- cacheBlkSize = icacheInterface ? icacheInterface->getBlockSize() : 64;
-
- // Create mask to get rid of offset bits.
- cacheBlkMask = (cacheBlkSize - 1);
-
- // Get the size of an instruction.
- instSize = sizeof(MachInst);
-
- // Create space to store a cache line.
- cacheData = new uint8_t[cacheBlkSize];
-
- cacheBlkValid = false;
-*/
for (int i = 0; i < TheISA::TotalNumRegs; ++i) {
thread.renameTable[i] = new DynInst(this);
thread.renameTable[i]->setCompleted();
backEnd->renameTable.copyFrom(thread.renameTable);
#if !FULL_SYSTEM
- pTable = p->pTable;
+// pTable = p->pTable;
#endif
+ lockFlag = 0;
+
DPRINTF(OzoneCPU, "OzoneCPU: Created Ozone cpu object.\n");
}
scheduleTickEvent(delay);
_status = Running;
thread._status = ExecContext::Active;
+ frontEnd->wakeFromQuiesce();
}
template <class Impl>
// Eventually change this in SMT.
assert(thread_num == 0);
// assert(xcProxy);
-
- assert(_status == Running);
+ // @todo: Figure out how to initially set the status properly so this is running.
+// assert(_status == Running);
notIdleFraction--;
unscheduleTickEvent();
_status = Idle;
{
DPRINTF(OzoneCPU, "\n\nOzoneCPU: Ticking cpu.\n");
+ _status = Running;
thread.renameTable[ZeroReg]->setIntResult(0);
thread.renameTable[ZeroReg+TheISA::FP_Base_DepTag]->
setDoubleResult(0.0);
// check for instruction-count-based events
comInstEventQueue[0]->serviceEvents(numInst);
- if (!tickEvent.scheduled())
+ if (!tickEvent.scheduled() && _status == Running)
tickEvent.schedule(curTick + 1);
}
thread.setNextPC(thread.readMiscReg(AlphaISA::IPR_EXC_ADDR));
+ lockFlag = false;
+
// Not sure how to make a similar check in the Ozone model
// if (!misspeculating()) {
kernelStats->hwrei();
this->cpu->kernelStats->hwrei();
this->cpu->checkInterrupts = true;
+ this->cpu->lockFlag = false;
// FIXME: XXX check for interrupts? XXX
return NoFault;
const bool is_branch = false, const bool branch_taken = false);
DynInstPtr getInst();
- void processCacheCompletion();
+ void processCacheCompletion(MemReqPtr &req);
void addFreeRegs(int num_freed);
SerializeBlocked,
SerializeComplete,
RenameBlocked,
+ QuiescePending,
BEBlocked
};
class ICacheCompletionEvent : public Event
{
private:
+ MemReqPtr req;
FrontEnd *frontEnd;
public:
- ICacheCompletionEvent(FrontEnd *_fe);
+ ICacheCompletionEvent(MemReqPtr &_req, FrontEnd *_fe);
virtual void process();
virtual const char *description();
};
- ICacheCompletionEvent cacheCompletionEvent;
-
MemInterface *icacheInterface;
#if !FULL_SYSTEM
void setPC(Addr val) { PC = val; }
void setNextPC(Addr val) { nextPC = val; }
+ void wakeFromQuiesce();
+
void dumpInsts();
private:
+#include "arch/faults.hh"
#include "arch/isa_traits.hh"
#include "base/statistics.hh"
#include "cpu/exec_context.hh"
template <class Impl>
FrontEnd<Impl>::FrontEnd(Params *params)
: branchPred(params),
- cacheCompletionEvent(this),
icacheInterface(params->icacheInterface),
instBufferSize(0),
maxInstBufferSize(params->maxInstBufferSize),
// Setup branch predictor.
// Setup Memory Request
+/*
memReq = new MemReq();
memReq->asid = 0;
memReq->data = new uint8_t[64];
-
+*/
+ memReq = NULL;
// Size of cache block.
cacheBlkSize = icacheInterface ? icacheInterface->getBlockSize() : 64;
cacheBlkValid = false;
#if !FULL_SYSTEM
- pTable = params->pTable;
+// pTable = params->pTable;
#endif
fetchFault = NoFault;
}
FrontEnd<Impl>::setXC(ExecContext *xc_ptr)
{
xc = xc_ptr;
- memReq->xc = xc;
+// memReq->xc = xc;
}
template <class Impl>
}
updateStatus();
return;
+ } else if (status == QuiescePending) {
+ DPRINTF(FE, "Waiting for quiesce to execute or get squashed.\n");
+ return;
} else if (status != IcacheMissComplete) {
if (fetchCacheLineNextCycle) {
Fault fault = fetchCacheLine();
// rename(num_inst);
// }
+#if FULL_SYSTEM
+ if (inst->isQuiesce()) {
+ warn("%lli: Quiesce instruction encountered, halting fetch!", curTick);
+ status = QuiescePending;
+ break;
+ }
+#endif
+
if (inst->predTaken()) {
// Start over with tick?
break;
// Setup the memReq to do a read of the first isntruction's address.
// Set the appropriate read size and flags as well.
+ memReq = new MemReq();
+
+ memReq->asid = 0;
+ memReq->thread_num = 0;
+ memReq->data = new uint8_t[64];
+ memReq->xc = xc;
memReq->cmd = Read;
memReq->reset(fetch_PC, cacheBlkSize, flags);
// Now do the timing access to see whether or not the instruction
// exists within the cache.
if (icacheInterface && fault == NoFault) {
+#if FULL_SYSTEM
+ if (cpu->system->memctrl->badaddr(memReq->paddr)) {
+ DPRINTF(FE, "Fetch: Bad address %#x (hopefully on a "
+ "misspeculating path!",
+ memReq->paddr);
+ return TheISA::genMachineCheckFault();
+ }
+#endif
+
memReq->completionEvent = NULL;
memReq->time = curTick;
+ fault = cpu->mem->read(memReq, cacheData);
MemAccessResult res = icacheInterface->access(memReq);
// If the cache missed then schedule an event to wake
// up this stage once the cache miss completes.
if (icacheInterface->doEvents() && res != MA_HIT) {
- memReq->completionEvent = new ICacheCompletionEvent(this);
+ memReq->completionEvent = new ICacheCompletionEvent(memReq, this);
status = IcacheMissStall;
cacheBlkValid = true;
- memcpy(cacheData, memReq->data, memReq->size);
+// memcpy(cacheData, memReq->data, memReq->size);
}
}
// Clear the icache miss if it's outstanding.
if (status == IcacheMissStall && icacheInterface) {
DPRINTF(FE, "Squashing outstanding Icache miss.\n");
- icacheInterface->squash(0);
+// icacheInterface->squash(0);
+ memReq = NULL;
}
if (status == SerializeBlocked) {
template <class Impl>
void
-FrontEnd<Impl>::processCacheCompletion()
+FrontEnd<Impl>::processCacheCompletion(MemReqPtr &req)
{
DPRINTF(FE, "Processing cache completion\n");
// Do something here.
- if (status != IcacheMissStall) {
+ if (status != IcacheMissStall ||
+ req != memReq) {
DPRINTF(FE, "Previous fetch was squashed.\n");
return;
}
fetchStatus[tid] = IcacheMissComplete;
}
*/
- memcpy(cacheData, memReq->data, memReq->size);
+// memcpy(cacheData, memReq->data, memReq->size);
// Reset the completion event to NULL.
- memReq->completionEvent = NULL;
+// memReq->completionEvent = NULL;
+ memReq = NULL;
}
template <class Impl>
}
}
+template <class Impl>
+void
+FrontEnd<Impl>::wakeFromQuiesce()
+{
+ DPRINTF(FE, "Waking up from quiesce\n");
+ // Hopefully this is safe
+ status = Running;
+}
+
template <class Impl>
void
FrontEnd<Impl>::dumpInsts()
}
template <class Impl>
-FrontEnd<Impl>::ICacheCompletionEvent::ICacheCompletionEvent(FrontEnd *fe)
- : Event(&mainEventQueue, Delayed_Writeback_Pri), frontEnd(fe)
+FrontEnd<Impl>::ICacheCompletionEvent::ICacheCompletionEvent(MemReqPtr &_req, FrontEnd *fe)
+ : Event(&mainEventQueue, Delayed_Writeback_Pri), req(_req), frontEnd(fe)
{
this->setFlags(Event::AutoDelete);
}
void
FrontEnd<Impl>::ICacheCompletionEvent::process()
{
- frontEnd->processCacheCompletion();
+ frontEnd->processCacheCompletion(req);
}
template <class Impl>
void regStats();
- void setCPU(FullCPU *cpu_ptr)
- { cpu = cpu_ptr; }
+ void setCPU(FullCPU *cpu_ptr);
void setFrontEnd(FrontEnd *front_end_ptr)
{ frontEnd = front_end_ptr; }
Stats::Scalar<> commit_eligible_samples;
Stats::Vector<> commit_eligible;
+ Stats::Vector<> squashedInsts;
+ Stats::Vector<> ROBSquashedInsts;
+
Stats::Scalar<> ROB_fcount;
Stats::Formula ROB_full_rate;
.desc("number cycles where commit BW limit reached")
;
+ squashedInsts
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:squashed_insts")
+ .desc("Number of instructions removed from inst list")
+ ;
+
+ ROBSquashedInsts
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:rob_squashed_insts")
+ .desc("Number of instructions removed from inst list when they reached the head of the ROB")
+ ;
+
ROB_fcount
.name(name() + ".ROB:full_count")
.desc("number of cycles where ROB was full")
// IQ.regStats();
}
+template <class Impl>
+void
+LWBackEnd<Impl>::setCPU(FullCPU *cpu_ptr)
+{
+ cpu = cpu_ptr;
+ LSQ.setCPU(cpu_ptr);
+}
+
template <class Impl>
void
LWBackEnd<Impl>::setCommBuffer(TimeBuffer<CommStruct> *_comm)
}
}
- // Now check if it's one of the special trap or barrier or
- // serializing instructions.
- if (inst->isThreadSync())
- {
- // Not handled for now.
- panic("Thread sync instructions are not handled yet.\n");
- }
+ // Not handled for now.
+ assert(!inst->isThreadSync());
// Check if the instruction caused a fault. If so, trap.
Fault inst_fault = inst->getFault();
if (inst_fault != NoFault) {
- if (!inst->isNop()) {
- DPRINTF(BE, "Inst [sn:%lli] PC %#x has a fault\n",
- inst->seqNum, inst->readPC());
- thread->setInst(
- static_cast<TheISA::MachInst>(inst->staticInst->machInst));
+ DPRINTF(BE, "Inst [sn:%lli] PC %#x has a fault\n",
+ inst->seqNum, inst->readPC());
+ thread->setInst(
+ static_cast<TheISA::MachInst>(inst->staticInst->machInst));
#if FULL_SYSTEM
- handleFault(inst_fault);
- return false;
+ handleFault(inst_fault);
+ return false;
#else // !FULL_SYSTEM
- panic("fault (%d) detected @ PC %08p", inst_fault,
- inst->PC);
+ panic("fault (%d) detected @ PC %08p", inst_fault,
+ inst->PC);
#endif // FULL_SYSTEM
- }
- }
-
- if (inst->isControl()) {
-// ++commitCommittedBranches;
}
int freed_regs = 0;
instList.pop_back();
--numInsts;
- cpu->numInst++;
thread->numInsts++;
++thread->funcExeInst;
// Maybe move this to where teh fault is handled; if the fault is handled,
void
LWBackEnd<Impl>::commitInsts()
{
- int commit_width = commitWidth ? commitWidth : width;
-
// Not sure this should be a loop or not.
int inst_num = 0;
- while (!instList.empty() && inst_num < commit_width) {
+ while (!instList.empty() && inst_num < commitWidth) {
if (instList.back()->isSquashed()) {
instList.back()->clearDependents();
instList.pop_back();
--numInsts;
+ ROBSquashedInsts[instList.back()->threadNumber]++;
continue;
}
DPRINTF(BE, "Can't commit, Instruction [sn:%lli] PC "
"%#x is head of ROB and not ready\n",
instList.back()->seqNum, instList.back()->readPC());
+ --inst_num;
break;
}
}
(*insts_it)->clearDependents();
+ squashedInsts[(*insts_it)->threadNumber]++;
+
instList.erase(insts_it++);
--numInsts;
}
{
unsigned thread = inst->threadNumber;
+ cpu->numInst++;
//
// Pick off the software prefetches
//
//#include "mem/page_table.hh"
#include "sim/sim_object.hh"
-class PageTable;
+//class PageTable;
/**
* Class that implements the actual LQ and SQ for each specific thread.
{ be = be_ptr; }
/** Sets the page table pointer. */
- void setPageTable(PageTable *pt_ptr);
+// void setPageTable(PageTable *pt_ptr);
/** Ticks the LSQ unit, which in this case only resets the number of
* used cache ports.
MemInterface *dcacheInterface;
/** Pointer to the page table. */
- PageTable *pTable;
+// PageTable *pTable;
public:
struct SQEntry {
// If there's no forwarding case, then go access memory
+ DPRINTF(OzoneLSQ, "Doing functional access for inst PC %#x\n",
+ inst->readPC());
+
+
+ // Setup MemReq pointer
+ req->cmd = Read;
+ req->completionEvent = NULL;
+ req->time = curTick;
+ assert(!req->data);
+ req->data = new uint8_t[64];
+ Fault fault = cpu->read(req, data);
+ memcpy(req->data, &data, sizeof(T));
+
++usedPorts;
// if we have a cache, do cache access too
"vaddr:%#x flags:%i\n",
inst->readPC(), req->paddr, req->vaddr, req->flags);
- // Setup MemReq pointer
- req->cmd = Read;
- req->completionEvent = NULL;
- req->time = curTick;
- assert(!req->data);
- req->data = new uint8_t[64];
assert(!req->completionEvent);
req->completionEvent =
{
storeQueue.clear();
}
-
+/*
template<class Impl>
void
OzoneLWLSQ<Impl>::setPageTable(PageTable *pt_ptr)
DPRINTF(OzoneLSQ, "Setting the page table pointer.\n");
pTable = pt_ptr;
}
-
+*/
template<class Impl>
void
OzoneLWLSQ<Impl>::resizeLQ(unsigned size)
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");
+ }
+
if (dcacheInterface) {
MemAccessResult result = dcacheInterface->access(req);
typename BackEnd::LdWritebackEvent *wb = NULL;
if (req->flags & LOCKED) {
// Stx_C does not generate a system port transaction.
- req->result=1;
+// req->result=1;
wb = new typename BackEnd::LdWritebackEvent(inst,
be);
}
if (req->flags & LOCKED) {
// Stx_C does not generate a system port transaction.
- if (req->flags & UNCACHEABLE) {
+/* if (req->flags & UNCACHEABLE) {
req->result = 2;
} else {
req->result = 1;
}
-
+*/
typename BackEnd::LdWritebackEvent *wb =
new typename BackEnd::LdWritebackEvent(inst,
be);
while (stores != 0 && (*sq_it).inst->seqNum > squashed_num) {
assert(!storeQueue.empty());
+
+ if ((*sq_it).canWB) {
+ break;
+ }
+
// Clear the smart pointer to make sure it is decremented.
DPRINTF(OzoneLSQ,"Store Instruction PC %#x idx:%i squashed [sn:%lli]\n",
(*sq_it).inst->readPC(), (*sq_it).inst->sqIdx,