[fpv] generate csr_assert on the fly

This PR uses PR #2941 method to generate csr assertions on the fly for
FPV testbenches.
This change includes: rv_plic, pinmux, padctrl, rv_plic top_level

Signed-off-by: Cindy Chen <chencindy@google.com>
diff --git a/hw/ip/padctrl/fpv/padctrl_fpv.core b/hw/ip/padctrl/fpv/padctrl_fpv.core
index f3c9889..07e33dd 100644
--- a/hw/ip/padctrl/fpv/padctrl_fpv.core
+++ b/hw/ip/padctrl/fpv/padctrl_fpv.core
@@ -12,14 +12,21 @@
       # from a particular top-level config
       - lowrisc:ip:padctrl
       - lowrisc:prim:prim_pkg
+      - lowrisc:fpv:csr_assert_gen
     files:
       - tb/padctrl_fpv.sv
       - tb/padctrl_bind_fpv.sv
       - vip/padctrl_assert_fpv.sv
       - vip/padring_assert_fpv.sv
-      - vip/padctrl_csr_assert_fpv.sv
     file_type: systemVerilogSource
 
+generate:
+  csr_assert_gen:
+    generator: csr_assert_gen
+    parameters:
+      spec: ../data/padctrl.hjson
+      depend: lowrisc:ip:padctrl_reg
+
 targets:
   default: &default_target
     # note, this setting is just used
@@ -27,7 +34,9 @@
     default_tool: icarus
     filesets:
       - files_formal
-    toplevel: padctrl_formal
+    generate:
+      - csr_assert_gen
+    toplevel: padctrl_fpv
 
   formal:
     <<: *default_target
