base.cc revision 4522
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), traceData(NULL), 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::Unallocated); 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 fetchOffset = 0; 96 stayAtPC = false; 97} 98 99BaseSimpleCPU::~BaseSimpleCPU() 100{ 101} 102 103void 104BaseSimpleCPU::deallocateContext(int thread_num) 105{ 106 // for now, these are equivalent 107 suspendContext(thread_num); 108} 109 110 111void 112BaseSimpleCPU::haltContext(int thread_num) 113{ 114 // for now, these are equivalent 115 suspendContext(thread_num); 116} 117 118 119void 120BaseSimpleCPU::regStats() 121{ 122 using namespace Stats; 123 124 BaseCPU::regStats(); 125 126 numInsts 127 .name(name() + ".num_insts") 128 .desc("Number of instructions executed") 129 ; 130 131 numMemRefs 132 .name(name() + ".num_refs") 133 .desc("Number of memory references") 134 ; 135 136 notIdleFraction 137 .name(name() + ".not_idle_fraction") 138 .desc("Percentage of non-idle cycles") 139 ; 140 141 idleFraction 142 .name(name() + ".idle_fraction") 143 .desc("Percentage of idle cycles") 144 ; 145 146 icacheStallCycles 147 .name(name() + ".icache_stall_cycles") 148 .desc("ICache total stall cycles") 149 .prereq(icacheStallCycles) 150 ; 151 152 dcacheStallCycles 153 .name(name() + ".dcache_stall_cycles") 154 .desc("DCache total stall cycles") 155 .prereq(dcacheStallCycles) 156 ; 157 158 icacheRetryCycles 159 .name(name() + ".icache_retry_cycles") 160 .desc("ICache total retry cycles") 161 .prereq(icacheRetryCycles) 162 ; 163 164 dcacheRetryCycles 165 .name(name() + ".dcache_retry_cycles") 166 .desc("DCache total retry cycles") 167 .prereq(dcacheRetryCycles) 168 ; 169 170 idleFraction = constant(1.0) - notIdleFraction; 171} 172 173void 174BaseSimpleCPU::resetStats() 175{ 176// startNumInst = numInst; 177 // notIdleFraction = (_status != Idle); 178} 179 180void 181BaseSimpleCPU::serialize(ostream &os) 182{ 183 BaseCPU::serialize(os); 184// SERIALIZE_SCALAR(inst); 185 nameOut(os, csprintf("%s.xc.0", name())); 186 thread->serialize(os); 187} 188 189void 190BaseSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 191{ 192 BaseCPU::unserialize(cp, section); 193// UNSERIALIZE_SCALAR(inst); 194 thread->unserialize(cp, csprintf("%s.xc.0", section)); 195} 196 197void 198change_thread_state(int thread_number, int activate, int priority) 199{ 200} 201 202Fault 203BaseSimpleCPU::copySrcTranslate(Addr src) 204{ 205#if 0 206 static bool no_warn = true; 207 int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; 208 // Only support block sizes of 64 atm. 209 assert(blk_size == 64); 210 int offset = src & (blk_size - 1); 211 212 // Make sure block doesn't span page 213 if (no_warn && 214 (src & PageMask) != ((src + blk_size) & PageMask) && 215 (src >> 40) != 0xfffffc) { 216 warn("Copied block source spans pages %x.", src); 217 no_warn = false; 218 } 219 220 memReq->reset(src & ~(blk_size - 1), blk_size); 221 222 // translate to physical address 223 Fault fault = thread->translateDataReadReq(req); 224 225 if (fault == NoFault) { 226 thread->copySrcAddr = src; 227 thread->copySrcPhysAddr = memReq->paddr + offset; 228 } else { 229 assert(!fault->isAlignmentFault()); 230 231 thread->copySrcAddr = 0; 232 thread->copySrcPhysAddr = 0; 233 } 234 return fault; 235#else 236 return NoFault; 237#endif 238} 239 240Fault 241BaseSimpleCPU::copy(Addr dest) 242{ 243#if 0 244 static bool no_warn = true; 245 int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; 246 // Only support block sizes of 64 atm. 247 assert(blk_size == 64); 248 uint8_t data[blk_size]; 249 //assert(thread->copySrcAddr); 250 int offset = dest & (blk_size - 1); 251 252 // Make sure block doesn't span page 253 if (no_warn && 254 (dest & PageMask) != ((dest + blk_size) & PageMask) && 255 (dest >> 40) != 0xfffffc) { 256 no_warn = false; 257 warn("Copied block destination spans pages %x. ", dest); 258 } 259 260 memReq->reset(dest & ~(blk_size -1), blk_size); 261 // translate to physical address 262 Fault fault = thread->translateDataWriteReq(req); 263 264 if (fault == NoFault) { 265 Addr dest_addr = memReq->paddr + offset; 266 // Need to read straight from memory since we have more than 8 bytes. 267 memReq->paddr = thread->copySrcPhysAddr; 268 thread->mem->read(memReq, data); 269 memReq->paddr = dest_addr; 270 thread->mem->write(memReq, data); 271 if (dcacheInterface) { 272 memReq->cmd = Copy; 273 memReq->completionEvent = NULL; 274 memReq->paddr = thread->copySrcPhysAddr; 275 memReq->dest = dest_addr; 276 memReq->size = 64; 277 memReq->time = curTick; 278 memReq->flags &= ~INST_READ; 279 dcacheInterface->access(memReq); 280 } 281 } 282 else 283 assert(!fault->isAlignmentFault()); 284 285 return fault; 286#else 287 panic("copy not implemented"); 288 return NoFault; 289#endif 290} 291 292#if FULL_SYSTEM 293Addr 294BaseSimpleCPU::dbg_vtophys(Addr addr) 295{ 296 return vtophys(tc, addr); 297} 298#endif // FULL_SYSTEM 299 300#if FULL_SYSTEM 301void 302BaseSimpleCPU::post_interrupt(int int_num, int index) 303{ 304 BaseCPU::post_interrupt(int_num, index); 305 306 if (thread->status() == ThreadContext::Suspended) { 307 DPRINTF(Quiesce,"Suspended Processor awoke\n"); 308 thread->activate(); 309 } 310} 311#endif // FULL_SYSTEM 312 313void 314BaseSimpleCPU::checkForInterrupts() 315{ 316#if FULL_SYSTEM 317 if (check_interrupts(tc)) { 318 Fault interrupt = interrupts.getInterrupt(tc); 319 320 if (interrupt != NoFault) { 321 interrupts.updateIntrInfo(tc); 322 interrupt->invoke(tc); 323 } 324 } 325#endif 326} 327 328 329Fault 330BaseSimpleCPU::setupFetchRequest(Request *req) 331{ 332 Addr threadPC = thread->readPC(); 333 334 // set up memory request for instruction fetch 335#if ISA_HAS_DELAY_SLOT 336 DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p NNPC:%08p\n",threadPC, 337 thread->readNextPC(),thread->readNextNPC()); 338#else 339 DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p",threadPC, 340 thread->readNextPC()); 341#endif 342 343 const Addr PCMask = ~((Addr)sizeof(MachInst) - 1); 344 Addr fetchPC = threadPC + fetchOffset; 345 req->setVirt(0, fetchPC & PCMask, sizeof(MachInst), 0, threadPC); 346 347 Fault fault = thread->translateInstReq(req); 348 349 return fault; 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 // keep an instruction count 363 numInst++; 364 numInsts++; 365 366 thread->funcExeInst++; 367 368 // check for instruction-count-based events 369 comInstEventQueue[0]->serviceEvents(numInst); 370 371 // decode the instruction 372 inst = gtoh(inst); 373 374 //If we're not in the middle of a macro instruction 375 if (!curMacroStaticInst) { 376 377 StaticInstPtr instPtr = NULL; 378 379 //Predecode, ie bundle up an ExtMachInst 380 //This should go away once the constructor can be set up properly 381 predecoder.setTC(thread->getTC()); 382 //If more fetch data is needed, pass it in. 383 if(predecoder.needMoreBytes()) 384 predecoder.moreBytes(thread->readPC() + fetchOffset, 0, inst); 385 else 386 predecoder.process(); 387 388 //If an instruction is ready, decode it. Otherwise, we'll have to 389 //fetch beyond the MachInst at the current pc. 390 if (predecoder.extMachInstReady()) { 391#if THE_ISA == X86_ISA 392 thread->setNextPC(thread->readPC() + predecoder.getInstSize()); 393#endif // X86_ISA 394 stayAtPC = false; 395 instPtr = StaticInst::decode(predecoder.getExtMachInst()); 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-> 406 fetchMicroOp(thread->readMicroPC()); 407 } else { 408 curStaticInst = instPtr; 409 } 410 } else { 411 //Read the next micro op from the macro op 412 curStaticInst = curMacroStaticInst-> 413 fetchMicroOp(thread->readMicroPC()); 414 } 415 416 //If we decoded an instruction this "tick", record information about it. 417 if(curStaticInst) 418 { 419#if TRACING_ON 420 traceData = Trace::getInstRecord(curTick, tc, curStaticInst, 421 thread->readPC()); 422 423 DPRINTF(Decode,"Decode: Decoded %s instruction: 0x%x\n", 424 curStaticInst->getName(), curStaticInst->machInst); 425#endif // TRACING_ON 426 427#if FULL_SYSTEM 428 thread->setInst(inst); 429#endif // FULL_SYSTEM 430 } 431} 432 433void 434BaseSimpleCPU::postExecute() 435{ 436#if FULL_SYSTEM 437 if (thread->profile) { 438 bool usermode = TheISA::inUserMode(tc); 439 thread->profilePC = usermode ? 1 : thread->readPC(); 440 StaticInstPtr si(inst); 441 ProfileNode *node = thread->profile->consume(tc, si); 442 if (node) 443 thread->profileNode = node; 444 } 445#endif 446 447 if (curStaticInst->isMemRef()) { 448 numMemRefs++; 449 } 450 451 if (curStaticInst->isLoad()) { 452 ++numLoad; 453 comLoadEventQueue[0]->serviceEvents(numLoad); 454 } 455 456 traceFunctions(thread->readPC()); 457 458 if (traceData) { 459 traceData->dump(); 460 delete traceData; 461 traceData = NULL; 462 } 463} 464 465 466void 467BaseSimpleCPU::advancePC(Fault fault) 468{ 469 //Since we're moving to a new pc, zero out the offset 470 fetchOffset = 0; 471 if (fault != NoFault) { 472 curMacroStaticInst = StaticInst::nullStaticInstPtr; 473 fault->invoke(tc); 474 thread->setMicroPC(0); 475 thread->setNextMicroPC(1); 476 } else { 477 //If we're at the last micro op for this instruction 478 if (curStaticInst && curStaticInst->isLastMicroOp()) { 479 //We should be working with a macro op 480 assert(curMacroStaticInst); 481 //Close out this macro op, and clean up the 482 //microcode state 483 curMacroStaticInst = StaticInst::nullStaticInstPtr; 484 thread->setMicroPC(0); 485 thread->setNextMicroPC(1); 486 } 487 //If we're still in a macro op 488 if (curMacroStaticInst) { 489 //Advance the micro pc 490 thread->setMicroPC(thread->readNextMicroPC()); 491 //Advance the "next" micro pc. Note that there are no delay 492 //slots, and micro ops are "word" addressed. 493 thread->setNextMicroPC(thread->readNextMicroPC() + 1); 494 } else { 495 // go to the next instruction 496 thread->setPC(thread->readNextPC()); 497 thread->setNextPC(thread->readNextNPC()); 498 thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst)); 499 assert(thread->readNextPC() != thread->readNextNPC()); 500 } 501 } 502 503#if FULL_SYSTEM 504 Addr oldpc; 505 do { 506 oldpc = thread->readPC(); 507 system->pcEventQueue.service(tc); 508 } while (oldpc != thread->readPC()); 509#endif 510} 511 512