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