Merge pull request #1644 from firesim/cospike-integration

Remove Dromajo in favor of Spike cosimulation
This commit is contained in:
Abraham Gonzalez 2023-09-05 19:12:48 -07:00 committed by GitHub
commit dee9a78333
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 979 additions and 1084 deletions

File diff suppressed because it is too large Load Diff

View File

@ -29,7 +29,6 @@ dependencies:
- conda-gcc-specs
- binutils
- dromajo # from ucb-bar channel - https://github.com/riscv-boom/dromajo
- riscv-tools==1.0.3 # from ucb-bar channel - https://github.com/ucb-bar/riscv-tools-feedstock
# firemarshal deps

View File

@ -371,7 +371,6 @@ class RuntimeHWConfig:
command_linklatencies = array_to_plusargs(all_linklatencies, "+linklatency")
command_netbws = array_to_plusargs(all_netbws, "+netbw")
command_shmemportnames = array_to_plusargs(all_shmemportnames, "+shmemportname")
command_dromajo = "+drj_dtb=" + all_bootbinaries[0] + ".dtb" + " +drj_bin=" + all_bootbinaries[0] + " +drj_rom=" + all_bootbinaries[0] + ".rom"
command_niclogs = array_to_lognames(all_macs, "niclog")
command_blkdev_logs = array_to_lognames(all_rootfses, "blkdev-log")
@ -399,7 +398,6 @@ class RuntimeHWConfig:
permissive_driver_args += command_blkdev_logs
permissive_driver_args += [f"{tracefile}", f"+trace-select={tracerv_config.select}", f"+trace-start={tracerv_config.start}", f"+trace-end={tracerv_config.end}", f"+trace-output-format={tracerv_config.output_format}", dwarf_file_name]
permissive_driver_args += [f"+autocounter-readrate={autocounter_config.readrate}", autocounterfile]
permissive_driver_args += [command_dromajo]
permissive_driver_args += [print_cycle_prefix, f"+print-start={synthprint_config.start}", f"+print-end={synthprint_config.end}"]
permissive_driver_args += command_linklatencies
permissive_driver_args += command_netbws

View File

@ -0,0 +1,39 @@
.. _spike:
Spike Co-simulation with BOOM designs
==================================================
Instead of using TracerV to provide a cycle-by-cycle trace of a target
CPU's architectural state, you can use the `Spike co-simulator <https://github.com/riscv-software-src/riscv-isa-sim>`_ to verify
the functionality of a BOOM design.
.. note:: This work currently only works for single core BOOM designs with a commit width of 1 or 2.
.. _cospike-bridge:
Building a Design with Cospike
-------------------------------
In all FireChip designs, TracerV is included by default.
To enable Cospike, you just need to add the Cospike bridge (``WithCospikeBridge``) to your BOOM target design config (default configs. located in ``$CHIPYARD/generators/firechip/src/main/scala/TargetConfigs.scala``).
An example configuration with Cospike is shown below:
.. code-block:: scala
class FireSimLargeBoomConfig extends Config(
new WithCospikeBridge ++ // add Cospike bridge to simulation
new WithDefaultFireSimBridges ++
new WithDefaultMemModel ++
new WithFireSimConfigTweaks ++
new chipyard.LargeBoomConfig)
At this point, you should run the ``firesim buildbitstream`` command for the BOOM config wanted.
At this point you are ready to run the simulation with Cospike by default enabled.
Troubleshooting Cospike Simulations with Meta-Simulations
----------------------------------------------------------
If FPGA simulation fails with Cospike, you can use metasimulation to determine if your Cospike setup is correct.
First refer to :ref:`metasimulation` for more information on metasimulation.
.. note:: Sometimes simulations in VCS will diverge unless a ``+define+RANDOM=0`` is added to the VCS flags in ``sim/midas/src/main/cc/rtlsim/Makefrag-vcs``.

View File

@ -1,111 +0,0 @@
.. _dromajo:
Dromajo Co-simulation with BOOM designs
==================================================
Instead of using TracerV to provide a cycle-by-cycle trace of a target
CPU's architectural state, you can use the `Dromajo co-simulator <https://github.com/chipsalliance/dromajo>`_ to verify
the functionality of a BOOM design.
.. note:: This work is highly experimental. We hope to integrate this into FireSim in a cleaner fashion at a later point.
.. note:: This work currently only works for single core BOOM designs.
.. _dromajo-bridge:
Building a Design with Dromajo
-------------------------------
In all FireChip designs, TracerV is included by default.
To enable Dromajo, you just need to add the Dromajo bridge (``WithDromajoBridge``) to your BOOM target design config (default configs. located in ``$CHIPYARD/generators/firechip/src/main/scala/TargetConfigs.scala``).
An example configuration with Dromajo is shown below:
.. code-block:: scala
class FireSimLargeBoomConfig extends Config(
new WithDromajoBridge ++ // add Dromajo bridge to simulation
new WithDefaultFireSimBridges ++
new WithDefaultMemModel ++
new WithFireSimConfigTweaks ++
new chipyard.LargeBoomConfig)
At this point, you should run the ``firesim buildbitstream`` command for the BOOM config wanted.
Running a FireSim Simulation
----------------------------
To run a simulation with Dromajo, you must modify the workload ``json`` to support Dromajo.
The following is an example using the base Linux workload generated from FireMarshal and modifying it for Dromajo.
Here is the modified workload json (renamed to ``br-base-dromajo`` from ``br-base``):
.. code-block:: json
{
"benchmark_name": "br-base-dromajo",
"common_simulation_outputs": [
"uartlog",
"dromajo_snap.re_regs"
],
"common_bootbinary": "../../../../../software/firemarshal/images/firechip/br-base/br-base-bin",
"common_rootfs": "../../../../../software/firemarshal/images/firechip/br-base/br-base.img",
"common_simulation_inputs": [
"br-base-bin.rom",
"br-base-bin.dtb"
]
}
You will notice there are two extra simulation inputs needed compared to the "base" unmodified
``br-base`` workload: a bootrom (``rom``) and a device tree blob (``dtb``).
Both files are found in your generated sources and should be moved into the workload directory (i.e. ``workloads/br-base-dromajo``).
.. code-block:: shell
cd $CHIPYARD
# copy/rename the rom file and put in the proper folder
cp sim/generated-src/f1/<LONG_NAME>/<LONG_NAME>.rom $FIRESIM/deploy/workloads/br-base-dromajo/br-base-bin.rom
# copy/rename the dtb file and put in the proper folder
cp sim/generated-src/f1/<LONG_NAME>/<LONG_NAME>.dtb $FIRESIM/deploy/workloads/br-base-dromajo/br-base-bin.dtb
After this process, you should see the following ``workloads/br-base-dromajo`` folder layout:
.. code-block:: shell
br-base-dromajo/
br-base-bin.rom
br-base-bin.dtb
README
.. note:: The name of the ``rom`` and ``dtb`` files must match the name of the workload binary i.e. ``common_bootbinary``.
At this point you are ready to run the simulation with Dromajo.
The commit log trace will by default print to the ``uartlog``.
However, you can avoid printing it out by changing ``verbose == false`` in the ``dromajo_cosim.cpp`` file
located in ``$CHIPYARD/tools/dromajo/dromajo-src/src/`` folder.
Troubleshooting Dromajo Simulations with Meta-Simulations
----------------------------------------------------------
If FPGA simulation fails with Dromajo, you can use metasimulation to determine if your Dromajo setup is correct.
First refer to :ref:`metasimulation` for more information on metasimulation.
The main difference between those instructions and simulations with Dromajo is that you need to manually point to the ``dtb``, ``rom``, and binary files when invoking the simulator.
Here is an example of a ``make`` command that can be run to check for a correct setup.
.. code-block:: shell
# enter simulation directory
cd $FIRESIM/sim/
# make command to run a binary
# <BIN> - absolute path to binary
# <DTB> - absolute path to dtb file
# <BOOTROM> - absolute path to rom file
# <YourBoomConfig> - Single-core BOOM configuration to test
make TARGET_CONFIG=<YourBoomConfig> SIM_BINARY=<BIN> EXTRA_SIM_ARGS="+drj_dtb=<DTB> +drj_rom=<BOOTROM> +drj_bin=<BIN>" run-vcs
It is important to have the ``+drj_*`` arguments, otherwise Dromajo will not match the simulation running on the DUT.
.. note:: Sometimes simulations in VCS will diverge unless a ``+define+RANDOM=0`` is added to the VCS flags in ``sim/midas/src/main/cc/rtlsim/Makefrag-vcs``.
.. warning:: Dromajo currently only works in VCS and FireSim simulations.

