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