cpu.cc revision 10407
12330SN/A/* 22330SN/A * Copyright (c) 2012-2014 ARM Limited 32330SN/A * All rights reserved 42330SN/A * 52330SN/A * The license below extends only to copyright in the software and shall 62330SN/A * not be construed as granting a license to any other intellectual 72330SN/A * property including but not limited to intellectual property relating 82330SN/A * to a hardware implementation of the functionality of the software 92330SN/A * licensed hereunder. You may use the software subject to the license 102330SN/A * terms below provided that you ensure that this notice is replicated 112330SN/A * unmodified and in its entirety in all distributions of the software, 122330SN/A * modified or unmodified, in source code or in binary form. 132330SN/A * 142330SN/A * Redistribution and use in source and binary forms, with or without 152330SN/A * modification, are permitted provided that the following conditions are 162330SN/A * met: redistributions of source code must retain the above copyright 172330SN/A * notice, this list of conditions and the following disclaimer; 182330SN/A * redistributions in binary form must reproduce the above copyright 192330SN/A * notice, this list of conditions and the following disclaimer in the 202330SN/A * documentation and/or other materials provided with the distribution; 212330SN/A * neither the name of the copyright holders nor the names of its 222330SN/A * contributors may be used to endorse or promote products derived from 232330SN/A * this software without specific prior written permission. 242330SN/A * 252330SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 262330SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 272689Sktlim@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 282689Sktlim@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 292330SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 302292SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 312292SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 322292SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 332292SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 342980Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 352362SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 362680Sktlim@umich.edu * 372292SN/A * Authors: Andrew Bardsley 382678Sktlim@umich.edu */ 392683Sktlim@umich.edu 402683Sktlim@umich.edu#include "arch/utility.hh" 412678Sktlim@umich.edu#include "cpu/minor/cpu.hh" 422678Sktlim@umich.edu#include "cpu/minor/dyn_inst.hh" 432292SN/A#include "cpu/minor/fetch1.hh" 442292SN/A#include "cpu/minor/pipeline.hh" 452292SN/A#include "debug/Drain.hh" 462292SN/A#include "debug/MinorCPU.hh" 472330SN/A#include "debug/Quiesce.hh" 482330SN/A 492330SN/AMinorCPU::MinorCPU(MinorCPUParams *params) : 502292SN/A BaseCPU(params), 512292SN/A drainManager(NULL) 523402Sktlim@umich.edu{ 532862Sktlim@umich.edu /* This is only written for one thread at the moment */ 543402Sktlim@umich.edu Minor::MinorThread *thread; 552862Sktlim@umich.edu 562330SN/A if (FullSystem) { 572330SN/A thread = new Minor::MinorThread(this, 0, params->system, params->itb, 582330SN/A params->dtb, params->isa[0]); 592330SN/A } else { 602330SN/A /* thread_id 0 */ 612330SN/A thread = new Minor::MinorThread(this, 0, params->system, 622292SN/A params->workload[0], params->itb, params->dtb, params->isa[0]); 632683Sktlim@umich.edu } 642683Sktlim@umich.edu 652292SN/A threads.push_back(thread); 663402Sktlim@umich.edu 672292SN/A thread->setStatus(ThreadContext::Halted); 683402Sktlim@umich.edu 693402Sktlim@umich.edu ThreadContext *tc = thread->getTC(); 702292SN/A 712683Sktlim@umich.edu if (params->checker) { 722862Sktlim@umich.edu fatal("The Minor model doesn't support checking (yet)\n"); 732862Sktlim@umich.edu } 742862Sktlim@umich.edu 752862Sktlim@umich.edu threadContexts.push_back(tc); 762683Sktlim@umich.edu 772683Sktlim@umich.edu Minor::MinorDynInst::init(); 782683Sktlim@umich.edu 792683Sktlim@umich.edu pipeline = new Minor::Pipeline(*this, *params); 802683Sktlim@umich.edu activityRecorder = pipeline->getActivityRecorder(); 812683Sktlim@umich.edu} 822683Sktlim@umich.edu 832683Sktlim@umich.eduMinorCPU::~MinorCPU() 842683Sktlim@umich.edu{ 852683Sktlim@umich.edu delete pipeline; 862683Sktlim@umich.edu 872683Sktlim@umich.edu for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) { 882683Sktlim@umich.edu delete threads[thread_id]; 892683Sktlim@umich.edu } 902683Sktlim@umich.edu} 912683Sktlim@umich.edu 922683Sktlim@umich.eduvoid 932683Sktlim@umich.eduMinorCPU::init() 942683Sktlim@umich.edu{ 952683Sktlim@umich.edu BaseCPU::init(); 962683Sktlim@umich.edu 972683Sktlim@umich.edu if (!params()->switched_out && 982683Sktlim@umich.edu system->getMemoryMode() != Enums::timing) 992690Sktlim@umich.edu { 1002690Sktlim@umich.edu fatal("The Minor CPU requires the memory system to be in " 1012683Sktlim@umich.edu "'timing' mode.\n"); 1022683Sktlim@umich.edu } 1032690Sktlim@umich.edu 1042690Sktlim@umich.edu /* Initialise the ThreadContext's memory proxies */ 1052683Sktlim@umich.edu for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) { 1062683Sktlim@umich.edu ThreadContext *tc = getContext(thread_id); 1072683Sktlim@umich.edu 1082683Sktlim@umich.edu tc->initMemProxies(tc); 1093402Sktlim@umich.edu } 1102683Sktlim@umich.edu 1112683Sktlim@umich.edu /* Initialise CPUs (== threads in the ISA) */ 1122683Sktlim@umich.edu if (FullSystem && !params()->switched_out) { 1132683Sktlim@umich.edu for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) 1142683Sktlim@umich.edu { 1152678Sktlim@umich.edu ThreadContext *tc = getContext(thread_id); 1162292SN/A 1172683Sktlim@umich.edu /* Initialize CPU, including PC */ 1182683Sktlim@umich.edu TheISA::initCPU(tc, cpuId()); 1192292SN/A } 1202683Sktlim@umich.edu } 1212683Sktlim@umich.edu} 1222683Sktlim@umich.edu 1232683Sktlim@umich.edu/** Stats interface from SimObject (by way of BaseCPU) */ 1242683Sktlim@umich.eduvoid 1252683Sktlim@umich.eduMinorCPU::regStats() 1262683Sktlim@umich.edu{ 1272683Sktlim@umich.edu BaseCPU::regStats(); 1282683Sktlim@umich.edu stats.regStats(name(), *this); 1292683Sktlim@umich.edu pipeline->regStats(); 1302683Sktlim@umich.edu} 1312683Sktlim@umich.edu 1322683Sktlim@umich.eduvoid 1332683Sktlim@umich.eduMinorCPU::serializeThread(std::ostream &os, ThreadID thread_id) 1342683Sktlim@umich.edu{ 1352683Sktlim@umich.edu threads[thread_id]->serialize(os); 1362683Sktlim@umich.edu} 1372683Sktlim@umich.edu 1382683Sktlim@umich.eduvoid 1392683Sktlim@umich.eduMinorCPU::unserializeThread(Checkpoint *cp, const std::string §ion, 1402683Sktlim@umich.edu ThreadID thread_id) 1412683Sktlim@umich.edu{ 1422683Sktlim@umich.edu if (thread_id != 0) 1432683Sktlim@umich.edu fatal("Trying to load more than one thread into a MinorCPU\n"); 1442683Sktlim@umich.edu 1452683Sktlim@umich.edu threads[thread_id]->unserialize(cp, section); 1462683Sktlim@umich.edu} 1472683Sktlim@umich.edu 1482683Sktlim@umich.eduvoid 1492683Sktlim@umich.eduMinorCPU::serialize(std::ostream &os) 1502683Sktlim@umich.edu{ 1512683Sktlim@umich.edu pipeline->serialize(os); 1522683Sktlim@umich.edu BaseCPU::serialize(os); 1532683Sktlim@umich.edu} 1542683Sktlim@umich.edu 1552683Sktlim@umich.eduvoid 1562683Sktlim@umich.eduMinorCPU::unserialize(Checkpoint *cp, const std::string §ion) 1573402Sktlim@umich.edu{ 1583402Sktlim@umich.edu pipeline->unserialize(cp, section); 1593402Sktlim@umich.edu BaseCPU::unserialize(cp, section); 1602683Sktlim@umich.edu} 1612683Sktlim@umich.edu 1622292SN/AAddr 1632292SN/AMinorCPU::dbg_vtophys(Addr addr) 1642292SN/A{ 1652292SN/A /* Note that this gives you the translation for thread 0 */ 1662292SN/A panic("No implementation for vtophy\n"); 1672690Sktlim@umich.edu 1682683Sktlim@umich.edu return 0; 1692683Sktlim@umich.edu} 1702292SN/A 1712683Sktlim@umich.eduvoid 1722683Sktlim@umich.eduMinorCPU::wakeup() 1732292SN/A{ 1742292SN/A DPRINTF(Drain, "MinorCPU wakeup\n"); 1752683Sktlim@umich.edu 1762292SN/A for (auto i = threads.begin(); i != threads.end(); i ++) { 1772292SN/A if ((*i)->status() == ThreadContext::Suspended) 1782292SN/A (*i)->activate(); 1792292SN/A } 1802292SN/A 1812330SN/A DPRINTF(Drain,"Suspended Processor awoke\n"); 1822683Sktlim@umich.edu} 1832683Sktlim@umich.edu 1842683Sktlim@umich.eduvoid 1852683Sktlim@umich.eduMinorCPU::startup() 1862683Sktlim@umich.edu{ 1872683Sktlim@umich.edu DPRINTF(MinorCPU, "MinorCPU startup\n"); 1882683Sktlim@umich.edu 1892683Sktlim@umich.edu BaseCPU::startup(); 1902292SN/A 1912678Sktlim@umich.edu for (auto i = threads.begin(); i != threads.end(); i ++) 1922678Sktlim@umich.edu (*i)->startup(); 1932292SN/A 1942292SN/A /* CPU state setup, activate initial context */ 1952292SN/A activateContext(0); 1962292SN/A} 1972292SN/A 1982292SN/Aunsigned int 1992330SN/AMinorCPU::drain(DrainManager *drain_manager) 2002330SN/A{ 2012330SN/A DPRINTF(Drain, "MinorCPU drain\n"); 2022683Sktlim@umich.edu 2032683Sktlim@umich.edu drainManager = drain_manager; 2042683Sktlim@umich.edu 2052683Sktlim@umich.edu /* Need to suspend all threads and wait for Execute to idle. 2062292SN/A * Tell Fetch1 not to fetch */ 2073276Sgblack@eecs.umich.edu unsigned int ret = pipeline->drain(drain_manager); 2083276Sgblack@eecs.umich.edu 2093276Sgblack@eecs.umich.edu if (ret == 0) 2103276Sgblack@eecs.umich.edu DPRINTF(Drain, "MinorCPU drained\n"); 2113276Sgblack@eecs.umich.edu else 2123276Sgblack@eecs.umich.edu DPRINTF(Drain, "MinorCPU not finished draining\n"); 2133276Sgblack@eecs.umich.edu 2143276Sgblack@eecs.umich.edu return ret; 2153276Sgblack@eecs.umich.edu} 2163276Sgblack@eecs.umich.edu 2172690Sktlim@umich.eduvoid 2182292SN/AMinorCPU::signalDrainDone() 2192292SN/A{ 2202292SN/A DPRINTF(Drain, "MinorCPU drain done\n"); 2212292SN/A setDrainState(Drainable::Drained); 2222292SN/A drainManager->signalDrainDone(); 2232292SN/A drainManager = NULL; 2242292SN/A} 2252292SN/A 2262292SN/Avoid 2272292SN/AMinorCPU::drainResume() 2282292SN/A{ 2292292SN/A assert(getDrainState() == Drainable::Drained || 2302292SN/A getDrainState() == Drainable::Running); 2312292SN/A 2322292SN/A if (switchedOut()) { 2332292SN/A DPRINTF(Drain, "drainResume while switched out. Ignoring\n"); 2342292SN/A return; 2352292SN/A } 2362292SN/A 2372292SN/A DPRINTF(Drain, "MinorCPU drainResume\n"); 2382292SN/A 2392292SN/A if (!system->isTimingMode()) { 2402292SN/A fatal("The Minor CPU requires the memory system to be in " 2412292SN/A "'timing' mode.\n"); 2422292SN/A } 243 244 wakeup(); 245 pipeline->drainResume(); 246 247 setDrainState(Drainable::Running); 248} 249 250void 251MinorCPU::memWriteback() 252{ 253 DPRINTF(Drain, "MinorCPU memWriteback\n"); 254} 255 256void 257MinorCPU::switchOut() 258{ 259 DPRINTF(MinorCPU, "MinorCPU switchOut\n"); 260 261 assert(!switchedOut()); 262 BaseCPU::switchOut(); 263 264 /* Check that the CPU is drained? */ 265 activityRecorder->reset(); 266} 267 268void 269MinorCPU::takeOverFrom(BaseCPU *old_cpu) 270{ 271 DPRINTF(MinorCPU, "MinorCPU takeOverFrom\n"); 272 273 BaseCPU::takeOverFrom(old_cpu); 274 275 /* Don't think I need to do anything here */ 276} 277 278void 279MinorCPU::activateContext(ThreadID thread_id) 280{ 281 DPRINTF(MinorCPU, "ActivateContext thread: %d", thread_id); 282 283 /* Do some cycle accounting. lastStopped is reset to stop the 284 * wakeup call on the pipeline from adding the quiesce period 285 * to BaseCPU::numCycles */ 286 stats.quiesceCycles += pipeline->cyclesSinceLastStopped(); 287 pipeline->resetLastStopped(); 288 289 /* Wake up the thread, wakeup the pipeline tick */ 290 threads[thread_id]->activate(); 291 wakeupOnEvent(Minor::Pipeline::CPUStageId); 292 pipeline->wakeupFetch(); 293} 294 295void 296MinorCPU::suspendContext(ThreadID thread_id) 297{ 298 DPRINTF(MinorCPU, "SuspendContext %d\n", thread_id); 299 300 threads[thread_id]->suspend(); 301} 302 303void 304MinorCPU::wakeupOnEvent(unsigned int stage_id) 305{ 306 DPRINTF(Quiesce, "Event wakeup from stage %d\n", stage_id); 307 308 /* Mark that some activity has taken place and start the pipeline */ 309 activityRecorder->activateStage(stage_id); 310 pipeline->start(); 311} 312 313MinorCPU * 314MinorCPUParams::create() 315{ 316 numThreads = 1; 317 if (!FullSystem && workload.size() != 1) 318 panic("only one workload allowed"); 319 return new MinorCPU(this); 320} 321 322MasterPort &MinorCPU::getInstPort() 323{ 324 return pipeline->getInstPort(); 325} 326 327MasterPort &MinorCPU::getDataPort() 328{ 329 return pipeline->getDataPort(); 330} 331 332Counter 333MinorCPU::totalInsts() const 334{ 335 Counter ret = 0; 336 337 for (auto i = threads.begin(); i != threads.end(); i ++) 338 ret += (*i)->numInst; 339 340 return ret; 341} 342 343Counter 344MinorCPU::totalOps() const 345{ 346 Counter ret = 0; 347 348 for (auto i = threads.begin(); i != threads.end(); i ++) 349 ret += (*i)->numOp; 350 351 return ret; 352} 353