timing.cc revision 8232
12632Sstever@eecs.umich.edu/*
22632Sstever@eecs.umich.edu * Copyright (c) 2010 ARM Limited
32632Sstever@eecs.umich.edu * All rights reserved
42632Sstever@eecs.umich.edu *
52632Sstever@eecs.umich.edu * The license below extends only to copyright in the software and shall
62632Sstever@eecs.umich.edu * not be construed as granting a license to any other intellectual
72632Sstever@eecs.umich.edu * property including but not limited to intellectual property relating
82632Sstever@eecs.umich.edu * to a hardware implementation of the functionality of the software
92632Sstever@eecs.umich.edu * licensed hereunder.  You may use the software subject to the license
102632Sstever@eecs.umich.edu * terms below provided that you ensure that this notice is replicated
112632Sstever@eecs.umich.edu * unmodified and in its entirety in all distributions of the software,
122632Sstever@eecs.umich.edu * modified or unmodified, in source code or in binary form.
132632Sstever@eecs.umich.edu *
142632Sstever@eecs.umich.edu * Copyright (c) 2002-2005 The Regents of The University of Michigan
152632Sstever@eecs.umich.edu * All rights reserved.
162632Sstever@eecs.umich.edu *
172632Sstever@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
182632Sstever@eecs.umich.edu * modification, are permitted provided that the following conditions are
192632Sstever@eecs.umich.edu * met: redistributions of source code must retain the above copyright
202632Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
212632Sstever@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
222632Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
232632Sstever@eecs.umich.edu * documentation and/or other materials provided with the distribution;
242632Sstever@eecs.umich.edu * neither the name of the copyright holders nor the names of its
252632Sstever@eecs.umich.edu * contributors may be used to endorse or promote products derived from
262632Sstever@eecs.umich.edu * this software without specific prior written permission.
272632Sstever@eecs.umich.edu *
282632Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
292632Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
302632Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
312022SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
322022SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
332022SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
342022SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
352022SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
362469SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
372469SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
382469SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
392469SN/A *
402516SN/A * Authors: Steve Reinhardt
412516SN/A */
422516SN/A
432482SN/A#include "arch/locked_mem.hh"
442516SN/A#include "arch/mmapped_ipr.hh"
452469SN/A#include "arch/utility.hh"
462486SN/A#include "base/bigint.hh"
472486SN/A#include "config/the_isa.hh"
482516SN/A#include "cpu/simple/timing.hh"
492580SN/A#include "cpu/exetrace.hh"
502580SN/A#include "debug/Config.hh"
512486SN/A#include "debug/ExecFaulting.hh"
522486SN/A#include "debug/SimpleCPU.hh"
532482SN/A#include "mem/packet.hh"
542516SN/A#include "mem/packet_access.hh"
552580SN/A#include "params/TimingSimpleCPU.hh"
562580SN/A#include "sim/faults.hh"
572486SN/A#include "sim/system.hh"
582482SN/A
592516SN/Ausing namespace std;
602516SN/Ausing namespace TheISA;
612516SN/A
622516SN/APort *
632580SN/ATimingSimpleCPU::getPort(const std::string &if_name, int idx)
642580SN/A{
652516SN/A    if (if_name == "dcache_port")
662516SN/A        return &dcachePort;
672516SN/A    else if (if_name == "icache_port")
682516SN/A        return &icachePort;
692482SN/A    else
702482SN/A        panic("No Such Port\n");
712591SN/A}
722516SN/A
732580SN/Avoid
742580SN/ATimingSimpleCPU::init()
752482SN/A{
762482SN/A    BaseCPU::init();
772591SN/A#if FULL_SYSTEM
782516SN/A    for (int i = 0; i < threadContexts.size(); ++i) {
792580SN/A        ThreadContext *tc = threadContexts[i];
802580SN/A
812482SN/A        // initialize CPU, including PC
822482SN/A        TheISA::initCPU(tc, _cpuId);
832591SN/A    }
842516SN/A#endif
852580SN/A}
862580SN/A
872482SN/ATick
882482SN/ATimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
892591SN/A{
902516SN/A    panic("TimingSimpleCPU doesn't expect recvAtomic callback!");
912580SN/A    return curTick();
922580SN/A}
932482SN/A
942482SN/Avoid
952591SN/ATimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
962516SN/A{
972580SN/A    //No internal storage to update, jusst return
982580SN/A    return;
992482SN/A}
1002482SN/A
1012591SN/Avoid
1022516SN/ATimingSimpleCPU::CpuPort::recvStatusChange(Status status)
1032580SN/A{
1042580SN/A    if (status == RangeChange) {
1052482SN/A        if (!snoopRangeSent) {
1062469SN/A            snoopRangeSent = true;
1072482SN/A            sendStatusChange(Port::RangeChange);
1082516SN/A        }
1092516SN/A        return;
1102516SN/A    }
1112516SN/A
1122469SN/A    panic("TimingSimpleCPU doesn't expect recvStatusChange callback!");
1132516SN/A}
1142516SN/A
1152516SN/A
1162469SN/Avoid
1172469SN/ATimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t)
1182482SN/A{
1192482SN/A    pkt = _pkt;
1202482SN/A    cpu->schedule(this, t);
1212482SN/A}
1222482SN/A
1232526SN/ATimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p)
1242516SN/A    : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this, p->clock),
1252516SN/A    dcachePort(this, p->clock), fetchEvent(this)
1262516SN/A{
1272516SN/A    _status = Idle;
1282516SN/A
1292469SN/A    icachePort.snoopRangeSent = false;
1302516SN/A    dcachePort.snoopRangeSent = false;
1312482SN/A
1322482SN/A    ifetch_pkt = dcache_pkt = NULL;
1332469SN/A    drainEvent = NULL;
1342516SN/A    previousTick = 0;
1352482SN/A    changeState(SimObject::Running);
1362482SN/A    system->totalNumInsts = 0;
1372516SN/A}
1382469SN/A
1392516SN/A
1402516SN/ATimingSimpleCPU::~TimingSimpleCPU()
1412482SN/A{
1422469SN/A}
1432516SN/A
1442482SN/Avoid
1452482SN/ATimingSimpleCPU::serialize(ostream &os)
1462516SN/A{
1472482SN/A    SimObject::State so_state = SimObject::getState();
1482482SN/A    SERIALIZE_ENUM(so_state);
1492482SN/A    BaseSimpleCPU::serialize(os);
1502482SN/A}
1512482SN/A
1522615SN/Avoid
1532469SN/ATimingSimpleCPU::unserialize(Checkpoint *cp, const string &section)
1542469SN/A{
1552482SN/A    SimObject::State so_state;
1562615SN/A    UNSERIALIZE_ENUM(so_state);
1572482SN/A    BaseSimpleCPU::unserialize(cp, section);
1582482SN/A}
1592482SN/A
1602588SN/Aunsigned int
1612482SN/ATimingSimpleCPU::drain(Event *drain_event)
1622526SN/A{
1632469SN/A    // TimingSimpleCPU is ready to drain if it's not waiting for
1642482SN/A    // an access to complete.
1652469SN/A    if (_status == Idle || _status == Running || _status == SwitchedOut) {
1662516SN/A        changeState(SimObject::Drained);
1672469SN/A        return 0;
1682580SN/A    } else {
1692469SN/A        changeState(SimObject::Draining);
1702580SN/A        drainEvent = drain_event;
1712469SN/A        return 1;
1722526SN/A    }
1732482SN/A}
1742482SN/A
1752482SN/Avoid
1762469SN/ATimingSimpleCPU::resume()
1772580SN/A{
1782580SN/A    DPRINTF(SimpleCPU, "Resume\n");
1792580SN/A    if (_status != SwitchedOut && _status != Idle) {
1802580SN/A        assert(system->getMemoryMode() == Enums::timing);
1812580SN/A
1822580SN/A        if (fetchEvent.scheduled())
1832580SN/A           deschedule(fetchEvent);
1842526SN/A
1852482SN/A        schedule(fetchEvent, nextCycle());
1862482SN/A    }
1872482SN/A
1882469SN/A    changeState(SimObject::Running);
1892516SN/A}
1902469SN/A
1912469SN/Avoid
1922580SN/ATimingSimpleCPU::switchOut()
1932469SN/A{
1942580SN/A    assert(_status == Running || _status == Idle);
1952580SN/A    _status = SwitchedOut;
1962469SN/A    numCycles += tickToCycles(curTick() - previousTick);
1972526SN/A
1982469SN/A    // If we've been scheduled to resume but are then told to switch out,
1992615SN/A    // we'll need to cancel it.
2002615SN/A    if (fetchEvent.scheduled())
2012469SN/A        deschedule(fetchEvent);
2022526SN/A}
2032469SN/A
2042615SN/A
2052615SN/Avoid
2062526SN/ATimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
2072526SN/A{
2082469SN/A    BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
2092516SN/A
2102469SN/A    // if any of this CPU's ThreadContexts are active, mark the CPU as
2112469SN/A    // running and schedule its tick event.
2122580SN/A    for (int i = 0; i < threadContexts.size(); ++i) {
2132469SN/A        ThreadContext *tc = threadContexts[i];
2142580SN/A        if (tc->status() == ThreadContext::Active && _status != Running) {
2152469SN/A            _status = Running;
2162526SN/A            break;
2172469SN/A        }
2182615SN/A    }
2192615SN/A
2202526SN/A    if (_status != Running) {
2212469SN/A        _status = Idle;
2222615SN/A    }
2232516SN/A    assert(threadContexts.size() == 1);
2242469SN/A    previousTick = curTick();
2252469SN/A}
2262224SN/A
2272469SN/A
2282516SN/Avoid
2292516SN/ATimingSimpleCPU::activateContext(int thread_num, int delay)
2302516SN/A{
2312469SN/A    DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay);
2322469SN/A
2332469SN/A    assert(thread_num == 0);
2342469SN/A    assert(thread);
2352469SN/A
2362526SN/A    assert(_status == Idle);
2372469SN/A
2382615SN/A    notIdleFraction++;
2392516SN/A    _status = Running;
2402469SN/A
2412469SN/A    // kick things off by initiating the fetch of the next instruction
2422469SN/A    schedule(fetchEvent, nextCycle(curTick() + ticks(delay)));
2432516SN/A}
2442516SN/A
2452516SN/A
2462516SN/Avoid
2472588SN/ATimingSimpleCPU::suspendContext(int thread_num)
2482516SN/A{
2492469SN/A    DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
2502469SN/A
2512469SN/A    assert(thread_num == 0);
2522469SN/A    assert(thread);
2532469SN/A
2542526SN/A    if (_status == Idle)
2552469SN/A        return;
2562516SN/A
2572469SN/A    assert(_status == Running);
2582469SN/A
2592469SN/A    // just change status to Idle... if status != Running,
2602469SN/A    // completeInst() will not initiate fetch of next instruction.
2612469SN/A
2622469SN/A    notIdleFraction--;
2632526SN/A    _status = Idle;
2642469SN/A}
2652516SN/A
2662469SN/Abool
2672469SN/ATimingSimpleCPU::handleReadPacket(PacketPtr pkt)
2682516SN/A{
2692469SN/A    RequestPtr req = pkt->req;
2702469SN/A    if (req->isMmappedIpr()) {
2712469SN/A        Tick delay;
2722526SN/A        delay = TheISA::handleIprRead(thread->getTC(), pkt);
2732469SN/A        new IprEvent(pkt, this, nextCycle(curTick() + delay));
2742516SN/A        _status = DcacheWaitResponse;
2752469SN/A        dcache_pkt = NULL;
2762469SN/A    } else if (!dcachePort.sendTiming(pkt)) {
2772469SN/A        _status = DcacheRetry;
2782469SN/A        dcache_pkt = pkt;
2792469SN/A    } else {
2802469SN/A        _status = DcacheWaitResponse;
2812469SN/A        // memory system takes ownership of packet
2822526SN/A        dcache_pkt = NULL;
2832469SN/A    }
2842516SN/A    return dcache_pkt == NULL;
2852469SN/A}
2862469SN/A
2872469SN/Avoid
2882469SN/ATimingSimpleCPU::sendData(RequestPtr req, uint8_t *data, uint64_t *res,
2892469SN/A                          bool read)
2902469SN/A{
2912469SN/A    PacketPtr pkt;
2922526SN/A    buildPacket(pkt, req, read);
2932469SN/A    pkt->dataDynamicArray<uint8_t>(data);
2942516SN/A    if (req->getFlags().isSet(Request::NO_ACCESS)) {
2952469SN/A        assert(!dcache_pkt);
2962469SN/A        pkt->makeResponse();
2972516SN/A        completeDataAccess(pkt);
2982469SN/A    } else if (read) {
2992469SN/A        handleReadPacket(pkt);
3002469SN/A    } else {
3012469SN/A        bool do_access = true;  // flag to suppress cache access
3022469SN/A
3032469SN/A        if (req->isLLSC()) {
3042469SN/A            do_access = TheISA::handleLockedWrite(thread, req);
3052469SN/A        } else if (req->isCondSwap()) {
3062469SN/A            assert(res);
3072469SN/A            req->setExtraData(*res);
3082526SN/A        }
3092526SN/A
3102526SN/A        if (do_access) {
3112526SN/A            dcache_pkt = pkt;
3122526SN/A            handleWritePacket();
3132526SN/A        } else {
3142526SN/A            _status = DcacheWaitResponse;
3152469SN/A            completeDataAccess(pkt);
3162526SN/A        }
3172526SN/A    }
3182526SN/A}
3192526SN/A
3202526SN/Avoid
3212526SN/ATimingSimpleCPU::sendSplitData(RequestPtr req1, RequestPtr req2,
3222526SN/A                               RequestPtr req, uint8_t *data, bool read)
3232526SN/A{
3242526SN/A    PacketPtr pkt1, pkt2;
3252526SN/A    buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read);
3262526SN/A    if (req->getFlags().isSet(Request::NO_ACCESS)) {
3272526SN/A        assert(!dcache_pkt);
3282526SN/A        pkt1->makeResponse();
3292526SN/A        completeDataAccess(pkt1);
3302526SN/A    } else if (read) {
3312526SN/A        SplitFragmentSenderState * send_state =
3322526SN/A            dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState);
3332526SN/A        if (handleReadPacket(pkt1)) {
3342526SN/A            send_state->clearFromParent();
3352526SN/A            send_state = dynamic_cast<SplitFragmentSenderState *>(
3362526SN/A                    pkt2->senderState);
3372526SN/A            if (handleReadPacket(pkt2)) {
3382526SN/A                send_state->clearFromParent();
3392526SN/A            }
3402526SN/A        }
3412526SN/A    } else {
3422526SN/A        dcache_pkt = pkt1;
3432526SN/A        SplitFragmentSenderState * send_state =
3442526SN/A            dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState);
3452526SN/A        if (handleWritePacket()) {
3462526SN/A            send_state->clearFromParent();
3472526SN/A            dcache_pkt = pkt2;
3482526SN/A            send_state = dynamic_cast<SplitFragmentSenderState *>(
3492526SN/A                    pkt2->senderState);
3502526SN/A            if (handleWritePacket()) {
3512526SN/A                send_state->clearFromParent();
3522526SN/A            }
3532526SN/A        }
3542526SN/A    }
3552526SN/A}
3562526SN/A
3572526SN/Avoid
3582526SN/ATimingSimpleCPU::translationFault(Fault fault)
3592526SN/A{
3602526SN/A    // fault may be NoFault in cases where a fault is suppressed,
3612526SN/A    // for instance prefetches.
3622526SN/A    numCycles += tickToCycles(curTick() - previousTick);
3632526SN/A    previousTick = curTick();
3642526SN/A
3652526SN/A    if (traceData) {
3662526SN/A        // Since there was a fault, we shouldn't trace this instruction.
3672526SN/A        delete traceData;
3682526SN/A        traceData = NULL;
3692526SN/A    }
3702526SN/A
3712526SN/A    postExecute();
3722526SN/A
3732526SN/A    if (getState() == SimObject::Draining) {
3742526SN/A        advancePC(fault);
3752526SN/A        completeDrain();
3762526SN/A    } else {
3772469SN/A        advanceInst(fault);
3782526SN/A    }
3792526SN/A}
3802526SN/A
3812526SN/Avoid
3822526SN/ATimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr req, bool read)
3832591SN/A{
3842591SN/A    MemCmd cmd;
3852591SN/A    if (read) {
3862526SN/A        cmd = MemCmd::ReadReq;
3872526SN/A        if (req->isLLSC())
3882526SN/A            cmd = MemCmd::LoadLockedReq;
3892591SN/A    } else {
3902591SN/A        cmd = MemCmd::WriteReq;
3912591SN/A        if (req->isLLSC()) {
3922526SN/A            cmd = MemCmd::StoreCondReq;
3932224SN/A        } else if (req->isSwap()) {
3942526SN/A            cmd = MemCmd::SwapReq;
3952526SN/A        }
3962615SN/A    }
3972615SN/A    pkt = new Packet(req, cmd, Packet::Broadcast);
3982526SN/A}
3992526SN/A
4002526SN/Avoid
4012526SN/ATimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2,
4022526SN/A        RequestPtr req1, RequestPtr req2, RequestPtr req,
4032526SN/A        uint8_t *data, bool read)
4042526SN/A{
4052526SN/A    pkt1 = pkt2 = NULL;
4062469SN/A
4072526SN/A    assert(!req1->isMmappedIpr() && !req2->isMmappedIpr());
4082526SN/A
4092516SN/A    if (req->getFlags().isSet(Request::NO_ACCESS)) {
4102591SN/A        buildPacket(pkt1, req, read);
4112516SN/A        return;
4122526SN/A    }
4132526SN/A
4142526SN/A    buildPacket(pkt1, req1, read);
4152615SN/A    buildPacket(pkt2, req2, read);
4162615SN/A
4172615SN/A    req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags());
4182615SN/A    PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(),
4192615SN/A                               Packet::Broadcast);
4202615SN/A
4212526SN/A    pkt->dataDynamicArray<uint8_t>(data);
4222526SN/A    pkt1->dataStatic<uint8_t>(data);
4232526SN/A    pkt2->dataStatic<uint8_t>(data + req1->getSize());
4242526SN/A
4252526SN/A    SplitMainSenderState * main_send_state = new SplitMainSenderState;
4262526SN/A    pkt->senderState = main_send_state;
4272526SN/A    main_send_state->fragments[0] = pkt1;
4282526SN/A    main_send_state->fragments[1] = pkt2;
4292526SN/A    main_send_state->outstanding = 2;
4302526SN/A    pkt1->senderState = new SplitFragmentSenderState(pkt, 0);
4312526SN/A    pkt2->senderState = new SplitFragmentSenderState(pkt, 1);
4322526SN/A}
4332526SN/A
4342526SN/AFault
4352469SN/ATimingSimpleCPU::readBytes(Addr addr, uint8_t *data,
4362526SN/A                           unsigned size, unsigned flags)
4372526SN/A{
4382526SN/A    Fault fault;
4392485SN/A    const int asid = 0;
4402526SN/A    const ThreadID tid = 0;
4412526SN/A    const Addr pc = thread->instAddr();
4422526SN/A    unsigned block_size = dcachePort.peerBlockSize();
4432485SN/A    BaseTLB::Mode mode = BaseTLB::Read;
4442526SN/A
4452526SN/A    if (traceData) {
4462526SN/A        traceData->setAddr(addr);
4472526SN/A    }
4482526SN/A
4492526SN/A    RequestPtr req  = new Request(asid, addr, size,
4502526SN/A                                  flags, pc, _cpuId, tid);
4512526SN/A
4522526SN/A    Addr split_addr = roundDown(addr + size - 1, block_size);
4532526SN/A    assert(split_addr <= addr || split_addr - addr < block_size);
4542526SN/A
4552526SN/A    _status = DTBWaitResponse;
4562526SN/A    if (split_addr > addr) {
4572526SN/A        RequestPtr req1, req2;
4582526SN/A        assert(!req->isLLSC() && !req->isSwap());
4592526SN/A        req->splitOnVaddr(split_addr, req1, req2);
4602526SN/A
4612526SN/A        WholeTranslationState *state =
4622526SN/A            new WholeTranslationState(req, req1, req2, new uint8_t[size],
4632469SN/A                                      NULL, mode);
4642469SN/A        DataTranslation<TimingSimpleCPU> *trans1 =
4652526SN/A            new DataTranslation<TimingSimpleCPU>(this, state, 0);
4662526SN/A        DataTranslation<TimingSimpleCPU> *trans2 =
4672526SN/A            new DataTranslation<TimingSimpleCPU>(this, state, 1);
4682526SN/A
4692526SN/A        thread->dtb->translateTiming(req1, tc, trans1, mode);
4702526SN/A        thread->dtb->translateTiming(req2, tc, trans2, mode);
4712526SN/A    } else {
4722526SN/A        WholeTranslationState *state =
4732526SN/A            new WholeTranslationState(req, new uint8_t[size], NULL, mode);
4742526SN/A        DataTranslation<TimingSimpleCPU> *translation
4752526SN/A            = new DataTranslation<TimingSimpleCPU>(this, state);
4762526SN/A        thread->dtb->translateTiming(req, tc, translation, mode);
4772526SN/A    }
4782561SN/A
4792561SN/A    return NoFault;
4802561SN/A}
4812526SN/A
4822526SN/Atemplate <class T>
4832526SN/AFault
4842526SN/ATimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
4852526SN/A{
4862561SN/A    return readBytes(addr, (uint8_t *)&data, sizeof(T), flags);
4872561SN/A}
4882561SN/A
4892561SN/A#ifndef DOXYGEN_SHOULD_SKIP_THIS
4902561SN/A
4912561SN/Atemplate
4922561SN/AFault
4932561SN/ATimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags);
4942561SN/A
4952561SN/Atemplate
4962561SN/AFault
4972561SN/ATimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags);
4982561SN/A
4992561SN/Atemplate
5002561SN/AFault
5012561SN/ATimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
5022561SN/A
5032561SN/Atemplate
5042561SN/AFault
5052561SN/ATimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
5062561SN/A
5072561SN/Atemplate
5082561SN/AFault
5092561SN/ATimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
5102526SN/A
5112526SN/Atemplate
5122526SN/AFault
5132526SN/ATimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
5142561SN/A
5152561SN/A#endif //DOXYGEN_SHOULD_SKIP_THIS
5162561SN/A
5172561SN/Atemplate<>
5182526SN/AFault
5192561SN/ATimingSimpleCPU::read(Addr addr, double &data, unsigned flags)
5202526SN/A{
5212561SN/A    return read(addr, *(uint64_t*)&data, flags);
5222561SN/A}
5232561SN/A
5242561SN/Atemplate<>
5252526SN/AFault
5262526SN/ATimingSimpleCPU::read(Addr addr, float &data, unsigned flags)
5272561SN/A{
5282561SN/A    return read(addr, *(uint32_t*)&data, flags);
5292561SN/A}
5302561SN/A
5312526SN/Atemplate<>
5322561SN/AFault
5332526SN/ATimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
5342561SN/A{
5352561SN/A    return read(addr, (uint32_t&)data, flags);
5362561SN/A}
5372526SN/A
5382526SN/Abool
5392526SN/ATimingSimpleCPU::handleWritePacket()
5402526SN/A{
5412526SN/A    RequestPtr req = dcache_pkt->req;
5422526SN/A    if (req->isMmappedIpr()) {
5432526SN/A        Tick delay;
5442526SN/A        delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt);
5452526SN/A        new IprEvent(dcache_pkt, this, nextCycle(curTick() + delay));
5462526SN/A        _status = DcacheWaitResponse;
5472526SN/A        dcache_pkt = NULL;
5482526SN/A    } else if (!dcachePort.sendTiming(dcache_pkt)) {
5492526SN/A        _status = DcacheRetry;
5502526SN/A    } else {
5512526SN/A        _status = DcacheWaitResponse;
5522526SN/A        // memory system takes ownership of packet
5532526SN/A        dcache_pkt = NULL;
5542526SN/A    }
5552526SN/A    return dcache_pkt == NULL;
5562526SN/A}
5572526SN/A
5582526SN/AFault
5592526SN/ATimingSimpleCPU::writeTheseBytes(uint8_t *data, unsigned size,
5602526SN/A                                 Addr addr, unsigned flags, uint64_t *res)
5612526SN/A{
5622561SN/A    const int asid = 0;
5632561SN/A    const ThreadID tid = 0;
5642526SN/A    const Addr pc = thread->instAddr();
5652526SN/A    unsigned block_size = dcachePort.peerBlockSize();
5662526SN/A    BaseTLB::Mode mode = BaseTLB::Write;
5672526SN/A
5682526SN/A    if (traceData) {
5692526SN/A        traceData->setAddr(addr);
5702526SN/A    }
5712526SN/A
5722526SN/A    RequestPtr req = new Request(asid, addr, size,
5732526SN/A                                 flags, pc, _cpuId, tid);
5742526SN/A
5752526SN/A    Addr split_addr = roundDown(addr + size - 1, block_size);
5762526SN/A    assert(split_addr <= addr || split_addr - addr < block_size);
5772526SN/A
5782526SN/A    _status = DTBWaitResponse;
5792526SN/A    if (split_addr > addr) {
5802526SN/A        RequestPtr req1, req2;
5812526SN/A        assert(!req->isLLSC() && !req->isSwap());
5822526SN/A        req->splitOnVaddr(split_addr, req1, req2);
5832526SN/A
5842526SN/A        WholeTranslationState *state =
5852561SN/A            new WholeTranslationState(req, req1, req2, data, res, mode);
5862561SN/A        DataTranslation<TimingSimpleCPU> *trans1 =
5872526SN/A            new DataTranslation<TimingSimpleCPU>(this, state, 0);
5882526SN/A        DataTranslation<TimingSimpleCPU> *trans2 =
5892526SN/A            new DataTranslation<TimingSimpleCPU>(this, state, 1);
5902526SN/A
5912526SN/A        thread->dtb->translateTiming(req1, tc, trans1, mode);
5922526SN/A        thread->dtb->translateTiming(req2, tc, trans2, mode);
5932526SN/A    } else {
5942526SN/A        WholeTranslationState *state =
5952526SN/A            new WholeTranslationState(req, data, res, mode);
5962526SN/A        DataTranslation<TimingSimpleCPU> *translation =
5972526SN/A            new DataTranslation<TimingSimpleCPU>(this, state);
5982526SN/A        thread->dtb->translateTiming(req, tc, translation, mode);
5992526SN/A    }
6002526SN/A
6012526SN/A    // Translation faults will be returned via finishTranslation()
6022526SN/A    return NoFault;
6032526SN/A}
6042526SN/A
6052526SN/AFault
6062526SN/ATimingSimpleCPU::writeBytes(uint8_t *data, unsigned size,
6072526SN/A                            Addr addr, unsigned flags, uint64_t *res)
6082526SN/A{
6092526SN/A    uint8_t *newData = new uint8_t[size];
6102526SN/A    memcpy(newData, data, size);
6112526SN/A    return writeTheseBytes(newData, size, addr, flags, res);
6122526SN/A}
6132526SN/A
6142526SN/Atemplate <class T>
6152526SN/AFault
6162526SN/ATimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
6172526SN/A{
6182469SN/A    if (traceData) {
6192469SN/A        traceData->setData(data);
6202526SN/A    }
6212526SN/A    T *dataP = (T*) new uint8_t[sizeof(T)];
6222526SN/A    *dataP = TheISA::htog(data);
6232526SN/A
6242526SN/A    return writeTheseBytes((uint8_t *)dataP, sizeof(T), addr, flags, res);
6252526SN/A}
6262526SN/A
6272526SN/A
6282526SN/A#ifndef DOXYGEN_SHOULD_SKIP_THIS
6292526SN/Atemplate
6302526SN/AFault
6312526SN/ATimingSimpleCPU::write(Twin32_t data, Addr addr,
6322526SN/A                       unsigned flags, uint64_t *res);
6332526SN/A
6342526SN/Atemplate
6352526SN/AFault
6362526SN/ATimingSimpleCPU::write(Twin64_t data, Addr addr,
6372526SN/A                       unsigned flags, uint64_t *res);
6382526SN/A
6392526SN/Atemplate
6402526SN/AFault
6412526SN/ATimingSimpleCPU::write(uint64_t data, Addr addr,
6422526SN/A                       unsigned flags, uint64_t *res);
6432526SN/A
6442526SN/Atemplate
6452526SN/AFault
6462526SN/ATimingSimpleCPU::write(uint32_t data, Addr addr,
6472526SN/A                       unsigned flags, uint64_t *res);
6482526SN/A
6492526SN/Atemplate
6502526SN/AFault
6512526SN/ATimingSimpleCPU::write(uint16_t data, Addr addr,
6522526SN/A                       unsigned flags, uint64_t *res);
6532526SN/A
6542526SN/Atemplate
6552526SN/AFault
6562526SN/ATimingSimpleCPU::write(uint8_t data, Addr addr,
6572526SN/A                       unsigned flags, uint64_t *res);
6582526SN/A
6592526SN/A#endif //DOXYGEN_SHOULD_SKIP_THIS
6602526SN/A
6612526SN/Atemplate<>
6622526SN/AFault
6632526SN/ATimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
6642526SN/A{
6652526SN/A    return write(*(uint64_t*)&data, addr, flags, res);
6662526SN/A}
6672526SN/A
6682526SN/Atemplate<>
6692526SN/AFault
6702526SN/ATimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
6712526SN/A{
6722526SN/A    return write(*(uint32_t*)&data, addr, flags, res);
6732526SN/A}
6742526SN/A
6752526SN/A
6762526SN/Atemplate<>
6772526SN/AFault
6782526SN/ATimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
6792526SN/A{
6802526SN/A    return write((uint32_t)data, addr, flags, res);
6812526SN/A}
6822526SN/A
6832526SN/A
6842526SN/Avoid
6852526SN/ATimingSimpleCPU::finishTranslation(WholeTranslationState *state)
6862526SN/A{
6872561SN/A    _status = Running;
6882561SN/A
6892469SN/A    if (state->getFault() != NoFault) {
6902526SN/A        if (state->isPrefetch()) {
6912526SN/A            state->setNoFault();
6922526SN/A        }
6932526SN/A        delete [] state->data;
6942561SN/A        state->deleteReqs();
6952561SN/A        translationFault(state->getFault());
6962526SN/A    } else {
6972526SN/A        if (!state->isSplit) {
6982526SN/A            sendData(state->mainReq, state->data, state->res,
6992526SN/A                     state->mode == BaseTLB::Read);
7002526SN/A        } else {
7012526SN/A            sendSplitData(state->sreqLow, state->sreqHigh, state->mainReq,
7022526SN/A                          state->data, state->mode == BaseTLB::Read);
7032526SN/A        }
7042526SN/A    }
7052526SN/A
7062526SN/A    delete state;
7072526SN/A}
7082526SN/A
7092526SN/A
7102526SN/Avoid
7112526SN/ATimingSimpleCPU::fetch()
7122526SN/A{
7132526SN/A    DPRINTF(SimpleCPU, "Fetch\n");
7142526SN/A
7152526SN/A    if (!curStaticInst || !curStaticInst->isDelayedCommit())
7162526SN/A        checkForInterrupts();
7172526SN/A
7182526SN/A    checkPcEventQueue();
7192526SN/A
7202469SN/A    // We must have just got suspended by a PC event
7212022SN/A    if (_status == Idle)
722        return;
723
724    TheISA::PCState pcState = thread->pcState();
725    bool needToFetch = !isRomMicroPC(pcState.microPC()) && !curMacroStaticInst;
726
727    if (needToFetch) {
728        Request *ifetch_req = new Request();
729        ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0);
730        setupFetchRequest(ifetch_req);
731        thread->itb->translateTiming(ifetch_req, tc, &fetchTranslation,
732                BaseTLB::Execute);
733    } else {
734        _status = IcacheWaitResponse;
735        completeIfetch(NULL);
736
737        numCycles += tickToCycles(curTick() - previousTick);
738        previousTick = curTick();
739    }
740}
741
742
743void
744TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc)
745{
746    if (fault == NoFault) {
747        ifetch_pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast);
748        ifetch_pkt->dataStatic(&inst);
749
750        if (!icachePort.sendTiming(ifetch_pkt)) {
751            // Need to wait for retry
752            _status = IcacheRetry;
753        } else {
754            // Need to wait for cache to respond
755            _status = IcacheWaitResponse;
756            // ownership of packet transferred to memory system
757            ifetch_pkt = NULL;
758        }
759    } else {
760        delete req;
761        // fetch fault: advance directly to next instruction (fault handler)
762        _status = Running;
763        advanceInst(fault);
764    }
765
766    numCycles += tickToCycles(curTick() - previousTick);
767    previousTick = curTick();
768}
769
770
771void
772TimingSimpleCPU::advanceInst(Fault fault)
773{
774    if (fault != NoFault || !stayAtPC)
775        advancePC(fault);
776
777    if (_status == Running) {
778        // kick off fetch of next instruction... callback from icache
779        // response will cause that instruction to be executed,
780        // keeping the CPU running.
781        fetch();
782    }
783}
784
785
786void
787TimingSimpleCPU::completeIfetch(PacketPtr pkt)
788{
789    DPRINTF(SimpleCPU, "Complete ICache Fetch\n");
790
791    // received a response from the icache: execute the received
792    // instruction
793
794    assert(!pkt || !pkt->isError());
795    assert(_status == IcacheWaitResponse);
796
797    _status = Running;
798
799    numCycles += tickToCycles(curTick() - previousTick);
800    previousTick = curTick();
801
802    if (getState() == SimObject::Draining) {
803        if (pkt) {
804            delete pkt->req;
805            delete pkt;
806        }
807
808        completeDrain();
809        return;
810    }
811
812    preExecute();
813    if (curStaticInst && curStaticInst->isMemRef()) {
814        // load or store: just send to dcache
815        Fault fault = curStaticInst->initiateAcc(this, traceData);
816
817        // If we're not running now the instruction will complete in a dcache
818        // response callback or the instruction faulted and has started an
819        // ifetch
820        if (_status == Running) {
821            if (fault != NoFault && traceData) {
822                // If there was a fault, we shouldn't trace this instruction.
823                delete traceData;
824                traceData = NULL;
825            }
826
827            postExecute();
828            // @todo remove me after debugging with legion done
829            if (curStaticInst && (!curStaticInst->isMicroop() ||
830                        curStaticInst->isFirstMicroop()))
831                instCnt++;
832            advanceInst(fault);
833        }
834    } else if (curStaticInst) {
835        // non-memory instruction: execute completely now
836        Fault fault = curStaticInst->execute(this, traceData);
837
838        // keep an instruction count
839        if (fault == NoFault)
840            countInst();
841        else if (traceData && !DTRACE(ExecFaulting)) {
842            delete traceData;
843            traceData = NULL;
844        }
845
846        postExecute();
847        // @todo remove me after debugging with legion done
848        if (curStaticInst && (!curStaticInst->isMicroop() ||
849                    curStaticInst->isFirstMicroop()))
850            instCnt++;
851        advanceInst(fault);
852    } else {
853        advanceInst(NoFault);
854    }
855
856    if (pkt) {
857        delete pkt->req;
858        delete pkt;
859    }
860}
861
862void
863TimingSimpleCPU::IcachePort::ITickEvent::process()
864{
865    cpu->completeIfetch(pkt);
866}
867
868bool
869TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt)
870{
871    if (pkt->isResponse() && !pkt->wasNacked()) {
872        // delay processing of returned data until next CPU clock edge
873        Tick next_tick = cpu->nextCycle(curTick());
874
875        if (next_tick == curTick())
876            cpu->completeIfetch(pkt);
877        else
878            tickEvent.schedule(pkt, next_tick);
879
880        return true;
881    }
882    else if (pkt->wasNacked()) {
883        assert(cpu->_status == IcacheWaitResponse);
884        pkt->reinitNacked();
885        if (!sendTiming(pkt)) {
886            cpu->_status = IcacheRetry;
887            cpu->ifetch_pkt = pkt;
888        }
889    }
890    //Snooping a Coherence Request, do nothing
891    return true;
892}
893
894void
895TimingSimpleCPU::IcachePort::recvRetry()
896{
897    // we shouldn't get a retry unless we have a packet that we're
898    // waiting to transmit
899    assert(cpu->ifetch_pkt != NULL);
900    assert(cpu->_status == IcacheRetry);
901    PacketPtr tmp = cpu->ifetch_pkt;
902    if (sendTiming(tmp)) {
903        cpu->_status = IcacheWaitResponse;
904        cpu->ifetch_pkt = NULL;
905    }
906}
907
908void
909TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
910{
911    // received a response from the dcache: complete the load or store
912    // instruction
913    assert(!pkt->isError());
914    assert(_status == DcacheWaitResponse || _status == DTBWaitResponse ||
915           pkt->req->getFlags().isSet(Request::NO_ACCESS));
916
917    numCycles += tickToCycles(curTick() - previousTick);
918    previousTick = curTick();
919
920    if (pkt->senderState) {
921        SplitFragmentSenderState * send_state =
922            dynamic_cast<SplitFragmentSenderState *>(pkt->senderState);
923        assert(send_state);
924        delete pkt->req;
925        delete pkt;
926        PacketPtr big_pkt = send_state->bigPkt;
927        delete send_state;
928
929        SplitMainSenderState * main_send_state =
930            dynamic_cast<SplitMainSenderState *>(big_pkt->senderState);
931        assert(main_send_state);
932        // Record the fact that this packet is no longer outstanding.
933        assert(main_send_state->outstanding != 0);
934        main_send_state->outstanding--;
935
936        if (main_send_state->outstanding) {
937            return;
938        } else {
939            delete main_send_state;
940            big_pkt->senderState = NULL;
941            pkt = big_pkt;
942        }
943    }
944
945    _status = Running;
946
947    Fault fault = curStaticInst->completeAcc(pkt, this, traceData);
948
949    // keep an instruction count
950    if (fault == NoFault)
951        countInst();
952    else if (traceData) {
953        // If there was a fault, we shouldn't trace this instruction.
954        delete traceData;
955        traceData = NULL;
956    }
957
958    // the locked flag may be cleared on the response packet, so check
959    // pkt->req and not pkt to see if it was a load-locked
960    if (pkt->isRead() && pkt->req->isLLSC()) {
961        TheISA::handleLockedRead(thread, pkt->req);
962    }
963
964    delete pkt->req;
965    delete pkt;
966
967    postExecute();
968
969    if (getState() == SimObject::Draining) {
970        advancePC(fault);
971        completeDrain();
972
973        return;
974    }
975
976    advanceInst(fault);
977}
978
979
980void
981TimingSimpleCPU::completeDrain()
982{
983    DPRINTF(Config, "Done draining\n");
984    changeState(SimObject::Drained);
985    drainEvent->process();
986}
987
988void
989TimingSimpleCPU::DcachePort::setPeer(Port *port)
990{
991    Port::setPeer(port);
992
993#if FULL_SYSTEM
994    // Update the ThreadContext's memory ports (Functional/Virtual
995    // Ports)
996    cpu->tcBase()->connectMemPorts(cpu->tcBase());
997#endif
998}
999
1000bool
1001TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
1002{
1003    if (pkt->isResponse() && !pkt->wasNacked()) {
1004        // delay processing of returned data until next CPU clock edge
1005        Tick next_tick = cpu->nextCycle(curTick());
1006
1007        if (next_tick == curTick()) {
1008            cpu->completeDataAccess(pkt);
1009        } else {
1010            if (!tickEvent.scheduled()) {
1011                tickEvent.schedule(pkt, next_tick);
1012            } else {
1013                // In the case of a split transaction and a cache that is
1014                // faster than a CPU we could get two responses before
1015                // next_tick expires
1016                if (!retryEvent.scheduled())
1017                    schedule(retryEvent, next_tick);
1018                return false;
1019            }
1020        }
1021
1022        return true;
1023    }
1024    else if (pkt->wasNacked()) {
1025        assert(cpu->_status == DcacheWaitResponse);
1026        pkt->reinitNacked();
1027        if (!sendTiming(pkt)) {
1028            cpu->_status = DcacheRetry;
1029            cpu->dcache_pkt = pkt;
1030        }
1031    }
1032    //Snooping a Coherence Request, do nothing
1033    return true;
1034}
1035
1036void
1037TimingSimpleCPU::DcachePort::DTickEvent::process()
1038{
1039    cpu->completeDataAccess(pkt);
1040}
1041
1042void
1043TimingSimpleCPU::DcachePort::recvRetry()
1044{
1045    // we shouldn't get a retry unless we have a packet that we're
1046    // waiting to transmit
1047    assert(cpu->dcache_pkt != NULL);
1048    assert(cpu->_status == DcacheRetry);
1049    PacketPtr tmp = cpu->dcache_pkt;
1050    if (tmp->senderState) {
1051        // This is a packet from a split access.
1052        SplitFragmentSenderState * send_state =
1053            dynamic_cast<SplitFragmentSenderState *>(tmp->senderState);
1054        assert(send_state);
1055        PacketPtr big_pkt = send_state->bigPkt;
1056
1057        SplitMainSenderState * main_send_state =
1058            dynamic_cast<SplitMainSenderState *>(big_pkt->senderState);
1059        assert(main_send_state);
1060
1061        if (sendTiming(tmp)) {
1062            // If we were able to send without retrying, record that fact
1063            // and try sending the other fragment.
1064            send_state->clearFromParent();
1065            int other_index = main_send_state->getPendingFragment();
1066            if (other_index > 0) {
1067                tmp = main_send_state->fragments[other_index];
1068                cpu->dcache_pkt = tmp;
1069                if ((big_pkt->isRead() && cpu->handleReadPacket(tmp)) ||
1070                        (big_pkt->isWrite() && cpu->handleWritePacket())) {
1071                    main_send_state->fragments[other_index] = NULL;
1072                }
1073            } else {
1074                cpu->_status = DcacheWaitResponse;
1075                // memory system takes ownership of packet
1076                cpu->dcache_pkt = NULL;
1077            }
1078        }
1079    } else if (sendTiming(tmp)) {
1080        cpu->_status = DcacheWaitResponse;
1081        // memory system takes ownership of packet
1082        cpu->dcache_pkt = NULL;
1083    }
1084}
1085
1086TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu,
1087    Tick t)
1088    : pkt(_pkt), cpu(_cpu)
1089{
1090    cpu->schedule(this, t);
1091}
1092
1093void
1094TimingSimpleCPU::IprEvent::process()
1095{
1096    cpu->completeDataAccess(pkt);
1097}
1098
1099const char *
1100TimingSimpleCPU::IprEvent::description() const
1101{
1102    return "Timing Simple CPU Delay IPR event";
1103}
1104
1105
1106void
1107TimingSimpleCPU::printAddr(Addr a)
1108{
1109    dcachePort.printAddr(a);
1110}
1111
1112
1113////////////////////////////////////////////////////////////////////////
1114//
1115//  TimingSimpleCPU Simulation Object
1116//
1117TimingSimpleCPU *
1118TimingSimpleCPUParams::create()
1119{
1120    numThreads = 1;
1121#if !FULL_SYSTEM
1122    if (workload.size() != 1)
1123        panic("only one workload allowed");
1124#endif
1125    return new TimingSimpleCPU(this);
1126}
1127