Merge pull request #1644 from firesim/cospike-integration
Remove Dromajo in favor of Spike cosimulation
This commit is contained in:
commit
dee9a78333
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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``.
|
|
@ -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.
|
|
|
@ -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
|
||||||
|
|
|
@ -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/`::
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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))
|
||||||
|
;
|
||||||
|
}
|
|
@ -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
|
|
@ -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))
|
|
||||||
;
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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}")
|
||||||
|
}
|
||||||
|
}
|
|
@ -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}")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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 \
|
||||||
|
|
|
@ -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
|
Loading…
Reference in New Issue