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