diff --git a/verif/env/uvme/cov/uvme_cva6_cov_model.sv b/verif/env/uvme/cov/uvme_cva6_cov_model.sv index 599145f21..0ea720ec8 100644 --- a/verif/env/uvme/cov/uvme_cva6_cov_model.sv +++ b/verif/env/uvme/cov/uvme_cva6_cov_model.sv @@ -31,6 +31,7 @@ class uvme_cva6_cov_model_c extends uvm_component; // Components uvme_cvxif_covg_c cvxif_covg; + uvme_isa_cov_model_c isa_covg; `uvm_component_utils_begin(uvme_cva6_cov_model_c) `uvm_field_object(cfg , UVM_DEFAULT) @@ -87,8 +88,16 @@ function void uvme_cva6_cov_model_c::build_phase(uvm_phase phase); `uvm_fatal("CNTXT", "Context handle is null") end - cvxif_covg = uvme_cvxif_covg_c::type_id::create("cvxif_covg", this); - uvm_config_db#(uvme_cva6_cfg_c)::set(this, "cvxif_covg", "cfg", cfg); + if (cfg.cov_cvxif_model_enabled) begin + cvxif_covg = uvme_cvxif_covg_c::type_id::create("cvxif_covg", this); + uvm_config_db#(uvme_cva6_cfg_c)::set(this, "cvxif_covg", "cfg", cfg); + end + + if (cfg.cov_isa_model_enabled) begin + isa_covg = uvme_isa_cov_model_c::type_id::create("isa_covg", this); + uvm_config_db#(uvme_cva6_cfg_c)::set(this, "isa_covg", "cfg", cfg); + end + uvm_config_db#(uvme_cva6_cntxt_c)::set(this, "cvxif_covg", "cntxt", cntxt); endfunction : build_phase diff --git a/verif/env/uvme/cov/uvme_isa_covg.sv b/verif/env/uvme/cov/uvme_isa_covg.sv new file mode 100644 index 000000000..a4c865a1a --- /dev/null +++ b/verif/env/uvme/cov/uvme_isa_covg.sv @@ -0,0 +1,193 @@ +// +// Copyright 2023 OpenHW Group +// Copyright 2023 Thales +// +// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://solderpad.org/licenses/ +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 + +covergroup cg_rtype( + string name, + bit reg_crosses_enabled, + bit reg_hazards_enabled, + bit rs1_is_signed, + bit rs2_is_signed, + bit rd_is_signed +) with function sample ( + uvma_isacov_instr_c instr +); + option.per_instance = 1; + option.name = name; + + cp_rs1: coverpoint instr.rvfi.rs1_addr; + cp_rs2: coverpoint instr.rvfi.rs2_addr; + cp_rd: coverpoint instr.rvfi.rd1_addr; + + cp_rd_rs1_hazard: coverpoint instr.rvfi.rd1_addr { + ignore_bins IGN_RS1_HAZARD_OFF = {[0:$]} `WITH (!reg_hazards_enabled); + bins RD[] = {[0:31]} iff (instr.rvfi.rd1_addr == instr.rvfi.rs1_addr); + } + + cp_rd_rs2_hazard: coverpoint instr.rvfi.rd1_addr { + ignore_bins IGN_RS2_HAZARD_OFF = {[0:$]} `WITH (!reg_hazards_enabled); + bins RD[] = {[0:31]} iff (instr.rvfi.rd1_addr == instr.rvfi.rs2_addr); + } + + cross_rd_rs1_rs2: cross cp_rd, cp_rs1, cp_rs2 { + ignore_bins IGN_OFF = cross_rd_rs1_rs2 `WITH (!reg_crosses_enabled); + } + + cp_rs1_value: coverpoint instr.get_instr_value_type(instr.rvfi.rs1_rdata, $bits(instr.rvfi.rs1_rdata), 1) { + ignore_bins POS_OFF = {POSITIVE} `WITH (!rs1_is_signed); + ignore_bins NEG_OFF = {NEGATIVE} `WITH (!rs1_is_signed); + ignore_bins NON_ZERO_OFF = {NON_ZERO} `WITH (rs1_is_signed); + } + + cp_rs2_value: coverpoint instr.get_instr_value_type(instr.rvfi.rs2_rdata, $bits(instr.rvfi.rs2_rdata), 1) { + ignore_bins POS_OFF = {POSITIVE} `WITH (!rs2_is_signed); + ignore_bins NEG_OFF = {NEGATIVE} `WITH (!rs2_is_signed); + ignore_bins NON_ZERO_OFF = {NON_ZERO} `WITH (rs2_is_signed); + } + + cross_rs1_rs2_value: cross cp_rs1_value, cp_rs2_value; + + cp_rd_value: coverpoint instr.get_instr_value_type(instr.rvfi.rd1_wdata, $bits(instr.rvfi.rd1_wdata), 1) { + ignore_bins POS_OFF = {POSITIVE} `WITH (!rd_is_signed); + ignore_bins NEG_OFF = {NEGATIVE} `WITH (!rd_is_signed); + ignore_bins NON_ZERO_OFF = {NON_ZERO} `WITH (rd_is_signed); + } + + `ISACOV_CP_BITWISE(cp_rs1_toggle, instr.rvfi.rs1_rdata, 1) + `ISACOV_CP_BITWISE(cp_rs2_toggle, instr.rvfi.rs2_rdata, 1) + `ISACOV_CP_BITWISE(cp_rd_toggle, instr.rvfi.rd1_wdata, 1) + +endgroup : cg_rtype + +class uvme_isa_cov_model_c extends uvm_component; + + /* + * Class members + */ + // Objects + uvme_cva6_cfg_c cfg ; + uvme_cva6_cntxt_c cntxt ; + + // TLM + uvm_tlm_analysis_fifo#(uvma_isacov_mon_trn_c) mon_trn_fifo; + + uvma_isacov_mon_trn_c mon_trn; + + `uvm_component_utils(uvme_isa_cov_model_c) + + //Zicond + cg_rtype rv32zicond_czero_eqz_cg; + cg_rtype rv32zicond_czero_nez_cg; + + extern function new(string name = "isa_cov_model", uvm_component parent = null); + extern function void build_phase(uvm_phase phase); + extern task run_phase(uvm_phase phase); + + extern task sample_isa(uvma_isacov_instr_c instr); + +endclass : uvme_isa_cov_model_c + +function uvme_isa_cov_model_c::new(string name = "isa_cov_model", uvm_component parent = null); + + super.new(name, parent); + +endfunction : new + +function void uvme_isa_cov_model_c::build_phase(uvm_phase phase); + + super.build_phase(phase); + + void'(uvm_config_db#(uvme_cva6_cfg_c)::get(this, "", "cfg", cfg)); + if (!cfg) begin + `uvm_fatal("CFG", "Configuration handle is null") + end + + if (cfg.ext_zicond_supported) begin + rv32zicond_czero_eqz_cg = new("rv32zicond_czero_eqz_cg", + .reg_crosses_enabled(cfg.isacov_cfg.reg_crosses_enabled), + .reg_hazards_enabled(cfg.isacov_cfg.reg_hazards_enabled), + .rs1_is_signed(1), + .rs2_is_signed(1), + .rd_is_signed(1)); + + rv32zicond_czero_nez_cg = new("rv32zicond_czero_nez_cg", + .reg_crosses_enabled(cfg.isacov_cfg.reg_crosses_enabled), + .reg_hazards_enabled(cfg.isacov_cfg.reg_hazards_enabled), + .rs1_is_signed(1), + .rs2_is_signed(1), + .rd_is_signed(1)); + end + + mon_trn_fifo = new("mon_trn_fifo" , this); + +endfunction : build_phase + +task uvme_isa_cov_model_c::run_phase(uvm_phase phase); + + super.run_phase(phase); + + `uvm_info("ISACOVG", "The isa env coverage model is running", UVM_LOW); + + forever begin + mon_trn_fifo.get(mon_trn); + sample_isa(mon_trn.instr); + end + +endtask : run_phase + +task uvme_isa_cov_model_c::sample_isa (uvma_isacov_instr_c instr); + + string instr_name; + logic have_sampled = 0; + + logic is_ecall_or_ebreak = + ( instr.rvfi.trap[ 8:3] == 8) || // Ecall U-mode + ( instr.rvfi.trap[ 8:3] == 11) || // Ecall M-mode + ((instr.rvfi.trap[ 8:3] == 3) && (instr.rvfi.trap[13:12] == 0)) || // Ebreak (ebreakm==0) + ( instr.rvfi.trap[11:9] == 1); // Ebreak to* or in D-mode (* ebreakm==1) + logic is_normal_instr = + (instr.rvfi.trap[0] == 0) || // No rvfi_trap + ((instr.rvfi.trap[11:9] == 4) && (instr.rvfi.trap[1] == 0)); // Single-step, without any exception + + bit [63:0] instr_isa = $signed(instr.rvfi.insn); + + bit [6:0] opcode = instr_isa [6:0]; + bit [6:0] func7 = instr_isa [31:25]; + bit [2:0] func3 = instr_isa [14:12]; + + if (opcode == 7'b0110011) begin + if (func7 == 7'b0000111) begin + if (func3 == 3'b101) begin + instr_name = "CZERO_EQZ"; + end + else if (func3 == 3'b111) begin + instr_name = "CZERO_NEZ"; + end + end + end + + if (!have_sampled && is_normal_instr && cfg.ext_zicond_supported) begin + have_sampled = 1; + case (instr_name) + "CZERO_EQZ": rv32zicond_czero_eqz_cg.sample(instr); + "CZERO_NEZ": rv32zicond_czero_nez_cg.sample(instr); + default: have_sampled = 0; + endcase + end + +endtask : sample_isa + diff --git a/verif/env/uvme/uvme_cva6_cfg.sv b/verif/env/uvme/uvme_cva6_cfg.sv index 1479d98b8..0ae8c0302 100644 --- a/verif/env/uvme/uvme_cva6_cfg.sv +++ b/verif/env/uvme/uvme_cva6_cfg.sv @@ -33,6 +33,8 @@ class uvme_cva6_cfg_c extends uvma_core_cntrl_cfg_c; rand bit scoreboarding_enabled; rand bit cov_model_enabled; + rand bit cov_cvxif_model_enabled; + rand bit cov_isa_model_enabled; rand bit trn_log_enabled; rand int unsigned sys_clk_period; @@ -43,12 +45,16 @@ class uvme_cva6_cfg_c extends uvma_core_cntrl_cfg_c; rand uvma_rvfi_cfg_c#(ILEN,XLEN) rvfi_cfg; rand uvma_isacov_cfg_c isacov_cfg; + // Zicond extension + rand bit ext_zicond_supported; + `uvm_object_utils_begin(uvme_cva6_cfg_c) `uvm_field_int ( enabled , UVM_DEFAULT ) `uvm_field_enum(uvm_active_passive_enum, is_active , UVM_DEFAULT ) `uvm_field_int ( scoreboarding_enabled , UVM_DEFAULT ) `uvm_field_int ( cov_model_enabled , UVM_DEFAULT ) `uvm_field_int ( trn_log_enabled , UVM_DEFAULT ) + `uvm_field_int ( ext_zicond_supported , UVM_DEFAULT ) `uvm_field_int ( sys_clk_period , UVM_DEFAULT + UVM_DEC) `uvm_field_object(clknrst_cfg, UVM_DEFAULT) @@ -65,12 +71,12 @@ class uvme_cva6_cfg_c extends uvma_core_cntrl_cfg_c; constraint defaults_cons { - soft enabled == 0; - soft is_active == UVM_ACTIVE; - soft scoreboarding_enabled == 1; - soft cov_model_enabled == 1; - soft trn_log_enabled == 1; - soft sys_clk_period == uvme_cva6_sys_default_clk_period; // see uvme_cva6_constants.sv + soft enabled == 1; + soft is_active == UVM_ACTIVE; + soft scoreboarding_enabled == 1; + soft cov_model_enabled == 1; + soft trn_log_enabled == 1; + soft sys_clk_period == uvme_cva6_sys_default_clk_period; // see uvme_cva6_constants.sv } constraint cvxif_feature { //CV32A60X do not support dual read & write also the memory interface @@ -103,6 +109,7 @@ class uvme_cva6_cfg_c extends uvma_core_cntrl_cfg_c; ext_zbt_supported == 0; ext_zifencei_supported == 1; ext_zicsr_supported == 1; + ext_zicond_supported == 1; mode_s_supported == 0; mode_u_supported == 0; @@ -165,6 +172,9 @@ class uvme_cva6_cfg_c extends uvma_core_cntrl_cfg_c; if (cov_model_enabled) { cvxif_cfg.cov_model_enabled == 1; isacov_cfg.cov_model_enabled == 1; + //env coverage models + cov_cvxif_model_enabled == 1; + cov_isa_model_enabled == 1; } } diff --git a/verif/env/uvme/uvme_cva6_env.sv b/verif/env/uvme/uvme_cva6_env.sv index 045f032ee..658283303 100644 --- a/verif/env/uvme/uvme_cva6_env.sv +++ b/verif/env/uvme/uvme_cva6_env.sv @@ -336,7 +336,12 @@ endtask function void uvme_cva6_env_c::connect_coverage_model(); - cvxif_agent.monitor.req_ap.connect(cov_model.cvxif_covg.req_item_fifo.analysis_export); + if (cfg.cov_cvxif_model_enabled) begin + cvxif_agent.monitor.req_ap.connect(cov_model.cvxif_covg.req_item_fifo.analysis_export); + end + if (cfg.cov_isa_model_enabled) begin + isacov_agent.monitor.ap.connect(cov_model.isa_covg.mon_trn_fifo.analysis_export); + end foreach (rvfi_agent.instr_mon_ap[i]) begin rvfi_agent.instr_mon_ap[i].connect(isacov_agent.monitor.rvfi_instr_imp); end diff --git a/verif/env/uvme/uvme_cva6_pkg.sv b/verif/env/uvme/uvme_cva6_pkg.sv index 5b0908c63..7f6ba520e 100644 --- a/verif/env/uvme/uvme_cva6_pkg.sv +++ b/verif/env/uvme/uvme_cva6_pkg.sv @@ -67,6 +67,7 @@ package uvme_cva6_pkg; `include "uvme_cva6_sb.sv" `include "uvme_cva6_vsqr.sv" `include "uvme_cvxif_covg.sv" + `include "uvme_isa_covg.sv" `include "uvme_cva6_cov_model.sv" `include "uvme_cva6_env.sv"