timing.cc revision 5496:6899b894166f
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/locked_mem.hh" 32#include "arch/mmaped_ipr.hh" 33#include "arch/utility.hh" 34#include "base/bigint.hh" 35#include "cpu/exetrace.hh" 36#include "cpu/simple/timing.hh" 37#include "mem/packet.hh" 38#include "mem/packet_access.hh" 39#include "params/TimingSimpleCPU.hh" 40#include "sim/system.hh" 41 42using namespace std; 43using namespace TheISA; 44 45Port * 46TimingSimpleCPU::getPort(const std::string &if_name, int idx) 47{ 48 if (if_name == "dcache_port") 49 return &dcachePort; 50 else if (if_name == "icache_port") 51 return &icachePort; 52 else 53 panic("No Such Port\n"); 54} 55 56void 57TimingSimpleCPU::init() 58{ 59 BaseCPU::init(); 60 cpuId = tc->readCpuId(); 61#if FULL_SYSTEM 62 for (int i = 0; i < threadContexts.size(); ++i) { 63 ThreadContext *tc = threadContexts[i]; 64 65 // initialize CPU, including PC 66 TheISA::initCPU(tc, cpuId); 67 } 68#endif 69} 70 71Tick 72TimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) 73{ 74 panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 75 return curTick; 76} 77 78void 79TimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) 80{ 81 //No internal storage to update, jusst return 82 return; 83} 84 85void 86TimingSimpleCPU::CpuPort::recvStatusChange(Status status) 87{ 88 if (status == RangeChange) { 89 if (!snoopRangeSent) { 90 snoopRangeSent = true; 91 sendStatusChange(Port::RangeChange); 92 } 93 return; 94 } 95 96 panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); 97} 98 99 100void 101TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) 102{ 103 pkt = _pkt; 104 Event::schedule(t); 105} 106 107TimingSimpleCPU::TimingSimpleCPU(Params *p) 108 : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock) 109{ 110 _status = Idle; 111 112 icachePort.snoopRangeSent = false; 113 dcachePort.snoopRangeSent = false; 114 115 ifetch_pkt = dcache_pkt = NULL; 116 drainEvent = NULL; 117 fetchEvent = NULL; 118 previousTick = 0; 119 changeState(SimObject::Running); 120} 121 122 123TimingSimpleCPU::~TimingSimpleCPU() 124{ 125} 126 127void 128TimingSimpleCPU::serialize(ostream &os) 129{ 130 SimObject::State so_state = SimObject::getState(); 131 SERIALIZE_ENUM(so_state); 132 BaseSimpleCPU::serialize(os); 133} 134 135void 136TimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 137{ 138 SimObject::State so_state; 139 UNSERIALIZE_ENUM(so_state); 140 BaseSimpleCPU::unserialize(cp, section); 141} 142 143unsigned int 144TimingSimpleCPU::drain(Event *drain_event) 145{ 146 // TimingSimpleCPU is ready to drain if it's not waiting for 147 // an access to complete. 148 if (_status == Idle || _status == Running || _status == SwitchedOut) { 149 changeState(SimObject::Drained); 150 return 0; 151 } else { 152 changeState(SimObject::Draining); 153 drainEvent = drain_event; 154 return 1; 155 } 156} 157 158void 159TimingSimpleCPU::resume() 160{ 161 DPRINTF(SimpleCPU, "Resume\n"); 162 if (_status != SwitchedOut && _status != Idle) { 163 assert(system->getMemoryMode() == Enums::timing); 164 165 // Delete the old event if it existed. 166 if (fetchEvent) { 167 if (fetchEvent->scheduled()) 168 fetchEvent->deschedule(); 169 170 delete fetchEvent; 171 } 172 173 fetchEvent = new FetchEvent(this, nextCycle()); 174 } 175 176 changeState(SimObject::Running); 177} 178 179void 180TimingSimpleCPU::switchOut() 181{ 182 assert(_status == Running || _status == Idle); 183 _status = SwitchedOut; 184 numCycles += tickToCycles(curTick - previousTick); 185 186 // If we've been scheduled to resume but are then told to switch out, 187 // we'll need to cancel it. 188 if (fetchEvent && fetchEvent->scheduled()) 189 fetchEvent->deschedule(); 190} 191 192 193void 194TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 195{ 196 BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort); 197 198 // if any of this CPU's ThreadContexts are active, mark the CPU as 199 // running and schedule its tick event. 200 for (int i = 0; i < threadContexts.size(); ++i) { 201 ThreadContext *tc = threadContexts[i]; 202 if (tc->status() == ThreadContext::Active && _status != Running) { 203 _status = Running; 204 break; 205 } 206 } 207 208 if (_status != Running) { 209 _status = Idle; 210 } 211 assert(threadContexts.size() == 1); 212 cpuId = tc->readCpuId(); 213 previousTick = curTick; 214} 215 216 217void 218TimingSimpleCPU::activateContext(int thread_num, int delay) 219{ 220 DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay); 221 222 assert(thread_num == 0); 223 assert(thread); 224 225 assert(_status == Idle); 226 227 notIdleFraction++; 228 _status = Running; 229 230 // kick things off by initiating the fetch of the next instruction 231 fetchEvent = new FetchEvent(this, nextCycle(curTick + ticks(delay))); 232} 233 234 235void 236TimingSimpleCPU::suspendContext(int thread_num) 237{ 238 DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num); 239 240 assert(thread_num == 0); 241 assert(thread); 242 243 assert(_status == Running); 244 245 // just change status to Idle... if status != Running, 246 // completeInst() will not initiate fetch of next instruction. 247 248 notIdleFraction--; 249 _status = Idle; 250} 251 252 253template <class T> 254Fault 255TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 256{ 257 Request *req = 258 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 259 cpuId, /* thread ID */ 0); 260 261 if (traceData) { 262 traceData->setAddr(req->getVaddr()); 263 } 264 265 // translate to physical address 266 Fault fault = thread->translateDataReadReq(req); 267 268 // Now do the access. 269 if (fault == NoFault) { 270 PacketPtr pkt = 271 new Packet(req, 272 (req->isLocked() ? 273 MemCmd::LoadLockedReq : MemCmd::ReadReq), 274 Packet::Broadcast); 275 pkt->dataDynamic<T>(new T); 276 277 if (req->isMmapedIpr()) { 278 Tick delay; 279 delay = TheISA::handleIprRead(thread->getTC(), pkt); 280 new IprEvent(pkt, this, nextCycle(curTick + delay)); 281 _status = DcacheWaitResponse; 282 dcache_pkt = NULL; 283 } else if (!dcachePort.sendTiming(pkt)) { 284 _status = DcacheRetry; 285 dcache_pkt = pkt; 286 } else { 287 _status = DcacheWaitResponse; 288 // memory system takes ownership of packet 289 dcache_pkt = NULL; 290 } 291 292 // This will need a new way to tell if it has a dcache attached. 293 if (req->isUncacheable()) 294 recordEvent("Uncached Read"); 295 } else { 296 delete req; 297 } 298 299 if (traceData) { 300 traceData->setData(data); 301 } 302 return fault; 303} 304 305Fault 306TimingSimpleCPU::translateDataReadAddr(Addr vaddr, Addr &paddr, 307 int size, unsigned flags) 308{ 309 Request *req = 310 new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0); 311 312 if (traceData) { 313 traceData->setAddr(vaddr); 314 } 315 316 Fault fault = thread->translateDataWriteReq(req); 317 318 if (fault == NoFault) 319 paddr = req->getPaddr(); 320 321 delete req; 322 return fault; 323} 324 325#ifndef DOXYGEN_SHOULD_SKIP_THIS 326 327template 328Fault 329TimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags); 330 331template 332Fault 333TimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags); 334 335template 336Fault 337TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 338 339template 340Fault 341TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 342 343template 344Fault 345TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 346 347template 348Fault 349TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 350 351#endif //DOXYGEN_SHOULD_SKIP_THIS 352 353template<> 354Fault 355TimingSimpleCPU::read(Addr addr, double &data, unsigned flags) 356{ 357 return read(addr, *(uint64_t*)&data, flags); 358} 359 360template<> 361Fault 362TimingSimpleCPU::read(Addr addr, float &data, unsigned flags) 363{ 364 return read(addr, *(uint32_t*)&data, flags); 365} 366 367 368template<> 369Fault 370TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 371{ 372 return read(addr, (uint32_t&)data, flags); 373} 374 375 376template <class T> 377Fault 378TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 379{ 380 Request *req = 381 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 382 cpuId, /* thread ID */ 0); 383 384 if (traceData) { 385 traceData->setAddr(req->getVaddr()); 386 } 387 388 // translate to physical address 389 Fault fault = thread->translateDataWriteReq(req); 390 391 // Now do the access. 392 if (fault == NoFault) { 393 MemCmd cmd = MemCmd::WriteReq; // default 394 bool do_access = true; // flag to suppress cache access 395 396 if (req->isLocked()) { 397 cmd = MemCmd::StoreCondReq; 398 do_access = TheISA::handleLockedWrite(thread, req); 399 } else if (req->isSwap()) { 400 cmd = MemCmd::SwapReq; 401 if (req->isCondSwap()) { 402 assert(res); 403 req->setExtraData(*res); 404 } 405 } 406 407 // Note: need to allocate dcache_pkt even if do_access is 408 // false, as it's used unconditionally to call completeAcc(). 409 assert(dcache_pkt == NULL); 410 dcache_pkt = new Packet(req, cmd, Packet::Broadcast); 411 dcache_pkt->allocate(); 412 dcache_pkt->set(data); 413 414 if (do_access) { 415 if (req->isMmapedIpr()) { 416 Tick delay; 417 dcache_pkt->set(htog(data)); 418 delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); 419 new IprEvent(dcache_pkt, this, nextCycle(curTick + delay)); 420 _status = DcacheWaitResponse; 421 dcache_pkt = NULL; 422 } else if (!dcachePort.sendTiming(dcache_pkt)) { 423 _status = DcacheRetry; 424 } else { 425 _status = DcacheWaitResponse; 426 // memory system takes ownership of packet 427 dcache_pkt = NULL; 428 } 429 } 430 // This will need a new way to tell if it's hooked up to a cache or not. 431 if (req->isUncacheable()) 432 recordEvent("Uncached Write"); 433 } else { 434 delete req; 435 } 436 437 if (traceData) { 438 traceData->setData(data); 439 } 440 441 // If the write needs to have a fault on the access, consider calling 442 // changeStatus() and changing it to "bad addr write" or something. 443 return fault; 444} 445 446Fault 447TimingSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr, 448 int size, unsigned flags) 449{ 450 Request *req = 451 new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0); 452 453 if (traceData) { 454 traceData->setAddr(vaddr); 455 } 456 457 Fault fault = thread->translateDataWriteReq(req); 458 459 if (fault == NoFault) 460 paddr = req->getPaddr(); 461 462 delete req; 463 return fault; 464} 465 466 467#ifndef DOXYGEN_SHOULD_SKIP_THIS 468template 469Fault 470TimingSimpleCPU::write(Twin32_t data, Addr addr, 471 unsigned flags, uint64_t *res); 472 473template 474Fault 475TimingSimpleCPU::write(Twin64_t data, Addr addr, 476 unsigned flags, uint64_t *res); 477 478template 479Fault 480TimingSimpleCPU::write(uint64_t data, Addr addr, 481 unsigned flags, uint64_t *res); 482 483template 484Fault 485TimingSimpleCPU::write(uint32_t data, Addr addr, 486 unsigned flags, uint64_t *res); 487 488template 489Fault 490TimingSimpleCPU::write(uint16_t data, Addr addr, 491 unsigned flags, uint64_t *res); 492 493template 494Fault 495TimingSimpleCPU::write(uint8_t data, Addr addr, 496 unsigned flags, uint64_t *res); 497 498#endif //DOXYGEN_SHOULD_SKIP_THIS 499 500template<> 501Fault 502TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 503{ 504 return write(*(uint64_t*)&data, addr, flags, res); 505} 506 507template<> 508Fault 509TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 510{ 511 return write(*(uint32_t*)&data, addr, flags, res); 512} 513 514 515template<> 516Fault 517TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 518{ 519 return write((uint32_t)data, addr, flags, res); 520} 521 522 523void 524TimingSimpleCPU::fetch() 525{ 526 DPRINTF(SimpleCPU, "Fetch\n"); 527 528 if (!curStaticInst || !curStaticInst->isDelayedCommit()) 529 checkForInterrupts(); 530 531 checkPcEventQueue(); 532 533 Request *ifetch_req = new Request(); 534 ifetch_req->setThreadContext(cpuId, /* thread ID */ 0); 535 Fault fault = setupFetchRequest(ifetch_req); 536 537 ifetch_pkt = new Packet(ifetch_req, MemCmd::ReadReq, Packet::Broadcast); 538 ifetch_pkt->dataStatic(&inst); 539 540 if (fault == NoFault) { 541 if (!icachePort.sendTiming(ifetch_pkt)) { 542 // Need to wait for retry 543 _status = IcacheRetry; 544 } else { 545 // Need to wait for cache to respond 546 _status = IcacheWaitResponse; 547 // ownership of packet transferred to memory system 548 ifetch_pkt = NULL; 549 } 550 } else { 551 delete ifetch_req; 552 delete ifetch_pkt; 553 // fetch fault: advance directly to next instruction (fault handler) 554 advanceInst(fault); 555 } 556 557 numCycles += tickToCycles(curTick - previousTick); 558 previousTick = curTick; 559} 560 561 562void 563TimingSimpleCPU::advanceInst(Fault fault) 564{ 565 advancePC(fault); 566 567 if (_status == Running) { 568 // kick off fetch of next instruction... callback from icache 569 // response will cause that instruction to be executed, 570 // keeping the CPU running. 571 fetch(); 572 } 573} 574 575 576void 577TimingSimpleCPU::completeIfetch(PacketPtr pkt) 578{ 579 DPRINTF(SimpleCPU, "Complete ICache Fetch\n"); 580 581 // received a response from the icache: execute the received 582 // instruction 583 assert(!pkt->isError()); 584 assert(_status == IcacheWaitResponse); 585 586 _status = Running; 587 588 numCycles += tickToCycles(curTick - previousTick); 589 previousTick = curTick; 590 591 if (getState() == SimObject::Draining) { 592 delete pkt->req; 593 delete pkt; 594 595 completeDrain(); 596 return; 597 } 598 599 preExecute(); 600 if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { 601 // load or store: just send to dcache 602 Fault fault = curStaticInst->initiateAcc(this, traceData); 603 if (_status != Running) { 604 // instruction will complete in dcache response callback 605 assert(_status == DcacheWaitResponse || _status == DcacheRetry); 606 assert(fault == NoFault); 607 } else { 608 if (fault == NoFault) { 609 // Note that ARM can have NULL packets if the instruction gets 610 // squashed due to predication 611 // early fail on store conditional: complete now 612 assert(dcache_pkt != NULL || THE_ISA == ARM_ISA); 613 614 fault = curStaticInst->completeAcc(dcache_pkt, this, 615 traceData); 616 if (dcache_pkt != NULL) 617 { 618 delete dcache_pkt->req; 619 delete dcache_pkt; 620 dcache_pkt = NULL; 621 } 622 623 // keep an instruction count 624 if (fault == NoFault) 625 countInst(); 626 } else if (traceData) { 627 // If there was a fault, we shouldn't trace this instruction. 628 delete traceData; 629 traceData = NULL; 630 } 631 632 postExecute(); 633 // @todo remove me after debugging with legion done 634 if (curStaticInst && (!curStaticInst->isMicroop() || 635 curStaticInst->isFirstMicroop())) 636 instCnt++; 637 advanceInst(fault); 638 } 639 } else { 640 // non-memory instruction: execute completely now 641 Fault fault = curStaticInst->execute(this, traceData); 642 643 // keep an instruction count 644 if (fault == NoFault) 645 countInst(); 646 else if (traceData) { 647 // If there was a fault, we shouldn't trace this instruction. 648 delete traceData; 649 traceData = NULL; 650 } 651 652 postExecute(); 653 // @todo remove me after debugging with legion done 654 if (curStaticInst && (!curStaticInst->isMicroop() || 655 curStaticInst->isFirstMicroop())) 656 instCnt++; 657 advanceInst(fault); 658 } 659 660 delete pkt->req; 661 delete pkt; 662} 663 664void 665TimingSimpleCPU::IcachePort::ITickEvent::process() 666{ 667 cpu->completeIfetch(pkt); 668} 669 670bool 671TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt) 672{ 673 if (pkt->isResponse() && !pkt->wasNacked()) { 674 // delay processing of returned data until next CPU clock edge 675 Tick next_tick = cpu->nextCycle(curTick); 676 677 if (next_tick == curTick) 678 cpu->completeIfetch(pkt); 679 else 680 tickEvent.schedule(pkt, next_tick); 681 682 return true; 683 } 684 else if (pkt->wasNacked()) { 685 assert(cpu->_status == IcacheWaitResponse); 686 pkt->reinitNacked(); 687 if (!sendTiming(pkt)) { 688 cpu->_status = IcacheRetry; 689 cpu->ifetch_pkt = pkt; 690 } 691 } 692 //Snooping a Coherence Request, do nothing 693 return true; 694} 695 696void 697TimingSimpleCPU::IcachePort::recvRetry() 698{ 699 // we shouldn't get a retry unless we have a packet that we're 700 // waiting to transmit 701 assert(cpu->ifetch_pkt != NULL); 702 assert(cpu->_status == IcacheRetry); 703 PacketPtr tmp = cpu->ifetch_pkt; 704 if (sendTiming(tmp)) { 705 cpu->_status = IcacheWaitResponse; 706 cpu->ifetch_pkt = NULL; 707 } 708} 709 710void 711TimingSimpleCPU::completeDataAccess(PacketPtr pkt) 712{ 713 // received a response from the dcache: complete the load or store 714 // instruction 715 assert(!pkt->isError()); 716 assert(_status == DcacheWaitResponse); 717 _status = Running; 718 719 numCycles += tickToCycles(curTick - previousTick); 720 previousTick = curTick; 721 722 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 723 724 // keep an instruction count 725 if (fault == NoFault) 726 countInst(); 727 else if (traceData) { 728 // If there was a fault, we shouldn't trace this instruction. 729 delete traceData; 730 traceData = NULL; 731 } 732 733 if (pkt->isRead() && pkt->isLocked()) { 734 TheISA::handleLockedRead(thread, pkt->req); 735 } 736 737 delete pkt->req; 738 delete pkt; 739 740 postExecute(); 741 742 if (getState() == SimObject::Draining) { 743 advancePC(fault); 744 completeDrain(); 745 746 return; 747 } 748 749 advanceInst(fault); 750} 751 752 753void 754TimingSimpleCPU::completeDrain() 755{ 756 DPRINTF(Config, "Done draining\n"); 757 changeState(SimObject::Drained); 758 drainEvent->process(); 759} 760 761void 762TimingSimpleCPU::DcachePort::setPeer(Port *port) 763{ 764 Port::setPeer(port); 765 766#if FULL_SYSTEM 767 // Update the ThreadContext's memory ports (Functional/Virtual 768 // Ports) 769 cpu->tcBase()->connectMemPorts(); 770#endif 771} 772 773bool 774TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt) 775{ 776 if (pkt->isResponse() && !pkt->wasNacked()) { 777 // delay processing of returned data until next CPU clock edge 778 Tick next_tick = cpu->nextCycle(curTick); 779 780 if (next_tick == curTick) 781 cpu->completeDataAccess(pkt); 782 else 783 tickEvent.schedule(pkt, next_tick); 784 785 return true; 786 } 787 else if (pkt->wasNacked()) { 788 assert(cpu->_status == DcacheWaitResponse); 789 pkt->reinitNacked(); 790 if (!sendTiming(pkt)) { 791 cpu->_status = DcacheRetry; 792 cpu->dcache_pkt = pkt; 793 } 794 } 795 //Snooping a Coherence Request, do nothing 796 return true; 797} 798 799void 800TimingSimpleCPU::DcachePort::DTickEvent::process() 801{ 802 cpu->completeDataAccess(pkt); 803} 804 805void 806TimingSimpleCPU::DcachePort::recvRetry() 807{ 808 // we shouldn't get a retry unless we have a packet that we're 809 // waiting to transmit 810 assert(cpu->dcache_pkt != NULL); 811 assert(cpu->_status == DcacheRetry); 812 PacketPtr tmp = cpu->dcache_pkt; 813 if (sendTiming(tmp)) { 814 cpu->_status = DcacheWaitResponse; 815 // memory system takes ownership of packet 816 cpu->dcache_pkt = NULL; 817 } 818} 819 820TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, Tick t) 821 : Event(&mainEventQueue), pkt(_pkt), cpu(_cpu) 822{ 823 schedule(t); 824} 825 826void 827TimingSimpleCPU::IprEvent::process() 828{ 829 cpu->completeDataAccess(pkt); 830} 831 832const char * 833TimingSimpleCPU::IprEvent::description() const 834{ 835 return "Timing Simple CPU Delay IPR event"; 836} 837 838 839void 840TimingSimpleCPU::printAddr(Addr a) 841{ 842 dcachePort.printAddr(a); 843} 844 845 846//////////////////////////////////////////////////////////////////////// 847// 848// TimingSimpleCPU Simulation Object 849// 850TimingSimpleCPU * 851TimingSimpleCPUParams::create() 852{ 853 TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params(); 854 params->name = name; 855 params->numberOfThreads = 1; 856 params->max_insts_any_thread = max_insts_any_thread; 857 params->max_insts_all_threads = max_insts_all_threads; 858 params->max_loads_any_thread = max_loads_any_thread; 859 params->max_loads_all_threads = max_loads_all_threads; 860 params->progress_interval = progress_interval; 861 params->deferRegistration = defer_registration; 862 params->clock = clock; 863 params->phase = phase; 864 params->functionTrace = function_trace; 865 params->functionTraceStart = function_trace_start; 866 params->system = system; 867 params->cpu_id = cpu_id; 868 params->tracer = tracer; 869 870 params->itb = itb; 871 params->dtb = dtb; 872#if FULL_SYSTEM 873 params->profile = profile; 874 params->do_quiesce = do_quiesce; 875 params->do_checkpoint_insts = do_checkpoint_insts; 876 params->do_statistics_insts = do_statistics_insts; 877#else 878 if (workload.size() != 1) 879 panic("only one workload allowed"); 880 params->process = workload[0]; 881#endif 882 883 TimingSimpleCPU *cpu = new TimingSimpleCPU(params); 884 return cpu; 885} 886