base.cc revision 2741
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 * Korey Sewell 30 */ 31 32#include "arch/utility.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/sampler/sampler.hh" 45#include "cpu/simple/base.hh" 46#include "cpu/simple_thread.hh" 47#include "cpu/smt.hh" 48#include "cpu/static_inst.hh" 49#include "cpu/thread_context.hh" 50#include "kern/kernel_stats.hh" 51#include "mem/packet_impl.hh" 52#include "sim/builder.hh" 53#include "sim/byteswap.hh" 54#include "sim/debug.hh" 55#include "sim/host.hh" 56#include "sim/sim_events.hh" 57#include "sim/sim_object.hh" 58#include "sim/stats.hh" 59 60#if FULL_SYSTEM 61#include "base/remote_gdb.hh" 62#include "sim/system.hh" 63#include "arch/tlb.hh" 64#include "arch/stacktrace.hh" 65#include "arch/vtophys.hh" 66#else // !FULL_SYSTEM 67#include "mem/mem_object.hh" 68#endif // FULL_SYSTEM 69 70using namespace std; 71using namespace TheISA; 72 73BaseSimpleCPU::BaseSimpleCPU(Params *p) 74 : BaseCPU(p), mem(p->mem), thread(NULL) 75{ 76#if FULL_SYSTEM 77 thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb); 78#else 79 thread = new SimpleThread(this, /* thread_num */ 0, p->process, 80 /* asid */ 0, mem); 81#endif // !FULL_SYSTEM 82 83 thread->setStatus(ThreadContext::Suspended); 84 85 tc = thread->getTC(); 86 87 numInst = 0; 88 startNumInst = 0; 89 numLoad = 0; 90 startNumLoad = 0; 91 lastIcacheStall = 0; 92 lastDcacheStall = 0; 93 94 threadContexts.push_back(tc); 95} 96 97BaseSimpleCPU::~BaseSimpleCPU() 98{ 99} 100 101void 102BaseSimpleCPU::deallocateContext(int thread_num) 103{ 104 // for now, these are equivalent 105 suspendContext(thread_num); 106} 107 108 109void 110BaseSimpleCPU::haltContext(int thread_num) 111{ 112 // for now, these are equivalent 113 suspendContext(thread_num); 114} 115 116 117void 118BaseSimpleCPU::regStats() 119{ 120 using namespace Stats; 121 122 BaseCPU::regStats(); 123 124 numInsts 125 .name(name() + ".num_insts") 126 .desc("Number of instructions executed") 127 ; 128 129 numMemRefs 130 .name(name() + ".num_refs") 131 .desc("Number of memory references") 132 ; 133 134 notIdleFraction 135 .name(name() + ".not_idle_fraction") 136 .desc("Percentage of non-idle cycles") 137 ; 138 139 idleFraction 140 .name(name() + ".idle_fraction") 141 .desc("Percentage of idle cycles") 142 ; 143 144 icacheStallCycles 145 .name(name() + ".icache_stall_cycles") 146 .desc("ICache total stall cycles") 147 .prereq(icacheStallCycles) 148 ; 149 150 dcacheStallCycles 151 .name(name() + ".dcache_stall_cycles") 152 .desc("DCache total stall cycles") 153 .prereq(dcacheStallCycles) 154 ; 155 156 icacheRetryCycles 157 .name(name() + ".icache_retry_cycles") 158 .desc("ICache total retry cycles") 159 .prereq(icacheRetryCycles) 160 ; 161 162 dcacheRetryCycles 163 .name(name() + ".dcache_retry_cycles") 164 .desc("DCache total retry cycles") 165 .prereq(dcacheRetryCycles) 166 ; 167 168 idleFraction = constant(1.0) - notIdleFraction; 169} 170 171void 172BaseSimpleCPU::resetStats() 173{ 174 startNumInst = numInst; 175 // notIdleFraction = (_status != Idle); 176} 177 178void 179BaseSimpleCPU::serialize(ostream &os) 180{ 181 BaseCPU::serialize(os); 182 SERIALIZE_SCALAR(inst); 183 nameOut(os, csprintf("%s.xc", name())); 184 thread->serialize(os); 185} 186 187void 188BaseSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 189{ 190 BaseCPU::unserialize(cp, section); 191 UNSERIALIZE_SCALAR(inst); 192 thread->unserialize(cp, csprintf("%s.xc", section)); 193} 194 195void 196change_thread_state(int thread_number, int activate, int priority) 197{ 198} 199 200Fault 201BaseSimpleCPU::copySrcTranslate(Addr src) 202{ 203#if 0 204 static bool no_warn = true; 205 int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; 206 // Only support block sizes of 64 atm. 207 assert(blk_size == 64); 208 int offset = src & (blk_size - 1); 209 210 // Make sure block doesn't span page 211 if (no_warn && 212 (src & PageMask) != ((src + blk_size) & PageMask) && 213 (src >> 40) != 0xfffffc) { 214 warn("Copied block source spans pages %x.", src); 215 no_warn = false; 216 } 217 218 memReq->reset(src & ~(blk_size - 1), blk_size); 219 220 // translate to physical address 221 Fault fault = thread->translateDataReadReq(req); 222 223 if (fault == NoFault) { 224 thread->copySrcAddr = src; 225 thread->copySrcPhysAddr = memReq->paddr + offset; 226 } else { 227 assert(!fault->isAlignmentFault()); 228 229 thread->copySrcAddr = 0; 230 thread->copySrcPhysAddr = 0; 231 } 232 return fault; 233#else 234 return NoFault; 235#endif 236} 237 238Fault 239BaseSimpleCPU::copy(Addr dest) 240{ 241#if 0 242 static bool no_warn = true; 243 int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; 244 // Only support block sizes of 64 atm. 245 assert(blk_size == 64); 246 uint8_t data[blk_size]; 247 //assert(thread->copySrcAddr); 248 int offset = dest & (blk_size - 1); 249 250 // Make sure block doesn't span page 251 if (no_warn && 252 (dest & PageMask) != ((dest + blk_size) & PageMask) && 253 (dest >> 40) != 0xfffffc) { 254 no_warn = false; 255 warn("Copied block destination spans pages %x. ", dest); 256 } 257 258 memReq->reset(dest & ~(blk_size -1), blk_size); 259 // translate to physical address 260 Fault fault = thread->translateDataWriteReq(req); 261 262 if (fault == NoFault) { 263 Addr dest_addr = memReq->paddr + offset; 264 // Need to read straight from memory since we have more than 8 bytes. 265 memReq->paddr = thread->copySrcPhysAddr; 266 thread->mem->read(memReq, data); 267 memReq->paddr = dest_addr; 268 thread->mem->write(memReq, data); 269 if (dcacheInterface) { 270 memReq->cmd = Copy; 271 memReq->completionEvent = NULL; 272 memReq->paddr = thread->copySrcPhysAddr; 273 memReq->dest = dest_addr; 274 memReq->size = 64; 275 memReq->time = curTick; 276 memReq->flags &= ~INST_READ; 277 dcacheInterface->access(memReq); 278 } 279 } 280 else 281 assert(!fault->isAlignmentFault()); 282 283 return fault; 284#else 285 panic("copy not implemented"); 286 return NoFault; 287#endif 288} 289 290#if FULL_SYSTEM 291Addr 292BaseSimpleCPU::dbg_vtophys(Addr addr) 293{ 294 return vtophys(tc, addr); 295} 296#endif // FULL_SYSTEM 297 298#if FULL_SYSTEM 299void 300BaseSimpleCPU::post_interrupt(int int_num, int index) 301{ 302 BaseCPU::post_interrupt(int_num, index); 303 304 if (thread->status() == ThreadContext::Suspended) { 305 DPRINTF(IPI,"Suspended Processor awoke\n"); 306 thread->activate(); 307 } 308} 309#endif // FULL_SYSTEM 310 311void 312BaseSimpleCPU::checkForInterrupts() 313{ 314#if FULL_SYSTEM 315 if (checkInterrupts && check_interrupts() && !thread->inPalMode()) { 316 int ipl = 0; 317 int summary = 0; 318 checkInterrupts = false; 319 320 if (thread->readMiscReg(IPR_SIRR)) { 321 for (int i = INTLEVEL_SOFTWARE_MIN; 322 i < INTLEVEL_SOFTWARE_MAX; i++) { 323 if (thread->readMiscReg(IPR_SIRR) & (ULL(1) << i)) { 324 // See table 4-19 of 21164 hardware reference 325 ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; 326 summary |= (ULL(1) << i); 327 } 328 } 329 } 330 331 uint64_t interrupts = thread->cpu->intr_status(); 332 for (int i = INTLEVEL_EXTERNAL_MIN; 333 i < INTLEVEL_EXTERNAL_MAX; i++) { 334 if (interrupts & (ULL(1) << i)) { 335 // See table 4-19 of 21164 hardware reference 336 ipl = i; 337 summary |= (ULL(1) << i); 338 } 339 } 340 341 if (thread->readMiscReg(IPR_ASTRR)) 342 panic("asynchronous traps not implemented\n"); 343 344 if (ipl && ipl > thread->readMiscReg(IPR_IPLR)) { 345 thread->setMiscReg(IPR_ISR, summary); 346 thread->setMiscReg(IPR_INTID, ipl); 347 348 Fault(new InterruptFault)->invoke(tc); 349 350 DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", 351 thread->readMiscReg(IPR_IPLR), ipl, summary); 352 } 353 } 354#endif 355} 356 357 358Fault 359BaseSimpleCPU::setupFetchRequest(Request *req) 360{ 361 // set up memory request for instruction fetch 362#if THE_ISA == ALPHA_ISA 363 DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p",thread->readPC(), 364 thread->readNextPC()); 365#else 366 DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p NNPC:%08p\n",thread->readPC(), 367 thread->readNextPC(),thread->readNextNPC()); 368#endif 369 370 req->setVirt(0, thread->readPC() & ~3, sizeof(MachInst), 371 (FULL_SYSTEM && (thread->readPC() & 1)) ? PHYSICAL : 0, 372 thread->readPC()); 373 374 Fault fault = thread->translateInstReq(req); 375 376 return fault; 377} 378 379 380void 381BaseSimpleCPU::preExecute() 382{ 383 // maintain $r0 semantics 384 thread->setIntReg(ZeroReg, 0); 385#if THE_ISA == ALPHA_ISA 386 thread->setFloatReg(ZeroReg, 0.0); 387#endif // ALPHA_ISA 388 389 // keep an instruction count 390 numInst++; 391 numInsts++; 392 393 thread->funcExeInst++; 394 395 // check for instruction-count-based events 396 comInstEventQueue[0]->serviceEvents(numInst); 397 398 // decode the instruction 399 inst = gtoh(inst); 400 curStaticInst = StaticInst::decode(makeExtMI(inst, thread->readPC())); 401 402 traceData = Trace::getInstRecord(curTick, tc, this, curStaticInst, 403 thread->readPC()); 404 405 DPRINTF(Decode,"Decode: Decoded %s instruction (opcode: 0x%x): 0x%x\n", 406 curStaticInst->getName(), curStaticInst->getOpcode(), 407 curStaticInst->machInst); 408 409#if FULL_SYSTEM 410 thread->setInst(inst); 411#endif // FULL_SYSTEM 412} 413 414void 415BaseSimpleCPU::postExecute() 416{ 417#if FULL_SYSTEM 418 if (system->kernelBinning->fnbin) { 419 assert(thread->getKernelStats()); 420 system->kernelBinning->execute(tc, inst); 421 } 422 423 if (thread->profile) { 424 bool usermode = 425 (thread->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0; 426 thread->profilePC = usermode ? 1 : thread->readPC(); 427 ProfileNode *node = thread->profile->consume(tc, inst); 428 if (node) 429 thread->profileNode = node; 430 } 431#endif 432 433 if (curStaticInst->isMemRef()) { 434 numMemRefs++; 435 } 436 437 if (curStaticInst->isLoad()) { 438 ++numLoad; 439 comLoadEventQueue[0]->serviceEvents(numLoad); 440 } 441 442 traceFunctions(thread->readPC()); 443 444 if (traceData) { 445 traceData->finalize(); 446 } 447} 448 449 450void 451BaseSimpleCPU::advancePC(Fault fault) 452{ 453 if (fault != NoFault) { 454#if FULL_SYSTEM 455 fault->invoke(tc); 456#else // !FULL_SYSTEM 457 fatal("fault (%s) detected @ PC %08p", fault->name(), thread->readPC()); 458#endif // FULL_SYSTEM 459 } 460 else { 461 // go to the next instruction 462 thread->setPC(thread->readNextPC()); 463#if THE_ISA == ALPHA_ISA 464 thread->setNextPC(thread->readNextPC() + sizeof(MachInst)); 465#else 466 thread->setNextPC(thread->readNextNPC()); 467 thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst)); 468#endif 469 470 } 471 472#if FULL_SYSTEM 473 Addr oldpc; 474 do { 475 oldpc = thread->readPC(); 476 system->pcEventQueue.service(tc); 477 } while (oldpc != thread->readPC()); 478#endif 479} 480 481