Fix the system clock at 1THz making 1 simulation tick = 1 ps
[gem5.git] / cpu / simple / cpu.cc
1 /*
2 * Copyright (c) 2002-2005 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/stats/events.hh"
45 #include "base/trace.hh"
46 #include "cpu/base.hh"
47 #include "cpu/exec_context.hh"
48 #include "cpu/exetrace.hh"
49 #include "cpu/profile.hh"
50 #include "cpu/sampler/sampler.hh"
51 #include "cpu/simple/cpu.hh"
52 #include "cpu/smt.hh"
53 #include "cpu/static_inst.hh"
54 #include "kern/kernel_stats.hh"
55 #include "mem/base_mem.hh"
56 #include "mem/mem_interface.hh"
57 #include "sim/builder.hh"
58 #include "sim/debug.hh"
59 #include "sim/host.hh"
60 #include "sim/sim_events.hh"
61 #include "sim/sim_object.hh"
62 #include "sim/stats.hh"
63
64 #if FULL_SYSTEM
65 #include "base/remote_gdb.hh"
66 #include "mem/functional/memory_control.hh"
67 #include "mem/functional/physical.hh"
68 #include "sim/system.hh"
69 #include "targetarch/alpha_memory.hh"
70 #include "targetarch/stacktrace.hh"
71 #include "targetarch/vtophys.hh"
72 #else // !FULL_SYSTEM
73 #include "mem/functional/functional.hh"
74 #endif // FULL_SYSTEM
75
76 using namespace std;
77
78
79 SimpleCPU::TickEvent::TickEvent(SimpleCPU *c, int w)
80 : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), width(w)
81 {
82 }
83
84 void
85 SimpleCPU::TickEvent::process()
86 {
87 int count = width;
88 do {
89 cpu->tick();
90 } while (--count > 0 && cpu->status() == Running);
91 }
92
93 const char *
94 SimpleCPU::TickEvent::description()
95 {
96 return "SimpleCPU tick event";
97 }
98
99
100 SimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu)
101 : Event(&mainEventQueue), cpu(_cpu)
102 {
103 }
104
105 void SimpleCPU::CacheCompletionEvent::process()
106 {
107 cpu->processCacheCompletion();
108 }
109
110 const char *
111 SimpleCPU::CacheCompletionEvent::description()
112 {
113 return "SimpleCPU cache completion event";
114 }
115
116 SimpleCPU::SimpleCPU(Params *p)
117 : BaseCPU(p), tickEvent(this, p->width), xc(NULL),
118 cacheCompletionEvent(this)
119 {
120 _status = Idle;
121 #if FULL_SYSTEM
122 xc = new ExecContext(this, 0, p->system, p->itb, p->dtb, p->mem);
123
124 // initialize CPU, including PC
125 TheISA::initCPU(&xc->regs);
126 #else
127 xc = new ExecContext(this, /* thread_num */ 0, p->process, /* asid */ 0);
128 #endif // !FULL_SYSTEM
129
130 icacheInterface = p->icache_interface;
131 dcacheInterface = p->dcache_interface;
132
133 memReq = new MemReq();
134 memReq->xc = xc;
135 memReq->asid = 0;
136 memReq->data = new uint8_t[64];
137
138 numInst = 0;
139 startNumInst = 0;
140 numLoad = 0;
141 startNumLoad = 0;
142 lastIcacheStall = 0;
143 lastDcacheStall = 0;
144
145 execContexts.push_back(xc);
146 }
147
148 SimpleCPU::~SimpleCPU()
149 {
150 }
151
152 void
153 SimpleCPU::switchOut(Sampler *s)
154 {
155 sampler = s;
156 if (status() == DcacheMissStall) {
157 DPRINTF(Sampler,"Outstanding dcache access, waiting for completion\n");
158 _status = DcacheMissSwitch;
159 }
160 else {
161 _status = SwitchedOut;
162
163 if (tickEvent.scheduled())
164 tickEvent.squash();
165
166 sampler->signalSwitched();
167 }
168 }
169
170
171 void
172 SimpleCPU::takeOverFrom(BaseCPU *oldCPU)
173 {
174 BaseCPU::takeOverFrom(oldCPU);
175
176 assert(!tickEvent.scheduled());
177
178 // if any of this CPU's ExecContexts are active, mark the CPU as
179 // running and schedule its tick event.
180 for (int i = 0; i < execContexts.size(); ++i) {
181 ExecContext *xc = execContexts[i];
182 if (xc->status() == ExecContext::Active && _status != Running) {
183 _status = Running;
184 tickEvent.schedule(curTick);
185 }
186 }
187 }
188
189
190 void
191 SimpleCPU::activateContext(int thread_num, int delay)
192 {
193 assert(thread_num == 0);
194 assert(xc);
195
196 assert(_status == Idle);
197 notIdleFraction++;
198 scheduleTickEvent(delay);
199 _status = Running;
200 }
201
202
203 void
204 SimpleCPU::suspendContext(int thread_num)
205 {
206 assert(thread_num == 0);
207 assert(xc);
208
209 assert(_status == Running);
210 notIdleFraction--;
211 unscheduleTickEvent();
212 _status = Idle;
213 }
214
215
216 void
217 SimpleCPU::deallocateContext(int thread_num)
218 {
219 // for now, these are equivalent
220 suspendContext(thread_num);
221 }
222
223
224 void
225 SimpleCPU::haltContext(int thread_num)
226 {
227 // for now, these are equivalent
228 suspendContext(thread_num);
229 }
230
231
232 void
233 SimpleCPU::regStats()
234 {
235 using namespace Stats;
236
237 BaseCPU::regStats();
238
239 numInsts
240 .name(name() + ".num_insts")
241 .desc("Number of instructions executed")
242 ;
243
244 numMemRefs
245 .name(name() + ".num_refs")
246 .desc("Number of memory references")
247 ;
248
249 notIdleFraction
250 .name(name() + ".not_idle_fraction")
251 .desc("Percentage of non-idle cycles")
252 ;
253
254 idleFraction
255 .name(name() + ".idle_fraction")
256 .desc("Percentage of idle cycles")
257 ;
258
259 icacheStallCycles
260 .name(name() + ".icache_stall_cycles")
261 .desc("ICache total stall cycles")
262 .prereq(icacheStallCycles)
263 ;
264
265 dcacheStallCycles
266 .name(name() + ".dcache_stall_cycles")
267 .desc("DCache total stall cycles")
268 .prereq(dcacheStallCycles)
269 ;
270
271 idleFraction = constant(1.0) - notIdleFraction;
272 }
273
274 void
275 SimpleCPU::resetStats()
276 {
277 startNumInst = numInst;
278 notIdleFraction = (_status != Idle);
279 }
280
281 void
282 SimpleCPU::serialize(ostream &os)
283 {
284 BaseCPU::serialize(os);
285 SERIALIZE_ENUM(_status);
286 SERIALIZE_SCALAR(inst);
287 nameOut(os, csprintf("%s.xc", name()));
288 xc->serialize(os);
289 nameOut(os, csprintf("%s.tickEvent", name()));
290 tickEvent.serialize(os);
291 nameOut(os, csprintf("%s.cacheCompletionEvent", name()));
292 cacheCompletionEvent.serialize(os);
293 }
294
295 void
296 SimpleCPU::unserialize(Checkpoint *cp, const string &section)
297 {
298 BaseCPU::unserialize(cp, section);
299 UNSERIALIZE_ENUM(_status);
300 UNSERIALIZE_SCALAR(inst);
301 xc->unserialize(cp, csprintf("%s.xc", section));
302 tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
303 cacheCompletionEvent
304 .unserialize(cp, csprintf("%s.cacheCompletionEvent", section));
305 }
306
307 void
308 change_thread_state(int thread_number, int activate, int priority)
309 {
310 }
311
312 Fault
313 SimpleCPU::copySrcTranslate(Addr src)
314 {
315 static bool no_warn = true;
316 int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
317 // Only support block sizes of 64 atm.
318 assert(blk_size == 64);
319 int offset = src & (blk_size - 1);
320
321 // Make sure block doesn't span page
322 if (no_warn &&
323 (src & TheISA::PageMask) != ((src + blk_size) & TheISA::PageMask) &&
324 (src >> 40) != 0xfffffc) {
325 warn("Copied block source spans pages %x.", src);
326 no_warn = false;
327 }
328
329 memReq->reset(src & ~(blk_size - 1), blk_size);
330
331 // translate to physical address
332 Fault fault = xc->translateDataReadReq(memReq);
333
334 assert(fault != Alignment_Fault);
335
336 if (fault == No_Fault) {
337 xc->copySrcAddr = src;
338 xc->copySrcPhysAddr = memReq->paddr + offset;
339 } else {
340 xc->copySrcAddr = 0;
341 xc->copySrcPhysAddr = 0;
342 }
343 return fault;
344 }
345
346 Fault
347 SimpleCPU::copy(Addr dest)
348 {
349 static bool no_warn = true;
350 int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
351 // Only support block sizes of 64 atm.
352 assert(blk_size == 64);
353 uint8_t data[blk_size];
354 //assert(xc->copySrcAddr);
355 int offset = dest & (blk_size - 1);
356
357 // Make sure block doesn't span page
358 if (no_warn &&
359 (dest & TheISA::PageMask) != ((dest + blk_size) & TheISA::PageMask) &&
360 (dest >> 40) != 0xfffffc) {
361 no_warn = false;
362 warn("Copied block destination spans pages %x. ", dest);
363 }
364
365 memReq->reset(dest & ~(blk_size -1), blk_size);
366 // translate to physical address
367 Fault fault = xc->translateDataWriteReq(memReq);
368
369 assert(fault != Alignment_Fault);
370
371 if (fault == No_Fault) {
372 Addr dest_addr = memReq->paddr + offset;
373 // Need to read straight from memory since we have more than 8 bytes.
374 memReq->paddr = xc->copySrcPhysAddr;
375 xc->mem->read(memReq, data);
376 memReq->paddr = dest_addr;
377 xc->mem->write(memReq, data);
378 if (dcacheInterface) {
379 memReq->cmd = Copy;
380 memReq->completionEvent = NULL;
381 memReq->paddr = xc->copySrcPhysAddr;
382 memReq->dest = dest_addr;
383 memReq->size = 64;
384 memReq->time = curTick;
385 dcacheInterface->access(memReq);
386 }
387 }
388 return fault;
389 }
390
391 // precise architected memory state accessor macros
392 template <class T>
393 Fault
394 SimpleCPU::read(Addr addr, T &data, unsigned flags)
395 {
396 if (status() == DcacheMissStall || status() == DcacheMissSwitch) {
397 Fault fault = xc->read(memReq,data);
398
399 if (traceData) {
400 traceData->setAddr(addr);
401 }
402 return fault;
403 }
404
405 memReq->reset(addr, sizeof(T), flags);
406
407 // translate to physical address
408 Fault fault = xc->translateDataReadReq(memReq);
409
410 // if we have a cache, do cache access too
411 if (fault == No_Fault && dcacheInterface) {
412 memReq->cmd = Read;
413 memReq->completionEvent = NULL;
414 memReq->time = curTick;
415 MemAccessResult result = dcacheInterface->access(memReq);
416
417 // Ugly hack to get an event scheduled *only* if the access is
418 // a miss. We really should add first-class support for this
419 // at some point.
420 if (result != MA_HIT && dcacheInterface->doEvents()) {
421 memReq->completionEvent = &cacheCompletionEvent;
422 lastDcacheStall = curTick;
423 unscheduleTickEvent();
424 _status = DcacheMissStall;
425 } else {
426 // do functional access
427 fault = xc->read(memReq, data);
428
429 }
430 } else if(fault == No_Fault) {
431 // do functional access
432 fault = xc->read(memReq, data);
433
434 }
435
436 if (!dcacheInterface && (memReq->flags & UNCACHEABLE))
437 recordEvent("Uncached Read");
438
439 return fault;
440 }
441
442 #ifndef DOXYGEN_SHOULD_SKIP_THIS
443
444 template
445 Fault
446 SimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
447
448 template
449 Fault
450 SimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
451
452 template
453 Fault
454 SimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
455
456 template
457 Fault
458 SimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
459
460 #endif //DOXYGEN_SHOULD_SKIP_THIS
461
462 template<>
463 Fault
464 SimpleCPU::read(Addr addr, double &data, unsigned flags)
465 {
466 return read(addr, *(uint64_t*)&data, flags);
467 }
468
469 template<>
470 Fault
471 SimpleCPU::read(Addr addr, float &data, unsigned flags)
472 {
473 return read(addr, *(uint32_t*)&data, flags);
474 }
475
476
477 template<>
478 Fault
479 SimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
480 {
481 return read(addr, (uint32_t&)data, flags);
482 }
483
484
485 template <class T>
486 Fault
487 SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
488 {
489 memReq->reset(addr, sizeof(T), flags);
490
491 // translate to physical address
492 Fault fault = xc->translateDataWriteReq(memReq);
493
494 // do functional access
495 if (fault == No_Fault)
496 fault = xc->write(memReq, data);
497
498 if (fault == No_Fault && dcacheInterface) {
499 memReq->cmd = Write;
500 memcpy(memReq->data,(uint8_t *)&data,memReq->size);
501 memReq->completionEvent = NULL;
502 memReq->time = curTick;
503 MemAccessResult result = dcacheInterface->access(memReq);
504
505 // Ugly hack to get an event scheduled *only* if the access is
506 // a miss. We really should add first-class support for this
507 // at some point.
508 if (result != MA_HIT && dcacheInterface->doEvents()) {
509 memReq->completionEvent = &cacheCompletionEvent;
510 lastDcacheStall = curTick;
511 unscheduleTickEvent();
512 _status = DcacheMissStall;
513 }
514 }
515
516 if (res && (fault == No_Fault))
517 *res = memReq->result;
518
519 if (!dcacheInterface && (memReq->flags & UNCACHEABLE))
520 recordEvent("Uncached Write");
521
522 return fault;
523 }
524
525
526 #ifndef DOXYGEN_SHOULD_SKIP_THIS
527 template
528 Fault
529 SimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res);
530
531 template
532 Fault
533 SimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res);
534
535 template
536 Fault
537 SimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res);
538
539 template
540 Fault
541 SimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res);
542
543 #endif //DOXYGEN_SHOULD_SKIP_THIS
544
545 template<>
546 Fault
547 SimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
548 {
549 return write(*(uint64_t*)&data, addr, flags, res);
550 }
551
552 template<>
553 Fault
554 SimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
555 {
556 return write(*(uint32_t*)&data, addr, flags, res);
557 }
558
559
560 template<>
561 Fault
562 SimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
563 {
564 return write((uint32_t)data, addr, flags, res);
565 }
566
567
568 #if FULL_SYSTEM
569 Addr
570 SimpleCPU::dbg_vtophys(Addr addr)
571 {
572 return vtophys(xc, addr);
573 }
574 #endif // FULL_SYSTEM
575
576 void
577 SimpleCPU::processCacheCompletion()
578 {
579 switch (status()) {
580 case IcacheMissStall:
581 icacheStallCycles += curTick - lastIcacheStall;
582 _status = IcacheMissComplete;
583 scheduleTickEvent(1);
584 break;
585 case DcacheMissStall:
586 if (memReq->cmd.isRead()) {
587 curStaticInst->execute(this,traceData);
588 if (traceData)
589 traceData->finalize();
590 }
591 dcacheStallCycles += curTick - lastDcacheStall;
592 _status = Running;
593 scheduleTickEvent(1);
594 break;
595 case DcacheMissSwitch:
596 if (memReq->cmd.isRead()) {
597 curStaticInst->execute(this,traceData);
598 if (traceData)
599 traceData->finalize();
600 }
601 _status = SwitchedOut;
602 sampler->signalSwitched();
603 case SwitchedOut:
604 // If this CPU has been switched out due to sampling/warm-up,
605 // ignore any further status changes (e.g., due to cache
606 // misses outstanding at the time of the switch).
607 return;
608 default:
609 panic("SimpleCPU::processCacheCompletion: bad state");
610 break;
611 }
612 }
613
614 #if FULL_SYSTEM
615 void
616 SimpleCPU::post_interrupt(int int_num, int index)
617 {
618 BaseCPU::post_interrupt(int_num, index);
619
620 if (xc->status() == ExecContext::Suspended) {
621 DPRINTF(IPI,"Suspended Processor awoke\n");
622 xc->activate();
623 }
624 }
625 #endif // FULL_SYSTEM
626
627 /* start simulation, program loaded, processor precise state initialized */
628 void
629 SimpleCPU::tick()
630 {
631 numCycles++;
632
633 traceData = NULL;
634
635 Fault fault = No_Fault;
636
637 #if FULL_SYSTEM
638 if (checkInterrupts && check_interrupts() && !xc->inPalMode() &&
639 status() != IcacheMissComplete) {
640 int ipl = 0;
641 int summary = 0;
642 checkInterrupts = false;
643 IntReg *ipr = xc->regs.ipr;
644
645 if (xc->regs.ipr[TheISA::IPR_SIRR]) {
646 for (int i = TheISA::INTLEVEL_SOFTWARE_MIN;
647 i < TheISA::INTLEVEL_SOFTWARE_MAX; i++) {
648 if (ipr[TheISA::IPR_SIRR] & (ULL(1) << i)) {
649 // See table 4-19 of 21164 hardware reference
650 ipl = (i - TheISA::INTLEVEL_SOFTWARE_MIN) + 1;
651 summary |= (ULL(1) << i);
652 }
653 }
654 }
655
656 uint64_t interrupts = xc->cpu->intr_status();
657 for (int i = TheISA::INTLEVEL_EXTERNAL_MIN;
658 i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) {
659 if (interrupts & (ULL(1) << i)) {
660 // See table 4-19 of 21164 hardware reference
661 ipl = i;
662 summary |= (ULL(1) << i);
663 }
664 }
665
666 if (ipr[TheISA::IPR_ASTRR])
667 panic("asynchronous traps not implemented\n");
668
669 if (ipl && ipl > xc->regs.ipr[TheISA::IPR_IPLR]) {
670 ipr[TheISA::IPR_ISR] = summary;
671 ipr[TheISA::IPR_INTID] = ipl;
672 xc->ev5_trap(Interrupt_Fault);
673
674 DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
675 ipr[TheISA::IPR_IPLR], ipl, summary);
676 }
677 }
678 #endif
679
680 // maintain $r0 semantics
681 xc->regs.intRegFile[ZeroReg] = 0;
682 #ifdef TARGET_ALPHA
683 xc->regs.floatRegFile.d[ZeroReg] = 0.0;
684 #endif // TARGET_ALPHA
685
686 if (status() == IcacheMissComplete) {
687 // We've already fetched an instruction and were stalled on an
688 // I-cache miss. No need to fetch it again.
689
690 // Set status to running; tick event will get rescheduled if
691 // necessary at end of tick() function.
692 _status = Running;
693 }
694 else {
695 // Try to fetch an instruction
696
697 // set up memory request for instruction fetch
698 #if FULL_SYSTEM
699 #define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0
700 #else
701 #define IFETCH_FLAGS(pc) 0
702 #endif
703
704 memReq->cmd = Read;
705 memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t),
706 IFETCH_FLAGS(xc->regs.pc));
707
708 fault = xc->translateInstReq(memReq);
709
710 if (fault == No_Fault)
711 fault = xc->mem->read(memReq, inst);
712
713 if (icacheInterface && fault == No_Fault) {
714 memReq->completionEvent = NULL;
715
716 memReq->time = curTick;
717 MemAccessResult result = icacheInterface->access(memReq);
718
719 // Ugly hack to get an event scheduled *only* if the access is
720 // a miss. We really should add first-class support for this
721 // at some point.
722 if (result != MA_HIT && icacheInterface->doEvents()) {
723 memReq->completionEvent = &cacheCompletionEvent;
724 lastIcacheStall = curTick;
725 unscheduleTickEvent();
726 _status = IcacheMissStall;
727 return;
728 }
729 }
730 }
731
732 // If we've got a valid instruction (i.e., no fault on instruction
733 // fetch), then execute it.
734 if (fault == No_Fault) {
735
736 // keep an instruction count
737 numInst++;
738 numInsts++;
739
740 // check for instruction-count-based events
741 comInstEventQueue[0]->serviceEvents(numInst);
742
743 // decode the instruction
744 inst = gtoh(inst);
745 curStaticInst = StaticInst<TheISA>::decode(inst);
746
747 traceData = Trace::getInstRecord(curTick, xc, this, curStaticInst,
748 xc->regs.pc);
749
750 #if FULL_SYSTEM
751 xc->setInst(inst);
752 #endif // FULL_SYSTEM
753
754 xc->func_exe_inst++;
755
756 fault = curStaticInst->execute(this, traceData);
757
758 #if FULL_SYSTEM
759 if (xc->fnbin) {
760 assert(xc->kernelStats);
761 system->kernelBinning->execute(xc, inst);
762 }
763
764 if (xc->profile) {
765 bool usermode = (xc->regs.ipr[AlphaISA::IPR_DTB_CM] & 0x18) != 0;
766 xc->profilePC = usermode ? 1 : xc->regs.pc;
767 ProfileNode *node = xc->profile->consume(xc, inst);
768 if (node)
769 xc->profileNode = node;
770 }
771 #endif
772
773 if (curStaticInst->isMemRef()) {
774 numMemRefs++;
775 }
776
777 if (curStaticInst->isLoad()) {
778 ++numLoad;
779 comLoadEventQueue[0]->serviceEvents(numLoad);
780 }
781
782 // If we have a dcache miss, then we can't finialize the instruction
783 // trace yet because we want to populate it with the data later
784 if (traceData &&
785 !(status() == DcacheMissStall && memReq->cmd.isRead())) {
786 traceData->finalize();
787 }
788
789 traceFunctions(xc->regs.pc);
790
791 } // if (fault == No_Fault)
792
793 if (fault != No_Fault) {
794 #if FULL_SYSTEM
795 xc->ev5_trap(fault);
796 #else // !FULL_SYSTEM
797 fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc);
798 #endif // FULL_SYSTEM
799 }
800 else {
801 // go to the next instruction
802 xc->regs.pc = xc->regs.npc;
803 xc->regs.npc += sizeof(MachInst);
804 }
805
806 #if FULL_SYSTEM
807 Addr oldpc;
808 do {
809 oldpc = xc->regs.pc;
810 system->pcEventQueue.service(xc);
811 } while (oldpc != xc->regs.pc);
812 #endif
813
814 assert(status() == Running ||
815 status() == Idle ||
816 status() == DcacheMissStall);
817
818 if (status() == Running && !tickEvent.scheduled())
819 tickEvent.schedule(curTick + cycles(1));
820 }
821
822 ////////////////////////////////////////////////////////////////////////
823 //
824 // SimpleCPU Simulation Object
825 //
826 BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
827
828 Param<Counter> max_insts_any_thread;
829 Param<Counter> max_insts_all_threads;
830 Param<Counter> max_loads_any_thread;
831 Param<Counter> max_loads_all_threads;
832
833 #if FULL_SYSTEM
834 SimObjectParam<AlphaITB *> itb;
835 SimObjectParam<AlphaDTB *> dtb;
836 SimObjectParam<FunctionalMemory *> mem;
837 SimObjectParam<System *> system;
838 Param<int> cpu_id;
839 Param<Tick> profile;
840 #else
841 SimObjectParam<Process *> workload;
842 #endif // FULL_SYSTEM
843
844 Param<int> clock;
845 SimObjectParam<BaseMem *> icache;
846 SimObjectParam<BaseMem *> dcache;
847
848 Param<bool> defer_registration;
849 Param<int> width;
850 Param<bool> function_trace;
851 Param<Tick> function_trace_start;
852
853 END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
854
855 BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
856
857 INIT_PARAM(max_insts_any_thread,
858 "terminate when any thread reaches this inst count"),
859 INIT_PARAM(max_insts_all_threads,
860 "terminate when all threads have reached this inst count"),
861 INIT_PARAM(max_loads_any_thread,
862 "terminate when any thread reaches this load count"),
863 INIT_PARAM(max_loads_all_threads,
864 "terminate when all threads have reached this load count"),
865
866 #if FULL_SYSTEM
867 INIT_PARAM(itb, "Instruction TLB"),
868 INIT_PARAM(dtb, "Data TLB"),
869 INIT_PARAM(mem, "memory"),
870 INIT_PARAM(system, "system object"),
871 INIT_PARAM(cpu_id, "processor ID"),
872 INIT_PARAM(profile, ""),
873 #else
874 INIT_PARAM(workload, "processes to run"),
875 #endif // FULL_SYSTEM
876
877 INIT_PARAM(clock, "clock speed"),
878 INIT_PARAM(icache, "L1 instruction cache object"),
879 INIT_PARAM(dcache, "L1 data cache object"),
880 INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
881 INIT_PARAM(width, "cpu width"),
882 INIT_PARAM(function_trace, "Enable function trace"),
883 INIT_PARAM(function_trace_start, "Cycle to start function trace")
884
885 END_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
886
887
888 CREATE_SIM_OBJECT(SimpleCPU)
889 {
890 SimpleCPU::Params *params = new SimpleCPU::Params();
891 params->name = getInstanceName();
892 params->numberOfThreads = 1;
893 params->max_insts_any_thread = max_insts_any_thread;
894 params->max_insts_all_threads = max_insts_all_threads;
895 params->max_loads_any_thread = max_loads_any_thread;
896 params->max_loads_all_threads = max_loads_all_threads;
897 params->deferRegistration = defer_registration;
898 params->clock = clock;
899 params->functionTrace = function_trace;
900 params->functionTraceStart = function_trace_start;
901 params->icache_interface = (icache) ? icache->getInterface() : NULL;
902 params->dcache_interface = (dcache) ? dcache->getInterface() : NULL;
903 params->width = width;
904
905 #if FULL_SYSTEM
906 params->itb = itb;
907 params->dtb = dtb;
908 params->mem = mem;
909 params->system = system;
910 params->cpu_id = cpu_id;
911 params->profile = profile;
912 #else
913 params->process = workload;
914 #endif
915
916 SimpleCPU *cpu = new SimpleCPU(params);
917 return cpu;
918 }
919
920 REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU)
921