atomic.cc revision 5101
11689SN/A/*
22326SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
31689SN/A * All rights reserved.
41689SN/A *
51689SN/A * Redistribution and use in source and binary forms, with or without
61689SN/A * modification, are permitted provided that the following conditions are
71689SN/A * met: redistributions of source code must retain the above copyright
81689SN/A * notice, this list of conditions and the following disclaimer;
91689SN/A * redistributions in binary form must reproduce the above copyright
101689SN/A * notice, this list of conditions and the following disclaimer in the
111689SN/A * documentation and/or other materials provided with the distribution;
121689SN/A * neither the name of the copyright holders nor the names of its
131689SN/A * contributors may be used to endorse or promote products derived from
141689SN/A * this software without specific prior written permission.
151689SN/A *
161689SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
171689SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
181689SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
191689SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
201689SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
211689SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
221689SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
231689SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
241689SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
251689SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
261689SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu *
282665Ssaidi@eecs.umich.edu * Authors: Steve Reinhardt
291689SN/A */
301689SN/A
311060SN/A#include "arch/locked_mem.hh"
321060SN/A#include "arch/mmaped_ipr.hh"
331689SN/A#include "arch/utility.hh"
341060SN/A#include "base/bigint.hh"
351060SN/A#include "cpu/exetrace.hh"
361060SN/A#include "cpu/simple/atomic.hh"
371060SN/A#include "mem/packet.hh"
382292SN/A#include "mem/packet_access.hh"
391717SN/A#include "params/AtomicSimpleCPU.hh"
401060SN/A#include "sim/system.hh"
411681SN/A
422292SN/Ausing namespace std;
432873Sktlim@umich.eduusing namespace TheISA;
441060SN/A
451061SN/AAtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c)
462292SN/A    : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
472292SN/A{
482292SN/A}
492292SN/A
502820Sktlim@umich.edu
512292SN/Avoid
522820Sktlim@umich.eduAtomicSimpleCPU::TickEvent::process()
532820Sktlim@umich.edu{
542307SN/A    cpu->tick();
552307SN/A}
561060SN/A
572292SN/Aconst char *
582292SN/AAtomicSimpleCPU::TickEvent::description()
592292SN/A{
601060SN/A    return "AtomicSimpleCPU tick";
611060SN/A}
621060SN/A
631060SN/APort *
641060SN/AAtomicSimpleCPU::getPort(const std::string &if_name, int idx)
651060SN/A{
661681SN/A    if (if_name == "dcache_port")
672292SN/A        return &dcachePort;
681681SN/A    else if (if_name == "icache_port")
692292SN/A        return &icachePort;
702292SN/A    else if (if_name == "physmem_port") {
712292SN/A        hasPhysMemPort = true;
722292SN/A        return &physmemPort;
732292SN/A    }
742935Sksewell@umich.edu    else
752292SN/A        panic("No Such Port\n");
762292SN/A}
772820Sktlim@umich.edu
782820Sktlim@umich.eduvoid
792292SN/AAtomicSimpleCPU::init()
802292SN/A{
812820Sktlim@umich.edu    BaseCPU::init();
822820Sktlim@umich.edu#if FULL_SYSTEM
832292SN/A    for (int i = 0; i < threadContexts.size(); ++i) {
842292SN/A        ThreadContext *tc = threadContexts[i];
852292SN/A
862292SN/A        // initialize CPU, including PC
872292SN/A        TheISA::initCPU(tc, tc->readCpuId());
882292SN/A    }
892292SN/A#endif
902292SN/A    if (hasPhysMemPort) {
911060SN/A        bool snoop = false;
921060SN/A        AddrRangeList pmAddrList;
931681SN/A        physmemPort.getPeerAddressRanges(pmAddrList, snoop);
941062SN/A        physMemAddr = *pmAddrList.begin();
952292SN/A    }
961062SN/A}
972301SN/A
982301SN/Abool
991062SN/AAtomicSimpleCPU::CpuPort::recvTiming(PacketPtr pkt)
1002727Sktlim@umich.edu{
1011062SN/A    panic("AtomicSimpleCPU doesn't expect recvTiming callback!");
1021062SN/A    return true;
1031062SN/A}
1041062SN/A
1051062SN/ATick
1061062SN/AAtomicSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
1071062SN/A{
1081062SN/A    //Snooping a coherence request, just return
1091062SN/A    return 0;
1101062SN/A}
1111062SN/A
1121062SN/Avoid
1131062SN/AAtomicSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
1141062SN/A{
1151062SN/A    //No internal storage to update, just return
1161062SN/A    return;
1171062SN/A}
1181062SN/A
1191062SN/Avoid
1201062SN/AAtomicSimpleCPU::CpuPort::recvStatusChange(Status status)
1211062SN/A{
1221062SN/A    if (status == RangeChange) {
1231062SN/A        if (!snoopRangeSent) {
1241062SN/A            snoopRangeSent = true;
1251062SN/A            sendStatusChange(Port::RangeChange);
1261062SN/A        }
1271062SN/A        return;
1281062SN/A    }
1291062SN/A
1301062SN/A    panic("AtomicSimpleCPU doesn't expect recvStatusChange callback!");
1311062SN/A}
1321062SN/A
1331062SN/Avoid
1341062SN/AAtomicSimpleCPU::CpuPort::recvRetry()
1351062SN/A{
1361062SN/A    panic("AtomicSimpleCPU doesn't expect recvRetry callback!");
1371062SN/A}
1381062SN/A
1391062SN/Avoid
1401062SN/AAtomicSimpleCPU::DcachePort::setPeer(Port *port)
1411062SN/A{
1422292SN/A    Port::setPeer(port);
1432292SN/A
1442292SN/A#if FULL_SYSTEM
1452292SN/A    // Update the ThreadContext's memory ports (Functional/Virtual
1461062SN/A    // Ports)
1471062SN/A    cpu->tcBase()->connectMemPorts();
1481062SN/A#endif
1491062SN/A}
1501062SN/A
1511062SN/AAtomicSimpleCPU::AtomicSimpleCPU(Params *p)
1521062SN/A    : BaseSimpleCPU(p), tickEvent(this),
1532292SN/A      width(p->width), simulate_stalls(p->simulate_stalls),
1542292SN/A      icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this),
1552292SN/A      physmemPort(name() + "-iport", this), hasPhysMemPort(false)
1562292SN/A{
1572292SN/A    _status = Idle;
1582292SN/A
1592292SN/A    icachePort.snoopRangeSent = false;
1602292SN/A    dcachePort.snoopRangeSent = false;
1612292SN/A
1622292SN/A    ifetch_req.setThreadContext(p->cpu_id, 0); // Add thread ID if we add MT
1632301SN/A    data_read_req.setThreadContext(p->cpu_id, 0); // Add thread ID here too
1642727Sktlim@umich.edu    data_write_req.setThreadContext(p->cpu_id, 0); // Add thread ID here too
1652353SN/A}
1662727Sktlim@umich.edu
1672727Sktlim@umich.edu
1682727Sktlim@umich.eduAtomicSimpleCPU::~AtomicSimpleCPU()
1692727Sktlim@umich.edu{
1702353SN/A}
1712727Sktlim@umich.edu
1722727Sktlim@umich.eduvoid
1732727Sktlim@umich.eduAtomicSimpleCPU::serialize(ostream &os)
1742727Sktlim@umich.edu{
1752353SN/A    SimObject::State so_state = SimObject::getState();
1762727Sktlim@umich.edu    SERIALIZE_ENUM(so_state);
1772727Sktlim@umich.edu    Status _status = status();
1782727Sktlim@umich.edu    SERIALIZE_ENUM(_status);
1792301SN/A    BaseSimpleCPU::serialize(os);
1802301SN/A    nameOut(os, csprintf("%s.tickEvent", name()));
1812301SN/A    tickEvent.serialize(os);
1822727Sktlim@umich.edu}
1832301SN/A
1842727Sktlim@umich.eduvoid
1852301SN/AAtomicSimpleCPU::unserialize(Checkpoint *cp, const string &section)
1862301SN/A{
1872301SN/A    SimObject::State so_state;
1882727Sktlim@umich.edu    UNSERIALIZE_ENUM(so_state);
1892301SN/A    UNSERIALIZE_ENUM(_status);
1902727Sktlim@umich.edu    BaseSimpleCPU::unserialize(cp, section);
1912301SN/A    tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
1922301SN/A}
1932301SN/A
1942727Sktlim@umich.eduvoid
1952301SN/AAtomicSimpleCPU::resume()
1962727Sktlim@umich.edu{
1972301SN/A    DPRINTF(SimpleCPU, "Resume\n");
1982301SN/A    if (_status != SwitchedOut && _status != Idle) {
1992301SN/A        assert(system->getMemoryMode() == Enums::atomic);
2002727Sktlim@umich.edu
2012301SN/A        changeState(SimObject::Running);
2022301SN/A        if (thread->status() == ThreadContext::Active) {
2032301SN/A            if (!tickEvent.scheduled()) {
2042301SN/A                tickEvent.schedule(nextCycle());
2052727Sktlim@umich.edu            }
2062727Sktlim@umich.edu        }
2072727Sktlim@umich.edu    }
2082727Sktlim@umich.edu}
2092727Sktlim@umich.edu
2102727Sktlim@umich.eduvoid
2112727Sktlim@umich.eduAtomicSimpleCPU::switchOut()
2122727Sktlim@umich.edu{
2132727Sktlim@umich.edu    assert(status() == Running || status() == Idle);
2142301SN/A    _status = SwitchedOut;
2152301SN/A
2162301SN/A    tickEvent.squash();
2172301SN/A}
2182301SN/A
2192727Sktlim@umich.edu
2202301SN/Avoid
2212326SN/AAtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
2222301SN/A{
2232301SN/A    BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
2242301SN/A
2252727Sktlim@umich.edu    assert(!tickEvent.scheduled());
2262301SN/A
2272326SN/A    // if any of this CPU's ThreadContexts are active, mark the CPU as
2282301SN/A    // running and schedule its tick event.
2292301SN/A    for (int i = 0; i < threadContexts.size(); ++i) {
2302301SN/A        ThreadContext *tc = threadContexts[i];
2312727Sktlim@umich.edu        if (tc->status() == ThreadContext::Active && _status != Running) {
2322301SN/A            _status = Running;
2332326SN/A            tickEvent.schedule(nextCycle());
2342301SN/A            break;
2352301SN/A        }
2362301SN/A    }
2372727Sktlim@umich.edu    if (_status != Running) {
2382301SN/A        _status = Idle;
2392326SN/A    }
2402301SN/A}
2412301SN/A
2422301SN/A
2432727Sktlim@umich.eduvoid
2442301SN/AAtomicSimpleCPU::activateContext(int thread_num, int delay)
2452326SN/A{
2462301SN/A    DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay);
2472301SN/A
2482727Sktlim@umich.edu    assert(thread_num == 0);
2492301SN/A    assert(thread);
2502326SN/A
2512301SN/A    assert(_status == Idle);
2522326SN/A    assert(!tickEvent.scheduled());
2532301SN/A
2542301SN/A    notIdleFraction++;
2552727Sktlim@umich.edu    numCycles += tickToCycles(thread->lastActivate - thread->lastSuspend);
2562301SN/A
2572326SN/A    //Make sure ticks are still on multiples of cycles
2582301SN/A    tickEvent.schedule(nextCycle(curTick + ticks(delay)));
2592326SN/A    _status = Running;
2602301SN/A}
2612301SN/A
2622727Sktlim@umich.edu
2632326SN/Avoid
2641062SN/AAtomicSimpleCPU::suspendContext(int thread_num)
2651062SN/A{
2661681SN/A    DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
2671060SN/A
2682292SN/A    assert(thread_num == 0);
2691060SN/A    assert(thread);
2702292SN/A
2712292SN/A    assert(_status == Running);
2722292SN/A
2732292SN/A    // tick event may not be scheduled if this gets called from inside
2742292SN/A    // an instruction's execution, e.g. "quiesce"
2752292SN/A    if (tickEvent.scheduled())
2762292SN/A        tickEvent.deschedule();
2772292SN/A
2782292SN/A    notIdleFraction--;
2792292SN/A    _status = Idle;
2802292SN/A}
2812292SN/A
2822292SN/A
2832733Sktlim@umich.edutemplate <class T>
2842292SN/AFault
2852292SN/AAtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
2861060SN/A{
2871060SN/A    // use the CPU's statically allocated read request and packet objects
2881060SN/A    Request *req = &data_read_req;
2891061SN/A
2902292SN/A    if (traceData) {
2912733Sktlim@umich.edu        traceData->setAddr(addr);
2921060SN/A    }
2931060SN/A
2941681SN/A    //The block size of our peer.
2951060SN/A    int blockSize = dcachePort.peerBlockSize();
2962292SN/A    //The size of the data we're trying to read.
2971060SN/A    int dataSize = sizeof(T);
2982292SN/A
2991060SN/A    uint8_t * dataPtr = (uint8_t *)&data;
3001060SN/A
3011060SN/A    //The address of the second part of this access if it needs to be split
3021060SN/A    //across a cache line boundary.
3031060SN/A    Addr secondAddr = roundDown(addr + dataSize - 1, blockSize);
3041060SN/A
3051060SN/A    if(secondAddr > addr)
3061060SN/A        dataSize = secondAddr - addr;
3072292SN/A
3082292SN/A    dcache_latency = 0;
3091060SN/A
3101060SN/A    while(1) {
3111060SN/A        req->setVirt(0, addr, dataSize, flags, thread->readPC());
3121060SN/A
3131681SN/A        // translate to physical address
3141060SN/A        Fault fault = thread->translateDataReadReq(req);
3152292SN/A
3161060SN/A        // Now do the access.
3172292SN/A        if (fault == NoFault) {
3181060SN/A            Packet pkt = Packet(req,
3191060SN/A                    req->isLocked() ? MemCmd::LoadLockedReq : MemCmd::ReadReq,
3201060SN/A                    Packet::Broadcast);
3211060SN/A            pkt.dataStatic(dataPtr);
3221060SN/A
3231060SN/A            if (req->isMmapedIpr())
3241681SN/A                dcache_latency += TheISA::handleIprRead(thread->getTC(), &pkt);
3251060SN/A            else {
3262292SN/A                if (hasPhysMemPort && pkt.getAddr() == physMemAddr)
3271060SN/A                    dcache_latency += physmemPort.sendAtomic(&pkt);
3282292SN/A                else
3291060SN/A                    dcache_latency += dcachePort.sendAtomic(&pkt);
3301060SN/A            }
3311060SN/A            dcache_access = true;
3321060SN/A
3331060SN/A            assert(!pkt.isError());
3341060SN/A
3351681SN/A            if (req->isLocked()) {
3361060SN/A                TheISA::handleLockedRead(thread, req);
3372980Sgblack@eecs.umich.edu            }
3381060SN/A        }
3392292SN/A
3402292SN/A        // This will need a new way to tell if it has a dcache attached.
3412292SN/A        if (req->isUncacheable())
3422292SN/A            recordEvent("Uncached Read");
3432292SN/A
3441060SN/A        //If there's a fault, return it
3451060SN/A        if (fault != NoFault)
3461681SN/A            return fault;
3471060SN/A        //If we don't need to access a second cache line, stop now.
3482292SN/A        if (secondAddr <= addr)
3491060SN/A        {
3502292SN/A            data = gtoh(data);
3512292SN/A            return fault;
3521060SN/A        }
3531060SN/A
3542307SN/A        /*
3552863Sktlim@umich.edu         * Set up for accessing the second cache line.
3562843Sktlim@umich.edu         */
3572307SN/A
3582843Sktlim@umich.edu        //Move the pointer we're reading into to the correct location.
3592843Sktlim@umich.edu        dataPtr += dataSize;
3602863Sktlim@umich.edu        //Adjust the size to get the remaining bytes.
3611681SN/A        dataSize = addr + sizeof(T) - secondAddr;
3621681SN/A        //And access the right address.
3632316SN/A        addr = secondAddr;
3641681SN/A    }
3652843Sktlim@umich.edu}
3662843Sktlim@umich.edu
3672843Sktlim@umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS
3682843Sktlim@umich.edu
3692843Sktlim@umich.edutemplate
3702843Sktlim@umich.eduFault
3712843Sktlim@umich.eduAtomicSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags);
3721681SN/A
3732348SN/Atemplate
3742307SN/AFault
3752367SN/AAtomicSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags);
3762367SN/A
3771681SN/Atemplate
3782307SN/AFault
3792307SN/AAtomicSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
3802307SN/A
3812307SN/Atemplate
3822307SN/AFault
3832307SN/AAtomicSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
3842307SN/A
3852307SN/Atemplate
3862307SN/AFault
3872307SN/AAtomicSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
3881681SN/A
3891681SN/Atemplate
3902307SN/AFault
3911681SN/AAtomicSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
3922307SN/A
3931060SN/A#endif //DOXYGEN_SHOULD_SKIP_THIS
3942348SN/A
3952307SN/Atemplate<>
3962307SN/AFault
3972307SN/AAtomicSimpleCPU::read(Addr addr, double &data, unsigned flags)
3982307SN/A{
3991060SN/A    return read(addr, *(uint64_t*)&data, flags);
4002307SN/A}
4012307SN/A
4022307SN/Atemplate<>
4031060SN/AFault
4042307SN/AAtomicSimpleCPU::read(Addr addr, float &data, unsigned flags)
4052307SN/A{
4061060SN/A    return read(addr, *(uint32_t*)&data, flags);
4072307SN/A}
4082307SN/A
4092307SN/A
4102307SN/Atemplate<>
4112307SN/AFault
4121060SN/AAtomicSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
4132307SN/A{
4142307SN/A    return read(addr, (uint32_t&)data, flags);
4152873Sktlim@umich.edu}
4162307SN/A
4171060SN/A
4181060SN/Atemplate <class T>
4191060SN/AFault
4201681SN/AAtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
4211060SN/A{
4222292SN/A    // use the CPU's statically allocated write request and packet objects
4232107SN/A    Request *req = &data_write_req;
4242292SN/A
4252292SN/A    if (traceData) {
4262107SN/A        traceData->setAddr(addr);
4272292SN/A    }
4282292SN/A
4292107SN/A    //The block size of our peer.
4302292SN/A    int blockSize = dcachePort.peerBlockSize();
4313093Sksewell@umich.edu    //The size of the data we're trying to read.
4323093Sksewell@umich.edu    int dataSize = sizeof(T);
4333093Sksewell@umich.edu
4342326SN/A    uint8_t * dataPtr = (uint8_t *)&data;
4352935Sksewell@umich.edu
4362292SN/A    //The address of the second part of this access if it needs to be split
4372107SN/A    //across a cache line boundary.
4382292SN/A    Addr secondAddr = roundDown(addr + dataSize - 1, blockSize);
4392935Sksewell@umich.edu
4402935Sksewell@umich.edu    if(secondAddr > addr)
4412935Sksewell@umich.edu        dataSize = secondAddr - addr;
4422292SN/A
4433093Sksewell@umich.edu    dcache_latency = 0;
4442935Sksewell@umich.edu
4452935Sksewell@umich.edu    while(1) {
4462935Sksewell@umich.edu        req->setVirt(0, addr, dataSize, flags, thread->readPC());
4472935Sksewell@umich.edu
4482935Sksewell@umich.edu        // translate to physical address
4492935Sksewell@umich.edu        Fault fault = thread->translateDataWriteReq(req);
4502935Sksewell@umich.edu
4512935Sksewell@umich.edu        // Now do the access.
4522935Sksewell@umich.edu        if (fault == NoFault) {
4532935Sksewell@umich.edu            MemCmd cmd = MemCmd::WriteReq; // default
4542935Sksewell@umich.edu            bool do_access = true;  // flag to suppress cache access
4552935Sksewell@umich.edu
4562292SN/A            if (req->isLocked()) {
4572292SN/A                cmd = MemCmd::StoreCondReq;
4582292SN/A                do_access = TheISA::handleLockedWrite(thread, req);
4592292SN/A            } else if (req->isSwap()) {
4602107SN/A                cmd = MemCmd::SwapReq;
4612292SN/A                if (req->isCondSwap()) {
4622107SN/A                    assert(res);
4632292SN/A                    req->setExtraData(*res);
4642292SN/A                }
4652107SN/A            }
4662935Sksewell@umich.edu
4672935Sksewell@umich.edu            if (do_access) {
4682702Sktlim@umich.edu                Packet pkt = Packet(req, cmd, Packet::Broadcast);
4692107SN/A                pkt.dataStatic(dataPtr);
4702107SN/A
4712107SN/A                if (req->isMmapedIpr()) {
4722107SN/A                    dcache_latency +=
4732292SN/A                        TheISA::handleIprWrite(thread->getTC(), &pkt);
4742292SN/A                } else {
4752292SN/A                    //XXX This needs to be outside of the loop in order to
4762292SN/A                    //work properly for cache line boundary crossing
4772292SN/A                    //accesses in transendian simulations.
4782292SN/A                    data = htog(data);
4792292SN/A                    if (hasPhysMemPort && pkt.getAddr() == physMemAddr)
4802292SN/A                        dcache_latency += physmemPort.sendAtomic(&pkt);
4812292SN/A                    else
4822935Sksewell@umich.edu                        dcache_latency += dcachePort.sendAtomic(&pkt);
4833093Sksewell@umich.edu                }
4842935Sksewell@umich.edu                dcache_access = true;
4852935Sksewell@umich.edu                assert(!pkt.isError());
4862935Sksewell@umich.edu
4872935Sksewell@umich.edu                if (req->isSwap()) {
4882935Sksewell@umich.edu                    assert(res);
4892935Sksewell@umich.edu                    *res = pkt.get<T>();
4902935Sksewell@umich.edu                }
4912935Sksewell@umich.edu            }
4922935Sksewell@umich.edu
4932935Sksewell@umich.edu            if (res && !req->isSwap()) {
4942935Sksewell@umich.edu                *res = req->getExtraData();
4952935Sksewell@umich.edu            }
4963093Sksewell@umich.edu        }
4973093Sksewell@umich.edu
4983093Sksewell@umich.edu        // This will need a new way to tell if it's hooked up to a cache or not.
4993093Sksewell@umich.edu        if (req->isUncacheable())
5002935Sksewell@umich.edu            recordEvent("Uncached Write");
5012292SN/A
5022292SN/A        //If there's a fault or we don't need to access a second cache line,
5032292SN/A        //stop now.
5042292SN/A        if (fault != NoFault || secondAddr <= addr)
5052292SN/A        {
5062292SN/A            // If the write needs to have a fault on the access, consider
5072292SN/A            // calling changeStatus() and changing it to "bad addr write"
5082292SN/A            // or something.
5092292SN/A            return fault;
5102292SN/A        }
5112292SN/A
5122292SN/A        /*
5132292SN/A         * Set up for accessing the second cache line.
5142292SN/A         */
5152292SN/A
5162292SN/A        //Move the pointer we're reading into to the correct location.
5173732Sktlim@umich.edu        dataPtr += dataSize;
5182292SN/A        //Adjust the size to get the remaining bytes.
5192292SN/A        dataSize = addr + sizeof(T) - secondAddr;
5202292SN/A        //And access the right address.
5212292SN/A        addr = secondAddr;
5222292SN/A    }
5232292SN/A}
5242292SN/A
5252292SN/A
5262292SN/A#ifndef DOXYGEN_SHOULD_SKIP_THIS
5272292SN/A
5282292SN/Atemplate
5292292SN/AFault
5302292SN/AAtomicSimpleCPU::write(Twin32_t data, Addr addr,
5312292SN/A                       unsigned flags, uint64_t *res);
5322292SN/A
5332292SN/Atemplate
5343732Sktlim@umich.eduFault
5352292SN/AAtomicSimpleCPU::write(Twin64_t data, Addr addr,
5362348SN/A                       unsigned flags, uint64_t *res);
5372292SN/A
5382292SN/Atemplate
5392292SN/AFault
5402292SN/AAtomicSimpleCPU::write(uint64_t data, Addr addr,
5412292SN/A                       unsigned flags, uint64_t *res);
5422292SN/A
5432292SN/Atemplate
5442292SN/AFault
5452292SN/AAtomicSimpleCPU::write(uint32_t data, Addr addr,
5462292SN/A                       unsigned flags, uint64_t *res);
5472292SN/A
5482292SN/Atemplate
5492292SN/AFault
5502292SN/AAtomicSimpleCPU::write(uint16_t data, Addr addr,
5512292SN/A                       unsigned flags, uint64_t *res);
5522292SN/A
5532292SN/Atemplate
5542292SN/AFault
5552292SN/AAtomicSimpleCPU::write(uint8_t data, Addr addr,
5562292SN/A                       unsigned flags, uint64_t *res);
5572292SN/A
5582292SN/A#endif //DOXYGEN_SHOULD_SKIP_THIS
5592292SN/A
5602292SN/Atemplate<>
5612292SN/AFault
5622292SN/AAtomicSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
5632292SN/A{
5642292SN/A    return write(*(uint64_t*)&data, addr, flags, res);
5652292SN/A}
5662292SN/A
5672292SN/Atemplate<>
5682292SN/AFault
5692292SN/AAtomicSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
5702292SN/A{
5712292SN/A    return write(*(uint32_t*)&data, addr, flags, res);
5722292SN/A}
5732292SN/A
5742292SN/A
5752292SN/Atemplate<>
5762292SN/AFault
5772292SN/AAtomicSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
5782292SN/A{
5792292SN/A    return write((uint32_t)data, addr, flags, res);
5802292SN/A}
5812292SN/A
5822292SN/A
5831060SN/Avoid
5841681SN/AAtomicSimpleCPU::tick()
5851060SN/A{
5861060SN/A    DPRINTF(SimpleCPU, "Tick\n");
5872292SN/A
5882292SN/A    Tick latency = ticks(1); // instruction takes one cycle by default
5892292SN/A
5902292SN/A    for (int i = 0; i < width; ++i) {
5912292SN/A        numCycles++;
5922292SN/A
5931681SN/A        if (!curStaticInst || !curStaticInst->isDelayedCommit())
5941681SN/A            checkForInterrupts();
5951060SN/A
5962292SN/A        Fault fault = setupFetchRequest(&ifetch_req);
5971060SN/A
5982292SN/A        if (fault == NoFault) {
5992292SN/A            Tick icache_latency = 0;
6001060SN/A            bool icache_access = false;
6012292SN/A            dcache_access = false; // assume no dcache access
6022292SN/A
6032292SN/A            //Fetch more instruction memory if necessary
6042292SN/A            //if(predecoder.needMoreBytes())
6053221Sktlim@umich.edu            //{
6063221Sktlim@umich.edu                icache_access = true;
6073221Sktlim@umich.edu                Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq,
6083221Sktlim@umich.edu                                           Packet::Broadcast);
6093221Sktlim@umich.edu                ifetch_pkt.dataStatic(&inst);
6102292SN/A
6112292SN/A                if (hasPhysMemPort && ifetch_pkt.getAddr() == physMemAddr)
6122292SN/A                    icache_latency = physmemPort.sendAtomic(&ifetch_pkt);
6132292SN/A                else
6142326SN/A                    icache_latency = icachePort.sendAtomic(&ifetch_pkt);
6152292SN/A
6162292SN/A                assert(!ifetch_pkt.isError());
6172820Sktlim@umich.edu
6182292SN/A                // ifetch_req is initialized to read the instruction directly
6192292SN/A                // into the CPU object's inst field.
6202292SN/A            //}
6212292SN/A
6222353SN/A            preExecute();
6232292SN/A
6242292SN/A            if (curStaticInst) {
6252353SN/A                fault = curStaticInst->execute(this, traceData);
6262353SN/A
6272292SN/A                // keep an instruction count
6282292SN/A                if (fault == NoFault)
6292292SN/A                    countInst();
6302292SN/A                else if (traceData) {
6312292SN/A                    // If there was a fault, we should trace this instruction.
6322292SN/A                    delete traceData;
6332292SN/A                    traceData = NULL;
6342292SN/A                }
6352292SN/A
6362292SN/A                postExecute();
6372292SN/A            }
6382292SN/A
6392731Sktlim@umich.edu            // @todo remove me after debugging with legion done
6402292SN/A            if (curStaticInst && (!curStaticInst->isMicroop() ||
6412292SN/A                        curStaticInst->isFirstMicroop()))
6422292SN/A                instCnt++;
6432292SN/A
6442292SN/A            if (simulate_stalls) {
6452292SN/A                Tick icache_stall =
6462292SN/A                    icache_access ? icache_latency - ticks(1) : 0;
6472292SN/A                Tick dcache_stall =
6482292SN/A                    dcache_access ? dcache_latency - ticks(1) : 0;
6492292SN/A                Tick stall_cycles = (icache_stall + dcache_stall) / ticks(1);
6502292SN/A                if (ticks(stall_cycles) < (icache_stall + dcache_stall))
6512292SN/A                    latency += ticks(stall_cycles+1);
6522292SN/A                else
6532292SN/A                    latency += ticks(stall_cycles);
6542292SN/A            }
6552292SN/A
6562292SN/A        }
6572292SN/A        if(fault != NoFault || !stayAtPC)
6582292SN/A            advancePC(fault);
6592292SN/A    }
6602292SN/A
6612292SN/A    if (_status != Idle)
6622292SN/A        tickEvent.schedule(curTick + latency);
6632292SN/A}
6642292SN/A
6652292SN/A
6662292SN/A////////////////////////////////////////////////////////////////////////
6672292SN/A//
6682292SN/A//  AtomicSimpleCPU Simulation Object
6692292SN/A//
6702292SN/AAtomicSimpleCPU *
6712292SN/AAtomicSimpleCPUParams::create()
6722292SN/A{
6732292SN/A    AtomicSimpleCPU::Params *params = new AtomicSimpleCPU::Params();
6742980Sgblack@eecs.umich.edu    params->name = name;
6752292SN/A    params->numberOfThreads = 1;
6762292SN/A    params->max_insts_any_thread = max_insts_any_thread;
6772292SN/A    params->max_insts_all_threads = max_insts_all_threads;
6782292SN/A    params->max_loads_any_thread = max_loads_any_thread;
6792292SN/A    params->max_loads_all_threads = max_loads_all_threads;
6802292SN/A    params->progress_interval = progress_interval;
6812292SN/A    params->deferRegistration = defer_registration;
6822292SN/A    params->phase = phase;
6832292SN/A    params->clock = clock;
6842292SN/A    params->functionTrace = function_trace;
6852292SN/A    params->functionTraceStart = function_trace_start;
6862292SN/A    params->width = width;
6872292SN/A    params->simulate_stalls = simulate_stalls;
6882292SN/A    params->system = system;
6892980Sgblack@eecs.umich.edu    params->cpu_id = cpu_id;
6902292SN/A    params->tracer = tracer;
6912292SN/A
6922292SN/A    params->itb = itb;
6932292SN/A    params->dtb = dtb;
6942292SN/A#if FULL_SYSTEM
6952292SN/A    params->profile = profile;
6962292SN/A    params->do_quiesce = do_quiesce;
6971062SN/A    params->do_checkpoint_insts = do_checkpoint_insts;
6981062SN/A    params->do_statistics_insts = do_statistics_insts;
6991681SN/A#else
7001062SN/A    if (workload.size() != 1)
7012292SN/A        panic("only one workload allowed");
7021062SN/A    params->process = workload[0];
7032292SN/A#endif
7041062SN/A
7052980Sgblack@eecs.umich.edu    AtomicSimpleCPU *cpu = new AtomicSimpleCPU(params);
7061062SN/A    return cpu;
7072292SN/A}
7081062SN/A