atomic.cc revision 7720
15347Ssaidi@eecs.umich.edu/*
23395Shsul@eecs.umich.edu * Copyright (c) 2002-2005 The Regents of The University of Michigan
33395Shsul@eecs.umich.edu * All rights reserved.
43395Shsul@eecs.umich.edu *
53395Shsul@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
63395Shsul@eecs.umich.edu * modification, are permitted provided that the following conditions are
73395Shsul@eecs.umich.edu * met: redistributions of source code must retain the above copyright
83395Shsul@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
93395Shsul@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
103395Shsul@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
113395Shsul@eecs.umich.edu * documentation and/or other materials provided with the distribution;
123395Shsul@eecs.umich.edu * neither the name of the copyright holders nor the names of its
133395Shsul@eecs.umich.edu * contributors may be used to endorse or promote products derived from
143395Shsul@eecs.umich.edu * this software without specific prior written permission.
153395Shsul@eecs.umich.edu *
163395Shsul@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
173395Shsul@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
183395Shsul@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
193395Shsul@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
203395Shsul@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
213395Shsul@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
223395Shsul@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
233395Shsul@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
243395Shsul@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
253395Shsul@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
263395Shsul@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273395Shsul@eecs.umich.edu *
283395Shsul@eecs.umich.edu * Authors: Steve Reinhardt
293395Shsul@eecs.umich.edu */
303509Shsul@eecs.umich.edu
313395Shsul@eecs.umich.edu#include "arch/locked_mem.hh"
323395Shsul@eecs.umich.edu#include "arch/mmaped_ipr.hh"
333395Shsul@eecs.umich.edu#include "arch/utility.hh"
343448Shsul@eecs.umich.edu#include "base/bigint.hh"
353395Shsul@eecs.umich.edu#include "config/the_isa.hh"
363481Shsul@eecs.umich.edu#include "cpu/exetrace.hh"
373481Shsul@eecs.umich.edu#include "cpu/simple/atomic.hh"
383481Shsul@eecs.umich.edu#include "mem/packet.hh"
393481Shsul@eecs.umich.edu#include "mem/packet_access.hh"
405347Ssaidi@eecs.umich.edu#include "params/AtomicSimpleCPU.hh"
413481Shsul@eecs.umich.edu#include "sim/faults.hh"
423681Sktlim@umich.edu#include "sim/system.hh"
433681Sktlim@umich.edu
443681Sktlim@umich.eduusing namespace std;
455347Ssaidi@eecs.umich.eduusing namespace TheISA;
463481Shsul@eecs.umich.edu
475347Ssaidi@eecs.umich.eduAtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c)
483481Shsul@eecs.umich.edu    : Event(CPU_Tick_Pri), cpu(c)
493481Shsul@eecs.umich.edu{
503481Shsul@eecs.umich.edu}
513481Shsul@eecs.umich.edu
523481Shsul@eecs.umich.edu
533481Shsul@eecs.umich.eduvoid
545369Ssaidi@eecs.umich.eduAtomicSimpleCPU::TickEvent::process()
553481Shsul@eecs.umich.edu{
565347Ssaidi@eecs.umich.edu    cpu->tick();
573481Shsul@eecs.umich.edu}
583481Shsul@eecs.umich.edu
593481Shsul@eecs.umich.educonst char *
603481Shsul@eecs.umich.eduAtomicSimpleCPU::TickEvent::description() const
613481Shsul@eecs.umich.edu{
623481Shsul@eecs.umich.edu    return "AtomicSimpleCPU tick";
633481Shsul@eecs.umich.edu}
643395Shsul@eecs.umich.edu
653395Shsul@eecs.umich.eduPort *
663395Shsul@eecs.umich.eduAtomicSimpleCPU::getPort(const string &if_name, int idx)
674167Sbinkertn@umich.edu{
683395Shsul@eecs.umich.edu    if (if_name == "dcache_port")
693395Shsul@eecs.umich.edu        return &dcachePort;
703395Shsul@eecs.umich.edu    else if (if_name == "icache_port")
713511Shsul@eecs.umich.edu        return &icachePort;
723395Shsul@eecs.umich.edu    else if (if_name == "physmem_port") {
733395Shsul@eecs.umich.edu        hasPhysMemPort = true;
743395Shsul@eecs.umich.edu        return &physmemPort;
755211Ssaidi@eecs.umich.edu    }
765211Ssaidi@eecs.umich.edu    else
773395Shsul@eecs.umich.edu        panic("No Such Port\n");
783395Shsul@eecs.umich.edu}
793395Shsul@eecs.umich.edu
805370Ssaidi@eecs.umich.eduvoid
815370Ssaidi@eecs.umich.eduAtomicSimpleCPU::init()
825370Ssaidi@eecs.umich.edu{
835370Ssaidi@eecs.umich.edu    BaseCPU::init();
845370Ssaidi@eecs.umich.edu#if FULL_SYSTEM
855370Ssaidi@eecs.umich.edu    ThreadID size = threadContexts.size();
863395Shsul@eecs.umich.edu    for (ThreadID i = 0; i < size; ++i) {
873395Shsul@eecs.umich.edu        ThreadContext *tc = threadContexts[i];
883481Shsul@eecs.umich.edu
893481Shsul@eecs.umich.edu        // initialize CPU, including PC
903481Shsul@eecs.umich.edu        TheISA::initCPU(tc, tc->contextId());
913481Shsul@eecs.umich.edu    }
923481Shsul@eecs.umich.edu#endif
933481Shsul@eecs.umich.edu    if (hasPhysMemPort) {
943481Shsul@eecs.umich.edu        bool snoop = false;
955361Srstrong@cs.ucsd.edu        AddrRangeList pmAddrList;
965369Ssaidi@eecs.umich.edu        physmemPort.getPeerAddressRanges(pmAddrList, snoop);
973481Shsul@eecs.umich.edu        physMemAddr = *pmAddrList.begin();
983481Shsul@eecs.umich.edu    }
993481Shsul@eecs.umich.edu    // Atomic doesn't do MT right now, so contextId == threadId
1003481Shsul@eecs.umich.edu    ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT
1015369Ssaidi@eecs.umich.edu    data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too
1025369Ssaidi@eecs.umich.edu    data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too
1035369Ssaidi@eecs.umich.edu}
1043481Shsul@eecs.umich.edu
1055311Ssaidi@eecs.umich.edubool
1063481Shsul@eecs.umich.eduAtomicSimpleCPU::CpuPort::recvTiming(PacketPtr pkt)
1073395Shsul@eecs.umich.edu{
1083395Shsul@eecs.umich.edu    panic("AtomicSimpleCPU doesn't expect recvTiming callback!");
1093395Shsul@eecs.umich.edu    return true;
1103395Shsul@eecs.umich.edu}
1113478Shsul@eecs.umich.edu
1123395Shsul@eecs.umich.eduTick
1133478Shsul@eecs.umich.eduAtomicSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
1143395Shsul@eecs.umich.edu{
1153395Shsul@eecs.umich.edu    //Snooping a coherence request, just return
1163478Shsul@eecs.umich.edu    return 0;
1173395Shsul@eecs.umich.edu}
1183395Shsul@eecs.umich.edu
1193478Shsul@eecs.umich.eduvoid
1203395Shsul@eecs.umich.eduAtomicSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
1213478Shsul@eecs.umich.edu{
1223480Shsul@eecs.umich.edu    //No internal storage to update, just return
1235361Srstrong@cs.ucsd.edu    return;
1245369Ssaidi@eecs.umich.edu}
1255361Srstrong@cs.ucsd.edu
1265361Srstrong@cs.ucsd.eduvoid
1275361Srstrong@cs.ucsd.eduAtomicSimpleCPU::CpuPort::recvStatusChange(Status status)
1285369Ssaidi@eecs.umich.edu{
1295361Srstrong@cs.ucsd.edu    if (status == RangeChange) {
1305361Srstrong@cs.ucsd.edu        if (!snoopRangeSent) {
1315361Srstrong@cs.ucsd.edu            snoopRangeSent = true;
1325361Srstrong@cs.ucsd.edu            sendStatusChange(Port::RangeChange);
1335361Srstrong@cs.ucsd.edu        }
1345361Srstrong@cs.ucsd.edu        return;
1355361Srstrong@cs.ucsd.edu    }
1365361Srstrong@cs.ucsd.edu
1375361Srstrong@cs.ucsd.edu    panic("AtomicSimpleCPU doesn't expect recvStatusChange callback!");
1385361Srstrong@cs.ucsd.edu}
1395361Srstrong@cs.ucsd.edu
1405361Srstrong@cs.ucsd.eduvoid
1415361Srstrong@cs.ucsd.eduAtomicSimpleCPU::CpuPort::recvRetry()
1425361Srstrong@cs.ucsd.edu{
1435361Srstrong@cs.ucsd.edu    panic("AtomicSimpleCPU doesn't expect recvRetry callback!");
1445353Svilas.sridharan@gmail.com}
1455353Svilas.sridharan@gmail.com
1465353Svilas.sridharan@gmail.comvoid
1473514Sktlim@umich.eduAtomicSimpleCPU::DcachePort::setPeer(Port *port)
1483481Shsul@eecs.umich.edu{
1493480Shsul@eecs.umich.edu    Port::setPeer(port);
1503480Shsul@eecs.umich.edu
1513480Shsul@eecs.umich.edu#if FULL_SYSTEM
1523395Shsul@eecs.umich.edu    // Update the ThreadContext's memory ports (Functional/Virtual
1533514Sktlim@umich.edu    // Ports)
1543514Sktlim@umich.edu    cpu->tcBase()->connectMemPorts(cpu->tcBase());
1553395Shsul@eecs.umich.edu#endif
1563478Shsul@eecs.umich.edu}
1573395Shsul@eecs.umich.edu
1585361Srstrong@cs.ucsd.eduAtomicSimpleCPU::AtomicSimpleCPU(AtomicSimpleCPUParams *p)
1595369Ssaidi@eecs.umich.edu    : BaseSimpleCPU(p), tickEvent(this), width(p->width), locked(false),
1605361Srstrong@cs.ucsd.edu      simulate_data_stalls(p->simulate_data_stalls),
1615361Srstrong@cs.ucsd.edu      simulate_inst_stalls(p->simulate_inst_stalls),
1625361Srstrong@cs.ucsd.edu      icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this),
1635361Srstrong@cs.ucsd.edu      physmemPort(name() + "-iport", this), hasPhysMemPort(false)
1645361Srstrong@cs.ucsd.edu{
1655361Srstrong@cs.ucsd.edu    _status = Idle;
1665361Srstrong@cs.ucsd.edu
1675369Ssaidi@eecs.umich.edu    icachePort.snoopRangeSent = false;
1685361Srstrong@cs.ucsd.edu    dcachePort.snoopRangeSent = false;
1695361Srstrong@cs.ucsd.edu
1705361Srstrong@cs.ucsd.edu}
1715361Srstrong@cs.ucsd.edu
1725361Srstrong@cs.ucsd.edu
1735361Srstrong@cs.ucsd.eduAtomicSimpleCPU::~AtomicSimpleCPU()
1745361Srstrong@cs.ucsd.edu{
1755361Srstrong@cs.ucsd.edu    if (tickEvent.scheduled()) {
1765361Srstrong@cs.ucsd.edu        deschedule(tickEvent);
1775361Srstrong@cs.ucsd.edu    }
1783395Shsul@eecs.umich.edu}
1793395Shsul@eecs.umich.edu
1805369Ssaidi@eecs.umich.eduvoid
1815361Srstrong@cs.ucsd.eduAtomicSimpleCPU::serialize(ostream &os)
1823395Shsul@eecs.umich.edu{
1833395Shsul@eecs.umich.edu    SimObject::State so_state = SimObject::getState();
1843395Shsul@eecs.umich.edu    SERIALIZE_ENUM(so_state);
1853395Shsul@eecs.umich.edu    SERIALIZE_SCALAR(locked);
1863395Shsul@eecs.umich.edu    BaseSimpleCPU::serialize(os);
1873395Shsul@eecs.umich.edu    nameOut(os, csprintf("%s.tickEvent", name()));
1885361Srstrong@cs.ucsd.edu    tickEvent.serialize(os);
1895361Srstrong@cs.ucsd.edu}
1905361Srstrong@cs.ucsd.edu
1915361Srstrong@cs.ucsd.eduvoid
1925361Srstrong@cs.ucsd.eduAtomicSimpleCPU::unserialize(Checkpoint *cp, const string &section)
1935361Srstrong@cs.ucsd.edu{
1943395Shsul@eecs.umich.edu    SimObject::State so_state;
1955361Srstrong@cs.ucsd.edu    UNSERIALIZE_ENUM(so_state);
1965361Srstrong@cs.ucsd.edu    UNSERIALIZE_SCALAR(locked);
1975361Srstrong@cs.ucsd.edu    BaseSimpleCPU::unserialize(cp, section);
1985361Srstrong@cs.ucsd.edu    tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
1995361Srstrong@cs.ucsd.edu}
2005369Ssaidi@eecs.umich.edu
2015361Srstrong@cs.ucsd.eduvoid
2023395Shsul@eecs.umich.eduAtomicSimpleCPU::resume()
2035361Srstrong@cs.ucsd.edu{
2045369Ssaidi@eecs.umich.edu    if (_status == Idle || _status == SwitchedOut)
2053395Shsul@eecs.umich.edu        return;
2065361Srstrong@cs.ucsd.edu
2075361Srstrong@cs.ucsd.edu    DPRINTF(SimpleCPU, "Resume\n");
2085361Srstrong@cs.ucsd.edu    assert(system->getMemoryMode() == Enums::atomic);
2095361Srstrong@cs.ucsd.edu
2105361Srstrong@cs.ucsd.edu    changeState(SimObject::Running);
2113395Shsul@eecs.umich.edu    if (thread->status() == ThreadContext::Active) {
2125361Srstrong@cs.ucsd.edu        if (!tickEvent.scheduled())
2135361Srstrong@cs.ucsd.edu            schedule(tickEvent, nextCycle());
2145361Srstrong@cs.ucsd.edu    }
2155361Srstrong@cs.ucsd.edu}
2165361Srstrong@cs.ucsd.edu
2175361Srstrong@cs.ucsd.eduvoid
2185361Srstrong@cs.ucsd.eduAtomicSimpleCPU::switchOut()
2195361Srstrong@cs.ucsd.edu{
2205361Srstrong@cs.ucsd.edu    assert(_status == Running || _status == Idle);
2215361Srstrong@cs.ucsd.edu    _status = SwitchedOut;
2225361Srstrong@cs.ucsd.edu
2233999Ssaidi@eecs.umich.edu    tickEvent.squash();
2245361Srstrong@cs.ucsd.edu}
2255361Srstrong@cs.ucsd.edu
2265361Srstrong@cs.ucsd.edu
2275361Srstrong@cs.ucsd.eduvoid
2285361Srstrong@cs.ucsd.eduAtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
2295361Srstrong@cs.ucsd.edu{
2305361Srstrong@cs.ucsd.edu    BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
2315361Srstrong@cs.ucsd.edu
2325361Srstrong@cs.ucsd.edu    assert(!tickEvent.scheduled());
2335361Srstrong@cs.ucsd.edu
2345361Srstrong@cs.ucsd.edu    // if any of this CPU's ThreadContexts are active, mark the CPU as
2355361Srstrong@cs.ucsd.edu    // running and schedule its tick event.
2365361Srstrong@cs.ucsd.edu    ThreadID size = threadContexts.size();
2373395Shsul@eecs.umich.edu    for (ThreadID i = 0; i < size; ++i) {
2383481Shsul@eecs.umich.edu        ThreadContext *tc = threadContexts[i];
2395361Srstrong@cs.ucsd.edu        if (tc->status() == ThreadContext::Active && _status != Running) {
2405361Srstrong@cs.ucsd.edu            _status = Running;
2415361Srstrong@cs.ucsd.edu            schedule(tickEvent, nextCycle());
2425361Srstrong@cs.ucsd.edu            break;
2435361Srstrong@cs.ucsd.edu        }
2445361Srstrong@cs.ucsd.edu    }
2455361Srstrong@cs.ucsd.edu    if (_status != Running) {
2465361Srstrong@cs.ucsd.edu        _status = Idle;
2475361Srstrong@cs.ucsd.edu    }
2485361Srstrong@cs.ucsd.edu    assert(threadContexts.size() == 1);
2495361Srstrong@cs.ucsd.edu    ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT
2505361Srstrong@cs.ucsd.edu    data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too
2513395Shsul@eecs.umich.edu    data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too
2525361Srstrong@cs.ucsd.edu}
2535361Srstrong@cs.ucsd.edu
2545361Srstrong@cs.ucsd.edu
2555361Srstrong@cs.ucsd.eduvoid
2565361Srstrong@cs.ucsd.eduAtomicSimpleCPU::activateContext(int thread_num, int delay)
2573395Shsul@eecs.umich.edu{
2583395Shsul@eecs.umich.edu    DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay);
2593395Shsul@eecs.umich.edu
2603395Shsul@eecs.umich.edu    assert(thread_num == 0);
2613395Shsul@eecs.umich.edu    assert(thread);
2623481Shsul@eecs.umich.edu
2635361Srstrong@cs.ucsd.edu    assert(_status == Idle);
2645361Srstrong@cs.ucsd.edu    assert(!tickEvent.scheduled());
2655361Srstrong@cs.ucsd.edu
2665361Srstrong@cs.ucsd.edu    notIdleFraction++;
2675361Srstrong@cs.ucsd.edu    numCycles += tickToCycles(thread->lastActivate - thread->lastSuspend);
2685361Srstrong@cs.ucsd.edu
2695361Srstrong@cs.ucsd.edu    //Make sure ticks are still on multiples of cycles
2705353Svilas.sridharan@gmail.com    schedule(tickEvent, nextCycle(curTick + ticks(delay)));
2715361Srstrong@cs.ucsd.edu    _status = Running;
2725361Srstrong@cs.ucsd.edu}
2735361Srstrong@cs.ucsd.edu
2745072Ssaidi@eecs.umich.edu
2753481Shsul@eecs.umich.eduvoid
2765072Ssaidi@eecs.umich.eduAtomicSimpleCPU::suspendContext(int thread_num)
2773395Shsul@eecs.umich.edu{
2783395Shsul@eecs.umich.edu    DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
2793395Shsul@eecs.umich.edu
2803395Shsul@eecs.umich.edu    assert(thread_num == 0);
2815361Srstrong@cs.ucsd.edu    assert(thread);
2825361Srstrong@cs.ucsd.edu
2835361Srstrong@cs.ucsd.edu    if (_status == Idle)
2845361Srstrong@cs.ucsd.edu        return;
2855369Ssaidi@eecs.umich.edu
2865361Srstrong@cs.ucsd.edu    assert(_status == Running);
2875369Ssaidi@eecs.umich.edu
2883395Shsul@eecs.umich.edu    // tick event may not be scheduled if this gets called from inside
2895361Srstrong@cs.ucsd.edu    // an instruction's execution, e.g. "quiesce"
2905369Ssaidi@eecs.umich.edu    if (tickEvent.scheduled())
2915361Srstrong@cs.ucsd.edu        deschedule(tickEvent);
2923395Shsul@eecs.umich.edu
2935361Srstrong@cs.ucsd.edu    notIdleFraction--;
2945361Srstrong@cs.ucsd.edu    _status = Idle;
2955361Srstrong@cs.ucsd.edu}
2963395Shsul@eecs.umich.edu
2975361Srstrong@cs.ucsd.edu
2985361Srstrong@cs.ucsd.eduFault
2995361Srstrong@cs.ucsd.eduAtomicSimpleCPU::readBytes(Addr addr, uint8_t * data,
3003999Ssaidi@eecs.umich.edu                           unsigned size, unsigned flags)
3015361Srstrong@cs.ucsd.edu{
3025361Srstrong@cs.ucsd.edu    // use the CPU's statically allocated read request and packet objects
3035361Srstrong@cs.ucsd.edu    Request *req = &data_read_req;
3045361Srstrong@cs.ucsd.edu
3055361Srstrong@cs.ucsd.edu    if (traceData) {
3065361Srstrong@cs.ucsd.edu        traceData->setAddr(addr);
3073999Ssaidi@eecs.umich.edu    }
3085361Srstrong@cs.ucsd.edu
3095361Srstrong@cs.ucsd.edu    //The block size of our peer.
3105361Srstrong@cs.ucsd.edu    unsigned blockSize = dcachePort.peerBlockSize();
3115369Ssaidi@eecs.umich.edu    //The size of the data we're trying to read.
3125369Ssaidi@eecs.umich.edu    int fullSize = size;
3135369Ssaidi@eecs.umich.edu
3145369Ssaidi@eecs.umich.edu    //The address of the second part of this access if it needs to be split
3155361Srstrong@cs.ucsd.edu    //across a cache line boundary.
3165361Srstrong@cs.ucsd.edu    Addr secondAddr = roundDown(addr + size - 1, blockSize);
3175361Srstrong@cs.ucsd.edu
3185361Srstrong@cs.ucsd.edu    if (secondAddr > addr)
3195361Srstrong@cs.ucsd.edu        size = secondAddr - addr;
3205361Srstrong@cs.ucsd.edu
3215361Srstrong@cs.ucsd.edu    dcache_latency = 0;
3225361Srstrong@cs.ucsd.edu
3235361Srstrong@cs.ucsd.edu    while (1) {
3245361Srstrong@cs.ucsd.edu        req->setVirt(0, addr, size, flags, thread->pcState().instAddr());
3255361Srstrong@cs.ucsd.edu
3265361Srstrong@cs.ucsd.edu        // translate to physical address
3275361Srstrong@cs.ucsd.edu        Fault fault = thread->dtb->translateAtomic(req, tc, BaseTLB::Read);
3285361Srstrong@cs.ucsd.edu
3295361Srstrong@cs.ucsd.edu        // Now do the access.
3305361Srstrong@cs.ucsd.edu        if (fault == NoFault && !req->getFlags().isSet(Request::NO_ACCESS)) {
3315361Srstrong@cs.ucsd.edu            Packet pkt = Packet(req,
3325361Srstrong@cs.ucsd.edu                    req->isLLSC() ? MemCmd::LoadLockedReq : MemCmd::ReadReq,
3335361Srstrong@cs.ucsd.edu                    Packet::Broadcast);
3345361Srstrong@cs.ucsd.edu            pkt.dataStatic(data);
3355361Srstrong@cs.ucsd.edu
3365361Srstrong@cs.ucsd.edu            if (req->isMmapedIpr())
3375361Srstrong@cs.ucsd.edu                dcache_latency += TheISA::handleIprRead(thread->getTC(), &pkt);
3385361Srstrong@cs.ucsd.edu            else {
3395361Srstrong@cs.ucsd.edu                if (hasPhysMemPort && pkt.getAddr() == physMemAddr)
3405361Srstrong@cs.ucsd.edu                    dcache_latency += physmemPort.sendAtomic(&pkt);
3415361Srstrong@cs.ucsd.edu                else
3425361Srstrong@cs.ucsd.edu                    dcache_latency += dcachePort.sendAtomic(&pkt);
3435361Srstrong@cs.ucsd.edu            }
3445361Srstrong@cs.ucsd.edu            dcache_access = true;
3455361Srstrong@cs.ucsd.edu
3465361Srstrong@cs.ucsd.edu            assert(!pkt.isError());
3473395Shsul@eecs.umich.edu
3483395Shsul@eecs.umich.edu            if (req->isLLSC()) {
3493395Shsul@eecs.umich.edu                TheISA::handleLockedRead(thread, req);
3503509Shsul@eecs.umich.edu            }
3513395Shsul@eecs.umich.edu        }
3523395Shsul@eecs.umich.edu
3535361Srstrong@cs.ucsd.edu        //If there's a fault, return it
3543395Shsul@eecs.umich.edu        if (fault != NoFault) {
3553395Shsul@eecs.umich.edu            if (req->isPrefetch()) {
3563511Shsul@eecs.umich.edu                return NoFault;
3573395Shsul@eecs.umich.edu            } else {
3583395Shsul@eecs.umich.edu                return fault;
3593395Shsul@eecs.umich.edu            }
3603395Shsul@eecs.umich.edu        }
3613514Sktlim@umich.edu
3623395Shsul@eecs.umich.edu        //If we don't need to access a second cache line, stop now.
363        if (secondAddr <= addr)
364        {
365            if (req->isLocked() && fault == NoFault) {
366                assert(!locked);
367                locked = true;
368            }
369            return fault;
370        }
371
372        /*
373         * Set up for accessing the second cache line.
374         */
375
376        //Move the pointer we're reading into to the correct location.
377        data += size;
378        //Adjust the size to get the remaining bytes.
379        size = addr + fullSize - secondAddr;
380        //And access the right address.
381        addr = secondAddr;
382    }
383}
384
385
386template <class T>
387Fault
388AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
389{
390    uint8_t *dataPtr = (uint8_t *)&data;
391    memset(dataPtr, 0, sizeof(data));
392    Fault fault = readBytes(addr, dataPtr, sizeof(data), flags);
393    if (fault == NoFault) {
394        data = gtoh(data);
395        if (traceData)
396            traceData->setData(data);
397    }
398    return fault;
399}
400
401#ifndef DOXYGEN_SHOULD_SKIP_THIS
402
403template
404Fault
405AtomicSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags);
406
407template
408Fault
409AtomicSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags);
410
411template
412Fault
413AtomicSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
414
415template
416Fault
417AtomicSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
418
419template
420Fault
421AtomicSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
422
423template
424Fault
425AtomicSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
426
427#endif //DOXYGEN_SHOULD_SKIP_THIS
428
429template<>
430Fault
431AtomicSimpleCPU::read(Addr addr, double &data, unsigned flags)
432{
433    return read(addr, *(uint64_t*)&data, flags);
434}
435
436template<>
437Fault
438AtomicSimpleCPU::read(Addr addr, float &data, unsigned flags)
439{
440    return read(addr, *(uint32_t*)&data, flags);
441}
442
443
444template<>
445Fault
446AtomicSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
447{
448    return read(addr, (uint32_t&)data, flags);
449}
450
451
452Fault
453AtomicSimpleCPU::writeBytes(uint8_t *data, unsigned size,
454                            Addr addr, unsigned flags, uint64_t *res)
455{
456    // use the CPU's statically allocated write request and packet objects
457    Request *req = &data_write_req;
458
459    if (traceData) {
460        traceData->setAddr(addr);
461    }
462
463    //The block size of our peer.
464    unsigned blockSize = dcachePort.peerBlockSize();
465    //The size of the data we're trying to read.
466    int fullSize = size;
467
468    //The address of the second part of this access if it needs to be split
469    //across a cache line boundary.
470    Addr secondAddr = roundDown(addr + size - 1, blockSize);
471
472    if(secondAddr > addr)
473        size = secondAddr - addr;
474
475    dcache_latency = 0;
476
477    while(1) {
478        req->setVirt(0, addr, size, flags, thread->pcState().instAddr());
479
480        // translate to physical address
481        Fault fault = thread->dtb->translateAtomic(req, tc, BaseTLB::Write);
482
483        // Now do the access.
484        if (fault == NoFault) {
485            MemCmd cmd = MemCmd::WriteReq; // default
486            bool do_access = true;  // flag to suppress cache access
487
488            if (req->isLLSC()) {
489                cmd = MemCmd::StoreCondReq;
490                do_access = TheISA::handleLockedWrite(thread, req);
491            } else if (req->isSwap()) {
492                cmd = MemCmd::SwapReq;
493                if (req->isCondSwap()) {
494                    assert(res);
495                    req->setExtraData(*res);
496                }
497            }
498
499            if (do_access && !req->getFlags().isSet(Request::NO_ACCESS)) {
500                Packet pkt = Packet(req, cmd, Packet::Broadcast);
501                pkt.dataStatic(data);
502
503                if (req->isMmapedIpr()) {
504                    dcache_latency +=
505                        TheISA::handleIprWrite(thread->getTC(), &pkt);
506                } else {
507                    if (hasPhysMemPort && pkt.getAddr() == physMemAddr)
508                        dcache_latency += physmemPort.sendAtomic(&pkt);
509                    else
510                        dcache_latency += dcachePort.sendAtomic(&pkt);
511                }
512                dcache_access = true;
513                assert(!pkt.isError());
514
515                if (req->isSwap()) {
516                    assert(res);
517                    memcpy(res, pkt.getPtr<uint8_t>(), fullSize);
518                }
519            }
520
521            if (res && !req->isSwap()) {
522                *res = req->getExtraData();
523            }
524        }
525
526        //If there's a fault or we don't need to access a second cache line,
527        //stop now.
528        if (fault != NoFault || secondAddr <= addr)
529        {
530            if (req->isLocked() && fault == NoFault) {
531                assert(locked);
532                locked = false;
533            }
534            if (fault != NoFault && req->isPrefetch()) {
535                return NoFault;
536            } else {
537                return fault;
538            }
539        }
540
541        /*
542         * Set up for accessing the second cache line.
543         */
544
545        //Move the pointer we're reading into to the correct location.
546        data += size;
547        //Adjust the size to get the remaining bytes.
548        size = addr + fullSize - secondAddr;
549        //And access the right address.
550        addr = secondAddr;
551    }
552}
553
554
555template <class T>
556Fault
557AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
558{
559    uint8_t *dataPtr = (uint8_t *)&data;
560    if (traceData)
561        traceData->setData(data);
562    data = htog(data);
563
564    Fault fault = writeBytes(dataPtr, sizeof(data), addr, flags, res);
565    if (fault == NoFault && data_write_req.isSwap()) {
566        *res = gtoh((T)*res);
567    }
568    return fault;
569}
570
571
572#ifndef DOXYGEN_SHOULD_SKIP_THIS
573
574template
575Fault
576AtomicSimpleCPU::write(Twin32_t data, Addr addr,
577                       unsigned flags, uint64_t *res);
578
579template
580Fault
581AtomicSimpleCPU::write(Twin64_t data, Addr addr,
582                       unsigned flags, uint64_t *res);
583
584template
585Fault
586AtomicSimpleCPU::write(uint64_t data, Addr addr,
587                       unsigned flags, uint64_t *res);
588
589template
590Fault
591AtomicSimpleCPU::write(uint32_t data, Addr addr,
592                       unsigned flags, uint64_t *res);
593
594template
595Fault
596AtomicSimpleCPU::write(uint16_t data, Addr addr,
597                       unsigned flags, uint64_t *res);
598
599template
600Fault
601AtomicSimpleCPU::write(uint8_t data, Addr addr,
602                       unsigned flags, uint64_t *res);
603
604#endif //DOXYGEN_SHOULD_SKIP_THIS
605
606template<>
607Fault
608AtomicSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
609{
610    return write(*(uint64_t*)&data, addr, flags, res);
611}
612
613template<>
614Fault
615AtomicSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
616{
617    return write(*(uint32_t*)&data, addr, flags, res);
618}
619
620
621template<>
622Fault
623AtomicSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
624{
625    return write((uint32_t)data, addr, flags, res);
626}
627
628
629void
630AtomicSimpleCPU::tick()
631{
632    DPRINTF(SimpleCPU, "Tick\n");
633
634    Tick latency = 0;
635
636    for (int i = 0; i < width || locked; ++i) {
637        numCycles++;
638
639        if (!curStaticInst || !curStaticInst->isDelayedCommit())
640            checkForInterrupts();
641
642        checkPcEventQueue();
643
644        Fault fault = NoFault;
645
646        TheISA::PCState pcState = thread->pcState();
647
648        bool needToFetch = !isRomMicroPC(pcState.microPC()) &&
649                           !curMacroStaticInst;
650        if (needToFetch) {
651            setupFetchRequest(&ifetch_req);
652            fault = thread->itb->translateAtomic(&ifetch_req, tc,
653                                                 BaseTLB::Execute);
654        }
655
656        if (fault == NoFault) {
657            Tick icache_latency = 0;
658            bool icache_access = false;
659            dcache_access = false; // assume no dcache access
660
661            if (needToFetch) {
662                // This is commented out because the predecoder would act like
663                // a tiny cache otherwise. It wouldn't be flushed when needed
664                // like the I cache. It should be flushed, and when that works
665                // this code should be uncommented.
666                //Fetch more instruction memory if necessary
667                //if(predecoder.needMoreBytes())
668                //{
669                    icache_access = true;
670                    Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq,
671                                               Packet::Broadcast);
672                    ifetch_pkt.dataStatic(&inst);
673
674                    if (hasPhysMemPort && ifetch_pkt.getAddr() == physMemAddr)
675                        icache_latency = physmemPort.sendAtomic(&ifetch_pkt);
676                    else
677                        icache_latency = icachePort.sendAtomic(&ifetch_pkt);
678
679                    assert(!ifetch_pkt.isError());
680
681                    // ifetch_req is initialized to read the instruction directly
682                    // into the CPU object's inst field.
683                //}
684            }
685
686            preExecute();
687
688            if (curStaticInst) {
689                fault = curStaticInst->execute(this, traceData);
690
691                // keep an instruction count
692                if (fault == NoFault)
693                    countInst();
694                else if (traceData && !DTRACE(ExecFaulting)) {
695                    delete traceData;
696                    traceData = NULL;
697                }
698
699                postExecute();
700            }
701
702            // @todo remove me after debugging with legion done
703            if (curStaticInst && (!curStaticInst->isMicroop() ||
704                        curStaticInst->isFirstMicroop()))
705                instCnt++;
706
707            Tick stall_ticks = 0;
708            if (simulate_inst_stalls && icache_access)
709                stall_ticks += icache_latency;
710
711            if (simulate_data_stalls && dcache_access)
712                stall_ticks += dcache_latency;
713
714            if (stall_ticks) {
715                Tick stall_cycles = stall_ticks / ticks(1);
716                Tick aligned_stall_ticks = ticks(stall_cycles);
717
718                if (aligned_stall_ticks < stall_ticks)
719                    aligned_stall_ticks += 1;
720
721                latency += aligned_stall_ticks;
722            }
723
724        }
725        if(fault != NoFault || !stayAtPC)
726            advancePC(fault);
727    }
728
729    // instruction takes at least one cycle
730    if (latency < ticks(1))
731        latency = ticks(1);
732
733    if (_status != Idle)
734        schedule(tickEvent, curTick + latency);
735}
736
737
738void
739AtomicSimpleCPU::printAddr(Addr a)
740{
741    dcachePort.printAddr(a);
742}
743
744
745////////////////////////////////////////////////////////////////////////
746//
747//  AtomicSimpleCPU Simulation Object
748//
749AtomicSimpleCPU *
750AtomicSimpleCPUParams::create()
751{
752    numThreads = 1;
753#if !FULL_SYSTEM
754    if (workload.size() != 1)
755        panic("only one workload allowed");
756#endif
757    return new AtomicSimpleCPU(this);
758}
759