Merge
[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/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 Fault
331 SimpleCPU::copySrcTranslate(Addr src)
332 {
333 memReq->reset(src, (dcacheInterface) ?
334 dcacheInterface->getBlockSize()
335 : 64);
336
337 // translate to physical address
338 Fault fault = xc->translateDataReadReq(memReq);
339
340 if (fault == No_Fault) {
341 xc->copySrcAddr = src;
342 xc->copySrcPhysAddr = memReq->paddr;
343 } else {
344 xc->copySrcAddr = 0;
345 xc->copySrcPhysAddr = 0;
346 }
347 return fault;
348 }
349
350 Fault
351 SimpleCPU::copy(Addr dest)
352 {
353 int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
354 uint8_t data[blk_size];
355 assert(xc->copySrcPhysAddr);
356 memReq->reset(dest, blk_size);
357 // translate to physical address
358 Fault fault = xc->translateDataWriteReq(memReq);
359 if (fault == No_Fault) {
360 Addr dest_addr = memReq->paddr;
361 // Need to read straight from memory since we have more than 8 bytes.
362 memReq->paddr = xc->copySrcPhysAddr;
363 xc->mem->read(memReq, data);
364 memReq->paddr = dest_addr;
365 xc->mem->write(memReq, data);
366 }
367 return fault;
368 }
369
370 // precise architected memory state accessor macros
371 template <class T>
372 Fault
373 SimpleCPU::read(Addr addr, T &data, unsigned flags)
374 {
375 memReq->reset(addr, sizeof(T), flags);
376
377 // translate to physical address
378 Fault fault = xc->translateDataReadReq(memReq);
379
380 // do functional access
381 if (fault == No_Fault)
382 fault = xc->read(memReq, data);
383
384 if (traceData) {
385 traceData->setAddr(addr);
386 if (fault == No_Fault)
387 traceData->setData(data);
388 }
389
390 // if we have a cache, do cache access too
391 if (fault == No_Fault && dcacheInterface) {
392 memReq->cmd = Read;
393 memReq->completionEvent = NULL;
394 memReq->time = curTick;
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 lastDcacheStall = curTick;
403 unscheduleTickEvent();
404 _status = DcacheMissStall;
405 }
406 }
407
408 return fault;
409 }
410
411 #ifndef DOXYGEN_SHOULD_SKIP_THIS
412
413 template
414 Fault
415 SimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
416
417 template
418 Fault
419 SimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
420
421 template
422 Fault
423 SimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
424
425 template
426 Fault
427 SimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
428
429 #endif //DOXYGEN_SHOULD_SKIP_THIS
430
431 template<>
432 Fault
433 SimpleCPU::read(Addr addr, double &data, unsigned flags)
434 {
435 return read(addr, *(uint64_t*)&data, flags);
436 }
437
438 template<>
439 Fault
440 SimpleCPU::read(Addr addr, float &data, unsigned flags)
441 {
442 return read(addr, *(uint32_t*)&data, flags);
443 }
444
445
446 template<>
447 Fault
448 SimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
449 {
450 return read(addr, (uint32_t&)data, flags);
451 }
452
453
454 template <class T>
455 Fault
456 SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
457 {
458 if (traceData) {
459 traceData->setAddr(addr);
460 traceData->setData(data);
461 }
462
463 memReq->reset(addr, sizeof(T), flags);
464
465 // translate to physical address
466 Fault fault = xc->translateDataWriteReq(memReq);
467
468 // do functional access
469 if (fault == No_Fault)
470 fault = xc->write(memReq, data);
471
472 if (fault == No_Fault && dcacheInterface) {
473 memReq->cmd = Write;
474 memcpy(memReq->data,(uint8_t *)&data,memReq->size);
475 memReq->completionEvent = NULL;
476 memReq->time = curTick;
477 MemAccessResult result = dcacheInterface->access(memReq);
478
479 // Ugly hack to get an event scheduled *only* if the access is
480 // a miss. We really should add first-class support for this
481 // at some point.
482 if (result != MA_HIT && dcacheInterface->doEvents()) {
483 memReq->completionEvent = &cacheCompletionEvent;
484 lastDcacheStall = curTick;
485 unscheduleTickEvent();
486 _status = DcacheMissStall;
487 }
488 }
489
490 if (res && (fault == No_Fault))
491 *res = memReq->result;
492
493 return fault;
494 }
495
496
497 #ifndef DOXYGEN_SHOULD_SKIP_THIS
498 template
499 Fault
500 SimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res);
501
502 template
503 Fault
504 SimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res);
505
506 template
507 Fault
508 SimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res);
509
510 template
511 Fault
512 SimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res);
513
514 #endif //DOXYGEN_SHOULD_SKIP_THIS
515
516 template<>
517 Fault
518 SimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
519 {
520 return write(*(uint64_t*)&data, addr, flags, res);
521 }
522
523 template<>
524 Fault
525 SimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
526 {
527 return write(*(uint32_t*)&data, addr, flags, res);
528 }
529
530
531 template<>
532 Fault
533 SimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
534 {
535 return write((uint32_t)data, addr, flags, res);
536 }
537
538
539 #ifdef FULL_SYSTEM
540 Addr
541 SimpleCPU::dbg_vtophys(Addr addr)
542 {
543 return vtophys(xc, addr);
544 }
545 #endif // FULL_SYSTEM
546
547 Tick save_cycle = 0;
548
549
550 void
551 SimpleCPU::processCacheCompletion()
552 {
553 switch (status()) {
554 case IcacheMissStall:
555 icacheStallCycles += curTick - lastIcacheStall;
556 _status = IcacheMissComplete;
557 scheduleTickEvent(1);
558 break;
559 case DcacheMissStall:
560 dcacheStallCycles += curTick - lastDcacheStall;
561 _status = Running;
562 scheduleTickEvent(1);
563 break;
564 case SwitchedOut:
565 // If this CPU has been switched out due to sampling/warm-up,
566 // ignore any further status changes (e.g., due to cache
567 // misses outstanding at the time of the switch).
568 return;
569 default:
570 panic("SimpleCPU::processCacheCompletion: bad state");
571 break;
572 }
573 }
574
575 #ifdef FULL_SYSTEM
576 void
577 SimpleCPU::post_interrupt(int int_num, int index)
578 {
579 BaseCPU::post_interrupt(int_num, index);
580
581 if (xc->status() == ExecContext::Suspended) {
582 DPRINTF(IPI,"Suspended Processor awoke\n");
583 xc->activate();
584 Annotate::Resume(xc);
585 }
586 }
587 #endif // FULL_SYSTEM
588
589 /* start simulation, program loaded, processor precise state initialized */
590 void
591 SimpleCPU::tick()
592 {
593 traceData = NULL;
594
595 Fault fault = No_Fault;
596
597 #ifdef FULL_SYSTEM
598 if (AlphaISA::check_interrupts &&
599 xc->cpu->check_interrupts() &&
600 !PC_PAL(xc->regs.pc) &&
601 status() != IcacheMissComplete) {
602 int ipl = 0;
603 int summary = 0;
604 AlphaISA::check_interrupts = 0;
605 IntReg *ipr = xc->regs.ipr;
606
607 if (xc->regs.ipr[TheISA::IPR_SIRR]) {
608 for (int i = TheISA::INTLEVEL_SOFTWARE_MIN;
609 i < TheISA::INTLEVEL_SOFTWARE_MAX; i++) {
610 if (ipr[TheISA::IPR_SIRR] & (ULL(1) << i)) {
611 // See table 4-19 of 21164 hardware reference
612 ipl = (i - TheISA::INTLEVEL_SOFTWARE_MIN) + 1;
613 summary |= (ULL(1) << i);
614 }
615 }
616 }
617
618 uint64_t interrupts = xc->cpu->intr_status();
619 for (int i = TheISA::INTLEVEL_EXTERNAL_MIN;
620 i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) {
621 if (interrupts & (ULL(1) << i)) {
622 // See table 4-19 of 21164 hardware reference
623 ipl = i;
624 summary |= (ULL(1) << i);
625 }
626 }
627
628 if (ipr[TheISA::IPR_ASTRR])
629 panic("asynchronous traps not implemented\n");
630
631 if (ipl && ipl > xc->regs.ipr[TheISA::IPR_IPLR]) {
632 ipr[TheISA::IPR_ISR] = summary;
633 ipr[TheISA::IPR_INTID] = ipl;
634 xc->ev5_trap(Interrupt_Fault);
635
636 DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
637 ipr[TheISA::IPR_IPLR], ipl, summary);
638 }
639 }
640 #endif
641
642 // maintain $r0 semantics
643 xc->regs.intRegFile[ZeroReg] = 0;
644 #ifdef TARGET_ALPHA
645 xc->regs.floatRegFile.d[ZeroReg] = 0.0;
646 #endif // TARGET_ALPHA
647
648 if (status() == IcacheMissComplete) {
649 // We've already fetched an instruction and were stalled on an
650 // I-cache miss. No need to fetch it again.
651
652 // Set status to running; tick event will get rescheduled if
653 // necessary at end of tick() function.
654 _status = Running;
655 }
656 else {
657 // Try to fetch an instruction
658
659 // set up memory request for instruction fetch
660 #ifdef FULL_SYSTEM
661 #define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0
662 #else
663 #define IFETCH_FLAGS(pc) 0
664 #endif
665
666 memReq->cmd = Read;
667 memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t),
668 IFETCH_FLAGS(xc->regs.pc));
669
670 fault = xc->translateInstReq(memReq);
671
672 if (fault == No_Fault)
673 fault = xc->mem->read(memReq, inst);
674
675 if (icacheInterface && fault == No_Fault) {
676 memReq->completionEvent = NULL;
677
678 memReq->time = curTick;
679 MemAccessResult result = icacheInterface->access(memReq);
680
681 // Ugly hack to get an event scheduled *only* if the access is
682 // a miss. We really should add first-class support for this
683 // at some point.
684 if (result != MA_HIT && icacheInterface->doEvents()) {
685 memReq->completionEvent = &cacheCompletionEvent;
686 lastIcacheStall = curTick;
687 unscheduleTickEvent();
688 _status = IcacheMissStall;
689 return;
690 }
691 }
692 }
693
694 // If we've got a valid instruction (i.e., no fault on instruction
695 // fetch), then execute it.
696 if (fault == No_Fault) {
697
698 // keep an instruction count
699 numInst++;
700
701 // check for instruction-count-based events
702 comInstEventQueue[0]->serviceEvents(numInst);
703
704 // decode the instruction
705 StaticInstPtr<TheISA> si(inst);
706
707 traceData = Trace::getInstRecord(curTick, xc, this, si,
708 xc->regs.pc);
709
710 #ifdef FULL_SYSTEM
711 xc->regs.opcode = (inst >> 26) & 0x3f;
712 xc->regs.ra = (inst >> 21) & 0x1f;
713 #endif // FULL_SYSTEM
714
715 xc->func_exe_inst++;
716
717 fault = si->execute(this, xc, traceData);
718
719 #ifdef FULL_SYSTEM
720 SWContext *ctx = xc->swCtx;
721 if (ctx)
722 ctx->process(xc, si.get());
723 #endif
724
725 if (si->isMemRef()) {
726 numMemRefs++;
727 }
728
729 if (si->isLoad()) {
730 ++numLoad;
731 comLoadEventQueue[0]->serviceEvents(numLoad);
732 }
733
734 if (traceData)
735 traceData->finalize();
736
737 } // if (fault == No_Fault)
738
739 if (fault != No_Fault) {
740 #ifdef FULL_SYSTEM
741 xc->ev5_trap(fault);
742 #else // !FULL_SYSTEM
743 fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc);
744 #endif // FULL_SYSTEM
745 }
746 else {
747 // go to the next instruction
748 xc->regs.pc = xc->regs.npc;
749 xc->regs.npc += sizeof(MachInst);
750 }
751
752 #ifdef FULL_SYSTEM
753 Addr oldpc;
754 do {
755 oldpc = xc->regs.pc;
756 system->pcEventQueue.service(xc);
757 } while (oldpc != xc->regs.pc);
758 #endif
759
760 assert(status() == Running ||
761 status() == Idle ||
762 status() == DcacheMissStall);
763
764 if (status() == Running && !tickEvent.scheduled())
765 tickEvent.schedule(curTick + 1);
766 }
767
768
769 ////////////////////////////////////////////////////////////////////////
770 //
771 // SimpleCPU Simulation Object
772 //
773 BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
774
775 Param<Counter> max_insts_any_thread;
776 Param<Counter> max_insts_all_threads;
777 Param<Counter> max_loads_any_thread;
778 Param<Counter> max_loads_all_threads;
779
780 #ifdef FULL_SYSTEM
781 SimObjectParam<AlphaITB *> itb;
782 SimObjectParam<AlphaDTB *> dtb;
783 SimObjectParam<FunctionalMemory *> mem;
784 SimObjectParam<System *> system;
785 Param<int> mult;
786 #else
787 SimObjectParam<Process *> workload;
788 #endif // FULL_SYSTEM
789
790 SimObjectParam<BaseMem *> icache;
791 SimObjectParam<BaseMem *> dcache;
792
793 Param<bool> defer_registration;
794
795 END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
796
797 BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
798
799 INIT_PARAM_DFLT(max_insts_any_thread,
800 "terminate when any thread reaches this inst count",
801 0),
802 INIT_PARAM_DFLT(max_insts_all_threads,
803 "terminate when all threads have reached this inst count",
804 0),
805 INIT_PARAM_DFLT(max_loads_any_thread,
806 "terminate when any thread reaches this load count",
807 0),
808 INIT_PARAM_DFLT(max_loads_all_threads,
809 "terminate when all threads have reached this load count",
810 0),
811
812 #ifdef FULL_SYSTEM
813 INIT_PARAM(itb, "Instruction TLB"),
814 INIT_PARAM(dtb, "Data TLB"),
815 INIT_PARAM(mem, "memory"),
816 INIT_PARAM(system, "system object"),
817 INIT_PARAM_DFLT(mult, "system clock multiplier", 1),
818 #else
819 INIT_PARAM(workload, "processes to run"),
820 #endif // FULL_SYSTEM
821
822 INIT_PARAM_DFLT(icache, "L1 instruction cache object", NULL),
823 INIT_PARAM_DFLT(dcache, "L1 data cache object", NULL),
824 INIT_PARAM_DFLT(defer_registration, "defer registration with system "
825 "(for sampling)", false)
826
827 END_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
828
829
830 CREATE_SIM_OBJECT(SimpleCPU)
831 {
832 SimpleCPU *cpu;
833 #ifdef FULL_SYSTEM
834 if (mult != 1)
835 panic("processor clock multiplier must be 1\n");
836
837 cpu = new SimpleCPU(getInstanceName(), system,
838 max_insts_any_thread, max_insts_all_threads,
839 max_loads_any_thread, max_loads_all_threads,
840 itb, dtb, mem,
841 (icache) ? icache->getInterface() : NULL,
842 (dcache) ? dcache->getInterface() : NULL,
843 defer_registration,
844 ticksPerSecond * mult);
845 #else
846
847 cpu = new SimpleCPU(getInstanceName(), workload,
848 max_insts_any_thread, max_insts_all_threads,
849 max_loads_any_thread, max_loads_all_threads,
850 (icache) ? icache->getInterface() : NULL,
851 (dcache) ? dcache->getInterface() : NULL,
852 defer_registration);
853
854 #endif // FULL_SYSTEM
855
856 return cpu;
857 }
858
859 REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU)
860