* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Kevin Lim
*/
-#include "arch/faults.hh"
+#include "sim/faults.hh"
#include "arch/isa_traits.hh"
+#include "arch/utility.hh"
#include "base/statistics.hh"
+#include "config/the_isa.hh"
+#include "config/use_checker.hh"
#include "cpu/thread_context.hh"
#include "cpu/exetrace.hh"
#include "cpu/ozone/front_end.hh"
-#include "mem/mem_interface.hh"
-#include "sim/byte_swap.hh"
+#include "mem/mem_object.hh"
+#include "mem/packet.hh"
+#include "mem/request.hh"
+
+#if USE_CHECKER
+#include "cpu/checker/cpu.hh"
+#endif
using namespace TheISA;
+template<class Impl>
+Tick
+FrontEnd<Impl>::IcachePort::recvAtomic(PacketPtr pkt)
+{
+ panic("FrontEnd doesn't expect recvAtomic callback!");
+ return curTick;
+}
+
+template<class Impl>
+void
+FrontEnd<Impl>::IcachePort::recvFunctional(PacketPtr pkt)
+{
+ warn("FrontEnd doesn't update state from functional calls");
+}
+
+template<class Impl>
+void
+FrontEnd<Impl>::IcachePort::recvStatusChange(Status status)
+{
+ if (status == RangeChange)
+ return;
+
+ panic("FrontEnd doesn't expect recvStatusChange callback!");
+}
+
+template<class Impl>
+bool
+FrontEnd<Impl>::IcachePort::recvTiming(PacketPtr pkt)
+{
+ fe->processCacheCompletion(pkt);
+ return true;
+}
+
+template<class Impl>
+void
+FrontEnd<Impl>::IcachePort::recvRetry()
+{
+ fe->recvRetry();
+}
+
template <class Impl>
FrontEnd<Impl>::FrontEnd(Params *params)
: branchPred(params),
- icacheInterface(params->icacheInterface),
+ icachePort(this),
+ numInstsReady(params->frontEndLatency, 0),
instBufferSize(0),
maxInstBufferSize(params->maxInstBufferSize),
+ latency(params->frontEndLatency),
width(params->frontEndWidth),
freeRegs(params->numPhysicalRegs),
numPhysRegs(params->numPhysicalRegs),
memReq = NULL;
// Size of cache block.
- cacheBlkSize = icacheInterface ? icacheInterface->getBlockSize() : 64;
+ cacheBlkSize = 64;
assert(isPowerOf2(cacheBlkSize));
fetchCacheLineNextCycle = true;
- cacheBlkValid = false;
+ cacheBlkValid = cacheBlocked = false;
+
+ retryPkt = NULL;
-#if !FULL_SYSTEM
-// pTable = params->pTable;
-#endif
fetchFault = NoFault;
}
return cpu->name() + ".frontend";
}
+template <class Impl>
+void
+FrontEnd<Impl>::setCPU(CPUType *cpu_ptr)
+{
+ cpu = cpu_ptr;
+
+ icachePort.setName(this->name() + "-iport");
+
+#if USE_CHECKER
+ if (cpu->checker) {
+ cpu->checker->setIcachePort(&icachePort);
+ }
+#endif
+}
+
template <class Impl>
void
FrontEnd<Impl>::setCommBuffer(TimeBuffer<CommStruct> *_comm)
if (switchedOut)
return;
+ for (int insts_to_queue = numInstsReady[-latency];
+ !instBuffer.empty() && insts_to_queue;
+ --insts_to_queue)
+ {
+ DPRINTF(FE, "Transferring instruction [sn:%lli] to the feBuffer\n",
+ instBuffer.front()->seqNum);
+ feBuffer.push_back(instBuffer.front());
+ instBuffer.pop_front();
+ }
+
+ numInstsReady.advance();
+
// @todo: Maybe I want to just have direct communication...
if (fromCommit->doneSeqNum) {
branchPred.update(fromCommit->doneSeqNum, 0);
IFQFcount += instBufferSize == maxInstBufferSize;
// Fetch cache line
- if (status == IcacheMissComplete) {
+ if (status == IcacheAccessComplete) {
cacheBlkValid = true;
status = Running;
- if (barrierInst)
- status = SerializeBlocked;
+// if (barrierInst)
+// status = SerializeBlocked;
if (freeRegs <= 0)
status = RenameBlocked;
checkBE();
- } else if (status == IcacheMissStall) {
- DPRINTF(FE, "Still in Icache miss stall.\n");
+ } else if (status == IcacheWaitResponse || status == IcacheWaitRetry) {
+ DPRINTF(FE, "Still in Icache wait.\n");
icacheStallCycles++;
return;
}
} else if (status == QuiescePending) {
DPRINTF(FE, "Waiting for quiesce to execute or get squashed.\n");
return;
- } else if (status != IcacheMissComplete) {
+ } else if (status != IcacheAccessComplete) {
if (fetchCacheLineNextCycle) {
Fault fault = fetchCacheLine();
if (fault != NoFault) {
fetchCacheLineNextCycle = false;
}
// If miss, stall until it returns.
- if (status == IcacheMissStall) {
+ if (status == IcacheWaitResponse || status == IcacheWaitRetry) {
// Tell CPU to not tick me for now.
return;
}
// latency
instBuffer.push_back(inst);
++instBufferSize;
+ numInstsReady[0]++;
++num_inst;
#if FULL_SYSTEM
if (inst->isQuiesce()) {
- warn("%lli: Quiesce instruction encountered, halting fetch!", curTick);
+// warn("%lli: Quiesce instruction encountered, halting fetch!", curTick);
status = QuiescePending;
break;
}
FrontEnd<Impl>::fetchCacheLine()
{
// Read a cache line, based on the current PC.
-#if FULL_SYSTEM
- // Flag to say whether or not address is physical addr.
- unsigned flags = cpu->inPalMode(PC) ? PHYSICAL : 0;
-#else
- unsigned flags = 0;
-#endif // FULL_SYSTEM
Fault fault = NoFault;
- if (interruptPending && flags == 0) {
+ //AlphaDep
+ if (interruptPending && (PC & 0x3)) {
return fault;
}
// 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->tc = tc;
- memReq->cmd = Read;
- memReq->reset(fetch_PC, cacheBlkSize, flags);
+ memReq = new Request(0, fetch_PC, cacheBlkSize, 0,
+ PC, cpu->thread->contextId());
// Translate the instruction request.
- fault = cpu->translateInstReq(memReq);
+ fault = cpu->itb->translateAtomic(memReq, thread, false, true);
// Now do the timing access to see whether or not the instruction
// exists within the cache.
- if (icacheInterface && fault == NoFault) {
-#if FULL_SYSTEM
+ if (fault == NoFault) {
+#if 0
if (cpu->system->memctrl->badaddr(memReq->paddr) ||
- memReq->flags & UNCACHEABLE) {
+ memReq->isUncacheable()) {
DPRINTF(FE, "Fetch: Bad address %#x (hopefully on a "
"misspeculating path!",
memReq->paddr);
}
#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(memReq, this);
-
- status = IcacheMissStall;
-
- cacheBlkValid = false;
-
- DPRINTF(FE, "Cache miss.\n");
- } else {
- DPRINTF(FE, "Cache hit.\n");
-
- cacheBlkValid = true;
-
-// memcpy(cacheData, memReq->data, memReq->size);
+ // Build packet here.
+ PacketPtr data_pkt = new Packet(memReq,
+ Packet::ReadReq, Packet::Broadcast);
+ data_pkt->dataStatic(cacheData);
+
+ if (!icachePort.sendTiming(data_pkt)) {
+ assert(retryPkt == NULL);
+ DPRINTF(Fetch, "Out of MSHRs!\n");
+ status = IcacheWaitRetry;
+ retryPkt = data_pkt;
+ cacheBlocked = true;
+ return NoFault;
}
+
+ status = IcacheWaitResponse;
}
// Note that this will set the cache block PC a bit earlier than it should
// Change status over to SerializeBlocked so that other stages know
// what this is blocked on.
- status = SerializeBlocked;
+// status = SerializeBlocked;
- barrierInst = inst;
- return true;
+// barrierInst = inst;
+// return true;
} else if ((inst->isStoreConditional() || inst->isSerializeAfter())
&& !inst->isSerializeHandled()) {
DPRINTF(FE, "Serialize after instruction encountered.\n");
// instruction->setASID(tid);
- instruction->setState(thread);
+ instruction->setThreadState(thread);
instruction->traceData = NULL;
instruction->fault = fault;
instruction->setCanIssue();
instBuffer.push_back(instruction);
+ numInstsReady[0]++;
++instBufferSize;
}
freeRegs+= inst->numDestRegs();
}
+ while (!feBuffer.empty() &&
+ feBuffer.back()->seqNum > squash_num) {
+ DynInstPtr inst = feBuffer.back();
+
+ DPRINTF(FE, "Squashing instruction [sn:%lli] PC %#x\n",
+ inst->seqNum, inst->readPC());
+
+ inst->clearDependents();
+
+ feBuffer.pop_back();
+ --instBufferSize;
+
+ freeRegs+= inst->numDestRegs();
+ }
+
// Copy over rename table from the back end.
renameTable.copyFrom(backEnd->renameTable);
}
// Clear the icache miss if it's outstanding.
- if (status == IcacheMissStall && icacheInterface) {
- DPRINTF(FE, "Squashing outstanding Icache miss.\n");
+ if (status == IcacheWaitResponse) {
+ DPRINTF(FE, "Squashing outstanding Icache access.\n");
memReq = NULL;
}
-
+/*
if (status == SerializeBlocked) {
assert(barrierInst->seqNum > squash_num);
barrierInst = NULL;
}
-
+*/
// Unless this squash originated from the front end, we're probably
// in running mode now.
// Actually might want to make this latency dependent.
typename Impl::DynInstPtr
FrontEnd<Impl>::getInst()
{
- if (instBufferSize == 0) {
+ if (feBuffer.empty()) {
return NULL;
}
- DynInstPtr inst = instBuffer.front();
+ DynInstPtr inst = feBuffer.front();
+
+ if (inst->isSerializeBefore() || inst->isIprAccess()) {
+ DPRINTF(FE, "Back end is getting a serialize before inst\n");
+ if (!backEnd->robEmpty()) {
+ DPRINTF(FE, "Rob is not empty yet, not returning inst\n");
+ return NULL;
+ }
+ inst->clearSerializeBefore();
+ }
- instBuffer.pop_front();
+ feBuffer.pop_front();
--instBufferSize;
template <class Impl>
void
-FrontEnd<Impl>::processCacheCompletion(MemReqPtr &req)
+FrontEnd<Impl>::processCacheCompletion(PacketPtr pkt)
{
DPRINTF(FE, "Processing cache completion\n");
// Do something here.
- if (status != IcacheMissStall ||
- req != memReq ||
+ if (status != IcacheWaitResponse ||
+ pkt->req != memReq ||
switchedOut) {
DPRINTF(FE, "Previous fetch was squashed.\n");
fetchIcacheSquashes++;
+ delete pkt->req;
+ delete pkt;
return;
}
- status = IcacheMissComplete;
+ status = IcacheAccessComplete;
/* if (checkStall(tid)) {
fetchStatus[tid] = Blocked;
// Reset the completion event to NULL.
// memReq->completionEvent = NULL;
+ delete pkt->req;
+ delete pkt;
memReq = NULL;
}
freeRegs = numPhysRegs;
}
+template <class Impl>
+void
+FrontEnd<Impl>::recvRetry()
+{
+ assert(cacheBlocked);
+ if (retryPkt != NULL) {
+ assert(status == IcacheWaitRetry);
+
+ if (icachePort.sendTiming(retryPkt)) {
+ status = IcacheWaitResponse;
+ retryPkt = NULL;
+ cacheBlocked = false;
+ }
+ } else {
+ // Access has been squashed since it was sent out. Just clear
+ // the cache being blocked.
+ cacheBlocked = false;
+ }
+
+}
+
template <class Impl>
bool
FrontEnd<Impl>::updateStatus()
}
if (status == BEBlocked && !be_block) {
- if (barrierInst) {
- status = SerializeBlocked;
- } else {
+// if (barrierInst) {
+// status = SerializeBlocked;
+// } else {
status = Running;
- }
+// }
ret_val = true;
}
return ret_val;
typename Impl::DynInstPtr
FrontEnd<Impl>::getInstFromCacheline()
{
+/*
if (status == SerializeComplete) {
DynInstPtr inst = barrierInst;
status = Running;
inst->clearSerializeBefore();
return inst;
}
-
+*/
InstSeqNum inst_seq;
MachInst inst;
// @todo: Fix this magic number used here to handle word offset (and
// Get the instruction from the array of the cache line.
inst = htog(*reinterpret_cast<MachInst *>(&cacheData[offset]));
+#if THE_ISA == ALPHA_ISA
ExtMachInst decode_inst = TheISA::makeExtMI(inst, PC);
+#elif THE_ISA == SPARC_ISA
+ ExtMachInst decode_inst = TheISA::makeExtMI(inst, tc);
+#endif
// Create a new DynInst from the instruction fetched.
DynInstPtr instruction = new DynInst(decode_inst, PC, PC+sizeof(MachInst),
inst_seq, cpu);
- instruction->setState(thread);
+ instruction->setThreadState(thread);
DPRINTF(FE, "Instruction [sn:%lli] created, with PC %#x\n%s\n",
inst_seq, instruction->readPC(),
instruction->staticInst->disassemble(PC));
instruction->traceData =
- Trace::getInstRecord(curTick, tc, cpu,
+ Trace::getInstRecord(curTick, tc,
instruction->staticInst,
- instruction->readPC(), 0);
+ instruction->readPC());
// Increment stat of fetched instructions.
++fetchedInsts;
squash(0, 0);
instBuffer.clear();
instBufferSize = 0;
+ feBuffer.clear();
status = Idle;
}
buff_it++;
}
}
-
-template <class Impl>
-FrontEnd<Impl>::ICacheCompletionEvent::ICacheCompletionEvent(MemReqPtr &_req, FrontEnd *fe)
- : Event(&mainEventQueue, Delayed_Writeback_Pri), req(_req), frontEnd(fe)
-{
- this->setFlags(Event::AutoDelete);
-}
-
-template <class Impl>
-void
-FrontEnd<Impl>::ICacheCompletionEvent::process()
-{
- frontEnd->processCacheCompletion(req);
-}
-
-template <class Impl>
-const char *
-FrontEnd<Impl>::ICacheCompletionEvent::description()
-{
- return "ICache completion event";
-}