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