Skip to content

Commit

Permalink
Merge pull request #2263 from silabs-hfegran/dev_hf_clic_cov
Browse files Browse the repository at this point in the history
Fixed irq->rvfi-connections, added clic model, naming cleanup
  • Loading branch information
silabs-robin authored Oct 30, 2023
2 parents 1340dc3 + 2a4aa3a commit da6f525
Show file tree
Hide file tree
Showing 6 changed files with 240 additions and 8 deletions.
219 changes: 219 additions & 0 deletions cv32e40s/env/uvme/cov/uvme_clic_covg.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
// Copyright 2020 OpenHW Group
// Copyright 2020 Datum Technology Corporation
// Copyright 2023 Silicon Labs, Inc.
//
// 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.

covergroup cg_clic_irq_entry(string name,
bit ext_m_supported,
bit ext_c_supported,
bit ext_zba_supported,
bit ext_zbb_supported,
bit ext_zbc_supported,
bit ext_zbs_supported,
bit ext_a_supported)
with function sample(uvma_isacov_instr_c instr);
option.name = name;
`per_instance_fcov
cp_irq : coverpoint(instr.name) {
`ISACOV_IGN_BINS
// These instructions will enter the exception handler which will gate off any interrupts
// by disabling MSIE immediately upon execution
ignore_bins ebreak_excp = { EBREAK };
ignore_bins c_ebreak_excp = { C_EBREAK };
ignore_bins ecal_excp = { ECALL };
}
endgroup : cg_clic_irq_entry

covergroup cg_clic_wfi_entry(string name,
bit ext_m_supported,
bit ext_c_supported,
bit ext_zba_supported,
bit ext_zbb_supported,
bit ext_zbc_supported,
bit ext_zbs_supported,
bit ext_a_supported)
with function sample(uvma_isacov_instr_c instr);
option.name = name;
`per_instance_fcov
cp_wfi : coverpoint instr.name {
`ISACOV_IGN_BINS
}
endgroup : cg_clic_wfi_entry

covergroup cg_clic_irq_exit(string name,
bit ext_m_supported,
bit ext_c_supported,
bit ext_zba_supported,
bit ext_zbb_supported,
bit ext_zbc_supported,
bit ext_zbs_supported,
bit ext_a_supported)
with function sample(uvma_isacov_instr_c instr);
option.name = name;
`per_instance_fcov
cp_irq : coverpoint instr.name {
`ISACOV_IGN_BINS
// Should not exit an IRQ into an MRET (usually interrupts are disabled at end of ISR)
ignore_bins mret_excp = { MRET };
// Should not exit an IRQ into a DRET
ignore_bins dret_excp = { DRET };
}
endgroup : cg_clic_irq_exit

covergroup cg_clic_wfi_exit(string name,
bit ext_m_supported,
bit ext_c_supported,
bit ext_zba_supported,
bit ext_zbb_supported,
bit ext_zbc_supported,
bit ext_zbs_supported,
bit ext_a_supported)
with function sample(uvma_isacov_instr_c instr);
option.name = name;
`per_instance_fcov
cp_wfi : coverpoint instr.name {
`ISACOV_IGN_BINS
}
endgroup : cg_clic_wfi_exit

class uvme_clic_covg extends uvm_component;

`uvm_analysis_imp_decl(_clic)
`uvm_analysis_imp_decl(_isacov)

string info_tag = "CLICIRQCOVG";
uvma_isacov_mon_trn_c last_instr_trn;
uvma_core_cntrl_cfg_c cfg;

int unsigned irq_nested_count; // Count interrupt entry count for functional coverage

cg_clic_irq_entry irq_entry_cg;
cg_clic_wfi_entry wfi_entry_cg;
cg_clic_irq_exit irq_exit_cg;
cg_clic_wfi_exit wfi_exit_cg;

uvm_analysis_imp_clic#(uvma_rvfi_instr_seq_item_c#(ILEN,XLEN), uvme_clic_covg) clic_mon_export;
uvm_analysis_imp_isacov#(uvma_isacov_mon_trn_c, uvme_clic_covg) isacov_mon_export;

