timing.cc revision 7911:267e1e16e51b
12131SN/A/* 25268Sksewell@umich.edu * Copyright (c) 2010 ARM Limited 35254Sksewell@umich.edu * All rights reserved 45254Sksewell@umich.edu * 52131SN/A * The license below extends only to copyright in the software and shall 65254Sksewell@umich.edu * not be construed as granting a license to any other intellectual 75254Sksewell@umich.edu * property including but not limited to intellectual property relating 85254Sksewell@umich.edu * to a hardware implementation of the functionality of the software 95254Sksewell@umich.edu * licensed hereunder. You may use the software subject to the license 105254Sksewell@umich.edu * terms below provided that you ensure that this notice is replicated 115254Sksewell@umich.edu * unmodified and in its entirety in all distributions of the software, 125254Sksewell@umich.edu * modified or unmodified, in source code or in binary form. 135254Sksewell@umich.edu * 145254Sksewell@umich.edu * Copyright (c) 2002-2005 The Regents of The University of Michigan 155254Sksewell@umich.edu * All rights reserved. 162131SN/A * 175254Sksewell@umich.edu * Redistribution and use in source and binary forms, with or without 185254Sksewell@umich.edu * modification, are permitted provided that the following conditions are 195254Sksewell@umich.edu * met: redistributions of source code must retain the above copyright 205254Sksewell@umich.edu * notice, this list of conditions and the following disclaimer; 215254Sksewell@umich.edu * redistributions in binary form must reproduce the above copyright 225254Sksewell@umich.edu * notice, this list of conditions and the following disclaimer in the 235254Sksewell@umich.edu * documentation and/or other materials provided with the distribution; 245254Sksewell@umich.edu * neither the name of the copyright holders nor the names of its 255254Sksewell@umich.edu * contributors may be used to endorse or promote products derived from 265254Sksewell@umich.edu * this software without specific prior written permission. 275254Sksewell@umich.edu * 282665Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 295254Sksewell@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 305254Sksewell@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 315222Sksewell@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 322131SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 332131SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 342239SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 357676Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 367676Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 377676Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 382680Sktlim@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 398232Snate@binkert.org * 407676Snate@binkert.org * Authors: Steve Reinhardt 412800Ssaidi@eecs.umich.edu */ 427676Snate@binkert.org 432800Ssaidi@eecs.umich.edu#include "arch/locked_mem.hh" 442800Ssaidi@eecs.umich.edu#include "arch/mmaped_ipr.hh" 452131SN/A#include "arch/utility.hh" 462447SN/A#include "base/bigint.hh" 472447SN/A#include "config/the_isa.hh" 482131SN/A#include "cpu/exetrace.hh" 492479SN/A#include "cpu/simple/timing.hh" 502447SN/A#include "mem/packet.hh" 512447SN/A#include "mem/packet_access.hh" 522131SN/A#include "params/TimingSimpleCPU.hh" 532479SN/A#include "sim/faults.hh" 542447SN/A#include "sim/system.hh" 552447SN/A 562447SN/Ausing namespace std; 575224Sksewell@umich.eduusing namespace TheISA; 585222Sksewell@umich.edu 595222Sksewell@umich.eduPort * 605222Sksewell@umich.eduTimingSimpleCPU::getPort(const std::string &if_name, int idx) 615222Sksewell@umich.edu{ 625222Sksewell@umich.edu if (if_name == "dcache_port") 632447SN/A return &dcachePort; 642447SN/A else if (if_name == "icache_port") 655222Sksewell@umich.edu return &icachePort; 665222Sksewell@umich.edu else 675222Sksewell@umich.edu panic("No Such Port\n"); 685222Sksewell@umich.edu} 695222Sksewell@umich.edu 705222Sksewell@umich.eduvoid 715222Sksewell@umich.eduTimingSimpleCPU::init() 725222Sksewell@umich.edu{ 735222Sksewell@umich.edu BaseCPU::init(); 745222Sksewell@umich.edu#if FULL_SYSTEM 755222Sksewell@umich.edu for (int i = 0; i < threadContexts.size(); ++i) { 765222Sksewell@umich.edu ThreadContext *tc = threadContexts[i]; 775222Sksewell@umich.edu 785224Sksewell@umich.edu // initialize CPU, including PC 795222Sksewell@umich.edu TheISA::initCPU(tc, _cpuId); 804661Sksewell@umich.edu } 814661Sksewell@umich.edu#endif 825224Sksewell@umich.edu} 835222Sksewell@umich.edu 844661Sksewell@umich.eduTick 854661Sksewell@umich.eduTimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) 865224Sksewell@umich.edu{ 874661Sksewell@umich.edu panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 884661Sksewell@umich.edu return curTick(); 894661Sksewell@umich.edu} 905222Sksewell@umich.edu 915222Sksewell@umich.eduvoid 922447SN/ATimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) 932447SN/A{ 944661Sksewell@umich.edu //No internal storage to update, jusst return 954661Sksewell@umich.edu return; 964661Sksewell@umich.edu} 974661Sksewell@umich.edu 982447SN/Avoid 995222Sksewell@umich.eduTimingSimpleCPU::CpuPort::recvStatusChange(Status status) 1002447SN/A{ 1012447SN/A if (status == RangeChange) { 1025222Sksewell@umich.edu if (!snoopRangeSent) { 1035222Sksewell@umich.edu snoopRangeSent = true; 1045222Sksewell@umich.edu sendStatusChange(Port::RangeChange); 1055222Sksewell@umich.edu } 1065222Sksewell@umich.edu return; 1075222Sksewell@umich.edu } 1085222Sksewell@umich.edu 1095222Sksewell@umich.edu panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); 1105222Sksewell@umich.edu} 1115222Sksewell@umich.edu 1125222Sksewell@umich.edu 1135222Sksewell@umich.eduvoid 1145222Sksewell@umich.eduTimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) 1155222Sksewell@umich.edu{ 1165222Sksewell@umich.edu pkt = _pkt; 1175222Sksewell@umich.edu cpu->schedule(this, t); 1185222Sksewell@umich.edu} 1195222Sksewell@umich.edu 1205222Sksewell@umich.eduTimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) 1215222Sksewell@umich.edu : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this, p->clock), 1225222Sksewell@umich.edu dcachePort(this, p->clock), fetchEvent(this) 1235222Sksewell@umich.edu{ 1245222Sksewell@umich.edu _status = Idle; 1255222Sksewell@umich.edu 1265222Sksewell@umich.edu icachePort.snoopRangeSent = false; 1275222Sksewell@umich.edu dcachePort.snoopRangeSent = false; 1285222Sksewell@umich.edu 1295222Sksewell@umich.edu ifetch_pkt = dcache_pkt = NULL; 1302447SN/A drainEvent = NULL; 1312447SN/A previousTick = 0; 1322447SN/A changeState(SimObject::Running); 1332447SN/A system->totalNumInsts = 0; 1342447SN/A} 1352447SN/A 1362447SN/A 1372447SN/ATimingSimpleCPU::~TimingSimpleCPU() 1382447SN/A{ 1392447SN/A} 1402447SN/A 1412447SN/Avoid 1422447SN/ATimingSimpleCPU::serialize(ostream &os) 1432447SN/A{ 1442447SN/A SimObject::State so_state = SimObject::getState(); 1452447SN/A SERIALIZE_ENUM(so_state); 1465222Sksewell@umich.edu BaseSimpleCPU::serialize(os); 1475222Sksewell@umich.edu} 1485222Sksewell@umich.edu 1492447SN/Avoid 1505222Sksewell@umich.eduTimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 1515222Sksewell@umich.edu{ 1525222Sksewell@umich.edu SimObject::State so_state; 1532447SN/A UNSERIALIZE_ENUM(so_state); 1545222Sksewell@umich.edu BaseSimpleCPU::unserialize(cp, section); 1555222Sksewell@umich.edu} 1565222Sksewell@umich.edu 1572447SN/Aunsigned int 1585222Sksewell@umich.eduTimingSimpleCPU::drain(Event *drain_event) 1592447SN/A{ 1602447SN/A // TimingSimpleCPU is ready to drain if it's not waiting for 1612447SN/A // an access to complete. 1625222Sksewell@umich.edu if (_status == Idle || _status == Running || _status == SwitchedOut) { 1632447SN/A changeState(SimObject::Drained); 1642447SN/A return 0; 1652447SN/A } else { 1665222Sksewell@umich.edu changeState(SimObject::Draining); 1674661Sksewell@umich.edu drainEvent = drain_event; 1684661Sksewell@umich.edu return 1; 1694661Sksewell@umich.edu } 1705222Sksewell@umich.edu} 1716378Sgblack@eecs.umich.edu 1726378Sgblack@eecs.umich.eduvoid 1735222Sksewell@umich.eduTimingSimpleCPU::resume() 1746378Sgblack@eecs.umich.edu{ 1756378Sgblack@eecs.umich.edu DPRINTF(SimpleCPU, "Resume\n"); 1766378Sgblack@eecs.umich.edu if (_status != SwitchedOut && _status != Idle) { 1775222Sksewell@umich.edu assert(system->getMemoryMode() == Enums::timing); 1785222Sksewell@umich.edu 1796378Sgblack@eecs.umich.edu if (fetchEvent.scheduled()) 1806379Sgblack@eecs.umich.edu deschedule(fetchEvent); 1815222Sksewell@umich.edu 1826378Sgblack@eecs.umich.edu schedule(fetchEvent, nextCycle()); 1836383Sgblack@eecs.umich.edu } 1846379Sgblack@eecs.umich.edu 1856378Sgblack@eecs.umich.edu changeState(SimObject::Running); 1866383Sgblack@eecs.umich.edu} 1876379Sgblack@eecs.umich.edu 1886379Sgblack@eecs.umich.eduvoid 1896383Sgblack@eecs.umich.eduTimingSimpleCPU::switchOut() 1905222Sksewell@umich.edu{ 1915222Sksewell@umich.edu assert(_status == Running || _status == Idle); 1926378Sgblack@eecs.umich.edu _status = SwitchedOut; 1936379Sgblack@eecs.umich.edu numCycles += tickToCycles(curTick() - previousTick); 1946383Sgblack@eecs.umich.edu 1955222Sksewell@umich.edu // If we've been scheduled to resume but are then told to switch out, 1966378Sgblack@eecs.umich.edu // we'll need to cancel it. 1976378Sgblack@eecs.umich.edu if (fetchEvent.scheduled()) 1986378Sgblack@eecs.umich.edu deschedule(fetchEvent); 1996378Sgblack@eecs.umich.edu} 2006378Sgblack@eecs.umich.edu 2016379Sgblack@eecs.umich.edu 2026378Sgblack@eecs.umich.eduvoid 2036383Sgblack@eecs.umich.eduTimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 2046378Sgblack@eecs.umich.edu{ 2056379Sgblack@eecs.umich.edu BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort); 2066378Sgblack@eecs.umich.edu 2076383Sgblack@eecs.umich.edu // if any of this CPU's ThreadContexts are active, mark the CPU as 2086378Sgblack@eecs.umich.edu // running and schedule its tick event. 2096379Sgblack@eecs.umich.edu for (int i = 0; i < threadContexts.size(); ++i) { 2106378Sgblack@eecs.umich.edu ThreadContext *tc = threadContexts[i]; 2115222Sksewell@umich.edu if (tc->status() == ThreadContext::Active && _status != Running) { 2126378Sgblack@eecs.umich.edu _status = Running; 2136383Sgblack@eecs.umich.edu break; 2146379Sgblack@eecs.umich.edu } 2156379Sgblack@eecs.umich.edu } 2166379Sgblack@eecs.umich.edu 2176383Sgblack@eecs.umich.edu if (_status != Running) { 2186378Sgblack@eecs.umich.edu _status = Idle; 2196378Sgblack@eecs.umich.edu } 2206378Sgblack@eecs.umich.edu assert(threadContexts.size() == 1); 2217678Sgblack@eecs.umich.edu previousTick = curTick(); 2226378Sgblack@eecs.umich.edu} 2236378Sgblack@eecs.umich.edu 2246378Sgblack@eecs.umich.edu 2256378Sgblack@eecs.umich.eduvoid 2266378Sgblack@eecs.umich.eduTimingSimpleCPU::activateContext(int thread_num, int delay) 2276378Sgblack@eecs.umich.edu{ 2286383Sgblack@eecs.umich.edu DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay); 2296378Sgblack@eecs.umich.edu 2306378Sgblack@eecs.umich.edu assert(thread_num == 0); 2316379Sgblack@eecs.umich.edu assert(thread); 2326378Sgblack@eecs.umich.edu 2336383Sgblack@eecs.umich.edu assert(_status == Idle); 2346378Sgblack@eecs.umich.edu 2356378Sgblack@eecs.umich.edu notIdleFraction++; 2366378Sgblack@eecs.umich.edu _status = Running; 2376378Sgblack@eecs.umich.edu 2386378Sgblack@eecs.umich.edu // kick things off by initiating the fetch of the next instruction 2396378Sgblack@eecs.umich.edu schedule(fetchEvent, nextCycle(curTick() + ticks(delay))); 2406378Sgblack@eecs.umich.edu} 2417678Sgblack@eecs.umich.edu 2426378Sgblack@eecs.umich.edu 2436378Sgblack@eecs.umich.eduvoid 2446378Sgblack@eecs.umich.eduTimingSimpleCPU::suspendContext(int thread_num) 2456383Sgblack@eecs.umich.edu{ 2466378Sgblack@eecs.umich.edu DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num); 2476378Sgblack@eecs.umich.edu 2486378Sgblack@eecs.umich.edu assert(thread_num == 0); 2496378Sgblack@eecs.umich.edu assert(thread); 2506383Sgblack@eecs.umich.edu 2516378Sgblack@eecs.umich.edu if (_status == Idle) 2526378Sgblack@eecs.umich.edu return; 2536378Sgblack@eecs.umich.edu 2546378Sgblack@eecs.umich.edu assert(_status == Running); 2557678Sgblack@eecs.umich.edu 2566378Sgblack@eecs.umich.edu // just change status to Idle... if status != Running, 2576378Sgblack@eecs.umich.edu // completeInst() will not initiate fetch of next instruction. 2586378Sgblack@eecs.umich.edu 2596378Sgblack@eecs.umich.edu notIdleFraction--; 2606378Sgblack@eecs.umich.edu _status = Idle; 2616378Sgblack@eecs.umich.edu} 2626378Sgblack@eecs.umich.edu 2636383Sgblack@eecs.umich.edubool 2646378Sgblack@eecs.umich.eduTimingSimpleCPU::handleReadPacket(PacketPtr pkt) 2656378Sgblack@eecs.umich.edu{ 2666378Sgblack@eecs.umich.edu RequestPtr req = pkt->req; 2676378Sgblack@eecs.umich.edu if (req->isMmapedIpr()) { 2687678Sgblack@eecs.umich.edu Tick delay; 2696378Sgblack@eecs.umich.edu delay = TheISA::handleIprRead(thread->getTC(), pkt); 2706378Sgblack@eecs.umich.edu new IprEvent(pkt, this, nextCycle(curTick() + delay)); 2716378Sgblack@eecs.umich.edu _status = DcacheWaitResponse; 2726378Sgblack@eecs.umich.edu dcache_pkt = NULL; 2736378Sgblack@eecs.umich.edu } else if (!dcachePort.sendTiming(pkt)) { 2746378Sgblack@eecs.umich.edu _status = DcacheRetry; 2756383Sgblack@eecs.umich.edu dcache_pkt = pkt; 2766378Sgblack@eecs.umich.edu } else { 2776378Sgblack@eecs.umich.edu _status = DcacheWaitResponse; 2786378Sgblack@eecs.umich.edu // memory system takes ownership of packet 2796378Sgblack@eecs.umich.edu dcache_pkt = NULL; 2807678Sgblack@eecs.umich.edu } 2816378Sgblack@eecs.umich.edu return dcache_pkt == NULL; 2826378Sgblack@eecs.umich.edu} 2836378Sgblack@eecs.umich.edu 2846383Sgblack@eecs.umich.eduvoid 2856383Sgblack@eecs.umich.eduTimingSimpleCPU::sendData(RequestPtr req, uint8_t *data, uint64_t *res, 2866379Sgblack@eecs.umich.edu bool read) 2876379Sgblack@eecs.umich.edu{ 2886379Sgblack@eecs.umich.edu PacketPtr pkt; 2896383Sgblack@eecs.umich.edu buildPacket(pkt, req, read); 2906379Sgblack@eecs.umich.edu pkt->dataDynamicArray<uint8_t>(data); 2916383Sgblack@eecs.umich.edu if (req->getFlags().isSet(Request::NO_ACCESS)) { 2926379Sgblack@eecs.umich.edu assert(!dcache_pkt); 2936383Sgblack@eecs.umich.edu pkt->makeResponse(); 2946378Sgblack@eecs.umich.edu completeDataAccess(pkt); 2956378Sgblack@eecs.umich.edu } else if (read) { 2966378Sgblack@eecs.umich.edu handleReadPacket(pkt); 2976378Sgblack@eecs.umich.edu } else { 2986378Sgblack@eecs.umich.edu bool do_access = true; // flag to suppress cache access 2996378Sgblack@eecs.umich.edu 3006383Sgblack@eecs.umich.edu if (req->isLLSC()) { 3016379Sgblack@eecs.umich.edu do_access = TheISA::handleLockedWrite(thread, req); 3026378Sgblack@eecs.umich.edu } else if (req->isCondSwap()) { 3036378Sgblack@eecs.umich.edu assert(res); 3046378Sgblack@eecs.umich.edu req->setExtraData(*res); 3057678Sgblack@eecs.umich.edu } 3066378Sgblack@eecs.umich.edu 3076378Sgblack@eecs.umich.edu if (do_access) { 3086378Sgblack@eecs.umich.edu dcache_pkt = pkt; 3096383Sgblack@eecs.umich.edu handleWritePacket(); 3106378Sgblack@eecs.umich.edu } else { 3116378Sgblack@eecs.umich.edu _status = DcacheWaitResponse; 3126378Sgblack@eecs.umich.edu completeDataAccess(pkt); 3136378Sgblack@eecs.umich.edu } 3146383Sgblack@eecs.umich.edu } 3156378Sgblack@eecs.umich.edu} 3166378Sgblack@eecs.umich.edu 3176378Sgblack@eecs.umich.eduvoid 3186378Sgblack@eecs.umich.eduTimingSimpleCPU::sendSplitData(RequestPtr req1, RequestPtr req2, 3197678Sgblack@eecs.umich.edu RequestPtr req, uint8_t *data, bool read) 3206378Sgblack@eecs.umich.edu{ 3216378Sgblack@eecs.umich.edu PacketPtr pkt1, pkt2; 3226378Sgblack@eecs.umich.edu buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read); 3236383Sgblack@eecs.umich.edu if (req->getFlags().isSet(Request::NO_ACCESS)) { 3246383Sgblack@eecs.umich.edu assert(!dcache_pkt); 3256379Sgblack@eecs.umich.edu pkt1->makeResponse(); 3266379Sgblack@eecs.umich.edu completeDataAccess(pkt1); 3276379Sgblack@eecs.umich.edu } else if (read) { 3286383Sgblack@eecs.umich.edu SplitFragmentSenderState * send_state = 3296379Sgblack@eecs.umich.edu dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 3306383Sgblack@eecs.umich.edu if (handleReadPacket(pkt1)) { 3316379Sgblack@eecs.umich.edu send_state->clearFromParent(); 3326383Sgblack@eecs.umich.edu send_state = dynamic_cast<SplitFragmentSenderState *>( 3336378Sgblack@eecs.umich.edu pkt2->senderState); 3346378Sgblack@eecs.umich.edu if (handleReadPacket(pkt2)) { 3356378Sgblack@eecs.umich.edu send_state->clearFromParent(); 3366378Sgblack@eecs.umich.edu } 3376378Sgblack@eecs.umich.edu } 3386383Sgblack@eecs.umich.edu } else { 3396378Sgblack@eecs.umich.edu dcache_pkt = pkt1; 3406379Sgblack@eecs.umich.edu SplitFragmentSenderState * send_state = 3416383Sgblack@eecs.umich.edu dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 3426378Sgblack@eecs.umich.edu if (handleWritePacket()) { 3436378Sgblack@eecs.umich.edu send_state->clearFromParent(); 3446378Sgblack@eecs.umich.edu dcache_pkt = pkt2; 3457678Sgblack@eecs.umich.edu send_state = dynamic_cast<SplitFragmentSenderState *>( 3466378Sgblack@eecs.umich.edu pkt2->senderState); 3476383Sgblack@eecs.umich.edu if (handleWritePacket()) { 3486378Sgblack@eecs.umich.edu send_state->clearFromParent(); 3496383Sgblack@eecs.umich.edu } 3506383Sgblack@eecs.umich.edu } 3516379Sgblack@eecs.umich.edu } 3526379Sgblack@eecs.umich.edu} 3536379Sgblack@eecs.umich.edu 3546383Sgblack@eecs.umich.eduvoid 3556383Sgblack@eecs.umich.eduTimingSimpleCPU::translationFault(Fault fault) 3566379Sgblack@eecs.umich.edu{ 3576383Sgblack@eecs.umich.edu // fault may be NoFault in cases where a fault is suppressed, 3586378Sgblack@eecs.umich.edu // for instance prefetches. 3596383Sgblack@eecs.umich.edu numCycles += tickToCycles(curTick() - previousTick); 3606378Sgblack@eecs.umich.edu previousTick = curTick(); 3616378Sgblack@eecs.umich.edu 3626379Sgblack@eecs.umich.edu if (traceData) { 3636378Sgblack@eecs.umich.edu // Since there was a fault, we shouldn't trace this instruction. 3646383Sgblack@eecs.umich.edu delete traceData; 3656378Sgblack@eecs.umich.edu traceData = NULL; 3666378Sgblack@eecs.umich.edu } 3676383Sgblack@eecs.umich.edu 3686378Sgblack@eecs.umich.edu postExecute(); 3696378Sgblack@eecs.umich.edu 3706378Sgblack@eecs.umich.edu if (getState() == SimObject::Draining) { 3716378Sgblack@eecs.umich.edu advancePC(fault); 3726378Sgblack@eecs.umich.edu completeDrain(); 3736378Sgblack@eecs.umich.edu } else { 3746378Sgblack@eecs.umich.edu advanceInst(fault); 3757678Sgblack@eecs.umich.edu } 3766378Sgblack@eecs.umich.edu} 3776378Sgblack@eecs.umich.edu 3786378Sgblack@eecs.umich.eduvoid 3796378Sgblack@eecs.umich.eduTimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr req, bool read) 3806383Sgblack@eecs.umich.edu{ 3816383Sgblack@eecs.umich.edu MemCmd cmd; 3826379Sgblack@eecs.umich.edu if (read) { 3836379Sgblack@eecs.umich.edu cmd = MemCmd::ReadReq; 3846379Sgblack@eecs.umich.edu if (req->isLLSC()) 3856383Sgblack@eecs.umich.edu cmd = MemCmd::LoadLockedReq; 3866378Sgblack@eecs.umich.edu } else { 3876383Sgblack@eecs.umich.edu cmd = MemCmd::WriteReq; 3886379Sgblack@eecs.umich.edu if (req->isLLSC()) { 3896383Sgblack@eecs.umich.edu cmd = MemCmd::StoreCondReq; 3906379Sgblack@eecs.umich.edu } else if (req->isSwap()) { 3916383Sgblack@eecs.umich.edu cmd = MemCmd::SwapReq; 3926378Sgblack@eecs.umich.edu } 3936378Sgblack@eecs.umich.edu } 3946379Sgblack@eecs.umich.edu pkt = new Packet(req, cmd, Packet::Broadcast); 3956378Sgblack@eecs.umich.edu} 3966383Sgblack@eecs.umich.edu 3976378Sgblack@eecs.umich.eduvoid 3986378Sgblack@eecs.umich.eduTimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, 3996383Sgblack@eecs.umich.edu RequestPtr req1, RequestPtr req2, RequestPtr req, 4006378Sgblack@eecs.umich.edu uint8_t *data, bool read) 4016378Sgblack@eecs.umich.edu{ 4026378Sgblack@eecs.umich.edu pkt1 = pkt2 = NULL; 4036378Sgblack@eecs.umich.edu 4046378Sgblack@eecs.umich.edu assert(!req1->isMmapedIpr() && !req2->isMmapedIpr()); 4056378Sgblack@eecs.umich.edu 4066378Sgblack@eecs.umich.edu if (req->getFlags().isSet(Request::NO_ACCESS)) { 4076378Sgblack@eecs.umich.edu buildPacket(pkt1, req, read); 4087678Sgblack@eecs.umich.edu return; 4096378Sgblack@eecs.umich.edu } 4106378Sgblack@eecs.umich.edu 4116383Sgblack@eecs.umich.edu buildPacket(pkt1, req1, read); 4126383Sgblack@eecs.umich.edu buildPacket(pkt2, req2, read); 4136379Sgblack@eecs.umich.edu 4146379Sgblack@eecs.umich.edu req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags()); 4156379Sgblack@eecs.umich.edu PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(), 4166383Sgblack@eecs.umich.edu Packet::Broadcast); 4176379Sgblack@eecs.umich.edu 4186383Sgblack@eecs.umich.edu pkt->dataDynamicArray<uint8_t>(data); 4196379Sgblack@eecs.umich.edu pkt1->dataStatic<uint8_t>(data); 4206383Sgblack@eecs.umich.edu pkt2->dataStatic<uint8_t>(data + req1->getSize()); 4216378Sgblack@eecs.umich.edu 4226378Sgblack@eecs.umich.edu SplitMainSenderState * main_send_state = new SplitMainSenderState; 4236378Sgblack@eecs.umich.edu pkt->senderState = main_send_state; 4246378Sgblack@eecs.umich.edu main_send_state->fragments[0] = pkt1; 4256383Sgblack@eecs.umich.edu main_send_state->fragments[1] = pkt2; 4266378Sgblack@eecs.umich.edu main_send_state->outstanding = 2; 4276378Sgblack@eecs.umich.edu pkt1->senderState = new SplitFragmentSenderState(pkt, 0); 4285222Sksewell@umich.edu pkt2->senderState = new SplitFragmentSenderState(pkt, 1); 4295222Sksewell@umich.edu} 4305222Sksewell@umich.edu 4316378Sgblack@eecs.umich.eduFault 4327678Sgblack@eecs.umich.eduTimingSimpleCPU::readBytes(Addr addr, uint8_t *data, 4335222Sksewell@umich.edu unsigned size, unsigned flags) 4346378Sgblack@eecs.umich.edu{ 4356378Sgblack@eecs.umich.edu Fault fault; 4365222Sksewell@umich.edu const int asid = 0; 4376378Sgblack@eecs.umich.edu const ThreadID tid = 0; 4386378Sgblack@eecs.umich.edu const Addr pc = thread->instAddr(); 4396378Sgblack@eecs.umich.edu unsigned block_size = dcachePort.peerBlockSize(); 4406383Sgblack@eecs.umich.edu BaseTLB::Mode mode = BaseTLB::Read; 4416378Sgblack@eecs.umich.edu 4425222Sksewell@umich.edu if (traceData) { 4435222Sksewell@umich.edu traceData->setAddr(addr); 4446378Sgblack@eecs.umich.edu } 4457678Sgblack@eecs.umich.edu 4465222Sksewell@umich.edu RequestPtr req = new Request(asid, addr, size, 4475222Sksewell@umich.edu flags, pc, _cpuId, tid); 4486378Sgblack@eecs.umich.edu 4496378Sgblack@eecs.umich.edu Addr split_addr = roundDown(addr + size - 1, block_size); 4506378Sgblack@eecs.umich.edu assert(split_addr <= addr || split_addr - addr < block_size); 4515222Sksewell@umich.edu 4526383Sgblack@eecs.umich.edu _status = DTBWaitResponse; 4536379Sgblack@eecs.umich.edu if (split_addr > addr) { 4546378Sgblack@eecs.umich.edu RequestPtr req1, req2; 4556383Sgblack@eecs.umich.edu assert(!req->isLLSC() && !req->isSwap()); 4566378Sgblack@eecs.umich.edu req->splitOnVaddr(split_addr, req1, req2); 4576378Sgblack@eecs.umich.edu 4586383Sgblack@eecs.umich.edu WholeTranslationState *state = 4596378Sgblack@eecs.umich.edu new WholeTranslationState(req, req1, req2, new uint8_t[size], 4605222Sksewell@umich.edu NULL, mode); 4616378Sgblack@eecs.umich.edu DataTranslation<TimingSimpleCPU> *trans1 = 4625222Sksewell@umich.edu new DataTranslation<TimingSimpleCPU>(this, state, 0); 4635222Sksewell@umich.edu DataTranslation<TimingSimpleCPU> *trans2 = 4645222Sksewell@umich.edu new DataTranslation<TimingSimpleCPU>(this, state, 1); 4655222Sksewell@umich.edu 4665222Sksewell@umich.edu thread->dtb->translateTiming(req1, tc, trans1, mode); 4676378Sgblack@eecs.umich.edu thread->dtb->translateTiming(req2, tc, trans2, mode); 4687678Sgblack@eecs.umich.edu } else { 4694661Sksewell@umich.edu WholeTranslationState *state = 4705224Sksewell@umich.edu new WholeTranslationState(req, new uint8_t[size], NULL, mode); 4716378Sgblack@eecs.umich.edu DataTranslation<TimingSimpleCPU> *translation 4726378Sgblack@eecs.umich.edu = new DataTranslation<TimingSimpleCPU>(this, state); 4736378Sgblack@eecs.umich.edu thread->dtb->translateTiming(req, tc, translation, mode); 4746378Sgblack@eecs.umich.edu } 4756378Sgblack@eecs.umich.edu 4766379Sgblack@eecs.umich.edu return NoFault; 4775224Sksewell@umich.edu} 4785224Sksewell@umich.edu 4796378Sgblack@eecs.umich.edutemplate <class T> 4806383Sgblack@eecs.umich.eduFault 4816379Sgblack@eecs.umich.eduTimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 4826383Sgblack@eecs.umich.edu{ 4835222Sksewell@umich.edu return readBytes(addr, (uint8_t *)&data, sizeof(T), flags); 4845222Sksewell@umich.edu} 4856378Sgblack@eecs.umich.edu 4867678Sgblack@eecs.umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS 4875222Sksewell@umich.edu 4885222Sksewell@umich.edutemplate 4896378Sgblack@eecs.umich.eduFault 4906378Sgblack@eecs.umich.eduTimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags); 4916378Sgblack@eecs.umich.edu 4926378Sgblack@eecs.umich.edutemplate 4936383Sgblack@eecs.umich.eduFault 4946378Sgblack@eecs.umich.eduTimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags); 4955222Sksewell@umich.edu 4965222Sksewell@umich.edutemplate 4975222Sksewell@umich.eduFault 4985222Sksewell@umich.eduTimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 4995222Sksewell@umich.edu 5006378Sgblack@eecs.umich.edutemplate 5017678Sgblack@eecs.umich.eduFault 5025222Sksewell@umich.eduTimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 5036378Sgblack@eecs.umich.edu 5046378Sgblack@eecs.umich.edutemplate 5055222Sksewell@umich.eduFault 5065222Sksewell@umich.eduTimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 5076378Sgblack@eecs.umich.edu 5087678Sgblack@eecs.umich.edutemplate 5095222Sksewell@umich.eduFault 5106378Sgblack@eecs.umich.eduTimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 5116378Sgblack@eecs.umich.edu 5124661Sksewell@umich.edu#endif //DOXYGEN_SHOULD_SKIP_THIS 5134661Sksewell@umich.edu 5146378Sgblack@eecs.umich.edutemplate<> 5157678Sgblack@eecs.umich.eduFault 5164661Sksewell@umich.eduTimingSimpleCPU::read(Addr addr, double &data, unsigned flags) 5175222Sksewell@umich.edu{ 5186378Sgblack@eecs.umich.edu return read(addr, *(uint64_t*)&data, flags); 5196378Sgblack@eecs.umich.edu} 5206378Sgblack@eecs.umich.edu 5216378Sgblack@eecs.umich.edutemplate<> 5226383Sgblack@eecs.umich.eduFault 5236379Sgblack@eecs.umich.eduTimingSimpleCPU::read(Addr addr, float &data, unsigned flags) 5246383Sgblack@eecs.umich.edu{ 5254661Sksewell@umich.edu return read(addr, *(uint32_t*)&data, flags); 5266378Sgblack@eecs.umich.edu} 5276378Sgblack@eecs.umich.edu 5286383Sgblack@eecs.umich.edutemplate<> 5296378Sgblack@eecs.umich.eduFault 5304661Sksewell@umich.eduTimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 5315222Sksewell@umich.edu{ 5325224Sksewell@umich.edu return read(addr, (uint32_t&)data, flags); 5335222Sksewell@umich.edu} 5344661Sksewell@umich.edu 5354661Sksewell@umich.edubool 5362447SN/ATimingSimpleCPU::handleWritePacket() 5372447SN/A{ 538 RequestPtr req = dcache_pkt->req; 539 if (req->isMmapedIpr()) { 540 Tick delay; 541 delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); 542 new IprEvent(dcache_pkt, this, nextCycle(curTick() + delay)); 543 _status = DcacheWaitResponse; 544 dcache_pkt = NULL; 545 } else if (!dcachePort.sendTiming(dcache_pkt)) { 546 _status = DcacheRetry; 547 } else { 548 _status = DcacheWaitResponse; 549 // memory system takes ownership of packet 550 dcache_pkt = NULL; 551 } 552 return dcache_pkt == NULL; 553} 554 555Fault 556TimingSimpleCPU::writeTheseBytes(uint8_t *data, unsigned size, 557 Addr addr, unsigned flags, uint64_t *res) 558{ 559 const int asid = 0; 560 const ThreadID tid = 0; 561 const Addr pc = thread->instAddr(); 562 unsigned block_size = dcachePort.peerBlockSize(); 563 BaseTLB::Mode mode = BaseTLB::Write; 564 565 if (traceData) { 566 traceData->setAddr(addr); 567 } 568 569 RequestPtr req = new Request(asid, addr, size, 570 flags, pc, _cpuId, tid); 571 572 Addr split_addr = roundDown(addr + size - 1, block_size); 573 assert(split_addr <= addr || split_addr - addr < block_size); 574 575 _status = DTBWaitResponse; 576 if (split_addr > addr) { 577 RequestPtr req1, req2; 578 assert(!req->isLLSC() && !req->isSwap()); 579 req->splitOnVaddr(split_addr, req1, req2); 580 581 WholeTranslationState *state = 582 new WholeTranslationState(req, req1, req2, data, res, mode); 583 DataTranslation<TimingSimpleCPU> *trans1 = 584 new DataTranslation<TimingSimpleCPU>(this, state, 0); 585 DataTranslation<TimingSimpleCPU> *trans2 = 586 new DataTranslation<TimingSimpleCPU>(this, state, 1); 587 588 thread->dtb->translateTiming(req1, tc, trans1, mode); 589 thread->dtb->translateTiming(req2, tc, trans2, mode); 590 } else { 591 WholeTranslationState *state = 592 new WholeTranslationState(req, data, res, mode); 593 DataTranslation<TimingSimpleCPU> *translation = 594 new DataTranslation<TimingSimpleCPU>(this, state); 595 thread->dtb->translateTiming(req, tc, translation, mode); 596 } 597 598 // Translation faults will be returned via finishTranslation() 599 return NoFault; 600} 601 602Fault 603TimingSimpleCPU::writeBytes(uint8_t *data, unsigned size, 604 Addr addr, unsigned flags, uint64_t *res) 605{ 606 uint8_t *newData = new uint8_t[size]; 607 memcpy(newData, data, size); 608 return writeTheseBytes(newData, size, addr, flags, res); 609} 610 611template <class T> 612Fault 613TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 614{ 615 if (traceData) { 616 traceData->setData(data); 617 } 618 T *dataP = (T*) new uint8_t[sizeof(T)]; 619 *dataP = TheISA::htog(data); 620 621 return writeTheseBytes((uint8_t *)dataP, sizeof(T), addr, flags, res); 622} 623 624 625#ifndef DOXYGEN_SHOULD_SKIP_THIS 626template 627Fault 628TimingSimpleCPU::write(Twin32_t data, Addr addr, 629 unsigned flags, uint64_t *res); 630 631template 632Fault 633TimingSimpleCPU::write(Twin64_t data, Addr addr, 634 unsigned flags, uint64_t *res); 635 636template 637Fault 638TimingSimpleCPU::write(uint64_t data, Addr addr, 639 unsigned flags, uint64_t *res); 640 641template 642Fault 643TimingSimpleCPU::write(uint32_t data, Addr addr, 644 unsigned flags, uint64_t *res); 645 646template 647Fault 648TimingSimpleCPU::write(uint16_t data, Addr addr, 649 unsigned flags, uint64_t *res); 650 651template 652Fault 653TimingSimpleCPU::write(uint8_t data, Addr addr, 654 unsigned flags, uint64_t *res); 655 656#endif //DOXYGEN_SHOULD_SKIP_THIS 657 658template<> 659Fault 660TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 661{ 662 return write(*(uint64_t*)&data, addr, flags, res); 663} 664 665template<> 666Fault 667TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 668{ 669 return write(*(uint32_t*)&data, addr, flags, res); 670} 671 672 673template<> 674Fault 675TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 676{ 677 return write((uint32_t)data, addr, flags, res); 678} 679 680 681void 682TimingSimpleCPU::finishTranslation(WholeTranslationState *state) 683{ 684 _status = Running; 685 686 if (state->getFault() != NoFault) { 687 if (state->isPrefetch()) { 688 state->setNoFault(); 689 } 690 delete [] state->data; 691 state->deleteReqs(); 692 translationFault(state->getFault()); 693 } else { 694 if (!state->isSplit) { 695 sendData(state->mainReq, state->data, state->res, 696 state->mode == BaseTLB::Read); 697 } else { 698 sendSplitData(state->sreqLow, state->sreqHigh, state->mainReq, 699 state->data, state->mode == BaseTLB::Read); 700 } 701 } 702 703 delete state; 704} 705 706 707void 708TimingSimpleCPU::fetch() 709{ 710 DPRINTF(SimpleCPU, "Fetch\n"); 711 712 if (!curStaticInst || !curStaticInst->isDelayedCommit()) 713 checkForInterrupts(); 714 715 checkPcEventQueue(); 716 717 TheISA::PCState pcState = thread->pcState(); 718 bool needToFetch = !isRomMicroPC(pcState.microPC()) && !curMacroStaticInst; 719 720 if (needToFetch) { 721 Request *ifetch_req = new Request(); 722 ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0); 723 setupFetchRequest(ifetch_req); 724 thread->itb->translateTiming(ifetch_req, tc, &fetchTranslation, 725 BaseTLB::Execute); 726 } else { 727 _status = IcacheWaitResponse; 728 completeIfetch(NULL); 729 730 numCycles += tickToCycles(curTick() - previousTick); 731 previousTick = curTick(); 732 } 733} 734 735 736void 737TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc) 738{ 739 if (fault == NoFault) { 740 ifetch_pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast); 741 ifetch_pkt->dataStatic(&inst); 742 743 if (!icachePort.sendTiming(ifetch_pkt)) { 744 // Need to wait for retry 745 _status = IcacheRetry; 746 } else { 747 // Need to wait for cache to respond 748 _status = IcacheWaitResponse; 749 // ownership of packet transferred to memory system 750 ifetch_pkt = NULL; 751 } 752 } else { 753 delete req; 754 // fetch fault: advance directly to next instruction (fault handler) 755 advanceInst(fault); 756 } 757 758 numCycles += tickToCycles(curTick() - previousTick); 759 previousTick = curTick(); 760} 761 762 763void 764TimingSimpleCPU::advanceInst(Fault fault) 765{ 766 if (fault != NoFault || !stayAtPC) 767 advancePC(fault); 768 769 if (_status == Running) { 770 // kick off fetch of next instruction... callback from icache 771 // response will cause that instruction to be executed, 772 // keeping the CPU running. 773 fetch(); 774 } 775} 776 777 778void 779TimingSimpleCPU::completeIfetch(PacketPtr pkt) 780{ 781 DPRINTF(SimpleCPU, "Complete ICache Fetch\n"); 782 783 // received a response from the icache: execute the received 784 // instruction 785 786 assert(!pkt || !pkt->isError()); 787 assert(_status == IcacheWaitResponse); 788 789 _status = Running; 790 791 numCycles += tickToCycles(curTick() - previousTick); 792 previousTick = curTick(); 793 794 if (getState() == SimObject::Draining) { 795 if (pkt) { 796 delete pkt->req; 797 delete pkt; 798 } 799 800 completeDrain(); 801 return; 802 } 803 804 preExecute(); 805 if (curStaticInst && curStaticInst->isMemRef()) { 806 // load or store: just send to dcache 807 Fault fault = curStaticInst->initiateAcc(this, traceData); 808 if (_status != Running) { 809 // instruction will complete in dcache response callback 810 assert(_status == DcacheWaitResponse || 811 _status == DcacheRetry || DTBWaitResponse); 812 assert(fault == NoFault); 813 } else { 814 if (fault != NoFault && traceData) { 815 // If there was a fault, we shouldn't trace this instruction. 816 delete traceData; 817 traceData = NULL; 818 } 819 820 postExecute(); 821 // @todo remove me after debugging with legion done 822 if (curStaticInst && (!curStaticInst->isMicroop() || 823 curStaticInst->isFirstMicroop())) 824 instCnt++; 825 advanceInst(fault); 826 } 827 } else if (curStaticInst) { 828 // non-memory instruction: execute completely now 829 Fault fault = curStaticInst->execute(this, traceData); 830 831 // keep an instruction count 832 if (fault == NoFault) 833 countInst(); 834 else if (traceData && !DTRACE(ExecFaulting)) { 835 delete traceData; 836 traceData = NULL; 837 } 838 839 postExecute(); 840 // @todo remove me after debugging with legion done 841 if (curStaticInst && (!curStaticInst->isMicroop() || 842 curStaticInst->isFirstMicroop())) 843 instCnt++; 844 advanceInst(fault); 845 } else { 846 advanceInst(NoFault); 847 } 848 849 if (pkt) { 850 delete pkt->req; 851 delete pkt; 852 } 853} 854 855void 856TimingSimpleCPU::IcachePort::ITickEvent::process() 857{ 858 cpu->completeIfetch(pkt); 859} 860 861bool 862TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt) 863{ 864 if (pkt->isResponse() && !pkt->wasNacked()) { 865 // delay processing of returned data until next CPU clock edge 866 Tick next_tick = cpu->nextCycle(curTick()); 867 868 if (next_tick == curTick()) 869 cpu->completeIfetch(pkt); 870 else 871 tickEvent.schedule(pkt, next_tick); 872 873 return true; 874 } 875 else if (pkt->wasNacked()) { 876 assert(cpu->_status == IcacheWaitResponse); 877 pkt->reinitNacked(); 878 if (!sendTiming(pkt)) { 879 cpu->_status = IcacheRetry; 880 cpu->ifetch_pkt = pkt; 881 } 882 } 883 //Snooping a Coherence Request, do nothing 884 return true; 885} 886 887void 888TimingSimpleCPU::IcachePort::recvRetry() 889{ 890 // we shouldn't get a retry unless we have a packet that we're 891 // waiting to transmit 892 assert(cpu->ifetch_pkt != NULL); 893 assert(cpu->_status == IcacheRetry); 894 PacketPtr tmp = cpu->ifetch_pkt; 895 if (sendTiming(tmp)) { 896 cpu->_status = IcacheWaitResponse; 897 cpu->ifetch_pkt = NULL; 898 } 899} 900 901void 902TimingSimpleCPU::completeDataAccess(PacketPtr pkt) 903{ 904 // received a response from the dcache: complete the load or store 905 // instruction 906 assert(!pkt->isError()); 907 assert(_status == DcacheWaitResponse || _status == DTBWaitResponse || 908 pkt->req->getFlags().isSet(Request::NO_ACCESS)); 909 910 numCycles += tickToCycles(curTick() - previousTick); 911 previousTick = curTick(); 912 913 if (pkt->senderState) { 914 SplitFragmentSenderState * send_state = 915 dynamic_cast<SplitFragmentSenderState *>(pkt->senderState); 916 assert(send_state); 917 delete pkt->req; 918 delete pkt; 919 PacketPtr big_pkt = send_state->bigPkt; 920 delete send_state; 921 922 SplitMainSenderState * main_send_state = 923 dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); 924 assert(main_send_state); 925 // Record the fact that this packet is no longer outstanding. 926 assert(main_send_state->outstanding != 0); 927 main_send_state->outstanding--; 928 929 if (main_send_state->outstanding) { 930 return; 931 } else { 932 delete main_send_state; 933 big_pkt->senderState = NULL; 934 pkt = big_pkt; 935 } 936 } 937 938 _status = Running; 939 940 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 941 942 // keep an instruction count 943 if (fault == NoFault) 944 countInst(); 945 else if (traceData) { 946 // If there was a fault, we shouldn't trace this instruction. 947 delete traceData; 948 traceData = NULL; 949 } 950 951 // the locked flag may be cleared on the response packet, so check 952 // pkt->req and not pkt to see if it was a load-locked 953 if (pkt->isRead() && pkt->req->isLLSC()) { 954 TheISA::handleLockedRead(thread, pkt->req); 955 } 956 957 delete pkt->req; 958 delete pkt; 959 960 postExecute(); 961 962 if (getState() == SimObject::Draining) { 963 advancePC(fault); 964 completeDrain(); 965 966 return; 967 } 968 969 advanceInst(fault); 970} 971 972 973void 974TimingSimpleCPU::completeDrain() 975{ 976 DPRINTF(Config, "Done draining\n"); 977 changeState(SimObject::Drained); 978 drainEvent->process(); 979} 980 981void 982TimingSimpleCPU::DcachePort::setPeer(Port *port) 983{ 984 Port::setPeer(port); 985 986#if FULL_SYSTEM 987 // Update the ThreadContext's memory ports (Functional/Virtual 988 // Ports) 989 cpu->tcBase()->connectMemPorts(cpu->tcBase()); 990#endif 991} 992 993bool 994TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt) 995{ 996 if (pkt->isResponse() && !pkt->wasNacked()) { 997 // delay processing of returned data until next CPU clock edge 998 Tick next_tick = cpu->nextCycle(curTick()); 999 1000 if (next_tick == curTick()) { 1001 cpu->completeDataAccess(pkt); 1002 } else { 1003 if (!tickEvent.scheduled()) { 1004 tickEvent.schedule(pkt, next_tick); 1005 } else { 1006 // In the case of a split transaction and a cache that is 1007 // faster than a CPU we could get two responses before 1008 // next_tick expires 1009 if (!retryEvent.scheduled()) 1010 schedule(retryEvent, next_tick); 1011 return false; 1012 } 1013 } 1014 1015 return true; 1016 } 1017 else if (pkt->wasNacked()) { 1018 assert(cpu->_status == DcacheWaitResponse); 1019 pkt->reinitNacked(); 1020 if (!sendTiming(pkt)) { 1021 cpu->_status = DcacheRetry; 1022 cpu->dcache_pkt = pkt; 1023 } 1024 } 1025 //Snooping a Coherence Request, do nothing 1026 return true; 1027} 1028 1029void 1030TimingSimpleCPU::DcachePort::DTickEvent::process() 1031{ 1032 cpu->completeDataAccess(pkt); 1033} 1034 1035void 1036TimingSimpleCPU::DcachePort::recvRetry() 1037{ 1038 // we shouldn't get a retry unless we have a packet that we're 1039 // waiting to transmit 1040 assert(cpu->dcache_pkt != NULL); 1041 assert(cpu->_status == DcacheRetry); 1042 PacketPtr tmp = cpu->dcache_pkt; 1043 if (tmp->senderState) { 1044 // This is a packet from a split access. 1045 SplitFragmentSenderState * send_state = 1046 dynamic_cast<SplitFragmentSenderState *>(tmp->senderState); 1047 assert(send_state); 1048 PacketPtr big_pkt = send_state->bigPkt; 1049 1050 SplitMainSenderState * main_send_state = 1051 dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); 1052 assert(main_send_state); 1053 1054 if (sendTiming(tmp)) { 1055 // If we were able to send without retrying, record that fact 1056 // and try sending the other fragment. 1057 send_state->clearFromParent(); 1058 int other_index = main_send_state->getPendingFragment(); 1059 if (other_index > 0) { 1060 tmp = main_send_state->fragments[other_index]; 1061 cpu->dcache_pkt = tmp; 1062 if ((big_pkt->isRead() && cpu->handleReadPacket(tmp)) || 1063 (big_pkt->isWrite() && cpu->handleWritePacket())) { 1064 main_send_state->fragments[other_index] = NULL; 1065 } 1066 } else { 1067 cpu->_status = DcacheWaitResponse; 1068 // memory system takes ownership of packet 1069 cpu->dcache_pkt = NULL; 1070 } 1071 } 1072 } else if (sendTiming(tmp)) { 1073 cpu->_status = DcacheWaitResponse; 1074 // memory system takes ownership of packet 1075 cpu->dcache_pkt = NULL; 1076 } 1077} 1078 1079TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, 1080 Tick t) 1081 : pkt(_pkt), cpu(_cpu) 1082{ 1083 cpu->schedule(this, t); 1084} 1085 1086void 1087TimingSimpleCPU::IprEvent::process() 1088{ 1089 cpu->completeDataAccess(pkt); 1090} 1091 1092const char * 1093TimingSimpleCPU::IprEvent::description() const 1094{ 1095 return "Timing Simple CPU Delay IPR event"; 1096} 1097 1098 1099void 1100TimingSimpleCPU::printAddr(Addr a) 1101{ 1102 dcachePort.printAddr(a); 1103} 1104 1105 1106//////////////////////////////////////////////////////////////////////// 1107// 1108// TimingSimpleCPU Simulation Object 1109// 1110TimingSimpleCPU * 1111TimingSimpleCPUParams::create() 1112{ 1113 numThreads = 1; 1114#if !FULL_SYSTEM 1115 if (workload.size() != 1) 1116 panic("only one workload allowed"); 1117#endif 1118 return new TimingSimpleCPU(this); 1119} 1120