base.cc revision 10464
12SN/A/* 28922Swilliam.wang@arm.com * Copyright (c) 2011-2012 ARM Limited 38707Sandreas.hansson@arm.com * All rights reserved 48707Sandreas.hansson@arm.com * 58707Sandreas.hansson@arm.com * The license below extends only to copyright in the software and shall 68707Sandreas.hansson@arm.com * not be construed as granting a license to any other intellectual 78707Sandreas.hansson@arm.com * property including but not limited to intellectual property relating 88707Sandreas.hansson@arm.com * to a hardware implementation of the functionality of the software 98707Sandreas.hansson@arm.com * licensed hereunder. You may use the software subject to the license 108707Sandreas.hansson@arm.com * terms below provided that you ensure that this notice is replicated 118707Sandreas.hansson@arm.com * unmodified and in its entirety in all distributions of the software, 128707Sandreas.hansson@arm.com * modified or unmodified, in source code or in binary form. 138707Sandreas.hansson@arm.com * 141762SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 157897Shestness@cs.utexas.edu * Copyright (c) 2011 Regents of the University of California 169983Sstever@gmail.com * Copyright (c) 2013 Advanced Micro Devices, Inc. 179983Sstever@gmail.com * Copyright (c) 2013 Mark D. Hill and David A. Wood 182SN/A * All rights reserved. 192SN/A * 202SN/A * Redistribution and use in source and binary forms, with or without 212SN/A * modification, are permitted provided that the following conditions are 222SN/A * met: redistributions of source code must retain the above copyright 232SN/A * notice, this list of conditions and the following disclaimer; 242SN/A * redistributions in binary form must reproduce the above copyright 252SN/A * notice, this list of conditions and the following disclaimer in the 262SN/A * documentation and/or other materials provided with the distribution; 272SN/A * neither the name of the copyright holders nor the names of its 282SN/A * contributors may be used to endorse or promote products derived from 292SN/A * this software without specific prior written permission. 302SN/A * 312SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 322SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 332SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 342SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 352SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 362SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 372SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 382SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 392SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 402SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 412SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 422665Ssaidi@eecs.umich.edu * 432665Ssaidi@eecs.umich.edu * Authors: Steve Reinhardt 442665Ssaidi@eecs.umich.edu * Nathan Binkert 457897Shestness@cs.utexas.edu * Rick Strong 462SN/A */ 472SN/A 481388SN/A#include <iostream> 498229Snate@binkert.org#include <sstream> 502SN/A#include <string> 512SN/A 527781SAli.Saidi@ARM.com#include "arch/tlb.hh" 538229Snate@binkert.org#include "base/loader/symtab.hh" 541191SN/A#include "base/cprintf.hh" 551191SN/A#include "base/misc.hh" 561388SN/A#include "base/output.hh" 575529Snate@binkert.org#include "base/trace.hh" 581717SN/A#include "cpu/base.hh" 598887Sgeoffrey.blake@arm.com#include "cpu/checker/cpu.hh" 602651Ssaidi@eecs.umich.edu#include "cpu/cpuevent.hh" 618229Snate@binkert.org#include "cpu/profile.hh" 622680Sktlim@umich.edu#include "cpu/thread_context.hh" 638232Snate@binkert.org#include "debug/SyscallVerbose.hh" 645529Snate@binkert.org#include "params/BaseCPU.hh" 658779Sgblack@eecs.umich.edu#include "sim/full_system.hh" 662190SN/A#include "sim/process.hh" 6756SN/A#include "sim/sim_events.hh" 688229Snate@binkert.org#include "sim/sim_exit.hh" 692190SN/A#include "sim/system.hh" 702SN/A 712359SN/A// Hack 722359SN/A#include "sim/stat_control.hh" 732359SN/A 742SN/Ausing namespace std; 752SN/A 762SN/Avector<BaseCPU *> BaseCPU::cpuList; 772SN/A 782SN/A// This variable reflects the max number of threads in any CPU. Be 792SN/A// careful to only use it once all the CPUs that you care about have 802SN/A// been initialized 812SN/Aint maxThreadsPerCPU = 1; 822SN/A 835606Snate@binkert.orgCPUProgressEvent::CPUProgressEvent(BaseCPU *_cpu, Tick ival) 846144Sksewell@umich.edu : Event(Event::Progress_Event_Pri), _interval(ival), lastNumInst(0), 856144Sksewell@umich.edu cpu(_cpu), _repeatEvent(true) 863126Sktlim@umich.edu{ 876144Sksewell@umich.edu if (_interval) 887823Ssteve.reinhardt@amd.com cpu->schedule(this, curTick() + _interval); 893126Sktlim@umich.edu} 903126Sktlim@umich.edu 912356SN/Avoid 922356SN/ACPUProgressEvent::process() 932356SN/A{ 948834Satgutier@umich.edu Counter temp = cpu->totalOps(); 952356SN/A#ifndef NDEBUG 969179Sandreas.hansson@arm.com double ipc = double(temp - lastNumInst) / (_interval / cpu->clockPeriod()); 972367SN/A 986144Sksewell@umich.edu DPRINTFN("%s progress event, total committed:%i, progress insts committed: " 996144Sksewell@umich.edu "%lli, IPC: %0.8d\n", cpu->name(), temp, temp - lastNumInst, 1006144Sksewell@umich.edu ipc); 1012356SN/A ipc = 0.0; 1022367SN/A#else 1036144Sksewell@umich.edu cprintf("%lli: %s progress event, total committed:%i, progress insts " 1047823Ssteve.reinhardt@amd.com "committed: %lli\n", curTick(), cpu->name(), temp, 1056144Sksewell@umich.edu temp - lastNumInst); 1062367SN/A#endif 1072356SN/A lastNumInst = temp; 1086144Sksewell@umich.edu 1096144Sksewell@umich.edu if (_repeatEvent) 1107823Ssteve.reinhardt@amd.com cpu->schedule(this, curTick() + _interval); 1112356SN/A} 1122356SN/A 1132356SN/Aconst char * 1145336Shines@cs.fsu.eduCPUProgressEvent::description() const 1152356SN/A{ 1164873Sstever@eecs.umich.edu return "CPU Progress"; 1172356SN/A} 1182356SN/A 1198876Sandreas.hansson@arm.comBaseCPU::BaseCPU(Params *p, bool is_checker) 12010190Sakash.bagdia@arm.com : MemObject(p), instCnt(0), _cpuId(p->cpu_id), _socketId(p->socket_id), 1218832SAli.Saidi@ARM.com _instMasterId(p->system->getMasterId(name() + ".inst")), 1228832SAli.Saidi@ARM.com _dataMasterId(p->system->getMasterId(name() + ".data")), 1239332Sdam.sunwoo@arm.com _taskId(ContextSwitchTaskId::Unknown), _pid(Request::invldPid), 1249814Sandreas.hansson@arm.com _switchedOut(p->switched_out), _cacheLineSize(p->system->cacheLineSize()), 1259220Shestness@cs.wisc.edu interrupts(p->interrupts), profileEvent(NULL), 1269157Sandreas.hansson@arm.com numThreads(p->numThreads), system(p->system) 1272SN/A{ 1285712Shsul@eecs.umich.edu // if Python did not provide a valid ID, do it here 1295712Shsul@eecs.umich.edu if (_cpuId == -1 ) { 1305712Shsul@eecs.umich.edu _cpuId = cpuList.size(); 1315712Shsul@eecs.umich.edu } 1325712Shsul@eecs.umich.edu 1332SN/A // add self to global list of CPUs 1342SN/A cpuList.push_back(this); 1352SN/A 13610190Sakash.bagdia@arm.com DPRINTF(SyscallVerbose, "Constructing CPU with id %d, socket id %d\n", 13710190Sakash.bagdia@arm.com _cpuId, _socketId); 1385712Shsul@eecs.umich.edu 1396221Snate@binkert.org if (numThreads > maxThreadsPerCPU) 1406221Snate@binkert.org maxThreadsPerCPU = numThreads; 1412SN/A 1422SN/A // allocate per-thread instruction-based event queues 1436221Snate@binkert.org comInstEventQueue = new EventQueue *[numThreads]; 1446221Snate@binkert.org for (ThreadID tid = 0; tid < numThreads; ++tid) 1456221Snate@binkert.org comInstEventQueue[tid] = 1466221Snate@binkert.org new EventQueue("instruction-based event queue"); 1472SN/A 1482SN/A // 1492SN/A // set up instruction-count-based termination events, if any 1502SN/A // 1515606Snate@binkert.org if (p->max_insts_any_thread != 0) { 1525606Snate@binkert.org const char *cause = "a thread reached the max instruction count"; 1539749Sandreas@sandberg.pp.se for (ThreadID tid = 0; tid < numThreads; ++tid) 1549749Sandreas@sandberg.pp.se scheduleInstStop(tid, p->max_insts_any_thread, cause); 1555606Snate@binkert.org } 1562SN/A 1579647Sdam.sunwoo@arm.com // Set up instruction-count-based termination events for SimPoints 1589647Sdam.sunwoo@arm.com // Typically, there are more than one action points. 1599647Sdam.sunwoo@arm.com // Simulation.py is responsible to take the necessary actions upon 1609647Sdam.sunwoo@arm.com // exitting the simulation loop. 1619647Sdam.sunwoo@arm.com if (!p->simpoint_start_insts.empty()) { 1629647Sdam.sunwoo@arm.com const char *cause = "simpoint starting point found"; 1639749Sandreas@sandberg.pp.se for (size_t i = 0; i < p->simpoint_start_insts.size(); ++i) 1649749Sandreas@sandberg.pp.se scheduleInstStop(0, p->simpoint_start_insts[i], cause); 1659647Sdam.sunwoo@arm.com } 1669647Sdam.sunwoo@arm.com 1671400SN/A if (p->max_insts_all_threads != 0) { 1685606Snate@binkert.org const char *cause = "all threads reached the max instruction count"; 1695606Snate@binkert.org 1702SN/A // allocate & initialize shared downcounter: each event will 1712SN/A // decrement this when triggered; simulation will terminate 1722SN/A // when counter reaches 0 1732SN/A int *counter = new int; 1746221Snate@binkert.org *counter = numThreads; 1756221Snate@binkert.org for (ThreadID tid = 0; tid < numThreads; ++tid) { 1765606Snate@binkert.org Event *event = new CountedExitEvent(cause, *counter); 1776670Shsul@eecs.umich.edu comInstEventQueue[tid]->schedule(event, p->max_insts_all_threads); 1785606Snate@binkert.org } 1792SN/A } 1802SN/A 181124SN/A // allocate per-thread load-based event queues 1826221Snate@binkert.org comLoadEventQueue = new EventQueue *[numThreads]; 1836221Snate@binkert.org for (ThreadID tid = 0; tid < numThreads; ++tid) 1846221Snate@binkert.org comLoadEventQueue[tid] = new EventQueue("load-based event queue"); 185124SN/A 186124SN/A // 187124SN/A // set up instruction-count-based termination events, if any 188124SN/A // 1895606Snate@binkert.org if (p->max_loads_any_thread != 0) { 1905606Snate@binkert.org const char *cause = "a thread reached the max load count"; 1919749Sandreas@sandberg.pp.se for (ThreadID tid = 0; tid < numThreads; ++tid) 1929749Sandreas@sandberg.pp.se scheduleLoadStop(tid, p->max_loads_any_thread, cause); 1935606Snate@binkert.org } 194124SN/A 1951400SN/A if (p->max_loads_all_threads != 0) { 1965606Snate@binkert.org const char *cause = "all threads reached the max load count"; 197124SN/A // allocate & initialize shared downcounter: each event will 198124SN/A // decrement this when triggered; simulation will terminate 199124SN/A // when counter reaches 0 200124SN/A int *counter = new int; 2016221Snate@binkert.org *counter = numThreads; 2026221Snate@binkert.org for (ThreadID tid = 0; tid < numThreads; ++tid) { 2035606Snate@binkert.org Event *event = new CountedExitEvent(cause, *counter); 2046221Snate@binkert.org comLoadEventQueue[tid]->schedule(event, p->max_loads_all_threads); 2055606Snate@binkert.org } 206124SN/A } 207124SN/A 2081191SN/A functionTracingEnabled = false; 2095529Snate@binkert.org if (p->function_trace) { 2108634Schris.emmons@arm.com const string fname = csprintf("ftrace.%s", name()); 2118634Schris.emmons@arm.com functionTraceStream = simout.find(fname); 2128634Schris.emmons@arm.com if (!functionTraceStream) 2138634Schris.emmons@arm.com functionTraceStream = simout.create(fname); 2148634Schris.emmons@arm.com 2151191SN/A currentFunctionStart = currentFunctionEnd = 0; 2165529Snate@binkert.org functionEntryTick = p->function_trace_start; 2171191SN/A 2185529Snate@binkert.org if (p->function_trace_start == 0) { 2191191SN/A functionTracingEnabled = true; 2201191SN/A } else { 2215606Snate@binkert.org typedef EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace> wrap; 2225606Snate@binkert.org Event *event = new wrap(this, true); 2235606Snate@binkert.org schedule(event, p->function_trace_start); 2241191SN/A } 2251191SN/A } 2268876Sandreas.hansson@arm.com 2278876Sandreas.hansson@arm.com // The interrupts should always be present unless this CPU is 2288876Sandreas.hansson@arm.com // switched in later or in case it is a checker CPU 2299433SAndreas.Sandberg@ARM.com if (!params()->switched_out && !is_checker) { 2308876Sandreas.hansson@arm.com if (interrupts) { 2318876Sandreas.hansson@arm.com interrupts->setCPU(this); 2328876Sandreas.hansson@arm.com } else { 2338876Sandreas.hansson@arm.com fatal("CPU %s has no interrupt controller.\n" 2348876Sandreas.hansson@arm.com "Ensure createInterruptController() is called.\n", name()); 2358876Sandreas.hansson@arm.com } 2368876Sandreas.hansson@arm.com } 2375810Sgblack@eecs.umich.edu 2388779Sgblack@eecs.umich.edu if (FullSystem) { 2398779Sgblack@eecs.umich.edu if (params()->profile) 2408779Sgblack@eecs.umich.edu profileEvent = new ProfileEvent(this, params()->profile); 2418779Sgblack@eecs.umich.edu } 2425529Snate@binkert.org tracer = params()->tracer; 2439384SAndreas.Sandberg@arm.com 2449384SAndreas.Sandberg@arm.com if (params()->isa.size() != numThreads) { 2459384SAndreas.Sandberg@arm.com fatal("Number of ISAs (%i) assigned to the CPU does not equal number " 2469384SAndreas.Sandberg@arm.com "of threads (%i).\n", params()->isa.size(), numThreads); 2479384SAndreas.Sandberg@arm.com } 2481917SN/A} 2491191SN/A 2501191SN/Avoid 2511191SN/ABaseCPU::enableFunctionTrace() 2521191SN/A{ 2531191SN/A functionTracingEnabled = true; 2541191SN/A} 2551191SN/A 2561191SN/ABaseCPU::~BaseCPU() 2571191SN/A{ 2589086Sandreas.hansson@arm.com delete profileEvent; 2599086Sandreas.hansson@arm.com delete[] comLoadEventQueue; 2609086Sandreas.hansson@arm.com delete[] comInstEventQueue; 2611191SN/A} 2621191SN/A 2631129SN/Avoid 2641129SN/ABaseCPU::init() 2651129SN/A{ 2669523SAndreas.Sandberg@ARM.com if (!params()->switched_out) { 2672680Sktlim@umich.edu registerThreadContexts(); 2689523SAndreas.Sandberg@ARM.com 2699523SAndreas.Sandberg@ARM.com verifyMemoryMode(); 2709523SAndreas.Sandberg@ARM.com } 2711129SN/A} 272180SN/A 2732SN/Avoid 2741917SN/ABaseCPU::startup() 2751917SN/A{ 2768779Sgblack@eecs.umich.edu if (FullSystem) { 2779433SAndreas.Sandberg@ARM.com if (!params()->switched_out && profileEvent) 2788779Sgblack@eecs.umich.edu schedule(profileEvent, curTick()); 2798779Sgblack@eecs.umich.edu } 2802356SN/A 2815529Snate@binkert.org if (params()->progress_interval) { 2829179Sandreas.hansson@arm.com new CPUProgressEvent(this, params()->progress_interval); 2832356SN/A } 2841917SN/A} 2851917SN/A 28610464SAndreas.Sandberg@ARM.comProbePoints::PMUUPtr 28710464SAndreas.Sandberg@ARM.comBaseCPU::pmuProbePoint(const char *name) 28810464SAndreas.Sandberg@ARM.com{ 28910464SAndreas.Sandberg@ARM.com ProbePoints::PMUUPtr ptr; 29010464SAndreas.Sandberg@ARM.com ptr.reset(new ProbePoints::PMU(getProbeManager(), name)); 29110464SAndreas.Sandberg@ARM.com 29210464SAndreas.Sandberg@ARM.com return ptr; 29310464SAndreas.Sandberg@ARM.com} 29410464SAndreas.Sandberg@ARM.com 29510464SAndreas.Sandberg@ARM.comvoid 29610464SAndreas.Sandberg@ARM.comBaseCPU::regProbePoints() 29710464SAndreas.Sandberg@ARM.com{ 29810464SAndreas.Sandberg@ARM.com ppCycles = pmuProbePoint("Cycles"); 29910464SAndreas.Sandberg@ARM.com 30010464SAndreas.Sandberg@ARM.com ppRetiredInsts = pmuProbePoint("RetiredInsts"); 30110464SAndreas.Sandberg@ARM.com ppRetiredLoads = pmuProbePoint("RetiredLoads"); 30210464SAndreas.Sandberg@ARM.com ppRetiredStores = pmuProbePoint("RetiredStores"); 30310464SAndreas.Sandberg@ARM.com ppRetiredBranches = pmuProbePoint("RetiredBranches"); 30410464SAndreas.Sandberg@ARM.com} 30510464SAndreas.Sandberg@ARM.com 30610464SAndreas.Sandberg@ARM.comvoid 30710464SAndreas.Sandberg@ARM.comBaseCPU::probeInstCommit(const StaticInstPtr &inst) 30810464SAndreas.Sandberg@ARM.com{ 30910464SAndreas.Sandberg@ARM.com if (!inst->isMicroop() || inst->isLastMicroop()) 31010464SAndreas.Sandberg@ARM.com ppRetiredInsts->notify(1); 31110464SAndreas.Sandberg@ARM.com 31210464SAndreas.Sandberg@ARM.com 31310464SAndreas.Sandberg@ARM.com if (inst->isLoad()) 31410464SAndreas.Sandberg@ARM.com ppRetiredLoads->notify(1); 31510464SAndreas.Sandberg@ARM.com 31610464SAndreas.Sandberg@ARM.com if (inst->isStore()) 31710464SAndreas.Sandberg@ARM.com ppRetiredLoads->notify(1); 31810464SAndreas.Sandberg@ARM.com 31910464SAndreas.Sandberg@ARM.com if (inst->isControl()) 32010464SAndreas.Sandberg@ARM.com ppRetiredBranches->notify(1); 32110464SAndreas.Sandberg@ARM.com} 3221917SN/A 3231917SN/Avoid 3242SN/ABaseCPU::regStats() 3252SN/A{ 326729SN/A using namespace Stats; 327707SN/A 328707SN/A numCycles 329707SN/A .name(name() + ".numCycles") 330707SN/A .desc("number of cpu cycles simulated") 331707SN/A ; 332707SN/A 3337914SBrad.Beckmann@amd.com numWorkItemsStarted 3347914SBrad.Beckmann@amd.com .name(name() + ".numWorkItemsStarted") 3357914SBrad.Beckmann@amd.com .desc("number of work items this cpu started") 3367914SBrad.Beckmann@amd.com ; 3377914SBrad.Beckmann@amd.com 3387914SBrad.Beckmann@amd.com numWorkItemsCompleted 3397914SBrad.Beckmann@amd.com .name(name() + ".numWorkItemsCompleted") 3407914SBrad.Beckmann@amd.com .desc("number of work items this cpu completed") 3417914SBrad.Beckmann@amd.com ; 3427914SBrad.Beckmann@amd.com 3432680Sktlim@umich.edu int size = threadContexts.size(); 3442SN/A if (size > 1) { 3452SN/A for (int i = 0; i < size; ++i) { 3462SN/A stringstream namestr; 3472SN/A ccprintf(namestr, "%s.ctx%d", name(), i); 3482680Sktlim@umich.edu threadContexts[i]->regStats(namestr.str()); 3492SN/A } 3502SN/A } else if (size == 1) 3512680Sktlim@umich.edu threadContexts[0]->regStats(name()); 3522SN/A} 3532SN/A 3549294Sandreas.hansson@arm.comBaseMasterPort & 3559294Sandreas.hansson@arm.comBaseCPU::getMasterPort(const string &if_name, PortID idx) 3568850Sandreas.hansson@arm.com{ 3578850Sandreas.hansson@arm.com // Get the right port based on name. This applies to all the 3588850Sandreas.hansson@arm.com // subclasses of the base CPU and relies on their implementation 3598850Sandreas.hansson@arm.com // of getDataPort and getInstPort. In all cases there methods 3609608Sandreas.hansson@arm.com // return a MasterPort pointer. 3618850Sandreas.hansson@arm.com if (if_name == "dcache_port") 3628922Swilliam.wang@arm.com return getDataPort(); 3638850Sandreas.hansson@arm.com else if (if_name == "icache_port") 3648922Swilliam.wang@arm.com return getInstPort(); 3658850Sandreas.hansson@arm.com else 3668922Swilliam.wang@arm.com return MemObject::getMasterPort(if_name, idx); 3678850Sandreas.hansson@arm.com} 3688850Sandreas.hansson@arm.com 369180SN/Avoid 3702680Sktlim@umich.eduBaseCPU::registerThreadContexts() 371180SN/A{ 3726221Snate@binkert.org ThreadID size = threadContexts.size(); 3736221Snate@binkert.org for (ThreadID tid = 0; tid < size; ++tid) { 3746221Snate@binkert.org ThreadContext *tc = threadContexts[tid]; 3752378SN/A 3765718Shsul@eecs.umich.edu /** This is so that contextId and cpuId match where there is a 3775718Shsul@eecs.umich.edu * 1cpu:1context relationship. Otherwise, the order of registration 3785718Shsul@eecs.umich.edu * could affect the assignment and cpu 1 could have context id 3, for 3795718Shsul@eecs.umich.edu * example. We may even want to do something like this for SMT so that 3805718Shsul@eecs.umich.edu * cpu 0 has the lowest thread contexts and cpu N has the highest, but 3815718Shsul@eecs.umich.edu * I'll just do this for now 3825718Shsul@eecs.umich.edu */ 3836221Snate@binkert.org if (numThreads == 1) 3845718Shsul@eecs.umich.edu tc->setContextId(system->registerThreadContext(tc, _cpuId)); 3855718Shsul@eecs.umich.edu else 3865718Shsul@eecs.umich.edu tc->setContextId(system->registerThreadContext(tc)); 3878779Sgblack@eecs.umich.edu 3888779Sgblack@eecs.umich.edu if (!FullSystem) 3898779Sgblack@eecs.umich.edu tc->getProcessPtr()->assignThreadContext(tc->contextId()); 390180SN/A } 391180SN/A} 392180SN/A 393180SN/A 3944000Ssaidi@eecs.umich.eduint 3954000Ssaidi@eecs.umich.eduBaseCPU::findContext(ThreadContext *tc) 3964000Ssaidi@eecs.umich.edu{ 3976221Snate@binkert.org ThreadID size = threadContexts.size(); 3986221Snate@binkert.org for (ThreadID tid = 0; tid < size; ++tid) { 3996221Snate@binkert.org if (tc == threadContexts[tid]) 4006221Snate@binkert.org return tid; 4014000Ssaidi@eecs.umich.edu } 4024000Ssaidi@eecs.umich.edu return 0; 4034000Ssaidi@eecs.umich.edu} 4044000Ssaidi@eecs.umich.edu 405180SN/Avoid 4062798Sktlim@umich.eduBaseCPU::switchOut() 407180SN/A{ 4089430SAndreas.Sandberg@ARM.com assert(!_switchedOut); 4099430SAndreas.Sandberg@ARM.com _switchedOut = true; 4102359SN/A if (profileEvent && profileEvent->scheduled()) 4115606Snate@binkert.org deschedule(profileEvent); 4129446SAndreas.Sandberg@ARM.com 4139446SAndreas.Sandberg@ARM.com // Flush all TLBs in the CPU to avoid having stale translations if 4149446SAndreas.Sandberg@ARM.com // it gets switched in later. 4159446SAndreas.Sandberg@ARM.com flushTLBs(); 416180SN/A} 417180SN/A 418180SN/Avoid 4198737Skoansin.tan@gmail.comBaseCPU::takeOverFrom(BaseCPU *oldCPU) 420180SN/A{ 4212680Sktlim@umich.edu assert(threadContexts.size() == oldCPU->threadContexts.size()); 4229152Satgutier@umich.edu assert(_cpuId == oldCPU->cpuId()); 4239430SAndreas.Sandberg@ARM.com assert(_switchedOut); 4249430SAndreas.Sandberg@ARM.com assert(oldCPU != this); 4259332Sdam.sunwoo@arm.com _pid = oldCPU->getPid(); 4269332Sdam.sunwoo@arm.com _taskId = oldCPU->taskId(); 4279430SAndreas.Sandberg@ARM.com _switchedOut = false; 4285712Shsul@eecs.umich.edu 4296221Snate@binkert.org ThreadID size = threadContexts.size(); 4306221Snate@binkert.org for (ThreadID i = 0; i < size; ++i) { 4312680Sktlim@umich.edu ThreadContext *newTC = threadContexts[i]; 4322680Sktlim@umich.edu ThreadContext *oldTC = oldCPU->threadContexts[i]; 433180SN/A 4342680Sktlim@umich.edu newTC->takeOverFrom(oldTC); 4352651Ssaidi@eecs.umich.edu 4362680Sktlim@umich.edu CpuEvent::replaceThreadContext(oldTC, newTC); 4372651Ssaidi@eecs.umich.edu 4385714Shsul@eecs.umich.edu assert(newTC->contextId() == oldTC->contextId()); 4395715Shsul@eecs.umich.edu assert(newTC->threadId() == oldTC->threadId()); 4405714Shsul@eecs.umich.edu system->replaceThreadContext(newTC, newTC->contextId()); 4412359SN/A 4425875Ssteve.reinhardt@amd.com /* This code no longer works since the zero register (e.g., 4435875Ssteve.reinhardt@amd.com * r31 on Alpha) doesn't necessarily contain zero at this 4445875Ssteve.reinhardt@amd.com * point. 4455875Ssteve.reinhardt@amd.com if (DTRACE(Context)) 4465217Ssaidi@eecs.umich.edu ThreadContext::compare(oldTC, newTC); 4475875Ssteve.reinhardt@amd.com */ 4487781SAli.Saidi@ARM.com 4499294Sandreas.hansson@arm.com BaseMasterPort *old_itb_port = oldTC->getITBPtr()->getMasterPort(); 4509294Sandreas.hansson@arm.com BaseMasterPort *old_dtb_port = oldTC->getDTBPtr()->getMasterPort(); 4519294Sandreas.hansson@arm.com BaseMasterPort *new_itb_port = newTC->getITBPtr()->getMasterPort(); 4529294Sandreas.hansson@arm.com BaseMasterPort *new_dtb_port = newTC->getDTBPtr()->getMasterPort(); 4537781SAli.Saidi@ARM.com 4547781SAli.Saidi@ARM.com // Move over any table walker ports if they exist 4559178Sandreas.hansson@arm.com if (new_itb_port) { 4569178Sandreas.hansson@arm.com assert(!new_itb_port->isConnected()); 4577781SAli.Saidi@ARM.com assert(old_itb_port); 4589178Sandreas.hansson@arm.com assert(old_itb_port->isConnected()); 4599294Sandreas.hansson@arm.com BaseSlavePort &slavePort = old_itb_port->getSlavePort(); 4609178Sandreas.hansson@arm.com old_itb_port->unbind(); 4618922Swilliam.wang@arm.com new_itb_port->bind(slavePort); 4627781SAli.Saidi@ARM.com } 4639178Sandreas.hansson@arm.com if (new_dtb_port) { 4649178Sandreas.hansson@arm.com assert(!new_dtb_port->isConnected()); 4657781SAli.Saidi@ARM.com assert(old_dtb_port); 4669178Sandreas.hansson@arm.com assert(old_dtb_port->isConnected()); 4679294Sandreas.hansson@arm.com BaseSlavePort &slavePort = old_dtb_port->getSlavePort(); 4689178Sandreas.hansson@arm.com old_dtb_port->unbind(); 4698922Swilliam.wang@arm.com new_dtb_port->bind(slavePort); 4707781SAli.Saidi@ARM.com } 47110194SGeoffrey.Blake@arm.com newTC->getITBPtr()->takeOverFrom(oldTC->getITBPtr()); 47210194SGeoffrey.Blake@arm.com newTC->getDTBPtr()->takeOverFrom(oldTC->getDTBPtr()); 4738733Sgeoffrey.blake@arm.com 4748887Sgeoffrey.blake@arm.com // Checker whether or not we have to transfer CheckerCPU 4758887Sgeoffrey.blake@arm.com // objects over in the switch 4768887Sgeoffrey.blake@arm.com CheckerCPU *oldChecker = oldTC->getCheckerCpuPtr(); 4778887Sgeoffrey.blake@arm.com CheckerCPU *newChecker = newTC->getCheckerCpuPtr(); 4788887Sgeoffrey.blake@arm.com if (oldChecker && newChecker) { 4799294Sandreas.hansson@arm.com BaseMasterPort *old_checker_itb_port = 4808922Swilliam.wang@arm.com oldChecker->getITBPtr()->getMasterPort(); 4819294Sandreas.hansson@arm.com BaseMasterPort *old_checker_dtb_port = 4828922Swilliam.wang@arm.com oldChecker->getDTBPtr()->getMasterPort(); 4839294Sandreas.hansson@arm.com BaseMasterPort *new_checker_itb_port = 4848922Swilliam.wang@arm.com newChecker->getITBPtr()->getMasterPort(); 4859294Sandreas.hansson@arm.com BaseMasterPort *new_checker_dtb_port = 4868922Swilliam.wang@arm.com newChecker->getDTBPtr()->getMasterPort(); 4878733Sgeoffrey.blake@arm.com 48810194SGeoffrey.Blake@arm.com newChecker->getITBPtr()->takeOverFrom(oldChecker->getITBPtr()); 48910194SGeoffrey.Blake@arm.com newChecker->getDTBPtr()->takeOverFrom(oldChecker->getDTBPtr()); 49010194SGeoffrey.Blake@arm.com 4918887Sgeoffrey.blake@arm.com // Move over any table walker ports if they exist for checker 4929178Sandreas.hansson@arm.com if (new_checker_itb_port) { 4939178Sandreas.hansson@arm.com assert(!new_checker_itb_port->isConnected()); 4948887Sgeoffrey.blake@arm.com assert(old_checker_itb_port); 4959178Sandreas.hansson@arm.com assert(old_checker_itb_port->isConnected()); 4969294Sandreas.hansson@arm.com BaseSlavePort &slavePort = 4979294Sandreas.hansson@arm.com old_checker_itb_port->getSlavePort(); 4989178Sandreas.hansson@arm.com old_checker_itb_port->unbind(); 4998922Swilliam.wang@arm.com new_checker_itb_port->bind(slavePort); 5008887Sgeoffrey.blake@arm.com } 5019178Sandreas.hansson@arm.com if (new_checker_dtb_port) { 5029178Sandreas.hansson@arm.com assert(!new_checker_dtb_port->isConnected()); 5038887Sgeoffrey.blake@arm.com assert(old_checker_dtb_port); 5049178Sandreas.hansson@arm.com assert(old_checker_dtb_port->isConnected()); 5059294Sandreas.hansson@arm.com BaseSlavePort &slavePort = 5069294Sandreas.hansson@arm.com old_checker_dtb_port->getSlavePort(); 5079178Sandreas.hansson@arm.com old_checker_dtb_port->unbind(); 5088922Swilliam.wang@arm.com new_checker_dtb_port->bind(slavePort); 5098887Sgeoffrey.blake@arm.com } 5108733Sgeoffrey.blake@arm.com } 511180SN/A } 512605SN/A 5133520Sgblack@eecs.umich.edu interrupts = oldCPU->interrupts; 5145810Sgblack@eecs.umich.edu interrupts->setCPU(this); 5159152Satgutier@umich.edu oldCPU->interrupts = NULL; 5162254SN/A 5178779Sgblack@eecs.umich.edu if (FullSystem) { 5188779Sgblack@eecs.umich.edu for (ThreadID i = 0; i < size; ++i) 5198779Sgblack@eecs.umich.edu threadContexts[i]->profileClear(); 5202254SN/A 5218779Sgblack@eecs.umich.edu if (profileEvent) 5228779Sgblack@eecs.umich.edu schedule(profileEvent, curTick()); 5238779Sgblack@eecs.umich.edu } 5244192Sktlim@umich.edu 5259178Sandreas.hansson@arm.com // All CPUs have an instruction and a data port, and the new CPU's 5269178Sandreas.hansson@arm.com // ports are dangling while the old CPU has its ports connected 5279178Sandreas.hansson@arm.com // already. Unbind the old CPU and then bind the ports of the one 5289178Sandreas.hansson@arm.com // we are switching to. 5299178Sandreas.hansson@arm.com assert(!getInstPort().isConnected()); 5309178Sandreas.hansson@arm.com assert(oldCPU->getInstPort().isConnected()); 5319294Sandreas.hansson@arm.com BaseSlavePort &inst_peer_port = oldCPU->getInstPort().getSlavePort(); 5329178Sandreas.hansson@arm.com oldCPU->getInstPort().unbind(); 5339178Sandreas.hansson@arm.com getInstPort().bind(inst_peer_port); 5344192Sktlim@umich.edu 5359178Sandreas.hansson@arm.com assert(!getDataPort().isConnected()); 5369178Sandreas.hansson@arm.com assert(oldCPU->getDataPort().isConnected()); 5379294Sandreas.hansson@arm.com BaseSlavePort &data_peer_port = oldCPU->getDataPort().getSlavePort(); 5389178Sandreas.hansson@arm.com oldCPU->getDataPort().unbind(); 5399178Sandreas.hansson@arm.com getDataPort().bind(data_peer_port); 540180SN/A} 541180SN/A 5429446SAndreas.Sandberg@ARM.comvoid 5439446SAndreas.Sandberg@ARM.comBaseCPU::flushTLBs() 5449446SAndreas.Sandberg@ARM.com{ 5459446SAndreas.Sandberg@ARM.com for (ThreadID i = 0; i < threadContexts.size(); ++i) { 5469446SAndreas.Sandberg@ARM.com ThreadContext &tc(*threadContexts[i]); 5479446SAndreas.Sandberg@ARM.com CheckerCPU *checker(tc.getCheckerCpuPtr()); 5489446SAndreas.Sandberg@ARM.com 5499446SAndreas.Sandberg@ARM.com tc.getITBPtr()->flushAll(); 5509446SAndreas.Sandberg@ARM.com tc.getDTBPtr()->flushAll(); 5519446SAndreas.Sandberg@ARM.com if (checker) { 5529446SAndreas.Sandberg@ARM.com checker->getITBPtr()->flushAll(); 5539446SAndreas.Sandberg@ARM.com checker->getDTBPtr()->flushAll(); 5549446SAndreas.Sandberg@ARM.com } 5559446SAndreas.Sandberg@ARM.com } 5569446SAndreas.Sandberg@ARM.com} 5579446SAndreas.Sandberg@ARM.com 558180SN/A 5595536Srstrong@hp.comBaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, Tick _interval) 5605606Snate@binkert.org : cpu(_cpu), interval(_interval) 5611917SN/A{ } 5621917SN/A 5631917SN/Avoid 5641917SN/ABaseCPU::ProfileEvent::process() 5651917SN/A{ 5666221Snate@binkert.org ThreadID size = cpu->threadContexts.size(); 5676221Snate@binkert.org for (ThreadID i = 0; i < size; ++i) { 5682680Sktlim@umich.edu ThreadContext *tc = cpu->threadContexts[i]; 5692680Sktlim@umich.edu tc->profileSample(); 5701917SN/A } 5712254SN/A 5727823Ssteve.reinhardt@amd.com cpu->schedule(this, curTick() + interval); 5731917SN/A} 5741917SN/A 5752SN/Avoid 576921SN/ABaseCPU::serialize(std::ostream &os) 577921SN/A{ 5784000Ssaidi@eecs.umich.edu SERIALIZE_SCALAR(instCnt); 5799332Sdam.sunwoo@arm.com 5809448SAndreas.Sandberg@ARM.com if (!_switchedOut) { 5819448SAndreas.Sandberg@ARM.com /* Unlike _pid, _taskId is not serialized, as they are dynamically 5829448SAndreas.Sandberg@ARM.com * assigned unique ids that are only meaningful for the duration of 5839448SAndreas.Sandberg@ARM.com * a specific run. We will need to serialize the entire taskMap in 5849448SAndreas.Sandberg@ARM.com * system. */ 5859448SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(_pid); 5869332Sdam.sunwoo@arm.com 5879448SAndreas.Sandberg@ARM.com interrupts->serialize(os); 5889448SAndreas.Sandberg@ARM.com 5899448SAndreas.Sandberg@ARM.com // Serialize the threads, this is done by the CPU implementation. 5909448SAndreas.Sandberg@ARM.com for (ThreadID i = 0; i < numThreads; ++i) { 5919448SAndreas.Sandberg@ARM.com nameOut(os, csprintf("%s.xc.%i", name(), i)); 5929448SAndreas.Sandberg@ARM.com serializeThread(os, i); 5939448SAndreas.Sandberg@ARM.com } 5949448SAndreas.Sandberg@ARM.com } 595921SN/A} 596921SN/A 597921SN/Avoid 598921SN/ABaseCPU::unserialize(Checkpoint *cp, const std::string §ion) 599921SN/A{ 6004000Ssaidi@eecs.umich.edu UNSERIALIZE_SCALAR(instCnt); 6019448SAndreas.Sandberg@ARM.com 6029448SAndreas.Sandberg@ARM.com if (!_switchedOut) { 6039448SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(_pid); 6049448SAndreas.Sandberg@ARM.com interrupts->unserialize(cp, section); 6059448SAndreas.Sandberg@ARM.com 6069448SAndreas.Sandberg@ARM.com // Unserialize the threads, this is done by the CPU implementation. 6079448SAndreas.Sandberg@ARM.com for (ThreadID i = 0; i < numThreads; ++i) 6089448SAndreas.Sandberg@ARM.com unserializeThread(cp, csprintf("%s.xc.%i", section, i), i); 6099448SAndreas.Sandberg@ARM.com } 610921SN/A} 611921SN/A 6121191SN/Avoid 6139749Sandreas@sandberg.pp.seBaseCPU::scheduleInstStop(ThreadID tid, Counter insts, const char *cause) 6149749Sandreas@sandberg.pp.se{ 6159749Sandreas@sandberg.pp.se const Tick now(comInstEventQueue[tid]->getCurTick()); 6169983Sstever@gmail.com Event *event(new LocalSimLoopExitEvent(cause, 0)); 6179749Sandreas@sandberg.pp.se 6189749Sandreas@sandberg.pp.se comInstEventQueue[tid]->schedule(event, now + insts); 6199749Sandreas@sandberg.pp.se} 6209749Sandreas@sandberg.pp.se 6219749Sandreas@sandberg.pp.sevoid 6229749Sandreas@sandberg.pp.seBaseCPU::scheduleLoadStop(ThreadID tid, Counter loads, const char *cause) 6239749Sandreas@sandberg.pp.se{ 6249749Sandreas@sandberg.pp.se const Tick now(comLoadEventQueue[tid]->getCurTick()); 6259983Sstever@gmail.com Event *event(new LocalSimLoopExitEvent(cause, 0)); 6269749Sandreas@sandberg.pp.se 6279749Sandreas@sandberg.pp.se comLoadEventQueue[tid]->schedule(event, now + loads); 6289749Sandreas@sandberg.pp.se} 6299749Sandreas@sandberg.pp.se 6309749Sandreas@sandberg.pp.se 6319749Sandreas@sandberg.pp.sevoid 6321191SN/ABaseCPU::traceFunctionsInternal(Addr pc) 6331191SN/A{ 6341191SN/A if (!debugSymbolTable) 6351191SN/A return; 6361191SN/A 6371191SN/A // if pc enters different function, print new function symbol and 6381191SN/A // update saved range. Otherwise do nothing. 6391191SN/A if (pc < currentFunctionStart || pc >= currentFunctionEnd) { 6401191SN/A string sym_str; 6411191SN/A bool found = debugSymbolTable->findNearestSymbol(pc, sym_str, 6421191SN/A currentFunctionStart, 6431191SN/A currentFunctionEnd); 6441191SN/A 6451191SN/A if (!found) { 6461191SN/A // no symbol found: use addr as label 6471191SN/A sym_str = csprintf("0x%x", pc); 6481191SN/A currentFunctionStart = pc; 6491191SN/A currentFunctionEnd = pc + 1; 6501191SN/A } 6511191SN/A 6521191SN/A ccprintf(*functionTraceStream, " (%d)\n%d: %s", 6537823Ssteve.reinhardt@amd.com curTick() - functionEntryTick, curTick(), sym_str); 6547823Ssteve.reinhardt@amd.com functionEntryTick = curTick(); 6551191SN/A } 6561191SN/A} 657