2c2
< * Copyright (c) 2004-2005 The Regents of The University of Michigan
---
> * Copyright (c) 2004-2006 The Regents of The University of Michigan
27,28d26
< *
< * Authors: Kevin Lim
31,33d28
< // Remove this later; used only for debugging.
< #define OPCODE(X) (X >> 26) & 0x3f
<
35c30
< #include "sim/byteswap.hh"
---
> #include "arch/utility.hh"
37,39d31
< #include "mem/base_mem.hh"
< #include "mem/mem_interface.hh"
< #include "mem/mem_req.hh"
41c33,36
<
---
> #include "mem/packet.hh"
> #include "mem/request.hh"
> #include "sim/byteswap.hh"
> #include "sim/host.hh"
43a39,52
> #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"
> #endif // FULL_SYSTEM
>
> #include <algorithm>
>
> using namespace std;
> using namespace TheISA;
>
45,48c54,55
< SimpleFetch<Impl>::CacheCompletionEvent
< ::CacheCompletionEvent(SimpleFetch *_fetch)
< : Event(&mainEventQueue),
< fetch(_fetch)
---
> Tick
> DefaultFetch<Impl>::IcachePort::recvAtomic(PacketPtr pkt)
49a57,58
> panic("DefaultFetch doesn't expect recvAtomic callback!");
> return curTick;
54c63
< SimpleFetch<Impl>::CacheCompletionEvent::process()
---
> DefaultFetch<Impl>::IcachePort::recvFunctional(PacketPtr pkt)
56c65
< fetch->processCacheCompletion();
---
> panic("DefaultFetch doesn't expect recvFunctional callback!");
60,61c69,70
< const char *
< SimpleFetch<Impl>::CacheCompletionEvent::description()
---
> void
> DefaultFetch<Impl>::IcachePort::recvStatusChange(Status status)
63c72,75
< return "SimpleFetch cache completion event";
---
> if (status == RangeChange)
> return;
>
> panic("DefaultFetch doesn't expect recvStatusChange callback!");
67,74c79,80
< SimpleFetch<Impl>::SimpleFetch(Params &params)
< : icacheInterface(params.icacheInterface),
< branchPred(params),
< decodeToFetchDelay(params.decodeToFetchDelay),
< renameToFetchDelay(params.renameToFetchDelay),
< iewToFetchDelay(params.iewToFetchDelay),
< commitToFetchDelay(params.commitToFetchDelay),
< fetchWidth(params.fetchWidth)
---
> bool
> DefaultFetch<Impl>::IcachePort::recvTiming(Packet *pkt)
76c82,84
< DPRINTF(Fetch, "Fetch: Fetch constructor called\n");
---
> fetch->processCacheCompletion(pkt);
> return true;
> }
78,79c86,102
< // Set status to idle.
< _status = Idle;
---
> template<class Impl>
> void
> DefaultFetch<Impl>::IcachePort::recvRetry()
> {
> panic("DefaultFetch doesn't support retry yet.");
> // we shouldn't get a retry unless we have a packet that we're
> // waiting to transmit
> /*
> assert(cpu->dcache_pkt != NULL);
> assert(cpu->_status == DcacheRetry);
> Packet *tmp = cpu->dcache_pkt;
> if (sendTiming(tmp)) {
> cpu->_status = DcacheWaitResponse;
> cpu->dcache_pkt = NULL;
> }
> */
> }
81,90c104,117
< // 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];
---
> template<class Impl>
> DefaultFetch<Impl>::DefaultFetch(Params *params)
> : branchPred(params),
> decodeToFetchDelay(params->decodeToFetchDelay),
> renameToFetchDelay(params->renameToFetchDelay),
> iewToFetchDelay(params->iewToFetchDelay),
> commitToFetchDelay(params->commitToFetchDelay),
> fetchWidth(params->fetchWidth),
> numThreads(params->numberOfThreads),
> numFetchingThreads(params->smtNumFetchingThreads),
> interruptPending(false)
> {
> if (numThreads > Impl::MaxThreads)
> fatal("numThreads is not a valid value\n");
91a119,149
> DPRINTF(Fetch, "Fetch constructor called\n");
>
> // Set fetch stage's status to inactive.
> _status = Inactive;
>
> 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");
> }
>
93c151
< cacheBlkSize = icacheInterface ? icacheInterface->getBlockSize() : 64;
---
> cacheBlkSize = 64;
97a156,172
> for (int tid=0; tid < numThreads; tid++) {
>
> fetchStatus[tid] = Running;
>
> priorityList.push_back(tid);
>
> memPkt[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;
> }
>
99a175
> }
101,102c177,181
< // Create space to store a cache line.
< cacheData = new uint8_t[cacheBlkSize];
---
> template <class Impl>
> std::string
> DefaultFetch<Impl>::name() const
> {
> return cpu->name() + ".fetch";
107c186
< SimpleFetch<Impl>::regStats()
---
> DefaultFetch<Impl>::regStats()
110c189
< .name(name() + ".icacheStallCycles")
---
> .name(name() + ".FETCH:icacheStallCycles")
115c194
< .name(name() + ".fetchedInsts")
---
> .name(name() + ".FETCH:Insts")
117a197,202
>
> fetchedBranches
> .name(name() + ".FETCH:Branches")
> .desc("Number of branches that fetch encountered")
> .prereq(fetchedBranches);
>
119c204
< .name(name() + ".predictedBranches")
---
> .name(name() + ".FETCH:predictedBranches")
121a207
>
123c209
< .name(name() + ".fetchCycles")
---
> .name(name() + ".FETCH:Cycles")
126a213
>
128c215
< .name(name() + ".fetchSquashCycles")
---
> .name(name() + ".FETCH:SquashCycles")
130a218,223
>
> fetchIdleCycles
> .name(name() + ".FETCH:IdleCycles")
> .desc("Number of cycles fetch was idle")
> .prereq(fetchIdleCycles);
>
132c225
< .name(name() + ".fetchBlockedCycles")
---
> .name(name() + ".FETCH:BlockedCycles")
134a228
>
136c230
< .name(name() + ".fetchedCacheLines")
---
> .name(name() + ".FETCH:CacheLines")
140c234,245
< fetch_nisn_dist
---
> 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
144c249
< .name(name() + ".FETCH:rate_dist")
---
> .name(name() + ".FETCH:rateDist")
146,147c251
< .flags(Stats::pdf)
< ;
---
> .flags(Stats::pdf);
148a253,270
> 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;
>
154c276
< SimpleFetch<Impl>::setCPU(FullCPU *cpu_ptr)
---
> DefaultFetch<Impl>::setCPU(FullCPU *cpu_ptr)
156c278
< DPRINTF(Fetch, "Fetch: Setting the CPU pointer.\n");
---
> DPRINTF(Fetch, "Setting the CPU pointer.\n");
158,159c280,286
< // This line will be removed eventually.
< memReq->xc = cpu->xcBase();
---
>
> // Name is finally available, so create the port.
> icachePort = new IcachePort(this);
>
> // Fetch needs to start fetching instructions at the very beginning,
> // so it must start up in active state.
> switchToActive();
164c291
< SimpleFetch<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer)
---
> DefaultFetch<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer)
166c293
< DPRINTF(Fetch, "Fetch: Setting the time buffer pointer.\n");
---
> DPRINTF(Fetch, "Setting the time buffer pointer.\n");
178c305
< SimpleFetch<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
---
> DefaultFetch<Impl>::setActiveThreads(list<unsigned> *at_ptr)
180c307,315
< DPRINTF(Fetch, "Fetch: Setting the fetch queue pointer.\n");
---
> 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");
186a322
> #if 0
189c325
< SimpleFetch<Impl>::processCacheCompletion()
---
> DefaultFetch<Impl>::setPageTable(PageTable *pt_ptr)
191c327,332
< DPRINTF(Fetch, "Fetch: Waking up from cache miss.\n");
---
> DPRINTF(Fetch, "Setting the page table pointer.\n");
> #if !FULL_SYSTEM
> pTable = pt_ptr;
> #endif
> }
> #endif
192a334,351
> 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(PacketPtr pkt)
> {
> unsigned tid = pkt->req->getThreadNum();
>
> DPRINTF(Fetch, "[tid:%u] Waking up from cache miss.\n",tid);
>
197,198c356,385
< if (_status == IcacheMissStall)
< _status = IcacheMissComplete;
---
> if (fetchStatus[tid] != IcacheWaitResponse ||
> pkt != memPkt[tid] ||
> isSwitchedOut()) {
> ++fetchIcacheSquashes;
> delete pkt;
> 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 IcacheAccessComplete if we're not stalled as well.
> if (checkStall(tid)) {
> fetchStatus[tid] = Blocked;
> } else {
> fetchStatus[tid] = IcacheAccessComplete;
> }
>
> // memcpy(cacheData[tid], memReq[tid]->data, memReq[tid]->size);
>
> // Reset the mem req to NULL.
> delete pkt->req;
> delete pkt;
> memPkt[tid] = NULL;
201a389,459
> 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>
203c461
< SimpleFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC)
---
> DefaultFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC)
216c474
< predict_taken = branchPred.predict(inst, next_PC);
---
> predict_taken = branchPred.predict(inst, next_PC, inst->threadNumber);
217a476,477
> ++fetchedBranches;
>
226,227c486,487
< Fault
< SimpleFetch<Impl>::fetchCacheLine(Addr fetch_PC)
---
> bool
> DefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid)
229,232c489
< // 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.
---
> Fault fault = NoFault;
236c493
< unsigned flags = cpu->inPalMode() ? PHYSICAL : 0;
---
> unsigned flags = cpu->inPalMode(fetch_PC) ? PHYSICAL : 0;
241c498,502
< Fault fault = NoFault;
---
> if (interruptPending && flags == 0 || switchedOut) {
> // Hold off fetch from getting new instructions while an interrupt
> // is pending.
> return false;
> }
246c507
< // Setup the memReq to do a read of the first isntruction's address.
---
> // Setup the memReq to do a read of the first instruction's address.
248,249c509,511
< memReq->cmd = Read;
< memReq->reset(fetch_PC, cacheBlkSize, flags);
---
> // Build request here.
> RequestPtr mem_req = new Request(tid, fetch_PC, cacheBlkSize, flags,
> fetch_PC, cpu->readCpuId(), tid);
250a513,514
> memPkt[tid] = NULL;
>
252,254c516,520
< // Should this function be
< // in the CPU class ? Probably...ITB/DTB should exist within the
< // CPU.
---
> //#if FULL_SYSTEM
> fault = cpu->translateInstReq(mem_req);
> //#else
> // fault = pTable->translate(memReq[tid]);
> //#endif
256,257d521
< fault = cpu->translateInstReq(memReq);
<
259c523
< // on what caused the fetch (ITB or Icache miss).
---
> // for the ITB miss to be handled.
263a528,543
> #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
>
> // Build packet here.
> PacketPtr data_pkt = new Packet(mem_req,
> Packet::ReadReq, Packet::Broadcast);
> data_pkt->dataStatic(cacheData[tid]);
>
265,266d544
< fault = cpu->mem->read(memReq, cacheData);
< // This read may change when the mem interface changes.
269d546
< }
271,275c548,554
< // 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;
---
> // Now do the timing access to see whether or not the instruction
> // exists within the cache.
> if (!icachePort->sendTiming(data_pkt)) {
> DPRINTF(Fetch, "[tid:%i] Out of MSHRs!\n", tid);
> ret_fault = NoFault;
> return false;
> }
277c556
< memReq->time = curTick;
---
> DPRINTF(Fetch, "Doing cache access.\n");
279c558
< MemAccessResult result = icacheInterface->access(memReq);
---
> lastIcacheStall[tid] = curTick;
281,285c560,561
< // 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);
---
> DPRINTF(Activity, "[tid:%i]: Activity: Waiting on I-cache "
> "response.\n", tid);
287,294c563
< // 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.
<
< DPRINTF(Fetch, "Fetch: Stalling due to icache miss.\n");
< _status = IcacheMissStall;
< }
---
> fetchStatus[tid] = IcacheWaitResponse;
297c566,567
< return fault;
---
> ret_fault = fault;
> return true;
302c572
< SimpleFetch<Impl>::doSquash(const Addr &new_PC)
---
> DefaultFetch<Impl>::doSquash(const Addr &new_PC, unsigned tid)
304c574,575
< DPRINTF(Fetch, "Fetch: Squashing, setting PC to: %#x.\n", new_PC);
---
> DPRINTF(Fetch, "[tid:%i]: Squashing, setting PC to: %#x.\n",
> tid, new_PC);
306,307c577,578
< cpu->setNextPC(new_PC + instSize);
< cpu->setPC(new_PC);
---
> PC[tid] = new_PC;
> nextPC[tid] = new_PC + instSize;
310,313c581,585
< if (_status == IcacheMissStall && icacheInterface) {
< DPRINTF(Fetch, "Fetch: Squashing outstanding Icache miss.\n");
< // @todo: Use an actual thread number here.
< icacheInterface->squash(0);
---
> if (fetchStatus[tid] == IcacheWaitResponse) {
> DPRINTF(Fetch, "[tid:%i]: Squashing outstanding Icache miss.\n",
> tid);
> delete memPkt[tid];
> memPkt[tid] = NULL;
316c588
< _status = Squashing;
---
> fetchStatus[tid] = Squashing;
323,324c595,597
< SimpleFetch<Impl>::squashFromDecode(const Addr &new_PC,
< const InstSeqNum &seq_num)
---
> DefaultFetch<Impl>::squashFromDecode(const Addr &new_PC,
> const InstSeqNum &seq_num,
> unsigned tid)
326c599
< DPRINTF(Fetch, "Fetch: Squashing from decode.\n");
---
> DPRINTF(Fetch, "[tid:%i]: Squashing from decode.\n",tid);
328c601
< doSquash(new_PC);
---
> doSquash(new_PC, tid);
332c605
< cpu->removeInstsUntil(seq_num);
---
> cpu->removeInstsUntil(seq_num, tid);
334a608,673
> 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] == IcacheAccessComplete) {
>
> if (_status == Inactive) {
> DPRINTF(Activity, "[tid:%i]: Activating stage.\n",tid);
>
> if (fetchStatus[tid] == IcacheAccessComplete) {
> 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;
> }
>
337c676
< SimpleFetch<Impl>::squash(const Addr &new_PC)
---
> DefaultFetch<Impl>::squash(const Addr &new_PC, unsigned tid)
339c678
< DPRINTF(Fetch, "Fetch: Squash from commit.\n");
---
> DPRINTF(Fetch, "[tid:%u]: Squash from commit.\n",tid);
341c680
< doSquash(new_PC);
---
> doSquash(new_PC, tid);
344c683
< cpu->removeInstsNotInROB();
---
> cpu->removeInstsNotInROB(tid);
347c686
< template<class Impl>
---
> template <class Impl>
349c688
< SimpleFetch<Impl>::tick()
---
> DefaultFetch<Impl>::tick()
350a690,782
> 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;
> }
>
352,354c784
< if (fromCommit->commitInfo.squash) {
< DPRINTF(Fetch, "Fetch: Squashing instructions due to squash "
< "from commit.\n");
---
> if (fromCommit->commitInfo[tid].squash) {
355a786,788
> DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash "
> "from commit.\n",tid);
>
357c790
< squash(fromCommit->commitInfo.nextPC);
---
> squash(fromCommit->commitInfo[tid].nextPC,tid);
360,363c793,797
< if (fromCommit->commitInfo.branchMispredict) {
< branchPred.squash(fromCommit->commitInfo.doneSeqNum,
< fromCommit->commitInfo.nextPC,
< fromCommit->commitInfo.branchTaken);
---
> if (fromCommit->commitInfo[tid].branchMispredict) {
> branchPred.squash(fromCommit->commitInfo[tid].doneSeqNum,
> fromCommit->commitInfo[tid].nextPC,
> fromCommit->commitInfo[tid].branchTaken,
> tid);
365c799,800
< branchPred.squash(fromCommit->commitInfo.doneSeqNum);
---
> branchPred.squash(fromCommit->commitInfo[tid].doneSeqNum,
> tid);
368,369c803,804
< return;
< } else if (fromCommit->commitInfo.doneSeqNum) {
---
> return true;
> } else if (fromCommit->commitInfo[tid].doneSeqNum) {
371,372c806,807
< // that was braodcasted.
< branchPred.update(fromCommit->commitInfo.doneSeqNum);
---
> // that was broadcasted.
> branchPred.update(fromCommit->commitInfo[tid].doneSeqNum, tid);
376,377c811,812
< if (fromCommit->commitInfo.robSquashing) {
< DPRINTF(Fetch, "Fetch: ROB is still squashing.\n");
---
> if (fromCommit->commitInfo[tid].robSquashing) {
> DPRINTF(Fetch, "[tid:%u]: ROB is still squashing Thread %u.\n", tid);
380c815
< _status = Squashing;
---
> fetchStatus[tid] = Squashing;
382,383c817
< ++fetchSquashCycles;
< return;
---
> return true;
387,389c821,823
< if (fromDecode->decodeInfo.squash) {
< DPRINTF(Fetch, "Fetch: Squashing instructions due to squash "
< "from decode.\n");
---
> if (fromDecode->decodeInfo[tid].squash) {
> DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash "
> "from decode.\n",tid);
392,395c826,830
< if (fromDecode->decodeInfo.branchMispredict) {
< branchPred.squash(fromDecode->decodeInfo.doneSeqNum,
< fromDecode->decodeInfo.nextPC,
< fromDecode->decodeInfo.branchTaken);
---
> if (fromDecode->decodeInfo[tid].branchMispredict) {
> branchPred.squash(fromDecode->decodeInfo[tid].doneSeqNum,
> fromDecode->decodeInfo[tid].nextPC,
> fromDecode->decodeInfo[tid].branchTaken,
> tid);
397c832,833
< branchPred.squash(fromDecode->decodeInfo.doneSeqNum);
---
> branchPred.squash(fromDecode->decodeInfo[tid].doneSeqNum,
> tid);
400,404c836,842
< if (_status != Squashing) {
< // Squash unless we're already squashing?
< squashFromDecode(fromDecode->decodeInfo.nextPC,
< fromDecode->decodeInfo.doneSeqNum);
< return;
---
> if (fetchStatus[tid] != Squashing) {
> // Squash unless we're already squashing
> squashFromDecode(fromDecode->decodeInfo[tid].nextPC,
> fromDecode->decodeInfo[tid].doneSeqNum,
> tid);
>
> return true;
408,414c846,847
< // 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.
---
> if (checkStall(tid) && fetchStatus[tid] != IcacheWaitResponse) {
> DPRINTF(Fetch, "[tid:%i]: Setting to blocked\n",tid);
416,422c849
< 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);
---
> fetchStatus[tid] = Blocked;
424,434c851
< _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;
---
> return true;
437,444c854,859
< // 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");
---
> 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);
446,447c861
< // Switch status to running
< _status = Running;
---
> fetchStatus[tid] = Running;
449,457c863
< ++fetchCycles;
<
< fetch();
< } else if (_status != IcacheMissStall) {
< DPRINTF(Fetch, "Fetch: Running stage.\n");
<
< ++fetchCycles;
<
< fetch();
---
> return true;
458a865,868
>
> // 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;
463c873
< SimpleFetch<Impl>::fetch()
---
> DefaultFetch<Impl>::fetch(bool &status_change)
467a878
> int tid = getFetchingThread(fetchPolicy);
468a880,887
> if (tid == -1) {
> DPRINTF(Fetch,"There are no more threads available to fetch from.\n");
>
> // Breaks looping condition in tick()
> threadFetched = numFetchingThreads;
> return;
> }
>
470c889
< Addr fetch_PC = cpu->readPC();
---
> Addr &fetch_PC = PC[tid];
478,479c897,899
< if (_status == IcacheMissComplete) {
< DPRINTF(Fetch, "Fetch: Icache miss is complete.\n");
---
> if (fetchStatus[tid] == IcacheAccessComplete) {
> DPRINTF(Fetch, "[tid:%i]: Icache miss is complete.\n",
> tid);
481,482c901,906
< // Reset the completion event to NULL.
< memReq->completionEvent = NULL;
---
> 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);
484c908,912
< _status = Running;
---
> bool fetch_success = fetchCacheLine(fetch_PC, fault, tid);
> if (!fetch_success) {
> ++fetchMiscStallCycles;
> return;
> }
486,488c914,922
< DPRINTF(Fetch, "Fetch: Attempting to translate and read "
< "instruction, starting at PC %08p.\n",
< fetch_PC);
---
> if (fetchStatus[tid] == Idle) {
> ++fetchIdleCycles;
> } else if (fetchStatus[tid] == Blocked) {
> ++fetchBlockedCycles;
> } else if (fetchStatus[tid] == Squashing) {
> ++fetchSquashCycles;
> } else if (fetchStatus[tid] == IcacheWaitResponse) {
> ++icacheStallCycles;
> }
490c924,926
< fault = fetchCacheLine(fetch_PC);
---
> // Status is Idle, Squashing, Blocked, or IcacheWaitResponse, so
> // fetch should do nothing.
> return;
493,496c929,934
< // 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) {
---
> ++fetchCycles;
>
> // If we had a stall due to an icache miss, then return.
> if (fetchStatus[tid] == IcacheWaitResponse) {
> ++icacheStallCycles;
> status_change = true;
500,504d937
< // 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.
<
508,509c941,943
< unsigned offset = fetch_PC & cacheBlkMask;
< unsigned fetched;
---
> ExtMachInst ext_inst;
> // @todo: Fix this hack.
> unsigned offset = (fetch_PC & cacheBlkMask) & ~3;
516c950,951
< DPRINTF(Fetch, "Fetch: Adding instructions to queue to decode.\n");
---
> DPRINTF(Fetch, "[tid:%i]: Adding instructions to queue to "
> "decode.\n",tid);
518,521d952
< //////////////////////////
< // Fetch first instruction
< //////////////////////////
<
526c957
< for (fetched = 0;
---
> for (;
528c959
< fetched < fetchWidth &&
---
> numInst < fetchWidth &&
530,531c961
< ++fetched)
< {
---
> ++numInst) {
541c971
< (&cacheData[offset]));
---
> (&cacheData[tid][offset]));
542a973,974
> ext_inst = TheISA::makeExtMI(inst, fetch_PC);
>
544c976,977
< DynInstPtr instruction = new DynInst(inst, fetch_PC, next_PC,
---
> DynInstPtr instruction = new DynInst(ext_inst, fetch_PC,
> next_PC,
545a979
> instruction->setThread(tid);
547,548c981
< DPRINTF(Fetch, "Fetch: Instruction %i created, with PC %#x\n",
< inst_seq, instruction->readPC());
---
> instruction->setASID(tid);
550,551c983
< DPRINTF(Fetch, "Fetch: Instruction opcode is: %03p\n",
< OPCODE(inst));
---
> instruction->setState(cpu->thread[tid]);
552a985,991
> 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));
>
554c993
< Trace::getInstRecord(curTick, cpu->xcBase(), cpu,
---
> Trace::getInstRecord(curTick, cpu->xcBase(tid), cpu,
556c995
< instruction->readPC(), 0);
---
> instruction->readPC(),tid);
561c1000
< cpu->addInst(instruction);
---
> instruction->setInstListIt(cpu->addInst(instruction));
565c1004
< toDecode->insts[fetched] = instruction;
---
> toDecode->insts[numInst] = instruction;
574a1014,1022
> if (instruction->isQuiesce()) {
> warn("%lli: Quiesce instruction encountered, halting fetch!",
> curTick);
> fetchStatus[tid] = QuiescePending;
> ++numInst;
> status_change = true;
> break;
> }
>
576a1025
> }
578c1027,1028
< fetch_nisn_dist.sample(fetched);
---
> if (numInst > 0) {
> wroteToTimeBuffer = true;
582,586c1032
< // 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).
---
> // cycle will be.
588,590c1034,1037
< DPRINTF(Fetch, "Fetch: Setting PC to %08p.\n", next_PC);
< cpu->setPC(next_PC);
< cpu->setNextPC(next_PC + instSize);
---
> DPRINTF(Fetch, "[tid:%i]: Setting PC to %08p.\n",tid, next_PC);
>
> PC[tid] = next_PC;
> nextPC[tid] = next_PC + instSize;
592,595c1039,1042
< // If the issue was an icache miss, then we can just return and
< // wait until it is handled.
< if (_status == IcacheMissStall) {
< return;
---
> // We shouldn't be in an icache miss and also have a fault (an ITB
> // miss)
> if (fetchStatus[tid] == IcacheWaitResponse) {
> panic("Fetch should have exited prior to this!");
598,605c1045,1053
< // 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.
---
> // 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;
607c1055,1060
< DPRINTF(Fetch, "Fetch: Blocked, need to handle the trap.\n");
---
> // 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);
609,614c1062,1080
< _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.
---
> 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]);
616c1082
< fatal("fault (%d) detected @ PC %08p", fault, cpu->readPC());
---
> fatal("fault (%d) detected @ PC %08p", fault, PC[tid]);
619a1086,1231
>
>
> ///////////////////////////////////////
> // //
> // 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] == IcacheAccessComplete ||
> 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] == IcacheAccessComplete ||
> 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] == IcacheAccessComplete ||
> 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] == IcacheAccessComplete ||
> 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;
> }