misc,ext: Add gem5/SST integration

Enable a gem5 system to be an SST::Component.

This change includes,
  - SST::gem5Component: responsible for,
      - initializing the Python environment for gem5
      - instantiating gem5 SimObjects
      - connecting SST::SSTResponderSubComponent to
gem5::OutgoingRequestBridge
      - hanlding the gem5 event queue (no thread-synchronization)
      - handling executing gem5 events
  - SST::SSTResponderSubComponent: responsible for,
      - receiving gem5 requests and sending the requests to
memory.
      - sending responses to the corresponding
gem5::OutgoingRequestBridge.
  - SST::SSTResponder: owned by SSTResponderSubComponent, the
actual actor that sends gem5's requests to memory.
  - gem5::OutgoingRequestBridge: receives the requests from
gem5 and sends them to SST. This SimObject allows the initialization
requests to be cached and the receiver could query the
initialization data later on.
  - gem5::SSTResponderInterface: the interface specifying how SST
communicates with gem5.
  - A working example of a gem5/SST setup.

More information is available at ext/sst/README.md.
For installation instructions, please refer to ext/sst/INSTALL.md.

Change-Id: I6b81260ef825415bcfe72b8a078854f4c94de782
Signed-off-by: Hoa Nguyen <hoanguyen@ucdavis.edu>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/50468
Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-by: Bobby R. Bruce <bbruce@ucdavis.edu>
Maintainer: Giacomo Travaglini <giacomo.travaglini@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Hoa Nguyen
2021-09-16 12:48:53 -07:00
parent 39d4cdcd6b
commit 7bc9b0175f
28 changed files with 2077 additions and 1235 deletions

View File

@@ -0,0 +1,163 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import m5
from m5.objects import *
from os import path
# For downloading the disk image
from gem5.resources.resource import Resource
import argparse
def generateMemNode(state, mem_range):
node = FdtNode("memory@%x" % int(mem_range.start))
node.append(FdtPropertyStrings("device_type", ["memory"]))
node.append(FdtPropertyWords("reg",
state.addrCells(mem_range.start) +
state.sizeCells(mem_range.size()) ))
return node
def generateDtb(system):
"""
Autogenerate DTB. Arguments are the folder where the DTB
will be stored, and the name of the DTB file.
"""
state = FdtState(addr_cells=2, size_cells=2, cpu_cells=1)
root = FdtNode('/')
root.append(state.addrCellsProperty())
root.append(state.sizeCellsProperty())
root.appendCompatible(["riscv-virtio"])
for mem_range in system.mem_ranges:
root.append(generateMemNode(state, mem_range))
sections = [*system.cpu, system.platform]
for section in sections:
for node in section.generateDeviceTree(state):
if node.get_name() == root.get_name():
root.merge(node)
else:
root.append(node)
fdt = Fdt()
fdt.add_rootnode(root)
fdt.writeDtsFile(path.join(m5.options.outdir, 'device.dts'))
fdt.writeDtbFile(path.join(m5.options.outdir, 'device.dtb'))
def createHiFivePlatform(system):
# Since the latency from CPU to the bus was set in SST, additional latency
# is undesirable.
system.membus = NoncoherentXBar(
frontend_latency = 0, forward_latency = 0, response_latency = 0,
header_latency = 0, width = 64
)
system.membus.badaddr_responder = BadAddr()
system.membus.default = \
system.membus.badaddr_responder.pio
system.memory_outgoing_bridge = OutgoingRequestBridge()
system.memory_outgoing_bridge.port = system.membus.mem_side_ports
for cpu in system.cpu:
cpu.createThreads()
cpu.icache_port = system.membus.cpu_side_ports
cpu.dcache_port = system.membus.cpu_side_ports
cpu.mmu.connectWalkerPorts(
system.membus.cpu_side_ports, system.membus.cpu_side_ports)
system.platform = HiFive()
system.platform.rtc = RiscvRTC(frequency=Frequency("100MHz"))
system.platform.clint.int_pin = system.platform.rtc.int_pin
system.pma_checker = PMAChecker(
uncacheable=[
*system.platform._on_chip_ranges(),
*system.platform._off_chip_ranges(),
]
)
system.iobus = IOXBar()
system.bridge = Bridge(delay='50ns')
system.bridge.mem_side_port = system.iobus.cpu_side_ports
system.bridge.cpu_side_port = system.membus.mem_side_ports
system.bridge.ranges = system.platform._off_chip_ranges()
system.platform.setNumCores(1)
system.platform.attachOnChipIO(system.membus)
system.platform.attachOffChipIO(system.iobus)
system.platform.attachPlic()
parser = argparse.ArgumentParser()
parser.add_argument('--cpu-clock-rate', type=str,
help='CPU clock rate, e.g. 3GHz')
parser.add_argument('--memory-size', type=str, help='Memory size, e.g. 4GiB')
args = parser.parse_args()
cpu_clock_rate = args.cpu_clock_rate
memory_size = args.memory_size
# Try downloading the Resource
bbl_resource = Resource("riscv-boot-exit-nodisk")
bbl_path = bbl_resource.get_local_path()
system = System()
system.clk_domain = SrcClockDomain(
clock=cpu_clock_rate, voltage_domain=VoltageDomain()
)
system.mem_ranges = [AddrRange(start=0x80000000, size=memory_size)]
system.cpu = [TimingSimpleCPU(cpu_id=i) for i in range(1)]
system.mem_mode = 'timing'
createHiFivePlatform(system)
system.system_outgoing_bridge = OutgoingRequestBridge()
system.system_port = system.system_outgoing_bridge.port
generateDtb(system)
system.workload = RiscvLinux()
system.workload.addr_check = False
system.workload.object_file = bbl_path
system.workload.dtb_filename = path.join(m5.options.outdir, 'device.dtb')
system.workload.dtb_addr = 0x87e00000
kernel_cmd = [
# specifying Linux kernel boot options
"console=ttyS0"
]
system.workload.command_line = " ".join(kernel_cmd)
for cpu in system.cpu:
cpu.createInterruptController()
root = Root(full_system = True, system = system)

View File

@@ -1,235 +0,0 @@
// Copyright (c) 2015 ARM Limited
// All rights reserved.
//
// The license below extends only to copyright in the software and shall
// not be construed as granting a license to any other intellectual
// property including but not limited to intellectual property relating
// to a hardware implementation of the functionality of the software
// licensed hereunder. You may use the software subject to the license
// terms below provided that you ensure that this notice is replicated
// unmodified and in its entirety in all distributions of the software,
// modified or unmodified, in source code or in binary form.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Copyright 2009-2014 Sandia Coporation. Under the terms
// of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S.
// Government retains certain rights in this software.
//
// Copyright (c) 2009-2014, Sandia Corporation
// All rights reserved.
//
// For license information, see the LICENSE file in the current directory.
#include "gem5.hh"
#ifdef fatal // gem5 sets this
#undef fatal
#endif
#include <mem/packet.hh>
#include <elements/memHierarchy/memNIC.h>
using namespace SST;
using namespace SST::gem5;
using namespace SST::MemHierarchy;
ExtMaster::ExtMaster(gem5Component *g, Output &o, ::gem5::ExternalMaster& p,
std::string &n) :
::gem5::ExternalMaster::Port(n, p), out(o), port(p),
simPhase(CONSTRUCTION), gem5(g), name(n)
{
Params _p; // will be ignored
nic = dynamic_cast<MemNIC*>(gem5->loadModuleWithComponent("memHierarchy.memNIC", g, _p));
MemNIC::ComponentInfo ci;
ci.num_vcs = 1;
ci.link_port = "network";
ci.link_bandwidth = "16GB/s";
ci.link_inbuf_size = "1KB";
ci.link_outbuf_size = "1KB";
ci.network_addr = 0; // hard coded at the moment
ci.type = MemNIC::TypeDirectoryCtrl;
nic->moduleInit(ci, new Event::Handler<ExtMaster>
(this, &ExtMaster::handleEvent));
}
void
ExtMaster::init(unsigned phase)
{
simPhase = INIT;
if (phase == 0) {
assert(nic);
for (auto range : getAddrRanges()) {
MemNIC::ComponentTypeInfo ti;
ti.rangeStart = range.start();
ti.rangeEnd = range.end();
ti.interleaveSize = 0;
ti.interleaveStep = 0;
nic->addTypeInfo(ti);
ranges.insert(range);
}
}
nic->init(phase);
}
void
ExtMaster::setup(void)
{
nic->setup();
simPhase = RUN;
}
void
ExtMaster::finish(void)
{
nic->finish();
}
void
ExtMaster::clock(void)
{
nic->clock();
}
void
ExtMaster::handleEvent(SST::Event* event)
{
if (simPhase == CONSTRUCTION) {
out.fatal(CALL_INFO, 1, "received Event during Construction phase\n");
}
MemEvent *ev = dynamic_cast<MemEvent*>(event);
if (!ev) {
out.fatal(CALL_INFO, 1, "Can't handle non-MemEvent Event's\n");
}
Command cmdI = ev->getCmd(); // command in - SST
::gem5::MemCmd::Command cmdO; // command out - gem5
bool data = false;
switch (cmdI) {
case GetS: cmdO = ::gem5::MemCmd::ReadReq; break;
case GetX: cmdO = ::gem5::MemCmd::WriteReq; data = true; break;
case GetSEx:
case PutS:
case PutM:
case PutE:
case PutX:
case PutXE:
case Inv:
case FetchInv:
case FetchInvX:
case NACK:
case NULLCMD:
case GetSResp:
case GetXResp:
case FetchResp:
case FetchXResp:
out.fatal(CALL_INFO, 1, "Don't know how to convert "
"SST command %s to gem5\n",
CommandString[cmdI]);
}
::gem5::Request::FlagsType flags = 0;
if (ev->queryFlag(MemEvent::F_LOCKED))
flags |= ::gem5::Request::LOCKED_RMW;
if (ev->queryFlag(MemEvent::F_NONCACHEABLE))
flags |= ::gem5::Request::UNCACHEABLE;
if (ev->isLoadLink()) {
assert(cmdI == GetS);
cmdO = ::gem5::MemCmd::LoadLockedReq;
} else if (ev->isStoreConditional()) {
assert(cmdI == GetX);
cmdO = ::gem5::MemCmd::StoreCondReq;
}
auto req = std::make_shared<::gem5::Request>(
ev->getAddr(), ev->getSize(), flags, 0);
req->setContext(ev->getGroupId());
auto pkt = new ::gem5::Packet(req, cmdO);
pkt->allocate();
if (data) {
pkt->setData(ev->getPayload().data());
}
pkt->pushSenderState(new SenderState(ev));
if (blocked() || !sendTimingReq(pkt))
sendQ.push_back(pkt);
}
bool
ExtMaster::recvTimingResp(::gem5::PacketPtr pkt) {
if (simPhase == INIT) {
out.fatal(CALL_INFO, 1, "not prepared to handle INIT-phase traffic\n");
}
// get original SST packet from gem5 SenderState
auto senderState = dynamic_cast<SenderState*>(pkt->popSenderState());
if (!senderState)
out.fatal(CALL_INFO, 1, "gem5 senderState corrupt\n");
// make (new) response packet, discard (old) original request
MemEvent* ev = senderState->event;
delete senderState;
MemEvent* resp = ev->makeResponse();
delete ev;
// copy the payload and then destroy gem5 packet
resp->setPayload(pkt->getSize(), pkt->getPtr<uint8_t>());
delete pkt;
nic->send(resp);
return true;
}
void
ExtMaster::recvReqRetry() {
while (blocked() && sendTimingReq(sendQ.front())) {
sendQ.pop_front();
}
}
void
ExtMaster::recvRangeChange() {
for (auto range : getAddrRanges()) {
if (ranges.find(range) == ranges.end()) { // i.e. if not found,
MemNIC::ComponentTypeInfo ti; // indicating a new range.
ti.rangeStart = range.start();
ti.rangeEnd = range.end();
ti.interleaveSize = 0;
ti.interleaveStep = 0;
nic->addTypeInfo(ti);
ranges.insert(range);
}
}
}

