From 08ee0589bb65c293502299e181a9490bb0525bc0 Mon Sep 17 00:00:00 2001 From: Ksenia Dobrovolskaya Date: Tue, 11 Jun 2024 14:48:28 +0300 Subject: [PATCH 1/3] Implementing callbacks in sail-riscv for state-changing events 1. Added callback functions for XRegs, FRegs, VRegs, PC, CSR, memory writes and CSR, memory reads. 2. Added implementation of callbacks for RVFI records in riscv_rvfi_callbacks.c. 3. Added default callback OCaml-implementations in the file platform.ml. --- Makefile | 11 +- c_emulator/riscv_config.h | 1 + c_emulator/riscv_default_callbacks.c | 11 ++ c_emulator/riscv_rvfi_callbacks.c | 37 +++++ c_emulator/riscv_sail.h | 14 ++ c_emulator/riscv_sim.c | 2 + model/prelude.sail | 1 - model/riscv_fdext_regs.sail | 7 +- model/riscv_insts_vext_mem.sail | 9 +- model/riscv_insts_vext_vset.sail | 22 +-- model/riscv_insts_zicsr.sail | 6 +- model/riscv_mem.sail | 51 ++----- model/riscv_pc_access.sail | 1 + model/riscv_regs.sail | 14 +- model/riscv_sys_control.sail | 16 +-- model/riscv_types.sail | 15 ++ model/riscv_vext_regs.sail | 3 +- model/riscv_vreg_type.sail | 5 + model/rvfi_dii.sail | 44 ++++++ ocaml_emulator/platform.ml | 197 +++++++++++++++++++++++++++ test/run_tests.sh | 0 21 files changed, 370 insertions(+), 97 deletions(-) create mode 100644 c_emulator/riscv_default_callbacks.c create mode 100644 c_emulator/riscv_rvfi_callbacks.c create mode 100644 ocaml_emulator/platform.ml mode change 100755 => 100644 test/run_tests.sh diff --git a/Makefile b/Makefile index 6e6483320..cff1d2fd3 100644 --- a/Makefile +++ b/Makefile @@ -225,11 +225,11 @@ c_preserve_fns=-c_preserve _set_Misa_C generated_definitions/c/riscv_model_$(ARCH).c: $(SAIL_SRCS) model/main.sail Makefile mkdir -p generated_definitions/c - $(SAIL) $(SAIL_FLAGS) $(c_preserve_fns) -O -Oconstant_fold -memo_z3 -c -c_include riscv_prelude.h -c_include riscv_platform.h -c_no_main $(SAIL_SRCS) model/main.sail -o $(basename $@) + $(SAIL) $(SAIL_FLAGS) $(c_preserve_fns) -O -Oconstant_fold -memo_z3 -c -c_include riscv_default_callbacks.c -c_include riscv_prelude.h -c_include riscv_platform.h -c_no_main $(SAIL_SRCS) model/main.sail -o $(basename $@) generated_definitions/c2/riscv_model_$(ARCH).c: $(SAIL_SRCS) model/main.sail Makefile mkdir -p generated_definitions/c2 - $(SAIL) $(SAIL_FLAGS) -no_warn -memo_z3 -config c_emulator/config.json -c2 $(SAIL_SRCS) -o $(basename $@) + $(SAIL) $(SAIL_FLAGS) -no_warn -memo_z3 -config c_emulator/config.json -c2 -c_include riscv_default_callbacks.c $(SAIL_SRCS) -o $(basename $@) $(SOFTFLOAT_LIBS): $(MAKE) SPECIALIZE_TYPE=$(SOFTFLOAT_SPECIALIZE_TYPE) -C $(SOFTFLOAT_LIBDIR) @@ -255,13 +255,18 @@ rvfi_preserve_fns=-c_preserve rvfi_set_instr_packet \ -c_preserve rvfi_get_int_data \ -c_preserve rvfi_zero_exec_packet \ -c_preserve rvfi_halt_exec_packet \ + -c_preserve rvfi_write \ + -c_preserve rvfi_read \ + -c_preserve rvfi_mem_exception \ + -c_preserve rvfi_wX \ + -c_preserve print_rvfi_exec \ -c_preserve print_instr_packet \ -c_preserve print_rvfi_exec # sed -i isn't posix compliant, unfortunately generated_definitions/c/riscv_rvfi_model_$(ARCH).c: $(SAIL_RVFI_SRCS) model/main.sail Makefile mkdir -p generated_definitions/c - $(SAIL) $(c_preserve_fns) $(rvfi_preserve_fns) $(SAIL_FLAGS) -O -Oconstant_fold -memo_z3 -c -c_include riscv_prelude.h -c_include riscv_platform.h -c_no_main $(SAIL_RVFI_SRCS) model/main.sail -o $(basename $@) + $(SAIL) $(c_preserve_fns) $(rvfi_preserve_fns) $(SAIL_FLAGS) -O -Oconstant_fold -memo_z3 -c -c_include riscv_prelude.h -c_include riscv_platform.h -c_no_main $(SAIL_RVFI_SRCS) -c_include riscv_rvfi_callbacks.c model/main.sail -o $(basename $@) sed -e '/^[[:space:]]*$$/d' $@ > $@.new mv $@.new $@ diff --git a/c_emulator/riscv_config.h b/c_emulator/riscv_config.h index 0f662310d..d2ce50649 100644 --- a/c_emulator/riscv_config.h +++ b/c_emulator/riscv_config.h @@ -6,3 +6,4 @@ extern bool config_print_step; extern bool config_print_reg; extern bool config_print_mem_access; extern bool config_print_platform; +extern bool rv_enable_callbacks; diff --git a/c_emulator/riscv_default_callbacks.c b/c_emulator/riscv_default_callbacks.c new file mode 100644 index 000000000..fd7fa3e84 --- /dev/null +++ b/c_emulator/riscv_default_callbacks.c @@ -0,0 +1,11 @@ +/* The model assumes that these functions do not change the state of the model. + */ +int mem_write_callback(uint64_t addr, uint64_t width, lbits value) { } +int mem_read_callback(uint64_t addr, uint64_t width, lbits value) { } +int mem_exception_callback(uint64_t addr, uint64_t num_of_exception) { } +int xreg_write_callback(unsigned reg, uint64_t value) { } +int freg_write_callback(unsigned reg, uint64_t value) { } +int csr_write_callback(unsigned reg, uint64_t value) { } +int csr_read_callback(unsigned reg, uint64_t value) { } +int vreg_write_callback(unsigned reg, lbits value) { } +int pc_write_callback(uint64_t value) { } diff --git a/c_emulator/riscv_rvfi_callbacks.c b/c_emulator/riscv_rvfi_callbacks.c new file mode 100644 index 000000000..77cd37e8e --- /dev/null +++ b/c_emulator/riscv_rvfi_callbacks.c @@ -0,0 +1,37 @@ +#include "riscv_config.h" + +int zrvfi_write(uint64_t addr, int64_t width, lbits value); +int zrvfi_read(uint64_t addr, sail_int width, lbits value); +int zrvfi_mem_exception(uint64_t addr); +int zrvfi_wX(int64_t reg, uint64_t value); + +int mem_write_callback(uint64_t addr, uint64_t width, lbits value) +{ + if (rv_enable_callbacks) + zrvfi_write(addr, width, value); +} +int mem_read_callback(uint64_t addr, uint64_t width, lbits value) +{ + if (rv_enable_callbacks) { + sail_int len; + CREATE(sail_int)(&len); + CONVERT_OF(sail_int, mach_int)(&len, width); + zrvfi_read(addr, len, value); + KILL(sail_int)(&len); + } +} +int mem_exception_callback(uint64_t addr, uint64_t num_of_exception) +{ + if (rv_enable_callbacks) + zrvfi_mem_exception(addr); +} +int xreg_write_callback(unsigned reg, uint64_t value) +{ + if (rv_enable_callbacks) + zrvfi_wX(reg, value); +} +int freg_write_callback(unsigned reg, uint64_t value) { } +int csr_write_callback(unsigned reg, uint64_t value) { } +int csr_read_callback(unsigned reg, uint64_t value) { } +int vreg_write_callback(unsigned reg, lbits value) { } +int pc_write_callback(uint64_t value) { } diff --git a/c_emulator/riscv_sail.h b/c_emulator/riscv_sail.h index da29c2ba9..e7247fc58 100644 --- a/c_emulator/riscv_sail.h +++ b/c_emulator/riscv_sail.h @@ -50,6 +50,20 @@ extern bool zhtif_done; extern mach_bits zhtif_exit_code; extern bool have_exception; +/* Callbacks for state-changing events */ + +/* The model assumes that these functions do not change the state of the model. + */ +int mem_write_callback(uint64_t addr, uint64_t width, lbits value); +int mem_read_callback(uint64_t addr, uint64_t width, lbits value); +int mem_exception_callback(uint64_t addr, uint64_t num_of_exception); +int xreg_write_callback(unsigned reg, uint64_t value); +int freg_write_callback(unsigned reg, uint64_t value); +int csr_write_callback(unsigned reg, uint64_t value); +int csr_read_callback(unsigned reg, uint64_t value); +int vreg_write_callback(unsigned reg, lbits value); +int pc_write_callback(uint64_t value); + /* machine state */ extern uint32_t zcur_privilege; diff --git a/c_emulator/riscv_sim.c b/c_emulator/riscv_sim.c index 3f812c5ec..d3066c7d7 100644 --- a/c_emulator/riscv_sim.c +++ b/c_emulator/riscv_sim.c @@ -93,6 +93,7 @@ bool config_print_mem_access = true; bool config_print_platform = true; bool config_print_rvfi = false; bool config_print_step = false; +bool rv_enable_callbacks = true; void set_config_print(char *var, bool val) { @@ -102,6 +103,7 @@ void set_config_print(char *var, bool val) config_print_reg = val; config_print_platform = val; config_print_rvfi = val; + rv_enable_callbacks = val; } else if (strcmp("instr", var) == 0) { config_print_instr = val; } else if (strcmp("reg", var) == 0) { diff --git a/model/prelude.sail b/model/prelude.sail index 8c03c58da..01eb3277b 100644 --- a/model/prelude.sail +++ b/model/prelude.sail @@ -76,7 +76,6 @@ val get_config_print_mem = pure {c:"get_config_print_mem"} : unit -> bool val get_config_print_platform = pure {c:"get_config_print_platform"} : unit -> bool // defaults for other backends function get_config_print_instr () = false -function get_config_print_reg () = false function get_config_print_mem () = false function get_config_print_platform () = false diff --git a/model/riscv_fdext_regs.sail b/model/riscv_fdext_regs.sail index bb6860121..488ee8c8b 100644 --- a/model/riscv_fdext_regs.sail +++ b/model/riscv_fdext_regs.sail @@ -193,11 +193,8 @@ function wF (r : regno, in_v : flenbits) -> unit = { }; dirty_fd_context(); - - if get_config_print_reg() - then - /* TODO: will only print bits; should we print in floating point format? */ - print_reg("f" ^ dec_str(r) ^ " <- " ^ FRegStr(v)); + + freg_write_callback(regno_to_regidx(r), in_v); } function rF_bits(i: regidx) -> flenbits = rF(unsigned(i)) diff --git a/model/riscv_insts_vext_mem.sail b/model/riscv_insts_vext_mem.sail index cc8161304..928747433 100644 --- a/model/riscv_insts_vext_mem.sail +++ b/model/riscv_insts_vext_mem.sail @@ -154,7 +154,7 @@ function process_vlsegff (nf, vm, vd, load_width_bytes, rs1, EMUL_pow, num_elem) if i == 0 then { ext_handle_data_check_error(e); return RETIRE_FAIL } else { vl = to_bits(xlen, i); - print_reg("CSR vl <- " ^ BitStr(vl)); + csr_write_callback(csr_name_map("vl"), vl); trimmed = true } }, @@ -163,7 +163,7 @@ function process_vlsegff (nf, vm, vd, load_width_bytes, rs1, EMUL_pow, num_elem) if i == 0 then { handle_mem_exception(vaddr, E_Load_Addr_Align()); return RETIRE_FAIL } else { vl = to_bits(xlen, i); - print_reg("CSR vl <- " ^ BitStr(vl)); + csr_write_callback(csr_name_map("vl"), vl); trimmed = true } } else match translateAddr(vaddr, Read(Data)) { @@ -171,7 +171,7 @@ function process_vlsegff (nf, vm, vd, load_width_bytes, rs1, EMUL_pow, num_elem) if i == 0 then { handle_mem_exception(vaddr, e); return RETIRE_FAIL } else { vl = to_bits(xlen, i); - print_reg("CSR vl <- " ^ BitStr(vl)); + csr_write_callback(csr_name_map("vl"), vl); trimmed = true } }, @@ -182,7 +182,8 @@ function process_vlsegff (nf, vm, vd, load_width_bytes, rs1, EMUL_pow, num_elem) if i == 0 then { handle_mem_exception(vaddr, e); return RETIRE_FAIL } else { vl = to_bits(xlen, i); - print_reg("CSR vl <- " ^ BitStr(vl)); + csr_write_callback(csr_name_map("vl"), vl); +>>>>>>> cb0b429d (Implementing callbacks in sail-riscv for state-changing events) trimmed = true } } diff --git a/model/riscv_insts_vext_vset.sail b/model/riscv_insts_vext_vset.sail index 9cbed51fd..d0b8eba89 100644 --- a/model/riscv_insts_vext_vset.sail +++ b/model/riscv_insts_vext_vset.sail @@ -51,8 +51,8 @@ function handle_illegal_vtype() = { */ vtype.bits = 0b1 @ zeros(xlen - 1); /* set vtype.vill */ vl = zeros(); - print_reg("CSR vtype <- " ^ BitStr(vtype.bits)); - print_reg("CSR vl <- " ^ BitStr(vl)) + csr_write_callback(csr_name_map("vtype"), vtype.bits); + csr_write_callback(csr_name_map("vl"), vl); } val calculate_new_vl : (int, int) -> xlenbits @@ -106,9 +106,9 @@ function clause execute VSETVLI(ma, ta, sew, lmul, rs1, rd) = { /* reset vstart to 0 */ vstart = zeros(); - print_reg("CSR vtype <- " ^ BitStr(vtype.bits)); - print_reg("CSR vl <- " ^ BitStr(vl)); - print_reg("CSR vstart <- " ^ BitStr(vstart)); + csr_write_callback(csr_name_map("vtype"), vtype.bits); + csr_write_callback(csr_name_map("vl"), vl); + csr_write_callback(csr_name_map("vstart"), zero_extend(vstart)); RETIRE_SUCCESS } @@ -157,9 +157,9 @@ function clause execute VSETVL(rs2, rs1, rd) = { /* reset vstart to 0 */ vstart = zeros(); - print_reg("CSR vtype <- " ^ BitStr(vtype.bits)); - print_reg("CSR vl <- " ^ BitStr(vl)); - print_reg("CSR vstart <- " ^ BitStr(vstart)); + csr_write_callback(csr_name_map("vtype"), vtype.bits); + csr_write_callback(csr_name_map("vl"), vl); + csr_write_callback(csr_name_map("vstart"), zero_extend(vstart)); RETIRE_SUCCESS } @@ -193,9 +193,9 @@ function clause execute VSETIVLI(ma, ta, sew, lmul, uimm, rd) = { /* reset vstart to 0 */ vstart = zeros(); - print_reg("CSR vtype <- " ^ BitStr(vtype.bits)); - print_reg("CSR vl <- " ^ BitStr(vl)); - print_reg("CSR vstart <- " ^ BitStr(vstart)); + csr_write_callback(csr_name_map("vtype"), vtype.bits); + csr_write_callback(csr_name_map("vl"), vl); + csr_write_callback(csr_name_map("vstart"), zero_extend(vstart)); RETIRE_SUCCESS } diff --git a/model/riscv_insts_zicsr.sail b/model/riscv_insts_zicsr.sail index 5e4d47b9e..92863b3bc 100644 --- a/model/riscv_insts_zicsr.sail +++ b/model/riscv_insts_zicsr.sail @@ -193,11 +193,9 @@ function clause execute CSR(csr, rs1, rd, is_imm, op) = { CSRRC => csr_val & ~(rs1_val) }; let final_val = write_CSR(csr, new_val); - if get_config_print_reg() - then print_reg("CSR " ^ to_str(csr) ^ " <- " ^ bits_str(final_val) ^ " (input: " ^ bits_str(new_val) ^ ")") + csr_write_callback(csr, final_val); } else { - if get_config_print_reg() - then print_reg("CSR " ^ to_str(csr) ^ " -> " ^ bits_str(csr_val)); + csr_read_callback(csr, csr_val); }; X(rd) = csr_val; RETIRE_SUCCESS diff --git a/model/riscv_mem.sail b/model/riscv_mem.sail index 82227ad7e..3468ce702 100644 --- a/model/riscv_mem.sail +++ b/model/riscv_mem.sail @@ -117,25 +117,6 @@ function checked_mem_read forall 'n, 0 < 'n <= max_mem_access . ( /* Atomic accesses can be done to MMIO regions, e.g. in kernel access to device registers. */ -$ifdef RVFI_DII -val rvfi_read : forall 'n, 'n > 0. (xlenbits, int('n), MemoryOpResult((bits(8 * 'n), mem_meta))) -> unit -function rvfi_read (addr, width, result) = { - rvfi_mem_data[rvfi_mem_addr] = zero_extend(addr); - rvfi_mem_data_present = true; - match result { - /* TODO: report tag bit for capability writes and extend mask by one bit. */ - MemValue(v, _) => if width <= 16 - then { rvfi_mem_data[rvfi_mem_rdata] = sail_zero_extend(v, 256); - rvfi_mem_data[rvfi_mem_rmask] = rvfi_encode_width_mask(width) } - else { internal_error(__FILE__, __LINE__, "Expected at most 16 bytes here!") }, - MemException(_) => () - }; -} -$else -val rvfi_read : forall 'n, 'n > 0. (xlenbits, int('n), MemoryOpResult((bits(8 * 'n), mem_meta))) -> unit -function rvfi_read (addr, width, result) = () -$endif - val mem_read : forall 'n, 0 < 'n <= max_mem_access . (AccessType(ext_access_type), xlenbits, int('n), bool, bool, bool) -> MemoryOpResult(bits(8 * 'n)) val mem_read_priv : forall 'n, 0 < 'n <= max_mem_access . (AccessType(ext_access_type), Privilege, xlenbits, int('n), bool, bool, bool) -> MemoryOpResult(bits(8 * 'n)) val mem_read_meta : forall 'n, 0 < 'n <= max_mem_access . (AccessType(ext_access_type), xlenbits, int('n), bool, bool, bool, bool) -> MemoryOpResult((bits(8 * 'n), mem_meta)) @@ -151,7 +132,10 @@ function mem_read_priv_meta (typ, priv, paddr, width, aq, rl, res, meta) = { (false, true, true) => throw(Error_not_implemented("lr.rl")), (_, _, _) => checked_mem_read(typ, priv, paddr, width, aq, rl, res, meta) }; - rvfi_read(paddr, width, result); + match result { + MemValue(value, _) => mem_read_callback(paddr, width, value), + MemException(e) => mem_exception_callback(paddr, num_of_ExceptionType(e)) + }; result } @@ -172,28 +156,6 @@ function mem_write_ea (addr, width, aq, rl, con) = then MemException(E_SAMO_Addr_Align()) else MemValue(write_ram_ea(write_kind_of_flags(aq, rl, con), addr, width)) -$ifdef RVFI_DII -val rvfi_write : forall 'n, 0 < 'n <= max_mem_access . (xlenbits, int('n), bits(8 * 'n), mem_meta, MemoryOpResult(bool)) -> unit -function rvfi_write (addr, width, value, meta, result) = { - rvfi_mem_data[rvfi_mem_addr] = zero_extend(addr); - rvfi_mem_data_present = true; - match result { - /* Log only the memory address (without the value) if the write fails. */ - MemValue(_) => if width <= 16 then { - /* TODO: report tag bit for capability writes and extend mask by one bit. */ - rvfi_mem_data[rvfi_mem_wdata] = sail_zero_extend(value,256); - rvfi_mem_data[rvfi_mem_wmask] = rvfi_encode_width_mask(width); - } else { - internal_error(__FILE__, __LINE__, "Expected at most 16 bytes here!"); - }, - MemException(_) => () - } -} -$else -val rvfi_write : forall 'n, 'n > 0. (xlenbits, int('n), bits(8 * 'n), mem_meta, MemoryOpResult(bool)) -> unit -function rvfi_write (addr, width, value, meta, result) = () -$endif - // only used for actual memory regions, to avoid MMIO effects function phys_mem_write forall 'n, 0 < 'n <= max_mem_access . (wk : write_kind, paddr : xlenbits, width : int('n), data : bits(8 * 'n), meta : mem_meta) -> MemoryOpResult(bool) = { let result = MemValue(write_ram(wk, paddr, width, data, meta)); @@ -243,7 +205,10 @@ function mem_write_value_priv_meta (paddr, width, value, typ, priv, meta, aq, rl then MemException(E_SAMO_Addr_Align()) else { let result = checked_mem_write(paddr, width, value, typ, priv, meta, aq, rl, con); - rvfi_write(paddr, width, value, meta, result); + match result { + MemValue(_) => mem_write_callback(paddr, width, value), + MemException(e) => mem_exception_callback(paddr, num_of_ExceptionType(e)) + }; result } } diff --git a/model/riscv_pc_access.sail b/model/riscv_pc_access.sail index 018512336..372efeec9 100644 --- a/model/riscv_pc_access.sail +++ b/model/riscv_pc_access.sail @@ -28,5 +28,6 @@ function set_next_pc(pc) = { val tick_pc : unit -> unit function tick_pc() = { + pc_write_callback(PC); PC = nextPC } diff --git a/model/riscv_regs.sail b/model/riscv_regs.sail index 26faef210..6d18e468e 100644 --- a/model/riscv_regs.sail +++ b/model/riscv_regs.sail @@ -88,16 +88,6 @@ function rX (r : regno) -> xlenbits = { regval_from_reg(v) } -$ifdef RVFI_DII -function rvfi_wX (r : regno, v : xlenbits) -> unit = { - rvfi_int_data[rvfi_rd_wdata] = zero_extend(v); - rvfi_int_data[rvfi_rd_addr] = to_bits(8,r); - rvfi_int_data_present = true; -} -$else -function rvfi_wX (r : regno, v : xlenbits) -> unit = () -$endif - function wX (r : regno, in_v : xlenbits) -> unit = { let v = regval_into_reg(in_v); match r { @@ -136,9 +126,7 @@ function wX (r : regno, in_v : xlenbits) -> unit = { _ => assert(false, "invalid register number") }; if (r != 0) then { - rvfi_wX(r, in_v); - if get_config_print_reg() - then print_reg("x" ^ dec_str(r) ^ " <- " ^ RegStr(v)); + xreg_write_callback(regno_to_regidx(r), in_v); } } diff --git a/model/riscv_sys_control.sail b/model/riscv_sys_control.sail index a2835dda1..201e1eebc 100644 --- a/model/riscv_sys_control.sail +++ b/model/riscv_sys_control.sail @@ -314,8 +314,7 @@ function trap_handler(del_priv : Privilege, intr : bool, c : exc_code, pc : xlen handle_trap_extension(del_priv, pc, ext); - if get_config_print_reg() - then print_reg("CSR mstatus <- " ^ BitStr(mstatus.bits)); + csr_write_callback(csr_name_map("mstatus"), mstatus.bits); prepare_trap_vector(del_priv, mcause) }, @@ -339,8 +338,7 @@ function trap_handler(del_priv : Privilege, intr : bool, c : exc_code, pc : xlen handle_trap_extension(del_priv, pc, ext); - if get_config_print_reg() - then print_reg("CSR mstatus <- " ^ BitStr(mstatus.bits)); + csr_write_callback(csr_name_map("mstatus"), mstatus.bits); prepare_trap_vector(del_priv, scause) }, @@ -367,8 +365,7 @@ function exception_handler(cur_priv : Privilege, ctl : ctl_result, if cur_privilege != Machine then mstatus[MPRV] = 0b0; - if get_config_print_reg() - then print_reg("CSR mstatus <- " ^ BitStr(mstatus.bits)); + csr_write_callback(csr_name_map("mstatus"), mstatus.bits); if get_config_print_platform() then print_platform("ret-ing from " ^ to_str(prev_priv) ^ " to " ^ to_str(cur_privilege)); @@ -383,8 +380,7 @@ function exception_handler(cur_priv : Privilege, ctl : ctl_result, if cur_privilege != Machine then mstatus[MPRV] = 0b0; - if get_config_print_reg() - then print_reg("CSR mstatus <- " ^ BitStr(mstatus.bits)); + csr_write_callback(csr_name_map("mstatus"), mstatus.bits); if get_config_print_platform() then print_platform("ret-ing from " ^ to_str(prev_priv) ^ " to " ^ to_str(cur_privilege)); @@ -490,9 +486,7 @@ function init_sys() -> unit = { // PMP's L and A fields are set to 0 on reset. init_pmp(); - // log compatibility with spike - if get_config_print_reg() - then print_reg("CSR mstatus <- " ^ BitStr(mstatus.bits) ^ " (input: " ^ BitStr(zeros() : xlenbits) ^ ")") + csr_write_callback(csr_name_map("mstatus"), mstatus.bits); } /* memory access exceptions, defined here for use by the platform model. */ diff --git a/model/riscv_types.sail b/model/riscv_types.sail index c333c4e17..abd9fbe30 100644 --- a/model/riscv_types.sail +++ b/model/riscv_types.sail @@ -43,6 +43,8 @@ type regno = range(0, 31) function regidx_to_regno (b : regidx) -> regno = unsigned(b) +function regno_to_regidx (b : regno) -> regidx = to_bits(5, b) + /* mapping RVC register indices into normal indices */ val creg2reg_idx : cregidx -> regidx function creg2reg_idx(creg) = 0b01 @ creg @@ -410,3 +412,16 @@ function report_invalid_width(f , l, w, k) -> 'a = { internal_error(f, l, "Invalid width, " ^ size_mnemonic(w) ^ ", for " ^ k ^ " with xlen=" ^ dec_str(xlen)) } + +/* Callbacks for state-changing events */ + +/* Defaults for these functions in riscv_default_callbacks.c and platform_impl.ml */ + +val mem_write_callback = pure {ocaml: "Platform.mem_write_callback", c: "mem_write_callback"} : forall 'n, 0 < 'n <= max_mem_access . (/* addr */ xlenbits, /* width */ int('n), /* value */ bits(8 * 'n)) -> unit +val mem_read_callback = pure {ocaml: "Platform.mem_read_callback", c: "mem_read_callback"} : forall 'n, 0 < 'n <= max_mem_access . (/* addr */ xlenbits, /* width */ int('n), /* value */ bits(8 * 'n)) -> unit +val mem_exception_callback = pure {ocaml: "Platform.mem_exception_callback", c: "mem_exception_callback"} : forall 'n, 0 <= 'n < xlen . (/* addr */ xlenbits, /* num_of_ExceptionType */ int('n)) -> unit +val pc_write_callback = pure {ocaml: "Platform.pc_write_callback", c: "pc_write_callback"} : xlenbits -> unit +val xreg_write_callback = pure {ocaml: "Platform.xreg_write_callback", c: "xreg_write_callback"} : (regidx, xlenbits) -> unit +val freg_write_callback = pure {ocaml: "Platform.freg_write_callback", c: "freg_write_callback"} : (regidx, flenbits) -> unit +val csr_write_callback = pure {ocaml: "Platform.csr_write_callback", c: "csr_write_callback"} : (csreg, xlenbits) -> unit +val csr_read_callback = pure {ocaml: "Platform.csr_read_callback", c: "csr_read_callback"} : (csreg, xlenbits) -> unit diff --git a/model/riscv_vext_regs.sail b/model/riscv_vext_regs.sail index aadd05bc2..6920aad87 100644 --- a/model/riscv_vext_regs.sail +++ b/model/riscv_vext_regs.sail @@ -163,8 +163,7 @@ function wV (r : regno, v : vregtype) -> unit = { let VLEN = unsigned(vlenb) * 8; assert(0 < VLEN & VLEN <= sizeof(vlenmax)); - if get_config_print_reg() - then print_reg("v" ^ dec_str(r) ^ " <- " ^ BitStr(v[VLEN - 1 .. 0])); + vreg_write_callback(regno_to_regidx(r), v); } function rV_bits(i: regidx) -> vregtype = rV(unsigned(i)) diff --git a/model/riscv_vreg_type.sail b/model/riscv_vreg_type.sail index 2ab211b8c..5ab69305a 100755 --- a/model/riscv_vreg_type.sail +++ b/model/riscv_vreg_type.sail @@ -146,3 +146,8 @@ enum fwffunct6 = { FWF_VADD, FWF_VSUB } enum fvfmfunct6 = { VFM_VMFEQ, VFM_VMFLE, VFM_VMFLT, VFM_VMFNE, VFM_VMFGT, VFM_VMFGE } enum vmlsop = { VLM, VSM } + +/* Callbacks for vregs state-changing events */ + +/* Default for this function in riscv_default_callbacks.c and platform_impl.ml */ +val vreg_write_callback = pure {ocaml: "Platform.vreg_write_callback", c: "vreg_write_callback"} : (regidx, vregtype) -> unit diff --git a/model/rvfi_dii.sail b/model/rvfi_dii.sail index 6b02155b0..59108bab2 100644 --- a/model/rvfi_dii.sail +++ b/model/rvfi_dii.sail @@ -325,3 +325,47 @@ function print_rvfi_exec () = { print_bits("rvfi_pc_rdata : ", rvfi_pc_data[rvfi_pc_rdata]); print_bits("rvfi_order : ", rvfi_inst_data[rvfi_order]); } + +/* RVFI records */ + +val internal_error : forall ('a : Type). (string, int, string) -> 'a + +val rvfi_write : forall 'n, 0 < 'n <= max_mem_access . (xlenbits, int('n), bits(8 * 'n)) -> unit +function rvfi_write (addr, width, value) = { + rvfi_mem_data[rvfi_mem_addr] = zero_extend(addr); + rvfi_mem_data_present = true; + if width <= 16 then { + /* TODO: report tag bit for capability writes and extend mask by one bit. */ + rvfi_mem_data[rvfi_mem_wdata] = sail_zero_extend(value, 256); + rvfi_mem_data[rvfi_mem_wmask] = rvfi_encode_width_mask(width); + } else { + internal_error(__FILE__, __LINE__, "Expected at most 16 bytes here!"); + }; +} + +val rvfi_read : forall 'n, 'n > 0. (xlenbits, int('n), bits(8 * 'n)) -> unit +function rvfi_read (addr, width, value) = { + rvfi_mem_data[rvfi_mem_addr] = zero_extend(addr); + rvfi_mem_data_present = true; + if width <= 16 then { + /* TODO: report tag bit for capability writes and extend mask by one bit. */ + rvfi_mem_data[rvfi_mem_rdata] = sail_zero_extend(value, 256); + rvfi_mem_data[rvfi_mem_rmask] = rvfi_encode_width_mask(width) + } else { + internal_error(__FILE__, __LINE__, "Expected at most 16 bytes here!") + }; +} + +val rvfi_mem_exception : xlenbits -> unit +function rvfi_mem_exception (addr) = { + /* Log only the memory address (without the value) if the write fails. */ + rvfi_mem_data[rvfi_mem_addr] = zero_extend(addr); + rvfi_mem_data_present = true; +} + +val rvfi_wX : forall 'n, 0 <= 'n < 32. (int('n), xlenbits) -> unit +function rvfi_wX (r,v) = { + rvfi_int_data[rvfi_rd_wdata] = zero_extend(v); + rvfi_int_data[rvfi_rd_addr] = to_bits(8, r); + rvfi_int_data_present = true; +} diff --git a/ocaml_emulator/platform.ml b/ocaml_emulator/platform.ml new file mode 100644 index 000000000..0c8422641 --- /dev/null +++ b/ocaml_emulator/platform.ml @@ -0,0 +1,197 @@ +open Sail_lib;; +module P = Platform_impl;; +module Elf = Elf_loader;; + +(* Platform configuration *) + +let config_enable_rvc = ref true +let config_enable_next = ref false +let config_enable_writable_misa = ref true +let config_enable_dirty_update = ref false +let config_enable_misaligned_access = ref false +let config_mtval_has_illegal_inst_bits = ref false +let config_enable_svinval = ref false +let config_enable_zcb = ref false +let config_enable_writable_fiom = ref true +let config_enable_vext = ref true +let config_enable_bext = ref false +let config_pmp_count = ref Big_int.zero +let config_pmp_grain = ref Big_int.zero + +let set_config_pmp_count x = config_pmp_count := Big_int.of_int x +let set_config_pmp_grain x = config_pmp_grain := Big_int.of_int x + +let platform_arch = ref P.RV64 + +(* Defaults for callbacks functions. + The model assumes that these functions do not change the state of the model. *) +let mem_write_callback (addr, width, value) = () +let mem_read_callback (addr, width, value) = () +let mem_exception_callback (addr, num_of_exception) = () +let pc_write_callback value = () +let xreg_write_callback (reg, value) = () +let freg_write_callback (reg, value) = () +let csr_write_callback (reg, value) = () +let csr_read_callback (reg, value) = () +let vreg_write_callback (reg, value) = () + +(* logging *) + +let config_print_instr = ref true +let config_print_reg = ref true +let config_print_mem_access = ref true +let config_print_platform = ref true + +let print_instr s = + if !config_print_instr + then print_endline s + else () + +let print_reg s = + if !config_print_reg + then print_endline s + else () + +let print_mem_access s = + if !config_print_mem_access + then print_endline s + else () + +let print_platform s = + if !config_print_platform + then print_endline s + else () + +let get_config_print_instr () = !config_print_instr +let get_config_print_reg () = !config_print_reg +let get_config_print_mem () = !config_print_mem_access +let get_config_print_platform () = !config_print_platform + +(* Mapping to Sail externs *) +let cur_arch_bitwidth () = + match !platform_arch with + | P.RV64 -> Big_int.of_int 64 + | P.RV32 -> Big_int.of_int 32 + +let arch_bits_of_int i = + get_slice_int (cur_arch_bitwidth (), Big_int.of_int i, Big_int.zero) + +let arch_bits_of_int64 i = + get_slice_int (cur_arch_bitwidth (), Big_int.of_int64 i, Big_int.zero) + +let rom_size_ref = ref 0 +let make_rom arch start_pc = + let reset_vec = + List.concat (List.map P.uint32_to_bytes (P.reset_vec_int arch start_pc)) in + let dtb = P.make_dtb (P.make_dts arch) in + let rom = reset_vec @ dtb in + ( rom_size_ref := List.length rom; + (* + List.iteri (fun i c -> + print_mem_access "rom[0x%Lx] <- %x\n" + (Int64.add P.rom_base (Int64.of_int i)) + c + ) rom; + *) + rom ) + +let enable_writable_misa () = !config_enable_writable_misa +let enable_rvc () = !config_enable_rvc +let enable_next () = !config_enable_next +let enable_fdext () = false +let enable_vext () = !config_enable_vext +let enable_bext () = !config_enable_bext +let enable_dirty_update () = !config_enable_dirty_update +let enable_misaligned_access () = !config_enable_misaligned_access +let mtval_has_illegal_inst_bits () = !config_mtval_has_illegal_inst_bits +let enable_svinval () = !config_enable_svinval +let enable_zcb () = !config_enable_zcb +let enable_zfinx () = false +let enable_writable_fiom () = !config_enable_writable_fiom +let pmp_count () = !config_pmp_count +let pmp_grain () = !config_pmp_grain + +let rom_base () = arch_bits_of_int64 P.rom_base +let rom_size () = arch_bits_of_int !rom_size_ref + +let dram_base () = arch_bits_of_int64 P.dram_base +let dram_size () = arch_bits_of_int64 !P.dram_size_ref + +let clint_base () = arch_bits_of_int64 P.clint_base +let clint_size () = arch_bits_of_int64 P.clint_size + +let insns_per_tick () = Big_int.of_int P.insns_per_tick + +let htif_tohost () = + arch_bits_of_int64 (Big_int.to_int64 (Elf.elf_tohost ())) + +(* Entropy Source - get random bits *) + +(* This function can be changed to support deterministic sequences of + pseudo-random bytes. This is useful for testing. *) +let get_16_random_bits () = arch_bits_of_int (Random.int 0xFFFF) + +(* load reservation *) + +let speculate_conditional () = true + +let reservation = ref "none" (* shouldn't match any valid address *) + +let load_reservation addr = + print_platform (Printf.sprintf "reservation <- %s\n" (string_of_bits addr)); + reservation := string_of_bits addr + +let match_reservation addr = + print_platform (Printf.sprintf "reservation: %s, key=%s\n" (!reservation) (string_of_bits addr)); + string_of_bits addr = !reservation + +let cancel_reservation () = + print_platform (Printf.sprintf "reservation <- none\n"); + reservation := "none" + +let read_mem (rk, addrsize, addr, len) = + Sail_lib.fast_read_ram (len, addr) + +let write_mem_ea _ = () + +let write_mem (wk, addrsize, addr, len, value) = + Sail_lib.write_ram' (len, Sail_lib.uint addr, value); true + +let excl_res _ = true + +let barrier _ = () + +(* terminal I/O *) + +let term_write char_bits = + let big_char = Big_int.bitwise_and (uint char_bits) (Big_int.of_int 255) in + P.term_write (char_of_int (Big_int.to_int big_char)) + +let term_read () = + let c = P.term_read () in + arch_bits_of_int (int_of_char c) + +(* physical memory *) + +let get_mem_bytes addr len = + read_mem_bytes addr len + +(* returns starting value for PC, i.e. start of reset vector *) +let init arch elf_file = + platform_arch := arch; + Elf.load_elf elf_file; + + print_platform (Printf.sprintf "\nRegistered htif_tohost at 0x%Lx.\n" (Big_int.to_int64 (Elf.elf_tohost ()))); + print_platform (Printf.sprintf "Registered clint at 0x%Lx (size 0x%Lx).\n%!" P.clint_base P.clint_size); + + let start_pc = Elf.Big_int.to_int64 (Elf.elf_entry ()) in + let rom = make_rom arch start_pc in + let rom_base = Big_int.of_int64 P.rom_base in + let rec write_rom ofs = function + | [] -> () + | h :: tl -> let addr = Big_int.add rom_base (Big_int.of_int ofs) in + (wram addr h); + write_rom (ofs + 1) tl + in ( write_rom 0 rom; + get_slice_int (cur_arch_bitwidth (), rom_base, Big_int.zero) + ) diff --git a/test/run_tests.sh b/test/run_tests.sh old mode 100755 new mode 100644 From ffc1318985d288582a2f1860d3fd02fc38f04eb7 Mon Sep 17 00:00:00 2001 From: Ksenia Dobrovolskaya Date: Wed, 9 Oct 2024 14:51:53 +0300 Subject: [PATCH 2/3] Added implementation of callbacks for trace printing in riscv_default_callbacks.c. --- Makefile | 14 +- c_emulator/riscv_default_callbacks.c | 57 +++++++- c_emulator/riscv_prelude.h | 2 - c_emulator/riscv_rvfi_callbacks.c | 3 +- model/prelude.sail | 1 - model/riscv_csr_begin.sail | 14 ++ model/riscv_insts_vext_mem.sail | 1 - model/riscv_mem.sail | 11 +- model/riscv_regs.sail | 4 +- model/riscv_types.sail | 45 ++++-- model/riscv_vreg_type.sail | 15 +- ocaml_emulator/platform.ml | 197 --------------------------- test/run_tests.sh | 0 13 files changed, 128 insertions(+), 236 deletions(-) delete mode 100644 ocaml_emulator/platform.ml mode change 100644 => 100755 test/run_tests.sh diff --git a/Makefile b/Makefile index cff1d2fd3..101949abc 100644 --- a/Makefile +++ b/Makefile @@ -221,15 +221,22 @@ cloc: gcovr: gcovr -r . --html --html-detail -o index.html -c_preserve_fns=-c_preserve _set_Misa_C +c_preserve_fns=-c_preserve _set_Misa_C \ + -c_preserve mem_write_callback_default \ + -c_preserve mem_read_callback_default \ + -c_preserve xreg_write_callback_default \ + -c_preserve freg_write_callback_default \ + -c_preserve csr_write_callback_default \ + -c_preserve csr_read_callback_default \ + -c_preserve vreg_write_callback_default generated_definitions/c/riscv_model_$(ARCH).c: $(SAIL_SRCS) model/main.sail Makefile mkdir -p generated_definitions/c - $(SAIL) $(SAIL_FLAGS) $(c_preserve_fns) -O -Oconstant_fold -memo_z3 -c -c_include riscv_default_callbacks.c -c_include riscv_prelude.h -c_include riscv_platform.h -c_no_main $(SAIL_SRCS) model/main.sail -o $(basename $@) + $(SAIL) $(SAIL_FLAGS) $(c_preserve_fns) -O -Oconstant_fold -memo_z3 -c -c_include riscv_prelude.h -c_include riscv_platform.h -c_no_main $(SAIL_SRCS) -c_include riscv_default_callbacks.c model/main.sail -o $(basename $@) generated_definitions/c2/riscv_model_$(ARCH).c: $(SAIL_SRCS) model/main.sail Makefile mkdir -p generated_definitions/c2 - $(SAIL) $(SAIL_FLAGS) -no_warn -memo_z3 -config c_emulator/config.json -c2 -c_include riscv_default_callbacks.c $(SAIL_SRCS) -o $(basename $@) + $(SAIL) $(SAIL_FLAGS) -no_warn -memo_z3 -config c_emulator/config.json -c2 $(SAIL_SRCS) -o $(basename $@) $(SOFTFLOAT_LIBS): $(MAKE) SPECIALIZE_TYPE=$(SOFTFLOAT_SPECIALIZE_TYPE) -C $(SOFTFLOAT_LIBDIR) @@ -259,7 +266,6 @@ rvfi_preserve_fns=-c_preserve rvfi_set_instr_packet \ -c_preserve rvfi_read \ -c_preserve rvfi_mem_exception \ -c_preserve rvfi_wX \ - -c_preserve print_rvfi_exec \ -c_preserve print_instr_packet \ -c_preserve print_rvfi_exec diff --git a/c_emulator/riscv_default_callbacks.c b/c_emulator/riscv_default_callbacks.c index fd7fa3e84..9d7517034 100644 --- a/c_emulator/riscv_default_callbacks.c +++ b/c_emulator/riscv_default_callbacks.c @@ -1,11 +1,54 @@ +#include "riscv_config.h" + +int zmem_write_callback_default(long unsigned int addr, long int width, lbits value); +int zmem_read_callback_default(const char *type, long unsigned int addr, + long int width, lbits value); +int zxreg_write_callback_default(long unsigned int reg, long unsigned int value); +int zfreg_write_callback_default(long unsigned int reg, long unsigned int value); +int zcsr_write_callback_default(long unsigned int reg, long unsigned int value); +int zcsr_read_callback_default(long unsigned int reg, long unsigned int value); +int zvreg_write_callback_default(long unsigned int reg, lbits value); + /* The model assumes that these functions do not change the state of the model. */ -int mem_write_callback(uint64_t addr, uint64_t width, lbits value) { } -int mem_read_callback(uint64_t addr, uint64_t width, lbits value) { } +int mem_write_callback(uint64_t addr, uint64_t width, lbits value) { + if (config_print_mem_access) + zmem_write_callback_default(addr, width, value); +} + +int mem_read_callback(const char *type, uint64_t addr, uint64_t width, + lbits value) +{ + if (config_print_mem_access) + zmem_read_callback_default(type, addr, width, value); +} + int mem_exception_callback(uint64_t addr, uint64_t num_of_exception) { } -int xreg_write_callback(unsigned reg, uint64_t value) { } -int freg_write_callback(unsigned reg, uint64_t value) { } -int csr_write_callback(unsigned reg, uint64_t value) { } -int csr_read_callback(unsigned reg, uint64_t value) { } -int vreg_write_callback(unsigned reg, lbits value) { } + +int xreg_write_callback(unsigned reg, uint64_t value) { + if (config_print_reg) + zxreg_write_callback_default(reg, value); +} + +int freg_write_callback(unsigned reg, uint64_t value) { + /* TODO: will only print bits; should we print in floating point format? */ + if (config_print_reg) + zfreg_write_callback_default(reg, value); +} + +int csr_write_callback(unsigned reg, uint64_t value) { + if (config_print_reg) + zcsr_write_callback_default(reg, value); +} + +int csr_read_callback(unsigned reg, uint64_t value) { + if (config_print_reg) + zcsr_read_callback_default(reg, value); +} + +int vreg_write_callback(unsigned reg, lbits value) { + if (config_print_reg) + zvreg_write_callback_default(reg, value); +} + int pc_write_callback(uint64_t value) { } diff --git a/c_emulator/riscv_prelude.h b/c_emulator/riscv_prelude.h index f6692b414..3d9f6b2cb 100644 --- a/c_emulator/riscv_prelude.h +++ b/c_emulator/riscv_prelude.h @@ -12,6 +12,4 @@ unit print_mem_access(sail_string s); unit print_platform(sail_string s); bool get_config_print_instr(unit u); -bool get_config_print_reg(unit u); -bool get_config_print_mem(unit u); bool get_config_print_platform(unit u); diff --git a/c_emulator/riscv_rvfi_callbacks.c b/c_emulator/riscv_rvfi_callbacks.c index 77cd37e8e..c918f105c 100644 --- a/c_emulator/riscv_rvfi_callbacks.c +++ b/c_emulator/riscv_rvfi_callbacks.c @@ -10,7 +10,8 @@ int mem_write_callback(uint64_t addr, uint64_t width, lbits value) if (rv_enable_callbacks) zrvfi_write(addr, width, value); } -int mem_read_callback(uint64_t addr, uint64_t width, lbits value) +int mem_read_callback(const char *type, uint64_t addr, uint64_t width, + lbits value) { if (rv_enable_callbacks) { sail_int len; diff --git a/model/prelude.sail b/model/prelude.sail index 01eb3277b..082e223cf 100644 --- a/model/prelude.sail +++ b/model/prelude.sail @@ -76,7 +76,6 @@ val get_config_print_mem = pure {c:"get_config_print_mem"} : unit -> bool val get_config_print_platform = pure {c:"get_config_print_platform"} : unit -> bool // defaults for other backends function get_config_print_instr () = false -function get_config_print_mem () = false function get_config_print_platform () = false val sign_extend : forall 'n 'm, 'm >= 'n. (implicit('m), bits('n)) -> bits('m) diff --git a/model/riscv_csr_begin.sail b/model/riscv_csr_begin.sail index 053776435..d886e0e3e 100644 --- a/model/riscv_csr_begin.sail +++ b/model/riscv_csr_begin.sail @@ -338,3 +338,17 @@ scattered function read_CSR /* returns new value (after legalisation) if the CSR is defined */ val write_CSR : (csreg, xlenbits) -> xlenbits scattered function write_CSR + + +/* Implementations of default callbacks for trace printing */ + +val csr_write_callback_default : (csreg, xlenbits) -> unit +function csr_write_callback_default (csr, value) = { + print_reg("csr " ^ csr_name_map(csr) ^ " <- " ^ BitStr(value) ^ " (input: " ^ BitStr(value) ^ ")") +} + +val csr_read_callback_default : (csreg, xlenbits) -> unit +function csr_read_callback_default (csr, value) = { + print_reg("csr " ^ csr_name_map(csr) ^ " -> " ^ BitStr(value)) +} + diff --git a/model/riscv_insts_vext_mem.sail b/model/riscv_insts_vext_mem.sail index 928747433..cf121a3c1 100644 --- a/model/riscv_insts_vext_mem.sail +++ b/model/riscv_insts_vext_mem.sail @@ -183,7 +183,6 @@ function process_vlsegff (nf, vm, vd, load_width_bytes, rs1, EMUL_pow, num_elem) else { vl = to_bits(xlen, i); csr_write_callback(csr_name_map("vl"), vl); ->>>>>>> cb0b429d (Implementing callbacks in sail-riscv for state-changing events) trimmed = true } } diff --git a/model/riscv_mem.sail b/model/riscv_mem.sail index 3468ce702..3b091addb 100644 --- a/model/riscv_mem.sail +++ b/model/riscv_mem.sail @@ -73,9 +73,7 @@ function phys_mem_read forall 'n, 0 < 'n <= max_mem_access . (t : AccessType(ext (Execute(), None()) => MemException(E_Fetch_Access_Fault()), (Read(Data), None()) => MemException(E_Load_Access_Fault()), (_, None()) => MemException(E_SAMO_Access_Fault()), - (_, Some(v, m)) => { if get_config_print_mem() - then print_mem("mem[" ^ to_str(t) ^ "," ^ BitStr(paddr) ^ "] -> " ^ BitStr(v)); - MemValue(v, m) } + (_, Some(v, m)) => MemValue(v, m) } } @@ -133,7 +131,7 @@ function mem_read_priv_meta (typ, priv, paddr, width, aq, rl, res, meta) = { (_, _, _) => checked_mem_read(typ, priv, paddr, width, aq, rl, res, meta) }; match result { - MemValue(value, _) => mem_read_callback(paddr, width, value), + MemValue(value, _) => mem_read_callback(to_str(typ), paddr, width, value), MemException(e) => mem_exception_callback(paddr, num_of_ExceptionType(e)) }; result @@ -158,10 +156,7 @@ function mem_write_ea (addr, width, aq, rl, con) = // only used for actual memory regions, to avoid MMIO effects function phys_mem_write forall 'n, 0 < 'n <= max_mem_access . (wk : write_kind, paddr : xlenbits, width : int('n), data : bits(8 * 'n), meta : mem_meta) -> MemoryOpResult(bool) = { - let result = MemValue(write_ram(wk, paddr, width, data, meta)); - if get_config_print_mem() - then print_mem("mem[" ^ BitStr(paddr) ^ "] <- " ^ BitStr(data)); - result + MemValue(write_ram(wk, paddr, width, data, meta)); } /* dispatches to MMIO regions or physical memory regions depending on physical memory map */ diff --git a/model/riscv_regs.sail b/model/riscv_regs.sail index 6d18e468e..72258b9ce 100644 --- a/model/riscv_regs.sail +++ b/model/riscv_regs.sail @@ -125,9 +125,7 @@ function wX (r : regno, in_v : xlenbits) -> unit = { 31 => x31 = v, _ => assert(false, "invalid register number") }; - if (r != 0) then { - xreg_write_callback(regno_to_regidx(r), in_v); - } + if (r != 0) then xreg_write_callback(regno_to_regidx(r), in_v) } function rX_bits(i: regidx) -> xlenbits = rX(unsigned(i)) diff --git a/model/riscv_types.sail b/model/riscv_types.sail index abd9fbe30..73c547962 100644 --- a/model/riscv_types.sail +++ b/model/riscv_types.sail @@ -415,13 +415,38 @@ function report_invalid_width(f , l, w, k) -> 'a = { /* Callbacks for state-changing events */ -/* Defaults for these functions in riscv_default_callbacks.c and platform_impl.ml */ - -val mem_write_callback = pure {ocaml: "Platform.mem_write_callback", c: "mem_write_callback"} : forall 'n, 0 < 'n <= max_mem_access . (/* addr */ xlenbits, /* width */ int('n), /* value */ bits(8 * 'n)) -> unit -val mem_read_callback = pure {ocaml: "Platform.mem_read_callback", c: "mem_read_callback"} : forall 'n, 0 < 'n <= max_mem_access . (/* addr */ xlenbits, /* width */ int('n), /* value */ bits(8 * 'n)) -> unit -val mem_exception_callback = pure {ocaml: "Platform.mem_exception_callback", c: "mem_exception_callback"} : forall 'n, 0 <= 'n < xlen . (/* addr */ xlenbits, /* num_of_ExceptionType */ int('n)) -> unit -val pc_write_callback = pure {ocaml: "Platform.pc_write_callback", c: "pc_write_callback"} : xlenbits -> unit -val xreg_write_callback = pure {ocaml: "Platform.xreg_write_callback", c: "xreg_write_callback"} : (regidx, xlenbits) -> unit -val freg_write_callback = pure {ocaml: "Platform.freg_write_callback", c: "freg_write_callback"} : (regidx, flenbits) -> unit -val csr_write_callback = pure {ocaml: "Platform.csr_write_callback", c: "csr_write_callback"} : (csreg, xlenbits) -> unit -val csr_read_callback = pure {ocaml: "Platform.csr_read_callback", c: "csr_read_callback"} : (csreg, xlenbits) -> unit +/* Defaults for these functions in riscv_default_callbacks.c */ + +val mem_write_callback = pure {c: "mem_write_callback"} : forall 'n, 0 < 'n <= max_mem_access . (/* addr */ xlenbits, /* width */ int('n), /* value */ bits(8 * 'n)) -> unit +val mem_read_callback = pure {c: "mem_read_callback"} : forall 'n, 0 < 'n <= max_mem_access . (/* access type */ string, /* addr */ xlenbits, /* width */ int('n), /* value */ bits(8 * 'n)) -> unit +val mem_exception_callback = pure {c: "mem_exception_callback"} : forall 'n, 0 <= 'n < xlen . (/* addr */ xlenbits, /* num_of_ExceptionType */ int('n)) -> unit +val pc_write_callback = pure {c: "pc_write_callback"} : xlenbits -> unit +val xreg_write_callback = pure {c: "xreg_write_callback"} : (regidx, xlenbits) -> unit +val freg_write_callback = pure {c: "freg_write_callback"} : (regidx, flenbits) -> unit +val csr_write_callback = pure {c: "csr_write_callback"} : (csreg, xlenbits) -> unit +val csr_read_callback = pure {c: "csr_read_callback"} : (csreg, xlenbits) -> unit + +/* Implementations of default callbacks for trace printing */ + +val mem_write_callback_default : forall 'n, 0 < 'n <= max_mem_access . (/* addr */ xlenbits, /* width */ int('n), /* value */ bits(8 * 'n)) -> unit +function mem_write_callback_default (addr, width, value) = { + print_mem("mem[" ^ BitStr(addr) ^ "] <- " ^ BitStr(value)) +} + +val mem_read_callback_default : forall 'n, 0 < 'n <= max_mem_access . (/* access type */ string, /* addr */ xlenbits, /* width */ int('n), /* value */ bits(8 * 'n)) -> unit +function mem_read_callback_default (t, addr, width, value) = { + print_mem("mem[" ^ t ^ "," ^ BitStr(addr) ^ "] -> " ^ BitStr(value)) +} + +val xreg_write_callback_default : (regidx, xlenbits) -> unit +function xreg_write_callback_default (reg, value) = { + print_reg("x" ^ dec_str(regidx_to_regno(reg)) ^ " <- " ^ BitStr(value)) +} + +val freg_write_callback_default : (regidx, flenbits) -> unit +function freg_write_callback_default (reg, value) = { + /* todo: will only print bits; should we print in floating point format? */ + print_reg("f" ^ dec_str(regidx_to_regno(reg)) ^ " <- " ^ BitStr(value)) +} + + diff --git a/model/riscv_vreg_type.sail b/model/riscv_vreg_type.sail index 5ab69305a..e1f523b17 100755 --- a/model/riscv_vreg_type.sail +++ b/model/riscv_vreg_type.sail @@ -149,5 +149,16 @@ enum vmlsop = { VLM, VSM } /* Callbacks for vregs state-changing events */ -/* Default for this function in riscv_default_callbacks.c and platform_impl.ml */ -val vreg_write_callback = pure {ocaml: "Platform.vreg_write_callback", c: "vreg_write_callback"} : (regidx, vregtype) -> unit +/* Default for this function in riscv_default_callbacks.c */ + +val vreg_write_callback = pure {c: "vreg_write_callback"} : (regidx, vregtype) -> unit + +/* Implementations of default callbacks for trace printing */ + +val vreg_write_callback_default : (regidx, vregtype) -> unit +function vreg_write_callback_default (reg, value) = { + let VLEN = unsigned(vlenb) * 8; + assert(0 < VLEN & VLEN <= sizeof(vlenmax)); + print_reg("v" ^ dec_str(regidx_to_regno(reg)) ^ " <- " ^ BitStr(value[VLEN - 1 .. 0])) +} + diff --git a/ocaml_emulator/platform.ml b/ocaml_emulator/platform.ml deleted file mode 100644 index 0c8422641..000000000 --- a/ocaml_emulator/platform.ml +++ /dev/null @@ -1,197 +0,0 @@ -open Sail_lib;; -module P = Platform_impl;; -module Elf = Elf_loader;; - -(* Platform configuration *) - -let config_enable_rvc = ref true -let config_enable_next = ref false -let config_enable_writable_misa = ref true -let config_enable_dirty_update = ref false -let config_enable_misaligned_access = ref false -let config_mtval_has_illegal_inst_bits = ref false -let config_enable_svinval = ref false -let config_enable_zcb = ref false -let config_enable_writable_fiom = ref true -let config_enable_vext = ref true -let config_enable_bext = ref false -let config_pmp_count = ref Big_int.zero -let config_pmp_grain = ref Big_int.zero - -let set_config_pmp_count x = config_pmp_count := Big_int.of_int x -let set_config_pmp_grain x = config_pmp_grain := Big_int.of_int x - -let platform_arch = ref P.RV64 - -(* Defaults for callbacks functions. - The model assumes that these functions do not change the state of the model. *) -let mem_write_callback (addr, width, value) = () -let mem_read_callback (addr, width, value) = () -let mem_exception_callback (addr, num_of_exception) = () -let pc_write_callback value = () -let xreg_write_callback (reg, value) = () -let freg_write_callback (reg, value) = () -let csr_write_callback (reg, value) = () -let csr_read_callback (reg, value) = () -let vreg_write_callback (reg, value) = () - -(* logging *) - -let config_print_instr = ref true -let config_print_reg = ref true -let config_print_mem_access = ref true -let config_print_platform = ref true - -let print_instr s = - if !config_print_instr - then print_endline s - else () - -let print_reg s = - if !config_print_reg - then print_endline s - else () - -let print_mem_access s = - if !config_print_mem_access - then print_endline s - else () - -let print_platform s = - if !config_print_platform - then print_endline s - else () - -let get_config_print_instr () = !config_print_instr -let get_config_print_reg () = !config_print_reg -let get_config_print_mem () = !config_print_mem_access -let get_config_print_platform () = !config_print_platform - -(* Mapping to Sail externs *) -let cur_arch_bitwidth () = - match !platform_arch with - | P.RV64 -> Big_int.of_int 64 - | P.RV32 -> Big_int.of_int 32 - -let arch_bits_of_int i = - get_slice_int (cur_arch_bitwidth (), Big_int.of_int i, Big_int.zero) - -let arch_bits_of_int64 i = - get_slice_int (cur_arch_bitwidth (), Big_int.of_int64 i, Big_int.zero) - -let rom_size_ref = ref 0 -let make_rom arch start_pc = - let reset_vec = - List.concat (List.map P.uint32_to_bytes (P.reset_vec_int arch start_pc)) in - let dtb = P.make_dtb (P.make_dts arch) in - let rom = reset_vec @ dtb in - ( rom_size_ref := List.length rom; - (* - List.iteri (fun i c -> - print_mem_access "rom[0x%Lx] <- %x\n" - (Int64.add P.rom_base (Int64.of_int i)) - c - ) rom; - *) - rom ) - -let enable_writable_misa () = !config_enable_writable_misa -let enable_rvc () = !config_enable_rvc -let enable_next () = !config_enable_next -let enable_fdext () = false -let enable_vext () = !config_enable_vext -let enable_bext () = !config_enable_bext -let enable_dirty_update () = !config_enable_dirty_update -let enable_misaligned_access () = !config_enable_misaligned_access -let mtval_has_illegal_inst_bits () = !config_mtval_has_illegal_inst_bits -let enable_svinval () = !config_enable_svinval -let enable_zcb () = !config_enable_zcb -let enable_zfinx () = false -let enable_writable_fiom () = !config_enable_writable_fiom -let pmp_count () = !config_pmp_count -let pmp_grain () = !config_pmp_grain - -let rom_base () = arch_bits_of_int64 P.rom_base -let rom_size () = arch_bits_of_int !rom_size_ref - -let dram_base () = arch_bits_of_int64 P.dram_base -let dram_size () = arch_bits_of_int64 !P.dram_size_ref - -let clint_base () = arch_bits_of_int64 P.clint_base -let clint_size () = arch_bits_of_int64 P.clint_size - -let insns_per_tick () = Big_int.of_int P.insns_per_tick - -let htif_tohost () = - arch_bits_of_int64 (Big_int.to_int64 (Elf.elf_tohost ())) - -(* Entropy Source - get random bits *) - -(* This function can be changed to support deterministic sequences of - pseudo-random bytes. This is useful for testing. *) -let get_16_random_bits () = arch_bits_of_int (Random.int 0xFFFF) - -(* load reservation *) - -let speculate_conditional () = true - -let reservation = ref "none" (* shouldn't match any valid address *) - -let load_reservation addr = - print_platform (Printf.sprintf "reservation <- %s\n" (string_of_bits addr)); - reservation := string_of_bits addr - -let match_reservation addr = - print_platform (Printf.sprintf "reservation: %s, key=%s\n" (!reservation) (string_of_bits addr)); - string_of_bits addr = !reservation - -let cancel_reservation () = - print_platform (Printf.sprintf "reservation <- none\n"); - reservation := "none" - -let read_mem (rk, addrsize, addr, len) = - Sail_lib.fast_read_ram (len, addr) - -let write_mem_ea _ = () - -let write_mem (wk, addrsize, addr, len, value) = - Sail_lib.write_ram' (len, Sail_lib.uint addr, value); true - -let excl_res _ = true - -let barrier _ = () - -(* terminal I/O *) - -let term_write char_bits = - let big_char = Big_int.bitwise_and (uint char_bits) (Big_int.of_int 255) in - P.term_write (char_of_int (Big_int.to_int big_char)) - -let term_read () = - let c = P.term_read () in - arch_bits_of_int (int_of_char c) - -(* physical memory *) - -let get_mem_bytes addr len = - read_mem_bytes addr len - -(* returns starting value for PC, i.e. start of reset vector *) -let init arch elf_file = - platform_arch := arch; - Elf.load_elf elf_file; - - print_platform (Printf.sprintf "\nRegistered htif_tohost at 0x%Lx.\n" (Big_int.to_int64 (Elf.elf_tohost ()))); - print_platform (Printf.sprintf "Registered clint at 0x%Lx (size 0x%Lx).\n%!" P.clint_base P.clint_size); - - let start_pc = Elf.Big_int.to_int64 (Elf.elf_entry ()) in - let rom = make_rom arch start_pc in - let rom_base = Big_int.of_int64 P.rom_base in - let rec write_rom ofs = function - | [] -> () - | h :: tl -> let addr = Big_int.add rom_base (Big_int.of_int ofs) in - (wram addr h); - write_rom (ofs + 1) tl - in ( write_rom 0 rom; - get_slice_int (cur_arch_bitwidth (), rom_base, Big_int.zero) - ) diff --git a/test/run_tests.sh b/test/run_tests.sh old mode 100644 new mode 100755 From 232e5bd230d21b79c5fc9ff31a44d832d9a49ba2 Mon Sep 17 00:00:00 2001 From: Ksenia Dobrovolskaya Date: Tue, 15 Oct 2024 18:20:36 +0300 Subject: [PATCH 3/3] Added implementations of default callbacks for trace printing in riscv_default_callbacks.c --- Makefile | 9 +-- c_emulator/riscv_default_callbacks.c | 91 +++++++++++++++++++--------- model/riscv_csr_begin.sail | 13 ---- model/riscv_types.sail | 24 -------- model/riscv_vreg_type.sail | 9 --- 5 files changed, 65 insertions(+), 81 deletions(-) diff --git a/Makefile b/Makefile index 101949abc..6e0a5d330 100644 --- a/Makefile +++ b/Makefile @@ -221,14 +221,7 @@ cloc: gcovr: gcovr -r . --html --html-detail -o index.html -c_preserve_fns=-c_preserve _set_Misa_C \ - -c_preserve mem_write_callback_default \ - -c_preserve mem_read_callback_default \ - -c_preserve xreg_write_callback_default \ - -c_preserve freg_write_callback_default \ - -c_preserve csr_write_callback_default \ - -c_preserve csr_read_callback_default \ - -c_preserve vreg_write_callback_default +c_preserve_fns=-c_preserve _set_Misa_C generated_definitions/c/riscv_model_$(ARCH).c: $(SAIL_SRCS) model/main.sail Makefile mkdir -p generated_definitions/c diff --git a/c_emulator/riscv_default_callbacks.c b/c_emulator/riscv_default_callbacks.c index 9d7517034..0cec7c93a 100644 --- a/c_emulator/riscv_default_callbacks.c +++ b/c_emulator/riscv_default_callbacks.c @@ -1,54 +1,91 @@ #include "riscv_config.h" +#include -int zmem_write_callback_default(long unsigned int addr, long int width, lbits value); -int zmem_read_callback_default(const char *type, long unsigned int addr, - long int width, lbits value); -int zxreg_write_callback_default(long unsigned int reg, long unsigned int value); -int zfreg_write_callback_default(long unsigned int reg, long unsigned int value); -int zcsr_write_callback_default(long unsigned int reg, long unsigned int value); -int zcsr_read_callback_default(long unsigned int reg, long unsigned int value); -int zvreg_write_callback_default(long unsigned int reg, lbits value); +void zcsr_name_map_forwards(sail_string *rop, uint64_t); -/* The model assumes that these functions do not change the state of the model. +static uint8_t *get_lbits_data(lbits val) +{ + uint8_t *data = (uint8_t *)calloc(val.len, sizeof(uint8_t)); + mpz_export(data, NULL, -1, 1, 0, 0, val.bits); + return data; +} + +/* Implementations of default callbacks for trace printing. + * + * The model assumes that these functions do not change the state of the model. */ -int mem_write_callback(uint64_t addr, uint64_t width, lbits value) { - if (config_print_mem_access) - zmem_write_callback_default(addr, width, value); +int mem_write_callback(uint64_t addr, uint64_t width, lbits value) +{ + if (config_print_mem_access) { + char *lbits_data = get_lbits_data(value); + printf("mem[0x%.16lX] <- 0x", addr); + for (int i = width - 1; i >= 0; --i) + printf("%02hhX", lbits_data[i]); + printf("\n"); + free(lbits_data); + } } int mem_read_callback(const char *type, uint64_t addr, uint64_t width, lbits value) { - if (config_print_mem_access) - zmem_read_callback_default(type, addr, width, value); + if (config_print_mem_access) { + char *lbits_data = get_lbits_data(value); + printf("mem[%s,0x%.16lX] -> 0x", type, addr); + for (int i = width - 1; i >= 0; --i) + printf("%02hhX", lbits_data[i]); + printf("\n"); + free(lbits_data); + } } int mem_exception_callback(uint64_t addr, uint64_t num_of_exception) { } -int xreg_write_callback(unsigned reg, uint64_t value) { +int xreg_write_callback(unsigned reg, uint64_t value) +{ if (config_print_reg) - zxreg_write_callback_default(reg, value); + printf("x%d <- 0x%.16lX\n", reg, value); } -int freg_write_callback(unsigned reg, uint64_t value) { +int freg_write_callback(unsigned reg, uint64_t value) +{ /* TODO: will only print bits; should we print in floating point format? */ if (config_print_reg) - zfreg_write_callback_default(reg, value); + printf("f%d <- 0x%.16lX\n", reg, value); } -int csr_write_callback(unsigned reg, uint64_t value) { - if (config_print_reg) - zcsr_write_callback_default(reg, value); +int csr_write_callback(unsigned reg, uint64_t value) +{ + if (config_print_reg) { + sail_string csr_name; + CREATE(sail_string)(&csr_name); + zcsr_name_map_forwards(&csr_name, reg); + printf("CSR %s <- 0x%.16lX (input: 0x%.16lX)\n", csr_name, value, value); + KILL(sail_string)(&csr_name); + } } -int csr_read_callback(unsigned reg, uint64_t value) { - if (config_print_reg) - zcsr_read_callback_default(reg, value); +int csr_read_callback(unsigned reg, uint64_t value) +{ + if (config_print_reg) { + sail_string csr_name; + CREATE(sail_string)(&csr_name); + zcsr_name_map_forwards(&csr_name, reg); + printf("CSR %s -> 0x%.16lX\n", csr_name, value); + KILL(sail_string)(&csr_name); + } } -int vreg_write_callback(unsigned reg, lbits value) { - if (config_print_reg) - zvreg_write_callback_default(reg, value); +int vreg_write_callback(unsigned reg, lbits value) +{ + if (config_print_reg) { + char *lbits_data = get_lbits_data(value); + printf("v%d <- ", reg); + for (int i = value.len - 1; i >= 0; --i) + printf("%02hhX", lbits_data[i]); + printf("\n"); + free(lbits_data); + } } int pc_write_callback(uint64_t value) { } diff --git a/model/riscv_csr_begin.sail b/model/riscv_csr_begin.sail index d886e0e3e..ddb35536f 100644 --- a/model/riscv_csr_begin.sail +++ b/model/riscv_csr_begin.sail @@ -339,16 +339,3 @@ scattered function read_CSR val write_CSR : (csreg, xlenbits) -> xlenbits scattered function write_CSR - -/* Implementations of default callbacks for trace printing */ - -val csr_write_callback_default : (csreg, xlenbits) -> unit -function csr_write_callback_default (csr, value) = { - print_reg("csr " ^ csr_name_map(csr) ^ " <- " ^ BitStr(value) ^ " (input: " ^ BitStr(value) ^ ")") -} - -val csr_read_callback_default : (csreg, xlenbits) -> unit -function csr_read_callback_default (csr, value) = { - print_reg("csr " ^ csr_name_map(csr) ^ " -> " ^ BitStr(value)) -} - diff --git a/model/riscv_types.sail b/model/riscv_types.sail index 73c547962..d03e5df6e 100644 --- a/model/riscv_types.sail +++ b/model/riscv_types.sail @@ -426,27 +426,3 @@ val freg_write_callback = pure {c: "freg_write_callback"} : (regidx, flenbits) - val csr_write_callback = pure {c: "csr_write_callback"} : (csreg, xlenbits) -> unit val csr_read_callback = pure {c: "csr_read_callback"} : (csreg, xlenbits) -> unit -/* Implementations of default callbacks for trace printing */ - -val mem_write_callback_default : forall 'n, 0 < 'n <= max_mem_access . (/* addr */ xlenbits, /* width */ int('n), /* value */ bits(8 * 'n)) -> unit -function mem_write_callback_default (addr, width, value) = { - print_mem("mem[" ^ BitStr(addr) ^ "] <- " ^ BitStr(value)) -} - -val mem_read_callback_default : forall 'n, 0 < 'n <= max_mem_access . (/* access type */ string, /* addr */ xlenbits, /* width */ int('n), /* value */ bits(8 * 'n)) -> unit -function mem_read_callback_default (t, addr, width, value) = { - print_mem("mem[" ^ t ^ "," ^ BitStr(addr) ^ "] -> " ^ BitStr(value)) -} - -val xreg_write_callback_default : (regidx, xlenbits) -> unit -function xreg_write_callback_default (reg, value) = { - print_reg("x" ^ dec_str(regidx_to_regno(reg)) ^ " <- " ^ BitStr(value)) -} - -val freg_write_callback_default : (regidx, flenbits) -> unit -function freg_write_callback_default (reg, value) = { - /* todo: will only print bits; should we print in floating point format? */ - print_reg("f" ^ dec_str(regidx_to_regno(reg)) ^ " <- " ^ BitStr(value)) -} - - diff --git a/model/riscv_vreg_type.sail b/model/riscv_vreg_type.sail index e1f523b17..ca1b2ce93 100755 --- a/model/riscv_vreg_type.sail +++ b/model/riscv_vreg_type.sail @@ -153,12 +153,3 @@ enum vmlsop = { VLM, VSM } val vreg_write_callback = pure {c: "vreg_write_callback"} : (regidx, vregtype) -> unit -/* Implementations of default callbacks for trace printing */ - -val vreg_write_callback_default : (regidx, vregtype) -> unit -function vreg_write_callback_default (reg, value) = { - let VLEN = unsigned(vlenb) * 8; - assert(0 < VLEN & VLEN <= sizeof(vlenmax)); - print_reg("v" ^ dec_str(regidx_to_regno(reg)) ^ " <- " ^ BitStr(value[VLEN - 1 .. 0])) -} -