diff --git a/hw/ip/padctrl/fpv/vip/padctrl_csr_assert_fpv.sv b/hw/ip/padctrl/fpv/vip/padctrl_csr_assert_fpv.sv
deleted file mode 100644
index cdf1901..0000000
--- a/hw/ip/padctrl/fpv/vip/padctrl_csr_assert_fpv.sv
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-
-// 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
-
-`include "prim_assert.sv"
-
-// Block: padctrl
-module padctrl_csr_assert_fpv import tlul_pkg::*; import padctrl_reg_pkg::*; (
-  input clk_i,
-  input rst_ni,
-
-  // tile link ports
-  input tl_h2d_t h2d,
-  input tl_d2h_t d2h,
-
-  // reg and hw ports
-  input padctrl_reg2hw_t reg2hw,
-  input padctrl_hw2reg_t hw2reg
-);
-
-  parameter int DWidth = 32;
-  // mask register to convert byte to bit
-  logic [DWidth-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;
-  assign a_mask_bit[23:16] = h2d.a_mask[2] ? '1 : '0;
-  assign a_mask_bit[31:24] = h2d.a_mask[3] ? '1 : '0;
-
-  // declare common read and write sequences
-  sequence device_wr_S(logic [5:0] addr);
-    h2d.a_address == addr && h2d.a_opcode inside {PutFullData, PutPartialData} &&
-        h2d.a_valid && h2d.d_ready && !d2h.d_valid;
-  endsequence
-
-  sequence device_rd_S(logic [5:0] addr);
-    h2d.a_address == addr && h2d.a_opcode inside {Get} && h2d.a_valid && h2d.d_ready &&
-        !d2h.d_valid;
-  endsequence
-
-  // declare common read and write properties
-  // for homog registers, we check by a reg; for non-homog regs, we check by field.
-  // `mask` is used for checking by field. It masks out any act_data that are not within the field
-  // `lsb` is used to check non-homog multi_reg. Because we are using a local copy `_fpv` variable
-  // 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 [5:0] addr, bit [DWidth-1:0] act_data, bit regen,
-                bit [DWidth-1:0] mask, int lsb);
-    logic [DWidth-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 [5:0] addr, bit [DWidth-1:0] act_data, bit regen,
-                    bit [DWidth-1:0] mask, int lsb);
-    logic [DWidth-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 w1c_P(bit [5:0] addr, bit [DWidth-1:0] act_data, bit regen,
-                bit [DWidth-1:0] mask, int lsb);
-    logic [DWidth-1:0] id, exp_data;
-    (device_wr_S(addr), id = h2d.a_source, exp_data = h2d.a_data & a_mask_bit & mask & '0) ##1
-        first_match(##[0:$] d2h.d_valid && d2h.d_source == id) |->
-        (d2h.d_error || (act_data << lsb) == exp_data || !regen);
-  endproperty
-
-  property w1c_ext_P(bit [5:0] addr, bit [DWidth-1:0] act_data, bit regen,
-                    bit [DWidth-1:0] mask, int lsb);
-    logic [DWidth-1:0] id, exp_data;
-    (device_wr_S(addr), id = h2d.a_source, exp_data = h2d.a_data & a_mask_bit & mask & '0) ##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 [5:0] addr, bit [DWidth-1:0] act_data, bit [DWidth-1:0] mask, int lsb);
-    logic [DWidth-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 [5:0] addr, bit [DWidth-1:0] act_data, bit [DWidth-1:0] mask,
-      int lsb);
-    logic [DWidth-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
-
-  // read a WO register, always return 0
-  property r_wo_P(bit [5:0] addr);
-    logic [DWidth-1:0] id;
-    (device_rd_S(addr), id = h2d.a_source) ##1
-        first_match(##[0:$] (d2h.d_valid && d2h.d_source == id)) |->
-        (d2h.d_error || d2h.d_data == 0);
-  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
-
-
-  // assertions for register: regen
-
-  // define local fpv variable for multi-reg
-  logic [39:0] dio_pads_q_fpv;
-  logic [39:0] dio_pads_d_fpv;
-  for (genvar s = 0; s < 4; s++) begin : gen_dio_pads_q
-    assign dio_pads_q_fpv[((s+1)*10-1):s*10] = reg2hw.dio_pads[s].q;
-    assign dio_pads_d_fpv[((s+1)*10-1):s*10] = hw2reg.dio_pads[s].d;
-  end
-
-  // assertions for register: dio_pads0
-  `ASSERT(dio_pads0_wr_A, wr_ext_P(6'h4, dio_pads_q_fpv[29:0], dut.u_reg.regen_qs, 'h3fffffff, 0))
-  `ASSERT(dio_pads0_rd_A, rd_ext_P(6'h4, dio_pads_d_fpv[29:0], 'h3fffffff, 0))
-  // assertions for register: dio_pads1
-  `ASSERT(dio_pads1_wr_A, wr_ext_P(6'h8, dio_pads_q_fpv[39:30], dut.u_reg.regen_qs, 'h3ff, 0))
-  `ASSERT(dio_pads1_rd_A, rd_ext_P(6'h8, dio_pads_d_fpv[39:30], 'h3ff, 0))
-
-  // define local fpv variable for multi-reg
-  logic [159:0] mio_pads_q_fpv;
-  logic [159:0] mio_pads_d_fpv;
-  for (genvar s = 0; s < 16; s++) begin : gen_mio_pads_q
-    assign mio_pads_q_fpv[((s+1)*10-1):s*10] = reg2hw.mio_pads[s].q;
-    assign mio_pads_d_fpv[((s+1)*10-1):s*10] = hw2reg.mio_pads[s].d;
-  end
-
-  // assertions for register: mio_pads0
-  `ASSERT(mio_pads0_wr_A, wr_ext_P(6'hc, mio_pads_q_fpv[29:0], dut.u_reg.regen_qs, 'h3fffffff, 0))
-  `ASSERT(mio_pads0_rd_A, rd_ext_P(6'hc, mio_pads_d_fpv[29:0], 'h3fffffff, 0))
-  // assertions for register: mio_pads1
-  `ASSERT(mio_pads1_wr_A, wr_ext_P(6'h10, mio_pads_q_fpv[59:30], dut.u_reg.regen_qs, 'h3fffffff, 0))
-  `ASSERT(mio_pads1_rd_A, rd_ext_P(6'h10, mio_pads_d_fpv[59:30], 'h3fffffff, 0))
-  // assertions for register: mio_pads2
-  `ASSERT(mio_pads2_wr_A, wr_ext_P(6'h14, mio_pads_q_fpv[89:60], dut.u_reg.regen_qs, 'h3fffffff, 0))
-  `ASSERT(mio_pads2_rd_A, rd_ext_P(6'h14, mio_pads_d_fpv[89:60], 'h3fffffff, 0))
-  // assertions for register: mio_pads3
-  `ASSERT(mio_pads3_wr_A, wr_ext_P(6'h18, mio_pads_q_fpv[119:90], dut.u_reg.regen_qs, 'h3fffffff, 0))
-  `ASSERT(mio_pads3_rd_A, rd_ext_P(6'h18, mio_pads_d_fpv[119:90], 'h3fffffff, 0))
-  // assertions for register: mio_pads4
-  `ASSERT(mio_pads4_wr_A, wr_ext_P(6'h1c, mio_pads_q_fpv[149:120], dut.u_reg.regen_qs, 'h3fffffff, 0))
-  `ASSERT(mio_pads4_rd_A, rd_ext_P(6'h1c, mio_pads_d_fpv[149:120], 'h3fffffff, 0))
-  // assertions for register: mio_pads5
-  `ASSERT(mio_pads5_wr_A, wr_ext_P(6'h20, mio_pads_q_fpv[159:150], dut.u_reg.regen_qs, 'h3ff, 0))
-  `ASSERT(mio_pads5_rd_A, rd_ext_P(6'h20, mio_pads_d_fpv[159:150], 'h3ff, 0))
-
-
-endmodule
diff --git a/hw/ip/pinmux/fpv/pinmux_fpv.core b/hw/ip/pinmux/fpv/pinmux_fpv.core
index e31ecd9..dc7f03c 100644
--- a/hw/ip/pinmux/fpv/pinmux_fpv.core
+++ b/hw/ip/pinmux/fpv/pinmux_fpv.core
@@ -5,23 +5,32 @@
 name: "lowrisc:fpv:pinmux_fpv:0.1"
 description: "pinmux FPV target"
 filesets:
-  files_fpv:
+  files_formal:
     depend:
       - lowrisc:prim:all
       - lowrisc:ip:tlul
       - lowrisc:ip:pinmux
+      - lowrisc:fpv:csr_assert_gen
     files:
       - vip/pinmux_assert_fpv.sv
       - tb/pinmux_bind_fpv.sv
       - tb/pinmux_fpv.sv
-      - vip/pinmux_csr_assert_fpv.sv
     file_type: systemVerilogSource
 
+generate:
+  csr_assert_gen:
+    generator: csr_assert_gen
+    parameters:
+      spec: ../data/pinmux.hjson
+      depend: lowrisc:ip:pinmux_reg
+
 targets:
   default: &default_target
     default_tool: icarus
     filesets:
-      - files_fpv
+      - files_formal
+    generate:
+      - csr_assert_gen
     toplevel: pinmux_fpv
 
   formal:
diff --git a/hw/ip/pinmux/fpv/vip/pinmux_csr_assert_fpv.sv b/hw/ip/pinmux/fpv/vip/pinmux_csr_assert_fpv.sv
deleted file mode 100644
index 0130006..0000000
--- a/hw/ip/pinmux/fpv/vip/pinmux_csr_assert_fpv.sv
+++ /dev/null
@@ -1,338 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-
-// 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
-
-`include "prim_assert.sv"
-
-// Block: pinmux
-module pinmux_csr_assert_fpv import tlul_pkg::*; import pinmux_reg_pkg::*; (
-  input clk_i,
-  input rst_ni,
-
-  // tile link ports
-  input tl_h2d_t h2d,
-  input tl_d2h_t d2h,
-
-  // reg and hw ports
-  input pinmux_reg2hw_t reg2hw,
-  input pinmux_hw2reg_t hw2reg
-);
-
-  parameter int DWidth = 32;
-  // mask register to convert byte to bit
-  logic [DWidth-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;
-  assign a_mask_bit[23:16] = h2d.a_mask[2] ? '1 : '0;
-  assign a_mask_bit[31:24] = h2d.a_mask[3] ? '1 : '0;
-
-  // declare common read and write sequences
-  sequence device_wr_S(logic [6:0] addr);
-    h2d.a_address == addr && h2d.a_opcode inside {PutFullData, PutPartialData} &&
-        h2d.a_valid && h2d.d_ready && !d2h.d_valid;
-  endsequence
-
-  sequence device_rd_S(logic [6:0] addr);
-    h2d.a_address == addr && h2d.a_opcode inside {Get} && h2d.a_valid && h2d.d_ready &&
-        !d2h.d_valid;
-  endsequence
-
-  // declare common read and write properties
-  // for homog registers, we check by a reg; for non-homog regs, we check by field.
-  // `mask` is used for checking by field. It masks out any act_data that are not within the field
-  // `lsb` is used to check non-homog multi_reg. Because we are using a local copy `_fpv` variable
-  // 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 [6:0] addr, bit [DWidth-1:0] act_data, bit regen,
-                bit [DWidth-1:0] mask, int lsb);
-    logic [DWidth-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 [6:0] addr, bit [DWidth-1:0] act_data, bit regen,
-                    bit [DWidth-1:0] mask, int lsb);
-    logic [DWidth-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 w1c_P(bit [6:0] addr, bit [DWidth-1:0] act_data, bit regen,
-                bit [DWidth-1:0] mask, int lsb);
-    logic [DWidth-1:0] id, exp_data;
-    (device_wr_S(addr), id = h2d.a_source, exp_data = h2d.a_data & a_mask_bit & mask & '0) ##1
-        first_match(##[0:$] d2h.d_valid && d2h.d_source == id) |->
-        (d2h.d_error || (act_data << lsb) == exp_data || !regen);
-  endproperty
-
-  property w1c_ext_P(bit [6:0] addr, bit [DWidth-1:0] act_data, bit regen,
-                    bit [DWidth-1:0] mask, int lsb);
-    logic [DWidth-1:0] id, exp_data;
-    (device_wr_S(addr), id = h2d.a_source, exp_data = h2d.a_data & a_mask_bit & mask & '0) ##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 [6:0] addr, bit [DWidth-1:0] act_data, bit [DWidth-1:0] mask, int lsb);
-    logic [DWidth-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 [6:0] addr, bit [DWidth-1:0] act_data, bit [DWidth-1:0] mask,
-      int lsb);
-    logic [DWidth-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
-
-  // read a WO register, always return 0
-  property r_wo_P(bit [6:0] addr);
-    logic [DWidth-1:0] id;
-    (device_rd_S(addr), id = h2d.a_source) ##1
-        first_match(##[0:$] (d2h.d_valid && d2h.d_source == id)) |->
-        (d2h.d_error || d2h.d_data == 0);
-  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
-
-
-  // assertions for register: regen
-
-  // define local fpv variable for multi-reg
-  logic [191:0] periph_insel_q_fpv;
-  for (genvar s = 0; s < 32; s++) begin : gen_periph_insel_q
-    assign periph_insel_q_fpv[((s+1)*6-1):s*6] = reg2hw.periph_insel[s].q;
-  end
-
-  // assertions for register: periph_insel0
-  `ASSERT(periph_insel0_wr_A, wr_P(7'h4, periph_insel_q_fpv[29:0], dut.u_reg.regen_qs, 'h3fffffff, 0))
-  `ASSERT(periph_insel0_rd_A, rd_P(7'h4, periph_insel_q_fpv[29:0], 'h3fffffff, 0))
-  // assertions for register: periph_insel1
-  `ASSERT(periph_insel1_wr_A, wr_P(7'h8, periph_insel_q_fpv[59:30], dut.u_reg.regen_qs, 'h3fffffff, 0))
-  `ASSERT(periph_insel1_rd_A, rd_P(7'h8, periph_insel_q_fpv[59:30], 'h3fffffff, 0))
-  // assertions for register: periph_insel2
-  `ASSERT(periph_insel2_wr_A, wr_P(7'hc, periph_insel_q_fpv[89:60], dut.u_reg.regen_qs, 'h3fffffff, 0))
-  `ASSERT(periph_insel2_rd_A, rd_P(7'hc, periph_insel_q_fpv[89:60], 'h3fffffff, 0))
-  // assertions for register: periph_insel3
-  `ASSERT(periph_insel3_wr_A, wr_P(7'h10, periph_insel_q_fpv[119:90], dut.u_reg.regen_qs, 'h3fffffff, 0))
-  `ASSERT(periph_insel3_rd_A, rd_P(7'h10, periph_insel_q_fpv[119:90], 'h3fffffff, 0))
-  // assertions for register: periph_insel4
-  `ASSERT(periph_insel4_wr_A, wr_P(7'h14, periph_insel_q_fpv[149:120], dut.u_reg.regen_qs, 'h3fffffff, 0))
-  `ASSERT(periph_insel4_rd_A, rd_P(7'h14, periph_insel_q_fpv[149:120], 'h3fffffff, 0))
-  // assertions for register: periph_insel5
-  `ASSERT(periph_insel5_wr_A, wr_P(7'h18, periph_insel_q_fpv[179:150], dut.u_reg.regen_qs, 'h3fffffff, 0))
-  `ASSERT(periph_insel5_rd_A, rd_P(7'h18, periph_insel_q_fpv[179:150], 'h3fffffff, 0))
-  // assertions for register: periph_insel6
-  `ASSERT(periph_insel6_wr_A, wr_P(7'h1c, periph_insel_q_fpv[191:180], dut.u_reg.regen_qs, 'hfff, 0))
-  `ASSERT(periph_insel6_rd_A, rd_P(7'h1c, periph_insel_q_fpv[191:180], 'hfff, 0))
-
-  // define local fpv variable for multi-reg
-  logic [191:0] mio_outsel_q_fpv;
-  for (genvar s = 0; s < 32; s++) begin : gen_mio_outsel_q
-    assign mio_outsel_q_fpv[((s+1)*6-1):s*6] = reg2hw.mio_outsel[s].q;
-  end
-
-  // assertions for register: mio_outsel0
-  `ASSERT(mio_outsel0_wr_A, wr_P(7'h20, mio_outsel_q_fpv[29:0], dut.u_reg.regen_qs, 'h3fffffff, 0))
-  `ASSERT(mio_outsel0_rd_A, rd_P(7'h20, mio_outsel_q_fpv[29:0], 'h3fffffff, 0))
-  // assertions for register: mio_outsel1
-  `ASSERT(mio_outsel1_wr_A, wr_P(7'h24, mio_outsel_q_fpv[59:30], dut.u_reg.regen_qs, 'h3fffffff, 0))
-  `ASSERT(mio_outsel1_rd_A, rd_P(7'h24, mio_outsel_q_fpv[59:30], 'h3fffffff, 0))
-  // assertions for register: mio_outsel2
-  `ASSERT(mio_outsel2_wr_A, wr_P(7'h28, mio_outsel_q_fpv[89:60], dut.u_reg.regen_qs, 'h3fffffff, 0))
-  `ASSERT(mio_outsel2_rd_A, rd_P(7'h28, mio_outsel_q_fpv[89:60], 'h3fffffff, 0))
-  // assertions for register: mio_outsel3
-  `ASSERT(mio_outsel3_wr_A, wr_P(7'h2c, mio_outsel_q_fpv[119:90], dut.u_reg.regen_qs, 'h3fffffff, 0))
-  `ASSERT(mio_outsel3_rd_A, rd_P(7'h2c, mio_outsel_q_fpv[119:90], 'h3fffffff, 0))
-  // assertions for register: mio_outsel4
-  `ASSERT(mio_outsel4_wr_A, wr_P(7'h30, mio_outsel_q_fpv[149:120], dut.u_reg.regen_qs, 'h3fffffff, 0))
-  `ASSERT(mio_outsel4_rd_A, rd_P(7'h30, mio_outsel_q_fpv[149:120], 'h3fffffff, 0))
-  // assertions for register: mio_outsel5
-  `ASSERT(mio_outsel5_wr_A, wr_P(7'h34, mio_outsel_q_fpv[179:150], dut.u_reg.regen_qs, 'h3fffffff, 0))
-  `ASSERT(mio_outsel5_rd_A, rd_P(7'h34, mio_outsel_q_fpv[179:150], 'h3fffffff, 0))
-  // assertions for register: mio_outsel6
-  `ASSERT(mio_outsel6_wr_A, wr_P(7'h38, mio_outsel_q_fpv[191:180], dut.u_reg.regen_qs, 'hfff, 0))
-  `ASSERT(mio_outsel6_rd_A, rd_P(7'h38, mio_outsel_q_fpv[191:180], 'hfff, 0))
-
-  // define local fpv variable for multi-reg
-  logic [63:0] mio_out_sleep_val_q_fpv;
-  for (genvar s = 0; s < 32; s++) begin : gen_mio_out_sleep_val_q
-    assign mio_out_sleep_val_q_fpv[((s+1)*2-1):s*2] = reg2hw.mio_out_sleep_val[s].q;
-  end
-
-  // assertions for register: mio_out_sleep_val0
-  `ASSERT(mio_out_sleep_val0_wr_A, wr_P(7'h3c, mio_out_sleep_val_q_fpv[31:0], dut.u_reg.regen_qs, 'hffffffff, 0))
-  `ASSERT(mio_out_sleep_val0_rd_A, rd_P(7'h3c, mio_out_sleep_val_q_fpv[31:0], 'hffffffff, 0))
-  // assertions for register: mio_out_sleep_val1
-  `ASSERT(mio_out_sleep_val1_wr_A, wr_P(7'h40, mio_out_sleep_val_q_fpv[63:32], dut.u_reg.regen_qs, 'hffffffff, 0))
-  `ASSERT(mio_out_sleep_val1_rd_A, rd_P(7'h40, mio_out_sleep_val_q_fpv[63:32], 'hffffffff, 0))
-
-  // define local fpv variable for multi-reg
-  logic [31:0] dio_out_sleep_val_q_fpv;
-  logic [31:0] dio_out_sleep_val_d_fpv;
-  for (genvar s = 0; s < 16; s++) begin : gen_dio_out_sleep_val_q
-    assign dio_out_sleep_val_q_fpv[((s+1)*2-1):s*2] = reg2hw.dio_out_sleep_val[s].q;
-    assign dio_out_sleep_val_d_fpv[((s+1)*2-1):s*2] = hw2reg.dio_out_sleep_val[s].d;
-  end
-
-  // assertions for register: dio_out_sleep_val
-  `ASSERT(dio_out_sleep_val_wr_A, wr_ext_P(7'h44, dio_out_sleep_val_q_fpv[31:0], dut.u_reg.regen_qs, 'hffffffff, 0))
-  `ASSERT(dio_out_sleep_val_rd_A, rd_ext_P(7'h44, dio_out_sleep_val_d_fpv[31:0], 'hffffffff, 0))
-
-  // define local fpv variable for multi-reg
-  logic [7:0] wkup_detector_en_q_fpv;
-  for (genvar s = 0; s < 8; s++) begin : gen_wkup_detector_en_q
-    assign wkup_detector_en_q_fpv[((s+1)*1-1):s*1] = reg2hw.wkup_detector_en[s].q;
-  end
-
-  // assertions for register: wkup_detector_en
-  `ASSERT(wkup_detector_en_wr_A, wr_P(7'h48, wkup_detector_en_q_fpv[7:0], dut.u_reg.regen_qs, 'hff, 0))
-  `ASSERT(wkup_detector_en_rd_A, rd_P(7'h48, wkup_detector_en_q_fpv[7:0], 'hff, 0))
-
-  // define local fpv variable for multi-reg
-  logic [23:0] wkup_detector_mode_q_fpv;
-  logic [7:0] wkup_detector_filter_q_fpv;
-  logic [7:0] wkup_detector_miodio_q_fpv;
-  for (genvar s = 0; s < 8; s++) begin : gen_wkup_detector_q
-    assign wkup_detector_mode_q_fpv[((s+1)*3-1):s*3] = reg2hw.wkup_detector[s].mode.q;
-    assign wkup_detector_filter_q_fpv[((s+1)*1-1):s*1] = reg2hw.wkup_detector[s].filter.q;
-    assign wkup_detector_miodio_q_fpv[((s+1)*1-1):s*1] = reg2hw.wkup_detector[s].miodio.q;
-  end
-
-  // assertions for register: wkup_detector0
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector0_mode0_wr_A, wr_P(7'h4c, wkup_detector_mode_q_fpv[2:0], dut.u_reg.regen_qs, 'h7, 0))
-  `ASSERT(wkup_detector0_mode0_rd_A, rd_P(7'h4c, wkup_detector_mode_q_fpv[2:0], 'h7, 0))
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector0_filter0_wr_A, wr_P(7'h4c, wkup_detector_filter_q_fpv[0:0], dut.u_reg.regen_qs, 'h8, 3))
-  `ASSERT(wkup_detector0_filter0_rd_A, rd_P(7'h4c, wkup_detector_filter_q_fpv[0:0], 'h8, 3))
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector0_miodio0_wr_A, wr_P(7'h4c, wkup_detector_miodio_q_fpv[0:0], dut.u_reg.regen_qs, 'h10, 4))
-  `ASSERT(wkup_detector0_miodio0_rd_A, rd_P(7'h4c, wkup_detector_miodio_q_fpv[0:0], 'h10, 4))
-  // assertions for register: wkup_detector1
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector1_mode1_wr_A, wr_P(7'h50, wkup_detector_mode_q_fpv[5:3], dut.u_reg.regen_qs, 'h7, 0))
-  `ASSERT(wkup_detector1_mode1_rd_A, rd_P(7'h50, wkup_detector_mode_q_fpv[5:3], 'h7, 0))
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector1_filter1_wr_A, wr_P(7'h50, wkup_detector_filter_q_fpv[1:1], dut.u_reg.regen_qs, 'h8, 3))
-  `ASSERT(wkup_detector1_filter1_rd_A, rd_P(7'h50, wkup_detector_filter_q_fpv[1:1], 'h8, 3))
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector1_miodio1_wr_A, wr_P(7'h50, wkup_detector_miodio_q_fpv[1:1], dut.u_reg.regen_qs, 'h10, 4))
-  `ASSERT(wkup_detector1_miodio1_rd_A, rd_P(7'h50, wkup_detector_miodio_q_fpv[1:1], 'h10, 4))
-  // assertions for register: wkup_detector2
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector2_mode2_wr_A, wr_P(7'h54, wkup_detector_mode_q_fpv[8:6], dut.u_reg.regen_qs, 'h7, 0))
-  `ASSERT(wkup_detector2_mode2_rd_A, rd_P(7'h54, wkup_detector_mode_q_fpv[8:6], 'h7, 0))
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector2_filter2_wr_A, wr_P(7'h54, wkup_detector_filter_q_fpv[2:2], dut.u_reg.regen_qs, 'h8, 3))
-  `ASSERT(wkup_detector2_filter2_rd_A, rd_P(7'h54, wkup_detector_filter_q_fpv[2:2], 'h8, 3))
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector2_miodio2_wr_A, wr_P(7'h54, wkup_detector_miodio_q_fpv[2:2], dut.u_reg.regen_qs, 'h10, 4))
-  `ASSERT(wkup_detector2_miodio2_rd_A, rd_P(7'h54, wkup_detector_miodio_q_fpv[2:2], 'h10, 4))
-  // assertions for register: wkup_detector3
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector3_mode3_wr_A, wr_P(7'h58, wkup_detector_mode_q_fpv[11:9], dut.u_reg.regen_qs, 'h7, 0))
-  `ASSERT(wkup_detector3_mode3_rd_A, rd_P(7'h58, wkup_detector_mode_q_fpv[11:9], 'h7, 0))
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector3_filter3_wr_A, wr_P(7'h58, wkup_detector_filter_q_fpv[3:3], dut.u_reg.regen_qs, 'h8, 3))
-  `ASSERT(wkup_detector3_filter3_rd_A, rd_P(7'h58, wkup_detector_filter_q_fpv[3:3], 'h8, 3))
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector3_miodio3_wr_A, wr_P(7'h58, wkup_detector_miodio_q_fpv[3:3], dut.u_reg.regen_qs, 'h10, 4))
-  `ASSERT(wkup_detector3_miodio3_rd_A, rd_P(7'h58, wkup_detector_miodio_q_fpv[3:3], 'h10, 4))
-  // assertions for register: wkup_detector4
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector4_mode4_wr_A, wr_P(7'h5c, wkup_detector_mode_q_fpv[14:12], dut.u_reg.regen_qs, 'h7, 0))
-  `ASSERT(wkup_detector4_mode4_rd_A, rd_P(7'h5c, wkup_detector_mode_q_fpv[14:12], 'h7, 0))
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector4_filter4_wr_A, wr_P(7'h5c, wkup_detector_filter_q_fpv[4:4], dut.u_reg.regen_qs, 'h8, 3))
-  `ASSERT(wkup_detector4_filter4_rd_A, rd_P(7'h5c, wkup_detector_filter_q_fpv[4:4], 'h8, 3))
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector4_miodio4_wr_A, wr_P(7'h5c, wkup_detector_miodio_q_fpv[4:4], dut.u_reg.regen_qs, 'h10, 4))
-  `ASSERT(wkup_detector4_miodio4_rd_A, rd_P(7'h5c, wkup_detector_miodio_q_fpv[4:4], 'h10, 4))
-  // assertions for register: wkup_detector5
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector5_mode5_wr_A, wr_P(7'h60, wkup_detector_mode_q_fpv[17:15], dut.u_reg.regen_qs, 'h7, 0))
-  `ASSERT(wkup_detector5_mode5_rd_A, rd_P(7'h60, wkup_detector_mode_q_fpv[17:15], 'h7, 0))
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector5_filter5_wr_A, wr_P(7'h60, wkup_detector_filter_q_fpv[5:5], dut.u_reg.regen_qs, 'h8, 3))
-  `ASSERT(wkup_detector5_filter5_rd_A, rd_P(7'h60, wkup_detector_filter_q_fpv[5:5], 'h8, 3))
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector5_miodio5_wr_A, wr_P(7'h60, wkup_detector_miodio_q_fpv[5:5], dut.u_reg.regen_qs, 'h10, 4))
-  `ASSERT(wkup_detector5_miodio5_rd_A, rd_P(7'h60, wkup_detector_miodio_q_fpv[5:5], 'h10, 4))
-  // assertions for register: wkup_detector6
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector6_mode6_wr_A, wr_P(7'h64, wkup_detector_mode_q_fpv[20:18], dut.u_reg.regen_qs, 'h7, 0))
-  `ASSERT(wkup_detector6_mode6_rd_A, rd_P(7'h64, wkup_detector_mode_q_fpv[20:18], 'h7, 0))
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector6_filter6_wr_A, wr_P(7'h64, wkup_detector_filter_q_fpv[6:6], dut.u_reg.regen_qs, 'h8, 3))
-  `ASSERT(wkup_detector6_filter6_rd_A, rd_P(7'h64, wkup_detector_filter_q_fpv[6:6], 'h8, 3))
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector6_miodio6_wr_A, wr_P(7'h64, wkup_detector_miodio_q_fpv[6:6], dut.u_reg.regen_qs, 'h10, 4))
-  `ASSERT(wkup_detector6_miodio6_rd_A, rd_P(7'h64, wkup_detector_miodio_q_fpv[6:6], 'h10, 4))
-  // assertions for register: wkup_detector7
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector7_mode7_wr_A, wr_P(7'h68, wkup_detector_mode_q_fpv[23:21], dut.u_reg.regen_qs, 'h7, 0))
-  `ASSERT(wkup_detector7_mode7_rd_A, rd_P(7'h68, wkup_detector_mode_q_fpv[23:21], 'h7, 0))
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector7_filter7_wr_A, wr_P(7'h68, wkup_detector_filter_q_fpv[7:7], dut.u_reg.regen_qs, 'h8, 3))
-  `ASSERT(wkup_detector7_filter7_rd_A, rd_P(7'h68, wkup_detector_filter_q_fpv[7:7], 'h8, 3))
-  // this is a non-homog multi-reg
-  `ASSERT(wkup_detector7_miodio7_wr_A, wr_P(7'h68, wkup_detector_miodio_q_fpv[7:7], dut.u_reg.regen_qs, 'h10, 4))
-  `ASSERT(wkup_detector7_miodio7_rd_A, rd_P(7'h68, wkup_detector_miodio_q_fpv[7:7], 'h10, 4))
-
-  // define local fpv variable for multi-reg
-  logic [63:0] wkup_detector_cnt_th_q_fpv;
-  for (genvar s = 0; s < 8; s++) begin : gen_wkup_detector_cnt_th_q
-    assign wkup_detector_cnt_th_q_fpv[((s+1)*8-1):s*8] = reg2hw.wkup_detector_cnt_th[s].q;
-  end
-
-  // assertions for register: wkup_detector_cnt_th0
-  `ASSERT(wkup_detector_cnt_th0_wr_A, wr_P(7'h6c, wkup_detector_cnt_th_q_fpv[31:0], dut.u_reg.regen_qs, 'hffffffff, 0))
-  `ASSERT(wkup_detector_cnt_th0_rd_A, rd_P(7'h6c, wkup_detector_cnt_th_q_fpv[31:0], 'hffffffff, 0))
-  // assertions for register: wkup_detector_cnt_th1
-  `ASSERT(wkup_detector_cnt_th1_wr_A, wr_P(7'h70, wkup_detector_cnt_th_q_fpv[63:32], dut.u_reg.regen_qs, 'hffffffff, 0))
-  `ASSERT(wkup_detector_cnt_th1_rd_A, rd_P(7'h70, wkup_detector_cnt_th_q_fpv[63:32], 'hffffffff, 0))
-
-  // define local fpv variable for multi-reg
-  logic [39:0] wkup_detector_padsel_q_fpv;
-  for (genvar s = 0; s < 8; s++) begin : gen_wkup_detector_padsel_q
-    assign wkup_detector_padsel_q_fpv[((s+1)*5-1):s*5] = reg2hw.wkup_detector_padsel[s].q;
-  end
-
-  // assertions for register: wkup_detector_padsel0
-  `ASSERT(wkup_detector_padsel0_wr_A, wr_P(7'h74, wkup_detector_padsel_q_fpv[29:0], dut.u_reg.regen_qs, 'h3fffffff, 0))
-  `ASSERT(wkup_detector_padsel0_rd_A, rd_P(7'h74, wkup_detector_padsel_q_fpv[29:0], 'h3fffffff, 0))
-  // assertions for register: wkup_detector_padsel1
-  `ASSERT(wkup_detector_padsel1_wr_A, wr_P(7'h78, wkup_detector_padsel_q_fpv[39:30], dut.u_reg.regen_qs, 'h3ff, 0))
-  `ASSERT(wkup_detector_padsel1_rd_A, rd_P(7'h78, wkup_detector_padsel_q_fpv[39:30], 'h3ff, 0))
-
-  // define local fpv variable for multi-reg
-  logic [7:0] wkup_cause_q_fpv;
-  logic [7:0] wkup_cause_d_fpv;
-  for (genvar s = 0; s < 8; s++) begin : gen_wkup_cause_q
-    assign wkup_cause_q_fpv[((s+1)*1-1):s*1] = reg2hw.wkup_cause[s].q;
-    assign wkup_cause_d_fpv[((s+1)*1-1):s*1] = hw2reg.wkup_cause[s].d;
-  end
-
-  // assertions for register: wkup_cause
-  `ASSERT(wkup_cause_wr_A, wr_ext_P(7'h7c, wkup_cause_q_fpv[7:0], dut.u_reg.regen_qs, 'hff, 0))
-  `ASSERT(wkup_cause_rd_A, rd_ext_P(7'h7c, wkup_cause_d_fpv[7:0], 'hff, 0))
-
-
-endmodule
diff --git a/hw/ip/rv_plic/data/rv_plic_fpv.core.tpl b/hw/ip/rv_plic/data/rv_plic_fpv.core.tpl
index fd5c59f..507e02d 100644
--- a/hw/ip/rv_plic/data/rv_plic_fpv.core.tpl
+++ b/hw/ip/rv_plic/data/rv_plic_fpv.core.tpl
@@ -10,12 +10,19 @@
     depend:
       - lowrisc:fpv:rv_plic_component_fpv
       - lowrisc:top_earlgrey:rv_plic
+      - lowrisc:fpv:csr_assert_gen
     files:
-      - rv_plic_csr_assert_fpv.sv
       - rv_plic_bind_fpv.sv
       - rv_plic_fpv.sv
     file_type: systemVerilogSource
 
+generate:
+  csr_assert_gen:
+    generator: csr_assert_gen
+    parameters:
+      spec: ../../data/autogen/rv_plic.hjson
+      depend: lowrisc:top_earlgrey:rv_plic
+
 targets:
   default: &default_target
     # note, this setting is just used
@@ -23,6 +30,8 @@
     default_tool: icarus
     filesets:
       - files_formal
+    generate:
+      - csr_assert_gen
     toplevel: rv_plic_fpv
 
   formal:
diff --git a/hw/ip/rv_plic/fpv/rv_plic_generic_fpv.core b/hw/ip/rv_plic/fpv/rv_plic_generic_fpv.core
index 0f98a47..305b989 100644
--- a/hw/ip/rv_plic/fpv/rv_plic_generic_fpv.core
+++ b/hw/ip/rv_plic/fpv/rv_plic_generic_fpv.core
@@ -12,12 +12,19 @@
       # note: this is an example config which may differ
       # from a particular top-level config
       - lowrisc:ip:rv_plic_example
+      - lowrisc:fpv:csr_assert_gen
     files:
-      - vip/rv_plic_csr_assert_fpv.sv
       - tb/rv_plic_bind_fpv.sv
       - tb/rv_plic_generic_fpv.sv
     file_type: systemVerilogSource
 
+generate:
+  csr_assert_gen:
+    generator: csr_assert_gen
+    parameters:
+      spec: ../data/rv_plic.hjson
+      depend: lowrisc:ip:rv_plic_example
+
 targets:
   default: &default_target
     # note, this setting is just used
@@ -25,6 +32,8 @@
     default_tool: icarus
     filesets:
       - files_formal
+    generate:
+      - csr_assert_gen
     toplevel: rv_plic_generic_fpv
 
   formal:
diff --git a/hw/ip/rv_plic/fpv/vip/rv_plic_csr_assert_fpv.sv b/hw/ip/rv_plic/fpv/vip/rv_plic_csr_assert_fpv.sv
deleted file mode 100644
index d9e1574..0000000
--- a/hw/ip/rv_plic/fpv/vip/rv_plic_csr_assert_fpv.sv
+++ /dev/null
@@ -1,285 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-
-// 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
-
-`include "prim_assert.sv"
-
-// Block: rv_plic
-module rv_plic_csr_assert_fpv import tlul_pkg::*; import rv_plic_reg_pkg::*; (
-  input clk_i,
-  input rst_ni,
-
-  // tile link ports
-  input tl_h2d_t h2d,
-  input tl_d2h_t d2h,
-
-  // reg and hw ports
-  input rv_plic_reg2hw_t reg2hw,
-  input rv_plic_hw2reg_t hw2reg
-);
-
-  parameter int DWidth = 32;
-  // mask register to convert byte to bit
-  logic [DWidth-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;
-  assign a_mask_bit[23:16] = h2d.a_mask[2] ? '1 : '0;
-  assign a_mask_bit[31:24] = h2d.a_mask[3] ? '1 : '0;
-
-  // declare common read and write sequences
-  sequence device_wr_S(logic [8:0] addr);
-    h2d.a_address == addr && h2d.a_opcode inside {PutFullData, PutPartialData} &&
-        h2d.a_valid && h2d.d_ready && !d2h.d_valid;
-  endsequence
-
-  sequence device_rd_S(logic [8:0] addr);
-    h2d.a_address == addr && h2d.a_opcode inside {Get} && h2d.a_valid && h2d.d_ready &&
-        !d2h.d_valid;
-  endsequence
-
-  // declare common read and write properties
-  // for homog registers, we check by a reg; for non-homog regs, we check by field.
-  // `mask` is used for checking by field. It masks out any act_data that are not within the field
-  // `lsb` is used to check non-homog multi_reg. Because we are using a local copy `_fpv` variable
-  // 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 [8:0] addr, bit [DWidth-1:0] act_data, bit regen,
-                bit [DWidth-1:0] mask, int lsb);
-    logic [DWidth-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 [8:0] addr, bit [DWidth-1:0] act_data, bit regen,
-                    bit [DWidth-1:0] mask, int lsb);
-    logic [DWidth-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 w1c_P(bit [8:0] addr, bit [DWidth-1:0] act_data, bit regen,
-                bit [DWidth-1:0] mask, int lsb);
-    logic [DWidth-1:0] id, exp_data;
-    (device_wr_S(addr), id = h2d.a_source, exp_data = h2d.a_data & a_mask_bit & mask & '0) ##1
-        first_match(##[0:$] d2h.d_valid && d2h.d_source == id) |->
-        (d2h.d_error || (act_data << lsb) == exp_data || !regen);
-  endproperty
-
-  property w1c_ext_P(bit [8:0] addr, bit [DWidth-1:0] act_data, bit regen,
-                    bit [DWidth-1:0] mask, int lsb);
-    logic [DWidth-1:0] id, exp_data;
-    (device_wr_S(addr), id = h2d.a_source, exp_data = h2d.a_data & a_mask_bit & mask & '0) ##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 [8:0] addr, bit [DWidth-1:0] act_data, bit [DWidth-1:0] mask, int lsb);
-    logic [DWidth-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 [8:0] addr, bit [DWidth-1:0] act_data, bit [DWidth-1:0] mask,
-      int lsb);
-    logic [DWidth-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
-
-  // read a WO register, always return 0
-  property r_wo_P(bit [8:0] addr);
-    logic [DWidth-1:0] id;
-    (device_rd_S(addr), id = h2d.a_source) ##1
-        first_match(##[0:$] (d2h.d_valid && d2h.d_source == id)) |->
-        (d2h.d_error || d2h.d_data == 0);
-  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
-
-
-  // define local fpv variable for multi-reg
-  logic [31:0] ip_d_fpv;
-  for (genvar s = 0; s < 32; s++) begin : gen_ip_q
-    assign ip_d_fpv[((s+1)*1-1):s*1] = hw2reg.ip[s].d;
-  end
-
-  // assertions for register: ip
-  `ASSERT(ip_rd_A, rd_P(9'h0, ip_d_fpv[31:0], 'hffffffff, 0))
-
-  // define local fpv variable for multi-reg
-  logic [31:0] le_q_fpv;
-  for (genvar s = 0; s < 32; s++) begin : gen_le_q
-    assign le_q_fpv[((s+1)*1-1):s*1] = reg2hw.le[s].q;
-  end
-
-  // assertions for register: le
-  `ASSERT(le_wr_A, wr_P(9'h4, le_q_fpv[31:0], 1, 'hffffffff, 0))
-  `ASSERT(le_rd_A, rd_P(9'h4, le_q_fpv[31:0], 'hffffffff, 0))
-
-  // assertions for register: prio0
-  `ASSERT(prio0_wr_A, wr_P(9'h8, reg2hw.prio0.q, 1, 'h7, 0))
-  `ASSERT(prio0_rd_A, rd_P(9'h8, reg2hw.prio0.q, 'hffffffff, 0))
-
-  // assertions for register: prio1
-  `ASSERT(prio1_wr_A, wr_P(9'hc, reg2hw.prio1.q, 1, 'h7, 0))
-  `ASSERT(prio1_rd_A, rd_P(9'hc, reg2hw.prio1.q, 'hffffffff, 0))
-
-  // assertions for register: prio2
-  `ASSERT(prio2_wr_A, wr_P(9'h10, reg2hw.prio2.q, 1, 'h7, 0))
-  `ASSERT(prio2_rd_A, rd_P(9'h10, reg2hw.prio2.q, 'hffffffff, 0))
-
-  // assertions for register: prio3
-  `ASSERT(prio3_wr_A, wr_P(9'h14, reg2hw.prio3.q, 1, 'h7, 0))
-  `ASSERT(prio3_rd_A, rd_P(9'h14, reg2hw.prio3.q, 'hffffffff, 0))
-
-  // assertions for register: prio4
-  `ASSERT(prio4_wr_A, wr_P(9'h18, reg2hw.prio4.q, 1, 'h7, 0))
-  `ASSERT(prio4_rd_A, rd_P(9'h18, reg2hw.prio4.q, 'hffffffff, 0))
-
-  // assertions for register: prio5
-  `ASSERT(prio5_wr_A, wr_P(9'h1c, reg2hw.prio5.q, 1, 'h7, 0))
-  `ASSERT(prio5_rd_A, rd_P(9'h1c, reg2hw.prio5.q, 'hffffffff, 0))
-
-  // assertions for register: prio6
-  `ASSERT(prio6_wr_A, wr_P(9'h20, reg2hw.prio6.q, 1, 'h7, 0))
-  `ASSERT(prio6_rd_A, rd_P(9'h20, reg2hw.prio6.q, 'hffffffff, 0))
-
-  // assertions for register: prio7
-  `ASSERT(prio7_wr_A, wr_P(9'h24, reg2hw.prio7.q, 1, 'h7, 0))
-  `ASSERT(prio7_rd_A, rd_P(9'h24, reg2hw.prio7.q, 'hffffffff, 0))
-
-  // assertions for register: prio8
-  `ASSERT(prio8_wr_A, wr_P(9'h28, reg2hw.prio8.q, 1, 'h7, 0))
-  `ASSERT(prio8_rd_A, rd_P(9'h28, reg2hw.prio8.q, 'hffffffff, 0))
-
-  // assertions for register: prio9
-  `ASSERT(prio9_wr_A, wr_P(9'h2c, reg2hw.prio9.q, 1, 'h7, 0))
-  `ASSERT(prio9_rd_A, rd_P(9'h2c, reg2hw.prio9.q, 'hffffffff, 0))
-
-  // assertions for register: prio10
-  `ASSERT(prio10_wr_A, wr_P(9'h30, reg2hw.prio10.q, 1, 'h7, 0))
-  `ASSERT(prio10_rd_A, rd_P(9'h30, reg2hw.prio10.q, 'hffffffff, 0))
-
-  // assertions for register: prio11
-  `ASSERT(prio11_wr_A, wr_P(9'h34, reg2hw.prio11.q, 1, 'h7, 0))
-  `ASSERT(prio11_rd_A, rd_P(9'h34, reg2hw.prio11.q, 'hffffffff, 0))
-
-  // assertions for register: prio12
-  `ASSERT(prio12_wr_A, wr_P(9'h38, reg2hw.prio12.q, 1, 'h7, 0))
-  `ASSERT(prio12_rd_A, rd_P(9'h38, reg2hw.prio12.q, 'hffffffff, 0))
-
-  // assertions for register: prio13
-  `ASSERT(prio13_wr_A, wr_P(9'h3c, reg2hw.prio13.q, 1, 'h7, 0))
-  `ASSERT(prio13_rd_A, rd_P(9'h3c, reg2hw.prio13.q, 'hffffffff, 0))
-
-  // assertions for register: prio14
-  `ASSERT(prio14_wr_A, wr_P(9'h40, reg2hw.prio14.q, 1, 'h7, 0))
-  `ASSERT(prio14_rd_A, rd_P(9'h40, reg2hw.prio14.q, 'hffffffff, 0))
-
-  // assertions for register: prio15
-  `ASSERT(prio15_wr_A, wr_P(9'h44, reg2hw.prio15.q, 1, 'h7, 0))
-  `ASSERT(prio15_rd_A, rd_P(9'h44, reg2hw.prio15.q, 'hffffffff, 0))
-
-  // assertions for register: prio16
-  `ASSERT(prio16_wr_A, wr_P(9'h48, reg2hw.prio16.q, 1, 'h7, 0))
-  `ASSERT(prio16_rd_A, rd_P(9'h48, reg2hw.prio16.q, 'hffffffff, 0))
-
-  // assertions for register: prio17
-  `ASSERT(prio17_wr_A, wr_P(9'h4c, reg2hw.prio17.q, 1, 'h7, 0))
-  `ASSERT(prio17_rd_A, rd_P(9'h4c, reg2hw.prio17.q, 'hffffffff, 0))
-
-  // assertions for register: prio18
-  `ASSERT(prio18_wr_A, wr_P(9'h50, reg2hw.prio18.q, 1, 'h7, 0))
-  `ASSERT(prio18_rd_A, rd_P(9'h50, reg2hw.prio18.q, 'hffffffff, 0))
-
-  // assertions for register: prio19
-  `ASSERT(prio19_wr_A, wr_P(9'h54, reg2hw.prio19.q, 1, 'h7, 0))
-  `ASSERT(prio19_rd_A, rd_P(9'h54, reg2hw.prio19.q, 'hffffffff, 0))
-
-  // assertions for register: prio20
-  `ASSERT(prio20_wr_A, wr_P(9'h58, reg2hw.prio20.q, 1, 'h7, 0))
-  `ASSERT(prio20_rd_A, rd_P(9'h58, reg2hw.prio20.q, 'hffffffff, 0))
-
-  // assertions for register: prio21
-  `ASSERT(prio21_wr_A, wr_P(9'h5c, reg2hw.prio21.q, 1, 'h7, 0))
-  `ASSERT(prio21_rd_A, rd_P(9'h5c, reg2hw.prio21.q, 'hffffffff, 0))
-
-  // assertions for register: prio22
-  `ASSERT(prio22_wr_A, wr_P(9'h60, reg2hw.prio22.q, 1, 'h7, 0))
-  `ASSERT(prio22_rd_A, rd_P(9'h60, reg2hw.prio22.q, 'hffffffff, 0))
-
-  // assertions for register: prio23
-  `ASSERT(prio23_wr_A, wr_P(9'h64, reg2hw.prio23.q, 1, 'h7, 0))
-  `ASSERT(prio23_rd_A, rd_P(9'h64, reg2hw.prio23.q, 'hffffffff, 0))
-
-  // assertions for register: prio24
-  `ASSERT(prio24_wr_A, wr_P(9'h68, reg2hw.prio24.q, 1, 'h7, 0))
-  `ASSERT(prio24_rd_A, rd_P(9'h68, reg2hw.prio24.q, 'hffffffff, 0))
-
-  // assertions for register: prio25
-  `ASSERT(prio25_wr_A, wr_P(9'h6c, reg2hw.prio25.q, 1, 'h7, 0))
-  `ASSERT(prio25_rd_A, rd_P(9'h6c, reg2hw.prio25.q, 'hffffffff, 0))
-
-  // assertions for register: prio26
-  `ASSERT(prio26_wr_A, wr_P(9'h70, reg2hw.prio26.q, 1, 'h7, 0))
-  `ASSERT(prio26_rd_A, rd_P(9'h70, reg2hw.prio26.q, 'hffffffff, 0))
-
-  // assertions for register: prio27
-  `ASSERT(prio27_wr_A, wr_P(9'h74, reg2hw.prio27.q, 1, 'h7, 0))
-  `ASSERT(prio27_rd_A, rd_P(9'h74, reg2hw.prio27.q, 'hffffffff, 0))
-
-  // assertions for register: prio28
-  `ASSERT(prio28_wr_A, wr_P(9'h78, reg2hw.prio28.q, 1, 'h7, 0))
-  `ASSERT(prio28_rd_A, rd_P(9'h78, reg2hw.prio28.q, 'hffffffff, 0))
-
-  // assertions for register: prio29
-  `ASSERT(prio29_wr_A, wr_P(9'h7c, reg2hw.prio29.q, 1, 'h7, 0))
-  `ASSERT(prio29_rd_A, rd_P(9'h7c, reg2hw.prio29.q, 'hffffffff, 0))
-
-  // assertions for register: prio30
-  `ASSERT(prio30_wr_A, wr_P(9'h80, reg2hw.prio30.q, 1, 'h7, 0))
-  `ASSERT(prio30_rd_A, rd_P(9'h80, reg2hw.prio30.q, 'hffffffff, 0))
-
-  // assertions for register: prio31
-  `ASSERT(prio31_wr_A, wr_P(9'h84, reg2hw.prio31.q, 1, 'h7, 0))
-  `ASSERT(prio31_rd_A, rd_P(9'h84, reg2hw.prio31.q, 'hffffffff, 0))
-
-  // define local fpv variable for multi-reg
-  logic [31:0] ie0_q_fpv;
-  for (genvar s = 0; s < 32; s++) begin : gen_ie0_q
-    assign ie0_q_fpv[((s+1)*1-1):s*1] = reg2hw.ie0[s].q;
-  end
-
-  // assertions for register: ie0
-  `ASSERT(ie0_wr_A, wr_P(9'h100, ie0_q_fpv[31:0], 1, 'hffffffff, 0))
-  `ASSERT(ie0_rd_A, rd_P(9'h100, ie0_q_fpv[31:0], 'hffffffff, 0))
-
-  // assertions for register: threshold0
-  `ASSERT(threshold0_wr_A, wr_P(9'h104, reg2hw.threshold0.q, 1, 'h7, 0))
-  `ASSERT(threshold0_rd_A, rd_P(9'h104, reg2hw.threshold0.q, 'hffffffff, 0))
-
-  // assertions for register: cc0
-  `ASSERT(cc0_wr_A, wr_ext_P(9'h108, reg2hw.cc0.q, 1, 'h3f, 0))
-  `ASSERT(cc0_rd_A, rd_ext_P(9'h108, hw2reg.cc0.d, 'hffffffff, 0))
-
-  // assertions for register: msip0
-  `ASSERT(msip0_wr_A, wr_P(9'h10c, reg2hw.msip0.q, 1, 'h1, 0))
-  `ASSERT(msip0_rd_A, rd_P(9'h10c, reg2hw.msip0.q, 'hffffffff, 0))
-
-
-endmodule
diff --git a/hw/top_earlgrey/ip/rv_plic/fpv/autogen/rv_plic_csr_assert_fpv.sv b/hw/top_earlgrey/ip/rv_plic/fpv/autogen/rv_plic_csr_assert_fpv.sv
deleted file mode 100644
index 67aa2a3..0000000
--- a/hw/top_earlgrey/ip/rv_plic/fpv/autogen/rv_plic_csr_assert_fpv.sv
+++ /dev/null
@@ -1,505 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-
-// 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
-
-`include "prim_assert.sv"
-
-// Block: rv_plic
-module rv_plic_csr_assert_fpv import tlul_pkg::*; import rv_plic_reg_pkg::*; (
-  input clk_i,
-  input rst_ni,
-
-  // tile link ports
-  input tl_h2d_t h2d,
-  input tl_d2h_t d2h,
-
-  // reg and hw ports
-  input rv_plic_reg2hw_t reg2hw,
-  input rv_plic_hw2reg_t hw2reg
-);
-
-  parameter int DWidth = 32;
-  // mask register to convert byte to bit
-  logic [DWidth-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;
-  assign a_mask_bit[23:16] = h2d.a_mask[2] ? '1 : '0;
-  assign a_mask_bit[31:24] = h2d.a_mask[3] ? '1 : '0;
-
-  // declare common read and write sequences
-  sequence device_wr_S(logic [9:0] addr);
-    h2d.a_address == addr && h2d.a_opcode inside {PutFullData, PutPartialData} &&
-        h2d.a_valid && h2d.d_ready && !d2h.d_valid;
-  endsequence
-
-  sequence device_rd_S(logic [9:0] addr);
-    h2d.a_address == addr && h2d.a_opcode inside {Get} && h2d.a_valid && h2d.d_ready &&
-        !d2h.d_valid;
-  endsequence
-
-  // declare common read and write properties
-  // for homog registers, we check by a reg; for non-homog regs, we check by field.
-  // `mask` is used for checking by field. It masks out any act_data that are not within the field
-  // `lsb` is used to check non-homog multi_reg. Because we are using a local copy `_fpv` variable
-  // 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 [9:0] addr, bit [DWidth-1:0] act_data, bit regen,
-                bit [DWidth-1:0] mask, int lsb);
-    logic [DWidth-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 [9:0] addr, bit [DWidth-1:0] act_data, bit regen,
-                    bit [DWidth-1:0] mask, int lsb);
-    logic [DWidth-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 w1c_P(bit [9:0] addr, bit [DWidth-1:0] act_data, bit regen,
-                bit [DWidth-1:0] mask, int lsb);
-    logic [DWidth-1:0] id, exp_data;
-    (device_wr_S(addr), id = h2d.a_source, exp_data = h2d.a_data & a_mask_bit & mask & '0) ##1
-        first_match(##[0:$] d2h.d_valid && d2h.d_source == id) |->
-        (d2h.d_error || (act_data << lsb) == exp_data || !regen);
-  endproperty
-
-  property w1c_ext_P(bit [9:0] addr, bit [DWidth-1:0] act_data, bit regen,
-                    bit [DWidth-1:0] mask, int lsb);
-    logic [DWidth-1:0] id, exp_data;
-    (device_wr_S(addr), id = h2d.a_source, exp_data = h2d.a_data & a_mask_bit & mask & '0) ##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 [9:0] addr, bit [DWidth-1:0] act_data, bit [DWidth-1:0] mask, int lsb);
-    logic [DWidth-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 [9:0] addr, bit [DWidth-1:0] act_data, bit [DWidth-1:0] mask,
-      int lsb);
-    logic [DWidth-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
-
-  // read a WO register, always return 0
-  property r_wo_P(bit [9:0] addr);
-    logic [DWidth-1:0] id;
-    (device_rd_S(addr), id = h2d.a_source) ##1
-        first_match(##[0:$] (d2h.d_valid && d2h.d_source == id)) |->
-        (d2h.d_error || d2h.d_data == 0);
-  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
-
-
-  // define local fpv variable for multi-reg
-  logic [82:0] ip_d_fpv;
-  for (genvar s = 0; s < 83; s++) begin : gen_ip_q
-    assign ip_d_fpv[((s+1)*1-1):s*1] = hw2reg.ip[s].d;
-  end
-
-  // assertions for register: ip0
-  `ASSERT(ip0_rd_A, rd_P(10'h0, ip_d_fpv[31:0], 'hffffffff, 0))
-  // assertions for register: ip1
-  `ASSERT(ip1_rd_A, rd_P(10'h4, ip_d_fpv[63:32], 'hffffffff, 0))
-  // assertions for register: ip2
-  `ASSERT(ip2_rd_A, rd_P(10'h8, ip_d_fpv[82:64], 'h7ffff, 0))
-
-  // define local fpv variable for multi-reg
-  logic [82:0] le_q_fpv;
-  for (genvar s = 0; s < 83; s++) begin : gen_le_q
-    assign le_q_fpv[((s+1)*1-1):s*1] = reg2hw.le[s].q;
-  end
-
-  // assertions for register: le0
-  `ASSERT(le0_wr_A, wr_P(10'hc, le_q_fpv[31:0], 1, 'hffffffff, 0))
-  `ASSERT(le0_rd_A, rd_P(10'hc, le_q_fpv[31:0], 'hffffffff, 0))
-  // assertions for register: le1
-  `ASSERT(le1_wr_A, wr_P(10'h10, le_q_fpv[63:32], 1, 'hffffffff, 0))
-  `ASSERT(le1_rd_A, rd_P(10'h10, le_q_fpv[63:32], 'hffffffff, 0))
-  // assertions for register: le2
-  `ASSERT(le2_wr_A, wr_P(10'h14, le_q_fpv[82:64], 1, 'h7ffff, 0))
-  `ASSERT(le2_rd_A, rd_P(10'h14, le_q_fpv[82:64], 'h7ffff, 0))
-
-  // assertions for register: prio0
-  `ASSERT(prio0_wr_A, wr_P(10'h18, reg2hw.prio0.q, 1, 'h3, 0))
-  `ASSERT(prio0_rd_A, rd_P(10'h18, reg2hw.prio0.q, 'hffffffff, 0))
-
-  // assertions for register: prio1
-  `ASSERT(prio1_wr_A, wr_P(10'h1c, reg2hw.prio1.q, 1, 'h3, 0))
-  `ASSERT(prio1_rd_A, rd_P(10'h1c, reg2hw.prio1.q, 'hffffffff, 0))
-
-  // assertions for register: prio2
-  `ASSERT(prio2_wr_A, wr_P(10'h20, reg2hw.prio2.q, 1, 'h3, 0))
-  `ASSERT(prio2_rd_A, rd_P(10'h20, reg2hw.prio2.q, 'hffffffff, 0))
-
-  // assertions for register: prio3
-  `ASSERT(prio3_wr_A, wr_P(10'h24, reg2hw.prio3.q, 1, 'h3, 0))
-  `ASSERT(prio3_rd_A, rd_P(10'h24, reg2hw.prio3.q, 'hffffffff, 0))
-
-  // assertions for register: prio4
-  `ASSERT(prio4_wr_A, wr_P(10'h28, reg2hw.prio4.q, 1, 'h3, 0))
-  `ASSERT(prio4_rd_A, rd_P(10'h28, reg2hw.prio4.q, 'hffffffff, 0))
-
-  // assertions for register: prio5
-  `ASSERT(prio5_wr_A, wr_P(10'h2c, reg2hw.prio5.q, 1, 'h3, 0))
-  `ASSERT(prio5_rd_A, rd_P(10'h2c, reg2hw.prio5.q, 'hffffffff, 0))
-
-  // assertions for register: prio6
-  `ASSERT(prio6_wr_A, wr_P(10'h30, reg2hw.prio6.q, 1, 'h3, 0))
-  `ASSERT(prio6_rd_A, rd_P(10'h30, reg2hw.prio6.q, 'hffffffff, 0))
-
-  // assertions for register: prio7
-  `ASSERT(prio7_wr_A, wr_P(10'h34, reg2hw.prio7.q, 1, 'h3, 0))
-  `ASSERT(prio7_rd_A, rd_P(10'h34, reg2hw.prio7.q, 'hffffffff, 0))
-
-  // assertions for register: prio8
-  `ASSERT(prio8_wr_A, wr_P(10'h38, reg2hw.prio8.q, 1, 'h3, 0))
-  `ASSERT(prio8_rd_A, rd_P(10'h38, reg2hw.prio8.q, 'hffffffff, 0))
-
-  // assertions for register: prio9
-  `ASSERT(prio9_wr_A, wr_P(10'h3c, reg2hw.prio9.q, 1, 'h3, 0))
-  `ASSERT(prio9_rd_A, rd_P(10'h3c, reg2hw.prio9.q, 'hffffffff, 0))
-
-  // assertions for register: prio10
-  `ASSERT(prio10_wr_A, wr_P(10'h40, reg2hw.prio10.q, 1, 'h3, 0))
-  `ASSERT(prio10_rd_A, rd_P(10'h40, reg2hw.prio10.q, 'hffffffff, 0))
-
-  // assertions for register: prio11
-  `ASSERT(prio11_wr_A, wr_P(10'h44, reg2hw.prio11.q, 1, 'h3, 0))
-  `ASSERT(prio11_rd_A, rd_P(10'h44, reg2hw.prio11.q, 'hffffffff, 0))
-
-  // assertions for register: prio12
-  `ASSERT(prio12_wr_A, wr_P(10'h48, reg2hw.prio12.q, 1, 'h3, 0))
-  `ASSERT(prio12_rd_A, rd_P(10'h48, reg2hw.prio12.q, 'hffffffff, 0))
-
-  // assertions for register: prio13
-  `ASSERT(prio13_wr_A, wr_P(10'h4c, reg2hw.prio13.q, 1, 'h3, 0))
-  `ASSERT(prio13_rd_A, rd_P(10'h4c, reg2hw.prio13.q, 'hffffffff, 0))
-
-  // assertions for register: prio14
-  `ASSERT(prio14_wr_A, wr_P(10'h50, reg2hw.prio14.q, 1, 'h3, 0))
-  `ASSERT(prio14_rd_A, rd_P(10'h50, reg2hw.prio14.q, 'hffffffff, 0))
-
-  // assertions for register: prio15
-  `ASSERT(prio15_wr_A, wr_P(10'h54, reg2hw.prio15.q, 1, 'h3, 0))
-  `ASSERT(prio15_rd_A, rd_P(10'h54, reg2hw.prio15.q, 'hffffffff, 0))
-
-  // assertions for register: prio16
-  `ASSERT(prio16_wr_A, wr_P(10'h58, reg2hw.prio16.q, 1, 'h3, 0))
-  `ASSERT(prio16_rd_A, rd_P(10'h58, reg2hw.prio16.q, 'hffffffff, 0))
-
-  // assertions for register: prio17
-  `ASSERT(prio17_wr_A, wr_P(10'h5c, reg2hw.prio17.q, 1, 'h3, 0))
-  `ASSERT(prio17_rd_A, rd_P(10'h5c, reg2hw.prio17.q, 'hffffffff, 0))
-
-  // assertions for register: prio18
-  `ASSERT(prio18_wr_A, wr_P(10'h60, reg2hw.prio18.q, 1, 'h3, 0))
-  `ASSERT(prio18_rd_A, rd_P(10'h60, reg2hw.prio18.q, 'hffffffff, 0))
-
-  // assertions for register: prio19
-  `ASSERT(prio19_wr_A, wr_P(10'h64, reg2hw.prio19.q, 1, 'h3, 0))
-  `ASSERT(prio19_rd_A, rd_P(10'h64, reg2hw.prio19.q, 'hffffffff, 0))
-
-  // assertions for register: prio20
-  `ASSERT(prio20_wr_A, wr_P(10'h68, reg2hw.prio20.q, 1, 'h3, 0))
-  `ASSERT(prio20_rd_A, rd_P(10'h68, reg2hw.prio20.q, 'hffffffff, 0))
-
-  // assertions for register: prio21
-  `ASSERT(prio21_wr_A, wr_P(10'h6c, reg2hw.prio21.q, 1, 'h3, 0))
-  `ASSERT(prio21_rd_A, rd_P(10'h6c, reg2hw.prio21.q, 'hffffffff, 0))
-
-  // assertions for register: prio22
-  `ASSERT(prio22_wr_A, wr_P(10'h70, reg2hw.prio22.q, 1, 'h3, 0))
-  `ASSERT(prio22_rd_A, rd_P(10'h70, reg2hw.prio22.q, 'hffffffff, 0))
-
-  // assertions for register: prio23
-  `ASSERT(prio23_wr_A, wr_P(10'h74, reg2hw.prio23.q, 1, 'h3, 0))
-  `ASSERT(prio23_rd_A, rd_P(10'h74, reg2hw.prio23.q, 'hffffffff, 0))
-
-  // assertions for register: prio24
-  `ASSERT(prio24_wr_A, wr_P(10'h78, reg2hw.prio24.q, 1, 'h3, 0))
-  `ASSERT(prio24_rd_A, rd_P(10'h78, reg2hw.prio24.q, 'hffffffff, 0))
-
-  // assertions for register: prio25
-  `ASSERT(prio25_wr_A, wr_P(10'h7c, reg2hw.prio25.q, 1, 'h3, 0))
-  `ASSERT(prio25_rd_A, rd_P(10'h7c, reg2hw.prio25.q, 'hffffffff, 0))
-
-  // assertions for register: prio26
-  `ASSERT(prio26_wr_A, wr_P(10'h80, reg2hw.prio26.q, 1, 'h3, 0))
-  `ASSERT(prio26_rd_A, rd_P(10'h80, reg2hw.prio26.q, 'hffffffff, 0))
-
-  // assertions for register: prio27
-  `ASSERT(prio27_wr_A, wr_P(10'h84, reg2hw.prio27.q, 1, 'h3, 0))
-  `ASSERT(prio27_rd_A, rd_P(10'h84, reg2hw.prio27.q, 'hffffffff, 0))
-
-  // assertions for register: prio28
-  `ASSERT(prio28_wr_A, wr_P(10'h88, reg2hw.prio28.q, 1, 'h3, 0))
-  `ASSERT(prio28_rd_A, rd_P(10'h88, reg2hw.prio28.q, 'hffffffff, 0))
-
-  // assertions for register: prio29
-  `ASSERT(prio29_wr_A, wr_P(10'h8c, reg2hw.prio29.q, 1, 'h3, 0))
-  `ASSERT(prio29_rd_A, rd_P(10'h8c, reg2hw.prio29.q, 'hffffffff, 0))
-
-  // assertions for register: prio30
-  `ASSERT(prio30_wr_A, wr_P(10'h90, reg2hw.prio30.q, 1, 'h3, 0))
-  `ASSERT(prio30_rd_A, rd_P(10'h90, reg2hw.prio30.q, 'hffffffff, 0))
-
-  // assertions for register: prio31
-  `ASSERT(prio31_wr_A, wr_P(10'h94, reg2hw.prio31.q, 1, 'h3, 0))
-  `ASSERT(prio31_rd_A, rd_P(10'h94, reg2hw.prio31.q, 'hffffffff, 0))
-
-  // assertions for register: prio32
-  `ASSERT(prio32_wr_A, wr_P(10'h98, reg2hw.prio32.q, 1, 'h3, 0))
-  `ASSERT(prio32_rd_A, rd_P(10'h98, reg2hw.prio32.q, 'hffffffff, 0))
-
-  // assertions for register: prio33
-  `ASSERT(prio33_wr_A, wr_P(10'h9c, reg2hw.prio33.q, 1, 'h3, 0))
-  `ASSERT(prio33_rd_A, rd_P(10'h9c, reg2hw.prio33.q, 'hffffffff, 0))
-
-  // assertions for register: prio34
-  `ASSERT(prio34_wr_A, wr_P(10'ha0, reg2hw.prio34.q, 1, 'h3, 0))
-  `ASSERT(prio34_rd_A, rd_P(10'ha0, reg2hw.prio34.q, 'hffffffff, 0))
-
-  // assertions for register: prio35
-  `ASSERT(prio35_wr_A, wr_P(10'ha4, reg2hw.prio35.q, 1, 'h3, 0))
-  `ASSERT(prio35_rd_A, rd_P(10'ha4, reg2hw.prio35.q, 'hffffffff, 0))
-
-  // assertions for register: prio36
-  `ASSERT(prio36_wr_A, wr_P(10'ha8, reg2hw.prio36.q, 1, 'h3, 0))
-  `ASSERT(prio36_rd_A, rd_P(10'ha8, reg2hw.prio36.q, 'hffffffff, 0))
-
-  // assertions for register: prio37
-  `ASSERT(prio37_wr_A, wr_P(10'hac, reg2hw.prio37.q, 1, 'h3, 0))
-  `ASSERT(prio37_rd_A, rd_P(10'hac, reg2hw.prio37.q, 'hffffffff, 0))
-
-  // assertions for register: prio38
-  `ASSERT(prio38_wr_A, wr_P(10'hb0, reg2hw.prio38.q, 1, 'h3, 0))
-  `ASSERT(prio38_rd_A, rd_P(10'hb0, reg2hw.prio38.q, 'hffffffff, 0))
-
-  // assertions for register: prio39
-  `ASSERT(prio39_wr_A, wr_P(10'hb4, reg2hw.prio39.q, 1, 'h3, 0))
-  `ASSERT(prio39_rd_A, rd_P(10'hb4, reg2hw.prio39.q, 'hffffffff, 0))
-
-  // assertions for register: prio40
-  `ASSERT(prio40_wr_A, wr_P(10'hb8, reg2hw.prio40.q, 1, 'h3, 0))
-  `ASSERT(prio40_rd_A, rd_P(10'hb8, reg2hw.prio40.q, 'hffffffff, 0))
-
-  // assertions for register: prio41
-  `ASSERT(prio41_wr_A, wr_P(10'hbc, reg2hw.prio41.q, 1, 'h3, 0))
-  `ASSERT(prio41_rd_A, rd_P(10'hbc, reg2hw.prio41.q, 'hffffffff, 0))
-
-  // assertions for register: prio42
-  `ASSERT(prio42_wr_A, wr_P(10'hc0, reg2hw.prio42.q, 1, 'h3, 0))
-  `ASSERT(prio42_rd_A, rd_P(10'hc0, reg2hw.prio42.q, 'hffffffff, 0))
-
-  // assertions for register: prio43
-  `ASSERT(prio43_wr_A, wr_P(10'hc4, reg2hw.prio43.q, 1, 'h3, 0))
-  `ASSERT(prio43_rd_A, rd_P(10'hc4, reg2hw.prio43.q, 'hffffffff, 0))
-
-  // assertions for register: prio44
-  `ASSERT(prio44_wr_A, wr_P(10'hc8, reg2hw.prio44.q, 1, 'h3, 0))
-  `ASSERT(prio44_rd_A, rd_P(10'hc8, reg2hw.prio44.q, 'hffffffff, 0))
-
-  // assertions for register: prio45
-  `ASSERT(prio45_wr_A, wr_P(10'hcc, reg2hw.prio45.q, 1, 'h3, 0))
-  `ASSERT(prio45_rd_A, rd_P(10'hcc, reg2hw.prio45.q, 'hffffffff, 0))
-
-  // assertions for register: prio46
-  `ASSERT(prio46_wr_A, wr_P(10'hd0, reg2hw.prio46.q, 1, 'h3, 0))
-  `ASSERT(prio46_rd_A, rd_P(10'hd0, reg2hw.prio46.q, 'hffffffff, 0))
-
-  // assertions for register: prio47
-  `ASSERT(prio47_wr_A, wr_P(10'hd4, reg2hw.prio47.q, 1, 'h3, 0))
-  `ASSERT(prio47_rd_A, rd_P(10'hd4, reg2hw.prio47.q, 'hffffffff, 0))
-
-  // assertions for register: prio48
-  `ASSERT(prio48_wr_A, wr_P(10'hd8, reg2hw.prio48.q, 1, 'h3, 0))
-  `ASSERT(prio48_rd_A, rd_P(10'hd8, reg2hw.prio48.q, 'hffffffff, 0))
-
-  // assertions for register: prio49
-  `ASSERT(prio49_wr_A, wr_P(10'hdc, reg2hw.prio49.q, 1, 'h3, 0))
-  `ASSERT(prio49_rd_A, rd_P(10'hdc, reg2hw.prio49.q, 'hffffffff, 0))
-
-  // assertions for register: prio50
-  `ASSERT(prio50_wr_A, wr_P(10'he0, reg2hw.prio50.q, 1, 'h3, 0))
-  `ASSERT(prio50_rd_A, rd_P(10'he0, reg2hw.prio50.q, 'hffffffff, 0))
-
-  // assertions for register: prio51
-  `ASSERT(prio51_wr_A, wr_P(10'he4, reg2hw.prio51.q, 1, 'h3, 0))
-  `ASSERT(prio51_rd_A, rd_P(10'he4, reg2hw.prio51.q, 'hffffffff, 0))
-
-  // assertions for register: prio52
-  `ASSERT(prio52_wr_A, wr_P(10'he8, reg2hw.prio52.q, 1, 'h3, 0))
-  `ASSERT(prio52_rd_A, rd_P(10'he8, reg2hw.prio52.q, 'hffffffff, 0))
-
-  // assertions for register: prio53
-  `ASSERT(prio53_wr_A, wr_P(10'hec, reg2hw.prio53.q, 1, 'h3, 0))
-  `ASSERT(prio53_rd_A, rd_P(10'hec, reg2hw.prio53.q, 'hffffffff, 0))
-
-  // assertions for register: prio54
-  `ASSERT(prio54_wr_A, wr_P(10'hf0, reg2hw.prio54.q, 1, 'h3, 0))
-  `ASSERT(prio54_rd_A, rd_P(10'hf0, reg2hw.prio54.q, 'hffffffff, 0))
-
-  // assertions for register: prio55
-  `ASSERT(prio55_wr_A, wr_P(10'hf4, reg2hw.prio55.q, 1, 'h3, 0))
-  `ASSERT(prio55_rd_A, rd_P(10'hf4, reg2hw.prio55.q, 'hffffffff, 0))
-
-  // assertions for register: prio56
-  `ASSERT(prio56_wr_A, wr_P(10'hf8, reg2hw.prio56.q, 1, 'h3, 0))
-  `ASSERT(prio56_rd_A, rd_P(10'hf8, reg2hw.prio56.q, 'hffffffff, 0))
-
-  // assertions for register: prio57
-  `ASSERT(prio57_wr_A, wr_P(10'hfc, reg2hw.prio57.q, 1, 'h3, 0))
-  `ASSERT(prio57_rd_A, rd_P(10'hfc, reg2hw.prio57.q, 'hffffffff, 0))
-
-  // assertions for register: prio58
-  `ASSERT(prio58_wr_A, wr_P(10'h100, reg2hw.prio58.q, 1, 'h3, 0))
-  `ASSERT(prio58_rd_A, rd_P(10'h100, reg2hw.prio58.q, 'hffffffff, 0))
-
-  // assertions for register: prio59
-  `ASSERT(prio59_wr_A, wr_P(10'h104, reg2hw.prio59.q, 1, 'h3, 0))
-  `ASSERT(prio59_rd_A, rd_P(10'h104, reg2hw.prio59.q, 'hffffffff, 0))
-
-  // assertions for register: prio60
-  `ASSERT(prio60_wr_A, wr_P(10'h108, reg2hw.prio60.q, 1, 'h3, 0))
-  `ASSERT(prio60_rd_A, rd_P(10'h108, reg2hw.prio60.q, 'hffffffff, 0))
-
-  // assertions for register: prio61
-  `ASSERT(prio61_wr_A, wr_P(10'h10c, reg2hw.prio61.q, 1, 'h3, 0))
-  `ASSERT(prio61_rd_A, rd_P(10'h10c, reg2hw.prio61.q, 'hffffffff, 0))
-
-  // assertions for register: prio62
-  `ASSERT(prio62_wr_A, wr_P(10'h110, reg2hw.prio62.q, 1, 'h3, 0))
-  `ASSERT(prio62_rd_A, rd_P(10'h110, reg2hw.prio62.q, 'hffffffff, 0))
-
-  // assertions for register: prio63
-  `ASSERT(prio63_wr_A, wr_P(10'h114, reg2hw.prio63.q, 1, 'h3, 0))
-  `ASSERT(prio63_rd_A, rd_P(10'h114, reg2hw.prio63.q, 'hffffffff, 0))
-
-  // assertions for register: prio64
-  `ASSERT(prio64_wr_A, wr_P(10'h118, reg2hw.prio64.q, 1, 'h3, 0))
-  `ASSERT(prio64_rd_A, rd_P(10'h118, reg2hw.prio64.q, 'hffffffff, 0))
-
-  // assertions for register: prio65
-  `ASSERT(prio65_wr_A, wr_P(10'h11c, reg2hw.prio65.q, 1, 'h3, 0))
-  `ASSERT(prio65_rd_A, rd_P(10'h11c, reg2hw.prio65.q, 'hffffffff, 0))
-
-  // assertions for register: prio66
-  `ASSERT(prio66_wr_A, wr_P(10'h120, reg2hw.prio66.q, 1, 'h3, 0))
-  `ASSERT(prio66_rd_A, rd_P(10'h120, reg2hw.prio66.q, 'hffffffff, 0))
-
-  // assertions for register: prio67
-  `ASSERT(prio67_wr_A, wr_P(10'h124, reg2hw.prio67.q, 1, 'h3, 0))
-  `ASSERT(prio67_rd_A, rd_P(10'h124, reg2hw.prio67.q, 'hffffffff, 0))
-
-  // assertions for register: prio68
-  `ASSERT(prio68_wr_A, wr_P(10'h128, reg2hw.prio68.q, 1, 'h3, 0))
-  `ASSERT(prio68_rd_A, rd_P(10'h128, reg2hw.prio68.q, 'hffffffff, 0))
-
-  // assertions for register: prio69
-  `ASSERT(prio69_wr_A, wr_P(10'h12c, reg2hw.prio69.q, 1, 'h3, 0))
-  `ASSERT(prio69_rd_A, rd_P(10'h12c, reg2hw.prio69.q, 'hffffffff, 0))
-
-  // assertions for register: prio70
-  `ASSERT(prio70_wr_A, wr_P(10'h130, reg2hw.prio70.q, 1, 'h3, 0))
-  `ASSERT(prio70_rd_A, rd_P(10'h130, reg2hw.prio70.q, 'hffffffff, 0))
-
-  // assertions for register: prio71
-  `ASSERT(prio71_wr_A, wr_P(10'h134, reg2hw.prio71.q, 1, 'h3, 0))
-  `ASSERT(prio71_rd_A, rd_P(10'h134, reg2hw.prio71.q, 'hffffffff, 0))
-
-  // assertions for register: prio72
-  `ASSERT(prio72_wr_A, wr_P(10'h138, reg2hw.prio72.q, 1, 'h3, 0))
-  `ASSERT(prio72_rd_A, rd_P(10'h138, reg2hw.prio72.q, 'hffffffff, 0))
-
-  // assertions for register: prio73
-  `ASSERT(prio73_wr_A, wr_P(10'h13c, reg2hw.prio73.q, 1, 'h3, 0))
-  `ASSERT(prio73_rd_A, rd_P(10'h13c, reg2hw.prio73.q, 'hffffffff, 0))
-
-  // assertions for register: prio74
-  `ASSERT(prio74_wr_A, wr_P(10'h140, reg2hw.prio74.q, 1, 'h3, 0))
-  `ASSERT(prio74_rd_A, rd_P(10'h140, reg2hw.prio74.q, 'hffffffff, 0))
-
-  // assertions for register: prio75
-  `ASSERT(prio75_wr_A, wr_P(10'h144, reg2hw.prio75.q, 1, 'h3, 0))
-  `ASSERT(prio75_rd_A, rd_P(10'h144, reg2hw.prio75.q, 'hffffffff, 0))
-
-  // assertions for register: prio76
-  `ASSERT(prio76_wr_A, wr_P(10'h148, reg2hw.prio76.q, 1, 'h3, 0))
-  `ASSERT(prio76_rd_A, rd_P(10'h148, reg2hw.prio76.q, 'hffffffff, 0))
-
-  // assertions for register: prio77
-  `ASSERT(prio77_wr_A, wr_P(10'h14c, reg2hw.prio77.q, 1, 'h3, 0))
-  `ASSERT(prio77_rd_A, rd_P(10'h14c, reg2hw.prio77.q, 'hffffffff, 0))
-
-  // assertions for register: prio78
-  `ASSERT(prio78_wr_A, wr_P(10'h150, reg2hw.prio78.q, 1, 'h3, 0))
-  `ASSERT(prio78_rd_A, rd_P(10'h150, reg2hw.prio78.q, 'hffffffff, 0))
-
-  // assertions for register: prio79
-  `ASSERT(prio79_wr_A, wr_P(10'h154, reg2hw.prio79.q, 1, 'h3, 0))
-  `ASSERT(prio79_rd_A, rd_P(10'h154, reg2hw.prio79.q, 'hffffffff, 0))
-
-  // assertions for register: prio80
-  `ASSERT(prio80_wr_A, wr_P(10'h158, reg2hw.prio80.q, 1, 'h3, 0))
-  `ASSERT(prio80_rd_A, rd_P(10'h158, reg2hw.prio80.q, 'hffffffff, 0))
-
-  // assertions for register: prio81
-  `ASSERT(prio81_wr_A, wr_P(10'h15c, reg2hw.prio81.q, 1, 'h3, 0))
-  `ASSERT(prio81_rd_A, rd_P(10'h15c, reg2hw.prio81.q, 'hffffffff, 0))
-
-  // assertions for register: prio82
-  `ASSERT(prio82_wr_A, wr_P(10'h160, reg2hw.prio82.q, 1, 'h3, 0))
-  `ASSERT(prio82_rd_A, rd_P(10'h160, reg2hw.prio82.q, 'hffffffff, 0))
-
-  // define local fpv variable for multi-reg
-  logic [82:0] ie0_q_fpv;
-  for (genvar s = 0; s < 83; s++) begin : gen_ie0_q
-    assign ie0_q_fpv[((s+1)*1-1):s*1] = reg2hw.ie0[s].q;
-  end
-
-  // assertions for register: ie00
-  `ASSERT(ie00_wr_A, wr_P(10'h200, ie0_q_fpv[31:0], 1, 'hffffffff, 0))
-  `ASSERT(ie00_rd_A, rd_P(10'h200, ie0_q_fpv[31:0], 'hffffffff, 0))
-  // assertions for register: ie01
-  `ASSERT(ie01_wr_A, wr_P(10'h204, ie0_q_fpv[63:32], 1, 'hffffffff, 0))
-  `ASSERT(ie01_rd_A, rd_P(10'h204, ie0_q_fpv[63:32], 'hffffffff, 0))
-  // assertions for register: ie02
-  `ASSERT(ie02_wr_A, wr_P(10'h208, ie0_q_fpv[82:64], 1, 'h7ffff, 0))
-  `ASSERT(ie02_rd_A, rd_P(10'h208, ie0_q_fpv[82:64], 'h7ffff, 0))
-
-  // assertions for register: threshold0
-  `ASSERT(threshold0_wr_A, wr_P(10'h20c, reg2hw.threshold0.q, 1, 'h3, 0))
-  `ASSERT(threshold0_rd_A, rd_P(10'h20c, reg2hw.threshold0.q, 'hffffffff, 0))
-
-  // assertions for register: cc0
-  `ASSERT(cc0_wr_A, wr_ext_P(10'h210, reg2hw.cc0.q, 1, 'h7f, 0))
-  `ASSERT(cc0_rd_A, rd_ext_P(10'h210, hw2reg.cc0.d, 'hffffffff, 0))
-
-  // assertions for register: msip0
-  `ASSERT(msip0_wr_A, wr_P(10'h214, reg2hw.msip0.q, 1, 'h1, 0))
-  `ASSERT(msip0_rd_A, rd_P(10'h214, reg2hw.msip0.q, 'hffffffff, 0))
-
-
-endmodule
diff --git a/hw/top_earlgrey/ip/rv_plic/fpv/autogen/rv_plic_fpv.core b/hw/top_earlgrey/ip/rv_plic/fpv/autogen/rv_plic_fpv.core
index fd5c59f..507e02d 100644
--- a/hw/top_earlgrey/ip/rv_plic/fpv/autogen/rv_plic_fpv.core
+++ b/hw/top_earlgrey/ip/rv_plic/fpv/autogen/rv_plic_fpv.core
@@ -10,12 +10,19 @@
     depend:
       - lowrisc:fpv:rv_plic_component_fpv
       - lowrisc:top_earlgrey:rv_plic
+      - lowrisc:fpv:csr_assert_gen
     files:
-      - rv_plic_csr_assert_fpv.sv
       - rv_plic_bind_fpv.sv
       - rv_plic_fpv.sv
     file_type: systemVerilogSource
 
+generate:
+  csr_assert_gen:
+    generator: csr_assert_gen
+    parameters:
+      spec: ../../data/autogen/rv_plic.hjson
+      depend: lowrisc:top_earlgrey:rv_plic
+
 targets:
   default: &default_target
     # note, this setting is just used
@@ -23,6 +30,8 @@
     default_tool: icarus
     filesets:
       - files_formal
+    generate:
+      - csr_assert_gen
     toplevel: rv_plic_fpv
 
   formal:
diff --git a/util/fpvgen/fusesoc.core.tpl b/util/fpvgen/fusesoc.core.tpl
index 5778dea..5f64dda 100644
--- a/util/fpvgen/fusesoc.core.tpl
+++ b/util/fpvgen/fusesoc.core.tpl
@@ -9,17 +9,26 @@
     depend:
 % for dep in dut.deps:
       - ${dep}
+  % if dut.is_cip:
+      - lowrisc:fpv:csr_assert_gen
+  % endif
 % endfor
       # TODO: add more dependencies here if needed
     files:
       - vip/${dut.name}_assert_fpv.sv
       - tb/${dut.name}_bind_fpv.sv
       - tb/${dut.name}_fpv.sv
-% if dut.is_cip:
-      - vip/${dut.name}_csr_assert_fpv.sv
-% endif
     file_type: systemVerilogSource
 
+% if dut.is_cip:
+generate:
+  csr_assert_gen:
+    generator: csr_assert_gen
+    parameters:
+      spec: ../data/${dut_name}.hjson
+      depend: lowrisc:ip:${dut_name}
+% endif
+
 targets:
   default: &default_target
     # note, this setting is just used
@@ -27,6 +36,10 @@
     default_tool: icarus
     filesets:
       - files_formal
+% if dut.is_cip:
+    generate:
+      - csr_assert_gen
+% endif
     toplevel: ${dut.name}_fpv
 
   formal:
diff --git a/util/topgen.py b/util/topgen.py
index e2651c2..01d2ec8 100755
--- a/util/topgen.py
+++ b/util/topgen.py
@@ -17,7 +17,7 @@
 from mako.template import Template
 
 import tlgen
-from reggen import gen_dv, gen_fpv, gen_rtl, validate
+from reggen import gen_dv, gen_rtl, validate
 from topgen import (amend_clocks, get_hjsonobj_xbars, merge_top, search_ips,
                     validate_top)
 
@@ -260,7 +260,6 @@
                             object_pairs_hook=OrderedDict)
     validate.validate(hjson_obj)
     gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
-    gen_fpv.gen_fpv(hjson_obj, str(fpv_path))
 
     # Generate RV_PLIC Top Module
     with rtl_tpl_path.open(mode='r', encoding='UTF-8') as fin: