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