mirror of
https://github.com/openhwgroup/cve2.git
synced 2025-04-24 14:09:08 -04:00
[dv] Ibex uarch functional coverage
This adds a framework for gathering functional coverage for Ibex microarchitecture along with a selection of initial coverpoints.
This commit is contained in:
parent
d717e2385e
commit
794d865f56
11 changed files with 251 additions and 0 deletions
17
dv/fcov/dv_fcov.core
Normal file
17
dv/fcov/dv_fcov.core
Normal file
|
@ -0,0 +1,17 @@
|
|||
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:dv_fcov"
|
||||
description: "DV FCOV utilities"
|
||||
|
||||
filesets:
|
||||
files_fcov:
|
||||
files:
|
||||
- dv_fcov_macros.svh: {is_include_file: true}
|
||||
file_type: systemVerilogSource
|
||||
|
||||
targets:
|
||||
default:
|
||||
filesets:
|
||||
- files_fcov
|
48
dv/fcov/dv_fcov_macros.svh
Normal file
48
dv/fcov/dv_fcov_macros.svh
Normal file
|
@ -0,0 +1,48 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Coverage support is not available in Verilator but it's useful to include extra fcov signals for
|
||||
// linting purposes. They need to be marked as unused to avoid warnings.
|
||||
|
||||
// Include FCOV RTL by default. Exclude it for synthesis and where explicitly requested (by defining
|
||||
// EXCLUDE_FCOV).
|
||||
`ifdef SYNTHESIS
|
||||
`define EXCLUDE_FCOV
|
||||
`elsif YOSYS
|
||||
`define EXCLUDE_FCOV
|
||||
`endif
|
||||
|
||||
`ifdef VERILATOR
|
||||
`define FCOV_MARK_UNUSED(__var_type, __var_name) \
|
||||
__var_type unused_fcov_``__var_name; \
|
||||
assign unused_fcov_``__var_name = fcov_``__var_name;
|
||||
`else
|
||||
`define FCOV_MARK_UNUSED(__var_type, __var_name)
|
||||
`endif
|
||||
|
||||
`ifndef FCOV_SIGNAL
|
||||
`define FCOV_SIGNAL(__var_type, __var_name, __var_definition) \
|
||||
`ifndef EXCLUDE_FCOV \
|
||||
__var_type fcov_``__var_name; \
|
||||
\
|
||||
assign fcov_``__var_name = __var_definition; \
|
||||
\
|
||||
`FCOV_MARK_UNUSED(__var_type, __var_name) \
|
||||
`endif
|
||||
`endif
|
||||
|
||||
`ifndef FCOV_SIGNAL_GEN_IF
|
||||
`define FCOV_SIGNAL_GEN_IF(__var_type, __var_name, __var_definition, __generate_test, __default_val = '0) \
|
||||
`ifndef EXCLUDE_FCOV \
|
||||
__var_type fcov_``__var_name; \
|
||||
\
|
||||
if (__generate_test) begin : g_fcov_``__var_name \
|
||||
assign fcov_``__var_name = __var_definition; \
|
||||
end else begin : g_no_fcov_``__var_name \
|
||||
assign fcov_``__var_name = __default_val; \
|
||||
end \
|
||||
\
|
||||
`FCOV_MARK_UNUSED(__var_type, __var_name) \
|
||||
`endif
|
||||
`endif
|
9
dv/uvm/core_ibex/fcov/core_ibex_fcov_bind.sv
Normal file
9
dv/uvm/core_ibex/fcov/core_ibex_fcov_bind.sv
Normal file
|
@ -0,0 +1,9 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
module core_ibex_fcov_bind;
|
||||
bind ibex_core core_ibex_fcov_if u_fcov_bind (
|
||||
.*
|
||||
);
|
||||
endmodule
|
141
dv/uvm/core_ibex/fcov/core_ibex_fcov_if.sv
Normal file
141
dv/uvm/core_ibex/fcov/core_ibex_fcov_if.sv
Normal file
|
@ -0,0 +1,141 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
interface core_ibex_fcov_if import ibex_pkg::*; (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
||||
input priv_lvl_e priv_mode_id,
|
||||
input priv_lvl_e priv_mode_if,
|
||||
input priv_lvl_e priv_mode_lsu
|
||||
);
|
||||
`include "dv_macros.svh"
|
||||
import uvm_pkg::*;
|
||||
|
||||
typedef enum {
|
||||
InsnCategoryALU,
|
||||
InsnCategoryMult,
|
||||
InsnCategoryDiv,
|
||||
InsnCategoryBranch,
|
||||
InsnCategoryJump,
|
||||
InsnCategoryLoad,
|
||||
InsnCategoryStore,
|
||||
InsnCategoryOther,
|
||||
InsnCategoryNone
|
||||
} insn_category_e;
|
||||
|
||||
typedef enum {
|
||||
IdStallTypeNone,
|
||||
IdStallTypeInsn,
|
||||
IdStallTypeLdHz,
|
||||
IdStallTypeMem
|
||||
} id_stall_type_e;
|
||||
|
||||
insn_category_e id_instr_category;
|
||||
|
||||
// Set `id_instr_category` to the appropriate category for the uncompressed instruction in the
|
||||
// ID/EX stage. Compressed instructions are not handled (`id_stage_i.instr_rdata_i` is always
|
||||
// uncompressed). When the `id_stage.instr_valid_i` isn't set `InsnCategoryNone` is the given
|
||||
// instruction category.
|
||||
// TODO: Illegal instructions
|
||||
always_comb begin
|
||||
case (id_stage_i.instr_rdata_i[6:0])
|
||||
ibex_pkg::OPCODE_LUI: id_instr_category = InsnCategoryALU;
|
||||
ibex_pkg::OPCODE_AUIPC: id_instr_category = InsnCategoryALU;
|
||||
ibex_pkg::OPCODE_JAL: id_instr_category = InsnCategoryJump;
|
||||
ibex_pkg::OPCODE_JALR: id_instr_category = InsnCategoryJump;
|
||||
ibex_pkg::OPCODE_BRANCH: id_instr_category = InsnCategoryBranch;
|
||||
ibex_pkg::OPCODE_LOAD: id_instr_category = InsnCategoryLoad;
|
||||
ibex_pkg::OPCODE_STORE: id_instr_category = InsnCategoryStore;
|
||||
ibex_pkg::OPCODE_OP_IMM: id_instr_category = InsnCategoryALU;
|
||||
ibex_pkg::OPCODE_OP: begin
|
||||
if(id_stage_i.instr_rdata_i[31:25] == 7'b0000000) begin
|
||||
id_instr_category = InsnCategoryALU; // RV32I ALU reg-reg ops
|
||||
end else if (id_stage_i.instr_rdata_i[31:25] == 7'b0000001) begin
|
||||
if (id_stage_i.instr_rdata_i[14]) begin
|
||||
id_instr_category = InsnCategoryMult; //MUL*
|
||||
end else begin
|
||||
id_instr_category = InsnCategoryDiv; // DIV*
|
||||
end
|
||||
end
|
||||
end
|
||||
default: id_instr_category = InsnCategoryOther;
|
||||
endcase
|
||||
|
||||
if (!id_stage_i.instr_valid_i) begin
|
||||
id_instr_category = InsnCategoryNone;
|
||||
end
|
||||
end
|
||||
|
||||
id_stall_type_e id_stall_type;
|
||||
|
||||
// Set `id_stall_type` to the appropriate type based on signals in the ID/EX stage
|
||||
always_comb begin
|
||||
id_stall_type = IdStallTypeNone;
|
||||
|
||||
if (id_stage_i.instr_valid_i) begin
|
||||
if (id_stage_i.stall_mem) begin
|
||||
id_stall_type = IdStallTypeMem;
|
||||
end
|
||||
|
||||
if (id_stage_i.stall_ld_hz) begin
|
||||
id_stall_type = IdStallTypeLdHz;
|
||||
end
|
||||
|
||||
if (id_stage_i.stall_multdiv || id_stage_i.stall_branch ||
|
||||
id_stage_i.stall_jump) begin
|
||||
id_stall_type = IdStallTypeInsn;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
`DV_FCOV_SVA(instruction_unstalled, id_stall_type != IdStallTypeNone ##1
|
||||
id_stall_type == IdStallTypeNone)
|
||||
|
||||
covergroup uarch_cg @(posedge clk_i);
|
||||
type_option.strobe = 1;
|
||||
|
||||
`DV_FCOV_EXPR_SEEN(cp_insn_unstalled, instruction_unstalled.triggered)
|
||||
|
||||
cp_insn_category_id: coverpoint id_instr_category;
|
||||
|
||||
cp_stall_type_id: coverpoint id_stall_type;
|
||||
|
||||
cp_wb_reg_hz: coverpoint id_stage_i.fcov_rf_rd_wb_hz;
|
||||
cp_wb_load_hz: coverpoint id_stage_i.fcov_rf_rd_wb_hz &&
|
||||
wb_stage_i.outstanding_load_wb_o;
|
||||
|
||||
cp_ls_error_exception: coverpoint load_store_unit_i.fcov_ls_error_exception;
|
||||
cp_ls_pmp_exception: coverpoint load_store_unit_i.fcov_ls_pmp_exception;
|
||||
|
||||
cp_branch_taken: coverpoint id_stage_i.fcov_branch_taken;
|
||||
cp_branch_not_taken: coverpoint id_stage_i.fcov_branch_not_taken;
|
||||
|
||||
cp_priv_mode_id: coverpoint priv_mode_id;
|
||||
cp_priv_mode_if: coverpoint priv_mode_if;
|
||||
cp_prov_mode_lsu: coverpoint priv_mode_lsu;
|
||||
|
||||
`DV_FCOV_EXPR_SEEN(cp_interrupt_taken, id_stage_i.controller_i.fcov_interrupt_taken)
|
||||
`DV_FCOV_EXPR_SEEN(cp_debug_entry_if, id_stage_i.controller_i.fcov_debug_entry_if)
|
||||
`DV_FCOV_EXPR_SEEN(cp_debug_entry_id, id_stage_i.controller_i.fcov_debug_entry_id)
|
||||
`DV_FCOV_EXPR_SEEN(cp_pipe_flush, id_stage_i.controller_i.fcov_pipe_flush)
|
||||
|
||||
wb_reg_hz_instr_cross: cross cp_insn_category_id, cp_wb_reg_hz;
|
||||
stall_cross: cross cp_insn_category_id, cp_stall_type_id;
|
||||
pipe_cross: cross cp_insn_category_id, if_stage_i.if_instr_valid,
|
||||
wb_stage_i.fcov_wb_valid;
|
||||
|
||||
interrupt_taken_instr_cross: cross cp_insn_unstalled, cp_interrupt_taken, cp_insn_category_id;
|
||||
debug_entry_if_instr_cross: cross cp_debug_entry_if, cp_insn_category_id;
|
||||
pipe_flush_instr_cross: cross cp_pipe_flush, cp_insn_category_id;
|
||||
endgroup
|
||||
|
||||
bit en_uarch_cov;
|
||||
|
||||
initial begin
|
||||
void'($value$plusargs("enable_uarch_cov=%d", en_uarch_cov));
|
||||
end
|
||||
|
||||
`DV_INSTANTIATE_CG(uarch_cg, en_uarch_cov)
|
||||
endinterface
|
|
@ -65,6 +65,7 @@ ${PRJ_DIR}/vendor/google_riscv-dv/src/riscv_signature_pkg.sv
|
|||
+incdir+${PRJ_DIR}/dv/uvm/core_ibex/tests
|
||||
+incdir+${PRJ_DIR}/dv/uvm/core_ibex/common/ibex_mem_intf_agent
|
||||
+incdir+${PRJ_DIR}/dv/uvm/core_ibex/common/irq_agent
|
||||
+incdir+${PRJ_DIR}/dv/fcov
|
||||
+incdir+${PRJ_DIR}/vendor/lowrisc_ip/dv/sv/mem_model
|
||||
+incdir+${PRJ_DIR}/vendor/lowrisc_ip/dv/sv/dv_utils
|
||||
+incdir+${PRJ_DIR}/vendor/lowrisc_ip/dv/sv/str_utils
|
||||
|
@ -85,4 +86,6 @@ ${PRJ_DIR}/dv/uvm/core_ibex/env/core_ibex_rvfi_if.sv
|
|||
${PRJ_DIR}/dv/uvm/core_ibex/env/core_ibex_csr_if.sv
|
||||
${PRJ_DIR}/dv/uvm/core_ibex/env/core_ibex_env_pkg.sv
|
||||
${PRJ_DIR}/dv/uvm/core_ibex/tests/core_ibex_test_pkg.sv
|
||||
${PRJ_DIR}/dv/uvm/core_ibex/fcov/core_ibex_fcov_if.sv
|
||||
${PRJ_DIR}/dv/uvm/core_ibex/fcov/core_ibex_fcov_bind.sv
|
||||
${PRJ_DIR}/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
-cm_log /dev/null
|
||||
-assert nopostproc
|
||||
-cm_name test_<test_name>_<iteration>
|
||||
+enable_uarch_cov=1
|
||||
wave_opts: >
|
||||
-ucli -do <cwd>/vcs.tcl
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ filesets:
|
|||
- lowrisc:prim:lfsr
|
||||
- lowrisc:ibex:ibex_pkg
|
||||
- lowrisc:ibex:ibex_icache
|
||||
- lowrisc:dv:dv_fcov
|
||||
files:
|
||||
- rtl/ibex_alu.sv
|
||||
- rtl/ibex_branch_predict.sv
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
|
||||
`include "prim_assert.sv"
|
||||
`include "dv_fcov_macros.svh"
|
||||
|
||||
module ibex_controller #(
|
||||
parameter bit WritebackStage = 0,
|
||||
|
@ -829,6 +830,14 @@ module ibex_controller #(
|
|||
end
|
||||
end
|
||||
|
||||
//////////
|
||||
// FCOV //
|
||||
//////////
|
||||
`FCOV_SIGNAL(logic, interrupt_taken, (ctrl_fsm_cs != IRQ_TAKEN) & (ctrl_fsm_ns == IRQ_TAKEN));
|
||||
`FCOV_SIGNAL(logic, debug_entry_if, (ctrl_fsm_cs != DBG_TAKEN_IF) & (ctrl_fsm_ns == DBG_TAKEN_IF));
|
||||
`FCOV_SIGNAL(logic, debug_entry_id, (ctrl_fsm_cs != DBG_TAKEN_ID) & (ctrl_fsm_ns == DBG_TAKEN_ID));
|
||||
`FCOV_SIGNAL(logic, pipe_flush, (ctrl_fsm_cs != FLUSH) & (ctrl_fsm_ns == FLUSH));
|
||||
|
||||
////////////////
|
||||
// Assertions //
|
||||
////////////////
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
|
||||
`include "prim_assert.sv"
|
||||
`include "dv_fcov_macros.svh"
|
||||
|
||||
module ibex_id_stage #(
|
||||
parameter bit RV32E = 0,
|
||||
|
@ -990,6 +991,17 @@ module ibex_id_stage #(
|
|||
assign perf_mul_wait_o = stall_multdiv & mult_en_dec;
|
||||
assign perf_div_wait_o = stall_multdiv & div_en_dec;
|
||||
|
||||
//////////
|
||||
// FCOV //
|
||||
//////////
|
||||
|
||||
`FCOV_SIGNAL_GEN_IF(logic, rf_rd_wb_hz,
|
||||
(gen_stall_mem.rf_rd_a_hz | gen_stall_mem.rf_rd_b_hz) & instr_valid_i, WritebackStage)
|
||||
`FCOV_SIGNAL(logic, branch_taken,
|
||||
instr_executing & (id_fsm_q == FIRST_CYCLE) & branch_decision_i);
|
||||
`FCOV_SIGNAL(logic, branch_not_taken,
|
||||
instr_executing & (id_fsm_q == FIRST_CYCLE) & ~branch_decision_i);
|
||||
|
||||
////////////////
|
||||
// Assertions //
|
||||
////////////////
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
|
||||
`include "prim_assert.sv"
|
||||
`include "dv_fcov_macros.svh"
|
||||
|
||||
module ibex_load_store_unit
|
||||
(
|
||||
|
@ -494,6 +495,12 @@ module ibex_load_store_unit
|
|||
|
||||
assign busy_o = (ls_fsm_cs != IDLE);
|
||||
|
||||
//////////
|
||||
// FCOV //
|
||||
//////////
|
||||
`FCOV_SIGNAL(logic, ls_error_exception, (load_err_o | store_err_o) & ~pmp_err_q);
|
||||
`FCOV_SIGNAL(logic, ls_pmp_exception, (load_err_o | store_err_o) & pmp_err_q);
|
||||
|
||||
////////////////
|
||||
// Assertions //
|
||||
////////////////
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
|
||||
`include "prim_assert.sv"
|
||||
`include "dv_fcov_macros.svh"
|
||||
|
||||
module ibex_wb_stage #(
|
||||
parameter bit WritebackStage = 1'b0
|
||||
|
@ -172,5 +173,7 @@ module ibex_wb_stage #(
|
|||
assign rf_wdata_wb_o = rf_wdata_wb_mux_we[0] ? rf_wdata_wb_mux[0] : rf_wdata_wb_mux[1];
|
||||
assign rf_we_wb_o = |rf_wdata_wb_mux_we;
|
||||
|
||||
`FCOV_SIGNAL_GEN_IF(logic, wb_valid, g_writeback_stage.wb_valid_q, WritebackStage)
|
||||
|
||||
`ASSERT(RFWriteFromOneSourceOnly, $onehot0(rf_wdata_wb_mux_we))
|
||||
endmodule
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue