timing.cc revision 7745
1955SN/A/* 2955SN/A * Copyright (c) 2010 ARM Limited 31762SN/A * All rights reserved 4955SN/A * 5955SN/A * The license below extends only to copyright in the software and shall 6955SN/A * not be construed as granting a license to any other intellectual 7955SN/A * property including but not limited to intellectual property relating 8955SN/A * to a hardware implementation of the functionality of the software 9955SN/A * licensed hereunder. You may use the software subject to the license 10955SN/A * terms below provided that you ensure that this notice is replicated 11955SN/A * unmodified and in its entirety in all distributions of the software, 12955SN/A * modified or unmodified, in source code or in binary form. 13955SN/A * 14955SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 15955SN/A * All rights reserved. 16955SN/A * 17955SN/A * Redistribution and use in source and binary forms, with or without 18955SN/A * modification, are permitted provided that the following conditions are 19955SN/A * met: redistributions of source code must retain the above copyright 20955SN/A * notice, this list of conditions and the following disclaimer; 21955SN/A * redistributions in binary form must reproduce the above copyright 22955SN/A * notice, this list of conditions and the following disclaimer in the 23955SN/A * documentation and/or other materials provided with the distribution; 24955SN/A * neither the name of the copyright holders nor the names of its 25955SN/A * contributors may be used to endorse or promote products derived from 26955SN/A * this software without specific prior written permission. 27955SN/A * 282665Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 292665Ssaidi@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30955SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31955SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32955SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33955SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34955SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 352632Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 362632Sstever@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 372632Sstever@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 382632Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39955SN/A * 402632Sstever@eecs.umich.edu * Authors: Steve Reinhardt 412632Sstever@eecs.umich.edu */ 422761Sstever@eecs.umich.edu 432632Sstever@eecs.umich.edu#include "arch/locked_mem.hh" 442632Sstever@eecs.umich.edu#include "arch/mmaped_ipr.hh" 452632Sstever@eecs.umich.edu#include "arch/utility.hh" 462761Sstever@eecs.umich.edu#include "base/bigint.hh" 472761Sstever@eecs.umich.edu#include "config/the_isa.hh" 482761Sstever@eecs.umich.edu#include "cpu/exetrace.hh" 492632Sstever@eecs.umich.edu#include "cpu/simple/timing.hh" 502632Sstever@eecs.umich.edu#include "mem/packet.hh" 512761Sstever@eecs.umich.edu#include "mem/packet_access.hh" 522761Sstever@eecs.umich.edu#include "params/TimingSimpleCPU.hh" 532761Sstever@eecs.umich.edu#include "sim/faults.hh" 542761Sstever@eecs.umich.edu#include "sim/system.hh" 552761Sstever@eecs.umich.edu 562632Sstever@eecs.umich.eduusing namespace std; 572632Sstever@eecs.umich.eduusing namespace TheISA; 582632Sstever@eecs.umich.edu 592632Sstever@eecs.umich.eduPort * 602632Sstever@eecs.umich.eduTimingSimpleCPU::getPort(const std::string &if_name, int idx) 612632Sstever@eecs.umich.edu{ 622632Sstever@eecs.umich.edu if (if_name == "dcache_port") 63955SN/A return &dcachePort; 64955SN/A else if (if_name == "icache_port") 65955SN/A return &icachePort; 66955SN/A else 67955SN/A panic("No Such Port\n"); 683918Ssaidi@eecs.umich.edu} 694202Sbinkertn@umich.edu 704678Snate@binkert.orgvoid 71955SN/ATimingSimpleCPU::init() 722656Sstever@eecs.umich.edu{ 732656Sstever@eecs.umich.edu BaseCPU::init(); 742656Sstever@eecs.umich.edu#if FULL_SYSTEM 752656Sstever@eecs.umich.edu for (int i = 0; i < threadContexts.size(); ++i) { 762656Sstever@eecs.umich.edu ThreadContext *tc = threadContexts[i]; 772656Sstever@eecs.umich.edu 782656Sstever@eecs.umich.edu // initialize CPU, including PC 792653Sstever@eecs.umich.edu TheISA::initCPU(tc, _cpuId); 802653Sstever@eecs.umich.edu } 812653Sstever@eecs.umich.edu#endif 822653Sstever@eecs.umich.edu} 832653Sstever@eecs.umich.edu 842653Sstever@eecs.umich.eduTick 852653Sstever@eecs.umich.eduTimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) 862653Sstever@eecs.umich.edu{ 872653Sstever@eecs.umich.edu panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 882653Sstever@eecs.umich.edu return curTick; 894781Snate@binkert.org} 901852SN/A 91955SN/Avoid 92955SN/ATimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) 93955SN/A{ 943717Sstever@eecs.umich.edu //No internal storage to update, jusst return 953716Sstever@eecs.umich.edu return; 96955SN/A} 971533SN/A 983716Sstever@eecs.umich.eduvoid 991533SN/ATimingSimpleCPU::CpuPort::recvStatusChange(Status status) 1004678Snate@binkert.org{ 1014678Snate@binkert.org if (status == RangeChange) { 1024678Snate@binkert.org if (!snoopRangeSent) { 1034678Snate@binkert.org snoopRangeSent = true; 1044678Snate@binkert.org sendStatusChange(Port::RangeChange); 1054678Snate@binkert.org } 1064678Snate@binkert.org return; 1074678Snate@binkert.org } 1084678Snate@binkert.org 1094678Snate@binkert.org panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); 1104678Snate@binkert.org} 1114678Snate@binkert.org 1124678Snate@binkert.org 1134678Snate@binkert.orgvoid 1144678Snate@binkert.orgTimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) 1154678Snate@binkert.org{ 1164678Snate@binkert.org pkt = _pkt; 1174678Snate@binkert.org cpu->schedule(this, t); 1184678Snate@binkert.org} 1194678Snate@binkert.org 1204678Snate@binkert.orgTimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) 1214678Snate@binkert.org : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this, p->clock), 1224678Snate@binkert.org dcachePort(this, p->clock), fetchEvent(this) 1234678Snate@binkert.org{ 1244678Snate@binkert.org _status = Idle; 1254678Snate@binkert.org 1264678Snate@binkert.org icachePort.snoopRangeSent = false; 1274678Snate@binkert.org dcachePort.snoopRangeSent = false; 128955SN/A 129955SN/A ifetch_pkt = dcache_pkt = NULL; 1302632Sstever@eecs.umich.edu drainEvent = NULL; 1312632Sstever@eecs.umich.edu previousTick = 0; 132955SN/A changeState(SimObject::Running); 133955SN/A} 134955SN/A 135955SN/A 1362632Sstever@eecs.umich.eduTimingSimpleCPU::~TimingSimpleCPU() 137955SN/A{ 1382632Sstever@eecs.umich.edu} 1392632Sstever@eecs.umich.edu 1402632Sstever@eecs.umich.eduvoid 1412632Sstever@eecs.umich.eduTimingSimpleCPU::serialize(ostream &os) 1422632Sstever@eecs.umich.edu{ 1432632Sstever@eecs.umich.edu SimObject::State so_state = SimObject::getState(); 1442632Sstever@eecs.umich.edu SERIALIZE_ENUM(so_state); 1453053Sstever@eecs.umich.edu BaseSimpleCPU::serialize(os); 1463053Sstever@eecs.umich.edu} 1473053Sstever@eecs.umich.edu 1483053Sstever@eecs.umich.eduvoid 1493053Sstever@eecs.umich.eduTimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 1503053Sstever@eecs.umich.edu{ 1513053Sstever@eecs.umich.edu SimObject::State so_state; 1523053Sstever@eecs.umich.edu UNSERIALIZE_ENUM(so_state); 1533053Sstever@eecs.umich.edu BaseSimpleCPU::unserialize(cp, section); 1543053Sstever@eecs.umich.edu} 1553053Sstever@eecs.umich.edu 1563053Sstever@eecs.umich.eduunsigned int 1573053Sstever@eecs.umich.eduTimingSimpleCPU::drain(Event *drain_event) 1583053Sstever@eecs.umich.edu{ 1593053Sstever@eecs.umich.edu // TimingSimpleCPU is ready to drain if it's not waiting for 1603053Sstever@eecs.umich.edu // an access to complete. 1612632Sstever@eecs.umich.edu if (_status == Idle || _status == Running || _status == SwitchedOut) { 1622632Sstever@eecs.umich.edu changeState(SimObject::Drained); 1632632Sstever@eecs.umich.edu return 0; 1642632Sstever@eecs.umich.edu } else { 1652632Sstever@eecs.umich.edu changeState(SimObject::Draining); 1662632Sstever@eecs.umich.edu drainEvent = drain_event; 1673718Sstever@eecs.umich.edu return 1; 1683718Sstever@eecs.umich.edu } 1693718Sstever@eecs.umich.edu} 1703718Sstever@eecs.umich.edu 1713718Sstever@eecs.umich.eduvoid 1723718Sstever@eecs.umich.eduTimingSimpleCPU::resume() 1733718Sstever@eecs.umich.edu{ 1743718Sstever@eecs.umich.edu DPRINTF(SimpleCPU, "Resume\n"); 1753718Sstever@eecs.umich.edu if (_status != SwitchedOut && _status != Idle) { 1763718Sstever@eecs.umich.edu assert(system->getMemoryMode() == Enums::timing); 1773718Sstever@eecs.umich.edu 1783718Sstever@eecs.umich.edu if (fetchEvent.scheduled()) 1793718Sstever@eecs.umich.edu deschedule(fetchEvent); 1802634Sstever@eecs.umich.edu 1812634Sstever@eecs.umich.edu schedule(fetchEvent, nextCycle()); 1822632Sstever@eecs.umich.edu } 1832638Sstever@eecs.umich.edu 1842632Sstever@eecs.umich.edu changeState(SimObject::Running); 1852632Sstever@eecs.umich.edu} 1862632Sstever@eecs.umich.edu 1872632Sstever@eecs.umich.eduvoid 1882632Sstever@eecs.umich.eduTimingSimpleCPU::switchOut() 1892632Sstever@eecs.umich.edu{ 1901858SN/A assert(_status == Running || _status == Idle); 1913716Sstever@eecs.umich.edu _status = SwitchedOut; 1922638Sstever@eecs.umich.edu numCycles += tickToCycles(curTick - previousTick); 1932638Sstever@eecs.umich.edu 1942638Sstever@eecs.umich.edu // If we've been scheduled to resume but are then told to switch out, 1952638Sstever@eecs.umich.edu // we'll need to cancel it. 1962638Sstever@eecs.umich.edu if (fetchEvent.scheduled()) 1972638Sstever@eecs.umich.edu deschedule(fetchEvent); 1982638Sstever@eecs.umich.edu} 1993716Sstever@eecs.umich.edu 2002634Sstever@eecs.umich.edu 2012634Sstever@eecs.umich.eduvoid 202955SN/ATimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 203955SN/A{ 204955SN/A BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort); 205955SN/A 206955SN/A // if any of this CPU's ThreadContexts are active, mark the CPU as 207955SN/A // running and schedule its tick event. 208955SN/A for (int i = 0; i < threadContexts.size(); ++i) { 209955SN/A ThreadContext *tc = threadContexts[i]; 2101858SN/A if (tc->status() == ThreadContext::Active && _status != Running) { 2111858SN/A _status = Running; 2122632Sstever@eecs.umich.edu break; 213955SN/A } 2144781Snate@binkert.org } 2153643Ssaidi@eecs.umich.edu 2163643Ssaidi@eecs.umich.edu if (_status != Running) { 2173643Ssaidi@eecs.umich.edu _status = Idle; 2183643Ssaidi@eecs.umich.edu } 2193643Ssaidi@eecs.umich.edu assert(threadContexts.size() == 1); 2203643Ssaidi@eecs.umich.edu previousTick = curTick; 2213643Ssaidi@eecs.umich.edu} 2224494Ssaidi@eecs.umich.edu 2234494Ssaidi@eecs.umich.edu 2243716Sstever@eecs.umich.eduvoid 2251105SN/ATimingSimpleCPU::activateContext(int thread_num, int delay) 2262667Sstever@eecs.umich.edu{ 2272667Sstever@eecs.umich.edu DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay); 2282667Sstever@eecs.umich.edu 2292667Sstever@eecs.umich.edu assert(thread_num == 0); 2302667Sstever@eecs.umich.edu assert(thread); 2312667Sstever@eecs.umich.edu 2321869SN/A assert(_status == Idle); 2331869SN/A 2341869SN/A notIdleFraction++; 2351869SN/A _status = Running; 2361869SN/A 2371065SN/A // kick things off by initiating the fetch of the next instruction 2382632Sstever@eecs.umich.edu schedule(fetchEvent, nextCycle(curTick + ticks(delay))); 2392632Sstever@eecs.umich.edu} 2403918Ssaidi@eecs.umich.edu 2413918Ssaidi@eecs.umich.edu 2423940Ssaidi@eecs.umich.eduvoid 2434781Snate@binkert.orgTimingSimpleCPU::suspendContext(int thread_num) 2444781Snate@binkert.org{ 2453918Ssaidi@eecs.umich.edu DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num); 2464781Snate@binkert.org 2474781Snate@binkert.org assert(thread_num == 0); 2483918Ssaidi@eecs.umich.edu assert(thread); 2494781Snate@binkert.org 2504781Snate@binkert.org if (_status == Idle) 2513940Ssaidi@eecs.umich.edu return; 2523942Ssaidi@eecs.umich.edu 2533940Ssaidi@eecs.umich.edu assert(_status == Running); 2543918Ssaidi@eecs.umich.edu 2553918Ssaidi@eecs.umich.edu // just change status to Idle... if status != Running, 256955SN/A // completeInst() will not initiate fetch of next instruction. 2571858SN/A 2583918Ssaidi@eecs.umich.edu notIdleFraction--; 2593918Ssaidi@eecs.umich.edu _status = Idle; 2603918Ssaidi@eecs.umich.edu} 2613918Ssaidi@eecs.umich.edu 2623940Ssaidi@eecs.umich.edubool 2633940Ssaidi@eecs.umich.eduTimingSimpleCPU::handleReadPacket(PacketPtr pkt) 2643918Ssaidi@eecs.umich.edu{ 2653918Ssaidi@eecs.umich.edu RequestPtr req = pkt->req; 2663918Ssaidi@eecs.umich.edu if (req->isMmapedIpr()) { 2673918Ssaidi@eecs.umich.edu Tick delay; 2683918Ssaidi@eecs.umich.edu delay = TheISA::handleIprRead(thread->getTC(), pkt); 2693918Ssaidi@eecs.umich.edu new IprEvent(pkt, this, nextCycle(curTick + delay)); 2703918Ssaidi@eecs.umich.edu _status = DcacheWaitResponse; 2713918Ssaidi@eecs.umich.edu dcache_pkt = NULL; 2723918Ssaidi@eecs.umich.edu } else if (!dcachePort.sendTiming(pkt)) { 2733940Ssaidi@eecs.umich.edu _status = DcacheRetry; 2743918Ssaidi@eecs.umich.edu dcache_pkt = pkt; 2753918Ssaidi@eecs.umich.edu } else { 2761851SN/A _status = DcacheWaitResponse; 2771851SN/A // memory system takes ownership of packet 2781858SN/A dcache_pkt = NULL; 2792632Sstever@eecs.umich.edu } 280955SN/A return dcache_pkt == NULL; 2813053Sstever@eecs.umich.edu} 2823053Sstever@eecs.umich.edu 2833053Sstever@eecs.umich.eduvoid 2843053Sstever@eecs.umich.eduTimingSimpleCPU::sendData(RequestPtr req, uint8_t *data, uint64_t *res, 2853053Sstever@eecs.umich.edu bool read) 2863053Sstever@eecs.umich.edu{ 2873053Sstever@eecs.umich.edu PacketPtr pkt; 2883053Sstever@eecs.umich.edu buildPacket(pkt, req, read); 2893053Sstever@eecs.umich.edu pkt->dataDynamicArray<uint8_t>(data); 2904742Sstever@eecs.umich.edu if (req->getFlags().isSet(Request::NO_ACCESS)) { 2914742Sstever@eecs.umich.edu assert(!dcache_pkt); 2923053Sstever@eecs.umich.edu pkt->makeResponse(); 2933053Sstever@eecs.umich.edu completeDataAccess(pkt); 2943053Sstever@eecs.umich.edu } else if (read) { 2953053Sstever@eecs.umich.edu handleReadPacket(pkt); 2963053Sstever@eecs.umich.edu } else { 2973053Sstever@eecs.umich.edu bool do_access = true; // flag to suppress cache access 2983053Sstever@eecs.umich.edu 2993053Sstever@eecs.umich.edu if (req->isLLSC()) { 3003053Sstever@eecs.umich.edu do_access = TheISA::handleLockedWrite(thread, req); 3012667Sstever@eecs.umich.edu } else if (req->isCondSwap()) { 3024554Sbinkertn@umich.edu assert(res); 3034554Sbinkertn@umich.edu req->setExtraData(*res); 3042667Sstever@eecs.umich.edu } 3054554Sbinkertn@umich.edu 3064554Sbinkertn@umich.edu if (do_access) { 3074554Sbinkertn@umich.edu dcache_pkt = pkt; 3084554Sbinkertn@umich.edu handleWritePacket(); 3094554Sbinkertn@umich.edu } else { 3104554Sbinkertn@umich.edu _status = DcacheWaitResponse; 3114554Sbinkertn@umich.edu completeDataAccess(pkt); 3124781Snate@binkert.org } 3134554Sbinkertn@umich.edu } 3144554Sbinkertn@umich.edu} 3152667Sstever@eecs.umich.edu 3164554Sbinkertn@umich.eduvoid 3174554Sbinkertn@umich.eduTimingSimpleCPU::sendSplitData(RequestPtr req1, RequestPtr req2, 3184554Sbinkertn@umich.edu RequestPtr req, uint8_t *data, bool read) 3194554Sbinkertn@umich.edu{ 3202667Sstever@eecs.umich.edu PacketPtr pkt1, pkt2; 3214554Sbinkertn@umich.edu buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read); 3222667Sstever@eecs.umich.edu if (req->getFlags().isSet(Request::NO_ACCESS)) { 3234554Sbinkertn@umich.edu assert(!dcache_pkt); 3244554Sbinkertn@umich.edu pkt1->makeResponse(); 3252667Sstever@eecs.umich.edu completeDataAccess(pkt1); 3262638Sstever@eecs.umich.edu } else if (read) { 3272638Sstever@eecs.umich.edu if (handleReadPacket(pkt1)) { 3282638Sstever@eecs.umich.edu SplitFragmentSenderState * send_state = 3293716Sstever@eecs.umich.edu dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 3303716Sstever@eecs.umich.edu send_state->clearFromParent(); 3311858SN/A if (handleReadPacket(pkt2)) { 3323118Sstever@eecs.umich.edu send_state = dynamic_cast<SplitFragmentSenderState *>( 3333118Sstever@eecs.umich.edu pkt1->senderState); 3343118Sstever@eecs.umich.edu send_state->clearFromParent(); 3353118Sstever@eecs.umich.edu } 3363118Sstever@eecs.umich.edu } 3373118Sstever@eecs.umich.edu } else { 3383118Sstever@eecs.umich.edu dcache_pkt = pkt1; 3393118Sstever@eecs.umich.edu if (handleWritePacket()) { 3403118Sstever@eecs.umich.edu SplitFragmentSenderState * send_state = 3413118Sstever@eecs.umich.edu dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 3423118Sstever@eecs.umich.edu send_state->clearFromParent(); 3433716Sstever@eecs.umich.edu dcache_pkt = pkt2; 3443118Sstever@eecs.umich.edu if (handleWritePacket()) { 3453118Sstever@eecs.umich.edu send_state = dynamic_cast<SplitFragmentSenderState *>( 3463118Sstever@eecs.umich.edu pkt1->senderState); 3473118Sstever@eecs.umich.edu send_state->clearFromParent(); 3483118Sstever@eecs.umich.edu } 3493118Sstever@eecs.umich.edu } 3503118Sstever@eecs.umich.edu } 3513118Sstever@eecs.umich.edu} 3523118Sstever@eecs.umich.edu 3533716Sstever@eecs.umich.eduvoid 3543118Sstever@eecs.umich.eduTimingSimpleCPU::translationFault(Fault fault) 3553118Sstever@eecs.umich.edu{ 3563118Sstever@eecs.umich.edu // fault may be NoFault in cases where a fault is suppressed, 3573118Sstever@eecs.umich.edu // for instance prefetches. 3583118Sstever@eecs.umich.edu numCycles += tickToCycles(curTick - previousTick); 3593118Sstever@eecs.umich.edu previousTick = curTick; 3603118Sstever@eecs.umich.edu 3613118Sstever@eecs.umich.edu if (traceData) { 3623118Sstever@eecs.umich.edu // Since there was a fault, we shouldn't trace this instruction. 3633118Sstever@eecs.umich.edu delete traceData; 3643483Ssaidi@eecs.umich.edu traceData = NULL; 3653494Ssaidi@eecs.umich.edu } 3663494Ssaidi@eecs.umich.edu 3673483Ssaidi@eecs.umich.edu postExecute(); 3683483Ssaidi@eecs.umich.edu 3693483Ssaidi@eecs.umich.edu if (getState() == SimObject::Draining) { 3703053Sstever@eecs.umich.edu advancePC(fault); 3713053Sstever@eecs.umich.edu completeDrain(); 3723918Ssaidi@eecs.umich.edu } else { 3733053Sstever@eecs.umich.edu advanceInst(fault); 3743053Sstever@eecs.umich.edu } 3753053Sstever@eecs.umich.edu} 3763053Sstever@eecs.umich.edu 3773053Sstever@eecs.umich.eduvoid 3781858SN/ATimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr req, bool read) 3791858SN/A{ 3801858SN/A MemCmd cmd; 3811858SN/A if (read) { 3821858SN/A cmd = MemCmd::ReadReq; 3831858SN/A if (req->isLLSC()) 3841859SN/A cmd = MemCmd::LoadLockedReq; 3851858SN/A } else { 3861858SN/A cmd = MemCmd::WriteReq; 3871858SN/A if (req->isLLSC()) { 3881859SN/A cmd = MemCmd::StoreCondReq; 3891859SN/A } else if (req->isSwap()) { 3901862SN/A cmd = MemCmd::SwapReq; 3913053Sstever@eecs.umich.edu } 3923053Sstever@eecs.umich.edu } 3933053Sstever@eecs.umich.edu pkt = new Packet(req, cmd, Packet::Broadcast); 3943053Sstever@eecs.umich.edu} 3951859SN/A 3961859SN/Avoid 3971859SN/ATimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, 3981859SN/A RequestPtr req1, RequestPtr req2, RequestPtr req, 3991859SN/A uint8_t *data, bool read) 4001859SN/A{ 4011859SN/A pkt1 = pkt2 = NULL; 4021859SN/A 4031862SN/A assert(!req1->isMmapedIpr() && !req2->isMmapedIpr()); 4041859SN/A 4051859SN/A if (req->getFlags().isSet(Request::NO_ACCESS)) { 4061859SN/A buildPacket(pkt1, req, read); 4071858SN/A return; 4081858SN/A } 4092139SN/A 4104202Sbinkertn@umich.edu buildPacket(pkt1, req1, read); 4114202Sbinkertn@umich.edu buildPacket(pkt2, req2, read); 4122139SN/A 4132155SN/A req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags()); 4144202Sbinkertn@umich.edu PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(), 4154202Sbinkertn@umich.edu Packet::Broadcast); 4164202Sbinkertn@umich.edu 4172155SN/A pkt->dataDynamicArray<uint8_t>(data); 4181869SN/A pkt1->dataStatic<uint8_t>(data); 4191869SN/A pkt2->dataStatic<uint8_t>(data + req1->getSize()); 4201869SN/A 4211869SN/A SplitMainSenderState * main_send_state = new SplitMainSenderState; 4224202Sbinkertn@umich.edu pkt->senderState = main_send_state; 4234202Sbinkertn@umich.edu main_send_state->fragments[0] = pkt1; 4244202Sbinkertn@umich.edu main_send_state->fragments[1] = pkt2; 4254202Sbinkertn@umich.edu main_send_state->outstanding = 2; 4264202Sbinkertn@umich.edu pkt1->senderState = new SplitFragmentSenderState(pkt, 0); 4274202Sbinkertn@umich.edu pkt2->senderState = new SplitFragmentSenderState(pkt, 1); 4284202Sbinkertn@umich.edu} 4294202Sbinkertn@umich.edu 4304202Sbinkertn@umich.eduFault 4314202Sbinkertn@umich.eduTimingSimpleCPU::readBytes(Addr addr, uint8_t *data, 4324202Sbinkertn@umich.edu unsigned size, unsigned flags) 4334202Sbinkertn@umich.edu{ 4344202Sbinkertn@umich.edu Fault fault; 4354202Sbinkertn@umich.edu const int asid = 0; 4364202Sbinkertn@umich.edu const ThreadID tid = 0; 4374202Sbinkertn@umich.edu const Addr pc = thread->instAddr(); 4384773Snate@binkert.org unsigned block_size = dcachePort.peerBlockSize(); 4394775Snate@binkert.org BaseTLB::Mode mode = BaseTLB::Read; 4404775Snate@binkert.org 4414773Snate@binkert.org if (traceData) { 4424773Snate@binkert.org traceData->setAddr(addr); 4434773Snate@binkert.org } 4444773Snate@binkert.org 4454773Snate@binkert.org RequestPtr req = new Request(asid, addr, size, 4464773Snate@binkert.org flags, pc, _cpuId, tid); 4471869SN/A 4484202Sbinkertn@umich.edu Addr split_addr = roundDown(addr + size - 1, block_size); 4491869SN/A assert(split_addr <= addr || split_addr - addr < block_size); 4502508SN/A 4512508SN/A _status = DTBWaitResponse; 4522508SN/A if (split_addr > addr) { 4532508SN/A RequestPtr req1, req2; 4544202Sbinkertn@umich.edu assert(!req->isLLSC() && !req->isSwap()); 4551869SN/A req->splitOnVaddr(split_addr, req1, req2); 4561869SN/A 4571869SN/A WholeTranslationState *state = 4581869SN/A new WholeTranslationState(req, req1, req2, new uint8_t[size], 4591869SN/A NULL, mode); 4601869SN/A DataTranslation<TimingSimpleCPU> *trans1 = 4611965SN/A new DataTranslation<TimingSimpleCPU>(this, state, 0); 4621965SN/A DataTranslation<TimingSimpleCPU> *trans2 = 4631965SN/A new DataTranslation<TimingSimpleCPU>(this, state, 1); 4641869SN/A 4651869SN/A thread->dtb->translateTiming(req1, tc, trans1, mode); 4662733Sktlim@umich.edu thread->dtb->translateTiming(req2, tc, trans2, mode); 4671869SN/A } else { 4681884SN/A WholeTranslationState *state = 4691884SN/A new WholeTranslationState(req, new uint8_t[size], NULL, mode); 4703356Sbinkertn@umich.edu DataTranslation<TimingSimpleCPU> *translation 4713356Sbinkertn@umich.edu = new DataTranslation<TimingSimpleCPU>(this, state); 4723356Sbinkertn@umich.edu thread->dtb->translateTiming(req, tc, translation, mode); 4734773Snate@binkert.org } 4744773Snate@binkert.org 4754773Snate@binkert.org return NoFault; 4761869SN/A} 4771858SN/A 4781869SN/Atemplate <class T> 4791869SN/AFault 4801869SN/ATimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 4811858SN/A{ 4822761Sstever@eecs.umich.edu return readBytes(addr, (uint8_t *)&data, sizeof(T), flags); 4831869SN/A} 4842733Sktlim@umich.edu 4853584Ssaidi@eecs.umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS 4861869SN/A 4871869SN/Atemplate 4881869SN/AFault 4891869SN/ATimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags); 4901869SN/A 4911869SN/Atemplate 4921858SN/AFault 493955SN/ATimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags); 494955SN/A 4951869SN/Atemplate 4961869SN/AFault 4971869SN/ATimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 4981869SN/A 4991869SN/Atemplate 5001869SN/AFault 5011869SN/ATimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 5021869SN/A 5031869SN/Atemplate 5041869SN/AFault 5051869SN/ATimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 5061869SN/A 5071869SN/Atemplate 5081869SN/AFault 5091869SN/ATimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 5101869SN/A 5111869SN/A#endif //DOXYGEN_SHOULD_SKIP_THIS 5121869SN/A 5131869SN/Atemplate<> 5141869SN/AFault 5151869SN/ATimingSimpleCPU::read(Addr addr, double &data, unsigned flags) 5161869SN/A{ 5171869SN/A return read(addr, *(uint64_t*)&data, flags); 5181869SN/A} 5191869SN/A 5201869SN/Atemplate<> 5211869SN/AFault 5221869SN/ATimingSimpleCPU::read(Addr addr, float &data, unsigned flags) 5231869SN/A{ 5243716Sstever@eecs.umich.edu return read(addr, *(uint32_t*)&data, flags); 5253356Sbinkertn@umich.edu} 5263356Sbinkertn@umich.edu 5273356Sbinkertn@umich.edutemplate<> 5283356Sbinkertn@umich.eduFault 5293356Sbinkertn@umich.eduTimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 5303356Sbinkertn@umich.edu{ 5314781Snate@binkert.org return read(addr, (uint32_t&)data, flags); 5321869SN/A} 5331869SN/A 5341869SN/Abool 5351869SN/ATimingSimpleCPU::handleWritePacket() 5361869SN/A{ 5371869SN/A RequestPtr req = dcache_pkt->req; 5381869SN/A if (req->isMmapedIpr()) { 5392655Sstever@eecs.umich.edu Tick delay; 5402655Sstever@eecs.umich.edu delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); 5412655Sstever@eecs.umich.edu new IprEvent(dcache_pkt, this, nextCycle(curTick + delay)); 5422655Sstever@eecs.umich.edu _status = DcacheWaitResponse; 5432655Sstever@eecs.umich.edu dcache_pkt = NULL; 5442655Sstever@eecs.umich.edu } else if (!dcachePort.sendTiming(dcache_pkt)) { 5452655Sstever@eecs.umich.edu _status = DcacheRetry; 5462655Sstever@eecs.umich.edu } else { 5472655Sstever@eecs.umich.edu _status = DcacheWaitResponse; 5482655Sstever@eecs.umich.edu // memory system takes ownership of packet 5492655Sstever@eecs.umich.edu dcache_pkt = NULL; 5502655Sstever@eecs.umich.edu } 5512655Sstever@eecs.umich.edu return dcache_pkt == NULL; 5522655Sstever@eecs.umich.edu} 5532655Sstever@eecs.umich.edu 5542655Sstever@eecs.umich.eduFault 5552655Sstever@eecs.umich.eduTimingSimpleCPU::writeTheseBytes(uint8_t *data, unsigned size, 5562655Sstever@eecs.umich.edu Addr addr, unsigned flags, uint64_t *res) 5572655Sstever@eecs.umich.edu{ 5582655Sstever@eecs.umich.edu const int asid = 0; 5592655Sstever@eecs.umich.edu const ThreadID tid = 0; 5602655Sstever@eecs.umich.edu const Addr pc = thread->instAddr(); 5612655Sstever@eecs.umich.edu unsigned block_size = dcachePort.peerBlockSize(); 5622655Sstever@eecs.umich.edu BaseTLB::Mode mode = BaseTLB::Write; 5632655Sstever@eecs.umich.edu 5642655Sstever@eecs.umich.edu if (traceData) { 5652634Sstever@eecs.umich.edu traceData->setAddr(addr); 5662634Sstever@eecs.umich.edu } 5672634Sstever@eecs.umich.edu 5682634Sstever@eecs.umich.edu RequestPtr req = new Request(asid, addr, size, 5692634Sstever@eecs.umich.edu flags, pc, _cpuId, tid); 5702634Sstever@eecs.umich.edu 5712638Sstever@eecs.umich.edu Addr split_addr = roundDown(addr + size - 1, block_size); 5722638Sstever@eecs.umich.edu assert(split_addr <= addr || split_addr - addr < block_size); 5733716Sstever@eecs.umich.edu 5742638Sstever@eecs.umich.edu _status = DTBWaitResponse; 5752638Sstever@eecs.umich.edu if (split_addr > addr) { 5761869SN/A RequestPtr req1, req2; 5771869SN/A assert(!req->isLLSC() && !req->isSwap()); 5783546Sgblack@eecs.umich.edu req->splitOnVaddr(split_addr, req1, req2); 5793546Sgblack@eecs.umich.edu 5803546Sgblack@eecs.umich.edu WholeTranslationState *state = 5813546Sgblack@eecs.umich.edu new WholeTranslationState(req, req1, req2, data, res, mode); 5824202Sbinkertn@umich.edu DataTranslation<TimingSimpleCPU> *trans1 = 5833546Sgblack@eecs.umich.edu new DataTranslation<TimingSimpleCPU>(this, state, 0); 5843546Sgblack@eecs.umich.edu DataTranslation<TimingSimpleCPU> *trans2 = 5853546Sgblack@eecs.umich.edu new DataTranslation<TimingSimpleCPU>(this, state, 1); 5863546Sgblack@eecs.umich.edu 5873546Sgblack@eecs.umich.edu thread->dtb->translateTiming(req1, tc, trans1, mode); 5884781Snate@binkert.org thread->dtb->translateTiming(req2, tc, trans2, mode); 5894781Snate@binkert.org } else { 5904781Snate@binkert.org WholeTranslationState *state = 5914781Snate@binkert.org new WholeTranslationState(req, data, res, mode); 5924781Snate@binkert.org DataTranslation<TimingSimpleCPU> *translation = 5934781Snate@binkert.org new DataTranslation<TimingSimpleCPU>(this, state); 5944781Snate@binkert.org thread->dtb->translateTiming(req, tc, translation, mode); 5954781Snate@binkert.org } 5964781Snate@binkert.org 5974781Snate@binkert.org // Translation faults will be returned via finishTranslation() 5984781Snate@binkert.org return NoFault; 5994781Snate@binkert.org} 6003546Sgblack@eecs.umich.edu 6013546Sgblack@eecs.umich.eduFault 6023546Sgblack@eecs.umich.eduTimingSimpleCPU::writeBytes(uint8_t *data, unsigned size, 6034781Snate@binkert.org Addr addr, unsigned flags, uint64_t *res) 6043546Sgblack@eecs.umich.edu{ 6053546Sgblack@eecs.umich.edu uint8_t *newData = new uint8_t[size]; 6063546Sgblack@eecs.umich.edu memcpy(newData, data, size); 6073546Sgblack@eecs.umich.edu return writeTheseBytes(newData, size, addr, flags, res); 6083546Sgblack@eecs.umich.edu} 6093546Sgblack@eecs.umich.edu 6103546Sgblack@eecs.umich.edutemplate <class T> 6113546Sgblack@eecs.umich.eduFault 6123546Sgblack@eecs.umich.eduTimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 6133546Sgblack@eecs.umich.edu{ 6144202Sbinkertn@umich.edu if (traceData) { 6153546Sgblack@eecs.umich.edu traceData->setData(data); 6163546Sgblack@eecs.umich.edu } 6173546Sgblack@eecs.umich.edu T *dataP = (T*) new uint8_t[sizeof(T)]; 618955SN/A *dataP = TheISA::htog(data); 619955SN/A 620955SN/A return writeTheseBytes((uint8_t *)dataP, sizeof(T), addr, flags, res); 621955SN/A} 6221858SN/A 6231858SN/A 6241858SN/A#ifndef DOXYGEN_SHOULD_SKIP_THIS 6252632Sstever@eecs.umich.edutemplate 6262632Sstever@eecs.umich.eduFault 6274773Snate@binkert.orgTimingSimpleCPU::write(Twin32_t data, Addr addr, 6284773Snate@binkert.org unsigned flags, uint64_t *res); 6292632Sstever@eecs.umich.edu 6302632Sstever@eecs.umich.edutemplate 6312632Sstever@eecs.umich.eduFault 6322634Sstever@eecs.umich.eduTimingSimpleCPU::write(Twin64_t data, Addr addr, 6332638Sstever@eecs.umich.edu unsigned flags, uint64_t *res); 6342023SN/A 6352632Sstever@eecs.umich.edutemplate 6362632Sstever@eecs.umich.eduFault 6372632Sstever@eecs.umich.eduTimingSimpleCPU::write(uint64_t data, Addr addr, 6382632Sstever@eecs.umich.edu unsigned flags, uint64_t *res); 6392632Sstever@eecs.umich.edu 6403716Sstever@eecs.umich.edutemplate 6412632Sstever@eecs.umich.eduFault 6422632Sstever@eecs.umich.eduTimingSimpleCPU::write(uint32_t data, Addr addr, 6432632Sstever@eecs.umich.edu unsigned flags, uint64_t *res); 6442632Sstever@eecs.umich.edu 6452632Sstever@eecs.umich.edutemplate 6462023SN/AFault 6472632Sstever@eecs.umich.eduTimingSimpleCPU::write(uint16_t data, Addr addr, 6482632Sstever@eecs.umich.edu unsigned flags, uint64_t *res); 6491889SN/A 6501889SN/Atemplate 6512632Sstever@eecs.umich.eduFault 6522632Sstever@eecs.umich.eduTimingSimpleCPU::write(uint8_t data, Addr addr, 6532632Sstever@eecs.umich.edu unsigned flags, uint64_t *res); 6542632Sstever@eecs.umich.edu 6553716Sstever@eecs.umich.edu#endif //DOXYGEN_SHOULD_SKIP_THIS 6563716Sstever@eecs.umich.edu 6572632Sstever@eecs.umich.edutemplate<> 6582632Sstever@eecs.umich.eduFault 6592632Sstever@eecs.umich.eduTimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 6602632Sstever@eecs.umich.edu{ 6612632Sstever@eecs.umich.edu return write(*(uint64_t*)&data, addr, flags, res); 6622632Sstever@eecs.umich.edu} 6632632Sstever@eecs.umich.edu 6642632Sstever@eecs.umich.edutemplate<> 6651888SN/AFault 6661888SN/ATimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 6671869SN/A{ 6681869SN/A return write(*(uint32_t*)&data, addr, flags, res); 6691858SN/A} 6702598SN/A 6712598SN/A 6722598SN/Atemplate<> 6732598SN/AFault 6742598SN/ATimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 6751858SN/A{ 6761858SN/A return write((uint32_t)data, addr, flags, res); 6771858SN/A} 6781858SN/A 6791858SN/A 6801858SN/Avoid 6811858SN/ATimingSimpleCPU::finishTranslation(WholeTranslationState *state) 6821858SN/A{ 6831858SN/A _status = Running; 6841871SN/A 6851858SN/A if (state->getFault() != NoFault) { 6861858SN/A if (state->isPrefetch()) { 6871858SN/A state->setNoFault(); 6881858SN/A } 6891858SN/A delete [] state->data; 6901858SN/A state->deleteReqs(); 6911858SN/A translationFault(state->getFault()); 6921858SN/A } else { 6931858SN/A if (!state->isSplit) { 6941858SN/A sendData(state->mainReq, state->data, state->res, 6951858SN/A state->mode == BaseTLB::Read); 6961859SN/A } else { 6971859SN/A sendSplitData(state->sreqLow, state->sreqHigh, state->mainReq, 6981869SN/A state->data, state->mode == BaseTLB::Read); 6991888SN/A } 7002632Sstever@eecs.umich.edu } 7011869SN/A 7021884SN/A delete state; 7031884SN/A} 7041884SN/A 7051884SN/A 7061884SN/Avoid 7071884SN/ATimingSimpleCPU::fetch() 7081965SN/A{ 7091965SN/A DPRINTF(SimpleCPU, "Fetch\n"); 7101965SN/A 7112761Sstever@eecs.umich.edu if (!curStaticInst || !curStaticInst->isDelayedCommit()) 7121869SN/A checkForInterrupts(); 7131869SN/A 7142632Sstever@eecs.umich.edu checkPcEventQueue(); 7152667Sstever@eecs.umich.edu 7161869SN/A TheISA::PCState pcState = thread->pcState(); 7171869SN/A bool needToFetch = !isRomMicroPC(pcState.microPC()) && !curMacroStaticInst; 7182929Sktlim@umich.edu 7192929Sktlim@umich.edu if (needToFetch) { 7203716Sstever@eecs.umich.edu Request *ifetch_req = new Request(); 7212929Sktlim@umich.edu ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0); 722955SN/A setupFetchRequest(ifetch_req); 7232598SN/A thread->itb->translateTiming(ifetch_req, tc, &fetchTranslation, 7242598SN/A BaseTLB::Execute); 7253546Sgblack@eecs.umich.edu } else { 726955SN/A _status = IcacheWaitResponse; 727955SN/A completeIfetch(NULL); 728955SN/A 7291530SN/A numCycles += tickToCycles(curTick - previousTick); 730955SN/A previousTick = curTick; 731955SN/A } 732955SN/A} 733 734 735void 736TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc) 737{ 738 if (fault == NoFault) { 739 ifetch_pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast); 740 ifetch_pkt->dataStatic(&inst); 741 742 if (!icachePort.sendTiming(ifetch_pkt)) { 743 // Need to wait for retry 744 _status = IcacheRetry; 745 } else { 746 // Need to wait for cache to respond 747 _status = IcacheWaitResponse; 748 // ownership of packet transferred to memory system 749 ifetch_pkt = NULL; 750 } 751 } else { 752 delete req; 753 // fetch fault: advance directly to next instruction (fault handler) 754 advanceInst(fault); 755 } 756 757 numCycles += tickToCycles(curTick - previousTick); 758 previousTick = curTick; 759} 760 761 762void 763TimingSimpleCPU::advanceInst(Fault fault) 764{ 765 if (fault != NoFault || !stayAtPC) 766 advancePC(fault); 767 768 if (_status == Running) { 769 // kick off fetch of next instruction... callback from icache 770 // response will cause that instruction to be executed, 771 // keeping the CPU running. 772 fetch(); 773 } 774} 775 776 777void 778TimingSimpleCPU::completeIfetch(PacketPtr pkt) 779{ 780 DPRINTF(SimpleCPU, "Complete ICache Fetch\n"); 781 782 // received a response from the icache: execute the received 783 // instruction 784 785 assert(!pkt || !pkt->isError()); 786 assert(_status == IcacheWaitResponse); 787 788 _status = Running; 789 790 numCycles += tickToCycles(curTick - previousTick); 791 previousTick = curTick; 792 793 if (getState() == SimObject::Draining) { 794 if (pkt) { 795 delete pkt->req; 796 delete pkt; 797 } 798 799 completeDrain(); 800 return; 801 } 802 803 preExecute(); 804 if (curStaticInst && curStaticInst->isMemRef()) { 805 // load or store: just send to dcache 806 Fault fault = curStaticInst->initiateAcc(this, traceData); 807 if (_status != Running) { 808 // instruction will complete in dcache response callback 809 assert(_status == DcacheWaitResponse || 810 _status == DcacheRetry || DTBWaitResponse); 811 assert(fault == NoFault); 812 } else { 813 if (fault != NoFault && traceData) { 814 // If there was a fault, we shouldn't trace this instruction. 815 delete traceData; 816 traceData = NULL; 817 } 818 819 postExecute(); 820 // @todo remove me after debugging with legion done 821 if (curStaticInst && (!curStaticInst->isMicroop() || 822 curStaticInst->isFirstMicroop())) 823 instCnt++; 824 advanceInst(fault); 825 } 826 } else if (curStaticInst) { 827 // non-memory instruction: execute completely now 828 Fault fault = curStaticInst->execute(this, traceData); 829 830 // keep an instruction count 831 if (fault == NoFault) 832 countInst(); 833 else if (traceData && !DTRACE(ExecFaulting)) { 834 delete traceData; 835 traceData = NULL; 836 } 837 838 postExecute(); 839 // @todo remove me after debugging with legion done 840 if (curStaticInst && (!curStaticInst->isMicroop() || 841 curStaticInst->isFirstMicroop())) 842 instCnt++; 843 advanceInst(fault); 844 } else { 845 advanceInst(NoFault); 846 } 847 848 if (pkt) { 849 delete pkt->req; 850 delete pkt; 851 } 852} 853 854void 855TimingSimpleCPU::IcachePort::ITickEvent::process() 856{ 857 cpu->completeIfetch(pkt); 858} 859 860bool 861TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt) 862{ 863 if (pkt->isResponse() && !pkt->wasNacked()) { 864 // delay processing of returned data until next CPU clock edge 865 Tick next_tick = cpu->nextCycle(curTick); 866 867 if (next_tick == curTick) 868 cpu->completeIfetch(pkt); 869 else 870 tickEvent.schedule(pkt, next_tick); 871 872 return true; 873 } 874 else if (pkt->wasNacked()) { 875 assert(cpu->_status == IcacheWaitResponse); 876 pkt->reinitNacked(); 877 if (!sendTiming(pkt)) { 878 cpu->_status = IcacheRetry; 879 cpu->ifetch_pkt = pkt; 880 } 881 } 882 //Snooping a Coherence Request, do nothing 883 return true; 884} 885 886void 887TimingSimpleCPU::IcachePort::recvRetry() 888{ 889 // we shouldn't get a retry unless we have a packet that we're 890 // waiting to transmit 891 assert(cpu->ifetch_pkt != NULL); 892 assert(cpu->_status == IcacheRetry); 893 PacketPtr tmp = cpu->ifetch_pkt; 894 if (sendTiming(tmp)) { 895 cpu->_status = IcacheWaitResponse; 896 cpu->ifetch_pkt = NULL; 897 } 898} 899 900void 901TimingSimpleCPU::completeDataAccess(PacketPtr pkt) 902{ 903 // received a response from the dcache: complete the load or store 904 // instruction 905 assert(!pkt->isError()); 906 assert(_status == DcacheWaitResponse || _status == DTBWaitResponse || 907 pkt->req->getFlags().isSet(Request::NO_ACCESS)); 908 909 numCycles += tickToCycles(curTick - previousTick); 910 previousTick = curTick; 911 912 if (pkt->senderState) { 913 SplitFragmentSenderState * send_state = 914 dynamic_cast<SplitFragmentSenderState *>(pkt->senderState); 915 assert(send_state); 916 delete pkt->req; 917 delete pkt; 918 PacketPtr big_pkt = send_state->bigPkt; 919 delete send_state; 920 921 SplitMainSenderState * main_send_state = 922 dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); 923 assert(main_send_state); 924 // Record the fact that this packet is no longer outstanding. 925 assert(main_send_state->outstanding != 0); 926 main_send_state->outstanding--; 927 928 if (main_send_state->outstanding) { 929 return; 930 } else { 931 delete main_send_state; 932 big_pkt->senderState = NULL; 933 pkt = big_pkt; 934 } 935 } 936 937 _status = Running; 938 939 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 940 941 // keep an instruction count 942 if (fault == NoFault) 943 countInst(); 944 else if (traceData) { 945 // If there was a fault, we shouldn't trace this instruction. 946 delete traceData; 947 traceData = NULL; 948 } 949 950 // the locked flag may be cleared on the response packet, so check 951 // pkt->req and not pkt to see if it was a load-locked 952 if (pkt->isRead() && pkt->req->isLLSC()) { 953 TheISA::handleLockedRead(thread, pkt->req); 954 } 955 956 delete pkt->req; 957 delete pkt; 958 959 postExecute(); 960 961 if (getState() == SimObject::Draining) { 962 advancePC(fault); 963 completeDrain(); 964 965 return; 966 } 967 968 advanceInst(fault); 969} 970 971 972void 973TimingSimpleCPU::completeDrain() 974{ 975 DPRINTF(Config, "Done draining\n"); 976 changeState(SimObject::Drained); 977 drainEvent->process(); 978} 979 980void 981TimingSimpleCPU::DcachePort::setPeer(Port *port) 982{ 983 Port::setPeer(port); 984 985#if FULL_SYSTEM 986 // Update the ThreadContext's memory ports (Functional/Virtual 987 // Ports) 988 cpu->tcBase()->connectMemPorts(cpu->tcBase()); 989#endif 990} 991 992bool 993TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt) 994{ 995 if (pkt->isResponse() && !pkt->wasNacked()) { 996 // delay processing of returned data until next CPU clock edge 997 Tick next_tick = cpu->nextCycle(curTick); 998 999 if (next_tick == curTick) { 1000 cpu->completeDataAccess(pkt); 1001 } else { 1002 if (!tickEvent.scheduled()) { 1003 tickEvent.schedule(pkt, next_tick); 1004 } else { 1005 // In the case of a split transaction and a cache that is 1006 // faster than a CPU we could get two responses before 1007 // next_tick expires 1008 if (!retryEvent.scheduled()) 1009 schedule(retryEvent, next_tick); 1010 return false; 1011 } 1012 } 1013 1014 return true; 1015 } 1016 else if (pkt->wasNacked()) { 1017 assert(cpu->_status == DcacheWaitResponse); 1018 pkt->reinitNacked(); 1019 if (!sendTiming(pkt)) { 1020 cpu->_status = DcacheRetry; 1021 cpu->dcache_pkt = pkt; 1022 } 1023 } 1024 //Snooping a Coherence Request, do nothing 1025 return true; 1026} 1027 1028void 1029TimingSimpleCPU::DcachePort::DTickEvent::process() 1030{ 1031 cpu->completeDataAccess(pkt); 1032} 1033 1034void 1035TimingSimpleCPU::DcachePort::recvRetry() 1036{ 1037 // we shouldn't get a retry unless we have a packet that we're 1038 // waiting to transmit 1039 assert(cpu->dcache_pkt != NULL); 1040 assert(cpu->_status == DcacheRetry); 1041 PacketPtr tmp = cpu->dcache_pkt; 1042 if (tmp->senderState) { 1043 // This is a packet from a split access. 1044 SplitFragmentSenderState * send_state = 1045 dynamic_cast<SplitFragmentSenderState *>(tmp->senderState); 1046 assert(send_state); 1047 PacketPtr big_pkt = send_state->bigPkt; 1048 1049 SplitMainSenderState * main_send_state = 1050 dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); 1051 assert(main_send_state); 1052 1053 if (sendTiming(tmp)) { 1054 // If we were able to send without retrying, record that fact 1055 // and try sending the other fragment. 1056 send_state->clearFromParent(); 1057 int other_index = main_send_state->getPendingFragment(); 1058 if (other_index > 0) { 1059 tmp = main_send_state->fragments[other_index]; 1060 cpu->dcache_pkt = tmp; 1061 if ((big_pkt->isRead() && cpu->handleReadPacket(tmp)) || 1062 (big_pkt->isWrite() && cpu->handleWritePacket())) { 1063 main_send_state->fragments[other_index] = NULL; 1064 } 1065 } else { 1066 cpu->_status = DcacheWaitResponse; 1067 // memory system takes ownership of packet 1068 cpu->dcache_pkt = NULL; 1069 } 1070 } 1071 } else if (sendTiming(tmp)) { 1072 cpu->_status = DcacheWaitResponse; 1073 // memory system takes ownership of packet 1074 cpu->dcache_pkt = NULL; 1075 } 1076} 1077 1078TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, 1079 Tick t) 1080 : pkt(_pkt), cpu(_cpu) 1081{ 1082 cpu->schedule(this, t); 1083} 1084 1085void 1086TimingSimpleCPU::IprEvent::process() 1087{ 1088 cpu->completeDataAccess(pkt); 1089} 1090 1091const char * 1092TimingSimpleCPU::IprEvent::description() const 1093{ 1094 return "Timing Simple CPU Delay IPR event"; 1095} 1096 1097 1098void 1099TimingSimpleCPU::printAddr(Addr a) 1100{ 1101 dcachePort.printAddr(a); 1102} 1103 1104 1105//////////////////////////////////////////////////////////////////////// 1106// 1107// TimingSimpleCPU Simulation Object 1108// 1109TimingSimpleCPU * 1110TimingSimpleCPUParams::create() 1111{ 1112 numThreads = 1; 1113#if !FULL_SYSTEM 1114 if (workload.size() != 1) 1115 panic("only one workload allowed"); 1116#endif 1117 return new TimingSimpleCPU(this); 1118} 1119