#ifndef __CPU_OZONE_INORDER_BACK_END_HH__ #define __CPU_OZONE_INORDER_BACK_END_HH__ #include #include "arch/faults.hh" #include "base/timebuf.hh" #include "cpu/exec_context.hh" #include "cpu/inst_seq.hh" #include "cpu/ozone/rename_table.hh" #include "cpu/ozone/thread_state.hh" #include "mem/mem_interface.hh" #include "mem/mem_req.hh" #include "sim/eventq.hh" template class InorderBackEnd { public: typedef typename Impl::Params Params; typedef typename Impl::DynInstPtr DynInstPtr; typedef typename Impl::FullCPU FullCPU; typedef typename Impl::FrontEnd FrontEnd; typedef typename FullCPU::OzoneXC OzoneXC; typedef typename Impl::FullCPU::CommStruct CommStruct; InorderBackEnd(Params *params); std::string name() const; void setCPU(FullCPU *cpu_ptr) { cpu = cpu_ptr; } void setFrontEnd(FrontEnd *front_end_ptr) { frontEnd = front_end_ptr; } void setCommBuffer(TimeBuffer *_comm) { comm = _comm; } void setXC(ExecContext *xc_ptr); void setThreadState(OzoneThreadState *thread_ptr); void regStats() { } #if FULL_SYSTEM void checkInterrupts(); #endif void tick(); void executeInsts(); void squash(const InstSeqNum &squash_num, const Addr &next_PC); void squashFromXC(); void generateXCEvent() { } bool robEmpty() { return instList.empty(); } bool isFull() { return false; } bool isBlocked() { return status == DcacheMissStoreStall || status == DcacheMissLoadStall || interruptBlocked; } void fetchFault(Fault &fault); void dumpInsts(); private: void handleFault(); void setSquashInfoFromXC(); bool squashPending; InstSeqNum squashSeqNum; Addr squashNextPC; Fault faultFromFetch; bool interruptBlocked; public: template Fault read(Addr addr, T &data, unsigned flags); template Fault read(MemReqPtr &req, T &data, int load_idx); template Fault write(T data, Addr addr, unsigned flags, uint64_t *res); template Fault write(MemReqPtr &req, T &data, int store_idx); Addr readCommitPC() { return commitPC; } Addr commitPC; public: FullCPU *cpu; FrontEnd *frontEnd; ExecContext *xc; OzoneThreadState *thread; RenameTable renameTable; protected: enum Status { Running, Idle, DcacheMissLoadStall, DcacheMissStoreStall, DcacheMissComplete, Blocked }; Status status; class DCacheCompletionEvent : public Event { private: InorderBackEnd *be; public: DCacheCompletionEvent(InorderBackEnd *_be); virtual void process(); virtual const char *description(); DynInstPtr inst; }; friend class DCacheCompletionEvent; DCacheCompletionEvent cacheCompletionEvent; MemInterface *dcacheInterface; MemReqPtr memReq; private: typedef typename std::list::iterator InstListIt; std::list instList; // General back end width. Used if the more specific isn't given. int width; int latency; int squashLatency; TimeBuffer numInstsToWB; TimeBuffer::wire instsAdded; TimeBuffer::wire instsToExecute; TimeBuffer *comm; // number of cycles stalled for D-cache misses Stats::Scalar<> dcacheStallCycles; Counter lastDcacheStall; }; template template Fault InorderBackEnd::read(Addr addr, T &data, unsigned flags) { memReq->reset(addr, sizeof(T), flags); // translate to physical address Fault fault = cpu->translateDataReadReq(memReq); // if we have a cache, do cache access too if (fault == NoFault && dcacheInterface) { memReq->cmd = Read; memReq->completionEvent = NULL; memReq->time = curTick; memReq->flags &= ~INST_READ; MemAccessResult result = dcacheInterface->access(memReq); // Ugly hack to get an event scheduled *only* if the access is // a miss. We really should add first-class support for this // at some point. if (result != MA_HIT) { // Fix this hack for keeping funcExeInst correct with loads that // are executed twice. memReq->completionEvent = &cacheCompletionEvent; lastDcacheStall = curTick; // unscheduleTickEvent(); status = DcacheMissLoadStall; DPRINTF(IBE, "Dcache miss stall!\n"); } else { // do functional access DPRINTF(IBE, "Dcache hit!\n"); } } /* if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) recordEvent("Uncached Read"); */ return fault; } #if 0 template template Fault InorderBackEnd::read(MemReqPtr &req, T &data) { #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 Fault error; error = thread->mem->read(req, data); data = LittleEndianGuest::gtoh(data); return error; } #endif template template Fault InorderBackEnd::write(T data, Addr addr, unsigned flags, uint64_t *res) { memReq->reset(addr, sizeof(T), flags); // translate to physical address Fault fault = cpu->translateDataWriteReq(memReq); if (fault == NoFault && dcacheInterface) { memReq->cmd = Write; // memcpy(memReq->data,(uint8_t *)&data,memReq->size); memReq->completionEvent = NULL; memReq->time = curTick; memReq->flags &= ~INST_READ; MemAccessResult result = dcacheInterface->access(memReq); // Ugly hack to get an event scheduled *only* if the access is // a miss. We really should add first-class support for this // at some point. if (result != MA_HIT) { memReq->completionEvent = &cacheCompletionEvent; lastDcacheStall = curTick; // unscheduleTickEvent(); status = DcacheMissStoreStall; DPRINTF(IBE, "Dcache miss stall!\n"); } else { DPRINTF(IBE, "Dcache hit!\n"); } } if (res && (fault == NoFault)) *res = memReq->result; /* if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) recordEvent("Uncached Write"); */ return fault; } #if 0 template template Fault InorderBackEnd::write(MemReqPtr &req, T &data) { #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 < cpu->system->execContexts.size(); i++){ xc = cpu->system->execContexts[i]; if ((xc->readMiscReg(TheISA::Lock_Addr_DepTag) & ~0xf) == (req->paddr & ~0xf)) { xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); } } #endif return thread->mem->write(req, (T)LittleEndianGuest::htog(data)); } #endif template template Fault InorderBackEnd::read(MemReqPtr &req, T &data, int load_idx) { // panic("Unimplemented!"); // memReq->reset(addr, sizeof(T), flags); // translate to physical address // Fault fault = cpu->translateDataReadReq(req); // if we have a cache, do cache access too if (dcacheInterface) { req->cmd = Read; req->completionEvent = NULL; req->data = new uint8_t[64]; req->time = curTick; req->flags &= ~INST_READ; MemAccessResult result = dcacheInterface->access(req); // Ugly hack to get an event scheduled *only* if the access is // a miss. We really should add first-class support for this // at some point. if (result != MA_HIT) { req->completionEvent = &cacheCompletionEvent; lastDcacheStall = curTick; // unscheduleTickEvent(); status = DcacheMissLoadStall; DPRINTF(IBE, "Dcache miss load stall!\n"); } else { DPRINTF(IBE, "Dcache hit!\n"); } } /* if (!dcacheInterface && (req->flags & UNCACHEABLE)) recordEvent("Uncached Read"); */ return NoFault; } template template Fault InorderBackEnd::write(MemReqPtr &req, T &data, int store_idx) { // req->reset(addr, sizeof(T), flags); // translate to physical address // Fault fault = cpu->translateDataWriteReq(req); if (dcacheInterface) { req->cmd = Write; req->data = new uint8_t[64]; memcpy(req->data,(uint8_t *)&data,req->size); req->completionEvent = NULL; req->time = curTick; req->flags &= ~INST_READ; MemAccessResult result = dcacheInterface->access(req); // Ugly hack to get an event scheduled *only* if the access is // a miss. We really should add first-class support for this // at some point. if (result != MA_HIT) { req->completionEvent = &cacheCompletionEvent; lastDcacheStall = curTick; // unscheduleTickEvent(); status = DcacheMissStoreStall; DPRINTF(IBE, "Dcache miss store stall!\n"); } else { DPRINTF(IBE, "Dcache hit!\n"); } } if (req->flags & LOCKED) { if (req->flags & UNCACHEABLE) { // Don't update result register (see stq_c in isa_desc) req->result = 2; } else { req->result = 1; } } /* if (res && (fault == NoFault)) *res = req->result; */ /* if (!dcacheInterface && (req->flags & UNCACHEABLE)) recordEvent("Uncached Write"); */ return NoFault; } #endif // __CPU_OZONE_INORDER_BACK_END_HH__