timing.cc revision 8232
12632Sstever@eecs.umich.edu/* 22632Sstever@eecs.umich.edu * Copyright (c) 2010 ARM Limited 32632Sstever@eecs.umich.edu * All rights reserved 42632Sstever@eecs.umich.edu * 52632Sstever@eecs.umich.edu * The license below extends only to copyright in the software and shall 62632Sstever@eecs.umich.edu * not be construed as granting a license to any other intellectual 72632Sstever@eecs.umich.edu * property including but not limited to intellectual property relating 82632Sstever@eecs.umich.edu * to a hardware implementation of the functionality of the software 92632Sstever@eecs.umich.edu * licensed hereunder. You may use the software subject to the license 102632Sstever@eecs.umich.edu * terms below provided that you ensure that this notice is replicated 112632Sstever@eecs.umich.edu * unmodified and in its entirety in all distributions of the software, 122632Sstever@eecs.umich.edu * modified or unmodified, in source code or in binary form. 132632Sstever@eecs.umich.edu * 142632Sstever@eecs.umich.edu * Copyright (c) 2002-2005 The Regents of The University of Michigan 152632Sstever@eecs.umich.edu * All rights reserved. 162632Sstever@eecs.umich.edu * 172632Sstever@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 182632Sstever@eecs.umich.edu * modification, are permitted provided that the following conditions are 192632Sstever@eecs.umich.edu * met: redistributions of source code must retain the above copyright 202632Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 212632Sstever@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 222632Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 232632Sstever@eecs.umich.edu * documentation and/or other materials provided with the distribution; 242632Sstever@eecs.umich.edu * neither the name of the copyright holders nor the names of its 252632Sstever@eecs.umich.edu * contributors may be used to endorse or promote products derived from 262632Sstever@eecs.umich.edu * this software without specific prior written permission. 272632Sstever@eecs.umich.edu * 282632Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 292632Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 302632Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 312022SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 322022SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 332022SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 342022SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 352022SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 362469SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 372469SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 382469SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 392469SN/A * 402516SN/A * Authors: Steve Reinhardt 412516SN/A */ 422516SN/A 432482SN/A#include "arch/locked_mem.hh" 442516SN/A#include "arch/mmapped_ipr.hh" 452469SN/A#include "arch/utility.hh" 462486SN/A#include "base/bigint.hh" 472486SN/A#include "config/the_isa.hh" 482516SN/A#include "cpu/simple/timing.hh" 492580SN/A#include "cpu/exetrace.hh" 502580SN/A#include "debug/Config.hh" 512486SN/A#include "debug/ExecFaulting.hh" 522486SN/A#include "debug/SimpleCPU.hh" 532482SN/A#include "mem/packet.hh" 542516SN/A#include "mem/packet_access.hh" 552580SN/A#include "params/TimingSimpleCPU.hh" 562580SN/A#include "sim/faults.hh" 572486SN/A#include "sim/system.hh" 582482SN/A 592516SN/Ausing namespace std; 602516SN/Ausing namespace TheISA; 612516SN/A 622516SN/APort * 632580SN/ATimingSimpleCPU::getPort(const std::string &if_name, int idx) 642580SN/A{ 652516SN/A if (if_name == "dcache_port") 662516SN/A return &dcachePort; 672516SN/A else if (if_name == "icache_port") 682516SN/A return &icachePort; 692482SN/A else 702482SN/A panic("No Such Port\n"); 712591SN/A} 722516SN/A 732580SN/Avoid 742580SN/ATimingSimpleCPU::init() 752482SN/A{ 762482SN/A BaseCPU::init(); 772591SN/A#if FULL_SYSTEM 782516SN/A for (int i = 0; i < threadContexts.size(); ++i) { 792580SN/A ThreadContext *tc = threadContexts[i]; 802580SN/A 812482SN/A // initialize CPU, including PC 822482SN/A TheISA::initCPU(tc, _cpuId); 832591SN/A } 842516SN/A#endif 852580SN/A} 862580SN/A 872482SN/ATick 882482SN/ATimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) 892591SN/A{ 902516SN/A panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 912580SN/A return curTick(); 922580SN/A} 932482SN/A 942482SN/Avoid 952591SN/ATimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) 962516SN/A{ 972580SN/A //No internal storage to update, jusst return 982580SN/A return; 992482SN/A} 1002482SN/A 1012591SN/Avoid 1022516SN/ATimingSimpleCPU::CpuPort::recvStatusChange(Status status) 1032580SN/A{ 1042580SN/A if (status == RangeChange) { 1052482SN/A if (!snoopRangeSent) { 1062469SN/A snoopRangeSent = true; 1072482SN/A sendStatusChange(Port::RangeChange); 1082516SN/A } 1092516SN/A return; 1102516SN/A } 1112516SN/A 1122469SN/A panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); 1132516SN/A} 1142516SN/A 1152516SN/A 1162469SN/Avoid 1172469SN/ATimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t) 1182482SN/A{ 1192482SN/A pkt = _pkt; 1202482SN/A cpu->schedule(this, t); 1212482SN/A} 1222482SN/A 1232526SN/ATimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p) 1242516SN/A : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this, p->clock), 1252516SN/A dcachePort(this, p->clock), fetchEvent(this) 1262516SN/A{ 1272516SN/A _status = Idle; 1282516SN/A 1292469SN/A icachePort.snoopRangeSent = false; 1302516SN/A dcachePort.snoopRangeSent = false; 1312482SN/A 1322482SN/A ifetch_pkt = dcache_pkt = NULL; 1332469SN/A drainEvent = NULL; 1342516SN/A previousTick = 0; 1352482SN/A changeState(SimObject::Running); 1362482SN/A system->totalNumInsts = 0; 1372516SN/A} 1382469SN/A 1392516SN/A 1402516SN/ATimingSimpleCPU::~TimingSimpleCPU() 1412482SN/A{ 1422469SN/A} 1432516SN/A 1442482SN/Avoid 1452482SN/ATimingSimpleCPU::serialize(ostream &os) 1462516SN/A{ 1472482SN/A SimObject::State so_state = SimObject::getState(); 1482482SN/A SERIALIZE_ENUM(so_state); 1492482SN/A BaseSimpleCPU::serialize(os); 1502482SN/A} 1512482SN/A 1522615SN/Avoid 1532469SN/ATimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 1542469SN/A{ 1552482SN/A SimObject::State so_state; 1562615SN/A UNSERIALIZE_ENUM(so_state); 1572482SN/A BaseSimpleCPU::unserialize(cp, section); 1582482SN/A} 1592482SN/A 1602588SN/Aunsigned int 1612482SN/ATimingSimpleCPU::drain(Event *drain_event) 1622526SN/A{ 1632469SN/A // TimingSimpleCPU is ready to drain if it's not waiting for 1642482SN/A // an access to complete. 1652469SN/A if (_status == Idle || _status == Running || _status == SwitchedOut) { 1662516SN/A changeState(SimObject::Drained); 1672469SN/A return 0; 1682580SN/A } else { 1692469SN/A changeState(SimObject::Draining); 1702580SN/A drainEvent = drain_event; 1712469SN/A return 1; 1722526SN/A } 1732482SN/A} 1742482SN/A 1752482SN/Avoid 1762469SN/ATimingSimpleCPU::resume() 1772580SN/A{ 1782580SN/A DPRINTF(SimpleCPU, "Resume\n"); 1792580SN/A if (_status != SwitchedOut && _status != Idle) { 1802580SN/A assert(system->getMemoryMode() == Enums::timing); 1812580SN/A 1822580SN/A if (fetchEvent.scheduled()) 1832580SN/A deschedule(fetchEvent); 1842526SN/A 1852482SN/A schedule(fetchEvent, nextCycle()); 1862482SN/A } 1872482SN/A 1882469SN/A changeState(SimObject::Running); 1892516SN/A} 1902469SN/A 1912469SN/Avoid 1922580SN/ATimingSimpleCPU::switchOut() 1932469SN/A{ 1942580SN/A assert(_status == Running || _status == Idle); 1952580SN/A _status = SwitchedOut; 1962469SN/A numCycles += tickToCycles(curTick() - previousTick); 1972526SN/A 1982469SN/A // If we've been scheduled to resume but are then told to switch out, 1992615SN/A // we'll need to cancel it. 2002615SN/A if (fetchEvent.scheduled()) 2012469SN/A deschedule(fetchEvent); 2022526SN/A} 2032469SN/A 2042615SN/A 2052615SN/Avoid 2062526SN/ATimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 2072526SN/A{ 2082469SN/A BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort); 2092516SN/A 2102469SN/A // if any of this CPU's ThreadContexts are active, mark the CPU as 2112469SN/A // running and schedule its tick event. 2122580SN/A for (int i = 0; i < threadContexts.size(); ++i) { 2132469SN/A ThreadContext *tc = threadContexts[i]; 2142580SN/A if (tc->status() == ThreadContext::Active && _status != Running) { 2152469SN/A _status = Running; 2162526SN/A break; 2172469SN/A } 2182615SN/A } 2192615SN/A 2202526SN/A if (_status != Running) { 2212469SN/A _status = Idle; 2222615SN/A } 2232516SN/A assert(threadContexts.size() == 1); 2242469SN/A previousTick = curTick(); 2252469SN/A} 2262224SN/A 2272469SN/A 2282516SN/Avoid 2292516SN/ATimingSimpleCPU::activateContext(int thread_num, int delay) 2302516SN/A{ 2312469SN/A DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay); 2322469SN/A 2332469SN/A assert(thread_num == 0); 2342469SN/A assert(thread); 2352469SN/A 2362526SN/A assert(_status == Idle); 2372469SN/A 2382615SN/A notIdleFraction++; 2392516SN/A _status = Running; 2402469SN/A 2412469SN/A // kick things off by initiating the fetch of the next instruction 2422469SN/A schedule(fetchEvent, nextCycle(curTick() + ticks(delay))); 2432516SN/A} 2442516SN/A 2452516SN/A 2462516SN/Avoid 2472588SN/ATimingSimpleCPU::suspendContext(int thread_num) 2482516SN/A{ 2492469SN/A DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num); 2502469SN/A 2512469SN/A assert(thread_num == 0); 2522469SN/A assert(thread); 2532469SN/A 2542526SN/A if (_status == Idle) 2552469SN/A return; 2562516SN/A 2572469SN/A assert(_status == Running); 2582469SN/A 2592469SN/A // just change status to Idle... if status != Running, 2602469SN/A // completeInst() will not initiate fetch of next instruction. 2612469SN/A 2622469SN/A notIdleFraction--; 2632526SN/A _status = Idle; 2642469SN/A} 2652516SN/A 2662469SN/Abool 2672469SN/ATimingSimpleCPU::handleReadPacket(PacketPtr pkt) 2682516SN/A{ 2692469SN/A RequestPtr req = pkt->req; 2702469SN/A if (req->isMmappedIpr()) { 2712469SN/A Tick delay; 2722526SN/A delay = TheISA::handleIprRead(thread->getTC(), pkt); 2732469SN/A new IprEvent(pkt, this, nextCycle(curTick() + delay)); 2742516SN/A _status = DcacheWaitResponse; 2752469SN/A dcache_pkt = NULL; 2762469SN/A } else if (!dcachePort.sendTiming(pkt)) { 2772469SN/A _status = DcacheRetry; 2782469SN/A dcache_pkt = pkt; 2792469SN/A } else { 2802469SN/A _status = DcacheWaitResponse; 2812469SN/A // memory system takes ownership of packet 2822526SN/A dcache_pkt = NULL; 2832469SN/A } 2842516SN/A return dcache_pkt == NULL; 2852469SN/A} 2862469SN/A 2872469SN/Avoid 2882469SN/ATimingSimpleCPU::sendData(RequestPtr req, uint8_t *data, uint64_t *res, 2892469SN/A bool read) 2902469SN/A{ 2912469SN/A PacketPtr pkt; 2922526SN/A buildPacket(pkt, req, read); 2932469SN/A pkt->dataDynamicArray<uint8_t>(data); 2942516SN/A if (req->getFlags().isSet(Request::NO_ACCESS)) { 2952469SN/A assert(!dcache_pkt); 2962469SN/A pkt->makeResponse(); 2972516SN/A completeDataAccess(pkt); 2982469SN/A } else if (read) { 2992469SN/A handleReadPacket(pkt); 3002469SN/A } else { 3012469SN/A bool do_access = true; // flag to suppress cache access 3022469SN/A 3032469SN/A if (req->isLLSC()) { 3042469SN/A do_access = TheISA::handleLockedWrite(thread, req); 3052469SN/A } else if (req->isCondSwap()) { 3062469SN/A assert(res); 3072469SN/A req->setExtraData(*res); 3082526SN/A } 3092526SN/A 3102526SN/A if (do_access) { 3112526SN/A dcache_pkt = pkt; 3122526SN/A handleWritePacket(); 3132526SN/A } else { 3142526SN/A _status = DcacheWaitResponse; 3152469SN/A completeDataAccess(pkt); 3162526SN/A } 3172526SN/A } 3182526SN/A} 3192526SN/A 3202526SN/Avoid 3212526SN/ATimingSimpleCPU::sendSplitData(RequestPtr req1, RequestPtr req2, 3222526SN/A RequestPtr req, uint8_t *data, bool read) 3232526SN/A{ 3242526SN/A PacketPtr pkt1, pkt2; 3252526SN/A buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read); 3262526SN/A if (req->getFlags().isSet(Request::NO_ACCESS)) { 3272526SN/A assert(!dcache_pkt); 3282526SN/A pkt1->makeResponse(); 3292526SN/A completeDataAccess(pkt1); 3302526SN/A } else if (read) { 3312526SN/A SplitFragmentSenderState * send_state = 3322526SN/A dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 3332526SN/A if (handleReadPacket(pkt1)) { 3342526SN/A send_state->clearFromParent(); 3352526SN/A send_state = dynamic_cast<SplitFragmentSenderState *>( 3362526SN/A pkt2->senderState); 3372526SN/A if (handleReadPacket(pkt2)) { 3382526SN/A send_state->clearFromParent(); 3392526SN/A } 3402526SN/A } 3412526SN/A } else { 3422526SN/A dcache_pkt = pkt1; 3432526SN/A SplitFragmentSenderState * send_state = 3442526SN/A dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState); 3452526SN/A if (handleWritePacket()) { 3462526SN/A send_state->clearFromParent(); 3472526SN/A dcache_pkt = pkt2; 3482526SN/A send_state = dynamic_cast<SplitFragmentSenderState *>( 3492526SN/A pkt2->senderState); 3502526SN/A if (handleWritePacket()) { 3512526SN/A send_state->clearFromParent(); 3522526SN/A } 3532526SN/A } 3542526SN/A } 3552526SN/A} 3562526SN/A 3572526SN/Avoid 3582526SN/ATimingSimpleCPU::translationFault(Fault fault) 3592526SN/A{ 3602526SN/A // fault may be NoFault in cases where a fault is suppressed, 3612526SN/A // for instance prefetches. 3622526SN/A numCycles += tickToCycles(curTick() - previousTick); 3632526SN/A previousTick = curTick(); 3642526SN/A 3652526SN/A if (traceData) { 3662526SN/A // Since there was a fault, we shouldn't trace this instruction. 3672526SN/A delete traceData; 3682526SN/A traceData = NULL; 3692526SN/A } 3702526SN/A 3712526SN/A postExecute(); 3722526SN/A 3732526SN/A if (getState() == SimObject::Draining) { 3742526SN/A advancePC(fault); 3752526SN/A completeDrain(); 3762526SN/A } else { 3772469SN/A advanceInst(fault); 3782526SN/A } 3792526SN/A} 3802526SN/A 3812526SN/Avoid 3822526SN/ATimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr req, bool read) 3832591SN/A{ 3842591SN/A MemCmd cmd; 3852591SN/A if (read) { 3862526SN/A cmd = MemCmd::ReadReq; 3872526SN/A if (req->isLLSC()) 3882526SN/A cmd = MemCmd::LoadLockedReq; 3892591SN/A } else { 3902591SN/A cmd = MemCmd::WriteReq; 3912591SN/A if (req->isLLSC()) { 3922526SN/A cmd = MemCmd::StoreCondReq; 3932224SN/A } else if (req->isSwap()) { 3942526SN/A cmd = MemCmd::SwapReq; 3952526SN/A } 3962615SN/A } 3972615SN/A pkt = new Packet(req, cmd, Packet::Broadcast); 3982526SN/A} 3992526SN/A 4002526SN/Avoid 4012526SN/ATimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, 4022526SN/A RequestPtr req1, RequestPtr req2, RequestPtr req, 4032526SN/A uint8_t *data, bool read) 4042526SN/A{ 4052526SN/A pkt1 = pkt2 = NULL; 4062469SN/A 4072526SN/A assert(!req1->isMmappedIpr() && !req2->isMmappedIpr()); 4082526SN/A 4092516SN/A if (req->getFlags().isSet(Request::NO_ACCESS)) { 4102591SN/A buildPacket(pkt1, req, read); 4112516SN/A return; 4122526SN/A } 4132526SN/A 4142526SN/A buildPacket(pkt1, req1, read); 4152615SN/A buildPacket(pkt2, req2, read); 4162615SN/A 4172615SN/A req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags()); 4182615SN/A PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(), 4192615SN/A Packet::Broadcast); 4202615SN/A 4212526SN/A pkt->dataDynamicArray<uint8_t>(data); 4222526SN/A pkt1->dataStatic<uint8_t>(data); 4232526SN/A pkt2->dataStatic<uint8_t>(data + req1->getSize()); 4242526SN/A 4252526SN/A SplitMainSenderState * main_send_state = new SplitMainSenderState; 4262526SN/A pkt->senderState = main_send_state; 4272526SN/A main_send_state->fragments[0] = pkt1; 4282526SN/A main_send_state->fragments[1] = pkt2; 4292526SN/A main_send_state->outstanding = 2; 4302526SN/A pkt1->senderState = new SplitFragmentSenderState(pkt, 0); 4312526SN/A pkt2->senderState = new SplitFragmentSenderState(pkt, 1); 4322526SN/A} 4332526SN/A 4342526SN/AFault 4352469SN/ATimingSimpleCPU::readBytes(Addr addr, uint8_t *data, 4362526SN/A unsigned size, unsigned flags) 4372526SN/A{ 4382526SN/A Fault fault; 4392485SN/A const int asid = 0; 4402526SN/A const ThreadID tid = 0; 4412526SN/A const Addr pc = thread->instAddr(); 4422526SN/A unsigned block_size = dcachePort.peerBlockSize(); 4432485SN/A BaseTLB::Mode mode = BaseTLB::Read; 4442526SN/A 4452526SN/A if (traceData) { 4462526SN/A traceData->setAddr(addr); 4472526SN/A } 4482526SN/A 4492526SN/A RequestPtr req = new Request(asid, addr, size, 4502526SN/A flags, pc, _cpuId, tid); 4512526SN/A 4522526SN/A Addr split_addr = roundDown(addr + size - 1, block_size); 4532526SN/A assert(split_addr <= addr || split_addr - addr < block_size); 4542526SN/A 4552526SN/A _status = DTBWaitResponse; 4562526SN/A if (split_addr > addr) { 4572526SN/A RequestPtr req1, req2; 4582526SN/A assert(!req->isLLSC() && !req->isSwap()); 4592526SN/A req->splitOnVaddr(split_addr, req1, req2); 4602526SN/A 4612526SN/A WholeTranslationState *state = 4622526SN/A new WholeTranslationState(req, req1, req2, new uint8_t[size], 4632469SN/A NULL, mode); 4642469SN/A DataTranslation<TimingSimpleCPU> *trans1 = 4652526SN/A new DataTranslation<TimingSimpleCPU>(this, state, 0); 4662526SN/A DataTranslation<TimingSimpleCPU> *trans2 = 4672526SN/A new DataTranslation<TimingSimpleCPU>(this, state, 1); 4682526SN/A 4692526SN/A thread->dtb->translateTiming(req1, tc, trans1, mode); 4702526SN/A thread->dtb->translateTiming(req2, tc, trans2, mode); 4712526SN/A } else { 4722526SN/A WholeTranslationState *state = 4732526SN/A new WholeTranslationState(req, new uint8_t[size], NULL, mode); 4742526SN/A DataTranslation<TimingSimpleCPU> *translation 4752526SN/A = new DataTranslation<TimingSimpleCPU>(this, state); 4762526SN/A thread->dtb->translateTiming(req, tc, translation, mode); 4772526SN/A } 4782561SN/A 4792561SN/A return NoFault; 4802561SN/A} 4812526SN/A 4822526SN/Atemplate <class T> 4832526SN/AFault 4842526SN/ATimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 4852526SN/A{ 4862561SN/A return readBytes(addr, (uint8_t *)&data, sizeof(T), flags); 4872561SN/A} 4882561SN/A 4892561SN/A#ifndef DOXYGEN_SHOULD_SKIP_THIS 4902561SN/A 4912561SN/Atemplate 4922561SN/AFault 4932561SN/ATimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags); 4942561SN/A 4952561SN/Atemplate 4962561SN/AFault 4972561SN/ATimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags); 4982561SN/A 4992561SN/Atemplate 5002561SN/AFault 5012561SN/ATimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 5022561SN/A 5032561SN/Atemplate 5042561SN/AFault 5052561SN/ATimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 5062561SN/A 5072561SN/Atemplate 5082561SN/AFault 5092561SN/ATimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 5102526SN/A 5112526SN/Atemplate 5122526SN/AFault 5132526SN/ATimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 5142561SN/A 5152561SN/A#endif //DOXYGEN_SHOULD_SKIP_THIS 5162561SN/A 5172561SN/Atemplate<> 5182526SN/AFault 5192561SN/ATimingSimpleCPU::read(Addr addr, double &data, unsigned flags) 5202526SN/A{ 5212561SN/A return read(addr, *(uint64_t*)&data, flags); 5222561SN/A} 5232561SN/A 5242561SN/Atemplate<> 5252526SN/AFault 5262526SN/ATimingSimpleCPU::read(Addr addr, float &data, unsigned flags) 5272561SN/A{ 5282561SN/A return read(addr, *(uint32_t*)&data, flags); 5292561SN/A} 5302561SN/A 5312526SN/Atemplate<> 5322561SN/AFault 5332526SN/ATimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 5342561SN/A{ 5352561SN/A return read(addr, (uint32_t&)data, flags); 5362561SN/A} 5372526SN/A 5382526SN/Abool 5392526SN/ATimingSimpleCPU::handleWritePacket() 5402526SN/A{ 5412526SN/A RequestPtr req = dcache_pkt->req; 5422526SN/A if (req->isMmappedIpr()) { 5432526SN/A Tick delay; 5442526SN/A delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt); 5452526SN/A new IprEvent(dcache_pkt, this, nextCycle(curTick() + delay)); 5462526SN/A _status = DcacheWaitResponse; 5472526SN/A dcache_pkt = NULL; 5482526SN/A } else if (!dcachePort.sendTiming(dcache_pkt)) { 5492526SN/A _status = DcacheRetry; 5502526SN/A } else { 5512526SN/A _status = DcacheWaitResponse; 5522526SN/A // memory system takes ownership of packet 5532526SN/A dcache_pkt = NULL; 5542526SN/A } 5552526SN/A return dcache_pkt == NULL; 5562526SN/A} 5572526SN/A 5582526SN/AFault 5592526SN/ATimingSimpleCPU::writeTheseBytes(uint8_t *data, unsigned size, 5602526SN/A Addr addr, unsigned flags, uint64_t *res) 5612526SN/A{ 5622561SN/A const int asid = 0; 5632561SN/A const ThreadID tid = 0; 5642526SN/A const Addr pc = thread->instAddr(); 5652526SN/A unsigned block_size = dcachePort.peerBlockSize(); 5662526SN/A BaseTLB::Mode mode = BaseTLB::Write; 5672526SN/A 5682526SN/A if (traceData) { 5692526SN/A traceData->setAddr(addr); 5702526SN/A } 5712526SN/A 5722526SN/A RequestPtr req = new Request(asid, addr, size, 5732526SN/A flags, pc, _cpuId, tid); 5742526SN/A 5752526SN/A Addr split_addr = roundDown(addr + size - 1, block_size); 5762526SN/A assert(split_addr <= addr || split_addr - addr < block_size); 5772526SN/A 5782526SN/A _status = DTBWaitResponse; 5792526SN/A if (split_addr > addr) { 5802526SN/A RequestPtr req1, req2; 5812526SN/A assert(!req->isLLSC() && !req->isSwap()); 5822526SN/A req->splitOnVaddr(split_addr, req1, req2); 5832526SN/A 5842526SN/A WholeTranslationState *state = 5852561SN/A new WholeTranslationState(req, req1, req2, data, res, mode); 5862561SN/A DataTranslation<TimingSimpleCPU> *trans1 = 5872526SN/A new DataTranslation<TimingSimpleCPU>(this, state, 0); 5882526SN/A DataTranslation<TimingSimpleCPU> *trans2 = 5892526SN/A new DataTranslation<TimingSimpleCPU>(this, state, 1); 5902526SN/A 5912526SN/A thread->dtb->translateTiming(req1, tc, trans1, mode); 5922526SN/A thread->dtb->translateTiming(req2, tc, trans2, mode); 5932526SN/A } else { 5942526SN/A WholeTranslationState *state = 5952526SN/A new WholeTranslationState(req, data, res, mode); 5962526SN/A DataTranslation<TimingSimpleCPU> *translation = 5972526SN/A new DataTranslation<TimingSimpleCPU>(this, state); 5982526SN/A thread->dtb->translateTiming(req, tc, translation, mode); 5992526SN/A } 6002526SN/A 6012526SN/A // Translation faults will be returned via finishTranslation() 6022526SN/A return NoFault; 6032526SN/A} 6042526SN/A 6052526SN/AFault 6062526SN/ATimingSimpleCPU::writeBytes(uint8_t *data, unsigned size, 6072526SN/A Addr addr, unsigned flags, uint64_t *res) 6082526SN/A{ 6092526SN/A uint8_t *newData = new uint8_t[size]; 6102526SN/A memcpy(newData, data, size); 6112526SN/A return writeTheseBytes(newData, size, addr, flags, res); 6122526SN/A} 6132526SN/A 6142526SN/Atemplate <class T> 6152526SN/AFault 6162526SN/ATimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 6172526SN/A{ 6182469SN/A if (traceData) { 6192469SN/A traceData->setData(data); 6202526SN/A } 6212526SN/A T *dataP = (T*) new uint8_t[sizeof(T)]; 6222526SN/A *dataP = TheISA::htog(data); 6232526SN/A 6242526SN/A return writeTheseBytes((uint8_t *)dataP, sizeof(T), addr, flags, res); 6252526SN/A} 6262526SN/A 6272526SN/A 6282526SN/A#ifndef DOXYGEN_SHOULD_SKIP_THIS 6292526SN/Atemplate 6302526SN/AFault 6312526SN/ATimingSimpleCPU::write(Twin32_t data, Addr addr, 6322526SN/A unsigned flags, uint64_t *res); 6332526SN/A 6342526SN/Atemplate 6352526SN/AFault 6362526SN/ATimingSimpleCPU::write(Twin64_t data, Addr addr, 6372526SN/A unsigned flags, uint64_t *res); 6382526SN/A 6392526SN/Atemplate 6402526SN/AFault 6412526SN/ATimingSimpleCPU::write(uint64_t data, Addr addr, 6422526SN/A unsigned flags, uint64_t *res); 6432526SN/A 6442526SN/Atemplate 6452526SN/AFault 6462526SN/ATimingSimpleCPU::write(uint32_t data, Addr addr, 6472526SN/A unsigned flags, uint64_t *res); 6482526SN/A 6492526SN/Atemplate 6502526SN/AFault 6512526SN/ATimingSimpleCPU::write(uint16_t data, Addr addr, 6522526SN/A unsigned flags, uint64_t *res); 6532526SN/A 6542526SN/Atemplate 6552526SN/AFault 6562526SN/ATimingSimpleCPU::write(uint8_t data, Addr addr, 6572526SN/A unsigned flags, uint64_t *res); 6582526SN/A 6592526SN/A#endif //DOXYGEN_SHOULD_SKIP_THIS 6602526SN/A 6612526SN/Atemplate<> 6622526SN/AFault 6632526SN/ATimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 6642526SN/A{ 6652526SN/A return write(*(uint64_t*)&data, addr, flags, res); 6662526SN/A} 6672526SN/A 6682526SN/Atemplate<> 6692526SN/AFault 6702526SN/ATimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 6712526SN/A{ 6722526SN/A return write(*(uint32_t*)&data, addr, flags, res); 6732526SN/A} 6742526SN/A 6752526SN/A 6762526SN/Atemplate<> 6772526SN/AFault 6782526SN/ATimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 6792526SN/A{ 6802526SN/A return write((uint32_t)data, addr, flags, res); 6812526SN/A} 6822526SN/A 6832526SN/A 6842526SN/Avoid 6852526SN/ATimingSimpleCPU::finishTranslation(WholeTranslationState *state) 6862526SN/A{ 6872561SN/A _status = Running; 6882561SN/A 6892469SN/A if (state->getFault() != NoFault) { 6902526SN/A if (state->isPrefetch()) { 6912526SN/A state->setNoFault(); 6922526SN/A } 6932526SN/A delete [] state->data; 6942561SN/A state->deleteReqs(); 6952561SN/A translationFault(state->getFault()); 6962526SN/A } else { 6972526SN/A if (!state->isSplit) { 6982526SN/A sendData(state->mainReq, state->data, state->res, 6992526SN/A state->mode == BaseTLB::Read); 7002526SN/A } else { 7012526SN/A sendSplitData(state->sreqLow, state->sreqHigh, state->mainReq, 7022526SN/A state->data, state->mode == BaseTLB::Read); 7032526SN/A } 7042526SN/A } 7052526SN/A 7062526SN/A delete state; 7072526SN/A} 7082526SN/A 7092526SN/A 7102526SN/Avoid 7112526SN/ATimingSimpleCPU::fetch() 7122526SN/A{ 7132526SN/A DPRINTF(SimpleCPU, "Fetch\n"); 7142526SN/A 7152526SN/A if (!curStaticInst || !curStaticInst->isDelayedCommit()) 7162526SN/A checkForInterrupts(); 7172526SN/A 7182526SN/A checkPcEventQueue(); 7192526SN/A 7202469SN/A // We must have just got suspended by a PC event 7212022SN/A if (_status == Idle) 722 return; 723 724 TheISA::PCState pcState = thread->pcState(); 725 bool needToFetch = !isRomMicroPC(pcState.microPC()) && !curMacroStaticInst; 726 727 if (needToFetch) { 728 Request *ifetch_req = new Request(); 729 ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0); 730 setupFetchRequest(ifetch_req); 731 thread->itb->translateTiming(ifetch_req, tc, &fetchTranslation, 732 BaseTLB::Execute); 733 } else { 734 _status = IcacheWaitResponse; 735 completeIfetch(NULL); 736 737 numCycles += tickToCycles(curTick() - previousTick); 738 previousTick = curTick(); 739 } 740} 741 742 743void 744TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc) 745{ 746 if (fault == NoFault) { 747 ifetch_pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast); 748 ifetch_pkt->dataStatic(&inst); 749 750 if (!icachePort.sendTiming(ifetch_pkt)) { 751 // Need to wait for retry 752 _status = IcacheRetry; 753 } else { 754 // Need to wait for cache to respond 755 _status = IcacheWaitResponse; 756 // ownership of packet transferred to memory system 757 ifetch_pkt = NULL; 758 } 759 } else { 760 delete req; 761 // fetch fault: advance directly to next instruction (fault handler) 762 _status = Running; 763 advanceInst(fault); 764 } 765 766 numCycles += tickToCycles(curTick() - previousTick); 767 previousTick = curTick(); 768} 769 770 771void 772TimingSimpleCPU::advanceInst(Fault fault) 773{ 774 if (fault != NoFault || !stayAtPC) 775 advancePC(fault); 776 777 if (_status == Running) { 778 // kick off fetch of next instruction... callback from icache 779 // response will cause that instruction to be executed, 780 // keeping the CPU running. 781 fetch(); 782 } 783} 784 785 786void 787TimingSimpleCPU::completeIfetch(PacketPtr pkt) 788{ 789 DPRINTF(SimpleCPU, "Complete ICache Fetch\n"); 790 791 // received a response from the icache: execute the received 792 // instruction 793 794 assert(!pkt || !pkt->isError()); 795 assert(_status == IcacheWaitResponse); 796 797 _status = Running; 798 799 numCycles += tickToCycles(curTick() - previousTick); 800 previousTick = curTick(); 801 802 if (getState() == SimObject::Draining) { 803 if (pkt) { 804 delete pkt->req; 805 delete pkt; 806 } 807 808 completeDrain(); 809 return; 810 } 811 812 preExecute(); 813 if (curStaticInst && curStaticInst->isMemRef()) { 814 // load or store: just send to dcache 815 Fault fault = curStaticInst->initiateAcc(this, traceData); 816 817 // If we're not running now the instruction will complete in a dcache 818 // response callback or the instruction faulted and has started an 819 // ifetch 820 if (_status == Running) { 821 if (fault != NoFault && traceData) { 822 // If there was a fault, we shouldn't trace this instruction. 823 delete traceData; 824 traceData = NULL; 825 } 826 827 postExecute(); 828 // @todo remove me after debugging with legion done 829 if (curStaticInst && (!curStaticInst->isMicroop() || 830 curStaticInst->isFirstMicroop())) 831 instCnt++; 832 advanceInst(fault); 833 } 834 } else if (curStaticInst) { 835 // non-memory instruction: execute completely now 836 Fault fault = curStaticInst->execute(this, traceData); 837 838 // keep an instruction count 839 if (fault == NoFault) 840 countInst(); 841 else if (traceData && !DTRACE(ExecFaulting)) { 842 delete traceData; 843 traceData = NULL; 844 } 845 846 postExecute(); 847 // @todo remove me after debugging with legion done 848 if (curStaticInst && (!curStaticInst->isMicroop() || 849 curStaticInst->isFirstMicroop())) 850 instCnt++; 851 advanceInst(fault); 852 } else { 853 advanceInst(NoFault); 854 } 855 856 if (pkt) { 857 delete pkt->req; 858 delete pkt; 859 } 860} 861 862void 863TimingSimpleCPU::IcachePort::ITickEvent::process() 864{ 865 cpu->completeIfetch(pkt); 866} 867 868bool 869TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt) 870{ 871 if (pkt->isResponse() && !pkt->wasNacked()) { 872 // delay processing of returned data until next CPU clock edge 873 Tick next_tick = cpu->nextCycle(curTick()); 874 875 if (next_tick == curTick()) 876 cpu->completeIfetch(pkt); 877 else 878 tickEvent.schedule(pkt, next_tick); 879 880 return true; 881 } 882 else if (pkt->wasNacked()) { 883 assert(cpu->_status == IcacheWaitResponse); 884 pkt->reinitNacked(); 885 if (!sendTiming(pkt)) { 886 cpu->_status = IcacheRetry; 887 cpu->ifetch_pkt = pkt; 888 } 889 } 890 //Snooping a Coherence Request, do nothing 891 return true; 892} 893 894void 895TimingSimpleCPU::IcachePort::recvRetry() 896{ 897 // we shouldn't get a retry unless we have a packet that we're 898 // waiting to transmit 899 assert(cpu->ifetch_pkt != NULL); 900 assert(cpu->_status == IcacheRetry); 901 PacketPtr tmp = cpu->ifetch_pkt; 902 if (sendTiming(tmp)) { 903 cpu->_status = IcacheWaitResponse; 904 cpu->ifetch_pkt = NULL; 905 } 906} 907 908void 909TimingSimpleCPU::completeDataAccess(PacketPtr pkt) 910{ 911 // received a response from the dcache: complete the load or store 912 // instruction 913 assert(!pkt->isError()); 914 assert(_status == DcacheWaitResponse || _status == DTBWaitResponse || 915 pkt->req->getFlags().isSet(Request::NO_ACCESS)); 916 917 numCycles += tickToCycles(curTick() - previousTick); 918 previousTick = curTick(); 919 920 if (pkt->senderState) { 921 SplitFragmentSenderState * send_state = 922 dynamic_cast<SplitFragmentSenderState *>(pkt->senderState); 923 assert(send_state); 924 delete pkt->req; 925 delete pkt; 926 PacketPtr big_pkt = send_state->bigPkt; 927 delete send_state; 928 929 SplitMainSenderState * main_send_state = 930 dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); 931 assert(main_send_state); 932 // Record the fact that this packet is no longer outstanding. 933 assert(main_send_state->outstanding != 0); 934 main_send_state->outstanding--; 935 936 if (main_send_state->outstanding) { 937 return; 938 } else { 939 delete main_send_state; 940 big_pkt->senderState = NULL; 941 pkt = big_pkt; 942 } 943 } 944 945 _status = Running; 946 947 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 948 949 // keep an instruction count 950 if (fault == NoFault) 951 countInst(); 952 else if (traceData) { 953 // If there was a fault, we shouldn't trace this instruction. 954 delete traceData; 955 traceData = NULL; 956 } 957 958 // the locked flag may be cleared on the response packet, so check 959 // pkt->req and not pkt to see if it was a load-locked 960 if (pkt->isRead() && pkt->req->isLLSC()) { 961 TheISA::handleLockedRead(thread, pkt->req); 962 } 963 964 delete pkt->req; 965 delete pkt; 966 967 postExecute(); 968 969 if (getState() == SimObject::Draining) { 970 advancePC(fault); 971 completeDrain(); 972 973 return; 974 } 975 976 advanceInst(fault); 977} 978 979 980void 981TimingSimpleCPU::completeDrain() 982{ 983 DPRINTF(Config, "Done draining\n"); 984 changeState(SimObject::Drained); 985 drainEvent->process(); 986} 987 988void 989TimingSimpleCPU::DcachePort::setPeer(Port *port) 990{ 991 Port::setPeer(port); 992 993#if FULL_SYSTEM 994 // Update the ThreadContext's memory ports (Functional/Virtual 995 // Ports) 996 cpu->tcBase()->connectMemPorts(cpu->tcBase()); 997#endif 998} 999 1000bool 1001TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt) 1002{ 1003 if (pkt->isResponse() && !pkt->wasNacked()) { 1004 // delay processing of returned data until next CPU clock edge 1005 Tick next_tick = cpu->nextCycle(curTick()); 1006 1007 if (next_tick == curTick()) { 1008 cpu->completeDataAccess(pkt); 1009 } else { 1010 if (!tickEvent.scheduled()) { 1011 tickEvent.schedule(pkt, next_tick); 1012 } else { 1013 // In the case of a split transaction and a cache that is 1014 // faster than a CPU we could get two responses before 1015 // next_tick expires 1016 if (!retryEvent.scheduled()) 1017 schedule(retryEvent, next_tick); 1018 return false; 1019 } 1020 } 1021 1022 return true; 1023 } 1024 else if (pkt->wasNacked()) { 1025 assert(cpu->_status == DcacheWaitResponse); 1026 pkt->reinitNacked(); 1027 if (!sendTiming(pkt)) { 1028 cpu->_status = DcacheRetry; 1029 cpu->dcache_pkt = pkt; 1030 } 1031 } 1032 //Snooping a Coherence Request, do nothing 1033 return true; 1034} 1035 1036void 1037TimingSimpleCPU::DcachePort::DTickEvent::process() 1038{ 1039 cpu->completeDataAccess(pkt); 1040} 1041 1042void 1043TimingSimpleCPU::DcachePort::recvRetry() 1044{ 1045 // we shouldn't get a retry unless we have a packet that we're 1046 // waiting to transmit 1047 assert(cpu->dcache_pkt != NULL); 1048 assert(cpu->_status == DcacheRetry); 1049 PacketPtr tmp = cpu->dcache_pkt; 1050 if (tmp->senderState) { 1051 // This is a packet from a split access. 1052 SplitFragmentSenderState * send_state = 1053 dynamic_cast<SplitFragmentSenderState *>(tmp->senderState); 1054 assert(send_state); 1055 PacketPtr big_pkt = send_state->bigPkt; 1056 1057 SplitMainSenderState * main_send_state = 1058 dynamic_cast<SplitMainSenderState *>(big_pkt->senderState); 1059 assert(main_send_state); 1060 1061 if (sendTiming(tmp)) { 1062 // If we were able to send without retrying, record that fact 1063 // and try sending the other fragment. 1064 send_state->clearFromParent(); 1065 int other_index = main_send_state->getPendingFragment(); 1066 if (other_index > 0) { 1067 tmp = main_send_state->fragments[other_index]; 1068 cpu->dcache_pkt = tmp; 1069 if ((big_pkt->isRead() && cpu->handleReadPacket(tmp)) || 1070 (big_pkt->isWrite() && cpu->handleWritePacket())) { 1071 main_send_state->fragments[other_index] = NULL; 1072 } 1073 } else { 1074 cpu->_status = DcacheWaitResponse; 1075 // memory system takes ownership of packet 1076 cpu->dcache_pkt = NULL; 1077 } 1078 } 1079 } else if (sendTiming(tmp)) { 1080 cpu->_status = DcacheWaitResponse; 1081 // memory system takes ownership of packet 1082 cpu->dcache_pkt = NULL; 1083 } 1084} 1085 1086TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, 1087 Tick t) 1088 : pkt(_pkt), cpu(_cpu) 1089{ 1090 cpu->schedule(this, t); 1091} 1092 1093void 1094TimingSimpleCPU::IprEvent::process() 1095{ 1096 cpu->completeDataAccess(pkt); 1097} 1098 1099const char * 1100TimingSimpleCPU::IprEvent::description() const 1101{ 1102 return "Timing Simple CPU Delay IPR event"; 1103} 1104 1105 1106void 1107TimingSimpleCPU::printAddr(Addr a) 1108{ 1109 dcachePort.printAddr(a); 1110} 1111 1112 1113//////////////////////////////////////////////////////////////////////// 1114// 1115// TimingSimpleCPU Simulation Object 1116// 1117TimingSimpleCPU * 1118TimingSimpleCPUParams::create() 1119{ 1120 numThreads = 1; 1121#if !FULL_SYSTEM 1122 if (workload.size() != 1) 1123 panic("only one workload allowed"); 1124#endif 1125 return new TimingSimpleCPU(this); 1126} 1127