atomic.cc revision 4999
16313Sgblack@eecs.umich.edu/* 26313Sgblack@eecs.umich.edu * Copyright (c) 2002-2005 The Regents of The University of Michigan 36313Sgblack@eecs.umich.edu * All rights reserved. 46313Sgblack@eecs.umich.edu * 56313Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 66313Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 76313Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 86313Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 96313Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 106313Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 116313Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 126313Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 136313Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 146313Sgblack@eecs.umich.edu * this software without specific prior written permission. 156313Sgblack@eecs.umich.edu * 166313Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 176313Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 186313Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 196313Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 206313Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 216313Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 226313Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 236313Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 246313Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 256313Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 266313Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 276313Sgblack@eecs.umich.edu * 286313Sgblack@eecs.umich.edu * Authors: Steve Reinhardt 296313Sgblack@eecs.umich.edu */ 306313Sgblack@eecs.umich.edu 316313Sgblack@eecs.umich.edu#include "arch/locked_mem.hh" 326334Sgblack@eecs.umich.edu#include "arch/mmaped_ipr.hh" 336334Sgblack@eecs.umich.edu#include "arch/utility.hh" 346334Sgblack@eecs.umich.edu#include "base/bigint.hh" 356334Sgblack@eecs.umich.edu#include "cpu/exetrace.hh" 366334Sgblack@eecs.umich.edu#include "cpu/simple/atomic.hh" 376313Sgblack@eecs.umich.edu#include "mem/packet.hh" 386313Sgblack@eecs.umich.edu#include "mem/packet_access.hh" 396313Sgblack@eecs.umich.edu#include "params/AtomicSimpleCPU.hh" 406313Sgblack@eecs.umich.edu#include "sim/system.hh" 416313Sgblack@eecs.umich.edu 426334Sgblack@eecs.umich.eduusing namespace std; 436334Sgblack@eecs.umich.eduusing namespace TheISA; 446334Sgblack@eecs.umich.edu 456334Sgblack@eecs.umich.eduAtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c) 466334Sgblack@eecs.umich.edu : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) 476334Sgblack@eecs.umich.edu{ 486334Sgblack@eecs.umich.edu} 496334Sgblack@eecs.umich.edu 506334Sgblack@eecs.umich.edu 516334Sgblack@eecs.umich.eduvoid 526334Sgblack@eecs.umich.eduAtomicSimpleCPU::TickEvent::process() 536334Sgblack@eecs.umich.edu{ 546334Sgblack@eecs.umich.edu cpu->tick(); 556334Sgblack@eecs.umich.edu} 566334Sgblack@eecs.umich.edu 576334Sgblack@eecs.umich.educonst char * 586334Sgblack@eecs.umich.eduAtomicSimpleCPU::TickEvent::description() 596334Sgblack@eecs.umich.edu{ 606334Sgblack@eecs.umich.edu return "AtomicSimpleCPU tick"; 616334Sgblack@eecs.umich.edu} 626334Sgblack@eecs.umich.edu 636334Sgblack@eecs.umich.eduPort * 646334Sgblack@eecs.umich.eduAtomicSimpleCPU::getPort(const std::string &if_name, int idx) 656334Sgblack@eecs.umich.edu{ 666334Sgblack@eecs.umich.edu if (if_name == "dcache_port") 676334Sgblack@eecs.umich.edu return &dcachePort; 686334Sgblack@eecs.umich.edu else if (if_name == "icache_port") 696334Sgblack@eecs.umich.edu return &icachePort; 706334Sgblack@eecs.umich.edu else if (if_name == "physmem_port") { 716334Sgblack@eecs.umich.edu hasPhysMemPort = true; 726334Sgblack@eecs.umich.edu return &physmemPort; 736334Sgblack@eecs.umich.edu } 746334Sgblack@eecs.umich.edu else 756334Sgblack@eecs.umich.edu panic("No Such Port\n"); 766334Sgblack@eecs.umich.edu} 776334Sgblack@eecs.umich.edu 786334Sgblack@eecs.umich.eduvoid 796334Sgblack@eecs.umich.eduAtomicSimpleCPU::init() 806334Sgblack@eecs.umich.edu{ 816334Sgblack@eecs.umich.edu BaseCPU::init(); 826334Sgblack@eecs.umich.edu#if FULL_SYSTEM 836334Sgblack@eecs.umich.edu for (int i = 0; i < threadContexts.size(); ++i) { 846334Sgblack@eecs.umich.edu ThreadContext *tc = threadContexts[i]; 856334Sgblack@eecs.umich.edu 866334Sgblack@eecs.umich.edu // initialize CPU, including PC 876334Sgblack@eecs.umich.edu TheISA::initCPU(tc, tc->readCpuId()); 886334Sgblack@eecs.umich.edu } 896334Sgblack@eecs.umich.edu#endif 906334Sgblack@eecs.umich.edu if (hasPhysMemPort) { 916334Sgblack@eecs.umich.edu bool snoop = false; 926334Sgblack@eecs.umich.edu AddrRangeList pmAddrList; 936334Sgblack@eecs.umich.edu physmemPort.getPeerAddressRanges(pmAddrList, snoop); 946334Sgblack@eecs.umich.edu physMemAddr = *pmAddrList.begin(); 956334Sgblack@eecs.umich.edu } 966334Sgblack@eecs.umich.edu} 976334Sgblack@eecs.umich.edu 986334Sgblack@eecs.umich.edubool 996334Sgblack@eecs.umich.eduAtomicSimpleCPU::CpuPort::recvTiming(PacketPtr pkt) 1006313Sgblack@eecs.umich.edu{ 1016334Sgblack@eecs.umich.edu panic("AtomicSimpleCPU doesn't expect recvTiming callback!"); 1026313Sgblack@eecs.umich.edu return true; 1036334Sgblack@eecs.umich.edu} 1046334Sgblack@eecs.umich.edu 1056334Sgblack@eecs.umich.eduTick 1066334Sgblack@eecs.umich.eduAtomicSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt) 1076334Sgblack@eecs.umich.edu{ 1086334Sgblack@eecs.umich.edu //Snooping a coherence request, just return 1096334Sgblack@eecs.umich.edu return 0; 1106334Sgblack@eecs.umich.edu} 1116334Sgblack@eecs.umich.edu 1126334Sgblack@eecs.umich.eduvoid 1136334Sgblack@eecs.umich.eduAtomicSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt) 1146334Sgblack@eecs.umich.edu{ 1156334Sgblack@eecs.umich.edu //No internal storage to update, just return 1166334Sgblack@eecs.umich.edu return; 1176334Sgblack@eecs.umich.edu} 1186334Sgblack@eecs.umich.edu 1196334Sgblack@eecs.umich.eduvoid 1206334Sgblack@eecs.umich.eduAtomicSimpleCPU::CpuPort::recvStatusChange(Status status) 1216334Sgblack@eecs.umich.edu{ 1226334Sgblack@eecs.umich.edu if (status == RangeChange) { 1236334Sgblack@eecs.umich.edu if (!snoopRangeSent) { 1246334Sgblack@eecs.umich.edu snoopRangeSent = true; 1256334Sgblack@eecs.umich.edu sendStatusChange(Port::RangeChange); 1266334Sgblack@eecs.umich.edu } 1276334Sgblack@eecs.umich.edu return; 1286334Sgblack@eecs.umich.edu } 1296334Sgblack@eecs.umich.edu 1306334Sgblack@eecs.umich.edu panic("AtomicSimpleCPU doesn't expect recvStatusChange callback!"); 1316334Sgblack@eecs.umich.edu} 1326334Sgblack@eecs.umich.edu 1336334Sgblack@eecs.umich.eduvoid 1346334Sgblack@eecs.umich.eduAtomicSimpleCPU::CpuPort::recvRetry() 1356334Sgblack@eecs.umich.edu{ 1366334Sgblack@eecs.umich.edu panic("AtomicSimpleCPU doesn't expect recvRetry callback!"); 1376334Sgblack@eecs.umich.edu} 1386334Sgblack@eecs.umich.edu 1396334Sgblack@eecs.umich.eduvoid 1406334Sgblack@eecs.umich.eduAtomicSimpleCPU::DcachePort::setPeer(Port *port) 1416334Sgblack@eecs.umich.edu{ 1426334Sgblack@eecs.umich.edu Port::setPeer(port); 1436334Sgblack@eecs.umich.edu 1446334Sgblack@eecs.umich.edu#if FULL_SYSTEM 1456334Sgblack@eecs.umich.edu // Update the ThreadContext's memory ports (Functional/Virtual 1466334Sgblack@eecs.umich.edu // Ports) 1476334Sgblack@eecs.umich.edu cpu->tcBase()->connectMemPorts(); 1486334Sgblack@eecs.umich.edu#endif 1496334Sgblack@eecs.umich.edu} 1506334Sgblack@eecs.umich.edu 1516334Sgblack@eecs.umich.eduAtomicSimpleCPU::AtomicSimpleCPU(Params *p) 1526334Sgblack@eecs.umich.edu : BaseSimpleCPU(p), tickEvent(this), 1536334Sgblack@eecs.umich.edu width(p->width), simulate_stalls(p->simulate_stalls), 1546334Sgblack@eecs.umich.edu icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this), 1556334Sgblack@eecs.umich.edu physmemPort(name() + "-iport", this), hasPhysMemPort(false) 1566334Sgblack@eecs.umich.edu{ 1576334Sgblack@eecs.umich.edu _status = Idle; 1586334Sgblack@eecs.umich.edu 1596334Sgblack@eecs.umich.edu icachePort.snoopRangeSent = false; 1606334Sgblack@eecs.umich.edu dcachePort.snoopRangeSent = false; 1616334Sgblack@eecs.umich.edu 1626334Sgblack@eecs.umich.edu ifetch_req.setThreadContext(p->cpu_id, 0); // Add thread ID if we add MT 1636334Sgblack@eecs.umich.edu data_read_req.setThreadContext(p->cpu_id, 0); // Add thread ID here too 1646334Sgblack@eecs.umich.edu data_write_req.setThreadContext(p->cpu_id, 0); // Add thread ID here too 1656334Sgblack@eecs.umich.edu} 1666334Sgblack@eecs.umich.edu 1676334Sgblack@eecs.umich.edu 1686334Sgblack@eecs.umich.eduAtomicSimpleCPU::~AtomicSimpleCPU() 1696334Sgblack@eecs.umich.edu{ 1706334Sgblack@eecs.umich.edu} 1716334Sgblack@eecs.umich.edu 1726334Sgblack@eecs.umich.eduvoid 1736334Sgblack@eecs.umich.eduAtomicSimpleCPU::serialize(ostream &os) 1746334Sgblack@eecs.umich.edu{ 1756334Sgblack@eecs.umich.edu SimObject::State so_state = SimObject::getState(); 1766334Sgblack@eecs.umich.edu SERIALIZE_ENUM(so_state); 1776334Sgblack@eecs.umich.edu Status _status = status(); 1786334Sgblack@eecs.umich.edu SERIALIZE_ENUM(_status); 1796334Sgblack@eecs.umich.edu BaseSimpleCPU::serialize(os); 1806334Sgblack@eecs.umich.edu nameOut(os, csprintf("%s.tickEvent", name())); 1816334Sgblack@eecs.umich.edu tickEvent.serialize(os); 1826334Sgblack@eecs.umich.edu} 1836334Sgblack@eecs.umich.edu 1846334Sgblack@eecs.umich.eduvoid 1856334Sgblack@eecs.umich.eduAtomicSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 1866334Sgblack@eecs.umich.edu{ 1876334Sgblack@eecs.umich.edu SimObject::State so_state; 1886334Sgblack@eecs.umich.edu UNSERIALIZE_ENUM(so_state); 1896334Sgblack@eecs.umich.edu UNSERIALIZE_ENUM(_status); 1906334Sgblack@eecs.umich.edu BaseSimpleCPU::unserialize(cp, section); 1916334Sgblack@eecs.umich.edu tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); 1926334Sgblack@eecs.umich.edu} 1936334Sgblack@eecs.umich.edu 1946334Sgblack@eecs.umich.eduvoid 1956334Sgblack@eecs.umich.eduAtomicSimpleCPU::resume() 1966334Sgblack@eecs.umich.edu{ 1976334Sgblack@eecs.umich.edu DPRINTF(SimpleCPU, "Resume\n"); 1986334Sgblack@eecs.umich.edu if (_status != SwitchedOut && _status != Idle) { 1996334Sgblack@eecs.umich.edu assert(system->getMemoryMode() == Enums::atomic); 2006334Sgblack@eecs.umich.edu 2016334Sgblack@eecs.umich.edu changeState(SimObject::Running); 2026334Sgblack@eecs.umich.edu if (thread->status() == ThreadContext::Active) { 2036334Sgblack@eecs.umich.edu if (!tickEvent.scheduled()) { 2046334Sgblack@eecs.umich.edu tickEvent.schedule(nextCycle()); 2056334Sgblack@eecs.umich.edu } 2066334Sgblack@eecs.umich.edu } 2076334Sgblack@eecs.umich.edu } 2086334Sgblack@eecs.umich.edu} 2096334Sgblack@eecs.umich.edu 2106334Sgblack@eecs.umich.eduvoid 2116334Sgblack@eecs.umich.eduAtomicSimpleCPU::switchOut() 2126334Sgblack@eecs.umich.edu{ 2136334Sgblack@eecs.umich.edu assert(status() == Running || status() == Idle); 2146334Sgblack@eecs.umich.edu _status = SwitchedOut; 2156334Sgblack@eecs.umich.edu 2166334Sgblack@eecs.umich.edu tickEvent.squash(); 2176334Sgblack@eecs.umich.edu} 2186334Sgblack@eecs.umich.edu 2196334Sgblack@eecs.umich.edu 2206334Sgblack@eecs.umich.eduvoid 2216334Sgblack@eecs.umich.eduAtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 2226334Sgblack@eecs.umich.edu{ 2236334Sgblack@eecs.umich.edu BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort); 2246334Sgblack@eecs.umich.edu 2256334Sgblack@eecs.umich.edu assert(!tickEvent.scheduled()); 2266334Sgblack@eecs.umich.edu 2276334Sgblack@eecs.umich.edu // if any of this CPU's ThreadContexts are active, mark the CPU as 2286334Sgblack@eecs.umich.edu // running and schedule its tick event. 2296334Sgblack@eecs.umich.edu for (int i = 0; i < threadContexts.size(); ++i) { 2306334Sgblack@eecs.umich.edu ThreadContext *tc = threadContexts[i]; 2316334Sgblack@eecs.umich.edu if (tc->status() == ThreadContext::Active && _status != Running) { 2326334Sgblack@eecs.umich.edu _status = Running; 2336334Sgblack@eecs.umich.edu tickEvent.schedule(nextCycle()); 2346334Sgblack@eecs.umich.edu break; 2356334Sgblack@eecs.umich.edu } 2366334Sgblack@eecs.umich.edu } 2376334Sgblack@eecs.umich.edu if (_status != Running) { 2386334Sgblack@eecs.umich.edu _status = Idle; 2396334Sgblack@eecs.umich.edu } 2406334Sgblack@eecs.umich.edu} 2416334Sgblack@eecs.umich.edu 2426334Sgblack@eecs.umich.edu 2436334Sgblack@eecs.umich.eduvoid 2446334Sgblack@eecs.umich.eduAtomicSimpleCPU::activateContext(int thread_num, int delay) 2456334Sgblack@eecs.umich.edu{ 2466334Sgblack@eecs.umich.edu DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay); 2476334Sgblack@eecs.umich.edu 2486334Sgblack@eecs.umich.edu assert(thread_num == 0); 2496334Sgblack@eecs.umich.edu assert(thread); 2506334Sgblack@eecs.umich.edu 2516334Sgblack@eecs.umich.edu assert(_status == Idle); 2526334Sgblack@eecs.umich.edu assert(!tickEvent.scheduled()); 2536334Sgblack@eecs.umich.edu 2546334Sgblack@eecs.umich.edu notIdleFraction++; 2556334Sgblack@eecs.umich.edu 2566334Sgblack@eecs.umich.edu //Make sure ticks are still on multiples of cycles 2576334Sgblack@eecs.umich.edu tickEvent.schedule(nextCycle(curTick + cycles(delay))); 2586334Sgblack@eecs.umich.edu _status = Running; 2596334Sgblack@eecs.umich.edu} 2606334Sgblack@eecs.umich.edu 2616334Sgblack@eecs.umich.edu 2626334Sgblack@eecs.umich.eduvoid 2636334Sgblack@eecs.umich.eduAtomicSimpleCPU::suspendContext(int thread_num) 2646334Sgblack@eecs.umich.edu{ 2656334Sgblack@eecs.umich.edu DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num); 2666334Sgblack@eecs.umich.edu 2676334Sgblack@eecs.umich.edu assert(thread_num == 0); 2686334Sgblack@eecs.umich.edu assert(thread); 2696334Sgblack@eecs.umich.edu 2706334Sgblack@eecs.umich.edu assert(_status == Running); 2716334Sgblack@eecs.umich.edu 2726334Sgblack@eecs.umich.edu // tick event may not be scheduled if this gets called from inside 2736334Sgblack@eecs.umich.edu // an instruction's execution, e.g. "quiesce" 2746334Sgblack@eecs.umich.edu if (tickEvent.scheduled()) 2756334Sgblack@eecs.umich.edu tickEvent.deschedule(); 2766334Sgblack@eecs.umich.edu 2776334Sgblack@eecs.umich.edu notIdleFraction--; 2786334Sgblack@eecs.umich.edu _status = Idle; 2796334Sgblack@eecs.umich.edu} 2806334Sgblack@eecs.umich.edu 2816334Sgblack@eecs.umich.edu 2826334Sgblack@eecs.umich.edutemplate <class T> 2836334Sgblack@eecs.umich.eduFault 2846334Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, T &data, unsigned flags) 2856334Sgblack@eecs.umich.edu{ 2866334Sgblack@eecs.umich.edu // use the CPU's statically allocated read request and packet objects 2876334Sgblack@eecs.umich.edu Request *req = &data_read_req; 2886334Sgblack@eecs.umich.edu 2896334Sgblack@eecs.umich.edu if (traceData) { 2906334Sgblack@eecs.umich.edu traceData->setAddr(addr); 2916334Sgblack@eecs.umich.edu } 2926334Sgblack@eecs.umich.edu 2936334Sgblack@eecs.umich.edu //The block size of our peer. 2946334Sgblack@eecs.umich.edu int blockSize = dcachePort.peerBlockSize(); 2956334Sgblack@eecs.umich.edu //The size of the data we're trying to read. 2966334Sgblack@eecs.umich.edu int dataSize = sizeof(T); 2976334Sgblack@eecs.umich.edu 2986334Sgblack@eecs.umich.edu uint8_t * dataPtr = (uint8_t *)&data; 2996334Sgblack@eecs.umich.edu 3006334Sgblack@eecs.umich.edu //The address of the second part of this access if it needs to be split 3016334Sgblack@eecs.umich.edu //across a cache line boundary. 3026334Sgblack@eecs.umich.edu Addr secondAddr = roundDown(addr + dataSize - 1, blockSize); 3036334Sgblack@eecs.umich.edu 3046334Sgblack@eecs.umich.edu if(secondAddr > addr) 3056334Sgblack@eecs.umich.edu dataSize = secondAddr - addr; 3066334Sgblack@eecs.umich.edu 3076334Sgblack@eecs.umich.edu dcache_latency = 0; 3086334Sgblack@eecs.umich.edu 3096334Sgblack@eecs.umich.edu while(1) { 3106334Sgblack@eecs.umich.edu req->setVirt(0, addr, dataSize, flags, thread->readPC()); 3116334Sgblack@eecs.umich.edu 3126334Sgblack@eecs.umich.edu // translate to physical address 3136334Sgblack@eecs.umich.edu Fault fault = thread->translateDataReadReq(req); 3146334Sgblack@eecs.umich.edu 3156334Sgblack@eecs.umich.edu // Now do the access. 3166334Sgblack@eecs.umich.edu if (fault == NoFault) { 3176334Sgblack@eecs.umich.edu Packet pkt = Packet(req, 3186334Sgblack@eecs.umich.edu req->isLocked() ? MemCmd::LoadLockedReq : MemCmd::ReadReq, 3196334Sgblack@eecs.umich.edu Packet::Broadcast); 3206334Sgblack@eecs.umich.edu pkt.dataStatic(dataPtr); 3216334Sgblack@eecs.umich.edu 3226334Sgblack@eecs.umich.edu if (req->isMmapedIpr()) 3236334Sgblack@eecs.umich.edu dcache_latency += TheISA::handleIprRead(thread->getTC(), &pkt); 3246334Sgblack@eecs.umich.edu else { 3256334Sgblack@eecs.umich.edu if (hasPhysMemPort && pkt.getAddr() == physMemAddr) 3266334Sgblack@eecs.umich.edu dcache_latency += physmemPort.sendAtomic(&pkt); 3276334Sgblack@eecs.umich.edu else 3286334Sgblack@eecs.umich.edu dcache_latency += dcachePort.sendAtomic(&pkt); 3296334Sgblack@eecs.umich.edu } 3306334Sgblack@eecs.umich.edu dcache_access = true; 3316334Sgblack@eecs.umich.edu assert(!pkt.isError()); 3326334Sgblack@eecs.umich.edu 3336334Sgblack@eecs.umich.edu if (req->isLocked()) { 3346334Sgblack@eecs.umich.edu TheISA::handleLockedRead(thread, req); 3356334Sgblack@eecs.umich.edu } 3366334Sgblack@eecs.umich.edu } 3376334Sgblack@eecs.umich.edu 3386334Sgblack@eecs.umich.edu // This will need a new way to tell if it has a dcache attached. 3396334Sgblack@eecs.umich.edu if (req->isUncacheable()) 3406334Sgblack@eecs.umich.edu recordEvent("Uncached Read"); 3416334Sgblack@eecs.umich.edu 3426334Sgblack@eecs.umich.edu //If there's a fault, return it 3436334Sgblack@eecs.umich.edu if (fault != NoFault) 3446334Sgblack@eecs.umich.edu return fault; 3456334Sgblack@eecs.umich.edu //If we don't need to access a second cache line, stop now. 3466334Sgblack@eecs.umich.edu if (secondAddr <= addr) 3476334Sgblack@eecs.umich.edu { 3486334Sgblack@eecs.umich.edu data = gtoh(data); 3496334Sgblack@eecs.umich.edu return fault; 3506334Sgblack@eecs.umich.edu } 3516334Sgblack@eecs.umich.edu 3526334Sgblack@eecs.umich.edu /* 3536334Sgblack@eecs.umich.edu * Set up for accessing the second cache line. 3546334Sgblack@eecs.umich.edu */ 3556334Sgblack@eecs.umich.edu 3566334Sgblack@eecs.umich.edu //Move the pointer we're reading into to the correct location. 3576334Sgblack@eecs.umich.edu dataPtr += dataSize; 3586334Sgblack@eecs.umich.edu //Adjust the size to get the remaining bytes. 3596334Sgblack@eecs.umich.edu dataSize = addr + sizeof(T) - secondAddr; 3606334Sgblack@eecs.umich.edu //And access the right address. 3616334Sgblack@eecs.umich.edu addr = secondAddr; 3626334Sgblack@eecs.umich.edu } 3636334Sgblack@eecs.umich.edu} 3646334Sgblack@eecs.umich.edu 3656334Sgblack@eecs.umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS 3666334Sgblack@eecs.umich.edu 3676334Sgblack@eecs.umich.edutemplate 3686334Sgblack@eecs.umich.eduFault 3696334Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags); 3706334Sgblack@eecs.umich.edu 3716334Sgblack@eecs.umich.edutemplate 3726334Sgblack@eecs.umich.eduFault 3736334Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags); 3746334Sgblack@eecs.umich.edu 3756334Sgblack@eecs.umich.edutemplate 3766334Sgblack@eecs.umich.eduFault 3776334Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); 3786334Sgblack@eecs.umich.edu 3796334Sgblack@eecs.umich.edutemplate 3806334Sgblack@eecs.umich.eduFault 3816334Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); 3826334Sgblack@eecs.umich.edu 3836334Sgblack@eecs.umich.edutemplate 3846334Sgblack@eecs.umich.eduFault 3856334Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); 3866334Sgblack@eecs.umich.edu 3876334Sgblack@eecs.umich.edutemplate 3886334Sgblack@eecs.umich.eduFault 3896334Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); 3906334Sgblack@eecs.umich.edu 3916334Sgblack@eecs.umich.edu#endif //DOXYGEN_SHOULD_SKIP_THIS 3926334Sgblack@eecs.umich.edu 3936334Sgblack@eecs.umich.edutemplate<> 3946334Sgblack@eecs.umich.eduFault 3956334Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, double &data, unsigned flags) 3966334Sgblack@eecs.umich.edu{ 3976334Sgblack@eecs.umich.edu return read(addr, *(uint64_t*)&data, flags); 3986334Sgblack@eecs.umich.edu} 3996334Sgblack@eecs.umich.edu 4006334Sgblack@eecs.umich.edutemplate<> 4016334Sgblack@eecs.umich.eduFault 4026334Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, float &data, unsigned flags) 4036334Sgblack@eecs.umich.edu{ 4046334Sgblack@eecs.umich.edu return read(addr, *(uint32_t*)&data, flags); 4056334Sgblack@eecs.umich.edu} 4066334Sgblack@eecs.umich.edu 4076334Sgblack@eecs.umich.edu 4086334Sgblack@eecs.umich.edutemplate<> 4096334Sgblack@eecs.umich.eduFault 4106334Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) 4116334Sgblack@eecs.umich.edu{ 4126334Sgblack@eecs.umich.edu return read(addr, (uint32_t&)data, flags); 4136334Sgblack@eecs.umich.edu} 4146334Sgblack@eecs.umich.edu 4156334Sgblack@eecs.umich.edu 4166334Sgblack@eecs.umich.edutemplate <class T> 4176334Sgblack@eecs.umich.eduFault 4186334Sgblack@eecs.umich.eduAtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 4196334Sgblack@eecs.umich.edu{ 4206334Sgblack@eecs.umich.edu // use the CPU's statically allocated write request and packet objects 4216334Sgblack@eecs.umich.edu Request *req = &data_write_req; 4226334Sgblack@eecs.umich.edu 4236334Sgblack@eecs.umich.edu if (traceData) { 4246334Sgblack@eecs.umich.edu traceData->setAddr(addr); 4256334Sgblack@eecs.umich.edu } 4266334Sgblack@eecs.umich.edu 4276334Sgblack@eecs.umich.edu //The block size of our peer. 4286334Sgblack@eecs.umich.edu int blockSize = dcachePort.peerBlockSize(); 4296334Sgblack@eecs.umich.edu //The size of the data we're trying to read. 4306334Sgblack@eecs.umich.edu int dataSize = sizeof(T); 4316313Sgblack@eecs.umich.edu 4326313Sgblack@eecs.umich.edu uint8_t * dataPtr = (uint8_t *)&data; 4336313Sgblack@eecs.umich.edu 4346334Sgblack@eecs.umich.edu //The address of the second part of this access if it needs to be split 4356313Sgblack@eecs.umich.edu //across a cache line boundary. 4366334Sgblack@eecs.umich.edu Addr secondAddr = roundDown(addr + dataSize - 1, blockSize); 4376334Sgblack@eecs.umich.edu 4386334Sgblack@eecs.umich.edu if(secondAddr > addr) 4396334Sgblack@eecs.umich.edu dataSize = secondAddr - addr; 4406334Sgblack@eecs.umich.edu 4416334Sgblack@eecs.umich.edu dcache_latency = 0; 4426334Sgblack@eecs.umich.edu 4436313Sgblack@eecs.umich.edu while(1) { 4446313Sgblack@eecs.umich.edu req->setVirt(0, addr, dataSize, flags, thread->readPC()); 4456334Sgblack@eecs.umich.edu 4466334Sgblack@eecs.umich.edu // translate to physical address 4476334Sgblack@eecs.umich.edu Fault fault = thread->translateDataWriteReq(req); 4486313Sgblack@eecs.umich.edu 4496334Sgblack@eecs.umich.edu // Now do the access. 4506313Sgblack@eecs.umich.edu if (fault == NoFault) { 4516334Sgblack@eecs.umich.edu MemCmd cmd = MemCmd::WriteReq; // default 4526334Sgblack@eecs.umich.edu bool do_access = true; // flag to suppress cache access 4536334Sgblack@eecs.umich.edu 4546334Sgblack@eecs.umich.edu if (req->isLocked()) { 4556334Sgblack@eecs.umich.edu cmd = MemCmd::StoreCondReq; 4566334Sgblack@eecs.umich.edu do_access = TheISA::handleLockedWrite(thread, req); 4576334Sgblack@eecs.umich.edu } else if (req->isSwap()) { 4586334Sgblack@eecs.umich.edu cmd = MemCmd::SwapReq; 4596334Sgblack@eecs.umich.edu if (req->isCondSwap()) { 4606334Sgblack@eecs.umich.edu assert(res); 4616334Sgblack@eecs.umich.edu req->setExtraData(*res); 4626334Sgblack@eecs.umich.edu } 4636334Sgblack@eecs.umich.edu } 4646334Sgblack@eecs.umich.edu 4656313Sgblack@eecs.umich.edu if (do_access) { 4666313Sgblack@eecs.umich.edu Packet pkt = Packet(req, cmd, Packet::Broadcast); 4676313Sgblack@eecs.umich.edu pkt.dataStatic(dataPtr); 4686334Sgblack@eecs.umich.edu 4696313Sgblack@eecs.umich.edu if (req->isMmapedIpr()) { 4706334Sgblack@eecs.umich.edu dcache_latency += 4716334Sgblack@eecs.umich.edu TheISA::handleIprWrite(thread->getTC(), &pkt); 4726334Sgblack@eecs.umich.edu } else { 4736334Sgblack@eecs.umich.edu //XXX This needs to be outside of the loop in order to 4746334Sgblack@eecs.umich.edu //work properly for cache line boundary crossing 4756334Sgblack@eecs.umich.edu //accesses in transendian simulations. 4766334Sgblack@eecs.umich.edu data = htog(data); 4776334Sgblack@eecs.umich.edu if (hasPhysMemPort && pkt.getAddr() == physMemAddr) 4786334Sgblack@eecs.umich.edu dcache_latency += physmemPort.sendAtomic(&pkt); 4796313Sgblack@eecs.umich.edu else 4806313Sgblack@eecs.umich.edu dcache_latency += dcachePort.sendAtomic(&pkt); 4816313Sgblack@eecs.umich.edu } 4826334Sgblack@eecs.umich.edu dcache_access = true; 4836313Sgblack@eecs.umich.edu assert(!pkt.isError()); 4846334Sgblack@eecs.umich.edu 4856334Sgblack@eecs.umich.edu if (req->isSwap()) { 4866334Sgblack@eecs.umich.edu assert(res); 4876334Sgblack@eecs.umich.edu *res = pkt.get<T>(); 4886334Sgblack@eecs.umich.edu } 4896334Sgblack@eecs.umich.edu } 4906334Sgblack@eecs.umich.edu 4916334Sgblack@eecs.umich.edu if (res && !req->isSwap()) { 4926334Sgblack@eecs.umich.edu *res = req->getExtraData(); 4936334Sgblack@eecs.umich.edu } 4946334Sgblack@eecs.umich.edu } 4956334Sgblack@eecs.umich.edu 4966334Sgblack@eecs.umich.edu // This will need a new way to tell if it's hooked up to a cache or not. 4976334Sgblack@eecs.umich.edu if (req->isUncacheable()) 4986334Sgblack@eecs.umich.edu recordEvent("Uncached Write"); 4996334Sgblack@eecs.umich.edu 5006334Sgblack@eecs.umich.edu //If there's a fault or we don't need to access a second cache line, 5016334Sgblack@eecs.umich.edu //stop now. 5026334Sgblack@eecs.umich.edu if (fault != NoFault || secondAddr <= addr) 5036334Sgblack@eecs.umich.edu { 5046334Sgblack@eecs.umich.edu // If the write needs to have a fault on the access, consider 5056334Sgblack@eecs.umich.edu // calling changeStatus() and changing it to "bad addr write" 5066334Sgblack@eecs.umich.edu // or something. 5076334Sgblack@eecs.umich.edu return fault; 5086334Sgblack@eecs.umich.edu } 5096334Sgblack@eecs.umich.edu 5106334Sgblack@eecs.umich.edu /* 5116334Sgblack@eecs.umich.edu * Set up for accessing the second cache line. 5126334Sgblack@eecs.umich.edu */ 5136334Sgblack@eecs.umich.edu 5146334Sgblack@eecs.umich.edu //Move the pointer we're reading into to the correct location. 5156334Sgblack@eecs.umich.edu dataPtr += dataSize; 5166334Sgblack@eecs.umich.edu //Adjust the size to get the remaining bytes. 5176334Sgblack@eecs.umich.edu dataSize = addr + sizeof(T) - secondAddr; 5186334Sgblack@eecs.umich.edu //And access the right address. 5196334Sgblack@eecs.umich.edu addr = secondAddr; 5206334Sgblack@eecs.umich.edu } 5216334Sgblack@eecs.umich.edu} 5226334Sgblack@eecs.umich.edu 5236334Sgblack@eecs.umich.edu 5246334Sgblack@eecs.umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS 5256334Sgblack@eecs.umich.edu 5266334Sgblack@eecs.umich.edutemplate 5276334Sgblack@eecs.umich.eduFault 5286334Sgblack@eecs.umich.eduAtomicSimpleCPU::write(Twin32_t data, Addr addr, 5296334Sgblack@eecs.umich.edu unsigned flags, uint64_t *res); 5306334Sgblack@eecs.umich.edu 5316334Sgblack@eecs.umich.edutemplate 5326334Sgblack@eecs.umich.eduFault 5336334Sgblack@eecs.umich.eduAtomicSimpleCPU::write(Twin64_t data, Addr addr, 5346334Sgblack@eecs.umich.edu unsigned flags, uint64_t *res); 5356334Sgblack@eecs.umich.edu 5366334Sgblack@eecs.umich.edutemplate 5376334Sgblack@eecs.umich.eduFault 5386334Sgblack@eecs.umich.eduAtomicSimpleCPU::write(uint64_t data, Addr addr, 5396334Sgblack@eecs.umich.edu unsigned flags, uint64_t *res); 5406334Sgblack@eecs.umich.edu 5416334Sgblack@eecs.umich.edutemplate 5426313Sgblack@eecs.umich.eduFault 5436313Sgblack@eecs.umich.eduAtomicSimpleCPU::write(uint32_t data, Addr addr, 5446313Sgblack@eecs.umich.edu unsigned flags, uint64_t *res); 5456334Sgblack@eecs.umich.edu 5466313Sgblack@eecs.umich.edutemplate 5476334Sgblack@eecs.umich.eduFault 5486334Sgblack@eecs.umich.eduAtomicSimpleCPU::write(uint16_t data, Addr addr, 5496334Sgblack@eecs.umich.edu unsigned flags, uint64_t *res); 5506334Sgblack@eecs.umich.edu 5516334Sgblack@eecs.umich.edutemplate 5526334Sgblack@eecs.umich.eduFault 5536334Sgblack@eecs.umich.eduAtomicSimpleCPU::write(uint8_t data, Addr addr, 5546313Sgblack@eecs.umich.edu unsigned flags, uint64_t *res); 5556313Sgblack@eecs.umich.edu 5566313Sgblack@eecs.umich.edu#endif //DOXYGEN_SHOULD_SKIP_THIS 5576334Sgblack@eecs.umich.edu 5586313Sgblack@eecs.umich.edutemplate<> 5596334Sgblack@eecs.umich.eduFault 5606334Sgblack@eecs.umich.eduAtomicSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 5616334Sgblack@eecs.umich.edu{ 5626334Sgblack@eecs.umich.edu return write(*(uint64_t*)&data, addr, flags, res); 5636334Sgblack@eecs.umich.edu} 5646334Sgblack@eecs.umich.edu 5656334Sgblack@eecs.umich.edutemplate<> 5666334Sgblack@eecs.umich.eduFault 5676334Sgblack@eecs.umich.eduAtomicSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 5686334Sgblack@eecs.umich.edu{ 5696334Sgblack@eecs.umich.edu return write(*(uint32_t*)&data, addr, flags, res); 5706334Sgblack@eecs.umich.edu} 5716334Sgblack@eecs.umich.edu 5726334Sgblack@eecs.umich.edu 5736334Sgblack@eecs.umich.edutemplate<> 5746334Sgblack@eecs.umich.eduFault 5756334Sgblack@eecs.umich.eduAtomicSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 5766334Sgblack@eecs.umich.edu{ 5776334Sgblack@eecs.umich.edu return write((uint32_t)data, addr, flags, res); 5786334Sgblack@eecs.umich.edu} 5796334Sgblack@eecs.umich.edu 5806334Sgblack@eecs.umich.edu 5816334Sgblack@eecs.umich.eduvoid 5826334Sgblack@eecs.umich.eduAtomicSimpleCPU::tick() 5836334Sgblack@eecs.umich.edu{ 5846334Sgblack@eecs.umich.edu DPRINTF(SimpleCPU, "Tick\n"); 5856334Sgblack@eecs.umich.edu 5866334Sgblack@eecs.umich.edu Tick latency = cycles(1); // instruction takes one cycle by default 5876334Sgblack@eecs.umich.edu 5886334Sgblack@eecs.umich.edu for (int i = 0; i < width; ++i) { 5896334Sgblack@eecs.umich.edu numCycles++; 5906334Sgblack@eecs.umich.edu 5916334Sgblack@eecs.umich.edu if (!curStaticInst || !curStaticInst->isDelayedCommit()) 5926334Sgblack@eecs.umich.edu checkForInterrupts(); 5936334Sgblack@eecs.umich.edu 5946334Sgblack@eecs.umich.edu Fault fault = setupFetchRequest(&ifetch_req); 5956334Sgblack@eecs.umich.edu 5966334Sgblack@eecs.umich.edu if (fault == NoFault) { 5976334Sgblack@eecs.umich.edu Tick icache_latency = 0; 5986334Sgblack@eecs.umich.edu bool icache_access = false; 5996334Sgblack@eecs.umich.edu dcache_access = false; // assume no dcache access 6006334Sgblack@eecs.umich.edu 6016334Sgblack@eecs.umich.edu //Fetch more instruction memory if necessary 6026334Sgblack@eecs.umich.edu //if(predecoder.needMoreBytes()) 6036334Sgblack@eecs.umich.edu //{ 6046334Sgblack@eecs.umich.edu icache_access = true; 6056334Sgblack@eecs.umich.edu Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq, 6066334Sgblack@eecs.umich.edu Packet::Broadcast); 6076334Sgblack@eecs.umich.edu ifetch_pkt.dataStatic(&inst); 6086334Sgblack@eecs.umich.edu 6096334Sgblack@eecs.umich.edu if (hasPhysMemPort && ifetch_pkt.getAddr() == physMemAddr) 6106334Sgblack@eecs.umich.edu icache_latency = physmemPort.sendAtomic(&ifetch_pkt); 6116334Sgblack@eecs.umich.edu else 6126334Sgblack@eecs.umich.edu icache_latency = icachePort.sendAtomic(&ifetch_pkt); 6136334Sgblack@eecs.umich.edu 6146334Sgblack@eecs.umich.edu 6156334Sgblack@eecs.umich.edu // ifetch_req is initialized to read the instruction directly 6166334Sgblack@eecs.umich.edu // into the CPU object's inst field. 6176334Sgblack@eecs.umich.edu //} 6186334Sgblack@eecs.umich.edu 6196313Sgblack@eecs.umich.edu preExecute(); 6206313Sgblack@eecs.umich.edu 6216313Sgblack@eecs.umich.edu if(curStaticInst) 622 { 623 fault = curStaticInst->execute(this, traceData); 624 625 // keep an instruction count 626 if (fault == NoFault) 627 countInst(); 628 629 postExecute(); 630 } 631 632 // @todo remove me after debugging with legion done 633 if (curStaticInst && (!curStaticInst->isMicroop() || 634 curStaticInst->isFirstMicroop())) 635 instCnt++; 636 637 if (simulate_stalls) { 638 Tick icache_stall = 639 icache_access ? icache_latency - cycles(1) : 0; 640 Tick dcache_stall = 641 dcache_access ? dcache_latency - cycles(1) : 0; 642 Tick stall_cycles = (icache_stall + dcache_stall) / cycles(1); 643 if (cycles(stall_cycles) < (icache_stall + dcache_stall)) 644 latency += cycles(stall_cycles+1); 645 else 646 latency += cycles(stall_cycles); 647 } 648 649 } 650 if(fault != NoFault || !stayAtPC) 651 advancePC(fault); 652 } 653 654 if (_status != Idle) 655 tickEvent.schedule(curTick + latency); 656} 657 658 659//////////////////////////////////////////////////////////////////////// 660// 661// AtomicSimpleCPU Simulation Object 662// 663AtomicSimpleCPU * 664AtomicSimpleCPUParams::create() 665{ 666 AtomicSimpleCPU::Params *params = new AtomicSimpleCPU::Params(); 667 params->name = name; 668 params->numberOfThreads = 1; 669 params->max_insts_any_thread = max_insts_any_thread; 670 params->max_insts_all_threads = max_insts_all_threads; 671 params->max_loads_any_thread = max_loads_any_thread; 672 params->max_loads_all_threads = max_loads_all_threads; 673 params->progress_interval = progress_interval; 674 params->deferRegistration = defer_registration; 675 params->phase = phase; 676 params->clock = clock; 677 params->functionTrace = function_trace; 678 params->functionTraceStart = function_trace_start; 679 params->width = width; 680 params->simulate_stalls = simulate_stalls; 681 params->system = system; 682 params->cpu_id = cpu_id; 683 params->tracer = tracer; 684 685 params->itb = itb; 686 params->dtb = dtb; 687#if FULL_SYSTEM 688 params->profile = profile; 689 params->do_quiesce = do_quiesce; 690 params->do_checkpoint_insts = do_checkpoint_insts; 691 params->do_statistics_insts = do_statistics_insts; 692#else 693 if (workload.size() != 1) 694 panic("only one workload allowed"); 695 params->process = workload[0]; 696#endif 697 698 AtomicSimpleCPU *cpu = new AtomicSimpleCPU(params); 699 return cpu; 700} 701