base.cc revision 7045
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/faults.hh" 32#include "arch/utility.hh" 33#include "base/cp_annotate.hh" 34#include "base/cprintf.hh" 35#include "base/inifile.hh" 36#include "base/loader/symtab.hh" 37#include "base/misc.hh" 38#include "base/pollevent.hh" 39#include "base/range.hh" 40#include "base/stats/events.hh" 41#include "base/trace.hh" 42#include "base/types.hh" 43#include "config/the_isa.hh" 44#include "cpu/base.hh" 45#include "cpu/exetrace.hh" 46#include "cpu/profile.hh" 47#include "cpu/simple/base.hh" 48#include "cpu/simple_thread.hh" 49#include "cpu/smt.hh" 50#include "cpu/static_inst.hh" 51#include "cpu/thread_context.hh" 52#include "mem/packet.hh" 53#include "mem/request.hh" 54#include "params/BaseSimpleCPU.hh" 55#include "sim/byteswap.hh" 56#include "sim/debug.hh" 57#include "sim/sim_events.hh" 58#include "sim/sim_object.hh" 59#include "sim/stats.hh" 60#include "sim/system.hh" 61 62#if FULL_SYSTEM 63#include "arch/kernel_stats.hh" 64#include "arch/stacktrace.hh" 65#include "arch/tlb.hh" 66#include "arch/vtophys.hh" 67#include "base/remote_gdb.hh" 68#else // !FULL_SYSTEM 69#include "mem/mem_object.hh" 70#endif // FULL_SYSTEM 71 72using namespace std; 73using namespace TheISA; 74 75BaseSimpleCPU::BaseSimpleCPU(BaseSimpleCPUParams *p) 76 : BaseCPU(p), traceData(NULL), thread(NULL), predecoder(NULL) 77{ 78#if FULL_SYSTEM 79 thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb); 80#else 81 thread = new SimpleThread(this, /* thread_num */ 0, p->workload[0], 82 p->itb, p->dtb); 83#endif // !FULL_SYSTEM 84 85 thread->setStatus(ThreadContext::Halted); 86 87 tc = thread->getTC(); 88 89 numInst = 0; 90 startNumInst = 0; 91 numLoad = 0; 92 startNumLoad = 0; 93 lastIcacheStall = 0; 94 lastDcacheStall = 0; 95 96 threadContexts.push_back(tc); 97 98 99 fetchOffset = 0; 100 stayAtPC = false; 101} 102 103BaseSimpleCPU::~BaseSimpleCPU() 104{ 105} 106 107void 108BaseSimpleCPU::deallocateContext(int thread_num) 109{ 110 // for now, these are equivalent 111 suspendContext(thread_num); 112} 113 114 115void 116BaseSimpleCPU::haltContext(int thread_num) 117{ 118 // for now, these are equivalent 119 suspendContext(thread_num); 120} 121 122 123void 124BaseSimpleCPU::regStats() 125{ 126 using namespace Stats; 127 128 BaseCPU::regStats(); 129 130 numInsts 131 .name(name() + ".num_insts") 132 .desc("Number of instructions executed") 133 ; 134 135 numMemRefs 136 .name(name() + ".num_refs") 137 .desc("Number of memory references") 138 ; 139 140 notIdleFraction 141 .name(name() + ".not_idle_fraction") 142 .desc("Percentage of non-idle cycles") 143 ; 144 145 idleFraction 146 .name(name() + ".idle_fraction") 147 .desc("Percentage of idle cycles") 148 ; 149 150 icacheStallCycles 151 .name(name() + ".icache_stall_cycles") 152 .desc("ICache total stall cycles") 153 .prereq(icacheStallCycles) 154 ; 155 156 dcacheStallCycles 157 .name(name() + ".dcache_stall_cycles") 158 .desc("DCache total stall cycles") 159 .prereq(dcacheStallCycles) 160 ; 161 162 icacheRetryCycles 163 .name(name() + ".icache_retry_cycles") 164 .desc("ICache total retry cycles") 165 .prereq(icacheRetryCycles) 166 ; 167 168 dcacheRetryCycles 169 .name(name() + ".dcache_retry_cycles") 170 .desc("DCache total retry cycles") 171 .prereq(dcacheRetryCycles) 172 ; 173 174 idleFraction = constant(1.0) - notIdleFraction; 175} 176 177void 178BaseSimpleCPU::resetStats() 179{ 180// startNumInst = numInst; 181 notIdleFraction = (_status != Idle); 182} 183 184void 185BaseSimpleCPU::serialize(ostream &os) 186{ 187 SERIALIZE_ENUM(_status); 188 BaseCPU::serialize(os); 189// SERIALIZE_SCALAR(inst); 190 nameOut(os, csprintf("%s.xc.0", name())); 191 thread->serialize(os); 192} 193 194void 195BaseSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 196{ 197 UNSERIALIZE_ENUM(_status); 198 BaseCPU::unserialize(cp, section); 199// UNSERIALIZE_SCALAR(inst); 200 thread->unserialize(cp, csprintf("%s.xc.0", section)); 201} 202 203void 204change_thread_state(ThreadID tid, int activate, int priority) 205{ 206} 207 208void 209BaseSimpleCPU::prefetch(Addr addr, unsigned flags) 210{ 211 if (traceData) { 212 traceData->setAddr(addr); 213 } 214 215 // need to do this... 216} 217 218void 219BaseSimpleCPU::writeHint(Addr addr, int size, unsigned flags) 220{ 221 if (traceData) { 222 traceData->setAddr(addr); 223 } 224 225 // need to do this... 226} 227 228 229Fault 230BaseSimpleCPU::copySrcTranslate(Addr src) 231{ 232#if 0 233 static bool no_warn = true; 234 unsigned blk_size = 235 (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; 236 // Only support block sizes of 64 atm. 237 assert(blk_size == 64); 238 int offset = src & (blk_size - 1); 239 240 // Make sure block doesn't span page 241 if (no_warn && 242 (src & PageMask) != ((src + blk_size) & PageMask) && 243 (src >> 40) != 0xfffffc) { 244 warn("Copied block source spans pages %x.", src); 245 no_warn = false; 246 } 247 248 memReq->reset(src & ~(blk_size - 1), blk_size); 249 250 // translate to physical address 251 Fault fault = thread->translateDataReadReq(req); 252 253 if (fault == NoFault) { 254 thread->copySrcAddr = src; 255 thread->copySrcPhysAddr = memReq->paddr + offset; 256 } else { 257 assert(!fault->isAlignmentFault()); 258 259 thread->copySrcAddr = 0; 260 thread->copySrcPhysAddr = 0; 261 } 262 return fault; 263#else 264 return NoFault; 265#endif 266} 267 268Fault 269BaseSimpleCPU::copy(Addr dest) 270{ 271#if 0 272 static bool no_warn = true; 273 unsigned blk_size = 274 (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; 275 // Only support block sizes of 64 atm. 276 assert(blk_size == 64); 277 uint8_t data[blk_size]; 278 //assert(thread->copySrcAddr); 279 int offset = dest & (blk_size - 1); 280 281 // Make sure block doesn't span page 282 if (no_warn && 283 (dest & PageMask) != ((dest + blk_size) & PageMask) && 284 (dest >> 40) != 0xfffffc) { 285 no_warn = false; 286 warn("Copied block destination spans pages %x. ", dest); 287 } 288 289 memReq->reset(dest & ~(blk_size -1), blk_size); 290 // translate to physical address 291 Fault fault = thread->translateDataWriteReq(req); 292 293 if (fault == NoFault) { 294 Addr dest_addr = memReq->paddr + offset; 295 // Need to read straight from memory since we have more than 8 bytes. 296 memReq->paddr = thread->copySrcPhysAddr; 297 thread->mem->read(memReq, data); 298 memReq->paddr = dest_addr; 299 thread->mem->write(memReq, data); 300 if (dcacheInterface) { 301 memReq->cmd = Copy; 302 memReq->completionEvent = NULL; 303 memReq->paddr = thread->copySrcPhysAddr; 304 memReq->dest = dest_addr; 305 memReq->size = 64; 306 memReq->time = curTick; 307 dcacheInterface->access(memReq); 308 } 309 } 310 else 311 assert(!fault->isAlignmentFault()); 312 313 return fault; 314#else 315 panic("copy not implemented"); 316 return NoFault; 317#endif 318} 319 320#if FULL_SYSTEM 321Addr 322BaseSimpleCPU::dbg_vtophys(Addr addr) 323{ 324 return vtophys(tc, addr); 325} 326#endif // FULL_SYSTEM 327 328#if FULL_SYSTEM 329void 330BaseSimpleCPU::wakeup() 331{ 332 if (thread->status() != ThreadContext::Suspended) 333 return; 334 335 DPRINTF(Quiesce,"Suspended Processor awoke\n"); 336 thread->activate(); 337} 338#endif // FULL_SYSTEM 339 340void 341BaseSimpleCPU::checkForInterrupts() 342{ 343#if FULL_SYSTEM 344 if (checkInterrupts(tc)) { 345 Fault interrupt = interrupts->getInterrupt(tc); 346 347 if (interrupt != NoFault) { 348 predecoder.reset(); 349 interrupts->updateIntrInfo(tc); 350 interrupt->invoke(tc); 351 } 352 } 353#endif 354} 355 356 357void 358BaseSimpleCPU::setupFetchRequest(Request *req) 359{ 360 Addr threadPC = thread->readPC(); 361 362 // set up memory request for instruction fetch 363#if ISA_HAS_DELAY_SLOT 364 DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p NNPC:%08p\n",threadPC, 365 thread->readNextPC(),thread->readNextNPC()); 366#else 367 DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p\n",threadPC, 368 thread->readNextPC()); 369#endif 370 371 Addr fetchPC = (threadPC & PCMask) + fetchOffset; 372 req->setVirt(0, fetchPC, sizeof(MachInst), Request::INST_FETCH, threadPC); 373} 374 375 376void 377BaseSimpleCPU::preExecute() 378{ 379 // maintain $r0 semantics 380 thread->setIntReg(ZeroReg, 0); 381#if THE_ISA == ALPHA_ISA 382 thread->setFloatReg(ZeroReg, 0.0); 383#endif // ALPHA_ISA 384 385 // check for instruction-count-based events 386 comInstEventQueue[0]->serviceEvents(numInst); 387 388 // decode the instruction 389 inst = gtoh(inst); 390 391 MicroPC upc = thread->readMicroPC(); 392 393 if (isRomMicroPC(upc)) { 394 stayAtPC = false; 395 curStaticInst = microcodeRom.fetchMicroop(upc, curMacroStaticInst); 396 } else if (!curMacroStaticInst) { 397 //We're not in the middle of a macro instruction 398 StaticInstPtr instPtr = NULL; 399 400 //Predecode, ie bundle up an ExtMachInst 401 //This should go away once the constructor can be set up properly 402 predecoder.setTC(thread->getTC()); 403 //If more fetch data is needed, pass it in. 404 Addr fetchPC = (thread->readPC() & PCMask) + fetchOffset; 405 //if(predecoder.needMoreBytes()) 406 predecoder.moreBytes(thread->readPC(), fetchPC, inst); 407 //else 408 // predecoder.process(); 409 410 //If an instruction is ready, decode it. Otherwise, we'll have to 411 //fetch beyond the MachInst at the current pc. 412 if (predecoder.extMachInstReady()) { 413#if THE_ISA == X86_ISA 414 thread->setNextPC(thread->readPC() + predecoder.getInstSize()); 415#endif // X86_ISA 416 stayAtPC = false; 417 instPtr = StaticInst::decode(predecoder.getExtMachInst(), 418 thread->readPC()); 419 } else { 420 stayAtPC = true; 421 fetchOffset += sizeof(MachInst); 422 } 423 424 //If we decoded an instruction and it's microcoded, start pulling 425 //out micro ops 426 if (instPtr && instPtr->isMacroop()) { 427 curMacroStaticInst = instPtr; 428 curStaticInst = curMacroStaticInst->fetchMicroop(upc); 429 } else { 430 curStaticInst = instPtr; 431 } 432 } else { 433 //Read the next micro op from the macro op 434 curStaticInst = curMacroStaticInst->fetchMicroop(upc); 435 } 436 437 //If we decoded an instruction this "tick", record information about it. 438 if(curStaticInst) 439 { 440#if TRACING_ON 441 traceData = tracer->getInstRecord(curTick, tc, 442 curStaticInst, thread->readPC(), 443 curMacroStaticInst, thread->readMicroPC()); 444 445 DPRINTF(Decode,"Decode: Decoded %s instruction: 0x%x\n", 446 curStaticInst->getName(), curStaticInst->machInst); 447#endif // TRACING_ON 448 449#if FULL_SYSTEM 450 thread->setInst(inst); 451#endif // FULL_SYSTEM 452 } 453} 454 455void 456BaseSimpleCPU::postExecute() 457{ 458#if FULL_SYSTEM 459 if (thread->profile && curStaticInst) { 460 bool usermode = TheISA::inUserMode(tc); 461 thread->profilePC = usermode ? 1 : thread->readPC(); 462 ProfileNode *node = thread->profile->consume(tc, curStaticInst); 463 if (node) 464 thread->profileNode = node; 465 } 466#endif 467 468 if (curStaticInst->isMemRef()) { 469 numMemRefs++; 470 } 471 472 if (curStaticInst->isLoad()) { 473 ++numLoad; 474 comLoadEventQueue[0]->serviceEvents(numLoad); 475 } 476 477 if (CPA::available()) { 478 CPA::cpa()->swAutoBegin(tc, thread->readNextPC()); 479 } 480 481 traceFunctions(thread->readPC()); 482 483 if (traceData) { 484 traceData->dump(); 485 delete traceData; 486 traceData = NULL; 487 } 488} 489 490 491void 492BaseSimpleCPU::advancePC(Fault fault) 493{ 494 //Since we're moving to a new pc, zero out the offset 495 fetchOffset = 0; 496 if (fault != NoFault) { 497 curMacroStaticInst = StaticInst::nullStaticInstPtr; 498 predecoder.reset(); 499 fault->invoke(tc); 500 } else { 501 //If we're at the last micro op for this instruction 502 if (curStaticInst && curStaticInst->isLastMicroop()) { 503 //We should be working with a macro op or be in the ROM 504 assert(curMacroStaticInst || 505 isRomMicroPC(thread->readMicroPC())); 506 //Close out this macro op, and clean up the 507 //microcode state 508 curMacroStaticInst = StaticInst::nullStaticInstPtr; 509 thread->setMicroPC(normalMicroPC(0)); 510 thread->setNextMicroPC(normalMicroPC(1)); 511 } 512 //If we're still in a macro op 513 if (curMacroStaticInst || isRomMicroPC(thread->readMicroPC())) { 514 //Advance the micro pc 515 thread->setMicroPC(thread->readNextMicroPC()); 516 //Advance the "next" micro pc. Note that there are no delay 517 //slots, and micro ops are "word" addressed. 518 thread->setNextMicroPC(thread->readNextMicroPC() + 1); 519 } else { 520 // go to the next instruction 521 thread->setPC(thread->readNextPC()); 522 thread->setNextPC(thread->readNextNPC()); 523 thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst)); 524 assert(thread->readNextPC() != thread->readNextNPC()); 525 } 526 } 527} 528 529/*Fault 530BaseSimpleCPU::CacheOp(uint8_t Op, Addr EffAddr) 531{ 532 // translate to physical address 533 Fault fault = NoFault; 534 int CacheID = Op & 0x3; // Lower 3 bits identify Cache 535 int CacheOP = Op >> 2; // Upper 3 bits identify Cache Operation 536 if(CacheID > 1) 537 { 538 warn("CacheOps not implemented for secondary/tertiary caches\n"); 539 } 540 else 541 { 542 switch(CacheOP) 543 { // Fill Packet Type 544 case 0: warn("Invalidate Cache Op\n"); 545 break; 546 case 1: warn("Index Load Tag Cache Op\n"); 547 break; 548 case 2: warn("Index Store Tag Cache Op\n"); 549 break; 550 case 4: warn("Hit Invalidate Cache Op\n"); 551 break; 552 case 5: warn("Fill/Hit Writeback Invalidate Cache Op\n"); 553 break; 554 case 6: warn("Hit Writeback\n"); 555 break; 556 case 7: warn("Fetch & Lock Cache Op\n"); 557 break; 558 default: warn("Unimplemented Cache Op\n"); 559 } 560 } 561 return fault; 562}*/ 563