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