219{ 220 DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num); 221 222 assert(thread_num == 0); 223 assert(thread); 224 225 if (_status == Idle) 226 return; 227 228 assert(_status == Running); 229 230 // just change status to Idle... if status != Running, 231 // completeInst() will not initiate fetch of next instruction. 232 233 notIdleFraction--; 234 _status = Idle; 235} 236 237bool 238TimingSimpleCPU::handleReadPacket(PacketPtr pkt) 239{ 240 RequestPtr req = pkt->req; 241 if (req->isMmappedIpr()) { 242 Tick delay; 243 delay = TheISA::handleIprRead(thread->getTC(), pkt); 244 new IprEvent(pkt, this, nextCycle(curTick() + delay)); 245 _status = DcacheWaitResponse; 246 dcache_pkt = NULL; 247 } else if (!dcachePort.sendTiming(pkt)) { 248 _status = DcacheRetry; 249 dcache_pkt = pkt; 250 } else { 251 _status = DcacheWaitResponse; 252 // memory system takes ownership of packet 253 dcache_pkt = NULL; 254 } 255 return dcache_pkt == NULL; 256} 257 258void 259TimingSimpleCPU::sendData(RequestPtr req, uint8_t *data, uint64_t *res, 260 bool read) 261{ 262 PacketPtr pkt; 263 buildPacket(pkt, req, read); 264 pkt->dataDynamicArray<uint8_t>(data); 265 if (req->getFlags().isSet(Request::NO_ACCESS)) { 266 assert(!dcache_pkt); 267 pkt->makeResponse(); 268 completeDataAccess(pkt); 269 } else if (read) { 270 handleReadPacket(pkt); 271 } else { 272 bool do_access = true; // flag to suppress cache access 273 274 if (req->isLLSC()) { 275 do_access = TheISA::handleLockedWrite(thread, req); 276 } else if (req->isCondSwap()) { 277 assert(res); 278 req->setExtraData(*res); 279 } 280 281 if (do_access) { 282 dcache_pkt = pkt; 283 handleWritePacket(); 284 } else { 285 _status = DcacheWaitResponse; 286 completeDataAccess(pkt); 287 } 288 } 289} 290 291void 292TimingSimpleCPU::sendSplitData(RequestPtr req1, RequestPtr req2, 293 RequestPtr req, uint8_t *data, bool read) 294{ 295 PacketPtr pkt1, pkt2; 296 buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read); 297 if (req->getFlags().isSet(Request::NO_ACCESS)) { 298 assert(!dcache_pkt); 299 pkt1->makeResponse(); 300 completeDataAccess(pkt1); 301 } else if (read) { 302 SplitFragmentSenderState * send_state = 303 dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 304 if (handleReadPacket(pkt1)) { 305 send_state->clearFromParent(); 306 send_state = dynamic_cast<SplitFragmentSenderState *>( 307 pkt2->senderState); 308 if (handleReadPacket(pkt2)) { 309 send_state->clearFromParent(); 310 } 311 } 312 } else { 313 dcache_pkt = pkt1; 314 SplitFragmentSenderState * send_state = 315 dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 316 if (handleWritePacket()) { 317 send_state->clearFromParent(); 318 dcache_pkt = pkt2; 319 send_state = dynamic_cast<SplitFragmentSenderState *>( 320 pkt2->senderState); 321 if (handleWritePacket()) { 322 send_state->clearFromParent(); 323 } 324 } 325 } 326} 327 328void 329TimingSimpleCPU::translationFault(Fault fault) 330{ 331 // fault may be NoFault in cases where a fault is suppressed, 332 // for instance prefetches. 333 numCycles += tickToCycles(curTick() - previousTick); 334 previousTick = curTick(); 335 336 if (traceData) { 337 // Since there was a fault, we shouldn't trace this instruction. 338 delete traceData; 339 traceData = NULL; 340 } 341 342 postExecute(); 343 344 if (getState() == SimObject::Draining) { 345 advancePC(fault); 346 completeDrain(); 347 } else { 348 advanceInst(fault); 349 } 350} 351 352void 353TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr req, bool read) 354{ 355 MemCmd cmd; 356 if (read) { 357 cmd = MemCmd::ReadReq; 358 if (req->isLLSC()) 359 cmd = MemCmd::LoadLockedReq; 360 } else { 361 cmd = MemCmd::WriteReq; 362 if (req->isLLSC()) { 363 cmd = MemCmd::StoreCondReq; 364 } else if (req->isSwap()) { 365 cmd = MemCmd::SwapReq; 366 } 367 } 368 pkt = new Packet(req, cmd, Packet::Broadcast); 369} 370 371void 372TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, 373 RequestPtr req1, RequestPtr req2, RequestPtr req, 374 uint8_t *data, bool read) 375{ 376 pkt1 = pkt2 = NULL; 377 378 assert(!req1->isMmappedIpr() && !req2->isMmappedIpr()); 379 380 if (req->getFlags().isSet(Request::NO_ACCESS)) { 381 buildPacket(pkt1, req, read); 382 return; 383 } 384 385 buildPacket(pkt1, req1, read); 386 buildPacket(pkt2, req2, read); 387 388 req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags()); 389 PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(), 390 Packet::Broadcast); 391 392 pkt->dataDynamicArray<uint8_t>(data); 393 pkt1->dataStatic<uint8_t>(data); 394 pkt2->dataStatic<uint8_t>(data + req1->getSize()); 395 396 SplitMainSenderState * main_send_state = new SplitMainSenderState; 397 pkt->senderState = main_send_state; 398 main_send_state->fragments[0] = pkt1; 399 main_send_state->fragments[1] = pkt2; 400 main_send_state->outstanding = 2; 401 pkt1->senderState = new SplitFragmentSenderState(pkt, 0); 402 pkt2->senderState = new SplitFragmentSenderState(pkt, 1); 403} 404 405Fault 406TimingSimpleCPU::readMem(Addr addr, uint8_t *data, 407 unsigned size, unsigned flags) 408{ 409 Fault fault; 410 const int asid = 0; 411 const ThreadID tid = 0; 412 const Addr pc = thread->instAddr(); 413 unsigned block_size = dcachePort.peerBlockSize(); 414 BaseTLB::Mode mode = BaseTLB::Read; 415 416 if (traceData) { 417 traceData->setAddr(addr); 418 } 419 420 RequestPtr req = new Request(asid, addr, size, 421 flags, pc, _cpuId, tid); 422 423 Addr split_addr = roundDown(addr + size - 1, block_size); 424 assert(split_addr <= addr || split_addr - addr < block_size); 425 426 _status = DTBWaitResponse; 427 if (split_addr > addr) { 428 RequestPtr req1, req2; 429 assert(!req->isLLSC() && !req->isSwap()); 430 req->splitOnVaddr(split_addr, req1, req2); 431 432 WholeTranslationState *state = 433 new WholeTranslationState(req, req1, req2, new uint8_t[size], 434 NULL, mode); 435 DataTranslation<TimingSimpleCPU *> *trans1 = 436 new DataTranslation<TimingSimpleCPU *>(this, state, 0); 437 DataTranslation<TimingSimpleCPU *> *trans2 = 438 new DataTranslation<TimingSimpleCPU *>(this, state, 1); 439 440 thread->dtb->translateTiming(req1, tc, trans1, mode); 441 thread->dtb->translateTiming(req2, tc, trans2, mode); 442 } else { 443 WholeTranslationState *state = 444 new WholeTranslationState(req, new uint8_t[size], NULL, mode); 445 DataTranslation<TimingSimpleCPU *> *translation 446 = new DataTranslation<TimingSimpleCPU *>(this, state); 447 thread->dtb->translateTiming(req, tc, translation, mode); 448 } 449 450 return NoFault; 451} 452 453bool 454TimingSimpleCPU::handleWritePacket() 455{ 456 RequestPtr req = dcache_pkt->req; 457 if (req->isMmappedIpr()) { 458 Tick delay; 459 delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); 460 new IprEvent(dcache_pkt, this, nextCycle(curTick() + delay)); 461 _status = DcacheWaitResponse; 462 dcache_pkt = NULL; 463 } else if (!dcachePort.sendTiming(dcache_pkt)) { 464 _status = DcacheRetry; 465 } else { 466 _status = DcacheWaitResponse; 467 // memory system takes ownership of packet 468 dcache_pkt = NULL; 469 } 470 return dcache_pkt == NULL; 471} 472 473Fault 474TimingSimpleCPU::writeMem(uint8_t *data, unsigned size, 475 Addr addr, unsigned flags, uint64_t *res) 476{ 477 uint8_t *newData = new uint8_t[size]; 478 memcpy(newData, data, size); 479 480 const int asid = 0; 481 const ThreadID tid = 0; 482 const Addr pc = thread->instAddr(); 483 unsigned block_size = dcachePort.peerBlockSize(); 484 BaseTLB::Mode mode = BaseTLB::Write; 485 486 if (traceData) { 487 traceData->setAddr(addr); 488 } 489 490 RequestPtr req = new Request(asid, addr, size, 491 flags, pc, _cpuId, tid); 492 493 Addr split_addr = roundDown(addr + size - 1, block_size); 494 assert(split_addr <= addr || split_addr - addr < block_size); 495 496 _status = DTBWaitResponse; 497 if (split_addr > addr) { 498 RequestPtr req1, req2; 499 assert(!req->isLLSC() && !req->isSwap()); 500 req->splitOnVaddr(split_addr, req1, req2); 501 502 WholeTranslationState *state = 503 new WholeTranslationState(req, req1, req2, newData, res, mode); 504 DataTranslation<TimingSimpleCPU *> *trans1 = 505 new DataTranslation<TimingSimpleCPU *>(this, state, 0); 506 DataTranslation<TimingSimpleCPU *> *trans2 = 507 new DataTranslation<TimingSimpleCPU *>(this, state, 1); 508 509 thread->dtb->translateTiming(req1, tc, trans1, mode); 510 thread->dtb->translateTiming(req2, tc, trans2, mode); 511 } else { 512 WholeTranslationState *state = 513 new WholeTranslationState(req, newData, res, mode); 514 DataTranslation<TimingSimpleCPU *> *translation = 515 new DataTranslation<TimingSimpleCPU *>(this, state); 516 thread->dtb->translateTiming(req, tc, translation, mode); 517 } 518 519 // Translation faults will be returned via finishTranslation() 520 return NoFault; 521} 522 523 524void 525TimingSimpleCPU::finishTranslation(WholeTranslationState *state) 526{ 527 _status = Running; 528 529 if (state->getFault() != NoFault) { 530 if (state->isPrefetch()) { 531 state->setNoFault(); 532 } 533 delete [] state->data; 534 state->deleteReqs(); 535 translationFault(state->getFault()); 536 } else { 537 if (!state->isSplit) { 538 sendData(state->mainReq, state->data, state->res, 539 state->mode == BaseTLB::Read); 540 } else { 541 sendSplitData(state->sreqLow, state->sreqHigh, state->mainReq, 542 state->data, state->mode == BaseTLB::Read); 543 } 544 } 545 546 delete state; 547} 548 549 550void 551TimingSimpleCPU::fetch() 552{ 553 DPRINTF(SimpleCPU, "Fetch\n"); 554 555 if (!curStaticInst || !curStaticInst->isDelayedCommit()) 556 checkForInterrupts(); 557 558 checkPcEventQueue(); 559 560 // We must have just got suspended by a PC event 561 if (_status == Idle) 562 return; 563 564 TheISA::PCState pcState = thread->pcState(); 565 bool needToFetch = !isRomMicroPC(pcState.microPC()) && !curMacroStaticInst; 566 567 if (needToFetch) { 568 _status = Running; 569 Request *ifetch_req = new Request(); 570 ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0); 571 setupFetchRequest(ifetch_req); 572 DPRINTF(SimpleCPU, "Translating address %#x\n", ifetch_req->getVaddr()); 573 thread->itb->translateTiming(ifetch_req, tc, &fetchTranslation, 574 BaseTLB::Execute); 575 } else { 576 _status = IcacheWaitResponse; 577 completeIfetch(NULL); 578 579 numCycles += tickToCycles(curTick() - previousTick); 580 previousTick = curTick(); 581 } 582} 583 584 585void 586TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc) 587{ 588 if (fault == NoFault) { 589 DPRINTF(SimpleCPU, "Sending fetch for addr %#x(pa: %#x)\n", 590 req->getVaddr(), req->getPaddr()); 591 ifetch_pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast); 592 ifetch_pkt->dataStatic(&inst); 593 DPRINTF(SimpleCPU, " -- pkt addr: %#x\n", ifetch_pkt->getAddr()); 594 595 if (!icachePort.sendTiming(ifetch_pkt)) { 596 // Need to wait for retry 597 _status = IcacheRetry; 598 } else { 599 // Need to wait for cache to respond 600 _status = IcacheWaitResponse; 601 // ownership of packet transferred to memory system 602 ifetch_pkt = NULL; 603 } 604 } else { 605 DPRINTF(SimpleCPU, "Translation of addr %#x faulted\n", req->getVaddr()); 606 delete req; 607 // fetch fault: advance directly to next instruction (fault handler) 608 _status = Running; 609 advanceInst(fault); 610 } 611 612 numCycles += tickToCycles(curTick() - previousTick); 613 previousTick = curTick(); 614} 615 616 617void 618TimingSimpleCPU::advanceInst(Fault fault) 619{ 620 621 if (_status == Faulting) 622 return; 623 624 if (fault != NoFault) { 625 advancePC(fault); 626 DPRINTF(SimpleCPU, "Fault occured, scheduling fetch event\n"); 627 reschedule(fetchEvent, nextCycle(), true); 628 _status = Faulting; 629 return; 630 } 631 632 633 if (!stayAtPC) 634 advancePC(fault); 635 636 if (_status == Running) { 637 // kick off fetch of next instruction... callback from icache 638 // response will cause that instruction to be executed, 639 // keeping the CPU running. 640 fetch(); 641 } 642} 643 644 645void 646TimingSimpleCPU::completeIfetch(PacketPtr pkt) 647{ 648 DPRINTF(SimpleCPU, "Complete ICache Fetch for addr %#x\n", pkt ? 649 pkt->getAddr() : 0); 650 651 // received a response from the icache: execute the received 652 // instruction 653 654 assert(!pkt || !pkt->isError()); 655 assert(_status == IcacheWaitResponse); 656 657 _status = Running; 658 659 numCycles += tickToCycles(curTick() - previousTick); 660 previousTick = curTick(); 661 662 if (getState() == SimObject::Draining) { 663 if (pkt) { 664 delete pkt->req; 665 delete pkt; 666 } 667 668 completeDrain(); 669 return; 670 } 671 672 preExecute(); 673 if (curStaticInst && curStaticInst->isMemRef()) { 674 // load or store: just send to dcache 675 Fault fault = curStaticInst->initiateAcc(this, traceData); 676 677 // If we're not running now the instruction will complete in a dcache 678 // response callback or the instruction faulted and has started an 679 // ifetch 680 if (_status == Running) { 681 if (fault != NoFault && traceData) { 682 // If there was a fault, we shouldn't trace this instruction. 683 delete traceData; 684 traceData = NULL; 685 } 686 687 postExecute(); 688 // @todo remove me after debugging with legion done 689 if (curStaticInst && (!curStaticInst->isMicroop() || 690 curStaticInst->isFirstMicroop())) 691 instCnt++; 692 advanceInst(fault); 693 } 694 } else if (curStaticInst) { 695 // non-memory instruction: execute completely now 696 Fault fault = curStaticInst->execute(this, traceData); 697 698 // keep an instruction count 699 if (fault == NoFault) 700 countInst(); 701 else if (traceData && !DTRACE(ExecFaulting)) { 702 delete traceData; 703 traceData = NULL; 704 } 705 706 postExecute(); 707 // @todo remove me after debugging with legion done 708 if (curStaticInst && (!curStaticInst->isMicroop() || 709 curStaticInst->isFirstMicroop())) 710 instCnt++; 711 advanceInst(fault); 712 } else { 713 advanceInst(NoFault); 714 } 715 716 if (pkt) { 717 delete pkt->req; 718 delete pkt; 719 } 720} 721 722void 723TimingSimpleCPU::IcachePort::ITickEvent::process() 724{ 725 cpu->completeIfetch(pkt); 726} 727 728bool 729TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt) 730{ 731 if (pkt->isResponse() && !pkt->wasNacked()) { 732 DPRINTF(SimpleCPU, "Received timing response %#x\n", pkt->getAddr()); 733 // delay processing of returned data until next CPU clock edge 734 Tick next_tick = cpu->nextCycle(curTick()); 735 736 if (next_tick == curTick()) 737 cpu->completeIfetch(pkt); 738 else 739 tickEvent.schedule(pkt, next_tick); 740 741 return true; 742 } else if (pkt->wasNacked()) { 743 assert(cpu->_status == IcacheWaitResponse); 744 pkt->reinitNacked(); 745 if (!sendTiming(pkt)) { 746 cpu->_status = IcacheRetry; 747 cpu->ifetch_pkt = pkt; 748 } 749 } 750 //Snooping a Coherence Request, do nothing 751 return true; 752} 753 754void 755TimingSimpleCPU::IcachePort::recvRetry() 756{ 757 // we shouldn't get a retry unless we have a packet that we're 758 // waiting to transmit 759 assert(cpu->ifetch_pkt != NULL); 760 assert(cpu->_status == IcacheRetry); 761 PacketPtr tmp = cpu->ifetch_pkt; 762 if (sendTiming(tmp)) { 763 cpu->_status = IcacheWaitResponse; 764 cpu->ifetch_pkt = NULL; 765 } 766} 767 768void 769TimingSimpleCPU::completeDataAccess(PacketPtr pkt) 770{ 771 // received a response from the dcache: complete the load or store 772 // instruction 773 assert(!pkt->isError()); 774 assert(_status == DcacheWaitResponse || _status == DTBWaitResponse || 775 pkt->req->getFlags().isSet(Request::NO_ACCESS)); 776 777 numCycles += tickToCycles(curTick() - previousTick); 778 previousTick = curTick(); 779 780 if (pkt->senderState) { 781 SplitFragmentSenderState * send_state = 782 dynamic_cast<SplitFragmentSenderState *>(pkt->senderState); 783 assert(send_state); 784 delete pkt->req; 785 delete pkt; 786 PacketPtr big_pkt = send_state->bigPkt; 787 delete send_state; 788 789 SplitMainSenderState * main_send_state = 790 dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); 791 assert(main_send_state); 792 // Record the fact that this packet is no longer outstanding. 793 assert(main_send_state->outstanding != 0); 794 main_send_state->outstanding--; 795 796 if (main_send_state->outstanding) { 797 return; 798 } else { 799 delete main_send_state; 800 big_pkt->senderState = NULL; 801 pkt = big_pkt; 802 } 803 } 804 805 _status = Running; 806 807 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 808 809 // keep an instruction count 810 if (fault == NoFault) 811 countInst(); 812 else if (traceData) { 813 // If there was a fault, we shouldn't trace this instruction. 814 delete traceData; 815 traceData = NULL; 816 } 817 818 // the locked flag may be cleared on the response packet, so check 819 // pkt->req and not pkt to see if it was a load-locked 820 if (pkt->isRead() && pkt->req->isLLSC()) { 821 TheISA::handleLockedRead(thread, pkt->req); 822 } 823 824 delete pkt->req; 825 delete pkt; 826 827 postExecute(); 828 829 if (getState() == SimObject::Draining) { 830 advancePC(fault); 831 completeDrain(); 832 833 return; 834 } 835 836 advanceInst(fault); 837} 838 839 840void 841TimingSimpleCPU::completeDrain() 842{ 843 DPRINTF(Config, "Done draining\n"); 844 changeState(SimObject::Drained); 845 drainEvent->process(); 846} 847
| 250{ 251 DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num); 252 253 assert(thread_num == 0); 254 assert(thread); 255 256 if (_status == Idle) 257 return; 258 259 assert(_status == Running); 260 261 // just change status to Idle... if status != Running, 262 // completeInst() will not initiate fetch of next instruction. 263 264 notIdleFraction--; 265 _status = Idle; 266} 267 268bool 269TimingSimpleCPU::handleReadPacket(PacketPtr pkt) 270{ 271 RequestPtr req = pkt->req; 272 if (req->isMmappedIpr()) { 273 Tick delay; 274 delay = TheISA::handleIprRead(thread->getTC(), pkt); 275 new IprEvent(pkt, this, nextCycle(curTick() + delay)); 276 _status = DcacheWaitResponse; 277 dcache_pkt = NULL; 278 } else if (!dcachePort.sendTiming(pkt)) { 279 _status = DcacheRetry; 280 dcache_pkt = pkt; 281 } else { 282 _status = DcacheWaitResponse; 283 // memory system takes ownership of packet 284 dcache_pkt = NULL; 285 } 286 return dcache_pkt == NULL; 287} 288 289void 290TimingSimpleCPU::sendData(RequestPtr req, uint8_t *data, uint64_t *res, 291 bool read) 292{ 293 PacketPtr pkt; 294 buildPacket(pkt, req, read); 295 pkt->dataDynamicArray<uint8_t>(data); 296 if (req->getFlags().isSet(Request::NO_ACCESS)) { 297 assert(!dcache_pkt); 298 pkt->makeResponse(); 299 completeDataAccess(pkt); 300 } else if (read) { 301 handleReadPacket(pkt); 302 } else { 303 bool do_access = true; // flag to suppress cache access 304 305 if (req->isLLSC()) { 306 do_access = TheISA::handleLockedWrite(thread, req); 307 } else if (req->isCondSwap()) { 308 assert(res); 309 req->setExtraData(*res); 310 } 311 312 if (do_access) { 313 dcache_pkt = pkt; 314 handleWritePacket(); 315 } else { 316 _status = DcacheWaitResponse; 317 completeDataAccess(pkt); 318 } 319 } 320} 321 322void 323TimingSimpleCPU::sendSplitData(RequestPtr req1, RequestPtr req2, 324 RequestPtr req, uint8_t *data, bool read) 325{ 326 PacketPtr pkt1, pkt2; 327 buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read); 328 if (req->getFlags().isSet(Request::NO_ACCESS)) { 329 assert(!dcache_pkt); 330 pkt1->makeResponse(); 331 completeDataAccess(pkt1); 332 } else if (read) { 333 SplitFragmentSenderState * send_state = 334 dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 335 if (handleReadPacket(pkt1)) { 336 send_state->clearFromParent(); 337 send_state = dynamic_cast<SplitFragmentSenderState *>( 338 pkt2->senderState); 339 if (handleReadPacket(pkt2)) { 340 send_state->clearFromParent(); 341 } 342 } 343 } else { 344 dcache_pkt = pkt1; 345 SplitFragmentSenderState * send_state = 346 dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 347 if (handleWritePacket()) { 348 send_state->clearFromParent(); 349 dcache_pkt = pkt2; 350 send_state = dynamic_cast<SplitFragmentSenderState *>( 351 pkt2->senderState); 352 if (handleWritePacket()) { 353 send_state->clearFromParent(); 354 } 355 } 356 } 357} 358 359void 360TimingSimpleCPU::translationFault(Fault fault) 361{ 362 // fault may be NoFault in cases where a fault is suppressed, 363 // for instance prefetches. 364 numCycles += tickToCycles(curTick() - previousTick); 365 previousTick = curTick(); 366 367 if (traceData) { 368 // Since there was a fault, we shouldn't trace this instruction. 369 delete traceData; 370 traceData = NULL; 371 } 372 373 postExecute(); 374 375 if (getState() == SimObject::Draining) { 376 advancePC(fault); 377 completeDrain(); 378 } else { 379 advanceInst(fault); 380 } 381} 382 383void 384TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr req, bool read) 385{ 386 MemCmd cmd; 387 if (read) { 388 cmd = MemCmd::ReadReq; 389 if (req->isLLSC()) 390 cmd = MemCmd::LoadLockedReq; 391 } else { 392 cmd = MemCmd::WriteReq; 393 if (req->isLLSC()) { 394 cmd = MemCmd::StoreCondReq; 395 } else if (req->isSwap()) { 396 cmd = MemCmd::SwapReq; 397 } 398 } 399 pkt = new Packet(req, cmd, Packet::Broadcast); 400} 401 402void 403TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, 404 RequestPtr req1, RequestPtr req2, RequestPtr req, 405 uint8_t *data, bool read) 406{ 407 pkt1 = pkt2 = NULL; 408 409 assert(!req1->isMmappedIpr() && !req2->isMmappedIpr()); 410 411 if (req->getFlags().isSet(Request::NO_ACCESS)) { 412 buildPacket(pkt1, req, read); 413 return; 414 } 415 416 buildPacket(pkt1, req1, read); 417 buildPacket(pkt2, req2, read); 418 419 req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags()); 420 PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(), 421 Packet::Broadcast); 422 423 pkt->dataDynamicArray<uint8_t>(data); 424 pkt1->dataStatic<uint8_t>(data); 425 pkt2->dataStatic<uint8_t>(data + req1->getSize()); 426 427 SplitMainSenderState * main_send_state = new SplitMainSenderState; 428 pkt->senderState = main_send_state; 429 main_send_state->fragments[0] = pkt1; 430 main_send_state->fragments[1] = pkt2; 431 main_send_state->outstanding = 2; 432 pkt1->senderState = new SplitFragmentSenderState(pkt, 0); 433 pkt2->senderState = new SplitFragmentSenderState(pkt, 1); 434} 435 436Fault 437TimingSimpleCPU::readMem(Addr addr, uint8_t *data, 438 unsigned size, unsigned flags) 439{ 440 Fault fault; 441 const int asid = 0; 442 const ThreadID tid = 0; 443 const Addr pc = thread->instAddr(); 444 unsigned block_size = dcachePort.peerBlockSize(); 445 BaseTLB::Mode mode = BaseTLB::Read; 446 447 if (traceData) { 448 traceData->setAddr(addr); 449 } 450 451 RequestPtr req = new Request(asid, addr, size, 452 flags, pc, _cpuId, tid); 453 454 Addr split_addr = roundDown(addr + size - 1, block_size); 455 assert(split_addr <= addr || split_addr - addr < block_size); 456 457 _status = DTBWaitResponse; 458 if (split_addr > addr) { 459 RequestPtr req1, req2; 460 assert(!req->isLLSC() && !req->isSwap()); 461 req->splitOnVaddr(split_addr, req1, req2); 462 463 WholeTranslationState *state = 464 new WholeTranslationState(req, req1, req2, new uint8_t[size], 465 NULL, mode); 466 DataTranslation<TimingSimpleCPU *> *trans1 = 467 new DataTranslation<TimingSimpleCPU *>(this, state, 0); 468 DataTranslation<TimingSimpleCPU *> *trans2 = 469 new DataTranslation<TimingSimpleCPU *>(this, state, 1); 470 471 thread->dtb->translateTiming(req1, tc, trans1, mode); 472 thread->dtb->translateTiming(req2, tc, trans2, mode); 473 } else { 474 WholeTranslationState *state = 475 new WholeTranslationState(req, new uint8_t[size], NULL, mode); 476 DataTranslation<TimingSimpleCPU *> *translation 477 = new DataTranslation<TimingSimpleCPU *>(this, state); 478 thread->dtb->translateTiming(req, tc, translation, mode); 479 } 480 481 return NoFault; 482} 483 484bool 485TimingSimpleCPU::handleWritePacket() 486{ 487 RequestPtr req = dcache_pkt->req; 488 if (req->isMmappedIpr()) { 489 Tick delay; 490 delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); 491 new IprEvent(dcache_pkt, this, nextCycle(curTick() + delay)); 492 _status = DcacheWaitResponse; 493 dcache_pkt = NULL; 494 } else if (!dcachePort.sendTiming(dcache_pkt)) { 495 _status = DcacheRetry; 496 } else { 497 _status = DcacheWaitResponse; 498 // memory system takes ownership of packet 499 dcache_pkt = NULL; 500 } 501 return dcache_pkt == NULL; 502} 503 504Fault 505TimingSimpleCPU::writeMem(uint8_t *data, unsigned size, 506 Addr addr, unsigned flags, uint64_t *res) 507{ 508 uint8_t *newData = new uint8_t[size]; 509 memcpy(newData, data, size); 510 511 const int asid = 0; 512 const ThreadID tid = 0; 513 const Addr pc = thread->instAddr(); 514 unsigned block_size = dcachePort.peerBlockSize(); 515 BaseTLB::Mode mode = BaseTLB::Write; 516 517 if (traceData) { 518 traceData->setAddr(addr); 519 } 520 521 RequestPtr req = new Request(asid, addr, size, 522 flags, pc, _cpuId, tid); 523 524 Addr split_addr = roundDown(addr + size - 1, block_size); 525 assert(split_addr <= addr || split_addr - addr < block_size); 526 527 _status = DTBWaitResponse; 528 if (split_addr > addr) { 529 RequestPtr req1, req2; 530 assert(!req->isLLSC() && !req->isSwap()); 531 req->splitOnVaddr(split_addr, req1, req2); 532 533 WholeTranslationState *state = 534 new WholeTranslationState(req, req1, req2, newData, res, mode); 535 DataTranslation<TimingSimpleCPU *> *trans1 = 536 new DataTranslation<TimingSimpleCPU *>(this, state, 0); 537 DataTranslation<TimingSimpleCPU *> *trans2 = 538 new DataTranslation<TimingSimpleCPU *>(this, state, 1); 539 540 thread->dtb->translateTiming(req1, tc, trans1, mode); 541 thread->dtb->translateTiming(req2, tc, trans2, mode); 542 } else { 543 WholeTranslationState *state = 544 new WholeTranslationState(req, newData, res, mode); 545 DataTranslation<TimingSimpleCPU *> *translation = 546 new DataTranslation<TimingSimpleCPU *>(this, state); 547 thread->dtb->translateTiming(req, tc, translation, mode); 548 } 549 550 // Translation faults will be returned via finishTranslation() 551 return NoFault; 552} 553 554 555void 556TimingSimpleCPU::finishTranslation(WholeTranslationState *state) 557{ 558 _status = Running; 559 560 if (state->getFault() != NoFault) { 561 if (state->isPrefetch()) { 562 state->setNoFault(); 563 } 564 delete [] state->data; 565 state->deleteReqs(); 566 translationFault(state->getFault()); 567 } else { 568 if (!state->isSplit) { 569 sendData(state->mainReq, state->data, state->res, 570 state->mode == BaseTLB::Read); 571 } else { 572 sendSplitData(state->sreqLow, state->sreqHigh, state->mainReq, 573 state->data, state->mode == BaseTLB::Read); 574 } 575 } 576 577 delete state; 578} 579 580 581void 582TimingSimpleCPU::fetch() 583{ 584 DPRINTF(SimpleCPU, "Fetch\n"); 585 586 if (!curStaticInst || !curStaticInst->isDelayedCommit()) 587 checkForInterrupts(); 588 589 checkPcEventQueue(); 590 591 // We must have just got suspended by a PC event 592 if (_status == Idle) 593 return; 594 595 TheISA::PCState pcState = thread->pcState(); 596 bool needToFetch = !isRomMicroPC(pcState.microPC()) && !curMacroStaticInst; 597 598 if (needToFetch) { 599 _status = Running; 600 Request *ifetch_req = new Request(); 601 ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0); 602 setupFetchRequest(ifetch_req); 603 DPRINTF(SimpleCPU, "Translating address %#x\n", ifetch_req->getVaddr()); 604 thread->itb->translateTiming(ifetch_req, tc, &fetchTranslation, 605 BaseTLB::Execute); 606 } else { 607 _status = IcacheWaitResponse; 608 completeIfetch(NULL); 609 610 numCycles += tickToCycles(curTick() - previousTick); 611 previousTick = curTick(); 612 } 613} 614 615 616void 617TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc) 618{ 619 if (fault == NoFault) { 620 DPRINTF(SimpleCPU, "Sending fetch for addr %#x(pa: %#x)\n", 621 req->getVaddr(), req->getPaddr()); 622 ifetch_pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast); 623 ifetch_pkt->dataStatic(&inst); 624 DPRINTF(SimpleCPU, " -- pkt addr: %#x\n", ifetch_pkt->getAddr()); 625 626 if (!icachePort.sendTiming(ifetch_pkt)) { 627 // Need to wait for retry 628 _status = IcacheRetry; 629 } else { 630 // Need to wait for cache to respond 631 _status = IcacheWaitResponse; 632 // ownership of packet transferred to memory system 633 ifetch_pkt = NULL; 634 } 635 } else { 636 DPRINTF(SimpleCPU, "Translation of addr %#x faulted\n", req->getVaddr()); 637 delete req; 638 // fetch fault: advance directly to next instruction (fault handler) 639 _status = Running; 640 advanceInst(fault); 641 } 642 643 numCycles += tickToCycles(curTick() - previousTick); 644 previousTick = curTick(); 645} 646 647 648void 649TimingSimpleCPU::advanceInst(Fault fault) 650{ 651 652 if (_status == Faulting) 653 return; 654 655 if (fault != NoFault) { 656 advancePC(fault); 657 DPRINTF(SimpleCPU, "Fault occured, scheduling fetch event\n"); 658 reschedule(fetchEvent, nextCycle(), true); 659 _status = Faulting; 660 return; 661 } 662 663 664 if (!stayAtPC) 665 advancePC(fault); 666 667 if (_status == Running) { 668 // kick off fetch of next instruction... callback from icache 669 // response will cause that instruction to be executed, 670 // keeping the CPU running. 671 fetch(); 672 } 673} 674 675 676void 677TimingSimpleCPU::completeIfetch(PacketPtr pkt) 678{ 679 DPRINTF(SimpleCPU, "Complete ICache Fetch for addr %#x\n", pkt ? 680 pkt->getAddr() : 0); 681 682 // received a response from the icache: execute the received 683 // instruction 684 685 assert(!pkt || !pkt->isError()); 686 assert(_status == IcacheWaitResponse); 687 688 _status = Running; 689 690 numCycles += tickToCycles(curTick() - previousTick); 691 previousTick = curTick(); 692 693 if (getState() == SimObject::Draining) { 694 if (pkt) { 695 delete pkt->req; 696 delete pkt; 697 } 698 699 completeDrain(); 700 return; 701 } 702 703 preExecute(); 704 if (curStaticInst && curStaticInst->isMemRef()) { 705 // load or store: just send to dcache 706 Fault fault = curStaticInst->initiateAcc(this, traceData); 707 708 // If we're not running now the instruction will complete in a dcache 709 // response callback or the instruction faulted and has started an 710 // ifetch 711 if (_status == Running) { 712 if (fault != NoFault && traceData) { 713 // If there was a fault, we shouldn't trace this instruction. 714 delete traceData; 715 traceData = NULL; 716 } 717 718 postExecute(); 719 // @todo remove me after debugging with legion done 720 if (curStaticInst && (!curStaticInst->isMicroop() || 721 curStaticInst->isFirstMicroop())) 722 instCnt++; 723 advanceInst(fault); 724 } 725 } else if (curStaticInst) { 726 // non-memory instruction: execute completely now 727 Fault fault = curStaticInst->execute(this, traceData); 728 729 // keep an instruction count 730 if (fault == NoFault) 731 countInst(); 732 else if (traceData && !DTRACE(ExecFaulting)) { 733 delete traceData; 734 traceData = NULL; 735 } 736 737 postExecute(); 738 // @todo remove me after debugging with legion done 739 if (curStaticInst && (!curStaticInst->isMicroop() || 740 curStaticInst->isFirstMicroop())) 741 instCnt++; 742 advanceInst(fault); 743 } else { 744 advanceInst(NoFault); 745 } 746 747 if (pkt) { 748 delete pkt->req; 749 delete pkt; 750 } 751} 752 753void 754TimingSimpleCPU::IcachePort::ITickEvent::process() 755{ 756 cpu->completeIfetch(pkt); 757} 758 759bool 760TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt) 761{ 762 if (pkt->isResponse() && !pkt->wasNacked()) { 763 DPRINTF(SimpleCPU, "Received timing response %#x\n", pkt->getAddr()); 764 // delay processing of returned data until next CPU clock edge 765 Tick next_tick = cpu->nextCycle(curTick()); 766 767 if (next_tick == curTick()) 768 cpu->completeIfetch(pkt); 769 else 770 tickEvent.schedule(pkt, next_tick); 771 772 return true; 773 } else if (pkt->wasNacked()) { 774 assert(cpu->_status == IcacheWaitResponse); 775 pkt->reinitNacked(); 776 if (!sendTiming(pkt)) { 777 cpu->_status = IcacheRetry; 778 cpu->ifetch_pkt = pkt; 779 } 780 } 781 //Snooping a Coherence Request, do nothing 782 return true; 783} 784 785void 786TimingSimpleCPU::IcachePort::recvRetry() 787{ 788 // we shouldn't get a retry unless we have a packet that we're 789 // waiting to transmit 790 assert(cpu->ifetch_pkt != NULL); 791 assert(cpu->_status == IcacheRetry); 792 PacketPtr tmp = cpu->ifetch_pkt; 793 if (sendTiming(tmp)) { 794 cpu->_status = IcacheWaitResponse; 795 cpu->ifetch_pkt = NULL; 796 } 797} 798 799void 800TimingSimpleCPU::completeDataAccess(PacketPtr pkt) 801{ 802 // received a response from the dcache: complete the load or store 803 // instruction 804 assert(!pkt->isError()); 805 assert(_status == DcacheWaitResponse || _status == DTBWaitResponse || 806 pkt->req->getFlags().isSet(Request::NO_ACCESS)); 807 808 numCycles += tickToCycles(curTick() - previousTick); 809 previousTick = curTick(); 810 811 if (pkt->senderState) { 812 SplitFragmentSenderState * send_state = 813 dynamic_cast<SplitFragmentSenderState *>(pkt->senderState); 814 assert(send_state); 815 delete pkt->req; 816 delete pkt; 817 PacketPtr big_pkt = send_state->bigPkt; 818 delete send_state; 819 820 SplitMainSenderState * main_send_state = 821 dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); 822 assert(main_send_state); 823 // Record the fact that this packet is no longer outstanding. 824 assert(main_send_state->outstanding != 0); 825 main_send_state->outstanding--; 826 827 if (main_send_state->outstanding) { 828 return; 829 } else { 830 delete main_send_state; 831 big_pkt->senderState = NULL; 832 pkt = big_pkt; 833 } 834 } 835 836 _status = Running; 837 838 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 839 840 // keep an instruction count 841 if (fault == NoFault) 842 countInst(); 843 else if (traceData) { 844 // If there was a fault, we shouldn't trace this instruction. 845 delete traceData; 846 traceData = NULL; 847 } 848 849 // the locked flag may be cleared on the response packet, so check 850 // pkt->req and not pkt to see if it was a load-locked 851 if (pkt->isRead() && pkt->req->isLLSC()) { 852 TheISA::handleLockedRead(thread, pkt->req); 853 } 854 855 delete pkt->req; 856 delete pkt; 857 858 postExecute(); 859 860 if (getState() == SimObject::Draining) { 861 advancePC(fault); 862 completeDrain(); 863 864 return; 865 } 866 867 advanceInst(fault); 868} 869 870 871void 872TimingSimpleCPU::completeDrain() 873{ 874 DPRINTF(Config, "Done draining\n"); 875 changeState(SimObject::Drained); 876 drainEvent->process(); 877} 878
|