timing.cc revision 5710
12SN/A/* 21762SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 32SN/A * All rights reserved. 42SN/A * 52SN/A * Redistribution and use in source and binary forms, with or without 62SN/A * modification, are permitted provided that the following conditions are 72SN/A * met: redistributions of source code must retain the above copyright 82SN/A * notice, this list of conditions and the following disclaimer; 92SN/A * redistributions in binary form must reproduce the above copyright 102SN/A * notice, this list of conditions and the following disclaimer in the 112SN/A * documentation and/or other materials provided with the distribution; 122SN/A * neither the name of the copyright holders nor the names of its 132SN/A * contributors may be used to endorse or promote products derived from 142SN/A * this software without specific prior written permission. 152SN/A * 162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu * 282760Sbinkertn@umich.edu * Authors: Steve Reinhardt 292760Sbinkertn@umich.edu */ 302665Ssaidi@eecs.umich.edu 312SN/A#include "arch/locked_mem.hh" 322SN/A#include "arch/mmaped_ipr.hh" 332SN/A#include "arch/utility.hh" 342SN/A#include "base/bigint.hh" 352SN/A#include "cpu/exetrace.hh" 362SN/A#include "cpu/simple/timing.hh" 372SN/A#include "mem/packet.hh" 382SN/A#include "mem/packet_access.hh" 392SN/A#include "params/TimingSimpleCPU.hh" 402SN/A#include "sim/system.hh" 418229Snate@binkert.org 422SN/Ausing namespace std; 438229Snate@binkert.orgusing namespace TheISA; 444841Ssaidi@eecs.umich.edu 452SN/APort * 466214Snate@binkert.orgTimingSimpleCPU::getPort(const std::string &if_name, int idx) 472SN/A{ 482738Sstever@eecs.umich.edu if (if_name == "dcache_port") 49395SN/A return &dcachePort; 50237SN/A else if (if_name == "icache_port") 514000Ssaidi@eecs.umich.edu return &icachePort; 522SN/A else 53217SN/A panic("No Such Port\n"); 54502SN/A} 55217SN/A 56217SN/Avoid 57237SN/ATimingSimpleCPU::init() 58502SN/A{ 59217SN/A BaseCPU::init(); 60217SN/A cpuId = tc->readCpuId(); 616820SLisa.Hsu@amd.com#if FULL_SYSTEM 626820SLisa.Hsu@amd.com for (int i = 0; i < threadContexts.size(); ++i) { 636820SLisa.Hsu@amd.com ThreadContext *tc = threadContexts[i]; 646820SLisa.Hsu@amd.com 65217SN/A // initialize CPU, including PC 666227Snate@binkert.org TheISA::initCPU(tc, cpuId); 67217SN/A } 68217SN/A#endif 694841Ssaidi@eecs.umich.edu} 704841Ssaidi@eecs.umich.edu 714841Ssaidi@eecs.umich.eduTick 724841Ssaidi@eecs.umich.eduTimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) 737948SAli.Saidi@ARM.com{ 747948SAli.Saidi@ARM.com panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 757948SAli.Saidi@ARM.com return curTick; 767948SAli.Saidi@ARM.com} 77237SN/A 786227Snate@binkert.orgvoid 79217SN/ATimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) 804841Ssaidi@eecs.umich.edu{ 814841Ssaidi@eecs.umich.edu //No internal storage to update, jusst return 824841Ssaidi@eecs.umich.edu return; 834841Ssaidi@eecs.umich.edu} 847948SAli.Saidi@ARM.com 857948SAli.Saidi@ARM.comvoid 867948SAli.Saidi@ARM.comTimingSimpleCPU::CpuPort::recvStatusChange(Status status) 877948SAli.Saidi@ARM.com{ 88237SN/A if (status == RangeChange) { 89237SN/A if (!snoopRangeSent) { 904000Ssaidi@eecs.umich.edu snoopRangeSent = true; 91237SN/A sendStatusChange(Port::RangeChange); 928902Sandreas.hansson@arm.com } 938902Sandreas.hansson@arm.com return; 948902Sandreas.hansson@arm.com } 958902Sandreas.hansson@arm.com 968902Sandreas.hansson@arm.com panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); 978902Sandreas.hansson@arm.com} 988902Sandreas.hansson@arm.com 998902Sandreas.hansson@arm.com 1008902Sandreas.hansson@arm.comvoid 1018902Sandreas.hansson@arm.comTimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) 1028902Sandreas.hansson@arm.com{ 103237SN/A pkt = _pkt; 104217SN/A cpu->schedule(this, t); 105217SN/A} 106217SN/A 107237SN/ATimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) 1085543Ssaidi@eecs.umich.edu : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock), fetchEvent(this) 109217SN/A{ 1105543Ssaidi@eecs.umich.edu _status = Idle; 1116820SLisa.Hsu@amd.com 112217SN/A icachePort.snoopRangeSent = false; 113223SN/A dcachePort.snoopRangeSent = false; 1145543Ssaidi@eecs.umich.edu 115223SN/A ifetch_pkt = dcache_pkt = NULL; 1165543Ssaidi@eecs.umich.edu drainEvent = NULL; 1175543Ssaidi@eecs.umich.edu previousTick = 0; 1185543Ssaidi@eecs.umich.edu changeState(SimObject::Running); 1195543Ssaidi@eecs.umich.edu} 1208902Sandreas.hansson@arm.com 121223SN/A 122223SN/ATimingSimpleCPU::~TimingSimpleCPU() 1235543Ssaidi@eecs.umich.edu{ 124217SN/A} 125217SN/A 1265543Ssaidi@eecs.umich.eduvoid 127237SN/ATimingSimpleCPU::serialize(ostream &os) 128237SN/A{ 1295543Ssaidi@eecs.umich.edu SimObject::State so_state = SimObject::getState(); 130237SN/A SERIALIZE_ENUM(so_state); 1315543Ssaidi@eecs.umich.edu BaseSimpleCPU::serialize(os); 1325543Ssaidi@eecs.umich.edu} 1335543Ssaidi@eecs.umich.edu 1345543Ssaidi@eecs.umich.eduvoid 1358902Sandreas.hansson@arm.comTimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 136237SN/A{ 137217SN/A SimObject::State so_state; 1382SN/A UNSERIALIZE_ENUM(so_state); 1392SN/A BaseSimpleCPU::unserialize(cp, section); 1402SN/A} 141395SN/A 1422SN/Aunsigned int 1432SN/ATimingSimpleCPU::drain(Event *drain_event) 144510SN/A{ 145510SN/A // TimingSimpleCPU is ready to drain if it's not waiting for 1462SN/A // an access to complete. 1472SN/A if (_status == Idle || _status == Running || _status == SwitchedOut) { 1485739Snate@binkert.org changeState(SimObject::Drained); 1495739Snate@binkert.org return 0; 1502SN/A } else { 151265SN/A changeState(SimObject::Draining); 152512SN/A drainEvent = drain_event; 1532SN/A return 1; 1545739Snate@binkert.org } 1555739Snate@binkert.org} 156237SN/A 1575739Snate@binkert.orgvoid 1582SN/ATimingSimpleCPU::resume() 1592287SN/A{ 1602287SN/A DPRINTF(SimpleCPU, "Resume\n"); 1612287SN/A if (_status != SwitchedOut && _status != Idle) { 1622868Sktlim@umich.edu assert(system->getMemoryMode() == Enums::timing); 163395SN/A 1642SN/A if (fetchEvent.scheduled()) 1652SN/A deschedule(fetchEvent); 1662SN/A 167395SN/A schedule(fetchEvent, nextCycle()); 168395SN/A } 1692SN/A 1702SN/A changeState(SimObject::Running); 1712SN/A} 172395SN/A 1732SN/Avoid 174395SN/ATimingSimpleCPU::switchOut() 1752SN/A{ 1762SN/A assert(_status == Running || _status == Idle); 177395SN/A _status = SwitchedOut; 1782SN/A numCycles += tickToCycles(curTick - previousTick); 179395SN/A 1802SN/A // If we've been scheduled to resume but are then told to switch out, 1812SN/A // we'll need to cancel it. 1822SN/A if (fetchEvent.scheduled()) 183395SN/A deschedule(fetchEvent); 1842SN/A} 185395SN/A 1862SN/A 187395SN/Avoid 1882SN/ATimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 1892SN/A{ 190395SN/A BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort); 191395SN/A 1922SN/A // if any of this CPU's ThreadContexts are active, mark the CPU as 1932SN/A // running and schedule its tick event. 1942SN/A for (int i = 0; i < threadContexts.size(); ++i) { 195395SN/A ThreadContext *tc = threadContexts[i]; 196395SN/A if (tc->status() == ThreadContext::Active && _status != Running) { 1972SN/A _status = Running; 1982SN/A break; 1992SN/A } 2002SN/A } 2012SN/A 2022SN/A if (_status != Running) { 203395SN/A _status = Idle; 2042SN/A } 2052SN/A assert(threadContexts.size() == 1); 2062SN/A cpuId = tc->readCpuId(); 2072SN/A previousTick = curTick; 2082SN/A} 2092SN/A 2102SN/A 2112SN/Avoid 212395SN/ATimingSimpleCPU::activateContext(int thread_num, int delay) 213395SN/A{ 2142738Sstever@eecs.umich.edu DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay); 2152SN/A 2162SN/A assert(thread_num == 0); 2172SN/A assert(thread); 2182SN/A 2192SN/A assert(_status == Idle); 220395SN/A 221395SN/A notIdleFraction++; 2222SN/A _status = Running; 223395SN/A 2242SN/A // kick things off by initiating the fetch of the next instruction 225395SN/A schedule(fetchEvent, nextCycle(curTick + ticks(delay))); 2262SN/A} 227395SN/A 2282738Sstever@eecs.umich.edu 2292SN/Avoid 2302SN/ATimingSimpleCPU::suspendContext(int thread_num) 2312SN/A{ 2322SN/A DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num); 233395SN/A 2342SN/A assert(thread_num == 0); 2352SN/A assert(thread); 2365543Ssaidi@eecs.umich.edu 2375543Ssaidi@eecs.umich.edu assert(_status == Running); 238237SN/A 2392SN/A // just change status to Idle... if status != Running, 240237SN/A // completeInst() will not initiate fetch of next instruction. 241237SN/A 242237SN/A notIdleFraction--; 243237SN/A _status = Idle; 244237SN/A} 245237SN/A 246237SN/A 2477491Ssteve.reinhardt@amd.comtemplate <class T> 248237SN/AFault 249937SN/ATimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 250937SN/A{ 251237SN/A Request *req = 252237SN/A new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 253237SN/A cpuId, /* thread ID */ 0); 254237SN/A 2554000Ssaidi@eecs.umich.edu if (traceData) { 256304SN/A traceData->setAddr(req->getVaddr()); 257304SN/A } 258449SN/A 259449SN/A // translate to physical address 260449SN/A Fault fault = thread->translateDataReadReq(req); 2617491Ssteve.reinhardt@amd.com 2627491Ssteve.reinhardt@amd.com // Now do the access. 2637491Ssteve.reinhardt@amd.com if (fault == NoFault) { 2647491Ssteve.reinhardt@amd.com PacketPtr pkt = 2657491Ssteve.reinhardt@amd.com new Packet(req, 2667491Ssteve.reinhardt@amd.com (req->isLocked() ? 2677491Ssteve.reinhardt@amd.com MemCmd::LoadLockedReq : MemCmd::ReadReq), 2687491Ssteve.reinhardt@amd.com Packet::Broadcast); 2697491Ssteve.reinhardt@amd.com pkt->dataDynamic<T>(new T); 2707491Ssteve.reinhardt@amd.com 2717491Ssteve.reinhardt@amd.com if (req->isMmapedIpr()) { 2727823Ssteve.reinhardt@amd.com Tick delay; 2737491Ssteve.reinhardt@amd.com delay = TheISA::handleIprRead(thread->getTC(), pkt); 2747491Ssteve.reinhardt@amd.com new IprEvent(pkt, this, nextCycle(curTick + delay)); 275449SN/A _status = DcacheWaitResponse; 276449SN/A dcache_pkt = NULL; 277449SN/A } else if (!dcachePort.sendTiming(pkt)) { 278449SN/A _status = DcacheRetry; 279449SN/A dcache_pkt = pkt; 280449SN/A } else { 281449SN/A _status = DcacheWaitResponse; 282449SN/A // memory system takes ownership of packet 283449SN/A dcache_pkt = NULL; 284237SN/A } 2852SN/A 2862SN/A // This will need a new way to tell if it has a dcache attached. 287 if (req->isUncacheable()) 288 recordEvent("Uncached Read"); 289 } else { 290 delete req; 291 } 292 293 if (traceData) { 294 traceData->setData(data); 295 } 296 return fault; 297} 298 299Fault 300TimingSimpleCPU::translateDataReadAddr(Addr vaddr, Addr &paddr, 301 int size, unsigned flags) 302{ 303 Request *req = 304 new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0); 305 306 if (traceData) { 307 traceData->setAddr(vaddr); 308 } 309 310 Fault fault = thread->translateDataWriteReq(req); 311 312 if (fault == NoFault) 313 paddr = req->getPaddr(); 314 315 delete req; 316 return fault; 317} 318 319#ifndef DOXYGEN_SHOULD_SKIP_THIS 320 321template 322Fault 323TimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags); 324 325template 326Fault 327TimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags); 328 329template 330Fault 331TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 332 333template 334Fault 335TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 336 337template 338Fault 339TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 340 341template 342Fault 343TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 344 345#endif //DOXYGEN_SHOULD_SKIP_THIS 346 347template<> 348Fault 349TimingSimpleCPU::read(Addr addr, double &data, unsigned flags) 350{ 351 return read(addr, *(uint64_t*)&data, flags); 352} 353 354template<> 355Fault 356TimingSimpleCPU::read(Addr addr, float &data, unsigned flags) 357{ 358 return read(addr, *(uint32_t*)&data, flags); 359} 360 361 362template<> 363Fault 364TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 365{ 366 return read(addr, (uint32_t&)data, flags); 367} 368 369 370template <class T> 371Fault 372TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 373{ 374 Request *req = 375 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 376 cpuId, /* thread ID */ 0); 377 378 if (traceData) { 379 traceData->setAddr(req->getVaddr()); 380 } 381 382 // translate to physical address 383 Fault fault = thread->translateDataWriteReq(req); 384 385 // Now do the access. 386 if (fault == NoFault) { 387 MemCmd cmd = MemCmd::WriteReq; // default 388 bool do_access = true; // flag to suppress cache access 389 390 if (req->isLocked()) { 391 cmd = MemCmd::StoreCondReq; 392 do_access = TheISA::handleLockedWrite(thread, req); 393 } else if (req->isSwap()) { 394 cmd = MemCmd::SwapReq; 395 if (req->isCondSwap()) { 396 assert(res); 397 req->setExtraData(*res); 398 } 399 } 400 401 // Note: need to allocate dcache_pkt even if do_access is 402 // false, as it's used unconditionally to call completeAcc(). 403 assert(dcache_pkt == NULL); 404 dcache_pkt = new Packet(req, cmd, Packet::Broadcast); 405 dcache_pkt->allocate(); 406 dcache_pkt->set(data); 407 408 if (do_access) { 409 if (req->isMmapedIpr()) { 410 Tick delay; 411 dcache_pkt->set(htog(data)); 412 delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); 413 new IprEvent(dcache_pkt, this, nextCycle(curTick + delay)); 414 _status = DcacheWaitResponse; 415 dcache_pkt = NULL; 416 } else if (!dcachePort.sendTiming(dcache_pkt)) { 417 _status = DcacheRetry; 418 } else { 419 _status = DcacheWaitResponse; 420 // memory system takes ownership of packet 421 dcache_pkt = NULL; 422 } 423 } 424 // This will need a new way to tell if it's hooked up to a cache or not. 425 if (req->isUncacheable()) 426 recordEvent("Uncached Write"); 427 } else { 428 delete req; 429 } 430 431 if (traceData) { 432 traceData->setData(data); 433 } 434 435 // If the write needs to have a fault on the access, consider calling 436 // changeStatus() and changing it to "bad addr write" or something. 437 return fault; 438} 439 440Fault 441TimingSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr, 442 int size, unsigned flags) 443{ 444 Request *req = 445 new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0); 446 447 if (traceData) { 448 traceData->setAddr(vaddr); 449 } 450 451 Fault fault = thread->translateDataWriteReq(req); 452 453 if (fault == NoFault) 454 paddr = req->getPaddr(); 455 456 delete req; 457 return fault; 458} 459 460 461#ifndef DOXYGEN_SHOULD_SKIP_THIS 462template 463Fault 464TimingSimpleCPU::write(Twin32_t data, Addr addr, 465 unsigned flags, uint64_t *res); 466 467template 468Fault 469TimingSimpleCPU::write(Twin64_t data, Addr addr, 470 unsigned flags, uint64_t *res); 471 472template 473Fault 474TimingSimpleCPU::write(uint64_t data, Addr addr, 475 unsigned flags, uint64_t *res); 476 477template 478Fault 479TimingSimpleCPU::write(uint32_t data, Addr addr, 480 unsigned flags, uint64_t *res); 481 482template 483Fault 484TimingSimpleCPU::write(uint16_t data, Addr addr, 485 unsigned flags, uint64_t *res); 486 487template 488Fault 489TimingSimpleCPU::write(uint8_t data, Addr addr, 490 unsigned flags, uint64_t *res); 491 492#endif //DOXYGEN_SHOULD_SKIP_THIS 493 494template<> 495Fault 496TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 497{ 498 return write(*(uint64_t*)&data, addr, flags, res); 499} 500 501template<> 502Fault 503TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 504{ 505 return write(*(uint32_t*)&data, addr, flags, res); 506} 507 508 509template<> 510Fault 511TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 512{ 513 return write((uint32_t)data, addr, flags, res); 514} 515 516 517void 518TimingSimpleCPU::fetch() 519{ 520 DPRINTF(SimpleCPU, "Fetch\n"); 521 522 if (!curStaticInst || !curStaticInst->isDelayedCommit()) 523 checkForInterrupts(); 524 525 checkPcEventQueue(); 526 527 bool fromRom = isRomMicroPC(thread->readMicroPC()); 528 529 if (!fromRom) { 530 Request *ifetch_req = new Request(); 531 ifetch_req->setThreadContext(cpuId, /* thread ID */ 0); 532 Fault fault = setupFetchRequest(ifetch_req); 533 534 ifetch_pkt = new Packet(ifetch_req, MemCmd::ReadReq, Packet::Broadcast); 535 ifetch_pkt->dataStatic(&inst); 536 537 if (fault == NoFault) { 538 if (!icachePort.sendTiming(ifetch_pkt)) { 539 // Need to wait for retry 540 _status = IcacheRetry; 541 } else { 542 // Need to wait for cache to respond 543 _status = IcacheWaitResponse; 544 // ownership of packet transferred to memory system 545 ifetch_pkt = NULL; 546 } 547 } else { 548 delete ifetch_req; 549 delete ifetch_pkt; 550 // fetch fault: advance directly to next instruction (fault handler) 551 advanceInst(fault); 552 } 553 } else { 554 _status = IcacheWaitResponse; 555 completeIfetch(NULL); 556 } 557 558 numCycles += tickToCycles(curTick - previousTick); 559 previousTick = curTick; 560} 561 562 563void 564TimingSimpleCPU::advanceInst(Fault fault) 565{ 566 advancePC(fault); 567 568 if (_status == Running) { 569 // kick off fetch of next instruction... callback from icache 570 // response will cause that instruction to be executed, 571 // keeping the CPU running. 572 fetch(); 573 } 574} 575 576 577void 578TimingSimpleCPU::completeIfetch(PacketPtr pkt) 579{ 580 DPRINTF(SimpleCPU, "Complete ICache Fetch\n"); 581 582 // received a response from the icache: execute the received 583 // instruction 584 585 assert(!pkt || !pkt->isError()); 586 assert(_status == IcacheWaitResponse); 587 588 _status = Running; 589 590 numCycles += tickToCycles(curTick - previousTick); 591 previousTick = curTick; 592 593 if (getState() == SimObject::Draining) { 594 if (pkt) { 595 delete pkt->req; 596 delete pkt; 597 } 598 599 completeDrain(); 600 return; 601 } 602 603 preExecute(); 604 if (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 { 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 } 663 664 if (pkt) { 665 delete pkt->req; 666 delete pkt; 667 } 668} 669 670void 671TimingSimpleCPU::IcachePort::ITickEvent::process() 672{ 673 cpu->completeIfetch(pkt); 674} 675 676bool 677TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt) 678{ 679 if (pkt->isResponse() && !pkt->wasNacked()) { 680 // delay processing of returned data until next CPU clock edge 681 Tick next_tick = cpu->nextCycle(curTick); 682 683 if (next_tick == curTick) 684 cpu->completeIfetch(pkt); 685 else 686 tickEvent.schedule(pkt, next_tick); 687 688 return true; 689 } 690 else if (pkt->wasNacked()) { 691 assert(cpu->_status == IcacheWaitResponse); 692 pkt->reinitNacked(); 693 if (!sendTiming(pkt)) { 694 cpu->_status = IcacheRetry; 695 cpu->ifetch_pkt = pkt; 696 } 697 } 698 //Snooping a Coherence Request, do nothing 699 return true; 700} 701 702void 703TimingSimpleCPU::IcachePort::recvRetry() 704{ 705 // we shouldn't get a retry unless we have a packet that we're 706 // waiting to transmit 707 assert(cpu->ifetch_pkt != NULL); 708 assert(cpu->_status == IcacheRetry); 709 PacketPtr tmp = cpu->ifetch_pkt; 710 if (sendTiming(tmp)) { 711 cpu->_status = IcacheWaitResponse; 712 cpu->ifetch_pkt = NULL; 713 } 714} 715 716void 717TimingSimpleCPU::completeDataAccess(PacketPtr pkt) 718{ 719 // received a response from the dcache: complete the load or store 720 // instruction 721 assert(!pkt->isError()); 722 assert(_status == DcacheWaitResponse); 723 _status = Running; 724 725 numCycles += tickToCycles(curTick - previousTick); 726 previousTick = curTick; 727 728 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 729 730 // keep an instruction count 731 if (fault == NoFault) 732 countInst(); 733 else if (traceData) { 734 // If there was a fault, we shouldn't trace this instruction. 735 delete traceData; 736 traceData = NULL; 737 } 738 739 // the locked flag may be cleared on the response packet, so check 740 // pkt->req and not pkt to see if it was a load-locked 741 if (pkt->isRead() && pkt->req->isLocked()) { 742 TheISA::handleLockedRead(thread, pkt->req); 743 } 744 745 delete pkt->req; 746 delete pkt; 747 748 postExecute(); 749 750 if (getState() == SimObject::Draining) { 751 advancePC(fault); 752 completeDrain(); 753 754 return; 755 } 756 757 advanceInst(fault); 758} 759 760 761void 762TimingSimpleCPU::completeDrain() 763{ 764 DPRINTF(Config, "Done draining\n"); 765 changeState(SimObject::Drained); 766 drainEvent->process(); 767} 768 769void 770TimingSimpleCPU::DcachePort::setPeer(Port *port) 771{ 772 Port::setPeer(port); 773 774#if FULL_SYSTEM 775 // Update the ThreadContext's memory ports (Functional/Virtual 776 // Ports) 777 cpu->tcBase()->connectMemPorts(cpu->tcBase()); 778#endif 779} 780 781bool 782TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt) 783{ 784 if (pkt->isResponse() && !pkt->wasNacked()) { 785 // delay processing of returned data until next CPU clock edge 786 Tick next_tick = cpu->nextCycle(curTick); 787 788 if (next_tick == curTick) 789 cpu->completeDataAccess(pkt); 790 else 791 tickEvent.schedule(pkt, next_tick); 792 793 return true; 794 } 795 else if (pkt->wasNacked()) { 796 assert(cpu->_status == DcacheWaitResponse); 797 pkt->reinitNacked(); 798 if (!sendTiming(pkt)) { 799 cpu->_status = DcacheRetry; 800 cpu->dcache_pkt = pkt; 801 } 802 } 803 //Snooping a Coherence Request, do nothing 804 return true; 805} 806 807void 808TimingSimpleCPU::DcachePort::DTickEvent::process() 809{ 810 cpu->completeDataAccess(pkt); 811} 812 813void 814TimingSimpleCPU::DcachePort::recvRetry() 815{ 816 // we shouldn't get a retry unless we have a packet that we're 817 // waiting to transmit 818 assert(cpu->dcache_pkt != NULL); 819 assert(cpu->_status == DcacheRetry); 820 PacketPtr tmp = cpu->dcache_pkt; 821 if (sendTiming(tmp)) { 822 cpu->_status = DcacheWaitResponse; 823 // memory system takes ownership of packet 824 cpu->dcache_pkt = NULL; 825 } 826} 827 828TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, 829 Tick t) 830 : pkt(_pkt), cpu(_cpu) 831{ 832 cpu->schedule(this, t); 833} 834 835void 836TimingSimpleCPU::IprEvent::process() 837{ 838 cpu->completeDataAccess(pkt); 839} 840 841const char * 842TimingSimpleCPU::IprEvent::description() const 843{ 844 return "Timing Simple CPU Delay IPR event"; 845} 846 847 848void 849TimingSimpleCPU::printAddr(Addr a) 850{ 851 dcachePort.printAddr(a); 852} 853 854 855//////////////////////////////////////////////////////////////////////// 856// 857// TimingSimpleCPU Simulation Object 858// 859TimingSimpleCPU * 860TimingSimpleCPUParams::create() 861{ 862 numThreads = 1; 863#if !FULL_SYSTEM 864 if (workload.size() != 1) 865 panic("only one workload allowed"); 866#endif 867 return new TimingSimpleCPU(this); 868} 869