atomic.cc revision 5496
111106Spower.jg@gmail.com/* 211106Spower.jg@gmail.com * Copyright (c) 2002-2005 The Regents of The University of Michigan 311106Spower.jg@gmail.com * All rights reserved. 411106Spower.jg@gmail.com * 511106Spower.jg@gmail.com * Redistribution and use in source and binary forms, with or without 611106Spower.jg@gmail.com * modification, are permitted provided that the following conditions are 711106Spower.jg@gmail.com * met: redistributions of source code must retain the above copyright 811106Spower.jg@gmail.com * notice, this list of conditions and the following disclaimer; 911106Spower.jg@gmail.com * redistributions in binary form must reproduce the above copyright 1011106Spower.jg@gmail.com * notice, this list of conditions and the following disclaimer in the 1111106Spower.jg@gmail.com * documentation and/or other materials provided with the distribution; 1211106Spower.jg@gmail.com * neither the name of the copyright holders nor the names of its 1311106Spower.jg@gmail.com * contributors may be used to endorse or promote products derived from 1411106Spower.jg@gmail.com * this software without specific prior written permission. 1511106Spower.jg@gmail.com * 1611106Spower.jg@gmail.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1711570SCurtis.Dunham@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1811106Spower.jg@gmail.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1911312Santhony.gutierrez@amd.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2011106Spower.jg@gmail.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2111106Spower.jg@gmail.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2211106Spower.jg@gmail.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2311106Spower.jg@gmail.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2411106Spower.jg@gmail.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2511106Spower.jg@gmail.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2611680SCurtis.Dunham@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2711106Spower.jg@gmail.com * 2811106Spower.jg@gmail.com * Authors: Steve Reinhardt 2911219Snilay@cs.wisc.edu */ 3011106Spower.jg@gmail.com 3111570SCurtis.Dunham@arm.com#include "arch/locked_mem.hh" 3211570SCurtis.Dunham@arm.com#include "arch/mmaped_ipr.hh" 3311570SCurtis.Dunham@arm.com#include "arch/utility.hh" 3411570SCurtis.Dunham@arm.com#include "base/bigint.hh" 3511106Spower.jg@gmail.com#include "cpu/exetrace.hh" 3611106Spower.jg@gmail.com#include "cpu/simple/atomic.hh" 3711440SCurtis.Dunham@arm.com#include "mem/packet.hh" 3811440SCurtis.Dunham@arm.com#include "mem/packet_access.hh" 3911106Spower.jg@gmail.com#include "params/AtomicSimpleCPU.hh" 4011106Spower.jg@gmail.com#include "sim/system.hh" 4111106Spower.jg@gmail.com 4211106Spower.jg@gmail.comusing namespace std; 4311106Spower.jg@gmail.comusing namespace TheISA; 4411106Spower.jg@gmail.com 4511106Spower.jg@gmail.comAtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c) 4611106Spower.jg@gmail.com : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) 4711106Spower.jg@gmail.com{ 4811106Spower.jg@gmail.com} 4911106Spower.jg@gmail.com 5011106Spower.jg@gmail.com 5111106Spower.jg@gmail.comvoid 5211106Spower.jg@gmail.comAtomicSimpleCPU::TickEvent::process() 5311106Spower.jg@gmail.com{ 5411106Spower.jg@gmail.com cpu->tick(); 5511106Spower.jg@gmail.com} 5611106Spower.jg@gmail.com 5711106Spower.jg@gmail.comconst char * 5811106Spower.jg@gmail.comAtomicSimpleCPU::TickEvent::description() const 5911106Spower.jg@gmail.com{ 6011106Spower.jg@gmail.com return "AtomicSimpleCPU tick"; 6111106Spower.jg@gmail.com} 6211106Spower.jg@gmail.com 6311106Spower.jg@gmail.comPort * 6411106Spower.jg@gmail.comAtomicSimpleCPU::getPort(const std::string &if_name, int idx) 6511106Spower.jg@gmail.com{ 6611106Spower.jg@gmail.com if (if_name == "dcache_port") 6711106Spower.jg@gmail.com return &dcachePort; 6811106Spower.jg@gmail.com else if (if_name == "icache_port") 6911570SCurtis.Dunham@arm.com return &icachePort; 7011106Spower.jg@gmail.com else if (if_name == "physmem_port") { 7111106Spower.jg@gmail.com hasPhysMemPort = true; 7211106Spower.jg@gmail.com return &physmemPort; 7311106Spower.jg@gmail.com } 7411106Spower.jg@gmail.com else 7511106Spower.jg@gmail.com panic("No Such Port\n"); 7611106Spower.jg@gmail.com} 7711106Spower.jg@gmail.com 7811106Spower.jg@gmail.comvoid 7911106Spower.jg@gmail.comAtomicSimpleCPU::init() 8011106Spower.jg@gmail.com{ 8111106Spower.jg@gmail.com BaseCPU::init(); 8211106Spower.jg@gmail.com cpuId = tc->readCpuId(); 8311106Spower.jg@gmail.com#if FULL_SYSTEM 8411106Spower.jg@gmail.com for (int i = 0; i < threadContexts.size(); ++i) { 8511570SCurtis.Dunham@arm.com ThreadContext *tc = threadContexts[i]; 8611570SCurtis.Dunham@arm.com 8711570SCurtis.Dunham@arm.com // initialize CPU, including PC 8811570SCurtis.Dunham@arm.com TheISA::initCPU(tc, cpuId); 8911106Spower.jg@gmail.com } 9011106Spower.jg@gmail.com#endif 9111106Spower.jg@gmail.com if (hasPhysMemPort) { 9211106Spower.jg@gmail.com bool snoop = false; 9311106Spower.jg@gmail.com AddrRangeList pmAddrList; 9411106Spower.jg@gmail.com physmemPort.getPeerAddressRanges(pmAddrList, snoop); 9511106Spower.jg@gmail.com physMemAddr = *pmAddrList.begin(); 9611106Spower.jg@gmail.com } 9711106Spower.jg@gmail.com ifetch_req.setThreadContext(cpuId, 0); // Add thread ID if we add MT 9811106Spower.jg@gmail.com data_read_req.setThreadContext(cpuId, 0); // Add thread ID here too 9911106Spower.jg@gmail.com data_write_req.setThreadContext(cpuId, 0); // Add thread ID here too 10011106Spower.jg@gmail.com} 10111106Spower.jg@gmail.com 10211106Spower.jg@gmail.combool 10311680SCurtis.Dunham@arm.comAtomicSimpleCPU::CpuPort::recvTiming(PacketPtr pkt) 10411106Spower.jg@gmail.com{ 10511106Spower.jg@gmail.com panic("AtomicSimpleCPU doesn't expect recvTiming callback!"); 10611219Snilay@cs.wisc.edu return true; 10711570SCurtis.Dunham@arm.com} 10811106Spower.jg@gmail.com 10911106Spower.jg@gmail.comTick 11011106Spower.jg@gmail.comAtomicSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) 11111106Spower.jg@gmail.com{ 11211106Spower.jg@gmail.com //Snooping a coherence request, just return 11311106Spower.jg@gmail.com return 0; 11411570SCurtis.Dunham@arm.com} 11511570SCurtis.Dunham@arm.com 11611570SCurtis.Dunham@arm.comvoid 11711570SCurtis.Dunham@arm.comAtomicSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) 11811106Spower.jg@gmail.com{ 11911106Spower.jg@gmail.com //No internal storage to update, just return 12011106Spower.jg@gmail.com return; 12111106Spower.jg@gmail.com} 12211106Spower.jg@gmail.com 12311106Spower.jg@gmail.comvoid 12411106Spower.jg@gmail.comAtomicSimpleCPU::CpuPort::recvStatusChange(Status status) 12511106Spower.jg@gmail.com{ 12611106Spower.jg@gmail.com if (status == RangeChange) { 12711219Snilay@cs.wisc.edu if (!snoopRangeSent) { 12811106Spower.jg@gmail.com snoopRangeSent = true; 12911106Spower.jg@gmail.com sendStatusChange(Port::RangeChange); 13011106Spower.jg@gmail.com } 13111106Spower.jg@gmail.com return; 13211106Spower.jg@gmail.com } 13311106Spower.jg@gmail.com 13411106Spower.jg@gmail.com panic("AtomicSimpleCPU doesn't expect recvStatusChange callback!"); 13511106Spower.jg@gmail.com} 13611570SCurtis.Dunham@arm.com 13711106Spower.jg@gmail.comvoid 13811106Spower.jg@gmail.comAtomicSimpleCPU::CpuPort::recvRetry() 13911570SCurtis.Dunham@arm.com{ 14011570SCurtis.Dunham@arm.com panic("AtomicSimpleCPU doesn't expect recvRetry callback!"); 14111570SCurtis.Dunham@arm.com} 14211570SCurtis.Dunham@arm.com 14311106Spower.jg@gmail.comvoid 14411106Spower.jg@gmail.comAtomicSimpleCPU::DcachePort::setPeer(Port *port) 14511106Spower.jg@gmail.com{ 14611106Spower.jg@gmail.com Port::setPeer(port); 14711106Spower.jg@gmail.com 14811106Spower.jg@gmail.com#if FULL_SYSTEM 14911106Spower.jg@gmail.com // Update the ThreadContext's memory ports (Functional/Virtual 15011106Spower.jg@gmail.com // Ports) 15111106Spower.jg@gmail.com cpu->tcBase()->connectMemPorts(); 15211106Spower.jg@gmail.com#endif 15311106Spower.jg@gmail.com} 15411680SCurtis.Dunham@arm.com 15511106Spower.jg@gmail.comAtomicSimpleCPU::AtomicSimpleCPU(Params *p) 15611106Spower.jg@gmail.com : BaseSimpleCPU(p), tickEvent(this), width(p->width), 15711219Snilay@cs.wisc.edu simulate_data_stalls(p->simulate_data_stalls), 15811570SCurtis.Dunham@arm.com simulate_inst_stalls(p->simulate_inst_stalls), 15911106Spower.jg@gmail.com icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this), 16011106Spower.jg@gmail.com physmemPort(name() + "-iport", this), hasPhysMemPort(false) 16111106Spower.jg@gmail.com{ 16211106Spower.jg@gmail.com _status = Idle; 16311106Spower.jg@gmail.com 16411106Spower.jg@gmail.com icachePort.snoopRangeSent = false; 16511570SCurtis.Dunham@arm.com dcachePort.snoopRangeSent = false; 16611570SCurtis.Dunham@arm.com 16711570SCurtis.Dunham@arm.com} 16811570SCurtis.Dunham@arm.com 16911106Spower.jg@gmail.com 17011106Spower.jg@gmail.comAtomicSimpleCPU::~AtomicSimpleCPU() 17111106Spower.jg@gmail.com{ 17211106Spower.jg@gmail.com} 17311106Spower.jg@gmail.com 17411106Spower.jg@gmail.comvoid 17511106Spower.jg@gmail.comAtomicSimpleCPU::serialize(ostream &os) 17611106Spower.jg@gmail.com{ 17711106Spower.jg@gmail.com SimObject::State so_state = SimObject::getState(); 17811219Snilay@cs.wisc.edu SERIALIZE_ENUM(so_state); 17911106Spower.jg@gmail.com BaseSimpleCPU::serialize(os); 18011106Spower.jg@gmail.com nameOut(os, csprintf("%s.tickEvent", name())); 18111106Spower.jg@gmail.com tickEvent.serialize(os); 18211106Spower.jg@gmail.com} 18311106Spower.jg@gmail.com 18411106Spower.jg@gmail.comvoid 18511106Spower.jg@gmail.comAtomicSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 18611106Spower.jg@gmail.com{ 18711570SCurtis.Dunham@arm.com SimObject::State so_state; 18811106Spower.jg@gmail.com UNSERIALIZE_ENUM(so_state); 18911106Spower.jg@gmail.com BaseSimpleCPU::unserialize(cp, section); 19011570SCurtis.Dunham@arm.com tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); 19111570SCurtis.Dunham@arm.com} 19211570SCurtis.Dunham@arm.com 19311570SCurtis.Dunham@arm.comvoid 19411106Spower.jg@gmail.comAtomicSimpleCPU::resume() 19511106Spower.jg@gmail.com{ 19611106Spower.jg@gmail.com if (_status == Idle || _status == SwitchedOut) 19711106Spower.jg@gmail.com return; 19811106Spower.jg@gmail.com 19911106Spower.jg@gmail.com DPRINTF(SimpleCPU, "Resume\n"); 20011106Spower.jg@gmail.com assert(system->getMemoryMode() == Enums::atomic); 20111106Spower.jg@gmail.com 20211106Spower.jg@gmail.com changeState(SimObject::Running); 20311106Spower.jg@gmail.com if (thread->status() == ThreadContext::Active) { 20411106Spower.jg@gmail.com if (!tickEvent.scheduled()) { 20511106Spower.jg@gmail.com tickEvent.schedule(nextCycle()); 20611106Spower.jg@gmail.com } 20711106Spower.jg@gmail.com } 20811106Spower.jg@gmail.com} 20911106Spower.jg@gmail.com 21011106Spower.jg@gmail.comvoid 21111106Spower.jg@gmail.comAtomicSimpleCPU::switchOut() 21211106Spower.jg@gmail.com{ 21311106Spower.jg@gmail.com assert(_status == Running || _status == Idle); 21411106Spower.jg@gmail.com _status = SwitchedOut; 21511106Spower.jg@gmail.com 21611106Spower.jg@gmail.com tickEvent.squash(); 21711106Spower.jg@gmail.com} 21811106Spower.jg@gmail.com 21911106Spower.jg@gmail.com 22011106Spower.jg@gmail.comvoid 22111106Spower.jg@gmail.comAtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 22211106Spower.jg@gmail.com{ 22311106Spower.jg@gmail.com BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort); 22411106Spower.jg@gmail.com 22511106Spower.jg@gmail.com assert(!tickEvent.scheduled()); 22611106Spower.jg@gmail.com 22711106Spower.jg@gmail.com // if any of this CPU's ThreadContexts are active, mark the CPU as 22811106Spower.jg@gmail.com // running and schedule its tick event. 22911106Spower.jg@gmail.com for (int i = 0; i < threadContexts.size(); ++i) { 23011106Spower.jg@gmail.com ThreadContext *tc = threadContexts[i]; 23111106Spower.jg@gmail.com if (tc->status() == ThreadContext::Active && _status != Running) { 23211106Spower.jg@gmail.com _status = Running; 23311106Spower.jg@gmail.com tickEvent.schedule(nextCycle()); 23411106Spower.jg@gmail.com break; 23511106Spower.jg@gmail.com } 23611106Spower.jg@gmail.com } 23711106Spower.jg@gmail.com if (_status != Running) { 23811106Spower.jg@gmail.com _status = Idle; 23911106Spower.jg@gmail.com } 24011106Spower.jg@gmail.com assert(threadContexts.size() == 1); 24111106Spower.jg@gmail.com cpuId = tc->readCpuId(); 24211106Spower.jg@gmail.com ifetch_req.setThreadContext(cpuId, 0); // Add thread ID if we add MT 24311106Spower.jg@gmail.com data_read_req.setThreadContext(cpuId, 0); // Add thread ID here too 24411106Spower.jg@gmail.com data_write_req.setThreadContext(cpuId, 0); // Add thread ID here too 24511106Spower.jg@gmail.com} 24611106Spower.jg@gmail.com 24711219Snilay@cs.wisc.edu 24811106Spower.jg@gmail.comvoid 24911570SCurtis.Dunham@arm.comAtomicSimpleCPU::activateContext(int thread_num, int delay) 25011106Spower.jg@gmail.com{ 25111106Spower.jg@gmail.com DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay); 25211106Spower.jg@gmail.com 25311570SCurtis.Dunham@arm.com assert(thread_num == 0); 25411570SCurtis.Dunham@arm.com assert(thread); 25511570SCurtis.Dunham@arm.com 25611440SCurtis.Dunham@arm.com assert(_status == Idle); 25711570SCurtis.Dunham@arm.com assert(!tickEvent.scheduled()); 25811106Spower.jg@gmail.com 25911219Snilay@cs.wisc.edu notIdleFraction++; 26011106Spower.jg@gmail.com numCycles += tickToCycles(thread->lastActivate - thread->lastSuspend); 26111106Spower.jg@gmail.com 26211106Spower.jg@gmail.com //Make sure ticks are still on multiples of cycles 26311106Spower.jg@gmail.com tickEvent.schedule(nextCycle(curTick + ticks(delay))); 26411106Spower.jg@gmail.com _status = Running; 26511106Spower.jg@gmail.com} 26611106Spower.jg@gmail.com 26711219Snilay@cs.wisc.edu 26811219Snilay@cs.wisc.eduvoid 26911219Snilay@cs.wisc.eduAtomicSimpleCPU::suspendContext(int thread_num) 27011219Snilay@cs.wisc.edu{ 27111219Snilay@cs.wisc.edu DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num); 27211219Snilay@cs.wisc.edu 27311219Snilay@cs.wisc.edu assert(thread_num == 0); 27411106Spower.jg@gmail.com assert(thread); 27511106Spower.jg@gmail.com 27611106Spower.jg@gmail.com assert(_status == Running); 27711680SCurtis.Dunham@arm.com 27811106Spower.jg@gmail.com // tick event may not be scheduled if this gets called from inside 27911106Spower.jg@gmail.com // an instruction's execution, e.g. "quiesce" 28011219Snilay@cs.wisc.edu if (tickEvent.scheduled()) 28111570SCurtis.Dunham@arm.com tickEvent.deschedule(); 28211106Spower.jg@gmail.com 28311106Spower.jg@gmail.com notIdleFraction--; 28411106Spower.jg@gmail.com _status = Idle; 28511106Spower.jg@gmail.com} 28611106Spower.jg@gmail.com 28711106Spower.jg@gmail.com 28811570SCurtis.Dunham@arm.comtemplate <class T> 28911570SCurtis.Dunham@arm.comFault 29011570SCurtis.Dunham@arm.comAtomicSimpleCPU::read(Addr addr, T &data, unsigned flags) 29111570SCurtis.Dunham@arm.com{ 29211106Spower.jg@gmail.com // use the CPU's statically allocated read request and packet objects 29311106Spower.jg@gmail.com Request *req = &data_read_req; 29411106Spower.jg@gmail.com 29511106Spower.jg@gmail.com if (traceData) { 29611106Spower.jg@gmail.com traceData->setAddr(addr); 29711106Spower.jg@gmail.com } 29811106Spower.jg@gmail.com 29911106Spower.jg@gmail.com //The block size of our peer. 30011106Spower.jg@gmail.com int blockSize = dcachePort.peerBlockSize(); 30111219Snilay@cs.wisc.edu //The size of the data we're trying to read. 30211106Spower.jg@gmail.com int dataSize = sizeof(T); 30311106Spower.jg@gmail.com 30411106Spower.jg@gmail.com uint8_t * dataPtr = (uint8_t *)&data; 30511106Spower.jg@gmail.com 30611106Spower.jg@gmail.com //The address of the second part of this access if it needs to be split 30711106Spower.jg@gmail.com //across a cache line boundary. 30811106Spower.jg@gmail.com Addr secondAddr = roundDown(addr + dataSize - 1, blockSize); 30911106Spower.jg@gmail.com 31011570SCurtis.Dunham@arm.com if(secondAddr > addr) 31111106Spower.jg@gmail.com dataSize = secondAddr - addr; 31211106Spower.jg@gmail.com 31311570SCurtis.Dunham@arm.com dcache_latency = 0; 31411570SCurtis.Dunham@arm.com 31511570SCurtis.Dunham@arm.com while(1) { 31611570SCurtis.Dunham@arm.com req->setVirt(0, addr, dataSize, flags, thread->readPC()); 31711106Spower.jg@gmail.com 31811106Spower.jg@gmail.com // translate to physical address 31911106Spower.jg@gmail.com Fault fault = thread->translateDataReadReq(req); 32011106Spower.jg@gmail.com 32111106Spower.jg@gmail.com // Now do the access. 32211680SCurtis.Dunham@arm.com if (fault == NoFault) { 32311106Spower.jg@gmail.com Packet pkt = Packet(req, 32411680SCurtis.Dunham@arm.com req->isLocked() ? MemCmd::LoadLockedReq : MemCmd::ReadReq, 32511106Spower.jg@gmail.com Packet::Broadcast); 32611106Spower.jg@gmail.com pkt.dataStatic(dataPtr); 32711106Spower.jg@gmail.com 32811680SCurtis.Dunham@arm.com if (req->isMmapedIpr()) 32911106Spower.jg@gmail.com dcache_latency += TheISA::handleIprRead(thread->getTC(), &pkt); 33011680SCurtis.Dunham@arm.com else { 33111106Spower.jg@gmail.com if (hasPhysMemPort && pkt.getAddr() == physMemAddr) 33211106Spower.jg@gmail.com dcache_latency += physmemPort.sendAtomic(&pkt); 33311106Spower.jg@gmail.com else 33411680SCurtis.Dunham@arm.com dcache_latency += dcachePort.sendAtomic(&pkt); 33511106Spower.jg@gmail.com } 33611680SCurtis.Dunham@arm.com dcache_access = true; 33711106Spower.jg@gmail.com 33811680SCurtis.Dunham@arm.com assert(!pkt.isError()); 33911106Spower.jg@gmail.com 34011680SCurtis.Dunham@arm.com if (req->isLocked()) { 34111106Spower.jg@gmail.com TheISA::handleLockedRead(thread, req); 34211680SCurtis.Dunham@arm.com } 34311106Spower.jg@gmail.com } 34411106Spower.jg@gmail.com 34511106Spower.jg@gmail.com // This will need a new way to tell if it has a dcache attached. 34611106Spower.jg@gmail.com if (req->isUncacheable()) 34711106Spower.jg@gmail.com recordEvent("Uncached Read"); 34811106Spower.jg@gmail.com 34911106Spower.jg@gmail.com //If there's a fault, return it 35011106Spower.jg@gmail.com if (fault != NoFault) 35111106Spower.jg@gmail.com return fault; 35211106Spower.jg@gmail.com //If we don't need to access a second cache line, stop now. 35311106Spower.jg@gmail.com if (secondAddr <= addr) 35411570SCurtis.Dunham@arm.com { 35511106Spower.jg@gmail.com data = gtoh(data); 35611106Spower.jg@gmail.com if (traceData) { 35711106Spower.jg@gmail.com traceData->setData(data); 35811106Spower.jg@gmail.com } 35911106Spower.jg@gmail.com return fault; 36011106Spower.jg@gmail.com } 36111106Spower.jg@gmail.com 36211680SCurtis.Dunham@arm.com /* 36311106Spower.jg@gmail.com * Set up for accessing the second cache line. 36411106Spower.jg@gmail.com */ 36511106Spower.jg@gmail.com 36611106Spower.jg@gmail.com //Move the pointer we're reading into to the correct location. 36711570SCurtis.Dunham@arm.com dataPtr += dataSize; 36811570SCurtis.Dunham@arm.com //Adjust the size to get the remaining bytes. 36911570SCurtis.Dunham@arm.com dataSize = addr + sizeof(T) - secondAddr; 37011106Spower.jg@gmail.com //And access the right address. 37111570SCurtis.Dunham@arm.com addr = secondAddr; 37211680SCurtis.Dunham@arm.com } 37311106Spower.jg@gmail.com} 37411106Spower.jg@gmail.com 37511106Spower.jg@gmail.comFault 37611106Spower.jg@gmail.comAtomicSimpleCPU::translateDataReadAddr(Addr vaddr, Addr & paddr, 37711106Spower.jg@gmail.com int size, unsigned flags) 37811106Spower.jg@gmail.com{ 37911106Spower.jg@gmail.com // use the CPU's statically allocated read request and packet objects 38011106Spower.jg@gmail.com Request *req = &data_read_req; 38111106Spower.jg@gmail.com 38211106Spower.jg@gmail.com if (traceData) { 38311106Spower.jg@gmail.com traceData->setAddr(vaddr); 38411106Spower.jg@gmail.com } 38511106Spower.jg@gmail.com 38611106Spower.jg@gmail.com //The block size of our peer. 38711106Spower.jg@gmail.com int blockSize = dcachePort.peerBlockSize(); 38811106Spower.jg@gmail.com //The size of the data we're trying to read. 38911106Spower.jg@gmail.com int dataSize = size; 39011106Spower.jg@gmail.com 39111106Spower.jg@gmail.com bool firstTimeThrough = true; 39211106Spower.jg@gmail.com 39311106Spower.jg@gmail.com //The address of the second part of this access if it needs to be split 39411680SCurtis.Dunham@arm.com //across a cache line boundary. 39511106Spower.jg@gmail.com Addr secondAddr = roundDown(vaddr + dataSize - 1, blockSize); 39611680SCurtis.Dunham@arm.com 39711106Spower.jg@gmail.com if(secondAddr > vaddr) 39811106Spower.jg@gmail.com dataSize = secondAddr - vaddr; 39911106Spower.jg@gmail.com 40011106Spower.jg@gmail.com while(1) { 40111106Spower.jg@gmail.com req->setVirt(0, vaddr, dataSize, flags, thread->readPC()); 40211106Spower.jg@gmail.com 40311106Spower.jg@gmail.com // translate to physical address 40411106Spower.jg@gmail.com Fault fault = thread->translateDataReadReq(req); 40511680SCurtis.Dunham@arm.com 40611106Spower.jg@gmail.com //If there's a fault, return it 40711570SCurtis.Dunham@arm.com if (fault != NoFault) 40811106Spower.jg@gmail.com return fault; 40911106Spower.jg@gmail.com 41011106Spower.jg@gmail.com if (firstTimeThrough) { 41111570SCurtis.Dunham@arm.com paddr = req->getPaddr(); 41211570SCurtis.Dunham@arm.com firstTimeThrough = false; 41311570SCurtis.Dunham@arm.com } 41411440SCurtis.Dunham@arm.com 41511570SCurtis.Dunham@arm.com //If we don't need to access a second cache line, stop now. 41611106Spower.jg@gmail.com if (secondAddr <= vaddr) 41711680SCurtis.Dunham@arm.com return fault; 41811106Spower.jg@gmail.com 41911106Spower.jg@gmail.com /* 42011106Spower.jg@gmail.com * Set up for accessing the second cache line. 42111106Spower.jg@gmail.com */ 42211106Spower.jg@gmail.com 42311106Spower.jg@gmail.com //Adjust the size to get the remaining bytes. 42411106Spower.jg@gmail.com dataSize = vaddr + size - secondAddr; 42511680SCurtis.Dunham@arm.com //And access the right address. 42611680SCurtis.Dunham@arm.com vaddr = secondAddr; 42711680SCurtis.Dunham@arm.com } 42811680SCurtis.Dunham@arm.com} 42911680SCurtis.Dunham@arm.com 43011680SCurtis.Dunham@arm.com#ifndef DOXYGEN_SHOULD_SKIP_THIS 43111680SCurtis.Dunham@arm.com 432template 433Fault 434AtomicSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags); 435 436template 437Fault 438AtomicSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags); 439 440template 441Fault 442AtomicSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 443 444template 445Fault 446AtomicSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 447 448template 449Fault 450AtomicSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 451 452template 453Fault 454AtomicSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 455 456#endif //DOXYGEN_SHOULD_SKIP_THIS 457 458template<> 459Fault 460AtomicSimpleCPU::read(Addr addr, double &data, unsigned flags) 461{ 462 return read(addr, *(uint64_t*)&data, flags); 463} 464 465template<> 466Fault 467AtomicSimpleCPU::read(Addr addr, float &data, unsigned flags) 468{ 469 return read(addr, *(uint32_t*)&data, flags); 470} 471 472 473template<> 474Fault 475AtomicSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 476{ 477 return read(addr, (uint32_t&)data, flags); 478} 479 480 481template <class T> 482Fault 483AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 484{ 485 // use the CPU's statically allocated write request and packet objects 486 Request *req = &data_write_req; 487 488 if (traceData) { 489 traceData->setAddr(addr); 490 } 491 492 //The block size of our peer. 493 int blockSize = dcachePort.peerBlockSize(); 494 //The size of the data we're trying to read. 495 int dataSize = sizeof(T); 496 497 uint8_t * dataPtr = (uint8_t *)&data; 498 499 //The address of the second part of this access if it needs to be split 500 //across a cache line boundary. 501 Addr secondAddr = roundDown(addr + dataSize - 1, blockSize); 502 503 if(secondAddr > addr) 504 dataSize = secondAddr - addr; 505 506 dcache_latency = 0; 507 508 while(1) { 509 req->setVirt(0, addr, dataSize, flags, thread->readPC()); 510 511 // translate to physical address 512 Fault fault = thread->translateDataWriteReq(req); 513 514 // Now do the access. 515 if (fault == NoFault) { 516 MemCmd cmd = MemCmd::WriteReq; // default 517 bool do_access = true; // flag to suppress cache access 518 519 if (req->isLocked()) { 520 cmd = MemCmd::StoreCondReq; 521 do_access = TheISA::handleLockedWrite(thread, req); 522 } else if (req->isSwap()) { 523 cmd = MemCmd::SwapReq; 524 if (req->isCondSwap()) { 525 assert(res); 526 req->setExtraData(*res); 527 } 528 } 529 530 if (do_access) { 531 Packet pkt = Packet(req, cmd, Packet::Broadcast); 532 pkt.dataStatic(dataPtr); 533 534 if (req->isMmapedIpr()) { 535 dcache_latency += 536 TheISA::handleIprWrite(thread->getTC(), &pkt); 537 } else { 538 //XXX This needs to be outside of the loop in order to 539 //work properly for cache line boundary crossing 540 //accesses in transendian simulations. 541 data = htog(data); 542 if (hasPhysMemPort && pkt.getAddr() == physMemAddr) 543 dcache_latency += physmemPort.sendAtomic(&pkt); 544 else 545 dcache_latency += dcachePort.sendAtomic(&pkt); 546 } 547 dcache_access = true; 548 assert(!pkt.isError()); 549 550 if (req->isSwap()) { 551 assert(res); 552 *res = pkt.get<T>(); 553 } 554 } 555 556 if (res && !req->isSwap()) { 557 *res = req->getExtraData(); 558 } 559 } 560 561 // This will need a new way to tell if it's hooked up to a cache or not. 562 if (req->isUncacheable()) 563 recordEvent("Uncached Write"); 564 565 //If there's a fault or we don't need to access a second cache line, 566 //stop now. 567 if (fault != NoFault || secondAddr <= addr) 568 { 569 // If the write needs to have a fault on the access, consider 570 // calling changeStatus() and changing it to "bad addr write" 571 // or something. 572 if (traceData) { 573 traceData->setData(data); 574 } 575 return fault; 576 } 577 578 /* 579 * Set up for accessing the second cache line. 580 */ 581 582 //Move the pointer we're reading into to the correct location. 583 dataPtr += dataSize; 584 //Adjust the size to get the remaining bytes. 585 dataSize = addr + sizeof(T) - secondAddr; 586 //And access the right address. 587 addr = secondAddr; 588 } 589} 590 591Fault 592AtomicSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr, 593 int size, unsigned flags) 594{ 595 // use the CPU's statically allocated write request and packet objects 596 Request *req = &data_write_req; 597 598 if (traceData) { 599 traceData->setAddr(vaddr); 600 } 601 602 //The block size of our peer. 603 int blockSize = dcachePort.peerBlockSize(); 604 605 //The address of the second part of this access if it needs to be split 606 //across a cache line boundary. 607 Addr secondAddr = roundDown(vaddr + size - 1, blockSize); 608 609 //The size of the data we're trying to read. 610 int dataSize = size; 611 612 bool firstTimeThrough = true; 613 614 if(secondAddr > vaddr) 615 dataSize = secondAddr - vaddr; 616 617 dcache_latency = 0; 618 619 while(1) { 620 req->setVirt(0, vaddr, dataSize, flags, thread->readPC()); 621 622 // translate to physical address 623 Fault fault = thread->translateDataWriteReq(req); 624 625 //If there's a fault or we don't need to access a second cache line, 626 //stop now. 627 if (fault != NoFault) 628 return fault; 629 630 if (firstTimeThrough) { 631 paddr = req->getPaddr(); 632 firstTimeThrough = false; 633 } 634 635 if (secondAddr <= vaddr) 636 return fault; 637 638 /* 639 * Set up for accessing the second cache line. 640 */ 641 642 //Adjust the size to get the remaining bytes. 643 dataSize = vaddr + size - secondAddr; 644 //And access the right address. 645 vaddr = secondAddr; 646 } 647} 648 649 650#ifndef DOXYGEN_SHOULD_SKIP_THIS 651 652template 653Fault 654AtomicSimpleCPU::write(Twin32_t data, Addr addr, 655 unsigned flags, uint64_t *res); 656 657template 658Fault 659AtomicSimpleCPU::write(Twin64_t data, Addr addr, 660 unsigned flags, uint64_t *res); 661 662template 663Fault 664AtomicSimpleCPU::write(uint64_t data, Addr addr, 665 unsigned flags, uint64_t *res); 666 667template 668Fault 669AtomicSimpleCPU::write(uint32_t data, Addr addr, 670 unsigned flags, uint64_t *res); 671 672template 673Fault 674AtomicSimpleCPU::write(uint16_t data, Addr addr, 675 unsigned flags, uint64_t *res); 676 677template 678Fault 679AtomicSimpleCPU::write(uint8_t data, Addr addr, 680 unsigned flags, uint64_t *res); 681 682#endif //DOXYGEN_SHOULD_SKIP_THIS 683 684template<> 685Fault 686AtomicSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 687{ 688 return write(*(uint64_t*)&data, addr, flags, res); 689} 690 691template<> 692Fault 693AtomicSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 694{ 695 return write(*(uint32_t*)&data, addr, flags, res); 696} 697 698 699template<> 700Fault 701AtomicSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 702{ 703 return write((uint32_t)data, addr, flags, res); 704} 705 706 707void 708AtomicSimpleCPU::tick() 709{ 710 DPRINTF(SimpleCPU, "Tick\n"); 711 712 Tick latency = 0; 713 714 for (int i = 0; i < width; ++i) { 715 numCycles++; 716 717 if (!curStaticInst || !curStaticInst->isDelayedCommit()) 718 checkForInterrupts(); 719 720 checkPcEventQueue(); 721 722 Fault fault = setupFetchRequest(&ifetch_req); 723 724 if (fault == NoFault) { 725 Tick icache_latency = 0; 726 bool icache_access = false; 727 dcache_access = false; // assume no dcache access 728 729 //Fetch more instruction memory if necessary 730 //if(predecoder.needMoreBytes()) 731 //{ 732 icache_access = true; 733 Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq, 734 Packet::Broadcast); 735 ifetch_pkt.dataStatic(&inst); 736 737 if (hasPhysMemPort && ifetch_pkt.getAddr() == physMemAddr) 738 icache_latency = physmemPort.sendAtomic(&ifetch_pkt); 739 else 740 icache_latency = icachePort.sendAtomic(&ifetch_pkt); 741 742 assert(!ifetch_pkt.isError()); 743 744 // ifetch_req is initialized to read the instruction directly 745 // into the CPU object's inst field. 746 //} 747 748 preExecute(); 749 750 if (curStaticInst) { 751 fault = curStaticInst->execute(this, traceData); 752 753 // keep an instruction count 754 if (fault == NoFault) 755 countInst(); 756 else if (traceData) { 757 // If there was a fault, we should trace this instruction. 758 delete traceData; 759 traceData = NULL; 760 } 761 762 postExecute(); 763 } 764 765 // @todo remove me after debugging with legion done 766 if (curStaticInst && (!curStaticInst->isMicroop() || 767 curStaticInst->isFirstMicroop())) 768 instCnt++; 769 770 Tick stall_ticks = 0; 771 if (simulate_inst_stalls && icache_access) 772 stall_ticks += icache_latency; 773 774 if (simulate_data_stalls && dcache_access) 775 stall_ticks += dcache_latency; 776 777 if (stall_ticks) { 778 Tick stall_cycles = stall_ticks / ticks(1); 779 Tick aligned_stall_ticks = ticks(stall_cycles); 780 781 if (aligned_stall_ticks < stall_ticks) 782 aligned_stall_ticks += 1; 783 784 latency += aligned_stall_ticks; 785 } 786 787 } 788 if(fault != NoFault || !stayAtPC) 789 advancePC(fault); 790 } 791 792 // instruction takes at least one cycle 793 if (latency < ticks(1)) 794 latency = ticks(1); 795 796 if (_status != Idle) 797 tickEvent.schedule(curTick + latency); 798} 799 800 801void 802AtomicSimpleCPU::printAddr(Addr a) 803{ 804 dcachePort.printAddr(a); 805} 806 807 808//////////////////////////////////////////////////////////////////////// 809// 810// AtomicSimpleCPU Simulation Object 811// 812AtomicSimpleCPU * 813AtomicSimpleCPUParams::create() 814{ 815 AtomicSimpleCPU::Params *params = new AtomicSimpleCPU::Params(); 816 params->name = name; 817 params->numberOfThreads = 1; 818 params->max_insts_any_thread = max_insts_any_thread; 819 params->max_insts_all_threads = max_insts_all_threads; 820 params->max_loads_any_thread = max_loads_any_thread; 821 params->max_loads_all_threads = max_loads_all_threads; 822 params->progress_interval = progress_interval; 823 params->deferRegistration = defer_registration; 824 params->phase = phase; 825 params->clock = clock; 826 params->functionTrace = function_trace; 827 params->functionTraceStart = function_trace_start; 828 params->width = width; 829 params->simulate_data_stalls = simulate_data_stalls; 830 params->simulate_inst_stalls = simulate_inst_stalls; 831 params->system = system; 832 params->cpu_id = cpu_id; 833 params->tracer = tracer; 834 835 params->itb = itb; 836 params->dtb = dtb; 837#if FULL_SYSTEM 838 params->profile = profile; 839 params->do_quiesce = do_quiesce; 840 params->do_checkpoint_insts = do_checkpoint_insts; 841 params->do_statistics_insts = do_statistics_insts; 842#else 843 if (workload.size() != 1) 844 panic("only one workload allowed"); 845 params->process = workload[0]; 846#endif 847 848 AtomicSimpleCPU *cpu = new AtomicSimpleCPU(params); 849 return cpu; 850} 851