timing.cc revision 4115:cc1d6df13c7d
15222Sksewell@umich.edu/* 25268Sksewell@umich.edu * Copyright (c) 2002-2005 The Regents of The University of Michigan 35254Sksewell@umich.edu * All rights reserved. 45222Sksewell@umich.edu * 55222Sksewell@umich.edu * Redistribution and use in source and binary forms, with or without 65222Sksewell@umich.edu * modification, are permitted provided that the following conditions are 75222Sksewell@umich.edu * met: redistributions of source code must retain the above copyright 85222Sksewell@umich.edu * notice, this list of conditions and the following disclaimer; 95222Sksewell@umich.edu * redistributions in binary form must reproduce the above copyright 105222Sksewell@umich.edu * notice, this list of conditions and the following disclaimer in the 115222Sksewell@umich.edu * documentation and/or other materials provided with the distribution; 125222Sksewell@umich.edu * neither the name of the copyright holders nor the names of its 135222Sksewell@umich.edu * contributors may be used to endorse or promote products derived from 145222Sksewell@umich.edu * this software without specific prior written permission. 155222Sksewell@umich.edu * 165222Sksewell@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 175222Sksewell@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 185222Sksewell@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 195222Sksewell@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 205222Sksewell@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 215222Sksewell@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 225222Sksewell@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 235222Sksewell@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 245222Sksewell@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 255222Sksewell@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 265222Sksewell@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 275222Sksewell@umich.edu * 285222Sksewell@umich.edu * Authors: Steve Reinhardt 295268Sksewell@umich.edu */ 305268Sksewell@umich.edu 315254Sksewell@umich.edu#include "arch/locked_mem.hh" 325222Sksewell@umich.edu#include "arch/utility.hh" 335222Sksewell@umich.edu#include "base/bigint.hh" 3411793Sbrandon.potter@amd.com#include "cpu/exetrace.hh" 3511793Sbrandon.potter@amd.com#include "cpu/simple/timing.hh" 365222Sksewell@umich.edu#include "mem/packet.hh" 375222Sksewell@umich.edu#include "mem/packet_access.hh" 385222Sksewell@umich.edu#include "sim/builder.hh" 395222Sksewell@umich.edu#include "sim/system.hh" 405222Sksewell@umich.edu 418758Sgblack@eecs.umich.eduusing namespace std; 425254Sksewell@umich.eduusing namespace TheISA; 435222Sksewell@umich.edu 445222Sksewell@umich.eduPort * 455222Sksewell@umich.eduTimingSimpleCPU::getPort(const std::string &if_name, int idx) 465222Sksewell@umich.edu{ 475222Sksewell@umich.edu if (if_name == "dcache_port") 485222Sksewell@umich.edu return &dcachePort; 498758Sgblack@eecs.umich.edu else if (if_name == "icache_port") 508758Sgblack@eecs.umich.edu return &icachePort; 515222Sksewell@umich.edu else 525222Sksewell@umich.edu panic("No Such Port\n"); 535222Sksewell@umich.edu} 545222Sksewell@umich.edu 555222Sksewell@umich.eduvoid 568758Sgblack@eecs.umich.eduTimingSimpleCPU::init() 575222Sksewell@umich.edu{ 585222Sksewell@umich.edu BaseCPU::init(); 59#if FULL_SYSTEM 60 for (int i = 0; i < threadContexts.size(); ++i) { 61 ThreadContext *tc = threadContexts[i]; 62 63 // initialize CPU, including PC 64 TheISA::initCPU(tc, tc->readCpuId()); 65 } 66#endif 67} 68 69Tick 70TimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) 71{ 72 panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 73 return curTick; 74} 75 76void 77TimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) 78{ 79 //No internal storage to update, jusst return 80 return; 81} 82 83void 84TimingSimpleCPU::CpuPort::recvStatusChange(Status status) 85{ 86 if (status == RangeChange) { 87 if (!snoopRangeSent) { 88 snoopRangeSent = true; 89 sendStatusChange(Port::RangeChange); 90 } 91 return; 92 } 93 94 panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); 95} 96 97 98void 99TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) 100{ 101 pkt = _pkt; 102 Event::schedule(t); 103} 104 105TimingSimpleCPU::TimingSimpleCPU(Params *p) 106 : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock), 107 cpu_id(p->cpu_id) 108{ 109 _status = Idle; 110 111 icachePort.snoopRangeSent = false; 112 dcachePort.snoopRangeSent = false; 113 114 ifetch_pkt = dcache_pkt = NULL; 115 drainEvent = NULL; 116 fetchEvent = NULL; 117 previousTick = 0; 118 changeState(SimObject::Running); 119} 120 121 122TimingSimpleCPU::~TimingSimpleCPU() 123{ 124} 125 126void 127TimingSimpleCPU::serialize(ostream &os) 128{ 129 SimObject::State so_state = SimObject::getState(); 130 SERIALIZE_ENUM(so_state); 131 BaseSimpleCPU::serialize(os); 132} 133 134void 135TimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 136{ 137 SimObject::State so_state; 138 UNSERIALIZE_ENUM(so_state); 139 BaseSimpleCPU::unserialize(cp, section); 140} 141 142unsigned int 143TimingSimpleCPU::drain(Event *drain_event) 144{ 145 // TimingSimpleCPU is ready to drain if it's not waiting for 146 // an access to complete. 147 if (status() == Idle || status() == Running || status() == SwitchedOut) { 148 changeState(SimObject::Drained); 149 return 0; 150 } else { 151 changeState(SimObject::Draining); 152 drainEvent = drain_event; 153 return 1; 154 } 155} 156 157void 158TimingSimpleCPU::resume() 159{ 160 if (_status != SwitchedOut && _status != Idle) { 161 assert(system->getMemoryMode() == System::Timing); 162 163 // Delete the old event if it existed. 164 if (fetchEvent) { 165 if (fetchEvent->scheduled()) 166 fetchEvent->deschedule(); 167 168 delete fetchEvent; 169 } 170 171 fetchEvent = 172 new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false); 173 fetchEvent->schedule(nextCycle()); 174 } 175 176 changeState(SimObject::Running); 177 previousTick = curTick; 178} 179 180void 181TimingSimpleCPU::switchOut() 182{ 183 assert(status() == Running || status() == Idle); 184 _status = SwitchedOut; 185 numCycles += curTick - previousTick; 186 187 // If we've been scheduled to resume but are then told to switch out, 188 // we'll need to cancel it. 189 if (fetchEvent && fetchEvent->scheduled()) 190 fetchEvent->deschedule(); 191} 192 193 194void 195TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 196{ 197 BaseCPU::takeOverFrom(oldCPU); 198 199 // if any of this CPU's ThreadContexts are active, mark the CPU as 200 // running and schedule its tick event. 201 for (int i = 0; i < threadContexts.size(); ++i) { 202 ThreadContext *tc = threadContexts[i]; 203 if (tc->status() == ThreadContext::Active && _status != Running) { 204 _status = Running; 205 break; 206 } 207 } 208 209 if (_status != Running) { 210 _status = Idle; 211 } 212 213 Port *peer; 214 if (icachePort.getPeer() == NULL) { 215 peer = oldCPU->getPort("icache_port")->getPeer(); 216 icachePort.setPeer(peer); 217 } else { 218 peer = icachePort.getPeer(); 219 } 220 peer->setPeer(&icachePort); 221 222 if (dcachePort.getPeer() == NULL) { 223 peer = oldCPU->getPort("dcache_port")->getPeer(); 224 dcachePort.setPeer(peer); 225 } else { 226 peer = dcachePort.getPeer(); 227 } 228 peer->setPeer(&dcachePort); 229} 230 231 232void 233TimingSimpleCPU::activateContext(int thread_num, int delay) 234{ 235 assert(thread_num == 0); 236 assert(thread); 237 238 assert(_status == Idle); 239 240 notIdleFraction++; 241 _status = Running; 242 243#if FULL_SYSTEM 244 // Connect the ThreadContext's memory ports (Functional/Virtual 245 // Ports) 246 tc->connectMemPorts(); 247#endif 248 249 // kick things off by initiating the fetch of the next instruction 250 fetchEvent = 251 new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false); 252 fetchEvent->schedule(nextCycle(curTick + cycles(delay))); 253} 254 255 256void 257TimingSimpleCPU::suspendContext(int thread_num) 258{ 259 assert(thread_num == 0); 260 assert(thread); 261 262 assert(_status == Running); 263 264 // just change status to Idle... if status != Running, 265 // completeInst() will not initiate fetch of next instruction. 266 267 notIdleFraction--; 268 _status = Idle; 269} 270 271 272template <class T> 273Fault 274TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 275{ 276 Request *req = 277 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 278 cpu_id, /* thread ID */ 0); 279 280 if (traceData) { 281 traceData->setAddr(req->getVaddr()); 282 } 283 284 // translate to physical address 285 Fault fault = thread->translateDataReadReq(req); 286 287 // Now do the access. 288 if (fault == NoFault) { 289 PacketPtr pkt = 290 new Packet(req, MemCmd::ReadReq, Packet::Broadcast); 291 pkt->dataDynamic<T>(new T); 292 293 if (!dcachePort.sendTiming(pkt)) { 294 _status = DcacheRetry; 295 dcache_pkt = pkt; 296 } else { 297 _status = DcacheWaitResponse; 298 // memory system takes ownership of packet 299 dcache_pkt = NULL; 300 } 301 } else { 302 delete req; 303 } 304 305 // This will need a new way to tell if it has a dcache attached. 306 if (req->isUncacheable()) 307 recordEvent("Uncached Read"); 308 309 return fault; 310} 311 312#ifndef DOXYGEN_SHOULD_SKIP_THIS 313 314template 315Fault 316TimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags); 317 318template 319Fault 320TimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags); 321 322template 323Fault 324TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 325 326template 327Fault 328TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 329 330template 331Fault 332TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 333 334template 335Fault 336TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 337 338#endif //DOXYGEN_SHOULD_SKIP_THIS 339 340template<> 341Fault 342TimingSimpleCPU::read(Addr addr, double &data, unsigned flags) 343{ 344 return read(addr, *(uint64_t*)&data, flags); 345} 346 347template<> 348Fault 349TimingSimpleCPU::read(Addr addr, float &data, unsigned flags) 350{ 351 return read(addr, *(uint32_t*)&data, flags); 352} 353 354 355template<> 356Fault 357TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 358{ 359 return read(addr, (uint32_t&)data, flags); 360} 361 362 363template <class T> 364Fault 365TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 366{ 367 Request *req = 368 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 369 cpu_id, /* thread ID */ 0); 370 371 if (traceData) { 372 traceData->setAddr(req->getVaddr()); 373 } 374 375 // translate to physical address 376 Fault fault = thread->translateDataWriteReq(req); 377 378 // Now do the access. 379 if (fault == NoFault) { 380 assert(dcache_pkt == NULL); 381 if (req->isSwap()) 382 dcache_pkt = new Packet(req, MemCmd::SwapReq, Packet::Broadcast); 383 else 384 dcache_pkt = new Packet(req, MemCmd::WriteReq, Packet::Broadcast); 385 dcache_pkt->allocate(); 386 dcache_pkt->set(data); 387 388 bool do_access = true; // flag to suppress cache access 389 390 if (req->isLocked()) { 391 do_access = TheISA::handleLockedWrite(thread, req); 392 } 393 if (req->isCondSwap()) { 394 assert(res); 395 req->setExtraData(*res); 396 } 397 398 if (do_access) { 399 if (!dcachePort.sendTiming(dcache_pkt)) { 400 _status = DcacheRetry; 401 } else { 402 _status = DcacheWaitResponse; 403 // memory system takes ownership of packet 404 dcache_pkt = NULL; 405 } 406 } 407 } else { 408 delete req; 409 } 410 411 // This will need a new way to tell if it's hooked up to a cache or not. 412 if (req->isUncacheable()) 413 recordEvent("Uncached Write"); 414 415 // If the write needs to have a fault on the access, consider calling 416 // changeStatus() and changing it to "bad addr write" or something. 417 return fault; 418} 419 420 421#ifndef DOXYGEN_SHOULD_SKIP_THIS 422template 423Fault 424TimingSimpleCPU::write(uint64_t data, Addr addr, 425 unsigned flags, uint64_t *res); 426 427template 428Fault 429TimingSimpleCPU::write(uint32_t data, Addr addr, 430 unsigned flags, uint64_t *res); 431 432template 433Fault 434TimingSimpleCPU::write(uint16_t data, Addr addr, 435 unsigned flags, uint64_t *res); 436 437template 438Fault 439TimingSimpleCPU::write(uint8_t data, Addr addr, 440 unsigned flags, uint64_t *res); 441 442#endif //DOXYGEN_SHOULD_SKIP_THIS 443 444template<> 445Fault 446TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 447{ 448 return write(*(uint64_t*)&data, addr, flags, res); 449} 450 451template<> 452Fault 453TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 454{ 455 return write(*(uint32_t*)&data, addr, flags, res); 456} 457 458 459template<> 460Fault 461TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 462{ 463 return write((uint32_t)data, addr, flags, res); 464} 465 466 467void 468TimingSimpleCPU::fetch() 469{ 470 if (!curStaticInst || !curStaticInst->isDelayedCommit()) 471 checkForInterrupts(); 472 473 Request *ifetch_req = new Request(); 474 ifetch_req->setThreadContext(cpu_id, /* thread ID */ 0); 475 Fault fault = setupFetchRequest(ifetch_req); 476 477 ifetch_pkt = new Packet(ifetch_req, MemCmd::ReadReq, Packet::Broadcast); 478 ifetch_pkt->dataStatic(&inst); 479 480 if (fault == NoFault) { 481 if (!icachePort.sendTiming(ifetch_pkt)) { 482 // Need to wait for retry 483 _status = IcacheRetry; 484 } else { 485 // Need to wait for cache to respond 486 _status = IcacheWaitResponse; 487 // ownership of packet transferred to memory system 488 ifetch_pkt = NULL; 489 } 490 } else { 491 delete ifetch_req; 492 delete ifetch_pkt; 493 // fetch fault: advance directly to next instruction (fault handler) 494 advanceInst(fault); 495 } 496 497 numCycles += curTick - previousTick; 498 previousTick = curTick; 499} 500 501 502void 503TimingSimpleCPU::advanceInst(Fault fault) 504{ 505 advancePC(fault); 506 507 if (_status == Running) { 508 // kick off fetch of next instruction... callback from icache 509 // response will cause that instruction to be executed, 510 // keeping the CPU running. 511 fetch(); 512 } 513} 514 515 516void 517TimingSimpleCPU::completeIfetch(PacketPtr pkt) 518{ 519 // received a response from the icache: execute the received 520 // instruction 521 assert(pkt->result == Packet::Success); 522 assert(_status == IcacheWaitResponse); 523 524 _status = Running; 525 526 numCycles += curTick - previousTick; 527 previousTick = curTick; 528 529 if (getState() == SimObject::Draining) { 530 delete pkt->req; 531 delete pkt; 532 533 completeDrain(); 534 return; 535 } 536 537 preExecute(); 538 if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { 539 // load or store: just send to dcache 540 Fault fault = curStaticInst->initiateAcc(this, traceData); 541 if (_status != Running) { 542 // instruction will complete in dcache response callback 543 assert(_status == DcacheWaitResponse || _status == DcacheRetry); 544 assert(fault == NoFault); 545 } else { 546 if (fault == NoFault) { 547 // early fail on store conditional: complete now 548 assert(dcache_pkt != NULL); 549 fault = curStaticInst->completeAcc(dcache_pkt, this, 550 traceData); 551 delete dcache_pkt->req; 552 delete dcache_pkt; 553 dcache_pkt = NULL; 554 } 555 postExecute(); 556 advanceInst(fault); 557 } 558 } else { 559 // non-memory instruction: execute completely now 560 Fault fault = curStaticInst->execute(this, traceData); 561 postExecute(); 562 advanceInst(fault); 563 } 564 565 delete pkt->req; 566 delete pkt; 567} 568 569void 570TimingSimpleCPU::IcachePort::ITickEvent::process() 571{ 572 cpu->completeIfetch(pkt); 573} 574 575bool 576TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt) 577{ 578 if (pkt->isResponse()) { 579 // delay processing of returned data until next CPU clock edge 580 Tick mem_time = pkt->req->getTime(); 581 Tick next_tick = cpu->nextCycle(mem_time); 582 583 if (next_tick == curTick) 584 cpu->completeIfetch(pkt); 585 else 586 tickEvent.schedule(pkt, next_tick); 587 588 return true; 589 } 590 else { 591 //Snooping a Coherence Request, do nothing 592 return true; 593 } 594} 595 596void 597TimingSimpleCPU::IcachePort::recvRetry() 598{ 599 // we shouldn't get a retry unless we have a packet that we're 600 // waiting to transmit 601 assert(cpu->ifetch_pkt != NULL); 602 assert(cpu->_status == IcacheRetry); 603 PacketPtr tmp = cpu->ifetch_pkt; 604 if (sendTiming(tmp)) { 605 cpu->_status = IcacheWaitResponse; 606 cpu->ifetch_pkt = NULL; 607 } 608} 609 610void 611TimingSimpleCPU::completeDataAccess(PacketPtr pkt) 612{ 613 // received a response from the dcache: complete the load or store 614 // instruction 615 assert(pkt->result == Packet::Success); 616 assert(_status == DcacheWaitResponse); 617 _status = Running; 618 619 numCycles += curTick - previousTick; 620 previousTick = curTick; 621 622 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 623 624 if (pkt->isRead() && pkt->req->isLocked()) { 625 TheISA::handleLockedRead(thread, pkt->req); 626 } 627 628 delete pkt->req; 629 delete pkt; 630 631 postExecute(); 632 633 if (getState() == SimObject::Draining) { 634 advancePC(fault); 635 completeDrain(); 636 637 return; 638 } 639 640 advanceInst(fault); 641} 642 643 644void 645TimingSimpleCPU::completeDrain() 646{ 647 DPRINTF(Config, "Done draining\n"); 648 changeState(SimObject::Drained); 649 drainEvent->process(); 650} 651 652bool 653TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt) 654{ 655 if (pkt->isResponse()) { 656 // delay processing of returned data until next CPU clock edge 657 Tick mem_time = pkt->req->getTime(); 658 Tick next_tick = cpu->nextCycle(mem_time); 659 660 if (next_tick == curTick) 661 cpu->completeDataAccess(pkt); 662 else 663 tickEvent.schedule(pkt, next_tick); 664 665 return true; 666 } 667 else { 668 //Snooping a coherence req, do nothing 669 return true; 670 } 671} 672 673void 674TimingSimpleCPU::DcachePort::DTickEvent::process() 675{ 676 cpu->completeDataAccess(pkt); 677} 678 679void 680TimingSimpleCPU::DcachePort::recvRetry() 681{ 682 // we shouldn't get a retry unless we have a packet that we're 683 // waiting to transmit 684 assert(cpu->dcache_pkt != NULL); 685 assert(cpu->_status == DcacheRetry); 686 PacketPtr tmp = cpu->dcache_pkt; 687 if (sendTiming(tmp)) { 688 cpu->_status = DcacheWaitResponse; 689 // memory system takes ownership of packet 690 cpu->dcache_pkt = NULL; 691 } 692} 693 694 695//////////////////////////////////////////////////////////////////////// 696// 697// TimingSimpleCPU Simulation Object 698// 699BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 700 701 Param<Counter> max_insts_any_thread; 702 Param<Counter> max_insts_all_threads; 703 Param<Counter> max_loads_any_thread; 704 Param<Counter> max_loads_all_threads; 705 Param<Tick> progress_interval; 706 SimObjectParam<System *> system; 707 Param<int> cpu_id; 708 709#if FULL_SYSTEM 710 SimObjectParam<TheISA::ITB *> itb; 711 SimObjectParam<TheISA::DTB *> dtb; 712 Param<Tick> profile; 713 714 Param<bool> do_quiesce; 715 Param<bool> do_checkpoint_insts; 716 Param<bool> do_statistics_insts; 717#else 718 SimObjectParam<Process *> workload; 719#endif // FULL_SYSTEM 720 721 Param<int> clock; 722 Param<int> phase; 723 724 Param<bool> defer_registration; 725 Param<int> width; 726 Param<bool> function_trace; 727 Param<Tick> function_trace_start; 728 Param<bool> simulate_stalls; 729 730END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 731 732BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 733 734 INIT_PARAM(max_insts_any_thread, 735 "terminate when any thread reaches this inst count"), 736 INIT_PARAM(max_insts_all_threads, 737 "terminate when all threads have reached this inst count"), 738 INIT_PARAM(max_loads_any_thread, 739 "terminate when any thread reaches this load count"), 740 INIT_PARAM(max_loads_all_threads, 741 "terminate when all threads have reached this load count"), 742 INIT_PARAM(progress_interval, "Progress interval"), 743 INIT_PARAM(system, "system object"), 744 INIT_PARAM(cpu_id, "processor ID"), 745 746#if FULL_SYSTEM 747 INIT_PARAM(itb, "Instruction TLB"), 748 INIT_PARAM(dtb, "Data TLB"), 749 INIT_PARAM(profile, ""), 750 INIT_PARAM(do_quiesce, ""), 751 INIT_PARAM(do_checkpoint_insts, ""), 752 INIT_PARAM(do_statistics_insts, ""), 753#else 754 INIT_PARAM(workload, "processes to run"), 755#endif // FULL_SYSTEM 756 757 INIT_PARAM(clock, "clock speed"), 758 INIT_PARAM_DFLT(phase, "clock phase", 0), 759 INIT_PARAM(defer_registration, "defer system registration (for sampling)"), 760 INIT_PARAM(width, "cpu width"), 761 INIT_PARAM(function_trace, "Enable function trace"), 762 INIT_PARAM(function_trace_start, "Cycle to start function trace"), 763 INIT_PARAM(simulate_stalls, "Simulate cache stall cycles") 764 765END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 766 767 768CREATE_SIM_OBJECT(TimingSimpleCPU) 769{ 770 TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params(); 771 params->name = getInstanceName(); 772 params->numberOfThreads = 1; 773 params->max_insts_any_thread = max_insts_any_thread; 774 params->max_insts_all_threads = max_insts_all_threads; 775 params->max_loads_any_thread = max_loads_any_thread; 776 params->max_loads_all_threads = max_loads_all_threads; 777 params->progress_interval = progress_interval; 778 params->deferRegistration = defer_registration; 779 params->clock = clock; 780 params->phase = phase; 781 params->functionTrace = function_trace; 782 params->functionTraceStart = function_trace_start; 783 params->system = system; 784 params->cpu_id = cpu_id; 785 786#if FULL_SYSTEM 787 params->itb = itb; 788 params->dtb = dtb; 789 params->profile = profile; 790 params->do_quiesce = do_quiesce; 791 params->do_checkpoint_insts = do_checkpoint_insts; 792 params->do_statistics_insts = do_statistics_insts; 793#else 794 params->process = workload; 795#endif 796 797 TimingSimpleCPU *cpu = new TimingSimpleCPU(params); 798 return cpu; 799} 800 801REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU) 802 803