timing.cc revision 3201:7c3b18c01b0e
12497SN/A/* 210719SMarco.Balboni@ARM.com * Copyright (c) 2002-2005 The Regents of The University of Michigan 38711SN/A * All rights reserved. 48711SN/A * 58711SN/A * Redistribution and use in source and binary forms, with or without 68711SN/A * modification, are permitted provided that the following conditions are 78711SN/A * met: redistributions of source code must retain the above copyright 88711SN/A * notice, this list of conditions and the following disclaimer; 98711SN/A * redistributions in binary form must reproduce the above copyright 108711SN/A * notice, this list of conditions and the following disclaimer in the 118711SN/A * documentation and/or other materials provided with the distribution; 128711SN/A * neither the name of the copyright holders nor the names of its 138711SN/A * contributors may be used to endorse or promote products derived from 142497SN/A * this software without specific prior written permission. 152497SN/A * 162497SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172497SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182497SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192497SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202497SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212497SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222497SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232497SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242497SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252497SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262497SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272497SN/A * 282497SN/A * Authors: Steve Reinhardt 292497SN/A */ 302497SN/A 312497SN/A#include "arch/locked_mem.hh" 322497SN/A#include "arch/utility.hh" 332497SN/A#include "cpu/exetrace.hh" 342497SN/A#include "cpu/simple/timing.hh" 352497SN/A#include "mem/packet_impl.hh" 362497SN/A#include "sim/builder.hh" 372497SN/A#include "sim/system.hh" 382497SN/A 392665SN/Ausing namespace std; 402665SN/Ausing namespace TheISA; 418715SN/A 428922SN/APort * 432497SN/ATimingSimpleCPU::getPort(const std::string &if_name, int idx) 442497SN/A{ 452497SN/A if (if_name == "dcache_port") 462982SN/A return &dcachePort; 4710405Sandreas.hansson@arm.com else if (if_name == "icache_port") 482497SN/A return &icachePort; 492497SN/A else 5011793Sbrandon.potter@amd.com panic("No Such Port\n"); 5111793Sbrandon.potter@amd.com} 522846SN/A 532548SN/Avoid 5410405Sandreas.hansson@arm.comTimingSimpleCPU::init() 5510405Sandreas.hansson@arm.com{ 562497SN/A BaseCPU::init(); 5710405Sandreas.hansson@arm.com#if FULL_SYSTEM 5810405Sandreas.hansson@arm.com for (int i = 0; i < threadContexts.size(); ++i) { 597523SN/A ThreadContext *tc = threadContexts[i]; 608851SN/A 618948SN/A // initialize CPU, including PC 628948SN/A TheISA::initCPU(tc, tc->readCpuId()); 638851SN/A } 649095SN/A#endif 6510405Sandreas.hansson@arm.com} 668922SN/A 679715SN/ATick 689715SN/ATimingSimpleCPU::CpuPort::recvAtomic(Packet *pkt) 698851SN/A{ 708851SN/A panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 718948SN/A return curTick; 728948SN/A} 738915SN/A 749031SN/Avoid 759095SN/ATimingSimpleCPU::CpuPort::recvFunctional(Packet *pkt) 7610405Sandreas.hansson@arm.com{ 779036SN/A //No internal storage to update, jusst return 788922SN/A return; 799715SN/A} 809715SN/A 818915SN/Avoid 828915SN/ATimingSimpleCPU::CpuPort::recvStatusChange(Status status) 838948SN/A{ 848851SN/A if (status == RangeChange) 859095SN/A return; 8610888Sandreas.hansson@arm.com 878922SN/A panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); 889715SN/A} 899715SN/A 908851SN/A 918851SN/Avoid 927523SN/ATimingSimpleCPU::CpuPort::TickEvent::schedule(Packet *_pkt, Tick t) 937523SN/A{ 947523SN/A pkt = _pkt; 9510405Sandreas.hansson@arm.com Event::schedule(t); 969715SN/A} 9710405Sandreas.hansson@arm.com 9810405Sandreas.hansson@arm.comTimingSimpleCPU::TimingSimpleCPU(Params *p) 9910405Sandreas.hansson@arm.com : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock), 10010405Sandreas.hansson@arm.com cpu_id(p->cpu_id) 1019715SN/A{ 1029715SN/A _status = Idle; 1038948SN/A ifetch_pkt = dcache_pkt = NULL; 10410405Sandreas.hansson@arm.com drainEvent = NULL; 1053244SN/A fetchEvent = NULL; 1068975SN/A changeState(SimObject::Running); 1079032SN/A} 1083244SN/A 10910405Sandreas.hansson@arm.com 1109036SN/ATimingSimpleCPU::~TimingSimpleCPU() 1119036SN/A{ 1129612SN/A} 1139712SN/A 1149612SN/Avoid 11510405Sandreas.hansson@arm.comTimingSimpleCPU::serialize(ostream &os) 1169036SN/A{ 1179715SN/A SimObject::State so_state = SimObject::getState(); 11810405Sandreas.hansson@arm.com SERIALIZE_ENUM(so_state); 1198949SN/A BaseSimpleCPU::serialize(os); 1203244SN/A} 1213244SN/A 1223244SN/Avoid 12310405Sandreas.hansson@arm.comTimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 1248949SN/A{ 1255197SN/A SimObject::State so_state; 1269712SN/A UNSERIALIZE_ENUM(so_state); 1279712SN/A BaseSimpleCPU::unserialize(cp, section); 1289712SN/A} 1299712SN/A 1309712SN/Aunsigned int 13110719SMarco.Balboni@ARM.comTimingSimpleCPU::drain(Event *drain_event) 13210719SMarco.Balboni@ARM.com{ 13310719SMarco.Balboni@ARM.com // TimingSimpleCPU is ready to drain if it's not waiting for 13410719SMarco.Balboni@ARM.com // an access to complete. 13510719SMarco.Balboni@ARM.com if (status() == Idle || status() == Running || status() == SwitchedOut) { 13610719SMarco.Balboni@ARM.com changeState(SimObject::Drained); 13710719SMarco.Balboni@ARM.com return 0; 13810719SMarco.Balboni@ARM.com } else { 13910719SMarco.Balboni@ARM.com changeState(SimObject::Draining); 14010719SMarco.Balboni@ARM.com drainEvent = drain_event; 14110719SMarco.Balboni@ARM.com return 1; 1428915SN/A } 14310656Sandreas.hansson@arm.com} 14410656Sandreas.hansson@arm.com 14510656Sandreas.hansson@arm.comvoid 14611284Sandreas.hansson@arm.comTimingSimpleCPU::resume() 14710656Sandreas.hansson@arm.com{ 1489612SN/A if (_status != SwitchedOut && _status != Idle) { 1499712SN/A assert(system->getMemoryMode() == System::Timing); 1508948SN/A 1518975SN/A // Delete the old event if it existed. 15210405Sandreas.hansson@arm.com if (fetchEvent) { 1538975SN/A if (fetchEvent->scheduled()) 1548948SN/A fetchEvent->deschedule(); 15510719SMarco.Balboni@ARM.com 15610719SMarco.Balboni@ARM.com delete fetchEvent; 1579549SN/A } 1589547SN/A 1599715SN/A fetchEvent = 16010719SMarco.Balboni@ARM.com new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false); 1618948SN/A fetchEvent->schedule(curTick); 1628975SN/A } 1638975SN/A 1648975SN/A changeState(SimObject::Running); 16510656Sandreas.hansson@arm.com} 16610656Sandreas.hansson@arm.com 16710656Sandreas.hansson@arm.comvoid 16810656Sandreas.hansson@arm.comTimingSimpleCPU::switchOut() 16910656Sandreas.hansson@arm.com{ 17010656Sandreas.hansson@arm.com assert(status() == Running || status() == Idle); 1719715SN/A _status = SwitchedOut; 1728975SN/A 1739712SN/A // If we've been scheduled to resume but are then told to switch out, 1749712SN/A // we'll need to cancel it. 17510405Sandreas.hansson@arm.com if (fetchEvent && fetchEvent->scheduled()) 1769712SN/A fetchEvent->deschedule(); 1779712SN/A} 1788975SN/A 1798975SN/A 1808975SN/Avoid 1818975SN/ATimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 18210405Sandreas.hansson@arm.com{ 1838975SN/A BaseCPU::takeOverFrom(oldCPU); 1848975SN/A 1859032SN/A // if any of this CPU's ThreadContexts are active, mark the CPU as 1868975SN/A // running and schedule its tick event. 18710656Sandreas.hansson@arm.com for (int i = 0; i < threadContexts.size(); ++i) { 18810656Sandreas.hansson@arm.com ThreadContext *tc = threadContexts[i]; 18910656Sandreas.hansson@arm.com if (tc->status() == ThreadContext::Active && _status != Running) { 19010656Sandreas.hansson@arm.com _status = Running; 19110572Sandreas.hansson@arm.com break; 19210572Sandreas.hansson@arm.com } 1939713SN/A } 19410405Sandreas.hansson@arm.com 1959033SN/A if (_status != Running) { 1969715SN/A _status = Idle; 19710405Sandreas.hansson@arm.com } 1988975SN/A} 1998975SN/A 2008975SN/A 2018975SN/Avoid 20210405Sandreas.hansson@arm.comTimingSimpleCPU::activateContext(int thread_num, int delay) 2038975SN/A{ 2048975SN/A assert(thread_num == 0); 2059712SN/A assert(thread); 2069712SN/A 2079712SN/A assert(_status == Idle); 2089712SN/A 2099712SN/A notIdleFraction++; 21010719SMarco.Balboni@ARM.com _status = Running; 21110719SMarco.Balboni@ARM.com // kick things off by initiating the fetch of the next instruction 21210719SMarco.Balboni@ARM.com fetchEvent = 21310719SMarco.Balboni@ARM.com new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false); 21410719SMarco.Balboni@ARM.com fetchEvent->schedule(curTick + cycles(delay)); 21510719SMarco.Balboni@ARM.com} 21610719SMarco.Balboni@ARM.com 21710719SMarco.Balboni@ARM.com 2188975SN/Avoid 21910888Sandreas.hansson@arm.comTimingSimpleCPU::suspendContext(int thread_num) 22010888Sandreas.hansson@arm.com{ 22110888Sandreas.hansson@arm.com assert(thread_num == 0); 22210888Sandreas.hansson@arm.com assert(thread); 22310888Sandreas.hansson@arm.com 2248975SN/A assert(_status == Running); 22510656Sandreas.hansson@arm.com 22610656Sandreas.hansson@arm.com // just change status to Idle... if status != Running, 22710656Sandreas.hansson@arm.com // completeInst() will not initiate fetch of next instruction. 2289715SN/A 2298975SN/A notIdleFraction--; 2309712SN/A _status = Idle; 2319712SN/A} 23210405Sandreas.hansson@arm.com 2339712SN/A 2349712SN/Atemplate <class T> 2358975SN/AFault 2368975SN/ATimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 2378975SN/A{ 2389092SN/A Request *req = 23910713Sandreas.hansson@arm.com new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 2409092SN/A cpu_id, /* thread ID */ 0); 2419093SN/A 2429093SN/A if (traceData) { 2439093SN/A traceData->setAddr(req->getVaddr()); 2449715SN/A } 2459092SN/A 2469092SN/A // translate to physical address 2479036SN/A Fault fault = thread->translateDataReadReq(req); 24810405Sandreas.hansson@arm.com 2498975SN/A // Now do the access. 25010405Sandreas.hansson@arm.com if (fault == NoFault) { 2519032SN/A Packet *pkt = 2528949SN/A new Packet(req, Packet::ReadReq, Packet::Broadcast); 2538915SN/A pkt->dataDynamic<T>(new T); 25410405Sandreas.hansson@arm.com 25510405Sandreas.hansson@arm.com if (!dcachePort.sendTiming(pkt)) { 2569712SN/A _status = DcacheRetry; 2579036SN/A dcache_pkt = pkt; 25810405Sandreas.hansson@arm.com } else { 25910405Sandreas.hansson@arm.com _status = DcacheWaitResponse; 26010405Sandreas.hansson@arm.com // memory system takes ownership of packet 26110405Sandreas.hansson@arm.com dcache_pkt = NULL; 26210405Sandreas.hansson@arm.com } 26310405Sandreas.hansson@arm.com } 2648948SN/A 2658948SN/A // This will need a new way to tell if it has a dcache attached. 26610405Sandreas.hansson@arm.com if (req->isUncacheable()) 2678948SN/A recordEvent("Uncached Read"); 2689712SN/A 26910405Sandreas.hansson@arm.com return fault; 27010405Sandreas.hansson@arm.com} 27110405Sandreas.hansson@arm.com 27210405Sandreas.hansson@arm.com#ifndef DOXYGEN_SHOULD_SKIP_THIS 27310405Sandreas.hansson@arm.com 27410405Sandreas.hansson@arm.comtemplate 27510405Sandreas.hansson@arm.comFault 27610405Sandreas.hansson@arm.comTimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 27710405Sandreas.hansson@arm.com 2789712SN/Atemplate 2799547SN/AFault 28010694SMarco.Balboni@ARM.comTimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 2818948SN/A 2828948SN/Atemplate 2838948SN/AFault 2842497SN/ATimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 28510405Sandreas.hansson@arm.com 2862497SN/Atemplate 2878663SN/AFault 2888663SN/ATimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 28910405Sandreas.hansson@arm.com 2908949SN/A#endif //DOXYGEN_SHOULD_SKIP_THIS 2919032SN/A 2928663SN/Atemplate<> 2938663SN/AFault 2948663SN/ATimingSimpleCPU::read(Addr addr, double &data, unsigned flags) 29510888Sandreas.hansson@arm.com{ 29610888Sandreas.hansson@arm.com return read(addr, *(uint64_t*)&data, flags); 29710888Sandreas.hansson@arm.com} 29810888Sandreas.hansson@arm.com 29910888Sandreas.hansson@arm.comtemplate<> 30010888Sandreas.hansson@arm.comFault 30110888Sandreas.hansson@arm.comTimingSimpleCPU::read(Addr addr, float &data, unsigned flags) 30210888Sandreas.hansson@arm.com{ 30310888Sandreas.hansson@arm.com return read(addr, *(uint32_t*)&data, flags); 30410888Sandreas.hansson@arm.com} 30510888Sandreas.hansson@arm.com 30610888Sandreas.hansson@arm.com 3079036SN/Atemplate<> 3089036SN/AFault 3094912SN/ATimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 3109036SN/A{ 3119036SN/A return read(addr, (uint32_t&)data, flags); 3128948SN/A} 3138948SN/A 31410405Sandreas.hansson@arm.com 31510405Sandreas.hansson@arm.comtemplate <class T> 3168948SN/AFault 31710405Sandreas.hansson@arm.comTimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 3188948SN/A{ 3199712SN/A Request *req = 3209712SN/A new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 32110405Sandreas.hansson@arm.com cpu_id, /* thread ID */ 0); 3229712SN/A 32310405Sandreas.hansson@arm.com // translate to physical address 32410405Sandreas.hansson@arm.com Fault fault = thread->translateDataWriteReq(req); 32510405Sandreas.hansson@arm.com 32610405Sandreas.hansson@arm.com // Now do the access. 32710405Sandreas.hansson@arm.com if (fault == NoFault) { 32810405Sandreas.hansson@arm.com assert(dcache_pkt == NULL); 3299712SN/A dcache_pkt = new Packet(req, Packet::WriteReq, Packet::Broadcast); 330 dcache_pkt->allocate(); 331 dcache_pkt->set(data); 332 333 bool do_access = true; // flag to suppress cache access 334 335 if (req->isLocked()) { 336 do_access = TheISA::handleLockedWrite(thread, req); 337 } 338 339 if (do_access) { 340 if (!dcachePort.sendTiming(dcache_pkt)) { 341 _status = DcacheRetry; 342 } else { 343 _status = DcacheWaitResponse; 344 // memory system takes ownership of packet 345 dcache_pkt = NULL; 346 } 347 } 348 } 349 350 // This will need a new way to tell if it's hooked up to a cache or not. 351 if (req->isUncacheable()) 352 recordEvent("Uncached Write"); 353 354 // If the write needs to have a fault on the access, consider calling 355 // changeStatus() and changing it to "bad addr write" or something. 356 return fault; 357} 358 359 360#ifndef DOXYGEN_SHOULD_SKIP_THIS 361template 362Fault 363TimingSimpleCPU::write(uint64_t data, Addr addr, 364 unsigned flags, uint64_t *res); 365 366template 367Fault 368TimingSimpleCPU::write(uint32_t data, Addr addr, 369 unsigned flags, uint64_t *res); 370 371template 372Fault 373TimingSimpleCPU::write(uint16_t data, Addr addr, 374 unsigned flags, uint64_t *res); 375 376template 377Fault 378TimingSimpleCPU::write(uint8_t data, Addr addr, 379 unsigned flags, uint64_t *res); 380 381#endif //DOXYGEN_SHOULD_SKIP_THIS 382 383template<> 384Fault 385TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 386{ 387 return write(*(uint64_t*)&data, addr, flags, res); 388} 389 390template<> 391Fault 392TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 393{ 394 return write(*(uint32_t*)&data, addr, flags, res); 395} 396 397 398template<> 399Fault 400TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 401{ 402 return write((uint32_t)data, addr, flags, res); 403} 404 405 406void 407TimingSimpleCPU::fetch() 408{ 409 checkForInterrupts(); 410 411 Request *ifetch_req = new Request(); 412 ifetch_req->setThreadContext(cpu_id, /* thread ID */ 0); 413 Fault fault = setupFetchRequest(ifetch_req); 414 415 ifetch_pkt = new Packet(ifetch_req, Packet::ReadReq, Packet::Broadcast); 416 ifetch_pkt->dataStatic(&inst); 417 418 if (fault == NoFault) { 419 if (!icachePort.sendTiming(ifetch_pkt)) { 420 // Need to wait for retry 421 _status = IcacheRetry; 422 } else { 423 // Need to wait for cache to respond 424 _status = IcacheWaitResponse; 425 // ownership of packet transferred to memory system 426 ifetch_pkt = NULL; 427 } 428 } else { 429 // fetch fault: advance directly to next instruction (fault handler) 430 advanceInst(fault); 431 } 432} 433 434 435void 436TimingSimpleCPU::advanceInst(Fault fault) 437{ 438 advancePC(fault); 439 440 if (_status == Running) { 441 // kick off fetch of next instruction... callback from icache 442 // response will cause that instruction to be executed, 443 // keeping the CPU running. 444 fetch(); 445 } 446} 447 448 449void 450TimingSimpleCPU::completeIfetch(Packet *pkt) 451{ 452 // received a response from the icache: execute the received 453 // instruction 454 assert(pkt->result == Packet::Success); 455 assert(_status == IcacheWaitResponse); 456 457 _status = Running; 458 459 delete pkt->req; 460 delete pkt; 461 462 if (getState() == SimObject::Draining) { 463 completeDrain(); 464 return; 465 } 466 467 preExecute(); 468 if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { 469 // load or store: just send to dcache 470 Fault fault = curStaticInst->initiateAcc(this, traceData); 471 if (_status != Running) { 472 // instruction will complete in dcache response callback 473 assert(_status == DcacheWaitResponse || _status == DcacheRetry); 474 assert(fault == NoFault); 475 } else { 476 if (fault == NoFault) { 477 // early fail on store conditional: complete now 478 assert(dcache_pkt != NULL); 479 fault = curStaticInst->completeAcc(dcache_pkt, this, 480 traceData); 481 delete dcache_pkt->req; 482 delete dcache_pkt; 483 dcache_pkt = NULL; 484 } 485 postExecute(); 486 advanceInst(fault); 487 } 488 } else { 489 // non-memory instruction: execute completely now 490 Fault fault = curStaticInst->execute(this, traceData); 491 postExecute(); 492 advanceInst(fault); 493 } 494} 495 496void 497TimingSimpleCPU::IcachePort::ITickEvent::process() 498{ 499 cpu->completeIfetch(pkt); 500} 501 502bool 503TimingSimpleCPU::IcachePort::recvTiming(Packet *pkt) 504{ 505 // delay processing of returned data until next CPU clock edge 506 Tick time = pkt->req->getTime(); 507 while (time < curTick) 508 time += lat; 509 510 if (time == curTick) 511 cpu->completeIfetch(pkt); 512 else 513 tickEvent.schedule(pkt, time); 514 515 return true; 516} 517 518void 519TimingSimpleCPU::IcachePort::recvRetry() 520{ 521 // we shouldn't get a retry unless we have a packet that we're 522 // waiting to transmit 523 assert(cpu->ifetch_pkt != NULL); 524 assert(cpu->_status == IcacheRetry); 525 Packet *tmp = cpu->ifetch_pkt; 526 if (sendTiming(tmp)) { 527 cpu->_status = IcacheWaitResponse; 528 cpu->ifetch_pkt = NULL; 529 } 530} 531 532void 533TimingSimpleCPU::completeDataAccess(Packet *pkt) 534{ 535 // received a response from the dcache: complete the load or store 536 // instruction 537 assert(pkt->result == Packet::Success); 538 assert(_status == DcacheWaitResponse); 539 _status = Running; 540 541 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 542 543 if (pkt->isRead() && pkt->req->isLocked()) { 544 TheISA::handleLockedRead(thread, pkt->req); 545 } 546 547 delete pkt->req; 548 delete pkt; 549 550 if (getState() == SimObject::Draining) { 551 advancePC(fault); 552 completeDrain(); 553 554 return; 555 } 556 557 postExecute(); 558 advanceInst(fault); 559} 560 561 562void 563TimingSimpleCPU::completeDrain() 564{ 565 DPRINTF(Config, "Done draining\n"); 566 changeState(SimObject::Drained); 567 drainEvent->process(); 568} 569 570bool 571TimingSimpleCPU::DcachePort::recvTiming(Packet *pkt) 572{ 573 // delay processing of returned data until next CPU clock edge 574 Tick time = pkt->req->getTime(); 575 while (time < curTick) 576 time += lat; 577 578 if (time == curTick) 579 cpu->completeDataAccess(pkt); 580 else 581 tickEvent.schedule(pkt, time); 582 583 return true; 584} 585 586void 587TimingSimpleCPU::DcachePort::DTickEvent::process() 588{ 589 cpu->completeDataAccess(pkt); 590} 591 592void 593TimingSimpleCPU::DcachePort::recvRetry() 594{ 595 // we shouldn't get a retry unless we have a packet that we're 596 // waiting to transmit 597 assert(cpu->dcache_pkt != NULL); 598 assert(cpu->_status == DcacheRetry); 599 Packet *tmp = cpu->dcache_pkt; 600 if (sendTiming(tmp)) { 601 cpu->_status = DcacheWaitResponse; 602 // memory system takes ownership of packet 603 cpu->dcache_pkt = NULL; 604 } 605} 606 607 608//////////////////////////////////////////////////////////////////////// 609// 610// TimingSimpleCPU Simulation Object 611// 612BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 613 614 Param<Counter> max_insts_any_thread; 615 Param<Counter> max_insts_all_threads; 616 Param<Counter> max_loads_any_thread; 617 Param<Counter> max_loads_all_threads; 618 Param<Tick> progress_interval; 619 SimObjectParam<MemObject *> mem; 620 SimObjectParam<System *> system; 621 Param<int> cpu_id; 622 623#if FULL_SYSTEM 624 SimObjectParam<AlphaITB *> itb; 625 SimObjectParam<AlphaDTB *> dtb; 626 Param<Tick> profile; 627#else 628 SimObjectParam<Process *> workload; 629#endif // FULL_SYSTEM 630 631 Param<int> clock; 632 633 Param<bool> defer_registration; 634 Param<int> width; 635 Param<bool> function_trace; 636 Param<Tick> function_trace_start; 637 Param<bool> simulate_stalls; 638 639END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 640 641BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 642 643 INIT_PARAM(max_insts_any_thread, 644 "terminate when any thread reaches this inst count"), 645 INIT_PARAM(max_insts_all_threads, 646 "terminate when all threads have reached this inst count"), 647 INIT_PARAM(max_loads_any_thread, 648 "terminate when any thread reaches this load count"), 649 INIT_PARAM(max_loads_all_threads, 650 "terminate when all threads have reached this load count"), 651 INIT_PARAM(progress_interval, "Progress interval"), 652 INIT_PARAM(mem, "memory"), 653 INIT_PARAM(system, "system object"), 654 INIT_PARAM(cpu_id, "processor ID"), 655 656#if FULL_SYSTEM 657 INIT_PARAM(itb, "Instruction TLB"), 658 INIT_PARAM(dtb, "Data TLB"), 659 INIT_PARAM(profile, ""), 660#else 661 INIT_PARAM(workload, "processes to run"), 662#endif // FULL_SYSTEM 663 664 INIT_PARAM(clock, "clock speed"), 665 INIT_PARAM(defer_registration, "defer system registration (for sampling)"), 666 INIT_PARAM(width, "cpu width"), 667 INIT_PARAM(function_trace, "Enable function trace"), 668 INIT_PARAM(function_trace_start, "Cycle to start function trace"), 669 INIT_PARAM(simulate_stalls, "Simulate cache stall cycles") 670 671END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 672 673 674CREATE_SIM_OBJECT(TimingSimpleCPU) 675{ 676 TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params(); 677 params->name = getInstanceName(); 678 params->numberOfThreads = 1; 679 params->max_insts_any_thread = max_insts_any_thread; 680 params->max_insts_all_threads = max_insts_all_threads; 681 params->max_loads_any_thread = max_loads_any_thread; 682 params->max_loads_all_threads = max_loads_all_threads; 683 params->progress_interval = progress_interval; 684 params->deferRegistration = defer_registration; 685 params->clock = clock; 686 params->functionTrace = function_trace; 687 params->functionTraceStart = function_trace_start; 688 params->mem = mem; 689 params->system = system; 690 params->cpu_id = cpu_id; 691 692#if FULL_SYSTEM 693 params->itb = itb; 694 params->dtb = dtb; 695 params->profile = profile; 696#else 697 params->process = workload; 698#endif 699 700 TimingSimpleCPU *cpu = new TimingSimpleCPU(params); 701 return cpu; 702} 703 704REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU) 705 706