base.cc revision 3435:0830790f937c
12330SN/A/* 22330SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 32330SN/A * All rights reserved. 42330SN/A * 52330SN/A * Redistribution and use in source and binary forms, with or without 62330SN/A * modification, are permitted provided that the following conditions are 72330SN/A * met: redistributions of source code must retain the above copyright 82330SN/A * notice, this list of conditions and the following disclaimer; 92330SN/A * redistributions in binary form must reproduce the above copyright 102330SN/A * notice, this list of conditions and the following disclaimer in the 112330SN/A * documentation and/or other materials provided with the distribution; 122330SN/A * neither the name of the copyright holders nor the names of its 132330SN/A * contributors may be used to endorse or promote products derived from 142330SN/A * this software without specific prior written permission. 152330SN/A * 162330SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172330SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182330SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192330SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202330SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212330SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222330SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232330SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242330SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252330SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262330SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272689Sktlim@umich.edu * 282689Sktlim@umich.edu * Authors: Steve Reinhardt 292330SN/A */ 302292SN/A 312292SN/A#include "arch/utility.hh" 322292SN/A#include "arch/faults.hh" 332292SN/A#include "base/cprintf.hh" 342980Sgblack@eecs.umich.edu#include "base/inifile.hh" 352362SN/A#include "base/loader/symtab.hh" 362680Sktlim@umich.edu#include "base/misc.hh" 372292SN/A#include "base/pollevent.hh" 382678Sktlim@umich.edu#include "base/range.hh" 392683Sktlim@umich.edu#include "base/stats/events.hh" 402683Sktlim@umich.edu#include "base/trace.hh" 412678Sktlim@umich.edu#include "cpu/base.hh" 422678Sktlim@umich.edu#include "cpu/exetrace.hh" 432292SN/A#include "cpu/profile.hh" 442292SN/A#include "cpu/simple/base.hh" 452292SN/A#include "cpu/simple_thread.hh" 462292SN/A#include "cpu/smt.hh" 472330SN/A#include "cpu/static_inst.hh" 482330SN/A#include "cpu/thread_context.hh" 492330SN/A#include "kern/kernel_stats.hh" 502292SN/A#include "mem/packet.hh" 512292SN/A#include "sim/builder.hh" 523402Sktlim@umich.edu#include "sim/byteswap.hh" 532862Sktlim@umich.edu#include "sim/debug.hh" 543486Sktlim@umich.edu#include "sim/host.hh" 553402Sktlim@umich.edu#include "sim/sim_events.hh" 562862Sktlim@umich.edu#include "sim/sim_object.hh" 572330SN/A#include "sim/stats.hh" 582330SN/A#include "sim/system.hh" 592330SN/A 602330SN/A#if FULL_SYSTEM 612330SN/A#include "base/remote_gdb.hh" 622330SN/A#include "arch/tlb.hh" 632292SN/A#include "arch/stacktrace.hh" 642683Sktlim@umich.edu#include "arch/vtophys.hh" 652683Sktlim@umich.edu#else // !FULL_SYSTEM 662292SN/A#include "mem/mem_object.hh" 673402Sktlim@umich.edu#endif // FULL_SYSTEM 682292SN/A 693402Sktlim@umich.eduusing namespace std; 703402Sktlim@umich.eduusing namespace TheISA; 712292SN/A 722683Sktlim@umich.eduBaseSimpleCPU::BaseSimpleCPU(Params *p) 733486Sktlim@umich.edu : BaseCPU(p), mem(p->mem), thread(NULL) 743486Sktlim@umich.edu{ 752862Sktlim@umich.edu#if FULL_SYSTEM 762862Sktlim@umich.edu thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb); 772862Sktlim@umich.edu#else 782862Sktlim@umich.edu thread = new SimpleThread(this, /* thread_num */ 0, p->process, 792683Sktlim@umich.edu /* asid */ 0, mem); 802683Sktlim@umich.edu#endif // !FULL_SYSTEM 812683Sktlim@umich.edu 822683Sktlim@umich.edu thread->setStatus(ThreadContext::Suspended); 832683Sktlim@umich.edu 842683Sktlim@umich.edu tc = thread->getTC(); 852683Sktlim@umich.edu 862683Sktlim@umich.edu numInst = 0; 872683Sktlim@umich.edu startNumInst = 0; 882683Sktlim@umich.edu numLoad = 0; 892683Sktlim@umich.edu startNumLoad = 0; 902683Sktlim@umich.edu lastIcacheStall = 0; 912683Sktlim@umich.edu lastDcacheStall = 0; 922683Sktlim@umich.edu 932683Sktlim@umich.edu threadContexts.push_back(tc); 942683Sktlim@umich.edu} 952683Sktlim@umich.edu 962683Sktlim@umich.eduBaseSimpleCPU::~BaseSimpleCPU() 972683Sktlim@umich.edu{ 982683Sktlim@umich.edu} 992683Sktlim@umich.edu 1002683Sktlim@umich.eduvoid 1012683Sktlim@umich.eduBaseSimpleCPU::deallocateContext(int thread_num) 1022690Sktlim@umich.edu{ 1032690Sktlim@umich.edu // for now, these are equivalent 1042683Sktlim@umich.edu suspendContext(thread_num); 1052683Sktlim@umich.edu} 1062690Sktlim@umich.edu 1072690Sktlim@umich.edu 1082683Sktlim@umich.eduvoid 1092683Sktlim@umich.eduBaseSimpleCPU::haltContext(int thread_num) 1102683Sktlim@umich.edu{ 1112683Sktlim@umich.edu // for now, these are equivalent 1123402Sktlim@umich.edu suspendContext(thread_num); 1132683Sktlim@umich.edu} 1142683Sktlim@umich.edu 1152683Sktlim@umich.edu 1162683Sktlim@umich.eduvoid 1172683Sktlim@umich.eduBaseSimpleCPU::regStats() 1182678Sktlim@umich.edu{ 1192292SN/A using namespace Stats; 1202683Sktlim@umich.edu 1212683Sktlim@umich.edu BaseCPU::regStats(); 1222292SN/A 1232683Sktlim@umich.edu numInsts 1242683Sktlim@umich.edu .name(name() + ".num_insts") 1252683Sktlim@umich.edu .desc("Number of instructions executed") 1262683Sktlim@umich.edu ; 1272683Sktlim@umich.edu 1282683Sktlim@umich.edu numMemRefs 1292683Sktlim@umich.edu .name(name() + ".num_refs") 1302683Sktlim@umich.edu .desc("Number of memory references") 1312683Sktlim@umich.edu ; 1322683Sktlim@umich.edu 1332683Sktlim@umich.edu notIdleFraction 1342683Sktlim@umich.edu .name(name() + ".not_idle_fraction") 1352683Sktlim@umich.edu .desc("Percentage of non-idle cycles") 1362683Sktlim@umich.edu ; 1372683Sktlim@umich.edu 1382683Sktlim@umich.edu idleFraction 1392683Sktlim@umich.edu .name(name() + ".idle_fraction") 1402683Sktlim@umich.edu .desc("Percentage of idle cycles") 1412683Sktlim@umich.edu ; 1423486Sktlim@umich.edu 1433486Sktlim@umich.edu icacheStallCycles 1443486Sktlim@umich.edu .name(name() + ".icache_stall_cycles") 1453486Sktlim@umich.edu .desc("ICache total stall cycles") 1463486Sktlim@umich.edu .prereq(icacheStallCycles) 1473486Sktlim@umich.edu ; 1482683Sktlim@umich.edu 1492683Sktlim@umich.edu dcacheStallCycles 1502683Sktlim@umich.edu .name(name() + ".dcache_stall_cycles") 1512683Sktlim@umich.edu .desc("DCache total stall cycles") 1522683Sktlim@umich.edu .prereq(dcacheStallCycles) 1532683Sktlim@umich.edu ; 1542683Sktlim@umich.edu 1552683Sktlim@umich.edu icacheRetryCycles 1562683Sktlim@umich.edu .name(name() + ".icache_retry_cycles") 1572683Sktlim@umich.edu .desc("ICache total retry cycles") 1582683Sktlim@umich.edu .prereq(icacheRetryCycles) 1592683Sktlim@umich.edu ; 1602683Sktlim@umich.edu 1612683Sktlim@umich.edu dcacheRetryCycles 1622683Sktlim@umich.edu .name(name() + ".dcache_retry_cycles") 1632683Sktlim@umich.edu .desc("DCache total retry cycles") 1642683Sktlim@umich.edu .prereq(dcacheRetryCycles) 1652683Sktlim@umich.edu ; 1663402Sktlim@umich.edu 1673402Sktlim@umich.edu idleFraction = constant(1.0) - notIdleFraction; 1683402Sktlim@umich.edu} 1692683Sktlim@umich.edu 1702683Sktlim@umich.eduvoid 1712292SN/ABaseSimpleCPU::resetStats() 1722292SN/A{ 1732292SN/A// startNumInst = numInst; 1742292SN/A // notIdleFraction = (_status != Idle); 1752292SN/A} 1762690Sktlim@umich.edu 1772683Sktlim@umich.eduvoid 1782683Sktlim@umich.eduBaseSimpleCPU::serialize(ostream &os) 1792292SN/A{ 1802683Sktlim@umich.edu BaseCPU::serialize(os); 1812683Sktlim@umich.edu// SERIALIZE_SCALAR(inst); 1822292SN/A nameOut(os, csprintf("%s.xc.0", name())); 1832292SN/A thread->serialize(os); 1842683Sktlim@umich.edu} 1852292SN/A 1862292SN/Avoid 1872292SN/ABaseSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 1882292SN/A{ 1892292SN/A BaseCPU::unserialize(cp, section); 1902330SN/A// UNSERIALIZE_SCALAR(inst); 1912683Sktlim@umich.edu thread->unserialize(cp, csprintf("%s.xc.0", section)); 1922683Sktlim@umich.edu} 1932683Sktlim@umich.edu 1942683Sktlim@umich.eduvoid 1952683Sktlim@umich.educhange_thread_state(int thread_number, int activate, int priority) 1962683Sktlim@umich.edu{ 1972683Sktlim@umich.edu} 1982683Sktlim@umich.edu 1992292SN/AFault 2002678Sktlim@umich.eduBaseSimpleCPU::copySrcTranslate(Addr src) 2012678Sktlim@umich.edu{ 2022292SN/A#if 0 2032292SN/A static bool no_warn = true; 2042292SN/A int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; 2052292SN/A // Only support block sizes of 64 atm. 2062292SN/A assert(blk_size == 64); 2072292SN/A int offset = src & (blk_size - 1); 2082330SN/A 2092330SN/A // Make sure block doesn't span page 2102330SN/A if (no_warn && 2112683Sktlim@umich.edu (src & PageMask) != ((src + blk_size) & PageMask) && 2122683Sktlim@umich.edu (src >> 40) != 0xfffffc) { 2132683Sktlim@umich.edu warn("Copied block source spans pages %x.", src); 2142683Sktlim@umich.edu no_warn = false; 2152292SN/A } 2163276Sgblack@eecs.umich.edu 2173276Sgblack@eecs.umich.edu memReq->reset(src & ~(blk_size - 1), blk_size); 2183276Sgblack@eecs.umich.edu 2193276Sgblack@eecs.umich.edu // translate to physical address 2203276Sgblack@eecs.umich.edu Fault fault = thread->translateDataReadReq(req); 2213276Sgblack@eecs.umich.edu 2223276Sgblack@eecs.umich.edu if (fault == NoFault) { 2233276Sgblack@eecs.umich.edu thread->copySrcAddr = src; 2243276Sgblack@eecs.umich.edu thread->copySrcPhysAddr = memReq->paddr + offset; 2253276Sgblack@eecs.umich.edu } else { 2262690Sktlim@umich.edu assert(!fault->isAlignmentFault()); 2272292SN/A 2282292SN/A thread->copySrcAddr = 0; 2292292SN/A thread->copySrcPhysAddr = 0; 2302292SN/A } 2312292SN/A return fault; 2322292SN/A#else 2332292SN/A return NoFault; 2342292SN/A#endif 2352292SN/A} 2362292SN/A 2372292SN/AFault 2382292SN/ABaseSimpleCPU::copy(Addr dest) 2392292SN/A{ 2402292SN/A#if 0 2412292SN/A static bool no_warn = true; 2422292SN/A int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; 2432292SN/A // Only support block sizes of 64 atm. 2442292SN/A assert(blk_size == 64); 2452292SN/A uint8_t data[blk_size]; 2462292SN/A //assert(thread->copySrcAddr); 2472292SN/A int offset = dest & (blk_size - 1); 2482292SN/A 2492292SN/A // Make sure block doesn't span page 2502292SN/A if (no_warn && 2512292SN/A (dest & PageMask) != ((dest + blk_size) & PageMask) && 252 (dest >> 40) != 0xfffffc) { 253 no_warn = false; 254 warn("Copied block destination spans pages %x. ", dest); 255 } 256 257 memReq->reset(dest & ~(blk_size -1), blk_size); 258 // translate to physical address 259 Fault fault = thread->translateDataWriteReq(req); 260 261 if (fault == NoFault) { 262 Addr dest_addr = memReq->paddr + offset; 263 // Need to read straight from memory since we have more than 8 bytes. 264 memReq->paddr = thread->copySrcPhysAddr; 265 thread->mem->read(memReq, data); 266 memReq->paddr = dest_addr; 267 thread->mem->write(memReq, data); 268 if (dcacheInterface) { 269 memReq->cmd = Copy; 270 memReq->completionEvent = NULL; 271 memReq->paddr = thread->copySrcPhysAddr; 272 memReq->dest = dest_addr; 273 memReq->size = 64; 274 memReq->time = curTick; 275 memReq->flags &= ~INST_READ; 276 dcacheInterface->access(memReq); 277 } 278 } 279 else 280 assert(!fault->isAlignmentFault()); 281 282 return fault; 283#else 284 panic("copy not implemented"); 285 return NoFault; 286#endif 287} 288 289#if FULL_SYSTEM 290Addr 291BaseSimpleCPU::dbg_vtophys(Addr addr) 292{ 293 return vtophys(tc, addr); 294} 295#endif // FULL_SYSTEM 296 297#if FULL_SYSTEM 298void 299BaseSimpleCPU::post_interrupt(int int_num, int index) 300{ 301 BaseCPU::post_interrupt(int_num, index); 302 303 if (thread->status() == ThreadContext::Suspended) { 304 DPRINTF(IPI,"Suspended Processor awoke\n"); 305 thread->activate(); 306 } 307} 308#endif // FULL_SYSTEM 309 310void 311BaseSimpleCPU::checkForInterrupts() 312{ 313#if FULL_SYSTEM 314 if (checkInterrupts && check_interrupts() && !thread->inPalMode()) { 315 int ipl = 0; 316 int summary = 0; 317 checkInterrupts = false; 318 319 if (thread->readMiscReg(IPR_SIRR)) { 320 for (int i = INTLEVEL_SOFTWARE_MIN; 321 i < INTLEVEL_SOFTWARE_MAX; i++) { 322 if (thread->readMiscReg(IPR_SIRR) & (ULL(1) << i)) { 323 // See table 4-19 of 21164 hardware reference 324 ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; 325 summary |= (ULL(1) << i); 326 } 327 } 328 } 329 330 uint64_t interrupts = thread->cpu->intr_status(); 331 for (int i = INTLEVEL_EXTERNAL_MIN; 332 i < INTLEVEL_EXTERNAL_MAX; i++) { 333 if (interrupts & (ULL(1) << i)) { 334 // See table 4-19 of 21164 hardware reference 335 ipl = i; 336 summary |= (ULL(1) << i); 337 } 338 } 339 340 if (thread->readMiscReg(IPR_ASTRR)) 341 panic("asynchronous traps not implemented\n"); 342 343 if (ipl && ipl > thread->readMiscReg(IPR_IPLR)) { 344 thread->setMiscReg(IPR_ISR, summary); 345 thread->setMiscReg(IPR_INTID, ipl); 346 347 Fault(new InterruptFault)->invoke(tc); 348 349 DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", 350 thread->readMiscReg(IPR_IPLR), ipl, summary); 351 } 352 } 353#endif 354} 355 356 357Fault 358BaseSimpleCPU::setupFetchRequest(Request *req) 359{ 360 // set up memory request for instruction fetch 361#if ISA_HAS_DELAY_SLOT 362 DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p NNPC:%08p\n",thread->readPC(), 363 thread->readNextPC(),thread->readNextNPC()); 364#else 365 DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p",thread->readPC(), 366 thread->readNextPC()); 367#endif 368 369 req->setVirt(0, thread->readPC() & ~3, sizeof(MachInst), 370 (FULL_SYSTEM && (thread->readPC() & 1)) ? PHYSICAL : 0, 371 thread->readPC()); 372 373 Fault fault = thread->translateInstReq(req); 374 375 return fault; 376} 377 378 379void 380BaseSimpleCPU::preExecute() 381{ 382 // maintain $r0 semantics 383 thread->setIntReg(ZeroReg, 0); 384#if THE_ISA == ALPHA_ISA 385 thread->setFloatReg(ZeroReg, 0.0); 386#endif // ALPHA_ISA 387 388 // keep an instruction count 389 numInst++; 390 numInsts++; 391 392 thread->funcExeInst++; 393 394 // check for instruction-count-based events 395 comInstEventQueue[0]->serviceEvents(numInst); 396 397 // decode the instruction 398 inst = gtoh(inst); 399 //If we're not in the middle of a macro instruction 400 if (!curMacroStaticInst) { 401 StaticInstPtr instPtr = StaticInst::decode(makeExtMI(inst, thread->getTC())); 402 if (instPtr->isMacroOp()) { 403 curMacroStaticInst = instPtr; 404 curStaticInst = curMacroStaticInst->fetchMicroOp(0); 405 } else { 406 curStaticInst = instPtr; 407 } 408 } else { 409 //Read the next micro op from the macro op 410 curStaticInst = curMacroStaticInst->fetchMicroOp(thread->readMicroPC()); 411 } 412 413 414 traceData = Trace::getInstRecord(curTick, tc, curStaticInst, 415 thread->readPC()); 416 417 DPRINTF(Decode,"Decode: Decoded %s instruction (opcode: 0x%x): 0x%x\n", 418 curStaticInst->getName(), curStaticInst->getOpcode(), 419 curStaticInst->machInst); 420 421#if FULL_SYSTEM 422 thread->setInst(inst); 423#endif // FULL_SYSTEM 424} 425 426void 427BaseSimpleCPU::postExecute() 428{ 429#if FULL_SYSTEM 430 if (thread->profile) { 431 bool usermode = 432 (thread->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0; 433 thread->profilePC = usermode ? 1 : thread->readPC(); 434 ProfileNode *node = thread->profile->consume(tc, inst); 435 if (node) 436 thread->profileNode = node; 437 } 438#endif 439 440 if (curStaticInst->isMemRef()) { 441 numMemRefs++; 442 } 443 444 if (curStaticInst->isLoad()) { 445 ++numLoad; 446 comLoadEventQueue[0]->serviceEvents(numLoad); 447 } 448 449 traceFunctions(thread->readPC()); 450 451 if (traceData) { 452 traceData->finalize(); 453 } 454} 455 456 457void 458BaseSimpleCPU::advancePC(Fault fault) 459{ 460 if (fault != NoFault) { 461 fault->invoke(tc); 462 } else { 463 //If we're at the last micro op for this instruction 464 if (curStaticInst->isLastMicroOp()) { 465 //We should be working with a macro op 466 assert(curMacroStaticInst); 467 //Close out this macro op, and clean up the 468 //microcode state 469 curMacroStaticInst = StaticInst::nullStaticInstPtr; 470 thread->setMicroPC(0); 471 thread->setNextMicroPC(1); 472 } 473 //If we're still in a macro op 474 if (curMacroStaticInst) { 475 //Advance the micro pc 476 thread->setMicroPC(thread->readNextMicroPC()); 477 //Advance the "next" micro pc. Note that there are no delay 478 //slots, and micro ops are "word" addressed. 479 thread->setNextMicroPC(thread->readNextMicroPC() + 1); 480 } else { 481 // go to the next instruction 482 thread->setPC(thread->readNextPC()); 483#if ISA_HAS_DELAY_SLOT 484 thread->setNextPC(thread->readNextNPC()); 485 thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst)); 486 assert(thread->readNextPC() != thread->readNextNPC()); 487#else 488 thread->setNextPC(thread->readNextPC() + sizeof(MachInst)); 489#endif 490 } 491 } 492 493#if FULL_SYSTEM 494 Addr oldpc; 495 do { 496 oldpc = thread->readPC(); 497 system->pcEventQueue.service(tc); 498 } while (oldpc != thread->readPC()); 499#endif 500} 501 502