atomic.cc revision 8949
110515SAli.Saidi@ARM.com/*
210515SAli.Saidi@ARM.com * Copyright (c) 2012 ARM Limited
310515SAli.Saidi@ARM.com * All rights reserved.
410515SAli.Saidi@ARM.com *
510515SAli.Saidi@ARM.com * The license below extends only to copyright in the software and shall
610515SAli.Saidi@ARM.com * not be construed as granting a license to any other intellectual
710515SAli.Saidi@ARM.com * property including but not limited to intellectual property relating
810515SAli.Saidi@ARM.com * to a hardware implementation of the functionality of the software
910515SAli.Saidi@ARM.com * licensed hereunder.  You may use the software subject to the license
1010515SAli.Saidi@ARM.com * terms below provided that you ensure that this notice is replicated
1110515SAli.Saidi@ARM.com * unmodified and in its entirety in all distributions of the software,
1210515SAli.Saidi@ARM.com * modified or unmodified, in source code or in binary form.
1310515SAli.Saidi@ARM.com *
1410515SAli.Saidi@ARM.com * Copyright (c) 2002-2005 The Regents of The University of Michigan
1511570SCurtis.Dunham@arm.com * All rights reserved.
1610515SAli.Saidi@ARM.com *
1710515SAli.Saidi@ARM.com * Redistribution and use in source and binary forms, with or without
1810515SAli.Saidi@ARM.com * modification, are permitted provided that the following conditions are
1911570SCurtis.Dunham@arm.com * met: redistributions of source code must retain the above copyright
2011570SCurtis.Dunham@arm.com * notice, this list of conditions and the following disclaimer;
2110515SAli.Saidi@ARM.com * redistributions in binary form must reproduce the above copyright
2210515SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer in the
2310515SAli.Saidi@ARM.com * documentation and/or other materials provided with the distribution;
2411570SCurtis.Dunham@arm.com * neither the name of the copyright holders nor the names of its
2510515SAli.Saidi@ARM.com * contributors may be used to endorse or promote products derived from
2610515SAli.Saidi@ARM.com * this software without specific prior written permission.
2710515SAli.Saidi@ARM.com *
2811570SCurtis.Dunham@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2910515SAli.Saidi@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3010515SAli.Saidi@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3110515SAli.Saidi@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3210515SAli.Saidi@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3311570SCurtis.Dunham@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3410515SAli.Saidi@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3510515SAli.Saidi@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3610515SAli.Saidi@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3710515SAli.Saidi@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3810515SAli.Saidi@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3910515SAli.Saidi@ARM.com *
4010798Ssteve.reinhardt@amd.com * Authors: Steve Reinhardt
4110798Ssteve.reinhardt@amd.com */
4210515SAli.Saidi@ARM.com
4311167Sjthestness@gmail.com#include "arch/locked_mem.hh"
4410515SAli.Saidi@ARM.com#include "arch/mmapped_ipr.hh"
4511570SCurtis.Dunham@arm.com#include "arch/utility.hh"
4611570SCurtis.Dunham@arm.com#include "base/bigint.hh"
4711570SCurtis.Dunham@arm.com#include "config/the_isa.hh"
4810515SAli.Saidi@ARM.com#include "cpu/simple/atomic.hh"
4910515SAli.Saidi@ARM.com#include "cpu/exetrace.hh"
5010515SAli.Saidi@ARM.com#include "debug/ExecFaulting.hh"
5111570SCurtis.Dunham@arm.com#include "debug/SimpleCPU.hh"
5211570SCurtis.Dunham@arm.com#include "mem/packet.hh"
5310515SAli.Saidi@ARM.com#include "mem/packet_access.hh"
5410515SAli.Saidi@ARM.com#include "mem/physical.hh"
5511570SCurtis.Dunham@arm.com#include "params/AtomicSimpleCPU.hh"
5611570SCurtis.Dunham@arm.com#include "sim/faults.hh"
5710515SAli.Saidi@ARM.com#include "sim/system.hh"
5810515SAli.Saidi@ARM.com#include "sim/full_system.hh"
5910515SAli.Saidi@ARM.com
6010515SAli.Saidi@ARM.comusing namespace std;
6110515SAli.Saidi@ARM.comusing namespace TheISA;
6210515SAli.Saidi@ARM.com
6310515SAli.Saidi@ARM.comAtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c)
6410515SAli.Saidi@ARM.com    : Event(CPU_Tick_Pri), cpu(c)
6510515SAli.Saidi@ARM.com{
6610515SAli.Saidi@ARM.com}
6710515SAli.Saidi@ARM.com
6810515SAli.Saidi@ARM.com
6911570SCurtis.Dunham@arm.comvoid
7010515SAli.Saidi@ARM.comAtomicSimpleCPU::TickEvent::process()
7110515SAli.Saidi@ARM.com{
7211570SCurtis.Dunham@arm.com    cpu->tick();
7311570SCurtis.Dunham@arm.com}
7411570SCurtis.Dunham@arm.com
7511570SCurtis.Dunham@arm.comconst char *
7610515SAli.Saidi@ARM.comAtomicSimpleCPU::TickEvent::description() const
7710515SAli.Saidi@ARM.com{
7810515SAli.Saidi@ARM.com    return "AtomicSimpleCPU tick";
7910515SAli.Saidi@ARM.com}
8010515SAli.Saidi@ARM.com
8110515SAli.Saidi@ARM.comvoid
8210515SAli.Saidi@ARM.comAtomicSimpleCPU::init()
8310515SAli.Saidi@ARM.com{
8410515SAli.Saidi@ARM.com    BaseCPU::init();
8510515SAli.Saidi@ARM.com
8610515SAli.Saidi@ARM.com    // Initialise the ThreadContext's memory proxies
8710515SAli.Saidi@ARM.com    tcBase()->initMemProxies(tcBase());
8810515SAli.Saidi@ARM.com
8910515SAli.Saidi@ARM.com    if (FullSystem) {
9010515SAli.Saidi@ARM.com        ThreadID size = threadContexts.size();
9110515SAli.Saidi@ARM.com        for (ThreadID i = 0; i < size; ++i) {
9210515SAli.Saidi@ARM.com            ThreadContext *tc = threadContexts[i];
9310515SAli.Saidi@ARM.com            // initialize CPU, including PC
9410515SAli.Saidi@ARM.com            TheISA::initCPU(tc, tc->contextId());
9510515SAli.Saidi@ARM.com        }
9610515SAli.Saidi@ARM.com    }
9710515SAli.Saidi@ARM.com
9810515SAli.Saidi@ARM.com    // Atomic doesn't do MT right now, so contextId == threadId
9910515SAli.Saidi@ARM.com    ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT
10010515SAli.Saidi@ARM.com    data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too
10110515SAli.Saidi@ARM.com    data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too
10211570SCurtis.Dunham@arm.com}
10310515SAli.Saidi@ARM.com
10410515SAli.Saidi@ARM.comAtomicSimpleCPU::AtomicSimpleCPU(AtomicSimpleCPUParams *p)
10510515SAli.Saidi@ARM.com    : BaseSimpleCPU(p), tickEvent(this), width(p->width), locked(false),
10610515SAli.Saidi@ARM.com      simulate_data_stalls(p->simulate_data_stalls),
10710515SAli.Saidi@ARM.com      simulate_inst_stalls(p->simulate_inst_stalls),
10810515SAli.Saidi@ARM.com      icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this),
10910515SAli.Saidi@ARM.com      fastmem(p->fastmem)
11010515SAli.Saidi@ARM.com{
11110515SAli.Saidi@ARM.com    _status = Idle;
11210515SAli.Saidi@ARM.com}
11310515SAli.Saidi@ARM.com
11410515SAli.Saidi@ARM.com
11510515SAli.Saidi@ARM.comAtomicSimpleCPU::~AtomicSimpleCPU()
11610515SAli.Saidi@ARM.com{
11710515SAli.Saidi@ARM.com    if (tickEvent.scheduled()) {
11810515SAli.Saidi@ARM.com        deschedule(tickEvent);
11910515SAli.Saidi@ARM.com    }
12010515SAli.Saidi@ARM.com}
12110515SAli.Saidi@ARM.com
12210515SAli.Saidi@ARM.comvoid
12310515SAli.Saidi@ARM.comAtomicSimpleCPU::serialize(ostream &os)
12410515SAli.Saidi@ARM.com{
12510515SAli.Saidi@ARM.com    SimObject::State so_state = SimObject::getState();
12610515SAli.Saidi@ARM.com    SERIALIZE_ENUM(so_state);
12710515SAli.Saidi@ARM.com    SERIALIZE_SCALAR(locked);
12810515SAli.Saidi@ARM.com    BaseSimpleCPU::serialize(os);
12910515SAli.Saidi@ARM.com    nameOut(os, csprintf("%s.tickEvent", name()));
13010515SAli.Saidi@ARM.com    tickEvent.serialize(os);
13110515SAli.Saidi@ARM.com}
13210515SAli.Saidi@ARM.com
13310515SAli.Saidi@ARM.comvoid
13410515SAli.Saidi@ARM.comAtomicSimpleCPU::unserialize(Checkpoint *cp, const string &section)
13510515SAli.Saidi@ARM.com{
13610515SAli.Saidi@ARM.com    SimObject::State so_state;
13711570SCurtis.Dunham@arm.com    UNSERIALIZE_ENUM(so_state);
13810515SAli.Saidi@ARM.com    UNSERIALIZE_SCALAR(locked);
13910515SAli.Saidi@ARM.com    BaseSimpleCPU::unserialize(cp, section);
14010515SAli.Saidi@ARM.com    tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
14110515SAli.Saidi@ARM.com}
14210515SAli.Saidi@ARM.com
14310515SAli.Saidi@ARM.comvoid
14410515SAli.Saidi@ARM.comAtomicSimpleCPU::resume()
14510515SAli.Saidi@ARM.com{
14610515SAli.Saidi@ARM.com    if (_status == Idle || _status == SwitchedOut)
14710515SAli.Saidi@ARM.com        return;
14810515SAli.Saidi@ARM.com
14910515SAli.Saidi@ARM.com    DPRINTF(SimpleCPU, "Resume\n");
15010515SAli.Saidi@ARM.com    assert(system->getMemoryMode() == Enums::atomic);
15110515SAli.Saidi@ARM.com
15210515SAli.Saidi@ARM.com    changeState(SimObject::Running);
15310515SAli.Saidi@ARM.com    if (thread->status() == ThreadContext::Active) {
15410515SAli.Saidi@ARM.com        if (!tickEvent.scheduled())
15510515SAli.Saidi@ARM.com            schedule(tickEvent, nextCycle());
15610515SAli.Saidi@ARM.com    }
15710515SAli.Saidi@ARM.com    system->totalNumInsts = 0;
15810515SAli.Saidi@ARM.com}
15910515SAli.Saidi@ARM.com
16010515SAli.Saidi@ARM.comvoid
16110515SAli.Saidi@ARM.comAtomicSimpleCPU::switchOut()
16210515SAli.Saidi@ARM.com{
16310515SAli.Saidi@ARM.com    assert(_status == Running || _status == Idle);
16410515SAli.Saidi@ARM.com    _status = SwitchedOut;
16510515SAli.Saidi@ARM.com
16610515SAli.Saidi@ARM.com    tickEvent.squash();
16710515SAli.Saidi@ARM.com}
16810515SAli.Saidi@ARM.com
16910515SAli.Saidi@ARM.com
17010515SAli.Saidi@ARM.comvoid
17110515SAli.Saidi@ARM.comAtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
17210515SAli.Saidi@ARM.com{
17310515SAli.Saidi@ARM.com    BaseCPU::takeOverFrom(oldCPU);
17410515SAli.Saidi@ARM.com
17510515SAli.Saidi@ARM.com    assert(!tickEvent.scheduled());
17611570SCurtis.Dunham@arm.com
17711570SCurtis.Dunham@arm.com    // if any of this CPU's ThreadContexts are active, mark the CPU as
17811570SCurtis.Dunham@arm.com    // running and schedule its tick event.
17911570SCurtis.Dunham@arm.com    ThreadID size = threadContexts.size();
18010515SAli.Saidi@ARM.com    for (ThreadID i = 0; i < size; ++i) {
18110515SAli.Saidi@ARM.com        ThreadContext *tc = threadContexts[i];
18210515SAli.Saidi@ARM.com        if (tc->status() == ThreadContext::Active && _status != Running) {
18310515SAli.Saidi@ARM.com            _status = Running;
18410515SAli.Saidi@ARM.com            schedule(tickEvent, nextCycle());
18510515SAli.Saidi@ARM.com            break;
18610515SAli.Saidi@ARM.com        }
18710515SAli.Saidi@ARM.com    }
18810515SAli.Saidi@ARM.com    if (_status != Running) {
18910515SAli.Saidi@ARM.com        _status = Idle;
19010515SAli.Saidi@ARM.com    }
19110515SAli.Saidi@ARM.com    assert(threadContexts.size() == 1);
19210515SAli.Saidi@ARM.com    ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT
19310515SAli.Saidi@ARM.com    data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too
19410515SAli.Saidi@ARM.com    data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too
19510515SAli.Saidi@ARM.com}
19610515SAli.Saidi@ARM.com
19710515SAli.Saidi@ARM.com
19810515SAli.Saidi@ARM.comvoid
19910515SAli.Saidi@ARM.comAtomicSimpleCPU::activateContext(ThreadID thread_num, int delay)
20010515SAli.Saidi@ARM.com{
20110515SAli.Saidi@ARM.com    DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay);
20210515SAli.Saidi@ARM.com
20310515SAli.Saidi@ARM.com    assert(thread_num == 0);
20410515SAli.Saidi@ARM.com    assert(thread);
20510515SAli.Saidi@ARM.com
20610515SAli.Saidi@ARM.com    assert(_status == Idle);
20710515SAli.Saidi@ARM.com    assert(!tickEvent.scheduled());
20810515SAli.Saidi@ARM.com
20910515SAli.Saidi@ARM.com    notIdleFraction++;
21010798Ssteve.reinhardt@amd.com    numCycles += tickToCycles(thread->lastActivate - thread->lastSuspend);
21110515SAli.Saidi@ARM.com
21210515SAli.Saidi@ARM.com    //Make sure ticks are still on multiples of cycles
21310515SAli.Saidi@ARM.com    schedule(tickEvent, nextCycle(curTick() + ticks(delay)));
21410515SAli.Saidi@ARM.com    _status = Running;
21510515SAli.Saidi@ARM.com}
21610515SAli.Saidi@ARM.com
21710515SAli.Saidi@ARM.com
21810515SAli.Saidi@ARM.comvoid
21911570SCurtis.Dunham@arm.comAtomicSimpleCPU::suspendContext(ThreadID thread_num)
22011570SCurtis.Dunham@arm.com{
22111570SCurtis.Dunham@arm.com    DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
22211570SCurtis.Dunham@arm.com
22311570SCurtis.Dunham@arm.com    assert(thread_num == 0);
22411570SCurtis.Dunham@arm.com    assert(thread);
22510515SAli.Saidi@ARM.com
22610515SAli.Saidi@ARM.com    if (_status == Idle)
22711570SCurtis.Dunham@arm.com        return;
22810515SAli.Saidi@ARM.com
22910515SAli.Saidi@ARM.com    assert(_status == Running);
23011103Snilay@cs.wisc.edu
23110515SAli.Saidi@ARM.com    // tick event may not be scheduled if this gets called from inside
23210515SAli.Saidi@ARM.com    // an instruction's execution, e.g. "quiesce"
23310515SAli.Saidi@ARM.com    if (tickEvent.scheduled())
23410515SAli.Saidi@ARM.com        deschedule(tickEvent);
23511239Sandreas.sandberg@arm.com
23611570SCurtis.Dunham@arm.com    notIdleFraction--;
23710798Ssteve.reinhardt@amd.com    _status = Idle;
23810515SAli.Saidi@ARM.com}
23910515SAli.Saidi@ARM.com
24010900Snilay@cs.wisc.edu
24110515SAli.Saidi@ARM.comFault
24210515SAli.Saidi@ARM.comAtomicSimpleCPU::readMem(Addr addr, uint8_t * data,
24311570SCurtis.Dunham@arm.com                         unsigned size, unsigned flags)
24411570SCurtis.Dunham@arm.com{
24511570SCurtis.Dunham@arm.com    // use the CPU's statically allocated read request and packet objects
24611570SCurtis.Dunham@arm.com    Request *req = &data_read_req;
24710515SAli.Saidi@ARM.com
24810515SAli.Saidi@ARM.com    if (traceData) {
24910515SAli.Saidi@ARM.com        traceData->setAddr(addr);
25010515SAli.Saidi@ARM.com    }
25110515SAli.Saidi@ARM.com
25210515SAli.Saidi@ARM.com    //The block size of our peer.
25310515SAli.Saidi@ARM.com    unsigned blockSize = dcachePort.peerBlockSize();
25410515SAli.Saidi@ARM.com    //The size of the data we're trying to read.
25510515SAli.Saidi@ARM.com    int fullSize = size;
25611239Sandreas.sandberg@arm.com
25710515SAli.Saidi@ARM.com    //The address of the second part of this access if it needs to be split
25810515SAli.Saidi@ARM.com    //across a cache line boundary.
25910515SAli.Saidi@ARM.com    Addr secondAddr = roundDown(addr + size - 1, blockSize);
26010515SAli.Saidi@ARM.com
26110515SAli.Saidi@ARM.com    if (secondAddr > addr)
26210515SAli.Saidi@ARM.com        size = secondAddr - addr;
26310515SAli.Saidi@ARM.com
26410515SAli.Saidi@ARM.com    dcache_latency = 0;
26511570SCurtis.Dunham@arm.com
26610515SAli.Saidi@ARM.com    while (1) {
26710515SAli.Saidi@ARM.com        req->setVirt(0, addr, size, flags, dataMasterId(), thread->pcState().instAddr());
26811570SCurtis.Dunham@arm.com
26911570SCurtis.Dunham@arm.com        // translate to physical address
27011570SCurtis.Dunham@arm.com        Fault fault = thread->dtb->translateAtomic(req, tc, BaseTLB::Read);
27111570SCurtis.Dunham@arm.com
27210515SAli.Saidi@ARM.com        // Now do the access.
27310515SAli.Saidi@ARM.com        if (fault == NoFault && !req->getFlags().isSet(Request::NO_ACCESS)) {
27410515SAli.Saidi@ARM.com            Packet pkt = Packet(req,
27510515SAli.Saidi@ARM.com                                req->isLLSC() ? MemCmd::LoadLockedReq :
27610515SAli.Saidi@ARM.com                                MemCmd::ReadReq);
27710515SAli.Saidi@ARM.com            pkt.dataStatic(data);
27810515SAli.Saidi@ARM.com
27910515SAli.Saidi@ARM.com            if (req->isMmappedIpr())
28010798Ssteve.reinhardt@amd.com                dcache_latency += TheISA::handleIprRead(thread->getTC(), &pkt);
28110515SAli.Saidi@ARM.com            else {
28210515SAli.Saidi@ARM.com                if (fastmem && system->isMemAddr(pkt.getAddr()))
28310515SAli.Saidi@ARM.com                    system->getPhysMem().access(&pkt);
28410515SAli.Saidi@ARM.com                else
28510515SAli.Saidi@ARM.com                    dcache_latency += dcachePort.sendAtomic(&pkt);
28610515SAli.Saidi@ARM.com            }
28710515SAli.Saidi@ARM.com            dcache_access = true;
28810515SAli.Saidi@ARM.com
28910515SAli.Saidi@ARM.com            assert(!pkt.isError());
29010515SAli.Saidi@ARM.com
29110515SAli.Saidi@ARM.com            if (req->isLLSC()) {
29210515SAli.Saidi@ARM.com                TheISA::handleLockedRead(thread, req);
29310515SAli.Saidi@ARM.com            }
29411570SCurtis.Dunham@arm.com        }
29510515SAli.Saidi@ARM.com
29610515SAli.Saidi@ARM.com        //If there's a fault, return it
29710515SAli.Saidi@ARM.com        if (fault != NoFault) {
29811570SCurtis.Dunham@arm.com            if (req->isPrefetch()) {
29911570SCurtis.Dunham@arm.com                return NoFault;
30011570SCurtis.Dunham@arm.com            } else {
30111570SCurtis.Dunham@arm.com                return fault;
30210515SAli.Saidi@ARM.com            }
30310515SAli.Saidi@ARM.com        }
30410515SAli.Saidi@ARM.com
30510515SAli.Saidi@ARM.com        //If we don't need to access a second cache line, stop now.
30610515SAli.Saidi@ARM.com        if (secondAddr <= addr)
30710515SAli.Saidi@ARM.com        {
30810515SAli.Saidi@ARM.com            if (req->isLocked() && fault == NoFault) {
30910515SAli.Saidi@ARM.com                assert(!locked);
31010515SAli.Saidi@ARM.com                locked = true;
31110515SAli.Saidi@ARM.com            }
31210515SAli.Saidi@ARM.com            return fault;
31310515SAli.Saidi@ARM.com        }
31410515SAli.Saidi@ARM.com
31511570SCurtis.Dunham@arm.com        /*
31610515SAli.Saidi@ARM.com         * Set up for accessing the second cache line.
31710515SAli.Saidi@ARM.com         */
31810515SAli.Saidi@ARM.com
31911570SCurtis.Dunham@arm.com        //Move the pointer we're reading into to the correct location.
32011570SCurtis.Dunham@arm.com        data += size;
32111570SCurtis.Dunham@arm.com        //Adjust the size to get the remaining bytes.
32211570SCurtis.Dunham@arm.com        size = addr + fullSize - secondAddr;
32310515SAli.Saidi@ARM.com        //And access the right address.
32410515SAli.Saidi@ARM.com        addr = secondAddr;
32510515SAli.Saidi@ARM.com    }
32610515SAli.Saidi@ARM.com}
32710515SAli.Saidi@ARM.com
32810515SAli.Saidi@ARM.com
32910515SAli.Saidi@ARM.comFault
33010515SAli.Saidi@ARM.comAtomicSimpleCPU::writeMem(uint8_t *data, unsigned size,
33110515SAli.Saidi@ARM.com                          Addr addr, unsigned flags, uint64_t *res)
33210515SAli.Saidi@ARM.com{
33310515SAli.Saidi@ARM.com    // use the CPU's statically allocated write request and packet objects
33410515SAli.Saidi@ARM.com    Request *req = &data_write_req;
33510515SAli.Saidi@ARM.com
33610515SAli.Saidi@ARM.com    if (traceData) {
33710515SAli.Saidi@ARM.com        traceData->setAddr(addr);
33810515SAli.Saidi@ARM.com    }
33910515SAli.Saidi@ARM.com
34010515SAli.Saidi@ARM.com    //The block size of our peer.
34110515SAli.Saidi@ARM.com    unsigned blockSize = dcachePort.peerBlockSize();
34210515SAli.Saidi@ARM.com    //The size of the data we're trying to read.
34310515SAli.Saidi@ARM.com    int fullSize = size;
34410900Snilay@cs.wisc.edu
34510515SAli.Saidi@ARM.com    //The address of the second part of this access if it needs to be split
34610515SAli.Saidi@ARM.com    //across a cache line boundary.
34710515SAli.Saidi@ARM.com    Addr secondAddr = roundDown(addr + size - 1, blockSize);
34810515SAli.Saidi@ARM.com
34910515SAli.Saidi@ARM.com    if(secondAddr > addr)
35010515SAli.Saidi@ARM.com        size = secondAddr - addr;
35110515SAli.Saidi@ARM.com
35210515SAli.Saidi@ARM.com    dcache_latency = 0;
35310515SAli.Saidi@ARM.com
35410515SAli.Saidi@ARM.com    while(1) {
35510515SAli.Saidi@ARM.com        req->setVirt(0, addr, size, flags, dataMasterId(), thread->pcState().instAddr());
35610515SAli.Saidi@ARM.com
35710515SAli.Saidi@ARM.com        // translate to physical address
35810900Snilay@cs.wisc.edu        Fault fault = thread->dtb->translateAtomic(req, tc, BaseTLB::Write);
35910515SAli.Saidi@ARM.com
36010515SAli.Saidi@ARM.com        // Now do the access.
36110515SAli.Saidi@ARM.com        if (fault == NoFault) {
36210515SAli.Saidi@ARM.com            MemCmd cmd = MemCmd::WriteReq; // default
36310515SAli.Saidi@ARM.com            bool do_access = true;  // flag to suppress cache access
36410515SAli.Saidi@ARM.com
36510900Snilay@cs.wisc.edu            if (req->isLLSC()) {
36610515SAli.Saidi@ARM.com                cmd = MemCmd::StoreCondReq;
36710515SAli.Saidi@ARM.com                do_access = TheISA::handleLockedWrite(thread, req);
36810515SAli.Saidi@ARM.com            } else if (req->isSwap()) {
36910515SAli.Saidi@ARM.com                cmd = MemCmd::SwapReq;
37010515SAli.Saidi@ARM.com                if (req->isCondSwap()) {
37110515SAli.Saidi@ARM.com                    assert(res);
37210900Snilay@cs.wisc.edu                    req->setExtraData(*res);
37310515SAli.Saidi@ARM.com                }
37410515SAli.Saidi@ARM.com            }
37510515SAli.Saidi@ARM.com
37610515SAli.Saidi@ARM.com            if (do_access && !req->getFlags().isSet(Request::NO_ACCESS)) {
37710515SAli.Saidi@ARM.com                Packet pkt = Packet(req, cmd);
37810515SAli.Saidi@ARM.com                pkt.dataStatic(data);
37910515SAli.Saidi@ARM.com
38010515SAli.Saidi@ARM.com                if (req->isMmappedIpr()) {
38110515SAli.Saidi@ARM.com                    dcache_latency +=
38210515SAli.Saidi@ARM.com                        TheISA::handleIprWrite(thread->getTC(), &pkt);
38310515SAli.Saidi@ARM.com                } else {
38410515SAli.Saidi@ARM.com                    if (fastmem && system->isMemAddr(pkt.getAddr()))
38510515SAli.Saidi@ARM.com                        system->getPhysMem().access(&pkt);
38610900Snilay@cs.wisc.edu                    else
38710515SAli.Saidi@ARM.com                        dcache_latency += dcachePort.sendAtomic(&pkt);
38810515SAli.Saidi@ARM.com                }
38910515SAli.Saidi@ARM.com                dcache_access = true;
39010515SAli.Saidi@ARM.com                assert(!pkt.isError());
39110515SAli.Saidi@ARM.com
39210515SAli.Saidi@ARM.com                if (req->isSwap()) {
39310515SAli.Saidi@ARM.com                    assert(res);
39410515SAli.Saidi@ARM.com                    memcpy(res, pkt.getPtr<uint8_t>(), fullSize);
39510515SAli.Saidi@ARM.com                }
39610515SAli.Saidi@ARM.com            }
39710515SAli.Saidi@ARM.com
39810515SAli.Saidi@ARM.com            if (res && !req->isSwap()) {
39910515SAli.Saidi@ARM.com                *res = req->getExtraData();
40010900Snilay@cs.wisc.edu            }
40110515SAli.Saidi@ARM.com        }
40210515SAli.Saidi@ARM.com
40310515SAli.Saidi@ARM.com        //If there's a fault or we don't need to access a second cache line,
40410515SAli.Saidi@ARM.com        //stop now.
40510515SAli.Saidi@ARM.com        if (fault != NoFault || secondAddr <= addr)
40610515SAli.Saidi@ARM.com        {
40710515SAli.Saidi@ARM.com            if (req->isLocked() && fault == NoFault) {
40810515SAli.Saidi@ARM.com                assert(locked);
40910515SAli.Saidi@ARM.com                locked = false;
41010515SAli.Saidi@ARM.com            }
41110515SAli.Saidi@ARM.com            if (fault != NoFault && req->isPrefetch()) {
41210515SAli.Saidi@ARM.com                return NoFault;
41310515SAli.Saidi@ARM.com            } else {
41410900Snilay@cs.wisc.edu                return fault;
41510515SAli.Saidi@ARM.com            }
41610515SAli.Saidi@ARM.com        }
41710515SAli.Saidi@ARM.com
41810515SAli.Saidi@ARM.com        /*
41910515SAli.Saidi@ARM.com         * Set up for accessing the second cache line.
42010515SAli.Saidi@ARM.com         */
42110900Snilay@cs.wisc.edu
42210515SAli.Saidi@ARM.com        //Move the pointer we're reading into to the correct location.
42310515SAli.Saidi@ARM.com        data += size;
42410515SAli.Saidi@ARM.com        //Adjust the size to get the remaining bytes.
42510515SAli.Saidi@ARM.com        size = addr + fullSize - secondAddr;
42610515SAli.Saidi@ARM.com        //And access the right address.
42710515SAli.Saidi@ARM.com        addr = secondAddr;
42810900Snilay@cs.wisc.edu    }
42910515SAli.Saidi@ARM.com}
43010515SAli.Saidi@ARM.com
43110515SAli.Saidi@ARM.com
43210515SAli.Saidi@ARM.comvoid
43310515SAli.Saidi@ARM.comAtomicSimpleCPU::tick()
43410515SAli.Saidi@ARM.com{
43510900Snilay@cs.wisc.edu    DPRINTF(SimpleCPU, "Tick\n");
43610515SAli.Saidi@ARM.com
43710515SAli.Saidi@ARM.com    Tick latency = 0;
43810515SAli.Saidi@ARM.com
43910515SAli.Saidi@ARM.com    for (int i = 0; i < width || locked; ++i) {
44010515SAli.Saidi@ARM.com        numCycles++;
44110515SAli.Saidi@ARM.com
44210900Snilay@cs.wisc.edu        if (!curStaticInst || !curStaticInst->isDelayedCommit())
44310515SAli.Saidi@ARM.com            checkForInterrupts();
44410515SAli.Saidi@ARM.com
44510515SAli.Saidi@ARM.com        checkPcEventQueue();
44610515SAli.Saidi@ARM.com        // We must have just got suspended by a PC event
44710515SAli.Saidi@ARM.com        if (_status == Idle)
44810515SAli.Saidi@ARM.com            return;
44910900Snilay@cs.wisc.edu
45010515SAli.Saidi@ARM.com        Fault fault = NoFault;
45110515SAli.Saidi@ARM.com
45210515SAli.Saidi@ARM.com        TheISA::PCState pcState = thread->pcState();
45310515SAli.Saidi@ARM.com
45410515SAli.Saidi@ARM.com        bool needToFetch = !isRomMicroPC(pcState.microPC()) &&
45510515SAli.Saidi@ARM.com                           !curMacroStaticInst;
45610900Snilay@cs.wisc.edu        if (needToFetch) {
45710515SAli.Saidi@ARM.com            setupFetchRequest(&ifetch_req);
45810515SAli.Saidi@ARM.com            fault = thread->itb->translateAtomic(&ifetch_req, tc,
45910515SAli.Saidi@ARM.com                                                 BaseTLB::Execute);
46010515SAli.Saidi@ARM.com        }
46110515SAli.Saidi@ARM.com
46210515SAli.Saidi@ARM.com        if (fault == NoFault) {
46310900Snilay@cs.wisc.edu            Tick icache_latency = 0;
46410515SAli.Saidi@ARM.com            bool icache_access = false;
46510515SAli.Saidi@ARM.com            dcache_access = false; // assume no dcache access
46610515SAli.Saidi@ARM.com
46710515SAli.Saidi@ARM.com            if (needToFetch) {
46810515SAli.Saidi@ARM.com                // This is commented out because the predecoder would act like
46910515SAli.Saidi@ARM.com                // a tiny cache otherwise. It wouldn't be flushed when needed
47010900Snilay@cs.wisc.edu                // like the I cache. It should be flushed, and when that works
47110515SAli.Saidi@ARM.com                // this code should be uncommented.
47210515SAli.Saidi@ARM.com                //Fetch more instruction memory if necessary
47310515SAli.Saidi@ARM.com                //if(predecoder.needMoreBytes())
47410515SAli.Saidi@ARM.com                //{
47510515SAli.Saidi@ARM.com                    icache_access = true;
47610515SAli.Saidi@ARM.com                    Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq);
47710900Snilay@cs.wisc.edu                    ifetch_pkt.dataStatic(&inst);
47810515SAli.Saidi@ARM.com
47910515SAli.Saidi@ARM.com                    if (fastmem && system->isMemAddr(ifetch_pkt.getAddr()))
48010515SAli.Saidi@ARM.com                        system->getPhysMem().access(&ifetch_pkt);
48110515SAli.Saidi@ARM.com                    else
48210515SAli.Saidi@ARM.com                        icache_latency = icachePort.sendAtomic(&ifetch_pkt);
48310515SAli.Saidi@ARM.com
48410900Snilay@cs.wisc.edu                    assert(!ifetch_pkt.isError());
48510515SAli.Saidi@ARM.com
48610515SAli.Saidi@ARM.com                    // ifetch_req is initialized to read the instruction directly
48710515SAli.Saidi@ARM.com                    // into the CPU object's inst field.
48810515SAli.Saidi@ARM.com                //}
48910515SAli.Saidi@ARM.com            }
49010515SAli.Saidi@ARM.com
49110900Snilay@cs.wisc.edu            preExecute();
49210515SAli.Saidi@ARM.com
49310515SAli.Saidi@ARM.com            if (curStaticInst) {
49410515SAli.Saidi@ARM.com                fault = curStaticInst->execute(this, traceData);
49510515SAli.Saidi@ARM.com
49610515SAli.Saidi@ARM.com                // keep an instruction count
49710515SAli.Saidi@ARM.com                if (fault == NoFault)
49810900Snilay@cs.wisc.edu                    countInst();
49910515SAli.Saidi@ARM.com                else if (traceData && !DTRACE(ExecFaulting)) {
50010515SAli.Saidi@ARM.com                    delete traceData;
50110515SAli.Saidi@ARM.com                    traceData = NULL;
50210515SAli.Saidi@ARM.com                }
50310515SAli.Saidi@ARM.com
50410515SAli.Saidi@ARM.com                postExecute();
50510900Snilay@cs.wisc.edu            }
50610515SAli.Saidi@ARM.com
50710515SAli.Saidi@ARM.com            // @todo remove me after debugging with legion done
50810515SAli.Saidi@ARM.com            if (curStaticInst && (!curStaticInst->isMicroop() ||
50910515SAli.Saidi@ARM.com                        curStaticInst->isFirstMicroop()))
51010515SAli.Saidi@ARM.com                instCnt++;
51110515SAli.Saidi@ARM.com
51210900Snilay@cs.wisc.edu            Tick stall_ticks = 0;
51310515SAli.Saidi@ARM.com            if (simulate_inst_stalls && icache_access)
51410515SAli.Saidi@ARM.com                stall_ticks += icache_latency;
51510515SAli.Saidi@ARM.com
51610515SAli.Saidi@ARM.com            if (simulate_data_stalls && dcache_access)
51710515SAli.Saidi@ARM.com                stall_ticks += dcache_latency;
51810515SAli.Saidi@ARM.com
51910900Snilay@cs.wisc.edu            if (stall_ticks) {
52010515SAli.Saidi@ARM.com                Tick stall_cycles = stall_ticks / ticks(1);
52110515SAli.Saidi@ARM.com                Tick aligned_stall_ticks = ticks(stall_cycles);
52210515SAli.Saidi@ARM.com
52310515SAli.Saidi@ARM.com                if (aligned_stall_ticks < stall_ticks)
52410515SAli.Saidi@ARM.com                    aligned_stall_ticks += 1;
52510515SAli.Saidi@ARM.com
52610900Snilay@cs.wisc.edu                latency += aligned_stall_ticks;
52710515SAli.Saidi@ARM.com            }
52810515SAli.Saidi@ARM.com
52910515SAli.Saidi@ARM.com        }
53010515SAli.Saidi@ARM.com        if(fault != NoFault || !stayAtPC)
53110515SAli.Saidi@ARM.com            advancePC(fault);
53210515SAli.Saidi@ARM.com    }
53310900Snilay@cs.wisc.edu
53410515SAli.Saidi@ARM.com    // instruction takes at least one cycle
53510515SAli.Saidi@ARM.com    if (latency < ticks(1))
53610515SAli.Saidi@ARM.com        latency = ticks(1);
53710515SAli.Saidi@ARM.com
53810515SAli.Saidi@ARM.com    if (_status != Idle)
53910515SAli.Saidi@ARM.com        schedule(tickEvent, curTick() + latency);
54010900Snilay@cs.wisc.edu}
54110515SAli.Saidi@ARM.com
54210515SAli.Saidi@ARM.com
54310515SAli.Saidi@ARM.comvoid
54410515SAli.Saidi@ARM.comAtomicSimpleCPU::printAddr(Addr a)
54510515SAli.Saidi@ARM.com{
54610515SAli.Saidi@ARM.com    dcachePort.printAddr(a);
54710900Snilay@cs.wisc.edu}
54810515SAli.Saidi@ARM.com
54910515SAli.Saidi@ARM.com
55010515SAli.Saidi@ARM.com////////////////////////////////////////////////////////////////////////
55110515SAli.Saidi@ARM.com//
55210515SAli.Saidi@ARM.com//  AtomicSimpleCPU Simulation Object
55310515SAli.Saidi@ARM.com//
55410900Snilay@cs.wisc.eduAtomicSimpleCPU *
55510515SAli.Saidi@ARM.comAtomicSimpleCPUParams::create()
55610515SAli.Saidi@ARM.com{
55710515SAli.Saidi@ARM.com    numThreads = 1;
55810515SAli.Saidi@ARM.com    if (!FullSystem && workload.size() != 1)
55910515SAli.Saidi@ARM.com        panic("only one workload allowed");
56010515SAli.Saidi@ARM.com    return new AtomicSimpleCPU(this);
56110900Snilay@cs.wisc.edu}
56210515SAli.Saidi@ARM.com