base.cc revision 2420
1/*
2 * Copyright (c) 2002-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <cmath>
30#include <cstdio>
31#include <cstdlib>
32#include <iostream>
33#include <iomanip>
34#include <list>
35#include <sstream>
36#include <string>
37
38#include "base/cprintf.hh"
39#include "base/inifile.hh"
40#include "base/loader/symtab.hh"
41#include "base/misc.hh"
42#include "base/pollevent.hh"
43#include "base/range.hh"
44#include "base/stats/events.hh"
45#include "base/trace.hh"
46#include "cpu/base.hh"
47#include "cpu/exec_context.hh"
48#include "cpu/exetrace.hh"
49#include "cpu/profile.hh"
50#include "cpu/sampler/sampler.hh"
51#include "cpu/simple/cpu.hh"
52#include "cpu/smt.hh"
53#include "cpu/static_inst.hh"
54#include "kern/kernel_stats.hh"
55#include "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#if 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/stacktrace.hh"
69#include "targetarch/vtophys.hh"
70#else // !FULL_SYSTEM
71#include "mem/memory.hh"
72#endif // FULL_SYSTEM
73
74using namespace std;
75
76
77SimpleCPU::TickEvent::TickEvent(SimpleCPU *c, int w)
78    : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), width(w)
79{
80}
81
82void
83SimpleCPU::TickEvent::process()
84{
85    int count = width;
86    do {
87        cpu->tick();
88    } while (--count > 0 && cpu->status() == Running);
89}
90
91const char *
92SimpleCPU::TickEvent::description()
93{
94    return "SimpleCPU tick event";
95}
96
97
98bool
99SimpleCPU::CpuPort::recvTiming(Packet &pkt)
100{
101    cpu->processResponse(pkt);
102    return true;
103}
104
105Tick
106SimpleCPU::CpuPort::recvAtomic(Packet &pkt)
107{
108    panic("CPU doesn't expect callback!");
109    return curTick;
110}
111
112void
113SimpleCPU::CpuPort::recvFunctional(Packet &pkt)
114{
115    panic("CPU doesn't expect callback!");
116}
117
118void
119SimpleCPU::CpuPort::recvStatusChange(Status status)
120{
121    cpu->recvStatusChange(status);
122}
123
124Packet *
125SimpleCPU::CpuPort::recvRetry()
126{
127    return cpu->processRetry();
128}
129
130SimpleCPU::SimpleCPU(Params *p)
131    : BaseCPU(p), icachePort(this),
132      dcachePort(this), tickEvent(this, p->width), xc(NULL)
133{
134    _status = Idle;
135
136    //Create Memory Ports (conect them up)
137    p->mem->addPort("DCACHE");
138    dcachePort.setPeer(p->mem->getPort("DCACHE"));
139    (p->mem->getPort("DCACHE"))->setPeer(&dcachePort);
140
141    p->mem->addPort("ICACHE");
142    icachePort.setPeer(p->mem->getPort("ICACHE"));
143    (p->mem->getPort("ICACHE"))->setPeer(&icachePort);
144
145#if FULL_SYSTEM
146    xc = new ExecContext(this, 0, p->system, p->itb, p->dtb, p->mem);
147
148    // initialize CPU, including PC
149    TheISA::initCPU(&xc->regs);
150#else
151    xc = new ExecContext(this, /* thread_num */ 0, p->process, /* asid */ 0,
152                         &dcachePort);
153#endif // !FULL_SYSTEM
154
155#if SIMPLE_CPU_MEM_ATOMIC || SIMPLE_CPU_MEM_IMMEDIATE
156    ifetch_req = new CpuRequest;
157    ifetch_req->asid = 0;
158    ifetch_req->size = sizeof(MachInst);
159    ifetch_pkt = new Packet;
160    ifetch_pkt->cmd = Read;
161    ifetch_pkt->data = (uint8_t *)&inst;
162    ifetch_pkt->req = ifetch_req;
163    ifetch_pkt->size = sizeof(MachInst);
164
165    data_read_req = new CpuRequest;
166    data_read_req->asid = 0;
167    data_read_pkt = new Packet;
168    data_read_pkt->cmd = Read;
169    data_read_pkt->data = new uint8_t[8];
170    data_read_pkt->req = data_read_req;
171
172    data_write_req = new CpuRequest;
173    data_write_req->asid = 0;
174    data_write_pkt = new Packet;
175    data_write_pkt->cmd = Write;
176    data_write_pkt->req = data_write_req;
177#endif
178
179    numInst = 0;
180    startNumInst = 0;
181    numLoad = 0;
182    startNumLoad = 0;
183    lastIcacheStall = 0;
184    lastDcacheStall = 0;
185
186    execContexts.push_back(xc);
187}
188
189SimpleCPU::~SimpleCPU()
190{
191}
192
193void
194SimpleCPU::switchOut(Sampler *s)
195{
196    sampler = s;
197    if (status() == DcacheWaitResponse) {
198        DPRINTF(Sampler,"Outstanding dcache access, waiting for completion\n");
199        _status = DcacheWaitSwitch;
200    }
201    else {
202        _status = SwitchedOut;
203
204        if (tickEvent.scheduled())
205            tickEvent.squash();
206
207        sampler->signalSwitched();
208    }
209}
210
211
212void
213SimpleCPU::takeOverFrom(BaseCPU *oldCPU)
214{
215    BaseCPU::takeOverFrom(oldCPU);
216
217    assert(!tickEvent.scheduled());
218
219    // if any of this CPU's ExecContexts are active, mark the CPU as
220    // running and schedule its tick event.
221    for (int i = 0; i < execContexts.size(); ++i) {
222        ExecContext *xc = execContexts[i];
223        if (xc->status() == ExecContext::Active && _status != Running) {
224            _status = Running;
225            tickEvent.schedule(curTick);
226        }
227    }
228}
229
230
231void
232SimpleCPU::activateContext(int thread_num, int delay)
233{
234    assert(thread_num == 0);
235    assert(xc);
236
237    assert(_status == Idle);
238    notIdleFraction++;
239    scheduleTickEvent(delay);
240    _status = Running;
241}
242
243
244void
245SimpleCPU::suspendContext(int thread_num)
246{
247    assert(thread_num == 0);
248    assert(xc);
249
250    assert(_status == Running);
251    notIdleFraction--;
252    unscheduleTickEvent();
253    _status = Idle;
254}
255
256
257void
258SimpleCPU::deallocateContext(int thread_num)
259{
260    // for now, these are equivalent
261    suspendContext(thread_num);
262}
263
264
265void
266SimpleCPU::haltContext(int thread_num)
267{
268    // for now, these are equivalent
269    suspendContext(thread_num);
270}
271
272
273void
274SimpleCPU::regStats()
275{
276    using namespace Stats;
277
278    BaseCPU::regStats();
279
280    numInsts
281        .name(name() + ".num_insts")
282        .desc("Number of instructions executed")
283        ;
284
285    numMemRefs
286        .name(name() + ".num_refs")
287        .desc("Number of memory references")
288        ;
289
290    notIdleFraction
291        .name(name() + ".not_idle_fraction")
292        .desc("Percentage of non-idle cycles")
293        ;
294
295    idleFraction
296        .name(name() + ".idle_fraction")
297        .desc("Percentage of idle cycles")
298        ;
299
300    icacheStallCycles
301        .name(name() + ".icache_stall_cycles")
302        .desc("ICache total stall cycles")
303        .prereq(icacheStallCycles)
304        ;
305
306    dcacheStallCycles
307        .name(name() + ".dcache_stall_cycles")
308        .desc("DCache total stall cycles")
309        .prereq(dcacheStallCycles)
310        ;
311
312    icacheRetryCycles
313        .name(name() + ".icache_retry_cycles")
314        .desc("ICache total retry cycles")
315        .prereq(icacheRetryCycles)
316        ;
317
318    dcacheRetryCycles
319        .name(name() + ".dcache_retry_cycles")
320        .desc("DCache total retry cycles")
321        .prereq(dcacheRetryCycles)
322        ;
323
324    idleFraction = constant(1.0) - notIdleFraction;
325}
326
327void
328SimpleCPU::resetStats()
329{
330    startNumInst = numInst;
331    notIdleFraction = (_status != Idle);
332}
333
334void
335SimpleCPU::serialize(ostream &os)
336{
337    BaseCPU::serialize(os);
338    SERIALIZE_ENUM(_status);
339    SERIALIZE_SCALAR(inst);
340    nameOut(os, csprintf("%s.xc", name()));
341    xc->serialize(os);
342    nameOut(os, csprintf("%s.tickEvent", name()));
343    tickEvent.serialize(os);
344    nameOut(os, csprintf("%s.cacheCompletionEvent", name()));
345}
346
347void
348SimpleCPU::unserialize(Checkpoint *cp, const string &section)
349{
350    BaseCPU::unserialize(cp, section);
351    UNSERIALIZE_ENUM(_status);
352    UNSERIALIZE_SCALAR(inst);
353    xc->unserialize(cp, csprintf("%s.xc", section));
354    tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
355}
356
357void
358change_thread_state(int thread_number, int activate, int priority)
359{
360}
361
362Fault
363SimpleCPU::copySrcTranslate(Addr src)
364{
365#if 0
366    static bool no_warn = true;
367    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
368    // Only support block sizes of 64 atm.
369    assert(blk_size == 64);
370    int offset = src & (blk_size - 1);
371
372    // Make sure block doesn't span page
373    if (no_warn &&
374        (src & TheISA::PageMask) != ((src + blk_size) & TheISA::PageMask) &&
375        (src >> 40) != 0xfffffc) {
376        warn("Copied block source spans pages %x.", src);
377        no_warn = false;
378    }
379
380    memReq->reset(src & ~(blk_size - 1), blk_size);
381
382    // translate to physical address
383    Fault fault = xc->translateDataReadReq(req);
384
385    assert(fault != Alignment_Fault);
386
387    if (fault == No_Fault) {
388        xc->copySrcAddr = src;
389        xc->copySrcPhysAddr = memReq->paddr + offset;
390    } else {
391        xc->copySrcAddr = 0;
392        xc->copySrcPhysAddr = 0;
393    }
394    return fault;
395#else
396    return No_Fault;
397#endif
398}
399
400Fault
401SimpleCPU::copy(Addr dest)
402{
403#if 0
404    static bool no_warn = true;
405    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
406    // Only support block sizes of 64 atm.
407    assert(blk_size == 64);
408    uint8_t data[blk_size];
409    //assert(xc->copySrcAddr);
410    int offset = dest & (blk_size - 1);
411
412    // Make sure block doesn't span page
413    if (no_warn &&
414        (dest & TheISA::PageMask) != ((dest + blk_size) & TheISA::PageMask) &&
415        (dest >> 40) != 0xfffffc) {
416        no_warn = false;
417        warn("Copied block destination spans pages %x. ", dest);
418    }
419
420    memReq->reset(dest & ~(blk_size -1), blk_size);
421    // translate to physical address
422    Fault fault = xc->translateDataWriteReq(req);
423
424    assert(fault != Alignment_Fault);
425
426    if (fault == No_Fault) {
427        Addr dest_addr = memReq->paddr + offset;
428        // Need to read straight from memory since we have more than 8 bytes.
429        memReq->paddr = xc->copySrcPhysAddr;
430        xc->mem->read(memReq, data);
431        memReq->paddr = dest_addr;
432        xc->mem->write(memReq, data);
433        if (dcacheInterface) {
434            memReq->cmd = Copy;
435            memReq->completionEvent = NULL;
436            memReq->paddr = xc->copySrcPhysAddr;
437            memReq->dest = dest_addr;
438            memReq->size = 64;
439            memReq->time = curTick;
440            memReq->flags &= ~INST_READ;
441            dcacheInterface->access(memReq);
442        }
443    }
444    return fault;
445#else
446    panic("copy not implemented");
447    return No_Fault;
448#endif
449}
450
451// precise architected memory state accessor macros
452template <class T>
453Fault
454SimpleCPU::read(Addr addr, T &data, unsigned flags)
455{
456    if (status() == DcacheWaitResponse || status() == DcacheWaitSwitch) {
457//	Fault fault = xc->read(memReq,data);
458        // Not sure what to check for no fault...
459        if (data_read_pkt->result == Success) {
460            memcpy(&data, data_read_pkt->data, sizeof(T));
461        }
462
463        if (traceData) {
464            traceData->setAddr(addr);
465        }
466
467        // @todo: Figure out a way to create a Fault from the packet result.
468        return No_Fault;
469    }
470
471//    memReq->reset(addr, sizeof(T), flags);
472
473#if SIMPLE_CPU_MEM_TIMING
474    CpuRequest *data_read_req = new CpuRequest;
475#endif
476
477    data_read_req->vaddr = addr;
478    data_read_req->size = sizeof(T);
479    data_read_req->flags = flags;
480    data_read_req->time = curTick;
481
482    // translate to physical address
483    Fault fault = xc->translateDataReadReq(data_read_req);
484
485    // Now do the access.
486    if (fault == No_Fault) {
487#if SIMPLE_CPU_MEM_TIMING
488        data_read_pkt = new Packet;
489        data_read_pkt->cmd = Read;
490        data_read_pkt->req = data_read_req;
491        data_read_pkt->data = new uint8_t[8];
492#endif
493        data_read_pkt->addr = data_read_req->paddr;
494        data_read_pkt->size = sizeof(T);
495
496        sendDcacheRequest(data_read_pkt);
497
498#if SIMPLE_CPU_MEM_IMMEDIATE
499        // Need to find a way to not duplicate code above.
500
501        if (data_read_pkt->result == Success) {
502            memcpy(&data, data_read_pkt->data, sizeof(T));
503        }
504
505        if (traceData) {
506            traceData->setAddr(addr);
507        }
508
509        // @todo: Figure out a way to create a Fault from the packet result.
510        return No_Fault;
511#endif
512    }
513/*
514        memReq->cmd = Read;
515        memReq->completionEvent = NULL;
516        memReq->time = curTick;
517        memReq->flags &= ~INST_READ;
518        MemAccessResult result = dcacheInterface->access(memReq);
519
520        // Ugly hack to get an event scheduled *only* if the access is
521        // a miss.  We really should add first-class support for this
522        // at some point.
523        if (result != MA_HIT && dcacheInterface->doEvents()) {
524            memReq->completionEvent = &cacheCompletionEvent;
525            lastDcacheStall = curTick;
526            unscheduleTickEvent();
527            _status = DcacheMissStall;
528        } else {
529            // do functional access
530            fault = xc->read(memReq, data);
531
532        }
533
534    } else if(fault == No_Fault) {
535        // do functional access
536        fault = xc->read(memReq, data);
537
538    }
539*/
540    // This will need a new way to tell if it has a dcache attached.
541    if (data_read_req->flags & UNCACHEABLE)
542        recordEvent("Uncached Read");
543
544    return fault;
545}
546
547#ifndef DOXYGEN_SHOULD_SKIP_THIS
548
549template
550Fault
551SimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
552
553template
554Fault
555SimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
556
557template
558Fault
559SimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
560
561template
562Fault
563SimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
564
565#endif //DOXYGEN_SHOULD_SKIP_THIS
566
567template<>
568Fault
569SimpleCPU::read(Addr addr, double &data, unsigned flags)
570{
571    return read(addr, *(uint64_t*)&data, flags);
572}
573
574template<>
575Fault
576SimpleCPU::read(Addr addr, float &data, unsigned flags)
577{
578    return read(addr, *(uint32_t*)&data, flags);
579}
580
581
582template<>
583Fault
584SimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
585{
586    return read(addr, (uint32_t&)data, flags);
587}
588
589
590template <class T>
591Fault
592SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
593{
594    data_write_req->vaddr = addr;
595    data_write_req->time = curTick;
596    data_write_req->size = sizeof(T);
597    data_write_req->flags = flags;
598
599    // translate to physical address
600    Fault fault = xc->translateDataWriteReq(data_write_req);
601
602    // Now do the access.
603    if (fault == No_Fault) {
604#if SIMPLE_CPU_MEM_TIMING
605        data_write_pkt = new Packet;
606        data_write_pkt->cmd = Write;
607        data_write_pkt->req = data_write_req;
608        data_write_pkt->data = new uint8_t[64];
609        memcpy(data_write_pkt->data, &data, sizeof(T));
610#else
611        data_write_pkt->data = (uint8_t *)&data;
612#endif
613        data_write_pkt->addr = data_write_req->paddr;
614        data_write_pkt->size = sizeof(T);
615
616        sendDcacheRequest(data_write_pkt);
617    }
618
619/*
620    // do functional access
621    if (fault == No_Fault)
622        fault = xc->write(memReq, data);
623
624    if (fault == No_Fault && dcacheInterface) {
625        memReq->cmd = Write;
626        memcpy(memReq->data,(uint8_t *)&data,memReq->size);
627        memReq->completionEvent = NULL;
628        memReq->time = curTick;
629        memReq->flags &= ~INST_READ;
630        MemAccessResult result = dcacheInterface->access(memReq);
631
632        // Ugly hack to get an event scheduled *only* if the access is
633        // a miss.  We really should add first-class support for this
634        // at some point.
635        if (result != MA_HIT && dcacheInterface->doEvents()) {
636            memReq->completionEvent = &cacheCompletionEvent;
637            lastDcacheStall = curTick;
638            unscheduleTickEvent();
639            _status = DcacheMissStall;
640        }
641    }
642*/
643    if (res && (fault == No_Fault))
644        *res = data_write_pkt->result;
645
646    // This will need a new way to tell if it's hooked up to a cache or not.
647    if (data_write_req->flags & UNCACHEABLE)
648        recordEvent("Uncached Write");
649
650    // If the write needs to have a fault on the access, consider calling
651    // changeStatus() and changing it to "bad addr write" or something.
652    return fault;
653}
654
655
656#ifndef DOXYGEN_SHOULD_SKIP_THIS
657template
658Fault
659SimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res);
660
661template
662Fault
663SimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res);
664
665template
666Fault
667SimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res);
668
669template
670Fault
671SimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res);
672
673#endif //DOXYGEN_SHOULD_SKIP_THIS
674
675template<>
676Fault
677SimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
678{
679    return write(*(uint64_t*)&data, addr, flags, res);
680}
681
682template<>
683Fault
684SimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
685{
686    return write(*(uint32_t*)&data, addr, flags, res);
687}
688
689
690template<>
691Fault
692SimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
693{
694    return write((uint32_t)data, addr, flags, res);
695}
696
697
698#if FULL_SYSTEM
699Addr
700SimpleCPU::dbg_vtophys(Addr addr)
701{
702    return vtophys(xc, addr);
703}
704#endif // FULL_SYSTEM
705
706void
707SimpleCPU::sendIcacheRequest(Packet *pkt)
708{
709    assert(!tickEvent.scheduled());
710#if SIMPLE_CPU_MEM_TIMING
711    retry_pkt = pkt;
712    bool success = icachePort.sendTiming(*pkt);
713
714    unscheduleTickEvent();
715
716    lastIcacheStall = curTick;
717
718    if (!success) {
719        // Need to wait for retry
720        _status = IcacheRetry;
721    } else {
722        // Need to wait for cache to respond
723        _status = IcacheWaitResponse;
724    }
725#elif SIMPLE_CPU_MEM_ATOMIC
726    Tick latency = icachePort.sendAtomic(*pkt);
727
728    unscheduleTickEvent();
729    scheduleTickEvent(latency);
730
731    // Note that Icache miss cycles will be incorrect.  Unless
732    // we check the status of the packet sent (is this valid?),
733    // we won't know if the latency is a hit or a miss.
734    icacheStallCycles += latency;
735
736    _status = IcacheAccessComplete;
737#elif SIMPLE_CPU_MEM_IMMEDIATE
738    icachePort.sendAtomic(*pkt);
739#else
740#error "SimpleCPU has no mem model set"
741#endif
742}
743
744void
745SimpleCPU::sendDcacheRequest(Packet *pkt)
746{
747    assert(!tickEvent.scheduled());
748#if SIMPLE_CPU_MEM_TIMING
749    unscheduleTickEvent();
750
751    retry_pkt = pkt;
752    bool success = dcachePort.sendTiming(*pkt);
753
754    lastDcacheStall = curTick;
755
756    if (!success) {
757        _status = DcacheRetry;
758    } else {
759        _status = DcacheWaitResponse;
760    }
761#elif SIMPLE_CPU_MEM_ATOMIC
762    unscheduleTickEvent();
763
764    Tick latency = dcachePort.sendAtomic(*pkt);
765
766    scheduleTickEvent(latency);
767
768    // Note that Dcache miss cycles will be incorrect.  Unless
769    // we check the status of the packet sent (is this valid?),
770    // we won't know if the latency is a hit or a miss.
771    dcacheStallCycles += latency;
772#elif SIMPLE_CPU_MEM_IMMEDIATE
773    dcachePort.sendAtomic(*pkt);
774#else
775#error "SimpleCPU has no mem model set"
776#endif
777}
778
779void
780SimpleCPU::processResponse(Packet &response)
781{
782    assert(SIMPLE_CPU_MEM_TIMING);
783
784    // For what things is the CPU the consumer of the packet it sent
785    // out?  This may create a memory leak if that's the case and it's
786    // expected of the SimpleCPU to delete its own packet.
787    Packet *pkt = &response;
788
789    switch (status()) {
790      case IcacheWaitResponse:
791        icacheStallCycles += curTick - lastIcacheStall;
792
793        _status = IcacheAccessComplete;
794        scheduleTickEvent(1);
795
796        // Copy the icache data into the instruction itself.
797        memcpy(&inst, pkt->data, sizeof(inst));
798
799        delete pkt;
800        break;
801      case DcacheWaitResponse:
802        if (pkt->cmd == Read) {
803            curStaticInst->execute(this,traceData);
804            if (traceData)
805                traceData->finalize();
806        }
807
808        delete pkt;
809
810        dcacheStallCycles += curTick - lastDcacheStall;
811        _status = Running;
812        scheduleTickEvent(1);
813        break;
814      case DcacheWaitSwitch:
815        if (pkt->cmd == Read) {
816            curStaticInst->execute(this,traceData);
817            if (traceData)
818                traceData->finalize();
819        }
820
821        delete pkt;
822
823        _status = SwitchedOut;
824        sampler->signalSwitched();
825      case SwitchedOut:
826        // If this CPU has been switched out due to sampling/warm-up,
827        // ignore any further status changes (e.g., due to cache
828        // misses outstanding at the time of the switch).
829        delete pkt;
830
831        return;
832      default:
833        panic("SimpleCPU::processCacheCompletion: bad state");
834        break;
835    }
836}
837
838Packet *
839SimpleCPU::processRetry()
840{
841#if SIMPLE_CPU_MEM_TIMING
842    switch(status()) {
843      case IcacheRetry:
844        icacheRetryCycles += curTick - lastIcacheStall;
845        return retry_pkt;
846        break;
847      case DcacheRetry:
848        dcacheRetryCycles += curTick - lastDcacheStall;
849        return retry_pkt;
850        break;
851      default:
852        panic("SimpleCPU::processRetry: bad state");
853        break;
854    }
855#else
856    panic("shouldn't be here");
857#endif
858}
859
860#if FULL_SYSTEM
861void
862SimpleCPU::post_interrupt(int int_num, int index)
863{
864    BaseCPU::post_interrupt(int_num, index);
865
866    if (xc->status() == ExecContext::Suspended) {
867                DPRINTF(IPI,"Suspended Processor awoke\n");
868        xc->activate();
869    }
870}
871#endif // FULL_SYSTEM
872
873/* start simulation, program loaded, processor precise state initialized */
874void
875SimpleCPU::tick()
876{
877    numCycles++;
878
879    traceData = NULL;
880
881    Fault fault = No_Fault;
882
883#if FULL_SYSTEM
884    if (checkInterrupts && check_interrupts() && !xc->inPalMode() &&
885        status() != IcacheMissComplete) {
886        int ipl = 0;
887        int summary = 0;
888        checkInterrupts = false;
889        IntReg *ipr = xc->regs.ipr;
890
891        if (xc->regs.ipr[TheISA::IPR_SIRR]) {
892            for (int i = TheISA::INTLEVEL_SOFTWARE_MIN;
893                 i < TheISA::INTLEVEL_SOFTWARE_MAX; i++) {
894                if (ipr[TheISA::IPR_SIRR] & (ULL(1) << i)) {
895                    // See table 4-19 of 21164 hardware reference
896                    ipl = (i - TheISA::INTLEVEL_SOFTWARE_MIN) + 1;
897                    summary |= (ULL(1) << i);
898                }
899            }
900        }
901
902        uint64_t interrupts = xc->cpu->intr_status();
903        for (int i = TheISA::INTLEVEL_EXTERNAL_MIN;
904            i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) {
905            if (interrupts & (ULL(1) << i)) {
906                // See table 4-19 of 21164 hardware reference
907                ipl = i;
908                summary |= (ULL(1) << i);
909            }
910        }
911
912        if (ipr[TheISA::IPR_ASTRR])
913            panic("asynchronous traps not implemented\n");
914
915        if (ipl && ipl > xc->regs.ipr[TheISA::IPR_IPLR]) {
916            ipr[TheISA::IPR_ISR] = summary;
917            ipr[TheISA::IPR_INTID] = ipl;
918            xc->ev5_trap(Interrupt_Fault);
919
920            DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
921                    ipr[TheISA::IPR_IPLR], ipl, summary);
922        }
923    }
924#endif
925
926    // maintain $r0 semantics
927    xc->regs.intRegFile[ZeroReg] = 0;
928#ifdef TARGET_ALPHA
929    xc->regs.floatRegFile.d[ZeroReg] = 0.0;
930#endif // TARGET_ALPHA
931
932    if (status() == IcacheAccessComplete) {
933        // We've already fetched an instruction and were stalled on an
934        // I-cache miss.  No need to fetch it again.
935
936        // Set status to running; tick event will get rescheduled if
937        // necessary at end of tick() function.
938        _status = Running;
939    } else {
940        // Try to fetch an instruction
941
942        // set up memory request for instruction fetch
943#if FULL_SYSTEM
944#define IFETCH_FLAGS(pc)	((pc) & 1) ? PHYSICAL : 0
945#else
946#define IFETCH_FLAGS(pc)	0
947#endif
948
949#if SIMPLE_CPU_MEM_TIMING
950        CpuRequest *ifetch_req = new CpuRequest();
951        ifetch_req->size = sizeof(MachInst);
952#endif
953
954        ifetch_req->vaddr = xc->regs.pc & ~3;
955        ifetch_req->time = curTick;
956
957/*	memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t),
958                     IFETCH_FLAGS(xc->regs.pc));
959*/
960
961        fault = xc->translateInstReq(ifetch_req);
962
963        if (fault == No_Fault) {
964#if SIMPLE_CPU_MEM_TIMING
965            Packet *ifetch_pkt = new Packet;
966            ifetch_pkt->cmd = Read;
967            ifetch_pkt->data = (uint8_t *)&inst;
968            ifetch_pkt->req = ifetch_req;
969            ifetch_pkt->size = sizeof(MachInst);
970#endif
971            ifetch_pkt->addr = ifetch_req->paddr;
972
973            sendIcacheRequest(ifetch_pkt);
974#if SIMPLE_CPU_MEM_TIMING || SIMPLE_CPU_MEM_ATOMIC
975            return;
976#endif
977/*
978        if (icacheInterface && fault == No_Fault) {
979            memReq->completionEvent = NULL;
980
981            memReq->time = curTick;
982            memReq->flags |= INST_READ;
983            MemAccessResult result = icacheInterface->access(memReq);
984
985            // Ugly hack to get an event scheduled *only* if the access is
986            // a miss.  We really should add first-class support for this
987            // at some point.
988                if (result != MA_HIT && icacheInterface->doEvents()) {
989                memReq->completionEvent = &cacheCompletionEvent;
990                lastIcacheStall = curTick;
991                unscheduleTickEvent();
992                _status = IcacheMissStall;
993                return;
994            }
995        }
996*/
997        }
998    }
999
1000    // If we've got a valid instruction (i.e., no fault on instruction
1001    // fetch), then execute it.
1002    if (fault == No_Fault) {
1003
1004        // keep an instruction count
1005        numInst++;
1006        numInsts++;
1007
1008        // check for instruction-count-based events
1009        comInstEventQueue[0]->serviceEvents(numInst);
1010
1011        // decode the instruction
1012        inst = gtoh(inst);
1013        curStaticInst = StaticInst<TheISA>::decode(inst);
1014
1015        traceData = Trace::getInstRecord(curTick, xc, this, curStaticInst,
1016                                         xc->regs.pc);
1017
1018#if FULL_SYSTEM
1019        xc->setInst(inst);
1020#endif // FULL_SYSTEM
1021
1022        xc->func_exe_inst++;
1023
1024        fault = curStaticInst->execute(this, traceData);
1025
1026#if FULL_SYSTEM
1027        if (xc->fnbin) {
1028            assert(xc->kernelStats);
1029            system->kernelBinning->execute(xc, inst);
1030        }
1031
1032        if (xc->profile) {
1033            bool usermode = (xc->regs.ipr[AlphaISA::IPR_DTB_CM] & 0x18) != 0;
1034            xc->profilePC = usermode ? 1 : xc->regs.pc;
1035            ProfileNode *node = xc->profile->consume(xc, inst);
1036            if (node)
1037                xc->profileNode = node;
1038        }
1039#endif
1040
1041        if (curStaticInst->isMemRef()) {
1042            numMemRefs++;
1043        }
1044
1045        if (curStaticInst->isLoad()) {
1046            ++numLoad;
1047            comLoadEventQueue[0]->serviceEvents(numLoad);
1048        }
1049
1050        // If we have a dcache miss, then we can't finialize the instruction
1051        // trace yet because we want to populate it with the data later
1052        if (traceData && (status() != DcacheWaitResponse)) {
1053            traceData->finalize();
1054        }
1055
1056        traceFunctions(xc->regs.pc);
1057
1058    }	// if (fault == No_Fault)
1059
1060    if (fault != No_Fault) {
1061#if FULL_SYSTEM
1062        xc->ev5_trap(fault);
1063#else // !FULL_SYSTEM
1064        fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc);
1065#endif // FULL_SYSTEM
1066    }
1067    else {
1068        // go to the next instruction
1069        xc->regs.pc = xc->regs.npc;
1070        xc->regs.npc += sizeof(MachInst);
1071    }
1072
1073#if FULL_SYSTEM
1074    Addr oldpc;
1075    do {
1076        oldpc = xc->regs.pc;
1077        system->pcEventQueue.service(xc);
1078    } while (oldpc != xc->regs.pc);
1079#endif
1080
1081    assert(status() == Running ||
1082           status() == Idle ||
1083           status() == DcacheWaitResponse);
1084
1085    if (status() == Running && !tickEvent.scheduled())
1086        tickEvent.schedule(curTick + cycles(1));
1087}
1088
1089////////////////////////////////////////////////////////////////////////
1090//
1091//  SimpleCPU Simulation Object
1092//
1093BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
1094
1095    Param<Counter> max_insts_any_thread;
1096    Param<Counter> max_insts_all_threads;
1097    Param<Counter> max_loads_any_thread;
1098    Param<Counter> max_loads_all_threads;
1099
1100#if FULL_SYSTEM
1101    SimObjectParam<AlphaITB *> itb;
1102    SimObjectParam<AlphaDTB *> dtb;
1103    SimObjectParam<System *> system;
1104    Param<int> cpu_id;
1105    Param<Tick> profile;
1106#else
1107    SimObjectParam<Memory *> mem;
1108    SimObjectParam<Process *> workload;
1109#endif // FULL_SYSTEM
1110
1111    Param<int> clock;
1112
1113    Param<bool> defer_registration;
1114    Param<int> width;
1115    Param<bool> function_trace;
1116    Param<Tick> function_trace_start;
1117
1118END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
1119
1120BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
1121
1122    INIT_PARAM(max_insts_any_thread,
1123               "terminate when any thread reaches this inst count"),
1124    INIT_PARAM(max_insts_all_threads,
1125               "terminate when all threads have reached this inst count"),
1126    INIT_PARAM(max_loads_any_thread,
1127               "terminate when any thread reaches this load count"),
1128    INIT_PARAM(max_loads_all_threads,
1129               "terminate when all threads have reached this load count"),
1130
1131#if FULL_SYSTEM
1132    INIT_PARAM(itb, "Instruction TLB"),
1133    INIT_PARAM(dtb, "Data TLB"),
1134    INIT_PARAM(system, "system object"),
1135    INIT_PARAM(cpu_id, "processor ID"),
1136    INIT_PARAM(profile, ""),
1137#else
1138    INIT_PARAM(mem, "memory"),
1139    INIT_PARAM(workload, "processes to run"),
1140#endif // FULL_SYSTEM
1141
1142    INIT_PARAM(clock, "clock speed"),
1143    INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
1144    INIT_PARAM(width, "cpu width"),
1145    INIT_PARAM(function_trace, "Enable function trace"),
1146    INIT_PARAM(function_trace_start, "Cycle to start function trace")
1147
1148END_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
1149
1150
1151CREATE_SIM_OBJECT(SimpleCPU)
1152{
1153    SimpleCPU::Params *params = new SimpleCPU::Params();
1154    params->name = getInstanceName();
1155    params->numberOfThreads = 1;
1156    params->max_insts_any_thread = max_insts_any_thread;
1157    params->max_insts_all_threads = max_insts_all_threads;
1158    params->max_loads_any_thread = max_loads_any_thread;
1159    params->max_loads_all_threads = max_loads_all_threads;
1160    params->deferRegistration = defer_registration;
1161    params->clock = clock;
1162    params->functionTrace = function_trace;
1163    params->functionTraceStart = function_trace_start;
1164    params->width = width;
1165
1166#if FULL_SYSTEM
1167    params->itb = itb;
1168    params->dtb = dtb;
1169    params->system = system;
1170    params->cpu_id = cpu_id;
1171    params->profile = profile;
1172#else
1173    params->mem = mem;
1174    params->process = workload;
1175#endif
1176
1177    SimpleCPU *cpu = new SimpleCPU(params);
1178    return cpu;
1179}
1180
1181REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU)
1182
1183