base.cc revision 7445:dfd04ffc1773
1/*
2 * Copyright (c) 2010 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2002-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Steve Reinhardt
41 */
42
43#include "arch/faults.hh"
44#include "arch/utility.hh"
45#include "base/cp_annotate.hh"
46#include "base/cprintf.hh"
47#include "base/inifile.hh"
48#include "base/loader/symtab.hh"
49#include "base/misc.hh"
50#include "base/pollevent.hh"
51#include "base/range.hh"
52#include "base/stats/events.hh"
53#include "base/trace.hh"
54#include "base/types.hh"
55#include "config/the_isa.hh"
56#include "cpu/base.hh"
57#include "cpu/exetrace.hh"
58#include "cpu/profile.hh"
59#include "cpu/simple/base.hh"
60#include "cpu/simple_thread.hh"
61#include "cpu/smt.hh"
62#include "cpu/static_inst.hh"
63#include "cpu/thread_context.hh"
64#include "mem/packet.hh"
65#include "mem/request.hh"
66#include "params/BaseSimpleCPU.hh"
67#include "sim/byteswap.hh"
68#include "sim/debug.hh"
69#include "sim/sim_events.hh"
70#include "sim/sim_object.hh"
71#include "sim/stats.hh"
72#include "sim/system.hh"
73
74#if FULL_SYSTEM
75#include "arch/kernel_stats.hh"
76#include "arch/stacktrace.hh"
77#include "arch/tlb.hh"
78#include "arch/vtophys.hh"
79#else // !FULL_SYSTEM
80#include "mem/mem_object.hh"
81#endif // FULL_SYSTEM
82
83using namespace std;
84using namespace TheISA;
85
86BaseSimpleCPU::BaseSimpleCPU(BaseSimpleCPUParams *p)
87    : BaseCPU(p), traceData(NULL), thread(NULL), predecoder(NULL)
88{
89#if FULL_SYSTEM
90    thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb);
91#else
92    thread = new SimpleThread(this, /* thread_num */ 0, p->workload[0],
93            p->itb, p->dtb);
94#endif // !FULL_SYSTEM
95
96    thread->setStatus(ThreadContext::Halted);
97
98    tc = thread->getTC();
99
100    numInst = 0;
101    startNumInst = 0;
102    numLoad = 0;
103    startNumLoad = 0;
104    lastIcacheStall = 0;
105    lastDcacheStall = 0;
106
107    threadContexts.push_back(tc);
108
109
110    fetchOffset = 0;
111    stayAtPC = false;
112}
113
114BaseSimpleCPU::~BaseSimpleCPU()
115{
116}
117
118void
119BaseSimpleCPU::deallocateContext(int thread_num)
120{
121    // for now, these are equivalent
122    suspendContext(thread_num);
123}
124
125
126void
127BaseSimpleCPU::haltContext(int thread_num)
128{
129    // for now, these are equivalent
130    suspendContext(thread_num);
131}
132
133
134void
135BaseSimpleCPU::regStats()
136{
137    using namespace Stats;
138
139    BaseCPU::regStats();
140
141    numInsts
142        .name(name() + ".num_insts")
143        .desc("Number of instructions executed")
144        ;
145
146    numMemRefs
147        .name(name() + ".num_refs")
148        .desc("Number of memory references")
149        ;
150
151    notIdleFraction
152        .name(name() + ".not_idle_fraction")
153        .desc("Percentage of non-idle cycles")
154        ;
155
156    idleFraction
157        .name(name() + ".idle_fraction")
158        .desc("Percentage of idle cycles")
159        ;
160
161    icacheStallCycles
162        .name(name() + ".icache_stall_cycles")
163        .desc("ICache total stall cycles")
164        .prereq(icacheStallCycles)
165        ;
166
167    dcacheStallCycles
168        .name(name() + ".dcache_stall_cycles")
169        .desc("DCache total stall cycles")
170        .prereq(dcacheStallCycles)
171        ;
172
173    icacheRetryCycles
174        .name(name() + ".icache_retry_cycles")
175        .desc("ICache total retry cycles")
176        .prereq(icacheRetryCycles)
177        ;
178
179    dcacheRetryCycles
180        .name(name() + ".dcache_retry_cycles")
181        .desc("DCache total retry cycles")
182        .prereq(dcacheRetryCycles)
183        ;
184
185    idleFraction = constant(1.0) - notIdleFraction;
186}
187
188void
189BaseSimpleCPU::resetStats()
190{
191//    startNumInst = numInst;
192     notIdleFraction = (_status != Idle);
193}
194
195void
196BaseSimpleCPU::serialize(ostream &os)
197{
198    SERIALIZE_ENUM(_status);
199    BaseCPU::serialize(os);
200//    SERIALIZE_SCALAR(inst);
201    nameOut(os, csprintf("%s.xc.0", name()));
202    thread->serialize(os);
203}
204
205void
206BaseSimpleCPU::unserialize(Checkpoint *cp, const string &section)
207{
208    UNSERIALIZE_ENUM(_status);
209    BaseCPU::unserialize(cp, section);
210//    UNSERIALIZE_SCALAR(inst);
211    thread->unserialize(cp, csprintf("%s.xc.0", section));
212}
213
214void
215change_thread_state(ThreadID tid, int activate, int priority)
216{
217}
218
219void
220BaseSimpleCPU::prefetch(Addr addr, unsigned flags)
221{
222    if (traceData) {
223        traceData->setAddr(addr);
224    }
225
226    // need to do this...
227}
228
229void
230BaseSimpleCPU::writeHint(Addr addr, int size, unsigned flags)
231{
232    if (traceData) {
233        traceData->setAddr(addr);
234    }
235
236    // need to do this...
237}
238
239
240Fault
241BaseSimpleCPU::copySrcTranslate(Addr src)
242{
243#if 0
244    static bool no_warn = true;
245    unsigned blk_size =
246        (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
247    // Only support block sizes of 64 atm.
248    assert(blk_size == 64);
249    int offset = src & (blk_size - 1);
250
251    // Make sure block doesn't span page
252    if (no_warn &&
253        (src & PageMask) != ((src + blk_size) & PageMask) &&
254        (src >> 40) != 0xfffffc) {
255        warn("Copied block source spans pages %x.", src);
256        no_warn = false;
257    }
258
259    memReq->reset(src & ~(blk_size - 1), blk_size);
260
261    // translate to physical address
262    Fault fault = thread->translateDataReadReq(req);
263
264    if (fault == NoFault) {
265        thread->copySrcAddr = src;
266        thread->copySrcPhysAddr = memReq->paddr + offset;
267    } else {
268        assert(!fault->isAlignmentFault());
269
270        thread->copySrcAddr = 0;
271        thread->copySrcPhysAddr = 0;
272    }
273    return fault;
274#else
275    return NoFault;
276#endif
277}
278
279Fault
280BaseSimpleCPU::copy(Addr dest)
281{
282#if 0
283    static bool no_warn = true;
284    unsigned blk_size =
285        (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
286    // Only support block sizes of 64 atm.
287    assert(blk_size == 64);
288    uint8_t data[blk_size];
289    //assert(thread->copySrcAddr);
290    int offset = dest & (blk_size - 1);
291
292    // Make sure block doesn't span page
293    if (no_warn &&
294        (dest & PageMask) != ((dest + blk_size) & PageMask) &&
295        (dest >> 40) != 0xfffffc) {
296        no_warn = false;
297        warn("Copied block destination spans pages %x. ", dest);
298    }
299
300    memReq->reset(dest & ~(blk_size -1), blk_size);
301    // translate to physical address
302    Fault fault = thread->translateDataWriteReq(req);
303
304    if (fault == NoFault) {
305        Addr dest_addr = memReq->paddr + offset;
306        // Need to read straight from memory since we have more than 8 bytes.
307        memReq->paddr = thread->copySrcPhysAddr;
308        thread->mem->read(memReq, data);
309        memReq->paddr = dest_addr;
310        thread->mem->write(memReq, data);
311        if (dcacheInterface) {
312            memReq->cmd = Copy;
313            memReq->completionEvent = NULL;
314            memReq->paddr = thread->copySrcPhysAddr;
315            memReq->dest = dest_addr;
316            memReq->size = 64;
317            memReq->time = curTick;
318            dcacheInterface->access(memReq);
319        }
320    }
321    else
322        assert(!fault->isAlignmentFault());
323
324    return fault;
325#else
326    panic("copy not implemented");
327    return NoFault;
328#endif
329}
330
331#if FULL_SYSTEM
332Addr
333BaseSimpleCPU::dbg_vtophys(Addr addr)
334{
335    return vtophys(tc, addr);
336}
337#endif // FULL_SYSTEM
338
339#if FULL_SYSTEM
340void
341BaseSimpleCPU::wakeup()
342{
343    if (thread->status() != ThreadContext::Suspended)
344        return;
345
346    DPRINTF(Quiesce,"Suspended Processor awoke\n");
347    thread->activate();
348}
349#endif // FULL_SYSTEM
350
351void
352BaseSimpleCPU::checkForInterrupts()
353{
354#if FULL_SYSTEM
355    if (checkInterrupts(tc)) {
356        Fault interrupt = interrupts->getInterrupt(tc);
357
358        if (interrupt != NoFault) {
359            fetchOffset = 0;
360            interrupts->updateIntrInfo(tc);
361            interrupt->invoke(tc);
362            predecoder.reset();
363        }
364    }
365#endif
366}
367
368
369void
370BaseSimpleCPU::setupFetchRequest(Request *req)
371{
372    Addr threadPC = thread->readPC();
373
374    // set up memory request for instruction fetch
375#if ISA_HAS_DELAY_SLOT
376    DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p NNPC:%08p\n",threadPC,
377            thread->readNextPC(),thread->readNextNPC());
378#else
379    DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p\n",threadPC,
380            thread->readNextPC());
381#endif
382
383    Addr fetchPC = (threadPC & PCMask) + fetchOffset;
384    req->setVirt(0, fetchPC, sizeof(MachInst), Request::INST_FETCH, threadPC);
385}
386
387
388void
389BaseSimpleCPU::preExecute()
390{
391    // maintain $r0 semantics
392    thread->setIntReg(ZeroReg, 0);
393#if THE_ISA == ALPHA_ISA
394    thread->setFloatReg(ZeroReg, 0.0);
395#endif // ALPHA_ISA
396
397    // check for instruction-count-based events
398    comInstEventQueue[0]->serviceEvents(numInst);
399
400    // decode the instruction
401    inst = gtoh(inst);
402
403    MicroPC upc = thread->readMicroPC();
404
405    if (isRomMicroPC(upc)) {
406        stayAtPC = false;
407        curStaticInst = microcodeRom.fetchMicroop(upc, curMacroStaticInst);
408    } else if (!curMacroStaticInst) {
409        //We're not in the middle of a macro instruction
410        StaticInstPtr instPtr = NULL;
411
412        //Predecode, ie bundle up an ExtMachInst
413        //This should go away once the constructor can be set up properly
414        predecoder.setTC(thread->getTC());
415        //If more fetch data is needed, pass it in.
416        Addr fetchPC = (thread->readPC() & PCMask) + fetchOffset;
417        //if(predecoder.needMoreBytes())
418            predecoder.moreBytes(thread->readPC(), fetchPC, inst);
419        //else
420        //    predecoder.process();
421
422        //If an instruction is ready, decode it. Otherwise, we'll have to
423        //fetch beyond the MachInst at the current pc.
424        if (predecoder.extMachInstReady()) {
425#if THE_ISA == X86_ISA || THE_ISA == ARM_ISA
426            thread->setNextPC(thread->readPC() + predecoder.getInstSize());
427#endif // X86_ISA
428            stayAtPC = false;
429            instPtr = StaticInst::decode(predecoder.getExtMachInst(),
430                                         thread->readPC());
431        } else {
432            stayAtPC = true;
433            fetchOffset += sizeof(MachInst);
434        }
435
436        //If we decoded an instruction and it's microcoded, start pulling
437        //out micro ops
438        if (instPtr && instPtr->isMacroop()) {
439            curMacroStaticInst = instPtr;
440            curStaticInst = curMacroStaticInst->fetchMicroop(upc);
441        } else {
442            curStaticInst = instPtr;
443        }
444    } else {
445        //Read the next micro op from the macro op
446        curStaticInst = curMacroStaticInst->fetchMicroop(upc);
447    }
448
449    //If we decoded an instruction this "tick", record information about it.
450    if(curStaticInst)
451    {
452#if TRACING_ON
453        traceData = tracer->getInstRecord(curTick, tc,
454                curStaticInst, thread->readPC(),
455                curMacroStaticInst, thread->readMicroPC());
456
457        DPRINTF(Decode,"Decode: Decoded %s instruction: 0x%x\n",
458                curStaticInst->getName(), curStaticInst->machInst);
459#endif // TRACING_ON
460
461#if FULL_SYSTEM
462        thread->setInst(inst);
463#endif // FULL_SYSTEM
464    }
465}
466
467void
468BaseSimpleCPU::postExecute()
469{
470#if FULL_SYSTEM
471    if (thread->profile && curStaticInst) {
472        bool usermode = TheISA::inUserMode(tc);
473        thread->profilePC = usermode ? 1 : thread->readPC();
474        ProfileNode *node = thread->profile->consume(tc, curStaticInst);
475        if (node)
476            thread->profileNode = node;
477    }
478#endif
479
480    if (curStaticInst->isMemRef()) {
481        numMemRefs++;
482    }
483
484    if (curStaticInst->isLoad()) {
485        ++numLoad;
486        comLoadEventQueue[0]->serviceEvents(numLoad);
487    }
488
489    if (CPA::available()) {
490        CPA::cpa()->swAutoBegin(tc, thread->readNextPC());
491    }
492
493    traceFunctions(thread->readPC());
494
495    if (traceData) {
496        traceData->dump();
497        delete traceData;
498        traceData = NULL;
499    }
500}
501
502
503void
504BaseSimpleCPU::advancePC(Fault fault)
505{
506    //Since we're moving to a new pc, zero out the offset
507    fetchOffset = 0;
508    if (fault != NoFault) {
509        curMacroStaticInst = StaticInst::nullStaticInstPtr;
510        fault->invoke(tc);
511        predecoder.reset();
512    } else {
513        //If we're at the last micro op for this instruction
514        if (curStaticInst && curStaticInst->isLastMicroop()) {
515            //We should be working with a macro op or be in the ROM
516            assert(curMacroStaticInst ||
517                    isRomMicroPC(thread->readMicroPC()));
518            //Close out this macro op, and clean up the
519            //microcode state
520            curMacroStaticInst = StaticInst::nullStaticInstPtr;
521            thread->setMicroPC(normalMicroPC(0));
522            thread->setNextMicroPC(normalMicroPC(1));
523        }
524        //If we're still in a macro op
525        if (curMacroStaticInst || isRomMicroPC(thread->readMicroPC())) {
526            //Advance the micro pc
527            thread->setMicroPC(thread->readNextMicroPC());
528            //Advance the "next" micro pc. Note that there are no delay
529            //slots, and micro ops are "word" addressed.
530            thread->setNextMicroPC(thread->readNextMicroPC() + 1);
531        } else {
532            // go to the next instruction
533            thread->setPC(thread->readNextPC());
534            thread->setNextPC(thread->readNextNPC());
535            thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst));
536            assert(thread->readNextPC() != thread->readNextNPC());
537        }
538    }
539}
540
541/*Fault
542BaseSimpleCPU::CacheOp(uint8_t Op, Addr EffAddr)
543{
544    // translate to physical address
545    Fault fault = NoFault;
546    int CacheID = Op & 0x3; // Lower 3 bits identify Cache
547    int CacheOP = Op >> 2; // Upper 3 bits identify Cache Operation
548    if(CacheID > 1)
549      {
550        warn("CacheOps not implemented for secondary/tertiary caches\n");
551      }
552    else
553      {
554        switch(CacheOP)
555          { // Fill Packet Type
556          case 0: warn("Invalidate Cache Op\n");
557            break;
558          case 1: warn("Index Load Tag Cache Op\n");
559            break;
560          case 2: warn("Index Store Tag Cache Op\n");
561            break;
562          case 4: warn("Hit Invalidate Cache Op\n");
563            break;
564          case 5: warn("Fill/Hit Writeback Invalidate Cache Op\n");
565            break;
566          case 6: warn("Hit Writeback\n");
567            break;
568          case 7: warn("Fetch & Lock Cache Op\n");
569            break;
570          default: warn("Unimplemented Cache Op\n");
571          }
572      }
573    return fault;
574}*/
575