timing.cc revision 7720:65d338a8dba4
1/*
2 * Copyright (c) 2002-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Steve Reinhardt
29 */
30
31#include "arch/locked_mem.hh"
32#include "arch/mmaped_ipr.hh"
33#include "arch/utility.hh"
34#include "base/bigint.hh"
35#include "config/the_isa.hh"
36#include "cpu/exetrace.hh"
37#include "cpu/simple/timing.hh"
38#include "mem/packet.hh"
39#include "mem/packet_access.hh"
40#include "params/TimingSimpleCPU.hh"
41#include "sim/faults.hh"
42#include "sim/system.hh"
43
44using namespace std;
45using namespace TheISA;
46
47Port *
48TimingSimpleCPU::getPort(const std::string &if_name, int idx)
49{
50    if (if_name == "dcache_port")
51        return &dcachePort;
52    else if (if_name == "icache_port")
53        return &icachePort;
54    else
55        panic("No Such Port\n");
56}
57
58void
59TimingSimpleCPU::init()
60{
61    BaseCPU::init();
62#if FULL_SYSTEM
63    for (int i = 0; i < threadContexts.size(); ++i) {
64        ThreadContext *tc = threadContexts[i];
65
66        // initialize CPU, including PC
67        TheISA::initCPU(tc, _cpuId);
68    }
69#endif
70}
71
72Tick
73TimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
74{
75    panic("TimingSimpleCPU doesn't expect recvAtomic callback!");
76    return curTick;
77}
78
79void
80TimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
81{
82    //No internal storage to update, jusst return
83    return;
84}
85
86void
87TimingSimpleCPU::CpuPort::recvStatusChange(Status status)
88{
89    if (status == RangeChange) {
90        if (!snoopRangeSent) {
91            snoopRangeSent = true;
92            sendStatusChange(Port::RangeChange);
93        }
94        return;
95    }
96
97    panic("TimingSimpleCPU doesn't expect recvStatusChange callback!");
98}
99
100
101void
102TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t)
103{
104    pkt = _pkt;
105    cpu->schedule(this, t);
106}
107
108TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p)
109    : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this, p->clock),
110    dcachePort(this, p->clock), fetchEvent(this)
111{
112    _status = Idle;
113
114    icachePort.snoopRangeSent = false;
115    dcachePort.snoopRangeSent = false;
116
117    ifetch_pkt = dcache_pkt = NULL;
118    drainEvent = NULL;
119    previousTick = 0;
120    changeState(SimObject::Running);
121}
122
123
124TimingSimpleCPU::~TimingSimpleCPU()
125{
126}
127
128void
129TimingSimpleCPU::serialize(ostream &os)
130{
131    SimObject::State so_state = SimObject::getState();
132    SERIALIZE_ENUM(so_state);
133    BaseSimpleCPU::serialize(os);
134}
135
136void
137TimingSimpleCPU::unserialize(Checkpoint *cp, const string &section)
138{
139    SimObject::State so_state;
140    UNSERIALIZE_ENUM(so_state);
141    BaseSimpleCPU::unserialize(cp, section);
142}
143
144unsigned int
145TimingSimpleCPU::drain(Event *drain_event)
146{
147    // TimingSimpleCPU is ready to drain if it's not waiting for
148    // an access to complete.
149    if (_status == Idle || _status == Running || _status == SwitchedOut) {
150        changeState(SimObject::Drained);
151        return 0;
152    } else {
153        changeState(SimObject::Draining);
154        drainEvent = drain_event;
155        return 1;
156    }
157}
158
159void
160TimingSimpleCPU::resume()
161{
162    DPRINTF(SimpleCPU, "Resume\n");
163    if (_status != SwitchedOut && _status != Idle) {
164        assert(system->getMemoryMode() == Enums::timing);
165
166        if (fetchEvent.scheduled())
167           deschedule(fetchEvent);
168
169        schedule(fetchEvent, nextCycle());
170    }
171
172    changeState(SimObject::Running);
173}
174
175void
176TimingSimpleCPU::switchOut()
177{
178    assert(_status == Running || _status == Idle);
179    _status = SwitchedOut;
180    numCycles += tickToCycles(curTick - previousTick);
181
182    // If we've been scheduled to resume but are then told to switch out,
183    // we'll need to cancel it.
184    if (fetchEvent.scheduled())
185        deschedule(fetchEvent);
186}
187
188
189void
190TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
191{
192    BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
193
194    // if any of this CPU's ThreadContexts are active, mark the CPU as
195    // running and schedule its tick event.
196    for (int i = 0; i < threadContexts.size(); ++i) {
197        ThreadContext *tc = threadContexts[i];
198        if (tc->status() == ThreadContext::Active && _status != Running) {
199            _status = Running;
200            break;
201        }
202    }
203
204    if (_status != Running) {
205        _status = Idle;
206    }
207    assert(threadContexts.size() == 1);
208    previousTick = curTick;
209}
210
211
212void
213TimingSimpleCPU::activateContext(int thread_num, int delay)
214{
215    DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay);
216
217    assert(thread_num == 0);
218    assert(thread);
219
220    assert(_status == Idle);
221
222    notIdleFraction++;
223    _status = Running;
224
225    // kick things off by initiating the fetch of the next instruction
226    schedule(fetchEvent, nextCycle(curTick + ticks(delay)));
227}
228
229
230void
231TimingSimpleCPU::suspendContext(int thread_num)
232{
233    DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
234
235    assert(thread_num == 0);
236    assert(thread);
237
238    if (_status == Idle)
239        return;
240
241    assert(_status == Running);
242
243    // just change status to Idle... if status != Running,
244    // completeInst() will not initiate fetch of next instruction.
245
246    notIdleFraction--;
247    _status = Idle;
248}
249
250bool
251TimingSimpleCPU::handleReadPacket(PacketPtr pkt)
252{
253    RequestPtr req = pkt->req;
254    if (req->isMmapedIpr()) {
255        Tick delay;
256        delay = TheISA::handleIprRead(thread->getTC(), pkt);
257        new IprEvent(pkt, this, nextCycle(curTick + delay));
258        _status = DcacheWaitResponse;
259        dcache_pkt = NULL;
260    } else if (!dcachePort.sendTiming(pkt)) {
261        _status = DcacheRetry;
262        dcache_pkt = pkt;
263    } else {
264        _status = DcacheWaitResponse;
265        // memory system takes ownership of packet
266        dcache_pkt = NULL;
267    }
268    return dcache_pkt == NULL;
269}
270
271void
272TimingSimpleCPU::sendData(RequestPtr req, uint8_t *data, uint64_t *res,
273                          bool read)
274{
275    PacketPtr pkt;
276    buildPacket(pkt, req, read);
277    pkt->dataDynamicArray<uint8_t>(data);
278    if (req->getFlags().isSet(Request::NO_ACCESS)) {
279        assert(!dcache_pkt);
280        pkt->makeResponse();
281        completeDataAccess(pkt);
282    } else if (read) {
283        handleReadPacket(pkt);
284    } else {
285        bool do_access = true;  // flag to suppress cache access
286
287        if (req->isLLSC()) {
288            do_access = TheISA::handleLockedWrite(thread, req);
289        } else if (req->isCondSwap()) {
290            assert(res);
291            req->setExtraData(*res);
292        }
293
294        if (do_access) {
295            dcache_pkt = pkt;
296            handleWritePacket();
297        } else {
298            _status = DcacheWaitResponse;
299            completeDataAccess(pkt);
300        }
301    }
302}
303
304void
305TimingSimpleCPU::sendSplitData(RequestPtr req1, RequestPtr req2,
306                               RequestPtr req, uint8_t *data, bool read)
307{
308    PacketPtr pkt1, pkt2;
309    buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read);
310    if (req->getFlags().isSet(Request::NO_ACCESS)) {
311        assert(!dcache_pkt);
312        pkt1->makeResponse();
313        completeDataAccess(pkt1);
314    } else if (read) {
315        if (handleReadPacket(pkt1)) {
316            SplitFragmentSenderState * send_state =
317                dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState);
318            send_state->clearFromParent();
319            if (handleReadPacket(pkt2)) {
320                send_state = dynamic_cast<SplitFragmentSenderState *>(
321                        pkt1->senderState);
322                send_state->clearFromParent();
323            }
324        }
325    } else {
326        dcache_pkt = pkt1;
327        if (handleWritePacket()) {
328            SplitFragmentSenderState * send_state =
329                dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState);
330            send_state->clearFromParent();
331            dcache_pkt = pkt2;
332            if (handleWritePacket()) {
333                send_state = dynamic_cast<SplitFragmentSenderState *>(
334                        pkt1->senderState);
335                send_state->clearFromParent();
336            }
337        }
338    }
339}
340
341void
342TimingSimpleCPU::translationFault(Fault fault)
343{
344    // fault may be NoFault in cases where a fault is suppressed,
345    // for instance prefetches.
346    numCycles += tickToCycles(curTick - previousTick);
347    previousTick = curTick;
348
349    if (traceData) {
350        // Since there was a fault, we shouldn't trace this instruction.
351        delete traceData;
352        traceData = NULL;
353    }
354
355    postExecute();
356
357    if (getState() == SimObject::Draining) {
358        advancePC(fault);
359        completeDrain();
360    } else {
361        advanceInst(fault);
362    }
363}
364
365void
366TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr req, bool read)
367{
368    MemCmd cmd;
369    if (read) {
370        cmd = MemCmd::ReadReq;
371        if (req->isLLSC())
372            cmd = MemCmd::LoadLockedReq;
373    } else {
374        cmd = MemCmd::WriteReq;
375        if (req->isLLSC()) {
376            cmd = MemCmd::StoreCondReq;
377        } else if (req->isSwap()) {
378            cmd = MemCmd::SwapReq;
379        }
380    }
381    pkt = new Packet(req, cmd, Packet::Broadcast);
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->isMmapedIpr() && !req2->isMmapedIpr());
392
393    if (req->getFlags().isSet(Request::NO_ACCESS)) {
394        buildPacket(pkt1, req, read);
395        return;
396    }
397
398    buildPacket(pkt1, req1, read);
399    buildPacket(pkt2, req2, read);
400
401    req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags());
402    PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(),
403                               Packet::Broadcast);
404
405    pkt->dataDynamicArray<uint8_t>(data);
406    pkt1->dataStatic<uint8_t>(data);
407    pkt2->dataStatic<uint8_t>(data + req1->getSize());
408
409    SplitMainSenderState * main_send_state = new SplitMainSenderState;
410    pkt->senderState = main_send_state;
411    main_send_state->fragments[0] = pkt1;
412    main_send_state->fragments[1] = pkt2;
413    main_send_state->outstanding = 2;
414    pkt1->senderState = new SplitFragmentSenderState(pkt, 0);
415    pkt2->senderState = new SplitFragmentSenderState(pkt, 1);
416}
417
418Fault
419TimingSimpleCPU::readBytes(Addr addr, uint8_t *data,
420                           unsigned size, unsigned flags)
421{
422    Fault fault;
423    const int asid = 0;
424    const ThreadID tid = 0;
425    const Addr pc = thread->instAddr();
426    unsigned block_size = dcachePort.peerBlockSize();
427    BaseTLB::Mode mode = BaseTLB::Read;
428
429    if (traceData) {
430        traceData->setAddr(addr);
431    }
432
433    RequestPtr req  = new Request(asid, addr, size,
434                                  flags, pc, _cpuId, tid);
435
436    Addr split_addr = roundDown(addr + size - 1, block_size);
437    assert(split_addr <= addr || split_addr - addr < block_size);
438
439    _status = DTBWaitResponse;
440    if (split_addr > addr) {
441        RequestPtr req1, req2;
442        assert(!req->isLLSC() && !req->isSwap());
443        req->splitOnVaddr(split_addr, req1, req2);
444
445        WholeTranslationState *state =
446            new WholeTranslationState(req, req1, req2, new uint8_t[size],
447                                      NULL, mode);
448        DataTranslation<TimingSimpleCPU> *trans1 =
449            new DataTranslation<TimingSimpleCPU>(this, state, 0);
450        DataTranslation<TimingSimpleCPU> *trans2 =
451            new DataTranslation<TimingSimpleCPU>(this, state, 1);
452
453        thread->dtb->translateTiming(req1, tc, trans1, mode);
454        thread->dtb->translateTiming(req2, tc, trans2, mode);
455    } else {
456        WholeTranslationState *state =
457            new WholeTranslationState(req, new uint8_t[size], NULL, mode);
458        DataTranslation<TimingSimpleCPU> *translation
459            = new DataTranslation<TimingSimpleCPU>(this, state);
460        thread->dtb->translateTiming(req, tc, translation, mode);
461    }
462
463    return NoFault;
464}
465
466template <class T>
467Fault
468TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
469{
470    return readBytes(addr, (uint8_t *)&data, sizeof(T), flags);
471}
472
473#ifndef DOXYGEN_SHOULD_SKIP_THIS
474
475template
476Fault
477TimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags);
478
479template
480Fault
481TimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags);
482
483template
484Fault
485TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
486
487template
488Fault
489TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
490
491template
492Fault
493TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
494
495template
496Fault
497TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
498
499#endif //DOXYGEN_SHOULD_SKIP_THIS
500
501template<>
502Fault
503TimingSimpleCPU::read(Addr addr, double &data, unsigned flags)
504{
505    return read(addr, *(uint64_t*)&data, flags);
506}
507
508template<>
509Fault
510TimingSimpleCPU::read(Addr addr, float &data, unsigned flags)
511{
512    return read(addr, *(uint32_t*)&data, flags);
513}
514
515template<>
516Fault
517TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
518{
519    return read(addr, (uint32_t&)data, flags);
520}
521
522bool
523TimingSimpleCPU::handleWritePacket()
524{
525    RequestPtr req = dcache_pkt->req;
526    if (req->isMmapedIpr()) {
527        Tick delay;
528        delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt);
529        new IprEvent(dcache_pkt, this, nextCycle(curTick + delay));
530        _status = DcacheWaitResponse;
531        dcache_pkt = NULL;
532    } else if (!dcachePort.sendTiming(dcache_pkt)) {
533        _status = DcacheRetry;
534    } else {
535        _status = DcacheWaitResponse;
536        // memory system takes ownership of packet
537        dcache_pkt = NULL;
538    }
539    return dcache_pkt == NULL;
540}
541
542Fault
543TimingSimpleCPU::writeTheseBytes(uint8_t *data, unsigned size,
544                                 Addr addr, unsigned flags, uint64_t *res)
545{
546    const int asid = 0;
547    const ThreadID tid = 0;
548    const Addr pc = thread->instAddr();
549    unsigned block_size = dcachePort.peerBlockSize();
550    BaseTLB::Mode mode = BaseTLB::Write;
551
552    if (traceData) {
553        traceData->setAddr(addr);
554    }
555
556    RequestPtr req = new Request(asid, addr, size,
557                                 flags, pc, _cpuId, tid);
558
559    Addr split_addr = roundDown(addr + size - 1, block_size);
560    assert(split_addr <= addr || split_addr - addr < block_size);
561
562    _status = DTBWaitResponse;
563    if (split_addr > addr) {
564        RequestPtr req1, req2;
565        assert(!req->isLLSC() && !req->isSwap());
566        req->splitOnVaddr(split_addr, req1, req2);
567
568        WholeTranslationState *state =
569            new WholeTranslationState(req, req1, req2, data, res, mode);
570        DataTranslation<TimingSimpleCPU> *trans1 =
571            new DataTranslation<TimingSimpleCPU>(this, state, 0);
572        DataTranslation<TimingSimpleCPU> *trans2 =
573            new DataTranslation<TimingSimpleCPU>(this, state, 1);
574
575        thread->dtb->translateTiming(req1, tc, trans1, mode);
576        thread->dtb->translateTiming(req2, tc, trans2, mode);
577    } else {
578        WholeTranslationState *state =
579            new WholeTranslationState(req, data, res, mode);
580        DataTranslation<TimingSimpleCPU> *translation =
581            new DataTranslation<TimingSimpleCPU>(this, state);
582        thread->dtb->translateTiming(req, tc, translation, mode);
583    }
584
585    // Translation faults will be returned via finishTranslation()
586    return NoFault;
587}
588
589Fault
590TimingSimpleCPU::writeBytes(uint8_t *data, unsigned size,
591                            Addr addr, unsigned flags, uint64_t *res)
592{
593    uint8_t *newData = new uint8_t[size];
594    memcpy(newData, data, size);
595    return writeTheseBytes(newData, size, addr, flags, res);
596}
597
598template <class T>
599Fault
600TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
601{
602    if (traceData) {
603        traceData->setData(data);
604    }
605    T *dataP = (T*) new uint8_t[sizeof(T)];
606    *dataP = TheISA::htog(data);
607
608    return writeTheseBytes((uint8_t *)dataP, sizeof(T), addr, flags, res);
609}
610
611
612#ifndef DOXYGEN_SHOULD_SKIP_THIS
613template
614Fault
615TimingSimpleCPU::write(Twin32_t data, Addr addr,
616                       unsigned flags, uint64_t *res);
617
618template
619Fault
620TimingSimpleCPU::write(Twin64_t data, Addr addr,
621                       unsigned flags, uint64_t *res);
622
623template
624Fault
625TimingSimpleCPU::write(uint64_t data, Addr addr,
626                       unsigned flags, uint64_t *res);
627
628template
629Fault
630TimingSimpleCPU::write(uint32_t data, Addr addr,
631                       unsigned flags, uint64_t *res);
632
633template
634Fault
635TimingSimpleCPU::write(uint16_t data, Addr addr,
636                       unsigned flags, uint64_t *res);
637
638template
639Fault
640TimingSimpleCPU::write(uint8_t data, Addr addr,
641                       unsigned flags, uint64_t *res);
642
643#endif //DOXYGEN_SHOULD_SKIP_THIS
644
645template<>
646Fault
647TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
648{
649    return write(*(uint64_t*)&data, addr, flags, res);
650}
651
652template<>
653Fault
654TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
655{
656    return write(*(uint32_t*)&data, addr, flags, res);
657}
658
659
660template<>
661Fault
662TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
663{
664    return write((uint32_t)data, addr, flags, res);
665}
666
667
668void
669TimingSimpleCPU::finishTranslation(WholeTranslationState *state)
670{
671    _status = Running;
672
673    if (state->getFault() != NoFault) {
674        if (state->isPrefetch()) {
675            state->setNoFault();
676        }
677        delete [] state->data;
678        state->deleteReqs();
679        translationFault(state->getFault());
680    } else {
681        if (!state->isSplit) {
682            sendData(state->mainReq, state->data, state->res,
683                     state->mode == BaseTLB::Read);
684        } else {
685            sendSplitData(state->sreqLow, state->sreqHigh, state->mainReq,
686                          state->data, state->mode == BaseTLB::Read);
687        }
688    }
689
690    delete state;
691}
692
693
694void
695TimingSimpleCPU::fetch()
696{
697    DPRINTF(SimpleCPU, "Fetch\n");
698
699    if (!curStaticInst || !curStaticInst->isDelayedCommit())
700        checkForInterrupts();
701
702    checkPcEventQueue();
703
704    TheISA::PCState pcState = thread->pcState();
705    bool needToFetch = !isRomMicroPC(pcState.microPC()) && !curMacroStaticInst;
706
707    if (needToFetch) {
708        Request *ifetch_req = new Request();
709        ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0);
710        setupFetchRequest(ifetch_req);
711        thread->itb->translateTiming(ifetch_req, tc, &fetchTranslation,
712                BaseTLB::Execute);
713    } else {
714        _status = IcacheWaitResponse;
715        completeIfetch(NULL);
716
717        numCycles += tickToCycles(curTick - previousTick);
718        previousTick = curTick;
719    }
720}
721
722
723void
724TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc)
725{
726    if (fault == NoFault) {
727        ifetch_pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast);
728        ifetch_pkt->dataStatic(&inst);
729
730        if (!icachePort.sendTiming(ifetch_pkt)) {
731            // Need to wait for retry
732            _status = IcacheRetry;
733        } else {
734            // Need to wait for cache to respond
735            _status = IcacheWaitResponse;
736            // ownership of packet transferred to memory system
737            ifetch_pkt = NULL;
738        }
739    } else {
740        delete req;
741        // fetch fault: advance directly to next instruction (fault handler)
742        advanceInst(fault);
743    }
744
745    numCycles += tickToCycles(curTick - previousTick);
746    previousTick = curTick;
747}
748
749
750void
751TimingSimpleCPU::advanceInst(Fault fault)
752{
753    if (fault != NoFault || !stayAtPC)
754        advancePC(fault);
755
756    if (_status == Running) {
757        // kick off fetch of next instruction... callback from icache
758        // response will cause that instruction to be executed,
759        // keeping the CPU running.
760        fetch();
761    }
762}
763
764
765void
766TimingSimpleCPU::completeIfetch(PacketPtr pkt)
767{
768    DPRINTF(SimpleCPU, "Complete ICache Fetch\n");
769
770    // received a response from the icache: execute the received
771    // instruction
772
773    assert(!pkt || !pkt->isError());
774    assert(_status == IcacheWaitResponse);
775
776    _status = Running;
777
778    numCycles += tickToCycles(curTick - previousTick);
779    previousTick = curTick;
780
781    if (getState() == SimObject::Draining) {
782        if (pkt) {
783            delete pkt->req;
784            delete pkt;
785        }
786
787        completeDrain();
788        return;
789    }
790
791    preExecute();
792    if (curStaticInst &&
793            curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) {
794        // load or store: just send to dcache
795        Fault fault = curStaticInst->initiateAcc(this, traceData);
796        if (_status != Running) {
797            // instruction will complete in dcache response callback
798            assert(_status == DcacheWaitResponse ||
799                    _status == DcacheRetry || DTBWaitResponse);
800            assert(fault == NoFault);
801        } else {
802            if (fault != NoFault && traceData) {
803                // If there was a fault, we shouldn't trace this instruction.
804                delete traceData;
805                traceData = NULL;
806            }
807
808            postExecute();
809            // @todo remove me after debugging with legion done
810            if (curStaticInst && (!curStaticInst->isMicroop() ||
811                        curStaticInst->isFirstMicroop()))
812                instCnt++;
813            advanceInst(fault);
814        }
815    } else if (curStaticInst) {
816        // non-memory instruction: execute completely now
817        Fault fault = curStaticInst->execute(this, traceData);
818
819        // keep an instruction count
820        if (fault == NoFault)
821            countInst();
822        else if (traceData && !DTRACE(ExecFaulting)) {
823            delete traceData;
824            traceData = NULL;
825        }
826
827        postExecute();
828        // @todo remove me after debugging with legion done
829        if (curStaticInst && (!curStaticInst->isMicroop() ||
830                    curStaticInst->isFirstMicroop()))
831            instCnt++;
832        advanceInst(fault);
833    } else {
834        advanceInst(NoFault);
835    }
836
837    if (pkt) {
838        delete pkt->req;
839        delete pkt;
840    }
841}
842
843void
844TimingSimpleCPU::IcachePort::ITickEvent::process()
845{
846    cpu->completeIfetch(pkt);
847}
848
849bool
850TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt)
851{
852    if (pkt->isResponse() && !pkt->wasNacked()) {
853        // delay processing of returned data until next CPU clock edge
854        Tick next_tick = cpu->nextCycle(curTick);
855
856        if (next_tick == curTick)
857            cpu->completeIfetch(pkt);
858        else
859            tickEvent.schedule(pkt, next_tick);
860
861        return true;
862    }
863    else if (pkt->wasNacked()) {
864        assert(cpu->_status == IcacheWaitResponse);
865        pkt->reinitNacked();
866        if (!sendTiming(pkt)) {
867            cpu->_status = IcacheRetry;
868            cpu->ifetch_pkt = pkt;
869        }
870    }
871    //Snooping a Coherence Request, do nothing
872    return true;
873}
874
875void
876TimingSimpleCPU::IcachePort::recvRetry()
877{
878    // we shouldn't get a retry unless we have a packet that we're
879    // waiting to transmit
880    assert(cpu->ifetch_pkt != NULL);
881    assert(cpu->_status == IcacheRetry);
882    PacketPtr tmp = cpu->ifetch_pkt;
883    if (sendTiming(tmp)) {
884        cpu->_status = IcacheWaitResponse;
885        cpu->ifetch_pkt = NULL;
886    }
887}
888
889void
890TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
891{
892    // received a response from the dcache: complete the load or store
893    // instruction
894    assert(!pkt->isError());
895    assert(_status == DcacheWaitResponse || _status == DTBWaitResponse ||
896           pkt->req->getFlags().isSet(Request::NO_ACCESS));
897
898    numCycles += tickToCycles(curTick - previousTick);
899    previousTick = curTick;
900
901    if (pkt->senderState) {
902        SplitFragmentSenderState * send_state =
903            dynamic_cast<SplitFragmentSenderState *>(pkt->senderState);
904        assert(send_state);
905        delete pkt->req;
906        delete pkt;
907        PacketPtr big_pkt = send_state->bigPkt;
908        delete send_state;
909
910        SplitMainSenderState * main_send_state =
911            dynamic_cast<SplitMainSenderState *>(big_pkt->senderState);
912        assert(main_send_state);
913        // Record the fact that this packet is no longer outstanding.
914        assert(main_send_state->outstanding != 0);
915        main_send_state->outstanding--;
916
917        if (main_send_state->outstanding) {
918            return;
919        } else {
920            delete main_send_state;
921            big_pkt->senderState = NULL;
922            pkt = big_pkt;
923        }
924    }
925
926    _status = Running;
927
928    Fault fault = curStaticInst->completeAcc(pkt, this, traceData);
929
930    // keep an instruction count
931    if (fault == NoFault)
932        countInst();
933    else if (traceData) {
934        // If there was a fault, we shouldn't trace this instruction.
935        delete traceData;
936        traceData = NULL;
937    }
938
939    // the locked flag may be cleared on the response packet, so check
940    // pkt->req and not pkt to see if it was a load-locked
941    if (pkt->isRead() && pkt->req->isLLSC()) {
942        TheISA::handleLockedRead(thread, pkt->req);
943    }
944
945    delete pkt->req;
946    delete pkt;
947
948    postExecute();
949
950    if (getState() == SimObject::Draining) {
951        advancePC(fault);
952        completeDrain();
953
954        return;
955    }
956
957    advanceInst(fault);
958}
959
960
961void
962TimingSimpleCPU::completeDrain()
963{
964    DPRINTF(Config, "Done draining\n");
965    changeState(SimObject::Drained);
966    drainEvent->process();
967}
968
969void
970TimingSimpleCPU::DcachePort::setPeer(Port *port)
971{
972    Port::setPeer(port);
973
974#if FULL_SYSTEM
975    // Update the ThreadContext's memory ports (Functional/Virtual
976    // Ports)
977    cpu->tcBase()->connectMemPorts(cpu->tcBase());
978#endif
979}
980
981bool
982TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
983{
984    if (pkt->isResponse() && !pkt->wasNacked()) {
985        // delay processing of returned data until next CPU clock edge
986        Tick next_tick = cpu->nextCycle(curTick);
987
988        if (next_tick == curTick) {
989            cpu->completeDataAccess(pkt);
990        } else {
991            tickEvent.schedule(pkt, next_tick);
992        }
993
994        return true;
995    }
996    else if (pkt->wasNacked()) {
997        assert(cpu->_status == DcacheWaitResponse);
998        pkt->reinitNacked();
999        if (!sendTiming(pkt)) {
1000            cpu->_status = DcacheRetry;
1001            cpu->dcache_pkt = pkt;
1002        }
1003    }
1004    //Snooping a Coherence Request, do nothing
1005    return true;
1006}
1007
1008void
1009TimingSimpleCPU::DcachePort::DTickEvent::process()
1010{
1011    cpu->completeDataAccess(pkt);
1012}
1013
1014void
1015TimingSimpleCPU::DcachePort::recvRetry()
1016{
1017    // we shouldn't get a retry unless we have a packet that we're
1018    // waiting to transmit
1019    assert(cpu->dcache_pkt != NULL);
1020    assert(cpu->_status == DcacheRetry);
1021    PacketPtr tmp = cpu->dcache_pkt;
1022    if (tmp->senderState) {
1023        // This is a packet from a split access.
1024        SplitFragmentSenderState * send_state =
1025            dynamic_cast<SplitFragmentSenderState *>(tmp->senderState);
1026        assert(send_state);
1027        PacketPtr big_pkt = send_state->bigPkt;
1028
1029        SplitMainSenderState * main_send_state =
1030            dynamic_cast<SplitMainSenderState *>(big_pkt->senderState);
1031        assert(main_send_state);
1032
1033        if (sendTiming(tmp)) {
1034            // If we were able to send without retrying, record that fact
1035            // and try sending the other fragment.
1036            send_state->clearFromParent();
1037            int other_index = main_send_state->getPendingFragment();
1038            if (other_index > 0) {
1039                tmp = main_send_state->fragments[other_index];
1040                cpu->dcache_pkt = tmp;
1041                if ((big_pkt->isRead() && cpu->handleReadPacket(tmp)) ||
1042                        (big_pkt->isWrite() && cpu->handleWritePacket())) {
1043                    main_send_state->fragments[other_index] = NULL;
1044                }
1045            } else {
1046                cpu->_status = DcacheWaitResponse;
1047                // memory system takes ownership of packet
1048                cpu->dcache_pkt = NULL;
1049            }
1050        }
1051    } else if (sendTiming(tmp)) {
1052        cpu->_status = DcacheWaitResponse;
1053        // memory system takes ownership of packet
1054        cpu->dcache_pkt = NULL;
1055    }
1056}
1057
1058TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu,
1059    Tick t)
1060    : pkt(_pkt), cpu(_cpu)
1061{
1062    cpu->schedule(this, t);
1063}
1064
1065void
1066TimingSimpleCPU::IprEvent::process()
1067{
1068    cpu->completeDataAccess(pkt);
1069}
1070
1071const char *
1072TimingSimpleCPU::IprEvent::description() const
1073{
1074    return "Timing Simple CPU Delay IPR event";
1075}
1076
1077
1078void
1079TimingSimpleCPU::printAddr(Addr a)
1080{
1081    dcachePort.printAddr(a);
1082}
1083
1084
1085////////////////////////////////////////////////////////////////////////
1086//
1087//  TimingSimpleCPU Simulation Object
1088//
1089TimingSimpleCPU *
1090TimingSimpleCPUParams::create()
1091{
1092    numThreads = 1;
1093#if !FULL_SYSTEM
1094    if (workload.size() != 1)
1095        panic("only one workload allowed");
1096#endif
1097    return new TimingSimpleCPU(this);
1098}
1099