1/* 2 * Copyright (c) 2002-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Steve Reinhardt 29 */ 30 31#include "arch/locked_mem.hh" 32#include "arch/utility.hh" 33#include "cpu/exetrace.hh" 34#include "cpu/simple/timing.hh" 35#include "mem/packet.hh" 36#include "mem/packet_access.hh" 37#include "sim/builder.hh" 38#include "sim/system.hh" 39 40using namespace std; 41using namespace TheISA; 42 43Port * 44TimingSimpleCPU::getPort(const std::string &if_name, int idx) 45{ 46 if (if_name == "dcache_port") 47 return &dcachePort; 48 else if (if_name == "icache_port") 49 return &icachePort; 50 else 51 panic("No Such Port\n"); 52} 53 54void 55TimingSimpleCPU::init() 56{ 57 BaseCPU::init(); 58#if FULL_SYSTEM 59 for (int i = 0; i < threadContexts.size(); ++i) { 60 ThreadContext *tc = threadContexts[i]; 61 62 // initialize CPU, including PC 63 TheISA::initCPU(tc, tc->readCpuId()); 64 } 65#endif 66} 67 68Tick 69TimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) 70{ 71 panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 72 return curTick; 73} 74 75void 76TimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) 77{ 78 //No internal storage to update, jusst return 79 return; 80} 81 82void 83TimingSimpleCPU::CpuPort::recvStatusChange(Status status) 84{
| 1/* 2 * Copyright (c) 2002-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Steve Reinhardt 29 */ 30 31#include "arch/locked_mem.hh" 32#include "arch/utility.hh" 33#include "cpu/exetrace.hh" 34#include "cpu/simple/timing.hh" 35#include "mem/packet.hh" 36#include "mem/packet_access.hh" 37#include "sim/builder.hh" 38#include "sim/system.hh" 39 40using namespace std; 41using namespace TheISA; 42 43Port * 44TimingSimpleCPU::getPort(const std::string &if_name, int idx) 45{ 46 if (if_name == "dcache_port") 47 return &dcachePort; 48 else if (if_name == "icache_port") 49 return &icachePort; 50 else 51 panic("No Such Port\n"); 52} 53 54void 55TimingSimpleCPU::init() 56{ 57 BaseCPU::init(); 58#if FULL_SYSTEM 59 for (int i = 0; i < threadContexts.size(); ++i) { 60 ThreadContext *tc = threadContexts[i]; 61 62 // initialize CPU, including PC 63 TheISA::initCPU(tc, tc->readCpuId()); 64 } 65#endif 66} 67 68Tick 69TimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) 70{ 71 panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 72 return curTick; 73} 74 75void 76TimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) 77{ 78 //No internal storage to update, jusst return 79 return; 80} 81 82void 83TimingSimpleCPU::CpuPort::recvStatusChange(Status status) 84{
|
104 ifetch_pkt = dcache_pkt = NULL; 105 drainEvent = NULL; 106 fetchEvent = NULL; 107 previousTick = 0; 108 changeState(SimObject::Running); 109} 110 111 112TimingSimpleCPU::~TimingSimpleCPU() 113{ 114} 115 116void 117TimingSimpleCPU::serialize(ostream &os) 118{ 119 SimObject::State so_state = SimObject::getState(); 120 SERIALIZE_ENUM(so_state); 121 BaseSimpleCPU::serialize(os); 122} 123 124void 125TimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 126{ 127 SimObject::State so_state; 128 UNSERIALIZE_ENUM(so_state); 129 BaseSimpleCPU::unserialize(cp, section); 130} 131 132unsigned int 133TimingSimpleCPU::drain(Event *drain_event) 134{ 135 // TimingSimpleCPU is ready to drain if it's not waiting for 136 // an access to complete. 137 if (status() == Idle || status() == Running || status() == SwitchedOut) { 138 changeState(SimObject::Drained); 139 return 0; 140 } else { 141 changeState(SimObject::Draining); 142 drainEvent = drain_event; 143 return 1; 144 } 145} 146 147void 148TimingSimpleCPU::resume() 149{ 150 if (_status != SwitchedOut && _status != Idle) { 151 assert(system->getMemoryMode() == System::Timing); 152 153 // Delete the old event if it existed. 154 if (fetchEvent) { 155 if (fetchEvent->scheduled()) 156 fetchEvent->deschedule(); 157 158 delete fetchEvent; 159 } 160 161 fetchEvent = 162 new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false); 163 fetchEvent->schedule(curTick); 164 } 165 166 changeState(SimObject::Running); 167 previousTick = curTick; 168} 169 170void 171TimingSimpleCPU::switchOut() 172{ 173 assert(status() == Running || status() == Idle); 174 _status = SwitchedOut; 175 numCycles += curTick - previousTick; 176 177 // If we've been scheduled to resume but are then told to switch out, 178 // we'll need to cancel it. 179 if (fetchEvent && fetchEvent->scheduled()) 180 fetchEvent->deschedule(); 181} 182 183 184void 185TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 186{ 187 BaseCPU::takeOverFrom(oldCPU); 188 189 // if any of this CPU's ThreadContexts are active, mark the CPU as 190 // running and schedule its tick event. 191 for (int i = 0; i < threadContexts.size(); ++i) { 192 ThreadContext *tc = threadContexts[i]; 193 if (tc->status() == ThreadContext::Active && _status != Running) { 194 _status = Running; 195 break; 196 } 197 } 198 199 if (_status != Running) { 200 _status = Idle; 201 } 202 203 Port *peer; 204 if (icachePort.getPeer() == NULL) { 205 peer = oldCPU->getPort("icache_port")->getPeer(); 206 icachePort.setPeer(peer); 207 } else { 208 peer = icachePort.getPeer(); 209 } 210 peer->setPeer(&icachePort); 211 212 if (dcachePort.getPeer() == NULL) { 213 peer = oldCPU->getPort("dcache_port")->getPeer(); 214 dcachePort.setPeer(peer); 215 } else { 216 peer = dcachePort.getPeer(); 217 } 218 peer->setPeer(&dcachePort); 219} 220 221 222void 223TimingSimpleCPU::activateContext(int thread_num, int delay) 224{ 225 assert(thread_num == 0); 226 assert(thread); 227 228 assert(_status == Idle); 229 230 notIdleFraction++; 231 _status = Running; 232 // kick things off by initiating the fetch of the next instruction 233 fetchEvent = 234 new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false); 235 fetchEvent->schedule(curTick + cycles(delay)); 236} 237 238 239void 240TimingSimpleCPU::suspendContext(int thread_num) 241{ 242 assert(thread_num == 0); 243 assert(thread); 244 245 assert(_status == Running); 246 247 // just change status to Idle... if status != Running, 248 // completeInst() will not initiate fetch of next instruction. 249 250 notIdleFraction--; 251 _status = Idle; 252} 253 254 255template <class T> 256Fault 257TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 258{ 259 Request *req = 260 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 261 cpu_id, /* thread ID */ 0); 262 263 if (traceData) { 264 traceData->setAddr(req->getVaddr()); 265 } 266 267 // translate to physical address 268 Fault fault = thread->translateDataReadReq(req); 269 270 // Now do the access. 271 if (fault == NoFault) { 272 PacketPtr pkt = 273 new Packet(req, Packet::ReadReq, Packet::Broadcast); 274 pkt->dataDynamic<T>(new T); 275 276 if (!dcachePort.sendTiming(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 } 285 286 // This will need a new way to tell if it has a dcache attached. 287 if (req->isUncacheable()) 288 recordEvent("Uncached Read"); 289 290 return fault; 291} 292 293#ifndef DOXYGEN_SHOULD_SKIP_THIS 294 295template 296Fault 297TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 298 299template 300Fault 301TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 302 303template 304Fault 305TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 306 307template 308Fault 309TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 310 311#endif //DOXYGEN_SHOULD_SKIP_THIS 312 313template<> 314Fault 315TimingSimpleCPU::read(Addr addr, double &data, unsigned flags) 316{ 317 return read(addr, *(uint64_t*)&data, flags); 318} 319 320template<> 321Fault 322TimingSimpleCPU::read(Addr addr, float &data, unsigned flags) 323{ 324 return read(addr, *(uint32_t*)&data, flags); 325} 326 327 328template<> 329Fault 330TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 331{ 332 return read(addr, (uint32_t&)data, flags); 333} 334 335 336template <class T> 337Fault 338TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 339{ 340 Request *req = 341 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 342 cpu_id, /* thread ID */ 0); 343 344 // translate to physical address 345 Fault fault = thread->translateDataWriteReq(req); 346 347 // Now do the access. 348 if (fault == NoFault) { 349 assert(dcache_pkt == NULL); 350 dcache_pkt = new Packet(req, Packet::WriteReq, Packet::Broadcast); 351 dcache_pkt->allocate(); 352 dcache_pkt->set(data); 353 354 bool do_access = true; // flag to suppress cache access 355 356 if (req->isLocked()) { 357 do_access = TheISA::handleLockedWrite(thread, req); 358 } 359 360 if (do_access) { 361 if (!dcachePort.sendTiming(dcache_pkt)) { 362 _status = DcacheRetry; 363 } else { 364 _status = DcacheWaitResponse; 365 // memory system takes ownership of packet 366 dcache_pkt = NULL; 367 } 368 } 369 } 370 371 // This will need a new way to tell if it's hooked up to a cache or not. 372 if (req->isUncacheable()) 373 recordEvent("Uncached Write"); 374 375 // If the write needs to have a fault on the access, consider calling 376 // changeStatus() and changing it to "bad addr write" or something. 377 return fault; 378} 379 380 381#ifndef DOXYGEN_SHOULD_SKIP_THIS 382template 383Fault 384TimingSimpleCPU::write(uint64_t data, Addr addr, 385 unsigned flags, uint64_t *res); 386 387template 388Fault 389TimingSimpleCPU::write(uint32_t data, Addr addr, 390 unsigned flags, uint64_t *res); 391 392template 393Fault 394TimingSimpleCPU::write(uint16_t data, Addr addr, 395 unsigned flags, uint64_t *res); 396 397template 398Fault 399TimingSimpleCPU::write(uint8_t data, Addr addr, 400 unsigned flags, uint64_t *res); 401 402#endif //DOXYGEN_SHOULD_SKIP_THIS 403 404template<> 405Fault 406TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 407{ 408 return write(*(uint64_t*)&data, addr, flags, res); 409} 410 411template<> 412Fault 413TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 414{ 415 return write(*(uint32_t*)&data, addr, flags, res); 416} 417 418 419template<> 420Fault 421TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 422{ 423 return write((uint32_t)data, addr, flags, res); 424} 425 426 427void 428TimingSimpleCPU::fetch() 429{ 430 if (!curStaticInst || !curStaticInst->isDelayedCommit()) 431 checkForInterrupts(); 432 433 Request *ifetch_req = new Request(); 434 ifetch_req->setThreadContext(cpu_id, /* thread ID */ 0); 435 Fault fault = setupFetchRequest(ifetch_req); 436 437 ifetch_pkt = new Packet(ifetch_req, Packet::ReadReq, Packet::Broadcast); 438 ifetch_pkt->dataStatic(&inst); 439 440 if (fault == NoFault) { 441 if (!icachePort.sendTiming(ifetch_pkt)) { 442 // Need to wait for retry 443 _status = IcacheRetry; 444 } else { 445 // Need to wait for cache to respond 446 _status = IcacheWaitResponse; 447 // ownership of packet transferred to memory system 448 ifetch_pkt = NULL; 449 } 450 } else { 451 // fetch fault: advance directly to next instruction (fault handler) 452 advanceInst(fault); 453 } 454 455 numCycles += curTick - previousTick; 456 previousTick = curTick; 457} 458 459 460void 461TimingSimpleCPU::advanceInst(Fault fault) 462{ 463 advancePC(fault); 464 465 if (_status == Running) { 466 // kick off fetch of next instruction... callback from icache 467 // response will cause that instruction to be executed, 468 // keeping the CPU running. 469 fetch(); 470 } 471} 472 473 474void 475TimingSimpleCPU::completeIfetch(PacketPtr pkt) 476{ 477 // received a response from the icache: execute the received 478 // instruction 479 assert(pkt->result == Packet::Success); 480 assert(_status == IcacheWaitResponse); 481 482 _status = Running; 483 484 delete pkt->req; 485 delete pkt; 486 487 numCycles += curTick - previousTick; 488 previousTick = curTick; 489 490 if (getState() == SimObject::Draining) { 491 completeDrain(); 492 return; 493 } 494 495 preExecute(); 496 if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { 497 // load or store: just send to dcache 498 Fault fault = curStaticInst->initiateAcc(this, traceData); 499 if (_status != Running) { 500 // instruction will complete in dcache response callback 501 assert(_status == DcacheWaitResponse || _status == DcacheRetry); 502 assert(fault == NoFault); 503 } else { 504 if (fault == NoFault) { 505 // early fail on store conditional: complete now 506 assert(dcache_pkt != NULL); 507 fault = curStaticInst->completeAcc(dcache_pkt, this, 508 traceData); 509 delete dcache_pkt->req; 510 delete dcache_pkt; 511 dcache_pkt = NULL; 512 } 513 postExecute(); 514 advanceInst(fault); 515 } 516 } else { 517 // non-memory instruction: execute completely now 518 Fault fault = curStaticInst->execute(this, traceData); 519 postExecute(); 520 advanceInst(fault); 521 } 522} 523 524void 525TimingSimpleCPU::IcachePort::ITickEvent::process() 526{ 527 cpu->completeIfetch(pkt); 528} 529 530bool 531TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt) 532{ 533 if (pkt->isResponse()) { 534 // delay processing of returned data until next CPU clock edge 535 Tick mem_time = pkt->req->getTime(); 536 Tick next_tick = cpu->nextCycle(mem_time); 537 538 if (next_tick == curTick) 539 cpu->completeIfetch(pkt); 540 else 541 tickEvent.schedule(pkt, next_tick); 542 543 return true; 544 } 545 else { 546 //Snooping a Coherence Request, do nothing 547 return true; 548 } 549} 550 551void 552TimingSimpleCPU::IcachePort::recvRetry() 553{ 554 // we shouldn't get a retry unless we have a packet that we're 555 // waiting to transmit 556 assert(cpu->ifetch_pkt != NULL); 557 assert(cpu->_status == IcacheRetry); 558 PacketPtr tmp = cpu->ifetch_pkt; 559 if (sendTiming(tmp)) { 560 cpu->_status = IcacheWaitResponse; 561 cpu->ifetch_pkt = NULL; 562 } 563} 564 565void 566TimingSimpleCPU::completeDataAccess(PacketPtr pkt) 567{ 568 // received a response from the dcache: complete the load or store 569 // instruction 570 assert(pkt->result == Packet::Success); 571 assert(_status == DcacheWaitResponse); 572 _status = Running; 573 574 numCycles += curTick - previousTick; 575 previousTick = curTick; 576 577 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 578 579 if (pkt->isRead() && pkt->req->isLocked()) { 580 TheISA::handleLockedRead(thread, pkt->req); 581 } 582 583 delete pkt->req; 584 delete pkt; 585 586 postExecute(); 587 588 if (getState() == SimObject::Draining) { 589 advancePC(fault); 590 completeDrain(); 591 592 return; 593 } 594 595 advanceInst(fault); 596} 597 598 599void 600TimingSimpleCPU::completeDrain() 601{ 602 DPRINTF(Config, "Done draining\n"); 603 changeState(SimObject::Drained); 604 drainEvent->process(); 605} 606 607bool 608TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt) 609{ 610 if (pkt->isResponse()) { 611 // delay processing of returned data until next CPU clock edge 612 Tick mem_time = pkt->req->getTime(); 613 Tick next_tick = cpu->nextCycle(mem_time); 614 615 if (next_tick == curTick) 616 cpu->completeDataAccess(pkt); 617 else 618 tickEvent.schedule(pkt, next_tick); 619 620 return true; 621 } 622 else { 623 //Snooping a coherence req, do nothing 624 return true; 625 } 626} 627 628void 629TimingSimpleCPU::DcachePort::DTickEvent::process() 630{ 631 cpu->completeDataAccess(pkt); 632} 633 634void 635TimingSimpleCPU::DcachePort::recvRetry() 636{ 637 // we shouldn't get a retry unless we have a packet that we're 638 // waiting to transmit 639 assert(cpu->dcache_pkt != NULL); 640 assert(cpu->_status == DcacheRetry); 641 PacketPtr tmp = cpu->dcache_pkt; 642 if (sendTiming(tmp)) { 643 cpu->_status = DcacheWaitResponse; 644 // memory system takes ownership of packet 645 cpu->dcache_pkt = NULL; 646 } 647} 648 649 650//////////////////////////////////////////////////////////////////////// 651// 652// TimingSimpleCPU Simulation Object 653// 654BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 655 656 Param<Counter> max_insts_any_thread; 657 Param<Counter> max_insts_all_threads; 658 Param<Counter> max_loads_any_thread; 659 Param<Counter> max_loads_all_threads; 660 Param<Tick> progress_interval; 661 SimObjectParam<System *> system; 662 Param<int> cpu_id; 663 664#if FULL_SYSTEM 665 SimObjectParam<TheISA::ITB *> itb; 666 SimObjectParam<TheISA::DTB *> dtb; 667 Param<Tick> profile; 668 669 Param<bool> do_quiesce; 670 Param<bool> do_checkpoint_insts; 671 Param<bool> do_statistics_insts; 672#else 673 SimObjectParam<Process *> workload; 674#endif // FULL_SYSTEM 675 676 Param<int> clock; 677 678 Param<bool> defer_registration; 679 Param<int> width; 680 Param<bool> function_trace; 681 Param<Tick> function_trace_start; 682 Param<bool> simulate_stalls; 683 684END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 685 686BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 687 688 INIT_PARAM(max_insts_any_thread, 689 "terminate when any thread reaches this inst count"), 690 INIT_PARAM(max_insts_all_threads, 691 "terminate when all threads have reached this inst count"), 692 INIT_PARAM(max_loads_any_thread, 693 "terminate when any thread reaches this load count"), 694 INIT_PARAM(max_loads_all_threads, 695 "terminate when all threads have reached this load count"), 696 INIT_PARAM(progress_interval, "Progress interval"), 697 INIT_PARAM(system, "system object"), 698 INIT_PARAM(cpu_id, "processor ID"), 699 700#if FULL_SYSTEM 701 INIT_PARAM(itb, "Instruction TLB"), 702 INIT_PARAM(dtb, "Data TLB"), 703 INIT_PARAM(profile, ""), 704 INIT_PARAM(do_quiesce, ""), 705 INIT_PARAM(do_checkpoint_insts, ""), 706 INIT_PARAM(do_statistics_insts, ""), 707#else 708 INIT_PARAM(workload, "processes to run"), 709#endif // FULL_SYSTEM 710 711 INIT_PARAM(clock, "clock speed"), 712 INIT_PARAM(defer_registration, "defer system registration (for sampling)"), 713 INIT_PARAM(width, "cpu width"), 714 INIT_PARAM(function_trace, "Enable function trace"), 715 INIT_PARAM(function_trace_start, "Cycle to start function trace"), 716 INIT_PARAM(simulate_stalls, "Simulate cache stall cycles") 717 718END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 719 720 721CREATE_SIM_OBJECT(TimingSimpleCPU) 722{ 723 TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params(); 724 params->name = getInstanceName(); 725 params->numberOfThreads = 1; 726 params->max_insts_any_thread = max_insts_any_thread; 727 params->max_insts_all_threads = max_insts_all_threads; 728 params->max_loads_any_thread = max_loads_any_thread; 729 params->max_loads_all_threads = max_loads_all_threads; 730 params->progress_interval = progress_interval; 731 params->deferRegistration = defer_registration; 732 params->clock = clock; 733 params->functionTrace = function_trace; 734 params->functionTraceStart = function_trace_start; 735 params->system = system; 736 params->cpu_id = cpu_id; 737 738#if FULL_SYSTEM 739 params->itb = itb; 740 params->dtb = dtb; 741 params->profile = profile; 742 params->do_quiesce = do_quiesce; 743 params->do_checkpoint_insts = do_checkpoint_insts; 744 params->do_statistics_insts = do_statistics_insts; 745#else 746 params->process = workload; 747#endif 748 749 TimingSimpleCPU *cpu = new TimingSimpleCPU(params); 750 return cpu; 751} 752 753REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU) 754
| 113 ifetch_pkt = dcache_pkt = NULL; 114 drainEvent = NULL; 115 fetchEvent = NULL; 116 previousTick = 0; 117 changeState(SimObject::Running); 118} 119 120 121TimingSimpleCPU::~TimingSimpleCPU() 122{ 123} 124 125void 126TimingSimpleCPU::serialize(ostream &os) 127{ 128 SimObject::State so_state = SimObject::getState(); 129 SERIALIZE_ENUM(so_state); 130 BaseSimpleCPU::serialize(os); 131} 132 133void 134TimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 135{ 136 SimObject::State so_state; 137 UNSERIALIZE_ENUM(so_state); 138 BaseSimpleCPU::unserialize(cp, section); 139} 140 141unsigned int 142TimingSimpleCPU::drain(Event *drain_event) 143{ 144 // TimingSimpleCPU is ready to drain if it's not waiting for 145 // an access to complete. 146 if (status() == Idle || status() == Running || status() == SwitchedOut) { 147 changeState(SimObject::Drained); 148 return 0; 149 } else { 150 changeState(SimObject::Draining); 151 drainEvent = drain_event; 152 return 1; 153 } 154} 155 156void 157TimingSimpleCPU::resume() 158{ 159 if (_status != SwitchedOut && _status != Idle) { 160 assert(system->getMemoryMode() == System::Timing); 161 162 // Delete the old event if it existed. 163 if (fetchEvent) { 164 if (fetchEvent->scheduled()) 165 fetchEvent->deschedule(); 166 167 delete fetchEvent; 168 } 169 170 fetchEvent = 171 new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false); 172 fetchEvent->schedule(curTick); 173 } 174 175 changeState(SimObject::Running); 176 previousTick = curTick; 177} 178 179void 180TimingSimpleCPU::switchOut() 181{ 182 assert(status() == Running || status() == Idle); 183 _status = SwitchedOut; 184 numCycles += curTick - previousTick; 185 186 // If we've been scheduled to resume but are then told to switch out, 187 // we'll need to cancel it. 188 if (fetchEvent && fetchEvent->scheduled()) 189 fetchEvent->deschedule(); 190} 191 192 193void 194TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 195{ 196 BaseCPU::takeOverFrom(oldCPU); 197 198 // if any of this CPU's ThreadContexts are active, mark the CPU as 199 // running and schedule its tick event. 200 for (int i = 0; i < threadContexts.size(); ++i) { 201 ThreadContext *tc = threadContexts[i]; 202 if (tc->status() == ThreadContext::Active && _status != Running) { 203 _status = Running; 204 break; 205 } 206 } 207 208 if (_status != Running) { 209 _status = Idle; 210 } 211 212 Port *peer; 213 if (icachePort.getPeer() == NULL) { 214 peer = oldCPU->getPort("icache_port")->getPeer(); 215 icachePort.setPeer(peer); 216 } else { 217 peer = icachePort.getPeer(); 218 } 219 peer->setPeer(&icachePort); 220 221 if (dcachePort.getPeer() == NULL) { 222 peer = oldCPU->getPort("dcache_port")->getPeer(); 223 dcachePort.setPeer(peer); 224 } else { 225 peer = dcachePort.getPeer(); 226 } 227 peer->setPeer(&dcachePort); 228} 229 230 231void 232TimingSimpleCPU::activateContext(int thread_num, int delay) 233{ 234 assert(thread_num == 0); 235 assert(thread); 236 237 assert(_status == Idle); 238 239 notIdleFraction++; 240 _status = Running; 241 // kick things off by initiating the fetch of the next instruction 242 fetchEvent = 243 new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false); 244 fetchEvent->schedule(curTick + cycles(delay)); 245} 246 247 248void 249TimingSimpleCPU::suspendContext(int thread_num) 250{ 251 assert(thread_num == 0); 252 assert(thread); 253 254 assert(_status == Running); 255 256 // just change status to Idle... if status != Running, 257 // completeInst() will not initiate fetch of next instruction. 258 259 notIdleFraction--; 260 _status = Idle; 261} 262 263 264template <class T> 265Fault 266TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 267{ 268 Request *req = 269 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 270 cpu_id, /* thread ID */ 0); 271 272 if (traceData) { 273 traceData->setAddr(req->getVaddr()); 274 } 275 276 // translate to physical address 277 Fault fault = thread->translateDataReadReq(req); 278 279 // Now do the access. 280 if (fault == NoFault) { 281 PacketPtr pkt = 282 new Packet(req, Packet::ReadReq, Packet::Broadcast); 283 pkt->dataDynamic<T>(new T); 284 285 if (!dcachePort.sendTiming(pkt)) { 286 _status = DcacheRetry; 287 dcache_pkt = pkt; 288 } else { 289 _status = DcacheWaitResponse; 290 // memory system takes ownership of packet 291 dcache_pkt = NULL; 292 } 293 } 294 295 // This will need a new way to tell if it has a dcache attached. 296 if (req->isUncacheable()) 297 recordEvent("Uncached Read"); 298 299 return fault; 300} 301 302#ifndef DOXYGEN_SHOULD_SKIP_THIS 303 304template 305Fault 306TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 307 308template 309Fault 310TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 311 312template 313Fault 314TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 315 316template 317Fault 318TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 319 320#endif //DOXYGEN_SHOULD_SKIP_THIS 321 322template<> 323Fault 324TimingSimpleCPU::read(Addr addr, double &data, unsigned flags) 325{ 326 return read(addr, *(uint64_t*)&data, flags); 327} 328 329template<> 330Fault 331TimingSimpleCPU::read(Addr addr, float &data, unsigned flags) 332{ 333 return read(addr, *(uint32_t*)&data, flags); 334} 335 336 337template<> 338Fault 339TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 340{ 341 return read(addr, (uint32_t&)data, flags); 342} 343 344 345template <class T> 346Fault 347TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 348{ 349 Request *req = 350 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 351 cpu_id, /* thread ID */ 0); 352 353 // translate to physical address 354 Fault fault = thread->translateDataWriteReq(req); 355 356 // Now do the access. 357 if (fault == NoFault) { 358 assert(dcache_pkt == NULL); 359 dcache_pkt = new Packet(req, Packet::WriteReq, Packet::Broadcast); 360 dcache_pkt->allocate(); 361 dcache_pkt->set(data); 362 363 bool do_access = true; // flag to suppress cache access 364 365 if (req->isLocked()) { 366 do_access = TheISA::handleLockedWrite(thread, req); 367 } 368 369 if (do_access) { 370 if (!dcachePort.sendTiming(dcache_pkt)) { 371 _status = DcacheRetry; 372 } else { 373 _status = DcacheWaitResponse; 374 // memory system takes ownership of packet 375 dcache_pkt = NULL; 376 } 377 } 378 } 379 380 // This will need a new way to tell if it's hooked up to a cache or not. 381 if (req->isUncacheable()) 382 recordEvent("Uncached Write"); 383 384 // If the write needs to have a fault on the access, consider calling 385 // changeStatus() and changing it to "bad addr write" or something. 386 return fault; 387} 388 389 390#ifndef DOXYGEN_SHOULD_SKIP_THIS 391template 392Fault 393TimingSimpleCPU::write(uint64_t data, Addr addr, 394 unsigned flags, uint64_t *res); 395 396template 397Fault 398TimingSimpleCPU::write(uint32_t data, Addr addr, 399 unsigned flags, uint64_t *res); 400 401template 402Fault 403TimingSimpleCPU::write(uint16_t data, Addr addr, 404 unsigned flags, uint64_t *res); 405 406template 407Fault 408TimingSimpleCPU::write(uint8_t data, Addr addr, 409 unsigned flags, uint64_t *res); 410 411#endif //DOXYGEN_SHOULD_SKIP_THIS 412 413template<> 414Fault 415TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 416{ 417 return write(*(uint64_t*)&data, addr, flags, res); 418} 419 420template<> 421Fault 422TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 423{ 424 return write(*(uint32_t*)&data, addr, flags, res); 425} 426 427 428template<> 429Fault 430TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 431{ 432 return write((uint32_t)data, addr, flags, res); 433} 434 435 436void 437TimingSimpleCPU::fetch() 438{ 439 if (!curStaticInst || !curStaticInst->isDelayedCommit()) 440 checkForInterrupts(); 441 442 Request *ifetch_req = new Request(); 443 ifetch_req->setThreadContext(cpu_id, /* thread ID */ 0); 444 Fault fault = setupFetchRequest(ifetch_req); 445 446 ifetch_pkt = new Packet(ifetch_req, Packet::ReadReq, Packet::Broadcast); 447 ifetch_pkt->dataStatic(&inst); 448 449 if (fault == NoFault) { 450 if (!icachePort.sendTiming(ifetch_pkt)) { 451 // Need to wait for retry 452 _status = IcacheRetry; 453 } else { 454 // Need to wait for cache to respond 455 _status = IcacheWaitResponse; 456 // ownership of packet transferred to memory system 457 ifetch_pkt = NULL; 458 } 459 } else { 460 // fetch fault: advance directly to next instruction (fault handler) 461 advanceInst(fault); 462 } 463 464 numCycles += curTick - previousTick; 465 previousTick = curTick; 466} 467 468 469void 470TimingSimpleCPU::advanceInst(Fault fault) 471{ 472 advancePC(fault); 473 474 if (_status == Running) { 475 // kick off fetch of next instruction... callback from icache 476 // response will cause that instruction to be executed, 477 // keeping the CPU running. 478 fetch(); 479 } 480} 481 482 483void 484TimingSimpleCPU::completeIfetch(PacketPtr pkt) 485{ 486 // received a response from the icache: execute the received 487 // instruction 488 assert(pkt->result == Packet::Success); 489 assert(_status == IcacheWaitResponse); 490 491 _status = Running; 492 493 delete pkt->req; 494 delete pkt; 495 496 numCycles += curTick - previousTick; 497 previousTick = curTick; 498 499 if (getState() == SimObject::Draining) { 500 completeDrain(); 501 return; 502 } 503 504 preExecute(); 505 if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { 506 // load or store: just send to dcache 507 Fault fault = curStaticInst->initiateAcc(this, traceData); 508 if (_status != Running) { 509 // instruction will complete in dcache response callback 510 assert(_status == DcacheWaitResponse || _status == DcacheRetry); 511 assert(fault == NoFault); 512 } else { 513 if (fault == NoFault) { 514 // early fail on store conditional: complete now 515 assert(dcache_pkt != NULL); 516 fault = curStaticInst->completeAcc(dcache_pkt, this, 517 traceData); 518 delete dcache_pkt->req; 519 delete dcache_pkt; 520 dcache_pkt = NULL; 521 } 522 postExecute(); 523 advanceInst(fault); 524 } 525 } else { 526 // non-memory instruction: execute completely now 527 Fault fault = curStaticInst->execute(this, traceData); 528 postExecute(); 529 advanceInst(fault); 530 } 531} 532 533void 534TimingSimpleCPU::IcachePort::ITickEvent::process() 535{ 536 cpu->completeIfetch(pkt); 537} 538 539bool 540TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt) 541{ 542 if (pkt->isResponse()) { 543 // delay processing of returned data until next CPU clock edge 544 Tick mem_time = pkt->req->getTime(); 545 Tick next_tick = cpu->nextCycle(mem_time); 546 547 if (next_tick == curTick) 548 cpu->completeIfetch(pkt); 549 else 550 tickEvent.schedule(pkt, next_tick); 551 552 return true; 553 } 554 else { 555 //Snooping a Coherence Request, do nothing 556 return true; 557 } 558} 559 560void 561TimingSimpleCPU::IcachePort::recvRetry() 562{ 563 // we shouldn't get a retry unless we have a packet that we're 564 // waiting to transmit 565 assert(cpu->ifetch_pkt != NULL); 566 assert(cpu->_status == IcacheRetry); 567 PacketPtr tmp = cpu->ifetch_pkt; 568 if (sendTiming(tmp)) { 569 cpu->_status = IcacheWaitResponse; 570 cpu->ifetch_pkt = NULL; 571 } 572} 573 574void 575TimingSimpleCPU::completeDataAccess(PacketPtr pkt) 576{ 577 // received a response from the dcache: complete the load or store 578 // instruction 579 assert(pkt->result == Packet::Success); 580 assert(_status == DcacheWaitResponse); 581 _status = Running; 582 583 numCycles += curTick - previousTick; 584 previousTick = curTick; 585 586 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 587 588 if (pkt->isRead() && pkt->req->isLocked()) { 589 TheISA::handleLockedRead(thread, pkt->req); 590 } 591 592 delete pkt->req; 593 delete pkt; 594 595 postExecute(); 596 597 if (getState() == SimObject::Draining) { 598 advancePC(fault); 599 completeDrain(); 600 601 return; 602 } 603 604 advanceInst(fault); 605} 606 607 608void 609TimingSimpleCPU::completeDrain() 610{ 611 DPRINTF(Config, "Done draining\n"); 612 changeState(SimObject::Drained); 613 drainEvent->process(); 614} 615 616bool 617TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt) 618{ 619 if (pkt->isResponse()) { 620 // delay processing of returned data until next CPU clock edge 621 Tick mem_time = pkt->req->getTime(); 622 Tick next_tick = cpu->nextCycle(mem_time); 623 624 if (next_tick == curTick) 625 cpu->completeDataAccess(pkt); 626 else 627 tickEvent.schedule(pkt, next_tick); 628 629 return true; 630 } 631 else { 632 //Snooping a coherence req, do nothing 633 return true; 634 } 635} 636 637void 638TimingSimpleCPU::DcachePort::DTickEvent::process() 639{ 640 cpu->completeDataAccess(pkt); 641} 642 643void 644TimingSimpleCPU::DcachePort::recvRetry() 645{ 646 // we shouldn't get a retry unless we have a packet that we're 647 // waiting to transmit 648 assert(cpu->dcache_pkt != NULL); 649 assert(cpu->_status == DcacheRetry); 650 PacketPtr tmp = cpu->dcache_pkt; 651 if (sendTiming(tmp)) { 652 cpu->_status = DcacheWaitResponse; 653 // memory system takes ownership of packet 654 cpu->dcache_pkt = NULL; 655 } 656} 657 658 659//////////////////////////////////////////////////////////////////////// 660// 661// TimingSimpleCPU Simulation Object 662// 663BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 664 665 Param<Counter> max_insts_any_thread; 666 Param<Counter> max_insts_all_threads; 667 Param<Counter> max_loads_any_thread; 668 Param<Counter> max_loads_all_threads; 669 Param<Tick> progress_interval; 670 SimObjectParam<System *> system; 671 Param<int> cpu_id; 672 673#if FULL_SYSTEM 674 SimObjectParam<TheISA::ITB *> itb; 675 SimObjectParam<TheISA::DTB *> dtb; 676 Param<Tick> profile; 677 678 Param<bool> do_quiesce; 679 Param<bool> do_checkpoint_insts; 680 Param<bool> do_statistics_insts; 681#else 682 SimObjectParam<Process *> workload; 683#endif // FULL_SYSTEM 684 685 Param<int> clock; 686 687 Param<bool> defer_registration; 688 Param<int> width; 689 Param<bool> function_trace; 690 Param<Tick> function_trace_start; 691 Param<bool> simulate_stalls; 692 693END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 694 695BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 696 697 INIT_PARAM(max_insts_any_thread, 698 "terminate when any thread reaches this inst count"), 699 INIT_PARAM(max_insts_all_threads, 700 "terminate when all threads have reached this inst count"), 701 INIT_PARAM(max_loads_any_thread, 702 "terminate when any thread reaches this load count"), 703 INIT_PARAM(max_loads_all_threads, 704 "terminate when all threads have reached this load count"), 705 INIT_PARAM(progress_interval, "Progress interval"), 706 INIT_PARAM(system, "system object"), 707 INIT_PARAM(cpu_id, "processor ID"), 708 709#if FULL_SYSTEM 710 INIT_PARAM(itb, "Instruction TLB"), 711 INIT_PARAM(dtb, "Data TLB"), 712 INIT_PARAM(profile, ""), 713 INIT_PARAM(do_quiesce, ""), 714 INIT_PARAM(do_checkpoint_insts, ""), 715 INIT_PARAM(do_statistics_insts, ""), 716#else 717 INIT_PARAM(workload, "processes to run"), 718#endif // FULL_SYSTEM 719 720 INIT_PARAM(clock, "clock speed"), 721 INIT_PARAM(defer_registration, "defer system registration (for sampling)"), 722 INIT_PARAM(width, "cpu width"), 723 INIT_PARAM(function_trace, "Enable function trace"), 724 INIT_PARAM(function_trace_start, "Cycle to start function trace"), 725 INIT_PARAM(simulate_stalls, "Simulate cache stall cycles") 726 727END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 728 729 730CREATE_SIM_OBJECT(TimingSimpleCPU) 731{ 732 TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params(); 733 params->name = getInstanceName(); 734 params->numberOfThreads = 1; 735 params->max_insts_any_thread = max_insts_any_thread; 736 params->max_insts_all_threads = max_insts_all_threads; 737 params->max_loads_any_thread = max_loads_any_thread; 738 params->max_loads_all_threads = max_loads_all_threads; 739 params->progress_interval = progress_interval; 740 params->deferRegistration = defer_registration; 741 params->clock = clock; 742 params->functionTrace = function_trace; 743 params->functionTraceStart = function_trace_start; 744 params->system = system; 745 params->cpu_id = cpu_id; 746 747#if FULL_SYSTEM 748 params->itb = itb; 749 params->dtb = dtb; 750 params->profile = profile; 751 params->do_quiesce = do_quiesce; 752 params->do_checkpoint_insts = do_checkpoint_insts; 753 params->do_statistics_insts = do_statistics_insts; 754#else 755 params->process = workload; 756#endif 757 758 TimingSimpleCPU *cpu = new TimingSimpleCPU(params); 759 return cpu; 760} 761 762REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU) 763
|