base.cc revision 334
14120Sgblack@eecs.umich.edu/*
24120Sgblack@eecs.umich.edu * Copyright (c) 2003 The Regents of The University of Michigan
34120Sgblack@eecs.umich.edu * All rights reserved.
44120Sgblack@eecs.umich.edu *
54120Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
64120Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
74120Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
84120Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
94120Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
104120Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
114120Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
124120Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
134120Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
144120Sgblack@eecs.umich.edu * this software without specific prior written permission.
154120Sgblack@eecs.umich.edu *
164120Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
174120Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
184120Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
194120Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
204120Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
214120Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
224120Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
234120Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
244120Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
254120Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
264120Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
274120Sgblack@eecs.umich.edu */
284120Sgblack@eecs.umich.edu
294120Sgblack@eecs.umich.edu#include <cmath>
304120Sgblack@eecs.umich.edu#include <cstdio>
314120Sgblack@eecs.umich.edu#include <cstdlib>
324120Sgblack@eecs.umich.edu#include <iostream>
334120Sgblack@eecs.umich.edu#include <iomanip>
344120Sgblack@eecs.umich.edu#include <list>
354120Sgblack@eecs.umich.edu#include <sstream>
364120Sgblack@eecs.umich.edu#include <string>
374120Sgblack@eecs.umich.edu
384120Sgblack@eecs.umich.edu#include "base/cprintf.hh"
394120Sgblack@eecs.umich.edu#include "base/inifile.hh"
404120Sgblack@eecs.umich.edu#include "base/loader/symtab.hh"
414120Sgblack@eecs.umich.edu#include "base/misc.hh"
424120Sgblack@eecs.umich.edu#include "base/pollevent.hh"
434120Sgblack@eecs.umich.edu#include "base/range.hh"
444120Sgblack@eecs.umich.edu#include "base/trace.hh"
454120Sgblack@eecs.umich.edu#include "cpu/base_cpu.hh"
464120Sgblack@eecs.umich.edu#include "cpu/exec_context.hh"
474120Sgblack@eecs.umich.edu#include "cpu/exetrace.hh"
484120Sgblack@eecs.umich.edu#include "cpu/full_cpu/smt.hh"
494120Sgblack@eecs.umich.edu#include "cpu/simple_cpu/simple_cpu.hh"
504120Sgblack@eecs.umich.edu#include "cpu/static_inst.hh"
514120Sgblack@eecs.umich.edu#include "mem/base_mem.hh"
524120Sgblack@eecs.umich.edu#include "mem/mem_interface.hh"
534120Sgblack@eecs.umich.edu#include "sim/annotation.hh"
544120Sgblack@eecs.umich.edu#include "sim/builder.hh"
554120Sgblack@eecs.umich.edu#include "sim/debug.hh"
564120Sgblack@eecs.umich.edu#include "sim/host.hh"
574120Sgblack@eecs.umich.edu#include "sim/sim_events.hh"
584120Sgblack@eecs.umich.edu#include "sim/sim_object.hh"
594120Sgblack@eecs.umich.edu#include "sim/sim_stats.hh"
604120Sgblack@eecs.umich.edu
614120Sgblack@eecs.umich.edu#ifdef FULL_SYSTEM
624120Sgblack@eecs.umich.edu#include "base/remote_gdb.hh"
634120Sgblack@eecs.umich.edu#include "dev/alpha_access.h"
644120Sgblack@eecs.umich.edu#include "dev/pciareg.h"
654120Sgblack@eecs.umich.edu#include "mem/functional_mem/memory_control.hh"
664120Sgblack@eecs.umich.edu#include "mem/functional_mem/physical_memory.hh"
674120Sgblack@eecs.umich.edu#include "sim/system.hh"
684120Sgblack@eecs.umich.edu#include "targetarch/alpha_memory.hh"
694120Sgblack@eecs.umich.edu#include "targetarch/vtophys.hh"
704120Sgblack@eecs.umich.edu#else // !FULL_SYSTEM
714120Sgblack@eecs.umich.edu#include "eio/eio.hh"
724120Sgblack@eecs.umich.edu#include "mem/functional_mem/functional_memory.hh"
734120Sgblack@eecs.umich.edu#include "sim/prog.hh"
744120Sgblack@eecs.umich.edu#endif // FULL_SYSTEM
754120Sgblack@eecs.umich.edu
764120Sgblack@eecs.umich.eduusing namespace std;
774120Sgblack@eecs.umich.edu
784120Sgblack@eecs.umich.eduSimpleCPU::TickEvent::TickEvent(SimpleCPU *c)
794120Sgblack@eecs.umich.edu    : Event(&mainEventQueue, 100), cpu(c)
804120Sgblack@eecs.umich.edu{
814120Sgblack@eecs.umich.edu}
824120Sgblack@eecs.umich.edu
834120Sgblack@eecs.umich.eduvoid
844120Sgblack@eecs.umich.eduSimpleCPU::TickEvent::process()
854120Sgblack@eecs.umich.edu{
864202Sbinkertn@umich.edu    cpu->tick();
874202Sbinkertn@umich.edu}
884202Sbinkertn@umich.edu
894202Sbinkertn@umich.educonst char *
904202Sbinkertn@umich.eduSimpleCPU::TickEvent::description()
914240Sgblack@eecs.umich.edu{
924202Sbinkertn@umich.edu    return "SimpleCPU tick event";
934202Sbinkertn@umich.edu}
944120Sgblack@eecs.umich.edu
954202Sbinkertn@umich.edu
964202Sbinkertn@umich.eduSimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu)
974202Sbinkertn@umich.edu    : Event(&mainEventQueue),
984202Sbinkertn@umich.edu      cpu(_cpu)
994202Sbinkertn@umich.edu{
1004120Sgblack@eecs.umich.edu}
1014202Sbinkertn@umich.edu
1024202Sbinkertn@umich.eduvoid SimpleCPU::CacheCompletionEvent::process()
1034202Sbinkertn@umich.edu{
1044120Sgblack@eecs.umich.edu    cpu->processCacheCompletion();
1054202Sbinkertn@umich.edu}
1064202Sbinkertn@umich.edu
1074202Sbinkertn@umich.educonst char *
1084202Sbinkertn@umich.eduSimpleCPU::CacheCompletionEvent::description()
1094202Sbinkertn@umich.edu{
1104202Sbinkertn@umich.edu    return "SimpleCPU cache completion event";
111}
112
113#ifdef FULL_SYSTEM
114SimpleCPU::SimpleCPU(const string &_name,
115                     System *_system,
116                     Counter max_insts_any_thread,
117                     Counter max_insts_all_threads,
118                     Counter max_loads_any_thread,
119                     Counter max_loads_all_threads,
120                     AlphaItb *itb, AlphaDtb *dtb,
121                     FunctionalMemory *mem,
122                     MemInterface *icache_interface,
123                     MemInterface *dcache_interface,
124                     Tick freq)
125    : BaseCPU(_name, /* number_of_threads */ 1,
126              max_insts_any_thread, max_insts_all_threads,
127              max_loads_any_thread, max_loads_all_threads,
128              _system, freq),
129#else
130SimpleCPU::SimpleCPU(const string &_name, Process *_process,
131                     Counter max_insts_any_thread,
132                     Counter max_insts_all_threads,
133                     Counter max_loads_any_thread,
134                     Counter max_loads_all_threads,
135                     MemInterface *icache_interface,
136                     MemInterface *dcache_interface)
137    : BaseCPU(_name, /* number_of_threads */ 1,
138              max_insts_any_thread, max_insts_all_threads,
139              max_loads_any_thread, max_loads_all_threads),
140#endif
141      tickEvent(this), xc(NULL), cacheCompletionEvent(this)
142{
143    _status = Idle;
144#ifdef FULL_SYSTEM
145    xc = new ExecContext(this, 0, system, itb, dtb, mem);
146
147    // initialize CPU, including PC
148    TheISA::initCPU(&xc->regs);
149#else
150    xc = new ExecContext(this, /* thread_num */ 0, _process, /* asid */ 0);
151#endif // !FULL_SYSTEM
152
153    icacheInterface = icache_interface;
154    dcacheInterface = dcache_interface;
155
156    memReq = new MemReq();
157    memReq->xc = xc;
158    memReq->asid = 0;
159    memReq->data = new uint8_t[64];
160
161    numInst = 0;
162    startNumInst = 0;
163    numLoad = 0;
164    startNumLoad = 0;
165    lastIcacheStall = 0;
166    lastDcacheStall = 0;
167
168    execContexts.push_back(xc);
169}
170
171SimpleCPU::~SimpleCPU()
172{
173}
174
175void
176SimpleCPU::switchOut()
177{
178    _status = SwitchedOut;
179    if (tickEvent.scheduled())
180        tickEvent.squash();
181}
182
183
184void
185SimpleCPU::takeOverFrom(BaseCPU *oldCPU)
186{
187    BaseCPU::takeOverFrom(oldCPU);
188
189    assert(!tickEvent.scheduled());
190
191    // if any of this CPU's ExecContexts are active, mark the CPU as
192    // running and schedule its tick event.
193    for (int i = 0; i < execContexts.size(); ++i) {
194        ExecContext *xc = execContexts[i];
195        if (xc->status() == ExecContext::Active && _status != Running) {
196            _status = Running;
197            tickEvent.schedule(curTick);
198        }
199    }
200
201    oldCPU->switchOut();
202}
203
204
205void
206SimpleCPU::execCtxStatusChg(int thread_num) {
207    assert(thread_num == 0);
208    assert(xc);
209
210    if (xc->status() == ExecContext::Active)
211        setStatus(Running);
212    else
213        setStatus(Idle);
214}
215
216
217void
218SimpleCPU::regStats()
219{
220    using namespace Statistics;
221
222    BaseCPU::regStats();
223
224    numInsts
225        .name(name() + ".num_insts")
226        .desc("Number of instructions executed")
227        ;
228
229    numMemRefs
230        .name(name() + ".num_refs")
231        .desc("Number of memory references")
232        ;
233
234    idleFraction
235        .name(name() + ".idle_fraction")
236        .desc("Percentage of idle cycles")
237        ;
238
239    icacheStallCycles
240        .name(name() + ".icache_stall_cycles")
241        .desc("ICache total stall cycles")
242        .prereq(icacheStallCycles)
243        ;
244
245    dcacheStallCycles
246        .name(name() + ".dcache_stall_cycles")
247        .desc("DCache total stall cycles")
248        .prereq(dcacheStallCycles)
249        ;
250
251    numInsts = Statistics::scalar(numInst) - Statistics::scalar(startNumInst);
252    simInsts += numInsts;
253}
254
255void
256SimpleCPU::resetStats()
257{
258    startNumInst = numInst;
259}
260
261void
262SimpleCPU::serialize(ostream &os)
263{
264    SERIALIZE_ENUM(_status);
265    SERIALIZE_SCALAR(inst);
266    nameOut(os, csprintf("%s.xc", name()));
267    xc->serialize(os);
268    nameOut(os, csprintf("%s.tickEvent", name()));
269    tickEvent.serialize(os);
270    nameOut(os, csprintf("%s.cacheCompletionEvent", name()));
271    cacheCompletionEvent.serialize(os);
272}
273
274void
275SimpleCPU::unserialize(Checkpoint *cp, const string &section)
276{
277    UNSERIALIZE_ENUM(_status);
278    UNSERIALIZE_SCALAR(inst);
279    xc->unserialize(cp, csprintf("%s.xc", section));
280    tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
281    cacheCompletionEvent
282        .unserialize(cp, csprintf("%s.cacheCompletionEvent", section));
283}
284
285void
286change_thread_state(int thread_number, int activate, int priority)
287{
288}
289
290// precise architected memory state accessor macros
291template <class T>
292Fault
293SimpleCPU::read(Addr addr, T& data, unsigned flags)
294{
295    memReq->reset(addr, sizeof(T), flags);
296
297    // translate to physical address
298    Fault fault = xc->translateDataReadReq(memReq);
299
300    // do functional access
301    if (fault == No_Fault)
302        fault = xc->read(memReq, data);
303
304    if (traceData) {
305        traceData->setAddr(addr);
306        if (fault == No_Fault)
307            traceData->setData(data);
308    }
309
310    // if we have a cache, do cache access too
311    if (fault == No_Fault && dcacheInterface) {
312        memReq->cmd = Read;
313        memReq->completionEvent = NULL;
314        memReq->time = curTick;
315        memReq->flags &= ~UNCACHEABLE;
316        MemAccessResult result = dcacheInterface->access(memReq);
317
318        // Ugly hack to get an event scheduled *only* if the access is
319        // a miss.  We really should add first-class support for this
320        // at some point.
321        if (result != MA_HIT && dcacheInterface->doEvents) {
322            memReq->completionEvent = &cacheCompletionEvent;
323            setStatus(DcacheMissStall);
324        }
325    }
326
327    return fault;
328}
329
330#ifndef DOXYGEN_SHOULD_SKIP_THIS
331
332template
333Fault
334SimpleCPU::read(Addr addr, uint64_t& data, unsigned flags);
335
336template
337Fault
338SimpleCPU::read(Addr addr, uint32_t& data, unsigned flags);
339
340template
341Fault
342SimpleCPU::read(Addr addr, uint16_t& data, unsigned flags);
343
344template
345Fault
346SimpleCPU::read(Addr addr, uint8_t& data, unsigned flags);
347
348#endif //DOXYGEN_SHOULD_SKIP_THIS
349
350template<>
351Fault
352SimpleCPU::read(Addr addr, double& data, unsigned flags)
353{
354    return read(addr, *(uint64_t*)&data, flags);
355}
356
357template<>
358Fault
359SimpleCPU::read(Addr addr, float& data, unsigned flags)
360{
361    return read(addr, *(uint32_t*)&data, flags);
362}
363
364
365template<>
366Fault
367SimpleCPU::read(Addr addr, int32_t& data, unsigned flags)
368{
369    return read(addr, (uint32_t&)data, flags);
370}
371
372
373template <class T>
374Fault
375SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
376{
377    if (traceData) {
378        traceData->setAddr(addr);
379        traceData->setData(data);
380    }
381
382    memReq->reset(addr, sizeof(T), flags);
383
384    // translate to physical address
385    Fault fault = xc->translateDataWriteReq(memReq);
386
387    // do functional access
388    if (fault == No_Fault)
389        fault = xc->write(memReq, data);
390
391    if (fault == No_Fault && dcacheInterface) {
392        memReq->cmd = Write;
393        memcpy(memReq->data,(uint8_t *)&data,memReq->size);
394        memReq->completionEvent = NULL;
395        memReq->time = curTick;
396        memReq->flags &= ~UNCACHEABLE;
397        MemAccessResult result = dcacheInterface->access(memReq);
398
399        // Ugly hack to get an event scheduled *only* if the access is
400        // a miss.  We really should add first-class support for this
401        // at some point.
402        if (result != MA_HIT && dcacheInterface->doEvents) {
403            memReq->completionEvent = &cacheCompletionEvent;
404            setStatus(DcacheMissStall);
405        }
406    }
407
408    if (res && (fault == No_Fault))
409        *res = memReq->result;
410
411    return fault;
412}
413
414
415#ifndef DOXYGEN_SHOULD_SKIP_THIS
416template
417Fault
418SimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res);
419
420template
421Fault
422SimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res);
423
424template
425Fault
426SimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res);
427
428template
429Fault
430SimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res);
431
432#endif //DOXYGEN_SHOULD_SKIP_THIS
433
434template<>
435Fault
436SimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
437{
438    return write(*(uint64_t*)&data, addr, flags, res);
439}
440
441template<>
442Fault
443SimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
444{
445    return write(*(uint32_t*)&data, addr, flags, res);
446}
447
448
449template<>
450Fault
451SimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
452{
453    return write((uint32_t)data, addr, flags, res);
454}
455
456
457#ifdef FULL_SYSTEM
458Addr
459SimpleCPU::dbg_vtophys(Addr addr)
460{
461    return vtophys(xc, addr);
462}
463#endif // FULL_SYSTEM
464
465Tick save_cycle = 0;
466
467
468void
469SimpleCPU::processCacheCompletion()
470{
471    switch (status()) {
472      case IcacheMissStall:
473        icacheStallCycles += curTick - lastIcacheStall;
474        setStatus(IcacheMissComplete);
475        break;
476      case DcacheMissStall:
477        dcacheStallCycles += curTick - lastDcacheStall;
478        setStatus(Running);
479        break;
480      case SwitchedOut:
481        // If this CPU has been switched out due to sampling/warm-up,
482        // ignore any further status changes (e.g., due to cache
483        // misses outstanding at the time of the switch).
484        return;
485      default:
486        panic("SimpleCPU::processCacheCompletion: bad state");
487        break;
488    }
489}
490
491#ifdef FULL_SYSTEM
492void
493SimpleCPU::post_interrupt(int int_num, int index)
494{
495    BaseCPU::post_interrupt(int_num, index);
496
497    if (xc->status() == ExecContext::Suspended) {
498                DPRINTF(IPI,"Suspended Processor awoke\n");
499        xc->setStatus(ExecContext::Active);
500        Annotate::Resume(xc);
501    }
502}
503#endif // FULL_SYSTEM
504
505/* start simulation, program loaded, processor precise state initialized */
506void
507SimpleCPU::tick()
508{
509    traceData = NULL;
510
511    Fault fault = No_Fault;
512
513#ifdef FULL_SYSTEM
514    if (AlphaISA::check_interrupts &&
515        xc->cpu->check_interrupts() &&
516        !PC_PAL(xc->regs.pc) &&
517        status() != IcacheMissComplete) {
518        int ipl = 0;
519        int summary = 0;
520        AlphaISA::check_interrupts = 0;
521        IntReg *ipr = xc->regs.ipr;
522
523        if (xc->regs.ipr[TheISA::IPR_SIRR]) {
524            for (int i = TheISA::INTLEVEL_SOFTWARE_MIN;
525                 i < TheISA::INTLEVEL_SOFTWARE_MAX; i++) {
526                if (ipr[TheISA::IPR_SIRR] & (ULL(1) << i)) {
527                    // See table 4-19 of 21164 hardware reference
528                    ipl = (i - TheISA::INTLEVEL_SOFTWARE_MIN) + 1;
529                    summary |= (ULL(1) << i);
530                }
531            }
532        }
533
534        uint64_t interrupts = xc->cpu->intr_status();
535        for (int i = TheISA::INTLEVEL_EXTERNAL_MIN;
536            i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) {
537            if (interrupts & (ULL(1) << i)) {
538                // See table 4-19 of 21164 hardware reference
539                ipl = i;
540                summary |= (ULL(1) << i);
541            }
542        }
543
544        if (ipr[TheISA::IPR_ASTRR])
545            panic("asynchronous traps not implemented\n");
546
547        if (ipl && ipl > xc->regs.ipr[TheISA::IPR_IPLR]) {
548            ipr[TheISA::IPR_ISR] = summary;
549            ipr[TheISA::IPR_INTID] = ipl;
550            xc->ev5_trap(Interrupt_Fault);
551
552            DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
553                    ipr[TheISA::IPR_IPLR], ipl, summary);
554        }
555    }
556#endif
557
558    // maintain $r0 semantics
559    xc->regs.intRegFile[ZeroReg] = 0;
560#ifdef TARGET_ALPHA
561    xc->regs.floatRegFile.d[ZeroReg] = 0.0;
562#endif // TARGET_ALPHA
563
564    if (status() == IcacheMissComplete) {
565        // We've already fetched an instruction and were stalled on an
566        // I-cache miss.  No need to fetch it again.
567
568        setStatus(Running);
569    }
570    else {
571        // Try to fetch an instruction
572
573        // set up memory request for instruction fetch
574#ifdef FULL_SYSTEM
575#define IFETCH_FLAGS(pc)	((pc) & 1) ? PHYSICAL : 0
576#else
577#define IFETCH_FLAGS(pc)	0
578#endif
579
580        memReq->cmd = Read;
581        memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t),
582                     IFETCH_FLAGS(xc->regs.pc));
583
584        fault = xc->translateInstReq(memReq);
585
586        if (fault == No_Fault)
587            fault = xc->mem->read(memReq, inst);
588
589        if (icacheInterface && fault == No_Fault) {
590            memReq->completionEvent = NULL;
591
592            memReq->time = curTick;
593            memReq->flags &= ~UNCACHEABLE;
594            MemAccessResult result = icacheInterface->access(memReq);
595
596            // Ugly hack to get an event scheduled *only* if the access is
597            // a miss.  We really should add first-class support for this
598            // at some point.
599            if (result != MA_HIT && icacheInterface->doEvents) {
600                memReq->completionEvent = &cacheCompletionEvent;
601                setStatus(IcacheMissStall);
602                return;
603            }
604        }
605    }
606
607    // If we've got a valid instruction (i.e., no fault on instruction
608    // fetch), then execute it.
609    if (fault == No_Fault) {
610
611        // keep an instruction count
612        numInst++;
613
614        // check for instruction-count-based events
615        comInsnEventQueue[0]->serviceEvents(numInst);
616
617        // decode the instruction
618        StaticInstPtr<TheISA> si(inst);
619
620        traceData = Trace::getInstRecord(curTick, xc, this, si,
621                                         xc->regs.pc);
622
623#ifdef FULL_SYSTEM
624        xc->regs.opcode = (inst >> 26) & 0x3f;
625        xc->regs.ra = (inst >> 21) & 0x1f;
626#endif // FULL_SYSTEM
627
628        xc->func_exe_insn++;
629
630        fault = si->execute(this, xc, traceData);
631#ifdef FS_MEASURE
632        if (!(xc->misspeculating()) && (xc->system->bin)) {
633            SWContext *ctx = xc->swCtx;
634            if (ctx && !ctx->callStack.empty()) {
635                if (si->isCall()) {
636                    ctx->calls++;
637                }
638                if (si->isReturn()) {
639                     if (ctx->calls == 0) {
640                        fnCall *top = ctx->callStack.top();
641                        DPRINTF(TCPIP, "Removing %s from callstack.\n", top->name);
642                        delete top;
643                        ctx->callStack.pop();
644                        if (ctx->callStack.empty())
645                            xc->system->nonPath->activate();
646                        else
647                            ctx->callStack.top()->myBin->activate();
648
649                        xc->system->dumpState(xc);
650                    } else {
651                        ctx->calls--;
652                    }
653                }
654            }
655        }
656#endif
657        if (si->isMemRef()) {
658            numMemRefs++;
659        }
660
661        if (si->isLoad()) {
662            ++numLoad;
663            comLoadEventQueue[0]->serviceEvents(numLoad);
664        }
665
666        if (traceData)
667            traceData->finalize();
668
669    }	// if (fault == No_Fault)
670
671    if (fault != No_Fault) {
672#ifdef FULL_SYSTEM
673        xc->ev5_trap(fault);
674#else // !FULL_SYSTEM
675        fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc);
676#endif // FULL_SYSTEM
677    }
678    else {
679        // go to the next instruction
680        xc->regs.pc = xc->regs.npc;
681        xc->regs.npc += sizeof(MachInst);
682    }
683
684#ifdef FULL_SYSTEM
685    Addr oldpc;
686    do {
687        oldpc = xc->regs.pc;
688        system->pcEventQueue.service(xc);
689    } while (oldpc != xc->regs.pc);
690#endif
691
692    assert(status() == Running ||
693           status() == Idle ||
694           status() == DcacheMissStall);
695
696    if (status() == Running && !tickEvent.scheduled())
697        tickEvent.schedule(curTick + 1);
698}
699
700
701////////////////////////////////////////////////////////////////////////
702//
703//  SimpleCPU Simulation Object
704//
705BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
706
707    Param<Counter> max_insts_any_thread;
708    Param<Counter> max_insts_all_threads;
709    Param<Counter> max_loads_any_thread;
710    Param<Counter> max_loads_all_threads;
711
712#ifdef FULL_SYSTEM
713    SimObjectParam<AlphaItb *> itb;
714    SimObjectParam<AlphaDtb *> dtb;
715    SimObjectParam<FunctionalMemory *> mem;
716    SimObjectParam<System *> system;
717    Param<int> mult;
718#else
719    SimObjectParam<Process *> workload;
720#endif // FULL_SYSTEM
721
722    SimObjectParam<BaseMem *> icache;
723    SimObjectParam<BaseMem *> dcache;
724
725    Param<bool> defer_registration;
726
727END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
728
729BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
730
731    INIT_PARAM_DFLT(max_insts_any_thread,
732                    "terminate when any thread reaches this insn count",
733                    0),
734    INIT_PARAM_DFLT(max_insts_all_threads,
735                    "terminate when all threads have reached this insn count",
736                    0),
737    INIT_PARAM_DFLT(max_loads_any_thread,
738                    "terminate when any thread reaches this load count",
739                    0),
740    INIT_PARAM_DFLT(max_loads_all_threads,
741                    "terminate when all threads have reached this load count",
742                    0),
743
744#ifdef FULL_SYSTEM
745    INIT_PARAM(itb, "Instruction TLB"),
746    INIT_PARAM(dtb, "Data TLB"),
747    INIT_PARAM(mem, "memory"),
748    INIT_PARAM(system, "system object"),
749    INIT_PARAM_DFLT(mult, "system clock multiplier", 1),
750#else
751    INIT_PARAM(workload, "processes to run"),
752#endif // FULL_SYSTEM
753
754    INIT_PARAM_DFLT(icache, "L1 instruction cache object", NULL),
755    INIT_PARAM_DFLT(dcache, "L1 data cache object", NULL),
756    INIT_PARAM_DFLT(defer_registration, "defer registration with system "
757                    "(for sampling)", false)
758
759END_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
760
761
762CREATE_SIM_OBJECT(SimpleCPU)
763{
764    SimpleCPU *cpu;
765#ifdef FULL_SYSTEM
766    if (mult != 1)
767        panic("processor clock multiplier must be 1\n");
768
769    cpu = new SimpleCPU(getInstanceName(), system,
770                        max_insts_any_thread, max_insts_all_threads,
771                        max_loads_any_thread, max_loads_all_threads,
772                        itb, dtb, mem,
773                        (icache) ? icache->getInterface() : NULL,
774                        (dcache) ? dcache->getInterface() : NULL,
775                        ticksPerSecond * mult);
776#else
777
778    cpu = new SimpleCPU(getInstanceName(), workload,
779                        max_insts_any_thread, max_insts_all_threads,
780                        max_loads_any_thread, max_loads_all_threads,
781                        (icache) ? icache->getInterface() : NULL,
782                        (dcache) ? dcache->getInterface() : NULL);
783
784#endif // FULL_SYSTEM
785
786    if (!defer_registration) {
787        cpu->registerExecContexts();
788    }
789
790    return cpu;
791}
792
793REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU)
794