atomic.cc revision 5496
111106Spower.jg@gmail.com/*
211106Spower.jg@gmail.com * Copyright (c) 2002-2005 The Regents of The University of Michigan
311106Spower.jg@gmail.com * All rights reserved.
411106Spower.jg@gmail.com *
511106Spower.jg@gmail.com * Redistribution and use in source and binary forms, with or without
611106Spower.jg@gmail.com * modification, are permitted provided that the following conditions are
711106Spower.jg@gmail.com * met: redistributions of source code must retain the above copyright
811106Spower.jg@gmail.com * notice, this list of conditions and the following disclaimer;
911106Spower.jg@gmail.com * redistributions in binary form must reproduce the above copyright
1011106Spower.jg@gmail.com * notice, this list of conditions and the following disclaimer in the
1111106Spower.jg@gmail.com * documentation and/or other materials provided with the distribution;
1211106Spower.jg@gmail.com * neither the name of the copyright holders nor the names of its
1311106Spower.jg@gmail.com * contributors may be used to endorse or promote products derived from
1411106Spower.jg@gmail.com * this software without specific prior written permission.
1511106Spower.jg@gmail.com *
1611106Spower.jg@gmail.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1711570SCurtis.Dunham@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1811106Spower.jg@gmail.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1911312Santhony.gutierrez@amd.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2011106Spower.jg@gmail.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2111106Spower.jg@gmail.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2211106Spower.jg@gmail.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2311106Spower.jg@gmail.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2411106Spower.jg@gmail.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2511106Spower.jg@gmail.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2611680SCurtis.Dunham@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2711106Spower.jg@gmail.com *
2811106Spower.jg@gmail.com * Authors: Steve Reinhardt
2911219Snilay@cs.wisc.edu */
3011106Spower.jg@gmail.com
3111570SCurtis.Dunham@arm.com#include "arch/locked_mem.hh"
3211570SCurtis.Dunham@arm.com#include "arch/mmaped_ipr.hh"
3311570SCurtis.Dunham@arm.com#include "arch/utility.hh"
3411570SCurtis.Dunham@arm.com#include "base/bigint.hh"
3511106Spower.jg@gmail.com#include "cpu/exetrace.hh"
3611106Spower.jg@gmail.com#include "cpu/simple/atomic.hh"
3711440SCurtis.Dunham@arm.com#include "mem/packet.hh"
3811440SCurtis.Dunham@arm.com#include "mem/packet_access.hh"
3911106Spower.jg@gmail.com#include "params/AtomicSimpleCPU.hh"
4011106Spower.jg@gmail.com#include "sim/system.hh"
4111106Spower.jg@gmail.com
4211106Spower.jg@gmail.comusing namespace std;
4311106Spower.jg@gmail.comusing namespace TheISA;
4411106Spower.jg@gmail.com
4511106Spower.jg@gmail.comAtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c)
4611106Spower.jg@gmail.com    : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
4711106Spower.jg@gmail.com{
4811106Spower.jg@gmail.com}
4911106Spower.jg@gmail.com
5011106Spower.jg@gmail.com
5111106Spower.jg@gmail.comvoid
5211106Spower.jg@gmail.comAtomicSimpleCPU::TickEvent::process()
5311106Spower.jg@gmail.com{
5411106Spower.jg@gmail.com    cpu->tick();
5511106Spower.jg@gmail.com}
5611106Spower.jg@gmail.com
5711106Spower.jg@gmail.comconst char *
5811106Spower.jg@gmail.comAtomicSimpleCPU::TickEvent::description() const
5911106Spower.jg@gmail.com{
6011106Spower.jg@gmail.com    return "AtomicSimpleCPU tick";
6111106Spower.jg@gmail.com}
6211106Spower.jg@gmail.com
6311106Spower.jg@gmail.comPort *
6411106Spower.jg@gmail.comAtomicSimpleCPU::getPort(const std::string &if_name, int idx)
6511106Spower.jg@gmail.com{
6611106Spower.jg@gmail.com    if (if_name == "dcache_port")
6711106Spower.jg@gmail.com        return &dcachePort;
6811106Spower.jg@gmail.com    else if (if_name == "icache_port")
6911570SCurtis.Dunham@arm.com        return &icachePort;
7011106Spower.jg@gmail.com    else if (if_name == "physmem_port") {
7111106Spower.jg@gmail.com        hasPhysMemPort = true;
7211106Spower.jg@gmail.com        return &physmemPort;
7311106Spower.jg@gmail.com    }
7411106Spower.jg@gmail.com    else
7511106Spower.jg@gmail.com        panic("No Such Port\n");
7611106Spower.jg@gmail.com}
7711106Spower.jg@gmail.com
7811106Spower.jg@gmail.comvoid
7911106Spower.jg@gmail.comAtomicSimpleCPU::init()
8011106Spower.jg@gmail.com{
8111106Spower.jg@gmail.com    BaseCPU::init();
8211106Spower.jg@gmail.com    cpuId = tc->readCpuId();
8311106Spower.jg@gmail.com#if FULL_SYSTEM
8411106Spower.jg@gmail.com    for (int i = 0; i < threadContexts.size(); ++i) {
8511570SCurtis.Dunham@arm.com        ThreadContext *tc = threadContexts[i];
8611570SCurtis.Dunham@arm.com
8711570SCurtis.Dunham@arm.com        // initialize CPU, including PC
8811570SCurtis.Dunham@arm.com        TheISA::initCPU(tc, cpuId);
8911106Spower.jg@gmail.com    }
9011106Spower.jg@gmail.com#endif
9111106Spower.jg@gmail.com    if (hasPhysMemPort) {
9211106Spower.jg@gmail.com        bool snoop = false;
9311106Spower.jg@gmail.com        AddrRangeList pmAddrList;
9411106Spower.jg@gmail.com        physmemPort.getPeerAddressRanges(pmAddrList, snoop);
9511106Spower.jg@gmail.com        physMemAddr = *pmAddrList.begin();
9611106Spower.jg@gmail.com    }
9711106Spower.jg@gmail.com    ifetch_req.setThreadContext(cpuId, 0); // Add thread ID if we add MT
9811106Spower.jg@gmail.com    data_read_req.setThreadContext(cpuId, 0); // Add thread ID here too
9911106Spower.jg@gmail.com    data_write_req.setThreadContext(cpuId, 0); // Add thread ID here too
10011106Spower.jg@gmail.com}
10111106Spower.jg@gmail.com
10211106Spower.jg@gmail.combool
10311680SCurtis.Dunham@arm.comAtomicSimpleCPU::CpuPort::recvTiming(PacketPtr pkt)
10411106Spower.jg@gmail.com{
10511106Spower.jg@gmail.com    panic("AtomicSimpleCPU doesn't expect recvTiming callback!");
10611219Snilay@cs.wisc.edu    return true;
10711570SCurtis.Dunham@arm.com}
10811106Spower.jg@gmail.com
10911106Spower.jg@gmail.comTick
11011106Spower.jg@gmail.comAtomicSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
11111106Spower.jg@gmail.com{
11211106Spower.jg@gmail.com    //Snooping a coherence request, just return
11311106Spower.jg@gmail.com    return 0;
11411570SCurtis.Dunham@arm.com}
11511570SCurtis.Dunham@arm.com
11611570SCurtis.Dunham@arm.comvoid
11711570SCurtis.Dunham@arm.comAtomicSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
11811106Spower.jg@gmail.com{
11911106Spower.jg@gmail.com    //No internal storage to update, just return
12011106Spower.jg@gmail.com    return;
12111106Spower.jg@gmail.com}
12211106Spower.jg@gmail.com
12311106Spower.jg@gmail.comvoid
12411106Spower.jg@gmail.comAtomicSimpleCPU::CpuPort::recvStatusChange(Status status)
12511106Spower.jg@gmail.com{
12611106Spower.jg@gmail.com    if (status == RangeChange) {
12711219Snilay@cs.wisc.edu        if (!snoopRangeSent) {
12811106Spower.jg@gmail.com            snoopRangeSent = true;
12911106Spower.jg@gmail.com            sendStatusChange(Port::RangeChange);
13011106Spower.jg@gmail.com        }
13111106Spower.jg@gmail.com        return;
13211106Spower.jg@gmail.com    }
13311106Spower.jg@gmail.com
13411106Spower.jg@gmail.com    panic("AtomicSimpleCPU doesn't expect recvStatusChange callback!");
13511106Spower.jg@gmail.com}
13611570SCurtis.Dunham@arm.com
13711106Spower.jg@gmail.comvoid
13811106Spower.jg@gmail.comAtomicSimpleCPU::CpuPort::recvRetry()
13911570SCurtis.Dunham@arm.com{
14011570SCurtis.Dunham@arm.com    panic("AtomicSimpleCPU doesn't expect recvRetry callback!");
14111570SCurtis.Dunham@arm.com}
14211570SCurtis.Dunham@arm.com
14311106Spower.jg@gmail.comvoid
14411106Spower.jg@gmail.comAtomicSimpleCPU::DcachePort::setPeer(Port *port)
14511106Spower.jg@gmail.com{
14611106Spower.jg@gmail.com    Port::setPeer(port);
14711106Spower.jg@gmail.com
14811106Spower.jg@gmail.com#if FULL_SYSTEM
14911106Spower.jg@gmail.com    // Update the ThreadContext's memory ports (Functional/Virtual
15011106Spower.jg@gmail.com    // Ports)
15111106Spower.jg@gmail.com    cpu->tcBase()->connectMemPorts();
15211106Spower.jg@gmail.com#endif
15311106Spower.jg@gmail.com}
15411680SCurtis.Dunham@arm.com
15511106Spower.jg@gmail.comAtomicSimpleCPU::AtomicSimpleCPU(Params *p)
15611106Spower.jg@gmail.com    : BaseSimpleCPU(p), tickEvent(this), width(p->width),
15711219Snilay@cs.wisc.edu      simulate_data_stalls(p->simulate_data_stalls),
15811570SCurtis.Dunham@arm.com      simulate_inst_stalls(p->simulate_inst_stalls),
15911106Spower.jg@gmail.com      icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this),
16011106Spower.jg@gmail.com      physmemPort(name() + "-iport", this), hasPhysMemPort(false)
16111106Spower.jg@gmail.com{
16211106Spower.jg@gmail.com    _status = Idle;
16311106Spower.jg@gmail.com
16411106Spower.jg@gmail.com    icachePort.snoopRangeSent = false;
16511570SCurtis.Dunham@arm.com    dcachePort.snoopRangeSent = false;
16611570SCurtis.Dunham@arm.com
16711570SCurtis.Dunham@arm.com}
16811570SCurtis.Dunham@arm.com
16911106Spower.jg@gmail.com
17011106Spower.jg@gmail.comAtomicSimpleCPU::~AtomicSimpleCPU()
17111106Spower.jg@gmail.com{
17211106Spower.jg@gmail.com}
17311106Spower.jg@gmail.com
17411106Spower.jg@gmail.comvoid
17511106Spower.jg@gmail.comAtomicSimpleCPU::serialize(ostream &os)
17611106Spower.jg@gmail.com{
17711106Spower.jg@gmail.com    SimObject::State so_state = SimObject::getState();
17811219Snilay@cs.wisc.edu    SERIALIZE_ENUM(so_state);
17911106Spower.jg@gmail.com    BaseSimpleCPU::serialize(os);
18011106Spower.jg@gmail.com    nameOut(os, csprintf("%s.tickEvent", name()));
18111106Spower.jg@gmail.com    tickEvent.serialize(os);
18211106Spower.jg@gmail.com}
18311106Spower.jg@gmail.com
18411106Spower.jg@gmail.comvoid
18511106Spower.jg@gmail.comAtomicSimpleCPU::unserialize(Checkpoint *cp, const string &section)
18611106Spower.jg@gmail.com{
18711570SCurtis.Dunham@arm.com    SimObject::State so_state;
18811106Spower.jg@gmail.com    UNSERIALIZE_ENUM(so_state);
18911106Spower.jg@gmail.com    BaseSimpleCPU::unserialize(cp, section);
19011570SCurtis.Dunham@arm.com    tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
19111570SCurtis.Dunham@arm.com}
19211570SCurtis.Dunham@arm.com
19311570SCurtis.Dunham@arm.comvoid
19411106Spower.jg@gmail.comAtomicSimpleCPU::resume()
19511106Spower.jg@gmail.com{
19611106Spower.jg@gmail.com    if (_status == Idle || _status == SwitchedOut)
19711106Spower.jg@gmail.com        return;
19811106Spower.jg@gmail.com
19911106Spower.jg@gmail.com    DPRINTF(SimpleCPU, "Resume\n");
20011106Spower.jg@gmail.com    assert(system->getMemoryMode() == Enums::atomic);
20111106Spower.jg@gmail.com
20211106Spower.jg@gmail.com    changeState(SimObject::Running);
20311106Spower.jg@gmail.com    if (thread->status() == ThreadContext::Active) {
20411106Spower.jg@gmail.com        if (!tickEvent.scheduled()) {
20511106Spower.jg@gmail.com            tickEvent.schedule(nextCycle());
20611106Spower.jg@gmail.com        }
20711106Spower.jg@gmail.com    }
20811106Spower.jg@gmail.com}
20911106Spower.jg@gmail.com
21011106Spower.jg@gmail.comvoid
21111106Spower.jg@gmail.comAtomicSimpleCPU::switchOut()
21211106Spower.jg@gmail.com{
21311106Spower.jg@gmail.com    assert(_status == Running || _status == Idle);
21411106Spower.jg@gmail.com    _status = SwitchedOut;
21511106Spower.jg@gmail.com
21611106Spower.jg@gmail.com    tickEvent.squash();
21711106Spower.jg@gmail.com}
21811106Spower.jg@gmail.com
21911106Spower.jg@gmail.com
22011106Spower.jg@gmail.comvoid
22111106Spower.jg@gmail.comAtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
22211106Spower.jg@gmail.com{
22311106Spower.jg@gmail.com    BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
22411106Spower.jg@gmail.com
22511106Spower.jg@gmail.com    assert(!tickEvent.scheduled());
22611106Spower.jg@gmail.com
22711106Spower.jg@gmail.com    // if any of this CPU's ThreadContexts are active, mark the CPU as
22811106Spower.jg@gmail.com    // running and schedule its tick event.
22911106Spower.jg@gmail.com    for (int i = 0; i < threadContexts.size(); ++i) {
23011106Spower.jg@gmail.com        ThreadContext *tc = threadContexts[i];
23111106Spower.jg@gmail.com        if (tc->status() == ThreadContext::Active && _status != Running) {
23211106Spower.jg@gmail.com            _status = Running;
23311106Spower.jg@gmail.com            tickEvent.schedule(nextCycle());
23411106Spower.jg@gmail.com            break;
23511106Spower.jg@gmail.com        }
23611106Spower.jg@gmail.com    }
23711106Spower.jg@gmail.com    if (_status != Running) {
23811106Spower.jg@gmail.com        _status = Idle;
23911106Spower.jg@gmail.com    }
24011106Spower.jg@gmail.com    assert(threadContexts.size() == 1);
24111106Spower.jg@gmail.com    cpuId = tc->readCpuId();
24211106Spower.jg@gmail.com    ifetch_req.setThreadContext(cpuId, 0); // Add thread ID if we add MT
24311106Spower.jg@gmail.com    data_read_req.setThreadContext(cpuId, 0); // Add thread ID here too
24411106Spower.jg@gmail.com    data_write_req.setThreadContext(cpuId, 0); // Add thread ID here too
24511106Spower.jg@gmail.com}
24611106Spower.jg@gmail.com
24711219Snilay@cs.wisc.edu
24811106Spower.jg@gmail.comvoid
24911570SCurtis.Dunham@arm.comAtomicSimpleCPU::activateContext(int thread_num, int delay)
25011106Spower.jg@gmail.com{
25111106Spower.jg@gmail.com    DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay);
25211106Spower.jg@gmail.com
25311570SCurtis.Dunham@arm.com    assert(thread_num == 0);
25411570SCurtis.Dunham@arm.com    assert(thread);
25511570SCurtis.Dunham@arm.com
25611440SCurtis.Dunham@arm.com    assert(_status == Idle);
25711570SCurtis.Dunham@arm.com    assert(!tickEvent.scheduled());
25811106Spower.jg@gmail.com
25911219Snilay@cs.wisc.edu    notIdleFraction++;
26011106Spower.jg@gmail.com    numCycles += tickToCycles(thread->lastActivate - thread->lastSuspend);
26111106Spower.jg@gmail.com
26211106Spower.jg@gmail.com    //Make sure ticks are still on multiples of cycles
26311106Spower.jg@gmail.com    tickEvent.schedule(nextCycle(curTick + ticks(delay)));
26411106Spower.jg@gmail.com    _status = Running;
26511106Spower.jg@gmail.com}
26611106Spower.jg@gmail.com
26711219Snilay@cs.wisc.edu
26811219Snilay@cs.wisc.eduvoid
26911219Snilay@cs.wisc.eduAtomicSimpleCPU::suspendContext(int thread_num)
27011219Snilay@cs.wisc.edu{
27111219Snilay@cs.wisc.edu    DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
27211219Snilay@cs.wisc.edu
27311219Snilay@cs.wisc.edu    assert(thread_num == 0);
27411106Spower.jg@gmail.com    assert(thread);
27511106Spower.jg@gmail.com
27611106Spower.jg@gmail.com    assert(_status == Running);
27711680SCurtis.Dunham@arm.com
27811106Spower.jg@gmail.com    // tick event may not be scheduled if this gets called from inside
27911106Spower.jg@gmail.com    // an instruction's execution, e.g. "quiesce"
28011219Snilay@cs.wisc.edu    if (tickEvent.scheduled())
28111570SCurtis.Dunham@arm.com        tickEvent.deschedule();
28211106Spower.jg@gmail.com
28311106Spower.jg@gmail.com    notIdleFraction--;
28411106Spower.jg@gmail.com    _status = Idle;
28511106Spower.jg@gmail.com}
28611106Spower.jg@gmail.com
28711106Spower.jg@gmail.com
28811570SCurtis.Dunham@arm.comtemplate <class T>
28911570SCurtis.Dunham@arm.comFault
29011570SCurtis.Dunham@arm.comAtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
29111570SCurtis.Dunham@arm.com{
29211106Spower.jg@gmail.com    // use the CPU's statically allocated read request and packet objects
29311106Spower.jg@gmail.com    Request *req = &data_read_req;
29411106Spower.jg@gmail.com
29511106Spower.jg@gmail.com    if (traceData) {
29611106Spower.jg@gmail.com        traceData->setAddr(addr);
29711106Spower.jg@gmail.com    }
29811106Spower.jg@gmail.com
29911106Spower.jg@gmail.com    //The block size of our peer.
30011106Spower.jg@gmail.com    int blockSize = dcachePort.peerBlockSize();
30111219Snilay@cs.wisc.edu    //The size of the data we're trying to read.
30211106Spower.jg@gmail.com    int dataSize = sizeof(T);
30311106Spower.jg@gmail.com
30411106Spower.jg@gmail.com    uint8_t * dataPtr = (uint8_t *)&data;
30511106Spower.jg@gmail.com
30611106Spower.jg@gmail.com    //The address of the second part of this access if it needs to be split
30711106Spower.jg@gmail.com    //across a cache line boundary.
30811106Spower.jg@gmail.com    Addr secondAddr = roundDown(addr + dataSize - 1, blockSize);
30911106Spower.jg@gmail.com
31011570SCurtis.Dunham@arm.com    if(secondAddr > addr)
31111106Spower.jg@gmail.com        dataSize = secondAddr - addr;
31211106Spower.jg@gmail.com
31311570SCurtis.Dunham@arm.com    dcache_latency = 0;
31411570SCurtis.Dunham@arm.com
31511570SCurtis.Dunham@arm.com    while(1) {
31611570SCurtis.Dunham@arm.com        req->setVirt(0, addr, dataSize, flags, thread->readPC());
31711106Spower.jg@gmail.com
31811106Spower.jg@gmail.com        // translate to physical address
31911106Spower.jg@gmail.com        Fault fault = thread->translateDataReadReq(req);
32011106Spower.jg@gmail.com
32111106Spower.jg@gmail.com        // Now do the access.
32211680SCurtis.Dunham@arm.com        if (fault == NoFault) {
32311106Spower.jg@gmail.com            Packet pkt = Packet(req,
32411680SCurtis.Dunham@arm.com                    req->isLocked() ? MemCmd::LoadLockedReq : MemCmd::ReadReq,
32511106Spower.jg@gmail.com                    Packet::Broadcast);
32611106Spower.jg@gmail.com            pkt.dataStatic(dataPtr);
32711106Spower.jg@gmail.com
32811680SCurtis.Dunham@arm.com            if (req->isMmapedIpr())
32911106Spower.jg@gmail.com                dcache_latency += TheISA::handleIprRead(thread->getTC(), &pkt);
33011680SCurtis.Dunham@arm.com            else {
33111106Spower.jg@gmail.com                if (hasPhysMemPort && pkt.getAddr() == physMemAddr)
33211106Spower.jg@gmail.com                    dcache_latency += physmemPort.sendAtomic(&pkt);
33311106Spower.jg@gmail.com                else
33411680SCurtis.Dunham@arm.com                    dcache_latency += dcachePort.sendAtomic(&pkt);
33511106Spower.jg@gmail.com            }
33611680SCurtis.Dunham@arm.com            dcache_access = true;
33711106Spower.jg@gmail.com
33811680SCurtis.Dunham@arm.com            assert(!pkt.isError());
33911106Spower.jg@gmail.com
34011680SCurtis.Dunham@arm.com            if (req->isLocked()) {
34111106Spower.jg@gmail.com                TheISA::handleLockedRead(thread, req);
34211680SCurtis.Dunham@arm.com            }
34311106Spower.jg@gmail.com        }
34411106Spower.jg@gmail.com
34511106Spower.jg@gmail.com        // This will need a new way to tell if it has a dcache attached.
34611106Spower.jg@gmail.com        if (req->isUncacheable())
34711106Spower.jg@gmail.com            recordEvent("Uncached Read");
34811106Spower.jg@gmail.com
34911106Spower.jg@gmail.com        //If there's a fault, return it
35011106Spower.jg@gmail.com        if (fault != NoFault)
35111106Spower.jg@gmail.com            return fault;
35211106Spower.jg@gmail.com        //If we don't need to access a second cache line, stop now.
35311106Spower.jg@gmail.com        if (secondAddr <= addr)
35411570SCurtis.Dunham@arm.com        {
35511106Spower.jg@gmail.com            data = gtoh(data);
35611106Spower.jg@gmail.com            if (traceData) {
35711106Spower.jg@gmail.com                traceData->setData(data);
35811106Spower.jg@gmail.com            }
35911106Spower.jg@gmail.com            return fault;
36011106Spower.jg@gmail.com        }
36111106Spower.jg@gmail.com
36211680SCurtis.Dunham@arm.com        /*
36311106Spower.jg@gmail.com         * Set up for accessing the second cache line.
36411106Spower.jg@gmail.com         */
36511106Spower.jg@gmail.com
36611106Spower.jg@gmail.com        //Move the pointer we're reading into to the correct location.
36711570SCurtis.Dunham@arm.com        dataPtr += dataSize;
36811570SCurtis.Dunham@arm.com        //Adjust the size to get the remaining bytes.
36911570SCurtis.Dunham@arm.com        dataSize = addr + sizeof(T) - secondAddr;
37011106Spower.jg@gmail.com        //And access the right address.
37111570SCurtis.Dunham@arm.com        addr = secondAddr;
37211680SCurtis.Dunham@arm.com    }
37311106Spower.jg@gmail.com}
37411106Spower.jg@gmail.com
37511106Spower.jg@gmail.comFault
37611106Spower.jg@gmail.comAtomicSimpleCPU::translateDataReadAddr(Addr vaddr, Addr & paddr,
37711106Spower.jg@gmail.com        int size, unsigned flags)
37811106Spower.jg@gmail.com{
37911106Spower.jg@gmail.com    // use the CPU's statically allocated read request and packet objects
38011106Spower.jg@gmail.com    Request *req = &data_read_req;
38111106Spower.jg@gmail.com
38211106Spower.jg@gmail.com    if (traceData) {
38311106Spower.jg@gmail.com        traceData->setAddr(vaddr);
38411106Spower.jg@gmail.com    }
38511106Spower.jg@gmail.com
38611106Spower.jg@gmail.com    //The block size of our peer.
38711106Spower.jg@gmail.com    int blockSize = dcachePort.peerBlockSize();
38811106Spower.jg@gmail.com    //The size of the data we're trying to read.
38911106Spower.jg@gmail.com    int dataSize = size;
39011106Spower.jg@gmail.com
39111106Spower.jg@gmail.com    bool firstTimeThrough = true;
39211106Spower.jg@gmail.com
39311106Spower.jg@gmail.com    //The address of the second part of this access if it needs to be split
39411680SCurtis.Dunham@arm.com    //across a cache line boundary.
39511106Spower.jg@gmail.com    Addr secondAddr = roundDown(vaddr + dataSize - 1, blockSize);
39611680SCurtis.Dunham@arm.com
39711106Spower.jg@gmail.com    if(secondAddr > vaddr)
39811106Spower.jg@gmail.com        dataSize = secondAddr - vaddr;
39911106Spower.jg@gmail.com
40011106Spower.jg@gmail.com    while(1) {
40111106Spower.jg@gmail.com        req->setVirt(0, vaddr, dataSize, flags, thread->readPC());
40211106Spower.jg@gmail.com
40311106Spower.jg@gmail.com        // translate to physical address
40411106Spower.jg@gmail.com        Fault fault = thread->translateDataReadReq(req);
40511680SCurtis.Dunham@arm.com
40611106Spower.jg@gmail.com        //If there's a fault, return it
40711570SCurtis.Dunham@arm.com        if (fault != NoFault)
40811106Spower.jg@gmail.com            return fault;
40911106Spower.jg@gmail.com
41011106Spower.jg@gmail.com        if (firstTimeThrough) {
41111570SCurtis.Dunham@arm.com            paddr = req->getPaddr();
41211570SCurtis.Dunham@arm.com            firstTimeThrough = false;
41311570SCurtis.Dunham@arm.com        }
41411440SCurtis.Dunham@arm.com
41511570SCurtis.Dunham@arm.com        //If we don't need to access a second cache line, stop now.
41611106Spower.jg@gmail.com        if (secondAddr <= vaddr)
41711680SCurtis.Dunham@arm.com            return fault;
41811106Spower.jg@gmail.com
41911106Spower.jg@gmail.com        /*
42011106Spower.jg@gmail.com         * Set up for accessing the second cache line.
42111106Spower.jg@gmail.com         */
42211106Spower.jg@gmail.com
42311106Spower.jg@gmail.com        //Adjust the size to get the remaining bytes.
42411106Spower.jg@gmail.com        dataSize = vaddr + size - secondAddr;
42511680SCurtis.Dunham@arm.com        //And access the right address.
42611680SCurtis.Dunham@arm.com        vaddr = secondAddr;
42711680SCurtis.Dunham@arm.com    }
42811680SCurtis.Dunham@arm.com}
42911680SCurtis.Dunham@arm.com
43011680SCurtis.Dunham@arm.com#ifndef DOXYGEN_SHOULD_SKIP_THIS
43111680SCurtis.Dunham@arm.com
432template
433Fault
434AtomicSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags);
435
436template
437Fault
438AtomicSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags);
439
440template
441Fault
442AtomicSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
443
444template
445Fault
446AtomicSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
447
448template
449Fault
450AtomicSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
451
452template
453Fault
454AtomicSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
455
456#endif //DOXYGEN_SHOULD_SKIP_THIS
457
458template<>
459Fault
460AtomicSimpleCPU::read(Addr addr, double &data, unsigned flags)
461{
462    return read(addr, *(uint64_t*)&data, flags);
463}
464
465template<>
466Fault
467AtomicSimpleCPU::read(Addr addr, float &data, unsigned flags)
468{
469    return read(addr, *(uint32_t*)&data, flags);
470}
471
472
473template<>
474Fault
475AtomicSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
476{
477    return read(addr, (uint32_t&)data, flags);
478}
479
480
481template <class T>
482Fault
483AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
484{
485    // use the CPU's statically allocated write request and packet objects
486    Request *req = &data_write_req;
487
488    if (traceData) {
489        traceData->setAddr(addr);
490    }
491
492    //The block size of our peer.
493    int blockSize = dcachePort.peerBlockSize();
494    //The size of the data we're trying to read.
495    int dataSize = sizeof(T);
496
497    uint8_t * dataPtr = (uint8_t *)&data;
498
499    //The address of the second part of this access if it needs to be split
500    //across a cache line boundary.
501    Addr secondAddr = roundDown(addr + dataSize - 1, blockSize);
502
503    if(secondAddr > addr)
504        dataSize = secondAddr - addr;
505
506    dcache_latency = 0;
507
508    while(1) {
509        req->setVirt(0, addr, dataSize, flags, thread->readPC());
510
511        // translate to physical address
512        Fault fault = thread->translateDataWriteReq(req);
513
514        // Now do the access.
515        if (fault == NoFault) {
516            MemCmd cmd = MemCmd::WriteReq; // default
517            bool do_access = true;  // flag to suppress cache access
518
519            if (req->isLocked()) {
520                cmd = MemCmd::StoreCondReq;
521                do_access = TheISA::handleLockedWrite(thread, req);
522            } else if (req->isSwap()) {
523                cmd = MemCmd::SwapReq;
524                if (req->isCondSwap()) {
525                    assert(res);
526                    req->setExtraData(*res);
527                }
528            }
529
530            if (do_access) {
531                Packet pkt = Packet(req, cmd, Packet::Broadcast);
532                pkt.dataStatic(dataPtr);
533
534                if (req->isMmapedIpr()) {
535                    dcache_latency +=
536                        TheISA::handleIprWrite(thread->getTC(), &pkt);
537                } else {
538                    //XXX This needs to be outside of the loop in order to
539                    //work properly for cache line boundary crossing
540                    //accesses in transendian simulations.
541                    data = htog(data);
542                    if (hasPhysMemPort && pkt.getAddr() == physMemAddr)
543                        dcache_latency += physmemPort.sendAtomic(&pkt);
544                    else
545                        dcache_latency += dcachePort.sendAtomic(&pkt);
546                }
547                dcache_access = true;
548                assert(!pkt.isError());
549
550                if (req->isSwap()) {
551                    assert(res);
552                    *res = pkt.get<T>();
553                }
554            }
555
556            if (res && !req->isSwap()) {
557                *res = req->getExtraData();
558            }
559        }
560
561        // This will need a new way to tell if it's hooked up to a cache or not.
562        if (req->isUncacheable())
563            recordEvent("Uncached Write");
564
565        //If there's a fault or we don't need to access a second cache line,
566        //stop now.
567        if (fault != NoFault || secondAddr <= addr)
568        {
569            // If the write needs to have a fault on the access, consider
570            // calling changeStatus() and changing it to "bad addr write"
571            // or something.
572            if (traceData) {
573                traceData->setData(data);
574            }
575            return fault;
576        }
577
578        /*
579         * Set up for accessing the second cache line.
580         */
581
582        //Move the pointer we're reading into to the correct location.
583        dataPtr += dataSize;
584        //Adjust the size to get the remaining bytes.
585        dataSize = addr + sizeof(T) - secondAddr;
586        //And access the right address.
587        addr = secondAddr;
588    }
589}
590
591Fault
592AtomicSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr,
593        int size, unsigned flags)
594{
595    // use the CPU's statically allocated write request and packet objects
596    Request *req = &data_write_req;
597
598    if (traceData) {
599        traceData->setAddr(vaddr);
600    }
601
602    //The block size of our peer.
603    int blockSize = dcachePort.peerBlockSize();
604
605    //The address of the second part of this access if it needs to be split
606    //across a cache line boundary.
607    Addr secondAddr = roundDown(vaddr + size - 1, blockSize);
608
609    //The size of the data we're trying to read.
610    int dataSize = size;
611
612    bool firstTimeThrough = true;
613
614    if(secondAddr > vaddr)
615        dataSize = secondAddr - vaddr;
616
617    dcache_latency = 0;
618
619    while(1) {
620        req->setVirt(0, vaddr, dataSize, flags, thread->readPC());
621
622        // translate to physical address
623        Fault fault = thread->translateDataWriteReq(req);
624
625        //If there's a fault or we don't need to access a second cache line,
626        //stop now.
627        if (fault != NoFault)
628            return fault;
629
630        if (firstTimeThrough) {
631            paddr = req->getPaddr();
632            firstTimeThrough = false;
633        }
634
635        if (secondAddr <= vaddr)
636            return fault;
637
638        /*
639         * Set up for accessing the second cache line.
640         */
641
642        //Adjust the size to get the remaining bytes.
643        dataSize = vaddr + size - secondAddr;
644        //And access the right address.
645        vaddr = secondAddr;
646    }
647}
648
649
650#ifndef DOXYGEN_SHOULD_SKIP_THIS
651
652template
653Fault
654AtomicSimpleCPU::write(Twin32_t data, Addr addr,
655                       unsigned flags, uint64_t *res);
656
657template
658Fault
659AtomicSimpleCPU::write(Twin64_t data, Addr addr,
660                       unsigned flags, uint64_t *res);
661
662template
663Fault
664AtomicSimpleCPU::write(uint64_t data, Addr addr,
665                       unsigned flags, uint64_t *res);
666
667template
668Fault
669AtomicSimpleCPU::write(uint32_t data, Addr addr,
670                       unsigned flags, uint64_t *res);
671
672template
673Fault
674AtomicSimpleCPU::write(uint16_t data, Addr addr,
675                       unsigned flags, uint64_t *res);
676
677template
678Fault
679AtomicSimpleCPU::write(uint8_t data, Addr addr,
680                       unsigned flags, uint64_t *res);
681
682#endif //DOXYGEN_SHOULD_SKIP_THIS
683
684template<>
685Fault
686AtomicSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
687{
688    return write(*(uint64_t*)&data, addr, flags, res);
689}
690
691template<>
692Fault
693AtomicSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
694{
695    return write(*(uint32_t*)&data, addr, flags, res);
696}
697
698
699template<>
700Fault
701AtomicSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
702{
703    return write((uint32_t)data, addr, flags, res);
704}
705
706
707void
708AtomicSimpleCPU::tick()
709{
710    DPRINTF(SimpleCPU, "Tick\n");
711
712    Tick latency = 0;
713
714    for (int i = 0; i < width; ++i) {
715        numCycles++;
716
717        if (!curStaticInst || !curStaticInst->isDelayedCommit())
718            checkForInterrupts();
719
720        checkPcEventQueue();
721
722        Fault fault = setupFetchRequest(&ifetch_req);
723
724        if (fault == NoFault) {
725            Tick icache_latency = 0;
726            bool icache_access = false;
727            dcache_access = false; // assume no dcache access
728
729            //Fetch more instruction memory if necessary
730            //if(predecoder.needMoreBytes())
731            //{
732                icache_access = true;
733                Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq,
734                                           Packet::Broadcast);
735                ifetch_pkt.dataStatic(&inst);
736
737                if (hasPhysMemPort && ifetch_pkt.getAddr() == physMemAddr)
738                    icache_latency = physmemPort.sendAtomic(&ifetch_pkt);
739                else
740                    icache_latency = icachePort.sendAtomic(&ifetch_pkt);
741
742                assert(!ifetch_pkt.isError());
743
744                // ifetch_req is initialized to read the instruction directly
745                // into the CPU object's inst field.
746            //}
747
748            preExecute();
749
750            if (curStaticInst) {
751                fault = curStaticInst->execute(this, traceData);
752
753                // keep an instruction count
754                if (fault == NoFault)
755                    countInst();
756                else if (traceData) {
757                    // If there was a fault, we should trace this instruction.
758                    delete traceData;
759                    traceData = NULL;
760                }
761
762                postExecute();
763            }
764
765            // @todo remove me after debugging with legion done
766            if (curStaticInst && (!curStaticInst->isMicroop() ||
767                        curStaticInst->isFirstMicroop()))
768                instCnt++;
769
770            Tick stall_ticks = 0;
771            if (simulate_inst_stalls && icache_access)
772                stall_ticks += icache_latency;
773
774            if (simulate_data_stalls && dcache_access)
775                stall_ticks += dcache_latency;
776
777            if (stall_ticks) {
778                Tick stall_cycles = stall_ticks / ticks(1);
779                Tick aligned_stall_ticks = ticks(stall_cycles);
780
781                if (aligned_stall_ticks < stall_ticks)
782                    aligned_stall_ticks += 1;
783
784                latency += aligned_stall_ticks;
785            }
786
787        }
788        if(fault != NoFault || !stayAtPC)
789            advancePC(fault);
790    }
791
792    // instruction takes at least one cycle
793    if (latency < ticks(1))
794        latency = ticks(1);
795
796    if (_status != Idle)
797        tickEvent.schedule(curTick + latency);
798}
799
800
801void
802AtomicSimpleCPU::printAddr(Addr a)
803{
804    dcachePort.printAddr(a);
805}
806
807
808////////////////////////////////////////////////////////////////////////
809//
810//  AtomicSimpleCPU Simulation Object
811//
812AtomicSimpleCPU *
813AtomicSimpleCPUParams::create()
814{
815    AtomicSimpleCPU::Params *params = new AtomicSimpleCPU::Params();
816    params->name = name;
817    params->numberOfThreads = 1;
818    params->max_insts_any_thread = max_insts_any_thread;
819    params->max_insts_all_threads = max_insts_all_threads;
820    params->max_loads_any_thread = max_loads_any_thread;
821    params->max_loads_all_threads = max_loads_all_threads;
822    params->progress_interval = progress_interval;
823    params->deferRegistration = defer_registration;
824    params->phase = phase;
825    params->clock = clock;
826    params->functionTrace = function_trace;
827    params->functionTraceStart = function_trace_start;
828    params->width = width;
829    params->simulate_data_stalls = simulate_data_stalls;
830    params->simulate_inst_stalls = simulate_inst_stalls;
831    params->system = system;
832    params->cpu_id = cpu_id;
833    params->tracer = tracer;
834
835    params->itb = itb;
836    params->dtb = dtb;
837#if FULL_SYSTEM
838    params->profile = profile;
839    params->do_quiesce = do_quiesce;
840    params->do_checkpoint_insts = do_checkpoint_insts;
841    params->do_statistics_insts = do_statistics_insts;
842#else
843    if (workload.size() != 1)
844        panic("only one workload allowed");
845    params->process = workload[0];
846#endif
847
848    AtomicSimpleCPU *cpu = new AtomicSimpleCPU(params);
849    return cpu;
850}
851