atomic.cc revision 8949
110515SAli.Saidi@ARM.com/* 210515SAli.Saidi@ARM.com * Copyright (c) 2012 ARM Limited 310515SAli.Saidi@ARM.com * All rights reserved. 410515SAli.Saidi@ARM.com * 510515SAli.Saidi@ARM.com * The license below extends only to copyright in the software and shall 610515SAli.Saidi@ARM.com * not be construed as granting a license to any other intellectual 710515SAli.Saidi@ARM.com * property including but not limited to intellectual property relating 810515SAli.Saidi@ARM.com * to a hardware implementation of the functionality of the software 910515SAli.Saidi@ARM.com * licensed hereunder. You may use the software subject to the license 1010515SAli.Saidi@ARM.com * terms below provided that you ensure that this notice is replicated 1110515SAli.Saidi@ARM.com * unmodified and in its entirety in all distributions of the software, 1210515SAli.Saidi@ARM.com * modified or unmodified, in source code or in binary form. 1310515SAli.Saidi@ARM.com * 1410515SAli.Saidi@ARM.com * Copyright (c) 2002-2005 The Regents of The University of Michigan 1511570SCurtis.Dunham@arm.com * All rights reserved. 1610515SAli.Saidi@ARM.com * 1710515SAli.Saidi@ARM.com * Redistribution and use in source and binary forms, with or without 1810515SAli.Saidi@ARM.com * modification, are permitted provided that the following conditions are 1911570SCurtis.Dunham@arm.com * met: redistributions of source code must retain the above copyright 2011570SCurtis.Dunham@arm.com * notice, this list of conditions and the following disclaimer; 2110515SAli.Saidi@ARM.com * redistributions in binary form must reproduce the above copyright 2210515SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer in the 2310515SAli.Saidi@ARM.com * documentation and/or other materials provided with the distribution; 2411570SCurtis.Dunham@arm.com * neither the name of the copyright holders nor the names of its 2510515SAli.Saidi@ARM.com * contributors may be used to endorse or promote products derived from 2610515SAli.Saidi@ARM.com * this software without specific prior written permission. 2710515SAli.Saidi@ARM.com * 2811570SCurtis.Dunham@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2910515SAli.Saidi@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3010515SAli.Saidi@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3110515SAli.Saidi@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3210515SAli.Saidi@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3311570SCurtis.Dunham@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3410515SAli.Saidi@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3510515SAli.Saidi@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3610515SAli.Saidi@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3710515SAli.Saidi@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3810515SAli.Saidi@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3910515SAli.Saidi@ARM.com * 4010798Ssteve.reinhardt@amd.com * Authors: Steve Reinhardt 4110798Ssteve.reinhardt@amd.com */ 4210515SAli.Saidi@ARM.com 4311167Sjthestness@gmail.com#include "arch/locked_mem.hh" 4410515SAli.Saidi@ARM.com#include "arch/mmapped_ipr.hh" 4511570SCurtis.Dunham@arm.com#include "arch/utility.hh" 4611570SCurtis.Dunham@arm.com#include "base/bigint.hh" 4711570SCurtis.Dunham@arm.com#include "config/the_isa.hh" 4810515SAli.Saidi@ARM.com#include "cpu/simple/atomic.hh" 4910515SAli.Saidi@ARM.com#include "cpu/exetrace.hh" 5010515SAli.Saidi@ARM.com#include "debug/ExecFaulting.hh" 5111570SCurtis.Dunham@arm.com#include "debug/SimpleCPU.hh" 5211570SCurtis.Dunham@arm.com#include "mem/packet.hh" 5310515SAli.Saidi@ARM.com#include "mem/packet_access.hh" 5410515SAli.Saidi@ARM.com#include "mem/physical.hh" 5511570SCurtis.Dunham@arm.com#include "params/AtomicSimpleCPU.hh" 5611570SCurtis.Dunham@arm.com#include "sim/faults.hh" 5710515SAli.Saidi@ARM.com#include "sim/system.hh" 5810515SAli.Saidi@ARM.com#include "sim/full_system.hh" 5910515SAli.Saidi@ARM.com 6010515SAli.Saidi@ARM.comusing namespace std; 6110515SAli.Saidi@ARM.comusing namespace TheISA; 6210515SAli.Saidi@ARM.com 6310515SAli.Saidi@ARM.comAtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c) 6410515SAli.Saidi@ARM.com : Event(CPU_Tick_Pri), cpu(c) 6510515SAli.Saidi@ARM.com{ 6610515SAli.Saidi@ARM.com} 6710515SAli.Saidi@ARM.com 6810515SAli.Saidi@ARM.com 6911570SCurtis.Dunham@arm.comvoid 7010515SAli.Saidi@ARM.comAtomicSimpleCPU::TickEvent::process() 7110515SAli.Saidi@ARM.com{ 7211570SCurtis.Dunham@arm.com cpu->tick(); 7311570SCurtis.Dunham@arm.com} 7411570SCurtis.Dunham@arm.com 7511570SCurtis.Dunham@arm.comconst char * 7610515SAli.Saidi@ARM.comAtomicSimpleCPU::TickEvent::description() const 7710515SAli.Saidi@ARM.com{ 7810515SAli.Saidi@ARM.com return "AtomicSimpleCPU tick"; 7910515SAli.Saidi@ARM.com} 8010515SAli.Saidi@ARM.com 8110515SAli.Saidi@ARM.comvoid 8210515SAli.Saidi@ARM.comAtomicSimpleCPU::init() 8310515SAli.Saidi@ARM.com{ 8410515SAli.Saidi@ARM.com BaseCPU::init(); 8510515SAli.Saidi@ARM.com 8610515SAli.Saidi@ARM.com // Initialise the ThreadContext's memory proxies 8710515SAli.Saidi@ARM.com tcBase()->initMemProxies(tcBase()); 8810515SAli.Saidi@ARM.com 8910515SAli.Saidi@ARM.com if (FullSystem) { 9010515SAli.Saidi@ARM.com ThreadID size = threadContexts.size(); 9110515SAli.Saidi@ARM.com for (ThreadID i = 0; i < size; ++i) { 9210515SAli.Saidi@ARM.com ThreadContext *tc = threadContexts[i]; 9310515SAli.Saidi@ARM.com // initialize CPU, including PC 9410515SAli.Saidi@ARM.com TheISA::initCPU(tc, tc->contextId()); 9510515SAli.Saidi@ARM.com } 9610515SAli.Saidi@ARM.com } 9710515SAli.Saidi@ARM.com 9810515SAli.Saidi@ARM.com // Atomic doesn't do MT right now, so contextId == threadId 9910515SAli.Saidi@ARM.com ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT 10010515SAli.Saidi@ARM.com data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too 10110515SAli.Saidi@ARM.com data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too 10211570SCurtis.Dunham@arm.com} 10310515SAli.Saidi@ARM.com 10410515SAli.Saidi@ARM.comAtomicSimpleCPU::AtomicSimpleCPU(AtomicSimpleCPUParams *p) 10510515SAli.Saidi@ARM.com : BaseSimpleCPU(p), tickEvent(this), width(p->width), locked(false), 10610515SAli.Saidi@ARM.com simulate_data_stalls(p->simulate_data_stalls), 10710515SAli.Saidi@ARM.com simulate_inst_stalls(p->simulate_inst_stalls), 10810515SAli.Saidi@ARM.com icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this), 10910515SAli.Saidi@ARM.com fastmem(p->fastmem) 11010515SAli.Saidi@ARM.com{ 11110515SAli.Saidi@ARM.com _status = Idle; 11210515SAli.Saidi@ARM.com} 11310515SAli.Saidi@ARM.com 11410515SAli.Saidi@ARM.com 11510515SAli.Saidi@ARM.comAtomicSimpleCPU::~AtomicSimpleCPU() 11610515SAli.Saidi@ARM.com{ 11710515SAli.Saidi@ARM.com if (tickEvent.scheduled()) { 11810515SAli.Saidi@ARM.com deschedule(tickEvent); 11910515SAli.Saidi@ARM.com } 12010515SAli.Saidi@ARM.com} 12110515SAli.Saidi@ARM.com 12210515SAli.Saidi@ARM.comvoid 12310515SAli.Saidi@ARM.comAtomicSimpleCPU::serialize(ostream &os) 12410515SAli.Saidi@ARM.com{ 12510515SAli.Saidi@ARM.com SimObject::State so_state = SimObject::getState(); 12610515SAli.Saidi@ARM.com SERIALIZE_ENUM(so_state); 12710515SAli.Saidi@ARM.com SERIALIZE_SCALAR(locked); 12810515SAli.Saidi@ARM.com BaseSimpleCPU::serialize(os); 12910515SAli.Saidi@ARM.com nameOut(os, csprintf("%s.tickEvent", name())); 13010515SAli.Saidi@ARM.com tickEvent.serialize(os); 13110515SAli.Saidi@ARM.com} 13210515SAli.Saidi@ARM.com 13310515SAli.Saidi@ARM.comvoid 13410515SAli.Saidi@ARM.comAtomicSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 13510515SAli.Saidi@ARM.com{ 13610515SAli.Saidi@ARM.com SimObject::State so_state; 13711570SCurtis.Dunham@arm.com UNSERIALIZE_ENUM(so_state); 13810515SAli.Saidi@ARM.com UNSERIALIZE_SCALAR(locked); 13910515SAli.Saidi@ARM.com BaseSimpleCPU::unserialize(cp, section); 14010515SAli.Saidi@ARM.com tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); 14110515SAli.Saidi@ARM.com} 14210515SAli.Saidi@ARM.com 14310515SAli.Saidi@ARM.comvoid 14410515SAli.Saidi@ARM.comAtomicSimpleCPU::resume() 14510515SAli.Saidi@ARM.com{ 14610515SAli.Saidi@ARM.com if (_status == Idle || _status == SwitchedOut) 14710515SAli.Saidi@ARM.com return; 14810515SAli.Saidi@ARM.com 14910515SAli.Saidi@ARM.com DPRINTF(SimpleCPU, "Resume\n"); 15010515SAli.Saidi@ARM.com assert(system->getMemoryMode() == Enums::atomic); 15110515SAli.Saidi@ARM.com 15210515SAli.Saidi@ARM.com changeState(SimObject::Running); 15310515SAli.Saidi@ARM.com if (thread->status() == ThreadContext::Active) { 15410515SAli.Saidi@ARM.com if (!tickEvent.scheduled()) 15510515SAli.Saidi@ARM.com schedule(tickEvent, nextCycle()); 15610515SAli.Saidi@ARM.com } 15710515SAli.Saidi@ARM.com system->totalNumInsts = 0; 15810515SAli.Saidi@ARM.com} 15910515SAli.Saidi@ARM.com 16010515SAli.Saidi@ARM.comvoid 16110515SAli.Saidi@ARM.comAtomicSimpleCPU::switchOut() 16210515SAli.Saidi@ARM.com{ 16310515SAli.Saidi@ARM.com assert(_status == Running || _status == Idle); 16410515SAli.Saidi@ARM.com _status = SwitchedOut; 16510515SAli.Saidi@ARM.com 16610515SAli.Saidi@ARM.com tickEvent.squash(); 16710515SAli.Saidi@ARM.com} 16810515SAli.Saidi@ARM.com 16910515SAli.Saidi@ARM.com 17010515SAli.Saidi@ARM.comvoid 17110515SAli.Saidi@ARM.comAtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 17210515SAli.Saidi@ARM.com{ 17310515SAli.Saidi@ARM.com BaseCPU::takeOverFrom(oldCPU); 17410515SAli.Saidi@ARM.com 17510515SAli.Saidi@ARM.com assert(!tickEvent.scheduled()); 17611570SCurtis.Dunham@arm.com 17711570SCurtis.Dunham@arm.com // if any of this CPU's ThreadContexts are active, mark the CPU as 17811570SCurtis.Dunham@arm.com // running and schedule its tick event. 17911570SCurtis.Dunham@arm.com ThreadID size = threadContexts.size(); 18010515SAli.Saidi@ARM.com for (ThreadID i = 0; i < size; ++i) { 18110515SAli.Saidi@ARM.com ThreadContext *tc = threadContexts[i]; 18210515SAli.Saidi@ARM.com if (tc->status() == ThreadContext::Active && _status != Running) { 18310515SAli.Saidi@ARM.com _status = Running; 18410515SAli.Saidi@ARM.com schedule(tickEvent, nextCycle()); 18510515SAli.Saidi@ARM.com break; 18610515SAli.Saidi@ARM.com } 18710515SAli.Saidi@ARM.com } 18810515SAli.Saidi@ARM.com if (_status != Running) { 18910515SAli.Saidi@ARM.com _status = Idle; 19010515SAli.Saidi@ARM.com } 19110515SAli.Saidi@ARM.com assert(threadContexts.size() == 1); 19210515SAli.Saidi@ARM.com ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT 19310515SAli.Saidi@ARM.com data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too 19410515SAli.Saidi@ARM.com data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too 19510515SAli.Saidi@ARM.com} 19610515SAli.Saidi@ARM.com 19710515SAli.Saidi@ARM.com 19810515SAli.Saidi@ARM.comvoid 19910515SAli.Saidi@ARM.comAtomicSimpleCPU::activateContext(ThreadID thread_num, int delay) 20010515SAli.Saidi@ARM.com{ 20110515SAli.Saidi@ARM.com DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay); 20210515SAli.Saidi@ARM.com 20310515SAli.Saidi@ARM.com assert(thread_num == 0); 20410515SAli.Saidi@ARM.com assert(thread); 20510515SAli.Saidi@ARM.com 20610515SAli.Saidi@ARM.com assert(_status == Idle); 20710515SAli.Saidi@ARM.com assert(!tickEvent.scheduled()); 20810515SAli.Saidi@ARM.com 20910515SAli.Saidi@ARM.com notIdleFraction++; 21010798Ssteve.reinhardt@amd.com numCycles += tickToCycles(thread->lastActivate - thread->lastSuspend); 21110515SAli.Saidi@ARM.com 21210515SAli.Saidi@ARM.com //Make sure ticks are still on multiples of cycles 21310515SAli.Saidi@ARM.com schedule(tickEvent, nextCycle(curTick() + ticks(delay))); 21410515SAli.Saidi@ARM.com _status = Running; 21510515SAli.Saidi@ARM.com} 21610515SAli.Saidi@ARM.com 21710515SAli.Saidi@ARM.com 21810515SAli.Saidi@ARM.comvoid 21911570SCurtis.Dunham@arm.comAtomicSimpleCPU::suspendContext(ThreadID thread_num) 22011570SCurtis.Dunham@arm.com{ 22111570SCurtis.Dunham@arm.com DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num); 22211570SCurtis.Dunham@arm.com 22311570SCurtis.Dunham@arm.com assert(thread_num == 0); 22411570SCurtis.Dunham@arm.com assert(thread); 22510515SAli.Saidi@ARM.com 22610515SAli.Saidi@ARM.com if (_status == Idle) 22711570SCurtis.Dunham@arm.com return; 22810515SAli.Saidi@ARM.com 22910515SAli.Saidi@ARM.com assert(_status == Running); 23011103Snilay@cs.wisc.edu 23110515SAli.Saidi@ARM.com // tick event may not be scheduled if this gets called from inside 23210515SAli.Saidi@ARM.com // an instruction's execution, e.g. "quiesce" 23310515SAli.Saidi@ARM.com if (tickEvent.scheduled()) 23410515SAli.Saidi@ARM.com deschedule(tickEvent); 23511239Sandreas.sandberg@arm.com 23611570SCurtis.Dunham@arm.com notIdleFraction--; 23710798Ssteve.reinhardt@amd.com _status = Idle; 23810515SAli.Saidi@ARM.com} 23910515SAli.Saidi@ARM.com 24010900Snilay@cs.wisc.edu 24110515SAli.Saidi@ARM.comFault 24210515SAli.Saidi@ARM.comAtomicSimpleCPU::readMem(Addr addr, uint8_t * data, 24311570SCurtis.Dunham@arm.com unsigned size, unsigned flags) 24411570SCurtis.Dunham@arm.com{ 24511570SCurtis.Dunham@arm.com // use the CPU's statically allocated read request and packet objects 24611570SCurtis.Dunham@arm.com Request *req = &data_read_req; 24710515SAli.Saidi@ARM.com 24810515SAli.Saidi@ARM.com if (traceData) { 24910515SAli.Saidi@ARM.com traceData->setAddr(addr); 25010515SAli.Saidi@ARM.com } 25110515SAli.Saidi@ARM.com 25210515SAli.Saidi@ARM.com //The block size of our peer. 25310515SAli.Saidi@ARM.com unsigned blockSize = dcachePort.peerBlockSize(); 25410515SAli.Saidi@ARM.com //The size of the data we're trying to read. 25510515SAli.Saidi@ARM.com int fullSize = size; 25611239Sandreas.sandberg@arm.com 25710515SAli.Saidi@ARM.com //The address of the second part of this access if it needs to be split 25810515SAli.Saidi@ARM.com //across a cache line boundary. 25910515SAli.Saidi@ARM.com Addr secondAddr = roundDown(addr + size - 1, blockSize); 26010515SAli.Saidi@ARM.com 26110515SAli.Saidi@ARM.com if (secondAddr > addr) 26210515SAli.Saidi@ARM.com size = secondAddr - addr; 26310515SAli.Saidi@ARM.com 26410515SAli.Saidi@ARM.com dcache_latency = 0; 26511570SCurtis.Dunham@arm.com 26610515SAli.Saidi@ARM.com while (1) { 26710515SAli.Saidi@ARM.com req->setVirt(0, addr, size, flags, dataMasterId(), thread->pcState().instAddr()); 26811570SCurtis.Dunham@arm.com 26911570SCurtis.Dunham@arm.com // translate to physical address 27011570SCurtis.Dunham@arm.com Fault fault = thread->dtb->translateAtomic(req, tc, BaseTLB::Read); 27111570SCurtis.Dunham@arm.com 27210515SAli.Saidi@ARM.com // Now do the access. 27310515SAli.Saidi@ARM.com if (fault == NoFault && !req->getFlags().isSet(Request::NO_ACCESS)) { 27410515SAli.Saidi@ARM.com Packet pkt = Packet(req, 27510515SAli.Saidi@ARM.com req->isLLSC() ? MemCmd::LoadLockedReq : 27610515SAli.Saidi@ARM.com MemCmd::ReadReq); 27710515SAli.Saidi@ARM.com pkt.dataStatic(data); 27810515SAli.Saidi@ARM.com 27910515SAli.Saidi@ARM.com if (req->isMmappedIpr()) 28010798Ssteve.reinhardt@amd.com dcache_latency += TheISA::handleIprRead(thread->getTC(), &pkt); 28110515SAli.Saidi@ARM.com else { 28210515SAli.Saidi@ARM.com if (fastmem && system->isMemAddr(pkt.getAddr())) 28310515SAli.Saidi@ARM.com system->getPhysMem().access(&pkt); 28410515SAli.Saidi@ARM.com else 28510515SAli.Saidi@ARM.com dcache_latency += dcachePort.sendAtomic(&pkt); 28610515SAli.Saidi@ARM.com } 28710515SAli.Saidi@ARM.com dcache_access = true; 28810515SAli.Saidi@ARM.com 28910515SAli.Saidi@ARM.com assert(!pkt.isError()); 29010515SAli.Saidi@ARM.com 29110515SAli.Saidi@ARM.com if (req->isLLSC()) { 29210515SAli.Saidi@ARM.com TheISA::handleLockedRead(thread, req); 29310515SAli.Saidi@ARM.com } 29411570SCurtis.Dunham@arm.com } 29510515SAli.Saidi@ARM.com 29610515SAli.Saidi@ARM.com //If there's a fault, return it 29710515SAli.Saidi@ARM.com if (fault != NoFault) { 29811570SCurtis.Dunham@arm.com if (req->isPrefetch()) { 29911570SCurtis.Dunham@arm.com return NoFault; 30011570SCurtis.Dunham@arm.com } else { 30111570SCurtis.Dunham@arm.com return fault; 30210515SAli.Saidi@ARM.com } 30310515SAli.Saidi@ARM.com } 30410515SAli.Saidi@ARM.com 30510515SAli.Saidi@ARM.com //If we don't need to access a second cache line, stop now. 30610515SAli.Saidi@ARM.com if (secondAddr <= addr) 30710515SAli.Saidi@ARM.com { 30810515SAli.Saidi@ARM.com if (req->isLocked() && fault == NoFault) { 30910515SAli.Saidi@ARM.com assert(!locked); 31010515SAli.Saidi@ARM.com locked = true; 31110515SAli.Saidi@ARM.com } 31210515SAli.Saidi@ARM.com return fault; 31310515SAli.Saidi@ARM.com } 31410515SAli.Saidi@ARM.com 31511570SCurtis.Dunham@arm.com /* 31610515SAli.Saidi@ARM.com * Set up for accessing the second cache line. 31710515SAli.Saidi@ARM.com */ 31810515SAli.Saidi@ARM.com 31911570SCurtis.Dunham@arm.com //Move the pointer we're reading into to the correct location. 32011570SCurtis.Dunham@arm.com data += size; 32111570SCurtis.Dunham@arm.com //Adjust the size to get the remaining bytes. 32211570SCurtis.Dunham@arm.com size = addr + fullSize - secondAddr; 32310515SAli.Saidi@ARM.com //And access the right address. 32410515SAli.Saidi@ARM.com addr = secondAddr; 32510515SAli.Saidi@ARM.com } 32610515SAli.Saidi@ARM.com} 32710515SAli.Saidi@ARM.com 32810515SAli.Saidi@ARM.com 32910515SAli.Saidi@ARM.comFault 33010515SAli.Saidi@ARM.comAtomicSimpleCPU::writeMem(uint8_t *data, unsigned size, 33110515SAli.Saidi@ARM.com Addr addr, unsigned flags, uint64_t *res) 33210515SAli.Saidi@ARM.com{ 33310515SAli.Saidi@ARM.com // use the CPU's statically allocated write request and packet objects 33410515SAli.Saidi@ARM.com Request *req = &data_write_req; 33510515SAli.Saidi@ARM.com 33610515SAli.Saidi@ARM.com if (traceData) { 33710515SAli.Saidi@ARM.com traceData->setAddr(addr); 33810515SAli.Saidi@ARM.com } 33910515SAli.Saidi@ARM.com 34010515SAli.Saidi@ARM.com //The block size of our peer. 34110515SAli.Saidi@ARM.com unsigned blockSize = dcachePort.peerBlockSize(); 34210515SAli.Saidi@ARM.com //The size of the data we're trying to read. 34310515SAli.Saidi@ARM.com int fullSize = size; 34410900Snilay@cs.wisc.edu 34510515SAli.Saidi@ARM.com //The address of the second part of this access if it needs to be split 34610515SAli.Saidi@ARM.com //across a cache line boundary. 34710515SAli.Saidi@ARM.com Addr secondAddr = roundDown(addr + size - 1, blockSize); 34810515SAli.Saidi@ARM.com 34910515SAli.Saidi@ARM.com if(secondAddr > addr) 35010515SAli.Saidi@ARM.com size = secondAddr - addr; 35110515SAli.Saidi@ARM.com 35210515SAli.Saidi@ARM.com dcache_latency = 0; 35310515SAli.Saidi@ARM.com 35410515SAli.Saidi@ARM.com while(1) { 35510515SAli.Saidi@ARM.com req->setVirt(0, addr, size, flags, dataMasterId(), thread->pcState().instAddr()); 35610515SAli.Saidi@ARM.com 35710515SAli.Saidi@ARM.com // translate to physical address 35810900Snilay@cs.wisc.edu Fault fault = thread->dtb->translateAtomic(req, tc, BaseTLB::Write); 35910515SAli.Saidi@ARM.com 36010515SAli.Saidi@ARM.com // Now do the access. 36110515SAli.Saidi@ARM.com if (fault == NoFault) { 36210515SAli.Saidi@ARM.com MemCmd cmd = MemCmd::WriteReq; // default 36310515SAli.Saidi@ARM.com bool do_access = true; // flag to suppress cache access 36410515SAli.Saidi@ARM.com 36510900Snilay@cs.wisc.edu if (req->isLLSC()) { 36610515SAli.Saidi@ARM.com cmd = MemCmd::StoreCondReq; 36710515SAli.Saidi@ARM.com do_access = TheISA::handleLockedWrite(thread, req); 36810515SAli.Saidi@ARM.com } else if (req->isSwap()) { 36910515SAli.Saidi@ARM.com cmd = MemCmd::SwapReq; 37010515SAli.Saidi@ARM.com if (req->isCondSwap()) { 37110515SAli.Saidi@ARM.com assert(res); 37210900Snilay@cs.wisc.edu req->setExtraData(*res); 37310515SAli.Saidi@ARM.com } 37410515SAli.Saidi@ARM.com } 37510515SAli.Saidi@ARM.com 37610515SAli.Saidi@ARM.com if (do_access && !req->getFlags().isSet(Request::NO_ACCESS)) { 37710515SAli.Saidi@ARM.com Packet pkt = Packet(req, cmd); 37810515SAli.Saidi@ARM.com pkt.dataStatic(data); 37910515SAli.Saidi@ARM.com 38010515SAli.Saidi@ARM.com if (req->isMmappedIpr()) { 38110515SAli.Saidi@ARM.com dcache_latency += 38210515SAli.Saidi@ARM.com TheISA::handleIprWrite(thread->getTC(), &pkt); 38310515SAli.Saidi@ARM.com } else { 38410515SAli.Saidi@ARM.com if (fastmem && system->isMemAddr(pkt.getAddr())) 38510515SAli.Saidi@ARM.com system->getPhysMem().access(&pkt); 38610900Snilay@cs.wisc.edu else 38710515SAli.Saidi@ARM.com dcache_latency += dcachePort.sendAtomic(&pkt); 38810515SAli.Saidi@ARM.com } 38910515SAli.Saidi@ARM.com dcache_access = true; 39010515SAli.Saidi@ARM.com assert(!pkt.isError()); 39110515SAli.Saidi@ARM.com 39210515SAli.Saidi@ARM.com if (req->isSwap()) { 39310515SAli.Saidi@ARM.com assert(res); 39410515SAli.Saidi@ARM.com memcpy(res, pkt.getPtr<uint8_t>(), fullSize); 39510515SAli.Saidi@ARM.com } 39610515SAli.Saidi@ARM.com } 39710515SAli.Saidi@ARM.com 39810515SAli.Saidi@ARM.com if (res && !req->isSwap()) { 39910515SAli.Saidi@ARM.com *res = req->getExtraData(); 40010900Snilay@cs.wisc.edu } 40110515SAli.Saidi@ARM.com } 40210515SAli.Saidi@ARM.com 40310515SAli.Saidi@ARM.com //If there's a fault or we don't need to access a second cache line, 40410515SAli.Saidi@ARM.com //stop now. 40510515SAli.Saidi@ARM.com if (fault != NoFault || secondAddr <= addr) 40610515SAli.Saidi@ARM.com { 40710515SAli.Saidi@ARM.com if (req->isLocked() && fault == NoFault) { 40810515SAli.Saidi@ARM.com assert(locked); 40910515SAli.Saidi@ARM.com locked = false; 41010515SAli.Saidi@ARM.com } 41110515SAli.Saidi@ARM.com if (fault != NoFault && req->isPrefetch()) { 41210515SAli.Saidi@ARM.com return NoFault; 41310515SAli.Saidi@ARM.com } else { 41410900Snilay@cs.wisc.edu return fault; 41510515SAli.Saidi@ARM.com } 41610515SAli.Saidi@ARM.com } 41710515SAli.Saidi@ARM.com 41810515SAli.Saidi@ARM.com /* 41910515SAli.Saidi@ARM.com * Set up for accessing the second cache line. 42010515SAli.Saidi@ARM.com */ 42110900Snilay@cs.wisc.edu 42210515SAli.Saidi@ARM.com //Move the pointer we're reading into to the correct location. 42310515SAli.Saidi@ARM.com data += size; 42410515SAli.Saidi@ARM.com //Adjust the size to get the remaining bytes. 42510515SAli.Saidi@ARM.com size = addr + fullSize - secondAddr; 42610515SAli.Saidi@ARM.com //And access the right address. 42710515SAli.Saidi@ARM.com addr = secondAddr; 42810900Snilay@cs.wisc.edu } 42910515SAli.Saidi@ARM.com} 43010515SAli.Saidi@ARM.com 43110515SAli.Saidi@ARM.com 43210515SAli.Saidi@ARM.comvoid 43310515SAli.Saidi@ARM.comAtomicSimpleCPU::tick() 43410515SAli.Saidi@ARM.com{ 43510900Snilay@cs.wisc.edu DPRINTF(SimpleCPU, "Tick\n"); 43610515SAli.Saidi@ARM.com 43710515SAli.Saidi@ARM.com Tick latency = 0; 43810515SAli.Saidi@ARM.com 43910515SAli.Saidi@ARM.com for (int i = 0; i < width || locked; ++i) { 44010515SAli.Saidi@ARM.com numCycles++; 44110515SAli.Saidi@ARM.com 44210900Snilay@cs.wisc.edu if (!curStaticInst || !curStaticInst->isDelayedCommit()) 44310515SAli.Saidi@ARM.com checkForInterrupts(); 44410515SAli.Saidi@ARM.com 44510515SAli.Saidi@ARM.com checkPcEventQueue(); 44610515SAli.Saidi@ARM.com // We must have just got suspended by a PC event 44710515SAli.Saidi@ARM.com if (_status == Idle) 44810515SAli.Saidi@ARM.com return; 44910900Snilay@cs.wisc.edu 45010515SAli.Saidi@ARM.com Fault fault = NoFault; 45110515SAli.Saidi@ARM.com 45210515SAli.Saidi@ARM.com TheISA::PCState pcState = thread->pcState(); 45310515SAli.Saidi@ARM.com 45410515SAli.Saidi@ARM.com bool needToFetch = !isRomMicroPC(pcState.microPC()) && 45510515SAli.Saidi@ARM.com !curMacroStaticInst; 45610900Snilay@cs.wisc.edu if (needToFetch) { 45710515SAli.Saidi@ARM.com setupFetchRequest(&ifetch_req); 45810515SAli.Saidi@ARM.com fault = thread->itb->translateAtomic(&ifetch_req, tc, 45910515SAli.Saidi@ARM.com BaseTLB::Execute); 46010515SAli.Saidi@ARM.com } 46110515SAli.Saidi@ARM.com 46210515SAli.Saidi@ARM.com if (fault == NoFault) { 46310900Snilay@cs.wisc.edu Tick icache_latency = 0; 46410515SAli.Saidi@ARM.com bool icache_access = false; 46510515SAli.Saidi@ARM.com dcache_access = false; // assume no dcache access 46610515SAli.Saidi@ARM.com 46710515SAli.Saidi@ARM.com if (needToFetch) { 46810515SAli.Saidi@ARM.com // This is commented out because the predecoder would act like 46910515SAli.Saidi@ARM.com // a tiny cache otherwise. It wouldn't be flushed when needed 47010900Snilay@cs.wisc.edu // like the I cache. It should be flushed, and when that works 47110515SAli.Saidi@ARM.com // this code should be uncommented. 47210515SAli.Saidi@ARM.com //Fetch more instruction memory if necessary 47310515SAli.Saidi@ARM.com //if(predecoder.needMoreBytes()) 47410515SAli.Saidi@ARM.com //{ 47510515SAli.Saidi@ARM.com icache_access = true; 47610515SAli.Saidi@ARM.com Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq); 47710900Snilay@cs.wisc.edu ifetch_pkt.dataStatic(&inst); 47810515SAli.Saidi@ARM.com 47910515SAli.Saidi@ARM.com if (fastmem && system->isMemAddr(ifetch_pkt.getAddr())) 48010515SAli.Saidi@ARM.com system->getPhysMem().access(&ifetch_pkt); 48110515SAli.Saidi@ARM.com else 48210515SAli.Saidi@ARM.com icache_latency = icachePort.sendAtomic(&ifetch_pkt); 48310515SAli.Saidi@ARM.com 48410900Snilay@cs.wisc.edu assert(!ifetch_pkt.isError()); 48510515SAli.Saidi@ARM.com 48610515SAli.Saidi@ARM.com // ifetch_req is initialized to read the instruction directly 48710515SAli.Saidi@ARM.com // into the CPU object's inst field. 48810515SAli.Saidi@ARM.com //} 48910515SAli.Saidi@ARM.com } 49010515SAli.Saidi@ARM.com 49110900Snilay@cs.wisc.edu preExecute(); 49210515SAli.Saidi@ARM.com 49310515SAli.Saidi@ARM.com if (curStaticInst) { 49410515SAli.Saidi@ARM.com fault = curStaticInst->execute(this, traceData); 49510515SAli.Saidi@ARM.com 49610515SAli.Saidi@ARM.com // keep an instruction count 49710515SAli.Saidi@ARM.com if (fault == NoFault) 49810900Snilay@cs.wisc.edu countInst(); 49910515SAli.Saidi@ARM.com else if (traceData && !DTRACE(ExecFaulting)) { 50010515SAli.Saidi@ARM.com delete traceData; 50110515SAli.Saidi@ARM.com traceData = NULL; 50210515SAli.Saidi@ARM.com } 50310515SAli.Saidi@ARM.com 50410515SAli.Saidi@ARM.com postExecute(); 50510900Snilay@cs.wisc.edu } 50610515SAli.Saidi@ARM.com 50710515SAli.Saidi@ARM.com // @todo remove me after debugging with legion done 50810515SAli.Saidi@ARM.com if (curStaticInst && (!curStaticInst->isMicroop() || 50910515SAli.Saidi@ARM.com curStaticInst->isFirstMicroop())) 51010515SAli.Saidi@ARM.com instCnt++; 51110515SAli.Saidi@ARM.com 51210900Snilay@cs.wisc.edu Tick stall_ticks = 0; 51310515SAli.Saidi@ARM.com if (simulate_inst_stalls && icache_access) 51410515SAli.Saidi@ARM.com stall_ticks += icache_latency; 51510515SAli.Saidi@ARM.com 51610515SAli.Saidi@ARM.com if (simulate_data_stalls && dcache_access) 51710515SAli.Saidi@ARM.com stall_ticks += dcache_latency; 51810515SAli.Saidi@ARM.com 51910900Snilay@cs.wisc.edu if (stall_ticks) { 52010515SAli.Saidi@ARM.com Tick stall_cycles = stall_ticks / ticks(1); 52110515SAli.Saidi@ARM.com Tick aligned_stall_ticks = ticks(stall_cycles); 52210515SAli.Saidi@ARM.com 52310515SAli.Saidi@ARM.com if (aligned_stall_ticks < stall_ticks) 52410515SAli.Saidi@ARM.com aligned_stall_ticks += 1; 52510515SAli.Saidi@ARM.com 52610900Snilay@cs.wisc.edu latency += aligned_stall_ticks; 52710515SAli.Saidi@ARM.com } 52810515SAli.Saidi@ARM.com 52910515SAli.Saidi@ARM.com } 53010515SAli.Saidi@ARM.com if(fault != NoFault || !stayAtPC) 53110515SAli.Saidi@ARM.com advancePC(fault); 53210515SAli.Saidi@ARM.com } 53310900Snilay@cs.wisc.edu 53410515SAli.Saidi@ARM.com // instruction takes at least one cycle 53510515SAli.Saidi@ARM.com if (latency < ticks(1)) 53610515SAli.Saidi@ARM.com latency = ticks(1); 53710515SAli.Saidi@ARM.com 53810515SAli.Saidi@ARM.com if (_status != Idle) 53910515SAli.Saidi@ARM.com schedule(tickEvent, curTick() + latency); 54010900Snilay@cs.wisc.edu} 54110515SAli.Saidi@ARM.com 54210515SAli.Saidi@ARM.com 54310515SAli.Saidi@ARM.comvoid 54410515SAli.Saidi@ARM.comAtomicSimpleCPU::printAddr(Addr a) 54510515SAli.Saidi@ARM.com{ 54610515SAli.Saidi@ARM.com dcachePort.printAddr(a); 54710900Snilay@cs.wisc.edu} 54810515SAli.Saidi@ARM.com 54910515SAli.Saidi@ARM.com 55010515SAli.Saidi@ARM.com//////////////////////////////////////////////////////////////////////// 55110515SAli.Saidi@ARM.com// 55210515SAli.Saidi@ARM.com// AtomicSimpleCPU Simulation Object 55310515SAli.Saidi@ARM.com// 55410900Snilay@cs.wisc.eduAtomicSimpleCPU * 55510515SAli.Saidi@ARM.comAtomicSimpleCPUParams::create() 55610515SAli.Saidi@ARM.com{ 55710515SAli.Saidi@ARM.com numThreads = 1; 55810515SAli.Saidi@ARM.com if (!FullSystem && workload.size() != 1) 55910515SAli.Saidi@ARM.com panic("only one workload allowed"); 56010515SAli.Saidi@ARM.com return new AtomicSimpleCPU(this); 56110900Snilay@cs.wisc.edu} 56210515SAli.Saidi@ARM.com