atomic.cc revision 5714
17375Sgblack@eecs.umich.edu/*
27375Sgblack@eecs.umich.edu * Copyright (c) 2002-2005 The Regents of The University of Michigan
37375Sgblack@eecs.umich.edu * All rights reserved.
47375Sgblack@eecs.umich.edu *
57375Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
67375Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
77375Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
87375Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
97375Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
107375Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
117375Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
127375Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
137375Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
147375Sgblack@eecs.umich.edu * this software without specific prior written permission.
157375Sgblack@eecs.umich.edu *
167375Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
177375Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
187375Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
197375Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
207375Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
217375Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
227375Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
237375Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
247375Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
257375Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
267375Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
277375Sgblack@eecs.umich.edu *
287375Sgblack@eecs.umich.edu * Authors: Steve Reinhardt
297375Sgblack@eecs.umich.edu */
307375Sgblack@eecs.umich.edu
317375Sgblack@eecs.umich.edu#include "arch/locked_mem.hh"
327375Sgblack@eecs.umich.edu#include "arch/mmaped_ipr.hh"
337375Sgblack@eecs.umich.edu#include "arch/utility.hh"
347375Sgblack@eecs.umich.edu#include "base/bigint.hh"
357375Sgblack@eecs.umich.edu#include "cpu/exetrace.hh"
367375Sgblack@eecs.umich.edu#include "cpu/simple/atomic.hh"
377375Sgblack@eecs.umich.edu#include "mem/packet.hh"
387375Sgblack@eecs.umich.edu#include "mem/packet_access.hh"
397375Sgblack@eecs.umich.edu#include "params/AtomicSimpleCPU.hh"
407375Sgblack@eecs.umich.edu#include "sim/system.hh"
417375Sgblack@eecs.umich.edu
427375Sgblack@eecs.umich.eduusing namespace std;
437375Sgblack@eecs.umich.eduusing namespace TheISA;
447378Sgblack@eecs.umich.edu
457378Sgblack@eecs.umich.eduAtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c)
467382Sgblack@eecs.umich.edu    : Event(CPU_Tick_Pri), cpu(c)
477375Sgblack@eecs.umich.edu{
487384Sgblack@eecs.umich.edu}
497384Sgblack@eecs.umich.edu
507384Sgblack@eecs.umich.edu
517375Sgblack@eecs.umich.eduvoid
527375Sgblack@eecs.umich.eduAtomicSimpleCPU::TickEvent::process()
537375Sgblack@eecs.umich.edu{
547375Sgblack@eecs.umich.edu    cpu->tick();
557375Sgblack@eecs.umich.edu}
567375Sgblack@eecs.umich.edu
577375Sgblack@eecs.umich.educonst char *
587375Sgblack@eecs.umich.eduAtomicSimpleCPU::TickEvent::description() const
597375Sgblack@eecs.umich.edu{
607375Sgblack@eecs.umich.edu    return "AtomicSimpleCPU tick";
617375Sgblack@eecs.umich.edu}
627375Sgblack@eecs.umich.edu
637375Sgblack@eecs.umich.eduPort *
647375Sgblack@eecs.umich.eduAtomicSimpleCPU::getPort(const std::string &if_name, int idx)
657375Sgblack@eecs.umich.edu{
667375Sgblack@eecs.umich.edu    if (if_name == "dcache_port")
677375Sgblack@eecs.umich.edu        return &dcachePort;
687375Sgblack@eecs.umich.edu    else if (if_name == "icache_port")
697375Sgblack@eecs.umich.edu        return &icachePort;
707375Sgblack@eecs.umich.edu    else if (if_name == "physmem_port") {
717375Sgblack@eecs.umich.edu        hasPhysMemPort = true;
727375Sgblack@eecs.umich.edu        return &physmemPort;
737375Sgblack@eecs.umich.edu    }
747375Sgblack@eecs.umich.edu    else
757375Sgblack@eecs.umich.edu        panic("No Such Port\n");
767375Sgblack@eecs.umich.edu}
777376Sgblack@eecs.umich.edu
787376Sgblack@eecs.umich.eduvoid
797376Sgblack@eecs.umich.eduAtomicSimpleCPU::init()
807375Sgblack@eecs.umich.edu{
817375Sgblack@eecs.umich.edu    BaseCPU::init();
827378Sgblack@eecs.umich.edu#if FULL_SYSTEM
837378Sgblack@eecs.umich.edu    for (int i = 0; i < threadContexts.size(); ++i) {
847378Sgblack@eecs.umich.edu        ThreadContext *tc = threadContexts[i];
857378Sgblack@eecs.umich.edu
867378Sgblack@eecs.umich.edu        // initialize CPU, including PC
877378Sgblack@eecs.umich.edu        TheISA::initCPU(tc, tc->contextId());
887378Sgblack@eecs.umich.edu    }
897378Sgblack@eecs.umich.edu#endif
907378Sgblack@eecs.umich.edu    if (hasPhysMemPort) {
917378Sgblack@eecs.umich.edu        bool snoop = false;
927378Sgblack@eecs.umich.edu        AddrRangeList pmAddrList;
937378Sgblack@eecs.umich.edu        physmemPort.getPeerAddressRanges(pmAddrList, snoop);
947378Sgblack@eecs.umich.edu        physMemAddr = *pmAddrList.begin();
957378Sgblack@eecs.umich.edu    }
967378Sgblack@eecs.umich.edu    // Atomic doesn't do MT right now, so contextId == threadId
977378Sgblack@eecs.umich.edu    ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT
987378Sgblack@eecs.umich.edu    data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too
997378Sgblack@eecs.umich.edu    data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too
1007378Sgblack@eecs.umich.edu}
1017378Sgblack@eecs.umich.edu
1027378Sgblack@eecs.umich.edubool
1037378Sgblack@eecs.umich.eduAtomicSimpleCPU::CpuPort::recvTiming(PacketPtr pkt)
1047378Sgblack@eecs.umich.edu{
1057378Sgblack@eecs.umich.edu    panic("AtomicSimpleCPU doesn't expect recvTiming callback!");
1067378Sgblack@eecs.umich.edu    return true;
1077378Sgblack@eecs.umich.edu}
1087382Sgblack@eecs.umich.edu
1097382Sgblack@eecs.umich.eduTick
1107382Sgblack@eecs.umich.eduAtomicSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
1117382Sgblack@eecs.umich.edu{
1127382Sgblack@eecs.umich.edu    //Snooping a coherence request, just return
1137382Sgblack@eecs.umich.edu    return 0;
1147382Sgblack@eecs.umich.edu}
1157382Sgblack@eecs.umich.edu
1167382Sgblack@eecs.umich.eduvoid
1177382Sgblack@eecs.umich.eduAtomicSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
1187382Sgblack@eecs.umich.edu{
1197382Sgblack@eecs.umich.edu    //No internal storage to update, just return
1207382Sgblack@eecs.umich.edu    return;
1217382Sgblack@eecs.umich.edu}
1227382Sgblack@eecs.umich.edu
1237382Sgblack@eecs.umich.eduvoid
1247382Sgblack@eecs.umich.eduAtomicSimpleCPU::CpuPort::recvStatusChange(Status status)
1257382Sgblack@eecs.umich.edu{
1267382Sgblack@eecs.umich.edu    if (status == RangeChange) {
1277382Sgblack@eecs.umich.edu        if (!snoopRangeSent) {
1287384Sgblack@eecs.umich.edu            snoopRangeSent = true;
1297384Sgblack@eecs.umich.edu            sendStatusChange(Port::RangeChange);
1307384Sgblack@eecs.umich.edu        }
1317384Sgblack@eecs.umich.edu        return;
1327384Sgblack@eecs.umich.edu    }
1337384Sgblack@eecs.umich.edu
1347384Sgblack@eecs.umich.edu    panic("AtomicSimpleCPU doesn't expect recvStatusChange callback!");
1357384Sgblack@eecs.umich.edu}
1367384Sgblack@eecs.umich.edu
1377384Sgblack@eecs.umich.eduvoid
1387384Sgblack@eecs.umich.eduAtomicSimpleCPU::CpuPort::recvRetry()
1397384Sgblack@eecs.umich.edu{
1407384Sgblack@eecs.umich.edu    panic("AtomicSimpleCPU doesn't expect recvRetry callback!");
1417384Sgblack@eecs.umich.edu}
1427384Sgblack@eecs.umich.edu
1437384Sgblack@eecs.umich.eduvoid
1447384Sgblack@eecs.umich.eduAtomicSimpleCPU::DcachePort::setPeer(Port *port)
1457384Sgblack@eecs.umich.edu{
1467384Sgblack@eecs.umich.edu    Port::setPeer(port);
1477384Sgblack@eecs.umich.edu
1487384Sgblack@eecs.umich.edu#if FULL_SYSTEM
1497384Sgblack@eecs.umich.edu    // Update the ThreadContext's memory ports (Functional/Virtual
1507384Sgblack@eecs.umich.edu    // Ports)
1517384Sgblack@eecs.umich.edu    cpu->tcBase()->connectMemPorts(cpu->tcBase());
1527384Sgblack@eecs.umich.edu#endif
1537384Sgblack@eecs.umich.edu}
1547384Sgblack@eecs.umich.edu
1557384Sgblack@eecs.umich.eduAtomicSimpleCPU::AtomicSimpleCPU(AtomicSimpleCPUParams *p)
1567384Sgblack@eecs.umich.edu    : BaseSimpleCPU(p), tickEvent(this), width(p->width),
1577384Sgblack@eecs.umich.edu      simulate_data_stalls(p->simulate_data_stalls),
1587384Sgblack@eecs.umich.edu      simulate_inst_stalls(p->simulate_inst_stalls),
1597384Sgblack@eecs.umich.edu      icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this),
1607384Sgblack@eecs.umich.edu      physmemPort(name() + "-iport", this), hasPhysMemPort(false)
1617384Sgblack@eecs.umich.edu{
1627384Sgblack@eecs.umich.edu    _status = Idle;
1637384Sgblack@eecs.umich.edu
1647384Sgblack@eecs.umich.edu    icachePort.snoopRangeSent = false;
1657384Sgblack@eecs.umich.edu    dcachePort.snoopRangeSent = false;
1667384Sgblack@eecs.umich.edu
1677384Sgblack@eecs.umich.edu}
1687384Sgblack@eecs.umich.edu
1697384Sgblack@eecs.umich.edu
1707384Sgblack@eecs.umich.eduAtomicSimpleCPU::~AtomicSimpleCPU()
1717384Sgblack@eecs.umich.edu{
1727384Sgblack@eecs.umich.edu}
1737384Sgblack@eecs.umich.edu
1747384Sgblack@eecs.umich.eduvoid
1757384Sgblack@eecs.umich.eduAtomicSimpleCPU::serialize(ostream &os)
1767384Sgblack@eecs.umich.edu{
1777384Sgblack@eecs.umich.edu    SimObject::State so_state = SimObject::getState();
1787386Sgblack@eecs.umich.edu    SERIALIZE_ENUM(so_state);
1797386Sgblack@eecs.umich.edu    BaseSimpleCPU::serialize(os);
1807386Sgblack@eecs.umich.edu    nameOut(os, csprintf("%s.tickEvent", name()));
1817386Sgblack@eecs.umich.edu    tickEvent.serialize(os);
1827386Sgblack@eecs.umich.edu}
1837386Sgblack@eecs.umich.edu
1847386Sgblack@eecs.umich.eduvoid
1857386Sgblack@eecs.umich.eduAtomicSimpleCPU::unserialize(Checkpoint *cp, const string &section)
1867386Sgblack@eecs.umich.edu{
1877386Sgblack@eecs.umich.edu    SimObject::State so_state;
1887386Sgblack@eecs.umich.edu    UNSERIALIZE_ENUM(so_state);
1897386Sgblack@eecs.umich.edu    BaseSimpleCPU::unserialize(cp, section);
1907386Sgblack@eecs.umich.edu    tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
1917386Sgblack@eecs.umich.edu}
1927386Sgblack@eecs.umich.edu
1937386Sgblack@eecs.umich.eduvoid
1947386Sgblack@eecs.umich.eduAtomicSimpleCPU::resume()
1957386Sgblack@eecs.umich.edu{
1967386Sgblack@eecs.umich.edu    if (_status == Idle || _status == SwitchedOut)
1977386Sgblack@eecs.umich.edu        return;
1987386Sgblack@eecs.umich.edu
1997386Sgblack@eecs.umich.edu    DPRINTF(SimpleCPU, "Resume\n");
2007386Sgblack@eecs.umich.edu    assert(system->getMemoryMode() == Enums::atomic);
2017386Sgblack@eecs.umich.edu
2027385Sgblack@eecs.umich.edu    changeState(SimObject::Running);
2037384Sgblack@eecs.umich.edu    if (thread->status() == ThreadContext::Active) {
2047385Sgblack@eecs.umich.edu        if (!tickEvent.scheduled())
2057385Sgblack@eecs.umich.edu            schedule(tickEvent, nextCycle());
2067385Sgblack@eecs.umich.edu    }
2077384Sgblack@eecs.umich.edu}
2087384Sgblack@eecs.umich.edu
2097384Sgblack@eecs.umich.eduvoid
2107384Sgblack@eecs.umich.eduAtomicSimpleCPU::switchOut()
2117384Sgblack@eecs.umich.edu{
2127384Sgblack@eecs.umich.edu    assert(_status == Running || _status == Idle);
2137384Sgblack@eecs.umich.edu    _status = SwitchedOut;
2147384Sgblack@eecs.umich.edu
2157384Sgblack@eecs.umich.edu    tickEvent.squash();
2167384Sgblack@eecs.umich.edu}
2177384Sgblack@eecs.umich.edu
2187384Sgblack@eecs.umich.edu
2197384Sgblack@eecs.umich.eduvoid
2207384Sgblack@eecs.umich.eduAtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
2217384Sgblack@eecs.umich.edu{
2227384Sgblack@eecs.umich.edu    BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
2237384Sgblack@eecs.umich.edu
2247385Sgblack@eecs.umich.edu    assert(!tickEvent.scheduled());
2257385Sgblack@eecs.umich.edu
2267385Sgblack@eecs.umich.edu    // if any of this CPU's ThreadContexts are active, mark the CPU as
2277385Sgblack@eecs.umich.edu    // running and schedule its tick event.
2287385Sgblack@eecs.umich.edu    for (int i = 0; i < threadContexts.size(); ++i) {
2297384Sgblack@eecs.umich.edu        ThreadContext *tc = threadContexts[i];
2307384Sgblack@eecs.umich.edu        if (tc->status() == ThreadContext::Active && _status != Running) {
2317384Sgblack@eecs.umich.edu            _status = Running;
2327384Sgblack@eecs.umich.edu            schedule(tickEvent, nextCycle());
2337386Sgblack@eecs.umich.edu            break;
2347386Sgblack@eecs.umich.edu        }
2357386Sgblack@eecs.umich.edu    }
2367386Sgblack@eecs.umich.edu    if (_status != Running) {
2377386Sgblack@eecs.umich.edu        _status = Idle;
2387386Sgblack@eecs.umich.edu    }
2397386Sgblack@eecs.umich.edu    assert(threadContexts.size() == 1);
2407386Sgblack@eecs.umich.edu    ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT
2417386Sgblack@eecs.umich.edu    data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too
2427386Sgblack@eecs.umich.edu    data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too
2437386Sgblack@eecs.umich.edu}
2447386Sgblack@eecs.umich.edu
2457386Sgblack@eecs.umich.edu
2467386Sgblack@eecs.umich.eduvoid
2477386Sgblack@eecs.umich.eduAtomicSimpleCPU::activateContext(int thread_num, int delay)
2487386Sgblack@eecs.umich.edu{
2497386Sgblack@eecs.umich.edu    DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay);
2507386Sgblack@eecs.umich.edu
2517386Sgblack@eecs.umich.edu    assert(thread_num == 0);
2527386Sgblack@eecs.umich.edu    assert(thread);
2537386Sgblack@eecs.umich.edu
2547386Sgblack@eecs.umich.edu    assert(_status == Idle);
2557386Sgblack@eecs.umich.edu    assert(!tickEvent.scheduled());
2567386Sgblack@eecs.umich.edu
2577386Sgblack@eecs.umich.edu    notIdleFraction++;
2587386Sgblack@eecs.umich.edu    numCycles += tickToCycles(thread->lastActivate - thread->lastSuspend);
2597386Sgblack@eecs.umich.edu
2607386Sgblack@eecs.umich.edu    //Make sure ticks are still on multiples of cycles
2617386Sgblack@eecs.umich.edu    schedule(tickEvent, nextCycle(curTick + ticks(delay)));
2627386Sgblack@eecs.umich.edu    _status = Running;
2637386Sgblack@eecs.umich.edu}
2647386Sgblack@eecs.umich.edu
2657386Sgblack@eecs.umich.edu
2667386Sgblack@eecs.umich.eduvoid
2677386Sgblack@eecs.umich.eduAtomicSimpleCPU::suspendContext(int thread_num)
2687386Sgblack@eecs.umich.edu{
2697386Sgblack@eecs.umich.edu    DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
2707386Sgblack@eecs.umich.edu
2717386Sgblack@eecs.umich.edu    assert(thread_num == 0);
2727386Sgblack@eecs.umich.edu    assert(thread);
2737386Sgblack@eecs.umich.edu
2747386Sgblack@eecs.umich.edu    assert(_status == Running);
2757386Sgblack@eecs.umich.edu
2767386Sgblack@eecs.umich.edu    // tick event may not be scheduled if this gets called from inside
2777386Sgblack@eecs.umich.edu    // an instruction's execution, e.g. "quiesce"
2787386Sgblack@eecs.umich.edu    if (tickEvent.scheduled())
2797386Sgblack@eecs.umich.edu        deschedule(tickEvent);
2807386Sgblack@eecs.umich.edu
2817386Sgblack@eecs.umich.edu    notIdleFraction--;
2827386Sgblack@eecs.umich.edu    _status = Idle;
2837386Sgblack@eecs.umich.edu}
2847386Sgblack@eecs.umich.edu
2857386Sgblack@eecs.umich.edu
2867386Sgblack@eecs.umich.edutemplate <class T>
2877386Sgblack@eecs.umich.eduFault
2887386Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
2897386Sgblack@eecs.umich.edu{
2907386Sgblack@eecs.umich.edu    // use the CPU's statically allocated read request and packet objects
2917386Sgblack@eecs.umich.edu    Request *req = &data_read_req;
2927386Sgblack@eecs.umich.edu
2937386Sgblack@eecs.umich.edu    if (traceData) {
2947386Sgblack@eecs.umich.edu        traceData->setAddr(addr);
2957386Sgblack@eecs.umich.edu    }
2967386Sgblack@eecs.umich.edu
2977386Sgblack@eecs.umich.edu    //The block size of our peer.
2987386Sgblack@eecs.umich.edu    int blockSize = dcachePort.peerBlockSize();
2997386Sgblack@eecs.umich.edu    //The size of the data we're trying to read.
3007386Sgblack@eecs.umich.edu    int dataSize = sizeof(T);
3017386Sgblack@eecs.umich.edu
3027386Sgblack@eecs.umich.edu    uint8_t * dataPtr = (uint8_t *)&data;
3037386Sgblack@eecs.umich.edu
3047386Sgblack@eecs.umich.edu    //The address of the second part of this access if it needs to be split
3057386Sgblack@eecs.umich.edu    //across a cache line boundary.
3067386Sgblack@eecs.umich.edu    Addr secondAddr = roundDown(addr + dataSize - 1, blockSize);
3077386Sgblack@eecs.umich.edu
3087386Sgblack@eecs.umich.edu    if(secondAddr > addr)
3097386Sgblack@eecs.umich.edu        dataSize = secondAddr - addr;
3107386Sgblack@eecs.umich.edu
3117379Sgblack@eecs.umich.edu    dcache_latency = 0;
3127388Sgblack@eecs.umich.edu
3137388Sgblack@eecs.umich.edu    while(1) {
3147379Sgblack@eecs.umich.edu        req->setVirt(0, addr, dataSize, flags, thread->readPC());
3157388Sgblack@eecs.umich.edu
3167388Sgblack@eecs.umich.edu        // translate to physical address
3177379Sgblack@eecs.umich.edu        Fault fault = thread->translateDataReadReq(req);
3187379Sgblack@eecs.umich.edu
3197388Sgblack@eecs.umich.edu        // Now do the access.
3207388Sgblack@eecs.umich.edu        if (fault == NoFault) {
3217388Sgblack@eecs.umich.edu            Packet pkt = Packet(req,
3227388Sgblack@eecs.umich.edu                    req->isLocked() ? MemCmd::LoadLockedReq : MemCmd::ReadReq,
3237379Sgblack@eecs.umich.edu                    Packet::Broadcast);
3247382Sgblack@eecs.umich.edu            pkt.dataStatic(dataPtr);
3257382Sgblack@eecs.umich.edu
3267382Sgblack@eecs.umich.edu            if (req->isMmapedIpr())
3277382Sgblack@eecs.umich.edu                dcache_latency += TheISA::handleIprRead(thread->getTC(), &pkt);
3287382Sgblack@eecs.umich.edu            else {
3297382Sgblack@eecs.umich.edu                if (hasPhysMemPort && pkt.getAddr() == physMemAddr)
3307382Sgblack@eecs.umich.edu                    dcache_latency += physmemPort.sendAtomic(&pkt);
3317382Sgblack@eecs.umich.edu                else
3327382Sgblack@eecs.umich.edu                    dcache_latency += dcachePort.sendAtomic(&pkt);
3337382Sgblack@eecs.umich.edu            }
3347382Sgblack@eecs.umich.edu            dcache_access = true;
3357382Sgblack@eecs.umich.edu
3367382Sgblack@eecs.umich.edu            assert(!pkt.isError());
3377379Sgblack@eecs.umich.edu
3387379Sgblack@eecs.umich.edu            if (req->isLocked()) {
3397381Sgblack@eecs.umich.edu                TheISA::handleLockedRead(thread, req);
3407379Sgblack@eecs.umich.edu            }
3417382Sgblack@eecs.umich.edu        }
3427379Sgblack@eecs.umich.edu
3437379Sgblack@eecs.umich.edu        // This will need a new way to tell if it has a dcache attached.
3447381Sgblack@eecs.umich.edu        if (req->isUncacheable())
3457379Sgblack@eecs.umich.edu            recordEvent("Uncached Read");
3467382Sgblack@eecs.umich.edu
3477379Sgblack@eecs.umich.edu        //If there's a fault, return it
3487379Sgblack@eecs.umich.edu        if (fault != NoFault)
3497379Sgblack@eecs.umich.edu            return fault;
3507379Sgblack@eecs.umich.edu        //If we don't need to access a second cache line, stop now.
3517381Sgblack@eecs.umich.edu        if (secondAddr <= addr)
3527379Sgblack@eecs.umich.edu        {
3537382Sgblack@eecs.umich.edu            data = gtoh(data);
3547379Sgblack@eecs.umich.edu            if (traceData) {
3557379Sgblack@eecs.umich.edu                traceData->setData(data);
3567381Sgblack@eecs.umich.edu            }
3577379Sgblack@eecs.umich.edu            return fault;
3587382Sgblack@eecs.umich.edu        }
3597379Sgblack@eecs.umich.edu
3607379Sgblack@eecs.umich.edu        /*
3617379Sgblack@eecs.umich.edu         * Set up for accessing the second cache line.
3627379Sgblack@eecs.umich.edu         */
3637379Sgblack@eecs.umich.edu
3647379Sgblack@eecs.umich.edu        //Move the pointer we're reading into to the correct location.
3657381Sgblack@eecs.umich.edu        dataPtr += dataSize;
3667379Sgblack@eecs.umich.edu        //Adjust the size to get the remaining bytes.
3677382Sgblack@eecs.umich.edu        dataSize = addr + sizeof(T) - secondAddr;
3687379Sgblack@eecs.umich.edu        //And access the right address.
3697379Sgblack@eecs.umich.edu        addr = secondAddr;
3707381Sgblack@eecs.umich.edu    }
3717379Sgblack@eecs.umich.edu}
3727382Sgblack@eecs.umich.edu
3737379Sgblack@eecs.umich.eduFault
3747379Sgblack@eecs.umich.eduAtomicSimpleCPU::translateDataReadAddr(Addr vaddr, Addr & paddr,
3757379Sgblack@eecs.umich.edu        int size, unsigned flags)
3767379Sgblack@eecs.umich.edu{
3777381Sgblack@eecs.umich.edu    // use the CPU's statically allocated read request and packet objects
3787379Sgblack@eecs.umich.edu    Request *req = &data_read_req;
3797382Sgblack@eecs.umich.edu
3807379Sgblack@eecs.umich.edu    if (traceData) {
3817379Sgblack@eecs.umich.edu        traceData->setAddr(vaddr);
3827381Sgblack@eecs.umich.edu    }
3837379Sgblack@eecs.umich.edu
3847382Sgblack@eecs.umich.edu    //The block size of our peer.
3857379Sgblack@eecs.umich.edu    int blockSize = dcachePort.peerBlockSize();
3867379Sgblack@eecs.umich.edu    //The size of the data we're trying to read.
3877379Sgblack@eecs.umich.edu    int dataSize = size;
3887379Sgblack@eecs.umich.edu
3897379Sgblack@eecs.umich.edu    bool firstTimeThrough = true;
3907379Sgblack@eecs.umich.edu
3917379Sgblack@eecs.umich.edu    //The address of the second part of this access if it needs to be split
3927379Sgblack@eecs.umich.edu    //across a cache line boundary.
3937386Sgblack@eecs.umich.edu    Addr secondAddr = roundDown(vaddr + dataSize - 1, blockSize);
3947379Sgblack@eecs.umich.edu
3957379Sgblack@eecs.umich.edu    if(secondAddr > vaddr)
3967379Sgblack@eecs.umich.edu        dataSize = secondAddr - vaddr;
3977379Sgblack@eecs.umich.edu
3987382Sgblack@eecs.umich.edu    while(1) {
3997382Sgblack@eecs.umich.edu        req->setVirt(0, vaddr, dataSize, flags, thread->readPC());
4007382Sgblack@eecs.umich.edu
4017382Sgblack@eecs.umich.edu        // translate to physical address
4027386Sgblack@eecs.umich.edu        Fault fault = thread->translateDataReadReq(req);
4037379Sgblack@eecs.umich.edu
4047379Sgblack@eecs.umich.edu        //If there's a fault, return it
4057379Sgblack@eecs.umich.edu        if (fault != NoFault)
4067386Sgblack@eecs.umich.edu            return fault;
4077379Sgblack@eecs.umich.edu
4087379Sgblack@eecs.umich.edu        if (firstTimeThrough) {
4097379Sgblack@eecs.umich.edu            paddr = req->getPaddr();
4107379Sgblack@eecs.umich.edu            firstTimeThrough = false;
4117382Sgblack@eecs.umich.edu        }
4127382Sgblack@eecs.umich.edu
4137382Sgblack@eecs.umich.edu        //If we don't need to access a second cache line, stop now.
4147382Sgblack@eecs.umich.edu        if (secondAddr <= vaddr)
4157386Sgblack@eecs.umich.edu            return fault;
4167379Sgblack@eecs.umich.edu
4177379Sgblack@eecs.umich.edu        /*
4187379Sgblack@eecs.umich.edu         * Set up for accessing the second cache line.
4197388Sgblack@eecs.umich.edu         */
4207388Sgblack@eecs.umich.edu
4217379Sgblack@eecs.umich.edu        //Adjust the size to get the remaining bytes.
4227388Sgblack@eecs.umich.edu        dataSize = vaddr + size - secondAddr;
4237382Sgblack@eecs.umich.edu        //And access the right address.
4247379Sgblack@eecs.umich.edu        vaddr = secondAddr;
4257379Sgblack@eecs.umich.edu    }
4267388Sgblack@eecs.umich.edu}
4277388Sgblack@eecs.umich.edu
4287388Sgblack@eecs.umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS
4297388Sgblack@eecs.umich.edu
4307379Sgblack@eecs.umich.edutemplate
4317382Sgblack@eecs.umich.eduFault
4327382Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags);
4337382Sgblack@eecs.umich.edu
4347382Sgblack@eecs.umich.edutemplate
4357382Sgblack@eecs.umich.eduFault
4367382Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags);
4377382Sgblack@eecs.umich.edu
4387382Sgblack@eecs.umich.edutemplate
4397382Sgblack@eecs.umich.eduFault
4407382Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
4417382Sgblack@eecs.umich.edu
4427382Sgblack@eecs.umich.edutemplate
4437379Sgblack@eecs.umich.eduFault
4447379Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
4457379Sgblack@eecs.umich.edu
4467379Sgblack@eecs.umich.edutemplate
4477382Sgblack@eecs.umich.eduFault
4487379Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
4497379Sgblack@eecs.umich.edu
4507379Sgblack@eecs.umich.edutemplate
4517379Sgblack@eecs.umich.eduFault
4527382Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
4537379Sgblack@eecs.umich.edu
4547379Sgblack@eecs.umich.edu#endif //DOXYGEN_SHOULD_SKIP_THIS
4557379Sgblack@eecs.umich.edu
4567379Sgblack@eecs.umich.edutemplate<>
4577379Sgblack@eecs.umich.eduFault
4587379Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, double &data, unsigned flags)
4597382Sgblack@eecs.umich.edu{
4607379Sgblack@eecs.umich.edu    return read(addr, *(uint64_t*)&data, flags);
4617379Sgblack@eecs.umich.edu}
4627379Sgblack@eecs.umich.edu
4637379Sgblack@eecs.umich.edutemplate<>
4647382Sgblack@eecs.umich.eduFault
4657379Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, float &data, unsigned flags)
4667379Sgblack@eecs.umich.edu{
4677379Sgblack@eecs.umich.edu    return read(addr, *(uint32_t*)&data, flags);
4687379Sgblack@eecs.umich.edu}
4697379Sgblack@eecs.umich.edu
4707379Sgblack@eecs.umich.edu
4717379Sgblack@eecs.umich.edutemplate<>
4727379Sgblack@eecs.umich.eduFault
4737382Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
4747379Sgblack@eecs.umich.edu{
4757379Sgblack@eecs.umich.edu    return read(addr, (uint32_t&)data, flags);
4767379Sgblack@eecs.umich.edu}
4777379Sgblack@eecs.umich.edu
4787382Sgblack@eecs.umich.edu
4797379Sgblack@eecs.umich.edutemplate <class T>
4807379Sgblack@eecs.umich.eduFault
4817379Sgblack@eecs.umich.eduAtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
4827379Sgblack@eecs.umich.edu{
4837379Sgblack@eecs.umich.edu    // use the CPU's statically allocated write request and packet objects
4847379Sgblack@eecs.umich.edu    Request *req = &data_write_req;
4857382Sgblack@eecs.umich.edu
4867379Sgblack@eecs.umich.edu    if (traceData) {
4877379Sgblack@eecs.umich.edu        traceData->setAddr(addr);
4887379Sgblack@eecs.umich.edu    }
4897379Sgblack@eecs.umich.edu
4907382Sgblack@eecs.umich.edu    //The block size of our peer.
4917379Sgblack@eecs.umich.edu    int blockSize = dcachePort.peerBlockSize();
4927379Sgblack@eecs.umich.edu    //The size of the data we're trying to read.
4937379Sgblack@eecs.umich.edu    int dataSize = sizeof(T);
4947379Sgblack@eecs.umich.edu
4957379Sgblack@eecs.umich.edu    uint8_t * dataPtr = (uint8_t *)&data;
4967379Sgblack@eecs.umich.edu
4977379Sgblack@eecs.umich.edu    //The address of the second part of this access if it needs to be split
4987379Sgblack@eecs.umich.edu    //across a cache line boundary.
4997386Sgblack@eecs.umich.edu    Addr secondAddr = roundDown(addr + dataSize - 1, blockSize);
5007379Sgblack@eecs.umich.edu
5017379Sgblack@eecs.umich.edu    if(secondAddr > addr)
5027379Sgblack@eecs.umich.edu        dataSize = secondAddr - addr;
5037379Sgblack@eecs.umich.edu
5047382Sgblack@eecs.umich.edu    dcache_latency = 0;
5057382Sgblack@eecs.umich.edu
5067382Sgblack@eecs.umich.edu    while(1) {
5077382Sgblack@eecs.umich.edu        req->setVirt(0, addr, dataSize, flags, thread->readPC());
5087386Sgblack@eecs.umich.edu
5097379Sgblack@eecs.umich.edu        // translate to physical address
5107379Sgblack@eecs.umich.edu        Fault fault = thread->translateDataWriteReq(req);
5117379Sgblack@eecs.umich.edu
5127386Sgblack@eecs.umich.edu        // Now do the access.
5137379Sgblack@eecs.umich.edu        if (fault == NoFault) {
5147379Sgblack@eecs.umich.edu            MemCmd cmd = MemCmd::WriteReq; // default
5157379Sgblack@eecs.umich.edu            bool do_access = true;  // flag to suppress cache access
5167379Sgblack@eecs.umich.edu
5177382Sgblack@eecs.umich.edu            if (req->isLocked()) {
5187382Sgblack@eecs.umich.edu                cmd = MemCmd::StoreCondReq;
5197382Sgblack@eecs.umich.edu                do_access = TheISA::handleLockedWrite(thread, req);
5207382Sgblack@eecs.umich.edu            } else if (req->isSwap()) {
5217386Sgblack@eecs.umich.edu                cmd = MemCmd::SwapReq;
5227379Sgblack@eecs.umich.edu                if (req->isCondSwap()) {
5237379Sgblack@eecs.umich.edu                    assert(res);
5247378Sgblack@eecs.umich.edu                    req->setExtraData(*res);
5257378Sgblack@eecs.umich.edu                }
5267378Sgblack@eecs.umich.edu            }
5277378Sgblack@eecs.umich.edu
5287378Sgblack@eecs.umich.edu            if (do_access) {
5297378Sgblack@eecs.umich.edu                Packet pkt = Packet(req, cmd, Packet::Broadcast);
5307378Sgblack@eecs.umich.edu                pkt.dataStatic(dataPtr);
5317378Sgblack@eecs.umich.edu
5327378Sgblack@eecs.umich.edu                if (req->isMmapedIpr()) {
5337378Sgblack@eecs.umich.edu                    dcache_latency +=
5347378Sgblack@eecs.umich.edu                        TheISA::handleIprWrite(thread->getTC(), &pkt);
5357378Sgblack@eecs.umich.edu                } else {
5367378Sgblack@eecs.umich.edu                    //XXX This needs to be outside of the loop in order to
5377378Sgblack@eecs.umich.edu                    //work properly for cache line boundary crossing
5387378Sgblack@eecs.umich.edu                    //accesses in transendian simulations.
5397378Sgblack@eecs.umich.edu                    data = htog(data);
5407378Sgblack@eecs.umich.edu                    if (hasPhysMemPort && pkt.getAddr() == physMemAddr)
5417378Sgblack@eecs.umich.edu                        dcache_latency += physmemPort.sendAtomic(&pkt);
5427378Sgblack@eecs.umich.edu                    else
5437378Sgblack@eecs.umich.edu                        dcache_latency += dcachePort.sendAtomic(&pkt);
5447378Sgblack@eecs.umich.edu                }
5457378Sgblack@eecs.umich.edu                dcache_access = true;
5467378Sgblack@eecs.umich.edu                assert(!pkt.isError());
5477378Sgblack@eecs.umich.edu
5487378Sgblack@eecs.umich.edu                if (req->isSwap()) {
5497378Sgblack@eecs.umich.edu                    assert(res);
5507378Sgblack@eecs.umich.edu                    *res = pkt.get<T>();
5517378Sgblack@eecs.umich.edu                }
5527378Sgblack@eecs.umich.edu            }
5537378Sgblack@eecs.umich.edu
5547378Sgblack@eecs.umich.edu            if (res && !req->isSwap()) {
5557378Sgblack@eecs.umich.edu                *res = req->getExtraData();
5567378Sgblack@eecs.umich.edu            }
5577378Sgblack@eecs.umich.edu        }
5587378Sgblack@eecs.umich.edu
5597378Sgblack@eecs.umich.edu        // This will need a new way to tell if it's hooked up to a cache or not.
5607378Sgblack@eecs.umich.edu        if (req->isUncacheable())
5617378Sgblack@eecs.umich.edu            recordEvent("Uncached Write");
5627378Sgblack@eecs.umich.edu
5637378Sgblack@eecs.umich.edu        //If there's a fault or we don't need to access a second cache line,
5647378Sgblack@eecs.umich.edu        //stop now.
5657378Sgblack@eecs.umich.edu        if (fault != NoFault || secondAddr <= addr)
5667378Sgblack@eecs.umich.edu        {
5677378Sgblack@eecs.umich.edu            // If the write needs to have a fault on the access, consider
5687378Sgblack@eecs.umich.edu            // calling changeStatus() and changing it to "bad addr write"
5697378Sgblack@eecs.umich.edu            // or something.
5707378Sgblack@eecs.umich.edu            if (traceData) {
5717376Sgblack@eecs.umich.edu                traceData->setData(data);
5727376Sgblack@eecs.umich.edu            }
5737376Sgblack@eecs.umich.edu            return fault;
5747376Sgblack@eecs.umich.edu        }
5757376Sgblack@eecs.umich.edu
5767376Sgblack@eecs.umich.edu        /*
5777376Sgblack@eecs.umich.edu         * Set up for accessing the second cache line.
5787376Sgblack@eecs.umich.edu         */
5797376Sgblack@eecs.umich.edu
5807376Sgblack@eecs.umich.edu        //Move the pointer we're reading into to the correct location.
5817376Sgblack@eecs.umich.edu        dataPtr += dataSize;
5827376Sgblack@eecs.umich.edu        //Adjust the size to get the remaining bytes.
5837376Sgblack@eecs.umich.edu        dataSize = addr + sizeof(T) - secondAddr;
5847376Sgblack@eecs.umich.edu        //And access the right address.
5857376Sgblack@eecs.umich.edu        addr = secondAddr;
5867376Sgblack@eecs.umich.edu    }
5877376Sgblack@eecs.umich.edu}
5887376Sgblack@eecs.umich.edu
5897376Sgblack@eecs.umich.eduFault
5907376Sgblack@eecs.umich.eduAtomicSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr,
5917376Sgblack@eecs.umich.edu        int size, unsigned flags)
5927376Sgblack@eecs.umich.edu{
5937376Sgblack@eecs.umich.edu    // use the CPU's statically allocated write request and packet objects
5947376Sgblack@eecs.umich.edu    Request *req = &data_write_req;
5957376Sgblack@eecs.umich.edu
5967376Sgblack@eecs.umich.edu    if (traceData) {
5977376Sgblack@eecs.umich.edu        traceData->setAddr(vaddr);
5987376Sgblack@eecs.umich.edu    }
5997376Sgblack@eecs.umich.edu
6007376Sgblack@eecs.umich.edu    //The block size of our peer.
6017376Sgblack@eecs.umich.edu    int blockSize = dcachePort.peerBlockSize();
6027376Sgblack@eecs.umich.edu
6037376Sgblack@eecs.umich.edu    //The address of the second part of this access if it needs to be split
6047376Sgblack@eecs.umich.edu    //across a cache line boundary.
6057376Sgblack@eecs.umich.edu    Addr secondAddr = roundDown(vaddr + size - 1, blockSize);
6067376Sgblack@eecs.umich.edu
6077376Sgblack@eecs.umich.edu    //The size of the data we're trying to read.
6087376Sgblack@eecs.umich.edu    int dataSize = size;
6097376Sgblack@eecs.umich.edu
6107376Sgblack@eecs.umich.edu    bool firstTimeThrough = true;
6117376Sgblack@eecs.umich.edu
6127376Sgblack@eecs.umich.edu    if(secondAddr > vaddr)
6137376Sgblack@eecs.umich.edu        dataSize = secondAddr - vaddr;
6147376Sgblack@eecs.umich.edu
6157376Sgblack@eecs.umich.edu    dcache_latency = 0;
6167376Sgblack@eecs.umich.edu
6177376Sgblack@eecs.umich.edu    while(1) {
6187376Sgblack@eecs.umich.edu        req->setVirt(0, vaddr, dataSize, flags, thread->readPC());
6197376Sgblack@eecs.umich.edu
6207376Sgblack@eecs.umich.edu        // translate to physical address
6217376Sgblack@eecs.umich.edu        Fault fault = thread->translateDataWriteReq(req);
6227376Sgblack@eecs.umich.edu
6237376Sgblack@eecs.umich.edu        //If there's a fault or we don't need to access a second cache line,
6247376Sgblack@eecs.umich.edu        //stop now.
6257376Sgblack@eecs.umich.edu        if (fault != NoFault)
6267376Sgblack@eecs.umich.edu            return fault;
6277376Sgblack@eecs.umich.edu
6287376Sgblack@eecs.umich.edu        if (firstTimeThrough) {
6297376Sgblack@eecs.umich.edu            paddr = req->getPaddr();
6307376Sgblack@eecs.umich.edu            firstTimeThrough = false;
6317376Sgblack@eecs.umich.edu        }
6327376Sgblack@eecs.umich.edu
6337375Sgblack@eecs.umich.edu        if (secondAddr <= vaddr)
6347375Sgblack@eecs.umich.edu            return fault;
6357375Sgblack@eecs.umich.edu
6367375Sgblack@eecs.umich.edu        /*
6377375Sgblack@eecs.umich.edu         * Set up for accessing the second cache line.
6387375Sgblack@eecs.umich.edu         */
6397375Sgblack@eecs.umich.edu
6407375Sgblack@eecs.umich.edu        //Adjust the size to get the remaining bytes.
6417375Sgblack@eecs.umich.edu        dataSize = vaddr + size - secondAddr;
6427375Sgblack@eecs.umich.edu        //And access the right address.
6437375Sgblack@eecs.umich.edu        vaddr = secondAddr;
6447375Sgblack@eecs.umich.edu    }
6457375Sgblack@eecs.umich.edu}
6467375Sgblack@eecs.umich.edu
6477375Sgblack@eecs.umich.edu
6487375Sgblack@eecs.umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS
6497375Sgblack@eecs.umich.edu
6507375Sgblack@eecs.umich.edutemplate
6517375Sgblack@eecs.umich.eduFault
6527375Sgblack@eecs.umich.eduAtomicSimpleCPU::write(Twin32_t data, Addr addr,
6537375Sgblack@eecs.umich.edu                       unsigned flags, uint64_t *res);
6547375Sgblack@eecs.umich.edu
6557375Sgblack@eecs.umich.edutemplate
6567375Sgblack@eecs.umich.eduFault
6577375Sgblack@eecs.umich.eduAtomicSimpleCPU::write(Twin64_t data, Addr addr,
6587375Sgblack@eecs.umich.edu                       unsigned flags, uint64_t *res);
6597375Sgblack@eecs.umich.edu
6607375Sgblack@eecs.umich.edutemplate
6617375Sgblack@eecs.umich.eduFault
6627375Sgblack@eecs.umich.eduAtomicSimpleCPU::write(uint64_t data, Addr addr,
6637375Sgblack@eecs.umich.edu                       unsigned flags, uint64_t *res);
6647375Sgblack@eecs.umich.edu
6657375Sgblack@eecs.umich.edutemplate
6667375Sgblack@eecs.umich.eduFault
6677375Sgblack@eecs.umich.eduAtomicSimpleCPU::write(uint32_t data, Addr addr,
6687375Sgblack@eecs.umich.edu                       unsigned flags, uint64_t *res);
6697375Sgblack@eecs.umich.edu
6707375Sgblack@eecs.umich.edutemplate
6717375Sgblack@eecs.umich.eduFault
6727375Sgblack@eecs.umich.eduAtomicSimpleCPU::write(uint16_t data, Addr addr,
6737375Sgblack@eecs.umich.edu                       unsigned flags, uint64_t *res);
6747375Sgblack@eecs.umich.edu
6757375Sgblack@eecs.umich.edutemplate
6767375Sgblack@eecs.umich.eduFault
6777375Sgblack@eecs.umich.eduAtomicSimpleCPU::write(uint8_t data, Addr addr,
6787375Sgblack@eecs.umich.edu                       unsigned flags, uint64_t *res);
6797375Sgblack@eecs.umich.edu
6807375Sgblack@eecs.umich.edu#endif //DOXYGEN_SHOULD_SKIP_THIS
6817384Sgblack@eecs.umich.edu
6827384Sgblack@eecs.umich.edutemplate<>
6837375Sgblack@eecs.umich.eduFault
684AtomicSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
685{
686    return write(*(uint64_t*)&data, addr, flags, res);
687}
688
689template<>
690Fault
691AtomicSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
692{
693    return write(*(uint32_t*)&data, addr, flags, res);
694}
695
696
697template<>
698Fault
699AtomicSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
700{
701    return write((uint32_t)data, addr, flags, res);
702}
703
704
705void
706AtomicSimpleCPU::tick()
707{
708    DPRINTF(SimpleCPU, "Tick\n");
709
710    Tick latency = 0;
711
712    for (int i = 0; i < width; ++i) {
713        numCycles++;
714
715        if (!curStaticInst || !curStaticInst->isDelayedCommit())
716            checkForInterrupts();
717
718        checkPcEventQueue();
719
720        Fault fault = NoFault;
721
722        bool fromRom = isRomMicroPC(thread->readMicroPC());
723        if (!fromRom)
724            fault = setupFetchRequest(&ifetch_req);
725
726        if (fault == NoFault) {
727            Tick icache_latency = 0;
728            bool icache_access = false;
729            dcache_access = false; // assume no dcache access
730
731            if (!fromRom) {
732                // This is commented out because the predecoder would act like
733                // a tiny cache otherwise. It wouldn't be flushed when needed
734                // like the I cache. It should be flushed, and when that works
735                // this code should be uncommented.
736                //Fetch more instruction memory if necessary
737                //if(predecoder.needMoreBytes())
738                //{
739                    icache_access = true;
740                    Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq,
741                                               Packet::Broadcast);
742                    ifetch_pkt.dataStatic(&inst);
743
744                    if (hasPhysMemPort && ifetch_pkt.getAddr() == physMemAddr)
745                        icache_latency = physmemPort.sendAtomic(&ifetch_pkt);
746                    else
747                        icache_latency = icachePort.sendAtomic(&ifetch_pkt);
748
749                    assert(!ifetch_pkt.isError());
750
751                    // ifetch_req is initialized to read the instruction directly
752                    // into the CPU object's inst field.
753                //}
754            }
755
756            preExecute();
757
758            if (curStaticInst) {
759                fault = curStaticInst->execute(this, traceData);
760
761                // keep an instruction count
762                if (fault == NoFault)
763                    countInst();
764                else if (traceData) {
765                    // If there was a fault, we should trace this instruction.
766                    delete traceData;
767                    traceData = NULL;
768                }
769
770                postExecute();
771            }
772
773            // @todo remove me after debugging with legion done
774            if (curStaticInst && (!curStaticInst->isMicroop() ||
775                        curStaticInst->isFirstMicroop()))
776                instCnt++;
777
778            Tick stall_ticks = 0;
779            if (simulate_inst_stalls && icache_access)
780                stall_ticks += icache_latency;
781
782            if (simulate_data_stalls && dcache_access)
783                stall_ticks += dcache_latency;
784
785            if (stall_ticks) {
786                Tick stall_cycles = stall_ticks / ticks(1);
787                Tick aligned_stall_ticks = ticks(stall_cycles);
788
789                if (aligned_stall_ticks < stall_ticks)
790                    aligned_stall_ticks += 1;
791
792                latency += aligned_stall_ticks;
793            }
794
795        }
796        if(fault != NoFault || !stayAtPC)
797            advancePC(fault);
798    }
799
800    // instruction takes at least one cycle
801    if (latency < ticks(1))
802        latency = ticks(1);
803
804    if (_status != Idle)
805        schedule(tickEvent, curTick + latency);
806}
807
808
809void
810AtomicSimpleCPU::printAddr(Addr a)
811{
812    dcachePort.printAddr(a);
813}
814
815
816////////////////////////////////////////////////////////////////////////
817//
818//  AtomicSimpleCPU Simulation Object
819//
820AtomicSimpleCPU *
821AtomicSimpleCPUParams::create()
822{
823    numThreads = 1;
824#if !FULL_SYSTEM
825    if (workload.size() != 1)
826        panic("only one workload allowed");
827#endif
828    return new AtomicSimpleCPU(this);
829}
830