summaryrefslogtreecommitdiff
path: root/riscv
diff options
context:
space:
mode:
authorBrian Campbell2018-11-12 16:10:04 +0000
committerBrian Campbell2018-11-12 16:10:04 +0000
commit4d652c426f57e5255ef8c1d828c53abcbb69d722 (patch)
treef0e6a997737357c1a0505aa5571fe17c32cdd4a0 /riscv
parentd0f80cd274d16b049896628e6046062eac95258f (diff)
Add RVFI DII version of the RISC-V simulator for TestRIG
The new riscv_rvfi target should still be usable as a normal simulator, but also has extra registers in the model for the RVFI DII protocol and code to update them, and the driver has a -r option to enable RVFI mode.
Diffstat (limited to 'riscv')
-rw-r--r--riscv/Makefile9
-rw-r--r--riscv/main_rvfi.sail104
-rw-r--r--riscv/riscv_mem.sail44
-rw-r--r--riscv/riscv_sail.h8
-rw-r--r--riscv/riscv_sim.c143
-rw-r--r--riscv/riscv_sys.sail10
-rw-r--r--riscv/riscv_types.sail12
-rw-r--r--riscv/rvfi_dii.sail98
8 files changed, 425 insertions, 3 deletions
diff --git a/riscv/Makefile b/riscv/Makefile
index e6bbbd5c..a49ba6e3 100644
--- a/riscv/Makefile
+++ b/riscv/Makefile
@@ -6,9 +6,11 @@ SAIL_RMEM_INST_SRCS = riscv_insts_begin.sail $(SAIL_RMEM_INST) riscv_insts_end.s
# non-instruction sources
SAIL_OTHER_SRCS = prelude.sail riscv_types.sail riscv_sys.sail riscv_platform.sail riscv_mem.sail riscv_vmem.sail
+SAIL_OTHER_RVFI_SRCS = prelude.sail rvfi_dii.sail riscv_types.sail riscv_sys.sail riscv_platform.sail riscv_mem.sail riscv_vmem.sail
SAIL_SRCS = $(SAIL_OTHER_SRCS) $(SAIL_SEQ_INST_SRCS) riscv_step.sail riscv_analysis.sail
SAIL_RMEM_SRCS = $(SAIL_OTHER_SRCS) $(SAIL_RMEM_INST_SRCS) riscv_step.sail riscv_analysis.sail
+SAIL_RVFI_SRCS = $(SAIL_OTHER_RVFI_SRCS) $(SAIL_SEQ_INST_SRCS) riscv_step.sail riscv_analysis.sail
PLATFORM_OCAML_SRCS = platform.ml platform_impl.ml platform_main.ml
SAIL_DIR ?= $(realpath ..)
@@ -73,6 +75,12 @@ riscv_model.c: $(SAIL_SRCS) main.sail Makefile
riscv_sim: riscv_model.c riscv_sim.c $(C_INCS) $(C_SRCS) $(CPP_SRCS) Makefile
gcc -g $(C_WARNINGS) $(C_FLAGS) -O2 riscv_model.c riscv_sim.c $(C_SRCS) ../lib/*.c $(C_LIBS) -o $@
+riscv_rvfi_model.c: $(SAIL_RVFI_SRCS) main_rvfi.sail Makefile
+ $(SAIL) -O -memo_z3 -c -c_include riscv_prelude.h -c_include riscv_platform.h -c_no_main $(SAIL_RVFI_SRCS) main_rvfi.sail 1> $@
+
+riscv_rvfi: riscv_rvfi_model.c riscv_sim.c $(C_INCS) $(C_SRCS) $(CPP_SRCS) Makefile
+ gcc -g $(C_WARNINGS) $(C_FLAGS) -O2 riscv_rvfi_model.c -DRVFI_DII riscv_sim.c $(C_SRCS) ../lib/*.c $(C_LIBS) -o $@
+
latex: $(SAIL_SRCS) Makefile
$(SAIL) -latex -latex_prefix sail -o sail_ltx $(SAIL_SRCS)
@@ -141,5 +149,6 @@ clean:
-rm -f riscv.vo riscv_types.vo riscv_extras.vo riscv.v riscv_types.v
-rm -f riscv_duopod.vo riscv_duopod_types.vo riscv_duopod.v riscv_duopod_types.v
-rm -f riscv.c riscv_model.c riscv_sim
+ -rm -f riscv_rvfi_model.c riscv_rvfi
-Holmake cleanAll
ocamlbuild -clean
diff --git a/riscv/main_rvfi.sail b/riscv/main_rvfi.sail
new file mode 100644
index 00000000..e1469f7f
--- /dev/null
+++ b/riscv/main_rvfi.sail
@@ -0,0 +1,104 @@
+// Alternative fetch and step for RVFI DII mode.
+
+val rvfi_fetch : unit -> FetchResult effect {escape, rmem, rreg, wmv, wreg}
+
+function rvfi_fetch() = {
+ let i = rvfi_instruction.rvfi_insn();
+ rvfi_exec->rvfi_order() = minstret;
+ rvfi_exec->rvfi_pc_rdata() = PC;
+ rvfi_exec->rvfi_insn() = zero_extend(i,64);
+ /* TODO: should we write these even if they're not really registers? */
+ rvfi_exec->rvfi_rs1_data() = X(i[19 .. 15]);
+ rvfi_exec->rvfi_rs2_data() = X(i[24 .. 20]);
+ rvfi_exec->rvfi_rs1_addr() = zero_extend(i[19 .. 15],8);
+ rvfi_exec->rvfi_rs2_addr() = zero_extend(i[24 .. 20],8);
+ if (i[1 .. 0] == 0b11)
+ then F_Base(i)
+ else F_RVC(i[15 .. 0])
+}
+
+// This should be kept in sync with the normal step - at the moment the only
+// changes are to replace fetch by rvfi_fetch and record the next PC.
+
+/* returns whether to increment the step count in the trace */
+val rvfi_step : int -> bool effect {barr, eamem, escape, exmem, rmem, rreg, wmv, wreg}
+function rvfi_step(step_no) = {
+ minstret_written = false; /* see note for minstret */
+ let (retired, stepped) : (bool, bool) =
+ match curInterrupt(cur_privilege, mip, mie, mideleg) {
+ Some(intr, priv) => {
+ print_bits("Handling interrupt: ", intr);
+ handle_interrupt(intr, priv);
+ (false, false)
+ },
+ None() => {
+ match rvfi_fetch() {
+ F_Error(e, addr) => {
+ handle_mem_exception(addr, e);
+ (false, false)
+ },
+ F_RVC(h) => {
+ match decodeCompressed(h) {
+ None() => {
+ print("[" ^ string_of_int(step_no) ^ "] [" ^ cur_privilege ^ "]: " ^ BitStr(PC) ^ " (" ^ BitStr(h) ^ ") <no-decode>");
+ instbits = EXTZ(h);
+ handle_illegal();
+ (false, true)
+ },
+ Some(ast) => {
+ print("[" ^ string_of_int(step_no) ^ "] [" ^ cur_privilege ^ "]: " ^ BitStr(PC) ^ " (" ^ BitStr(h) ^ ") " ^ ast);
+ nextPC = PC + 2;
+ (execute(ast), true)
+ }
+ }
+ },
+ F_Base(w) => {
+ match decode(w) {
+ None() => {
+ print("[" ^ string_of_int(step_no) ^ "] [" ^ cur_privilege ^ "]: " ^ BitStr(PC) ^ " (" ^ BitStr(w) ^ ") <no-decode>");
+ instbits = EXTZ(w);
+ handle_illegal();
+ (false, true)
+ },
+ Some(ast) => {
+ print("[" ^ string_of_int(step_no) ^ "] [" ^ cur_privilege ^ "]: " ^ BitStr(PC) ^ " (" ^ BitStr(w) ^ ") " ^ ast);
+ nextPC = PC + 4;
+ (execute(ast), true)
+ }
+ }
+ }
+ }
+ }
+ };
+ PC = nextPC;
+ rvfi_exec->rvfi_pc_wdata() = PC;
+//print_rvfi_exec();
+ if retired then retire_instruction();
+ stepped
+}
+
+
+/* Dummy to make sure that sail doesn't throw functions away */
+
+val main : unit -> unit effect {barr, eamem, escape, exmem, rmem, rreg, wmv, wreg}
+
+function main () = {
+
+ // PC = __GetSlice_int(64, elf_entry(), 0);
+ rvfi_set_instr_packet(0x0000000000000000);
+ print_bits("", rvfi_get_cmd());
+ let _ = rvfi_step(0);
+ rvfi_zero_exec_packet();
+ rvfi_halt_exec_packet();
+ let _ = rvfi_get_exec_packet();
+ PC = zero_extend(0x1000, 64);
+ print_bits("PC = ", PC);
+ try {
+ init_platform();
+ init_sys();
+ loop()
+ } catch {
+ Error_not_implemented(s) => print_string("Error: Not implemented: ", s),
+ Error_internal_error() => print("Error: internal error")
+ }
+}
diff --git a/riscv/riscv_mem.sail b/riscv/riscv_mem.sail
index 2bcc9797..dc30a7ae 100644
--- a/riscv/riscv_mem.sail
+++ b/riscv/riscv_mem.sail
@@ -40,10 +40,34 @@ function MEMr_reserved (addr, width) = checked_mem_read(Data, add
function MEMr_reserved_acquire (addr, width) = checked_mem_read(Data, addr, width, true, false, true)
function MEMr_reserved_strong_acquire (addr, width) = checked_mem_read(Data, addr, width, true, true, true)
+$ifdef RVFI_DII
+val rvfi_read : forall 'n, 'n > 0. (xlenbits, atom('n), MemoryOpResult(bits(8 * 'n))) -> unit effect {wreg}
+function rvfi_read (addr, width, result) = {
+ rvfi_exec->rvfi_mem_addr() = addr;
+ match result {
+ MemValue(v) =>
+ if width <= 8
+ then {
+ rvfi_exec->rvfi_mem_wdata() = zero_extend(v,64);
+ rvfi_exec->rvfi_mem_wmask() = to_bits(8,width)
+ } else (),
+ MemException(_) => ()
+ };
+}
+$else
+val rvfi_read : forall 'n, 'n > 0. (xlenbits, atom('n), MemoryOpResult(bits(8 * 'n))) -> unit
+function rvfi_read (addr, width, value) = ()
+$endif
+
/* NOTE: The rreg effect is due to MMIO. */
+$ifdef RVFI_DII
+val mem_read : forall 'n, 'n > 0. (xlenbits, atom('n), bool, bool, bool) -> MemoryOpResult(bits(8 * 'n)) effect {wreg, rmem, rreg, escape}
+$else
val mem_read : forall 'n, 'n > 0. (xlenbits, atom('n), bool, bool, bool) -> MemoryOpResult(bits(8 * 'n)) effect {rmem, rreg, escape}
+$endif
function mem_read (addr, width, aq, rl, res) = {
+ let result : MemoryOpResult(bits(8 * 'n)) =
if (aq | res) & (~ (is_aligned_addr(addr, width)))
then MemException(E_Load_Addr_Align)
else match (aq, rl, res) {
@@ -55,7 +79,9 @@ function mem_read (addr, width, aq, rl, res) = {
(true, true, false) => MEMr_strong_acquire(addr, width),
(false, true, true) => throw(Error_not_implemented("lr.rl")),
(true, true, true) => MEMr_reserved_strong_acquire(addr, width)
- }
+ };
+ rvfi_read(addr, width, result);
+ result
}
val MEMea = {lem: "MEMea", coq: "MEMea", _: "memea"} : forall 'n.
@@ -118,10 +144,26 @@ function MEMval_conditional (addr, width, data) = checked_mem_wri
function MEMval_conditional_release (addr, width, data) = checked_mem_write(addr, width, data)
function MEMval_conditional_strong_release (addr, width, data) = checked_mem_write(addr, width, data)
+
+$ifdef RVFI_DII
+val rvfi_write : forall 'n, 'n > 0. (xlenbits, atom('n), bits(8 * 'n)) -> unit effect {wreg}
+function rvfi_write (addr, width, value) = {
+ rvfi_exec->rvfi_mem_addr() = addr;
+ if width <= 8 then {
+ rvfi_exec->rvfi_mem_wdata() = zero_extend(value,64);
+ rvfi_exec->rvfi_mem_wmask() = to_bits(8,width);
+ }
+}
+$else
+val rvfi_write : forall 'n, 'n > 0. (xlenbits, atom('n), bits(8 * 'n)) -> unit
+function rvfi_write (addr, width, value) = ()
+$endif
+
/* NOTE: The wreg effect is due to MMIO, the rreg is due to checking mtime. */
val mem_write_value : forall 'n, 'n > 0. (xlenbits, atom('n), bits(8 * 'n), bool, bool, bool) -> MemoryOpResult(bool) effect {wmv, rreg, wreg, escape}
function mem_write_value (addr, width, value, aq, rl, con) = {
+ rvfi_write(addr, width, value);
if (rl | con) & (~ (is_aligned_addr(addr, width)))
then MemException(E_SAMO_Addr_Align)
else match (aq, rl, con) {
diff --git a/riscv/riscv_sail.h b/riscv/riscv_sail.h
index f2569b3b..ba052af1 100644
--- a/riscv/riscv_sail.h
+++ b/riscv/riscv_sail.h
@@ -14,6 +14,14 @@ unit zinit_sys(unit);
bool zstep(sail_int);
unit ztick_clock(unit);
unit ztick_platform(unit);
+#ifdef RVFI_DII
+unit zrvfi_set_instr_packet(mach_bits);
+mach_bits zrvfi_get_cmd(unit);
+bool zrvfi_step(sail_int);
+unit zrvfi_zzero_exec_packet(unit);
+unit zrvfi_halt_exec_packet(unit);
+void zrvfi_get_exec_packet(sail_bits *rop, unit);
+#endif
extern bool zhtif_done;
extern mach_bits zhtif_exit_code;
diff --git a/riscv/riscv_sim.c b/riscv/riscv_sim.c
index 276c7b1b..98f17349 100644
--- a/riscv/riscv_sim.c
+++ b/riscv/riscv_sim.c
@@ -6,6 +6,8 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
+#include <sys/socket.h>
+#include <netinet/ip.h>
#include <fcntl.h>
#include "elf.h"
@@ -45,6 +47,10 @@ char *term_log = NULL;
char *dtb_file = NULL;
unsigned char *dtb = NULL;
size_t dtb_len = 0;
+#ifdef RVFI_DII
+static bool rvfi_dii = false;
+static int rvfi_dii_sock;
+#endif
unsigned char *spike_dtb = NULL;
size_t spike_dtb_len = 0;
@@ -56,13 +62,20 @@ static struct option options[] = {
{"dump-dts", no_argument, 0, 's'},
{"device-tree-blob", required_argument, 0, 'b'},
{"terminal-log", required_argument, 0, 't'},
+#ifdef RVFI_DII
+ {"rvfi-dii", no_argument, 0, 'r'},
+#endif
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
static void print_usage(const char *argv0, int ec)
{
+#ifdef RVFI_DII
+ fprintf(stdout, "Usage: %s [options] [<elf_file>]\n", argv0);
+#else
fprintf(stdout, "Usage: %s [options] <elf_file>\n", argv0);
+#endif
struct option *opt = options;
while (opt->name) {
fprintf(stdout, "\t -%c\t %s\n", (char)opt->val, opt->name);
@@ -123,7 +136,7 @@ char *process_args(int argc, char **argv)
{
int c, idx = 1;
while(true) {
- c = getopt_long(argc, argv, "dmsb:t:v:h", options, &idx);
+ c = getopt_long(argc, argv, "dmsb:t:v:hr", options, &idx);
if (c == -1) break;
switch (c) {
case 'd':
@@ -146,16 +159,28 @@ char *process_args(int argc, char **argv)
case 'h':
print_usage(argv[0], 0);
break;
+#ifdef RVFI_DII
+ case 'r':
+ rvfi_dii = true;
+ break;
+#endif
default:
fprintf(stderr, "Unrecognized optchar %c\n", c);
print_usage(argv[0], 1);
}
}
if (do_dump_dts) dump_dts();
+#ifdef RVFI_DII
+ if (idx > argc || (idx == argc && !rvfi_dii)) print_usage(argv[0], 0);
+#else
if (idx >= argc) print_usage(argv[0], 0);
+#endif
if (term_log == NULL) term_log = strdup("term.log");
if (dtb_file) read_dtb(dtb_file);
+#ifdef RVFI_DII
+ if (!rvfi_dii)
+#endif
fprintf(stdout, "Running file %s.\n", argv[optind]);
return argv[optind];
}
@@ -276,6 +301,11 @@ void init_sail_reset_vector(uint64_t entry)
/* set rom size */
rv_rom_size = rom_end - rv_rom_base;
+#ifdef RVFI_DII
+ if (rvfi_dii)
+ zPC = entry;
+ else
+#endif
/* boot at reset vector */
zPC = rv_rom_base;
}
@@ -374,6 +404,26 @@ void flush_logs(void)
fflush(stdout);
}
+#ifdef RVFI_DII
+void rvfi_send_trace(void) {
+ sail_bits packet;
+ CREATE(sail_bits)(&packet);
+ zrvfi_get_exec_packet(&packet, UNIT);
+ if (packet.len % 8 != 0) {
+ fprintf(stderr, "RVFI-DII trace packet not byte aligned: %d\n", (int)packet.len);
+ exit(1);
+ }
+ unsigned char bytes[packet.len / 8];
+ /* mpz_export might not write all of the null bytes */
+ memset(bytes, 0, sizeof(bytes));
+ mpz_export(bytes, NULL, -1, 1, 0, 0, *(packet.bits));
+ if (write(rvfi_dii_sock, bytes, packet.len / 8) == -1) {
+ fprintf(stderr, "Writing RVFI DII trace failed: %s", strerror(errno));
+ exit(1);
+ }
+}
+#endif
+
void run_sail(void)
{
bool spike_done;
@@ -383,8 +433,46 @@ void run_sail(void)
/* initialize the step number */
mach_int step_no = 0;
int insn_cnt = 0;
+#ifdef RVFI_DII
+ bool need_instr = true;
+#endif
while (!zhtif_done) {
+#ifdef RVFI_DII
+ if (rvfi_dii) {
+ if (need_instr) {
+ mach_bits instr_bits;
+ if (read(rvfi_dii_sock, &instr_bits, sizeof(instr_bits)) == -1) {
+ fprintf(stderr, "Reading RVFI DII command failed: %s", strerror(errno));
+ exit(1);
+ }
+ zrvfi_set_instr_packet(instr_bits);
+ zrvfi_zzero_exec_packet(UNIT);
+ mach_bits cmd = zrvfi_get_cmd(UNIT);
+ switch (cmd) {
+ case 0: /* EndOfTrace */
+ zrvfi_halt_exec_packet(UNIT);
+ rvfi_send_trace();
+ return;
+ case 1: /* Instruction */
+ break;
+ default:
+ fprintf(stderr, "Unknown RVFI-DII command: %d\n", (int)cmd);
+ exit(1);
+ }
+ }
+ sail_int sail_step;
+ CREATE(sail_int)(&sail_step);
+ CONVERT_OF(sail_int, mach_int)(&sail_step, step_no);
+ stepped = zrvfi_step(sail_step);
+ if (have_exception) goto step_exception;
+ flush_logs();
+ if (stepped) {
+ need_instr = true;
+ rvfi_send_trace();
+ }
+ } else
+#endif
{ /* run a Sail step */
sail_int sail_step;
CREATE(sail_int)(&sail_step);
@@ -471,7 +559,46 @@ int main(int argc, char **argv)
char *file = process_args(argc, argv);
init_logs();
+#ifdef RVFI_DII
+ uint64_t entry;
+ if (rvfi_dii) {
+ entry = 0x80000000;
+ int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (listen_sock == -1) {
+ fprintf(stderr, "Unable to create socket: %s", strerror(errno));
+ return 1;
+ }
+ int opt = 1;
+ if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
+ fprintf(stderr, "Unable to set reuseaddr on socket: %s", strerror(errno));
+ return 1;
+ }
+ struct sockaddr_in addr = {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = INADDR_ANY,
+ .sin_port = htons(1234)
+ };
+ if (bind(listen_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+ fprintf(stderr, "Unable to set bind socket: %s", strerror(errno));
+ return 1;
+ }
+ if (listen(listen_sock, 1) == -1) {
+ fprintf(stderr, "Unable to listen on socket: %s", strerror(errno));
+ return 1;
+ }
+ printf("Waiting for connection\n");
+ rvfi_dii_sock = accept(listen_sock, NULL, NULL);
+ if (rvfi_dii_sock == -1) {
+ fprintf(stderr, "Unable to accept connection on socket: %s", strerror(errno));
+ return 1;
+ }
+ close(listen_sock);
+ printf("Connected\n");
+ } else
+ entry = load_sail(file);
+#else
uint64_t entry = load_sail(file);
+#endif
/* initialize spike before sail so that we can access the device-tree blob,
* until we roll our own.
@@ -481,6 +608,18 @@ int main(int argc, char **argv)
if (!init_check(s)) finish(1);
- run_sail();
+ do {
+ run_sail();
+#ifndef RVFI_DII
+ } while (0);
+#else
+ if (rvfi_dii) {
+ /* Reset for next test; currently we only quit when the connection breaks
+ and we crash due to SIGPIPE. */
+ model_fini();
+ init_sail(entry);
+ }
+ } while (rvfi_dii);
+#endif
flush_logs();
}
diff --git a/riscv/riscv_sys.sail b/riscv/riscv_sys.sail
index 9c49d9e5..81871f91 100644
--- a/riscv/riscv_sys.sail
+++ b/riscv/riscv_sys.sail
@@ -874,10 +874,20 @@ union ctl_result = {
/* TODO: CTL_URET */
}
+$ifdef RVFI_DII
+val rvfi_trap : unit -> unit effect {wreg}
+function rvfi_trap () =
+ rvfi_exec->rvfi_trap() = 0x01
+$else
+val rvfi_trap : unit -> unit
+function rvfi_trap () = ()
+$endif
+
/* handle exceptional ctl flow by updating nextPC and operating privilege */
function handle_trap(del_priv : Privilege, intr : bool, c : exc_code, pc : xlenbits, info : option(xlenbits))
-> xlenbits = {
+ rvfi_trap();
print("handling " ^ (if intr then "int#" else "exc#") ^ BitStr(c) ^ " at priv " ^ del_priv ^ " with tval " ^ BitStr(tval(info)));
match (del_priv) {
diff --git a/riscv/riscv_types.sail b/riscv/riscv_types.sail
index 4cbc6f87..7e29ef3c 100644
--- a/riscv/riscv_types.sail
+++ b/riscv/riscv_types.sail
@@ -114,6 +114,17 @@ function rX r = match r {
31 => x31
}
+$ifdef RVFI_DII
+val rvfi_wX : forall 'n, 0 <= 'n < 32. (regno('n), xlenbits) -> unit effect {wreg}
+function rvfi_wX (r,v) = {
+ rvfi_exec->rvfi_rd_wdata() = v;
+ rvfi_exec->rvfi_rd_addr() = to_bits(8,r);
+}
+$else
+val rvfi_wX : forall 'n, 0 <= 'n < 32. (regno('n), xlenbits) -> unit
+function rvfi_wX (r,v) = ()
+$endif
+
val wX : forall 'n, 0 <= 'n < 32. (regno('n), xlenbits) -> unit effect {wreg}
function wX (r, v) = {
match r {
@@ -151,6 +162,7 @@ function wX (r, v) = {
31 => x31 = v
};
if (r != 0) then {
+ rvfi_wX(r,v);
// Xs[r] = v;
print("x" ^ string_of_int(r) ^ " <- " ^ BitStr(v));
}
diff --git a/riscv/rvfi_dii.sail b/riscv/rvfi_dii.sail
new file mode 100644
index 00000000..9680ab49
--- /dev/null
+++ b/riscv/rvfi_dii.sail
@@ -0,0 +1,98 @@
+// "RISC-V Formal Interface - Direct Instruction Injection" support
+// For use with https://github.com/CTSRD-CHERI/TestRIG
+
+$define RVFI_DII
+
+bitfield RVFI_DII_Instruction_Packet : bits(64) = {
+ padding : 63 .. 56, // [7]
+ rvfi_cmd : 55 .. 48, // [6] This token is a trace command. For example, reset device under test.
+ rvfi_time : 47 .. 32, // [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.
+ rvfi_insn : 31 .. 0, // [0 - 3] Instruction word: 32-bit instruction or command. The lower 16-bits
+ // may decode to a 16-bit compressed instruction.
+}
+
+register rvfi_instruction : RVFI_DII_Instruction_Packet
+
+val rvfi_set_instr_packet : bits(64) -> unit effect {wreg}
+
+function rvfi_set_instr_packet(p) =
+ rvfi_instruction = Mk_RVFI_DII_Instruction_Packet(p)
+
+val rvfi_get_cmd : unit -> bits(8) effect {rreg}
+
+function rvfi_get_cmd () = rvfi_instruction.rvfi_cmd()
+
+val print_instr_packet : bits(64) -> unit
+
+function print_instr_packet(bs) = {
+ let p = Mk_RVFI_DII_Instruction_Packet(bs);
+ print_bits("command", p.rvfi_cmd());
+ print_bits("instruction", p.rvfi_insn())
+}
+
+bitfield RVFI_DII_Execution_Packet : bits(704) = {
+ rvfi_intr : 703 .. 696, // [87] Trap handler: Set for first instruction in trap handler.
+ rvfi_halt : 695 .. 688, // [86] Halt indicator: Marks the last instruction retired
+ // before halting execution.
+ rvfi_trap : 687 .. 680, // [85] Trap indicator: Invalid decode, misaligned access or
+ // jump command to misaligned address.
+ rvfi_rd_addr : 679 .. 672, // [84] Write register address: MUST be 0 if not used.
+ rvfi_rs2_addr : 671 .. 664, // [83] otherwise set as decoded.
+ rvfi_rs1_addr : 663 .. 656, // [82] Read register addresses: Can be arbitrary when not used,
+ rvfi_mem_wmask : 655 .. 648, // [81] Write mask: Indicates valid bytes written. 0 if unused.
+ rvfi_mem_rmask : 647 .. 640, // [80] Read mask: Indicates valid bytes read. 0 if unused.
+ rvfi_mem_wdata : 639 .. 576, // [72 - 79] Write data: Data written to memory by this command.
+ rvfi_mem_rdata : 575 .. 512, // [64 - 71] Read data: Data read from mem_addr (i.e. before write)
+ rvfi_mem_addr : 511 .. 448, // [56 - 63] Memory access addr: Points to byte address (aligned if define
+ // is set). *Should* be straightforward.
+ // 0 if unused.
+ rvfi_rd_wdata : 447 .. 384, // [48 - 55] Write register value: MUST be 0 if rd_ is 0.
+ rvfi_rs2_data : 383 .. 320, // [40 - 47] above. Must be 0 if register ID is 0.
+ rvfi_rs1_data : 319 .. 256, // [32 - 39] Read register values: Values as read from registers named
+ rvfi_insn : 255 .. 192, // [24 - 31] Instruction word: 32-bit command value.
+ rvfi_pc_wdata : 191 .. 128, // [16 - 23] PC after instr: Following PC - either PC + 4 or jump/trap target.
+ rvfi_pc_rdata : 127 .. 64, // [08 - 15] PC before instr: PC for current instruction
+ rvfi_order : 63 .. 0, // [00 - 07] Instruction number: INSTRET value after completion.
+}
+
+register rvfi_exec : RVFI_DII_Execution_Packet
+
+val rvfi_zero_exec_packet : unit -> unit effect {wreg}
+
+function rvfi_zero_exec_packet () =
+ rvfi_exec = Mk_RVFI_DII_Execution_Packet(zero_extend(0b0,704))
+
+val rvfi_halt_exec_packet : unit -> unit effect {wreg}
+
+function rvfi_halt_exec_packet () =
+ rvfi_exec->rvfi_halt() = 0x01
+
+val rvfi_get_exec_packet : unit -> bits(704) effect {rreg}
+
+function rvfi_get_exec_packet() = rvfi_exec.bits()
+
+val print_rvfi_exec : unit -> unit effect {rreg}
+
+function print_rvfi_exec () = {
+ print_bits("rvfi_intr : ", rvfi_exec.rvfi_intr());
+ print_bits("rvfi_halt : ", rvfi_exec.rvfi_halt());
+ print_bits("rvfi_trap : ", rvfi_exec.rvfi_trap());
+ print_bits("rvfi_rd_addr : ", rvfi_exec.rvfi_rd_addr());
+ print_bits("rvfi_rs2_addr : ", rvfi_exec.rvfi_rs2_addr());
+ print_bits("rvfi_rs1_addr : ", rvfi_exec.rvfi_rs1_addr());
+ print_bits("rvfi_mem_wmask: ", rvfi_exec.rvfi_mem_wmask());
+ print_bits("rvfi_mem_rmask: ", rvfi_exec.rvfi_mem_rmask());
+ print_bits("rvfi_mem_wdata: ", rvfi_exec.rvfi_mem_wdata());
+ print_bits("rvfi_mem_rdata: ", rvfi_exec.rvfi_mem_rdata());
+ print_bits("rvfi_mem_addr : ", rvfi_exec.rvfi_mem_addr());
+ print_bits("rvfi_rd_wdata : ", rvfi_exec.rvfi_rd_wdata());
+ print_bits("rvfi_rs2_data : ", rvfi_exec.rvfi_rs2_data());
+ print_bits("rvfi_rs1_data : ", rvfi_exec.rvfi_rs1_data());
+ print_bits("rvfi_insn : ", rvfi_exec.rvfi_insn());
+ print_bits("rvfi_pc_wdata : ", rvfi_exec.rvfi_pc_wdata());
+ print_bits("rvfi_pc_rdata : ", rvfi_exec.rvfi_pc_rdata());
+ print_bits("rvfi_order : ", rvfi_exec.rvfi_order());
+}