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