fetch1.cc revision 11568
110259SAndrew.Bardsley@arm.com/* 210259SAndrew.Bardsley@arm.com * Copyright (c) 2013-2014 ARM Limited 310259SAndrew.Bardsley@arm.com * All rights reserved 410259SAndrew.Bardsley@arm.com * 510259SAndrew.Bardsley@arm.com * The license below extends only to copyright in the software and shall 610259SAndrew.Bardsley@arm.com * not be construed as granting a license to any other intellectual 710259SAndrew.Bardsley@arm.com * property including but not limited to intellectual property relating 810259SAndrew.Bardsley@arm.com * to a hardware implementation of the functionality of the software 910259SAndrew.Bardsley@arm.com * licensed hereunder. You may use the software subject to the license 1010259SAndrew.Bardsley@arm.com * terms below provided that you ensure that this notice is replicated 1110259SAndrew.Bardsley@arm.com * unmodified and in its entirety in all distributions of the software, 1210259SAndrew.Bardsley@arm.com * modified or unmodified, in source code or in binary form. 1310259SAndrew.Bardsley@arm.com * 1410259SAndrew.Bardsley@arm.com * Redistribution and use in source and binary forms, with or without 1510259SAndrew.Bardsley@arm.com * modification, are permitted provided that the following conditions are 1610259SAndrew.Bardsley@arm.com * met: redistributions of source code must retain the above copyright 1710259SAndrew.Bardsley@arm.com * notice, this list of conditions and the following disclaimer; 1810259SAndrew.Bardsley@arm.com * redistributions in binary form must reproduce the above copyright 1910259SAndrew.Bardsley@arm.com * notice, this list of conditions and the following disclaimer in the 2010259SAndrew.Bardsley@arm.com * documentation and/or other materials provided with the distribution; 2110259SAndrew.Bardsley@arm.com * neither the name of the copyright holders nor the names of its 2210259SAndrew.Bardsley@arm.com * contributors may be used to endorse or promote products derived from 2310259SAndrew.Bardsley@arm.com * this software without specific prior written permission. 2410259SAndrew.Bardsley@arm.com * 2510259SAndrew.Bardsley@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2610259SAndrew.Bardsley@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2710259SAndrew.Bardsley@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2810259SAndrew.Bardsley@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2910259SAndrew.Bardsley@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3010259SAndrew.Bardsley@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3110259SAndrew.Bardsley@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3210259SAndrew.Bardsley@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3310259SAndrew.Bardsley@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3410259SAndrew.Bardsley@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3510259SAndrew.Bardsley@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3610259SAndrew.Bardsley@arm.com * 3710259SAndrew.Bardsley@arm.com * Authors: Andrew Bardsley 3810259SAndrew.Bardsley@arm.com */ 3910259SAndrew.Bardsley@arm.com 4010259SAndrew.Bardsley@arm.com#include <cstring> 4110259SAndrew.Bardsley@arm.com#include <iomanip> 4210259SAndrew.Bardsley@arm.com#include <sstream> 4310259SAndrew.Bardsley@arm.com 4410259SAndrew.Bardsley@arm.com#include "base/cast.hh" 4510259SAndrew.Bardsley@arm.com#include "cpu/minor/fetch1.hh" 4610259SAndrew.Bardsley@arm.com#include "cpu/minor/pipeline.hh" 4710259SAndrew.Bardsley@arm.com#include "debug/Drain.hh" 4810259SAndrew.Bardsley@arm.com#include "debug/Fetch.hh" 4910259SAndrew.Bardsley@arm.com#include "debug/MinorTrace.hh" 5010259SAndrew.Bardsley@arm.com 5110259SAndrew.Bardsley@arm.comnamespace Minor 5210259SAndrew.Bardsley@arm.com{ 5310259SAndrew.Bardsley@arm.com 5410259SAndrew.Bardsley@arm.comFetch1::Fetch1(const std::string &name_, 5510259SAndrew.Bardsley@arm.com MinorCPU &cpu_, 5610259SAndrew.Bardsley@arm.com MinorCPUParams ¶ms, 5710259SAndrew.Bardsley@arm.com Latch<BranchData>::Output inp_, 5810259SAndrew.Bardsley@arm.com Latch<ForwardLineData>::Input out_, 5910259SAndrew.Bardsley@arm.com Latch<BranchData>::Output prediction_, 6011567Smitch.hayenga@arm.com std::vector<InputBuffer<ForwardLineData>> &next_stage_input_buffer) : 6110259SAndrew.Bardsley@arm.com Named(name_), 6210259SAndrew.Bardsley@arm.com cpu(cpu_), 6310259SAndrew.Bardsley@arm.com inp(inp_), 6410259SAndrew.Bardsley@arm.com out(out_), 6510259SAndrew.Bardsley@arm.com prediction(prediction_), 6610259SAndrew.Bardsley@arm.com nextStageReserve(next_stage_input_buffer), 6710259SAndrew.Bardsley@arm.com icachePort(name_ + ".icache_port", *this, cpu_), 6810259SAndrew.Bardsley@arm.com lineSnap(params.fetch1LineSnapWidth), 6910259SAndrew.Bardsley@arm.com maxLineWidth(params.fetch1LineWidth), 7010259SAndrew.Bardsley@arm.com fetchLimit(params.fetch1FetchLimit), 7111567Smitch.hayenga@arm.com fetchInfo(params.numThreads), 7211567Smitch.hayenga@arm.com threadPriority(0), 7310259SAndrew.Bardsley@arm.com requests(name_ + ".requests", "lines", params.fetch1FetchLimit), 7410259SAndrew.Bardsley@arm.com transfers(name_ + ".transfers", "lines", params.fetch1FetchLimit), 7510259SAndrew.Bardsley@arm.com icacheState(IcacheRunning), 7610259SAndrew.Bardsley@arm.com lineSeqNum(InstId::firstLineSeqNum), 7710259SAndrew.Bardsley@arm.com numFetchesInMemorySystem(0), 7810259SAndrew.Bardsley@arm.com numFetchesInITLB(0) 7910259SAndrew.Bardsley@arm.com{ 8010259SAndrew.Bardsley@arm.com if (lineSnap == 0) { 8110259SAndrew.Bardsley@arm.com lineSnap = cpu.cacheLineSize(); 8210259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "lineSnap set to cache line size of: %d\n", 8310259SAndrew.Bardsley@arm.com lineSnap); 8410259SAndrew.Bardsley@arm.com } 8510259SAndrew.Bardsley@arm.com 8610259SAndrew.Bardsley@arm.com if (maxLineWidth == 0) { 8710259SAndrew.Bardsley@arm.com maxLineWidth = cpu.cacheLineSize(); 8810259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "maxLineWidth set to cache line size of: %d\n", 8910259SAndrew.Bardsley@arm.com maxLineWidth); 9010259SAndrew.Bardsley@arm.com } 9110259SAndrew.Bardsley@arm.com 9210259SAndrew.Bardsley@arm.com /* These assertions should be copied to the Python config. as well */ 9310259SAndrew.Bardsley@arm.com if ((lineSnap % sizeof(TheISA::MachInst)) != 0) { 9410259SAndrew.Bardsley@arm.com fatal("%s: fetch1LineSnapWidth must be a multiple " 9510259SAndrew.Bardsley@arm.com "of sizeof(TheISA::MachInst) (%d)\n", name_, 9610259SAndrew.Bardsley@arm.com sizeof(TheISA::MachInst)); 9710259SAndrew.Bardsley@arm.com } 9810259SAndrew.Bardsley@arm.com 9910259SAndrew.Bardsley@arm.com if (!(maxLineWidth >= lineSnap && 10010259SAndrew.Bardsley@arm.com (maxLineWidth % sizeof(TheISA::MachInst)) == 0)) 10110259SAndrew.Bardsley@arm.com { 10210259SAndrew.Bardsley@arm.com fatal("%s: fetch1LineWidth must be a multiple of" 10310259SAndrew.Bardsley@arm.com " sizeof(TheISA::MachInst)" 10410259SAndrew.Bardsley@arm.com " (%d), and >= fetch1LineSnapWidth (%d)\n", 10510259SAndrew.Bardsley@arm.com name_, sizeof(TheISA::MachInst), lineSnap); 10610259SAndrew.Bardsley@arm.com } 10710259SAndrew.Bardsley@arm.com 10810259SAndrew.Bardsley@arm.com if (fetchLimit < 1) { 10910259SAndrew.Bardsley@arm.com fatal("%s: fetch1FetchLimit must be >= 1 (%d)\n", name_, 11010259SAndrew.Bardsley@arm.com fetchLimit); 11110259SAndrew.Bardsley@arm.com } 11210259SAndrew.Bardsley@arm.com} 11310259SAndrew.Bardsley@arm.com 11411567Smitch.hayenga@arm.cominline ThreadID 11511567Smitch.hayenga@arm.comFetch1::getScheduledThread() 11611567Smitch.hayenga@arm.com{ 11711567Smitch.hayenga@arm.com /* Select thread via policy. */ 11811567Smitch.hayenga@arm.com std::vector<ThreadID> priority_list; 11911567Smitch.hayenga@arm.com 12011567Smitch.hayenga@arm.com switch (cpu.threadPolicy) { 12111567Smitch.hayenga@arm.com case Enums::SingleThreaded: 12211567Smitch.hayenga@arm.com priority_list.push_back(0); 12311567Smitch.hayenga@arm.com break; 12411567Smitch.hayenga@arm.com case Enums::RoundRobin: 12511567Smitch.hayenga@arm.com priority_list = cpu.roundRobinPriority(threadPriority); 12611567Smitch.hayenga@arm.com break; 12711567Smitch.hayenga@arm.com case Enums::Random: 12811567Smitch.hayenga@arm.com priority_list = cpu.randomPriority(); 12911567Smitch.hayenga@arm.com break; 13011567Smitch.hayenga@arm.com default: 13111567Smitch.hayenga@arm.com panic("Unknown fetch policy"); 13211567Smitch.hayenga@arm.com } 13311567Smitch.hayenga@arm.com 13411567Smitch.hayenga@arm.com for (auto tid : priority_list) { 13511567Smitch.hayenga@arm.com if (cpu.getContext(tid)->status() == ThreadContext::Active && 13611567Smitch.hayenga@arm.com !fetchInfo[tid].blocked && 13711567Smitch.hayenga@arm.com fetchInfo[tid].state == FetchRunning) { 13811567Smitch.hayenga@arm.com threadPriority = tid; 13911567Smitch.hayenga@arm.com return tid; 14011567Smitch.hayenga@arm.com } 14111567Smitch.hayenga@arm.com } 14211567Smitch.hayenga@arm.com 14311567Smitch.hayenga@arm.com return InvalidThreadID; 14411567Smitch.hayenga@arm.com} 14511567Smitch.hayenga@arm.com 14610259SAndrew.Bardsley@arm.comvoid 14711567Smitch.hayenga@arm.comFetch1::fetchLine(ThreadID tid) 14810259SAndrew.Bardsley@arm.com{ 14911567Smitch.hayenga@arm.com /* Reference the currently used thread state. */ 15011567Smitch.hayenga@arm.com Fetch1ThreadInfo &thread = fetchInfo[tid]; 15111567Smitch.hayenga@arm.com 15210259SAndrew.Bardsley@arm.com /* If line_offset != 0, a request is pushed for the remainder of the 15310259SAndrew.Bardsley@arm.com * line. */ 15410259SAndrew.Bardsley@arm.com /* Use a lower, sizeof(MachInst) aligned address for the fetch */ 15511567Smitch.hayenga@arm.com Addr aligned_pc = thread.pc.instAddr() & ~((Addr) lineSnap - 1); 15610259SAndrew.Bardsley@arm.com unsigned int line_offset = aligned_pc % lineSnap; 15710259SAndrew.Bardsley@arm.com unsigned int request_size = maxLineWidth - line_offset; 15810259SAndrew.Bardsley@arm.com 15910259SAndrew.Bardsley@arm.com /* Fill in the line's id */ 16011567Smitch.hayenga@arm.com InstId request_id(tid, 16111567Smitch.hayenga@arm.com thread.streamSeqNum, thread.predictionSeqNum, 16210259SAndrew.Bardsley@arm.com lineSeqNum); 16310259SAndrew.Bardsley@arm.com 16411567Smitch.hayenga@arm.com FetchRequestPtr request = new FetchRequest(*this, request_id, thread.pc); 16510259SAndrew.Bardsley@arm.com 16610259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Inserting fetch into the fetch queue " 16710259SAndrew.Bardsley@arm.com "%s addr: 0x%x pc: %s line_offset: %d request_size: %d\n", 16811567Smitch.hayenga@arm.com request_id, aligned_pc, thread.pc, line_offset, request_size); 16910259SAndrew.Bardsley@arm.com 17011567Smitch.hayenga@arm.com request->request.setContext(cpu.threads[tid]->getTC()->contextId()); 17110259SAndrew.Bardsley@arm.com request->request.setVirt(0 /* asid */, 17210259SAndrew.Bardsley@arm.com aligned_pc, request_size, Request::INST_FETCH, cpu.instMasterId(), 17310259SAndrew.Bardsley@arm.com /* I've no idea why we need the PC, but give it */ 17411567Smitch.hayenga@arm.com thread.pc.instAddr()); 17510259SAndrew.Bardsley@arm.com 17610259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Submitting ITLB request\n"); 17710259SAndrew.Bardsley@arm.com numFetchesInITLB++; 17810259SAndrew.Bardsley@arm.com 17910259SAndrew.Bardsley@arm.com request->state = FetchRequest::InTranslation; 18010259SAndrew.Bardsley@arm.com 18110259SAndrew.Bardsley@arm.com /* Reserve space in the queues upstream of requests for results */ 18210259SAndrew.Bardsley@arm.com transfers.reserve(); 18310259SAndrew.Bardsley@arm.com requests.push(request); 18410259SAndrew.Bardsley@arm.com 18510259SAndrew.Bardsley@arm.com /* Submit the translation request. The response will come 18610259SAndrew.Bardsley@arm.com * through finish/markDelayed on this request as it bears 18710259SAndrew.Bardsley@arm.com * the Translation interface */ 18810259SAndrew.Bardsley@arm.com cpu.threads[request->id.threadId]->itb->translateTiming( 18910259SAndrew.Bardsley@arm.com &request->request, 19010259SAndrew.Bardsley@arm.com cpu.getContext(request->id.threadId), 19110259SAndrew.Bardsley@arm.com request, BaseTLB::Execute); 19210259SAndrew.Bardsley@arm.com 19310259SAndrew.Bardsley@arm.com lineSeqNum++; 19410259SAndrew.Bardsley@arm.com 19510259SAndrew.Bardsley@arm.com /* Step the PC for the next line onto the line aligned next address. 19610259SAndrew.Bardsley@arm.com * Note that as instructions can span lines, this PC is only a 19710259SAndrew.Bardsley@arm.com * reliable 'new' PC if the next line has a new stream sequence number. */ 19810259SAndrew.Bardsley@arm.com#if THE_ISA == ALPHA_ISA 19910259SAndrew.Bardsley@arm.com /* Restore the low bits of the PC used as address space flags */ 20011567Smitch.hayenga@arm.com Addr pc_low_bits = thread.pc.instAddr() & 20110259SAndrew.Bardsley@arm.com ((Addr) (1 << sizeof(TheISA::MachInst)) - 1); 20210259SAndrew.Bardsley@arm.com 20311567Smitch.hayenga@arm.com thread.pc.set(aligned_pc + request_size + pc_low_bits); 20410259SAndrew.Bardsley@arm.com#else 20511567Smitch.hayenga@arm.com thread.pc.set(aligned_pc + request_size); 20610259SAndrew.Bardsley@arm.com#endif 20710259SAndrew.Bardsley@arm.com} 20810259SAndrew.Bardsley@arm.com 20910259SAndrew.Bardsley@arm.comstd::ostream & 21010259SAndrew.Bardsley@arm.comoperator <<(std::ostream &os, Fetch1::IcacheState state) 21110259SAndrew.Bardsley@arm.com{ 21210259SAndrew.Bardsley@arm.com switch (state) { 21310259SAndrew.Bardsley@arm.com case Fetch1::IcacheRunning: 21410259SAndrew.Bardsley@arm.com os << "IcacheRunning"; 21510259SAndrew.Bardsley@arm.com break; 21610259SAndrew.Bardsley@arm.com case Fetch1::IcacheNeedsRetry: 21710259SAndrew.Bardsley@arm.com os << "IcacheNeedsRetry"; 21810259SAndrew.Bardsley@arm.com break; 21910259SAndrew.Bardsley@arm.com default: 22010259SAndrew.Bardsley@arm.com os << "IcacheState-" << static_cast<int>(state); 22110259SAndrew.Bardsley@arm.com break; 22210259SAndrew.Bardsley@arm.com } 22310259SAndrew.Bardsley@arm.com return os; 22410259SAndrew.Bardsley@arm.com} 22510259SAndrew.Bardsley@arm.com 22610259SAndrew.Bardsley@arm.comvoid 22710259SAndrew.Bardsley@arm.comFetch1::FetchRequest::makePacket() 22810259SAndrew.Bardsley@arm.com{ 22910259SAndrew.Bardsley@arm.com /* Make the necessary packet for a memory transaction */ 23010259SAndrew.Bardsley@arm.com packet = new Packet(&request, MemCmd::ReadReq); 23110259SAndrew.Bardsley@arm.com packet->allocate(); 23210259SAndrew.Bardsley@arm.com 23310259SAndrew.Bardsley@arm.com /* This FetchRequest becomes SenderState to allow the response to be 23410259SAndrew.Bardsley@arm.com * identified */ 23510259SAndrew.Bardsley@arm.com packet->pushSenderState(this); 23610259SAndrew.Bardsley@arm.com} 23710259SAndrew.Bardsley@arm.com 23810259SAndrew.Bardsley@arm.comvoid 23910379Sandreas.hansson@arm.comFetch1::FetchRequest::finish(const Fault &fault_, RequestPtr request_, 24010379Sandreas.hansson@arm.com ThreadContext *tc, BaseTLB::Mode mode) 24110259SAndrew.Bardsley@arm.com{ 24210259SAndrew.Bardsley@arm.com fault = fault_; 24310259SAndrew.Bardsley@arm.com 24410259SAndrew.Bardsley@arm.com state = Translated; 24510259SAndrew.Bardsley@arm.com fetch.handleTLBResponse(this); 24610259SAndrew.Bardsley@arm.com 24710259SAndrew.Bardsley@arm.com /* Let's try and wake up the processor for the next cycle */ 24810259SAndrew.Bardsley@arm.com fetch.cpu.wakeupOnEvent(Pipeline::Fetch1StageId); 24910259SAndrew.Bardsley@arm.com} 25010259SAndrew.Bardsley@arm.com 25110259SAndrew.Bardsley@arm.comvoid 25210259SAndrew.Bardsley@arm.comFetch1::handleTLBResponse(FetchRequestPtr response) 25310259SAndrew.Bardsley@arm.com{ 25410259SAndrew.Bardsley@arm.com numFetchesInITLB--; 25510259SAndrew.Bardsley@arm.com 25610259SAndrew.Bardsley@arm.com if (response->fault != NoFault) { 25710259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Fault in address ITLB translation: %s, " 25810259SAndrew.Bardsley@arm.com "paddr: 0x%x, vaddr: 0x%x\n", 25910259SAndrew.Bardsley@arm.com response->fault->name(), 26010259SAndrew.Bardsley@arm.com (response->request.hasPaddr() ? response->request.getPaddr() : 0), 26110259SAndrew.Bardsley@arm.com response->request.getVaddr()); 26210259SAndrew.Bardsley@arm.com 26310259SAndrew.Bardsley@arm.com if (DTRACE(MinorTrace)) 26410259SAndrew.Bardsley@arm.com minorTraceResponseLine(name(), response); 26510259SAndrew.Bardsley@arm.com } else { 26610259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Got ITLB response\n"); 26710259SAndrew.Bardsley@arm.com } 26810259SAndrew.Bardsley@arm.com 26910259SAndrew.Bardsley@arm.com response->state = FetchRequest::Translated; 27010259SAndrew.Bardsley@arm.com 27110259SAndrew.Bardsley@arm.com tryToSendToTransfers(response); 27210259SAndrew.Bardsley@arm.com} 27310259SAndrew.Bardsley@arm.com 27410259SAndrew.Bardsley@arm.comFetch1::FetchRequest::~FetchRequest() 27510259SAndrew.Bardsley@arm.com{ 27610259SAndrew.Bardsley@arm.com if (packet) 27710259SAndrew.Bardsley@arm.com delete packet; 27810259SAndrew.Bardsley@arm.com} 27910259SAndrew.Bardsley@arm.com 28010259SAndrew.Bardsley@arm.comvoid 28110259SAndrew.Bardsley@arm.comFetch1::tryToSendToTransfers(FetchRequestPtr request) 28210259SAndrew.Bardsley@arm.com{ 28310259SAndrew.Bardsley@arm.com if (!requests.empty() && requests.front() != request) { 28410259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Fetch not at front of requests queue, can't" 28510259SAndrew.Bardsley@arm.com " issue to memory\n"); 28610259SAndrew.Bardsley@arm.com return; 28710259SAndrew.Bardsley@arm.com } 28810259SAndrew.Bardsley@arm.com 28910259SAndrew.Bardsley@arm.com if (request->state == FetchRequest::InTranslation) { 29010259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Fetch still in translation, not issuing to" 29110259SAndrew.Bardsley@arm.com " memory\n"); 29210259SAndrew.Bardsley@arm.com return; 29310259SAndrew.Bardsley@arm.com } 29410259SAndrew.Bardsley@arm.com 29510259SAndrew.Bardsley@arm.com if (request->isDiscardable() || request->fault != NoFault) { 29610259SAndrew.Bardsley@arm.com /* Discarded and faulting requests carry on through transfers 29710259SAndrew.Bardsley@arm.com * as Complete/packet == NULL */ 29810259SAndrew.Bardsley@arm.com 29910259SAndrew.Bardsley@arm.com request->state = FetchRequest::Complete; 30010259SAndrew.Bardsley@arm.com moveFromRequestsToTransfers(request); 30110259SAndrew.Bardsley@arm.com 30210259SAndrew.Bardsley@arm.com /* Wake up the pipeline next cycle as there will be no event 30310259SAndrew.Bardsley@arm.com * for this queue->queue transfer */ 30410259SAndrew.Bardsley@arm.com cpu.wakeupOnEvent(Pipeline::Fetch1StageId); 30510259SAndrew.Bardsley@arm.com } else if (request->state == FetchRequest::Translated) { 30610259SAndrew.Bardsley@arm.com if (!request->packet) 30710259SAndrew.Bardsley@arm.com request->makePacket(); 30810259SAndrew.Bardsley@arm.com 30910259SAndrew.Bardsley@arm.com /* Ensure that the packet won't delete the request */ 31010259SAndrew.Bardsley@arm.com assert(request->packet->needsResponse()); 31110259SAndrew.Bardsley@arm.com 31210259SAndrew.Bardsley@arm.com if (tryToSend(request)) 31310259SAndrew.Bardsley@arm.com moveFromRequestsToTransfers(request); 31410259SAndrew.Bardsley@arm.com } else { 31510259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Not advancing line fetch\n"); 31610259SAndrew.Bardsley@arm.com } 31710259SAndrew.Bardsley@arm.com} 31810259SAndrew.Bardsley@arm.com 31910259SAndrew.Bardsley@arm.comvoid 32010259SAndrew.Bardsley@arm.comFetch1::moveFromRequestsToTransfers(FetchRequestPtr request) 32110259SAndrew.Bardsley@arm.com{ 32210259SAndrew.Bardsley@arm.com assert(!requests.empty() && requests.front() == request); 32310259SAndrew.Bardsley@arm.com 32410259SAndrew.Bardsley@arm.com requests.pop(); 32510259SAndrew.Bardsley@arm.com transfers.push(request); 32610259SAndrew.Bardsley@arm.com} 32710259SAndrew.Bardsley@arm.com 32810259SAndrew.Bardsley@arm.combool 32910259SAndrew.Bardsley@arm.comFetch1::tryToSend(FetchRequestPtr request) 33010259SAndrew.Bardsley@arm.com{ 33110259SAndrew.Bardsley@arm.com bool ret = false; 33210259SAndrew.Bardsley@arm.com 33310259SAndrew.Bardsley@arm.com if (icachePort.sendTimingReq(request->packet)) { 33410259SAndrew.Bardsley@arm.com /* Invalidate the fetch_requests packet so we don't 33510259SAndrew.Bardsley@arm.com * accidentally fail to deallocate it (or use it!) 33610259SAndrew.Bardsley@arm.com * later by overwriting it */ 33710259SAndrew.Bardsley@arm.com request->packet = NULL; 33810259SAndrew.Bardsley@arm.com request->state = FetchRequest::RequestIssuing; 33910259SAndrew.Bardsley@arm.com numFetchesInMemorySystem++; 34010259SAndrew.Bardsley@arm.com 34110259SAndrew.Bardsley@arm.com ret = true; 34210259SAndrew.Bardsley@arm.com 34310259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Issued fetch request to memory: %s\n", 34410259SAndrew.Bardsley@arm.com request->id); 34510259SAndrew.Bardsley@arm.com } else { 34610259SAndrew.Bardsley@arm.com /* Needs to be resent, wait for that */ 34710259SAndrew.Bardsley@arm.com icacheState = IcacheNeedsRetry; 34810259SAndrew.Bardsley@arm.com 34910259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Line fetch needs to retry: %s\n", 35010259SAndrew.Bardsley@arm.com request->id); 35110259SAndrew.Bardsley@arm.com } 35210259SAndrew.Bardsley@arm.com 35310259SAndrew.Bardsley@arm.com return ret; 35410259SAndrew.Bardsley@arm.com} 35510259SAndrew.Bardsley@arm.com 35610259SAndrew.Bardsley@arm.comvoid 35710259SAndrew.Bardsley@arm.comFetch1::stepQueues() 35810259SAndrew.Bardsley@arm.com{ 35910259SAndrew.Bardsley@arm.com IcacheState old_icache_state = icacheState; 36010259SAndrew.Bardsley@arm.com 36110259SAndrew.Bardsley@arm.com switch (icacheState) { 36210259SAndrew.Bardsley@arm.com case IcacheRunning: 36310259SAndrew.Bardsley@arm.com /* Move ITLB results on to the memory system */ 36410259SAndrew.Bardsley@arm.com if (!requests.empty()) { 36510259SAndrew.Bardsley@arm.com tryToSendToTransfers(requests.front()); 36610259SAndrew.Bardsley@arm.com } 36710259SAndrew.Bardsley@arm.com break; 36810259SAndrew.Bardsley@arm.com case IcacheNeedsRetry: 36910259SAndrew.Bardsley@arm.com break; 37010259SAndrew.Bardsley@arm.com } 37110259SAndrew.Bardsley@arm.com 37210259SAndrew.Bardsley@arm.com if (icacheState != old_icache_state) { 37310259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Step in state %s moving to state %s\n", 37410259SAndrew.Bardsley@arm.com old_icache_state, icacheState); 37510259SAndrew.Bardsley@arm.com } 37610259SAndrew.Bardsley@arm.com} 37710259SAndrew.Bardsley@arm.com 37810259SAndrew.Bardsley@arm.comvoid 37910259SAndrew.Bardsley@arm.comFetch1::popAndDiscard(FetchQueue &queue) 38010259SAndrew.Bardsley@arm.com{ 38110259SAndrew.Bardsley@arm.com if (!queue.empty()) { 38210259SAndrew.Bardsley@arm.com delete queue.front(); 38310259SAndrew.Bardsley@arm.com queue.pop(); 38410259SAndrew.Bardsley@arm.com } 38510259SAndrew.Bardsley@arm.com} 38610259SAndrew.Bardsley@arm.com 38710259SAndrew.Bardsley@arm.comunsigned int 38810259SAndrew.Bardsley@arm.comFetch1::numInFlightFetches() 38910259SAndrew.Bardsley@arm.com{ 39010259SAndrew.Bardsley@arm.com return requests.occupiedSpace() + 39110259SAndrew.Bardsley@arm.com transfers.occupiedSpace(); 39210259SAndrew.Bardsley@arm.com} 39310259SAndrew.Bardsley@arm.com 39410259SAndrew.Bardsley@arm.com/** Print the appropriate MinorLine line for a fetch response */ 39510259SAndrew.Bardsley@arm.comvoid 39610259SAndrew.Bardsley@arm.comFetch1::minorTraceResponseLine(const std::string &name, 39710259SAndrew.Bardsley@arm.com Fetch1::FetchRequestPtr response) const 39810259SAndrew.Bardsley@arm.com{ 39910259SAndrew.Bardsley@arm.com Request &request M5_VAR_USED = response->request; 40010259SAndrew.Bardsley@arm.com 40110259SAndrew.Bardsley@arm.com if (response->packet && response->packet->isError()) { 40210259SAndrew.Bardsley@arm.com MINORLINE(this, "id=F;%s vaddr=0x%x fault=\"error packet\"\n", 40310259SAndrew.Bardsley@arm.com response->id, request.getVaddr()); 40410259SAndrew.Bardsley@arm.com } else if (response->fault != NoFault) { 40510259SAndrew.Bardsley@arm.com MINORLINE(this, "id=F;%s vaddr=0x%x fault=\"%s\"\n", 40610259SAndrew.Bardsley@arm.com response->id, request.getVaddr(), response->fault->name()); 40710259SAndrew.Bardsley@arm.com } else { 40810259SAndrew.Bardsley@arm.com MINORLINE(this, "id=%s size=%d vaddr=0x%x paddr=0x%x\n", 40910259SAndrew.Bardsley@arm.com response->id, request.getSize(), 41010259SAndrew.Bardsley@arm.com request.getVaddr(), request.getPaddr()); 41110259SAndrew.Bardsley@arm.com } 41210259SAndrew.Bardsley@arm.com} 41310259SAndrew.Bardsley@arm.com 41410259SAndrew.Bardsley@arm.combool 41510259SAndrew.Bardsley@arm.comFetch1::recvTimingResp(PacketPtr response) 41610259SAndrew.Bardsley@arm.com{ 41710259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "recvTimingResp %d\n", numFetchesInMemorySystem); 41810259SAndrew.Bardsley@arm.com 41910259SAndrew.Bardsley@arm.com /* Only push the response if we didn't change stream? No, all responses 42010259SAndrew.Bardsley@arm.com * should hit the responses queue. It's the job of 'step' to throw them 42110259SAndrew.Bardsley@arm.com * away. */ 42210259SAndrew.Bardsley@arm.com FetchRequestPtr fetch_request = safe_cast<FetchRequestPtr> 42310259SAndrew.Bardsley@arm.com (response->popSenderState()); 42410259SAndrew.Bardsley@arm.com 42510259SAndrew.Bardsley@arm.com /* Fixup packet in fetch_request as this may have changed */ 42610259SAndrew.Bardsley@arm.com assert(!fetch_request->packet); 42710259SAndrew.Bardsley@arm.com fetch_request->packet = response; 42810259SAndrew.Bardsley@arm.com 42910259SAndrew.Bardsley@arm.com numFetchesInMemorySystem--; 43010259SAndrew.Bardsley@arm.com fetch_request->state = FetchRequest::Complete; 43110259SAndrew.Bardsley@arm.com 43210259SAndrew.Bardsley@arm.com if (DTRACE(MinorTrace)) 43310259SAndrew.Bardsley@arm.com minorTraceResponseLine(name(), fetch_request); 43410259SAndrew.Bardsley@arm.com 43510259SAndrew.Bardsley@arm.com if (response->isError()) { 43610259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Received error response packet: %s\n", 43710259SAndrew.Bardsley@arm.com fetch_request->id); 43810259SAndrew.Bardsley@arm.com } 43910259SAndrew.Bardsley@arm.com 44010259SAndrew.Bardsley@arm.com /* We go to idle even if there are more things to do on the queues as 44110259SAndrew.Bardsley@arm.com * it's the job of step to actually step us on to the next transaction */ 44210259SAndrew.Bardsley@arm.com 44310259SAndrew.Bardsley@arm.com /* Let's try and wake up the processor for the next cycle to move on 44410259SAndrew.Bardsley@arm.com * queues */ 44510259SAndrew.Bardsley@arm.com cpu.wakeupOnEvent(Pipeline::Fetch1StageId); 44610259SAndrew.Bardsley@arm.com 44710259SAndrew.Bardsley@arm.com /* Never busy */ 44810259SAndrew.Bardsley@arm.com return true; 44910259SAndrew.Bardsley@arm.com} 45010259SAndrew.Bardsley@arm.com 45110259SAndrew.Bardsley@arm.comvoid 45210713Sandreas.hansson@arm.comFetch1::recvReqRetry() 45310259SAndrew.Bardsley@arm.com{ 45410259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "recvRetry\n"); 45510259SAndrew.Bardsley@arm.com assert(icacheState == IcacheNeedsRetry); 45610259SAndrew.Bardsley@arm.com assert(!requests.empty()); 45710259SAndrew.Bardsley@arm.com 45810259SAndrew.Bardsley@arm.com FetchRequestPtr retryRequest = requests.front(); 45910259SAndrew.Bardsley@arm.com 46010259SAndrew.Bardsley@arm.com icacheState = IcacheRunning; 46110259SAndrew.Bardsley@arm.com 46210259SAndrew.Bardsley@arm.com if (tryToSend(retryRequest)) 46310259SAndrew.Bardsley@arm.com moveFromRequestsToTransfers(retryRequest); 46410259SAndrew.Bardsley@arm.com} 46510259SAndrew.Bardsley@arm.com 46610259SAndrew.Bardsley@arm.comstd::ostream & 46710259SAndrew.Bardsley@arm.comoperator <<(std::ostream &os, Fetch1::FetchState state) 46810259SAndrew.Bardsley@arm.com{ 46910259SAndrew.Bardsley@arm.com switch (state) { 47010259SAndrew.Bardsley@arm.com case Fetch1::FetchHalted: 47110259SAndrew.Bardsley@arm.com os << "FetchHalted"; 47210259SAndrew.Bardsley@arm.com break; 47310259SAndrew.Bardsley@arm.com case Fetch1::FetchWaitingForPC: 47410259SAndrew.Bardsley@arm.com os << "FetchWaitingForPC"; 47510259SAndrew.Bardsley@arm.com break; 47610259SAndrew.Bardsley@arm.com case Fetch1::FetchRunning: 47710259SAndrew.Bardsley@arm.com os << "FetchRunning"; 47810259SAndrew.Bardsley@arm.com break; 47910259SAndrew.Bardsley@arm.com default: 48010259SAndrew.Bardsley@arm.com os << "FetchState-" << static_cast<int>(state); 48110259SAndrew.Bardsley@arm.com break; 48210259SAndrew.Bardsley@arm.com } 48310259SAndrew.Bardsley@arm.com return os; 48410259SAndrew.Bardsley@arm.com} 48510259SAndrew.Bardsley@arm.com 48610259SAndrew.Bardsley@arm.comvoid 48710259SAndrew.Bardsley@arm.comFetch1::changeStream(const BranchData &branch) 48810259SAndrew.Bardsley@arm.com{ 48911567Smitch.hayenga@arm.com Fetch1ThreadInfo &thread = fetchInfo[branch.threadId]; 49011567Smitch.hayenga@arm.com 49110259SAndrew.Bardsley@arm.com updateExpectedSeqNums(branch); 49210259SAndrew.Bardsley@arm.com 49310259SAndrew.Bardsley@arm.com /* Start fetching again if we were stopped */ 49410259SAndrew.Bardsley@arm.com switch (branch.reason) { 49510259SAndrew.Bardsley@arm.com case BranchData::SuspendThread: 49611567Smitch.hayenga@arm.com { 49711567Smitch.hayenga@arm.com if (thread.wakeupGuard) { 49811567Smitch.hayenga@arm.com DPRINTF(Fetch, "Not suspending fetch due to guard: %s\n", 49911567Smitch.hayenga@arm.com branch); 50011567Smitch.hayenga@arm.com } else { 50111567Smitch.hayenga@arm.com DPRINTF(Fetch, "Suspending fetch: %s\n", branch); 50211567Smitch.hayenga@arm.com thread.state = FetchWaitingForPC; 50311567Smitch.hayenga@arm.com } 50411567Smitch.hayenga@arm.com } 50510259SAndrew.Bardsley@arm.com break; 50610259SAndrew.Bardsley@arm.com case BranchData::HaltFetch: 50710259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Halting fetch\n"); 50811567Smitch.hayenga@arm.com thread.state = FetchHalted; 50910259SAndrew.Bardsley@arm.com break; 51010259SAndrew.Bardsley@arm.com default: 51110259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Changing stream on branch: %s\n", branch); 51211567Smitch.hayenga@arm.com thread.state = FetchRunning; 51310259SAndrew.Bardsley@arm.com break; 51410259SAndrew.Bardsley@arm.com } 51511567Smitch.hayenga@arm.com thread.pc = branch.target; 51610259SAndrew.Bardsley@arm.com} 51710259SAndrew.Bardsley@arm.com 51810259SAndrew.Bardsley@arm.comvoid 51910259SAndrew.Bardsley@arm.comFetch1::updateExpectedSeqNums(const BranchData &branch) 52010259SAndrew.Bardsley@arm.com{ 52111567Smitch.hayenga@arm.com Fetch1ThreadInfo &thread = fetchInfo[branch.threadId]; 52211567Smitch.hayenga@arm.com 52310259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Updating streamSeqNum from: %d to %d," 52410259SAndrew.Bardsley@arm.com " predictionSeqNum from: %d to %d\n", 52511567Smitch.hayenga@arm.com thread.streamSeqNum, branch.newStreamSeqNum, 52611567Smitch.hayenga@arm.com thread.predictionSeqNum, branch.newPredictionSeqNum); 52710259SAndrew.Bardsley@arm.com 52810259SAndrew.Bardsley@arm.com /* Change the stream */ 52911567Smitch.hayenga@arm.com thread.streamSeqNum = branch.newStreamSeqNum; 53010259SAndrew.Bardsley@arm.com /* Update the prediction. Note that it's possible for this to 53110259SAndrew.Bardsley@arm.com * actually set the prediction to an *older* value if new 53210259SAndrew.Bardsley@arm.com * predictions have been discarded by execute */ 53311567Smitch.hayenga@arm.com thread.predictionSeqNum = branch.newPredictionSeqNum; 53410259SAndrew.Bardsley@arm.com} 53510259SAndrew.Bardsley@arm.com 53610259SAndrew.Bardsley@arm.comvoid 53710259SAndrew.Bardsley@arm.comFetch1::processResponse(Fetch1::FetchRequestPtr response, 53810259SAndrew.Bardsley@arm.com ForwardLineData &line) 53910259SAndrew.Bardsley@arm.com{ 54011567Smitch.hayenga@arm.com Fetch1ThreadInfo &thread = fetchInfo[response->id.threadId]; 54110259SAndrew.Bardsley@arm.com PacketPtr packet = response->packet; 54210259SAndrew.Bardsley@arm.com 54310259SAndrew.Bardsley@arm.com /* Pass the prefetch abort (if any) on to Fetch2 in a ForwardLineData 54410259SAndrew.Bardsley@arm.com * structure */ 54510259SAndrew.Bardsley@arm.com line.setFault(response->fault); 54610259SAndrew.Bardsley@arm.com /* Make sequence numbers valid in return */ 54710259SAndrew.Bardsley@arm.com line.id = response->id; 54810259SAndrew.Bardsley@arm.com /* Set PC to virtual address */ 54910259SAndrew.Bardsley@arm.com line.pc = response->pc; 55010259SAndrew.Bardsley@arm.com /* Set the lineBase, which is a sizeof(MachInst) aligned address <= 55110259SAndrew.Bardsley@arm.com * pc.instAddr() */ 55210259SAndrew.Bardsley@arm.com line.lineBaseAddr = response->request.getVaddr(); 55310259SAndrew.Bardsley@arm.com 55410259SAndrew.Bardsley@arm.com if (response->fault != NoFault) { 55510259SAndrew.Bardsley@arm.com /* Stop fetching if there was a fault */ 55610259SAndrew.Bardsley@arm.com /* Should probably try to flush the queues as well, but we 55710259SAndrew.Bardsley@arm.com * can't be sure that this fault will actually reach Execute, and we 55810259SAndrew.Bardsley@arm.com * can't (currently) selectively remove this stream from the queues */ 55910259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Stopping line fetch because of fault: %s\n", 56010259SAndrew.Bardsley@arm.com response->fault->name()); 56111567Smitch.hayenga@arm.com thread.state = Fetch1::FetchWaitingForPC; 56210259SAndrew.Bardsley@arm.com } else { 56310259SAndrew.Bardsley@arm.com line.adoptPacketData(packet); 56410259SAndrew.Bardsley@arm.com /* Null the response's packet to prevent the response from trying to 56510259SAndrew.Bardsley@arm.com * deallocate the packet */ 56610259SAndrew.Bardsley@arm.com response->packet = NULL; 56710259SAndrew.Bardsley@arm.com } 56810259SAndrew.Bardsley@arm.com} 56910259SAndrew.Bardsley@arm.com 57010259SAndrew.Bardsley@arm.comvoid 57110259SAndrew.Bardsley@arm.comFetch1::evaluate() 57210259SAndrew.Bardsley@arm.com{ 57310259SAndrew.Bardsley@arm.com const BranchData &execute_branch = *inp.outputWire; 57410259SAndrew.Bardsley@arm.com const BranchData &fetch2_branch = *prediction.outputWire; 57510259SAndrew.Bardsley@arm.com ForwardLineData &line_out = *out.inputWire; 57610259SAndrew.Bardsley@arm.com 57710259SAndrew.Bardsley@arm.com assert(line_out.isBubble()); 57810259SAndrew.Bardsley@arm.com 57911567Smitch.hayenga@arm.com for (ThreadID tid = 0; tid < cpu.numThreads; tid++) 58011567Smitch.hayenga@arm.com fetchInfo[tid].blocked = !nextStageReserve[tid].canReserve(); 58110259SAndrew.Bardsley@arm.com 58211567Smitch.hayenga@arm.com /** Are both branches from later stages valid and for the same thread? */ 58311567Smitch.hayenga@arm.com if (execute_branch.threadId != InvalidThreadID && 58411567Smitch.hayenga@arm.com execute_branch.threadId == fetch2_branch.threadId) { 58511567Smitch.hayenga@arm.com 58611567Smitch.hayenga@arm.com Fetch1ThreadInfo &thread = fetchInfo[execute_branch.threadId]; 58711567Smitch.hayenga@arm.com 58811567Smitch.hayenga@arm.com /* Are we changing stream? Look to the Execute branches first, then 58911567Smitch.hayenga@arm.com * to predicted changes of stream from Fetch2 */ 59011567Smitch.hayenga@arm.com if (execute_branch.isStreamChange()) { 59111567Smitch.hayenga@arm.com if (thread.state == FetchHalted) { 59211567Smitch.hayenga@arm.com DPRINTF(Fetch, "Halted, ignoring branch: %s\n", execute_branch); 59311567Smitch.hayenga@arm.com } else { 59410259SAndrew.Bardsley@arm.com changeStream(execute_branch); 59511567Smitch.hayenga@arm.com } 59611567Smitch.hayenga@arm.com 59711567Smitch.hayenga@arm.com if (!fetch2_branch.isBubble()) { 59811567Smitch.hayenga@arm.com DPRINTF(Fetch, "Ignoring simultaneous prediction: %s\n", 59911567Smitch.hayenga@arm.com fetch2_branch); 60011567Smitch.hayenga@arm.com } 60111567Smitch.hayenga@arm.com 60211567Smitch.hayenga@arm.com /* The streamSeqNum tagging in request/response ->req should handle 60311567Smitch.hayenga@arm.com * discarding those requests when we get to them. */ 60411567Smitch.hayenga@arm.com } else if (thread.state != FetchHalted && fetch2_branch.isStreamChange()) { 60511567Smitch.hayenga@arm.com /* Handle branch predictions by changing the instruction source 60611567Smitch.hayenga@arm.com * if we're still processing the same stream (as set by streamSeqNum) 60711567Smitch.hayenga@arm.com * as the one of the prediction. 60811567Smitch.hayenga@arm.com */ 60911567Smitch.hayenga@arm.com if (fetch2_branch.newStreamSeqNum != thread.streamSeqNum) { 61011567Smitch.hayenga@arm.com DPRINTF(Fetch, "Not changing stream on prediction: %s," 61111567Smitch.hayenga@arm.com " streamSeqNum mismatch\n", 61211567Smitch.hayenga@arm.com fetch2_branch); 61310259SAndrew.Bardsley@arm.com } else { 61411567Smitch.hayenga@arm.com changeStream(fetch2_branch); 61510259SAndrew.Bardsley@arm.com } 61611567Smitch.hayenga@arm.com } 61711567Smitch.hayenga@arm.com } else { 61811567Smitch.hayenga@arm.com /* Fetch2 and Execute branches are for different threads */ 61911567Smitch.hayenga@arm.com if (execute_branch.threadId != InvalidThreadID && 62011567Smitch.hayenga@arm.com execute_branch.isStreamChange()) { 62111567Smitch.hayenga@arm.com 62211567Smitch.hayenga@arm.com if (fetchInfo[execute_branch.threadId].state == FetchHalted) { 62311567Smitch.hayenga@arm.com DPRINTF(Fetch, "Halted, ignoring branch: %s\n", execute_branch); 62411567Smitch.hayenga@arm.com } else { 62511567Smitch.hayenga@arm.com changeStream(execute_branch); 62611567Smitch.hayenga@arm.com } 62710259SAndrew.Bardsley@arm.com } 62810259SAndrew.Bardsley@arm.com 62911567Smitch.hayenga@arm.com if (fetch2_branch.threadId != InvalidThreadID && 63011567Smitch.hayenga@arm.com fetch2_branch.isStreamChange()) { 63110259SAndrew.Bardsley@arm.com 63211567Smitch.hayenga@arm.com if (fetchInfo[fetch2_branch.threadId].state == FetchHalted) { 63311567Smitch.hayenga@arm.com DPRINTF(Fetch, "Halted, ignoring branch: %s\n", fetch2_branch); 63411567Smitch.hayenga@arm.com } else if (fetch2_branch.newStreamSeqNum != fetchInfo[fetch2_branch.threadId].streamSeqNum) { 63511567Smitch.hayenga@arm.com DPRINTF(Fetch, "Not changing stream on prediction: %s," 63611567Smitch.hayenga@arm.com " streamSeqNum mismatch\n", fetch2_branch); 63711567Smitch.hayenga@arm.com } else { 63811567Smitch.hayenga@arm.com changeStream(fetch2_branch); 63911567Smitch.hayenga@arm.com } 64010259SAndrew.Bardsley@arm.com } 64110259SAndrew.Bardsley@arm.com } 64210259SAndrew.Bardsley@arm.com 64311567Smitch.hayenga@arm.com if (numInFlightFetches() < fetchLimit) { 64411567Smitch.hayenga@arm.com ThreadID fetch_tid = getScheduledThread(); 64511567Smitch.hayenga@arm.com 64611567Smitch.hayenga@arm.com if (fetch_tid != InvalidThreadID) { 64711567Smitch.hayenga@arm.com DPRINTF(Fetch, "Fetching from thread %d\n", fetch_tid); 64811567Smitch.hayenga@arm.com 64911567Smitch.hayenga@arm.com /* Generate fetch to selected thread */ 65011567Smitch.hayenga@arm.com fetchLine(fetch_tid); 65111567Smitch.hayenga@arm.com /* Take up a slot in the fetch queue */ 65211567Smitch.hayenga@arm.com nextStageReserve[fetch_tid].reserve(); 65311567Smitch.hayenga@arm.com } else { 65411567Smitch.hayenga@arm.com DPRINTF(Fetch, "No active threads available to fetch from\n"); 65511567Smitch.hayenga@arm.com } 65610259SAndrew.Bardsley@arm.com } 65710259SAndrew.Bardsley@arm.com 65811567Smitch.hayenga@arm.com 65910259SAndrew.Bardsley@arm.com /* Halting shouldn't prevent fetches in flight from being processed */ 66010259SAndrew.Bardsley@arm.com /* Step fetches through the icachePort queues and memory system */ 66110259SAndrew.Bardsley@arm.com stepQueues(); 66210259SAndrew.Bardsley@arm.com 66310259SAndrew.Bardsley@arm.com /* As we've thrown away early lines, if there is a line, it must 66410259SAndrew.Bardsley@arm.com * be from the right stream */ 66510259SAndrew.Bardsley@arm.com if (!transfers.empty() && 66610259SAndrew.Bardsley@arm.com transfers.front()->isComplete()) 66710259SAndrew.Bardsley@arm.com { 66810259SAndrew.Bardsley@arm.com Fetch1::FetchRequestPtr response = transfers.front(); 66910259SAndrew.Bardsley@arm.com 67010259SAndrew.Bardsley@arm.com if (response->isDiscardable()) { 67111567Smitch.hayenga@arm.com nextStageReserve[response->id.threadId].freeReservation(); 67210259SAndrew.Bardsley@arm.com 67311567Smitch.hayenga@arm.com DPRINTF(Fetch, "Discarding translated fetch as it's for" 67410259SAndrew.Bardsley@arm.com " an old stream\n"); 67510259SAndrew.Bardsley@arm.com 67610259SAndrew.Bardsley@arm.com /* Wake up next cycle just in case there was some other 67710259SAndrew.Bardsley@arm.com * action to do */ 67810259SAndrew.Bardsley@arm.com cpu.wakeupOnEvent(Pipeline::Fetch1StageId); 67910259SAndrew.Bardsley@arm.com } else { 68010259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Processing fetched line: %s\n", 68110259SAndrew.Bardsley@arm.com response->id); 68210259SAndrew.Bardsley@arm.com 68310259SAndrew.Bardsley@arm.com processResponse(response, line_out); 68410259SAndrew.Bardsley@arm.com } 68510259SAndrew.Bardsley@arm.com 68610259SAndrew.Bardsley@arm.com popAndDiscard(transfers); 68710259SAndrew.Bardsley@arm.com } 68810259SAndrew.Bardsley@arm.com 68910259SAndrew.Bardsley@arm.com /* If we generated output, and mark the stage as being active 69010259SAndrew.Bardsley@arm.com * to encourage that output on to the next stage */ 69110259SAndrew.Bardsley@arm.com if (!line_out.isBubble()) 69210259SAndrew.Bardsley@arm.com cpu.activityRecorder->activity(); 69310259SAndrew.Bardsley@arm.com 69410259SAndrew.Bardsley@arm.com /* Fetch1 has no inputBuffer so the only activity we can have is to 69510259SAndrew.Bardsley@arm.com * generate a line output (tested just above) or to initiate a memory 69610259SAndrew.Bardsley@arm.com * fetch which will signal activity when it returns/needs stepping 69710259SAndrew.Bardsley@arm.com * between queues */ 69811567Smitch.hayenga@arm.com 69911567Smitch.hayenga@arm.com 70011567Smitch.hayenga@arm.com /* This looks hackish. And it is, but there doesn't seem to be a better 70111567Smitch.hayenga@arm.com * way to do this. The signal from commit to suspend fetch takes 1 70211567Smitch.hayenga@arm.com * clock cycle to propagate to fetch. However, a legitimate wakeup 70311567Smitch.hayenga@arm.com * may occur between cycles from the memory system. Thus wakeup guard 70411567Smitch.hayenga@arm.com * prevents us from suspending in that case. */ 70511567Smitch.hayenga@arm.com 70611567Smitch.hayenga@arm.com for (auto& thread : fetchInfo) { 70711567Smitch.hayenga@arm.com thread.wakeupGuard = false; 70811567Smitch.hayenga@arm.com } 70911567Smitch.hayenga@arm.com} 71011567Smitch.hayenga@arm.com 71111567Smitch.hayenga@arm.comvoid 71211567Smitch.hayenga@arm.comFetch1::wakeupFetch(ThreadID tid) 71311567Smitch.hayenga@arm.com{ 71411567Smitch.hayenga@arm.com ThreadContext *thread_ctx = cpu.getContext(tid); 71511567Smitch.hayenga@arm.com Fetch1ThreadInfo &thread = fetchInfo[tid]; 71611567Smitch.hayenga@arm.com thread.pc = thread_ctx->pcState(); 71711567Smitch.hayenga@arm.com thread.state = FetchRunning; 71811567Smitch.hayenga@arm.com thread.wakeupGuard = true; 71911567Smitch.hayenga@arm.com DPRINTF(Fetch, "[tid:%d]: Changing stream wakeup %s\n", 72011567Smitch.hayenga@arm.com tid, thread_ctx->pcState()); 72111567Smitch.hayenga@arm.com 72211567Smitch.hayenga@arm.com cpu.wakeupOnEvent(Pipeline::Fetch1StageId); 72310259SAndrew.Bardsley@arm.com} 72410259SAndrew.Bardsley@arm.com 72510259SAndrew.Bardsley@arm.combool 72610259SAndrew.Bardsley@arm.comFetch1::isDrained() 72710259SAndrew.Bardsley@arm.com{ 72811567Smitch.hayenga@arm.com bool drained = numInFlightFetches() == 0 && (*out.inputWire).isBubble(); 72911567Smitch.hayenga@arm.com for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 73011567Smitch.hayenga@arm.com Fetch1ThreadInfo &thread = fetchInfo[tid]; 73111567Smitch.hayenga@arm.com DPRINTF(Drain, "isDrained[tid:%d]: %s %s%s\n", 73211567Smitch.hayenga@arm.com tid, 73311567Smitch.hayenga@arm.com thread.state == FetchHalted, 73411567Smitch.hayenga@arm.com (numInFlightFetches() == 0 ? "" : "inFlightFetches "), 73511567Smitch.hayenga@arm.com ((*out.inputWire).isBubble() ? "" : "outputtingLine")); 73610259SAndrew.Bardsley@arm.com 73711568Smitch.hayenga@arm.com drained = drained && (thread.state != FetchRunning); 73811567Smitch.hayenga@arm.com } 73911567Smitch.hayenga@arm.com 74011567Smitch.hayenga@arm.com return drained; 74110259SAndrew.Bardsley@arm.com} 74210259SAndrew.Bardsley@arm.com 74310259SAndrew.Bardsley@arm.comvoid 74410259SAndrew.Bardsley@arm.comFetch1::FetchRequest::reportData(std::ostream &os) const 74510259SAndrew.Bardsley@arm.com{ 74610259SAndrew.Bardsley@arm.com os << id; 74710259SAndrew.Bardsley@arm.com} 74810259SAndrew.Bardsley@arm.com 74910259SAndrew.Bardsley@arm.combool Fetch1::FetchRequest::isDiscardable() const 75010259SAndrew.Bardsley@arm.com{ 75111567Smitch.hayenga@arm.com Fetch1ThreadInfo &thread = fetch.fetchInfo[id.threadId]; 75211567Smitch.hayenga@arm.com 75310259SAndrew.Bardsley@arm.com /* Can't discard lines in TLB/memory */ 75410259SAndrew.Bardsley@arm.com return state != InTranslation && state != RequestIssuing && 75511567Smitch.hayenga@arm.com (id.streamSeqNum != thread.streamSeqNum || 75611567Smitch.hayenga@arm.com id.predictionSeqNum != thread.predictionSeqNum); 75710259SAndrew.Bardsley@arm.com} 75810259SAndrew.Bardsley@arm.com 75910259SAndrew.Bardsley@arm.comvoid 76010259SAndrew.Bardsley@arm.comFetch1::minorTrace() const 76110259SAndrew.Bardsley@arm.com{ 76211567Smitch.hayenga@arm.com // TODO: Un-bork minorTrace for THREADS 76311567Smitch.hayenga@arm.com // bork bork bork 76411567Smitch.hayenga@arm.com const Fetch1ThreadInfo &thread = fetchInfo[0]; 76511567Smitch.hayenga@arm.com 76610259SAndrew.Bardsley@arm.com std::ostringstream data; 76710259SAndrew.Bardsley@arm.com 76811567Smitch.hayenga@arm.com if (thread.blocked) 76910259SAndrew.Bardsley@arm.com data << 'B'; 77010259SAndrew.Bardsley@arm.com else 77110259SAndrew.Bardsley@arm.com (*out.inputWire).reportData(data); 77210259SAndrew.Bardsley@arm.com 77310259SAndrew.Bardsley@arm.com MINORTRACE("state=%s icacheState=%s in_tlb_mem=%s/%s" 77411567Smitch.hayenga@arm.com " streamSeqNum=%d lines=%s\n", thread.state, icacheState, 77510259SAndrew.Bardsley@arm.com numFetchesInITLB, numFetchesInMemorySystem, 77611567Smitch.hayenga@arm.com thread.streamSeqNum, data.str()); 77710259SAndrew.Bardsley@arm.com requests.minorTrace(); 77810259SAndrew.Bardsley@arm.com transfers.minorTrace(); 77910259SAndrew.Bardsley@arm.com} 78010259SAndrew.Bardsley@arm.com 78110259SAndrew.Bardsley@arm.com} 782