base.cc revision 4376
1/* 2 * Copyright (c) 2002-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Steve Reinhardt 29 */ 30 31#include "arch/utility.hh" 32#include "arch/faults.hh" 33#include "base/cprintf.hh" 34#include "base/inifile.hh" 35#include "base/loader/symtab.hh" 36#include "base/misc.hh" 37#include "base/pollevent.hh" 38#include "base/range.hh" 39#include "base/stats/events.hh" 40#include "base/trace.hh" 41#include "cpu/base.hh" 42#include "cpu/exetrace.hh" 43#include "cpu/profile.hh" 44#include "cpu/simple/base.hh" 45#include "cpu/simple_thread.hh" 46#include "cpu/smt.hh" 47#include "cpu/static_inst.hh" 48#include "cpu/thread_context.hh" 49#include "mem/packet.hh" 50#include "sim/builder.hh" 51#include "sim/byteswap.hh" 52#include "sim/debug.hh" 53#include "sim/host.hh" 54#include "sim/sim_events.hh" 55#include "sim/sim_object.hh" 56#include "sim/stats.hh" 57#include "sim/system.hh" 58 59#if FULL_SYSTEM 60#include "arch/kernel_stats.hh" 61#include "arch/stacktrace.hh" 62#include "arch/tlb.hh" 63#include "arch/vtophys.hh" 64#include "base/remote_gdb.hh" 65#else // !FULL_SYSTEM 66#include "mem/mem_object.hh" 67#endif // FULL_SYSTEM 68 69using namespace std; 70using namespace TheISA; 71 72BaseSimpleCPU::BaseSimpleCPU(Params *p) 73 : BaseCPU(p), thread(NULL), predecoder(NULL) 74{ 75#if FULL_SYSTEM 76 thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb); 77#else 78 thread = new SimpleThread(this, /* thread_num */ 0, p->process, 79 /* asid */ 0); 80#endif // !FULL_SYSTEM 81 82 thread->setStatus(ThreadContext::Suspended); 83 84 tc = thread->getTC(); 85 86 numInst = 0; 87 startNumInst = 0; 88 numLoad = 0; 89 startNumLoad = 0; 90 lastIcacheStall = 0; 91 lastDcacheStall = 0; 92 93 threadContexts.push_back(tc); 94} 95 96BaseSimpleCPU::~BaseSimpleCPU() 97{ 98} 99 100void 101BaseSimpleCPU::deallocateContext(int thread_num) 102{ 103 // for now, these are equivalent 104 suspendContext(thread_num); 105} 106 107 108void 109BaseSimpleCPU::haltContext(int thread_num) 110{ 111 // for now, these are equivalent 112 suspendContext(thread_num); 113} 114 115 116void 117BaseSimpleCPU::regStats() 118{ 119 using namespace Stats; 120 121 BaseCPU::regStats(); 122 123 numInsts 124 .name(name() + ".num_insts") 125 .desc("Number of instructions executed") 126 ; 127 128 numMemRefs 129 .name(name() + ".num_refs") 130 .desc("Number of memory references") 131 ; 132 133 notIdleFraction 134 .name(name() + ".not_idle_fraction") 135 .desc("Percentage of non-idle cycles") 136 ; 137 138 idleFraction 139 .name(name() + ".idle_fraction") 140 .desc("Percentage of idle cycles") 141 ; 142 143 icacheStallCycles 144 .name(name() + ".icache_stall_cycles") 145 .desc("ICache total stall cycles") 146 .prereq(icacheStallCycles) 147 ; 148 149 dcacheStallCycles 150 .name(name() + ".dcache_stall_cycles") 151 .desc("DCache total stall cycles") 152 .prereq(dcacheStallCycles) 153 ; 154 155 icacheRetryCycles 156 .name(name() + ".icache_retry_cycles") 157 .desc("ICache total retry cycles") 158 .prereq(icacheRetryCycles) 159 ; 160 161 dcacheRetryCycles 162 .name(name() + ".dcache_retry_cycles") 163 .desc("DCache total retry cycles") 164 .prereq(dcacheRetryCycles) 165 ; 166 167 idleFraction = constant(1.0) - notIdleFraction; 168} 169 170void 171BaseSimpleCPU::resetStats() 172{ 173// startNumInst = numInst; 174 // notIdleFraction = (_status != Idle); 175} 176 177void 178BaseSimpleCPU::serialize(ostream &os) 179{ 180 BaseCPU::serialize(os); 181// SERIALIZE_SCALAR(inst); 182 nameOut(os, csprintf("%s.xc.0", name())); 183 thread->serialize(os); 184} 185 186void 187BaseSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 188{ 189 BaseCPU::unserialize(cp, section); 190// UNSERIALIZE_SCALAR(inst); 191 thread->unserialize(cp, csprintf("%s.xc.0", section)); 192} 193 194void 195change_thread_state(int thread_number, int activate, int priority) 196{ 197} 198 199Fault 200BaseSimpleCPU::copySrcTranslate(Addr src) 201{ 202#if 0 203 static bool no_warn = true; 204 int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; 205 // Only support block sizes of 64 atm. 206 assert(blk_size == 64); 207 int offset = src & (blk_size - 1); 208 209 // Make sure block doesn't span page 210 if (no_warn && 211 (src & PageMask) != ((src + blk_size) & PageMask) && 212 (src >> 40) != 0xfffffc) { 213 warn("Copied block source spans pages %x.", src); 214 no_warn = false; 215 } 216 217 memReq->reset(src & ~(blk_size - 1), blk_size); 218 219 // translate to physical address 220 Fault fault = thread->translateDataReadReq(req); 221 222 if (fault == NoFault) { 223 thread->copySrcAddr = src; 224 thread->copySrcPhysAddr = memReq->paddr + offset; 225 } else { 226 assert(!fault->isAlignmentFault()); 227 228 thread->copySrcAddr = 0; 229 thread->copySrcPhysAddr = 0; 230 } 231 return fault; 232#else 233 return NoFault; 234#endif 235} 236 237Fault 238BaseSimpleCPU::copy(Addr dest) 239{ 240#if 0 241 static bool no_warn = true; 242 int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; 243 // Only support block sizes of 64 atm. 244 assert(blk_size == 64); 245 uint8_t data[blk_size]; 246 //assert(thread->copySrcAddr); 247 int offset = dest & (blk_size - 1); 248 249 // Make sure block doesn't span page 250 if (no_warn && 251 (dest & PageMask) != ((dest + blk_size) & PageMask) && 252 (dest >> 40) != 0xfffffc) { 253 no_warn = false; 254 warn("Copied block destination spans pages %x. ", dest); 255 } 256 257 memReq->reset(dest & ~(blk_size -1), blk_size); 258 // translate to physical address 259 Fault fault = thread->translateDataWriteReq(req); 260 261 if (fault == NoFault) { 262 Addr dest_addr = memReq->paddr + offset; 263 // Need to read straight from memory since we have more than 8 bytes. 264 memReq->paddr = thread->copySrcPhysAddr; 265 thread->mem->read(memReq, data); 266 memReq->paddr = dest_addr; 267 thread->mem->write(memReq, data); 268 if (dcacheInterface) { 269 memReq->cmd = Copy; 270 memReq->completionEvent = NULL; 271 memReq->paddr = thread->copySrcPhysAddr; 272 memReq->dest = dest_addr; 273 memReq->size = 64; 274 memReq->time = curTick; 275 memReq->flags &= ~INST_READ; 276 dcacheInterface->access(memReq); 277 } 278 } 279 else 280 assert(!fault->isAlignmentFault()); 281 282 return fault; 283#else 284 panic("copy not implemented"); 285 return NoFault; 286#endif 287} 288 289#if FULL_SYSTEM 290Addr 291BaseSimpleCPU::dbg_vtophys(Addr addr) 292{ 293 return vtophys(tc, addr); 294} 295#endif // FULL_SYSTEM 296 297#if FULL_SYSTEM 298void 299BaseSimpleCPU::post_interrupt(int int_num, int index) 300{ 301 BaseCPU::post_interrupt(int_num, index); 302 303 if (thread->status() == ThreadContext::Suspended) { 304 DPRINTF(Quiesce,"Suspended Processor awoke\n"); 305 thread->activate(); 306 } 307} 308#endif // FULL_SYSTEM 309 310void 311BaseSimpleCPU::checkForInterrupts() 312{ 313#if FULL_SYSTEM 314 if (check_interrupts(tc)) { 315 Fault interrupt = interrupts.getInterrupt(tc); 316 317 if (interrupt != NoFault) { 318 interrupts.updateIntrInfo(tc); 319 interrupt->invoke(tc); 320 } 321 } 322#endif 323} 324 325 326Fault 327BaseSimpleCPU::setupFetchRequest(Request *req) 328{ 329 // set up memory request for instruction fetch 330#if ISA_HAS_DELAY_SLOT 331 DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p NNPC:%08p\n",thread->readPC(), 332 thread->readNextPC(),thread->readNextNPC()); 333#else 334 DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p",thread->readPC(), 335 thread->readNextPC()); 336#endif 337 338 // This will generate a mask which aligns the pc on MachInst size 339 // boundaries. It won't work for non-power-of-two sized MachInsts, but 340 // it will work better than a hard coded mask. 341 const Addr PCMask = ~(sizeof(MachInst) - 1); 342 req->setVirt(0, thread->readPC() & PCMask, sizeof(MachInst), 0, 343 thread->readPC()); 344 345 Fault fault = thread->translateInstReq(req); 346 347 return fault; 348} 349 350 351void 352BaseSimpleCPU::preExecute() 353{ 354 // maintain $r0 semantics 355 thread->setIntReg(ZeroReg, 0); 356#if THE_ISA == ALPHA_ISA 357 thread->setFloatReg(ZeroReg, 0.0); 358#endif // ALPHA_ISA 359 360 // keep an instruction count 361 numInst++; 362 numInsts++; 363 364 thread->funcExeInst++; 365 366 // check for instruction-count-based events 367 comInstEventQueue[0]->serviceEvents(numInst); 368 369 // decode the instruction 370 inst = gtoh(inst); 371 //If we're not in the middle of a macro instruction 372 if (!curMacroStaticInst) { 373 StaticInstPtr instPtr = NULL; 374 375 //Predecode, ie bundle up an ExtMachInst 376 //This should go away once the constructor can be set up properly 377 predecoder.setTC(thread->getTC()); 378 //If more fetch data is needed, pass it in. 379 if(predecoder.needMoreBytes()) 380 predecoder.moreBytes(thread->readPC(), 0, inst); 381 else 382 predecoder.process(); 383 //If an instruction is ready, decode it 384 if (predecoder.extMachInstReady()) 385 instPtr = StaticInst::decode(predecoder.getExtMachInst()); 386 387 //If we decoded an instruction and it's microcoded, start pulling 388 //out micro ops 389 if (instPtr && instPtr->isMacroOp()) { 390 curMacroStaticInst = instPtr; 391 curStaticInst = curMacroStaticInst-> 392 fetchMicroOp(thread->readMicroPC()); 393 } else { 394 curStaticInst = instPtr; 395 } 396 } else { 397 //Read the next micro op from the macro op 398 curStaticInst = curMacroStaticInst-> 399 fetchMicroOp(thread->readMicroPC()); 400 } 401 402 //If we decoded an instruction this "tick", record information about it. 403 if(curStaticInst) 404 { 405 traceData = Trace::getInstRecord(curTick, tc, curStaticInst, 406 thread->readPC()); 407 408 DPRINTF(Decode,"Decode: Decoded %s instruction: 0x%x\n", 409 curStaticInst->getName(), curStaticInst->machInst); 410 411#if FULL_SYSTEM 412 thread->setInst(inst); 413#endif // FULL_SYSTEM 414 } 415} 416 417void 418BaseSimpleCPU::postExecute() 419{ 420#if FULL_SYSTEM 421 if (thread->profile) { 422 bool usermode = TheISA::inUserMode(tc); 423 thread->profilePC = usermode ? 1 : thread->readPC(); 424 StaticInstPtr si(inst); 425 ProfileNode *node = thread->profile->consume(tc, si); 426 if (node) 427 thread->profileNode = node; 428 } 429#endif 430 431 if (curStaticInst->isMemRef()) { 432 numMemRefs++; 433 } 434 435 if (curStaticInst->isLoad()) { 436 ++numLoad; 437 comLoadEventQueue[0]->serviceEvents(numLoad); 438 } 439 440 traceFunctions(thread->readPC()); 441 442 if (traceData) { 443 traceData->dump(); 444 delete traceData; 445 traceData = NULL; 446 } 447} 448 449 450void 451BaseSimpleCPU::advancePC(Fault fault) 452{ 453 if (fault != NoFault) { 454 curMacroStaticInst = StaticInst::nullStaticInstPtr; 455 fault->invoke(tc); 456 thread->setMicroPC(0); 457 thread->setNextMicroPC(1); 458 } else if (predecoder.needMoreBytes()) { 459 //If we're at the last micro op for this instruction 460 if (curStaticInst && curStaticInst->isLastMicroOp()) { 461 //We should be working with a macro op 462 assert(curMacroStaticInst); 463 //Close out this macro op, and clean up the 464 //microcode state 465 curMacroStaticInst = StaticInst::nullStaticInstPtr; 466 thread->setMicroPC(0); 467 thread->setNextMicroPC(1); 468 } 469 //If we're still in a macro op 470 if (curMacroStaticInst) { 471 //Advance the micro pc 472 thread->setMicroPC(thread->readNextMicroPC()); 473 //Advance the "next" micro pc. Note that there are no delay 474 //slots, and micro ops are "word" addressed. 475 thread->setNextMicroPC(thread->readNextMicroPC() + 1); 476 } else { 477 // go to the next instruction 478 thread->setPC(thread->readNextPC()); 479 thread->setNextPC(thread->readNextNPC()); 480 thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst)); 481 assert(thread->readNextPC() != thread->readNextNPC()); 482 } 483 } 484 485#if FULL_SYSTEM 486 Addr oldpc; 487 do { 488 oldpc = thread->readPC(); 489 system->pcEventQueue.service(tc); 490 } while (oldpc != thread->readPC()); 491#endif 492} 493 494