timing.cc revision 12284
111308Santhony.gutierrez@amd.com/* 211308Santhony.gutierrez@amd.com * Copyright 2014 Google, Inc. 311308Santhony.gutierrez@amd.com * Copyright (c) 2010-2013,2015,2017 ARM Limited 411308Santhony.gutierrez@amd.com * All rights reserved 511308Santhony.gutierrez@amd.com * 611308Santhony.gutierrez@amd.com * The license below extends only to copyright in the software and shall 711308Santhony.gutierrez@amd.com * not be construed as granting a license to any other intellectual 811308Santhony.gutierrez@amd.com * property including but not limited to intellectual property relating 911308Santhony.gutierrez@amd.com * to a hardware implementation of the functionality of the software 1011308Santhony.gutierrez@amd.com * licensed hereunder. You may use the software subject to the license 1111308Santhony.gutierrez@amd.com * terms below provided that you ensure that this notice is replicated 1211308Santhony.gutierrez@amd.com * unmodified and in its entirety in all distributions of the software, 1311308Santhony.gutierrez@amd.com * modified or unmodified, in source code or in binary form. 1411308Santhony.gutierrez@amd.com * 1511308Santhony.gutierrez@amd.com * Copyright (c) 2002-2005 The Regents of The University of Michigan 1611308Santhony.gutierrez@amd.com * All rights reserved. 1711308Santhony.gutierrez@amd.com * 1811308Santhony.gutierrez@amd.com * Redistribution and use in source and binary forms, with or without 1911308Santhony.gutierrez@amd.com * modification, are permitted provided that the following conditions are 2011308Santhony.gutierrez@amd.com * met: redistributions of source code must retain the above copyright 2111308Santhony.gutierrez@amd.com * notice, this list of conditions and the following disclaimer; 2211308Santhony.gutierrez@amd.com * redistributions in binary form must reproduce the above copyright 2311308Santhony.gutierrez@amd.com * notice, this list of conditions and the following disclaimer in the 2411308Santhony.gutierrez@amd.com * documentation and/or other materials provided with the distribution; 2511308Santhony.gutierrez@amd.com * neither the name of the copyright holders nor the names of its 2611308Santhony.gutierrez@amd.com * contributors may be used to endorse or promote products derived from 2711308Santhony.gutierrez@amd.com * this software without specific prior written permission. 2811308Santhony.gutierrez@amd.com * 2911308Santhony.gutierrez@amd.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3011308Santhony.gutierrez@amd.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3111308Santhony.gutierrez@amd.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3211308Santhony.gutierrez@amd.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3311308Santhony.gutierrez@amd.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3411308Santhony.gutierrez@amd.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3511308Santhony.gutierrez@amd.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3611308Santhony.gutierrez@amd.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3711308Santhony.gutierrez@amd.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3811308Santhony.gutierrez@amd.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3911308Santhony.gutierrez@amd.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 4011308Santhony.gutierrez@amd.com * 4111308Santhony.gutierrez@amd.com * Authors: Steve Reinhardt 4211308Santhony.gutierrez@amd.com */ 4311308Santhony.gutierrez@amd.com 4411308Santhony.gutierrez@amd.com#include "cpu/simple/timing.hh" 4511308Santhony.gutierrez@amd.com 4611308Santhony.gutierrez@amd.com#include "arch/locked_mem.hh" 4711308Santhony.gutierrez@amd.com#include "arch/mmapped_ipr.hh" 4811308Santhony.gutierrez@amd.com#include "arch/utility.hh" 4911308Santhony.gutierrez@amd.com#include "base/bigint.hh" 5011308Santhony.gutierrez@amd.com#include "config/the_isa.hh" 5111308Santhony.gutierrez@amd.com#include "cpu/exetrace.hh" 5211308Santhony.gutierrez@amd.com#include "debug/Config.hh" 5311308Santhony.gutierrez@amd.com#include "debug/Drain.hh" 5411308Santhony.gutierrez@amd.com#include "debug/ExecFaulting.hh" 5511639Salexandru.dutu@amd.com#include "debug/Mwait.hh" 5611308Santhony.gutierrez@amd.com#include "debug/SimpleCPU.hh" 5711308Santhony.gutierrez@amd.com#include "mem/packet.hh" 5811308Santhony.gutierrez@amd.com#include "mem/packet_access.hh" 5911308Santhony.gutierrez@amd.com#include "params/TimingSimpleCPU.hh" 6011308Santhony.gutierrez@amd.com#include "sim/faults.hh" 6111639Salexandru.dutu@amd.com#include "sim/full_system.hh" 6211639Salexandru.dutu@amd.com#include "sim/system.hh" 6311639Salexandru.dutu@amd.com 6411639Salexandru.dutu@amd.comusing namespace std; 6511639Salexandru.dutu@amd.comusing namespace TheISA; 6611639Salexandru.dutu@amd.com 6711639Salexandru.dutu@amd.comvoid 6811639Salexandru.dutu@amd.comTimingSimpleCPU::init() 6911639Salexandru.dutu@amd.com{ 7011639Salexandru.dutu@amd.com BaseSimpleCPU::init(); 7111308Santhony.gutierrez@amd.com} 7211639Salexandru.dutu@amd.com 7311639Salexandru.dutu@amd.comvoid 7411308Santhony.gutierrez@amd.comTimingSimpleCPU::TimingCPUPort::TickEvent::schedule(PacketPtr _pkt, Tick t) 7511308Santhony.gutierrez@amd.com{ 7611639Salexandru.dutu@amd.com pkt = _pkt; 7711639Salexandru.dutu@amd.com cpu->schedule(this, t); 7811639Salexandru.dutu@amd.com} 7911639Salexandru.dutu@amd.com 8011308Santhony.gutierrez@amd.comTimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) 8111308Santhony.gutierrez@amd.com : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this), 8211308Santhony.gutierrez@amd.com dcachePort(this), ifetch_pkt(NULL), dcache_pkt(NULL), previousCycle(0), 8311308Santhony.gutierrez@amd.com fetchEvent([this]{ fetch(); }, name()) 8411308Santhony.gutierrez@amd.com{ 8511308Santhony.gutierrez@amd.com _status = Idle; 8611639Salexandru.dutu@amd.com} 8711639Salexandru.dutu@amd.com 8811639Salexandru.dutu@amd.com 8911639Salexandru.dutu@amd.com 9011534Sjohn.kalamatianos@amd.comTimingSimpleCPU::~TimingSimpleCPU() 9111639Salexandru.dutu@amd.com{ 9211534Sjohn.kalamatianos@amd.com} 9311308Santhony.gutierrez@amd.com 9411308Santhony.gutierrez@amd.comDrainState 9511308Santhony.gutierrez@amd.comTimingSimpleCPU::drain() 9611308Santhony.gutierrez@amd.com{ 9711308Santhony.gutierrez@amd.com // Deschedule any power gating event (if any) 9811523Sdavid.guillen@arm.com deschedulePowerGatingEvent(); 9911523Sdavid.guillen@arm.com 10011308Santhony.gutierrez@amd.com if (switchedOut()) 10111308Santhony.gutierrez@amd.com return DrainState::Drained; 10211308Santhony.gutierrez@amd.com 10311308Santhony.gutierrez@amd.com if (_status == Idle || 10411308Santhony.gutierrez@amd.com (_status == BaseSimpleCPU::Running && isDrained())) { 10511308Santhony.gutierrez@amd.com DPRINTF(Drain, "No need to drain.\n"); 10611308Santhony.gutierrez@amd.com activeThreads.clear(); 10711308Santhony.gutierrez@amd.com return DrainState::Drained; 10811308Santhony.gutierrez@amd.com } else { 10911308Santhony.gutierrez@amd.com DPRINTF(Drain, "Requesting drain.\n"); 11011308Santhony.gutierrez@amd.com 11111308Santhony.gutierrez@amd.com // The fetch event can become descheduled if a drain didn't 11211308Santhony.gutierrez@amd.com // succeed on the first attempt. We need to reschedule it if 11311308Santhony.gutierrez@amd.com // the CPU is waiting for a microcode routine to complete. 11411308Santhony.gutierrez@amd.com if (_status == BaseSimpleCPU::Running && !fetchEvent.scheduled()) 11511308Santhony.gutierrez@amd.com schedule(fetchEvent, clockEdge()); 11611308Santhony.gutierrez@amd.com 11711308Santhony.gutierrez@amd.com return DrainState::Draining; 11811308Santhony.gutierrez@amd.com } 11911308Santhony.gutierrez@amd.com} 12011308Santhony.gutierrez@amd.com 12111308Santhony.gutierrez@amd.comvoid 12211308Santhony.gutierrez@amd.comTimingSimpleCPU::drainResume() 12311308Santhony.gutierrez@amd.com{ 12411308Santhony.gutierrez@amd.com assert(!fetchEvent.scheduled()); 12511308Santhony.gutierrez@amd.com if (switchedOut()) 12611308Santhony.gutierrez@amd.com return; 12711308Santhony.gutierrez@amd.com 12811308Santhony.gutierrez@amd.com DPRINTF(SimpleCPU, "Resume\n"); 12911308Santhony.gutierrez@amd.com verifyMemoryMode(); 13011308Santhony.gutierrez@amd.com 13111308Santhony.gutierrez@amd.com assert(!threadContexts.empty()); 13211308Santhony.gutierrez@amd.com 13311308Santhony.gutierrez@amd.com _status = BaseSimpleCPU::Idle; 13411308Santhony.gutierrez@amd.com 13511308Santhony.gutierrez@amd.com for (ThreadID tid = 0; tid < numThreads; tid++) { 13611308Santhony.gutierrez@amd.com if (threadInfo[tid]->thread->status() == ThreadContext::Active) { 13711308Santhony.gutierrez@amd.com threadInfo[tid]->notIdleFraction = 1; 13811308Santhony.gutierrez@amd.com 13911308Santhony.gutierrez@amd.com activeThreads.push_back(tid); 14011308Santhony.gutierrez@amd.com 14111308Santhony.gutierrez@amd.com _status = BaseSimpleCPU::Running; 14211308Santhony.gutierrez@amd.com 14311308Santhony.gutierrez@amd.com // Fetch if any threads active 14411308Santhony.gutierrez@amd.com if (!fetchEvent.scheduled()) { 14511308Santhony.gutierrez@amd.com schedule(fetchEvent, nextCycle()); 14611308Santhony.gutierrez@amd.com } 14711308Santhony.gutierrez@amd.com } else { 14811308Santhony.gutierrez@amd.com threadInfo[tid]->notIdleFraction = 0; 14911308Santhony.gutierrez@amd.com } 15011308Santhony.gutierrez@amd.com } 15111308Santhony.gutierrez@amd.com 15211308Santhony.gutierrez@amd.com // Reschedule any power gating event (if any) 15311308Santhony.gutierrez@amd.com schedulePowerGatingEvent(); 15411534Sjohn.kalamatianos@amd.com 15511308Santhony.gutierrez@amd.com system->totalNumInsts = 0; 15611308Santhony.gutierrez@amd.com} 15711308Santhony.gutierrez@amd.com 15811640Salexandru.dutu@amd.combool 15911308Santhony.gutierrez@amd.comTimingSimpleCPU::tryCompleteDrain() 16011640Salexandru.dutu@amd.com{ 16111639Salexandru.dutu@amd.com if (drainState() != DrainState::Draining) 16211308Santhony.gutierrez@amd.com return false; 16311308Santhony.gutierrez@amd.com 16411308Santhony.gutierrez@amd.com DPRINTF(Drain, "tryCompleteDrain.\n"); 16511308Santhony.gutierrez@amd.com if (!isDrained()) 16611308Santhony.gutierrez@amd.com return false; 16711308Santhony.gutierrez@amd.com 16811308Santhony.gutierrez@amd.com DPRINTF(Drain, "CPU done draining, processing drain event\n"); 16911308Santhony.gutierrez@amd.com signalDrainDone(); 17011308Santhony.gutierrez@amd.com 17111308Santhony.gutierrez@amd.com return true; 17211308Santhony.gutierrez@amd.com} 17311308Santhony.gutierrez@amd.com 17411308Santhony.gutierrez@amd.comvoid 17511308Santhony.gutierrez@amd.comTimingSimpleCPU::switchOut() 17611308Santhony.gutierrez@amd.com{ 17711308Santhony.gutierrez@amd.com SimpleExecContext& t_info = *threadInfo[curThread]; 17811308Santhony.gutierrez@amd.com M5_VAR_USED SimpleThread* thread = t_info.thread; 17911308Santhony.gutierrez@amd.com 18011308Santhony.gutierrez@amd.com BaseSimpleCPU::switchOut(); 18111308Santhony.gutierrez@amd.com 18211308Santhony.gutierrez@amd.com assert(!fetchEvent.scheduled()); 18311308Santhony.gutierrez@amd.com assert(_status == BaseSimpleCPU::Running || _status == Idle); 18411308Santhony.gutierrez@amd.com assert(!t_info.stayAtPC); 18511308Santhony.gutierrez@amd.com assert(thread->microPC() == 0); 18611308Santhony.gutierrez@amd.com 18711308Santhony.gutierrez@amd.com updateCycleCounts(); 18811308Santhony.gutierrez@amd.com updateCycleCounters(BaseCPU::CPU_STATE_ON); 18911308Santhony.gutierrez@amd.com} 19011308Santhony.gutierrez@amd.com 19111308Santhony.gutierrez@amd.com 19211308Santhony.gutierrez@amd.comvoid 19311308Santhony.gutierrez@amd.comTimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 19411308Santhony.gutierrez@amd.com{ 19511308Santhony.gutierrez@amd.com BaseSimpleCPU::takeOverFrom(oldCPU); 19611308Santhony.gutierrez@amd.com 19711308Santhony.gutierrez@amd.com previousCycle = curCycle(); 19811308Santhony.gutierrez@amd.com} 19911308Santhony.gutierrez@amd.com 20011308Santhony.gutierrez@amd.comvoid 20111308Santhony.gutierrez@amd.comTimingSimpleCPU::verifyMemoryMode() const 20211308Santhony.gutierrez@amd.com{ 20311308Santhony.gutierrez@amd.com if (!system->isTimingMode()) { 20411308Santhony.gutierrez@amd.com fatal("The timing CPU requires the memory system to be in " 20511308Santhony.gutierrez@amd.com "'timing' mode.\n"); 20611308Santhony.gutierrez@amd.com } 20711308Santhony.gutierrez@amd.com} 20811308Santhony.gutierrez@amd.com 20911308Santhony.gutierrez@amd.comvoid 21011308Santhony.gutierrez@amd.comTimingSimpleCPU::activateContext(ThreadID thread_num) 21111308Santhony.gutierrez@amd.com{ 21211308Santhony.gutierrez@amd.com DPRINTF(SimpleCPU, "ActivateContext %d\n", thread_num); 21311308Santhony.gutierrez@amd.com 21411308Santhony.gutierrez@amd.com assert(thread_num < numThreads); 21511308Santhony.gutierrez@amd.com 21611308Santhony.gutierrez@amd.com threadInfo[thread_num]->notIdleFraction = 1; 21711308Santhony.gutierrez@amd.com if (_status == BaseSimpleCPU::Idle) 21811308Santhony.gutierrez@amd.com _status = BaseSimpleCPU::Running; 21911308Santhony.gutierrez@amd.com 22011308Santhony.gutierrez@amd.com // kick things off by initiating the fetch of the next instruction 22111308Santhony.gutierrez@amd.com if (!fetchEvent.scheduled()) 22211308Santhony.gutierrez@amd.com schedule(fetchEvent, clockEdge(Cycles(0))); 22311308Santhony.gutierrez@amd.com 22411308Santhony.gutierrez@amd.com if (std::find(activeThreads.begin(), activeThreads.end(), thread_num) 22511308Santhony.gutierrez@amd.com == activeThreads.end()) { 22611308Santhony.gutierrez@amd.com activeThreads.push_back(thread_num); 22711308Santhony.gutierrez@amd.com } 22811308Santhony.gutierrez@amd.com 22911308Santhony.gutierrez@amd.com BaseCPU::activateContext(thread_num); 23011308Santhony.gutierrez@amd.com} 23111308Santhony.gutierrez@amd.com 23211308Santhony.gutierrez@amd.com 23311308Santhony.gutierrez@amd.comvoid 23411308Santhony.gutierrez@amd.comTimingSimpleCPU::suspendContext(ThreadID thread_num) 23511308Santhony.gutierrez@amd.com{ 23611308Santhony.gutierrez@amd.com DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num); 23711308Santhony.gutierrez@amd.com 23811308Santhony.gutierrez@amd.com assert(thread_num < numThreads); 23911308Santhony.gutierrez@amd.com activeThreads.remove(thread_num); 24011308Santhony.gutierrez@amd.com 24111308Santhony.gutierrez@amd.com if (_status == Idle) 24211308Santhony.gutierrez@amd.com return; 24311308Santhony.gutierrez@amd.com 24411308Santhony.gutierrez@amd.com assert(_status == BaseSimpleCPU::Running); 24511308Santhony.gutierrez@amd.com 24611308Santhony.gutierrez@amd.com threadInfo[thread_num]->notIdleFraction = 0; 24711308Santhony.gutierrez@amd.com 24811308Santhony.gutierrez@amd.com if (activeThreads.empty()) { 24911308Santhony.gutierrez@amd.com _status = Idle; 25011308Santhony.gutierrez@amd.com 25111308Santhony.gutierrez@amd.com if (fetchEvent.scheduled()) { 25211308Santhony.gutierrez@amd.com deschedule(fetchEvent); 25311308Santhony.gutierrez@amd.com } 25411308Santhony.gutierrez@amd.com } 25511308Santhony.gutierrez@amd.com 25611308Santhony.gutierrez@amd.com BaseCPU::suspendContext(thread_num); 25711308Santhony.gutierrez@amd.com} 25811308Santhony.gutierrez@amd.com 25911308Santhony.gutierrez@amd.combool 26011308Santhony.gutierrez@amd.comTimingSimpleCPU::handleReadPacket(PacketPtr pkt) 26111308Santhony.gutierrez@amd.com{ 26211308Santhony.gutierrez@amd.com SimpleExecContext &t_info = *threadInfo[curThread]; 26311308Santhony.gutierrez@amd.com SimpleThread* thread = t_info.thread; 26411308Santhony.gutierrez@amd.com 26511308Santhony.gutierrez@amd.com RequestPtr req = pkt->req; 26611308Santhony.gutierrez@amd.com 26711308Santhony.gutierrez@amd.com // We're about the issues a locked load, so tell the monitor 26811308Santhony.gutierrez@amd.com // to start caring about this address 26911308Santhony.gutierrez@amd.com if (pkt->isRead() && pkt->req->isLLSC()) { 27011308Santhony.gutierrez@amd.com TheISA::handleLockedRead(thread, pkt->req); 27111308Santhony.gutierrez@amd.com } 27211308Santhony.gutierrez@amd.com if (req->isMmappedIpr()) { 27311308Santhony.gutierrez@amd.com Cycles delay = TheISA::handleIprRead(thread->getTC(), pkt); 27411308Santhony.gutierrez@amd.com new IprEvent(pkt, this, clockEdge(delay)); 27511308Santhony.gutierrez@amd.com _status = DcacheWaitResponse; 27611308Santhony.gutierrez@amd.com dcache_pkt = NULL; 27711308Santhony.gutierrez@amd.com } else if (!dcachePort.sendTimingReq(pkt)) { 27811308Santhony.gutierrez@amd.com _status = DcacheRetry; 27911308Santhony.gutierrez@amd.com dcache_pkt = pkt; 28011308Santhony.gutierrez@amd.com } else { 28111308Santhony.gutierrez@amd.com _status = DcacheWaitResponse; 28211308Santhony.gutierrez@amd.com // memory system takes ownership of packet 28311308Santhony.gutierrez@amd.com dcache_pkt = NULL; 28411308Santhony.gutierrez@amd.com } 28511308Santhony.gutierrez@amd.com return dcache_pkt == NULL; 28611308Santhony.gutierrez@amd.com} 28711308Santhony.gutierrez@amd.com 28811308Santhony.gutierrez@amd.comvoid 28911308Santhony.gutierrez@amd.comTimingSimpleCPU::sendData(RequestPtr req, uint8_t *data, uint64_t *res, 29011308Santhony.gutierrez@amd.com bool read) 29111308Santhony.gutierrez@amd.com{ 29211308Santhony.gutierrez@amd.com SimpleExecContext &t_info = *threadInfo[curThread]; 29311308Santhony.gutierrez@amd.com SimpleThread* thread = t_info.thread; 29411308Santhony.gutierrez@amd.com 29511308Santhony.gutierrez@amd.com PacketPtr pkt = buildPacket(req, read); 29611308Santhony.gutierrez@amd.com pkt->dataDynamic<uint8_t>(data); 29711308Santhony.gutierrez@amd.com if (req->getFlags().isSet(Request::NO_ACCESS)) { 29811308Santhony.gutierrez@amd.com assert(!dcache_pkt); 29911308Santhony.gutierrez@amd.com pkt->makeResponse(); 30011308Santhony.gutierrez@amd.com completeDataAccess(pkt); 30111308Santhony.gutierrez@amd.com } else if (read) { 30211308Santhony.gutierrez@amd.com handleReadPacket(pkt); 30311308Santhony.gutierrez@amd.com } else { 30411308Santhony.gutierrez@amd.com bool do_access = true; // flag to suppress cache access 30511308Santhony.gutierrez@amd.com 30611308Santhony.gutierrez@amd.com if (req->isLLSC()) { 30711308Santhony.gutierrez@amd.com do_access = TheISA::handleLockedWrite(thread, req, dcachePort.cacheBlockMask); 30811308Santhony.gutierrez@amd.com } else if (req->isCondSwap()) { 30911308Santhony.gutierrez@amd.com assert(res); 31011308Santhony.gutierrez@amd.com req->setExtraData(*res); 31111308Santhony.gutierrez@amd.com } 31211308Santhony.gutierrez@amd.com 31311308Santhony.gutierrez@amd.com if (do_access) { 31411308Santhony.gutierrez@amd.com dcache_pkt = pkt; 31511308Santhony.gutierrez@amd.com handleWritePacket(); 31611308Santhony.gutierrez@amd.com threadSnoop(pkt, curThread); 31711308Santhony.gutierrez@amd.com } else { 31811308Santhony.gutierrez@amd.com _status = DcacheWaitResponse; 31911308Santhony.gutierrez@amd.com completeDataAccess(pkt); 32011308Santhony.gutierrez@amd.com } 32111308Santhony.gutierrez@amd.com } 32211308Santhony.gutierrez@amd.com} 32311308Santhony.gutierrez@amd.com 32411308Santhony.gutierrez@amd.comvoid 32511308Santhony.gutierrez@amd.comTimingSimpleCPU::sendSplitData(RequestPtr req1, RequestPtr req2, 32611308Santhony.gutierrez@amd.com RequestPtr req, uint8_t *data, bool read) 32711308Santhony.gutierrez@amd.com{ 32811308Santhony.gutierrez@amd.com PacketPtr pkt1, pkt2; 32911308Santhony.gutierrez@amd.com buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read); 33011308Santhony.gutierrez@amd.com if (req->getFlags().isSet(Request::NO_ACCESS)) { 33111308Santhony.gutierrez@amd.com assert(!dcache_pkt); 33211308Santhony.gutierrez@amd.com pkt1->makeResponse(); 33311308Santhony.gutierrez@amd.com completeDataAccess(pkt1); 33411308Santhony.gutierrez@amd.com } else if (read) { 33511308Santhony.gutierrez@amd.com SplitFragmentSenderState * send_state = 33611639Salexandru.dutu@amd.com dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 33711639Salexandru.dutu@amd.com if (handleReadPacket(pkt1)) { 33811308Santhony.gutierrez@amd.com send_state->clearFromParent(); 33911308Santhony.gutierrez@amd.com send_state = dynamic_cast<SplitFragmentSenderState *>( 34011308Santhony.gutierrez@amd.com pkt2->senderState); 34111639Salexandru.dutu@amd.com if (handleReadPacket(pkt2)) { 34211308Santhony.gutierrez@amd.com send_state->clearFromParent(); 34311308Santhony.gutierrez@amd.com } 34411308Santhony.gutierrez@amd.com } 34511308Santhony.gutierrez@amd.com } else { 34611308Santhony.gutierrez@amd.com dcache_pkt = pkt1; 34711308Santhony.gutierrez@amd.com SplitFragmentSenderState * send_state = 34811308Santhony.gutierrez@amd.com dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 34911308Santhony.gutierrez@amd.com if (handleWritePacket()) { 35011308Santhony.gutierrez@amd.com send_state->clearFromParent(); 35111308Santhony.gutierrez@amd.com dcache_pkt = pkt2; 35211308Santhony.gutierrez@amd.com send_state = dynamic_cast<SplitFragmentSenderState *>( 35311308Santhony.gutierrez@amd.com pkt2->senderState); 35411308Santhony.gutierrez@amd.com if (handleWritePacket()) { 35511308Santhony.gutierrez@amd.com send_state->clearFromParent(); 35611308Santhony.gutierrez@amd.com } 35711308Santhony.gutierrez@amd.com } 35811308Santhony.gutierrez@amd.com } 35911308Santhony.gutierrez@amd.com} 36011308Santhony.gutierrez@amd.com 36111345Sjohn.kalamatianos@amd.comvoid 36211308Santhony.gutierrez@amd.comTimingSimpleCPU::translationFault(const Fault &fault) 36311308Santhony.gutierrez@amd.com{ 36411308Santhony.gutierrez@amd.com // fault may be NoFault in cases where a fault is suppressed, 36511308Santhony.gutierrez@amd.com // for instance prefetches. 36611308Santhony.gutierrez@amd.com updateCycleCounts(); 36711308Santhony.gutierrez@amd.com updateCycleCounters(BaseCPU::CPU_STATE_ON); 36811308Santhony.gutierrez@amd.com 36911308Santhony.gutierrez@amd.com if (traceData) { 37011308Santhony.gutierrez@amd.com // Since there was a fault, we shouldn't trace this instruction. 37111308Santhony.gutierrez@amd.com delete traceData; 37211308Santhony.gutierrez@amd.com traceData = NULL; 37311308Santhony.gutierrez@amd.com } 37411308Santhony.gutierrez@amd.com 37511308Santhony.gutierrez@amd.com postExecute(); 37611308Santhony.gutierrez@amd.com 37711308Santhony.gutierrez@amd.com advanceInst(fault); 37811308Santhony.gutierrez@amd.com} 37911308Santhony.gutierrez@amd.com 38011308Santhony.gutierrez@amd.comPacketPtr 38111308Santhony.gutierrez@amd.comTimingSimpleCPU::buildPacket(RequestPtr req, bool read) 38211308Santhony.gutierrez@amd.com{ 38311308Santhony.gutierrez@amd.com return read ? Packet::createRead(req) : Packet::createWrite(req); 38411308Santhony.gutierrez@amd.com} 38511308Santhony.gutierrez@amd.com 38611308Santhony.gutierrez@amd.comvoid 38711308Santhony.gutierrez@amd.comTimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, 38811308Santhony.gutierrez@amd.com RequestPtr req1, RequestPtr req2, RequestPtr req, 38911308Santhony.gutierrez@amd.com uint8_t *data, bool read) 39011308Santhony.gutierrez@amd.com{ 39111308Santhony.gutierrez@amd.com pkt1 = pkt2 = NULL; 39211308Santhony.gutierrez@amd.com 39311308Santhony.gutierrez@amd.com assert(!req1->isMmappedIpr() && !req2->isMmappedIpr()); 39411308Santhony.gutierrez@amd.com 39511308Santhony.gutierrez@amd.com if (req->getFlags().isSet(Request::NO_ACCESS)) { 39611308Santhony.gutierrez@amd.com pkt1 = buildPacket(req, read); 39711308Santhony.gutierrez@amd.com return; 39811639Salexandru.dutu@amd.com } 39911308Santhony.gutierrez@amd.com 40011308Santhony.gutierrez@amd.com pkt1 = buildPacket(req1, read); 40111308Santhony.gutierrez@amd.com pkt2 = buildPacket(req2, read); 40211308Santhony.gutierrez@amd.com 40311308Santhony.gutierrez@amd.com PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand()); 40411308Santhony.gutierrez@amd.com 40511308Santhony.gutierrez@amd.com pkt->dataDynamic<uint8_t>(data); 40611308Santhony.gutierrez@amd.com pkt1->dataStatic<uint8_t>(data); 40711308Santhony.gutierrez@amd.com pkt2->dataStatic<uint8_t>(data + req1->getSize()); 40811308Santhony.gutierrez@amd.com 40911308Santhony.gutierrez@amd.com SplitMainSenderState * main_send_state = new SplitMainSenderState; 41011308Santhony.gutierrez@amd.com pkt->senderState = main_send_state; 41111308Santhony.gutierrez@amd.com main_send_state->fragments[0] = pkt1; 41211308Santhony.gutierrez@amd.com main_send_state->fragments[1] = pkt2; 41311308Santhony.gutierrez@amd.com main_send_state->outstanding = 2; 41411308Santhony.gutierrez@amd.com pkt1->senderState = new SplitFragmentSenderState(pkt, 0); 41511308Santhony.gutierrez@amd.com pkt2->senderState = new SplitFragmentSenderState(pkt, 1); 41611308Santhony.gutierrez@amd.com} 41711308Santhony.gutierrez@amd.com 41811308Santhony.gutierrez@amd.comFault 41911639Salexandru.dutu@amd.comTimingSimpleCPU::readMem(Addr addr, uint8_t *data, 42011308Santhony.gutierrez@amd.com unsigned size, Request::Flags flags) 42111308Santhony.gutierrez@amd.com{ 42211308Santhony.gutierrez@amd.com panic("readMem() is for atomic accesses, and should " 42311308Santhony.gutierrez@amd.com "never be called on TimingSimpleCPU.\n"); 42411308Santhony.gutierrez@amd.com} 42511308Santhony.gutierrez@amd.com 42611308Santhony.gutierrez@amd.comFault 42711308Santhony.gutierrez@amd.comTimingSimpleCPU::initiateMemRead(Addr addr, unsigned size, 42811308Santhony.gutierrez@amd.com Request::Flags flags) 42911308Santhony.gutierrez@amd.com{ 43011308Santhony.gutierrez@amd.com SimpleExecContext &t_info = *threadInfo[curThread]; 43111308Santhony.gutierrez@amd.com SimpleThread* thread = t_info.thread; 43211308Santhony.gutierrez@amd.com 43311308Santhony.gutierrez@amd.com Fault fault; 43411308Santhony.gutierrez@amd.com const int asid = 0; 43511308Santhony.gutierrez@amd.com const Addr pc = thread->instAddr(); 43611308Santhony.gutierrez@amd.com unsigned block_size = cacheLineSize(); 43711308Santhony.gutierrez@amd.com BaseTLB::Mode mode = BaseTLB::Read; 43811308Santhony.gutierrez@amd.com 43911308Santhony.gutierrez@amd.com if (traceData) 44011308Santhony.gutierrez@amd.com traceData->setMem(addr, size, flags); 44111308Santhony.gutierrez@amd.com 44211308Santhony.gutierrez@amd.com RequestPtr req = new Request(asid, addr, size, flags, dataMasterId(), pc, 44311308Santhony.gutierrez@amd.com thread->contextId()); 44411308Santhony.gutierrez@amd.com 44511308Santhony.gutierrez@amd.com req->taskId(taskId()); 44611308Santhony.gutierrez@amd.com 44711639Salexandru.dutu@amd.com Addr split_addr = roundDown(addr + size - 1, block_size); 44811308Santhony.gutierrez@amd.com assert(split_addr <= addr || split_addr - addr < block_size); 44911308Santhony.gutierrez@amd.com 45011308Santhony.gutierrez@amd.com _status = DTBWaitResponse; 45111308Santhony.gutierrez@amd.com if (split_addr > addr) { 45211308Santhony.gutierrez@amd.com RequestPtr req1, req2; 45311308Santhony.gutierrez@amd.com assert(!req->isLLSC() && !req->isSwap()); 45411308Santhony.gutierrez@amd.com req->splitOnVaddr(split_addr, req1, req2); 45511639Salexandru.dutu@amd.com 45611308Santhony.gutierrez@amd.com WholeTranslationState *state = 45711308Santhony.gutierrez@amd.com new WholeTranslationState(req, req1, req2, new uint8_t[size], 45811308Santhony.gutierrez@amd.com NULL, mode); 45911308Santhony.gutierrez@amd.com DataTranslation<TimingSimpleCPU *> *trans1 = 46011308Santhony.gutierrez@amd.com new DataTranslation<TimingSimpleCPU *>(this, state, 0); 46111308Santhony.gutierrez@amd.com DataTranslation<TimingSimpleCPU *> *trans2 = 46211308Santhony.gutierrez@amd.com new DataTranslation<TimingSimpleCPU *>(this, state, 1); 46311308Santhony.gutierrez@amd.com 46411308Santhony.gutierrez@amd.com thread->dtb->translateTiming(req1, thread->getTC(), trans1, mode); 46511308Santhony.gutierrez@amd.com thread->dtb->translateTiming(req2, thread->getTC(), trans2, mode); 46611308Santhony.gutierrez@amd.com } else { 46711308Santhony.gutierrez@amd.com WholeTranslationState *state = 46811308Santhony.gutierrez@amd.com new WholeTranslationState(req, new uint8_t[size], NULL, mode); 46911308Santhony.gutierrez@amd.com DataTranslation<TimingSimpleCPU *> *translation 47011639Salexandru.dutu@amd.com = new DataTranslation<TimingSimpleCPU *>(this, state); 47111308Santhony.gutierrez@amd.com thread->dtb->translateTiming(req, thread->getTC(), translation, mode); 47211308Santhony.gutierrez@amd.com } 47311308Santhony.gutierrez@amd.com 47411308Santhony.gutierrez@amd.com return NoFault; 47511308Santhony.gutierrez@amd.com} 47611308Santhony.gutierrez@amd.com 47711308Santhony.gutierrez@amd.combool 47811308Santhony.gutierrez@amd.comTimingSimpleCPU::handleWritePacket() 47911308Santhony.gutierrez@amd.com{ 48011308Santhony.gutierrez@amd.com SimpleExecContext &t_info = *threadInfo[curThread]; 48111308Santhony.gutierrez@amd.com SimpleThread* thread = t_info.thread; 48211308Santhony.gutierrez@amd.com 48311308Santhony.gutierrez@amd.com RequestPtr req = dcache_pkt->req; 48411308Santhony.gutierrez@amd.com if (req->isMmappedIpr()) { 48511308Santhony.gutierrez@amd.com Cycles delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); 48611308Santhony.gutierrez@amd.com new IprEvent(dcache_pkt, this, clockEdge(delay)); 48711639Salexandru.dutu@amd.com _status = DcacheWaitResponse; 48811308Santhony.gutierrez@amd.com dcache_pkt = NULL; 48911308Santhony.gutierrez@amd.com } else if (!dcachePort.sendTimingReq(dcache_pkt)) { 49011308Santhony.gutierrez@amd.com _status = DcacheRetry; 49111308Santhony.gutierrez@amd.com } else { 49211308Santhony.gutierrez@amd.com _status = DcacheWaitResponse; 49311308Santhony.gutierrez@amd.com // memory system takes ownership of packet 49411639Salexandru.dutu@amd.com dcache_pkt = NULL; 49511308Santhony.gutierrez@amd.com } 49611308Santhony.gutierrez@amd.com return dcache_pkt == NULL; 49711308Santhony.gutierrez@amd.com} 49811308Santhony.gutierrez@amd.com 49911308Santhony.gutierrez@amd.comFault 50011308Santhony.gutierrez@amd.comTimingSimpleCPU::writeMem(uint8_t *data, unsigned size, 50111308Santhony.gutierrez@amd.com Addr addr, Request::Flags flags, uint64_t *res) 50211308Santhony.gutierrez@amd.com{ 50311308Santhony.gutierrez@amd.com SimpleExecContext &t_info = *threadInfo[curThread]; 50411308Santhony.gutierrez@amd.com SimpleThread* thread = t_info.thread; 50511308Santhony.gutierrez@amd.com 50611308Santhony.gutierrez@amd.com uint8_t *newData = new uint8_t[size]; 50711308Santhony.gutierrez@amd.com const int asid = 0; 50811308Santhony.gutierrez@amd.com const Addr pc = thread->instAddr(); 50911639Salexandru.dutu@amd.com unsigned block_size = cacheLineSize(); 51011308Santhony.gutierrez@amd.com BaseTLB::Mode mode = BaseTLB::Write; 51111308Santhony.gutierrez@amd.com 51211308Santhony.gutierrez@amd.com if (data == NULL) { 51311308Santhony.gutierrez@amd.com assert(flags & Request::CACHE_BLOCK_ZERO); 51411308Santhony.gutierrez@amd.com // This must be a cache block cleaning request 51511308Santhony.gutierrez@amd.com memset(newData, 0, size); 51611308Santhony.gutierrez@amd.com } else { 51711308Santhony.gutierrez@amd.com memcpy(newData, data, size); 51811308Santhony.gutierrez@amd.com } 51911308Santhony.gutierrez@amd.com 52011308Santhony.gutierrez@amd.com if (traceData) 52111308Santhony.gutierrez@amd.com traceData->setMem(addr, size, flags); 52211308Santhony.gutierrez@amd.com 52311308Santhony.gutierrez@amd.com RequestPtr req = new Request(asid, addr, size, flags, dataMasterId(), pc, 52411308Santhony.gutierrez@amd.com thread->contextId()); 52511308Santhony.gutierrez@amd.com 52611639Salexandru.dutu@amd.com req->taskId(taskId()); 52711308Santhony.gutierrez@amd.com 52811308Santhony.gutierrez@amd.com Addr split_addr = roundDown(addr + size - 1, block_size); 52911308Santhony.gutierrez@amd.com assert(split_addr <= addr || split_addr - addr < block_size); 53011308Santhony.gutierrez@amd.com 53111308Santhony.gutierrez@amd.com _status = DTBWaitResponse; 53211308Santhony.gutierrez@amd.com if (split_addr > addr) { 53311639Salexandru.dutu@amd.com RequestPtr req1, req2; 53411308Santhony.gutierrez@amd.com assert(!req->isLLSC() && !req->isSwap()); 53511308Santhony.gutierrez@amd.com req->splitOnVaddr(split_addr, req1, req2); 53611308Santhony.gutierrez@amd.com 53711308Santhony.gutierrez@amd.com WholeTranslationState *state = 53811308Santhony.gutierrez@amd.com new WholeTranslationState(req, req1, req2, newData, res, mode); 53911308Santhony.gutierrez@amd.com DataTranslation<TimingSimpleCPU *> *trans1 = 54011308Santhony.gutierrez@amd.com new DataTranslation<TimingSimpleCPU *>(this, state, 0); 54111308Santhony.gutierrez@amd.com DataTranslation<TimingSimpleCPU *> *trans2 = 54211308Santhony.gutierrez@amd.com new DataTranslation<TimingSimpleCPU *>(this, state, 1); 54311308Santhony.gutierrez@amd.com 54411308Santhony.gutierrez@amd.com thread->dtb->translateTiming(req1, thread->getTC(), trans1, mode); 54511308Santhony.gutierrez@amd.com thread->dtb->translateTiming(req2, thread->getTC(), trans2, mode); 54611308Santhony.gutierrez@amd.com } else { 54711308Santhony.gutierrez@amd.com WholeTranslationState *state = 54811308Santhony.gutierrez@amd.com new WholeTranslationState(req, newData, res, mode); 54911639Salexandru.dutu@amd.com DataTranslation<TimingSimpleCPU *> *translation = 55011308Santhony.gutierrez@amd.com new DataTranslation<TimingSimpleCPU *>(this, state); 55111308Santhony.gutierrez@amd.com thread->dtb->translateTiming(req, thread->getTC(), translation, mode); 55211308Santhony.gutierrez@amd.com } 55311308Santhony.gutierrez@amd.com 55411308Santhony.gutierrez@amd.com // Translation faults will be returned via finishTranslation() 55511308Santhony.gutierrez@amd.com return NoFault; 55611308Santhony.gutierrez@amd.com} 55711308Santhony.gutierrez@amd.com 55811308Santhony.gutierrez@amd.comvoid 55911308Santhony.gutierrez@amd.comTimingSimpleCPU::threadSnoop(PacketPtr pkt, ThreadID sender) 56011308Santhony.gutierrez@amd.com{ 56111308Santhony.gutierrez@amd.com for (ThreadID tid = 0; tid < numThreads; tid++) { 56211308Santhony.gutierrez@amd.com if (tid != sender) { 56311308Santhony.gutierrez@amd.com if (getCpuAddrMonitor(tid)->doMonitor(pkt)) { 56411308Santhony.gutierrez@amd.com wakeup(tid); 56511308Santhony.gutierrez@amd.com } 56611308Santhony.gutierrez@amd.com TheISA::handleLockedSnoop(threadInfo[tid]->thread, pkt, 56711308Santhony.gutierrez@amd.com dcachePort.cacheBlockMask); 56811308Santhony.gutierrez@amd.com } 56911308Santhony.gutierrez@amd.com } 57011308Santhony.gutierrez@amd.com} 57111308Santhony.gutierrez@amd.com 57211308Santhony.gutierrez@amd.comvoid 57311308Santhony.gutierrez@amd.comTimingSimpleCPU::finishTranslation(WholeTranslationState *state) 57411308Santhony.gutierrez@amd.com{ 57511308Santhony.gutierrez@amd.com _status = BaseSimpleCPU::Running; 57611308Santhony.gutierrez@amd.com 57711308Santhony.gutierrez@amd.com if (state->getFault() != NoFault) { 57811308Santhony.gutierrez@amd.com if (state->isPrefetch()) { 57911308Santhony.gutierrez@amd.com state->setNoFault(); 58011308Santhony.gutierrez@amd.com } 58111308Santhony.gutierrez@amd.com delete [] state->data; 58211639Salexandru.dutu@amd.com state->deleteReqs(); 58311308Santhony.gutierrez@amd.com translationFault(state->getFault()); 58411308Santhony.gutierrez@amd.com } else { 58511308Santhony.gutierrez@amd.com if (!state->isSplit) { 58611308Santhony.gutierrez@amd.com sendData(state->mainReq, state->data, state->res, 58711308Santhony.gutierrez@amd.com state->mode == BaseTLB::Read); 58811639Salexandru.dutu@amd.com } else { 58911308Santhony.gutierrez@amd.com sendSplitData(state->sreqLow, state->sreqHigh, state->mainReq, 59011308Santhony.gutierrez@amd.com state->data, state->mode == BaseTLB::Read); 59111308Santhony.gutierrez@amd.com } 59211308Santhony.gutierrez@amd.com } 59311308Santhony.gutierrez@amd.com 59411308Santhony.gutierrez@amd.com delete state; 59511308Santhony.gutierrez@amd.com} 59611308Santhony.gutierrez@amd.com 59711308Santhony.gutierrez@amd.com 59811308Santhony.gutierrez@amd.comvoid 59911308Santhony.gutierrez@amd.comTimingSimpleCPU::fetch() 60011308Santhony.gutierrez@amd.com{ 60111308Santhony.gutierrez@amd.com // Change thread if multi-threaded 60211308Santhony.gutierrez@amd.com swapActiveThread(); 60311308Santhony.gutierrez@amd.com 60411308Santhony.gutierrez@amd.com SimpleExecContext &t_info = *threadInfo[curThread]; 60511308Santhony.gutierrez@amd.com SimpleThread* thread = t_info.thread; 60611308Santhony.gutierrez@amd.com 60711308Santhony.gutierrez@amd.com DPRINTF(SimpleCPU, "Fetch\n"); 60811308Santhony.gutierrez@amd.com 60911308Santhony.gutierrez@amd.com if (!curStaticInst || !curStaticInst->isDelayedCommit()) { 61011308Santhony.gutierrez@amd.com checkForInterrupts(); 61111308Santhony.gutierrez@amd.com checkPcEventQueue(); 61211308Santhony.gutierrez@amd.com } 61311308Santhony.gutierrez@amd.com 61411308Santhony.gutierrez@amd.com // We must have just got suspended by a PC event 61511308Santhony.gutierrez@amd.com if (_status == Idle) 61611308Santhony.gutierrez@amd.com return; 61711308Santhony.gutierrez@amd.com 61811308Santhony.gutierrez@amd.com TheISA::PCState pcState = thread->pcState(); 61911308Santhony.gutierrez@amd.com bool needToFetch = !isRomMicroPC(pcState.microPC()) && 62011308Santhony.gutierrez@amd.com !curMacroStaticInst; 62111308Santhony.gutierrez@amd.com 62211308Santhony.gutierrez@amd.com if (needToFetch) { 62311308Santhony.gutierrez@amd.com _status = BaseSimpleCPU::Running; 62411308Santhony.gutierrez@amd.com Request *ifetch_req = new Request(); 62511308Santhony.gutierrez@amd.com ifetch_req->taskId(taskId()); 62611308Santhony.gutierrez@amd.com ifetch_req->setContext(thread->contextId()); 62711308Santhony.gutierrez@amd.com setupFetchRequest(ifetch_req); 62811308Santhony.gutierrez@amd.com DPRINTF(SimpleCPU, "Translating address %#x\n", ifetch_req->getVaddr()); 62911308Santhony.gutierrez@amd.com thread->itb->translateTiming(ifetch_req, thread->getTC(), 63011308Santhony.gutierrez@amd.com &fetchTranslation, BaseTLB::Execute); 63111308Santhony.gutierrez@amd.com } else { 63211308Santhony.gutierrez@amd.com _status = IcacheWaitResponse; 63311308Santhony.gutierrez@amd.com completeIfetch(NULL); 63411308Santhony.gutierrez@amd.com 63511308Santhony.gutierrez@amd.com updateCycleCounts(); 63611308Santhony.gutierrez@amd.com updateCycleCounters(BaseCPU::CPU_STATE_ON); 63711308Santhony.gutierrez@amd.com } 63811308Santhony.gutierrez@amd.com} 63911639Salexandru.dutu@amd.com 64011639Salexandru.dutu@amd.com 64111308Santhony.gutierrez@amd.comvoid 64211308Santhony.gutierrez@amd.comTimingSimpleCPU::sendFetch(const Fault &fault, RequestPtr req, 64311308Santhony.gutierrez@amd.com ThreadContext *tc) 64411308Santhony.gutierrez@amd.com{ 64511308Santhony.gutierrez@amd.com if (fault == NoFault) { 64611308Santhony.gutierrez@amd.com DPRINTF(SimpleCPU, "Sending fetch for addr %#x(pa: %#x)\n", 64711308Santhony.gutierrez@amd.com req->getVaddr(), req->getPaddr()); 64811308Santhony.gutierrez@amd.com ifetch_pkt = new Packet(req, MemCmd::ReadReq); 64911308Santhony.gutierrez@amd.com ifetch_pkt->dataStatic(&inst); 65011308Santhony.gutierrez@amd.com DPRINTF(SimpleCPU, " -- pkt addr: %#x\n", ifetch_pkt->getAddr()); 65111308Santhony.gutierrez@amd.com 65211308Santhony.gutierrez@amd.com if (!icachePort.sendTimingReq(ifetch_pkt)) { 65311308Santhony.gutierrez@amd.com // Need to wait for retry 65411639Salexandru.dutu@amd.com _status = IcacheRetry; 65511639Salexandru.dutu@amd.com } else { 65611308Santhony.gutierrez@amd.com // Need to wait for cache to respond 65711308Santhony.gutierrez@amd.com _status = IcacheWaitResponse; 65811308Santhony.gutierrez@amd.com // ownership of packet transferred to memory system 65911308Santhony.gutierrez@amd.com ifetch_pkt = NULL; 66011308Santhony.gutierrez@amd.com } 66111308Santhony.gutierrez@amd.com } else { 66211308Santhony.gutierrez@amd.com DPRINTF(SimpleCPU, "Translation of addr %#x faulted\n", req->getVaddr()); 66311308Santhony.gutierrez@amd.com delete req; 66411308Santhony.gutierrez@amd.com // fetch fault: advance directly to next instruction (fault handler) 66511308Santhony.gutierrez@amd.com _status = BaseSimpleCPU::Running; 66611308Santhony.gutierrez@amd.com advanceInst(fault); 66711308Santhony.gutierrez@amd.com } 66811639Salexandru.dutu@amd.com 66911639Salexandru.dutu@amd.com updateCycleCounts(); 67011308Santhony.gutierrez@amd.com updateCycleCounters(BaseCPU::CPU_STATE_ON); 67111308Santhony.gutierrez@amd.com} 67211308Santhony.gutierrez@amd.com 67311308Santhony.gutierrez@amd.com 67411308Santhony.gutierrez@amd.comvoid 67511639Salexandru.dutu@amd.comTimingSimpleCPU::advanceInst(const Fault &fault) 67611639Salexandru.dutu@amd.com{ 67711308Santhony.gutierrez@amd.com SimpleExecContext &t_info = *threadInfo[curThread]; 67811308Santhony.gutierrez@amd.com 67911308Santhony.gutierrez@amd.com if (_status == Faulting) 68011308Santhony.gutierrez@amd.com return; 68111308Santhony.gutierrez@amd.com 68211639Salexandru.dutu@amd.com if (fault != NoFault) { 68311639Salexandru.dutu@amd.com DPRINTF(SimpleCPU, "Fault occured, scheduling fetch event\n"); 68411639Salexandru.dutu@amd.com 68511308Santhony.gutierrez@amd.com advancePC(fault); 68611308Santhony.gutierrez@amd.com 68711308Santhony.gutierrez@amd.com Tick stall = dynamic_pointer_cast<SyscallRetryFault>(fault) ? 68811308Santhony.gutierrez@amd.com clockEdge(syscallRetryLatency) : clockEdge(); 68911308Santhony.gutierrez@amd.com 69011639Salexandru.dutu@amd.com reschedule(fetchEvent, stall, true); 69111639Salexandru.dutu@amd.com 69211308Santhony.gutierrez@amd.com _status = Faulting; 69311308Santhony.gutierrez@amd.com return; 69411308Santhony.gutierrez@amd.com } 69511308Santhony.gutierrez@amd.com 69611308Santhony.gutierrez@amd.com 69711639Salexandru.dutu@amd.com if (!t_info.stayAtPC) 69811639Salexandru.dutu@amd.com advancePC(fault); 69911308Santhony.gutierrez@amd.com 70011308Santhony.gutierrez@amd.com if (tryCompleteDrain()) 70111308Santhony.gutierrez@amd.com return; 70211308Santhony.gutierrez@amd.com 70311308Santhony.gutierrez@amd.com if (_status == BaseSimpleCPU::Running) { 70411639Salexandru.dutu@amd.com // kick off fetch of next instruction... callback from icache 70511639Salexandru.dutu@amd.com // response will cause that instruction to be executed, 70611639Salexandru.dutu@amd.com // keeping the CPU running. 70711308Santhony.gutierrez@amd.com fetch(); 70811308Santhony.gutierrez@amd.com } 70911308Santhony.gutierrez@amd.com} 71011308Santhony.gutierrez@amd.com 71111308Santhony.gutierrez@amd.com 71211639Salexandru.dutu@amd.comvoid 71311639Salexandru.dutu@amd.comTimingSimpleCPU::completeIfetch(PacketPtr pkt) 71411308Santhony.gutierrez@amd.com{ 71511308Santhony.gutierrez@amd.com SimpleExecContext& t_info = *threadInfo[curThread]; 71611308Santhony.gutierrez@amd.com 71711308Santhony.gutierrez@amd.com DPRINTF(SimpleCPU, "Complete ICache Fetch for addr %#x\n", pkt ? 71811308Santhony.gutierrez@amd.com pkt->getAddr() : 0); 71911639Salexandru.dutu@amd.com 72011639Salexandru.dutu@amd.com // received a response from the icache: execute the received 72111308Santhony.gutierrez@amd.com // instruction 72211308Santhony.gutierrez@amd.com assert(!pkt || !pkt->isError()); 72311308Santhony.gutierrez@amd.com assert(_status == IcacheWaitResponse); 72411308Santhony.gutierrez@amd.com 72511308Santhony.gutierrez@amd.com _status = BaseSimpleCPU::Running; 72611639Salexandru.dutu@amd.com 72711639Salexandru.dutu@amd.com updateCycleCounts(); 72811639Salexandru.dutu@amd.com updateCycleCounters(BaseCPU::CPU_STATE_ON); 72911308Santhony.gutierrez@amd.com 73011308Santhony.gutierrez@amd.com if (pkt) 73111308Santhony.gutierrez@amd.com pkt->req->setAccessLatency(); 73211308Santhony.gutierrez@amd.com 73311308Santhony.gutierrez@amd.com 73411308Santhony.gutierrez@amd.com preExecute(); 73511308Santhony.gutierrez@amd.com if (curStaticInst && curStaticInst->isMemRef()) { 73611308Santhony.gutierrez@amd.com // load or store: just send to dcache 73711308Santhony.gutierrez@amd.com Fault fault = curStaticInst->initiateAcc(&t_info, traceData); 73811308Santhony.gutierrez@amd.com 73911308Santhony.gutierrez@amd.com // If we're not running now the instruction will complete in a dcache 74011308Santhony.gutierrez@amd.com // response callback or the instruction faulted and has started an 74111308Santhony.gutierrez@amd.com // ifetch 74211308Santhony.gutierrez@amd.com if (_status == BaseSimpleCPU::Running) { 74311308Santhony.gutierrez@amd.com if (fault != NoFault && traceData) { 74411308Santhony.gutierrez@amd.com // If there was a fault, we shouldn't trace this instruction. 74511308Santhony.gutierrez@amd.com delete traceData; 74611308Santhony.gutierrez@amd.com traceData = NULL; 74711308Santhony.gutierrez@amd.com } 74811308Santhony.gutierrez@amd.com 74911308Santhony.gutierrez@amd.com postExecute(); 75011308Santhony.gutierrez@amd.com // @todo remove me after debugging with legion done 75111308Santhony.gutierrez@amd.com if (curStaticInst && (!curStaticInst->isMicroop() || 75211308Santhony.gutierrez@amd.com curStaticInst->isFirstMicroop())) 75311308Santhony.gutierrez@amd.com instCnt++; 75411308Santhony.gutierrez@amd.com advanceInst(fault); 75511308Santhony.gutierrez@amd.com } 75611308Santhony.gutierrez@amd.com } else if (curStaticInst) { 75711308Santhony.gutierrez@amd.com // non-memory instruction: execute completely now 75811308Santhony.gutierrez@amd.com Fault fault = curStaticInst->execute(&t_info, traceData); 75911308Santhony.gutierrez@amd.com 76011308Santhony.gutierrez@amd.com // keep an instruction count 76111308Santhony.gutierrez@amd.com if (fault == NoFault) 76211308Santhony.gutierrez@amd.com countInst(); 76311308Santhony.gutierrez@amd.com else if (traceData && !DTRACE(ExecFaulting)) { 76411308Santhony.gutierrez@amd.com delete traceData; 76511308Santhony.gutierrez@amd.com traceData = NULL; 76611308Santhony.gutierrez@amd.com } 76711308Santhony.gutierrez@amd.com 76811308Santhony.gutierrez@amd.com postExecute(); 76911308Santhony.gutierrez@amd.com // @todo remove me after debugging with legion done 77011308Santhony.gutierrez@amd.com if (curStaticInst && (!curStaticInst->isMicroop() || 77111308Santhony.gutierrez@amd.com curStaticInst->isFirstMicroop())) 77211308Santhony.gutierrez@amd.com instCnt++; 77311308Santhony.gutierrez@amd.com advanceInst(fault); 77411308Santhony.gutierrez@amd.com } else { 77511308Santhony.gutierrez@amd.com advanceInst(NoFault); 77611308Santhony.gutierrez@amd.com } 77711308Santhony.gutierrez@amd.com 77811308Santhony.gutierrez@amd.com if (pkt) { 77911308Santhony.gutierrez@amd.com delete pkt->req; 78011308Santhony.gutierrez@amd.com delete pkt; 78111308Santhony.gutierrez@amd.com } 78211308Santhony.gutierrez@amd.com} 78311308Santhony.gutierrez@amd.com 78411308Santhony.gutierrez@amd.comvoid 78511308Santhony.gutierrez@amd.comTimingSimpleCPU::IcachePort::ITickEvent::process() 78611308Santhony.gutierrez@amd.com{ 78711308Santhony.gutierrez@amd.com cpu->completeIfetch(pkt); 78811308Santhony.gutierrez@amd.com} 78911308Santhony.gutierrez@amd.com 79011308Santhony.gutierrez@amd.combool 79111308Santhony.gutierrez@amd.comTimingSimpleCPU::IcachePort::recvTimingResp(PacketPtr pkt) 79211308Santhony.gutierrez@amd.com{ 79311308Santhony.gutierrez@amd.com DPRINTF(SimpleCPU, "Received fetch response %#x\n", pkt->getAddr()); 79411308Santhony.gutierrez@amd.com // we should only ever see one response per cycle since we only 79511308Santhony.gutierrez@amd.com // issue a new request once this response is sunk 79611308Santhony.gutierrez@amd.com assert(!tickEvent.scheduled()); 79711308Santhony.gutierrez@amd.com // delay processing of returned data until next CPU clock edge 79811308Santhony.gutierrez@amd.com tickEvent.schedule(pkt, cpu->clockEdge()); 79911308Santhony.gutierrez@amd.com 80011308Santhony.gutierrez@amd.com return true; 80111308Santhony.gutierrez@amd.com} 80211308Santhony.gutierrez@amd.com 80311308Santhony.gutierrez@amd.comvoid 80411308Santhony.gutierrez@amd.comTimingSimpleCPU::IcachePort::recvReqRetry() 80511308Santhony.gutierrez@amd.com{ 80611308Santhony.gutierrez@amd.com // we shouldn't get a retry unless we have a packet that we're 80711308Santhony.gutierrez@amd.com // waiting to transmit 80811308Santhony.gutierrez@amd.com assert(cpu->ifetch_pkt != NULL); 80911308Santhony.gutierrez@amd.com assert(cpu->_status == IcacheRetry); 81011308Santhony.gutierrez@amd.com PacketPtr tmp = cpu->ifetch_pkt; 81111308Santhony.gutierrez@amd.com if (sendTimingReq(tmp)) { 81211308Santhony.gutierrez@amd.com cpu->_status = IcacheWaitResponse; 81311308Santhony.gutierrez@amd.com cpu->ifetch_pkt = NULL; 81411308Santhony.gutierrez@amd.com } 81511308Santhony.gutierrez@amd.com} 81611308Santhony.gutierrez@amd.com 81711308Santhony.gutierrez@amd.comvoid 81811308Santhony.gutierrez@amd.comTimingSimpleCPU::completeDataAccess(PacketPtr pkt) 81911308Santhony.gutierrez@amd.com{ 82011308Santhony.gutierrez@amd.com // received a response from the dcache: complete the load or store 82111308Santhony.gutierrez@amd.com // instruction 82211308Santhony.gutierrez@amd.com assert(!pkt->isError()); 82311308Santhony.gutierrez@amd.com assert(_status == DcacheWaitResponse || _status == DTBWaitResponse || 82411308Santhony.gutierrez@amd.com pkt->req->getFlags().isSet(Request::NO_ACCESS)); 82511308Santhony.gutierrez@amd.com 82611308Santhony.gutierrez@amd.com pkt->req->setAccessLatency(); 82711308Santhony.gutierrez@amd.com 82811308Santhony.gutierrez@amd.com updateCycleCounts(); 82911308Santhony.gutierrez@amd.com updateCycleCounters(BaseCPU::CPU_STATE_ON); 83011308Santhony.gutierrez@amd.com 83111308Santhony.gutierrez@amd.com if (pkt->senderState) { 83211308Santhony.gutierrez@amd.com SplitFragmentSenderState * send_state = 83311308Santhony.gutierrez@amd.com dynamic_cast<SplitFragmentSenderState *>(pkt->senderState); 83411308Santhony.gutierrez@amd.com assert(send_state); 83511308Santhony.gutierrez@amd.com delete pkt->req; 83611308Santhony.gutierrez@amd.com delete pkt; 83711308Santhony.gutierrez@amd.com PacketPtr big_pkt = send_state->bigPkt; 83811308Santhony.gutierrez@amd.com delete send_state; 83911308Santhony.gutierrez@amd.com 84011308Santhony.gutierrez@amd.com SplitMainSenderState * main_send_state = 84111308Santhony.gutierrez@amd.com dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); 84211308Santhony.gutierrez@amd.com assert(main_send_state); 84311308Santhony.gutierrez@amd.com // Record the fact that this packet is no longer outstanding. 84411308Santhony.gutierrez@amd.com assert(main_send_state->outstanding != 0); 84511308Santhony.gutierrez@amd.com main_send_state->outstanding--; 84611308Santhony.gutierrez@amd.com 84711308Santhony.gutierrez@amd.com if (main_send_state->outstanding) { 84811308Santhony.gutierrez@amd.com return; 84911308Santhony.gutierrez@amd.com } else { 85011308Santhony.gutierrez@amd.com delete main_send_state; 85111308Santhony.gutierrez@amd.com big_pkt->senderState = NULL; 85211308Santhony.gutierrez@amd.com pkt = big_pkt; 85311308Santhony.gutierrez@amd.com } 85411308Santhony.gutierrez@amd.com } 85511308Santhony.gutierrez@amd.com 85611308Santhony.gutierrez@amd.com _status = BaseSimpleCPU::Running; 85711308Santhony.gutierrez@amd.com 85811308Santhony.gutierrez@amd.com Fault fault = curStaticInst->completeAcc(pkt, threadInfo[curThread], 85911308Santhony.gutierrez@amd.com traceData); 86011308Santhony.gutierrez@amd.com 86111308Santhony.gutierrez@amd.com // keep an instruction count 86211308Santhony.gutierrez@amd.com if (fault == NoFault) 86311308Santhony.gutierrez@amd.com countInst(); 86411308Santhony.gutierrez@amd.com else if (traceData) { 86511308Santhony.gutierrez@amd.com // If there was a fault, we shouldn't trace this instruction. 86611308Santhony.gutierrez@amd.com delete traceData; 86711308Santhony.gutierrez@amd.com traceData = NULL; 86811639Salexandru.dutu@amd.com } 86911308Santhony.gutierrez@amd.com 87011308Santhony.gutierrez@amd.com delete pkt->req; 87111308Santhony.gutierrez@amd.com delete pkt; 87211308Santhony.gutierrez@amd.com 87311308Santhony.gutierrez@amd.com postExecute(); 87411308Santhony.gutierrez@amd.com 87511308Santhony.gutierrez@amd.com advanceInst(fault); 87611308Santhony.gutierrez@amd.com} 87711308Santhony.gutierrez@amd.com 87811308Santhony.gutierrez@amd.comvoid 87911308Santhony.gutierrez@amd.comTimingSimpleCPU::updateCycleCounts() 88011308Santhony.gutierrez@amd.com{ 88111308Santhony.gutierrez@amd.com const Cycles delta(curCycle() - previousCycle); 88211308Santhony.gutierrez@amd.com 88311308Santhony.gutierrez@amd.com numCycles += delta; 88411308Santhony.gutierrez@amd.com 88511308Santhony.gutierrez@amd.com previousCycle = curCycle(); 88611308Santhony.gutierrez@amd.com} 88711308Santhony.gutierrez@amd.com 88811308Santhony.gutierrez@amd.comvoid 88911308Santhony.gutierrez@amd.comTimingSimpleCPU::DcachePort::recvTimingSnoopReq(PacketPtr pkt) 89011308Santhony.gutierrez@amd.com{ 89111308Santhony.gutierrez@amd.com for (ThreadID tid = 0; tid < cpu->numThreads; tid++) { 89211308Santhony.gutierrez@amd.com if (cpu->getCpuAddrMonitor(tid)->doMonitor(pkt)) { 89311308Santhony.gutierrez@amd.com cpu->wakeup(tid); 89411308Santhony.gutierrez@amd.com } 89511308Santhony.gutierrez@amd.com } 89611308Santhony.gutierrez@amd.com 89711308Santhony.gutierrez@amd.com // Making it uniform across all CPUs: 89811308Santhony.gutierrez@amd.com // The CPUs need to be woken up only on an invalidation packet (when using caches) 89911308Santhony.gutierrez@amd.com // or on an incoming write packet (when not using caches) 90011308Santhony.gutierrez@amd.com // It is not necessary to wake up the processor on all incoming packets 90111308Santhony.gutierrez@amd.com if (pkt->isInvalidate() || pkt->isWrite()) { 90211308Santhony.gutierrez@amd.com for (auto &t_info : cpu->threadInfo) { 90311308Santhony.gutierrez@amd.com TheISA::handleLockedSnoop(t_info->thread, pkt, cacheBlockMask); 90411308Santhony.gutierrez@amd.com } 90511308Santhony.gutierrez@amd.com } 90611308Santhony.gutierrez@amd.com} 90711308Santhony.gutierrez@amd.com 90811308Santhony.gutierrez@amd.comvoid 90911308Santhony.gutierrez@amd.comTimingSimpleCPU::DcachePort::recvFunctionalSnoop(PacketPtr pkt) 91011308Santhony.gutierrez@amd.com{ 91111308Santhony.gutierrez@amd.com for (ThreadID tid = 0; tid < cpu->numThreads; tid++) { 91211308Santhony.gutierrez@amd.com if (cpu->getCpuAddrMonitor(tid)->doMonitor(pkt)) { 91311308Santhony.gutierrez@amd.com cpu->wakeup(tid); 91411308Santhony.gutierrez@amd.com } 91511308Santhony.gutierrez@amd.com } 91611308Santhony.gutierrez@amd.com} 91711308Santhony.gutierrez@amd.com 91811308Santhony.gutierrez@amd.combool 91911308Santhony.gutierrez@amd.comTimingSimpleCPU::DcachePort::recvTimingResp(PacketPtr pkt) 92011308Santhony.gutierrez@amd.com{ 92111308Santhony.gutierrez@amd.com DPRINTF(SimpleCPU, "Received load/store response %#x\n", pkt->getAddr()); 92211308Santhony.gutierrez@amd.com 92311308Santhony.gutierrez@amd.com // The timing CPU is not really ticked, instead it relies on the 92411308Santhony.gutierrez@amd.com // memory system (fetch and load/store) to set the pace. 92511308Santhony.gutierrez@amd.com if (!tickEvent.scheduled()) { 92611308Santhony.gutierrez@amd.com // Delay processing of returned data until next CPU clock edge 92711308Santhony.gutierrez@amd.com tickEvent.schedule(pkt, cpu->clockEdge()); 92811308Santhony.gutierrez@amd.com return true; 92911308Santhony.gutierrez@amd.com } else { 93011308Santhony.gutierrez@amd.com // In the case of a split transaction and a cache that is 93111308Santhony.gutierrez@amd.com // faster than a CPU we could get two responses in the 93211308Santhony.gutierrez@amd.com // same tick, delay the second one 93311308Santhony.gutierrez@amd.com if (!retryRespEvent.scheduled()) 93411640Salexandru.dutu@amd.com cpu->schedule(retryRespEvent, cpu->clockEdge(Cycles(1))); 93511640Salexandru.dutu@amd.com return false; 93611640Salexandru.dutu@amd.com } 93711640Salexandru.dutu@amd.com} 93811640Salexandru.dutu@amd.com 93911640Salexandru.dutu@amd.comvoid 94011640Salexandru.dutu@amd.comTimingSimpleCPU::DcachePort::DTickEvent::process() 94111640Salexandru.dutu@amd.com{ 94211640Salexandru.dutu@amd.com cpu->completeDataAccess(pkt); 94311640Salexandru.dutu@amd.com} 944 945void 946TimingSimpleCPU::DcachePort::recvReqRetry() 947{ 948 // we shouldn't get a retry unless we have a packet that we're 949 // waiting to transmit 950 assert(cpu->dcache_pkt != NULL); 951 assert(cpu->_status == DcacheRetry); 952 PacketPtr tmp = cpu->dcache_pkt; 953 if (tmp->senderState) { 954 // This is a packet from a split access. 955 SplitFragmentSenderState * send_state = 956 dynamic_cast<SplitFragmentSenderState *>(tmp->senderState); 957 assert(send_state); 958 PacketPtr big_pkt = send_state->bigPkt; 959 960 SplitMainSenderState * main_send_state = 961 dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); 962 assert(main_send_state); 963 964 if (sendTimingReq(tmp)) { 965 // If we were able to send without retrying, record that fact 966 // and try sending the other fragment. 967 send_state->clearFromParent(); 968 int other_index = main_send_state->getPendingFragment(); 969 if (other_index > 0) { 970 tmp = main_send_state->fragments[other_index]; 971 cpu->dcache_pkt = tmp; 972 if ((big_pkt->isRead() && cpu->handleReadPacket(tmp)) || 973 (big_pkt->isWrite() && cpu->handleWritePacket())) { 974 main_send_state->fragments[other_index] = NULL; 975 } 976 } else { 977 cpu->_status = DcacheWaitResponse; 978 // memory system takes ownership of packet 979 cpu->dcache_pkt = NULL; 980 } 981 } 982 } else if (sendTimingReq(tmp)) { 983 cpu->_status = DcacheWaitResponse; 984 // memory system takes ownership of packet 985 cpu->dcache_pkt = NULL; 986 } 987} 988 989TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, 990 Tick t) 991 : pkt(_pkt), cpu(_cpu) 992{ 993 cpu->schedule(this, t); 994} 995 996void 997TimingSimpleCPU::IprEvent::process() 998{ 999 cpu->completeDataAccess(pkt); 1000} 1001 1002const char * 1003TimingSimpleCPU::IprEvent::description() const 1004{ 1005 return "Timing Simple CPU Delay IPR event"; 1006} 1007 1008 1009void 1010TimingSimpleCPU::printAddr(Addr a) 1011{ 1012 dcachePort.printAddr(a); 1013} 1014 1015 1016//////////////////////////////////////////////////////////////////////// 1017// 1018// TimingSimpleCPU Simulation Object 1019// 1020TimingSimpleCPU * 1021TimingSimpleCPUParams::create() 1022{ 1023 return new TimingSimpleCPU(this); 1024} 1025