blob: 417246dabcc2c1dacdc5db182ed7254f3d54b6ba [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Implements functional coverage for csrng.
interface csrng_cov_if (
input logic clk_i
);
import uvm_pkg::*;
import dv_utils_pkg::*;
import csrng_pkg::*;
import csrng_agent_pkg::*;
import csrng_env_pkg::*;
import prim_mubi_pkg::*;
`include "dv_fcov_macros.svh"
bit en_full_cov = 1'b1;
bit en_intg_cov = 1'b1;
logic [1:0] hw0_cmd_depth;
logic [1:0] hw1_cmd_depth;
logic [1:0] sw_cmd_depth;
logic hw0_cmd_rdy, hw0_cmd_vld, hw0_cmd_pop;
logic hw1_cmd_rdy, hw1_cmd_vld, hw1_cmd_pop;
logic sw_cmd_rdy, sw_cmd_vld, sw_cmd_pop;
logic hw0_genbits_rdy, hw0_genbits_vld, hw0_genbits_depth;
logic hw1_genbits_rdy, hw1_genbits_vld, hw1_genbits_depth;
logic sw_genbits_rdy, sw_genbits_vld, sw_genbits_depth;
assign hw0_cmd_depth = u_csrng_core.gen_cmd_stage[0].u_csrng_cmd_stage.sfifo_cmd_depth;
assign hw1_cmd_depth = u_csrng_core.gen_cmd_stage[1].u_csrng_cmd_stage.sfifo_cmd_depth;
assign sw_cmd_depth = u_csrng_core.gen_cmd_stage[2].u_csrng_cmd_stage.sfifo_cmd_depth;
assign hw0_genbits_depth =
u_csrng_core.gen_cmd_stage[0].u_csrng_cmd_stage.u_prim_fifo_genbits.depth_o;
assign hw1_genbits_depth =
u_csrng_core.gen_cmd_stage[1].u_csrng_cmd_stage.u_prim_fifo_genbits.depth_o;
assign sw_genbits_depth =
u_csrng_core.gen_cmd_stage[2].u_csrng_cmd_stage.u_prim_fifo_genbits.depth_o;
assign hw0_cmd_vld = u_csrng_core.gen_cmd_stage[0].u_csrng_cmd_stage.cmd_stage_vld_i;
assign hw0_cmd_rdy = u_csrng_core.gen_cmd_stage[0].u_csrng_cmd_stage.cmd_stage_rdy_o;
assign hw0_cmd_pop = u_csrng_core.gen_cmd_stage[0].u_csrng_cmd_stage.cmd_fifo_pop;
assign hw1_cmd_vld = u_csrng_core.gen_cmd_stage[1].u_csrng_cmd_stage.cmd_stage_vld_i;
assign hw1_cmd_rdy = u_csrng_core.gen_cmd_stage[1].u_csrng_cmd_stage.cmd_stage_rdy_o;
assign hw1_cmd_pop = u_csrng_core.gen_cmd_stage[1].u_csrng_cmd_stage.cmd_fifo_pop;
assign sw_cmd_vld = u_csrng_core.gen_cmd_stage[2].u_csrng_cmd_stage.cmd_stage_vld_i;
assign sw_cmd_rdy = u_csrng_core.gen_cmd_stage[2].u_csrng_cmd_stage.cmd_stage_rdy_o;
assign sw_cmd_pop = u_csrng_core.gen_cmd_stage[2].u_csrng_cmd_stage.cmd_fifo_pop;
assign hw0_genbits_vld = u_csrng_core.gen_cmd_stage[0].u_csrng_cmd_stage.genbits_vld_o;
assign hw0_genbits_rdy = u_csrng_core.gen_cmd_stage[0].u_csrng_cmd_stage.genbits_rdy_i;
assign hw1_genbits_vld = u_csrng_core.gen_cmd_stage[1].u_csrng_cmd_stage.genbits_vld_o;
assign hw1_genbits_rdy = u_csrng_core.gen_cmd_stage[1].u_csrng_cmd_stage.genbits_rdy_i;
assign sw_genbits_vld = u_csrng_core.gen_cmd_stage[2].u_csrng_cmd_stage.genbits_vld_o;
assign sw_genbits_rdy = u_csrng_core.gen_cmd_stage[2].u_csrng_cmd_stage.genbits_rdy_i;
// If en_full_cov is set, then en_intg_cov must also be set since it is a subset.
bit en_intg_cov_loc;
assign en_intg_cov_loc = en_full_cov | en_intg_cov;
covergroup csrng_sfifo_cg @(posedge clk_i);
option.name = "csrng_sfifo_cg";
option.per_instance = 1;
// HW0 App
cp_hw0_cmd_depth: coverpoint hw0_cmd_depth{
illegal_bins more_than_depth = {3};
}
cp_hw0_genbits_depth: coverpoint hw0_genbits_depth;
hw0_cmd_push_cross: cross cp_hw0_cmd_depth, hw0_cmd_vld, hw0_cmd_rdy{
// Note: The csrng_err and csrng_intr tests inject different types of errors into various
// FIFOs which may cause the command FIFOs to be not full and not ready / full and ready.
// We thus use assertions to detect such illegal states that can be disabled if needed.
ignore_bins not_full_and_not_ready = !binsof(cp_hw0_cmd_depth) intersect {2}
with (!hw0_cmd_rdy);
ignore_bins full_and_ready = binsof(cp_hw0_cmd_depth) intersect {2} with (hw0_cmd_rdy);
}
hw0_cmd_pop_cross: cross cp_hw0_cmd_depth, hw0_cmd_pop{
// Note: The csrng_err and csrng_intr tests inject different types of errors into various
// FIFOs which may cause the command FIFOs to get read while being empty. If that happens,
// a fatal alert must be signaled. However, multiple FIFO error conditions are collected
// in the same alert, we don't need to test every possible alert condition for every
// possible FIFO and thus ignore this particular cross point.
ignore_bins empty_and_pop = binsof(cp_hw0_cmd_depth) intersect {0}
with (hw0_cmd_pop);
}
hw0_genbits_pop_cross: cross cp_hw0_genbits_depth, hw0_genbits_vld, hw0_genbits_rdy{
// Note: cs_enable factors into vld_o. If the module is disabled, vld_o may still be low
// despite the FIFO being full. This is thus not an illegal bin, the disable/re-enable
// testing will help us to hit those cross points.
illegal_bins empty_and_valid =
binsof(cp_hw0_genbits_depth) intersect {0} with (hw0_genbits_vld);
}
// HW1 App
cp_hw1_cmd_depth: coverpoint hw1_cmd_depth{
illegal_bins more_than_depth = {3};
}
cp_hw1_genbits_depth: coverpoint hw1_genbits_depth;
hw1_cmd_push_cross: cross cp_hw1_cmd_depth, hw1_cmd_vld, hw1_cmd_rdy{
// Note: The csrng_err and csrng_intr tests inject different types of errors into various
// FIFOs which may cause the command FIFOs to be not full and not ready / full and ready.
// We thus use assertions to detect such illegal states that can be disabled if needed.
ignore_bins not_full_and_not_ready = !binsof(cp_hw1_cmd_depth) intersect {2}
with (!hw1_cmd_rdy);
ignore_bins full_and_ready = binsof(cp_hw1_cmd_depth) intersect {2} with (hw1_cmd_rdy);
}
hw1_cmd_pop_cross: cross cp_hw1_cmd_depth, hw1_cmd_pop{
// Note: The csrng_err and csrng_intr tests inject different types of errors into various
// FIFOs which may cause the command FIFOs to get read while being empty. If that happens,
// a fatal alert must be signaled. However, multiple FIFO error conditions are collected
// in the same alert, we don't need to test every possible alert condition for every
// possible FIFO and thus ignore this particular cross point.
ignore_bins empty_and_pop = binsof(cp_hw1_cmd_depth) intersect {0}
with (hw1_cmd_pop);
}
hw1_genbits_pop_cross: cross cp_hw1_genbits_depth, hw1_genbits_vld, hw1_genbits_rdy{
// Note: cs_enable factors into vld_o. If the module is disabled, vld_o may still be low
// despite the FIFO being full. This is thus not an illegal bin, the disable/re-enable
// testing will help us to hit those cross points.
illegal_bins empty_and_valid =
binsof(cp_hw1_genbits_depth) intersect {0} with (hw1_genbits_vld);
}
// SW App
cp_sw_cmd_depth: coverpoint sw_cmd_depth{
illegal_bins more_than_depth = {3};
}
cp_sw_genbits_depth: coverpoint sw_genbits_depth;
sw_cmd_push_cross: cross cp_sw_cmd_depth, sw_cmd_vld, sw_cmd_rdy{
// Note: The csrng_err and csrng_intr tests inject different types of errors into various
// FIFOs which may cause the command FIFOs to be not full and not ready / full and ready.
// We thus use assertions to detect such illegal states that can be disabled if needed.
ignore_bins not_full_and_not_ready = !binsof(cp_sw_cmd_depth) intersect {2}
with (!sw_cmd_rdy);
ignore_bins full_and_ready = binsof(cp_sw_cmd_depth) intersect {2} with (sw_cmd_rdy);
}
sw_cmd_pop_cross: cross cp_sw_cmd_depth, sw_cmd_pop{
// Note: The csrng_err and csrng_intr tests inject different types of errors into various
// FIFOs which may cause the command FIFOs to get read while being empty. If that happens,
// a fatal alert must be signaled. However, multiple FIFO error conditions are collected
// in the same alert, we don't need to test every possible alert condition for every
// possible FIFO and thus ignore this particular cross point.
ignore_bins empty_and_pop = binsof(cp_sw_cmd_depth) intersect {0}
with (sw_cmd_pop);
}
sw_genbits_pop_cross: cross cp_sw_genbits_depth, sw_genbits_vld, sw_genbits_rdy{
// Note: cs_enable factors into vld_o. If the module is disabled, vld_o may still be low
// despite the FIFO being full. This is thus not an illegal bin, the disable/re-enable
// testing will help us to hit those cross points.
illegal_bins empty_and_valid =
binsof(cp_sw_genbits_depth) intersect {0} with (sw_genbits_vld);
}
// Crosses between Apps
cmd_depth_cross: cross cp_hw0_cmd_depth, cp_hw1_cmd_depth, cp_sw_cmd_depth;
genbits_depth_cross: cross cp_hw0_genbits_depth, cp_hw1_genbits_depth, cp_sw_genbits_depth;
endgroup : csrng_sfifo_cg
covergroup csrng_cfg_cg with function sample(bit [7:0] otp_en_cs_sw_app_read,
bit [3:0] lc_hw_debug_en,
mubi4_t sw_app_enable,
mubi4_t read_int_state,
bit regwen
);
option.name = "csrng_cfg_cg";
option.per_instance = 1;
cp_sw_app_read: coverpoint otp_en_cs_sw_app_read {
bins mubi_true = { MuBi8True };
bins mubi_false = { MuBi8False };
bins mubi_inval = {[0:$]} with (!(item inside {MuBi8True, MuBi8False}));
}
cp_lc_hw_debug_en: coverpoint lc_hw_debug_en {
bins lc_on = { lc_ctrl_pkg::On };
bins lc_off = { lc_ctrl_pkg::Off };
bins lc_inval = {[0:$]} with (!(item inside {lc_ctrl_pkg::On, lc_ctrl_pkg::Off}));
}
cp_sw_app_enable: coverpoint sw_app_enable;
cp_read_int_state: coverpoint read_int_state;
cp_regwen: coverpoint regwen;
sw_app_read_sw_app_enable_cross: cross cp_sw_app_read, cp_sw_app_enable;
endgroup : csrng_cfg_cg
covergroup csrng_sts_cg with function sample();
option.name = "csrng_sts_cg";
option.per_instance = 1;
cp_hw_inst_exc: coverpoint u_reg.hw_exc_sts_qs[NUM_HW_APPS-1:0] {
bins no_exc = { 0 };
bins hw0_exc = { 1 };
bins hw1_exc = { 2 };
bins sim_exc = { 3 }; // simultaneous exception on both HW app interfaces
}
cp_sw_cmd_sts_cmd_rdy: coverpoint u_reg.sw_cmd_sts_cmd_rdy_qs {
bins not_ready = { 1'b0 };
bins ready = { 1'b1 };
}
cp_sw_cmd_sts_cmd_sts: coverpoint u_reg.sw_cmd_sts_cmd_sts_qs {
bins success = { 1'b0 };
bins error = { 1'b1 };
}
endgroup : csrng_sts_cg
covergroup csrng_err_code_cg with function sample(err_code_bit_e err_code_bit,
bit [2:0] fifo_err_type);
option.name = "csrng_err_code_cg";
option.per_instance = 1;
cp_err_codes: coverpoint err_code_bit{
// This is covered separately as it's about reporting the type of SFIFO failure
ignore_bins fifo_type = {FIFO_WRITE_ERR, FIFO_READ_ERR, FIFO_STATE_ERR};
}
cp_fifo_err_type: coverpoint fifo_err_type{
wildcard bins no_err = { 3'b000 };
wildcard bins write_err = { 3'b??1 };
wildcard bins read_err = { 3'b?1? };
wildcard bins state_err = { 3'b1?? };
}
fifo_err_type_cross: cross cp_err_codes, cp_fifo_err_type{
// If ERR_CODE register has SFIFO related field set, it also needs to set at least one
// FIFO_*_ERR field.
illegal_bins illegal = !binsof(cp_err_codes) intersect {CMD_STAGE_SM_ERR, MAIN_SM_ERR,
DRBG_GEN_SM_ERR, DRBG_UPDBE_SM_ERR,
DRBG_UPDOB_SM_ERR, AES_CIPHER_SM_ERR,
CMD_GEN_CNT_ERR} &&
binsof(cp_fifo_err_type) intersect {0};
ignore_bins ignore = binsof(cp_err_codes) intersect {CMD_STAGE_SM_ERR, MAIN_SM_ERR,
DRBG_GEN_SM_ERR, DRBG_UPDBE_SM_ERR,
DRBG_UPDOB_SM_ERR, AES_CIPHER_SM_ERR,
CMD_GEN_CNT_ERR};
}
cp_csrng_aes_fsm_err: coverpoint
u_csrng_core.u_csrng_block_encrypt.u_aes_cipher_core.u_aes_cipher_control.mr_alert {
bins no_err = { 0 };
bins rail_0 = { 1 };
bins rail_1 = { 2 };
bins rail_2 = { 4 };
ignore_bins other = { 3, [5:7]};
}
endgroup : csrng_err_code_cg
covergroup csrng_err_code_test_cg with function sample(err_code_bit_e err_test);
option.name = "csrng_err_code_test_cg";
option.per_instance = 1;
err_code_test_cp: coverpoint err_test;
endgroup : csrng_err_code_test_cg
covergroup csrng_recov_alert_sts_cg with function sample(recov_alert_bit_e recov_alert);
option.name = "csrng_recov_alert_sts_cg";
option.per_instance = 1;
recov_alert_sts_cp: coverpoint recov_alert;
endgroup : csrng_recov_alert_sts_cg
covergroup csrng_cmds_cg with function sample(bit[NUM_HW_APPS-1:0] app,
acmd_e acmd,
bit[3:0] clen,
bit[3:0] flags,
bit[18:0] glen
);
option.name = "csrng_cmds_cg";
option.per_instance = 1;
cp_app: coverpoint app {
bins hw_app0 = { 0 };
bins hw_app1 = { 1 };
bins sw_app = { 2 };
ignore_bins other = { 3 };
}
cp_acmd: coverpoint acmd {
illegal_bins illegal = { INV, GENB, GENU };
}
cp_clen: coverpoint clen {
bins zero = { 0 };
bins one = { 1 };
bins two = { 2 };
bins three = { 3 };
bins four = { 4 };
bins five = { 5 };
bins six = { 6 };
bins seven = { 7 };
bins eight = { 8 };
bins nine = { 9 };
bins ten = { 10 };
bins eleven = { 11 };
bins twelve = { 12 };
ignore_bins other = { [13:15] };
}
cp_flags: coverpoint flags {
bins false = { MuBi4False };
bins true = { MuBi4True };
}
cp_glen: coverpoint glen {
bins one = { 1 };
bins multiple = { [2:$] };
ignore_bins zero = { 0 };
}
app_acmd_cross: cross cp_app, cp_acmd;
acmd_clen_cross: cross cp_acmd, cp_clen {
ignore_bins invalid = binsof(cp_acmd) intersect { UNI } &&
binsof(cp_clen) intersect { [1:$] };
}
acmd_flags_cross: cross cp_acmd, cp_flags;
acmd_glen_cross: cross cp_acmd, cp_glen;
flags_clen_acmd_cross: cross cp_acmd, cp_flags, cp_clen {
// Use only Entropy Source seed
bins ins_only_entropy_src_seed = binsof(cp_flags) intersect {MuBi4False} &&
binsof(cp_clen) intersect {0} &&
binsof(cp_acmd) intersect {INS};
bins res_only_entropy_src_seed = binsof(cp_flags) intersect {MuBi4False} &&
binsof(cp_clen) intersect {0} &&
binsof(cp_acmd) intersect {RES};
// Use Entropy Source Seed ^ Additional Data (clen)
bins ins_xored_entropy_src_seed = binsof(cp_flags) intersect {MuBi4False} &&
binsof(cp_clen) intersect {[1:$]} &&
binsof(cp_acmd) intersect {INS};
bins res_xored_entropy_src_seed = binsof(cp_flags) intersect {MuBi4False} &&
binsof(cp_clen) intersect {[1:$]} &&
binsof(cp_acmd) intersect {RES};
// Use zero as seed
bins ins_zero_seed = binsof(cp_flags) intersect {MuBi4True} &&
binsof(cp_clen) intersect {0} &&
binsof(cp_acmd) intersect {INS};
bins res_zero_seed = binsof(cp_flags) intersect {MuBi4True} &&
binsof(cp_clen) intersect {0} &&
binsof(cp_acmd) intersect {RES};
// Use Additional Data (clen) as seed
bins ins_add_data_seed = binsof(cp_flags) intersect {MuBi4True} &&
binsof(cp_clen) intersect {[1:$]} &&
binsof(cp_acmd) intersect {INS};
bins res_add_data_seed = binsof(cp_flags) intersect {MuBi4True} &&
binsof(cp_clen) intersect {[1:$]} &&
binsof(cp_acmd) intersect {RES};
// Since other modes are not related with flag0, ignore them in this cross.
ignore_bins ignore = binsof(cp_acmd) intersect {UPD, UNI, GEN};
}
endgroup : csrng_cmds_cg
`DV_FCOV_INSTANTIATE_CG(csrng_sfifo_cg, en_full_cov)
`DV_FCOV_INSTANTIATE_CG(csrng_cfg_cg, en_full_cov)
`DV_FCOV_INSTANTIATE_CG(csrng_cmds_cg, en_full_cov)
`DV_FCOV_INSTANTIATE_CG(csrng_sts_cg, en_full_cov)
`DV_FCOV_INSTANTIATE_CG(csrng_err_code_cg, en_full_cov)
`DV_FCOV_INSTANTIATE_CG(csrng_err_code_test_cg, en_full_cov)
`DV_FCOV_INSTANTIATE_CG(csrng_recov_alert_sts_cg, en_full_cov)
// Sample functions needed for xcelium
function automatic void cg_cfg_sample(csrng_env_cfg cfg);
csrng_cfg_cg_inst.sample(cfg.otp_en_cs_sw_app_read,
cfg.lc_hw_debug_en,
cfg.sw_app_enable,
cfg.read_int_state,
cfg.regwen
);
endfunction
function automatic void cg_cmds_sample(bit[NUM_HW_APPS-1:0] hwapp, csrng_item cs_item);
csrng_cmds_cg_inst.sample(hwapp,
cs_item.acmd,
cs_item.clen,
cs_item.flags,
cs_item.glen
);
csrng_sts_cg_inst.sample();
endfunction
function automatic void cg_err_code_sample(bit [31:0] err_code);
// A single error might cause multiple bits in ERR_CODE to get set. For example, some
// countermeasures always cause the main FSM to escalate and report an error itself.
for (int unsigned i = 0; i < 27; i++) begin
if (err_code[i]) begin
csrng_err_code_cg_inst.sample(err_code_bit_e'(i), err_code[30:28]);
end
end
csrng_sts_cg_inst.sample();
endfunction
function automatic void cg_err_test_sample(bit [4:0] err_test_code);
csrng_err_code_test_cg_inst.sample(err_code_bit_e'(err_test_code));
endfunction
function automatic void cg_recov_alert_sample(bit [31:0] recov_alert);
csrng_recov_alert_sts_cg_inst.sample(recov_alert_bit_e'($clog2(recov_alert)));
endfunction
endinterface : csrng_cov_if