[fpv/csr_assert] add csr support for regwen Issue #3035 recorded compile errors when some module enabled FPV csr assert. The reason was because of the regwen registers. They could not be accessed through `reg2hw` or `hw2reg`. To solve this issue, this PR stored the regwen values locally. This PR also cleans up a few redundant code. fpv CSR assert also does not support backdoor write, so the csr assert will be disabled if backdoor write is enabled. Right now the only compile error remaining are: 1. alert_handler: the enable register "classa_clren" can be written by hw. Will need more support on FPV csr assert 2. flash_ctrl: the enable registers in flash_ctrl are not all W0C, reg `ctrl_regwen` is RO. Will need more support on FPV csr assert Signed-off-by: Cindy Chen <chencindy@google.com>
diff --git a/hw/dv/sv/dv_lib/dv_base_vseq.sv b/hw/dv/sv/dv_lib/dv_base_vseq.sv index e91c95f..e0eb185 100644 --- a/hw/dv/sv/dv_lib/dv_base_vseq.sv +++ b/hw/dv/sv/dv_lib/dv_base_vseq.sv
@@ -193,6 +193,7 @@ m_csr_write_seq.set_csr_excl_item(csr_excl); m_csr_write_seq.external_checker = cfg.en_scb; m_csr_write_seq.en_rand_backdoor_write = 1; + set_csr_assert_en(.enable(0)); // csr assert does not support backdoor write if (!enable_asserts_in_hw_reset_rand_wr) $assertoff; m_csr_write_seq.start(null); @@ -213,4 +214,9 @@ m_csr_seq.start(null); endtask + // enable/disable csr_assert + virtual function void set_csr_assert_en(bit enable, string path = "*"); + uvm_config_db#(bit)::set(null, path, "csr_assert_en", enable); + endfunction + endclass
diff --git a/hw/ip/alert_handler/dv/sva/alert_handler_bind.sv b/hw/ip/alert_handler/dv/sva/alert_handler_bind.sv index 985ed92..d126192 100644 --- a/hw/ip/alert_handler/dv/sva/alert_handler_bind.sv +++ b/hw/ip/alert_handler/dv/sva/alert_handler_bind.sv
@@ -13,14 +13,15 @@ .d2h (tl_o) ); + // TODO: current csr assert only support enable register sw access only // import alert_handler_reg_pkg::*; // bind alert_handler alert_handler_csr_assert_fpv alert_handler_csr_assert ( // .clk_i, // .rst_ni, // .h2d (tl_i), // .d2h (tl_o), - // .reg2hw (reg2hw), - // .hw2reg (hw2reg) + // .reg2hw (i_reg_wrap.reg2hw), + // .hw2reg (i_reg_wrap.hw2reg) // ); endmodule
diff --git a/hw/ip/flash_ctrl/dv/sva/flash_ctrl_bind.sv b/hw/ip/flash_ctrl/dv/sva/flash_ctrl_bind.sv index 0f59ecf..cc4f003 100644 --- a/hw/ip/flash_ctrl/dv/sva/flash_ctrl_bind.sv +++ b/hw/ip/flash_ctrl/dv/sva/flash_ctrl_bind.sv
@@ -13,6 +13,7 @@ .d2h (tl_o) ); + // TODO: flash_ctrl's enable registers are not all RW0C, need more support on CSR FPV assertion // import flash_ctrl_reg_pkg::*; // bind flash_ctrl flash_ctrl_csr_assert_fpv flash_ctrl_csr_assert ( // .clk_i,
diff --git a/hw/ip/keymgr/dv/sva/keymgr_bind.sv b/hw/ip/keymgr/dv/sva/keymgr_bind.sv index 0b067be..2cc08c7 100644 --- a/hw/ip/keymgr/dv/sva/keymgr_bind.sv +++ b/hw/ip/keymgr/dv/sva/keymgr_bind.sv
@@ -14,13 +14,13 @@ ); import keymgr_reg_pkg::*; - //bind keymgr keymgr_csr_assert_fpv keymgr_csr_assert ( - // .clk_i, - // .rst_ni, - // .h2d (tl_i), - // .d2h (tl_o), - // .reg2hw (reg2hw), - // .hw2reg (hw2reg) - //); + bind keymgr keymgr_csr_assert_fpv keymgr_csr_assert ( + .clk_i, + .rst_ni, + .h2d (tl_i), + .d2h (tl_o), + .reg2hw (reg2hw), + .hw2reg (hw2reg) + ); endmodule
diff --git a/hw/ip/spi_device/dv/sva/spi_device_bind.sv b/hw/ip/spi_device/dv/sva/spi_device_bind.sv index 5178d16..c8248a3 100644 --- a/hw/ip/spi_device/dv/sva/spi_device_bind.sv +++ b/hw/ip/spi_device/dv/sva/spi_device_bind.sv
@@ -13,14 +13,14 @@ .d2h (tl_o) ); - // import spi_device_reg_pkg::*; - // bind spi_device spi_device_csr_assert_fpv spi_device_csr_assert ( - // .clk_i, - // .rst_ni, - // .h2d (tl_i), - // .d2h (tl_o), - // .reg2hw (reg2hw), - // .hw2reg (hw2reg) - // ); + import spi_device_reg_pkg::*; + bind spi_device spi_device_csr_assert_fpv spi_device_csr_assert ( + .clk_i, + .rst_ni, + .h2d (tl_i), + .d2h (tl_o), + .reg2hw (reg2hw), + .hw2reg (hw2reg) + ); endmodule
diff --git a/hw/ip/usbdev/dv/sva/usbdev_bind.sv b/hw/ip/usbdev/dv/sva/usbdev_bind.sv index 14a27ee..9740b2e 100644 --- a/hw/ip/usbdev/dv/sva/usbdev_bind.sv +++ b/hw/ip/usbdev/dv/sva/usbdev_bind.sv
@@ -13,14 +13,14 @@ .d2h (tl_o) ); - // import usbdev_reg_pkg::*; - // bind usbdev usbdev_csr_assert_fpv usbdev_csr_assert ( - // .clk_i, - // .rst_ni, - // .h2d (tl_i), - // .d2h (tl_o), - // .reg2hw (reg2hw), - // .hw2reg (hw2reg) - // ); + import usbdev_reg_pkg::*; + bind usbdev usbdev_csr_assert_fpv usbdev_csr_assert ( + .clk_i, + .rst_ni, + .h2d (tl_i), + .d2h (tl_o), + .reg2hw (reg2hw), + .hw2reg (hw2reg) + ); endmodule
diff --git a/hw/ip/usbdev/dv/sva/usbdev_sva.core b/hw/ip/usbdev/dv/sva/usbdev_sva.core index 7609d89..63d5a55 100644 --- a/hw/ip/usbdev/dv/sva/usbdev_sva.core +++ b/hw/ip/usbdev/dv/sva/usbdev_sva.core
@@ -24,5 +24,5 @@ default: filesets: - files_dv - # generate: - # - csr_assert_gen + generate: + - csr_assert_gen
diff --git a/util/reggen/fpv_csr.sv.tpl b/util/reggen/fpv_csr.sv.tpl index c7aac49..4b525ae 100644 --- a/util/reggen/fpv_csr.sv.tpl +++ b/util/reggen/fpv_csr.sv.tpl
@@ -4,8 +4,9 @@ // FPV CSR read and write assertions auto-generated by `reggen` containing data structure // Do Not Edit directly -// TODO: This automation does not support: shadow reg and regwen reg -// This automation assumes that W1C and W0C are registers with 1 bit per field +// TODO: This automation does not support: shadow reg, has_d has_de not has_q (right now does not +// have internal storage if de=0) +// This automation assumes that enable registers are 1 bit with RW0C or RW1C access policy <% from reggen import (gen_fpv) %>\ <% from topgen import lib @@ -18,7 +19,8 @@ `include "prim_assert.sv" // Block: ${block.name} -module ${block.name}_csr_assert_fpv import tlul_pkg::*; import ${block.name}_reg_pkg::*; ( +module ${block.name}_csr_assert_fpv import tlul_pkg::*; import ${block.name}_reg_pkg::*; + import top_pkg::*;( input clk_i, input rst_ni, @@ -31,9 +33,17 @@ input ${block.name}_hw2reg_t hw2reg ); - parameter int DWidth = 32; +`ifndef VERILATOR +`ifndef SYNTHESIS + +`ifdef UVM + import uvm_pkg::*; +`endif + + bit disable_sva; + // mask register to convert byte to bit - logic [DWidth-1:0] a_mask_bit; + logic [TL_DW-1:0] a_mask_bit; assign a_mask_bit[7:0] = h2d.a_mask[0] ? '1 : '0; assign a_mask_bit[15:8] = h2d.a_mask[1] ? '1 : '0; @@ -41,22 +51,85 @@ assign a_mask_bit[31:24] = h2d.a_mask[3] ? '1 : '0; <% - addr_msb = block.addr_width - 1 - mask = block.addr_width + addr_msb = block.addr_width - 1 + reg_width = block.addr_width + regen_names = list() + regen_addrs = list() + regen_swaccess = list() %>\ - // normalized address only take the [${addr_msb}:2] address from the TLUL a_address - bit [${addr_msb} : 0] normalized_addr; - assign normalized_addr = h2d.a_address >> 2; + bit [${addr_msb}:0] normalized_addr; + assign normalized_addr = {h2d.a_address[${addr_msb}:2], 2'b0}; + +% for r in block.get_regs_flat(): + % if r.regwen and r.regwen not in regen_names: +<% regen_names.append(r.regwen) %>\ + % endif +% endfor +% for r in block.get_regs_flat(): + % if r.name in regen_names: +<% + reg_offset = str(reg_width) + "'h" + "%x" % r.offset + regen_addrs.append(reg_offset) + regen_swaccess.append(r.get_field_flat(0).swaccess.name) +%>\ + % endif +% endfor + // declare variables to hold enable registers values + typedef struct packed { + logic [TL_DW-1:0] data; + logic [TL_AW-1:0] addr; + logic [TL_SZW-1:0] size; + logic [TL_DW-1:0] mask; + } tlul_req_t; + + // max there are 2*TL_AIW num of reqs source IDs + tlul_req_t [2**TL_AIW-1:0] tlul_req; +% for regen_name in regen_names: + logic ${regen_name}; +% endfor + // use negedge clk to avoid possible race conditions + always_ff @(negedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + tlul_req <= '0; +% for regen_name in regen_names: + ${regen_name} <= 1'b1; +% endfor + end else begin + if (h2d.a_valid && h2d.a_opcode inside {PutFullData, PutPartialData}) begin + // store each request in tlul_req array (we use blocking statements below so + // that we can handle the case where request and response for the same + // source-ID happen in the same cycle) + if (d2h.a_ready) begin + tlul_req[h2d.a_source].mask <= a_mask_bit; + tlul_req[h2d.a_source].data <= h2d.a_data; + tlul_req[h2d.a_source].addr <= normalized_addr; + end + end // h2d.a_valid + + if (d2h.d_valid) begin + // update tlul_req array + if (h2d.d_ready) begin +% for regen_name in regen_names: + ${"if" if loop.first else "end else if"} (tlul_req[d2h.d_source].addr == ${regen_addrs[loop.index]} && tlul_req[d2h.d_source].mask[0] && ${regen_name}) begin + ${regen_name} <= ${"!" if regen_swaccess[loop.index] == "W1C" else ""}tlul_req[d2h.d_source].data[0]; + % if loop.last: + end + % endif +% endfor + end + end //d2h.d_valid + end + end // declare common read and write sequences sequence device_wr_S(logic [${addr_msb}:0] addr); - normalized_addr == (addr >> 2) && h2d.a_opcode inside {PutFullData, PutPartialData} && + normalized_addr == addr && h2d.a_opcode inside {PutFullData, PutPartialData} && h2d.a_valid && h2d.d_ready && !d2h.d_valid; endsequence sequence device_rd_S(logic [${addr_msb}:0] addr); - normalized_addr == (addr >> 2) && h2d.a_opcode inside {Get} && h2d.a_valid && h2d.d_ready && + normalized_addr == addr && h2d.a_opcode inside {Get} && h2d.a_valid && h2d.d_ready && !d2h.d_valid; endsequence @@ -67,18 +140,18 @@ // to store all the multi-reg within one basefield, we need to shift the `_fpv` value to the // correct bits, then compare with read/write exp_data. - property wr_P(bit [${addr_msb}:0] addr, bit [DWidth-1:0] act_data, bit regen, - bit [DWidth-1:0] mask, int lsb); - logic [DWidth-1:0] id, exp_data; + property wr_P(bit [${addr_msb}:0] addr, bit [TL_DW-1:0] act_data, bit regen, + bit [TL_DW-1:0] mask, int lsb); + logic [TL_DW-1:0] id, exp_data; (device_wr_S(addr), id = h2d.a_source, exp_data = h2d.a_data & a_mask_bit & mask) ##1 first_match(##[0:$] d2h.d_valid && d2h.d_source == id) |-> (d2h.d_error || (act_data << lsb) == exp_data || !regen); endproperty // external reg will use one clk cycle to update act_data from external - property wr_ext_P(bit [${addr_msb}:0] addr, bit [DWidth-1:0] act_data, bit regen, - bit [DWidth-1:0] mask, int lsb); - logic [DWidth-1:0] id, exp_data; + property wr_ext_P(bit [${addr_msb}:0] addr, bit [TL_DW-1:0] act_data, bit regen, + bit [TL_DW-1:0] mask, int lsb); + logic [TL_DW-1:0] id, exp_data; (device_wr_S(addr), id = h2d.a_source, exp_data = h2d.a_data & a_mask_bit & mask) ##1 first_match(##[0:$] (d2h.d_valid && d2h.d_source == id)) |-> (d2h.d_error || ($past(act_data) << lsb) == exp_data || !regen); @@ -86,60 +159,58 @@ // W1C register, if write 1 external data will be cleared to 0; // if write 0, internal data won't change - property w1c_P(bit [${addr_msb}:0] addr, bit [DWidth-1:0] act_data, bit regen, - bit [DWidth-1:0] mask, int lsb); - logic [DWidth-1:0] id, exp_data; + property w1c_P(bit [${addr_msb}:0] addr, bit [TL_DW-1:0] act_data, bit regen, + bit [TL_DW-1:0] mask, int lsb); + logic [TL_DW-1:0] id, exp_data; (device_wr_S(addr), id = h2d.a_source, exp_data = h2d.a_data & a_mask_bit & mask) ##1 first_match(##[0:$] d2h.d_valid && d2h.d_source == id) |-> (d2h.d_error || ((act_data << lsb) & exp_data) == 0 || !regen); endproperty - property w1c_ext_P(bit [${addr_msb}:0] addr, bit [DWidth-1:0] act_data, bit regen, - bit [DWidth-1:0] mask, int lsb); - logic [DWidth-1:0] id, exp_data; + property w1c_ext_P(bit [${addr_msb}:0] addr, bit [TL_DW-1:0] act_data, bit regen, + bit [TL_DW-1:0] mask, int lsb); + logic [TL_DW-1:0] id, exp_data; (device_wr_S(addr), id = h2d.a_source, exp_data = h2d.a_data & a_mask_bit & mask) ##1 first_match(##[0:$] (d2h.d_valid && d2h.d_source == id)) |-> (d2h.d_error || ($past(act_data) << lsb) == exp_data || !regen); endproperty - property rd_P(bit [${addr_msb}:0] addr, bit [DWidth-1:0] act_data, bit [DWidth-1:0] mask, int lsb); - logic [DWidth-1:0] id, exp_data; + property rd_P(bit [${addr_msb}:0] addr, bit [TL_DW-1:0] act_data, bit [TL_DW-1:0] mask, int lsb); + logic [TL_DW-1:0] id, exp_data; (device_rd_S(addr), id = h2d.a_source, exp_data = $past(act_data)) ##1 first_match(##[0:$] (d2h.d_valid && d2h.d_source == id)) |-> (d2h.d_error || (d2h.d_data & mask) >> lsb == exp_data); endproperty - property rd_ext_P(bit [${addr_msb}:0] addr, bit [DWidth-1:0] act_data, bit [DWidth-1:0] mask, + property rd_ext_P(bit [${addr_msb}:0] addr, bit [TL_DW-1:0] act_data, bit [TL_DW-1:0] mask, int lsb); - logic [DWidth-1:0] id, exp_data; + logic [TL_DW-1:0] id, exp_data; (device_rd_S(addr), id = h2d.a_source, exp_data = act_data) ##1 first_match(##[0:$] (d2h.d_valid && d2h.d_source == id)) |-> (d2h.d_error || (d2h.d_data & mask) >> lsb == exp_data); endproperty - // TODO: currently not used, will use once support regwen reg - property wr_regen_stable_P(bit regen, bit [DWidth-1:0] exp_data); - (!regen && $stable(regen)) |-> $stable(exp_data); - endproperty - % for r in block.regs: <% - has_q = r.get_n_bits(["q"]) > 0 - has_d = r.get_n_bits(["d"]) > 0 + has_q = r.get_n_bits(["q"]) > 0 + has_d = r.get_n_bits(["d"]) > 0 has_de = r.get_n_bits(["de"]) > 0 %>\ % if not r.get_field_flat(0).shadowed: % if r.is_multi_reg(): <% - mreg_name = r.name - mreg_width_list = list() + mreg_name = r.name + mreg_width_list = list() mreg_fpv_name_list = list() mreg_dut_path_list = list() - mreg_num_regs = r.get_n_fields_flat() + mreg_has_q_list = list() + mreg_has_d_list = list() + mreg_has_de_list = list() + mreg_num_regs = r.get_n_fields_flat() mreg_msb = -1 mreg_lsb = 0 - i = 0 + i = 0 %>\ % if not r.ishomog: % for field in r.get_reg_flat(0).fields: @@ -147,11 +218,14 @@ mreg_fpv_name_list.append(mreg_name + "_" + field.get_basename()) mreg_dut_path_list.append(mreg_name + "[s]." + field.get_basename()) mreg_width_list.append(field.msb - field.lsb + 1) + mreg_has_q_list.append(field.get_n_bits(["q"]) > 0) + mreg_has_d_list.append(field.get_n_bits(["d"]) > 0) + mreg_has_de_list.append(field.get_n_bits(["de"]) > 0) %>\ % endfor <% mreg_num_base_fields = len(mreg_fpv_name_list) - mreg_num_regs = mreg_num_regs / mreg_num_base_fields + mreg_num_regs = mreg_num_regs / mreg_num_base_fields %>\ % else: <% @@ -160,17 +234,20 @@ mreg_fpv_name_list.append(mreg_name) mreg_dut_path_list.append(mreg_name + "[s]") mreg_width_list.append(f.msb - f.lsb + 1) + mreg_has_q_list.append(has_q) + mreg_has_d_list.append(has_d) + mreg_has_de_list.append(has_de) %>\ % endif // define local fpv variable for multi-reg % if r.get_n_bits(["q", "d"]): % for fpv_name in mreg_fpv_name_list: -${declare_fpv_var(fpv_name, int(mreg_width_list[loop.index] * mreg_num_regs - 1))}\ +${declare_fpv_var(fpv_name, int(mreg_width_list[loop.index] * mreg_num_regs - 1), loop.index)}\ % endfor for (genvar s = 0; s < ${int(mreg_num_regs)}; s++) begin : gen_${mreg_name}_q % for fpv_name in mreg_fpv_name_list: -${assign_fpv_var(fpv_name, mreg_dut_path_list[loop.index], int(mreg_width_list[loop.index]))}\ +${assign_fpv_var(fpv_name, mreg_dut_path_list[loop.index], int(mreg_width_list[loop.index]), loop.index)}\ % endfor end % endif @@ -178,35 +255,37 @@ % for reg_flat in r.get_regs_flat(): <% - reg_name = reg_flat.name - reg_width = block.addr_width - reg_offset = str(reg_width) + "'h" + "%x" % reg_flat.offset - reg_msb = reg_flat.width - 1 - regwen = reg_flat.regwen + reg_name = reg_flat.name + reg_offset = str(reg_width) + "'h" + "%x" % reg_flat.offset + reg_msb = reg_flat.width - 1 + regwen = reg_flat.regwen reg_wr_mask = 0 %>\ // assertions for register: ${reg_name} % if regwen: -<% reg_wen = "u_reg." + regwen + "_qs" %>\ +<% reg_wen = regwen %>\ % else: <% reg_wen = "1" %>\ % endif % for f in reg_flat.get_fields_flat(): <% - field_name = f.name - assert_path = reg_name + "." + field_name - assert_name = reg_name + "_" + field_name - field_access = f.swaccess.name - field_wr_mask = ((1 << (f.msb-f.lsb + 1)) -1) << f.lsb + field_name = f.name + assert_path = reg_name + "." + field_name + assert_name = reg_name + "_" + field_name + field_access = f.swaccess.name + field_wr_mask = ((1 << (f.msb-f.lsb + 1)) -1) << f.lsb field_wr_mask_h = format(field_wr_mask, 'x') - reg_wr_mask |= field_wr_mask - reg_wr_mask_h = format(reg_wr_mask, 'x') - lsb = f.lsb - sw_rdaccess = f.swrdaccess.name + reg_wr_mask |= field_wr_mask + reg_wr_mask_h = format(reg_wr_mask, 'x') + lsb = f.lsb + sw_rdaccess = f.swrdaccess.name + had_q = f.get_n_bits(["q"]) > 0 + has_d = f.get_n_bits(["d"]) > 0 + has_de = f.get_n_bits(["de"]) > 0 %>\ % if not r.ishomog: - // this is a non-homog multi-reg % if r.is_multi_reg(): + // this is a non-homog multi-reg <% mreg_lsb = i * mreg_width_list[loop.index] mreg_msb = mreg_lsb + mreg_width_list[loop.index] - 1 @@ -235,6 +314,17 @@ % endif % endfor + `ifdef UVM + initial forever begin + bit csr_assert_en; + uvm_config_db#(bit)::wait_modified(null, "%m", "csr_assert_en"); + if (!uvm_config_db#(bit)::get(null, "%m", "csr_assert_en", csr_assert_en)) begin + `uvm_fatal("csr_assert", "Can't find csr_assert_en") + end + disable_sva = !csr_assert_en; + end + `endif + <%def name="gen_asserts_by_category(assert_name, assert_path, is_ext, wr_mask)">\ % if has_q: <% reg_w_path = "reg2hw." + assert_path + ".q" %>\ @@ -246,10 +336,11 @@ % if has_d: % if has_de and has_q: <% reg_r_path = "hw2reg." + assert_path + ".de ? hw2reg." + assert_path + ".d :reg2hw." + assert_path + ".q" %>\ - % else: -<% reg_r_path = "hw2reg." + assert_path + ".d" %>\ - % endif ${gen_rd_asserts(assert_name, is_ext, reg_r_path, wr_mask)}\ + % elif not has_de: +<% reg_r_path = "hw2reg." + assert_path + ".d" %>\ +${gen_rd_asserts(assert_name, is_ext, reg_r_path, wr_mask)}\ + % endif % endif </%def>\ <%def name="gen_multi_reg_asserts_by_category(assert_name, multi_reg_name, mreg_msb, mreg_lsb, is_ext, wr_mask)">\ @@ -261,8 +352,10 @@ % endif % endif % if has_d: -<% reg_r_path = mreg_name + "_d_fpv[" + str(mreg_msb) + ":" + str(mreg_lsb) + "]"%>\ + % if not has_de: +<% reg_r_path = multi_reg_name + "_d_fpv[" + str(mreg_msb) + ":" + str(mreg_lsb) + "]"%>\ ${gen_rd_asserts(assert_name, is_ext, reg_r_path, wr_mask)}\ + % endif % endif </%def>\ <%def name="gen_wr_asserts(name, is_ext, reg_w_path, wr_mask)">\ @@ -277,9 +370,9 @@ <% shift_index = 0 %>\ % endif % if field_access == "W1C": - `ASSERT(${name}_w1c_A, w1c_${wr_property}(${reg_offset}, ${reg_w_path}, ${reg_wen}, 'h${wr_mask}, ${shift_index})) + `ASSERT(${name}_w1c_A, w1c_${wr_property}(${reg_offset}, ${reg_w_path}, ${reg_wen}, 'h${wr_mask}, ${shift_index}), clk_i, !rst_ni || disable_sva) % elif field_access in {"RW", "WO", "W0C"}: - `ASSERT(${name}_wr_A, wr_${wr_property}(${reg_offset}, ${reg_w_path}, ${reg_wen}, 'h${wr_mask}, ${shift_index})) + `ASSERT(${name}_wr_A, wr_${wr_property}(${reg_offset}, ${reg_w_path}, ${reg_wen}, 'h${wr_mask}, ${shift_index}), clk_i, !rst_ni || disable_sva) % endif </%def>\ <%def name="gen_rd_asserts(name, is_ext, reg_r_path, mask)">\ @@ -294,27 +387,29 @@ <% shift_index = 0 %>\ % endif % if sw_rdaccess == "NONE" and field_access == "W1C": - `ASSERT(${name}_rd_A, ${rd_property}(${reg_offset}, 0, 'h${mask}, ${shift_index})) + `ASSERT(${name}_rd_A, ${rd_property}(${reg_offset}, 0, 'h${mask}, ${shift_index}), clk_i, !rst_ni || disable_sva) % elif field_access in {"RW", "W0C", "W1C"}: - `ASSERT(${name}_rd_A, ${rd_property}(${reg_offset}, ${reg_r_path}, 'h${mask}, ${shift_index})) + `ASSERT(${name}_rd_A, ${rd_property}(${reg_offset}, ${reg_r_path}, 'h${mask}, ${shift_index}), clk_i, !rst_ni || disable_sva) % endif </%def>\ -<%def name="declare_fpv_var(name, width)">\ - % if has_q: +<%def name="declare_fpv_var(name, width, l_index)">\ + % if mreg_has_q_list[l_index]: logic [${width}:0] ${name}_q_fpv; % endif - % if has_d: + % if mreg_has_d_list[l_index]: logic [${width}:0] ${name}_d_fpv; % endif </%def>\ -<%def name="assign_fpv_var(fpv_name, dut_path, width)">\ - % if has_q: +<%def name="assign_fpv_var(fpv_name, dut_path, width, l_index)">\ + % if mreg_has_q_list[l_index]: assign ${fpv_name}_q_fpv[((s+1)*${width}-1):s*${width}] = reg2hw.${dut_path}.q; % endif - % if has_d: + % if mreg_has_d_list[l_index]: assign ${fpv_name}_d_fpv[((s+1)*${width}-1):s*${width}] = hw2reg.${dut_path}.d; % endif </%def>\ </%def>\ ${construct_classes(block)} +`endif +`endif endmodule