@@ -10,7 +10,10 @@ interface core_ibex_pmp_fcov_if import ibex_pkg::*; #(
10
10
// 0 = No restriction, 1 = 8 byte, 2 = 16 byte, 3 = 32 byte, etc.
11
11
parameter int unsigned PMPGranularity = 0 ,
12
12
// Number of implemented regions
13
- parameter int unsigned PMPNumRegions = 4
13
+ parameter int unsigned PMPNumRegions = 4 ,
14
+ // Debug Module Address Space
15
+ parameter int unsigned DmBaseAddr = 32'h1A110000 ,
16
+ parameter int unsigned DmAddrMask = 32'h00000FFF
14
17
) (
15
18
input clk_i,
16
19
input rst_ni,
@@ -20,6 +23,8 @@ interface core_ibex_pmp_fcov_if import ibex_pkg::*; #(
20
23
input logic pmp_req_err [3 ],
21
24
input pmp_mseccfg_t csr_pmp_mseccfg,
22
25
26
+ input logic debug_mode,
27
+
23
28
input logic data_req_out,
24
29
25
30
input fcov_csr_write
@@ -97,6 +102,8 @@ interface core_ibex_pmp_fcov_if import ibex_pkg::*; #(
97
102
end
98
103
99
104
if (PMPEnable) begin : g_pmp_cgs
105
+ logic [PMPNumChan- 1 : 0 ] fcov_access_attempted_into_dm;
106
+
100
107
logic [PMPNumRegions- 1 : 0 ] pmp_iside_match;
101
108
logic [PMPNumRegions- 1 : 0 ] pmp_iside2_match;
102
109
logic [PMPNumRegions- 1 : 0 ] pmp_dside_match;
@@ -136,6 +143,14 @@ interface core_ibex_pmp_fcov_if import ibex_pkg::*; #(
136
143
assign pmp_dside_boundary_cross = | (pmp_dside_match ^ pmp_dside_match_last) &
137
144
load_store_unit_i.fcov_ls_second_req;
138
145
146
+ logic pmp_iside_access_fault_check;
147
+ logic pmp_iside2_access_fault_check;
148
+ logic pmp_dside_access_fault_check;
149
+
150
+ assign pmp_iside_access_fault_check = g_pmp.pmp_i.access_fault_check_res[PMP_I ];
151
+ assign pmp_iside2_access_fault_check = g_pmp.pmp_i.access_fault_check_res[PMP_I2 ];
152
+ assign pmp_dside_access_fault_check = g_pmp.pmp_i.access_fault_check_res[PMP_D ];
153
+
139
154
for (genvar i_region = 0 ; i_region < PMPNumRegions; i_region + = 1 ) begin : g_pmp_region_fcov
140
155
pmp_priv_bits_e pmp_region_priv_bits;
141
156
pmp_priv_bits_e pmp_region_priv_bits_wr;
@@ -237,7 +252,8 @@ interface core_ibex_pmp_fcov_if import ibex_pkg::*; #(
237
252
cross cp_region_priv_bits, cp_req_type_iside, cp_priv_lvl_iside, pmp_iside_req_err
238
253
iff (g_pmp_fcov_signals.g_pmp_region_fcov[i_region].fcov_pmp_region_ichan_access &&
239
254
g_pmp_fcov_signals.fcov_pmp_region_ichan_priority[i_region] &&
240
- csr_pmp_cfg[i_region].mode != PMP_MODE_OFF ) {
255
+ csr_pmp_cfg[i_region].mode != PMP_MODE_OFF &&
256
+ ! (fcov_access_attempted_into_dm[PMP_I ])) {
241
257
242
258
// Will never see a succesful exec access when execute is disallowed
243
259
illegal_bins illegal_allow_exec =
@@ -294,7 +310,8 @@ interface core_ibex_pmp_fcov_if import ibex_pkg::*; #(
294
310
cross cp_region_priv_bits, cp_req_type_iside2, cp_priv_lvl_iside2, pmp_iside2_req_err
295
311
iff (g_pmp_fcov_signals.g_pmp_region_fcov[i_region].fcov_pmp_region_ichan2_access &&
296
312
g_pmp_fcov_signals.fcov_pmp_region_ichan2_priority[i_region] &&
297
- csr_pmp_cfg[i_region].mode != PMP_MODE_OFF ) {
313
+ csr_pmp_cfg[i_region].mode != PMP_MODE_OFF &&
314
+ ! (fcov_access_attempted_into_dm[PMP_I2 ])) {
298
315
299
316
// Will never see a succesful exec access when execute is disallowed
300
317
illegal_bins illegal_allow_exec =
@@ -351,7 +368,8 @@ interface core_ibex_pmp_fcov_if import ibex_pkg::*; #(
351
368
cross cp_region_priv_bits, cp_req_type_dside, cp_priv_lvl_dside, pmp_dside_req_err
352
369
iff (g_pmp_fcov_signals.g_pmp_region_fcov[i_region].fcov_pmp_region_dchan_access &&
353
370
g_pmp_fcov_signals.fcov_pmp_region_dchan_priority[i_region] &&
354
- csr_pmp_cfg[i_region].mode != PMP_MODE_OFF ) {
371
+ csr_pmp_cfg[i_region].mode != PMP_MODE_OFF &&
372
+ ! (fcov_access_attempted_into_dm[PMP_D ])) {
355
373
356
374
// Will never see a succesful read access when read is disallowed
357
375
illegal_bins illegal_allow_read =
@@ -498,6 +516,22 @@ interface core_ibex_pmp_fcov_if import ibex_pkg::*; #(
498
516
cs_registers_i.priv_mode_id_o,
499
517
current_priv_perm_check);
500
518
519
+ // Create a signal 'fcov_access_attempted_into_dm' for each PMP channel, which becomes true at
520
+ // the point when a memory access into the debug_module address space via that channel is
521
+ // accesses-checked by its PMP unit. If true we know that the current instruction at least
522
+ // attempted to make an access, and we can then cross this signal with the result of the pmp
523
+ // check and the current debug_mode state to capture all appropriate coverage.
524
+ logic [PMPNumChan- 1 : 0 ] access_check_into_dm;
525
+ for (genvar c = 0 ; c < PMPNumChan; c++ ) begin : g_pmp_channel_access_check
526
+ assign access_check_into_dm[c] = (g_pmp.pmp_req_addr[c][31 : 0 ] & ~ DmAddrMask) == DmBaseAddr;
527
+ end
528
+ assign fcov_access_attempted_into_dm[PMP_I ] =
529
+ access_check_into_dm[PMP_D ] & data_req_out;
530
+ assign fcov_access_attempted_into_dm[PMP_I2 ] =
531
+ access_check_into_dm[PMP_I2 ] & if_stage_i.if_id_pipe_reg_we;
532
+ assign fcov_access_attempted_into_dm[PMP_D ] =
533
+ access_check_into_dm[PMP_I ] & if_stage_i.if_id_pipe_reg_we;
534
+
501
535
covergroup pmp_top_cg @ (posedge clk_i);
502
536
option .per_instance = 1 ;
503
537
option .name = " pmp_top_cg" ;
@@ -709,6 +743,109 @@ interface core_ibex_pmp_fcov_if import ibex_pkg::*; #(
709
743
misaligned_lsu_access_cross : cross misaligned_pmp_err_last,
710
744
load_store_unit_i.fcov_ls_mis_pmp_err_2
711
745
iff (pmp_dside_boundary_cross);
746
+
747
+ // Debug Module Accesses
748
+
749
+ // Coverpoints that we have attempted to access the debug module address range
750
+ //
751
+ // The riscv-dbg module states the following:
752
+ // > riscv-dbg/doc/debug-system.md (# Debug Memory)
753
+ // > The Debug Memory should only be accessible from the CPU if it is in debug mode.
754
+ // However, The RISC-V Debug Specification does not mandate this. Bins for accesses in normal
755
+ // mode are ignored for the purpose of this coverage.
756
+
757
+ dm_fetch_iside_debug_mode_cp : coverpoint debug_mode
758
+ iff (fcov_access_attempted_into_dm[PMP_I ])
759
+ {
760
+ bins dm_debug_mode_fetch = { 1'b1 } ;
761
+ // We shouldn't be fetching from the debug module unless in debug mode.
762
+ ignore_bins dm_normal_mode_fetch = { 1'b0 } ;
763
+ }
764
+ dm_fetch_iside2_debug_mode_cp : coverpoint debug_mode
765
+ iff (fcov_access_attempted_into_dm[PMP_I2 ])
766
+ {
767
+ bins dm_debug_mode_fetch = { 1'b1 } ;
768
+ // We shouldn't be fetching from the debug module unless in debug mode.
769
+ ignore_bins dm_normal_mode_fetch = { 1'b0 } ;
770
+ }
771
+ dm_load_store_debug_mode_cp : coverpoint debug_mode
772
+ iff (fcov_access_attempted_into_dm[PMP_D ])
773
+ {
774
+ bins dm_debug_mode_load_store = { 1'b1 } ;
775
+ // We shouldn't be loading/storing from/to the debug module unless in debug mode.
776
+ ignore_bins dm_normal_mode_load_store = { 1'b0 } ;
777
+ }
778
+
779
+ cp_ls_pmp_exception : coverpoint load_store_unit_i.fcov_ls_pmp_exception;
780
+
781
+ // Cross access attempts with the result of the access check
782
+
783
+ dm_fetch_access_iside_cross: cross
784
+ dm_fetch_iside_debug_mode_cp,
785
+ pmp_iside_req_err,
786
+ pmp_iside_access_fault_check
787
+ {
788
+ // Fetches should never fail the access check in debug mode
789
+ // This behaviour is checked via cosimulation.
790
+ illegal_bins dm_debug_mode_disallowed_fetch =
791
+ binsof (pmp_iside_req_err) intersect { 1'b1 } &&
792
+ binsof (dm_fetch_iside_debug_mode_cp) intersect { 1'b1 } ;
793
+
794
+ // Allowed fetches in debug mode may or may not override a denying PMP region.
795
+ // Create a bin for each possibility.
796
+ bins dm_debug_mode_pmp_allow_fetch_allowed =
797
+ binsof (dm_fetch_iside_debug_mode_cp) intersect { 1'b1 } &&
798
+ binsof (pmp_iside_access_fault_check) intersect { 1'b0 } &&
799
+ binsof (pmp_iside_req_err) intersect { 1'b0 } ;
800
+ bins dm_debug_mode_pmp_deny_fetch_allowed =
801
+ binsof (dm_fetch_iside_debug_mode_cp) intersect { 1'b1 } &&
802
+ binsof (pmp_iside_access_fault_check) intersect { 1'b1 } &&
803
+ binsof (pmp_iside_req_err) intersect { 1'b0 } ;
804
+ }
805
+
806
+ dm_fetch_access_iside2_cross: cross
807
+ dm_fetch_iside2_debug_mode_cp,
808
+ pmp_iside2_req_err,
809
+ pmp_iside2_access_fault_check
810
+ {
811
+ // Fetches should never fail the access check in debug mode
812
+ illegal_bins dm_debug_mode_disallowed_fetch =
813
+ binsof (pmp_iside2_req_err) intersect { 1'b1 } &&
814
+ binsof (dm_fetch_iside2_debug_mode_cp) intersect { 1'b1 } ;
815
+
816
+ // Allowed fetches in debug mode may or may not override a denying PMP region.
817
+ // Create a bin for each possibility.
818
+ bins dm_debug_mode_pmp_allow_fetch_allowed =
819
+ binsof (dm_fetch_iside2_debug_mode_cp) intersect { 1'b1 } &&
820
+ binsof (pmp_iside2_access_fault_check) intersect { 1'b0 } &&
821
+ binsof (pmp_iside2_req_err) intersect { 1'b0 } ;
822
+ bins dm_debug_mode_pmp_deny_fetch_allowed =
823
+ binsof (dm_fetch_iside2_debug_mode_cp) intersect { 1'b1 } &&
824
+ binsof (pmp_iside2_access_fault_check) intersect { 1'b1 } &&
825
+ binsof (pmp_iside2_req_err) intersect { 1'b0 } ;
826
+ }
827
+
828
+ dm_load_store_access_cross: cross
829
+ dm_load_store_debug_mode_cp,
830
+ cp_ls_pmp_exception,
831
+ pmp_dside_access_fault_check
832
+ {
833
+ // Loads/Stores should never fail the access check in debug mode
834
+ illegal_bins dm_debug_mode_disallowed_load_store =
835
+ binsof (cp_ls_pmp_exception) intersect { 1'b1 } &&
836
+ binsof (dm_load_store_debug_mode_cp) intersect { 1'b1 } ;
837
+
838
+ // Allowed loads/stores in debug mode may or may not override a denying PMP region.
839
+ // Create a bin for each possibility.
840
+ bins dm_debug_mode_pmp_allow_allowed_load_store =
841
+ binsof (dm_load_store_debug_mode_cp) intersect { 1'b1 } &&
842
+ binsof (pmp_dside_access_fault_check) intersect { 1'b1 } &&
843
+ binsof (cp_ls_pmp_exception) intersect { 1'b0 } ;
844
+ bins dm_debug_mode_pmp_deny_allowed_load_store =
845
+ binsof (dm_load_store_debug_mode_cp) intersect { 1'b1 } &&
846
+ binsof (pmp_dside_access_fault_check) intersect { 1'b0 } &&
847
+ binsof (cp_ls_pmp_exception) intersect { 1'b0 } ;
848
+ }
712
849
endgroup
713
850
714
851
`DV_FCOV_INSTANTIATE_CG (pmp_top_cg, en_pmp_fcov)
0 commit comments