View File

@ -17,5 +17,5 @@ features.
Debugging-Hardware-Using-ILA.rst
AutoCounter.rst
TracerV-with-FlameGraph.rst
Dromajo.rst
Cospike.rst
Debugging-Hanging-Simulators.rst

View File

@ -27,6 +27,9 @@ Single tests may be run directly out of :gh-file-ref:`sim/` as follows::
# Run a specific integration test (desired)
make testOnly TARGET_PROJECT=midasexamples SCALA_TEST=firesim.midasexamples.GCDF1Test
# note: you can disable certain subsets of tests by using a
# TEST_DISABLE_{VERILATOR,VCS,VIVADO}=1 environment variable
These tests may be run from the SBT console continuously, and SBT will rerun
them on Scala changes (but not driver changes). Out of :gh-file-ref:`sim/`::

View File

@ -6,4 +6,4 @@ if [ ! -d "$REQS_DIR" ]; then
echo "$REQS_DIR does not exist, make sure you're calling this script from firesim/"
exit 1
fi
conda-lock --conda $(which conda) -f "$REQS_DIR/firesim.yaml" -f "$REQS_DIR/ci-shared.yaml" -p linux-64 --lockfile "$REQS_DIR/conda-reqs.conda-lock.yml"
conda-lock -f "$REQS_DIR/firesim.yaml" -f "$REQS_DIR/ci-shared.yaml" -p linux-64 --lockfile "$REQS_DIR/conda-reqs.conda-lock.yml"

View File

