2c2
< * Copyright (c) 2004-2006 The Regents of The University of Michigan
---
> * Copyright (c) 2004-2005 The Regents of The University of Michigan
26a27,28
> *
> * Authors: Kevin Lim
28a31,33
> // Remove this later; used only for debugging.
> #define OPCODE(X) (X >> 26) & 0x3f
>
29a35
> #include "sim/byteswap.hh"
31d36
< #include "cpu/o3/fetch.hh"
35c40,41
< #include "sim/byteswap.hh"
---
> #include "cpu/o3/fetch.hh"
>
38,52d43
< #if FULL_SYSTEM
< #include "arch/tlb.hh"
< #include "arch/vtophys.hh"
< #include "base/remote_gdb.hh"
< #include "mem/functional/memory_control.hh"
< #include "mem/functional/physical.hh"
< #include "sim/system.hh"
< #else // !FULL_SYSTEM
< #include "mem/functional/functional.hh"
< #endif // FULL_SYSTEM
<
< #include <algorithm>
<
< using namespace std;
<
54,57c45,47
< DefaultFetch<Impl>::CacheCompletionEvent::CacheCompletionEvent(MemReqPtr &_req,
< DefaultFetch *_fetch)
< : Event(&mainEventQueue, Delayed_Writeback_Pri),
< req(_req),
---
> SimpleFetch<Impl>::CacheCompletionEvent
> ::CacheCompletionEvent(SimpleFetch *_fetch)
> : Event(&mainEventQueue),
60d49
< this->setFlags(Event::AutoDelete);
65c54
< DefaultFetch<Impl>::CacheCompletionEvent::process()
---
> SimpleFetch<Impl>::CacheCompletionEvent::process()
67c56
< fetch->processCacheCompletion(req);
---
> fetch->processCacheCompletion();
72c61
< DefaultFetch<Impl>::CacheCompletionEvent::description()
---
> SimpleFetch<Impl>::CacheCompletionEvent::description()
74c63
< return "DefaultFetch cache completion event";
---
> return "SimpleFetch cache completion event";
78,79c67,68
< DefaultFetch<Impl>::DefaultFetch(Params *params)
< : icacheInterface(params->icacheInterface),
---
> SimpleFetch<Impl>::SimpleFetch(Params &params)
> : icacheInterface(params.icacheInterface),
81,88c70,74
< decodeToFetchDelay(params->decodeToFetchDelay),
< renameToFetchDelay(params->renameToFetchDelay),
< iewToFetchDelay(params->iewToFetchDelay),
< commitToFetchDelay(params->commitToFetchDelay),
< fetchWidth(params->fetchWidth),
< numThreads(params->numberOfThreads),
< numFetchingThreads(params->smtNumFetchingThreads),
< interruptPending(false)
---
> decodeToFetchDelay(params.decodeToFetchDelay),
> renameToFetchDelay(params.renameToFetchDelay),
> iewToFetchDelay(params.iewToFetchDelay),
> commitToFetchDelay(params.commitToFetchDelay),
> fetchWidth(params.fetchWidth)
90,91c76
< if (numThreads > Impl::MaxThreads)
< fatal("numThreads is not a valid value\n");
---
> DPRINTF(Fetch, "Fetch: Fetch constructor called\n");
93c78,79
< DPRINTF(Fetch, "Fetch constructor called\n");
---
> // Set status to idle.
> _status = Idle;
95,96c81,90
< // Set fetch stage's status to inactive.
< _status = Inactive;
---
> // Create a new memory request.
> memReq = new MemReq();
> // Not sure of this parameter. I think it should be based on the
> // thread number.
> #if !FULL_SYSTEM
> memReq->asid = 0;
> #else
> memReq->asid = 0;
> #endif // FULL_SYSTEM
> memReq->data = new uint8_t[64];
98,123d91
< string policy = params->smtFetchPolicy;
<
< // Convert string to lowercase
< std::transform(policy.begin(), policy.end(), policy.begin(),
< (int(*)(int)) tolower);
<
< // Figure out fetch policy
< if (policy == "singlethread") {
< fetchPolicy = SingleThread;
< } else if (policy == "roundrobin") {
< fetchPolicy = RoundRobin;
< DPRINTF(Fetch, "Fetch policy set to Round Robin\n");
< } else if (policy == "branch") {
< fetchPolicy = Branch;
< DPRINTF(Fetch, "Fetch policy set to Branch Count\n");
< } else if (policy == "iqcount") {
< fetchPolicy = IQ;
< DPRINTF(Fetch, "Fetch policy set to IQ count\n");
< } else if (policy == "lsqcount") {
< fetchPolicy = LSQ;
< DPRINTF(Fetch, "Fetch policy set to LSQ count\n");
< } else {
< fatal("Invalid Fetch Policy. Options Are: {SingleThread,"
< " RoundRobin,LSQcount,IQcount}\n");
< }
<
130,147d97
< for (int tid=0; tid < numThreads; tid++) {
<
< fetchStatus[tid] = Running;
<
< priorityList.push_back(tid);
<
< // Create a new memory request.
< memReq[tid] = NULL;
<
< // Create space to store a cache line.
< cacheData[tid] = new uint8_t[cacheBlkSize];
<
< stalls[tid].decode = 0;
< stalls[tid].rename = 0;
< stalls[tid].iew = 0;
< stalls[tid].commit = 0;
< }
<
150d99
< }
152,156c101,102
< template <class Impl>
< std::string
< DefaultFetch<Impl>::name() const
< {
< return cpu->name() + ".fetch";
---
> // Create space to store a cache line.
> cacheData = new uint8_t[cacheBlkSize];
161c107
< DefaultFetch<Impl>::regStats()
---
> SimpleFetch<Impl>::regStats()
164c110
< .name(name() + ".FETCH:icacheStallCycles")
---
> .name(name() + ".icacheStallCycles")
169c115
< .name(name() + ".FETCH:Insts")
---
> .name(name() + ".fetchedInsts")
172,177d117
<
< fetchedBranches
< .name(name() + ".FETCH:Branches")
< .desc("Number of branches that fetch encountered")
< .prereq(fetchedBranches);
<
179c119
< .name(name() + ".FETCH:predictedBranches")
---
> .name(name() + ".predictedBranches")
182d121
<
184c123
< .name(name() + ".FETCH:Cycles")
---
> .name(name() + ".fetchCycles")
188d126
<
190c128
< .name(name() + ".FETCH:SquashCycles")
---
> .name(name() + ".fetchSquashCycles")
193,198d130
<
< fetchIdleCycles
< .name(name() + ".FETCH:IdleCycles")
< .desc("Number of cycles fetch was idle")
< .prereq(fetchIdleCycles);
<
200c132
< .name(name() + ".FETCH:BlockedCycles")
---
> .name(name() + ".fetchBlockedCycles")
203d134
<
205c136
< .name(name() + ".FETCH:CacheLines")
---
> .name(name() + ".fetchedCacheLines")
209,220c140
< fetchMiscStallCycles
< .name(name() + ".FETCH:MiscStallCycles")
< .desc("Number of cycles fetch has spent waiting on interrupts, or "
< "bad addresses, or out of MSHRs")
< .prereq(fetchMiscStallCycles);
<
< fetchIcacheSquashes
< .name(name() + ".FETCH:IcacheSquashes")
< .desc("Number of outstanding Icache misses that were squashed")
< .prereq(fetchIcacheSquashes);
<
< fetchNisnDist
---
> fetch_nisn_dist
224c144
< .name(name() + ".FETCH:rateDist")
---
> .name(name() + ".FETCH:rate_dist")
226c146,147
< .flags(Stats::pdf);
---
> .flags(Stats::pdf)
> ;
228,245d148
< idleRate
< .name(name() + ".FETCH:idleRate")
< .desc("Percent of cycles fetch was idle")
< .prereq(idleRate);
< idleRate = fetchIdleCycles * 100 / cpu->numCycles;
<
< branchRate
< .name(name() + ".FETCH:branchRate")
< .desc("Number of branch fetches per cycle")
< .flags(Stats::total);
< branchRate = predictedBranches / cpu->numCycles;
<
< fetchRate
< .name(name() + ".FETCH:rate")
< .desc("Number of inst fetches per cycle")
< .flags(Stats::total);
< fetchRate = fetchedInsts / cpu->numCycles;
<
251c154
< DefaultFetch<Impl>::setCPU(FullCPU *cpu_ptr)
---
> SimpleFetch<Impl>::setCPU(FullCPU *cpu_ptr)
253c156
< DPRINTF(Fetch, "Setting the CPU pointer.\n");
---
> DPRINTF(Fetch, "Fetch: Setting the CPU pointer.\n");
255,258c158,159
<
< // Fetch needs to start fetching instructions at the very beginning,
< // so it must start up in active state.
< switchToActive();
---
> // This line will be removed eventually.
> memReq->xc = cpu->xcBase();
263c164
< DefaultFetch<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer)
---
> SimpleFetch<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer)
265c166
< DPRINTF(Fetch, "Setting the time buffer pointer.\n");
---
> DPRINTF(Fetch, "Fetch: Setting the time buffer pointer.\n");
277c178
< DefaultFetch<Impl>::setActiveThreads(list<unsigned> *at_ptr)
---
> SimpleFetch<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
279,287c180
< DPRINTF(Fetch, "Setting active threads list pointer.\n");
< activeThreads = at_ptr;
< }
<
< template<class Impl>
< void
< DefaultFetch<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
< {
< DPRINTF(Fetch, "Setting the fetch queue pointer.\n");
---
> DPRINTF(Fetch, "Fetch: Setting the fetch queue pointer.\n");
294d186
< #if 0
297c189
< DefaultFetch<Impl>::setPageTable(PageTable *pt_ptr)
---
> SimpleFetch<Impl>::processCacheCompletion()
299,304c191
< DPRINTF(Fetch, "Setting the page table pointer.\n");
< #if !FULL_SYSTEM
< pTable = pt_ptr;
< #endif
< }
< #endif
---
> DPRINTF(Fetch, "Fetch: Waking up from cache miss.\n");
306,323d192
< template<class Impl>
< void
< DefaultFetch<Impl>::initStage()
< {
< for (int tid = 0; tid < numThreads; tid++) {
< PC[tid] = cpu->readPC(tid);
< nextPC[tid] = cpu->readNextPC(tid);
< }
< }
<
< template<class Impl>
< void
< DefaultFetch<Impl>::processCacheCompletion(MemReqPtr &req)
< {
< unsigned tid = req->thread_num;
<
< DPRINTF(Fetch, "[tid:%u] Waking up from cache miss.\n",tid);
<
328,354c197,198
< if (fetchStatus[tid] != IcacheMissStall ||
< req != memReq[tid] ||
< isSwitchedOut()) {
< ++fetchIcacheSquashes;
< return;
< }
<
< // Wake up the CPU (if it went to sleep and was waiting on this completion
< // event).
< cpu->wakeCPU();
<
< DPRINTF(Activity, "[tid:%u] Activating fetch due to cache completion\n",
< tid);
<
< switchToActive();
<
< // Only switch to IcacheMissComplete if we're not stalled as well.
< if (checkStall(tid)) {
< fetchStatus[tid] = Blocked;
< } else {
< fetchStatus[tid] = IcacheMissComplete;
< }
<
< // memcpy(cacheData[tid], memReq[tid]->data, memReq[tid]->size);
<
< // Reset the mem req to NULL.
< memReq[tid] = NULL;
---
> if (_status == IcacheMissStall)
> _status = IcacheMissComplete;
358,428d201
< void
< DefaultFetch<Impl>::switchOut()
< {
< switchedOut = true;
< cpu->signalSwitched();
< }
<
< template <class Impl>
< void
< DefaultFetch<Impl>::doSwitchOut()
< {
< branchPred.switchOut();
< }
<
< template <class Impl>
< void
< DefaultFetch<Impl>::takeOverFrom()
< {
< // Reset all state
< for (int i = 0; i < Impl::MaxThreads; ++i) {
< stalls[i].decode = 0;
< stalls[i].rename = 0;
< stalls[i].iew = 0;
< stalls[i].commit = 0;
< PC[i] = cpu->readPC(i);
< nextPC[i] = cpu->readNextPC(i);
< fetchStatus[i] = Running;
< }
< numInst = 0;
< wroteToTimeBuffer = false;
< _status = Inactive;
< switchedOut = false;
< branchPred.takeOverFrom();
< }
<
< template <class Impl>
< void
< DefaultFetch<Impl>::wakeFromQuiesce()
< {
< DPRINTF(Fetch, "Waking up from quiesce\n");
< // Hopefully this is safe
< fetchStatus[0] = Running;
< }
<
< template <class Impl>
< inline void
< DefaultFetch<Impl>::switchToActive()
< {
< if (_status == Inactive) {
< DPRINTF(Activity, "Activating stage.\n");
<
< cpu->activateStage(FullCPU::FetchIdx);
<
< _status = Active;
< }
< }
<
< template <class Impl>
< inline void
< DefaultFetch<Impl>::switchToInactive()
< {
< if (_status == Active) {
< DPRINTF(Activity, "Deactivating stage.\n");
<
< cpu->deactivateStage(FullCPU::FetchIdx);
<
< _status = Inactive;
< }
< }
<
< template <class Impl>
430c203
< DefaultFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC)
---
> SimpleFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC)
443c216
< predict_taken = branchPred.predict(inst, next_PC, inst->threadNumber);
---
> predict_taken = branchPred.predict(inst, next_PC);
445,446d217
< ++fetchedBranches;
<
455,456c226,227
< bool
< DefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid)
---
> Fault
> SimpleFetch<Impl>::fetchCacheLine(Addr fetch_PC)
458c229,232
< Fault fault = NoFault;
---
> // Check if the instruction exists within the cache.
> // If it does, then proceed on to read the instruction and the rest
> // of the instructions in the cache line until either the end of the
> // cache line or a predicted taken branch is encountered.
462c236
< unsigned flags = cpu->inPalMode(fetch_PC) ? PHYSICAL : 0;
---
> unsigned flags = cpu->inPalMode() ? PHYSICAL : 0;
467,471c241
< if (interruptPending && flags == 0 || switchedOut) {
< // Hold off fetch from getting new instructions while an interrupt
< // is pending.
< return false;
< }
---
> Fault fault = NoFault;
476c246
< // Setup the memReq to do a read of the first instruction's address.
---
> // Setup the memReq to do a read of the first isntruction's address.
478c248,249
< memReq[tid] = new MemReq();
---
> memReq->cmd = Read;
> memReq->reset(fetch_PC, cacheBlkSize, flags);
480,486d250
< memReq[tid]->asid = tid;
< memReq[tid]->thread_num = tid;
< memReq[tid]->data = new uint8_t[64];
< memReq[tid]->xc = cpu->xcBase(tid);
< memReq[tid]->cmd = Read;
< memReq[tid]->reset(fetch_PC, cacheBlkSize, flags);
<
488,492c252,254
< //#if FULL_SYSTEM
< fault = cpu->translateInstReq(memReq[tid]);
< //#else
< // fault = pTable->translate(memReq[tid]);
< //#endif
---
> // Should this function be
> // in the CPU class ? Probably...ITB/DTB should exist within the
> // CPU.
493a256,257
> fault = cpu->translateInstReq(memReq);
>
495c259
< // for the ITB miss to be handled.
---
> // on what caused the fetch (ITB or Icache miss).
500,510d263
< #if FULL_SYSTEM
< if (cpu->system->memctrl->badaddr(memReq[tid]->paddr) ||
< memReq[tid]->flags & UNCACHEABLE) {
< DPRINTF(Fetch, "Fetch: Bad address %#x (hopefully on a "
< "misspeculating path)!",
< memReq[tid]->paddr);
< ret_fault = TheISA::genMachineCheckFault();
< return false;
< }
< #endif
<
512c265
< fault = cpu->mem->read(memReq[tid], cacheData[tid]);
---
> fault = cpu->mem->read(memReq, cacheData);
515,518c268,269
< // Now do the timing access to see whether or not the instruction
< // exists within the cache.
< if (icacheInterface && !icacheInterface->isBlocked()) {
< DPRINTF(Fetch, "Doing cache access.\n");
---
> fetchedCacheLines++;
> }
520c271,275
< memReq[tid]->completionEvent = NULL;
---
> // Now do the timing access to see whether or not the instruction
> // exists within the cache.
> if (icacheInterface && fault == NoFault) {
> DPRINTF(Fetch, "Fetch: Doing timing memory access.\n");
> memReq->completionEvent = NULL;
522c277
< memReq[tid]->time = curTick;
---
> memReq->time = curTick;
524c279
< MemAccessResult result = icacheInterface->access(memReq[tid]);
---
> MemAccessResult result = icacheInterface->access(memReq);
526c281,285
< fetchedCacheLines++;
---
> // If the cache missed (in this model functional and timing
> // memories are different), then schedule an event to wake
> // up this stage once the cache miss completes.
> if (result != MA_HIT && icacheInterface->doEvents()) {
> memReq->completionEvent = new CacheCompletionEvent(this);
528,531c287,290
< // If the cache missed, then schedule an event to wake
< // up this stage once the cache miss completes.
< // @todo: Possibly allow for longer than 1 cycle cache hits.
< if (result != MA_HIT && icacheInterface->doEvents()) {
---
> // How does current model work as far as individual
> // stages scheduling/unscheduling?
> // Perhaps have only the main CPU scheduled/unscheduled,
> // and have it choose what stages to run appropriately.
533,551c292,293
< memReq[tid]->completionEvent =
< new CacheCompletionEvent(memReq[tid], this);
<
< lastIcacheStall[tid] = curTick;
<
< DPRINTF(Activity, "[tid:%i]: Activity: Stalling due to I-cache "
< "miss.\n", tid);
<
< fetchStatus[tid] = IcacheMissStall;
< } else {
< DPRINTF(Fetch, "[tid:%i]: I-Cache hit. Doing Instruction "
< "read.\n", tid);
<
< // memcpy(cacheData[tid], memReq[tid]->data, memReq[tid]->size);
< }
< } else {
< DPRINTF(Fetch, "[tid:%i] Out of MSHRs!\n", tid);
< ret_fault = NoFault;
< return false;
---
> DPRINTF(Fetch, "Fetch: Stalling due to icache miss.\n");
> _status = IcacheMissStall;
555,556c297
< ret_fault = fault;
< return true;
---
> return fault;
561c302
< DefaultFetch<Impl>::doSquash(const Addr &new_PC, unsigned tid)
---
> SimpleFetch<Impl>::doSquash(const Addr &new_PC)
563,564c304
< DPRINTF(Fetch, "[tid:%i]: Squashing, setting PC to: %#x.\n",
< tid, new_PC);
---
> DPRINTF(Fetch, "Fetch: Squashing, setting PC to: %#x.\n", new_PC);
566,567c306,307
< PC[tid] = new_PC;
< nextPC[tid] = new_PC + instSize;
---
> cpu->setNextPC(new_PC + instSize);
> cpu->setPC(new_PC);
570,573c310,313
< if (fetchStatus[tid] == IcacheMissStall && icacheInterface) {
< DPRINTF(Fetch, "[tid:%i]: Squashing outstanding Icache miss.\n",
< tid);
< memReq[tid] = NULL;
---
> if (_status == IcacheMissStall && icacheInterface) {
> DPRINTF(Fetch, "Fetch: Squashing outstanding Icache miss.\n");
> // @todo: Use an actual thread number here.
> icacheInterface->squash(0);
576c316
< fetchStatus[tid] = Squashing;
---
> _status = Squashing;
583,585c323,324
< DefaultFetch<Impl>::squashFromDecode(const Addr &new_PC,
< const InstSeqNum &seq_num,
< unsigned tid)
---
> SimpleFetch<Impl>::squashFromDecode(const Addr &new_PC,
> const InstSeqNum &seq_num)
587c326
< DPRINTF(Fetch, "[tid:%i]: Squashing from decode.\n",tid);
---
> DPRINTF(Fetch, "Fetch: Squashing from decode.\n");
589c328
< doSquash(new_PC, tid);
---
> doSquash(new_PC);
593c332
< cpu->removeInstsUntil(seq_num, tid);
---
> cpu->removeInstsUntil(seq_num);
596,661d334
< template<class Impl>
< bool
< DefaultFetch<Impl>::checkStall(unsigned tid) const
< {
< bool ret_val = false;
<
< if (cpu->contextSwitch) {
< DPRINTF(Fetch,"[tid:%i]: Stalling for a context switch.\n",tid);
< ret_val = true;
< } else if (stalls[tid].decode) {
< DPRINTF(Fetch,"[tid:%i]: Stall from Decode stage detected.\n",tid);
< ret_val = true;
< } else if (stalls[tid].rename) {
< DPRINTF(Fetch,"[tid:%i]: Stall from Rename stage detected.\n",tid);
< ret_val = true;
< } else if (stalls[tid].iew) {
< DPRINTF(Fetch,"[tid:%i]: Stall from IEW stage detected.\n",tid);
< ret_val = true;
< } else if (stalls[tid].commit) {
< DPRINTF(Fetch,"[tid:%i]: Stall from Commit stage detected.\n",tid);
< ret_val = true;
< }
<
< return ret_val;
< }
<
< template<class Impl>
< typename DefaultFetch<Impl>::FetchStatus
< DefaultFetch<Impl>::updateFetchStatus()
< {
< //Check Running
< list<unsigned>::iterator threads = (*activeThreads).begin();
<
< while (threads != (*activeThreads).end()) {
<
< unsigned tid = *threads++;
<
< if (fetchStatus[tid] == Running ||
< fetchStatus[tid] == Squashing ||
< fetchStatus[tid] == IcacheMissComplete) {
<
< if (_status == Inactive) {
< DPRINTF(Activity, "[tid:%i]: Activating stage.\n",tid);
<
< if (fetchStatus[tid] == IcacheMissComplete) {
< DPRINTF(Activity, "[tid:%i]: Activating fetch due to cache"
< "completion\n",tid);
< }
<
< cpu->activateStage(FullCPU::FetchIdx);
< }
<
< return Active;
< }
< }
<
< // Stage is switching from active to inactive, notify CPU of it.
< if (_status == Active) {
< DPRINTF(Activity, "Deactivating stage.\n");
<
< cpu->deactivateStage(FullCPU::FetchIdx);
< }
<
< return Inactive;
< }
<
664c337
< DefaultFetch<Impl>::squash(const Addr &new_PC, unsigned tid)
---
> SimpleFetch<Impl>::squash(const Addr &new_PC)
666c339
< DPRINTF(Fetch, "[tid:%u]: Squash from commit.\n",tid);
---
> DPRINTF(Fetch, "Fetch: Squash from commit.\n");
668c341
< doSquash(new_PC, tid);
---
> doSquash(new_PC);
671c344
< cpu->removeInstsNotInROB(tid);
---
> cpu->removeInstsNotInROB();
674c347
< template <class Impl>
---
> template<class Impl>
676c349
< DefaultFetch<Impl>::tick()
---
> SimpleFetch<Impl>::tick()
678,770d350
< list<unsigned>::iterator threads = (*activeThreads).begin();
< bool status_change = false;
<
< wroteToTimeBuffer = false;
<
< while (threads != (*activeThreads).end()) {
< unsigned tid = *threads++;
<
< // Check the signals for each thread to determine the proper status
< // for each thread.
< bool updated_status = checkSignalsAndUpdate(tid);
< status_change = status_change || updated_status;
< }
<
< DPRINTF(Fetch, "Running stage.\n");
<
< // Reset the number of the instruction we're fetching.
< numInst = 0;
<
< if (fromCommit->commitInfo[0].interruptPending) {
< interruptPending = true;
< }
< if (fromCommit->commitInfo[0].clearInterrupt) {
< interruptPending = false;
< }
<
< for (threadFetched = 0; threadFetched < numFetchingThreads;
< threadFetched++) {
< // Fetch each of the actively fetching threads.
< fetch(status_change);
< }
<
< // Record number of instructions fetched this cycle for distribution.
< fetchNisnDist.sample(numInst);
<
< if (status_change) {
< // Change the fetch stage status if there was a status change.
< _status = updateFetchStatus();
< }
<
< // If there was activity this cycle, inform the CPU of it.
< if (wroteToTimeBuffer || cpu->contextSwitch) {
< DPRINTF(Activity, "Activity this cycle.\n");
<
< cpu->activityThisCycle();
< }
< }
<
< template <class Impl>
< bool
< DefaultFetch<Impl>::checkSignalsAndUpdate(unsigned tid)
< {
< // Update the per thread stall statuses.
< if (fromDecode->decodeBlock[tid]) {
< stalls[tid].decode = true;
< }
<
< if (fromDecode->decodeUnblock[tid]) {
< assert(stalls[tid].decode);
< assert(!fromDecode->decodeBlock[tid]);
< stalls[tid].decode = false;
< }
<
< if (fromRename->renameBlock[tid]) {
< stalls[tid].rename = true;
< }
<
< if (fromRename->renameUnblock[tid]) {
< assert(stalls[tid].rename);
< assert(!fromRename->renameBlock[tid]);
< stalls[tid].rename = false;
< }
<
< if (fromIEW->iewBlock[tid]) {
< stalls[tid].iew = true;
< }
<
< if (fromIEW->iewUnblock[tid]) {
< assert(stalls[tid].iew);
< assert(!fromIEW->iewBlock[tid]);
< stalls[tid].iew = false;
< }
<
< if (fromCommit->commitBlock[tid]) {
< stalls[tid].commit = true;
< }
<
< if (fromCommit->commitUnblock[tid]) {
< assert(stalls[tid].commit);
< assert(!fromCommit->commitBlock[tid]);
< stalls[tid].commit = false;
< }
<
772c352,354
< if (fromCommit->commitInfo[tid].squash) {
---
> if (fromCommit->commitInfo.squash) {
> DPRINTF(Fetch, "Fetch: Squashing instructions due to squash "
> "from commit.\n");
774,776d355
< DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash "
< "from commit.\n",tid);
<
778c357
< squash(fromCommit->commitInfo[tid].nextPC,tid);
---
> squash(fromCommit->commitInfo.nextPC);
781,785c360,363
< if (fromCommit->commitInfo[tid].branchMispredict) {
< branchPred.squash(fromCommit->commitInfo[tid].doneSeqNum,
< fromCommit->commitInfo[tid].nextPC,
< fromCommit->commitInfo[tid].branchTaken,
< tid);
---
> if (fromCommit->commitInfo.branchMispredict) {
> branchPred.squash(fromCommit->commitInfo.doneSeqNum,
> fromCommit->commitInfo.nextPC,
> fromCommit->commitInfo.branchTaken);
787,788c365
< branchPred.squash(fromCommit->commitInfo[tid].doneSeqNum,
< tid);
---
> branchPred.squash(fromCommit->commitInfo.doneSeqNum);
791,792c368,369
< return true;
< } else if (fromCommit->commitInfo[tid].doneSeqNum) {
---
> return;
> } else if (fromCommit->commitInfo.doneSeqNum) {
794,795c371,372
< // that was broadcasted.
< branchPred.update(fromCommit->commitInfo[tid].doneSeqNum, tid);
---
> // that was braodcasted.
> branchPred.update(fromCommit->commitInfo.doneSeqNum);
799,800c376,377
< if (fromCommit->commitInfo[tid].robSquashing) {
< DPRINTF(Fetch, "[tid:%u]: ROB is still squashing Thread %u.\n", tid);
---
> if (fromCommit->commitInfo.robSquashing) {
> DPRINTF(Fetch, "Fetch: ROB is still squashing.\n");
803c380
< fetchStatus[tid] = Squashing;
---
> _status = Squashing;
805c382,383
< return true;
---
> ++fetchSquashCycles;
> return;
809,811c387,389
< if (fromDecode->decodeInfo[tid].squash) {
< DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash "
< "from decode.\n",tid);
---
> if (fromDecode->decodeInfo.squash) {
> DPRINTF(Fetch, "Fetch: Squashing instructions due to squash "
> "from decode.\n");
814,818c392,395
< if (fromDecode->decodeInfo[tid].branchMispredict) {
< branchPred.squash(fromDecode->decodeInfo[tid].doneSeqNum,
< fromDecode->decodeInfo[tid].nextPC,
< fromDecode->decodeInfo[tid].branchTaken,
< tid);
---
> if (fromDecode->decodeInfo.branchMispredict) {
> branchPred.squash(fromDecode->decodeInfo.doneSeqNum,
> fromDecode->decodeInfo.nextPC,
> fromDecode->decodeInfo.branchTaken);
820,821c397
< branchPred.squash(fromDecode->decodeInfo[tid].doneSeqNum,
< tid);
---
> branchPred.squash(fromDecode->decodeInfo.doneSeqNum);
824,830c400,404
< if (fetchStatus[tid] != Squashing) {
< // Squash unless we're already squashing
< squashFromDecode(fromDecode->decodeInfo[tid].nextPC,
< fromDecode->decodeInfo[tid].doneSeqNum,
< tid);
<
< return true;
---
> if (_status != Squashing) {
> // Squash unless we're already squashing?
> squashFromDecode(fromDecode->decodeInfo.nextPC,
> fromDecode->decodeInfo.doneSeqNum);
> return;
834,835c408,414
< if (checkStall(tid) && fetchStatus[tid] != IcacheMissStall) {
< DPRINTF(Fetch, "[tid:%i]: Setting to blocked\n",tid);
---
> // Check if any of the stall signals are high.
> if (fromDecode->decodeInfo.stall ||
> fromRename->renameInfo.stall ||
> fromIEW->iewInfo.stall ||
> fromCommit->commitInfo.stall)
> {
> // Block stage, regardless of current status.
837c416,422
< fetchStatus[tid] = Blocked;
---
> DPRINTF(Fetch, "Fetch: Stalling stage.\n");
> DPRINTF(Fetch, "Fetch: Statuses: Decode: %i Rename: %i IEW: %i "
> "Commit: %i\n",
> fromDecode->decodeInfo.stall,
> fromRename->renameInfo.stall,
> fromIEW->iewInfo.stall,
> fromCommit->commitInfo.stall);
839c424,434
< return true;
---
> _status = Blocked;
>
> ++fetchBlockedCycles;
> return;
> } else if (_status == Blocked) {
> // Unblock stage if status is currently blocked and none of the
> // stall signals are being held high.
> _status = Running;
>
> ++fetchBlockedCycles;
> return;
842,847c437,444
< if (fetchStatus[tid] == Blocked ||
< fetchStatus[tid] == Squashing) {
< // Switch status to running if fetch isn't being told to block or
< // squash this cycle.
< DPRINTF(Fetch, "[tid:%i]: Done squashing, switching to running.\n",
< tid);
---
> // If fetch has reached this point, then there are no squash signals
> // still being held high. Check if fetch is in the squashing state;
> // if so, fetch can switch to running.
> // Similarly, there are no blocked signals still being held high.
> // Check if fetch is in the blocked state; if so, fetch can switch to
> // running.
> if (_status == Squashing) {
> DPRINTF(Fetch, "Fetch: Done squashing, switching to running.\n");
849c446,447
< fetchStatus[tid] = Running;
---
> // Switch status to running
> _status = Running;
851,852c449
< return true;
< }
---
> ++fetchCycles;
854,856c451,458
< // If we've reached this point, we have not gotten any signals that
< // cause fetch to change its status. Fetch remains the same as before.
< return false;
---
> fetch();
> } else if (_status != IcacheMissStall) {
> DPRINTF(Fetch, "Fetch: Running stage.\n");
>
> ++fetchCycles;
>
> fetch();
> }
861c463
< DefaultFetch<Impl>::fetch(bool &status_change)
---
> SimpleFetch<Impl>::fetch()
866d467
< int tid = getFetchingThread(fetchPolicy);
868,875d468
< if (tid == -1) {
< DPRINTF(Fetch,"There are no more threads available to fetch from.\n");
<
< // Breaks looping condition in tick()
< threadFetched = numFetchingThreads;
< return;
< }
<
877c470
< Addr &fetch_PC = PC[tid];
---
> Addr fetch_PC = cpu->readPC();
885,887c478,479
< if (fetchStatus[tid] == IcacheMissComplete) {
< DPRINTF(Fetch, "[tid:%i]: Icache miss is complete.\n",
< tid);
---
> if (_status == IcacheMissComplete) {
> DPRINTF(Fetch, "Fetch: Icache miss is complete.\n");
889,894c481,482
< fetchStatus[tid] = Running;
< status_change = true;
< } else if (fetchStatus[tid] == Running) {
< DPRINTF(Fetch, "[tid:%i]: Attempting to translate and read "
< "instruction, starting at PC %08p.\n",
< tid, fetch_PC);
---
> // Reset the completion event to NULL.
> memReq->completionEvent = NULL;
896,900c484
< bool fetch_success = fetchCacheLine(fetch_PC, fault, tid);
< if (!fetch_success) {
< ++fetchMiscStallCycles;
< return;
< }
---
> _status = Running;
902,910c486,488
< if (fetchStatus[tid] == Idle) {
< ++fetchIdleCycles;
< } else if (fetchStatus[tid] == Blocked) {
< ++fetchBlockedCycles;
< } else if (fetchStatus[tid] == Squashing) {
< ++fetchSquashCycles;
< } else if (fetchStatus[tid] == IcacheMissStall) {
< ++icacheStallCycles;
< }
---
> DPRINTF(Fetch, "Fetch: Attempting to translate and read "
> "instruction, starting at PC %08p.\n",
> fetch_PC);
912,914c490
< // Status is Idle, Squashing, Blocked, or IcacheMissStall, so
< // fetch should do nothing.
< return;
---
> fault = fetchCacheLine(fetch_PC);
917,922c493,496
< ++fetchCycles;
<
< // If we had a stall due to an icache miss, then return.
< if (fetchStatus[tid] == IcacheMissStall) {
< ++icacheStallCycles;
< status_change = true;
---
> // If we had a stall due to an icache miss, then return. It'd
> // be nicer if this were handled through the kind of fault that
> // is returned by the function.
> if (_status == IcacheMissStall) {
925a500,504
> // As far as timing goes, the CPU will need to send an event through
> // the MemReq in order to be woken up once the memory access completes.
> // Probably have a status on a per thread basis so each thread can
> // block independently and be woken up independently.
>
929,931c508,509
< ExtMachInst ext_inst;
< // @todo: Fix this hack.
< unsigned offset = (fetch_PC & cacheBlkMask) & ~3;
---
> unsigned offset = fetch_PC & cacheBlkMask;
> unsigned fetched;
938,939c516
< DPRINTF(Fetch, "[tid:%i]: Adding instructions to queue to "
< "decode.\n",tid);
---
> DPRINTF(Fetch, "Fetch: Adding instructions to queue to decode.\n");
940a518,521
> //////////////////////////
> // Fetch first instruction
> //////////////////////////
>
945c526
< for (;
---
> for (fetched = 0;
947c528
< numInst < fetchWidth &&
---
> fetched < fetchWidth &&
949c530,531
< ++numInst) {
---
> ++fetched)
> {
959c541
< (&cacheData[tid][offset]));
---
> (&cacheData[offset]));
961,962d542
< ext_inst = TheISA::makeExtMI(inst, fetch_PC);
<
964,965c544
< DynInstPtr instruction = new DynInst(ext_inst, fetch_PC,
< next_PC,
---
> DynInstPtr instruction = new DynInst(inst, fetch_PC, next_PC,
967d545
< instruction->setThread(tid);
969c547,548
< instruction->setASID(tid);
---
> DPRINTF(Fetch, "Fetch: Instruction %i created, with PC %#x\n",
> inst_seq, instruction->readPC());
971c550,551
< instruction->setState(cpu->thread[tid]);
---
> DPRINTF(Fetch, "Fetch: Instruction opcode is: %03p\n",
> OPCODE(inst));
973,979d552
< DPRINTF(Fetch, "[tid:%i]: Instruction PC %#x created "
< "[sn:%lli]\n",
< tid, instruction->readPC(), inst_seq);
<
< DPRINTF(Fetch, "[tid:%i]: Instruction is: %s\n",
< tid, instruction->staticInst->disassemble(fetch_PC));
<
981c554
< Trace::getInstRecord(curTick, cpu->xcBase(tid), cpu,
---
> Trace::getInstRecord(curTick, cpu->xcBase(), cpu,
983c556
< instruction->readPC(),tid);
---
> instruction->readPC(), 0);
988c561
< instruction->setInstListIt(cpu->addInst(instruction));
---
> cpu->addInst(instruction);
992c565
< toDecode->insts[numInst] = instruction;
---
> toDecode->insts[fetched] = instruction;
1002,1010d574
< if (instruction->isQuiesce()) {
< warn("%lli: Quiesce instruction encountered, halting fetch!",
< curTick);
< fetchStatus[tid] = QuiescePending;
< ++numInst;
< status_change = true;
< break;
< }
<
1013d576
< }
1015,1016c578
< if (numInst > 0) {
< wroteToTimeBuffer = true;
---
> fetch_nisn_dist.sample(fetched);
1020c582,586
< // cycle will be.
---
> // cycle will be. Might want to move this to the beginning of this
> // function so that the PC updates at the beginning of everything.
> // Or might want to leave setting the PC to the main CPU, with fetch
> // only changing the nextPC (will require correct determination of
> // next PC).
1022,1025c588,590
< DPRINTF(Fetch, "[tid:%i]: Setting PC to %08p.\n",tid, next_PC);
<
< PC[tid] = next_PC;
< nextPC[tid] = next_PC + instSize;
---
> DPRINTF(Fetch, "Fetch: Setting PC to %08p.\n", next_PC);
> cpu->setPC(next_PC);
> cpu->setNextPC(next_PC + instSize);
1027,1030c592,595
< // We shouldn't be in an icache miss and also have a fault (an ITB
< // miss)
< if (fetchStatus[tid] == IcacheMissStall) {
< panic("Fetch should have exited prior to this!");
---
> // If the issue was an icache miss, then we can just return and
> // wait until it is handled.
> if (_status == IcacheMissStall) {
> return;
1033,1041c598,605
< // Send the fault to commit. This thread will not do anything
< // until commit handles the fault. The only other way it can
< // wake up is if a squash comes along and changes the PC.
< #if FULL_SYSTEM
< assert(numInst != fetchWidth);
< // Get a sequence number.
< inst_seq = cpu->getAndIncrementInstSeq();
< // We will use a nop in order to carry the fault.
< ext_inst = TheISA::NoopMachInst;
---
> // Handle the fault.
> // This stage will not be able to continue until all the ROB
> // slots are empty, at which point the fault can be handled.
> // The only other way it can wake up is if a squash comes along
> // and changes the PC. Not sure how to handle that case...perhaps
> // have it handled by the upper level CPU class which peeks into the
> // time buffer and sees if a squash comes along, in which case it
> // changes the status.
1043,1048c607
< // Create a new DynInst from the dummy nop.
< DynInstPtr instruction = new DynInst(ext_inst, fetch_PC,
< next_PC,
< inst_seq, cpu);
< instruction->setPredTarg(next_PC + instSize);
< instruction->setThread(tid);
---
> DPRINTF(Fetch, "Fetch: Blocked, need to handle the trap.\n");
1050,1068c609,614
< instruction->setASID(tid);
<
< instruction->setState(cpu->thread[tid]);
<
< instruction->traceData = NULL;
<
< instruction->setInstListIt(cpu->addInst(instruction));
<
< instruction->fault = fault;
<
< toDecode->insts[numInst] = instruction;
< toDecode->size++;
<
< DPRINTF(Fetch, "[tid:%i]: Blocked, need to handle the trap.\n",tid);
<
< fetchStatus[tid] = TrapPending;
< status_change = true;
<
< warn("%lli fault (%d) detected @ PC %08p", curTick, fault, PC[tid]);
---
> _status = Blocked;
> #if FULL_SYSTEM
> // cpu->trap(fault);
> // Send a signal to the ROB indicating that there's a trap from the
> // fetch stage that needs to be handled. Need to indicate that
> // there's a fault, and the fault type.
1070c616
< fatal("fault (%d) detected @ PC %08p", fault, PC[tid]);
---
> fatal("fault (%d) detected @ PC %08p", fault, cpu->readPC());
1074,1219d619
<
<
< ///////////////////////////////////////
< // //
< // SMT FETCH POLICY MAINTAINED HERE //
< // //
< ///////////////////////////////////////
< template<class Impl>
< int
< DefaultFetch<Impl>::getFetchingThread(FetchPriority &fetch_priority)
< {
< if (numThreads > 1) {
< switch (fetch_priority) {
<
< case SingleThread:
< return 0;
<
< case RoundRobin:
< return roundRobin();
<
< case IQ:
< return iqCount();
<
< case LSQ:
< return lsqCount();
<
< case Branch:
< return branchCount();
<
< default:
< return -1;
< }
< } else {
< int tid = *((*activeThreads).begin());
<
< if (fetchStatus[tid] == Running ||
< fetchStatus[tid] == IcacheMissComplete ||
< fetchStatus[tid] == Idle) {
< return tid;
< } else {
< return -1;
< }
< }
<
< }
<
<
< template<class Impl>
< int
< DefaultFetch<Impl>::roundRobin()
< {
< list<unsigned>::iterator pri_iter = priorityList.begin();
< list<unsigned>::iterator end = priorityList.end();
<
< int high_pri;
<
< while (pri_iter != end) {
< high_pri = *pri_iter;
<
< assert(high_pri <= numThreads);
<
< if (fetchStatus[high_pri] == Running ||
< fetchStatus[high_pri] == IcacheMissComplete ||
< fetchStatus[high_pri] == Idle) {
<
< priorityList.erase(pri_iter);
< priorityList.push_back(high_pri);
<
< return high_pri;
< }
<
< pri_iter++;
< }
<
< return -1;
< }
<
< template<class Impl>
< int
< DefaultFetch<Impl>::iqCount()
< {
< priority_queue<unsigned> PQ;
<
< list<unsigned>::iterator threads = (*activeThreads).begin();
<
< while (threads != (*activeThreads).end()) {
< unsigned tid = *threads++;
<
< PQ.push(fromIEW->iewInfo[tid].iqCount);
< }
<
< while (!PQ.empty()) {
<
< unsigned high_pri = PQ.top();
<
< if (fetchStatus[high_pri] == Running ||
< fetchStatus[high_pri] == IcacheMissComplete ||
< fetchStatus[high_pri] == Idle)
< return high_pri;
< else
< PQ.pop();
<
< }
<
< return -1;
< }
<
< template<class Impl>
< int
< DefaultFetch<Impl>::lsqCount()
< {
< priority_queue<unsigned> PQ;
<
<
< list<unsigned>::iterator threads = (*activeThreads).begin();
<
< while (threads != (*activeThreads).end()) {
< unsigned tid = *threads++;
<
< PQ.push(fromIEW->iewInfo[tid].ldstqCount);
< }
<
< while (!PQ.empty()) {
<
< unsigned high_pri = PQ.top();
<
< if (fetchStatus[high_pri] == Running ||
< fetchStatus[high_pri] == IcacheMissComplete ||
< fetchStatus[high_pri] == Idle)
< return high_pri;
< else
< PQ.pop();
<
< }
<
< return -1;
< }
<
< template<class Impl>
< int
< DefaultFetch<Impl>::branchCount()
< {
< list<unsigned>::iterator threads = (*activeThreads).begin();
<
< return *threads;
< }