`uvm_component_utils(uvme_clic_covg)

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

extern function void write_clic(uvma_rvfi_instr_seq_item_c#(ILEN,XLEN) trn);
extern function void write_isacov(uvma_isacov_mon_trn_c trn);

endclass : uvme_clic_covg

function uvme_clic_covg::new(string name = "clic_covg", uvm_component parent = null);
super.new(name, parent);

clic_mon_export = new("clic_mon_export", this);
isacov_mon_export = new("isacov_mon_export", this);

endfunction : new

function void uvme_clic_covg::build_phase(uvm_phase phase);
super.build_phase(phase);

void'(uvm_config_db#(uvma_core_cntrl_cfg_c)::get(this, "", "cfg", cfg));
if (!cfg) begin
`uvm_fatal("CFG", "Configuration handle is null")
end

irq_entry_cg = new("clic_irq_entry",
.ext_m_supported(cfg.ext_m_supported),
.ext_c_supported(cfg.ext_c_supported),
.ext_zba_supported(cfg.ext_zba_supported),
.ext_zbb_supported(cfg.ext_zbb_supported),
.ext_zbc_supported(cfg.ext_zbc_supported),
.ext_zbs_supported(cfg.ext_zbs_supported),
.ext_a_supported(cfg.ext_a_supported));

wfi_entry_cg = new("clic_wfi_entry",
.ext_m_supported(cfg.ext_m_supported),
.ext_c_supported(cfg.ext_c_supported),
.ext_zba_supported(cfg.ext_zba_supported),
.ext_zbb_supported(cfg.ext_zbb_supported),
.ext_zbc_supported(cfg.ext_zbc_supported),
.ext_zbs_supported(cfg.ext_zbs_supported),
.ext_a_supported(cfg.ext_a_supported));

irq_exit_cg = new("clic_irq_exit",
.ext_m_supported(cfg.ext_m_supported),
.ext_c_supported(cfg.ext_c_supported),
.ext_zba_supported(cfg.ext_zba_supported),
.ext_zbb_supported(cfg.ext_zbb_supported),
.ext_zbc_supported(cfg.ext_zbc_supported),
.ext_zbs_supported(cfg.ext_zbs_supported),
.ext_a_supported(cfg.ext_a_supported));

wfi_exit_cg = new("clic_wfi_exit",
.ext_m_supported(cfg.ext_m_supported),
.ext_c_supported(cfg.ext_c_supported),
.ext_zba_supported(cfg.ext_zba_supported),
.ext_zbb_supported(cfg.ext_zbb_supported),
.ext_zbc_supported(cfg.ext_zbc_supported),
.ext_zbs_supported(cfg.ext_zbs_supported),
.ext_a_supported(cfg.ext_a_supported));
endfunction : build_phase

task uvme_clic_covg::run_phase(uvm_phase phase);

super.run_phase(phase);

`uvm_info(info_tag, "The clic interrupt coverage model is running", UVM_LOW);

endtask : run_phase

function void uvme_clic_covg::write_clic(uvma_rvfi_instr_seq_item_c#(ILEN,XLEN) trn);

if (cfg.clic_interrupt_enable) begin
if (trn.intr.intr == 1 && trn.intr.interrupt == 1 && last_instr_trn != null) begin
`uvm_info(info_tag, $sformatf("IRQ entered from %s", last_instr_trn.instr.name.name()), UVM_DEBUG)
irq_entry_cg.sample(last_instr_trn.instr);
irq_nested_count++;
end
end

endfunction : write_clic

function void uvme_clic_covg::write_isacov(uvma_isacov_mon_trn_c trn);

if (cfg.clic_interrupt_enable) begin
// If this is a WFI, then sample the last instruction
if (trn.instr.name == WFI && last_instr_trn != null) begin
wfi_entry_cg.sample(last_instr_trn.instr);
end

