cpu.cc revision 13632:483aaa00c69c
1/* 2 * Copyright (c) 2012-2014, 2017 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Andrew Bardsley 38 */ 39 40#include "cpu/minor/cpu.hh" 41 42#include "arch/utility.hh" 43#include "cpu/minor/dyn_inst.hh" 44#include "cpu/minor/fetch1.hh" 45#include "cpu/minor/pipeline.hh" 46#include "debug/Drain.hh" 47#include "debug/MinorCPU.hh" 48#include "debug/Quiesce.hh" 49 50MinorCPU::MinorCPU(MinorCPUParams *params) : 51 BaseCPU(params), 52 pipelineStartupEvent([this]{ wakeupPipeline(); }, name()), 53 threadPolicy(params->threadPolicy) 54{ 55 /* This is only written for one thread at the moment */ 56 Minor::MinorThread *thread; 57 58 for (ThreadID i = 0; i < numThreads; i++) { 59 if (FullSystem) { 60 thread = new Minor::MinorThread(this, i, params->system, 61 params->itb, params->dtb, params->isa[i]); 62 thread->setStatus(ThreadContext::Halted); 63 } else { 64 thread = new Minor::MinorThread(this, i, params->system, 65 params->workload[i], params->itb, params->dtb, 66 params->isa[i]); 67 } 68 69 threads.push_back(thread); 70 ThreadContext *tc = thread->getTC(); 71 threadContexts.push_back(tc); 72 } 73 74 75 if (params->checker) { 76 fatal("The Minor model doesn't support checking (yet)\n"); 77 } 78 79 Minor::MinorDynInst::init(); 80 81 pipeline = new Minor::Pipeline(*this, *params); 82 activityRecorder = pipeline->getActivityRecorder(); 83} 84 85MinorCPU::~MinorCPU() 86{ 87 delete pipeline; 88 89 for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) { 90 delete threads[thread_id]; 91 } 92} 93 94void 95MinorCPU::init() 96{ 97 BaseCPU::init(); 98 99 if (!params()->switched_out && 100 system->getMemoryMode() != Enums::timing) 101 { 102 fatal("The Minor CPU requires the memory system to be in " 103 "'timing' mode.\n"); 104 } 105 106 /* Initialise the ThreadContext's memory proxies */ 107 for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) { 108 ThreadContext *tc = getContext(thread_id); 109 110 tc->initMemProxies(tc); 111 } 112 113 /* Initialise CPUs (== threads in the ISA) */ 114 if (FullSystem && !params()->switched_out) { 115 for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) 116 { 117 ThreadContext *tc = getContext(thread_id); 118 119 /* Initialize CPU, including PC */ 120 TheISA::initCPU(tc, cpuId()); 121 } 122 } 123} 124 125/** Stats interface from SimObject (by way of BaseCPU) */ 126void 127MinorCPU::regStats() 128{ 129 BaseCPU::regStats(); 130 stats.regStats(name(), *this); 131 pipeline->regStats(); 132} 133 134void 135MinorCPU::serializeThread(CheckpointOut &cp, ThreadID thread_id) const 136{ 137 threads[thread_id]->serialize(cp); 138} 139 140void 141MinorCPU::unserializeThread(CheckpointIn &cp, ThreadID thread_id) 142{ 143 threads[thread_id]->unserialize(cp); 144} 145 146void 147MinorCPU::serialize(CheckpointOut &cp) const 148{ 149 pipeline->serialize(cp); 150 BaseCPU::serialize(cp); 151} 152 153void 154MinorCPU::unserialize(CheckpointIn &cp) 155{ 156 pipeline->unserialize(cp); 157 BaseCPU::unserialize(cp); 158} 159 160Addr 161MinorCPU::dbg_vtophys(Addr addr) 162{ 163 /* Note that this gives you the translation for thread 0 */ 164 panic("No implementation for vtophy\n"); 165 166 return 0; 167} 168 169void 170MinorCPU::wakeup(ThreadID tid) 171{ 172 DPRINTF(Drain, "[tid:%d] MinorCPU wakeup\n", tid); 173 assert(tid < numThreads); 174 175 if (threads[tid]->status() == ThreadContext::Suspended) { 176 threads[tid]->activate(); 177 } 178} 179 180void 181MinorCPU::startup() 182{ 183 DPRINTF(MinorCPU, "MinorCPU startup\n"); 184 185 BaseCPU::startup(); 186 187 for (ThreadID tid = 0; tid < numThreads; tid++) { 188 threads[tid]->startup(); 189 pipeline->wakeupFetch(tid); 190 } 191} 192 193DrainState 194MinorCPU::drain() 195{ 196 // Deschedule any power gating event (if any) 197 deschedulePowerGatingEvent(); 198 199 if (switchedOut()) { 200 DPRINTF(Drain, "Minor CPU switched out, draining not needed.\n"); 201 return DrainState::Drained; 202 } 203 204 DPRINTF(Drain, "MinorCPU drain\n"); 205 206 /* Need to suspend all threads and wait for Execute to idle. 207 * Tell Fetch1 not to fetch */ 208 if (pipeline->drain()) { 209 DPRINTF(Drain, "MinorCPU drained\n"); 210 return DrainState::Drained; 211 } else { 212 DPRINTF(Drain, "MinorCPU not finished draining\n"); 213 return DrainState::Draining; 214 } 215} 216 217void 218MinorCPU::signalDrainDone() 219{ 220 DPRINTF(Drain, "MinorCPU drain done\n"); 221 Drainable::signalDrainDone(); 222} 223 224void 225MinorCPU::drainResume() 226{ 227 /* When taking over from another cpu make sure lastStopped 228 * is reset since it might have not been defined previously 229 * and might lead to a stats corruption */ 230 pipeline->resetLastStopped(); 231 232 if (switchedOut()) { 233 DPRINTF(Drain, "drainResume while switched out. Ignoring\n"); 234 return; 235 } 236 237 DPRINTF(Drain, "MinorCPU drainResume\n"); 238 239 if (!system->isTimingMode()) { 240 fatal("The Minor CPU requires the memory system to be in " 241 "'timing' mode.\n"); 242 } 243 244 for (ThreadID tid = 0; tid < numThreads; tid++){ 245 wakeup(tid); 246 } 247 248 pipeline->drainResume(); 249 250 // Reschedule any power gating event (if any) 251 schedulePowerGatingEvent(); 252} 253 254void 255MinorCPU::memWriteback() 256{ 257 DPRINTF(Drain, "MinorCPU memWriteback\n"); 258} 259 260void 261MinorCPU::switchOut() 262{ 263 DPRINTF(MinorCPU, "MinorCPU switchOut\n"); 264 265 assert(!switchedOut()); 266 BaseCPU::switchOut(); 267 268 /* Check that the CPU is drained? */ 269 activityRecorder->reset(); 270} 271 272void 273MinorCPU::takeOverFrom(BaseCPU *old_cpu) 274{ 275 DPRINTF(MinorCPU, "MinorCPU takeOverFrom\n"); 276 277 BaseCPU::takeOverFrom(old_cpu); 278} 279 280void 281MinorCPU::activateContext(ThreadID thread_id) 282{ 283 /* Remember to wake up this thread_id by scheduling the 284 * pipelineStartup event. 285 * We can't wakeupFetch the thread right away because its context may 286 * not have been fully initialized. For example, in the case of clone 287 * syscall, this activateContext function is called in the middle of 288 * the syscall and before the new thread context is initialized. 289 * If we start fetching right away, the new thread will fetch from an 290 * invalid address (i.e., pc is not initialized yet), which could lead 291 * to a page fault. Instead, we remember which threads to wake up and 292 * schedule an event to wake all them up after their contexts are 293 * fully initialized */ 294 readyThreads.push_back(thread_id); 295 if (!pipelineStartupEvent.scheduled()) 296 schedule(pipelineStartupEvent, clockEdge(Cycles(0))); 297} 298 299void 300MinorCPU::wakeupPipeline() 301{ 302 for (auto thread_id : readyThreads) { 303 DPRINTF(MinorCPU, "ActivateContext thread: %d\n", thread_id); 304 305 /* Do some cycle accounting. lastStopped is reset to stop the 306 * wakeup call on the pipeline from adding the quiesce period 307 * to BaseCPU::numCycles */ 308 stats.quiesceCycles += pipeline->cyclesSinceLastStopped(); 309 pipeline->resetLastStopped(); 310 311 /* Wake up the thread, wakeup the pipeline tick */ 312 threads[thread_id]->activate(); 313 wakeupOnEvent(Minor::Pipeline::CPUStageId); 314 315 pipeline->wakeupFetch(thread_id); 316 BaseCPU::activateContext(thread_id); 317 } 318 319 readyThreads.clear(); 320} 321 322void 323MinorCPU::suspendContext(ThreadID thread_id) 324{ 325 DPRINTF(MinorCPU, "SuspendContext %d\n", thread_id); 326 327 threads[thread_id]->suspend(); 328 329 BaseCPU::suspendContext(thread_id); 330} 331 332void 333MinorCPU::wakeupOnEvent(unsigned int stage_id) 334{ 335 DPRINTF(Quiesce, "Event wakeup from stage %d\n", stage_id); 336 337 /* Mark that some activity has taken place and start the pipeline */ 338 activityRecorder->activateStage(stage_id); 339 pipeline->start(); 340} 341 342MinorCPU * 343MinorCPUParams::create() 344{ 345 return new MinorCPU(this); 346} 347 348MasterPort &MinorCPU::getInstPort() 349{ 350 return pipeline->getInstPort(); 351} 352 353MasterPort &MinorCPU::getDataPort() 354{ 355 return pipeline->getDataPort(); 356} 357 358Counter 359MinorCPU::totalInsts() const 360{ 361 Counter ret = 0; 362 363 for (auto i = threads.begin(); i != threads.end(); i ++) 364 ret += (*i)->numInst; 365 366 return ret; 367} 368 369Counter 370MinorCPU::totalOps() const 371{ 372 Counter ret = 0; 373 374 for (auto i = threads.begin(); i != threads.end(); i ++) 375 ret += (*i)->numOp; 376 377 return ret; 378} 379