atomic.cc revision 4878
112854Sgabeblack@google.com/*
212854Sgabeblack@google.com * Copyright (c) 2002-2005 The Regents of The University of Michigan
312854Sgabeblack@google.com * All rights reserved.
412854Sgabeblack@google.com *
512854Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
612854Sgabeblack@google.com * modification, are permitted provided that the following conditions are
712854Sgabeblack@google.com * met: redistributions of source code must retain the above copyright
812854Sgabeblack@google.com * notice, this list of conditions and the following disclaimer;
912854Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright
1012854Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the
1112854Sgabeblack@google.com * documentation and/or other materials provided with the distribution;
1212854Sgabeblack@google.com * neither the name of the copyright holders nor the names of its
1312854Sgabeblack@google.com * contributors may be used to endorse or promote products derived from
1412854Sgabeblack@google.com * this software without specific prior written permission.
1512854Sgabeblack@google.com *
1612854Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1712854Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1812854Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1912854Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2012854Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2112854Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2212854Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2312854Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2412854Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2512854Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2612854Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2712854Sgabeblack@google.com *
2812854Sgabeblack@google.com * Authors: Steve Reinhardt
2912854Sgabeblack@google.com */
3012854Sgabeblack@google.com
3112854Sgabeblack@google.com#include "arch/locked_mem.hh"
3212854Sgabeblack@google.com#include "arch/mmaped_ipr.hh"
3312854Sgabeblack@google.com#include "arch/utility.hh"
3412854Sgabeblack@google.com#include "base/bigint.hh"
3512854Sgabeblack@google.com#include "cpu/exetrace.hh"
3612854Sgabeblack@google.com#include "cpu/simple/atomic.hh"
3712854Sgabeblack@google.com#include "mem/packet.hh"
3812854Sgabeblack@google.com#include "mem/packet_access.hh"
3912854Sgabeblack@google.com#include "sim/builder.hh"
4012854Sgabeblack@google.com#include "sim/system.hh"
4112854Sgabeblack@google.com
4212854Sgabeblack@google.comusing namespace std;
4312854Sgabeblack@google.comusing namespace TheISA;
4412854Sgabeblack@google.com
4512854Sgabeblack@google.comAtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c)
4612854Sgabeblack@google.com    : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
4712854Sgabeblack@google.com{
4812854Sgabeblack@google.com}
4912854Sgabeblack@google.com
5012854Sgabeblack@google.com
5112854Sgabeblack@google.comvoid
5212854Sgabeblack@google.comAtomicSimpleCPU::TickEvent::process()
5312854Sgabeblack@google.com{
5412854Sgabeblack@google.com    cpu->tick();
5512854Sgabeblack@google.com}
5612854Sgabeblack@google.com
5712854Sgabeblack@google.comconst char *
5812854Sgabeblack@google.comAtomicSimpleCPU::TickEvent::description()
5912854Sgabeblack@google.com{
6012854Sgabeblack@google.com    return "AtomicSimpleCPU tick";
6112854Sgabeblack@google.com}
6212854Sgabeblack@google.com
6312854Sgabeblack@google.comPort *
6412854Sgabeblack@google.comAtomicSimpleCPU::getPort(const std::string &if_name, int idx)
6512854Sgabeblack@google.com{
6612854Sgabeblack@google.com    if (if_name == "dcache_port")
6712854Sgabeblack@google.com        return &dcachePort;
6812854Sgabeblack@google.com    else if (if_name == "icache_port")
6912854Sgabeblack@google.com        return &icachePort;
7012854Sgabeblack@google.com    else
7112854Sgabeblack@google.com        panic("No Such Port\n");
7212854Sgabeblack@google.com}
7312854Sgabeblack@google.com
7412854Sgabeblack@google.comvoid
7512854Sgabeblack@google.comAtomicSimpleCPU::init()
7612854Sgabeblack@google.com{
7712854Sgabeblack@google.com    BaseCPU::init();
7812854Sgabeblack@google.com#if FULL_SYSTEM
7912854Sgabeblack@google.com    for (int i = 0; i < threadContexts.size(); ++i) {
8012854Sgabeblack@google.com        ThreadContext *tc = threadContexts[i];
8112854Sgabeblack@google.com
8212854Sgabeblack@google.com        // initialize CPU, including PC
8312854Sgabeblack@google.com        TheISA::initCPU(tc, tc->readCpuId());
8412854Sgabeblack@google.com    }
8512854Sgabeblack@google.com#endif
8612854Sgabeblack@google.com}
8712854Sgabeblack@google.com
8812854Sgabeblack@google.combool
8912854Sgabeblack@google.comAtomicSimpleCPU::CpuPort::recvTiming(PacketPtr pkt)
9012854Sgabeblack@google.com{
9112854Sgabeblack@google.com    panic("AtomicSimpleCPU doesn't expect recvTiming callback!");
9212854Sgabeblack@google.com    return true;
9312854Sgabeblack@google.com}
9412854Sgabeblack@google.com
9512854Sgabeblack@google.comTick
9612854Sgabeblack@google.comAtomicSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
9712854Sgabeblack@google.com{
9812854Sgabeblack@google.com    //Snooping a coherence request, just return
9912854Sgabeblack@google.com    return 0;
10012854Sgabeblack@google.com}
10112854Sgabeblack@google.com
10212854Sgabeblack@google.comvoid
10312854Sgabeblack@google.comAtomicSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
10412854Sgabeblack@google.com{
10512854Sgabeblack@google.com    //No internal storage to update, just return
10612854Sgabeblack@google.com    return;
10712854Sgabeblack@google.com}
10812854Sgabeblack@google.com
10912854Sgabeblack@google.comvoid
11012854Sgabeblack@google.comAtomicSimpleCPU::CpuPort::recvStatusChange(Status status)
11112854Sgabeblack@google.com{
11212854Sgabeblack@google.com    if (status == RangeChange) {
11312854Sgabeblack@google.com        if (!snoopRangeSent) {
11412854Sgabeblack@google.com            snoopRangeSent = true;
11512854Sgabeblack@google.com            sendStatusChange(Port::RangeChange);
11612854Sgabeblack@google.com        }
11712854Sgabeblack@google.com        return;
11812854Sgabeblack@google.com    }
11912854Sgabeblack@google.com
12012854Sgabeblack@google.com    panic("AtomicSimpleCPU doesn't expect recvStatusChange callback!");
12112854Sgabeblack@google.com}
12212854Sgabeblack@google.com
12312854Sgabeblack@google.comvoid
12412854Sgabeblack@google.comAtomicSimpleCPU::CpuPort::recvRetry()
12512854Sgabeblack@google.com{
12612854Sgabeblack@google.com    panic("AtomicSimpleCPU doesn't expect recvRetry callback!");
12712854Sgabeblack@google.com}
12812854Sgabeblack@google.com
12912854Sgabeblack@google.comvoid
13012854Sgabeblack@google.comAtomicSimpleCPU::DcachePort::setPeer(Port *port)
13112854Sgabeblack@google.com{
13212854Sgabeblack@google.com    Port::setPeer(port);
13312854Sgabeblack@google.com
13412854Sgabeblack@google.com#if FULL_SYSTEM
13512854Sgabeblack@google.com    // Update the ThreadContext's memory ports (Functional/Virtual
13612854Sgabeblack@google.com    // Ports)
13712854Sgabeblack@google.com    cpu->tcBase()->connectMemPorts();
13812854Sgabeblack@google.com#endif
13912854Sgabeblack@google.com}
14012854Sgabeblack@google.com
14112854Sgabeblack@google.comAtomicSimpleCPU::AtomicSimpleCPU(Params *p)
14212854Sgabeblack@google.com    : BaseSimpleCPU(p), tickEvent(this),
14312854Sgabeblack@google.com      width(p->width), simulate_stalls(p->simulate_stalls),
14412854Sgabeblack@google.com      icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this)
14512854Sgabeblack@google.com{
14612854Sgabeblack@google.com    _status = Idle;
14712854Sgabeblack@google.com
14812854Sgabeblack@google.com    icachePort.snoopRangeSent = false;
14912854Sgabeblack@google.com    dcachePort.snoopRangeSent = false;
15012854Sgabeblack@google.com
15112854Sgabeblack@google.com    ifetch_req.setThreadContext(p->cpu_id, 0); // Add thread ID if we add MT
15212854Sgabeblack@google.com    data_read_req.setThreadContext(p->cpu_id, 0); // Add thread ID here too
15312854Sgabeblack@google.com    data_write_req.setThreadContext(p->cpu_id, 0); // Add thread ID here too
15412854Sgabeblack@google.com}
15512854Sgabeblack@google.com
15612854Sgabeblack@google.com
15712854Sgabeblack@google.comAtomicSimpleCPU::~AtomicSimpleCPU()
15812854Sgabeblack@google.com{
15912854Sgabeblack@google.com}
16012854Sgabeblack@google.com
16112854Sgabeblack@google.comvoid
16212854Sgabeblack@google.comAtomicSimpleCPU::serialize(ostream &os)
16312854Sgabeblack@google.com{
16412854Sgabeblack@google.com    SimObject::State so_state = SimObject::getState();
16512854Sgabeblack@google.com    SERIALIZE_ENUM(so_state);
16612854Sgabeblack@google.com    Status _status = status();
16712854Sgabeblack@google.com    SERIALIZE_ENUM(_status);
16812854Sgabeblack@google.com    BaseSimpleCPU::serialize(os);
16912854Sgabeblack@google.com    nameOut(os, csprintf("%s.tickEvent", name()));
17012854Sgabeblack@google.com    tickEvent.serialize(os);
17112854Sgabeblack@google.com}
17212854Sgabeblack@google.com
17312854Sgabeblack@google.comvoid
17412854Sgabeblack@google.comAtomicSimpleCPU::unserialize(Checkpoint *cp, const string &section)
17512854Sgabeblack@google.com{
17612854Sgabeblack@google.com    SimObject::State so_state;
17712854Sgabeblack@google.com    UNSERIALIZE_ENUM(so_state);
17812854Sgabeblack@google.com    UNSERIALIZE_ENUM(_status);
17912854Sgabeblack@google.com    BaseSimpleCPU::unserialize(cp, section);
18012854Sgabeblack@google.com    tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
18112854Sgabeblack@google.com}
18212854Sgabeblack@google.com
18312854Sgabeblack@google.comvoid
18412854Sgabeblack@google.comAtomicSimpleCPU::resume()
18512854Sgabeblack@google.com{
18612854Sgabeblack@google.com    if (_status != SwitchedOut && _status != Idle) {
18712854Sgabeblack@google.com        assert(system->getMemoryMode() == System::Atomic);
18812854Sgabeblack@google.com
18912854Sgabeblack@google.com        changeState(SimObject::Running);
19012854Sgabeblack@google.com        if (thread->status() == ThreadContext::Active) {
19112854Sgabeblack@google.com            if (!tickEvent.scheduled()) {
19212854Sgabeblack@google.com                tickEvent.schedule(nextCycle());
19312854Sgabeblack@google.com            }
19412854Sgabeblack@google.com        }
19512854Sgabeblack@google.com    }
19612854Sgabeblack@google.com}
19712854Sgabeblack@google.com
19812854Sgabeblack@google.comvoid
19912854Sgabeblack@google.comAtomicSimpleCPU::switchOut()
20012854Sgabeblack@google.com{
20112854Sgabeblack@google.com    assert(status() == Running || status() == Idle);
20212854Sgabeblack@google.com    _status = SwitchedOut;
20312854Sgabeblack@google.com
20412854Sgabeblack@google.com    tickEvent.squash();
20512854Sgabeblack@google.com}
20612854Sgabeblack@google.com
20712854Sgabeblack@google.com
20812854Sgabeblack@google.comvoid
20912854Sgabeblack@google.comAtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
21012854Sgabeblack@google.com{
21112854Sgabeblack@google.com    BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
21212854Sgabeblack@google.com
21312854Sgabeblack@google.com    assert(!tickEvent.scheduled());
21412854Sgabeblack@google.com
21512854Sgabeblack@google.com    // if any of this CPU's ThreadContexts are active, mark the CPU as
21612854Sgabeblack@google.com    // running and schedule its tick event.
21712854Sgabeblack@google.com    for (int i = 0; i < threadContexts.size(); ++i) {
21812854Sgabeblack@google.com        ThreadContext *tc = threadContexts[i];
21912854Sgabeblack@google.com        if (tc->status() == ThreadContext::Active && _status != Running) {
22012854Sgabeblack@google.com            _status = Running;
22112854Sgabeblack@google.com            tickEvent.schedule(nextCycle());
22212854Sgabeblack@google.com            break;
22312854Sgabeblack@google.com        }
22412854Sgabeblack@google.com    }
22512854Sgabeblack@google.com    if (_status != Running) {
22612854Sgabeblack@google.com        _status = Idle;
22712854Sgabeblack@google.com    }
22812854Sgabeblack@google.com}
22912854Sgabeblack@google.com
23012854Sgabeblack@google.com
23112854Sgabeblack@google.comvoid
23212854Sgabeblack@google.comAtomicSimpleCPU::activateContext(int thread_num, int delay)
23312854Sgabeblack@google.com{
23412854Sgabeblack@google.com    assert(thread_num == 0);
23512854Sgabeblack@google.com    assert(thread);
23612854Sgabeblack@google.com
23712854Sgabeblack@google.com    assert(_status == Idle);
23812854Sgabeblack@google.com    assert(!tickEvent.scheduled());
23912854Sgabeblack@google.com
24012854Sgabeblack@google.com    notIdleFraction++;
24112854Sgabeblack@google.com
24212854Sgabeblack@google.com    //Make sure ticks are still on multiples of cycles
24312854Sgabeblack@google.com    tickEvent.schedule(nextCycle(curTick + cycles(delay)));
24412854Sgabeblack@google.com    _status = Running;
24512854Sgabeblack@google.com}
24612854Sgabeblack@google.com
24712854Sgabeblack@google.com
24812854Sgabeblack@google.comvoid
24912854Sgabeblack@google.comAtomicSimpleCPU::suspendContext(int thread_num)
25012854Sgabeblack@google.com{
25112854Sgabeblack@google.com    assert(thread_num == 0);
25212854Sgabeblack@google.com    assert(thread);
25312854Sgabeblack@google.com
25412854Sgabeblack@google.com    assert(_status == Running);
25512854Sgabeblack@google.com
25612854Sgabeblack@google.com    // tick event may not be scheduled if this gets called from inside
25712854Sgabeblack@google.com    // an instruction's execution, e.g. "quiesce"
25812854Sgabeblack@google.com    if (tickEvent.scheduled())
25912854Sgabeblack@google.com        tickEvent.deschedule();
26012854Sgabeblack@google.com
26112854Sgabeblack@google.com    notIdleFraction--;
26212854Sgabeblack@google.com    _status = Idle;
26312854Sgabeblack@google.com}
26412854Sgabeblack@google.com
26512854Sgabeblack@google.com
26612854Sgabeblack@google.comtemplate <class T>
26712854Sgabeblack@google.comFault
26812854Sgabeblack@google.comAtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
26912854Sgabeblack@google.com{
27012854Sgabeblack@google.com    // use the CPU's statically allocated read request and packet objects
27112854Sgabeblack@google.com    Request *req = &data_read_req;
27212854Sgabeblack@google.com    req->setVirt(0, addr, sizeof(T), flags, thread->readPC());
27312854Sgabeblack@google.com
27412854Sgabeblack@google.com    if (traceData) {
27512854Sgabeblack@google.com        traceData->setAddr(addr);
27612854Sgabeblack@google.com    }
27712854Sgabeblack@google.com
27812854Sgabeblack@google.com    // translate to physical address
27912854Sgabeblack@google.com    Fault fault = thread->translateDataReadReq(req);
28012854Sgabeblack@google.com
28112854Sgabeblack@google.com    // Now do the access.
28212854Sgabeblack@google.com    if (fault == NoFault) {
28312854Sgabeblack@google.com        Packet pkt =
28412854Sgabeblack@google.com            Packet(req,
28512854Sgabeblack@google.com                   req->isLocked() ? MemCmd::LoadLockedReq : MemCmd::ReadReq,
28612854Sgabeblack@google.com                   Packet::Broadcast);
28712854Sgabeblack@google.com        pkt.dataStatic(&data);
28812854Sgabeblack@google.com
28912854Sgabeblack@google.com        if (req->isMmapedIpr())
29012854Sgabeblack@google.com            dcache_latency = TheISA::handleIprRead(thread->getTC(), &pkt);
29112854Sgabeblack@google.com        else
29212854Sgabeblack@google.com            dcache_latency = dcachePort.sendAtomic(&pkt);
29312854Sgabeblack@google.com        dcache_access = true;
29412854Sgabeblack@google.com        assert(!pkt.isError());
29512854Sgabeblack@google.com
29612854Sgabeblack@google.com        if (req->isLocked()) {
29712854Sgabeblack@google.com            TheISA::handleLockedRead(thread, req);
29812854Sgabeblack@google.com        }
29912854Sgabeblack@google.com    }
30012854Sgabeblack@google.com
30112854Sgabeblack@google.com    // This will need a new way to tell if it has a dcache attached.
30212854Sgabeblack@google.com    if (req->isUncacheable())
30312854Sgabeblack@google.com        recordEvent("Uncached Read");
30412854Sgabeblack@google.com
30512854Sgabeblack@google.com    return fault;
30612854Sgabeblack@google.com}
30712854Sgabeblack@google.com
30812854Sgabeblack@google.com#ifndef DOXYGEN_SHOULD_SKIP_THIS
30912854Sgabeblack@google.com
31012854Sgabeblack@google.comtemplate
31112854Sgabeblack@google.comFault
31212854Sgabeblack@google.comAtomicSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags);
31312854Sgabeblack@google.com
31412854Sgabeblack@google.comtemplate
31512854Sgabeblack@google.comFault
31612854Sgabeblack@google.comAtomicSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags);
31712854Sgabeblack@google.com
31812854Sgabeblack@google.comtemplate
31912854Sgabeblack@google.comFault
32012854Sgabeblack@google.comAtomicSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
32112854Sgabeblack@google.com
32212854Sgabeblack@google.comtemplate
32312854Sgabeblack@google.comFault
32412854Sgabeblack@google.comAtomicSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
32512854Sgabeblack@google.com
32612854Sgabeblack@google.comtemplate
32712854Sgabeblack@google.comFault
32812854Sgabeblack@google.comAtomicSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
32912854Sgabeblack@google.com
33012854Sgabeblack@google.comtemplate
33112854Sgabeblack@google.comFault
33212854Sgabeblack@google.comAtomicSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
33312854Sgabeblack@google.com
33412854Sgabeblack@google.com#endif //DOXYGEN_SHOULD_SKIP_THIS
33512854Sgabeblack@google.com
33612854Sgabeblack@google.comtemplate<>
33712854Sgabeblack@google.comFault
33812854Sgabeblack@google.comAtomicSimpleCPU::read(Addr addr, double &data, unsigned flags)
33912854Sgabeblack@google.com{
34012854Sgabeblack@google.com    return read(addr, *(uint64_t*)&data, flags);
34112854Sgabeblack@google.com}
34212854Sgabeblack@google.com
34312854Sgabeblack@google.comtemplate<>
34412854Sgabeblack@google.comFault
34512854Sgabeblack@google.comAtomicSimpleCPU::read(Addr addr, float &data, unsigned flags)
34612854Sgabeblack@google.com{
34712854Sgabeblack@google.com    return read(addr, *(uint32_t*)&data, flags);
34812854Sgabeblack@google.com}
34912854Sgabeblack@google.com
35012854Sgabeblack@google.com
35112854Sgabeblack@google.comtemplate<>
35212854Sgabeblack@google.comFault
35312854Sgabeblack@google.comAtomicSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
35412854Sgabeblack@google.com{
35512854Sgabeblack@google.com    return read(addr, (uint32_t&)data, flags);
35612854Sgabeblack@google.com}
35712854Sgabeblack@google.com
35812854Sgabeblack@google.com
35912854Sgabeblack@google.comtemplate <class T>
36012854Sgabeblack@google.comFault
36112854Sgabeblack@google.comAtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
36212854Sgabeblack@google.com{
36312854Sgabeblack@google.com    // use the CPU's statically allocated write request and packet objects
36412854Sgabeblack@google.com    Request *req = &data_write_req;
36512854Sgabeblack@google.com    req->setVirt(0, addr, sizeof(T), flags, thread->readPC());
36612854Sgabeblack@google.com
36712854Sgabeblack@google.com    if (traceData) {
36812854Sgabeblack@google.com        traceData->setAddr(addr);
36912854Sgabeblack@google.com    }
37012854Sgabeblack@google.com
37112854Sgabeblack@google.com    // translate to physical address
37212854Sgabeblack@google.com    Fault fault = thread->translateDataWriteReq(req);
37312854Sgabeblack@google.com
37412854Sgabeblack@google.com    // Now do the access.
37512854Sgabeblack@google.com    if (fault == NoFault) {
37612854Sgabeblack@google.com        MemCmd cmd = MemCmd::WriteReq; // default
37712854Sgabeblack@google.com        bool do_access = true;  // flag to suppress cache access
37812854Sgabeblack@google.com
37912854Sgabeblack@google.com        if (req->isLocked()) {
38012854Sgabeblack@google.com            cmd = MemCmd::StoreCondReq;
38112854Sgabeblack@google.com            do_access = TheISA::handleLockedWrite(thread, req);
38212854Sgabeblack@google.com        } else if (req->isSwap()) {
38312854Sgabeblack@google.com            cmd = MemCmd::SwapReq;
38412854Sgabeblack@google.com            if (req->isCondSwap()) {
38512854Sgabeblack@google.com                assert(res);
38612854Sgabeblack@google.com                req->setExtraData(*res);
38712854Sgabeblack@google.com            }
38812854Sgabeblack@google.com        }
38912854Sgabeblack@google.com
39012854Sgabeblack@google.com        if (do_access) {
39112854Sgabeblack@google.com            Packet pkt = Packet(req, cmd, Packet::Broadcast);
39212854Sgabeblack@google.com            pkt.dataStatic(&data);
39312854Sgabeblack@google.com
39412854Sgabeblack@google.com            if (req->isMmapedIpr()) {
39512854Sgabeblack@google.com                dcache_latency = TheISA::handleIprWrite(thread->getTC(), &pkt);
39612854Sgabeblack@google.com            } else {
39712854Sgabeblack@google.com                data = htog(data);
39812854Sgabeblack@google.com                dcache_latency = dcachePort.sendAtomic(&pkt);
39912854Sgabeblack@google.com            }
40012854Sgabeblack@google.com            dcache_access = true;
40112854Sgabeblack@google.com            assert(!pkt.isError());
40212854Sgabeblack@google.com
40312854Sgabeblack@google.com            if (req->isSwap()) {
40412854Sgabeblack@google.com                assert(res);
40512854Sgabeblack@google.com                *res = pkt.get<T>();
40612854Sgabeblack@google.com            }
40712854Sgabeblack@google.com        }
40812854Sgabeblack@google.com
40912854Sgabeblack@google.com        if (res && !req->isSwap()) {
41012854Sgabeblack@google.com            *res = req->getExtraData();
41112854Sgabeblack@google.com        }
41212854Sgabeblack@google.com    }
41312854Sgabeblack@google.com
41412854Sgabeblack@google.com    // This will need a new way to tell if it's hooked up to a cache or not.
41512854Sgabeblack@google.com    if (req->isUncacheable())
41612854Sgabeblack@google.com        recordEvent("Uncached Write");
41712854Sgabeblack@google.com
41812854Sgabeblack@google.com    // If the write needs to have a fault on the access, consider calling
41912854Sgabeblack@google.com    // changeStatus() and changing it to "bad addr write" or something.
42012854Sgabeblack@google.com    return fault;
42112854Sgabeblack@google.com}
42212854Sgabeblack@google.com
42312854Sgabeblack@google.com
42412854Sgabeblack@google.com#ifndef DOXYGEN_SHOULD_SKIP_THIS
42512854Sgabeblack@google.com
42612854Sgabeblack@google.comtemplate
42712854Sgabeblack@google.comFault
42812854Sgabeblack@google.comAtomicSimpleCPU::write(Twin32_t data, Addr addr,
42912854Sgabeblack@google.com                       unsigned flags, uint64_t *res);
43012854Sgabeblack@google.com
43112854Sgabeblack@google.comtemplate
43212854Sgabeblack@google.comFault
43312854Sgabeblack@google.comAtomicSimpleCPU::write(Twin64_t data, Addr addr,
43412854Sgabeblack@google.com                       unsigned flags, uint64_t *res);
43512854Sgabeblack@google.com
43612854Sgabeblack@google.comtemplate
43712854Sgabeblack@google.comFault
43812854Sgabeblack@google.comAtomicSimpleCPU::write(uint64_t data, Addr addr,
43912854Sgabeblack@google.com                       unsigned flags, uint64_t *res);
44012854Sgabeblack@google.com
44112854Sgabeblack@google.comtemplate
44212854Sgabeblack@google.comFault
44312854Sgabeblack@google.comAtomicSimpleCPU::write(uint32_t data, Addr addr,
44412854Sgabeblack@google.com                       unsigned flags, uint64_t *res);
44512854Sgabeblack@google.com
44612854Sgabeblack@google.comtemplate
44712854Sgabeblack@google.comFault
44812854Sgabeblack@google.comAtomicSimpleCPU::write(uint16_t data, Addr addr,
44912854Sgabeblack@google.com                       unsigned flags, uint64_t *res);
45012854Sgabeblack@google.com
45112854Sgabeblack@google.comtemplate
45212854Sgabeblack@google.comFault
45312854Sgabeblack@google.comAtomicSimpleCPU::write(uint8_t data, Addr addr,
45412854Sgabeblack@google.com                       unsigned flags, uint64_t *res);
45512854Sgabeblack@google.com
45612854Sgabeblack@google.com#endif //DOXYGEN_SHOULD_SKIP_THIS
45712854Sgabeblack@google.com
45812854Sgabeblack@google.comtemplate<>
45912854Sgabeblack@google.comFault
46012854Sgabeblack@google.comAtomicSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
46112854Sgabeblack@google.com{
46212854Sgabeblack@google.com    return write(*(uint64_t*)&data, addr, flags, res);
46312854Sgabeblack@google.com}
46412854Sgabeblack@google.com
46512854Sgabeblack@google.comtemplate<>
46612854Sgabeblack@google.comFault
46712854Sgabeblack@google.comAtomicSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
46812854Sgabeblack@google.com{
46912854Sgabeblack@google.com    return write(*(uint32_t*)&data, addr, flags, res);
47012854Sgabeblack@google.com}
47112854Sgabeblack@google.com
47212854Sgabeblack@google.com
47312854Sgabeblack@google.comtemplate<>
47412854Sgabeblack@google.comFault
47512854Sgabeblack@google.comAtomicSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
47612854Sgabeblack@google.com{
47712854Sgabeblack@google.com    return write((uint32_t)data, addr, flags, res);
47812854Sgabeblack@google.com}
47912854Sgabeblack@google.com
48012854Sgabeblack@google.com
48112854Sgabeblack@google.comvoid
48212854Sgabeblack@google.comAtomicSimpleCPU::tick()
48312854Sgabeblack@google.com{
48412854Sgabeblack@google.com    Tick latency = cycles(1); // instruction takes one cycle by default
48512854Sgabeblack@google.com
48612854Sgabeblack@google.com    for (int i = 0; i < width; ++i) {
48712854Sgabeblack@google.com        numCycles++;
48812854Sgabeblack@google.com
48912854Sgabeblack@google.com        if (!curStaticInst || !curStaticInst->isDelayedCommit())
49012854Sgabeblack@google.com            checkForInterrupts();
49112854Sgabeblack@google.com
49212854Sgabeblack@google.com        Fault fault = setupFetchRequest(&ifetch_req);
49312854Sgabeblack@google.com
49412854Sgabeblack@google.com        if (fault == NoFault) {
49512854Sgabeblack@google.com            Tick icache_latency = 0;
49612854Sgabeblack@google.com            bool icache_access = false;
49712854Sgabeblack@google.com            dcache_access = false; // assume no dcache access
49812854Sgabeblack@google.com
49912854Sgabeblack@google.com            //Fetch more instruction memory if necessary
50012854Sgabeblack@google.com            //if(predecoder.needMoreBytes())
50112854Sgabeblack@google.com            //{
50212854Sgabeblack@google.com                icache_access = true;
50312854Sgabeblack@google.com                Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq,
50412854Sgabeblack@google.com                                           Packet::Broadcast);
50512854Sgabeblack@google.com                ifetch_pkt.dataStatic(&inst);
50612854Sgabeblack@google.com
50712854Sgabeblack@google.com                icache_latency = icachePort.sendAtomic(&ifetch_pkt);
50812854Sgabeblack@google.com                // ifetch_req is initialized to read the instruction directly
50912854Sgabeblack@google.com                // into the CPU object's inst field.
51012854Sgabeblack@google.com            //}
51112854Sgabeblack@google.com
51212854Sgabeblack@google.com            preExecute();
51312854Sgabeblack@google.com
51412854Sgabeblack@google.com            if(curStaticInst)
51512854Sgabeblack@google.com            {
51612854Sgabeblack@google.com                fault = curStaticInst->execute(this, traceData);
51712854Sgabeblack@google.com                postExecute();
51812854Sgabeblack@google.com            }
51912854Sgabeblack@google.com
52012854Sgabeblack@google.com            // @todo remove me after debugging with legion done
52112854Sgabeblack@google.com            if (curStaticInst && (!curStaticInst->isMicroop() ||
52212854Sgabeblack@google.com                        curStaticInst->isFirstMicroop()))
52312854Sgabeblack@google.com                instCnt++;
52412854Sgabeblack@google.com
52512854Sgabeblack@google.com            if (simulate_stalls) {
52612854Sgabeblack@google.com                Tick icache_stall =
52712854Sgabeblack@google.com                    icache_access ? icache_latency - cycles(1) : 0;
52812854Sgabeblack@google.com                Tick dcache_stall =
52912854Sgabeblack@google.com                    dcache_access ? dcache_latency - cycles(1) : 0;
53012854Sgabeblack@google.com                Tick stall_cycles = (icache_stall + dcache_stall) / cycles(1);
53112854Sgabeblack@google.com                if (cycles(stall_cycles) < (icache_stall + dcache_stall))
53212854Sgabeblack@google.com                    latency += cycles(stall_cycles+1);
53312854Sgabeblack@google.com                else
53412854Sgabeblack@google.com                    latency += cycles(stall_cycles);
53512854Sgabeblack@google.com            }
53612854Sgabeblack@google.com
53712854Sgabeblack@google.com        }
53812854Sgabeblack@google.com        if(fault != NoFault || !stayAtPC)
53912854Sgabeblack@google.com            advancePC(fault);
54012854Sgabeblack@google.com    }
54112854Sgabeblack@google.com
54212854Sgabeblack@google.com    if (_status != Idle)
54312854Sgabeblack@google.com        tickEvent.schedule(curTick + latency);
54412854Sgabeblack@google.com}
54512854Sgabeblack@google.com
54612854Sgabeblack@google.com
54712854Sgabeblack@google.com////////////////////////////////////////////////////////////////////////
54812854Sgabeblack@google.com//
54912854Sgabeblack@google.com//  AtomicSimpleCPU Simulation Object
55012854Sgabeblack@google.com//
55112854Sgabeblack@google.comBEGIN_DECLARE_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
55212854Sgabeblack@google.com
55312854Sgabeblack@google.com    Param<Counter> max_insts_any_thread;
55412854Sgabeblack@google.com    Param<Counter> max_insts_all_threads;
55512854Sgabeblack@google.com    Param<Counter> max_loads_any_thread;
55612854Sgabeblack@google.com    Param<Counter> max_loads_all_threads;
55712854Sgabeblack@google.com    Param<Tick> progress_interval;
55812854Sgabeblack@google.com    SimObjectParam<System *> system;
55912854Sgabeblack@google.com    Param<int> cpu_id;
56012854Sgabeblack@google.com
56112854Sgabeblack@google.com#if FULL_SYSTEM
56212854Sgabeblack@google.com    SimObjectParam<TheISA::ITB *> itb;
56312854Sgabeblack@google.com    SimObjectParam<TheISA::DTB *> dtb;
56412854Sgabeblack@google.com    Param<Tick> profile;
56512854Sgabeblack@google.com
56612854Sgabeblack@google.com    Param<bool> do_quiesce;
56712854Sgabeblack@google.com    Param<bool> do_checkpoint_insts;
56812854Sgabeblack@google.com    Param<bool> do_statistics_insts;
56912854Sgabeblack@google.com#else
57012854Sgabeblack@google.com    SimObjectParam<Process *> workload;
57112854Sgabeblack@google.com#endif // FULL_SYSTEM
57212854Sgabeblack@google.com
57312854Sgabeblack@google.com    Param<int> clock;
57412854Sgabeblack@google.com    Param<int> phase;
57512854Sgabeblack@google.com
57612854Sgabeblack@google.com    Param<bool> defer_registration;
57712854Sgabeblack@google.com    Param<int> width;
57812854Sgabeblack@google.com    Param<bool> function_trace;
57912854Sgabeblack@google.com    Param<Tick> function_trace_start;
58012854Sgabeblack@google.com    Param<bool> simulate_stalls;
58112854Sgabeblack@google.com
58212854Sgabeblack@google.comEND_DECLARE_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
58312854Sgabeblack@google.com
58412854Sgabeblack@google.comBEGIN_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
58512854Sgabeblack@google.com
58612854Sgabeblack@google.com    INIT_PARAM(max_insts_any_thread,
58712854Sgabeblack@google.com               "terminate when any thread reaches this inst count"),
58812854Sgabeblack@google.com    INIT_PARAM(max_insts_all_threads,
58912854Sgabeblack@google.com               "terminate when all threads have reached this inst count"),
59012854Sgabeblack@google.com    INIT_PARAM(max_loads_any_thread,
59112854Sgabeblack@google.com               "terminate when any thread reaches this load count"),
59212854Sgabeblack@google.com    INIT_PARAM(max_loads_all_threads,
59312854Sgabeblack@google.com               "terminate when all threads have reached this load count"),
59412854Sgabeblack@google.com    INIT_PARAM(progress_interval, "Progress interval"),
59512854Sgabeblack@google.com    INIT_PARAM(system, "system object"),
59612854Sgabeblack@google.com    INIT_PARAM(cpu_id, "processor ID"),
59712854Sgabeblack@google.com
59812854Sgabeblack@google.com#if FULL_SYSTEM
59912854Sgabeblack@google.com    INIT_PARAM(itb, "Instruction TLB"),
60012854Sgabeblack@google.com    INIT_PARAM(dtb, "Data TLB"),
60112854Sgabeblack@google.com    INIT_PARAM(profile, ""),
60212854Sgabeblack@google.com    INIT_PARAM(do_quiesce, ""),
60312854Sgabeblack@google.com    INIT_PARAM(do_checkpoint_insts, ""),
60412854Sgabeblack@google.com    INIT_PARAM(do_statistics_insts, ""),
60512854Sgabeblack@google.com#else
60612854Sgabeblack@google.com    INIT_PARAM(workload, "processes to run"),
60712854Sgabeblack@google.com#endif // FULL_SYSTEM
60812854Sgabeblack@google.com
60912854Sgabeblack@google.com    INIT_PARAM(clock, "clock speed"),
61012854Sgabeblack@google.com    INIT_PARAM_DFLT(phase, "clock phase", 0),
61112854Sgabeblack@google.com    INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
61212854Sgabeblack@google.com    INIT_PARAM(width, "cpu width"),
61312854Sgabeblack@google.com    INIT_PARAM(function_trace, "Enable function trace"),
61412854Sgabeblack@google.com    INIT_PARAM(function_trace_start, "Cycle to start function trace"),
61512854Sgabeblack@google.com    INIT_PARAM(simulate_stalls, "Simulate cache stall cycles")
61612854Sgabeblack@google.com
61712854Sgabeblack@google.comEND_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
61812854Sgabeblack@google.com
61912854Sgabeblack@google.com
62012854Sgabeblack@google.comCREATE_SIM_OBJECT(AtomicSimpleCPU)
62112854Sgabeblack@google.com{
62212854Sgabeblack@google.com    AtomicSimpleCPU::Params *params = new AtomicSimpleCPU::Params();
62312854Sgabeblack@google.com    params->name = getInstanceName();
62412854Sgabeblack@google.com    params->numberOfThreads = 1;
62512854Sgabeblack@google.com    params->max_insts_any_thread = max_insts_any_thread;
62612854Sgabeblack@google.com    params->max_insts_all_threads = max_insts_all_threads;
62712854Sgabeblack@google.com    params->max_loads_any_thread = max_loads_any_thread;
62812854Sgabeblack@google.com    params->max_loads_all_threads = max_loads_all_threads;
62912854Sgabeblack@google.com    params->progress_interval = progress_interval;
63012854Sgabeblack@google.com    params->deferRegistration = defer_registration;
63112854Sgabeblack@google.com    params->phase = phase;
63212854Sgabeblack@google.com    params->clock = clock;
63312854Sgabeblack@google.com    params->functionTrace = function_trace;
63412854Sgabeblack@google.com    params->functionTraceStart = function_trace_start;
63512854Sgabeblack@google.com    params->width = width;
63612854Sgabeblack@google.com    params->simulate_stalls = simulate_stalls;
63712854Sgabeblack@google.com    params->system = system;
63812854Sgabeblack@google.com    params->cpu_id = cpu_id;
63912854Sgabeblack@google.com
64012854Sgabeblack@google.com#if FULL_SYSTEM
64112854Sgabeblack@google.com    params->itb = itb;
64212854Sgabeblack@google.com    params->dtb = dtb;
64312854Sgabeblack@google.com    params->profile = profile;
64412854Sgabeblack@google.com    params->do_quiesce = do_quiesce;
64512854Sgabeblack@google.com    params->do_checkpoint_insts = do_checkpoint_insts;
64612854Sgabeblack@google.com    params->do_statistics_insts = do_statistics_insts;
64712854Sgabeblack@google.com#else
64812854Sgabeblack@google.com    params->process = workload;
64912854Sgabeblack@google.com#endif
65012854Sgabeblack@google.com
65112854Sgabeblack@google.com    AtomicSimpleCPU *cpu = new AtomicSimpleCPU(params);
65212854Sgabeblack@google.com    return cpu;
65312854Sgabeblack@google.com}
65412854Sgabeblack@google.com
65512854Sgabeblack@google.comREGISTER_SIM_OBJECT("AtomicSimpleCPU", AtomicSimpleCPU)
65612854Sgabeblack@google.com
65712854Sgabeblack@google.com