atomic.cc revision 5101
12623SN/A/*
22623SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
32623SN/A * All rights reserved.
42623SN/A *
52623SN/A * Redistribution and use in source and binary forms, with or without
62623SN/A * modification, are permitted provided that the following conditions are
72623SN/A * met: redistributions of source code must retain the above copyright
82623SN/A * notice, this list of conditions and the following disclaimer;
92623SN/A * redistributions in binary form must reproduce the above copyright
102623SN/A * notice, this list of conditions and the following disclaimer in the
112623SN/A * documentation and/or other materials provided with the distribution;
122623SN/A * neither the name of the copyright holders nor the names of its
132623SN/A * contributors may be used to endorse or promote products derived from
142623SN/A * this software without specific prior written permission.
152623SN/A *
162623SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172623SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182623SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192623SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202623SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212623SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222623SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232623SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242623SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252623SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262623SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu *
282665Ssaidi@eecs.umich.edu * Authors: Steve Reinhardt
292623SN/A */
302623SN/A
313170Sstever@eecs.umich.edu#include "arch/locked_mem.hh"
323806Ssaidi@eecs.umich.edu#include "arch/mmaped_ipr.hh"
332623SN/A#include "arch/utility.hh"
344040Ssaidi@eecs.umich.edu#include "base/bigint.hh"
356658Snate@binkert.org#include "cpu/exetrace.hh"
362623SN/A#include "cpu/simple/atomic.hh"
372623SN/A#include "mem/packet.hh"
383348Sbinkertn@umich.edu#include "mem/packet_access.hh"
393348Sbinkertn@umich.edu#include "params/AtomicSimpleCPU.hh"
404762Snate@binkert.org#include "sim/system.hh"
417678Sgblack@eecs.umich.edu
422901Ssaidi@eecs.umich.eduusing namespace std;
432623SN/Ausing namespace TheISA;
442623SN/A
452623SN/AAtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c)
462623SN/A    : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
472623SN/A{
485606Snate@binkert.org}
492623SN/A
502623SN/A
512623SN/Avoid
522623SN/AAtomicSimpleCPU::TickEvent::process()
532623SN/A{
542623SN/A    cpu->tick();
552623SN/A}
562623SN/A
572623SN/Aconst char *
582623SN/AAtomicSimpleCPU::TickEvent::description()
592623SN/A{
605336Shines@cs.fsu.edu    return "AtomicSimpleCPU tick";
612623SN/A}
624873Sstever@eecs.umich.edu
632623SN/APort *
642623SN/AAtomicSimpleCPU::getPort(const std::string &if_name, int idx)
652856Srdreslin@umich.edu{
666227Snate@binkert.org    if (if_name == "dcache_port")
672856Srdreslin@umich.edu        return &dcachePort;
682856Srdreslin@umich.edu    else if (if_name == "icache_port")
692856Srdreslin@umich.edu        return &icachePort;
702856Srdreslin@umich.edu    else if (if_name == "physmem_port") {
712856Srdreslin@umich.edu        hasPhysMemPort = true;
724968Sacolyte@umich.edu        return &physmemPort;
734968Sacolyte@umich.edu    }
744968Sacolyte@umich.edu    else
754968Sacolyte@umich.edu        panic("No Such Port\n");
762856Srdreslin@umich.edu}
772856Srdreslin@umich.edu
782856Srdreslin@umich.eduvoid
792623SN/AAtomicSimpleCPU::init()
802623SN/A{
812623SN/A    BaseCPU::init();
822623SN/A#if FULL_SYSTEM
832623SN/A    for (int i = 0; i < threadContexts.size(); ++i) {
842623SN/A        ThreadContext *tc = threadContexts[i];
856221Snate@binkert.org
866221Snate@binkert.org        // initialize CPU, including PC
872680Sktlim@umich.edu        TheISA::initCPU(tc, tc->readCpuId());
882623SN/A    }
892623SN/A#endif
905714Shsul@eecs.umich.edu    if (hasPhysMemPort) {
912623SN/A        bool snoop = false;
922623SN/A        AddrRangeList pmAddrList;
934968Sacolyte@umich.edu        physmemPort.getPeerAddressRanges(pmAddrList, snoop);
944968Sacolyte@umich.edu        physMemAddr = *pmAddrList.begin();
954968Sacolyte@umich.edu    }
964968Sacolyte@umich.edu}
974968Sacolyte@umich.edu
984968Sacolyte@umich.edubool
995714Shsul@eecs.umich.eduAtomicSimpleCPU::CpuPort::recvTiming(PacketPtr pkt)
1005712Shsul@eecs.umich.edu{
1015712Shsul@eecs.umich.edu    panic("AtomicSimpleCPU doesn't expect recvTiming callback!");
1025712Shsul@eecs.umich.edu    return true;
1032623SN/A}
1042623SN/A
1052623SN/ATick
1063349Sbinkertn@umich.eduAtomicSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
1072623SN/A{
1083184Srdreslin@umich.edu    //Snooping a coherence request, just return
1092623SN/A    return 0;
1102623SN/A}
1112623SN/A
1122623SN/Avoid
1133349Sbinkertn@umich.eduAtomicSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
1142623SN/A{
1153310Srdreslin@umich.edu    //No internal storage to update, just return
1163649Srdreslin@umich.edu    return;
1172623SN/A}
1182623SN/A
1192623SN/Avoid
1203349Sbinkertn@umich.eduAtomicSimpleCPU::CpuPort::recvStatusChange(Status status)
1212623SN/A{
1223184Srdreslin@umich.edu    if (status == RangeChange) {
1233184Srdreslin@umich.edu        if (!snoopRangeSent) {
1242623SN/A            snoopRangeSent = true;
1252623SN/A            sendStatusChange(Port::RangeChange);
1262623SN/A        }
1272623SN/A        return;
1282623SN/A    }
1293647Srdreslin@umich.edu
1303647Srdreslin@umich.edu    panic("AtomicSimpleCPU doesn't expect recvStatusChange callback!");
1313647Srdreslin@umich.edu}
1323647Srdreslin@umich.edu
1333647Srdreslin@umich.eduvoid
1342626SN/AAtomicSimpleCPU::CpuPort::recvRetry()
1353647Srdreslin@umich.edu{
1362626SN/A    panic("AtomicSimpleCPU doesn't expect recvRetry callback!");
1372623SN/A}
1382623SN/A
1392623SN/Avoid
1402657Ssaidi@eecs.umich.eduAtomicSimpleCPU::DcachePort::setPeer(Port *port)
1412623SN/A{
1422623SN/A    Port::setPeer(port);
1432623SN/A
1442623SN/A#if FULL_SYSTEM
1452623SN/A    // Update the ThreadContext's memory ports (Functional/Virtual
1464192Sktlim@umich.edu    // Ports)
1474192Sktlim@umich.edu    cpu->tcBase()->connectMemPorts();
1484192Sktlim@umich.edu#endif
1494192Sktlim@umich.edu}
1504192Sktlim@umich.edu
1514192Sktlim@umich.eduAtomicSimpleCPU::AtomicSimpleCPU(Params *p)
1524192Sktlim@umich.edu    : BaseSimpleCPU(p), tickEvent(this),
1534192Sktlim@umich.edu      width(p->width), simulate_stalls(p->simulate_stalls),
1545497Ssaidi@eecs.umich.edu      icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this),
1554192Sktlim@umich.edu      physmemPort(name() + "-iport", this), hasPhysMemPort(false)
1564192Sktlim@umich.edu{
1572623SN/A    _status = Idle;
1585529Snate@binkert.org
1596078Sgblack@eecs.umich.edu    icachePort.snoopRangeSent = false;
1605487Snate@binkert.org    dcachePort.snoopRangeSent = false;
1615487Snate@binkert.org
1624968Sacolyte@umich.edu    ifetch_req.setThreadContext(p->cpu_id, 0); // Add thread ID if we add MT
1634968Sacolyte@umich.edu    data_read_req.setThreadContext(p->cpu_id, 0); // Add thread ID here too
1642623SN/A    data_write_req.setThreadContext(p->cpu_id, 0); // Add thread ID here too
1652623SN/A}
1662623SN/A
1673647Srdreslin@umich.edu
1683647Srdreslin@umich.eduAtomicSimpleCPU::~AtomicSimpleCPU()
1693647Srdreslin@umich.edu{
1702623SN/A}
1712623SN/A
1722623SN/Avoid
1732623SN/AAtomicSimpleCPU::serialize(ostream &os)
1742623SN/A{
1756775SBrad.Beckmann@amd.com    SimObject::State so_state = SimObject::getState();
1766775SBrad.Beckmann@amd.com    SERIALIZE_ENUM(so_state);
1776775SBrad.Beckmann@amd.com    Status _status = status();
1782623SN/A    SERIALIZE_ENUM(_status);
1792623SN/A    BaseSimpleCPU::serialize(os);
1802623SN/A    nameOut(os, csprintf("%s.tickEvent", name()));
1812623SN/A    tickEvent.serialize(os);
1822623SN/A}
1832915Sktlim@umich.edu
1842915Sktlim@umich.eduvoid
1856078Sgblack@eecs.umich.eduAtomicSimpleCPU::unserialize(Checkpoint *cp, const string &section)
1863145Shsul@eecs.umich.edu{
1872623SN/A    SimObject::State so_state;
1882623SN/A    UNSERIALIZE_ENUM(so_state);
1892623SN/A    UNSERIALIZE_ENUM(_status);
1902623SN/A    BaseSimpleCPU::unserialize(cp, section);
1912623SN/A    tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
1922623SN/A}
1932623SN/A
1942915Sktlim@umich.eduvoid
1952915Sktlim@umich.eduAtomicSimpleCPU::resume()
1966078Sgblack@eecs.umich.edu{
1973145Shsul@eecs.umich.edu    DPRINTF(SimpleCPU, "Resume\n");
1982915Sktlim@umich.edu    if (_status != SwitchedOut && _status != Idle) {
1992915Sktlim@umich.edu        assert(system->getMemoryMode() == Enums::atomic);
2002915Sktlim@umich.edu
2012915Sktlim@umich.edu        changeState(SimObject::Running);
2022915Sktlim@umich.edu        if (thread->status() == ThreadContext::Active) {
2032915Sktlim@umich.edu            if (!tickEvent.scheduled()) {
2045220Ssaidi@eecs.umich.edu                tickEvent.schedule(nextCycle());
2055220Ssaidi@eecs.umich.edu            }
2065220Ssaidi@eecs.umich.edu        }
2074940Snate@binkert.org    }
2085220Ssaidi@eecs.umich.edu}
2093324Shsul@eecs.umich.edu
2105220Ssaidi@eecs.umich.eduvoid
2115220Ssaidi@eecs.umich.eduAtomicSimpleCPU::switchOut()
2125606Snate@binkert.org{
2135606Snate@binkert.org    assert(status() == Running || status() == Idle);
2142915Sktlim@umich.edu    _status = SwitchedOut;
2157897Shestness@cs.utexas.edu
2162623SN/A    tickEvent.squash();
2172623SN/A}
2182623SN/A
2192798Sktlim@umich.edu
2202623SN/Avoid
2215496Ssaidi@eecs.umich.eduAtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
2222798Sktlim@umich.edu{
2232623SN/A    BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
2242798Sktlim@umich.edu
2252623SN/A    assert(!tickEvent.scheduled());
2262623SN/A
2272623SN/A    // if any of this CPU's ThreadContexts are active, mark the CPU as
2282623SN/A    // running and schedule its tick event.
2292623SN/A    for (int i = 0; i < threadContexts.size(); ++i) {
2302623SN/A        ThreadContext *tc = threadContexts[i];
2314192Sktlim@umich.edu        if (tc->status() == ThreadContext::Active && _status != Running) {
2322623SN/A            _status = Running;
2332623SN/A            tickEvent.schedule(nextCycle());
2342623SN/A            break;
2352680Sktlim@umich.edu        }
2362623SN/A    }
2376221Snate@binkert.org    if (_status != Running) {
2386221Snate@binkert.org        _status = Idle;
2392680Sktlim@umich.edu    }
2402680Sktlim@umich.edu}
2412623SN/A
2425606Snate@binkert.org
2432623SN/Avoid
2442623SN/AAtomicSimpleCPU::activateContext(int thread_num, int delay)
2452623SN/A{
2463512Sktlim@umich.edu    DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay);
2473512Sktlim@umich.edu
2483512Sktlim@umich.edu    assert(thread_num == 0);
2495169Ssaidi@eecs.umich.edu    assert(thread);
2505712Shsul@eecs.umich.edu
2515712Shsul@eecs.umich.edu    assert(_status == Idle);
2525712Shsul@eecs.umich.edu    assert(!tickEvent.scheduled());
2532623SN/A
2542623SN/A    notIdleFraction++;
2552623SN/A    numCycles += tickToCycles(thread->lastActivate - thread->lastSuspend);
2562623SN/A
2572623SN/A    //Make sure ticks are still on multiples of cycles
2582623SN/A    tickEvent.schedule(nextCycle(curTick + ticks(delay)));
2594940Snate@binkert.org    _status = Running;
2604940Snate@binkert.org}
2612623SN/A
2622683Sktlim@umich.edu
2632623SN/Avoid
2642623SN/AAtomicSimpleCPU::suspendContext(int thread_num)
2652623SN/A{
2662623SN/A    DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
2672623SN/A
2685101Ssaidi@eecs.umich.edu    assert(thread_num == 0);
2693686Sktlim@umich.edu    assert(thread);
2703430Sgblack@eecs.umich.edu
2717823Ssteve.reinhardt@amd.com    assert(_status == Running);
2722623SN/A
2732623SN/A    // tick event may not be scheduled if this gets called from inside
2742623SN/A    // an instruction's execution, e.g. "quiesce"
2752623SN/A    if (tickEvent.scheduled())
2762623SN/A        tickEvent.deschedule();
2772623SN/A
2782623SN/A    notIdleFraction--;
2794940Snate@binkert.org    _status = Idle;
2804940Snate@binkert.org}
2812623SN/A
2822683Sktlim@umich.edu
2832623SN/Atemplate <class T>
2846043Sgblack@eecs.umich.eduFault
2856043Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
2866043Sgblack@eecs.umich.edu{
2872623SN/A    // use the CPU's statically allocated read request and packet objects
2882626SN/A    Request *req = &data_read_req;
2892626SN/A
2902626SN/A    if (traceData) {
2912626SN/A        traceData->setAddr(addr);
2925606Snate@binkert.org    }
2932623SN/A
2942623SN/A    //The block size of our peer.
2952623SN/A    int blockSize = dcachePort.peerBlockSize();
2962623SN/A    //The size of the data we're trying to read.
2972623SN/A    int dataSize = sizeof(T);
2982623SN/A
2992623SN/A    uint8_t * dataPtr = (uint8_t *)&data;
3007520Sgblack@eecs.umich.edu
3017520Sgblack@eecs.umich.edu    //The address of the second part of this access if it needs to be split
3022623SN/A    //across a cache line boundary.
3033169Sstever@eecs.umich.edu    Addr secondAddr = roundDown(addr + dataSize - 1, blockSize);
3044870Sstever@eecs.umich.edu
3052623SN/A    if(secondAddr > addr)
3062623SN/A        dataSize = secondAddr - addr;
3072623SN/A
3082623SN/A    dcache_latency = 0;
3092623SN/A
3104999Sgblack@eecs.umich.edu    while(1) {
3116227Snate@binkert.org        req->setVirt(0, addr, dataSize, flags, thread->readPC());
3124999Sgblack@eecs.umich.edu
3137520Sgblack@eecs.umich.edu        // translate to physical address
3142623SN/A        Fault fault = thread->translateDataReadReq(req);
3154999Sgblack@eecs.umich.edu
3164999Sgblack@eecs.umich.edu        // Now do the access.
3177520Sgblack@eecs.umich.edu        if (fault == NoFault) {
3184999Sgblack@eecs.umich.edu            Packet pkt = Packet(req,
3197520Sgblack@eecs.umich.edu                    req->isLocked() ? MemCmd::LoadLockedReq : MemCmd::ReadReq,
3207520Sgblack@eecs.umich.edu                    Packet::Broadcast);
3214999Sgblack@eecs.umich.edu            pkt.dataStatic(dataPtr);
3224999Sgblack@eecs.umich.edu
3234999Sgblack@eecs.umich.edu            if (req->isMmapedIpr())
3247520Sgblack@eecs.umich.edu                dcache_latency += TheISA::handleIprRead(thread->getTC(), &pkt);
3257720Sgblack@eecs.umich.edu            else {
3264999Sgblack@eecs.umich.edu                if (hasPhysMemPort && pkt.getAddr() == physMemAddr)
3274999Sgblack@eecs.umich.edu                    dcache_latency += physmemPort.sendAtomic(&pkt);
3286023Snate@binkert.org                else
3294999Sgblack@eecs.umich.edu                    dcache_latency += dcachePort.sendAtomic(&pkt);
3304999Sgblack@eecs.umich.edu            }
3316623Sgblack@eecs.umich.edu            dcache_access = true;
3324999Sgblack@eecs.umich.edu
3336102Sgblack@eecs.umich.edu            assert(!pkt.isError());
3344999Sgblack@eecs.umich.edu
3357520Sgblack@eecs.umich.edu            if (req->isLocked()) {
3364999Sgblack@eecs.umich.edu                TheISA::handleLockedRead(thread, req);
3374999Sgblack@eecs.umich.edu            }
3384999Sgblack@eecs.umich.edu        }
3394999Sgblack@eecs.umich.edu
3404999Sgblack@eecs.umich.edu        // This will need a new way to tell if it has a dcache attached.
3414999Sgblack@eecs.umich.edu        if (req->isUncacheable())
3424999Sgblack@eecs.umich.edu            recordEvent("Uncached Read");
3434999Sgblack@eecs.umich.edu
3444999Sgblack@eecs.umich.edu        //If there's a fault, return it
3454999Sgblack@eecs.umich.edu        if (fault != NoFault)
3465012Sgblack@eecs.umich.edu            return fault;
3474999Sgblack@eecs.umich.edu        //If we don't need to access a second cache line, stop now.
3484999Sgblack@eecs.umich.edu        if (secondAddr <= addr)
3496102Sgblack@eecs.umich.edu        {
3504999Sgblack@eecs.umich.edu            data = gtoh(data);
3514999Sgblack@eecs.umich.edu            return fault;
3524968Sacolyte@umich.edu        }
3534986Ssaidi@eecs.umich.edu
3544999Sgblack@eecs.umich.edu        /*
3556739Sgblack@eecs.umich.edu         * Set up for accessing the second cache line.
3566739Sgblack@eecs.umich.edu         */
3576739Sgblack@eecs.umich.edu
3586739Sgblack@eecs.umich.edu        //Move the pointer we're reading into to the correct location.
3596739Sgblack@eecs.umich.edu        dataPtr += dataSize;
3606739Sgblack@eecs.umich.edu        //Adjust the size to get the remaining bytes.
3616739Sgblack@eecs.umich.edu        dataSize = addr + sizeof(T) - secondAddr;
3626739Sgblack@eecs.umich.edu        //And access the right address.
3634999Sgblack@eecs.umich.edu        addr = secondAddr;
3644999Sgblack@eecs.umich.edu    }
3654999Sgblack@eecs.umich.edu}
3666078Sgblack@eecs.umich.edu
3676078Sgblack@eecs.umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS
3686078Sgblack@eecs.umich.edu
3696078Sgblack@eecs.umich.edutemplate
3704999Sgblack@eecs.umich.eduFault
3714968Sacolyte@umich.eduAtomicSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags);
3723170Sstever@eecs.umich.edu
3734999Sgblack@eecs.umich.edutemplate
3744999Sgblack@eecs.umich.eduFault
3754999Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags);
3764999Sgblack@eecs.umich.edu
3774999Sgblack@eecs.umich.edutemplate
3787520Sgblack@eecs.umich.eduFault
3794999Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
3807520Sgblack@eecs.umich.edu
3814999Sgblack@eecs.umich.edutemplate
3824999Sgblack@eecs.umich.eduFault
3832623SN/AAtomicSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
3842623SN/A
3852623SN/Atemplate
3867520Sgblack@eecs.umich.eduFault
3877520Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
3887520Sgblack@eecs.umich.edu
3897520Sgblack@eecs.umich.edutemplate
3907520Sgblack@eecs.umich.eduFault
3917520Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
3927520Sgblack@eecs.umich.edu
3937520Sgblack@eecs.umich.edu#endif //DOXYGEN_SHOULD_SKIP_THIS
3947520Sgblack@eecs.umich.edu
3957520Sgblack@eecs.umich.edutemplate<>
3967520Sgblack@eecs.umich.eduFault
3977520Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, double &data, unsigned flags)
3987520Sgblack@eecs.umich.edu{
3997520Sgblack@eecs.umich.edu    return read(addr, *(uint64_t*)&data, flags);
4007520Sgblack@eecs.umich.edu}
4017520Sgblack@eecs.umich.edu
4022623SN/Atemplate<>
4032623SN/AFault
4042623SN/AAtomicSimpleCPU::read(Addr addr, float &data, unsigned flags)
4052623SN/A{
4064115Ssaidi@eecs.umich.edu    return read(addr, *(uint32_t*)&data, flags);
4074115Ssaidi@eecs.umich.edu}
4084115Ssaidi@eecs.umich.edu
4094115Ssaidi@eecs.umich.edu
4104040Ssaidi@eecs.umich.edutemplate<>
4114040Ssaidi@eecs.umich.eduFault
4124040Ssaidi@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
4134040Ssaidi@eecs.umich.edu{
4142623SN/A    return read(addr, (uint32_t&)data, flags);
4152623SN/A}
4162623SN/A
4172623SN/A
4182623SN/Atemplate <class T>
4192623SN/AFault
4202623SN/AAtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
4212623SN/A{
4222623SN/A    // use the CPU's statically allocated write request and packet objects
4232623SN/A    Request *req = &data_write_req;
4242623SN/A
4252623SN/A    if (traceData) {
4262623SN/A        traceData->setAddr(addr);
4272623SN/A    }
4282623SN/A
4292623SN/A    //The block size of our peer.
4302623SN/A    int blockSize = dcachePort.peerBlockSize();
4312623SN/A    //The size of the data we're trying to read.
4322623SN/A    int dataSize = sizeof(T);
4332623SN/A
4342623SN/A    uint8_t * dataPtr = (uint8_t *)&data;
4352623SN/A
4362623SN/A    //The address of the second part of this access if it needs to be split
4372623SN/A    //across a cache line boundary.
4382623SN/A    Addr secondAddr = roundDown(addr + dataSize - 1, blockSize);
4392623SN/A
4402623SN/A    if(secondAddr > addr)
4412623SN/A        dataSize = secondAddr - addr;
4422623SN/A
4432623SN/A    dcache_latency = 0;
4442623SN/A
4452623SN/A    while(1) {
4462623SN/A        req->setVirt(0, addr, dataSize, flags, thread->readPC());
4472623SN/A
4482623SN/A        // translate to physical address
4492623SN/A        Fault fault = thread->translateDataWriteReq(req);
4502623SN/A
4512623SN/A        // Now do the access.
4522623SN/A        if (fault == NoFault) {
4532623SN/A            MemCmd cmd = MemCmd::WriteReq; // default
4547520Sgblack@eecs.umich.edu            bool do_access = true;  // flag to suppress cache access
4557520Sgblack@eecs.umich.edu
4562623SN/A            if (req->isLocked()) {
4573169Sstever@eecs.umich.edu                cmd = MemCmd::StoreCondReq;
4584870Sstever@eecs.umich.edu                do_access = TheISA::handleLockedWrite(thread, req);
4592623SN/A            } else if (req->isSwap()) {
4602623SN/A                cmd = MemCmd::SwapReq;
4612623SN/A                if (req->isCondSwap()) {
4622623SN/A                    assert(res);
4632623SN/A                    req->setExtraData(*res);
4644999Sgblack@eecs.umich.edu                }
4656227Snate@binkert.org            }
4664999Sgblack@eecs.umich.edu
4677520Sgblack@eecs.umich.edu            if (do_access) {
4682623SN/A                Packet pkt = Packet(req, cmd, Packet::Broadcast);
4694999Sgblack@eecs.umich.edu                pkt.dataStatic(dataPtr);
4704999Sgblack@eecs.umich.edu
4717520Sgblack@eecs.umich.edu                if (req->isMmapedIpr()) {
4724999Sgblack@eecs.umich.edu                    dcache_latency +=
4734999Sgblack@eecs.umich.edu                        TheISA::handleIprWrite(thread->getTC(), &pkt);
4747520Sgblack@eecs.umich.edu                } else {
4754999Sgblack@eecs.umich.edu                    //XXX This needs to be outside of the loop in order to
4764999Sgblack@eecs.umich.edu                    //work properly for cache line boundary crossing
4774999Sgblack@eecs.umich.edu                    //accesses in transendian simulations.
4784999Sgblack@eecs.umich.edu                    data = htog(data);
4797720Sgblack@eecs.umich.edu                    if (hasPhysMemPort && pkt.getAddr() == physMemAddr)
4804999Sgblack@eecs.umich.edu                        dcache_latency += physmemPort.sendAtomic(&pkt);
4814999Sgblack@eecs.umich.edu                    else
4826023Snate@binkert.org                        dcache_latency += dcachePort.sendAtomic(&pkt);
4834999Sgblack@eecs.umich.edu                }
4844999Sgblack@eecs.umich.edu                dcache_access = true;
4854999Sgblack@eecs.umich.edu                assert(!pkt.isError());
4864999Sgblack@eecs.umich.edu
4874999Sgblack@eecs.umich.edu                if (req->isSwap()) {
4884999Sgblack@eecs.umich.edu                    assert(res);
4896102Sgblack@eecs.umich.edu                    *res = pkt.get<T>();
4904999Sgblack@eecs.umich.edu                }
4914999Sgblack@eecs.umich.edu            }
4924999Sgblack@eecs.umich.edu
4934999Sgblack@eecs.umich.edu            if (res && !req->isSwap()) {
4944999Sgblack@eecs.umich.edu                *res = req->getExtraData();
4954999Sgblack@eecs.umich.edu            }
4964999Sgblack@eecs.umich.edu        }
4974999Sgblack@eecs.umich.edu
4984999Sgblack@eecs.umich.edu        // This will need a new way to tell if it's hooked up to a cache or not.
4994999Sgblack@eecs.umich.edu        if (req->isUncacheable())
5006623Sgblack@eecs.umich.edu            recordEvent("Uncached Write");
5014999Sgblack@eecs.umich.edu
5027520Sgblack@eecs.umich.edu        //If there's a fault or we don't need to access a second cache line,
5034999Sgblack@eecs.umich.edu        //stop now.
5044999Sgblack@eecs.umich.edu        if (fault != NoFault || secondAddr <= addr)
5054999Sgblack@eecs.umich.edu        {
5064999Sgblack@eecs.umich.edu            // If the write needs to have a fault on the access, consider
5074999Sgblack@eecs.umich.edu            // calling changeStatus() and changing it to "bad addr write"
5084999Sgblack@eecs.umich.edu            // or something.
5094999Sgblack@eecs.umich.edu            return fault;
5104999Sgblack@eecs.umich.edu        }
5114999Sgblack@eecs.umich.edu
5124999Sgblack@eecs.umich.edu        /*
5134999Sgblack@eecs.umich.edu         * Set up for accessing the second cache line.
5144999Sgblack@eecs.umich.edu         */
5154999Sgblack@eecs.umich.edu
5164999Sgblack@eecs.umich.edu        //Move the pointer we're reading into to the correct location.
5174999Sgblack@eecs.umich.edu        dataPtr += dataSize;
5187520Sgblack@eecs.umich.edu        //Adjust the size to get the remaining bytes.
5194999Sgblack@eecs.umich.edu        dataSize = addr + sizeof(T) - secondAddr;
5204999Sgblack@eecs.umich.edu        //And access the right address.
5214999Sgblack@eecs.umich.edu        addr = secondAddr;
5224999Sgblack@eecs.umich.edu    }
5234999Sgblack@eecs.umich.edu}
5244878Sstever@eecs.umich.edu
5254040Ssaidi@eecs.umich.edu
5264040Ssaidi@eecs.umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS
5274999Sgblack@eecs.umich.edu
5284999Sgblack@eecs.umich.edutemplate
5294999Sgblack@eecs.umich.eduFault
5304999Sgblack@eecs.umich.eduAtomicSimpleCPU::write(Twin32_t data, Addr addr,
5316078Sgblack@eecs.umich.edu                       unsigned flags, uint64_t *res);
5326078Sgblack@eecs.umich.edu
5336078Sgblack@eecs.umich.edutemplate
5346078Sgblack@eecs.umich.eduFault
5356739Sgblack@eecs.umich.eduAtomicSimpleCPU::write(Twin64_t data, Addr addr,
5366739Sgblack@eecs.umich.edu                       unsigned flags, uint64_t *res);
5376739Sgblack@eecs.umich.edu
5386739Sgblack@eecs.umich.edutemplate
5396739Sgblack@eecs.umich.eduFault
5403170Sstever@eecs.umich.eduAtomicSimpleCPU::write(uint64_t data, Addr addr,
5413170Sstever@eecs.umich.edu                       unsigned flags, uint64_t *res);
5424999Sgblack@eecs.umich.edu
5434999Sgblack@eecs.umich.edutemplate
5444999Sgblack@eecs.umich.eduFault
5454999Sgblack@eecs.umich.eduAtomicSimpleCPU::write(uint32_t data, Addr addr,
5464999Sgblack@eecs.umich.edu                       unsigned flags, uint64_t *res);
5477520Sgblack@eecs.umich.edu
5484999Sgblack@eecs.umich.edutemplate
5497520Sgblack@eecs.umich.eduFault
5504999Sgblack@eecs.umich.eduAtomicSimpleCPU::write(uint16_t data, Addr addr,
5514999Sgblack@eecs.umich.edu                       unsigned flags, uint64_t *res);
5522623SN/A
5532623SN/Atemplate
5542623SN/AFault
5552623SN/AAtomicSimpleCPU::write(uint8_t data, Addr addr,
5567520Sgblack@eecs.umich.edu                       unsigned flags, uint64_t *res);
5577520Sgblack@eecs.umich.edu
5587520Sgblack@eecs.umich.edu#endif //DOXYGEN_SHOULD_SKIP_THIS
5597520Sgblack@eecs.umich.edu
5607520Sgblack@eecs.umich.edutemplate<>
5617520Sgblack@eecs.umich.eduFault
5627520Sgblack@eecs.umich.eduAtomicSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
5637520Sgblack@eecs.umich.edu{
5647520Sgblack@eecs.umich.edu    return write(*(uint64_t*)&data, addr, flags, res);
5657520Sgblack@eecs.umich.edu}
5667520Sgblack@eecs.umich.edu
5677520Sgblack@eecs.umich.edutemplate<>
5687520Sgblack@eecs.umich.eduFault
5697520Sgblack@eecs.umich.eduAtomicSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
5707520Sgblack@eecs.umich.edu{
5717520Sgblack@eecs.umich.edu    return write(*(uint32_t*)&data, addr, flags, res);
5727520Sgblack@eecs.umich.edu}
5732623SN/A
5744224Sgblack@eecs.umich.edu
5754224Sgblack@eecs.umich.edutemplate<>
5764224Sgblack@eecs.umich.eduFault
5774224Sgblack@eecs.umich.eduAtomicSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
5784224Sgblack@eecs.umich.edu{
5794224Sgblack@eecs.umich.edu    return write((uint32_t)data, addr, flags, res);
5804224Sgblack@eecs.umich.edu}
5814224Sgblack@eecs.umich.edu
5824224Sgblack@eecs.umich.edu
5834224Sgblack@eecs.umich.eduvoid
5844224Sgblack@eecs.umich.eduAtomicSimpleCPU::tick()
5852623SN/A{
5862623SN/A    DPRINTF(SimpleCPU, "Tick\n");
5872623SN/A
5882623SN/A    Tick latency = ticks(1); // instruction takes one cycle by default
5892623SN/A
5902623SN/A    for (int i = 0; i < width; ++i) {
5912623SN/A        numCycles++;
5922623SN/A
5932623SN/A        if (!curStaticInst || !curStaticInst->isDelayedCommit())
5942623SN/A            checkForInterrupts();
5952623SN/A
5962623SN/A        Fault fault = setupFetchRequest(&ifetch_req);
5972623SN/A
5982623SN/A        if (fault == NoFault) {
5992623SN/A            Tick icache_latency = 0;
6002623SN/A            bool icache_access = false;
6012623SN/A            dcache_access = false; // assume no dcache access
6022623SN/A
6032623SN/A            //Fetch more instruction memory if necessary
6042623SN/A            //if(predecoder.needMoreBytes())
6052623SN/A            //{
6062623SN/A                icache_access = true;
6072623SN/A                Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq,
6082623SN/A                                           Packet::Broadcast);
6092623SN/A                ifetch_pkt.dataStatic(&inst);
6102623SN/A
6112623SN/A                if (hasPhysMemPort && ifetch_pkt.getAddr() == physMemAddr)
6122623SN/A                    icache_latency = physmemPort.sendAtomic(&ifetch_pkt);
6132623SN/A                else
6142623SN/A                    icache_latency = icachePort.sendAtomic(&ifetch_pkt);
6152623SN/A
6162623SN/A                assert(!ifetch_pkt.isError());
6172623SN/A
6182623SN/A                // ifetch_req is initialized to read the instruction directly
6192623SN/A                // into the CPU object's inst field.
6202623SN/A            //}
6212623SN/A
6222623SN/A            preExecute();
6232623SN/A
6242623SN/A            if (curStaticInst) {
6252623SN/A                fault = curStaticInst->execute(this, traceData);
6262623SN/A
6272623SN/A                // keep an instruction count
6282623SN/A                if (fault == NoFault)
6292623SN/A                    countInst();
6302623SN/A                else if (traceData) {
6312623SN/A                    // If there was a fault, we should trace this instruction.
6322623SN/A                    delete traceData;
6334940Snate@binkert.org                    traceData = NULL;
6344940Snate@binkert.org                }
6355487Snate@binkert.org
6362623SN/A                postExecute();
6376078Sgblack@eecs.umich.edu            }
6382623SN/A
6392623SN/A            // @todo remove me after debugging with legion done
6403387Sgblack@eecs.umich.edu            if (curStaticInst && (!curStaticInst->isMicroop() ||
6413387Sgblack@eecs.umich.edu                        curStaticInst->isFirstMicroop()))
6422626SN/A                instCnt++;
6435348Ssaidi@eecs.umich.edu
6445348Ssaidi@eecs.umich.edu            if (simulate_stalls) {
6455669Sgblack@eecs.umich.edu                Tick icache_stall =
6465669Sgblack@eecs.umich.edu                    icache_access ? icache_latency - ticks(1) : 0;
6477720Sgblack@eecs.umich.edu                Tick dcache_stall =
6487720Sgblack@eecs.umich.edu                    dcache_access ? dcache_latency - ticks(1) : 0;
6497720Sgblack@eecs.umich.edu                Tick stall_cycles = (icache_stall + dcache_stall) / ticks(1);
6507720Sgblack@eecs.umich.edu                if (ticks(stall_cycles) < (icache_stall + dcache_stall))
6517720Sgblack@eecs.umich.edu                    latency += ticks(stall_cycles+1);
6525894Sgblack@eecs.umich.edu                else
6536023Snate@binkert.org                    latency += ticks(stall_cycles);
6546023Snate@binkert.org            }
6555894Sgblack@eecs.umich.edu
6562623SN/A        }
6572623SN/A        if(fault != NoFault || !stayAtPC)
6584182Sgblack@eecs.umich.edu            advancePC(fault);
6594182Sgblack@eecs.umich.edu    }
6604182Sgblack@eecs.umich.edu
6612662Sstever@eecs.umich.edu    if (_status != Idle)
6627720Sgblack@eecs.umich.edu        tickEvent.schedule(curTick + latency);
6635694Sgblack@eecs.umich.edu}
6645694Sgblack@eecs.umich.edu
6655694Sgblack@eecs.umich.edu
6665694Sgblack@eecs.umich.edu////////////////////////////////////////////////////////////////////////
6675669Sgblack@eecs.umich.edu//
6685669Sgblack@eecs.umich.edu//  AtomicSimpleCPU Simulation Object
6695669Sgblack@eecs.umich.edu//
6705669Sgblack@eecs.umich.eduAtomicSimpleCPU *
6715669Sgblack@eecs.umich.eduAtomicSimpleCPUParams::create()
6725669Sgblack@eecs.umich.edu{
6735669Sgblack@eecs.umich.edu    AtomicSimpleCPU::Params *params = new AtomicSimpleCPU::Params();
6742623SN/A    params->name = name;
6755669Sgblack@eecs.umich.edu    params->numberOfThreads = 1;
6765669Sgblack@eecs.umich.edu    params->max_insts_any_thread = max_insts_any_thread;
6775669Sgblack@eecs.umich.edu    params->max_insts_all_threads = max_insts_all_threads;
6785669Sgblack@eecs.umich.edu    params->max_loads_any_thread = max_loads_any_thread;
6794968Sacolyte@umich.edu    params->max_loads_all_threads = max_loads_all_threads;
6805669Sgblack@eecs.umich.edu    params->progress_interval = progress_interval;
6814968Sacolyte@umich.edu    params->deferRegistration = defer_registration;
6825669Sgblack@eecs.umich.edu    params->phase = phase;
6835669Sgblack@eecs.umich.edu    params->clock = clock;
6845669Sgblack@eecs.umich.edu    params->functionTrace = function_trace;
6855669Sgblack@eecs.umich.edu    params->functionTraceStart = function_trace_start;
6864182Sgblack@eecs.umich.edu    params->width = width;
6872623SN/A    params->simulate_stalls = simulate_stalls;
6883814Ssaidi@eecs.umich.edu    params->system = system;
6895001Sgblack@eecs.umich.edu    params->cpu_id = cpu_id;
6904182Sgblack@eecs.umich.edu    params->tracer = tracer;
6914998Sgblack@eecs.umich.edu
6924998Sgblack@eecs.umich.edu    params->itb = itb;
6934998Sgblack@eecs.umich.edu    params->dtb = dtb;
6944998Sgblack@eecs.umich.edu#if FULL_SYSTEM
6957655Sali.saidi@arm.com    params->profile = profile;
6965001Sgblack@eecs.umich.edu    params->do_quiesce = do_quiesce;
6975001Sgblack@eecs.umich.edu    params->do_checkpoint_insts = do_checkpoint_insts;
6985001Sgblack@eecs.umich.edu    params->do_statistics_insts = do_statistics_insts;
6994998Sgblack@eecs.umich.edu#else
7004182Sgblack@eecs.umich.edu    if (workload.size() != 1)
7014182Sgblack@eecs.umich.edu        panic("only one workload allowed");
7022623SN/A    params->process = workload[0];
7033814Ssaidi@eecs.umich.edu#endif
7044539Sgblack@eecs.umich.edu
7054539Sgblack@eecs.umich.edu    AtomicSimpleCPU *cpu = new AtomicSimpleCPU(params);
7063814Ssaidi@eecs.umich.edu    return cpu;
7073814Ssaidi@eecs.umich.edu}
7085487Snate@binkert.org