@ -7,7 +7,6 @@ project {
]
excludePaths = [
"glob:**firesim-lib/src/main/scala/bridges/BlockDevBridge.scala",
"glob:**firesim-lib/src/main/scala/bridges/DromajoBridge.scala",
"glob:**firesim-lib/src/main/scala/bridges/GroundTestBridge.scala",
"glob:**firesim-lib/src/main/scala/bridges/TSIBridge.scala",
"glob:**firesim-lib/src/main/scala/bridges/SimpleNICBridge.scala",

View File

@ -0,0 +1,245 @@
// See LICENSE for license details
#include "cospike.h"
#include "cospike_impl.h"
#include <assert.h>
#include <iostream>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
// Create bitmask macro
#define BIT_MASK(__ITYPE__, __ONE_COUNT__) \
(((__ITYPE__)(-((__ONE_COUNT__) != 0))) & \
(((__ITYPE__)-1) >> ((sizeof(__ITYPE__) * CHAR_BIT) - (__ONE_COUNT__))))
#define TO_BYTES(__BITS__) ((__BITS__) / 8)
#define DEBUG
char cospike_t::KIND;
/**
* Constructor for cospike
*/
cospike_t::cospike_t(simif_t &sim,
StreamEngine &stream,
int cospikeno,
std::vector<std::string> &args,
uint32_t iaddr_width,
uint32_t insn_width,
uint32_t cause_width,
uint32_t wdata_width,
uint32_t num_commit_insts,
uint32_t bits_per_trace,
const char *isa,
uint32_t vlen,
const char *priv,
uint32_t pmp_regions,
uint64_t mem0_base,
uint64_t mem0_size,
uint32_t nharts,
const char *bootrom,
uint32_t hartid,
uint32_t stream_idx,
uint32_t stream_depth)
: streaming_bridge_driver_t(sim, stream, &KIND), args(args), _isa(isa),
_vlen(vlen), _priv(priv), _pmp_regions(pmp_regions),
_mem0_base(mem0_base), _mem0_size(mem0_size), _nharts(nharts),
_bootrom(bootrom), _hartid(hartid), _num_commit_insts(num_commit_insts),
_bits_per_trace(bits_per_trace), stream_idx(stream_idx),
stream_depth(stream_depth) {
this->_valid_width = 1;
this->_iaddr_width = TO_BYTES(iaddr_width);
this->_insn_width = TO_BYTES(insn_width);
this->_exception_width = 1;
this->_interrupt_width = 1;
this->_cause_width = TO_BYTES(cause_width);
this->_wdata_width = TO_BYTES(wdata_width);
this->_priv_width = 1;
// must align with how the trace is composed
this->_valid_offset = 0;
this->_iaddr_offset = this->_valid_offset + this->_valid_width;
this->_insn_offset = this->_iaddr_offset + this->_iaddr_width;
this->_priv_offset = this->_insn_offset + this->_insn_width;
this->_exception_offset = this->_priv_offset + this->_priv_width;
this->_interrupt_offset = this->_exception_offset + this->_exception_width;
this->_cause_offset = this->_interrupt_offset + this->_interrupt_width;
this->_wdata_offset = this->_cause_offset + this->_cause_width;
this->cospike_failed = false;
this->cospike_exit_code = 0;
}
/**
* Setup simulation and initialize cospike cosimulation
*/
void cospike_t::init() {
printf("[INFO] Cospike: Attached cospike to a single instruction trace with "
"%d instructions.\n",
this->_num_commit_insts);
cospike_set_sysinfo((char *)this->_isa,
this->_vlen,
(char *)this->_priv,
this->_pmp_regions,
this->_mem0_base,
this->_mem0_size,
this->_nharts,
(char *)this->_bootrom,
this->args);
}
#define SHIFT_BITS(__RTYPE__, __BYTE_WIDTH__) \
((sizeof(__RTYPE__) - (__BYTE_WIDTH__)) * 8)
#define SIGNED_EXTRACT_NON_ALIGNED( \
__ITYPE__, __RTYPE__, __BUF__, __BYTE_WIDTH__, __BYTE_OFFSET__) \
(*((__ITYPE__ *)((__BUF__) + (__BYTE_OFFSET__))) & \
BIT_MASK(__RTYPE__, (__BYTE_WIDTH__)*8))
#define EXTRACT_ALIGNED( \
__ITYPE__, __RTYPE__, __BUF__, __BYTE_WIDTH__, __BYTE_OFFSET__) \
((((__ITYPE__)SIGNED_EXTRACT_NON_ALIGNED( \
__ITYPE__, __RTYPE__, __BUF__, __BYTE_WIDTH__, __BYTE_OFFSET__)) \
<< SHIFT_BITS(__RTYPE__, __BYTE_WIDTH__)) >> \
SHIFT_BITS(__RTYPE__, __BYTE_WIDTH__))
/**
* Call cospike co-sim functions with an aligned buffer.
* This returns the return code of the co-sim functions.
*/
int cospike_t::invoke_cospike(uint8_t *buf) {
bool valid = buf[0];
// this crazy to extract the right value then sign extend within the size
uint64_t iaddr = EXTRACT_ALIGNED(int64_t,
uint64_t,
buf,
this->_iaddr_width,
this->_iaddr_offset); // aka the pc
uint32_t insn = EXTRACT_ALIGNED(
int32_t, uint32_t, buf, this->_insn_width, this->_insn_offset);
bool exception = buf[this->_exception_offset];
bool interrupt = buf[this->_interrupt_offset];
uint64_t cause = EXTRACT_ALIGNED(
int64_t, uint64_t, buf, this->_cause_width, this->_cause_offset);
uint64_t wdata =
this->_wdata_width != 0
? EXTRACT_ALIGNED(
int64_t, uint64_t, buf, this->_wdata_width, this->_wdata_offset)
: 0;
uint8_t priv = buf[this->_priv_offset];
#ifdef DEBUG
fprintf(stderr,
"C[%d] V(%d) PC(0x%lx) Insn(0x%x) EIC(%d:%d:%ld) Wdata(%d:0x%lx) "
"Priv(%d)\n",
this->_hartid,
valid,
iaddr,
insn,
exception,
interrupt,
cause,
(this->_wdata_width != 0),
wdata,
priv);
#endif
if (valid || exception || cause) {
return cospike_cosim(0, // TODO: No cycle given
this->_hartid,
(this->_wdata_width != 0),
valid,
iaddr,
insn,
exception,
interrupt,
cause,
wdata,
priv);
} else {
return 0;
}
}
/**
* Read queue and co-simulate
*/
size_t cospike_t::process_tokens(int num_beats, size_t minimum_batch_beats) {
const size_t maximum_batch_bytes = num_beats * STREAM_WIDTH_BYTES;
const size_t minimum_batch_bytes = minimum_batch_beats * STREAM_WIDTH_BYTES;
// TODO: as opt can mmap file and just load directly into it.
page_aligned_sized_array(OUTBUF, maximum_batch_bytes);
auto bytes_received =
pull(stream_idx, OUTBUF, maximum_batch_bytes, minimum_batch_bytes);
const size_t bytes_per_trace = this->_bits_per_trace / 8;
for (uint32_t offset = 0; offset < bytes_received;
offset += bytes_per_trace) {
#ifdef DEBUG
fprintf(stderr,
"Off(%d/%ld:%lu) token(",
offset,
bytes_received,
offset / bytes_per_trace);
for (int32_t i = STREAM_WIDTH_BYTES - 1; i >= 0; --i) {
fprintf(stderr, "%02x", (OUTBUF + offset)[i]);
if (i == bytes_per_trace)
fprintf(stderr, " ");
}
fprintf(stderr, ")\n");
#endif
// invoke cospike (requires that buffer is aligned properly)
int rval = this->invoke_cospike(((uint8_t *)OUTBUF) + offset);
if (rval) {
cospike_failed = true;
cospike_exit_code = rval;
printf("[ERROR] Cospike: Errored during simulation with %d\n", rval);
#ifdef DEBUG
fprintf(stderr, "Off(%lu) token(", offset / bytes_per_trace);
for (int32_t i = STREAM_WIDTH_BYTES - 1; i >= 0; --i) {
fprintf(stderr, "%02x", (OUTBUF + offset)[i]);
if (i == bytes_per_trace)
fprintf(stderr, " ");
}
fprintf(stderr, ")\n");
fprintf(stderr, "get_next_token token(");
auto next_off = offset + STREAM_WIDTH_BYTES;
for (auto i = STREAM_WIDTH_BYTES - 1; i >= 0; --i) {
fprintf(stderr, "%02x", (OUTBUF + next_off)[i]);
if (i == bytes_per_trace)
fprintf(stderr, " ");
}
fprintf(stderr, ")\n");
#endif
break;
}
}
return bytes_received;
}
/**
* Move forward the simulation
*/
void cospike_t::tick() {
this->process_tokens(this->stream_depth, this->stream_depth);
}
/**
* Pull in any remaining tokens and use them (if the simulation hasn't already
* failed)
*/
void cospike_t::flush() {
// only flush if there wasn't a failure before
while (!cospike_failed && (this->process_tokens(this->stream_depth, 0) > 0))
;
}

View File

