Skip to content

Commit bd8466d

Browse files
[fcov] Add fcov for the interaction of pmp with debug module accesses
Accesses to the debug module in debug mode should never be denied by the PMP unit. This commit implements fcov to confirm we have stimulated this particular behaviour in relevant related states. Illegal bins are used for incorrect behaviour (e.g. denied access in debug mode) Other behaviours such as debug module accesses outside of debug mode are left as ignore_bins for now. This is not explicitly disallowed by the specification, and our implementation does not have any opinion about its validity, but external debug modules opine that it should not be allowed. We could possibly expand the stimulus in the future to test this condition, but it is low priority.
1 parent 51573f9 commit bd8466d

File tree

2 files changed

+143
-6
lines changed

2 files changed

+143
-6
lines changed

dv/uvm/core_ibex/fcov/core_ibex_fcov_bind.sv

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ module core_ibex_fcov_bind;
1010
bind ibex_core core_ibex_pmp_fcov_if
1111
#(.PMPGranularity(PMPGranularity),
1212
.PMPNumRegions(PMPNumRegions),
13-
.PMPEnable(PMPEnable))
14-
u_pmp_fcov_bind (
13+
.PMPEnable(PMPEnable)
14+
) u_pmp_fcov_bind (
1515
.*
1616
);
1717
endmodule

dv/uvm/core_ibex/fcov/core_ibex_pmp_fcov_if.sv

Lines changed: 141 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ interface core_ibex_pmp_fcov_if import ibex_pkg::*; #(
1010
// 0 = No restriction, 1 = 8 byte, 2 = 16 byte, 3 = 32 byte, etc.
1111
parameter int unsigned PMPGranularity = 0,
1212
// 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
1417
) (
1518
input clk_i,
1619
input rst_ni,
@@ -20,6 +23,8 @@ interface core_ibex_pmp_fcov_if import ibex_pkg::*; #(
2023
input logic pmp_req_err [3],
2124
input pmp_mseccfg_t csr_pmp_mseccfg,
2225

26+
input logic debug_mode,
27+
2328
input logic data_req_out,
2429

2530
input fcov_csr_write
@@ -97,6 +102,8 @@ interface core_ibex_pmp_fcov_if import ibex_pkg::*; #(
97102
end
98103

99104
if (PMPEnable) begin : g_pmp_cgs
105+
logic [PMPNumChan-1:0] fcov_access_attempted_into_dm;
106+
100107
logic [PMPNumRegions-1:0] pmp_iside_match;
101108
logic [PMPNumRegions-1:0] pmp_iside2_match;
102109
logic [PMPNumRegions-1:0] pmp_dside_match;
@@ -136,6 +143,14 @@ interface core_ibex_pmp_fcov_if import ibex_pkg::*; #(
136143
assign pmp_dside_boundary_cross = |(pmp_dside_match ^ pmp_dside_match_last) &
137144
load_store_unit_i.fcov_ls_second_req;
138145

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+
139154
for (genvar i_region = 0; i_region < PMPNumRegions; i_region += 1) begin : g_pmp_region_fcov
140155
pmp_priv_bits_e pmp_region_priv_bits;
141156
pmp_priv_bits_e pmp_region_priv_bits_wr;
@@ -237,7 +252,8 @@ interface core_ibex_pmp_fcov_if import ibex_pkg::*; #(
237252
cross cp_region_priv_bits, cp_req_type_iside, cp_priv_lvl_iside, pmp_iside_req_err
238253
iff (g_pmp_fcov_signals.g_pmp_region_fcov[i_region].fcov_pmp_region_ichan_access &&
239254
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])) {
241257

242258
// Will never see a succesful exec access when execute is disallowed
243259
illegal_bins illegal_allow_exec =
@@ -294,7 +310,8 @@ interface core_ibex_pmp_fcov_if import ibex_pkg::*; #(
294310
cross cp_region_priv_bits, cp_req_type_iside2, cp_priv_lvl_iside2, pmp_iside2_req_err
295311
iff (g_pmp_fcov_signals.g_pmp_region_fcov[i_region].fcov_pmp_region_ichan2_access &&
296312
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])) {
298315

299316
// Will never see a succesful exec access when execute is disallowed
300317
illegal_bins illegal_allow_exec =
@@ -351,7 +368,8 @@ interface core_ibex_pmp_fcov_if import ibex_pkg::*; #(
351368
cross cp_region_priv_bits, cp_req_type_dside, cp_priv_lvl_dside, pmp_dside_req_err
352369
iff (g_pmp_fcov_signals.g_pmp_region_fcov[i_region].fcov_pmp_region_dchan_access &&
353370
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])) {
355373

356374
// Will never see a succesful read access when read is disallowed
357375
illegal_bins illegal_allow_read =
@@ -498,6 +516,22 @@ interface core_ibex_pmp_fcov_if import ibex_pkg::*; #(
498516
cs_registers_i.priv_mode_id_o,
499517
current_priv_perm_check);
500518

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+
501535
covergroup pmp_top_cg @(posedge clk_i);
502536
option.per_instance = 1;
503537
option.name = "pmp_top_cg";
@@ -709,6 +743,109 @@ interface core_ibex_pmp_fcov_if import ibex_pkg::*; #(
709743
misaligned_lsu_access_cross: cross misaligned_pmp_err_last,
710744
load_store_unit_i.fcov_ls_mis_pmp_err_2
711745
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+
}
712849
endgroup
713850

714851
`DV_FCOV_INSTANTIATE_CG(pmp_top_cg, en_pmp_fcov)

0 commit comments

Comments
 (0)