base.cc revision 5496:6899b894166f
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 * Authors: Steve Reinhardt
29 */
30
31#include "arch/utility.hh"
32#include "arch/faults.hh"
33#include "base/cprintf.hh"
34#include "base/inifile.hh"
35#include "base/loader/symtab.hh"
36#include "base/misc.hh"
37#include "base/pollevent.hh"
38#include "base/range.hh"
39#include "base/stats/events.hh"
40#include "base/trace.hh"
41#include "cpu/base.hh"
42#include "cpu/exetrace.hh"
43#include "cpu/profile.hh"
44#include "cpu/simple/base.hh"
45#include "cpu/simple_thread.hh"
46#include "cpu/smt.hh"
47#include "cpu/static_inst.hh"
48#include "cpu/thread_context.hh"
49#include "mem/packet.hh"
50#include "sim/byteswap.hh"
51#include "sim/debug.hh"
52#include "sim/host.hh"
53#include "sim/sim_events.hh"
54#include "sim/sim_object.hh"
55#include "sim/stats.hh"
56#include "sim/system.hh"
57
58#if FULL_SYSTEM
59#include "arch/kernel_stats.hh"
60#include "arch/stacktrace.hh"
61#include "arch/tlb.hh"
62#include "arch/vtophys.hh"
63#include "base/remote_gdb.hh"
64#else // !FULL_SYSTEM
65#include "mem/mem_object.hh"
66#endif // FULL_SYSTEM
67
68using namespace std;
69using namespace TheISA;
70
71BaseSimpleCPU::BaseSimpleCPU(Params *p)
72    : BaseCPU(p), traceData(NULL), thread(NULL), predecoder(NULL)
73{
74#if FULL_SYSTEM
75    thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb);
76#else
77    thread = new SimpleThread(this, /* thread_num */ 0, p->process,
78            p->itb, p->dtb, /* asid */ 0);
79#endif // !FULL_SYSTEM
80
81    thread->setStatus(ThreadContext::Unallocated);
82
83    tc = thread->getTC();
84
85    numInst = 0;
86    startNumInst = 0;
87    numLoad = 0;
88    startNumLoad = 0;
89    lastIcacheStall = 0;
90    lastDcacheStall = 0;
91
92    threadContexts.push_back(tc);
93
94
95    fetchOffset = 0;
96    stayAtPC = false;
97}
98
99BaseSimpleCPU::~BaseSimpleCPU()
100{
101}
102
103void
104BaseSimpleCPU::deallocateContext(int thread_num)
105{
106    // for now, these are equivalent
107    suspendContext(thread_num);
108}
109
110
111void
112BaseSimpleCPU::haltContext(int thread_num)
113{
114    // for now, these are equivalent
115    suspendContext(thread_num);
116}
117
118
119void
120BaseSimpleCPU::regStats()
121{
122    using namespace Stats;
123
124    BaseCPU::regStats();
125
126    numInsts
127        .name(name() + ".num_insts")
128        .desc("Number of instructions executed")
129        ;
130
131    numMemRefs
132        .name(name() + ".num_refs")
133        .desc("Number of memory references")
134        ;
135
136    notIdleFraction
137        .name(name() + ".not_idle_fraction")
138        .desc("Percentage of non-idle cycles")
139        ;
140
141    idleFraction
142        .name(name() + ".idle_fraction")
143        .desc("Percentage of idle cycles")
144        ;
145
146    icacheStallCycles
147        .name(name() + ".icache_stall_cycles")
148        .desc("ICache total stall cycles")
149        .prereq(icacheStallCycles)
150        ;
151
152    dcacheStallCycles
153        .name(name() + ".dcache_stall_cycles")
154        .desc("DCache total stall cycles")
155        .prereq(dcacheStallCycles)
156        ;
157
158    icacheRetryCycles
159        .name(name() + ".icache_retry_cycles")
160        .desc("ICache total retry cycles")
161        .prereq(icacheRetryCycles)
162        ;
163
164    dcacheRetryCycles
165        .name(name() + ".dcache_retry_cycles")
166        .desc("DCache total retry cycles")
167        .prereq(dcacheRetryCycles)
168        ;
169
170    idleFraction = constant(1.0) - notIdleFraction;
171}
172
173void
174BaseSimpleCPU::resetStats()
175{
176//    startNumInst = numInst;
177     notIdleFraction = (_status != Idle);
178}
179
180void
181BaseSimpleCPU::serialize(ostream &os)
182{
183    SERIALIZE_ENUM(_status);
184    BaseCPU::serialize(os);
185//    SERIALIZE_SCALAR(inst);
186    nameOut(os, csprintf("%s.xc.0", name()));
187    thread->serialize(os);
188}
189
190void
191BaseSimpleCPU::unserialize(Checkpoint *cp, const string &section)
192{
193    UNSERIALIZE_ENUM(_status);
194    BaseCPU::unserialize(cp, section);
195//    UNSERIALIZE_SCALAR(inst);
196    thread->unserialize(cp, csprintf("%s.xc.0", section));
197}
198
199void
200change_thread_state(int thread_number, int activate, int priority)
201{
202}
203
204Fault
205BaseSimpleCPU::copySrcTranslate(Addr src)
206{
207#if 0
208    static bool no_warn = true;
209    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
210    // Only support block sizes of 64 atm.
211    assert(blk_size == 64);
212    int offset = src & (blk_size - 1);
213
214    // Make sure block doesn't span page
215    if (no_warn &&
216        (src & PageMask) != ((src + blk_size) & PageMask) &&
217        (src >> 40) != 0xfffffc) {
218        warn("Copied block source spans pages %x.", src);
219        no_warn = false;
220    }
221
222    memReq->reset(src & ~(blk_size - 1), blk_size);
223
224    // translate to physical address
225    Fault fault = thread->translateDataReadReq(req);
226
227    if (fault == NoFault) {
228        thread->copySrcAddr = src;
229        thread->copySrcPhysAddr = memReq->paddr + offset;
230    } else {
231        assert(!fault->isAlignmentFault());
232
233        thread->copySrcAddr = 0;
234        thread->copySrcPhysAddr = 0;
235    }
236    return fault;
237#else
238    return NoFault;
239#endif
240}
241
242Fault
243BaseSimpleCPU::copy(Addr dest)
244{
245#if 0
246    static bool no_warn = true;
247    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
248    // Only support block sizes of 64 atm.
249    assert(blk_size == 64);
250    uint8_t data[blk_size];
251    //assert(thread->copySrcAddr);
252    int offset = dest & (blk_size - 1);
253
254    // Make sure block doesn't span page
255    if (no_warn &&
256        (dest & PageMask) != ((dest + blk_size) & PageMask) &&
257        (dest >> 40) != 0xfffffc) {
258        no_warn = false;
259        warn("Copied block destination spans pages %x. ", dest);
260    }
261
262    memReq->reset(dest & ~(blk_size -1), blk_size);
263    // translate to physical address
264    Fault fault = thread->translateDataWriteReq(req);
265
266    if (fault == NoFault) {
267        Addr dest_addr = memReq->paddr + offset;
268        // Need to read straight from memory since we have more than 8 bytes.
269        memReq->paddr = thread->copySrcPhysAddr;
270        thread->mem->read(memReq, data);
271        memReq->paddr = dest_addr;
272        thread->mem->write(memReq, data);
273        if (dcacheInterface) {
274            memReq->cmd = Copy;
275            memReq->completionEvent = NULL;
276            memReq->paddr = thread->copySrcPhysAddr;
277            memReq->dest = dest_addr;
278            memReq->size = 64;
279            memReq->time = curTick;
280            memReq->flags &= ~INST_READ;
281            dcacheInterface->access(memReq);
282        }
283    }
284    else
285        assert(!fault->isAlignmentFault());
286
287    return fault;
288#else
289    panic("copy not implemented");
290    return NoFault;
291#endif
292}
293
294#if FULL_SYSTEM
295Addr
296BaseSimpleCPU::dbg_vtophys(Addr addr)
297{
298    return vtophys(tc, addr);
299}
300#endif // FULL_SYSTEM
301
302#if FULL_SYSTEM
303void
304BaseSimpleCPU::post_interrupt(int int_num, int index)
305{
306    BaseCPU::post_interrupt(int_num, index);
307
308    if (thread->status() == ThreadContext::Suspended) {
309                DPRINTF(Quiesce,"Suspended Processor awoke\n");
310        thread->activate();
311    }
312}
313#endif // FULL_SYSTEM
314
315void
316BaseSimpleCPU::checkForInterrupts()
317{
318#if FULL_SYSTEM
319    if (check_interrupts(tc)) {
320        Fault interrupt = interrupts.getInterrupt(tc);
321
322        if (interrupt != NoFault) {
323            interrupts.updateIntrInfo(tc);
324            interrupt->invoke(tc);
325        }
326    }
327#endif
328}
329
330
331Fault
332BaseSimpleCPU::setupFetchRequest(Request *req)
333{
334    Addr threadPC = thread->readPC();
335
336    // set up memory request for instruction fetch
337#if ISA_HAS_DELAY_SLOT
338    DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p NNPC:%08p\n",threadPC,
339            thread->readNextPC(),thread->readNextNPC());
340#else
341    DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p\n",threadPC,
342            thread->readNextPC());
343#endif
344
345    Addr fetchPC = (threadPC & PCMask) + fetchOffset;
346    req->setVirt(0, fetchPC, sizeof(MachInst), 0, threadPC);
347
348    Fault fault = thread->translateInstReq(req);
349
350    return fault;
351}
352
353
354void
355BaseSimpleCPU::preExecute()
356{
357    // maintain $r0 semantics
358    thread->setIntReg(ZeroReg, 0);
359#if THE_ISA == ALPHA_ISA
360    thread->setFloatReg(ZeroReg, 0.0);
361#endif // ALPHA_ISA
362
363    // check for instruction-count-based events
364    comInstEventQueue[0]->serviceEvents(numInst);
365
366    // decode the instruction
367    inst = gtoh(inst);
368
369    //If we're not in the middle of a macro instruction
370    if (!curMacroStaticInst) {
371
372        StaticInstPtr instPtr = NULL;
373
374        //Predecode, ie bundle up an ExtMachInst
375        //This should go away once the constructor can be set up properly
376        predecoder.setTC(thread->getTC());
377        //If more fetch data is needed, pass it in.
378        Addr fetchPC = (thread->readPC() & PCMask) + fetchOffset;
379        //if(predecoder.needMoreBytes())
380            predecoder.moreBytes(thread->readPC(), fetchPC, inst);
381        //else
382        //    predecoder.process();
383
384        //If an instruction is ready, decode it. Otherwise, we'll have to
385        //fetch beyond the MachInst at the current pc.
386        if (predecoder.extMachInstReady()) {
387#if THE_ISA == X86_ISA
388            thread->setNextPC(thread->readPC() + predecoder.getInstSize());
389#endif // X86_ISA
390            stayAtPC = false;
391            instPtr = StaticInst::decode(predecoder.getExtMachInst(),
392                                         thread->readPC());
393        } else {
394            stayAtPC = true;
395            fetchOffset += sizeof(MachInst);
396        }
397
398        //If we decoded an instruction and it's microcoded, start pulling
399        //out micro ops
400        if (instPtr && instPtr->isMacroop()) {
401            curMacroStaticInst = instPtr;
402            curStaticInst = curMacroStaticInst->
403                fetchMicroop(thread->readMicroPC());
404        } else {
405            curStaticInst = instPtr;
406        }
407    } else {
408        //Read the next micro op from the macro op
409        curStaticInst = curMacroStaticInst->
410            fetchMicroop(thread->readMicroPC());
411    }
412
413    //If we decoded an instruction this "tick", record information about it.
414    if(curStaticInst)
415    {
416#if TRACING_ON
417        traceData = tracer->getInstRecord(curTick, tc, curStaticInst,
418                                         thread->readPC());
419
420        DPRINTF(Decode,"Decode: Decoded %s instruction: 0x%x\n",
421                curStaticInst->getName(), curStaticInst->machInst);
422#endif // TRACING_ON
423
424#if FULL_SYSTEM
425        thread->setInst(inst);
426#endif // FULL_SYSTEM
427    }
428}
429
430void
431BaseSimpleCPU::postExecute()
432{
433#if FULL_SYSTEM
434    if (thread->profile && curStaticInst) {
435        bool usermode = TheISA::inUserMode(tc);
436        thread->profilePC = usermode ? 1 : thread->readPC();
437        ProfileNode *node = thread->profile->consume(tc, curStaticInst);
438        if (node)
439            thread->profileNode = node;
440    }
441#endif
442
443    if (curStaticInst->isMemRef()) {
444        numMemRefs++;
445    }
446
447    if (curStaticInst->isLoad()) {
448        ++numLoad;
449        comLoadEventQueue[0]->serviceEvents(numLoad);
450    }
451
452    traceFunctions(thread->readPC());
453
454    if (traceData) {
455        traceData->dump();
456        delete traceData;
457        traceData = NULL;
458    }
459}
460
461
462void
463BaseSimpleCPU::advancePC(Fault fault)
464{
465    //Since we're moving to a new pc, zero out the offset
466    fetchOffset = 0;
467    if (fault != NoFault) {
468        curMacroStaticInst = StaticInst::nullStaticInstPtr;
469        predecoder.reset();
470        thread->setMicroPC(0);
471        thread->setNextMicroPC(1);
472        fault->invoke(tc);
473    } else {
474        //If we're at the last micro op for this instruction
475        if (curStaticInst && curStaticInst->isLastMicroop()) {
476            //We should be working with a macro op
477            assert(curMacroStaticInst);
478            //Close out this macro op, and clean up the
479            //microcode state
480            curMacroStaticInst = StaticInst::nullStaticInstPtr;
481            thread->setMicroPC(0);
482            thread->setNextMicroPC(1);
483        }
484        //If we're still in a macro op
485        if (curMacroStaticInst) {
486            //Advance the micro pc
487            thread->setMicroPC(thread->readNextMicroPC());
488            //Advance the "next" micro pc. Note that there are no delay
489            //slots, and micro ops are "word" addressed.
490            thread->setNextMicroPC(thread->readNextMicroPC() + 1);
491        } else {
492            // go to the next instruction
493            thread->setPC(thread->readNextPC());
494            thread->setNextPC(thread->readNextNPC());
495            thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst));
496            assert(thread->readNextPC() != thread->readNextNPC());
497        }
498    }
499}
500
501/*Fault
502BaseSimpleCPU::CacheOp(uint8_t Op, Addr EffAddr)
503{
504    // translate to physical address
505    Fault fault = NoFault;
506    int CacheID = Op & 0x3; // Lower 3 bits identify Cache
507    int CacheOP = Op >> 2; // Upper 3 bits identify Cache Operation
508    if(CacheID > 1)
509      {
510        warn("CacheOps not implemented for secondary/tertiary caches\n");
511      }
512    else
513      {
514        switch(CacheOP)
515          { // Fill Packet Type
516          case 0: warn("Invalidate Cache Op\n");
517            break;
518          case 1: warn("Index Load Tag Cache Op\n");
519            break;
520          case 2: warn("Index Store Tag Cache Op\n");
521            break;
522          case 4: warn("Hit Invalidate Cache Op\n");
523            break;
524          case 5: warn("Fill/Hit Writeback Invalidate Cache Op\n");
525            break;
526          case 6: warn("Hit Writeback\n");
527            break;
528          case 7: warn("Fetch & Lock Cache Op\n");
529            break;
530          default: warn("Unimplemented Cache Op\n");
531          }
532      }
533    return fault;
534}*/
535