atomic.cc revision 7046:d21d575a6f99
16019Shines@cs.fsu.edu/*
211496Sandreas.sandberg@arm.com * Copyright (c) 2002-2005 The Regents of The University of Michigan
37093Sgblack@eecs.umich.edu * All rights reserved.
47093Sgblack@eecs.umich.edu *
57093Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
67093Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
77093Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
87093Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
97093Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
107093Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
117093Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
127093Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
137093Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
146019Shines@cs.fsu.edu * this software without specific prior written permission.
156019Shines@cs.fsu.edu *
166019Shines@cs.fsu.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176019Shines@cs.fsu.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186019Shines@cs.fsu.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196019Shines@cs.fsu.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206019Shines@cs.fsu.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216019Shines@cs.fsu.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226019Shines@cs.fsu.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236019Shines@cs.fsu.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246019Shines@cs.fsu.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256019Shines@cs.fsu.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266019Shines@cs.fsu.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276019Shines@cs.fsu.edu *
286019Shines@cs.fsu.edu * Authors: Steve Reinhardt
296019Shines@cs.fsu.edu */
306019Shines@cs.fsu.edu
316019Shines@cs.fsu.edu#include "arch/locked_mem.hh"
326019Shines@cs.fsu.edu#include "arch/mmaped_ipr.hh"
336019Shines@cs.fsu.edu#include "arch/utility.hh"
346019Shines@cs.fsu.edu#include "base/bigint.hh"
356019Shines@cs.fsu.edu#include "config/the_isa.hh"
366019Shines@cs.fsu.edu#include "cpu/exetrace.hh"
376019Shines@cs.fsu.edu#include "cpu/simple/atomic.hh"
386019Shines@cs.fsu.edu#include "mem/packet.hh"
396019Shines@cs.fsu.edu#include "mem/packet_access.hh"
406019Shines@cs.fsu.edu#include "params/AtomicSimpleCPU.hh"
416735Sgblack@eecs.umich.edu#include "sim/system.hh"
426735Sgblack@eecs.umich.edu
4310037SARM gem5 Developersusing namespace std;
4410037SARM gem5 Developersusing namespace TheISA;
456019Shines@cs.fsu.edu
466019Shines@cs.fsu.eduAtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c)
476019Shines@cs.fsu.edu    : Event(CPU_Tick_Pri), cpu(c)
4811793Sbrandon.potter@amd.com{
4911793Sbrandon.potter@amd.com}
5010037SARM gem5 Developers
5110037SARM gem5 Developers
5210037SARM gem5 Developersvoid
538229Snate@binkert.orgAtomicSimpleCPU::TickEvent::process()
548229Snate@binkert.org{
556019Shines@cs.fsu.edu    cpu->tick();
568232Snate@binkert.org}
578782Sgblack@eecs.umich.edu
586019Shines@cs.fsu.educonst char *
596019Shines@cs.fsu.eduAtomicSimpleCPU::TickEvent::description() const
606019Shines@cs.fsu.edu{
616019Shines@cs.fsu.edu    return "AtomicSimpleCPU tick";
6210037SARM gem5 Developers}
6310037SARM gem5 Developers
6410037SARM gem5 DevelopersPort *
6510037SARM gem5 DevelopersAtomicSimpleCPU::getPort(const string &if_name, int idx)
6610037SARM gem5 Developers{
6710037SARM gem5 Developers    if (if_name == "dcache_port")
6810037SARM gem5 Developers        return &dcachePort;
6910037SARM gem5 Developers    else if (if_name == "icache_port")
7010037SARM gem5 Developers        return &icachePort;
7110037SARM gem5 Developers    else if (if_name == "physmem_port") {
7210037SARM gem5 Developers        hasPhysMemPort = true;
7310037SARM gem5 Developers        return &physmemPort;
7410037SARM gem5 Developers    }
7510037SARM gem5 Developers    else
7610037SARM gem5 Developers        panic("No Such Port\n");
7710037SARM gem5 Developers}
7810037SARM gem5 Developers
7910037SARM gem5 Developersvoid
8010037SARM gem5 DevelopersAtomicSimpleCPU::init()
8110037SARM gem5 Developers{
8210037SARM gem5 Developers    BaseCPU::init();
8310037SARM gem5 Developers#if FULL_SYSTEM
8410037SARM gem5 Developers    ThreadID size = threadContexts.size();
8510037SARM gem5 Developers    for (ThreadID i = 0; i < size; ++i) {
8610037SARM gem5 Developers        ThreadContext *tc = threadContexts[i];
8710037SARM gem5 Developers
8810037SARM gem5 Developers        // initialize CPU, including PC
8910037SARM gem5 Developers        TheISA::initCPU(tc, tc->contextId());
9010037SARM gem5 Developers    }
9110037SARM gem5 Developers#endif
9210037SARM gem5 Developers    if (hasPhysMemPort) {
9310037SARM gem5 Developers        bool snoop = false;
9410037SARM gem5 Developers        AddrRangeList pmAddrList;
9510037SARM gem5 Developers        physmemPort.getPeerAddressRanges(pmAddrList, snoop);
9610037SARM gem5 Developers        physMemAddr = *pmAddrList.begin();
9710037SARM gem5 Developers    }
9810037SARM gem5 Developers    // Atomic doesn't do MT right now, so contextId == threadId
9910037SARM gem5 Developers    ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT
10010037SARM gem5 Developers    data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too
10110037SARM gem5 Developers    data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too
1026019Shines@cs.fsu.edu}
10310037SARM gem5 Developers
10410037SARM gem5 Developersbool
10510037SARM gem5 DevelopersAtomicSimpleCPU::CpuPort::recvTiming(PacketPtr pkt)
1066019Shines@cs.fsu.edu{
10710037SARM gem5 Developers    panic("AtomicSimpleCPU doesn't expect recvTiming callback!");
10810037SARM gem5 Developers    return true;
10910037SARM gem5 Developers}
11010037SARM gem5 Developers
11110037SARM gem5 DevelopersTick
11210037SARM gem5 DevelopersAtomicSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
11310037SARM gem5 Developers{
11410037SARM gem5 Developers    //Snooping a coherence request, just return
11510037SARM gem5 Developers    return 0;
11610037SARM gem5 Developers}
11710037SARM gem5 Developers
11810037SARM gem5 Developersvoid
11910037SARM gem5 DevelopersAtomicSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
12010037SARM gem5 Developers{
12110037SARM gem5 Developers    //No internal storage to update, just return
12210037SARM gem5 Developers    return;
12310037SARM gem5 Developers}
12410037SARM gem5 Developers
12510037SARM gem5 Developersvoid
12610037SARM gem5 DevelopersAtomicSimpleCPU::CpuPort::recvStatusChange(Status status)
12710037SARM gem5 Developers{
12810037SARM gem5 Developers    if (status == RangeChange) {
12910037SARM gem5 Developers        if (!snoopRangeSent) {
13010037SARM gem5 Developers            snoopRangeSent = true;
13110037SARM gem5 Developers            sendStatusChange(Port::RangeChange);
13210037SARM gem5 Developers        }
13310037SARM gem5 Developers        return;
13410037SARM gem5 Developers    }
13510037SARM gem5 Developers
13610037SARM gem5 Developers    panic("AtomicSimpleCPU doesn't expect recvStatusChange callback!");
13710037SARM gem5 Developers}
13810037SARM gem5 Developers
13910037SARM gem5 Developersvoid
14010037SARM gem5 DevelopersAtomicSimpleCPU::CpuPort::recvRetry()
14110037SARM gem5 Developers{
14210037SARM gem5 Developers    panic("AtomicSimpleCPU doesn't expect recvRetry callback!");
14310037SARM gem5 Developers}
14410037SARM gem5 Developers
14510037SARM gem5 Developersvoid
14610037SARM gem5 DevelopersAtomicSimpleCPU::DcachePort::setPeer(Port *port)
1476019Shines@cs.fsu.edu{
14810037SARM gem5 Developers    Port::setPeer(port);
14910037SARM gem5 Developers
15010037SARM gem5 Developers#if FULL_SYSTEM
1516019Shines@cs.fsu.edu    // Update the ThreadContext's memory ports (Functional/Virtual
15210037SARM gem5 Developers    // Ports)
15310037SARM gem5 Developers    cpu->tcBase()->connectMemPorts(cpu->tcBase());
15410037SARM gem5 Developers#endif
15510037SARM gem5 Developers}
15610037SARM gem5 Developers
15710037SARM gem5 DevelopersAtomicSimpleCPU::AtomicSimpleCPU(AtomicSimpleCPUParams *p)
15810037SARM gem5 Developers    : BaseSimpleCPU(p), tickEvent(this), width(p->width), locked(false),
15910037SARM gem5 Developers      simulate_data_stalls(p->simulate_data_stalls),
16010037SARM gem5 Developers      simulate_inst_stalls(p->simulate_inst_stalls),
16110037SARM gem5 Developers      icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this),
16210037SARM gem5 Developers      physmemPort(name() + "-iport", this), hasPhysMemPort(false)
16310037SARM gem5 Developers{
16410037SARM gem5 Developers    _status = Idle;
16510037SARM gem5 Developers
16610037SARM gem5 Developers    icachePort.snoopRangeSent = false;
16710037SARM gem5 Developers    dcachePort.snoopRangeSent = false;
16810037SARM gem5 Developers
16910037SARM gem5 Developers}
17010037SARM gem5 Developers
17110037SARM gem5 Developers
17210037SARM gem5 DevelopersAtomicSimpleCPU::~AtomicSimpleCPU()
17310037SARM gem5 Developers{
17410037SARM gem5 Developers    if (tickEvent.scheduled()) {
17510037SARM gem5 Developers        deschedule(tickEvent);
17610037SARM gem5 Developers    }
17710037SARM gem5 Developers}
17810037SARM gem5 Developers
17910037SARM gem5 Developersvoid
18010037SARM gem5 DevelopersAtomicSimpleCPU::serialize(ostream &os)
18110037SARM gem5 Developers{
18210037SARM gem5 Developers    SimObject::State so_state = SimObject::getState();
18310037SARM gem5 Developers    SERIALIZE_ENUM(so_state);
18410037SARM gem5 Developers    SERIALIZE_SCALAR(locked);
18510037SARM gem5 Developers    BaseSimpleCPU::serialize(os);
18610037SARM gem5 Developers    nameOut(os, csprintf("%s.tickEvent", name()));
18710037SARM gem5 Developers    tickEvent.serialize(os);
18810037SARM gem5 Developers}
18910037SARM gem5 Developers
19010037SARM gem5 Developersvoid
19110037SARM gem5 DevelopersAtomicSimpleCPU::unserialize(Checkpoint *cp, const string &section)
19210037SARM gem5 Developers{
1936019Shines@cs.fsu.edu    SimObject::State so_state;
19410037SARM gem5 Developers    UNSERIALIZE_ENUM(so_state);
19510037SARM gem5 Developers    UNSERIALIZE_SCALAR(locked);
19610037SARM gem5 Developers    BaseSimpleCPU::unserialize(cp, section);
1976019Shines@cs.fsu.edu    tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
19810037SARM gem5 Developers}
19910037SARM gem5 Developers
20010037SARM gem5 Developersvoid
20110037SARM gem5 DevelopersAtomicSimpleCPU::resume()
20210037SARM gem5 Developers{
20310037SARM gem5 Developers    if (_status == Idle || _status == SwitchedOut)
20410037SARM gem5 Developers        return;
20510037SARM gem5 Developers
20610037SARM gem5 Developers    DPRINTF(SimpleCPU, "Resume\n");
20710037SARM gem5 Developers    assert(system->getMemoryMode() == Enums::atomic);
20810037SARM gem5 Developers
20910037SARM gem5 Developers    changeState(SimObject::Running);
21010037SARM gem5 Developers    if (thread->status() == ThreadContext::Active) {
21110037SARM gem5 Developers        if (!tickEvent.scheduled())
21210037SARM gem5 Developers            schedule(tickEvent, nextCycle());
21310037SARM gem5 Developers    }
21410037SARM gem5 Developers}
21510037SARM gem5 Developers
21610037SARM gem5 Developersvoid
21710037SARM gem5 DevelopersAtomicSimpleCPU::switchOut()
21810037SARM gem5 Developers{
21910037SARM gem5 Developers    assert(_status == Running || _status == Idle);
22010037SARM gem5 Developers    _status = SwitchedOut;
22110037SARM gem5 Developers
22210037SARM gem5 Developers    tickEvent.squash();
22310037SARM gem5 Developers}
22410037SARM gem5 Developers
22510037SARM gem5 Developers
22610037SARM gem5 Developersvoid
22710037SARM gem5 DevelopersAtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
22810037SARM gem5 Developers{
22910037SARM gem5 Developers    BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
23010037SARM gem5 Developers
23110037SARM gem5 Developers    assert(!tickEvent.scheduled());
23210037SARM gem5 Developers
23310037SARM gem5 Developers    // if any of this CPU's ThreadContexts are active, mark the CPU as
23410037SARM gem5 Developers    // running and schedule its tick event.
23510037SARM gem5 Developers    ThreadID size = threadContexts.size();
23610037SARM gem5 Developers    for (ThreadID i = 0; i < size; ++i) {
23710037SARM gem5 Developers        ThreadContext *tc = threadContexts[i];
23810037SARM gem5 Developers        if (tc->status() == ThreadContext::Active && _status != Running) {
23910037SARM gem5 Developers            _status = Running;
24010037SARM gem5 Developers            schedule(tickEvent, nextCycle());
24110037SARM gem5 Developers            break;
24210037SARM gem5 Developers        }
24310037SARM gem5 Developers    }
24410037SARM gem5 Developers    if (_status != Running) {
24510037SARM gem5 Developers        _status = Idle;
24610037SARM gem5 Developers    }
24710037SARM gem5 Developers    assert(threadContexts.size() == 1);
24810037SARM gem5 Developers    ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT
24910037SARM gem5 Developers    data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too
25010037SARM gem5 Developers    data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too
25110037SARM gem5 Developers}
25210037SARM gem5 Developers
25310037SARM gem5 Developers
25410037SARM gem5 Developersvoid
25510037SARM gem5 DevelopersAtomicSimpleCPU::activateContext(int thread_num, int delay)
25610037SARM gem5 Developers{
25710037SARM gem5 Developers    DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay);
25810037SARM gem5 Developers
25910037SARM gem5 Developers    assert(thread_num == 0);
26010037SARM gem5 Developers    assert(thread);
26110037SARM gem5 Developers
26210037SARM gem5 Developers    assert(_status == Idle);
26310037SARM gem5 Developers    assert(!tickEvent.scheduled());
26410037SARM gem5 Developers
26510037SARM gem5 Developers    notIdleFraction++;
26610037SARM gem5 Developers    numCycles += tickToCycles(thread->lastActivate - thread->lastSuspend);
26710037SARM gem5 Developers
26810037SARM gem5 Developers    //Make sure ticks are still on multiples of cycles
26910037SARM gem5 Developers    schedule(tickEvent, nextCycle(curTick + ticks(delay)));
27010037SARM gem5 Developers    _status = Running;
27110037SARM gem5 Developers}
27210037SARM gem5 Developers
27310037SARM gem5 Developers
27410037SARM gem5 Developersvoid
27510037SARM gem5 DevelopersAtomicSimpleCPU::suspendContext(int thread_num)
27610037SARM gem5 Developers{
27710037SARM gem5 Developers    DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
27810037SARM gem5 Developers
27910037SARM gem5 Developers    assert(thread_num == 0);
28010037SARM gem5 Developers    assert(thread);
28110037SARM gem5 Developers
28210037SARM gem5 Developers    if (_status == Idle)
28310037SARM gem5 Developers        return;
28410037SARM gem5 Developers
28510037SARM gem5 Developers    assert(_status == Running);
28610037SARM gem5 Developers
28710037SARM gem5 Developers    // tick event may not be scheduled if this gets called from inside
28810037SARM gem5 Developers    // an instruction's execution, e.g. "quiesce"
28910037SARM gem5 Developers    if (tickEvent.scheduled())
29010037SARM gem5 Developers        deschedule(tickEvent);
29110037SARM gem5 Developers
29210037SARM gem5 Developers    notIdleFraction--;
29310037SARM gem5 Developers    _status = Idle;
29410037SARM gem5 Developers}
29510037SARM gem5 Developers
2966019Shines@cs.fsu.edu
29710037SARM gem5 Developerstemplate <class T>
2987362Sgblack@eecs.umich.eduFault
2996735Sgblack@eecs.umich.eduAtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
30010037SARM gem5 Developers{
3016019Shines@cs.fsu.edu    // use the CPU's statically allocated read request and packet objects
30210037SARM gem5 Developers    Request *req = &data_read_req;
30310037SARM gem5 Developers
3047400SAli.Saidi@ARM.com    if (traceData) {
3056735Sgblack@eecs.umich.edu        traceData->setAddr(addr);
3066735Sgblack@eecs.umich.edu    }
30710037SARM gem5 Developers
3086735Sgblack@eecs.umich.edu    //The block size of our peer.
30910037SARM gem5 Developers    unsigned blockSize = dcachePort.peerBlockSize();
31010037SARM gem5 Developers    //The size of the data we're trying to read.
31110037SARM gem5 Developers    int dataSize = sizeof(T);
31210037SARM gem5 Developers
3137400SAli.Saidi@ARM.com    uint8_t * dataPtr = (uint8_t *)&data;
31410037SARM gem5 Developers
31510037SARM gem5 Developers    //The address of the second part of this access if it needs to be split
31610037SARM gem5 Developers    //across a cache line boundary.
31710037SARM gem5 Developers    Addr secondAddr = roundDown(addr + dataSize - 1, blockSize);
31810037SARM gem5 Developers
31910037SARM gem5 Developers    if(secondAddr > addr)
32010037SARM gem5 Developers        dataSize = secondAddr - addr;
32110037SARM gem5 Developers
32210037SARM gem5 Developers    dcache_latency = 0;
32310037SARM gem5 Developers
32410037SARM gem5 Developers    while(1) {
32510037SARM gem5 Developers        req->setVirt(0, addr, dataSize, flags, thread->readPC());
32610037SARM gem5 Developers
32710037SARM gem5 Developers        // translate to physical address
32810037SARM gem5 Developers        Fault fault = thread->dtb->translateAtomic(req, tc, BaseTLB::Read);
32910037SARM gem5 Developers
33010037SARM gem5 Developers        // Now do the access.
3316019Shines@cs.fsu.edu        if (fault == NoFault && !req->getFlags().isSet(Request::NO_ACCESS)) {
3326019Shines@cs.fsu.edu            Packet pkt = Packet(req,
33310037SARM gem5 Developers                    req->isLLSC() ? MemCmd::LoadLockedReq : MemCmd::ReadReq,
33410037SARM gem5 Developers                    Packet::Broadcast);
33510037SARM gem5 Developers            pkt.dataStatic(dataPtr);
33610037SARM gem5 Developers
33710037SARM gem5 Developers            if (req->isMmapedIpr())
33810037SARM gem5 Developers                dcache_latency += TheISA::handleIprRead(thread->getTC(), &pkt);
33910037SARM gem5 Developers            else {
34010037SARM gem5 Developers                if (hasPhysMemPort && pkt.getAddr() == physMemAddr)
34110037SARM gem5 Developers                    dcache_latency += physmemPort.sendAtomic(&pkt);
34211574SCurtis.Dunham@arm.com                else
34311574SCurtis.Dunham@arm.com                    dcache_latency += dcachePort.sendAtomic(&pkt);
34411574SCurtis.Dunham@arm.com            }
34511574SCurtis.Dunham@arm.com            dcache_access = true;
34610037SARM gem5 Developers
34710037SARM gem5 Developers            assert(!pkt.isError());
34810037SARM gem5 Developers
34910037SARM gem5 Developers            if (req->isLLSC()) {
35010037SARM gem5 Developers                TheISA::handleLockedRead(thread, req);
35110037SARM gem5 Developers            }
35210037SARM gem5 Developers        }
35310037SARM gem5 Developers
35410037SARM gem5 Developers        //If there's a fault, return it
35510037SARM gem5 Developers        if (fault != NoFault) {
35610037SARM gem5 Developers            if (req->isPrefetch()) {
35710037SARM gem5 Developers                return NoFault;
35810037SARM gem5 Developers            } else {
35910037SARM gem5 Developers                return fault;
36010037SARM gem5 Developers            }
36110037SARM gem5 Developers        }
36210037SARM gem5 Developers
36310037SARM gem5 Developers        //If we don't need to access a second cache line, stop now.
36410037SARM gem5 Developers        if (secondAddr <= addr)
36510037SARM gem5 Developers        {
36610037SARM gem5 Developers            data = gtoh(data);
36710037SARM gem5 Developers            if (traceData) {
36810037SARM gem5 Developers                traceData->setData(data);
36910037SARM gem5 Developers            }
37010037SARM gem5 Developers            if (req->isLocked() && fault == NoFault) {
37110037SARM gem5 Developers                assert(!locked);
37210037SARM gem5 Developers                locked = true;
37310037SARM gem5 Developers            }
37410037SARM gem5 Developers            return fault;
37510037SARM gem5 Developers        }
37610037SARM gem5 Developers
37710037SARM gem5 Developers        /*
37810037SARM gem5 Developers         * Set up for accessing the second cache line.
37910037SARM gem5 Developers         */
38010037SARM gem5 Developers
38110037SARM gem5 Developers        //Move the pointer we're reading into to the correct location.
38210037SARM gem5 Developers        dataPtr += dataSize;
38310037SARM gem5 Developers        //Adjust the size to get the remaining bytes.
38410037SARM gem5 Developers        dataSize = addr + sizeof(T) - secondAddr;
38510037SARM gem5 Developers        //And access the right address.
38610037SARM gem5 Developers        addr = secondAddr;
38710037SARM gem5 Developers    }
38810037SARM gem5 Developers}
38910037SARM gem5 Developers
39010037SARM gem5 Developers#ifndef DOXYGEN_SHOULD_SKIP_THIS
39110037SARM gem5 Developers
39210037SARM gem5 Developerstemplate
39310037SARM gem5 DevelopersFault
39410037SARM gem5 DevelopersAtomicSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags);
39510037SARM gem5 Developers
39610037SARM gem5 Developerstemplate
39710037SARM gem5 DevelopersFault
39810037SARM gem5 DevelopersAtomicSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags);
39910037SARM gem5 Developers
40010037SARM gem5 Developerstemplate
40110037SARM gem5 DevelopersFault
40210037SARM gem5 DevelopersAtomicSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
40310037SARM gem5 Developers
40410037SARM gem5 Developerstemplate
40510037SARM gem5 DevelopersFault
40610037SARM gem5 DevelopersAtomicSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
40710037SARM gem5 Developers
40810037SARM gem5 Developerstemplate
40910037SARM gem5 DevelopersFault
41010037SARM gem5 DevelopersAtomicSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
41110037SARM gem5 Developers
41210037SARM gem5 Developerstemplate
41310037SARM gem5 DevelopersFault
41410037SARM gem5 DevelopersAtomicSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
41510037SARM gem5 Developers
41610037SARM gem5 Developers#endif //DOXYGEN_SHOULD_SKIP_THIS
41710037SARM gem5 Developers
41810037SARM gem5 Developerstemplate<>
41910037SARM gem5 DevelopersFault
42010037SARM gem5 DevelopersAtomicSimpleCPU::read(Addr addr, double &data, unsigned flags)
42110037SARM gem5 Developers{
42210037SARM gem5 Developers    return read(addr, *(uint64_t*)&data, flags);
42310037SARM gem5 Developers}
42410037SARM gem5 Developers
42510037SARM gem5 Developerstemplate<>
42610037SARM gem5 DevelopersFault
42710037SARM gem5 DevelopersAtomicSimpleCPU::read(Addr addr, float &data, unsigned flags)
42810037SARM gem5 Developers{
42910417Sandreas.hansson@arm.com    return read(addr, *(uint32_t*)&data, flags);
4306019Shines@cs.fsu.edu}
43110037SARM gem5 Developers
43210037SARM gem5 Developers
43310037SARM gem5 Developerstemplate<>
43410037SARM gem5 DevelopersFault
43510037SARM gem5 DevelopersAtomicSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
43610037SARM gem5 Developers{
43710037SARM gem5 Developers    return read(addr, (uint32_t&)data, flags);
43810037SARM gem5 Developers}
43910037SARM gem5 Developers
44010037SARM gem5 Developers
44110037SARM gem5 Developerstemplate <class T>
44210037SARM gem5 DevelopersFault
44311578SDylan.Johnson@ARM.comAtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
44411578SDylan.Johnson@ARM.com{
44510037SARM gem5 Developers    // use the CPU's statically allocated write request and packet objects
44610037SARM gem5 Developers    Request *req = &data_write_req;
44710037SARM gem5 Developers
44810037SARM gem5 Developers    if (traceData) {
44910037SARM gem5 Developers        traceData->setAddr(addr);
45010037SARM gem5 Developers        traceData->setData(data);
45110037SARM gem5 Developers    }
45210037SARM gem5 Developers
45310037SARM gem5 Developers    //The block size of our peer.
45410037SARM gem5 Developers    unsigned blockSize = dcachePort.peerBlockSize();
45510037SARM gem5 Developers    //The size of the data we're trying to read.
45610037SARM gem5 Developers    int dataSize = sizeof(T);
45710037SARM gem5 Developers
45810037SARM gem5 Developers    uint8_t * dataPtr = (uint8_t *)&data;
45910037SARM gem5 Developers
46010037SARM gem5 Developers    //The address of the second part of this access if it needs to be split
46110037SARM gem5 Developers    //across a cache line boundary.
46210037SARM gem5 Developers    Addr secondAddr = roundDown(addr + dataSize - 1, blockSize);
4636735Sgblack@eecs.umich.edu
4648782Sgblack@eecs.umich.edu    if(secondAddr > addr)
4658782Sgblack@eecs.umich.edu        dataSize = secondAddr - addr;
4666735Sgblack@eecs.umich.edu
4676019Shines@cs.fsu.edu    dcache_latency = 0;
4686735Sgblack@eecs.umich.edu
46910037SARM gem5 Developers    while(1) {
4708303SAli.Saidi@ARM.com        req->setVirt(0, addr, dataSize, flags, thread->readPC());
47110338SCurtis.Dunham@arm.com
47210338SCurtis.Dunham@arm.com        // translate to physical address
47310338SCurtis.Dunham@arm.com        Fault fault = thread->dtb->translateAtomic(req, tc, BaseTLB::Write);
47410338SCurtis.Dunham@arm.com
4758303SAli.Saidi@ARM.com        // Now do the access.
4767720Sgblack@eecs.umich.edu        if (fault == NoFault) {
4778205SAli.Saidi@ARM.com            MemCmd cmd = MemCmd::WriteReq; // default
4788205SAli.Saidi@ARM.com            bool do_access = true;  // flag to suppress cache access
4798205SAli.Saidi@ARM.com
4806735Sgblack@eecs.umich.edu            if (req->isLLSC()) {
48110037SARM gem5 Developers                cmd = MemCmd::StoreCondReq;
48210037SARM gem5 Developers                do_access = TheISA::handleLockedWrite(thread, req);
48310037SARM gem5 Developers            } else if (req->isSwap()) {
48410037SARM gem5 Developers                cmd = MemCmd::SwapReq;
48510037SARM gem5 Developers                if (req->isCondSwap()) {
48610037SARM gem5 Developers                    assert(res);
48710037SARM gem5 Developers                    req->setExtraData(*res);
48810037SARM gem5 Developers                }
48910037SARM gem5 Developers            }
49010037SARM gem5 Developers
49110037SARM gem5 Developers            if (do_access && !req->getFlags().isSet(Request::NO_ACCESS)) {
49210037SARM gem5 Developers                Packet pkt = Packet(req, cmd, Packet::Broadcast);
49310037SARM gem5 Developers                pkt.dataStatic(dataPtr);
49410037SARM gem5 Developers
49510037SARM gem5 Developers                if (req->isMmapedIpr()) {
49610037SARM gem5 Developers                    dcache_latency +=
49710037SARM gem5 Developers                        TheISA::handleIprWrite(thread->getTC(), &pkt);
49810037SARM gem5 Developers                } else {
49910037SARM gem5 Developers                    //XXX This needs to be outside of the loop in order to
50010037SARM gem5 Developers                    //work properly for cache line boundary crossing
50110037SARM gem5 Developers                    //accesses in transendian simulations.
50210037SARM gem5 Developers                    data = htog(data);
50310037SARM gem5 Developers                    if (hasPhysMemPort && pkt.getAddr() == physMemAddr)
50410037SARM gem5 Developers                        dcache_latency += physmemPort.sendAtomic(&pkt);
50510037SARM gem5 Developers                    else
50610037SARM gem5 Developers                        dcache_latency += dcachePort.sendAtomic(&pkt);
50710037SARM gem5 Developers                }
50810037SARM gem5 Developers                dcache_access = true;
50910037SARM gem5 Developers                assert(!pkt.isError());
51010037SARM gem5 Developers
51110037SARM gem5 Developers                if (req->isSwap()) {
51210037SARM gem5 Developers                    assert(res);
51310037SARM gem5 Developers                    *res = pkt.get<T>();
51410037SARM gem5 Developers                }
51510037SARM gem5 Developers            }
51610037SARM gem5 Developers
51710037SARM gem5 Developers            if (res && !req->isSwap()) {
51810037SARM gem5 Developers                *res = req->getExtraData();
51910037SARM gem5 Developers            }
52010037SARM gem5 Developers        }
52110037SARM gem5 Developers
52210037SARM gem5 Developers        //If there's a fault or we don't need to access a second cache line,
52310037SARM gem5 Developers        //stop now.
52410037SARM gem5 Developers        if (fault != NoFault || secondAddr <= addr)
52510037SARM gem5 Developers        {
52610037SARM gem5 Developers            if (req->isLocked() && fault == NoFault) {
52710037SARM gem5 Developers                assert(locked);
52810037SARM gem5 Developers                locked = false;
5296735Sgblack@eecs.umich.edu            }
5306735Sgblack@eecs.umich.edu            if (fault != NoFault && req->isPrefetch()) {
5316735Sgblack@eecs.umich.edu                return NoFault;
53210037SARM gem5 Developers            } else {
5338518Sgeoffrey.blake@arm.com                return fault;
5348518Sgeoffrey.blake@arm.com            }
5356735Sgblack@eecs.umich.edu        }
53610037SARM gem5 Developers
53710037SARM gem5 Developers        /*
53810037SARM gem5 Developers         * Set up for accessing the second cache line.
53910037SARM gem5 Developers         */
54010037SARM gem5 Developers
54110037SARM gem5 Developers        //Move the pointer we're reading into to the correct location.
54210037SARM gem5 Developers        dataPtr += dataSize;
54310037SARM gem5 Developers        //Adjust the size to get the remaining bytes.
54410037SARM gem5 Developers        dataSize = addr + sizeof(T) - secondAddr;
54510037SARM gem5 Developers        //And access the right address.
54610037SARM gem5 Developers        addr = secondAddr;
54710037SARM gem5 Developers    }
5486735Sgblack@eecs.umich.edu}
5496735Sgblack@eecs.umich.edu
5506735Sgblack@eecs.umich.edu
5516735Sgblack@eecs.umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS
5526735Sgblack@eecs.umich.edu
5536735Sgblack@eecs.umich.edutemplate
5546735Sgblack@eecs.umich.eduFault
5556735Sgblack@eecs.umich.eduAtomicSimpleCPU::write(Twin32_t data, Addr addr,
5566735Sgblack@eecs.umich.edu                       unsigned flags, uint64_t *res);
55710037SARM gem5 Developers
55810037SARM gem5 Developerstemplate
55910037SARM gem5 DevelopersFault
5606735Sgblack@eecs.umich.eduAtomicSimpleCPU::write(Twin64_t data, Addr addr,
5616735Sgblack@eecs.umich.edu                       unsigned flags, uint64_t *res);
5626735Sgblack@eecs.umich.edu
5636735Sgblack@eecs.umich.edutemplate
56410037SARM gem5 DevelopersFault
56510037SARM gem5 DevelopersAtomicSimpleCPU::write(uint64_t data, Addr addr,
56610037SARM gem5 Developers                       unsigned flags, uint64_t *res);
56710037SARM gem5 Developers
56810037SARM gem5 Developerstemplate
56910037SARM gem5 DevelopersFault
57010037SARM gem5 DevelopersAtomicSimpleCPU::write(uint32_t data, Addr addr,
57110037SARM gem5 Developers                       unsigned flags, uint64_t *res);
57210037SARM gem5 Developers
57310037SARM gem5 Developerstemplate
5746735Sgblack@eecs.umich.eduFault
5756735Sgblack@eecs.umich.eduAtomicSimpleCPU::write(uint16_t data, Addr addr,
5767093Sgblack@eecs.umich.edu                       unsigned flags, uint64_t *res);
5777093Sgblack@eecs.umich.edu
5787720Sgblack@eecs.umich.edutemplate
5797585SAli.Saidi@arm.comFault
5807720Sgblack@eecs.umich.eduAtomicSimpleCPU::write(uint8_t data, Addr addr,
5817720Sgblack@eecs.umich.edu                       unsigned flags, uint64_t *res);
5827720Sgblack@eecs.umich.edu
5837720Sgblack@eecs.umich.edu#endif //DOXYGEN_SHOULD_SKIP_THIS
5847720Sgblack@eecs.umich.edu
5857720Sgblack@eecs.umich.edutemplate<>
58610037SARM gem5 DevelopersFault
58710037SARM gem5 DevelopersAtomicSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
5887720Sgblack@eecs.umich.edu{
5896019Shines@cs.fsu.edu    return write(*(uint64_t*)&data, addr, flags, res);
5907189Sgblack@eecs.umich.edu}
5917400SAli.Saidi@ARM.com
59210417Sandreas.hansson@arm.comtemplate<>
59310037SARM gem5 DevelopersFault
59410037SARM gem5 DevelopersAtomicSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
59510037SARM gem5 Developers{
59610037SARM gem5 Developers    return write(*(uint32_t*)&data, addr, flags, res);
59710037SARM gem5 Developers}
59810037SARM gem5 Developers
59910037SARM gem5 Developers
60010037SARM gem5 Developerstemplate<>
60111574SCurtis.Dunham@arm.comFault
60211574SCurtis.Dunham@arm.comAtomicSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
60311574SCurtis.Dunham@arm.com{
60411574SCurtis.Dunham@arm.com    return write((uint32_t)data, addr, flags, res);
60511574SCurtis.Dunham@arm.com}
60610037SARM gem5 Developers
60710037SARM gem5 Developers
60810037SARM gem5 Developersvoid
60910037SARM gem5 DevelopersAtomicSimpleCPU::tick()
61010037SARM gem5 Developers{
61110037SARM gem5 Developers    DPRINTF(SimpleCPU, "Tick\n");
61210037SARM gem5 Developers
61310037SARM gem5 Developers    Tick latency = 0;
61410037SARM gem5 Developers
61510037SARM gem5 Developers    for (int i = 0; i < width || locked; ++i) {
61610037SARM gem5 Developers        numCycles++;
61710037SARM gem5 Developers
61810037SARM gem5 Developers        if (!curStaticInst || !curStaticInst->isDelayedCommit())
61910338SCurtis.Dunham@arm.com            checkForInterrupts();
62010338SCurtis.Dunham@arm.com
62110338SCurtis.Dunham@arm.com        checkPcEventQueue();
62210037SARM gem5 Developers
62310037SARM gem5 Developers        Fault fault = NoFault;
62410037SARM gem5 Developers
62510037SARM gem5 Developers        bool fromRom = isRomMicroPC(thread->readMicroPC());
62610037SARM gem5 Developers        if (!fromRom && !curMacroStaticInst) {
62710037SARM gem5 Developers            setupFetchRequest(&ifetch_req);
62810037SARM gem5 Developers            fault = thread->itb->translateAtomic(&ifetch_req, tc,
62910037SARM gem5 Developers                                                 BaseTLB::Execute);
63010037SARM gem5 Developers        }
63110037SARM gem5 Developers
63210338SCurtis.Dunham@arm.com        if (fault == NoFault) {
63310037SARM gem5 Developers            Tick icache_latency = 0;
63410037SARM gem5 Developers            bool icache_access = false;
63510037SARM gem5 Developers            dcache_access = false; // assume no dcache access
63610037SARM gem5 Developers
63710037SARM gem5 Developers            if (!fromRom && !curMacroStaticInst) {
63810037SARM gem5 Developers                // This is commented out because the predecoder would act like
63910037SARM gem5 Developers                // a tiny cache otherwise. It wouldn't be flushed when needed
64010037SARM gem5 Developers                // like the I cache. It should be flushed, and when that works
64110037SARM gem5 Developers                // this code should be uncommented.
64210037SARM gem5 Developers                //Fetch more instruction memory if necessary
64310037SARM gem5 Developers                //if(predecoder.needMoreBytes())
64410037SARM gem5 Developers                //{
64510037SARM gem5 Developers                    icache_access = true;
64610037SARM gem5 Developers                    Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq,
64710037SARM gem5 Developers                                               Packet::Broadcast);
64810037SARM gem5 Developers                    ifetch_pkt.dataStatic(&inst);
64910037SARM gem5 Developers
65010037SARM gem5 Developers                    if (hasPhysMemPort && ifetch_pkt.getAddr() == physMemAddr)
65110037SARM gem5 Developers                        icache_latency = physmemPort.sendAtomic(&ifetch_pkt);
65210037SARM gem5 Developers                    else
65310037SARM gem5 Developers                        icache_latency = icachePort.sendAtomic(&ifetch_pkt);
65410037SARM gem5 Developers
65510037SARM gem5 Developers                    assert(!ifetch_pkt.isError());
65610037SARM gem5 Developers
65710037SARM gem5 Developers                    // ifetch_req is initialized to read the instruction directly
65810037SARM gem5 Developers                    // into the CPU object's inst field.
65910037SARM gem5 Developers                //}
66010037SARM gem5 Developers            }
66110037SARM gem5 Developers
66210037SARM gem5 Developers            preExecute();
66310037SARM gem5 Developers
66410037SARM gem5 Developers            if (curStaticInst) {
66510037SARM gem5 Developers                fault = curStaticInst->execute(this, traceData);
66610037SARM gem5 Developers
66710037SARM gem5 Developers                // keep an instruction count
66810037SARM gem5 Developers                if (fault == NoFault)
66910037SARM gem5 Developers                    countInst();
67010037SARM gem5 Developers                else if (traceData) {
67110037SARM gem5 Developers                    // If there was a fault, we should trace this instruction.
67210037SARM gem5 Developers                    delete traceData;
67310037SARM gem5 Developers                    traceData = NULL;
67410037SARM gem5 Developers                }
67510037SARM gem5 Developers
67610037SARM gem5 Developers                postExecute();
67710037SARM gem5 Developers            }
67810037SARM gem5 Developers
67910037SARM gem5 Developers            // @todo remove me after debugging with legion done
68010037SARM gem5 Developers            if (curStaticInst && (!curStaticInst->isMicroop() ||
68110037SARM gem5 Developers                        curStaticInst->isFirstMicroop()))
68210417Sandreas.hansson@arm.com                instCnt++;
6837400SAli.Saidi@ARM.com
6848782Sgblack@eecs.umich.edu            Tick stall_ticks = 0;
68511150Smitch.hayenga@arm.com            if (simulate_inst_stalls && icache_access)
6868782Sgblack@eecs.umich.edu                stall_ticks += icache_latency;
6878782Sgblack@eecs.umich.edu
68810037SARM gem5 Developers            if (simulate_data_stalls && dcache_access)
68910037SARM gem5 Developers                stall_ticks += dcache_latency;
69010037SARM gem5 Developers
69110037SARM gem5 Developers            if (stall_ticks) {
69210037SARM gem5 Developers                Tick stall_cycles = stall_ticks / ticks(1);
69310037SARM gem5 Developers                Tick aligned_stall_ticks = ticks(stall_cycles);
69410037SARM gem5 Developers
69510037SARM gem5 Developers                if (aligned_stall_ticks < stall_ticks)
69610037SARM gem5 Developers                    aligned_stall_ticks += 1;
69710037SARM gem5 Developers
69810037SARM gem5 Developers                latency += aligned_stall_ticks;
69910037SARM gem5 Developers            }
70010037SARM gem5 Developers
70110037SARM gem5 Developers        }
70210037SARM gem5 Developers        if(fault != NoFault || !stayAtPC)
70310037SARM gem5 Developers            advancePC(fault);
70410037SARM gem5 Developers    }
70510037SARM gem5 Developers
70610037SARM gem5 Developers    // instruction takes at least one cycle
7077400SAli.Saidi@ARM.com    if (latency < ticks(1))
7087400SAli.Saidi@ARM.com        latency = ticks(1);
7097189Sgblack@eecs.umich.edu
71010417Sandreas.hansson@arm.com    if (_status != Idle)
7117189Sgblack@eecs.umich.edu        schedule(tickEvent, curTick + latency);
7128782Sgblack@eecs.umich.edu}
7138782Sgblack@eecs.umich.edu
7148806Sgblack@eecs.umich.edu
7158806Sgblack@eecs.umich.eduvoid
7168806Sgblack@eecs.umich.eduAtomicSimpleCPU::printAddr(Addr a)
7178806Sgblack@eecs.umich.edu{
7188806Sgblack@eecs.umich.edu    dcachePort.printAddr(a);
7198806Sgblack@eecs.umich.edu}
7208806Sgblack@eecs.umich.edu
7218806Sgblack@eecs.umich.edu
7228806Sgblack@eecs.umich.edu////////////////////////////////////////////////////////////////////////
7238806Sgblack@eecs.umich.edu//
7248806Sgblack@eecs.umich.edu//  AtomicSimpleCPU Simulation Object
7257189Sgblack@eecs.umich.edu//
7268806Sgblack@eecs.umich.eduAtomicSimpleCPU *
7278806Sgblack@eecs.umich.eduAtomicSimpleCPUParams::create()
7287189Sgblack@eecs.umich.edu{
7297189Sgblack@eecs.umich.edu    numThreads = 1;
7307189Sgblack@eecs.umich.edu#if !FULL_SYSTEM
73110037SARM gem5 Developers    if (workload.size() != 1)
73210037SARM gem5 Developers        panic("only one workload allowed");
73310037SARM gem5 Developers#endif
73410037SARM gem5 Developers    return new AtomicSimpleCPU(this);
73510037SARM gem5 Developers}
73610037SARM gem5 Developers