timing.cc revision 4200:f55b59fc848b
13938Ssaidi@eecs.umich.edu/* 212701Snikos.nikoleris@arm.com * Copyright (c) 2002-2005 The Regents of The University of Michigan 39419Sandreas.hansson@arm.com * All rights reserved. 49419Sandreas.hansson@arm.com * 59419Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without 69419Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are 79419Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright 89419Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer; 99419Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright 109419Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the 119419Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution; 129419Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its 139419Sandreas.hansson@arm.com * contributors may be used to endorse or promote products derived from 143938Ssaidi@eecs.umich.edu * this software without specific prior written permission. 153938Ssaidi@eecs.umich.edu * 163938Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 173938Ssaidi@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 183938Ssaidi@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 193938Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 203938Ssaidi@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 213938Ssaidi@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 223938Ssaidi@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 233938Ssaidi@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 243938Ssaidi@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 253938Ssaidi@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 263938Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 273938Ssaidi@eecs.umich.edu * 283938Ssaidi@eecs.umich.edu * Authors: Steve Reinhardt 293938Ssaidi@eecs.umich.edu */ 303938Ssaidi@eecs.umich.edu 313938Ssaidi@eecs.umich.edu#include "arch/locked_mem.hh" 323938Ssaidi@eecs.umich.edu#include "arch/utility.hh" 333938Ssaidi@eecs.umich.edu#include "base/bigint.hh" 343938Ssaidi@eecs.umich.edu#include "cpu/exetrace.hh" 353938Ssaidi@eecs.umich.edu#include "cpu/simple/timing.hh" 363938Ssaidi@eecs.umich.edu#include "mem/packet.hh" 373938Ssaidi@eecs.umich.edu#include "mem/packet_access.hh" 383938Ssaidi@eecs.umich.edu#include "sim/builder.hh" 393938Ssaidi@eecs.umich.edu#include "sim/system.hh" 403938Ssaidi@eecs.umich.edu 413938Ssaidi@eecs.umich.eduusing namespace std; 423938Ssaidi@eecs.umich.eduusing namespace TheISA; 433938Ssaidi@eecs.umich.edu 443938Ssaidi@eecs.umich.eduPort * 453938Ssaidi@eecs.umich.eduTimingSimpleCPU::getPort(const std::string &if_name, int idx) 4612225Sgiacomo.travaglini@arm.com{ 4712225Sgiacomo.travaglini@arm.com if (if_name == "dcache_port") 489419Sandreas.hansson@arm.com return &dcachePort; 493938Ssaidi@eecs.umich.edu else if (if_name == "icache_port") 5010291SAndreas.Sandberg@ARM.com return &icachePort; 5110291SAndreas.Sandberg@ARM.com else 5210291SAndreas.Sandberg@ARM.com panic("No Such Port\n"); 5310291SAndreas.Sandberg@ARM.com} 5410291SAndreas.Sandberg@ARM.com 5510291SAndreas.Sandberg@ARM.comvoid 5610686SAndreas.Sandberg@ARM.comTimingSimpleCPU::init() 5710686SAndreas.Sandberg@ARM.com{ 5812595Ssiddhesh.poyarekar@gmail.com BaseCPU::init(); 5912806Sandreas.sandberg@arm.com#if FULL_SYSTEM 6012806Sandreas.sandberg@arm.com for (int i = 0; i < threadContexts.size(); ++i) { 6110291SAndreas.Sandberg@ARM.com ThreadContext *tc = threadContexts[i]; 6210104Smitch.hayenga@arm.com 6310104Smitch.hayenga@arm.com // initialize CPU, including PC 6410291SAndreas.Sandberg@ARM.com TheISA::initCPU(tc, tc->readCpuId()); 6510104Smitch.hayenga@arm.com } 6610291SAndreas.Sandberg@ARM.com#endif 673938Ssaidi@eecs.umich.edu} 683938Ssaidi@eecs.umich.edu 6912392Sjason@lowepower.comTick 7012392Sjason@lowepower.comTimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) 7112392Sjason@lowepower.com{ 7212392Sjason@lowepower.com panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 7312392Sjason@lowepower.com return curTick; 7412392Sjason@lowepower.com} 7512392Sjason@lowepower.com 7612392Sjason@lowepower.comvoid 7712392Sjason@lowepower.comTimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) 7812701Snikos.nikoleris@arm.com{ 7912701Snikos.nikoleris@arm.com //No internal storage to update, jusst return 8012701Snikos.nikoleris@arm.com return; 8112701Snikos.nikoleris@arm.com} 8212701Snikos.nikoleris@arm.com 8312701Snikos.nikoleris@arm.comvoid 8412392Sjason@lowepower.comTimingSimpleCPU::CpuPort::recvStatusChange(Status status) 8512392Sjason@lowepower.com{ 8612392Sjason@lowepower.com if (status == RangeChange) { 8712701Snikos.nikoleris@arm.com if (!snoopRangeSent) { 8812701Snikos.nikoleris@arm.com snoopRangeSent = true; 8912392Sjason@lowepower.com sendStatusChange(Port::RangeChange); 9012392Sjason@lowepower.com } 9112225Sgiacomo.travaglini@arm.com return; 9212225Sgiacomo.travaglini@arm.com } 9312225Sgiacomo.travaglini@arm.com 9412225Sgiacomo.travaglini@arm.com panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); 9512859Sanimalvgamer@gmail.com} 9612225Sgiacomo.travaglini@arm.com 9712225Sgiacomo.travaglini@arm.com 9812225Sgiacomo.travaglini@arm.comvoid 9912225Sgiacomo.travaglini@arm.comTimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) 10012225Sgiacomo.travaglini@arm.com{ 10112225Sgiacomo.travaglini@arm.com pkt = _pkt; 10212225Sgiacomo.travaglini@arm.com Event::schedule(t); 10312225Sgiacomo.travaglini@arm.com} 10412225Sgiacomo.travaglini@arm.com 10512225Sgiacomo.travaglini@arm.comTimingSimpleCPU::TimingSimpleCPU(Params *p) 10612225Sgiacomo.travaglini@arm.com : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock), 10712225Sgiacomo.travaglini@arm.com cpu_id(p->cpu_id) 10812225Sgiacomo.travaglini@arm.com{ 10912225Sgiacomo.travaglini@arm.com _status = Idle; 11012225Sgiacomo.travaglini@arm.com 11112859Sanimalvgamer@gmail.com icachePort.snoopRangeSent = false; 11212225Sgiacomo.travaglini@arm.com dcachePort.snoopRangeSent = false; 11312225Sgiacomo.travaglini@arm.com 11412225Sgiacomo.travaglini@arm.com ifetch_pkt = dcache_pkt = NULL; 1153938Ssaidi@eecs.umich.edu 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, &icachePort, &dcachePort); 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 214 215void 216TimingSimpleCPU::activateContext(int thread_num, int delay) 217{ 218 assert(thread_num == 0); 219 assert(thread); 220 221 assert(_status == Idle); 222 223 notIdleFraction++; 224 _status = Running; 225 226 // kick things off by initiating the fetch of the next instruction 227 fetchEvent = 228 new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false); 229 fetchEvent->schedule(nextCycle(curTick + cycles(delay))); 230} 231 232 233void 234TimingSimpleCPU::suspendContext(int thread_num) 235{ 236 assert(thread_num == 0); 237 assert(thread); 238 239 assert(_status == Running); 240 241 // just change status to Idle... if status != Running, 242 // completeInst() will not initiate fetch of next instruction. 243 244 notIdleFraction--; 245 _status = Idle; 246} 247 248 249template <class T> 250Fault 251TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 252{ 253 Request *req = 254 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 255 cpu_id, /* thread ID */ 0); 256 257 if (traceData) { 258 traceData->setAddr(req->getVaddr()); 259 } 260 261 // translate to physical address 262 Fault fault = thread->translateDataReadReq(req); 263 264 // Now do the access. 265 if (fault == NoFault) { 266 PacketPtr pkt = 267 new Packet(req, MemCmd::ReadReq, Packet::Broadcast); 268 pkt->dataDynamic<T>(new T); 269 270 if (!dcachePort.sendTiming(pkt)) { 271 _status = DcacheRetry; 272 dcache_pkt = pkt; 273 } else { 274 _status = DcacheWaitResponse; 275 // memory system takes ownership of packet 276 dcache_pkt = NULL; 277 } 278 279 // This will need a new way to tell if it has a dcache attached. 280 if (req->isUncacheable()) 281 recordEvent("Uncached Read"); 282 } else { 283 delete req; 284 } 285 286 return fault; 287} 288 289#ifndef DOXYGEN_SHOULD_SKIP_THIS 290 291template 292Fault 293TimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags); 294 295template 296Fault 297TimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags); 298 299template 300Fault 301TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 302 303template 304Fault 305TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 306 307template 308Fault 309TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 310 311template 312Fault 313TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 314 315#endif //DOXYGEN_SHOULD_SKIP_THIS 316 317template<> 318Fault 319TimingSimpleCPU::read(Addr addr, double &data, unsigned flags) 320{ 321 return read(addr, *(uint64_t*)&data, flags); 322} 323 324template<> 325Fault 326TimingSimpleCPU::read(Addr addr, float &data, unsigned flags) 327{ 328 return read(addr, *(uint32_t*)&data, flags); 329} 330 331 332template<> 333Fault 334TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 335{ 336 return read(addr, (uint32_t&)data, flags); 337} 338 339 340template <class T> 341Fault 342TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 343{ 344 Request *req = 345 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 346 cpu_id, /* thread ID */ 0); 347 348 if (traceData) { 349 traceData->setAddr(req->getVaddr()); 350 } 351 352 // translate to physical address 353 Fault fault = thread->translateDataWriteReq(req); 354 355 // Now do the access. 356 if (fault == NoFault) { 357 assert(dcache_pkt == NULL); 358 if (req->isSwap()) 359 dcache_pkt = new Packet(req, MemCmd::SwapReq, Packet::Broadcast); 360 else 361 dcache_pkt = new Packet(req, MemCmd::WriteReq, Packet::Broadcast); 362 dcache_pkt->allocate(); 363 dcache_pkt->set(data); 364 365 bool do_access = true; // flag to suppress cache access 366 367 if (req->isLocked()) { 368 do_access = TheISA::handleLockedWrite(thread, req); 369 } 370 if (req->isCondSwap()) { 371 assert(res); 372 req->setExtraData(*res); 373 } 374 375 if (do_access) { 376 if (!dcachePort.sendTiming(dcache_pkt)) { 377 _status = DcacheRetry; 378 } else { 379 _status = DcacheWaitResponse; 380 // memory system takes ownership of packet 381 dcache_pkt = NULL; 382 } 383 } 384 // This will need a new way to tell if it's hooked up to a cache or not. 385 if (req->isUncacheable()) 386 recordEvent("Uncached Write"); 387 } else { 388 delete req; 389 } 390 391 392 // If the write needs to have a fault on the access, consider calling 393 // changeStatus() and changing it to "bad addr write" or something. 394 return fault; 395} 396 397 398#ifndef DOXYGEN_SHOULD_SKIP_THIS 399template 400Fault 401TimingSimpleCPU::write(uint64_t data, Addr addr, 402 unsigned flags, uint64_t *res); 403 404template 405Fault 406TimingSimpleCPU::write(uint32_t data, Addr addr, 407 unsigned flags, uint64_t *res); 408 409template 410Fault 411TimingSimpleCPU::write(uint16_t data, Addr addr, 412 unsigned flags, uint64_t *res); 413 414template 415Fault 416TimingSimpleCPU::write(uint8_t data, Addr addr, 417 unsigned flags, uint64_t *res); 418 419#endif //DOXYGEN_SHOULD_SKIP_THIS 420 421template<> 422Fault 423TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 424{ 425 return write(*(uint64_t*)&data, addr, flags, res); 426} 427 428template<> 429Fault 430TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 431{ 432 return write(*(uint32_t*)&data, addr, flags, res); 433} 434 435 436template<> 437Fault 438TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 439{ 440 return write((uint32_t)data, addr, flags, res); 441} 442 443 444void 445TimingSimpleCPU::fetch() 446{ 447 if (!curStaticInst || !curStaticInst->isDelayedCommit()) 448 checkForInterrupts(); 449 450 Request *ifetch_req = new Request(); 451 ifetch_req->setThreadContext(cpu_id, /* thread ID */ 0); 452 Fault fault = setupFetchRequest(ifetch_req); 453 454 ifetch_pkt = new Packet(ifetch_req, MemCmd::ReadReq, Packet::Broadcast); 455 ifetch_pkt->dataStatic(&inst); 456 457 if (fault == NoFault) { 458 if (!icachePort.sendTiming(ifetch_pkt)) { 459 // Need to wait for retry 460 _status = IcacheRetry; 461 } else { 462 // Need to wait for cache to respond 463 _status = IcacheWaitResponse; 464 // ownership of packet transferred to memory system 465 ifetch_pkt = NULL; 466 } 467 } else { 468 delete ifetch_req; 469 delete ifetch_pkt; 470 // fetch fault: advance directly to next instruction (fault handler) 471 advanceInst(fault); 472 } 473 474 numCycles += curTick - previousTick; 475 previousTick = curTick; 476} 477 478 479void 480TimingSimpleCPU::advanceInst(Fault fault) 481{ 482 advancePC(fault); 483 484 if (_status == Running) { 485 // kick off fetch of next instruction... callback from icache 486 // response will cause that instruction to be executed, 487 // keeping the CPU running. 488 fetch(); 489 } 490} 491 492 493void 494TimingSimpleCPU::completeIfetch(PacketPtr pkt) 495{ 496 // received a response from the icache: execute the received 497 // instruction 498 assert(pkt->result == Packet::Success); 499 assert(_status == IcacheWaitResponse); 500 501 _status = Running; 502 503 numCycles += curTick - previousTick; 504 previousTick = curTick; 505 506 if (getState() == SimObject::Draining) { 507 delete pkt->req; 508 delete pkt; 509 510 completeDrain(); 511 return; 512 } 513 514 preExecute(); 515 if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { 516 // load or store: just send to dcache 517 Fault fault = curStaticInst->initiateAcc(this, traceData); 518 if (_status != Running) { 519 // instruction will complete in dcache response callback 520 assert(_status == DcacheWaitResponse || _status == DcacheRetry); 521 assert(fault == NoFault); 522 } else { 523 if (fault == NoFault) { 524 // early fail on store conditional: complete now 525 assert(dcache_pkt != NULL); 526 fault = curStaticInst->completeAcc(dcache_pkt, this, 527 traceData); 528 delete dcache_pkt->req; 529 delete dcache_pkt; 530 dcache_pkt = NULL; 531 } 532 postExecute(); 533 advanceInst(fault); 534 } 535 } else { 536 // non-memory instruction: execute completely now 537 Fault fault = curStaticInst->execute(this, traceData); 538 postExecute(); 539 advanceInst(fault); 540 } 541 542 delete pkt->req; 543 delete pkt; 544} 545 546void 547TimingSimpleCPU::IcachePort::ITickEvent::process() 548{ 549 cpu->completeIfetch(pkt); 550} 551 552bool 553TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt) 554{ 555 if (pkt->isResponse()) { 556 // delay processing of returned data until next CPU clock edge 557 Tick mem_time = pkt->req->getTime(); 558 Tick next_tick = cpu->nextCycle(mem_time); 559 560 if (next_tick == curTick) 561 cpu->completeIfetch(pkt); 562 else 563 tickEvent.schedule(pkt, next_tick); 564 565 return true; 566 } 567 else { 568 //Snooping a Coherence Request, do nothing 569 return true; 570 } 571} 572 573void 574TimingSimpleCPU::IcachePort::recvRetry() 575{ 576 // we shouldn't get a retry unless we have a packet that we're 577 // waiting to transmit 578 assert(cpu->ifetch_pkt != NULL); 579 assert(cpu->_status == IcacheRetry); 580 PacketPtr tmp = cpu->ifetch_pkt; 581 if (sendTiming(tmp)) { 582 cpu->_status = IcacheWaitResponse; 583 cpu->ifetch_pkt = NULL; 584 } 585} 586 587void 588TimingSimpleCPU::completeDataAccess(PacketPtr pkt) 589{ 590 // received a response from the dcache: complete the load or store 591 // instruction 592 assert(pkt->result == Packet::Success); 593 assert(_status == DcacheWaitResponse); 594 _status = Running; 595 596 numCycles += curTick - previousTick; 597 previousTick = curTick; 598 599 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 600 601 if (pkt->isRead() && pkt->req->isLocked()) { 602 TheISA::handleLockedRead(thread, pkt->req); 603 } 604 605 delete pkt->req; 606 delete pkt; 607 608 postExecute(); 609 610 if (getState() == SimObject::Draining) { 611 advancePC(fault); 612 completeDrain(); 613 614 return; 615 } 616 617 advanceInst(fault); 618} 619 620 621void 622TimingSimpleCPU::completeDrain() 623{ 624 DPRINTF(Config, "Done draining\n"); 625 changeState(SimObject::Drained); 626 drainEvent->process(); 627} 628 629void 630TimingSimpleCPU::DcachePort::setPeer(Port *port) 631{ 632 Port::setPeer(port); 633 634#if FULL_SYSTEM 635 // Update the ThreadContext's memory ports (Functional/Virtual 636 // Ports) 637 cpu->tcBase()->connectMemPorts(); 638#endif 639} 640 641bool 642TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt) 643{ 644 if (pkt->isResponse()) { 645 // delay processing of returned data until next CPU clock edge 646 Tick mem_time = pkt->req->getTime(); 647 Tick next_tick = cpu->nextCycle(mem_time); 648 649 if (next_tick == curTick) 650 cpu->completeDataAccess(pkt); 651 else 652 tickEvent.schedule(pkt, next_tick); 653 654 return true; 655 } 656 else { 657 //Snooping a coherence req, do nothing 658 return true; 659 } 660} 661 662void 663TimingSimpleCPU::DcachePort::DTickEvent::process() 664{ 665 cpu->completeDataAccess(pkt); 666} 667 668void 669TimingSimpleCPU::DcachePort::recvRetry() 670{ 671 // we shouldn't get a retry unless we have a packet that we're 672 // waiting to transmit 673 assert(cpu->dcache_pkt != NULL); 674 assert(cpu->_status == DcacheRetry); 675 PacketPtr tmp = cpu->dcache_pkt; 676 if (sendTiming(tmp)) { 677 cpu->_status = DcacheWaitResponse; 678 // memory system takes ownership of packet 679 cpu->dcache_pkt = NULL; 680 } 681} 682 683 684//////////////////////////////////////////////////////////////////////// 685// 686// TimingSimpleCPU Simulation Object 687// 688BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 689 690 Param<Counter> max_insts_any_thread; 691 Param<Counter> max_insts_all_threads; 692 Param<Counter> max_loads_any_thread; 693 Param<Counter> max_loads_all_threads; 694 Param<Tick> progress_interval; 695 SimObjectParam<System *> system; 696 Param<int> cpu_id; 697 698#if FULL_SYSTEM 699 SimObjectParam<TheISA::ITB *> itb; 700 SimObjectParam<TheISA::DTB *> dtb; 701 Param<Tick> profile; 702 703 Param<bool> do_quiesce; 704 Param<bool> do_checkpoint_insts; 705 Param<bool> do_statistics_insts; 706#else 707 SimObjectParam<Process *> workload; 708#endif // FULL_SYSTEM 709 710 Param<int> clock; 711 Param<int> phase; 712 713 Param<bool> defer_registration; 714 Param<int> width; 715 Param<bool> function_trace; 716 Param<Tick> function_trace_start; 717 Param<bool> simulate_stalls; 718 719END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 720 721BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 722 723 INIT_PARAM(max_insts_any_thread, 724 "terminate when any thread reaches this inst count"), 725 INIT_PARAM(max_insts_all_threads, 726 "terminate when all threads have reached this inst count"), 727 INIT_PARAM(max_loads_any_thread, 728 "terminate when any thread reaches this load count"), 729 INIT_PARAM(max_loads_all_threads, 730 "terminate when all threads have reached this load count"), 731 INIT_PARAM(progress_interval, "Progress interval"), 732 INIT_PARAM(system, "system object"), 733 INIT_PARAM(cpu_id, "processor ID"), 734 735#if FULL_SYSTEM 736 INIT_PARAM(itb, "Instruction TLB"), 737 INIT_PARAM(dtb, "Data TLB"), 738 INIT_PARAM(profile, ""), 739 INIT_PARAM(do_quiesce, ""), 740 INIT_PARAM(do_checkpoint_insts, ""), 741 INIT_PARAM(do_statistics_insts, ""), 742#else 743 INIT_PARAM(workload, "processes to run"), 744#endif // FULL_SYSTEM 745 746 INIT_PARAM(clock, "clock speed"), 747 INIT_PARAM_DFLT(phase, "clock phase", 0), 748 INIT_PARAM(defer_registration, "defer system registration (for sampling)"), 749 INIT_PARAM(width, "cpu width"), 750 INIT_PARAM(function_trace, "Enable function trace"), 751 INIT_PARAM(function_trace_start, "Cycle to start function trace"), 752 INIT_PARAM(simulate_stalls, "Simulate cache stall cycles") 753 754END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 755 756 757CREATE_SIM_OBJECT(TimingSimpleCPU) 758{ 759 TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params(); 760 params->name = getInstanceName(); 761 params->numberOfThreads = 1; 762 params->max_insts_any_thread = max_insts_any_thread; 763 params->max_insts_all_threads = max_insts_all_threads; 764 params->max_loads_any_thread = max_loads_any_thread; 765 params->max_loads_all_threads = max_loads_all_threads; 766 params->progress_interval = progress_interval; 767 params->deferRegistration = defer_registration; 768 params->clock = clock; 769 params->phase = phase; 770 params->functionTrace = function_trace; 771 params->functionTraceStart = function_trace_start; 772 params->system = system; 773 params->cpu_id = cpu_id; 774 775#if FULL_SYSTEM 776 params->itb = itb; 777 params->dtb = dtb; 778 params->profile = profile; 779 params->do_quiesce = do_quiesce; 780 params->do_checkpoint_insts = do_checkpoint_insts; 781 params->do_statistics_insts = do_statistics_insts; 782#else 783 params->process = workload; 784#endif 785 786 TimingSimpleCPU *cpu = new TimingSimpleCPU(params); 787 return cpu; 788} 789 790REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU) 791 792