Update pulp_riscv_dbg to pulp-platform/riscv-dbg@834853c
Update code from upstream repository https://github.com/pulp-
platform/riscv-dbg to revision
834853c0c68fc48d032a3e256e563f2b0bd28492
* Added missing reset to cmd_valid_q; fixes pulp-platform/riscv-dbg#28
(Arjan Bink)
* Update CHANGELOG.md with OBI wrapper addition (Arjan Bink)
* Add optional wrapper to make dm_top compatible to the OBI spec
(Arjan Bink)
* Avoid X's on hartinfo_i in assertion at time 0 (Eugene Feinberg)
* Fix dependency typo (Eugene Feinberg)
* Fix haltsum1-3 calculation (bluew)
* Update CHANGELOG.md (bluew)
* Make two scratch debug rom the default (Florian Zaruba)
* riscv-dbg: Make second scratch register optional (Florian Zaruba)
* Simplify cross compilation step (bluew)
* Add CI badge to README.md (bluew)
* Update CHANGELOG.md (bluew)
* Add tb running dm+ri5cy through OpenOCD compliance tests (bluew)
* Fixed a typo (: vs ::) in dp_mem.sv that crashed compilation
(Florian Glaser)
* Use correct bit width (pbing)
* Use explicit base address for data regiser access (bluew)
* Fix off-by-one error in data and progbuf end address (bluew)
* Correct typos in dm_csrs.sv (Felix Yan)
* Fix date in changelog (Philipp Wagner)
* Update CHANGELOG.md (bluew)
Signed-off-by: Michael Schaffner <msf@opentitan.org>
diff --git a/hw/vendor/patches/pulp_riscv_dbg/0001-Style-lint-cleanup-to-make-Verible-lint-happy.patch b/hw/vendor/patches/pulp_riscv_dbg/0001-Style-lint-cleanup-to-make-Verible-lint-happy.patch
new file mode 100644
index 0000000..1c5668c
--- /dev/null
+++ b/hw/vendor/patches/pulp_riscv_dbg/0001-Style-lint-cleanup-to-make-Verible-lint-happy.patch
@@ -0,0 +1,216 @@
+From 50425c66be52b7d97071e285e6899ed4e33484f1 Mon Sep 17 00:00:00 2001
+From: Michael Schaffner <msf@google.com>
+Date: Mon, 13 Jul 2020 19:25:04 -0700
+Subject: [PATCH 1/2] Style lint cleanup to make Verible lint happy
+
+Signed-off-by: Michael Schaffner <msf@google.com>
+---
+ src/dm_csrs.sv | 6 +++---
+ src/dm_mem.sv | 7 +++++--
+ src/dm_obi_top.sv | 50 ++++++++++++++++++++++++++---------------------
+ src/dm_pkg.sv | 2 +-
+ src/dm_sba.sv | 6 +++---
+ 5 files changed, 40 insertions(+), 31 deletions(-)
+
+diff --git a/src/dm_csrs.sv b/src/dm_csrs.sv
+index 78fd32a..f131392 100644
+--- a/src/dm_csrs.sv
++++ b/src/dm_csrs.sv
+@@ -91,8 +91,8 @@ module dm_csrs #(
+ logic resp_queue_pop;
+ logic [31:0] resp_queue_data;
+
+- localparam dm::dm_csr_e DataEnd = dm::dm_csr_e'(dm::Data0 + {4'b0, dm::DataCount} - 8'h01);
+- localparam dm::dm_csr_e ProgBufEnd = dm::dm_csr_e'(dm::ProgBuf0 + {4'b0, dm::ProgBufSize} - 8'h01);
++ localparam dm::dm_csr_e DataEnd = dm::dm_csr_e'(dm::Data0 + {4'b0, dm::DataCount} - 8'h1);
++ localparam dm::dm_csr_e ProgBufEnd = dm::dm_csr_e'(dm::ProgBuf0 + {4'b0, dm::ProgBufSize} - 8'h1);
+
+ logic [31:0] haltsum0, haltsum1, haltsum2, haltsum3;
+ logic [((NrHarts-1)/2**5 + 1) * 32 - 1 : 0] halted;
+@@ -521,7 +521,7 @@ module dm_csrs #(
+ dmcontrol_d.resumereq = 1'b0;
+ end
+ // static values for dcsr
+- sbcs_d.sbversion = 3'b1;
++ sbcs_d.sbversion = 3'd1;
+ sbcs_d.sbbusy = sbbusy_i;
+ sbcs_d.sbasize = $bits(sbcs_d.sbasize)'(BusWidth);
+ sbcs_d.sbaccess128 = 1'b0;
+diff --git a/src/dm_mem.sv b/src/dm_mem.sv
+index 6f0da5e..550b7cc 100755
+--- a/src/dm_mem.sv
++++ b/src/dm_mem.sv
+@@ -336,7 +336,8 @@ module dm_mem #(
+ abstract_cmd[0][31:0] = dm::illegal();
+ // load debug module base address into a0, this is shared among all commands
+ abstract_cmd[0][63:32] = HasSndScratch ? dm::auipc(5'd10, '0) : dm::nop();
+- abstract_cmd[1][31:0] = HasSndScratch ? dm::srli(5'd10, 5'd10, 6'd12) : dm::nop(); // clr lowest 12b -> DM base offset
++ // clr lowest 12b -> DM base offset
++ abstract_cmd[1][31:0] = HasSndScratch ? dm::srli(5'd10, 5'd10, 6'd12) : dm::nop();
+ abstract_cmd[1][63:32] = HasSndScratch ? dm::slli(5'd10, 5'd10, 6'd12) : dm::nop();
+ abstract_cmd[2][31:0] = dm::nop();
+ abstract_cmd[2][63:32] = dm::nop();
+@@ -395,7 +396,9 @@ module dm_mem #(
+ end
+ end else if (32'(ac_ar.aarsize) < MaxAar && ac_ar.transfer && !ac_ar.write) begin
+ // store a0 in dscratch1
+- abstract_cmd[0][31:0] = HasSndScratch ? dm::csrr(dm::CSR_DSCRATCH1, LoadBaseAddr) : dm::nop();
++ abstract_cmd[0][31:0] = HasSndScratch ?
++ dm::csrr(dm::CSR_DSCRATCH1, LoadBaseAddr) :
++ dm::nop();
+ // this range is reserved
+ if (ac_ar.regno[15:14] != '0) begin
+ abstract_cmd[0][31:0] = dm::ebreak(); // we leave asap
+diff --git a/src/dm_obi_top.sv b/src/dm_obi_top.sv
+index 635f37e..190830c 100644
+--- a/src/dm_obi_top.sv
++++ b/src/dm_obi_top.sv
+@@ -61,42 +61,48 @@
+ ////////////////////////////////////////////////////////////////////////////////
+
+ module dm_obi_top #(
+- parameter int unsigned IdWidth = 1, // Width of aid/rid
++ parameter int unsigned IdWidth = 1, // Width of aid/rid
+ parameter int unsigned NrHarts = 1,
+ parameter int unsigned BusWidth = 32,
+- parameter int unsigned DmBaseAddress = 'h1000, // default to non-zero page
++ parameter int unsigned DmBaseAddress = 'h1000, // default to non-zero page
+ // Bitmask to select physically available harts for systems
+ // that don't use hart numbers in a contiguous fashion.
+ parameter logic [NrHarts-1:0] SelectableHarts = {NrHarts{1'b1}}
+ ) (
+- input logic clk_i, // clock
+- input logic rst_ni, // asynchronous reset active low, connect PoR here, not the system reset
++ input logic clk_i, // clock
++ // asynchronous reset active low, connect PoR here, not the system reset
++ input logic rst_ni,
+ input logic testmode_i,
+- output logic ndmreset_o, // non-debug module reset
+- output logic dmactive_o, // debug module is active
+- output logic [NrHarts-1:0] debug_req_o, // async debug request
+- input logic [NrHarts-1:0] unavailable_i, // communicate whether the hart is unavailable (e.g.: power down)
++ output logic ndmreset_o, // non-debug module reset
++ output logic dmactive_o, // debug module is active
++ output logic [NrHarts-1:0] debug_req_o, // async debug request
++ // communicate whether the hart is unavailable (e.g.: power down)
++ input logic [NrHarts-1:0] unavailable_i,
+ dm::hartinfo_t [NrHarts-1:0] hartinfo_i,
+
+ input logic slave_req_i,
+- output logic slave_gnt_o, // OBI grant for slave_req_i (not present on dm_top)
++ // OBI grant for slave_req_i (not present on dm_top)
++ output logic slave_gnt_o,
+ input logic slave_we_i,
+ input logic [BusWidth-1:0] slave_addr_i,
+ input logic [BusWidth/8-1:0] slave_be_i,
+ input logic [BusWidth-1:0] slave_wdata_i,
+- input logic [IdWidth-1:0] slave_aid_i, // Address phase transaction identifier (not present on dm_top)
+- output logic slave_rvalid_o, // OBI rvalid signal (end of response phase for reads/writes) (not present on dm_top)
++ // Address phase transaction identifier (not present on dm_top)
++ input logic [IdWidth-1:0] slave_aid_i,
++ // OBI rvalid signal (end of response phase for reads/writes) (not present on dm_top)
++ output logic slave_rvalid_o,
+ output logic [BusWidth-1:0] slave_rdata_o,
+- output logic [IdWidth-1:0] slave_rid_o, // Response phase transaction identifier (not present on dm_top)
++ // Response phase transaction identifier (not present on dm_top)
++ output logic [IdWidth-1:0] slave_rid_o,
+
+ output logic master_req_o,
+- output logic [BusWidth-1:0] master_addr_o, // Renamed according to OBI spec
++ output logic [BusWidth-1:0] master_addr_o, // Renamed according to OBI spec
+ output logic master_we_o,
+ output logic [BusWidth-1:0] master_wdata_o,
+ output logic [BusWidth/8-1:0] master_be_o,
+ input logic master_gnt_i,
+- input logic master_rvalid_i, // Renamed according to OBI spec
+- input logic [BusWidth-1:0] master_rdata_i, // Renamed according to OBI spec
++ input logic master_rvalid_i, // Renamed according to OBI spec
++ input logic [BusWidth-1:0] master_rdata_i, // Renamed according to OBI spec
+
+ // Connection to DTM - compatible to RocketChip Debug Module
+ input logic dmi_rst_ni,
+@@ -137,13 +143,13 @@ module dm_obi_top #(
+ .slave_rdata_o ( slave_rdata_o ),
+
+ .master_req_o ( master_req_o ),
+- .master_add_o ( master_addr_o ), // Renamed according to OBI spec
++ .master_add_o ( master_addr_o ), // Renamed according to OBI spec
+ .master_we_o ( master_we_o ),
+ .master_wdata_o ( master_wdata_o ),
+ .master_be_o ( master_be_o ),
+ .master_gnt_i ( master_gnt_i ),
+- .master_r_valid_i ( master_rvalid_i ), // Renamed according to OBI spec
+- .master_r_rdata_i ( master_rdata_i ), // Renamed according to OBI spec
++ .master_r_valid_i ( master_rvalid_i ), // Renamed according to OBI spec
++ .master_r_rdata_i ( master_rdata_i ), // Renamed according to OBI spec
+
+ .dmi_rst_ni ( dmi_rst_ni ),
+ .dmi_req_valid_i ( dmi_req_valid_i ),
+@@ -165,16 +171,16 @@ module dm_obi_top #(
+ slave_rvalid_q <= 1'b0;
+ slave_rid_q <= 'b0;
+ end else begin
+- if (slave_req_i && slave_gnt_o) begin // 1 cycle pulse on rvalid for every granted request
++ if (slave_req_i && slave_gnt_o) begin // 1 cycle pulse on rvalid for every granted request
+ slave_rvalid_q <= 1'b1;
+- slave_rid_q <= slave_aid_i; // Mirror aid to rid
++ slave_rid_q <= slave_aid_i; // Mirror aid to rid
+ end else begin
+- slave_rvalid_q <= 1'b0; // rid is don't care if rvalid = 0
++ slave_rvalid_q <= 1'b0; // rid is don't care if rvalid = 0
+ end
+ end
+ end
+
+- assign slave_gnt_o = 1'b1; // Always receptive to request (slave_req_i)
++ assign slave_gnt_o = 1'b1; // Always receptive to request (slave_req_i)
+ assign slave_rvalid_o = slave_rvalid_q;
+ assign slave_rid_o = slave_rid_q;
+
+diff --git a/src/dm_pkg.sv b/src/dm_pkg.sv
+index de75c3e..1b7d0f5 100644
+--- a/src/dm_pkg.sv
++++ b/src/dm_pkg.sv
+@@ -201,7 +201,7 @@ package dm;
+ logic sbaccess8;
+ } sbcs_t;
+
+- localparam logic[1:0] DTM_SUCCESS = 2'h0;
++ localparam logic [1:0] DTM_SUCCESS = 2'h0;
+
+ typedef struct packed {
+ logic [6:0] addr;
+diff --git a/src/dm_sba.sv b/src/dm_sba.sv
+index f605088..c97f956 100644
+--- a/src/dm_sba.sv
++++ b/src/dm_sba.sv
+@@ -104,7 +104,7 @@ module dm_sba #(
+ be[int'({be_idx[$high(be_idx):1], 1'b0}) +: 2] = '1;
+ end
+ 3'b010: begin
+- if (BusWidth == 32'd64) be[int'({be_idx[$high(be_idx)], 2'b0}) +: 4] = '1;
++ if (BusWidth == 32'd64) be[int'({be_idx[$high(be_idx)], 2'h0}) +: 4] = '1;
+ else be = '1;
+ end
+ 3'b011: be = '1;
+@@ -117,7 +117,7 @@ module dm_sba #(
+ if (sbdata_valid_o) begin
+ state_d = Idle;
+ // auto-increment address
+- if (sbautoincrement_i) sbaddress_o = sbaddress_i + (32'b1 << sbaccess_i);
++ if (sbautoincrement_i) sbaddress_o = sbaddress_i + (32'h1 << sbaccess_i);
+ end
+ end
+
+@@ -125,7 +125,7 @@ module dm_sba #(
+ if (sbdata_valid_o) begin
+ state_d = Idle;
+ // auto-increment address
+- if (sbautoincrement_i) sbaddress_o = sbaddress_i + (32'b1 << sbaccess_i);
++ if (sbautoincrement_i) sbaddress_o = sbaddress_i + (32'h1 << sbaccess_i);
+ end
+ end
+
+--
+2.27.0.389.gc38d7665816-goog
+
diff --git a/hw/vendor/patches/pulp_riscv_dbg/0001-Use-lowrisc-instead-of-PULP-primitives.patch b/hw/vendor/patches/pulp_riscv_dbg/0002-Use-lowrisc-instead-of-PULP-primitives.patch
similarity index 95%
rename from hw/vendor/patches/pulp_riscv_dbg/0001-Use-lowrisc-instead-of-PULP-primitives.patch
rename to hw/vendor/patches/pulp_riscv_dbg/0002-Use-lowrisc-instead-of-PULP-primitives.patch
index af45482..6aa3270 100644
--- a/hw/vendor/patches/pulp_riscv_dbg/0001-Use-lowrisc-instead-of-PULP-primitives.patch
+++ b/hw/vendor/patches/pulp_riscv_dbg/0002-Use-lowrisc-instead-of-PULP-primitives.patch
@@ -1,7 +1,7 @@
-From 2179b843c1a753642d803918170c21d6e74b9beb Mon Sep 17 00:00:00 2001
+From 570145de9ffca99595e2fee9fcfb433fee6c3610 Mon Sep 17 00:00:00 2001
From: Philipp Wagner <phw@lowrisc.org>
Date: Fri, 22 Feb 2019 14:48:46 +0000
-Subject: [PATCH] Use lowrisc instead of PULP primitives
+Subject: [PATCH 2/2] Use lowrisc instead of PULP primitives
---
src/dm_csrs.sv | 42 +++++++++++++++-------------------
@@ -10,7 +10,7 @@
3 files changed, 60 insertions(+), 58 deletions(-)
diff --git a/src/dm_csrs.sv b/src/dm_csrs.sv
-index 807bb19..6f9028b 100644
+index f131392..b7fc5e1 100644
--- a/src/dm_csrs.sv
+++ b/src/dm_csrs.sv
@@ -78,6 +78,7 @@ module dm_csrs #(
@@ -31,7 +31,7 @@
- logic resp_queue_pop;
logic [31:0] resp_queue_data;
- localparam dm::dm_csr_e DataEnd = dm::dm_csr_e'((dm::Data0 + {4'b0, dm::DataCount}));
+ localparam dm::dm_csr_e DataEnd = dm::dm_csr_e'(dm::Data0 + {4'b0, dm::DataCount} - 8'h1);
@@ -180,9 +177,6 @@ module dm_csrs #(
// a successful response returns zero
@@ -190,5 +190,5 @@
// TDO changes state at negative edge of TCK
--
-2.25.0.341.g760bfbb309-goog
+2.27.0.389.gc38d7665816-goog
diff --git a/hw/vendor/pulp_riscv_dbg.lock.hjson b/hw/vendor/pulp_riscv_dbg.lock.hjson
index a72162c..e4f3ad5 100644
--- a/hw/vendor/pulp_riscv_dbg.lock.hjson
+++ b/hw/vendor/pulp_riscv_dbg.lock.hjson
@@ -9,6 +9,6 @@
upstream:
{
url: https://github.com/pulp-platform/riscv-dbg
- rev: 2b1e9d09614c2bf2774f897c5151697cd6f034ed
+ rev: 834853c0c68fc48d032a3e256e563f2b0bd28492
}
}
diff --git a/hw/vendor/pulp_riscv_dbg/.travis.yml b/hw/vendor/pulp_riscv_dbg/.travis.yml
new file mode 100644
index 0000000..7d8bce5
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/.travis.yml
@@ -0,0 +1,85 @@
+language: cpp
+# run on new infrastructure
+dist: xenial
+sudo: false
+cache:
+ apt: true
+ directories:
+ $RISCV
+ $VERILATOR_ROOT
+ timeout: 1000
+
+# required packages to install
+addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ packages:
+ - gcc-7
+ - g++-7
+ - gperf
+ - autoconf
+ - automake
+ - autotools-dev
+ - libmpc-dev
+ - libmpfr-dev
+ - libgmp-dev
+ - gawk
+ - build-essential
+ - bison
+ - flex
+ - texinfo
+ - python-pexpect
+ - libusb-1.0-0-dev
+ - default-jdk
+ - zlib1g-dev
+ - valgrind
+env:
+ global:
+ - RISCV="/home/travis/riscv_install"
+ - VERILATOR_ROOT="/home/travis/verilator-4.018"
+
+
+before_install:
+ - export CXX=g++-7 CC=gcc-7
+ # setup dependent paths
+ - export PATH=$RISCV/bin:$VERILATOR_ROOT/bin:$PATH
+ - export LIBRARY_PATH=$RISCV/lib
+ - export LD_LIBRARY_PATH=$RISCV/lib
+ - export C_INCLUDE_PATH=$RISCV/include:$VERILATOR_ROOT/share/verilator/include
+ - export CPLUS_INCLUDE_PATH=$RISCV/include:$VERILATOR_ROOT/share/verilator/include
+ - export PKG_CONFIG_PATH=$VERILATOR_ROOT/share/pkgconfig
+ # number of parallel jobs to use for make commands and simulation
+ - export NUM_JOBS=4
+ - ci/make-tmp.sh
+ - git submodule update --init --recursive
+
+stages:
+ - download
+ - compile1
+ - compile2
+ - test
+
+jobs:
+ include:
+ - stage: download
+ name: download pulp gcc
+ script:
+ - ci/download-pulp-gcc.sh
+
+ - stage: compile2
+ name: build verilator
+ script:
+ - ci/install-verilator.sh
+ - stage: compile2
+ name: build openocd
+ script:
+ - ci/get-openocd.sh
+
+ - stage: test
+ name: run openocd debug module tests
+ script:
+ - ci/veri-run-openocd-compliance.sh
+
+# extra time during long builds
+install: travis_wait
diff --git a/hw/vendor/pulp_riscv_dbg/Bender.yml b/hw/vendor/pulp_riscv_dbg/Bender.yml
index 3b4f7f7..150a79d 100644
--- a/hw/vendor/pulp_riscv_dbg/Bender.yml
+++ b/hw/vendor/pulp_riscv_dbg/Bender.yml
@@ -5,9 +5,11 @@
files:
- src/dm_pkg.sv
- debug_rom/debug_rom.sv
+ - debug_rom/debug_rom_snd_scratch.sv
- src/dm_csrs.sv
- src/dm_mem.sv
- src/dm_top.sv
+ - src/dm_obi_top.sv
- src/dmi_cdc.sv
- src/dmi_jtag.sv
- src/dmi_jtag_tap.sv
diff --git a/hw/vendor/pulp_riscv_dbg/CHANGELOG.md b/hw/vendor/pulp_riscv_dbg/CHANGELOG.md
index 7acfa6d..f95fde8 100644
--- a/hw/vendor/pulp_riscv_dbg/CHANGELOG.md
+++ b/hw/vendor/pulp_riscv_dbg/CHANGELOG.md
@@ -5,7 +5,37 @@
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [Unreleased]
+
+### Added
+- Optional wrapper `dm_obi_top.sv` that wraps `dm_top` providing an OBI compliant interface
+- `tb` that runs dm in conjunction with ri5cy and OpenOCD
+- `.travis-ci.yml` running `tb` with verilator
+
+### Changed
+- Made second scratch register optional (default is two) from [@zarubaf](https://github.com/zarubaf
+
+### Fixed
+- Off-by-one error in data and progbuf end address from [@pbing](https://github.com/pbing)
+- Haltsum1-3 calculation
+
+## [0.3.0] - 2020-01-23
+
+### Added
+- Documentation in `doc/` from [@imphil](https://github.com/imphil)
+
+### Changed
+- Various linting issues and cleanups from [@msfschaffner](https://github.com/msfschaffner)
+
+### Fixed
+- Corruption on debug exception entry [@tomroberts-lowrisc](https://github.com/tomroberts-lowrisc)
+- truncation of `selected_hart`
+
+## [0.2.0] - 2019-08-16
+
+## Added
- Add Bender.yml
+
+### Fixed
- Fix haltsum1, haltsum2 and haltsum3
- Fix minor linter issues
diff --git a/hw/vendor/pulp_riscv_dbg/README.md b/hw/vendor/pulp_riscv_dbg/README.md
index a5662d5..fe28e6d 100644
--- a/hw/vendor/pulp_riscv_dbg/README.md
+++ b/hw/vendor/pulp_riscv_dbg/README.md
@@ -1,3 +1,5 @@
+[](https://travis-ci.com/pulp-platform/riscv-dbg)
+
# RISC-V Debug Support for PULP Cores
This module is an implementation of a debug unit compliant with the [RISC-V
@@ -33,6 +35,5 @@
We use OpenOCD's [RISC-V compliance
tests](https://github.com/riscv/riscv-openocd/blob/riscv/src/target/riscv/riscv-013.c),
-our custom testbench in
-[PULPissimo](https://github.com/pulp-platform/pulpissimo) and
-[riscv-tests/debug](https://github.com/riscv/riscv-tests/tree/master/debug).
\ No newline at end of file
+our custom testbench in `tb/` and
+[riscv-tests/debug](https://github.com/riscv/riscv-tests/tree/master/debug).
diff --git a/hw/vendor/pulp_riscv_dbg/ci/download-pulp-gcc.sh b/hw/vendor/pulp_riscv_dbg/ci/download-pulp-gcc.sh
new file mode 100755
index 0000000..eaab8ad
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/ci/download-pulp-gcc.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+set -o pipefail
+set -e
+
+ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
+VERSION="v1.0.16"
+
+# mkdir -p $RISCV
+
+wget https://github.com/pulp-platform/pulp-riscv-gnu-toolchain/releases/download/$VERSION/$VERSION-pulp-riscv-gcc-ubuntu-16.tar.bz2
+echo "unpacking pulp gcc and installing to $RISCV"
+tar -xvf $VERSION-pulp-riscv-gcc-ubuntu-16.tar.bz2 -C "$RISCV" --strip 1
diff --git a/hw/vendor/pulp_riscv_dbg/ci/get-openocd.sh b/hw/vendor/pulp_riscv_dbg/ci/get-openocd.sh
new file mode 100755
index 0000000..5d37936
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/ci/get-openocd.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+
+set -e
+
+VERSION="af3a034b57279d2a400d87e7508c9a92254ec165"
+
+mkdir -p $RISCV/
+cd $RISCV
+
+check_version() {
+ $1 --version | awk "NR==1 {if (\$NF>$2) {exit 0} exit 1}" || (
+ echo $3 requires at least version $2 of $1. Aborting.
+ exit 1
+ )
+}
+
+
+if [ -z ${NUM_JOBS} ]; then
+ NUM_JOBS=1
+fi
+
+if ! [ -e $RISCV/bin/openocd ]; then
+ if ! [ -e $RISCV/riscv-openocd ]; then
+ git clone https://github.com/riscv/riscv-openocd.git
+ fi
+ check_version automake 1.14 "OpenOCD build"
+ check_version autoconf 2.64 "OpenOCD build"
+
+ cd riscv-openocd
+ git checkout $VERSION
+ git submodule update --init --recursive
+
+ echo "Compiling OpenOCD"
+ ./bootstrap
+ ./configure --prefix=$RISCV --disable-werror --disable-wextra --enable-remote-bitbang
+ make -j${NUM_JOBS}
+ make install
+ echo "Compilation Finished"
+fi
+
diff --git a/hw/vendor/pulp_riscv_dbg/ci/install-verilator.sh b/hw/vendor/pulp_riscv_dbg/ci/install-verilator.sh
new file mode 100755
index 0000000..2dae385
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/ci/install-verilator.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+set -e
+ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
+cd $ROOT/tmp
+
+if [ -z ${NUM_JOBS} ]; then
+ NUM_JOBS=1
+fi
+
+if [ ! -e "$VERILATOR_ROOT/bin/verilator" ]; then
+ echo "Installing Verilator"
+ rm -f verilator*.tgz
+ wget https://www.veripool.org/ftp/verilator-4.018.tgz
+ tar xzf verilator*.tgz
+ rm -f verilator*.tgz
+ cd verilator-4.018
+ mkdir -p $VERILATOR_ROOT
+ # copy scripts
+ autoconf && ./configure --prefix="$VERILATOR_ROOT" && make -j${NUM_JOBS}
+ make install
+ # not obvious to me why these symlinks are missing
+ ln -s $VERILATOR_ROOT/share/verilator/include $VERILATOR_ROOT/include
+ ln -s $VERILATOR_ROOT/share/verilator/bin/verilator_includer \
+ $VERILATOR_ROOT/bin/verilator_includer
+ make test
+else
+ echo "Using Verilator from cached directory."
+fi
diff --git a/hw/vendor/pulp_riscv_dbg/ci/make-tmp.sh b/hw/vendor/pulp_riscv_dbg/ci/make-tmp.sh
new file mode 100755
index 0000000..a3c34c1
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/ci/make-tmp.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+set -e
+cd "$(dirname "${BASH_SOURCE[0]}")/.."
+[ -d tmp ] || rm -rf tmp
+mkdir -p tmp
diff --git a/hw/vendor/pulp_riscv_dbg/ci/openocd-to-junit.py b/hw/vendor/pulp_riscv_dbg/ci/openocd-to-junit.py
new file mode 100755
index 0000000..392fb74
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/ci/openocd-to-junit.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python3
+import sys, getopt
+from junit_xml import *
+
+
+def main(argv):
+ inputfile = ''
+ outputfile = ''
+
+ try:
+ opts, args = getopt.getopt(argv,"hi:o:",["ifile=","ofile="])
+ except getopt.GetoptError:
+ print ('openocd-to-junit.py -i <inputfile> -o <outputfile>')
+ sys.exit(2)
+ for opt, arg in opts:
+ if opt == '-h':
+ print ('openocd-to-junit.py -i <inputfile> -o <outputfile>')
+ sys.exit()
+ elif opt in ("-i", "--ifile"):
+ inputfile = arg
+ elif opt in ("-o", "--ofile"):
+ outputfile = arg
+
+ test_strings = defaultdict(list)
+ test_timestamps = {}
+ current_testname = ''
+
+ test_cases = []
+ current_test_case = None
+
+ ocd_stdout = ''
+
+ with open(inputfile, 'r') as infile:
+ for line in infile:
+ if 'Info' in line and 'riscv013_test_compliance()' in line:
+ print(line.split(' '))
+ current_testname = ' '.join(line.split(' ')[7:])
+ test_strings[current_testname].append(line)
+ test_timestamps[current_testname] = line.split(' ')[3]
+
+ ocd_stdout += line
+
+ for k,v in test_strings.items():
+ current_test_case = TestCase(k, stdout=''.join(v),
+ timestamp=test_timestamps[k])
+ error_msg = ""
+ for line in v:
+ if 'FAILED' in line:
+ error_msg += line;
+
+ if error_msg:
+ current_test_case.add_error_info(error_msg)
+
+ test_cases.append(current_test_case)
+
+ ts = TestSuite("openocd-compliance", test_cases, stdout=ocd_stdout)
+ # pretty printing is on by default but can be disabled using prettyprint=False
+ with open(outputfile, 'w') as outfile:
+ TestSuite.to_file(outfile, [ts])
+
+if __name__ == "__main__":
+ main(sys.argv[1:])
diff --git a/hw/vendor/pulp_riscv_dbg/ci/run-openocd-compliance.sh b/hw/vendor/pulp_riscv_dbg/ci/run-openocd-compliance.sh
new file mode 100755
index 0000000..ad37aaa
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/ci/run-openocd-compliance.sh
@@ -0,0 +1,47 @@
+#!/usr/bin/env bash
+
+set -e
+
+ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
+
+if [ -z "${RISCV}" ]
+then
+ echo "RISCV is empty"
+ exit 1
+fi
+
+function cleanup {
+ echo "cleaning up processes and tmp files"
+ sleep 2
+ echo "vsim pid is:${vsim_pid} pgid:${vsim_pgid}"
+ if ps -p "${vsim_pid}" > /dev/null
+ then
+ echo "vsim pid exists, killing it"
+ kill -- -"${vsim_pgid}"
+ fi
+ rm "${vsim_out}"
+}
+
+trap cleanup EXIT
+
+vsim_out=$(mktemp)
+openocd_out=openocd.log
+
+make -C "${ROOT}"/tb/dm vsim-run &> "${vsim_out}"&
+# record vsim pid/pgid to kill it if it survives this script
+vsim_pid=$!
+vsim_pgid=$(ps -o pgid= ${vsim_pid} | grep -o [0-9]*)
+
+# block until we get "Listening on port" so that we are safe to connect openocd
+coproc grep -m 1 "Listening on port"
+tail -f -n0 "${vsim_out}" --pid "$COPROC_PID" >&"${COPROC[1]}"
+
+echo "Starting openocd"
+"${RISCV}"/bin/openocd -f "${ROOT}"/tb/dm/dm_compliance_test.cfg |& tee "${openocd_out}"
+
+
+if grep -q "ALL TESTS PASSED" "${openocd_out}"; then
+ exit 0
+fi
+exit 1
+
diff --git a/hw/vendor/pulp_riscv_dbg/ci/veri-run-openocd-compliance.sh b/hw/vendor/pulp_riscv_dbg/ci/veri-run-openocd-compliance.sh
new file mode 100755
index 0000000..09b5892
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/ci/veri-run-openocd-compliance.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+
+set -e
+
+ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
+
+if [ -z "${RISCV}" ]
+then
+ echo "RISCV is empty"
+ exit 1
+fi
+
+
+veri_out=$(mktemp)
+openocd_out=openocd.log
+
+make -C "${ROOT}"/tb veri-run |& tee "${veri_out}"&
+# record veri pid/pgid to kill it if it survives this script
+veri_pid=$!
+veri_pgid=$(ps -o pgid= ${veri_pid} | grep -o [0-9]*)
+
+# block until we get "Listening on port" so that we are safe to connect openocd
+coproc grep -m 1 "Listening on port"
+tail -f -n0 "${veri_out}" --pid "$COPROC_PID" >&"${COPROC[1]}"
+
+echo "Starting openocd"
+"${RISCV}"/bin/openocd -f "${ROOT}"/tb/dm_compliance_test.cfg |& tee "${openocd_out}"
+
+if grep -q "ALL TESTS PASSED" "${openocd_out}"; then
+ exit 0
+fi
+exit 1
+
diff --git a/hw/vendor/pulp_riscv_dbg/debug_rom/Makefile b/hw/vendor/pulp_riscv_dbg/debug_rom/Makefile
index cf44fb4..b23370a 100644
--- a/hw/vendor/pulp_riscv_dbg/debug_rom/Makefile
+++ b/hw/vendor/pulp_riscv_dbg/debug_rom/Makefile
@@ -1,6 +1,6 @@
# See LICENSE.SiFive for license details
-debug_rom = debug_rom.sv
+debug_rom = debug_rom.sv debug_rom_one_scratch.sv
GCC?=riscv64-unknown-elf-gcc
OBJCOPY?=riscv64-unknown-elf-objcopy
@@ -18,8 +18,8 @@
%.bin: %.elf
$(OBJCOPY) -O binary $< $@
-%.elf: %.S link.ld
- $(GCC) -I$(RISCV)/include -Tlink.ld $< -nostdlib -fPIC -static -Wl,--no-gc-sections -o $@
+%.elf: $(findstring debug_rom, $(debug_rom)).S link.ld
+ $(GCC) $(if $(findstring one_scratch,$@),,-DSND_SCRATCH=1) -I$(RISCV)/include -Tlink.ld $< -nostdlib -fPIC -static -Wl,--no-gc-sections -o $@
%.dump: %.elf
$(OBJDUMP) -d $< --disassemble-all --disassemble-zeroes --section=.text --section=.text.startup --section=.text.init --section=.data > $@
diff --git a/hw/vendor/pulp_riscv_dbg/debug_rom/debug_rom.S b/hw/vendor/pulp_riscv_dbg/debug_rom/debug_rom.S
index 089e043..2989c7e 100644
--- a/hw/vendor/pulp_riscv_dbg/debug_rom/debug_rom.S
+++ b/hw/vendor/pulp_riscv_dbg/debug_rom/debug_rom.S
@@ -2,6 +2,8 @@
#include "encoding.h"
+// The debugger can assume as second scratch register.
+// # define SND_SCRATCH 1
// These are implementation-specific addresses in the Debug Module
#define HALTED 0x100
#define GOING 0x104
@@ -36,24 +38,31 @@
// into the Abstract Data or Program Buffer registers.
fence
csrw CSR_DSCRATCH0, s0 // Save s0 to allow signaling MHARTID
+#ifdef SND_SCRATCH
csrw CSR_DSCRATCH1, a0 // Save a0 to allow loading arbitrary DM base
auipc a0, 0 // Get PC
srli a0, a0, 12 // And throw away lower 12 bits to get the DM base
slli a0, a0, 12
-
+#endif
// We continue to let the hart know that we are halted in order that
// a DM which was reset is still made aware that a hart is halted.
// We keep checking both whether there is something the debugger wants
// us to do, or whether we should resume.
entry_loop:
csrr s0, CSR_MHARTID
+#ifdef SND_SCRATCH
sw s0, HALTED(a0)
add s0, s0, a0
+#else
+ sw s0, HALTED(zero)
+#endif
lbu s0, FLAGS(s0) // 1 byte flag per hart. Only one hart advances here.
andi s0, s0, (1 << FLAG_GO)
bnez s0, going
csrr s0, CSR_MHARTID
+#ifdef SND_SCRATCH
add s0, s0, a0
+#endif
lbu s0, FLAGS(s0) // multiple harts can resume here
andi s0, s0, (1 << FLAG_RESUME)
bnez s0, resume
@@ -63,6 +72,7 @@
// We can only get here due to an exception while in debug mode. Hence,
// we do not need to save a0 to a scratch register as it has already
// been saved on debug entry.
+#ifdef SND_SCRATCH
auipc a0, 0 // Get POC
srli a0, a0, 12 // And throw away lower 12 bits to get the DM base
slli a0, a0, 12
@@ -71,20 +81,31 @@
// have been saved on debug entry. Restoring them here avoids issues
// with registers being overwritten by exceptions occuring during
// program buffer execution.
- csrr s0, CSR_DSCRATCH0 // Restore s0 here
csrr a0, CSR_DSCRATCH1 // Restore a0 here
+#else
+ sw zero, EXCEPTION(zero) // Let debug module know you got an exception.
+#endif
+ csrr s0, CSR_DSCRATCH0 // Restore s0 here
ebreak
going:
+#ifdef SND_SCRATCH
sw zero, GOING(a0) // When debug module sees this write, the GO flag is reset.
- csrr s0, CSR_DSCRATCH0 // Restore s0 here
csrr a0, CSR_DSCRATCH1 // Restore a0 here
+#else
+ sw zero, GOING(zero) // When debug module sees this write, the GO flag is reset.
+#endif
+ csrr s0, CSR_DSCRATCH0 // Restore s0 here
jal zero, whereto
_resume:
csrr s0, CSR_MHARTID
+#ifdef SND_SCRATCH
sw s0, RESUMING(a0) // When Debug Module sees this write, the RESUME flag is reset.
- csrr s0, CSR_DSCRATCH0 // Restore s0 here
csrr a0, CSR_DSCRATCH1 // Restore a0 here
+#else
+ sw s0, RESUMING(zero) // When Debug Module sees this write, the RESUME flag is reset.
+#endif
+ csrr s0, CSR_DSCRATCH0 // Restore s0 here
dret
// END OF ACTUAL "ROM" CONTENTS. BELOW IS JUST FOR LINKER SCRIPT.
diff --git a/hw/vendor/pulp_riscv_dbg/debug_rom/debug_rom.h b/hw/vendor/pulp_riscv_dbg/debug_rom/debug_rom.h
index ae5b42b..b4f2d35 100644
--- a/hw/vendor/pulp_riscv_dbg/debug_rom/debug_rom.h
+++ b/hw/vendor/pulp_riscv_dbg/debug_rom/debug_rom.h
@@ -28,17 +28,17 @@
0x00c55513,
0x00c51513,
0x10052623,
- 0x7b202473,
0x7b302573,
+ 0x7b202473,
0x00100073,
0x10052223,
- 0x7b202473,
0x7b302573,
+ 0x7b202473,
0xa85ff06f,
0xf1402473,
0x10852423,
- 0x7b202473,
0x7b302573,
+ 0x7b202473,
0x7b200073,
0x00000000
};
diff --git a/hw/vendor/pulp_riscv_dbg/debug_rom/debug_rom.sv b/hw/vendor/pulp_riscv_dbg/debug_rom/debug_rom.sv
index fdf2fe8..a0e0208 100644
--- a/hw/vendor/pulp_riscv_dbg/debug_rom/debug_rom.sv
+++ b/hw/vendor/pulp_riscv_dbg/debug_rom/debug_rom.sv
@@ -25,12 +25,12 @@
const logic [RomSize-1:0][63:0] mem = {
64'h00000000_7b200073,
- 64'h7b302573_7b202473,
+ 64'h7b202473_7b302573,
64'h10852423_f1402473,
- 64'ha85ff06f_7b302573,
- 64'h7b202473_10052223,
- 64'h00100073_7b302573,
- 64'h7b202473_10052623,
+ 64'ha85ff06f_7b202473,
+ 64'h7b302573_10052223,
+ 64'h00100073_7b202473,
+ 64'h7b302573_10052623,
64'h00c51513_00c55513,
64'h00000517_fd5ff06f,
64'hfa041ce3_00247413,
diff --git a/hw/vendor/pulp_riscv_dbg/debug_rom/debug_rom_one_scratch.h b/hw/vendor/pulp_riscv_dbg/debug_rom/debug_rom_one_scratch.h
new file mode 100644
index 0000000..625d66a
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/debug_rom/debug_rom_one_scratch.h
@@ -0,0 +1,32 @@
+// Auto-generated code
+
+const int reset_vec_size = 26;
+
+uint32_t reset_vec[reset_vec_size] = {
+ 0x00c0006f,
+ 0x0500006f,
+ 0x0340006f,
+ 0x0ff0000f,
+ 0x7b241073,
+ 0xf1402473,
+ 0x10802023,
+ 0x40044403,
+ 0x00147413,
+ 0x02041263,
+ 0xf1402473,
+ 0x40044403,
+ 0x00247413,
+ 0xfc0418e3,
+ 0xfddff06f,
+ 0x10002623,
+ 0x7b202473,
+ 0x00100073,
+ 0x10002223,
+ 0x7b202473,
+ 0xab1ff06f,
+ 0xf1402473,
+ 0x10802423,
+ 0x7b202473,
+ 0x7b200073,
+ 0x00000000
+};
diff --git a/hw/vendor/pulp_riscv_dbg/debug_rom/debug_rom_one_scratch.sv b/hw/vendor/pulp_riscv_dbg/debug_rom/debug_rom_one_scratch.sv
new file mode 100644
index 0000000..78d47be
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/debug_rom/debug_rom_one_scratch.sv
@@ -0,0 +1,59 @@
+/* Copyright 2018 ETH Zurich and University of Bologna.
+ * Copyright and related rights are licensed under the Solderpad Hardware
+ * License, Version 0.51 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+ * or agreed to in writing, software, hardware and materials distributed under
+ * this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ *
+ * File: $filename.v
+ *
+ * Description: Auto-generated bootrom
+ */
+
+// Auto-generated code
+module debug_rom_one_scratch (
+ input logic clk_i,
+ input logic req_i,
+ input logic [63:0] addr_i,
+ output logic [63:0] rdata_o
+);
+
+ localparam int unsigned RomSize = 13;
+
+ const logic [RomSize-1:0][63:0] mem = {
+ 64'h00000000_7b200073,
+ 64'h7b202473_10802423,
+ 64'hf1402473_ab1ff06f,
+ 64'h7b202473_10002223,
+ 64'h00100073_7b202473,
+ 64'h10002623_fddff06f,
+ 64'hfc0418e3_00247413,
+ 64'h40044403_f1402473,
+ 64'h02041263_00147413,
+ 64'h40044403_10802023,
+ 64'hf1402473_7b241073,
+ 64'h0ff0000f_0340006f,
+ 64'h0500006f_00c0006f
+ };
+
+ logic [$clog2(RomSize)-1:0] addr_q;
+
+ always_ff @(posedge clk_i) begin
+ if (req_i) begin
+ addr_q <= addr_i[$clog2(RomSize)-1+3:3];
+ end
+ end
+
+ // this prevents spurious Xes from propagating into
+ // the speculative fetch stage of the core
+ always_comb begin : p_outmux
+ rdata_o = '0;
+ if (addr_q < $clog2(RomSize)'(RomSize)) begin
+ rdata_o = mem[addr_q];
+ end
+ end
+
+endmodule
diff --git a/hw/vendor/pulp_riscv_dbg/doc/debug-system.md b/hw/vendor/pulp_riscv_dbg/doc/debug-system.md
index c11d02e..708aa92 100644
--- a/hw/vendor/pulp_riscv_dbg/doc/debug-system.md
+++ b/hw/vendor/pulp_riscv_dbg/doc/debug-system.md
@@ -9,6 +9,8 @@
- JTAG Debug Transport Module (DTM) according to the RISC-V Debug Specification.
- System Bus Access with generic 32 or 64 bit bus interface.
- Support for up to 2^20 harts through one Debug Module
+- Support for arbitrary memory location of DM
+- Support for one debug scratch register if the DM is located at the zero page.
## Description
@@ -205,11 +207,11 @@
Four debug-specific CSRs must be supported by the core, as described in the Debug Specification Section 4.8.
**Address** | **Name** | **Access** | **Description**
------------ | --------- | ----------------------------- | ------------------------
+----------- | --------- | ----------------------------- | ----------------------------------------------------------------------------
0x7b0 | dcsr | _field-dependent; check spec_ | Debug Control and Status
0x7b1 | dpc | RW from Debug Mode only | Debug PC
0x7b2 | dscratch0 | RW from Debug Mode only | Debug Scratch Register 0
-0x7b3 | dscratch1 | RW from Debug Mode only | Debug Scratch Register 1
+0x7b3 | dscratch1 | RW from Debug Mode only | Debug Scratch Register 1 (only required if DM is not located at address 0x0)
#### DRET Instruction
@@ -273,6 +275,66 @@
input logic [BusWidth-1:0] slave_wdata_i,
output logic [BusWidth-1:0] slave_rdata_o
```
+### OBI Bus Interface (optional)
+
+A wrapper (called dm_obi_top) is provided which wraps the Debug Module (dm_top) and makes it OBI compliant. This wrapper
+can be ignored (and dm_top can be used directly instead) in case of non OBI compatible systems.
+
+The OBI (Open Bus Interface) specification is at https://github.com/openhwgroup/core-v-docs/blob/master/cores/cv32e40p/.
+
+The Debug Module connects to the system bus as device, exposing the debug memory (the Program Buffer and the Debug ROM),
+and as host for the System Bus Access (SBA) functionality. The bus interface is according to the OBI specification in both cases.
+The bus width is configurable to be 32 or 64 bit using the `BusWidth` parameter. The transfer identifier width is configurable
+using the `IdWidth` parameter.
+
+#### Host (Master) OBI Interface
+
+Compared to dm_top the slave interface of dm_obi_top has the following additional signals: slave_gnt_o, slave_rvalid_o, slave_aid_i,
+slave_rid_o. Compared to dm_top the master interface of dm_obi_top has some renamed signals (master_addr_o, master_rvalid_i, master_rdata_i
+instead of master_add_o, master_r_valid_i, master_r_rdata_i).
+
+Both interfaces are OBI compliant.
+
+**Signal** | **Width (bit)** | **Direction** | **Description**
+---------- | --------------- | ------------- | ---------------------------------------------------------------------------------------------------------
+req | 1 | output | Request valid, must stay high until gnt is high for one cycle
+addr | BusWidth | output | Address, word aligned
+we | BusWidth | output | Write Enable, high for writes, low for reads. Sent together with req
+be | 1 | output | Byte Enable. Is set for the bytes to write/read, sent together with req
+wdata | BusWidth | output | Data to be written to device, sent together with req
+gnt | 1 | input | The device accepted the request. Host outputs may change in the next cycle.
+rvalid | 1 | input | r_rdata hold valid data when r_valid is high. This signal will be high for exactly one cycle per request.
+rdata | BusWidth | input | Data read from the device
+
+No error response is currently implemented.
+
+**SystemVerilog interface definition (host side)**
+
+```verilog
+output logic master_req_o,
+output logic [BusWidth-1:0] master_addr_o,
+output logic master_we_o,
+output logic [BusWidth-1:0] master_wdata_o,
+output logic [BusWidth/8-1:0] master_be_o,
+input logic master_gnt_i,
+input logic master_rvalid_i,
+input logic [BusWidth-1:0] master_rdata_i
+```
+
+**SystemVerilog interface definition (device side)**
+
+```verilog
+input logic slave_req_i,
+output logic slave_gnt_o,
+input logic slave_we_i,
+input logic [BusWidth-1:0] slave_addr_i,
+input logic [BusWidth/8-1:0] slave_be_i,
+input logic [BusWidth-1:0] slave_wdata_i,
+input logic [IdWidth-1:0] slave_aid_i,
+output logic slave_rvalid_o,
+output logic [BusWidth-1:0] slave_rdata_o,
+output logic [IdWidth-1:0] slave_rid_o
+```
### The Debug Module Interface (DMI)
diff --git a/hw/vendor/pulp_riscv_dbg/src/dm_csrs.sv b/hw/vendor/pulp_riscv_dbg/src/dm_csrs.sv
index f9c946a..b7fc5e1 100644
--- a/hw/vendor/pulp_riscv_dbg/src/dm_csrs.sv
+++ b/hw/vendor/pulp_riscv_dbg/src/dm_csrs.sv
@@ -48,8 +48,8 @@
output logic cmd_valid_o, // debugger writing to cmd field
output dm::command_t cmd_o, // abstract command
- input logic cmderror_valid_i, // an error occured
- input dm::cmderr_e cmderror_i, // this error occured
+ input logic cmderror_valid_i, // an error occurred
+ input dm::cmderr_e cmderror_i, // this error occurred
input logic cmdbusy_i, // cmd is currently busy executing
output logic [dm::ProgBufSize-1:0][31:0] progbuf_o, // to system bus
@@ -88,17 +88,17 @@
logic [31:0] resp_queue_data;
- localparam dm::dm_csr_e DataEnd = dm::dm_csr_e'((dm::Data0 + {4'b0, dm::DataCount}));
- localparam dm::dm_csr_e ProgBufEnd = dm::dm_csr_e'((dm::ProgBuf0 + {4'b0, dm::ProgBufSize}));
+ localparam dm::dm_csr_e DataEnd = dm::dm_csr_e'(dm::Data0 + {4'b0, dm::DataCount} - 8'h1);
+ localparam dm::dm_csr_e ProgBufEnd = dm::dm_csr_e'(dm::ProgBuf0 + {4'b0, dm::ProgBufSize} - 8'h1);
logic [31:0] haltsum0, haltsum1, haltsum2, haltsum3;
logic [((NrHarts-1)/2**5 + 1) * 32 - 1 : 0] halted;
logic [(NrHarts-1)/2**5:0][31:0] halted_reshaped0;
- logic [NrHarts/2**10:0][31:0] halted_reshaped1;
- logic [NrHarts/2**15:0][31:0] halted_reshaped2;
- logic [(NrHarts/2**10+1)*32-1:0] halted_flat1;
- logic [(NrHarts/2**15+1)*32-1:0] halted_flat2;
- logic [32-1:0] halted_flat3;
+ logic [(NrHarts-1)/2**10:0][31:0] halted_reshaped1;
+ logic [(NrHarts-1)/2**15:0][31:0] halted_reshaped2;
+ logic [((NrHarts-1)/2**10+1)*32-1:0] halted_flat1;
+ logic [((NrHarts-1)/2**15+1)*32-1:0] halted_flat2;
+ logic [31:0] halted_flat3;
// haltsum0
logic [14:0] hartsel_idx0;
@@ -120,12 +120,12 @@
haltsum1 = '0;
hartsel_idx1 = hartsel_o[19:10];
- for (int unsigned k = 0; k < NrHarts/2**5+1; k++) begin
+ for (int unsigned k = 0; k < (NrHarts-1)/2**5+1; k++) begin
halted_flat1[k] = |halted_reshaped0[k];
end
halted_reshaped1 = halted_flat1;
- if (hartsel_idx1 < 10'((NrHarts/2**10+1))) begin
+ if (hartsel_idx1 < 10'(((NrHarts-1)/2**10+1))) begin
haltsum1 = halted_reshaped1[hartsel_idx1];
end
end
@@ -137,12 +137,12 @@
haltsum2 = '0;
hartsel_idx2 = hartsel_o[19:15];
- for (int unsigned k = 0; k < NrHarts/2**10+1; k++) begin
+ for (int unsigned k = 0; k < (NrHarts-1)/2**10+1; k++) begin
halted_flat2[k] = |halted_reshaped1[k];
end
halted_reshaped2 = halted_flat2;
- if (hartsel_idx2 < 5'((NrHarts/2**15+1))) begin
+ if (hartsel_idx2 < 5'(((NrHarts-1)/2**15+1))) begin
haltsum2 = halted_reshaped2[hartsel_idx2];
end
end
@@ -515,7 +515,7 @@
dmcontrol_d.resumereq = 1'b0;
end
// static values for dcsr
- sbcs_d.sbversion = 3'b1;
+ sbcs_d.sbversion = 3'd1;
sbcs_d.sbbusy = sbbusy_i;
sbcs_d.sbasize = $bits(sbcs_d.sbasize)'(BusWidth);
sbcs_d.sbaccess128 = 1'b0;
@@ -574,6 +574,7 @@
// this is the only write-able bit during reset
cmderr_q <= dm::CmdErrNone;
command_q <= '0;
+ cmd_valid_q <= '0;
abstractauto_q <= '0;
progbuf_q <= '0;
data_q <= '0;
diff --git a/hw/vendor/pulp_riscv_dbg/src/dm_mem.sv b/hw/vendor/pulp_riscv_dbg/src/dm_mem.sv
old mode 100644
new mode 100755
index 938e883..550b7cc
--- a/hw/vendor/pulp_riscv_dbg/src/dm_mem.sv
+++ b/hw/vendor/pulp_riscv_dbg/src/dm_mem.sv
@@ -19,7 +19,8 @@
module dm_mem #(
parameter int unsigned NrHarts = 1,
parameter int unsigned BusWidth = 32,
- parameter logic [NrHarts-1:0] SelectableHarts = {NrHarts{1'b1}}
+ parameter logic [NrHarts-1:0] SelectableHarts = {NrHarts{1'b1}},
+ parameter int unsigned DmBaseAddress = '0
) (
input logic clk_i, // Clock
input logic rst_ni, // debug module reset
@@ -60,9 +61,12 @@
localparam int unsigned HartSelLen = (NrHarts == 1) ? 1 : $clog2(NrHarts);
localparam int unsigned NrHartsAligned = 2**HartSelLen;
localparam int unsigned MaxAar = (BusWidth == 64) ? 4 : 3;
+ localparam bit HasSndScratch = (DmBaseAddress != 0);
+ // Depending on whether we are at the zero page or not we either use `x0` or `x10/a0`
+ localparam logic [4:0] LoadBaseAddr = (DmBaseAddress == 0) ? 5'd0 : 5'd10;
localparam logic [DbgAddressBits-1:0] DataBaseAddr = (dm::DataAddr);
- localparam logic [DbgAddressBits-1:0] DataEndAddr = (dm::DataAddr + 4*dm::DataCount);
+ localparam logic [DbgAddressBits-1:0] DataEndAddr = (dm::DataAddr + 4*dm::DataCount - 1);
localparam logic [DbgAddressBits-1:0] ProgBufBaseAddr = (dm::DataAddr - 4*dm::ProgBufSize);
localparam logic [DbgAddressBits-1:0] ProgBufEndAddr = (dm::DataAddr - 1);
localparam logic [DbgAddressBits-1:0] AbstractCmdBaseAddr = (ProgBufBaseAddr - 4*10);
@@ -252,7 +256,7 @@
// an exception occurred during execution
ExceptionAddr: exception = 1'b1;
// core can write data registers
- [(dm::DataAddr):DataEndAddr]: begin
+ [DataBaseAddr:DataEndAddr]: begin
data_valid_o = 1'b1;
for (int i = 0; i < $bits(be_i); i++) begin
if (be_i[i]) begin
@@ -331,14 +335,15 @@
// if ac_ar.transfer is not set then we can take a shortcut to the program buffer
abstract_cmd[0][31:0] = dm::illegal();
// load debug module base address into a0, this is shared among all commands
- abstract_cmd[0][63:32] = dm::auipc(5'd10, '0);
- abstract_cmd[1][31:0] = dm::srli(5'd10, 5'd10, 6'd12); // clr lowest 12b -> DM base offset
- abstract_cmd[1][63:32] = dm::slli(5'd10, 5'd10, 6'd12);
+ abstract_cmd[0][63:32] = HasSndScratch ? dm::auipc(5'd10, '0) : dm::nop();
+ // clr lowest 12b -> DM base offset
+ abstract_cmd[1][31:0] = HasSndScratch ? dm::srli(5'd10, 5'd10, 6'd12) : dm::nop();
+ abstract_cmd[1][63:32] = HasSndScratch ? dm::slli(5'd10, 5'd10, 6'd12) : dm::nop();
abstract_cmd[2][31:0] = dm::nop();
abstract_cmd[2][63:32] = dm::nop();
abstract_cmd[3][31:0] = dm::nop();
abstract_cmd[3][63:32] = dm::nop();
- abstract_cmd[4][31:0] = dm::csrr(dm::CSR_DSCRATCH1, 5'd10);
+ abstract_cmd[4][31:0] = HasSndScratch ? dm::csrr(dm::CSR_DSCRATCH1, 5'd10) : dm::nop();
abstract_cmd[4][63:32] = dm::ebreak();
abstract_cmd[7:5] = '0;
@@ -350,19 +355,19 @@
dm::AccessRegister: begin
if (32'(ac_ar.aarsize) < MaxAar && ac_ar.transfer && ac_ar.write) begin
// store a0 in dscratch1
- abstract_cmd[0][31:0] = dm::csrw(dm::CSR_DSCRATCH1, 5'd10);
+ abstract_cmd[0][31:0] = HasSndScratch ? dm::csrr(dm::CSR_DSCRATCH1, 5'd10) : dm::nop();
// this range is reserved
if (ac_ar.regno[15:14] != '0) begin
abstract_cmd[0][31:0] = dm::ebreak(); // we leave asap
unsupported_command = 1'b1;
// A0 access needs to be handled separately, as we use A0 to load
// the DM address offset need to access DSCRATCH1 in this case
- end else if (ac_ar.regno[12] && (!ac_ar.regno[5]) &&
+ end else if (HasSndScratch && ac_ar.regno[12] && (!ac_ar.regno[5]) &&
(ac_ar.regno[4:0] == 5'd10)) begin
// store s0 in dscratch
abstract_cmd[2][31:0] = dm::csrw(dm::CSR_DSCRATCH0, 5'd8);
// load from data register
- abstract_cmd[2][63:32] = dm::load(ac_ar.aarsize, 5'd8, 5'd10, dm::DataAddr);
+ abstract_cmd[2][63:32] = dm::load(ac_ar.aarsize, 5'd8, LoadBaseAddr, dm::DataAddr);
// and store it in the corresponding CSR
abstract_cmd[3][31:0] = dm::csrw(dm::CSR_DSCRATCH1, 5'd8);
// restore s0 again from dscratch
@@ -372,10 +377,10 @@
// determine whether we want to access the floating point register or not
if (ac_ar.regno[5]) begin
abstract_cmd[2][31:0] =
- dm::float_load(ac_ar.aarsize, ac_ar.regno[4:0], 5'd10, dm::DataAddr);
+ dm::float_load(ac_ar.aarsize, ac_ar.regno[4:0], LoadBaseAddr, dm::DataAddr);
end else begin
abstract_cmd[2][31:0] =
- dm::load(ac_ar.aarsize, ac_ar.regno[4:0], 5'd10, dm::DataAddr);
+ dm::load(ac_ar.aarsize, ac_ar.regno[4:0], LoadBaseAddr, dm::DataAddr);
end
// CSR access
end else begin
@@ -383,7 +388,7 @@
// store s0 in dscratch
abstract_cmd[2][31:0] = dm::csrw(dm::CSR_DSCRATCH0, 5'd8);
// load from data register
- abstract_cmd[2][63:32] = dm::load(ac_ar.aarsize, 5'd8, 5'd10, dm::DataAddr);
+ abstract_cmd[2][63:32] = dm::load(ac_ar.aarsize, 5'd8, LoadBaseAddr, dm::DataAddr);
// and store it in the corresponding CSR
abstract_cmd[3][31:0] = dm::csrw(dm::csr_reg_t'(ac_ar.regno[11:0]), 5'd8);
// restore s0 again from dscratch
@@ -391,21 +396,23 @@
end
end else if (32'(ac_ar.aarsize) < MaxAar && ac_ar.transfer && !ac_ar.write) begin
// store a0 in dscratch1
- abstract_cmd[0][31:0] = dm::csrw(dm::CSR_DSCRATCH1, 5'd10);
+ abstract_cmd[0][31:0] = HasSndScratch ?
+ dm::csrr(dm::CSR_DSCRATCH1, LoadBaseAddr) :
+ dm::nop();
// this range is reserved
if (ac_ar.regno[15:14] != '0) begin
abstract_cmd[0][31:0] = dm::ebreak(); // we leave asap
unsupported_command = 1'b1;
// A0 access needs to be handled separately, as we use A0 to load
// the DM address offset need to access DSCRATCH1 in this case
- end else if (ac_ar.regno[12] && (!ac_ar.regno[5]) &&
+ end else if (HasSndScratch && ac_ar.regno[12] && (!ac_ar.regno[5]) &&
(ac_ar.regno[4:0] == 5'd10)) begin
// store s0 in dscratch
abstract_cmd[2][31:0] = dm::csrw(dm::CSR_DSCRATCH0, 5'd8);
// read value from CSR into s0
abstract_cmd[2][63:32] = dm::csrr(dm::CSR_DSCRATCH1, 5'd8);
// and store s0 into data section
- abstract_cmd[3][31:0] = dm::store(ac_ar.aarsize, 5'd8, 5'd10, dm::DataAddr);
+ abstract_cmd[3][31:0] = dm::store(ac_ar.aarsize, 5'd8, LoadBaseAddr, dm::DataAddr);
// restore s0 again from dscratch
abstract_cmd[3][63:32] = dm::csrr(dm::CSR_DSCRATCH0, 5'd8);
// GPR/FPR access
@@ -413,10 +420,10 @@
// determine whether we want to access the floating point register or not
if (ac_ar.regno[5]) begin
abstract_cmd[2][31:0] =
- dm::float_store(ac_ar.aarsize, ac_ar.regno[4:0], 5'd10, dm::DataAddr);
+ dm::float_store(ac_ar.aarsize, ac_ar.regno[4:0], LoadBaseAddr, dm::DataAddr);
end else begin
abstract_cmd[2][31:0] =
- dm::store(ac_ar.aarsize, ac_ar.regno[4:0], 5'd10, dm::DataAddr);
+ dm::store(ac_ar.aarsize, ac_ar.regno[4:0], LoadBaseAddr, dm::DataAddr);
end
// CSR access
end else begin
@@ -426,7 +433,7 @@
// read value from CSR into s0
abstract_cmd[2][63:32] = dm::csrr(dm::csr_reg_t'(ac_ar.regno[11:0]), 5'd8);
// and store s0 into data section
- abstract_cmd[3][31:0] = dm::store(ac_ar.aarsize, 5'd8, 5'd10, dm::DataAddr);
+ abstract_cmd[3][31:0] = dm::store(ac_ar.aarsize, 5'd8, LoadBaseAddr, dm::DataAddr);
// restore s0 again from dscratch
abstract_cmd[3][63:32] = dm::csrr(dm::CSR_DSCRATCH0, 5'd8);
end
@@ -459,12 +466,31 @@
logic [63:0] rom_addr;
assign rom_addr = 64'(addr_i);
- debug_rom i_debug_rom (
- .clk_i,
- .req_i,
- .addr_i ( rom_addr ),
- .rdata_o ( rom_rdata )
- );
+
+ // Depending on whether the debug module is located
+ // at the zero page we can instantiate a simplified version
+ // which only requires one scratch register per hart.
+ // For all other cases we need to set aside
+ // two registers per hart, hence we also need
+ // two scratch registers.
+ if (HasSndScratch) begin : gen_rom_snd_scratch
+ debug_rom i_debug_rom (
+ .clk_i,
+ .req_i,
+ .addr_i ( rom_addr ),
+ .rdata_o ( rom_rdata )
+ );
+ end else begin : gen_rom_one_scratch
+ // It uses the zero register (`x0`) as the base
+ // for its loads. The zero register does not need to
+ // be saved.
+ debug_rom_one_scratch i_debug_rom (
+ .clk_i,
+ .req_i,
+ .addr_i ( rom_addr ),
+ .rdata_o ( rom_rdata )
+ );
+ end
// ROM starts at the HaltAddress of the core e.g.: it immediately jumps to
// the ROM base address
diff --git a/hw/vendor/pulp_riscv_dbg/src/dm_obi_top.sv b/hw/vendor/pulp_riscv_dbg/src/dm_obi_top.sv
new file mode 100644
index 0000000..190830c
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/src/dm_obi_top.sv
@@ -0,0 +1,187 @@
+// Copyright 2020 Silicon Labs, Inc.
+//
+// This file, and derivatives thereof are licensed under the
+// Solderpad License, Version 2.0 (the "License").
+//
+// Use of this file means you agree to the terms and conditions
+// of the license and are in full compliance with the License.
+//
+// You may obtain a copy of the License at:
+//
+// https://solderpad.org/licenses/SHL-2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// and hardware implementations thereof distributed under the License
+// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+// OF ANY KIND, EITHER EXPRESSED OR IMPLIED.
+//
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// Engineer: Arjan Bink - arjan.bink@silabs.com //
+// //
+// Design Name: OBI Wrapper for Debug Module (dm_top) //
+// Project Name: CV32E40P //
+// Language: SystemVerilog //
+// //
+// Description: Wrapper for the Debug Module (dm_top) which gives it an //
+// OBI (Open Bus Interface) compatible interfaces so that it //
+// can be integrated without further glue logic (other than //
+// tie offs in an OBI compliant system. //
+// //
+// This wrapper is only intended for OBI compliant systems; //
+// in other systems the existing dm_top can be used as before //
+// and this wrapper can be ignored. //
+// //
+// The OBI spec is available at: //
+// //
+// - https://github.com/openhwgroup/core-v-docs/blob/master/ //
+// cores/cv32e40p/ //
+// //
+// Compared to 'logint' interfaces of dm_top the following //
+// signals are added: //
+// //
+// - slave_* OBI interface: //
+// //
+// - slave_gnt_o //
+// - slave_rvalid_o //
+// - slave_aid_i //
+// - slave_rid_o //
+// //
+// Compared to 'logint' interfaces of dm_top the following //
+// signals have been renamed: //
+// //
+// - master_* OBI interface: //
+// //
+// - Renamed master_add_o to master_addr_o //
+// - Renamed master_r_valid_i to master_rvalid_i //
+// - Renamed master_r_rdata_i to master_rdata_i //
+// //
+////////////////////////////////////////////////////////////////////////////////
+
+module dm_obi_top #(
+ parameter int unsigned IdWidth = 1, // Width of aid/rid
+ parameter int unsigned NrHarts = 1,
+ parameter int unsigned BusWidth = 32,
+ parameter int unsigned DmBaseAddress = 'h1000, // default to non-zero page
+ // Bitmask to select physically available harts for systems
+ // that don't use hart numbers in a contiguous fashion.
+ parameter logic [NrHarts-1:0] SelectableHarts = {NrHarts{1'b1}}
+) (
+ input logic clk_i, // clock
+ // asynchronous reset active low, connect PoR here, not the system reset
+ input logic rst_ni,
+ input logic testmode_i,
+ output logic ndmreset_o, // non-debug module reset
+ output logic dmactive_o, // debug module is active
+ output logic [NrHarts-1:0] debug_req_o, // async debug request
+ // communicate whether the hart is unavailable (e.g.: power down)
+ input logic [NrHarts-1:0] unavailable_i,
+ dm::hartinfo_t [NrHarts-1:0] hartinfo_i,
+
+ input logic slave_req_i,
+ // OBI grant for slave_req_i (not present on dm_top)
+ output logic slave_gnt_o,
+ input logic slave_we_i,
+ input logic [BusWidth-1:0] slave_addr_i,
+ input logic [BusWidth/8-1:0] slave_be_i,
+ input logic [BusWidth-1:0] slave_wdata_i,
+ // Address phase transaction identifier (not present on dm_top)
+ input logic [IdWidth-1:0] slave_aid_i,
+ // OBI rvalid signal (end of response phase for reads/writes) (not present on dm_top)
+ output logic slave_rvalid_o,
+ output logic [BusWidth-1:0] slave_rdata_o,
+ // Response phase transaction identifier (not present on dm_top)
+ output logic [IdWidth-1:0] slave_rid_o,
+
+ output logic master_req_o,
+ output logic [BusWidth-1:0] master_addr_o, // Renamed according to OBI spec
+ output logic master_we_o,
+ output logic [BusWidth-1:0] master_wdata_o,
+ output logic [BusWidth/8-1:0] master_be_o,
+ input logic master_gnt_i,
+ input logic master_rvalid_i, // Renamed according to OBI spec
+ input logic [BusWidth-1:0] master_rdata_i, // Renamed according to OBI spec
+
+ // Connection to DTM - compatible to RocketChip Debug Module
+ input logic dmi_rst_ni,
+ input logic dmi_req_valid_i,
+ output logic dmi_req_ready_o,
+ input dm::dmi_req_t dmi_req_i,
+
+ output logic dmi_resp_valid_o,
+ input logic dmi_resp_ready_i,
+ output dm::dmi_resp_t dmi_resp_o
+);
+
+ // Slave response phase (rvalid and identifier)
+ logic slave_rvalid_q;
+ logic [IdWidth-1:0] slave_rid_q;
+
+ // dm_top instance
+ dm_top #(
+ .NrHarts ( NrHarts ),
+ .BusWidth ( BusWidth ),
+ .DmBaseAddress ( DmBaseAddress ),
+ .SelectableHarts ( SelectableHarts )
+ ) i_dm_top (
+ .clk_i ( clk_i ),
+ .rst_ni ( rst_ni ),
+ .testmode_i ( testmode_i ),
+ .ndmreset_o ( ndmreset_o ),
+ .dmactive_o ( dmactive_o ),
+ .debug_req_o ( debug_req_o ),
+ .unavailable_i ( unavailable_i ),
+ .hartinfo_i ( hartinfo_i ),
+
+ .slave_req_i ( slave_req_i ),
+ .slave_we_i ( slave_we_i ),
+ .slave_addr_i ( slave_addr_i ),
+ .slave_be_i ( slave_be_i ),
+ .slave_wdata_i ( slave_wdata_i ),
+ .slave_rdata_o ( slave_rdata_o ),
+
+ .master_req_o ( master_req_o ),
+ .master_add_o ( master_addr_o ), // Renamed according to OBI spec
+ .master_we_o ( master_we_o ),
+ .master_wdata_o ( master_wdata_o ),
+ .master_be_o ( master_be_o ),
+ .master_gnt_i ( master_gnt_i ),
+ .master_r_valid_i ( master_rvalid_i ), // Renamed according to OBI spec
+ .master_r_rdata_i ( master_rdata_i ), // Renamed according to OBI spec
+
+ .dmi_rst_ni ( dmi_rst_ni ),
+ .dmi_req_valid_i ( dmi_req_valid_i ),
+ .dmi_req_ready_o ( dmi_req_ready_o ),
+ .dmi_req_i ( dmi_req_i ),
+
+ .dmi_resp_valid_o ( dmi_resp_valid_o ),
+ .dmi_resp_ready_i ( dmi_resp_ready_i ),
+ .dmi_resp_o ( dmi_resp_o )
+ );
+
+ // Extension to wrap dm_top as an OBI-compliant module
+ //
+ // dm_top has an implied rvalid pulse the cycle after its granted request.
+
+ // Registers
+ always_ff @(posedge clk_i or negedge rst_ni) begin : obi_regs
+ if (!rst_ni) begin
+ slave_rvalid_q <= 1'b0;
+ slave_rid_q <= 'b0;
+ end else begin
+ if (slave_req_i && slave_gnt_o) begin // 1 cycle pulse on rvalid for every granted request
+ slave_rvalid_q <= 1'b1;
+ slave_rid_q <= slave_aid_i; // Mirror aid to rid
+ end else begin
+ slave_rvalid_q <= 1'b0; // rid is don't care if rvalid = 0
+ end
+ end
+ end
+
+ assign slave_gnt_o = 1'b1; // Always receptive to request (slave_req_i)
+ assign slave_rvalid_o = slave_rvalid_q;
+ assign slave_rid_o = slave_rid_q;
+
+endmodule : dm_obi_top
diff --git a/hw/vendor/pulp_riscv_dbg/src/dm_pkg.sv b/hw/vendor/pulp_riscv_dbg/src/dm_pkg.sv
index de75c3e..1b7d0f5 100644
--- a/hw/vendor/pulp_riscv_dbg/src/dm_pkg.sv
+++ b/hw/vendor/pulp_riscv_dbg/src/dm_pkg.sv
@@ -201,7 +201,7 @@
logic sbaccess8;
} sbcs_t;
- localparam logic[1:0] DTM_SUCCESS = 2'h0;
+ localparam logic [1:0] DTM_SUCCESS = 2'h0;
typedef struct packed {
logic [6:0] addr;
diff --git a/hw/vendor/pulp_riscv_dbg/src/dm_sba.sv b/hw/vendor/pulp_riscv_dbg/src/dm_sba.sv
index f605088..c97f956 100644
--- a/hw/vendor/pulp_riscv_dbg/src/dm_sba.sv
+++ b/hw/vendor/pulp_riscv_dbg/src/dm_sba.sv
@@ -104,7 +104,7 @@
be[int'({be_idx[$high(be_idx):1], 1'b0}) +: 2] = '1;
end
3'b010: begin
- if (BusWidth == 32'd64) be[int'({be_idx[$high(be_idx)], 2'b0}) +: 4] = '1;
+ if (BusWidth == 32'd64) be[int'({be_idx[$high(be_idx)], 2'h0}) +: 4] = '1;
else be = '1;
end
3'b011: be = '1;
@@ -117,7 +117,7 @@
if (sbdata_valid_o) begin
state_d = Idle;
// auto-increment address
- if (sbautoincrement_i) sbaddress_o = sbaddress_i + (32'b1 << sbaccess_i);
+ if (sbautoincrement_i) sbaddress_o = sbaddress_i + (32'h1 << sbaccess_i);
end
end
@@ -125,7 +125,7 @@
if (sbdata_valid_o) begin
state_d = Idle;
// auto-increment address
- if (sbautoincrement_i) sbaddress_o = sbaddress_i + (32'b1 << sbaccess_i);
+ if (sbautoincrement_i) sbaddress_o = sbaddress_i + (32'h1 << sbaccess_i);
end
end
diff --git a/hw/vendor/pulp_riscv_dbg/tb/.clang-format b/hw/vendor/pulp_riscv_dbg/tb/.clang-format
new file mode 100644
index 0000000..ab4772e
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/.clang-format
@@ -0,0 +1,35 @@
+---
+BasedOnStyle: LLVM
+IndentWidth: 4
+UseTab: Never
+BreakBeforeBraces: Linux
+AlwaysBreakBeforeMultilineStrings: true
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+IndentCaseLabels: false
+AlignEscapedNewlinesLeft: false
+AlignTrailingComments: true
+AlignOperands: true
+AllowAllParametersOfDeclarationOnNextLine: false
+AlignAfterOpenBracket: true
+SpaceAfterCStyleCast: false
+MaxEmptyLinesToKeep: 2
+BreakBeforeBinaryOperators: NonAssignment
+BreakStringLiterals: false
+SortIncludes: false
+ContinuationIndentWidth: 4
+ColumnLimit: 80
+IndentPPDirectives: AfterHash
+BinPackArguments: true
+BinPackParameters: true
+ForEachMacros:
+ - 'TAILQ_FOREACH'
+ - 'TAILQ_FOREACH_REVERSE'
+BreakBeforeBinaryOperators: None
+MaxEmptyLinesToKeep: 1
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlignConsecutiveAssignments: true
+...
diff --git a/hw/vendor/pulp_riscv_dbg/tb/.gitignore b/hw/vendor/pulp_riscv_dbg/tb/.gitignore
new file mode 100644
index 0000000..667cf44
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/.gitignore
@@ -0,0 +1,26 @@
+TAGS
+memory_dump.bin
+modelsim.ini
+*.o
+work/*
+*.vstf
+*.wlf
+*.log
+objdump
+.build-rtl
+.lib-rtl
+.opt-rtl
+*.elf
+*.hex
+riscv
+common_cells
+tech_cells_generic
+fpnew
+transcript
+.nfs*
+simv*
+ucli.key
+DVEfiles
+cobj_dir
+obj_dir
+testbench_verilator
diff --git a/hw/vendor/pulp_riscv_dbg/tb/LICENSE.Berkeley b/hw/vendor/pulp_riscv_dbg/tb/LICENSE.Berkeley
new file mode 100644
index 0000000..5e890e5
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/LICENSE.Berkeley
@@ -0,0 +1,24 @@
+Copyright (c) 2011-2016, The Regents of the University of California
+(Regents). All Rights Reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. Neither the name of the Regents nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
+OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
+BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
+HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
+MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
diff --git a/hw/vendor/pulp_riscv_dbg/tb/LICENSE.SiFive b/hw/vendor/pulp_riscv_dbg/tb/LICENSE.SiFive
new file mode 100644
index 0000000..7e70933
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/LICENSE.SiFive
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2016-2017 SiFive, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/hw/vendor/pulp_riscv_dbg/tb/Makefile b/hw/vendor/pulp_riscv_dbg/tb/Makefile
new file mode 100644
index 0000000..9395fe0
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/Makefile
@@ -0,0 +1,323 @@
+# Copyright 2019 Clifford Wolf
+# Copyright 2019 Robert Balas
+# Copyright 2020 ETH Zurich and University of Bologna.
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# Author: Robert Balas (balasr@iis.ee.ethz.ch)
+# Description: All in one. Uses parts of picorv32's makefile.
+
+MAKE = make
+CTAGS = ctags
+
+# vsim configuration
+VVERSION = "10.7b"
+
+VLIB = vlib-$(VVERSION)
+VWORK = work
+
+VLOG = vlog-$(VVERSION)
+VLOG_FLAGS = -pedanticerrors -suppress 2577 -suppress 2583
+VLOG_LOG = vloggy
+
+VOPT = vopt-$(VVERSION)
+VOPT_FLAGS = -debugdb -fsmdebug -pedanticerrors #=mnprft
+
+VSIM = vsim-$(VVERSION)
+VSIM_HOME = /usr/pack/modelsim-$(VVERSION)-kgf/questasim
+VSIM_FLAGS = # user defined
+ALL_VSIM_FLAGS = $(VSIM_FLAGS) -sv_lib remote_bitbang/librbs_vsim
+VSIM_DEBUG_FLAGS = -debugdb
+VSIM_GUI_FLAGS = -gui -debugdb
+VSIM_SCRIPT_BATCH = vsim_batch.tcl
+VSIM_SCRIPT_GUI = vsim_gui.tcl
+
+VCS = vcs-2017.03-kgf vcs
+VCS_HOME = /usr/pack/vcs-2017.03-kgf
+VCS_FLAGS =
+SIMV_FLAGS =
+
+# verilator configuration
+VERILATOR = verilator
+VERI_FLAGS =
+VERI_COMPILE_FLAGS =
+VERI_TRACE =
+VERI_DIR = cobj_dir
+VERI_CFLAGS = -O2
+
+# RTL source files
+RTLSRC_TB_PKG :=
+RTLSRC_TB_TOP := tb_top.sv
+RTLSRC_TB := boot_rom.sv \
+ dp_ram.sv \
+ mm_ram.sv \
+ SimJTAG.sv \
+ tb_test_env.sv \
+ tb_top.sv
+
+RTLSRC_VERI_TB := boot_rom.sv \
+ dp_ram.sv \
+ mm_ram.sv \
+ SimJTAG.sv \
+ tb_test_env.sv \
+ tb_top_verilator.sv
+
+RTLSRC_INCDIR := riscv/rtl/include
+
+RTLSRC_FPNEW_PKG := fpnew/src/fpnew_pkg.sv
+RTLSRC_RISCV_PKG += $(addprefix riscv/rtl/include/,\
+ apu_core_package.sv riscv_defines.sv \
+ riscv_tracer_defines.sv)
+RTLSRC_DM_PKG += ../src/dm_pkg.sv
+
+RTLSRC_PKG = $(RTLSRC_FPNEW_PKG) dm_tb_pkg.sv $(RTLSRC_RISCV_PKG) $(RTLSRC_DM_PKG)
+RTLSRC_RISCV := $(addprefix riscv/rtl/,\
+ cv32e40p_sim_clock_gating.sv \
+ register_file_test_wrap.sv \
+ riscv_tracer.sv \
+ riscv_register_file.sv \
+ riscv_alu.sv \
+ riscv_alu_basic.sv \
+ riscv_alu_div.sv \
+ riscv_compressed_decoder.sv \
+ riscv_controller.sv \
+ riscv_cs_registers.sv \
+ riscv_decoder.sv \
+ riscv_int_controller.sv \
+ riscv_ex_stage.sv \
+ riscv_hwloop_controller.sv \
+ riscv_hwloop_regs.sv \
+ riscv_id_stage.sv \
+ riscv_if_stage.sv \
+ riscv_load_store_unit.sv \
+ riscv_mult.sv \
+ riscv_prefetch_buffer.sv \
+ riscv_prefetch_L0_buffer.sv \
+ riscv_core.sv \
+ riscv_apu_disp.sv \
+ riscv_fetch_fifo.sv \
+ riscv_L0_buffer.sv \
+ riscv_pmp.sv)
+RTLSRC_COMMON := $(addprefix common_cells/src/,\
+ cdc_2phase.sv fifo_v2.sv fifo_v3.sv\
+ rstgen.sv rstgen_bypass.sv)
+RTLSRC_TECH := $(addprefix tech_cells_generic/src/,\
+ cluster_clock_inverter.sv pulp_clock_mux2.sv\
+ cluster_clock_gating.sv)
+RTLSRC_DEBUG := ../debug_rom/debug_rom.sv
+RTLSRC_DEBUG += $(addprefix ../src/,\
+ dm_csrs.sv dmi_cdc.sv dmi_jtag.sv \
+ dmi_jtag_tap.sv dm_mem.sv \
+ dm_sba.sv dm_top.sv dm_obi_top.sv)
+
+RTLSRC += $(RTLSRC_RISCV) $(RTLSRC_COMMON) $(RTLSRC_TECH) $(RTLSRC_DEBUG)
+
+# versions for this tb
+RI5CY_SHA = d049690e7867291830631db7dbeb47c92718ed9e
+FPU_SHA = v0.6.1
+COMMON_SHA = 337f54a7cdfdad78b124cbdd2a627db3e0939141
+TECH_SHA = b35652608124b7ea813818b14a00ca76edd7599d
+
+RAM_START_ADDR = 0x1c000000
+
+# TODO: clean this up
+RTLSRC_VLOG_TB_TOP := $(basename $(notdir $(RTLSRC_TB_TOP)))
+RTLSRC_VOPT_TB_TOP := $(addsuffix _vopt, $(RTLSRC_VLOG_TB_TOP))
+
+# riscv bare metal cross compiling
+RISCV ?= $(HOME)/.riscv
+RV_CC = $(RISCV)/bin/riscv32-unknown-elf-gcc
+RV_CFLAGS = -march=rv32imc -Os -g
+RV_LDFLAGS = -nostdlib -static -T prog/link.ld
+RV_LDLIBS = -lc -lm -lgcc
+RV_OBJCOPY = $(RISCV)/bin/riscv32-unknown-elf-objcopy
+
+# assume verilator if no target chosen
+.DEFAULT_GOAL := veri-run
+
+all: veri-run
+
+# vsim testbench compilation and optimization
+vlib: .lib-rtl
+
+.lib-rtl:
+ $(VLIB) $(VWORK)
+ touch .lib-rtl
+
+# rebuild if we change some sourcefile
+.build-rtl: .lib-rtl $(RTLSRC_PKG) $(RTLSRC) $(RTLSRC_TB_PKG) $(RTLSRC_TB)
+ $(VLOG) -work $(VWORK) +incdir+$(RTLSRC_INCDIR) $(VLOG_FLAGS) \
+ $(RTLSRC_PKG) $(RTLSRC) $(RTLSRC_TB_PKG) $(RTLSRC_TB)
+ touch .build-rtl
+
+vsim-all: .opt-rtl
+
+.opt-rtl: .build-rtl
+ $(VOPT) -work $(VWORK) $(VOPT_FLAGS) $(RTLSRC_VLOG_TB_TOP) -o \
+ $(RTLSRC_VOPT_TB_TOP)
+ touch .opt-rtl
+
+# vcs testbench compilation
+
+vcsify: $(RTLSRC_PKG) $(RTLSRC) $(RTLSRC_TB_PKG) $(RTLSRC_TB) remote_bitbang/librbs_vcs.so
+ $(VCS) +vc -sverilog -race=all -ignore unique_checks -full64 \
+ -timescale=1ns/1ps \
+ -CC "-I$(VCS_HOME)/include -O3 -march=native" $(VCS_FLAGS) \
+ $(RTLSRC_PKG) $(RTLSRC) $(RTLSRC_TB_PKG) $(RTLSRC_TB) \
+ +incdir+$(RTLSRC_INCDIR)
+
+vcs-clean:
+ rm -rf simv* *.daidir *.vpd *.db csrc ucli.key vc_hdrs.h
+
+# verilator testbench compilation
+
+# We first test if the user wants to to vcd dumping. This hacky part is required
+# because we need to conditionally compile the testbench (-DVCD_TRACE) and pass
+# the --trace flags to the verilator call
+ifeq ($(findstring +vcd,$(VERI_FLAGS)),+vcd)
+VERI_TRACE="--trace"
+VERI_CFLAGS+="-DVCD_TRACE"
+endif
+VPATH += ../
+verilate: testbench_verilator
+
+# We set the RUNPATH (not RPATH, allows LD_LIBRARY_PATH to overwrite) to
+# remote_bitbang and manually link against librbs_veri since putting in
+# librbs_veri.so as parameter doesn't work because it searches in the build
+# directory
+testbench_verilator: $(RTLSRC_VERI_TB) $(RTLSRC_PKG) $(RTLSRC) \
+ remote_bitbang/librbs_veri.so
+ $(VERILATOR) --cc --sv --exe $(VERI_TRACE) \
+ --Wno-lint --Wno-UNOPTFLAT --Wno-BLKANDNBLK \
+ --Wno-MODDUP +incdir+$(RTLSRC_INCDIR) --top-module \
+ tb_top_verilator --Mdir $(VERI_DIR) \
+ -CFLAGS "-std=gnu++11 $(VERI_CFLAGS)" $(VERI_COMPILE_FLAGS) \
+ $(RTLSRC_PKG) $(RTLSRC_VERI_TB) $(RTLSRC) \
+ -LDFLAGS "-L../remote_bitbang \
+ -Wl,--enable-new-dtags -Wl,-rpath,remote_bitbang -lrbs_veri" \
+ tb_top_verilator.cpp
+ cd $(VERI_DIR) && $(MAKE) -f Vtb_top_verilator.mk
+ cp $(VERI_DIR)/Vtb_top_verilator testbench_verilator
+
+verilate-clean:
+ if [ -d $(VERI_DIR) ]; then rm -r $(VERI_DIR); fi
+ rm -rf testbench_verilator
+
+# git dependencies
+download_deps: fpnew/src/fpnew_pkg.sv $(RTLSRC_COMMON) $(RTLSRC_TECH) $(RTLSRC_RISCV)
+
+fpnew/src/fpnew_pkg.sv:
+ git clone https://github.com/pulp-platform/fpnew.git --recurse -b v0.6.1
+
+$(RTLSRC_COMMON):
+ git clone https://github.com/pulp-platform/common_cells.git
+ cd common_cells/ && git checkout $(COMMON_SHA)
+
+$(RTLSRC_TECH):
+ git clone https://github.com/pulp-platform/tech_cells_generic.git
+ cd tech_cells_generic/ && git checkout $(TECH_SHA)
+
+$(RTLSRC_RISCV_PKG) $(RTLSRC_RISCV):
+ git clone https://github.com/openhwgroup/cv32e40p.git riscv
+ cd riscv/ && git checkout $(RI5CY_SHA)
+
+# openocd server
+remote_bitbang/librbs_veri.so: INCLUDE_DIRS =./ $(VSIM_HOME)/include
+remote_bitbang/librbs_veri.so:
+ $(MAKE) -C remote_bitbang all
+ mv remote_bitbang/librbs.so $@
+
+remote_bitbang/librbs_vsim.so: INCLUDE_DIRS =./ $(VSIM_HOME)/include
+remote_bitbang/librbs_vsim.so:
+ $(MAKE) -C remote_bitbang all
+ mv remote_bitbang/librbs.so $@
+
+remote_bitbang/librbs_vcs.so: INCLUDE_DIRS =./ $(VCS_HOME)/include
+remote_bitbang/librbs_vcs.so:
+ $(MAKE) -C remote_bitbang all
+ mv remote_bitbang/librbs.so $@
+
+rbs-clean:
+ $(MAKE) -C remote_bitbang clean
+ rm -rf remote_bitbang/librbs_vsim.so remote_bitbang/librbs_vcs.so
+
+# run tb and exit
+.PHONY: vsim-tb-run
+vsim-tb-run: ALL_VSIM_FLAGS += -c
+vsim-tb-run: vsim-all remote_bitbang/librbs_vsim.so
+ $(VSIM) -work $(VWORK) $(ALL_VSIM_FLAGS) \
+ $(RTLSRC_VOPT_TB_TOP) -do 'source $(VSIM_SCRIPT_BATCH); exit -f'
+
+# run tb and drop into interactive shell
+.PHONY: vsim-tb-run-sh
+vsim-tb-run: ALL_VSIM_FLAGS += -c
+vsim-tb-run-sh: vsim-all remote_bitbang/librbs_vsim.so
+ $(VSIM) -work $(VWORK) $(ALL_VSIM_FLAGS) \
+ $(RTLSRC_VOPT_TB_TOP) -do $(VSIM_SCRIPT_BATCH)
+
+# run tb with simulator gui
+.PHONY: vsim-tb-run-gui
+vsim-tb-run-gui: ALL_VSIM_FLAGS += $(VSIM_GUI_FLAGS)
+vsim-tb-run-gui: vsim-all remote_bitbang/librbs_vsim.so
+ $(VSIM) -work $(VWORK) $(ALL_VSIM_FLAGS) \
+ $(RTLSRC_VOPT_TB_TOP) -do $(VSIM_SCRIPT_GUI)
+
+
+.PHONY: vsim-clean
+vsim-clean:
+ if [ -d $(VWORK) ]; then rm -r $(VWORK); fi
+ rm -f transcript vsim.wlf vsim.dbg trace_core*.log \
+ .build-rtl .opt-rtl .lib-rtl *.vcd objdump
+
+# compile and dump program
+prog/test.elf: prog/test.c prog/crt0.S prog/syscalls.c prog/vectors.S
+ $(RV_CC) $(RV_CFLAGS) $(RV_CPPFLAGS) $(RV_LDFLAGS) $^ $(RV_LDLIBS) -o $@
+
+prog/test.hex: prog/test.elf
+ $(RV_OBJCOPY) -O verilog --change-addresses -$(RAM_START_ADDR) $< $@
+
+.PHONY: prog-clean
+prog-clean:
+ rm -vrf $(addprefix prog/,test.elf test.hex)
+
+# run program
+.PHONY: veri-run
+veri-run: verilate prog/test.hex
+ ./testbench_verilator $(VERI_FLAGS) \
+ "+firmware=prog/test.hex"
+
+.PHONY: vsim-run
+vsim-run: vsim-all prog/test.hex
+vsim-run: ALL_VSIM_FLAGS += "+firmware=prog/test.hex"
+vsim-run: vsim-tb-run
+
+.PHONY: vsim-run-gui
+vsim-run-gui: vsim-all prog/test.hex
+vsim-run-gui: ALL_VSIM_FLAGS += "+firmware=prog/test.hex"
+vsim-run-gui: vsim-tb-run-gui
+
+.PHONY: vcs-run
+vcs-run: vcsify prog/test.hex
+ ./simv -sv_lib remote_bitbang/librbs_vcs $(SIMV_FLAGS) "+firmware=prog/test.hex"
+
+.PHONY: vcs-run-gui
+vcs-run-gui: VCS_FLAGS+=-debug_all
+vcs-run-gui: vcsify prog/test.hex
+ ./simv -sv_lib remote_bitbang/librbs_vcs $(SIMV_FLAGS) -gui "+firmware=prog/test.hex"
+
+# general targets
+.PHONY: clean
+clean: vsim-clean verilate-clean vcs-clean rbs-clean prog-clean
+
+.PHONY: distclean
+distclean: clean
+ rm -rf common_cells/ tech_cells_generic/ fpnew/ riscv/
diff --git a/hw/vendor/pulp_riscv_dbg/tb/README.md b/hw/vendor/pulp_riscv_dbg/tb/README.md
new file mode 100644
index 0000000..59960eb
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/README.md
@@ -0,0 +1,51 @@
+Debug Unit plus RI5CY Testbench
+=====================
+
+This testbench tests RI5CY together with a v0.13.1 compliant [debug
+unit](https://www.github.com/pulp-platform/riscv-dbg). There are several tests
+that can be run, but for now it is just `riscv test_compliance` of
+[riscv-openocd](https://www.github.com/riscv/riscv-openocd) (see in
+`pulpissimo.cfg`) and a not yet scripted run of gdb connecting to openocd,
+loading and running a hello world program (see `prog/test.c`).
+
+You need `riscv-openocd`.
+
+Running the testbench with vsim
+----------------------
+Point you environment variable `RISCV` to your RISC-V toolchain. Call `make
+vsim-run` to build the testbench and the program, and run it with vsim. Use
+`VSIM_FLAGS` to configure the simulator e.g. `make vsim-run VSIM_FLAGS="-gui
+-debugdb"`.
+
+Running the testbench with vcs
+----------------------
+Point you environment variable `RISCV` to your RISC-V toolchain. Call `make
+vcs-run`. Use `VCS_FLAGS` and `SIMV_FLAGS` to configure vcs e.g. `make vcs-run
+VCS_FLAGS="-debug_all"`.
+
+
+Running the testbench with [verilator](https://www.veripool.org/wiki/verilator)
+----------------------
+Point you environment variable `RISCV` to your RISC-V toolchain. Call `make
+veri-run`. Use `VERI_FLAGS` to configure verilator e.g. `make firmware-veri-run
+VERI_FLAGS="+firmware=path_to_firmware +vcd"` to use a custom firmware and dump
+to a vcd file.
+
+
+Options
+----------------------
+A few plusarg options are supported.
+* `+verbose` to show all memory read and writes and other miscellaneous information.
+
+* `+vcd` to produce a vcd file called `riscy_tb.vcd`. Verilator always produces
+ a vcd file called `verilator_tb.vcd`.
+
+* `+firmware=path_to_firmware` to load a specific firmware. It is a bit tricky to
+build and link your own program. Look into the `prog` folder for an example.
+
+Example Run
+-----------------------
+1. `make veri-run`
+3. (in new terminal) `export JTAG_VPI_PORT=port_name_from 1.`
+2. (in new terminal) `openocd -f dm_compliance_test.cfg`
+4. Now you can connect with gdb and interact with the testbench
diff --git a/hw/vendor/pulp_riscv_dbg/tb/SimJTAG.sv b/hw/vendor/pulp_riscv_dbg/tb/SimJTAG.sv
new file mode 100644
index 0000000..7c6c110
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/SimJTAG.sv
@@ -0,0 +1,85 @@
+// See LICENSE.SiFive for license details.
+//VCS coverage exclude_file
+import "DPI-C" function int jtag_tick
+(
+ input int port,
+ output bit jtag_TCK,
+ output bit jtag_TMS,
+ output bit jtag_TDI,
+ output bit jtag_TRSTn,
+
+ input bit jtag_TDO
+);
+
+module SimJTAG #(
+ parameter TICK_DELAY = 50,
+ parameter PORT = 0
+ )(
+
+ input clock,
+ input reset,
+
+ input enable,
+ input init_done,
+
+ output jtag_TCK,
+ output jtag_TMS,
+ output jtag_TDI,
+ output jtag_TRSTn,
+
+ input jtag_TDO_data,
+ input jtag_TDO_driven,
+
+ output [31:0] exit
+ );
+
+ reg [31:0] tickCounterReg;
+ wire [31:0] tickCounterNxt;
+
+ assign tickCounterNxt = (tickCounterReg == 0) ? TICK_DELAY : (tickCounterReg - 1);
+
+ bit r_reset;
+
+ wire [31:0] random_bits = $random;
+
+ wire #0.1 __jtag_TDO = jtag_TDO_driven ?
+ jtag_TDO_data : random_bits[0];
+
+ bit __jtag_TCK;
+ bit __jtag_TMS;
+ bit __jtag_TDI;
+ bit __jtag_TRSTn;
+ int __exit;
+
+ reg init_done_sticky;
+
+ assign #0.1 jtag_TCK = __jtag_TCK;
+ assign #0.1 jtag_TMS = __jtag_TMS;
+ assign #0.1 jtag_TDI = __jtag_TDI;
+ assign #0.1 jtag_TRSTn = __jtag_TRSTn;
+
+ assign #0.1 exit = __exit;
+
+ always @(posedge clock) begin
+ r_reset <= reset;
+ if (reset || r_reset) begin
+ __exit = 0;
+ tickCounterReg <= TICK_DELAY;
+ init_done_sticky <= 1'b0;
+ end else begin
+ init_done_sticky <= init_done | init_done_sticky;
+ if (enable && init_done_sticky) begin
+ tickCounterReg <= tickCounterNxt;
+ if (tickCounterReg == 0) begin
+ __exit = jtag_tick(PORT,
+ __jtag_TCK,
+ __jtag_TMS,
+ __jtag_TDI,
+ __jtag_TRSTn,
+ __jtag_TDO);
+ end
+ end // if (enable && init_done_sticky)
+ end // else: !if(reset || r_reset)
+ end // always @ (posedge clock)
+
+endmodule
diff --git a/hw/vendor/pulp_riscv_dbg/tb/boot_rom.sv b/hw/vendor/pulp_riscv_dbg/tb/boot_rom.sv
new file mode 100644
index 0000000..3610af4
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/boot_rom.sv
@@ -0,0 +1,39 @@
+// Copyright 2020 ETH Zurich and University of Bologna.
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+// Author: Robert Balas <balasr@iis.ee.ethz.ch>
+// Description: Bootrom for firmware booting
+
+module boot_rom (
+ input logic clk_i,
+ input logic req_i,
+ input logic [31:0] addr_i,
+ output logic [31:0] rdata_o
+);
+ localparam int RomSize = 2;
+ localparam logic [31:0] entry_addr = 32'h1c00_0080;
+
+ const logic [RomSize-1:0][31:0] mem = {
+ dm_tb_pkg::jalr(5'h0, 5'h1, entry_addr[11:0]),
+ dm_tb_pkg::lui(5'h1, entry_addr[31:12])
+ };
+
+ logic [$clog2(RomSize)-1:0] addr_q;
+
+
+ assign rdata_o = (addr_q < RomSize) ? mem[addr_q] : '0;
+
+ always_ff @(posedge clk_i) begin
+ if (req_i) begin
+ addr_q <= addr_i[$clog2(RomSize)-1+3:2];
+ end
+ end
+
+endmodule
diff --git a/hw/vendor/pulp_riscv_dbg/tb/dm_compliance_test.cfg b/hw/vendor/pulp_riscv_dbg/tb/dm_compliance_test.cfg
new file mode 100644
index 0000000..96c7ca6
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/dm_compliance_test.cfg
@@ -0,0 +1,31 @@
+debug_level 4
+adapter_khz 10000
+
+interface remote_bitbang
+remote_bitbang_host localhost
+
+remote_bitbang_port 9999
+
+set _CHIPNAME riscv
+jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x249511C3
+
+foreach t [jtag names] {
+ puts [format "TAP: %s\n" $t]
+}
+
+set _TARGETNAME $_CHIPNAME.cpu
+#target create $_TARGETNAME riscv -chain-position $_TARGETNAME -coreid 0x3e0
+target create $_TARGETNAME riscv -chain-position $_TARGETNAME -rtos riscv
+
+riscv set_reset_timeout_sec 2000
+riscv set_command_timeout_sec 2000
+
+# prefer to use sba for system bus access
+riscv set_prefer_sba on
+
+# dump jtag chain
+scan_chain
+
+init
+riscv test_compliance
+shutdown
diff --git a/hw/vendor/pulp_riscv_dbg/tb/dm_debug.cfg b/hw/vendor/pulp_riscv_dbg/tb/dm_debug.cfg
new file mode 100644
index 0000000..1ac2555
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/dm_debug.cfg
@@ -0,0 +1,32 @@
+debug_level 4
+adapter_khz 10000
+
+interface remote_bitbang
+remote_bitbang_host localhost
+
+remote_bitbang_port $::env(JTAG_VPI_PORT)
+
+set _CHIPNAME riscv
+jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x249511C3
+
+foreach t [jtag names] {
+ puts [format "TAP: %s\n" $t]
+}
+
+set _TARGETNAME $_CHIPNAME.cpu
+#target create $_TARGETNAME riscv -chain-position $_TARGETNAME -coreid 0x3e0
+target create $_TARGETNAME riscv -chain-position $_TARGETNAME -rtos riscv
+
+riscv set_reset_timeout_sec 2000
+riscv set_command_timeout_sec 2000
+
+# prefer to use sba for system bus access
+riscv set_prefer_sba on
+
+# dump jtag chain
+scan_chain
+
+init
+
+halt
+echo "Ready for Remote Connections"
diff --git a/hw/vendor/pulp_riscv_dbg/tb/dm_tb_pkg.sv b/hw/vendor/pulp_riscv_dbg/tb/dm_tb_pkg.sv
new file mode 100644
index 0000000..e0c5674
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/dm_tb_pkg.sv
@@ -0,0 +1,58 @@
+// Copyright 2020 ETH Zurich and University of Bologna.
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+//
+// Contributor: Robert Balas <balasr@iis.ethz.ch>
+
+
+package dm_tb_pkg;
+
+ // PULPissimo-like memory map
+ typedef enum logic [31:0] {
+ ROM_BASE = 32'h1A00_0000,
+ FLL_BASE = 32'h1A10_0000,
+ GPIO_BASE = 32'h1A10_1000,
+ UDMA_BASE = 32'h1A10_2000,
+ CNTRL_BASE = 32'h1A10_4000,
+ ADVTIMER_BASE = 32'h1A10_5000,
+ EVENT_BASE = 32'h1A10_6000,
+ TIMER_BASE = 32'h1A10_B000,
+ HWPE_BASE = 32'h1A10_C000,
+ STDOUT_BASE = 32'h1A10_F000,
+ DEBUG_BASE = 32'h1A11_0000,
+ SRAM_BASE = 32'h1C00_0000
+ } mmap_base_t;
+
+ localparam logic [31:0] ROM_LEN = 32'h0010_0000;
+ localparam logic [31:0] FLL_LEN = 32'h0000_1000;
+ localparam logic [31:0] GPIO_LEN = 32'h0000_1000;
+ localparam logic [31:0] UDMA_LEN = 32'h0000_2000;
+ localparam logic [31:0] CNTRL_LEN = 32'h0000_1000;
+ localparam logic [31:0] ADVTIMER_LEN = 32'h0000_1000;
+ localparam logic [31:0] EVENT_LEN = 32'h0000_5000;
+ localparam logic [31:0] TIMER_LEN = 32'h0000_1000;
+ localparam logic [31:0] HWPE_LEN = 32'h0000_3000;
+ localparam logic [31:0] STDOUT_LEN = 32'h0000_1000;
+ localparam logic [31:0] DEBUG_LEN = 32'h0000_1000;
+ localparam logic [31:0] SRAM_LEN = 32'h000f_C000;
+
+ // helper functions
+ function automatic logic [31:0] jal (logic[4:0] rd, logic [20:0] imm);
+ return {imm[20], imm[10:1], imm[11], imm[19:12], rd, 7'h6f};
+ endfunction
+
+ function automatic logic [31:0] jalr (logic[4:0] rd, logic[4:0] rs1, logic [11:0] offset);
+ return {offset[11:0], rs1, 3'b0, rd, 7'h67};
+ endfunction
+
+ function automatic logic [31:0] lui (logic[4:0] rd, logic [19:0] uimm);
+ return {uimm, rd, 7'b0110111};
+ endfunction
+
+endpackage // riscv_tb_pkg
diff --git a/hw/vendor/pulp_riscv_dbg/tb/dp_ram.sv b/hw/vendor/pulp_riscv_dbg/tb/dp_ram.sv
new file mode 100644
index 0000000..f7f224b
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/dp_ram.sv
@@ -0,0 +1,84 @@
+// Copyright 2020 ETH Zurich and University of Bologna.
+// Copyright 2017 Embecosm Limited <www.embecosm.com>
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+module dp_ram #(
+ parameter int unsigned ADDR_WIDTH = 8,
+ parameter int unsigned INSTR_RDATA_WIDTH = 128
+) (
+ input logic clk_i,
+
+ input logic en_a_i,
+ input logic [ADDR_WIDTH-1:0] addr_a_i,
+ input logic [31:0] wdata_a_i,
+ output logic [INSTR_RDATA_WIDTH-1:0] rdata_a_o,
+ input logic we_a_i,
+ input logic [3:0] be_a_i,
+
+ input logic en_b_i,
+ input logic [ADDR_WIDTH-1:0] addr_b_i,
+ input logic [31:0] wdata_b_i,
+ output logic [31:0] rdata_b_o,
+ input logic we_b_i,
+ input logic [3:0] be_b_i
+);
+
+ localparam bytes = 2**ADDR_WIDTH;
+
+ logic [7:0] mem[bytes];
+ logic [ADDR_WIDTH-1:0] addr_a_int;
+ logic [ADDR_WIDTH-1:0] addr_b_int;
+
+ always_comb addr_a_int = {addr_a_i[ADDR_WIDTH-1:2], 2'b0};
+ always_comb addr_b_int = {addr_b_i[ADDR_WIDTH-1:2], 2'b0};
+
+ always @(posedge clk_i) begin
+ for (int i = 0; i < INSTR_RDATA_WIDTH/8; i++) begin
+ rdata_a_o[(i*8)+: 8] <= mem[addr_a_int + i];
+ end
+
+ /* addr_b_i is the actual memory address referenced */
+ if (en_b_i) begin
+ /* handle writes */
+ if (we_b_i) begin
+ if (be_b_i[0]) mem[addr_b_int ] <= wdata_b_i[ 0+:8];
+ if (be_b_i[1]) mem[addr_b_int + 1] <= wdata_b_i[ 8+:8];
+ if (be_b_i[2]) mem[addr_b_int + 2] <= wdata_b_i[16+:8];
+ if (be_b_i[3]) mem[addr_b_int + 3] <= wdata_b_i[24+:8];
+ end
+ /* handle reads */
+ else begin
+ if ($test$plusargs("verbose"))
+ $display("read addr=0x%08x: data=0x%08x", addr_b_int,
+ {mem[addr_b_int + 3], mem[addr_b_int + 2],
+ mem[addr_b_int + 1], mem[addr_b_int + 0]});
+
+ rdata_b_o[ 7: 0] <= mem[addr_b_int ];
+ rdata_b_o[15: 8] <= mem[addr_b_int + 1];
+ rdata_b_o[23:16] <= mem[addr_b_int + 2];
+ rdata_b_o[31:24] <= mem[addr_b_int + 3];
+ end
+ end
+ end
+
+ export "DPI-C" function read_byte;
+ export "DPI-C" task write_byte;
+
+ function int read_byte(input logic [ADDR_WIDTH-1:0] byte_addr);
+ read_byte = mem[byte_addr];
+ endfunction
+
+ task write_byte(input integer byte_addr, logic [7:0] val, output logic [7:0] other);
+ mem[byte_addr] = val;
+ other = mem[byte_addr];
+
+ endtask
+
+endmodule // dp_ram
diff --git a/hw/vendor/pulp_riscv_dbg/tb/mm_ram.sv b/hw/vendor/pulp_riscv_dbg/tb/mm_ram.sv
new file mode 100644
index 0000000..887baa6
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/mm_ram.sv
@@ -0,0 +1,571 @@
+// Copyright 2020 ETH Zurich and University of Bologna.
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+// RAM and MM wrapper for RI5CY
+// Contributor: Robert Balas <balasr@iis.ee.ethz.ch>
+//
+// This maps the dp_ram module to the instruction and data ports of the RI5CY
+// processor core and some pseudo peripherals
+
+module mm_ram #(
+ parameter int unsigned RAM_ADDR_WIDTH = 16,
+ parameter int unsigned INSTR_RDATA_WIDTH = 32,
+ parameter bit JTAG_BOOT = 1
+) (
+ input logic clk_i,
+ input logic rst_ni,
+
+ input logic instr_req_i,
+ input logic [31:0] instr_addr_i,
+ output logic [INSTR_RDATA_WIDTH-1:0] instr_rdata_o,
+ output logic instr_rvalid_o,
+ output logic instr_gnt_o,
+
+ input logic data_req_i,
+ input logic [31:0] data_addr_i,
+ input logic data_we_i,
+ input logic [3:0] data_be_i,
+ input logic [31:0] data_wdata_i,
+ output logic [31:0] data_rdata_o,
+ output logic data_rvalid_o,
+ output logic data_gnt_o,
+
+ input logic sb_req_i,
+ input logic [31:0] sb_addr_i,
+ input logic sb_we_i,
+ input logic [3:0] sb_be_i,
+ input logic [31:0] sb_wdata_i,
+ output logic [31:0] sb_rdata_o,
+ output logic sb_rvalid_o,
+ output logic sb_gnt_o,
+
+ output logic dm_req_o,
+ output logic [31:0] dm_addr_o,
+ output logic dm_we_o,
+ output logic [3:0] dm_be_o,
+ output logic [31:0] dm_wdata_o,
+ input logic [31:0] dm_rdata_i,
+ input logic dm_rvalid_i,
+ input logic dm_gnt_i,
+
+
+ input logic [4:0] irq_id_i,
+ input logic irq_ack_i,
+ output logic [4:0] irq_id_o,
+ output logic irq_o,
+
+ output logic tests_passed_o,
+ output logic tests_failed_o
+);
+
+ import dm_tb_pkg::*;
+
+ localparam int TIMER_IRQ_ID = 3;
+
+ // mux for read and writes
+ enum logic [2:0]{RAM, DEBUG, ROM, UNMAP, IDLE_READ} select_rdata_d, select_rdata_q;
+
+ enum logic [1:0]{SB, CORE, IDLE_WRITE} select_wdata_d, select_wdata_q;
+
+ logic data_rvalid_d, data_rvalid_q;
+ logic sb_rvalid_d, sb_rvalid_q;
+ logic instr_rvalid_d, instr_rvalid_q;
+
+ // TODO: oof
+ logic [31:0] data_addr_aligned;
+
+ // signals to ram
+ logic ram_data_req;
+ logic [RAM_ADDR_WIDTH-1:0] ram_data_addr;
+ logic [31:0] ram_data_wdata;
+ logic [31:0] ram_data_rdata;
+ logic ram_data_we;
+ logic [3:0] ram_data_be;
+
+ // signals to rom
+ logic rom_req;
+ logic [31:0] rom_addr;
+ logic [31:0] rom_rdata;
+
+ // signals to read access debug unit
+ logic dm_req;
+ logic [31:0] dm_addr;
+ logic dm_we;
+ logic [3:0] dm_be;
+ logic [31:0] dm_wdata;
+ logic [31:0] dm_rdata;
+ logic dm_rvalid;
+ logic dm_gnt;
+
+ logic ram_instr_req;
+ logic [31:0] ram_instr_addr;
+ logic [INSTR_RDATA_WIDTH-1:0] ram_instr_rdata;
+
+
+
+
+ // signals to print peripheral
+ logic [31:0] print_wdata;
+ logic print_valid;
+
+ // signals to timer
+ logic [31:0] timer_irq_mask_q;
+ logic [31:0] timer_cnt_q;
+ logic irq_q;
+ logic timer_reg_valid;
+ logic timer_val_valid;
+ logic [31:0] timer_wdata;
+
+
+ // uhh, align?
+ always_comb data_addr_aligned = {data_addr_i[31:2], 2'b0};
+
+ // Handle system bus, core data accesses and instr access to rom, ram and
+ // debug unit. Someone make a for gen loop here.
+ always_comb begin
+ sb_gnt_o = '0;
+ data_gnt_o = '0;
+ instr_gnt_o = '0;
+
+ ram_data_req = '0;
+ ram_data_addr = '0;
+ ram_data_wdata = '0;
+ ram_data_we = '0;
+ ram_data_be = '0;
+
+ ram_instr_req = '0;
+ ram_instr_addr = '0;
+
+ dm_req = '0;
+ dm_addr = '0;
+ dm_we = '0;
+ dm_be = '0;
+ dm_wdata = '0;
+
+ rom_req = '0;
+ rom_addr = '0;
+
+ print_wdata = '0;
+ print_valid = '0;
+
+ select_rdata_d = IDLE_READ;
+ select_wdata_d = IDLE_WRITE;
+
+ data_rvalid_d = '0;
+ sb_rvalid_d = '0;
+ instr_rvalid_d = '0;
+
+ tests_passed_o = '0;
+ tests_failed_o = '0;
+
+
+ // memory map:
+ // the ram is mapped from 0 to SRAM_LEN and SRAM_BASE to SRAM_BASE + SRAM_LEN
+ // this mirroring is the same as in pulpissimo
+
+ // instruction data reads to ram can always go
+ if (instr_req_i && ((instr_addr_i >= SRAM_BASE && instr_addr_i < SRAM_BASE + SRAM_LEN) ||
+ (instr_addr_i >= 0 && instr_addr_i < SRAM_LEN))) begin
+ instr_gnt_o = '1;
+ instr_rvalid_d = '1;
+ ram_instr_req = '1;
+ ram_instr_addr = instr_addr_i;
+
+ end
+
+
+ // priority to sb access over data access
+ if (sb_req_i) begin
+ sb_gnt_o = '1;
+ sb_rvalid_d = '1;
+
+ if (sb_we_i) begin // handle writes
+ if (sb_addr_i >= ROM_BASE && sb_addr_i < ROM_BASE + ROM_LEN) begin
+ end else if (sb_addr_i >= FLL_BASE && sb_addr_i < FLL_BASE + FLL_LEN) begin
+ end else if (sb_addr_i >= GPIO_BASE && sb_addr_i < GPIO_BASE + GPIO_LEN) begin
+ end else if (sb_addr_i >= UDMA_BASE && sb_addr_i < UDMA_BASE + UDMA_LEN) begin
+ end else if (sb_addr_i >= CNTRL_BASE && sb_addr_i < CNTRL_BASE + CNTRL_LEN) begin
+ end else if (sb_addr_i >= ADVTIMER_BASE && sb_addr_i < ADVTIMER_BASE + ADVTIMER_LEN) begin
+ end else if (sb_addr_i >= EVENT_BASE && sb_addr_i < EVENT_BASE + EVENT_LEN) begin
+ end else if (sb_addr_i >= TIMER_BASE && sb_addr_i < TIMER_BASE + TIMER_LEN) begin
+ end else if (sb_addr_i >= HWPE_BASE && sb_addr_i < HWPE_BASE + HWPE_LEN) begin
+ end else if (sb_addr_i >= STDOUT_BASE && sb_addr_i < STDOUT_BASE + STDOUT_LEN) begin
+ select_wdata_d = SB;
+ print_wdata = sb_wdata_i;
+ print_valid = '1;
+
+ end else if (sb_addr_i >= DEBUG_BASE && sb_addr_i < DEBUG_BASE + DEBUG_LEN) begin
+ end else if ((sb_addr_i >= SRAM_BASE && sb_addr_i < SRAM_BASE + SRAM_LEN) ||
+ (sb_addr_i >= 0 && sb_addr_i < SRAM_LEN)) begin
+ select_wdata_d = SB;
+ ram_data_req = sb_req_i;
+ ram_data_addr = sb_addr_i[RAM_ADDR_WIDTH-1:0]; // just clip higher bits
+ ram_data_wdata = sb_wdata_i;
+ ram_data_we = sb_we_i;
+ ram_data_be = sb_be_i;
+
+ end else begin
+ $error("Writing to unmapped memory at %x", sb_addr_i);
+ end
+
+ end else begin // handle reads
+ if (sb_addr_i >= ROM_BASE && sb_addr_i < ROM_BASE + ROM_LEN) begin
+ select_rdata_d = ROM;
+
+ end else if (sb_addr_i >= FLL_BASE && sb_addr_i < FLL_BASE + FLL_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (sb_addr_i >= GPIO_BASE && sb_addr_i < GPIO_BASE + GPIO_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (sb_addr_i >= UDMA_BASE && sb_addr_i < UDMA_BASE + UDMA_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (sb_addr_i >= CNTRL_BASE && sb_addr_i < CNTRL_BASE + CNTRL_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (sb_addr_i >= ADVTIMER_BASE && sb_addr_i < ADVTIMER_BASE + ADVTIMER_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (sb_addr_i >= EVENT_BASE && sb_addr_i < EVENT_BASE + EVENT_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (sb_addr_i >= TIMER_BASE && sb_addr_i < TIMER_BASE + TIMER_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (sb_addr_i >= HWPE_BASE && sb_addr_i < HWPE_BASE + HWPE_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (sb_addr_i >= STDOUT_BASE && sb_addr_i < STDOUT_BASE + STDOUT_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (sb_addr_i >= DEBUG_BASE && sb_addr_i < DEBUG_BASE + DEBUG_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if ((sb_addr_i >= SRAM_BASE && sb_addr_i < SRAM_BASE + SRAM_LEN) ||
+ (sb_addr_i >= 0 && sb_addr_i < SRAM_LEN)) begin
+ select_rdata_d = RAM;
+ ram_data_req = sb_req_i;
+ ram_data_addr = sb_addr_i[RAM_ADDR_WIDTH-1:0];
+ ram_data_wdata = sb_wdata_i;
+ ram_data_we = sb_we_i;
+ ram_data_be = sb_be_i;
+
+ end else begin
+ select_rdata_d = UNMAP;
+ end
+
+ end
+ end else if (data_req_i) begin
+ data_gnt_o = '1;
+ data_rvalid_d = '1;
+
+ if (data_we_i) begin // handle writes
+ if (data_addr_i >= ROM_BASE && data_addr_i < ROM_BASE + ROM_LEN) begin
+ end else if (data_addr_i >= FLL_BASE && data_addr_i < FLL_BASE + FLL_LEN) begin
+ end else if (data_addr_i >= GPIO_BASE && data_addr_i < GPIO_BASE + GPIO_LEN) begin
+ end else if (data_addr_i >= UDMA_BASE && data_addr_i < UDMA_BASE + UDMA_LEN) begin
+ end else if (data_addr_i >= CNTRL_BASE && data_addr_i < CNTRL_BASE + CNTRL_LEN) begin
+ if(data_wdata_i === 32'hF00D)
+ tests_passed_o = 1'b1;
+ else
+ tests_failed_o = 1'b1;
+
+ end else if (data_addr_i >= ADVTIMER_BASE && data_addr_i < ADVTIMER_BASE + ADVTIMER_LEN) begin
+ end else if (data_addr_i >= EVENT_BASE && data_addr_i < EVENT_BASE + EVENT_LEN) begin
+ end else if (data_addr_i >= TIMER_BASE && data_addr_i < TIMER_BASE + TIMER_LEN) begin
+ end else if (data_addr_i >= HWPE_BASE && data_addr_i < HWPE_BASE + HWPE_LEN) begin
+ end else if (data_addr_i >= STDOUT_BASE && data_addr_i < STDOUT_BASE + STDOUT_LEN) begin
+ select_wdata_d = CORE;
+ print_wdata = data_wdata_i;
+ print_valid = '1;
+
+ end else if (data_addr_i >= DEBUG_BASE && data_addr_i < DEBUG_BASE + DEBUG_LEN) begin
+ select_wdata_d = CORE;
+ dm_req = data_req_i;
+ dm_addr = data_addr_i;
+ dm_we = data_we_i;
+ dm_be = data_be_i;
+ dm_wdata = data_wdata_i;
+
+ end else if ((data_addr_i >= SRAM_BASE && data_addr_i < SRAM_BASE + SRAM_LEN) ||
+ (data_addr_i >= 0 && data_addr_i < SRAM_LEN)) begin
+ select_wdata_d = CORE;
+ ram_data_req = data_req_i;
+ ram_data_addr = data_addr_i[RAM_ADDR_WIDTH-1:0]; // just clip higher bits
+ ram_data_wdata = data_wdata_i;
+ ram_data_we = data_we_i;
+ ram_data_be = data_be_i;
+
+ end else begin
+ end
+
+ end else begin // handle reads
+ if (data_addr_i >= ROM_BASE && data_addr_i < ROM_BASE + ROM_LEN) begin
+ select_rdata_d = ROM;
+ rom_req = data_req_i;
+ rom_addr = data_addr_i - ROM_BASE;
+ // TODO data_be_i
+
+ end else if (data_addr_i >= FLL_BASE && data_addr_i < FLL_BASE + FLL_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (data_addr_i >= GPIO_BASE && data_addr_i < GPIO_BASE + GPIO_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (data_addr_i >= UDMA_BASE && data_addr_i < UDMA_BASE + UDMA_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (data_addr_i >= CNTRL_BASE && data_addr_i < CNTRL_BASE + CNTRL_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (data_addr_i >= ADVTIMER_BASE && data_addr_i < ADVTIMER_BASE + ADVTIMER_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (data_addr_i >= EVENT_BASE && data_addr_i < EVENT_BASE + EVENT_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (data_addr_i >= TIMER_BASE && data_addr_i < TIMER_BASE + TIMER_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (data_addr_i >= HWPE_BASE && data_addr_i < HWPE_BASE + HWPE_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (data_addr_i >= STDOUT_BASE && data_addr_i < STDOUT_BASE + STDOUT_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (data_addr_i >= DEBUG_BASE && data_addr_i < DEBUG_BASE + DEBUG_LEN) begin
+ select_rdata_d = DEBUG;
+ dm_req = data_req_i;
+ dm_addr = data_addr_i;
+ dm_we = data_we_i;
+ dm_be = data_be_i;
+
+ end else if ((data_addr_i >= SRAM_BASE && data_addr_i < SRAM_BASE + SRAM_LEN) ||
+ (data_addr_i >= 0 && data_addr_i < SRAM_LEN)) begin
+ select_rdata_d = RAM;
+ ram_data_req = data_req_i;
+ ram_data_addr = data_addr_i[RAM_ADDR_WIDTH-1:0];
+ ram_data_we = data_we_i;
+ ram_data_be = data_be_i;
+
+ end else begin
+ select_rdata_d = UNMAP;
+ end
+
+ end
+ end else if (instr_req_i) begin
+ instr_gnt_o = '1;
+ instr_rvalid_d = '1;
+ // handle reads
+ if (instr_addr_i >= ROM_BASE && instr_addr_i < ROM_BASE + ROM_LEN) begin
+ select_rdata_d = ROM;
+ rom_req = instr_req_i;
+ rom_addr = instr_addr_i - ROM_BASE - 32'h80;
+
+ end else if (instr_addr_i >= FLL_BASE && instr_addr_i < FLL_BASE + FLL_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (instr_addr_i >= GPIO_BASE && instr_addr_i < GPIO_BASE + GPIO_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (instr_addr_i >= UDMA_BASE && instr_addr_i < UDMA_BASE + UDMA_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (instr_addr_i >= CNTRL_BASE && instr_addr_i < CNTRL_BASE + CNTRL_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (instr_addr_i >= ADVTIMER_BASE && instr_addr_i < ADVTIMER_BASE + ADVTIMER_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (instr_addr_i >= EVENT_BASE && instr_addr_i < EVENT_BASE + EVENT_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (instr_addr_i >= TIMER_BASE && instr_addr_i < TIMER_BASE + TIMER_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (instr_addr_i >= HWPE_BASE && instr_addr_i < HWPE_BASE + HWPE_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (instr_addr_i >= STDOUT_BASE && instr_addr_i < STDOUT_BASE + STDOUT_LEN) begin
+ select_rdata_d = UNMAP;
+ end else if (instr_addr_i >= DEBUG_BASE && instr_addr_i < DEBUG_BASE + DEBUG_LEN) begin
+ select_rdata_d = DEBUG;
+ dm_req = '1;
+ dm_addr = instr_addr_i;
+ dm_we = '0;
+ dm_be = 4'b1111;
+
+ end else if ((instr_addr_i >= SRAM_BASE && instr_addr_i < SRAM_BASE + SRAM_LEN) ||
+ (instr_addr_i >=0 && instr_addr_i < SRAM_LEN)) begin
+ // handled separately
+ select_rdata_d = RAM;
+ end else begin
+ select_rdata_d = UNMAP;
+ end
+ end
+ end
+
+
+`ifndef VERILATOR
+ // make sure we don't access any unmapped memory
+
+ out_of_bounds_write: assert property
+ (@(posedge clk_i) disable iff (!rst_ni)
+ (data_req_i && data_gnt_o && data_we_i |->
+ (data_addr_i >= STDOUT_BASE && data_addr_i < STDOUT_BASE + STDOUT_LEN)
+ || (data_addr_i >= DEBUG_BASE && data_addr_i < DEBUG_BASE + DEBUG_LEN)
+ || (data_addr_i >= SRAM_BASE && data_addr_i < SRAM_BASE + SRAM_LEN)
+ || (data_addr_i >= 0 && data_addr_i < SRAM_LEN)))
+ else $error("out of bounds write to %08x with %08x",
+ data_addr_i, data_wdata_i);
+
+ out_of_bounds_read: assert property
+ (@(posedge clk_i) disable iff (!rst_ni)
+ (select_rdata_q != UNMAP))
+ else $error("out of bounds read");
+`endif
+
+ // make sure we select the proper read data
+ always_comb begin: read_mux_sb_data_instr
+ data_rdata_o = '0;
+ sb_rdata_o = '0;
+ instr_rdata_o = ram_instr_rdata;
+
+ if(select_rdata_q == RAM) begin
+ data_rdata_o = ram_data_rdata;
+ sb_rdata_o = ram_data_rdata;
+
+ end else if (select_rdata_q == DEBUG) begin
+ data_rdata_o = dm_rdata;
+ sb_rdata_o = dm_rdata; //TODO: not possible
+ instr_rdata_o = dm_rdata;
+
+ end else if (select_rdata_q == ROM) begin
+ // either we got into a loop for jtag booting or we jumpt to the l2
+ // boot address (1c00_0080 === 0000_0080) to run a firmware directly
+ if (JTAG_BOOT) begin
+ data_rdata_o = 32'b00000000000000000000000001101111; //while(true)
+ sb_rdata_o = 32'b00000000000000000000000001101111;
+ instr_rdata_o = 32'b00000000000000000000000001101111;
+ end else begin
+ data_rdata_o = rom_rdata; //jal(5'b0, 21'h80); // jump to 0x0 + 0x80
+ sb_rdata_o = rom_rdata; //jal(5'b0, 21'h80);
+ instr_rdata_o = rom_rdata; //jal(5'b0, 21'h80);
+ end
+
+ end else if (select_rdata_q == IDLE_READ) begin
+ end
+ end
+
+ // print to stdout pseudo peripheral
+ always_ff @(posedge clk_i, negedge rst_ni) begin: print_peripheral
+ if(print_valid) begin
+ if ($test$plusargs("verbose")) begin
+ if (32 <= print_wdata && print_wdata < 128)
+ $display("OUT: '%c'", print_wdata[7:0]);
+ else
+ $display("OUT: %3d", print_wdata);
+
+ end else begin
+ $write("%c", print_wdata[7:0]);
+`ifndef VERILATOR
+ $fflush();
+`endif
+ end
+ end
+ end
+
+ assign irq_id_o = TIMER_IRQ_ID;
+ assign irq_o = irq_q;
+
+ // Control timer. We need one to have some kind of timeout for tests that
+ // get stuck in some loop. The riscv-tests also mandate that. Enable timer
+ // interrupt by writing 1 to timer_irq_mask_q. Write initial value to
+ // timer_cnt_q which gets counted down each cycle. When it transitions from
+ // 1 to 0, and interrupt request (irq_q) is made (masked by timer_irq_mask_q).
+ always_ff @(posedge clk_i, negedge rst_ni) begin: tb_timer
+ if(~rst_ni) begin
+ timer_irq_mask_q <= '0;
+ timer_cnt_q <= '0;
+ irq_q <= '0;
+
+ end else begin
+ // set timer irq mask
+ if(timer_reg_valid) begin
+ timer_irq_mask_q <= timer_wdata;
+
+ // write timer value
+ end else if(timer_val_valid) begin
+ timer_cnt_q <= timer_wdata;
+
+ end else begin
+ if(timer_cnt_q > 0)
+ timer_cnt_q <= timer_cnt_q - 1;
+
+ if(timer_cnt_q == 1)
+ irq_q <= 1'b1 && timer_irq_mask_q[TIMER_IRQ_ID];
+
+ if(irq_ack_i == 1'b1 && irq_id_i == TIMER_IRQ_ID)
+ irq_q <= '0;
+
+ end
+ end
+ end
+
+ // show writes if requested
+ always_ff @(posedge clk_i, negedge rst_ni) begin: verbose_writes
+ if ($test$plusargs("verbose") && data_req_i && data_we_i)
+ $display("write addr=0x%08x: data=0x%08x",
+ data_addr_i, data_wdata_i);
+ end
+
+ // debug rom for booting directly to the firmware
+ boot_rom boot_rom_i (
+ .clk_i ( clk_i ),
+ .req_i ( rom_req ),
+ .addr_i ( rom_addr ),
+ .rdata_o( rom_rdata )
+ );
+
+
+ // instantiate the ram
+ dp_ram #(
+ .ADDR_WIDTH (RAM_ADDR_WIDTH),
+ .INSTR_RDATA_WIDTH (INSTR_RDATA_WIDTH)
+ ) dp_ram_i (
+ .clk_i ( clk_i ),
+
+ .en_a_i ( ram_instr_req ),
+ .addr_a_i ( ram_instr_addr[RAM_ADDR_WIDTH-1:0] ),
+ .wdata_a_i ( '0 ), // Not writing so ignored
+ .rdata_a_o ( ram_instr_rdata ),
+ .we_a_i ( '0 ),
+ .be_a_i ( 4'b1111 ), // Always want 32-bits
+
+ .en_b_i ( ram_data_req ),
+ .addr_b_i ( ram_data_addr ),
+ .wdata_b_i ( ram_data_wdata ),
+ .rdata_b_o ( ram_data_rdata ),
+ .we_b_i ( ram_data_we ),
+ .be_b_i ( ram_data_be )
+ );
+
+ // do the handshacking stuff by assuming we always react in one cycle
+ assign dm_req_o = dm_req;
+ assign dm_addr_o = dm_addr;
+ assign dm_we_o = dm_we;
+ assign dm_be_o = dm_be;
+ assign dm_wdata_o = dm_wdata;
+ assign dm_rdata = dm_rdata_i;
+ assign dm_rvalid = dm_rvalid_i; // TODO: we dont' care about this
+ assign dm_gnt = dm_gnt_i; // TODO: we don't care about this
+
+
+ // sb and core rvalid
+ assign data_rvalid_o = data_rvalid_q;
+ assign sb_rvalid_o = sb_rvalid_q;
+ assign instr_rvalid_o = instr_rvalid_q;
+
+
+ always_ff @(posedge clk_i, negedge rst_ni) begin
+ if (~rst_ni) begin
+ select_rdata_q <= IDLE_READ;
+ select_wdata_q <= IDLE_WRITE;
+
+ data_rvalid_q <= '0;
+ sb_rvalid_q <= '0;
+ instr_rvalid_q <= '0;
+
+ end else begin
+ select_rdata_q <= select_rdata_d;
+ select_wdata_q <= select_wdata_d;
+
+ data_rvalid_q <= data_rvalid_d;
+ sb_rvalid_q <= sb_rvalid_d;
+ instr_rvalid_q <= instr_rvalid_d;
+
+ end
+ end
+
+endmodule // ram
diff --git a/hw/vendor/pulp_riscv_dbg/tb/prog/crt0.S b/hw/vendor/pulp_riscv_dbg/tb/prog/crt0.S
new file mode 100644
index 0000000..5f8d2b2
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/prog/crt0.S
@@ -0,0 +1,66 @@
+/* Copyright (c) 2017 SiFive Inc. All rights reserved.
+ * Copyright (c) 2019 ETH Zürich and University of Bologna
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the FreeBSD License. This program is distributed in the hope that
+ * it will be useful, but WITHOUT ANY WARRANTY expressed or implied,
+ * including the implied warranties of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. A copy of this license is available at
+ * http://www.opensource.org/licenses.
+ */
+
+/* Entry point for bare metal programs */
+.section .text.start
+.global _start
+.type _start, @function
+
+_start:
+/* initialize global pointer */
+.option push
+.option norelax
+1: auipc gp, %pcrel_hi(__global_pointer$)
+ addi gp, gp, %pcrel_lo(1b)
+.option pop
+
+/* initialize stack pointer */
+ la sp, _sp
+
+/* set vector table address */
+ la a0, __vector_start
+ csrw mtvec, a0
+/* set vector table address for CLINTx */
+ la a0, __vector_x_start
+ csrw 0x307, a0
+
+/* clear the bss segment */
+ la a0, __bss_start
+ la a2, __bss_end
+ sub a2, a2, a0
+ li a1, 0
+ call memset
+
+/* new-style constructors and destructors */
+ la a0, __libc_fini_array
+ call atexit
+ call __libc_init_array
+
+/* call main */
+ lw a0, 0(sp) /* a0 = argc */
+ addi a1, sp, __SIZEOF_POINTER__ /* a1 = argv */
+ li a2, 0 /* a2 = envp = NULL */
+ call main
+ tail exit
+
+.size _start, .-_start
+
+.global _init
+.type _init, @function
+.global _fini
+.type _fini, @function
+_init:
+_fini:
+ /* These don't have to do anything since we use init_array/fini_array. Prevent
+ missing symbol error */
+ ret
+.size _init, .-_init
+.size _fini, .-_fini
diff --git a/hw/vendor/pulp_riscv_dbg/tb/prog/link.ld b/hw/vendor/pulp_riscv_dbg/tb/prog/link.ld
new file mode 100644
index 0000000..e8fb802
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/prog/link.ld
@@ -0,0 +1,385 @@
+/* Script for -z combreloc: combine and sort reloc sections */
+/* Copyright (C) 2014-2018 Free Software Foundation, Inc.
+ Copyright (C) 2019 ETH Zürich and University of Bologna
+ Copying and distribution of this script, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. */
+
+/* This linker script is derived from the default linker script of the RISC-V
+ gcc compiler. We have made a few changes to make it suitable for linking bare
+ metal programs. These are mostly removing dynamic linking related sections and
+ putting sections into our memory regions. */
+
+OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv",
+ "elf32-littleriscv")
+OUTPUT_ARCH(riscv)
+ENTRY(_start)
+
+MEMORY
+{
+ /* the memory in the testbench is 1024k in size;
+ * set LENGTH=1008k and leave at least 16k for stack */
+ ram (rwxai) : ORIGIN = 0x1c000000, LENGTH = 0x000fc000
+}
+
+SECTIONS
+{
+ /* we want a fixed entry point */
+ PROVIDE(__boot_address = ORIGIN(ram) + 0x180);
+
+ /* stack and heap related settings */
+ __stack_size = DEFINED(__stack_size) ? __stack_size : 0x400;
+ PROVIDE(__stack_size = __stack_size);
+ __heap_size = DEFINED(__heap_size) ? __heap_size : 0x400;
+
+
+ /* Read-only sections, merged into text segment: */
+ PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x10000)); . = SEGMENT_START("text-segment", 0x10000) + SIZEOF_HEADERS;
+
+
+ /* We don't do any dynamic linking so we remove everything related to it */
+/*
+ .interp : { *(.interp) }
+ .note.gnu.build-id : { *(.note.gnu.build-id) }
+ .hash : { *(.hash) }
+ .gnu.hash : { *(.gnu.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .rela.dyn :
+ {
+ *(.rela.init)
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+ *(.rela.fini)
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+ *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+ *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+ *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+ *(.rela.ctors)
+ *(.rela.dtors)
+ *(.rela.got)
+ *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*)
+ *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*)
+ *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*)
+ *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
+ *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+ PROVIDE_HIDDEN (__rela_iplt_start = .);
+ *(.rela.iplt)
+ PROVIDE_HIDDEN (__rela_iplt_end = .);
+ }
+ .rela.plt :
+ {
+ *(.rela.plt)
+ }
+*/
+
+ /* interrupt vectors */
+ .vectors (ORIGIN(ram)):
+ {
+ PROVIDE(__vector_start = .);
+ KEEP(*(.vectors));
+ } >ram
+
+ /* interrupt vectors x*/
+ .vectors_x (ORIGIN(ram) + 0x100):
+ {
+ PROVIDE(__vector_x_start = .);
+ KEEP(*(.vectors_x));
+ } >ram
+
+ /* crt0 init code */
+ .init (__boot_address):
+ {
+ KEEP (*(SORT_NONE(.init)))
+ KEEP (*(.text.start))
+ } >ram
+
+
+ /* More dynamic linking sections */
+/*
+ .plt : { *(.plt) }
+ .iplt : { *(.iplt) }
+*/
+
+
+ /* the bulk of the program: main, libc, functions etc. */
+ .text :
+ {
+ *(.text.unlikely .text.*_unlikely .text.unlikely.*)
+ *(.text.exit .text.exit.*)
+ *(.text.startup .text.startup.*)
+ *(.text.hot .text.hot.*)
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ } >ram
+
+
+ /* not used by RISC-V*/
+ .fini :
+ {
+ KEEP (*(SORT_NONE(.fini)))
+ } >ram
+
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+
+
+ /* read-only sections */
+ .rodata :
+ {
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+ } >ram
+ .rodata1 :
+ {
+ *(.rodata1)
+ } >ram
+
+
+ /* second level sbss and sdata, I don't think we need this */
+ /* .sdata2 : {*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)} */
+ /* .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } */
+
+
+ /* gcc language agnostic exception related sections (try-catch-finally) */
+ .eh_frame_hdr :
+ {
+ *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*)
+ } >ram
+ .eh_frame : ONLY_IF_RO
+ {
+ KEEP (*(.eh_frame)) *(.eh_frame.*)
+ } >ram
+ .gcc_except_table : ONLY_IF_RO
+ {
+ *(.gcc_except_table .gcc_except_table.*)
+ } >ram
+ .gnu_extab : ONLY_IF_RO
+ {
+ *(.gnu_extab*)
+ } >ram
+ /* These sections are generated by the Sun/Oracle C++ compiler. */
+ /*
+ .exception_ranges : ONLY_IF_RO { *(.exception_ranges
+ .exception_ranges*) }
+ */
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. */
+ . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
+
+
+ /* Exception handling */
+ .eh_frame : ONLY_IF_RW
+ {
+ KEEP (*(.eh_frame)) *(.eh_frame.*)
+ } >ram
+ .gnu_extab : ONLY_IF_RW
+ {
+ *(.gnu_extab)
+ } >ram
+ .gcc_except_table : ONLY_IF_RW
+ {
+ *(.gcc_except_table .gcc_except_table.*)
+ } >ram
+ .exception_ranges : ONLY_IF_RW
+ {
+ *(.exception_ranges .exception_ranges*)
+ } >ram
+
+
+ /* Thread Local Storage sections */
+ .tdata :
+ {
+ PROVIDE_HIDDEN (__tdata_start = .);
+ *(.tdata .tdata.* .gnu.linkonce.td.*)
+ } >ram
+ .tbss :
+ {
+ *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon)
+ } >ram
+
+
+ /* initialization and termination routines */
+ .preinit_array :
+ {
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ } >ram
+ .init_array :
+ {
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
+ KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ } >ram
+ .fini_array :
+ {
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
+ KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ } >ram
+ .ctors :
+ {
+ /* gcc uses crtbegin.o to find the start of
+ the constructors, so we make sure it is
+ first. Because this is a wildcard, it
+ doesn't matter if the user does not
+ actually link against crtbegin.o; the
+ linker won't look for a file to match a
+ wildcard. The wildcard also means that it
+ doesn't matter which directory crtbegin.o
+ is in. */
+ KEEP (*crtbegin.o(.ctors))
+ KEEP (*crtbegin?.o(.ctors))
+ /* We don't want to include the .ctor section from
+ the crtend.o file until after the sorted ctors.
+ The .ctor section from the crtend file contains the
+ end of ctors marker and it must be last */
+ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ } >ram
+ .dtors :
+ {
+ KEEP (*crtbegin.o(.dtors))
+ KEEP (*crtbegin?.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ } >ram
+
+ /* .jcr : { KEEP (*(.jcr)) } */
+ /* .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } */
+ /* .dynamic : { *(.dynamic) } */
+ . = DATA_SEGMENT_RELRO_END (0, .);
+
+
+ /* data sections for initalized data */
+ .data :
+ {
+ __DATA_BEGIN__ = .;
+ *(.data .data.* .gnu.linkonce.d.*)
+ SORT(CONSTRUCTORS)
+ } >ram
+ .data1 :
+ {
+ *(.data1)
+ } > ram
+
+ /* no dynamic linking, no object tables required */
+ /* .got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) } */
+
+ /* We want the small data sections together, so single-instruction offsets
+ can access them all, and initialized data all before uninitialized, so
+ we can shorten the on-disk segment size. */
+ .sdata :
+ {
+ __SDATA_BEGIN__ = .;
+ *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*)
+ *(.sdata .sdata.* .gnu.linkonce.s.*)
+ } >ram
+ _edata = .; PROVIDE (edata = .);
+ . = .;
+
+
+ /* zero initialized sections */
+ __bss_start = .;
+ .sbss :
+ {
+ *(.dynsbss)
+ *(.sbss .sbss.* .gnu.linkonce.sb.*)
+ *(.scommon)
+ } >ram
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections.
+ FIXME: Why do we need it? When there is no .bss section, we don't
+ pad the .data section. */
+ . = ALIGN(. != 0 ? 32 / 8 : 1);
+ } >ram
+ . = ALIGN(32 / 8);
+ . = SEGMENT_START("ldata-segment", .);
+ . = ALIGN(32 / 8);
+ __BSS_END__ = .;
+ __bss_end = .;
+
+ /* The compiler uses this to access data in the .sdata, .data, .sbss and .bss
+ sections with fewer instructions (relaxation). This reduces code size. */
+ __global_pointer$ = MIN(__SDATA_BEGIN__ + 0x800,
+ MAX(__DATA_BEGIN__ + 0x800, __BSS_END__ - 0x800));
+ _end = .; PROVIDE (end = .);
+ . = DATA_SEGMENT_END (.);
+
+
+ /* heap: we should consider putting this to the bottom of the address space */
+ .heap :
+ {
+ PROVIDE(__heap_start = .);
+ . = __heap_size;
+ PROVIDE(__heap_end = .);
+ } >ram
+
+
+ /* stack: we should consider putting this further to the top of the address
+ space */
+ .stack : ALIGN(16) /* this is a requirement of the ABI(?) */
+ {
+ PROVIDE(__stack_start = .);
+ . = __stack_size;
+ PROVIDE(_sp = .);
+ PROVIDE(__stack_end = .);
+ } >ram
+
+
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ /* DWARF 3 */
+ .debug_pubtypes 0 : { *(.debug_pubtypes) }
+ .debug_ranges 0 : { *(.debug_ranges) }
+ /* DWARF Extension. */
+ .debug_macro 0 : { *(.debug_macro) }
+ .debug_addr 0 : { *(.debug_addr) }
+ .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
+ /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
+}
diff --git a/hw/vendor/pulp_riscv_dbg/tb/prog/syscalls.c b/hw/vendor/pulp_riscv_dbg/tb/prog/syscalls.c
new file mode 100644
index 0000000..31f0159
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/prog/syscalls.c
@@ -0,0 +1,270 @@
+/* An extremely minimalist syscalls.c for newlib
+ * Based on riscv newlib libgloss/riscv/sys_*.c
+ *
+ * Copyright 2019 Clifford Wolf
+ * Copyright 2019 ETH Zürich and University of Bologna
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/stat.h>
+#include <newlib.h>
+#include <unistd.h>
+#include <errno.h>
+#undef errno
+extern int errno;
+
+/* write to this reg for outputting strings */
+#define STDOUT_REG 0x10000000
+/* write test result of program to this reg */
+#define RESULT_REG 0x20000000
+/* write exit value of program to this reg */
+#define EXIT_REG 0x20000004
+
+#define STDOUT_FILENO 1
+
+/* It turns out that older newlib versions use different symbol names which goes
+ * against newlib recommendations. Anyway this is fixed in later version.
+ */
+#if __NEWLIB__ <= 2 && __NEWLIB_MINOR__ <= 5
+# define _sbrk sbrk
+# define _write write
+# define _close close
+# define _lseek lseek
+# define _read read
+# define _fstat fstat
+# define _isatty isatty
+#endif
+
+void unimplemented_syscall()
+{
+ const char *p = "Unimplemented system call called!\n";
+ while (*p)
+ *(volatile int *)STDOUT_REG = *(p++);
+}
+
+int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int _access(const char *file, int mode)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int _chdir(const char *path)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int _chmod(const char *path, mode_t mode)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int _chown(const char *path, uid_t owner, gid_t group)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int _close(int file)
+{
+ return -1;
+}
+
+int _execve(const char *name, char *const argv[], char *const env[])
+{
+ errno = ENOMEM;
+ return -1;
+}
+
+void _exit(int exit_status)
+{
+ *(volatile int *)EXIT_REG = exit_status;
+ asm volatile("wfi");
+}
+
+int _faccessat(int dirfd, const char *file, int mode, int flags)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int _fork(void)
+{
+ errno = EAGAIN;
+ return -1;
+}
+
+int _fstat(int file, struct stat *st)
+{
+ st->st_mode = S_IFCHR;
+ return 0;
+ // errno = -ENOSYS;
+ // return -1;
+}
+
+int _fstatat(int dirfd, const char *file, struct stat *st, int flags)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int _ftime(struct timeb *tp)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+char *_getcwd(char *buf, size_t size)
+{
+ errno = -ENOSYS;
+ return NULL;
+}
+
+int _getpid()
+{
+ return 1;
+}
+
+int _gettimeofday(struct timeval *tp, void *tzp)
+{
+ errno = -ENOSYS;
+ return -1;
+}
+
+int _isatty(int file)
+{
+ return (file == STDOUT_FILENO);
+}
+
+int _kill(int pid, int sig)
+{
+ errno = EINVAL;
+ return -1;
+}
+
+int _link(const char *old_name, const char *new_name)
+{
+ errno = EMLINK;
+ return -1;
+}
+
+off_t _lseek(int file, off_t ptr, int dir)
+{
+ return 0;
+}
+
+int _lstat(const char *file, struct stat *st)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int _open(const char *name, int flags, int mode)
+{
+ return -1;
+}
+
+int _openat(int dirfd, const char *name, int flags, int mode)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+ssize_t _read(int file, void *ptr, size_t len)
+{
+ return 0;
+}
+
+int _stat(const char *file, struct stat *st)
+{
+ st->st_mode = S_IFCHR;
+ return 0;
+ // errno = ENOSYS;
+ // return -1;
+}
+
+long _sysconf(int name)
+{
+
+ return -1;
+}
+
+clock_t _times(struct tms *buf)
+{
+ return -1;
+}
+
+int _unlink(const char *name)
+{
+ errno = ENOENT;
+ return -1;
+}
+
+int _utime(const char *path, const struct utimbuf *times)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int _wait(int *status)
+{
+ errno = ECHILD;
+ return -1;
+}
+
+ssize_t _write(int file, const void *ptr, size_t len)
+{
+ if (file != STDOUT_FILENO) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ const void *eptr = ptr + len;
+ while (ptr != eptr)
+ *(volatile int *)STDOUT_REG = *(char *)(ptr++);
+ return len;
+}
+
+extern char __heap_start[];
+extern char __heap_end[];
+static char *brk = __heap_start;
+
+int _brk(void *addr)
+{
+ brk = addr;
+ return 0;
+}
+
+void *_sbrk(ptrdiff_t incr)
+{
+ char *old_brk = brk;
+
+ if (__heap_start == __heap_end) {
+ return NULL;
+ }
+
+ if ((brk += incr) < __heap_end) {
+ brk += incr;
+ } else {
+ brk = __heap_end;
+ }
+ return old_brk;
+}
diff --git a/hw/vendor/pulp_riscv_dbg/tb/prog/test.c b/hw/vendor/pulp_riscv_dbg/tb/prog/test.c
new file mode 100644
index 0000000..81a3579
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/prog/test.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int main(){
+ printf("hello world!\n");
+ return 0;
+}
diff --git a/hw/vendor/pulp_riscv_dbg/tb/prog/vectors.S b/hw/vendor/pulp_riscv_dbg/tb/prog/vectors.S
new file mode 100644
index 0000000..f23c057
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/prog/vectors.S
@@ -0,0 +1,152 @@
+/*
+* Copyright 2019 ETH Zürich and University of Bologna
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+.section .vectors, "ax"
+.option norvc
+vector_table:
+ j sw_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j verification_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+ j __no_irq_handler
+
+/* this is fixed to 0x8000, used for PULP_SECURE=0. We redirect this entry to the
+new vector table (which is at mtvec) */
+/* .section .legacy_irq, "ax" */
+/* j vector_table */
+/* j __no_irq_handler */
+/* j __no_irq_handler */
+/* j __no_irq_handler */
+
+.section .text.vecs
+/* exception handling */
+__no_irq_handler:
+ la a0, no_exception_handler_msg
+ jal ra, puts
+ j __no_irq_handler
+
+
+sw_irq_handler:
+ csrr t0, mcause
+ slli t0, t0, 1 /* shift off the high bit */
+ srli t0, t0, 1
+ li t1, 2
+ beq t0, t1, handle_illegal_insn
+ li t1, 11
+ beq t0, t1, handle_ecall
+ li t1, 3
+ beq t0, t1, handle_ebreak
+ j handle_unknown
+
+handle_ecall:
+ la a0, ecall_msg
+ jal ra, puts
+ j end_handler
+
+handle_ebreak:
+ la a0, ebreak_msg
+ jal ra, puts
+ j end_handler
+
+handle_illegal_insn:
+ la a0, illegal_insn_msg
+ jal ra, puts
+ j end_handler
+
+handle_unknown:
+ la a0, unknown_msg
+ jal ra, puts
+ j end_handler
+
+end_handler:
+ csrr a0, mepc
+ addi a0, a0, 4
+ csrw mepc, a0
+ mret
+/* this interrupt can be generated for verification purposes, random or when the PC is equal to a given value*/
+verification_irq_handler:
+ mret
+
+.section .rodata
+illegal_insn_msg:
+ .string "illegal instruction exception handler entered\n"
+ecall_msg:
+ .string "ecall exception handler entered\n"
+ebreak_msg:
+ .string "ebreak exception handler entered\n"
+unknown_msg:
+ .string "unknown exception handler entered\n"
+no_exception_handler_msg:
+ .string "no exception handler installed\n"
diff --git a/hw/vendor/pulp_riscv_dbg/tb/remote_bitbang/.gitignore b/hw/vendor/pulp_riscv_dbg/tb/remote_bitbang/.gitignore
new file mode 100644
index 0000000..0015e3f
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/remote_bitbang/.gitignore
@@ -0,0 +1,3 @@
+*.o
+*.d
+*.so
\ No newline at end of file
diff --git a/hw/vendor/pulp_riscv_dbg/tb/remote_bitbang/Makefile b/hw/vendor/pulp_riscv_dbg/tb/remote_bitbang/Makefile
new file mode 100644
index 0000000..8deb36a
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/remote_bitbang/Makefile
@@ -0,0 +1,124 @@
+# Copyright (C) 2020 ETH Zurich and University of Bologna
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+# Author: Robert Balas (balasr@iis.ee.ethz.ch)
+
+CFLAGS = -Wall -Wextra -Wno-missing-field-initializers \
+ -Wno-unused-function -Wno-missing-braces \
+ -O2 -g -march=native \
+ -DENABLE_LOGGING -DNDEBUG
+CFLAGS_DBG =
+# we need gnu11 and no-strict-aliasing
+ALL_CFLAGS = -std=gnu11 -fno-strict-aliasing $(CFLAGS)
+ALL_CFLAGS_DBG = -std=gnu11 -Wall -Wextra -Wno-missing-field-initializers \
+ -Wno-unused-function -Wno-missing-braces \
+ -O0 -g -fno-strict-aliasing \
+ -fsanitize=address -fno-omit-frame-pointer \
+ -DENABLE_LOGGING -DENABLE_DEBUG $(CFLAGS_DBG)\
+# -fsanitize=undefined \
+# -fsanitize=leak \
+
+
+# TODO: better path?
+LIB_DIRS =
+LIBS =
+INCLUDE_DIRS = ./
+
+
+LDFLAGS = $(addprefix -L, $(LIB_DIRS))
+LDLIBS = $(addprefix -l, $(LIBS))
+
+SRCS = remote_bitbang.c sim_jtag.c
+OBJS = $(SRCS:.c=.o)
+INCLUDES = $(addprefix -I, $(INCLUDE_DIRS))
+
+HEADERS = $(wildcard *.h)
+
+# libs
+SV_LIB = librbs.so
+
+# header file dependency generation
+DEPDIR := .d
+DEPDIRS := $(addsuffix /$(DEPDIR),.)
+# goal: make gcc put a dependency file called obj.Td (derived from subdir/obj.o)
+# in subdir/.d/
+DEPFLAGS = -MT $@ -MMD -MP -MF $(@D)/$(DEPDIR)/$(patsubst %.o,%.Td,$(@F))
+# move gcc generated header dependencies to DEPDIR
+# this rename step is here to make the header dependency generation "atomic"
+POSTCOMPILE = @mv -f $(@D)/$(DEPDIR)/$(patsubst %.o,%.Td,$(@F)) \
+ $(@D)/$(DEPDIR)/$(patsubst %.o,%.d,$(@F)) && touch $@
+
+# GNU recommendations for install targets
+prefix = /usr/local
+exec_prefix = $(prefix)
+bindir = $(exec_prefix)/bin
+libdir = $(exec_prefix)/lib
+includedir = $(prefix)/include
+
+INSTALL = install
+INSTALL_PROGRAM = $(INSTALL)
+INSTALL_DATA = ${INSTALL} -m 644
+
+CTAGS = ctags
+
+# compilation targets
+all: sv-lib
+
+debug: ALL_CFLAGS = $(ALL_CFLAGS_DBG)
+debug: all
+
+sv-lib: ALL_CFLAGS += -fPIC
+sv-lib: $(SV_LIB)
+
+#compilation boilerplate
+$(SV_LIB): $(OBJS)
+ $(LD) -shared -E --exclude-libs ALL -o $(SV_LIB) $(LDFLAGS) \
+ $(OBJS) $(LDLIBS)
+
+# $@ = name of target
+# $< = first dependency
+%.o: %.c
+%.o: %.c $(DEPDIR)/%.d $(DEPDIRS)
+ $(CC) $(DEPFLAGS) $(ALL_CFLAGS) $(INCLUDES) $(LDFLAGS) \
+ -c $(CPPFLAGS) $< -o $@ $(LDLIBS)
+ $(POSTCOMPILE)
+
+# check if we need to create the dependencies folders (gcc doesn't)
+$(DEPDIRS):
+ $(shell mkdir -p $(DEPDIRS) > /dev/null)
+# make won't fail if the dependency file doesn't exist
+$(addsuffix /$(DEPDIR)/%.d,. main benchmark test dpi): ;
+
+# prevent automatic deletion as intermediate file
+.PRECIOUS: $(addsuffix /$(DEPDIR)/%.d,. main benchmark test dpi)
+
+# emacs tag generation
+.PHONY: TAGS
+TAGS:
+ $(CTAGS) -R -e -h=".c.h" --tag-relative=always \
+ . $(LIB_DIRS) $(INCLUDE_DIRS) $(BINUTILS_PATH)/bfd
+
+# TODO: missing install targets
+# cleanup
+.PHONY: clean
+clean:
+ rm -rf $(SV_LIB) $(OBJS) $(DEPDIRS)
+
+.PHONY: distclean
+distclean: clean
+ rm -f TAGS
+
+# include auto generated header dependency information
+include $(wildcard $(addsuffix /*.d,$(DEPDIRS)))
diff --git a/hw/vendor/pulp_riscv_dbg/tb/remote_bitbang/rbs_test.c b/hw/vendor/pulp_riscv_dbg/tb/remote_bitbang/rbs_test.c
new file mode 100644
index 0000000..328574e
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/remote_bitbang/rbs_test.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 2020 ETH Zurich and University of Bologna
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Author: Robert Balas (balasr@iis.ee.ethz.ch)
+ */
+
+#include <stdio.h>
+#include "remote_bitbang.h"
+
+int main()
+{
+ unsigned char jtag_TCK, jtag_TMS, jtag_TDI, jtag_TRSTn;
+ unsigned char jtag_TDO = 0;
+
+ printf("calling rbs_init\n");
+ int v = rbs_init(0);
+
+ printf("tick 1\n");
+ rbs_tick(&jtag_TCK, &jtag_TMS, &jtag_TDI, &jtag_TRSTn, jtag_TDO);
+ printf("jtag exit is %d\n", rbs_done());
+ return 0;
+}
diff --git a/hw/vendor/pulp_riscv_dbg/tb/remote_bitbang/remote_bitbang.c b/hw/vendor/pulp_riscv_dbg/tb/remote_bitbang/remote_bitbang.c
new file mode 100644
index 0000000..e77c00d
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/remote_bitbang/remote_bitbang.c
@@ -0,0 +1,275 @@
+// See LICENSE.Berkeley for license details.
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "remote_bitbang.h"
+
+int rbs_init(uint16_t port)
+{
+ socket_fd = 0;
+ client_fd = 0;
+ recv_start = 0;
+ recv_end = 0;
+ rbs_err = 0;
+
+ socket_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (socket_fd == -1) {
+ fprintf(stderr, "remote_bitbang failed to make socket: %s (%d)\n",
+ strerror(errno), errno);
+ abort();
+ }
+
+ fcntl(socket_fd, F_SETFL, O_NONBLOCK);
+ int reuseaddr = 1;
+ if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
+ sizeof(int)) == -1) {
+ fprintf(stderr, "remote_bitbang failed setsockopt: %s (%d)\n",
+ strerror(errno), errno);
+ abort();
+ }
+
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_ANY;
+ addr.sin_port = htons(port);
+
+ if (bind(socket_fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+ fprintf(stderr, "remote_bitbang failed to bind socket: %s (%d)\n",
+ strerror(errno), errno);
+ abort();
+ }
+
+ if (listen(socket_fd, 1) == -1) {
+ fprintf(stderr, "remote_bitbang failed to listen on socket: %s (%d)\n",
+ strerror(errno), errno);
+ abort();
+ }
+
+ socklen_t addrlen = sizeof(addr);
+ if (getsockname(socket_fd, (struct sockaddr *)&addr, &addrlen) == -1) {
+ fprintf(stderr, "remote_bitbang getsockname failed: %s (%d)\n",
+ strerror(errno), errno);
+ abort();
+ }
+
+ tck = 1;
+ tms = 1;
+ tdi = 1;
+ trstn = 1;
+ quit = 0;
+
+ fprintf(stderr, "JTAG remote bitbang server is ready\n");
+ fprintf(stderr, "Listening on port %d\n", ntohs(addr.sin_port));
+ return 1;
+}
+
+void rbs_accept()
+{
+ fprintf(stderr, "Attempting to accept client socket\n");
+ int again = 1;
+ while (again != 0) {
+ client_fd = accept(socket_fd, NULL, NULL);
+ if (client_fd == -1) {
+ if (errno == EAGAIN) {
+ // No client waiting to connect right now.
+ } else {
+ fprintf(stderr, "failed to accept on socket: %s (%d)\n",
+ strerror(errno), errno);
+ again = 0;
+ abort();
+ }
+ } else {
+ fcntl(client_fd, F_SETFL, O_NONBLOCK);
+ fprintf(stderr, "Accepted successfully.");
+ again = 0;
+ }
+ }
+}
+
+void rbs_tick(unsigned char *jtag_tck, unsigned char *jtag_tms,
+ unsigned char *jtag_tdi, unsigned char *jtag_trstn,
+ unsigned char jtag_tdo)
+{
+ if (client_fd > 0) {
+ tdo = jtag_tdo;
+ rbs_execute_command();
+ } else {
+ rbs_accept();
+ }
+
+ *jtag_tck = tck;
+ *jtag_tms = tms;
+ *jtag_tdi = tdi;
+ *jtag_trstn = trstn;
+}
+
+void rbs_reset()
+{
+ // trstn = 0;
+}
+
+void rbs_set_pins(char _tck, char _tms, char _tdi)
+{
+ tck = _tck;
+ tms = _tms;
+ tdi = _tdi;
+}
+
+void rbs_execute_command()
+{
+ char command;
+ int again = 1;
+ while (again) {
+ ssize_t num_read = read(client_fd, &command, sizeof(command));
+ if (num_read == -1) {
+ if (errno == EAGAIN) {
+ // We'll try again the next call.
+ if (VERBOSE)
+ fprintf(
+ stderr,
+ "Received no command. Will try again on the next call\n");
+ } else {
+ fprintf(stderr,
+ "remote_bitbang failed to read on socket: %s (%d)\n",
+ strerror(errno), errno);
+ again = 0;
+ abort();
+ }
+ } else if (num_read == 0) {
+ fprintf(stderr, "No command received. Stopping further reads.\n");
+ // again = 1;
+ return;
+ } else {
+ again = 0;
+ }
+ }
+
+ int dosend = 0;
+
+ char tosend = '?';
+
+ switch (command) {
+ case 'B':
+ if (VERBOSE)
+ fprintf(stderr, "*BLINK*\n");
+ break;
+ case 'b':
+ if (VERBOSE)
+ fprintf(stderr, "blink off\n");
+ break;
+ case 'r':
+ if (VERBOSE)
+ fprintf(stderr, "r-reset\n");
+ rbs_reset();
+ break; // This is wrong. 'r' has other bits that indicated TRST and
+ // SRST.
+ case 's':
+ if (VERBOSE)
+ fprintf(stderr, "s-reset\n");
+ rbs_reset();
+ break; // This is wrong.
+ case 't':
+ if (VERBOSE)
+ fprintf(stderr, "t-reset\n");
+ rbs_reset();
+ break; // This is wrong.
+ case 'u':
+ if (VERBOSE)
+ fprintf(stderr, "u-reset\n");
+ rbs_reset();
+ break; // This is wrong.
+ case '0':
+ if (VERBOSE)
+ fprintf(stderr, "Write 0 0 0\n");
+ rbs_set_pins(0, 0, 0);
+ break;
+ case '1':
+ if (VERBOSE)
+ fprintf(stderr, "Write 0 0 1\n");
+ rbs_set_pins(0, 0, 1);
+ break;
+ case '2':
+ if (VERBOSE)
+ fprintf(stderr, "Write 0 1 0\n");
+ rbs_set_pins(0, 1, 0);
+ break;
+ case '3':
+ if (VERBOSE)
+ fprintf(stderr, "Write 0 1 1\n");
+ rbs_set_pins(0, 1, 1);
+ break;
+ case '4':
+ if (VERBOSE)
+ fprintf(stderr, "Write 1 0 0\n");
+ rbs_set_pins(1, 0, 0);
+ break;
+ case '5':
+ if (VERBOSE)
+ fprintf(stderr, "Write 1 0 1\n");
+ rbs_set_pins(1, 0, 1);
+ break;
+ case '6':
+ if (VERBOSE)
+ fprintf(stderr, "Write 1 1 0\n");
+ rbs_set_pins(1, 1, 0);
+ break;
+ case '7':
+ if (VERBOSE)
+ fprintf(stderr, "Write 1 1 1\n");
+ rbs_set_pins(1, 1, 1);
+ break;
+ case 'R':
+ if (VERBOSE)
+ fprintf(stderr, "Read req\n");
+ dosend = 1;
+ tosend = tdo ? '1' : '0';
+ break;
+ case 'Q':
+ if (VERBOSE)
+ fprintf(stderr, "Quit req\n");
+ quit = 1;
+ break;
+ default:
+ fprintf(stderr, "remote_bitbang got unsupported command '%c'\n",
+ command);
+ }
+ if (dosend) {
+ while (1) {
+ ssize_t bytes = write(client_fd, &tosend, sizeof(tosend));
+ if (bytes == -1) {
+ fprintf(stderr, "failed to write to socket: %s (%d)\n",
+ strerror(errno), errno);
+ abort();
+ }
+ if (bytes > 0) {
+ break;
+ }
+ }
+ }
+
+ if (quit) {
+ fprintf(stderr, "Remote end disconnected\n");
+ close(client_fd);
+ client_fd = 0;
+ }
+}
+
+unsigned char rbs_done()
+{
+ return quit;
+}
+
+int rbs_exit_code()
+{
+ return rbs_err;
+}
diff --git a/hw/vendor/pulp_riscv_dbg/tb/remote_bitbang/remote_bitbang.h b/hw/vendor/pulp_riscv_dbg/tb/remote_bitbang/remote_bitbang.h
new file mode 100644
index 0000000..460819e
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/remote_bitbang/remote_bitbang.h
@@ -0,0 +1,52 @@
+// See LICENSE.Berkeley for license details.
+
+#ifndef REMOTE_BITBANG_H
+#define REMOTE_BITBANG_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#define VERBOSE 0
+
+int rbs_err;
+
+unsigned char tck;
+unsigned char tms;
+unsigned char tdi;
+unsigned char trstn;
+unsigned char tdo;
+unsigned char quit;
+
+int socket_fd;
+int client_fd;
+
+static const ssize_t buf_size = 64 * 1024;
+char recv_buf[64 * 1024];
+ssize_t recv_start, recv_end;
+
+// Create a new server, listening for connections from localhost on the given
+// port.
+int rbs_init(uint16_t port);
+
+// Do a bit of work.
+void rbs_tick(unsigned char *jtag_tck, unsigned char *jtag_tms,
+ unsigned char *jtag_tdi, unsigned char *jtag_trstn,
+ unsigned char jtag_tdo);
+
+unsigned char rbs_done();
+
+int rbs_exit_code();
+
+// Check for a client connecting, and accept if there is one.
+void rbs_accept();
+// Execute any commands the client has for us.
+// But we only execute 1 because we need time for the
+// simulation to run.
+void rbs_execute_command();
+
+// Reset. Currently does nothing.
+void rbs_reset();
+
+void rbs_set_pins(char _tck, char _tms, char _tdi);
+
+#endif
diff --git a/hw/vendor/pulp_riscv_dbg/tb/remote_bitbang/sim_jtag.c b/hw/vendor/pulp_riscv_dbg/tb/remote_bitbang/sim_jtag.c
new file mode 100644
index 0000000..769ba88
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/remote_bitbang/sim_jtag.c
@@ -0,0 +1,29 @@
+// See LICENSE.SiFive for license details.
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "remote_bitbang.h"
+
+int init = 0;
+
+int jtag_tick(int port, unsigned char *jtag_TCK, unsigned char *jtag_TMS,
+ unsigned char *jtag_TDI, unsigned char *jtag_TRSTn,
+ unsigned char jtag_TDO)
+
+{
+ if (!init) {
+ if (port < 0 || port > UINT16_MAX)
+ fprintf(stderr, "Port number of out range: %d\n", port);
+ init = rbs_init(port);
+ }
+
+ rbs_tick(jtag_TCK, jtag_TMS, jtag_TDI, jtag_TRSTn, jtag_TDO);
+ if (VERBOSE)
+ fprintf(
+ stderr,
+ "Tick with: TCK=%hhd TMS=%hhd TDI=%hhd TRSTn=%hhd --> TDO=%hhd\n",
+ *jtag_TCK, *jtag_TMS, *jtag_TDI, *jtag_TRSTn, jtag_TDO);
+
+ return rbs_done() ? (rbs_exit_code() << 1 | 1) : 0;
+}
diff --git a/hw/vendor/pulp_riscv_dbg/tb/tb_test_env.sv b/hw/vendor/pulp_riscv_dbg/tb/tb_test_env.sv
new file mode 100644
index 0000000..f9e72a8
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/tb_test_env.sv
@@ -0,0 +1,338 @@
+// Copyright 2020 ETH Zurich and University of Bologna.
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+// Wrapper for a RI5CY testbench, containing RI5CY, Memory and stdout peripheral
+// Contributor: Robert Balas <balasr@iis.ee.ethz.ch>
+
+module tb_test_env #(
+ parameter int unsigned INSTR_RDATA_WIDTH = 32,
+ parameter int unsigned RAM_ADDR_WIDTH = 20,
+ parameter logic [31:0] BOOT_ADDR = 'h80,
+ parameter bit PULP_SECURE = 1,
+ parameter bit JTAG_BOOT = 1,
+ parameter int unsigned OPENOCD_PORT = 0,
+ parameter bit A_EXTENSION = 0
+) (
+ input logic clk_i,
+ input logic rst_ni,
+
+ // currently we are not making use of those signals
+ input logic fetch_enable_i,
+ output logic tests_passed_o,
+ output logic tests_failed_o);
+
+ // defs from pulpissimo
+ // localparam CLUSTER_ID = 6'd31;
+ // localparam CORE_ID = 4'd0;
+ // test defs
+ localparam CLUSTER_ID = 6'd0;
+ localparam CORE_ID = 4'd0;
+
+ localparam CORE_MHARTID = {CLUSTER_ID, 1'b0, CORE_ID};
+ localparam NrHarts = 1;
+ localparam logic [NrHarts-1:0] SELECTABLE_HARTS = 1 << CORE_MHARTID;
+
+ // signals connecting core to memory
+ logic instr_req;
+ logic instr_gnt;
+ logic instr_rvalid;
+ logic [31:0] instr_addr;
+ logic [INSTR_RDATA_WIDTH-1:0] instr_rdata;
+
+ logic data_req;
+ logic data_gnt;
+ logic data_rvalid;
+ logic [31:0] data_addr;
+ logic data_we;
+ logic [3:0] data_be;
+ logic [31:0] data_rdata;
+ logic [31:0] data_wdata;
+
+ // jtag openocd bridge signals
+ logic sim_jtag_tck;
+ logic sim_jtag_tms;
+ logic sim_jtag_tdi;
+ logic sim_jtag_trstn;
+ logic sim_jtag_tdo;
+ logic [31:0] sim_jtag_exit;
+ logic sim_jtag_enable;
+
+ // signals for debug unit
+ logic debug_req_ready;
+ dm::dmi_resp_t debug_resp;
+ logic jtag_req_valid;
+ dm::dmi_req_t jtag_dmi_req;
+ logic jtag_resp_ready;
+ logic jtag_resp_valid;
+ logic [NrHarts-1:0] dm_debug_req;
+ logic ndmreset, ndmreset_n;
+
+ // debug unit slave interface
+ logic dm_grant;
+ logic dm_rvalid;
+ logic dm_req;
+ logic dm_we;
+ logic [31:0] dm_addr;
+ logic [31:0] dm_wdata;
+ logic [31:0] dm_rdata;
+ logic [3:0] dm_be;
+
+ // debug unit master interface (system bus access)
+ logic sb_req;
+ logic [31:0] sb_addr;
+ logic sb_we;
+ logic [31:0] sb_wdata;
+ logic [3:0] sb_be;
+ logic sb_gnt;
+ logic sb_rvalid;
+ logic [31:0] sb_rdata;
+
+ // irq signals (not used)
+ logic irq;
+ logic [0:4] irq_id_in;
+ logic irq_ack;
+ logic [0:4] irq_id_out;
+ logic irq_sec;
+
+ // make jtag bridge work
+ assign sim_jtag_enable = JTAG_BOOT;
+
+ // interrupts (only timer for now)
+ assign irq_sec = '0;
+
+ // instantiate the core
+ riscv_core #(
+ .INSTR_RDATA_WIDTH (INSTR_RDATA_WIDTH),
+ .PULP_SECURE(PULP_SECURE),
+ .A_EXTENSION(A_EXTENSION),
+ .FPU(0)
+ ) riscv_core_i (
+ .clk_i ( clk_i ),
+ .rst_ni ( ndmreset_n ),
+
+ .clock_en_i ( '1 ),
+ .test_en_i ( '0 ),
+
+ .boot_addr_i ( BOOT_ADDR ),
+ .core_id_i ( CORE_ID ),
+ .cluster_id_i ( CLUSTER_ID ),
+
+ .instr_addr_o ( instr_addr ),
+ .instr_req_o ( instr_req ),
+ .instr_rdata_i ( instr_rdata ),
+ .instr_gnt_i ( instr_gnt ),
+ .instr_rvalid_i ( instr_rvalid ),
+
+ .data_addr_o ( data_addr ),
+ .data_wdata_o ( data_wdata ),
+ .data_we_o ( data_we ),
+ .data_req_o ( data_req ),
+ .data_be_o ( data_be ),
+ .data_rdata_i ( data_rdata ),
+ .data_gnt_i ( data_gnt ),
+ .data_rvalid_i ( data_rvalid ),
+ .data_atop_o ( ),
+
+ .apu_master_req_o ( ),
+ .apu_master_ready_o ( ),
+ .apu_master_gnt_i ( ),
+ .apu_master_operands_o ( ),
+ .apu_master_op_o ( ),
+ .apu_master_type_o ( ),
+ .apu_master_flags_o ( ),
+ .apu_master_valid_i ( ),
+ .apu_master_result_i ( ),
+ .apu_master_flags_i ( ),
+
+
+ .irq_software_i ( 1'b0 ),
+ .irq_timer_i ( 1'b0 ),
+ .irq_external_i ( 1'b0 ),
+ .irq_fast_i ( 15'b0 ),
+ .irq_nmi_i ( 1'b0 ),
+ .irq_fastx_i ( 32'b0 ),
+
+ .irq_ack_o ( irq_ack ),
+ .irq_id_o ( irq_id_out ),
+ .irq_sec_i ( irq_sec ),
+
+ .sec_lvl_o ( sec_lvl_o ),
+
+ .debug_req_i ( dm_debug_req[CORE_MHARTID] ),
+
+ .fetch_enable_i ( fetch_enable_i ),
+ .core_busy_o ( core_busy_o ),
+
+ .ext_perf_counters_i ( ),
+ .fregfile_disable_i ( 1'b0 )
+ );
+
+ // this handles read to RAM and memory mapped pseudo peripherals
+ mm_ram #(
+ .RAM_ADDR_WIDTH (RAM_ADDR_WIDTH),
+ .INSTR_RDATA_WIDTH (INSTR_RDATA_WIDTH),
+ .JTAG_BOOT(JTAG_BOOT)
+ ) mm_ram_i (
+ .clk_i ( clk_i ),
+ .rst_ni ( ndmreset_n ),
+
+ // core instruction access
+ .instr_req_i ( instr_req ),
+ .instr_addr_i ( instr_addr ),
+ .instr_rdata_o ( instr_rdata ),
+ .instr_rvalid_o ( instr_rvalid ),
+ .instr_gnt_o ( instr_gnt ),
+
+ // core data access
+ .data_req_i ( data_req ),
+ .data_addr_i ( data_addr ),
+ .data_we_i ( data_we ),
+ .data_be_i ( data_be ),
+ .data_wdata_i ( data_wdata ),
+ .data_rdata_o ( data_rdata ),
+ .data_rvalid_o ( data_rvalid ),
+ .data_gnt_o ( data_gnt ),
+
+ // system bus access from debug unit
+ .sb_req_i ( sb_req ),
+ .sb_addr_i ( sb_addr ),
+ .sb_we_i ( sb_we ),
+ .sb_be_i ( sb_be ),
+ .sb_wdata_i ( sb_wdata ),
+ .sb_rdata_o ( sb_rdata ),
+ .sb_rvalid_o ( sb_rvalid ),
+ .sb_gnt_o ( sb_gnt ),
+
+ // access to debug unit
+ .dm_req_o ( dm_req ),
+ .dm_addr_o ( dm_addr ),
+ .dm_we_o ( dm_we ),
+ .dm_be_o ( dm_be ),
+ .dm_wdata_o ( dm_wdata ),
+ .dm_rdata_i ( dm_rdata ),
+ .dm_rvalid_i ( dm_rvalid ),
+ .dm_gnt_i ( dm_gnt ),
+
+
+ .irq_id_i ( irq_id_out ),
+ .irq_ack_i ( irq_ack ),
+ .irq_id_o ( irq_id_in ),
+ .irq_o ( irq ),
+
+ .tests_passed_o ( tests_passed_o ),
+ .tests_failed_o ( tests_failed_o )
+ );
+
+ // debug subsystem
+ dmi_jtag #(
+ .IdcodeValue ( 32'h249511C3 )
+ ) i_dmi_jtag (
+ .clk_i ( clk_i ),
+ .rst_ni ( rst_ni ),
+ .testmode_i ( 1'b0 ),
+ .dmi_req_o ( jtag_dmi_req ),
+ .dmi_req_valid_o ( jtag_req_valid ),
+ .dmi_req_ready_i ( debug_req_ready ),
+ .dmi_resp_i ( debug_resp ),
+ .dmi_resp_ready_o ( jtag_resp_ready ),
+ .dmi_resp_valid_i ( jtag_resp_valid ),
+ .dmi_rst_no ( ), // not connected
+ .tck_i ( sim_jtag_tck ),
+ .tms_i ( sim_jtag_tms ),
+ .trst_ni ( sim_jtag_trstn ),
+ .td_i ( sim_jtag_tdi ),
+ .td_o ( sim_jtag_tdo ),
+ .tdo_oe_o ( )
+ );
+
+ dm_top #(
+ .NrHarts ( NrHarts ),
+ .BusWidth ( 32 ),
+ .SelectableHarts ( SELECTABLE_HARTS )
+ ) i_dm_top (
+
+ .clk_i ( clk_i ),
+ .rst_ni ( rst_ni ),
+ .testmode_i ( 1'b0 ),
+ .ndmreset_o ( ndmreset ),
+ .dmactive_o ( ), // active debug session TODO
+ .debug_req_o ( dm_debug_req ),
+ .unavailable_i ( ~SELECTABLE_HARTS ),
+ .hartinfo_i ( '0 ),
+
+ .slave_req_i ( dm_req ),
+ .slave_we_i ( dm_we ),
+ .slave_addr_i ( dm_addr ),
+ .slave_be_i ( dm_be ),
+ .slave_wdata_i ( dm_wdata ),
+ .slave_rdata_o ( dm_rdata ),
+
+ .master_req_o ( sb_req ),
+ .master_add_o ( sb_addr ),
+ .master_we_o ( sb_we ),
+ .master_wdata_o ( sb_wdata ),
+ .master_be_o ( sb_be ),
+ .master_gnt_i ( sb_gnt ),
+ .master_r_valid_i ( sb_rvalid ),
+ .master_r_rdata_i ( sb_rdata ),
+
+ .dmi_rst_ni ( rst_ni ),
+ .dmi_req_valid_i ( jtag_req_valid ),
+ .dmi_req_ready_o ( debug_req_ready ),
+ .dmi_req_i ( jtag_dmi_req ),
+ .dmi_resp_valid_o ( jtag_resp_valid ),
+ .dmi_resp_ready_i ( jtag_resp_ready ),
+ .dmi_resp_o ( debug_resp )
+ );
+
+ // grant in the same cycle
+ assign dm_gnt = dm_req;
+ // valid read/write in the next cycle
+ always_ff @(posedge clk_i or negedge rst_ni) begin : dm_valid_handler
+ if(~rst_ni) begin
+ dm_rvalid <= '0;
+ end else begin
+ dm_rvalid <= dm_gnt;
+ end
+ end
+
+ // reset handling with ndmreset
+ rstgen i_rstgen_main (
+ .clk_i ( clk_i ),
+ .rst_ni ( rst_ni & (~ndmreset) ),
+ .test_mode_i ( '0 ),
+ .rst_no ( ndmreset_n ),
+ .init_no ( ) // keep open
+ );
+
+ // jtag calls from dpi
+ SimJTAG #(
+ .TICK_DELAY (1),
+ .PORT(OPENOCD_PORT)
+ ) i_sim_jtag (
+ .clock ( clk_i ),
+ .reset ( ~rst_ni ),
+ .enable ( sim_jtag_enable ),
+ .init_done ( rst_ni ),
+ .jtag_TCK ( sim_jtag_tck ),
+ .jtag_TMS ( sim_jtag_tms ),
+ .jtag_TDI ( sim_jtag_tdi ),
+ .jtag_TRSTn ( sim_jtag_trstn ),
+ .jtag_TDO_data ( sim_jtag_tdo ),
+ .jtag_TDO_driven ( 1'b1 ),
+ .exit ( sim_jtag_exit )
+ );
+
+ always_comb begin : jtag_exit_handler
+ if (sim_jtag_exit)
+ $finish(2); // print stats too
+ end
+
+endmodule // tb_test_env
diff --git a/hw/vendor/pulp_riscv_dbg/tb/tb_top.sv b/hw/vendor/pulp_riscv_dbg/tb/tb_top.sv
new file mode 100644
index 0000000..9e7525f
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/tb_top.sv
@@ -0,0 +1,138 @@
+// Copyright 2017 Embecosm Limited <www.embecosm.com>
+// Copyright 2018 Robert Balas <balasr@student.ethz.ch>
+// Copyright 2020 ETH Zurich and University of Bologna.
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+// Top level wrapper for a RI5CY testbench
+// Contributor: Robert Balas <balasr@iis.ee.ethz.ch>
+// Jeremy Bennett <jeremy.bennett@embecosm.com>
+
+module tb_top #(
+ parameter int unsigned INSTR_RDATA_WIDTH = 32,
+ parameter int unsigned RAM_ADDR_WIDTH = 22,
+ parameter logic [31:0] BOOT_ADDR = 'h1A00_0180,
+ parameter bit JTAG_BOOT = 1,
+ parameter int unsigned OPENOCD_PORT = 9999
+);
+
+ // comment to record execution trace
+ //`define TRACE_EXECUTION
+
+ const time CLK_PHASE_HI = 5ns;
+ const time CLK_PHASE_LO = 5ns;
+ const time CLK_PERIOD = CLK_PHASE_HI + CLK_PHASE_LO;
+ const time STIM_APPLICATION_DEL = CLK_PERIOD * 0.1;
+ const time RESP_ACQUISITION_DEL = CLK_PERIOD * 0.9;
+ const time RESET_DEL = STIM_APPLICATION_DEL;
+ const int RESET_WAIT_CYCLES = 4;
+
+ // clock and reset for tb
+ logic clk = 'b1;
+ logic rst_n = 'b0;
+
+ // testbench result
+ logic tests_passed;
+ logic tests_failed;
+
+ // signals for ri5cy
+ logic fetch_enable;
+
+
+ // make the core start fetching instruction immediately
+ assign fetch_enable = '1;
+
+ // allow vcd dump
+ initial begin: dump_vars
+ if ($test$plusargs("vcd")) begin
+ $dumpfile("riscy_tb.vcd");
+ $dumpvars(0, tb_top);
+ end
+`ifdef QUESTA
+ if ($test$plusargs("wlfdump")) begin
+ $wlfdumpvars(0, tb_top);
+ end
+`endif
+ end
+
+ // we either load the provided firmware or execute a small test program that
+ // doesn't do more than an infinite loop with some I/O
+ initial begin: load_prog
+ automatic logic [1023:0] firmware;
+ automatic int prog_size = 6;
+
+ if($value$plusargs("firmware=%s", firmware)) begin
+ if($test$plusargs("verbose"))
+ $display("[TESTBENCH] %t: loading firmware %0s ...",
+ $time, firmware);
+ $readmemh(firmware, tb_test_env_i.mm_ram_i.dp_ram_i.mem);
+
+ end else begin
+ $display("No firmware specified");
+ end
+ end
+
+ // clock generation
+ initial begin: clock_gen
+ forever begin
+ #CLK_PHASE_HI clk = 1'b0;
+ #CLK_PHASE_LO clk = 1'b1;
+ end
+ end: clock_gen
+
+ // reset generation
+ initial begin: reset_gen
+ rst_n = 1'b0;
+
+ // wait a few cycles
+ repeat (RESET_WAIT_CYCLES) begin
+ @(posedge clk); //TODO: was posedge, see below
+ end
+
+ // start running
+ #RESET_DEL rst_n = 1'b1;
+ if($test$plusargs("verbose"))
+ $display("reset deasserted", $time);
+
+ end: reset_gen
+
+ // set timing format
+ initial begin: timing_format
+ $timeformat(-9, 0, "ns", 9);
+ end: timing_format
+
+ // check if we succeded
+ always_ff @(posedge clk, negedge rst_n) begin
+ if (tests_passed) begin
+ $display("Exit Success");
+ $finish;
+ end
+ if (tests_failed) begin
+ $display("Exit FAILURE");
+ $finish;
+ end
+ end
+
+ // wrapper for riscv, the memory system and stdout peripheral
+ tb_test_env #(
+ .INSTR_RDATA_WIDTH (INSTR_RDATA_WIDTH),
+ .RAM_ADDR_WIDTH (RAM_ADDR_WIDTH),
+ .BOOT_ADDR (BOOT_ADDR),
+ .PULP_SECURE (1),
+ .JTAG_BOOT (JTAG_BOOT),
+ .OPENOCD_PORT (OPENOCD_PORT)
+ ) tb_test_env_i(
+ .clk_i ( clk ),
+ .rst_ni ( rst_n ),
+ .fetch_enable_i ( fetch_enable ),
+ .tests_passed_o ( tests_passed ),
+ .tests_failed_o ( tests_failed )
+ );
+
+endmodule // tb_top
diff --git a/hw/vendor/pulp_riscv_dbg/tb/tb_top_verilator.cpp b/hw/vendor/pulp_riscv_dbg/tb/tb_top_verilator.cpp
new file mode 100644
index 0000000..1009b13
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/tb_top_verilator.cpp
@@ -0,0 +1,105 @@
+// Copyright 2018 Robert Balas <balasr@student.ethz.ch>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+// Top level wrapper for a verilator RI5CY testbench
+// Contributor: Robert Balas <balasr@student.ethz.ch>
+
+#include "svdpi.h"
+#include "Vtb_top_verilator__Dpi.h"
+#include "Vtb_top_verilator.h"
+#include "verilated_vcd_c.h"
+#include "verilated.h"
+
+#include <iostream>
+#include <iomanip>
+#include <fstream>
+#include <exception>
+#include <cstdio>
+#include <cstdint>
+#include <cerrno>
+
+void dump_memory();
+double sc_time_stamp();
+
+static vluint64_t t = 0;
+Vtb_top_verilator *top;
+
+int main(int argc, char **argv, char **env)
+{
+ Verilated::commandArgs(argc, argv);
+ Verilated::traceEverOn(true);
+ top = new Vtb_top_verilator();
+
+ svSetScope(svGetScopeFromName(
+ "TOP.tb_top_verilator.mm_ram_i.dp_ram_i"));
+ Verilated::scopesDump();
+
+#ifdef VCD_TRACE
+ VerilatedVcdC *tfp = new VerilatedVcdC;
+ top->trace(tfp, 99);
+ tfp->open("verilator_tb.vcd");
+#endif
+ top->fetch_enable_i = 1;
+ top->clk_i = 0;
+ top->rst_ni = 0;
+
+ top->eval();
+ dump_memory();
+
+ while (!Verilated::gotFinish()) {
+ if (t > 40)
+ top->rst_ni = 1;
+ top->clk_i = !top->clk_i;
+ top->eval();
+#ifdef VCD_TRACE
+ tfp->dump(t);
+#endif
+ t += 5;
+ }
+#ifdef VCD_TRACE
+ tfp->close();
+#endif
+ delete top;
+ exit(0);
+}
+
+double sc_time_stamp()
+{
+ return t;
+}
+
+void dump_memory()
+{
+ errno = 0;
+ std::ofstream mem_file;
+ svLogicVecVal addr = {0};
+
+ mem_file.exceptions(std::ofstream::failbit | std::ofstream::badbit);
+ try {
+ mem_file.open("memory_dump.bin");
+ for (size_t i = 0; i < 1048576; i++) {
+ addr.aval = i;
+ uint32_t val = read_byte(&addr);
+ mem_file << std::setfill('0') << std::setw(2) << std::hex << val
+ << std::endl;
+ }
+ mem_file.close();
+
+ std::cout << "finished dumping memory" << std::endl;
+
+ } catch (std::ofstream::failure e) {
+ std::cerr << "exception opening/reading/closing file memory_dump.bin\n";
+ }
+}
diff --git a/hw/vendor/pulp_riscv_dbg/tb/tb_top_verilator.sv b/hw/vendor/pulp_riscv_dbg/tb/tb_top_verilator.sv
new file mode 100644
index 0000000..2c7ef95
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/tb_top_verilator.sv
@@ -0,0 +1,330 @@
+// Copyright 2018 Robert Balas <balasr@student.ethz.ch>
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+// Top level wrapper for a verilator RI5CY testbench
+// Contributor: Robert Balas <balasr@student.ethz.ch>
+
+module tb_top_verilator #(
+ parameter int unsigned INSTR_RDATA_WIDTH = 32,
+ parameter int unsigned RAM_ADDR_WIDTH = 22,
+ parameter logic [31:0] BOOT_ADDR = 'h1A00_0180,
+ parameter bit JTAG_BOOT = 1,
+ parameter int unsigned OPENOCD_PORT = 9999
+) (
+ input logic clk_i,
+ input logic rst_ni,
+ input logic fetch_enable_i,
+ output logic tests_passed_o,
+ output logic tests_failed_o
+);
+ // defs from pulpissimo
+ // localparam CLUSTER_ID = 6'd31;
+ // localparam CORE_ID = 4'd0;
+ // test defs
+ localparam CLUSTER_ID = 6'd0;
+ localparam CORE_ID = 4'd0;
+
+ localparam CORE_MHARTID = {CLUSTER_ID, 1'b0, CORE_ID};
+ localparam NrHarts = 1;
+ localparam logic [NrHarts-1:0] SELECTABLE_HARTS = 1 << CORE_MHARTID;
+
+ // signals connecting core to memory
+ logic instr_req;
+ logic instr_gnt;
+ logic instr_rvalid;
+ logic [31:0] instr_addr;
+ logic [INSTR_RDATA_WIDTH-1:0] instr_rdata;
+
+ logic data_req;
+ logic data_gnt;
+ logic data_rvalid;
+ logic [31:0] data_addr;
+ logic data_we;
+ logic [3:0] data_be;
+ logic [31:0] data_rdata;
+ logic [31:0] data_wdata;
+
+ // jtag openocd bridge signals
+ logic sim_jtag_tck;
+ logic sim_jtag_tms;
+ logic sim_jtag_tdi;
+ logic sim_jtag_trstn;
+ logic sim_jtag_tdo;
+ logic [31:0] sim_jtag_exit;
+ logic sim_jtag_enable;
+
+ // signals for debug unit
+ logic debug_req_ready;
+ dm::dmi_resp_t debug_resp;
+ logic jtag_req_valid;
+ dm::dmi_req_t jtag_dmi_req;
+ logic jtag_resp_ready;
+ logic jtag_resp_valid;
+ logic [NrHarts-1:0] dm_debug_req;
+ logic ndmreset, ndmreset_n;
+
+ // debug unit slave interface
+ logic dm_grant;
+ logic dm_rvalid;
+ logic dm_req;
+ logic dm_we;
+ logic [31:0] dm_addr;
+ logic [31:0] dm_wdata;
+ logic [31:0] dm_rdata;
+ logic [3:0] dm_be;
+
+ // debug unit master interface (system bus access)
+ logic sb_req;
+ logic [31:0] sb_addr;
+ logic sb_we;
+ logic [31:0] sb_wdata;
+ logic [3:0] sb_be;
+ logic sb_gnt;
+ logic sb_rvalid;
+ logic [31:0] sb_rdata;
+
+ // irq signals (not used)
+ logic irq;
+ logic [0:4] irq_id_in;
+ logic irq_ack;
+ logic [0:4] irq_id_out;
+ logic irq_sec;
+
+ // make jtag bridge work
+ assign sim_jtag_enable = JTAG_BOOT;
+
+ // interrupts (only timer for now)
+ assign irq_sec = '0;
+
+ // instantiate the core
+ riscv_core #(
+ .INSTR_RDATA_WIDTH (INSTR_RDATA_WIDTH),
+ .PULP_SECURE(1),
+ .FPU(0)
+ ) riscv_core_i (
+ .clk_i ( clk_i ),
+ .rst_ni ( ndmreset_n ),
+
+ .clock_en_i ( '1 ),
+ .test_en_i ( '0 ),
+
+ .boot_addr_i ( BOOT_ADDR ),
+ .core_id_i ( CORE_ID ),
+ .cluster_id_i ( CLUSTER_ID ),
+
+ .instr_addr_o ( instr_addr ),
+ .instr_req_o ( instr_req ),
+ .instr_rdata_i ( instr_rdata ),
+ .instr_gnt_i ( instr_gnt ),
+ .instr_rvalid_i ( instr_rvalid ),
+
+ .data_addr_o ( data_addr ),
+ .data_wdata_o ( data_wdata ),
+ .data_we_o ( data_we ),
+ .data_req_o ( data_req ),
+ .data_be_o ( data_be ),
+ .data_rdata_i ( data_rdata ),
+ .data_gnt_i ( data_gnt ),
+ .data_rvalid_i ( data_rvalid ),
+
+ .apu_master_req_o ( ),
+ .apu_master_ready_o ( ),
+ .apu_master_gnt_i ( ),
+ .apu_master_operands_o ( ),
+ .apu_master_op_o ( ),
+ .apu_master_type_o ( ),
+ .apu_master_flags_o ( ),
+ .apu_master_valid_i ( ),
+ .apu_master_result_i ( ),
+ .apu_master_flags_i ( ),
+
+
+ .irq_software_i ( 1'b0 ),
+ .irq_timer_i ( 1'b0 ),
+ .irq_external_i ( 1'b0 ),
+ .irq_fast_i ( 15'b0 ),
+ .irq_nmi_i ( 1'b0 ),
+ .irq_fastx_i ( 32'b0 ),
+ .irq_ack_o ( irq_ack ),
+ .irq_id_o ( irq_id_out ),
+ .irq_sec_i ( irq_sec ),
+
+ .sec_lvl_o ( sec_lvl_o ),
+
+ .debug_req_i ( dm_debug_req[CORE_MHARTID] ),
+
+ .fetch_enable_i ( fetch_enable_i ),
+ .core_busy_o ( core_busy_o ),
+
+ .ext_perf_counters_i ( ),
+ .fregfile_disable_i ( 1'b0 ));
+
+ // this handles read to RAM and memory mapped pseudo peripherals
+ mm_ram #(
+ .RAM_ADDR_WIDTH (RAM_ADDR_WIDTH),
+ .INSTR_RDATA_WIDTH (INSTR_RDATA_WIDTH),
+ .JTAG_BOOT(JTAG_BOOT)
+ ) mm_ram_i (
+ .clk_i ( clk_i ),
+ .rst_ni ( ndmreset_n ),
+
+ // core instruction access
+ .instr_req_i ( instr_req ),
+ .instr_addr_i ( instr_addr ),
+ .instr_rdata_o ( instr_rdata ),
+ .instr_rvalid_o ( instr_rvalid ),
+ .instr_gnt_o ( instr_gnt ),
+
+ // core data access
+ .data_req_i ( data_req ),
+ .data_addr_i ( data_addr ),
+ .data_we_i ( data_we ),
+ .data_be_i ( data_be ),
+ .data_wdata_i ( data_wdata ),
+ .data_rdata_o ( data_rdata ),
+ .data_rvalid_o ( data_rvalid ),
+ .data_gnt_o ( data_gnt ),
+
+ // system bus access from debug unit
+ .sb_req_i ( sb_req ),
+ .sb_addr_i ( sb_addr ),
+ .sb_we_i ( sb_we ),
+ .sb_be_i ( sb_be ),
+ .sb_wdata_i ( sb_wdata ),
+ .sb_rdata_o ( sb_rdata ),
+ .sb_rvalid_o ( sb_rvalid ),
+ .sb_gnt_o ( sb_gnt ),
+
+ // access to debug unit
+ .dm_req_o ( dm_req ),
+ .dm_addr_o ( dm_addr ),
+ .dm_we_o ( dm_we ),
+ .dm_be_o ( dm_be ),
+ .dm_wdata_o ( dm_wdata ),
+ .dm_rdata_i ( dm_rdata ),
+ .dm_rvalid_i ( dm_rvalid ),
+ .dm_gnt_i ( dm_gnt ),
+
+
+ .irq_id_i ( irq_id_out ),
+ .irq_ack_i ( irq_ack ),
+ .irq_id_o ( irq_id_in ),
+ .irq_o ( irq ),
+
+ .tests_passed_o ( tests_passed_o ),
+ .tests_failed_o ( tests_failed_o ));
+
+ // debug subsystem
+ dmi_jtag #(
+ .IdcodeValue ( 32'h249511C3 )
+ ) i_dmi_jtag (
+ .clk_i ( clk_i ),
+ .rst_ni ( rst_ni ),
+ .testmode_i ( 1'b0 ),
+ .dmi_req_o ( jtag_dmi_req ),
+ .dmi_req_valid_o ( jtag_req_valid ),
+ .dmi_req_ready_i ( debug_req_ready ),
+ .dmi_resp_i ( debug_resp ),
+ .dmi_resp_ready_o ( jtag_resp_ready ),
+ .dmi_resp_valid_i ( jtag_resp_valid ),
+ .dmi_rst_no ( ), // not connected
+ .tck_i ( sim_jtag_tck ),
+ .tms_i ( sim_jtag_tms ),
+ .trst_ni ( sim_jtag_trstn ),
+ .td_i ( sim_jtag_tdi ),
+ .td_o ( sim_jtag_tdo ),
+ .tdo_oe_o ( )
+ );
+
+ dm_top #(
+ .NrHarts ( NrHarts ),
+ .BusWidth ( 32 ),
+ .SelectableHarts ( SELECTABLE_HARTS )
+ ) i_dm_top (
+
+ .clk_i ( clk_i ),
+ .rst_ni ( rst_ni ),
+ .testmode_i ( 1'b0 ),
+ .ndmreset_o ( ndmreset ),
+ .dmactive_o ( ), // active debug session TODO
+ .debug_req_o ( dm_debug_req ),
+ .unavailable_i ( ~SELECTABLE_HARTS ),
+ .hartinfo_i ( '0 ),
+
+ .slave_req_i ( dm_req ),
+ .slave_we_i ( dm_we ),
+ .slave_addr_i ( dm_addr ),
+ .slave_be_i ( dm_be ),
+ .slave_wdata_i ( dm_wdata ),
+ .slave_rdata_o ( dm_rdata ),
+
+ .master_req_o ( sb_req ),
+ .master_add_o ( sb_addr ),
+ .master_we_o ( sb_we ),
+ .master_wdata_o ( sb_wdata ),
+ .master_be_o ( sb_be ),
+ .master_gnt_i ( sb_gnt ),
+ .master_r_valid_i ( sb_rvalid ),
+ .master_r_rdata_i ( sb_rdata ),
+
+ .dmi_rst_ni ( rst_ni ),
+ .dmi_req_valid_i ( jtag_req_valid ),
+ .dmi_req_ready_o ( debug_req_ready ),
+ .dmi_req_i ( jtag_dmi_req ),
+ .dmi_resp_valid_o ( jtag_resp_valid ),
+ .dmi_resp_ready_i ( jtag_resp_ready ),
+ .dmi_resp_o ( debug_resp )
+ );
+
+ // grant in the same cycle
+ assign dm_gnt = dm_req;
+ // valid read/write in the next cycle
+ always_ff @(posedge clk_i or negedge rst_ni) begin : dm_valid_handler
+ if(~rst_ni) begin
+ dm_rvalid <= '0;
+ end else begin
+ dm_rvalid <= dm_gnt;
+ end
+ end
+
+ // reset handling with ndmreset
+ rstgen i_rstgen_main (
+ .clk_i ( clk_i ),
+ .rst_ni ( rst_ni & (~ndmreset) ),
+ .test_mode_i ( '0 ),
+ .rst_no ( ndmreset_n ),
+ .init_no ( ) // keep open
+ );
+
+ // jtag calls from dpi
+ SimJTAG #(
+ .TICK_DELAY (1),
+ .PORT(OPENOCD_PORT)
+ ) i_sim_jtag (
+ .clock ( clk_i ),
+ .reset ( ~rst_ni ),
+ .enable ( sim_jtag_enable ),
+ .init_done ( rst_ni ),
+ .jtag_TCK ( sim_jtag_tck ),
+ .jtag_TMS ( sim_jtag_tms ),
+ .jtag_TDI ( sim_jtag_tdi ),
+ .jtag_TRSTn ( sim_jtag_trstn ),
+ .jtag_TDO_data ( sim_jtag_tdo ),
+ .jtag_TDO_driven ( 1'b1 ),
+ .exit ( sim_jtag_exit )
+ );
+
+ always_comb begin : jtag_exit_handler
+ if (sim_jtag_exit)
+ $finish(2); // print stats too
+ end
+
+endmodule // tb_top_verilator
+
diff --git a/hw/vendor/pulp_riscv_dbg/tb/unused/SimDTM.sv b/hw/vendor/pulp_riscv_dbg/tb/unused/SimDTM.sv
new file mode 100644
index 0000000..293e784
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/unused/SimDTM.sv
@@ -0,0 +1,81 @@
+// See LICENSE.SiFive for license details.
+//VCS coverage exclude_file
+
+import "DPI-C" function int debug_tick
+(
+ output bit debug_req_valid,
+ input bit debug_req_ready,
+ output int debug_req_bits_addr,
+ output int debug_req_bits_op,
+ output int debug_req_bits_data,
+
+ input bit debug_resp_valid,
+ output bit debug_resp_ready,
+ input int debug_resp_bits_resp,
+ input int debug_resp_bits_data
+);
+
+module SimDTM(
+ input clk,
+ input reset,
+
+ output debug_req_valid,
+ input debug_req_ready,
+ output [ 6:0] debug_req_bits_addr,
+ output [ 1:0] debug_req_bits_op,
+ output [31:0] debug_req_bits_data,
+
+ input debug_resp_valid,
+ output debug_resp_ready,
+ input [ 1:0] debug_resp_bits_resp,
+ input [31:0] debug_resp_bits_data,
+
+ output [31:0] exit
+);
+
+ bit r_reset;
+
+ wire #0.1 __debug_req_ready = debug_req_ready;
+ wire #0.1 __debug_resp_valid = debug_resp_valid;
+ wire [31:0] #0.1 __debug_resp_bits_resp = {30'b0, debug_resp_bits_resp};
+ wire [31:0] #0.1 __debug_resp_bits_data = debug_resp_bits_data;
+
+ bit __debug_req_valid;
+ int __debug_req_bits_addr;
+ int __debug_req_bits_op;
+ int __debug_req_bits_data;
+ bit __debug_resp_ready;
+ int __exit;
+
+ assign #0.1 debug_req_valid = __debug_req_valid;
+ assign #0.1 debug_req_bits_addr = __debug_req_bits_addr[6:0];
+ assign #0.1 debug_req_bits_op = __debug_req_bits_op[1:0];
+ assign #0.1 debug_req_bits_data = __debug_req_bits_data[31:0];
+ assign #0.1 debug_resp_ready = __debug_resp_ready;
+ assign #0.1 exit = __exit;
+
+ always @(posedge clk)
+ begin
+ r_reset <= reset;
+ if (reset || r_reset)
+ begin
+ __debug_req_valid = 0;
+ __debug_resp_ready = 0;
+ __exit = 0;
+ end
+ else
+ begin
+ __exit = debug_tick(
+ __debug_req_valid,
+ __debug_req_ready,
+ __debug_req_bits_addr,
+ __debug_req_bits_op,
+ __debug_req_bits_data,
+ __debug_resp_valid,
+ __debug_resp_ready,
+ __debug_resp_bits_resp,
+ __debug_resp_bits_data
+ );
+ end
+ end
+endmodule
diff --git a/hw/vendor/pulp_riscv_dbg/tb/vsim_batch.tcl b/hw/vendor/pulp_riscv_dbg/tb/vsim_batch.tcl
new file mode 100644
index 0000000..01c0d3e
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/vsim_batch.tcl
@@ -0,0 +1,15 @@
+# Copyright 2020 ETH Zurich and University of Bologna.
+# Copyright and related rights are licensed under the Solderpad Hardware
+# License, Version 0.51 (the "License"); you may not use this file except in
+# compliance with the License. You may obtain a copy of the License at
+# http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+# or agreed to in writing, software, hardware and materials distributed under
+# this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+# CONDITIONS OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+
+# Author: Robert Balas (balasr@student.ethz.ch)
+# Description: TCL scripts to facilitate simulations
+
+set NoQuitOnFinish 1
+run -all
diff --git a/hw/vendor/pulp_riscv_dbg/tb/vsim_gui.tcl b/hw/vendor/pulp_riscv_dbg/tb/vsim_gui.tcl
new file mode 100644
index 0000000..571b66e
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/vsim_gui.tcl
@@ -0,0 +1,16 @@
+# Copyright 2019 ETH Zurich and University of Bologna.
+# Copyright and related rights are licensed under the Solderpad Hardware
+# License, Version 0.51 (the "License"); you may not use this file except in
+# compliance with the License. You may obtain a copy of the License at
+# http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+# or agreed to in writing, software, hardware and materials distributed under
+# this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+# CONDITIONS OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+
+# Author: Robert Balas (balasr@student.ethz.ch)
+# Description: TCL scripts to facilitate simulations
+
+set NoQuitOnFinish 1
+source waves.tcl
+run -all
diff --git a/hw/vendor/pulp_riscv_dbg/tb/waves.tcl b/hw/vendor/pulp_riscv_dbg/tb/waves.tcl
new file mode 100644
index 0000000..f535d80
--- /dev/null
+++ b/hw/vendor/pulp_riscv_dbg/tb/waves.tcl
@@ -0,0 +1,117 @@
+# Copyright 2020 ETH Zurich and University of Bologna.
+# Copyright and related rights are licensed under the Solderpad Hardware
+# License, Version 0.51 (the "License"); you may not use this file except in
+# compliance with the License. You may obtain a copy of the License at
+# http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+# or agreed to in writing, software, hardware and materials distributed under
+# this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+# CONDITIONS OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+
+# Author: Robert Balas (balasr@iis.ee.ethz.ch)
+# Description: TCL scripts to facilitate simulations
+# catch {
+# if {$trdb_all ne ""} {
+# foreach inst $trdb_all {
+# add wave -group [file tail $inst] $inst/*
+# }
+# }
+# } err
+
+# if {$err ne ""} {
+# puts "\[TCL\]: Suppressed error: $err"
+# }
+
+# add fc
+set rvcores [find instances -recursive -bydu riscv_core -nodu]
+set fpuprivate [find instances -recursive -bydu fpu_private]
+set tb_top [find instances -recursive -bydu tb_top -nod]
+set mm_ram [find instances -recursive -bydu mm_ram -nod]
+set dp_ram [find instances -recursive -bydu dp_ram -nod]
+
+if {$tb_top ne ""} {
+ foreach inst $tb_top {
+ add wave -group [file tail $inst] $inst/*
+ }
+}
+
+if {$mm_ram ne ""} {
+ foreach inst $mm_ram {
+ add wave -group [file tail $inst] $inst/*
+ }
+}
+
+if {$dp_ram ne ""} {
+ foreach inst $dp_ram {
+ add wave -group [file tail $inst] $inst/*
+ }
+}
+
+if {$rvcores ne ""} {
+ set rvprefetch [find instances -recursive -bydu riscv_prefetch_L0_buffer -nodu]
+
+ add wave -group "Core" $rvcores/*
+ add wave -group "IF Stage" -group "Hwlp Ctrl" $rvcores/if_stage_i/hwloop_controller_i/*
+ if {$rvprefetch ne ""} {
+ add wave -group "IF Stage" -group "Prefetch" -group "L0" $rvcores/if_stage_i/prefetch_128/prefetch_buffer_i/L0_buffer_i/*
+ add wave -group "IF Stage" -group "Prefetch" $rvcores/if_stage_i/prefetch_128/prefetch_buffer_i/*
+ } {
+ add wave -group "IF Stage" -group "Prefetch" -group "FIFO" $rvcores/if_stage_i/prefetch_32/prefetch_buffer_i/fifo_i/*
+ add wave -group "IF Stage" -group "Prefetch" $rvcores/if_stage_i/prefetch_32/prefetch_buffer_i/*
+ }
+ add wave -group "IF Stage" $rvcores/if_stage_i/*
+ add wave -group "ID Stage" $rvcores/id_stage_i/*
+ add wave -group "RF" $rvcores/id_stage_i/registers_i/riscv_register_file_i/mem
+ add wave -group "RF_FP" $rvcores/id_stage_i/registers_i/riscv_register_file_i/mem_fp
+ add wave -group "Decoder" $rvcores/id_stage_i/decoder_i/*
+ add wave -group "Controller" $rvcores/id_stage_i/controller_i/*
+ add wave -group "Int Ctrl" $rvcores/id_stage_i/int_controller_i/*
+ add wave -group "Hwloop Regs" $rvcores/id_stage_i/hwloop_regs_i/*
+ add wave -group "EX Stage" -group "ALU" $rvcores/ex_stage_i/alu_i/*
+ add wave -group "EX Stage" -group "ALU_DIV" $rvcores/ex_stage_i/alu_i/int_div/div_i/*
+ add wave -group "EX Stage" -group "MUL" $rvcores/ex_stage_i/mult_i/*
+ if {$fpuprivate ne ""} {
+ add wave -group "EX Stage" -group "APU_DISP" $rvcores/ex_stage_i/genblk1/apu_disp_i/*
+ add wave -group "EX Stage" -group "FPU" $rvcores/ex_stage_i/genblk1/genblk1/fpu_i/*
+ }
+ add wave -group "EX Stage" $rvcores/ex_stage_i/*
+ add wave -group "LSU" $rvcores/load_store_unit_i/*
+ add wave -group "CSR" $rvcores/cs_registers_i/*
+}
+
+# add dm
+set dm [find instances -recursive -bydu dm_top -nodu]
+set dm_mem [find instances -recursive -bydu dm_mem -nodu]
+set dm_csrs [find instances -recursive -bydu dm_csrs -nodu]
+set dm_sba [find instances -recursive -bydu dm_sba -nodu]
+
+if {$dm ne ""} {
+ add wave -group "DM" $dm/*
+}
+if {$dm_mem ne ""} {
+ add wave -group "DM" -group "dm_mem" $dm_mem/*
+}
+if {$dm_csrs ne ""} {
+ add wave -group "DM" -group "dm_csrs" $dm_csrs/*
+}
+if {$dm_sba ne ""} {
+ add wave -group "DM" -group "dm_sba" $dm_sba/*
+}
+
+# add dmi_jtag
+set dmi [find instances -recursive -bydu dmi_jtag -nodu]
+set dmi_tap [find instances -recursive -bydu dmi_jtag_tap -nodu]
+
+if {$dmi ne ""} {
+ add wave -group "DMI" $dmi/*
+}
+if {$dmi_tap ne ""} {
+ add wave -group "DMI" -group "dmi_tap" $dmi_tap/*
+}
+
+
+configure wave -namecolwidth 250
+configure wave -valuecolwidth 100
+configure wave -justifyvalue left
+configure wave -signalnamewidth 1
+configure wave -timelineunits ns