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 &section)
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