timing.cc revision 13652:45d94ac03a27
110915Sandreas.sandberg@arm.com/* 210915Sandreas.sandberg@arm.com * Copyright 2014 Google, Inc. 310915Sandreas.sandberg@arm.com * Copyright (c) 2010-2013,2015,2017 ARM Limited 410915Sandreas.sandberg@arm.com * All rights reserved 510915Sandreas.sandberg@arm.com * 610915Sandreas.sandberg@arm.com * The license below extends only to copyright in the software and shall 710915Sandreas.sandberg@arm.com * not be construed as granting a license to any other intellectual 810915Sandreas.sandberg@arm.com * property including but not limited to intellectual property relating 910915Sandreas.sandberg@arm.com * to a hardware implementation of the functionality of the software 1010915Sandreas.sandberg@arm.com * licensed hereunder. You may use the software subject to the license 1110915Sandreas.sandberg@arm.com * terms below provided that you ensure that this notice is replicated 1210915Sandreas.sandberg@arm.com * unmodified and in its entirety in all distributions of the software, 1310915Sandreas.sandberg@arm.com * modified or unmodified, in source code or in binary form. 1410915Sandreas.sandberg@arm.com * 1510915Sandreas.sandberg@arm.com * Copyright (c) 2002-2005 The Regents of The University of Michigan 1610915Sandreas.sandberg@arm.com * All rights reserved. 1710915Sandreas.sandberg@arm.com * 1810915Sandreas.sandberg@arm.com * Redistribution and use in source and binary forms, with or without 1910915Sandreas.sandberg@arm.com * modification, are permitted provided that the following conditions are 2010915Sandreas.sandberg@arm.com * met: redistributions of source code must retain the above copyright 2110915Sandreas.sandberg@arm.com * notice, this list of conditions and the following disclaimer; 2210915Sandreas.sandberg@arm.com * redistributions in binary form must reproduce the above copyright 2310915Sandreas.sandberg@arm.com * notice, this list of conditions and the following disclaimer in the 2410915Sandreas.sandberg@arm.com * documentation and/or other materials provided with the distribution; 2510915Sandreas.sandberg@arm.com * neither the name of the copyright holders nor the names of its 2610915Sandreas.sandberg@arm.com * contributors may be used to endorse or promote products derived from 2710915Sandreas.sandberg@arm.com * this software without specific prior written permission. 2810915Sandreas.sandberg@arm.com * 2910915Sandreas.sandberg@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3010915Sandreas.sandberg@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3110915Sandreas.sandberg@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3210915Sandreas.sandberg@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3310915Sandreas.sandberg@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3410915Sandreas.sandberg@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3510915Sandreas.sandberg@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3610915Sandreas.sandberg@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3710915Sandreas.sandberg@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3810915Sandreas.sandberg@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3910915Sandreas.sandberg@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 4010915Sandreas.sandberg@arm.com * 4110915Sandreas.sandberg@arm.com * Authors: Steve Reinhardt 4210915Sandreas.sandberg@arm.com */ 4310915Sandreas.sandberg@arm.com 4410915Sandreas.sandberg@arm.com#include "cpu/simple/timing.hh" 4510915Sandreas.sandberg@arm.com 4610915Sandreas.sandberg@arm.com#include "arch/locked_mem.hh" 4710915Sandreas.sandberg@arm.com#include "arch/mmapped_ipr.hh" 4810915Sandreas.sandberg@arm.com#include "arch/utility.hh" 4910915Sandreas.sandberg@arm.com#include "config/the_isa.hh" 5010915Sandreas.sandberg@arm.com#include "cpu/exetrace.hh" 5110915Sandreas.sandberg@arm.com#include "debug/Config.hh" 5210915Sandreas.sandberg@arm.com#include "debug/Drain.hh" 5310915Sandreas.sandberg@arm.com#include "debug/ExecFaulting.hh" 54#include "debug/Mwait.hh" 55#include "debug/SimpleCPU.hh" 56#include "mem/packet.hh" 57#include "mem/packet_access.hh" 58#include "params/TimingSimpleCPU.hh" 59#include "sim/faults.hh" 60#include "sim/full_system.hh" 61#include "sim/system.hh" 62 63using namespace std; 64using namespace TheISA; 65 66void 67TimingSimpleCPU::init() 68{ 69 BaseSimpleCPU::init(); 70} 71 72void 73TimingSimpleCPU::TimingCPUPort::TickEvent::schedule(PacketPtr _pkt, Tick t) 74{ 75 pkt = _pkt; 76 cpu->schedule(this, t); 77} 78 79TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) 80 : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this), 81 dcachePort(this), ifetch_pkt(NULL), dcache_pkt(NULL), previousCycle(0), 82 fetchEvent([this]{ fetch(); }, name()) 83{ 84 _status = Idle; 85} 86 87 88 89TimingSimpleCPU::~TimingSimpleCPU() 90{ 91} 92 93DrainState 94TimingSimpleCPU::drain() 95{ 96 // Deschedule any power gating event (if any) 97 deschedulePowerGatingEvent(); 98 99 if (switchedOut()) 100 return DrainState::Drained; 101 102 if (_status == Idle || 103 (_status == BaseSimpleCPU::Running && isDrained())) { 104 DPRINTF(Drain, "No need to drain.\n"); 105 activeThreads.clear(); 106 return DrainState::Drained; 107 } else { 108 DPRINTF(Drain, "Requesting drain.\n"); 109 110 // The fetch event can become descheduled if a drain didn't 111 // succeed on the first attempt. We need to reschedule it if 112 // the CPU is waiting for a microcode routine to complete. 113 if (_status == BaseSimpleCPU::Running && !fetchEvent.scheduled()) 114 schedule(fetchEvent, clockEdge()); 115 116 return DrainState::Draining; 117 } 118} 119 120void 121TimingSimpleCPU::drainResume() 122{ 123 assert(!fetchEvent.scheduled()); 124 if (switchedOut()) 125 return; 126 127 DPRINTF(SimpleCPU, "Resume\n"); 128 verifyMemoryMode(); 129 130 assert(!threadContexts.empty()); 131 132 _status = BaseSimpleCPU::Idle; 133 134 for (ThreadID tid = 0; tid < numThreads; tid++) { 135 if (threadInfo[tid]->thread->status() == ThreadContext::Active) { 136 threadInfo[tid]->notIdleFraction = 1; 137 138 activeThreads.push_back(tid); 139 140 _status = BaseSimpleCPU::Running; 141 142 // Fetch if any threads active 143 if (!fetchEvent.scheduled()) { 144 schedule(fetchEvent, nextCycle()); 145 } 146 } else { 147 threadInfo[tid]->notIdleFraction = 0; 148 } 149 } 150 151 // Reschedule any power gating event (if any) 152 schedulePowerGatingEvent(); 153 154 system->totalNumInsts = 0; 155} 156 157bool 158TimingSimpleCPU::tryCompleteDrain() 159{ 160 if (drainState() != DrainState::Draining) 161 return false; 162 163 DPRINTF(Drain, "tryCompleteDrain.\n"); 164 if (!isDrained()) 165 return false; 166 167 DPRINTF(Drain, "CPU done draining, processing drain event\n"); 168 signalDrainDone(); 169 170 return true; 171} 172 173void 174TimingSimpleCPU::switchOut() 175{ 176 SimpleExecContext& t_info = *threadInfo[curThread]; 177 M5_VAR_USED SimpleThread* thread = t_info.thread; 178 179 BaseSimpleCPU::switchOut(); 180 181 assert(!fetchEvent.scheduled()); 182 assert(_status == BaseSimpleCPU::Running || _status == Idle); 183 assert(!t_info.stayAtPC); 184 assert(thread->microPC() == 0); 185 186 updateCycleCounts(); 187 updateCycleCounters(BaseCPU::CPU_STATE_ON); 188} 189 190 191void 192TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 193{ 194 BaseSimpleCPU::takeOverFrom(oldCPU); 195 196 previousCycle = curCycle(); 197} 198 199void 200TimingSimpleCPU::verifyMemoryMode() const 201{ 202 if (!system->isTimingMode()) { 203 fatal("The timing CPU requires the memory system to be in " 204 "'timing' mode.\n"); 205 } 206} 207 208void 209TimingSimpleCPU::activateContext(ThreadID thread_num) 210{ 211 DPRINTF(SimpleCPU, "ActivateContext %d\n", thread_num); 212 213 assert(thread_num < numThreads); 214 215 threadInfo[thread_num]->notIdleFraction = 1; 216 if (_status == BaseSimpleCPU::Idle) 217 _status = BaseSimpleCPU::Running; 218 219 // kick things off by initiating the fetch of the next instruction 220 if (!fetchEvent.scheduled()) 221 schedule(fetchEvent, clockEdge(Cycles(0))); 222 223 if (std::find(activeThreads.begin(), activeThreads.end(), thread_num) 224 == activeThreads.end()) { 225 activeThreads.push_back(thread_num); 226 } 227 228 BaseCPU::activateContext(thread_num); 229} 230 231 232void 233TimingSimpleCPU::suspendContext(ThreadID thread_num) 234{ 235 DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num); 236 237 assert(thread_num < numThreads); 238 activeThreads.remove(thread_num); 239 240 if (_status == Idle) 241 return; 242 243 assert(_status == BaseSimpleCPU::Running); 244 245 threadInfo[thread_num]->notIdleFraction = 0; 246 247 if (activeThreads.empty()) { 248 _status = Idle; 249 250 if (fetchEvent.scheduled()) { 251 deschedule(fetchEvent); 252 } 253 } 254 255 BaseCPU::suspendContext(thread_num); 256} 257 258bool 259TimingSimpleCPU::handleReadPacket(PacketPtr pkt) 260{ 261 SimpleExecContext &t_info = *threadInfo[curThread]; 262 SimpleThread* thread = t_info.thread; 263 264 const RequestPtr &req = pkt->req; 265 266 // We're about the issues a locked load, so tell the monitor 267 // to start caring about this address 268 if (pkt->isRead() && pkt->req->isLLSC()) { 269 TheISA::handleLockedRead(thread, pkt->req); 270 } 271 if (req->isMmappedIpr()) { 272 Cycles delay = TheISA::handleIprRead(thread->getTC(), pkt); 273 new IprEvent(pkt, this, clockEdge(delay)); 274 _status = DcacheWaitResponse; 275 dcache_pkt = NULL; 276 } else if (!dcachePort.sendTimingReq(pkt)) { 277 _status = DcacheRetry; 278 dcache_pkt = pkt; 279 } else { 280 _status = DcacheWaitResponse; 281 // memory system takes ownership of packet 282 dcache_pkt = NULL; 283 } 284 return dcache_pkt == NULL; 285} 286 287void 288TimingSimpleCPU::sendData(const RequestPtr &req, uint8_t *data, uint64_t *res, 289 bool read) 290{ 291 SimpleExecContext &t_info = *threadInfo[curThread]; 292 SimpleThread* thread = t_info.thread; 293 294 PacketPtr pkt = buildPacket(req, read); 295 pkt->dataDynamic<uint8_t>(data); 296 297 if (req->getFlags().isSet(Request::NO_ACCESS)) { 298 assert(!dcache_pkt); 299 pkt->makeResponse(); 300 completeDataAccess(pkt); 301 } else if (read) { 302 handleReadPacket(pkt); 303 } else { 304 bool do_access = true; // flag to suppress cache access 305 306 if (req->isLLSC()) { 307 do_access = TheISA::handleLockedWrite(thread, req, dcachePort.cacheBlockMask); 308 } else if (req->isCondSwap()) { 309 assert(res); 310 req->setExtraData(*res); 311 } 312 313 if (do_access) { 314 dcache_pkt = pkt; 315 handleWritePacket(); 316 threadSnoop(pkt, curThread); 317 } else { 318 _status = DcacheWaitResponse; 319 completeDataAccess(pkt); 320 } 321 } 322} 323 324void 325TimingSimpleCPU::sendSplitData(const RequestPtr &req1, const RequestPtr &req2, 326 const RequestPtr &req, uint8_t *data, bool read) 327{ 328 PacketPtr pkt1, pkt2; 329 buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read); 330 if (req->getFlags().isSet(Request::NO_ACCESS)) { 331 assert(!dcache_pkt); 332 pkt1->makeResponse(); 333 completeDataAccess(pkt1); 334 } else if (read) { 335 SplitFragmentSenderState * send_state = 336 dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 337 if (handleReadPacket(pkt1)) { 338 send_state->clearFromParent(); 339 send_state = dynamic_cast<SplitFragmentSenderState *>( 340 pkt2->senderState); 341 if (handleReadPacket(pkt2)) { 342 send_state->clearFromParent(); 343 } 344 } 345 } else { 346 dcache_pkt = pkt1; 347 SplitFragmentSenderState * send_state = 348 dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 349 if (handleWritePacket()) { 350 send_state->clearFromParent(); 351 dcache_pkt = pkt2; 352 send_state = dynamic_cast<SplitFragmentSenderState *>( 353 pkt2->senderState); 354 if (handleWritePacket()) { 355 send_state->clearFromParent(); 356 } 357 } 358 } 359} 360 361void 362TimingSimpleCPU::translationFault(const Fault &fault) 363{ 364 // fault may be NoFault in cases where a fault is suppressed, 365 // for instance prefetches. 366 updateCycleCounts(); 367 updateCycleCounters(BaseCPU::CPU_STATE_ON); 368 369 if (traceData) { 370 // Since there was a fault, we shouldn't trace this instruction. 371 delete traceData; 372 traceData = NULL; 373 } 374 375 postExecute(); 376 377 advanceInst(fault); 378} 379 380PacketPtr 381TimingSimpleCPU::buildPacket(const RequestPtr &req, bool read) 382{ 383 return read ? Packet::createRead(req) : Packet::createWrite(req); 384} 385 386void 387TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, 388 const RequestPtr &req1, const RequestPtr &req2, const RequestPtr &req, 389 uint8_t *data, bool read) 390{ 391 pkt1 = pkt2 = NULL; 392 393 assert(!req1->isMmappedIpr() && !req2->isMmappedIpr()); 394 395 if (req->getFlags().isSet(Request::NO_ACCESS)) { 396 pkt1 = buildPacket(req, read); 397 return; 398 } 399 400 pkt1 = buildPacket(req1, read); 401 pkt2 = buildPacket(req2, read); 402 403 PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand()); 404 405 pkt->dataDynamic<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::initiateMemRead(Addr addr, unsigned size, 420 Request::Flags flags) 421{ 422 SimpleExecContext &t_info = *threadInfo[curThread]; 423 SimpleThread* thread = t_info.thread; 424 425 Fault fault; 426 const int asid = 0; 427 const Addr pc = thread->instAddr(); 428 unsigned block_size = cacheLineSize(); 429 BaseTLB::Mode mode = BaseTLB::Read; 430 431 if (traceData) 432 traceData->setMem(addr, size, flags); 433 434 RequestPtr req = std::make_shared<Request>( 435 asid, addr, size, flags, dataMasterId(), pc, 436 thread->contextId()); 437 438 req->taskId(taskId()); 439 440 Addr split_addr = roundDown(addr + size - 1, block_size); 441 assert(split_addr <= addr || split_addr - addr < block_size); 442 443 _status = DTBWaitResponse; 444 if (split_addr > addr) { 445 RequestPtr req1, req2; 446 assert(!req->isLLSC() && !req->isSwap()); 447 req->splitOnVaddr(split_addr, req1, req2); 448 449 WholeTranslationState *state = 450 new WholeTranslationState(req, req1, req2, new uint8_t[size], 451 NULL, mode); 452 DataTranslation<TimingSimpleCPU *> *trans1 = 453 new DataTranslation<TimingSimpleCPU *>(this, state, 0); 454 DataTranslation<TimingSimpleCPU *> *trans2 = 455 new DataTranslation<TimingSimpleCPU *>(this, state, 1); 456 457 thread->dtb->translateTiming(req1, thread->getTC(), trans1, mode); 458 thread->dtb->translateTiming(req2, thread->getTC(), trans2, mode); 459 } else { 460 WholeTranslationState *state = 461 new WholeTranslationState(req, new uint8_t[size], NULL, mode); 462 DataTranslation<TimingSimpleCPU *> *translation 463 = new DataTranslation<TimingSimpleCPU *>(this, state); 464 thread->dtb->translateTiming(req, thread->getTC(), translation, mode); 465 } 466 467 return NoFault; 468} 469 470bool 471TimingSimpleCPU::handleWritePacket() 472{ 473 SimpleExecContext &t_info = *threadInfo[curThread]; 474 SimpleThread* thread = t_info.thread; 475 476 const RequestPtr &req = dcache_pkt->req; 477 if (req->isMmappedIpr()) { 478 Cycles delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); 479 new IprEvent(dcache_pkt, this, clockEdge(delay)); 480 _status = DcacheWaitResponse; 481 dcache_pkt = NULL; 482 } else if (!dcachePort.sendTimingReq(dcache_pkt)) { 483 _status = DcacheRetry; 484 } else { 485 _status = DcacheWaitResponse; 486 // memory system takes ownership of packet 487 dcache_pkt = NULL; 488 } 489 return dcache_pkt == NULL; 490} 491 492Fault 493TimingSimpleCPU::writeMem(uint8_t *data, unsigned size, 494 Addr addr, Request::Flags flags, uint64_t *res) 495{ 496 SimpleExecContext &t_info = *threadInfo[curThread]; 497 SimpleThread* thread = t_info.thread; 498 499 uint8_t *newData = new uint8_t[size]; 500 const int asid = 0; 501 const Addr pc = thread->instAddr(); 502 unsigned block_size = cacheLineSize(); 503 BaseTLB::Mode mode = BaseTLB::Write; 504 505 if (data == NULL) { 506 assert(flags & Request::STORE_NO_DATA); 507 // This must be a cache block cleaning request 508 memset(newData, 0, size); 509 } else { 510 memcpy(newData, data, size); 511 } 512 513 if (traceData) 514 traceData->setMem(addr, size, flags); 515 516 RequestPtr req = std::make_shared<Request>( 517 asid, addr, size, flags, dataMasterId(), pc, 518 thread->contextId()); 519 520 req->taskId(taskId()); 521 522 Addr split_addr = roundDown(addr + size - 1, block_size); 523 assert(split_addr <= addr || split_addr - addr < block_size); 524 525 _status = DTBWaitResponse; 526 if (split_addr > addr) { 527 RequestPtr req1, req2; 528 assert(!req->isLLSC() && !req->isSwap()); 529 req->splitOnVaddr(split_addr, req1, req2); 530 531 WholeTranslationState *state = 532 new WholeTranslationState(req, req1, req2, newData, res, mode); 533 DataTranslation<TimingSimpleCPU *> *trans1 = 534 new DataTranslation<TimingSimpleCPU *>(this, state, 0); 535 DataTranslation<TimingSimpleCPU *> *trans2 = 536 new DataTranslation<TimingSimpleCPU *>(this, state, 1); 537 538 thread->dtb->translateTiming(req1, thread->getTC(), trans1, mode); 539 thread->dtb->translateTiming(req2, thread->getTC(), trans2, mode); 540 } else { 541 WholeTranslationState *state = 542 new WholeTranslationState(req, newData, res, mode); 543 DataTranslation<TimingSimpleCPU *> *translation = 544 new DataTranslation<TimingSimpleCPU *>(this, state); 545 thread->dtb->translateTiming(req, thread->getTC(), translation, mode); 546 } 547 548 // Translation faults will be returned via finishTranslation() 549 return NoFault; 550} 551 552Fault 553TimingSimpleCPU::initiateMemAMO(Addr addr, unsigned size, 554 Request::Flags flags, 555 AtomicOpFunctor *amo_op) 556{ 557 SimpleExecContext &t_info = *threadInfo[curThread]; 558 SimpleThread* thread = t_info.thread; 559 560 Fault fault; 561 const int asid = 0; 562 const Addr pc = thread->instAddr(); 563 unsigned block_size = cacheLineSize(); 564 BaseTLB::Mode mode = BaseTLB::Write; 565 566 if (traceData) 567 traceData->setMem(addr, size, flags); 568 569 RequestPtr req = make_shared<Request>(asid, addr, size, flags, 570 dataMasterId(), pc, thread->contextId(), amo_op); 571 572 assert(req->hasAtomicOpFunctor()); 573 574 req->taskId(taskId()); 575 576 Addr split_addr = roundDown(addr + size - 1, block_size); 577 578 // AMO requests that access across a cache line boundary are not 579 // allowed since the cache does not guarantee AMO ops to be executed 580 // atomically in two cache lines 581 // For ISAs such as x86 that requires AMO operations to work on 582 // accesses that cross cache-line boundaries, the cache needs to be 583 // modified to support locking both cache lines to guarantee the 584 // atomicity. 585 if (split_addr > addr) { 586 panic("AMO requests should not access across a cache line boundary\n"); 587 } 588 589 _status = DTBWaitResponse; 590 591 WholeTranslationState *state = 592 new WholeTranslationState(req, new uint8_t[size], NULL, mode); 593 DataTranslation<TimingSimpleCPU *> *translation 594 = new DataTranslation<TimingSimpleCPU *>(this, state); 595 thread->dtb->translateTiming(req, thread->getTC(), translation, mode); 596 597 return NoFault; 598} 599 600void 601TimingSimpleCPU::threadSnoop(PacketPtr pkt, ThreadID sender) 602{ 603 for (ThreadID tid = 0; tid < numThreads; tid++) { 604 if (tid != sender) { 605 if (getCpuAddrMonitor(tid)->doMonitor(pkt)) { 606 wakeup(tid); 607 } 608 TheISA::handleLockedSnoop(threadInfo[tid]->thread, pkt, 609 dcachePort.cacheBlockMask); 610 } 611 } 612} 613 614void 615TimingSimpleCPU::finishTranslation(WholeTranslationState *state) 616{ 617 _status = BaseSimpleCPU::Running; 618 619 if (state->getFault() != NoFault) { 620 if (state->isPrefetch()) { 621 state->setNoFault(); 622 } 623 delete [] state->data; 624 state->deleteReqs(); 625 translationFault(state->getFault()); 626 } else { 627 if (!state->isSplit) { 628 sendData(state->mainReq, state->data, state->res, 629 state->mode == BaseTLB::Read); 630 } else { 631 sendSplitData(state->sreqLow, state->sreqHigh, state->mainReq, 632 state->data, state->mode == BaseTLB::Read); 633 } 634 } 635 636 delete state; 637} 638 639 640void 641TimingSimpleCPU::fetch() 642{ 643 // Change thread if multi-threaded 644 swapActiveThread(); 645 646 SimpleExecContext &t_info = *threadInfo[curThread]; 647 SimpleThread* thread = t_info.thread; 648 649 DPRINTF(SimpleCPU, "Fetch\n"); 650 651 if (!curStaticInst || !curStaticInst->isDelayedCommit()) { 652 checkForInterrupts(); 653 checkPcEventQueue(); 654 } 655 656 // We must have just got suspended by a PC event 657 if (_status == Idle) 658 return; 659 660 TheISA::PCState pcState = thread->pcState(); 661 bool needToFetch = !isRomMicroPC(pcState.microPC()) && 662 !curMacroStaticInst; 663 664 if (needToFetch) { 665 _status = BaseSimpleCPU::Running; 666 RequestPtr ifetch_req = std::make_shared<Request>(); 667 ifetch_req->taskId(taskId()); 668 ifetch_req->setContext(thread->contextId()); 669 setupFetchRequest(ifetch_req); 670 DPRINTF(SimpleCPU, "Translating address %#x\n", ifetch_req->getVaddr()); 671 thread->itb->translateTiming(ifetch_req, thread->getTC(), 672 &fetchTranslation, BaseTLB::Execute); 673 } else { 674 _status = IcacheWaitResponse; 675 completeIfetch(NULL); 676 677 updateCycleCounts(); 678 updateCycleCounters(BaseCPU::CPU_STATE_ON); 679 } 680} 681 682 683void 684TimingSimpleCPU::sendFetch(const Fault &fault, const RequestPtr &req, 685 ThreadContext *tc) 686{ 687 if (fault == NoFault) { 688 DPRINTF(SimpleCPU, "Sending fetch for addr %#x(pa: %#x)\n", 689 req->getVaddr(), req->getPaddr()); 690 ifetch_pkt = new Packet(req, MemCmd::ReadReq); 691 ifetch_pkt->dataStatic(&inst); 692 DPRINTF(SimpleCPU, " -- pkt addr: %#x\n", ifetch_pkt->getAddr()); 693 694 if (!icachePort.sendTimingReq(ifetch_pkt)) { 695 // Need to wait for retry 696 _status = IcacheRetry; 697 } else { 698 // Need to wait for cache to respond 699 _status = IcacheWaitResponse; 700 // ownership of packet transferred to memory system 701 ifetch_pkt = NULL; 702 } 703 } else { 704 DPRINTF(SimpleCPU, "Translation of addr %#x faulted\n", req->getVaddr()); 705 // fetch fault: advance directly to next instruction (fault handler) 706 _status = BaseSimpleCPU::Running; 707 advanceInst(fault); 708 } 709 710 updateCycleCounts(); 711 updateCycleCounters(BaseCPU::CPU_STATE_ON); 712} 713 714 715void 716TimingSimpleCPU::advanceInst(const Fault &fault) 717{ 718 SimpleExecContext &t_info = *threadInfo[curThread]; 719 720 if (_status == Faulting) 721 return; 722 723 if (fault != NoFault) { 724 DPRINTF(SimpleCPU, "Fault occured. Handling the fault\n"); 725 726 advancePC(fault); 727 728 // A syscall fault could suspend this CPU (e.g., futex_wait) 729 // If the _status is not Idle, schedule an event to fetch the next 730 // instruction after 'stall' ticks. 731 // If the cpu has been suspended (i.e., _status == Idle), another 732 // cpu will wake this cpu up later. 733 if (_status != Idle) { 734 DPRINTF(SimpleCPU, "Scheduling fetch event after the Fault\n"); 735 736 Tick stall = dynamic_pointer_cast<SyscallRetryFault>(fault) ? 737 clockEdge(syscallRetryLatency) : clockEdge(); 738 reschedule(fetchEvent, stall, true); 739 _status = Faulting; 740 } 741 742 return; 743 } 744 745 if (!t_info.stayAtPC) 746 advancePC(fault); 747 748 if (tryCompleteDrain()) 749 return; 750 751 if (_status == BaseSimpleCPU::Running) { 752 // kick off fetch of next instruction... callback from icache 753 // response will cause that instruction to be executed, 754 // keeping the CPU running. 755 fetch(); 756 } 757} 758 759 760void 761TimingSimpleCPU::completeIfetch(PacketPtr pkt) 762{ 763 SimpleExecContext& t_info = *threadInfo[curThread]; 764 765 DPRINTF(SimpleCPU, "Complete ICache Fetch for addr %#x\n", pkt ? 766 pkt->getAddr() : 0); 767 768 // received a response from the icache: execute the received 769 // instruction 770 assert(!pkt || !pkt->isError()); 771 assert(_status == IcacheWaitResponse); 772 773 _status = BaseSimpleCPU::Running; 774 775 updateCycleCounts(); 776 updateCycleCounters(BaseCPU::CPU_STATE_ON); 777 778 if (pkt) 779 pkt->req->setAccessLatency(); 780 781 782 preExecute(); 783 if (curStaticInst && curStaticInst->isMemRef()) { 784 // load or store: just send to dcache 785 Fault fault = curStaticInst->initiateAcc(&t_info, traceData); 786 787 // If we're not running now the instruction will complete in a dcache 788 // response callback or the instruction faulted and has started an 789 // ifetch 790 if (_status == BaseSimpleCPU::Running) { 791 if (fault != NoFault && traceData) { 792 // If there was a fault, we shouldn't trace this instruction. 793 delete traceData; 794 traceData = NULL; 795 } 796 797 postExecute(); 798 // @todo remove me after debugging with legion done 799 if (curStaticInst && (!curStaticInst->isMicroop() || 800 curStaticInst->isFirstMicroop())) 801 instCnt++; 802 advanceInst(fault); 803 } 804 } else if (curStaticInst) { 805 // non-memory instruction: execute completely now 806 Fault fault = curStaticInst->execute(&t_info, traceData); 807 808 // keep an instruction count 809 if (fault == NoFault) 810 countInst(); 811 else if (traceData && !DTRACE(ExecFaulting)) { 812 delete traceData; 813 traceData = NULL; 814 } 815 816 postExecute(); 817 // @todo remove me after debugging with legion done 818 if (curStaticInst && (!curStaticInst->isMicroop() || 819 curStaticInst->isFirstMicroop())) 820 instCnt++; 821 advanceInst(fault); 822 } else { 823 advanceInst(NoFault); 824 } 825 826 if (pkt) { 827 delete pkt; 828 } 829} 830 831void 832TimingSimpleCPU::IcachePort::ITickEvent::process() 833{ 834 cpu->completeIfetch(pkt); 835} 836 837bool 838TimingSimpleCPU::IcachePort::recvTimingResp(PacketPtr pkt) 839{ 840 DPRINTF(SimpleCPU, "Received fetch response %#x\n", pkt->getAddr()); 841 // we should only ever see one response per cycle since we only 842 // issue a new request once this response is sunk 843 assert(!tickEvent.scheduled()); 844 // delay processing of returned data until next CPU clock edge 845 tickEvent.schedule(pkt, cpu->clockEdge()); 846 847 return true; 848} 849 850void 851TimingSimpleCPU::IcachePort::recvReqRetry() 852{ 853 // we shouldn't get a retry unless we have a packet that we're 854 // waiting to transmit 855 assert(cpu->ifetch_pkt != NULL); 856 assert(cpu->_status == IcacheRetry); 857 PacketPtr tmp = cpu->ifetch_pkt; 858 if (sendTimingReq(tmp)) { 859 cpu->_status = IcacheWaitResponse; 860 cpu->ifetch_pkt = NULL; 861 } 862} 863 864void 865TimingSimpleCPU::completeDataAccess(PacketPtr pkt) 866{ 867 // received a response from the dcache: complete the load or store 868 // instruction 869 assert(!pkt->isError()); 870 assert(_status == DcacheWaitResponse || _status == DTBWaitResponse || 871 pkt->req->getFlags().isSet(Request::NO_ACCESS)); 872 873 pkt->req->setAccessLatency(); 874 875 updateCycleCounts(); 876 updateCycleCounters(BaseCPU::CPU_STATE_ON); 877 878 if (pkt->senderState) { 879 SplitFragmentSenderState * send_state = 880 dynamic_cast<SplitFragmentSenderState *>(pkt->senderState); 881 assert(send_state); 882 delete pkt; 883 PacketPtr big_pkt = send_state->bigPkt; 884 delete send_state; 885 886 SplitMainSenderState * main_send_state = 887 dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); 888 assert(main_send_state); 889 // Record the fact that this packet is no longer outstanding. 890 assert(main_send_state->outstanding != 0); 891 main_send_state->outstanding--; 892 893 if (main_send_state->outstanding) { 894 return; 895 } else { 896 delete main_send_state; 897 big_pkt->senderState = NULL; 898 pkt = big_pkt; 899 } 900 } 901 902 _status = BaseSimpleCPU::Running; 903 904 Fault fault = curStaticInst->completeAcc(pkt, threadInfo[curThread], 905 traceData); 906 907 // keep an instruction count 908 if (fault == NoFault) 909 countInst(); 910 else if (traceData) { 911 // If there was a fault, we shouldn't trace this instruction. 912 delete traceData; 913 traceData = NULL; 914 } 915 916 delete pkt; 917 918 postExecute(); 919 920 advanceInst(fault); 921} 922 923void 924TimingSimpleCPU::updateCycleCounts() 925{ 926 const Cycles delta(curCycle() - previousCycle); 927 928 numCycles += delta; 929 930 previousCycle = curCycle(); 931} 932 933void 934TimingSimpleCPU::DcachePort::recvTimingSnoopReq(PacketPtr pkt) 935{ 936 for (ThreadID tid = 0; tid < cpu->numThreads; tid++) { 937 if (cpu->getCpuAddrMonitor(tid)->doMonitor(pkt)) { 938 cpu->wakeup(tid); 939 } 940 } 941 942 // Making it uniform across all CPUs: 943 // The CPUs need to be woken up only on an invalidation packet (when using caches) 944 // or on an incoming write packet (when not using caches) 945 // It is not necessary to wake up the processor on all incoming packets 946 if (pkt->isInvalidate() || pkt->isWrite()) { 947 for (auto &t_info : cpu->threadInfo) { 948 TheISA::handleLockedSnoop(t_info->thread, pkt, cacheBlockMask); 949 } 950 } 951} 952 953void 954TimingSimpleCPU::DcachePort::recvFunctionalSnoop(PacketPtr pkt) 955{ 956 for (ThreadID tid = 0; tid < cpu->numThreads; tid++) { 957 if (cpu->getCpuAddrMonitor(tid)->doMonitor(pkt)) { 958 cpu->wakeup(tid); 959 } 960 } 961} 962 963bool 964TimingSimpleCPU::DcachePort::recvTimingResp(PacketPtr pkt) 965{ 966 DPRINTF(SimpleCPU, "Received load/store response %#x\n", pkt->getAddr()); 967 968 // The timing CPU is not really ticked, instead it relies on the 969 // memory system (fetch and load/store) to set the pace. 970 if (!tickEvent.scheduled()) { 971 // Delay processing of returned data until next CPU clock edge 972 tickEvent.schedule(pkt, cpu->clockEdge()); 973 return true; 974 } else { 975 // In the case of a split transaction and a cache that is 976 // faster than a CPU we could get two responses in the 977 // same tick, delay the second one 978 if (!retryRespEvent.scheduled()) 979 cpu->schedule(retryRespEvent, cpu->clockEdge(Cycles(1))); 980 return false; 981 } 982} 983 984void 985TimingSimpleCPU::DcachePort::DTickEvent::process() 986{ 987 cpu->completeDataAccess(pkt); 988} 989 990void 991TimingSimpleCPU::DcachePort::recvReqRetry() 992{ 993 // we shouldn't get a retry unless we have a packet that we're 994 // waiting to transmit 995 assert(cpu->dcache_pkt != NULL); 996 assert(cpu->_status == DcacheRetry); 997 PacketPtr tmp = cpu->dcache_pkt; 998 if (tmp->senderState) { 999 // This is a packet from a split access. 1000 SplitFragmentSenderState * send_state = 1001 dynamic_cast<SplitFragmentSenderState *>(tmp->senderState); 1002 assert(send_state); 1003 PacketPtr big_pkt = send_state->bigPkt; 1004 1005 SplitMainSenderState * main_send_state = 1006 dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); 1007 assert(main_send_state); 1008 1009 if (sendTimingReq(tmp)) { 1010 // If we were able to send without retrying, record that fact 1011 // and try sending the other fragment. 1012 send_state->clearFromParent(); 1013 int other_index = main_send_state->getPendingFragment(); 1014 if (other_index > 0) { 1015 tmp = main_send_state->fragments[other_index]; 1016 cpu->dcache_pkt = tmp; 1017 if ((big_pkt->isRead() && cpu->handleReadPacket(tmp)) || 1018 (big_pkt->isWrite() && cpu->handleWritePacket())) { 1019 main_send_state->fragments[other_index] = NULL; 1020 } 1021 } else { 1022 cpu->_status = DcacheWaitResponse; 1023 // memory system takes ownership of packet 1024 cpu->dcache_pkt = NULL; 1025 } 1026 } 1027 } else if (sendTimingReq(tmp)) { 1028 cpu->_status = DcacheWaitResponse; 1029 // memory system takes ownership of packet 1030 cpu->dcache_pkt = NULL; 1031 } 1032} 1033 1034TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, 1035 Tick t) 1036 : pkt(_pkt), cpu(_cpu) 1037{ 1038 cpu->schedule(this, t); 1039} 1040 1041void 1042TimingSimpleCPU::IprEvent::process() 1043{ 1044 cpu->completeDataAccess(pkt); 1045} 1046 1047const char * 1048TimingSimpleCPU::IprEvent::description() const 1049{ 1050 return "Timing Simple CPU Delay IPR event"; 1051} 1052 1053 1054void 1055TimingSimpleCPU::printAddr(Addr a) 1056{ 1057 dcachePort.printAddr(a); 1058} 1059 1060 1061//////////////////////////////////////////////////////////////////////// 1062// 1063// TimingSimpleCPU Simulation Object 1064// 1065TimingSimpleCPU * 1066TimingSimpleCPUParams::create() 1067{ 1068 return new TimingSimpleCPU(this); 1069} 1070