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