configs,ext: Updated the gem5 SST Bridge to use SST 13.0.0 (#396)
This change updates the gem5 SST Bridge to use SST 13.0.0. Changes are made to replace SimpleMem class to StandardMem class as SimpleMem will be deprecated in SST 14 and above. In addition, the translator.hh is updated to translate more types of gem5 packets. A new parameter `ports` was added on SST's side when invoking the gem5 component which does not require recompiling the gem5 component whenever a new outgoing bridge is added in a gem5 config.
This commit is contained in:
@@ -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.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without
|
# 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.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.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.iobus = IOXBar()
|
||||||
system.bridge = Bridge(delay="50ns")
|
system.bridge = Bridge(delay="50ns")
|
||||||
system.bridge.mem_side_port = system.iobus.cpu_side_ports
|
system.bridge.mem_side_port = system.iobus.cpu_side_ports
|
||||||
@@ -122,6 +115,15 @@ def createHiFivePlatform(system):
|
|||||||
|
|
||||||
system.platform.setNumCores(1)
|
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.attachOnChipIO(system.membus)
|
||||||
system.platform.attachOffChipIO(system.iobus)
|
system.platform.attachOffChipIO(system.iobus)
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# Installing SST
|
# Installing SST
|
||||||
|
|
||||||
The links to download SST source code are available here
|
The links to download SST source code are available at
|
||||||
[http://sst-simulator.org/SSTPages/SSTMainDownloads/].
|
<http://sst-simulator.org/SSTPages/SSTMainDownloads/>.
|
||||||
This guide is using the most recent SST version (11.0.0) as of September 2021.
|
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
|
The following guide assumes `$SST_CORE_HOME` as the location where SST will be
|
||||||
installed.
|
installed.
|
||||||
|
|
||||||
@@ -11,14 +11,14 @@ installed.
|
|||||||
### Downloading the SST-Core Source Code
|
### Downloading the SST-Core Source Code
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
wget https://github.com/sstsimulator/sst-core/releases/download/v11.1.0_Final/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 xf sstcore-11.1.0.tar.gz
|
tar xzf sstcore-13.0.0.tar.gz
|
||||||
```
|
```
|
||||||
|
|
||||||
### Installing SST-Core
|
### Installing SST-Core
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cd sstcore-11.1.0
|
cd sstcore-13.0.0
|
||||||
./configure --prefix=$SST_CORE_HOME --with-python=/usr/bin/python3-config \
|
./configure --prefix=$SST_CORE_HOME --with-python=/usr/bin/python3-config \
|
||||||
--disable-mpi # optional, used when MPI is not available.
|
--disable-mpi # optional, used when MPI is not available.
|
||||||
make all -j$(nproc)
|
make all -j$(nproc)
|
||||||
@@ -36,14 +36,14 @@ export PATH=$SST_CORE_HOME/bin:$PATH
|
|||||||
### Downloading the SST-Elements Source Code
|
### Downloading the SST-Elements Source Code
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
wget https://github.com/sstsimulator/sst-elements/releases/download/v11.1.0_Final/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 xf sstelements-11.1.0.tar.gz
|
tar xzf sstelements-13.0.0.tar.gz
|
||||||
```
|
```
|
||||||
|
|
||||||
### Installing SST-Elements
|
### Installing SST-Elements
|
||||||
|
|
||||||
```sh
|
```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 \
|
./configure --prefix=$SST_CORE_HOME --with-python=/usr/bin/python3-config \
|
||||||
--with-sst-core=$SST_CORE_HOME
|
--with-sst-core=$SST_CORE_HOME
|
||||||
make all -j$(nproc)
|
make all -j$(nproc)
|
||||||
@@ -58,24 +58,36 @@ echo "export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$SST_CORE_HOME/lib/pkgconfig/" >>
|
|||||||
|
|
||||||
### Building gem5 library
|
### 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
|
```sh
|
||||||
scons build/RISCV/libgem5_opt.so -j $(nproc) --without-tcmalloc --duplicate-sources
|
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.
|
**Note:**
|
||||||
`--duplicate-sources` is required as the compilation of SST depends on sources to be present in the "build" directory.
|
* `--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
|
### Compiling the SST integration
|
||||||
|
|
||||||
At the root of gem5 folder,
|
Go to the SST directory in the gem5 repo.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cd ext/sst
|
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
|
### Running an example simulation
|
||||||
|
|
||||||
See `README.md`
|
See `README.md`
|
||||||
|
|||||||
21
ext/sst/Makefile.linux
Normal file
21
ext/sst/Makefile.linux
Normal file
@@ -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
|
||||||
21
ext/sst/Makefile.mac
Normal file
21
ext/sst/Makefile.mac
Normal file
@@ -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
|
||||||
@@ -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.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@@ -70,7 +70,6 @@
|
|||||||
|
|
||||||
#include <sst/core/sst_config.h>
|
#include <sst/core/sst_config.h>
|
||||||
#include <sst/core/componentInfo.h>
|
#include <sst/core/componentInfo.h>
|
||||||
#include <sst/core/interfaces/simpleMem.h>
|
|
||||||
#include <sst/elements/memHierarchy/memEvent.h>
|
#include <sst/elements/memHierarchy/memEvent.h>
|
||||||
#include <sst/elements/memHierarchy/memTypes.h>
|
#include <sst/elements/memHierarchy/memTypes.h>
|
||||||
#include <sst/elements/memHierarchy/util.h>
|
#include <sst/elements/memHierarchy/util.h>
|
||||||
@@ -169,16 +168,29 @@ gem5Component::gem5Component(SST::ComponentId_t id, SST::Params& params):
|
|||||||
registerAsPrimaryComponent();
|
registerAsPrimaryComponent();
|
||||||
primaryComponentDoNotEndSim();
|
primaryComponentDoNotEndSim();
|
||||||
|
|
||||||
systemPort = \
|
// We need to add another parameter when invoking gem5 scripts from SST to
|
||||||
loadUserSubComponent<SSTResponderSubComponent>("system_port",0);
|
// keep a track of all the OutgoingBridges. This will allow to add or
|
||||||
cachePort = \
|
// remove OutgoingBridges from gem5 configs without the need to recompile
|
||||||
loadUserSubComponent<SSTResponderSubComponent>("cache_port", 0);
|
// the ext/sst source everytime.
|
||||||
|
std::string ports = params.find<std::string>("ports", "");
|
||||||
systemPort->setTimeConverter(timeConverter);
|
if (ports.empty()) {
|
||||||
systemPort->setOutputStream(&(output));
|
output.fatal(
|
||||||
cachePort->setTimeConverter(timeConverter);
|
CALL_INFO, -1, "Component %s must have a 'ports' parameter.\n",
|
||||||
cachePort->setOutputStream(&(output));
|
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<SSTResponderSubComponent>(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()
|
gem5Component::~gem5Component()
|
||||||
@@ -216,8 +228,9 @@ gem5Component::init(unsigned phase)
|
|||||||
|
|
||||||
// find the corresponding SimObject for each SSTResponderSubComponent
|
// find the corresponding SimObject for each SSTResponderSubComponent
|
||||||
gem5::Root* gem5_root = gem5::Root::root();
|
gem5::Root* gem5_root = gem5::Root::root();
|
||||||
systemPort->findCorrespondingSimObject(gem5_root);
|
for (auto &port : sstPorts) {
|
||||||
cachePort->findCorrespondingSimObject(gem5_root);
|
port->findCorrespondingSimObject(gem5_root);
|
||||||
|
}
|
||||||
|
|
||||||
// initialize the gem5 event queue
|
// initialize the gem5 event queue
|
||||||
if (!(threadInitialized)) {
|
if (!(threadInitialized)) {
|
||||||
@@ -230,17 +243,18 @@ gem5Component::init(unsigned phase)
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
for (auto &port : sstPorts) {
|
||||||
systemPort->init(phase);
|
port->init(phase);
|
||||||
cachePort->init(phase);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gem5Component::setup()
|
gem5Component::setup()
|
||||||
{
|
{
|
||||||
output.verbose(CALL_INFO, 1, 0, "Component is being setup.\n");
|
output.verbose(CALL_INFO, 1, 0, "Component is being setup.\n");
|
||||||
systemPort->setup();
|
for (auto &port : sstPorts) {
|
||||||
cachePort->setup();
|
port->setup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -427,3 +441,16 @@ gem5Component::splitCommandArgs(std::string &cmd, std::vector<char*> &args)
|
|||||||
for (auto part: parsed_args)
|
for (auto part: parsed_args)
|
||||||
args.push_back(strdup(part.c_str()));
|
args.push_back(strdup(part.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gem5Component::splitPortNames(std::string port_names)
|
||||||
|
{
|
||||||
|
std::vector<std::string> parsed_args = tokenizeString(
|
||||||
|
port_names, {'\\', ' ', '\'', '\"'}
|
||||||
|
);
|
||||||
|
sstPortCount = 0;
|
||||||
|
for (auto part: parsed_args) {
|
||||||
|
sstPortNames.push_back(strdup(part.c_str()));
|
||||||
|
sstPortCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@@ -79,7 +79,6 @@
|
|||||||
#include <sst/core/sst_config.h>
|
#include <sst/core/sst_config.h>
|
||||||
#include <sst/core/component.h>
|
#include <sst/core/component.h>
|
||||||
|
|
||||||
#include <sst/core/simulation.h>
|
|
||||||
#include <sst/core/interfaces/stringEvent.h>
|
#include <sst/core/interfaces/stringEvent.h>
|
||||||
#include <sst/core/interfaces/simpleMem.h>
|
#include <sst/core/interfaces/simpleMem.h>
|
||||||
|
|
||||||
@@ -108,15 +107,20 @@ class gem5Component: public SST::Component
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
SST::Output output;
|
SST::Output output;
|
||||||
SSTResponderSubComponent* systemPort;
|
|
||||||
SSTResponderSubComponent* cachePort;
|
|
||||||
uint64_t clocksProcessed;
|
uint64_t clocksProcessed;
|
||||||
SST::TimeConverter* timeConverter;
|
SST::TimeConverter* timeConverter;
|
||||||
gem5::GlobalSimLoopExitEvent *simulateLimitEvent;
|
gem5::GlobalSimLoopExitEvent *simulateLimitEvent;
|
||||||
std::vector<char*> args;
|
std::vector<char*> 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<SSTResponderSubComponent*> sstPorts;
|
||||||
|
std::vector<std::string> sstPortNames;
|
||||||
|
int sstPortCount;
|
||||||
|
|
||||||
void initPython(int argc, char **argv);
|
void initPython(int argc, char **argv);
|
||||||
void splitCommandArgs(std::string &cmd, std::vector<char*> &args);
|
void splitCommandArgs(std::string &cmd, std::vector<char*> &args);
|
||||||
|
void splitPortNames(std::string port_names);
|
||||||
|
|
||||||
bool threadInitialized;
|
bool threadInitialized;
|
||||||
|
|
||||||
@@ -139,6 +143,7 @@ class gem5Component: public SST::Component
|
|||||||
)
|
)
|
||||||
|
|
||||||
SST_ELI_DOCUMENT_SUBCOMPONENT_SLOTS(
|
SST_ELI_DOCUMENT_SUBCOMPONENT_SLOTS(
|
||||||
|
// These are the generally expected ports.
|
||||||
{"system_port", "Connection to gem5 system_port", "gem5.gem5Bridge"},
|
{"system_port", "Connection to gem5 system_port", "gem5.gem5Bridge"},
|
||||||
{"cache_port", "Connection to gem5 CPU", "gem5.gem5Bridge"}
|
{"cache_port", "Connection to gem5 CPU", "gem5.gem5Bridge"}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
# unmodified and in its entirety in all distributions of the software,
|
# unmodified and in its entirety in all distributions of the software,
|
||||||
# modified or unmodified, in source code or in binary form.
|
# 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.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without
|
# Redistribution and use in source and binary forms, with or without
|
||||||
@@ -46,9 +46,10 @@ cache_link_latency = "1ps"
|
|||||||
|
|
||||||
kernel = "vmlinux_exit.arm64"
|
kernel = "vmlinux_exit.arm64"
|
||||||
cpu_clock_rate = "3GHz"
|
cpu_clock_rate = "3GHz"
|
||||||
# gem5 will send requests to physical addresses of range [0x80000000, inf) to memory
|
# gem5 will send requests to physical addresses of range [0x80000000, inf) to
|
||||||
# currently, we do not subtract 0x80000000 from the request's address to get the "real" address
|
# memory currently, we do not subtract 0x80000000 from the request's address to
|
||||||
# so, the mem_size would always be 2GiB larger than the desired memory size
|
# get the "real" address so, the mem_size would always be 2GiB larger than the
|
||||||
|
# desired memory size
|
||||||
memory_size_gem5 = "4GiB"
|
memory_size_gem5 = "4GiB"
|
||||||
memory_size_sst = "16GiB"
|
memory_size_sst = "16GiB"
|
||||||
addr_range_end = UnitAlgebra(memory_size_sst).getRoundedValue()
|
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} \
|
--cpu-clock-rate {cpu_clock_rate} \
|
||||||
--memory-size {memory_size_gem5}"
|
--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 = {
|
cpu_params = {
|
||||||
"frequency": cpu_clock_rate,
|
"frequency": cpu_clock_rate,
|
||||||
"cmd": gem5_command,
|
"cmd": gem5_command,
|
||||||
|
"ports" : " ".join(port_list),
|
||||||
|
"debug_flags" : ""
|
||||||
}
|
}
|
||||||
|
|
||||||
gem5_node = sst.Component("gem5_node", "gem5.gem5Component")
|
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 = sst.Component("cache_bus", "memHierarchy.Bus")
|
||||||
cache_bus.addParams( { "bus_frequency" : cpu_clock_rate } )
|
cache_bus.addParams( { "bus_frequency" : cpu_clock_rate } )
|
||||||
|
# for initialization
|
||||||
system_port = gem5_node.setSubComponent("system_port", "gem5.gem5Bridge", 0) # for initialization
|
system_port = gem5_node.setSubComponent("system_port", "gem5.gem5Bridge", 0)
|
||||||
system_port.addParams({
|
system_port.addParams({
|
||||||
"response_receiver_name": "system.system_outgoing_bridge",
|
"response_receiver_name": sst_ports["system_port"],
|
||||||
"mem_size": memory_size_sst
|
"mem_size": memory_size_sst
|
||||||
})
|
})
|
||||||
|
# SST -> gem5
|
||||||
cache_port = gem5_node.setSubComponent("cache_port", "gem5.gem5Bridge", 0) # SST -> gem5
|
cache_port = gem5_node.setSubComponent("cache_port", "gem5.gem5Bridge", 0)
|
||||||
cache_port.addParams({
|
cache_port.addParams({
|
||||||
"response_receiver_name": "system.memory_outgoing_bridge",
|
"response_receiver_name": sst_ports["cache_port"],
|
||||||
"mem_size": memory_size_sst
|
"mem_size": memory_size_sst
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -98,11 +112,12 @@ l1_cache.addParams(l1_params)
|
|||||||
|
|
||||||
# Memory
|
# Memory
|
||||||
memctrl = sst.Component("memory", "memHierarchy.MemController")
|
memctrl = sst.Component("memory", "memHierarchy.MemController")
|
||||||
|
# `addr_range_end` should be changed accordingly to memory_size_sst
|
||||||
memctrl.addParams({
|
memctrl.addParams({
|
||||||
"debug" : "0",
|
"debug" : "0",
|
||||||
"clock" : "1GHz",
|
"clock" : "1GHz",
|
||||||
"request_width" : "64",
|
"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 = memctrl.setSubComponent("backend", "memHierarchy.simpleMem")
|
||||||
memory.addParams({
|
memory.addParams({
|
||||||
|
|||||||
@@ -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.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without
|
# Redistribution and use in source and binary forms, with or without
|
||||||
@@ -34,9 +34,10 @@ cache_link_latency = "1ps"
|
|||||||
|
|
||||||
bbl = "riscv-boot-exit-nodisk"
|
bbl = "riscv-boot-exit-nodisk"
|
||||||
cpu_clock_rate = "3GHz"
|
cpu_clock_rate = "3GHz"
|
||||||
# gem5 will send requests to physical addresses of range [0x80000000, inf) to memory
|
# gem5 will send requests to physical addresses of range [0x80000000, inf) to
|
||||||
# currently, we do not subtract 0x80000000 from the request's address to get the "real" address
|
# memory currently, we do not subtract 0x80000000 from the request's address to
|
||||||
# so, the mem_size would always be 2GiB larger than the desired memory size
|
# get the "real" address so, the mem_size would always be 2GiB larger than the
|
||||||
|
# desired memory size
|
||||||
memory_size_gem5 = "4GiB"
|
memory_size_gem5 = "4GiB"
|
||||||
memory_size_sst = "6GiB"
|
memory_size_sst = "6GiB"
|
||||||
addr_range_end = UnitAlgebra(memory_size_sst).getRoundedValue()
|
addr_range_end = UnitAlgebra(memory_size_sst).getRoundedValue()
|
||||||
@@ -52,10 +53,24 @@ l1_params = {
|
|||||||
"L1" : "1",
|
"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 = {
|
cpu_params = {
|
||||||
"frequency": cpu_clock_rate,
|
"frequency": cpu_clock_rate,
|
||||||
"cmd": " ../../configs/example/sst/riscv_fs.py --cpu-clock-rate {} --memory-size {}".format(cpu_clock_rate, memory_size_gem5),
|
"cmd": " ../../configs/example/sst/riscv_fs.py"
|
||||||
"debug_flags": ""
|
+ 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")
|
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 = sst.Component("cache_bus", "memHierarchy.Bus")
|
||||||
cache_bus.addParams( { "bus_frequency" : cpu_clock_rate } )
|
cache_bus.addParams( { "bus_frequency" : cpu_clock_rate } )
|
||||||
|
|
||||||
system_port = gem5_node.setSubComponent("system_port", "gem5.gem5Bridge", 0) # for initialization
|
# for initialization
|
||||||
system_port.addParams({ "response_receiver_name": "system.system_outgoing_bridge"}) # tell the SubComponent the name of the corresponding SimObject
|
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
|
# SST -> gem5
|
||||||
cache_port.addParams({ "response_receiver_name": "system.memory_outgoing_bridge"})
|
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
|
||||||
l1_cache = sst.Component("l1_cache", "memHierarchy.Cache")
|
l1_cache = sst.Component("l1_cache", "memHierarchy.Cache")
|
||||||
@@ -76,11 +94,12 @@ l1_cache.addParams(l1_params)
|
|||||||
|
|
||||||
# Memory
|
# Memory
|
||||||
memctrl = sst.Component("memory", "memHierarchy.MemController")
|
memctrl = sst.Component("memory", "memHierarchy.MemController")
|
||||||
|
# `addr_range_end` should be changed accordingly to memory_size_sst
|
||||||
memctrl.addParams({
|
memctrl.addParams({
|
||||||
"debug" : "0",
|
"debug" : "0",
|
||||||
"clock" : "1GHz",
|
"clock" : "1GHz",
|
||||||
"request_width" : "64",
|
"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 = memctrl.setSubComponent("backend", "memHierarchy.simpleMem")
|
||||||
memory.addParams({
|
memory.addParams({
|
||||||
|
|||||||
@@ -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.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@@ -35,9 +35,8 @@
|
|||||||
#include <sst/core/sst_config.h>
|
#include <sst/core/sst_config.h>
|
||||||
#include <sst/core/component.h>
|
#include <sst/core/component.h>
|
||||||
|
|
||||||
#include <sst/core/simulation.h>
|
|
||||||
#include <sst/core/interfaces/stringEvent.h>
|
#include <sst/core/interfaces/stringEvent.h>
|
||||||
#include <sst/core/interfaces/simpleMem.h>
|
#include <sst/core/interfaces/stdMem.h>
|
||||||
|
|
||||||
#include <sst/core/eli/elementinfo.h>
|
#include <sst/core/eli/elementinfo.h>
|
||||||
#include <sst/core/link.h>
|
#include <sst/core/link.h>
|
||||||
|
|||||||
@@ -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.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// 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
|
// SHARE_PORTS means the interface can use our port as if it were its own
|
||||||
// INSERT_STATS means the interface will inherit our statistic
|
// INSERT_STATS means the interface will inherit our statistic
|
||||||
// configuration (e.g., if ours are enabled, the interface’s will be too)
|
// configuration (e.g., if ours are enabled, the interface’s will be too)
|
||||||
memoryInterface = \
|
memoryInterface = loadAnonymousSubComponent<SST::Interfaces::StandardMem>(
|
||||||
loadAnonymousSubComponent<SST::Interfaces::SimpleMem>(
|
"memHierarchy.standardInterface", "memory", 0,
|
||||||
"memHierarchy.memInterface", "memory", 0,
|
SST::ComponentInfo::SHARE_PORTS | SST::ComponentInfo::INSERT_STATS,
|
||||||
SST::ComponentInfo::SHARE_PORTS | SST::ComponentInfo::INSERT_STATS,
|
interface_params, timeConverter,
|
||||||
interface_params, timeConverter,
|
new SST::Interfaces::StandardMem::Handler<SSTResponderSubComponent>(
|
||||||
new SST::Interfaces::SimpleMem::Handler<SSTResponderSubComponent>(
|
this, &SSTResponderSubComponent::portEventHandler)
|
||||||
this, &SSTResponderSubComponent::portEventHandler)
|
|
||||||
);
|
);
|
||||||
assert(memoryInterface != NULL);
|
assert(memoryInterface != NULL);
|
||||||
}
|
}
|
||||||
@@ -91,9 +90,9 @@ SSTResponderSubComponent::setResponseReceiver(
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
SSTResponderSubComponent::handleTimingReq(
|
SSTResponderSubComponent::handleTimingReq(
|
||||||
SST::Interfaces::SimpleMem::Request* request)
|
SST::Interfaces::StandardMem::Request* request)
|
||||||
{
|
{
|
||||||
memoryInterface->sendRequest(request);
|
memoryInterface->send(request);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,12 +103,10 @@ SSTResponderSubComponent::init(unsigned phase)
|
|||||||
for (auto p: responseReceiver->getInitData()) {
|
for (auto p: responseReceiver->getInitData()) {
|
||||||
gem5::Addr addr = p.first;
|
gem5::Addr addr = p.first;
|
||||||
std::vector<uint8_t> data = p.second;
|
std::vector<uint8_t> data = p.second;
|
||||||
SST::Interfaces::SimpleMem::Request* request = \
|
SST::Interfaces::StandardMem::Request* request = \
|
||||||
new SST::Interfaces::SimpleMem::Request(
|
new SST::Interfaces::StandardMem::Write(
|
||||||
SST::Interfaces::SimpleMem::Request::Command::Write, addr,
|
addr, data.size(), data);
|
||||||
data.size(), data
|
memoryInterface->sendUntimedData(request);
|
||||||
);
|
|
||||||
memoryInterface->sendInitData(request);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
memoryInterface->init(phase);
|
memoryInterface->init(phase);
|
||||||
@@ -132,20 +129,24 @@ SSTResponderSubComponent::findCorrespondingSimObject(gem5::Root* gem5_root)
|
|||||||
|
|
||||||
void
|
void
|
||||||
SSTResponderSubComponent::handleSwapReqResponse(
|
SSTResponderSubComponent::handleSwapReqResponse(
|
||||||
SST::Interfaces::SimpleMem::Request* request)
|
SST::Interfaces::StandardMem::Request* request)
|
||||||
{
|
{
|
||||||
// get the data, then,
|
// get the data, then,
|
||||||
// 1. send a response to gem5 with the original data
|
// 1. send a response to gem5 with the original data
|
||||||
// 2. send a write to memory with atomic op applied
|
// 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);
|
TPacketMap::iterator it = sstRequestIdToPacketMap.find(request_id);
|
||||||
assert(it != sstRequestIdToPacketMap.end());
|
assert(it != sstRequestIdToPacketMap.end());
|
||||||
std::vector<uint8_t> data = request->data;
|
std::vector<uint8_t> data = \
|
||||||
|
dynamic_cast<SST::Interfaces::StandardMem::ReadResp*>(request)->data;
|
||||||
|
|
||||||
// step 1
|
// step 1
|
||||||
gem5::PacketPtr pkt = it->second;
|
gem5::PacketPtr pkt = it->second;
|
||||||
pkt->setData(request->data.data());
|
pkt->setData(
|
||||||
|
dynamic_cast<SST::Interfaces::StandardMem::ReadResp*>(
|
||||||
|
request)->data.data()
|
||||||
|
);
|
||||||
pkt->makeAtomicResponse();
|
pkt->makeAtomicResponse();
|
||||||
pkt->headerDelay = pkt->payloadDelay = 0;
|
pkt->headerDelay = pkt->payloadDelay = 0;
|
||||||
if (blocked() || !responseReceiver->sendTimingResp(pkt))
|
if (blocked() || !responseReceiver->sendTimingResp(pkt))
|
||||||
@@ -153,27 +154,29 @@ SSTResponderSubComponent::handleSwapReqResponse(
|
|||||||
|
|
||||||
// step 2
|
// step 2
|
||||||
(*(pkt->getAtomicOp()))(data.data()); // apply the atomic op
|
(*(pkt->getAtomicOp()))(data.data()); // apply the atomic op
|
||||||
SST::Interfaces::SimpleMem::Request::Command cmd = \
|
// This is a Write. Need to use the Write visitor class. But the original
|
||||||
SST::Interfaces::SimpleMem::Request::Command::Write;
|
// request is a read response. Therefore, we need to find the address and
|
||||||
SST::Interfaces::SimpleMem::Addr addr = request->addr;
|
// the data size and then call Write.
|
||||||
|
SST::Interfaces::StandardMem::Addr addr = \
|
||||||
|
dynamic_cast<SST::Interfaces::StandardMem::ReadResp*>(request)->pAddr;
|
||||||
auto data_size = data.size();
|
auto data_size = data.size();
|
||||||
SST::Interfaces::SimpleMem::Request* write_request = \
|
// Create the Write request here.
|
||||||
new SST::Interfaces::SimpleMem::Request(
|
SST::Interfaces::StandardMem::Request* write_request = \
|
||||||
cmd, addr, data_size, data
|
new SST::Interfaces::StandardMem::Write(addr, data_size, data);
|
||||||
);
|
// F_LOCKED flag in SimpleMem was changed to ReadLock and WriteUnlock
|
||||||
write_request->setMemFlags(
|
// visitor classes. This has to be addressed in the future. The boot test
|
||||||
SST::Interfaces::SimpleMem::Request::Flags::F_LOCKED);
|
// works without using ReadLock and WriteUnlock classes.
|
||||||
memoryInterface->sendRequest(write_request);
|
memoryInterface->send(write_request);
|
||||||
|
|
||||||
delete request;
|
delete request;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SSTResponderSubComponent::portEventHandler(
|
SSTResponderSubComponent::portEventHandler(
|
||||||
SST::Interfaces::SimpleMem::Request* request)
|
SST::Interfaces::StandardMem::Request* request)
|
||||||
{
|
{
|
||||||
// Expect to handle an SST response
|
// 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);
|
TPacketMap::iterator it = sstRequestIdToPacketMap.find(request_id);
|
||||||
|
|
||||||
@@ -193,19 +196,27 @@ SSTResponderSubComponent::portEventHandler(
|
|||||||
|
|
||||||
Translator::inplaceSSTRequestToGem5PacketPtr(pkt, request);
|
Translator::inplaceSSTRequestToGem5PacketPtr(pkt, request);
|
||||||
|
|
||||||
if (blocked() || !(responseReceiver->sendTimingResp(pkt)))
|
if (blocked() || !(responseReceiver->sendTimingResp(pkt))) {
|
||||||
responseQueue.push(pkt);
|
responseQueue.push(pkt);
|
||||||
} else { // we can handle unexpected invalidates, but nothing else.
|
}
|
||||||
SST::Interfaces::SimpleMem::Request::Command cmd = request->cmd;
|
} else {
|
||||||
if (cmd == SST::Interfaces::SimpleMem::Request::Command::WriteResp)
|
// we can handle unexpected invalidates, but nothing else.
|
||||||
|
if (SST::Interfaces::StandardMem::Read* test =
|
||||||
|
dynamic_cast<SST::Interfaces::StandardMem::Read*>(request)) {
|
||||||
return;
|
return;
|
||||||
assert(cmd == SST::Interfaces::SimpleMem::Request::Command::Inv);
|
}
|
||||||
|
else if (SST::Interfaces::StandardMem::WriteResp* test =
|
||||||
// make Req/Pkt for Snoop/no response needed
|
dynamic_cast<SST::Interfaces::StandardMem::WriteResp*>(
|
||||||
|
request)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// for Snoop/no response needed
|
||||||
// presently no consideration for masterId, packet type, flags...
|
// presently no consideration for masterId, packet type, flags...
|
||||||
gem5::RequestPtr req = std::make_shared<gem5::Request>(
|
gem5::RequestPtr req = std::make_shared<gem5::Request>(
|
||||||
request->addr, request->size, 0, 0
|
dynamic_cast<SST::Interfaces::StandardMem::FlushAddr*>(
|
||||||
);
|
request)->pAddr,
|
||||||
|
dynamic_cast<SST::Interfaces::StandardMem::FlushAddr*>(
|
||||||
|
request)->size, 0, 0);
|
||||||
|
|
||||||
gem5::PacketPtr pkt = new gem5::Packet(
|
gem5::PacketPtr pkt = new gem5::Packet(
|
||||||
req, gem5::MemCmd::InvalidateReq);
|
req, gem5::MemCmd::InvalidateReq);
|
||||||
|
|||||||
@@ -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.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@@ -36,10 +36,8 @@
|
|||||||
|
|
||||||
#include <sst/core/sst_config.h>
|
#include <sst/core/sst_config.h>
|
||||||
#include <sst/core/component.h>
|
#include <sst/core/component.h>
|
||||||
|
|
||||||
#include <sst/core/simulation.h>
|
|
||||||
#include <sst/core/interfaces/stringEvent.h>
|
#include <sst/core/interfaces/stringEvent.h>
|
||||||
#include <sst/core/interfaces/simpleMem.h>
|
#include <sst/core/interfaces/stdMem.h>
|
||||||
|
|
||||||
#include <sst/core/eli/elementinfo.h>
|
#include <sst/core/eli/elementinfo.h>
|
||||||
#include <sst/core/link.h>
|
#include <sst/core/link.h>
|
||||||
@@ -59,12 +57,12 @@ class SSTResponderSubComponent: public SST::SubComponent
|
|||||||
gem5::OutgoingRequestBridge* responseReceiver;
|
gem5::OutgoingRequestBridge* responseReceiver;
|
||||||
gem5::SSTResponderInterface* sstResponder;
|
gem5::SSTResponderInterface* sstResponder;
|
||||||
|
|
||||||
SST::Interfaces::SimpleMem* memoryInterface;
|
SST::Interfaces::StandardMem* memoryInterface;
|
||||||
SST::TimeConverter* timeConverter;
|
SST::TimeConverter* timeConverter;
|
||||||
SST::Output* output;
|
SST::Output* output;
|
||||||
std::queue<gem5::PacketPtr> responseQueue;
|
std::queue<gem5::PacketPtr> responseQueue;
|
||||||
|
|
||||||
std::vector<SST::Interfaces::SimpleMem::Request*> initRequests;
|
std::vector<SST::Interfaces::StandardMem::Request*> initRequests;
|
||||||
|
|
||||||
std::string gem5SimObjectName;
|
std::string gem5SimObjectName;
|
||||||
std::string memSize;
|
std::string memSize;
|
||||||
@@ -78,7 +76,7 @@ class SSTResponderSubComponent: public SST::SubComponent
|
|||||||
void setOutputStream(SST::Output* output_);
|
void setOutputStream(SST::Output* output_);
|
||||||
|
|
||||||
void setResponseReceiver(gem5::OutgoingRequestBridge* gem5_bridge);
|
void setResponseReceiver(gem5::OutgoingRequestBridge* gem5_bridge);
|
||||||
void portEventHandler(SST::Interfaces::SimpleMem::Request* request);
|
void portEventHandler(SST::Interfaces::StandardMem::Request* request);
|
||||||
|
|
||||||
bool blocked();
|
bool blocked();
|
||||||
void setup();
|
void setup();
|
||||||
@@ -86,18 +84,18 @@ class SSTResponderSubComponent: public SST::SubComponent
|
|||||||
// return true if the SimObject could be found
|
// return true if the SimObject could be found
|
||||||
bool findCorrespondingSimObject(gem5::Root* gem5_root);
|
bool findCorrespondingSimObject(gem5::Root* gem5_root);
|
||||||
|
|
||||||
bool handleTimingReq(SST::Interfaces::SimpleMem::Request* request);
|
bool handleTimingReq(SST::Interfaces::StandardMem::Request* request);
|
||||||
void handleRecvRespRetry();
|
void handleRecvRespRetry();
|
||||||
void handleRecvFunctional(gem5::PacketPtr pkt);
|
void handleRecvFunctional(gem5::PacketPtr pkt);
|
||||||
void handleSwapReqResponse(SST::Interfaces::SimpleMem::Request* request);
|
void handleSwapReqResponse(SST::Interfaces::StandardMem::Request* request);
|
||||||
|
|
||||||
TPacketMap sstRequestIdToPacketMap;
|
TPacketMap sstRequestIdToPacketMap;
|
||||||
|
|
||||||
public: // register the component to SST
|
public: // register the component to SST
|
||||||
SST_ELI_REGISTER_SUBCOMPONENT_API(SSTResponderSubComponent);
|
SST_ELI_REGISTER_SUBCOMPONENT_API(SSTResponderSubComponent);
|
||||||
SST_ELI_REGISTER_SUBCOMPONENT_DERIVED(
|
SST_ELI_REGISTER_SUBCOMPONENT(
|
||||||
SSTResponderSubComponent,
|
SSTResponderSubComponent,
|
||||||
"gem5", // SST will look for libgem5.so
|
"gem5", // SST will look for libgem5.so or libgem5.dylib
|
||||||
"gem5Bridge",
|
"gem5Bridge",
|
||||||
SST_ELI_ELEMENT_VERSION(1, 0, 0),
|
SST_ELI_ELEMENT_VERSION(1, 0, 0),
|
||||||
"Initialize gem5 and link SST's ports to gem5's ports",
|
"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(
|
SST_ELI_DOCUMENT_SUBCOMPONENT_SLOTS(
|
||||||
{"memory", "Interface to the memory subsystem", \
|
{"memory", "Interface to the memory subsystem", \
|
||||||
"SST::Interfaces::SimpleMem"}
|
"SST::Interfaces::StandardMem"}
|
||||||
)
|
)
|
||||||
|
|
||||||
SST_ELI_DOCUMENT_PORTS(
|
SST_ELI_DOCUMENT_PORTS(
|
||||||
|
|||||||
@@ -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.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@@ -27,87 +27,143 @@
|
|||||||
#ifndef __TRANSLATOR_H__
|
#ifndef __TRANSLATOR_H__
|
||||||
#define __TRANSLATOR_H__
|
#define __TRANSLATOR_H__
|
||||||
|
|
||||||
#include <sst/core/simulation.h>
|
#include <sst/core/interfaces/stdMem.h>
|
||||||
#include <sst/core/interfaces/stringEvent.h>
|
#include <sst/core/interfaces/stringEvent.h>
|
||||||
#include <sst/core/interfaces/simpleMem.h>
|
|
||||||
#include <sst/elements/memHierarchy/memEvent.h>
|
#include <sst/elements/memHierarchy/memEvent.h>
|
||||||
#include <sst/elements/memHierarchy/memTypes.h>
|
#include <sst/elements/memHierarchy/memTypes.h>
|
||||||
#include <sst/elements/memHierarchy/util.h>
|
#include <sst/elements/memHierarchy/util.h>
|
||||||
|
|
||||||
typedef std::unordered_map<SST::Interfaces::SimpleMem::Request::id_t,
|
typedef std::unordered_map<SST::Interfaces::StandardMem::Request::id_t,
|
||||||
gem5::PacketPtr> TPacketMap;
|
gem5::PacketPtr> TPacketMap;
|
||||||
|
|
||||||
namespace Translator
|
namespace Translator
|
||||||
{
|
{
|
||||||
|
|
||||||
inline SST::Interfaces::SimpleMem::Request*
|
inline SST::Interfaces::StandardMem::Request*
|
||||||
gem5RequestToSSTRequest(gem5::PacketPtr pkt,
|
gem5RequestToSSTRequest(gem5::PacketPtr pkt,
|
||||||
TPacketMap& sst_request_id_to_packet_map)
|
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()) {
|
switch ((gem5::MemCmd::Command)pkt->cmd.toInt()) {
|
||||||
case gem5::MemCmd::HardPFReq:
|
case gem5::MemCmd::HardPFReq:
|
||||||
case gem5::MemCmd::SoftPFReq:
|
case gem5::MemCmd::SoftPFReq:
|
||||||
case gem5::MemCmd::SoftPFExReq:
|
case gem5::MemCmd::SoftPFExReq:
|
||||||
case gem5::MemCmd::LoadLockedReq:
|
case gem5::MemCmd::LoadLockedReq:
|
||||||
case gem5::MemCmd::ReadExReq:
|
case gem5::MemCmd::ReadExReq:
|
||||||
|
case gem5::MemCmd::ReadCleanReq:
|
||||||
|
case gem5::MemCmd::ReadSharedReq:
|
||||||
case gem5::MemCmd::ReadReq:
|
case gem5::MemCmd::ReadReq:
|
||||||
case gem5::MemCmd::SwapReq:
|
case gem5::MemCmd::SwapReq:
|
||||||
cmd = SST::Interfaces::SimpleMem::Request::Command::Read;
|
sst_command_type = Read;
|
||||||
break;
|
break;
|
||||||
case gem5::MemCmd::StoreCondReq:
|
case gem5::MemCmd::StoreCondReq:
|
||||||
|
case gem5::MemCmd::WritebackDirty:
|
||||||
|
case gem5::MemCmd::WritebackClean:
|
||||||
case gem5::MemCmd::WriteReq:
|
case gem5::MemCmd::WriteReq:
|
||||||
cmd = SST::Interfaces::SimpleMem::Request::Command::Write;
|
sst_command_type = Write;
|
||||||
break;
|
break;
|
||||||
case gem5::MemCmd::CleanInvalidReq:
|
case gem5::MemCmd::CleanInvalidReq:
|
||||||
case gem5::MemCmd::InvalidateReq:
|
case gem5::MemCmd::InvalidateReq:
|
||||||
cmd = SST::Interfaces::SimpleMem::Request::Command::FlushLineInv;
|
sst_command_type = FlushAddr;
|
||||||
break;
|
break;
|
||||||
case gem5::MemCmd::CleanSharedReq:
|
case gem5::MemCmd::CleanSharedReq:
|
||||||
cmd = SST::Interfaces::SimpleMem::Request::Command::FlushLine;
|
sst_command_type = FlushAddr;
|
||||||
|
flush_addr_flag = false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unable to convert gem5 packet: %s\n", pkt->cmd.toString());
|
panic("Unable to convert gem5 packet: %s\n", pkt->cmd.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
SST::Interfaces::SimpleMem::Addr addr = pkt->getAddr();
|
SST::Interfaces::StandardMem::Addr addr = pkt->getAddr();
|
||||||
|
|
||||||
uint8_t* data_ptr = pkt->getPtr<uint8_t>();
|
|
||||||
auto data_size = pkt->getSize();
|
auto data_size = pkt->getSize();
|
||||||
std::vector<uint8_t> data = std::vector<uint8_t>(
|
std::vector<uint8_t> data;
|
||||||
data_ptr, data_ptr + data_size
|
// 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<uint8_t>();
|
||||||
|
data = std::vector<uint8_t>(data_ptr, data_ptr + data_size);
|
||||||
|
|
||||||
SST::Interfaces::SimpleMem::Request* request = \
|
}
|
||||||
new SST::Interfaces::SimpleMem::Request(
|
// Now convert a sst StandardMem request.
|
||||||
cmd, addr, data_size, data
|
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
|
if ((gem5::MemCmd::Command)pkt->cmd.toInt() == gem5::MemCmd::LoadLockedReq
|
||||||
|| (gem5::MemCmd::Command)pkt->cmd.toInt() == gem5::MemCmd::SwapReq
|
|| (gem5::MemCmd::Command)pkt->cmd.toInt() == gem5::MemCmd::SwapReq
|
||||||
|| pkt->req->isLockedRMW()) {
|
|| pkt->req->isLockedRMW()) {
|
||||||
request->setMemFlags(
|
// F_LOCKED is deprecated. Therefore I'm skipping this flag for the
|
||||||
SST::Interfaces::SimpleMem::Request::Flags::F_LOCKED);
|
// StandardMem request.
|
||||||
} else if ((gem5::MemCmd::Command)pkt->cmd.toInt() == \
|
} else if ((gem5::MemCmd::Command)pkt->cmd.toInt() ==
|
||||||
gem5::MemCmd::StoreCondReq) {
|
gem5::MemCmd::StoreCondReq) {
|
||||||
request->setMemFlags(
|
// F_LLSC is deprecated. Therefore I'm skipping this flag for the
|
||||||
SST::Interfaces::SimpleMem::Request::Flags::F_LLSC);
|
// StandardMem request.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pkt->req->isUncacheable()) {
|
if (pkt->req->isUncacheable()) {
|
||||||
request->setFlags(
|
request->setFlag(
|
||||||
SST::Interfaces::SimpleMem::Request::Flags::F_NONCACHEABLE);
|
SST::Interfaces::StandardMem::Request::Flag::F_NONCACHEABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pkt->needsResponse())
|
if (pkt->needsResponse())
|
||||||
sst_request_id_to_packet_map[request->id] = pkt;
|
sst_request_id_to_packet_map[request->getID()] = pkt;
|
||||||
|
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
inplaceSSTRequestToGem5PacketPtr(gem5::PacketPtr pkt,
|
inplaceSSTRequestToGem5PacketPtr(gem5::PacketPtr pkt,
|
||||||
SST::Interfaces::SimpleMem::Request* request)
|
SST::Interfaces::StandardMem::Request* request)
|
||||||
{
|
{
|
||||||
pkt->makeResponse();
|
pkt->makeResponse();
|
||||||
|
|
||||||
@@ -116,8 +172,18 @@ inplaceSSTRequestToGem5PacketPtr(gem5::PacketPtr pkt,
|
|||||||
// SC interprets ExtraData == 1 as the store was successful
|
// SC interprets ExtraData == 1 as the store was successful
|
||||||
pkt->req->setExtraData(1);
|
pkt->req->setExtraData(1);
|
||||||
}
|
}
|
||||||
|
// If there is data in the request, send it back. Only ReadResp requests
|
||||||
pkt->setData(request->data.data());
|
// 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<SST::Interfaces::StandardMem::ReadResp*>(request)) {
|
||||||
|
pkt->setData(dynamic_cast<SST::Interfaces::StandardMem::ReadResp*>(
|
||||||
|
request)->data.data()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Clear out bus delay notifications
|
// Clear out bus delay notifications
|
||||||
pkt->headerDelay = pkt->payloadDelay = 0;
|
pkt->headerDelay = pkt->payloadDelay = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user