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