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 - conda-gcc-specs
- binutils - 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 - riscv-tools==1.0.3 # from ucb-bar channel - https://github.com/ucb-bar/riscv-tools-feedstock
# firemarshal deps # firemarshal deps

View File

@ -371,7 +371,6 @@ class RuntimeHWConfig:
command_linklatencies = array_to_plusargs(all_linklatencies, "+linklatency") command_linklatencies = array_to_plusargs(all_linklatencies, "+linklatency")
command_netbws = array_to_plusargs(all_netbws, "+netbw") command_netbws = array_to_plusargs(all_netbws, "+netbw")
command_shmemportnames = array_to_plusargs(all_shmemportnames, "+shmemportname") 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_niclogs = array_to_lognames(all_macs, "niclog")
command_blkdev_logs = array_to_lognames(all_rootfses, "blkdev-log") 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 += 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"{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 += [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 += [print_cycle_prefix, f"+print-start={synthprint_config.start}", f"+print-end={synthprint_config.end}"]
permissive_driver_args += command_linklatencies permissive_driver_args += command_linklatencies
permissive_driver_args += command_netbws 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 Debugging-Hardware-Using-ILA.rst
AutoCounter.rst AutoCounter.rst
TracerV-with-FlameGraph.rst TracerV-with-FlameGraph.rst
Dromajo.rst Cospike.rst
Debugging-Hanging-Simulators.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) # Run a specific integration test (desired)
make testOnly TARGET_PROJECT=midasexamples SCALA_TEST=firesim.midasexamples.GCDF1Test 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 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/`:: 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/" echo "$REQS_DIR does not exist, make sure you're calling this script from firesim/"
exit 1 exit 1
fi 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 = [ excludePaths = [
"glob:**firesim-lib/src/main/scala/bridges/BlockDevBridge.scala", "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/GroundTestBridge.scala",
"glob:**firesim-lib/src/main/scala/bridges/TSIBridge.scala", "glob:**firesim-lib/src/main/scala/bridges/TSIBridge.scala",
"glob:**firesim-lib/src/main/scala/bridges/SimpleNICBridge.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 TestPointerChaser.cc \
| grep -v simif_ \ | grep -v simif_ \
| grep -v tracerv \ | grep -v tracerv \
| grep -v dromajo \
| grep -v tsibridge \ | grep -v tsibridge \
| grep -v fesvr \ | grep -v fesvr \
| grep -v generated-src \ | grep -v generated-src \

View File

@ -5,44 +5,21 @@
# Driver Sources & Flags # # 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 TESTCHIPIP_CSRC_DIR = $(chipyard_dir)/generators/testchipip/src/main/resources/testchipip/csrc
CHIPYARD_ROM = $(chipyard_dir)/generators/testchipip/bootrom/bootrom.rv64.img ifeq (,$(wildcard $(RISCV)/lib/libriscv.so))
DROMAJO_ROM = $(GENERATED_DIR)/$(long_name).rom $(warning libriscv not found)
LRISCV=
DTS_FILE = $(GENERATED_DIR)/$(long_name).dts else
DROMAJO_DTB = $(GENERATED_DIR)/$(long_name).dtb LRISCV=-lriscv
endif
$(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)
firesim_lib_dir = $(firesim_base_dir)/firesim-lib/src/main/cc firesim_lib_dir = $(firesim_base_dir)/firesim-lib/src/main/cc
driver_dir = $(firesim_base_dir)/src/main/cc driver_dir = $(firesim_base_dir)/src/main/cc
DRIVER_H = \ DRIVER_H = \
$(shell find $(driver_dir) -name "*.h") \ $(shell find $(driver_dir) -name "*.h") \
$(shell find $(firesim_lib_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_tsi.h \
$(TESTCHIPIP_CSRC_DIR)/testchip_htif.h $(TESTCHIPIP_CSRC_DIR)/testchip_htif.h
@ -50,7 +27,7 @@ DRIVER_CC = \
$(addprefix $(driver_dir)/firesim/, $(addsuffix .cc, firesim_top)) \ $(addprefix $(driver_dir)/firesim/, $(addsuffix .cc, firesim_top)) \
$(wildcard $(addprefix $(firesim_lib_dir)/, $(addsuffix .cc, bridges/* fesvr/* bridges/tracerv/*))) \ $(wildcard $(addprefix $(firesim_lib_dir)/, $(addsuffix .cc, bridges/* fesvr/* bridges/tracerv/*))) \
$(RISCV)/lib/libfesvr.a \ $(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_tsi.cc \
$(TESTCHIPIP_CSRC_DIR)/testchip_htif.cc $(TESTCHIPIP_CSRC_DIR)/testchip_htif.cc
@ -58,10 +35,9 @@ DRIVER_CC = \
TARGET_CXX_FLAGS += -g \ TARGET_CXX_FLAGS += -g \
-isystem $(RISCV)/include \ -isystem $(RISCV)/include \
-isystem $(TESTCHIPIP_CSRC_DIR) \ -isystem $(TESTCHIPIP_CSRC_DIR) \
-isystem $(DROMAJO_INCLUDE_DIR) \
-I$(driver_dir)/firesim \ -I$(driver_dir)/firesim \
-I$(firesim_lib_dir) \ -I$(firesim_lib_dir) \
-I$(GENERATED_DIR) \ -I$(GENERATED_DIR) \
-Wno-inconsistent-missing-override -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 # DOC include end: Bridge Build System Changes

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