244 // kick things off by initiating the fetch of the next instruction 245 fetchEvent = 246 new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false); 247 fetchEvent->schedule(nextCycle(curTick + cycles(delay))); 248} 249 250 251void 252TimingSimpleCPU::suspendContext(int thread_num) 253{ 254 assert(thread_num == 0); 255 assert(thread); 256 257 assert(_status == Running); 258 259 // just change status to Idle... if status != Running, 260 // completeInst() will not initiate fetch of next instruction. 261 262 notIdleFraction--; 263 _status = Idle; 264} 265 266 267template <class T> 268Fault 269TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 270{ 271 Request *req = 272 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 273 cpu_id, /* thread ID */ 0); 274 275 if (traceData) { 276 traceData->setAddr(req->getVaddr()); 277 } 278 279 // translate to physical address 280 Fault fault = thread->translateDataReadReq(req); 281 282 // Now do the access. 283 if (fault == NoFault) { 284 PacketPtr pkt = 285 new Packet(req, Packet::ReadReq, Packet::Broadcast); 286 pkt->dataDynamic<T>(new T); 287 288 if (!dcachePort.sendTiming(pkt)) { 289 _status = DcacheRetry; 290 dcache_pkt = pkt; 291 } else { 292 _status = DcacheWaitResponse; 293 // memory system takes ownership of packet 294 dcache_pkt = NULL; 295 } 296 } else { 297 delete req; 298 } 299 300 // This will need a new way to tell if it has a dcache attached. 301 if (req->isUncacheable()) 302 recordEvent("Uncached Read"); 303 304 return fault; 305} 306 307#ifndef DOXYGEN_SHOULD_SKIP_THIS 308 309template 310Fault 311TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 312 313template 314Fault 315TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 316 317template 318Fault 319TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 320 321template 322Fault 323TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 324 325#endif //DOXYGEN_SHOULD_SKIP_THIS 326 327template<> 328Fault 329TimingSimpleCPU::read(Addr addr, double &data, unsigned flags) 330{ 331 return read(addr, *(uint64_t*)&data, flags); 332} 333 334template<> 335Fault 336TimingSimpleCPU::read(Addr addr, float &data, unsigned flags) 337{ 338 return read(addr, *(uint32_t*)&data, flags); 339} 340 341 342template<> 343Fault 344TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 345{ 346 return read(addr, (uint32_t&)data, flags); 347} 348 349 350template <class T> 351Fault 352TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 353{ 354 Request *req = 355 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 356 cpu_id, /* thread ID */ 0); 357 358 // translate to physical address 359 Fault fault = thread->translateDataWriteReq(req); 360 361 // Now do the access. 362 if (fault == NoFault) { 363 assert(dcache_pkt == NULL); 364 dcache_pkt = new Packet(req, Packet::WriteReq, Packet::Broadcast); 365 dcache_pkt->allocate(); 366 dcache_pkt->set(data); 367 368 bool do_access = true; // flag to suppress cache access 369 370 if (req->isLocked()) { 371 do_access = TheISA::handleLockedWrite(thread, req); 372 } 373 374 if (do_access) { 375 if (!dcachePort.sendTiming(dcache_pkt)) { 376 _status = DcacheRetry; 377 } else { 378 _status = DcacheWaitResponse; 379 // memory system takes ownership of packet 380 dcache_pkt = NULL; 381 } 382 } 383 } else { 384 delete req; 385 } 386 387 // This will need a new way to tell if it's hooked up to a cache or not. 388 if (req->isUncacheable()) 389 recordEvent("Uncached Write"); 390 391 // If the write needs to have a fault on the access, consider calling 392 // changeStatus() and changing it to "bad addr write" or something. 393 return fault; 394} 395 396 397#ifndef DOXYGEN_SHOULD_SKIP_THIS 398template 399Fault 400TimingSimpleCPU::write(uint64_t data, Addr addr, 401 unsigned flags, uint64_t *res); 402 403template 404Fault 405TimingSimpleCPU::write(uint32_t data, Addr addr, 406 unsigned flags, uint64_t *res); 407 408template 409Fault 410TimingSimpleCPU::write(uint16_t data, Addr addr, 411 unsigned flags, uint64_t *res); 412 413template 414Fault 415TimingSimpleCPU::write(uint8_t data, Addr addr, 416 unsigned flags, uint64_t *res); 417 418#endif //DOXYGEN_SHOULD_SKIP_THIS 419 420template<> 421Fault 422TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 423{ 424 return write(*(uint64_t*)&data, addr, flags, res); 425} 426 427template<> 428Fault 429TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 430{ 431 return write(*(uint32_t*)&data, addr, flags, res); 432} 433 434 435template<> 436Fault 437TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 438{ 439 return write((uint32_t)data, addr, flags, res); 440} 441 442 443void 444TimingSimpleCPU::fetch() 445{ 446 if (!curStaticInst || !curStaticInst->isDelayedCommit()) 447 checkForInterrupts(); 448 449 Request *ifetch_req = new Request(); 450 ifetch_req->setThreadContext(cpu_id, /* thread ID */ 0); 451 Fault fault = setupFetchRequest(ifetch_req); 452 453 ifetch_pkt = new Packet(ifetch_req, Packet::ReadReq, Packet::Broadcast); 454 ifetch_pkt->dataStatic(&inst); 455 456 if (fault == NoFault) { 457 if (!icachePort.sendTiming(ifetch_pkt)) { 458 // Need to wait for retry 459 _status = IcacheRetry; 460 } else { 461 // Need to wait for cache to respond 462 _status = IcacheWaitResponse; 463 // ownership of packet transferred to memory system 464 ifetch_pkt = NULL; 465 } 466 } else { 467 delete ifetch_req; 468 delete ifetch_pkt; 469 // fetch fault: advance directly to next instruction (fault handler) 470 advanceInst(fault); 471 } 472 473 numCycles += curTick - previousTick; 474 previousTick = curTick; 475} 476 477 478void 479TimingSimpleCPU::advanceInst(Fault fault) 480{ 481 advancePC(fault); 482 483 if (_status == Running) { 484 // kick off fetch of next instruction... callback from icache 485 // response will cause that instruction to be executed, 486 // keeping the CPU running. 487 fetch(); 488 } 489} 490 491 492void 493TimingSimpleCPU::completeIfetch(PacketPtr pkt) 494{ 495 // received a response from the icache: execute the received 496 // instruction 497 assert(pkt->result == Packet::Success); 498 assert(_status == IcacheWaitResponse); 499 500 _status = Running; 501 502 numCycles += curTick - previousTick; 503 previousTick = curTick; 504 505 if (getState() == SimObject::Draining) { 506 delete pkt->req; 507 delete pkt; 508 509 completeDrain(); 510 return; 511 } 512 513 preExecute(); 514 if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { 515 // load or store: just send to dcache 516 Fault fault = curStaticInst->initiateAcc(this, traceData); 517 if (_status != Running) { 518 // instruction will complete in dcache response callback 519 assert(_status == DcacheWaitResponse || _status == DcacheRetry); 520 assert(fault == NoFault); 521 } else { 522 if (fault == NoFault) { 523 // early fail on store conditional: complete now 524 assert(dcache_pkt != NULL); 525 fault = curStaticInst->completeAcc(dcache_pkt, this, 526 traceData); 527 delete dcache_pkt->req; 528 delete dcache_pkt; 529 dcache_pkt = NULL; 530 } 531 postExecute(); 532 advanceInst(fault); 533 } 534 } else { 535 // non-memory instruction: execute completely now 536 Fault fault = curStaticInst->execute(this, traceData); 537 postExecute(); 538 advanceInst(fault); 539 } 540 541 delete pkt->req; 542 delete pkt; 543} 544 545void 546TimingSimpleCPU::IcachePort::ITickEvent::process() 547{ 548 cpu->completeIfetch(pkt); 549} 550 551bool 552TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt) 553{ 554 if (pkt->isResponse()) { 555 // delay processing of returned data until next CPU clock edge 556 Tick mem_time = pkt->req->getTime(); 557 Tick next_tick = cpu->nextCycle(mem_time); 558 559 if (next_tick == curTick) 560 cpu->completeIfetch(pkt); 561 else 562 tickEvent.schedule(pkt, next_tick); 563 564 return true; 565 } 566 else { 567 //Snooping a Coherence Request, do nothing 568 return true; 569 } 570} 571 572void 573TimingSimpleCPU::IcachePort::recvRetry() 574{ 575 // we shouldn't get a retry unless we have a packet that we're 576 // waiting to transmit 577 assert(cpu->ifetch_pkt != NULL); 578 assert(cpu->_status == IcacheRetry); 579 PacketPtr tmp = cpu->ifetch_pkt; 580 if (sendTiming(tmp)) { 581 cpu->_status = IcacheWaitResponse; 582 cpu->ifetch_pkt = NULL; 583 } 584} 585 586void 587TimingSimpleCPU::completeDataAccess(PacketPtr pkt) 588{ 589 // received a response from the dcache: complete the load or store 590 // instruction 591 assert(pkt->result == Packet::Success); 592 assert(_status == DcacheWaitResponse); 593 _status = Running; 594 595 numCycles += curTick - previousTick; 596 previousTick = curTick; 597 598 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 599 600 if (pkt->isRead() && pkt->req->isLocked()) { 601 TheISA::handleLockedRead(thread, pkt->req); 602 } 603 604 delete pkt->req; 605 delete pkt; 606 607 postExecute(); 608 609 if (getState() == SimObject::Draining) { 610 advancePC(fault); 611 completeDrain(); 612 613 return; 614 } 615 616 advanceInst(fault); 617} 618 619 620void 621TimingSimpleCPU::completeDrain() 622{ 623 DPRINTF(Config, "Done draining\n"); 624 changeState(SimObject::Drained); 625 drainEvent->process(); 626} 627 628bool 629TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt) 630{ 631 if (pkt->isResponse()) { 632 // delay processing of returned data until next CPU clock edge 633 Tick mem_time = pkt->req->getTime(); 634 Tick next_tick = cpu->nextCycle(mem_time); 635 636 if (next_tick == curTick) 637 cpu->completeDataAccess(pkt); 638 else 639 tickEvent.schedule(pkt, next_tick); 640 641 return true; 642 } 643 else { 644 //Snooping a coherence req, do nothing 645 return true; 646 } 647} 648 649void 650TimingSimpleCPU::DcachePort::DTickEvent::process() 651{ 652 cpu->completeDataAccess(pkt); 653} 654 655void 656TimingSimpleCPU::DcachePort::recvRetry() 657{ 658 // we shouldn't get a retry unless we have a packet that we're 659 // waiting to transmit 660 assert(cpu->dcache_pkt != NULL); 661 assert(cpu->_status == DcacheRetry); 662 PacketPtr tmp = cpu->dcache_pkt; 663 if (sendTiming(tmp)) { 664 cpu->_status = DcacheWaitResponse; 665 // memory system takes ownership of packet 666 cpu->dcache_pkt = NULL; 667 } 668} 669 670 671//////////////////////////////////////////////////////////////////////// 672// 673// TimingSimpleCPU Simulation Object 674// 675BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 676 677 Param<Counter> max_insts_any_thread; 678 Param<Counter> max_insts_all_threads; 679 Param<Counter> max_loads_any_thread; 680 Param<Counter> max_loads_all_threads; 681 Param<Tick> progress_interval; 682 SimObjectParam<System *> system; 683 Param<int> cpu_id; 684 685#if FULL_SYSTEM 686 SimObjectParam<TheISA::ITB *> itb; 687 SimObjectParam<TheISA::DTB *> dtb; 688 Param<Tick> profile; 689 690 Param<bool> do_quiesce; 691 Param<bool> do_checkpoint_insts; 692 Param<bool> do_statistics_insts; 693#else 694 SimObjectParam<Process *> workload; 695#endif // FULL_SYSTEM 696 697 Param<int> clock; 698 Param<int> phase; 699 700 Param<bool> defer_registration; 701 Param<int> width; 702 Param<bool> function_trace; 703 Param<Tick> function_trace_start; 704 Param<bool> simulate_stalls; 705 706END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 707 708BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 709 710 INIT_PARAM(max_insts_any_thread, 711 "terminate when any thread reaches this inst count"), 712 INIT_PARAM(max_insts_all_threads, 713 "terminate when all threads have reached this inst count"), 714 INIT_PARAM(max_loads_any_thread, 715 "terminate when any thread reaches this load count"), 716 INIT_PARAM(max_loads_all_threads, 717 "terminate when all threads have reached this load count"), 718 INIT_PARAM(progress_interval, "Progress interval"), 719 INIT_PARAM(system, "system object"), 720 INIT_PARAM(cpu_id, "processor ID"), 721 722#if FULL_SYSTEM 723 INIT_PARAM(itb, "Instruction TLB"), 724 INIT_PARAM(dtb, "Data TLB"), 725 INIT_PARAM(profile, ""), 726 INIT_PARAM(do_quiesce, ""), 727 INIT_PARAM(do_checkpoint_insts, ""), 728 INIT_PARAM(do_statistics_insts, ""), 729#else 730 INIT_PARAM(workload, "processes to run"), 731#endif // FULL_SYSTEM 732 733 INIT_PARAM(clock, "clock speed"), 734 INIT_PARAM_DFLT(phase, "clock phase", 0), 735 INIT_PARAM(defer_registration, "defer system registration (for sampling)"), 736 INIT_PARAM(width, "cpu width"), 737 INIT_PARAM(function_trace, "Enable function trace"), 738 INIT_PARAM(function_trace_start, "Cycle to start function trace"), 739 INIT_PARAM(simulate_stalls, "Simulate cache stall cycles") 740 741END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 742 743 744CREATE_SIM_OBJECT(TimingSimpleCPU) 745{ 746 TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params(); 747 params->name = getInstanceName(); 748 params->numberOfThreads = 1; 749 params->max_insts_any_thread = max_insts_any_thread; 750 params->max_insts_all_threads = max_insts_all_threads; 751 params->max_loads_any_thread = max_loads_any_thread; 752 params->max_loads_all_threads = max_loads_all_threads; 753 params->progress_interval = progress_interval; 754 params->deferRegistration = defer_registration; 755 params->clock = clock; 756 params->phase = phase; 757 params->functionTrace = function_trace; 758 params->functionTraceStart = function_trace_start; 759 params->system = system; 760 params->cpu_id = cpu_id; 761 762#if FULL_SYSTEM 763 params->itb = itb; 764 params->dtb = dtb; 765 params->profile = profile; 766 params->do_quiesce = do_quiesce; 767 params->do_checkpoint_insts = do_checkpoint_insts; 768 params->do_statistics_insts = do_statistics_insts; 769#else 770 params->process = workload; 771#endif 772 773 TimingSimpleCPU *cpu = new TimingSimpleCPU(params); 774 return cpu; 775} 776 777REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU) 778
| 248 // kick things off by initiating the fetch of the next instruction 249 fetchEvent = 250 new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false); 251 fetchEvent->schedule(nextCycle(curTick + cycles(delay))); 252} 253 254 255void 256TimingSimpleCPU::suspendContext(int thread_num) 257{ 258 assert(thread_num == 0); 259 assert(thread); 260 261 assert(_status == Running); 262 263 // just change status to Idle... if status != Running, 264 // completeInst() will not initiate fetch of next instruction. 265 266 notIdleFraction--; 267 _status = Idle; 268} 269 270 271template <class T> 272Fault 273TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 274{ 275 Request *req = 276 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 277 cpu_id, /* thread ID */ 0); 278 279 if (traceData) { 280 traceData->setAddr(req->getVaddr()); 281 } 282 283 // translate to physical address 284 Fault fault = thread->translateDataReadReq(req); 285 286 // Now do the access. 287 if (fault == NoFault) { 288 PacketPtr pkt = 289 new Packet(req, Packet::ReadReq, Packet::Broadcast); 290 pkt->dataDynamic<T>(new T); 291 292 if (!dcachePort.sendTiming(pkt)) { 293 _status = DcacheRetry; 294 dcache_pkt = pkt; 295 } else { 296 _status = DcacheWaitResponse; 297 // memory system takes ownership of packet 298 dcache_pkt = NULL; 299 } 300 } else { 301 delete req; 302 } 303 304 // This will need a new way to tell if it has a dcache attached. 305 if (req->isUncacheable()) 306 recordEvent("Uncached Read"); 307 308 return fault; 309} 310 311#ifndef DOXYGEN_SHOULD_SKIP_THIS 312 313template 314Fault 315TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 316 317template 318Fault 319TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 320 321template 322Fault 323TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 324 325template 326Fault 327TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 328 329#endif //DOXYGEN_SHOULD_SKIP_THIS 330 331template<> 332Fault 333TimingSimpleCPU::read(Addr addr, double &data, unsigned flags) 334{ 335 return read(addr, *(uint64_t*)&data, flags); 336} 337 338template<> 339Fault 340TimingSimpleCPU::read(Addr addr, float &data, unsigned flags) 341{ 342 return read(addr, *(uint32_t*)&data, flags); 343} 344 345 346template<> 347Fault 348TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 349{ 350 return read(addr, (uint32_t&)data, flags); 351} 352 353 354template <class T> 355Fault 356TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 357{ 358 Request *req = 359 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 360 cpu_id, /* thread ID */ 0); 361 362 // translate to physical address 363 Fault fault = thread->translateDataWriteReq(req); 364 365 // Now do the access. 366 if (fault == NoFault) { 367 assert(dcache_pkt == NULL); 368 dcache_pkt = new Packet(req, Packet::WriteReq, Packet::Broadcast); 369 dcache_pkt->allocate(); 370 dcache_pkt->set(data); 371 372 bool do_access = true; // flag to suppress cache access 373 374 if (req->isLocked()) { 375 do_access = TheISA::handleLockedWrite(thread, req); 376 } 377 378 if (do_access) { 379 if (!dcachePort.sendTiming(dcache_pkt)) { 380 _status = DcacheRetry; 381 } else { 382 _status = DcacheWaitResponse; 383 // memory system takes ownership of packet 384 dcache_pkt = NULL; 385 } 386 } 387 } else { 388 delete req; 389 } 390 391 // This will need a new way to tell if it's hooked up to a cache or not. 392 if (req->isUncacheable()) 393 recordEvent("Uncached Write"); 394 395 // If the write needs to have a fault on the access, consider calling 396 // changeStatus() and changing it to "bad addr write" or something. 397 return fault; 398} 399 400 401#ifndef DOXYGEN_SHOULD_SKIP_THIS 402template 403Fault 404TimingSimpleCPU::write(uint64_t data, Addr addr, 405 unsigned flags, uint64_t *res); 406 407template 408Fault 409TimingSimpleCPU::write(uint32_t data, Addr addr, 410 unsigned flags, uint64_t *res); 411 412template 413Fault 414TimingSimpleCPU::write(uint16_t data, Addr addr, 415 unsigned flags, uint64_t *res); 416 417template 418Fault 419TimingSimpleCPU::write(uint8_t data, Addr addr, 420 unsigned flags, uint64_t *res); 421 422#endif //DOXYGEN_SHOULD_SKIP_THIS 423 424template<> 425Fault 426TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 427{ 428 return write(*(uint64_t*)&data, addr, flags, res); 429} 430 431template<> 432Fault 433TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 434{ 435 return write(*(uint32_t*)&data, addr, flags, res); 436} 437 438 439template<> 440Fault 441TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 442{ 443 return write((uint32_t)data, addr, flags, res); 444} 445 446 447void 448TimingSimpleCPU::fetch() 449{ 450 if (!curStaticInst || !curStaticInst->isDelayedCommit()) 451 checkForInterrupts(); 452 453 Request *ifetch_req = new Request(); 454 ifetch_req->setThreadContext(cpu_id, /* thread ID */ 0); 455 Fault fault = setupFetchRequest(ifetch_req); 456 457 ifetch_pkt = new Packet(ifetch_req, Packet::ReadReq, Packet::Broadcast); 458 ifetch_pkt->dataStatic(&inst); 459 460 if (fault == NoFault) { 461 if (!icachePort.sendTiming(ifetch_pkt)) { 462 // Need to wait for retry 463 _status = IcacheRetry; 464 } else { 465 // Need to wait for cache to respond 466 _status = IcacheWaitResponse; 467 // ownership of packet transferred to memory system 468 ifetch_pkt = NULL; 469 } 470 } else { 471 delete ifetch_req; 472 delete ifetch_pkt; 473 // fetch fault: advance directly to next instruction (fault handler) 474 advanceInst(fault); 475 } 476 477 numCycles += curTick - previousTick; 478 previousTick = curTick; 479} 480 481 482void 483TimingSimpleCPU::advanceInst(Fault fault) 484{ 485 advancePC(fault); 486 487 if (_status == Running) { 488 // kick off fetch of next instruction... callback from icache 489 // response will cause that instruction to be executed, 490 // keeping the CPU running. 491 fetch(); 492 } 493} 494 495 496void 497TimingSimpleCPU::completeIfetch(PacketPtr pkt) 498{ 499 // received a response from the icache: execute the received 500 // instruction 501 assert(pkt->result == Packet::Success); 502 assert(_status == IcacheWaitResponse); 503 504 _status = Running; 505 506 numCycles += curTick - previousTick; 507 previousTick = curTick; 508 509 if (getState() == SimObject::Draining) { 510 delete pkt->req; 511 delete pkt; 512 513 completeDrain(); 514 return; 515 } 516 517 preExecute(); 518 if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { 519 // load or store: just send to dcache 520 Fault fault = curStaticInst->initiateAcc(this, traceData); 521 if (_status != Running) { 522 // instruction will complete in dcache response callback 523 assert(_status == DcacheWaitResponse || _status == DcacheRetry); 524 assert(fault == NoFault); 525 } else { 526 if (fault == NoFault) { 527 // early fail on store conditional: complete now 528 assert(dcache_pkt != NULL); 529 fault = curStaticInst->completeAcc(dcache_pkt, this, 530 traceData); 531 delete dcache_pkt->req; 532 delete dcache_pkt; 533 dcache_pkt = NULL; 534 } 535 postExecute(); 536 advanceInst(fault); 537 } 538 } else { 539 // non-memory instruction: execute completely now 540 Fault fault = curStaticInst->execute(this, traceData); 541 postExecute(); 542 advanceInst(fault); 543 } 544 545 delete pkt->req; 546 delete pkt; 547} 548 549void 550TimingSimpleCPU::IcachePort::ITickEvent::process() 551{ 552 cpu->completeIfetch(pkt); 553} 554 555bool 556TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt) 557{ 558 if (pkt->isResponse()) { 559 // delay processing of returned data until next CPU clock edge 560 Tick mem_time = pkt->req->getTime(); 561 Tick next_tick = cpu->nextCycle(mem_time); 562 563 if (next_tick == curTick) 564 cpu->completeIfetch(pkt); 565 else 566 tickEvent.schedule(pkt, next_tick); 567 568 return true; 569 } 570 else { 571 //Snooping a Coherence Request, do nothing 572 return true; 573 } 574} 575 576void 577TimingSimpleCPU::IcachePort::recvRetry() 578{ 579 // we shouldn't get a retry unless we have a packet that we're 580 // waiting to transmit 581 assert(cpu->ifetch_pkt != NULL); 582 assert(cpu->_status == IcacheRetry); 583 PacketPtr tmp = cpu->ifetch_pkt; 584 if (sendTiming(tmp)) { 585 cpu->_status = IcacheWaitResponse; 586 cpu->ifetch_pkt = NULL; 587 } 588} 589 590void 591TimingSimpleCPU::completeDataAccess(PacketPtr pkt) 592{ 593 // received a response from the dcache: complete the load or store 594 // instruction 595 assert(pkt->result == Packet::Success); 596 assert(_status == DcacheWaitResponse); 597 _status = Running; 598 599 numCycles += curTick - previousTick; 600 previousTick = curTick; 601 602 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 603 604 if (pkt->isRead() && pkt->req->isLocked()) { 605 TheISA::handleLockedRead(thread, pkt->req); 606 } 607 608 delete pkt->req; 609 delete pkt; 610 611 postExecute(); 612 613 if (getState() == SimObject::Draining) { 614 advancePC(fault); 615 completeDrain(); 616 617 return; 618 } 619 620 advanceInst(fault); 621} 622 623 624void 625TimingSimpleCPU::completeDrain() 626{ 627 DPRINTF(Config, "Done draining\n"); 628 changeState(SimObject::Drained); 629 drainEvent->process(); 630} 631 632bool 633TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt) 634{ 635 if (pkt->isResponse()) { 636 // delay processing of returned data until next CPU clock edge 637 Tick mem_time = pkt->req->getTime(); 638 Tick next_tick = cpu->nextCycle(mem_time); 639 640 if (next_tick == curTick) 641 cpu->completeDataAccess(pkt); 642 else 643 tickEvent.schedule(pkt, next_tick); 644 645 return true; 646 } 647 else { 648 //Snooping a coherence req, do nothing 649 return true; 650 } 651} 652 653void 654TimingSimpleCPU::DcachePort::DTickEvent::process() 655{ 656 cpu->completeDataAccess(pkt); 657} 658 659void 660TimingSimpleCPU::DcachePort::recvRetry() 661{ 662 // we shouldn't get a retry unless we have a packet that we're 663 // waiting to transmit 664 assert(cpu->dcache_pkt != NULL); 665 assert(cpu->_status == DcacheRetry); 666 PacketPtr tmp = cpu->dcache_pkt; 667 if (sendTiming(tmp)) { 668 cpu->_status = DcacheWaitResponse; 669 // memory system takes ownership of packet 670 cpu->dcache_pkt = NULL; 671 } 672} 673 674 675//////////////////////////////////////////////////////////////////////// 676// 677// TimingSimpleCPU Simulation Object 678// 679BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 680 681 Param<Counter> max_insts_any_thread; 682 Param<Counter> max_insts_all_threads; 683 Param<Counter> max_loads_any_thread; 684 Param<Counter> max_loads_all_threads; 685 Param<Tick> progress_interval; 686 SimObjectParam<System *> system; 687 Param<int> cpu_id; 688 689#if FULL_SYSTEM 690 SimObjectParam<TheISA::ITB *> itb; 691 SimObjectParam<TheISA::DTB *> dtb; 692 Param<Tick> profile; 693 694 Param<bool> do_quiesce; 695 Param<bool> do_checkpoint_insts; 696 Param<bool> do_statistics_insts; 697#else 698 SimObjectParam<Process *> workload; 699#endif // FULL_SYSTEM 700 701 Param<int> clock; 702 Param<int> phase; 703 704 Param<bool> defer_registration; 705 Param<int> width; 706 Param<bool> function_trace; 707 Param<Tick> function_trace_start; 708 Param<bool> simulate_stalls; 709 710END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 711 712BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 713 714 INIT_PARAM(max_insts_any_thread, 715 "terminate when any thread reaches this inst count"), 716 INIT_PARAM(max_insts_all_threads, 717 "terminate when all threads have reached this inst count"), 718 INIT_PARAM(max_loads_any_thread, 719 "terminate when any thread reaches this load count"), 720 INIT_PARAM(max_loads_all_threads, 721 "terminate when all threads have reached this load count"), 722 INIT_PARAM(progress_interval, "Progress interval"), 723 INIT_PARAM(system, "system object"), 724 INIT_PARAM(cpu_id, "processor ID"), 725 726#if FULL_SYSTEM 727 INIT_PARAM(itb, "Instruction TLB"), 728 INIT_PARAM(dtb, "Data TLB"), 729 INIT_PARAM(profile, ""), 730 INIT_PARAM(do_quiesce, ""), 731 INIT_PARAM(do_checkpoint_insts, ""), 732 INIT_PARAM(do_statistics_insts, ""), 733#else 734 INIT_PARAM(workload, "processes to run"), 735#endif // FULL_SYSTEM 736 737 INIT_PARAM(clock, "clock speed"), 738 INIT_PARAM_DFLT(phase, "clock phase", 0), 739 INIT_PARAM(defer_registration, "defer system registration (for sampling)"), 740 INIT_PARAM(width, "cpu width"), 741 INIT_PARAM(function_trace, "Enable function trace"), 742 INIT_PARAM(function_trace_start, "Cycle to start function trace"), 743 INIT_PARAM(simulate_stalls, "Simulate cache stall cycles") 744 745END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 746 747 748CREATE_SIM_OBJECT(TimingSimpleCPU) 749{ 750 TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params(); 751 params->name = getInstanceName(); 752 params->numberOfThreads = 1; 753 params->max_insts_any_thread = max_insts_any_thread; 754 params->max_insts_all_threads = max_insts_all_threads; 755 params->max_loads_any_thread = max_loads_any_thread; 756 params->max_loads_all_threads = max_loads_all_threads; 757 params->progress_interval = progress_interval; 758 params->deferRegistration = defer_registration; 759 params->clock = clock; 760 params->phase = phase; 761 params->functionTrace = function_trace; 762 params->functionTraceStart = function_trace_start; 763 params->system = system; 764 params->cpu_id = cpu_id; 765 766#if FULL_SYSTEM 767 params->itb = itb; 768 params->dtb = dtb; 769 params->profile = profile; 770 params->do_quiesce = do_quiesce; 771 params->do_checkpoint_insts = do_checkpoint_insts; 772 params->do_statistics_insts = do_statistics_insts; 773#else 774 params->process = workload; 775#endif 776 777 TimingSimpleCPU *cpu = new TimingSimpleCPU(params); 778 return cpu; 779} 780 781REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU) 782
|