@ -0,0 +1,94 @@
// See LICENSE for license details
#ifndef __COSPIKE_H
#define __COSPIKE_H
#include "core/bridge_driver.h"
#include <string>
#include <vector>
class cospike_t : public streaming_bridge_driver_t {
public:
/// The identifier for the bridge type used for casts.
static char KIND;
cospike_t(simif_t &sim,
StreamEngine &stream,
int cospikeno,
std::vector<std::string> &args,
uint32_t iaddr_width,
uint32_t insn_width,
uint32_t cause_width,
uint32_t wdata_width,
uint32_t num_commit_insts,
uint32_t bits_per_trace,
const char *isa,
uint32_t vlen,
const char *priv,
uint32_t pmp_regions,
uint64_t mem0_base,
uint64_t mem0_size,
uint32_t nharts,
const char *bootrom,
uint32_t hartid,
uint32_t stream_idx,
uint32_t stream_depth);
~cospike_t() override = default;
void init() override;
void tick() override;
bool terminate() override { return cospike_failed; };
int exit_code() override { return (cospike_failed) ? cospike_exit_code : 0; };
void finish() override { this->flush(); };
private:
int invoke_cospike(uint8_t *buf);
size_t process_tokens(int num_beats, size_t minimum_batch_beats);
void flush();
std::vector<std::string> args;
// in bytes
uint32_t _valid_width;
uint32_t _iaddr_width;
uint32_t _insn_width;
uint32_t _wdata_width;
uint32_t _priv_width;
uint32_t _exception_width;
uint32_t _interrupt_width;
uint32_t _cause_width;
uint32_t _tval_width;
// in bytes
uint32_t _valid_offset;
uint32_t _iaddr_offset;
uint32_t _insn_offset;
uint32_t _wdata_offset;
uint32_t _priv_offset;
uint32_t _exception_offset;
uint32_t _interrupt_offset;
uint32_t _cause_offset;
uint32_t _tval_offset;
const char *_isa;
uint32_t _vlen;
const char *_priv;
uint32_t _pmp_regions;
uint64_t _mem0_base;
uint64_t _mem0_size;
uint32_t _nharts;
const char *_bootrom;
uint32_t _hartid;
// other misc members
uint32_t _num_commit_insts;
uint32_t _bits_per_trace;
bool cospike_failed;
int cospike_exit_code;
// stream config
int stream_idx;
int stream_depth;
};
#endif // __COSPIKE_H

View File

@ -1,306 +0,0 @@
// See LICENSE for license details
#include "dromajo.h"
#include <assert.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
// Create bitmask macro
#define BIT_MASK(__TYPE__, __ONE_COUNT__) \
((__TYPE__)(-((__ONE_COUNT__) != 0))) & \
(((__TYPE__)-1) >> ((sizeof(__TYPE__) * CHAR_BIT) - (__ONE_COUNT__)))
// #define DEBUG
char dromajo_t::KIND;
/**
* Constructor for Dromajo
*/
dromajo_t::dromajo_t(simif_t &sim,
StreamEngine &stream,
std::vector<std::string> &args,
const DROMAJOBRIDGEMODULE_struct &mmio_addrs,
const dromajo_config_t &config,
int iaddr_width,
int insn_width,
int wdata_width,
int cause_width,
int tval_width,
int num_traces,
int stream_idx,
int stream_depth)
: streaming_bridge_driver_t(sim, stream, &KIND), mmio_addrs(mmio_addrs),
config(config), stream_idx(stream_idx), stream_depth(stream_depth) {
// setup max constants given from the RTL
this->_num_traces = num_traces;
this->_valid_width = 1;
this->_iaddr_width = iaddr_width / 8;
this->_insn_width = insn_width / 8;
this->_wdata_width = wdata_width / 8;
this->_priv_width = 1;
this->_exception_width = 1;
this->_interrupt_width = 1;
this->_cause_width = cause_width / 8;
this->_tval_width = tval_width / 8;
this->_valid_offset = 0;
this->_iaddr_offset = this->_valid_offset + this->_valid_width;
;
this->_insn_offset = this->_iaddr_offset + this->_iaddr_width;
this->_wdata_offset = this->_insn_offset + this->_insn_width;
this->_priv_offset = this->_wdata_offset + this->_wdata_width;
this->_exception_offset = this->_priv_offset + this->_priv_width;
this->_interrupt_offset = this->_exception_offset + this->_exception_width;
this->_cause_offset = this->_interrupt_offset + this->_interrupt_width;
this->_tval_offset = this->_cause_offset + this->_cause_width;
// setup misc. state variables
this->_trace_idx = 0;
this->dromajo_failed = false;
this->dromajo_exit_code = 0;
this->dromajo_state = NULL;
this->dromajo_cosim = true; // by default enable cosim
this->saw_int_excp = false; // used to not trigger interrupts multiple times
// setup dromajo variables
std::string dromajo_dtb_arg = std::string("+drj_dtb=");
std::string dromajo_bin_arg = std::string("+drj_bin=");
std::string dromajo_rom_arg = std::string("+drj_rom=");
bool dtb_found = false;
bool bin_found = false;
bool bootrom_found = false;
this->dromajo_dtb = "";
this->dromajo_bootrom = "";
this->dromajo_bin = "";
const char *d_rom = NULL;
const char *d_dtb = NULL;
const char *d_bin = NULL;
for (auto &arg : args) {
if (arg.find(dromajo_dtb_arg) == 0) {
d_dtb = const_cast<char *>(arg.c_str()) + dromajo_dtb_arg.length();
this->dromajo_dtb = std::string(d_dtb);
dtb_found = true;
}
if (arg.find(dromajo_rom_arg) == 0) {
d_rom = const_cast<char *>(arg.c_str()) + dromajo_rom_arg.length();
this->dromajo_bootrom = std::string(d_rom);
bootrom_found = true;
}
if (arg.find(dromajo_bin_arg) == 0) {
d_bin = const_cast<char *>(arg.c_str()) + dromajo_bin_arg.length();
this->dromajo_bin = std::string(d_bin);
bin_found = true;
}
}
if (!dtb_found || !bin_found || !bootrom_found) {
printf("[WARNING] Missing Dromajo input file(s) (make sure you have a dtb, "
"bin, and bootrom passed in)\n");
printf("[WARNING] Disabling Dromajo Bridge\n");
this->dromajo_cosim = false;
}
}
/**
* Destructor for Dromajo
*/
dromajo_t::~dromajo_t() {
if (this->dromajo_state)
dromajo_cosim_fini(this->dromajo_state);
}
/**
* Setup simulation and initialize Dromajo cosimulation
*/
void dromajo_t::init() {
// skip if co-sim not enabled
if (!this->dromajo_cosim)
return;
printf("[INFO] Dromajo: Attached Dromajo to %d instruction traces\n",
this->_num_traces);
// setup arguments
std::vector<std::string> dromajo_args{
"./dromajo",
"--compact_bootrom",
"--custom_extension",
"--clear_ids",
"--reset_vector",
config.resetVector,
"--bootrom",
dromajo_bootrom,
"--mmio_range",
std::string(config.mmioStart) + ":" + config.mmioEnd,
"--plic",
std::string(config.plicBase) + ":" + config.plicSize,
"--clint",
std::string(config.clintBase) + ":" + config.clintSize,
"--memory_size",
config.memSize,
"--save",
"dromajo_snap",
"--dtb",
dromajo_dtb,
dromajo_bin};
printf("[INFO] Dromajo command: \n");
char *dromajo_argv[dromajo_args.size()];
for (size_t i = 0; i < dromajo_args.size(); ++i) {
dromajo_argv[i] = const_cast<char *>(dromajo_args[i].c_str());
printf("%s ", dromajo_argv[i]);
}
printf("\n");
this->dromajo_state = dromajo_cosim_init(dromajo_args.size(), dromajo_argv);
if (this->dromajo_state == NULL) {
printf("[ERROR] Error setting up Dromajo\n");
exit(1);
}
}
/**
* Call Dromajo co-sim functions with an aligned buffer.
* This returns the return code of the co-sim functions.
*/
int dromajo_t::invoke_dromajo(uint8_t *buf) {
bool valid = buf[0];
int hartid = 0; // only works for single core
// this crazy to extract the right value then sign extend within the size
uint64_t pc = ((int64_t)(*((int64_t *)(buf + this->_iaddr_offset)) &
BIT_MASK(uint64_t, this->_iaddr_width * 8))
<< (sizeof(uint64_t) - this->_iaddr_width) * 8) >>
(sizeof(uint64_t) - this->_iaddr_width) * 8;
uint32_t insn = ((int32_t)(*((int32_t *)(buf + this->_insn_offset)) &
BIT_MASK(uint32_t, this->_insn_width * 8))
<< (sizeof(uint32_t) - this->_insn_width) * 8) >>
(sizeof(uint32_t) - this->_insn_width) * 8;
uint64_t wdata = ((int64_t)(*((int64_t *)(buf + this->_wdata_offset)) &
BIT_MASK(uint64_t, this->_wdata_width * 8))
<< (sizeof(uint64_t) - this->_wdata_width) * 8) >>
(sizeof(uint64_t) - this->_wdata_width) * 8;
uint64_t mstatus = 0; // default not checked
bool check = true; // default check all
bool interrupt = buf[this->_interrupt_offset];
bool exception = buf[this->_exception_offset];
int64_t cause = (*((uint64_t *)(buf + this->_cause_offset)) &
BIT_MASK(uint64_t, this->_cause_width * 8)) |
((uint64_t)interrupt << 63);
if (valid) {
#ifdef DEBUG
if (interrupt || exception)
fprintf(
stderr, "[DEBUG] INT/EXCEP raised (on valid): cause = %lx\n", cause);
#endif
return dromajo_cosim_step(
this->dromajo_state, hartid, pc, insn, wdata, mstatus, check);
}
if ((interrupt || exception) && !(this->saw_int_excp)) {
#ifdef DEBUG
fprintf(stderr, "[DEBUG] INT/EXCEP raised (normal): cause = %lx\n", cause);
#endif
dromajo_cosim_raise_trap(this->dromajo_state, hartid, cause);
this->saw_int_excp = true;
}
return 0;
}
/**
* Read queue and co-simulate
*/
size_t dromajo_t::process_tokens(int num_beats, size_t minimum_batch_beats) {
size_t maximum_batch_bytes = num_beats * STREAM_WIDTH_BYTES;
size_t minimum_batch_bytes = minimum_batch_beats * STREAM_WIDTH_BYTES;
// TODO: as opt can mmap file and just load directly into it.
page_aligned_sized_array(OUTBUF, maximum_batch_bytes);
auto bytes_received =
pull(stream_idx, OUTBUF, maximum_batch_bytes, minimum_batch_bytes);
// skip if co-sim not enabled
if (!this->dromajo_cosim)
return bytes_received;
for (uint32_t offset = 0; offset < bytes_received;
offset += STREAM_WIDTH_BYTES / 2) {
// invoke dromajo (requires that buffer is aligned properly)
int rval = this->invoke_dromajo(((uint8_t *)OUTBUF) + offset);
if (rval) {
dromajo_failed = true;
dromajo_exit_code = rval;
printf("[ERROR] Dromajo: Errored during simulation with %d\n", rval);
#ifdef DEBUG
fprintf(stderr,
"C[%d] off(%d) token(",
this->_trace_idx,
offset / (STREAM_WIDTH_BYTES / 2));
for (int32_t i = STREAM_WIDTH_BYTES - 1; i >= 0; --i) {
fprintf(stderr, "%02x", (OUTBUF + offset)[i]);
if (i == STREAM_WIDTH_BYTES / 2)
fprintf(stderr, " ");
}
fprintf(stderr, ")\n");
fprintf(stderr, "get_next_token token(");
uint32_t next_off = offset += STREAM_WIDTH_BYTES;
for (int32_t i = STREAM_WIDTH_BYTES - 1; i >= 0; --i) {
fprintf(stderr, "%02x", (OUTBUF + next_off)[i]);
if (i == STREAM_WIDTH_BYTES / 2)
fprintf(stderr, " ");
}
fprintf(stderr, ")\n");
#endif
return bytes_received;
}
// move to next inst. trace
this->_trace_idx = (this->_trace_idx + 1) % this->_num_traces;
// if int/excp was found in this set of commit traces... reset on next set
// of commit traces
if (this->_trace_idx == 0) {
this->saw_int_excp = false;
}
// add an extra STREAM_WIDTH_BYTES if there is an odd amount of traces
if (this->_trace_idx == 0 && (this->_num_traces % 2 == 1)) {
#ifdef DEBUG
fprintf(stderr,
"off(%d + 1) = %d\n",
offset / (STREAM_WIDTH_BYTES / 2),
(offset + STREAM_WIDTH_BYTES / 2) / (STREAM_WIDTH_BYTES / 2));
#endif
offset += STREAM_WIDTH_BYTES / 2;
}
}
return bytes_received;
}
/**
* Move forward the simulation
*/
void dromajo_t::tick() {
this->process_tokens(this->stream_depth, this->stream_depth);
}
/**
* Pull in any remaining tokens and use them (if the simulation hasn't already
* failed)
*/
void dromajo_t::flush() {
// only flush if there wasn't a failure before
while (!dromajo_failed && (this->process_tokens(this->stream_depth, 0) > 0))
;
}

View File

