[fpv/csr] Check d_error when addr is OOB

This PR checks if d_error is asserted when the address is OOB.

Signed-off-by: Cindy Chen <chencindy@opentitan.org>
diff --git a/hw/ip/rstmgr/dv/sva/rstmgr_sva.core b/hw/ip/rstmgr/dv/sva/rstmgr_sva.core
index 2468483..3562643 100644
--- a/hw/ip/rstmgr/dv/sva/rstmgr_sva.core
+++ b/hw/ip/rstmgr/dv/sva/rstmgr_sva.core
@@ -24,7 +24,7 @@
   csr_assert_gen:
     generator: csr_assert_gen
     parameters:
-      spec: ../../data/rstmgr.hjson
+      spec: ../../../../top_earlgrey/ip/rstmgr/data/autogen/rstmgr.hjson
 
 targets:
   default: &default_target
diff --git a/util/reggen/fpv_csr.sv.tpl b/util/reggen/fpv_csr.sv.tpl
index b2dcd40..7058d66 100644
--- a/util/reggen/fpv_csr.sv.tpl
+++ b/util/reggen/fpv_csr.sv.tpl
@@ -47,6 +47,8 @@
   hro_regs_list = [r for r in rb.flat_regs if (not r.is_hw_writable() and not r.shadowed)]
   num_hro_regs = len(hro_regs_list)
   hro_map = {r.offset: (idx, r) for idx, r in enumerate(hro_regs_list)}
+  max_reg_addr = rb.flat_regs[-1].offset
+  windows = rb.windows
 %>\
 
 // Currently FPV csr assertion only support HRO registers.
@@ -54,6 +56,8 @@
 `ifndef VERILATOR
 `ifndef SYNTHESIS
 
+  logic oob_addr_err;
+
   parameter bit[3:0] MAX_A_SOURCE = 10; // used for FPV only to reduce runtime
 
   typedef struct packed {
@@ -124,6 +128,7 @@
   // for write HRO registers, store the write data into exp_vals
   always_ff @(negedge clk_i or negedge rst_ni) begin
     if (!rst_ni) begin
+       oob_addr_err <= 1'b0;
        pend_trans <= '0;
   % for hro_reg in hro_regs_list:
        exp_vals[${hro_map.get(hro_reg.offset)[0]}] <= 'h${f'{hro_reg.resval:0x}'};
@@ -134,13 +139,22 @@
       % endif
   % endfor
     end else begin
+      oob_addr_err <= 1'b0;
       if (h2d.a_valid && d2h.a_ready) begin
-        pend_trans[h2d.a_source].addr <= normalized_addr;
-        if (h2d.a_opcode inside {PutFullData, PutPartialData}) begin
-          pend_trans[h2d.a_source].wr_data <= h2d.a_data & a_mask_bit;
-          pend_trans[h2d.a_source].wr_pending <= 1'b1;
-        end else if (h2d.a_opcode == Get) begin
-          pend_trans[h2d.a_source].rd_pending <= 1'b1;
+        if ((normalized_addr inside {[0:${max_reg_addr}]})
+ % for window in windows:
+            || (normalized_addr inside {[${window.offset}: (${window.offset}+${window.items}*8)]})
+ % endfor
+           ) begin
+          pend_trans[h2d.a_source].addr <= normalized_addr;
+          if (h2d.a_opcode inside {PutFullData, PutPartialData}) begin
+            pend_trans[h2d.a_source].wr_data <= h2d.a_data & a_mask_bit;
+            pend_trans[h2d.a_source].wr_pending <= 1'b1;
+          end else if (h2d.a_opcode == Get) begin
+            pend_trans[h2d.a_source].rd_pending <= 1'b1;
+          end
+        end else begin
+          oob_addr_err <= 1'b1;
         end
       end
       if (d2h.d_valid) begin
@@ -187,6 +201,8 @@
   % endfor
 % endif
 
+  `ASSERT(TlulOOBAddrErr_A, oob_addr_err |-> s_eventually(d2h.d_valid && d2h.d_error))
+
   // This FPV only assumption is to reduce the FPV runtime.
   `ASSUME_FPV(TlulSource_M, h2d.a_source >=  0 && h2d.a_source <= MAX_A_SOURCE, clk_i, !rst_ni)