atomic.cc revision 7655
17199Sgblack@eecs.umich.edu/*
27199Sgblack@eecs.umich.edu * Copyright (c) 2002-2005 The Regents of The University of Michigan
37199Sgblack@eecs.umich.edu * All rights reserved.
47199Sgblack@eecs.umich.edu *
57199Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
67199Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
77199Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
87199Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
97199Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
107199Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
117199Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
127199Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
137199Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
147199Sgblack@eecs.umich.edu * this software without specific prior written permission.
157199Sgblack@eecs.umich.edu *
167199Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
177199Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
187199Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
197199Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
207199Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
217199Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
227199Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
237199Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
247199Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
257199Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
267199Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
277199Sgblack@eecs.umich.edu *
287199Sgblack@eecs.umich.edu * Authors: Steve Reinhardt
297199Sgblack@eecs.umich.edu */
307199Sgblack@eecs.umich.edu
317199Sgblack@eecs.umich.edu#include "arch/locked_mem.hh"
327199Sgblack@eecs.umich.edu#include "arch/mmaped_ipr.hh"
337199Sgblack@eecs.umich.edu#include "arch/utility.hh"
347199Sgblack@eecs.umich.edu#include "base/bigint.hh"
357199Sgblack@eecs.umich.edu#include "config/the_isa.hh"
367199Sgblack@eecs.umich.edu#include "cpu/exetrace.hh"
377199Sgblack@eecs.umich.edu#include "cpu/simple/atomic.hh"
387199Sgblack@eecs.umich.edu#include "mem/packet.hh"
397199Sgblack@eecs.umich.edu#include "mem/packet_access.hh"
407199Sgblack@eecs.umich.edu#include "params/AtomicSimpleCPU.hh"
417199Sgblack@eecs.umich.edu#include "sim/system.hh"
427199Sgblack@eecs.umich.edu
437199Sgblack@eecs.umich.eduusing namespace std;
447199Sgblack@eecs.umich.eduusing namespace TheISA;
457199Sgblack@eecs.umich.edu
467199Sgblack@eecs.umich.eduAtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c)
477199Sgblack@eecs.umich.edu    : Event(CPU_Tick_Pri), cpu(c)
487199Sgblack@eecs.umich.edu{
497199Sgblack@eecs.umich.edu}
507199Sgblack@eecs.umich.edu
517199Sgblack@eecs.umich.edu
527199Sgblack@eecs.umich.eduvoid
537199Sgblack@eecs.umich.eduAtomicSimpleCPU::TickEvent::process()
547199Sgblack@eecs.umich.edu{
557199Sgblack@eecs.umich.edu    cpu->tick();
567199Sgblack@eecs.umich.edu}
577199Sgblack@eecs.umich.edu
587202Sgblack@eecs.umich.educonst char *
597202Sgblack@eecs.umich.eduAtomicSimpleCPU::TickEvent::description() const
607202Sgblack@eecs.umich.edu{
617202Sgblack@eecs.umich.edu    return "AtomicSimpleCPU tick";
627202Sgblack@eecs.umich.edu}
637202Sgblack@eecs.umich.edu
647202Sgblack@eecs.umich.eduPort *
657202Sgblack@eecs.umich.eduAtomicSimpleCPU::getPort(const string &if_name, int idx)
667202Sgblack@eecs.umich.edu{
677202Sgblack@eecs.umich.edu    if (if_name == "dcache_port")
687202Sgblack@eecs.umich.edu        return &dcachePort;
697202Sgblack@eecs.umich.edu    else if (if_name == "icache_port")
707202Sgblack@eecs.umich.edu        return &icachePort;
717202Sgblack@eecs.umich.edu    else if (if_name == "physmem_port") {
727202Sgblack@eecs.umich.edu        hasPhysMemPort = true;
737202Sgblack@eecs.umich.edu        return &physmemPort;
747202Sgblack@eecs.umich.edu    }
757202Sgblack@eecs.umich.edu    else
767202Sgblack@eecs.umich.edu        panic("No Such Port\n");
777202Sgblack@eecs.umich.edu}
787202Sgblack@eecs.umich.edu
797202Sgblack@eecs.umich.eduvoid
807400SAli.Saidi@ARM.comAtomicSimpleCPU::init()
817202Sgblack@eecs.umich.edu{
827400SAli.Saidi@ARM.com    BaseCPU::init();
837202Sgblack@eecs.umich.edu#if FULL_SYSTEM
847202Sgblack@eecs.umich.edu    ThreadID size = threadContexts.size();
857202Sgblack@eecs.umich.edu    for (ThreadID i = 0; i < size; ++i) {
867202Sgblack@eecs.umich.edu        ThreadContext *tc = threadContexts[i];
877202Sgblack@eecs.umich.edu
887202Sgblack@eecs.umich.edu        // initialize CPU, including PC
897202Sgblack@eecs.umich.edu        TheISA::initCPU(tc, tc->contextId());
907202Sgblack@eecs.umich.edu    }
917202Sgblack@eecs.umich.edu#endif
927202Sgblack@eecs.umich.edu    if (hasPhysMemPort) {
937202Sgblack@eecs.umich.edu        bool snoop = false;
947202Sgblack@eecs.umich.edu        AddrRangeList pmAddrList;
957202Sgblack@eecs.umich.edu        physmemPort.getPeerAddressRanges(pmAddrList, snoop);
967202Sgblack@eecs.umich.edu        physMemAddr = *pmAddrList.begin();
977202Sgblack@eecs.umich.edu    }
987202Sgblack@eecs.umich.edu    // Atomic doesn't do MT right now, so contextId == threadId
997202Sgblack@eecs.umich.edu    ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT
1007202Sgblack@eecs.umich.edu    data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too
1017202Sgblack@eecs.umich.edu    data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too
1027400SAli.Saidi@ARM.com}
1037202Sgblack@eecs.umich.edu
1047400SAli.Saidi@ARM.combool
1057202Sgblack@eecs.umich.eduAtomicSimpleCPU::CpuPort::recvTiming(PacketPtr pkt)
1067202Sgblack@eecs.umich.edu{
1077202Sgblack@eecs.umich.edu    panic("AtomicSimpleCPU doesn't expect recvTiming callback!");
1087202Sgblack@eecs.umich.edu    return true;
1097202Sgblack@eecs.umich.edu}
1107202Sgblack@eecs.umich.edu
1117202Sgblack@eecs.umich.eduTick
1127202Sgblack@eecs.umich.eduAtomicSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
1137202Sgblack@eecs.umich.edu{
1147202Sgblack@eecs.umich.edu    //Snooping a coherence request, just return
1157202Sgblack@eecs.umich.edu    return 0;
1167202Sgblack@eecs.umich.edu}
1177202Sgblack@eecs.umich.edu
1187202Sgblack@eecs.umich.eduvoid
1197202Sgblack@eecs.umich.eduAtomicSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
1207202Sgblack@eecs.umich.edu{
1217202Sgblack@eecs.umich.edu    //No internal storage to update, just return
1227209Sgblack@eecs.umich.edu    return;
1237209Sgblack@eecs.umich.edu}
1247209Sgblack@eecs.umich.edu
1257209Sgblack@eecs.umich.eduvoid
1267209Sgblack@eecs.umich.eduAtomicSimpleCPU::CpuPort::recvStatusChange(Status status)
1277261Sgblack@eecs.umich.edu{
1287209Sgblack@eecs.umich.edu    if (status == RangeChange) {
1297209Sgblack@eecs.umich.edu        if (!snoopRangeSent) {
1307261Sgblack@eecs.umich.edu            snoopRangeSent = true;
1317261Sgblack@eecs.umich.edu            sendStatusChange(Port::RangeChange);
1327209Sgblack@eecs.umich.edu        }
1337209Sgblack@eecs.umich.edu        return;
1347209Sgblack@eecs.umich.edu    }
1357209Sgblack@eecs.umich.edu
1367209Sgblack@eecs.umich.edu    panic("AtomicSimpleCPU doesn't expect recvStatusChange callback!");
1377209Sgblack@eecs.umich.edu}
1387209Sgblack@eecs.umich.edu
1397209Sgblack@eecs.umich.eduvoid
1407209Sgblack@eecs.umich.eduAtomicSimpleCPU::CpuPort::recvRetry()
1417261Sgblack@eecs.umich.edu{
1427209Sgblack@eecs.umich.edu    panic("AtomicSimpleCPU doesn't expect recvRetry callback!");
1437209Sgblack@eecs.umich.edu}
1447261Sgblack@eecs.umich.edu
1457261Sgblack@eecs.umich.eduvoid
1467209Sgblack@eecs.umich.eduAtomicSimpleCPU::DcachePort::setPeer(Port *port)
1477209Sgblack@eecs.umich.edu{
1487209Sgblack@eecs.umich.edu    Port::setPeer(port);
1497209Sgblack@eecs.umich.edu
1507209Sgblack@eecs.umich.edu#if FULL_SYSTEM
1517209Sgblack@eecs.umich.edu    // Update the ThreadContext's memory ports (Functional/Virtual
1527261Sgblack@eecs.umich.edu    // Ports)
1537209Sgblack@eecs.umich.edu    cpu->tcBase()->connectMemPorts(cpu->tcBase());
1547209Sgblack@eecs.umich.edu#endif
1557261Sgblack@eecs.umich.edu}
1567261Sgblack@eecs.umich.edu
1577209Sgblack@eecs.umich.eduAtomicSimpleCPU::AtomicSimpleCPU(AtomicSimpleCPUParams *p)
1587226Sgblack@eecs.umich.edu    : BaseSimpleCPU(p), tickEvent(this), width(p->width), locked(false),
1597249Sgblack@eecs.umich.edu      simulate_data_stalls(p->simulate_data_stalls),
1607249Sgblack@eecs.umich.edu      simulate_inst_stalls(p->simulate_inst_stalls),
1617249Sgblack@eecs.umich.edu      icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this),
1627249Sgblack@eecs.umich.edu      physmemPort(name() + "-iport", this), hasPhysMemPort(false)
1637249Sgblack@eecs.umich.edu{
1647249Sgblack@eecs.umich.edu    _status = Idle;
1657249Sgblack@eecs.umich.edu
1667249Sgblack@eecs.umich.edu    icachePort.snoopRangeSent = false;
1677249Sgblack@eecs.umich.edu    dcachePort.snoopRangeSent = false;
1687249Sgblack@eecs.umich.edu
1697249Sgblack@eecs.umich.edu}
1707249Sgblack@eecs.umich.edu
1717249Sgblack@eecs.umich.edu
1727261Sgblack@eecs.umich.eduAtomicSimpleCPU::~AtomicSimpleCPU()
1737249Sgblack@eecs.umich.edu{
1747249Sgblack@eecs.umich.edu    if (tickEvent.scheduled()) {
1757261Sgblack@eecs.umich.edu        deschedule(tickEvent);
1767261Sgblack@eecs.umich.edu    }
1777249Sgblack@eecs.umich.edu}
1787249Sgblack@eecs.umich.edu
1797251Sgblack@eecs.umich.eduvoid
1807251Sgblack@eecs.umich.eduAtomicSimpleCPU::serialize(ostream &os)
1817251Sgblack@eecs.umich.edu{
1827261Sgblack@eecs.umich.edu    SimObject::State so_state = SimObject::getState();
1837251Sgblack@eecs.umich.edu    SERIALIZE_ENUM(so_state);
1847251Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(locked);
1857261Sgblack@eecs.umich.edu    BaseSimpleCPU::serialize(os);
1867261Sgblack@eecs.umich.edu    nameOut(os, csprintf("%s.tickEvent", name()));
1877251Sgblack@eecs.umich.edu    tickEvent.serialize(os);
1887251Sgblack@eecs.umich.edu}
1897226Sgblack@eecs.umich.edu
1907226Sgblack@eecs.umich.eduvoid
1917226Sgblack@eecs.umich.eduAtomicSimpleCPU::unserialize(Checkpoint *cp, const string &section)
1927232Sgblack@eecs.umich.edu{
1937226Sgblack@eecs.umich.edu    SimObject::State so_state;
1947226Sgblack@eecs.umich.edu    UNSERIALIZE_ENUM(so_state);
1957226Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(locked);
1967226Sgblack@eecs.umich.edu    BaseSimpleCPU::unserialize(cp, section);
1977226Sgblack@eecs.umich.edu    tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
1987232Sgblack@eecs.umich.edu}
1997226Sgblack@eecs.umich.edu
2007226Sgblack@eecs.umich.eduvoid
2017232Sgblack@eecs.umich.eduAtomicSimpleCPU::resume()
2027232Sgblack@eecs.umich.edu{
2037226Sgblack@eecs.umich.edu    if (_status == Idle || _status == SwitchedOut)
2047226Sgblack@eecs.umich.edu        return;
2057226Sgblack@eecs.umich.edu
2067226Sgblack@eecs.umich.edu    DPRINTF(SimpleCPU, "Resume\n");
2077226Sgblack@eecs.umich.edu    assert(system->getMemoryMode() == Enums::atomic);
2087232Sgblack@eecs.umich.edu
2097226Sgblack@eecs.umich.edu    changeState(SimObject::Running);
2107226Sgblack@eecs.umich.edu    if (thread->status() == ThreadContext::Active) {
2117226Sgblack@eecs.umich.edu        if (!tickEvent.scheduled())
2127226Sgblack@eecs.umich.edu            schedule(tickEvent, nextCycle());
2137226Sgblack@eecs.umich.edu    }
2147232Sgblack@eecs.umich.edu}
2157226Sgblack@eecs.umich.edu
2167226Sgblack@eecs.umich.eduvoid
2177232Sgblack@eecs.umich.eduAtomicSimpleCPU::switchOut()
2187232Sgblack@eecs.umich.edu{
2197226Sgblack@eecs.umich.edu    assert(_status == Running || _status == Idle);
2207226Sgblack@eecs.umich.edu    _status = SwitchedOut;
2217226Sgblack@eecs.umich.edu
2227226Sgblack@eecs.umich.edu    tickEvent.squash();
2237226Sgblack@eecs.umich.edu}
2247226Sgblack@eecs.umich.edu
2257226Sgblack@eecs.umich.edu
2267226Sgblack@eecs.umich.eduvoid
2277232Sgblack@eecs.umich.eduAtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
2287226Sgblack@eecs.umich.edu{
2297226Sgblack@eecs.umich.edu    BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
2307232Sgblack@eecs.umich.edu
2317226Sgblack@eecs.umich.edu    assert(!tickEvent.scheduled());
2327226Sgblack@eecs.umich.edu
2337226Sgblack@eecs.umich.edu    // if any of this CPU's ThreadContexts are active, mark the CPU as
2347226Sgblack@eecs.umich.edu    // running and schedule its tick event.
2357232Sgblack@eecs.umich.edu    ThreadID size = threadContexts.size();
2367226Sgblack@eecs.umich.edu    for (ThreadID i = 0; i < size; ++i) {
2377226Sgblack@eecs.umich.edu        ThreadContext *tc = threadContexts[i];
2387232Sgblack@eecs.umich.edu        if (tc->status() == ThreadContext::Active && _status != Running) {
2397232Sgblack@eecs.umich.edu            _status = Running;
2407226Sgblack@eecs.umich.edu            schedule(tickEvent, nextCycle());
2417226Sgblack@eecs.umich.edu            break;
2427226Sgblack@eecs.umich.edu        }
2437226Sgblack@eecs.umich.edu    }
2447226Sgblack@eecs.umich.edu    if (_status != Running) {
2457226Sgblack@eecs.umich.edu        _status = Idle;
2467226Sgblack@eecs.umich.edu    }
2477226Sgblack@eecs.umich.edu    assert(threadContexts.size() == 1);
2487232Sgblack@eecs.umich.edu    ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT
2497226Sgblack@eecs.umich.edu    data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too
2507226Sgblack@eecs.umich.edu    data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too
2517232Sgblack@eecs.umich.edu}
2527226Sgblack@eecs.umich.edu
2537226Sgblack@eecs.umich.edu
2547226Sgblack@eecs.umich.eduvoid
2557226Sgblack@eecs.umich.eduAtomicSimpleCPU::activateContext(int thread_num, int delay)
2567232Sgblack@eecs.umich.edu{
2577226Sgblack@eecs.umich.edu    DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay);
2587226Sgblack@eecs.umich.edu
2597232Sgblack@eecs.umich.edu    assert(thread_num == 0);
2607232Sgblack@eecs.umich.edu    assert(thread);
2617226Sgblack@eecs.umich.edu
2627234Sgblack@eecs.umich.edu    assert(_status == Idle);
2637234Sgblack@eecs.umich.edu    assert(!tickEvent.scheduled());
2647234Sgblack@eecs.umich.edu
2657234Sgblack@eecs.umich.edu    notIdleFraction++;
2667234Sgblack@eecs.umich.edu    numCycles += tickToCycles(thread->lastActivate - thread->lastSuspend);
2677234Sgblack@eecs.umich.edu
2687234Sgblack@eecs.umich.edu    //Make sure ticks are still on multiples of cycles
2697234Sgblack@eecs.umich.edu    schedule(tickEvent, nextCycle(curTick + ticks(delay)));
2707234Sgblack@eecs.umich.edu    _status = Running;
2717234Sgblack@eecs.umich.edu}
2727234Sgblack@eecs.umich.edu
2737234Sgblack@eecs.umich.edu
2747234Sgblack@eecs.umich.eduvoid
2757234Sgblack@eecs.umich.eduAtomicSimpleCPU::suspendContext(int thread_num)
2767234Sgblack@eecs.umich.edu{
2777234Sgblack@eecs.umich.edu    DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
2787234Sgblack@eecs.umich.edu
2797234Sgblack@eecs.umich.edu    assert(thread_num == 0);
2807234Sgblack@eecs.umich.edu    assert(thread);
2817234Sgblack@eecs.umich.edu
2827234Sgblack@eecs.umich.edu    if (_status == Idle)
2837234Sgblack@eecs.umich.edu        return;
2847234Sgblack@eecs.umich.edu
2857234Sgblack@eecs.umich.edu    assert(_status == Running);
2867234Sgblack@eecs.umich.edu
2877234Sgblack@eecs.umich.edu    // tick event may not be scheduled if this gets called from inside
2887234Sgblack@eecs.umich.edu    // an instruction's execution, e.g. "quiesce"
2897234Sgblack@eecs.umich.edu    if (tickEvent.scheduled())
2907234Sgblack@eecs.umich.edu        deschedule(tickEvent);
2917234Sgblack@eecs.umich.edu
2927234Sgblack@eecs.umich.edu    notIdleFraction--;
2937234Sgblack@eecs.umich.edu    _status = Idle;
2947234Sgblack@eecs.umich.edu}
2957234Sgblack@eecs.umich.edu
2967234Sgblack@eecs.umich.edu
2977234Sgblack@eecs.umich.eduFault
2987234Sgblack@eecs.umich.eduAtomicSimpleCPU::readBytes(Addr addr, uint8_t * data,
2997234Sgblack@eecs.umich.edu                           unsigned size, unsigned flags)
3007234Sgblack@eecs.umich.edu{
3017234Sgblack@eecs.umich.edu    // use the CPU's statically allocated read request and packet objects
3027234Sgblack@eecs.umich.edu    Request *req = &data_read_req;
3037234Sgblack@eecs.umich.edu
3047234Sgblack@eecs.umich.edu    if (traceData) {
3057234Sgblack@eecs.umich.edu        traceData->setAddr(addr);
3067234Sgblack@eecs.umich.edu    }
3077234Sgblack@eecs.umich.edu
3087234Sgblack@eecs.umich.edu    //The block size of our peer.
3097234Sgblack@eecs.umich.edu    unsigned blockSize = dcachePort.peerBlockSize();
3107234Sgblack@eecs.umich.edu    //The size of the data we're trying to read.
3117234Sgblack@eecs.umich.edu    int fullSize = size;
3127234Sgblack@eecs.umich.edu
3137234Sgblack@eecs.umich.edu    //The address of the second part of this access if it needs to be split
3147234Sgblack@eecs.umich.edu    //across a cache line boundary.
3157234Sgblack@eecs.umich.edu    Addr secondAddr = roundDown(addr + size - 1, blockSize);
3167234Sgblack@eecs.umich.edu
3177234Sgblack@eecs.umich.edu    if (secondAddr > addr)
3187234Sgblack@eecs.umich.edu        size = secondAddr - addr;
3197234Sgblack@eecs.umich.edu
3207234Sgblack@eecs.umich.edu    dcache_latency = 0;
3217234Sgblack@eecs.umich.edu
3227234Sgblack@eecs.umich.edu    while (1) {
3237234Sgblack@eecs.umich.edu        req->setVirt(0, addr, size, flags, thread->readPC());
3247234Sgblack@eecs.umich.edu
3257234Sgblack@eecs.umich.edu        // translate to physical address
3267234Sgblack@eecs.umich.edu        Fault fault = thread->dtb->translateAtomic(req, tc, BaseTLB::Read);
3277234Sgblack@eecs.umich.edu
3287234Sgblack@eecs.umich.edu        // Now do the access.
3297234Sgblack@eecs.umich.edu        if (fault == NoFault && !req->getFlags().isSet(Request::NO_ACCESS)) {
3307234Sgblack@eecs.umich.edu            Packet pkt = Packet(req,
3317234Sgblack@eecs.umich.edu                    req->isLLSC() ? MemCmd::LoadLockedReq : MemCmd::ReadReq,
3327234Sgblack@eecs.umich.edu                    Packet::Broadcast);
3337234Sgblack@eecs.umich.edu            pkt.dataStatic(data);
3347234Sgblack@eecs.umich.edu
3357234Sgblack@eecs.umich.edu            if (req->isMmapedIpr())
3367234Sgblack@eecs.umich.edu                dcache_latency += TheISA::handleIprRead(thread->getTC(), &pkt);
3377234Sgblack@eecs.umich.edu            else {
3387234Sgblack@eecs.umich.edu                if (hasPhysMemPort && pkt.getAddr() == physMemAddr)
3397234Sgblack@eecs.umich.edu                    dcache_latency += physmemPort.sendAtomic(&pkt);
3407234Sgblack@eecs.umich.edu                else
3417234Sgblack@eecs.umich.edu                    dcache_latency += dcachePort.sendAtomic(&pkt);
3427234Sgblack@eecs.umich.edu            }
3437234Sgblack@eecs.umich.edu            dcache_access = true;
3447234Sgblack@eecs.umich.edu
3457234Sgblack@eecs.umich.edu            assert(!pkt.isError());
3467234Sgblack@eecs.umich.edu
3477234Sgblack@eecs.umich.edu            if (req->isLLSC()) {
3487234Sgblack@eecs.umich.edu                TheISA::handleLockedRead(thread, req);
3497234Sgblack@eecs.umich.edu            }
3507234Sgblack@eecs.umich.edu        }
3517234Sgblack@eecs.umich.edu
3527234Sgblack@eecs.umich.edu        //If there's a fault, return it
3537234Sgblack@eecs.umich.edu        if (fault != NoFault) {
3547234Sgblack@eecs.umich.edu            if (req->isPrefetch()) {
3557234Sgblack@eecs.umich.edu                return NoFault;
3567234Sgblack@eecs.umich.edu            } else {
3577234Sgblack@eecs.umich.edu                return fault;
3587234Sgblack@eecs.umich.edu            }
3597234Sgblack@eecs.umich.edu        }
3607234Sgblack@eecs.umich.edu
3617234Sgblack@eecs.umich.edu        //If we don't need to access a second cache line, stop now.
3627234Sgblack@eecs.umich.edu        if (secondAddr <= addr)
3637234Sgblack@eecs.umich.edu        {
3647234Sgblack@eecs.umich.edu            if (req->isLocked() && fault == NoFault) {
3657234Sgblack@eecs.umich.edu                assert(!locked);
3667234Sgblack@eecs.umich.edu                locked = true;
3677234Sgblack@eecs.umich.edu            }
3687234Sgblack@eecs.umich.edu            return fault;
3697234Sgblack@eecs.umich.edu        }
3707234Sgblack@eecs.umich.edu
3717234Sgblack@eecs.umich.edu        /*
3727234Sgblack@eecs.umich.edu         * Set up for accessing the second cache line.
3737234Sgblack@eecs.umich.edu         */
3747234Sgblack@eecs.umich.edu
3757234Sgblack@eecs.umich.edu        //Move the pointer we're reading into to the correct location.
3767234Sgblack@eecs.umich.edu        data += size;
3777234Sgblack@eecs.umich.edu        //Adjust the size to get the remaining bytes.
3787234Sgblack@eecs.umich.edu        size = addr + fullSize - secondAddr;
3797234Sgblack@eecs.umich.edu        //And access the right address.
3807234Sgblack@eecs.umich.edu        addr = secondAddr;
3817234Sgblack@eecs.umich.edu    }
3827234Sgblack@eecs.umich.edu}
3837234Sgblack@eecs.umich.edu
3847234Sgblack@eecs.umich.edu
3857234Sgblack@eecs.umich.edutemplate <class T>
3867234Sgblack@eecs.umich.eduFault
3877234Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
3887234Sgblack@eecs.umich.edu{
3897234Sgblack@eecs.umich.edu    uint8_t *dataPtr = (uint8_t *)&data;
3907234Sgblack@eecs.umich.edu    memset(dataPtr, 0, sizeof(data));
3917234Sgblack@eecs.umich.edu    Fault fault = readBytes(addr, dataPtr, sizeof(data), flags);
3927234Sgblack@eecs.umich.edu    if (fault == NoFault) {
3937234Sgblack@eecs.umich.edu        data = gtoh(data);
3947234Sgblack@eecs.umich.edu        if (traceData)
3957234Sgblack@eecs.umich.edu            traceData->setData(data);
3967234Sgblack@eecs.umich.edu    }
3977234Sgblack@eecs.umich.edu    return fault;
3987234Sgblack@eecs.umich.edu}
3997234Sgblack@eecs.umich.edu
4007234Sgblack@eecs.umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS
4017234Sgblack@eecs.umich.edu
4027234Sgblack@eecs.umich.edutemplate
4037234Sgblack@eecs.umich.eduFault
4047239Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags);
4057239Sgblack@eecs.umich.edu
4067239Sgblack@eecs.umich.edutemplate
4077239Sgblack@eecs.umich.eduFault
4087239Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags);
4097239Sgblack@eecs.umich.edu
4107239Sgblack@eecs.umich.edutemplate
4117239Sgblack@eecs.umich.eduFault
4127239Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
4137239Sgblack@eecs.umich.edu
4147239Sgblack@eecs.umich.edutemplate
4157239Sgblack@eecs.umich.eduFault
4167239Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
4177239Sgblack@eecs.umich.edu
4187239Sgblack@eecs.umich.edutemplate
4197239Sgblack@eecs.umich.eduFault
4207239Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
4217239Sgblack@eecs.umich.edu
4227242Sgblack@eecs.umich.edutemplate
4237242Sgblack@eecs.umich.eduFault
4247242Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
4257242Sgblack@eecs.umich.edu
4267242Sgblack@eecs.umich.edu#endif //DOXYGEN_SHOULD_SKIP_THIS
4277242Sgblack@eecs.umich.edu
4287242Sgblack@eecs.umich.edutemplate<>
4297242Sgblack@eecs.umich.eduFault
4307242Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, double &data, unsigned flags)
4317242Sgblack@eecs.umich.edu{
4327242Sgblack@eecs.umich.edu    return read(addr, *(uint64_t*)&data, flags);
4337242Sgblack@eecs.umich.edu}
4347242Sgblack@eecs.umich.edu
4357242Sgblack@eecs.umich.edutemplate<>
4367242Sgblack@eecs.umich.eduFault
4377242Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, float &data, unsigned flags)
4387242Sgblack@eecs.umich.edu{
4397242Sgblack@eecs.umich.edu    return read(addr, *(uint32_t*)&data, flags);
4407242Sgblack@eecs.umich.edu}
4417242Sgblack@eecs.umich.edu
4427242Sgblack@eecs.umich.edu
4437242Sgblack@eecs.umich.edutemplate<>
4447242Sgblack@eecs.umich.eduFault
4457242Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
4467242Sgblack@eecs.umich.edu{
4477242Sgblack@eecs.umich.edu    return read(addr, (uint32_t&)data, flags);
4487242Sgblack@eecs.umich.edu}
4497242Sgblack@eecs.umich.edu
4507242Sgblack@eecs.umich.edu
4517242Sgblack@eecs.umich.eduFault
4527242Sgblack@eecs.umich.eduAtomicSimpleCPU::writeBytes(uint8_t *data, unsigned size,
4537242Sgblack@eecs.umich.edu                            Addr addr, unsigned flags, uint64_t *res)
4547242Sgblack@eecs.umich.edu{
4557242Sgblack@eecs.umich.edu    // use the CPU's statically allocated write request and packet objects
4567242Sgblack@eecs.umich.edu    Request *req = &data_write_req;
4577242Sgblack@eecs.umich.edu
4587247Sgblack@eecs.umich.edu    if (traceData) {
4597247Sgblack@eecs.umich.edu        traceData->setAddr(addr);
4607247Sgblack@eecs.umich.edu    }
4617247Sgblack@eecs.umich.edu
4627247Sgblack@eecs.umich.edu    //The block size of our peer.
4637254Sgblack@eecs.umich.edu    unsigned blockSize = dcachePort.peerBlockSize();
4647254Sgblack@eecs.umich.edu    //The size of the data we're trying to read.
4657254Sgblack@eecs.umich.edu    int fullSize = size;
4667254Sgblack@eecs.umich.edu
4677254Sgblack@eecs.umich.edu    //The address of the second part of this access if it needs to be split
4687254Sgblack@eecs.umich.edu    //across a cache line boundary.
4697254Sgblack@eecs.umich.edu    Addr secondAddr = roundDown(addr + size - 1, blockSize);
4707254Sgblack@eecs.umich.edu
4717254Sgblack@eecs.umich.edu    if(secondAddr > addr)
4727254Sgblack@eecs.umich.edu        size = secondAddr - addr;
4737254Sgblack@eecs.umich.edu
4747254Sgblack@eecs.umich.edu    dcache_latency = 0;
4757254Sgblack@eecs.umich.edu
4767254Sgblack@eecs.umich.edu    while(1) {
4777254Sgblack@eecs.umich.edu        req->setVirt(0, addr, size, flags, thread->readPC());
4787254Sgblack@eecs.umich.edu
4797254Sgblack@eecs.umich.edu        // translate to physical address
4807254Sgblack@eecs.umich.edu        Fault fault = thread->dtb->translateAtomic(req, tc, BaseTLB::Write);
4817254Sgblack@eecs.umich.edu
4827254Sgblack@eecs.umich.edu        // Now do the access.
4837254Sgblack@eecs.umich.edu        if (fault == NoFault) {
4847257Sgblack@eecs.umich.edu            MemCmd cmd = MemCmd::WriteReq; // default
4857257Sgblack@eecs.umich.edu            bool do_access = true;  // flag to suppress cache access
4867257Sgblack@eecs.umich.edu
4877257Sgblack@eecs.umich.edu            if (req->isLLSC()) {
4887257Sgblack@eecs.umich.edu                cmd = MemCmd::StoreCondReq;
4897257Sgblack@eecs.umich.edu                do_access = TheISA::handleLockedWrite(thread, req);
4907257Sgblack@eecs.umich.edu            } else if (req->isSwap()) {
4917257Sgblack@eecs.umich.edu                cmd = MemCmd::SwapReq;
4927257Sgblack@eecs.umich.edu                if (req->isCondSwap()) {
4937257Sgblack@eecs.umich.edu                    assert(res);
4947257Sgblack@eecs.umich.edu                    req->setExtraData(*res);
4957257Sgblack@eecs.umich.edu                }
4967257Sgblack@eecs.umich.edu            }
4977257Sgblack@eecs.umich.edu
4987257Sgblack@eecs.umich.edu            if (do_access && !req->getFlags().isSet(Request::NO_ACCESS)) {
4997257Sgblack@eecs.umich.edu                Packet pkt = Packet(req, cmd, Packet::Broadcast);
5007257Sgblack@eecs.umich.edu                pkt.dataStatic(data);
5017257Sgblack@eecs.umich.edu
5027257Sgblack@eecs.umich.edu                if (req->isMmapedIpr()) {
5037257Sgblack@eecs.umich.edu                    dcache_latency +=
5047257Sgblack@eecs.umich.edu                        TheISA::handleIprWrite(thread->getTC(), &pkt);
5057262Sgblack@eecs.umich.edu                } else {
5067347SAli.Saidi@ARM.com                    if (hasPhysMemPort && pkt.getAddr() == physMemAddr)
5077347SAli.Saidi@ARM.com                        dcache_latency += physmemPort.sendAtomic(&pkt);
5087347SAli.Saidi@ARM.com                    else
5097347SAli.Saidi@ARM.com                        dcache_latency += dcachePort.sendAtomic(&pkt);
5107347SAli.Saidi@ARM.com                }
5117347SAli.Saidi@ARM.com                dcache_access = true;
5127347SAli.Saidi@ARM.com                assert(!pkt.isError());
5137347SAli.Saidi@ARM.com
5147347SAli.Saidi@ARM.com                if (req->isSwap()) {
5157347SAli.Saidi@ARM.com                    assert(res);
5167347SAli.Saidi@ARM.com                    memcpy(res, pkt.getPtr<uint8_t>(), fullSize);
5177262Sgblack@eecs.umich.edu                }
5187347SAli.Saidi@ARM.com            }
5197262Sgblack@eecs.umich.edu
5207262Sgblack@eecs.umich.edu            if (res && !req->isSwap()) {
5217262Sgblack@eecs.umich.edu                *res = req->getExtraData();
5227262Sgblack@eecs.umich.edu            }
5237262Sgblack@eecs.umich.edu        }
5247347SAli.Saidi@ARM.com
5257347SAli.Saidi@ARM.com        //If there's a fault or we don't need to access a second cache line,
5267347SAli.Saidi@ARM.com        //stop now.
5277347SAli.Saidi@ARM.com        if (fault != NoFault || secondAddr <= addr)
5287347SAli.Saidi@ARM.com        {
5297347SAli.Saidi@ARM.com            if (req->isLocked() && fault == NoFault) {
5307347SAli.Saidi@ARM.com                assert(locked);
5317347SAli.Saidi@ARM.com                locked = false;
5327347SAli.Saidi@ARM.com            }
5337347SAli.Saidi@ARM.com            if (fault != NoFault && req->isPrefetch()) {
5347347SAli.Saidi@ARM.com                return NoFault;
5357262Sgblack@eecs.umich.edu            } else {
5367347SAli.Saidi@ARM.com                return fault;
5377262Sgblack@eecs.umich.edu            }
5387262Sgblack@eecs.umich.edu        }
5397262Sgblack@eecs.umich.edu
5407262Sgblack@eecs.umich.edu        /*
5417283Sgblack@eecs.umich.edu         * Set up for accessing the second cache line.
5427283Sgblack@eecs.umich.edu         */
5437283Sgblack@eecs.umich.edu
5447283Sgblack@eecs.umich.edu        //Move the pointer we're reading into to the correct location.
5457283Sgblack@eecs.umich.edu        data += size;
5467283Sgblack@eecs.umich.edu        //Adjust the size to get the remaining bytes.
5477283Sgblack@eecs.umich.edu        size = addr + fullSize - secondAddr;
5487283Sgblack@eecs.umich.edu        //And access the right address.
5497283Sgblack@eecs.umich.edu        addr = secondAddr;
5507283Sgblack@eecs.umich.edu    }
5517283Sgblack@eecs.umich.edu}
5527283Sgblack@eecs.umich.edu
5537283Sgblack@eecs.umich.edu
5547283Sgblack@eecs.umich.edutemplate <class T>
5557283Sgblack@eecs.umich.eduFault
5567283Sgblack@eecs.umich.eduAtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
5577283Sgblack@eecs.umich.edu{
5587283Sgblack@eecs.umich.edu    uint8_t *dataPtr = (uint8_t *)&data;
5597283Sgblack@eecs.umich.edu    if (traceData)
5607283Sgblack@eecs.umich.edu        traceData->setData(data);
5617307Sgblack@eecs.umich.edu    data = htog(data);
5627307Sgblack@eecs.umich.edu
5637307Sgblack@eecs.umich.edu    Fault fault = writeBytes(dataPtr, sizeof(data), addr, flags, res);
5647307Sgblack@eecs.umich.edu    if (fault == NoFault && data_write_req.isSwap()) {
5657307Sgblack@eecs.umich.edu        *res = gtoh((T)*res);
5667307Sgblack@eecs.umich.edu    }
5677307Sgblack@eecs.umich.edu    return fault;
5687307Sgblack@eecs.umich.edu}
5697307Sgblack@eecs.umich.edu
5707307Sgblack@eecs.umich.edu
5717307Sgblack@eecs.umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS
5727307Sgblack@eecs.umich.edu
5737315Sgblack@eecs.umich.edutemplate
5747315Sgblack@eecs.umich.eduFault
5757315Sgblack@eecs.umich.eduAtomicSimpleCPU::write(Twin32_t data, Addr addr,
5767315Sgblack@eecs.umich.edu                       unsigned flags, uint64_t *res);
5777315Sgblack@eecs.umich.edu
5787315Sgblack@eecs.umich.edutemplate
5797315Sgblack@eecs.umich.eduFault
5807315Sgblack@eecs.umich.eduAtomicSimpleCPU::write(Twin64_t data, Addr addr,
5817315Sgblack@eecs.umich.edu                       unsigned flags, uint64_t *res);
5827400SAli.Saidi@ARM.com
5837315Sgblack@eecs.umich.edutemplate
5847315Sgblack@eecs.umich.eduFault
5857315Sgblack@eecs.umich.eduAtomicSimpleCPU::write(uint64_t data, Addr addr,
5867315Sgblack@eecs.umich.edu                       unsigned flags, uint64_t *res);
5877315Sgblack@eecs.umich.edu
5887315Sgblack@eecs.umich.edutemplate
5897400SAli.Saidi@ARM.comFault
5907315Sgblack@eecs.umich.eduAtomicSimpleCPU::write(uint32_t data, Addr addr,
5917315Sgblack@eecs.umich.edu                       unsigned flags, uint64_t *res);
5927315Sgblack@eecs.umich.edu
5937315Sgblack@eecs.umich.edutemplate
5947315Sgblack@eecs.umich.eduFault
5957315Sgblack@eecs.umich.eduAtomicSimpleCPU::write(uint16_t data, Addr addr,
5967315Sgblack@eecs.umich.edu                       unsigned flags, uint64_t *res);
5977315Sgblack@eecs.umich.edu
5987315Sgblack@eecs.umich.edutemplate
5997315Sgblack@eecs.umich.eduFault
6007315Sgblack@eecs.umich.eduAtomicSimpleCPU::write(uint8_t data, Addr addr,
6017315Sgblack@eecs.umich.edu                       unsigned flags, uint64_t *res);
6027315Sgblack@eecs.umich.edu
6037315Sgblack@eecs.umich.edu#endif //DOXYGEN_SHOULD_SKIP_THIS
6047315Sgblack@eecs.umich.edu
6057202Sgblack@eecs.umich.edutemplate<>
606Fault
607AtomicSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
608{
609    return write(*(uint64_t*)&data, addr, flags, res);
610}
611
612template<>
613Fault
614AtomicSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
615{
616    return write(*(uint32_t*)&data, addr, flags, res);
617}
618
619
620template<>
621Fault
622AtomicSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
623{
624    return write((uint32_t)data, addr, flags, res);
625}
626
627
628void
629AtomicSimpleCPU::tick()
630{
631    DPRINTF(SimpleCPU, "Tick\n");
632
633    Tick latency = 0;
634
635    for (int i = 0; i < width || locked; ++i) {
636        numCycles++;
637
638        if (!curStaticInst || !curStaticInst->isDelayedCommit())
639            checkForInterrupts();
640
641        checkPcEventQueue();
642
643        Fault fault = NoFault;
644
645        bool fromRom = isRomMicroPC(thread->readMicroPC());
646        if (!fromRom && !curMacroStaticInst) {
647            setupFetchRequest(&ifetch_req);
648            fault = thread->itb->translateAtomic(&ifetch_req, tc,
649                                                 BaseTLB::Execute);
650        }
651
652        if (fault == NoFault) {
653            Tick icache_latency = 0;
654            bool icache_access = false;
655            dcache_access = false; // assume no dcache access
656
657            if (!fromRom && !curMacroStaticInst) {
658                // This is commented out because the predecoder would act like
659                // a tiny cache otherwise. It wouldn't be flushed when needed
660                // like the I cache. It should be flushed, and when that works
661                // this code should be uncommented.
662                //Fetch more instruction memory if necessary
663                //if(predecoder.needMoreBytes())
664                //{
665                    icache_access = true;
666                    Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq,
667                                               Packet::Broadcast);
668                    ifetch_pkt.dataStatic(&inst);
669
670                    if (hasPhysMemPort && ifetch_pkt.getAddr() == physMemAddr)
671                        icache_latency = physmemPort.sendAtomic(&ifetch_pkt);
672                    else
673                        icache_latency = icachePort.sendAtomic(&ifetch_pkt);
674
675                    assert(!ifetch_pkt.isError());
676
677                    // ifetch_req is initialized to read the instruction directly
678                    // into the CPU object's inst field.
679                //}
680            }
681
682            preExecute();
683
684            if (curStaticInst) {
685                fault = curStaticInst->execute(this, traceData);
686
687                // keep an instruction count
688                if (fault == NoFault)
689                    countInst();
690                else if (traceData && !DTRACE(ExecFaulting)) {
691                    delete traceData;
692                    traceData = NULL;
693                }
694
695                postExecute();
696            }
697
698            // @todo remove me after debugging with legion done
699            if (curStaticInst && (!curStaticInst->isMicroop() ||
700                        curStaticInst->isFirstMicroop()))
701                instCnt++;
702
703            Tick stall_ticks = 0;
704            if (simulate_inst_stalls && icache_access)
705                stall_ticks += icache_latency;
706
707            if (simulate_data_stalls && dcache_access)
708                stall_ticks += dcache_latency;
709
710            if (stall_ticks) {
711                Tick stall_cycles = stall_ticks / ticks(1);
712                Tick aligned_stall_ticks = ticks(stall_cycles);
713
714                if (aligned_stall_ticks < stall_ticks)
715                    aligned_stall_ticks += 1;
716
717                latency += aligned_stall_ticks;
718            }
719
720        }
721        if(fault != NoFault || !stayAtPC)
722            advancePC(fault);
723    }
724
725    // instruction takes at least one cycle
726    if (latency < ticks(1))
727        latency = ticks(1);
728
729    if (_status != Idle)
730        schedule(tickEvent, curTick + latency);
731}
732
733
734void
735AtomicSimpleCPU::printAddr(Addr a)
736{
737    dcachePort.printAddr(a);
738}
739
740
741////////////////////////////////////////////////////////////////////////
742//
743//  AtomicSimpleCPU Simulation Object
744//
745AtomicSimpleCPU *
746AtomicSimpleCPUParams::create()
747{
748    numThreads = 1;
749#if !FULL_SYSTEM
750    if (workload.size() != 1)
751        panic("only one workload allowed");
752#endif
753    return new AtomicSimpleCPU(this);
754}
755