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