@ -1,100 +0,0 @@
// See LICENSE for license details
#ifndef __DROMAJO_H
#define __DROMAJO_H
#include "core/bridge_driver.h"
#include "dromajo_cosim.h"
#include <string>
#include <vector>
struct DROMAJOBRIDGEMODULE_struct {};
struct dromajo_config_t {
const char *resetVector;
const char *mmioStart;
const char *mmioEnd;
const char *memSize;
const char *plicBase;
const char *plicSize;
const char *clintBase;
const char *clintSize;
};
class dromajo_t : public streaming_bridge_driver_t {
public:
/// The identifier for the bridge type used for casts.
static char KIND;
dromajo_t(simif_t &sim,
StreamEngine &stream,
std::vector<std::string> &args,
const DROMAJOBRIDGEMODULE_struct &mmio_addrs,
const dromajo_config_t &config,
int iaddr_width,
int insn_width,
int wdata_width,
int cause_width,
int tval_width,
int num_traces,
int stream_idx,
int stream_depth);
~dromajo_t();
virtual void init();
virtual void tick();
virtual bool terminate() { return dromajo_failed; };
virtual int exit_code() { return (dromajo_failed) ? dromajo_exit_code : 0; };
virtual void finish() { this->flush(); };
private:
const DROMAJOBRIDGEMODULE_struct mmio_addrs;
const dromajo_config_t config;
simif_t *_sim;
int invoke_dromajo(uint8_t *buf);
int beats_available_stable();
size_t process_tokens(int num_beats, size_t minimum_batch_beats);
void flush();
// in bytes
uint32_t _valid_width;
uint32_t _iaddr_width;
uint32_t _insn_width;
uint32_t _wdata_width;
uint32_t _priv_width;
uint32_t _exception_width;
uint32_t _interrupt_width;
uint32_t _cause_width;
uint32_t _tval_width;
// in bytes
uint32_t _valid_offset;
uint32_t _iaddr_offset;
uint32_t _insn_offset;
uint32_t _wdata_offset;
uint32_t _priv_offset;
uint32_t _exception_offset;
uint32_t _interrupt_offset;
uint32_t _cause_offset;
uint32_t _tval_offset;
// other misc members
uint32_t _num_traces;
uint8_t _trace_idx;
bool dromajo_failed;
int dromajo_exit_code;
bool dromajo_cosim;
bool saw_int_excp;
// dromajo specific
std::string dromajo_dtb;
std::string dromajo_bootrom;
std::string dromajo_bin;
dromajo_cosim_state_t *dromajo_state;
// stream config
int stream_idx;
int stream_depth;
};
#endif // __DROMAJO_H

View File

@ -0,0 +1,210 @@
//See LICENSE for license details
package firesim.bridges
import chisel3._
import chisel3.util._
import org.chipsalliance.cde.config.Parameters
import freechips.rocketchip.util.DecoupledHelper
import testchipip.{SerializableTileTraceIO, SpikeCosimConfig, TileTraceIO, TraceBundleWidths}
import midas.widgets._
case class CospikeBridgeParams(
widths: TraceBundleWidths,
hartid: Int,
cfg: SpikeCosimConfig,
)
class CospikeTargetIO(widths: TraceBundleWidths) extends Bundle {
val trace = Input(new SerializableTileTraceIO(widths))
}
/** Blackbox that is instantiated in the target
*/
class CospikeBridge(params: CospikeBridgeParams)
extends BlackBox
with Bridge[HostPortIO[CospikeTargetIO], CospikeBridgeModule] {
val io = IO(new CospikeTargetIO(params.widths))
val bridgeIO = HostPort(io)
// give the Cospike params to the GG module
val constructorArg = Some(params)
// generate annotations to pass to GG
generateAnnotations()
}
/** Helper function to connect blackbox
*/
object CospikeBridge {
def apply(trace: TileTraceIO, hartid: Int, cfg: SpikeCosimConfig) = {
val params = new CospikeBridgeParams(trace.traceBundleWidths, hartid, cfg)
val cosim = withClockAndReset(trace.clock, trace.reset) {
Module(new CospikeBridge(params))
}
cosim.io.trace.trace.insns.map(t => {
t := DontCare
t.valid := false.B
})
cosim.io.trace := trace.asSerializableTileTrace
cosim
}
}
//*************************************************
//* GOLDEN GATE MODULE
//* This lives in the host (still runs on the FPGA)
//*************************************************
class CospikeBridgeModule(params: CospikeBridgeParams)(implicit p: Parameters)
extends BridgeModule[HostPortIO[CospikeTargetIO]]()(p)
with StreamToHostCPU {
// CONSTANTS: DMA Parameters
val toHostCPUQueueDepth = 6144
lazy val module = new BridgeModuleImp(this) {
// setup io
val io = IO(new WidgetIO)
val hPort = IO(HostPort(new CospikeTargetIO(params.widths)))
// helper to get number to round up to nearest multiple
def roundUp(num: Int, mult: Int): Int = { (num.toFloat / mult).ceil.toInt * mult }
// get the traces
val traces = hPort.hBits.trace.trace.insns.map({ unmasked =>
val masked = WireDefault(unmasked)
masked.valid := unmasked.valid && !hPort.hBits.trace.reset
masked
})
private val iaddrWidth = roundUp(traces.map(_.iaddr.getWidth).max, 8)
private val insnWidth = roundUp(traces.map(_.insn.getWidth).max, 8)
private val causeWidth = roundUp(traces.map(_.cause.getWidth).max, 8)
private val wdataWidth = roundUp(traces.map(t => if (t.wdata.isDefined) t.wdata.get.getWidth else 0).max, 8)
// hack since for some reason padding a bool doesn't work...
def boolPad(in: Bool, size: Int): UInt = {
val temp = Wire(UInt(size.W))
temp := in.asUInt
temp
}
// matches order of TracedInstruction in CSR.scala
val paddedTraces = traces.map { trace =>
val pre_cat = Cat(
trace.cause.pad(causeWidth),
boolPad(trace.interrupt, 8),
boolPad(trace.exception, 8),
trace.priv.asUInt.pad(8),
trace.insn.pad(insnWidth),
trace.iaddr.pad(iaddrWidth),
boolPad(trace.valid, 8),
)
if (wdataWidth == 0) {
pre_cat
} else {
Cat(trace.wdata.get.pad(wdataWidth), pre_cat)
}
}
val maxTraceSize = paddedTraces.map(t => t.getWidth).max
val outDataSzBits = streamEnq.bits.getWidth
val totalTracesPerToken = (outDataSzBits / maxTraceSize).toInt
val bitsPerTrace = roundUp(outDataSzBits / totalTracesPerToken, 8)
require(
maxTraceSize < bitsPerTrace,
f"All instruction trace bits (i.e. valid, pc, instBits...) (${maxTraceSize}b) must fit in ${bitsPerTrace}b",
)
require(
bitsPerTrace * totalTracesPerToken <= outDataSzBits,
f"All traces must fit in single token (${bitsPerTrace * totalTracesPerToken} > ${outDataSzBits})",
)
val armCount = (traces.length + totalTracesPerToken - 1) / totalTracesPerToken
// Literally each arm of the mux, these are directly the bits that get put into the bump
val allStreamBits =
paddedTraces.grouped(totalTracesPerToken).toSeq.map(grp => Cat(grp.map(t => t.asUInt.pad(bitsPerTrace)).reverse))
// Number of bits to use for the counter, the +1 is required because the counter will count 1 past the number of arms
val counterBits = log2Ceil(armCount + 1)
// This counter acts to select the mux arm
val counter = RegInit(0.U(counterBits.W))
// The main mux where the input arms are different possible valid traces, and the output goes to streamEnq
val streamMux = MuxLookup(counter, allStreamBits(0), Seq.tabulate(armCount)(x => x.U -> allStreamBits(x)))
// a parallel set of arms to a parallel mux, true if any instructions in the arm are valid (OR reduction)
val anyValid =
traces
.grouped(totalTracesPerToken)
.toSeq
.map(arm => arm.map(trace => trace.valid | trace.exception | (trace.cause =/= 0.U)).reduce((a, b) => (a | b)))
// all of the valids of the larger indexed arms are OR reduced
val anyValidRemain =
Seq.tabulate(armCount)(idx => (idx until armCount).map(x => anyValid(x)).reduce((a, b) => (a | b)))
val anyValidRemainMux = MuxLookup(counter, false.B, Seq.tabulate(armCount)(x => x.U -> anyValidRemain(x)))
streamEnq.bits := streamMux
val maybeFire = !anyValidRemainMux || (counter === (armCount - 1).U)
val maybeEnq = anyValidRemainMux
val commonPredicates = Seq(hPort.toHost.hValid, streamEnq.ready)
val do_enq_helper = DecoupledHelper((maybeEnq +: commonPredicates): _*)
val do_fire_helper = DecoupledHelper((maybeFire +: commonPredicates): _*)
// Note, if we dequeue a token that wins out over the increment below
when(do_fire_helper.fire()) {
counter := 0.U
}.elsewhen(do_enq_helper.fire()) {
counter := counter + 1.U
}
streamEnq.valid := do_enq_helper.fire(streamEnq.ready)
hPort.toHost.hReady := do_fire_helper.fire(hPort.toHost.hValid)
hPort.fromHost.hValid := true.B // this is uni-directional. we don't drive tokens back to target
genCRFile()
// modify the output header file
override def genHeader(base: BigInt, memoryRegions: Map[String, BigInt], sb: StringBuilder): Unit = {
genConstructor(
base,
sb,
"cospike_t",
"cospike",
Seq(
UInt32(iaddrWidth),
UInt32(insnWidth),
UInt32(causeWidth),
UInt32(wdataWidth),
UInt32(traces.length),
UInt32(bitsPerTrace),
CStrLit(params.cfg.isa),
UInt32(params.cfg.vlen),
CStrLit(params.cfg.priv),
UInt32(params.cfg.pmpregions),
UInt64(params.cfg.mem0_base),
UInt64(params.cfg.mem0_size),
UInt32(params.cfg.nharts),
CStrLit(params.cfg.bootrom),
UInt32(params.hartid),
UInt32(toHostStreamIdx),
UInt32(toHostCPUQueueDepth),
),
hasStreams = true,
)
}
// general information printout
println(s"Cospike Bridge Information")
println(s" Total Inst. Traces (i.e. Commit Width): ${traces.length}")
println(s" Total Traces Per Token: ${totalTracesPerToken}")
}
}

