[sparse_fsm_flop] Create flop macro to increase DV coverage Signed-off-by: Michael Schaffner <msf@opentitan.org>
diff --git a/hw/dv/sv/sec_cm/prim_sparse_fsm_flop_if.sv b/hw/dv/sv/sec_cm/prim_sparse_fsm_flop_if.sv index 06d27fc..b57346c 100644 --- a/hw/dv/sv/sec_cm/prim_sparse_fsm_flop_if.sv +++ b/hw/dv/sv/sec_cm/prim_sparse_fsm_flop_if.sv
@@ -7,7 +7,8 @@ // This contains a proxy class and store the object in sec_cm_pkg, which can be used in vseq to // control inject_fault and restore_fault interface prim_sparse_fsm_flop_if #( - parameter int Width = 2 + parameter int Width = 2, + parameter string CustomForceName = "" ) ( input clk_i, input rst_ni); @@ -23,6 +24,11 @@ string path = dv_utils_pkg::get_parent_hier($sformatf("%m")); string signal_forced = $sformatf("%s.state_o", path); + // This signal only has to be forced if the associated parameter + // CustomForceName in prim_sparse_fsm_flop is set to a non-empty string. + string parent_path = dv_utils_pkg::get_parent_hier($sformatf("%m"), 2); + string custom_signal_forced = $sformatf("%s.%s", parent_path, CustomForceName); + class prim_sparse_fsm_flop_if_proxy extends sec_cm_pkg::sec_cm_base_if_proxy; `uvm_object_new @@ -36,17 +42,26 @@ `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(force_value, $countones(force_value ^ orig_value) inside {[1: MaxFlipBits]};) - `DV_CHECK(uvm_hdl_deposit(signal_forced, force_value)) `uvm_info(msg_id, $sformatf("Forcing %s from %0d to %0d", signal_forced, orig_value, force_value), UVM_LOW) - + `DV_CHECK(uvm_hdl_deposit(signal_forced, force_value)) + if (CustomForceName != "") begin + `uvm_info(msg_id, $sformatf("Forcing %s from %0d to %0d", + custom_signal_forced, orig_value, force_value), UVM_LOW) + `DV_CHECK(uvm_hdl_deposit(custom_signal_forced, force_value)) + end @(posedge clk_i); endtask virtual task restore_fault(); - `DV_CHECK(uvm_hdl_deposit(signal_forced, orig_value)) `uvm_info(msg_id, $sformatf("Forcing %s to original value %0d", signal_forced, orig_value), UVM_LOW) + `DV_CHECK(uvm_hdl_deposit(signal_forced, orig_value)) + if (CustomForceName != "") begin + `uvm_info(msg_id, $sformatf("Forcing %s to original value %0d", custom_signal_forced, + orig_value), UVM_LOW) + `DV_CHECK(uvm_hdl_deposit(custom_signal_forced, orig_value)) + end endtask endclass
diff --git a/hw/dv/sv/sec_cm/sec_cm_prim_sparse_fsm_flop_bind.sv b/hw/dv/sv/sec_cm/sec_cm_prim_sparse_fsm_flop_bind.sv index 7bc15ae..c820882 100644 --- a/hw/dv/sv/sec_cm/sec_cm_prim_sparse_fsm_flop_bind.sv +++ b/hw/dv/sv/sec_cm/sec_cm_prim_sparse_fsm_flop_bind.sv
@@ -4,5 +4,5 @@ module sec_cm_prim_sparse_fsm_flop_bind(); bind prim_sparse_fsm_flop prim_sparse_fsm_flop_if #( - .Width(Width)) u_prim_sparse_fsm_flop_if (.*); + .Width(Width), .CustomForceName(CustomForceName)) u_prim_sparse_fsm_flop_if (.*); endmodule
diff --git a/hw/ip/prim/lint/prim_assert.waiver b/hw/ip/prim/lint/prim_assert.waiver index 8ae9e4a..f811952 100644 --- a/hw/ip/prim/lint/prim_assert.waiver +++ b/hw/ip/prim/lint/prim_assert.waiver
@@ -6,7 +6,10 @@ waive -rules {UNDEF_MACRO_REF} -location {prim_assert.sv} -regexp {Macro definition for 'ASSERT_RPT' includes expansion of undefined macro '__(FILE|LINE)__'} \ -comment "This is an UVM specific macro inside our assertion shortcuts" -# unfortunately most tools do not support line wrapping within the declaration of macro functions, hence we have to waive -# line length violations. + +# unfortunately most tools do not support line wrapping within the declaration of macro functions, +# hence we have to waive line length violations. waive -rules {LINE_LENGTH} -location {prim_assert.sv} -msg {Line length of} \ -comment "Some macros cannot be line-wrapped, as some tools do not support that." +waive -rules {LINE_LENGTH} -location {prim_flop_macros.sv} -msg {Line length of} \ + -comment "Some macros cannot be line-wrapped, as some tools do not support that."
diff --git a/hw/ip/prim/lint/prim_sparse_fsm_flop.vlt b/hw/ip/prim/lint/prim_sparse_fsm_flop.vlt index ca198d7..1ae4299 100644 --- a/hw/ip/prim/lint/prim_sparse_fsm_flop.vlt +++ b/hw/ip/prim/lint/prim_sparse_fsm_flop.vlt
@@ -6,3 +6,4 @@ // This parameter is only used in DV/FPV. lint_off -rule UNUSED -file "*/rtl/prim_sparse_fsm_flop.sv" -match "*EnableAlertTriggerSVA*" +lint_off -rule UNUSED -file "*/rtl/prim_sparse_fsm_flop.sv" -match "*CustomForceName*"
diff --git a/hw/ip/prim/prim_assert.core b/hw/ip/prim/prim_assert.core index 12cf78a..26e88e4 100644 --- a/hw/ip/prim/prim_assert.core +++ b/hw/ip/prim/prim_assert.core
@@ -13,6 +13,7 @@ - rtl/prim_assert_yosys_macros.svh : {is_include_file : true} - rtl/prim_assert_standard_macros.svh : {is_include_file : true} - rtl/prim_assert_sec_cm.svh : {is_include_file : true} + - rtl/prim_flop_macros.sv : {is_include_file : true} file_type: systemVerilogSource files_verilator_waiver:
diff --git a/hw/ip/prim/rtl/prim_assert.sv b/hw/ip/prim/rtl/prim_assert.sv index a5b17a8..2521042 100644 --- a/hw/ip/prim/rtl/prim_assert.sv +++ b/hw/ip/prim/rtl/prim_assert.sv
@@ -141,5 +141,6 @@ `endif `include "prim_assert_sec_cm.svh" +`include "prim_flop_macros.sv" `endif // PRIM_ASSERT_SV
diff --git a/hw/ip/prim/rtl/prim_flop_macros.sv b/hw/ip/prim/rtl/prim_flop_macros.sv new file mode 100644 index 0000000..edae459 --- /dev/null +++ b/hw/ip/prim/rtl/prim_flop_macros.sv
@@ -0,0 +1,74 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`ifndef PRIM_FLOP_MACROS_SV +`define PRIM_FLOP_MACROS_SV + +///////////////////////////////////// +// Default Values for Macros below // +///////////////////////////////////// + +`define PRIM_FLOP_CLK clk_i +`define PRIM_FLOP_RST rst_ni +`define PRIM_FLOP_RESVAL '0 + +///////////////////// +// Register Macros // +///////////////////// + +// TODO: define other variations of register macros so that they can be used throughout all designs +// to make the code more concise. + +// Register with asynchronous reset. +`define PRIM_FLOP_A(__d, __q, __resval = `PRIM_FLOP_RESVAL, __clk = `PRIM_FLOP_CLK, __rst_n = `PRIM_FLOP_RST) \ + always_ff @(posedge __clk or negedge __rst_n) begin \ + if (!__rst_n) begin \ + __q <= __resval; \ + end else begin \ + __q <= __d; \ + end \ + end + +/////////////////////////// +// Macro for Sparse FSMs // +/////////////////////////// + +// Simulation tools typically infer FSMs and report coverage for these separately. However, tools +// like Xcelium and VCS seem to have problems inferring FSMs if the state register is not coded in +// a behavioral always_ff block in the same hierarchy. To that end, this uses a modified variant +// with a second behavioral register definition for RTL simulations so that FSMs can be inferred. +// Note that in this variant, the __q output is disconnected from prim_sparse_fsm_flop and attached +// to the behavioral flop. An assertion is added to ensure equivalence between the +// prim_sparse_fsm_flop output and the behavioral flop output in that case. +`define PRIM_FLOP_SPARSE_FSM(__name, __d, __q, __type, __resval = `PRIM_FLOP_RESVAL, __clk = `PRIM_FLOP_CLK, __rst_n = `PRIM_FLOP_RST, __alert_trigger_sva_en = 1) \ + `ifdef SIMULATION \ + prim_sparse_fsm_flop #( \ + .StateEnumT(__type), \ + .Width($bits(__type)), \ + .ResetValue($bits(__type)'(__resval)), \ + .EnableAlertTriggerSVA(__alert_trigger_sva_en), \ + .CustomForceName(`PRIM_STRINGIFY(__q)) \ + ) __name ( \ + .clk_i ( __clk ), \ + .rst_ni ( __rst_n ), \ + .state_i ( __d ), \ + .state_o ( ) \ + ); \ + `PRIM_FLOP_A(__d, __q, __resval, __clk, __rst_n) \ + `ASSERT(``__name``_A, __q === ``__name``.state_o) \ + `else \ + prim_sparse_fsm_flop #( \ + .StateEnumT(__type), \ + .Width($bits(__type)), \ + .ResetValue($bits(__type)'(__resval)), \ + .EnableAlertTriggerSVA(__alert_trigger_sva_en) \ + ) __name ( \ + .clk_i ( __clk ), \ + .rst_ni ( __rst_n ), \ + .state_i ( __d ), \ + .state_o ( __q ) \ + ); \ + `endif + +`endif // PRIM_FLOP_MACROS_SV
diff --git a/hw/ip/prim/rtl/prim_sparse_fsm_flop.sv b/hw/ip/prim/rtl/prim_sparse_fsm_flop.sv index a327457..d55db6a 100644 --- a/hw/ip/prim/rtl/prim_sparse_fsm_flop.sv +++ b/hw/ip/prim/rtl/prim_sparse_fsm_flop.sv
@@ -5,21 +5,29 @@ `include "prim_assert.sv" module prim_sparse_fsm_flop #( - parameter type StateEnumT = logic, parameter int Width = 1, - parameter logic [Width-1:0] ResetValue = 0, + parameter type StateEnumT = logic [Width-1:0], + parameter logic [Width-1:0] ResetValue = '0, // This should only be disabled in special circumstances, for example // in non-comportable IPs where an error does not trigger an alert. parameter bit EnableAlertTriggerSVA = 1 +`ifdef SIMULATION + , + // In case this parameter is set to a non-empty string, the + // prim_sparse_fsm_flop_if will also force the signal with this name + // in the parent module that instantiates prim_sparse_fsm_flop. + parameter string CustomForceName = "" +`endif ) ( - input clk_i, - input rst_ni, - input [Width-1:0] state_i, - output logic [Width-1:0] state_o + input clk_i, + input rst_ni, + input StateEnumT state_i, + output StateEnumT state_o ); logic unused_err_o; + logic [Width-1:0] state_raw; prim_flop #( .Width(Width), .ResetValue(ResetValue) @@ -27,15 +35,16 @@ .clk_i, .rst_ni, .d_i(state_i), - .q_o(state_o) + .q_o(state_raw) ); + assign state_o = StateEnumT'(state_raw); `ifdef INC_ASSERT assign unused_err_o = is_undefined_state(state_o); - function automatic logic is_undefined_state(logic [Width-1:0] sig); + function automatic logic is_undefined_state(StateEnumT sig); for (int i = 0, StateEnumT t = t.first(); i < t.num(); i += 1, t = t.next()) begin - if (StateEnumT'(sig) === t) return 0; + if (sig === t) return 0; end return 1; endfunction