fetch1.cc revision 12749
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 4011793Sbrandon.potter@amd.com#include "cpu/minor/fetch1.hh" 4111793Sbrandon.potter@amd.com 4210259SAndrew.Bardsley@arm.com#include <cstring> 4310259SAndrew.Bardsley@arm.com#include <iomanip> 4410259SAndrew.Bardsley@arm.com#include <sstream> 4510259SAndrew.Bardsley@arm.com 4610259SAndrew.Bardsley@arm.com#include "base/cast.hh" 4710259SAndrew.Bardsley@arm.com#include "cpu/minor/pipeline.hh" 4810259SAndrew.Bardsley@arm.com#include "debug/Drain.hh" 4910259SAndrew.Bardsley@arm.com#include "debug/Fetch.hh" 5010259SAndrew.Bardsley@arm.com#include "debug/MinorTrace.hh" 5110259SAndrew.Bardsley@arm.com 5210259SAndrew.Bardsley@arm.comnamespace Minor 5310259SAndrew.Bardsley@arm.com{ 5410259SAndrew.Bardsley@arm.com 5510259SAndrew.Bardsley@arm.comFetch1::Fetch1(const std::string &name_, 5610259SAndrew.Bardsley@arm.com MinorCPU &cpu_, 5710259SAndrew.Bardsley@arm.com MinorCPUParams ¶ms, 5810259SAndrew.Bardsley@arm.com Latch<BranchData>::Output inp_, 5910259SAndrew.Bardsley@arm.com Latch<ForwardLineData>::Input out_, 6010259SAndrew.Bardsley@arm.com Latch<BranchData>::Output prediction_, 6111567Smitch.hayenga@arm.com std::vector<InputBuffer<ForwardLineData>> &next_stage_input_buffer) : 6210259SAndrew.Bardsley@arm.com Named(name_), 6310259SAndrew.Bardsley@arm.com cpu(cpu_), 6410259SAndrew.Bardsley@arm.com inp(inp_), 6510259SAndrew.Bardsley@arm.com out(out_), 6610259SAndrew.Bardsley@arm.com prediction(prediction_), 6710259SAndrew.Bardsley@arm.com nextStageReserve(next_stage_input_buffer), 6810259SAndrew.Bardsley@arm.com icachePort(name_ + ".icache_port", *this, cpu_), 6910259SAndrew.Bardsley@arm.com lineSnap(params.fetch1LineSnapWidth), 7010259SAndrew.Bardsley@arm.com maxLineWidth(params.fetch1LineWidth), 7110259SAndrew.Bardsley@arm.com fetchLimit(params.fetch1FetchLimit), 7211567Smitch.hayenga@arm.com fetchInfo(params.numThreads), 7311567Smitch.hayenga@arm.com threadPriority(0), 7410259SAndrew.Bardsley@arm.com requests(name_ + ".requests", "lines", params.fetch1FetchLimit), 7510259SAndrew.Bardsley@arm.com transfers(name_ + ".transfers", "lines", params.fetch1FetchLimit), 7610259SAndrew.Bardsley@arm.com icacheState(IcacheRunning), 7710259SAndrew.Bardsley@arm.com lineSeqNum(InstId::firstLineSeqNum), 7810259SAndrew.Bardsley@arm.com numFetchesInMemorySystem(0), 7910259SAndrew.Bardsley@arm.com numFetchesInITLB(0) 8010259SAndrew.Bardsley@arm.com{ 8110259SAndrew.Bardsley@arm.com if (lineSnap == 0) { 8210259SAndrew.Bardsley@arm.com lineSnap = cpu.cacheLineSize(); 8310259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "lineSnap set to cache line size of: %d\n", 8410259SAndrew.Bardsley@arm.com lineSnap); 8510259SAndrew.Bardsley@arm.com } 8610259SAndrew.Bardsley@arm.com 8710259SAndrew.Bardsley@arm.com if (maxLineWidth == 0) { 8810259SAndrew.Bardsley@arm.com maxLineWidth = cpu.cacheLineSize(); 8910259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "maxLineWidth set to cache line size of: %d\n", 9010259SAndrew.Bardsley@arm.com maxLineWidth); 9110259SAndrew.Bardsley@arm.com } 9210259SAndrew.Bardsley@arm.com 9310259SAndrew.Bardsley@arm.com /* These assertions should be copied to the Python config. as well */ 9410259SAndrew.Bardsley@arm.com if ((lineSnap % sizeof(TheISA::MachInst)) != 0) { 9510259SAndrew.Bardsley@arm.com fatal("%s: fetch1LineSnapWidth must be a multiple " 9610259SAndrew.Bardsley@arm.com "of sizeof(TheISA::MachInst) (%d)\n", name_, 9710259SAndrew.Bardsley@arm.com sizeof(TheISA::MachInst)); 9810259SAndrew.Bardsley@arm.com } 9910259SAndrew.Bardsley@arm.com 10010259SAndrew.Bardsley@arm.com if (!(maxLineWidth >= lineSnap && 10110259SAndrew.Bardsley@arm.com (maxLineWidth % sizeof(TheISA::MachInst)) == 0)) 10210259SAndrew.Bardsley@arm.com { 10310259SAndrew.Bardsley@arm.com fatal("%s: fetch1LineWidth must be a multiple of" 10410259SAndrew.Bardsley@arm.com " sizeof(TheISA::MachInst)" 10510259SAndrew.Bardsley@arm.com " (%d), and >= fetch1LineSnapWidth (%d)\n", 10610259SAndrew.Bardsley@arm.com name_, sizeof(TheISA::MachInst), lineSnap); 10710259SAndrew.Bardsley@arm.com } 10810259SAndrew.Bardsley@arm.com 10910259SAndrew.Bardsley@arm.com if (fetchLimit < 1) { 11010259SAndrew.Bardsley@arm.com fatal("%s: fetch1FetchLimit must be >= 1 (%d)\n", name_, 11110259SAndrew.Bardsley@arm.com fetchLimit); 11210259SAndrew.Bardsley@arm.com } 11310259SAndrew.Bardsley@arm.com} 11410259SAndrew.Bardsley@arm.com 11511567Smitch.hayenga@arm.cominline ThreadID 11611567Smitch.hayenga@arm.comFetch1::getScheduledThread() 11711567Smitch.hayenga@arm.com{ 11811567Smitch.hayenga@arm.com /* Select thread via policy. */ 11911567Smitch.hayenga@arm.com std::vector<ThreadID> priority_list; 12011567Smitch.hayenga@arm.com 12111567Smitch.hayenga@arm.com switch (cpu.threadPolicy) { 12211567Smitch.hayenga@arm.com case Enums::SingleThreaded: 12311567Smitch.hayenga@arm.com priority_list.push_back(0); 12411567Smitch.hayenga@arm.com break; 12511567Smitch.hayenga@arm.com case Enums::RoundRobin: 12611567Smitch.hayenga@arm.com priority_list = cpu.roundRobinPriority(threadPriority); 12711567Smitch.hayenga@arm.com break; 12811567Smitch.hayenga@arm.com case Enums::Random: 12911567Smitch.hayenga@arm.com priority_list = cpu.randomPriority(); 13011567Smitch.hayenga@arm.com break; 13111567Smitch.hayenga@arm.com default: 13211567Smitch.hayenga@arm.com panic("Unknown fetch policy"); 13311567Smitch.hayenga@arm.com } 13411567Smitch.hayenga@arm.com 13511567Smitch.hayenga@arm.com for (auto tid : priority_list) { 13611567Smitch.hayenga@arm.com if (cpu.getContext(tid)->status() == ThreadContext::Active && 13711567Smitch.hayenga@arm.com !fetchInfo[tid].blocked && 13811567Smitch.hayenga@arm.com fetchInfo[tid].state == FetchRunning) { 13911567Smitch.hayenga@arm.com threadPriority = tid; 14011567Smitch.hayenga@arm.com return tid; 14111567Smitch.hayenga@arm.com } 14211567Smitch.hayenga@arm.com } 14311567Smitch.hayenga@arm.com 14411567Smitch.hayenga@arm.com return InvalidThreadID; 14511567Smitch.hayenga@arm.com} 14611567Smitch.hayenga@arm.com 14710259SAndrew.Bardsley@arm.comvoid 14811567Smitch.hayenga@arm.comFetch1::fetchLine(ThreadID tid) 14910259SAndrew.Bardsley@arm.com{ 15011567Smitch.hayenga@arm.com /* Reference the currently used thread state. */ 15111567Smitch.hayenga@arm.com Fetch1ThreadInfo &thread = fetchInfo[tid]; 15211567Smitch.hayenga@arm.com 15310259SAndrew.Bardsley@arm.com /* If line_offset != 0, a request is pushed for the remainder of the 15410259SAndrew.Bardsley@arm.com * line. */ 15510259SAndrew.Bardsley@arm.com /* Use a lower, sizeof(MachInst) aligned address for the fetch */ 15611567Smitch.hayenga@arm.com Addr aligned_pc = thread.pc.instAddr() & ~((Addr) lineSnap - 1); 15710259SAndrew.Bardsley@arm.com unsigned int line_offset = aligned_pc % lineSnap; 15810259SAndrew.Bardsley@arm.com unsigned int request_size = maxLineWidth - line_offset; 15910259SAndrew.Bardsley@arm.com 16010259SAndrew.Bardsley@arm.com /* Fill in the line's id */ 16111567Smitch.hayenga@arm.com InstId request_id(tid, 16211567Smitch.hayenga@arm.com thread.streamSeqNum, thread.predictionSeqNum, 16310259SAndrew.Bardsley@arm.com lineSeqNum); 16410259SAndrew.Bardsley@arm.com 16511567Smitch.hayenga@arm.com FetchRequestPtr request = new FetchRequest(*this, request_id, thread.pc); 16610259SAndrew.Bardsley@arm.com 16710259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Inserting fetch into the fetch queue " 16810259SAndrew.Bardsley@arm.com "%s addr: 0x%x pc: %s line_offset: %d request_size: %d\n", 16911567Smitch.hayenga@arm.com request_id, aligned_pc, thread.pc, line_offset, request_size); 17010259SAndrew.Bardsley@arm.com 17112749Sgiacomo.travaglini@arm.com request->request->setContext(cpu.threads[tid]->getTC()->contextId()); 17212749Sgiacomo.travaglini@arm.com request->request->setVirt(0 /* asid */, 17310259SAndrew.Bardsley@arm.com aligned_pc, request_size, Request::INST_FETCH, cpu.instMasterId(), 17410259SAndrew.Bardsley@arm.com /* I've no idea why we need the PC, but give it */ 17511567Smitch.hayenga@arm.com thread.pc.instAddr()); 17610259SAndrew.Bardsley@arm.com 17710259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Submitting ITLB request\n"); 17810259SAndrew.Bardsley@arm.com numFetchesInITLB++; 17910259SAndrew.Bardsley@arm.com 18010259SAndrew.Bardsley@arm.com request->state = FetchRequest::InTranslation; 18110259SAndrew.Bardsley@arm.com 18210259SAndrew.Bardsley@arm.com /* Reserve space in the queues upstream of requests for results */ 18310259SAndrew.Bardsley@arm.com transfers.reserve(); 18410259SAndrew.Bardsley@arm.com requests.push(request); 18510259SAndrew.Bardsley@arm.com 18610259SAndrew.Bardsley@arm.com /* Submit the translation request. The response will come 18710259SAndrew.Bardsley@arm.com * through finish/markDelayed on this request as it bears 18810259SAndrew.Bardsley@arm.com * the Translation interface */ 18910259SAndrew.Bardsley@arm.com cpu.threads[request->id.threadId]->itb->translateTiming( 19012749Sgiacomo.travaglini@arm.com request->request, 19110259SAndrew.Bardsley@arm.com cpu.getContext(request->id.threadId), 19210259SAndrew.Bardsley@arm.com request, BaseTLB::Execute); 19310259SAndrew.Bardsley@arm.com 19410259SAndrew.Bardsley@arm.com lineSeqNum++; 19510259SAndrew.Bardsley@arm.com 19610259SAndrew.Bardsley@arm.com /* Step the PC for the next line onto the line aligned next address. 19710259SAndrew.Bardsley@arm.com * Note that as instructions can span lines, this PC is only a 19810259SAndrew.Bardsley@arm.com * reliable 'new' PC if the next line has a new stream sequence number. */ 19910259SAndrew.Bardsley@arm.com#if THE_ISA == ALPHA_ISA 20010259SAndrew.Bardsley@arm.com /* Restore the low bits of the PC used as address space flags */ 20111567Smitch.hayenga@arm.com Addr pc_low_bits = thread.pc.instAddr() & 20210259SAndrew.Bardsley@arm.com ((Addr) (1 << sizeof(TheISA::MachInst)) - 1); 20310259SAndrew.Bardsley@arm.com 20411567Smitch.hayenga@arm.com thread.pc.set(aligned_pc + request_size + pc_low_bits); 20510259SAndrew.Bardsley@arm.com#else 20611567Smitch.hayenga@arm.com thread.pc.set(aligned_pc + request_size); 20710259SAndrew.Bardsley@arm.com#endif 20810259SAndrew.Bardsley@arm.com} 20910259SAndrew.Bardsley@arm.com 21010259SAndrew.Bardsley@arm.comstd::ostream & 21110259SAndrew.Bardsley@arm.comoperator <<(std::ostream &os, Fetch1::IcacheState state) 21210259SAndrew.Bardsley@arm.com{ 21310259SAndrew.Bardsley@arm.com switch (state) { 21410259SAndrew.Bardsley@arm.com case Fetch1::IcacheRunning: 21510259SAndrew.Bardsley@arm.com os << "IcacheRunning"; 21610259SAndrew.Bardsley@arm.com break; 21710259SAndrew.Bardsley@arm.com case Fetch1::IcacheNeedsRetry: 21810259SAndrew.Bardsley@arm.com os << "IcacheNeedsRetry"; 21910259SAndrew.Bardsley@arm.com break; 22010259SAndrew.Bardsley@arm.com default: 22110259SAndrew.Bardsley@arm.com os << "IcacheState-" << static_cast<int>(state); 22210259SAndrew.Bardsley@arm.com break; 22310259SAndrew.Bardsley@arm.com } 22410259SAndrew.Bardsley@arm.com return os; 22510259SAndrew.Bardsley@arm.com} 22610259SAndrew.Bardsley@arm.com 22710259SAndrew.Bardsley@arm.comvoid 22810259SAndrew.Bardsley@arm.comFetch1::FetchRequest::makePacket() 22910259SAndrew.Bardsley@arm.com{ 23010259SAndrew.Bardsley@arm.com /* Make the necessary packet for a memory transaction */ 23112749Sgiacomo.travaglini@arm.com packet = new Packet(request, MemCmd::ReadReq); 23210259SAndrew.Bardsley@arm.com packet->allocate(); 23310259SAndrew.Bardsley@arm.com 23410259SAndrew.Bardsley@arm.com /* This FetchRequest becomes SenderState to allow the response to be 23510259SAndrew.Bardsley@arm.com * identified */ 23610259SAndrew.Bardsley@arm.com packet->pushSenderState(this); 23710259SAndrew.Bardsley@arm.com} 23810259SAndrew.Bardsley@arm.com 23910259SAndrew.Bardsley@arm.comvoid 24012749Sgiacomo.travaglini@arm.comFetch1::FetchRequest::finish(const Fault &fault_, const RequestPtr &request_, 24110379Sandreas.hansson@arm.com ThreadContext *tc, BaseTLB::Mode mode) 24210259SAndrew.Bardsley@arm.com{ 24310259SAndrew.Bardsley@arm.com fault = fault_; 24410259SAndrew.Bardsley@arm.com 24510259SAndrew.Bardsley@arm.com state = Translated; 24610259SAndrew.Bardsley@arm.com fetch.handleTLBResponse(this); 24710259SAndrew.Bardsley@arm.com 24810259SAndrew.Bardsley@arm.com /* Let's try and wake up the processor for the next cycle */ 24910259SAndrew.Bardsley@arm.com fetch.cpu.wakeupOnEvent(Pipeline::Fetch1StageId); 25010259SAndrew.Bardsley@arm.com} 25110259SAndrew.Bardsley@arm.com 25210259SAndrew.Bardsley@arm.comvoid 25310259SAndrew.Bardsley@arm.comFetch1::handleTLBResponse(FetchRequestPtr response) 25410259SAndrew.Bardsley@arm.com{ 25510259SAndrew.Bardsley@arm.com numFetchesInITLB--; 25610259SAndrew.Bardsley@arm.com 25710259SAndrew.Bardsley@arm.com if (response->fault != NoFault) { 25810259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Fault in address ITLB translation: %s, " 25910259SAndrew.Bardsley@arm.com "paddr: 0x%x, vaddr: 0x%x\n", 26010259SAndrew.Bardsley@arm.com response->fault->name(), 26112749Sgiacomo.travaglini@arm.com (response->request->hasPaddr() ? 26212749Sgiacomo.travaglini@arm.com response->request->getPaddr() : 0), 26312749Sgiacomo.travaglini@arm.com response->request->getVaddr()); 26410259SAndrew.Bardsley@arm.com 26510259SAndrew.Bardsley@arm.com if (DTRACE(MinorTrace)) 26610259SAndrew.Bardsley@arm.com minorTraceResponseLine(name(), response); 26710259SAndrew.Bardsley@arm.com } else { 26810259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Got ITLB response\n"); 26910259SAndrew.Bardsley@arm.com } 27010259SAndrew.Bardsley@arm.com 27110259SAndrew.Bardsley@arm.com response->state = FetchRequest::Translated; 27210259SAndrew.Bardsley@arm.com 27310259SAndrew.Bardsley@arm.com tryToSendToTransfers(response); 27410259SAndrew.Bardsley@arm.com} 27510259SAndrew.Bardsley@arm.com 27610259SAndrew.Bardsley@arm.comFetch1::FetchRequest::~FetchRequest() 27710259SAndrew.Bardsley@arm.com{ 27810259SAndrew.Bardsley@arm.com if (packet) 27910259SAndrew.Bardsley@arm.com delete packet; 28010259SAndrew.Bardsley@arm.com} 28110259SAndrew.Bardsley@arm.com 28210259SAndrew.Bardsley@arm.comvoid 28310259SAndrew.Bardsley@arm.comFetch1::tryToSendToTransfers(FetchRequestPtr request) 28410259SAndrew.Bardsley@arm.com{ 28510259SAndrew.Bardsley@arm.com if (!requests.empty() && requests.front() != request) { 28610259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Fetch not at front of requests queue, can't" 28710259SAndrew.Bardsley@arm.com " issue to memory\n"); 28810259SAndrew.Bardsley@arm.com return; 28910259SAndrew.Bardsley@arm.com } 29010259SAndrew.Bardsley@arm.com 29110259SAndrew.Bardsley@arm.com if (request->state == FetchRequest::InTranslation) { 29210259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Fetch still in translation, not issuing to" 29310259SAndrew.Bardsley@arm.com " memory\n"); 29410259SAndrew.Bardsley@arm.com return; 29510259SAndrew.Bardsley@arm.com } 29610259SAndrew.Bardsley@arm.com 29710259SAndrew.Bardsley@arm.com if (request->isDiscardable() || request->fault != NoFault) { 29810259SAndrew.Bardsley@arm.com /* Discarded and faulting requests carry on through transfers 29910259SAndrew.Bardsley@arm.com * as Complete/packet == NULL */ 30010259SAndrew.Bardsley@arm.com 30110259SAndrew.Bardsley@arm.com request->state = FetchRequest::Complete; 30210259SAndrew.Bardsley@arm.com moveFromRequestsToTransfers(request); 30310259SAndrew.Bardsley@arm.com 30410259SAndrew.Bardsley@arm.com /* Wake up the pipeline next cycle as there will be no event 30510259SAndrew.Bardsley@arm.com * for this queue->queue transfer */ 30610259SAndrew.Bardsley@arm.com cpu.wakeupOnEvent(Pipeline::Fetch1StageId); 30710259SAndrew.Bardsley@arm.com } else if (request->state == FetchRequest::Translated) { 30810259SAndrew.Bardsley@arm.com if (!request->packet) 30910259SAndrew.Bardsley@arm.com request->makePacket(); 31010259SAndrew.Bardsley@arm.com 31110259SAndrew.Bardsley@arm.com /* Ensure that the packet won't delete the request */ 31210259SAndrew.Bardsley@arm.com assert(request->packet->needsResponse()); 31310259SAndrew.Bardsley@arm.com 31410259SAndrew.Bardsley@arm.com if (tryToSend(request)) 31510259SAndrew.Bardsley@arm.com moveFromRequestsToTransfers(request); 31610259SAndrew.Bardsley@arm.com } else { 31710259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Not advancing line fetch\n"); 31810259SAndrew.Bardsley@arm.com } 31910259SAndrew.Bardsley@arm.com} 32010259SAndrew.Bardsley@arm.com 32110259SAndrew.Bardsley@arm.comvoid 32210259SAndrew.Bardsley@arm.comFetch1::moveFromRequestsToTransfers(FetchRequestPtr request) 32310259SAndrew.Bardsley@arm.com{ 32410259SAndrew.Bardsley@arm.com assert(!requests.empty() && requests.front() == request); 32510259SAndrew.Bardsley@arm.com 32610259SAndrew.Bardsley@arm.com requests.pop(); 32710259SAndrew.Bardsley@arm.com transfers.push(request); 32810259SAndrew.Bardsley@arm.com} 32910259SAndrew.Bardsley@arm.com 33010259SAndrew.Bardsley@arm.combool 33110259SAndrew.Bardsley@arm.comFetch1::tryToSend(FetchRequestPtr request) 33210259SAndrew.Bardsley@arm.com{ 33310259SAndrew.Bardsley@arm.com bool ret = false; 33410259SAndrew.Bardsley@arm.com 33510259SAndrew.Bardsley@arm.com if (icachePort.sendTimingReq(request->packet)) { 33610259SAndrew.Bardsley@arm.com /* Invalidate the fetch_requests packet so we don't 33710259SAndrew.Bardsley@arm.com * accidentally fail to deallocate it (or use it!) 33810259SAndrew.Bardsley@arm.com * later by overwriting it */ 33910259SAndrew.Bardsley@arm.com request->packet = NULL; 34010259SAndrew.Bardsley@arm.com request->state = FetchRequest::RequestIssuing; 34110259SAndrew.Bardsley@arm.com numFetchesInMemorySystem++; 34210259SAndrew.Bardsley@arm.com 34310259SAndrew.Bardsley@arm.com ret = true; 34410259SAndrew.Bardsley@arm.com 34510259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Issued fetch request to memory: %s\n", 34610259SAndrew.Bardsley@arm.com request->id); 34710259SAndrew.Bardsley@arm.com } else { 34810259SAndrew.Bardsley@arm.com /* Needs to be resent, wait for that */ 34910259SAndrew.Bardsley@arm.com icacheState = IcacheNeedsRetry; 35010259SAndrew.Bardsley@arm.com 35110259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Line fetch needs to retry: %s\n", 35210259SAndrew.Bardsley@arm.com request->id); 35310259SAndrew.Bardsley@arm.com } 35410259SAndrew.Bardsley@arm.com 35510259SAndrew.Bardsley@arm.com return ret; 35610259SAndrew.Bardsley@arm.com} 35710259SAndrew.Bardsley@arm.com 35810259SAndrew.Bardsley@arm.comvoid 35910259SAndrew.Bardsley@arm.comFetch1::stepQueues() 36010259SAndrew.Bardsley@arm.com{ 36110259SAndrew.Bardsley@arm.com IcacheState old_icache_state = icacheState; 36210259SAndrew.Bardsley@arm.com 36310259SAndrew.Bardsley@arm.com switch (icacheState) { 36410259SAndrew.Bardsley@arm.com case IcacheRunning: 36510259SAndrew.Bardsley@arm.com /* Move ITLB results on to the memory system */ 36610259SAndrew.Bardsley@arm.com if (!requests.empty()) { 36710259SAndrew.Bardsley@arm.com tryToSendToTransfers(requests.front()); 36810259SAndrew.Bardsley@arm.com } 36910259SAndrew.Bardsley@arm.com break; 37010259SAndrew.Bardsley@arm.com case IcacheNeedsRetry: 37110259SAndrew.Bardsley@arm.com break; 37210259SAndrew.Bardsley@arm.com } 37310259SAndrew.Bardsley@arm.com 37410259SAndrew.Bardsley@arm.com if (icacheState != old_icache_state) { 37510259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Step in state %s moving to state %s\n", 37610259SAndrew.Bardsley@arm.com old_icache_state, icacheState); 37710259SAndrew.Bardsley@arm.com } 37810259SAndrew.Bardsley@arm.com} 37910259SAndrew.Bardsley@arm.com 38010259SAndrew.Bardsley@arm.comvoid 38110259SAndrew.Bardsley@arm.comFetch1::popAndDiscard(FetchQueue &queue) 38210259SAndrew.Bardsley@arm.com{ 38310259SAndrew.Bardsley@arm.com if (!queue.empty()) { 38410259SAndrew.Bardsley@arm.com delete queue.front(); 38510259SAndrew.Bardsley@arm.com queue.pop(); 38610259SAndrew.Bardsley@arm.com } 38710259SAndrew.Bardsley@arm.com} 38810259SAndrew.Bardsley@arm.com 38910259SAndrew.Bardsley@arm.comunsigned int 39010259SAndrew.Bardsley@arm.comFetch1::numInFlightFetches() 39110259SAndrew.Bardsley@arm.com{ 39210259SAndrew.Bardsley@arm.com return requests.occupiedSpace() + 39310259SAndrew.Bardsley@arm.com transfers.occupiedSpace(); 39410259SAndrew.Bardsley@arm.com} 39510259SAndrew.Bardsley@arm.com 39610259SAndrew.Bardsley@arm.com/** Print the appropriate MinorLine line for a fetch response */ 39710259SAndrew.Bardsley@arm.comvoid 39810259SAndrew.Bardsley@arm.comFetch1::minorTraceResponseLine(const std::string &name, 39910259SAndrew.Bardsley@arm.com Fetch1::FetchRequestPtr response) const 40010259SAndrew.Bardsley@arm.com{ 40112749Sgiacomo.travaglini@arm.com const RequestPtr &request M5_VAR_USED = response->request; 40210259SAndrew.Bardsley@arm.com 40310259SAndrew.Bardsley@arm.com if (response->packet && response->packet->isError()) { 40410259SAndrew.Bardsley@arm.com MINORLINE(this, "id=F;%s vaddr=0x%x fault=\"error packet\"\n", 40512749Sgiacomo.travaglini@arm.com response->id, request->getVaddr()); 40610259SAndrew.Bardsley@arm.com } else if (response->fault != NoFault) { 40710259SAndrew.Bardsley@arm.com MINORLINE(this, "id=F;%s vaddr=0x%x fault=\"%s\"\n", 40812749Sgiacomo.travaglini@arm.com response->id, request->getVaddr(), response->fault->name()); 40910259SAndrew.Bardsley@arm.com } else { 41010259SAndrew.Bardsley@arm.com MINORLINE(this, "id=%s size=%d vaddr=0x%x paddr=0x%x\n", 41112749Sgiacomo.travaglini@arm.com response->id, request->getSize(), 41212749Sgiacomo.travaglini@arm.com request->getVaddr(), request->getPaddr()); 41310259SAndrew.Bardsley@arm.com } 41410259SAndrew.Bardsley@arm.com} 41510259SAndrew.Bardsley@arm.com 41610259SAndrew.Bardsley@arm.combool 41710259SAndrew.Bardsley@arm.comFetch1::recvTimingResp(PacketPtr response) 41810259SAndrew.Bardsley@arm.com{ 41910259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "recvTimingResp %d\n", numFetchesInMemorySystem); 42010259SAndrew.Bardsley@arm.com 42110259SAndrew.Bardsley@arm.com /* Only push the response if we didn't change stream? No, all responses 42210259SAndrew.Bardsley@arm.com * should hit the responses queue. It's the job of 'step' to throw them 42310259SAndrew.Bardsley@arm.com * away. */ 42410259SAndrew.Bardsley@arm.com FetchRequestPtr fetch_request = safe_cast<FetchRequestPtr> 42510259SAndrew.Bardsley@arm.com (response->popSenderState()); 42610259SAndrew.Bardsley@arm.com 42710259SAndrew.Bardsley@arm.com /* Fixup packet in fetch_request as this may have changed */ 42810259SAndrew.Bardsley@arm.com assert(!fetch_request->packet); 42910259SAndrew.Bardsley@arm.com fetch_request->packet = response; 43010259SAndrew.Bardsley@arm.com 43110259SAndrew.Bardsley@arm.com numFetchesInMemorySystem--; 43210259SAndrew.Bardsley@arm.com fetch_request->state = FetchRequest::Complete; 43310259SAndrew.Bardsley@arm.com 43410259SAndrew.Bardsley@arm.com if (DTRACE(MinorTrace)) 43510259SAndrew.Bardsley@arm.com minorTraceResponseLine(name(), fetch_request); 43610259SAndrew.Bardsley@arm.com 43710259SAndrew.Bardsley@arm.com if (response->isError()) { 43810259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Received error response packet: %s\n", 43910259SAndrew.Bardsley@arm.com fetch_request->id); 44010259SAndrew.Bardsley@arm.com } 44110259SAndrew.Bardsley@arm.com 44210259SAndrew.Bardsley@arm.com /* We go to idle even if there are more things to do on the queues as 44310259SAndrew.Bardsley@arm.com * it's the job of step to actually step us on to the next transaction */ 44410259SAndrew.Bardsley@arm.com 44510259SAndrew.Bardsley@arm.com /* Let's try and wake up the processor for the next cycle to move on 44610259SAndrew.Bardsley@arm.com * queues */ 44710259SAndrew.Bardsley@arm.com cpu.wakeupOnEvent(Pipeline::Fetch1StageId); 44810259SAndrew.Bardsley@arm.com 44910259SAndrew.Bardsley@arm.com /* Never busy */ 45010259SAndrew.Bardsley@arm.com return true; 45110259SAndrew.Bardsley@arm.com} 45210259SAndrew.Bardsley@arm.com 45310259SAndrew.Bardsley@arm.comvoid 45410713Sandreas.hansson@arm.comFetch1::recvReqRetry() 45510259SAndrew.Bardsley@arm.com{ 45610259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "recvRetry\n"); 45710259SAndrew.Bardsley@arm.com assert(icacheState == IcacheNeedsRetry); 45810259SAndrew.Bardsley@arm.com assert(!requests.empty()); 45910259SAndrew.Bardsley@arm.com 46010259SAndrew.Bardsley@arm.com FetchRequestPtr retryRequest = requests.front(); 46110259SAndrew.Bardsley@arm.com 46210259SAndrew.Bardsley@arm.com icacheState = IcacheRunning; 46310259SAndrew.Bardsley@arm.com 46410259SAndrew.Bardsley@arm.com if (tryToSend(retryRequest)) 46510259SAndrew.Bardsley@arm.com moveFromRequestsToTransfers(retryRequest); 46610259SAndrew.Bardsley@arm.com} 46710259SAndrew.Bardsley@arm.com 46810259SAndrew.Bardsley@arm.comstd::ostream & 46910259SAndrew.Bardsley@arm.comoperator <<(std::ostream &os, Fetch1::FetchState state) 47010259SAndrew.Bardsley@arm.com{ 47110259SAndrew.Bardsley@arm.com switch (state) { 47210259SAndrew.Bardsley@arm.com case Fetch1::FetchHalted: 47310259SAndrew.Bardsley@arm.com os << "FetchHalted"; 47410259SAndrew.Bardsley@arm.com break; 47510259SAndrew.Bardsley@arm.com case Fetch1::FetchWaitingForPC: 47610259SAndrew.Bardsley@arm.com os << "FetchWaitingForPC"; 47710259SAndrew.Bardsley@arm.com break; 47810259SAndrew.Bardsley@arm.com case Fetch1::FetchRunning: 47910259SAndrew.Bardsley@arm.com os << "FetchRunning"; 48010259SAndrew.Bardsley@arm.com break; 48110259SAndrew.Bardsley@arm.com default: 48210259SAndrew.Bardsley@arm.com os << "FetchState-" << static_cast<int>(state); 48310259SAndrew.Bardsley@arm.com break; 48410259SAndrew.Bardsley@arm.com } 48510259SAndrew.Bardsley@arm.com return os; 48610259SAndrew.Bardsley@arm.com} 48710259SAndrew.Bardsley@arm.com 48810259SAndrew.Bardsley@arm.comvoid 48910259SAndrew.Bardsley@arm.comFetch1::changeStream(const BranchData &branch) 49010259SAndrew.Bardsley@arm.com{ 49111567Smitch.hayenga@arm.com Fetch1ThreadInfo &thread = fetchInfo[branch.threadId]; 49211567Smitch.hayenga@arm.com 49310259SAndrew.Bardsley@arm.com updateExpectedSeqNums(branch); 49410259SAndrew.Bardsley@arm.com 49510259SAndrew.Bardsley@arm.com /* Start fetching again if we were stopped */ 49610259SAndrew.Bardsley@arm.com switch (branch.reason) { 49710259SAndrew.Bardsley@arm.com case BranchData::SuspendThread: 49811567Smitch.hayenga@arm.com { 49911567Smitch.hayenga@arm.com if (thread.wakeupGuard) { 50011567Smitch.hayenga@arm.com DPRINTF(Fetch, "Not suspending fetch due to guard: %s\n", 50111567Smitch.hayenga@arm.com branch); 50211567Smitch.hayenga@arm.com } else { 50311567Smitch.hayenga@arm.com DPRINTF(Fetch, "Suspending fetch: %s\n", branch); 50411567Smitch.hayenga@arm.com thread.state = FetchWaitingForPC; 50511567Smitch.hayenga@arm.com } 50611567Smitch.hayenga@arm.com } 50710259SAndrew.Bardsley@arm.com break; 50810259SAndrew.Bardsley@arm.com case BranchData::HaltFetch: 50910259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Halting fetch\n"); 51011567Smitch.hayenga@arm.com thread.state = FetchHalted; 51110259SAndrew.Bardsley@arm.com break; 51210259SAndrew.Bardsley@arm.com default: 51310259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Changing stream on branch: %s\n", branch); 51411567Smitch.hayenga@arm.com thread.state = FetchRunning; 51510259SAndrew.Bardsley@arm.com break; 51610259SAndrew.Bardsley@arm.com } 51711567Smitch.hayenga@arm.com thread.pc = branch.target; 51810259SAndrew.Bardsley@arm.com} 51910259SAndrew.Bardsley@arm.com 52010259SAndrew.Bardsley@arm.comvoid 52110259SAndrew.Bardsley@arm.comFetch1::updateExpectedSeqNums(const BranchData &branch) 52210259SAndrew.Bardsley@arm.com{ 52311567Smitch.hayenga@arm.com Fetch1ThreadInfo &thread = fetchInfo[branch.threadId]; 52411567Smitch.hayenga@arm.com 52510259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Updating streamSeqNum from: %d to %d," 52610259SAndrew.Bardsley@arm.com " predictionSeqNum from: %d to %d\n", 52711567Smitch.hayenga@arm.com thread.streamSeqNum, branch.newStreamSeqNum, 52811567Smitch.hayenga@arm.com thread.predictionSeqNum, branch.newPredictionSeqNum); 52910259SAndrew.Bardsley@arm.com 53010259SAndrew.Bardsley@arm.com /* Change the stream */ 53111567Smitch.hayenga@arm.com thread.streamSeqNum = branch.newStreamSeqNum; 53210259SAndrew.Bardsley@arm.com /* Update the prediction. Note that it's possible for this to 53310259SAndrew.Bardsley@arm.com * actually set the prediction to an *older* value if new 53410259SAndrew.Bardsley@arm.com * predictions have been discarded by execute */ 53511567Smitch.hayenga@arm.com thread.predictionSeqNum = branch.newPredictionSeqNum; 53610259SAndrew.Bardsley@arm.com} 53710259SAndrew.Bardsley@arm.com 53810259SAndrew.Bardsley@arm.comvoid 53910259SAndrew.Bardsley@arm.comFetch1::processResponse(Fetch1::FetchRequestPtr response, 54010259SAndrew.Bardsley@arm.com ForwardLineData &line) 54110259SAndrew.Bardsley@arm.com{ 54211567Smitch.hayenga@arm.com Fetch1ThreadInfo &thread = fetchInfo[response->id.threadId]; 54310259SAndrew.Bardsley@arm.com PacketPtr packet = response->packet; 54410259SAndrew.Bardsley@arm.com 54510259SAndrew.Bardsley@arm.com /* Pass the prefetch abort (if any) on to Fetch2 in a ForwardLineData 54610259SAndrew.Bardsley@arm.com * structure */ 54710259SAndrew.Bardsley@arm.com line.setFault(response->fault); 54810259SAndrew.Bardsley@arm.com /* Make sequence numbers valid in return */ 54910259SAndrew.Bardsley@arm.com line.id = response->id; 55010259SAndrew.Bardsley@arm.com /* Set PC to virtual address */ 55110259SAndrew.Bardsley@arm.com line.pc = response->pc; 55210259SAndrew.Bardsley@arm.com /* Set the lineBase, which is a sizeof(MachInst) aligned address <= 55310259SAndrew.Bardsley@arm.com * pc.instAddr() */ 55412749Sgiacomo.travaglini@arm.com line.lineBaseAddr = response->request->getVaddr(); 55510259SAndrew.Bardsley@arm.com 55610259SAndrew.Bardsley@arm.com if (response->fault != NoFault) { 55710259SAndrew.Bardsley@arm.com /* Stop fetching if there was a fault */ 55810259SAndrew.Bardsley@arm.com /* Should probably try to flush the queues as well, but we 55910259SAndrew.Bardsley@arm.com * can't be sure that this fault will actually reach Execute, and we 56010259SAndrew.Bardsley@arm.com * can't (currently) selectively remove this stream from the queues */ 56110259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Stopping line fetch because of fault: %s\n", 56210259SAndrew.Bardsley@arm.com response->fault->name()); 56311567Smitch.hayenga@arm.com thread.state = Fetch1::FetchWaitingForPC; 56410259SAndrew.Bardsley@arm.com } else { 56510259SAndrew.Bardsley@arm.com line.adoptPacketData(packet); 56610259SAndrew.Bardsley@arm.com /* Null the response's packet to prevent the response from trying to 56710259SAndrew.Bardsley@arm.com * deallocate the packet */ 56810259SAndrew.Bardsley@arm.com response->packet = NULL; 56910259SAndrew.Bardsley@arm.com } 57010259SAndrew.Bardsley@arm.com} 57110259SAndrew.Bardsley@arm.com 57210259SAndrew.Bardsley@arm.comvoid 57310259SAndrew.Bardsley@arm.comFetch1::evaluate() 57410259SAndrew.Bardsley@arm.com{ 57510259SAndrew.Bardsley@arm.com const BranchData &execute_branch = *inp.outputWire; 57610259SAndrew.Bardsley@arm.com const BranchData &fetch2_branch = *prediction.outputWire; 57710259SAndrew.Bardsley@arm.com ForwardLineData &line_out = *out.inputWire; 57810259SAndrew.Bardsley@arm.com 57910259SAndrew.Bardsley@arm.com assert(line_out.isBubble()); 58010259SAndrew.Bardsley@arm.com 58111567Smitch.hayenga@arm.com for (ThreadID tid = 0; tid < cpu.numThreads; tid++) 58211567Smitch.hayenga@arm.com fetchInfo[tid].blocked = !nextStageReserve[tid].canReserve(); 58310259SAndrew.Bardsley@arm.com 58411567Smitch.hayenga@arm.com /** Are both branches from later stages valid and for the same thread? */ 58511567Smitch.hayenga@arm.com if (execute_branch.threadId != InvalidThreadID && 58611567Smitch.hayenga@arm.com execute_branch.threadId == fetch2_branch.threadId) { 58711567Smitch.hayenga@arm.com 58811567Smitch.hayenga@arm.com Fetch1ThreadInfo &thread = fetchInfo[execute_branch.threadId]; 58911567Smitch.hayenga@arm.com 59011567Smitch.hayenga@arm.com /* Are we changing stream? Look to the Execute branches first, then 59111567Smitch.hayenga@arm.com * to predicted changes of stream from Fetch2 */ 59211567Smitch.hayenga@arm.com if (execute_branch.isStreamChange()) { 59311567Smitch.hayenga@arm.com if (thread.state == FetchHalted) { 59411567Smitch.hayenga@arm.com DPRINTF(Fetch, "Halted, ignoring branch: %s\n", execute_branch); 59511567Smitch.hayenga@arm.com } else { 59610259SAndrew.Bardsley@arm.com changeStream(execute_branch); 59711567Smitch.hayenga@arm.com } 59811567Smitch.hayenga@arm.com 59911567Smitch.hayenga@arm.com if (!fetch2_branch.isBubble()) { 60011567Smitch.hayenga@arm.com DPRINTF(Fetch, "Ignoring simultaneous prediction: %s\n", 60111567Smitch.hayenga@arm.com fetch2_branch); 60211567Smitch.hayenga@arm.com } 60311567Smitch.hayenga@arm.com 60411567Smitch.hayenga@arm.com /* The streamSeqNum tagging in request/response ->req should handle 60511567Smitch.hayenga@arm.com * discarding those requests when we get to them. */ 60611567Smitch.hayenga@arm.com } else if (thread.state != FetchHalted && fetch2_branch.isStreamChange()) { 60711567Smitch.hayenga@arm.com /* Handle branch predictions by changing the instruction source 60811567Smitch.hayenga@arm.com * if we're still processing the same stream (as set by streamSeqNum) 60911567Smitch.hayenga@arm.com * as the one of the prediction. 61011567Smitch.hayenga@arm.com */ 61111567Smitch.hayenga@arm.com if (fetch2_branch.newStreamSeqNum != thread.streamSeqNum) { 61211567Smitch.hayenga@arm.com DPRINTF(Fetch, "Not changing stream on prediction: %s," 61311567Smitch.hayenga@arm.com " streamSeqNum mismatch\n", 61411567Smitch.hayenga@arm.com fetch2_branch); 61510259SAndrew.Bardsley@arm.com } else { 61611567Smitch.hayenga@arm.com changeStream(fetch2_branch); 61710259SAndrew.Bardsley@arm.com } 61811567Smitch.hayenga@arm.com } 61911567Smitch.hayenga@arm.com } else { 62011567Smitch.hayenga@arm.com /* Fetch2 and Execute branches are for different threads */ 62111567Smitch.hayenga@arm.com if (execute_branch.threadId != InvalidThreadID && 62211567Smitch.hayenga@arm.com execute_branch.isStreamChange()) { 62311567Smitch.hayenga@arm.com 62411567Smitch.hayenga@arm.com if (fetchInfo[execute_branch.threadId].state == FetchHalted) { 62511567Smitch.hayenga@arm.com DPRINTF(Fetch, "Halted, ignoring branch: %s\n", execute_branch); 62611567Smitch.hayenga@arm.com } else { 62711567Smitch.hayenga@arm.com changeStream(execute_branch); 62811567Smitch.hayenga@arm.com } 62910259SAndrew.Bardsley@arm.com } 63010259SAndrew.Bardsley@arm.com 63111567Smitch.hayenga@arm.com if (fetch2_branch.threadId != InvalidThreadID && 63211567Smitch.hayenga@arm.com fetch2_branch.isStreamChange()) { 63310259SAndrew.Bardsley@arm.com 63411567Smitch.hayenga@arm.com if (fetchInfo[fetch2_branch.threadId].state == FetchHalted) { 63511567Smitch.hayenga@arm.com DPRINTF(Fetch, "Halted, ignoring branch: %s\n", fetch2_branch); 63611567Smitch.hayenga@arm.com } else if (fetch2_branch.newStreamSeqNum != fetchInfo[fetch2_branch.threadId].streamSeqNum) { 63711567Smitch.hayenga@arm.com DPRINTF(Fetch, "Not changing stream on prediction: %s," 63811567Smitch.hayenga@arm.com " streamSeqNum mismatch\n", fetch2_branch); 63911567Smitch.hayenga@arm.com } else { 64011567Smitch.hayenga@arm.com changeStream(fetch2_branch); 64111567Smitch.hayenga@arm.com } 64210259SAndrew.Bardsley@arm.com } 64310259SAndrew.Bardsley@arm.com } 64410259SAndrew.Bardsley@arm.com 64511567Smitch.hayenga@arm.com if (numInFlightFetches() < fetchLimit) { 64611567Smitch.hayenga@arm.com ThreadID fetch_tid = getScheduledThread(); 64711567Smitch.hayenga@arm.com 64811567Smitch.hayenga@arm.com if (fetch_tid != InvalidThreadID) { 64911567Smitch.hayenga@arm.com DPRINTF(Fetch, "Fetching from thread %d\n", fetch_tid); 65011567Smitch.hayenga@arm.com 65111567Smitch.hayenga@arm.com /* Generate fetch to selected thread */ 65211567Smitch.hayenga@arm.com fetchLine(fetch_tid); 65311567Smitch.hayenga@arm.com /* Take up a slot in the fetch queue */ 65411567Smitch.hayenga@arm.com nextStageReserve[fetch_tid].reserve(); 65511567Smitch.hayenga@arm.com } else { 65611567Smitch.hayenga@arm.com DPRINTF(Fetch, "No active threads available to fetch from\n"); 65711567Smitch.hayenga@arm.com } 65810259SAndrew.Bardsley@arm.com } 65910259SAndrew.Bardsley@arm.com 66011567Smitch.hayenga@arm.com 66110259SAndrew.Bardsley@arm.com /* Halting shouldn't prevent fetches in flight from being processed */ 66210259SAndrew.Bardsley@arm.com /* Step fetches through the icachePort queues and memory system */ 66310259SAndrew.Bardsley@arm.com stepQueues(); 66410259SAndrew.Bardsley@arm.com 66510259SAndrew.Bardsley@arm.com /* As we've thrown away early lines, if there is a line, it must 66610259SAndrew.Bardsley@arm.com * be from the right stream */ 66710259SAndrew.Bardsley@arm.com if (!transfers.empty() && 66810259SAndrew.Bardsley@arm.com transfers.front()->isComplete()) 66910259SAndrew.Bardsley@arm.com { 67010259SAndrew.Bardsley@arm.com Fetch1::FetchRequestPtr response = transfers.front(); 67110259SAndrew.Bardsley@arm.com 67210259SAndrew.Bardsley@arm.com if (response->isDiscardable()) { 67311567Smitch.hayenga@arm.com nextStageReserve[response->id.threadId].freeReservation(); 67410259SAndrew.Bardsley@arm.com 67511567Smitch.hayenga@arm.com DPRINTF(Fetch, "Discarding translated fetch as it's for" 67610259SAndrew.Bardsley@arm.com " an old stream\n"); 67710259SAndrew.Bardsley@arm.com 67810259SAndrew.Bardsley@arm.com /* Wake up next cycle just in case there was some other 67910259SAndrew.Bardsley@arm.com * action to do */ 68010259SAndrew.Bardsley@arm.com cpu.wakeupOnEvent(Pipeline::Fetch1StageId); 68110259SAndrew.Bardsley@arm.com } else { 68210259SAndrew.Bardsley@arm.com DPRINTF(Fetch, "Processing fetched line: %s\n", 68310259SAndrew.Bardsley@arm.com response->id); 68410259SAndrew.Bardsley@arm.com 68510259SAndrew.Bardsley@arm.com processResponse(response, line_out); 68610259SAndrew.Bardsley@arm.com } 68710259SAndrew.Bardsley@arm.com 68810259SAndrew.Bardsley@arm.com popAndDiscard(transfers); 68910259SAndrew.Bardsley@arm.com } 69010259SAndrew.Bardsley@arm.com 69110259SAndrew.Bardsley@arm.com /* If we generated output, and mark the stage as being active 69210259SAndrew.Bardsley@arm.com * to encourage that output on to the next stage */ 69310259SAndrew.Bardsley@arm.com if (!line_out.isBubble()) 69410259SAndrew.Bardsley@arm.com cpu.activityRecorder->activity(); 69510259SAndrew.Bardsley@arm.com 69610259SAndrew.Bardsley@arm.com /* Fetch1 has no inputBuffer so the only activity we can have is to 69710259SAndrew.Bardsley@arm.com * generate a line output (tested just above) or to initiate a memory 69810259SAndrew.Bardsley@arm.com * fetch which will signal activity when it returns/needs stepping 69910259SAndrew.Bardsley@arm.com * between queues */ 70011567Smitch.hayenga@arm.com 70111567Smitch.hayenga@arm.com 70211567Smitch.hayenga@arm.com /* This looks hackish. And it is, but there doesn't seem to be a better 70311567Smitch.hayenga@arm.com * way to do this. The signal from commit to suspend fetch takes 1 70411567Smitch.hayenga@arm.com * clock cycle to propagate to fetch. However, a legitimate wakeup 70511567Smitch.hayenga@arm.com * may occur between cycles from the memory system. Thus wakeup guard 70611567Smitch.hayenga@arm.com * prevents us from suspending in that case. */ 70711567Smitch.hayenga@arm.com 70811567Smitch.hayenga@arm.com for (auto& thread : fetchInfo) { 70911567Smitch.hayenga@arm.com thread.wakeupGuard = false; 71011567Smitch.hayenga@arm.com } 71111567Smitch.hayenga@arm.com} 71211567Smitch.hayenga@arm.com 71311567Smitch.hayenga@arm.comvoid 71411567Smitch.hayenga@arm.comFetch1::wakeupFetch(ThreadID tid) 71511567Smitch.hayenga@arm.com{ 71611567Smitch.hayenga@arm.com ThreadContext *thread_ctx = cpu.getContext(tid); 71711567Smitch.hayenga@arm.com Fetch1ThreadInfo &thread = fetchInfo[tid]; 71811567Smitch.hayenga@arm.com thread.pc = thread_ctx->pcState(); 71911567Smitch.hayenga@arm.com thread.state = FetchRunning; 72011567Smitch.hayenga@arm.com thread.wakeupGuard = true; 72111567Smitch.hayenga@arm.com DPRINTF(Fetch, "[tid:%d]: Changing stream wakeup %s\n", 72211567Smitch.hayenga@arm.com tid, thread_ctx->pcState()); 72311567Smitch.hayenga@arm.com 72411567Smitch.hayenga@arm.com cpu.wakeupOnEvent(Pipeline::Fetch1StageId); 72510259SAndrew.Bardsley@arm.com} 72610259SAndrew.Bardsley@arm.com 72710259SAndrew.Bardsley@arm.combool 72810259SAndrew.Bardsley@arm.comFetch1::isDrained() 72910259SAndrew.Bardsley@arm.com{ 73011567Smitch.hayenga@arm.com bool drained = numInFlightFetches() == 0 && (*out.inputWire).isBubble(); 73111567Smitch.hayenga@arm.com for (ThreadID tid = 0; tid < cpu.numThreads; tid++) { 73211567Smitch.hayenga@arm.com Fetch1ThreadInfo &thread = fetchInfo[tid]; 73311567Smitch.hayenga@arm.com DPRINTF(Drain, "isDrained[tid:%d]: %s %s%s\n", 73411567Smitch.hayenga@arm.com tid, 73511567Smitch.hayenga@arm.com thread.state == FetchHalted, 73611567Smitch.hayenga@arm.com (numInFlightFetches() == 0 ? "" : "inFlightFetches "), 73711567Smitch.hayenga@arm.com ((*out.inputWire).isBubble() ? "" : "outputtingLine")); 73810259SAndrew.Bardsley@arm.com 73911568Smitch.hayenga@arm.com drained = drained && (thread.state != FetchRunning); 74011567Smitch.hayenga@arm.com } 74111567Smitch.hayenga@arm.com 74211567Smitch.hayenga@arm.com return drained; 74310259SAndrew.Bardsley@arm.com} 74410259SAndrew.Bardsley@arm.com 74510259SAndrew.Bardsley@arm.comvoid 74610259SAndrew.Bardsley@arm.comFetch1::FetchRequest::reportData(std::ostream &os) const 74710259SAndrew.Bardsley@arm.com{ 74810259SAndrew.Bardsley@arm.com os << id; 74910259SAndrew.Bardsley@arm.com} 75010259SAndrew.Bardsley@arm.com 75110259SAndrew.Bardsley@arm.combool Fetch1::FetchRequest::isDiscardable() const 75210259SAndrew.Bardsley@arm.com{ 75311567Smitch.hayenga@arm.com Fetch1ThreadInfo &thread = fetch.fetchInfo[id.threadId]; 75411567Smitch.hayenga@arm.com 75510259SAndrew.Bardsley@arm.com /* Can't discard lines in TLB/memory */ 75610259SAndrew.Bardsley@arm.com return state != InTranslation && state != RequestIssuing && 75711567Smitch.hayenga@arm.com (id.streamSeqNum != thread.streamSeqNum || 75811567Smitch.hayenga@arm.com id.predictionSeqNum != thread.predictionSeqNum); 75910259SAndrew.Bardsley@arm.com} 76010259SAndrew.Bardsley@arm.com 76110259SAndrew.Bardsley@arm.comvoid 76210259SAndrew.Bardsley@arm.comFetch1::minorTrace() const 76310259SAndrew.Bardsley@arm.com{ 76411567Smitch.hayenga@arm.com // TODO: Un-bork minorTrace for THREADS 76511567Smitch.hayenga@arm.com // bork bork bork 76611567Smitch.hayenga@arm.com const Fetch1ThreadInfo &thread = fetchInfo[0]; 76711567Smitch.hayenga@arm.com 76810259SAndrew.Bardsley@arm.com std::ostringstream data; 76910259SAndrew.Bardsley@arm.com 77011567Smitch.hayenga@arm.com if (thread.blocked) 77110259SAndrew.Bardsley@arm.com data << 'B'; 77210259SAndrew.Bardsley@arm.com else 77310259SAndrew.Bardsley@arm.com (*out.inputWire).reportData(data); 77410259SAndrew.Bardsley@arm.com 77510259SAndrew.Bardsley@arm.com MINORTRACE("state=%s icacheState=%s in_tlb_mem=%s/%s" 77611567Smitch.hayenga@arm.com " streamSeqNum=%d lines=%s\n", thread.state, icacheState, 77710259SAndrew.Bardsley@arm.com numFetchesInITLB, numFetchesInMemorySystem, 77811567Smitch.hayenga@arm.com thread.streamSeqNum, data.str()); 77910259SAndrew.Bardsley@arm.com requests.minorTrace(); 78010259SAndrew.Bardsley@arm.com transfers.minorTrace(); 78110259SAndrew.Bardsley@arm.com} 78210259SAndrew.Bardsley@arm.com 78310259SAndrew.Bardsley@arm.com} 784