View File

@ -1,145 +0,0 @@
//See LICENSE for license details
package firesim.bridges
import chisel3._
import chisel3.util._
import org.chipsalliance.cde.config.Parameters
import freechips.rocketchip.util._
import testchipip.{TileTraceIO, TraceBundleWidths, SerializableTileTraceIO}
import midas.widgets._
/**
* Blackbox that is instantiated in the target
*/
class DromajoBridge(widths: TraceBundleWidths) extends BlackBox
with Bridge[HostPortIO[SerializableTileTraceIO], DromajoBridgeModule]
{
val io = IO(new SerializableTileTraceIO(widths))
val bridgeIO = HostPort(io)
// give the Dromajo key to the GG module
val constructorArg = Some(widths)
// generate annotations to pass to GG
generateAnnotations()
}
/**
* Helper function to connect blackbox
*/
object DromajoBridge {
def apply(tracedInsns: TileTraceIO)(implicit p: Parameters): DromajoBridge = {
val b = Module(new DromajoBridge(tracedInsns.traceBundleWidths))
b.io.trace := tracedInsns.asSerializableTileTrace
b
}
}
//*************************************************
//* GOLDEN GATE MODULE
//* This lives in the host (still runs on the FPGA)
//*************************************************
class DromajoBridgeModule(key: TraceBundleWidths)(implicit p: Parameters) extends BridgeModule[HostPortIO[SerializableTileTraceIO]]()(p)
with StreamToHostCPU
{
// CONSTANTS: DMA Parameters
val toHostCPUQueueDepth = 6144
lazy val module = new BridgeModuleImp(this) {
// setup io
val io = IO(new WidgetIO)
val hPort = IO(HostPort(new SerializableTileTraceIO(key)))
// helper to get number to round up to nearest multiple
def roundUp(num: Int, mult: Int): Int = { (num/mult).ceil.toInt * mult }
// get the traces
val traces = hPort.hBits.trace.insns.map({ unmasked =>
val masked = WireDefault(unmasked)
masked.valid := unmasked.valid && !hPort.hBits.reset
masked
})
private val iaddrWidth = roundUp(traces.map(_.iaddr.getWidth).max, 8)
private val insnWidth = roundUp(traces.map(_.insn.getWidth).max, 8)
private val wdataWidth = roundUp(traces.map(_.wdata.get.getWidth).max, 8)
private val causeWidth = roundUp(traces.map(_.cause.getWidth).max, 8)
private val tvalWidth = roundUp(traces.map(_.tval.getWidth).max, 8)
// hack since for some reason padding a bool doesn't work...
def boolPad(in: Bool, size: Int): UInt = {
val temp = Wire(UInt(size.W))
temp := in.asUInt
temp
}
val paddedTraces = traces.map { trace =>
Cat(
trace.tval.pad(tvalWidth),
trace.cause.pad(causeWidth),
boolPad(trace.interrupt, 8),
boolPad(trace.exception, 8),
trace.priv.asUInt.pad(8),
trace.wdata.get.pad(wdataWidth),
trace.insn.pad(insnWidth),
trace.iaddr.pad(iaddrWidth),
boolPad(trace.valid, 8)
)
}
val maxTraceSize = paddedTraces.map(t => t.getWidth).max
val outDataSzBits = streamEnq.bits.getWidth
// constant
val totalTracesPerToken = 2 // minTraceSz==190b so round up to nearest is 256b
// constant
require(maxTraceSize < (outDataSzBits / totalTracesPerToken), "All instruction trace bits (i.e. valid, pc, instBits...) must fit in 256b")
// how many traces being sent over
val numTraces = traces.size
// num tokens needed to display full set of instructions from one cycle
val numTokenForAll = ((numTraces - 1) / totalTracesPerToken) + 1
// only inc the counter when the something is sent (this implies that the input is valid and output is avail on the other side)
val counterFire = streamEnq.fire
val (cnt, wrap) = Counter(counterFire, numTokenForAll)
val paddedTracesAligned = paddedTraces.map(t => t.asUInt.pad(outDataSzBits/totalTracesPerToken))
val paddedTracesTruncated = if (numTraces == 1) {
(paddedTracesAligned.asUInt >> (outDataSzBits.U * cnt))
} else {
(paddedTracesAligned.asUInt >> (outDataSzBits.U * cnt))(outDataSzBits-1, 0)
}
streamEnq.valid := hPort.toHost.hValid
streamEnq.bits := paddedTracesTruncated
// tell the host that you are ready to get more
hPort.toHost.hReady := streamEnq.ready && wrap
// This is uni-directional. We don't drive tokens back to the target.
hPort.fromHost.hValid := true.B
genCRFile()
// modify the output header file
override def genHeader(base: BigInt, memoryRegions: Map[String, BigInt], sb: StringBuilder): Unit = {
genConstructor(base, sb, "dromajo_t", "dromajo", Seq(
UInt32(iaddrWidth),
UInt32(insnWidth),
UInt32(wdataWidth),
UInt32(causeWidth),
UInt32(tvalWidth),
UInt32(numTraces)
))
}
// general information printout
println(s"Dromajo Bridge Information")
println(s" Total Inst. Traces / Commit Width: ${numTraces}")
}
}