View File

@@ -1,120 +0,0 @@
// Copyright (c) 2015 ARM Limited
// All rights reserved.
//
// The license below extends only to copyright in the software and shall
// not be construed as granting a license to any other intellectual
// property including but not limited to intellectual property relating
// to a hardware implementation of the functionality of the software
// licensed hereunder. You may use the software subject to the license
// terms below provided that you ensure that this notice is replicated
// unmodified and in its entirety in all distributions of the software,
// modified or unmodified, in source code or in binary form.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Copyright 2009-2014 Sandia Coporation. Under the terms
// of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S.
// Government retains certain rights in this software.
//
// Copyright (c) 2009-2014, Sandia Corporation
// All rights reserved.
//
// For license information, see the LICENSE file in the current directory.
#ifndef EXT_SST_EXTMASTER_HH
#define EXT_SST_EXTMASTER_HH
#include <list>
#include <set>
#include <core/component.h>
#include <elements/memHierarchy/memEvent.h>
#include <base/addr_range.hh>
#include <mem/external_master.hh>
#include <mem/packet.hh>
#include <mem/request.hh>
#include <sim/sim_object.hh>
namespace SST {
using MemHierarchy::MemEvent;
class Link;
class Event;
namespace MemHierarchy {
class MemNIC;
}
namespace gem5 {
class gem5Component;
class ExtMaster : public ::gem5::ExternalMaster::Port
{
enum Phase { CONSTRUCTION, INIT, RUN };
Output& out;
const ::gem5::ExternalMaster& port;
Phase simPhase;
gem5Component *const gem5;
const std::string name;
std::list<::gem5::PacketPtr> sendQ;
bool blocked() { return !sendQ.empty(); }
MemHierarchy::MemNIC * nic;
struct SenderState : public ::gem5::Packet::SenderState
{
MemEvent *event;
SenderState(MemEvent* e) : event(e) {}
};
std::set<::gem5::AddrRange> ranges;
public:
bool recvTimingResp(::gem5::PacketPtr);
void recvReqRetry();
ExtMaster(gem5Component*, Output&, ::gem5::ExternalMaster&, std::string&);
void init(unsigned phase);
void setup();
void finish();
void clock();
// receive Requests from SST bound for a gem5 slave;
// this module is "external" from gem5's perspective, thus ExternalMaster.
void handleEvent(SST::Event*);
protected:
virtual void recvRangeChange();
};
} // namespace gem5
} // namespace SST
#endif

View File

@@ -1,204 +0,0 @@
// Copyright (c) 2015 ARM Limited
// All rights reserved.
//
// The license below extends only to copyright in the software and shall
// not be construed as granting a license to any other intellectual
// property including but not limited to intellectual property relating
// to a hardware implementation of the functionality of the software
// licensed hereunder. You may use the software subject to the license
// terms below provided that you ensure that this notice is replicated
// unmodified and in its entirety in all distributions of the software,
// modified or unmodified, in source code or in binary form.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Copyright 2009-2014 Sandia Coporation. Under the terms
// of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S.
// Government retains certain rights in this software.
//
// Copyright (c) 2009-2014, Sandia Corporation
// All rights reserved.
//
// For license information, see the LICENSE file in the current directory.
#include "gem5.hh"
#ifdef fatal // gem5 sets this
#undef fatal
#endif
#include <base/types.hh>
using namespace SST;
using namespace SST::gem5;
using namespace SST::MemHierarchy;
ExtSlave::ExtSlave(gem5Component *g5c, Output &out,
::gem5::ExternalSlave& port, std::string &name) :
::gem5::ExternalSlave::Port(name, port),
comp(g5c), out(out), simPhase(CONSTRUCTION), initPackets(NULL),
link(comp->configureLink(name, new Event::Handler<ExtSlave>(this,
&ExtSlave::handleEvent)))
{
if (!link) {
out.fatal(CALL_INFO, 1, "Failed to configure link %s\n", name.c_str());
}
}
void
ExtSlave::init(unsigned phase)
{
simPhase = INIT;
if (initPackets) {
while (!initPackets->empty()) {
link->sendInitData(initPackets->front());
initPackets->pop_front();
}
delete initPackets;
initPackets = NULL;
}
}
void
ExtSlave::recvFunctional(::gem5::PacketPtr pkt)
{
if (simPhase == CONSTRUCTION) {
if (initPackets == NULL) {
initPackets = new std::list<MemEvent*>;
}
::gem5::MemCmd::Command pktCmd =
(::gem5::MemCmd::Command)pkt->cmd.toInt();
assert(pktCmd == ::gem5::MemCmd::WriteReq);
::gem5::Addr a = pkt->getAddr();
MemEvent* ev = new MemEvent(comp, a, a, GetX);
ev->setPayload(pkt->getSize(), pkt->getPtr<uint8_t>());
initPackets->push_back(ev);
} else {
panic("Functional accesses not allowed after construction phase");
}
}
bool
ExtSlave::recvTimingReq(::gem5::PacketPtr pkt)
{
Command cmd;
switch ((::gem5::MemCmd::Command)pkt->cmd.toInt()) {
case ::gem5::MemCmd::HardPFReq:
case ::gem5::MemCmd::SoftPFReq:
case ::gem5::MemCmd::LoadLockedReq:
case ::gem5::MemCmd::ReadExReq:
case ::gem5::MemCmd::ReadReq: cmd = GetS; break;
case ::gem5::MemCmd::StoreCondReq:
case ::gem5::MemCmd::WriteReq: cmd = GetX; break;
default:
out.fatal(CALL_INFO, 1, "Don't know how to convert gem5 packet "
"command %s to SST\n", pkt->cmd.toString().c_str());
}
auto ev = new MemEvent(comp, pkt->getAddr(), pkt->getAddr(), cmd);
ev->setPayload(pkt->getSize(), pkt->getPtr<uint8_t>());
if ((::gem5::MemCmd::Command)pkt->cmd.toInt() ==
::gem5::MemCmd::LoadLockedReq) {
ev->setLoadLink();
} else if ((::gem5::MemCmd::Command)pkt->cmd.toInt() ==
::gem5::MemCmd::StoreCondReq) {
ev->setStoreConditional();
}
if (pkt->req->isLockedRMW()) ev->setFlag(MemEvent::F_LOCKED);
if (pkt->req->isUncacheable()) ev->setFlag(MemEvent::F_NONCACHEABLE);
if (pkt->req->hasContextId()) ev->setGroupId(pkt->req->contextId());
// Prefetches not working with SST; it maybe be dropping them, treating them
// as not deserving of responses, or something else -- not sure yet.
// ev->setPrefetchFlag(pkt->req->isPrefetch());
if (simPhase == INIT) {
link->sendInitData(ev);
delete pkt;
} else {
if (pkt->needsResponse()) {
PacketMap[ev->getID()] = pkt;
}
link->send(ev);
}
return true;
}
void
ExtSlave::handleEvent(Event* ev)
{
MemEvent* event = dynamic_cast<MemEvent*>(ev);
if (!event) {
out.fatal(CALL_INFO, 1, "ExtSlave handleEvent received non-MemEvent\n");
delete ev;
return;
}
Event::id_type id = event->getID();
PacketMap_t::iterator mi = PacketMap.find(id);
if (mi != PacketMap.end()) { // replying to prior request
::gem5::PacketPtr pkt = mi->second;
PacketMap.erase(mi);
pkt->makeResponse(); // Convert to a response packet
pkt->setData(event->getPayload().data());
// Resolve the success of Store Conditionals
if (pkt->isLLSC() && pkt->isWrite()) {
pkt->req->setExtraData(event->isAtomic());
}
// Clear out bus delay notifications
pkt->headerDelay = pkt->payloadDelay = 0;
if (blocked() || !sendTimingResp(pkt)) {
respQ.push_back(pkt);
}
} else { // we can handle unexpected invalidates, but nothing else.
Command cmd = event->getCmd();
assert(cmd == Inv);
// make Req/Pkt for Snoop/no response needed
// presently no consideration for masterId, packet type, flags...
::gem5::RequestPtr req = std::make_shared<::gem5::Request>(
event->getAddr(), event->getSize(), 0, 0);
auto pkt = new ::gem5::Packet(req, ::gem5::MemCmd::InvalidateReq);
// Clear out bus delay notifications
pkt->headerDelay = pkt->payloadDelay = 0;
sendTimingSnoopReq(pkt);
}
delete event;
}
void
ExtSlave::recvRespRetry()
{
while (blocked() && sendTimingResp(respQ.front())) {
respQ.pop_front();
}
}

View File

@@ -1,121 +0,0 @@
// Copyright (c) 2015 ARM Limited
// All rights reserved.
//
// The license below extends only to copyright in the software and shall
// not be construed as granting a license to any other intellectual
// property including but not limited to intellectual property relating
// to a hardware implementation of the functionality of the software
// licensed hereunder. You may use the software subject to the license
// terms below provided that you ensure that this notice is replicated
// unmodified and in its entirety in all distributions of the software,
// modified or unmodified, in source code or in binary form.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Copyright 2009-2014 Sandia Coporation. Under the terms
// of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S.
// Government retains certain rights in this software.
//
// Copyright (c) 2009-2014, Sandia Corporation
// All rights reserved.
//
// For license information, see the LICENSE file in the current directory.
#ifndef EXT_SST_EXTSLAVE_HH
#define EXT_SST_EXTSLAVE_HH
#include <list>
#include <string>
#include <core/interfaces/simpleMem.h>
#include <base/logging.hh>
#include <mem/packet.hh>
#include <mem/request.hh>
#include <mem/external_slave.hh>
#include <sim/sim_object.hh>
namespace SST {
class Link;
class Event;
class MemEvent;
namespace gem5 {
class gem5Component;
class ExtSlave : public ::gem5::ExternalSlave::Port
{
public:
const std::string name;
bool
recvTimingSnoopResp(::gem5::PacketPtr packet)
{
fatal("recvTimingSnoopResp unimplemented");
return false;
}
bool recvTimingReq(::gem5::PacketPtr packet);
void recvFunctional(::gem5::PacketPtr packet);
void recvRespRetry();
::gem5::Tick
recvAtomic(::gem5::PacketPtr packet)
{
fatal("recvAtomic unimplemented");
}
enum Phase { CONSTRUCTION, INIT, RUN };
gem5Component *comp;
Output &out;
Phase simPhase;
std::list<MemEvent*>* initPackets;
Link* link;
std::list<::gem5::PacketPtr> respQ;
bool blocked() { return !respQ.empty(); }
typedef std::map<Event::id_type, ::gem5::Packet*> PacketMap_t;
PacketMap_t PacketMap; // SST Event id -> gem5 Packet*
public:
ExtSlave(gem5Component*, Output&, ::gem5::ExternalSlave&, std::string&);
void init(unsigned phase);
void
setup()
{
simPhase = RUN;
}
void handleEvent(Event*);
};
}
}
#endif

