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