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