timing.cc revision 5669
12221SN/A/* 22221SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 32221SN/A * All rights reserved. 42221SN/A * 52221SN/A * Redistribution and use in source and binary forms, with or without 62221SN/A * modification, are permitted provided that the following conditions are 72221SN/A * met: redistributions of source code must retain the above copyright 82221SN/A * notice, this list of conditions and the following disclaimer; 92221SN/A * redistributions in binary form must reproduce the above copyright 102221SN/A * notice, this list of conditions and the following disclaimer in the 112221SN/A * documentation and/or other materials provided with the distribution; 122221SN/A * neither the name of the copyright holders nor the names of its 132221SN/A * contributors may be used to endorse or promote products derived from 142221SN/A * this software without specific prior written permission. 152221SN/A * 162221SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172221SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182221SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192221SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202221SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212221SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222221SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232221SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242221SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252221SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262221SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu * 282665Ssaidi@eecs.umich.edu * Authors: Steve Reinhardt 292665Ssaidi@eecs.umich.edu */ 302221SN/A 312221SN/A#include "arch/locked_mem.hh" 323890Ssaidi@eecs.umich.edu#include "arch/mmaped_ipr.hh" 333890Ssaidi@eecs.umich.edu#include "arch/utility.hh" 342221SN/A#include "base/bigint.hh" 354997Sgblack@eecs.umich.edu#include "cpu/exetrace.hh" 367678Sgblack@eecs.umich.edu#include "cpu/simple/timing.hh" 372221SN/A#include "mem/packet.hh" 382221SN/A#include "mem/packet_access.hh" 392221SN/A#include "params/TimingSimpleCPU.hh" 402221SN/A#include "sim/system.hh" 412223SN/A 422221SN/Ausing namespace std; 432221SN/Ausing namespace TheISA; 443415Sgblack@eecs.umich.edu 453415Sgblack@eecs.umich.eduPort * 462221SN/ATimingSimpleCPU::getPort(const std::string &if_name, int idx) 474997Sgblack@eecs.umich.edu{ 484997Sgblack@eecs.umich.edu if (if_name == "dcache_port") 493573Sgblack@eecs.umich.edu return &dcachePort; 502221SN/A else if (if_name == "icache_port") 512221SN/A return &icachePort; 523576Sgblack@eecs.umich.edu else 533576Sgblack@eecs.umich.edu panic("No Such Port\n"); 543576Sgblack@eecs.umich.edu} 553576Sgblack@eecs.umich.edu 563576Sgblack@eecs.umich.eduvoid 573576Sgblack@eecs.umich.eduTimingSimpleCPU::init() 583576Sgblack@eecs.umich.edu{ 593576Sgblack@eecs.umich.edu BaseCPU::init(); 603576Sgblack@eecs.umich.edu cpuId = tc->readCpuId(); 613573Sgblack@eecs.umich.edu#if FULL_SYSTEM 623573Sgblack@eecs.umich.edu for (int i = 0; i < threadContexts.size(); ++i) { 633573Sgblack@eecs.umich.edu ThreadContext *tc = threadContexts[i]; 643573Sgblack@eecs.umich.edu 653573Sgblack@eecs.umich.edu // initialize CPU, including PC 663576Sgblack@eecs.umich.edu TheISA::initCPU(tc, cpuId); 673573Sgblack@eecs.umich.edu } 683573Sgblack@eecs.umich.edu#endif 692221SN/A} 707678Sgblack@eecs.umich.edu 717678Sgblack@eecs.umich.eduTick 722221SN/ATimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) 732223SN/A{ 742223SN/A panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 752223SN/A return curTick; 763576Sgblack@eecs.umich.edu} 772221SN/A 782221SN/Avoid 793573Sgblack@eecs.umich.eduTimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) 803573Sgblack@eecs.umich.edu{ 812221SN/A //No internal storage to update, jusst return 823573Sgblack@eecs.umich.edu return; 833573Sgblack@eecs.umich.edu} 842221SN/A 854695Sgblack@eecs.umich.eduvoid 863573Sgblack@eecs.umich.eduTimingSimpleCPU::CpuPort::recvStatusChange(Status status) 873573Sgblack@eecs.umich.edu{ 883573Sgblack@eecs.umich.edu if (status == RangeChange) { 893576Sgblack@eecs.umich.edu if (!snoopRangeSent) { 903576Sgblack@eecs.umich.edu snoopRangeSent = true; 913576Sgblack@eecs.umich.edu sendStatusChange(Port::RangeChange); 923576Sgblack@eecs.umich.edu } 933573Sgblack@eecs.umich.edu return; 943573Sgblack@eecs.umich.edu } 953576Sgblack@eecs.umich.edu 963576Sgblack@eecs.umich.edu panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); 977678Sgblack@eecs.umich.edu} 987678Sgblack@eecs.umich.edu 997678Sgblack@eecs.umich.edu 1007678Sgblack@eecs.umich.eduvoid 1013576Sgblack@eecs.umich.eduTimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) 1023576Sgblack@eecs.umich.edu{ 1033576Sgblack@eecs.umich.edu pkt = _pkt; 1043576Sgblack@eecs.umich.edu cpu->schedule(this, t); 1053576Sgblack@eecs.umich.edu} 1063576Sgblack@eecs.umich.edu 1073576Sgblack@eecs.umich.eduTimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) 1083576Sgblack@eecs.umich.edu : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock) 1093576Sgblack@eecs.umich.edu{ 1103576Sgblack@eecs.umich.edu _status = Idle; 1113576Sgblack@eecs.umich.edu 1123576Sgblack@eecs.umich.edu icachePort.snoopRangeSent = false; 1133576Sgblack@eecs.umich.edu dcachePort.snoopRangeSent = false; 1143576Sgblack@eecs.umich.edu 1153576Sgblack@eecs.umich.edu ifetch_pkt = dcache_pkt = NULL; 1163576Sgblack@eecs.umich.edu drainEvent = NULL; 1173576Sgblack@eecs.umich.edu fetchEvent = NULL; 1183576Sgblack@eecs.umich.edu previousTick = 0; 1193576Sgblack@eecs.umich.edu changeState(SimObject::Running); 1203576Sgblack@eecs.umich.edu} 1213576Sgblack@eecs.umich.edu 1223576Sgblack@eecs.umich.edu 1233576Sgblack@eecs.umich.eduTimingSimpleCPU::~TimingSimpleCPU() 1243576Sgblack@eecs.umich.edu{ 1253576Sgblack@eecs.umich.edu} 1263576Sgblack@eecs.umich.edu 1273576Sgblack@eecs.umich.eduvoid 1283576Sgblack@eecs.umich.eduTimingSimpleCPU::serialize(ostream &os) 1293576Sgblack@eecs.umich.edu{ 1303576Sgblack@eecs.umich.edu SimObject::State so_state = SimObject::getState(); 1313576Sgblack@eecs.umich.edu SERIALIZE_ENUM(so_state); 1323576Sgblack@eecs.umich.edu BaseSimpleCPU::serialize(os); 1333576Sgblack@eecs.umich.edu} 1343576Sgblack@eecs.umich.edu 1353576Sgblack@eecs.umich.eduvoid 1363576Sgblack@eecs.umich.eduTimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 1373576Sgblack@eecs.umich.edu{ 1383576Sgblack@eecs.umich.edu SimObject::State so_state; 1393573Sgblack@eecs.umich.edu UNSERIALIZE_ENUM(so_state); 1403573Sgblack@eecs.umich.edu BaseSimpleCPU::unserialize(cp, section); 1413573Sgblack@eecs.umich.edu} 1423573Sgblack@eecs.umich.edu 1434695Sgblack@eecs.umich.eduunsigned int 1442221SN/ATimingSimpleCPU::drain(Event *drain_event) 1452221SN/A{ 1463576Sgblack@eecs.umich.edu // TimingSimpleCPU is ready to drain if it's not waiting for 1473576Sgblack@eecs.umich.edu // an access to complete. 1483576Sgblack@eecs.umich.edu if (_status == Idle || _status == Running || _status == SwitchedOut) { 1493576Sgblack@eecs.umich.edu changeState(SimObject::Drained); 1503576Sgblack@eecs.umich.edu return 0; 1513576Sgblack@eecs.umich.edu } else { 1523576Sgblack@eecs.umich.edu changeState(SimObject::Draining); 1533576Sgblack@eecs.umich.edu drainEvent = drain_event; 1543576Sgblack@eecs.umich.edu return 1; 1553576Sgblack@eecs.umich.edu } 1563576Sgblack@eecs.umich.edu} 1573576Sgblack@eecs.umich.edu 1583573Sgblack@eecs.umich.eduvoid 1593573Sgblack@eecs.umich.eduTimingSimpleCPU::resume() 1602221SN/A{ 1612221SN/A DPRINTF(SimpleCPU, "Resume\n"); 1624695Sgblack@eecs.umich.edu if (_status != SwitchedOut && _status != Idle) { 1632221SN/A assert(system->getMemoryMode() == Enums::timing); 1642221SN/A 1653576Sgblack@eecs.umich.edu // Delete the old event if it existed. 1663576Sgblack@eecs.umich.edu if (fetchEvent) { 1673576Sgblack@eecs.umich.edu if (fetchEvent->scheduled()) 1683576Sgblack@eecs.umich.edu deschedule(fetchEvent); 1693576Sgblack@eecs.umich.edu 1703576Sgblack@eecs.umich.edu delete fetchEvent; 1713576Sgblack@eecs.umich.edu } 1723576Sgblack@eecs.umich.edu 1733576Sgblack@eecs.umich.edu fetchEvent = new FetchEvent(this, nextCycle()); 1743576Sgblack@eecs.umich.edu } 1753576Sgblack@eecs.umich.edu 1763576Sgblack@eecs.umich.edu changeState(SimObject::Running); 1773576Sgblack@eecs.umich.edu} 1783576Sgblack@eecs.umich.edu 1793576Sgblack@eecs.umich.eduvoid 1803576Sgblack@eecs.umich.eduTimingSimpleCPU::switchOut() 1813576Sgblack@eecs.umich.edu{ 1823576Sgblack@eecs.umich.edu assert(_status == Running || _status == Idle); 1833576Sgblack@eecs.umich.edu _status = SwitchedOut; 1843576Sgblack@eecs.umich.edu numCycles += tickToCycles(curTick - previousTick); 1853576Sgblack@eecs.umich.edu 1863576Sgblack@eecs.umich.edu // If we've been scheduled to resume but are then told to switch out, 1873576Sgblack@eecs.umich.edu // we'll need to cancel it. 1883576Sgblack@eecs.umich.edu if (fetchEvent && fetchEvent->scheduled()) 1893576Sgblack@eecs.umich.edu deschedule(fetchEvent); 1903576Sgblack@eecs.umich.edu} 1913576Sgblack@eecs.umich.edu 1923576Sgblack@eecs.umich.edu 1933576Sgblack@eecs.umich.eduvoid 1943576Sgblack@eecs.umich.eduTimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 1953576Sgblack@eecs.umich.edu{ 1963576Sgblack@eecs.umich.edu BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort); 1973576Sgblack@eecs.umich.edu 1983576Sgblack@eecs.umich.edu // if any of this CPU's ThreadContexts are active, mark the CPU as 1993576Sgblack@eecs.umich.edu // running and schedule its tick event. 2003576Sgblack@eecs.umich.edu for (int i = 0; i < threadContexts.size(); ++i) { 2013576Sgblack@eecs.umich.edu ThreadContext *tc = threadContexts[i]; 2023576Sgblack@eecs.umich.edu if (tc->status() == ThreadContext::Active && _status != Running) { 2034103Ssaidi@eecs.umich.edu _status = Running; 2044103Ssaidi@eecs.umich.edu break; 2053576Sgblack@eecs.umich.edu } 2063576Sgblack@eecs.umich.edu } 2073576Sgblack@eecs.umich.edu 2083576Sgblack@eecs.umich.edu if (_status != Running) { 2093576Sgblack@eecs.umich.edu _status = Idle; 2104997Sgblack@eecs.umich.edu } 2114997Sgblack@eecs.umich.edu assert(threadContexts.size() == 1); 2124997Sgblack@eecs.umich.edu cpuId = tc->readCpuId(); 2134997Sgblack@eecs.umich.edu previousTick = curTick; 2144997Sgblack@eecs.umich.edu} 2154997Sgblack@eecs.umich.edu 2164997Sgblack@eecs.umich.edu 2174997Sgblack@eecs.umich.eduvoid 2187678Sgblack@eecs.umich.eduTimingSimpleCPU::activateContext(int thread_num, int delay) 2197678Sgblack@eecs.umich.edu{ 2204997Sgblack@eecs.umich.edu DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay); 2214997Sgblack@eecs.umich.edu 2223576Sgblack@eecs.umich.edu assert(thread_num == 0); 2234997Sgblack@eecs.umich.edu assert(thread); 2244997Sgblack@eecs.umich.edu 2254997Sgblack@eecs.umich.edu assert(_status == Idle); 2264997Sgblack@eecs.umich.edu 2274997Sgblack@eecs.umich.edu notIdleFraction++; 2284997Sgblack@eecs.umich.edu _status = Running; 2294997Sgblack@eecs.umich.edu 2304997Sgblack@eecs.umich.edu // kick things off by initiating the fetch of the next instruction 2317678Sgblack@eecs.umich.edu fetchEvent = new FetchEvent(this); 2327678Sgblack@eecs.umich.edu schedule(fetchEvent, nextCycle(curTick + ticks(delay))); 2334997Sgblack@eecs.umich.edu} 2344997Sgblack@eecs.umich.edu 2353576Sgblack@eecs.umich.edu 2363576Sgblack@eecs.umich.eduvoid 2373576Sgblack@eecs.umich.eduTimingSimpleCPU::suspendContext(int thread_num) 2383576Sgblack@eecs.umich.edu{ 2393576Sgblack@eecs.umich.edu DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num); 2403576Sgblack@eecs.umich.edu 2413576Sgblack@eecs.umich.edu assert(thread_num == 0); 2423576Sgblack@eecs.umich.edu assert(thread); 2433576Sgblack@eecs.umich.edu 2443893Shsul@eecs.umich.edu assert(_status == Running); 2453576Sgblack@eecs.umich.edu 2463576Sgblack@eecs.umich.edu // just change status to Idle... if status != Running, 2473576Sgblack@eecs.umich.edu // completeInst() will not initiate fetch of next instruction. 2483576Sgblack@eecs.umich.edu 2493576Sgblack@eecs.umich.edu notIdleFraction--; 2503576Sgblack@eecs.umich.edu _status = Idle; 2513576Sgblack@eecs.umich.edu} 2527678Sgblack@eecs.umich.edu 2537678Sgblack@eecs.umich.edu 2543576Sgblack@eecs.umich.edutemplate <class T> 2553576Sgblack@eecs.umich.eduFault 2563576Sgblack@eecs.umich.eduTimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 2573576Sgblack@eecs.umich.edu{ 2583576Sgblack@eecs.umich.edu Request *req = 2593576Sgblack@eecs.umich.edu new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 2603576Sgblack@eecs.umich.edu cpuId, /* thread ID */ 0); 2613576Sgblack@eecs.umich.edu 2623576Sgblack@eecs.umich.edu if (traceData) { 2633576Sgblack@eecs.umich.edu traceData->setAddr(req->getVaddr()); 2643576Sgblack@eecs.umich.edu } 2653576Sgblack@eecs.umich.edu 2663576Sgblack@eecs.umich.edu // translate to physical address 2673576Sgblack@eecs.umich.edu Fault fault = thread->translateDataReadReq(req); 2683576Sgblack@eecs.umich.edu 2697678Sgblack@eecs.umich.edu // Now do the access. 2707678Sgblack@eecs.umich.edu if (fault == NoFault) { 2713576Sgblack@eecs.umich.edu PacketPtr pkt = 2723576Sgblack@eecs.umich.edu new Packet(req, 2733576Sgblack@eecs.umich.edu (req->isLocked() ? 2743576Sgblack@eecs.umich.edu MemCmd::LoadLockedReq : MemCmd::ReadReq), 2753576Sgblack@eecs.umich.edu Packet::Broadcast); 2763576Sgblack@eecs.umich.edu pkt->dataDynamic<T>(new T); 2773576Sgblack@eecs.umich.edu 2783576Sgblack@eecs.umich.edu if (req->isMmapedIpr()) { 2793576Sgblack@eecs.umich.edu Tick delay; 2803576Sgblack@eecs.umich.edu delay = TheISA::handleIprRead(thread->getTC(), pkt); 2813576Sgblack@eecs.umich.edu new IprEvent(pkt, this, nextCycle(curTick + delay)); 2823576Sgblack@eecs.umich.edu _status = DcacheWaitResponse; 2833576Sgblack@eecs.umich.edu dcache_pkt = NULL; 2844111Sgblack@eecs.umich.edu } else if (!dcachePort.sendTiming(pkt)) { 2854111Sgblack@eecs.umich.edu _status = DcacheRetry; 2867678Sgblack@eecs.umich.edu dcache_pkt = pkt; 2877678Sgblack@eecs.umich.edu } else { 2884111Sgblack@eecs.umich.edu _status = DcacheWaitResponse; 2893576Sgblack@eecs.umich.edu // memory system takes ownership of packet 2903576Sgblack@eecs.umich.edu dcache_pkt = NULL; 2912221SN/A } 2922221SN/A 2932223SN/A // This will need a new way to tell if it has a dcache attached. 2942221SN/A if (req->isUncacheable()) 2952221SN/A recordEvent("Uncached Read"); 2962800Ssaidi@eecs.umich.edu } else { 2972223SN/A delete req; 2982221SN/A } 2993890Ssaidi@eecs.umich.edu 300 if (traceData) { 301 traceData->setData(data); 302 } 303 return fault; 304} 305 306Fault 307TimingSimpleCPU::translateDataReadAddr(Addr vaddr, Addr &paddr, 308 int size, unsigned flags) 309{ 310 Request *req = 311 new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0); 312 313 if (traceData) { 314 traceData->setAddr(vaddr); 315 } 316 317 Fault fault = thread->translateDataWriteReq(req); 318 319 if (fault == NoFault) 320 paddr = req->getPaddr(); 321 322 delete req; 323 return fault; 324} 325 326#ifndef DOXYGEN_SHOULD_SKIP_THIS 327 328template 329Fault 330TimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags); 331 332template 333Fault 334TimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags); 335 336template 337Fault 338TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 339 340template 341Fault 342TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 343 344template 345Fault 346TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 347 348template 349Fault 350TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 351 352#endif //DOXYGEN_SHOULD_SKIP_THIS 353 354template<> 355Fault 356TimingSimpleCPU::read(Addr addr, double &data, unsigned flags) 357{ 358 return read(addr, *(uint64_t*)&data, flags); 359} 360 361template<> 362Fault 363TimingSimpleCPU::read(Addr addr, float &data, unsigned flags) 364{ 365 return read(addr, *(uint32_t*)&data, flags); 366} 367 368 369template<> 370Fault 371TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 372{ 373 return read(addr, (uint32_t&)data, flags); 374} 375 376 377template <class T> 378Fault 379TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 380{ 381 Request *req = 382 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 383 cpuId, /* thread ID */ 0); 384 385 if (traceData) { 386 traceData->setAddr(req->getVaddr()); 387 } 388 389 // translate to physical address 390 Fault fault = thread->translateDataWriteReq(req); 391 392 // Now do the access. 393 if (fault == NoFault) { 394 MemCmd cmd = MemCmd::WriteReq; // default 395 bool do_access = true; // flag to suppress cache access 396 397 if (req->isLocked()) { 398 cmd = MemCmd::StoreCondReq; 399 do_access = TheISA::handleLockedWrite(thread, req); 400 } else if (req->isSwap()) { 401 cmd = MemCmd::SwapReq; 402 if (req->isCondSwap()) { 403 assert(res); 404 req->setExtraData(*res); 405 } 406 } 407 408 // Note: need to allocate dcache_pkt even if do_access is 409 // false, as it's used unconditionally to call completeAcc(). 410 assert(dcache_pkt == NULL); 411 dcache_pkt = new Packet(req, cmd, Packet::Broadcast); 412 dcache_pkt->allocate(); 413 dcache_pkt->set(data); 414 415 if (do_access) { 416 if (req->isMmapedIpr()) { 417 Tick delay; 418 dcache_pkt->set(htog(data)); 419 delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); 420 new IprEvent(dcache_pkt, this, nextCycle(curTick + delay)); 421 _status = DcacheWaitResponse; 422 dcache_pkt = NULL; 423 } else if (!dcachePort.sendTiming(dcache_pkt)) { 424 _status = DcacheRetry; 425 } else { 426 _status = DcacheWaitResponse; 427 // memory system takes ownership of packet 428 dcache_pkt = NULL; 429 } 430 } 431 // This will need a new way to tell if it's hooked up to a cache or not. 432 if (req->isUncacheable()) 433 recordEvent("Uncached Write"); 434 } else { 435 delete req; 436 } 437 438 if (traceData) { 439 traceData->setData(data); 440 } 441 442 // If the write needs to have a fault on the access, consider calling 443 // changeStatus() and changing it to "bad addr write" or something. 444 return fault; 445} 446 447Fault 448TimingSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr, 449 int size, unsigned flags) 450{ 451 Request *req = 452 new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0); 453 454 if (traceData) { 455 traceData->setAddr(vaddr); 456 } 457 458 Fault fault = thread->translateDataWriteReq(req); 459 460 if (fault == NoFault) 461 paddr = req->getPaddr(); 462 463 delete req; 464 return fault; 465} 466 467 468#ifndef DOXYGEN_SHOULD_SKIP_THIS 469template 470Fault 471TimingSimpleCPU::write(Twin32_t data, Addr addr, 472 unsigned flags, uint64_t *res); 473 474template 475Fault 476TimingSimpleCPU::write(Twin64_t data, Addr addr, 477 unsigned flags, uint64_t *res); 478 479template 480Fault 481TimingSimpleCPU::write(uint64_t data, Addr addr, 482 unsigned flags, uint64_t *res); 483 484template 485Fault 486TimingSimpleCPU::write(uint32_t data, Addr addr, 487 unsigned flags, uint64_t *res); 488 489template 490Fault 491TimingSimpleCPU::write(uint16_t data, Addr addr, 492 unsigned flags, uint64_t *res); 493 494template 495Fault 496TimingSimpleCPU::write(uint8_t data, Addr addr, 497 unsigned flags, uint64_t *res); 498 499#endif //DOXYGEN_SHOULD_SKIP_THIS 500 501template<> 502Fault 503TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 504{ 505 return write(*(uint64_t*)&data, addr, flags, res); 506} 507 508template<> 509Fault 510TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 511{ 512 return write(*(uint32_t*)&data, addr, flags, res); 513} 514 515 516template<> 517Fault 518TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 519{ 520 return write((uint32_t)data, addr, flags, res); 521} 522 523 524void 525TimingSimpleCPU::fetch() 526{ 527 DPRINTF(SimpleCPU, "Fetch\n"); 528 529 if (!curStaticInst || !curStaticInst->isDelayedCommit()) 530 checkForInterrupts(); 531 532 checkPcEventQueue(); 533 534 bool fromRom = isRomMicroPC(thread->readMicroPC()); 535 536 if (!fromRom) { 537 Request *ifetch_req = new Request(); 538 ifetch_req->setThreadContext(cpuId, /* thread ID */ 0); 539 Fault fault = setupFetchRequest(ifetch_req); 540 541 ifetch_pkt = new Packet(ifetch_req, MemCmd::ReadReq, Packet::Broadcast); 542 ifetch_pkt->dataStatic(&inst); 543 544 if (fault == NoFault) { 545 if (!icachePort.sendTiming(ifetch_pkt)) { 546 // Need to wait for retry 547 _status = IcacheRetry; 548 } else { 549 // Need to wait for cache to respond 550 _status = IcacheWaitResponse; 551 // ownership of packet transferred to memory system 552 ifetch_pkt = NULL; 553 } 554 } else { 555 delete ifetch_req; 556 delete ifetch_pkt; 557 // fetch fault: advance directly to next instruction (fault handler) 558 advanceInst(fault); 559 } 560 } else { 561 _status = IcacheWaitResponse; 562 completeIfetch(NULL); 563 } 564 565 numCycles += tickToCycles(curTick - previousTick); 566 previousTick = curTick; 567} 568 569 570void 571TimingSimpleCPU::advanceInst(Fault fault) 572{ 573 advancePC(fault); 574 575 if (_status == Running) { 576 // kick off fetch of next instruction... callback from icache 577 // response will cause that instruction to be executed, 578 // keeping the CPU running. 579 fetch(); 580 } 581} 582 583 584void 585TimingSimpleCPU::completeIfetch(PacketPtr pkt) 586{ 587 DPRINTF(SimpleCPU, "Complete ICache Fetch\n"); 588 589 // received a response from the icache: execute the received 590 // instruction 591 592 assert(!pkt || !pkt->isError()); 593 assert(_status == IcacheWaitResponse); 594 595 _status = Running; 596 597 numCycles += tickToCycles(curTick - previousTick); 598 previousTick = curTick; 599 600 if (getState() == SimObject::Draining) { 601 if (pkt) { 602 delete pkt->req; 603 delete pkt; 604 } 605 606 completeDrain(); 607 return; 608 } 609 610 preExecute(); 611 if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { 612 // load or store: just send to dcache 613 Fault fault = curStaticInst->initiateAcc(this, traceData); 614 if (_status != Running) { 615 // instruction will complete in dcache response callback 616 assert(_status == DcacheWaitResponse || _status == DcacheRetry); 617 assert(fault == NoFault); 618 } else { 619 if (fault == NoFault) { 620 // Note that ARM can have NULL packets if the instruction gets 621 // squashed due to predication 622 // early fail on store conditional: complete now 623 assert(dcache_pkt != NULL || THE_ISA == ARM_ISA); 624 625 fault = curStaticInst->completeAcc(dcache_pkt, this, 626 traceData); 627 if (dcache_pkt != NULL) 628 { 629 delete dcache_pkt->req; 630 delete dcache_pkt; 631 dcache_pkt = NULL; 632 } 633 634 // keep an instruction count 635 if (fault == NoFault) 636 countInst(); 637 } else if (traceData) { 638 // If there was a fault, we shouldn't trace this instruction. 639 delete traceData; 640 traceData = NULL; 641 } 642 643 postExecute(); 644 // @todo remove me after debugging with legion done 645 if (curStaticInst && (!curStaticInst->isMicroop() || 646 curStaticInst->isFirstMicroop())) 647 instCnt++; 648 advanceInst(fault); 649 } 650 } else { 651 // non-memory instruction: execute completely now 652 Fault fault = curStaticInst->execute(this, traceData); 653 654 // keep an instruction count 655 if (fault == NoFault) 656 countInst(); 657 else if (traceData) { 658 // If there was a fault, we shouldn't trace this instruction. 659 delete traceData; 660 traceData = NULL; 661 } 662 663 postExecute(); 664 // @todo remove me after debugging with legion done 665 if (curStaticInst && (!curStaticInst->isMicroop() || 666 curStaticInst->isFirstMicroop())) 667 instCnt++; 668 advanceInst(fault); 669 } 670 671 if (pkt) { 672 delete pkt->req; 673 delete pkt; 674 } 675} 676 677void 678TimingSimpleCPU::IcachePort::ITickEvent::process() 679{ 680 cpu->completeIfetch(pkt); 681} 682 683bool 684TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt) 685{ 686 if (pkt->isResponse() && !pkt->wasNacked()) { 687 // delay processing of returned data until next CPU clock edge 688 Tick next_tick = cpu->nextCycle(curTick); 689 690 if (next_tick == curTick) 691 cpu->completeIfetch(pkt); 692 else 693 tickEvent.schedule(pkt, next_tick); 694 695 return true; 696 } 697 else if (pkt->wasNacked()) { 698 assert(cpu->_status == IcacheWaitResponse); 699 pkt->reinitNacked(); 700 if (!sendTiming(pkt)) { 701 cpu->_status = IcacheRetry; 702 cpu->ifetch_pkt = pkt; 703 } 704 } 705 //Snooping a Coherence Request, do nothing 706 return true; 707} 708 709void 710TimingSimpleCPU::IcachePort::recvRetry() 711{ 712 // we shouldn't get a retry unless we have a packet that we're 713 // waiting to transmit 714 assert(cpu->ifetch_pkt != NULL); 715 assert(cpu->_status == IcacheRetry); 716 PacketPtr tmp = cpu->ifetch_pkt; 717 if (sendTiming(tmp)) { 718 cpu->_status = IcacheWaitResponse; 719 cpu->ifetch_pkt = NULL; 720 } 721} 722 723void 724TimingSimpleCPU::completeDataAccess(PacketPtr pkt) 725{ 726 // received a response from the dcache: complete the load or store 727 // instruction 728 assert(!pkt->isError()); 729 assert(_status == DcacheWaitResponse); 730 _status = Running; 731 732 numCycles += tickToCycles(curTick - previousTick); 733 previousTick = curTick; 734 735 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 736 737 // keep an instruction count 738 if (fault == NoFault) 739 countInst(); 740 else if (traceData) { 741 // If there was a fault, we shouldn't trace this instruction. 742 delete traceData; 743 traceData = NULL; 744 } 745 746 // the locked flag may be cleared on the response packet, so check 747 // pkt->req and not pkt to see if it was a load-locked 748 if (pkt->isRead() && pkt->req->isLocked()) { 749 TheISA::handleLockedRead(thread, pkt->req); 750 } 751 752 delete pkt->req; 753 delete pkt; 754 755 postExecute(); 756 757 if (getState() == SimObject::Draining) { 758 advancePC(fault); 759 completeDrain(); 760 761 return; 762 } 763 764 advanceInst(fault); 765} 766 767 768void 769TimingSimpleCPU::completeDrain() 770{ 771 DPRINTF(Config, "Done draining\n"); 772 changeState(SimObject::Drained); 773 drainEvent->process(); 774} 775 776void 777TimingSimpleCPU::DcachePort::setPeer(Port *port) 778{ 779 Port::setPeer(port); 780 781#if FULL_SYSTEM 782 // Update the ThreadContext's memory ports (Functional/Virtual 783 // Ports) 784 cpu->tcBase()->connectMemPorts(cpu->tcBase()); 785#endif 786} 787 788bool 789TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt) 790{ 791 if (pkt->isResponse() && !pkt->wasNacked()) { 792 // delay processing of returned data until next CPU clock edge 793 Tick next_tick = cpu->nextCycle(curTick); 794 795 if (next_tick == curTick) 796 cpu->completeDataAccess(pkt); 797 else 798 tickEvent.schedule(pkt, next_tick); 799 800 return true; 801 } 802 else if (pkt->wasNacked()) { 803 assert(cpu->_status == DcacheWaitResponse); 804 pkt->reinitNacked(); 805 if (!sendTiming(pkt)) { 806 cpu->_status = DcacheRetry; 807 cpu->dcache_pkt = pkt; 808 } 809 } 810 //Snooping a Coherence Request, do nothing 811 return true; 812} 813 814void 815TimingSimpleCPU::DcachePort::DTickEvent::process() 816{ 817 cpu->completeDataAccess(pkt); 818} 819 820void 821TimingSimpleCPU::DcachePort::recvRetry() 822{ 823 // we shouldn't get a retry unless we have a packet that we're 824 // waiting to transmit 825 assert(cpu->dcache_pkt != NULL); 826 assert(cpu->_status == DcacheRetry); 827 PacketPtr tmp = cpu->dcache_pkt; 828 if (sendTiming(tmp)) { 829 cpu->_status = DcacheWaitResponse; 830 // memory system takes ownership of packet 831 cpu->dcache_pkt = NULL; 832 } 833} 834 835TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, 836 Tick t) 837 : pkt(_pkt), cpu(_cpu) 838{ 839 cpu->schedule(this, t); 840} 841 842void 843TimingSimpleCPU::IprEvent::process() 844{ 845 cpu->completeDataAccess(pkt); 846} 847 848const char * 849TimingSimpleCPU::IprEvent::description() const 850{ 851 return "Timing Simple CPU Delay IPR event"; 852} 853 854 855void 856TimingSimpleCPU::printAddr(Addr a) 857{ 858 dcachePort.printAddr(a); 859} 860 861 862//////////////////////////////////////////////////////////////////////// 863// 864// TimingSimpleCPU Simulation Object 865// 866TimingSimpleCPU * 867TimingSimpleCPUParams::create() 868{ 869 numThreads = 1; 870#if !FULL_SYSTEM 871 if (workload.size() != 1) 872 panic("only one workload allowed"); 873#endif 874 return new TimingSimpleCPU(this); 875} 876