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