base.cc revision 10537
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" 5810529Smorr@cs.wisc.edu#include "cpu/checker/cpu.hh" 591717SN/A#include "cpu/base.hh" 602651Ssaidi@eecs.umich.edu#include "cpu/cpuevent.hh" 618229Snate@binkert.org#include "cpu/profile.hh" 622680Sktlim@umich.edu#include "cpu/thread_context.hh" 6310529Smorr@cs.wisc.edu#include "debug/Mwait.hh" 648232Snate@binkert.org#include "debug/SyscallVerbose.hh" 6510529Smorr@cs.wisc.edu#include "mem/page_table.hh" 665529Snate@binkert.org#include "params/BaseCPU.hh" 678779Sgblack@eecs.umich.edu#include "sim/full_system.hh" 682190SN/A#include "sim/process.hh" 6956SN/A#include "sim/sim_events.hh" 708229Snate@binkert.org#include "sim/sim_exit.hh" 712190SN/A#include "sim/system.hh" 722SN/A 732359SN/A// Hack 742359SN/A#include "sim/stat_control.hh" 752359SN/A 762SN/Ausing namespace std; 772SN/A 782SN/Avector<BaseCPU *> BaseCPU::cpuList; 792SN/A 802SN/A// This variable reflects the max number of threads in any CPU. Be 812SN/A// careful to only use it once all the CPUs that you care about have 822SN/A// been initialized 832SN/Aint maxThreadsPerCPU = 1; 842SN/A 855606Snate@binkert.orgCPUProgressEvent::CPUProgressEvent(BaseCPU *_cpu, Tick ival) 866144Sksewell@umich.edu : Event(Event::Progress_Event_Pri), _interval(ival), lastNumInst(0), 876144Sksewell@umich.edu cpu(_cpu), _repeatEvent(true) 883126Sktlim@umich.edu{ 896144Sksewell@umich.edu if (_interval) 907823Ssteve.reinhardt@amd.com cpu->schedule(this, curTick() + _interval); 913126Sktlim@umich.edu} 923126Sktlim@umich.edu 932356SN/Avoid 942356SN/ACPUProgressEvent::process() 952356SN/A{ 968834Satgutier@umich.edu Counter temp = cpu->totalOps(); 972356SN/A#ifndef NDEBUG 989179Sandreas.hansson@arm.com double ipc = double(temp - lastNumInst) / (_interval / cpu->clockPeriod()); 992367SN/A 1006144Sksewell@umich.edu DPRINTFN("%s progress event, total committed:%i, progress insts committed: " 1016144Sksewell@umich.edu "%lli, IPC: %0.8d\n", cpu->name(), temp, temp - lastNumInst, 1026144Sksewell@umich.edu ipc); 1032356SN/A ipc = 0.0; 1042367SN/A#else 1056144Sksewell@umich.edu cprintf("%lli: %s progress event, total committed:%i, progress insts " 1067823Ssteve.reinhardt@amd.com "committed: %lli\n", curTick(), cpu->name(), temp, 1076144Sksewell@umich.edu temp - lastNumInst); 1082367SN/A#endif 1092356SN/A lastNumInst = temp; 1106144Sksewell@umich.edu 1116144Sksewell@umich.edu if (_repeatEvent) 1127823Ssteve.reinhardt@amd.com cpu->schedule(this, curTick() + _interval); 1132356SN/A} 1142356SN/A 1152356SN/Aconst char * 1165336Shines@cs.fsu.eduCPUProgressEvent::description() const 1172356SN/A{ 1184873Sstever@eecs.umich.edu return "CPU Progress"; 1192356SN/A} 1202356SN/A 1218876Sandreas.hansson@arm.comBaseCPU::BaseCPU(Params *p, bool is_checker) 12210190Sakash.bagdia@arm.com : MemObject(p), instCnt(0), _cpuId(p->cpu_id), _socketId(p->socket_id), 1238832SAli.Saidi@ARM.com _instMasterId(p->system->getMasterId(name() + ".inst")), 1248832SAli.Saidi@ARM.com _dataMasterId(p->system->getMasterId(name() + ".data")), 1259332Sdam.sunwoo@arm.com _taskId(ContextSwitchTaskId::Unknown), _pid(Request::invldPid), 1269814Sandreas.hansson@arm.com _switchedOut(p->switched_out), _cacheLineSize(p->system->cacheLineSize()), 1279220Shestness@cs.wisc.edu interrupts(p->interrupts), profileEvent(NULL), 12810529Smorr@cs.wisc.edu numThreads(p->numThreads), system(p->system), 12910537Sandreas.hansson@arm.com functionTraceStream(nullptr), currentFunctionStart(0), 13010537Sandreas.hansson@arm.com currentFunctionEnd(0), functionEntryTick(0), 13110529Smorr@cs.wisc.edu addressMonitor() 1322SN/A{ 1335712Shsul@eecs.umich.edu // if Python did not provide a valid ID, do it here 1345712Shsul@eecs.umich.edu if (_cpuId == -1 ) { 1355712Shsul@eecs.umich.edu _cpuId = cpuList.size(); 1365712Shsul@eecs.umich.edu } 1375712Shsul@eecs.umich.edu 1382SN/A // add self to global list of CPUs 1392SN/A cpuList.push_back(this); 1402SN/A 14110190Sakash.bagdia@arm.com DPRINTF(SyscallVerbose, "Constructing CPU with id %d, socket id %d\n", 14210190Sakash.bagdia@arm.com _cpuId, _socketId); 1435712Shsul@eecs.umich.edu 1446221Snate@binkert.org if (numThreads > maxThreadsPerCPU) 1456221Snate@binkert.org maxThreadsPerCPU = numThreads; 1462SN/A 1472SN/A // allocate per-thread instruction-based event queues 1486221Snate@binkert.org comInstEventQueue = new EventQueue *[numThreads]; 1496221Snate@binkert.org for (ThreadID tid = 0; tid < numThreads; ++tid) 1506221Snate@binkert.org comInstEventQueue[tid] = 1516221Snate@binkert.org new EventQueue("instruction-based event queue"); 1522SN/A 1532SN/A // 1542SN/A // set up instruction-count-based termination events, if any 1552SN/A // 1565606Snate@binkert.org if (p->max_insts_any_thread != 0) { 1575606Snate@binkert.org const char *cause = "a thread reached the max instruction count"; 1589749Sandreas@sandberg.pp.se for (ThreadID tid = 0; tid < numThreads; ++tid) 1599749Sandreas@sandberg.pp.se scheduleInstStop(tid, p->max_insts_any_thread, cause); 1605606Snate@binkert.org } 1612SN/A 1629647Sdam.sunwoo@arm.com // Set up instruction-count-based termination events for SimPoints 1639647Sdam.sunwoo@arm.com // Typically, there are more than one action points. 1649647Sdam.sunwoo@arm.com // Simulation.py is responsible to take the necessary actions upon 1659647Sdam.sunwoo@arm.com // exitting the simulation loop. 1669647Sdam.sunwoo@arm.com if (!p->simpoint_start_insts.empty()) { 1679647Sdam.sunwoo@arm.com const char *cause = "simpoint starting point found"; 1689749Sandreas@sandberg.pp.se for (size_t i = 0; i < p->simpoint_start_insts.size(); ++i) 1699749Sandreas@sandberg.pp.se scheduleInstStop(0, p->simpoint_start_insts[i], cause); 1709647Sdam.sunwoo@arm.com } 1719647Sdam.sunwoo@arm.com 1721400SN/A if (p->max_insts_all_threads != 0) { 1735606Snate@binkert.org const char *cause = "all threads reached the max instruction count"; 1745606Snate@binkert.org 1752SN/A // allocate & initialize shared downcounter: each event will 1762SN/A // decrement this when triggered; simulation will terminate 1772SN/A // when counter reaches 0 1782SN/A int *counter = new int; 1796221Snate@binkert.org *counter = numThreads; 1806221Snate@binkert.org for (ThreadID tid = 0; tid < numThreads; ++tid) { 1815606Snate@binkert.org Event *event = new CountedExitEvent(cause, *counter); 1826670Shsul@eecs.umich.edu comInstEventQueue[tid]->schedule(event, p->max_insts_all_threads); 1835606Snate@binkert.org } 1842SN/A } 1852SN/A 186124SN/A // allocate per-thread load-based event queues 1876221Snate@binkert.org comLoadEventQueue = new EventQueue *[numThreads]; 1886221Snate@binkert.org for (ThreadID tid = 0; tid < numThreads; ++tid) 1896221Snate@binkert.org comLoadEventQueue[tid] = new EventQueue("load-based event queue"); 190124SN/A 191124SN/A // 192124SN/A // set up instruction-count-based termination events, if any 193124SN/A // 1945606Snate@binkert.org if (p->max_loads_any_thread != 0) { 1955606Snate@binkert.org const char *cause = "a thread reached the max load count"; 1969749Sandreas@sandberg.pp.se for (ThreadID tid = 0; tid < numThreads; ++tid) 1979749Sandreas@sandberg.pp.se scheduleLoadStop(tid, p->max_loads_any_thread, cause); 1985606Snate@binkert.org } 199124SN/A 2001400SN/A if (p->max_loads_all_threads != 0) { 2015606Snate@binkert.org const char *cause = "all threads reached the max load count"; 202124SN/A // allocate & initialize shared downcounter: each event will 203124SN/A // decrement this when triggered; simulation will terminate 204124SN/A // when counter reaches 0 205124SN/A int *counter = new int; 2066221Snate@binkert.org *counter = numThreads; 2076221Snate@binkert.org for (ThreadID tid = 0; tid < numThreads; ++tid) { 2085606Snate@binkert.org Event *event = new CountedExitEvent(cause, *counter); 2096221Snate@binkert.org comLoadEventQueue[tid]->schedule(event, p->max_loads_all_threads); 2105606Snate@binkert.org } 211124SN/A } 212124SN/A 2131191SN/A functionTracingEnabled = false; 2145529Snate@binkert.org if (p->function_trace) { 2158634Schris.emmons@arm.com const string fname = csprintf("ftrace.%s", name()); 2168634Schris.emmons@arm.com functionTraceStream = simout.find(fname); 2178634Schris.emmons@arm.com if (!functionTraceStream) 2188634Schris.emmons@arm.com functionTraceStream = simout.create(fname); 2198634Schris.emmons@arm.com 2201191SN/A currentFunctionStart = currentFunctionEnd = 0; 2215529Snate@binkert.org functionEntryTick = p->function_trace_start; 2221191SN/A 2235529Snate@binkert.org if (p->function_trace_start == 0) { 2241191SN/A functionTracingEnabled = true; 2251191SN/A } else { 2265606Snate@binkert.org typedef EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace> wrap; 2275606Snate@binkert.org Event *event = new wrap(this, true); 2285606Snate@binkert.org schedule(event, p->function_trace_start); 2291191SN/A } 2301191SN/A } 2318876Sandreas.hansson@arm.com 2328876Sandreas.hansson@arm.com // The interrupts should always be present unless this CPU is 2338876Sandreas.hansson@arm.com // switched in later or in case it is a checker CPU 2349433SAndreas.Sandberg@ARM.com if (!params()->switched_out && !is_checker) { 2358876Sandreas.hansson@arm.com if (interrupts) { 2368876Sandreas.hansson@arm.com interrupts->setCPU(this); 2378876Sandreas.hansson@arm.com } else { 2388876Sandreas.hansson@arm.com fatal("CPU %s has no interrupt controller.\n" 2398876Sandreas.hansson@arm.com "Ensure createInterruptController() is called.\n", name()); 2408876Sandreas.hansson@arm.com } 2418876Sandreas.hansson@arm.com } 2425810Sgblack@eecs.umich.edu 2438779Sgblack@eecs.umich.edu if (FullSystem) { 2448779Sgblack@eecs.umich.edu if (params()->profile) 2458779Sgblack@eecs.umich.edu profileEvent = new ProfileEvent(this, params()->profile); 2468779Sgblack@eecs.umich.edu } 2475529Snate@binkert.org tracer = params()->tracer; 2489384SAndreas.Sandberg@arm.com 2499384SAndreas.Sandberg@arm.com if (params()->isa.size() != numThreads) { 2509384SAndreas.Sandberg@arm.com fatal("Number of ISAs (%i) assigned to the CPU does not equal number " 2519384SAndreas.Sandberg@arm.com "of threads (%i).\n", params()->isa.size(), numThreads); 2529384SAndreas.Sandberg@arm.com } 2531917SN/A} 2541191SN/A 2551191SN/Avoid 2561191SN/ABaseCPU::enableFunctionTrace() 2571191SN/A{ 2581191SN/A functionTracingEnabled = true; 2591191SN/A} 2601191SN/A 2611191SN/ABaseCPU::~BaseCPU() 2621191SN/A{ 2639086Sandreas.hansson@arm.com delete profileEvent; 2649086Sandreas.hansson@arm.com delete[] comLoadEventQueue; 2659086Sandreas.hansson@arm.com delete[] comInstEventQueue; 2661191SN/A} 2671191SN/A 2681129SN/Avoid 26910529Smorr@cs.wisc.eduBaseCPU::armMonitor(Addr address) 27010529Smorr@cs.wisc.edu{ 27110529Smorr@cs.wisc.edu addressMonitor.armed = true; 27210529Smorr@cs.wisc.edu addressMonitor.vAddr = address; 27310529Smorr@cs.wisc.edu addressMonitor.pAddr = 0x0; 27410529Smorr@cs.wisc.edu DPRINTF(Mwait,"Armed monitor (vAddr=0x%lx)\n", address); 27510529Smorr@cs.wisc.edu} 27610529Smorr@cs.wisc.edu 27710529Smorr@cs.wisc.edubool 27810529Smorr@cs.wisc.eduBaseCPU::mwait(PacketPtr pkt) 27910529Smorr@cs.wisc.edu{ 28010529Smorr@cs.wisc.edu if(addressMonitor.gotWakeup == false) { 28110529Smorr@cs.wisc.edu int block_size = cacheLineSize(); 28210529Smorr@cs.wisc.edu uint64_t mask = ~((uint64_t)(block_size - 1)); 28310529Smorr@cs.wisc.edu 28410529Smorr@cs.wisc.edu assert(pkt->req->hasPaddr()); 28510529Smorr@cs.wisc.edu addressMonitor.pAddr = pkt->getAddr() & mask; 28610529Smorr@cs.wisc.edu addressMonitor.waiting = true; 28710529Smorr@cs.wisc.edu 28810529Smorr@cs.wisc.edu DPRINTF(Mwait,"mwait called (vAddr=0x%lx, line's paddr=0x%lx)\n", 28910529Smorr@cs.wisc.edu addressMonitor.vAddr, addressMonitor.pAddr); 29010529Smorr@cs.wisc.edu return true; 29110529Smorr@cs.wisc.edu } else { 29210529Smorr@cs.wisc.edu addressMonitor.gotWakeup = false; 29310529Smorr@cs.wisc.edu return false; 29410529Smorr@cs.wisc.edu } 29510529Smorr@cs.wisc.edu} 29610529Smorr@cs.wisc.edu 29710529Smorr@cs.wisc.eduvoid 29810529Smorr@cs.wisc.eduBaseCPU::mwaitAtomic(ThreadContext *tc, TheISA::TLB *dtb) 29910529Smorr@cs.wisc.edu{ 30010529Smorr@cs.wisc.edu Request req; 30110529Smorr@cs.wisc.edu Addr addr = addressMonitor.vAddr; 30210529Smorr@cs.wisc.edu int block_size = cacheLineSize(); 30310529Smorr@cs.wisc.edu uint64_t mask = ~((uint64_t)(block_size - 1)); 30410529Smorr@cs.wisc.edu int size = block_size; 30510529Smorr@cs.wisc.edu 30610529Smorr@cs.wisc.edu //The address of the next line if it crosses a cache line boundary. 30710529Smorr@cs.wisc.edu Addr secondAddr = roundDown(addr + size - 1, block_size); 30810529Smorr@cs.wisc.edu 30910529Smorr@cs.wisc.edu if (secondAddr > addr) 31010529Smorr@cs.wisc.edu size = secondAddr - addr; 31110529Smorr@cs.wisc.edu 31210529Smorr@cs.wisc.edu req.setVirt(0, addr, size, 0x0, dataMasterId(), tc->instAddr()); 31310529Smorr@cs.wisc.edu 31410529Smorr@cs.wisc.edu // translate to physical address 31510529Smorr@cs.wisc.edu Fault fault = dtb->translateAtomic(&req, tc, BaseTLB::Read); 31610529Smorr@cs.wisc.edu assert(fault == NoFault); 31710529Smorr@cs.wisc.edu 31810529Smorr@cs.wisc.edu addressMonitor.pAddr = req.getPaddr() & mask; 31910529Smorr@cs.wisc.edu addressMonitor.waiting = true; 32010529Smorr@cs.wisc.edu 32110529Smorr@cs.wisc.edu DPRINTF(Mwait,"mwait called (vAddr=0x%lx, line's paddr=0x%lx)\n", 32210529Smorr@cs.wisc.edu addressMonitor.vAddr, addressMonitor.pAddr); 32310529Smorr@cs.wisc.edu} 32410529Smorr@cs.wisc.edu 32510529Smorr@cs.wisc.eduvoid 3261129SN/ABaseCPU::init() 3271129SN/A{ 3289523SAndreas.Sandberg@ARM.com if (!params()->switched_out) { 3292680Sktlim@umich.edu registerThreadContexts(); 3309523SAndreas.Sandberg@ARM.com 3319523SAndreas.Sandberg@ARM.com verifyMemoryMode(); 3329523SAndreas.Sandberg@ARM.com } 3331129SN/A} 334180SN/A 3352SN/Avoid 3361917SN/ABaseCPU::startup() 3371917SN/A{ 3388779Sgblack@eecs.umich.edu if (FullSystem) { 3399433SAndreas.Sandberg@ARM.com if (!params()->switched_out && profileEvent) 3408779Sgblack@eecs.umich.edu schedule(profileEvent, curTick()); 3418779Sgblack@eecs.umich.edu } 3422356SN/A 3435529Snate@binkert.org if (params()->progress_interval) { 3449179Sandreas.hansson@arm.com new CPUProgressEvent(this, params()->progress_interval); 3452356SN/A } 3461917SN/A} 3471917SN/A 34810464SAndreas.Sandberg@ARM.comProbePoints::PMUUPtr 34910464SAndreas.Sandberg@ARM.comBaseCPU::pmuProbePoint(const char *name) 35010464SAndreas.Sandberg@ARM.com{ 35110464SAndreas.Sandberg@ARM.com ProbePoints::PMUUPtr ptr; 35210464SAndreas.Sandberg@ARM.com ptr.reset(new ProbePoints::PMU(getProbeManager(), name)); 35310464SAndreas.Sandberg@ARM.com 35410464SAndreas.Sandberg@ARM.com return ptr; 35510464SAndreas.Sandberg@ARM.com} 35610464SAndreas.Sandberg@ARM.com 35710464SAndreas.Sandberg@ARM.comvoid 35810464SAndreas.Sandberg@ARM.comBaseCPU::regProbePoints() 35910464SAndreas.Sandberg@ARM.com{ 36010464SAndreas.Sandberg@ARM.com ppCycles = pmuProbePoint("Cycles"); 36110464SAndreas.Sandberg@ARM.com 36210464SAndreas.Sandberg@ARM.com ppRetiredInsts = pmuProbePoint("RetiredInsts"); 36310464SAndreas.Sandberg@ARM.com ppRetiredLoads = pmuProbePoint("RetiredLoads"); 36410464SAndreas.Sandberg@ARM.com ppRetiredStores = pmuProbePoint("RetiredStores"); 36510464SAndreas.Sandberg@ARM.com ppRetiredBranches = pmuProbePoint("RetiredBranches"); 36610464SAndreas.Sandberg@ARM.com} 36710464SAndreas.Sandberg@ARM.com 36810464SAndreas.Sandberg@ARM.comvoid 36910464SAndreas.Sandberg@ARM.comBaseCPU::probeInstCommit(const StaticInstPtr &inst) 37010464SAndreas.Sandberg@ARM.com{ 37110464SAndreas.Sandberg@ARM.com if (!inst->isMicroop() || inst->isLastMicroop()) 37210464SAndreas.Sandberg@ARM.com ppRetiredInsts->notify(1); 37310464SAndreas.Sandberg@ARM.com 37410464SAndreas.Sandberg@ARM.com 37510464SAndreas.Sandberg@ARM.com if (inst->isLoad()) 37610464SAndreas.Sandberg@ARM.com ppRetiredLoads->notify(1); 37710464SAndreas.Sandberg@ARM.com 37810464SAndreas.Sandberg@ARM.com if (inst->isStore()) 37910464SAndreas.Sandberg@ARM.com ppRetiredLoads->notify(1); 38010464SAndreas.Sandberg@ARM.com 38110464SAndreas.Sandberg@ARM.com if (inst->isControl()) 38210464SAndreas.Sandberg@ARM.com ppRetiredBranches->notify(1); 38310464SAndreas.Sandberg@ARM.com} 3841917SN/A 3851917SN/Avoid 3862SN/ABaseCPU::regStats() 3872SN/A{ 388729SN/A using namespace Stats; 389707SN/A 390707SN/A numCycles 391707SN/A .name(name() + ".numCycles") 392707SN/A .desc("number of cpu cycles simulated") 393707SN/A ; 394707SN/A 3957914SBrad.Beckmann@amd.com numWorkItemsStarted 3967914SBrad.Beckmann@amd.com .name(name() + ".numWorkItemsStarted") 3977914SBrad.Beckmann@amd.com .desc("number of work items this cpu started") 3987914SBrad.Beckmann@amd.com ; 3997914SBrad.Beckmann@amd.com 4007914SBrad.Beckmann@amd.com numWorkItemsCompleted 4017914SBrad.Beckmann@amd.com .name(name() + ".numWorkItemsCompleted") 4027914SBrad.Beckmann@amd.com .desc("number of work items this cpu completed") 4037914SBrad.Beckmann@amd.com ; 4047914SBrad.Beckmann@amd.com 4052680Sktlim@umich.edu int size = threadContexts.size(); 4062SN/A if (size > 1) { 4072SN/A for (int i = 0; i < size; ++i) { 4082SN/A stringstream namestr; 4092SN/A ccprintf(namestr, "%s.ctx%d", name(), i); 4102680Sktlim@umich.edu threadContexts[i]->regStats(namestr.str()); 4112SN/A } 4122SN/A } else if (size == 1) 4132680Sktlim@umich.edu threadContexts[0]->regStats(name()); 4142SN/A} 4152SN/A 4169294Sandreas.hansson@arm.comBaseMasterPort & 4179294Sandreas.hansson@arm.comBaseCPU::getMasterPort(const string &if_name, PortID idx) 4188850Sandreas.hansson@arm.com{ 4198850Sandreas.hansson@arm.com // Get the right port based on name. This applies to all the 4208850Sandreas.hansson@arm.com // subclasses of the base CPU and relies on their implementation 4218850Sandreas.hansson@arm.com // of getDataPort and getInstPort. In all cases there methods 4229608Sandreas.hansson@arm.com // return a MasterPort pointer. 4238850Sandreas.hansson@arm.com if (if_name == "dcache_port") 4248922Swilliam.wang@arm.com return getDataPort(); 4258850Sandreas.hansson@arm.com else if (if_name == "icache_port") 4268922Swilliam.wang@arm.com return getInstPort(); 4278850Sandreas.hansson@arm.com else 4288922Swilliam.wang@arm.com return MemObject::getMasterPort(if_name, idx); 4298850Sandreas.hansson@arm.com} 4308850Sandreas.hansson@arm.com 431180SN/Avoid 4322680Sktlim@umich.eduBaseCPU::registerThreadContexts() 433180SN/A{ 4346221Snate@binkert.org ThreadID size = threadContexts.size(); 4356221Snate@binkert.org for (ThreadID tid = 0; tid < size; ++tid) { 4366221Snate@binkert.org ThreadContext *tc = threadContexts[tid]; 4372378SN/A 4385718Shsul@eecs.umich.edu /** This is so that contextId and cpuId match where there is a 4395718Shsul@eecs.umich.edu * 1cpu:1context relationship. Otherwise, the order of registration 4405718Shsul@eecs.umich.edu * could affect the assignment and cpu 1 could have context id 3, for 4415718Shsul@eecs.umich.edu * example. We may even want to do something like this for SMT so that 4425718Shsul@eecs.umich.edu * cpu 0 has the lowest thread contexts and cpu N has the highest, but 4435718Shsul@eecs.umich.edu * I'll just do this for now 4445718Shsul@eecs.umich.edu */ 4456221Snate@binkert.org if (numThreads == 1) 4465718Shsul@eecs.umich.edu tc->setContextId(system->registerThreadContext(tc, _cpuId)); 4475718Shsul@eecs.umich.edu else 4485718Shsul@eecs.umich.edu tc->setContextId(system->registerThreadContext(tc)); 4498779Sgblack@eecs.umich.edu 4508779Sgblack@eecs.umich.edu if (!FullSystem) 4518779Sgblack@eecs.umich.edu tc->getProcessPtr()->assignThreadContext(tc->contextId()); 452180SN/A } 453180SN/A} 454180SN/A 455180SN/A 4564000Ssaidi@eecs.umich.eduint 4574000Ssaidi@eecs.umich.eduBaseCPU::findContext(ThreadContext *tc) 4584000Ssaidi@eecs.umich.edu{ 4596221Snate@binkert.org ThreadID size = threadContexts.size(); 4606221Snate@binkert.org for (ThreadID tid = 0; tid < size; ++tid) { 4616221Snate@binkert.org if (tc == threadContexts[tid]) 4626221Snate@binkert.org return tid; 4634000Ssaidi@eecs.umich.edu } 4644000Ssaidi@eecs.umich.edu return 0; 4654000Ssaidi@eecs.umich.edu} 4664000Ssaidi@eecs.umich.edu 467180SN/Avoid 4682798Sktlim@umich.eduBaseCPU::switchOut() 469180SN/A{ 4709430SAndreas.Sandberg@ARM.com assert(!_switchedOut); 4719430SAndreas.Sandberg@ARM.com _switchedOut = true; 4722359SN/A if (profileEvent && profileEvent->scheduled()) 4735606Snate@binkert.org deschedule(profileEvent); 4749446SAndreas.Sandberg@ARM.com 4759446SAndreas.Sandberg@ARM.com // Flush all TLBs in the CPU to avoid having stale translations if 4769446SAndreas.Sandberg@ARM.com // it gets switched in later. 4779446SAndreas.Sandberg@ARM.com flushTLBs(); 478180SN/A} 479180SN/A 480180SN/Avoid 4818737Skoansin.tan@gmail.comBaseCPU::takeOverFrom(BaseCPU *oldCPU) 482180SN/A{ 4832680Sktlim@umich.edu assert(threadContexts.size() == oldCPU->threadContexts.size()); 4849152Satgutier@umich.edu assert(_cpuId == oldCPU->cpuId()); 4859430SAndreas.Sandberg@ARM.com assert(_switchedOut); 4869430SAndreas.Sandberg@ARM.com assert(oldCPU != this); 4879332Sdam.sunwoo@arm.com _pid = oldCPU->getPid(); 4889332Sdam.sunwoo@arm.com _taskId = oldCPU->taskId(); 4899430SAndreas.Sandberg@ARM.com _switchedOut = false; 4905712Shsul@eecs.umich.edu 4916221Snate@binkert.org ThreadID size = threadContexts.size(); 4926221Snate@binkert.org for (ThreadID i = 0; i < size; ++i) { 4932680Sktlim@umich.edu ThreadContext *newTC = threadContexts[i]; 4942680Sktlim@umich.edu ThreadContext *oldTC = oldCPU->threadContexts[i]; 495180SN/A 4962680Sktlim@umich.edu newTC->takeOverFrom(oldTC); 4972651Ssaidi@eecs.umich.edu 4982680Sktlim@umich.edu CpuEvent::replaceThreadContext(oldTC, newTC); 4992651Ssaidi@eecs.umich.edu 5005714Shsul@eecs.umich.edu assert(newTC->contextId() == oldTC->contextId()); 5015715Shsul@eecs.umich.edu assert(newTC->threadId() == oldTC->threadId()); 5025714Shsul@eecs.umich.edu system->replaceThreadContext(newTC, newTC->contextId()); 5032359SN/A 5045875Ssteve.reinhardt@amd.com /* This code no longer works since the zero register (e.g., 5055875Ssteve.reinhardt@amd.com * r31 on Alpha) doesn't necessarily contain zero at this 5065875Ssteve.reinhardt@amd.com * point. 5075875Ssteve.reinhardt@amd.com if (DTRACE(Context)) 5085217Ssaidi@eecs.umich.edu ThreadContext::compare(oldTC, newTC); 5095875Ssteve.reinhardt@amd.com */ 5107781SAli.Saidi@ARM.com 5119294Sandreas.hansson@arm.com BaseMasterPort *old_itb_port = oldTC->getITBPtr()->getMasterPort(); 5129294Sandreas.hansson@arm.com BaseMasterPort *old_dtb_port = oldTC->getDTBPtr()->getMasterPort(); 5139294Sandreas.hansson@arm.com BaseMasterPort *new_itb_port = newTC->getITBPtr()->getMasterPort(); 5149294Sandreas.hansson@arm.com BaseMasterPort *new_dtb_port = newTC->getDTBPtr()->getMasterPort(); 5157781SAli.Saidi@ARM.com 5167781SAli.Saidi@ARM.com // Move over any table walker ports if they exist 5179178Sandreas.hansson@arm.com if (new_itb_port) { 5189178Sandreas.hansson@arm.com assert(!new_itb_port->isConnected()); 5197781SAli.Saidi@ARM.com assert(old_itb_port); 5209178Sandreas.hansson@arm.com assert(old_itb_port->isConnected()); 5219294Sandreas.hansson@arm.com BaseSlavePort &slavePort = old_itb_port->getSlavePort(); 5229178Sandreas.hansson@arm.com old_itb_port->unbind(); 5238922Swilliam.wang@arm.com new_itb_port->bind(slavePort); 5247781SAli.Saidi@ARM.com } 5259178Sandreas.hansson@arm.com if (new_dtb_port) { 5269178Sandreas.hansson@arm.com assert(!new_dtb_port->isConnected()); 5277781SAli.Saidi@ARM.com assert(old_dtb_port); 5289178Sandreas.hansson@arm.com assert(old_dtb_port->isConnected()); 5299294Sandreas.hansson@arm.com BaseSlavePort &slavePort = old_dtb_port->getSlavePort(); 5309178Sandreas.hansson@arm.com old_dtb_port->unbind(); 5318922Swilliam.wang@arm.com new_dtb_port->bind(slavePort); 5327781SAli.Saidi@ARM.com } 53310194SGeoffrey.Blake@arm.com newTC->getITBPtr()->takeOverFrom(oldTC->getITBPtr()); 53410194SGeoffrey.Blake@arm.com newTC->getDTBPtr()->takeOverFrom(oldTC->getDTBPtr()); 5358733Sgeoffrey.blake@arm.com 5368887Sgeoffrey.blake@arm.com // Checker whether or not we have to transfer CheckerCPU 5378887Sgeoffrey.blake@arm.com // objects over in the switch 5388887Sgeoffrey.blake@arm.com CheckerCPU *oldChecker = oldTC->getCheckerCpuPtr(); 5398887Sgeoffrey.blake@arm.com CheckerCPU *newChecker = newTC->getCheckerCpuPtr(); 5408887Sgeoffrey.blake@arm.com if (oldChecker && newChecker) { 5419294Sandreas.hansson@arm.com BaseMasterPort *old_checker_itb_port = 5428922Swilliam.wang@arm.com oldChecker->getITBPtr()->getMasterPort(); 5439294Sandreas.hansson@arm.com BaseMasterPort *old_checker_dtb_port = 5448922Swilliam.wang@arm.com oldChecker->getDTBPtr()->getMasterPort(); 5459294Sandreas.hansson@arm.com BaseMasterPort *new_checker_itb_port = 5468922Swilliam.wang@arm.com newChecker->getITBPtr()->getMasterPort(); 5479294Sandreas.hansson@arm.com BaseMasterPort *new_checker_dtb_port = 5488922Swilliam.wang@arm.com newChecker->getDTBPtr()->getMasterPort(); 5498733Sgeoffrey.blake@arm.com 55010194SGeoffrey.Blake@arm.com newChecker->getITBPtr()->takeOverFrom(oldChecker->getITBPtr()); 55110194SGeoffrey.Blake@arm.com newChecker->getDTBPtr()->takeOverFrom(oldChecker->getDTBPtr()); 55210194SGeoffrey.Blake@arm.com 5538887Sgeoffrey.blake@arm.com // Move over any table walker ports if they exist for checker 5549178Sandreas.hansson@arm.com if (new_checker_itb_port) { 5559178Sandreas.hansson@arm.com assert(!new_checker_itb_port->isConnected()); 5568887Sgeoffrey.blake@arm.com assert(old_checker_itb_port); 5579178Sandreas.hansson@arm.com assert(old_checker_itb_port->isConnected()); 5589294Sandreas.hansson@arm.com BaseSlavePort &slavePort = 5599294Sandreas.hansson@arm.com old_checker_itb_port->getSlavePort(); 5609178Sandreas.hansson@arm.com old_checker_itb_port->unbind(); 5618922Swilliam.wang@arm.com new_checker_itb_port->bind(slavePort); 5628887Sgeoffrey.blake@arm.com } 5639178Sandreas.hansson@arm.com if (new_checker_dtb_port) { 5649178Sandreas.hansson@arm.com assert(!new_checker_dtb_port->isConnected()); 5658887Sgeoffrey.blake@arm.com assert(old_checker_dtb_port); 5669178Sandreas.hansson@arm.com assert(old_checker_dtb_port->isConnected()); 5679294Sandreas.hansson@arm.com BaseSlavePort &slavePort = 5689294Sandreas.hansson@arm.com old_checker_dtb_port->getSlavePort(); 5699178Sandreas.hansson@arm.com old_checker_dtb_port->unbind(); 5708922Swilliam.wang@arm.com new_checker_dtb_port->bind(slavePort); 5718887Sgeoffrey.blake@arm.com } 5728733Sgeoffrey.blake@arm.com } 573180SN/A } 574605SN/A 5753520Sgblack@eecs.umich.edu interrupts = oldCPU->interrupts; 5765810Sgblack@eecs.umich.edu interrupts->setCPU(this); 5779152Satgutier@umich.edu oldCPU->interrupts = NULL; 5782254SN/A 5798779Sgblack@eecs.umich.edu if (FullSystem) { 5808779Sgblack@eecs.umich.edu for (ThreadID i = 0; i < size; ++i) 5818779Sgblack@eecs.umich.edu threadContexts[i]->profileClear(); 5822254SN/A 5838779Sgblack@eecs.umich.edu if (profileEvent) 5848779Sgblack@eecs.umich.edu schedule(profileEvent, curTick()); 5858779Sgblack@eecs.umich.edu } 5864192Sktlim@umich.edu 5879178Sandreas.hansson@arm.com // All CPUs have an instruction and a data port, and the new CPU's 5889178Sandreas.hansson@arm.com // ports are dangling while the old CPU has its ports connected 5899178Sandreas.hansson@arm.com // already. Unbind the old CPU and then bind the ports of the one 5909178Sandreas.hansson@arm.com // we are switching to. 5919178Sandreas.hansson@arm.com assert(!getInstPort().isConnected()); 5929178Sandreas.hansson@arm.com assert(oldCPU->getInstPort().isConnected()); 5939294Sandreas.hansson@arm.com BaseSlavePort &inst_peer_port = oldCPU->getInstPort().getSlavePort(); 5949178Sandreas.hansson@arm.com oldCPU->getInstPort().unbind(); 5959178Sandreas.hansson@arm.com getInstPort().bind(inst_peer_port); 5964192Sktlim@umich.edu 5979178Sandreas.hansson@arm.com assert(!getDataPort().isConnected()); 5989178Sandreas.hansson@arm.com assert(oldCPU->getDataPort().isConnected()); 5999294Sandreas.hansson@arm.com BaseSlavePort &data_peer_port = oldCPU->getDataPort().getSlavePort(); 6009178Sandreas.hansson@arm.com oldCPU->getDataPort().unbind(); 6019178Sandreas.hansson@arm.com getDataPort().bind(data_peer_port); 602180SN/A} 603180SN/A 6049446SAndreas.Sandberg@ARM.comvoid 6059446SAndreas.Sandberg@ARM.comBaseCPU::flushTLBs() 6069446SAndreas.Sandberg@ARM.com{ 6079446SAndreas.Sandberg@ARM.com for (ThreadID i = 0; i < threadContexts.size(); ++i) { 6089446SAndreas.Sandberg@ARM.com ThreadContext &tc(*threadContexts[i]); 6099446SAndreas.Sandberg@ARM.com CheckerCPU *checker(tc.getCheckerCpuPtr()); 6109446SAndreas.Sandberg@ARM.com 6119446SAndreas.Sandberg@ARM.com tc.getITBPtr()->flushAll(); 6129446SAndreas.Sandberg@ARM.com tc.getDTBPtr()->flushAll(); 6139446SAndreas.Sandberg@ARM.com if (checker) { 6149446SAndreas.Sandberg@ARM.com checker->getITBPtr()->flushAll(); 6159446SAndreas.Sandberg@ARM.com checker->getDTBPtr()->flushAll(); 6169446SAndreas.Sandberg@ARM.com } 6179446SAndreas.Sandberg@ARM.com } 6189446SAndreas.Sandberg@ARM.com} 6199446SAndreas.Sandberg@ARM.com 620180SN/A 6215536Srstrong@hp.comBaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, Tick _interval) 6225606Snate@binkert.org : cpu(_cpu), interval(_interval) 6231917SN/A{ } 6241917SN/A 6251917SN/Avoid 6261917SN/ABaseCPU::ProfileEvent::process() 6271917SN/A{ 6286221Snate@binkert.org ThreadID size = cpu->threadContexts.size(); 6296221Snate@binkert.org for (ThreadID i = 0; i < size; ++i) { 6302680Sktlim@umich.edu ThreadContext *tc = cpu->threadContexts[i]; 6312680Sktlim@umich.edu tc->profileSample(); 6321917SN/A } 6332254SN/A 6347823Ssteve.reinhardt@amd.com cpu->schedule(this, curTick() + interval); 6351917SN/A} 6361917SN/A 6372SN/Avoid 638921SN/ABaseCPU::serialize(std::ostream &os) 639921SN/A{ 6404000Ssaidi@eecs.umich.edu SERIALIZE_SCALAR(instCnt); 6419332Sdam.sunwoo@arm.com 6429448SAndreas.Sandberg@ARM.com if (!_switchedOut) { 6439448SAndreas.Sandberg@ARM.com /* Unlike _pid, _taskId is not serialized, as they are dynamically 6449448SAndreas.Sandberg@ARM.com * assigned unique ids that are only meaningful for the duration of 6459448SAndreas.Sandberg@ARM.com * a specific run. We will need to serialize the entire taskMap in 6469448SAndreas.Sandberg@ARM.com * system. */ 6479448SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(_pid); 6489332Sdam.sunwoo@arm.com 6499448SAndreas.Sandberg@ARM.com interrupts->serialize(os); 6509448SAndreas.Sandberg@ARM.com 6519448SAndreas.Sandberg@ARM.com // Serialize the threads, this is done by the CPU implementation. 6529448SAndreas.Sandberg@ARM.com for (ThreadID i = 0; i < numThreads; ++i) { 6539448SAndreas.Sandberg@ARM.com nameOut(os, csprintf("%s.xc.%i", name(), i)); 6549448SAndreas.Sandberg@ARM.com serializeThread(os, i); 6559448SAndreas.Sandberg@ARM.com } 6569448SAndreas.Sandberg@ARM.com } 657921SN/A} 658921SN/A 659921SN/Avoid 660921SN/ABaseCPU::unserialize(Checkpoint *cp, const std::string §ion) 661921SN/A{ 6624000Ssaidi@eecs.umich.edu UNSERIALIZE_SCALAR(instCnt); 6639448SAndreas.Sandberg@ARM.com 6649448SAndreas.Sandberg@ARM.com if (!_switchedOut) { 6659448SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(_pid); 6669448SAndreas.Sandberg@ARM.com interrupts->unserialize(cp, section); 6679448SAndreas.Sandberg@ARM.com 6689448SAndreas.Sandberg@ARM.com // Unserialize the threads, this is done by the CPU implementation. 6699448SAndreas.Sandberg@ARM.com for (ThreadID i = 0; i < numThreads; ++i) 6709448SAndreas.Sandberg@ARM.com unserializeThread(cp, csprintf("%s.xc.%i", section, i), i); 6719448SAndreas.Sandberg@ARM.com } 672921SN/A} 673921SN/A 6741191SN/Avoid 6759749Sandreas@sandberg.pp.seBaseCPU::scheduleInstStop(ThreadID tid, Counter insts, const char *cause) 6769749Sandreas@sandberg.pp.se{ 6779749Sandreas@sandberg.pp.se const Tick now(comInstEventQueue[tid]->getCurTick()); 6789983Sstever@gmail.com Event *event(new LocalSimLoopExitEvent(cause, 0)); 6799749Sandreas@sandberg.pp.se 6809749Sandreas@sandberg.pp.se comInstEventQueue[tid]->schedule(event, now + insts); 6819749Sandreas@sandberg.pp.se} 6829749Sandreas@sandberg.pp.se 68310529Smorr@cs.wisc.eduAddressMonitor::AddressMonitor() { 68410529Smorr@cs.wisc.edu armed = false; 68510529Smorr@cs.wisc.edu waiting = false; 68610529Smorr@cs.wisc.edu gotWakeup = false; 68710529Smorr@cs.wisc.edu} 68810529Smorr@cs.wisc.edu 68910529Smorr@cs.wisc.edubool AddressMonitor::doMonitor(PacketPtr pkt) { 69010529Smorr@cs.wisc.edu assert(pkt->req->hasPaddr()); 69110529Smorr@cs.wisc.edu if(armed && waiting) { 69210529Smorr@cs.wisc.edu if(pAddr == pkt->getAddr()) { 69310529Smorr@cs.wisc.edu DPRINTF(Mwait,"pAddr=0x%lx invalidated: waking up core\n", 69410529Smorr@cs.wisc.edu pkt->getAddr()); 69510529Smorr@cs.wisc.edu waiting = false; 69610529Smorr@cs.wisc.edu return true; 69710529Smorr@cs.wisc.edu } 69810529Smorr@cs.wisc.edu } 69910529Smorr@cs.wisc.edu return false; 70010529Smorr@cs.wisc.edu} 70110529Smorr@cs.wisc.edu 7029749Sandreas@sandberg.pp.sevoid 7039749Sandreas@sandberg.pp.seBaseCPU::scheduleLoadStop(ThreadID tid, Counter loads, const char *cause) 7049749Sandreas@sandberg.pp.se{ 7059749Sandreas@sandberg.pp.se const Tick now(comLoadEventQueue[tid]->getCurTick()); 7069983Sstever@gmail.com Event *event(new LocalSimLoopExitEvent(cause, 0)); 7079749Sandreas@sandberg.pp.se 7089749Sandreas@sandberg.pp.se comLoadEventQueue[tid]->schedule(event, now + loads); 7099749Sandreas@sandberg.pp.se} 7109749Sandreas@sandberg.pp.se 7119749Sandreas@sandberg.pp.se 7129749Sandreas@sandberg.pp.sevoid 7131191SN/ABaseCPU::traceFunctionsInternal(Addr pc) 7141191SN/A{ 7151191SN/A if (!debugSymbolTable) 7161191SN/A return; 7171191SN/A 7181191SN/A // if pc enters different function, print new function symbol and 7191191SN/A // update saved range. Otherwise do nothing. 7201191SN/A if (pc < currentFunctionStart || pc >= currentFunctionEnd) { 7211191SN/A string sym_str; 7221191SN/A bool found = debugSymbolTable->findNearestSymbol(pc, sym_str, 7231191SN/A currentFunctionStart, 7241191SN/A currentFunctionEnd); 7251191SN/A 7261191SN/A if (!found) { 7271191SN/A // no symbol found: use addr as label 7281191SN/A sym_str = csprintf("0x%x", pc); 7291191SN/A currentFunctionStart = pc; 7301191SN/A currentFunctionEnd = pc + 1; 7311191SN/A } 7321191SN/A 7331191SN/A ccprintf(*functionTraceStream, " (%d)\n%d: %s", 7347823Ssteve.reinhardt@amd.com curTick() - functionEntryTick, curTick(), sym_str); 7357823Ssteve.reinhardt@amd.com functionEntryTick = curTick(); 7361191SN/A } 7371191SN/A} 738