mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-22 04:47:25 -04:00
[dv, icache] Add functional coverage
This commit is contained in:
parent
ef6219b0ad
commit
6b3e0e7914
6 changed files with 313 additions and 3 deletions
|
@ -18,7 +18,7 @@ VERBOSITY=
|
|||
# The number of seeds to run for each selected test. Defaults to 1.
|
||||
RESEED=1
|
||||
|
||||
SIM=vcs
|
||||
SIM=xcelium
|
||||
|
||||
# Specify the seed for the test to run. If this is empty, dvsim.py
|
||||
# will pick random seeds. By default, we make runs reproducible, so
|
||||
|
@ -35,7 +35,7 @@ scratch-root := $(ibex-top)/build
|
|||
dvsim-py := $(ibex-top)/vendor/lowrisc_ip/util/dvsim/dvsim.py
|
||||
dvsim-std-args := --scratch-root $(scratch-root)
|
||||
|
||||
waves-arg := $(if $(filter-out 0,$(WAVES)),--waves,)
|
||||
waves-arg := $(if $(filter-out 0,$(WAVES)),--waves shm,)
|
||||
coverage-arg := $(if $(filter-out 0,$(COVERAGE)),-c,)
|
||||
verbosity-arg := $(if $(VERBOSITY),--verbosity $(VERBOSITY),)
|
||||
reseed-arg := --reseed $(RESEED)
|
||||
|
|
24
dv/uvm/icache/dv/fcov/ibex_icache_fcov.core
Normal file
24
dv/uvm/icache/dv/fcov/ibex_icache_fcov.core
Normal file
|
@ -0,0 +1,24 @@
|
|||
CAPI=2:
|
||||
# Copyright lowRISC contributors.
|
||||
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
name: "lowrisc:dv:ibex_icache_fcov"
|
||||
description: "Ibex ICache functional coverage and bind files"
|
||||
filesets:
|
||||
files_rtl:
|
||||
depend:
|
||||
- lowrisc:ibex:ibex_icache
|
||||
|
||||
files_dv:
|
||||
depend:
|
||||
- lowrisc:dv:dv_utils
|
||||
files:
|
||||
- ibex_icache_fcov_if.sv
|
||||
- ibex_icache_fcov_bind.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
default:
|
||||
filesets:
|
||||
- files_rtl
|
||||
- files_dv
|
11
dv/uvm/icache/dv/fcov/ibex_icache_fcov_bind.sv
Normal file
11
dv/uvm/icache/dv/fcov/ibex_icache_fcov_bind.sv
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Binds icache functional coverage interface to the top-level ibex_icache
|
||||
// module.
|
||||
module ibex_icache_fcov_bind;
|
||||
bind ibex_icache ibex_icache_fcov_if#(
|
||||
.NUM_FB(NUM_FB)
|
||||
) u_ibex_icache_fcov_if (.*);
|
||||
endmodule
|
272
dv/uvm/icache/dv/fcov/ibex_icache_fcov_if.sv
Normal file
272
dv/uvm/icache/dv/fcov/ibex_icache_fcov_if.sv
Normal file
|
@ -0,0 +1,272 @@
|
|||
interface ibex_icache_fcov_if import ibex_pkg::*; #(
|
||||
parameter int NUM_FB = 4
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
input req_i,
|
||||
input branch_i,
|
||||
input icache_enable_i,
|
||||
input icache_inval_i,
|
||||
input lookup_throttle,
|
||||
input lookup_req_ic0,
|
||||
input tag_req_ic0,
|
||||
input data_req_ic0,
|
||||
input fill_req_ic0,
|
||||
input inval_write_req,
|
||||
input ecc_write_req,
|
||||
input skid_valid_q,
|
||||
input valid_o,
|
||||
input [ADDR_W-1:0] lookup_addr_ic0,
|
||||
input lookup_valid_ic1,
|
||||
input tag_hit_ic1,
|
||||
input [IC_NUM_WAYS-1:0] tag_match_ic1,
|
||||
|
||||
input [NUM_FB-1:0] fill_hit_ic1,
|
||||
input [NUM_FB-1:0] fill_busy_q,
|
||||
input [NUM_FB-1:0] fill_rvd_done,
|
||||
input [NUM_FB-1:0] fill_ram_done_q,
|
||||
input [NUM_FB-1:0] fill_hit_q,
|
||||
input [NUM_FB-1:0] fill_cache_q,
|
||||
input [NUM_FB-1:0] fill_stale_q,
|
||||
input [NUM_FB-1:0] fill_done,
|
||||
input [NUM_FB-1:0] fill_ext_hold_q,
|
||||
input [NUM_FB-1:0] fill_ext_done_q,
|
||||
logic [NUM_FB-1:0] fill_data_hit,
|
||||
logic [NUM_FB-1:0] fill_data_rvd,
|
||||
logic [NUM_FB-1:0] fill_alloc,
|
||||
logic [NUM_FB-1:0][NUM_FB-1:0] fill_older_q,
|
||||
input [NUM_FB-1:0][IC_LINE_BEATS-1:0] fill_err_q,
|
||||
input [NUM_FB-1:0][IC_LINE_BEATS_W:0] fill_rvd_cnt_q,
|
||||
input [NUM_FB-1:0][IC_LINE_BEATS_W:0] fill_ext_cnt_q,
|
||||
input [ADDR_W-1:0] fill_addr_q [NUM_FB]
|
||||
);
|
||||
localparam int IC_NUM_WAYS_W = $clog2(IC_NUM_WAYS);
|
||||
|
||||
function automatic logic [IC_NUM_WAYS_W-1:0] way_num(logic [IC_NUM_WAYS-1:0] way_onehot);
|
||||
for (int i = 0;i < IC_NUM_WAYS; ++i) begin
|
||||
if (way_onehot[i]) begin
|
||||
return i;
|
||||
end
|
||||
end
|
||||
|
||||
return 'x;
|
||||
endfunction
|
||||
|
||||
`include "dv_fcov_macros.svh"
|
||||
import uvm_pkg::*;
|
||||
|
||||
typedef enum {
|
||||
FillBufIdle,
|
||||
FillBufReqing,
|
||||
FillBufReqingAndFilling,
|
||||
FillBufFilling,
|
||||
FillBufAllocating,
|
||||
FillBufAwaitingOutput
|
||||
} fill_buffer_state_e;
|
||||
|
||||
typedef enum {
|
||||
FillBufNotDone,
|
||||
FillBufDoneHitNoExtReqs,
|
||||
FillBufDoneHitExtReqs,
|
||||
FillBufDoneMiss,
|
||||
FillBufDoneBranchNoExtReqs,
|
||||
FillBufDoneBranchExtReqs,
|
||||
FillBufDoneNoCache,
|
||||
FillBufDoneMemErr
|
||||
} fill_buffer_done_reason_e;
|
||||
|
||||
typedef enum {
|
||||
ICDataSrcCache,
|
||||
ICDataSrcFB,
|
||||
ICDataSrcExt
|
||||
} ic_data_src_e;
|
||||
|
||||
bit en_icache_fcov = 0;
|
||||
|
||||
initial begin
|
||||
void'($value$plusargs("enable_icache_fcov=%d", en_icache_fcov));
|
||||
end
|
||||
|
||||
ic_data_src_e ic_data_src;
|
||||
|
||||
always_comb begin
|
||||
ic_data_src = ICDataSrcFB;
|
||||
if (|fill_data_rvd) begin
|
||||
ic_data_src = ICDataSrcExt;
|
||||
end else if (|fill_data_hit) begin
|
||||
ic_data_src = ICDataSrcCache;
|
||||
end
|
||||
end
|
||||
|
||||
logic [IC_LINE_BEATS-1:0] data_err_ecc;
|
||||
for (genvar i_beat = 0; i_beat < IC_LINE_BEATS; ++i_beat) begin : g_data_err_ecc
|
||||
assign data_err_ecc[i_beat] = |gen_data_ecc_checking.data_err_ic1[i_beat*2+:2];
|
||||
end
|
||||
|
||||
covergroup icache_cg @(posedge clk_i);
|
||||
option.per_instance = 1;
|
||||
option.name = "icache_cg";
|
||||
|
||||
`DV_FCOV_EXPR_SEEN(req_when_fb_full, req_i & (&fill_busy_q))
|
||||
`DV_FCOV_EXPR_SEEN(branch_when_fb_full, branch_i & (&fill_busy_q))
|
||||
`DV_FCOV_EXPR_SEEN(throttle_req, lookup_throttle & lookup_req_ic0)
|
||||
|
||||
cp_lookup_req: coverpoint branch_i iff (lookup_req_ic0) {
|
||||
bins straightline_req = {1'b0};
|
||||
bins branch_req = {1'b1};
|
||||
}
|
||||
|
||||
cp_fill_buffer_usage: coverpoint $countones(fill_busy_q) {
|
||||
bins fill_level[] = {[0:NUM_FB]};
|
||||
illegal_bins illegal = default;
|
||||
}
|
||||
|
||||
cp_hit_miss: coverpoint tag_hit_ic1 iff (lookup_valid_ic1) {
|
||||
bins miss = {1'b0};
|
||||
bins hit = {1'b1};
|
||||
}
|
||||
|
||||
cp_hit_way: coverpoint way_num(tag_match_ic1) iff (lookup_valid_ic1 && tag_hit_ic1);
|
||||
|
||||
cp_data_ecc_err: coverpoint data_err_ecc
|
||||
iff (lookup_valid_ic1 && tag_hit_ic1);
|
||||
|
||||
cp_tag_ecc_err: coverpoint way_num(gen_data_ecc_checking.tag_err_ic1) iff (lookup_valid_ic1);
|
||||
|
||||
cp_data_src: coverpoint ic_data_src iff (valid_o);
|
||||
|
||||
tag_req_cross: cross req_i, branch_i, fill_req_ic0, inval_write_req, ecc_write_req {
|
||||
// The ICache will still perform lookups when we assert branch_i without req_i but this is not
|
||||
// a behaviour Ibex uses
|
||||
ignore_bins branch_no_req =
|
||||
binsof(req_i) intersect {1'b0} && binsof(branch_i) intersect {1'b1};
|
||||
|
||||
// When we're invalidating fill and ecc requests cannot occur
|
||||
illegal_bins illegal_with_inval = binsof(inval_write_req) intersect {1'b1} && (
|
||||
binsof(fill_req_ic0) intersect {1'b1} ||
|
||||
binsof(ecc_write_req) intersect {1'b1});
|
||||
}
|
||||
|
||||
data_req_cross: cross fill_req_ic0, cp_lookup_req iff (data_req_ic0);
|
||||
data_src_cross: cross icache_enable_i, skid_valid_q, cp_data_src iff (valid_o);
|
||||
endgroup
|
||||
|
||||
`DV_FCOV_INSTANTIATE_CG(icache_cg, en_icache_fcov)
|
||||
|
||||
logic last_icache_enable;
|
||||
logic last_icache_inval;
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
last_icache_enable <= 1'b0;
|
||||
last_icache_inval <= 1'b0;
|
||||
end else begin
|
||||
last_icache_enable <= icache_enable_i;
|
||||
last_icache_inval <= icache_inval_i;
|
||||
end
|
||||
end
|
||||
|
||||
logic icache_just_disabled, icache_just_enabled;
|
||||
logic icache_inval_start;
|
||||
|
||||
assign icache_just_disabled = last_icache_enable & ~icache_enable_i;
|
||||
assign icache_just_enabled = ~last_icache_enable & icache_enable_i;
|
||||
|
||||
assign icache_inval_start = ~last_icache_inval & icache_inval_i;
|
||||
|
||||
logic [IC_LINE_BEATS_W-1:0] starting_beat;
|
||||
assign starting_beat = lookup_addr_ic0[IC_LINE_W-1:BUS_W];
|
||||
|
||||
for (genvar i_fb = 0;i_fb < NUM_FB; ++i_fb) begin : g_fb_cov
|
||||
fill_buffer_state_e fill_buffer_state;
|
||||
logic fill_alloc_done_or_skip;
|
||||
logic fill_requesting;
|
||||
|
||||
assign fill_alloc_done_or_skip =
|
||||
fill_ram_done_q[i_fb] | fill_hit_q[i_fb] | ~fill_cache_q[i_fb] | (|fill_err_q[i_fb]);
|
||||
|
||||
assign fill_requesting = !fill_ext_done_q[i_fb] && (fill_rvd_cnt_q[i_fb] == '0)
|
||||
&& (fill_ext_cnt_q[i_fb] != IC_LINE_BEATS);
|
||||
|
||||
always_comb begin
|
||||
fill_buffer_state = FillBufIdle;
|
||||
|
||||
if (fill_busy_q[i_fb]) begin
|
||||
if (fill_requesting) begin
|
||||
fill_buffer_state = FillBufReqing;
|
||||
end else if (!fill_rvd_done[i_fb]) begin
|
||||
if (!fill_ext_done_q[i_fb]) begin
|
||||
fill_buffer_state = FillBufReqingAndFilling;
|
||||
end else begin
|
||||
fill_buffer_state = FillBufFilling;
|
||||
end
|
||||
end else if (!fill_alloc_done_or_skip) begin
|
||||
fill_buffer_state = FillBufAllocating;
|
||||
end else begin
|
||||
fill_buffer_state = FillBufAwaitingOutput;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
logic fill_awaiting_ext_req;
|
||||
|
||||
fill_buffer_done_reason_e fill_buffer_done_reason;
|
||||
|
||||
assign fill_has_ext_req = (fill_ext_cnt_q[i_fb] != '0) || fill_ext_hold_q[i_fb];
|
||||
|
||||
always_comb begin
|
||||
fill_buffer_done_reason = FillBufNotDone;
|
||||
|
||||
if (fill_done[i_fb]) begin
|
||||
if (|fill_err_q[i_fb]) begin
|
||||
fill_buffer_done_reason = FillBufDoneMemErr;
|
||||
end else if (~fill_cache_q[i_fb]) begin
|
||||
if (branch_i || fill_stale_q[i_fb]) begin
|
||||
fill_buffer_done_reason = fill_has_ext_req ? FillBufDoneBranchExtReqs :
|
||||
FillBufDoneBranchNoExtReqs;
|
||||
end else begin
|
||||
fill_buffer_done_reason = FillBufDoneNoCache;
|
||||
end
|
||||
end else if (fill_hit_q[i_fb]) begin
|
||||
fill_buffer_done_reason = fill_has_ext_req ? FillBufDoneHitExtReqs :
|
||||
FillBufDoneHitNoExtReqs;
|
||||
end else begin
|
||||
fill_buffer_done_reason = FillBufDoneMiss;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
logic [NUM_FB-1:0] addr_matches;
|
||||
|
||||
for (genvar i_other_fb = 0; i_other_fb < NUM_FB; ++i_other_fb) begin : g_other_fb
|
||||
if (i_other_fb != i_fb) begin
|
||||
assign addr_matches[i_other_fb] = fill_busy_q[i_fb] & fill_busy_q[i_other_fb] &
|
||||
(fill_addr_q[i_fb] == fill_addr_q[i_other_fb]);
|
||||
end else begin
|
||||
assign addr_matches[i_other_fb] = 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
covergroup icache_fillbuf_cg @(posedge clk_i);
|
||||
option.per_instance = 1;
|
||||
option.name = "icache_fillbuf_cg";
|
||||
|
||||
`DV_FCOV_EXPR_SEEN(addr_hz, |addr_matches)
|
||||
|
||||
cp_out_of_order_finish: coverpoint $countones(fill_older_q[i_fb] & fill_busy_q)
|
||||
iff (fill_done[i_fb]) {
|
||||
bins older_fill_bufs[] = {[0:NUM_FB-1]};
|
||||
illegal_bins illegal = default;
|
||||
}
|
||||
cp_state: coverpoint fill_buffer_state;
|
||||
cp_fill_buffer_done_reason : coverpoint fill_buffer_done_reason;
|
||||
cp_state_when_disabling: coverpoint fill_buffer_state iff icache_just_disabled;
|
||||
cp_state_when_enabling: coverpoint fill_buffer_state iff icache_just_enabled;
|
||||
cp_state_when_inval_start: coverpoint fill_buffer_state iff icache_inval_start;
|
||||
cp_starting_beat: coverpoint starting_beat iff fill_alloc[i_fb];
|
||||
endgroup
|
||||
|
||||
`DV_FCOV_INSTANTIATE_CG(icache_fillbuf_cg, en_icache_fcov)
|
||||
end
|
||||
endinterface
|
|
@ -12,6 +12,7 @@ filesets:
|
|||
files_dv:
|
||||
depend:
|
||||
- lowrisc:dv:ibex_icache_test
|
||||
- lowrisc:dv:ibex_icache_fcov
|
||||
- lowrisc:prim:ram_1p_scr
|
||||
files:
|
||||
- tb/tb.sv
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
"{proj_root}/vendor/lowrisc_ip/dv/verilator/memutil_dpi_scrambled_opts.hjson"
|
||||
]
|
||||
|
||||
sim_tops: ["ibex_icache_fcov_bind"]
|
||||
|
||||
build_modes: [
|
||||
{
|
||||
name: default
|
||||
|
@ -45,7 +47,7 @@
|
|||
uvm_test: ibex_icache_base_test
|
||||
uvm_test_seq: ibex_icache_base_vseq
|
||||
|
||||
run_opts: ["+test_timeout_ns=1000000000"]
|
||||
run_opts: ["+test_timeout_ns=1000000000", "+enable_icache_fcov=1"]
|
||||
|
||||
// List of test specifications.
|
||||
tests: [
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue