timing.cc revision 7691
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->readPC();
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->readPC();
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    bool fromRom = isRomMicroPC(thread->readMicroPC());
705
706    if (!fromRom && !curMacroStaticInst) {
707        Request *ifetch_req = new Request();
708        ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0);
709        setupFetchRequest(ifetch_req);
710        thread->itb->translateTiming(ifetch_req, tc, &fetchTranslation,
711                BaseTLB::Execute);
712    } else {
713        _status = IcacheWaitResponse;
714        completeIfetch(NULL);
715
716        numCycles += tickToCycles(curTick - previousTick);
717        previousTick = curTick;
718    }
719}
720
721
722void
723TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc)
724{
725    if (fault == NoFault) {
726        ifetch_pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast);
727        ifetch_pkt->dataStatic(&inst);
728
729        if (!icachePort.sendTiming(ifetch_pkt)) {
730            // Need to wait for retry
731            _status = IcacheRetry;
732        } else {
733            // Need to wait for cache to respond
734            _status = IcacheWaitResponse;
735            // ownership of packet transferred to memory system
736            ifetch_pkt = NULL;
737        }
738    } else {
739        delete req;
740        // fetch fault: advance directly to next instruction (fault handler)
741        advanceInst(fault);
742    }
743
744    numCycles += tickToCycles(curTick - previousTick);
745    previousTick = curTick;
746}
747
748
749void
750TimingSimpleCPU::advanceInst(Fault fault)
751{
752    if (fault != NoFault || !stayAtPC)
753        advancePC(fault);
754
755    if (_status == Running) {
756        // kick off fetch of next instruction... callback from icache
757        // response will cause that instruction to be executed,
758        // keeping the CPU running.
759        fetch();
760    }
761}
762
763
764void
765TimingSimpleCPU::completeIfetch(PacketPtr pkt)
766{
767    DPRINTF(SimpleCPU, "Complete ICache Fetch\n");
768
769    // received a response from the icache: execute the received
770    // instruction
771
772    assert(!pkt || !pkt->isError());
773    assert(_status == IcacheWaitResponse);
774
775    _status = Running;
776
777    numCycles += tickToCycles(curTick - previousTick);
778    previousTick = curTick;
779
780    if (getState() == SimObject::Draining) {
781        if (pkt) {
782            delete pkt->req;
783            delete pkt;
784        }
785
786        completeDrain();
787        return;
788    }
789
790    preExecute();
791    if (curStaticInst &&
792            curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) {
793        // load or store: just send to dcache
794        Fault fault = curStaticInst->initiateAcc(this, traceData);
795        if (_status != Running) {
796            // instruction will complete in dcache response callback
797            assert(_status == DcacheWaitResponse ||
798                    _status == DcacheRetry || DTBWaitResponse);
799            assert(fault == NoFault);
800        } else {
801            if (fault != NoFault && traceData) {
802                // If there was a fault, we shouldn't trace this instruction.
803                delete traceData;
804                traceData = NULL;
805            }
806
807            postExecute();
808            // @todo remove me after debugging with legion done
809            if (curStaticInst && (!curStaticInst->isMicroop() ||
810                        curStaticInst->isFirstMicroop()))
811                instCnt++;
812            advanceInst(fault);
813        }
814    } else if (curStaticInst) {
815        // non-memory instruction: execute completely now
816        Fault fault = curStaticInst->execute(this, traceData);
817
818        // keep an instruction count
819        if (fault == NoFault)
820            countInst();
821        else if (traceData && !DTRACE(ExecFaulting)) {
822            delete traceData;
823            traceData = NULL;
824        }
825
826        postExecute();
827        // @todo remove me after debugging with legion done
828        if (curStaticInst && (!curStaticInst->isMicroop() ||
829                    curStaticInst->isFirstMicroop()))
830            instCnt++;
831        advanceInst(fault);
832    } else {
833        advanceInst(NoFault);
834    }
835
836    if (pkt) {
837        delete pkt->req;
838        delete pkt;
839    }
840}
841
842void
843TimingSimpleCPU::IcachePort::ITickEvent::process()
844{
845    cpu->completeIfetch(pkt);
846}
847
848bool
849TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt)
850{
851    if (pkt->isResponse() && !pkt->wasNacked()) {
852        // delay processing of returned data until next CPU clock edge
853        Tick next_tick = cpu->nextCycle(curTick);
854
855        if (next_tick == curTick)
856            cpu->completeIfetch(pkt);
857        else
858            tickEvent.schedule(pkt, next_tick);
859
860        return true;
861    }
862    else if (pkt->wasNacked()) {
863        assert(cpu->_status == IcacheWaitResponse);
864        pkt->reinitNacked();
865        if (!sendTiming(pkt)) {
866            cpu->_status = IcacheRetry;
867            cpu->ifetch_pkt = pkt;
868        }
869    }
870    //Snooping a Coherence Request, do nothing
871    return true;
872}
873
874void
875TimingSimpleCPU::IcachePort::recvRetry()
876{
877    // we shouldn't get a retry unless we have a packet that we're
878    // waiting to transmit
879    assert(cpu->ifetch_pkt != NULL);
880    assert(cpu->_status == IcacheRetry);
881    PacketPtr tmp = cpu->ifetch_pkt;
882    if (sendTiming(tmp)) {
883        cpu->_status = IcacheWaitResponse;
884        cpu->ifetch_pkt = NULL;
885    }
886}
887
888void
889TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
890{
891    // received a response from the dcache: complete the load or store
892    // instruction
893    assert(!pkt->isError());
894    assert(_status == DcacheWaitResponse || _status == DTBWaitResponse ||
895           pkt->req->getFlags().isSet(Request::NO_ACCESS));
896
897    numCycles += tickToCycles(curTick - previousTick);
898    previousTick = curTick;
899
900    if (pkt->senderState) {
901        SplitFragmentSenderState * send_state =
902            dynamic_cast<SplitFragmentSenderState *>(pkt->senderState);
903        assert(send_state);
904        delete pkt->req;
905        delete pkt;
906        PacketPtr big_pkt = send_state->bigPkt;
907        delete send_state;
908
909        SplitMainSenderState * main_send_state =
910            dynamic_cast<SplitMainSenderState *>(big_pkt->senderState);
911        assert(main_send_state);
912        // Record the fact that this packet is no longer outstanding.
913        assert(main_send_state->outstanding != 0);
914        main_send_state->outstanding--;
915
916        if (main_send_state->outstanding) {
917            return;
918        } else {
919            delete main_send_state;
920            big_pkt->senderState = NULL;
921            pkt = big_pkt;
922        }
923    }
924
925    _status = Running;
926
927    Fault fault = curStaticInst->completeAcc(pkt, this, traceData);
928
929    // keep an instruction count
930    if (fault == NoFault)
931        countInst();
932    else if (traceData) {
933        // If there was a fault, we shouldn't trace this instruction.
934        delete traceData;
935        traceData = NULL;
936    }
937
938    // the locked flag may be cleared on the response packet, so check
939    // pkt->req and not pkt to see if it was a load-locked
940    if (pkt->isRead() && pkt->req->isLLSC()) {
941        TheISA::handleLockedRead(thread, pkt->req);
942    }
943
944    delete pkt->req;
945    delete pkt;
946
947    postExecute();
948
949    if (getState() == SimObject::Draining) {
950        advancePC(fault);
951        completeDrain();
952
953        return;
954    }
955
956    advanceInst(fault);
957}
958
959
960void
961TimingSimpleCPU::completeDrain()
962{
963    DPRINTF(Config, "Done draining\n");
964    changeState(SimObject::Drained);
965    drainEvent->process();
966}
967
968void
969TimingSimpleCPU::DcachePort::setPeer(Port *port)
970{
971    Port::setPeer(port);
972
973#if FULL_SYSTEM
974    // Update the ThreadContext's memory ports (Functional/Virtual
975    // Ports)
976    cpu->tcBase()->connectMemPorts(cpu->tcBase());
977#endif
978}
979
980bool
981TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
982{
983    if (pkt->isResponse() && !pkt->wasNacked()) {
984        // delay processing of returned data until next CPU clock edge
985        Tick next_tick = cpu->nextCycle(curTick);
986
987        if (next_tick == curTick) {
988            cpu->completeDataAccess(pkt);
989        } else {
990            tickEvent.schedule(pkt, next_tick);
991        }
992
993        return true;
994    }
995    else if (pkt->wasNacked()) {
996        assert(cpu->_status == DcacheWaitResponse);
997        pkt->reinitNacked();
998        if (!sendTiming(pkt)) {
999            cpu->_status = DcacheRetry;
1000            cpu->dcache_pkt = pkt;
1001        }
1002    }
1003    //Snooping a Coherence Request, do nothing
1004    return true;
1005}
1006
1007void
1008TimingSimpleCPU::DcachePort::DTickEvent::process()
1009{
1010    cpu->completeDataAccess(pkt);
1011}
1012
1013void
1014TimingSimpleCPU::DcachePort::recvRetry()
1015{
1016    // we shouldn't get a retry unless we have a packet that we're
1017    // waiting to transmit
1018    assert(cpu->dcache_pkt != NULL);
1019    assert(cpu->_status == DcacheRetry);
1020    PacketPtr tmp = cpu->dcache_pkt;
1021    if (tmp->senderState) {
1022        // This is a packet from a split access.
1023        SplitFragmentSenderState * send_state =
1024            dynamic_cast<SplitFragmentSenderState *>(tmp->senderState);
1025        assert(send_state);
1026        PacketPtr big_pkt = send_state->bigPkt;
1027
1028        SplitMainSenderState * main_send_state =
1029            dynamic_cast<SplitMainSenderState *>(big_pkt->senderState);
1030        assert(main_send_state);
1031
1032        if (sendTiming(tmp)) {
1033            // If we were able to send without retrying, record that fact
1034            // and try sending the other fragment.
1035            send_state->clearFromParent();
1036            int other_index = main_send_state->getPendingFragment();
1037            if (other_index > 0) {
1038                tmp = main_send_state->fragments[other_index];
1039                cpu->dcache_pkt = tmp;
1040                if ((big_pkt->isRead() && cpu->handleReadPacket(tmp)) ||
1041                        (big_pkt->isWrite() && cpu->handleWritePacket())) {
1042                    main_send_state->fragments[other_index] = NULL;
1043                }
1044            } else {
1045                cpu->_status = DcacheWaitResponse;
1046                // memory system takes ownership of packet
1047                cpu->dcache_pkt = NULL;
1048            }
1049        }
1050    } else if (sendTiming(tmp)) {
1051        cpu->_status = DcacheWaitResponse;
1052        // memory system takes ownership of packet
1053        cpu->dcache_pkt = NULL;
1054    }
1055}
1056
1057TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu,
1058    Tick t)
1059    : pkt(_pkt), cpu(_cpu)
1060{
1061    cpu->schedule(this, t);
1062}
1063
1064void
1065TimingSimpleCPU::IprEvent::process()
1066{
1067    cpu->completeDataAccess(pkt);
1068}
1069
1070const char *
1071TimingSimpleCPU::IprEvent::description() const
1072{
1073    return "Timing Simple CPU Delay IPR event";
1074}
1075
1076
1077void
1078TimingSimpleCPU::printAddr(Addr a)
1079{
1080    dcachePort.printAddr(a);
1081}
1082
1083
1084////////////////////////////////////////////////////////////////////////
1085//
1086//  TimingSimpleCPU Simulation Object
1087//
1088TimingSimpleCPU *
1089TimingSimpleCPUParams::create()
1090{
1091    numThreads = 1;
1092#if !FULL_SYSTEM
1093    if (workload.size() != 1)
1094        panic("only one workload allowed");
1095#endif
1096    return new TimingSimpleCPU(this);
1097}
1098