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