// If last instruction was WFI, then sample exit WFI coverage
if (last_instr_trn != null && last_instr_trn.instr.name == WFI) begin
`uvm_info(info_tag, $sformatf("WFI Exit: instruction is %s", trn.instr.name.name()), UVM_DEBUG)
wfi_exit_cg.sample(trn.instr);
end

// For each mret decrement the interrupt count
if (last_instr_trn != null && last_instr_trn.instr.name == MRET && irq_nested_count) begin
`uvm_info(info_tag, $sformatf("IRQ exited to %s", trn.instr.name.name()), UVM_DEBUG)
irq_exit_cg.sample(trn.instr);
irq_nested_count--;
end

// When an instruction is sampled, just save the handle here
// It will be sampled when an interrupt or wfi event occurs
last_instr_trn = trn;
end

endfunction : write_isacov
4 changes: 4 additions & 0 deletions cv32e40s/env/uvme/cov/uvme_cv32e40s_cov_model.sv
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class uvme_cv32e40s_cov_model_c extends uvm_component;
uvme_cv32e40s_cfg_c cfg;
uvme_cv32e40s_cntxt_c cntxt;

uvme_clic_covg clic_covg;
uvme_interrupt_covg interrupt_covg;
uvme_debug_covg debug_covg;
uvme_exceptions_covg exceptions_covg;
Expand Down Expand Up @@ -82,6 +83,9 @@ function void uvme_cv32e40s_cov_model_c::build_phase(uvm_phase phase);
`uvm_fatal("CNTXT", "Context handle is null")
end

clic_covg = uvme_clic_covg::type_id::create("clic_covg", this);
uvm_config_db#(uvma_core_cntrl_cfg_c)::set(this, "clic_covg", "cfg", cfg);

interrupt_covg = uvme_interrupt_covg::type_id::create("interrupt_covg", this);
uvm_config_db#(uvma_core_cntrl_cfg_c)::set(this, "interrupt_covg", "cfg", cfg);

Expand Down
18 changes: 11 additions & 7 deletions cv32e40s/env/uvme/cov/uvme_interrupt_covg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
///////////////////////////////////////////////////////////////////////////////

`uvm_analysis_imp_decl(_interrupt)
`uvm_analysis_imp_decl(_instr)
`uvm_analysis_imp_decl(_isacov)

