atomic.cc revision 3170
111507SCurtis.Dunham@arm.com/*
211507SCurtis.Dunham@arm.com * Copyright (c) 2002-2005 The Regents of The University of Michigan
311960Sgabeblack@google.com * All rights reserved.
411960Sgabeblack@google.com *
511960Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
611960Sgabeblack@google.com * modification, are permitted provided that the following conditions are
711960Sgabeblack@google.com * met: redistributions of source code must retain the above copyright
811960Sgabeblack@google.com * notice, this list of conditions and the following disclaimer;
911960Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright
1011960Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the
1111960Sgabeblack@google.com * documentation and/or other materials provided with the distribution;
1211960Sgabeblack@google.com * neither the name of the copyright holders nor the names of its
1311960Sgabeblack@google.com * contributors may be used to endorse or promote products derived from
1411960Sgabeblack@google.com * this software without specific prior written permission.
1511960Sgabeblack@google.com *
1611960Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1711960Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1811960Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1911960Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2011960Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2111960Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2211960Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2311960Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2411960Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2511960Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2611960Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2711960Sgabeblack@google.com *
2811960Sgabeblack@google.com * Authors: Steve Reinhardt
2911960Sgabeblack@google.com */
3011960Sgabeblack@google.com
3111960Sgabeblack@google.com#include "arch/locked_mem.hh"
3211960Sgabeblack@google.com#include "arch/utility.hh"
3311960Sgabeblack@google.com#include "cpu/exetrace.hh"
3411960Sgabeblack@google.com#include "cpu/simple/atomic.hh"
3511960Sgabeblack@google.com#include "mem/packet_impl.hh"
3611960Sgabeblack@google.com#include "sim/builder.hh"
3711960Sgabeblack@google.com#include "sim/system.hh"
3811960Sgabeblack@google.com
3911960Sgabeblack@google.comusing namespace std;
4011960Sgabeblack@google.comusing namespace TheISA;
4111960Sgabeblack@google.com
4211960Sgabeblack@google.comAtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c)
4311960Sgabeblack@google.com    : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
4411960Sgabeblack@google.com{
4511960Sgabeblack@google.com}
4611960Sgabeblack@google.com
4711960Sgabeblack@google.com
4811960Sgabeblack@google.comvoid
4911960Sgabeblack@google.comAtomicSimpleCPU::TickEvent::process()
5011960Sgabeblack@google.com{
5111960Sgabeblack@google.com    cpu->tick();
5211960Sgabeblack@google.com}
5311960Sgabeblack@google.com
5411960Sgabeblack@google.comconst char *
5511960Sgabeblack@google.comAtomicSimpleCPU::TickEvent::description()
5611960Sgabeblack@google.com{
5711960Sgabeblack@google.com    return "AtomicSimpleCPU tick event";
5811960Sgabeblack@google.com}
5911960Sgabeblack@google.com
6011960Sgabeblack@google.comPort *
6111960Sgabeblack@google.comAtomicSimpleCPU::getPort(const std::string &if_name, int idx)
6211960Sgabeblack@google.com{
6311960Sgabeblack@google.com    if (if_name == "dcache_port")
6411960Sgabeblack@google.com        return &dcachePort;
6511960Sgabeblack@google.com    else if (if_name == "icache_port")
6611960Sgabeblack@google.com        return &icachePort;
6711960Sgabeblack@google.com    else
6811960Sgabeblack@google.com        panic("No Such Port\n");
6911960Sgabeblack@google.com}
7011960Sgabeblack@google.com
7111960Sgabeblack@google.comvoid
7211960Sgabeblack@google.comAtomicSimpleCPU::init()
7311960Sgabeblack@google.com{
7411960Sgabeblack@google.com    //Create Memory Ports (conect them up)
7511960Sgabeblack@google.com//    Port *mem_dport = mem->getPort("");
7611960Sgabeblack@google.com//    dcachePort.setPeer(mem_dport);
7711960Sgabeblack@google.com//    mem_dport->setPeer(&dcachePort);
7811960Sgabeblack@google.com
7911960Sgabeblack@google.com//    Port *mem_iport = mem->getPort("");
8011960Sgabeblack@google.com//    icachePort.setPeer(mem_iport);
8111960Sgabeblack@google.com//    mem_iport->setPeer(&icachePort);
8211960Sgabeblack@google.com
8311960Sgabeblack@google.com    BaseCPU::init();
8411960Sgabeblack@google.com#if FULL_SYSTEM
8511960Sgabeblack@google.com    for (int i = 0; i < threadContexts.size(); ++i) {
8611960Sgabeblack@google.com        ThreadContext *tc = threadContexts[i];
8711960Sgabeblack@google.com
8811960Sgabeblack@google.com        // initialize CPU, including PC
8911960Sgabeblack@google.com        TheISA::initCPU(tc, tc->readCpuId());
9011960Sgabeblack@google.com    }
9111960Sgabeblack@google.com#endif
9211960Sgabeblack@google.com}
9311960Sgabeblack@google.com
9411960Sgabeblack@google.combool
9511960Sgabeblack@google.comAtomicSimpleCPU::CpuPort::recvTiming(Packet *pkt)
9611960Sgabeblack@google.com{
9711960Sgabeblack@google.com    panic("AtomicSimpleCPU doesn't expect recvAtomic callback!");
9811960Sgabeblack@google.com    return true;
9911960Sgabeblack@google.com}
10011960Sgabeblack@google.com
10111960Sgabeblack@google.comTick
10211960Sgabeblack@google.comAtomicSimpleCPU::CpuPort::recvAtomic(Packet *pkt)
10311960Sgabeblack@google.com{
10411960Sgabeblack@google.com    panic("AtomicSimpleCPU doesn't expect recvAtomic callback!");
10511960Sgabeblack@google.com    return curTick;
10611960Sgabeblack@google.com}
10711960Sgabeblack@google.com
10811960Sgabeblack@google.comvoid
10911960Sgabeblack@google.comAtomicSimpleCPU::CpuPort::recvFunctional(Packet *pkt)
11011960Sgabeblack@google.com{
11111960Sgabeblack@google.com    panic("AtomicSimpleCPU doesn't expect recvFunctional callback!");
11211960Sgabeblack@google.com}
11311960Sgabeblack@google.com
11411960Sgabeblack@google.comvoid
11511960Sgabeblack@google.comAtomicSimpleCPU::CpuPort::recvStatusChange(Status status)
11611960Sgabeblack@google.com{
11711960Sgabeblack@google.com    if (status == RangeChange)
11811960Sgabeblack@google.com        return;
11911960Sgabeblack@google.com
12011960Sgabeblack@google.com    panic("AtomicSimpleCPU doesn't expect recvStatusChange callback!");
12111960Sgabeblack@google.com}
12211960Sgabeblack@google.com
12311960Sgabeblack@google.comvoid
12411960Sgabeblack@google.comAtomicSimpleCPU::CpuPort::recvRetry()
12511960Sgabeblack@google.com{
12611960Sgabeblack@google.com    panic("AtomicSimpleCPU doesn't expect recvRetry callback!");
12711960Sgabeblack@google.com}
12811960Sgabeblack@google.com
12911960Sgabeblack@google.com
13011960Sgabeblack@google.comAtomicSimpleCPU::AtomicSimpleCPU(Params *p)
13111960Sgabeblack@google.com    : BaseSimpleCPU(p), tickEvent(this),
13211960Sgabeblack@google.com      width(p->width), simulate_stalls(p->simulate_stalls),
13311960Sgabeblack@google.com      icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this)
13411960Sgabeblack@google.com{
13511960Sgabeblack@google.com    _status = Idle;
13611960Sgabeblack@google.com
13711960Sgabeblack@google.com    ifetch_req = new Request();
13811960Sgabeblack@google.com    ifetch_req->setThreadContext(p->cpu_id, 0); // Add thread ID if we add MT
13911960Sgabeblack@google.com    ifetch_pkt = new Packet(ifetch_req, Packet::ReadReq, Packet::Broadcast);
14011960Sgabeblack@google.com    ifetch_pkt->dataStatic(&inst);
14111960Sgabeblack@google.com
14211960Sgabeblack@google.com    data_read_req = new Request();
14311960Sgabeblack@google.com    data_read_req->setThreadContext(p->cpu_id, 0); // Add thread ID here too
14411960Sgabeblack@google.com    data_read_pkt = new Packet(data_read_req, Packet::ReadReq,
14511960Sgabeblack@google.com                               Packet::Broadcast);
14611960Sgabeblack@google.com    data_read_pkt->dataStatic(&dataReg);
14711960Sgabeblack@google.com
14811960Sgabeblack@google.com    data_write_req = new Request();
14911960Sgabeblack@google.com    data_write_req->setThreadContext(p->cpu_id, 0); // Add thread ID here too
15011960Sgabeblack@google.com    data_write_pkt = new Packet(data_write_req, Packet::WriteReq,
15111960Sgabeblack@google.com                                Packet::Broadcast);
15211960Sgabeblack@google.com}
15311960Sgabeblack@google.com
15411960Sgabeblack@google.com
15511960Sgabeblack@google.comAtomicSimpleCPU::~AtomicSimpleCPU()
15611960Sgabeblack@google.com{
15711960Sgabeblack@google.com}
15811960Sgabeblack@google.com
15911960Sgabeblack@google.comvoid
16011960Sgabeblack@google.comAtomicSimpleCPU::serialize(ostream &os)
16111960Sgabeblack@google.com{
16211960Sgabeblack@google.com    SimObject::State so_state = SimObject::getState();
16311960Sgabeblack@google.com    SERIALIZE_ENUM(so_state);
16411960Sgabeblack@google.com    BaseSimpleCPU::serialize(os);
16511960Sgabeblack@google.com    nameOut(os, csprintf("%s.tickEvent", name()));
16611960Sgabeblack@google.com    tickEvent.serialize(os);
16711960Sgabeblack@google.com}
16811960Sgabeblack@google.com
16911960Sgabeblack@google.comvoid
17011960Sgabeblack@google.comAtomicSimpleCPU::unserialize(Checkpoint *cp, const string &section)
17111960Sgabeblack@google.com{
17211960Sgabeblack@google.com    SimObject::State so_state;
17311960Sgabeblack@google.com    UNSERIALIZE_ENUM(so_state);
17411960Sgabeblack@google.com    BaseSimpleCPU::unserialize(cp, section);
17511960Sgabeblack@google.com    tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
17611960Sgabeblack@google.com}
17711960Sgabeblack@google.com
17811960Sgabeblack@google.comvoid
17911960Sgabeblack@google.comAtomicSimpleCPU::resume()
18011960Sgabeblack@google.com{
18111960Sgabeblack@google.com    assert(system->getMemoryMode() == System::Atomic);
18211960Sgabeblack@google.com    changeState(SimObject::Running);
18311960Sgabeblack@google.com    if (thread->status() == ThreadContext::Active) {
18411960Sgabeblack@google.com        if (!tickEvent.scheduled())
18511960Sgabeblack@google.com            tickEvent.schedule(curTick);
18611960Sgabeblack@google.com    }
18711960Sgabeblack@google.com}
18811960Sgabeblack@google.com
18911960Sgabeblack@google.comvoid
19011960Sgabeblack@google.comAtomicSimpleCPU::switchOut()
19111960Sgabeblack@google.com{
19211960Sgabeblack@google.com    assert(status() == Running || status() == Idle);
19311960Sgabeblack@google.com    _status = SwitchedOut;
19411960Sgabeblack@google.com
19511960Sgabeblack@google.com    tickEvent.squash();
19611960Sgabeblack@google.com}
19711960Sgabeblack@google.com
19811960Sgabeblack@google.com
19911960Sgabeblack@google.comvoid
20011960Sgabeblack@google.comAtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
20111960Sgabeblack@google.com{
20211960Sgabeblack@google.com    BaseCPU::takeOverFrom(oldCPU);
20311960Sgabeblack@google.com
20411960Sgabeblack@google.com    assert(!tickEvent.scheduled());
20511960Sgabeblack@google.com
20611960Sgabeblack@google.com    // if any of this CPU's ThreadContexts are active, mark the CPU as
20711960Sgabeblack@google.com    // running and schedule its tick event.
20811960Sgabeblack@google.com    for (int i = 0; i < threadContexts.size(); ++i) {
20911960Sgabeblack@google.com        ThreadContext *tc = threadContexts[i];
21011960Sgabeblack@google.com        if (tc->status() == ThreadContext::Active && _status != Running) {
21111960Sgabeblack@google.com            _status = Running;
21211960Sgabeblack@google.com            tickEvent.schedule(curTick);
21311960Sgabeblack@google.com            break;
21411960Sgabeblack@google.com        }
21511960Sgabeblack@google.com    }
21611960Sgabeblack@google.com}
21711960Sgabeblack@google.com
21811960Sgabeblack@google.com
21911960Sgabeblack@google.comvoid
22011960Sgabeblack@google.comAtomicSimpleCPU::activateContext(int thread_num, int delay)
22111960Sgabeblack@google.com{
22211960Sgabeblack@google.com    assert(thread_num == 0);
22311960Sgabeblack@google.com    assert(thread);
22411960Sgabeblack@google.com
22511960Sgabeblack@google.com    assert(_status == Idle);
22611960Sgabeblack@google.com    assert(!tickEvent.scheduled());
22711960Sgabeblack@google.com
22811960Sgabeblack@google.com    notIdleFraction++;
22911960Sgabeblack@google.com    tickEvent.schedule(curTick + cycles(delay));
23011960Sgabeblack@google.com    _status = Running;
23111960Sgabeblack@google.com}
23211960Sgabeblack@google.com
23311960Sgabeblack@google.com
23411960Sgabeblack@google.comvoid
23511960Sgabeblack@google.comAtomicSimpleCPU::suspendContext(int thread_num)
23611960Sgabeblack@google.com{
23711960Sgabeblack@google.com    assert(thread_num == 0);
23811960Sgabeblack@google.com    assert(thread);
23911960Sgabeblack@google.com
24011960Sgabeblack@google.com    assert(_status == Running);
24111960Sgabeblack@google.com
24211960Sgabeblack@google.com    // tick event may not be scheduled if this gets called from inside
24311960Sgabeblack@google.com    // an instruction's execution, e.g. "quiesce"
24411960Sgabeblack@google.com    if (tickEvent.scheduled())
24511960Sgabeblack@google.com        tickEvent.deschedule();
24611960Sgabeblack@google.com
24711960Sgabeblack@google.com    notIdleFraction--;
24811960Sgabeblack@google.com    _status = Idle;
24911960Sgabeblack@google.com}
25011960Sgabeblack@google.com
25111960Sgabeblack@google.com
25211960Sgabeblack@google.comtemplate <class T>
25311960Sgabeblack@google.comFault
25411960Sgabeblack@google.comAtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
25511960Sgabeblack@google.com{
25611960Sgabeblack@google.com    // use the CPU's statically allocated read request and packet objects
25711960Sgabeblack@google.com    Request *req = data_read_req;
25811960Sgabeblack@google.com    Packet  *pkt = data_read_pkt;
25911960Sgabeblack@google.com
26011960Sgabeblack@google.com    req->setVirt(0, addr, sizeof(T), flags, thread->readPC());
26111960Sgabeblack@google.com
26211960Sgabeblack@google.com    if (traceData) {
26311960Sgabeblack@google.com        traceData->setAddr(addr);
26411960Sgabeblack@google.com    }
26511960Sgabeblack@google.com
26611960Sgabeblack@google.com    // translate to physical address
26711960Sgabeblack@google.com    Fault fault = thread->translateDataReadReq(req);
26811960Sgabeblack@google.com
26911960Sgabeblack@google.com    // Now do the access.
27011960Sgabeblack@google.com    if (fault == NoFault) {
27111960Sgabeblack@google.com        pkt->reinitFromRequest();
27211960Sgabeblack@google.com
27311960Sgabeblack@google.com        dcache_latency = dcachePort.sendAtomic(pkt);
27411960Sgabeblack@google.com        dcache_access = true;
27511960Sgabeblack@google.com
27611960Sgabeblack@google.com        assert(pkt->result == Packet::Success);
27711960Sgabeblack@google.com        data = pkt->get<T>();
27811960Sgabeblack@google.com
27911960Sgabeblack@google.com        if (req->isLocked()) {
28011960Sgabeblack@google.com            TheISA::handleLockedRead(thread, req);
28111960Sgabeblack@google.com        }
28211960Sgabeblack@google.com    }
28311960Sgabeblack@google.com
28411960Sgabeblack@google.com    // This will need a new way to tell if it has a dcache attached.
28511960Sgabeblack@google.com    if (req->getFlags() & UNCACHEABLE)
28611960Sgabeblack@google.com        recordEvent("Uncached Read");
28711960Sgabeblack@google.com
28811960Sgabeblack@google.com    return fault;
28911960Sgabeblack@google.com}
29011960Sgabeblack@google.com
29111960Sgabeblack@google.com#ifndef DOXYGEN_SHOULD_SKIP_THIS
29211960Sgabeblack@google.com
29311960Sgabeblack@google.comtemplate
29411960Sgabeblack@google.comFault
29511960Sgabeblack@google.comAtomicSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
29611960Sgabeblack@google.com
29711960Sgabeblack@google.comtemplate
29811960Sgabeblack@google.comFault
29911960Sgabeblack@google.comAtomicSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
30011960Sgabeblack@google.com
30111960Sgabeblack@google.comtemplate
30211960Sgabeblack@google.comFault
30311960Sgabeblack@google.comAtomicSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
30411960Sgabeblack@google.com
30511960Sgabeblack@google.comtemplate
30611960Sgabeblack@google.comFault
30711960Sgabeblack@google.comAtomicSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
30811960Sgabeblack@google.com
30911960Sgabeblack@google.com#endif //DOXYGEN_SHOULD_SKIP_THIS
31011960Sgabeblack@google.com
31111960Sgabeblack@google.comtemplate<>
31211960Sgabeblack@google.comFault
31311960Sgabeblack@google.comAtomicSimpleCPU::read(Addr addr, double &data, unsigned flags)
31411960Sgabeblack@google.com{
31511960Sgabeblack@google.com    return read(addr, *(uint64_t*)&data, flags);
31611960Sgabeblack@google.com}
31711960Sgabeblack@google.com
31811960Sgabeblack@google.comtemplate<>
31911960Sgabeblack@google.comFault
32011960Sgabeblack@google.comAtomicSimpleCPU::read(Addr addr, float &data, unsigned flags)
32111960Sgabeblack@google.com{
32211960Sgabeblack@google.com    return read(addr, *(uint32_t*)&data, flags);
32311960Sgabeblack@google.com}
32411960Sgabeblack@google.com
32511960Sgabeblack@google.com
32611960Sgabeblack@google.comtemplate<>
32711960Sgabeblack@google.comFault
32811960Sgabeblack@google.comAtomicSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
32911960Sgabeblack@google.com{
33011960Sgabeblack@google.com    return read(addr, (uint32_t&)data, flags);
33111960Sgabeblack@google.com}
33211960Sgabeblack@google.com
33311960Sgabeblack@google.com
33411960Sgabeblack@google.comtemplate <class T>
33511960Sgabeblack@google.comFault
33611960Sgabeblack@google.comAtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
33711960Sgabeblack@google.com{
33811960Sgabeblack@google.com    // use the CPU's statically allocated write request and packet objects
33911960Sgabeblack@google.com    Request *req = data_write_req;
34011960Sgabeblack@google.com    Packet  *pkt = data_write_pkt;
34111960Sgabeblack@google.com
34211960Sgabeblack@google.com    req->setVirt(0, addr, sizeof(T), flags, thread->readPC());
34311960Sgabeblack@google.com
34411960Sgabeblack@google.com    if (traceData) {
34511960Sgabeblack@google.com        traceData->setAddr(addr);
34611960Sgabeblack@google.com    }
34711960Sgabeblack@google.com
34811960Sgabeblack@google.com    // translate to physical address
34911960Sgabeblack@google.com    Fault fault = thread->translateDataWriteReq(req);
35011960Sgabeblack@google.com
35111960Sgabeblack@google.com    // Now do the access.
35211960Sgabeblack@google.com    if (fault == NoFault) {
35311960Sgabeblack@google.com        bool do_access = true;  // flag to suppress cache access
35411960Sgabeblack@google.com
35511960Sgabeblack@google.com        if (req->isLocked()) {
35611960Sgabeblack@google.com            do_access = TheISA::handleLockedWrite(thread, req);
35711960Sgabeblack@google.com        }
35811960Sgabeblack@google.com
35911960Sgabeblack@google.com        if (do_access) {
36011960Sgabeblack@google.com            data = htog(data);
36111960Sgabeblack@google.com            pkt->reinitFromRequest();
36211960Sgabeblack@google.com            pkt->dataStatic(&data);
36311960Sgabeblack@google.com
36411960Sgabeblack@google.com            dcache_latency = dcachePort.sendAtomic(pkt);
36511960Sgabeblack@google.com            dcache_access = true;
36611960Sgabeblack@google.com
36711960Sgabeblack@google.com            assert(pkt->result == Packet::Success);
36811960Sgabeblack@google.com        }
36911960Sgabeblack@google.com
37011960Sgabeblack@google.com        if (req->isLocked()) {
37111960Sgabeblack@google.com            uint64_t scResult = req->getScResult();
37211960Sgabeblack@google.com            if (scResult != 0) {
37311960Sgabeblack@google.com                // clear failure counter
37411960Sgabeblack@google.com                thread->setStCondFailures(0);
37511960Sgabeblack@google.com            }
37611960Sgabeblack@google.com            if (res) {
37711960Sgabeblack@google.com                *res = req->getScResult();
37811960Sgabeblack@google.com            }
37911960Sgabeblack@google.com        }
38011960Sgabeblack@google.com    }
38111960Sgabeblack@google.com
38211960Sgabeblack@google.com    // This will need a new way to tell if it's hooked up to a cache or not.
38311960Sgabeblack@google.com    if (req->getFlags() & UNCACHEABLE)
38411960Sgabeblack@google.com        recordEvent("Uncached Write");
38511960Sgabeblack@google.com
38611960Sgabeblack@google.com    // If the write needs to have a fault on the access, consider calling
38711960Sgabeblack@google.com    // changeStatus() and changing it to "bad addr write" or something.
38811960Sgabeblack@google.com    return fault;
38911960Sgabeblack@google.com}
39011960Sgabeblack@google.com
39111960Sgabeblack@google.com
39211960Sgabeblack@google.com#ifndef DOXYGEN_SHOULD_SKIP_THIS
39311960Sgabeblack@google.comtemplate
39411960Sgabeblack@google.comFault
39511960Sgabeblack@google.comAtomicSimpleCPU::write(uint64_t data, Addr addr,
39611960Sgabeblack@google.com                       unsigned flags, uint64_t *res);
39711960Sgabeblack@google.com
39811960Sgabeblack@google.comtemplate
39911960Sgabeblack@google.comFault
40011960Sgabeblack@google.comAtomicSimpleCPU::write(uint32_t data, Addr addr,
40111960Sgabeblack@google.com                       unsigned flags, uint64_t *res);
40211960Sgabeblack@google.com
40311960Sgabeblack@google.comtemplate
40411960Sgabeblack@google.comFault
40511960Sgabeblack@google.comAtomicSimpleCPU::write(uint16_t data, Addr addr,
40611960Sgabeblack@google.com                       unsigned flags, uint64_t *res);
40711960Sgabeblack@google.com
40811960Sgabeblack@google.comtemplate
40911960Sgabeblack@google.comFault
41011960Sgabeblack@google.comAtomicSimpleCPU::write(uint8_t data, Addr addr,
41111960Sgabeblack@google.com                       unsigned flags, uint64_t *res);
41211960Sgabeblack@google.com
41311960Sgabeblack@google.com#endif //DOXYGEN_SHOULD_SKIP_THIS
41411960Sgabeblack@google.com
41511960Sgabeblack@google.comtemplate<>
41611960Sgabeblack@google.comFault
41711960Sgabeblack@google.comAtomicSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
41811960Sgabeblack@google.com{
41911960Sgabeblack@google.com    return write(*(uint64_t*)&data, addr, flags, res);
42011960Sgabeblack@google.com}
42111960Sgabeblack@google.com
42211960Sgabeblack@google.comtemplate<>
42311960Sgabeblack@google.comFault
42411960Sgabeblack@google.comAtomicSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
42511960Sgabeblack@google.com{
42611960Sgabeblack@google.com    return write(*(uint32_t*)&data, addr, flags, res);
42711960Sgabeblack@google.com}
42811960Sgabeblack@google.com
42911960Sgabeblack@google.com
43011960Sgabeblack@google.comtemplate<>
43111960Sgabeblack@google.comFault
43211960Sgabeblack@google.comAtomicSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
43311960Sgabeblack@google.com{
43411960Sgabeblack@google.com    return write((uint32_t)data, addr, flags, res);
43511960Sgabeblack@google.com}
43611960Sgabeblack@google.com
43711960Sgabeblack@google.com
43811960Sgabeblack@google.comvoid
43911960Sgabeblack@google.comAtomicSimpleCPU::tick()
44011960Sgabeblack@google.com{
44111960Sgabeblack@google.com    Tick latency = cycles(1); // instruction takes one cycle by default
44211960Sgabeblack@google.com
44311960Sgabeblack@google.com    for (int i = 0; i < width; ++i) {
44411960Sgabeblack@google.com        numCycles++;
44511960Sgabeblack@google.com
44611960Sgabeblack@google.com        checkForInterrupts();
44711960Sgabeblack@google.com
44811960Sgabeblack@google.com        Fault fault = setupFetchRequest(ifetch_req);
44911960Sgabeblack@google.com
45011960Sgabeblack@google.com        if (fault == NoFault) {
45111960Sgabeblack@google.com            ifetch_pkt->reinitFromRequest();
45211960Sgabeblack@google.com
45311960Sgabeblack@google.com            Tick icache_latency = icachePort.sendAtomic(ifetch_pkt);
45411960Sgabeblack@google.com            // ifetch_req is initialized to read the instruction directly
45511960Sgabeblack@google.com            // into the CPU object's inst field.
45611960Sgabeblack@google.com
45711960Sgabeblack@google.com            dcache_access = false; // assume no dcache access
45811960Sgabeblack@google.com            preExecute();
45911960Sgabeblack@google.com            fault = curStaticInst->execute(this, traceData);
46011960Sgabeblack@google.com            postExecute();
46111960Sgabeblack@google.com
46211960Sgabeblack@google.com            if (simulate_stalls) {
46311960Sgabeblack@google.com                Tick icache_stall = icache_latency - cycles(1);
46411960Sgabeblack@google.com                Tick dcache_stall =
46511960Sgabeblack@google.com                    dcache_access ? dcache_latency - cycles(1) : 0;
46611960Sgabeblack@google.com                Tick stall_cycles = (icache_stall + dcache_stall) / cycles(1);
46711960Sgabeblack@google.com                if (cycles(stall_cycles) < (icache_stall + dcache_stall))
46811960Sgabeblack@google.com                    latency += cycles(stall_cycles+1);
46911960Sgabeblack@google.com                else
47011960Sgabeblack@google.com                    latency += cycles(stall_cycles);
47111960Sgabeblack@google.com            }
47211960Sgabeblack@google.com
47311960Sgabeblack@google.com        }
47411960Sgabeblack@google.com
47511960Sgabeblack@google.com        advancePC(fault);
47611960Sgabeblack@google.com    }
47711960Sgabeblack@google.com
47811960Sgabeblack@google.com    if (_status != Idle)
47911960Sgabeblack@google.com        tickEvent.schedule(curTick + latency);
48011960Sgabeblack@google.com}
48111960Sgabeblack@google.com
48211960Sgabeblack@google.com
48311960Sgabeblack@google.com////////////////////////////////////////////////////////////////////////
48411960Sgabeblack@google.com//
48511960Sgabeblack@google.com//  AtomicSimpleCPU Simulation Object
48611960Sgabeblack@google.com//
48711960Sgabeblack@google.comBEGIN_DECLARE_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
48811960Sgabeblack@google.com
48911960Sgabeblack@google.com    Param<Counter> max_insts_any_thread;
49011960Sgabeblack@google.com    Param<Counter> max_insts_all_threads;
49111960Sgabeblack@google.com    Param<Counter> max_loads_any_thread;
49211960Sgabeblack@google.com    Param<Counter> max_loads_all_threads;
49311960Sgabeblack@google.com    Param<Tick> progress_interval;
49411960Sgabeblack@google.com    SimObjectParam<MemObject *> mem;
49511960Sgabeblack@google.com    SimObjectParam<System *> system;
49611960Sgabeblack@google.com    Param<int> cpu_id;
49711960Sgabeblack@google.com
49811960Sgabeblack@google.com#if FULL_SYSTEM
49911960Sgabeblack@google.com    SimObjectParam<AlphaITB *> itb;
50011960Sgabeblack@google.com    SimObjectParam<AlphaDTB *> dtb;
50111960Sgabeblack@google.com    Param<Tick> profile;
50211960Sgabeblack@google.com#else
50311960Sgabeblack@google.com    SimObjectParam<Process *> workload;
50411960Sgabeblack@google.com#endif // FULL_SYSTEM
50511960Sgabeblack@google.com
50611960Sgabeblack@google.com    Param<int> clock;
50711960Sgabeblack@google.com
50811960Sgabeblack@google.com    Param<bool> defer_registration;
50911960Sgabeblack@google.com    Param<int> width;
51011960Sgabeblack@google.com    Param<bool> function_trace;
51111960Sgabeblack@google.com    Param<Tick> function_trace_start;
51211960Sgabeblack@google.com    Param<bool> simulate_stalls;
51311960Sgabeblack@google.com
51411960Sgabeblack@google.comEND_DECLARE_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
51511960Sgabeblack@google.com
51611960Sgabeblack@google.comBEGIN_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
51711960Sgabeblack@google.com
51811960Sgabeblack@google.com    INIT_PARAM(max_insts_any_thread,
51911960Sgabeblack@google.com               "terminate when any thread reaches this inst count"),
52011960Sgabeblack@google.com    INIT_PARAM(max_insts_all_threads,
52111960Sgabeblack@google.com               "terminate when all threads have reached this inst count"),
52211960Sgabeblack@google.com    INIT_PARAM(max_loads_any_thread,
52311960Sgabeblack@google.com               "terminate when any thread reaches this load count"),
52411960Sgabeblack@google.com    INIT_PARAM(max_loads_all_threads,
52511960Sgabeblack@google.com               "terminate when all threads have reached this load count"),
52611960Sgabeblack@google.com    INIT_PARAM(progress_interval, "Progress interval"),
52711960Sgabeblack@google.com    INIT_PARAM(mem, "memory"),
52811960Sgabeblack@google.com    INIT_PARAM(system, "system object"),
52911960Sgabeblack@google.com    INIT_PARAM(cpu_id, "processor ID"),
53011960Sgabeblack@google.com
53111960Sgabeblack@google.com#if FULL_SYSTEM
53211960Sgabeblack@google.com    INIT_PARAM(itb, "Instruction TLB"),
53311960Sgabeblack@google.com    INIT_PARAM(dtb, "Data TLB"),
53411960Sgabeblack@google.com    INIT_PARAM(profile, ""),
53511960Sgabeblack@google.com#else
53611960Sgabeblack@google.com    INIT_PARAM(workload, "processes to run"),
53711960Sgabeblack@google.com#endif // FULL_SYSTEM
53811960Sgabeblack@google.com
53911960Sgabeblack@google.com    INIT_PARAM(clock, "clock speed"),
54011960Sgabeblack@google.com    INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
54111960Sgabeblack@google.com    INIT_PARAM(width, "cpu width"),
54211960Sgabeblack@google.com    INIT_PARAM(function_trace, "Enable function trace"),
54311960Sgabeblack@google.com    INIT_PARAM(function_trace_start, "Cycle to start function trace"),
54411960Sgabeblack@google.com    INIT_PARAM(simulate_stalls, "Simulate cache stall cycles")
54511960Sgabeblack@google.com
54611960Sgabeblack@google.comEND_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
54711960Sgabeblack@google.com
54811960Sgabeblack@google.com
54911960Sgabeblack@google.comCREATE_SIM_OBJECT(AtomicSimpleCPU)
55011960Sgabeblack@google.com{
55111960Sgabeblack@google.com    AtomicSimpleCPU::Params *params = new AtomicSimpleCPU::Params();
55211960Sgabeblack@google.com    params->name = getInstanceName();
55311960Sgabeblack@google.com    params->numberOfThreads = 1;
55411960Sgabeblack@google.com    params->max_insts_any_thread = max_insts_any_thread;
55511960Sgabeblack@google.com    params->max_insts_all_threads = max_insts_all_threads;
55611960Sgabeblack@google.com    params->max_loads_any_thread = max_loads_any_thread;
55711960Sgabeblack@google.com    params->max_loads_all_threads = max_loads_all_threads;
55811960Sgabeblack@google.com    params->progress_interval = progress_interval;
55911960Sgabeblack@google.com    params->deferRegistration = defer_registration;
56011960Sgabeblack@google.com    params->clock = clock;
56111960Sgabeblack@google.com    params->functionTrace = function_trace;
56211960Sgabeblack@google.com    params->functionTraceStart = function_trace_start;
56311960Sgabeblack@google.com    params->width = width;
56411960Sgabeblack@google.com    params->simulate_stalls = simulate_stalls;
56511960Sgabeblack@google.com    params->mem = mem;
56611960Sgabeblack@google.com    params->system = system;
56711960Sgabeblack@google.com    params->cpu_id = cpu_id;
56811960Sgabeblack@google.com
56911960Sgabeblack@google.com#if FULL_SYSTEM
57011960Sgabeblack@google.com    params->itb = itb;
57111960Sgabeblack@google.com    params->dtb = dtb;
57211960Sgabeblack@google.com    params->profile = profile;
57311960Sgabeblack@google.com#else
57411960Sgabeblack@google.com    params->process = workload;
57511960Sgabeblack@google.com#endif
57611960Sgabeblack@google.com
57711960Sgabeblack@google.com    AtomicSimpleCPU *cpu = new AtomicSimpleCPU(params);
57811960Sgabeblack@google.com    return cpu;
57911960Sgabeblack@google.com}
58011960Sgabeblack@google.com
58111960Sgabeblack@google.comREGISTER_SIM_OBJECT("AtomicSimpleCPU", AtomicSimpleCPU)
58211960Sgabeblack@google.com
58311960Sgabeblack@google.com