timing.cc revision 7745
1955SN/A/*
2955SN/A * Copyright (c) 2010 ARM Limited
31762SN/A * All rights reserved
4955SN/A *
5955SN/A * The license below extends only to copyright in the software and shall
6955SN/A * not be construed as granting a license to any other intellectual
7955SN/A * property including but not limited to intellectual property relating
8955SN/A * to a hardware implementation of the functionality of the software
9955SN/A * licensed hereunder.  You may use the software subject to the license
10955SN/A * terms below provided that you ensure that this notice is replicated
11955SN/A * unmodified and in its entirety in all distributions of the software,
12955SN/A * modified or unmodified, in source code or in binary form.
13955SN/A *
14955SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
15955SN/A * All rights reserved.
16955SN/A *
17955SN/A * Redistribution and use in source and binary forms, with or without
18955SN/A * modification, are permitted provided that the following conditions are
19955SN/A * met: redistributions of source code must retain the above copyright
20955SN/A * notice, this list of conditions and the following disclaimer;
21955SN/A * redistributions in binary form must reproduce the above copyright
22955SN/A * notice, this list of conditions and the following disclaimer in the
23955SN/A * documentation and/or other materials provided with the distribution;
24955SN/A * neither the name of the copyright holders nor the names of its
25955SN/A * contributors may be used to endorse or promote products derived from
26955SN/A * this software without specific prior written permission.
27955SN/A *
282665Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
292665Ssaidi@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30955SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31955SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32955SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33955SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34955SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
352632Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
362632Sstever@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
372632Sstever@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
382632Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39955SN/A *
402632Sstever@eecs.umich.edu * Authors: Steve Reinhardt
412632Sstever@eecs.umich.edu */
422761Sstever@eecs.umich.edu
432632Sstever@eecs.umich.edu#include "arch/locked_mem.hh"
442632Sstever@eecs.umich.edu#include "arch/mmaped_ipr.hh"
452632Sstever@eecs.umich.edu#include "arch/utility.hh"
462761Sstever@eecs.umich.edu#include "base/bigint.hh"
472761Sstever@eecs.umich.edu#include "config/the_isa.hh"
482761Sstever@eecs.umich.edu#include "cpu/exetrace.hh"
492632Sstever@eecs.umich.edu#include "cpu/simple/timing.hh"
502632Sstever@eecs.umich.edu#include "mem/packet.hh"
512761Sstever@eecs.umich.edu#include "mem/packet_access.hh"
522761Sstever@eecs.umich.edu#include "params/TimingSimpleCPU.hh"
532761Sstever@eecs.umich.edu#include "sim/faults.hh"
542761Sstever@eecs.umich.edu#include "sim/system.hh"
552761Sstever@eecs.umich.edu
562632Sstever@eecs.umich.eduusing namespace std;
572632Sstever@eecs.umich.eduusing namespace TheISA;
582632Sstever@eecs.umich.edu
592632Sstever@eecs.umich.eduPort *
602632Sstever@eecs.umich.eduTimingSimpleCPU::getPort(const std::string &if_name, int idx)
612632Sstever@eecs.umich.edu{
622632Sstever@eecs.umich.edu    if (if_name == "dcache_port")
63955SN/A        return &dcachePort;
64955SN/A    else if (if_name == "icache_port")
65955SN/A        return &icachePort;
66955SN/A    else
67955SN/A        panic("No Such Port\n");
683918Ssaidi@eecs.umich.edu}
694202Sbinkertn@umich.edu
704678Snate@binkert.orgvoid
71955SN/ATimingSimpleCPU::init()
722656Sstever@eecs.umich.edu{
732656Sstever@eecs.umich.edu    BaseCPU::init();
742656Sstever@eecs.umich.edu#if FULL_SYSTEM
752656Sstever@eecs.umich.edu    for (int i = 0; i < threadContexts.size(); ++i) {
762656Sstever@eecs.umich.edu        ThreadContext *tc = threadContexts[i];
772656Sstever@eecs.umich.edu
782656Sstever@eecs.umich.edu        // initialize CPU, including PC
792653Sstever@eecs.umich.edu        TheISA::initCPU(tc, _cpuId);
802653Sstever@eecs.umich.edu    }
812653Sstever@eecs.umich.edu#endif
822653Sstever@eecs.umich.edu}
832653Sstever@eecs.umich.edu
842653Sstever@eecs.umich.eduTick
852653Sstever@eecs.umich.eduTimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
862653Sstever@eecs.umich.edu{
872653Sstever@eecs.umich.edu    panic("TimingSimpleCPU doesn't expect recvAtomic callback!");
882653Sstever@eecs.umich.edu    return curTick;
894781Snate@binkert.org}
901852SN/A
91955SN/Avoid
92955SN/ATimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
93955SN/A{
943717Sstever@eecs.umich.edu    //No internal storage to update, jusst return
953716Sstever@eecs.umich.edu    return;
96955SN/A}
971533SN/A
983716Sstever@eecs.umich.eduvoid
991533SN/ATimingSimpleCPU::CpuPort::recvStatusChange(Status status)
1004678Snate@binkert.org{
1014678Snate@binkert.org    if (status == RangeChange) {
1024678Snate@binkert.org        if (!snoopRangeSent) {
1034678Snate@binkert.org            snoopRangeSent = true;
1044678Snate@binkert.org            sendStatusChange(Port::RangeChange);
1054678Snate@binkert.org        }
1064678Snate@binkert.org        return;
1074678Snate@binkert.org    }
1084678Snate@binkert.org
1094678Snate@binkert.org    panic("TimingSimpleCPU doesn't expect recvStatusChange callback!");
1104678Snate@binkert.org}
1114678Snate@binkert.org
1124678Snate@binkert.org
1134678Snate@binkert.orgvoid
1144678Snate@binkert.orgTimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t)
1154678Snate@binkert.org{
1164678Snate@binkert.org    pkt = _pkt;
1174678Snate@binkert.org    cpu->schedule(this, t);
1184678Snate@binkert.org}
1194678Snate@binkert.org
1204678Snate@binkert.orgTimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p)
1214678Snate@binkert.org    : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this, p->clock),
1224678Snate@binkert.org    dcachePort(this, p->clock), fetchEvent(this)
1234678Snate@binkert.org{
1244678Snate@binkert.org    _status = Idle;
1254678Snate@binkert.org
1264678Snate@binkert.org    icachePort.snoopRangeSent = false;
1274678Snate@binkert.org    dcachePort.snoopRangeSent = false;
128955SN/A
129955SN/A    ifetch_pkt = dcache_pkt = NULL;
1302632Sstever@eecs.umich.edu    drainEvent = NULL;
1312632Sstever@eecs.umich.edu    previousTick = 0;
132955SN/A    changeState(SimObject::Running);
133955SN/A}
134955SN/A
135955SN/A
1362632Sstever@eecs.umich.eduTimingSimpleCPU::~TimingSimpleCPU()
137955SN/A{
1382632Sstever@eecs.umich.edu}
1392632Sstever@eecs.umich.edu
1402632Sstever@eecs.umich.eduvoid
1412632Sstever@eecs.umich.eduTimingSimpleCPU::serialize(ostream &os)
1422632Sstever@eecs.umich.edu{
1432632Sstever@eecs.umich.edu    SimObject::State so_state = SimObject::getState();
1442632Sstever@eecs.umich.edu    SERIALIZE_ENUM(so_state);
1453053Sstever@eecs.umich.edu    BaseSimpleCPU::serialize(os);
1463053Sstever@eecs.umich.edu}
1473053Sstever@eecs.umich.edu
1483053Sstever@eecs.umich.eduvoid
1493053Sstever@eecs.umich.eduTimingSimpleCPU::unserialize(Checkpoint *cp, const string &section)
1503053Sstever@eecs.umich.edu{
1513053Sstever@eecs.umich.edu    SimObject::State so_state;
1523053Sstever@eecs.umich.edu    UNSERIALIZE_ENUM(so_state);
1533053Sstever@eecs.umich.edu    BaseSimpleCPU::unserialize(cp, section);
1543053Sstever@eecs.umich.edu}
1553053Sstever@eecs.umich.edu
1563053Sstever@eecs.umich.eduunsigned int
1573053Sstever@eecs.umich.eduTimingSimpleCPU::drain(Event *drain_event)
1583053Sstever@eecs.umich.edu{
1593053Sstever@eecs.umich.edu    // TimingSimpleCPU is ready to drain if it's not waiting for
1603053Sstever@eecs.umich.edu    // an access to complete.
1612632Sstever@eecs.umich.edu    if (_status == Idle || _status == Running || _status == SwitchedOut) {
1622632Sstever@eecs.umich.edu        changeState(SimObject::Drained);
1632632Sstever@eecs.umich.edu        return 0;
1642632Sstever@eecs.umich.edu    } else {
1652632Sstever@eecs.umich.edu        changeState(SimObject::Draining);
1662632Sstever@eecs.umich.edu        drainEvent = drain_event;
1673718Sstever@eecs.umich.edu        return 1;
1683718Sstever@eecs.umich.edu    }
1693718Sstever@eecs.umich.edu}
1703718Sstever@eecs.umich.edu
1713718Sstever@eecs.umich.eduvoid
1723718Sstever@eecs.umich.eduTimingSimpleCPU::resume()
1733718Sstever@eecs.umich.edu{
1743718Sstever@eecs.umich.edu    DPRINTF(SimpleCPU, "Resume\n");
1753718Sstever@eecs.umich.edu    if (_status != SwitchedOut && _status != Idle) {
1763718Sstever@eecs.umich.edu        assert(system->getMemoryMode() == Enums::timing);
1773718Sstever@eecs.umich.edu
1783718Sstever@eecs.umich.edu        if (fetchEvent.scheduled())
1793718Sstever@eecs.umich.edu           deschedule(fetchEvent);
1802634Sstever@eecs.umich.edu
1812634Sstever@eecs.umich.edu        schedule(fetchEvent, nextCycle());
1822632Sstever@eecs.umich.edu    }
1832638Sstever@eecs.umich.edu
1842632Sstever@eecs.umich.edu    changeState(SimObject::Running);
1852632Sstever@eecs.umich.edu}
1862632Sstever@eecs.umich.edu
1872632Sstever@eecs.umich.eduvoid
1882632Sstever@eecs.umich.eduTimingSimpleCPU::switchOut()
1892632Sstever@eecs.umich.edu{
1901858SN/A    assert(_status == Running || _status == Idle);
1913716Sstever@eecs.umich.edu    _status = SwitchedOut;
1922638Sstever@eecs.umich.edu    numCycles += tickToCycles(curTick - previousTick);
1932638Sstever@eecs.umich.edu
1942638Sstever@eecs.umich.edu    // If we've been scheduled to resume but are then told to switch out,
1952638Sstever@eecs.umich.edu    // we'll need to cancel it.
1962638Sstever@eecs.umich.edu    if (fetchEvent.scheduled())
1972638Sstever@eecs.umich.edu        deschedule(fetchEvent);
1982638Sstever@eecs.umich.edu}
1993716Sstever@eecs.umich.edu
2002634Sstever@eecs.umich.edu
2012634Sstever@eecs.umich.eduvoid
202955SN/ATimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
203955SN/A{
204955SN/A    BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
205955SN/A
206955SN/A    // if any of this CPU's ThreadContexts are active, mark the CPU as
207955SN/A    // running and schedule its tick event.
208955SN/A    for (int i = 0; i < threadContexts.size(); ++i) {
209955SN/A        ThreadContext *tc = threadContexts[i];
2101858SN/A        if (tc->status() == ThreadContext::Active && _status != Running) {
2111858SN/A            _status = Running;
2122632Sstever@eecs.umich.edu            break;
213955SN/A        }
2144781Snate@binkert.org    }
2153643Ssaidi@eecs.umich.edu
2163643Ssaidi@eecs.umich.edu    if (_status != Running) {
2173643Ssaidi@eecs.umich.edu        _status = Idle;
2183643Ssaidi@eecs.umich.edu    }
2193643Ssaidi@eecs.umich.edu    assert(threadContexts.size() == 1);
2203643Ssaidi@eecs.umich.edu    previousTick = curTick;
2213643Ssaidi@eecs.umich.edu}
2224494Ssaidi@eecs.umich.edu
2234494Ssaidi@eecs.umich.edu
2243716Sstever@eecs.umich.eduvoid
2251105SN/ATimingSimpleCPU::activateContext(int thread_num, int delay)
2262667Sstever@eecs.umich.edu{
2272667Sstever@eecs.umich.edu    DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay);
2282667Sstever@eecs.umich.edu
2292667Sstever@eecs.umich.edu    assert(thread_num == 0);
2302667Sstever@eecs.umich.edu    assert(thread);
2312667Sstever@eecs.umich.edu
2321869SN/A    assert(_status == Idle);
2331869SN/A
2341869SN/A    notIdleFraction++;
2351869SN/A    _status = Running;
2361869SN/A
2371065SN/A    // kick things off by initiating the fetch of the next instruction
2382632Sstever@eecs.umich.edu    schedule(fetchEvent, nextCycle(curTick + ticks(delay)));
2392632Sstever@eecs.umich.edu}
2403918Ssaidi@eecs.umich.edu
2413918Ssaidi@eecs.umich.edu
2423940Ssaidi@eecs.umich.eduvoid
2434781Snate@binkert.orgTimingSimpleCPU::suspendContext(int thread_num)
2444781Snate@binkert.org{
2453918Ssaidi@eecs.umich.edu    DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
2464781Snate@binkert.org
2474781Snate@binkert.org    assert(thread_num == 0);
2483918Ssaidi@eecs.umich.edu    assert(thread);
2494781Snate@binkert.org
2504781Snate@binkert.org    if (_status == Idle)
2513940Ssaidi@eecs.umich.edu        return;
2523942Ssaidi@eecs.umich.edu
2533940Ssaidi@eecs.umich.edu    assert(_status == Running);
2543918Ssaidi@eecs.umich.edu
2553918Ssaidi@eecs.umich.edu    // just change status to Idle... if status != Running,
256955SN/A    // completeInst() will not initiate fetch of next instruction.
2571858SN/A
2583918Ssaidi@eecs.umich.edu    notIdleFraction--;
2593918Ssaidi@eecs.umich.edu    _status = Idle;
2603918Ssaidi@eecs.umich.edu}
2613918Ssaidi@eecs.umich.edu
2623940Ssaidi@eecs.umich.edubool
2633940Ssaidi@eecs.umich.eduTimingSimpleCPU::handleReadPacket(PacketPtr pkt)
2643918Ssaidi@eecs.umich.edu{
2653918Ssaidi@eecs.umich.edu    RequestPtr req = pkt->req;
2663918Ssaidi@eecs.umich.edu    if (req->isMmapedIpr()) {
2673918Ssaidi@eecs.umich.edu        Tick delay;
2683918Ssaidi@eecs.umich.edu        delay = TheISA::handleIprRead(thread->getTC(), pkt);
2693918Ssaidi@eecs.umich.edu        new IprEvent(pkt, this, nextCycle(curTick + delay));
2703918Ssaidi@eecs.umich.edu        _status = DcacheWaitResponse;
2713918Ssaidi@eecs.umich.edu        dcache_pkt = NULL;
2723918Ssaidi@eecs.umich.edu    } else if (!dcachePort.sendTiming(pkt)) {
2733940Ssaidi@eecs.umich.edu        _status = DcacheRetry;
2743918Ssaidi@eecs.umich.edu        dcache_pkt = pkt;
2753918Ssaidi@eecs.umich.edu    } else {
2761851SN/A        _status = DcacheWaitResponse;
2771851SN/A        // memory system takes ownership of packet
2781858SN/A        dcache_pkt = NULL;
2792632Sstever@eecs.umich.edu    }
280955SN/A    return dcache_pkt == NULL;
2813053Sstever@eecs.umich.edu}
2823053Sstever@eecs.umich.edu
2833053Sstever@eecs.umich.eduvoid
2843053Sstever@eecs.umich.eduTimingSimpleCPU::sendData(RequestPtr req, uint8_t *data, uint64_t *res,
2853053Sstever@eecs.umich.edu                          bool read)
2863053Sstever@eecs.umich.edu{
2873053Sstever@eecs.umich.edu    PacketPtr pkt;
2883053Sstever@eecs.umich.edu    buildPacket(pkt, req, read);
2893053Sstever@eecs.umich.edu    pkt->dataDynamicArray<uint8_t>(data);
2904742Sstever@eecs.umich.edu    if (req->getFlags().isSet(Request::NO_ACCESS)) {
2914742Sstever@eecs.umich.edu        assert(!dcache_pkt);
2923053Sstever@eecs.umich.edu        pkt->makeResponse();
2933053Sstever@eecs.umich.edu        completeDataAccess(pkt);
2943053Sstever@eecs.umich.edu    } else if (read) {
2953053Sstever@eecs.umich.edu        handleReadPacket(pkt);
2963053Sstever@eecs.umich.edu    } else {
2973053Sstever@eecs.umich.edu        bool do_access = true;  // flag to suppress cache access
2983053Sstever@eecs.umich.edu
2993053Sstever@eecs.umich.edu        if (req->isLLSC()) {
3003053Sstever@eecs.umich.edu            do_access = TheISA::handleLockedWrite(thread, req);
3012667Sstever@eecs.umich.edu        } else if (req->isCondSwap()) {
3024554Sbinkertn@umich.edu            assert(res);
3034554Sbinkertn@umich.edu            req->setExtraData(*res);
3042667Sstever@eecs.umich.edu        }
3054554Sbinkertn@umich.edu
3064554Sbinkertn@umich.edu        if (do_access) {
3074554Sbinkertn@umich.edu            dcache_pkt = pkt;
3084554Sbinkertn@umich.edu            handleWritePacket();
3094554Sbinkertn@umich.edu        } else {
3104554Sbinkertn@umich.edu            _status = DcacheWaitResponse;
3114554Sbinkertn@umich.edu            completeDataAccess(pkt);
3124781Snate@binkert.org        }
3134554Sbinkertn@umich.edu    }
3144554Sbinkertn@umich.edu}
3152667Sstever@eecs.umich.edu
3164554Sbinkertn@umich.eduvoid
3174554Sbinkertn@umich.eduTimingSimpleCPU::sendSplitData(RequestPtr req1, RequestPtr req2,
3184554Sbinkertn@umich.edu                               RequestPtr req, uint8_t *data, bool read)
3194554Sbinkertn@umich.edu{
3202667Sstever@eecs.umich.edu    PacketPtr pkt1, pkt2;
3214554Sbinkertn@umich.edu    buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read);
3222667Sstever@eecs.umich.edu    if (req->getFlags().isSet(Request::NO_ACCESS)) {
3234554Sbinkertn@umich.edu        assert(!dcache_pkt);
3244554Sbinkertn@umich.edu        pkt1->makeResponse();
3252667Sstever@eecs.umich.edu        completeDataAccess(pkt1);
3262638Sstever@eecs.umich.edu    } else if (read) {
3272638Sstever@eecs.umich.edu        if (handleReadPacket(pkt1)) {
3282638Sstever@eecs.umich.edu            SplitFragmentSenderState * send_state =
3293716Sstever@eecs.umich.edu                dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState);
3303716Sstever@eecs.umich.edu            send_state->clearFromParent();
3311858SN/A            if (handleReadPacket(pkt2)) {
3323118Sstever@eecs.umich.edu                send_state = dynamic_cast<SplitFragmentSenderState *>(
3333118Sstever@eecs.umich.edu                        pkt1->senderState);
3343118Sstever@eecs.umich.edu                send_state->clearFromParent();
3353118Sstever@eecs.umich.edu            }
3363118Sstever@eecs.umich.edu        }
3373118Sstever@eecs.umich.edu    } else {
3383118Sstever@eecs.umich.edu        dcache_pkt = pkt1;
3393118Sstever@eecs.umich.edu        if (handleWritePacket()) {
3403118Sstever@eecs.umich.edu            SplitFragmentSenderState * send_state =
3413118Sstever@eecs.umich.edu                dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState);
3423118Sstever@eecs.umich.edu            send_state->clearFromParent();
3433716Sstever@eecs.umich.edu            dcache_pkt = pkt2;
3443118Sstever@eecs.umich.edu            if (handleWritePacket()) {
3453118Sstever@eecs.umich.edu                send_state = dynamic_cast<SplitFragmentSenderState *>(
3463118Sstever@eecs.umich.edu                        pkt1->senderState);
3473118Sstever@eecs.umich.edu                send_state->clearFromParent();
3483118Sstever@eecs.umich.edu            }
3493118Sstever@eecs.umich.edu        }
3503118Sstever@eecs.umich.edu    }
3513118Sstever@eecs.umich.edu}
3523118Sstever@eecs.umich.edu
3533716Sstever@eecs.umich.eduvoid
3543118Sstever@eecs.umich.eduTimingSimpleCPU::translationFault(Fault fault)
3553118Sstever@eecs.umich.edu{
3563118Sstever@eecs.umich.edu    // fault may be NoFault in cases where a fault is suppressed,
3573118Sstever@eecs.umich.edu    // for instance prefetches.
3583118Sstever@eecs.umich.edu    numCycles += tickToCycles(curTick - previousTick);
3593118Sstever@eecs.umich.edu    previousTick = curTick;
3603118Sstever@eecs.umich.edu
3613118Sstever@eecs.umich.edu    if (traceData) {
3623118Sstever@eecs.umich.edu        // Since there was a fault, we shouldn't trace this instruction.
3633118Sstever@eecs.umich.edu        delete traceData;
3643483Ssaidi@eecs.umich.edu        traceData = NULL;
3653494Ssaidi@eecs.umich.edu    }
3663494Ssaidi@eecs.umich.edu
3673483Ssaidi@eecs.umich.edu    postExecute();
3683483Ssaidi@eecs.umich.edu
3693483Ssaidi@eecs.umich.edu    if (getState() == SimObject::Draining) {
3703053Sstever@eecs.umich.edu        advancePC(fault);
3713053Sstever@eecs.umich.edu        completeDrain();
3723918Ssaidi@eecs.umich.edu    } else {
3733053Sstever@eecs.umich.edu        advanceInst(fault);
3743053Sstever@eecs.umich.edu    }
3753053Sstever@eecs.umich.edu}
3763053Sstever@eecs.umich.edu
3773053Sstever@eecs.umich.eduvoid
3781858SN/ATimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr req, bool read)
3791858SN/A{
3801858SN/A    MemCmd cmd;
3811858SN/A    if (read) {
3821858SN/A        cmd = MemCmd::ReadReq;
3831858SN/A        if (req->isLLSC())
3841859SN/A            cmd = MemCmd::LoadLockedReq;
3851858SN/A    } else {
3861858SN/A        cmd = MemCmd::WriteReq;
3871858SN/A        if (req->isLLSC()) {
3881859SN/A            cmd = MemCmd::StoreCondReq;
3891859SN/A        } else if (req->isSwap()) {
3901862SN/A            cmd = MemCmd::SwapReq;
3913053Sstever@eecs.umich.edu        }
3923053Sstever@eecs.umich.edu    }
3933053Sstever@eecs.umich.edu    pkt = new Packet(req, cmd, Packet::Broadcast);
3943053Sstever@eecs.umich.edu}
3951859SN/A
3961859SN/Avoid
3971859SN/ATimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2,
3981859SN/A        RequestPtr req1, RequestPtr req2, RequestPtr req,
3991859SN/A        uint8_t *data, bool read)
4001859SN/A{
4011859SN/A    pkt1 = pkt2 = NULL;
4021859SN/A
4031862SN/A    assert(!req1->isMmapedIpr() && !req2->isMmapedIpr());
4041859SN/A
4051859SN/A    if (req->getFlags().isSet(Request::NO_ACCESS)) {
4061859SN/A        buildPacket(pkt1, req, read);
4071858SN/A        return;
4081858SN/A    }
4092139SN/A
4104202Sbinkertn@umich.edu    buildPacket(pkt1, req1, read);
4114202Sbinkertn@umich.edu    buildPacket(pkt2, req2, read);
4122139SN/A
4132155SN/A    req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags());
4144202Sbinkertn@umich.edu    PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(),
4154202Sbinkertn@umich.edu                               Packet::Broadcast);
4164202Sbinkertn@umich.edu
4172155SN/A    pkt->dataDynamicArray<uint8_t>(data);
4181869SN/A    pkt1->dataStatic<uint8_t>(data);
4191869SN/A    pkt2->dataStatic<uint8_t>(data + req1->getSize());
4201869SN/A
4211869SN/A    SplitMainSenderState * main_send_state = new SplitMainSenderState;
4224202Sbinkertn@umich.edu    pkt->senderState = main_send_state;
4234202Sbinkertn@umich.edu    main_send_state->fragments[0] = pkt1;
4244202Sbinkertn@umich.edu    main_send_state->fragments[1] = pkt2;
4254202Sbinkertn@umich.edu    main_send_state->outstanding = 2;
4264202Sbinkertn@umich.edu    pkt1->senderState = new SplitFragmentSenderState(pkt, 0);
4274202Sbinkertn@umich.edu    pkt2->senderState = new SplitFragmentSenderState(pkt, 1);
4284202Sbinkertn@umich.edu}
4294202Sbinkertn@umich.edu
4304202Sbinkertn@umich.eduFault
4314202Sbinkertn@umich.eduTimingSimpleCPU::readBytes(Addr addr, uint8_t *data,
4324202Sbinkertn@umich.edu                           unsigned size, unsigned flags)
4334202Sbinkertn@umich.edu{
4344202Sbinkertn@umich.edu    Fault fault;
4354202Sbinkertn@umich.edu    const int asid = 0;
4364202Sbinkertn@umich.edu    const ThreadID tid = 0;
4374202Sbinkertn@umich.edu    const Addr pc = thread->instAddr();
4384773Snate@binkert.org    unsigned block_size = dcachePort.peerBlockSize();
4394775Snate@binkert.org    BaseTLB::Mode mode = BaseTLB::Read;
4404775Snate@binkert.org
4414773Snate@binkert.org    if (traceData) {
4424773Snate@binkert.org        traceData->setAddr(addr);
4434773Snate@binkert.org    }
4444773Snate@binkert.org
4454773Snate@binkert.org    RequestPtr req  = new Request(asid, addr, size,
4464773Snate@binkert.org                                  flags, pc, _cpuId, tid);
4471869SN/A
4484202Sbinkertn@umich.edu    Addr split_addr = roundDown(addr + size - 1, block_size);
4491869SN/A    assert(split_addr <= addr || split_addr - addr < block_size);
4502508SN/A
4512508SN/A    _status = DTBWaitResponse;
4522508SN/A    if (split_addr > addr) {
4532508SN/A        RequestPtr req1, req2;
4544202Sbinkertn@umich.edu        assert(!req->isLLSC() && !req->isSwap());
4551869SN/A        req->splitOnVaddr(split_addr, req1, req2);
4561869SN/A
4571869SN/A        WholeTranslationState *state =
4581869SN/A            new WholeTranslationState(req, req1, req2, new uint8_t[size],
4591869SN/A                                      NULL, mode);
4601869SN/A        DataTranslation<TimingSimpleCPU> *trans1 =
4611965SN/A            new DataTranslation<TimingSimpleCPU>(this, state, 0);
4621965SN/A        DataTranslation<TimingSimpleCPU> *trans2 =
4631965SN/A            new DataTranslation<TimingSimpleCPU>(this, state, 1);
4641869SN/A
4651869SN/A        thread->dtb->translateTiming(req1, tc, trans1, mode);
4662733Sktlim@umich.edu        thread->dtb->translateTiming(req2, tc, trans2, mode);
4671869SN/A    } else {
4681884SN/A        WholeTranslationState *state =
4691884SN/A            new WholeTranslationState(req, new uint8_t[size], NULL, mode);
4703356Sbinkertn@umich.edu        DataTranslation<TimingSimpleCPU> *translation
4713356Sbinkertn@umich.edu            = new DataTranslation<TimingSimpleCPU>(this, state);
4723356Sbinkertn@umich.edu        thread->dtb->translateTiming(req, tc, translation, mode);
4734773Snate@binkert.org    }
4744773Snate@binkert.org
4754773Snate@binkert.org    return NoFault;
4761869SN/A}
4771858SN/A
4781869SN/Atemplate <class T>
4791869SN/AFault
4801869SN/ATimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
4811858SN/A{
4822761Sstever@eecs.umich.edu    return readBytes(addr, (uint8_t *)&data, sizeof(T), flags);
4831869SN/A}
4842733Sktlim@umich.edu
4853584Ssaidi@eecs.umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS
4861869SN/A
4871869SN/Atemplate
4881869SN/AFault
4891869SN/ATimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags);
4901869SN/A
4911869SN/Atemplate
4921858SN/AFault
493955SN/ATimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags);
494955SN/A
4951869SN/Atemplate
4961869SN/AFault
4971869SN/ATimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
4981869SN/A
4991869SN/Atemplate
5001869SN/AFault
5011869SN/ATimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
5021869SN/A
5031869SN/Atemplate
5041869SN/AFault
5051869SN/ATimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
5061869SN/A
5071869SN/Atemplate
5081869SN/AFault
5091869SN/ATimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
5101869SN/A
5111869SN/A#endif //DOXYGEN_SHOULD_SKIP_THIS
5121869SN/A
5131869SN/Atemplate<>
5141869SN/AFault
5151869SN/ATimingSimpleCPU::read(Addr addr, double &data, unsigned flags)
5161869SN/A{
5171869SN/A    return read(addr, *(uint64_t*)&data, flags);
5181869SN/A}
5191869SN/A
5201869SN/Atemplate<>
5211869SN/AFault
5221869SN/ATimingSimpleCPU::read(Addr addr, float &data, unsigned flags)
5231869SN/A{
5243716Sstever@eecs.umich.edu    return read(addr, *(uint32_t*)&data, flags);
5253356Sbinkertn@umich.edu}
5263356Sbinkertn@umich.edu
5273356Sbinkertn@umich.edutemplate<>
5283356Sbinkertn@umich.eduFault
5293356Sbinkertn@umich.eduTimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
5303356Sbinkertn@umich.edu{
5314781Snate@binkert.org    return read(addr, (uint32_t&)data, flags);
5321869SN/A}
5331869SN/A
5341869SN/Abool
5351869SN/ATimingSimpleCPU::handleWritePacket()
5361869SN/A{
5371869SN/A    RequestPtr req = dcache_pkt->req;
5381869SN/A    if (req->isMmapedIpr()) {
5392655Sstever@eecs.umich.edu        Tick delay;
5402655Sstever@eecs.umich.edu        delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt);
5412655Sstever@eecs.umich.edu        new IprEvent(dcache_pkt, this, nextCycle(curTick + delay));
5422655Sstever@eecs.umich.edu        _status = DcacheWaitResponse;
5432655Sstever@eecs.umich.edu        dcache_pkt = NULL;
5442655Sstever@eecs.umich.edu    } else if (!dcachePort.sendTiming(dcache_pkt)) {
5452655Sstever@eecs.umich.edu        _status = DcacheRetry;
5462655Sstever@eecs.umich.edu    } else {
5472655Sstever@eecs.umich.edu        _status = DcacheWaitResponse;
5482655Sstever@eecs.umich.edu        // memory system takes ownership of packet
5492655Sstever@eecs.umich.edu        dcache_pkt = NULL;
5502655Sstever@eecs.umich.edu    }
5512655Sstever@eecs.umich.edu    return dcache_pkt == NULL;
5522655Sstever@eecs.umich.edu}
5532655Sstever@eecs.umich.edu
5542655Sstever@eecs.umich.eduFault
5552655Sstever@eecs.umich.eduTimingSimpleCPU::writeTheseBytes(uint8_t *data, unsigned size,
5562655Sstever@eecs.umich.edu                                 Addr addr, unsigned flags, uint64_t *res)
5572655Sstever@eecs.umich.edu{
5582655Sstever@eecs.umich.edu    const int asid = 0;
5592655Sstever@eecs.umich.edu    const ThreadID tid = 0;
5602655Sstever@eecs.umich.edu    const Addr pc = thread->instAddr();
5612655Sstever@eecs.umich.edu    unsigned block_size = dcachePort.peerBlockSize();
5622655Sstever@eecs.umich.edu    BaseTLB::Mode mode = BaseTLB::Write;
5632655Sstever@eecs.umich.edu
5642655Sstever@eecs.umich.edu    if (traceData) {
5652634Sstever@eecs.umich.edu        traceData->setAddr(addr);
5662634Sstever@eecs.umich.edu    }
5672634Sstever@eecs.umich.edu
5682634Sstever@eecs.umich.edu    RequestPtr req = new Request(asid, addr, size,
5692634Sstever@eecs.umich.edu                                 flags, pc, _cpuId, tid);
5702634Sstever@eecs.umich.edu
5712638Sstever@eecs.umich.edu    Addr split_addr = roundDown(addr + size - 1, block_size);
5722638Sstever@eecs.umich.edu    assert(split_addr <= addr || split_addr - addr < block_size);
5733716Sstever@eecs.umich.edu
5742638Sstever@eecs.umich.edu    _status = DTBWaitResponse;
5752638Sstever@eecs.umich.edu    if (split_addr > addr) {
5761869SN/A        RequestPtr req1, req2;
5771869SN/A        assert(!req->isLLSC() && !req->isSwap());
5783546Sgblack@eecs.umich.edu        req->splitOnVaddr(split_addr, req1, req2);
5793546Sgblack@eecs.umich.edu
5803546Sgblack@eecs.umich.edu        WholeTranslationState *state =
5813546Sgblack@eecs.umich.edu            new WholeTranslationState(req, req1, req2, data, res, mode);
5824202Sbinkertn@umich.edu        DataTranslation<TimingSimpleCPU> *trans1 =
5833546Sgblack@eecs.umich.edu            new DataTranslation<TimingSimpleCPU>(this, state, 0);
5843546Sgblack@eecs.umich.edu        DataTranslation<TimingSimpleCPU> *trans2 =
5853546Sgblack@eecs.umich.edu            new DataTranslation<TimingSimpleCPU>(this, state, 1);
5863546Sgblack@eecs.umich.edu
5873546Sgblack@eecs.umich.edu        thread->dtb->translateTiming(req1, tc, trans1, mode);
5884781Snate@binkert.org        thread->dtb->translateTiming(req2, tc, trans2, mode);
5894781Snate@binkert.org    } else {
5904781Snate@binkert.org        WholeTranslationState *state =
5914781Snate@binkert.org            new WholeTranslationState(req, data, res, mode);
5924781Snate@binkert.org        DataTranslation<TimingSimpleCPU> *translation =
5934781Snate@binkert.org            new DataTranslation<TimingSimpleCPU>(this, state);
5944781Snate@binkert.org        thread->dtb->translateTiming(req, tc, translation, mode);
5954781Snate@binkert.org    }
5964781Snate@binkert.org
5974781Snate@binkert.org    // Translation faults will be returned via finishTranslation()
5984781Snate@binkert.org    return NoFault;
5994781Snate@binkert.org}
6003546Sgblack@eecs.umich.edu
6013546Sgblack@eecs.umich.eduFault
6023546Sgblack@eecs.umich.eduTimingSimpleCPU::writeBytes(uint8_t *data, unsigned size,
6034781Snate@binkert.org                            Addr addr, unsigned flags, uint64_t *res)
6043546Sgblack@eecs.umich.edu{
6053546Sgblack@eecs.umich.edu    uint8_t *newData = new uint8_t[size];
6063546Sgblack@eecs.umich.edu    memcpy(newData, data, size);
6073546Sgblack@eecs.umich.edu    return writeTheseBytes(newData, size, addr, flags, res);
6083546Sgblack@eecs.umich.edu}
6093546Sgblack@eecs.umich.edu
6103546Sgblack@eecs.umich.edutemplate <class T>
6113546Sgblack@eecs.umich.eduFault
6123546Sgblack@eecs.umich.eduTimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
6133546Sgblack@eecs.umich.edu{
6144202Sbinkertn@umich.edu    if (traceData) {
6153546Sgblack@eecs.umich.edu        traceData->setData(data);
6163546Sgblack@eecs.umich.edu    }
6173546Sgblack@eecs.umich.edu    T *dataP = (T*) new uint8_t[sizeof(T)];
618955SN/A    *dataP = TheISA::htog(data);
619955SN/A
620955SN/A    return writeTheseBytes((uint8_t *)dataP, sizeof(T), addr, flags, res);
621955SN/A}
6221858SN/A
6231858SN/A
6241858SN/A#ifndef DOXYGEN_SHOULD_SKIP_THIS
6252632Sstever@eecs.umich.edutemplate
6262632Sstever@eecs.umich.eduFault
6274773Snate@binkert.orgTimingSimpleCPU::write(Twin32_t data, Addr addr,
6284773Snate@binkert.org                       unsigned flags, uint64_t *res);
6292632Sstever@eecs.umich.edu
6302632Sstever@eecs.umich.edutemplate
6312632Sstever@eecs.umich.eduFault
6322634Sstever@eecs.umich.eduTimingSimpleCPU::write(Twin64_t data, Addr addr,
6332638Sstever@eecs.umich.edu                       unsigned flags, uint64_t *res);
6342023SN/A
6352632Sstever@eecs.umich.edutemplate
6362632Sstever@eecs.umich.eduFault
6372632Sstever@eecs.umich.eduTimingSimpleCPU::write(uint64_t data, Addr addr,
6382632Sstever@eecs.umich.edu                       unsigned flags, uint64_t *res);
6392632Sstever@eecs.umich.edu
6403716Sstever@eecs.umich.edutemplate
6412632Sstever@eecs.umich.eduFault
6422632Sstever@eecs.umich.eduTimingSimpleCPU::write(uint32_t data, Addr addr,
6432632Sstever@eecs.umich.edu                       unsigned flags, uint64_t *res);
6442632Sstever@eecs.umich.edu
6452632Sstever@eecs.umich.edutemplate
6462023SN/AFault
6472632Sstever@eecs.umich.eduTimingSimpleCPU::write(uint16_t data, Addr addr,
6482632Sstever@eecs.umich.edu                       unsigned flags, uint64_t *res);
6491889SN/A
6501889SN/Atemplate
6512632Sstever@eecs.umich.eduFault
6522632Sstever@eecs.umich.eduTimingSimpleCPU::write(uint8_t data, Addr addr,
6532632Sstever@eecs.umich.edu                       unsigned flags, uint64_t *res);
6542632Sstever@eecs.umich.edu
6553716Sstever@eecs.umich.edu#endif //DOXYGEN_SHOULD_SKIP_THIS
6563716Sstever@eecs.umich.edu
6572632Sstever@eecs.umich.edutemplate<>
6582632Sstever@eecs.umich.eduFault
6592632Sstever@eecs.umich.eduTimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
6602632Sstever@eecs.umich.edu{
6612632Sstever@eecs.umich.edu    return write(*(uint64_t*)&data, addr, flags, res);
6622632Sstever@eecs.umich.edu}
6632632Sstever@eecs.umich.edu
6642632Sstever@eecs.umich.edutemplate<>
6651888SN/AFault
6661888SN/ATimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
6671869SN/A{
6681869SN/A    return write(*(uint32_t*)&data, addr, flags, res);
6691858SN/A}
6702598SN/A
6712598SN/A
6722598SN/Atemplate<>
6732598SN/AFault
6742598SN/ATimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
6751858SN/A{
6761858SN/A    return write((uint32_t)data, addr, flags, res);
6771858SN/A}
6781858SN/A
6791858SN/A
6801858SN/Avoid
6811858SN/ATimingSimpleCPU::finishTranslation(WholeTranslationState *state)
6821858SN/A{
6831858SN/A    _status = Running;
6841871SN/A
6851858SN/A    if (state->getFault() != NoFault) {
6861858SN/A        if (state->isPrefetch()) {
6871858SN/A            state->setNoFault();
6881858SN/A        }
6891858SN/A        delete [] state->data;
6901858SN/A        state->deleteReqs();
6911858SN/A        translationFault(state->getFault());
6921858SN/A    } else {
6931858SN/A        if (!state->isSplit) {
6941858SN/A            sendData(state->mainReq, state->data, state->res,
6951858SN/A                     state->mode == BaseTLB::Read);
6961859SN/A        } else {
6971859SN/A            sendSplitData(state->sreqLow, state->sreqHigh, state->mainReq,
6981869SN/A                          state->data, state->mode == BaseTLB::Read);
6991888SN/A        }
7002632Sstever@eecs.umich.edu    }
7011869SN/A
7021884SN/A    delete state;
7031884SN/A}
7041884SN/A
7051884SN/A
7061884SN/Avoid
7071884SN/ATimingSimpleCPU::fetch()
7081965SN/A{
7091965SN/A    DPRINTF(SimpleCPU, "Fetch\n");
7101965SN/A
7112761Sstever@eecs.umich.edu    if (!curStaticInst || !curStaticInst->isDelayedCommit())
7121869SN/A        checkForInterrupts();
7131869SN/A
7142632Sstever@eecs.umich.edu    checkPcEventQueue();
7152667Sstever@eecs.umich.edu
7161869SN/A    TheISA::PCState pcState = thread->pcState();
7171869SN/A    bool needToFetch = !isRomMicroPC(pcState.microPC()) && !curMacroStaticInst;
7182929Sktlim@umich.edu
7192929Sktlim@umich.edu    if (needToFetch) {
7203716Sstever@eecs.umich.edu        Request *ifetch_req = new Request();
7212929Sktlim@umich.edu        ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0);
722955SN/A        setupFetchRequest(ifetch_req);
7232598SN/A        thread->itb->translateTiming(ifetch_req, tc, &fetchTranslation,
7242598SN/A                BaseTLB::Execute);
7253546Sgblack@eecs.umich.edu    } else {
726955SN/A        _status = IcacheWaitResponse;
727955SN/A        completeIfetch(NULL);
728955SN/A
7291530SN/A        numCycles += tickToCycles(curTick - previousTick);
730955SN/A        previousTick = curTick;
731955SN/A    }
732955SN/A}
733
734
735void
736TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc)
737{
738    if (fault == NoFault) {
739        ifetch_pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast);
740        ifetch_pkt->dataStatic(&inst);
741
742        if (!icachePort.sendTiming(ifetch_pkt)) {
743            // Need to wait for retry
744            _status = IcacheRetry;
745        } else {
746            // Need to wait for cache to respond
747            _status = IcacheWaitResponse;
748            // ownership of packet transferred to memory system
749            ifetch_pkt = NULL;
750        }
751    } else {
752        delete req;
753        // fetch fault: advance directly to next instruction (fault handler)
754        advanceInst(fault);
755    }
756
757    numCycles += tickToCycles(curTick - previousTick);
758    previousTick = curTick;
759}
760
761
762void
763TimingSimpleCPU::advanceInst(Fault fault)
764{
765    if (fault != NoFault || !stayAtPC)
766        advancePC(fault);
767
768    if (_status == Running) {
769        // kick off fetch of next instruction... callback from icache
770        // response will cause that instruction to be executed,
771        // keeping the CPU running.
772        fetch();
773    }
774}
775
776
777void
778TimingSimpleCPU::completeIfetch(PacketPtr pkt)
779{
780    DPRINTF(SimpleCPU, "Complete ICache Fetch\n");
781
782    // received a response from the icache: execute the received
783    // instruction
784
785    assert(!pkt || !pkt->isError());
786    assert(_status == IcacheWaitResponse);
787
788    _status = Running;
789
790    numCycles += tickToCycles(curTick - previousTick);
791    previousTick = curTick;
792
793    if (getState() == SimObject::Draining) {
794        if (pkt) {
795            delete pkt->req;
796            delete pkt;
797        }
798
799        completeDrain();
800        return;
801    }
802
803    preExecute();
804    if (curStaticInst && curStaticInst->isMemRef()) {
805        // load or store: just send to dcache
806        Fault fault = curStaticInst->initiateAcc(this, traceData);
807        if (_status != Running) {
808            // instruction will complete in dcache response callback
809            assert(_status == DcacheWaitResponse ||
810                    _status == DcacheRetry || DTBWaitResponse);
811            assert(fault == NoFault);
812        } else {
813            if (fault != NoFault && traceData) {
814                // If there was a fault, we shouldn't trace this instruction.
815                delete traceData;
816                traceData = NULL;
817            }
818
819            postExecute();
820            // @todo remove me after debugging with legion done
821            if (curStaticInst && (!curStaticInst->isMicroop() ||
822                        curStaticInst->isFirstMicroop()))
823                instCnt++;
824            advanceInst(fault);
825        }
826    } else if (curStaticInst) {
827        // non-memory instruction: execute completely now
828        Fault fault = curStaticInst->execute(this, traceData);
829
830        // keep an instruction count
831        if (fault == NoFault)
832            countInst();
833        else if (traceData && !DTRACE(ExecFaulting)) {
834            delete traceData;
835            traceData = NULL;
836        }
837
838        postExecute();
839        // @todo remove me after debugging with legion done
840        if (curStaticInst && (!curStaticInst->isMicroop() ||
841                    curStaticInst->isFirstMicroop()))
842            instCnt++;
843        advanceInst(fault);
844    } else {
845        advanceInst(NoFault);
846    }
847
848    if (pkt) {
849        delete pkt->req;
850        delete pkt;
851    }
852}
853
854void
855TimingSimpleCPU::IcachePort::ITickEvent::process()
856{
857    cpu->completeIfetch(pkt);
858}
859
860bool
861TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt)
862{
863    if (pkt->isResponse() && !pkt->wasNacked()) {
864        // delay processing of returned data until next CPU clock edge
865        Tick next_tick = cpu->nextCycle(curTick);
866
867        if (next_tick == curTick)
868            cpu->completeIfetch(pkt);
869        else
870            tickEvent.schedule(pkt, next_tick);
871
872        return true;
873    }
874    else if (pkt->wasNacked()) {
875        assert(cpu->_status == IcacheWaitResponse);
876        pkt->reinitNacked();
877        if (!sendTiming(pkt)) {
878            cpu->_status = IcacheRetry;
879            cpu->ifetch_pkt = pkt;
880        }
881    }
882    //Snooping a Coherence Request, do nothing
883    return true;
884}
885
886void
887TimingSimpleCPU::IcachePort::recvRetry()
888{
889    // we shouldn't get a retry unless we have a packet that we're
890    // waiting to transmit
891    assert(cpu->ifetch_pkt != NULL);
892    assert(cpu->_status == IcacheRetry);
893    PacketPtr tmp = cpu->ifetch_pkt;
894    if (sendTiming(tmp)) {
895        cpu->_status = IcacheWaitResponse;
896        cpu->ifetch_pkt = NULL;
897    }
898}
899
900void
901TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
902{
903    // received a response from the dcache: complete the load or store
904    // instruction
905    assert(!pkt->isError());
906    assert(_status == DcacheWaitResponse || _status == DTBWaitResponse ||
907           pkt->req->getFlags().isSet(Request::NO_ACCESS));
908
909    numCycles += tickToCycles(curTick - previousTick);
910    previousTick = curTick;
911
912    if (pkt->senderState) {
913        SplitFragmentSenderState * send_state =
914            dynamic_cast<SplitFragmentSenderState *>(pkt->senderState);
915        assert(send_state);
916        delete pkt->req;
917        delete pkt;
918        PacketPtr big_pkt = send_state->bigPkt;
919        delete send_state;
920
921        SplitMainSenderState * main_send_state =
922            dynamic_cast<SplitMainSenderState *>(big_pkt->senderState);
923        assert(main_send_state);
924        // Record the fact that this packet is no longer outstanding.
925        assert(main_send_state->outstanding != 0);
926        main_send_state->outstanding--;
927
928        if (main_send_state->outstanding) {
929            return;
930        } else {
931            delete main_send_state;
932            big_pkt->senderState = NULL;
933            pkt = big_pkt;
934        }
935    }
936
937    _status = Running;
938
939    Fault fault = curStaticInst->completeAcc(pkt, this, traceData);
940
941    // keep an instruction count
942    if (fault == NoFault)
943        countInst();
944    else if (traceData) {
945        // If there was a fault, we shouldn't trace this instruction.
946        delete traceData;
947        traceData = NULL;
948    }
949
950    // the locked flag may be cleared on the response packet, so check
951    // pkt->req and not pkt to see if it was a load-locked
952    if (pkt->isRead() && pkt->req->isLLSC()) {
953        TheISA::handleLockedRead(thread, pkt->req);
954    }
955
956    delete pkt->req;
957    delete pkt;
958
959    postExecute();
960
961    if (getState() == SimObject::Draining) {
962        advancePC(fault);
963        completeDrain();
964
965        return;
966    }
967
968    advanceInst(fault);
969}
970
971
972void
973TimingSimpleCPU::completeDrain()
974{
975    DPRINTF(Config, "Done draining\n");
976    changeState(SimObject::Drained);
977    drainEvent->process();
978}
979
980void
981TimingSimpleCPU::DcachePort::setPeer(Port *port)
982{
983    Port::setPeer(port);
984
985#if FULL_SYSTEM
986    // Update the ThreadContext's memory ports (Functional/Virtual
987    // Ports)
988    cpu->tcBase()->connectMemPorts(cpu->tcBase());
989#endif
990}
991
992bool
993TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
994{
995    if (pkt->isResponse() && !pkt->wasNacked()) {
996        // delay processing of returned data until next CPU clock edge
997        Tick next_tick = cpu->nextCycle(curTick);
998
999        if (next_tick == curTick) {
1000            cpu->completeDataAccess(pkt);
1001        } else {
1002            if (!tickEvent.scheduled()) {
1003                tickEvent.schedule(pkt, next_tick);
1004            } else {
1005                // In the case of a split transaction and a cache that is
1006                // faster than a CPU we could get two responses before
1007                // next_tick expires
1008                if (!retryEvent.scheduled())
1009                    schedule(retryEvent, next_tick);
1010                return false;
1011            }
1012        }
1013
1014        return true;
1015    }
1016    else if (pkt->wasNacked()) {
1017        assert(cpu->_status == DcacheWaitResponse);
1018        pkt->reinitNacked();
1019        if (!sendTiming(pkt)) {
1020            cpu->_status = DcacheRetry;
1021            cpu->dcache_pkt = pkt;
1022        }
1023    }
1024    //Snooping a Coherence Request, do nothing
1025    return true;
1026}
1027
1028void
1029TimingSimpleCPU::DcachePort::DTickEvent::process()
1030{
1031    cpu->completeDataAccess(pkt);
1032}
1033
1034void
1035TimingSimpleCPU::DcachePort::recvRetry()
1036{
1037    // we shouldn't get a retry unless we have a packet that we're
1038    // waiting to transmit
1039    assert(cpu->dcache_pkt != NULL);
1040    assert(cpu->_status == DcacheRetry);
1041    PacketPtr tmp = cpu->dcache_pkt;
1042    if (tmp->senderState) {
1043        // This is a packet from a split access.
1044        SplitFragmentSenderState * send_state =
1045            dynamic_cast<SplitFragmentSenderState *>(tmp->senderState);
1046        assert(send_state);
1047        PacketPtr big_pkt = send_state->bigPkt;
1048
1049        SplitMainSenderState * main_send_state =
1050            dynamic_cast<SplitMainSenderState *>(big_pkt->senderState);
1051        assert(main_send_state);
1052
1053        if (sendTiming(tmp)) {
1054            // If we were able to send without retrying, record that fact
1055            // and try sending the other fragment.
1056            send_state->clearFromParent();
1057            int other_index = main_send_state->getPendingFragment();
1058            if (other_index > 0) {
1059                tmp = main_send_state->fragments[other_index];
1060                cpu->dcache_pkt = tmp;
1061                if ((big_pkt->isRead() && cpu->handleReadPacket(tmp)) ||
1062                        (big_pkt->isWrite() && cpu->handleWritePacket())) {
1063                    main_send_state->fragments[other_index] = NULL;
1064                }
1065            } else {
1066                cpu->_status = DcacheWaitResponse;
1067                // memory system takes ownership of packet
1068                cpu->dcache_pkt = NULL;
1069            }
1070        }
1071    } else if (sendTiming(tmp)) {
1072        cpu->_status = DcacheWaitResponse;
1073        // memory system takes ownership of packet
1074        cpu->dcache_pkt = NULL;
1075    }
1076}
1077
1078TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu,
1079    Tick t)
1080    : pkt(_pkt), cpu(_cpu)
1081{
1082    cpu->schedule(this, t);
1083}
1084
1085void
1086TimingSimpleCPU::IprEvent::process()
1087{
1088    cpu->completeDataAccess(pkt);
1089}
1090
1091const char *
1092TimingSimpleCPU::IprEvent::description() const
1093{
1094    return "Timing Simple CPU Delay IPR event";
1095}
1096
1097
1098void
1099TimingSimpleCPU::printAddr(Addr a)
1100{
1101    dcachePort.printAddr(a);
1102}
1103
1104
1105////////////////////////////////////////////////////////////////////////
1106//
1107//  TimingSimpleCPU Simulation Object
1108//
1109TimingSimpleCPU *
1110TimingSimpleCPUParams::create()
1111{
1112    numThreads = 1;
1113#if !FULL_SYSTEM
1114    if (workload.size() != 1)
1115        panic("only one workload allowed");
1116#endif
1117    return new TimingSimpleCPU(this);
1118}
1119