base.cc revision 2359
12SN/A/*
22188SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
32SN/A * All rights reserved.
42SN/A *
52SN/A * Redistribution and use in source and binary forms, with or without
62SN/A * modification, are permitted provided that the following conditions are
72SN/A * met: redistributions of source code must retain the above copyright
82SN/A * notice, this list of conditions and the following disclaimer;
92SN/A * redistributions in binary form must reproduce the above copyright
102SN/A * notice, this list of conditions and the following disclaimer in the
112SN/A * documentation and/or other materials provided with the distribution;
122SN/A * neither the name of the copyright holders nor the names of its
132SN/A * contributors may be used to endorse or promote products derived from
142SN/A * this software without specific prior written permission.
152SN/A *
162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665SN/A */
282665SN/A
292665SN/A#include <iostream>
302665SN/A#include <string>
312665SN/A#include <sstream>
322SN/A
332SN/A#include "base/cprintf.hh"
342SN/A#include "base/loader/symtab.hh"
352SN/A#include "base/misc.hh"
362465SN/A#include "base/output.hh"
373565Sgblack@eecs.umich.edu#include "cpu/base.hh"
385529Snate@binkert.org#include "cpu/exec_context.hh"
398777Sgblack@eecs.umich.edu#include "cpu/profile.hh"
401917SN/A#include "cpu/sampler/sampler.hh"
411070SN/A#include "sim/param.hh"
421917SN/A#include "sim/process.hh"
432188SN/A#include "sim/sim_events.hh"
448777Sgblack@eecs.umich.edu#include "sim/system.hh"
458777Sgblack@eecs.umich.edu
461917SN/A#include "base/trace.hh"
472290SN/A
488777Sgblack@eecs.umich.edu// Hack
498777Sgblack@eecs.umich.edu#include "sim/stat_control.hh"
508706Sandreas.hansson@arm.com
518799Sgblack@eecs.umich.eduusing namespace std;
528809Sgblack@eecs.umich.edu
538793Sgblack@eecs.umich.eduvector<BaseCPU *> BaseCPU::cpuList;
548777Sgblack@eecs.umich.edu
551070SN/A// This variable reflects the max number of threads in any CPU.  Be
561917SN/A// careful to only use it once all the CPUs that you care about have
572519SN/A// been initialized
582SN/Aint maxThreadsPerCPU = 1;
592SN/A
602SN/Avoid
612SN/ACPUProgressEvent::process()
628820Sgblack@eecs.umich.edu{
638820Sgblack@eecs.umich.edu#ifndef NDEBUG
649384SAndreas.Sandberg@arm.com    Counter temp = cpu->totalInstructions();
659384SAndreas.Sandberg@arm.com    double ipc = double(temp - lastNumInst) / (interval / cpu->cycles(1));
669384SAndreas.Sandberg@arm.com    DPRINTFN("%s progress event, instructions committed: %lli, IPC: %0.8d\n",
678766Sgblack@eecs.umich.edu             cpu->name(), temp - lastNumInst, ipc);
688766Sgblack@eecs.umich.edu    ipc = 0.0;
698766Sgblack@eecs.umich.edu    lastNumInst = temp;
708766Sgblack@eecs.umich.edu    schedule(curTick + interval);
719377Sgblack@eecs.umich.edu#endif
722683Sktlim@umich.edu}
736022Sgblack@eecs.umich.edu
749384SAndreas.Sandberg@arm.comconst char *
759384SAndreas.Sandberg@arm.comCPUProgressEvent::description()
769384SAndreas.Sandberg@arm.com{
772SN/A    return "CPU Progress event";
782683Sktlim@umich.edu}
792190SN/A
802680SN/A#if FULL_SYSTEM
812290SN/ABaseCPU::BaseCPU(Params *p)
826316Sgblack@eecs.umich.edu    : SimObject(p->name), clock(p->clock), checkInterrupts(true),
831917SN/A      params(p), number_of_threads(p->numberOfThreads), system(p->system)
848735Sandreas.hanson@arm.com#else
851982SN/ABaseCPU::BaseCPU(Params *p)
861917SN/A    : SimObject(p->name), clock(p->clock), params(p),
872683Sktlim@umich.edu      number_of_threads(p->numberOfThreads)
882683Sktlim@umich.edu#endif
891917SN/A{
901917SN/A//    currentTick = curTick;
911917SN/A    DPRINTF(FullCPU, "BaseCPU: Creating object, mem address %#x.\n", this);
921917SN/A
931917SN/A    // add self to global list of CPUs
941917SN/A    cpuList.push_back(this);
951917SN/A
961917SN/A    DPRINTF(FullCPU, "BaseCPU: CPU added to cpuList, mem address %#x.\n",
972521SN/A            this);
985482Snate@binkert.org
993548Sgblack@eecs.umich.edu    if (number_of_threads > maxThreadsPerCPU)
1002SN/A        maxThreadsPerCPU = number_of_threads;
1012862Sktlim@umich.edu
1022864Sktlim@umich.edu    // allocate per-thread instruction-based event queues
1039384SAndreas.Sandberg@arm.com    comInstEventQueue = new EventQueue *[number_of_threads];
1042190SN/A    for (int i = 0; i < number_of_threads; ++i)
1052683Sktlim@umich.edu        comInstEventQueue[i] = new EventQueue("instruction-based event queue");
1062190SN/A
1072190SN/A    //
1082683Sktlim@umich.edu    // set up instruction-count-based termination events, if any
1091070SN/A    //
1102680SN/A    if (p->max_insts_any_thread != 0)
1111070SN/A        for (int i = 0; i < number_of_threads; ++i)
1121070SN/A            new SimExitEvent(comInstEventQueue[i], p->max_insts_any_thread,
1131917SN/A                "a thread reached the max instruction count");
1142683Sktlim@umich.edu
115180SN/A    if (p->max_insts_all_threads != 0) {
116180SN/A        // allocate & initialize shared downcounter: each event will
1178793Sgblack@eecs.umich.edu        // decrement this when triggered; simulation will terminate
1188793Sgblack@eecs.umich.edu        // when counter reaches 0
1192235SN/A        int *counter = new int;
120180SN/A        *counter = number_of_threads;
1212862Sktlim@umich.edu        for (int i = 0; i < number_of_threads; ++i)
1228793Sgblack@eecs.umich.edu            new CountedExitEvent(comInstEventQueue[i],
1238793Sgblack@eecs.umich.edu                "all threads reached the max instruction count",
1248793Sgblack@eecs.umich.edu                p->max_insts_all_threads, *counter);
1258793Sgblack@eecs.umich.edu    }
1268793Sgblack@eecs.umich.edu
1278793Sgblack@eecs.umich.edu    // allocate per-thread load-based event queues
1288793Sgblack@eecs.umich.edu    comLoadEventQueue = new EventQueue *[number_of_threads];
1298793Sgblack@eecs.umich.edu    for (int i = 0; i < number_of_threads; ++i)
1308793Sgblack@eecs.umich.edu        comLoadEventQueue[i] = new EventQueue("load-based event queue");
1318793Sgblack@eecs.umich.edu
1328793Sgblack@eecs.umich.edu    //
1338793Sgblack@eecs.umich.edu    // set up instruction-count-based termination events, if any
1348793Sgblack@eecs.umich.edu    //
1358793Sgblack@eecs.umich.edu    if (p->max_loads_any_thread != 0)
1368793Sgblack@eecs.umich.edu        for (int i = 0; i < number_of_threads; ++i)
1372313SN/A            new SimExitEvent(comLoadEventQueue[i], p->max_loads_any_thread,
138180SN/A                "a thread reached the max load count");
139180SN/A
140180SN/A    if (p->max_loads_all_threads != 0) {
1416029Ssteve.reinhardt@amd.com        // allocate & initialize shared downcounter: each event will
142180SN/A        // decrement this when triggered; simulation will terminate
143180SN/A        // when counter reaches 0
1442SN/A        int *counter = new int;
1452864Sktlim@umich.edu        *counter = number_of_threads;
1462864Sktlim@umich.edu        for (int i = 0; i < number_of_threads; ++i)
1472864Sktlim@umich.edu            new CountedExitEvent(comLoadEventQueue[i],
1482864Sktlim@umich.edu                "all threads reached the max load count",
1498793Sgblack@eecs.umich.edu                p->max_loads_all_threads, *counter);
1508793Sgblack@eecs.umich.edu    }
1518793Sgblack@eecs.umich.edu
1528793Sgblack@eecs.umich.edu    if (p->stats_reset_inst != 0) {
1538793Sgblack@eecs.umich.edu        Stats::SetupEvent(Stats::Reset, p->stats_reset_inst, 0, comInstEventQueue[0]);
1548793Sgblack@eecs.umich.edu        cprintf("Stats reset event scheduled for %lli insts\n",
1558793Sgblack@eecs.umich.edu                p->stats_reset_inst);
1568793Sgblack@eecs.umich.edu    }
1578793Sgblack@eecs.umich.edu
1582864Sktlim@umich.edu#if FULL_SYSTEM
1592864Sktlim@umich.edu    memset(interrupts, 0, sizeof(interrupts));
1602864Sktlim@umich.edu    intstatus = 0;
1612864Sktlim@umich.edu#endif
1622862Sktlim@umich.edu
1632862Sktlim@umich.edu    functionTracingEnabled = false;
1642862Sktlim@umich.edu    if (p->functionTrace) {
1652862Sktlim@umich.edu        functionTraceStream = simout.find(csprintf("ftrace.%s", name()));
1662862Sktlim@umich.edu        currentFunctionStart = currentFunctionEnd = 0;
1678793Sgblack@eecs.umich.edu        functionEntryTick = p->functionTraceStart;
1688793Sgblack@eecs.umich.edu
1695714Shsul@eecs.umich.edu        if (p->functionTraceStart == 0) {
1705715Shsul@eecs.umich.edu            functionTracingEnabled = true;
1715714Shsul@eecs.umich.edu        } else {
1722862Sktlim@umich.edu            Event *e =
1732862Sktlim@umich.edu                new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this,
1742862Sktlim@umich.edu                                                                         true);
1752683Sktlim@umich.edu            e->schedule(p->functionTraceStart);
176217SN/A        }
1772862Sktlim@umich.edu    }
1786315Sgblack@eecs.umich.edu#if FULL_SYSTEM
1796316Sgblack@eecs.umich.edu    profileEvent = NULL;
1807720Sgblack@eecs.umich.edu    if (params->profile)
181223SN/A        profileEvent = new ProfileEvent(this, params->profile);
1826677SBrad.Beckmann@amd.com#endif
1836677SBrad.Beckmann@amd.com}
1846677SBrad.Beckmann@amd.com
1856677SBrad.Beckmann@amd.comBaseCPU::Params::Params()
1869384SAndreas.Sandberg@arm.com{
187217SN/A#if FULL_SYSTEM
188217SN/A    profile = false;
189217SN/A#endif
190217SN/A    checker = NULL;
1912683Sktlim@umich.edu}
192217SN/A
1932862Sktlim@umich.eduvoid
1946315Sgblack@eecs.umich.eduBaseCPU::enableFunctionTrace()
1956316Sgblack@eecs.umich.edu{
1967720Sgblack@eecs.umich.edu    functionTracingEnabled = true;
197223SN/A}
1986677SBrad.Beckmann@amd.com
1996677SBrad.Beckmann@amd.comBaseCPU::~BaseCPU()
2006677SBrad.Beckmann@amd.com{
2016677SBrad.Beckmann@amd.com}
2029384SAndreas.Sandberg@arm.com
203217SN/Avoid
204217SN/ABaseCPU::init()
2052683Sktlim@umich.edu{
2062683Sktlim@umich.edu    if (!params->deferRegistration)
2072683Sktlim@umich.edu        registerExecContexts();
2088735Sandreas.hanson@arm.com}
2098735Sandreas.hanson@arm.com
2102683Sktlim@umich.eduvoid
2112683Sktlim@umich.eduBaseCPU::startup()
212217SN/A{
213217SN/A#if FULL_SYSTEM
2149180Sandreas.hansson@arm.com    if (!params->deferRegistration && profileEvent)
2152SN/A        profileEvent->schedule(curTick);
2162680SN/A#endif
2172SN/A
2182SN/A    if (params->progress_interval) {
2197823Ssteve.reinhardt@amd.com        new CPUProgressEvent(&mainEventQueue, params->progress_interval,
2202188SN/A                             this);
2214400Srdreslin@umich.edu    }
2225715Shsul@eecs.umich.edu}
2235543Ssaidi@eecs.umich.edu
2244400Srdreslin@umich.edu
2252290SN/Avoid
2262680SN/ABaseCPU::regStats()
2272290SN/A{
2282290SN/A    using namespace Stats;
2298735Sandreas.hanson@arm.com
230393SN/A    numCycles
231393SN/A        .name(name() + ".numCycles")
232393SN/A        .desc("number of cpu cycles simulated")
2332683Sktlim@umich.edu        ;
234393SN/A
2352680SN/A    int size = execContexts.size();
236393SN/A    if (size > 1) {
237393SN/A        for (int i = 0; i < size; ++i) {
2387823Ssteve.reinhardt@amd.com            stringstream namestr;
2397823Ssteve.reinhardt@amd.com            ccprintf(namestr, "%s.ctx%d", name(), i);
2402680SN/A            execContexts[i]->regStats(namestr.str());
2418735Sandreas.hanson@arm.com        }
2422SN/A    } else if (size == 1)
2432SN/A        execContexts[0]->regStats(name());
244393SN/A
245393SN/A#if FULL_SYSTEM
2462683Sktlim@umich.edu#endif
247393SN/A}
2482680SN/A
249393SN/A
250393SN/Avoid
2512680SN/ABaseCPU::registerExecContexts()
2528735Sandreas.hanson@arm.com{
253393SN/A    for (int i = 0; i < execContexts.size(); ++i) {
254393SN/A        ExecContext *xc = execContexts[i];
255393SN/A
256393SN/A        if (xc->status() == ExecContext::Suspended) {
2572683Sktlim@umich.edu#if FULL_SYSTEM
2582SN/A            int id = params->cpu_id;
2598793Sgblack@eecs.umich.edu            if (id != -1)
2602341SN/A                id += i;
2612SN/A
262716SN/A        xc->setCpuId(system->registerExecContext(xc, id));
263716SN/A#else
2642683Sktlim@umich.edu        xc->setCpuId(xc->getProcessPtr()->registerExecContext(xc));
2652190SN/A#endif
2662680SN/A        }
2672190SN/A    }
2682190SN/A}
269
270
271void
272BaseCPU::switchOut(Sampler *sampler)
273{
274//    panic("This CPU doesn't support sampling!");
275#if FULL_SYSTEM
276    if (profileEvent && profileEvent->scheduled())
277        profileEvent->deschedule();
278#endif
279}
280
281void
282BaseCPU::takeOverFrom(BaseCPU *oldCPU)
283{
284//    currentTick = oldCPU->currentTick;
285    assert(execContexts.size() == oldCPU->execContexts.size());
286
287    for (int i = 0; i < execContexts.size(); ++i) {
288        ExecContext *newXC = execContexts[i];
289        ExecContext *oldXC = oldCPU->execContexts[i];
290
291        newXC->takeOverFrom(oldXC);
292        assert(newXC->readCpuId() == oldXC->readCpuId());
293#if FULL_SYSTEM
294        system->replaceExecContext(newXC, newXC->readCpuId());
295#else
296        assert(newXC->getProcessPtr() == oldXC->getProcessPtr());
297        newXC->getProcessPtr()->replaceExecContext(newXC, newXC->readCpuId());
298#endif
299
300//    TheISA::compareXCs(oldXC, newXC);
301    }
302
303#if FULL_SYSTEM
304    for (int i = 0; i < TheISA::NumInterruptLevels; ++i)
305        interrupts[i] = oldCPU->interrupts[i];
306    intstatus = oldCPU->intstatus;
307    checkInterrupts = oldCPU->checkInterrupts;
308
309//    for (int i = 0; i < execContexts.size(); ++i)
310//        execContexts[i]->profileClear();
311
312    // The Sampler must take care of this!
313//    if (profileEvent)
314//        profileEvent->schedule(curTick);
315#endif
316}
317
318
319#if FULL_SYSTEM
320BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval)
321    : Event(&mainEventQueue), cpu(_cpu), interval(_interval)
322{ }
323
324void
325BaseCPU::ProfileEvent::process()
326{
327    for (int i = 0, size = cpu->execContexts.size(); i < size; ++i) {
328        ExecContext *xc = cpu->execContexts[i];
329        xc->profileSample();
330    }
331
332    schedule(curTick + interval);
333}
334
335void
336BaseCPU::post_interrupt(int int_num, int index)
337{
338    DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);
339
340    if (int_num < 0 || int_num >= TheISA::NumInterruptLevels)
341        panic("int_num out of bounds\n");
342
343    if (index < 0 || index >= sizeof(uint64_t) * 8)
344        panic("int_num out of bounds\n");
345
346    checkInterrupts = true;
347    interrupts[int_num] |= 1 << index;
348    intstatus |= (ULL(1) << int_num);
349}
350
351void
352BaseCPU::clear_interrupt(int int_num, int index)
353{
354    DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index);
355
356    if (int_num < 0 || int_num >= TheISA::NumInterruptLevels)
357        panic("int_num out of bounds\n");
358
359    if (index < 0 || index >= sizeof(uint64_t) * 8)
360        panic("int_num out of bounds\n");
361
362    interrupts[int_num] &= ~(1 << index);
363    if (interrupts[int_num] == 0)
364        intstatus &= ~(ULL(1) << int_num);
365}
366
367void
368BaseCPU::clear_interrupts()
369{
370    DPRINTF(Interrupt, "Interrupts all cleared\n");
371
372    memset(interrupts, 0, sizeof(interrupts));
373    intstatus = 0;
374}
375
376
377void
378BaseCPU::serialize(std::ostream &os)
379{
380    SERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels);
381    SERIALIZE_SCALAR(intstatus);
382}
383
384void
385BaseCPU::unserialize(Checkpoint *cp, const std::string &section)
386{
387    UNSERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels);
388    UNSERIALIZE_SCALAR(intstatus);
389}
390
391#endif // FULL_SYSTEM
392
393void
394BaseCPU::traceFunctionsInternal(Addr pc)
395{
396    if (!debugSymbolTable)
397        return;
398
399    // if pc enters different function, print new function symbol and
400    // update saved range.  Otherwise do nothing.
401    if (pc < currentFunctionStart || pc >= currentFunctionEnd) {
402        string sym_str;
403        bool found = debugSymbolTable->findNearestSymbol(pc, sym_str,
404                                                         currentFunctionStart,
405                                                         currentFunctionEnd);
406
407        if (!found) {
408            // no symbol found: use addr as label
409            sym_str = csprintf("0x%x", pc);
410            currentFunctionStart = pc;
411            currentFunctionEnd = pc + 1;
412        }
413
414        ccprintf(*functionTraceStream, " (%d)\n%d: %s",
415                 curTick - functionEntryTick, curTick, sym_str);
416        functionEntryTick = curTick;
417    }
418}
419
420
421DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU)
422