diff --git a/configs/example/sst/riscv_fs.py b/configs/example/sst/riscv_fs.py
index 77db9e4dbe..46754debf5 100644
--- a/configs/example/sst/riscv_fs.py
+++ b/configs/example/sst/riscv_fs.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2021 The Regents of the University of California
+# Copyright (c) 2021-2023 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -104,16 +104,9 @@ def createHiFivePlatform(system):
system.platform.pci_host.pio = system.membus.mem_side_ports
- system.platform.rtc = RiscvRTC(frequency=Frequency("100MHz"))
+ system.platform.rtc = RiscvRTC(frequency=Frequency("10MHz"))
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
@@ -122,6 +115,15 @@ def createHiFivePlatform(system):
system.platform.setNumCores(1)
+ for cpu in system.cpu:
+ # pma_checker has to be added for each of the system cpus.
+ cpu.mmu.pma_checker = PMAChecker(
+ uncacheable=[
+ *system.platform._on_chip_ranges(),
+ *system.platform._off_chip_ranges(),
+ ]
+ )
+
system.platform.attachOnChipIO(system.membus)
system.platform.attachOffChipIO(system.iobus)
diff --git a/ext/sst/INSTALL.md b/ext/sst/INSTALL.md
index 91f92eb7ff..ba61996b32 100644
--- a/ext/sst/INSTALL.md
+++ b/ext/sst/INSTALL.md
@@ -1,8 +1,8 @@
# 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 links to download SST source code are available at
+.
+This guide is using the most recent SST version (13.0.0) as of September 2023.
The following guide assumes `$SST_CORE_HOME` as the location where SST will be
installed.
@@ -11,14 +11,14 @@ installed.
### Downloading the SST-Core Source Code
```sh
-wget https://github.com/sstsimulator/sst-core/releases/download/v11.1.0_Final/sstcore-11.1.0.tar.gz
-tar xf sstcore-11.1.0.tar.gz
+wget https://github.com/sstsimulator/sst-core/releases/download/v13.0.0_Final/sstcore-13.0.0.tar.gz
+tar xzf sstcore-13.0.0.tar.gz
```
### Installing SST-Core
```sh
-cd sstcore-11.1.0
+cd sstcore-13.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)
@@ -36,14 +36,14 @@ export PATH=$SST_CORE_HOME/bin:$PATH
### Downloading the SST-Elements Source Code
```sh
-wget https://github.com/sstsimulator/sst-elements/releases/download/v11.1.0_Final/sstelements-11.1.0.tar.gz
-tar xf sstelements-11.1.0.tar.gz
+wget https://github.com/sstsimulator/sst-elements/releases/download/v13.0.0_Final/sstelements-13.0.0.tar.gz
+tar xzf sstelements-13.0.0.tar.gz
```
### Installing SST-Elements
```sh
-cd sst-elements-library-11.1.0
+cd sst-elements-library-13.0.0
./configure --prefix=$SST_CORE_HOME --with-python=/usr/bin/python3-config \
--with-sst-core=$SST_CORE_HOME
make all -j$(nproc)
@@ -58,24 +58,36 @@ echo "export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$SST_CORE_HOME/lib/pkgconfig/" >>
### Building gem5 library
-At the root of gem5 folder,
-
+At the root of the gem5 folder, you need to compile gem5 as a library. This
+varies dependent on which OS you are using. If you're using Linux, then
+execute the following:
```sh
scons build/RISCV/libgem5_opt.so -j $(nproc) --without-tcmalloc --duplicate-sources
```
+In case you're using Mac, then type the following:
+```sh
+scons build/RISCV/libgem5_opt.dylib -j $(nproc) --without-tcmalloc --duplicate-sources
+```
-**Note:** `--without-tcmalloc` is required to avoid a conflict with SST's malloc.
-`--duplicate-sources` is required as the compilation of SST depends on sources to be present in the "build" directory.
+**Note:**
+* `--without-tcmalloc` is required to avoid a conflict with SST's malloc.
+* `--duplicate-sources` is required as the compilation of SST depends on sources to be present in the "build" directory.
+* The Mac version was tested on a Macbook Air with M2 processor.
### Compiling the SST integration
-At the root of gem5 folder,
-
+Go to the SST directory in the gem5 repo.
```sh
cd ext/sst
-make
```
-
+Depending on your OS, you need to copy the correct `Makefile.xxx` file to
+`Makefile`.
+```sh
+cp Makefile.xxx Makefile # linux or mac
+make -j4
+```
+The make file is hardcoded to RISC-V. IN the case you wish to compile to ARM,
+edit the Makefile or pass `ARCH=RISCV` to `ARCH=ARM` while compiling.
### Running an example simulation
See `README.md`
diff --git a/ext/sst/Makefile.linux b/ext/sst/Makefile.linux
new file mode 100644
index 0000000000..f44ecd46d9
--- /dev/null
+++ b/ext/sst/Makefile.linux
@@ -0,0 +1,21 @@
+SST_VERSION=SST-13.0.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/${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/ -I../../ext
+CPPFLAGS+=-MMD -MP
+SRC=$(wildcard *.cc)
+
+.PHONY: clean all
+
+all: libgem5.so
+
+libgem5.so: $(SRC:%.cc=%.o)
+ ${CXX} ${CPPFLAGS} ${LDFLAGS} $? -o $@ -l${GEM5_LIB}
+
+-include $(SRC:%.cc=%.d)
+
+clean:
+ ${RM} *.[do] libgem5.so
diff --git a/ext/sst/Makefile.mac b/ext/sst/Makefile.mac
new file mode 100644
index 0000000000..4a67570a44
--- /dev/null
+++ b/ext/sst/Makefile.mac
@@ -0,0 +1,21 @@
+SST_VERSION=SST-13.0.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/${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/ -I../../ext
+CPPFLAGS+=-MMD -MP
+SRC=$(wildcard *.cc)
+
+.PHONY: clean all
+
+all: libgem5.dylib
+
+libgem5.dylib: $(SRC:%.cc=%.o)
+ ${CXX} ${CPPFLAGS} ${LDFLAGS} $? -o $@ -l${GEM5_LIB}
+
+-include $(SRC:%.cc=%.d)
+
+clean:
+ ${RM} *.[do] libgem5.dylib
diff --git a/ext/sst/gem5.cc b/ext/sst/gem5.cc
index 7af0eed7b7..8c845f329e 100644
--- a/ext/sst/gem5.cc
+++ b/ext/sst/gem5.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Regents of the University of California
+// Copyright (c) 2021-2023 The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -70,7 +70,6 @@
#include
#include
-#include
#include
#include
#include
@@ -169,16 +168,29 @@ gem5Component::gem5Component(SST::ComponentId_t id, SST::Params& params):
registerAsPrimaryComponent();
primaryComponentDoNotEndSim();
- systemPort = \
- loadUserSubComponent("system_port",0);
- cachePort = \
- loadUserSubComponent("cache_port", 0);
-
- systemPort->setTimeConverter(timeConverter);
- systemPort->setOutputStream(&(output));
- cachePort->setTimeConverter(timeConverter);
- cachePort->setOutputStream(&(output));
-
+ // We need to add another parameter when invoking gem5 scripts from SST to
+ // keep a track of all the OutgoingBridges. This will allow to add or
+ // remove OutgoingBridges from gem5 configs without the need to recompile
+ // the ext/sst source everytime.
+ std::string ports = params.find("ports", "");
+ if (ports.empty()) {
+ output.fatal(
+ CALL_INFO, -1, "Component %s must have a 'ports' parameter.\n",
+ getName().c_str()
+ );
+ }
+ // Split the port names using the util method defined.
+ splitPortNames(ports);
+ for (int i = 0 ; i < sstPortCount ; i++) {
+ std::cout << sstPortNames[i] << std::endl;
+ sstPorts.push_back(
+ loadUserSubComponent(sstPortNames[i], 0)
+ );
+ // If the name defined in the `ports` is incorrect, then the program
+ // will crash when calling `setTimeConverter`.
+ sstPorts[i]->setTimeConverter(timeConverter);
+ sstPorts[i]->setOutputStream(&(output));
+ }
}
gem5Component::~gem5Component()
@@ -216,8 +228,9 @@ gem5Component::init(unsigned phase)
// find the corresponding SimObject for each SSTResponderSubComponent
gem5::Root* gem5_root = gem5::Root::root();
- systemPort->findCorrespondingSimObject(gem5_root);
- cachePort->findCorrespondingSimObject(gem5_root);
+ for (auto &port : sstPorts) {
+ port->findCorrespondingSimObject(gem5_root);
+ }
// initialize the gem5 event queue
if (!(threadInitialized)) {
@@ -230,17 +243,18 @@ gem5Component::init(unsigned phase)
}
}
-
- systemPort->init(phase);
- cachePort->init(phase);
+ for (auto &port : sstPorts) {
+ port->init(phase);
+ }
}
void
gem5Component::setup()
{
output.verbose(CALL_INFO, 1, 0, "Component is being setup.\n");
- systemPort->setup();
- cachePort->setup();
+ for (auto &port : sstPorts) {
+ port->setup();
+ }
}
void
@@ -427,3 +441,16 @@ gem5Component::splitCommandArgs(std::string &cmd, std::vector &args)
for (auto part: parsed_args)
args.push_back(strdup(part.c_str()));
}
+
+void
+gem5Component::splitPortNames(std::string port_names)
+{
+ std::vector parsed_args = tokenizeString(
+ port_names, {'\\', ' ', '\'', '\"'}
+ );
+ sstPortCount = 0;
+ for (auto part: parsed_args) {
+ sstPortNames.push_back(strdup(part.c_str()));
+ sstPortCount++;
+ }
+}
diff --git a/ext/sst/gem5.hh b/ext/sst/gem5.hh
index 447c68c3b2..fd00b1504e 100644
--- a/ext/sst/gem5.hh
+++ b/ext/sst/gem5.hh
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Regents of the University of California
+// Copyright (c) 2021-2023 The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -79,7 +79,6 @@
#include
#include
-#include
#include
#include
@@ -108,15 +107,20 @@ class gem5Component: public SST::Component
private:
SST::Output output;
- SSTResponderSubComponent* systemPort;
- SSTResponderSubComponent* cachePort;
uint64_t clocksProcessed;
SST::TimeConverter* timeConverter;
gem5::GlobalSimLoopExitEvent *simulateLimitEvent;
std::vector args;
+ // We need a list of incoming port names so that we don't need to recompile
+ // everytime when we add a new OutgoingBridge from python.
+ std::vector sstPorts;
+ std::vector sstPortNames;
+ int sstPortCount;
+
void initPython(int argc, char **argv);
void splitCommandArgs(std::string &cmd, std::vector &args);
+ void splitPortNames(std::string port_names);
bool threadInitialized;
@@ -139,6 +143,7 @@ class gem5Component: public SST::Component
)
SST_ELI_DOCUMENT_SUBCOMPONENT_SLOTS(
+ // These are the generally expected ports.
{"system_port", "Connection to gem5 system_port", "gem5.gem5Bridge"},
{"cache_port", "Connection to gem5 CPU", "gem5.gem5Bridge"}
)
diff --git a/ext/sst/sst/arm_example.py b/ext/sst/sst/arm_example.py
index cdee3ca40a..4bc111cb86 100644
--- a/ext/sst/sst/arm_example.py
+++ b/ext/sst/sst/arm_example.py
@@ -10,7 +10,7 @@
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
-# Copyright (c) 2021 The Regents of the University of California
+# Copyright (c) 2021-2023 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -46,9 +46,10 @@ cache_link_latency = "1ps"
kernel = "vmlinux_exit.arm64"
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
+# 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 = "16GiB"
addr_range_end = UnitAlgebra(memory_size_sst).getRoundedValue()
@@ -69,9 +70,22 @@ gem5_command = f" ../../configs/example/sst/arm_fs.py \
--cpu-clock-rate {cpu_clock_rate} \
--memory-size {memory_size_gem5}"
+# We keep a track of all the memory ports that we have.
+sst_ports = {
+ "system_port" : "system.system_outgoing_bridge",
+ "cache_port" : "system.memory_outgoing_bridge"
+}
+
+# We need a list of ports.
+port_list = []
+for port in sst_ports:
+ port_list.append(port)
+
cpu_params = {
"frequency": cpu_clock_rate,
"cmd": gem5_command,
+ "ports" : " ".join(port_list),
+ "debug_flags" : ""
}
gem5_node = sst.Component("gem5_node", "gem5.gem5Component")
@@ -79,16 +93,16 @@ 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
+# for initialization
+system_port = gem5_node.setSubComponent("system_port", "gem5.gem5Bridge", 0)
system_port.addParams({
- "response_receiver_name": "system.system_outgoing_bridge",
+ "response_receiver_name": sst_ports["system_port"],
"mem_size": memory_size_sst
})
-
-cache_port = gem5_node.setSubComponent("cache_port", "gem5.gem5Bridge", 0) # SST -> gem5
+# SST -> gem5
+cache_port = gem5_node.setSubComponent("cache_port", "gem5.gem5Bridge", 0)
cache_port.addParams({
- "response_receiver_name": "system.memory_outgoing_bridge",
+ "response_receiver_name": sst_ports["cache_port"],
"mem_size": memory_size_sst
})
@@ -98,11 +112,12 @@ l1_cache.addParams(l1_params)
# Memory
memctrl = sst.Component("memory", "memHierarchy.MemController")
+# `addr_range_end` should be changed accordingly to memory_size_sst
memctrl.addParams({
"debug" : "0",
"clock" : "1GHz",
"request_width" : "64",
- "addr_range_end" : addr_range_end, # should be changed accordingly to memory_size_sst
+ "addr_range_end" : addr_range_end,
})
memory = memctrl.setSubComponent("backend", "memHierarchy.simpleMem")
memory.addParams({
diff --git a/ext/sst/sst/example.py b/ext/sst/sst/example.py
index 76cf8ad24e..1c35bc3f83 100644
--- a/ext/sst/sst/example.py
+++ b/ext/sst/sst/example.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2021 The Regents of the University of California
+# Copyright (c) 2021-2023 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -34,9 +34,10 @@ 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
+# 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()
@@ -52,10 +53,24 @@ l1_params = {
"L1" : "1",
}
+# We keep a track of all the memory ports that we have.
+sst_ports = {
+ "system_port" : "system.system_outgoing_bridge",
+ "cache_port" : "system.memory_outgoing_bridge"
+}
+
+# We need a list of ports.
+port_list = []
+for port in sst_ports:
+ port_list.append(port)
+
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": ""
+ "cmd": " ../../configs/example/sst/riscv_fs.py"
+ + f" --cpu-clock-rate {cpu_clock_rate}"
+ + f" --memory-size {memory_size_gem5}",
+ "debug_flags": "",
+ "ports" : " ".join(port_list)
}
gem5_node = sst.Component("gem5_node", "gem5.gem5Component")
@@ -64,11 +79,14 @@ 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
+# for initialization
+system_port = gem5_node.setSubComponent(port_list[0], "gem5.gem5Bridge", 0)
+# tell the SubComponent the name of the corresponding SimObject
+system_port.addParams({ "response_receiver_name": sst_ports["system_port"]})
-cache_port = gem5_node.setSubComponent("cache_port", "gem5.gem5Bridge", 0) # SST -> gem5
-cache_port.addParams({ "response_receiver_name": "system.memory_outgoing_bridge"})
+# SST -> gem5
+cache_port = gem5_node.setSubComponent(port_list[1], "gem5.gem5Bridge", 0)
+cache_port.addParams({ "response_receiver_name": sst_ports["cache_port"]})
# L1 cache
l1_cache = sst.Component("l1_cache", "memHierarchy.Cache")
@@ -76,11 +94,12 @@ l1_cache.addParams(l1_params)
# Memory
memctrl = sst.Component("memory", "memHierarchy.MemController")
+# `addr_range_end` should be changed accordingly to memory_size_sst
memctrl.addParams({
"debug" : "0",
"clock" : "1GHz",
"request_width" : "64",
- "addr_range_end" : addr_range_end, # should be changed accordingly to memory_size_sst
+ "addr_range_end" : addr_range_end,
})
memory = memctrl.setSubComponent("backend", "memHierarchy.simpleMem")
memory.addParams({
diff --git a/ext/sst/sst_responder.hh b/ext/sst/sst_responder.hh
index a89d311064..5f483be845 100644
--- a/ext/sst/sst_responder.hh
+++ b/ext/sst/sst_responder.hh
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Regents of the University of California
+// Copyright (c) 2021-2023 The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -35,9 +35,8 @@
#include
#include
-#include
#include
-#include
+#include
#include
#include
diff --git a/ext/sst/sst_responder_subcomponent.cc b/ext/sst/sst_responder_subcomponent.cc
index 366f99aecf..8cd2c04628 100644
--- a/ext/sst/sst_responder_subcomponent.cc
+++ b/ext/sst/sst_responder_subcomponent.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Regents of the University of California
+// Copyright (c) 2021-2023 The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -64,13 +64,12 @@ SSTResponderSubComponent::setTimeConverter(SST::TimeConverter* tc)
// 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 interface’s will be too)
- memoryInterface = \
- loadAnonymousSubComponent(
- "memHierarchy.memInterface", "memory", 0,
- SST::ComponentInfo::SHARE_PORTS | SST::ComponentInfo::INSERT_STATS,
- interface_params, timeConverter,
- new SST::Interfaces::SimpleMem::Handler(
- this, &SSTResponderSubComponent::portEventHandler)
+ memoryInterface = loadAnonymousSubComponent(
+ "memHierarchy.standardInterface", "memory", 0,
+ SST::ComponentInfo::SHARE_PORTS | SST::ComponentInfo::INSERT_STATS,
+ interface_params, timeConverter,
+ new SST::Interfaces::StandardMem::Handler(
+ this, &SSTResponderSubComponent::portEventHandler)
);
assert(memoryInterface != NULL);
}
@@ -91,9 +90,9 @@ SSTResponderSubComponent::setResponseReceiver(
bool
SSTResponderSubComponent::handleTimingReq(
- SST::Interfaces::SimpleMem::Request* request)
+ SST::Interfaces::StandardMem::Request* request)
{
- memoryInterface->sendRequest(request);
+ memoryInterface->send(request);
return true;
}
@@ -104,12 +103,10 @@ SSTResponderSubComponent::init(unsigned phase)
for (auto p: responseReceiver->getInitData()) {
gem5::Addr addr = p.first;
std::vector 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);
+ SST::Interfaces::StandardMem::Request* request = \
+ new SST::Interfaces::StandardMem::Write(
+ addr, data.size(), data);
+ memoryInterface->sendUntimedData(request);
}
}
memoryInterface->init(phase);
@@ -132,20 +129,24 @@ SSTResponderSubComponent::findCorrespondingSimObject(gem5::Root* gem5_root)
void
SSTResponderSubComponent::handleSwapReqResponse(
- SST::Interfaces::SimpleMem::Request* request)
+ SST::Interfaces::StandardMem::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;
+ SST::Interfaces::StandardMem::Request::id_t request_id = request->getID();
TPacketMap::iterator it = sstRequestIdToPacketMap.find(request_id);
assert(it != sstRequestIdToPacketMap.end());
- std::vector data = request->data;
+ std::vector data = \
+ dynamic_cast(request)->data;
// step 1
gem5::PacketPtr pkt = it->second;
- pkt->setData(request->data.data());
+ pkt->setData(
+ dynamic_cast(
+ request)->data.data()
+ );
pkt->makeAtomicResponse();
pkt->headerDelay = pkt->payloadDelay = 0;
if (blocked() || !responseReceiver->sendTimingResp(pkt))
@@ -153,27 +154,29 @@ SSTResponderSubComponent::handleSwapReqResponse(
// 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;
+ // This is a Write. Need to use the Write visitor class. But the original
+ // request is a read response. Therefore, we need to find the address and
+ // the data size and then call Write.
+ SST::Interfaces::StandardMem::Addr addr = \
+ dynamic_cast(request)->pAddr;
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);
+ // Create the Write request here.
+ SST::Interfaces::StandardMem::Request* write_request = \
+ new SST::Interfaces::StandardMem::Write(addr, data_size, data);
+ // F_LOCKED flag in SimpleMem was changed to ReadLock and WriteUnlock
+ // visitor classes. This has to be addressed in the future. The boot test
+ // works without using ReadLock and WriteUnlock classes.
+ memoryInterface->send(write_request);
delete request;
}
void
SSTResponderSubComponent::portEventHandler(
- SST::Interfaces::SimpleMem::Request* request)
+ SST::Interfaces::StandardMem::Request* request)
{
// Expect to handle an SST response
- SST::Interfaces::SimpleMem::Request::id_t request_id = request->id;
+ SST::Interfaces::StandardMem::Request::id_t request_id = request->getID();
TPacketMap::iterator it = sstRequestIdToPacketMap.find(request_id);
@@ -193,19 +196,27 @@ SSTResponderSubComponent::portEventHandler(
Translator::inplaceSSTRequestToGem5PacketPtr(pkt, request);
- if (blocked() || !(responseReceiver->sendTimingResp(pkt)))
+ 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)
+ }
+ } else {
+ // we can handle unexpected invalidates, but nothing else.
+ if (SST::Interfaces::StandardMem::Read* test =
+ dynamic_cast(request)) {
return;
- assert(cmd == SST::Interfaces::SimpleMem::Request::Command::Inv);
-
- // make Req/Pkt for Snoop/no response needed
+ }
+ else if (SST::Interfaces::StandardMem::WriteResp* test =
+ dynamic_cast(
+ request)) {
+ return;
+ }
+ // for Snoop/no response needed
// presently no consideration for masterId, packet type, flags...
gem5::RequestPtr req = std::make_shared(
- request->addr, request->size, 0, 0
- );
+ dynamic_cast(
+ request)->pAddr,
+ dynamic_cast(
+ request)->size, 0, 0);
gem5::PacketPtr pkt = new gem5::Packet(
req, gem5::MemCmd::InvalidateReq);
diff --git a/ext/sst/sst_responder_subcomponent.hh b/ext/sst/sst_responder_subcomponent.hh
index 51bc4f9318..ed9f09d6b8 100644
--- a/ext/sst/sst_responder_subcomponent.hh
+++ b/ext/sst/sst_responder_subcomponent.hh
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Regents of the University of California
+// Copyright (c) 2021-2023 The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -36,10 +36,8 @@
#include
#include
-
-#include
#include
-#include
+#include
#include
#include
@@ -59,12 +57,12 @@ class SSTResponderSubComponent: public SST::SubComponent
gem5::OutgoingRequestBridge* responseReceiver;
gem5::SSTResponderInterface* sstResponder;
- SST::Interfaces::SimpleMem* memoryInterface;
+ SST::Interfaces::StandardMem* memoryInterface;
SST::TimeConverter* timeConverter;
SST::Output* output;
std::queue responseQueue;
- std::vector initRequests;
+ std::vector initRequests;
std::string gem5SimObjectName;
std::string memSize;
@@ -78,7 +76,7 @@ class SSTResponderSubComponent: public SST::SubComponent
void setOutputStream(SST::Output* output_);
void setResponseReceiver(gem5::OutgoingRequestBridge* gem5_bridge);
- void portEventHandler(SST::Interfaces::SimpleMem::Request* request);
+ void portEventHandler(SST::Interfaces::StandardMem::Request* request);
bool blocked();
void setup();
@@ -86,18 +84,18 @@ class SSTResponderSubComponent: public SST::SubComponent
// return true if the SimObject could be found
bool findCorrespondingSimObject(gem5::Root* gem5_root);
- bool handleTimingReq(SST::Interfaces::SimpleMem::Request* request);
+ bool handleTimingReq(SST::Interfaces::StandardMem::Request* request);
void handleRecvRespRetry();
void handleRecvFunctional(gem5::PacketPtr pkt);
- void handleSwapReqResponse(SST::Interfaces::SimpleMem::Request* request);
+ void handleSwapReqResponse(SST::Interfaces::StandardMem::Request* request);
TPacketMap sstRequestIdToPacketMap;
public: // register the component to SST
SST_ELI_REGISTER_SUBCOMPONENT_API(SSTResponderSubComponent);
- SST_ELI_REGISTER_SUBCOMPONENT_DERIVED(
+ SST_ELI_REGISTER_SUBCOMPONENT(
SSTResponderSubComponent,
- "gem5", // SST will look for libgem5.so
+ "gem5", // SST will look for libgem5.so or libgem5.dylib
"gem5Bridge",
SST_ELI_ELEMENT_VERSION(1, 0, 0),
"Initialize gem5 and link SST's ports to gem5's ports",
@@ -106,7 +104,7 @@ class SSTResponderSubComponent: public SST::SubComponent
SST_ELI_DOCUMENT_SUBCOMPONENT_SLOTS(
{"memory", "Interface to the memory subsystem", \
- "SST::Interfaces::SimpleMem"}
+ "SST::Interfaces::StandardMem"}
)
SST_ELI_DOCUMENT_PORTS(
diff --git a/ext/sst/translator.hh b/ext/sst/translator.hh
index 2d8c8b782a..bf6a168d9a 100644
--- a/ext/sst/translator.hh
+++ b/ext/sst/translator.hh
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The Regents of the University of California
+// Copyright (c) 2021-2023 The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -27,87 +27,143 @@
#ifndef __TRANSLATOR_H__
#define __TRANSLATOR_H__
-#include
+#include
#include
-#include
#include
#include
#include
-typedef std::unordered_map TPacketMap;
namespace Translator
{
-inline SST::Interfaces::SimpleMem::Request*
+inline SST::Interfaces::StandardMem::Request*
gem5RequestToSSTRequest(gem5::PacketPtr pkt,
TPacketMap& sst_request_id_to_packet_map)
{
- SST::Interfaces::SimpleMem::Request::Command cmd;
+ // Listing all the different SST Memory commands.
+ enum sst_standard_mem_commands
+ {
+ Read,
+ ReadResp,
+ Write,
+ WriteResp,
+ FlushAddr,
+ FlushResp,
+ ReadLock,
+ WriteUnlock,
+ LoadLink,
+ StoreConditional,
+ MoveData,
+ CustomReq,
+ CustomResp,
+ InvNotify
+
+ };
+ // SST's standard memory class has visitor classes for all the different
+ // types of memory commands. Request class now does not have a command
+ // variable. Instead for different types of request, we now need to
+ // dynamically cast the class object. I'm using an extra variable to map
+ // the type of command for SST.
+ int sst_command_type = -1;
+ // StandardMem only has one cache flush class with an option to flush or
+ // flush and invalidate an address. By default, this is set to true so that
+ // it corresponds to ge,::MemCmd::InvalidateReq
+ bool flush_addr_flag = true;
switch ((gem5::MemCmd::Command)pkt->cmd.toInt()) {
case gem5::MemCmd::HardPFReq:
case gem5::MemCmd::SoftPFReq:
case gem5::MemCmd::SoftPFExReq:
case gem5::MemCmd::LoadLockedReq:
case gem5::MemCmd::ReadExReq:
+ case gem5::MemCmd::ReadCleanReq:
+ case gem5::MemCmd::ReadSharedReq:
case gem5::MemCmd::ReadReq:
case gem5::MemCmd::SwapReq:
- cmd = SST::Interfaces::SimpleMem::Request::Command::Read;
+ sst_command_type = Read;
break;
case gem5::MemCmd::StoreCondReq:
+ case gem5::MemCmd::WritebackDirty:
+ case gem5::MemCmd::WritebackClean:
case gem5::MemCmd::WriteReq:
- cmd = SST::Interfaces::SimpleMem::Request::Command::Write;
+ sst_command_type = Write;
break;
case gem5::MemCmd::CleanInvalidReq:
case gem5::MemCmd::InvalidateReq:
- cmd = SST::Interfaces::SimpleMem::Request::Command::FlushLineInv;
+ sst_command_type = FlushAddr;
break;
case gem5::MemCmd::CleanSharedReq:
- cmd = SST::Interfaces::SimpleMem::Request::Command::FlushLine;
+ sst_command_type = FlushAddr;
+ flush_addr_flag = false;
break;
default:
panic("Unable to convert gem5 packet: %s\n", pkt->cmd.toString());
}
- SST::Interfaces::SimpleMem::Addr addr = pkt->getAddr();
-
- uint8_t* data_ptr = pkt->getPtr();
+ SST::Interfaces::StandardMem::Addr addr = pkt->getAddr();
auto data_size = pkt->getSize();
- std::vector data = std::vector(
- data_ptr, data_ptr + data_size
- );
+ std::vector data;
+ // Need to make sure that the command type is a Write to retrive the data
+ // data_ptr.
+ if (sst_command_type == Write) {
+ uint8_t* data_ptr = pkt->getPtr();
+ data = std::vector(data_ptr, data_ptr + data_size);
- SST::Interfaces::SimpleMem::Request* request = \
- new SST::Interfaces::SimpleMem::Request(
- cmd, addr, data_size, data
- );
+ }
+ // Now convert a sst StandardMem request.
+ SST::Interfaces::StandardMem::Request* request = nullptr;
+ // find the corresponding memory command type.
+ switch(sst_command_type) {
+ case Read:
+ request = new SST::Interfaces::StandardMem::Read(addr, data_size);
+ break;
+ case Write:
+ request =
+ new SST::Interfaces::StandardMem::Write(addr, data_size, data);
+ break;
+ case FlushAddr: {
+ // StandardMem::FlushAddr has a invoking variable called `depth`
+ // which defines the number of cache levels to invalidate. Ideally
+ // this has to be input from the SST config, however in
+ // implementation I'm hardcoding this value to 2.
+ int cache_depth = 2;
+ request =
+ new SST::Interfaces::StandardMem::FlushAddr(
+ addr, data_size, flush_addr_flag, cache_depth);
+ break;
+ }
+ default:
+ panic("Unable to translate command %d to Request class!",
+ sst_command_type);
+ }
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() == \
+ // F_LOCKED is deprecated. Therefore I'm skipping this flag for the
+ // StandardMem request.
+ } else if ((gem5::MemCmd::Command)pkt->cmd.toInt() ==
gem5::MemCmd::StoreCondReq) {
- request->setMemFlags(
- SST::Interfaces::SimpleMem::Request::Flags::F_LLSC);
+ // F_LLSC is deprecated. Therefore I'm skipping this flag for the
+ // StandardMem request.
}
if (pkt->req->isUncacheable()) {
- request->setFlags(
- SST::Interfaces::SimpleMem::Request::Flags::F_NONCACHEABLE);
+ request->setFlag(
+ SST::Interfaces::StandardMem::Request::Flag::F_NONCACHEABLE);
}
if (pkt->needsResponse())
- sst_request_id_to_packet_map[request->id] = pkt;
+ sst_request_id_to_packet_map[request->getID()] = pkt;
return request;
}
inline void
inplaceSSTRequestToGem5PacketPtr(gem5::PacketPtr pkt,
- SST::Interfaces::SimpleMem::Request* request)
+ SST::Interfaces::StandardMem::Request* request)
{
pkt->makeResponse();
@@ -116,8 +172,18 @@ inplaceSSTRequestToGem5PacketPtr(gem5::PacketPtr pkt,
// SC interprets ExtraData == 1 as the store was successful
pkt->req->setExtraData(1);
}
-
- pkt->setData(request->data.data());
+ // If there is data in the request, send it back. Only ReadResp requests
+ // have data associated with it. Other packets does not need to be casted.
+ if (!pkt->isWrite()) {
+ // Need to verify whether the packet is a ReadResp, otherwise the
+ // program will try to incorrectly cast the request object.
+ if (SST::Interfaces::StandardMem::ReadResp* test =
+ dynamic_cast(request)) {
+ pkt->setData(dynamic_cast(
+ request)->data.data()
+ );
+ }
+ }
// Clear out bus delay notifications
pkt->headerDelay = pkt->payloadDelay = 0;