timing.cc revision 13652
1955SN/A/* 2955SN/A * Copyright 2014 Google, Inc. 31762SN/A * Copyright (c) 2010-2013,2015,2017 ARM Limited 4955SN/A * All rights reserved 5955SN/A * 6955SN/A * The license below extends only to copyright in the software and shall 7955SN/A * not be construed as granting a license to any other intellectual 8955SN/A * property including but not limited to intellectual property relating 9955SN/A * to a hardware implementation of the functionality of the software 10955SN/A * licensed hereunder. You may use the software subject to the license 11955SN/A * terms below provided that you ensure that this notice is replicated 12955SN/A * unmodified and in its entirety in all distributions of the software, 13955SN/A * modified or unmodified, in source code or in binary form. 14955SN/A * 15955SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 16955SN/A * All rights reserved. 17955SN/A * 18955SN/A * Redistribution and use in source and binary forms, with or without 19955SN/A * modification, are permitted provided that the following conditions are 20955SN/A * met: redistributions of source code must retain the above copyright 21955SN/A * notice, this list of conditions and the following disclaimer; 22955SN/A * redistributions in binary form must reproduce the above copyright 23955SN/A * notice, this list of conditions and the following disclaimer in the 24955SN/A * documentation and/or other materials provided with the distribution; 25955SN/A * neither the name of the copyright holders nor the names of its 26955SN/A * contributors may be used to endorse or promote products derived from 27955SN/A * this software without specific prior written permission. 282665Ssaidi@eecs.umich.edu * 292665Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30955SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31955SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 32955SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33955SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34955SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 352632Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 362632Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 372632Sstever@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 382632Sstever@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39955SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 402632Sstever@eecs.umich.edu * 412632Sstever@eecs.umich.edu * Authors: Steve Reinhardt 422761Sstever@eecs.umich.edu */ 432632Sstever@eecs.umich.edu 442632Sstever@eecs.umich.edu#include "cpu/simple/timing.hh" 452632Sstever@eecs.umich.edu 462761Sstever@eecs.umich.edu#include "arch/locked_mem.hh" 472761Sstever@eecs.umich.edu#include "arch/mmapped_ipr.hh" 482761Sstever@eecs.umich.edu#include "arch/utility.hh" 492632Sstever@eecs.umich.edu#include "config/the_isa.hh" 502632Sstever@eecs.umich.edu#include "cpu/exetrace.hh" 512761Sstever@eecs.umich.edu#include "debug/Config.hh" 522761Sstever@eecs.umich.edu#include "debug/Drain.hh" 532761Sstever@eecs.umich.edu#include "debug/ExecFaulting.hh" 542761Sstever@eecs.umich.edu#include "debug/Mwait.hh" 552761Sstever@eecs.umich.edu#include "debug/SimpleCPU.hh" 562632Sstever@eecs.umich.edu#include "mem/packet.hh" 572632Sstever@eecs.umich.edu#include "mem/packet_access.hh" 582632Sstever@eecs.umich.edu#include "params/TimingSimpleCPU.hh" 592632Sstever@eecs.umich.edu#include "sim/faults.hh" 602632Sstever@eecs.umich.edu#include "sim/full_system.hh" 612632Sstever@eecs.umich.edu#include "sim/system.hh" 622632Sstever@eecs.umich.edu 63955SN/Ausing namespace std; 64955SN/Ausing namespace TheISA; 65955SN/A 66955SN/Avoid 67955SN/ATimingSimpleCPU::init() 685396Ssaidi@eecs.umich.edu{ 694202Sbinkertn@umich.edu BaseSimpleCPU::init(); 705342Sstever@gmail.com} 71955SN/A 725273Sstever@gmail.comvoid 735273Sstever@gmail.comTimingSimpleCPU::TimingCPUPort::TickEvent::schedule(PacketPtr _pkt, Tick t) 742656Sstever@eecs.umich.edu{ 752656Sstever@eecs.umich.edu pkt = _pkt; 762656Sstever@eecs.umich.edu cpu->schedule(this, t); 772656Sstever@eecs.umich.edu} 782656Sstever@eecs.umich.edu 792656Sstever@eecs.umich.eduTimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) 802656Sstever@eecs.umich.edu : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this), 812653Sstever@eecs.umich.edu dcachePort(this), ifetch_pkt(NULL), dcache_pkt(NULL), previousCycle(0), 825227Ssaidi@eecs.umich.edu fetchEvent([this]{ fetch(); }, name()) 835227Ssaidi@eecs.umich.edu{ 845227Ssaidi@eecs.umich.edu _status = Idle; 855227Ssaidi@eecs.umich.edu} 865396Ssaidi@eecs.umich.edu 875396Ssaidi@eecs.umich.edu 885396Ssaidi@eecs.umich.edu 895396Ssaidi@eecs.umich.eduTimingSimpleCPU::~TimingSimpleCPU() 905396Ssaidi@eecs.umich.edu{ 915396Ssaidi@eecs.umich.edu} 925396Ssaidi@eecs.umich.edu 935396Ssaidi@eecs.umich.eduDrainState 945396Ssaidi@eecs.umich.eduTimingSimpleCPU::drain() 955396Ssaidi@eecs.umich.edu{ 965396Ssaidi@eecs.umich.edu // Deschedule any power gating event (if any) 975396Ssaidi@eecs.umich.edu deschedulePowerGatingEvent(); 985396Ssaidi@eecs.umich.edu 995396Ssaidi@eecs.umich.edu if (switchedOut()) 1005396Ssaidi@eecs.umich.edu return DrainState::Drained; 1015396Ssaidi@eecs.umich.edu 1025396Ssaidi@eecs.umich.edu if (_status == Idle || 1035396Ssaidi@eecs.umich.edu (_status == BaseSimpleCPU::Running && isDrained())) { 1045396Ssaidi@eecs.umich.edu DPRINTF(Drain, "No need to drain.\n"); 1055396Ssaidi@eecs.umich.edu activeThreads.clear(); 1065396Ssaidi@eecs.umich.edu return DrainState::Drained; 1075396Ssaidi@eecs.umich.edu } else { 1085396Ssaidi@eecs.umich.edu DPRINTF(Drain, "Requesting drain.\n"); 1095396Ssaidi@eecs.umich.edu 1105396Ssaidi@eecs.umich.edu // The fetch event can become descheduled if a drain didn't 1115396Ssaidi@eecs.umich.edu // succeed on the first attempt. We need to reschedule it if 1125396Ssaidi@eecs.umich.edu // the CPU is waiting for a microcode routine to complete. 1135396Ssaidi@eecs.umich.edu if (_status == BaseSimpleCPU::Running && !fetchEvent.scheduled()) 1145396Ssaidi@eecs.umich.edu schedule(fetchEvent, clockEdge()); 1155396Ssaidi@eecs.umich.edu 1165396Ssaidi@eecs.umich.edu return DrainState::Draining; 1175396Ssaidi@eecs.umich.edu } 1185396Ssaidi@eecs.umich.edu} 1195396Ssaidi@eecs.umich.edu 1205396Ssaidi@eecs.umich.eduvoid 1215396Ssaidi@eecs.umich.eduTimingSimpleCPU::drainResume() 1225396Ssaidi@eecs.umich.edu{ 1235396Ssaidi@eecs.umich.edu assert(!fetchEvent.scheduled()); 1245396Ssaidi@eecs.umich.edu if (switchedOut()) 1255396Ssaidi@eecs.umich.edu return; 1265396Ssaidi@eecs.umich.edu 1275396Ssaidi@eecs.umich.edu DPRINTF(SimpleCPU, "Resume\n"); 1285396Ssaidi@eecs.umich.edu verifyMemoryMode(); 1295396Ssaidi@eecs.umich.edu 1305396Ssaidi@eecs.umich.edu assert(!threadContexts.empty()); 1315396Ssaidi@eecs.umich.edu 1325396Ssaidi@eecs.umich.edu _status = BaseSimpleCPU::Idle; 1335396Ssaidi@eecs.umich.edu 1345396Ssaidi@eecs.umich.edu for (ThreadID tid = 0; tid < numThreads; tid++) { 1355396Ssaidi@eecs.umich.edu if (threadInfo[tid]->thread->status() == ThreadContext::Active) { 1365396Ssaidi@eecs.umich.edu threadInfo[tid]->notIdleFraction = 1; 1375396Ssaidi@eecs.umich.edu 1385396Ssaidi@eecs.umich.edu activeThreads.push_back(tid); 1395396Ssaidi@eecs.umich.edu 1405396Ssaidi@eecs.umich.edu _status = BaseSimpleCPU::Running; 1415396Ssaidi@eecs.umich.edu 1425396Ssaidi@eecs.umich.edu // Fetch if any threads active 1435396Ssaidi@eecs.umich.edu if (!fetchEvent.scheduled()) { 1445396Ssaidi@eecs.umich.edu schedule(fetchEvent, nextCycle()); 1455396Ssaidi@eecs.umich.edu } 1465396Ssaidi@eecs.umich.edu } else { 1475396Ssaidi@eecs.umich.edu threadInfo[tid]->notIdleFraction = 0; 1485396Ssaidi@eecs.umich.edu } 1495396Ssaidi@eecs.umich.edu } 1504781Snate@binkert.org 1511852SN/A // Reschedule any power gating event (if any) 152955SN/A schedulePowerGatingEvent(); 153955SN/A 154955SN/A system->totalNumInsts = 0; 1553717Sstever@eecs.umich.edu} 1563716Sstever@eecs.umich.edu 157955SN/Abool 1581533SN/ATimingSimpleCPU::tryCompleteDrain() 1593716Sstever@eecs.umich.edu{ 1601533SN/A if (drainState() != DrainState::Draining) 1614678Snate@binkert.org return false; 1624678Snate@binkert.org 1634678Snate@binkert.org DPRINTF(Drain, "tryCompleteDrain.\n"); 1644678Snate@binkert.org if (!isDrained()) 1654678Snate@binkert.org return false; 1664678Snate@binkert.org 1674678Snate@binkert.org DPRINTF(Drain, "CPU done draining, processing drain event\n"); 1684678Snate@binkert.org signalDrainDone(); 1694678Snate@binkert.org 1704678Snate@binkert.org return true; 1714678Snate@binkert.org} 1724678Snate@binkert.org 1734678Snate@binkert.orgvoid 1744678Snate@binkert.orgTimingSimpleCPU::switchOut() 1754678Snate@binkert.org{ 1764678Snate@binkert.org SimpleExecContext& t_info = *threadInfo[curThread]; 1774678Snate@binkert.org M5_VAR_USED SimpleThread* thread = t_info.thread; 1784678Snate@binkert.org 1794678Snate@binkert.org BaseSimpleCPU::switchOut(); 1804678Snate@binkert.org 1814678Snate@binkert.org assert(!fetchEvent.scheduled()); 1824973Ssaidi@eecs.umich.edu assert(_status == BaseSimpleCPU::Running || _status == Idle); 1834678Snate@binkert.org assert(!t_info.stayAtPC); 1844678Snate@binkert.org assert(thread->microPC() == 0); 1854678Snate@binkert.org 1864678Snate@binkert.org updateCycleCounts(); 1874678Snate@binkert.org updateCycleCounters(BaseCPU::CPU_STATE_ON); 1884678Snate@binkert.org} 189955SN/A 190955SN/A 1912632Sstever@eecs.umich.eduvoid 1922632Sstever@eecs.umich.eduTimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 193955SN/A{ 194955SN/A BaseSimpleCPU::takeOverFrom(oldCPU); 195955SN/A 196955SN/A previousCycle = curCycle(); 1972632Sstever@eecs.umich.edu} 198955SN/A 1992632Sstever@eecs.umich.eduvoid 2002632Sstever@eecs.umich.eduTimingSimpleCPU::verifyMemoryMode() const 2012632Sstever@eecs.umich.edu{ 2022632Sstever@eecs.umich.edu if (!system->isTimingMode()) { 2032632Sstever@eecs.umich.edu fatal("The timing CPU requires the memory system to be in " 2042632Sstever@eecs.umich.edu "'timing' mode.\n"); 2052632Sstever@eecs.umich.edu } 2062632Sstever@eecs.umich.edu} 2072632Sstever@eecs.umich.edu 2082632Sstever@eecs.umich.eduvoid 2092632Sstever@eecs.umich.eduTimingSimpleCPU::activateContext(ThreadID thread_num) 2102632Sstever@eecs.umich.edu{ 2112632Sstever@eecs.umich.edu DPRINTF(SimpleCPU, "ActivateContext %d\n", thread_num); 2123718Sstever@eecs.umich.edu 2133718Sstever@eecs.umich.edu assert(thread_num < numThreads); 2143718Sstever@eecs.umich.edu 2153718Sstever@eecs.umich.edu threadInfo[thread_num]->notIdleFraction = 1; 2163718Sstever@eecs.umich.edu if (_status == BaseSimpleCPU::Idle) 2173718Sstever@eecs.umich.edu _status = BaseSimpleCPU::Running; 2183718Sstever@eecs.umich.edu 2193718Sstever@eecs.umich.edu // kick things off by initiating the fetch of the next instruction 2203718Sstever@eecs.umich.edu if (!fetchEvent.scheduled()) 2213718Sstever@eecs.umich.edu schedule(fetchEvent, clockEdge(Cycles(0))); 2223718Sstever@eecs.umich.edu 2233718Sstever@eecs.umich.edu if (std::find(activeThreads.begin(), activeThreads.end(), thread_num) 2243718Sstever@eecs.umich.edu == activeThreads.end()) { 2252634Sstever@eecs.umich.edu activeThreads.push_back(thread_num); 2262634Sstever@eecs.umich.edu } 2272632Sstever@eecs.umich.edu 2282638Sstever@eecs.umich.edu BaseCPU::activateContext(thread_num); 2292632Sstever@eecs.umich.edu} 2302632Sstever@eecs.umich.edu 2312632Sstever@eecs.umich.edu 2322632Sstever@eecs.umich.eduvoid 2332632Sstever@eecs.umich.eduTimingSimpleCPU::suspendContext(ThreadID thread_num) 2342632Sstever@eecs.umich.edu{ 2351858SN/A DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num); 2363716Sstever@eecs.umich.edu 2372638Sstever@eecs.umich.edu assert(thread_num < numThreads); 2382638Sstever@eecs.umich.edu activeThreads.remove(thread_num); 2392638Sstever@eecs.umich.edu 2402638Sstever@eecs.umich.edu if (_status == Idle) 2412638Sstever@eecs.umich.edu return; 2422638Sstever@eecs.umich.edu 2432638Sstever@eecs.umich.edu assert(_status == BaseSimpleCPU::Running); 2443716Sstever@eecs.umich.edu 2452634Sstever@eecs.umich.edu threadInfo[thread_num]->notIdleFraction = 0; 2462634Sstever@eecs.umich.edu 247955SN/A if (activeThreads.empty()) { 2485341Sstever@gmail.com _status = Idle; 2495341Sstever@gmail.com 2505341Sstever@gmail.com if (fetchEvent.scheduled()) { 2515341Sstever@gmail.com deschedule(fetchEvent); 252955SN/A } 253955SN/A } 254955SN/A 255955SN/A BaseCPU::suspendContext(thread_num); 256955SN/A} 257955SN/A 258955SN/Abool 2591858SN/ATimingSimpleCPU::handleReadPacket(PacketPtr pkt) 2601858SN/A{ 2612632Sstever@eecs.umich.edu SimpleExecContext &t_info = *threadInfo[curThread]; 262955SN/A SimpleThread* thread = t_info.thread; 2634494Ssaidi@eecs.umich.edu 2644494Ssaidi@eecs.umich.edu const RequestPtr &req = pkt->req; 2653716Sstever@eecs.umich.edu 2661105SN/A // We're about the issues a locked load, so tell the monitor 2672667Sstever@eecs.umich.edu // to start caring about this address 2682667Sstever@eecs.umich.edu if (pkt->isRead() && pkt->req->isLLSC()) { 2692667Sstever@eecs.umich.edu TheISA::handleLockedRead(thread, pkt->req); 2702667Sstever@eecs.umich.edu } 2712667Sstever@eecs.umich.edu if (req->isMmappedIpr()) { 2722667Sstever@eecs.umich.edu Cycles delay = TheISA::handleIprRead(thread->getTC(), pkt); 2731869SN/A new IprEvent(pkt, this, clockEdge(delay)); 2741869SN/A _status = DcacheWaitResponse; 2751869SN/A dcache_pkt = NULL; 2761869SN/A } else if (!dcachePort.sendTimingReq(pkt)) { 2771869SN/A _status = DcacheRetry; 2781065SN/A dcache_pkt = pkt; 2795341Sstever@gmail.com } else { 2805341Sstever@gmail.com _status = DcacheWaitResponse; 2815341Sstever@gmail.com // memory system takes ownership of packet 2825341Sstever@gmail.com dcache_pkt = NULL; 2835341Sstever@gmail.com } 2845341Sstever@gmail.com return dcache_pkt == NULL; 2855341Sstever@gmail.com} 2865341Sstever@gmail.com 2875341Sstever@gmail.comvoid 2885341Sstever@gmail.comTimingSimpleCPU::sendData(const RequestPtr &req, uint8_t *data, uint64_t *res, 2895341Sstever@gmail.com bool read) 2905341Sstever@gmail.com{ 2915341Sstever@gmail.com SimpleExecContext &t_info = *threadInfo[curThread]; 2925341Sstever@gmail.com SimpleThread* thread = t_info.thread; 2935341Sstever@gmail.com 2945341Sstever@gmail.com PacketPtr pkt = buildPacket(req, read); 2955341Sstever@gmail.com pkt->dataDynamic<uint8_t>(data); 2965341Sstever@gmail.com 2975341Sstever@gmail.com if (req->getFlags().isSet(Request::NO_ACCESS)) { 2985341Sstever@gmail.com assert(!dcache_pkt); 2995341Sstever@gmail.com pkt->makeResponse(); 3005341Sstever@gmail.com completeDataAccess(pkt); 3015341Sstever@gmail.com } else if (read) { 3025341Sstever@gmail.com handleReadPacket(pkt); 3035341Sstever@gmail.com } else { 3045341Sstever@gmail.com bool do_access = true; // flag to suppress cache access 3055341Sstever@gmail.com 3065397Ssaidi@eecs.umich.edu if (req->isLLSC()) { 3075397Ssaidi@eecs.umich.edu do_access = TheISA::handleLockedWrite(thread, req, dcachePort.cacheBlockMask); 3085341Sstever@gmail.com } else if (req->isCondSwap()) { 3095341Sstever@gmail.com assert(res); 3105341Sstever@gmail.com req->setExtraData(*res); 3115341Sstever@gmail.com } 3125341Sstever@gmail.com 3135341Sstever@gmail.com if (do_access) { 3145341Sstever@gmail.com dcache_pkt = pkt; 3155341Sstever@gmail.com handleWritePacket(); 3165341Sstever@gmail.com threadSnoop(pkt, curThread); 3175341Sstever@gmail.com } else { 3185341Sstever@gmail.com _status = DcacheWaitResponse; 3195341Sstever@gmail.com completeDataAccess(pkt); 3205341Sstever@gmail.com } 3215341Sstever@gmail.com } 3225341Sstever@gmail.com} 3235341Sstever@gmail.com 3245341Sstever@gmail.comvoid 3255341Sstever@gmail.comTimingSimpleCPU::sendSplitData(const RequestPtr &req1, const RequestPtr &req2, 3265341Sstever@gmail.com const RequestPtr &req, uint8_t *data, bool read) 3275341Sstever@gmail.com{ 3285341Sstever@gmail.com PacketPtr pkt1, pkt2; 3295341Sstever@gmail.com buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read); 3305344Sstever@gmail.com if (req->getFlags().isSet(Request::NO_ACCESS)) { 3315341Sstever@gmail.com assert(!dcache_pkt); 3325341Sstever@gmail.com pkt1->makeResponse(); 3335341Sstever@gmail.com completeDataAccess(pkt1); 3345341Sstever@gmail.com } else if (read) { 3355341Sstever@gmail.com SplitFragmentSenderState * send_state = 3362632Sstever@eecs.umich.edu dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 3375199Sstever@gmail.com if (handleReadPacket(pkt1)) { 3383918Ssaidi@eecs.umich.edu send_state->clearFromParent(); 3393918Ssaidi@eecs.umich.edu send_state = dynamic_cast<SplitFragmentSenderState *>( 3403940Ssaidi@eecs.umich.edu pkt2->senderState); 3414781Snate@binkert.org if (handleReadPacket(pkt2)) { 3424781Snate@binkert.org send_state->clearFromParent(); 3433918Ssaidi@eecs.umich.edu } 3444781Snate@binkert.org } 3454781Snate@binkert.org } else { 3463918Ssaidi@eecs.umich.edu dcache_pkt = pkt1; 3474781Snate@binkert.org SplitFragmentSenderState * send_state = 3484781Snate@binkert.org dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 3493940Ssaidi@eecs.umich.edu if (handleWritePacket()) { 3503942Ssaidi@eecs.umich.edu send_state->clearFromParent(); 3513940Ssaidi@eecs.umich.edu dcache_pkt = pkt2; 3523918Ssaidi@eecs.umich.edu send_state = dynamic_cast<SplitFragmentSenderState *>( 3533918Ssaidi@eecs.umich.edu pkt2->senderState); 354955SN/A if (handleWritePacket()) { 3551858SN/A send_state->clearFromParent(); 3563918Ssaidi@eecs.umich.edu } 3573918Ssaidi@eecs.umich.edu } 3583918Ssaidi@eecs.umich.edu } 3593918Ssaidi@eecs.umich.edu} 3603940Ssaidi@eecs.umich.edu 3613940Ssaidi@eecs.umich.eduvoid 3623918Ssaidi@eecs.umich.eduTimingSimpleCPU::translationFault(const Fault &fault) 3633918Ssaidi@eecs.umich.edu{ 3643918Ssaidi@eecs.umich.edu // fault may be NoFault in cases where a fault is suppressed, 3653918Ssaidi@eecs.umich.edu // for instance prefetches. 3663918Ssaidi@eecs.umich.edu updateCycleCounts(); 3673918Ssaidi@eecs.umich.edu updateCycleCounters(BaseCPU::CPU_STATE_ON); 3683918Ssaidi@eecs.umich.edu 3693918Ssaidi@eecs.umich.edu if (traceData) { 3703918Ssaidi@eecs.umich.edu // Since there was a fault, we shouldn't trace this instruction. 3713940Ssaidi@eecs.umich.edu delete traceData; 3723918Ssaidi@eecs.umich.edu traceData = NULL; 3733918Ssaidi@eecs.umich.edu } 3745397Ssaidi@eecs.umich.edu 3755397Ssaidi@eecs.umich.edu postExecute(); 3765397Ssaidi@eecs.umich.edu 3775397Ssaidi@eecs.umich.edu advanceInst(fault); 3785397Ssaidi@eecs.umich.edu} 3795397Ssaidi@eecs.umich.edu 3801851SN/APacketPtr 3811851SN/ATimingSimpleCPU::buildPacket(const RequestPtr &req, bool read) 3821858SN/A{ 3835200Sstever@gmail.com return read ? Packet::createRead(req) : Packet::createWrite(req); 384955SN/A} 3853053Sstever@eecs.umich.edu 3863053Sstever@eecs.umich.eduvoid 3873053Sstever@eecs.umich.eduTimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, 3883053Sstever@eecs.umich.edu const RequestPtr &req1, const RequestPtr &req2, const RequestPtr &req, 3893053Sstever@eecs.umich.edu uint8_t *data, bool read) 3903053Sstever@eecs.umich.edu{ 3913053Sstever@eecs.umich.edu pkt1 = pkt2 = NULL; 3923053Sstever@eecs.umich.edu 3933053Sstever@eecs.umich.edu assert(!req1->isMmappedIpr() && !req2->isMmappedIpr()); 3944742Sstever@eecs.umich.edu 3954742Sstever@eecs.umich.edu if (req->getFlags().isSet(Request::NO_ACCESS)) { 3963053Sstever@eecs.umich.edu pkt1 = buildPacket(req, read); 3973053Sstever@eecs.umich.edu return; 3983053Sstever@eecs.umich.edu } 3993053Sstever@eecs.umich.edu 4003053Sstever@eecs.umich.edu pkt1 = buildPacket(req1, read); 4013053Sstever@eecs.umich.edu pkt2 = buildPacket(req2, read); 4023053Sstever@eecs.umich.edu 4033053Sstever@eecs.umich.edu PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand()); 4043053Sstever@eecs.umich.edu 4052667Sstever@eecs.umich.edu pkt->dataDynamic<uint8_t>(data); 4064554Sbinkertn@umich.edu pkt1->dataStatic<uint8_t>(data); 4074554Sbinkertn@umich.edu pkt2->dataStatic<uint8_t>(data + req1->getSize()); 4082667Sstever@eecs.umich.edu 4094554Sbinkertn@umich.edu SplitMainSenderState * main_send_state = new SplitMainSenderState; 4104554Sbinkertn@umich.edu pkt->senderState = main_send_state; 4114554Sbinkertn@umich.edu main_send_state->fragments[0] = pkt1; 4124554Sbinkertn@umich.edu main_send_state->fragments[1] = pkt2; 4134554Sbinkertn@umich.edu main_send_state->outstanding = 2; 4144554Sbinkertn@umich.edu pkt1->senderState = new SplitFragmentSenderState(pkt, 0); 4154554Sbinkertn@umich.edu pkt2->senderState = new SplitFragmentSenderState(pkt, 1); 4164781Snate@binkert.org} 4174554Sbinkertn@umich.edu 4184554Sbinkertn@umich.eduFault 4192667Sstever@eecs.umich.eduTimingSimpleCPU::initiateMemRead(Addr addr, unsigned size, 4204554Sbinkertn@umich.edu Request::Flags flags) 4214554Sbinkertn@umich.edu{ 4224554Sbinkertn@umich.edu SimpleExecContext &t_info = *threadInfo[curThread]; 4234554Sbinkertn@umich.edu SimpleThread* thread = t_info.thread; 4242667Sstever@eecs.umich.edu 4254554Sbinkertn@umich.edu Fault fault; 4262667Sstever@eecs.umich.edu const int asid = 0; 4274554Sbinkertn@umich.edu const Addr pc = thread->instAddr(); 4284554Sbinkertn@umich.edu unsigned block_size = cacheLineSize(); 4292667Sstever@eecs.umich.edu BaseTLB::Mode mode = BaseTLB::Read; 4302638Sstever@eecs.umich.edu 4312638Sstever@eecs.umich.edu if (traceData) 4322638Sstever@eecs.umich.edu traceData->setMem(addr, size, flags); 4333716Sstever@eecs.umich.edu 4343716Sstever@eecs.umich.edu RequestPtr req = std::make_shared<Request>( 4351858SN/A asid, addr, size, flags, dataMasterId(), pc, 4365227Ssaidi@eecs.umich.edu thread->contextId()); 4375227Ssaidi@eecs.umich.edu 4385227Ssaidi@eecs.umich.edu req->taskId(taskId()); 4395227Ssaidi@eecs.umich.edu 4405227Ssaidi@eecs.umich.edu Addr split_addr = roundDown(addr + size - 1, block_size); 4415227Ssaidi@eecs.umich.edu assert(split_addr <= addr || split_addr - addr < block_size); 4425227Ssaidi@eecs.umich.edu 4435227Ssaidi@eecs.umich.edu _status = DTBWaitResponse; 4445227Ssaidi@eecs.umich.edu if (split_addr > addr) { 4455227Ssaidi@eecs.umich.edu RequestPtr req1, req2; 4465227Ssaidi@eecs.umich.edu assert(!req->isLLSC() && !req->isSwap()); 4475227Ssaidi@eecs.umich.edu req->splitOnVaddr(split_addr, req1, req2); 4485227Ssaidi@eecs.umich.edu 4495227Ssaidi@eecs.umich.edu WholeTranslationState *state = 4505227Ssaidi@eecs.umich.edu new WholeTranslationState(req, req1, req2, new uint8_t[size], 4515204Sstever@gmail.com NULL, mode); 4525204Sstever@gmail.com DataTranslation<TimingSimpleCPU *> *trans1 = 4535204Sstever@gmail.com new DataTranslation<TimingSimpleCPU *>(this, state, 0); 4545204Sstever@gmail.com DataTranslation<TimingSimpleCPU *> *trans2 = 4555204Sstever@gmail.com new DataTranslation<TimingSimpleCPU *>(this, state, 1); 4565204Sstever@gmail.com 4575204Sstever@gmail.com thread->dtb->translateTiming(req1, thread->getTC(), trans1, mode); 4585204Sstever@gmail.com thread->dtb->translateTiming(req2, thread->getTC(), trans2, mode); 4595204Sstever@gmail.com } else { 4605204Sstever@gmail.com WholeTranslationState *state = 4615204Sstever@gmail.com new WholeTranslationState(req, new uint8_t[size], NULL, mode); 4625204Sstever@gmail.com DataTranslation<TimingSimpleCPU *> *translation 4635204Sstever@gmail.com = new DataTranslation<TimingSimpleCPU *>(this, state); 4645204Sstever@gmail.com thread->dtb->translateTiming(req, thread->getTC(), translation, mode); 4655204Sstever@gmail.com } 4665204Sstever@gmail.com 4675204Sstever@gmail.com return NoFault; 4685204Sstever@gmail.com} 4695204Sstever@gmail.com 4703118Sstever@eecs.umich.edubool 4713118Sstever@eecs.umich.eduTimingSimpleCPU::handleWritePacket() 4723118Sstever@eecs.umich.edu{ 4733118Sstever@eecs.umich.edu SimpleExecContext &t_info = *threadInfo[curThread]; 4743118Sstever@eecs.umich.edu SimpleThread* thread = t_info.thread; 4753118Sstever@eecs.umich.edu 4763118Sstever@eecs.umich.edu const RequestPtr &req = dcache_pkt->req; 4773118Sstever@eecs.umich.edu if (req->isMmappedIpr()) { 4783118Sstever@eecs.umich.edu Cycles delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); 4793118Sstever@eecs.umich.edu new IprEvent(dcache_pkt, this, clockEdge(delay)); 4803118Sstever@eecs.umich.edu _status = DcacheWaitResponse; 4813716Sstever@eecs.umich.edu dcache_pkt = NULL; 4823118Sstever@eecs.umich.edu } else if (!dcachePort.sendTimingReq(dcache_pkt)) { 4833118Sstever@eecs.umich.edu _status = DcacheRetry; 4843118Sstever@eecs.umich.edu } else { 4853118Sstever@eecs.umich.edu _status = DcacheWaitResponse; 4863118Sstever@eecs.umich.edu // memory system takes ownership of packet 4873118Sstever@eecs.umich.edu dcache_pkt = NULL; 4883118Sstever@eecs.umich.edu } 4893118Sstever@eecs.umich.edu return dcache_pkt == NULL; 4903118Sstever@eecs.umich.edu} 4913716Sstever@eecs.umich.edu 4923118Sstever@eecs.umich.eduFault 4933118Sstever@eecs.umich.eduTimingSimpleCPU::writeMem(uint8_t *data, unsigned size, 4943118Sstever@eecs.umich.edu Addr addr, Request::Flags flags, uint64_t *res) 4953118Sstever@eecs.umich.edu{ 4963118Sstever@eecs.umich.edu SimpleExecContext &t_info = *threadInfo[curThread]; 4973118Sstever@eecs.umich.edu SimpleThread* thread = t_info.thread; 4983118Sstever@eecs.umich.edu 4993118Sstever@eecs.umich.edu uint8_t *newData = new uint8_t[size]; 5003118Sstever@eecs.umich.edu const int asid = 0; 5013118Sstever@eecs.umich.edu const Addr pc = thread->instAddr(); 5023483Ssaidi@eecs.umich.edu unsigned block_size = cacheLineSize(); 5033494Ssaidi@eecs.umich.edu BaseTLB::Mode mode = BaseTLB::Write; 5043494Ssaidi@eecs.umich.edu 5053483Ssaidi@eecs.umich.edu if (data == NULL) { 5063483Ssaidi@eecs.umich.edu assert(flags & Request::STORE_NO_DATA); 5073483Ssaidi@eecs.umich.edu // This must be a cache block cleaning request 5083053Sstever@eecs.umich.edu memset(newData, 0, size); 5093053Sstever@eecs.umich.edu } else { 5103918Ssaidi@eecs.umich.edu memcpy(newData, data, size); 5113053Sstever@eecs.umich.edu } 5123053Sstever@eecs.umich.edu 5133053Sstever@eecs.umich.edu if (traceData) 5143053Sstever@eecs.umich.edu traceData->setMem(addr, size, flags); 5153053Sstever@eecs.umich.edu 5161858SN/A RequestPtr req = std::make_shared<Request>( 5171858SN/A asid, addr, size, flags, dataMasterId(), pc, 5181858SN/A thread->contextId()); 5191858SN/A 5201858SN/A req->taskId(taskId()); 5211858SN/A 5221859SN/A Addr split_addr = roundDown(addr + size - 1, block_size); 5231858SN/A assert(split_addr <= addr || split_addr - addr < block_size); 5241858SN/A 5251858SN/A _status = DTBWaitResponse; 5261859SN/A if (split_addr > addr) { 5271859SN/A RequestPtr req1, req2; 5281862SN/A assert(!req->isLLSC() && !req->isSwap()); 5293053Sstever@eecs.umich.edu req->splitOnVaddr(split_addr, req1, req2); 5303053Sstever@eecs.umich.edu 5313053Sstever@eecs.umich.edu WholeTranslationState *state = 5323053Sstever@eecs.umich.edu new WholeTranslationState(req, req1, req2, newData, res, mode); 5331859SN/A DataTranslation<TimingSimpleCPU *> *trans1 = 5341859SN/A new DataTranslation<TimingSimpleCPU *>(this, state, 0); 5351859SN/A DataTranslation<TimingSimpleCPU *> *trans2 = 5361859SN/A new DataTranslation<TimingSimpleCPU *>(this, state, 1); 5371859SN/A 5381859SN/A thread->dtb->translateTiming(req1, thread->getTC(), trans1, mode); 5391859SN/A thread->dtb->translateTiming(req2, thread->getTC(), trans2, mode); 5401859SN/A } else { 5411862SN/A WholeTranslationState *state = 5421859SN/A new WholeTranslationState(req, newData, res, mode); 5431859SN/A DataTranslation<TimingSimpleCPU *> *translation = 5441859SN/A new DataTranslation<TimingSimpleCPU *>(this, state); 5451858SN/A thread->dtb->translateTiming(req, thread->getTC(), translation, mode); 5461858SN/A } 5472139SN/A 5484202Sbinkertn@umich.edu // Translation faults will be returned via finishTranslation() 5494202Sbinkertn@umich.edu return NoFault; 5502139SN/A} 5512155SN/A 5524202Sbinkertn@umich.eduFault 5534202Sbinkertn@umich.eduTimingSimpleCPU::initiateMemAMO(Addr addr, unsigned size, 5544202Sbinkertn@umich.edu Request::Flags flags, 5552155SN/A AtomicOpFunctor *amo_op) 5561869SN/A{ 5571869SN/A SimpleExecContext &t_info = *threadInfo[curThread]; 5581869SN/A SimpleThread* thread = t_info.thread; 5591869SN/A 5604202Sbinkertn@umich.edu Fault fault; 5614202Sbinkertn@umich.edu const int asid = 0; 5624202Sbinkertn@umich.edu const Addr pc = thread->instAddr(); 5634202Sbinkertn@umich.edu unsigned block_size = cacheLineSize(); 5644202Sbinkertn@umich.edu BaseTLB::Mode mode = BaseTLB::Write; 5654202Sbinkertn@umich.edu 5664202Sbinkertn@umich.edu if (traceData) 5674202Sbinkertn@umich.edu traceData->setMem(addr, size, flags); 5685341Sstever@gmail.com 5695341Sstever@gmail.com RequestPtr req = make_shared<Request>(asid, addr, size, flags, 5705341Sstever@gmail.com dataMasterId(), pc, thread->contextId(), amo_op); 5715342Sstever@gmail.com 5725342Sstever@gmail.com assert(req->hasAtomicOpFunctor()); 5734202Sbinkertn@umich.edu 5744202Sbinkertn@umich.edu req->taskId(taskId()); 5754202Sbinkertn@umich.edu 5764202Sbinkertn@umich.edu Addr split_addr = roundDown(addr + size - 1, block_size); 5774202Sbinkertn@umich.edu 5781869SN/A // AMO requests that access across a cache line boundary are not 5794202Sbinkertn@umich.edu // allowed since the cache does not guarantee AMO ops to be executed 5801869SN/A // atomically in two cache lines 5812508SN/A // For ISAs such as x86 that requires AMO operations to work on 5822508SN/A // accesses that cross cache-line boundaries, the cache needs to be 5832508SN/A // modified to support locking both cache lines to guarantee the 5842508SN/A // atomicity. 5854202Sbinkertn@umich.edu if (split_addr > addr) { 5861869SN/A panic("AMO requests should not access across a cache line boundary\n"); 5875385Sstever@gmail.com } 5885385Sstever@gmail.com 5895385Sstever@gmail.com _status = DTBWaitResponse; 5905385Sstever@gmail.com 5911869SN/A WholeTranslationState *state = 5921869SN/A new WholeTranslationState(req, new uint8_t[size], NULL, mode); 5931869SN/A DataTranslation<TimingSimpleCPU *> *translation 5941869SN/A = new DataTranslation<TimingSimpleCPU *>(this, state); 5951869SN/A thread->dtb->translateTiming(req, thread->getTC(), translation, mode); 5961965SN/A 5971965SN/A return NoFault; 5981965SN/A} 5991869SN/A 6001869SN/Avoid 6012733Sktlim@umich.eduTimingSimpleCPU::threadSnoop(PacketPtr pkt, ThreadID sender) 6023356Sbinkertn@umich.edu{ 6033356Sbinkertn@umich.edu for (ThreadID tid = 0; tid < numThreads; tid++) { 6044773Snate@binkert.org if (tid != sender) { 6051869SN/A if (getCpuAddrMonitor(tid)->doMonitor(pkt)) { 6061858SN/A wakeup(tid); 6071869SN/A } 6081869SN/A TheISA::handleLockedSnoop(threadInfo[tid]->thread, pkt, 6091869SN/A dcachePort.cacheBlockMask); 6101858SN/A } 6112761Sstever@eecs.umich.edu } 6121869SN/A} 6135385Sstever@gmail.com 6145385Sstever@gmail.comvoid 6153584Ssaidi@eecs.umich.eduTimingSimpleCPU::finishTranslation(WholeTranslationState *state) 6161869SN/A{ 6171869SN/A _status = BaseSimpleCPU::Running; 6181869SN/A 6191869SN/A if (state->getFault() != NoFault) { 6201869SN/A if (state->isPrefetch()) { 6211869SN/A state->setNoFault(); 6221858SN/A } 623955SN/A delete [] state->data; 624955SN/A state->deleteReqs(); 6251869SN/A translationFault(state->getFault()); 6261869SN/A } else { 6271869SN/A if (!state->isSplit) { 6281869SN/A sendData(state->mainReq, state->data, state->res, 6291869SN/A state->mode == BaseTLB::Read); 6301869SN/A } else { 6311869SN/A sendSplitData(state->sreqLow, state->sreqHigh, state->mainReq, 6321869SN/A state->data, state->mode == BaseTLB::Read); 6331869SN/A } 6341869SN/A } 6351869SN/A 6361869SN/A delete state; 6371869SN/A} 6381869SN/A 6391869SN/A 6401869SN/Avoid 6411869SN/ATimingSimpleCPU::fetch() 6421869SN/A{ 6431869SN/A // Change thread if multi-threaded 6441869SN/A swapActiveThread(); 6451869SN/A 6461869SN/A SimpleExecContext &t_info = *threadInfo[curThread]; 6471869SN/A SimpleThread* thread = t_info.thread; 6481869SN/A 6491869SN/A DPRINTF(SimpleCPU, "Fetch\n"); 6501869SN/A 6511869SN/A if (!curStaticInst || !curStaticInst->isDelayedCommit()) { 6521869SN/A checkForInterrupts(); 6531869SN/A checkPcEventQueue(); 6543716Sstever@eecs.umich.edu } 6553356Sbinkertn@umich.edu 6563356Sbinkertn@umich.edu // We must have just got suspended by a PC event 6573356Sbinkertn@umich.edu if (_status == Idle) 6583356Sbinkertn@umich.edu return; 6593356Sbinkertn@umich.edu 6603356Sbinkertn@umich.edu TheISA::PCState pcState = thread->pcState(); 6614781Snate@binkert.org bool needToFetch = !isRomMicroPC(pcState.microPC()) && 6621869SN/A !curMacroStaticInst; 6631869SN/A 6641869SN/A if (needToFetch) { 6651869SN/A _status = BaseSimpleCPU::Running; 6661869SN/A RequestPtr ifetch_req = std::make_shared<Request>(); 6671869SN/A ifetch_req->taskId(taskId()); 6681869SN/A ifetch_req->setContext(thread->contextId()); 6692655Sstever@eecs.umich.edu setupFetchRequest(ifetch_req); 6702655Sstever@eecs.umich.edu DPRINTF(SimpleCPU, "Translating address %#x\n", ifetch_req->getVaddr()); 6712655Sstever@eecs.umich.edu thread->itb->translateTiming(ifetch_req, thread->getTC(), 6722655Sstever@eecs.umich.edu &fetchTranslation, BaseTLB::Execute); 6732655Sstever@eecs.umich.edu } else { 6742655Sstever@eecs.umich.edu _status = IcacheWaitResponse; 6752655Sstever@eecs.umich.edu completeIfetch(NULL); 6762655Sstever@eecs.umich.edu 6772655Sstever@eecs.umich.edu updateCycleCounts(); 6782655Sstever@eecs.umich.edu updateCycleCounters(BaseCPU::CPU_STATE_ON); 6792655Sstever@eecs.umich.edu } 6802655Sstever@eecs.umich.edu} 6812655Sstever@eecs.umich.edu 6822655Sstever@eecs.umich.edu 6832655Sstever@eecs.umich.eduvoid 6842655Sstever@eecs.umich.eduTimingSimpleCPU::sendFetch(const Fault &fault, const RequestPtr &req, 6852655Sstever@eecs.umich.edu ThreadContext *tc) 6862655Sstever@eecs.umich.edu{ 6872655Sstever@eecs.umich.edu if (fault == NoFault) { 6882655Sstever@eecs.umich.edu DPRINTF(SimpleCPU, "Sending fetch for addr %#x(pa: %#x)\n", 6892655Sstever@eecs.umich.edu req->getVaddr(), req->getPaddr()); 6902655Sstever@eecs.umich.edu ifetch_pkt = new Packet(req, MemCmd::ReadReq); 6912655Sstever@eecs.umich.edu ifetch_pkt->dataStatic(&inst); 6922655Sstever@eecs.umich.edu DPRINTF(SimpleCPU, " -- pkt addr: %#x\n", ifetch_pkt->getAddr()); 6932655Sstever@eecs.umich.edu 6942655Sstever@eecs.umich.edu if (!icachePort.sendTimingReq(ifetch_pkt)) { 6952638Sstever@eecs.umich.edu // Need to wait for retry 6962638Sstever@eecs.umich.edu _status = IcacheRetry; 6973716Sstever@eecs.umich.edu } else { 6982638Sstever@eecs.umich.edu // Need to wait for cache to respond 6992638Sstever@eecs.umich.edu _status = IcacheWaitResponse; 7001869SN/A // ownership of packet transferred to memory system 7011869SN/A ifetch_pkt = NULL; 7023546Sgblack@eecs.umich.edu } 7033546Sgblack@eecs.umich.edu } else { 7043546Sgblack@eecs.umich.edu DPRINTF(SimpleCPU, "Translation of addr %#x faulted\n", req->getVaddr()); 7053546Sgblack@eecs.umich.edu // fetch fault: advance directly to next instruction (fault handler) 7064202Sbinkertn@umich.edu _status = BaseSimpleCPU::Running; 7073546Sgblack@eecs.umich.edu advanceInst(fault); 7083546Sgblack@eecs.umich.edu } 7093546Sgblack@eecs.umich.edu 7103546Sgblack@eecs.umich.edu updateCycleCounts(); 7113546Sgblack@eecs.umich.edu updateCycleCounters(BaseCPU::CPU_STATE_ON); 7124781Snate@binkert.org} 7134781Snate@binkert.org 7144781Snate@binkert.org 7154781Snate@binkert.orgvoid 7164781Snate@binkert.orgTimingSimpleCPU::advanceInst(const Fault &fault) 7174781Snate@binkert.org{ 7184781Snate@binkert.org SimpleExecContext &t_info = *threadInfo[curThread]; 7194781Snate@binkert.org 7204781Snate@binkert.org if (_status == Faulting) 7214781Snate@binkert.org return; 7224781Snate@binkert.org 7234781Snate@binkert.org if (fault != NoFault) { 7243546Sgblack@eecs.umich.edu DPRINTF(SimpleCPU, "Fault occured. Handling the fault\n"); 7253546Sgblack@eecs.umich.edu 7263546Sgblack@eecs.umich.edu advancePC(fault); 7274781Snate@binkert.org 7283546Sgblack@eecs.umich.edu // A syscall fault could suspend this CPU (e.g., futex_wait) 7293546Sgblack@eecs.umich.edu // If the _status is not Idle, schedule an event to fetch the next 7303546Sgblack@eecs.umich.edu // instruction after 'stall' ticks. 7313546Sgblack@eecs.umich.edu // If the cpu has been suspended (i.e., _status == Idle), another 7323546Sgblack@eecs.umich.edu // cpu will wake this cpu up later. 7333546Sgblack@eecs.umich.edu if (_status != Idle) { 7343546Sgblack@eecs.umich.edu DPRINTF(SimpleCPU, "Scheduling fetch event after the Fault\n"); 7353546Sgblack@eecs.umich.edu 7363546Sgblack@eecs.umich.edu Tick stall = dynamic_pointer_cast<SyscallRetryFault>(fault) ? 7373546Sgblack@eecs.umich.edu clockEdge(syscallRetryLatency) : clockEdge(); 7384202Sbinkertn@umich.edu reschedule(fetchEvent, stall, true); 7393546Sgblack@eecs.umich.edu _status = Faulting; 7403546Sgblack@eecs.umich.edu } 7413546Sgblack@eecs.umich.edu 742955SN/A return; 743955SN/A } 744955SN/A 745955SN/A if (!t_info.stayAtPC) 7461858SN/A advancePC(fault); 7471858SN/A 7481858SN/A if (tryCompleteDrain()) 7492632Sstever@eecs.umich.edu return; 7502632Sstever@eecs.umich.edu 7515343Sstever@gmail.com if (_status == BaseSimpleCPU::Running) { 7525343Sstever@gmail.com // kick off fetch of next instruction... callback from icache 7535343Sstever@gmail.com // response will cause that instruction to be executed, 7544773Snate@binkert.org // keeping the CPU running. 7554773Snate@binkert.org fetch(); 7562632Sstever@eecs.umich.edu } 7572632Sstever@eecs.umich.edu} 7582632Sstever@eecs.umich.edu 7592023SN/A 7602632Sstever@eecs.umich.eduvoid 7612632Sstever@eecs.umich.eduTimingSimpleCPU::completeIfetch(PacketPtr pkt) 7622632Sstever@eecs.umich.edu{ 7632632Sstever@eecs.umich.edu SimpleExecContext& t_info = *threadInfo[curThread]; 7642632Sstever@eecs.umich.edu 7653716Sstever@eecs.umich.edu DPRINTF(SimpleCPU, "Complete ICache Fetch for addr %#x\n", pkt ? 7665342Sstever@gmail.com pkt->getAddr() : 0); 7672632Sstever@eecs.umich.edu 7682632Sstever@eecs.umich.edu // received a response from the icache: execute the received 7692632Sstever@eecs.umich.edu // instruction 7702632Sstever@eecs.umich.edu assert(!pkt || !pkt->isError()); 7712023SN/A assert(_status == IcacheWaitResponse); 7722632Sstever@eecs.umich.edu 7732632Sstever@eecs.umich.edu _status = BaseSimpleCPU::Running; 7745342Sstever@gmail.com 7751889SN/A updateCycleCounts(); 7762632Sstever@eecs.umich.edu updateCycleCounters(BaseCPU::CPU_STATE_ON); 7772632Sstever@eecs.umich.edu 7782632Sstever@eecs.umich.edu if (pkt) 7792632Sstever@eecs.umich.edu pkt->req->setAccessLatency(); 7803716Sstever@eecs.umich.edu 7813716Sstever@eecs.umich.edu 7825342Sstever@gmail.com preExecute(); 7832632Sstever@eecs.umich.edu if (curStaticInst && curStaticInst->isMemRef()) { 7842632Sstever@eecs.umich.edu // load or store: just send to dcache 7852632Sstever@eecs.umich.edu Fault fault = curStaticInst->initiateAcc(&t_info, traceData); 7862632Sstever@eecs.umich.edu 7872632Sstever@eecs.umich.edu // If we're not running now the instruction will complete in a dcache 7882632Sstever@eecs.umich.edu // response callback or the instruction faulted and has started an 7892632Sstever@eecs.umich.edu // ifetch 7901888SN/A if (_status == BaseSimpleCPU::Running) { 7911888SN/A if (fault != NoFault && traceData) { 7921869SN/A // If there was a fault, we shouldn't trace this instruction. 7931869SN/A delete traceData; 7941858SN/A traceData = NULL; 7955341Sstever@gmail.com } 7962598SN/A 7972598SN/A postExecute(); 7982598SN/A // @todo remove me after debugging with legion done 7992598SN/A if (curStaticInst && (!curStaticInst->isMicroop() || 8001858SN/A curStaticInst->isFirstMicroop())) 8011858SN/A instCnt++; 8021858SN/A advanceInst(fault); 8031858SN/A } 8041858SN/A } else if (curStaticInst) { 8051858SN/A // non-memory instruction: execute completely now 8061858SN/A Fault fault = curStaticInst->execute(&t_info, traceData); 8071858SN/A 8081858SN/A // keep an instruction count 8091871SN/A if (fault == NoFault) 8101858SN/A countInst(); 8111858SN/A else if (traceData && !DTRACE(ExecFaulting)) { 8121858SN/A delete traceData; 8131858SN/A traceData = NULL; 8141858SN/A } 8151858SN/A 8161858SN/A postExecute(); 8171858SN/A // @todo remove me after debugging with legion done 8181858SN/A if (curStaticInst && (!curStaticInst->isMicroop() || 8191858SN/A curStaticInst->isFirstMicroop())) 8201858SN/A instCnt++; 8211859SN/A advanceInst(fault); 8221859SN/A } else { 8231869SN/A advanceInst(NoFault); 8241888SN/A } 8252632Sstever@eecs.umich.edu 8261869SN/A if (pkt) { 8271965SN/A delete pkt; 8281965SN/A } 8291965SN/A} 8302761Sstever@eecs.umich.edu 8311869SN/Avoid 8321869SN/ATimingSimpleCPU::IcachePort::ITickEvent::process() 8332632Sstever@eecs.umich.edu{ 8342667Sstever@eecs.umich.edu cpu->completeIfetch(pkt); 8351869SN/A} 8361869SN/A 8372929Sktlim@umich.edubool 8382929Sktlim@umich.eduTimingSimpleCPU::IcachePort::recvTimingResp(PacketPtr pkt) 8393716Sstever@eecs.umich.edu{ 8402929Sktlim@umich.edu DPRINTF(SimpleCPU, "Received fetch response %#x\n", pkt->getAddr()); 841955SN/A // we should only ever see one response per cycle since we only 8422598SN/A // issue a new request once this response is sunk 8432598SN/A assert(!tickEvent.scheduled()); 8443546Sgblack@eecs.umich.edu // delay processing of returned data until next CPU clock edge 845955SN/A tickEvent.schedule(pkt, cpu->clockEdge()); 846955SN/A 847955SN/A return true; 8481530SN/A} 849955SN/A 850955SN/Avoid 851955SN/ATimingSimpleCPU::IcachePort::recvReqRetry() 852{ 853 // we shouldn't get a retry unless we have a packet that we're 854 // waiting to transmit 855 assert(cpu->ifetch_pkt != NULL); 856 assert(cpu->_status == IcacheRetry); 857 PacketPtr tmp = cpu->ifetch_pkt; 858 if (sendTimingReq(tmp)) { 859 cpu->_status = IcacheWaitResponse; 860 cpu->ifetch_pkt = NULL; 861 } 862} 863 864void 865TimingSimpleCPU::completeDataAccess(PacketPtr pkt) 866{ 867 // received a response from the dcache: complete the load or store 868 // instruction 869 assert(!pkt->isError()); 870 assert(_status == DcacheWaitResponse || _status == DTBWaitResponse || 871 pkt->req->getFlags().isSet(Request::NO_ACCESS)); 872 873 pkt->req->setAccessLatency(); 874 875 updateCycleCounts(); 876 updateCycleCounters(BaseCPU::CPU_STATE_ON); 877 878 if (pkt->senderState) { 879 SplitFragmentSenderState * send_state = 880 dynamic_cast<SplitFragmentSenderState *>(pkt->senderState); 881 assert(send_state); 882 delete pkt; 883 PacketPtr big_pkt = send_state->bigPkt; 884 delete send_state; 885 886 SplitMainSenderState * main_send_state = 887 dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); 888 assert(main_send_state); 889 // Record the fact that this packet is no longer outstanding. 890 assert(main_send_state->outstanding != 0); 891 main_send_state->outstanding--; 892 893 if (main_send_state->outstanding) { 894 return; 895 } else { 896 delete main_send_state; 897 big_pkt->senderState = NULL; 898 pkt = big_pkt; 899 } 900 } 901 902 _status = BaseSimpleCPU::Running; 903 904 Fault fault = curStaticInst->completeAcc(pkt, threadInfo[curThread], 905 traceData); 906 907 // keep an instruction count 908 if (fault == NoFault) 909 countInst(); 910 else if (traceData) { 911 // If there was a fault, we shouldn't trace this instruction. 912 delete traceData; 913 traceData = NULL; 914 } 915 916 delete pkt; 917 918 postExecute(); 919 920 advanceInst(fault); 921} 922 923void 924TimingSimpleCPU::updateCycleCounts() 925{ 926 const Cycles delta(curCycle() - previousCycle); 927 928 numCycles += delta; 929 930 previousCycle = curCycle(); 931} 932 933void 934TimingSimpleCPU::DcachePort::recvTimingSnoopReq(PacketPtr pkt) 935{ 936 for (ThreadID tid = 0; tid < cpu->numThreads; tid++) { 937 if (cpu->getCpuAddrMonitor(tid)->doMonitor(pkt)) { 938 cpu->wakeup(tid); 939 } 940 } 941 942 // Making it uniform across all CPUs: 943 // The CPUs need to be woken up only on an invalidation packet (when using caches) 944 // or on an incoming write packet (when not using caches) 945 // It is not necessary to wake up the processor on all incoming packets 946 if (pkt->isInvalidate() || pkt->isWrite()) { 947 for (auto &t_info : cpu->threadInfo) { 948 TheISA::handleLockedSnoop(t_info->thread, pkt, cacheBlockMask); 949 } 950 } 951} 952 953void 954TimingSimpleCPU::DcachePort::recvFunctionalSnoop(PacketPtr pkt) 955{ 956 for (ThreadID tid = 0; tid < cpu->numThreads; tid++) { 957 if (cpu->getCpuAddrMonitor(tid)->doMonitor(pkt)) { 958 cpu->wakeup(tid); 959 } 960 } 961} 962 963bool 964TimingSimpleCPU::DcachePort::recvTimingResp(PacketPtr pkt) 965{ 966 DPRINTF(SimpleCPU, "Received load/store response %#x\n", pkt->getAddr()); 967 968 // The timing CPU is not really ticked, instead it relies on the 969 // memory system (fetch and load/store) to set the pace. 970 if (!tickEvent.scheduled()) { 971 // Delay processing of returned data until next CPU clock edge 972 tickEvent.schedule(pkt, cpu->clockEdge()); 973 return true; 974 } else { 975 // In the case of a split transaction and a cache that is 976 // faster than a CPU we could get two responses in the 977 // same tick, delay the second one 978 if (!retryRespEvent.scheduled()) 979 cpu->schedule(retryRespEvent, cpu->clockEdge(Cycles(1))); 980 return false; 981 } 982} 983 984void 985TimingSimpleCPU::DcachePort::DTickEvent::process() 986{ 987 cpu->completeDataAccess(pkt); 988} 989 990void 991TimingSimpleCPU::DcachePort::recvReqRetry() 992{ 993 // we shouldn't get a retry unless we have a packet that we're 994 // waiting to transmit 995 assert(cpu->dcache_pkt != NULL); 996 assert(cpu->_status == DcacheRetry); 997 PacketPtr tmp = cpu->dcache_pkt; 998 if (tmp->senderState) { 999 // This is a packet from a split access. 1000 SplitFragmentSenderState * send_state = 1001 dynamic_cast<SplitFragmentSenderState *>(tmp->senderState); 1002 assert(send_state); 1003 PacketPtr big_pkt = send_state->bigPkt; 1004 1005 SplitMainSenderState * main_send_state = 1006 dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); 1007 assert(main_send_state); 1008 1009 if (sendTimingReq(tmp)) { 1010 // If we were able to send without retrying, record that fact 1011 // and try sending the other fragment. 1012 send_state->clearFromParent(); 1013 int other_index = main_send_state->getPendingFragment(); 1014 if (other_index > 0) { 1015 tmp = main_send_state->fragments[other_index]; 1016 cpu->dcache_pkt = tmp; 1017 if ((big_pkt->isRead() && cpu->handleReadPacket(tmp)) || 1018 (big_pkt->isWrite() && cpu->handleWritePacket())) { 1019 main_send_state->fragments[other_index] = NULL; 1020 } 1021 } else { 1022 cpu->_status = DcacheWaitResponse; 1023 // memory system takes ownership of packet 1024 cpu->dcache_pkt = NULL; 1025 } 1026 } 1027 } else if (sendTimingReq(tmp)) { 1028 cpu->_status = DcacheWaitResponse; 1029 // memory system takes ownership of packet 1030 cpu->dcache_pkt = NULL; 1031 } 1032} 1033 1034TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, 1035 Tick t) 1036 : pkt(_pkt), cpu(_cpu) 1037{ 1038 cpu->schedule(this, t); 1039} 1040 1041void 1042TimingSimpleCPU::IprEvent::process() 1043{ 1044 cpu->completeDataAccess(pkt); 1045} 1046 1047const char * 1048TimingSimpleCPU::IprEvent::description() const 1049{ 1050 return "Timing Simple CPU Delay IPR event"; 1051} 1052 1053 1054void 1055TimingSimpleCPU::printAddr(Addr a) 1056{ 1057 dcachePort.printAddr(a); 1058} 1059 1060 1061//////////////////////////////////////////////////////////////////////// 1062// 1063// TimingSimpleCPU Simulation Object 1064// 1065TimingSimpleCPU * 1066TimingSimpleCPUParams::create() 1067{ 1068 return new TimingSimpleCPU(this); 1069} 1070