timing.cc revision 5408:703f1779cc89
112841Sgabeblack@google.com/*
212841Sgabeblack@google.com * Copyright (c) 2002-2005 The Regents of The University of Michigan
312841Sgabeblack@google.com * All rights reserved.
412841Sgabeblack@google.com *
512841Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
612841Sgabeblack@google.com * modification, are permitted provided that the following conditions are
712841Sgabeblack@google.com * met: redistributions of source code must retain the above copyright
812841Sgabeblack@google.com * notice, this list of conditions and the following disclaimer;
912841Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright
1012841Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the
1112841Sgabeblack@google.com * documentation and/or other materials provided with the distribution;
1212841Sgabeblack@google.com * neither the name of the copyright holders nor the names of its
1312841Sgabeblack@google.com * contributors may be used to endorse or promote products derived from
1412841Sgabeblack@google.com * this software without specific prior written permission.
1512841Sgabeblack@google.com *
1612841Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1712841Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1812841Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1912841Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2012841Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2112841Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2212841Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2312841Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2412841Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2512841Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2612841Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2712841Sgabeblack@google.com *
2812841Sgabeblack@google.com * Authors: Steve Reinhardt
2912841Sgabeblack@google.com */
3012841Sgabeblack@google.com
3112841Sgabeblack@google.com#include "arch/locked_mem.hh"
3212841Sgabeblack@google.com#include "arch/mmaped_ipr.hh"
3312841Sgabeblack@google.com#include "arch/utility.hh"
3412841Sgabeblack@google.com#include "base/bigint.hh"
3512841Sgabeblack@google.com#include "cpu/exetrace.hh"
3612841Sgabeblack@google.com#include "cpu/simple/timing.hh"
3712841Sgabeblack@google.com#include "mem/packet.hh"
3812841Sgabeblack@google.com#include "mem/packet_access.hh"
3912841Sgabeblack@google.com#include "params/TimingSimpleCPU.hh"
4012841Sgabeblack@google.com#include "sim/system.hh"
4112841Sgabeblack@google.com
4212841Sgabeblack@google.comusing namespace std;
4312841Sgabeblack@google.comusing namespace TheISA;
4412841Sgabeblack@google.com
4512841Sgabeblack@google.comPort *
4612841Sgabeblack@google.comTimingSimpleCPU::getPort(const std::string &if_name, int idx)
4712841Sgabeblack@google.com{
4812841Sgabeblack@google.com    if (if_name == "dcache_port")
4912841Sgabeblack@google.com        return &dcachePort;
5012841Sgabeblack@google.com    else if (if_name == "icache_port")
5112841Sgabeblack@google.com        return &icachePort;
5212841Sgabeblack@google.com    else
5312841Sgabeblack@google.com        panic("No Such Port\n");
5412841Sgabeblack@google.com}
5512841Sgabeblack@google.com
5612841Sgabeblack@google.comvoid
5712841Sgabeblack@google.comTimingSimpleCPU::init()
5812841Sgabeblack@google.com{
5912841Sgabeblack@google.com    BaseCPU::init();
6012841Sgabeblack@google.com    cpuId = tc->readCpuId();
6112841Sgabeblack@google.com#if FULL_SYSTEM
6212841Sgabeblack@google.com    for (int i = 0; i < threadContexts.size(); ++i) {
6312841Sgabeblack@google.com        ThreadContext *tc = threadContexts[i];
6412841Sgabeblack@google.com
6512841Sgabeblack@google.com        // initialize CPU, including PC
6612841Sgabeblack@google.com        TheISA::initCPU(tc, cpuId);
6712841Sgabeblack@google.com    }
6812878Sgabeblack@google.com#endif
6912878Sgabeblack@google.com}
7012878Sgabeblack@google.com
7112878Sgabeblack@google.comTick
7212878Sgabeblack@google.comTimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
7312878Sgabeblack@google.com{
7412841Sgabeblack@google.com    panic("TimingSimpleCPU doesn't expect recvAtomic callback!");
7512841Sgabeblack@google.com    return curTick;
7612841Sgabeblack@google.com}
7712841Sgabeblack@google.com
7812841Sgabeblack@google.comvoid
7912841Sgabeblack@google.comTimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
8012841Sgabeblack@google.com{
8112841Sgabeblack@google.com    //No internal storage to update, jusst return
8212841Sgabeblack@google.com    return;
8312841Sgabeblack@google.com}
8412841Sgabeblack@google.com
8512841Sgabeblack@google.comvoid
8612841Sgabeblack@google.comTimingSimpleCPU::CpuPort::recvStatusChange(Status status)
8712841Sgabeblack@google.com{
8812841Sgabeblack@google.com    if (status == RangeChange) {
8912841Sgabeblack@google.com        if (!snoopRangeSent) {
9012841Sgabeblack@google.com            snoopRangeSent = true;
9112841Sgabeblack@google.com            sendStatusChange(Port::RangeChange);
9212841Sgabeblack@google.com        }
9312841Sgabeblack@google.com        return;
9412841Sgabeblack@google.com    }
9512841Sgabeblack@google.com
9612841Sgabeblack@google.com    panic("TimingSimpleCPU doesn't expect recvStatusChange callback!");
9712841Sgabeblack@google.com}
9812841Sgabeblack@google.com
9912841Sgabeblack@google.com
10012841Sgabeblack@google.comvoid
10112841Sgabeblack@google.comTimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t)
10212841Sgabeblack@google.com{
10312841Sgabeblack@google.com    pkt = _pkt;
10412841Sgabeblack@google.com    Event::schedule(t);
10512841Sgabeblack@google.com}
10612841Sgabeblack@google.com
10712841Sgabeblack@google.comTimingSimpleCPU::TimingSimpleCPU(Params *p)
10812841Sgabeblack@google.com    : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock)
10912841Sgabeblack@google.com{
11012931Sgabeblack@google.com    _status = Idle;
11112931Sgabeblack@google.com
11212931Sgabeblack@google.com    icachePort.snoopRangeSent = false;
11312931Sgabeblack@google.com    dcachePort.snoopRangeSent = false;
11412931Sgabeblack@google.com
11512931Sgabeblack@google.com    ifetch_pkt = dcache_pkt = NULL;
11612931Sgabeblack@google.com    drainEvent = NULL;
11712841Sgabeblack@google.com    fetchEvent = NULL;
11812841Sgabeblack@google.com    previousTick = 0;
11912841Sgabeblack@google.com    changeState(SimObject::Running);
12012841Sgabeblack@google.com}
12112841Sgabeblack@google.com
122
123TimingSimpleCPU::~TimingSimpleCPU()
124{
125}
126
127void
128TimingSimpleCPU::serialize(ostream &os)
129{
130    SimObject::State so_state = SimObject::getState();
131    SERIALIZE_ENUM(so_state);
132    BaseSimpleCPU::serialize(os);
133}
134
135void
136TimingSimpleCPU::unserialize(Checkpoint *cp, const string &section)
137{
138    SimObject::State so_state;
139    UNSERIALIZE_ENUM(so_state);
140    BaseSimpleCPU::unserialize(cp, section);
141}
142
143unsigned int
144TimingSimpleCPU::drain(Event *drain_event)
145{
146    // TimingSimpleCPU is ready to drain if it's not waiting for
147    // an access to complete.
148    if (status() == Idle || status() == Running || status() == SwitchedOut) {
149        changeState(SimObject::Drained);
150        return 0;
151    } else {
152        changeState(SimObject::Draining);
153        drainEvent = drain_event;
154        return 1;
155    }
156}
157
158void
159TimingSimpleCPU::resume()
160{
161    DPRINTF(SimpleCPU, "Resume\n");
162    if (_status != SwitchedOut && _status != Idle) {
163        assert(system->getMemoryMode() == Enums::timing);
164
165        // Delete the old event if it existed.
166        if (fetchEvent) {
167            if (fetchEvent->scheduled())
168                fetchEvent->deschedule();
169
170            delete fetchEvent;
171        }
172
173        fetchEvent = new FetchEvent(this, nextCycle());
174    }
175
176    changeState(SimObject::Running);
177}
178
179void
180TimingSimpleCPU::switchOut()
181{
182    assert(status() == Running || status() == Idle);
183    _status = SwitchedOut;
184    numCycles += tickToCycles(curTick - previousTick);
185
186    // If we've been scheduled to resume but are then told to switch out,
187    // we'll need to cancel it.
188    if (fetchEvent && fetchEvent->scheduled())
189        fetchEvent->deschedule();
190}
191
192
193void
194TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
195{
196    BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
197
198    // if any of this CPU's ThreadContexts are active, mark the CPU as
199    // running and schedule its tick event.
200    for (int i = 0; i < threadContexts.size(); ++i) {
201        ThreadContext *tc = threadContexts[i];
202        if (tc->status() == ThreadContext::Active && _status != Running) {
203            _status = Running;
204            break;
205        }
206    }
207
208    if (_status != Running) {
209        _status = Idle;
210    }
211    assert(threadContexts.size() == 1);
212    cpuId = tc->readCpuId();
213    previousTick = curTick;
214}
215
216
217void
218TimingSimpleCPU::activateContext(int thread_num, int delay)
219{
220    DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay);
221
222    assert(thread_num == 0);
223    assert(thread);
224
225    assert(_status == Idle);
226
227    notIdleFraction++;
228    _status = Running;
229
230    // kick things off by initiating the fetch of the next instruction
231    fetchEvent = new FetchEvent(this, nextCycle(curTick + ticks(delay)));
232}
233
234
235void
236TimingSimpleCPU::suspendContext(int thread_num)
237{
238    DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
239
240    assert(thread_num == 0);
241    assert(thread);
242
243    assert(_status == Running);
244
245    // just change status to Idle... if status != Running,
246    // completeInst() will not initiate fetch of next instruction.
247
248    notIdleFraction--;
249    _status = Idle;
250}
251
252
253template <class T>
254Fault
255TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
256{
257    Request *req =
258        new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
259                    cpuId, /* thread ID */ 0);
260
261    if (traceData) {
262        traceData->setAddr(req->getVaddr());
263    }
264
265   // translate to physical address
266    Fault fault = thread->translateDataReadReq(req);
267
268    // Now do the access.
269    if (fault == NoFault) {
270        PacketPtr pkt =
271            new Packet(req,
272                       (req->isLocked() ?
273                        MemCmd::LoadLockedReq : MemCmd::ReadReq),
274                       Packet::Broadcast);
275        pkt->dataDynamic<T>(new T);
276
277        if (req->isMmapedIpr()) {
278            Tick delay;
279            delay = TheISA::handleIprRead(thread->getTC(), pkt);
280            new IprEvent(pkt, this, nextCycle(curTick + delay));
281            _status = DcacheWaitResponse;
282            dcache_pkt = NULL;
283        } else if (!dcachePort.sendTiming(pkt)) {
284            _status = DcacheRetry;
285            dcache_pkt = pkt;
286        } else {
287            _status = DcacheWaitResponse;
288            // memory system takes ownership of packet
289            dcache_pkt = NULL;
290        }
291
292        // This will need a new way to tell if it has a dcache attached.
293        if (req->isUncacheable())
294            recordEvent("Uncached Read");
295    } else {
296        delete req;
297    }
298
299    if (traceData) {
300        traceData->setData(data);
301    }
302    return fault;
303}
304
305Fault
306TimingSimpleCPU::translateDataReadAddr(Addr vaddr, Addr &paddr,
307        int size, unsigned flags)
308{
309    Request *req =
310        new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0);
311
312    if (traceData) {
313        traceData->setAddr(vaddr);
314    }
315
316    Fault fault = thread->translateDataWriteReq(req);
317
318    if (fault == NoFault)
319        paddr = req->getPaddr();
320
321    delete req;
322    return fault;
323}
324
325#ifndef DOXYGEN_SHOULD_SKIP_THIS
326
327template
328Fault
329TimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags);
330
331template
332Fault
333TimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags);
334
335template
336Fault
337TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
338
339template
340Fault
341TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
342
343template
344Fault
345TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
346
347template
348Fault
349TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
350
351#endif //DOXYGEN_SHOULD_SKIP_THIS
352
353template<>
354Fault
355TimingSimpleCPU::read(Addr addr, double &data, unsigned flags)
356{
357    return read(addr, *(uint64_t*)&data, flags);
358}
359
360template<>
361Fault
362TimingSimpleCPU::read(Addr addr, float &data, unsigned flags)
363{
364    return read(addr, *(uint32_t*)&data, flags);
365}
366
367
368template<>
369Fault
370TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
371{
372    return read(addr, (uint32_t&)data, flags);
373}
374
375
376template <class T>
377Fault
378TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
379{
380    Request *req =
381        new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
382                    cpuId, /* thread ID */ 0);
383
384    if (traceData) {
385        traceData->setAddr(req->getVaddr());
386    }
387
388    // translate to physical address
389    Fault fault = thread->translateDataWriteReq(req);
390
391    // Now do the access.
392    if (fault == NoFault) {
393        MemCmd cmd = MemCmd::WriteReq; // default
394        bool do_access = true;  // flag to suppress cache access
395
396        if (req->isLocked()) {
397            cmd = MemCmd::StoreCondReq;
398            do_access = TheISA::handleLockedWrite(thread, req);
399        } else if (req->isSwap()) {
400            cmd = MemCmd::SwapReq;
401            if (req->isCondSwap()) {
402                assert(res);
403                req->setExtraData(*res);
404            }
405        }
406
407        // Note: need to allocate dcache_pkt even if do_access is
408        // false, as it's used unconditionally to call completeAcc().
409        assert(dcache_pkt == NULL);
410        dcache_pkt = new Packet(req, cmd, Packet::Broadcast);
411        dcache_pkt->allocate();
412        dcache_pkt->set(data);
413
414        if (do_access) {
415            if (req->isMmapedIpr()) {
416                Tick delay;
417                dcache_pkt->set(htog(data));
418                delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt);
419                new IprEvent(dcache_pkt, this, nextCycle(curTick + delay));
420                _status = DcacheWaitResponse;
421                dcache_pkt = NULL;
422            } else if (!dcachePort.sendTiming(dcache_pkt)) {
423                _status = DcacheRetry;
424            } else {
425                _status = DcacheWaitResponse;
426                // memory system takes ownership of packet
427                dcache_pkt = NULL;
428            }
429        }
430        // This will need a new way to tell if it's hooked up to a cache or not.
431        if (req->isUncacheable())
432            recordEvent("Uncached Write");
433    } else {
434        delete req;
435    }
436
437    if (traceData) {
438        traceData->setData(data);
439    }
440
441    // If the write needs to have a fault on the access, consider calling
442    // changeStatus() and changing it to "bad addr write" or something.
443    return fault;
444}
445
446Fault
447TimingSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr,
448        int size, unsigned flags)
449{
450    Request *req =
451        new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0);
452
453    if (traceData) {
454        traceData->setAddr(vaddr);
455    }
456
457    Fault fault = thread->translateDataWriteReq(req);
458
459    if (fault == NoFault)
460        paddr = req->getPaddr();
461
462    delete req;
463    return fault;
464}
465
466
467#ifndef DOXYGEN_SHOULD_SKIP_THIS
468template
469Fault
470TimingSimpleCPU::write(Twin32_t data, Addr addr,
471                       unsigned flags, uint64_t *res);
472
473template
474Fault
475TimingSimpleCPU::write(Twin64_t data, Addr addr,
476                       unsigned flags, uint64_t *res);
477
478template
479Fault
480TimingSimpleCPU::write(uint64_t data, Addr addr,
481                       unsigned flags, uint64_t *res);
482
483template
484Fault
485TimingSimpleCPU::write(uint32_t data, Addr addr,
486                       unsigned flags, uint64_t *res);
487
488template
489Fault
490TimingSimpleCPU::write(uint16_t data, Addr addr,
491                       unsigned flags, uint64_t *res);
492
493template
494Fault
495TimingSimpleCPU::write(uint8_t data, Addr addr,
496                       unsigned flags, uint64_t *res);
497
498#endif //DOXYGEN_SHOULD_SKIP_THIS
499
500template<>
501Fault
502TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
503{
504    return write(*(uint64_t*)&data, addr, flags, res);
505}
506
507template<>
508Fault
509TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
510{
511    return write(*(uint32_t*)&data, addr, flags, res);
512}
513
514
515template<>
516Fault
517TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
518{
519    return write((uint32_t)data, addr, flags, res);
520}
521
522
523void
524TimingSimpleCPU::fetch()
525{
526    DPRINTF(SimpleCPU, "Fetch\n");
527
528    if (!curStaticInst || !curStaticInst->isDelayedCommit())
529        checkForInterrupts();
530
531    checkPcEventQueue();
532
533    Request *ifetch_req = new Request();
534    ifetch_req->setThreadContext(cpuId, /* thread ID */ 0);
535    Fault fault = setupFetchRequest(ifetch_req);
536
537    ifetch_pkt = new Packet(ifetch_req, MemCmd::ReadReq, Packet::Broadcast);
538    ifetch_pkt->dataStatic(&inst);
539
540    if (fault == NoFault) {
541        if (!icachePort.sendTiming(ifetch_pkt)) {
542            // Need to wait for retry
543            _status = IcacheRetry;
544        } else {
545            // Need to wait for cache to respond
546            _status = IcacheWaitResponse;
547            // ownership of packet transferred to memory system
548            ifetch_pkt = NULL;
549        }
550    } else {
551        delete ifetch_req;
552        delete ifetch_pkt;
553        // fetch fault: advance directly to next instruction (fault handler)
554        advanceInst(fault);
555    }
556
557    numCycles += tickToCycles(curTick - previousTick);
558    previousTick = curTick;
559}
560
561
562void
563TimingSimpleCPU::advanceInst(Fault fault)
564{
565    advancePC(fault);
566
567    if (_status == Running) {
568        // kick off fetch of next instruction... callback from icache
569        // response will cause that instruction to be executed,
570        // keeping the CPU running.
571        fetch();
572    }
573}
574
575
576void
577TimingSimpleCPU::completeIfetch(PacketPtr pkt)
578{
579    DPRINTF(SimpleCPU, "Complete ICache Fetch\n");
580
581    // received a response from the icache: execute the received
582    // instruction
583    assert(!pkt->isError());
584    assert(_status == IcacheWaitResponse);
585
586    _status = Running;
587
588    numCycles += tickToCycles(curTick - previousTick);
589    previousTick = curTick;
590
591    if (getState() == SimObject::Draining) {
592        delete pkt->req;
593        delete pkt;
594
595        completeDrain();
596        return;
597    }
598
599    preExecute();
600    if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) {
601        // load or store: just send to dcache
602        Fault fault = curStaticInst->initiateAcc(this, traceData);
603        if (_status != Running) {
604            // instruction will complete in dcache response callback
605            assert(_status == DcacheWaitResponse || _status == DcacheRetry);
606            assert(fault == NoFault);
607        } else {
608            if (fault == NoFault) {
609                // Note that ARM can have NULL packets if the instruction gets
610                // squashed due to predication
611                // early fail on store conditional: complete now
612                assert(dcache_pkt != NULL || THE_ISA == ARM_ISA);
613
614                fault = curStaticInst->completeAcc(dcache_pkt, this,
615                                                   traceData);
616                if (dcache_pkt != NULL)
617                {
618                    delete dcache_pkt->req;
619                    delete dcache_pkt;
620                    dcache_pkt = NULL;
621                }
622
623                // keep an instruction count
624                if (fault == NoFault)
625                    countInst();
626            } else if (traceData) {
627                // If there was a fault, we shouldn't trace this instruction.
628                delete traceData;
629                traceData = NULL;
630            }
631
632            postExecute();
633            // @todo remove me after debugging with legion done
634            if (curStaticInst && (!curStaticInst->isMicroop() ||
635                        curStaticInst->isFirstMicroop()))
636                instCnt++;
637            advanceInst(fault);
638        }
639    } else {
640        // non-memory instruction: execute completely now
641        Fault fault = curStaticInst->execute(this, traceData);
642
643        // keep an instruction count
644        if (fault == NoFault)
645            countInst();
646        else if (traceData) {
647            // If there was a fault, we shouldn't trace this instruction.
648            delete traceData;
649            traceData = NULL;
650        }
651
652        postExecute();
653        // @todo remove me after debugging with legion done
654        if (curStaticInst && (!curStaticInst->isMicroop() ||
655                    curStaticInst->isFirstMicroop()))
656            instCnt++;
657        advanceInst(fault);
658    }
659
660    delete pkt->req;
661    delete pkt;
662}
663
664void
665TimingSimpleCPU::IcachePort::ITickEvent::process()
666{
667    cpu->completeIfetch(pkt);
668}
669
670bool
671TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt)
672{
673    if (pkt->isResponse() && !pkt->wasNacked()) {
674        // delay processing of returned data until next CPU clock edge
675        Tick next_tick = cpu->nextCycle(curTick);
676
677        if (next_tick == curTick)
678            cpu->completeIfetch(pkt);
679        else
680            tickEvent.schedule(pkt, next_tick);
681
682        return true;
683    }
684    else if (pkt->wasNacked()) {
685        assert(cpu->_status == IcacheWaitResponse);
686        pkt->reinitNacked();
687        if (!sendTiming(pkt)) {
688            cpu->_status = IcacheRetry;
689            cpu->ifetch_pkt = pkt;
690        }
691    }
692    //Snooping a Coherence Request, do nothing
693    return true;
694}
695
696void
697TimingSimpleCPU::IcachePort::recvRetry()
698{
699    // we shouldn't get a retry unless we have a packet that we're
700    // waiting to transmit
701    assert(cpu->ifetch_pkt != NULL);
702    assert(cpu->_status == IcacheRetry);
703    PacketPtr tmp = cpu->ifetch_pkt;
704    if (sendTiming(tmp)) {
705        cpu->_status = IcacheWaitResponse;
706        cpu->ifetch_pkt = NULL;
707    }
708}
709
710void
711TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
712{
713    // received a response from the dcache: complete the load or store
714    // instruction
715    assert(!pkt->isError());
716    assert(_status == DcacheWaitResponse);
717    _status = Running;
718
719    numCycles += tickToCycles(curTick - previousTick);
720    previousTick = curTick;
721
722    Fault fault = curStaticInst->completeAcc(pkt, this, traceData);
723
724    // keep an instruction count
725    if (fault == NoFault)
726        countInst();
727    else if (traceData) {
728        // If there was a fault, we shouldn't trace this instruction.
729        delete traceData;
730        traceData = NULL;
731    }
732
733    if (pkt->isRead() && pkt->isLocked()) {
734        TheISA::handleLockedRead(thread, pkt->req);
735    }
736
737    delete pkt->req;
738    delete pkt;
739
740    postExecute();
741
742    if (getState() == SimObject::Draining) {
743        advancePC(fault);
744        completeDrain();
745
746        return;
747    }
748
749    advanceInst(fault);
750}
751
752
753void
754TimingSimpleCPU::completeDrain()
755{
756    DPRINTF(Config, "Done draining\n");
757    changeState(SimObject::Drained);
758    drainEvent->process();
759}
760
761void
762TimingSimpleCPU::DcachePort::setPeer(Port *port)
763{
764    Port::setPeer(port);
765
766#if FULL_SYSTEM
767    // Update the ThreadContext's memory ports (Functional/Virtual
768    // Ports)
769    cpu->tcBase()->connectMemPorts();
770#endif
771}
772
773bool
774TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
775{
776    if (pkt->isResponse() && !pkt->wasNacked()) {
777        // delay processing of returned data until next CPU clock edge
778        Tick next_tick = cpu->nextCycle(curTick);
779
780        if (next_tick == curTick)
781            cpu->completeDataAccess(pkt);
782        else
783            tickEvent.schedule(pkt, next_tick);
784
785        return true;
786    }
787    else if (pkt->wasNacked()) {
788        assert(cpu->_status == DcacheWaitResponse);
789        pkt->reinitNacked();
790        if (!sendTiming(pkt)) {
791            cpu->_status = DcacheRetry;
792            cpu->dcache_pkt = pkt;
793        }
794    }
795    //Snooping a Coherence Request, do nothing
796    return true;
797}
798
799void
800TimingSimpleCPU::DcachePort::DTickEvent::process()
801{
802    cpu->completeDataAccess(pkt);
803}
804
805void
806TimingSimpleCPU::DcachePort::recvRetry()
807{
808    // we shouldn't get a retry unless we have a packet that we're
809    // waiting to transmit
810    assert(cpu->dcache_pkt != NULL);
811    assert(cpu->_status == DcacheRetry);
812    PacketPtr tmp = cpu->dcache_pkt;
813    if (sendTiming(tmp)) {
814        cpu->_status = DcacheWaitResponse;
815        // memory system takes ownership of packet
816        cpu->dcache_pkt = NULL;
817    }
818}
819
820TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, Tick t)
821    : Event(&mainEventQueue), pkt(_pkt), cpu(_cpu)
822{
823    schedule(t);
824}
825
826void
827TimingSimpleCPU::IprEvent::process()
828{
829    cpu->completeDataAccess(pkt);
830}
831
832const char *
833TimingSimpleCPU::IprEvent::description() const
834{
835    return "Timing Simple CPU Delay IPR event";
836}
837
838
839void
840TimingSimpleCPU::printAddr(Addr a)
841{
842    dcachePort.printAddr(a);
843}
844
845
846////////////////////////////////////////////////////////////////////////
847//
848//  TimingSimpleCPU Simulation Object
849//
850TimingSimpleCPU *
851TimingSimpleCPUParams::create()
852{
853    TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params();
854    params->name = name;
855    params->numberOfThreads = 1;
856    params->max_insts_any_thread = max_insts_any_thread;
857    params->max_insts_all_threads = max_insts_all_threads;
858    params->max_loads_any_thread = max_loads_any_thread;
859    params->max_loads_all_threads = max_loads_all_threads;
860    params->progress_interval = progress_interval;
861    params->deferRegistration = defer_registration;
862    params->clock = clock;
863    params->phase = phase;
864    params->functionTrace = function_trace;
865    params->functionTraceStart = function_trace_start;
866    params->system = system;
867    params->cpu_id = cpu_id;
868    params->tracer = tracer;
869
870    params->itb = itb;
871    params->dtb = dtb;
872#if FULL_SYSTEM
873    params->profile = profile;
874    params->do_quiesce = do_quiesce;
875    params->do_checkpoint_insts = do_checkpoint_insts;
876    params->do_statistics_insts = do_statistics_insts;
877#else
878    if (workload.size() != 1)
879        panic("only one workload allowed");
880    params->process = workload[0];
881#endif
882
883    TimingSimpleCPU *cpu = new TimingSimpleCPU(params);
884    return cpu;
885}
886