timing.cc revision 12276
1/*
2 * Copyright 2014 Google, Inc.
3 * Copyright (c) 2010-2013,2015,2017 ARM Limited
4 * All rights reserved
5 *
6 * The license below extends only to copyright in the software and shall
7 * not be construed as granting a license to any other intellectual
8 * property including but not limited to intellectual property relating
9 * to a hardware implementation of the functionality of the software
10 * licensed hereunder.  You may use the software subject to the license
11 * terms below provided that you ensure that this notice is replicated
12 * unmodified and in its entirety in all distributions of the software,
13 * modified or unmodified, in source code or in binary form.
14 *
15 * Copyright (c) 2002-2005 The Regents of The University of Michigan
16 * All rights reserved.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions are
20 * met: redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer;
22 * redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution;
25 * neither the name of the copyright holders nor the names of its
26 * contributors may be used to endorse or promote products derived from
27 * this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 * Authors: Steve Reinhardt
42 */
43
44#include "cpu/simple/timing.hh"
45
46#include "arch/locked_mem.hh"
47#include "arch/mmapped_ipr.hh"
48#include "arch/utility.hh"
49#include "base/bigint.hh"
50#include "config/the_isa.hh"
51#include "cpu/exetrace.hh"
52#include "debug/Config.hh"
53#include "debug/Drain.hh"
54#include "debug/ExecFaulting.hh"
55#include "debug/Mwait.hh"
56#include "debug/SimpleCPU.hh"
57#include "mem/packet.hh"
58#include "mem/packet_access.hh"
59#include "params/TimingSimpleCPU.hh"
60#include "sim/faults.hh"
61#include "sim/full_system.hh"
62#include "sim/system.hh"
63
64using namespace std;
65using namespace TheISA;
66
67void
68TimingSimpleCPU::init()
69{
70    BaseSimpleCPU::init();
71}
72
73void
74TimingSimpleCPU::TimingCPUPort::TickEvent::schedule(PacketPtr _pkt, Tick t)
75{
76    pkt = _pkt;
77    cpu->schedule(this, t);
78}
79
80TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p)
81    : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this),
82      dcachePort(this), ifetch_pkt(NULL), dcache_pkt(NULL), previousCycle(0),
83      fetchEvent([this]{ fetch(); }, name())
84{
85    _status = Idle;
86}
87
88
89
90TimingSimpleCPU::~TimingSimpleCPU()
91{
92}
93
94DrainState
95TimingSimpleCPU::drain()
96{
97    // Deschedule any power gating event (if any)
98    deschedulePowerGatingEvent();
99
100    if (switchedOut())
101        return DrainState::Drained;
102
103    if (_status == Idle ||
104        (_status == BaseSimpleCPU::Running && isDrained())) {
105        DPRINTF(Drain, "No need to drain.\n");
106        activeThreads.clear();
107        return DrainState::Drained;
108    } else {
109        DPRINTF(Drain, "Requesting drain.\n");
110
111        // The fetch event can become descheduled if a drain didn't
112        // succeed on the first attempt. We need to reschedule it if
113        // the CPU is waiting for a microcode routine to complete.
114        if (_status == BaseSimpleCPU::Running && !fetchEvent.scheduled())
115            schedule(fetchEvent, clockEdge());
116
117        return DrainState::Draining;
118    }
119}
120
121void
122TimingSimpleCPU::drainResume()
123{
124    assert(!fetchEvent.scheduled());
125    if (switchedOut())
126        return;
127
128    DPRINTF(SimpleCPU, "Resume\n");
129    verifyMemoryMode();
130
131    assert(!threadContexts.empty());
132
133    _status = BaseSimpleCPU::Idle;
134
135    for (ThreadID tid = 0; tid < numThreads; tid++) {
136        if (threadInfo[tid]->thread->status() == ThreadContext::Active) {
137            threadInfo[tid]->notIdleFraction = 1;
138
139            activeThreads.push_back(tid);
140
141            _status = BaseSimpleCPU::Running;
142
143            // Fetch if any threads active
144            if (!fetchEvent.scheduled()) {
145                schedule(fetchEvent, nextCycle());
146            }
147        } else {
148            threadInfo[tid]->notIdleFraction = 0;
149        }
150    }
151
152    // Reschedule any power gating event (if any)
153    schedulePowerGatingEvent();
154
155    system->totalNumInsts = 0;
156}
157
158bool
159TimingSimpleCPU::tryCompleteDrain()
160{
161    if (drainState() != DrainState::Draining)
162        return false;
163
164    DPRINTF(Drain, "tryCompleteDrain.\n");
165    if (!isDrained())
166        return false;
167
168    DPRINTF(Drain, "CPU done draining, processing drain event\n");
169    signalDrainDone();
170
171    return true;
172}
173
174void
175TimingSimpleCPU::switchOut()
176{
177    SimpleExecContext& t_info = *threadInfo[curThread];
178    M5_VAR_USED SimpleThread* thread = t_info.thread;
179
180    BaseSimpleCPU::switchOut();
181
182    assert(!fetchEvent.scheduled());
183    assert(_status == BaseSimpleCPU::Running || _status == Idle);
184    assert(!t_info.stayAtPC);
185    assert(thread->microPC() == 0);
186
187    updateCycleCounts();
188}
189
190
191void
192TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
193{
194    BaseSimpleCPU::takeOverFrom(oldCPU);
195
196    previousCycle = curCycle();
197}
198
199void
200TimingSimpleCPU::verifyMemoryMode() const
201{
202    if (!system->isTimingMode()) {
203        fatal("The timing CPU requires the memory system to be in "
204              "'timing' mode.\n");
205    }
206}
207
208void
209TimingSimpleCPU::activateContext(ThreadID thread_num)
210{
211    DPRINTF(SimpleCPU, "ActivateContext %d\n", thread_num);
212
213    assert(thread_num < numThreads);
214
215    threadInfo[thread_num]->notIdleFraction = 1;
216    if (_status == BaseSimpleCPU::Idle)
217        _status = BaseSimpleCPU::Running;
218
219    // kick things off by initiating the fetch of the next instruction
220    if (!fetchEvent.scheduled())
221        schedule(fetchEvent, clockEdge(Cycles(0)));
222
223    if (std::find(activeThreads.begin(), activeThreads.end(), thread_num)
224         == activeThreads.end()) {
225        activeThreads.push_back(thread_num);
226    }
227
228    BaseCPU::activateContext(thread_num);
229}
230
231
232void
233TimingSimpleCPU::suspendContext(ThreadID thread_num)
234{
235    DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
236
237    assert(thread_num < numThreads);
238    activeThreads.remove(thread_num);
239
240    if (_status == Idle)
241        return;
242
243    assert(_status == BaseSimpleCPU::Running);
244
245    threadInfo[thread_num]->notIdleFraction = 0;
246
247    if (activeThreads.empty()) {
248        _status = Idle;
249
250        if (fetchEvent.scheduled()) {
251            deschedule(fetchEvent);
252        }
253    }
254
255    BaseCPU::suspendContext(thread_num);
256}
257
258bool
259TimingSimpleCPU::handleReadPacket(PacketPtr pkt)
260{
261    SimpleExecContext &t_info = *threadInfo[curThread];
262    SimpleThread* thread = t_info.thread;
263
264    RequestPtr req = pkt->req;
265
266    // We're about the issues a locked load, so tell the monitor
267    // to start caring about this address
268    if (pkt->isRead() && pkt->req->isLLSC()) {
269        TheISA::handleLockedRead(thread, pkt->req);
270    }
271    if (req->isMmappedIpr()) {
272        Cycles delay = TheISA::handleIprRead(thread->getTC(), pkt);
273        new IprEvent(pkt, this, clockEdge(delay));
274        _status = DcacheWaitResponse;
275        dcache_pkt = NULL;
276    } else if (!dcachePort.sendTimingReq(pkt)) {
277        _status = DcacheRetry;
278        dcache_pkt = pkt;
279    } else {
280        _status = DcacheWaitResponse;
281        // memory system takes ownership of packet
282        dcache_pkt = NULL;
283    }
284    return dcache_pkt == NULL;
285}
286
287void
288TimingSimpleCPU::sendData(RequestPtr req, uint8_t *data, uint64_t *res,
289                          bool read)
290{
291    SimpleExecContext &t_info = *threadInfo[curThread];
292    SimpleThread* thread = t_info.thread;
293
294    PacketPtr pkt = buildPacket(req, read);
295    pkt->dataDynamic<uint8_t>(data);
296    if (req->getFlags().isSet(Request::NO_ACCESS)) {
297        assert(!dcache_pkt);
298        pkt->makeResponse();
299        completeDataAccess(pkt);
300    } else if (read) {
301        handleReadPacket(pkt);
302    } else {
303        bool do_access = true;  // flag to suppress cache access
304
305        if (req->isLLSC()) {
306            do_access = TheISA::handleLockedWrite(thread, req, dcachePort.cacheBlockMask);
307        } else if (req->isCondSwap()) {
308            assert(res);
309            req->setExtraData(*res);
310        }
311
312        if (do_access) {
313            dcache_pkt = pkt;
314            handleWritePacket();
315            threadSnoop(pkt, curThread);
316        } else {
317            _status = DcacheWaitResponse;
318            completeDataAccess(pkt);
319        }
320    }
321}
322
323void
324TimingSimpleCPU::sendSplitData(RequestPtr req1, RequestPtr req2,
325                               RequestPtr req, uint8_t *data, bool read)
326{
327    PacketPtr pkt1, pkt2;
328    buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read);
329    if (req->getFlags().isSet(Request::NO_ACCESS)) {
330        assert(!dcache_pkt);
331        pkt1->makeResponse();
332        completeDataAccess(pkt1);
333    } else if (read) {
334        SplitFragmentSenderState * send_state =
335            dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState);
336        if (handleReadPacket(pkt1)) {
337            send_state->clearFromParent();
338            send_state = dynamic_cast<SplitFragmentSenderState *>(
339                    pkt2->senderState);
340            if (handleReadPacket(pkt2)) {
341                send_state->clearFromParent();
342            }
343        }
344    } else {
345        dcache_pkt = pkt1;
346        SplitFragmentSenderState * send_state =
347            dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState);
348        if (handleWritePacket()) {
349            send_state->clearFromParent();
350            dcache_pkt = pkt2;
351            send_state = dynamic_cast<SplitFragmentSenderState *>(
352                    pkt2->senderState);
353            if (handleWritePacket()) {
354                send_state->clearFromParent();
355            }
356        }
357    }
358}
359
360void
361TimingSimpleCPU::translationFault(const Fault &fault)
362{
363    // fault may be NoFault in cases where a fault is suppressed,
364    // for instance prefetches.
365    updateCycleCounts();
366
367    if (traceData) {
368        // Since there was a fault, we shouldn't trace this instruction.
369        delete traceData;
370        traceData = NULL;
371    }
372
373    postExecute();
374
375    advanceInst(fault);
376}
377
378PacketPtr
379TimingSimpleCPU::buildPacket(RequestPtr req, bool read)
380{
381    return read ? Packet::createRead(req) : Packet::createWrite(req);
382}
383
384void
385TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2,
386        RequestPtr req1, RequestPtr req2, RequestPtr req,
387        uint8_t *data, bool read)
388{
389    pkt1 = pkt2 = NULL;
390
391    assert(!req1->isMmappedIpr() && !req2->isMmappedIpr());
392
393    if (req->getFlags().isSet(Request::NO_ACCESS)) {
394        pkt1 = buildPacket(req, read);
395        return;
396    }
397
398    pkt1 = buildPacket(req1, read);
399    pkt2 = buildPacket(req2, read);
400
401    PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand());
402
403    pkt->dataDynamic<uint8_t>(data);
404    pkt1->dataStatic<uint8_t>(data);
405    pkt2->dataStatic<uint8_t>(data + req1->getSize());
406
407    SplitMainSenderState * main_send_state = new SplitMainSenderState;
408    pkt->senderState = main_send_state;
409    main_send_state->fragments[0] = pkt1;
410    main_send_state->fragments[1] = pkt2;
411    main_send_state->outstanding = 2;
412    pkt1->senderState = new SplitFragmentSenderState(pkt, 0);
413    pkt2->senderState = new SplitFragmentSenderState(pkt, 1);
414}
415
416Fault
417TimingSimpleCPU::readMem(Addr addr, uint8_t *data,
418                         unsigned size, Request::Flags flags)
419{
420    panic("readMem() is for atomic accesses, and should "
421          "never be called on TimingSimpleCPU.\n");
422}
423
424Fault
425TimingSimpleCPU::initiateMemRead(Addr addr, unsigned size,
426                                 Request::Flags flags)
427{
428    SimpleExecContext &t_info = *threadInfo[curThread];
429    SimpleThread* thread = t_info.thread;
430
431    Fault fault;
432    const int asid = 0;
433    const Addr pc = thread->instAddr();
434    unsigned block_size = cacheLineSize();
435    BaseTLB::Mode mode = BaseTLB::Read;
436
437    if (traceData)
438        traceData->setMem(addr, size, flags);
439
440    RequestPtr req = new Request(asid, addr, size, flags, dataMasterId(), pc,
441                                 thread->contextId());
442
443    req->taskId(taskId());
444
445    Addr split_addr = roundDown(addr + size - 1, block_size);
446    assert(split_addr <= addr || split_addr - addr < block_size);
447
448    _status = DTBWaitResponse;
449    if (split_addr > addr) {
450        RequestPtr req1, req2;
451        assert(!req->isLLSC() && !req->isSwap());
452        req->splitOnVaddr(split_addr, req1, req2);
453
454        WholeTranslationState *state =
455            new WholeTranslationState(req, req1, req2, new uint8_t[size],
456                                      NULL, mode);
457        DataTranslation<TimingSimpleCPU *> *trans1 =
458            new DataTranslation<TimingSimpleCPU *>(this, state, 0);
459        DataTranslation<TimingSimpleCPU *> *trans2 =
460            new DataTranslation<TimingSimpleCPU *>(this, state, 1);
461
462        thread->dtb->translateTiming(req1, thread->getTC(), trans1, mode);
463        thread->dtb->translateTiming(req2, thread->getTC(), trans2, mode);
464    } else {
465        WholeTranslationState *state =
466            new WholeTranslationState(req, new uint8_t[size], NULL, mode);
467        DataTranslation<TimingSimpleCPU *> *translation
468            = new DataTranslation<TimingSimpleCPU *>(this, state);
469        thread->dtb->translateTiming(req, thread->getTC(), translation, mode);
470    }
471
472    return NoFault;
473}
474
475bool
476TimingSimpleCPU::handleWritePacket()
477{
478    SimpleExecContext &t_info = *threadInfo[curThread];
479    SimpleThread* thread = t_info.thread;
480
481    RequestPtr req = dcache_pkt->req;
482    if (req->isMmappedIpr()) {
483        Cycles delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt);
484        new IprEvent(dcache_pkt, this, clockEdge(delay));
485        _status = DcacheWaitResponse;
486        dcache_pkt = NULL;
487    } else if (!dcachePort.sendTimingReq(dcache_pkt)) {
488        _status = DcacheRetry;
489    } else {
490        _status = DcacheWaitResponse;
491        // memory system takes ownership of packet
492        dcache_pkt = NULL;
493    }
494    return dcache_pkt == NULL;
495}
496
497Fault
498TimingSimpleCPU::writeMem(uint8_t *data, unsigned size,
499                          Addr addr, Request::Flags flags, uint64_t *res)
500{
501    SimpleExecContext &t_info = *threadInfo[curThread];
502    SimpleThread* thread = t_info.thread;
503
504    uint8_t *newData = new uint8_t[size];
505    const int asid = 0;
506    const Addr pc = thread->instAddr();
507    unsigned block_size = cacheLineSize();
508    BaseTLB::Mode mode = BaseTLB::Write;
509
510    if (data == NULL) {
511        assert(flags & Request::CACHE_BLOCK_ZERO);
512        // This must be a cache block cleaning request
513        memset(newData, 0, size);
514    } else {
515        memcpy(newData, data, size);
516    }
517
518    if (traceData)
519        traceData->setMem(addr, size, flags);
520
521    RequestPtr req = new Request(asid, addr, size, flags, dataMasterId(), pc,
522                                 thread->contextId());
523
524    req->taskId(taskId());
525
526    Addr split_addr = roundDown(addr + size - 1, block_size);
527    assert(split_addr <= addr || split_addr - addr < block_size);
528
529    _status = DTBWaitResponse;
530    if (split_addr > addr) {
531        RequestPtr req1, req2;
532        assert(!req->isLLSC() && !req->isSwap());
533        req->splitOnVaddr(split_addr, req1, req2);
534
535        WholeTranslationState *state =
536            new WholeTranslationState(req, req1, req2, newData, res, mode);
537        DataTranslation<TimingSimpleCPU *> *trans1 =
538            new DataTranslation<TimingSimpleCPU *>(this, state, 0);
539        DataTranslation<TimingSimpleCPU *> *trans2 =
540            new DataTranslation<TimingSimpleCPU *>(this, state, 1);
541
542        thread->dtb->translateTiming(req1, thread->getTC(), trans1, mode);
543        thread->dtb->translateTiming(req2, thread->getTC(), trans2, mode);
544    } else {
545        WholeTranslationState *state =
546            new WholeTranslationState(req, newData, res, mode);
547        DataTranslation<TimingSimpleCPU *> *translation =
548            new DataTranslation<TimingSimpleCPU *>(this, state);
549        thread->dtb->translateTiming(req, thread->getTC(), translation, mode);
550    }
551
552    // Translation faults will be returned via finishTranslation()
553    return NoFault;
554}
555
556void
557TimingSimpleCPU::threadSnoop(PacketPtr pkt, ThreadID sender)
558{
559    for (ThreadID tid = 0; tid < numThreads; tid++) {
560        if (tid != sender) {
561            if (getCpuAddrMonitor(tid)->doMonitor(pkt)) {
562                wakeup(tid);
563            }
564            TheISA::handleLockedSnoop(threadInfo[tid]->thread, pkt,
565                    dcachePort.cacheBlockMask);
566        }
567    }
568}
569
570void
571TimingSimpleCPU::finishTranslation(WholeTranslationState *state)
572{
573    _status = BaseSimpleCPU::Running;
574
575    if (state->getFault() != NoFault) {
576        if (state->isPrefetch()) {
577            state->setNoFault();
578        }
579        delete [] state->data;
580        state->deleteReqs();
581        translationFault(state->getFault());
582    } else {
583        if (!state->isSplit) {
584            sendData(state->mainReq, state->data, state->res,
585                     state->mode == BaseTLB::Read);
586        } else {
587            sendSplitData(state->sreqLow, state->sreqHigh, state->mainReq,
588                          state->data, state->mode == BaseTLB::Read);
589        }
590    }
591
592    delete state;
593}
594
595
596void
597TimingSimpleCPU::fetch()
598{
599    // Change thread if multi-threaded
600    swapActiveThread();
601
602    SimpleExecContext &t_info = *threadInfo[curThread];
603    SimpleThread* thread = t_info.thread;
604
605    DPRINTF(SimpleCPU, "Fetch\n");
606
607    if (!curStaticInst || !curStaticInst->isDelayedCommit()) {
608        checkForInterrupts();
609        checkPcEventQueue();
610    }
611
612    // We must have just got suspended by a PC event
613    if (_status == Idle)
614        return;
615
616    TheISA::PCState pcState = thread->pcState();
617    bool needToFetch = !isRomMicroPC(pcState.microPC()) &&
618                       !curMacroStaticInst;
619
620    if (needToFetch) {
621        _status = BaseSimpleCPU::Running;
622        Request *ifetch_req = new Request();
623        ifetch_req->taskId(taskId());
624        ifetch_req->setContext(thread->contextId());
625        setupFetchRequest(ifetch_req);
626        DPRINTF(SimpleCPU, "Translating address %#x\n", ifetch_req->getVaddr());
627        thread->itb->translateTiming(ifetch_req, thread->getTC(),
628                &fetchTranslation, BaseTLB::Execute);
629    } else {
630        _status = IcacheWaitResponse;
631        completeIfetch(NULL);
632
633        updateCycleCounts();
634    }
635}
636
637
638void
639TimingSimpleCPU::sendFetch(const Fault &fault, RequestPtr req,
640                           ThreadContext *tc)
641{
642    if (fault == NoFault) {
643        DPRINTF(SimpleCPU, "Sending fetch for addr %#x(pa: %#x)\n",
644                req->getVaddr(), req->getPaddr());
645        ifetch_pkt = new Packet(req, MemCmd::ReadReq);
646        ifetch_pkt->dataStatic(&inst);
647        DPRINTF(SimpleCPU, " -- pkt addr: %#x\n", ifetch_pkt->getAddr());
648
649        if (!icachePort.sendTimingReq(ifetch_pkt)) {
650            // Need to wait for retry
651            _status = IcacheRetry;
652        } else {
653            // Need to wait for cache to respond
654            _status = IcacheWaitResponse;
655            // ownership of packet transferred to memory system
656            ifetch_pkt = NULL;
657        }
658    } else {
659        DPRINTF(SimpleCPU, "Translation of addr %#x faulted\n", req->getVaddr());
660        delete req;
661        // fetch fault: advance directly to next instruction (fault handler)
662        _status = BaseSimpleCPU::Running;
663        advanceInst(fault);
664    }
665
666    updateCycleCounts();
667}
668
669
670void
671TimingSimpleCPU::advanceInst(const Fault &fault)
672{
673    SimpleExecContext &t_info = *threadInfo[curThread];
674
675    if (_status == Faulting)
676        return;
677
678    if (fault != NoFault) {
679        DPRINTF(SimpleCPU, "Fault occured, scheduling fetch event\n");
680
681        advancePC(fault);
682
683        Tick stall = dynamic_pointer_cast<SyscallRetryFault>(fault) ?
684                     clockEdge(syscallRetryLatency) : clockEdge();
685
686        reschedule(fetchEvent, stall, true);
687
688        _status = Faulting;
689        return;
690    }
691
692
693    if (!t_info.stayAtPC)
694        advancePC(fault);
695
696    if (tryCompleteDrain())
697            return;
698
699    if (_status == BaseSimpleCPU::Running) {
700        // kick off fetch of next instruction... callback from icache
701        // response will cause that instruction to be executed,
702        // keeping the CPU running.
703        fetch();
704    }
705}
706
707
708void
709TimingSimpleCPU::completeIfetch(PacketPtr pkt)
710{
711    SimpleExecContext& t_info = *threadInfo[curThread];
712
713    DPRINTF(SimpleCPU, "Complete ICache Fetch for addr %#x\n", pkt ?
714            pkt->getAddr() : 0);
715
716    // received a response from the icache: execute the received
717    // instruction
718    assert(!pkt || !pkt->isError());
719    assert(_status == IcacheWaitResponse);
720
721    _status = BaseSimpleCPU::Running;
722
723    updateCycleCounts();
724
725    if (pkt)
726        pkt->req->setAccessLatency();
727
728
729    preExecute();
730    if (curStaticInst && curStaticInst->isMemRef()) {
731        // load or store: just send to dcache
732        Fault fault = curStaticInst->initiateAcc(&t_info, traceData);
733
734        // If we're not running now the instruction will complete in a dcache
735        // response callback or the instruction faulted and has started an
736        // ifetch
737        if (_status == BaseSimpleCPU::Running) {
738            if (fault != NoFault && traceData) {
739                // If there was a fault, we shouldn't trace this instruction.
740                delete traceData;
741                traceData = NULL;
742            }
743
744            postExecute();
745            // @todo remove me after debugging with legion done
746            if (curStaticInst && (!curStaticInst->isMicroop() ||
747                        curStaticInst->isFirstMicroop()))
748                instCnt++;
749            advanceInst(fault);
750        }
751    } else if (curStaticInst) {
752        // non-memory instruction: execute completely now
753        Fault fault = curStaticInst->execute(&t_info, traceData);
754
755        // keep an instruction count
756        if (fault == NoFault)
757            countInst();
758        else if (traceData && !DTRACE(ExecFaulting)) {
759            delete traceData;
760            traceData = NULL;
761        }
762
763        postExecute();
764        // @todo remove me after debugging with legion done
765        if (curStaticInst && (!curStaticInst->isMicroop() ||
766                curStaticInst->isFirstMicroop()))
767            instCnt++;
768        advanceInst(fault);
769    } else {
770        advanceInst(NoFault);
771    }
772
773    if (pkt) {
774        delete pkt->req;
775        delete pkt;
776    }
777}
778
779void
780TimingSimpleCPU::IcachePort::ITickEvent::process()
781{
782    cpu->completeIfetch(pkt);
783}
784
785bool
786TimingSimpleCPU::IcachePort::recvTimingResp(PacketPtr pkt)
787{
788    DPRINTF(SimpleCPU, "Received fetch response %#x\n", pkt->getAddr());
789    // we should only ever see one response per cycle since we only
790    // issue a new request once this response is sunk
791    assert(!tickEvent.scheduled());
792    // delay processing of returned data until next CPU clock edge
793    tickEvent.schedule(pkt, cpu->clockEdge());
794
795    return true;
796}
797
798void
799TimingSimpleCPU::IcachePort::recvReqRetry()
800{
801    // we shouldn't get a retry unless we have a packet that we're
802    // waiting to transmit
803    assert(cpu->ifetch_pkt != NULL);
804    assert(cpu->_status == IcacheRetry);
805    PacketPtr tmp = cpu->ifetch_pkt;
806    if (sendTimingReq(tmp)) {
807        cpu->_status = IcacheWaitResponse;
808        cpu->ifetch_pkt = NULL;
809    }
810}
811
812void
813TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
814{
815    // received a response from the dcache: complete the load or store
816    // instruction
817    assert(!pkt->isError());
818    assert(_status == DcacheWaitResponse || _status == DTBWaitResponse ||
819           pkt->req->getFlags().isSet(Request::NO_ACCESS));
820
821    pkt->req->setAccessLatency();
822
823    updateCycleCounts();
824
825    if (pkt->senderState) {
826        SplitFragmentSenderState * send_state =
827            dynamic_cast<SplitFragmentSenderState *>(pkt->senderState);
828        assert(send_state);
829        delete pkt->req;
830        delete pkt;
831        PacketPtr big_pkt = send_state->bigPkt;
832        delete send_state;
833
834        SplitMainSenderState * main_send_state =
835            dynamic_cast<SplitMainSenderState *>(big_pkt->senderState);
836        assert(main_send_state);
837        // Record the fact that this packet is no longer outstanding.
838        assert(main_send_state->outstanding != 0);
839        main_send_state->outstanding--;
840
841        if (main_send_state->outstanding) {
842            return;
843        } else {
844            delete main_send_state;
845            big_pkt->senderState = NULL;
846            pkt = big_pkt;
847        }
848    }
849
850    _status = BaseSimpleCPU::Running;
851
852    Fault fault = curStaticInst->completeAcc(pkt, threadInfo[curThread],
853                                             traceData);
854
855    // keep an instruction count
856    if (fault == NoFault)
857        countInst();
858    else if (traceData) {
859        // If there was a fault, we shouldn't trace this instruction.
860        delete traceData;
861        traceData = NULL;
862    }
863
864    delete pkt->req;
865    delete pkt;
866
867    postExecute();
868
869    advanceInst(fault);
870}
871
872void
873TimingSimpleCPU::updateCycleCounts()
874{
875    const Cycles delta(curCycle() - previousCycle);
876
877    numCycles += delta;
878    ppCycles->notify(delta);
879
880    previousCycle = curCycle();
881}
882
883void
884TimingSimpleCPU::DcachePort::recvTimingSnoopReq(PacketPtr pkt)
885{
886    for (ThreadID tid = 0; tid < cpu->numThreads; tid++) {
887        if (cpu->getCpuAddrMonitor(tid)->doMonitor(pkt)) {
888            cpu->wakeup(tid);
889        }
890    }
891
892    // Making it uniform across all CPUs:
893    // The CPUs need to be woken up only on an invalidation packet (when using caches)
894    // or on an incoming write packet (when not using caches)
895    // It is not necessary to wake up the processor on all incoming packets
896    if (pkt->isInvalidate() || pkt->isWrite()) {
897        for (auto &t_info : cpu->threadInfo) {
898            TheISA::handleLockedSnoop(t_info->thread, pkt, cacheBlockMask);
899        }
900    }
901}
902
903void
904TimingSimpleCPU::DcachePort::recvFunctionalSnoop(PacketPtr pkt)
905{
906    for (ThreadID tid = 0; tid < cpu->numThreads; tid++) {
907        if (cpu->getCpuAddrMonitor(tid)->doMonitor(pkt)) {
908            cpu->wakeup(tid);
909        }
910    }
911}
912
913bool
914TimingSimpleCPU::DcachePort::recvTimingResp(PacketPtr pkt)
915{
916    DPRINTF(SimpleCPU, "Received load/store response %#x\n", pkt->getAddr());
917
918    // The timing CPU is not really ticked, instead it relies on the
919    // memory system (fetch and load/store) to set the pace.
920    if (!tickEvent.scheduled()) {
921        // Delay processing of returned data until next CPU clock edge
922        tickEvent.schedule(pkt, cpu->clockEdge());
923        return true;
924    } else {
925        // In the case of a split transaction and a cache that is
926        // faster than a CPU we could get two responses in the
927        // same tick, delay the second one
928        if (!retryRespEvent.scheduled())
929            cpu->schedule(retryRespEvent, cpu->clockEdge(Cycles(1)));
930        return false;
931    }
932}
933
934void
935TimingSimpleCPU::DcachePort::DTickEvent::process()
936{
937    cpu->completeDataAccess(pkt);
938}
939
940void
941TimingSimpleCPU::DcachePort::recvReqRetry()
942{
943    // we shouldn't get a retry unless we have a packet that we're
944    // waiting to transmit
945    assert(cpu->dcache_pkt != NULL);
946    assert(cpu->_status == DcacheRetry);
947    PacketPtr tmp = cpu->dcache_pkt;
948    if (tmp->senderState) {
949        // This is a packet from a split access.
950        SplitFragmentSenderState * send_state =
951            dynamic_cast<SplitFragmentSenderState *>(tmp->senderState);
952        assert(send_state);
953        PacketPtr big_pkt = send_state->bigPkt;
954
955        SplitMainSenderState * main_send_state =
956            dynamic_cast<SplitMainSenderState *>(big_pkt->senderState);
957        assert(main_send_state);
958
959        if (sendTimingReq(tmp)) {
960            // If we were able to send without retrying, record that fact
961            // and try sending the other fragment.
962            send_state->clearFromParent();
963            int other_index = main_send_state->getPendingFragment();
964            if (other_index > 0) {
965                tmp = main_send_state->fragments[other_index];
966                cpu->dcache_pkt = tmp;
967                if ((big_pkt->isRead() && cpu->handleReadPacket(tmp)) ||
968                        (big_pkt->isWrite() && cpu->handleWritePacket())) {
969                    main_send_state->fragments[other_index] = NULL;
970                }
971            } else {
972                cpu->_status = DcacheWaitResponse;
973                // memory system takes ownership of packet
974                cpu->dcache_pkt = NULL;
975            }
976        }
977    } else if (sendTimingReq(tmp)) {
978        cpu->_status = DcacheWaitResponse;
979        // memory system takes ownership of packet
980        cpu->dcache_pkt = NULL;
981    }
982}
983
984TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu,
985    Tick t)
986    : pkt(_pkt), cpu(_cpu)
987{
988    cpu->schedule(this, t);
989}
990
991void
992TimingSimpleCPU::IprEvent::process()
993{
994    cpu->completeDataAccess(pkt);
995}
996
997const char *
998TimingSimpleCPU::IprEvent::description() const
999{
1000    return "Timing Simple CPU Delay IPR event";
1001}
1002
1003
1004void
1005TimingSimpleCPU::printAddr(Addr a)
1006{
1007    dcachePort.printAddr(a);
1008}
1009
1010
1011////////////////////////////////////////////////////////////////////////
1012//
1013//  TimingSimpleCPU Simulation Object
1014//
1015TimingSimpleCPU *
1016TimingSimpleCPUParams::create()
1017{
1018    return new TimingSimpleCPU(this);
1019}
1020