timing.cc revision 7720
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 "config/the_isa.hh" 36#include "cpu/exetrace.hh" 37#include "cpu/simple/timing.hh" 38#include "mem/packet.hh" 39#include "mem/packet_access.hh" 40#include "params/TimingSimpleCPU.hh" 41#include "sim/faults.hh" 42#include "sim/system.hh" 43 44using namespace std; 45using namespace TheISA; 46 47Port * 48TimingSimpleCPU::getPort(const std::string &if_name, int idx) 49{ 50 if (if_name == "dcache_port") 51 return &dcachePort; 52 else if (if_name == "icache_port") 53 return &icachePort; 54 else 55 panic("No Such Port\n"); 56} 57 58void 59TimingSimpleCPU::init() 60{ 61 BaseCPU::init(); 62#if FULL_SYSTEM 63 for (int i = 0; i < threadContexts.size(); ++i) { 64 ThreadContext *tc = threadContexts[i]; 65 66 // initialize CPU, including PC 67 TheISA::initCPU(tc, _cpuId); 68 } 69#endif 70} 71 72Tick 73TimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) 74{ 75 panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 76 return curTick; 77} 78 79void 80TimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) 81{ 82 //No internal storage to update, jusst return 83 return; 84} 85 86void 87TimingSimpleCPU::CpuPort::recvStatusChange(Status status) 88{ 89 if (status == RangeChange) { 90 if (!snoopRangeSent) { 91 snoopRangeSent = true; 92 sendStatusChange(Port::RangeChange); 93 } 94 return; 95 } 96 97 panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); 98} 99 100 101void 102TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) 103{ 104 pkt = _pkt; 105 cpu->schedule(this, t); 106} 107 108TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) 109 : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this, p->clock), 110 dcachePort(this, p->clock), fetchEvent(this) 111{ 112 _status = Idle; 113 114 icachePort.snoopRangeSent = false; 115 dcachePort.snoopRangeSent = false; 116 117 ifetch_pkt = dcache_pkt = NULL; 118 drainEvent = NULL; 119 previousTick = 0; 120 changeState(SimObject::Running); 121} 122 123 124TimingSimpleCPU::~TimingSimpleCPU() 125{ 126} 127 128void 129TimingSimpleCPU::serialize(ostream &os) 130{ 131 SimObject::State so_state = SimObject::getState(); 132 SERIALIZE_ENUM(so_state); 133 BaseSimpleCPU::serialize(os); 134} 135 136void 137TimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 138{ 139 SimObject::State so_state; 140 UNSERIALIZE_ENUM(so_state); 141 BaseSimpleCPU::unserialize(cp, section); 142} 143 144unsigned int 145TimingSimpleCPU::drain(Event *drain_event) 146{ 147 // TimingSimpleCPU is ready to drain if it's not waiting for 148 // an access to complete. 149 if (_status == Idle || _status == Running || _status == SwitchedOut) { 150 changeState(SimObject::Drained); 151 return 0; 152 } else { 153 changeState(SimObject::Draining); 154 drainEvent = drain_event; 155 return 1; 156 } 157} 158 159void 160TimingSimpleCPU::resume() 161{ 162 DPRINTF(SimpleCPU, "Resume\n"); 163 if (_status != SwitchedOut && _status != Idle) { 164 assert(system->getMemoryMode() == Enums::timing); 165 166 if (fetchEvent.scheduled()) 167 deschedule(fetchEvent); 168 169 schedule(fetchEvent, nextCycle()); 170 } 171 172 changeState(SimObject::Running); 173} 174 175void 176TimingSimpleCPU::switchOut() 177{ 178 assert(_status == Running || _status == Idle); 179 _status = SwitchedOut; 180 numCycles += tickToCycles(curTick - previousTick); 181 182 // If we've been scheduled to resume but are then told to switch out, 183 // we'll need to cancel it. 184 if (fetchEvent.scheduled()) 185 deschedule(fetchEvent); 186} 187 188 189void 190TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 191{ 192 BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort); 193 194 // if any of this CPU's ThreadContexts are active, mark the CPU as 195 // running and schedule its tick event. 196 for (int i = 0; i < threadContexts.size(); ++i) { 197 ThreadContext *tc = threadContexts[i]; 198 if (tc->status() == ThreadContext::Active && _status != Running) { 199 _status = Running; 200 break; 201 } 202 } 203 204 if (_status != Running) { 205 _status = Idle; 206 } 207 assert(threadContexts.size() == 1); 208 previousTick = curTick; 209} 210 211 212void 213TimingSimpleCPU::activateContext(int thread_num, int delay) 214{ 215 DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay); 216 217 assert(thread_num == 0); 218 assert(thread); 219 220 assert(_status == Idle); 221 222 notIdleFraction++; 223 _status = Running; 224 225 // kick things off by initiating the fetch of the next instruction 226 schedule(fetchEvent, nextCycle(curTick + ticks(delay))); 227} 228 229 230void 231TimingSimpleCPU::suspendContext(int thread_num) 232{ 233 DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num); 234 235 assert(thread_num == 0); 236 assert(thread); 237 238 if (_status == Idle) 239 return; 240 241 assert(_status == Running); 242 243 // just change status to Idle... if status != Running, 244 // completeInst() will not initiate fetch of next instruction. 245 246 notIdleFraction--; 247 _status = Idle; 248} 249 250bool 251TimingSimpleCPU::handleReadPacket(PacketPtr pkt) 252{ 253 RequestPtr req = pkt->req; 254 if (req->isMmapedIpr()) { 255 Tick delay; 256 delay = TheISA::handleIprRead(thread->getTC(), pkt); 257 new IprEvent(pkt, this, nextCycle(curTick + delay)); 258 _status = DcacheWaitResponse; 259 dcache_pkt = NULL; 260 } else if (!dcachePort.sendTiming(pkt)) { 261 _status = DcacheRetry; 262 dcache_pkt = pkt; 263 } else { 264 _status = DcacheWaitResponse; 265 // memory system takes ownership of packet 266 dcache_pkt = NULL; 267 } 268 return dcache_pkt == NULL; 269} 270 271void 272TimingSimpleCPU::sendData(RequestPtr req, uint8_t *data, uint64_t *res, 273 bool read) 274{ 275 PacketPtr pkt; 276 buildPacket(pkt, req, read); 277 pkt->dataDynamicArray<uint8_t>(data); 278 if (req->getFlags().isSet(Request::NO_ACCESS)) { 279 assert(!dcache_pkt); 280 pkt->makeResponse(); 281 completeDataAccess(pkt); 282 } else if (read) { 283 handleReadPacket(pkt); 284 } else { 285 bool do_access = true; // flag to suppress cache access 286 287 if (req->isLLSC()) { 288 do_access = TheISA::handleLockedWrite(thread, req); 289 } else if (req->isCondSwap()) { 290 assert(res); 291 req->setExtraData(*res); 292 } 293 294 if (do_access) { 295 dcache_pkt = pkt; 296 handleWritePacket(); 297 } else { 298 _status = DcacheWaitResponse; 299 completeDataAccess(pkt); 300 } 301 } 302} 303 304void 305TimingSimpleCPU::sendSplitData(RequestPtr req1, RequestPtr req2, 306 RequestPtr req, uint8_t *data, bool read) 307{ 308 PacketPtr pkt1, pkt2; 309 buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read); 310 if (req->getFlags().isSet(Request::NO_ACCESS)) { 311 assert(!dcache_pkt); 312 pkt1->makeResponse(); 313 completeDataAccess(pkt1); 314 } else if (read) { 315 if (handleReadPacket(pkt1)) { 316 SplitFragmentSenderState * send_state = 317 dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 318 send_state->clearFromParent(); 319 if (handleReadPacket(pkt2)) { 320 send_state = dynamic_cast<SplitFragmentSenderState *>( 321 pkt1->senderState); 322 send_state->clearFromParent(); 323 } 324 } 325 } else { 326 dcache_pkt = pkt1; 327 if (handleWritePacket()) { 328 SplitFragmentSenderState * send_state = 329 dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 330 send_state->clearFromParent(); 331 dcache_pkt = pkt2; 332 if (handleWritePacket()) { 333 send_state = dynamic_cast<SplitFragmentSenderState *>( 334 pkt1->senderState); 335 send_state->clearFromParent(); 336 } 337 } 338 } 339} 340 341void 342TimingSimpleCPU::translationFault(Fault fault) 343{ 344 // fault may be NoFault in cases where a fault is suppressed, 345 // for instance prefetches. 346 numCycles += tickToCycles(curTick - previousTick); 347 previousTick = curTick; 348 349 if (traceData) { 350 // Since there was a fault, we shouldn't trace this instruction. 351 delete traceData; 352 traceData = NULL; 353 } 354 355 postExecute(); 356 357 if (getState() == SimObject::Draining) { 358 advancePC(fault); 359 completeDrain(); 360 } else { 361 advanceInst(fault); 362 } 363} 364 365void 366TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr req, bool read) 367{ 368 MemCmd cmd; 369 if (read) { 370 cmd = MemCmd::ReadReq; 371 if (req->isLLSC()) 372 cmd = MemCmd::LoadLockedReq; 373 } else { 374 cmd = MemCmd::WriteReq; 375 if (req->isLLSC()) { 376 cmd = MemCmd::StoreCondReq; 377 } else if (req->isSwap()) { 378 cmd = MemCmd::SwapReq; 379 } 380 } 381 pkt = new Packet(req, cmd, Packet::Broadcast); 382} 383 384void 385TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, 386 RequestPtr req1, RequestPtr req2, RequestPtr req, 387 uint8_t *data, bool read) 388{ 389 pkt1 = pkt2 = NULL; 390 391 assert(!req1->isMmapedIpr() && !req2->isMmapedIpr()); 392 393 if (req->getFlags().isSet(Request::NO_ACCESS)) { 394 buildPacket(pkt1, req, read); 395 return; 396 } 397 398 buildPacket(pkt1, req1, read); 399 buildPacket(pkt2, req2, read); 400 401 req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags()); 402 PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(), 403 Packet::Broadcast); 404 405 pkt->dataDynamicArray<uint8_t>(data); 406 pkt1->dataStatic<uint8_t>(data); 407 pkt2->dataStatic<uint8_t>(data + req1->getSize()); 408 409 SplitMainSenderState * main_send_state = new SplitMainSenderState; 410 pkt->senderState = main_send_state; 411 main_send_state->fragments[0] = pkt1; 412 main_send_state->fragments[1] = pkt2; 413 main_send_state->outstanding = 2; 414 pkt1->senderState = new SplitFragmentSenderState(pkt, 0); 415 pkt2->senderState = new SplitFragmentSenderState(pkt, 1); 416} 417 418Fault 419TimingSimpleCPU::readBytes(Addr addr, uint8_t *data, 420 unsigned size, unsigned flags) 421{ 422 Fault fault; 423 const int asid = 0; 424 const ThreadID tid = 0; 425 const Addr pc = thread->instAddr(); 426 unsigned block_size = dcachePort.peerBlockSize(); 427 BaseTLB::Mode mode = BaseTLB::Read; 428 429 if (traceData) { 430 traceData->setAddr(addr); 431 } 432 433 RequestPtr req = new Request(asid, addr, size, 434 flags, pc, _cpuId, tid); 435 436 Addr split_addr = roundDown(addr + size - 1, block_size); 437 assert(split_addr <= addr || split_addr - addr < block_size); 438 439 _status = DTBWaitResponse; 440 if (split_addr > addr) { 441 RequestPtr req1, req2; 442 assert(!req->isLLSC() && !req->isSwap()); 443 req->splitOnVaddr(split_addr, req1, req2); 444 445 WholeTranslationState *state = 446 new WholeTranslationState(req, req1, req2, new uint8_t[size], 447 NULL, mode); 448 DataTranslation<TimingSimpleCPU> *trans1 = 449 new DataTranslation<TimingSimpleCPU>(this, state, 0); 450 DataTranslation<TimingSimpleCPU> *trans2 = 451 new DataTranslation<TimingSimpleCPU>(this, state, 1); 452 453 thread->dtb->translateTiming(req1, tc, trans1, mode); 454 thread->dtb->translateTiming(req2, tc, trans2, mode); 455 } else { 456 WholeTranslationState *state = 457 new WholeTranslationState(req, new uint8_t[size], NULL, mode); 458 DataTranslation<TimingSimpleCPU> *translation 459 = new DataTranslation<TimingSimpleCPU>(this, state); 460 thread->dtb->translateTiming(req, tc, translation, mode); 461 } 462 463 return NoFault; 464} 465 466template <class T> 467Fault 468TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 469{ 470 return readBytes(addr, (uint8_t *)&data, sizeof(T), flags); 471} 472 473#ifndef DOXYGEN_SHOULD_SKIP_THIS 474 475template 476Fault 477TimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags); 478 479template 480Fault 481TimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags); 482 483template 484Fault 485TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 486 487template 488Fault 489TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 490 491template 492Fault 493TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 494 495template 496Fault 497TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 498 499#endif //DOXYGEN_SHOULD_SKIP_THIS 500 501template<> 502Fault 503TimingSimpleCPU::read(Addr addr, double &data, unsigned flags) 504{ 505 return read(addr, *(uint64_t*)&data, flags); 506} 507 508template<> 509Fault 510TimingSimpleCPU::read(Addr addr, float &data, unsigned flags) 511{ 512 return read(addr, *(uint32_t*)&data, flags); 513} 514 515template<> 516Fault 517TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 518{ 519 return read(addr, (uint32_t&)data, flags); 520} 521 522bool 523TimingSimpleCPU::handleWritePacket() 524{ 525 RequestPtr req = dcache_pkt->req; 526 if (req->isMmapedIpr()) { 527 Tick delay; 528 delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); 529 new IprEvent(dcache_pkt, this, nextCycle(curTick + delay)); 530 _status = DcacheWaitResponse; 531 dcache_pkt = NULL; 532 } else if (!dcachePort.sendTiming(dcache_pkt)) { 533 _status = DcacheRetry; 534 } else { 535 _status = DcacheWaitResponse; 536 // memory system takes ownership of packet 537 dcache_pkt = NULL; 538 } 539 return dcache_pkt == NULL; 540} 541 542Fault 543TimingSimpleCPU::writeTheseBytes(uint8_t *data, unsigned size, 544 Addr addr, unsigned flags, uint64_t *res) 545{ 546 const int asid = 0; 547 const ThreadID tid = 0; 548 const Addr pc = thread->instAddr(); 549 unsigned block_size = dcachePort.peerBlockSize(); 550 BaseTLB::Mode mode = BaseTLB::Write; 551 552 if (traceData) { 553 traceData->setAddr(addr); 554 } 555 556 RequestPtr req = new Request(asid, addr, size, 557 flags, pc, _cpuId, tid); 558 559 Addr split_addr = roundDown(addr + size - 1, block_size); 560 assert(split_addr <= addr || split_addr - addr < block_size); 561 562 _status = DTBWaitResponse; 563 if (split_addr > addr) { 564 RequestPtr req1, req2; 565 assert(!req->isLLSC() && !req->isSwap()); 566 req->splitOnVaddr(split_addr, req1, req2); 567 568 WholeTranslationState *state = 569 new WholeTranslationState(req, req1, req2, data, res, mode); 570 DataTranslation<TimingSimpleCPU> *trans1 = 571 new DataTranslation<TimingSimpleCPU>(this, state, 0); 572 DataTranslation<TimingSimpleCPU> *trans2 = 573 new DataTranslation<TimingSimpleCPU>(this, state, 1); 574 575 thread->dtb->translateTiming(req1, tc, trans1, mode); 576 thread->dtb->translateTiming(req2, tc, trans2, mode); 577 } else { 578 WholeTranslationState *state = 579 new WholeTranslationState(req, data, res, mode); 580 DataTranslation<TimingSimpleCPU> *translation = 581 new DataTranslation<TimingSimpleCPU>(this, state); 582 thread->dtb->translateTiming(req, tc, translation, mode); 583 } 584 585 // Translation faults will be returned via finishTranslation() 586 return NoFault; 587} 588 589Fault 590TimingSimpleCPU::writeBytes(uint8_t *data, unsigned size, 591 Addr addr, unsigned flags, uint64_t *res) 592{ 593 uint8_t *newData = new uint8_t[size]; 594 memcpy(newData, data, size); 595 return writeTheseBytes(newData, size, addr, flags, res); 596} 597 598template <class T> 599Fault 600TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 601{ 602 if (traceData) { 603 traceData->setData(data); 604 } 605 T *dataP = (T*) new uint8_t[sizeof(T)]; 606 *dataP = TheISA::htog(data); 607 608 return writeTheseBytes((uint8_t *)dataP, sizeof(T), addr, flags, res); 609} 610 611 612#ifndef DOXYGEN_SHOULD_SKIP_THIS 613template 614Fault 615TimingSimpleCPU::write(Twin32_t data, Addr addr, 616 unsigned flags, uint64_t *res); 617 618template 619Fault 620TimingSimpleCPU::write(Twin64_t data, Addr addr, 621 unsigned flags, uint64_t *res); 622 623template 624Fault 625TimingSimpleCPU::write(uint64_t data, Addr addr, 626 unsigned flags, uint64_t *res); 627 628template 629Fault 630TimingSimpleCPU::write(uint32_t data, Addr addr, 631 unsigned flags, uint64_t *res); 632 633template 634Fault 635TimingSimpleCPU::write(uint16_t data, Addr addr, 636 unsigned flags, uint64_t *res); 637 638template 639Fault 640TimingSimpleCPU::write(uint8_t data, Addr addr, 641 unsigned flags, uint64_t *res); 642 643#endif //DOXYGEN_SHOULD_SKIP_THIS 644 645template<> 646Fault 647TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 648{ 649 return write(*(uint64_t*)&data, addr, flags, res); 650} 651 652template<> 653Fault 654TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 655{ 656 return write(*(uint32_t*)&data, addr, flags, res); 657} 658 659 660template<> 661Fault 662TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 663{ 664 return write((uint32_t)data, addr, flags, res); 665} 666 667 668void 669TimingSimpleCPU::finishTranslation(WholeTranslationState *state) 670{ 671 _status = Running; 672 673 if (state->getFault() != NoFault) { 674 if (state->isPrefetch()) { 675 state->setNoFault(); 676 } 677 delete [] state->data; 678 state->deleteReqs(); 679 translationFault(state->getFault()); 680 } else { 681 if (!state->isSplit) { 682 sendData(state->mainReq, state->data, state->res, 683 state->mode == BaseTLB::Read); 684 } else { 685 sendSplitData(state->sreqLow, state->sreqHigh, state->mainReq, 686 state->data, state->mode == BaseTLB::Read); 687 } 688 } 689 690 delete state; 691} 692 693 694void 695TimingSimpleCPU::fetch() 696{ 697 DPRINTF(SimpleCPU, "Fetch\n"); 698 699 if (!curStaticInst || !curStaticInst->isDelayedCommit()) 700 checkForInterrupts(); 701 702 checkPcEventQueue(); 703 704 TheISA::PCState pcState = thread->pcState(); 705 bool needToFetch = !isRomMicroPC(pcState.microPC()) && !curMacroStaticInst; 706 707 if (needToFetch) { 708 Request *ifetch_req = new Request(); 709 ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0); 710 setupFetchRequest(ifetch_req); 711 thread->itb->translateTiming(ifetch_req, tc, &fetchTranslation, 712 BaseTLB::Execute); 713 } else { 714 _status = IcacheWaitResponse; 715 completeIfetch(NULL); 716 717 numCycles += tickToCycles(curTick - previousTick); 718 previousTick = curTick; 719 } 720} 721 722 723void 724TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc) 725{ 726 if (fault == NoFault) { 727 ifetch_pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast); 728 ifetch_pkt->dataStatic(&inst); 729 730 if (!icachePort.sendTiming(ifetch_pkt)) { 731 // Need to wait for retry 732 _status = IcacheRetry; 733 } else { 734 // Need to wait for cache to respond 735 _status = IcacheWaitResponse; 736 // ownership of packet transferred to memory system 737 ifetch_pkt = NULL; 738 } 739 } else { 740 delete req; 741 // fetch fault: advance directly to next instruction (fault handler) 742 advanceInst(fault); 743 } 744 745 numCycles += tickToCycles(curTick - previousTick); 746 previousTick = curTick; 747} 748 749 750void 751TimingSimpleCPU::advanceInst(Fault fault) 752{ 753 if (fault != NoFault || !stayAtPC) 754 advancePC(fault); 755 756 if (_status == Running) { 757 // kick off fetch of next instruction... callback from icache 758 // response will cause that instruction to be executed, 759 // keeping the CPU running. 760 fetch(); 761 } 762} 763 764 765void 766TimingSimpleCPU::completeIfetch(PacketPtr pkt) 767{ 768 DPRINTF(SimpleCPU, "Complete ICache Fetch\n"); 769 770 // received a response from the icache: execute the received 771 // instruction 772 773 assert(!pkt || !pkt->isError()); 774 assert(_status == IcacheWaitResponse); 775 776 _status = Running; 777 778 numCycles += tickToCycles(curTick - previousTick); 779 previousTick = curTick; 780 781 if (getState() == SimObject::Draining) { 782 if (pkt) { 783 delete pkt->req; 784 delete pkt; 785 } 786 787 completeDrain(); 788 return; 789 } 790 791 preExecute(); 792 if (curStaticInst && 793 curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { 794 // load or store: just send to dcache 795 Fault fault = curStaticInst->initiateAcc(this, traceData); 796 if (_status != Running) { 797 // instruction will complete in dcache response callback 798 assert(_status == DcacheWaitResponse || 799 _status == DcacheRetry || DTBWaitResponse); 800 assert(fault == NoFault); 801 } else { 802 if (fault != NoFault && traceData) { 803 // If there was a fault, we shouldn't trace this instruction. 804 delete traceData; 805 traceData = NULL; 806 } 807 808 postExecute(); 809 // @todo remove me after debugging with legion done 810 if (curStaticInst && (!curStaticInst->isMicroop() || 811 curStaticInst->isFirstMicroop())) 812 instCnt++; 813 advanceInst(fault); 814 } 815 } else if (curStaticInst) { 816 // non-memory instruction: execute completely now 817 Fault fault = curStaticInst->execute(this, traceData); 818 819 // keep an instruction count 820 if (fault == NoFault) 821 countInst(); 822 else if (traceData && !DTRACE(ExecFaulting)) { 823 delete traceData; 824 traceData = NULL; 825 } 826 827 postExecute(); 828 // @todo remove me after debugging with legion done 829 if (curStaticInst && (!curStaticInst->isMicroop() || 830 curStaticInst->isFirstMicroop())) 831 instCnt++; 832 advanceInst(fault); 833 } else { 834 advanceInst(NoFault); 835 } 836 837 if (pkt) { 838 delete pkt->req; 839 delete pkt; 840 } 841} 842 843void 844TimingSimpleCPU::IcachePort::ITickEvent::process() 845{ 846 cpu->completeIfetch(pkt); 847} 848 849bool 850TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt) 851{ 852 if (pkt->isResponse() && !pkt->wasNacked()) { 853 // delay processing of returned data until next CPU clock edge 854 Tick next_tick = cpu->nextCycle(curTick); 855 856 if (next_tick == curTick) 857 cpu->completeIfetch(pkt); 858 else 859 tickEvent.schedule(pkt, next_tick); 860 861 return true; 862 } 863 else if (pkt->wasNacked()) { 864 assert(cpu->_status == IcacheWaitResponse); 865 pkt->reinitNacked(); 866 if (!sendTiming(pkt)) { 867 cpu->_status = IcacheRetry; 868 cpu->ifetch_pkt = pkt; 869 } 870 } 871 //Snooping a Coherence Request, do nothing 872 return true; 873} 874 875void 876TimingSimpleCPU::IcachePort::recvRetry() 877{ 878 // we shouldn't get a retry unless we have a packet that we're 879 // waiting to transmit 880 assert(cpu->ifetch_pkt != NULL); 881 assert(cpu->_status == IcacheRetry); 882 PacketPtr tmp = cpu->ifetch_pkt; 883 if (sendTiming(tmp)) { 884 cpu->_status = IcacheWaitResponse; 885 cpu->ifetch_pkt = NULL; 886 } 887} 888 889void 890TimingSimpleCPU::completeDataAccess(PacketPtr pkt) 891{ 892 // received a response from the dcache: complete the load or store 893 // instruction 894 assert(!pkt->isError()); 895 assert(_status == DcacheWaitResponse || _status == DTBWaitResponse || 896 pkt->req->getFlags().isSet(Request::NO_ACCESS)); 897 898 numCycles += tickToCycles(curTick - previousTick); 899 previousTick = curTick; 900 901 if (pkt->senderState) { 902 SplitFragmentSenderState * send_state = 903 dynamic_cast<SplitFragmentSenderState *>(pkt->senderState); 904 assert(send_state); 905 delete pkt->req; 906 delete pkt; 907 PacketPtr big_pkt = send_state->bigPkt; 908 delete send_state; 909 910 SplitMainSenderState * main_send_state = 911 dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); 912 assert(main_send_state); 913 // Record the fact that this packet is no longer outstanding. 914 assert(main_send_state->outstanding != 0); 915 main_send_state->outstanding--; 916 917 if (main_send_state->outstanding) { 918 return; 919 } else { 920 delete main_send_state; 921 big_pkt->senderState = NULL; 922 pkt = big_pkt; 923 } 924 } 925 926 _status = Running; 927 928 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 929 930 // keep an instruction count 931 if (fault == NoFault) 932 countInst(); 933 else if (traceData) { 934 // If there was a fault, we shouldn't trace this instruction. 935 delete traceData; 936 traceData = NULL; 937 } 938 939 // the locked flag may be cleared on the response packet, so check 940 // pkt->req and not pkt to see if it was a load-locked 941 if (pkt->isRead() && pkt->req->isLLSC()) { 942 TheISA::handleLockedRead(thread, pkt->req); 943 } 944 945 delete pkt->req; 946 delete pkt; 947 948 postExecute(); 949 950 if (getState() == SimObject::Draining) { 951 advancePC(fault); 952 completeDrain(); 953 954 return; 955 } 956 957 advanceInst(fault); 958} 959 960 961void 962TimingSimpleCPU::completeDrain() 963{ 964 DPRINTF(Config, "Done draining\n"); 965 changeState(SimObject::Drained); 966 drainEvent->process(); 967} 968 969void 970TimingSimpleCPU::DcachePort::setPeer(Port *port) 971{ 972 Port::setPeer(port); 973 974#if FULL_SYSTEM 975 // Update the ThreadContext's memory ports (Functional/Virtual 976 // Ports) 977 cpu->tcBase()->connectMemPorts(cpu->tcBase()); 978#endif 979} 980 981bool 982TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt) 983{ 984 if (pkt->isResponse() && !pkt->wasNacked()) { 985 // delay processing of returned data until next CPU clock edge 986 Tick next_tick = cpu->nextCycle(curTick); 987 988 if (next_tick == curTick) { 989 cpu->completeDataAccess(pkt); 990 } else { 991 tickEvent.schedule(pkt, next_tick); 992 } 993 994 return true; 995 } 996 else if (pkt->wasNacked()) { 997 assert(cpu->_status == DcacheWaitResponse); 998 pkt->reinitNacked(); 999 if (!sendTiming(pkt)) { 1000 cpu->_status = DcacheRetry; 1001 cpu->dcache_pkt = pkt; 1002 } 1003 } 1004 //Snooping a Coherence Request, do nothing 1005 return true; 1006} 1007 1008void 1009TimingSimpleCPU::DcachePort::DTickEvent::process() 1010{ 1011 cpu->completeDataAccess(pkt); 1012} 1013 1014void 1015TimingSimpleCPU::DcachePort::recvRetry() 1016{ 1017 // we shouldn't get a retry unless we have a packet that we're 1018 // waiting to transmit 1019 assert(cpu->dcache_pkt != NULL); 1020 assert(cpu->_status == DcacheRetry); 1021 PacketPtr tmp = cpu->dcache_pkt; 1022 if (tmp->senderState) { 1023 // This is a packet from a split access. 1024 SplitFragmentSenderState * send_state = 1025 dynamic_cast<SplitFragmentSenderState *>(tmp->senderState); 1026 assert(send_state); 1027 PacketPtr big_pkt = send_state->bigPkt; 1028 1029 SplitMainSenderState * main_send_state = 1030 dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); 1031 assert(main_send_state); 1032 1033 if (sendTiming(tmp)) { 1034 // If we were able to send without retrying, record that fact 1035 // and try sending the other fragment. 1036 send_state->clearFromParent(); 1037 int other_index = main_send_state->getPendingFragment(); 1038 if (other_index > 0) { 1039 tmp = main_send_state->fragments[other_index]; 1040 cpu->dcache_pkt = tmp; 1041 if ((big_pkt->isRead() && cpu->handleReadPacket(tmp)) || 1042 (big_pkt->isWrite() && cpu->handleWritePacket())) { 1043 main_send_state->fragments[other_index] = NULL; 1044 } 1045 } else { 1046 cpu->_status = DcacheWaitResponse; 1047 // memory system takes ownership of packet 1048 cpu->dcache_pkt = NULL; 1049 } 1050 } 1051 } else if (sendTiming(tmp)) { 1052 cpu->_status = DcacheWaitResponse; 1053 // memory system takes ownership of packet 1054 cpu->dcache_pkt = NULL; 1055 } 1056} 1057 1058TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, 1059 Tick t) 1060 : pkt(_pkt), cpu(_cpu) 1061{ 1062 cpu->schedule(this, t); 1063} 1064 1065void 1066TimingSimpleCPU::IprEvent::process() 1067{ 1068 cpu->completeDataAccess(pkt); 1069} 1070 1071const char * 1072TimingSimpleCPU::IprEvent::description() const 1073{ 1074 return "Timing Simple CPU Delay IPR event"; 1075} 1076 1077 1078void 1079TimingSimpleCPU::printAddr(Addr a) 1080{ 1081 dcachePort.printAddr(a); 1082} 1083 1084 1085//////////////////////////////////////////////////////////////////////// 1086// 1087// TimingSimpleCPU Simulation Object 1088// 1089TimingSimpleCPU * 1090TimingSimpleCPUParams::create() 1091{ 1092 numThreads = 1; 1093#if !FULL_SYSTEM 1094 if (workload.size() != 1) 1095 panic("only one workload allowed"); 1096#endif 1097 return new TimingSimpleCPU(this); 1098} 1099