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