cpu.cc revision 11567
1/* 2 * Copyright (c) 2012-2014 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 "arch/utility.hh" 41#include "cpu/minor/cpu.hh" 42#include "cpu/minor/dyn_inst.hh" 43#include "cpu/minor/fetch1.hh" 44#include "cpu/minor/pipeline.hh" 45#include "debug/Drain.hh" 46#include "debug/MinorCPU.hh" 47#include "debug/Quiesce.hh" 48 49MinorCPU::MinorCPU(MinorCPUParams *params) : 50 BaseCPU(params), 51 threadPolicy(params->threadPolicy) 52{ 53 /* This is only written for one thread at the moment */ 54 Minor::MinorThread *thread; 55 56 for (ThreadID i = 0; i < numThreads; i++) { 57 if (FullSystem) { 58 thread = new Minor::MinorThread(this, i, params->system, 59 params->itb, params->dtb, params->isa[i]); 60 thread->setStatus(ThreadContext::Halted); 61 } else { 62 thread = new Minor::MinorThread(this, i, params->system, 63 params->workload[i], params->itb, params->dtb, 64 params->isa[i]); 65 } 66 67 threads.push_back(thread); 68 ThreadContext *tc = thread->getTC(); 69 threadContexts.push_back(tc); 70 } 71 72 73 if (params->checker) { 74 fatal("The Minor model doesn't support checking (yet)\n"); 75 } 76 77 Minor::MinorDynInst::init(); 78 79 pipeline = new Minor::Pipeline(*this, *params); 80 activityRecorder = pipeline->getActivityRecorder(); 81} 82 83MinorCPU::~MinorCPU() 84{ 85 delete pipeline; 86 87 for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) { 88 delete threads[thread_id]; 89 } 90} 91 92void 93MinorCPU::init() 94{ 95 BaseCPU::init(); 96 97 if (!params()->switched_out && 98 system->getMemoryMode() != Enums::timing) 99 { 100 fatal("The Minor CPU requires the memory system to be in " 101 "'timing' mode.\n"); 102 } 103 104 /* Initialise the ThreadContext's memory proxies */ 105 for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) { 106 ThreadContext *tc = getContext(thread_id); 107 108 tc->initMemProxies(tc); 109 } 110 111 /* Initialise CPUs (== threads in the ISA) */ 112 if (FullSystem && !params()->switched_out) { 113 for (ThreadID thread_id = 0; thread_id < threads.size(); thread_id++) 114 { 115 ThreadContext *tc = getContext(thread_id); 116 117 /* Initialize CPU, including PC */ 118 TheISA::initCPU(tc, cpuId()); 119 } 120 } 121} 122 123/** Stats interface from SimObject (by way of BaseCPU) */ 124void 125MinorCPU::regStats() 126{ 127 BaseCPU::regStats(); 128 stats.regStats(name(), *this); 129 pipeline->regStats(); 130} 131 132void 133MinorCPU::serializeThread(CheckpointOut &cp, ThreadID thread_id) const 134{ 135 threads[thread_id]->serialize(cp); 136} 137 138void 139MinorCPU::unserializeThread(CheckpointIn &cp, ThreadID thread_id) 140{ 141 threads[thread_id]->unserialize(cp); 142} 143 144void 145MinorCPU::serialize(CheckpointOut &cp) const 146{ 147 pipeline->serialize(cp); 148 BaseCPU::serialize(cp); 149} 150 151void 152MinorCPU::unserialize(CheckpointIn &cp) 153{ 154 pipeline->unserialize(cp); 155 BaseCPU::unserialize(cp); 156} 157 158Addr 159MinorCPU::dbg_vtophys(Addr addr) 160{ 161 /* Note that this gives you the translation for thread 0 */ 162 panic("No implementation for vtophy\n"); 163 164 return 0; 165} 166 167void 168MinorCPU::wakeup(ThreadID tid) 169{ 170 DPRINTF(Drain, "[tid:%d] MinorCPU wakeup\n", tid); 171 assert(tid < numThreads); 172 173 if (threads[tid]->status() == ThreadContext::Suspended) { 174 threads[tid]->activate(); 175 } 176} 177 178void 179MinorCPU::startup() 180{ 181 DPRINTF(MinorCPU, "MinorCPU startup\n"); 182 183 BaseCPU::startup(); 184 185 for (auto i = threads.begin(); i != threads.end(); i ++) 186 (*i)->startup(); 187 188 for (ThreadID tid = 0; tid < numThreads; tid++) { 189 threads[tid]->startup(); 190 pipeline->wakeupFetch(tid); 191 } 192} 193 194DrainState 195MinorCPU::drain() 196{ 197 if (switchedOut()) { 198 DPRINTF(Drain, "Minor CPU switched out, draining not needed.\n"); 199 return DrainState::Drained; 200 } 201 202 DPRINTF(Drain, "MinorCPU drain\n"); 203 204 /* Need to suspend all threads and wait for Execute to idle. 205 * Tell Fetch1 not to fetch */ 206 if (pipeline->drain()) { 207 DPRINTF(Drain, "MinorCPU drained\n"); 208 return DrainState::Drained; 209 } else { 210 DPRINTF(Drain, "MinorCPU not finished draining\n"); 211 return DrainState::Draining; 212 } 213} 214 215void 216MinorCPU::signalDrainDone() 217{ 218 DPRINTF(Drain, "MinorCPU drain done\n"); 219 Drainable::signalDrainDone(); 220} 221 222void 223MinorCPU::drainResume() 224{ 225 /* When taking over from another cpu make sure lastStopped 226 * is reset since it might have not been defined previously 227 * and might lead to a stats corruption */ 228 pipeline->resetLastStopped(); 229 230 if (switchedOut()) { 231 DPRINTF(Drain, "drainResume while switched out. Ignoring\n"); 232 return; 233 } 234 235 DPRINTF(Drain, "MinorCPU drainResume\n"); 236 237 if (!system->isTimingMode()) { 238 fatal("The Minor CPU requires the memory system to be in " 239 "'timing' mode.\n"); 240 } 241 242 for (ThreadID tid = 0; tid < numThreads; tid++) 243 wakeup(tid); 244 245 pipeline->drainResume(); 246} 247 248void 249MinorCPU::memWriteback() 250{ 251 DPRINTF(Drain, "MinorCPU memWriteback\n"); 252} 253 254void 255MinorCPU::switchOut() 256{ 257 DPRINTF(MinorCPU, "MinorCPU switchOut\n"); 258 259 assert(!switchedOut()); 260 BaseCPU::switchOut(); 261 262 /* Check that the CPU is drained? */ 263 activityRecorder->reset(); 264} 265 266void 267MinorCPU::takeOverFrom(BaseCPU *old_cpu) 268{ 269 DPRINTF(MinorCPU, "MinorCPU takeOverFrom\n"); 270 271 BaseCPU::takeOverFrom(old_cpu); 272} 273 274void 275MinorCPU::activateContext(ThreadID thread_id) 276{ 277 DPRINTF(MinorCPU, "ActivateContext thread: %d\n", thread_id); 278 279 /* Do some cycle accounting. lastStopped is reset to stop the 280 * wakeup call on the pipeline from adding the quiesce period 281 * to BaseCPU::numCycles */ 282 stats.quiesceCycles += pipeline->cyclesSinceLastStopped(); 283 pipeline->resetLastStopped(); 284 285 /* Wake up the thread, wakeup the pipeline tick */ 286 threads[thread_id]->activate(); 287 wakeupOnEvent(Minor::Pipeline::CPUStageId); 288 pipeline->wakeupFetch(thread_id); 289 290 BaseCPU::activateContext(thread_id); 291} 292 293void 294MinorCPU::suspendContext(ThreadID thread_id) 295{ 296 DPRINTF(MinorCPU, "SuspendContext %d\n", thread_id); 297 298 threads[thread_id]->suspend(); 299 300 BaseCPU::suspendContext(thread_id); 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 return new MinorCPU(this); 317} 318 319MasterPort &MinorCPU::getInstPort() 320{ 321 return pipeline->getInstPort(); 322} 323 324MasterPort &MinorCPU::getDataPort() 325{ 326 return pipeline->getDataPort(); 327} 328 329Counter 330MinorCPU::totalInsts() const 331{ 332 Counter ret = 0; 333 334 for (auto i = threads.begin(); i != threads.end(); i ++) 335 ret += (*i)->numInst; 336 337 return ret; 338} 339 340Counter 341MinorCPU::totalOps() const 342{ 343 Counter ret = 0; 344 345 for (auto i = threads.begin(); i != threads.end(); i ++) 346 ret += (*i)->numOp; 347 348 return ret; 349} 350