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