diff --git a/bhv/cv32e40s_rvfi.sv b/bhv/cv32e40s_rvfi.sv index 9a729e091..69643833f 100644 --- a/bhv/cv32e40s_rvfi.sv +++ b/bhv/cv32e40s_rvfi.sv @@ -111,7 +111,7 @@ module cv32e40s_rvfi input logic csr_mscratchcsw_in_wb_i, input logic csr_mscratchcswl_in_wb_i, input logic csr_mnxti_in_wb_i, - input logic wpt_match_wb_i, + input logic [31:0] wpt_match_wb_i, input mpu_status_e mpu_status_wb_i, input align_status_e align_status_wb_i, @@ -198,15 +198,9 @@ module cv32e40s_rvfi input logic [31:0] csr_tdata2_n_i, input logic [31:0] csr_tdata2_q_i, input logic csr_tdata2_we_i, - input logic [31:0] csr_tdata3_n_i, - input logic [31:0] csr_tdata3_q_i, - input logic csr_tdata3_we_i, input logic [31:0] csr_tinfo_n_i, input logic [31:0] csr_tinfo_q_i, input logic csr_tinfo_we_i, - input logic [31:0] csr_tcontrol_n_i, - input logic [31:0] csr_tcontrol_q_i, - input logic csr_tcontrol_we_i, input logic [31:0] csr_tselect_n_i, input logic [31:0] csr_tselect_q_i, input logic csr_tselect_we_i, @@ -309,6 +303,8 @@ module cv32e40s_rvfi output logic [63:0] rvfi_order, output logic [31:0] rvfi_insn, output logic [2:0] rvfi_instr_prot, + output logic [1:0] rvfi_instr_memtype, + output logic rvfi_instr_dbg, output rvfi_trap_t rvfi_trap, output logic [ 0:0] rvfi_halt, output rvfi_intr_t rvfi_intr, @@ -335,6 +331,9 @@ module cv32e40s_rvfi output logic [32*NMEM-1:0] rvfi_mem_rdata, output logic [32*NMEM-1:0] rvfi_mem_wdata, output logic [ 3*NMEM-1:0] rvfi_mem_prot, + output logic [ 6*NMEM-1:0] rvfi_mem_atop, + output logic [ 2*NMEM-1:0] rvfi_mem_memtype, + output logic [ NMEM-1 :0] rvfi_mem_dbg, output logic [32*32-1:0] rvfi_gpr_rdata, output logic [31:0] rvfi_gpr_rmask, @@ -423,18 +422,14 @@ module cv32e40s_rvfi output logic [31:0] rvfi_csr_tselect_wmask, output logic [31:0] rvfi_csr_tselect_rdata, output logic [31:0] rvfi_csr_tselect_wdata, - output logic [ 3:0] [31:0] rvfi_csr_tdata_rmask, // 1-3 implemented - output logic [ 3:0] [31:0] rvfi_csr_tdata_wmask, - output logic [ 3:0] [31:0] rvfi_csr_tdata_rdata, - output logic [ 3:0] [31:0] rvfi_csr_tdata_wdata, + output logic [ 2:0] [31:0] rvfi_csr_tdata_rmask, // 1-2 implemented + output logic [ 2:0] [31:0] rvfi_csr_tdata_wmask, + output logic [ 2:0] [31:0] rvfi_csr_tdata_rdata, + output logic [ 2:0] [31:0] rvfi_csr_tdata_wdata, output logic [31:0] rvfi_csr_tinfo_rmask, output logic [31:0] rvfi_csr_tinfo_wmask, output logic [31:0] rvfi_csr_tinfo_rdata, output logic [31:0] rvfi_csr_tinfo_wdata, - output logic [31:0] rvfi_csr_tcontrol_rmask, - output logic [31:0] rvfi_csr_tcontrol_wmask, - output logic [31:0] rvfi_csr_tcontrol_rdata, - output logic [31:0] rvfi_csr_tcontrol_wdata, output logic [31:0] rvfi_csr_dcsr_rmask, output logic [31:0] rvfi_csr_dcsr_wmask, output logic [31:0] rvfi_csr_dcsr_rdata, @@ -606,7 +601,7 @@ module cv32e40s_rvfi logic [4:0] debug_mode; logic [4:0] [ 2:0] debug_cause; logic [4:0] instr_pmp_err; - logic [4:0] [2:0] instr_prot; + obi_inst_req_t [4:0] instr_req; rvfi_intr_t [4:0] in_trap; logic [4:0] [ 4:0] rs1_addr; logic [4:0] [ 4:0] rs2_addr; @@ -834,7 +829,7 @@ module cv32e40s_rvfi // Indicate that a data transfer was blocked before reaching the bus. logic mem_access_blocked_wb; - assign mem_access_blocked_wb = wpt_match_wb_i || + assign mem_access_blocked_wb = |wpt_match_wb_i || (mpu_status_wb_i != MPU_OK) || (align_status_wb_i != ALIGN_OK); @@ -959,7 +954,7 @@ module cv32e40s_rvfi debug_mode <= '0; debug_cause <= '0; instr_pmp_err <= '0; - instr_prot <= '0; + instr_req <= '0; rs1_addr <= '0; rs2_addr <= '0; rs1_rdata <= '0; @@ -975,6 +970,8 @@ module cv32e40s_rvfi rvfi_order <= '0; rvfi_insn <= '0; rvfi_instr_prot <= '0; + rvfi_instr_memtype <= '0; + rvfi_instr_dbg <= '0; rvfi_pc_rdata <= '0; rvfi_pc_wdata <= '0; rvfi_trap <= '0; @@ -995,6 +992,9 @@ module cv32e40s_rvfi rvfi_mem_wmask <= '0; rvfi_mem_wdata <= '0; rvfi_mem_prot <= '0; + rvfi_mem_memtype <= '0; + rvfi_mem_atop <= '0; + rvfi_mem_dbg <= '0; rvfi_gpr_rdata <= '0; rvfi_gpr_rmask <= '0; rvfi_gpr_wdata <= '0; @@ -1047,7 +1047,7 @@ module cv32e40s_rvfi end // Capture OBI prot for the instruction fetch - instr_prot[STAGE_ID] <= obi_instr_if.req_payload.prot; + instr_req[STAGE_ID] <= obi_instr_if.req_payload; end else begin // Clear in trap if trap reached rvfi outputs or we insert a bubble into the ID stage @@ -1121,7 +1121,7 @@ module cv32e40s_rvfi debug_mode [STAGE_EX] <= debug_mode [STAGE_ID]; debug_cause[STAGE_EX] <= debug_cause[STAGE_ID]; instr_pmp_err[STAGE_EX] <= instr_pmp_err[STAGE_ID]; - instr_prot[STAGE_EX] <= instr_prot[STAGE_ID]; + instr_req[STAGE_EX] <= instr_req[STAGE_ID]; // Only update rs1/rs2 on the first part of a multi operation instruction. // Jumps may actually use rs1 before (id_valid && ex_ready), an assertion exists to check that @@ -1168,7 +1168,7 @@ module cv32e40s_rvfi debug_mode [STAGE_WB] <= debug_mode [STAGE_EX]; debug_cause[STAGE_WB] <= debug_cause [STAGE_EX]; instr_pmp_err[STAGE_WB] <= instr_pmp_err [STAGE_EX]; - instr_prot [STAGE_WB] <= instr_prot [STAGE_EX]; + instr_req [STAGE_WB] <= instr_req [STAGE_EX]; rs1_addr [STAGE_WB] <= rs1_addr [STAGE_EX]; rs2_addr [STAGE_WB] <= rs2_addr [STAGE_EX]; rs1_rdata [STAGE_WB] <= rs1_rdata [STAGE_EX]; @@ -1239,7 +1239,10 @@ module cv32e40s_rvfi rvfi_rs2_addr <= mret_ptr_wb ? rs2_addr [STAGE_WB_PAST] : rs2_addr [STAGE_WB]; rvfi_rs1_rdata <= mret_ptr_wb ? rs1_rdata[STAGE_WB_PAST] : rs1_rdata [STAGE_WB]; rvfi_rs2_rdata <= mret_ptr_wb ? rs2_rdata[STAGE_WB_PAST] : rs2_rdata [STAGE_WB]; - rvfi_instr_prot<= mret_ptr_wb ? instr_prot[STAGE_WB_PAST] : instr_prot[STAGE_WB]; + + rvfi_instr_prot <= mret_ptr_wb ? instr_req[STAGE_WB_PAST].prot : instr_req[STAGE_WB].prot; + rvfi_instr_memtype <= mret_ptr_wb ? instr_req[STAGE_WB_PAST].memtype : instr_req[STAGE_WB].memtype; + rvfi_instr_dbg <= mret_ptr_wb ? instr_req[STAGE_WB_PAST].dbg : instr_req[STAGE_WB].dbg; rvfi_mode <= priv_lvl_i; @@ -1263,7 +1266,7 @@ module cv32e40s_rvfi rs2_rdata[STAGE_WB_PAST] <= rs1_rdata[STAGE_WB]; debug_cause [STAGE_WB_PAST] <= debug_cause [STAGE_WB]; debug_mode [STAGE_WB_PAST] <= debug_mode[STAGE_WB]; - instr_prot[STAGE_WB_PAST] <= instr_prot[STAGE_WB]; + instr_req[STAGE_WB_PAST] <= instr_req[STAGE_WB]; pc_wb_past <= pc_wb_i; instr_rdata_wb_past <= instr_rdata_wb_i; rd_addr_wb_past <= rd_addr_wb; @@ -1277,6 +1280,9 @@ module cv32e40s_rvfi rvfi_mem_wmask <= '0; rvfi_mem_wdata <= '0; rvfi_mem_prot <= '0; + rvfi_mem_atop <= '0; + rvfi_mem_memtype <= '0; + rvfi_mem_dbg <= '0; rvfi_gpr_rdata <= '0; rvfi_gpr_rmask <= '0; @@ -1295,6 +1301,10 @@ module cv32e40s_rvfi rvfi_mem_wdata[(32*(memop_cnt+1))-1 -: 32] <= ex_mem_trans.wdata; // Using (2*memop_cnt+memop_cnt) rather than 3*memop_cnt. This is a workaround to avoid blackboxed multiplier in the slice boundary calculations rvfi_mem_prot [(2*memop_cnt + memop_cnt) +: 3] <= ex_mem_trans.prot; + // Using (4*memop_cnt) + (2*memop_cnt) rather than 6*memop_cnt. This is a workaround to avoid blackboxed multiplier in the slice boundary calculations. + rvfi_mem_atop [ ((4*memop_cnt) + (2*memop_cnt)) +: 6] <= 6'd0; + rvfi_mem_memtype [ (2*(memop_cnt+1))-1 -: 2] <= ex_mem_trans.memtype; + rvfi_mem_dbg [ (1*(memop_cnt+1))-1 -: 1] <= ex_mem_trans.dbg; end else if (lsu_split_2nd_xfer_wb && mem_access_blocked_wb) begin // 2nd transfer of a split misaligned is blocked. Clear related bits in rmask/wmask @@ -1546,21 +1556,11 @@ module cv32e40s_rvfi assign rvfi_csr_wdata_d.tdata[2] = csr_tdata2_n_i; assign rvfi_csr_wmask_d.tdata[2] = csr_tdata2_we_i ? '1 : '0; - assign rvfi_csr_rdata_d.tdata[3] = csr_tdata3_q_i; - assign rvfi_csr_rmask_d.tdata[3] = '1; - assign rvfi_csr_wdata_d.tdata[3] = csr_tdata3_n_i; - assign rvfi_csr_wmask_d.tdata[3] = csr_tdata3_we_i ? '1 : '0; - assign rvfi_csr_rdata_d.tinfo = csr_tinfo_q_i; assign rvfi_csr_rmask_d.tinfo = '1; assign rvfi_csr_wdata_d.tinfo = csr_tinfo_n_i; assign rvfi_csr_wmask_d.tinfo = csr_tinfo_we_i ? '1 : '0; - assign rvfi_csr_rdata_d.tcontrol = csr_tcontrol_q_i; - assign rvfi_csr_rmask_d.tcontrol = '1; - assign rvfi_csr_wdata_d.tcontrol = csr_tcontrol_n_i; - assign rvfi_csr_wmask_d.tcontrol = csr_tcontrol_we_i ? '1 : '0; - // Debug / Trace assign ex_csr_rdata_d.nmip = csr_dcsr_q_i[3]; // dcsr.nmip is autonomous. Propagate read value from EX stage assign rvfi_csr_rdata_d.dcsr = {csr_dcsr_q_i[31:4], ex_csr_rdata.nmip, csr_dcsr_q_i[2:0]}; @@ -1900,17 +1900,13 @@ module cv32e40s_rvfi assign rvfi_csr_tselect_wmask = rvfi_csr_wmask.tselect; assign rvfi_csr_tdata_rdata = rvfi_csr_rdata.tdata; assign rvfi_csr_tdata_rmask[0] = '0; // Does not exist - assign rvfi_csr_tdata_rmask[3:1] = rvfi_csr_rmask.tdata[3:1]; + assign rvfi_csr_tdata_rmask[2:1] = rvfi_csr_rmask.tdata[2:1]; assign rvfi_csr_tdata_wdata = rvfi_csr_wdata.tdata; assign rvfi_csr_tdata_wmask = rvfi_csr_wmask.tdata; assign rvfi_csr_tinfo_rdata = rvfi_csr_rdata.tinfo; assign rvfi_csr_tinfo_rmask = rvfi_csr_rmask.tinfo; assign rvfi_csr_tinfo_wdata = rvfi_csr_wdata.tinfo; assign rvfi_csr_tinfo_wmask = rvfi_csr_wmask.tinfo; - assign rvfi_csr_tcontrol_rdata = rvfi_csr_rdata.tcontrol; - assign rvfi_csr_tcontrol_rmask = rvfi_csr_rmask.tcontrol; - assign rvfi_csr_tcontrol_wdata = rvfi_csr_wdata.tcontrol; - assign rvfi_csr_tcontrol_wmask = rvfi_csr_wmask.tcontrol; assign rvfi_csr_dcsr_rdata = rvfi_csr_rdata.dcsr; assign rvfi_csr_dcsr_rmask = rvfi_csr_rmask.dcsr; assign rvfi_csr_dcsr_wdata = rvfi_csr_wdata.dcsr; diff --git a/bhv/cv32e40s_wrapper.sv b/bhv/cv32e40s_wrapper.sv index 93caa90a4..04463c805 100644 --- a/bhv/cv32e40s_wrapper.sv +++ b/bhv/cv32e40s_wrapper.sv @@ -332,6 +332,9 @@ module cv32e40s_wrapper .tselect_q (core_i.cs_registers_i.debug_triggers_i.gen_triggers.tselect_q), .tdata1_q (core_i.cs_registers_i.debug_triggers_i.gen_triggers.tdata1_q), .tdata2_q (core_i.cs_registers_i.debug_triggers_i.gen_triggers.tdata2_q), + .trigger_match_if_wb (core_i.ex_wb_pipe.trigger_match), + .trigger_match_ex_wb (core_i.wpt_match_wb), + .wb_valid_i (core_i.wb_valid), .*); end endgenerate @@ -369,7 +372,8 @@ module cv32e40s_wrapper #(.DEBUG (DEBUG), .PMA_NUM_REGIONS(PMA_NUM_REGIONS), .CLIC(CLIC), - .REGFILE_NUM_READ_PORTS(core_i.REGFILE_NUM_READ_PORTS)) + .REGFILE_NUM_READ_PORTS(core_i.REGFILE_NUM_READ_PORTS), + .DBG_NUM_TRIGGERS(DBG_NUM_TRIGGERS)) core_sva (// probed cs_registers signals .cs_registers_mie_q (core_i.cs_registers_i.mie_q), .cs_registers_mepc_n (core_i.cs_registers_i.mepc_n), @@ -731,9 +735,6 @@ endgenerate .csr_tdata2_n_i ( core_i.cs_registers_i.debug_triggers_i.tdata2_n_r ), .csr_tdata2_q_i ( core_i.cs_registers_i.tdata2_rdata ), .csr_tdata2_we_i ( core_i.cs_registers_i.debug_triggers_i.tdata2_we_r ), - .csr_tdata3_n_i ( core_i.cs_registers_i.debug_triggers_i.tdata3_n ), - .csr_tdata3_q_i ( core_i.cs_registers_i.tdata3_rdata ), - .csr_tdata3_we_i ( core_i.cs_registers_i.tdata3_we ), .csr_tinfo_n_i ( core_i.cs_registers_i.debug_triggers_i.tinfo_n ), .csr_tinfo_q_i ( core_i.cs_registers_i.tinfo_rdata ), .csr_tinfo_we_i ( core_i.cs_registers_i.tinfo_we ), @@ -761,9 +762,6 @@ endgenerate .csr_mstatush_n_i ( core_i.cs_registers_i.mstatush_n ), .csr_mstatush_q_i ( core_i.cs_registers_i.mstatush_rdata ), .csr_mstatush_we_i ( core_i.cs_registers_i.mstatush_we ), - .csr_tcontrol_n_i ( core_i.cs_registers_i.debug_triggers_i.tcontrol_n ), - .csr_tcontrol_q_i ( core_i.cs_registers_i.tcontrol_rdata ), - .csr_tcontrol_we_i ( core_i.cs_registers_i.tcontrol_we ), .csr_tselect_n_i ( core_i.cs_registers_i.debug_triggers_i.tselect_n ), .csr_tselect_q_i ( core_i.cs_registers_i.tselect_rdata ), .csr_tselect_we_i ( core_i.cs_registers_i.tselect_we ), diff --git a/bhv/include/cv32e40s_wrapper.vh b/bhv/include/cv32e40s_wrapper.vh index 63799fdfc..d9d09eacb 100644 --- a/bhv/include/cv32e40s_wrapper.vh +++ b/bhv/include/cv32e40s_wrapper.vh @@ -151,10 +151,6 @@ .rvfi_csr_tinfo_wmask(),\ .rvfi_csr_tinfo_rdata(),\ .rvfi_csr_tinfo_wdata(),\ -.rvfi_csr_tcontrol_rmask(),\ -.rvfi_csr_tcontrol_wmask(),\ -.rvfi_csr_tcontrol_rdata(),\ -.rvfi_csr_tcontrol_wdata(),\ .rvfi_csr_dcsr_rmask(),\ .rvfi_csr_dcsr_wmask(),\ .rvfi_csr_dcsr_rdata(),\ diff --git a/rtl/cv32e40s_controller.sv b/rtl/cv32e40s_controller.sv index 39237b17b..ca1479560 100644 --- a/rtl/cv32e40s_controller.sv +++ b/rtl/cv32e40s_controller.sv @@ -70,7 +70,7 @@ module cv32e40s_controller import cv32e40s_pkg::*; input ex_wb_pipe_t ex_wb_pipe_i, input mpu_status_e mpu_status_wb_i, // MPU status (WB stage) - input logic wpt_match_wb_i, // LSU watchpoint trigger in WB + input logic [31:0] wpt_match_wb_i, // LSU watchpoint trigger in WB input align_status_e align_status_wb_i, // Aligned status (atomics and mret pointers) in WB // Last operation bits diff --git a/rtl/cv32e40s_controller_fsm.sv b/rtl/cv32e40s_controller_fsm.sv index cc417ca0f..82e187369 100644 --- a/rtl/cv32e40s_controller_fsm.sv +++ b/rtl/cv32e40s_controller_fsm.sv @@ -74,7 +74,7 @@ module cv32e40s_controller_fsm import cv32e40s_pkg::*; input logic abort_op_wb_i, // WB stage contains an (to be) aborted instruction or sequence input mpu_status_e mpu_status_wb_i, // MPU status (WB timing) input align_status_e align_status_wb_i, // Aligned status (atomics) in WB - input logic wpt_match_wb_i, // LSU watchpoint trigger (WB) + input logic [31:0] wpt_match_wb_i, // LSU watchpoint trigger (WB) // From LSU (WB) @@ -183,7 +183,7 @@ module cv32e40s_controller_fsm import cv32e40s_pkg::*; logic mret_ptr_in_wb; // CLIC pointer caused by mret is in WB logic dret_in_wb; logic ebreak_in_wb; - logic trigger_match_in_wb; // mcontrol6 trigger in WB + logic trigger_match_in_wb; // mcontrol2/6 trigger in WB logic etrigger_in_wb; // exception trigger in WB logic clic_ptr_in_wb; // CLIC pointer caused by directly acking an SHV is in WB (no mret) @@ -447,7 +447,7 @@ module cv32e40s_controller_fsm import cv32e40s_pkg::*; // Trigger match in wb // Trigger_match during debug mode is masked in the trigger logic inside cs_registers.sv - assign trigger_match_in_wb = ((ex_wb_pipe_i.trigger_match || wpt_match_wb_i) && ex_wb_pipe_i.instr_valid); + assign trigger_match_in_wb = ((|ex_wb_pipe_i.trigger_match) || (|wpt_match_wb_i)) && ex_wb_pipe_i.instr_valid; // Only set the etrigger_in_wb flag when wb_valid is true (WB is not halted or killed). // If a higher priority event than taking an exception (NMI, external debug or interrupts) are present, wb_valid_i will be @@ -719,6 +719,8 @@ module cv32e40s_controller_fsm import cv32e40s_pkg::*; debug_cause_n = DBG_CAUSE_NONE; debug_mode_n = debug_mode_q; ctrl_fsm_o.debug_csr_save = 1'b0; + ctrl_fsm_o.debug_trigger_hit = '0; // Mask of which triggers did hit. + ctrl_fsm_o.debug_trigger_hit_update = 1'b0; // Signal that hit bits of mcontrol6 shall be written. ctrl_fsm_o.block_data_addr = 1'b0; // Single step halting of IF @@ -1184,6 +1186,13 @@ module cv32e40s_controller_fsm import cv32e40s_pkg::*; ctrl_fsm_o.csr_save_cause = !(ebreak_in_wb && debug_mode_q); // No CSR update for ebreak in debug mode ctrl_fsm_o.debug_csr_save = 1'b1; + // If a trigger was hit, signal that mcontrol6 hit1 and hit0 bits should be written. + // Only triggers configured as mcontrol6 will perform the actual write within debug_triggers. + if (debug_cause_q == DBG_CAUSE_TRIGGER) begin + ctrl_fsm_o.debug_trigger_hit_update = 1'b1; + ctrl_fsm_o.debug_trigger_hit = ex_wb_pipe_i.trigger_match | wpt_match_wb_i; + end + // debug_cause_q set when decision was made to enter debug if (debug_cause_q != DBG_CAUSE_STEP) begin // Kill pipeline diff --git a/rtl/cv32e40s_core.sv b/rtl/cv32e40s_core.sv index 41429080c..1fe00a085 100644 --- a/rtl/cv32e40s_core.sv +++ b/rtl/cv32e40s_core.sv @@ -264,7 +264,7 @@ module cv32e40s_core import cv32e40s_pkg::*; logic lsu_first_op_ex; logic lsu_last_op_ex; mpu_status_e lsu_mpu_status_wb; - logic lsu_wpt_match_wb; + logic [31:0] lsu_wpt_match_wb; align_status_e lsu_align_status_wb; logic [31:0] lsu_rdata_wb; lsu_err_wb_t lsu_err_wb; @@ -286,7 +286,7 @@ module cv32e40s_core import cv32e40s_pkg::*; logic data_stall_wb; - logic wpt_match_wb; // Sticky wpt_match from WB stage + logic [31:0] wpt_match_wb; // Sticky wpt_match from WB stage mpu_status_e mpu_status_wb; // Sticky mpu_status from WB stage align_status_e align_status_wb; // Sticky align_status from WB stage @@ -331,9 +331,11 @@ module cv32e40s_core import cv32e40s_pkg::*; dcsr_t dcsr; // trigger match detected in trigger module (using IF timing) - logic trigger_match_if; + // One bit per trigger (max 32 triggers) + logic [31:0] trigger_match_if; // trigger match detected in trigger module (using EX/LSU timing) - logic trigger_match_ex; + // One bit per trigger (max 32 triggers) + logic [31:0] trigger_match_ex; // trigger match detected in trigger module (using WB timing, etrigger) logic etrigger_wb; diff --git a/rtl/cv32e40s_cs_registers.sv b/rtl/cv32e40s_cs_registers.sv index 4cc4ad1de..1122b8807 100644 --- a/rtl/cv32e40s_cs_registers.sv +++ b/rtl/cv32e40s_cs_registers.sv @@ -134,8 +134,8 @@ module cv32e40s_cs_registers import cv32e40s_pkg::*; input logic [31:0] pc_if_i, input logic ptr_in_if_i, input privlvl_t priv_lvl_if_i, - output logic trigger_match_if_o, - output logic trigger_match_ex_o, + output logic [31:0] trigger_match_if_o, + output logic [31:0] trigger_match_ex_o, output logic etrigger_wb_o, input logic lsu_valid_ex_i, input logic [31:0] lsu_addr_ex_i, @@ -198,15 +198,9 @@ module cv32e40s_cs_registers import cv32e40s_pkg::*; logic [31:0] tdata2_rdata; logic tdata2_we; - logic [31:0] tdata3_rdata; - logic tdata3_we; - logic [31:0] tinfo_rdata; logic tinfo_we; - logic [31:0] tcontrol_rdata; - logic tcontrol_we; - // Debug dcsr_t dcsr_q, dcsr_n, dcsr_rdata; logic dcsr_we; @@ -664,15 +658,6 @@ module cv32e40s_cs_registers import cv32e40s_pkg::*; end end - CSR_TDATA3: begin - if (DBG_NUM_TRIGGERS > 0) begin - csr_rdata_int = tdata3_rdata; - end else begin - csr_rdata_int = '0; - illegal_csr_read = 1'b1; - end - end - CSR_TINFO: begin if (DBG_NUM_TRIGGERS > 0) begin csr_rdata_int = tinfo_rdata; @@ -682,15 +667,6 @@ module cv32e40s_cs_registers import cv32e40s_pkg::*; end end - CSR_TCONTROL: begin - if (DBG_NUM_TRIGGERS > 0) begin - csr_rdata_int = tcontrol_rdata; - end else begin - csr_rdata_int = '0; - illegal_csr_read = 1'b1; - end - end - CSR_DCSR: begin if (DEBUG) begin csr_rdata_int = dcsr_rdata; @@ -1023,12 +999,8 @@ module cv32e40s_cs_registers import cv32e40s_pkg::*; tdata2_we = 1'b0; - tdata3_we = 1'b0; - tinfo_we = 1'b0; - tcontrol_we = 1'b0; - mstatus_n = csr_next_value(mstatus_t'{ tw: csr_wdata_int[MSTATUS_TW_BIT], mprv: mstatus_mprv_resolve(mstatus_rdata.mprv, csr_wdata_int[MSTATUS_MPRV_BIT]), @@ -1356,20 +1328,10 @@ module cv32e40s_cs_registers import cv32e40s_pkg::*; end end - CSR_TDATA3: begin - if (ctrl_fsm_i.debug_mode) begin - tdata3_we = 1'b1; - end - end - CSR_TINFO: begin tinfo_we = 1'b1; end - CSR_TCONTROL: begin - tcontrol_we = 1'b1; - end - CSR_DCSR: begin dcsr_we = 1'b1; end @@ -2689,17 +2651,13 @@ module cv32e40s_cs_registers import cv32e40s_pkg::*; .tselect_we_i ( tselect_we ), .tdata1_we_i ( tdata1_we ), .tdata2_we_i ( tdata2_we ), - .tdata3_we_i ( tdata3_we ), .tinfo_we_i ( tinfo_we ), - .tcontrol_we_i ( tcontrol_we ), // CSR read data outputs .tselect_rdata_o ( tselect_rdata ), .tdata1_rdata_o ( tdata1_rdata ), .tdata2_rdata_o ( tdata2_rdata ), - .tdata3_rdata_o ( tdata3_rdata ), .tinfo_rdata_o ( tinfo_rdata ), - .tcontrol_rdata_o ( tcontrol_rdata ), // IF stage inputs .pc_if_i ( pc_if_i ), diff --git a/rtl/cv32e40s_debug_triggers.sv b/rtl/cv32e40s_debug_triggers.sv index 866b94492..c3fd5f816 100644 --- a/rtl/cv32e40s_debug_triggers.sv +++ b/rtl/cv32e40s_debug_triggers.sv @@ -45,17 +45,13 @@ import cv32e40s_pkg::*; input logic tselect_we_i, input logic tdata1_we_i, input logic tdata2_we_i, - input logic tdata3_we_i, input logic tinfo_we_i, - input logic tcontrol_we_i, // CSR read data outputs output logic [31:0] tselect_rdata_o, output logic [31:0] tdata1_rdata_o, output logic [31:0] tdata2_rdata_o, - output logic [31:0] tdata3_rdata_o, output logic [31:0] tinfo_rdata_o, - output logic [31:0] tcontrol_rdata_o, // IF stage inputs input logic [31:0] pc_if_i, @@ -76,18 +72,15 @@ import cv32e40s_pkg::*; input ctrl_fsm_t ctrl_fsm_i, // Trigger match outputs - output logic trigger_match_if_o, // Instruction address match - output logic trigger_match_ex_o, // Load/Store address match + output logic [31:0] trigger_match_if_o, // Instruction address match + output logic [31:0] trigger_match_ex_o, // Load/Store address match output logic etrigger_wb_o // Exception trigger match ); // CSR write data logic [31:0] tselect_n; - logic [31:0] tdata1_n; logic [31:0] tdata2_n; - logic [31:0] tdata3_n; logic [31:0] tinfo_n; - logic [31:0] tcontrol_n; // RVFI only signals logic [31:0] tdata1_n_r; @@ -105,8 +98,12 @@ import cv32e40s_pkg::*; if (DBG_NUM_TRIGGERS > 0) begin : gen_triggers // Internal CSR write enables logic [DBG_NUM_TRIGGERS-1 : 0] tdata1_we_int; + logic [DBG_NUM_TRIGGERS-1 : 0] tdata1_we_hit; logic [DBG_NUM_TRIGGERS-1 : 0] tdata2_we_int; + // Next-values for tdata1 + logic [31:0] tdata1_n[DBG_NUM_TRIGGERS]; + // CSR instance outputs logic [31:0] tdata1_q[DBG_NUM_TRIGGERS]; logic [31:0] tdata2_q[DBG_NUM_TRIGGERS]; @@ -148,89 +145,118 @@ import cv32e40s_pkg::*; // Exception trigger code match logic [31:0] exception_match[DBG_NUM_TRIGGERS]; + // Resolve hit1+hit0 of mcontrol6 + logic [1:0] mcontrol6_hit_resolved[DBG_NUM_TRIGGERS]; + + // Write data + // tdata1 has one _n value per implemented trigger to enable updating all hit-fields of + // mcontrol6 at the same time. + for (genvar idx=0; idx DBG_NUM_TRIGGERS-1) tselect_n = (csr_wdata_i < DBG_NUM_TRIGGERS) ? csr_wdata_i : tselect_rdata_o; - tdata1_n = tdata1_rdata_o; tdata2_n = tdata2_rdata_o; - if (tdata1_we_i) begin - if (csr_wdata_i[TDATA1_TTYPE_HIGH:TDATA1_TTYPE_LOW] == TTYPE_MCONTROL) begin - // Mcontrol supports any value in tdata2, no need to check tdata2 before writing tdata1 - tdata1_n = { - TTYPE_MCONTROL, // type : address/data match - 1'b1, // dmode : access from D mode only - 6'b000000, // maskmax : hardwired to zero - 1'b0, // hit : hardwired to zero - 1'b0, // select : hardwired to zero, only address matching - 1'b0, // timing : hardwired to zero, only 'before' timing - 2'b00, // sizelo : hardwired to zero, match any size - 4'b0001, // action : enter debug on match - 1'b0, // chain : hardwired to zero - mcontrol2_6_match_resolve(csr_wdata_i[MCONTROL2_6_MATCH_HIGH:MCONTROL2_6_MATCH_LOW]), // match, WARL(0,2,3) 10:7 - csr_wdata_i[6], // m : match in machine mode - 1'b0, // : hardwired to zero - 1'b0, // s : hardwired to zer0 - mcontrol2_6_u_resolve(csr_wdata_i[MCONTROL2_6_U]), // zero, U 3 - csr_wdata_i[2], // EXECUTE 2 - csr_wdata_i[1], // STORE 1 - csr_wdata_i[0] // LOAD 0 - }; - end else if (csr_wdata_i[TDATA1_TTYPE_HIGH:TDATA1_TTYPE_LOW] == TTYPE_MCONTROL6) begin - // Mcontrol6 supports any value in tdata2, no need to check tdata2 before writing tdata1 - tdata1_n = { - TTYPE_MCONTROL6, // type : address/data match - 1'b1, // dmode : access from D mode only - 2'b00, // zero 26:25 - 3'b000, // zero, vs, vu, hit 24:22 - 1'b0, // zero, select 21 - 1'b0, // zero, timing 20 - 4'b0000, // zero, size (match any size) 19:16 - 4'b0001, // action, WARL(1), enter debug 15:12 - 1'b0, // zero, chain 11 - mcontrol2_6_match_resolve(csr_wdata_i[MCONTROL2_6_MATCH_HIGH:MCONTROL2_6_MATCH_LOW]), // match, WARL(0,2,3) 10:7 - csr_wdata_i[6], // M 6 - 1'b0, // zero 5 - 1'b0, // zero, S 4 - mcontrol2_6_u_resolve(csr_wdata_i[MCONTROL2_6_U]), // zero, U 3 - csr_wdata_i[2], // EXECUTE 2 - csr_wdata_i[1], // STORE 1 - csr_wdata_i[0] // LOAD 0 - }; - end else if (csr_wdata_i[TDATA1_TTYPE_HIGH:TDATA1_TTYPE_LOW] == TTYPE_ETRIGGER) begin - // Etrigger can only support a subset of possible values in tdata2, only update tdata1 if - // tdata2 contains a legal value for etrigger. - - // Detect if any cleared bits in ETRIGGER_TDATA2_MASK are set in tdata2 - if (|(tdata2_rdata_o & (~ETRIGGER_TDATA2_MASK))) begin - // Unsupported exception codes enabled, default to disabled trigger. - tdata1_n = {TTYPE_DISABLED, 1'b1, {27{1'b0}}}; - end else begin - tdata1_n = { - TTYPE_ETRIGGER, // type : exception trigger - 1'b1, // dmode : access from D mode only 27 - 1'b0, // hit : WARL(0) 26 - 13'h0, // zero : tied to zero 25:13 - 1'b0, // vs : WARL(0) 12 - 1'b0, // vu : WARL(0) 11 - 1'b0, // zero : tied to zero 10 - csr_wdata_i[9], // m : Match in machine mode 9 - 1'b0, // zero : tied to zero 8 - 1'b0, // s : WARL(0) 7 - etrigger_u_resolve(csr_wdata_i[ETRIGGER_U]), // u : Match in user mode 6 - 6'b000001 // action : WARL(1), enter debug on match - }; - end - end else if (csr_wdata_i[TDATA1_TTYPE_HIGH:TDATA1_TTYPE_LOW] == TTYPE_DISABLED) begin - // All tdata2 values are legal for a disabled trigger, no WARL on tdata1. - tdata1_n = {TTYPE_DISABLED, 1'b1, {27{1'b0}}}; - end else begin - // No legal trigger type, set disabled trigger type 0xF - tdata1_n = {TTYPE_DISABLED, 1'b1, {27{1'b0}}}; - end - end // tdata1_we_i - // tdata2 if (tdata2_we_i) begin if ((tdata1_rdata_o[TDATA1_TTYPE_HIGH:TDATA1_TTYPE_LOW] == TTYPE_DISABLED) || @@ -244,9 +270,7 @@ import cv32e40s_pkg::*; end end // tdata2_we_i - tdata3_n = tdata3_rdata_o; // Read only tinfo_n = tinfo_rdata_o; // Read only - tcontrol_n = tcontrol_rdata_o; // Read only end // Calculate highest and lowest value of address[1:0] based on lsu_be_ex_i @@ -376,7 +400,7 @@ import cv32e40s_pkg::*; .clk ( clk ), .rst_n ( rst_n ), .scan_cg_en_i ( scan_cg_en_i ), - .wr_data_i ( tdata1_n ), + .wr_data_i ( tdata1_n[idx] ), .wr_en_i ( tdata1_we_int[idx] ), .rd_data_o ( tdata1_q[idx] ), .rd_error_o ( tdata1_rd_error[idx] ) @@ -401,7 +425,7 @@ import cv32e40s_pkg::*; ); // Set write enables - assign tdata1_we_int[idx] = tdata1_we_i && (tselect_rdata_o == idx); + assign tdata1_we_int[idx] = (tdata1_we_i && (tselect_rdata_o == idx)) || tdata1_we_hit[idx]; assign tdata2_we_int[idx] = tdata2_we_i && (tselect_rdata_o == idx); // Assign read data @@ -448,7 +472,14 @@ import cv32e40s_pkg::*; tdata1_we_r = tdata1_we_i || tselect_we_i; tdata2_we_r = tdata2_we_i || tselect_we_i; - tdata1_n_r = tdata1_n; + tdata1_n_r = tdata1_n[0]; + + for (int i=0; i - $past(wpt_match_wb_i)) + $past(|wpt_match_wb_i)) else `uvm_error("conroller", "LSU active in WB during DEBUG_TAKEN with no preceeding watchpoint trigger") // MRET in WB shall not update CSRs if WB stage is halted (debug entry) @@ -1091,7 +1091,7 @@ generate assert property (@(posedge clk) disable iff (!rst_n) (ex_wb_pipe_i.instr_valid && ex_wb_pipe_i.lsu_en) && ctrl_fsm_o.halt_wb |-> - wpt_match_wb_i) + |wpt_match_wb_i) else `uvm_error("controller", "LSU in WB halted without watchpoint trigger match") // Check that debug is always taken when a watchpoint trigger is arrives in WB // The watchpoint is halted during its first cycle in WB, thus checking during FUNCTIONAL state only, @@ -1099,7 +1099,7 @@ generate // the controller will go back to FUNCTIONAL. a_wpt_debug_entry: assert property (@(posedge clk) disable iff (!rst_n) - (ex_wb_pipe_i.instr_valid && wpt_match_wb_i) && (ctrl_fsm_cs == FUNCTIONAL) + (ex_wb_pipe_i.instr_valid && |wpt_match_wb_i) && (ctrl_fsm_cs == FUNCTIONAL) |-> (abort_op_wb_i && (ctrl_fsm_ns == DEBUG_TAKEN))) else `uvm_error("controller", "Debug not entered on a WPT match") diff --git a/sva/cv32e40s_core_sva.sv b/sva/cv32e40s_core_sva.sv index cffa7dfb2..e859ed482 100644 --- a/sva/cv32e40s_core_sva.sv +++ b/sva/cv32e40s_core_sva.sv @@ -29,7 +29,8 @@ module cv32e40s_core_sva parameter int PMA_NUM_REGIONS = 0, parameter bit CLIC = 0, parameter int unsigned REGFILE_NUM_READ_PORTS = 2, - parameter bit DEBUG = 1 + parameter bit DEBUG = 1, + parameter int DBG_NUM_TRIGGERS = 1 ) ( input logic clk, @@ -111,6 +112,8 @@ module cv32e40s_core_sva input rf_addr_t rf_raddr_id[REGFILE_NUM_READ_PORTS], input rf_data_t rf_rdata_id[REGFILE_NUM_READ_PORTS], + input logic [31:0] lsu_wpt_match_wb, + input logic alu_jmpr_id_i, input logic alu_en_id_i, @@ -865,6 +868,17 @@ generate // todo: add similar assertion as above to check that only one instruction moves from IF to ID while taking a single step (rename inst_taken to inst_taken_id and introduce similar inst_taken_if signal) + // Check that unused trigger bits remain zero + a_unused_trigger_bits: + assert property (@(posedge clk) disable iff (!rst_ni) + 1'b1 + |-> + (|if_id_pipe.trigger_match[31:DBG_NUM_TRIGGERS] == 1'b0) && + (|id_ex_pipe.trigger_match[31:DBG_NUM_TRIGGERS] == 1'b0) && + (|ex_wb_pipe.trigger_match[31:DBG_NUM_TRIGGERS] == 1'b0) && + (|lsu_wpt_match_wb[31:DBG_NUM_TRIGGERS] == 1'b0)) + else `uvm_error("core", "Unused trigger bits are not zero") + end endgenerate endmodule diff --git a/sva/cv32e40s_debug_triggers_sva.sv b/sva/cv32e40s_debug_triggers_sva.sv index 0c761cef1..ae8c98ebf 100644 --- a/sva/cv32e40s_debug_triggers_sva.sv +++ b/sva/cv32e40s_debug_triggers_sva.sv @@ -40,7 +40,11 @@ module cv32e40s_debug_triggers_sva input ctrl_fsm_t ctrl_fsm_i, input logic [31:0] tselect_q, input logic [31:0] tdata1_q[DBG_NUM_TRIGGERS], - input logic [31:0] tdata2_q[DBG_NUM_TRIGGERS] + input logic [31:0] tdata2_q[DBG_NUM_TRIGGERS], + input logic [31:0] trigger_match_if_wb, + input logic [31:0] trigger_match_ex_wb, + input logic wb_valid_i, + input logic tdata1_we_i ); @@ -81,6 +85,52 @@ module cv32e40s_debug_triggers_sva $stable(tdata2_q)) // Checking stability of ALL tdata2, not just the one selected else `uvm_error("debug_triggers", "tdata2_q changed after set/clear with rs1==0") +generate + for (genvar i=0; i + (tdata1_q[i][MCONTROL_6_HIT0] == 1'b1) && + (tdata1_q[i][MCONTROL_6_HIT1] == 1'b0)) + else `uvm_error("debug_triggers", "mcontrol6.hit0 not set on trigger match") + + // Check that trigger that did not match has stable {hit1, hit0} + a_mcontrol6_not_hit_stable: + assert property (@(posedge clk) disable iff (!rst_n) + (tdata1_q[i][TDATA1_TTYPE_HIGH:TDATA1_TTYPE_LOW] == TTYPE_MCONTROL6) && + |(trigger_match_if_wb | trigger_match_ex_wb) && // Any trigger matched + !(trigger_match_if_wb[i] || trigger_match_ex_wb[i]) && // But not this one + wb_valid_i + |=> + ($stable(tdata1_q[i][MCONTROL_6_HIT0])) && + ($stable(tdata1_q[i][MCONTROL_6_HIT1]))) + else `uvm_error("debug_triggers", "mcontrol6.hit0/1 changed without a trigger match") + end +endgenerate + + // Check that SW writes to tdata1 cannot happen at the same time as the controller wants to upate hit bits in mcontrol6 + a_tdata1_writes_unique: + assert property (@(posedge clk) disable iff (!rst_n) + (tdata1_we_i || ctrl_fsm_i.debug_trigger_hit_update) + |-> + (tdata1_we_i != ctrl_fsm_i.debug_trigger_hit_update)) + else `uvm_error("debug_triggers", "SW write to tdata1 at the same time as controller write.") + + // Check that we cannot have trigger match from both IF and EX for the same trigger + a_if_ex_trig_exclusive: + assert property (@(posedge clk) disable iff (!rst_n) + |(trigger_match_if_wb & trigger_match_ex_wb) == 1'b0) + else `uvm_error("debug_triggers", "Trigger match from both IF and EX for the same trigger should not happen") + + // Check that DBG_NUM_TRIGGERS is <= 32 + a_max_num_triggers: + assert property (@(posedge clk) disable iff (!rst_n) + (DBG_NUM_TRIGGERS <= 32)) + else `uvm_error("debug_triggers", "DBG_NUM_TRIGGERS can max have the value of 32") endmodule diff --git a/sva/cv32e40s_load_store_unit_sva.sv b/sva/cv32e40s_load_store_unit_sva.sv index ebab34798..e817fd98e 100644 --- a/sva/cv32e40s_load_store_unit_sva.sv +++ b/sva/cv32e40s_load_store_unit_sva.sv @@ -48,8 +48,8 @@ module cv32e40s_load_store_unit_sva input logic lsu_first_op_0_o, input logic valid_0_i, input logic ready_0_i, - input logic trigger_match_0_i, - input logic lsu_wpt_match_1_o + input logic [31:0] trigger_match_0_i, + input logic [31:0] lsu_wpt_match_1_o ); // Check that outstanding transaction count will not overflow DEPTH @@ -225,13 +225,13 @@ if (DEBUG) begin assert property (@(posedge clk) disable iff (!rst_n) (cnt_q == 2'b00) && (ex_wb_pipe_i.lsu_en && ex_wb_pipe_i.instr_valid) |-> - $past(lsu_wpt_match_1_o) && (ctrl_fsm_cs == DEBUG_TAKEN)) + |$past(lsu_wpt_match_1_o) && (ctrl_fsm_cs == DEBUG_TAKEN)) else `uvm_error("load_store_unit", "Illegal cause of cnt_q=0 while a valid LSU instruction is in WB") // MPU errors and watchpoint triggers cannot happen at the same time a_mpuerr_wpt_unique: assert property (@(posedge clk) disable iff (!rst_n) - lsu_wpt_match_1_o + |lsu_wpt_match_1_o |-> !(lsu_mpu_status_1_o != MPU_OK)) else `uvm_error("load_store_unit", "MPU error and watchpoint trigger not unique") diff --git a/sva/cv32e40s_rvfi_sva.sv b/sva/cv32e40s_rvfi_sva.sv index 997df3375..ef281db09 100644 --- a/sva/cv32e40s_rvfi_sva.sv +++ b/sva/cv32e40s_rvfi_sva.sv @@ -82,7 +82,10 @@ module cv32e40s_rvfi_sva input logic [ 4*NMEM-1:0] rvfi_mem_wmask, input logic [32*NMEM-1:0] rvfi_mem_rdata, input logic [32*NMEM-1:0] rvfi_mem_wdata, - input logic [ 3*NMEM-1:0] rvfi_mem_prot + input logic [ 3*NMEM-1:0] rvfi_mem_prot, + input logic [ 6*NMEM-1:0] rvfi_mem_atop, + input logic [ 2*NMEM-1:0] rvfi_mem_memtype, + input logic [ 1*NMEM-1:0] rvfi_mem_dbg ); rvfi_trap_t rvfi_trap_q; // RVFI trap value of the previous valid rvfi instruction @@ -373,6 +376,9 @@ end bit [32*NMEM-1:0] rdata; bit [32*NMEM-1:0] wdata; bit [ 3*NMEM-1:0] prot; + bit [ 6*NMEM-1:0] atop; + bit [ 2*NMEM-1:0] memtype; + bit [ 1*NMEM-1:0] dbg; } rvfi_mem_t; // Return number of memory operations based on rvfi_mem_rmaks/wmask @@ -437,12 +443,15 @@ end ((rvfi_trap.debug_cause == 3'h1) || // Debug Breakpoint (rvfi_trap.debug_cause == 3'h2)))); // Debug trigger match - assign rvfi_mem.addr = rvfi_mem_addr; - assign rvfi_mem.rmask = rvfi_mem_rmask; - assign rvfi_mem.wmask = rvfi_mem_wmask; - assign rvfi_mem.rdata = rvfi_mem_rdata; - assign rvfi_mem.wdata = rvfi_mem_wdata; - assign rvfi_mem.prot = rvfi_mem_prot; + assign rvfi_mem.addr = rvfi_mem_addr; + assign rvfi_mem.rmask = rvfi_mem_rmask; + assign rvfi_mem.wmask = rvfi_mem_wmask; + assign rvfi_mem.rdata = rvfi_mem_rdata; + assign rvfi_mem.wdata = rvfi_mem_wdata; + assign rvfi_mem.prot = rvfi_mem_prot; + assign rvfi_mem.atop = rvfi_mem_atop; + assign rvfi_mem.memtype = rvfi_mem_memtype; + assign rvfi_mem.dbg = rvfi_mem_dbg; localparam MAX_GNT_DLY = 2; @@ -555,12 +564,15 @@ end // Assemble expected transaction on RVFI, based on OBI FIFO always_comb begin - rvfi_mem_exp.addr [32*i_memop +: 32] = '0; - rvfi_mem_exp.rmask[ 4*i_memop +: 4] = '0; - rvfi_mem_exp.wmask[ 4*i_memop +: 4] = '0; - rvfi_mem_exp.rdata[32*i_memop +: 32] = '0; - rvfi_mem_exp.wdata[32*i_memop +: 32] = '0; - rvfi_mem_exp.prot [ 3*i_memop +: 3] = '0; + rvfi_mem_exp.addr [32*i_memop +: 32] = '0; + rvfi_mem_exp.rmask [ 4*i_memop +: 4] = '0; + rvfi_mem_exp.wmask [ 4*i_memop +: 4] = '0; + rvfi_mem_exp.rdata [32*i_memop +: 32] = '0; + rvfi_mem_exp.wdata [32*i_memop +: 32] = '0; + rvfi_mem_exp.prot [ 3*i_memop +: 3] = '0; + rvfi_mem_exp.atop [ 6*i_memop +: 6] = '0; + rvfi_mem_exp.memtype [ 2*i_memop +: 2] = '0; + rvfi_mem_exp.dbg [ 1*i_memop +: 1] = '0; exp_rvfi_mem_mask = '0; split_2nd_shift = '0; @@ -613,8 +625,11 @@ end end // Addr and prot are equal for both transfers in a split transfer - rvfi_mem_exp.addr[(32*i_memop) +: 32] = data_obi_req_fifo[rd_ptr_memop].addr; - rvfi_mem_exp.prot[(3*i_memop) +: 3] = data_obi_req_fifo[rd_ptr_memop].prot; + rvfi_mem_exp.addr [(32*i_memop) +: 32] = data_obi_req_fifo[rd_ptr_memop].addr; + rvfi_mem_exp.prot [(3*i_memop) +: 3] = data_obi_req_fifo[rd_ptr_memop].prot; + rvfi_mem_exp.atop [(6*i_memop) +: 6] = 6'd0; + rvfi_mem_exp.memtype[(2*i_memop) +: 2] = data_obi_req_fifo[rd_ptr_memop].memtype; + rvfi_mem_exp.dbg [(1*i_memop) +: 1] = data_obi_req_fifo[rd_ptr_memop].dbg; if(rvfi_mem_read[i_memop]) begin rvfi_mem_exp.rmask[(4*i_memop) +: 4] = exp_rvfi_mem_mask; @@ -650,6 +665,21 @@ end rvfi_mem_read[i_memop] |-> rvfi_mem_exp.prot[(3*i_memop) +: 3] == rvfi_mem_dly.prot[(3*i_memop) +: 3]) else `uvm_error("rvfi", "rvfi_mem_prot not consistent with OBI transfers for reads") + a_rvfi_mem_consistency_read_atop: + assert property (@(posedge clk_i) disable iff (!rst_ni) + rvfi_mem_read[i_memop] |-> rvfi_mem_exp.atop[(6*i_memop) +: 6] == rvfi_mem_dly.atop[(6*i_memop) +: 6]) + else `uvm_error("rvfi", "rvfi_mem_atop not consistent with OBI transfers for reads") + + a_rvfi_mem_consistency_read_memtype: + assert property (@(posedge clk_i) disable iff (!rst_ni) + rvfi_mem_read[i_memop] |-> rvfi_mem_exp.memtype[(2*i_memop) +: 2] == rvfi_mem_dly.memtype[(2*i_memop) +: 2]) + else `uvm_error("rvfi", "rvfi_mem_memtype not consistent with OBI transfers for reads") + + a_rvfi_mem_consistency_read_dbg: + assert property (@(posedge clk_i) disable iff (!rst_ni) + rvfi_mem_read[i_memop] |-> rvfi_mem_exp.dbg[(1*i_memop) +: 1] == rvfi_mem_dly.dbg[(1*i_memop) +: 1]) + else `uvm_error("rvfi", "rvfi_mem_dbg not consistent with OBI transfers for reads") + a_rvfi_mem_consistency_write_addr: assert property (@(posedge clk_i) disable iff (!rst_ni) obi_gnt_delay_ok && rvfi_mem_write[i_memop] |-> rvfi_mem_exp.addr[(32*i_memop) +: 32] == rvfi_mem_dly.addr[(32*i_memop) +: 32]) @@ -672,6 +702,20 @@ end obi_gnt_delay_ok && rvfi_mem_write[i_memop] |-> rvfi_mem_exp.prot[(3*i_memop) +: 3] == rvfi_mem_dly.prot[(3*i_memop) +: 3]) else `uvm_error("rvfi", "rvfi_mem_prot not consistent with OBI transfers for writes") + a_rvfi_mem_consistency_write_atop: + assert property (@(posedge clk_i) disable iff (!rst_ni) + obi_gnt_delay_ok && rvfi_mem_write[i_memop] |-> rvfi_mem_exp.atop[(6*i_memop) +: 6] == rvfi_mem_dly.atop[(6*i_memop) +: 6]) + else `uvm_error("rvfi", "rvfi_mem_atop not consistent with OBI transfers for writes") + + a_rvfi_mem_consistency_write_memtype: + assert property (@(posedge clk_i) disable iff (!rst_ni) + obi_gnt_delay_ok && rvfi_mem_write[i_memop] |-> rvfi_mem_exp.memtype[(2*i_memop) +: 2] == rvfi_mem_dly.memtype[(2*i_memop) +: 2]) + else `uvm_error("rvfi", "rvfi_mem_memtype not consistent with OBI transfers for writes") + + a_rvfi_mem_consistency_write_dbg: + assert property (@(posedge clk_i) disable iff (!rst_ni) + obi_gnt_delay_ok && rvfi_mem_write[i_memop] |-> rvfi_mem_exp.dbg[(1*i_memop) +: 1] == rvfi_mem_dly.dbg[(1*i_memop) +: 1]) + else `uvm_error("rvfi", "rvfi_mem_dbg not consistent with OBI transfers for writes") end endgenerate diff --git a/sva/cv32e40s_wb_stage_sva.sv b/sva/cv32e40s_wb_stage_sva.sv index c6b189c49..efd2391b6 100644 --- a/sva/cv32e40s_wb_stage_sva.sv +++ b/sva/cv32e40s_wb_stage_sva.sv @@ -40,10 +40,10 @@ module cv32e40s_wb_stage_sva input mpu_status_e lsu_mpu_status_i, input rf_addr_t rf_waddr_wb_o, input mpu_status_e lsu_mpu_status_q, - input logic lsu_wpt_match_i, + input logic [31:0] lsu_wpt_match_i, input logic rf_we_wb_o, input logic lsu_valid_q, - input logic lsu_wpt_match_q, + input logic [31:0] lsu_wpt_match_q, input logic lsu_valid_i ); @@ -98,7 +98,7 @@ module cv32e40s_wb_stage_sva a_lsu_wb_valid: assert property (@(posedge clk) disable iff (!rst_n) lsu_valid_i && - !(lsu_wpt_match_i || (lsu_mpu_status_i != MPU_OK)) + !(|lsu_wpt_match_i || (lsu_mpu_status_i != MPU_OK)) |-> wb_valid) else `uvm_error("wb_stage", "wb_valid not signaled immediately upon rvalid for LSU without WPT or MPU error") @@ -110,8 +110,8 @@ generate assert property (@(posedge clk) disable iff (!rst_n) lsu_valid_q |-> - lsu_wpt_match_q && - $past(lsu_wpt_match_i)) + |lsu_wpt_match_q && + |$past(lsu_wpt_match_i)) else `uvm_error("wb_stage", "LSU signal sticky for non-watchpoint cause") // A watchpoint trigger will be halted during its first cycle in WB, giving !wb_valid. @@ -119,14 +119,14 @@ generate // know the core hit a watchpoint. a_wpt_wb_halt: assert property (@(posedge clk) disable iff (!rst_n) - lsu_wpt_match_i + |lsu_wpt_match_i |-> !wb_valid && ctrl_fsm_i.halt_wb) else `uvm_error("wb_stage", "WB stage not halted on a WPT match") a_wpt_wb_valid: assert property (@(posedge clk) disable iff (!rst_n) - lsu_wpt_match_i + |lsu_wpt_match_i |=> wb_valid) else `uvm_error("wb_stage", "WB stage not setting wb_valid on a WPT") diff --git a/yaml/csr.yaml.m4 b/yaml/csr.yaml.m4 index 1f5858318..fa55ef031 100644 --- a/yaml/csr.yaml.m4 +++ b/yaml/csr.yaml.m4 @@ -4550,24 +4550,6 @@ ifelse(eval(DBG_NUM_TRIGGERS >= 1), 1, [[[ lsb: 0 ]]]) -ifelse(eval(DBG_NUM_TRIGGERS >= 1), 1, [[[ -- csr: tdata3 - description: > - Trigger Data Register 3 - address: 0x7A3 - privilege_mode: M - rv32: - - field_name: Zero - description: > - Not supported. - type: WARL - reset_val: 0 - msb: 31 - lsb: 0 - warl_legalize: | - val_out = 0 -]]]) - ifelse(eval(DBG_NUM_TRIGGERS >= 1), 1, [[[ - csr: tinfo description: > @@ -4575,12 +4557,19 @@ ifelse(eval(DBG_NUM_TRIGGERS >= 1), 1, [[[ address: 0x7A4 privilege_mode: M rv32: - - field_name: RESERVED_31_16 + - field_name: Version + description: > + Implemented version of Sdtrig + type: R + reset_val: 0x1 + msb: 31 + lsb: 24 + - field_name: RESERVED_23_16 description: > Reserved type: WARL reset_val: 0 - msb: 31 + msb: 23 lsb: 16 warl_legalize: | val_out = 0 @@ -4593,60 +4582,6 @@ ifelse(eval(DBG_NUM_TRIGGERS >= 1), 1, [[[ lsb: 0 ]]]) -ifelse(eval(DBG_NUM_TRIGGERS >= 1), 1, [[[ -- csr: tcontrol - description: > - Trigger control - address: 0x7A5 - privilege_mode: M - rv32: - - field_name: RESERVED_31_8 - description: > - Reserved - type: WARL - reset_val: 0 - msb: 31 - lsb: 8 - warl_legalize: | - val_out = 0 - - field_name: MPTE - description: > - MPTE - type: WARL - reset_val: 0 - msb: 7 - lsb: 7 - warl_legalize: | - val_out = 0 - - field_name: RESERVED_6_4 - description: > - Reserved - type: WARL - reset_val: 0 - msb: 6 - lsb: 4 - warl_legalize: | - val_out = 0 - - field_name: MTE - description: > - MTE - type: WARL - reset_val: 0 - msb: 3 - lsb: 3 - warl_legalize: | - val_out = 0 - - field_name: RESERVED_2_0 - description: > - Reserved - type: WARL - reset_val: 0 - msb: 2 - lsb: 0 - warl_legalize: | - val_out = 0 -]]]) - ifelse(eval(ZC != 0), 1, [[[ - csr: jvt description: >