94
ext/sst/INSTALL.md Normal file
View File

@@ -0,0 +1,94 @@
# Installing SST
The links to download SST source code are available here
[http://sst-simulator.org/SSTPages/SSTMainDownloads/].
This guide is using the most recent SST version (11.0.0) as of September 2021.
The following guide assumes `$SST_CORE_HOME` as the location where SST will be
installed.
## SST-Core
### Downloading the SST-Core Source Code
```sh
wget https://github.com/sstsimulator/sst-core/releases/download/v11.0.0_Final/sstcore-11.0.0.tar.gz
tar xf sstcore-11.0.0.tar.gz
```
### Installing SST-Core
```sh
cd sstcore-11.0.0
./configure --prefix=$SST_CORE_HOME --with-python=/usr/bin/python3-config \
--disable-mpi # optional, used when MPI is not available.
make all -j$(nproc)
make install
```
Update `PATH`,
```sh
export PATH=$SST_CORE_HOME/bin:$PATH
```
## SST-Elements
### Downloading the SST-Elements Source Code
```sh
wget https://github.com/sstsimulator/sst-elements/releases/download/v11.0.0_Final/sstelements-11.0.0.tar.gz
tar xf sstelements-11.0.0.tar.gz
```
### Installing SST-Elements
```shs
cd sst-elements-library-11.0.0
./configure --prefix=$SST_CORE_HOME --with-python=/usr/bin/python3-config \
--with-sst-core=$SST_CORE_HOME
make all -j$(nproc)
make install
```
Adding `PKG_CONFIG_PATH` to `.bashrc` (so pkg-config can find SST .pc file),
```sh
echo "export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$SST_CORE_HOME/lib/pkgconfig/" >> ~/.bashrc
```
### Building gem5 library
At the root of gem5 folder,
```sh
scons build/RISCV/libgem5_opt.so -j $(nproc) --without-tcmalloc
```
### Compiling the SST integration
At the root of gem5 folder,
```sh
cd ext/sst
make
```
### Running an example simulation
Downloading the built bootloader containing a Linux Kernel and a workload,
```sh
wget http://dist.gem5.org/dist/develop/misc/riscv/bbl-busybox-boot-exit
```
Running the simulation
```sh
sst --add-lib-path=./ sst/example.py
```
`bbl-busybox-boot-exit` contains an m5 binary, and `m5 exit` will be called
upon the booting process reaching the early userspace.
More information about building a bootloader containing a Linux Kernel and a
customized workload is available at
[https://gem5.googlesource.com/public/gem5-resources/+/refs/heads/develop/src/riscv-boot-exit-nodisk/].

View File

@@ -1,5 +1,31 @@
** This license only applies to the source files in this directory.
Copyright (c) 2021 The Regents of the University of California
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met: redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer;
redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution;
neither the name of the copyright holders nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Copyright (c) 2015 ARM Limited
All rights reserved.

View File

@@ -1,9 +1,10 @@
# These two variables are designed to be modifiable.
SST_VERSION=SST-trunk
SST_VERSION=SST-11.1.0 # Name of the .pc file in lib/pkgconfig where SST is installed
GEM5_LIB=gem5_opt
ARCH=RISCV
OFLAG=3
LDFLAGS=-shared -fno-common ${shell pkg-config ${SST_VERSION} --libs} -L../../build/ARM
CXXFLAGS=-std=c++0x -g -O2 -fPIC ${shell pkg-config ${SST_VERSION} --cflags} ${shell python-config --includes} -I../../build/ARM
LDFLAGS=-shared -fno-common ${shell pkg-config ${SST_VERSION} --libs} -L../../build/${ARCH}/ -Wl,-rpath ../../build/${ARCH}
CXXFLAGS=-std=c++17 -g -O${OFLAG} -fPIC ${shell pkg-config ${SST_VERSION} --cflags} ${shell python3-config --includes} -I../../build/${ARCH}/ -I../../ext/pybind11/include/ -I../../build/softfloat/
CPPFLAGS+=-MMD -MP
SRC=$(wildcard *.cc)

View File

@@ -1,65 +0,0 @@
This directory contains a connector that allows gem5 to be used as a
component in SST (Structural Simulation Toolkit, sst-simulator.org). More
specifically, it creates a .so that wraps the libgem5_*.so library. At a
high level, this allows memory traffic to pass between the two simulators.
SST Links are roughly analogous to gem5 Ports, although Links do not have
a notion of master and slave. This distinction is important to gem5, so
when connecting a gem5 CPU to an SST cache, an ExternalSlave must be used,
and similarly when connecting the memory side of SST cache to a gem5 port
(for memory <-> I/O), an ExternalMaster must be used.
The connector handles the administrative aspects of gem5
(initialization, simulation, shutdown) as well as translating
SST's MemEvents into gem5 Packets and vice-versa.
Step-by-step instructions:
0. install SST and its dependencies
Note: the Makefile assumes you installed from an SVN checkout, not a release.
If you install a release, modify SST_VERSION at the top of the Makefile.
0b. set/append to the PKG_CONFIG_PATH variable the path where SST installed
its pkgconfig, if not in a system-wide location.
Then from gem5 root:
1. build gem5 library:
% scons build/ARM/libgem5_opt.so
Note: if you would rather use a fast, debug, etc. variant instead,
modify GEM5_LIB at the top of the Makefile.
2. build gem5 SST component:
% make -C ext/sst
3. run SST like so:
% sst --add-lib-path <path to ./ext/sst> <config script, e.g. ext/sst/*.py>
===========
Note: if you want to use an arch other than ARM (not tested/supported),
tweak the Makefile to get includes from that build directory instead.
===========
This directory provides:
1. an SST "Component" for gem5;
2. a class that implements gem5's "ExternalMaster" interface to connect with
SST "Link"s exchanging "memEvents"
(sst/elements/memHierarchy stuff - caches, memories, etc.)
This lets gem5 receive packets from SST, as in
an SST LL$ (a master external to gem5) <-> I/O devices.
3. a class that implements gem5's "ExternalSlave" interface to connect with
SST "Link"s exchanging "memEvents" once again with the packet flow reversed:
gem5 CPU <-> SST L1 cache (a slave external to gem5)
4. an example configuration that uses both as follows:
gem5 CPUs
^
| [ExternalSlave]
v
SST cache hierarchy <-> SST memory
^
| [ExternalMaster]
v
gem5 I/O devices (terminal, disk, etc.)

85
ext/sst/README.md Normal file
View File

@@ -0,0 +1,85 @@
# Using gem5 in an SST simulation
## Overview
This directory contains the library needed to use gem5 TimingSimpleCPU model in
an SST-driven simulation.
When compiled, the gem5 library for SST `libgem5.so` will be generated,
containing the `libgem5_*.so` as well as the gem5 Component and the
SST Responder SubComponent.
```text
On/Off-chip devs TimingSimpleCPU
^ ^ ^
| | |
v v v
==================================== [gem5::NonCoherentXBar]
^ [OutgoingRequestBridge]
gem5_system_port |
[OutgoingRequestBridge] ^ |
| |
[SSTResponder] v v [SSTResponder]
gem5 Component {SSTResponderSubComponent, SSTResponderSubComponent}
^ ^
| |
v v
================================== [SST Bus]
^
|
v
SST cache <----> SST memory
```
## Components and SubComponents
- gem5 Component has the following responsibilities,
- initializing the gem5 Python environment
- instantiating/setting-up the gem5 SimObjects as specified by the gem5
configuration
- connect every SSTResponderSubComponent to the corresponding
OutgoingRequestBridge
- handling a gem5 event queue (with all thread-synchronization barriers
removed)
- handling executions of gem5 events when it has clockTick yielded by SST
**Note:** there should only be one gem5 Component per process.
- SSTResponderSubComponent has the responsibity of receiving requests from
gem5, translating requests to an SST Request and sending it to SSTResponder.
Upon receiving a response from the memory interface, SSTResponderSubComponent
will translate the response to a gem5 Packet and send it to the its
OutgoingRequestBridge.
- SSTResponder is owned by SSTResponderSubComponent. The responder will receive
the request from the SubComponent and send it to the SST memory hierarchy.
## Installation
See `INSTALL.md`.
## Running an example simulation
Downloading the built bootloader containing a Linux Kernel and a workload,
```sh
wget http://dist.gem5.org/dist/develop/misc/riscv/bbl-busybox-boot-exit
```
Running the simulation
```sh
sst sst/example.py
```
`bbl-busybox-boot-exit` contains an m5 binary, and `m5 exit` will be called
upon the booting process reaching the early userspace.
More information about building a bootloader containing a Linux Kernel and a
customized workload is available at
[https://gem5.googlesource.com/public/gem5-resources/+/refs/heads/develop/src/riscv-boot-exit-nodisk/].
## Notes
- SwapReq from gem5 requires reading from memory and writing to memory.
We handle the request in SST in a way that, when SST gets the response
from memory, SST will send that response to gem5, while SST will send
a write request with modified data to memory.

View File

@@ -1,15 +1,6 @@
// Copyright (c) 2015-2016 ARM Limited
// Copyright (c) 2021 The Regents of the University of California
// All rights reserved.
//
// The license below extends only to copyright in the software and shall
// not be construed as granting a license to any other intellectual
// property including but not limited to intellectual property relating
// to a hardware implementation of the functionality of the software
// licensed hereunder. You may use the software subject to the license
// terms below provided that you ensure that this notice is replicated
// unmodified and in its entirety in all distributions of the software,
// modified or unmodified, in source code or in binary form.
//
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
@@ -20,7 +11,42 @@
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Copyright (c) 2015-2016 ARM Limited
// All rights reserved.
//
// The license below extends only to copyright in the software and shall
// not be construed as granting a license to any other intellectual
// property including but not limited to intellectual property relating
// to a hardware implementation of the functionality of the software
// licensed hereunder. You may use the software subject to the license
// terms below provided that you ensure that this notice is replicated
// unmodified and in its entirety in all distributions of the software,
// modified or unmodified, in source code or in binary form.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -42,24 +68,49 @@
//
// For license information, see the LICENSE file in the current directory.
#include <core/sst_config.h>
#include <sst/core/sst_config.h>
#include <sst/core/componentInfo.h>
#include <sst/core/interfaces/simpleMem.h>
#include <sst/elements/memHierarchy/memEvent.h>
#include <sst/elements/memHierarchy/memTypes.h>
#include <sst/elements/memHierarchy/util.h>
#include <Python.h> // Before serialization to prevent spurious warnings
#include "gem5.hh"
#include "util.hh"
// System headers
#include <boost/tokenizer.hpp>
#include <algorithm>
#include <fstream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>
// gem5 Headers
#include <sim/cur_tick.hh>
#include <sim/core.hh>
#include <sim/init.hh>
#include <sim/init_signals.hh>
#include <sim/root.hh>
#include <sim/system.hh>
#include <sim/sim_events.hh>
#include <sim/sim_object.hh>
#include <base/logging.hh>
#include <base/debug.hh>
#include <base/pollevent.hh>
#include <base/types.hh>
#include <sim/async.hh>
#include <sim/eventq.hh>
#include <sim/sim_exit.hh>
#include <sim/stat_control.hh>
#include <sst/outgoing_request_bridge.hh>
#include <cassert>
#ifdef fatal // gem5 sets this
#undef fatal
#endif
@@ -67,205 +118,352 @@
// More SST Headers
#include <core/timeConverter.h>
using namespace SST;
using namespace SST::gem5;
gem5Component::gem5Component(ComponentId_t id, Params &params) :
SST::Component(id)
gem5Component::gem5Component(SST::ComponentId_t id, SST::Params& params):
SST::Component(id), threadInitialized(false)
{
dbg.init("@t:gem5:@p():@l " + getName() + ": ", 0, 0,
(Output::output_location_t)params.find<int>("comp_debug", 0));
info.init("gem5:" + getName() + ": ", 0, 0, Output::STDOUT);
output.init("gem5Component-" + getName() + "->", 1, 0,
SST::Output::STDOUT);
TimeConverter *clock = registerClock(
params.find<std::string>("frequency", "1GHz"),
new Clock::Handler<gem5Component>(this, &gem5Component::clockTick));
std::string cpu_frequency = params.find<std::string>("frequency", "");
if (cpu_frequency.empty()) {
output.fatal(
CALL_INFO, -1, "The frequency of the CPU must be specified.\n"
);
}
// This sets how many gem5 cycles we'll need to simulate per clock tick
sim_cycles = clock->getFactor();
// Disable gem5's inform() messages.
want_info = false;
// Register a handler to be called on a set frequency.
timeConverter = registerClock(
cpu_frequency,
new SST::Clock::Handler<gem5Component>(this, &gem5Component::clockTick)
);
// "cmd" -> gem5's Python
std::string cmd = params.find<std::string>("cmd", "");
if (cmd.empty()) {
dbg.fatal(CALL_INFO, -1, "Component %s must have a 'cmd' parameter.\n",
getName().c_str());
output.fatal(
CALL_INFO, -1, "Component %s must have a 'cmd' parameter.\n",
getName().c_str()
);
}
std::vector<char*> args;
args.push_back(const_cast<char*>("sst.x")); // TODO: Compute this somehow?
// Telling SST the command line call to gem5
args.push_back(const_cast<char*>("sst.x"));
splitCommandArgs(cmd, args);
args.push_back(const_cast<char*>("--initialize-only"));
dbg.output(CALL_INFO, "Command string: [sst.x %s --initialize-only]\n",
cmd.c_str());
output.output(CALL_INFO, "Command string: [sst.x %s]\n", cmd.c_str());
for (size_t i = 0; i < args.size(); ++i) {
dbg.output(CALL_INFO, " Arg [%02zu] = %s\n", i, args[i]);
output.output(CALL_INFO, " Arg [%02zu] = %s\n", i, args[i]);
}
std::vector<char*> flags;
std::string gem5DbgFlags = params.find<std::string>("gem5DebugFlags", "");
splitCommandArgs(gem5DbgFlags, flags);
for (auto flag : flags) {
dbg.output(CALL_INFO, " Setting Debug Flag [%s]\n", flag);
::gem5::setDebugFlag(flag);
// Parsing and setting gem5 debug flags
std::string gem5_debug_flags = params.find<std::string>("debug_flags", "");
for (auto const debug_flag: tokenizeString(gem5_debug_flags, {' ', ','})) {
output.output(CALL_INFO, "Debug flag += %s\n", debug_flag.c_str());
gem5::setDebugFlag(debug_flag.c_str());
}
// These are idempotent
::gem5::ExternalMaster::registerHandler("sst", this);
::gem5::ExternalSlave::registerHandler("sst", this);
// Initialize gem5's special signal handling.
::gem5::initSignals();
initPython(args.size(), &args[0]);
// tell the simulator not to end without us
registerAsPrimaryComponent();
primaryComponentDoNotEndSim();
clocks_processed = 0;
systemPort = \
loadUserSubComponent<SSTResponderSubComponent>("system_port",0);
cachePort = \
loadUserSubComponent<SSTResponderSubComponent>("cache_port", 0);
systemPort->setTimeConverter(timeConverter);
systemPort->setOutputStream(&(output));
cachePort->setTimeConverter(timeConverter);
cachePort->setOutputStream(&(output));
}
gem5Component::~gem5Component(void)
gem5Component::~gem5Component()
{
Py_Finalize();
}
void
gem5Component::init(unsigned phase)
{
for (auto m : masters) {
m->init(phase);
}
for (auto s : slaves) {
s->init(phase);
output.output(CALL_INFO," init phase: %u\n", phase);
if (phase == 0) {
initPython(args.size(), &args[0]);
const std::vector<std::string> m5_instantiate_commands = {
"m5.instantiate()"
};
execPythonCommands(m5_instantiate_commands);
// calling SimObject.startup()
const std::vector<std::string> simobject_setup_commands = {
"import atexit",
"import _m5",
"root = m5.objects.Root.getInstance()",
"for obj in root.descendants(): obj.startup()",
"atexit.register(m5.stats.dump)",
"atexit.register(_m5.core.doExitCleanup)",
"m5.stats.reset()"
};
execPythonCommands(simobject_setup_commands);
// find the corresponding SimObject for each SSTResponderSubComponent
gem5::Root* gem5_root = gem5::Root::root();
systemPort->findCorrespondingSimObject(gem5_root);
cachePort->findCorrespondingSimObject(gem5_root);
// initialize the gem5 event queue
if (!(threadInitialized)) {
threadInitialized = true;
gem5::simulate_limit_event = new gem5::GlobalSimLoopExitEvent(
gem5::mainEventQueue[0]->getCurTick(),
"simulate() limit reached",
0
);
}
}
systemPort->init(phase);
cachePort->init(phase);
}
void
gem5Component::setup(void)
gem5Component::setup()
{
// Switch connectors from initData to regular Sends
for (auto m : masters) {
m->setup();
}
for (auto s : slaves) {
s->setup();
}
output.verbose(CALL_INFO, 1, 0, "Component is being setup.\n");
systemPort->setup();
cachePort->setup();
}
void
gem5Component::finish(void)
gem5Component::finish()
{
for (auto m : masters) {
m->finish();
}
info.output("Complete. Clocks Processed: %" PRIu64"\n", clocks_processed);
output.verbose(CALL_INFO, 1, 0, "Component is being finished.\n");
}
bool
gem5Component::clockTick(Cycle_t cycle)
gem5Component::clockTick(SST::Cycle_t currentCycle)
{
dbg.output(CALL_INFO, "Cycle %lu\n", cycle);
// what to do in a SST's cycle
gem5::GlobalSimLoopExitEvent *event = simulateGem5(currentCycle);
clocksProcessed++;
// gem5 exits due to reasons other than reaching simulation limit
if (event != gem5::simulate_limit_event) {
output.output("exiting: curTick()=%lu cause=`%s` code=%d\n",
gem5::curTick(), event->getCause().c_str(), event->getCode()
);
// output gem5 stats
const std::vector<std::string> output_stats_commands = {
"m5.stats.dump()"
};
execPythonCommands(output_stats_commands);
for (auto m : masters) {
m->clock();
}
::gem5::GlobalSimLoopExitEvent *event = ::gem5::simulate(sim_cycles);
++clocks_processed;
if (event != simulate_limit_event) {
info.output("exiting: curTick()=%lu cause=`%s` code=%d\n",
::gem5::curTick(), event->getCause().c_str(),
event->getCode());
primaryComponentOKToEndSim();
return true;
}
// returning False means the simulation should go on
return false;
}
#define PyCC(x) (const_cast<char *>(x))
void
gem5Component::splitCommandArgs(std::string &cmd,
std::vector<char *> &args)
gem5::GlobalSimLoopExitEvent*
gem5Component::simulateGem5(uint64_t current_cycle)
{
std::string sep1("\\");
std::string sep2(" ");
std::string sep3("\"\'");
// This function should be similar to simulate() of src/sim/simulate.cc
// with synchronization barriers removed.
boost::escaped_list_separator<char> els(sep1, sep2, sep3);
boost::tokenizer<boost::escaped_list_separator<char>> tok(cmd, els);
inform_once("Entering event queue @ %d. Starting simulation...\n",
gem5::curTick());
for (auto beg : tok) {
args.push_back(strdup(beg.c_str()));
// Tick conversion
// The main logic for synchronize SST Tick and gem5 Tick is here.
// next_end_tick = current_cycle * timeConverter->getFactor()
uint64_t next_end_tick = \
timeConverter->convertToCoreTime(current_cycle);
// Here, if the next event in gem5's queue is not executed within the next
// cycle, there's no need to enter the gem5's sim loop.
if (next_end_tick < gem5::mainEventQueue[0]->getHead()->when())
return gem5::simulate_limit_event;
gem5::simulate_limit_event->reschedule(next_end_tick);
gem5::Event *local_event = doSimLoop(gem5::mainEventQueue[0]);
gem5::BaseGlobalEvent *global_event = local_event->globalEvent();
gem5::GlobalSimLoopExitEvent *global_exit_event =
dynamic_cast<gem5::GlobalSimLoopExitEvent *>(global_event);
return global_exit_event;
}
gem5::Event*
gem5Component::doSimLoop(gem5::EventQueue* eventq)
{
// This function should be similar to doSimLoop() in src/sim/simulate.cc
// with synchronization barriers removed.
gem5::curEventQueue(eventq);
eventq->handleAsyncInsertions();
while (true)
{
// there should always be at least one event (the SimLoopExitEvent
// we just scheduled) in the queue
assert(!eventq->empty());
assert(gem5::curTick() <= eventq->nextTick() &&
"event scheduled in the past");
if (gem5::async_event) {
// Take the event queue lock in case any of the service
// routines want to schedule new events.
if (gem5::async_statdump || gem5::async_statreset) {
gem5::statistics::schedStatEvent(gem5::async_statdump,
gem5::async_statreset);
gem5::async_statdump = false;
gem5::async_statreset = false;
}
if (gem5::async_io) {
gem5::async_io = false;
gem5::pollQueue.service();
}
if (gem5::async_exit) {
gem5::async_exit = false;
gem5::exitSimLoop("user interrupt received");
}
if (gem5::async_exception) {
gem5::async_exception = false;
return NULL;
}
}
gem5::Event *exit_event = eventq->serviceOne();
if (exit_event != NULL) {
return exit_event;
}
}
}
void
gem5Component::initPython(int argc, char *argv[])
int
gem5Component::execPythonCommands(const std::vector<std::string>& commands)
{
const char * m5MainCommands[] = {
"import m5",
"m5.main()",
0 // sentinel is required
};
PyObject *dict = PyModule_GetDict(pythonMain);
PyObject *mainModule,*mainDict;
PyObject *result;
Py_SetProgramName(argv[0]); // optional but recommended
Py_Initialize();
int ret = initM5Python();
if (ret != 0) {
dbg.fatal(CALL_INFO, -1, "Python failed to initialize. Code: %d\n",
ret);
for (auto const command: commands) {
result = PyRun_String(command.c_str(), Py_file_input, dict, dict);
if (!result) {
PyErr_Print();
return 1;
}
Py_DECREF(result);
}
return 0;
}
int
gem5Component::startM5(int argc, char **_argv)
{
// This function should be similar to m5Main() of src/sim/init.cc
#if HAVE_PROTOBUF
// Verify that the version of the protobuf library that we linked
// against is compatible with the version of the headers we
// compiled against.
GOOGLE_PROTOBUF_VERIFY_VERSION;
#endif
#if PY_MAJOR_VERSION >= 3
typedef std::unique_ptr<wchar_t[], decltype(&PyMem_RawFree)> WArgUPtr;
std::vector<WArgUPtr> v_argv;
std::vector<wchar_t *> vp_argv;
v_argv.reserve(argc);
vp_argv.reserve(argc);
for (int i = 0; i < argc; i++) {
v_argv.emplace_back(Py_DecodeLocale(_argv[i], NULL), &PyMem_RawFree);
vp_argv.emplace_back(v_argv.back().get());
}
wchar_t **argv = vp_argv.data();
#else
char **argv = _argv;
#endif
PySys_SetArgv(argc, argv);
mainModule = PyImport_AddModule("__main__");
assert(mainModule);
// We have to set things up in the special __main__ module
pythonMain = PyImport_AddModule(PyCC("__main__"));
if (pythonMain == NULL)
panic("Could not import __main__");
mainDict = PyModule_GetDict(mainModule);
assert(mainDict);
const std::vector<std::string> commands = {
"import m5",
"m5.main()"
};
execPythonCommands(commands);
PyObject *result;
const char **command = m5MainCommands;
#if HAVE_PROTOBUF
google::protobuf::ShutdownProtobufLibrary();
#endif
// evaluate each command in the m5MainCommands array (basically a
// bunch of python statements.
while (*command) {
result = PyRun_String(*command, Py_file_input, mainDict, mainDict);
if (!result) {
PyErr_Print();
break;
}
Py_DECREF(result);
return 0;
}
command++;
void
gem5Component::initPython(int argc, char *_argv[])
{
// should be similar to main() in src/sim/main.cc
PyObject *mainModule, *mainDict;
int ret;
// Initialize m5 special signal handling.
gem5::initSignals();
#if PY_MAJOR_VERSION >= 3
std::unique_ptr<wchar_t[], decltype(&PyMem_RawFree)> program(
Py_DecodeLocale(_argv[0], NULL),
&PyMem_RawFree);
Py_SetProgramName(program.get());
#else
Py_SetProgramName(_argv[0]);
#endif
// Register native modules with Python's init system before
// initializing the interpreter.
if (!Py_IsInitialized()) {
gem5::registerNativeModules();
// initialize embedded Python interpreter
Py_Initialize();
} else {
// https://stackoverflow.com/a/28349174
PyImport_AddModule("_m5");
PyObject* module = gem5::EmbeddedPyBind::initAll();
PyObject* sys_modules = PyImport_GetModuleDict();
PyDict_SetItemString(sys_modules, "_m5", module);
Py_DECREF(module);
}
// Initialize the embedded m5 python library
ret = gem5::EmbeddedPython::initAll();
if (ret == 0)
startM5(argc, _argv); // start m5
else
output.output(CALL_INFO, "Not calling m5Main due to ret=%d\n", ret);
}
::gem5::ExternalMaster::Port*
gem5Component::getExternalPort(const std::string &name,
::gem5::ExternalMaster &owner, const std::string &port_data)
void
gem5Component::splitCommandArgs(std::string &cmd, std::vector<char*> &args)
{
std::string s(name); // bridges non-& result and &-arg
auto master = new ExtMaster(this, info, owner, s);
masters.push_back(master);
return master;
}
std::vector<std::string> parsed_args = tokenizeString(
cmd, {'\\', ' ', '\'', '\"'}
);
::gem5::ExternalSlave::Port*
gem5Component::getExternalPort(const std::string &name,
::gem5::ExternalSlave &owner, const std::string &port_data)
{
std::string s(name); // bridges non-& result and &-arg
auto slave = new ExtSlave(this, info, owner, s);
slaves.push_back(slave);
return slave;
for (auto part: parsed_args)
args.push_back(strdup(part.c_str()));
}

View File

@@ -1,15 +1,6 @@
// Copyright (c) 2015 ARM Limited
// Copyright (c) 2021 The Regents of the University of California
// All rights reserved.
//
// The license below extends only to copyright in the software and shall
// not be construed as granting a license to any other intellectual
// property including but not limited to intellectual property relating
// to a hardware implementation of the functionality of the software
// licensed hereunder. You may use the software subject to the license
// terms below provided that you ensure that this notice is replicated
// unmodified and in its entirety in all distributions of the software,
// modified or unmodified, in source code or in binary form.
//
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
@@ -20,7 +11,42 @@
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Copyright (c) 2015 ARM Limited
// All rights reserved.
//
// The license below extends only to copyright in the software and shall
// not be construed as granting a license to any other intellectual
// property including but not limited to intellectual property relating
// to a hardware implementation of the functionality of the software
// licensed hereunder. You may use the software subject to the license
// terms below provided that you ensure that this notice is replicated
// unmodified and in its entirety in all distributions of the software,
// modified or unmodified, in source code or in binary form.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -42,61 +68,84 @@
//
// For license information, see the LICENSE file in the current directory.
#ifndef EXT_SST_GEM5_HH
#define EXT_SST_GEM5_HH
#ifndef __GEM5_COMPONENT_H__
#define __GEM5_COMPONENT_H__
#define TRACING_ON 0
#include <cstdint>
#include <string>
#include <vector>
#include <core/sst_config.h>
#include <core/component.h>
#include <sst/core/sst_config.h>
#include <sst/core/component.h>
#include <sst/core/simulation.h>
#include <sst/core/interfaces/stringEvent.h>
#include <sst/core/interfaces/simpleMem.h>
#include <mem/external_master.hh>
#include <mem/external_slave.hh>
#include <sim/simulate.hh>
#include "ExtMaster.hh"
#include "ExtSlave.hh"
#include <sst/core/eli/elementinfo.h>
#include <sst/core/link.h>
namespace SST {
namespace gem5 {
#include "sst_responder_subcomponent.hh"
class gem5Component : public SST::Component,
public ::gem5::ExternalSlave::Handler,
public ::gem5::ExternalMaster::Handler
class gem5Component: public SST::Component
{
private:
Output dbg;
Output info;
uint64_t sim_cycles;
uint64_t clocks_processed;
std::vector<ExtMaster*> masters;
std::vector<ExtSlave*> slaves;
void splitCommandArgs(std::string &cmd, std::vector<char*> &args);
void initPython(int argc, char *argv[]);
public:
gem5Component(ComponentId_t id, Params &params);
public:
gem5Component(SST::ComponentId_t id, SST::Params& params);
~gem5Component();
virtual void init(unsigned);
virtual void setup();
virtual void finish();
bool clockTick(Cycle_t);
virtual ::gem5::ExternalMaster::Port *getExternalPort(
const std::string &name, ::gem5::ExternalMaster &owner,
const std::string &port_data);
void init(unsigned phase);
void setup();
void finish();
bool clockTick(SST::Cycle_t current_cycle);
int startM5(int argc, char **_argv);
// stuff needed for gem5 sim
public:
PyObject *pythonMain;
int execPythonCommands(const std::vector<std::string>& commands);
private:
SST::Output output;
SSTResponderSubComponent* systemPort;
SSTResponderSubComponent* cachePort;
uint64_t clocksProcessed;
SST::TimeConverter* timeConverter;
gem5::GlobalSimLoopExitEvent *simulateLimitEvent;
std::vector<char*> args;
void initPython(int argc, char **argv);
void splitCommandArgs(std::string &cmd, std::vector<char*> &args);
bool threadInitialized;
gem5::GlobalSimLoopExitEvent* simulateGem5(gem5::Tick n_cycles);
static gem5::Event* doSimLoop(gem5::EventQueue* eventq);
public: // register the component to SST
SST_ELI_REGISTER_COMPONENT(
gem5Component,
"gem5", // SST will look for libgem5.so
"gem5Component",
SST_ELI_ELEMENT_VERSION(1, 0, 0),
"Initialize gem5 and link SST's ports to gem5's ports",
COMPONENT_CATEGORY_UNCATEGORIZED
)
SST_ELI_DOCUMENT_PARAMS(
{"cmd", "command to run gem5's config"}
)
SST_ELI_DOCUMENT_SUBCOMPONENT_SLOTS(
{"system_port", "Connection to gem5 system_port", "gem5.gem5Bridge"},
{"cache_port", "Connection to gem5 CPU", "gem5.gem5Bridge"}
)
virtual ::gem5::ExternalSlave::Port *getExternalPort(
const std::string &name, ::gem5::ExternalSlave &owner,
const std::string &port_data);
};
}
}
#endif
#endif // __GEM5_COMPONENT_H__

View File

@@ -1,80 +0,0 @@
// Copyright (c) 2015 ARM Limited
// All rights reserved.
//
// The license below extends only to copyright in the software and shall
// not be construed as granting a license to any other intellectual
// property including but not limited to intellectual property relating
// to a hardware implementation of the functionality of the software
// licensed hereunder. You may use the software subject to the license
// terms below provided that you ensure that this notice is replicated
// unmodified and in its entirety in all distributions of the software,
// modified or unmodified, in source code or in binary form.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Copyright 2009-2014 Sandia Coporation. Under the terms
// of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S.
// Government retains certain rights in this software.
//
// Copyright (c) 2009-2014, Sandia Corporation
// All rights reserved.
//
// For license information, see the LICENSE file in the current directory.
#include <core/sst_config.h>
#include "gem5.hh"
static
SST::Component* create_gem5(SST::ComponentId_t id, SST::Params &params)
{
return new SST::gem5::gem5Component(id, params);
}
static const SST::ElementInfoParam gem5_params[] = {
{"cmd", "gem5 command to execute."},
{"comp_debug", "Debug information from the component: 0 (off), 1 (stdout),"
" 2 (stderr), 3(file)"},
{"frequency", "Frequency with which to call into gem5"},
{NULL, NULL}
};
static const SST::ElementInfoComponent components[] = {
{ "gem5",
"gem5 simulation component",
NULL,
create_gem5,
gem5_params
},
{ NULL, NULL, NULL, NULL, NULL }
};
extern "C" {
SST::ElementLibraryInfo gem5_eli = {
"gem5",
"gem5 Simulation",
components,
};
}

3
ext/sst/sst/README.md Normal file
View File

@@ -0,0 +1,3 @@
# SST System Configurations
This folder contains SST configurations used for SST/gem5 simulation.

120
ext/sst/sst/example.py Normal file
View File

@@ -0,0 +1,120 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import sst
import sys
import os
from sst import UnitAlgebra
cache_link_latency = "1ps"
bbl = "riscv-boot-exit-nodisk"
cpu_clock_rate = "3GHz"
# gem5 will send requests to physical addresses of range [0x80000000, inf) to memory
# currently, we do not subtract 0x80000000 from the request's address to get the "real" address
# so, the mem_size would always be 2GiB larger than the desired memory size
memory_size_gem5 = "4GiB"
memory_size_sst = "6GiB"
addr_range_end = UnitAlgebra(memory_size_sst).getRoundedValue()
l1_params = {
"access_latency_cycles" : "1",
"cache_frequency" : cpu_clock_rate,
"replacement_policy" : "lru",
"coherence_protocol" : "MESI",
"associativity" : "4",
"cache_line_size" : "64",
"cache_size" : "4 KiB",
"L1" : "1",
}
cpu_params = {
"frequency": cpu_clock_rate,
"cmd": " ../../configs/example/sst/riscv_fs.py --cpu-clock-rate {} --memory-size {}".format(cpu_clock_rate, memory_size_gem5),
"debug_flags": ""
}
gem5_node = sst.Component("gem5_node", "gem5.gem5Component")
gem5_node.addParams(cpu_params)
cache_bus = sst.Component("cache_bus", "memHierarchy.Bus")
cache_bus.addParams( { "bus_frequency" : cpu_clock_rate } )
system_port = gem5_node.setSubComponent("system_port", "gem5.gem5Bridge", 0) # for initialization
system_port.addParams({ "response_receiver_name": "system.system_outgoing_bridge"}) # tell the SubComponent the name of the corresponding SimObject
cache_port = gem5_node.setSubComponent("cache_port", "gem5.gem5Bridge", 0) # SST -> gem5
cache_port.addParams({ "response_receiver_name": "system.memory_outgoing_bridge"})
# L1 cache
l1_cache = sst.Component("l1_cache", "memHierarchy.Cache")
l1_cache.addParams(l1_params)
# Memory
memctrl = sst.Component("memory", "memHierarchy.MemController")
memctrl.addParams({
"debug" : "0",
"clock" : "1GHz",
"request_width" : "64",
"addr_range_end" : addr_range_end, # should be changed accordingly to memory_size_sst
})
memory = memctrl.setSubComponent("backend", "memHierarchy.simpleMem")
memory.addParams({
"access_time" : "30ns",
"mem_size" : memory_size_sst
})
# Connections
# cpu <-> L1
cpu_cache_link = sst.Link("cpu_l1_cache_link")
cpu_cache_link.connect(
(cache_port, "port", cache_link_latency),
(cache_bus, "high_network_0", cache_link_latency)
)
system_cache_link = sst.Link("system_cache_link")
system_cache_link.connect(
(system_port, "port", cache_link_latency),
(cache_bus, "high_network_1", cache_link_latency)
)
cache_bus_cache_link = sst.Link("cache_bus_cache_link")
cache_bus_cache_link.connect(
(cache_bus, "low_network_0", cache_link_latency),
(l1_cache, "high_network_0", cache_link_latency)
)
# L1 <-> mem
cache_mem_link = sst.Link("l1_cache_mem_link")
cache_mem_link.connect(
(l1_cache, "low_network_0", cache_link_latency),
(memctrl, "direct_link", cache_link_latency)
)
# enable Statistics
stat_params = { "rate" : "0ns" }
sst.setStatisticLoadLevel(5)
sst.setStatisticOutput("sst.statOutputTXT", {"filepath" : "./sst-stats.txt"})
sst.enableAllStatisticsForComponentName("l1_cache", stat_params)
sst.enableAllStatisticsForComponentName("memory", stat_params)

68
ext/sst/sst_responder.cc Normal file
View File

@@ -0,0 +1,68 @@
// Copyright (c) 2021 The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "sst_responder.hh"
#include <cassert>
#include "translator.hh"
SSTResponder::SSTResponder(SSTResponderSubComponent* owner_)
: gem5::SSTResponderInterface()
{
owner = owner_;
}
SSTResponder::~SSTResponder()
{
}
void
SSTResponder::setOutputStream(SST::Output* output_)
{
output = output_;
}
bool
SSTResponder::handleRecvTimingReq(gem5::PacketPtr pkt)
{
auto request = Translator::gem5RequestToSSTRequest(
pkt, owner->sstRequestIdToPacketMap
);
return owner->handleTimingReq(request);
}
void
SSTResponder::handleRecvRespRetry()
{
owner->handleRecvRespRetry();
}
void
SSTResponder::handleRecvFunctional(gem5::PacketPtr pkt)
{
owner->handleRecvFunctional(pkt);
}

74
ext/sst/sst_responder.hh Normal file
View File

@@ -0,0 +1,74 @@
// Copyright (c) 2021 The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef __SST_RESPONDER_HH__
#define __SST_RESPONDER_HH__
#define TRACING_ON 0
#include <string>
#include <vector>
#include <sst/core/sst_config.h>
#include <sst/core/component.h>
#include <sst/core/simulation.h>
#include <sst/core/interfaces/stringEvent.h>
#include <sst/core/interfaces/simpleMem.h>
#include <sst/core/eli/elementinfo.h>
#include <sst/core/link.h>
#include <sst/elements/memHierarchy/memEvent.h>
#include <sst/elements/memHierarchy/memTypes.h>
#include <sst/elements/memHierarchy/util.h>
// from gem5
#include <sim/sim_object.hh>
#include <sst/outgoing_request_bridge.hh>
#include <sst/sst_responder_interface.hh>
#include "sst_responder_subcomponent.hh"
class SSTResponderSubComponent;
class SSTResponder: public gem5::SSTResponderInterface
{
private:
SSTResponderSubComponent* owner;
SST::Output* output;
public:
SSTResponder(SSTResponderSubComponent* owner_);
~SSTResponder() override;
void setOutputStream(SST::Output* output_);
bool handleRecvTimingReq(gem5::PacketPtr pkt) override;
void handleRecvRespRetry() override;
void handleRecvFunctional(gem5::PacketPtr pkt) override;
};
#endif // __SST_RESPONDER_HH__

View File

@@ -0,0 +1,238 @@
// Copyright (c) 2021 The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "sst_responder_subcomponent.hh"
#include <cassert>
#include <sstream>
#include <iomanip>
#ifdef fatal // gem5 sets this
#undef fatal
#endif
SSTResponderSubComponent::SSTResponderSubComponent(SST::ComponentId_t id,
SST::Params& params)
: SubComponent(id)
{
sstResponder = new SSTResponder(this);
gem5SimObjectName = params.find<std::string>("response_receiver_name", "");
if (gem5SimObjectName == "")
assert(false && "The response_receiver_name must be specified");
}
SSTResponderSubComponent::~SSTResponderSubComponent()
{
delete sstResponder;
}
void
SSTResponderSubComponent::setTimeConverter(SST::TimeConverter* tc)
{
timeConverter = tc;
// Get the memory interface
SST::Params interface_params;
// This is how you tell the interface the name of the port it should use
interface_params.insert("port", "port");
interface_params.insert("mem_size", "8GiB");
// Loads a “memHierarchy.memInterface” into index 0 of the “memory” slot
// SHARE_PORTS means the interface can use our port as if it were its own
// INSERT_STATS means the interface will inherit our statistic
// configuration (e.g., if ours are enabled, the interfaces will be too)
memoryInterface = \
loadAnonymousSubComponent<SST::Interfaces::SimpleMem>(
"memHierarchy.memInterface", "memory", 0,
SST::ComponentInfo::SHARE_PORTS | SST::ComponentInfo::INSERT_STATS,
interface_params, timeConverter,
new SST::Interfaces::SimpleMem::Handler<SSTResponderSubComponent>(
this, &SSTResponderSubComponent::portEventHandler)
);
assert(memoryInterface != NULL);
}
void
SSTResponderSubComponent::setOutputStream(SST::Output* output_)
{
output = output_;
}
void
SSTResponderSubComponent::setResponseReceiver(
gem5::OutgoingRequestBridge* gem5_bridge)
{
responseReceiver = gem5_bridge;
responseReceiver->setResponder(sstResponder);
}
bool
SSTResponderSubComponent::handleTimingReq(
SST::Interfaces::SimpleMem::Request* request)
{
memoryInterface->sendRequest(request);
return true;
}
void
SSTResponderSubComponent::init(unsigned phase)
{
if (phase == 1) {
for (auto p: responseReceiver->getInitData()) {
gem5::Addr addr = p.first;
std::vector<uint8_t> data = p.second;
SST::Interfaces::SimpleMem::Request* request = \
new SST::Interfaces::SimpleMem::Request(
SST::Interfaces::SimpleMem::Request::Command::Write, addr,
data.size(), data
);
memoryInterface->sendInitData(request);
}
}
memoryInterface->init(phase);
}
void
SSTResponderSubComponent::setup()
{
}
bool
SSTResponderSubComponent::findCorrespondingSimObject(gem5::Root* gem5_root)
{
gem5::OutgoingRequestBridge* receiver = \
dynamic_cast<gem5::OutgoingRequestBridge*>(
gem5_root->find(gem5SimObjectName.c_str()));
setResponseReceiver(receiver);
return receiver != NULL;
}
void
SSTResponderSubComponent::handleSwapReqResponse(
SST::Interfaces::SimpleMem::Request* request)
{
// get the data, then,
// 1. send a response to gem5 with the original data
// 2. send a write to memory with atomic op applied
SST::Interfaces::SimpleMem::Request::id_t request_id = request->id;
TPacketMap::iterator it = sstRequestIdToPacketMap.find(request_id);
assert(it != sstRequestIdToPacketMap.end());
std::vector<uint8_t> data = request->data;
// step 1
gem5::PacketPtr pkt = it->second;
pkt->setData(request->data.data());
pkt->makeAtomicResponse();
pkt->headerDelay = pkt->payloadDelay = 0;
if (blocked() || !responseReceiver->sendTimingResp(pkt))
responseQueue.push(pkt);
// step 2
(*(pkt->getAtomicOp()))(data.data()); // apply the atomic op
SST::Interfaces::SimpleMem::Request::Command cmd = \
SST::Interfaces::SimpleMem::Request::Command::Write;
SST::Interfaces::SimpleMem::Addr addr = request->addr;
auto data_size = data.size();
SST::Interfaces::SimpleMem::Request* write_request = \
new SST::Interfaces::SimpleMem::Request(
cmd, addr, data_size, data
);
write_request->setMemFlags(
SST::Interfaces::SimpleMem::Request::Flags::F_LOCKED);
memoryInterface->sendRequest(write_request);
delete request;
}
void
SSTResponderSubComponent::portEventHandler(
SST::Interfaces::SimpleMem::Request* request)
{
// Expect to handle an SST response
SST::Interfaces::SimpleMem::Request::id_t request_id = request->id;
TPacketMap::iterator it = sstRequestIdToPacketMap.find(request_id);
// replying to a prior request
if (it != sstRequestIdToPacketMap.end()) {
gem5::PacketPtr pkt = it->second; // the packet that needs response
// Responding to a SwapReq requires a special handler
// 1. send a response to gem5 with the original data
// 2. send a write to memory with atomic op applied
if ((gem5::MemCmd::Command)pkt->cmd.toInt() == gem5::MemCmd::SwapReq) {
handleSwapReqResponse(request);
return;
}
sstRequestIdToPacketMap.erase(it);
Translator::inplaceSSTRequestToGem5PacketPtr(pkt, request);
if (blocked() || !(responseReceiver->sendTimingResp(pkt)))
responseQueue.push(pkt);
} else { // we can handle unexpected invalidates, but nothing else.
SST::Interfaces::SimpleMem::Request::Command cmd = request->cmd;
if (cmd == SST::Interfaces::SimpleMem::Request::Command::WriteResp)
return;
assert(cmd == SST::Interfaces::SimpleMem::Request::Command::Inv);
// make Req/Pkt for Snoop/no response needed
// presently no consideration for masterId, packet type, flags...
gem5::RequestPtr req = std::make_shared<gem5::Request>(
request->addr, request->size, 0, 0
);
gem5::PacketPtr pkt = new gem5::Packet(
req, gem5::MemCmd::InvalidateReq);
// Clear out bus delay notifications
pkt->headerDelay = pkt->payloadDelay = 0;
responseReceiver->sendTimingSnoopReq(pkt);
}
delete request;
}
void
SSTResponderSubComponent::handleRecvRespRetry()
{
while (blocked() &&
responseReceiver->sendTimingResp(responseQueue.front()))
responseQueue.pop();
}
void
SSTResponderSubComponent::handleRecvFunctional(gem5::PacketPtr pkt)
{
}
bool
SSTResponderSubComponent::blocked()
{
return !(responseQueue.empty());
}

View File

@@ -0,0 +1,122 @@
// Copyright (c) 2021 The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef __SST_RESPONDER_SUBCOMPONENT_HH__
#define __SST_RESPONDER_SUBCOMPONENT_HH__
#define TRACING_ON 0
#include <string>
#include <vector>
#include <unordered_map>
#include <queue>
#include <sst/core/sst_config.h>
#include <sst/core/component.h>
#include <sst/core/simulation.h>
#include <sst/core/interfaces/stringEvent.h>
#include <sst/core/interfaces/simpleMem.h>
#include <sst/core/eli/elementinfo.h>
#include <sst/core/link.h>
// from gem5
#include <sim/sim_object.hh>
#include <sst/outgoing_request_bridge.hh>
#include <sim/root.hh>
#include <sst/sst_responder_interface.hh>
#include "translator.hh"
#include "sst_responder.hh"
class SSTResponderSubComponent: public SST::SubComponent
{
private:
gem5::OutgoingRequestBridge* responseReceiver;
gem5::SSTResponderInterface* sstResponder;
SST::Interfaces::SimpleMem* memoryInterface;
SST::TimeConverter* timeConverter;
SST::Output* output;
std::queue<gem5::PacketPtr> responseQueue;
std::vector<SST::Interfaces::SimpleMem::Request*> initRequests;
std::string gem5SimObjectName;
public:
SSTResponderSubComponent(SST::ComponentId_t id, SST::Params& params);
~SSTResponderSubComponent();
void init(unsigned phase);
void setTimeConverter(SST::TimeConverter* tc);
void setOutputStream(SST::Output* output_);
void setResponseReceiver(gem5::OutgoingRequestBridge* gem5_bridge);
void portEventHandler(SST::Interfaces::SimpleMem::Request* request);
bool blocked();
void setup();
// return true if the SimObject could be found
bool findCorrespondingSimObject(gem5::Root* gem5_root);
bool handleTimingReq(SST::Interfaces::SimpleMem::Request* request);
void handleRecvRespRetry();
void handleRecvFunctional(gem5::PacketPtr pkt);
void handleSwapReqResponse(SST::Interfaces::SimpleMem::Request* request);
TPacketMap sstRequestIdToPacketMap;
public: // register the component to SST
SST_ELI_REGISTER_SUBCOMPONENT_API(SSTResponderSubComponent);
SST_ELI_REGISTER_SUBCOMPONENT_DERIVED(
SSTResponderSubComponent,
"gem5", // SST will look for libgem5.so
"gem5Bridge",
SST_ELI_ELEMENT_VERSION(1, 0, 0),
"Initialize gem5 and link SST's ports to gem5's ports",
SSTResponderSubComponent
)
SST_ELI_DOCUMENT_SUBCOMPONENT_SLOTS(
{"memory", "Interface to the memory subsystem", \
"SST::Interfaces::SimpleMem"}
)
SST_ELI_DOCUMENT_PORTS(
{"port", "Handling mem events", {"memHierarchy.MemEvent", ""}}
)
SST_ELI_DOCUMENT_PARAMS(
{"response_receiver_name", \
"Name of the SimObject receiving the responses"}
)
};
#endif // __SST_RESPONDER_SUBCOMPONENT_HH__

View File

@@ -1,204 +0,0 @@
# Copyright (c) 2015-2016 ARM Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Curtis Dunham
import sst
import sys
import os
lat="1 ns"
buslat="2 ns"
clockRate = "1GHz"
def getenv(name):
res = ""
try:
res = os.environ[name]
except KeyError:
pass
return res
def debug(d):
try:
r = int(getenv(d))
except ValueError:
return 0
return r
baseCacheParams = ({
"debug" :debug("DEBUG"),
"debug_level" : 6,
"coherence_protocol" : "MSI",
"replacement_policy" : "LRU",
"cache_line_size" : 64,
"cache_frequency" : clockRate
})
l1CacheParams = ({
"debug" : debug("DEBUG"),
"debug_level" : 6,
"L1" : 1,
"cache_size" : "64 KB",
"associativity" : 4,
"access_latency_cycles" : 2,
"low_network_links" : 1
})
l2CacheParams = ({
"debug" : debug("DEBUG"),
"debug_level" : 6,
"L1" : 0,
"cache_size" : "256 KB",
"associativity" : 8,
"access_latency_cycles" : 8,
"high_network_links" : 1,
"mshr_num_entries" : 4096,
"low_network_links" : 1
})
GEM5 = sst.Component("system", "gem5.gem5")
GEM5.addParams({
"comp_debug" : debug("GEM5_DEBUG"),
"gem5DebugFlags" : debug("M5_DEBUG"),
"frequency" : clockRate,
"cmd" : "configs/example/fs.py --num-cpus 4 --disk-image=vexpress64-openembedded_minimal-armv8_20130623-376.img --root-device=/dev/sda2 --kernel=vmlinux.aarch64.20140821 --dtb-filename=vexpress.aarch64.20140821.dtb --mem-size=256MB --machine-type=VExpress_EMM64 --cpu-type=timing --external-memory-system=sst"
})
bus = sst.Component("membus", "memHierarchy.Bus")
bus.addParams({
"bus_frequency": "2GHz",
"debug" : debug("DEBUG"),
"debug_level" : 8
})
def buildL1(name, m5, connector):
cache = sst.Component(name, "memHierarchy.Cache")
cache.addParams(baseCacheParams)
cache.addParams(l1CacheParams)
link = sst.Link("cpu_%s_link"%name)
link.connect((m5, connector, lat), (cache, "high_network_0", lat))
return cache
SysBusConn = buildL1("gem5SystemBus", GEM5, "system.external_memory.port")
bus_port = 0
link = sst.Link("sysbus_bus_link")
link.connect((SysBusConn, "low_network_0", buslat), (bus, "high_network_%u" % bus_port, buslat))
bus_port = bus_port + 1
ioCache = buildL1("ioCache", GEM5, "system.iocache.port")
ioCache.addParams({
"debug" : 0,
"debug_level" : 6,
"cache_size" : "16 KB",
"associativity" : 4
})
link = sst.Link("ioCache_bus_link")
link.connect((ioCache, "low_network_0", buslat), (bus, "high_network_%u" % bus_port, buslat))
def buildCPU(m5, num):
l1iCache = buildL1("cpu%u.l1iCache" % num, m5, "system.cpu%u.icache.port" % num)
l1dCache = buildL1("cpu%u.l1dCache" % num, m5, "system.cpu%u.dcache.port" % num)
itlbCache = buildL1("cpu%u.itlbCache" % num, m5, "system.cpu%u.itb_walker_cache.port" % num)
dtlbCache = buildL1("cpu%u.dtlbCache" % num, m5, "system.cpu%u.dtb_walker_cache.port" % num)
l1dCache.addParams({
"debug" : 0,
"debug_level" : 10,
"snoop_l1_invalidations" : 1
})
global bus_port
link = sst.Link("cpu%u.l1iCache_bus_link" % num) ; bus_port = bus_port + 1
link.connect((l1iCache, "low_network_0", buslat), (bus, "high_network_%u" % bus_port, buslat))
link = sst.Link("cpu%u.l1dCache_bus_link" % num) ; bus_port = bus_port + 1
link.connect((l1dCache, "low_network_0", buslat), (bus, "high_network_%u" % bus_port, buslat))
link = sst.Link("cpu%u.itlbCache_bus_link" % num) ; bus_port = bus_port + 1
link.connect((itlbCache, "low_network_0", buslat), (bus, "high_network_%u" % bus_port, buslat))
link = sst.Link("cpu%u.dtlbCache_bus_link" % num) ; bus_port = bus_port + 1
link.connect((dtlbCache, "low_network_0", buslat), (bus, "high_network_%u" % bus_port, buslat))
buildCPU(GEM5, 0)
buildCPU(GEM5, 1)
buildCPU(GEM5, 2)
buildCPU(GEM5, 3)
l2cache = sst.Component("l2cache", "memHierarchy.Cache")
l2cache.addParams(baseCacheParams)
l2cache.addParams(l2CacheParams)
l2cache.addParams({
"network_address" : "2"
})
link = sst.Link("l2cache_bus_link")
link.connect((l2cache, "high_network_0", buslat), (bus, "low_network_0", buslat))
memory = sst.Component("memory", "memHierarchy.MemController")
memory.addParams({
"request_width" : 64,
"coherence_protocol" : "MSI",
"access_time" : "25 ns",
"backend.mem_size" : "256MiB",
"clock" : "2GHz",
"debug" : debug("DEBUG"),
"range_start" : 0, # 2 * (1024 ** 3), # it's behind a directory controller.
})
comp_chiprtr = sst.Component("chiprtr", "merlin.hr_router")
comp_chiprtr.addParams({
"xbar_bw" : "16GB/s",
"link_bw" : "16GB/s",
"input_buf_size" : "1KB",
"num_ports" : "3",
"flit_size" : "72B",
"output_buf_size" : "1KB",
"id" : "0",
"topology" : "merlin.singlerouter"
})
comp_dirctrl = sst.Component("dirctrl", "memHierarchy.DirectoryController")
comp_dirctrl.addParams({
"coherence_protocol" : "MSI",
"network_address" : "1",
"entry_cache_size" : "16384",
"network_bw" : "1GB/s",
"addr_range_start" : 2 * (1024 ** 3),
"addr_range_end" : 2 * (1024 ** 3) + 256 * (1024 ** 2)
})
sst.Link("link_cache_net_0").connect((l2cache, "directory", "10ns"), (comp_chiprtr, "port2", "2ns"))
sst.Link("link_dir_net_0").connect((comp_chiprtr, "port1", "2ns"), (comp_dirctrl, "network", "2ns"))
sst.Link("l2cache_io_link").connect((comp_chiprtr, "port0", "2ns"), (GEM5, "network", buslat))
sst.Link("link_dir_mem_link").connect((comp_dirctrl, "memory", "10ns"), (memory, "direct_link", "10ns"))

121
ext/sst/translator.hh Normal file
View File

@@ -0,0 +1,121 @@
// Copyright (c) 2021 The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef __TRANSLATOR_H__
#define __TRANSLATOR_H__
#include <sst/core/simulation.h>
#include <sst/core/interfaces/stringEvent.h>
#include <sst/core/interfaces/simpleMem.h>
#include <sst/elements/memHierarchy/memEvent.h>
#include <sst/elements/memHierarchy/memTypes.h>
#include <sst/elements/memHierarchy/util.h>
typedef std::unordered_map<SST::Interfaces::SimpleMem::Request::id_t,
gem5::PacketPtr> TPacketMap;
namespace Translator
{
inline SST::Interfaces::SimpleMem::Request*
gem5RequestToSSTRequest(gem5::PacketPtr pkt,
TPacketMap& sst_request_id_to_packet_map)
{
SST::Interfaces::SimpleMem::Request::Command cmd;
switch ((gem5::MemCmd::Command)pkt->cmd.toInt()) {
case gem5::MemCmd::HardPFReq:
case gem5::MemCmd::SoftPFReq:
case gem5::MemCmd::LoadLockedReq:
case gem5::MemCmd::ReadExReq:
case gem5::MemCmd::ReadReq:
case gem5::MemCmd::SwapReq:
cmd = SST::Interfaces::SimpleMem::Request::Command::Read;
break;
case gem5::MemCmd::StoreCondReq:
case gem5::MemCmd::WriteReq:
cmd = SST::Interfaces::SimpleMem::Request::Command::Write;
break;
default:
assert(false && "Unable to convert gem5 packet");
}
SST::Interfaces::SimpleMem::Addr addr = pkt->getAddr();
uint8_t* data_ptr = pkt->getPtr<uint8_t>();
auto data_size = pkt->getSize();
std::vector<uint8_t> data = std::vector<uint8_t>(
data_ptr, data_ptr + data_size
);
SST::Interfaces::SimpleMem::Request* request = \
new SST::Interfaces::SimpleMem::Request(
cmd, addr, data_size, data
);
if ((gem5::MemCmd::Command)pkt->cmd.toInt() == gem5::MemCmd::LoadLockedReq
|| (gem5::MemCmd::Command)pkt->cmd.toInt() == gem5::MemCmd::SwapReq
|| pkt->req->isLockedRMW()) {
request->setMemFlags(
SST::Interfaces::SimpleMem::Request::Flags::F_LOCKED);
} else if ((gem5::MemCmd::Command)pkt->cmd.toInt() == \
gem5::MemCmd::StoreCondReq) {
request->setMemFlags(
SST::Interfaces::SimpleMem::Request::Flags::F_LLSC);
}
if (pkt->req->isUncacheable()) {
request->setFlags(
SST::Interfaces::SimpleMem::Request::Flags::F_NONCACHEABLE);
}
if (pkt->needsResponse())
sst_request_id_to_packet_map[request->id] = pkt;
return request;
}
inline void
inplaceSSTRequestToGem5PacketPtr(gem5::PacketPtr pkt,
SST::Interfaces::SimpleMem::Request* request)
{
pkt->makeResponse();
// Resolve the success of Store Conditionals
if (pkt->isLLSC() && pkt->isWrite()) {
// SC interprets ExtraData == 1 as the store was successful
pkt->req->setExtraData(1);
}
pkt->setData(request->data.data());
// Clear out bus delay notifications
pkt->headerDelay = pkt->payloadDelay = 0;
}
}; // namespace Translator
#endif // __TRANSLATOR_H__

57
ext/sst/util.hh Normal file
View File

@@ -0,0 +1,57 @@
// Copyright (c) 2021 The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <algorithm>
#include <string>
#include <vector>
std::vector<std::string>
tokenizeString(std::string s_, const std::vector<char>& delimiters)
{
std::vector<std::string> tokens;
if (delimiters.size() < 1) {
tokens.push_back(s_);
return tokens;
}
std::string s = s_ + delimiters[0];
uint64_t pos = -1ULL; // the current position of the delimiter
uint64_t n = s.size(); // the length of the string s
while (pos != n - 1) {
uint64_t prev_pos = pos;
do {
pos++;
} while (std::find(delimiters.begin(), delimiters.end(), s[pos]) == \
delimiters.end());
if (pos > prev_pos + 1)
tokens.push_back(s.substr(prev_pos+1, pos - prev_pos - 1));
}
return tokens;
}

View File

@@ -0,0 +1,39 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from m5.params import *
from m5.SimObject import SimObject
class OutgoingRequestBridge(SimObject):
type = 'OutgoingRequestBridge'
cxx_header = "sst/outgoing_request_bridge.hh"
cxx_class = 'gem5::OutgoingRequestBridge'
port = ResponsePort("Response Port")
physical_address_ranges = VectorParam.AddrRange(
[AddrRange(0x80000000, MaxAddr)],
"Physical address ranges."
)

32
src/sst/SConscript Normal file
View File

@@ -0,0 +1,32 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Import('*')
SimObject('OutgoingRequestBridge.py')
Source('outgoing_request_bridge.cc')
Source('sst_responder_interface.cc')

View File

@@ -0,0 +1,154 @@
// Copyright (c) 2021 The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "sst/outgoing_request_bridge.hh"
#include <cassert>
#include <iomanip>
#include <sstream>
#include "base/trace.hh"
namespace gem5
{
OutgoingRequestBridge::OutgoingRequestBridge(
const OutgoingRequestBridgeParams &params) :
SimObject(params),
outgoingPort(std::string(name()), this),
sstResponder(nullptr),
physicalAddressRanges(params.physical_address_ranges.begin(),
params.physical_address_ranges.end())
{
}
OutgoingRequestBridge::~OutgoingRequestBridge()
{
}
OutgoingRequestBridge::
OutgoingRequestPort::OutgoingRequestPort(const std::string &name_,
OutgoingRequestBridge* owner_) :
ResponsePort(name_, owner_)
{
owner = owner_;
}
OutgoingRequestBridge::
OutgoingRequestPort::~OutgoingRequestPort()
{
}
void
OutgoingRequestBridge::init()
{
if (outgoingPort.isConnected())
outgoingPort.sendRangeChange();
}
Port &
OutgoingRequestBridge::getPort(const std::string &if_name, PortID idx)
{
return outgoingPort;
}
AddrRangeList
OutgoingRequestBridge::getAddrRanges() const
{
return outgoingPort.getAddrRanges();
}
std::vector<std::pair<Addr, std::vector<uint8_t>>>
OutgoingRequestBridge::getInitData() const
{
return initData;
}
void
OutgoingRequestBridge::setResponder(SSTResponderInterface* responder)
{
sstResponder = responder;
}
bool
OutgoingRequestBridge::sendTimingResp(gem5::PacketPtr pkt)
{
return outgoingPort.sendTimingResp(pkt);
}
void
OutgoingRequestBridge::sendTimingSnoopReq(gem5::PacketPtr pkt)
{
outgoingPort.sendTimingSnoopReq(pkt);
}
void
OutgoingRequestBridge::handleRecvFunctional(PacketPtr pkt)
{
uint8_t* ptr = pkt->getPtr<uint8_t>();
uint64_t size = pkt->getSize();
std::vector<uint8_t> data(ptr, ptr+size);
initData.push_back(std::make_pair(pkt->getAddr(), data));
}
Tick
OutgoingRequestBridge::
OutgoingRequestPort::recvAtomic(PacketPtr pkt)
{
assert(false && "OutgoingRequestPort::recvAtomic not implemented");
return Tick();
}
void
OutgoingRequestBridge::
OutgoingRequestPort::recvFunctional(PacketPtr pkt)
{
owner->handleRecvFunctional(pkt);
}
bool
OutgoingRequestBridge::
OutgoingRequestPort::recvTimingReq(PacketPtr pkt)
{
owner->sstResponder->handleRecvTimingReq(pkt);
return true;
}
void
OutgoingRequestBridge::
OutgoingRequestPort::recvRespRetry()
{
owner->sstResponder->handleRecvRespRetry();
}
AddrRangeList
OutgoingRequestBridge::
OutgoingRequestPort::getAddrRanges() const
{
return owner->physicalAddressRanges;
}
}; // namespace gem5

View File

@@ -0,0 +1,122 @@
// Copyright (c) 2021 The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef __SST_OUTGOING_REQUEST_BRIDGE_HH__
#define __SST_OUTGOING_REQUEST_BRIDGE_HH__
#include <utility>
#include <vector>
#include "mem/port.hh"
#include "params/OutgoingRequestBridge.hh"
#include "sim/sim_object.hh"
#include "sst/sst_responder_interface.hh"
/**
* - OutgoingRequestBridge acts as a SimObject owning pointers to both a gem5
* OutgoingRequestPort and an SST port (via SSTResponderInterface). This bridge
* will forward gem5 packets from the gem5 port to the SST interface. Responses
* from SST will be handle by OutgoingRequestPort itself. Note: the bridge
* should be decoupled from the SST libraries so that it'll be
* SST-version-independent. Thus, there's no translation between a gem5 packet
* and SST Response here.
*
* - OutgoingRequestPort is a specialized ResponsePort working with
* OutgoingRequestBridge.
*/
namespace gem5
{
class OutgoingRequestBridge: public SimObject
{
public:
class OutgoingRequestPort: public ResponsePort
{
private:
OutgoingRequestBridge* owner;
public:
OutgoingRequestPort(const std::string &name_,
OutgoingRequestBridge* owner_);
~OutgoingRequestPort();
Tick recvAtomic(PacketPtr pkt);
void recvFunctional(PacketPtr pkt);
bool recvTimingReq(PacketPtr pkt);
void recvRespRetry();
AddrRangeList getAddrRanges() const;
};
public:
// a gem5 ResponsePort
OutgoingRequestPort outgoingPort;
// pointer to the corresponding SST responder
SSTResponderInterface* sstResponder;
// this vector holds the initialization data sent by gem5
std::vector<std::pair<Addr, std::vector<uint8_t>>> initData;
AddrRangeList physicalAddressRanges;
public:
OutgoingRequestBridge(const OutgoingRequestBridgeParams &params);
~OutgoingRequestBridge();
// Required to let the OutgoingRequestPort to send range change request.
void init();
// Returns the range of addresses that the ports will handle.
// Currently, it will return the range of [0x80000000, inf), which is
// specific to RISCV (SiFive's HiFive boards).
AddrRangeList getAddrRanges() const;
// Required to return a port during gem5 instantiate phase.
Port & getPort(const std::string &if_name, PortID idx);
// Returns the buffered data for initialization. This is necessary as
// when gem5 sends functional requests to memory for initialization,
// the connection in SST Memory Hierarchy has not been constructed yet.
std::vector<std::pair<Addr, std::vector<uint8_t>>> getInitData() const;
// gem5 Component (from SST) will call this function to let set the
// bridge's corresponding SSTResponderSubComponent (which implemented
// SSTResponderInterface). I.e., this will connect this bridge to the
// corresponding port in SST.
void setResponder(SSTResponderInterface* responder);
// This function is called when SST wants to sent a timing response to gem5
bool sendTimingResp(PacketPtr pkt);
// This function is called when SST sends response having an invalidate .
void sendTimingSnoopReq(PacketPtr pkt);
// This function is called when gem5 wants to send a non-timing request
// to SST. Should only be called during the SST construction phase, i.e.
// not at the simulation time.
void handleRecvFunctional(PacketPtr pkt);
};
}; // namespace gem5
#endif //__SST_OUTGOING_REQUEST_BRIDGE_HH__

View File

@@ -0,0 +1,36 @@
// Copyright (c) 2021 The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "sst/sst_responder_interface.hh"
namespace gem5
{
SSTResponderInterface::SSTResponderInterface()
{
}
}; // namespace gem5

View File

@@ -0,0 +1,69 @@
// Copyright (c) 2021 The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef __SST_RESPONDER_INTERFACE_HH__
#define __SST_RESPONDER_INTERFACE_HH__
#include <string>
#include "mem/port.hh"
/**
* SSTResponderInterface provides an interface specified gem5's expectations
* on the functionality of an SST Responder. This interfaces expects
* SST Responder to be able to handle gem5 packet on recvTimingReq(),
* recvRespRetry(), and recvFunctional().
*/
namespace gem5
{
class SSTResponderInterface
{
public:
SSTResponderInterface();
virtual ~SSTResponderInterface() {};
// This function is called when OutgoingRequestBridge wants to forward
// a gem5 request to SST, i.e. when OutgoingRequestPort::recvTimingReq()
// is called.
virtual bool handleRecvTimingReq(PacketPtr pkt) = 0;
// This function is called when OutogingRequestPort::recvRespRetry() is
// called.
virtual void handleRecvRespRetry() = 0;
// This function is called when OutgoingRequestBridge wants to send a
// non-timing request. This function should only be called during the
// SST construction phrase, i.e. not at simulation time.
virtual void handleRecvFunctional(PacketPtr pkt) = 0;
};
} // namespace gem5
#endif // __SST_RESPONDER_INTERFACE_HH__