Skip to content

Commit

Permalink
Functional coverage : Create Unmapped instruction and exceptions cove…
Browse files Browse the repository at this point in the history
…rage models (#1818)
  • Loading branch information
AyoubJalali authored Feb 9, 2024
1 parent 3f8649e commit 22e9173
Show file tree
Hide file tree
Showing 5 changed files with 396 additions and 3 deletions.
12 changes: 9 additions & 3 deletions verif/env/uvme/cov/uvme_cva6_cov_model.sv
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ class uvme_cva6_cov_model_c extends uvm_component;
uvme_cva6_cntxt_c cntxt;

// Components
uvme_cvxif_covg_c cvxif_covg;
uvme_isa_cov_model_c isa_covg;
uvme_cva6_config_covg_c config_covg;
uvme_cvxif_covg_c cvxif_covg;
uvme_isa_cov_model_c isa_covg;
uvme_cva6_config_covg_c config_covg;
uvme_illegal_instr_cov_model_c illegal_covg;
uvme_exception_cov_model_c exception_covg;

//
uvm_analysis_export#(uvma_clknrst_mon_trn_c) reset_export;
Expand Down Expand Up @@ -104,7 +106,11 @@ function void uvme_cva6_cov_model_c::build_phase(uvm_phase phase);

if (cfg.cov_isa_model_enabled) begin
isa_covg = uvme_isa_cov_model_c::type_id::create("isa_covg", this);
illegal_covg = uvme_illegal_instr_cov_model_c::type_id::create("illegal_covg", this);
exception_covg = uvme_exception_cov_model_c::type_id::create("exception_covg", this);
uvm_config_db#(uvme_cva6_cfg_c)::set(this, "isa_covg", "cfg", cfg);
uvm_config_db#(uvme_cva6_cfg_c)::set(this, "illegal_covg", "cfg", cfg);
uvm_config_db#(uvme_cva6_cfg_c)::set(this, "exception_covg", "cfg", cfg);
end

uvm_config_db#(uvme_cva6_cntxt_c)::set(this, "cvxif_covg", "cntxt", cntxt);
Expand Down
154 changes: 154 additions & 0 deletions verif/env/uvme/cov/uvme_exception_covg.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
//
// Copyright 2024 OpenHW Group
// Copyright 2024 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

// Original Author: Ayoub JALALI ([email protected])

covergroup cg_exception(
string name,
bit pmp_supported,
bit unaligned_access_supported,
bit mode_u_supported,
bit mode_s_supported,
bit debug_supported
) with function sample (
uvma_isacov_instr_c instr
);
option.per_instance = 1;
option.name = name;

cp_exception: coverpoint instr.cause {
bins NO_EXCEPTION = {0} iff (!instr.trap);

bins BREAKPOINT = {3} iff (instr.trap);
bins BREAKPOINT_EXC_RAISED = (NO_EXCEPTION => BREAKPOINT => NO_EXCEPTION);

bins ILLEGAL_INSTR = {2} iff (instr.trap);
bins ILLEGAL_INSTR_EXC_RAISED = (NO_EXCEPTION => ILLEGAL_INSTR => NO_EXCEPTION);

ignore_bins IGN_ADDR_MISALIGNED_EXC = {0, 4, 6} iff (unaligned_access_supported);
bins INSTR_ADDR_MISALIGNED = {0} iff (instr.trap);
bins INSTR_ADDR_MISALIGNED_EXC_RAISED = (NO_EXCEPTION => INSTR_ADDR_MISALIGNED => NO_EXCEPTION);

bins LD_ADDR_MISALIGNED = {4} iff (instr.trap);
bins LD_ADDR_MISALIGNED_EXC_RAISED = (NO_EXCEPTION => LD_ADDR_MISALIGNED => NO_EXCEPTION);

bins ST_ADDR_MISALIGNED = {6} iff (instr.trap);
bins ST_ADDR_MISALIGNED_EXC_RAISED = (NO_EXCEPTION => ST_ADDR_MISALIGNED => NO_EXCEPTION);

ignore_bins IGN_ACCESS_FAULT_EXC = {1,5,7} iff (!pmp_supported);
bins INSTR_ACCESS_FAULT = {1} iff (instr.trap);
bins INSTR_ACCESS_FAULT_EXC_RAISED = (NO_EXCEPTION => INSTR_ACCESS_FAULT => NO_EXCEPTION);

bins LD_ACCESS_FAULT = {5} iff (instr.trap);
bins LD_ACCESS_FAULT_EXC_RAISED = (NO_EXCEPTION => LD_ACCESS_FAULT => NO_EXCEPTION);

bins ST_ACCESS_FAULT = {7} iff (instr.trap);
bins ST_ACCESS_FAULT_EXC_RAISED = (NO_EXCEPTION => ST_ACCESS_FAULT => NO_EXCEPTION);

ignore_bins IGN_ENV_CALL_UMODE = {8} iff (!mode_u_supported);
bins ENV_CALL_UMODE = {8} iff (instr.trap);
bins ENV_CALL_UMODE_EXC_RAISED = (NO_EXCEPTION => ENV_CALL_UMODE => NO_EXCEPTION);

ignore_bins IGN_ENV_CALL_SMODE = {9} iff (!mode_s_supported);
bins ENV_CALL_SMODE = {9} iff (instr.trap);
bins ENV_CALL_SMODE_EXC_RAISED = (NO_EXCEPTION => ENV_CALL_SMODE => NO_EXCEPTION);

bins ENV_CALL_MMODE = {11} iff (instr.trap);
bins ENV_CALL_MMODE_EXC_RAISED = (NO_EXCEPTION => ENV_CALL_MMODE => NO_EXCEPTION);

bins INSTR_PAGE_FAULT = {12} iff (instr.trap);
bins INSTR_PAGE_FAULT_EXC_RAISED = (NO_EXCEPTION => INSTR_PAGE_FAULT => NO_EXCEPTION);

bins LOAD_PAGE_FAULT = {13} iff (instr.trap);
bins LOAD_PAGE_FAULT_EXC_RAISED = (NO_EXCEPTION => LOAD_PAGE_FAULT => NO_EXCEPTION);

bins STORE_PAGE_FAULT = {15} iff (instr.trap);
bins STORE_PAGE_FAULT_EXC_RAISED = (NO_EXCEPTION => STORE_PAGE_FAULT => NO_EXCEPTION);

ignore_bins IGN_DEBUG_REQUEST = {24} iff (!debug_supported);
bins DEBUG_REQUEST = {24} iff (instr.trap);
bins DEBUG_REQUEST_EXC_RAISED = (NO_EXCEPTION => DEBUG_REQUEST => NO_EXCEPTION);

}

endgroup : cg_exception

class uvme_exception_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_exception_cov_model_c)