/*
* Covergroups
Expand Down Expand Up @@ -115,7 +115,7 @@ class uvme_interrupt_covg extends uvm_component;
cg_wfi_exit wfi_exit_cg;

uvm_analysis_imp_interrupt#(uvma_rvfi_instr_seq_item_c#(ILEN,XLEN), uvme_interrupt_covg) interrupt_mon_export;
uvm_analysis_imp_instr#(uvma_isacov_mon_trn_c, uvme_interrupt_covg) instr_mon_export;
uvm_analysis_imp_isacov#(uvma_isacov_mon_trn_c, uvme_interrupt_covg) isacov_mon_export;

`uvm_component_utils(uvme_interrupt_covg);

Expand All @@ -124,7 +124,7 @@ class uvme_interrupt_covg extends uvm_component;
extern task run_phase(uvm_phase phase);

extern function void write_interrupt(uvma_rvfi_instr_seq_item_c#(ILEN,XLEN) trn);
extern function void write_instr(uvma_isacov_mon_trn_c trn);
extern function void write_isacov(uvma_isacov_mon_trn_c trn);

endclass : uvme_interrupt_covg

Expand All @@ -136,7 +136,7 @@ function uvme_interrupt_covg::new(string name = "interrupt_covg", uvm_component


interrupt_mon_export = new("interrupt_mon_export", this);
instr_mon_export = new("instr_mon_export", this);
isacov_mon_export = new("isacov_mon_export", this);

endfunction : new

Expand Down Expand Up @@ -197,16 +197,19 @@ endtask : run_phase

function void uvme_interrupt_covg::write_interrupt(uvma_rvfi_instr_seq_item_c#(ILEN,XLEN) trn);

if (trn.intr == 1 && last_instr_trn != null) begin
if (cfg.basic_interrupt_enable) begin
if (trn.intr.intr == 1 && trn.intr.interrupt == 1 && last_instr_trn != null) begin
`uvm_info("INTERRUPTCOVG", $sformatf("IRQ entered from %s", last_instr_trn.instr.name.name()), UVM_DEBUG)
irq_entry_cg.sample(last_instr_trn.instr);
irq_nested_count++;
end
end

endfunction : write_interrupt

function void uvme_interrupt_covg::write_instr(uvma_isacov_mon_trn_c trn);
function void uvme_interrupt_covg::write_isacov(uvma_isacov_mon_trn_c trn);

if (cfg.basic_interrupt_enable) begin
// If this is a WFI, then sample the last instruction
if (trn.instr.name == WFI && last_instr_trn != null) begin
wfi_entry_cg.sample(last_instr_trn.instr);
Expand All @@ -228,5 +231,6 @@ function void uvme_interrupt_covg::write_instr(uvma_isacov_mon_trn_c trn);
// When an instruction is sampled, just save the handle here
// It will be sampled when an interrupt or wfi event occurs
last_instr_trn = trn;
end

endfunction : write_instr
endfunction : write_isacov
2 changes: 2 additions & 0 deletions cv32e40s/env/uvme/uvme_cv32e40s_cfg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,8 @@ class uvme_cv32e40s_cfg_c extends uvma_core_cntrl_cfg_c;
isacov_cfg.cov_model_enabled == 1;
debug_cfg.cov_model_enabled == 1;
pma_cfg.cov_model_enabled == 1;
clic_cfg.cov_model_enabled == clic_interrupt_enable;
interrupt_cfg.cov_model_enabled == basic_interrupt_enable;
obi_memory_instr_cfg.cov_model_enabled == 1;
obi_memory_data_cfg.cov_model_enabled == 1;
}
Expand Down
4 changes: 3 additions & 1 deletion cv32e40s/env/uvme/uvme_cv32e40s_env.sv
Original file line number Diff line number Diff line change
Expand Up @@ -530,12 +530,14 @@ function void uvme_cv32e40s_env_c::connect_coverage_model();

isacov_agent.monitor.ap.connect(cov_model.exceptions_covg.isacov_mon_export);
isacov_agent.monitor.ap.connect(cov_model.counters_covg.isacov_mon_export);
isacov_agent.monitor.ap.connect(cov_model.interrupt_covg.isacov_mon_export);
isacov_agent.monitor.ap.connect(cov_model.clic_covg.isacov_mon_export);

obi_memory_data_agent.mon_ap.connect(pma_agent.monitor.obi_d_export);
foreach (rvfi_agent.instr_mon_ap[i]) begin
rvfi_agent.instr_mon_ap[i].connect(isacov_agent.monitor.rvfi_instr_imp);
rvfi_agent.instr_mon_ap[i].connect(cov_model.interrupt_covg.interrupt_mon_export);
//rvfi_agent.instr_mon_ap[i].connect(cov_model.clic_covg.clic_mon_export); // TODO: silabs-hfegran
rvfi_agent.instr_mon_ap[i].connect(cov_model.clic_covg.clic_mon_export);
rvfi_agent.instr_mon_ap[i].connect(pma_agent.monitor.rvfi_instr_export);
end

Expand Down
1 change: 1 addition & 0 deletions cv32e40s/env/uvme/uvme_cv32e40s_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ package uvme_cv32e40s_pkg;
`include "uvma_cv32e40s_core_cntrl_drv.sv"
`include "uvma_cv32e40s_core_cntrl_agent.sv"
`include "uvme_interrupt_covg.sv"
`include "uvme_clic_covg.sv"
`include "uvme_debug_covg.sv"
`include "uvme_exceptions_covg.sv"
`include "uvme_counters_covg.sv"
Expand Down

0 comments on commit da6f525

Please sign in to comment.