1/*
2 * Copyright (c) 2013-2014 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Andrew Bardsley
38 */
39
40#include "cpu/minor/fetch1.hh"
41
42#include <cstring>
43#include <iomanip>
44#include <sstream>
45
46#include "base/cast.hh"
47#include "cpu/minor/pipeline.hh"
48#include "debug/Drain.hh"
49#include "debug/Fetch.hh"
50#include "debug/MinorTrace.hh"
51
52namespace Minor
53{
54
55Fetch1::Fetch1(const std::string &name_,
56    MinorCPU &cpu_,
57    MinorCPUParams &params,
58    Latch<BranchData>::Output inp_,
59    Latch<ForwardLineData>::Input out_,
60    Latch<BranchData>::Output prediction_,
61    std::vector<InputBuffer<ForwardLineData>> &next_stage_input_buffer) :
62    Named(name_),
63    cpu(cpu_),
64    inp(inp_),
65    out(out_),
66    prediction(prediction_),
67    nextStageReserve(next_stage_input_buffer),
68    icachePort(name_ + ".icache_port", *this, cpu_),
69    lineSnap(params.fetch1LineSnapWidth),
70    maxLineWidth(params.fetch1LineWidth),
71    fetchLimit(params.fetch1FetchLimit),
72    fetchInfo(params.numThreads),
73    threadPriority(0),
74    requests(name_ + ".requests", "lines", params.fetch1FetchLimit),
75    transfers(name_ + ".transfers", "lines", params.fetch1FetchLimit),
76    icacheState(IcacheRunning),
77    lineSeqNum(InstId::firstLineSeqNum),
78    numFetchesInMemorySystem(0),
79    numFetchesInITLB(0)
80{
81    if (lineSnap == 0) {
82        lineSnap = cpu.cacheLineSize();
83        DPRINTF(Fetch, "lineSnap set to cache line size of: %d\n",
84            lineSnap);
85    }
86
87    if (maxLineWidth == 0) {
88        maxLineWidth = cpu.cacheLineSize();
89        DPRINTF(Fetch, "maxLineWidth set to cache line size of: %d\n",
90            maxLineWidth);
91    }
92
93    /* These assertions should be copied to the Python config. as well */
94    if ((lineSnap % sizeof(TheISA::MachInst)) != 0) {
95        fatal("%s: fetch1LineSnapWidth must be a multiple "
96            "of sizeof(TheISA::MachInst) (%d)\n", name_,
97            sizeof(TheISA::MachInst));
98    }
99
100    if (!(maxLineWidth >= lineSnap &&
101        (maxLineWidth % sizeof(TheISA::MachInst)) == 0))
102    {
103        fatal("%s: fetch1LineWidth must be a multiple of"
104            " sizeof(TheISA::MachInst)"
105            " (%d), and >= fetch1LineSnapWidth (%d)\n",
106            name_, sizeof(TheISA::MachInst), lineSnap);
107    }
108
109    if (fetchLimit < 1) {
110        fatal("%s: fetch1FetchLimit must be >= 1 (%d)\n", name_,
111            fetchLimit);
112    }
113}
114
115inline ThreadID
116Fetch1::getScheduledThread()
117{
118    /* Select thread via policy. */
119    std::vector<ThreadID> priority_list;
120
121    switch (cpu.threadPolicy) {
122      case Enums::SingleThreaded:
123        priority_list.push_back(0);
124        break;
125      case Enums::RoundRobin:
126        priority_list = cpu.roundRobinPriority(threadPriority);
127        break;
128      case Enums::Random:
129        priority_list = cpu.randomPriority();
130        break;
131      default:
132        panic("Unknown fetch policy");
133    }
134
135    for (auto tid : priority_list) {
136        if (cpu.getContext(tid)->status() == ThreadContext::Active &&
137            !fetchInfo[tid].blocked &&
138            fetchInfo[tid].state == FetchRunning) {
139            threadPriority = tid;
140            return tid;
141        }
142    }
143
144   return InvalidThreadID;
145}
146
147void
148Fetch1::fetchLine(ThreadID tid)
149{
150    /* Reference the currently used thread state. */
151    Fetch1ThreadInfo &thread = fetchInfo[tid];
152
153    /* If line_offset != 0, a request is pushed for the remainder of the
154     * line. */
155    /* Use a lower, sizeof(MachInst) aligned address for the fetch */
156    Addr aligned_pc = thread.pc.instAddr() & ~((Addr) lineSnap - 1);
157    unsigned int line_offset = aligned_pc % lineSnap;
158    unsigned int request_size = maxLineWidth - line_offset;
159
160    /* Fill in the line's id */
161    InstId request_id(tid,
162        thread.streamSeqNum, thread.predictionSeqNum,
163        lineSeqNum);
164
165    FetchRequestPtr request = new FetchRequest(*this, request_id, thread.pc);
166
167    DPRINTF(Fetch, "Inserting fetch into the fetch queue "
168        "%s addr: 0x%x pc: %s line_offset: %d request_size: %d\n",
169        request_id, aligned_pc, thread.pc, line_offset, request_size);
170
171    request->request->setContext(cpu.threads[tid]->getTC()->contextId());
172    request->request->setVirt(0 /* asid */,
173        aligned_pc, request_size, Request::INST_FETCH, cpu.instMasterId(),
174        /* I've no idea why we need the PC, but give it */
175        thread.pc.instAddr());
176
177    DPRINTF(Fetch, "Submitting ITLB request\n");
178    numFetchesInITLB++;
179
180    request->state = FetchRequest::InTranslation;
181
182    /* Reserve space in the queues upstream of requests for results */
183    transfers.reserve();
184    requests.push(request);
185
186    /* Submit the translation request.  The response will come
187     *  through finish/markDelayed on this request as it bears
188     *  the Translation interface */
189    cpu.threads[request->id.threadId]->itb->translateTiming(
190        request->request,
191        cpu.getContext(request->id.threadId),
192        request, BaseTLB::Execute);
193
194    lineSeqNum++;
195
196    /* Step the PC for the next line onto the line aligned next address.
197     * Note that as instructions can span lines, this PC is only a
198     * reliable 'new' PC if the next line has a new stream sequence number. */
199#if THE_ISA == ALPHA_ISA
200    /* Restore the low bits of the PC used as address space flags */
201    Addr pc_low_bits = thread.pc.instAddr() &
202        ((Addr) (1 << sizeof(TheISA::MachInst)) - 1);
203
204    thread.pc.set(aligned_pc + request_size + pc_low_bits);
205#else
206    thread.pc.set(aligned_pc + request_size);
207#endif
208}
209
210std::ostream &
211operator <<(std::ostream &os, Fetch1::IcacheState state)
212{
213    switch (state) {
214      case Fetch1::IcacheRunning:
215        os << "IcacheRunning";
216        break;
217      case Fetch1::IcacheNeedsRetry:
218        os << "IcacheNeedsRetry";
219        break;
220      default:
221        os << "IcacheState-" << static_cast<int>(state);
222        break;
223    }
224    return os;
225}
226
227void
228Fetch1::FetchRequest::makePacket()
229{
230    /* Make the necessary packet for a memory transaction */
231    packet = new Packet(request, MemCmd::ReadReq);
232    packet->allocate();
233
234    /* This FetchRequest becomes SenderState to allow the response to be
235     *  identified */
236    packet->pushSenderState(this);
237}
238
239void
240Fetch1::FetchRequest::finish(const Fault &fault_, const RequestPtr &request_,
241                             ThreadContext *tc, BaseTLB::Mode mode)
242{
243    fault = fault_;
244
245    state = Translated;
246    fetch.handleTLBResponse(this);
247
248    /* Let's try and wake up the processor for the next cycle */
249    fetch.cpu.wakeupOnEvent(Pipeline::Fetch1StageId);
250}
251
252void
253Fetch1::handleTLBResponse(FetchRequestPtr response)
254{
255    numFetchesInITLB--;
256
257    if (response->fault != NoFault) {
258        DPRINTF(Fetch, "Fault in address ITLB translation: %s, "
259            "paddr: 0x%x, vaddr: 0x%x\n",
260            response->fault->name(),
261            (response->request->hasPaddr() ?
262                response->request->getPaddr() : 0),
263            response->request->getVaddr());
264
265        if (DTRACE(MinorTrace))
266            minorTraceResponseLine(name(), response);
267    } else {
268        DPRINTF(Fetch, "Got ITLB response\n");
269    }
270
271    response->state = FetchRequest::Translated;
272
273    tryToSendToTransfers(response);
274}
275
276Fetch1::FetchRequest::~FetchRequest()
277{
278    if (packet)
279        delete packet;
280}
281
282void
283Fetch1::tryToSendToTransfers(FetchRequestPtr request)
284{
285    if (!requests.empty() && requests.front() != request) {
286        DPRINTF(Fetch, "Fetch not at front of requests queue, can't"
287            " issue to memory\n");
288        return;
289    }
290
291    if (request->state == FetchRequest::InTranslation) {
292        DPRINTF(Fetch, "Fetch still in translation, not issuing to"
293            " memory\n");
294        return;
295    }
296
297    if (request->isDiscardable() || request->fault != NoFault) {
298        /* Discarded and faulting requests carry on through transfers
299         *  as Complete/packet == NULL */
300
301        request->state = FetchRequest::Complete;
302        moveFromRequestsToTransfers(request);
303
304        /* Wake up the pipeline next cycle as there will be no event
305         *  for this queue->queue transfer */
306        cpu.wakeupOnEvent(Pipeline::Fetch1StageId);
307    } else if (request->state == FetchRequest::Translated) {
308        if (!request->packet)
309            request->makePacket();
310
311        /* Ensure that the packet won't delete the request */
312        assert(request->packet->needsResponse());
313
314        if (tryToSend(request))
315            moveFromRequestsToTransfers(request);
316    } else {
317        DPRINTF(Fetch, "Not advancing line fetch\n");
318    }
319}
320
321void
322Fetch1::moveFromRequestsToTransfers(FetchRequestPtr request)
323{
324    assert(!requests.empty() && requests.front() == request);
325
326    requests.pop();
327    transfers.push(request);
328}
329
330bool
331Fetch1::tryToSend(FetchRequestPtr request)
332{
333    bool ret = false;
334
335    if (icachePort.sendTimingReq(request->packet)) {
336        /* Invalidate the fetch_requests packet so we don't
337         *  accidentally fail to deallocate it (or use it!)
338         *  later by overwriting it */
339        request->packet = NULL;
340        request->state = FetchRequest::RequestIssuing;
341        numFetchesInMemorySystem++;
342
343        ret = true;
344
345        DPRINTF(Fetch, "Issued fetch request to memory: %s\n",
346            request->id);
347    } else {
348        /* Needs to be resent, wait for that */
349        icacheState = IcacheNeedsRetry;
350
351        DPRINTF(Fetch, "Line fetch needs to retry: %s\n",
352            request->id);
353    }
354
355    return ret;
356}
357
358void
359Fetch1::stepQueues()
360{
361    IcacheState old_icache_state = icacheState;
362
363    switch (icacheState) {
364      case IcacheRunning:
365        /* Move ITLB results on to the memory system */
366        if (!requests.empty()) {
367            tryToSendToTransfers(requests.front());
368        }
369        break;
370      case IcacheNeedsRetry:
371        break;
372    }
373
374    if (icacheState != old_icache_state) {
375        DPRINTF(Fetch, "Step in state %s moving to state %s\n",
376            old_icache_state, icacheState);
377    }
378}
379
380void
381Fetch1::popAndDiscard(FetchQueue &queue)
382{
383    if (!queue.empty()) {
384        delete queue.front();
385        queue.pop();
386    }
387}
388
389unsigned int
390Fetch1::numInFlightFetches()
391{
392    return requests.occupiedSpace() +
393        transfers.occupiedSpace();
394}
395
396/** Print the appropriate MinorLine line for a fetch response */
397void
398Fetch1::minorTraceResponseLine(const std::string &name,
399    Fetch1::FetchRequestPtr response) const
400{
401    const RequestPtr &request M5_VAR_USED = response->request;
402
403    if (response->packet && response->packet->isError()) {
404        MINORLINE(this, "id=F;%s vaddr=0x%x fault=\"error packet\"\n",
405            response->id, request->getVaddr());
406    } else if (response->fault != NoFault) {
407        MINORLINE(this, "id=F;%s vaddr=0x%x fault=\"%s\"\n",
408            response->id, request->getVaddr(), response->fault->name());
409    } else {
410        MINORLINE(this, "id=%s size=%d vaddr=0x%x paddr=0x%x\n",
411            response->id, request->getSize(),
412            request->getVaddr(), request->getPaddr());
413    }
414}
415
416bool
417Fetch1::recvTimingResp(PacketPtr response)
418{
419    DPRINTF(Fetch, "recvTimingResp %d\n", numFetchesInMemorySystem);
420
421    /* Only push the response if we didn't change stream?  No,  all responses
422     *  should hit the responses queue.  It's the job of 'step' to throw them
423     *  away. */
424    FetchRequestPtr fetch_request = safe_cast<FetchRequestPtr>
425        (response->popSenderState());
426
427    /* Fixup packet in fetch_request as this may have changed */
428    assert(!fetch_request->packet);
429    fetch_request->packet = response;
430
431    numFetchesInMemorySystem--;
432    fetch_request->state = FetchRequest::Complete;
433
434    if (DTRACE(MinorTrace))
435        minorTraceResponseLine(name(), fetch_request);
436
437    if (response->isError()) {
438        DPRINTF(Fetch, "Received error response packet: %s\n",
439            fetch_request->id);
440    }
441
442    /* We go to idle even if there are more things to do on the queues as
443     *  it's the job of step to actually step us on to the next transaction */
444
445    /* Let's try and wake up the processor for the next cycle to move on
446     *  queues */
447    cpu.wakeupOnEvent(Pipeline::Fetch1StageId);
448
449    /* Never busy */
450    return true;
451}
452
453void
454Fetch1::recvReqRetry()
455{
456    DPRINTF(Fetch, "recvRetry\n");
457    assert(icacheState == IcacheNeedsRetry);
458    assert(!requests.empty());
459
460    FetchRequestPtr retryRequest = requests.front();
461
462    icacheState = IcacheRunning;
463
464    if (tryToSend(retryRequest))
465        moveFromRequestsToTransfers(retryRequest);
466}
467
468std::ostream &
469operator <<(std::ostream &os, Fetch1::FetchState state)
470{
471    switch (state) {
472      case Fetch1::FetchHalted:
473        os << "FetchHalted";
474        break;
475      case Fetch1::FetchWaitingForPC:
476        os << "FetchWaitingForPC";
477        break;
478      case Fetch1::FetchRunning:
479        os << "FetchRunning";
480        break;
481      default:
482        os << "FetchState-" << static_cast<int>(state);
483        break;
484    }
485    return os;
486}
487
488void
489Fetch1::changeStream(const BranchData &branch)
490{
491    Fetch1ThreadInfo &thread = fetchInfo[branch.threadId];
492
493    updateExpectedSeqNums(branch);
494
495    /* Start fetching again if we were stopped */
496    switch (branch.reason) {
497      case BranchData::SuspendThread:
498        {
499            if (thread.wakeupGuard) {
500                DPRINTF(Fetch, "Not suspending fetch due to guard: %s\n",
501                                branch);
502            } else {
503                DPRINTF(Fetch, "Suspending fetch: %s\n", branch);
504                thread.state = FetchWaitingForPC;
505            }
506        }
507        break;
508      case BranchData::HaltFetch:
509        DPRINTF(Fetch, "Halting fetch\n");
510        thread.state = FetchHalted;
511        break;
512      default:
513        DPRINTF(Fetch, "Changing stream on branch: %s\n", branch);
514        thread.state = FetchRunning;
515        break;
516    }
517    thread.pc = branch.target;
518}
519
520void
521Fetch1::updateExpectedSeqNums(const BranchData &branch)
522{
523    Fetch1ThreadInfo &thread = fetchInfo[branch.threadId];
524
525    DPRINTF(Fetch, "Updating streamSeqNum from: %d to %d,"
526        " predictionSeqNum from: %d to %d\n",
527        thread.streamSeqNum, branch.newStreamSeqNum,
528        thread.predictionSeqNum, branch.newPredictionSeqNum);
529
530    /* Change the stream */
531    thread.streamSeqNum = branch.newStreamSeqNum;
532    /* Update the prediction.  Note that it's possible for this to
533     *  actually set the prediction to an *older* value if new
534     *  predictions have been discarded by execute */
535    thread.predictionSeqNum = branch.newPredictionSeqNum;
536}
537
538void
539Fetch1::processResponse(Fetch1::FetchRequestPtr response,
540    ForwardLineData &line)
541{
542    Fetch1ThreadInfo &thread = fetchInfo[response->id.threadId];
543    PacketPtr packet = response->packet;
544
545    /* Pass the prefetch abort (if any) on to Fetch2 in a ForwardLineData
546     * structure */
547    line.setFault(response->fault);
548    /* Make sequence numbers valid in return */
549    line.id = response->id;
550    /* Set PC to virtual address */
551    line.pc = response->pc;
552    /* Set the lineBase, which is a sizeof(MachInst) aligned address <=
553     *  pc.instAddr() */
554    line.lineBaseAddr = response->request->getVaddr();
555
556    if (response->fault != NoFault) {
557        /* Stop fetching if there was a fault */
558        /* Should probably try to flush the queues as well, but we
559         * can't be sure that this fault will actually reach Execute, and we
560         * can't (currently) selectively remove this stream from the queues */
561        DPRINTF(Fetch, "Stopping line fetch because of fault: %s\n",
562            response->fault->name());
563        thread.state = Fetch1::FetchWaitingForPC;
564    } else {
565        line.adoptPacketData(packet);
566        /* Null the response's packet to prevent the response from trying to
567         *  deallocate the packet */
568        response->packet = NULL;
569    }
570}
571
572void
573Fetch1::evaluate()
574{
575    const BranchData &execute_branch = *inp.outputWire;
576    const BranchData &fetch2_branch = *prediction.outputWire;
577    ForwardLineData &line_out = *out.inputWire;
578
579    assert(line_out.isBubble());
580
581    for (ThreadID tid = 0; tid < cpu.numThreads; tid++)
582        fetchInfo[tid].blocked = !nextStageReserve[tid].canReserve();
583
584    /** Are both branches from later stages valid and for the same thread? */
585    if (execute_branch.threadId != InvalidThreadID &&
586        execute_branch.threadId == fetch2_branch.threadId) {
587
588        Fetch1ThreadInfo &thread = fetchInfo[execute_branch.threadId];
589
590        /* Are we changing stream?  Look to the Execute branches first, then
591         * to predicted changes of stream from Fetch2 */
592        if (execute_branch.isStreamChange()) {
593            if (thread.state == FetchHalted) {
594                DPRINTF(Fetch, "Halted, ignoring branch: %s\n", execute_branch);
595            } else {
596                changeStream(execute_branch);
597            }
598
599            if (!fetch2_branch.isBubble()) {
600                DPRINTF(Fetch, "Ignoring simultaneous prediction: %s\n",
601                    fetch2_branch);
602            }
603
604            /* The streamSeqNum tagging in request/response ->req should handle
605             *  discarding those requests when we get to them. */
606        } else if (thread.state != FetchHalted && fetch2_branch.isStreamChange()) {
607            /* Handle branch predictions by changing the instruction source
608             * if we're still processing the same stream (as set by streamSeqNum)
609             * as the one of the prediction.
610             */
611            if (fetch2_branch.newStreamSeqNum != thread.streamSeqNum) {
612                DPRINTF(Fetch, "Not changing stream on prediction: %s,"
613                    " streamSeqNum mismatch\n",
614                    fetch2_branch);
615            } else {
616                changeStream(fetch2_branch);
617            }
618        }
619    } else {
620        /* Fetch2 and Execute branches are for different threads */
621        if (execute_branch.threadId != InvalidThreadID &&
622            execute_branch.isStreamChange()) {
623
624            if (fetchInfo[execute_branch.threadId].state == FetchHalted) {
625                DPRINTF(Fetch, "Halted, ignoring branch: %s\n", execute_branch);
626            } else {
627                changeStream(execute_branch);
628            }
629        }
630
631        if (fetch2_branch.threadId != InvalidThreadID &&
632            fetch2_branch.isStreamChange()) {
633
634            if (fetchInfo[fetch2_branch.threadId].state == FetchHalted) {
635                DPRINTF(Fetch, "Halted, ignoring branch: %s\n", fetch2_branch);
636            } else if (fetch2_branch.newStreamSeqNum != fetchInfo[fetch2_branch.threadId].streamSeqNum) {
637                DPRINTF(Fetch, "Not changing stream on prediction: %s,"
638                    " streamSeqNum mismatch\n", fetch2_branch);
639            } else {
640                changeStream(fetch2_branch);
641            }
642        }
643    }
644
645    if (numInFlightFetches() < fetchLimit) {
646        ThreadID fetch_tid = getScheduledThread();
647
648        if (fetch_tid != InvalidThreadID) {
649            DPRINTF(Fetch, "Fetching from thread %d\n", fetch_tid);
650
651            /* Generate fetch to selected thread */
652            fetchLine(fetch_tid);
653            /* Take up a slot in the fetch queue */
654            nextStageReserve[fetch_tid].reserve();
655        } else {
656            DPRINTF(Fetch, "No active threads available to fetch from\n");
657        }
658    }
659
660
661    /* Halting shouldn't prevent fetches in flight from being processed */
662    /* Step fetches through the icachePort queues and memory system */
663    stepQueues();
664
665    /* As we've thrown away early lines, if there is a line, it must
666     *  be from the right stream */
667    if (!transfers.empty() &&
668        transfers.front()->isComplete())
669    {
670        Fetch1::FetchRequestPtr response = transfers.front();
671
672        if (response->isDiscardable()) {
673            nextStageReserve[response->id.threadId].freeReservation();
674
675            DPRINTF(Fetch, "Discarding translated fetch as it's for"
676                " an old stream\n");
677
678            /* Wake up next cycle just in case there was some other
679             *  action to do */
680            cpu.wakeupOnEvent(Pipeline::Fetch1StageId);
681        } else {
682            DPRINTF(Fetch, "Processing fetched line: %s\n",
683                response->id);
684
685            processResponse(response, line_out);
686        }
687
688        popAndDiscard(transfers);
689    }
690
691    /* If we generated output, and mark the stage as being active
692     *  to encourage that output on to the next stage */
693    if (!line_out.isBubble())
694        cpu.activityRecorder->activity();
695
696    /* Fetch1 has no inputBuffer so the only activity we can have is to
697     *  generate a line output (tested just above) or to initiate a memory
698     *  fetch which will signal activity when it returns/needs stepping
699     *  between queues */
700
701
702    /* This looks hackish.  And it is, but there doesn't seem to be a better
703     * way to do this.  The signal from commit to suspend fetch takes 1
704     * clock cycle to propagate to fetch.  However, a legitimate wakeup
705     * may occur between cycles from the memory system.  Thus wakeup guard
706     * prevents us from suspending in that case. */
707
708    for (auto& thread : fetchInfo) {
709        thread.wakeupGuard = false;
710    }
711}
712
713void
714Fetch1::wakeupFetch(ThreadID tid)
715{
716    ThreadContext *thread_ctx = cpu.getContext(tid);
717    Fetch1ThreadInfo &thread = fetchInfo[tid];
718    thread.pc = thread_ctx->pcState();
719    thread.state = FetchRunning;
720    thread.wakeupGuard = true;
721    DPRINTF(Fetch, "[tid:%d]: Changing stream wakeup %s\n",
722            tid, thread_ctx->pcState());
723
724    cpu.wakeupOnEvent(Pipeline::Fetch1StageId);
725}
726
727bool
728Fetch1::isDrained()
729{
730    bool drained = numInFlightFetches() == 0 && (*out.inputWire).isBubble();
731    for (ThreadID tid = 0; tid < cpu.numThreads; tid++) {
732        Fetch1ThreadInfo &thread = fetchInfo[tid];
733        DPRINTF(Drain, "isDrained[tid:%d]: %s %s%s\n",
734                tid,
735                thread.state == FetchHalted,
736                (numInFlightFetches() == 0 ? "" : "inFlightFetches "),
737                ((*out.inputWire).isBubble() ? "" : "outputtingLine"));
738
739        drained = drained && (thread.state != FetchRunning);
740    }
741
742    return drained;
743}
744
745void
746Fetch1::FetchRequest::reportData(std::ostream &os) const
747{
748    os << id;
749}
750
751bool Fetch1::FetchRequest::isDiscardable() const
752{
753    Fetch1ThreadInfo &thread = fetch.fetchInfo[id.threadId];
754
755    /* Can't discard lines in TLB/memory */
756    return state != InTranslation && state != RequestIssuing &&
757        (id.streamSeqNum != thread.streamSeqNum ||
758        id.predictionSeqNum != thread.predictionSeqNum);
759}
760
761void
762Fetch1::minorTrace() const
763{
764    // TODO: Un-bork minorTrace for THREADS
765    // bork bork bork
766    const Fetch1ThreadInfo &thread = fetchInfo[0];
767
768    std::ostringstream data;
769
770    if (thread.blocked)
771        data << 'B';
772    else
773        (*out.inputWire).reportData(data);
774
775    MINORTRACE("state=%s icacheState=%s in_tlb_mem=%s/%s"
776        " streamSeqNum=%d lines=%s\n", thread.state, icacheState,
777        numFetchesInITLB, numFetchesInMemorySystem,
778        thread.streamSeqNum, data.str());
779    requests.minorTrace();
780    transfers.minorTrace();
781}
782
783}
784