//Exception Covergroup
cg_exception exception_cg;

extern function new(string name = "exception_cov_model", uvm_component parent = null);
extern function void build_phase(uvm_phase phase);
extern task run_phase(uvm_phase phase);

endclass : uvme_exception_cov_model_c

function uvme_exception_cov_model_c::new(string name = "exception_cov_model", uvm_component parent = null);

super.new(name, parent);

endfunction : new

function void uvme_exception_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

exception_cg = new("exception_cg",
.pmp_supported(cfg.pmp_supported),
.unaligned_access_supported(cfg.unaligned_access_supported),
.mode_u_supported(cfg.mode_u_supported),
.mode_s_supported(cfg.mode_s_supported),
.debug_supported(cfg.debug_supported));

mon_trn_fifo = new("mon_trn_fifo" , this);

endfunction : build_phase

task uvme_exception_cov_model_c::run_phase(uvm_phase phase);

super.run_phase(phase);

`uvm_info("EXCEPTION_COVG", "The Exception env coverage model is running", UVM_LOW);

forever begin
mon_trn_fifo.get(mon_trn);
exception_cg.sample(mon_trn.instr);
end

endtask : run_phase

213 changes: 213 additions & 0 deletions verif/env/uvme/cov/uvme_illegal_instr_covg.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
//
// Copyright 2024 OpenHW Group
// Copyright 2024 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

// Original Author: Ayoub JALALI ([email protected])

covergroup cg_illegal_i(
string name
) with function sample (
uvma_isacov_instr_c instr
);
option.per_instance = 1;
option.name = name;

cp_illegal_opcode: coverpoint instr.rvfi.insn[6:0] {
bins ILLEGAL_OPCODE[3] = {[0:$]} with (!(item inside {legal_i_opcode}));
}

cp_illegal_funct3: coverpoint instr.rvfi.insn[14:12] { // if the instruction has funct3
bins ILLEGAL_FUNCT3[3] = {[0:$]} iff (instr.rvfi.insn[6:0] inside legal_i_opcode); //with the right opcode
bins ILLEGAL_NOPCODE_FUNCT3[3] = {[0:$]} iff (!(instr.rvfi.insn[6:0] inside legal_i_opcode)); //with the wrong opcode
}

cp_illegal_funct7: coverpoint instr.rvfi.insn[31:25] { // if the instruction has funct7
bins ILLEGAL_FUNCT7[3] = {[0:$]} with (!(item inside legal_i_funct7)) iff (instr.rvfi.insn[6:0] inside legal_i_opcode); //with the right opcode
bins ILLEGAL_NOPCODE_FUNCT7[3] = {[0:$]} with (!(item inside legal_i_funct7)) iff (!(instr.rvfi.insn[6:0] inside legal_i_opcode)); //with the wrong opcode
}

endgroup : cg_illegal_i

covergroup cg_illegal_m(
string name
) with function sample (
uvma_isacov_instr_c instr
);
option.per_instance = 1;
option.name = name;

cp_illegal_opcode: coverpoint instr.rvfi.insn[6:0] {
bins ILLEGAL_OPCODE[2] = {[0:$]} with (item != 7'b0110011);
}

cp_illegal_funct3: coverpoint instr.rvfi.insn[14:12] { // if the instruction has funct3
bins ILLEGAL_FUNCT3[3] = {[0:$]} iff (!(instr.rvfi.insn[6:0] == 7'b0110011 &
instr.rvfi.insn[31:25] == 7'b0000001)); //with the wrong opcode or the wrong funct7
}

cp_illegal_funct7: coverpoint instr.rvfi.insn[31:25] { // if the instruction has funct7
bins ILLEGAL_FUNCT7[3] = {[0:$]} with (item != 7'b0000001) iff (instr.rvfi.insn[6:0] == 7'b0110011); //with the right opcode
bins ILLEGAL_NOPCODE_FUNCT7[3] = {[0:$]} with (item != 7'b0000001) iff (instr.rvfi.insn[6:0] != 7'b0110011); //with the wrong opcode
}

endgroup : cg_illegal_m

covergroup cg_illegal_zicsr(
string name
) with function sample (
uvma_isacov_instr_c instr
);
option.per_instance = 1;
option.name = name;

cp_illegal_opcode: coverpoint instr.rvfi.insn[6:0] {
bins ILLEGAL_OPCODE[2] = {[0:$]} with (item != 7'b1110011);
}

cp_illegal_funct3: coverpoint instr.rvfi.insn[14:12] { // if the instruction has funct3
bins ILLEGAL_FUNCT3 = {0,4} iff (instr.rvfi.insn[6:0] == 7'b1110011); //with the right opcode
bins ILLEGAL_NOPCODE_FUNCT3 = {0,4} iff (instr.rvfi.insn[6:0] != 7'b1110011); //with the wrong opcode
}

endgroup : cg_illegal_zicsr

covergroup cg_illegal_zifencei(
string name
) with function sample (
uvma_isacov_instr_c instr
);
option.per_instance = 1;
option.name = name;

cp_illegal_opcode: coverpoint instr.rvfi.insn[6:0] {
bins ILLEGAL_OPCODE[2] = {[0:$]} with (item != 7'b0001111);
}

cp_illegal_funct3: coverpoint instr.rvfi.insn[14:12] { // if the instruction has funct3
bins ILLEGAL_FUNCT3[3] = {[0:$]} with (item != 7'b001) iff (instr.rvfi.insn[6:0] == 7'b0001111); //with the right opcode
bins ILLEGAL_NOPCODE_FUNCT3[3] = {[0:$]} with (item != 7'b001) iff (instr.rvfi.insn[6:0] != 7'b0001111); //with the wrong opcode
}

endgroup : cg_illegal_zifencei

class uvme_illegal_instr_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_illegal_instr_cov_model_c)

//Covergroup of Illegal instrcution
cg_illegal_i illegal_i_cg;
cg_illegal_m illegal_m_cg;
cg_illegal_zicsr illegal_zicsr_cg;
cg_illegal_zifencei illegal_zifencei_cg;

extern function new(string name = "illegal_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_illegal_instr_cov_model_c

function uvme_illegal_instr_cov_model_c::new(string name = "illegal_cov_model", uvm_component parent = null);

super.new(name, parent);

endfunction : new

function void uvme_illegal_instr_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_i_supported) begin
illegal_i_cg = new("illegal_i_cg");
end

if (cfg.ext_m_supported) begin
illegal_m_cg = new("illegal_m_cg");
end

if (cfg.ext_zicsr_supported) begin
illegal_zicsr_cg = new("illegal_zicsr_cg");
end

if (cfg.ext_zifencei_supported) begin
illegal_zifencei_cg = new("illegal_zifencei_cg");
end

mon_trn_fifo = new("mon_trn_fifo" , this);

endfunction : build_phase

task uvme_illegal_instr_cov_model_c::run_phase(uvm_phase phase);

super.run_phase(phase);

`uvm_info("ILLEGAL_INSTR_COVG", "The illegal instruction 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_illegal_instr_cov_model_c::sample_isa (uvma_isacov_instr_c instr);

string instr_name;
logic have_sampled = 0;

logic is_illegal_instr = (instr.cause == 2);

if (!have_sampled && is_illegal_instr && cfg.ext_i_supported) begin
have_sampled = 1;
illegal_i_cg.sample(instr);
end
if (!have_sampled && is_illegal_instr && cfg.ext_m_supported) begin
have_sampled = 1;
illegal_m_cg.sample(instr);
end
if (!have_sampled && is_illegal_instr && cfg.ext_zicsr_supported) begin
have_sampled = 1;
illegal_zicsr_cg.sample(instr);
end
if (!have_sampled && is_illegal_instr && cfg.ext_zifencei_supported) begin
have_sampled = 1;
illegal_zifencei_cg.sample(instr);
end
if (!have_sampled && is_illegal_instr) begin
`uvm_error("ILLEGAL_INSTR", $sformatf("Could not sample instruction: %h", instr.rvfi.insn));
end

endtask : sample_isa

Loading

0 comments on commit 22e9173

Please sign in to comment.