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