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 "base/bigint.hh" 34#include "cpu/exetrace.hh" 35#include "cpu/simple/timing.hh" 36#include "mem/packet.hh" 37#include "mem/packet_access.hh" 38#include "sim/builder.hh" 39#include "sim/system.hh" 40 41using namespace std; 42using namespace TheISA; 43 44Port * 45TimingSimpleCPU::getPort(const std::string &if_name, int idx) 46{ 47 if (if_name == "dcache_port") 48 return &dcachePort; 49 else if (if_name == "icache_port") 50 return &icachePort; 51 else 52 panic("No Such Port\n"); 53} 54 55void 56TimingSimpleCPU::init() 57{ 58 BaseCPU::init(); 59#if FULL_SYSTEM 60 for (int i = 0; i < threadContexts.size(); ++i) { 61 ThreadContext *tc = threadContexts[i]; 62 63 // initialize CPU, including PC 64 TheISA::initCPU(tc, tc->readCpuId()); 65 } 66#endif 67} 68 69Tick 70TimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) 71{ 72 panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 73 return curTick; 74} 75 76void 77TimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) 78{ 79 //No internal storage to update, jusst return 80 return; 81} 82 83void 84TimingSimpleCPU::CpuPort::recvStatusChange(Status status) 85{ 86 if (status == RangeChange) { 87 if (!snoopRangeSent) { 88 snoopRangeSent = true; 89 sendStatusChange(Port::RangeChange); 90 } 91 return; 92 } 93 94 panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); 95} 96 97 98void 99TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) 100{ 101 pkt = _pkt; 102 Event::schedule(t); 103} 104 105TimingSimpleCPU::TimingSimpleCPU(Params *p) 106 : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock), 107 cpu_id(p->cpu_id) 108{ 109 _status = Idle; 110 111 icachePort.snoopRangeSent = false; 112 dcachePort.snoopRangeSent = false; 113 114 ifetch_pkt = dcache_pkt = NULL; 115 drainEvent = NULL; 116 fetchEvent = NULL; 117 previousTick = 0; 118 changeState(SimObject::Running); 119} 120 121 122TimingSimpleCPU::~TimingSimpleCPU() 123{ 124} 125 126void 127TimingSimpleCPU::serialize(ostream &os) 128{ 129 SimObject::State so_state = SimObject::getState(); 130 SERIALIZE_ENUM(so_state); 131 BaseSimpleCPU::serialize(os); 132} 133 134void 135TimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 136{ 137 SimObject::State so_state; 138 UNSERIALIZE_ENUM(so_state); 139 BaseSimpleCPU::unserialize(cp, section); 140} 141 142unsigned int 143TimingSimpleCPU::drain(Event *drain_event) 144{ 145 // TimingSimpleCPU is ready to drain if it's not waiting for 146 // an access to complete. 147 if (status() == Idle || status() == Running || status() == SwitchedOut) { 148 changeState(SimObject::Drained); 149 return 0; 150 } else { 151 changeState(SimObject::Draining); 152 drainEvent = drain_event; 153 return 1; 154 } 155} 156 157void 158TimingSimpleCPU::resume() 159{ 160 if (_status != SwitchedOut && _status != Idle) { 161 assert(system->getMemoryMode() == System::Timing); 162 163 // Delete the old event if it existed. 164 if (fetchEvent) { 165 if (fetchEvent->scheduled()) 166 fetchEvent->deschedule(); 167 168 delete fetchEvent; 169 } 170
| 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 "base/bigint.hh" 34#include "cpu/exetrace.hh" 35#include "cpu/simple/timing.hh" 36#include "mem/packet.hh" 37#include "mem/packet_access.hh" 38#include "sim/builder.hh" 39#include "sim/system.hh" 40 41using namespace std; 42using namespace TheISA; 43 44Port * 45TimingSimpleCPU::getPort(const std::string &if_name, int idx) 46{ 47 if (if_name == "dcache_port") 48 return &dcachePort; 49 else if (if_name == "icache_port") 50 return &icachePort; 51 else 52 panic("No Such Port\n"); 53} 54 55void 56TimingSimpleCPU::init() 57{ 58 BaseCPU::init(); 59#if FULL_SYSTEM 60 for (int i = 0; i < threadContexts.size(); ++i) { 61 ThreadContext *tc = threadContexts[i]; 62 63 // initialize CPU, including PC 64 TheISA::initCPU(tc, tc->readCpuId()); 65 } 66#endif 67} 68 69Tick 70TimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) 71{ 72 panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 73 return curTick; 74} 75 76void 77TimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) 78{ 79 //No internal storage to update, jusst return 80 return; 81} 82 83void 84TimingSimpleCPU::CpuPort::recvStatusChange(Status status) 85{ 86 if (status == RangeChange) { 87 if (!snoopRangeSent) { 88 snoopRangeSent = true; 89 sendStatusChange(Port::RangeChange); 90 } 91 return; 92 } 93 94 panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); 95} 96 97 98void 99TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) 100{ 101 pkt = _pkt; 102 Event::schedule(t); 103} 104 105TimingSimpleCPU::TimingSimpleCPU(Params *p) 106 : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock), 107 cpu_id(p->cpu_id) 108{ 109 _status = Idle; 110 111 icachePort.snoopRangeSent = false; 112 dcachePort.snoopRangeSent = false; 113 114 ifetch_pkt = dcache_pkt = NULL; 115 drainEvent = NULL; 116 fetchEvent = NULL; 117 previousTick = 0; 118 changeState(SimObject::Running); 119} 120 121 122TimingSimpleCPU::~TimingSimpleCPU() 123{ 124} 125 126void 127TimingSimpleCPU::serialize(ostream &os) 128{ 129 SimObject::State so_state = SimObject::getState(); 130 SERIALIZE_ENUM(so_state); 131 BaseSimpleCPU::serialize(os); 132} 133 134void 135TimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 136{ 137 SimObject::State so_state; 138 UNSERIALIZE_ENUM(so_state); 139 BaseSimpleCPU::unserialize(cp, section); 140} 141 142unsigned int 143TimingSimpleCPU::drain(Event *drain_event) 144{ 145 // TimingSimpleCPU is ready to drain if it's not waiting for 146 // an access to complete. 147 if (status() == Idle || status() == Running || status() == SwitchedOut) { 148 changeState(SimObject::Drained); 149 return 0; 150 } else { 151 changeState(SimObject::Draining); 152 drainEvent = drain_event; 153 return 1; 154 } 155} 156 157void 158TimingSimpleCPU::resume() 159{ 160 if (_status != SwitchedOut && _status != Idle) { 161 assert(system->getMemoryMode() == System::Timing); 162 163 // Delete the old event if it existed. 164 if (fetchEvent) { 165 if (fetchEvent->scheduled()) 166 fetchEvent->deschedule(); 167 168 delete fetchEvent; 169 } 170
|
230} 231 232 233void 234TimingSimpleCPU::suspendContext(int thread_num) 235{ 236 assert(thread_num == 0); 237 assert(thread); 238 239 assert(_status == Running); 240 241 // just change status to Idle... if status != Running, 242 // completeInst() will not initiate fetch of next instruction. 243 244 notIdleFraction--; 245 _status = Idle; 246} 247 248 249template <class T> 250Fault 251TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 252{ 253 Request *req = 254 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 255 cpu_id, /* thread ID */ 0); 256 257 if (traceData) { 258 traceData->setAddr(req->getVaddr()); 259 } 260 261 // translate to physical address 262 Fault fault = thread->translateDataReadReq(req); 263 264 // Now do the access. 265 if (fault == NoFault) { 266 PacketPtr pkt = 267 new Packet(req, MemCmd::ReadReq, Packet::Broadcast); 268 pkt->dataDynamic<T>(new T); 269 270 if (!dcachePort.sendTiming(pkt)) { 271 _status = DcacheRetry; 272 dcache_pkt = pkt; 273 } else { 274 _status = DcacheWaitResponse; 275 // memory system takes ownership of packet 276 dcache_pkt = NULL; 277 } 278 279 // This will need a new way to tell if it has a dcache attached. 280 if (req->isUncacheable()) 281 recordEvent("Uncached Read"); 282 } else { 283 delete req; 284 } 285 286 return fault; 287} 288 289#ifndef DOXYGEN_SHOULD_SKIP_THIS 290 291template 292Fault 293TimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags); 294 295template 296Fault 297TimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags); 298 299template 300Fault 301TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 302 303template 304Fault 305TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 306 307template 308Fault 309TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 310 311template 312Fault 313TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 314 315#endif //DOXYGEN_SHOULD_SKIP_THIS 316 317template<> 318Fault 319TimingSimpleCPU::read(Addr addr, double &data, unsigned flags) 320{ 321 return read(addr, *(uint64_t*)&data, flags); 322} 323 324template<> 325Fault 326TimingSimpleCPU::read(Addr addr, float &data, unsigned flags) 327{ 328 return read(addr, *(uint32_t*)&data, flags); 329} 330 331 332template<> 333Fault 334TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 335{ 336 return read(addr, (uint32_t&)data, flags); 337} 338 339 340template <class T> 341Fault 342TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 343{ 344 Request *req = 345 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 346 cpu_id, /* thread ID */ 0); 347 348 if (traceData) { 349 traceData->setAddr(req->getVaddr()); 350 } 351 352 // translate to physical address 353 Fault fault = thread->translateDataWriteReq(req); 354 355 // Now do the access. 356 if (fault == NoFault) { 357 assert(dcache_pkt == NULL); 358 if (req->isSwap()) 359 dcache_pkt = new Packet(req, MemCmd::SwapReq, Packet::Broadcast); 360 else 361 dcache_pkt = new Packet(req, MemCmd::WriteReq, Packet::Broadcast); 362 dcache_pkt->allocate(); 363 dcache_pkt->set(data); 364 365 bool do_access = true; // flag to suppress cache access 366 367 if (req->isLocked()) { 368 do_access = TheISA::handleLockedWrite(thread, req); 369 } 370 if (req->isCondSwap()) { 371 assert(res); 372 req->setExtraData(*res); 373 } 374 375 if (do_access) { 376 if (!dcachePort.sendTiming(dcache_pkt)) { 377 _status = DcacheRetry; 378 } else { 379 _status = DcacheWaitResponse; 380 // memory system takes ownership of packet 381 dcache_pkt = NULL; 382 } 383 } 384 // This will need a new way to tell if it's hooked up to a cache or not. 385 if (req->isUncacheable()) 386 recordEvent("Uncached Write"); 387 } else { 388 delete req; 389 } 390 391 392 // If the write needs to have a fault on the access, consider calling 393 // changeStatus() and changing it to "bad addr write" or something. 394 return fault; 395} 396 397 398#ifndef DOXYGEN_SHOULD_SKIP_THIS 399template 400Fault 401TimingSimpleCPU::write(Twin32_t data, Addr addr, 402 unsigned flags, uint64_t *res); 403 404template 405Fault 406TimingSimpleCPU::write(Twin64_t data, Addr addr, 407 unsigned flags, uint64_t *res); 408 409template 410Fault 411TimingSimpleCPU::write(uint64_t data, Addr addr, 412 unsigned flags, uint64_t *res); 413 414template 415Fault 416TimingSimpleCPU::write(uint32_t data, Addr addr, 417 unsigned flags, uint64_t *res); 418 419template 420Fault 421TimingSimpleCPU::write(uint16_t data, Addr addr, 422 unsigned flags, uint64_t *res); 423 424template 425Fault 426TimingSimpleCPU::write(uint8_t data, Addr addr, 427 unsigned flags, uint64_t *res); 428 429#endif //DOXYGEN_SHOULD_SKIP_THIS 430 431template<> 432Fault 433TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 434{ 435 return write(*(uint64_t*)&data, addr, flags, res); 436} 437 438template<> 439Fault 440TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 441{ 442 return write(*(uint32_t*)&data, addr, flags, res); 443} 444 445 446template<> 447Fault 448TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 449{ 450 return write((uint32_t)data, addr, flags, res); 451} 452 453 454void 455TimingSimpleCPU::fetch() 456{ 457 if (!curStaticInst || !curStaticInst->isDelayedCommit()) 458 checkForInterrupts(); 459 460 Request *ifetch_req = new Request(); 461 ifetch_req->setThreadContext(cpu_id, /* thread ID */ 0); 462 Fault fault = setupFetchRequest(ifetch_req); 463 464 ifetch_pkt = new Packet(ifetch_req, MemCmd::ReadReq, Packet::Broadcast); 465 ifetch_pkt->dataStatic(&inst); 466 467 if (fault == NoFault) { 468 if (!icachePort.sendTiming(ifetch_pkt)) { 469 // Need to wait for retry 470 _status = IcacheRetry; 471 } else { 472 // Need to wait for cache to respond 473 _status = IcacheWaitResponse; 474 // ownership of packet transferred to memory system 475 ifetch_pkt = NULL; 476 } 477 } else { 478 delete ifetch_req; 479 delete ifetch_pkt; 480 // fetch fault: advance directly to next instruction (fault handler) 481 advanceInst(fault); 482 } 483 484 numCycles += curTick - previousTick; 485 previousTick = curTick; 486} 487 488 489void 490TimingSimpleCPU::advanceInst(Fault fault) 491{ 492 advancePC(fault); 493 494 if (_status == Running) { 495 // kick off fetch of next instruction... callback from icache 496 // response will cause that instruction to be executed, 497 // keeping the CPU running. 498 fetch(); 499 } 500} 501 502 503void 504TimingSimpleCPU::completeIfetch(PacketPtr pkt) 505{ 506 // received a response from the icache: execute the received 507 // instruction 508 assert(pkt->result == Packet::Success); 509 assert(_status == IcacheWaitResponse); 510 511 _status = Running; 512 513 numCycles += curTick - previousTick; 514 previousTick = curTick; 515 516 if (getState() == SimObject::Draining) { 517 delete pkt->req; 518 delete pkt; 519 520 completeDrain(); 521 return; 522 } 523 524 preExecute(); 525 if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { 526 // load or store: just send to dcache 527 Fault fault = curStaticInst->initiateAcc(this, traceData); 528 if (_status != Running) { 529 // instruction will complete in dcache response callback 530 assert(_status == DcacheWaitResponse || _status == DcacheRetry); 531 assert(fault == NoFault); 532 } else { 533 if (fault == NoFault) { 534 // early fail on store conditional: complete now 535 assert(dcache_pkt != NULL); 536 fault = curStaticInst->completeAcc(dcache_pkt, this, 537 traceData); 538 delete dcache_pkt->req; 539 delete dcache_pkt; 540 dcache_pkt = NULL; 541 } 542 postExecute(); 543 advanceInst(fault); 544 } 545 } else { 546 // non-memory instruction: execute completely now 547 Fault fault = curStaticInst->execute(this, traceData); 548 postExecute(); 549 advanceInst(fault); 550 } 551 552 delete pkt->req; 553 delete pkt; 554} 555 556void 557TimingSimpleCPU::IcachePort::ITickEvent::process() 558{ 559 cpu->completeIfetch(pkt); 560} 561 562bool 563TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt) 564{ 565 if (pkt->isResponse()) { 566 // delay processing of returned data until next CPU clock edge 567 Tick mem_time = pkt->req->getTime(); 568 Tick next_tick = cpu->nextCycle(mem_time); 569 570 if (next_tick == curTick) 571 cpu->completeIfetch(pkt); 572 else 573 tickEvent.schedule(pkt, next_tick); 574 575 return true; 576 } 577 else if (pkt->result == Packet::Nacked) { 578 assert(cpu->_status == IcacheWaitResponse); 579 pkt->reinitNacked(); 580 if (!sendTiming(pkt)) { 581 cpu->_status = IcacheRetry; 582 cpu->ifetch_pkt = pkt; 583 } 584 } 585 //Snooping a Coherence Request, do nothing 586 return true; 587} 588 589void 590TimingSimpleCPU::IcachePort::recvRetry() 591{ 592 // we shouldn't get a retry unless we have a packet that we're 593 // waiting to transmit 594 assert(cpu->ifetch_pkt != NULL); 595 assert(cpu->_status == IcacheRetry); 596 PacketPtr tmp = cpu->ifetch_pkt; 597 if (sendTiming(tmp)) { 598 cpu->_status = IcacheWaitResponse; 599 cpu->ifetch_pkt = NULL; 600 } 601} 602 603void 604TimingSimpleCPU::completeDataAccess(PacketPtr pkt) 605{ 606 // received a response from the dcache: complete the load or store 607 // instruction 608 assert(pkt->result == Packet::Success); 609 assert(_status == DcacheWaitResponse); 610 _status = Running; 611 612 numCycles += curTick - previousTick; 613 previousTick = curTick; 614 615 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 616 617 if (pkt->isRead() && pkt->req->isLocked()) { 618 TheISA::handleLockedRead(thread, pkt->req); 619 } 620 621 delete pkt->req; 622 delete pkt; 623 624 postExecute(); 625 626 if (getState() == SimObject::Draining) { 627 advancePC(fault); 628 completeDrain(); 629 630 return; 631 } 632 633 advanceInst(fault); 634} 635 636 637void 638TimingSimpleCPU::completeDrain() 639{ 640 DPRINTF(Config, "Done draining\n"); 641 changeState(SimObject::Drained); 642 drainEvent->process(); 643} 644 645void 646TimingSimpleCPU::DcachePort::setPeer(Port *port) 647{ 648 Port::setPeer(port); 649 650#if FULL_SYSTEM 651 // Update the ThreadContext's memory ports (Functional/Virtual 652 // Ports) 653 cpu->tcBase()->connectMemPorts(); 654#endif 655} 656 657bool 658TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt) 659{ 660 if (pkt->isResponse()) { 661 // delay processing of returned data until next CPU clock edge 662 Tick mem_time = pkt->req->getTime(); 663 Tick next_tick = cpu->nextCycle(mem_time); 664 665 if (next_tick == curTick) 666 cpu->completeDataAccess(pkt); 667 else 668 tickEvent.schedule(pkt, next_tick); 669 670 return true; 671 } 672 else if (pkt->result == Packet::Nacked) { 673 assert(cpu->_status == DcacheWaitResponse); 674 pkt->reinitNacked(); 675 if (!sendTiming(pkt)) { 676 cpu->_status = DcacheRetry; 677 cpu->dcache_pkt = pkt; 678 } 679 } 680 //Snooping a Coherence Request, do nothing 681 return true; 682} 683 684void 685TimingSimpleCPU::DcachePort::DTickEvent::process() 686{ 687 cpu->completeDataAccess(pkt); 688} 689 690void 691TimingSimpleCPU::DcachePort::recvRetry() 692{ 693 // we shouldn't get a retry unless we have a packet that we're 694 // waiting to transmit 695 assert(cpu->dcache_pkt != NULL); 696 assert(cpu->_status == DcacheRetry); 697 PacketPtr tmp = cpu->dcache_pkt; 698 if (sendTiming(tmp)) { 699 cpu->_status = DcacheWaitResponse; 700 // memory system takes ownership of packet 701 cpu->dcache_pkt = NULL; 702 } 703} 704 705 706//////////////////////////////////////////////////////////////////////// 707// 708// TimingSimpleCPU Simulation Object 709// 710BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 711 712 Param<Counter> max_insts_any_thread; 713 Param<Counter> max_insts_all_threads; 714 Param<Counter> max_loads_any_thread; 715 Param<Counter> max_loads_all_threads; 716 Param<Tick> progress_interval; 717 SimObjectParam<System *> system; 718 Param<int> cpu_id; 719 720#if FULL_SYSTEM 721 SimObjectParam<TheISA::ITB *> itb; 722 SimObjectParam<TheISA::DTB *> dtb; 723 Param<Tick> profile; 724 725 Param<bool> do_quiesce; 726 Param<bool> do_checkpoint_insts; 727 Param<bool> do_statistics_insts; 728#else 729 SimObjectParam<Process *> workload; 730#endif // FULL_SYSTEM 731 732 Param<int> clock; 733 Param<int> phase; 734 735 Param<bool> defer_registration; 736 Param<int> width; 737 Param<bool> function_trace; 738 Param<Tick> function_trace_start; 739 Param<bool> simulate_stalls; 740 741END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 742 743BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 744 745 INIT_PARAM(max_insts_any_thread, 746 "terminate when any thread reaches this inst count"), 747 INIT_PARAM(max_insts_all_threads, 748 "terminate when all threads have reached this inst count"), 749 INIT_PARAM(max_loads_any_thread, 750 "terminate when any thread reaches this load count"), 751 INIT_PARAM(max_loads_all_threads, 752 "terminate when all threads have reached this load count"), 753 INIT_PARAM(progress_interval, "Progress interval"), 754 INIT_PARAM(system, "system object"), 755 INIT_PARAM(cpu_id, "processor ID"), 756 757#if FULL_SYSTEM 758 INIT_PARAM(itb, "Instruction TLB"), 759 INIT_PARAM(dtb, "Data TLB"), 760 INIT_PARAM(profile, ""), 761 INIT_PARAM(do_quiesce, ""), 762 INIT_PARAM(do_checkpoint_insts, ""), 763 INIT_PARAM(do_statistics_insts, ""), 764#else 765 INIT_PARAM(workload, "processes to run"), 766#endif // FULL_SYSTEM 767 768 INIT_PARAM(clock, "clock speed"), 769 INIT_PARAM_DFLT(phase, "clock phase", 0), 770 INIT_PARAM(defer_registration, "defer system registration (for sampling)"), 771 INIT_PARAM(width, "cpu width"), 772 INIT_PARAM(function_trace, "Enable function trace"), 773 INIT_PARAM(function_trace_start, "Cycle to start function trace"), 774 INIT_PARAM(simulate_stalls, "Simulate cache stall cycles") 775 776END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 777 778 779CREATE_SIM_OBJECT(TimingSimpleCPU) 780{ 781 TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params(); 782 params->name = getInstanceName(); 783 params->numberOfThreads = 1; 784 params->max_insts_any_thread = max_insts_any_thread; 785 params->max_insts_all_threads = max_insts_all_threads; 786 params->max_loads_any_thread = max_loads_any_thread; 787 params->max_loads_all_threads = max_loads_all_threads; 788 params->progress_interval = progress_interval; 789 params->deferRegistration = defer_registration; 790 params->clock = clock; 791 params->phase = phase; 792 params->functionTrace = function_trace; 793 params->functionTraceStart = function_trace_start; 794 params->system = system; 795 params->cpu_id = cpu_id; 796 797#if FULL_SYSTEM 798 params->itb = itb; 799 params->dtb = dtb; 800 params->profile = profile; 801 params->do_quiesce = do_quiesce; 802 params->do_checkpoint_insts = do_checkpoint_insts; 803 params->do_statistics_insts = do_statistics_insts; 804#else 805 params->process = workload; 806#endif 807 808 TimingSimpleCPU *cpu = new TimingSimpleCPU(params); 809 return cpu; 810} 811 812REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU) 813
| 226} 227 228 229void 230TimingSimpleCPU::suspendContext(int thread_num) 231{ 232 assert(thread_num == 0); 233 assert(thread); 234 235 assert(_status == Running); 236 237 // just change status to Idle... if status != Running, 238 // completeInst() will not initiate fetch of next instruction. 239 240 notIdleFraction--; 241 _status = Idle; 242} 243 244 245template <class T> 246Fault 247TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 248{ 249 Request *req = 250 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 251 cpu_id, /* thread ID */ 0); 252 253 if (traceData) { 254 traceData->setAddr(req->getVaddr()); 255 } 256 257 // translate to physical address 258 Fault fault = thread->translateDataReadReq(req); 259 260 // Now do the access. 261 if (fault == NoFault) { 262 PacketPtr pkt = 263 new Packet(req, MemCmd::ReadReq, Packet::Broadcast); 264 pkt->dataDynamic<T>(new T); 265 266 if (!dcachePort.sendTiming(pkt)) { 267 _status = DcacheRetry; 268 dcache_pkt = pkt; 269 } else { 270 _status = DcacheWaitResponse; 271 // memory system takes ownership of packet 272 dcache_pkt = NULL; 273 } 274 275 // This will need a new way to tell if it has a dcache attached. 276 if (req->isUncacheable()) 277 recordEvent("Uncached Read"); 278 } else { 279 delete req; 280 } 281 282 return fault; 283} 284 285#ifndef DOXYGEN_SHOULD_SKIP_THIS 286 287template 288Fault 289TimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags); 290 291template 292Fault 293TimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags); 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 if (traceData) { 345 traceData->setAddr(req->getVaddr()); 346 } 347 348 // translate to physical address 349 Fault fault = thread->translateDataWriteReq(req); 350 351 // Now do the access. 352 if (fault == NoFault) { 353 assert(dcache_pkt == NULL); 354 if (req->isSwap()) 355 dcache_pkt = new Packet(req, MemCmd::SwapReq, Packet::Broadcast); 356 else 357 dcache_pkt = new Packet(req, MemCmd::WriteReq, Packet::Broadcast); 358 dcache_pkt->allocate(); 359 dcache_pkt->set(data); 360 361 bool do_access = true; // flag to suppress cache access 362 363 if (req->isLocked()) { 364 do_access = TheISA::handleLockedWrite(thread, req); 365 } 366 if (req->isCondSwap()) { 367 assert(res); 368 req->setExtraData(*res); 369 } 370 371 if (do_access) { 372 if (!dcachePort.sendTiming(dcache_pkt)) { 373 _status = DcacheRetry; 374 } else { 375 _status = DcacheWaitResponse; 376 // memory system takes ownership of packet 377 dcache_pkt = NULL; 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 } else { 384 delete req; 385 } 386 387 388 // If the write needs to have a fault on the access, consider calling 389 // changeStatus() and changing it to "bad addr write" or something. 390 return fault; 391} 392 393 394#ifndef DOXYGEN_SHOULD_SKIP_THIS 395template 396Fault 397TimingSimpleCPU::write(Twin32_t data, Addr addr, 398 unsigned flags, uint64_t *res); 399 400template 401Fault 402TimingSimpleCPU::write(Twin64_t data, Addr addr, 403 unsigned flags, uint64_t *res); 404 405template 406Fault 407TimingSimpleCPU::write(uint64_t data, Addr addr, 408 unsigned flags, uint64_t *res); 409 410template 411Fault 412TimingSimpleCPU::write(uint32_t data, Addr addr, 413 unsigned flags, uint64_t *res); 414 415template 416Fault 417TimingSimpleCPU::write(uint16_t data, Addr addr, 418 unsigned flags, uint64_t *res); 419 420template 421Fault 422TimingSimpleCPU::write(uint8_t data, Addr addr, 423 unsigned flags, uint64_t *res); 424 425#endif //DOXYGEN_SHOULD_SKIP_THIS 426 427template<> 428Fault 429TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 430{ 431 return write(*(uint64_t*)&data, addr, flags, res); 432} 433 434template<> 435Fault 436TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 437{ 438 return write(*(uint32_t*)&data, addr, flags, res); 439} 440 441 442template<> 443Fault 444TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 445{ 446 return write((uint32_t)data, addr, flags, res); 447} 448 449 450void 451TimingSimpleCPU::fetch() 452{ 453 if (!curStaticInst || !curStaticInst->isDelayedCommit()) 454 checkForInterrupts(); 455 456 Request *ifetch_req = new Request(); 457 ifetch_req->setThreadContext(cpu_id, /* thread ID */ 0); 458 Fault fault = setupFetchRequest(ifetch_req); 459 460 ifetch_pkt = new Packet(ifetch_req, MemCmd::ReadReq, Packet::Broadcast); 461 ifetch_pkt->dataStatic(&inst); 462 463 if (fault == NoFault) { 464 if (!icachePort.sendTiming(ifetch_pkt)) { 465 // Need to wait for retry 466 _status = IcacheRetry; 467 } else { 468 // Need to wait for cache to respond 469 _status = IcacheWaitResponse; 470 // ownership of packet transferred to memory system 471 ifetch_pkt = NULL; 472 } 473 } else { 474 delete ifetch_req; 475 delete ifetch_pkt; 476 // fetch fault: advance directly to next instruction (fault handler) 477 advanceInst(fault); 478 } 479 480 numCycles += curTick - previousTick; 481 previousTick = curTick; 482} 483 484 485void 486TimingSimpleCPU::advanceInst(Fault fault) 487{ 488 advancePC(fault); 489 490 if (_status == Running) { 491 // kick off fetch of next instruction... callback from icache 492 // response will cause that instruction to be executed, 493 // keeping the CPU running. 494 fetch(); 495 } 496} 497 498 499void 500TimingSimpleCPU::completeIfetch(PacketPtr pkt) 501{ 502 // received a response from the icache: execute the received 503 // instruction 504 assert(pkt->result == Packet::Success); 505 assert(_status == IcacheWaitResponse); 506 507 _status = Running; 508 509 numCycles += curTick - previousTick; 510 previousTick = curTick; 511 512 if (getState() == SimObject::Draining) { 513 delete pkt->req; 514 delete pkt; 515 516 completeDrain(); 517 return; 518 } 519 520 preExecute(); 521 if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { 522 // load or store: just send to dcache 523 Fault fault = curStaticInst->initiateAcc(this, traceData); 524 if (_status != Running) { 525 // instruction will complete in dcache response callback 526 assert(_status == DcacheWaitResponse || _status == DcacheRetry); 527 assert(fault == NoFault); 528 } else { 529 if (fault == NoFault) { 530 // early fail on store conditional: complete now 531 assert(dcache_pkt != NULL); 532 fault = curStaticInst->completeAcc(dcache_pkt, this, 533 traceData); 534 delete dcache_pkt->req; 535 delete dcache_pkt; 536 dcache_pkt = NULL; 537 } 538 postExecute(); 539 advanceInst(fault); 540 } 541 } else { 542 // non-memory instruction: execute completely now 543 Fault fault = curStaticInst->execute(this, traceData); 544 postExecute(); 545 advanceInst(fault); 546 } 547 548 delete pkt->req; 549 delete pkt; 550} 551 552void 553TimingSimpleCPU::IcachePort::ITickEvent::process() 554{ 555 cpu->completeIfetch(pkt); 556} 557 558bool 559TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt) 560{ 561 if (pkt->isResponse()) { 562 // delay processing of returned data until next CPU clock edge 563 Tick mem_time = pkt->req->getTime(); 564 Tick next_tick = cpu->nextCycle(mem_time); 565 566 if (next_tick == curTick) 567 cpu->completeIfetch(pkt); 568 else 569 tickEvent.schedule(pkt, next_tick); 570 571 return true; 572 } 573 else if (pkt->result == Packet::Nacked) { 574 assert(cpu->_status == IcacheWaitResponse); 575 pkt->reinitNacked(); 576 if (!sendTiming(pkt)) { 577 cpu->_status = IcacheRetry; 578 cpu->ifetch_pkt = pkt; 579 } 580 } 581 //Snooping a Coherence Request, do nothing 582 return true; 583} 584 585void 586TimingSimpleCPU::IcachePort::recvRetry() 587{ 588 // we shouldn't get a retry unless we have a packet that we're 589 // waiting to transmit 590 assert(cpu->ifetch_pkt != NULL); 591 assert(cpu->_status == IcacheRetry); 592 PacketPtr tmp = cpu->ifetch_pkt; 593 if (sendTiming(tmp)) { 594 cpu->_status = IcacheWaitResponse; 595 cpu->ifetch_pkt = NULL; 596 } 597} 598 599void 600TimingSimpleCPU::completeDataAccess(PacketPtr pkt) 601{ 602 // received a response from the dcache: complete the load or store 603 // instruction 604 assert(pkt->result == Packet::Success); 605 assert(_status == DcacheWaitResponse); 606 _status = Running; 607 608 numCycles += curTick - previousTick; 609 previousTick = curTick; 610 611 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 612 613 if (pkt->isRead() && pkt->req->isLocked()) { 614 TheISA::handleLockedRead(thread, pkt->req); 615 } 616 617 delete pkt->req; 618 delete pkt; 619 620 postExecute(); 621 622 if (getState() == SimObject::Draining) { 623 advancePC(fault); 624 completeDrain(); 625 626 return; 627 } 628 629 advanceInst(fault); 630} 631 632 633void 634TimingSimpleCPU::completeDrain() 635{ 636 DPRINTF(Config, "Done draining\n"); 637 changeState(SimObject::Drained); 638 drainEvent->process(); 639} 640 641void 642TimingSimpleCPU::DcachePort::setPeer(Port *port) 643{ 644 Port::setPeer(port); 645 646#if FULL_SYSTEM 647 // Update the ThreadContext's memory ports (Functional/Virtual 648 // Ports) 649 cpu->tcBase()->connectMemPorts(); 650#endif 651} 652 653bool 654TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt) 655{ 656 if (pkt->isResponse()) { 657 // delay processing of returned data until next CPU clock edge 658 Tick mem_time = pkt->req->getTime(); 659 Tick next_tick = cpu->nextCycle(mem_time); 660 661 if (next_tick == curTick) 662 cpu->completeDataAccess(pkt); 663 else 664 tickEvent.schedule(pkt, next_tick); 665 666 return true; 667 } 668 else if (pkt->result == Packet::Nacked) { 669 assert(cpu->_status == DcacheWaitResponse); 670 pkt->reinitNacked(); 671 if (!sendTiming(pkt)) { 672 cpu->_status = DcacheRetry; 673 cpu->dcache_pkt = pkt; 674 } 675 } 676 //Snooping a Coherence Request, do nothing 677 return true; 678} 679 680void 681TimingSimpleCPU::DcachePort::DTickEvent::process() 682{ 683 cpu->completeDataAccess(pkt); 684} 685 686void 687TimingSimpleCPU::DcachePort::recvRetry() 688{ 689 // we shouldn't get a retry unless we have a packet that we're 690 // waiting to transmit 691 assert(cpu->dcache_pkt != NULL); 692 assert(cpu->_status == DcacheRetry); 693 PacketPtr tmp = cpu->dcache_pkt; 694 if (sendTiming(tmp)) { 695 cpu->_status = DcacheWaitResponse; 696 // memory system takes ownership of packet 697 cpu->dcache_pkt = NULL; 698 } 699} 700 701 702//////////////////////////////////////////////////////////////////////// 703// 704// TimingSimpleCPU Simulation Object 705// 706BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 707 708 Param<Counter> max_insts_any_thread; 709 Param<Counter> max_insts_all_threads; 710 Param<Counter> max_loads_any_thread; 711 Param<Counter> max_loads_all_threads; 712 Param<Tick> progress_interval; 713 SimObjectParam<System *> system; 714 Param<int> cpu_id; 715 716#if FULL_SYSTEM 717 SimObjectParam<TheISA::ITB *> itb; 718 SimObjectParam<TheISA::DTB *> dtb; 719 Param<Tick> profile; 720 721 Param<bool> do_quiesce; 722 Param<bool> do_checkpoint_insts; 723 Param<bool> do_statistics_insts; 724#else 725 SimObjectParam<Process *> workload; 726#endif // FULL_SYSTEM 727 728 Param<int> clock; 729 Param<int> phase; 730 731 Param<bool> defer_registration; 732 Param<int> width; 733 Param<bool> function_trace; 734 Param<Tick> function_trace_start; 735 Param<bool> simulate_stalls; 736 737END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 738 739BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 740 741 INIT_PARAM(max_insts_any_thread, 742 "terminate when any thread reaches this inst count"), 743 INIT_PARAM(max_insts_all_threads, 744 "terminate when all threads have reached this inst count"), 745 INIT_PARAM(max_loads_any_thread, 746 "terminate when any thread reaches this load count"), 747 INIT_PARAM(max_loads_all_threads, 748 "terminate when all threads have reached this load count"), 749 INIT_PARAM(progress_interval, "Progress interval"), 750 INIT_PARAM(system, "system object"), 751 INIT_PARAM(cpu_id, "processor ID"), 752 753#if FULL_SYSTEM 754 INIT_PARAM(itb, "Instruction TLB"), 755 INIT_PARAM(dtb, "Data TLB"), 756 INIT_PARAM(profile, ""), 757 INIT_PARAM(do_quiesce, ""), 758 INIT_PARAM(do_checkpoint_insts, ""), 759 INIT_PARAM(do_statistics_insts, ""), 760#else 761 INIT_PARAM(workload, "processes to run"), 762#endif // FULL_SYSTEM 763 764 INIT_PARAM(clock, "clock speed"), 765 INIT_PARAM_DFLT(phase, "clock phase", 0), 766 INIT_PARAM(defer_registration, "defer system registration (for sampling)"), 767 INIT_PARAM(width, "cpu width"), 768 INIT_PARAM(function_trace, "Enable function trace"), 769 INIT_PARAM(function_trace_start, "Cycle to start function trace"), 770 INIT_PARAM(simulate_stalls, "Simulate cache stall cycles") 771 772END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 773 774 775CREATE_SIM_OBJECT(TimingSimpleCPU) 776{ 777 TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params(); 778 params->name = getInstanceName(); 779 params->numberOfThreads = 1; 780 params->max_insts_any_thread = max_insts_any_thread; 781 params->max_insts_all_threads = max_insts_all_threads; 782 params->max_loads_any_thread = max_loads_any_thread; 783 params->max_loads_all_threads = max_loads_all_threads; 784 params->progress_interval = progress_interval; 785 params->deferRegistration = defer_registration; 786 params->clock = clock; 787 params->phase = phase; 788 params->functionTrace = function_trace; 789 params->functionTraceStart = function_trace_start; 790 params->system = system; 791 params->cpu_id = cpu_id; 792 793#if FULL_SYSTEM 794 params->itb = itb; 795 params->dtb = dtb; 796 params->profile = profile; 797 params->do_quiesce = do_quiesce; 798 params->do_checkpoint_insts = do_checkpoint_insts; 799 params->do_statistics_insts = do_statistics_insts; 800#else 801 params->process = workload; 802#endif 803 804 TimingSimpleCPU *cpu = new TimingSimpleCPU(params); 805 return cpu; 806} 807 808REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU) 809
|