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