2 * Copyright (c) 2002-2005 The Regents of The University of Michigan
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.
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.
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/stats/events.hh"
45 #include "base/trace.hh"
46 #include "cpu/base.hh"
47 #include "cpu/cpu_exec_context.hh"
48 #include "cpu/exec_context.hh"
49 #include "cpu/exetrace.hh"
50 #include "cpu/profile.hh"
51 #include "cpu/sampler/sampler.hh"
52 #include "cpu/simple/cpu.hh"
54 #include "cpu/static_inst.hh"
55 #include "kern/kernel_stats.hh"
56 #include "mem/base_mem.hh"
57 #include "mem/mem_interface.hh"
58 #include "sim/byteswap.hh"
59 #include "sim/builder.hh"
60 #include "sim/debug.hh"
61 #include "sim/host.hh"
62 #include "sim/sim_events.hh"
63 #include "sim/sim_object.hh"
64 #include "sim/stats.hh"
67 #include "base/remote_gdb.hh"
68 #include "mem/functional/memory_control.hh"
69 #include "mem/functional/physical.hh"
70 #include "sim/system.hh"
71 #include "arch/tlb.hh"
72 #include "arch/stacktrace.hh"
73 #include "arch/vtophys.hh"
75 #include "mem/functional/functional.hh"
79 //The SimpleCPU does alpha only
80 using namespace AlphaISA
;
83 SimpleCPU::TickEvent::TickEvent(SimpleCPU
*c
, int w
)
84 : Event(&mainEventQueue
, CPU_Tick_Pri
), cpu(c
), width(w
)
94 for (int i
= 0; i
< execContexts
.size(); ++i
) {
95 ExecContext
*xc
= execContexts
[i
];
97 // initialize CPU, including PC
98 TheISA::initCPU(xc
, xc
->readCpuId());
104 SimpleCPU::TickEvent::process()
109 } while (--count
> 0 && cpu
->status() == Running
);
113 SimpleCPU::TickEvent::description()
115 return "SimpleCPU tick event";
119 SimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU
*_cpu
)
120 : Event(&mainEventQueue
), cpu(_cpu
)
124 void SimpleCPU::CacheCompletionEvent::process()
126 cpu
->processCacheCompletion();
130 SimpleCPU::CacheCompletionEvent::description()
132 return "SimpleCPU cache completion event";
135 SimpleCPU::SimpleCPU(Params
*p
)
136 : BaseCPU(p
), tickEvent(this, p
->width
), cpuXC(NULL
),
137 cacheCompletionEvent(this)
141 cpuXC
= new CPUExecContext(this, 0, p
->system
, p
->itb
, p
->dtb
, p
->mem
);
144 cpuXC
= new CPUExecContext(this, /* thread_num */ 0, p
->process
,
146 #endif // !FULL_SYSTEM
147 cpuXC
->setStatus(ExecContext::Suspended
);
148 xcProxy
= cpuXC
->getProxy();
150 icacheInterface
= p
->icache_interface
;
151 dcacheInterface
= p
->dcache_interface
;
153 memReq
= new MemReq();
154 memReq
->xc
= xcProxy
;
156 memReq
->data
= new uint8_t[64];
165 execContexts
.push_back(xcProxy
);
168 SimpleCPU::~SimpleCPU()
173 SimpleCPU::switchOut(Sampler
*s
)
176 if (status() == DcacheMissStall
) {
177 DPRINTF(Sampler
,"Outstanding dcache access, waiting for completion\n");
178 _status
= DcacheMissSwitch
;
181 _status
= SwitchedOut
;
183 if (tickEvent
.scheduled())
186 sampler
->signalSwitched();
192 SimpleCPU::takeOverFrom(BaseCPU
*oldCPU
)
194 BaseCPU::takeOverFrom(oldCPU
);
196 assert(!tickEvent
.scheduled());
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
) {
204 tickEvent
.schedule(curTick
);
211 SimpleCPU::activateContext(int thread_num
, int delay
)
213 assert(thread_num
== 0);
216 assert(_status
== Idle
|| _status
== SwitchedOut
);
218 scheduleTickEvent(delay
);
224 SimpleCPU::suspendContext(int thread_num
)
226 assert(thread_num
== 0);
229 assert(_status
== Running
|| _status
== SwitchedOut
);
231 unscheduleTickEvent();
237 SimpleCPU::deallocateContext(int thread_num
)
239 // for now, these are equivalent
240 suspendContext(thread_num
);
245 SimpleCPU::haltContext(int thread_num
)
247 // for now, these are equivalent
248 suspendContext(thread_num
);
253 SimpleCPU::regStats()
255 using namespace Stats
;
260 .name(name() + ".num_insts")
261 .desc("Number of instructions executed")
265 .name(name() + ".num_refs")
266 .desc("Number of memory references")
270 .name(name() + ".not_idle_fraction")
271 .desc("Percentage of non-idle cycles")
275 .name(name() + ".idle_fraction")
276 .desc("Percentage of idle cycles")
280 .name(name() + ".icache_stall_cycles")
281 .desc("ICache total stall cycles")
282 .prereq(icacheStallCycles
)
286 .name(name() + ".dcache_stall_cycles")
287 .desc("DCache total stall cycles")
288 .prereq(dcacheStallCycles
)
291 idleFraction
= constant(1.0) - notIdleFraction
;
295 SimpleCPU::resetStats()
297 startNumInst
= numInst
;
298 notIdleFraction
= (_status
!= Idle
);
302 SimpleCPU::serialize(ostream
&os
)
304 BaseCPU::serialize(os
);
305 SERIALIZE_ENUM(_status
);
306 SERIALIZE_SCALAR(inst
);
307 nameOut(os
, csprintf("%s.xc.0", name()));
308 cpuXC
->serialize(os
);
309 nameOut(os
, csprintf("%s.tickEvent", name()));
310 tickEvent
.serialize(os
);
311 nameOut(os
, csprintf("%s.cacheCompletionEvent", name()));
312 cacheCompletionEvent
.serialize(os
);
316 SimpleCPU::unserialize(Checkpoint
*cp
, const string
§ion
)
318 BaseCPU::unserialize(cp
, section
);
319 UNSERIALIZE_ENUM(_status
);
320 UNSERIALIZE_SCALAR(inst
);
321 cpuXC
->unserialize(cp
, csprintf("%s.xc.0", section
));
322 tickEvent
.unserialize(cp
, csprintf("%s.tickEvent", section
));
324 .unserialize(cp
, csprintf("%s.cacheCompletionEvent", section
));
328 change_thread_state(int thread_number
, int activate
, int priority
)
333 SimpleCPU::copySrcTranslate(Addr src
)
335 static bool no_warn
= true;
336 int blk_size
= (dcacheInterface
) ? dcacheInterface
->getBlockSize() : 64;
337 // Only support block sizes of 64 atm.
338 assert(blk_size
== 64);
339 int offset
= src
& (blk_size
- 1);
341 // Make sure block doesn't span page
343 (src
& PageMask
) != ((src
+ blk_size
) & PageMask
) &&
344 (src
>> 40) != 0xfffffc) {
345 warn("Copied block source spans pages %x.", src
);
349 memReq
->reset(src
& ~(blk_size
- 1), blk_size
);
351 // translate to physical address
352 Fault fault
= cpuXC
->translateDataReadReq(memReq
);
354 if (fault
== NoFault
) {
355 cpuXC
->copySrcAddr
= src
;
356 cpuXC
->copySrcPhysAddr
= memReq
->paddr
+ offset
;
358 assert(!fault
->isAlignmentFault());
360 cpuXC
->copySrcAddr
= 0;
361 cpuXC
->copySrcPhysAddr
= 0;
367 SimpleCPU::copy(Addr dest
)
369 static bool no_warn
= true;
370 int blk_size
= (dcacheInterface
) ? dcacheInterface
->getBlockSize() : 64;
371 // Only support block sizes of 64 atm.
372 assert(blk_size
== 64);
373 uint8_t data
[blk_size
];
374 //assert(cpuXC->copySrcAddr);
375 int offset
= dest
& (blk_size
- 1);
377 // Make sure block doesn't span page
379 (dest
& PageMask
) != ((dest
+ blk_size
) & PageMask
) &&
380 (dest
>> 40) != 0xfffffc) {
382 warn("Copied block destination spans pages %x. ", dest
);
385 memReq
->reset(dest
& ~(blk_size
-1), blk_size
);
386 // translate to physical address
387 Fault fault
= cpuXC
->translateDataWriteReq(memReq
);
389 if (fault
== NoFault
) {
390 Addr dest_addr
= memReq
->paddr
+ offset
;
391 // Need to read straight from memory since we have more than 8 bytes.
392 memReq
->paddr
= cpuXC
->copySrcPhysAddr
;
393 cpuXC
->mem
->read(memReq
, data
);
394 memReq
->paddr
= dest_addr
;
395 cpuXC
->mem
->write(memReq
, data
);
396 if (dcacheInterface
) {
398 memReq
->completionEvent
= NULL
;
399 memReq
->paddr
= cpuXC
->copySrcPhysAddr
;
400 memReq
->dest
= dest_addr
;
402 memReq
->time
= curTick
;
403 memReq
->flags
&= ~INST_READ
;
404 dcacheInterface
->access(memReq
);
408 assert(!fault
->isAlignmentFault());
413 // precise architected memory state accessor macros
416 SimpleCPU::read(Addr addr
, T
&data
, unsigned flags
)
418 if (status() == DcacheMissStall
|| status() == DcacheMissSwitch
) {
419 Fault fault
= cpuXC
->read(memReq
,data
);
422 traceData
->setAddr(memReq
->vaddr
);
427 memReq
->reset(addr
, sizeof(T
), flags
);
429 // translate to physical address
430 Fault fault
= cpuXC
->translateDataReadReq(memReq
);
432 // if we have a cache, do cache access too
433 if (fault
== NoFault
&& dcacheInterface
) {
435 memReq
->completionEvent
= NULL
;
436 memReq
->time
= curTick
;
437 memReq
->flags
&= ~INST_READ
;
438 MemAccessResult result
= dcacheInterface
->access(memReq
);
440 // Ugly hack to get an event scheduled *only* if the access is
441 // a miss. We really should add first-class support for this
443 if (result
!= MA_HIT
&& dcacheInterface
->doEvents()) {
444 memReq
->completionEvent
= &cacheCompletionEvent
;
445 lastDcacheStall
= curTick
;
446 unscheduleTickEvent();
447 _status
= DcacheMissStall
;
449 // do functional access
450 fault
= cpuXC
->read(memReq
, data
);
453 } else if(fault
== NoFault
) {
454 // do functional access
455 fault
= cpuXC
->read(memReq
, data
);
459 if (!dcacheInterface
&& (memReq
->flags
& UNCACHEABLE
))
460 recordEvent("Uncached Read");
465 #ifndef DOXYGEN_SHOULD_SKIP_THIS
469 SimpleCPU::read(Addr addr
, uint64_t &data
, unsigned flags
);
473 SimpleCPU::read(Addr addr
, uint32_t &data
, unsigned flags
);
477 SimpleCPU::read(Addr addr
, uint16_t &data
, unsigned flags
);
481 SimpleCPU::read(Addr addr
, uint8_t &data
, unsigned flags
);
483 #endif //DOXYGEN_SHOULD_SKIP_THIS
487 SimpleCPU::read(Addr addr
, double &data
, unsigned flags
)
489 return read(addr
, *(uint64_t*)&data
, flags
);
494 SimpleCPU::read(Addr addr
, float &data
, unsigned flags
)
496 return read(addr
, *(uint32_t*)&data
, flags
);
502 SimpleCPU::read(Addr addr
, int32_t &data
, unsigned flags
)
504 return read(addr
, (uint32_t&)data
, flags
);
510 SimpleCPU::write(T data
, Addr addr
, unsigned flags
, uint64_t *res
)
512 memReq
->reset(addr
, sizeof(T
), flags
);
514 // translate to physical address
515 Fault fault
= cpuXC
->translateDataWriteReq(memReq
);
517 // do functional access
518 if (fault
== NoFault
)
519 fault
= cpuXC
->write(memReq
, data
);
521 if (fault
== NoFault
&& dcacheInterface
) {
523 memcpy(memReq
->data
,(uint8_t *)&data
,memReq
->size
);
524 memReq
->completionEvent
= NULL
;
525 memReq
->time
= curTick
;
526 memReq
->flags
&= ~INST_READ
;
527 MemAccessResult result
= dcacheInterface
->access(memReq
);
529 // Ugly hack to get an event scheduled *only* if the access is
530 // a miss. We really should add first-class support for this
532 if (result
!= MA_HIT
&& dcacheInterface
->doEvents()) {
533 memReq
->completionEvent
= &cacheCompletionEvent
;
534 lastDcacheStall
= curTick
;
535 unscheduleTickEvent();
536 _status
= DcacheMissStall
;
540 if (res
&& (fault
== NoFault
))
541 *res
= memReq
->result
;
543 if (!dcacheInterface
&& (memReq
->flags
& UNCACHEABLE
))
544 recordEvent("Uncached Write");
550 #ifndef DOXYGEN_SHOULD_SKIP_THIS
553 SimpleCPU::write(uint64_t data
, Addr addr
, unsigned flags
, uint64_t *res
);
557 SimpleCPU::write(uint32_t data
, Addr addr
, unsigned flags
, uint64_t *res
);
561 SimpleCPU::write(uint16_t data
, Addr addr
, unsigned flags
, uint64_t *res
);
565 SimpleCPU::write(uint8_t data
, Addr addr
, unsigned flags
, uint64_t *res
);
567 #endif //DOXYGEN_SHOULD_SKIP_THIS
571 SimpleCPU::write(double data
, Addr addr
, unsigned flags
, uint64_t *res
)
573 return write(*(uint64_t*)&data
, addr
, flags
, res
);
578 SimpleCPU::write(float data
, Addr addr
, unsigned flags
, uint64_t *res
)
580 return write(*(uint32_t*)&data
, addr
, flags
, res
);
586 SimpleCPU::write(int32_t data
, Addr addr
, unsigned flags
, uint64_t *res
)
588 return write((uint32_t)data
, addr
, flags
, res
);
594 SimpleCPU::dbg_vtophys(Addr addr
)
596 return vtophys(xcProxy
, addr
);
598 #endif // FULL_SYSTEM
601 SimpleCPU::processCacheCompletion()
604 case IcacheMissStall
:
605 icacheStallCycles
+= curTick
- lastIcacheStall
;
606 _status
= IcacheMissComplete
;
607 scheduleTickEvent(1);
609 case DcacheMissStall
:
610 if (memReq
->cmd
.isRead()) {
611 curStaticInst
->execute(this,traceData
);
613 traceData
->finalize();
615 dcacheStallCycles
+= curTick
- lastDcacheStall
;
617 scheduleTickEvent(1);
619 case DcacheMissSwitch
:
620 if (memReq
->cmd
.isRead()) {
621 curStaticInst
->execute(this,traceData
);
623 traceData
->finalize();
625 _status
= SwitchedOut
;
626 sampler
->signalSwitched();
628 // If this CPU has been switched out due to sampling/warm-up,
629 // ignore any further status changes (e.g., due to cache
630 // misses outstanding at the time of the switch).
633 panic("SimpleCPU::processCacheCompletion: bad state");
640 SimpleCPU::post_interrupt(int int_num
, int index
)
642 BaseCPU::post_interrupt(int_num
, index
);
644 if (cpuXC
->status() == ExecContext::Suspended
) {
645 DPRINTF(IPI
,"Suspended Processor awoke\n");
649 #endif // FULL_SYSTEM
651 /* start simulation, program loaded, processor precise state initialized */
659 Fault fault
= NoFault
;
662 if (checkInterrupts
&& check_interrupts() && !cpuXC
->inPalMode() &&
663 status() != IcacheMissComplete
) {
666 checkInterrupts
= false;
668 if (cpuXC
->readMiscReg(IPR_SIRR
)) {
669 for (int i
= INTLEVEL_SOFTWARE_MIN
;
670 i
< INTLEVEL_SOFTWARE_MAX
; i
++) {
671 if (cpuXC
->readMiscReg(IPR_SIRR
) & (ULL(1) << i
)) {
672 // See table 4-19 of 21164 hardware reference
673 ipl
= (i
- INTLEVEL_SOFTWARE_MIN
) + 1;
674 summary
|= (ULL(1) << i
);
679 uint64_t interrupts
= cpuXC
->cpu
->intr_status();
680 for (int i
= INTLEVEL_EXTERNAL_MIN
;
681 i
< INTLEVEL_EXTERNAL_MAX
; i
++) {
682 if (interrupts
& (ULL(1) << i
)) {
683 // See table 4-19 of 21164 hardware reference
685 summary
|= (ULL(1) << i
);
689 if (cpuXC
->readMiscReg(IPR_ASTRR
))
690 panic("asynchronous traps not implemented\n");
692 if (ipl
&& ipl
> cpuXC
->readMiscReg(IPR_IPLR
)) {
693 cpuXC
->setMiscReg(IPR_ISR
, summary
);
694 cpuXC
->setMiscReg(IPR_INTID
, ipl
);
696 Fault(new InterruptFault
)->invoke(xcProxy
);
698 DPRINTF(Flow
, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
699 cpuXC
->readMiscReg(IPR_IPLR
), ipl
, summary
);
704 // maintain $r0 semantics
705 cpuXC
->setIntReg(ZeroReg
, 0);
707 cpuXC
->setFloatRegDouble(ZeroReg
, 0.0);
708 #endif // TARGET_ALPHA
710 if (status() == IcacheMissComplete
) {
711 // We've already fetched an instruction and were stalled on an
712 // I-cache miss. No need to fetch it again.
714 // Set status to running; tick event will get rescheduled if
715 // necessary at end of tick() function.
719 // Try to fetch an instruction
721 // set up memory request for instruction fetch
723 #define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0
725 #define IFETCH_FLAGS(pc) 0
729 memReq
->reset(cpuXC
->readPC() & ~3, sizeof(uint32_t),
730 IFETCH_FLAGS(cpuXC
->readPC()));
732 fault
= cpuXC
->translateInstReq(memReq
);
734 if (fault
== NoFault
)
735 fault
= cpuXC
->mem
->read(memReq
, inst
);
737 if (icacheInterface
&& fault
== NoFault
) {
738 memReq
->completionEvent
= NULL
;
740 memReq
->time
= curTick
;
741 memReq
->flags
|= INST_READ
;
742 MemAccessResult result
= icacheInterface
->access(memReq
);
744 // Ugly hack to get an event scheduled *only* if the access is
745 // a miss. We really should add first-class support for this
747 if (result
!= MA_HIT
&& icacheInterface
->doEvents()) {
748 memReq
->completionEvent
= &cacheCompletionEvent
;
749 lastIcacheStall
= curTick
;
750 unscheduleTickEvent();
751 _status
= IcacheMissStall
;
757 // If we've got a valid instruction (i.e., no fault on instruction
758 // fetch), then execute it.
759 if (fault
== NoFault
) {
761 // keep an instruction count
765 // check for instruction-count-based events
766 comInstEventQueue
[0]->serviceEvents(numInst
);
768 // decode the instruction
770 curStaticInst
= StaticInst::decode(makeExtMI(inst
, cpuXC
->readPC()));
772 traceData
= Trace::getInstRecord(curTick
, xcProxy
, this, curStaticInst
,
776 cpuXC
->setInst(inst
);
777 #endif // FULL_SYSTEM
779 cpuXC
->func_exe_inst
++;
781 fault
= curStaticInst
->execute(this, traceData
);
784 if (system
->kernelBinning
->fnbin
) {
785 assert(cpuXC
->getKernelStats());
786 system
->kernelBinning
->execute(xcProxy
, inst
);
789 if (cpuXC
->profile
) {
791 (cpuXC
->readMiscReg(AlphaISA::IPR_DTB_CM
) & 0x18) != 0;
792 cpuXC
->profilePC
= usermode
? 1 : cpuXC
->readPC();
793 ProfileNode
*node
= cpuXC
->profile
->consume(xcProxy
, inst
);
795 cpuXC
->profileNode
= node
;
799 if (curStaticInst
->isMemRef()) {
803 if (curStaticInst
->isLoad()) {
805 comLoadEventQueue
[0]->serviceEvents(numLoad
);
808 // If we have a dcache miss, then we can't finialize the instruction
809 // trace yet because we want to populate it with the data later
811 !(status() == DcacheMissStall
&& memReq
->cmd
.isRead())) {
812 traceData
->finalize();
815 traceFunctions(cpuXC
->readPC());
817 } // if (fault == NoFault)
819 if (fault
!= NoFault
) {
821 fault
->invoke(xcProxy
);
822 #else // !FULL_SYSTEM
823 fatal("fault (%d) detected @ PC 0x%08p", fault
, cpuXC
->readPC());
824 #endif // FULL_SYSTEM
827 #if THE_ISA != MIPS_ISA
828 // go to the next instruction
829 cpuXC
->setPC(cpuXC
->readNextPC());
830 cpuXC
->setNextPC(cpuXC
->readNextPC() + sizeof(MachInst
));
832 // go to the next instruction
833 cpuXC
->setPC(cpuXC
->readNextPC());
834 cpuXC
->setNextPC(cpuXC
->readNextNPC());
835 cpuXC
->setNextNPC(cpuXC
->readNextNPC() + sizeof(MachInst
));
843 oldpc
= cpuXC
->readPC();
844 system
->pcEventQueue
.service(xcProxy
);
845 } while (oldpc
!= cpuXC
->readPC());
848 assert(status() == Running
||
850 status() == DcacheMissStall
);
852 if (status() == Running
&& !tickEvent
.scheduled())
853 tickEvent
.schedule(curTick
+ cycles(1));
856 ////////////////////////////////////////////////////////////////////////
858 // SimpleCPU Simulation Object
860 BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU
)
862 Param
<Counter
> max_insts_any_thread
;
863 Param
<Counter
> max_insts_all_threads
;
864 Param
<Counter
> max_loads_any_thread
;
865 Param
<Counter
> max_loads_all_threads
;
866 Param
<Tick
> progress_interval
;
869 SimObjectParam
<AlphaITB
*> itb
;
870 SimObjectParam
<AlphaDTB
*> dtb
;
871 SimObjectParam
<FunctionalMemory
*> mem
;
872 SimObjectParam
<System
*> system
;
876 SimObjectParam
<Process
*> workload
;
877 #endif // FULL_SYSTEM
880 SimObjectParam
<BaseMem
*> icache
;
881 SimObjectParam
<BaseMem
*> dcache
;
883 Param
<bool> defer_registration
;
885 Param
<bool> function_trace
;
886 Param
<Tick
> function_trace_start
;
888 END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU
)
890 BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU
)
892 INIT_PARAM(max_insts_any_thread
,
893 "terminate when any thread reaches this inst count"),
894 INIT_PARAM(max_insts_all_threads
,
895 "terminate when all threads have reached this inst count"),
896 INIT_PARAM(max_loads_any_thread
,
897 "terminate when any thread reaches this load count"),
898 INIT_PARAM(max_loads_all_threads
,
899 "terminate when all threads have reached this load count"),
900 INIT_PARAM_DFLT(progress_interval
, "CPU Progress interval", 0),
903 INIT_PARAM(itb
, "Instruction TLB"),
904 INIT_PARAM(dtb
, "Data TLB"),
905 INIT_PARAM(mem
, "memory"),
906 INIT_PARAM(system
, "system object"),
907 INIT_PARAM(cpu_id
, "processor ID"),
908 INIT_PARAM(profile
, ""),
910 INIT_PARAM(workload
, "processes to run"),
911 #endif // FULL_SYSTEM
913 INIT_PARAM(clock
, "clock speed"),
914 INIT_PARAM(icache
, "L1 instruction cache object"),
915 INIT_PARAM(dcache
, "L1 data cache object"),
916 INIT_PARAM(defer_registration
, "defer system registration (for sampling)"),
917 INIT_PARAM(width
, "cpu width"),
918 INIT_PARAM(function_trace
, "Enable function trace"),
919 INIT_PARAM(function_trace_start
, "Cycle to start function trace")
921 END_INIT_SIM_OBJECT_PARAMS(SimpleCPU
)
924 CREATE_SIM_OBJECT(SimpleCPU
)
926 SimpleCPU::Params
*params
= new SimpleCPU::Params();
927 params
->name
= getInstanceName();
928 params
->numberOfThreads
= 1;
929 params
->max_insts_any_thread
= max_insts_any_thread
;
930 params
->max_insts_all_threads
= max_insts_all_threads
;
931 params
->max_loads_any_thread
= max_loads_any_thread
;
932 params
->max_loads_all_threads
= max_loads_all_threads
;
933 params
->deferRegistration
= defer_registration
;
934 params
->clock
= clock
;
935 params
->functionTrace
= function_trace
;
936 params
->functionTraceStart
= function_trace_start
;
937 params
->icache_interface
= (icache
) ? icache
->getInterface() : NULL
;
938 params
->dcache_interface
= (dcache
) ? dcache
->getInterface() : NULL
;
939 params
->width
= width
;
941 params
->progress_interval
= progress_interval
;
946 params
->system
= system
;
947 params
->cpu_id
= cpu_id
;
948 params
->profile
= profile
;
950 params
->process
= workload
;
953 SimpleCPU
*cpu
= new SimpleCPU(params
);
957 REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU
)