View File

@ -12,7 +12,6 @@ clang_tidy_files := $(shell \
| grep -v TestPointerChaser.cc \
| grep -v simif_ \
| grep -v tracerv \
| grep -v dromajo \
| grep -v tsibridge \
| grep -v fesvr \
| grep -v generated-src \

View File

@ -5,44 +5,21 @@
# Driver Sources & Flags #
##########################
# dromajo modifications
DROMAJO_LIB_DIR ?= $(CONDA_PREFIX)/lib
DROMAJO_INCLUDE_DIR ?= $(CONDA_PREFIX)/include
DROMAJO_LIB_NAME = dromajo_cosim
DROMAJO_H = $(GENERATED_DIR)/dromajo_params.h
DROMAJO_LONG_H = $(GENERATED_DIR)/$(long_name).dromajo_params.h
TESTCHIPIP_CSRC_DIR = $(chipyard_dir)/generators/testchipip/src/main/resources/testchipip/csrc
CHIPYARD_ROM = $(chipyard_dir)/generators/testchipip/bootrom/bootrom.rv64.img
DROMAJO_ROM = $(GENERATED_DIR)/$(long_name).rom
DTS_FILE = $(GENERATED_DIR)/$(long_name).dts
DROMAJO_DTB = $(GENERATED_DIR)/$(long_name).dtb
$(DROMAJO_LONG_H) $(DTS_FILE): $(simulator_verilog)
$(DROMAJO_H): $(DROMAJO_LONG_H)
rm -rf $(DROMAJO_H)
ln -s $(DROMAJO_LONG_H) $(DROMAJO_H)
$(DROMAJO_DTB): $(DTS_FILE)
dtc -I dts -O dtb -o $(DROMAJO_DTB) $(DTS_FILE)
$(DROMAJO_ROM): $(CHIPYARD_ROM)
rm -rf $(DROMAJO_ROM)
ln -s $(CHIPYARD_ROM) $(DROMAJO_ROM)
DROMAJO_REQS = $(DROMAJO_H) $(DROMAJO_ROM) $(DROMAJO_DTB)
ifeq (,$(wildcard $(RISCV)/lib/libriscv.so))
$(warning libriscv not found)
LRISCV=
else
LRISCV=-lriscv
endif
firesim_lib_dir = $(firesim_base_dir)/firesim-lib/src/main/cc
driver_dir = $(firesim_base_dir)/src/main/cc
DRIVER_H = \
$(shell find $(driver_dir) -name "*.h") \
$(shell find $(firesim_lib_dir) -name "*.h") \
$(DROMAJO_REQS) \
$(TESTCHIPIP_CSRC_DIR)/cospike_impl.h \
$(TESTCHIPIP_CSRC_DIR)/testchip_tsi.h \
$(TESTCHIPIP_CSRC_DIR)/testchip_htif.h
@ -50,7 +27,7 @@ DRIVER_CC = \
$(addprefix $(driver_dir)/firesim/, $(addsuffix .cc, firesim_top)) \
$(wildcard $(addprefix $(firesim_lib_dir)/, $(addsuffix .cc, bridges/* fesvr/* bridges/tracerv/*))) \
$(RISCV)/lib/libfesvr.a \
$(DROMAJO_LIB_DIR)/lib$(DROMAJO_LIB_NAME).a \
$(TESTCHIPIP_CSRC_DIR)/cospike_impl.cc \
$(TESTCHIPIP_CSRC_DIR)/testchip_tsi.cc \
$(TESTCHIPIP_CSRC_DIR)/testchip_htif.cc
@ -58,10 +35,9 @@ DRIVER_CC = \
TARGET_CXX_FLAGS += -g \
-isystem $(RISCV)/include \
-isystem $(TESTCHIPIP_CSRC_DIR) \
-isystem $(DROMAJO_INCLUDE_DIR) \
-I$(driver_dir)/firesim \
-I$(firesim_lib_dir) \
-I$(GENERATED_DIR) \
-Wno-inconsistent-missing-override
TARGET_LD_FLAGS += -L$(CONDA_PREFIX)/lib -l:libdwarf.so -l:libelf.so -lz
TARGET_LD_FLAGS += -L$(CONDA_PREFIX)/lib -l:libdwarf.so -l:libelf.so -lz -L$(RISCV)/lib -Wl,-rpath,$(RISCV)/lib $(LRISCV)
# DOC include end: Bridge Build System Changes

@ -1 +1 @@
Subproject commit 074c995a31ec04e1a920d4e8c353de8e84f34f4e
Subproject commit 5541582639f8c5feb578b91b75e5d660e37ed006