Fix stats reset
[gem5.git] / cpu / simple_cpu / simple_cpu.cc
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/annotation.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/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 #include "sim/prog.hh"
74 #endif // FULL_SYSTEM
75
76 using namespace std;
77
78 SimpleCPU::TickEvent::TickEvent(SimpleCPU *c)
79 : Event(&mainEventQueue, 100), cpu(c)
80 {
81 }
82
83 void
84 SimpleCPU::TickEvent::process()
85 {
86 cpu->tick();
87 }
88
89 const char *
90 SimpleCPU::TickEvent::description()
91 {
92 return "SimpleCPU tick event";
93 }
94
95
96 SimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu)
97 : Event(&mainEventQueue),
98 cpu(_cpu)
99 {
100 }
101
102 void SimpleCPU::CacheCompletionEvent::process()
103 {
104 cpu->processCacheCompletion();
105 }
106
107 const char *
108 SimpleCPU::CacheCompletionEvent::description()
109 {
110 return "SimpleCPU cache completion event";
111 }
112
113 #ifdef FULL_SYSTEM
114 SimpleCPU::SimpleCPU(const string &_name,
115 System *_system,
116 Counter max_insts_any_thread,
117 Counter max_insts_all_threads,
118 Counter max_loads_any_thread,
119 Counter max_loads_all_threads,
120 AlphaItb *itb, AlphaDtb *dtb,
121 FunctionalMemory *mem,
122 MemInterface *icache_interface,
123 MemInterface *dcache_interface,
124 Tick freq)
125 : BaseCPU(_name, /* number_of_threads */ 1,
126 max_insts_any_thread, max_insts_all_threads,
127 max_loads_any_thread, max_loads_all_threads,
128 _system, freq),
129 #else
130 SimpleCPU::SimpleCPU(const string &_name, Process *_process,
131 Counter max_insts_any_thread,
132 Counter max_insts_all_threads,
133 Counter max_loads_any_thread,
134 Counter max_loads_all_threads,
135 MemInterface *icache_interface,
136 MemInterface *dcache_interface)
137 : BaseCPU(_name, /* number_of_threads */ 1,
138 max_insts_any_thread, max_insts_all_threads,
139 max_loads_any_thread, max_loads_all_threads),
140 #endif
141 tickEvent(this), xc(NULL), 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 numLoad = 0;
163 lastIcacheStall = 0;
164 lastDcacheStall = 0;
165
166 execContexts.push_back(xc);
167 }
168
169 SimpleCPU::~SimpleCPU()
170 {
171 }
172
173 void
174 SimpleCPU::switchOut()
175 {
176 _status = SwitchedOut;
177 if (tickEvent.scheduled())
178 tickEvent.squash();
179 }
180
181
182 void
183 SimpleCPU::takeOverFrom(BaseCPU *oldCPU)
184 {
185 BaseCPU::takeOverFrom(oldCPU);
186
187 assert(!tickEvent.scheduled());
188
189 // if any of this CPU's ExecContexts are active, mark the CPU as
190 // running and schedule its tick event.
191 for (int i = 0; i < execContexts.size(); ++i) {
192 ExecContext *xc = execContexts[i];
193 if (xc->status() == ExecContext::Active && _status != Running) {
194 _status = Running;
195 tickEvent.schedule(curTick);
196 }
197 }
198
199 oldCPU->switchOut();
200 }
201
202
203 void
204 SimpleCPU::execCtxStatusChg(int thread_num) {
205 assert(thread_num == 0);
206 assert(xc);
207
208 if (xc->status() == ExecContext::Active)
209 setStatus(Running);
210 else
211 setStatus(Idle);
212 }
213
214
215 void
216 SimpleCPU::regStats()
217 {
218 BaseCPU::regStats();
219
220 numInsts
221 .name(name() + ".num_insts")
222 .desc("Number of instructions executed")
223 ;
224
225 numMemRefs
226 .name(name() + ".num_refs")
227 .desc("Number of memory references")
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 numInsts = Statistics::scalar(numInst);
248 simInsts += numInsts;
249 }
250
251 void
252 SimpleCPU::serialize(ostream &os)
253 {
254 SERIALIZE_ENUM(_status);
255 SERIALIZE_SCALAR(inst);
256 nameOut(os, csprintf("%s.xc", name()));
257 xc->serialize(os);
258 nameOut(os, csprintf("%s.tickEvent", name()));
259 tickEvent.serialize(os);
260 nameOut(os, csprintf("%s.cacheCompletionEvent", name()));
261 cacheCompletionEvent.serialize(os);
262 }
263
264 void
265 SimpleCPU::unserialize(Checkpoint *cp, const string &section)
266 {
267 UNSERIALIZE_ENUM(_status);
268 UNSERIALIZE_SCALAR(inst);
269 xc->unserialize(cp, csprintf("%s.xc", section));
270 tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
271 cacheCompletionEvent
272 .unserialize(cp, csprintf("%s.cacheCompletionEvent", section));
273 }
274
275 void
276 change_thread_state(int thread_number, int activate, int priority)
277 {
278 }
279
280 // precise architected memory state accessor macros
281 template <class T>
282 Fault
283 SimpleCPU::read(Addr addr, T& data, unsigned flags)
284 {
285 memReq->reset(addr, sizeof(T), flags);
286
287 // translate to physical address
288 Fault fault = xc->translateDataReadReq(memReq);
289
290 // do functional access
291 if (fault == No_Fault)
292 fault = xc->read(memReq, data);
293
294 if (traceData) {
295 traceData->setAddr(addr);
296 if (fault == No_Fault)
297 traceData->setData(data);
298 }
299
300 // if we have a cache, do cache access too
301 if (fault == No_Fault && dcacheInterface) {
302 memReq->cmd = Read;
303 memReq->completionEvent = NULL;
304 memReq->time = curTick;
305 memReq->flags &= ~UNCACHEABLE;
306 MemAccessResult result = dcacheInterface->access(memReq);
307
308 // Ugly hack to get an event scheduled *only* if the access is
309 // a miss. We really should add first-class support for this
310 // at some point.
311 if (result != MA_HIT && dcacheInterface->doEvents) {
312 memReq->completionEvent = &cacheCompletionEvent;
313 setStatus(DcacheMissStall);
314 }
315 }
316
317 return fault;
318 }
319
320 #ifndef DOXYGEN_SHOULD_SKIP_THIS
321
322 template
323 Fault
324 SimpleCPU::read(Addr addr, uint64_t& data, unsigned flags);
325
326 template
327 Fault
328 SimpleCPU::read(Addr addr, uint32_t& data, unsigned flags);
329
330 template
331 Fault
332 SimpleCPU::read(Addr addr, uint16_t& data, unsigned flags);
333
334 template
335 Fault
336 SimpleCPU::read(Addr addr, uint8_t& data, unsigned flags);
337
338 #endif //DOXYGEN_SHOULD_SKIP_THIS
339
340 template<>
341 Fault
342 SimpleCPU::read(Addr addr, double& data, unsigned flags)
343 {
344 return read(addr, *(uint64_t*)&data, flags);
345 }
346
347 template<>
348 Fault
349 SimpleCPU::read(Addr addr, float& data, unsigned flags)
350 {
351 return read(addr, *(uint32_t*)&data, flags);
352 }
353
354
355 template<>
356 Fault
357 SimpleCPU::read(Addr addr, int32_t& data, unsigned flags)
358 {
359 return read(addr, (uint32_t&)data, flags);
360 }
361
362
363 template <class T>
364 Fault
365 SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
366 {
367 if (traceData) {
368 traceData->setAddr(addr);
369 traceData->setData(data);
370 }
371
372 memReq->reset(addr, sizeof(T), flags);
373
374 // translate to physical address
375 Fault fault = xc->translateDataWriteReq(memReq);
376
377 // do functional access
378 if (fault == No_Fault)
379 fault = xc->write(memReq, data);
380
381 if (fault == No_Fault && dcacheInterface) {
382 memReq->cmd = Write;
383 memcpy(memReq->data,(uint8_t *)&data,memReq->size);
384 memReq->completionEvent = NULL;
385 memReq->time = curTick;
386 memReq->flags &= ~UNCACHEABLE;
387 MemAccessResult result = dcacheInterface->access(memReq);
388
389 // Ugly hack to get an event scheduled *only* if the access is
390 // a miss. We really should add first-class support for this
391 // at some point.
392 if (result != MA_HIT && dcacheInterface->doEvents) {
393 memReq->completionEvent = &cacheCompletionEvent;
394 setStatus(DcacheMissStall);
395 }
396 }
397
398 if (res && (fault == No_Fault))
399 *res = memReq->result;
400
401 return fault;
402 }
403
404
405 #ifndef DOXYGEN_SHOULD_SKIP_THIS
406 template
407 Fault
408 SimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res);
409
410 template
411 Fault
412 SimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res);
413
414 template
415 Fault
416 SimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res);
417
418 template
419 Fault
420 SimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res);
421
422 #endif //DOXYGEN_SHOULD_SKIP_THIS
423
424 template<>
425 Fault
426 SimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
427 {
428 return write(*(uint64_t*)&data, addr, flags, res);
429 }
430
431 template<>
432 Fault
433 SimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
434 {
435 return write(*(uint32_t*)&data, addr, flags, res);
436 }
437
438
439 template<>
440 Fault
441 SimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
442 {
443 return write((uint32_t)data, addr, flags, res);
444 }
445
446
447 #ifdef FULL_SYSTEM
448 Addr
449 SimpleCPU::dbg_vtophys(Addr addr)
450 {
451 return vtophys(xc, addr);
452 }
453 #endif // FULL_SYSTEM
454
455 Tick save_cycle = 0;
456
457
458 void
459 SimpleCPU::processCacheCompletion()
460 {
461 switch (status()) {
462 case IcacheMissStall:
463 icacheStallCycles += curTick - lastIcacheStall;
464 setStatus(IcacheMissComplete);
465 break;
466 case DcacheMissStall:
467 dcacheStallCycles += curTick - lastDcacheStall;
468 setStatus(Running);
469 break;
470 case SwitchedOut:
471 // If this CPU has been switched out due to sampling/warm-up,
472 // ignore any further status changes (e.g., due to cache
473 // misses outstanding at the time of the switch).
474 return;
475 default:
476 panic("SimpleCPU::processCacheCompletion: bad state");
477 break;
478 }
479 }
480
481 #ifdef FULL_SYSTEM
482 void
483 SimpleCPU::post_interrupt(int int_num, int index)
484 {
485 BaseCPU::post_interrupt(int_num, index);
486
487 if (xc->status() == ExecContext::Suspended) {
488 DPRINTF(IPI,"Suspended Processor awoke\n");
489 xc->setStatus(ExecContext::Active);
490 Annotate::Resume(xc);
491 }
492 }
493 #endif // FULL_SYSTEM
494
495 /* start simulation, program loaded, processor precise state initialized */
496 void
497 SimpleCPU::tick()
498 {
499 traceData = NULL;
500
501 Fault fault = No_Fault;
502
503 #ifdef FULL_SYSTEM
504 if (AlphaISA::check_interrupts &&
505 xc->cpu->check_interrupts() &&
506 !PC_PAL(xc->regs.pc) &&
507 status() != IcacheMissComplete) {
508 int ipl = 0;
509 int summary = 0;
510 AlphaISA::check_interrupts = 0;
511 IntReg *ipr = xc->regs.ipr;
512
513 if (xc->regs.ipr[TheISA::IPR_SIRR]) {
514 for (int i = TheISA::INTLEVEL_SOFTWARE_MIN;
515 i < TheISA::INTLEVEL_SOFTWARE_MAX; i++) {
516 if (ipr[TheISA::IPR_SIRR] & (ULL(1) << i)) {
517 // See table 4-19 of 21164 hardware reference
518 ipl = (i - TheISA::INTLEVEL_SOFTWARE_MIN) + 1;
519 summary |= (ULL(1) << i);
520 }
521 }
522 }
523
524 uint64_t interrupts = xc->cpu->intr_status();
525 for (int i = TheISA::INTLEVEL_EXTERNAL_MIN;
526 i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) {
527 if (interrupts & (ULL(1) << i)) {
528 // See table 4-19 of 21164 hardware reference
529 ipl = i;
530 summary |= (ULL(1) << i);
531 }
532 }
533
534 if (ipr[TheISA::IPR_ASTRR])
535 panic("asynchronous traps not implemented\n");
536
537 if (ipl && ipl > xc->regs.ipr[TheISA::IPR_IPLR]) {
538 ipr[TheISA::IPR_ISR] = summary;
539 ipr[TheISA::IPR_INTID] = ipl;
540 xc->ev5_trap(Interrupt_Fault);
541
542 DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
543 ipr[TheISA::IPR_IPLR], ipl, summary);
544 }
545 }
546 #endif
547
548 // maintain $r0 semantics
549 xc->regs.intRegFile[ZeroReg] = 0;
550 #ifdef TARGET_ALPHA
551 xc->regs.floatRegFile.d[ZeroReg] = 0.0;
552 #endif // TARGET_ALPHA
553
554 if (status() == IcacheMissComplete) {
555 // We've already fetched an instruction and were stalled on an
556 // I-cache miss. No need to fetch it again.
557
558 setStatus(Running);
559 }
560 else {
561 // Try to fetch an instruction
562
563 // set up memory request for instruction fetch
564 #ifdef FULL_SYSTEM
565 #define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0
566 #else
567 #define IFETCH_FLAGS(pc) 0
568 #endif
569
570 memReq->cmd = Read;
571 memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t),
572 IFETCH_FLAGS(xc->regs.pc));
573
574 fault = xc->translateInstReq(memReq);
575
576 if (fault == No_Fault)
577 fault = xc->mem->read(memReq, inst);
578
579 if (icacheInterface && fault == No_Fault) {
580 memReq->completionEvent = NULL;
581
582 memReq->time = curTick;
583 memReq->flags &= ~UNCACHEABLE;
584 MemAccessResult result = icacheInterface->access(memReq);
585
586 // Ugly hack to get an event scheduled *only* if the access is
587 // a miss. We really should add first-class support for this
588 // at some point.
589 if (result != MA_HIT && icacheInterface->doEvents) {
590 memReq->completionEvent = &cacheCompletionEvent;
591 setStatus(IcacheMissStall);
592 return;
593 }
594 }
595 }
596
597 // If we've got a valid instruction (i.e., no fault on instruction
598 // fetch), then execute it.
599 if (fault == No_Fault) {
600
601 // keep an instruction count
602 numInst++;
603
604 // check for instruction-count-based events
605 comInsnEventQueue[0]->serviceEvents(numInst);
606
607 // decode the instruction
608 StaticInstPtr<TheISA> si(inst);
609
610 traceData = Trace::getInstRecord(curTick, xc, this, si,
611 xc->regs.pc);
612
613 #ifdef FULL_SYSTEM
614 xc->regs.opcode = (inst >> 26) & 0x3f;
615 xc->regs.ra = (inst >> 21) & 0x1f;
616 #endif // FULL_SYSTEM
617
618 xc->func_exe_insn++;
619
620 fault = si->execute(this, xc, traceData);
621 #ifdef FS_MEASURE
622 if (!(xc->misspeculating()) && (xc->system->bin)) {
623 SWContext *ctx = xc->swCtx;
624 if (ctx && !ctx->callStack.empty()) {
625 if (si->isCall()) {
626 ctx->calls++;
627 }
628 if (si->isReturn()) {
629 if (ctx->calls == 0) {
630 fnCall *top = ctx->callStack.top();
631 DPRINTF(TCPIP, "Removing %s from callstack.\n", top->name);
632 delete top;
633 ctx->callStack.pop();
634 if (ctx->callStack.empty())
635 xc->system->nonPath->activate();
636 else
637 ctx->callStack.top()->myBin->activate();
638
639 xc->system->dumpState(xc);
640 } else {
641 ctx->calls--;
642 }
643 }
644 }
645 }
646 #endif
647 if (si->isMemRef()) {
648 numMemRefs++;
649 }
650
651 if (si->isLoad()) {
652 ++numLoad;
653 comLoadEventQueue[0]->serviceEvents(numLoad);
654 }
655
656 if (traceData)
657 traceData->finalize();
658
659 } // if (fault == No_Fault)
660
661 if (fault != No_Fault) {
662 #ifdef FULL_SYSTEM
663 xc->ev5_trap(fault);
664 #else // !FULL_SYSTEM
665 fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc);
666 #endif // FULL_SYSTEM
667 }
668 else {
669 // go to the next instruction
670 xc->regs.pc = xc->regs.npc;
671 xc->regs.npc += sizeof(MachInst);
672 }
673
674 #ifdef FULL_SYSTEM
675 Addr oldpc;
676 do {
677 oldpc = xc->regs.pc;
678 system->pcEventQueue.service(xc);
679 } while (oldpc != xc->regs.pc);
680 #endif
681
682 assert(status() == Running ||
683 status() == Idle ||
684 status() == DcacheMissStall);
685
686 if (status() == Running && !tickEvent.scheduled())
687 tickEvent.schedule(curTick + 1);
688 }
689
690
691 ////////////////////////////////////////////////////////////////////////
692 //
693 // SimpleCPU Simulation Object
694 //
695 BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
696
697 Param<Counter> max_insts_any_thread;
698 Param<Counter> max_insts_all_threads;
699 Param<Counter> max_loads_any_thread;
700 Param<Counter> max_loads_all_threads;
701
702 #ifdef FULL_SYSTEM
703 SimObjectParam<AlphaItb *> itb;
704 SimObjectParam<AlphaDtb *> dtb;
705 SimObjectParam<FunctionalMemory *> mem;
706 SimObjectParam<System *> system;
707 Param<int> mult;
708 #else
709 SimObjectParam<Process *> workload;
710 #endif // FULL_SYSTEM
711
712 SimObjectParam<BaseMem *> icache;
713 SimObjectParam<BaseMem *> dcache;
714
715 Param<bool> defer_registration;
716
717 END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
718
719 BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
720
721 INIT_PARAM_DFLT(max_insts_any_thread,
722 "terminate when any thread reaches this insn count",
723 0),
724 INIT_PARAM_DFLT(max_insts_all_threads,
725 "terminate when all threads have reached this insn count",
726 0),
727 INIT_PARAM_DFLT(max_loads_any_thread,
728 "terminate when any thread reaches this load count",
729 0),
730 INIT_PARAM_DFLT(max_loads_all_threads,
731 "terminate when all threads have reached this load count",
732 0),
733
734 #ifdef FULL_SYSTEM
735 INIT_PARAM(itb, "Instruction TLB"),
736 INIT_PARAM(dtb, "Data TLB"),
737 INIT_PARAM(mem, "memory"),
738 INIT_PARAM(system, "system object"),
739 INIT_PARAM_DFLT(mult, "system clock multiplier", 1),
740 #else
741 INIT_PARAM(workload, "processes to run"),
742 #endif // FULL_SYSTEM
743
744 INIT_PARAM_DFLT(icache, "L1 instruction cache object", NULL),
745 INIT_PARAM_DFLT(dcache, "L1 data cache object", NULL),
746 INIT_PARAM_DFLT(defer_registration, "defer registration with system "
747 "(for sampling)", false)
748
749 END_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
750
751
752 CREATE_SIM_OBJECT(SimpleCPU)
753 {
754 SimpleCPU *cpu;
755 #ifdef FULL_SYSTEM
756 if (mult != 1)
757 panic("processor clock multiplier must be 1\n");
758
759 cpu = new SimpleCPU(getInstanceName(), system,
760 max_insts_any_thread, max_insts_all_threads,
761 max_loads_any_thread, max_loads_all_threads,
762 itb, dtb, mem,
763 (icache) ? icache->getInterface() : NULL,
764 (dcache) ? dcache->getInterface() : NULL,
765 ticksPerSecond * mult);
766 #else
767
768 cpu = new SimpleCPU(getInstanceName(), workload,
769 max_insts_any_thread, max_insts_all_threads,
770 max_loads_any_thread, max_loads_all_threads,
771 (icache) ? icache->getInterface() : NULL,
772 (dcache) ? dcache->getInterface() : NULL);
773
774 #endif // FULL_SYSTEM
775
776 if (!defer_registration) {
777 cpu->registerExecContexts();
778 }
779
780 return cpu;
781 }
782
783 REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU)