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