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