timing.cc revision 5221
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 "cpu/exetrace.hh"
36#include "cpu/simple/timing.hh"
37#include "mem/packet.hh"
38#include "mem/packet_access.hh"
39#include "params/TimingSimpleCPU.hh"
40#include "sim/system.hh"
41
42using namespace std;
43using namespace TheISA;
44
45Port *
46TimingSimpleCPU::getPort(const std::string &if_name, int idx)
47{
48    if (if_name == "dcache_port")
49        return &dcachePort;
50    else if (if_name == "icache_port")
51        return &icachePort;
52    else
53        panic("No Such Port\n");
54}
55
56void
57TimingSimpleCPU::init()
58{
59    BaseCPU::init();
60#if FULL_SYSTEM
61    for (int i = 0; i < threadContexts.size(); ++i) {
62        ThreadContext *tc = threadContexts[i];
63
64        // initialize CPU, including PC
65        TheISA::initCPU(tc, tc->readCpuId());
66    }
67#endif
68}
69
70Tick
71TimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
72{
73    panic("TimingSimpleCPU doesn't expect recvAtomic callback!");
74    return curTick;
75}
76
77void
78TimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
79{
80    //No internal storage to update, jusst return
81    return;
82}
83
84void
85TimingSimpleCPU::CpuPort::recvStatusChange(Status status)
86{
87    if (status == RangeChange) {
88        if (!snoopRangeSent) {
89            snoopRangeSent = true;
90            sendStatusChange(Port::RangeChange);
91        }
92        return;
93    }
94
95    panic("TimingSimpleCPU doesn't expect recvStatusChange callback!");
96}
97
98
99void
100TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t)
101{
102    pkt = _pkt;
103    Event::schedule(t);
104}
105
106TimingSimpleCPU::TimingSimpleCPU(Params *p)
107    : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock)
108{
109    _status = Idle;
110
111    icachePort.snoopRangeSent = false;
112    dcachePort.snoopRangeSent = false;
113
114    ifetch_pkt = dcache_pkt = NULL;
115    drainEvent = NULL;
116    fetchEvent = NULL;
117    previousTick = 0;
118    changeState(SimObject::Running);
119}
120
121
122TimingSimpleCPU::~TimingSimpleCPU()
123{
124}
125
126void
127TimingSimpleCPU::serialize(ostream &os)
128{
129    SimObject::State so_state = SimObject::getState();
130    SERIALIZE_ENUM(so_state);
131    BaseSimpleCPU::serialize(os);
132}
133
134void
135TimingSimpleCPU::unserialize(Checkpoint *cp, const string &section)
136{
137    SimObject::State so_state;
138    UNSERIALIZE_ENUM(so_state);
139    BaseSimpleCPU::unserialize(cp, section);
140}
141
142unsigned int
143TimingSimpleCPU::drain(Event *drain_event)
144{
145    // TimingSimpleCPU is ready to drain if it's not waiting for
146    // an access to complete.
147    if (status() == Idle || status() == Running || status() == SwitchedOut) {
148        changeState(SimObject::Drained);
149        return 0;
150    } else {
151        changeState(SimObject::Draining);
152        drainEvent = drain_event;
153        return 1;
154    }
155}
156
157void
158TimingSimpleCPU::resume()
159{
160    DPRINTF(SimpleCPU, "Resume\n");
161    if (_status != SwitchedOut && _status != Idle) {
162        assert(system->getMemoryMode() == Enums::timing);
163
164        // Delete the old event if it existed.
165        if (fetchEvent) {
166            if (fetchEvent->scheduled())
167                fetchEvent->deschedule();
168
169            delete fetchEvent;
170        }
171
172        fetchEvent = new FetchEvent(this, nextCycle());
173    }
174
175    changeState(SimObject::Running);
176}
177
178void
179TimingSimpleCPU::switchOut()
180{
181    assert(status() == Running || status() == Idle);
182    _status = SwitchedOut;
183    numCycles += tickToCycles(curTick - previousTick);
184
185    // If we've been scheduled to resume but are then told to switch out,
186    // we'll need to cancel it.
187    if (fetchEvent && fetchEvent->scheduled())
188        fetchEvent->deschedule();
189}
190
191
192void
193TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
194{
195    BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
196
197    // if any of this CPU's ThreadContexts are active, mark the CPU as
198    // running and schedule its tick event.
199    for (int i = 0; i < threadContexts.size(); ++i) {
200        ThreadContext *tc = threadContexts[i];
201        if (tc->status() == ThreadContext::Active && _status != Running) {
202            _status = Running;
203            break;
204        }
205    }
206
207    if (_status != Running) {
208        _status = Idle;
209    }
210    assert(threadContexts.size() == 1);
211    cpuId = tc->readCpuId();
212    previousTick = curTick;
213}
214
215
216void
217TimingSimpleCPU::activateContext(int thread_num, int delay)
218{
219    DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay);
220
221    assert(thread_num == 0);
222    assert(thread);
223
224    assert(_status == Idle);
225
226    notIdleFraction++;
227    _status = Running;
228
229    // kick things off by initiating the fetch of the next instruction
230    fetchEvent = new FetchEvent(this, nextCycle(curTick + ticks(delay)));
231}
232
233
234void
235TimingSimpleCPU::suspendContext(int thread_num)
236{
237    DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
238
239    assert(thread_num == 0);
240    assert(thread);
241
242    assert(_status == Running);
243
244    // just change status to Idle... if status != Running,
245    // completeInst() will not initiate fetch of next instruction.
246
247    notIdleFraction--;
248    _status = Idle;
249}
250
251
252template <class T>
253Fault
254TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
255{
256    Request *req =
257        new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
258                    cpuId, /* thread ID */ 0);
259
260    if (traceData) {
261        traceData->setAddr(req->getVaddr());
262    }
263
264   // translate to physical address
265    Fault fault = thread->translateDataReadReq(req);
266
267    // Now do the access.
268    if (fault == NoFault) {
269        PacketPtr pkt =
270            new Packet(req,
271                       (req->isLocked() ?
272                        MemCmd::LoadLockedReq : MemCmd::ReadReq),
273                       Packet::Broadcast);
274        pkt->dataDynamic<T>(new T);
275
276        if (req->isMmapedIpr()) {
277            Tick delay;
278            delay = TheISA::handleIprRead(thread->getTC(), pkt);
279            new IprEvent(pkt, this, nextCycle(curTick + delay));
280            _status = DcacheWaitResponse;
281            dcache_pkt = NULL;
282        } else if (!dcachePort.sendTiming(pkt)) {
283            _status = DcacheRetry;
284            dcache_pkt = pkt;
285        } else {
286            _status = DcacheWaitResponse;
287            // memory system takes ownership of packet
288            dcache_pkt = NULL;
289        }
290
291        // This will need a new way to tell if it has a dcache attached.
292        if (req->isUncacheable())
293            recordEvent("Uncached Read");
294    } else {
295        delete req;
296    }
297
298    return fault;
299}
300
301Fault
302TimingSimpleCPU::translateDataReadAddr(Addr vaddr, Addr &paddr,
303        int size, unsigned flags)
304{
305    Request *req =
306        new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0);
307
308    if (traceData) {
309        traceData->setAddr(vaddr);
310    }
311
312    Fault fault = thread->translateDataWriteReq(req);
313
314    if (fault == NoFault)
315        paddr = req->getPaddr();
316
317    delete req;
318    return fault;
319}
320
321#ifndef DOXYGEN_SHOULD_SKIP_THIS
322
323template
324Fault
325TimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags);
326
327template
328Fault
329TimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags);
330
331template
332Fault
333TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
334
335template
336Fault
337TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
338
339template
340Fault
341TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
342
343template
344Fault
345TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
346
347#endif //DOXYGEN_SHOULD_SKIP_THIS
348
349template<>
350Fault
351TimingSimpleCPU::read(Addr addr, double &data, unsigned flags)
352{
353    return read(addr, *(uint64_t*)&data, flags);
354}
355
356template<>
357Fault
358TimingSimpleCPU::read(Addr addr, float &data, unsigned flags)
359{
360    return read(addr, *(uint32_t*)&data, flags);
361}
362
363
364template<>
365Fault
366TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
367{
368    return read(addr, (uint32_t&)data, flags);
369}
370
371
372template <class T>
373Fault
374TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
375{
376    Request *req =
377        new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
378                    cpuId, /* thread ID */ 0);
379
380    if (traceData) {
381        traceData->setAddr(req->getVaddr());
382    }
383
384    // translate to physical address
385    Fault fault = thread->translateDataWriteReq(req);
386
387    // Now do the access.
388    if (fault == NoFault) {
389        MemCmd cmd = MemCmd::WriteReq; // default
390        bool do_access = true;  // flag to suppress cache access
391
392        if (req->isLocked()) {
393            cmd = MemCmd::StoreCondReq;
394            do_access = TheISA::handleLockedWrite(thread, req);
395        } else if (req->isSwap()) {
396            cmd = MemCmd::SwapReq;
397            if (req->isCondSwap()) {
398                assert(res);
399                req->setExtraData(*res);
400            }
401        }
402
403        // Note: need to allocate dcache_pkt even if do_access is
404        // false, as it's used unconditionally to call completeAcc().
405        assert(dcache_pkt == NULL);
406        dcache_pkt = new Packet(req, cmd, Packet::Broadcast);
407        dcache_pkt->allocate();
408        dcache_pkt->set(data);
409
410        if (do_access) {
411            if (req->isMmapedIpr()) {
412                Tick delay;
413                dcache_pkt->set(htog(data));
414                delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt);
415                new IprEvent(dcache_pkt, this, nextCycle(curTick + delay));
416                _status = DcacheWaitResponse;
417                dcache_pkt = NULL;
418            } else if (!dcachePort.sendTiming(dcache_pkt)) {
419                _status = DcacheRetry;
420            } else {
421                _status = DcacheWaitResponse;
422                // memory system takes ownership of packet
423                dcache_pkt = NULL;
424            }
425        }
426        // This will need a new way to tell if it's hooked up to a cache or not.
427        if (req->isUncacheable())
428            recordEvent("Uncached Write");
429    } else {
430        delete req;
431    }
432
433
434    // If the write needs to have a fault on the access, consider calling
435    // changeStatus() and changing it to "bad addr write" or something.
436    return fault;
437}
438
439Fault
440TimingSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr,
441        int size, unsigned flags)
442{
443    Request *req =
444        new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0);
445
446    if (traceData) {
447        traceData->setAddr(vaddr);
448    }
449
450    Fault fault = thread->translateDataWriteReq(req);
451
452    if (fault == NoFault)
453        paddr = req->getPaddr();
454
455    delete req;
456    return fault;
457}
458
459
460#ifndef DOXYGEN_SHOULD_SKIP_THIS
461template
462Fault
463TimingSimpleCPU::write(Twin32_t data, Addr addr,
464                       unsigned flags, uint64_t *res);
465
466template
467Fault
468TimingSimpleCPU::write(Twin64_t data, Addr addr,
469                       unsigned flags, uint64_t *res);
470
471template
472Fault
473TimingSimpleCPU::write(uint64_t data, Addr addr,
474                       unsigned flags, uint64_t *res);
475
476template
477Fault
478TimingSimpleCPU::write(uint32_t data, Addr addr,
479                       unsigned flags, uint64_t *res);
480
481template
482Fault
483TimingSimpleCPU::write(uint16_t data, Addr addr,
484                       unsigned flags, uint64_t *res);
485
486template
487Fault
488TimingSimpleCPU::write(uint8_t data, Addr addr,
489                       unsigned flags, uint64_t *res);
490
491#endif //DOXYGEN_SHOULD_SKIP_THIS
492
493template<>
494Fault
495TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
496{
497    return write(*(uint64_t*)&data, addr, flags, res);
498}
499
500template<>
501Fault
502TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
503{
504    return write(*(uint32_t*)&data, addr, flags, res);
505}
506
507
508template<>
509Fault
510TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
511{
512    return write((uint32_t)data, addr, flags, res);
513}
514
515
516void
517TimingSimpleCPU::fetch()
518{
519    DPRINTF(SimpleCPU, "Fetch\n");
520
521    if (!curStaticInst || !curStaticInst->isDelayedCommit())
522        checkForInterrupts();
523
524    Request *ifetch_req = new Request();
525    ifetch_req->setThreadContext(cpuId, /* thread ID */ 0);
526    Fault fault = setupFetchRequest(ifetch_req);
527
528    ifetch_pkt = new Packet(ifetch_req, MemCmd::ReadReq, Packet::Broadcast);
529    ifetch_pkt->dataStatic(&inst);
530
531    if (fault == NoFault) {
532        if (!icachePort.sendTiming(ifetch_pkt)) {
533            // Need to wait for retry
534            _status = IcacheRetry;
535        } else {
536            // Need to wait for cache to respond
537            _status = IcacheWaitResponse;
538            // ownership of packet transferred to memory system
539            ifetch_pkt = NULL;
540        }
541    } else {
542        delete ifetch_req;
543        delete ifetch_pkt;
544        // fetch fault: advance directly to next instruction (fault handler)
545        advanceInst(fault);
546    }
547
548    numCycles += tickToCycles(curTick - previousTick);
549    previousTick = curTick;
550}
551
552
553void
554TimingSimpleCPU::advanceInst(Fault fault)
555{
556    advancePC(fault);
557
558    if (_status == Running) {
559        // kick off fetch of next instruction... callback from icache
560        // response will cause that instruction to be executed,
561        // keeping the CPU running.
562        fetch();
563    }
564}
565
566
567void
568TimingSimpleCPU::completeIfetch(PacketPtr pkt)
569{
570    DPRINTF(SimpleCPU, "Complete ICache Fetch\n");
571
572    // received a response from the icache: execute the received
573    // instruction
574    assert(!pkt->isError());
575    assert(_status == IcacheWaitResponse);
576
577    _status = Running;
578
579    numCycles += tickToCycles(curTick - previousTick);
580    previousTick = curTick;
581
582    if (getState() == SimObject::Draining) {
583        delete pkt->req;
584        delete pkt;
585
586        completeDrain();
587        return;
588    }
589
590    preExecute();
591    if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) {
592        // load or store: just send to dcache
593        Fault fault = curStaticInst->initiateAcc(this, traceData);
594        if (_status != Running) {
595            // instruction will complete in dcache response callback
596            assert(_status == DcacheWaitResponse || _status == DcacheRetry);
597            assert(fault == NoFault);
598        } else {
599            if (fault == NoFault) {
600                // early fail on store conditional: complete now
601                assert(dcache_pkt != NULL);
602                fault = curStaticInst->completeAcc(dcache_pkt, this,
603                                                   traceData);
604                delete dcache_pkt->req;
605                delete dcache_pkt;
606                dcache_pkt = NULL;
607
608                // keep an instruction count
609                if (fault == NoFault)
610                    countInst();
611            } else if (traceData) {
612                // If there was a fault, we shouldn't trace this instruction.
613                delete traceData;
614                traceData = NULL;
615            }
616
617            postExecute();
618            // @todo remove me after debugging with legion done
619            if (curStaticInst && (!curStaticInst->isMicroop() ||
620                        curStaticInst->isFirstMicroop()))
621                instCnt++;
622            advanceInst(fault);
623        }
624    } else {
625        // non-memory instruction: execute completely now
626        Fault fault = curStaticInst->execute(this, traceData);
627
628        // keep an instruction count
629        if (fault == NoFault)
630            countInst();
631        else if (traceData) {
632            // If there was a fault, we shouldn't trace this instruction.
633            delete traceData;
634            traceData = NULL;
635        }
636
637        postExecute();
638        // @todo remove me after debugging with legion done
639        if (curStaticInst && (!curStaticInst->isMicroop() ||
640                    curStaticInst->isFirstMicroop()))
641            instCnt++;
642        advanceInst(fault);
643    }
644
645    delete pkt->req;
646    delete pkt;
647}
648
649void
650TimingSimpleCPU::IcachePort::ITickEvent::process()
651{
652    cpu->completeIfetch(pkt);
653}
654
655bool
656TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt)
657{
658    if (pkt->isResponse() && !pkt->wasNacked()) {
659        // delay processing of returned data until next CPU clock edge
660        Tick next_tick = cpu->nextCycle(curTick);
661
662        if (next_tick == curTick)
663            cpu->completeIfetch(pkt);
664        else
665            tickEvent.schedule(pkt, next_tick);
666
667        return true;
668    }
669    else if (pkt->wasNacked()) {
670        assert(cpu->_status == IcacheWaitResponse);
671        pkt->reinitNacked();
672        if (!sendTiming(pkt)) {
673            cpu->_status = IcacheRetry;
674            cpu->ifetch_pkt = pkt;
675        }
676    }
677    //Snooping a Coherence Request, do nothing
678    return true;
679}
680
681void
682TimingSimpleCPU::IcachePort::recvRetry()
683{
684    // we shouldn't get a retry unless we have a packet that we're
685    // waiting to transmit
686    assert(cpu->ifetch_pkt != NULL);
687    assert(cpu->_status == IcacheRetry);
688    PacketPtr tmp = cpu->ifetch_pkt;
689    if (sendTiming(tmp)) {
690        cpu->_status = IcacheWaitResponse;
691        cpu->ifetch_pkt = NULL;
692    }
693}
694
695void
696TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
697{
698    // received a response from the dcache: complete the load or store
699    // instruction
700    assert(!pkt->isError());
701    assert(_status == DcacheWaitResponse);
702    _status = Running;
703
704    numCycles += tickToCycles(curTick - previousTick);
705    previousTick = curTick;
706
707    Fault fault = curStaticInst->completeAcc(pkt, this, traceData);
708
709    // keep an instruction count
710    if (fault == NoFault)
711        countInst();
712    else if (traceData) {
713        // If there was a fault, we shouldn't trace this instruction.
714        delete traceData;
715        traceData = NULL;
716    }
717
718    if (pkt->isRead() && pkt->isLocked()) {
719        TheISA::handleLockedRead(thread, pkt->req);
720    }
721
722    delete pkt->req;
723    delete pkt;
724
725    postExecute();
726
727    if (getState() == SimObject::Draining) {
728        advancePC(fault);
729        completeDrain();
730
731        return;
732    }
733
734    advanceInst(fault);
735}
736
737
738void
739TimingSimpleCPU::completeDrain()
740{
741    DPRINTF(Config, "Done draining\n");
742    changeState(SimObject::Drained);
743    drainEvent->process();
744}
745
746void
747TimingSimpleCPU::DcachePort::setPeer(Port *port)
748{
749    Port::setPeer(port);
750
751#if FULL_SYSTEM
752    // Update the ThreadContext's memory ports (Functional/Virtual
753    // Ports)
754    cpu->tcBase()->connectMemPorts();
755#endif
756}
757
758bool
759TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
760{
761    if (pkt->isResponse() && !pkt->wasNacked()) {
762        // delay processing of returned data until next CPU clock edge
763        Tick next_tick = cpu->nextCycle(curTick);
764
765        if (next_tick == curTick)
766            cpu->completeDataAccess(pkt);
767        else
768            tickEvent.schedule(pkt, next_tick);
769
770        return true;
771    }
772    else if (pkt->wasNacked()) {
773        assert(cpu->_status == DcacheWaitResponse);
774        pkt->reinitNacked();
775        if (!sendTiming(pkt)) {
776            cpu->_status = DcacheRetry;
777            cpu->dcache_pkt = pkt;
778        }
779    }
780    //Snooping a Coherence Request, do nothing
781    return true;
782}
783
784void
785TimingSimpleCPU::DcachePort::DTickEvent::process()
786{
787    cpu->completeDataAccess(pkt);
788}
789
790void
791TimingSimpleCPU::DcachePort::recvRetry()
792{
793    // we shouldn't get a retry unless we have a packet that we're
794    // waiting to transmit
795    assert(cpu->dcache_pkt != NULL);
796    assert(cpu->_status == DcacheRetry);
797    PacketPtr tmp = cpu->dcache_pkt;
798    if (sendTiming(tmp)) {
799        cpu->_status = DcacheWaitResponse;
800        // memory system takes ownership of packet
801        cpu->dcache_pkt = NULL;
802    }
803}
804
805TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, Tick t)
806    : Event(&mainEventQueue), pkt(_pkt), cpu(_cpu)
807{
808    schedule(t);
809}
810
811void
812TimingSimpleCPU::IprEvent::process()
813{
814    cpu->completeDataAccess(pkt);
815}
816
817const char *
818TimingSimpleCPU::IprEvent::description()
819{
820    return "Timing Simple CPU Delay IPR event";
821}
822
823
824////////////////////////////////////////////////////////////////////////
825//
826//  TimingSimpleCPU Simulation Object
827//
828TimingSimpleCPU *
829TimingSimpleCPUParams::create()
830{
831    TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params();
832    params->name = name;
833    params->numberOfThreads = 1;
834    params->max_insts_any_thread = max_insts_any_thread;
835    params->max_insts_all_threads = max_insts_all_threads;
836    params->max_loads_any_thread = max_loads_any_thread;
837    params->max_loads_all_threads = max_loads_all_threads;
838    params->progress_interval = progress_interval;
839    params->deferRegistration = defer_registration;
840    params->clock = clock;
841    params->phase = phase;
842    params->functionTrace = function_trace;
843    params->functionTraceStart = function_trace_start;
844    params->system = system;
845    params->cpu_id = cpu_id;
846    params->tracer = tracer;
847
848    params->itb = itb;
849    params->dtb = dtb;
850#if FULL_SYSTEM
851    params->profile = profile;
852    params->do_quiesce = do_quiesce;
853    params->do_checkpoint_insts = do_checkpoint_insts;
854    params->do_statistics_insts = do_statistics_insts;
855#else
856    if (workload.size() != 1)
857        panic("only one workload allowed");
858    params->process = workload[0];
859#endif
860
861    TimingSimpleCPU *cpu = new TimingSimpleCPU(params);
862    return cpu;
863}
864