base.cc revision 8229
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/loader/symtab.hh"
46#include "base/cp_annotate.hh"
47#include "base/cprintf.hh"
48#include "base/inifile.hh"
49#include "base/misc.hh"
50#include "base/pollevent.hh"
51#include "base/range.hh"
52#include "base/trace.hh"
53#include "base/types.hh"
54#include "config/the_isa.hh"
55#include "cpu/simple/base.hh"
56#include "cpu/base.hh"
57#include "cpu/exetrace.hh"
58#include "cpu/profile.hh"
59#include "cpu/simple_thread.hh"
60#include "cpu/smt.hh"
61#include "cpu/static_inst.hh"
62#include "cpu/thread_context.hh"
63#include "mem/packet.hh"
64#include "mem/request.hh"
65#include "params/BaseSimpleCPU.hh"
66#include "sim/byteswap.hh"
67#include "sim/debug.hh"
68#include "sim/sim_events.hh"
69#include "sim/sim_object.hh"
70#include "sim/stats.hh"
71#include "sim/system.hh"
72
73#if FULL_SYSTEM
74#include "arch/kernel_stats.hh"
75#include "arch/stacktrace.hh"
76#include "arch/tlb.hh"
77#include "arch/vtophys.hh"
78#else // !FULL_SYSTEM
79#include "mem/mem_object.hh"
80#endif // FULL_SYSTEM
81
82using namespace std;
83using namespace TheISA;
84
85BaseSimpleCPU::BaseSimpleCPU(BaseSimpleCPUParams *p)
86    : BaseCPU(p), traceData(NULL), thread(NULL), predecoder(NULL)
87{
88#if FULL_SYSTEM
89    thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb);
90#else
91    thread = new SimpleThread(this, /* thread_num */ 0, p->workload[0],
92            p->itb, p->dtb);
93#endif // !FULL_SYSTEM
94
95    thread->setStatus(ThreadContext::Halted);
96
97    tc = thread->getTC();
98
99    numInst = 0;
100    startNumInst = 0;
101    numLoad = 0;
102    startNumLoad = 0;
103    lastIcacheStall = 0;
104    lastDcacheStall = 0;
105
106    threadContexts.push_back(tc);
107
108
109    fetchOffset = 0;
110    stayAtPC = false;
111}
112
113BaseSimpleCPU::~BaseSimpleCPU()
114{
115}
116
117void
118BaseSimpleCPU::deallocateContext(int thread_num)
119{
120    // for now, these are equivalent
121    suspendContext(thread_num);
122}
123
124
125void
126BaseSimpleCPU::haltContext(int thread_num)
127{
128    // for now, these are equivalent
129    suspendContext(thread_num);
130}
131
132
133void
134BaseSimpleCPU::regStats()
135{
136    using namespace Stats;
137
138    BaseCPU::regStats();
139
140    numInsts
141        .name(name() + ".num_insts")
142        .desc("Number of instructions executed")
143        ;
144
145    numIntAluAccesses
146        .name(name() + ".num_int_alu_accesses")
147        .desc("Number of integer alu accesses")
148        ;
149
150    numFpAluAccesses
151        .name(name() + ".num_fp_alu_accesses")
152        .desc("Number of float alu accesses")
153        ;
154
155    numCallsReturns
156        .name(name() + ".num_func_calls")
157        .desc("number of times a function call or return occured")
158        ;
159
160    numCondCtrlInsts
161        .name(name() + ".num_conditional_control_insts")
162        .desc("number of instructions that are conditional controls")
163        ;
164
165    numIntInsts
166        .name(name() + ".num_int_insts")
167        .desc("number of integer instructions")
168        ;
169
170    numFpInsts
171        .name(name() + ".num_fp_insts")
172        .desc("number of float instructions")
173        ;
174
175    numIntRegReads
176        .name(name() + ".num_int_register_reads")
177        .desc("number of times the integer registers were read")
178        ;
179
180    numIntRegWrites
181        .name(name() + ".num_int_register_writes")
182        .desc("number of times the integer registers were written")
183        ;
184
185    numFpRegReads
186        .name(name() + ".num_fp_register_reads")
187        .desc("number of times the floating registers were read")
188        ;
189
190    numFpRegWrites
191        .name(name() + ".num_fp_register_writes")
192        .desc("number of times the floating registers were written")
193        ;
194
195    numMemRefs
196        .name(name()+".num_mem_refs")
197        .desc("number of memory refs")
198        ;
199
200    numStoreInsts
201        .name(name() + ".num_store_insts")
202        .desc("Number of store instructions")
203        ;
204
205    numLoadInsts
206        .name(name() + ".num_load_insts")
207        .desc("Number of load instructions")
208        ;
209
210    notIdleFraction
211        .name(name() + ".not_idle_fraction")
212        .desc("Percentage of non-idle cycles")
213        ;
214
215    idleFraction
216        .name(name() + ".idle_fraction")
217        .desc("Percentage of idle cycles")
218        ;
219
220    numBusyCycles
221        .name(name() + ".num_busy_cycles")
222        .desc("Number of busy cycles")
223        ;
224
225    numIdleCycles
226        .name(name()+".num_idle_cycles")
227        .desc("Number of idle cycles")
228        ;
229
230    icacheStallCycles
231        .name(name() + ".icache_stall_cycles")
232        .desc("ICache total stall cycles")
233        .prereq(icacheStallCycles)
234        ;
235
236    dcacheStallCycles
237        .name(name() + ".dcache_stall_cycles")
238        .desc("DCache total stall cycles")
239        .prereq(dcacheStallCycles)
240        ;
241
242    icacheRetryCycles
243        .name(name() + ".icache_retry_cycles")
244        .desc("ICache total retry cycles")
245        .prereq(icacheRetryCycles)
246        ;
247
248    dcacheRetryCycles
249        .name(name() + ".dcache_retry_cycles")
250        .desc("DCache total retry cycles")
251        .prereq(dcacheRetryCycles)
252        ;
253
254    idleFraction = constant(1.0) - notIdleFraction;
255    numIdleCycles = idleFraction * numCycles;
256    numBusyCycles = (notIdleFraction)*numCycles;
257}
258
259void
260BaseSimpleCPU::resetStats()
261{
262//    startNumInst = numInst;
263     notIdleFraction = (_status != Idle);
264}
265
266void
267BaseSimpleCPU::serialize(ostream &os)
268{
269    SERIALIZE_ENUM(_status);
270    BaseCPU::serialize(os);
271//    SERIALIZE_SCALAR(inst);
272    nameOut(os, csprintf("%s.xc.0", name()));
273    thread->serialize(os);
274}
275
276void
277BaseSimpleCPU::unserialize(Checkpoint *cp, const string &section)
278{
279    UNSERIALIZE_ENUM(_status);
280    BaseCPU::unserialize(cp, section);
281//    UNSERIALIZE_SCALAR(inst);
282    thread->unserialize(cp, csprintf("%s.xc.0", section));
283}
284
285void
286change_thread_state(ThreadID tid, int activate, int priority)
287{
288}
289
290#if FULL_SYSTEM
291Addr
292BaseSimpleCPU::dbg_vtophys(Addr addr)
293{
294    return vtophys(tc, addr);
295}
296#endif // FULL_SYSTEM
297
298#if FULL_SYSTEM
299void
300BaseSimpleCPU::wakeup()
301{
302    if (thread->status() != ThreadContext::Suspended)
303        return;
304
305    DPRINTF(Quiesce,"Suspended Processor awoke\n");
306    thread->activate();
307}
308#endif // FULL_SYSTEM
309
310void
311BaseSimpleCPU::checkForInterrupts()
312{
313#if FULL_SYSTEM
314    if (checkInterrupts(tc)) {
315        Fault interrupt = interrupts->getInterrupt(tc);
316
317        if (interrupt != NoFault) {
318            fetchOffset = 0;
319            interrupts->updateIntrInfo(tc);
320            interrupt->invoke(tc);
321            predecoder.reset();
322        }
323    }
324#endif
325}
326
327
328void
329BaseSimpleCPU::setupFetchRequest(Request *req)
330{
331    Addr instAddr = thread->instAddr();
332
333    // set up memory request for instruction fetch
334    DPRINTF(Fetch, "Fetch: PC:%08p\n", instAddr);
335
336    Addr fetchPC = (instAddr & PCMask) + fetchOffset;
337    req->setVirt(0, fetchPC, sizeof(MachInst), Request::INST_FETCH, instAddr);
338}
339
340
341void
342BaseSimpleCPU::preExecute()
343{
344    // maintain $r0 semantics
345    thread->setIntReg(ZeroReg, 0);
346#if THE_ISA == ALPHA_ISA
347    thread->setFloatReg(ZeroReg, 0.0);
348#endif // ALPHA_ISA
349
350    // check for instruction-count-based events
351    comInstEventQueue[0]->serviceEvents(numInst);
352    system->instEventQueue.serviceEvents(system->totalNumInsts);
353
354    // decode the instruction
355    inst = gtoh(inst);
356
357    TheISA::PCState pcState = thread->pcState();
358
359    if (isRomMicroPC(pcState.microPC())) {
360        stayAtPC = false;
361        curStaticInst = microcodeRom.fetchMicroop(pcState.microPC(),
362                                                  curMacroStaticInst);
363    } else if (!curMacroStaticInst) {
364        //We're not in the middle of a macro instruction
365        StaticInstPtr instPtr = NULL;
366
367        //Predecode, ie bundle up an ExtMachInst
368        //This should go away once the constructor can be set up properly
369        predecoder.setTC(thread->getTC());
370        //If more fetch data is needed, pass it in.
371        Addr fetchPC = (pcState.instAddr() & PCMask) + fetchOffset;
372        //if(predecoder.needMoreBytes())
373            predecoder.moreBytes(pcState, fetchPC, inst);
374        //else
375        //    predecoder.process();
376
377        //If an instruction is ready, decode it. Otherwise, we'll have to
378        //fetch beyond the MachInst at the current pc.
379        if (predecoder.extMachInstReady()) {
380            stayAtPC = false;
381            ExtMachInst machInst = predecoder.getExtMachInst(pcState);
382            thread->pcState(pcState);
383            instPtr = StaticInst::decode(machInst, pcState.instAddr());
384        } else {
385            stayAtPC = true;
386            fetchOffset += sizeof(MachInst);
387        }
388
389        //If we decoded an instruction and it's microcoded, start pulling
390        //out micro ops
391        if (instPtr && instPtr->isMacroop()) {
392            curMacroStaticInst = instPtr;
393            curStaticInst = curMacroStaticInst->fetchMicroop(pcState.microPC());
394        } else {
395            curStaticInst = instPtr;
396        }
397    } else {
398        //Read the next micro op from the macro op
399        curStaticInst = curMacroStaticInst->fetchMicroop(pcState.microPC());
400    }
401
402    //If we decoded an instruction this "tick", record information about it.
403    if(curStaticInst)
404    {
405#if TRACING_ON
406        traceData = tracer->getInstRecord(curTick(), tc,
407                curStaticInst, thread->pcState(), curMacroStaticInst);
408
409        DPRINTF(Decode,"Decode: Decoded %s instruction: 0x%x\n",
410                curStaticInst->getName(), curStaticInst->machInst);
411#endif // TRACING_ON
412    }
413}
414
415void
416BaseSimpleCPU::postExecute()
417{
418    assert(curStaticInst);
419
420    TheISA::PCState pc = tc->pcState();
421    Addr instAddr = pc.instAddr();
422#if FULL_SYSTEM
423    if (thread->profile) {
424        bool usermode = TheISA::inUserMode(tc);
425        thread->profilePC = usermode ? 1 : instAddr;
426        ProfileNode *node = thread->profile->consume(tc, curStaticInst);
427        if (node)
428            thread->profileNode = node;
429    }
430#endif
431
432    if (curStaticInst->isMemRef()) {
433        numMemRefs++;
434    }
435
436    if (curStaticInst->isLoad()) {
437        ++numLoad;
438        comLoadEventQueue[0]->serviceEvents(numLoad);
439    }
440
441    if (CPA::available()) {
442        CPA::cpa()->swAutoBegin(tc, pc.nextInstAddr());
443    }
444
445    /* Power model statistics */
446    //integer alu accesses
447    if (curStaticInst->isInteger()){
448        numIntAluAccesses++;
449        numIntInsts++;
450    }
451
452    //float alu accesses
453    if (curStaticInst->isFloating()){
454        numFpAluAccesses++;
455        numFpInsts++;
456    }
457
458    //number of function calls/returns to get window accesses
459    if (curStaticInst->isCall() || curStaticInst->isReturn()){
460        numCallsReturns++;
461    }
462
463    //the number of branch predictions that will be made
464    if (curStaticInst->isCondCtrl()){
465        numCondCtrlInsts++;
466    }
467
468    //result bus acceses
469    if (curStaticInst->isLoad()){
470        numLoadInsts++;
471    }
472
473    if (curStaticInst->isStore()){
474        numStoreInsts++;
475    }
476    /* End power model statistics */
477
478    traceFunctions(instAddr);
479
480    if (traceData) {
481        traceData->dump();
482        delete traceData;
483        traceData = NULL;
484    }
485}
486
487
488void
489BaseSimpleCPU::advancePC(Fault fault)
490{
491    //Since we're moving to a new pc, zero out the offset
492    fetchOffset = 0;
493    if (fault != NoFault) {
494        curMacroStaticInst = StaticInst::nullStaticInstPtr;
495        fault->invoke(tc, curStaticInst);
496        predecoder.reset();
497    } else {
498        if (curStaticInst) {
499            if (curStaticInst->isLastMicroop())
500                curMacroStaticInst = StaticInst::nullStaticInstPtr;
501            TheISA::PCState pcState = thread->pcState();
502            TheISA::advancePC(pcState, curStaticInst);
503            thread->pcState(pcState);
504        }
505    }
506}
507
508/*Fault
509BaseSimpleCPU::CacheOp(uint8_t Op, Addr EffAddr)
510{
511    // translate to physical address
512    Fault fault = NoFault;
513    int CacheID = Op & 0x3; // Lower 3 bits identify Cache
514    int CacheOP = Op >> 2; // Upper 3 bits identify Cache Operation
515    if(CacheID > 1)
516      {
517        warn("CacheOps not implemented for secondary/tertiary caches\n");
518      }
519    else
520      {
521        switch(CacheOP)
522          { // Fill Packet Type
523          case 0: warn("Invalidate Cache Op\n");
524            break;
525          case 1: warn("Index Load Tag Cache Op\n");
526            break;
527          case 2: warn("Index Store Tag Cache Op\n");
528            break;
529          case 4: warn("Hit Invalidate Cache Op\n");
530            break;
531          case 5: warn("Fill/Hit Writeback Invalidate Cache Op\n");
532            break;
533          case 6: warn("Hit Writeback\n");
534            break;
535          case 7: warn("Fetch & Lock Cache Op\n");
536            break;
537          default: warn("Unimplemented Cache Op\n");
538          }
539      }
540    return fault;
541}*/
542