timing.cc revision 4762
110623Smitch.hayenga@arm.com/* 211439SRekai.GonzalezAlberquilla@arm.com * Copyright (c) 2002-2005 The Regents of The University of Michigan 310623Smitch.hayenga@arm.com * All rights reserved. 410623Smitch.hayenga@arm.com * 510623Smitch.hayenga@arm.com * Redistribution and use in source and binary forms, with or without 610623Smitch.hayenga@arm.com * modification, are permitted provided that the following conditions are 710623Smitch.hayenga@arm.com * met: redistributions of source code must retain the above copyright 810623Smitch.hayenga@arm.com * notice, this list of conditions and the following disclaimer; 910623Smitch.hayenga@arm.com * redistributions in binary form must reproduce the above copyright 1010623Smitch.hayenga@arm.com * notice, this list of conditions and the following disclaimer in the 1110623Smitch.hayenga@arm.com * documentation and/or other materials provided with the distribution; 1210623Smitch.hayenga@arm.com * neither the name of the copyright holders nor the names of its 1310623Smitch.hayenga@arm.com * contributors may be used to endorse or promote products derived from 1410623Smitch.hayenga@arm.com * this software without specific prior written permission. 1510623Smitch.hayenga@arm.com * 1610623Smitch.hayenga@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1710623Smitch.hayenga@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1810623Smitch.hayenga@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1910623Smitch.hayenga@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2010623Smitch.hayenga@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2110623Smitch.hayenga@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2210623Smitch.hayenga@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2310623Smitch.hayenga@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2410623Smitch.hayenga@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2510623Smitch.hayenga@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2610623Smitch.hayenga@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2710623Smitch.hayenga@arm.com * 2810623Smitch.hayenga@arm.com * Authors: Steve Reinhardt 2910623Smitch.hayenga@arm.com */ 3010623Smitch.hayenga@arm.com 3110623Smitch.hayenga@arm.com#include "arch/locked_mem.hh" 3210623Smitch.hayenga@arm.com#include "arch/utility.hh" 3310623Smitch.hayenga@arm.com#include "base/bigint.hh" 3410623Smitch.hayenga@arm.com#include "cpu/exetrace.hh" 3510623Smitch.hayenga@arm.com#include "cpu/simple/timing.hh" 3610623Smitch.hayenga@arm.com#include "mem/packet.hh" 3710623Smitch.hayenga@arm.com#include "mem/packet_access.hh" 3810623Smitch.hayenga@arm.com#include "params/TimingSimpleCPU.hh" 3910623Smitch.hayenga@arm.com#include "sim/system.hh" 4011793Sbrandon.potter@amd.com 4111793Sbrandon.potter@amd.comusing namespace std; 4212727Snikos.nikoleris@arm.comusing namespace TheISA; 4312727Snikos.nikoleris@arm.com 4412727Snikos.nikoleris@arm.comPort * 4512727Snikos.nikoleris@arm.comTimingSimpleCPU::getPort(const std::string &if_name, int idx) 4610623Smitch.hayenga@arm.com{ 4712727Snikos.nikoleris@arm.com if (if_name == "dcache_port") 4812727Snikos.nikoleris@arm.com return &dcachePort; 4910623Smitch.hayenga@arm.com else if (if_name == "icache_port") 5010623Smitch.hayenga@arm.com return &icachePort; 5110623Smitch.hayenga@arm.com else 5210623Smitch.hayenga@arm.com panic("No Such Port\n"); 5310623Smitch.hayenga@arm.com} 5410623Smitch.hayenga@arm.com 5510623Smitch.hayenga@arm.comvoid 5610623Smitch.hayenga@arm.comTimingSimpleCPU::init() 5710623Smitch.hayenga@arm.com{ 5810623Smitch.hayenga@arm.com BaseCPU::init(); 5910623Smitch.hayenga@arm.com#if FULL_SYSTEM 6010623Smitch.hayenga@arm.com for (int i = 0; i < threadContexts.size(); ++i) { 6110623Smitch.hayenga@arm.com ThreadContext *tc = threadContexts[i]; 6210623Smitch.hayenga@arm.com 6310623Smitch.hayenga@arm.com // initialize CPU, including PC 6410623Smitch.hayenga@arm.com TheISA::initCPU(tc, tc->readCpuId()); 6510623Smitch.hayenga@arm.com } 6613416Sjavier.bueno@metempsy.com#endif 6713551Sjavier.bueno@metempsy.com} 6810623Smitch.hayenga@arm.com 6913551Sjavier.bueno@metempsy.comTick 7013551Sjavier.bueno@metempsy.comTimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) 7110623Smitch.hayenga@arm.com{ 7213551Sjavier.bueno@metempsy.com panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 7313551Sjavier.bueno@metempsy.com return curTick; 7413551Sjavier.bueno@metempsy.com} 7513551Sjavier.bueno@metempsy.com 7613551Sjavier.bueno@metempsy.comvoid 7713551Sjavier.bueno@metempsy.comTimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) 7813551Sjavier.bueno@metempsy.com{ 7913551Sjavier.bueno@metempsy.com //No internal storage to update, jusst return 8013551Sjavier.bueno@metempsy.com return; 8113551Sjavier.bueno@metempsy.com} 8210623Smitch.hayenga@arm.com 8310623Smitch.hayenga@arm.comvoid 8413551Sjavier.bueno@metempsy.comTimingSimpleCPU::CpuPort::recvStatusChange(Status status) 8510623Smitch.hayenga@arm.com{ 8613551Sjavier.bueno@metempsy.com if (status == RangeChange) { 8713551Sjavier.bueno@metempsy.com if (!snoopRangeSent) { 8813551Sjavier.bueno@metempsy.com snoopRangeSent = true; 8910623Smitch.hayenga@arm.com sendStatusChange(Port::RangeChange); 9013551Sjavier.bueno@metempsy.com } 9113551Sjavier.bueno@metempsy.com return; 9210623Smitch.hayenga@arm.com } 9313551Sjavier.bueno@metempsy.com 9413551Sjavier.bueno@metempsy.com panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); 9510623Smitch.hayenga@arm.com} 9613551Sjavier.bueno@metempsy.com 9711439SRekai.GonzalezAlberquilla@arm.com 9813551Sjavier.bueno@metempsy.comvoid 9913551Sjavier.bueno@metempsy.comTimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) 10013551Sjavier.bueno@metempsy.com{ 10113551Sjavier.bueno@metempsy.com pkt = _pkt; 10213551Sjavier.bueno@metempsy.com Event::schedule(t); 10313551Sjavier.bueno@metempsy.com} 10410623Smitch.hayenga@arm.com 10510623Smitch.hayenga@arm.comTimingSimpleCPU::TimingSimpleCPU(Params *p) 10610623Smitch.hayenga@arm.com : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock), 10710623Smitch.hayenga@arm.com cpu_id(p->cpu_id) 10810623Smitch.hayenga@arm.com{ 10910623Smitch.hayenga@arm.com _status = Idle; 11010623Smitch.hayenga@arm.com 11110623Smitch.hayenga@arm.com icachePort.snoopRangeSent = false; 11210623Smitch.hayenga@arm.com dcachePort.snoopRangeSent = false; 11310623Smitch.hayenga@arm.com 11411484Snikos.nikoleris@arm.com ifetch_pkt = dcache_pkt = NULL; 11510623Smitch.hayenga@arm.com drainEvent = NULL; 11610623Smitch.hayenga@arm.com fetchEvent = NULL; 11713551Sjavier.bueno@metempsy.com previousTick = 0; 11810623Smitch.hayenga@arm.com changeState(SimObject::Running); 11910623Smitch.hayenga@arm.com} 12010623Smitch.hayenga@arm.com 12111484Snikos.nikoleris@arm.com 12210623Smitch.hayenga@arm.comTimingSimpleCPU::~TimingSimpleCPU() 12310623Smitch.hayenga@arm.com{ 12410623Smitch.hayenga@arm.com} 12510623Smitch.hayenga@arm.com 12613422Sodanrc@yahoo.com.brvoid 12713551Sjavier.bueno@metempsy.comTimingSimpleCPU::serialize(ostream &os) 12810623Smitch.hayenga@arm.com{ 12911439SRekai.GonzalezAlberquilla@arm.com SimObject::State so_state = SimObject::getState(); 13013551Sjavier.bueno@metempsy.com SERIALIZE_ENUM(so_state); 13110623Smitch.hayenga@arm.com BaseSimpleCPU::serialize(os); 13210623Smitch.hayenga@arm.com} 13311439SRekai.GonzalezAlberquilla@arm.com 13411439SRekai.GonzalezAlberquilla@arm.comvoid 13511439SRekai.GonzalezAlberquilla@arm.comTimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 13611439SRekai.GonzalezAlberquilla@arm.com{ 13713551Sjavier.bueno@metempsy.com SimObject::State so_state; 13811439SRekai.GonzalezAlberquilla@arm.com UNSERIALIZE_ENUM(so_state); 13911439SRekai.GonzalezAlberquilla@arm.com BaseSimpleCPU::unserialize(cp, section); 14013551Sjavier.bueno@metempsy.com} 14111439SRekai.GonzalezAlberquilla@arm.com 14211439SRekai.GonzalezAlberquilla@arm.comunsigned int 14311439SRekai.GonzalezAlberquilla@arm.comTimingSimpleCPU::drain(Event *drain_event) 14410623Smitch.hayenga@arm.com{ 14510623Smitch.hayenga@arm.com // TimingSimpleCPU is ready to drain if it's not waiting for 14610623Smitch.hayenga@arm.com // an access to complete. 14710623Smitch.hayenga@arm.com if (status() == Idle || status() == Running || status() == SwitchedOut) { 14810623Smitch.hayenga@arm.com changeState(SimObject::Drained); 14910623Smitch.hayenga@arm.com return 0; 15010623Smitch.hayenga@arm.com } else { 15110623Smitch.hayenga@arm.com changeState(SimObject::Draining); 15210623Smitch.hayenga@arm.com drainEvent = drain_event; 15310623Smitch.hayenga@arm.com return 1; 15410623Smitch.hayenga@arm.com } 15510623Smitch.hayenga@arm.com} 15610623Smitch.hayenga@arm.com 15710623Smitch.hayenga@arm.comvoid 15810623Smitch.hayenga@arm.comTimingSimpleCPU::resume() 15910623Smitch.hayenga@arm.com{ 16010623Smitch.hayenga@arm.com if (_status != SwitchedOut && _status != Idle) { 16110623Smitch.hayenga@arm.com assert(system->getMemoryMode() == Enums::timing); 16210623Smitch.hayenga@arm.com 16310623Smitch.hayenga@arm.com // Delete the old event if it existed. 16410623Smitch.hayenga@arm.com if (fetchEvent) { 16510623Smitch.hayenga@arm.com if (fetchEvent->scheduled()) 16610623Smitch.hayenga@arm.com fetchEvent->deschedule(); 16710623Smitch.hayenga@arm.com 16810623Smitch.hayenga@arm.com delete fetchEvent; 16910623Smitch.hayenga@arm.com } 17010623Smitch.hayenga@arm.com 17111439SRekai.GonzalezAlberquilla@arm.com fetchEvent = new FetchEvent(this, nextCycle()); 17213551Sjavier.bueno@metempsy.com } 17313551Sjavier.bueno@metempsy.com 17413551Sjavier.bueno@metempsy.com changeState(SimObject::Running); 17511439SRekai.GonzalezAlberquilla@arm.com previousTick = curTick; 17611439SRekai.GonzalezAlberquilla@arm.com} 17713551Sjavier.bueno@metempsy.com 17811439SRekai.GonzalezAlberquilla@arm.comvoid 17911439SRekai.GonzalezAlberquilla@arm.comTimingSimpleCPU::switchOut() 18011439SRekai.GonzalezAlberquilla@arm.com{ 18113551Sjavier.bueno@metempsy.com assert(status() == Running || status() == Idle); 18211439SRekai.GonzalezAlberquilla@arm.com _status = SwitchedOut; 18313551Sjavier.bueno@metempsy.com numCycles += curTick - previousTick; 18411439SRekai.GonzalezAlberquilla@arm.com 18511439SRekai.GonzalezAlberquilla@arm.com // If we've been scheduled to resume but are then told to switch out, 18611439SRekai.GonzalezAlberquilla@arm.com // we'll need to cancel it. 18711439SRekai.GonzalezAlberquilla@arm.com if (fetchEvent && fetchEvent->scheduled()) 18811439SRekai.GonzalezAlberquilla@arm.com fetchEvent->deschedule(); 18911439SRekai.GonzalezAlberquilla@arm.com} 19011439SRekai.GonzalezAlberquilla@arm.com 19111439SRekai.GonzalezAlberquilla@arm.com 19211439SRekai.GonzalezAlberquilla@arm.comvoid 19311439SRekai.GonzalezAlberquilla@arm.comTimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 19411439SRekai.GonzalezAlberquilla@arm.com{ 19511439SRekai.GonzalezAlberquilla@arm.com BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort); 19611439SRekai.GonzalezAlberquilla@arm.com 19711439SRekai.GonzalezAlberquilla@arm.com // if any of this CPU's ThreadContexts are active, mark the CPU as 19811439SRekai.GonzalezAlberquilla@arm.com // running and schedule its tick event. 19911439SRekai.GonzalezAlberquilla@arm.com for (int i = 0; i < threadContexts.size(); ++i) { 20013551Sjavier.bueno@metempsy.com ThreadContext *tc = threadContexts[i]; 20111439SRekai.GonzalezAlberquilla@arm.com if (tc->status() == ThreadContext::Active && _status != Running) { 20211439SRekai.GonzalezAlberquilla@arm.com _status = Running; 20311439SRekai.GonzalezAlberquilla@arm.com break; 20413551Sjavier.bueno@metempsy.com } 20513551Sjavier.bueno@metempsy.com } 20613551Sjavier.bueno@metempsy.com 20713551Sjavier.bueno@metempsy.com if (_status != Running) { 20813551Sjavier.bueno@metempsy.com _status = Idle; 20913551Sjavier.bueno@metempsy.com } 21013551Sjavier.bueno@metempsy.com} 21113551Sjavier.bueno@metempsy.com 21213551Sjavier.bueno@metempsy.com 21313551Sjavier.bueno@metempsy.comvoid 21413551Sjavier.bueno@metempsy.comTimingSimpleCPU::activateContext(int thread_num, int delay) 21513551Sjavier.bueno@metempsy.com{ 21613551Sjavier.bueno@metempsy.com assert(thread_num == 0); 21713551Sjavier.bueno@metempsy.com assert(thread); 21813551Sjavier.bueno@metempsy.com 21913551Sjavier.bueno@metempsy.com assert(_status == Idle); 22013551Sjavier.bueno@metempsy.com 22111439SRekai.GonzalezAlberquilla@arm.com notIdleFraction++; 22211439SRekai.GonzalezAlberquilla@arm.com _status = Running; 22313551Sjavier.bueno@metempsy.com 22413551Sjavier.bueno@metempsy.com // kick things off by initiating the fetch of the next instruction 22511439SRekai.GonzalezAlberquilla@arm.com fetchEvent = new FetchEvent(this, nextCycle(curTick + cycles(delay))); 22611439SRekai.GonzalezAlberquilla@arm.com} 22711439SRekai.GonzalezAlberquilla@arm.com 22812748Sgiacomo.travaglini@arm.com 22913551Sjavier.bueno@metempsy.comvoid 23011439SRekai.GonzalezAlberquilla@arm.comTimingSimpleCPU::suspendContext(int thread_num) 23113551Sjavier.bueno@metempsy.com{ 23211439SRekai.GonzalezAlberquilla@arm.com assert(thread_num == 0); 23311439SRekai.GonzalezAlberquilla@arm.com assert(thread); 23411439SRekai.GonzalezAlberquilla@arm.com 23511439SRekai.GonzalezAlberquilla@arm.com assert(_status == Running); 23611439SRekai.GonzalezAlberquilla@arm.com 23713551Sjavier.bueno@metempsy.com // just change status to Idle... if status != Running, 23813551Sjavier.bueno@metempsy.com // completeInst() will not initiate fetch of next instruction. 23913551Sjavier.bueno@metempsy.com 24013551Sjavier.bueno@metempsy.com notIdleFraction--; 24111439SRekai.GonzalezAlberquilla@arm.com _status = Idle; 24211439SRekai.GonzalezAlberquilla@arm.com} 24311439SRekai.GonzalezAlberquilla@arm.com 24411439SRekai.GonzalezAlberquilla@arm.com 24511439SRekai.GonzalezAlberquilla@arm.comtemplate <class T> 24611439SRekai.GonzalezAlberquilla@arm.comFault 24711439SRekai.GonzalezAlberquilla@arm.comTimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 24811439SRekai.GonzalezAlberquilla@arm.com{ 24911439SRekai.GonzalezAlberquilla@arm.com Request *req = 25011439SRekai.GonzalezAlberquilla@arm.com new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(), 25111439SRekai.GonzalezAlberquilla@arm.com cpu_id, /* thread ID */ 0); 25211439SRekai.GonzalezAlberquilla@arm.com 25311439SRekai.GonzalezAlberquilla@arm.com if (traceData) { 25411439SRekai.GonzalezAlberquilla@arm.com traceData->setAddr(req->getVaddr()); 25511439SRekai.GonzalezAlberquilla@arm.com } 25611439SRekai.GonzalezAlberquilla@arm.com 25713551Sjavier.bueno@metempsy.com // translate to physical address 25811439SRekai.GonzalezAlberquilla@arm.com Fault fault = thread->translateDataReadReq(req); 25911439SRekai.GonzalezAlberquilla@arm.com 26011439SRekai.GonzalezAlberquilla@arm.com // Now do the access. 26111439SRekai.GonzalezAlberquilla@arm.com if (fault == NoFault) { 26211439SRekai.GonzalezAlberquilla@arm.com PacketPtr pkt = 26313551Sjavier.bueno@metempsy.com new Packet(req, MemCmd::ReadReq, Packet::Broadcast); 26411439SRekai.GonzalezAlberquilla@arm.com pkt->dataDynamic<T>(new T); 26511439SRekai.GonzalezAlberquilla@arm.com 26611439SRekai.GonzalezAlberquilla@arm.com if (!dcachePort.sendTiming(pkt)) { 26711439SRekai.GonzalezAlberquilla@arm.com _status = DcacheRetry; 26811439SRekai.GonzalezAlberquilla@arm.com dcache_pkt = pkt; 26911439SRekai.GonzalezAlberquilla@arm.com } else { 27011439SRekai.GonzalezAlberquilla@arm.com _status = DcacheWaitResponse; 27113551Sjavier.bueno@metempsy.com // memory system takes ownership of packet 27211439SRekai.GonzalezAlberquilla@arm.com dcache_pkt = NULL; 27311439SRekai.GonzalezAlberquilla@arm.com } 27413551Sjavier.bueno@metempsy.com 27511439SRekai.GonzalezAlberquilla@arm.com // This will need a new way to tell if it has a dcache attached. 27611439SRekai.GonzalezAlberquilla@arm.com if (req->isUncacheable()) 27711439SRekai.GonzalezAlberquilla@arm.com recordEvent("Uncached Read"); 27811439SRekai.GonzalezAlberquilla@arm.com } else { 27913428Sjavier.bueno@metempsy.com delete req; 28011439SRekai.GonzalezAlberquilla@arm.com } 28113428Sjavier.bueno@metempsy.com 28211439SRekai.GonzalezAlberquilla@arm.com return fault; 28311439SRekai.GonzalezAlberquilla@arm.com} 28411439SRekai.GonzalezAlberquilla@arm.com 28511439SRekai.GonzalezAlberquilla@arm.com#ifndef DOXYGEN_SHOULD_SKIP_THIS 28611439SRekai.GonzalezAlberquilla@arm.com 28711439SRekai.GonzalezAlberquilla@arm.comtemplate 28811439SRekai.GonzalezAlberquilla@arm.comFault 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 next_tick = cpu->nextCycle(curTick); 564 565 if (next_tick == curTick) 566 cpu->completeIfetch(pkt); 567 else 568 tickEvent.schedule(pkt, next_tick); 569 570 return true; 571 } 572 else if (pkt->result == Packet::Nacked) { 573 assert(cpu->_status == IcacheWaitResponse); 574 pkt->reinitNacked(); 575 if (!sendTiming(pkt)) { 576 cpu->_status = IcacheRetry; 577 cpu->ifetch_pkt = pkt; 578 } 579 } 580 //Snooping a Coherence Request, do nothing 581 return true; 582} 583 584void 585TimingSimpleCPU::IcachePort::recvRetry() 586{ 587 // we shouldn't get a retry unless we have a packet that we're 588 // waiting to transmit 589 assert(cpu->ifetch_pkt != NULL); 590 assert(cpu->_status == IcacheRetry); 591 PacketPtr tmp = cpu->ifetch_pkt; 592 if (sendTiming(tmp)) { 593 cpu->_status = IcacheWaitResponse; 594 cpu->ifetch_pkt = NULL; 595 } 596} 597 598void 599TimingSimpleCPU::completeDataAccess(PacketPtr pkt) 600{ 601 // received a response from the dcache: complete the load or store 602 // instruction 603 assert(pkt->result == Packet::Success); 604 assert(_status == DcacheWaitResponse); 605 _status = Running; 606 607 numCycles += curTick - previousTick; 608 previousTick = curTick; 609 610 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 611 612 if (pkt->isRead() && pkt->req->isLocked()) { 613 TheISA::handleLockedRead(thread, pkt->req); 614 } 615 616 delete pkt->req; 617 delete pkt; 618 619 postExecute(); 620 621 if (getState() == SimObject::Draining) { 622 advancePC(fault); 623 completeDrain(); 624 625 return; 626 } 627 628 advanceInst(fault); 629} 630 631 632void 633TimingSimpleCPU::completeDrain() 634{ 635 DPRINTF(Config, "Done draining\n"); 636 changeState(SimObject::Drained); 637 drainEvent->process(); 638} 639 640void 641TimingSimpleCPU::DcachePort::setPeer(Port *port) 642{ 643 Port::setPeer(port); 644 645#if FULL_SYSTEM 646 // Update the ThreadContext's memory ports (Functional/Virtual 647 // Ports) 648 cpu->tcBase()->connectMemPorts(); 649#endif 650} 651 652bool 653TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt) 654{ 655 if (pkt->isResponse()) { 656 // delay processing of returned data until next CPU clock edge 657 Tick next_tick = cpu->nextCycle(curTick); 658 659 if (next_tick == curTick) 660 cpu->completeDataAccess(pkt); 661 else 662 tickEvent.schedule(pkt, next_tick); 663 664 return true; 665 } 666 else if (pkt->result == Packet::Nacked) { 667 assert(cpu->_status == DcacheWaitResponse); 668 pkt->reinitNacked(); 669 if (!sendTiming(pkt)) { 670 cpu->_status = DcacheRetry; 671 cpu->dcache_pkt = pkt; 672 } 673 } 674 //Snooping a Coherence Request, do nothing 675 return true; 676} 677 678void 679TimingSimpleCPU::DcachePort::DTickEvent::process() 680{ 681 cpu->completeDataAccess(pkt); 682} 683 684void 685TimingSimpleCPU::DcachePort::recvRetry() 686{ 687 // we shouldn't get a retry unless we have a packet that we're 688 // waiting to transmit 689 assert(cpu->dcache_pkt != NULL); 690 assert(cpu->_status == DcacheRetry); 691 PacketPtr tmp = cpu->dcache_pkt; 692 if (sendTiming(tmp)) { 693 cpu->_status = DcacheWaitResponse; 694 // memory system takes ownership of packet 695 cpu->dcache_pkt = NULL; 696 } 697} 698 699 700//////////////////////////////////////////////////////////////////////// 701// 702// TimingSimpleCPU Simulation Object 703// 704TimingSimpleCPU * 705TimingSimpleCPUParams::create() 706{ 707 TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params(); 708 params->name = name; 709 params->numberOfThreads = 1; 710 params->max_insts_any_thread = max_insts_any_thread; 711 params->max_insts_all_threads = max_insts_all_threads; 712 params->max_loads_any_thread = max_loads_any_thread; 713 params->max_loads_all_threads = max_loads_all_threads; 714 params->progress_interval = progress_interval; 715 params->deferRegistration = defer_registration; 716 params->clock = clock; 717 params->phase = phase; 718 params->functionTrace = function_trace; 719 params->functionTraceStart = function_trace_start; 720 params->system = system; 721 params->cpu_id = cpu_id; 722 723#if FULL_SYSTEM 724 params->itb = itb; 725 params->dtb = dtb; 726 params->profile = profile; 727 params->do_quiesce = do_quiesce; 728 params->do_checkpoint_insts = do_checkpoint_insts; 729 params->do_statistics_insts = do_statistics_insts; 730#else 731 if (workload.size() != 1) 732 panic("only one workload allowed"); 733 params->process = workload[0]; 734#endif 735 736 TimingSimpleCPU *cpu = new TimingSimpleCPU(params); 737 return cpu; 738} 739