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/exec_context.hh"
48 #include "cpu/exetrace.hh"
49 #include "cpu/profile.hh"
50 #include "cpu/sampler/sampler.hh"
51 #include "cpu/simple/cpu.hh"
53 #include "cpu/static_inst.hh"
54 #include "kern/kernel_stats.hh"
55 #include "mem/base_mem.hh"
56 #include "mem/mem_interface.hh"
57 #include "sim/builder.hh"
58 #include "sim/debug.hh"
59 #include "sim/host.hh"
60 #include "sim/sim_events.hh"
61 #include "sim/sim_object.hh"
62 #include "sim/stats.hh"
65 #include "base/remote_gdb.hh"
66 #include "mem/functional/memory_control.hh"
67 #include "mem/functional/physical.hh"
68 #include "sim/system.hh"
69 #include "targetarch/alpha_memory.hh"
70 #include "targetarch/stacktrace.hh"
71 #include "targetarch/vtophys.hh"
73 #include "mem/functional/functional.hh"
79 SimpleCPU::TickEvent::TickEvent(SimpleCPU
*c
, int w
)
80 : Event(&mainEventQueue
, CPU_Tick_Pri
), cpu(c
), width(w
)
85 SimpleCPU::TickEvent::process()
90 } while (--count
> 0 && cpu
->status() == Running
);
94 SimpleCPU::TickEvent::description()
96 return "SimpleCPU tick event";
100 SimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU
*_cpu
)
101 : Event(&mainEventQueue
), cpu(_cpu
)
105 void SimpleCPU::CacheCompletionEvent::process()
107 cpu
->processCacheCompletion();
111 SimpleCPU::CacheCompletionEvent::description()
113 return "SimpleCPU cache completion event";
116 SimpleCPU::SimpleCPU(Params
*p
)
117 : BaseCPU(p
), tickEvent(this, p
->width
), xc(NULL
),
118 cacheCompletionEvent(this)
122 xc
= new ExecContext(this, 0, p
->system
, p
->itb
, p
->dtb
, p
->mem
);
124 // initialize CPU, including PC
125 TheISA::initCPU(&xc
->regs
);
127 xc
= new ExecContext(this, /* thread_num */ 0, p
->process
, /* asid */ 0);
128 #endif // !FULL_SYSTEM
130 icacheInterface
= p
->icache_interface
;
131 dcacheInterface
= p
->dcache_interface
;
133 memReq
= new MemReq();
136 memReq
->data
= new uint8_t[64];
145 execContexts
.push_back(xc
);
148 SimpleCPU::~SimpleCPU()
153 SimpleCPU::switchOut(Sampler
*s
)
156 if (status() == DcacheMissStall
) {
157 DPRINTF(Sampler
,"Outstanding dcache access, waiting for completion\n");
158 _status
= DcacheMissSwitch
;
161 _status
= SwitchedOut
;
163 if (tickEvent
.scheduled())
166 sampler
->signalSwitched();
172 SimpleCPU::takeOverFrom(BaseCPU
*oldCPU
)
174 BaseCPU::takeOverFrom(oldCPU
);
176 assert(!tickEvent
.scheduled());
178 // if any of this CPU's ExecContexts are active, mark the CPU as
179 // running and schedule its tick event.
180 for (int i
= 0; i
< execContexts
.size(); ++i
) {
181 ExecContext
*xc
= execContexts
[i
];
182 if (xc
->status() == ExecContext::Active
&& _status
!= Running
) {
184 tickEvent
.schedule(curTick
);
191 SimpleCPU::activateContext(int thread_num
, int delay
)
193 assert(thread_num
== 0);
196 assert(_status
== Idle
);
198 scheduleTickEvent(delay
);
204 SimpleCPU::suspendContext(int thread_num
)
206 assert(thread_num
== 0);
209 assert(_status
== Running
);
211 unscheduleTickEvent();
217 SimpleCPU::deallocateContext(int thread_num
)
219 // for now, these are equivalent
220 suspendContext(thread_num
);
225 SimpleCPU::haltContext(int thread_num
)
227 // for now, these are equivalent
228 suspendContext(thread_num
);
233 SimpleCPU::regStats()
235 using namespace Stats
;
240 .name(name() + ".num_insts")
241 .desc("Number of instructions executed")
245 .name(name() + ".num_refs")
246 .desc("Number of memory references")
250 .name(name() + ".not_idle_fraction")
251 .desc("Percentage of non-idle cycles")
255 .name(name() + ".idle_fraction")
256 .desc("Percentage of idle cycles")
260 .name(name() + ".icache_stall_cycles")
261 .desc("ICache total stall cycles")
262 .prereq(icacheStallCycles
)
266 .name(name() + ".dcache_stall_cycles")
267 .desc("DCache total stall cycles")
268 .prereq(dcacheStallCycles
)
271 idleFraction
= constant(1.0) - notIdleFraction
;
275 SimpleCPU::resetStats()
277 startNumInst
= numInst
;
278 notIdleFraction
= (_status
!= Idle
);
282 SimpleCPU::serialize(ostream
&os
)
284 BaseCPU::serialize(os
);
285 SERIALIZE_ENUM(_status
);
286 SERIALIZE_SCALAR(inst
);
287 nameOut(os
, csprintf("%s.xc", name()));
289 nameOut(os
, csprintf("%s.tickEvent", name()));
290 tickEvent
.serialize(os
);
291 nameOut(os
, csprintf("%s.cacheCompletionEvent", name()));
292 cacheCompletionEvent
.serialize(os
);
296 SimpleCPU::unserialize(Checkpoint
*cp
, const string
§ion
)
298 BaseCPU::unserialize(cp
, section
);
299 UNSERIALIZE_ENUM(_status
);
300 UNSERIALIZE_SCALAR(inst
);
301 xc
->unserialize(cp
, csprintf("%s.xc", section
));
302 tickEvent
.unserialize(cp
, csprintf("%s.tickEvent", section
));
304 .unserialize(cp
, csprintf("%s.cacheCompletionEvent", section
));
308 change_thread_state(int thread_number
, int activate
, int priority
)
313 SimpleCPU::copySrcTranslate(Addr src
)
315 static bool no_warn
= true;
316 int blk_size
= (dcacheInterface
) ? dcacheInterface
->getBlockSize() : 64;
317 // Only support block sizes of 64 atm.
318 assert(blk_size
== 64);
319 int offset
= src
& (blk_size
- 1);
321 // Make sure block doesn't span page
323 (src
& TheISA::PageMask
) != ((src
+ blk_size
) & TheISA::PageMask
) &&
324 (src
>> 40) != 0xfffffc) {
325 warn("Copied block source spans pages %x.", src
);
329 memReq
->reset(src
& ~(blk_size
- 1), blk_size
);
331 // translate to physical address
332 Fault fault
= xc
->translateDataReadReq(memReq
);
334 assert(fault
!= Alignment_Fault
);
336 if (fault
== No_Fault
) {
337 xc
->copySrcAddr
= src
;
338 xc
->copySrcPhysAddr
= memReq
->paddr
+ offset
;
341 xc
->copySrcPhysAddr
= 0;
347 SimpleCPU::copy(Addr dest
)
349 static bool no_warn
= true;
350 int blk_size
= (dcacheInterface
) ? dcacheInterface
->getBlockSize() : 64;
351 // Only support block sizes of 64 atm.
352 assert(blk_size
== 64);
353 uint8_t data
[blk_size
];
354 //assert(xc->copySrcAddr);
355 int offset
= dest
& (blk_size
- 1);
357 // Make sure block doesn't span page
359 (dest
& TheISA::PageMask
) != ((dest
+ blk_size
) & TheISA::PageMask
) &&
360 (dest
>> 40) != 0xfffffc) {
362 warn("Copied block destination spans pages %x. ", dest
);
365 memReq
->reset(dest
& ~(blk_size
-1), blk_size
);
366 // translate to physical address
367 Fault fault
= xc
->translateDataWriteReq(memReq
);
369 assert(fault
!= Alignment_Fault
);
371 if (fault
== No_Fault
) {
372 Addr dest_addr
= memReq
->paddr
+ offset
;
373 // Need to read straight from memory since we have more than 8 bytes.
374 memReq
->paddr
= xc
->copySrcPhysAddr
;
375 xc
->mem
->read(memReq
, data
);
376 memReq
->paddr
= dest_addr
;
377 xc
->mem
->write(memReq
, data
);
378 if (dcacheInterface
) {
380 memReq
->completionEvent
= NULL
;
381 memReq
->paddr
= xc
->copySrcPhysAddr
;
382 memReq
->dest
= dest_addr
;
384 memReq
->time
= curTick
;
385 dcacheInterface
->access(memReq
);
391 // precise architected memory state accessor macros
394 SimpleCPU::read(Addr addr
, T
&data
, unsigned flags
)
396 if (status() == DcacheMissStall
|| status() == DcacheMissSwitch
) {
397 Fault fault
= xc
->read(memReq
,data
);
400 traceData
->setAddr(addr
);
405 memReq
->reset(addr
, sizeof(T
), flags
);
407 // translate to physical address
408 Fault fault
= xc
->translateDataReadReq(memReq
);
410 // if we have a cache, do cache access too
411 if (fault
== No_Fault
&& dcacheInterface
) {
413 memReq
->completionEvent
= NULL
;
414 memReq
->time
= curTick
;
415 MemAccessResult result
= dcacheInterface
->access(memReq
);
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
420 if (result
!= MA_HIT
&& dcacheInterface
->doEvents()) {
421 memReq
->completionEvent
= &cacheCompletionEvent
;
422 lastDcacheStall
= curTick
;
423 unscheduleTickEvent();
424 _status
= DcacheMissStall
;
426 // do functional access
427 fault
= xc
->read(memReq
, data
);
430 } else if(fault
== No_Fault
) {
431 // do functional access
432 fault
= xc
->read(memReq
, data
);
436 if (!dcacheInterface
&& (memReq
->flags
& UNCACHEABLE
))
437 recordEvent("Uncached Read");
442 #ifndef DOXYGEN_SHOULD_SKIP_THIS
446 SimpleCPU::read(Addr addr
, uint64_t &data
, unsigned flags
);
450 SimpleCPU::read(Addr addr
, uint32_t &data
, unsigned flags
);
454 SimpleCPU::read(Addr addr
, uint16_t &data
, unsigned flags
);
458 SimpleCPU::read(Addr addr
, uint8_t &data
, unsigned flags
);
460 #endif //DOXYGEN_SHOULD_SKIP_THIS
464 SimpleCPU::read(Addr addr
, double &data
, unsigned flags
)
466 return read(addr
, *(uint64_t*)&data
, flags
);
471 SimpleCPU::read(Addr addr
, float &data
, unsigned flags
)
473 return read(addr
, *(uint32_t*)&data
, flags
);
479 SimpleCPU::read(Addr addr
, int32_t &data
, unsigned flags
)
481 return read(addr
, (uint32_t&)data
, flags
);
487 SimpleCPU::write(T data
, Addr addr
, unsigned flags
, uint64_t *res
)
489 memReq
->reset(addr
, sizeof(T
), flags
);
491 // translate to physical address
492 Fault fault
= xc
->translateDataWriteReq(memReq
);
494 // do functional access
495 if (fault
== No_Fault
)
496 fault
= xc
->write(memReq
, data
);
498 if (fault
== No_Fault
&& dcacheInterface
) {
500 memcpy(memReq
->data
,(uint8_t *)&data
,memReq
->size
);
501 memReq
->completionEvent
= NULL
;
502 memReq
->time
= curTick
;
503 MemAccessResult result
= dcacheInterface
->access(memReq
);
505 // Ugly hack to get an event scheduled *only* if the access is
506 // a miss. We really should add first-class support for this
508 if (result
!= MA_HIT
&& dcacheInterface
->doEvents()) {
509 memReq
->completionEvent
= &cacheCompletionEvent
;
510 lastDcacheStall
= curTick
;
511 unscheduleTickEvent();
512 _status
= DcacheMissStall
;
516 if (res
&& (fault
== No_Fault
))
517 *res
= memReq
->result
;
519 if (!dcacheInterface
&& (memReq
->flags
& UNCACHEABLE
))
520 recordEvent("Uncached Write");
526 #ifndef DOXYGEN_SHOULD_SKIP_THIS
529 SimpleCPU::write(uint64_t data
, Addr addr
, unsigned flags
, uint64_t *res
);
533 SimpleCPU::write(uint32_t data
, Addr addr
, unsigned flags
, uint64_t *res
);
537 SimpleCPU::write(uint16_t data
, Addr addr
, unsigned flags
, uint64_t *res
);
541 SimpleCPU::write(uint8_t data
, Addr addr
, unsigned flags
, uint64_t *res
);
543 #endif //DOXYGEN_SHOULD_SKIP_THIS
547 SimpleCPU::write(double data
, Addr addr
, unsigned flags
, uint64_t *res
)
549 return write(*(uint64_t*)&data
, addr
, flags
, res
);
554 SimpleCPU::write(float data
, Addr addr
, unsigned flags
, uint64_t *res
)
556 return write(*(uint32_t*)&data
, addr
, flags
, res
);
562 SimpleCPU::write(int32_t data
, Addr addr
, unsigned flags
, uint64_t *res
)
564 return write((uint32_t)data
, addr
, flags
, res
);
570 SimpleCPU::dbg_vtophys(Addr addr
)
572 return vtophys(xc
, addr
);
574 #endif // FULL_SYSTEM
577 SimpleCPU::processCacheCompletion()
580 case IcacheMissStall
:
581 icacheStallCycles
+= curTick
- lastIcacheStall
;
582 _status
= IcacheMissComplete
;
583 scheduleTickEvent(1);
585 case DcacheMissStall
:
586 if (memReq
->cmd
.isRead()) {
587 curStaticInst
->execute(this,traceData
);
589 traceData
->finalize();
591 dcacheStallCycles
+= curTick
- lastDcacheStall
;
593 scheduleTickEvent(1);
595 case DcacheMissSwitch
:
596 if (memReq
->cmd
.isRead()) {
597 curStaticInst
->execute(this,traceData
);
599 traceData
->finalize();
601 _status
= SwitchedOut
;
602 sampler
->signalSwitched();
604 // If this CPU has been switched out due to sampling/warm-up,
605 // ignore any further status changes (e.g., due to cache
606 // misses outstanding at the time of the switch).
609 panic("SimpleCPU::processCacheCompletion: bad state");
616 SimpleCPU::post_interrupt(int int_num
, int index
)
618 BaseCPU::post_interrupt(int_num
, index
);
620 if (xc
->status() == ExecContext::Suspended
) {
621 DPRINTF(IPI
,"Suspended Processor awoke\n");
625 #endif // FULL_SYSTEM
627 /* start simulation, program loaded, processor precise state initialized */
635 Fault fault
= No_Fault
;
638 if (checkInterrupts
&& check_interrupts() && !xc
->inPalMode() &&
639 status() != IcacheMissComplete
) {
642 checkInterrupts
= false;
643 IntReg
*ipr
= xc
->regs
.ipr
;
645 if (xc
->regs
.ipr
[TheISA::IPR_SIRR
]) {
646 for (int i
= TheISA::INTLEVEL_SOFTWARE_MIN
;
647 i
< TheISA::INTLEVEL_SOFTWARE_MAX
; i
++) {
648 if (ipr
[TheISA::IPR_SIRR
] & (ULL(1) << i
)) {
649 // See table 4-19 of 21164 hardware reference
650 ipl
= (i
- TheISA::INTLEVEL_SOFTWARE_MIN
) + 1;
651 summary
|= (ULL(1) << i
);
656 uint64_t interrupts
= xc
->cpu
->intr_status();
657 for (int i
= TheISA::INTLEVEL_EXTERNAL_MIN
;
658 i
< TheISA::INTLEVEL_EXTERNAL_MAX
; i
++) {
659 if (interrupts
& (ULL(1) << i
)) {
660 // See table 4-19 of 21164 hardware reference
662 summary
|= (ULL(1) << i
);
666 if (ipr
[TheISA::IPR_ASTRR
])
667 panic("asynchronous traps not implemented\n");
669 if (ipl
&& ipl
> xc
->regs
.ipr
[TheISA::IPR_IPLR
]) {
670 ipr
[TheISA::IPR_ISR
] = summary
;
671 ipr
[TheISA::IPR_INTID
] = ipl
;
672 xc
->ev5_trap(Interrupt_Fault
);
674 DPRINTF(Flow
, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
675 ipr
[TheISA::IPR_IPLR
], ipl
, summary
);
680 // maintain $r0 semantics
681 xc
->regs
.intRegFile
[ZeroReg
] = 0;
683 xc
->regs
.floatRegFile
.d
[ZeroReg
] = 0.0;
684 #endif // TARGET_ALPHA
686 if (status() == IcacheMissComplete
) {
687 // We've already fetched an instruction and were stalled on an
688 // I-cache miss. No need to fetch it again.
690 // Set status to running; tick event will get rescheduled if
691 // necessary at end of tick() function.
695 // Try to fetch an instruction
697 // set up memory request for instruction fetch
699 #define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0
701 #define IFETCH_FLAGS(pc) 0
705 memReq
->reset(xc
->regs
.pc
& ~3, sizeof(uint32_t),
706 IFETCH_FLAGS(xc
->regs
.pc
));
708 fault
= xc
->translateInstReq(memReq
);
710 if (fault
== No_Fault
)
711 fault
= xc
->mem
->read(memReq
, inst
);
713 if (icacheInterface
&& fault
== No_Fault
) {
714 memReq
->completionEvent
= NULL
;
716 memReq
->time
= curTick
;
717 MemAccessResult result
= icacheInterface
->access(memReq
);
719 // Ugly hack to get an event scheduled *only* if the access is
720 // a miss. We really should add first-class support for this
722 if (result
!= MA_HIT
&& icacheInterface
->doEvents()) {
723 memReq
->completionEvent
= &cacheCompletionEvent
;
724 lastIcacheStall
= curTick
;
725 unscheduleTickEvent();
726 _status
= IcacheMissStall
;
732 // If we've got a valid instruction (i.e., no fault on instruction
733 // fetch), then execute it.
734 if (fault
== No_Fault
) {
736 // keep an instruction count
740 // check for instruction-count-based events
741 comInstEventQueue
[0]->serviceEvents(numInst
);
743 // decode the instruction
745 curStaticInst
= StaticInst
<TheISA
>::decode(inst
);
747 traceData
= Trace::getInstRecord(curTick
, xc
, this, curStaticInst
,
752 #endif // FULL_SYSTEM
756 fault
= curStaticInst
->execute(this, traceData
);
760 assert(xc
->kernelStats
);
761 system
->kernelBinning
->execute(xc
, inst
);
765 bool usermode
= (xc
->regs
.ipr
[AlphaISA::IPR_DTB_CM
] & 0x18) != 0;
766 xc
->profilePC
= usermode
? 1 : xc
->regs
.pc
;
767 ProfileNode
*node
= xc
->profile
->consume(xc
, inst
);
769 xc
->profileNode
= node
;
773 if (curStaticInst
->isMemRef()) {
777 if (curStaticInst
->isLoad()) {
779 comLoadEventQueue
[0]->serviceEvents(numLoad
);
782 // If we have a dcache miss, then we can't finialize the instruction
783 // trace yet because we want to populate it with the data later
785 !(status() == DcacheMissStall
&& memReq
->cmd
.isRead())) {
786 traceData
->finalize();
789 traceFunctions(xc
->regs
.pc
);
791 } // if (fault == No_Fault)
793 if (fault
!= No_Fault
) {
796 #else // !FULL_SYSTEM
797 fatal("fault (%d) detected @ PC 0x%08p", fault
, xc
->regs
.pc
);
798 #endif // FULL_SYSTEM
801 // go to the next instruction
802 xc
->regs
.pc
= xc
->regs
.npc
;
803 xc
->regs
.npc
+= sizeof(MachInst
);
810 system
->pcEventQueue
.service(xc
);
811 } while (oldpc
!= xc
->regs
.pc
);
814 assert(status() == Running
||
816 status() == DcacheMissStall
);
818 if (status() == Running
&& !tickEvent
.scheduled())
819 tickEvent
.schedule(curTick
+ cycles(1));
822 ////////////////////////////////////////////////////////////////////////
824 // SimpleCPU Simulation Object
826 BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU
)
828 Param
<Counter
> max_insts_any_thread
;
829 Param
<Counter
> max_insts_all_threads
;
830 Param
<Counter
> max_loads_any_thread
;
831 Param
<Counter
> max_loads_all_threads
;
834 SimObjectParam
<AlphaITB
*> itb
;
835 SimObjectParam
<AlphaDTB
*> dtb
;
836 SimObjectParam
<FunctionalMemory
*> mem
;
837 SimObjectParam
<System
*> system
;
841 SimObjectParam
<Process
*> workload
;
842 #endif // FULL_SYSTEM
845 SimObjectParam
<BaseMem
*> icache
;
846 SimObjectParam
<BaseMem
*> dcache
;
848 Param
<bool> defer_registration
;
850 Param
<bool> function_trace
;
851 Param
<Tick
> function_trace_start
;
853 END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU
)
855 BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU
)
857 INIT_PARAM(max_insts_any_thread
,
858 "terminate when any thread reaches this inst count"),
859 INIT_PARAM(max_insts_all_threads
,
860 "terminate when all threads have reached this inst count"),
861 INIT_PARAM(max_loads_any_thread
,
862 "terminate when any thread reaches this load count"),
863 INIT_PARAM(max_loads_all_threads
,
864 "terminate when all threads have reached this load count"),
867 INIT_PARAM(itb
, "Instruction TLB"),
868 INIT_PARAM(dtb
, "Data TLB"),
869 INIT_PARAM(mem
, "memory"),
870 INIT_PARAM(system
, "system object"),
871 INIT_PARAM(cpu_id
, "processor ID"),
872 INIT_PARAM(profile
, ""),
874 INIT_PARAM(workload
, "processes to run"),
875 #endif // FULL_SYSTEM
877 INIT_PARAM(clock
, "clock speed"),
878 INIT_PARAM(icache
, "L1 instruction cache object"),
879 INIT_PARAM(dcache
, "L1 data cache object"),
880 INIT_PARAM(defer_registration
, "defer system registration (for sampling)"),
881 INIT_PARAM(width
, "cpu width"),
882 INIT_PARAM(function_trace
, "Enable function trace"),
883 INIT_PARAM(function_trace_start
, "Cycle to start function trace")
885 END_INIT_SIM_OBJECT_PARAMS(SimpleCPU
)
888 CREATE_SIM_OBJECT(SimpleCPU
)
890 SimpleCPU::Params
*params
= new SimpleCPU::Params();
891 params
->name
= getInstanceName();
892 params
->numberOfThreads
= 1;
893 params
->max_insts_any_thread
= max_insts_any_thread
;
894 params
->max_insts_all_threads
= max_insts_all_threads
;
895 params
->max_loads_any_thread
= max_loads_any_thread
;
896 params
->max_loads_all_threads
= max_loads_all_threads
;
897 params
->deferRegistration
= defer_registration
;
898 params
->clock
= clock
;
899 params
->functionTrace
= function_trace
;
900 params
->functionTraceStart
= function_trace_start
;
901 params
->icache_interface
= (icache
) ? icache
->getInterface() : NULL
;
902 params
->dcache_interface
= (dcache
) ? dcache
->getInterface() : NULL
;
903 params
->width
= width
;
909 params
->system
= system
;
910 params
->cpu_id
= cpu_id
;
911 params
->profile
= profile
;
913 params
->process
= workload
;
916 SimpleCPU
*cpu
= new SimpleCPU(params
);
920 REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU
)