base.cc revision 729
1/*
2 * Copyright (c) 2003 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
29#include <cmath>
30#include <cstdio>
31#include <cstdlib>
32#include <iostream>
33#include <iomanip>
34#include <list>
35#include <sstream>
36#include <string>
37
38#include "base/cprintf.hh"
39#include "base/inifile.hh"
40#include "base/loader/symtab.hh"
41#include "base/misc.hh"
42#include "base/pollevent.hh"
43#include "base/range.hh"
44#include "base/trace.hh"
45#include "cpu/base_cpu.hh"
46#include "cpu/exec_context.hh"
47#include "cpu/exetrace.hh"
48#include "cpu/full_cpu/smt.hh"
49#include "cpu/simple_cpu/simple_cpu.hh"
50#include "cpu/static_inst.hh"
51#include "mem/base_mem.hh"
52#include "mem/mem_interface.hh"
53#include "sim/builder.hh"
54#include "sim/debug.hh"
55#include "sim/host.hh"
56#include "sim/sim_events.hh"
57#include "sim/sim_object.hh"
58#include "sim/stats.hh"
59
60#ifdef FULL_SYSTEM
61#include "base/remote_gdb.hh"
62#include "dev/alpha_access.h"
63#include "dev/pciareg.h"
64#include "mem/functional_mem/memory_control.hh"
65#include "mem/functional_mem/physical_memory.hh"
66#include "sim/system.hh"
67#include "targetarch/alpha_memory.hh"
68#include "targetarch/vtophys.hh"
69#else // !FULL_SYSTEM
70#include "eio/eio.hh"
71#include "mem/functional_mem/functional_memory.hh"
72#endif // FULL_SYSTEM
73
74using namespace std;
75
76SimpleCPU::TickEvent::TickEvent(SimpleCPU *c)
77    : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
78{
79}
80
81void
82SimpleCPU::TickEvent::process()
83{
84    cpu->tick();
85}
86
87const char *
88SimpleCPU::TickEvent::description()
89{
90    return "SimpleCPU tick event";
91}
92
93
94SimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu)
95    : Event(&mainEventQueue),
96      cpu(_cpu)
97{
98}
99
100void SimpleCPU::CacheCompletionEvent::process()
101{
102    cpu->processCacheCompletion();
103}
104
105const char *
106SimpleCPU::CacheCompletionEvent::description()
107{
108    return "SimpleCPU cache completion event";
109}
110
111#ifdef FULL_SYSTEM
112SimpleCPU::SimpleCPU(const string &_name,
113                     System *_system,
114                     Counter max_insts_any_thread,
115                     Counter max_insts_all_threads,
116                     Counter max_loads_any_thread,
117                     Counter max_loads_all_threads,
118                     AlphaITB *itb, AlphaDTB *dtb,
119                     FunctionalMemory *mem,
120                     MemInterface *icache_interface,
121                     MemInterface *dcache_interface,
122                     bool _def_reg, Tick freq)
123    : BaseCPU(_name, /* number_of_threads */ 1,
124              max_insts_any_thread, max_insts_all_threads,
125              max_loads_any_thread, max_loads_all_threads,
126              _system, freq),
127#else
128SimpleCPU::SimpleCPU(const string &_name, Process *_process,
129                     Counter max_insts_any_thread,
130                     Counter max_insts_all_threads,
131                     Counter max_loads_any_thread,
132                     Counter max_loads_all_threads,
133                     MemInterface *icache_interface,
134                     MemInterface *dcache_interface,
135                     bool _def_reg)
136    : BaseCPU(_name, /* number_of_threads */ 1,
137              max_insts_any_thread, max_insts_all_threads,
138              max_loads_any_thread, max_loads_all_threads),
139#endif
140      tickEvent(this), xc(NULL), defer_registration(_def_reg),
141      cacheCompletionEvent(this)
142{
143    _status = Idle;
144#ifdef FULL_SYSTEM
145    xc = new ExecContext(this, 0, system, itb, dtb, mem);
146
147    // initialize CPU, including PC
148    TheISA::initCPU(&xc->regs);
149#else
150    xc = new ExecContext(this, /* thread_num */ 0, _process, /* asid */ 0);
151#endif // !FULL_SYSTEM
152
153    icacheInterface = icache_interface;
154    dcacheInterface = dcache_interface;
155
156    memReq = new MemReq();
157    memReq->xc = xc;
158    memReq->asid = 0;
159    memReq->data = new uint8_t[64];
160
161    numInst = 0;
162    startNumInst = 0;
163    numLoad = 0;
164    startNumLoad = 0;
165    lastIcacheStall = 0;
166    lastDcacheStall = 0;
167
168    execContexts.push_back(xc);
169}
170
171SimpleCPU::~SimpleCPU()
172{
173}
174
175void SimpleCPU::init()
176{
177    if (!defer_registration) {
178        this->registerExecContexts();
179    }
180}
181
182void
183SimpleCPU::switchOut()
184{
185    _status = SwitchedOut;
186    if (tickEvent.scheduled())
187        tickEvent.squash();
188}
189
190
191void
192SimpleCPU::takeOverFrom(BaseCPU *oldCPU)
193{
194    BaseCPU::takeOverFrom(oldCPU);
195
196    assert(!tickEvent.scheduled());
197
198    // if any of this CPU's ExecContexts are active, mark the CPU as
199    // running and schedule its tick event.
200    for (int i = 0; i < execContexts.size(); ++i) {
201        ExecContext *xc = execContexts[i];
202        if (xc->status() == ExecContext::Active && _status != Running) {
203            _status = Running;
204            tickEvent.schedule(curTick);
205        }
206    }
207
208    oldCPU->switchOut();
209}
210
211
212void
213SimpleCPU::activateContext(int thread_num, int delay)
214{
215    assert(thread_num == 0);
216    assert(xc);
217
218    assert(_status == Idle);
219    notIdleFraction++;
220    scheduleTickEvent(delay);
221    _status = Running;
222}
223
224
225void
226SimpleCPU::suspendContext(int thread_num)
227{
228    assert(thread_num == 0);
229    assert(xc);
230
231    assert(_status == Running);
232    notIdleFraction--;
233    unscheduleTickEvent();
234    _status = Idle;
235}
236
237
238void
239SimpleCPU::deallocateContext(int thread_num)
240{
241    // for now, these are equivalent
242    suspendContext(thread_num);
243}
244
245
246void
247SimpleCPU::haltContext(int thread_num)
248{
249    // for now, these are equivalent
250    suspendContext(thread_num);
251}
252
253
254void
255SimpleCPU::regStats()
256{
257    using namespace Stats;
258
259    BaseCPU::regStats();
260
261    numInsts
262        .name(name() + ".num_insts")
263        .desc("Number of instructions executed")
264        ;
265
266    numMemRefs
267        .name(name() + ".num_refs")
268        .desc("Number of memory references")
269        ;
270
271    idleFraction
272        .name(name() + ".idle_fraction")
273        .desc("Percentage of idle cycles")
274        ;
275
276    icacheStallCycles
277        .name(name() + ".icache_stall_cycles")
278        .desc("ICache total stall cycles")
279        .prereq(icacheStallCycles)
280        ;
281
282    dcacheStallCycles
283        .name(name() + ".dcache_stall_cycles")
284        .desc("DCache total stall cycles")
285        .prereq(dcacheStallCycles)
286        ;
287
288    idleFraction = constant(1.0) - notIdleFraction;
289}
290
291void
292SimpleCPU::resetStats()
293{
294    startNumInst = numInst;
295    notIdleFraction = (_status != Idle);
296}
297
298void
299SimpleCPU::serialize(ostream &os)
300{
301    SERIALIZE_ENUM(_status);
302    SERIALIZE_SCALAR(inst);
303    nameOut(os, csprintf("%s.xc", name()));
304    xc->serialize(os);
305    nameOut(os, csprintf("%s.tickEvent", name()));
306    tickEvent.serialize(os);
307    nameOut(os, csprintf("%s.cacheCompletionEvent", name()));
308    cacheCompletionEvent.serialize(os);
309}
310
311void
312SimpleCPU::unserialize(Checkpoint *cp, const string &section)
313{
314    UNSERIALIZE_ENUM(_status);
315    UNSERIALIZE_SCALAR(inst);
316    xc->unserialize(cp, csprintf("%s.xc", section));
317    tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
318    cacheCompletionEvent
319        .unserialize(cp, csprintf("%s.cacheCompletionEvent", section));
320}
321
322void
323change_thread_state(int thread_number, int activate, int priority)
324{
325}
326
327Fault
328SimpleCPU::copySrcTranslate(Addr src)
329{
330    memReq->reset(src, (dcacheInterface) ?
331                  dcacheInterface->getBlockSize()
332                  : 64);
333
334    // translate to physical address
335    Fault fault = xc->translateDataReadReq(memReq);
336
337    if (fault == No_Fault) {
338        xc->copySrcAddr = src;
339        xc->copySrcPhysAddr = memReq->paddr;
340    } else {
341        xc->copySrcAddr = 0;
342        xc->copySrcPhysAddr = 0;
343    }
344    return fault;
345}
346
347Fault
348SimpleCPU::copy(Addr dest)
349{
350    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
351    uint8_t data[blk_size];
352    assert(xc->copySrcPhysAddr);
353    memReq->reset(dest, blk_size);
354    // translate to physical address
355    Fault fault = xc->translateDataWriteReq(memReq);
356    if (fault == No_Fault) {
357        Addr dest_addr = memReq->paddr;
358        // Need to read straight from memory since we have more than 8 bytes.
359        memReq->paddr = xc->copySrcPhysAddr;
360        xc->mem->read(memReq, data);
361        memReq->paddr = dest_addr;
362        xc->mem->write(memReq, data);
363    }
364    return fault;
365}
366
367// precise architected memory state accessor macros
368template <class T>
369Fault
370SimpleCPU::read(Addr addr, T &data, unsigned flags)
371{
372    memReq->reset(addr, sizeof(T), flags);
373
374    // translate to physical address
375    Fault fault = xc->translateDataReadReq(memReq);
376
377    // do functional access
378    if (fault == No_Fault)
379        fault = xc->read(memReq, data);
380
381    if (traceData) {
382        traceData->setAddr(addr);
383        if (fault == No_Fault)
384            traceData->setData(data);
385    }
386
387    // if we have a cache, do cache access too
388    if (fault == No_Fault && dcacheInterface) {
389        memReq->cmd = Read;
390        memReq->completionEvent = NULL;
391        memReq->time = curTick;
392        MemAccessResult result = dcacheInterface->access(memReq);
393
394        // Ugly hack to get an event scheduled *only* if the access is
395        // a miss.  We really should add first-class support for this
396        // at some point.
397        if (result != MA_HIT && dcacheInterface->doEvents()) {
398            memReq->completionEvent = &cacheCompletionEvent;
399            lastDcacheStall = curTick;
400            unscheduleTickEvent();
401            _status = DcacheMissStall;
402        }
403    }
404
405    return fault;
406}
407
408#ifndef DOXYGEN_SHOULD_SKIP_THIS
409
410template
411Fault
412SimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
413
414template
415Fault
416SimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
417
418template
419Fault
420SimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
421
422template
423Fault
424SimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
425
426#endif //DOXYGEN_SHOULD_SKIP_THIS
427
428template<>
429Fault
430SimpleCPU::read(Addr addr, double &data, unsigned flags)
431{
432    return read(addr, *(uint64_t*)&data, flags);
433}
434
435template<>
436Fault
437SimpleCPU::read(Addr addr, float &data, unsigned flags)
438{
439    return read(addr, *(uint32_t*)&data, flags);
440}
441
442
443template<>
444Fault
445SimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
446{
447    return read(addr, (uint32_t&)data, flags);
448}
449
450
451template <class T>
452Fault
453SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
454{
455    if (traceData) {
456        traceData->setAddr(addr);
457        traceData->setData(data);
458    }
459
460    memReq->reset(addr, sizeof(T), flags);
461
462    // translate to physical address
463    Fault fault = xc->translateDataWriteReq(memReq);
464
465    // do functional access
466    if (fault == No_Fault)
467        fault = xc->write(memReq, data);
468
469    if (fault == No_Fault && dcacheInterface) {
470        memReq->cmd = Write;
471        memcpy(memReq->data,(uint8_t *)&data,memReq->size);
472        memReq->completionEvent = NULL;
473        memReq->time = curTick;
474        MemAccessResult result = dcacheInterface->access(memReq);
475
476        // Ugly hack to get an event scheduled *only* if the access is
477        // a miss.  We really should add first-class support for this
478        // at some point.
479        if (result != MA_HIT && dcacheInterface->doEvents()) {
480            memReq->completionEvent = &cacheCompletionEvent;
481            lastDcacheStall = curTick;
482            unscheduleTickEvent();
483            _status = DcacheMissStall;
484        }
485    }
486
487    if (res && (fault == No_Fault))
488        *res = memReq->result;
489
490    return fault;
491}
492
493
494#ifndef DOXYGEN_SHOULD_SKIP_THIS
495template
496Fault
497SimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res);
498
499template
500Fault
501SimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res);
502
503template
504Fault
505SimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res);
506
507template
508Fault
509SimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res);
510
511#endif //DOXYGEN_SHOULD_SKIP_THIS
512
513template<>
514Fault
515SimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
516{
517    return write(*(uint64_t*)&data, addr, flags, res);
518}
519
520template<>
521Fault
522SimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
523{
524    return write(*(uint32_t*)&data, addr, flags, res);
525}
526
527
528template<>
529Fault
530SimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
531{
532    return write((uint32_t)data, addr, flags, res);
533}
534
535
536#ifdef FULL_SYSTEM
537Addr
538SimpleCPU::dbg_vtophys(Addr addr)
539{
540    return vtophys(xc, addr);
541}
542#endif // FULL_SYSTEM
543
544Tick save_cycle = 0;
545
546
547void
548SimpleCPU::processCacheCompletion()
549{
550    switch (status()) {
551      case IcacheMissStall:
552        icacheStallCycles += curTick - lastIcacheStall;
553        _status = IcacheMissComplete;
554        scheduleTickEvent(1);
555        break;
556      case DcacheMissStall:
557        dcacheStallCycles += curTick - lastDcacheStall;
558        _status = Running;
559        scheduleTickEvent(1);
560        break;
561      case SwitchedOut:
562        // If this CPU has been switched out due to sampling/warm-up,
563        // ignore any further status changes (e.g., due to cache
564        // misses outstanding at the time of the switch).
565        return;
566      default:
567        panic("SimpleCPU::processCacheCompletion: bad state");
568        break;
569    }
570}
571
572#ifdef FULL_SYSTEM
573void
574SimpleCPU::post_interrupt(int int_num, int index)
575{
576    BaseCPU::post_interrupt(int_num, index);
577
578    if (xc->status() == ExecContext::Suspended) {
579                DPRINTF(IPI,"Suspended Processor awoke\n");
580        xc->activate();
581    }
582}
583#endif // FULL_SYSTEM
584
585/* start simulation, program loaded, processor precise state initialized */
586void
587SimpleCPU::tick()
588{
589    numCycles++;
590
591    traceData = NULL;
592
593    Fault fault = No_Fault;
594
595#ifdef FULL_SYSTEM
596    if (AlphaISA::check_interrupts &&
597        xc->cpu->check_interrupts() &&
598        !PC_PAL(xc->regs.pc) &&
599        status() != IcacheMissComplete) {
600        int ipl = 0;
601        int summary = 0;
602        AlphaISA::check_interrupts = 0;
603        IntReg *ipr = xc->regs.ipr;
604
605        if (xc->regs.ipr[TheISA::IPR_SIRR]) {
606            for (int i = TheISA::INTLEVEL_SOFTWARE_MIN;
607                 i < TheISA::INTLEVEL_SOFTWARE_MAX; i++) {
608                if (ipr[TheISA::IPR_SIRR] & (ULL(1) << i)) {
609                    // See table 4-19 of 21164 hardware reference
610                    ipl = (i - TheISA::INTLEVEL_SOFTWARE_MIN) + 1;
611                    summary |= (ULL(1) << i);
612                }
613            }
614        }
615
616        uint64_t interrupts = xc->cpu->intr_status();
617        for (int i = TheISA::INTLEVEL_EXTERNAL_MIN;
618            i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) {
619            if (interrupts & (ULL(1) << i)) {
620                // See table 4-19 of 21164 hardware reference
621                ipl = i;
622                summary |= (ULL(1) << i);
623            }
624        }
625
626        if (ipr[TheISA::IPR_ASTRR])
627            panic("asynchronous traps not implemented\n");
628
629        if (ipl && ipl > xc->regs.ipr[TheISA::IPR_IPLR]) {
630            ipr[TheISA::IPR_ISR] = summary;
631            ipr[TheISA::IPR_INTID] = ipl;
632            xc->ev5_trap(Interrupt_Fault);
633
634            DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
635                    ipr[TheISA::IPR_IPLR], ipl, summary);
636        }
637    }
638#endif
639
640    // maintain $r0 semantics
641    xc->regs.intRegFile[ZeroReg] = 0;
642#ifdef TARGET_ALPHA
643    xc->regs.floatRegFile.d[ZeroReg] = 0.0;
644#endif // TARGET_ALPHA
645
646    if (status() == IcacheMissComplete) {
647        // We've already fetched an instruction and were stalled on an
648        // I-cache miss.  No need to fetch it again.
649
650        // Set status to running; tick event will get rescheduled if
651        // necessary at end of tick() function.
652        _status = Running;
653    }
654    else {
655        // Try to fetch an instruction
656
657        // set up memory request for instruction fetch
658#ifdef FULL_SYSTEM
659#define IFETCH_FLAGS(pc)	((pc) & 1) ? PHYSICAL : 0
660#else
661#define IFETCH_FLAGS(pc)	0
662#endif
663
664        memReq->cmd = Read;
665        memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t),
666                     IFETCH_FLAGS(xc->regs.pc));
667
668        fault = xc->translateInstReq(memReq);
669
670        if (fault == No_Fault)
671            fault = xc->mem->read(memReq, inst);
672
673        if (icacheInterface && fault == No_Fault) {
674            memReq->completionEvent = NULL;
675
676            memReq->time = curTick;
677            MemAccessResult result = icacheInterface->access(memReq);
678
679            // Ugly hack to get an event scheduled *only* if the access is
680            // a miss.  We really should add first-class support for this
681            // at some point.
682            if (result != MA_HIT && icacheInterface->doEvents()) {
683                memReq->completionEvent = &cacheCompletionEvent;
684                lastIcacheStall = curTick;
685                unscheduleTickEvent();
686                _status = IcacheMissStall;
687                return;
688            }
689        }
690    }
691
692    // If we've got a valid instruction (i.e., no fault on instruction
693    // fetch), then execute it.
694    if (fault == No_Fault) {
695
696        // keep an instruction count
697        numInst++;
698        numInsts++;
699
700        // check for instruction-count-based events
701        comInstEventQueue[0]->serviceEvents(numInst);
702
703        // decode the instruction
704        StaticInstPtr<TheISA> si(inst);
705
706        traceData = Trace::getInstRecord(curTick, xc, this, si,
707                                         xc->regs.pc);
708
709#ifdef FULL_SYSTEM
710        xc->regs.opcode = (inst >> 26) & 0x3f;
711        xc->regs.ra = (inst >> 21) & 0x1f;
712#endif // FULL_SYSTEM
713
714        xc->func_exe_inst++;
715
716        fault = si->execute(this, traceData);
717
718#ifdef FULL_SYSTEM
719        SWContext *ctx = xc->swCtx;
720        if (ctx)
721            ctx->process(xc, si.get());
722#endif
723
724        if (si->isMemRef()) {
725            numMemRefs++;
726        }
727
728        if (si->isLoad()) {
729            ++numLoad;
730            comLoadEventQueue[0]->serviceEvents(numLoad);
731        }
732
733        if (traceData)
734            traceData->finalize();
735
736    }	// if (fault == No_Fault)
737
738    if (fault != No_Fault) {
739#ifdef FULL_SYSTEM
740        xc->ev5_trap(fault);
741#else // !FULL_SYSTEM
742        fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc);
743#endif // FULL_SYSTEM
744    }
745    else {
746        // go to the next instruction
747        xc->regs.pc = xc->regs.npc;
748        xc->regs.npc += sizeof(MachInst);
749    }
750
751#ifdef FULL_SYSTEM
752    Addr oldpc;
753    do {
754        oldpc = xc->regs.pc;
755        system->pcEventQueue.service(xc);
756    } while (oldpc != xc->regs.pc);
757#endif
758
759    assert(status() == Running ||
760           status() == Idle ||
761           status() == DcacheMissStall);
762
763    if (status() == Running && !tickEvent.scheduled())
764        tickEvent.schedule(curTick + 1);
765}
766
767
768////////////////////////////////////////////////////////////////////////
769//
770//  SimpleCPU Simulation Object
771//
772BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
773
774    Param<Counter> max_insts_any_thread;
775    Param<Counter> max_insts_all_threads;
776    Param<Counter> max_loads_any_thread;
777    Param<Counter> max_loads_all_threads;
778
779#ifdef FULL_SYSTEM
780    SimObjectParam<AlphaITB *> itb;
781    SimObjectParam<AlphaDTB *> dtb;
782    SimObjectParam<FunctionalMemory *> mem;
783    SimObjectParam<System *> system;
784    Param<int> mult;
785#else
786    SimObjectParam<Process *> workload;
787#endif // FULL_SYSTEM
788
789    SimObjectParam<BaseMem *> icache;
790    SimObjectParam<BaseMem *> dcache;
791
792    Param<bool> defer_registration;
793
794END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
795
796BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
797
798    INIT_PARAM_DFLT(max_insts_any_thread,
799                    "terminate when any thread reaches this inst count",
800                    0),
801    INIT_PARAM_DFLT(max_insts_all_threads,
802                    "terminate when all threads have reached this inst count",
803                    0),
804    INIT_PARAM_DFLT(max_loads_any_thread,
805                    "terminate when any thread reaches this load count",
806                    0),
807    INIT_PARAM_DFLT(max_loads_all_threads,
808                    "terminate when all threads have reached this load count",
809                    0),
810
811#ifdef FULL_SYSTEM
812    INIT_PARAM(itb, "Instruction TLB"),
813    INIT_PARAM(dtb, "Data TLB"),
814    INIT_PARAM(mem, "memory"),
815    INIT_PARAM(system, "system object"),
816    INIT_PARAM_DFLT(mult, "system clock multiplier", 1),
817#else
818    INIT_PARAM(workload, "processes to run"),
819#endif // FULL_SYSTEM
820
821    INIT_PARAM_DFLT(icache, "L1 instruction cache object", NULL),
822    INIT_PARAM_DFLT(dcache, "L1 data cache object", NULL),
823    INIT_PARAM_DFLT(defer_registration, "defer registration with system "
824                    "(for sampling)", false)
825
826END_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
827
828
829CREATE_SIM_OBJECT(SimpleCPU)
830{
831    SimpleCPU *cpu;
832#ifdef FULL_SYSTEM
833    if (mult != 1)
834        panic("processor clock multiplier must be 1\n");
835
836    cpu = new SimpleCPU(getInstanceName(), system,
837                        max_insts_any_thread, max_insts_all_threads,
838                        max_loads_any_thread, max_loads_all_threads,
839                        itb, dtb, mem,
840                        (icache) ? icache->getInterface() : NULL,
841                        (dcache) ? dcache->getInterface() : NULL,
842                        defer_registration,
843                        ticksPerSecond * mult);
844#else
845
846    cpu = new SimpleCPU(getInstanceName(), workload,
847                        max_insts_any_thread, max_insts_all_threads,
848                        max_loads_any_thread, max_loads_all_threads,
849                        (icache) ? icache->getInterface() : NULL,
850                        (dcache) ? dcache->getInterface() : NULL,
851                        defer_registration);
852
853#endif // FULL_SYSTEM
854
855    return cpu;
856}
857
858REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU)
859
860