From a05e75581726d18c16bca2d7b0b00bfe4a658759 Mon Sep 17 00:00:00 2001 From: Peter Rugg Date: Tue, 18 Feb 2025 18:02:49 +0000 Subject: [PATCH 01/12] Changes required to reproduce TestRIG build --- .gitmodules | 3 + corev_apu/tb/tb_testRig_cheri/Makefile | 12 +- .../tb/tb_testRig_cheri/src/SocketPacketUtils | 1 + .../src/cva6_dii_toplevel.cpp | 4 +- .../tb/tb_testRig_cheri/src/inc/socket.h | 34 --- corev_apu/tb/tb_testRig_cheri/src/socket.c | 267 ------------------ verif/regress/install-verilator.sh | 2 +- 7 files changed, 13 insertions(+), 310 deletions(-) create mode 160000 corev_apu/tb/tb_testRig_cheri/src/SocketPacketUtils delete mode 100644 corev_apu/tb/tb_testRig_cheri/src/inc/socket.h delete mode 100644 corev_apu/tb/tb_testRig_cheri/src/socket.c diff --git a/.gitmodules b/.gitmodules index ec6a9a8bf..bf7da440b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -52,3 +52,6 @@ [submodule "vendor/zero-day/axi_tagcontroller"] path = vendor/zero-day/axi_tagcontroller url = https://github.com/ninolomata/axi_cheri_tagcontroller.git +[submodule "corev_apu/tb/tb_testRig_cheri/src/SocketPacketUtils"] + path = corev_apu/tb/tb_testRig_cheri/src/SocketPacketUtils + url = https://github.com/CTSRD-CHERI/SocketPacketUtils diff --git a/corev_apu/tb/tb_testRig_cheri/Makefile b/corev_apu/tb/tb_testRig_cheri/Makefile index 338f27575..af746c611 100644 --- a/corev_apu/tb/tb_testRig_cheri/Makefile +++ b/corev_apu/tb/tb_testRig_cheri/Makefile @@ -16,6 +16,10 @@ # specific language governing permissions and limitations # under the License. +# root path +mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST))) +root-dir := $(abspath $(dir $(mkfile_path))../../..)/ + # questa library library ?= work # verilator lib @@ -27,14 +31,11 @@ top_level ?= ariane_tb # Maximum amount of cycles for a successful simulation run max_cycles ?= 10000000 # verilator version -verilator ?= /media/ninolomata/Nino1/CHERI/TestRIG/riscv-implementations/cva6/tools/verilator/bin/verilator +verilator ?= $(root-dir)/tools/verilator-v5.015/bin/verilator # traget option target-options ?= # additional definess defines ?= WT_DCACHE -# root path -mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST))) -root-dir := $(abspath $(dir $(mkfile_path))../../..)/ ifndef CVA6_REPO_DIR $(warning must set CVA6_REPO_DIR to point at the root of CVA6 sources -- doing it for you...) @@ -105,9 +106,8 @@ CFLAGS := -I$(QUESTASIM_HOME)/include \ -I$(VCS_HOME)/include \ -I$(RISCV)/include \ -I$(SPIKE_ROOT)/include \ - -I$(root-dir)/corev_apu/tb/tb_testRig_cheri/src/inc \ -I$(root-dir)/corev_apu/tb/tb_testRig_cheri/src/SocketPacketUtils \ - -std=c++11 -I$(root-dir)/corev_apu/tb/dpi -O3 + -I$(root-dir)/corev_apu/tb/dpi -O3 # this list contains the standalone components src := $(root-dir)/core/include/$(target)_config_pkg.sv \ diff --git a/corev_apu/tb/tb_testRig_cheri/src/SocketPacketUtils b/corev_apu/tb/tb_testRig_cheri/src/SocketPacketUtils new file mode 160000 index 000000000..3bcbc7081 --- /dev/null +++ b/corev_apu/tb/tb_testRig_cheri/src/SocketPacketUtils @@ -0,0 +1 @@ +Subproject commit 3bcbc70816e207e754e49ec75d803c12ff2bffd6 diff --git a/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp b/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp index ff4977045..dad3630ab 100644 --- a/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp +++ b/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp @@ -251,9 +251,9 @@ int main(int argc, char **argv) { }; int option_index = 0; #if VM_TRACE - int c = getopt_long(argc, argv, "-chpm:s:r:v:f:Vx:", long_options, &option_index); + int c = getopt_long(argc, argv, "-chpm:s:r:v:f:Vx:q:w:", long_options, &option_index); #else - int c = getopt_long(argc, argv, "-chpm:s:r:V", long_options, &option_index); + int c = getopt_long(argc, argv, "-chpm:s:r:V:q:w:", long_options, &option_index); #endif if (c == -1) break; retry: diff --git a/corev_apu/tb/tb_testRig_cheri/src/inc/socket.h b/corev_apu/tb/tb_testRig_cheri/src/inc/socket.h deleted file mode 100644 index 860e4f76f..000000000 --- a/corev_apu/tb/tb_testRig_cheri/src/inc/socket.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef __SOCKET_H__ -#define __SOCKET_H__ - -#ifdef __cplusplus -extern "C" { -#endif - #include - #include - #include - #define SOCKET_NAME_STR_SIZE 256 - #define SOCKET_INIT_FD -1 - #define SOCKET_INIT_CONNECTION -1 - #define SOCKET_MAX_CONNECTIONS 3 - - typedef struct sock_serv_state_t{ - char name[SOCKET_NAME_STR_SIZE]; - int port; - int fd; - int conn; - struct sockaddr_in address; - socklen_t addrlen; - } sock_serv_state_t; - - sock_serv_state_t* initSocketServ(const char * socket_name, unsigned int default_socket_port); - uint32_t get8SocketServ(sock_serv_state_t* sock_serv); - uint8_t put8SocketServ(sock_serv_state_t* sock_serv, uint8_t byte); - void getNSocketServ(unsigned int* result, sock_serv_state_t* sock_serv, int nbytes); - uint8_t putNSocketServ(sock_serv_state_t* sock_serv, int nbytes, unsigned int* data); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/corev_apu/tb/tb_testRig_cheri/src/socket.c b/corev_apu/tb/tb_testRig_cheri/src/socket.c deleted file mode 100644 index 1bdb7b49b..000000000 --- a/corev_apu/tb/tb_testRig_cheri/src/socket.c +++ /dev/null @@ -1,267 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define SOCKET_NAME_STR_SIZE 256 -#define SOCKET_INIT_FD -1 -#define SOCKET_INIT_CONNECTION -1 -#define SOCKET_MAX_CONNECTIONS 3 - -/** Returns true on success, or false if there was an error */ -int setSocketBlockingMode(int fd, int blocking) -{ - int ret = -1; - int flags = 0; - if (fd < 0) return -1; - flags = fcntl(fd, F_GETFL, 0); - if (flags == -1) return -1; - flags = (blocking == 1) ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); - ret = fcntl(fd, F_SETFL, flags); - return ret; -} - -static inline int acceptSocketServConnection(sock_serv_state_t* sock_state_ptr) { - // Check if socket created - if (sock_state_ptr == NULL) - return -1; - // Check connection and fd - if (sock_state_ptr->fd < 0 || sock_state_ptr->conn > 0) - return -1; - // Accept connection - sock_state_ptr->conn = accept(sock_state_ptr->fd, NULL, NULL); - // Make connection non-blocking - // if (sock_state_ptr->conn != -1) { - // setSocketBlockingMode(sock_state_ptr->conn, 0); - // return 0; - // } - if (sock_state_ptr->conn == -1) - return -1; - else - return 0; -} - -sock_serv_state_t* initSocketServ(const char * socket_name, unsigned int default_socket_port) { - struct sockaddr_in sock_address; - sock_serv_state_t* sock_state_ptr = NULL; - int sock_addrlen = sizeof(sock_address); - int ret = 0; - int opt = 1; - // Fail if socket already initialized - if (sock_state_ptr != NULL) { - fprintf(stderr, "ERROR: Socket already initialized ! \n"); - exit(EXIT_FAILURE); - } - // Initiliaze the socket - sock_state_ptr = (sock_serv_state_t *) malloc(sizeof(sock_serv_state_t)); - if (strncpy(sock_state_ptr->name, socket_name, SOCKET_NAME_STR_SIZE) == NULL) { - fprintf(stderr, "ERROR: Failed to copy socket name \n"); - exit(EXIT_FAILURE); - } - sock_state_ptr->port = default_socket_port; - sock_state_ptr->fd = SOCKET_INIT_FD; - sock_state_ptr->conn = SOCKET_INIT_CONNECTION; - - // Create socket file descriptor - sock_state_ptr->fd = socket(AF_INET, SOCK_STREAM, 0); - if (sock_state_ptr->fd < 0) { - perror("ERROR: Failed to create socket! \r\n"); - exit(EXIT_FAILURE); - } - - // Forcefully attaching socket to the port - if (setsockopt(sock_state_ptr->fd, SOL_SOCKET, SO_REUSEADDR, &opt,sizeof(opt)) < 0) { - perror("ERROR: Unable to set reuseaddr on socket!"); - exit(EXIT_FAILURE); - } - // Operation Bind - sock_state_ptr->addrlen = sizeof(sock_address); - memset(&sock_state_ptr->address, 0, sock_state_ptr->addrlen); - sock_state_ptr->address.sin_family = AF_INET; - sock_state_ptr->address.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - sock_state_ptr->address.sin_port = htons(sock_state_ptr->port); - ret = bind(sock_state_ptr->fd, (struct sockaddr*)&sock_state_ptr->address, sizeof(sock_state_ptr->address)); - if (ret < 0) { - perror("ERROR: bind failed ! \r\n"); - exit(EXIT_FAILURE); - } - // Start listen for connections - if (listen(sock_state_ptr->fd, 1) < 0) { - perror("ERROR: Listen failed ! \r\n"); - exit(EXIT_FAILURE); - } - - sock_state_ptr->conn = accept(sock_state_ptr->fd, NULL, NULL); - if (sock_state_ptr->conn == -1) - { - perror("ERROR: Accept connection failed ! \r\n"); - exit(EXIT_FAILURE); - } - // Set socket in non-blocking mode - // ret = setSocketBlockingMode(sock_state_ptr->fd, 0); - // assume always true - // if (ret < 0) { - // perror("ERROR: Setting socket in non-blocking mode"); - // exit(EXIT_FAILURE); - // } - return sock_state_ptr; -} - -// Non-blocking read of 8 bits -uint32_t get8SocketServ(sock_serv_state_t* sock_serv) -{ - uint8_t byte; - if (sock_serv == NULL) - return -1; - - if (acceptSocketServConnection(sock_serv) == -1) { - perror("ERROR: Connection failed ! \r\n"); - exit(EXIT_FAILURE); - } - - if (sock_serv->conn == -1) return -1; - int n = read(sock_serv->conn, &byte, 1); - if (n == 1) - return (uint32_t) byte; - else if (!(n == -1 && errno == EAGAIN)) { - close(sock_serv->conn); - sock_serv->conn = -1; - } - return -1; -} - -// Non-blocking write of 8 bits -uint8_t put8SocketServ(sock_serv_state_t* sock_serv, uint8_t byte) -{ - if (sock_serv == NULL) { - fprintf(stderr, "ERROR: Socket already initialized ! \n"); - exit(EXIT_FAILURE); - } - - //if (acceptSocketServConnection(sock_serv) == -1) { - // perror("ERROR: Connection failed ! \r\n"); - // exit(EXIT_FAILURE); - //} - - if (sock_serv->conn == -1) return 0; - int n = write(sock_serv->conn, &byte, 1); - if (n == 1) - return 1; - //else if (!(n == -1 && errno == EAGAIN)) { - // close(sock_serv->conn); - // sock_serv->conn = -1; - //} - return 0; -} - -// Try to read N bytes from socket, giving N+1 byte result. Bottom N -// bytes contain data and MSB is 0 if data is valid or non-zero if no -// data is available. Non-blocking on N-byte boundaries. -void getNSocketServ(unsigned int* result, sock_serv_state_t* sock_serv, int nbytes) -{ - printf("trying to read 1\r\n"); - uint8_t* bytes = (uint8_t*) result; - if (sock_serv == NULL) { - perror("ERROR: socket not provided ! \r\n"); - exit(EXIT_FAILURE); - return; - } - printf("trying to read \r\n"); - // if (acceptSocketServConnection(sock_serv) == -1) { - // perror("ERROR: Connection failed ! \r\n"); - // exit(EXIT_FAILURE); - // } - // printf(" Accept connection socket: %d conn %d port %d \r\n", sock_serv->fd, sock_serv->conn, sock_serv->port); - // if (sock_serv->conn == -1) { - // bytes[nbytes] = 0xff; - // return; - // } - int count = read(sock_serv->conn, bytes, nbytes); - printf("count %d \r\n",count); - printf("nbytes %d \r\n",nbytes); - if (count == nbytes) { - bytes[nbytes] = 0; - return; - } - else if (count > 0) { - // Use blocking reads to get remaining data - fd_set fds; - FD_ZERO(&fds); - FD_SET(sock_serv->conn, &fds); - while (count < nbytes) { - int res = select(sock_serv->conn+1, &fds, NULL, NULL, NULL); - assert(res >= 0); - res = read(sock_serv->conn, &bytes[count], nbytes-count); - assert(res >= 0); - count += res; - printf("count 1 %d \r\n",count); - } - bytes[nbytes] = 0; - return; - } - else { - bytes[nbytes] = 0xff; - if (!(count == -1 && errno == EAGAIN)) { - close(sock_serv->conn); - sock_serv->conn = -1; - } - return; - } -} - -// Try to write N bytes to socket. Non-blocking on N-bytes boundaries, -// returning 0 when no write performed. -uint8_t putNSocketServ(sock_serv_state_t* sock_serv, int nbytes, unsigned int* data) -{ - if (sock_serv == NULL) { - fprintf(stderr, "ERROR: Socket already initialized ! \n"); - exit(EXIT_FAILURE); - } - - // if (acceptSocketServConnection(sock_serv) == -1) { - // perror("ERROR: Connection failed ! \r\n"); - // exit(EXIT_FAILURE); - // } - //if (sock_serv->conn == -1) return 0; - uint8_t* bytes = (uint8_t*) data; - int count = write(sock_serv->conn, bytes, nbytes); - if (count == nbytes) - return 1; - else if (count > 0) { - // Use blocking writes to put remaining data - fd_set fds; - FD_ZERO(&fds); - FD_SET(sock_serv->conn, &fds); - while (count < nbytes) { - fflush(stdout); - int res = select(sock_serv->conn+1, &fds, NULL, NULL, NULL); - assert(res >= 0); - res = write(sock_serv->conn, &bytes[count], nbytes-count); - assert(res >= 0); - count += res; - } - return 1; - } - else { - if (!(count == -1 && errno == EAGAIN)) { - close(sock_serv->conn); - sock_serv->conn = -1; - } - return 0; - } -} \ No newline at end of file diff --git a/verif/regress/install-verilator.sh b/verif/regress/install-verilator.sh index a70fc145f..66cf9f472 100755 --- a/verif/regress/install-verilator.sh +++ b/verif/regress/install-verilator.sh @@ -18,7 +18,7 @@ fi VERILATOR_REPO="https://github.com/verilator/verilator.git" VERILATOR_BRANCH="master" # Use the release tag instead of a full SHA1 hash. -VERILATOR_HASH="v5.008" +VERILATOR_HASH="v5.015" VERILATOR_PATCH="$ROOT_PROJECT/verif/regress/verilator-v5.patch" # Unset historical variable VERILATOR_ROOT as it collides with the build process. From dc0a9da3f38500a0c973eb24b95500b6a37be71a Mon Sep 17 00:00:00 2001 From: Peter Rugg Date: Fri, 21 Feb 2025 12:33:42 +0000 Subject: [PATCH 02/12] Remove DMI and JTAG support from TestRIG tb This removes the fesvr and spike dependencies (and means that running the simulator doesn't disable terminal echo) --- corev_apu/tb/rvfi_tracer.sv | 4 + corev_apu/tb/tb_testRig_cheri/Makefile | 28 +--- .../hdl/ariane_testharness_dii.sv | 140 +----------------- .../src/cva6_dii_toplevel.cpp | 88 +---------- 4 files changed, 15 insertions(+), 245 deletions(-) diff --git a/corev_apu/tb/rvfi_tracer.sv b/corev_apu/tb/rvfi_tracer.sv index 004edaedd..92ae7d15f 100644 --- a/corev_apu/tb/rvfi_tracer.sv +++ b/corev_apu/tb/rvfi_tracer.sv @@ -7,6 +7,7 @@ // // Original Author: Jean-Roch COULON - Thales // +`ifndef DII `ifndef READ_SYMBOL_T `define READ_SYMBOL_T import "DPI-C" function byte read_symbol (input string symbol_name, inout longint unsigned address); @@ -18,6 +19,7 @@ import "DPI-C" function void read_elf(input string filename); import "DPI-C" function byte get_section(output longint address, output longint len); import "DPI-C" context function read_section_sv(input longint address, inout byte buffer[]); `endif +`endif module rvfi_tracer #( @@ -45,6 +47,7 @@ module rvfi_tracer #( f = $fopen($sformatf("trace_rvfi_hart_%h.dasm", HART_ID), "w"); if (!$value$plusargs("time_out=%d", SIM_FINISH)) SIM_FINISH = 2000000; if (!$value$plusargs("tohost_addr=%h", TOHOST_ADDR)) TOHOST_ADDR = '0; +`ifndef DII if (TOHOST_ADDR == '0) begin if (!$value$plusargs("elf_file=%s", binary)) binary = ""; if (binary != "") begin @@ -58,6 +61,7 @@ module rvfi_tracer #( $fwrite(f, "*** [rvfi_tracer] WARNING No valid address of 'tohost' (tohost == 0x%h), termination possible only by timeout or Ctrl-C!\n", TOHOST_ADDR); end end +`endif end final $fclose(f); diff --git a/corev_apu/tb/tb_testRig_cheri/Makefile b/corev_apu/tb/tb_testRig_cheri/Makefile index af746c611..f40e405ec 100644 --- a/corev_apu/tb/tb_testRig_cheri/Makefile +++ b/corev_apu/tb/tb_testRig_cheri/Makefile @@ -24,8 +24,6 @@ root-dir := $(abspath $(dir $(mkfile_path))../../..)/ library ?= work # verilator lib ver-library ?= work-ver -# library for DPI -dpi-library ?= work-dpi # Top level module to compile top_level ?= ariane_tb # Maximum amount of cycles for a successful simulation run @@ -51,8 +49,6 @@ ifndef RISCV $(error RISCV not set - please point your RISCV variable to your RISCV installation) endif -SPIKE_INSTALL_DIR ?= $(root-dir)/tools/spike - target ?= cv64a6_imafdch_sv39_rvfi_dii ifeq ($(target), cv64a6_imafdch_sv39_rvfi_dii) XLEN ?= 64 @@ -96,27 +92,14 @@ util := $(addprefix $(root-dir), $(util)) test_pkg := $(wildcard tb/test/*/*sequence_pkg.sv*) \ $(wildcard tb/test/*/*_pkg.sv*) -# DPI - dpi := $(patsubst $(root-dir)/corev_apu/tb/dpi/%.cc, ${dpi-library}/%.o, $(wildcard $(root-dir)/corev_apu/tb/dpi/*.cc)) - -dpi_hdr := $(wildcard $(root-dir)/corev_apu/tb/dpi/*.h) -# dpi_hdr := $(addprefix $(root-dir), $(dpi_hdr)) - CFLAGS := -I$(QUESTASIM_HOME)/include \ -I$(VCS_HOME)/include \ -I$(RISCV)/include \ - -I$(SPIKE_ROOT)/include \ -I$(root-dir)/corev_apu/tb/tb_testRig_cheri/src/SocketPacketUtils \ -I$(root-dir)/corev_apu/tb/dpi -O3 # this list contains the standalone components src := $(root-dir)/core/include/$(target)_config_pkg.sv \ - $(if $(spike-tandem),$(root-dir)/verif/tb/core/uvma_core_cntrl_pkg.sv) \ - $(if $(spike-tandem),$(root-dir)/verif/tb/core/uvma_cva6pkg_utils_pkg.sv) \ - $(if $(spike-tandem),$(root-dir)/verif/tb/core/uvma_rvfi_pkg.sv) \ - $(if $(spike-tandem),$(root-dir)/verif/tb/core/uvmc_rvfi_reference_model_pkg.sv) \ - $(if $(spike-tandem),$(root-dir)/verif/tb/core/uvmc_rvfi_scoreboard_pkg.sv) \ - $(if $(spike-tandem),$(root-dir)/corev_apu/tb/common/spike.sv) \ $(root-dir)/corev_apu/src/ariane.sv \ $(wildcard $(root-dir)/corev_apu/bootrom/*.sv) \ $(wildcard $(root-dir)/corev_apu/clint/*.sv) \ @@ -130,8 +113,6 @@ src := $(root-dir)/core/include/$(target)_config_pkg.sv $(root-dir)/corev_apu/rv_plic/rtl/plic_regmap.sv \ $(root-dir)/corev_apu/rv_plic/rtl/plic_top.sv \ $(root-dir)/corev_apu/riscv-dbg/src/dmi_cdc.sv \ - $(root-dir)/corev_apu/riscv-dbg/src/dmi_jtag.sv \ - $(root-dir)/corev_apu/riscv-dbg/src/dmi_jtag_tap.sv \ $(root-dir)/corev_apu/riscv-dbg/src/dm_csrs.sv \ $(root-dir)/corev_apu/riscv-dbg/src/dm_mem.sv \ $(root-dir)/corev_apu/riscv-dbg/src/dm_sba.sv \ @@ -204,8 +185,6 @@ src := $(root-dir)/core/include/$(target)_config_pkg.sv $(root-dir)/corev_apu/tb/ariane_peripherals.sv \ $(root-dir)/corev_apu/tb/rvfi_tracer.sv \ $(root-dir)/corev_apu/tb/common/uart.sv \ - $(root-dir)/corev_apu/tb/common/SimDTM.sv \ - $(root-dir)/corev_apu/tb/common/SimJTAG.sv \ $(root-dir)/corev_apu/tb/tb_testRig_cheri/hdl/ariane_testharness_dii.sv copro_src := core/cvxif_example/include/cvxif_instr_pkg.sv \ @@ -260,14 +239,13 @@ verilate_command := $(verilator) --no-timing $(root-dir)/verilator_config.vlt -Wno-BLKANDNBLK \ -Wno-style \ $(if $(DEBUG), --trace --trace-structs ) \ - -LDFLAGS "-L$(RISCV)/lib -L$(SPIKE_INSTALL_DIR)/lib -Wl,-rpath,$(RISCV)/lib -Wl,-rpath,$(SPIKE_INSTALL_DIR)/lib -lfesvr$(if $(PROFILE), -g -pg,) $(if $(DROMAJO), -L../corev_apu/tb/dromajo/src -ldromajo_cosim,) -lpthread" \ + -LDFLAGS "-L$(RISCV)/lib -Wl,-rpath,$(RISCV)/lib$(if $(PROFILE), -g -pg,) $(if $(DROMAJO), -L../corev_apu/tb/dromajo/src -ldromajo_cosim,) -lpthread" \ -CFLAGS "$(CFLAGS)$(if $(PROFILE), -g -pg,) $(if $(DROMAJO), -DDROMAJO=1,) -DVL_DEBUG" \ -Wall --cc --vpi \ $(list_incdir) --top-module ariane_testharness_dii \ --threads-dpi none \ --Mdir $(ver-library) -O3 \ - --exe ${root-dir}/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp ${root-dir}/corev_apu/tb/tb_testRig_cheri/src/SocketPacketUtils/socket_packet_utils.c ${root-dir}/corev_apu/tb/dpi/SimDTM.cc ${root-dir}/corev_apu/tb/dpi/SimJTAG.cc \ - ${root-dir}/corev_apu/tb/dpi/remote_bitbang.cc ${root-dir}/corev_apu/tb/dpi/msim_helper.cc + --exe ${root-dir}/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp ${root-dir}/corev_apu/tb/tb_testRig_cheri/src/SocketPacketUtils/socket_packet_utils.c # User Verilator, at some point in the future this will be auto-generated verilate: @@ -278,7 +256,7 @@ verilate: clean: rm -rf $(riscv-torture-dir)/output/test* - rm -rf $(library)/ $(dpi-library)/ $(ver-library)/ + rm -rf $(library)/ $(ver-library)/ rm -f tmp/*.ucdb tmp/*.log *.wlf *vstf wlft* *.ucdb .PHONY: diff --git a/corev_apu/tb/tb_testRig_cheri/hdl/ariane_testharness_dii.sv b/corev_apu/tb/tb_testRig_cheri/hdl/ariane_testharness_dii.sv index 9dc411f26..eae38bb51 100644 --- a/corev_apu/tb/tb_testRig_cheri/hdl/ariane_testharness_dii.sv +++ b/corev_apu/tb/tb_testRig_cheri/hdl/ariane_testharness_dii.sv @@ -31,7 +31,6 @@ module ariane_testharness_dii import cva6_cheri_pkg::*; #( parameter int unsigned AXI_USER_EN = CVA6Cfg.AXI_USER_EN, parameter int unsigned AXI_ADDRESS_WIDTH = 64, parameter int unsigned AXI_DATA_WIDTH = 64, - parameter bit InclSimDTM = 1'b1, parameter int unsigned NUM_WORDS = 2**25, // memory size parameter bit StallRandomOutput = 1'b0, parameter bit StallRandomInput = 1'b0 @@ -90,42 +89,14 @@ module ariane_testharness_dii import cva6_cheri_pkg::*; #( logic test_en; logic ndmreset; logic ndmreset_n; - logic debug_req_core; - int jtag_enable; logic init_done; - logic [31:0] jtag_exit, dmi_exit; logic [31:0] rvfi_exit; - logic jtag_TCK; - logic jtag_TMS; - logic jtag_TDI; - logic jtag_TRSTn; - logic jtag_TDO_data; - logic jtag_TDO_driven; - - logic debug_req_valid; logic debug_req_ready; logic debug_resp_valid; logic debug_resp_ready; - logic jtag_req_valid; - logic [6:0] jtag_req_bits_addr; - logic [1:0] jtag_req_bits_op; - logic [31:0] jtag_req_bits_data; - logic jtag_resp_ready; - logic jtag_resp_valid; - - logic dmi_req_valid; - logic dmi_resp_ready; - logic dmi_resp_valid; - - dm::dmi_req_t jtag_dmi_req; - dm::dmi_req_t dmi_req; - - dm::dmi_req_t debug_req; - dm::dmi_resp_t debug_resp; - logic [31:0] dii_insn; logic dii_ready; @@ -160,106 +131,9 @@ module ariane_testharness_dii import cva6_cheri_pkg::*; #( logic debug_enable; initial begin - if (!$value$plusargs("jtag_rbb_enable=%b", jtag_enable)) jtag_enable = 'h0; - if ($test$plusargs("debug_disable")) debug_enable = 'h0; else debug_enable = 'h1; if (CVA6Cfg.XLEN != 32 & CVA6Cfg.XLEN != 64) $error("CVA6Cfg.XLEN different from 32 and 64"); end - // debug if MUX - assign debug_req_valid = (jtag_enable[0]) ? jtag_req_valid : dmi_req_valid; - assign debug_resp_ready = (jtag_enable[0]) ? jtag_resp_ready : dmi_resp_ready; - assign debug_req = (jtag_enable[0]) ? jtag_dmi_req : dmi_req; - if (ariane_pkg::RVFI) begin - assign exit_o = (jtag_enable[0]) ? jtag_exit : rvfi_exit; - end else begin - assign exit_o = (jtag_enable[0]) ? jtag_exit : dmi_exit; - end - assign jtag_resp_valid = (jtag_enable[0]) ? debug_resp_valid : 1'b0; - assign dmi_resp_valid = (jtag_enable[0]) ? 1'b0 : debug_resp_valid; - - // SiFive's SimJTAG Module - // Converts to DPI calls - SimJTAG i_SimJTAG ( - .clock ( clk_i ), - .reset ( ~rst_ni ), - .enable ( jtag_enable[0] ), - .init_done ( init_done ), - .jtag_TCK ( jtag_TCK ), - .jtag_TMS ( jtag_TMS ), - .jtag_TDI ( jtag_TDI ), - .jtag_TRSTn ( jtag_TRSTn ), - .jtag_TDO_data ( jtag_TDO_data ), - .jtag_TDO_driven ( jtag_TDO_driven ), - .exit ( jtag_exit ) - ); - - dmi_jtag i_dmi_jtag ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .testmode_i ( test_en ), - .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 ( jtag_TCK ), - .tms_i ( jtag_TMS ), - .trst_ni ( jtag_TRSTn ), - .td_i ( jtag_TDI ), - .td_o ( jtag_TDO_data ), - .tdo_oe_o ( jtag_TDO_driven ) - ); - - // SiFive's SimDTM Module - // Converts to DPI calls - logic [1:0] debug_req_bits_op; - assign dmi_req.op = dm::dtm_op_e'(debug_req_bits_op); - - if (InclSimDTM) begin - SimDTM i_SimDTM ( - .clk ( clk_i ), - .reset ( ~rst_ni ), - .debug_req_valid ( dmi_req_valid ), - .debug_req_ready ( debug_req_ready ), - .debug_req_bits_addr ( dmi_req.addr ), - .debug_req_bits_op ( debug_req_bits_op ), - .debug_req_bits_data ( dmi_req.data ), - .debug_resp_valid ( dmi_resp_valid ), - .debug_resp_ready ( dmi_resp_ready ), - .debug_resp_bits_resp ( debug_resp.resp ), - .debug_resp_bits_data ( debug_resp.data ), - .exit ( dmi_exit ) - ); - end else begin - assign dmi_req_valid = '0; - assign debug_req_bits_op = '0; - assign dmi_exit = 1'b0; - end - - // this delay window allows the core to read and execute init code - // from the bootrom before the first debug request can interrupt - // core. this is needed in cases where an fsbl is involved that - // expects a0 and a1 to be initialized with the hart id and a - // pointer to the dev tree, respectively. - localparam int unsigned DmiDelCycles = 500; - - logic debug_req_core_ungtd; - int dmi_del_cnt_d, dmi_del_cnt_q; - - assign dmi_del_cnt_d = (dmi_del_cnt_q) ? dmi_del_cnt_q - 1 : 0; - assign debug_req_core = (dmi_del_cnt_q) ? 1'b0 : - (!debug_enable) ? 1'b0 : debug_req_core_ungtd; - - always_ff @(posedge clk_i or negedge rst_ni) begin : p_dmi_del_cnt - if(!rst_ni) begin - dmi_del_cnt_q <= DmiDelCycles; - end else begin - dmi_del_cnt_q <= dmi_del_cnt_d; - end - end - ariane_axi::req_t dm_axi_m_req; ariane_axi::resp_t dm_axi_m_resp; @@ -290,7 +164,7 @@ module ariane_testharness_dii import cva6_cheri_pkg::*; #( .testmode_i ( test_en ), .ndmreset_o ( ndmreset ), .dmactive_o ( ), // active debug session - .debug_req_o ( debug_req_core_ungtd ), + .debug_req_o ( /* NC */ ), .unavailable_i ( '0 ), .hartinfo_i ( {ariane_pkg::DebugHartInfo} ), .slave_req_i ( dm_slave_req ), @@ -308,12 +182,12 @@ module ariane_testharness_dii import cva6_cheri_pkg::*; #( .master_r_valid_i ( dm_master_r_valid ), .master_r_rdata_i ( dm_master_r_rdata ), .dmi_rst_ni ( rst_ni ), - .dmi_req_valid_i ( debug_req_valid ), - .dmi_req_ready_o ( debug_req_ready ), - .dmi_req_i ( debug_req ), - .dmi_resp_valid_o ( debug_resp_valid ), - .dmi_resp_ready_i ( debug_resp_ready ), - .dmi_resp_o ( debug_resp ) + .dmi_req_valid_i ( 1'b0 ), + .dmi_req_ready_o ( /* NC */ ), + .dmi_req_i ( /* NC */ ), + .dmi_resp_valid_o ( /* NC */ ), + .dmi_resp_ready_i ( 1'b0 ), + .dmi_resp_o ( /* NC */ ) ); diff --git a/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp b/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp index dad3630ab..a41a63def 100644 --- a/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp +++ b/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp @@ -42,10 +42,6 @@ #include #include -#include -#include -#include -#include "remote_bitbang.h" #include // This software is heavily based on Rocket Chip @@ -57,16 +53,7 @@ // allow modulus. You can also use a double, if you wish. static vluint64_t main_time = 0; -static const char *verilog_plusargs[] = {"jtag_rbb_enable", "time_out", "debug_disable"}; - -#ifndef DROMAJO -extern dtm_t* dtm; -extern remote_bitbang_t * jtag; - -void handle_sigterm(int sig) { - dtm->stop(); -} -#endif +static const char *verilog_plusargs[] = {"time_out"}; #ifdef DII struct RVFI_DII_Execution_Packet { @@ -107,10 +94,6 @@ struct RVFI_DII_Instruction_Packet { #endif -extern "C" void read_elf(const char* filename); -extern "C" char get_section (long long* address, long long* len); -extern "C" void read_section_void(long long address, void * buffer, uint64_t size = 0); - void PrintInstTrace(RVFI_DII_Instruction_Packet* packet){ std::cout << "<------Start instruction trace------>" << std::endl; std::cout << "cmd: " << ((packet->dii_cmd == 0) ? "End of Trace" : "Instruction") << std::endl; @@ -178,7 +161,6 @@ EMULATOR DEBUG OPTIONS (only supported in debug build -- try `make debug`)\n", -p, Print performance statistic at end of test\n\ ", stdout); // fputs("\n" PLUSARG_USAGE_OPTIONS, stdout); - fputs("\n" HTIF_USAGE_OPTIONS, stdout); printf("\n" "EXAMPLES\n" " - run a bare metal test:\n" @@ -194,19 +176,6 @@ EMULATOR DEBUG OPTIONS (only supported in debug build -- try `make debug`)\n", , program_name, program_name); } -// In case we use the DTM we do not want to use the JTAG -// to preload the data but only use the DTM to host fesvr functionality. -class preload_aware_dtm_t : public dtm_t { - public: - preload_aware_dtm_t(int argc, char **argv) : dtm_t(argc, argv) {} - bool is_address_preloaded(addr_t taddr, size_t len) override { return true; } - // We do not want to reset the hart here as the reset function in `dtm_t` seems to disregard - // the privilege level and in general does not perform propper reset (despite the name). - // As all our binaries in preloading will always start at the base of DRAM this should not - // be such a big problem. - void reset() {} -}; - int main(int argc, char **argv) { std::clock_t c_start = std::clock(); auto t_start = std::chrono::high_resolution_clock::now(); @@ -247,7 +216,6 @@ int main(int argc, char **argv) { {"socket-name", required_argument, 0, 'q' }, {"socket-default-port", required_argument, 0, 'w' }, #endif - HTIF_LONG_OPTIONS }; int option_index = 0; #if VM_TRACE @@ -330,19 +298,7 @@ int main(int argc, char **argv) { } goto retry; } - // If we STILL don't find a legacy '+' argument, it still could be - // an HTIF (HOST) argument and not an error. If this is the case, then - // we're done processing EMULATOR and VERILOG arguments. else { - static struct option htif_long_options [] = { HTIF_LONG_OPTIONS }; - struct option * htif_option = &htif_long_options[0]; - while (htif_option->name) { - if (arg.substr(1, strlen(htif_option->name)) == htif_option->name) { - optind--; - goto done_processing; - } - htif_option++; - } std::cerr << argv[0] << ": invalid plus-arg (Verilog or HTIF) \"" << arg << "\"\n"; c = '?'; @@ -350,12 +306,7 @@ int main(int argc, char **argv) { goto retry; } case 'P': break; // Nothing to do here, Verilog PlusArg - // Realize that we've hit HTIF (HOST) arguments or error out default: - if (c >= HTIF_LONG_OPTIONS_OPTIND) { - optind--; - goto done_processing; - } c = '?'; goto retry; } @@ -376,12 +327,7 @@ int main(int argc, char **argv) { const char *vcd_file = NULL; Verilated::commandArgs(argc, argv); - jtag = new remote_bitbang_t(rbb_port); - dtm = new preload_aware_dtm_t(htif_argc, htif_argv); - signal(SIGTERM, handle_sigterm); - Variane_testharness_dii* top(new Variane_testharness_dii); - //read_elf(htif_argv[1]); #if VM_TRACE Verilated::traceEverOn(true); // Verilator must compute traced signals @@ -438,15 +384,6 @@ int main(int argc, char **argv) { #ifdef DII size_t mem_size = 0x900000; -#else - size_t mem_size = 0xFFFFFF; - while(get_section(&addr, &len)) - { - if (addr == 0x80000000) - read_section_void(addr, (void *) MEM , mem_size); - } -#endif -#ifdef DII unsigned long long socket = serv_socket_create(socket_name, socket_default_port); serv_socket_init(socket); unsigned int received = 0; @@ -462,13 +399,7 @@ int main(int argc, char **argv) { std::vector instructions; std::vector returntrace; #endif -#if !defined(DROMAJO) || !defined(DII) - while (!dtm->done() && !jtag->done() && !(top->exit_o & 0x1)) { -#else - // the simulation gets killed by dromajo while (true) { -#endif - #ifdef DII // Routine to fetch a batch of intructions from the Vengine if (num_insn == 0) { @@ -573,23 +504,6 @@ int main(int argc, char **argv) { fclose(vcdfile); #endif - /* if (dtm->exit_code()) { - fprintf(stderr, "%s *** FAILED *** (tohost = %d) after %ld cycles\n", htif_argv[1], dtm->exit_code(), main_time); - ret = dtm->exit_code(); - } else if (jtag->exit_code()) { - fprintf(stderr, "%s *** FAILED *** (tohost = %d, seed %d) after %ld cycles\n", htif_argv[1], jtag->exit_code(), random_seed, main_time); - ret = jtag->exit_code(); - } else if (top->exit_o & 0xFFFFFFFE) { - int exitcode = ((unsigned int) top->exit_o) >> 1; - fprintf(stderr, "%s *** FAILED *** (tohost = %d) after %ld cycles\n", htif_argv[1], exitcode, main_time); - ret = exitcode; - } else { - fprintf(stderr, "%s *** SUCCESS *** (tohost = 0) after %ld cycles\n", htif_argv[1], main_time); - } */ - - if (dtm) delete dtm; - if (jtag) delete jtag; - std::clock_t c_end = std::clock(); auto t_end = std::chrono::high_resolution_clock::now(); From 271e551fa0e1f5a5f5a86e364ad2544e0c5b3f30 Mon Sep 17 00:00:00 2001 From: Peter Rugg Date: Fri, 21 Feb 2025 15:30:32 +0000 Subject: [PATCH 03/12] Print exectraces more eagerly --- corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp b/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp index a41a63def..c9b53936b 100644 --- a/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp +++ b/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp @@ -583,9 +583,6 @@ void returnTrace(std::vector &returntrace, unsigned l } else { returntrace.erase(returntrace.begin()); } - for (int i = 0; i < tosend; i++) { - PrintExecTrace(&sendarr[i]); - } // loop to make sure that the packet has been properly sent while(!serv_socket_putN(socket, sizeof(RVFI_DII_Execution_Packet) * tosend, (unsigned int *) sendarr)); } @@ -598,6 +595,7 @@ bool readTrace(std::vector &returntrace, Variane_test // this deals with counting instructions that the core has finished executing if (top->rvfi_valid_o || top->rvfi_trap_o) { RVFI_DII_Execution_Packet execpacket = readRVFI(top); + PrintExecTrace(&execpacket); returntrace.push_back(execpacket); return true; } From 5bee68fb5adf4c2122b9170bc35902953a681fb2 Mon Sep 17 00:00:00 2001 From: Peter Rugg Date: Fri, 21 Feb 2025 15:48:29 +0000 Subject: [PATCH 04/12] Fix some whitespace --- .../src/cva6_dii_toplevel.cpp | 78 +++++++++---------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp b/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp index c9b53936b..042e5f1a8 100644 --- a/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp +++ b/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp @@ -76,9 +76,9 @@ static const char *verilog_plusargs[] = {"time_out"}; std::uint8_t rvfi_rd_addr : 8; // [84] Write register address: MUST be 0 if not used. std::uint8_t rvfi_trap : 8; // [85] Trap indicator: Invalid decode, misaligned access or // jump command to misaligned address. - std::uint8_t rvfi_halt : 8; // [86] Halt indicator: Marks the last instruction retired + std::uint8_t rvfi_halt : 8; // [86] Halt indicator: Marks the last instruction retired // before halting execution. - std::uint8_t rvfi_intr : 8; // [87] Trap handler: Set for first instruction in trap handler. + std::uint8_t rvfi_intr : 8; // [87] Trap handler: Set for first instruction in trap handler. }; struct RVFI_DII_Instruction_Packet { @@ -104,24 +104,24 @@ void PrintInstTrace(RVFI_DII_Instruction_Packet* packet){ void PrintExecTrace(RVFI_DII_Execution_Packet* packet){ std::cout << "<------Start execution trace------>" << std::endl; - std::cout << "order: " << (int) packet->rvfi_order << std::endl; - std::cout << "pc_rdata: " << std::hex << (int) packet->rvfi_pc_rdata << std::endl; - std::cout << "pc_wdata: " << std::hex << (int) packet->rvfi_pc_wdata << std::endl; - std::cout << "insn: " << std::hex << (int) packet->rvfi_insn << std::endl; - std::cout << "rs1_data: " << std::hex << (int) packet->rvfi_rs1_data << std::endl; - std::cout << "rs2_data: " << std::hex << (int) packet->rvfi_rs2_data << std::endl; - std::cout << "rd_wdata: " << std::hex << (int) packet->rvfi_rd_wdata << std::endl; - std::cout << "mem_addr: " << std::hex << (int) packet->rvfi_mem_addr << std::endl; - std::cout << "mem_rdatal: " << std::hex << (int)packet->rvfi_mem_rdata << std::endl; - std::cout << "mem_wdatal: " << std::hex << (int) packet->rvfi_mem_wdata << std::endl; - std::cout << "mem_rmask: " << std::hex << (int) packet->rvfi_mem_rmask << std::endl; - std::cout << "mem_wmask: " << std::hex << (int) packet->rvfi_mem_wmask << std::endl; - std::cout << "rs1_addr: " << std::hex << (int) packet->rvfi_rs1_addr << std::endl; - std::cout << "rs2_addr: " << std::hex << (int) packet->rvfi_rs2_addr << std::endl; - std::cout << "rd_addr: " << std::hex << (int) packet->rvfi_rd_addr << std::endl; - std::cout << "trap: " << (int) packet->rvfi_trap << std::endl; - std::cout << "halt: " << (int) packet->rvfi_halt << std::endl; - std::cout << "instr: " << std::hex << (int) packet->rvfi_intr << std::endl; + std::cout << "order: " << (int) packet->rvfi_order << std::endl; + std::cout << "pc_rdata: " << std::hex << (int) packet->rvfi_pc_rdata << std::endl; + std::cout << "pc_wdata: " << std::hex << (int) packet->rvfi_pc_wdata << std::endl; + std::cout << "insn: " << std::hex << (int) packet->rvfi_insn << std::endl; + std::cout << "rs1_data: " << std::hex << (int) packet->rvfi_rs1_data << std::endl; + std::cout << "rs2_data: " << std::hex << (int) packet->rvfi_rs2_data << std::endl; + std::cout << "rd_wdata: " << std::hex << (int) packet->rvfi_rd_wdata << std::endl; + std::cout << "mem_addr: " << std::hex << (int) packet->rvfi_mem_addr << std::endl; + std::cout << "mem_rdatal: " << std::hex << (int)packet->rvfi_mem_rdata << std::endl; + std::cout << "mem_wdatal: " << std::hex << (int) packet->rvfi_mem_wdata << std::endl; + std::cout << "mem_rmask: " << std::hex << (int) packet->rvfi_mem_rmask << std::endl; + std::cout << "mem_wmask: " << std::hex << (int) packet->rvfi_mem_wmask << std::endl; + std::cout << "rs1_addr: " << std::hex << (int) packet->rvfi_rs1_addr << std::endl; + std::cout << "rs2_addr: " << std::hex << (int) packet->rvfi_rs2_addr << std::endl; + std::cout << "rd_addr: " << std::hex << (int) packet->rvfi_rd_addr << std::endl; + std::cout << "trap: " << (int) packet->rvfi_trap << std::endl; + std::cout << "halt: " << (int) packet->rvfi_halt << std::endl; + std::cout << "instr: " << std::hex << (int) packet->rvfi_intr << std::endl; std::cout << "<------Finish execution trace------>" << std::endl; } @@ -390,7 +390,7 @@ int main(int argc, char **argv) { unsigned int insn_count = 0; unsigned int traces_count = 0; unsigned int num_insn = 0; - // instruction + // instruction bool busy = false; bool inflight = false; bool eof_trace = false; @@ -407,11 +407,11 @@ int main(int argc, char **argv) { busy = true; num_insn = instructions.size(); } - + while (busy) { - if (readTrace(returntrace, top)){ - traces_count++; - } + if (readTrace(returntrace, top)){ + traces_count++; + } // Routine to inject instructions into the core via RVFIDII interface if (!instructions.empty() /* && !inflight */){ if ((traces_count != num_insn-1) && (top->rvfi_trap_o || (top->rvfi_valid_o && (top->rvfi_insn_o & 0x7F) == 0xF))) { @@ -435,26 +435,26 @@ int main(int argc, char **argv) { } } #endif - top->clk_i = 0; - top->eval(); + top->clk_i = 0; + top->eval(); #if VM_TRACE - if (vcdfile || fst_fname) - tfp->dump(static_cast(main_time * 2)); + if (vcdfile || fst_fname) + tfp->dump(static_cast(main_time * 2)); #endif - top->clk_i = 1; - top->eval(); + top->clk_i = 1; + top->eval(); #if VM_TRACE - if (vcdfile || fst_fname) - tfp->dump(static_cast(main_time * 2 + 1)); + if (vcdfile || fst_fname) + tfp->dump(static_cast(main_time * 2 + 1)); #endif - // toggle RTC - if (main_time % 2 == 0) { - top->rtc_i ^= 1; - } - main_time++; + // toggle RTC + if (main_time % 2 == 0) { + top->rtc_i ^= 1; + } + main_time++; - // Reset Routine + // Reset Routine if (eof_trace){ for (int i = 0; i < 10; i++) { top->rst_ni = 0; From c4397f3eaae11bfd630fe6fa5580e4ad1eec5813 Mon Sep 17 00:00:00 2001 From: Peter Rugg Date: Fri, 21 Feb 2025 15:50:27 +0000 Subject: [PATCH 05/12] Remove DII ifdef --- .../src/cva6_dii_toplevel.cpp | 77 ++++++++----------- 1 file changed, 32 insertions(+), 45 deletions(-) diff --git a/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp b/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp index 042e5f1a8..4854156c6 100644 --- a/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp +++ b/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp @@ -47,7 +47,6 @@ // This software is heavily based on Rocket Chip // Checkout this awesome project: // https://github.com/freechipsproject/rocket-chip/ -#define DII 1 // This is a 64-bit integer to reduce wrap over issues and // allow modulus. You can also use a double, if you wish. @@ -55,45 +54,42 @@ static vluint64_t main_time = 0; static const char *verilog_plusargs[] = {"time_out"}; -#ifdef DII - struct RVFI_DII_Execution_Packet { - std::uint64_t rvfi_order : 64; // [00 - 07] Instruction number: INSTRET value after completion. - std::uint64_t rvfi_pc_rdata : 64; // [08 - 15] PC before instr: PC for current instruction - std::uint64_t rvfi_pc_wdata : 64; // [16 - 23] PC after instr: Following PC - either PC + 4 or jump/trap target. - std::uint64_t rvfi_insn : 64; // [24 - 31] Instruction word: 32-bit command value. - std::uint64_t rvfi_rs1_data : 64; // [32 - 39] Read register values: Values as read from registers named - std::uint64_t rvfi_rs2_data : 64; // [40 - 47] above. Must be 0 if register ID is 0. - std::uint64_t rvfi_rd_wdata : 64; // [48 - 55] Write register value: MUST be 0 if rd_ is 0. - std::uint64_t rvfi_mem_addr : 64; // [56 - 63] Memory access addr: Points to byte address (aligned if define - // is set). *Should* be straightforward. - // 0 if unused. - std::uint64_t rvfi_mem_rdata : 64; // [64 - 71] Read data: Data read from mem_addr (i.e. before write) - std::uint64_t rvfi_mem_wdata : 64; // [72 - 79] Write data: Data written to memory by this command. - std::uint8_t rvfi_mem_rmask : 8; // [80] Read mask: Indicates valid bytes read. 0 if unused. - std::uint8_t rvfi_mem_wmask : 8; // [81] Write mask: Indicates valid bytes written. 0 if unused. - std::uint8_t rvfi_rs1_addr : 8; // [82] Read register addresses: Can be arbitrary when not used, - std::uint8_t rvfi_rs2_addr : 8; // [83] otherwise set as decoded. - std::uint8_t rvfi_rd_addr : 8; // [84] Write register address: MUST be 0 if not used. - std::uint8_t rvfi_trap : 8; // [85] Trap indicator: Invalid decode, misaligned access or - // jump command to misaligned address. - std::uint8_t rvfi_halt : 8; // [86] Halt indicator: Marks the last instruction retired - // before halting execution. - std::uint8_t rvfi_intr : 8; // [87] Trap handler: Set for first instruction in trap handler. +struct RVFI_DII_Execution_Packet { + std::uint64_t rvfi_order : 64; // [00 - 07] Instruction number: INSTRET value after completion. + std::uint64_t rvfi_pc_rdata : 64; // [08 - 15] PC before instr: PC for current instruction + std::uint64_t rvfi_pc_wdata : 64; // [16 - 23] PC after instr: Following PC - either PC + 4 or jump/trap target. + std::uint64_t rvfi_insn : 64; // [24 - 31] Instruction word: 32-bit command value. + std::uint64_t rvfi_rs1_data : 64; // [32 - 39] Read register values: Values as read from registers named + std::uint64_t rvfi_rs2_data : 64; // [40 - 47] above. Must be 0 if register ID is 0. + std::uint64_t rvfi_rd_wdata : 64; // [48 - 55] Write register value: MUST be 0 if rd_ is 0. + std::uint64_t rvfi_mem_addr : 64; // [56 - 63] Memory access addr: Points to byte address (aligned if define + // is set). *Should* be straightforward. + // 0 if unused. + std::uint64_t rvfi_mem_rdata : 64; // [64 - 71] Read data: Data read from mem_addr (i.e. before write) + std::uint64_t rvfi_mem_wdata : 64; // [72 - 79] Write data: Data written to memory by this command. + std::uint8_t rvfi_mem_rmask : 8; // [80] Read mask: Indicates valid bytes read. 0 if unused. + std::uint8_t rvfi_mem_wmask : 8; // [81] Write mask: Indicates valid bytes written. 0 if unused. + std::uint8_t rvfi_rs1_addr : 8; // [82] Read register addresses: Can be arbitrary when not used, + std::uint8_t rvfi_rs2_addr : 8; // [83] otherwise set as decoded. + std::uint8_t rvfi_rd_addr : 8; // [84] Write register address: MUST be 0 if not used. + std::uint8_t rvfi_trap : 8; // [85] Trap indicator: Invalid decode, misaligned access or + // jump command to misaligned address. + std::uint8_t rvfi_halt : 8; // [86] Halt indicator: Marks the last instruction retired + // before halting execution. + std::uint8_t rvfi_intr : 8; // [87] Trap handler: Set for first instruction in trap handler. }; struct RVFI_DII_Instruction_Packet { - std::uint32_t dii_insn : 32; // [0 - 3] Instruction word: 32-bit instruction or command. The lower 16-bits - // may decode to a 16-bit compressed instruction. - std::uint16_t dii_time : 16; // [5 - 4] Time to inject token. The difference between this and the previous - // instruction time gives a delay before injecting this instruction. - // This can be ignored for models but gives repeatability for implementations - // while shortening counterexamples. - std::uint8_t dii_cmd : 8; // [6] This token is a trace command. For example, reset device under test. - std::uint8_t padding : 8; // [7] + std::uint32_t dii_insn : 32; // [0 - 3] Instruction word: 32-bit instruction or command. The lower 16-bits + // may decode to a 16-bit compressed instruction. + std::uint16_t dii_time : 16; // [5 - 4] Time to inject token. The difference between this and the previous + // instruction time gives a delay before injecting this instruction. + // This can be ignored for models but gives repeatability for implementations + // while shortening counterexamples. + std::uint8_t dii_cmd : 8; // [6] This token is a trace command. For example, reset device under test. + std::uint8_t padding : 8; // [7] }; -#endif - void PrintInstTrace(RVFI_DII_Instruction_Packet* packet){ std::cout << "<------Start instruction trace------>" << std::endl; std::cout << "cmd: " << ((packet->dii_cmd == 0) ? "End of Trace" : "Instruction") << std::endl; @@ -194,10 +190,9 @@ int main(int argc, char **argv) { #endif char ** htif_argv = NULL; int verilog_plusargs_legal = 1; -#if DII + char* socket_name = NULL; int socket_default_port = -1; -#endif while (1) { static struct option long_options[] = { @@ -212,10 +207,8 @@ int main(int argc, char **argv) { {"dump-start", required_argument, 0, 'x' }, {"fst", required_argument, 0, 'f' }, #endif -#if DII {"socket-name", required_argument, 0, 'q' }, {"socket-default-port", required_argument, 0, 'w' }, -#endif }; int option_index = 0; #if VM_TRACE @@ -235,14 +228,12 @@ int main(int argc, char **argv) { case 'r': rbb_port = atoi(optarg); break; case 'V': verbose = true; break; case 'p': perf = true; break; -#ifdef DII case 'q': { socket_name = (char*) malloc(strlen(optarg)); strcpy(socket_name,optarg); break; } case 'w': socket_default_port = atoi(optarg); break; -#endif #if VM_TRACE case 'v': { vcdfile = strcmp(optarg, "-") == 0 ? stdout : fopen(optarg, "w"); @@ -382,7 +373,6 @@ int main(int argc, char **argv) { long long addr; long long len; -#ifdef DII size_t mem_size = 0x900000; unsigned long long socket = serv_socket_create(socket_name, socket_default_port); serv_socket_init(socket); @@ -398,9 +388,7 @@ int main(int argc, char **argv) { char recbuf[sizeof(RVFI_DII_Instruction_Packet) + 1] = {0}; std::vector instructions; std::vector returntrace; -#endif while (true) { -#ifdef DII // Routine to fetch a batch of intructions from the Vengine if (num_insn == 0) { fetchInstructions(instructions, received, socket); @@ -434,7 +422,6 @@ int main(int argc, char **argv) { inflight = false; } } -#endif top->clk_i = 0; top->eval(); #if VM_TRACE From e96f94a632e84c56a4bea16f221e86694f277e73 Mon Sep 17 00:00:00 2001 From: Peter Rugg Date: Fri, 21 Feb 2025 15:59:08 +0000 Subject: [PATCH 06/12] More cleanups of tb features incompatible with DII --- .../src/cva6_dii_toplevel.cpp | 44 +------------------ 1 file changed, 2 insertions(+), 42 deletions(-) diff --git a/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp b/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp index 4854156c6..629e89a15 100644 --- a/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp +++ b/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp @@ -154,7 +154,6 @@ EMULATOR DEBUG OPTIONS (only supported in debug build -- try `make debug`)\n", fputs("\ -v, --vcd=FILE, Write vcd trace to FILE (or '-' for stdout)\n\ -f, --fst=FILE, Write fst trace to FILE\n\ - -p, Print performance statistic at end of test\n\ ", stdout); // fputs("\n" PLUSARG_USAGE_OPTIONS, stdout); printf("\n" @@ -176,19 +175,12 @@ int main(int argc, char **argv) { std::clock_t c_start = std::clock(); auto t_start = std::chrono::high_resolution_clock::now(); bool verbose; - bool perf; - unsigned random_seed = (unsigned)time(NULL) ^ (unsigned)getpid(); - uint64_t max_cycles = -1; int ret = 0; - bool print_cycles = false; - // Port numbers are 16 bit unsigned integers. - uint16_t rbb_port = 0; #if VM_TRACE FILE * vcdfile = NULL; char * fst_fname = NULL; uint64_t start = 0; #endif - char ** htif_argv = NULL; int verilog_plusargs_legal = 1; char* socket_name = NULL; @@ -196,11 +188,7 @@ int main(int argc, char **argv) { while (1) { static struct option long_options[] = { - {"cycle-count", no_argument, 0, 'c' }, {"help", no_argument, 0, 'h' }, - {"max-cycles", required_argument, 0, 'm' }, - {"seed", required_argument, 0, 's' }, - {"rbb-port", required_argument, 0, 'r' }, {"verbose", no_argument, 0, 'V' }, #if VM_TRACE {"vcd", required_argument, 0, 'v' }, @@ -212,22 +200,17 @@ int main(int argc, char **argv) { }; int option_index = 0; #if VM_TRACE - int c = getopt_long(argc, argv, "-chpm:s:r:v:f:Vx:q:w:", long_options, &option_index); + int c = getopt_long(argc, argv, "-hv:f:Vx:q:w:", long_options, &option_index); #else - int c = getopt_long(argc, argv, "-chpm:s:r:V:q:w:", long_options, &option_index); + int c = getopt_long(argc, argv, "-hV:q:w:", long_options, &option_index); #endif if (c == -1) break; retry: switch (c) { // Process long and short EMULATOR options case '?': usage(argv[0]); return 1; - case 'c': print_cycles = true; break; case 'h': usage(argv[0]); return 0; - case 'm': max_cycles = atoll(optarg); break; - case 's': random_seed = atoi(optarg); break; - case 'r': rbb_port = atoi(optarg); break; case 'V': verbose = true; break; - case 'p': perf = true; break; case 'q': { socket_name = (char*) malloc(strlen(optarg)); strcpy(socket_name,optarg); @@ -259,18 +242,12 @@ int main(int argc, char **argv) { } if (arg == "+verbose") c = 'V'; - else if (arg.substr(0, 12) == "+max-cycles=") { - c = 'm'; - optarg = optarg+12; - } #if VM_TRACE else if (arg.substr(0, 12) == "+dump-start=") { c = 'x'; optarg = optarg+12; } #endif - else if (arg.substr(0, 12) == "+cycle-count") - c = 'c'; // If we don't find a legacy '+' EMULATOR argument, it still could be // a VERILOG_PLUSARG and not an error. else if (verilog_plusargs_legal) { @@ -304,15 +281,6 @@ int main(int argc, char **argv) { } done_processing: - /* if (optind == argc) { - std::cerr << "No binary specified for emulator\n"; - usage(argv[0]); - return 1; - } */ - int htif_argc = 1 + argc - optind; - htif_argv = (char **) malloc((htif_argc) * sizeof (char *)); - htif_argv[0] = argv[0]; - for (int i = 1; optind < argc;) htif_argv[i++] = argv[optind++]; std::cout << "start" << std::endl; const char *vcd_file = NULL; @@ -494,14 +462,6 @@ int main(int argc, char **argv) { std::clock_t c_end = std::clock(); auto t_end = std::chrono::high_resolution_clock::now(); - if (perf) { - std::cout << std::fixed << std::setprecision(2) << "CPU time used: " - << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n" - << "Wall clock time passed: " - << std::chrono::duration(t_end-t_start).count() - << " ms\n"; - } - return ret; } From ea320b443ae8bf2c3fb6afb8e74672aebd47ce64 Mon Sep 17 00:00:00 2001 From: Peter Rugg Date: Fri, 21 Feb 2025 16:12:35 +0000 Subject: [PATCH 07/12] More eagerly send traces back to Vengine --- corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp b/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp index 629e89a15..31254682f 100644 --- a/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp +++ b/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp @@ -445,10 +445,11 @@ int main(int argc, char **argv) { returntrace.push_back(rstpack); instructions.clear(); } - } - // Routine to return trace to Vengine - while (!returntrace.empty()) { - returnTrace(returntrace, socket); + + // Routine to return trace to Vengine + while (!returntrace.empty()) { + returnTrace(returntrace, socket); + } } } From 836169c1bea6d1e2eee60610fc7f1c1165f6f39b Mon Sep 17 00:00:00 2001 From: Peter Rugg Date: Thu, 27 Feb 2025 16:57:12 +0000 Subject: [PATCH 08/12] Remove duplicate import --- corev_apu/tb/tb_testRig_cheri/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/corev_apu/tb/tb_testRig_cheri/Makefile b/corev_apu/tb/tb_testRig_cheri/Makefile index f40e405ec..87d0f7126 100644 --- a/corev_apu/tb/tb_testRig_cheri/Makefile +++ b/corev_apu/tb/tb_testRig_cheri/Makefile @@ -180,7 +180,6 @@ src := $(root-dir)/core/include/$(target)_config_pkg.sv $(root-dir)/vendor/zero-day/axi_tagcontroller/src/axi_tagctrl_top.sv \ $(root-dir)/vendor/zero-day/axi_tagcontroller/src/axi_tagctrl_reg_wrap.sv \ $(root-dir)/corev_apu/tb/ariane_testharness.sv \ - $(root-dir)/corev_apu/tb/tb_testRig_cheri/hdl/ariane_testharness_dii.sv \ $(root-dir)/corev_apu/tb/cva6_cheri_tag_mem.sv \ $(root-dir)/corev_apu/tb/ariane_peripherals.sv \ $(root-dir)/corev_apu/tb/rvfi_tracer.sv \ From 24b541036fd9ccb547fb1af7fa57b7baf35c90c0 Mon Sep 17 00:00:00 2001 From: Peter Rugg Date: Fri, 14 Mar 2025 17:51:45 +0000 Subject: [PATCH 09/12] Fix RVFI blocking/non-blocking assign issue --- core/cva6_rvfi.sv | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/core/cva6_rvfi.sv b/core/cva6_rvfi.sv index 7ab1f1710..bd78cb203 100644 --- a/core/cva6_rvfi.sv +++ b/core/cva6_rvfi.sv @@ -271,7 +271,11 @@ module cva6_rvfi always_ff @(posedge clk_i) begin for (int i = 0; i < CVA6Cfg.NrCommitPorts; i++) begin logic exception; + logic [4:0] rd_addr; + logic [4:0] rs2_addr; exception = commit_instr_valid[i][0] && ex_commit_valid; + rd_addr = commit_instr_rd[i][4:0]; + rs2_addr = (is_amo_sc(commit_instr_op[i]) && wdata[i] == 1) ? '0 : commit_instr_rs2[i][4:0]; rvfi_instr_o[i].valid <= (commit_ack[i] && !ex_commit_valid) || (exception && (ex_commit_cause == riscv::ENV_CALL_MMODE || ex_commit_cause == riscv::ENV_CALL_SMODE || @@ -284,9 +288,9 @@ module cva6_rvfi rvfi_instr_o[i].mode <= (CVA6Cfg.DebugEn && debug_mode) ? 2'b10 : priv_lvl; rvfi_instr_o[i].ixl <= CVA6Cfg.XLEN == 64 ? 2 : 1; rvfi_instr_o[i].rs1_addr <= (is_amo_sc(commit_instr_op[i]) && wdata[i] == 1) ? '0 : commit_instr_rs1[i][4:0]; - rvfi_instr_o[i].rs2_addr <= (is_amo_sc(commit_instr_op[i]) && wdata[i] == 1) ? '0 : commit_instr_rs2[i][4:0]; - rvfi_instr_o[i].rd_addr <= commit_instr_rd[i][4:0]; - rvfi_instr_o[i].rd_wdata <= (rvfi_instr_o[i].rd_addr == 0) ? '0 : (CVA6Cfg.FpPresent && is_rd_fpr( + rvfi_instr_o[i].rs2_addr <= rs2_addr; + rvfi_instr_o[i].rd_addr <= rd_addr; + rvfi_instr_o[i].rd_wdata <= (rd_addr == 0) ? '0 : (CVA6Cfg.FpPresent && is_rd_fpr( commit_instr_op[i] )) ? commit_instr_result[i] : wdata[i]; rvfi_instr_o[i].pc_rdata <= commit_instr_pc[i]; @@ -305,7 +309,7 @@ module cva6_rvfi rvfi_instr_o[i].mem_rmask <= /* (mem_q[commit_pointer[i]].lsu_wmask == 16'hFFFF) ? '0 : */mem_q[commit_pointer[i]].lsu_rmask >> mem_q[commit_pointer[i]].lsu_addr[3:0]; rvfi_instr_o[i].mem_rdata <= commit_instr_result[i]; rvfi_instr_o[i].rs1_rdata <= mem_q[commit_pointer[i]].rs1_rdata; - rvfi_instr_o[i].rs2_rdata <= (rvfi_instr_o[i].rs2_addr == 0) ? '0 : mem_q[commit_pointer[i]].rs2_rdata; + rvfi_instr_o[i].rs2_rdata <= (rs2_addr == 0) ? '0 : mem_q[commit_pointer[i]].rs2_rdata; end end @@ -422,4 +426,4 @@ module cva6_rvfi endgenerate ; -endmodule \ No newline at end of file +endmodule From d47e2dc8b7d71b0bb0f95447a590c8f26235270d Mon Sep 17 00:00:00 2001 From: Peter Rugg Date: Fri, 28 Mar 2025 14:56:15 +0000 Subject: [PATCH 10/12] Disable Zcb extension in RVFI_DII config This is not supported by the version of the Sail model we are testing against --- core/include/cv64a6_imafdch_sv39_rvfi_dii_config_pkg.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/include/cv64a6_imafdch_sv39_rvfi_dii_config_pkg.sv b/core/include/cv64a6_imafdch_sv39_rvfi_dii_config_pkg.sv index 42bbfeb05..08f22eed6 100644 --- a/core/include/cv64a6_imafdch_sv39_rvfi_dii_config_pkg.sv +++ b/core/include/cv64a6_imafdch_sv39_rvfi_dii_config_pkg.sv @@ -18,7 +18,7 @@ package cva6_config_pkg; localparam CVA6ConfigCvxifEn = 0; localparam CVA6ConfigCExtEn = 1; - localparam CVA6ConfigZcbExtEn = 1; + localparam CVA6ConfigZcbExtEn = 0; localparam CVA6ConfigZcmpExtEn = 0; localparam CVA6ConfigAExtEn = 1; localparam CVA6ConfigHExtEn = 1; From 75aba50573ec0b47180b994c5142e098660461d4 Mon Sep 17 00:00:00 2001 From: Peter Rugg Date: Tue, 11 Mar 2025 11:01:30 +0000 Subject: [PATCH 11/12] Add DII support for pipelining and compressed instructions This includes removing some workarounds that modified the core in RVFI_DII mode to align with Sail with compressed instructions disabled --- .gitmodules | 6 +- core/branch_unit.sv | 9 +- core/cache_subsystem/wt_cache_subsystem.sv | 16 +- core/commit_stage.sv | 4 + core/csr_regfile.sv | 10 +- core/cva6.sv | 23 +- core/cva6_rvfi.sv | 11 +- core/decoder.sv | 3 + core/ex_stage.sv | 4 + core/frontend/frontend.sv | 48 ++- core/frontend/instr_queue.sv | 28 +- core/id_stage.sv | 2 + core/include/build_config_pkg.sv | 1 + core/include/config_pkg.sv | 3 + ...cv64a6_imafdch_sv39_rvfi_dii_config_pkg.sv | 4 +- .../cv64a6_imafdchzcheri_sv39_config_pkg.sv | 4 +- core/include/rvfi_types.svh | 7 - core/instr_realign.sv | 32 ++ core/issue_read_operands.sv | 5 + core/issue_stage.sv | 3 + core/load_unit.sv | 1 + core/rvfi_dii_generator.sv | 116 ++++--- corev_apu/fpga/src/ariane_xilinx.sv | 3 - corev_apu/src/ariane.sv | 7 - corev_apu/tb/ariane_testharness.sv | 5 - corev_apu/tb/common/SimDTM.sv | 4 + corev_apu/tb/common/SimJTAG.sv | 4 + corev_apu/tb/tb_testRig_cheri/Makefile | 6 +- .../hdl/ariane_testharness_dii.sv | 30 +- .../tb/tb_testRig_cheri/src/RVFI-DII-utils | 1 + .../tb/tb_testRig_cheri/src/SocketPacketUtils | 1 - .../src/cva6_dii_toplevel.cpp | 321 +++++------------- 32 files changed, 349 insertions(+), 373 deletions(-) create mode 160000 corev_apu/tb/tb_testRig_cheri/src/RVFI-DII-utils delete mode 160000 corev_apu/tb/tb_testRig_cheri/src/SocketPacketUtils diff --git a/.gitmodules b/.gitmodules index bf7da440b..5f3a3cf25 100644 --- a/.gitmodules +++ b/.gitmodules @@ -52,6 +52,6 @@ [submodule "vendor/zero-day/axi_tagcontroller"] path = vendor/zero-day/axi_tagcontroller url = https://github.com/ninolomata/axi_cheri_tagcontroller.git -[submodule "corev_apu/tb/tb_testRig_cheri/src/SocketPacketUtils"] - path = corev_apu/tb/tb_testRig_cheri/src/SocketPacketUtils - url = https://github.com/CTSRD-CHERI/SocketPacketUtils +[submodule "corev_apu/tb/tb_testRig_cheri/src/RVFI-DII-utils"] + path = corev_apu/tb/tb_testRig_cheri/src/RVFI-DII-utils + url = https://github.com/CTSRD-CHERI/RVFI-DII-utils.git diff --git a/core/branch_unit.sv b/core/branch_unit.sv index 4f45494ae..067b9ab0c 100644 --- a/core/branch_unit.sv +++ b/core/branch_unit.sv @@ -1,5 +1,6 @@ // Copyright 2018 ETH Zurich and University of Bologna. // Copyright 2025 Bruno Sá and Zero-Day Labs. +// Copyright 2025 Capabilities Limited. // 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 @@ -32,6 +33,8 @@ module branch_unit #( input fu_data_t fu_data_i, // Instruction PC - ISSUE_STAGE input logic [CVA6Cfg.PCLEN-1:0] pc_i, + // Instruction stream DII ID - ISSUE_STAGE + input logic [CVA6Cfg.DIIIDLEN-1:0] dii_id_i, // Instruction is compressed - ISSUE_STAGE input logic is_compressed_instr_i, // any functional unit is valid, check that there is no accidental mis-predict - TO_BE_COMPLETED @@ -144,6 +147,7 @@ module branch_unit #( branch_result_o = next_pc; end resolved_branch_o.pc = pc_i[CVA6Cfg.VLEN-1:0]; + if (CVA6Cfg.RVFI_DII) resolved_branch_o.dii_id = dii_id_i; // There are only two sources of mispredicts: // 1. Branches // 2. Jumps to register addresses @@ -198,11 +202,10 @@ module branch_unit #( target_pcc_top = target_pcc.top; target_pcc_address = target_pcc.addr; target_pcc_is_sealed = (operand_a.otype != cva6_cheri_pkg::UNSEALED_CAP); - // TODO-cheri(ninolomata): fix this once we disable compressed instructions without trigering errors - min_instr_off = ((CVA6Cfg.RVC && !CVA6Cfg.RVFI_DII) ? {{CVA6Cfg.XLEN-2{1'b0}}, 2'h2} : {{CVA6Cfg.XLEN-3{1'b0}}, 3'h4}); + min_instr_off = ((CVA6Cfg.RVC) ? {{CVA6Cfg.XLEN-2{1'b0}}, 2'h2} : {{CVA6Cfg.XLEN-3{1'b0}}, 3'h4}); // Only throw instruction address misaligned exception if this is indeed a `taken` conditional branch or // an unconditional jump - if (branch_valid_i && (target_address[0] || ((!CVA6Cfg.RVC || CVA6Cfg.RVFI_DII) && target_address[1])) && jump_taken) begin + if (branch_valid_i && (target_address[0] || (!CVA6Cfg.RVC && target_address[1])) && jump_taken) begin branch_exception_o.valid = 1'b1; end if (CVA6Cfg.CheriPresent && branch_valid_i && jump_taken) begin diff --git a/core/cache_subsystem/wt_cache_subsystem.sv b/core/cache_subsystem/wt_cache_subsystem.sv index 2cf2492b5..2ac3e549b 100644 --- a/core/cache_subsystem/wt_cache_subsystem.sv +++ b/core/cache_subsystem/wt_cache_subsystem.sv @@ -1,4 +1,5 @@ // Copyright 2018 ETH Zurich and University of Bologna. +// Copyright 2025 Capabilities Limited. // 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 @@ -33,7 +34,6 @@ module wt_cache_subsystem parameter type dcache_req_o_t = logic, parameter type icache_req_t = logic, parameter type icache_rtrn_t = logic, - parameter type rvfi_dii_inst_pack_t = logic, parameter int unsigned NumPorts = 4, parameter type noc_req_t = logic, parameter type noc_resp_t = logic @@ -73,11 +73,7 @@ module wt_cache_subsystem // Invalidations input logic [63:0] inval_addr_i, input logic inval_valid_i, - output logic inval_ready_o, - // RVFI_DII Interface - input logic rvfi_dii_rtrn_vld_i, - input rvfi_dii_inst_pack_t rvfi_dii_inst_pack_i, - output logic rvfi_dii_data_ready_o + output logic inval_ready_o // TODO: interrupt interface ); @@ -122,16 +118,12 @@ module wt_cache_subsystem .CVA6Cfg(CVA6Cfg), .icache_dreq_t(icache_dreq_t), .icache_drsp_t(icache_drsp_t), - .exception_t (exception_t), - .rvfi_dii_inst_pack_t (rvfi_dii_inst_pack_t) + .exception_t (exception_t) ) i_cva6_rvfi_dii_generator ( .clk_i (clk_i), .rst_ni (rst_ni), .dreq_i (icache_dreq_i), - .dreq_o (icache_dreq_o), - .rvfi_dii_rtrn_vld_i (rvfi_dii_rtrn_vld_i), - .rvfi_dii_inst_pack_i (rvfi_dii_inst_pack_i), - .rvfi_dii_data_ready_o (rvfi_dii_data_ready_o) + .dreq_o (icache_dreq_o) ); assign icache_areq_o = '0; assign icache_adapter_data_req = '0; diff --git a/core/commit_stage.sv b/core/commit_stage.sv index 62c9afc26..8b6f8dde5 100644 --- a/core/commit_stage.sv +++ b/core/commit_stage.sv @@ -1,5 +1,6 @@ // Copyright 2018 ETH Zurich and University of Bologna. // Copyright 2025 Bruno Sá and Zero-Day Labs. +// Copyright 2025 Capabilities Limited. // 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 @@ -33,6 +34,8 @@ module commit_stage output exception_t exception_o, // Mark the F state as dirty - CSR_REGFILE output logic dirty_fp_state_o, + // Last committed DII ID - FRONTEND + output logic [CVA6Cfg.DIIIDLEN-1 : 0] dii_id_o, // TO_BE_COMPLETED - CSR_REGFILE input logic single_step_i, // The instruction we want to commit - ISSUE_STAGE @@ -123,6 +126,7 @@ module commit_stage end assign pc_o = commit_instr_i[0].pc; + if (CVA6Cfg.RVFI_DII) assign dii_id_o = commit_instr_i[0].dii_id; // Dirty the FP state if we are committing anything related to the FPU always_comb begin : dirty_fp_state dirty_fp_state_o = 1'b0; diff --git a/core/csr_regfile.sv b/core/csr_regfile.sv index 57417ce12..29a79df56 100644 --- a/core/csr_regfile.sv +++ b/core/csr_regfile.sv @@ -1,5 +1,6 @@ // Copyright 2018 ETH Zurich and University of Bologna. // Copyright 2025 Bruno Sá and Zero-Day Labs. +// Copyright 2025 Capabilities Limited. // 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 @@ -397,9 +398,6 @@ if (CVA6Cfg.CheriPresent) begin riscv::CSR_MEPC: begin wr_cap = mepcc_q; wr_cap_addr = {csr_wdata[riscv::XLEN-1:1], 1'b0}; - // TODO-ninolomata(cheri): fix this - if (CVA6Cfg.RVFI_DII) - wr_cap_addr = {csr_wdata[riscv::XLEN-1:2], 2'b0}; end riscv::CSR_MTVEC: begin wr_cap = mtcc_q; @@ -417,9 +415,6 @@ if (CVA6Cfg.CheriPresent) begin riscv::CSR_SEPC: begin wr_cap = sepcc_q; wr_cap_addr = {csr_wdata[riscv::XLEN-1:1], 1'b0}; - // TODO-ninolomata(cheri): fix this - if (CVA6Cfg.RVFI_DII) - wr_cap_addr = {csr_wdata[riscv::XLEN-1:2], 2'b0}; end riscv::CSR_STVEC: begin wr_cap = stcc_q; @@ -1218,7 +1213,6 @@ end sscratchc_d = scr_wdata; end cva6_cheri_pkg::SCR_SEPCC: begin - // TODO-cheri(ninolomata):fix this it should clear bit 1 only sepcc_d = cva6_cheri_pkg::set_cap_reg_addr(scr_wdata, {scr_wdata[CVA6Cfg.XLEN-1:1], 1'b0}); end cva6_cheri_pkg::SCR_MTCC: begin @@ -1237,8 +1231,6 @@ end mscratchc_d = scr_wdata; end cva6_cheri_pkg::SCR_MEPCC: begin - // TODO-cheri(ninolomata):fix this it should clear bit 1 only - //mepcc_d = cva6_cheri_pkg::set_cap_reg_addr(scr_wdata, {scr_wdata[CVA6Cfg.XLEN-1:2], 2'b00}); mepcc_d = cva6_cheri_pkg::set_cap_reg_addr(scr_wdata, {scr_wdata[CVA6Cfg.XLEN-1:1], 1'b0}); end default: begin diff --git a/core/cva6.sv b/core/cva6.sv index 632aace06..6f6d10939 100644 --- a/core/cva6.sv +++ b/core/cva6.sv @@ -1,5 +1,6 @@ // Copyright 2017-2019 ETH Zurich and University of Bologna. // Copyright 2025 Bruno Sá and Zero-Day Labs. +// Copyright 2025 Capabilities Limited. // 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 @@ -30,7 +31,6 @@ module cva6 logic csr; rvfi_probes_instr_t instr; }, - parameter type rvfi_dii_inst_pack_t = `RVFI_DII_INSTR_T(CVA6Cfg), // branchpredict scoreboard entry // this is the struct which we will inject into the pipeline to guide the various @@ -66,6 +66,7 @@ module cva6 // I$ data requests localparam type icache_dreq_t = struct packed { logic req; // we request a new word + logic [CVA6Cfg.DIIIDLEN-1:0] dii_id; // next requested DII ID in instruction stream logic kill_s1; // kill the current request logic kill_s2; // kill the last request logic spec; // request is speculative @@ -78,6 +79,7 @@ module cva6 logic [CVA6Cfg.FETCH_WIDTH-1:0] data; // 2+ cycle out: tag logic [CVA6Cfg.FETCH_USER_WIDTH-1:0] user; // User bits logic [CVA6Cfg.VLEN-1:0] vaddr; // virtual address out + logic [CVA6Cfg.DIIIDLEN-1:0] dii_id; // First DII ID in the returned data exception_t ex; // we've encountered an exception }, @@ -85,6 +87,7 @@ module cva6 // store the decompressed instruction localparam type fetch_entry_t = struct packed { logic [CVA6Cfg.PCLEN-1:0] address; // the address of the instructions from below + logic [CVA6Cfg.DIIIDLEN-1:0] dii_id; // the DII ID of the instruction in the stream logic [31:0] instruction; // instruction word branchpredict_sbe_t branch_predict; // this field contains branch prediction information regarding the forward branch path exception_t ex; // this field contains exceptions which might have happened earlier, e.g.: fetch exceptions @@ -93,6 +96,7 @@ module cva6 // ID/EX/WB Stage localparam type scoreboard_entry_t = struct packed { logic [CVA6Cfg.PCLEN-1:0] pc; // PC of instruction + logic [CVA6Cfg.DIIIDLEN-1:0] dii_id; // DII ID of the instruction in the stream logic [CVA6Cfg.REGLEN-1:0] ddc; logic [CVA6Cfg.TRANS_ID_BITS-1:0] trans_id; // this can potentially be simplified, we could index the scoreboard entry // with the transaction id in any case make the width more generic @@ -130,6 +134,7 @@ module cva6 localparam type bp_resolve_t = struct packed { logic valid; // prediction with all its values is valid logic [CVA6Cfg.VLEN-1:0] pc; // PC of predict or mis-predict + logic [CVA6Cfg.DIIIDLEN-1:0] dii_id; // dii id of branch logic [CVA6Cfg.PCLEN-1:0] target_address; // target address at which to jump, or not logic is_mispredict; // set if this was a mis-predict logic is_taken; // branch is taken @@ -311,9 +316,6 @@ module cva6 input logic debug_req_i, // Probes to build RVFI, can be left open when not used - RVFI output rvfi_probes_t rvfi_probes_o, - input logic rvfi_dii_rtrn_vld_i, - input rvfi_dii_inst_pack_t rvfi_dii_inst_pack_i, - output logic rvfi_dii_data_ready_o, // CVXIF request - SUBSYSTEM output cvxif_req_t cvxif_req_o, // CVXIF response - SUBSYSTEM @@ -359,6 +361,7 @@ module cva6 exception_t ex_commit; // exception from commit stage bp_resolve_t resolved_branch; logic [ CVA6Cfg.PCLEN-1:0] pc_commit; + logic [ CVA6Cfg.DIIIDLEN-1:0] dii_id_commit; logic eret; logic [CVA6Cfg.NrCommitPorts-1:0] commit_ack; logic [CVA6Cfg.NrCommitPorts-1:0] commit_macro_ack; @@ -396,6 +399,7 @@ module cva6 fu_data_t fu_data_id_ex; logic [CVA6Cfg.PCLEN-1:0] pc_id_ex; + logic [CVA6Cfg.DIIIDLEN-1:0] dii_id_id_ex; logic is_compressed_instr_id_ex; logic [31:0] tinst_ex; // fixed latency units @@ -564,6 +568,7 @@ module cva6 logic flush_csr_ctrl; logic flush_unissued_instr_ctrl_id; logic flush_ctrl_if; + logic [CVA6Cfg.DIIIDLEN-1:0] flush_ctrl_dii_id_if; logic flush_ctrl_id; logic flush_ctrl_ex; logic flush_ctrl_bp; @@ -634,6 +639,7 @@ module cva6 .icache_dreq_o (icache_dreq_if_cache), .resolved_branch_i (resolved_branch), .pc_commit_i (pc_commit), + .dii_id_commit_i (dii_id_commit), .set_pc_commit_i (set_pc_ctrl_pcgen), .set_debug_pc_i (set_debug_pc), .epc_i (epc_commit_pcgen), @@ -785,6 +791,7 @@ module cva6 .rs2_forwarding_o (rs2_forwarding_id_ex), .fu_data_o (fu_data_id_ex), .pc_o (pc_id_ex), + .dii_id_o (dii_id_id_ex), .is_compressed_instr_o (is_compressed_instr_id_ex), .tinst_o (tinst_ex), // fixed latency unit ready @@ -866,6 +873,7 @@ module cva6 .rs2_forwarding_i(rs2_forwarding_id_ex), .fu_data_i(fu_data_id_ex), .pc_i(pc_id_ex), + .dii_id_i(dii_id_id_ex), .is_compressed_instr_i(is_compressed_instr_id_ex), .tinst_i(tinst_ex), // fixed latency units @@ -1015,6 +1023,7 @@ module cva6 .amo_resp_i (amo_resp), .commit_csr_o (csr_commit_commit_ex), .pc_o (pc_commit), + .dii_id_o (dii_id_commit), .csr_op_o (csr_op_commit_csr), .csr_wdata_o (csr_wdata_commit_csr), .csr_rdata_i (csr_rdata_csr_commit), @@ -1248,7 +1257,6 @@ module cva6 .dcache_req_i_t(dcache_req_i_t), .dcache_req_o_t(dcache_req_o_t), .exception_t (exception_t), - .rvfi_dii_inst_pack_t(rvfi_dii_inst_pack_t), .NumPorts (NumPorts), .noc_req_t (noc_req_t), .noc_resp_t(noc_resp_t) @@ -1284,10 +1292,7 @@ module cva6 .noc_resp_i (noc_resp_i), .inval_addr_i (inval_addr), .inval_valid_i (inval_valid), - .inval_ready_o (inval_ready), - .rvfi_dii_rtrn_vld_i (rvfi_dii_rtrn_vld_i), - .rvfi_dii_inst_pack_i (rvfi_dii_inst_pack_i), - .rvfi_dii_data_ready_o (rvfi_dii_data_ready_o) + .inval_ready_o (inval_ready) ); end else if (CVA6Cfg.DCacheType == config_pkg::HPDCACHE) begin : gen_cache_hpd cva6_hpdcache_subsystem #( diff --git a/core/cva6_rvfi.sv b/core/cva6_rvfi.sv index bd78cb203..3d70ba0f1 100644 --- a/core/cva6_rvfi.sv +++ b/core/cva6_rvfi.sv @@ -1,5 +1,6 @@ // Copyright 2024 Thales DIS France SAS // Copyright 2025 Bruno Sá and Zero-Day Labs. +// Copyright 2025 Capabilities Limited. // // Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -270,9 +271,11 @@ module cva6_rvfi always_ff @(posedge clk_i) begin for (int i = 0; i < CVA6Cfg.NrCommitPorts; i++) begin + logic [31:0] instr; logic exception; logic [4:0] rd_addr; logic [4:0] rs2_addr; + instr = mem_q[commit_pointer[i]].instr; exception = commit_instr_valid[i][0] && ex_commit_valid; rd_addr = commit_instr_rd[i][4:0]; rs2_addr = (is_amo_sc(commit_instr_op[i]) && wdata[i] == 1) ? '0 : commit_instr_rs2[i][4:0]; @@ -281,7 +284,7 @@ module cva6_rvfi ex_commit_cause == riscv::ENV_CALL_SMODE || ex_commit_cause == riscv::ENV_CALL_UMODE || ex_commit_cause == cva6_cheri_pkg::CAP_EXCEPTION)); - rvfi_instr_o[i].insn <= mem_q[commit_pointer[i]].instr; + rvfi_instr_o[i].insn <= instr; // when trap, the instruction is not executed rvfi_instr_o[i].trap <= exception; rvfi_instr_o[i].cause <= ex_commit_cause; @@ -294,12 +297,12 @@ module cva6_rvfi commit_instr_op[i] )) ? commit_instr_result[i] : wdata[i]; rvfi_instr_o[i].pc_rdata <= commit_instr_pc[i]; - if (mem_q[commit_pointer[i]].instr == 32'h30200073 && !exception) begin + if (instr == 32'h30200073 && !exception) begin rvfi_instr_o[i].pc_wdata <= csr.mepcc_q[63:0]; - end else if (mem_q[commit_pointer[i]].instr == 32'h10200073 && !exception) begin + end else if (instr == 32'h10200073 && !exception) begin rvfi_instr_o[i].pc_wdata <= csr.sepcc_q[63:0]; end else begin - rvfi_instr_o[i].pc_wdata <= (exception) ? {csr.mtcc_q[63:2], 2'b00} : (commit_instr_fu[i] == CTRL_FLOW) ? commit_instr_next_pc[i] : commit_instr_pc[i] + 4; + rvfi_instr_o[i].pc_wdata <= (exception) ? {csr.mtcc_q[63:2], 2'b00} : (commit_instr_fu[i] == CTRL_FLOW) ? commit_instr_next_pc[i] : commit_instr_pc[i] + (instr[1:0] == 2'b11 ? 4 : 2); end rvfi_instr_o[i].mem_addr <= mem_q[commit_pointer[i]].lsu_addr + ((commit_instr_op[i] == ariane_pkg::CLOAD_TAGS) ? 0 : 0); // So far, only write paddr is reported. TODO: read paddr diff --git a/core/decoder.sv b/core/decoder.sv index bb7a4786e..ebd8553c8 100644 --- a/core/decoder.sv +++ b/core/decoder.sv @@ -1,5 +1,6 @@ // Copyright 2018 ETH Zurich and University of Bologna. // Copyright 2025 Bruno Sá and Zero-Day Labs. +// Copyright 2025 Capabilities Limited. // 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 @@ -36,6 +37,7 @@ module decoder // PC from fetch stage - FRONTEND // TODO-cheri: make cheri optional input logic [CVA6Cfg.PCLEN-1:0] pc_i, + input logic [CVA6Cfg.DIIIDLEN-1:0] dii_id_i, // Is a compressed instruction - compressed_decoder input logic is_compressed_i, // Compressed form of instruction - FRONTEND @@ -191,6 +193,7 @@ module decoder instruction_o.use_zimm = 1'b0; instruction_o.bp = branch_predict_i; instruction_o.vfp = 1'b0; + if (CVA6Cfg.RVFI_DII) instruction_o.dii_id = dii_id_i; if (CVA6Cfg.CheriPresent) begin instruction_o.ddc = ddc_i; instruction_o.use_ddc = 1'b0; diff --git a/core/ex_stage.sv b/core/ex_stage.sv index c1d3999fd..e86943c16 100644 --- a/core/ex_stage.sv +++ b/core/ex_stage.sv @@ -1,6 +1,7 @@ // Copyright 2018 ETH Zurich and University of Bologna. // Copyright 2025 Bruno Sá and Zero-Day Labs. +// Copyright 2025 Capabilities Limited. // 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 @@ -47,6 +48,8 @@ module ex_stage input fu_data_t fu_data_i, // PC of the current instruction - ISSUE_STAGE input logic [CVA6Cfg.PCLEN-1:0] pc_i, + // DII ID of the current instruction - ISSUE_STAGE + input logic [CVA6Cfg.DIIIDLEN-1:0] dii_id_i, // DDC of the current instruction - ISSUE_STAGE input logic [CVA6Cfg.REGLEN-1:0] ddc_i, // Report whether isntruction is compressed - ISSUE_STAGE @@ -306,6 +309,7 @@ module ex_stage .debug_mode_i, .fu_data_i, .pc_i, + .dii_id_i, .is_compressed_instr_i, // any functional unit is valid, check that there is no accidental mis-predict .fu_valid_i ( alu_valid_i || lsu_valid_i || csr_valid_i || mult_valid_i || fpu_valid_i || acc_valid_i ) , diff --git a/core/frontend/frontend.sv b/core/frontend/frontend.sv index ad3058f58..2ff2c33a5 100644 --- a/core/frontend/frontend.sv +++ b/core/frontend/frontend.sv @@ -1,4 +1,5 @@ // Copyright 2018 ETH Zurich and University of Bologna. +// Copyright 2025 Capabilities Limited. // 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 @@ -42,6 +43,8 @@ module frontend input logic set_pc_commit_i, // COMMIT PC - COMMIT input logic [CVA6Cfg.PCLEN-1:0] pc_commit_i, + // COMMIT DII ID - COMMIT + input logic [CVA6Cfg.DIIIDLEN-1:0] dii_id_commit_i, // Exception event - COMMIT input logic ex_valid_i, // Mispredict event and next PC - EXECUTE @@ -95,6 +98,7 @@ module frontend logic icache_valid_q; ariane_pkg::frontend_exception_t icache_ex_valid_q; logic [ CVA6Cfg.VLEN-1:0] icache_vaddr_q; + logic [ CVA6Cfg.DIIIDLEN-1:0] icache_dii_id_q; logic [ CVA6Cfg.XLEN-1:0] icache_tval_q; logic [ CVA6Cfg.GPLEN-1:0] icache_gpaddr_q; logic [ 31:0] icache_tinst_q; @@ -107,17 +111,19 @@ module frontend // instruction fetch is ready logic if_ready; logic [CVA6Cfg.PCLEN-1:0] npc_d, npc_q; // next PC + logic [CVA6Cfg.DIIIDLEN-1:0] ndii_id_d, ndii_id_q; // indicates whether we come out of reset (then we need to load boot_addr_i) logic npc_rst_load_q; logic replay; logic [ CVA6Cfg.VLEN-1:0] replay_addr; + logic [ CVA6Cfg.DIIIDLEN-1:0] replay_dii_id; // shift amount logic [$clog2(CVA6Cfg.INSTR_PER_FETCH)-1:0] shamt; // address will always be 16 bit aligned, make this explicit here - if (CVA6Cfg.RVC && !CVA6Cfg.RVFI_DII) begin : gen_shamt + if (CVA6Cfg.RVC) begin : gen_shamt assign shamt = icache_dreq_i.vaddr[$clog2(CVA6Cfg.INSTR_PER_FETCH):1]; end else begin assign shamt = 1'b0; @@ -135,6 +141,7 @@ module frontend // re-aligned instruction and address (coming from cache - combinationally) logic [CVA6Cfg.INSTR_PER_FETCH-1:0][ 31:0] instr; logic [CVA6Cfg.INSTR_PER_FETCH-1:0][CVA6Cfg.VLEN-1:0] addr; + logic [CVA6Cfg.INSTR_PER_FETCH-1:0][CVA6Cfg.DIIIDLEN-1:0] dii_id; logic [CVA6Cfg.INSTR_PER_FETCH-1:0] instruction_valid; // BHT, BTB and RAS prediction bht_prediction_t [CVA6Cfg.INSTR_PER_FETCH-1:0] bht_prediction; @@ -151,6 +158,7 @@ module frontend // Instruction FIFO logic [ CVA6Cfg.VLEN-1:0] predict_address; + logic [ CVA6Cfg.DIIIDLEN-1:0] predict_dii_id; cf_t [CVA6Cfg.INSTR_PER_FETCH-1:0] cf_type; logic [CVA6Cfg.INSTR_PER_FETCH-1:0] taken_rvi_cf; logic [CVA6Cfg.INSTR_PER_FETCH-1:0] taken_rvc_cf; @@ -166,9 +174,11 @@ module frontend .valid_i (icache_valid_q), .serving_unaligned_o(serving_unaligned), .address_i (icache_vaddr_q), + .dii_id_i (icache_dii_id_q), .data_i (icache_data_q), .valid_o (instruction_valid), .addr_o (addr), + .dii_id_o (dii_id), .instr_o (instr) ); // -------------------- @@ -225,6 +235,7 @@ module frontend taken_rvi_cf = '0; taken_rvc_cf = '0; predict_address = '0; + if (CVA6Cfg.RVFI_DII) predict_dii_id = '0; for (int i = 0; i < CVA6Cfg.INSTR_PER_FETCH; i++) cf_type[i] = ariane_pkg::NoCF; @@ -244,6 +255,7 @@ module frontend ras_push = 1'b0; if (CVA6Cfg.BTBEntries && btb_prediction_shifted[i].valid) begin predict_address = btb_prediction_shifted[i].target_address; + if (CVA6Cfg.RVFI_DII) predict_dii_id = dii_id[i] + 1; cf_type[i] = ariane_pkg::JumpR; end end @@ -261,6 +273,7 @@ module frontend ras_pop = ras_predict.valid & instr_queue_consumed[i]; ras_push = 1'b0; predict_address = ras_predict.ra; + if (CVA6Cfg.RVFI_DII) predict_dii_id = dii_id[i] + 1; cf_type[i] = ariane_pkg::Return; end // branch prediction @@ -293,21 +306,20 @@ module frontend // calculate the jump target address if (taken_rvc_cf[i] || taken_rvi_cf[i]) begin predict_address = addr[i] + (taken_rvc_cf[i] ? rvc_imm[i] : rvi_imm[i]); + if (CVA6Cfg.RVFI_DII) predict_dii_id = dii_id[i] + 1; end end end // or reduce struct always_comb begin bp_valid = 1'b0; - //if (!CVA6Cfg.RVFI_DII) begin // BP cannot be valid if we have a return instruction and the RAS is not giving a valid address // Check that we encountered a control flow and that for a return the RAS // contains a valid prediction. for (int i = 0; i < CVA6Cfg.INSTR_PER_FETCH; i++) bp_valid |= ((cf_type[i] != NoCF & cf_type[i] != Return) | ((cf_type[i] == Return) & ras_predict.valid)); - //end end - assign is_mispredict = resolved_branch_i.valid & (resolved_branch_i.is_mispredict | CVA6Cfg.RVFI_DII); + assign is_mispredict = resolved_branch_i.valid & resolved_branch_i.is_mispredict; // Cache interface assign icache_dreq_o.req = instr_queue_ready; @@ -354,6 +366,7 @@ module frontend // Mis-predict handling is a little bit different // select PC a.k.a PC Gen logic [CVA6Cfg.VLEN-1:0] fetch_address; + logic [CVA6Cfg.DIIIDLEN-1:0] fetch_dii_id; always_comb begin : npc_select automatic cva6_cheri_pkg::cap_pcc_t debug_pcc; @@ -370,10 +383,18 @@ module frontend if (npc_rst_load_q) begin npc_d = boot_addr_i; fetch_address = boot_addr_i[CVA6Cfg.XLEN-1:0]; + if (CVA6Cfg.RVFI_DII) begin + ndii_id_d = test_dii_start(); + fetch_dii_id = test_dii_start(); + end end else begin fetch_address = npc_q[CVA6Cfg.VLEN-1:0]; // keep stable by default npc_d = npc_q; + if (CVA6Cfg.RVFI_DII) begin + fetch_dii_id = ndii_id_q; + ndii_id_d = ndii_id_q; + end end // 0. Branch Prediction if (bp_valid) begin @@ -382,6 +403,10 @@ module frontend npc_d = cva6_cheri_pkg::set_cap_pcc_cursor(npc_q, predict_address); else npc_d = predict_address; + if (CVA6Cfg.RVFI_DII) begin + fetch_dii_id = predict_dii_id; + ndii_id_d = predict_dii_id; + end end // 1. Default assignment if (if_ready) begin @@ -398,10 +423,12 @@ module frontend npc_d = cva6_cheri_pkg::set_cap_pcc_cursor(npc_q, replay_addr); else npc_d = replay_addr; + if (CVA6Cfg.RVFI_DII) ndii_id_d = replay_dii_id; end // 3. Control flow change request if (is_mispredict) begin npc_d = resolved_branch_i.target_address; + if (CVA6Cfg.RVFI_DII) ndii_id_d = resolved_branch_i.dii_id + 1; end // 4. Return from environment call if (eret_i) begin @@ -409,6 +436,7 @@ module frontend npc_d = cva6_cheri_pkg::cap_reg_to_cap_pcc(epc_i); else npc_d = epc_i; + if (CVA6Cfg.RVFI_DII) ndii_id_d = dii_id_commit_i + 1; end // 5. Exception/Interrupt if (ex_valid_i) begin @@ -416,6 +444,7 @@ module frontend npc_d = cva6_cheri_pkg::cap_reg_to_cap_pcc(trap_vector_base_i); else npc_d = trap_vector_base_i; + if (CVA6Cfg.RVFI_DII) ndii_id_d = dii_id_commit_i + 1; end // 6. Pipeline Flush because of CSR side effects // On a pipeline flush start fetching from the next address @@ -431,6 +460,7 @@ module frontend npc_d = cva6_cheri_pkg::set_cap_pcc_cursor(pc_commit_i, pc_commit_i + (halt_i ? '0 : {{CVA6Cfg.VLEN - 3{1'b0}}, 3'b100})); else npc_d = pc_commit_i + (halt_i ? '0 : {{CVA6Cfg.VLEN - 3{1'b0}}, 3'b100}); + if (CVA6Cfg.RVFI_DII) ndii_id_d = dii_id_commit_i + 1; end // 7. Debug // enter debug on a hard-coded base-address @@ -441,6 +471,7 @@ module frontend npc_d = CVA6Cfg.DmBaseAddress[CVA6Cfg.VLEN-1:0] + CVA6Cfg.HaltAddress[CVA6Cfg.VLEN-1:0]; end icache_dreq_o.vaddr = fetch_address; + if (CVA6Cfg.RVFI_DII) icache_dreq_o.dii_id = fetch_dii_id; if (CVA6Cfg.CheriPresent) begin icache_dreq_o.ex = cheri_ex; end @@ -453,8 +484,7 @@ always_comb begin : cheri_pcc_checks npcc = cva6_cheri_pkg::cap_pcc_t'(npc_q); - // TODO-cheri(ninolomata): fix this once we disable compressed instructions without trigering errors - min_instr_off = ((CVA6Cfg.RVC && !CVA6Cfg.RVFI_DII) ? {{CVA6Cfg.XLEN-2{1'b0}}, 2'h2} : {{CVA6Cfg.XLEN-3{1'b0}}, 3'h4}); + min_instr_off = ((CVA6Cfg.RVC) ? {{CVA6Cfg.XLEN-2{1'b0}}, 2'h2} : {{CVA6Cfg.XLEN-3{1'b0}}, 3'h4}); cheri_tval = {CVA6Cfg.XLEN{1'b0}}; cheri_ex.cause = cva6_cheri_pkg::CAP_EXCEPTION; @@ -498,10 +528,12 @@ end if (!rst_ni) begin npc_rst_load_q <= 1'b1; npc_q <= (CVA6Cfg.CheriPresent) ? cva6_cheri_pkg::PCC_ROOT_CAP : '0; + if (CVA6Cfg.RVFI_DII) ndii_id_q <= '0; speculative_q <= '0; icache_data_q <= '0; icache_valid_q <= 1'b0; icache_vaddr_q <= 'b0; + if (CVA6Cfg.RVFI_DII) icache_dii_id_q <= 'b0; icache_gpaddr_q <= 'b0; icache_tval_q <= 'b0; icache_tinst_q <= 'b0; @@ -512,11 +544,13 @@ end end else begin npc_rst_load_q <= 1'b0; npc_q <= npc_d; + if (CVA6Cfg.RVFI_DII) ndii_id_q <= ndii_id_d; speculative_q <= speculative_d; icache_valid_q <= icache_dreq_i.valid; if (icache_dreq_i.valid) begin icache_data_q <= icache_data; icache_vaddr_q <= icache_dreq_i.vaddr; + if (CVA6Cfg.RVFI_DII) icache_dii_id_q <= icache_dreq_i.dii_id; icache_tval_q <= icache_dreq_i.ex.tval; if (CVA6Cfg.RVH) begin icache_gpaddr_q <= icache_dreq_i.ex.tval2[CVA6Cfg.GPLEN-1:0]; @@ -639,6 +673,7 @@ end .flush_i (flush_i), .instr_i (instr), // from re-aligner .addr_i (addr), // from re-aligner + .dii_id_i (dii_id), .pc_i(npc_q), .exception_i (icache_ex_valid_q), // from I$ .exception_addr_i (icache_vaddr_q), @@ -653,6 +688,7 @@ end .ready_o (instr_queue_ready), .replay_o (replay), .replay_addr_o (replay_addr), + .replay_dii_id_o (replay_dii_id), .fetch_entry_o (fetch_entry_o), // to back-end .fetch_entry_valid_o(fetch_entry_valid_o), // to back-end .fetch_entry_ready_i(fetch_entry_ready_i) // to back-end diff --git a/core/frontend/instr_queue.sv b/core/frontend/instr_queue.sv index d9559aade..53f80d0ae 100644 --- a/core/frontend/instr_queue.sv +++ b/core/frontend/instr_queue.sv @@ -1,4 +1,5 @@ // Copyright 2018 - 2019 ETH Zurich and University of Bologna. +// Copyright 2025 Capabilities Limited. // 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 @@ -59,6 +60,8 @@ module instr_queue input logic [CVA6Cfg.INSTR_PER_FETCH-1:0][31:0] instr_i, // Instruction address - instr_realign input logic [CVA6Cfg.INSTR_PER_FETCH-1:0][CVA6Cfg.VLEN-1:0] addr_i, + // Instruction DII ID - instr_realign + input logic [CVA6Cfg.INSTR_PER_FETCH-1:0][CVA6Cfg.DIIIDLEN-1:0] dii_id_i, // Instruction Capability - instr_realign input logic [CVA6Cfg.PCLEN-1:0] pc_i, // Instruction is valid - instr_realign @@ -83,6 +86,8 @@ module instr_queue output logic replay_o, // Address at which to replay the fetch - FRONTEND output logic [CVA6Cfg.VLEN-1:0] replay_addr_o, + // DII ID to restart stream from - FRONTEND + output logic [CVA6Cfg.DIIIDLEN-1:0] replay_dii_id_o, // Handshake’s data with ID_STAGE - ID_STAGE output fetch_entry_t [ariane_pkg::SUPERSCALAR:0] fetch_entry_o, // Handshake’s valid with ID_STAGE - ID_STAGE @@ -96,6 +101,7 @@ module instr_queue typedef struct packed { logic [31:0] instr; // instruction word + logic [CVA6Cfg.DIIIDLEN-1:0] dii_id; // instruction DII ID ariane_pkg::cf_t cf; // branch was taken ariane_pkg::frontend_exception_t ex; // exception happened logic [CVA6Cfg.VLEN-1:0] ex_vaddr; // lower VLEN bits of tval for exception @@ -152,6 +158,7 @@ ariane_pkg::FETCH_FIFO_DEPTH logic [CVA6Cfg.INSTR_PER_FETCH*2-1:0] fifo_pos_extended; logic [CVA6Cfg.INSTR_PER_FETCH-1:0] fifo_pos; logic [CVA6Cfg.INSTR_PER_FETCH*2-1:0][31:0] instr; + logic [CVA6Cfg.INSTR_PER_FETCH*2-1:0][CVA6Cfg.DIIIDLEN-1:0] dii_id; ariane_pkg::cf_t [CVA6Cfg.INSTR_PER_FETCH*2-1:0] cf; // replay interface logic [CVA6Cfg.INSTR_PER_FETCH-1:0] instr_overflow_fifo; @@ -218,6 +225,10 @@ ariane_pkg::FETCH_FIFO_DEPTH assign instr[i+CVA6Cfg.INSTR_PER_FETCH] = instr_i[i]; assign cf[i] = cf_type_i[i]; assign cf[i+CVA6Cfg.INSTR_PER_FETCH] = cf_type_i[i]; + if (CVA6Cfg.RVFI_DII) begin + assign dii_id[i] = dii_id_i[i]; + assign dii_id[i+CVA6Cfg.INSTR_PER_FETCH] = dii_id_i[i]; + end end // shift the inputs @@ -237,6 +248,7 @@ ariane_pkg::FETCH_FIFO_DEPTH assign instr_data_in[i].ex_tinst = '0; assign instr_data_in[i].ex_gva = 1'b0; end + if (CVA6Cfg.RVFI_DII) assign instr_data_in[i].dii_id = dii_id[CVA6Cfg.INSTR_PER_FETCH+i-idx_is_q]; /* verilator lint_on WIDTH */ end end else begin : gen_multiple_instr_per_fetch_without_C @@ -250,6 +262,7 @@ ariane_pkg::FETCH_FIFO_DEPTH assign fifo_pos_extended = '0; assign fifo_pos = '0; assign instr = '0; + if (CVA6Cfg.RVFI_DII) assign dii_id = '0; assign popcount = '0; assign shamt = '0; assign valid = '0; @@ -263,6 +276,7 @@ ariane_pkg::FETCH_FIFO_DEPTH /* verilator lint_off WIDTH */ assign instr_data_in[0].instr = instr_i[0]; + if (CVA6Cfg.RVFI_DII) assign instr_data_in[0].dii_id = dii_id_i[0]; assign instr_data_in[0].cf = cf_type_i[0]; assign instr_data_in[0].ex = exception_i; // exceptions hold for the whole fetch packet assign instr_data_in[0].ex_vaddr = exception_addr_i; @@ -302,8 +316,10 @@ ariane_pkg::FETCH_FIFO_DEPTH // if we successfully pushed some instructions we can output the next instruction // which we didn't manage to push assign replay_addr_o = (address_overflow) ? addr_i[0] : addr_i[shamt]; + if (CVA6Cfg.RVFI_DII) assign replay_dii_id_o = (address_overflow) ? dii_id_i[0] : dii_id_i[shamt]; end else begin : gen_replay_addr_o_without_C assign replay_addr_o = addr_i[0]; + if (CVA6Cfg.RVFI_DII) assign replay_dii_id_o = dii_id_i[0]; end // ---------------------- @@ -335,6 +351,7 @@ ariane_pkg::FETCH_FIFO_DEPTH // assemble fetch entry for (int unsigned i = 0; i <= ariane_pkg::SUPERSCALAR; i++) begin fetch_entry_o[i].instruction = '0; + if (CVA6Cfg.RVFI_DII) fetch_entry_o[i].dii_id = '0; fetch_entry_o[i].address = pc_j[i]; fetch_entry_o[i].ex.valid = 1'b0; fetch_entry_o[i].ex.cause = '0; @@ -361,11 +378,12 @@ ariane_pkg::FETCH_FIFO_DEPTH fetch_entry_o[0].ex.cause = riscv::INSTR_PAGE_FAULT; end fetch_entry_o[0].instruction = instr_data_out[i].instr; + if (CVA6Cfg.RVFI_DII) fetch_entry_o[0].dii_id = instr_data_out[i].dii_id; fetch_entry_o[0].ex.valid = instr_data_out[i].ex != ariane_pkg::FE_NONE; if (CVA6Cfg.TvalEn) begin if (CVA6Cfg.CheriPresent && instr_data_out[i].ex == ariane_pkg::FE_INSTR_CHERI_FAULT) begin fetch_entry_o[0].ex.tval = instr_data_out[i].ex_tval; - end else begin + end else begin fetch_entry_o[0].ex.tval = { {(CVA6Cfg.XLEN - CVA6Cfg.VLEN) {1'b0}}, instr_data_out[i].ex_vaddr }; @@ -390,11 +408,12 @@ ariane_pkg::FETCH_FIFO_DEPTH fetch_entry_o[NID].ex.cause = riscv::INSTR_PAGE_FAULT; end fetch_entry_o[NID].instruction = instr_data_out[i].instr; + if (CVA6Cfg.RVFI_DII) fetch_entry_o[NID].dii_id = instr_data_out[i].dii_id; fetch_entry_o[NID].ex.valid = instr_data_out[i].ex != ariane_pkg::FE_NONE; if (CVA6Cfg.TvalEn) begin if (CVA6Cfg.CheriPresent && instr_data_out[i].ex == ariane_pkg::FE_INSTR_CHERI_FAULT) begin fetch_entry_o[NID].ex.tval = instr_data_out[i].ex_tval; - end else begin + end else begin fetch_entry_o[NID].ex.tval = { {{64 - riscv::VLEN{1'b0}}, instr_data_out[i].ex_vaddr} }; @@ -420,6 +439,7 @@ ariane_pkg::FETCH_FIFO_DEPTH idx_ds_d = '0; idx_is_d = '0; fetch_entry_o[0].instruction = instr_data_out[0].instr; + if (CVA6Cfg.RVFI_DII) fetch_entry_o[0].dii_id = instr_data_out[0].dii_id; fetch_entry_o[0].address = pc_q; fetch_entry_o[0].ex.valid = instr_data_out[0].ex != ariane_pkg::FE_NONE; @@ -433,7 +453,7 @@ ariane_pkg::FETCH_FIFO_DEPTH if (CVA6Cfg.TvalEn) begin if (CVA6Cfg.CheriPresent && instr_data_out[0].ex == ariane_pkg::FE_INSTR_CHERI_FAULT) begin fetch_entry_o[0].ex.tval = instr_data_out[0].ex_tval; - end else begin + end else begin fetch_entry_o[0].ex.tval = { {{64 - CVA6Cfg.VLEN{1'b0}}, instr_data_out[0].ex_vaddr} }; @@ -470,7 +490,7 @@ ariane_pkg::FETCH_FIFO_DEPTH for (genvar i = 0; i <= ariane_pkg::SUPERSCALAR; i++) begin if (CVA6Cfg.CheriPresent) begin assign pc_j[i+1] = fetch_entry_is_cf[i] ? cva6_cheri_pkg::set_cap_pcc_cursor(pc_j[i], address_out) : cva6_cheri_pkg::set_cap_pcc_cursor(pc_j[i], pc_j[i][CVA6Cfg.XLEN-1:0] + ((fetch_entry_o[i].instruction[1:0] != 2'b11) ? 'd2 : 'd4)); - end else begin + end else begin assign pc_j[i+1] = fetch_entry_is_cf[i] ? address_out : ( pc_j[i] + ((fetch_entry_o[i].instruction[1:0] != 2'b11) ? 'd2 : 'd4) ); diff --git a/core/id_stage.sv b/core/id_stage.sv index 13db62593..21234a4f2 100644 --- a/core/id_stage.sv +++ b/core/id_stage.sv @@ -1,4 +1,5 @@ // Copyright 2018 ETH Zurich and University of Bologna. +// Copyright 2025 Capabilities Limited. // 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 @@ -186,6 +187,7 @@ module id_stage #( .irq_ctrl_i, .irq_i, .pc_i (fetch_entry_i[i].address), + .dii_id_i (fetch_entry_i[i].dii_id), .ddc_i (ddc_i), .is_compressed_i (is_compressed_cmp[i]), .is_macro_instr_i (is_macro_instr_i[i]), diff --git a/core/include/build_config_pkg.sv b/core/include/build_config_pkg.sv index 5560001f5..87cd445bb 100644 --- a/core/include/build_config_pkg.sv +++ b/core/include/build_config_pkg.sv @@ -141,6 +141,7 @@ package build_config_pkg; cfg.CheriCapTagWidth = CVA6Cfg.CheriCapTagWidth; cfg.RVFI_DII = bit'(CVA6Cfg.RVFI_DII); + cfg.DIIIDLEN = CVA6Cfg.DIIIDLEN; cfg.DATA_USER_EN = CVA6Cfg.DataUserEn; cfg.WtDcacheWbufDepth = CVA6Cfg.WtDcacheWbufDepth; diff --git a/core/include/config_pkg.sv b/core/include/config_pkg.sv index 642047a6d..8176c7cf4 100644 --- a/core/include/config_pkg.sv +++ b/core/include/config_pkg.sv @@ -196,6 +196,8 @@ package config_pkg; int unsigned CheriCapTagWidth; // Enable RVDI_DII interface int unsigned RVFI_DII; + // DII ID Length + int unsigned DIIIDLEN; } cva6_user_cfg_t; typedef struct packed { @@ -332,6 +334,7 @@ package config_pkg; int unsigned CheriCapTagWidth; bit RVFI_DII; + int unsigned DIIIDLEN; int unsigned ModeW; int unsigned ASIDW; diff --git a/core/include/cv64a6_imafdch_sv39_rvfi_dii_config_pkg.sv b/core/include/cv64a6_imafdch_sv39_rvfi_dii_config_pkg.sv index 08f22eed6..3da7c73bf 100644 --- a/core/include/cv64a6_imafdch_sv39_rvfi_dii_config_pkg.sv +++ b/core/include/cv64a6_imafdch_sv39_rvfi_dii_config_pkg.sv @@ -30,6 +30,7 @@ package cva6_config_pkg; localparam CVA6ConfigCheriCapTagWidth = 1; localparam CVA6ConfigRVFI_DII = 1; + localparam CVA6ConfigDIIIDLEN = 6; localparam CVA6ConfigAxiIdWidth = 4; localparam CVA6ConfigAxiAddrWidth = 64; @@ -152,7 +153,8 @@ package cva6_config_pkg; NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs), DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth), CheriCapTagWidth : int'(CVA6ConfigCheriCapTagWidth), - RVFI_DII : int'(CVA6ConfigRVFI_DII) + RVFI_DII : int'(CVA6ConfigRVFI_DII), + DIIIDLEN : int'(CVA6ConfigDIIIDLEN) }; endpackage diff --git a/core/include/cv64a6_imafdchzcheri_sv39_config_pkg.sv b/core/include/cv64a6_imafdchzcheri_sv39_config_pkg.sv index bca40bb2a..73fce0e27 100644 --- a/core/include/cv64a6_imafdchzcheri_sv39_config_pkg.sv +++ b/core/include/cv64a6_imafdchzcheri_sv39_config_pkg.sv @@ -32,6 +32,7 @@ package cva6_config_pkg; localparam CVA6ConfigCheriCapTagWidth = 1; localparam CVA6ConfigRVFI_DII = 0; + localparam CVA6ConfigDIIIDLEN = 0; localparam CVA6ConfigAxiIdWidth = 4; localparam CVA6ConfigAxiAddrWidth = 64; @@ -154,7 +155,8 @@ package cva6_config_pkg; NrStorePipeRegs: int'(CVA6ConfigNrStorePipeRegs), DcacheIdWidth: int'(CVA6ConfigDcacheIdWidth), CheriCapTagWidth : int'(CVA6ConfigCheriCapTagWidth), - RVFI_DII : int'(CVA6ConfigRVFI_DII) + RVFI_DII : int'(CVA6ConfigRVFI_DII), + DIIIDLEN : int'(CVA6ConfigDIIIDLEN) }; endpackage diff --git a/core/include/rvfi_types.svh b/core/include/rvfi_types.svh index d9619130d..a0fddd121 100644 --- a/core/include/rvfi_types.svh +++ b/core/include/rvfi_types.svh @@ -28,13 +28,6 @@ logic [config_pkg::NRET*Cfg.CLEN-1:0] mem_wdata; \ } -`define RVFI_DII_INSTR_T(Cfg) struct packed { \ - logic [config_pkg::NRET*7:0] padding; \ - logic [config_pkg::NRET*7:0] rvfi_cmd; \ - logic [config_pkg::NRET*15:0] rvfi_time; \ - logic [config_pkg::NRET*31:0] rvfi_insn; \ -} - `define RVFI_CSR_ELMT_T(Cfg) struct packed { \ logic [Cfg.REGLEN-1:0] rdata; \ logic [Cfg.REGLEN-1:0] rmask; \ diff --git a/core/instr_realign.sv b/core/instr_realign.sv index 85d6d4f1c..cde054d7a 100644 --- a/core/instr_realign.sv +++ b/core/instr_realign.sv @@ -1,4 +1,5 @@ // Copyright 2018 - 2019 ETH Zurich and University of Bologna. +// Copyright 2025 Capabilities Limited. // 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 @@ -36,12 +37,16 @@ module instr_realign output logic serving_unaligned_o, // 32-bit block address - CACHE input logic [CVA6Cfg.VLEN-1:0] address_i, + // DII ID of requested instruction in block - CACHE + input logic [CVA6Cfg.DIIIDLEN-1:0] dii_id_i, // 32-bit block - CACHE input logic [CVA6Cfg.FETCH_WIDTH-1:0] data_i, // instruction is valid - FRONTEND output logic [CVA6Cfg.INSTR_PER_FETCH-1:0] valid_o, // Instruction address - FRONTEND output logic [CVA6Cfg.INSTR_PER_FETCH-1:0][CVA6Cfg.VLEN-1:0] addr_o, + // Instruction DII ID - FRONTEND + output logic [CVA6Cfg.INSTR_PER_FETCH-1:0][CVA6Cfg.DIIIDLEN-1:0] dii_id_o, // Instruction - instr_scan&instr_queue output logic [CVA6Cfg.INSTR_PER_FETCH-1:0][31:0] instr_o ); @@ -59,6 +64,7 @@ module instr_realign logic unaligned_d, unaligned_q; // register to save the unaligned address logic [CVA6Cfg.VLEN-1:0] unaligned_address_d, unaligned_address_q; + logic [CVA6Cfg.DIIIDLEN-1:0] unaligned_dii_id_d, unaligned_dii_id_q; // we have an unaligned instruction assign serving_unaligned_o = unaligned_q; @@ -72,10 +78,15 @@ module instr_realign valid_o[0] = valid_i; instr_o[0] = unaligned_q ? {data_i[15:0], unaligned_instr_q} : data_i[31:0]; addr_o[0] = unaligned_q ? unaligned_address_q : address_i; + if (CVA6Cfg.RVFI_DII) dii_id_o[0] = unaligned_q ? unaligned_dii_id_q : dii_id_i; valid_o[1] = 1'b0; instr_o[1] = '0; addr_o[1] = {address_i[CVA6Cfg.VLEN-1:2], 2'b10}; + if (CVA6Cfg.RVFI_DII) begin + dii_id_o[1] = dii_id_o[0] + 1; + unaligned_dii_id_d = dii_id_o[1]; + end // this instruction is compressed or the last instruction was unaligned if (instr_is_compressed[0] || unaligned_q) begin @@ -106,6 +117,7 @@ module instr_realign unaligned_d = 1'b1; unaligned_address_d = {address_i[CVA6Cfg.VLEN-1:2], 2'b10}; unaligned_instr_d = data_i[15:0]; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_d = dii_id_o[0]; // the instruction isn't compressed but only the lower is ready end else begin valid_o = {{CVA6Cfg.INSTR_PER_FETCH - 1{1'b0}}, 1'b1}; @@ -121,6 +133,7 @@ module instr_realign valid_o = '0; instr_o[0] = '0; addr_o[0] = '0; + if (CVA6Cfg.RVFI_DII) dii_id_o[0] = '0; instr_o[1] = '0; addr_o[1] = '0; instr_o[2] = '0; @@ -128,6 +141,13 @@ module instr_realign instr_o[3] = {16'b0, data_i[63:48]}; addr_o[3] = {address_i[riscv::VLEN-1:3], 3'b110}; + if (CVA6Cfg.RVFI_DII) begin + dii_id_o[0] = unaligned_q ? unaligned_dii_id_q : dii_id_i; + dii_id_o[1] = dii_id_o[0] + 1; + dii_id_o[2] = dii_id_o[0] + 2; + dii_id_o[3] = dii_id_o[0] + 3; + end + case (address_i[2:1]) 2'b00: begin valid_o[0] = valid_i; @@ -166,6 +186,7 @@ module instr_realign end else begin unaligned_instr_d = instr_o[3]; unaligned_address_d = addr_o[3]; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_d = dii_id_o[3]; end end else begin unaligned_d = 1'b0; @@ -180,11 +201,13 @@ module instr_realign end else begin unaligned_instr_d = instr_o[3]; unaligned_address_d = addr_o[3]; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_d = dii_id_o[3]; end end end else begin instr_o[0] = data_i[31:0]; addr_o[0] = address_i; + if (CVA6Cfg.RVFI_DII) dii_id_o[0] = dii_id_i; if (instr_is_compressed[0]) begin instr_o[1] = data_i[47:16]; @@ -209,6 +232,7 @@ module instr_realign unaligned_d = 1'b1; unaligned_instr_d = instr_o[3]; unaligned_address_d = addr_o[3]; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_d = dii_id_o[3]; end end end else begin @@ -221,6 +245,7 @@ module instr_realign unaligned_d = 1'b1; unaligned_instr_d = instr_o[3]; unaligned_address_d = addr_o[3]; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_d = dii_id_o[3]; end end end else begin @@ -242,6 +267,7 @@ module instr_realign unaligned_d = 1'b1; unaligned_instr_d = instr_o[3]; unaligned_address_d = addr_o[3]; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_d = dii_id_o[3]; end end end @@ -279,6 +305,7 @@ module instr_realign unaligned_d = 1'b1; unaligned_instr_d = instr_o[2]; unaligned_address_d = addr_o[2]; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_d = dii_id_o[2]; end end end else begin @@ -291,6 +318,7 @@ module instr_realign unaligned_d = 1'b1; unaligned_instr_d = instr_o[2]; unaligned_address_d = addr_o[2]; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_d = dii_id_o[2]; end end end @@ -316,6 +344,7 @@ module instr_realign unaligned_d = 1'b1; unaligned_instr_d = instr_o[1]; unaligned_address_d = addr_o[1]; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_d = dii_id_o[1]; end end end @@ -337,6 +366,7 @@ module instr_realign unaligned_d = 1'b1; unaligned_instr_d = instr_o[0]; unaligned_address_d = addr_o[0]; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_d = dii_id_o[0]; end end endcase @@ -348,9 +378,11 @@ module instr_realign unaligned_q <= 1'b0; unaligned_address_q <= '0; unaligned_instr_q <= '0; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_q <= '0; end else begin if (valid_i) begin unaligned_address_q <= unaligned_address_d; + if (CVA6Cfg.RVFI_DII) unaligned_dii_id_q <= unaligned_dii_id_d; unaligned_instr_q <= unaligned_instr_d; end diff --git a/core/issue_read_operands.sv b/core/issue_read_operands.sv index 5589c1f29..9f5e23ca5 100644 --- a/core/issue_read_operands.sv +++ b/core/issue_read_operands.sv @@ -1,5 +1,6 @@ // Copyright 2018 ETH Zurich and University of Bologna. // Copyright 2025 Bruno Sá and Zero-Day Labs. +// Copyright 2025 Capabilities Limited. // 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 @@ -71,6 +72,8 @@ module issue_read_operands output logic [CVA6Cfg.REGLEN-1:0] rs2_forwarding_o, // Instruction pc - TO_BE_COMPLETED output logic [CVA6Cfg.PCLEN-1:0] pc_o, + // Instruction DII ID - TO_BE_COMPLETED + output logic [CVA6Cfg.DIIIDLEN-1:0] dii_id_o, // Is compressed instruction - TO_BE_COMPLETED output logic is_compressed_instr_o, // Fixed Latency Unit ready to accept new request - TO_BE_COMPLETED @@ -656,6 +659,7 @@ module issue_read_operands pc_o <= '0; is_compressed_instr_o <= 1'b0; branch_predict_o <= {cf_t'(0), {CVA6Cfg.VLEN{1'b0}}}; + if (CVA6Cfg.RVFI_DII) dii_id_o <= '0; end else begin operand_a_q <= operand_a_n; operand_b_q <= operand_b_n; @@ -674,6 +678,7 @@ module issue_read_operands pc_o <= issue_instr_i.pc; is_compressed_instr_o <= issue_instr_i.is_compressed; branch_predict_o <= issue_instr_i.bp; + if (CVA6Cfg.RVFI_DII) dii_id_o <= issue_instr_i.dii_id; end end diff --git a/core/issue_stage.sv b/core/issue_stage.sv index 7b492cdf0..d0081da52 100644 --- a/core/issue_stage.sv +++ b/core/issue_stage.sv @@ -1,4 +1,5 @@ // Copyright 2018 ETH Zurich and University of Bologna. +// Copyright 2025 Capabilities Limited. // 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 @@ -54,6 +55,8 @@ module issue_stage output fu_data_t fu_data_o, // Program Counter - EX_STAGE output logic [CVA6Cfg.PCLEN-1:0] pc_o, + // DII ID - EX_STAGE + output logic [CVA6Cfg.DIIIDLEN-1:0] dii_id_o, // Is compressed instruction - EX_STAGE output logic is_compressed_instr_o, // Transformed trap instruction - EX_STAGE diff --git a/core/load_unit.sv b/core/load_unit.sv index 9421ff926..f085d9dbf 100644 --- a/core/load_unit.sv +++ b/core/load_unit.sv @@ -1,5 +1,6 @@ // Copyright 2018 ETH Zurich and University of Bologna. // Copyright 2025 Bruno Sá and Zero-Day Labs. +// Copyright 2025 Capabilities Limited. // 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 diff --git a/core/rvfi_dii_generator.sv b/core/rvfi_dii_generator.sv index 3ec1fa1b6..3f9fd1f23 100644 --- a/core/rvfi_dii_generator.sv +++ b/core/rvfi_dii_generator.sv @@ -1,5 +1,6 @@ // Copyright 2025 Bruno Sá and Zero-Day Labs. +// Copyright 2025 Capabilities Limited. // 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 @@ -14,6 +15,11 @@ // // Date: 01.01.2025 // Description: CVA6 RVFI DII Generator +// + +import "DPI-C" function byte get_dii_cmd(int idx); +import "DPI-C" function int get_dii_insn(int idx); +import "DPI-C" function int test_dii_start(); `include "common_cells/registers.svh" @@ -24,54 +30,88 @@ module rvfi_dii_generator parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty, parameter type icache_dreq_t = logic, parameter type icache_drsp_t = logic, - parameter type exception_t = logic, - parameter type rvfi_dii_inst_pack_t = logic + parameter type exception_t = logic ) ( input logic clk_i, input logic rst_ni, // data requests input icache_dreq_t dreq_i, - output icache_drsp_t dreq_o, - // refill port from Vengine - input logic rvfi_dii_rtrn_vld_i, - input rvfi_dii_inst_pack_t rvfi_dii_inst_pack_i, - output logic rvfi_dii_data_ready_o + output icache_drsp_t dreq_o ); - logic [CVA6Cfg.VLEN-1:0] vaddr_d, vaddr_q; - exception_t ex_d, ex_q; - logic busy_q, busy_d; - assign vaddr_d = (~busy_q & dreq_i.req) ? dreq_i.vaddr : vaddr_q; - assign ex_d = (~busy_q & dreq_i.req) ? dreq_i.ex : ex_q; + logic [CVA6Cfg.FETCH_ALIGN_BITS:0] fetch_offset_q, fetch_offset_d; + logic [CVA6Cfg.FETCH_WIDTH*2-1:0] fetch_buff_q, fetch_buff_d; + logic [CVA6Cfg.DIIIDLEN-1:0] dii_id_q, dii_id_d; + logic busy; + logic flushing; + logic [CVA6Cfg.VLEN-1:0] vaddr_buff; + exception_t ex_buff; - always_comb begin : inject_instr - dreq_o.ex = ex_q; - dreq_o.vaddr = vaddr_q; - dreq_o.valid = 1'b0; - dreq_o.ready = 1'b0; - dreq_o.data = rvfi_dii_inst_pack_i.rvfi_insn; - rvfi_dii_data_ready_o = 1'b0; - busy_d = busy_q; - if (busy_q) begin - rvfi_dii_data_ready_o = 1'b1; - if (rvfi_dii_rtrn_vld_i) begin - busy_d = 1'b0; - dreq_o.valid = 1'b1; - end - // check for errors - if ((dreq_i.kill_s1 || dreq_i.kill_s2) && !ex_q.valid) begin - busy_d = 1'b0; - rvfi_dii_data_ready_o = 1'b0; - dreq_o.valid = 1'b0; + logic [CVA6Cfg.FETCH_WIDTH*2-1:0] instr; // Wider than needed to be shifted in + logic [2:0] instr_bytes; + logic test_done; + always_comb begin + dii_id_d = dii_id_q; + fetch_offset_d = fetch_offset_q; + fetch_buff_d = fetch_buff_q; + instr = '0; + instr_bytes = '0; + test_done = '0; + if (busy && !dreq_i.kill_s2) begin + // Assume the pipeline consumed the full buffer + fetch_offset_d = {1'b0, fetch_offset_d[CVA6Cfg.FETCH_ALIGN_BITS-1:0]}; + fetch_buff_d = fetch_buff_d >> CVA6Cfg.FETCH_WIDTH; + // Shift the rest of the buffer into the requested slot + fetch_offset_d = fetch_offset_d + vaddr_buff[CVA6Cfg.FETCH_ALIGN_BITS-1:0]; + fetch_buff_d = fetch_buff_d << {vaddr_buff[CVA6Cfg.FETCH_ALIGN_BITS-1:0], 3'b0}; + while (~fetch_offset_d[CVA6Cfg.FETCH_ALIGN_BITS] & (~fetch_offset_d[CVA6Cfg.FETCH_ALIGN_BITS-1:0] != 0)) begin + test_done = get_dii_cmd(dii_id_d) == 0; + instr = test_done ? 32'h13 : get_dii_insn(dii_id_d); + instr_bytes = instr[1:0] == 2'b11 ? 3'd4 : 3'd2; + fetch_buff_d = fetch_buff_d | (instr << ({fetch_offset_d, 3'b0})); + fetch_offset_d = fetch_offset_d + instr_bytes; + dii_id_d = dii_id_d + (test_done ? 0 : 1); end + dreq_o.valid = 1'b1; end else begin - dreq_o.ready = 1'b1; - if (dreq_i.req && !dreq_i.kill_s1 && !dreq_i.kill_s2) - busy_d = 1'b1; + dreq_o.valid = 1'b0; end + dreq_o.ex = ex_buff; + dreq_o.vaddr = vaddr_buff; + dreq_o.data = fetch_buff_d; + dreq_o.user = '0; + dreq_o.ready = !dreq_i.kill_s1 && !dreq_i.kill_s2 && dreq_i.req; + dreq_o.dii_id = dii_id_q; end - `FFLARN(vaddr_q, vaddr_d, '1, '0, clk_i, rst_ni) - `FFLARN(ex_q, ex_d, '1, '0, clk_i, rst_ni) - `FFLARN(busy_q, busy_d, '1, '0, clk_i, rst_ni) - + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + dii_id_q <= test_dii_start(); + fetch_buff_q <= '0; + fetch_offset_q <= '0; + flushing <= '0; + busy <= '0; + end else begin + if (dreq_i.kill_s1 || dreq_i.kill_s2) begin + fetch_buff_q <= '0; + fetch_offset_q <= '0; + flushing <= 1; + busy <= '0; + end else begin + dii_id_q <= dii_id_d; + fetch_buff_q <= fetch_buff_d; + fetch_offset_q <= fetch_offset_d; + if (dreq_i.req) begin + busy <= 1; + vaddr_buff <= dreq_i.vaddr; + ex_buff <= dreq_i.ex; + if (flushing) begin + dii_id_q <= dreq_i.dii_id; + end + flushing <= 0; + end else begin + busy <= 0; + end + end + end + end endmodule diff --git a/corev_apu/fpga/src/ariane_xilinx.sv b/corev_apu/fpga/src/ariane_xilinx.sv index 05f2609f2..599c72048 100644 --- a/corev_apu/fpga/src/ariane_xilinx.sv +++ b/corev_apu/fpga/src/ariane_xilinx.sv @@ -786,9 +786,6 @@ ariane #( .ipi_i ( ipi ), .time_irq_i ( timer_irq ), .rvfi_probes_o( /* open */ ), - .rvfi_dii_rtrn_vld_i ('0), - .rvfi_dii_inst_pack_i ('0), - .rvfi_dii_data_ready_o (/* open */ ), .debug_req_i ( debug_req_irq ), .noc_req_o ( axi_ariane_req ), .noc_resp_i ( axi_ariane_resp ) diff --git a/corev_apu/src/ariane.sv b/corev_apu/src/ariane.sv index 37085ecce..9ccf9f930 100644 --- a/corev_apu/src/ariane.sv +++ b/corev_apu/src/ariane.sv @@ -21,7 +21,6 @@ module ariane import ariane_pkg::*; #( logic csr; logic instr; }, - parameter type rvfi_dii_inst_pack_t = logic, parameter int unsigned AxiAddrWidth = ariane_axi::AddrWidth, parameter int unsigned AxiDataWidth = ariane_axi::DataWidth, parameter int unsigned AxiIdWidth = ariane_axi::IdWidth, @@ -46,9 +45,6 @@ module ariane import ariane_pkg::*; #( // RISC-V formal interface port (`rvfi`): // Can be left open when formal tracing is not needed. output rvfi_probes_t rvfi_probes_o, - input logic rvfi_dii_rtrn_vld_i, - input rvfi_dii_inst_pack_t rvfi_dii_inst_pack_i, - output logic rvfi_dii_data_ready_o, // memory side output noc_req_t noc_req_o, input noc_resp_t noc_resp_i @@ -77,9 +73,6 @@ module ariane import ariane_pkg::*; #( .time_irq_i ( time_irq_i ), .debug_req_i ( debug_req_i ), .rvfi_probes_o ( rvfi_probes_o ), - .rvfi_dii_rtrn_vld_i (rvfi_dii_rtrn_vld_i ), - .rvfi_dii_inst_pack_i (rvfi_dii_inst_pack_i ), - .rvfi_dii_data_ready_o(rvfi_dii_data_ready_o ), .cvxif_req_o ( cvxif_req ), .cvxif_resp_i ( cvxif_resp ), .noc_req_o ( noc_req_o ), diff --git a/corev_apu/tb/ariane_testharness.sv b/corev_apu/tb/ariane_testharness.sv index 5adfd4093..13c129ddb 100644 --- a/corev_apu/tb/ariane_testharness.sv +++ b/corev_apu/tb/ariane_testharness.sv @@ -58,7 +58,6 @@ module ariane_testharness import cva6_cheri_pkg::*; #( rvfi_probes_csr_t csr; rvfi_probes_instr_t instr; }; - localparam type rvfi_dii_inst_pack_t = `RVFI_DII_INSTR_T(CVA6Cfg); // disable test-enable logic test_en; @@ -744,7 +743,6 @@ module ariane_testharness import cva6_cheri_pkg::*; #( .rvfi_probes_instr_t ( rvfi_probes_instr_t ), .rvfi_probes_csr_t ( rvfi_probes_csr_t ), .rvfi_probes_t ( rvfi_probes_t ), - .rvfi_dii_inst_pack_t ( rvfi_dii_inst_pack_t ), .noc_req_t ( ariane_axi::req_t ), .noc_resp_t ( ariane_axi::resp_t ) ) i_ariane ( @@ -756,9 +754,6 @@ module ariane_testharness import cva6_cheri_pkg::*; #( .ipi_i ( ipi ), .time_irq_i ( timer_irq ), .rvfi_probes_o ( rvfi_probes ), - .rvfi_dii_rtrn_vld_i (rvfi_dii_rtrn_vld_i), - .rvfi_dii_inst_pack_i (rvfi_dii_inst_pack_i), - .rvfi_dii_data_ready_o (rvfi_dii_data_ready_o), // Disable Debug when simulating with Spike `ifdef SPIKE_TANDEM .debug_req_i ( 1'b0 ), diff --git a/corev_apu/tb/common/SimDTM.sv b/corev_apu/tb/common/SimDTM.sv index 293e7841b..e0613e418 100644 --- a/corev_apu/tb/common/SimDTM.sv +++ b/corev_apu/tb/common/SimDTM.sv @@ -1,6 +1,7 @@ // See LICENSE.SiFive for license details. //VCS coverage exclude_file +`ifndef DII import "DPI-C" function int debug_tick ( output bit debug_req_valid, @@ -14,6 +15,7 @@ import "DPI-C" function int debug_tick input int debug_resp_bits_resp, input int debug_resp_bits_data ); +`endif module SimDTM( input clk, @@ -65,6 +67,7 @@ module SimDTM( end else begin + `ifndef DII __exit = debug_tick( __debug_req_valid, __debug_req_ready, @@ -76,6 +79,7 @@ module SimDTM( __debug_resp_bits_resp, __debug_resp_bits_data ); + `endif end end endmodule diff --git a/corev_apu/tb/common/SimJTAG.sv b/corev_apu/tb/common/SimJTAG.sv index 473d892ec..0be1a3693 100644 --- a/corev_apu/tb/common/SimJTAG.sv +++ b/corev_apu/tb/common/SimJTAG.sv @@ -1,5 +1,6 @@ // See LICENSE.SiFive for license details. //VCS coverage exclude_file +`ifndef DII import "DPI-C" function int jtag_tick ( output bit jtag_TCK, @@ -9,6 +10,7 @@ import "DPI-C" function int jtag_tick input bit jtag_TDO ); +`endif module SimJTAG #( parameter TICK_DELAY = 50 @@ -69,12 +71,14 @@ module SimJTAG #( if (enable && init_done_sticky) begin tickCounterReg <= tickCounterNxt; if (tickCounterReg == 0) begin + `ifndef DII __exit = jtag_tick( __jtag_TCK, __jtag_TMS, __jtag_TDI, __jtag_TRSTn, __jtag_TDO); + `endif end end // if (enable && init_done_sticky) end // else: !if(reset || r_reset) diff --git a/corev_apu/tb/tb_testRig_cheri/Makefile b/corev_apu/tb/tb_testRig_cheri/Makefile index 87d0f7126..f2a39e5ad 100644 --- a/corev_apu/tb/tb_testRig_cheri/Makefile +++ b/corev_apu/tb/tb_testRig_cheri/Makefile @@ -1,4 +1,5 @@ # Copyright 2025 Bruno Sá and Zero-Day Labs. +# Copyright 2025 Capabilities Limited. # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information @@ -95,7 +96,7 @@ test_pkg := $(wildcard tb/test/*/*sequence_pkg.sv*) \ CFLAGS := -I$(QUESTASIM_HOME)/include \ -I$(VCS_HOME)/include \ -I$(RISCV)/include \ - -I$(root-dir)/corev_apu/tb/tb_testRig_cheri/src/SocketPacketUtils \ + -I$(root-dir)/corev_apu/tb/tb_testRig_cheri/src/RVFI-DII-utils \ -I$(root-dir)/corev_apu/tb/dpi -O3 # this list contains the standalone components @@ -244,7 +245,8 @@ verilate_command := $(verilator) --no-timing $(root-dir)/verilator_config.vlt $(list_incdir) --top-module ariane_testharness_dii \ --threads-dpi none \ --Mdir $(ver-library) -O3 \ - --exe ${root-dir}/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp ${root-dir}/corev_apu/tb/tb_testRig_cheri/src/SocketPacketUtils/socket_packet_utils.c + --exe ${root-dir}/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp ${root-dir}/corev_apu/tb/tb_testRig_cheri/src/RVFI-DII-utils/rvfi_dii_utils.c \ + ${root-dir}/corev_apu/tb/tb_testRig_cheri/src/RVFI-DII-utils/SocketPacketUtils/socket_packet_utils.c # User Verilator, at some point in the future this will be auto-generated verilate: diff --git a/corev_apu/tb/tb_testRig_cheri/hdl/ariane_testharness_dii.sv b/corev_apu/tb/tb_testRig_cheri/hdl/ariane_testharness_dii.sv index eae38bb51..4bef0f04d 100644 --- a/corev_apu/tb/tb_testRig_cheri/hdl/ariane_testharness_dii.sv +++ b/corev_apu/tb/tb_testRig_cheri/hdl/ariane_testharness_dii.sv @@ -1,4 +1,5 @@ // Copyright 2025 Bruno Sá and Zero-Day Labs. +// Copyright 2025 Capabilities Limited. // 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 @@ -48,12 +49,12 @@ module ariane_testharness_dii import cva6_cheri_pkg::*; #( output logic [ 1:0] rvfi_mode_o, output logic [ 4:0] rvfi_rs1_addr_o, output logic [ 4:0] rvfi_rs2_addr_o, - output logic [CVA6Cfg.XLEN-1:0] rvfi_rs1_rdata_o, - output logic [CVA6Cfg.XLEN-1:0] rvfi_rs2_rdata_o, + output logic [CVA6Cfg.XLEN-1:0] rvfi_rs1_rdata_o, + output logic [CVA6Cfg.XLEN-1:0] rvfi_rs2_rdata_o, output logic [ 4:0] rvfi_rd_addr_o, - output logic [CVA6Cfg.XLEN-1:0] rvfi_rd_wdata_o, - output logic [CVA6Cfg.VLEN-1:0] rvfi_pc_rdata_o, - output logic [CVA6Cfg.VLEN-1:0] rvfi_pc_wdata_o, + output logic [CVA6Cfg.XLEN-1:0] rvfi_rd_wdata_o, + output logic [CVA6Cfg.VLEN-1:0] rvfi_pc_rdata_o, + output logic [CVA6Cfg.VLEN-1:0] rvfi_pc_wdata_o, output logic [CVA6Cfg.XLEN-1:0] rvfi_mem_addr_o, output logic [(CVA6Cfg.CLEN/8)-1:0] rvfi_mem_rmask_o, output logic [(CVA6Cfg.CLEN/8)-1:0] rvfi_mem_wmask_o, @@ -61,11 +62,6 @@ module ariane_testharness_dii import cva6_cheri_pkg::*; #( output logic [CVA6Cfg.XLEN-1:0] rvfi_mem_wdata_o, `endif -`ifdef DII - input logic [31:0] dii_insn_i, - output logic dii_ready_o, - input logic dii_valid_i, -`endif output logic [31:0] exit_o ); @@ -83,7 +79,6 @@ module ariane_testharness_dii import cva6_cheri_pkg::*; #( rvfi_probes_csr_t csr; rvfi_probes_instr_t instr; }; - localparam type rvfi_dii_inst_pack_t = `RVFI_DII_INSTR_T(CVA6Cfg); // disable test-enable logic test_en; @@ -97,9 +92,6 @@ module ariane_testharness_dii import cva6_cheri_pkg::*; #( logic debug_resp_valid; logic debug_resp_ready; - logic [31:0] dii_insn; - logic dii_ready; - assign test_en = 1'b0; AXI_BUS #( @@ -643,19 +635,12 @@ module ariane_testharness_dii import cva6_cheri_pkg::*; #( else boot_cap.addr = ariane_soc::ROMBase; end - rvfi_dii_inst_pack_t rvfi_dii_inst_pack; - - always_comb begin : gen_rvfi_dii - rvfi_dii_inst_pack = '0; - rvfi_dii_inst_pack.rvfi_insn = dii_insn; - end ariane #( .CVA6Cfg ( CVA6Cfg ), .rvfi_probes_instr_t ( rvfi_probes_instr_t ), .rvfi_probes_csr_t ( rvfi_probes_csr_t ), .rvfi_probes_t ( rvfi_probes_t ), - .rvfi_dii_inst_pack_t ( rvfi_dii_inst_pack_t ), .noc_req_t ( ariane_axi::req_t ), .noc_resp_t ( ariane_axi::resp_t ) ) i_ariane ( @@ -667,9 +652,6 @@ module ariane_testharness_dii import cva6_cheri_pkg::*; #( .ipi_i ( ipi ), .time_irq_i ( timer_irq ), .rvfi_probes_o ( rvfi_probes ), - .rvfi_dii_rtrn_vld_i ( dii_valid_i ), - .rvfi_dii_inst_pack_i ( dii_insn_i ), - .rvfi_dii_data_ready_o ( dii_ready_o ), // Disable Debug when simulating with Spike `ifdef SPIKE_TANDEM .debug_req_i ( 1'b0 ), diff --git a/corev_apu/tb/tb_testRig_cheri/src/RVFI-DII-utils b/corev_apu/tb/tb_testRig_cheri/src/RVFI-DII-utils new file mode 160000 index 000000000..69a06c7cf --- /dev/null +++ b/corev_apu/tb/tb_testRig_cheri/src/RVFI-DII-utils @@ -0,0 +1 @@ +Subproject commit 69a06c7cf45bb7735ad483b355b8378f7bab7b21 diff --git a/corev_apu/tb/tb_testRig_cheri/src/SocketPacketUtils b/corev_apu/tb/tb_testRig_cheri/src/SocketPacketUtils deleted file mode 160000 index 3bcbc7081..000000000 --- a/corev_apu/tb/tb_testRig_cheri/src/SocketPacketUtils +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3bcbc70816e207e754e49ec75d803c12ff2bffd6 diff --git a/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp b/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp index 31254682f..5b2c4249c 100644 --- a/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp +++ b/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp @@ -1,5 +1,6 @@ // Copyright 2025 Bruno Sá and Zero-Day Labs. +// Copyright 2025 Capabilities Limited. // Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information @@ -16,6 +17,8 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. +// +// Copyright 2025 Capabilities Limited #include "verilator.h" #include "verilated.h" @@ -36,13 +39,17 @@ #include #include #include -#include #include #include #include #include -#include +//Exclude DII getters as they are defined in a verilator header for DPI +#define exclude_dii_getters +#include + +#define DII_ID_WIDTH 6 +#define DII_ID_COUNT (1 << DII_ID_WIDTH) // This software is heavily based on Rocket Chip // Checkout this awesome project: @@ -54,78 +61,12 @@ static vluint64_t main_time = 0; static const char *verilog_plusargs[] = {"time_out"}; -struct RVFI_DII_Execution_Packet { - std::uint64_t rvfi_order : 64; // [00 - 07] Instruction number: INSTRET value after completion. - std::uint64_t rvfi_pc_rdata : 64; // [08 - 15] PC before instr: PC for current instruction - std::uint64_t rvfi_pc_wdata : 64; // [16 - 23] PC after instr: Following PC - either PC + 4 or jump/trap target. - std::uint64_t rvfi_insn : 64; // [24 - 31] Instruction word: 32-bit command value. - std::uint64_t rvfi_rs1_data : 64; // [32 - 39] Read register values: Values as read from registers named - std::uint64_t rvfi_rs2_data : 64; // [40 - 47] above. Must be 0 if register ID is 0. - std::uint64_t rvfi_rd_wdata : 64; // [48 - 55] Write register value: MUST be 0 if rd_ is 0. - std::uint64_t rvfi_mem_addr : 64; // [56 - 63] Memory access addr: Points to byte address (aligned if define - // is set). *Should* be straightforward. - // 0 if unused. - std::uint64_t rvfi_mem_rdata : 64; // [64 - 71] Read data: Data read from mem_addr (i.e. before write) - std::uint64_t rvfi_mem_wdata : 64; // [72 - 79] Write data: Data written to memory by this command. - std::uint8_t rvfi_mem_rmask : 8; // [80] Read mask: Indicates valid bytes read. 0 if unused. - std::uint8_t rvfi_mem_wmask : 8; // [81] Write mask: Indicates valid bytes written. 0 if unused. - std::uint8_t rvfi_rs1_addr : 8; // [82] Read register addresses: Can be arbitrary when not used, - std::uint8_t rvfi_rs2_addr : 8; // [83] otherwise set as decoded. - std::uint8_t rvfi_rd_addr : 8; // [84] Write register address: MUST be 0 if not used. - std::uint8_t rvfi_trap : 8; // [85] Trap indicator: Invalid decode, misaligned access or - // jump command to misaligned address. - std::uint8_t rvfi_halt : 8; // [86] Halt indicator: Marks the last instruction retired - // before halting execution. - std::uint8_t rvfi_intr : 8; // [87] Trap handler: Set for first instruction in trap handler. -}; - -struct RVFI_DII_Instruction_Packet { - std::uint32_t dii_insn : 32; // [0 - 3] Instruction word: 32-bit instruction or command. The lower 16-bits - // may decode to a 16-bit compressed instruction. - std::uint16_t dii_time : 16; // [5 - 4] Time to inject token. The difference between this and the previous - // instruction time gives a delay before injecting this instruction. - // This can be ignored for models but gives repeatability for implementations - // while shortening counterexamples. - std::uint8_t dii_cmd : 8; // [6] This token is a trace command. For example, reset device under test. - std::uint8_t padding : 8; // [7] -}; - -void PrintInstTrace(RVFI_DII_Instruction_Packet* packet){ - std::cout << "<------Start instruction trace------>" << std::endl; - std::cout << "cmd: " << ((packet->dii_cmd == 0) ? "End of Trace" : "Instruction") << std::endl; - std::cout << "time: " << (int) packet->dii_time << std::endl; - std::cout << "insn: " << std::hex << packet->dii_insn << std::endl; - std::cout << "<------Finish instruction trace------>" << std::endl; -} - -void PrintExecTrace(RVFI_DII_Execution_Packet* packet){ - std::cout << "<------Start execution trace------>" << std::endl; - std::cout << "order: " << (int) packet->rvfi_order << std::endl; - std::cout << "pc_rdata: " << std::hex << (int) packet->rvfi_pc_rdata << std::endl; - std::cout << "pc_wdata: " << std::hex << (int) packet->rvfi_pc_wdata << std::endl; - std::cout << "insn: " << std::hex << (int) packet->rvfi_insn << std::endl; - std::cout << "rs1_data: " << std::hex << (int) packet->rvfi_rs1_data << std::endl; - std::cout << "rs2_data: " << std::hex << (int) packet->rvfi_rs2_data << std::endl; - std::cout << "rd_wdata: " << std::hex << (int) packet->rvfi_rd_wdata << std::endl; - std::cout << "mem_addr: " << std::hex << (int) packet->rvfi_mem_addr << std::endl; - std::cout << "mem_rdatal: " << std::hex << (int)packet->rvfi_mem_rdata << std::endl; - std::cout << "mem_wdatal: " << std::hex << (int) packet->rvfi_mem_wdata << std::endl; - std::cout << "mem_rmask: " << std::hex << (int) packet->rvfi_mem_rmask << std::endl; - std::cout << "mem_wmask: " << std::hex << (int) packet->rvfi_mem_wmask << std::endl; - std::cout << "rs1_addr: " << std::hex << (int) packet->rvfi_rs1_addr << std::endl; - std::cout << "rs2_addr: " << std::hex << (int) packet->rvfi_rs2_addr << std::endl; - std::cout << "rd_addr: " << std::hex << (int) packet->rvfi_rd_addr << std::endl; - std::cout << "trap: " << (int) packet->rvfi_trap << std::endl; - std::cout << "halt: " << (int) packet->rvfi_halt << std::endl; - std::cout << "instr: " << std::hex << (int) packet->rvfi_intr << std::endl; - std::cout << "<------Finish execution trace------>" << std::endl; -} +static int current_test_dii_start = 0; // Routine to fetch intructions from the Vengine -void fetchInstructions(std::vector &instructions, unsigned int &cnt_rec, unsigned long long socket); -RVFI_DII_Execution_Packet readRVFI(Variane_testharness_dii *top); -void returnTrace(std::vector &returntrace, unsigned long long socket); -bool readTrace(std::vector &returntrace, Variane_testharness_dii *top); +rvfi_pkt_t readRVFI(Variane_testharness_dii *top); +bool readTrace(Variane_testharness_dii *top, unsigned int rvfi_id); +void sendReset(unsigned int rvfi_id); // Called by $time in Verilog converts to double, to match what SystemC does double sc_time_stamp () { @@ -172,8 +113,6 @@ EMULATOR DEBUG OPTIONS (only supported in debug build -- try `make debug`)\n", } int main(int argc, char **argv) { - std::clock_t c_start = std::clock(); - auto t_start = std::chrono::high_resolution_clock::now(); bool verbose; int ret = 0; #if VM_TRACE @@ -281,8 +220,6 @@ int main(int argc, char **argv) { } done_processing: - std::cout << "start" << std::endl; - const char *vcd_file = NULL; Verilated::commandArgs(argc, argv); @@ -312,6 +249,9 @@ int main(int argc, char **argv) { #endif #endif + + rvfi_dii_bridge_rst(DII_ID_WIDTH); + for (int i = 0; i < 10; i++) { top->rst_ni = 0; top->clk_i = 0; @@ -342,113 +282,63 @@ int main(int argc, char **argv) { long long len; size_t mem_size = 0x900000; - unsigned long long socket = serv_socket_create(socket_name, socket_default_port); - serv_socket_init(socket); - unsigned int received = 0; - unsigned int insn_count = 0; unsigned int traces_count = 0; - unsigned int num_insn = 0; // instruction - bool busy = false; - bool inflight = false; bool eof_trace = false; - RVFI_DII_Instruction_Packet next_instruction; - char recbuf[sizeof(RVFI_DII_Instruction_Packet) + 1] = {0}; - std::vector instructions; - std::vector returntrace; while (true) { - // Routine to fetch a batch of intructions from the Vengine - if (num_insn == 0) { - fetchInstructions(instructions, received, socket); - busy = true; - num_insn = instructions.size(); + if (readTrace(top, traces_count)) { + traces_count++; + traces_count %= DII_ID_COUNT; } - - while (busy) { - if (readTrace(returntrace, top)){ - traces_count++; - } - // Routine to inject instructions into the core via RVFIDII interface - if (!instructions.empty() /* && !inflight */){ - if ((traces_count != num_insn-1) && (top->rvfi_trap_o || (top->rvfi_valid_o && (top->rvfi_insn_o & 0x7F) == 0xF))) { - insn_count = traces_count; - } - next_instruction = instructions.at(insn_count); - if (next_instruction.dii_cmd && insn_count == traces_count) { - top->dii_valid_i = 1; - } else { - top->dii_valid_i = 0; - } - top->dii_insn_i = next_instruction.dii_insn; - if (top->dii_ready_o && next_instruction.dii_cmd && insn_count == traces_count){ - inflight = true; - insn_count++; - } else if (!next_instruction.dii_cmd && traces_count == num_insn-1) { - insn_count++; - eof_trace = true; - top->dii_valid_i = 0; - inflight = false; - } - } - top->clk_i = 0; - top->eval(); + if (get_dii_cmd(traces_count) == 0) { + eof_trace = true; + } + top->clk_i = 0; + top->eval(); #if VM_TRACE - if (vcdfile || fst_fname) - tfp->dump(static_cast(main_time * 2)); + if (vcdfile || fst_fname) + tfp->dump(static_cast(main_time * 2)); #endif - - top->clk_i = 1; - top->eval(); + top->clk_i = 1; + top->eval(); #if VM_TRACE - if (vcdfile || fst_fname) - tfp->dump(static_cast(main_time * 2 + 1)); + if (vcdfile || fst_fname) + tfp->dump(static_cast(main_time * 2 + 1)); #endif - // toggle RTC - if (main_time % 2 == 0) { - top->rtc_i ^= 1; - } - main_time++; + // toggle RTC + if (main_time % 2 == 0) { + top->rtc_i ^= 1; + } + main_time++; - // Reset Routine - if (eof_trace){ - for (int i = 0; i < 10; i++) { - top->rst_ni = 0; - top->clk_i = 0; - top->rtc_i = 0; - top->eval(); - #if VM_TRACE - if (vcdfile || fst_fname) - tfp->dump(static_cast(main_time * 2)); + // Reset Routine + if (eof_trace){ + sendReset(traces_count); + for (int i = 0; i < 10; i++) { + top->rst_ni = 0; + top->clk_i = 0; + top->rtc_i = 0; + top->eval(); + #if VM_TRACE + if (vcdfile || fst_fname) + tfp->dump(static_cast(main_time * 2)); + #endif + top->clk_i = 1; + top->eval(); + #if VM_TRACE + if (vcdfile || fst_fname) + tfp->dump(static_cast(main_time * 2 + 1)); #endif - top->clk_i = 1; - top->eval(); - #if VM_TRACE - if (vcdfile || fst_fname) - tfp->dump(static_cast(main_time * 2 + 1)); - #endif - main_time++; - } - top->rst_ni = 1; - eof_trace = false; - inflight = false; - busy = false; - traces_count = 0; - insn_count = 0; - num_insn = 0; - // Clear memory - for (int i = 0; i < (sizeof(MEM)/sizeof(MEM[0])); i++) { - MEM[i] = 0; - } - RVFI_DII_Execution_Packet rstpack = { - .rvfi_halt = 1 - }; - returntrace.push_back(rstpack); - instructions.clear(); + main_time++; } - - // Routine to return trace to Vengine - while (!returntrace.empty()) { - returnTrace(returntrace, socket); + top->rst_ni = 1; + eof_trace = false; + traces_count++; + traces_count %= DII_ID_COUNT; + current_test_dii_start = traces_count; + // Clear memory + for (int i = 0; i < (sizeof(MEM)/sizeof(MEM[0])); i++) { + MEM[i] = 0; } } } @@ -460,36 +350,37 @@ int main(int argc, char **argv) { fclose(vcdfile); #endif - std::clock_t c_end = std::clock(); - auto t_end = std::chrono::high_resolution_clock::now(); - return ret; } -// Routine to fetch intructions from the Vengine -void fetchInstructions(std::vector &instructions, unsigned int &cnt_rec, unsigned long long socket){ - RVFI_DII_Instruction_Packet *ins_packet; - bool eof_rec = false; - char recbuf[sizeof(RVFI_DII_Instruction_Packet) + 1] = {0}; - // try to receive a packet - do { - serv_socket_getN((unsigned int *) recbuf, socket, sizeof(RVFI_DII_Instruction_Packet)); - // the last byte received will be 0 if our attempt to receive a packet was successful - if (recbuf[sizeof(RVFI_DII_Instruction_Packet)] == 0) { - ins_packet = (RVFI_DII_Instruction_Packet *) recbuf; - instructions.push_back(*ins_packet); - PrintInstTrace(ins_packet); - cnt_rec++; - if (ins_packet->dii_cmd == 0) eof_rec = true; - } else { - // sleep for 1ms before retrying - usleep(1000); - } - } while(!eof_rec); +int test_dii_start() { + return current_test_dii_start; +} + +bool readTrace(Variane_testharness_dii *top, unsigned int rvfi_id) { + // read rvfi data and add packet to list of packets to send + // the condition to read data here is that there is an rvfi valid signal + // this deals with counting instructions that the core has finished executing + if (top->rvfi_valid_o || top->rvfi_trap_o) { + rvfi_pkt_t execpacket = readRVFI(top); + print_rvfi_pkt(&execpacket); + put_rvfi_pkt_wrap(rvfi_id, &execpacket); + return true; + } + return false; +} + +void sendReset(unsigned int rvfi_id) { + rvfi_pkt_t execpacket; + #define rvfi_field(name, type) execpacket.name = 0; + for_all_rvfi_fields + #undef rvfi_field + execpacket.rvfi_halt = 1; + put_rvfi_pkt_wrap(rvfi_id, &execpacket); } -RVFI_DII_Execution_Packet readRVFI(Variane_testharness_dii *top) { - RVFI_DII_Execution_Packet execpacket = { +rvfi_pkt_t readRVFI(Variane_testharness_dii *top) { + rvfi_pkt_t execpacket = { .rvfi_order = top->rvfi_order_o, .rvfi_pc_rdata = top->rvfi_pc_rdata_o , .rvfi_pc_wdata = top->rvfi_pc_wdata_o , @@ -511,41 +402,3 @@ RVFI_DII_Execution_Packet readRVFI(Variane_testharness_dii *top) { }; return execpacket; } - -void returnTrace(std::vector &returntrace, unsigned long long socket) { - const int BULK_SEND = 50; - if (returntrace.size() > 0) { - int tosend = 1; - for (int i = 0; i < returntrace.size(); i+=tosend) { - tosend = 1; - RVFI_DII_Execution_Packet sendarr[BULK_SEND]; - sendarr[0] = returntrace.front(); - // bulk send if possible - if (returntrace.size() - i > BULK_SEND) { - tosend = BULK_SEND; - for (int j = 0; j < tosend; j++) { - RVFI_DII_Execution_Packet execpacket = returntrace.front(); - sendarr[j] = returntrace.front(); - returntrace.erase(returntrace.begin()); - } - } else { - returntrace.erase(returntrace.begin()); - } - // loop to make sure that the packet has been properly sent - while(!serv_socket_putN(socket, sizeof(RVFI_DII_Execution_Packet) * tosend, (unsigned int *) sendarr)); - } - } -} - -bool readTrace(std::vector &returntrace, Variane_testharness_dii *top) { - // read rvfi data and add packet to list of packets to send - // the condition to read data here is that there is an rvfi valid signal - // this deals with counting instructions that the core has finished executing - if (top->rvfi_valid_o || top->rvfi_trap_o) { - RVFI_DII_Execution_Packet execpacket = readRVFI(top); - PrintExecTrace(&execpacket); - returntrace.push_back(execpacket); - return true; - } - return false; -} From 640c0db16af48a4fa1e79857e3290797e3577cb9 Mon Sep 17 00:00:00 2001 From: Peter Rugg Date: Fri, 28 Mar 2025 14:55:56 +0000 Subject: [PATCH 12/12] Flush stdout after eval-ing verilog --- corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp b/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp index 5b2c4249c..799100259 100644 --- a/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp +++ b/corev_apu/tb/tb_testRig_cheri/src/cva6_dii_toplevel.cpp @@ -257,12 +257,14 @@ int main(int argc, char **argv) { top->clk_i = 0; top->rtc_i = 0; top->eval(); + fflush(stdout); #if VM_TRACE if (vcdfile || fst_fname) tfp->dump(static_cast(main_time * 2)); #endif top->clk_i = 1; top->eval(); + fflush(stdout); #if VM_TRACE if (vcdfile || fst_fname) tfp->dump(static_cast(main_time * 2 + 1)); @@ -295,12 +297,14 @@ int main(int argc, char **argv) { } top->clk_i = 0; top->eval(); + fflush(stdout); #if VM_TRACE if (vcdfile || fst_fname) tfp->dump(static_cast(main_time * 2)); #endif top->clk_i = 1; top->eval(); + fflush(stdout); #if VM_TRACE if (vcdfile || fst_fname) tfp->dump(static_cast(main_time * 2 + 1)); @@ -319,12 +323,14 @@ int main(int argc, char **argv) { top->clk_i = 0; top->rtc_i = 0; top->eval(); + fflush(stdout); #if VM_TRACE if (vcdfile || fst_fname) tfp->dump(static_cast(main_time * 2)); #endif top->clk_i = 1; top->eval(); + fflush(stdout); #if VM_TRACE if (vcdfile || fst_fname) tfp->dump(static_cast(main_time * 2 + 1));