timing.cc revision 4115:cc1d6df13c7d
15222Sksewell@umich.edu/*
25268Sksewell@umich.edu * Copyright (c) 2002-2005 The Regents of The University of Michigan
35254Sksewell@umich.edu * All rights reserved.
45222Sksewell@umich.edu *
55222Sksewell@umich.edu * Redistribution and use in source and binary forms, with or without
65222Sksewell@umich.edu * modification, are permitted provided that the following conditions are
75222Sksewell@umich.edu * met: redistributions of source code must retain the above copyright
85222Sksewell@umich.edu * notice, this list of conditions and the following disclaimer;
95222Sksewell@umich.edu * redistributions in binary form must reproduce the above copyright
105222Sksewell@umich.edu * notice, this list of conditions and the following disclaimer in the
115222Sksewell@umich.edu * documentation and/or other materials provided with the distribution;
125222Sksewell@umich.edu * neither the name of the copyright holders nor the names of its
135222Sksewell@umich.edu * contributors may be used to endorse or promote products derived from
145222Sksewell@umich.edu * this software without specific prior written permission.
155222Sksewell@umich.edu *
165222Sksewell@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
175222Sksewell@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
185222Sksewell@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
195222Sksewell@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
205222Sksewell@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
215222Sksewell@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
225222Sksewell@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
235222Sksewell@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245222Sksewell@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255222Sksewell@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
265222Sksewell@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275222Sksewell@umich.edu *
285222Sksewell@umich.edu * Authors: Steve Reinhardt
295268Sksewell@umich.edu */
305268Sksewell@umich.edu
315254Sksewell@umich.edu#include "arch/locked_mem.hh"
325222Sksewell@umich.edu#include "arch/utility.hh"
335222Sksewell@umich.edu#include "base/bigint.hh"
3411793Sbrandon.potter@amd.com#include "cpu/exetrace.hh"
3511793Sbrandon.potter@amd.com#include "cpu/simple/timing.hh"
365222Sksewell@umich.edu#include "mem/packet.hh"
375222Sksewell@umich.edu#include "mem/packet_access.hh"
385222Sksewell@umich.edu#include "sim/builder.hh"
395222Sksewell@umich.edu#include "sim/system.hh"
405222Sksewell@umich.edu
418758Sgblack@eecs.umich.eduusing namespace std;
425254Sksewell@umich.eduusing namespace TheISA;
435222Sksewell@umich.edu
445222Sksewell@umich.eduPort *
455222Sksewell@umich.eduTimingSimpleCPU::getPort(const std::string &if_name, int idx)
465222Sksewell@umich.edu{
475222Sksewell@umich.edu    if (if_name == "dcache_port")
485222Sksewell@umich.edu        return &dcachePort;
498758Sgblack@eecs.umich.edu    else if (if_name == "icache_port")
508758Sgblack@eecs.umich.edu        return &icachePort;
515222Sksewell@umich.edu    else
525222Sksewell@umich.edu        panic("No Such Port\n");
535222Sksewell@umich.edu}
545222Sksewell@umich.edu
555222Sksewell@umich.eduvoid
568758Sgblack@eecs.umich.eduTimingSimpleCPU::init()
575222Sksewell@umich.edu{
585222Sksewell@umich.edu    BaseCPU::init();
59#if FULL_SYSTEM
60    for (int i = 0; i < threadContexts.size(); ++i) {
61        ThreadContext *tc = threadContexts[i];
62
63        // initialize CPU, including PC
64        TheISA::initCPU(tc, tc->readCpuId());
65    }
66#endif
67}
68
69Tick
70TimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
71{
72    panic("TimingSimpleCPU doesn't expect recvAtomic callback!");
73    return curTick;
74}
75
76void
77TimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
78{
79    //No internal storage to update, jusst return
80    return;
81}
82
83void
84TimingSimpleCPU::CpuPort::recvStatusChange(Status status)
85{
86    if (status == RangeChange) {
87        if (!snoopRangeSent) {
88            snoopRangeSent = true;
89            sendStatusChange(Port::RangeChange);
90        }
91        return;
92    }
93
94    panic("TimingSimpleCPU doesn't expect recvStatusChange callback!");
95}
96
97
98void
99TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t)
100{
101    pkt = _pkt;
102    Event::schedule(t);
103}
104
105TimingSimpleCPU::TimingSimpleCPU(Params *p)
106    : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock),
107      cpu_id(p->cpu_id)
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    if (_status != SwitchedOut && _status != Idle) {
161        assert(system->getMemoryMode() == System::Timing);
162
163        // Delete the old event if it existed.
164        if (fetchEvent) {
165            if (fetchEvent->scheduled())
166                fetchEvent->deschedule();
167
168            delete fetchEvent;
169        }
170
171        fetchEvent =
172            new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false);
173        fetchEvent->schedule(nextCycle());
174    }
175
176    changeState(SimObject::Running);
177    previousTick = curTick;
178}
179
180void
181TimingSimpleCPU::switchOut()
182{
183    assert(status() == Running || status() == Idle);
184    _status = SwitchedOut;
185    numCycles += curTick - previousTick;
186
187    // If we've been scheduled to resume but are then told to switch out,
188    // we'll need to cancel it.
189    if (fetchEvent && fetchEvent->scheduled())
190        fetchEvent->deschedule();
191}
192
193
194void
195TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
196{
197    BaseCPU::takeOverFrom(oldCPU);
198
199    // if any of this CPU's ThreadContexts are active, mark the CPU as
200    // running and schedule its tick event.
201    for (int i = 0; i < threadContexts.size(); ++i) {
202        ThreadContext *tc = threadContexts[i];
203        if (tc->status() == ThreadContext::Active && _status != Running) {
204            _status = Running;
205            break;
206        }
207    }
208
209    if (_status != Running) {
210        _status = Idle;
211    }
212
213    Port *peer;
214    if (icachePort.getPeer() == NULL) {
215        peer = oldCPU->getPort("icache_port")->getPeer();
216        icachePort.setPeer(peer);
217    } else {
218        peer = icachePort.getPeer();
219    }
220    peer->setPeer(&icachePort);
221
222    if (dcachePort.getPeer() == NULL) {
223        peer = oldCPU->getPort("dcache_port")->getPeer();
224        dcachePort.setPeer(peer);
225    } else {
226        peer = dcachePort.getPeer();
227    }
228    peer->setPeer(&dcachePort);
229}
230
231
232void
233TimingSimpleCPU::activateContext(int thread_num, int delay)
234{
235    assert(thread_num == 0);
236    assert(thread);
237
238    assert(_status == Idle);
239
240    notIdleFraction++;
241    _status = Running;
242
243#if FULL_SYSTEM
244    // Connect the ThreadContext's memory ports (Functional/Virtual
245    // Ports)
246    tc->connectMemPorts();
247#endif
248
249    // kick things off by initiating the fetch of the next instruction
250    fetchEvent =
251        new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false);
252    fetchEvent->schedule(nextCycle(curTick + cycles(delay)));
253}
254
255
256void
257TimingSimpleCPU::suspendContext(int thread_num)
258{
259    assert(thread_num == 0);
260    assert(thread);
261
262    assert(_status == Running);
263
264    // just change status to Idle... if status != Running,
265    // completeInst() will not initiate fetch of next instruction.
266
267    notIdleFraction--;
268    _status = Idle;
269}
270
271
272template <class T>
273Fault
274TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
275{
276    Request *req =
277        new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
278                    cpu_id, /* thread ID */ 0);
279
280    if (traceData) {
281        traceData->setAddr(req->getVaddr());
282    }
283
284   // translate to physical address
285    Fault fault = thread->translateDataReadReq(req);
286
287    // Now do the access.
288    if (fault == NoFault) {
289        PacketPtr pkt =
290            new Packet(req, MemCmd::ReadReq, Packet::Broadcast);
291        pkt->dataDynamic<T>(new T);
292
293        if (!dcachePort.sendTiming(pkt)) {
294            _status = DcacheRetry;
295            dcache_pkt = pkt;
296        } else {
297            _status = DcacheWaitResponse;
298            // memory system takes ownership of packet
299            dcache_pkt = NULL;
300        }
301    } else {
302        delete req;
303    }
304
305    // This will need a new way to tell if it has a dcache attached.
306    if (req->isUncacheable())
307        recordEvent("Uncached Read");
308
309    return fault;
310}
311
312#ifndef DOXYGEN_SHOULD_SKIP_THIS
313
314template
315Fault
316TimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags);
317
318template
319Fault
320TimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags);
321
322template
323Fault
324TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
325
326template
327Fault
328TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
329
330template
331Fault
332TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
333
334template
335Fault
336TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
337
338#endif //DOXYGEN_SHOULD_SKIP_THIS
339
340template<>
341Fault
342TimingSimpleCPU::read(Addr addr, double &data, unsigned flags)
343{
344    return read(addr, *(uint64_t*)&data, flags);
345}
346
347template<>
348Fault
349TimingSimpleCPU::read(Addr addr, float &data, unsigned flags)
350{
351    return read(addr, *(uint32_t*)&data, flags);
352}
353
354
355template<>
356Fault
357TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
358{
359    return read(addr, (uint32_t&)data, flags);
360}
361
362
363template <class T>
364Fault
365TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
366{
367    Request *req =
368        new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
369                    cpu_id, /* thread ID */ 0);
370
371    if (traceData) {
372        traceData->setAddr(req->getVaddr());
373    }
374
375    // translate to physical address
376    Fault fault = thread->translateDataWriteReq(req);
377
378    // Now do the access.
379    if (fault == NoFault) {
380        assert(dcache_pkt == NULL);
381        if (req->isSwap())
382            dcache_pkt = new Packet(req, MemCmd::SwapReq, Packet::Broadcast);
383        else
384            dcache_pkt = new Packet(req, MemCmd::WriteReq, Packet::Broadcast);
385        dcache_pkt->allocate();
386        dcache_pkt->set(data);
387
388        bool do_access = true;  // flag to suppress cache access
389
390        if (req->isLocked()) {
391            do_access = TheISA::handleLockedWrite(thread, req);
392        }
393        if (req->isCondSwap()) {
394             assert(res);
395             req->setExtraData(*res);
396        }
397
398        if (do_access) {
399            if (!dcachePort.sendTiming(dcache_pkt)) {
400                _status = DcacheRetry;
401            } else {
402                _status = DcacheWaitResponse;
403                // memory system takes ownership of packet
404                dcache_pkt = NULL;
405            }
406        }
407    } else {
408        delete req;
409    }
410
411    // This will need a new way to tell if it's hooked up to a cache or not.
412    if (req->isUncacheable())
413        recordEvent("Uncached Write");
414
415    // If the write needs to have a fault on the access, consider calling
416    // changeStatus() and changing it to "bad addr write" or something.
417    return fault;
418}
419
420
421#ifndef DOXYGEN_SHOULD_SKIP_THIS
422template
423Fault
424TimingSimpleCPU::write(uint64_t data, Addr addr,
425                       unsigned flags, uint64_t *res);
426
427template
428Fault
429TimingSimpleCPU::write(uint32_t data, Addr addr,
430                       unsigned flags, uint64_t *res);
431
432template
433Fault
434TimingSimpleCPU::write(uint16_t data, Addr addr,
435                       unsigned flags, uint64_t *res);
436
437template
438Fault
439TimingSimpleCPU::write(uint8_t data, Addr addr,
440                       unsigned flags, uint64_t *res);
441
442#endif //DOXYGEN_SHOULD_SKIP_THIS
443
444template<>
445Fault
446TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
447{
448    return write(*(uint64_t*)&data, addr, flags, res);
449}
450
451template<>
452Fault
453TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
454{
455    return write(*(uint32_t*)&data, addr, flags, res);
456}
457
458
459template<>
460Fault
461TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
462{
463    return write((uint32_t)data, addr, flags, res);
464}
465
466
467void
468TimingSimpleCPU::fetch()
469{
470    if (!curStaticInst || !curStaticInst->isDelayedCommit())
471        checkForInterrupts();
472
473    Request *ifetch_req = new Request();
474    ifetch_req->setThreadContext(cpu_id, /* thread ID */ 0);
475    Fault fault = setupFetchRequest(ifetch_req);
476
477    ifetch_pkt = new Packet(ifetch_req, MemCmd::ReadReq, Packet::Broadcast);
478    ifetch_pkt->dataStatic(&inst);
479
480    if (fault == NoFault) {
481        if (!icachePort.sendTiming(ifetch_pkt)) {
482            // Need to wait for retry
483            _status = IcacheRetry;
484        } else {
485            // Need to wait for cache to respond
486            _status = IcacheWaitResponse;
487            // ownership of packet transferred to memory system
488            ifetch_pkt = NULL;
489        }
490    } else {
491        delete ifetch_req;
492        delete ifetch_pkt;
493        // fetch fault: advance directly to next instruction (fault handler)
494        advanceInst(fault);
495    }
496
497    numCycles += curTick - previousTick;
498    previousTick = curTick;
499}
500
501
502void
503TimingSimpleCPU::advanceInst(Fault fault)
504{
505    advancePC(fault);
506
507    if (_status == Running) {
508        // kick off fetch of next instruction... callback from icache
509        // response will cause that instruction to be executed,
510        // keeping the CPU running.
511        fetch();
512    }
513}
514
515
516void
517TimingSimpleCPU::completeIfetch(PacketPtr pkt)
518{
519    // received a response from the icache: execute the received
520    // instruction
521    assert(pkt->result == Packet::Success);
522    assert(_status == IcacheWaitResponse);
523
524    _status = Running;
525
526    numCycles += curTick - previousTick;
527    previousTick = curTick;
528
529    if (getState() == SimObject::Draining) {
530        delete pkt->req;
531        delete pkt;
532
533        completeDrain();
534        return;
535    }
536
537    preExecute();
538    if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) {
539        // load or store: just send to dcache
540        Fault fault = curStaticInst->initiateAcc(this, traceData);
541        if (_status != Running) {
542            // instruction will complete in dcache response callback
543            assert(_status == DcacheWaitResponse || _status == DcacheRetry);
544            assert(fault == NoFault);
545        } else {
546            if (fault == NoFault) {
547                // early fail on store conditional: complete now
548                assert(dcache_pkt != NULL);
549                fault = curStaticInst->completeAcc(dcache_pkt, this,
550                                                   traceData);
551                delete dcache_pkt->req;
552                delete dcache_pkt;
553                dcache_pkt = NULL;
554            }
555            postExecute();
556            advanceInst(fault);
557        }
558    } else {
559        // non-memory instruction: execute completely now
560        Fault fault = curStaticInst->execute(this, traceData);
561        postExecute();
562        advanceInst(fault);
563    }
564
565    delete pkt->req;
566    delete pkt;
567}
568
569void
570TimingSimpleCPU::IcachePort::ITickEvent::process()
571{
572    cpu->completeIfetch(pkt);
573}
574
575bool
576TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt)
577{
578    if (pkt->isResponse()) {
579        // delay processing of returned data until next CPU clock edge
580        Tick mem_time = pkt->req->getTime();
581        Tick next_tick = cpu->nextCycle(mem_time);
582
583        if (next_tick == curTick)
584            cpu->completeIfetch(pkt);
585        else
586            tickEvent.schedule(pkt, next_tick);
587
588        return true;
589    }
590    else {
591        //Snooping a Coherence Request, do nothing
592        return true;
593    }
594}
595
596void
597TimingSimpleCPU::IcachePort::recvRetry()
598{
599    // we shouldn't get a retry unless we have a packet that we're
600    // waiting to transmit
601    assert(cpu->ifetch_pkt != NULL);
602    assert(cpu->_status == IcacheRetry);
603    PacketPtr tmp = cpu->ifetch_pkt;
604    if (sendTiming(tmp)) {
605        cpu->_status = IcacheWaitResponse;
606        cpu->ifetch_pkt = NULL;
607    }
608}
609
610void
611TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
612{
613    // received a response from the dcache: complete the load or store
614    // instruction
615    assert(pkt->result == Packet::Success);
616    assert(_status == DcacheWaitResponse);
617    _status = Running;
618
619    numCycles += curTick - previousTick;
620    previousTick = curTick;
621
622    Fault fault = curStaticInst->completeAcc(pkt, this, traceData);
623
624    if (pkt->isRead() && pkt->req->isLocked()) {
625        TheISA::handleLockedRead(thread, pkt->req);
626    }
627
628    delete pkt->req;
629    delete pkt;
630
631    postExecute();
632
633    if (getState() == SimObject::Draining) {
634        advancePC(fault);
635        completeDrain();
636
637        return;
638    }
639
640    advanceInst(fault);
641}
642
643
644void
645TimingSimpleCPU::completeDrain()
646{
647    DPRINTF(Config, "Done draining\n");
648    changeState(SimObject::Drained);
649    drainEvent->process();
650}
651
652bool
653TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
654{
655    if (pkt->isResponse()) {
656        // delay processing of returned data until next CPU clock edge
657        Tick mem_time = pkt->req->getTime();
658        Tick next_tick = cpu->nextCycle(mem_time);
659
660        if (next_tick == curTick)
661            cpu->completeDataAccess(pkt);
662        else
663            tickEvent.schedule(pkt, next_tick);
664
665        return true;
666    }
667    else {
668        //Snooping a coherence req, do nothing
669        return true;
670    }
671}
672
673void
674TimingSimpleCPU::DcachePort::DTickEvent::process()
675{
676    cpu->completeDataAccess(pkt);
677}
678
679void
680TimingSimpleCPU::DcachePort::recvRetry()
681{
682    // we shouldn't get a retry unless we have a packet that we're
683    // waiting to transmit
684    assert(cpu->dcache_pkt != NULL);
685    assert(cpu->_status == DcacheRetry);
686    PacketPtr tmp = cpu->dcache_pkt;
687    if (sendTiming(tmp)) {
688        cpu->_status = DcacheWaitResponse;
689        // memory system takes ownership of packet
690        cpu->dcache_pkt = NULL;
691    }
692}
693
694
695////////////////////////////////////////////////////////////////////////
696//
697//  TimingSimpleCPU Simulation Object
698//
699BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU)
700
701    Param<Counter> max_insts_any_thread;
702    Param<Counter> max_insts_all_threads;
703    Param<Counter> max_loads_any_thread;
704    Param<Counter> max_loads_all_threads;
705    Param<Tick> progress_interval;
706    SimObjectParam<System *> system;
707    Param<int> cpu_id;
708
709#if FULL_SYSTEM
710    SimObjectParam<TheISA::ITB *> itb;
711    SimObjectParam<TheISA::DTB *> dtb;
712    Param<Tick> profile;
713
714    Param<bool> do_quiesce;
715    Param<bool> do_checkpoint_insts;
716    Param<bool> do_statistics_insts;
717#else
718    SimObjectParam<Process *> workload;
719#endif // FULL_SYSTEM
720
721    Param<int> clock;
722    Param<int> phase;
723
724    Param<bool> defer_registration;
725    Param<int> width;
726    Param<bool> function_trace;
727    Param<Tick> function_trace_start;
728    Param<bool> simulate_stalls;
729
730END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU)
731
732BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU)
733
734    INIT_PARAM(max_insts_any_thread,
735               "terminate when any thread reaches this inst count"),
736    INIT_PARAM(max_insts_all_threads,
737               "terminate when all threads have reached this inst count"),
738    INIT_PARAM(max_loads_any_thread,
739               "terminate when any thread reaches this load count"),
740    INIT_PARAM(max_loads_all_threads,
741               "terminate when all threads have reached this load count"),
742    INIT_PARAM(progress_interval, "Progress interval"),
743    INIT_PARAM(system, "system object"),
744    INIT_PARAM(cpu_id, "processor ID"),
745
746#if FULL_SYSTEM
747    INIT_PARAM(itb, "Instruction TLB"),
748    INIT_PARAM(dtb, "Data TLB"),
749    INIT_PARAM(profile, ""),
750    INIT_PARAM(do_quiesce, ""),
751    INIT_PARAM(do_checkpoint_insts, ""),
752    INIT_PARAM(do_statistics_insts, ""),
753#else
754    INIT_PARAM(workload, "processes to run"),
755#endif // FULL_SYSTEM
756
757    INIT_PARAM(clock, "clock speed"),
758    INIT_PARAM_DFLT(phase, "clock phase", 0),
759    INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
760    INIT_PARAM(width, "cpu width"),
761    INIT_PARAM(function_trace, "Enable function trace"),
762    INIT_PARAM(function_trace_start, "Cycle to start function trace"),
763    INIT_PARAM(simulate_stalls, "Simulate cache stall cycles")
764
765END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU)
766
767
768CREATE_SIM_OBJECT(TimingSimpleCPU)
769{
770    TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params();
771    params->name = getInstanceName();
772    params->numberOfThreads = 1;
773    params->max_insts_any_thread = max_insts_any_thread;
774    params->max_insts_all_threads = max_insts_all_threads;
775    params->max_loads_any_thread = max_loads_any_thread;
776    params->max_loads_all_threads = max_loads_all_threads;
777    params->progress_interval = progress_interval;
778    params->deferRegistration = defer_registration;
779    params->clock = clock;
780    params->phase = phase;
781    params->functionTrace = function_trace;
782    params->functionTraceStart = function_trace_start;
783    params->system = system;
784    params->cpu_id = cpu_id;
785
786#if FULL_SYSTEM
787    params->itb = itb;
788    params->dtb = dtb;
789    params->profile = profile;
790    params->do_quiesce = do_quiesce;
791    params->do_checkpoint_insts = do_checkpoint_insts;
792    params->do_statistics_insts = do_statistics_insts;
793#else
794    params->process = workload;
795#endif
796
797    TimingSimpleCPU *cpu = new TimingSimpleCPU(params);
798    return cpu;
799}
800
801REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU)
802
803