base.cc revision 189
16691Stjones1@inf.ed.ac.uk/* 26691Stjones1@inf.ed.ac.uk * Copyright (c) 2003 The Regents of The University of Michigan 36691Stjones1@inf.ed.ac.uk * All rights reserved. 46691Stjones1@inf.ed.ac.uk * 56691Stjones1@inf.ed.ac.uk * Redistribution and use in source and binary forms, with or without 66691Stjones1@inf.ed.ac.uk * modification, are permitted provided that the following conditions are 76691Stjones1@inf.ed.ac.uk * met: redistributions of source code must retain the above copyright 86691Stjones1@inf.ed.ac.uk * notice, this list of conditions and the following disclaimer; 96691Stjones1@inf.ed.ac.uk * redistributions in binary form must reproduce the above copyright 106691Stjones1@inf.ed.ac.uk * notice, this list of conditions and the following disclaimer in the 116691Stjones1@inf.ed.ac.uk * documentation and/or other materials provided with the distribution; 126691Stjones1@inf.ed.ac.uk * neither the name of the copyright holders nor the names of its 136691Stjones1@inf.ed.ac.uk * contributors may be used to endorse or promote products derived from 146691Stjones1@inf.ed.ac.uk * this software without specific prior written permission. 156691Stjones1@inf.ed.ac.uk * 166691Stjones1@inf.ed.ac.uk * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 176691Stjones1@inf.ed.ac.uk * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 186691Stjones1@inf.ed.ac.uk * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 196691Stjones1@inf.ed.ac.uk * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 206691Stjones1@inf.ed.ac.uk * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 216691Stjones1@inf.ed.ac.uk * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 226691Stjones1@inf.ed.ac.uk * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 236691Stjones1@inf.ed.ac.uk * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 246691Stjones1@inf.ed.ac.uk * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 256691Stjones1@inf.ed.ac.uk * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 266691Stjones1@inf.ed.ac.uk * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 276691Stjones1@inf.ed.ac.uk */ 286691Stjones1@inf.ed.ac.uk 296691Stjones1@inf.ed.ac.uk#include <cmath> 306691Stjones1@inf.ed.ac.uk#include <cstdio> 316691Stjones1@inf.ed.ac.uk#include <cstdlib> 326691Stjones1@inf.ed.ac.uk#include <iostream> 336691Stjones1@inf.ed.ac.uk#include <iomanip> 3413610Sgiacomo.gabrielli@arm.com#include <list> 3512109SRekai.GonzalezAlberquilla@arm.com#include <sstream> 368961Sgblack@eecs.umich.edu#include <string> 376691Stjones1@inf.ed.ac.uk 3813556Sgabeblack@google.com#include "base/cprintf.hh" 396691Stjones1@inf.ed.ac.uk#include "base/inifile.hh" 406691Stjones1@inf.ed.ac.uk#include "base/loader/symtab.hh" 416691Stjones1@inf.ed.ac.uk#include "base/misc.hh" 426691Stjones1@inf.ed.ac.uk#include "base/pollevent.hh" 436691Stjones1@inf.ed.ac.uk#include "base/range.hh" 449065Sandreas.hansson@arm.com#include "base/trace.hh" 459065Sandreas.hansson@arm.com#include "cpu/base_cpu.hh" 469065Sandreas.hansson@arm.com#include "cpu/exec_context.hh" 479065Sandreas.hansson@arm.com#include "cpu/exetrace.hh" 486691Stjones1@inf.ed.ac.uk#include "cpu/full_cpu/smt.hh" 4913610Sgiacomo.gabrielli@arm.com#include "cpu/simple_cpu/simple_cpu.hh" 5013610Sgiacomo.gabrielli@arm.com#include "cpu/static_inst.hh" 5113610Sgiacomo.gabrielli@arm.com#include "mem/base_mem.hh" 5213610Sgiacomo.gabrielli@arm.com#include "mem/mem_interface.hh" 5313610Sgiacomo.gabrielli@arm.com#include "sim/annotation.hh" 5413610Sgiacomo.gabrielli@arm.com#include "sim/builder.hh" 5513610Sgiacomo.gabrielli@arm.com#include "sim/debug.hh" 5613610Sgiacomo.gabrielli@arm.com#include "sim/host.hh" 5713610Sgiacomo.gabrielli@arm.com#include "sim/sim_events.hh" 5813610Sgiacomo.gabrielli@arm.com#include "sim/sim_object.hh" 5913610Sgiacomo.gabrielli@arm.com#include "sim/sim_stats.hh" 6013610Sgiacomo.gabrielli@arm.com 6113610Sgiacomo.gabrielli@arm.com#ifdef FULL_SYSTEM 6213610Sgiacomo.gabrielli@arm.com#include "base/remote_gdb.hh" 6312109SRekai.GonzalezAlberquilla@arm.com#include "dev/alpha_access.h" 646691Stjones1@inf.ed.ac.uk#include "dev/pciareg.h" 656691Stjones1@inf.ed.ac.uk#include "mem/functional_mem/memory_control.hh" 666691Stjones1@inf.ed.ac.uk#include "mem/functional_mem/physical_memory.hh" 676691Stjones1@inf.ed.ac.uk#include "sim/system.hh" 686691Stjones1@inf.ed.ac.uk#include "targetarch/alpha_memory.hh" 696691Stjones1@inf.ed.ac.uk#include "targetarch/vtophys.hh" 706691Stjones1@inf.ed.ac.uk#else // !FULL_SYSTEM 716691Stjones1@inf.ed.ac.uk#include "eio/eio.hh" 726691Stjones1@inf.ed.ac.uk#include "mem/functional_mem/functional_memory.hh" 736691Stjones1@inf.ed.ac.uk#include "sim/prog.hh" 746691Stjones1@inf.ed.ac.uk#endif // FULL_SYSTEM 756691Stjones1@inf.ed.ac.uk 7613610Sgiacomo.gabrielli@arm.comusing namespace std; 7713610Sgiacomo.gabrielli@arm.com 7813610Sgiacomo.gabrielli@arm.comSimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu) 7913610Sgiacomo.gabrielli@arm.com : Event(&mainEventQueue), 809920Syasuko.eckert@amd.com cpu(_cpu) 816691Stjones1@inf.ed.ac.uk{ 826691Stjones1@inf.ed.ac.uk} 836691Stjones1@inf.ed.ac.uk 846691Stjones1@inf.ed.ac.ukvoid SimpleCPU::CacheCompletionEvent::process() 856691Stjones1@inf.ed.ac.uk{ 866691Stjones1@inf.ed.ac.uk cpu->processCacheCompletion(); 876691Stjones1@inf.ed.ac.uk} 886691Stjones1@inf.ed.ac.uk 896691Stjones1@inf.ed.ac.ukconst char * 906691Stjones1@inf.ed.ac.ukSimpleCPU::CacheCompletionEvent::description() 916691Stjones1@inf.ed.ac.uk{ 926691Stjones1@inf.ed.ac.uk return "cache completion event"; 936691Stjones1@inf.ed.ac.uk} 946691Stjones1@inf.ed.ac.uk 956691Stjones1@inf.ed.ac.uk#ifdef FULL_SYSTEM 966691Stjones1@inf.ed.ac.ukSimpleCPU::SimpleCPU(const string &_name, 976691Stjones1@inf.ed.ac.uk System *_system, 986691Stjones1@inf.ed.ac.uk Counter max_insts_any_thread, 996691Stjones1@inf.ed.ac.uk Counter max_insts_all_threads, 1006691Stjones1@inf.ed.ac.uk Counter max_loads_any_thread, 1016691Stjones1@inf.ed.ac.uk Counter max_loads_all_threads, 1026691Stjones1@inf.ed.ac.uk AlphaItb *itb, AlphaDtb *dtb, 1036691Stjones1@inf.ed.ac.uk FunctionalMemory *mem, 1046691Stjones1@inf.ed.ac.uk MemInterface *icache_interface, 1056691Stjones1@inf.ed.ac.uk MemInterface *dcache_interface, 1066691Stjones1@inf.ed.ac.uk Tick freq) 1076691Stjones1@inf.ed.ac.uk : BaseCPU(_name, /* number_of_threads */ 1, 1086691Stjones1@inf.ed.ac.uk max_insts_any_thread, max_insts_all_threads, 1096691Stjones1@inf.ed.ac.uk max_loads_any_thread, max_loads_all_threads, 1106691Stjones1@inf.ed.ac.uk _system, freq), 1117811Ssteve.reinhardt@amd.com#else 1126691Stjones1@inf.ed.ac.ukSimpleCPU::SimpleCPU(const string &_name, Process *_process, 1136691Stjones1@inf.ed.ac.uk Counter max_insts_any_thread, 114 Counter max_insts_all_threads, 115 Counter max_loads_any_thread, 116 Counter max_loads_all_threads, 117 MemInterface *icache_interface, 118 MemInterface *dcache_interface) 119 : BaseCPU(_name, /* number_of_threads */ 1, 120 max_insts_any_thread, max_insts_all_threads, 121 max_loads_any_thread, max_loads_all_threads), 122#endif 123 tickEvent(this), xc(NULL), cacheCompletionEvent(this) 124{ 125 _status = Idle; 126#ifdef FULL_SYSTEM 127 xc = new ExecContext(this, 0, system, itb, dtb, mem); 128 129 TheISA::initCPU(&xc->regs); 130 131 IntReg *ipr = xc->regs.ipr; 132 ipr[TheISA::IPR_MCSR] = 0x6; 133 134 AlphaISA::swap_palshadow(&xc->regs, true); 135 136 fault = Reset_Fault; 137 xc->regs.pc = ipr[TheISA::IPR_PAL_BASE] + AlphaISA::fault_addr[fault]; 138 xc->regs.npc = xc->regs.pc + sizeof(MachInst); 139#else 140 xc = new ExecContext(this, /* thread_num */ 0, _process, /* asid */ 0); 141 fault = No_Fault; 142#endif // !FULL_SYSTEM 143 144 icacheInterface = icache_interface; 145 dcacheInterface = dcache_interface; 146 147 memReq = new MemReq(); 148 memReq->xc = xc; 149 memReq->asid = 0; 150 memReq->data = new uint8_t[64]; 151 152 numInst = 0; 153 numLoad = 0; 154 last_idle = 0; 155 lastIcacheStall = 0; 156 lastDcacheStall = 0; 157 158 execContexts.push_back(xc); 159} 160 161SimpleCPU::~SimpleCPU() 162{ 163} 164 165 166void 167SimpleCPU::switchOut() 168{ 169 _status = SwitchedOut; 170 if (tickEvent.scheduled()) 171 tickEvent.squash(); 172} 173 174 175void 176SimpleCPU::takeOverFrom(BaseCPU *oldCPU) 177{ 178 BaseCPU::takeOverFrom(oldCPU); 179 180 assert(!tickEvent.scheduled()); 181 182 // if any of this CPU's ExecContexts are active, mark the CPU as 183 // running and schedule its tick event. 184 for (int i = 0; i < execContexts.size(); ++i) { 185 ExecContext *xc = execContexts[i]; 186 if (xc->status() == ExecContext::Active && _status != Running) { 187 _status = Running; 188 tickEvent.schedule(curTick); 189 } 190 } 191 192 oldCPU->switchOut(); 193} 194 195 196void 197SimpleCPU::execCtxStatusChg(int thread_num) { 198 assert(thread_num == 0); 199 assert(xc); 200 201 if (xc->status() == ExecContext::Active) 202 setStatus(Running); 203 else 204 setStatus(Idle); 205} 206 207 208void 209SimpleCPU::regStats() 210{ 211 BaseCPU::regStats(); 212 213 numInsts 214 .name(name() + ".num_insts") 215 .desc("Number of instructions executed") 216 ; 217 218 numMemRefs 219 .name(name() + ".num_refs") 220 .desc("Number of memory references") 221 ; 222 223 idleCycles 224 .name(name() + ".idle_cycles") 225 .desc("Number of idle cycles") 226 ; 227 228 idleFraction 229 .name(name() + ".idle_fraction") 230 .desc("Percentage of idle cycles") 231 ; 232 233 icacheStallCycles 234 .name(name() + ".icache_stall_cycles") 235 .desc("ICache total stall cycles") 236 .prereq(icacheStallCycles) 237 ; 238 239 dcacheStallCycles 240 .name(name() + ".dcache_stall_cycles") 241 .desc("DCache total stall cycles") 242 .prereq(dcacheStallCycles) 243 ; 244 245 idleFraction = idleCycles / simTicks; 246 247 numInsts = Statistics::scalar(numInst); 248 simInsts += numInsts; 249} 250 251void 252SimpleCPU::serialize() 253{ 254 nameOut(); 255 256#ifdef FULL_SYSTEM 257#if 0 258 // do we need this anymore?? egh 259 childOut("itb", xc->itb); 260 childOut("dtb", xc->dtb); 261 childOut("physmem", physmem); 262#endif 263#endif 264 265 for (int i = 0; i < NumIntRegs; i++) { 266 stringstream buf; 267 ccprintf(buf, "R%02d", i); 268 paramOut(buf.str(), xc->regs.intRegFile[i]); 269 } 270 for (int i = 0; i < NumFloatRegs; i++) { 271 stringstream buf; 272 ccprintf(buf, "F%02d", i); 273 paramOut(buf.str(), xc->regs.floatRegFile.d[i]); 274 } 275 // CPUTraitsType::serializeSpecialRegs(getProxy(), xc->regs); 276} 277 278void 279SimpleCPU::unserialize(IniFile &db, const string &category, ConfigNode *node) 280{ 281 string data; 282 283 for (int i = 0; i < NumIntRegs; i++) { 284 stringstream buf; 285 ccprintf(buf, "R%02d", i); 286 db.findDefault(category, buf.str(), data); 287 to_number(data,xc->regs.intRegFile[i]); 288 } 289 for (int i = 0; i < NumFloatRegs; i++) { 290 stringstream buf; 291 ccprintf(buf, "F%02d", i); 292 db.findDefault(category, buf.str(), data); 293 xc->regs.floatRegFile.d[i] = strtod(data.c_str(),NULL); 294 } 295 296 // Read in Special registers 297 298 // CPUTraitsType::unserializeSpecialRegs(db,category,node,xc->regs); 299} 300 301void 302change_thread_state(int thread_number, int activate, int priority) 303{ 304} 305 306// precise architected memory state accessor macros 307template <class T> 308Fault 309SimpleCPU::read(Addr addr, T& data, unsigned flags) 310{ 311 memReq->reset(addr, sizeof(T), flags); 312 313 // translate to physical address 314 Fault fault = xc->translateDataReadReq(memReq); 315 316 // do functional access 317 if (fault == No_Fault) 318 fault = xc->read(memReq, data); 319 320 if (traceData) { 321 traceData->setAddr(addr); 322 if (fault == No_Fault) 323 traceData->setData(data); 324 } 325 326 // if we have a cache, do cache access too 327 if (fault == No_Fault && dcacheInterface) { 328 memReq->cmd = Read; 329 memReq->completionEvent = NULL; 330 memReq->time = curTick; 331 memReq->flags &= ~UNCACHEABLE; 332 MemAccessResult result = dcacheInterface->access(memReq); 333 334 // Ugly hack to get an event scheduled *only* if the access is 335 // a miss. We really should add first-class support for this 336 // at some point. 337 if (result != MA_HIT && dcacheInterface->doEvents) { 338 memReq->completionEvent = &cacheCompletionEvent; 339 setStatus(DcacheMissStall); 340 } 341 } 342 343 return fault; 344} 345 346#ifndef DOXYGEN_SHOULD_SKIP_THIS 347 348template 349Fault 350SimpleCPU::read(Addr addr, uint64_t& data, unsigned flags); 351 352template 353Fault 354SimpleCPU::read(Addr addr, uint32_t& data, unsigned flags); 355 356template 357Fault 358SimpleCPU::read(Addr addr, uint16_t& data, unsigned flags); 359 360template 361Fault 362SimpleCPU::read(Addr addr, uint8_t& data, unsigned flags); 363 364#endif //DOXYGEN_SHOULD_SKIP_THIS 365 366template<> 367Fault 368SimpleCPU::read(Addr addr, double& data, unsigned flags) 369{ 370 return read(addr, *(uint64_t*)&data, flags); 371} 372 373template<> 374Fault 375SimpleCPU::read(Addr addr, float& data, unsigned flags) 376{ 377 return read(addr, *(uint32_t*)&data, flags); 378} 379 380 381template<> 382Fault 383SimpleCPU::read(Addr addr, int32_t& data, unsigned flags) 384{ 385 return read(addr, (uint32_t&)data, flags); 386} 387 388 389template <class T> 390Fault 391SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 392{ 393 if (traceData) { 394 traceData->setAddr(addr); 395 traceData->setData(data); 396 } 397 398 memReq->reset(addr, sizeof(T), flags); 399 400 // translate to physical address 401 Fault fault = xc->translateDataWriteReq(memReq); 402 403 // do functional access 404 if (fault == No_Fault) 405 fault = xc->write(memReq, data); 406 407 if (fault == No_Fault && dcacheInterface) { 408 memReq->cmd = Write; 409 memcpy(memReq->data,(uint8_t *)&data,memReq->size); 410 memReq->completionEvent = NULL; 411 memReq->time = curTick; 412 memReq->flags &= ~UNCACHEABLE; 413 MemAccessResult result = dcacheInterface->access(memReq); 414 415 // Ugly hack to get an event scheduled *only* if the access is 416 // a miss. We really should add first-class support for this 417 // at some point. 418 if (result != MA_HIT && dcacheInterface->doEvents) { 419 memReq->completionEvent = &cacheCompletionEvent; 420 setStatus(DcacheMissStall); 421 } 422 } 423 424 if (res && (fault == No_Fault)) 425 *res = memReq->result; 426 427 return fault; 428} 429 430 431#ifndef DOXYGEN_SHOULD_SKIP_THIS 432template 433Fault 434SimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res); 435 436template 437Fault 438SimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res); 439 440template 441Fault 442SimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res); 443 444template 445Fault 446SimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res); 447 448#endif //DOXYGEN_SHOULD_SKIP_THIS 449 450template<> 451Fault 452SimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 453{ 454 return write(*(uint64_t*)&data, addr, flags, res); 455} 456 457template<> 458Fault 459SimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 460{ 461 return write(*(uint32_t*)&data, addr, flags, res); 462} 463 464 465template<> 466Fault 467SimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 468{ 469 return write((uint32_t)data, addr, flags, res); 470} 471 472 473#ifdef FULL_SYSTEM 474Addr 475SimpleCPU::dbg_vtophys(Addr addr) 476{ 477 return vtophys(xc, addr); 478} 479#endif // FULL_SYSTEM 480 481Tick save_cycle = 0; 482 483 484void 485SimpleCPU::processCacheCompletion() 486{ 487 switch (status()) { 488 case IcacheMissStall: 489 icacheStallCycles += curTick - lastIcacheStall; 490 setStatus(IcacheMissComplete); 491 break; 492 case DcacheMissStall: 493 dcacheStallCycles += curTick - lastDcacheStall; 494 setStatus(Running); 495 break; 496 case SwitchedOut: 497 // If this CPU has been switched out due to sampling/warm-up, 498 // ignore any further status changes (e.g., due to cache 499 // misses outstanding at the time of the switch). 500 return; 501 default: 502 panic("SimpleCPU::processCacheCompletion: bad state"); 503 break; 504 } 505} 506 507#ifdef FULL_SYSTEM 508void 509SimpleCPU::post_interrupt(int int_num, int index) 510{ 511 BaseCPU::post_interrupt(int_num, index); 512 513 if (xc->status() == ExecContext::Suspended) { 514 DPRINTF(IPI,"Suspended Processor awoke\n"); 515 xc->setStatus(ExecContext::Active); 516 Annotate::Resume(xc); 517 } 518} 519#endif // FULL_SYSTEM 520 521/* start simulation, program loaded, processor precise state initialized */ 522void 523SimpleCPU::tick() 524{ 525 traceData = NULL; 526 527#ifdef FULL_SYSTEM 528 if (fault == No_Fault && AlphaISA::check_interrupts && 529 xc->cpu->check_interrupts() && 530 !PC_PAL(xc->regs.pc) && 531 status() != IcacheMissComplete) { 532 int ipl = 0; 533 int summary = 0; 534 AlphaISA::check_interrupts = 0; 535 IntReg *ipr = xc->regs.ipr; 536 537 if (xc->regs.ipr[TheISA::IPR_SIRR]) { 538 for (int i = TheISA::INTLEVEL_SOFTWARE_MIN; 539 i < TheISA::INTLEVEL_SOFTWARE_MAX; i++) { 540 if (ipr[TheISA::IPR_SIRR] & (ULL(1) << i)) { 541 // See table 4-19 of 21164 hardware reference 542 ipl = (i - TheISA::INTLEVEL_SOFTWARE_MIN) + 1; 543 summary |= (ULL(1) << i); 544 } 545 } 546 } 547 548 uint64_t interrupts = xc->cpu->intr_status(); 549 for (int i = TheISA::INTLEVEL_EXTERNAL_MIN; 550 i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) { 551 if (interrupts & (ULL(1) << i)) { 552 // See table 4-19 of 21164 hardware reference 553 ipl = i; 554 summary |= (ULL(1) << i); 555 } 556 } 557 558 if (ipr[TheISA::IPR_ASTRR]) 559 panic("asynchronous traps not implemented\n"); 560 561 if (ipl && ipl > xc->regs.ipr[TheISA::IPR_IPLR]) { 562 ipr[TheISA::IPR_ISR] = summary; 563 ipr[TheISA::IPR_INTID] = ipl; 564 xc->ev5_trap(Interrupt_Fault); 565 566 DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", 567 ipr[TheISA::IPR_IPLR], ipl, summary); 568 } 569 } 570#endif 571 572 // maintain $r0 semantics 573 xc->regs.intRegFile[ZeroReg] = 0; 574#ifdef TARGET_ALPHA 575 xc->regs.floatRegFile.d[ZeroReg] = 0.0; 576#endif // TARGET_ALPHA 577 578 if (status() == IcacheMissComplete) { 579 // We've already fetched an instruction and were stalled on an 580 // I-cache miss. No need to fetch it again. 581 582 setStatus(Running); 583 } 584 else { 585 // Try to fetch an instruction 586 587 // set up memory request for instruction fetch 588#ifdef FULL_SYSTEM 589#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 590#else 591#define IFETCH_FLAGS(pc) 0 592#endif 593 594 memReq->cmd = Read; 595 memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t), 596 IFETCH_FLAGS(xc->regs.pc)); 597 598 fault = xc->translateInstReq(memReq); 599 600 if (fault == No_Fault) 601 fault = xc->mem->read(memReq, inst); 602 603 if (icacheInterface && fault == No_Fault) { 604 memReq->completionEvent = NULL; 605 606 memReq->time = curTick; 607 memReq->flags &= ~UNCACHEABLE; 608 MemAccessResult result = icacheInterface->access(memReq); 609 610 // Ugly hack to get an event scheduled *only* if the access is 611 // a miss. We really should add first-class support for this 612 // at some point. 613 if (result != MA_HIT && icacheInterface->doEvents) { 614 memReq->completionEvent = &cacheCompletionEvent; 615 setStatus(IcacheMissStall); 616 return; 617 } 618 } 619 } 620 621 // If we've got a valid instruction (i.e., no fault on instruction 622 // fetch), then execute it. 623 if (fault == No_Fault) { 624 625 // keep an instruction count 626 numInst++; 627 628 // check for instruction-count-based events 629 comInsnEventQueue[0]->serviceEvents(numInst); 630 631 // decode the instruction 632 StaticInstPtr<TheISA> si(inst); 633 634 traceData = Trace::getInstRecord(curTick, xc, this, si, 635 xc->regs.pc); 636 637#ifdef FULL_SYSTEM 638 xc->regs.opcode = (inst >> 26) & 0x3f; 639 xc->regs.ra = (inst >> 21) & 0x1f; 640#endif // FULL_SYSTEM 641 642 xc->func_exe_insn++; 643 644 fault = si->execute(this, xc, traceData); 645 646 if (si->isMemRef()) { 647 numMemRefs++; 648 } 649 650 if (si->isLoad()) { 651 ++numLoad; 652 comLoadEventQueue[0]->serviceEvents(numLoad); 653 } 654 655 if (traceData) 656 traceData->finalize(); 657 658 } // if (fault == No_Fault) 659 660 if (fault != No_Fault) { 661#ifdef FULL_SYSTEM 662 xc->ev5_trap(fault); 663#else // !FULL_SYSTEM 664 fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc); 665#endif // FULL_SYSTEM 666 } 667 else { 668 // go to the next instruction 669 xc->regs.pc = xc->regs.npc; 670 xc->regs.npc += sizeof(MachInst); 671 } 672 673#ifdef FULL_SYSTEM 674 Addr oldpc; 675 do { 676 oldpc = xc->regs.pc; 677 system->pcEventQueue.service(xc); 678 } while (oldpc != xc->regs.pc); 679#endif 680 681 assert(status() == Running || 682 status() == Idle || 683 status() == DcacheMissStall); 684 685 if (status() == Running && !tickEvent.scheduled()) 686 tickEvent.schedule(curTick + 1); 687} 688 689 690//////////////////////////////////////////////////////////////////////// 691// 692// SimpleCPU Simulation Object 693// 694BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) 695 696 Param<Counter> max_insts_any_thread; 697 Param<Counter> max_insts_all_threads; 698 Param<Counter> max_loads_any_thread; 699 Param<Counter> max_loads_all_threads; 700 701#ifdef FULL_SYSTEM 702 SimObjectParam<AlphaItb *> itb; 703 SimObjectParam<AlphaDtb *> dtb; 704 SimObjectParam<FunctionalMemory *> mem; 705 SimObjectParam<System *> system; 706 Param<int> mult; 707#else 708 SimObjectParam<Process *> workload; 709#endif // FULL_SYSTEM 710 711 SimObjectParam<BaseMem *> icache; 712 SimObjectParam<BaseMem *> dcache; 713 714 Param<bool> defer_registration; 715 716END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) 717 718BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU) 719 720 INIT_PARAM_DFLT(max_insts_any_thread, 721 "terminate when any thread reaches this insn count", 722 0), 723 INIT_PARAM_DFLT(max_insts_all_threads, 724 "terminate when all threads have reached this insn count", 725 0), 726 INIT_PARAM_DFLT(max_loads_any_thread, 727 "terminate when any thread reaches this load count", 728 0), 729 INIT_PARAM_DFLT(max_loads_all_threads, 730 "terminate when all threads have reached this load count", 731 0), 732 733#ifdef FULL_SYSTEM 734 INIT_PARAM(itb, "Instruction TLB"), 735 INIT_PARAM(dtb, "Data TLB"), 736 INIT_PARAM(mem, "memory"), 737 INIT_PARAM(system, "system object"), 738 INIT_PARAM_DFLT(mult, "system clock multiplier", 1), 739#else 740 INIT_PARAM(workload, "processes to run"), 741#endif // FULL_SYSTEM 742 743 INIT_PARAM_DFLT(icache, "L1 instruction cache object", NULL), 744 INIT_PARAM_DFLT(dcache, "L1 data cache object", NULL), 745 INIT_PARAM_DFLT(defer_registration, "defer registration with system " 746 "(for sampling)", false) 747 748END_INIT_SIM_OBJECT_PARAMS(SimpleCPU) 749 750 751CREATE_SIM_OBJECT(SimpleCPU) 752{ 753 SimpleCPU *cpu; 754#ifdef FULL_SYSTEM 755 if (mult != 1) 756 panic("processor clock multiplier must be 1\n"); 757 758 cpu = new SimpleCPU(getInstanceName(), system, 759 max_insts_any_thread, max_insts_all_threads, 760 max_loads_any_thread, max_loads_all_threads, 761 itb, dtb, mem, 762 (icache) ? icache->getInterface() : NULL, 763 (dcache) ? dcache->getInterface() : NULL, 764 ticksPerSecond * mult); 765#else 766 767 cpu = new SimpleCPU(getInstanceName(), workload, 768 max_insts_any_thread, max_insts_all_threads, 769 max_loads_any_thread, max_loads_all_threads, 770 (icache) ? icache->getInterface() : NULL, 771 (dcache) ? dcache->getInterface() : NULL); 772 773#endif // FULL_SYSTEM 774 775 if (!defer_registration) { 776 cpu->registerExecContexts(); 777 } 778 779 return cpu; 780} 781 782REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU) 783