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