UVM环境介绍
HEAD commitID: 1f968ef
// Copyright 2020 OpenHW Group
// Copyright 2020 Datum Technology Corporation
// Copyright 2020 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.
`ifndef __UVMA_INTERRUPT_IF_SV__
`define __UVMA_INTERRUPT_IF_SV__
/**
* Encapsulates all signals and clocking of Interrupt interface. Used by
* monitor and driver.
*/
interface uvma_interrupt_if
(
);
// ---------------------------------------------------------------------------
// Interface wires
// ---------------------------------------------------------------------------
wire clk;
wire reset_n;
wire [31:0] irq;
wire irq_ack;
wire [4:0] irq_id;
// Used to time true interrupt entry with tracer instruction retirement
wire deferint;
wire ovp_cpu_state_stepi;
// -------------------------------------------------------------------
// Testbench control
// ---------------------------------------------------------------------------
// -------------------------------------------------------------------
bit is_active; // Set to active drive the interrupt lines
bit [31:0] irq_drv; // TB interrupt driver
// -------------------------------------------------------------------
// Begin module code
// -------------------------------------------------------------------
// Mux in driver to irq lines
assign irq = is_active ? irq_drv : 1'b0;
initial begin
is_active = 1'b0;
irq_drv = '0;
end
/**
* Used by target DUT.
*/
clocking dut_cb @(posedge clk or reset_n);
endclocking : dut_cb
/**
* Used by uvma_interrupt_drv_c.
*/
clocking drv_cb @(posedge clk or reset_n);
input #1step irq_ack,
irq_id;
output irq_drv;
endclocking : drv_cb
/**
* Used by uvma_interrupt_mon_c.
*/
clocking mon_cb @(posedge clk or reset_n);
input #1step irq_ack,
irq_id,
irq_drv;
endclocking : mon_cb
modport dut_mp (clocking dut_cb);
modport active_mp (clocking drv_cb);
modport passive_mp(clocking mon_cb);
endinterface : uvma_interrupt_if
`endif // __UVMA_INTERRUPT_IF_SV__
lib/uvm_agents/uvma_interrupt/uvma_interrupt_if.sv
1. 简要介绍
该文件是中断验证环境的接口定义文件,主要功能包括:
- 定义中断接口的所有信号
- 提供时钟和复位信号
- 支持驱动和监控功能
- 包含测试平台控制逻辑
2. 接口介绍
2.1 接口信号定义
wire clk;
wire reset_n;
wire [31:0] irq;
wire irq_ack;
wire [4:0] irq_id;
- 代码介绍:定义核心接口信号
- 信号说明:
clk
:时钟信号reset_n
:复位信号(低有效)irq
:32位中断请求信号irq_ack
:中断响应信号irq_id
:中断ID标识
2.2 测试控制信号
bit is_active;
bit [31:0] irq_drv;
- 代码介绍:定义测试平台控制信号
- 功能:
is_active
:控制是否主动驱动中断irq_drv
:测试平台驱动值
3. 参数介绍
3.1 时钟块定义
clocking dut_cb @(posedge clk or reset_n);
endclocking
- 参数说明:DUT端时钟块
- 特点:同步于时钟上升沿或复位信号
3.2 驱动时钟块
clocking drv_cb @(posedge clk or reset_n);
input #1step irq_ack, irq_id;
output irq_drv;
endclocking
- 参数说明:驱动器时钟块
- 时序特性:
- 输入信号有1step延迟
- 输出信号无延迟
4. 模块实现介绍
4.1 中断信号多路选择
assign irq = is_active ? irq_drv : 1'b0;
- 代码分析:
- 根据is_active选择驱动源
- 非主动模式时输出0
- 关键点:确保安全默认值
4.2 初始值设置
initial begin
is_active = 1'b0;
irq_drv = '0;
end
- 代码分析:初始化测试控制信号
- 设计特点:防止未定义行为
5. 总结
该接口文件具有以下特点:
- 完整的中断信号定义
- 清晰的时钟域划分
- 安全的测试控制逻辑
- 灵活的驱动选择机制
- 标准化的接口实现
作为验证环境的基础组件,它为中断验证提供了可靠的接口定义,确保验证组件能够正确访问DUT信号。
// Copyright 2020 OpenHW Group
// Copyright 2020 Datum Technology Corporation
// Copyright 2020 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.
`ifndef __UVMA_INTERRUPT_MON_TRN_LOGGER_SV__
`define __UVMA_INTERRUPT_MON_TRN_LOGGER_SV__
/**
* Component writing Interrupt monitor transactions interrupt data to disk as plain text.
*/
class uvma_interrupt_mon_trn_logger_c extends uvml_logs_mon_trn_logger_c#(
.T_TRN (uvma_interrupt_mon_trn_c),
.T_CFG (uvma_interrupt_cfg_c ),
.T_CNTXT(uvma_interrupt_cntxt_c )
);
`uvm_component_utils(uvma_interrupt_mon_trn_logger_c)
/**
* Default constructor.
*/
function new(string name="uvma_interrupt_mon_trn_logger", uvm_component parent=null);
super.new(name, parent);
endfunction : new
/**
* Writes contents of t to disk
*/
virtual function void write(uvma_interrupt_mon_trn_c t);
// TODO Implement uvma_interrupt_mon_trn_logger_c::write()
// Ex: fwrite($sformatf(" %t | %08h | %02b | %04d | %02h |", $realtime(), t.a, t.b, t.c, t.d));
endfunction : write
/**
* Writes log header to disk
*/
virtual function void print_header();
// TODO Implement uvma_interrupt_mon_trn_logger_c::print_header()
// Ex: fwrite("----------------------------------------------");
// fwrite(" TIME | FIELD A | FIELD B | FIELD C | FIELD D ");
// fwrite("----------------------------------------------");
endfunction : print_header
endclass : uvma_interrupt_mon_trn_logger_c
/**
* Component writing INTERRUPT monitor transactions interrupt data to disk as JavaScript Object Notation (JSON).
*/
class uvma_interrupt_mon_trn_logger_json_c extends uvma_interrupt_mon_trn_logger_c;
`uvm_component_utils(uvma_interrupt_mon_trn_logger_json_c)
/**
* Set file extension to '.json'.
*/
function new(string name="uvma_interrupt_mon_trn_logger_json", uvm_component parent=null);
super.new(name, parent);
fextension = "json";
endfunction : new
/**
* Writes contents of t to disk.
*/
virtual function void write(uvma_interrupt_mon_trn_c t);
// TODO Implement uvma_interrupt_mon_trn_logger_json_c::write()
// Ex: fwrite({"{",
// $sformatf("\"time\":\"%0t\",", $realtime()),
// $sformatf("\"a\":%h," , t.a ),
// $sformatf("\"b\":%b," , t.b ),
// $sformatf("\"c\":%d," , t.c ),
// $sformatf("\"d\":%h," , t.c ),
// "},"});
endfunction : write
/**
* Empty function.
*/
virtual function void print_header();
// Do nothing: JSON files do not use headers.
endfunction : print_header
endclass : uvma_interrupt_mon_trn_logger_json_c
`endif // __UVMA_INTERRUPT_MON_TRN_LOGGER_SV__
lib/uvm_agents/uvma_interrupt/uvma_interrupt_mon_trn_logger.sv
1. 简要介绍
该文件是中断验证环境的监控事务日志记录器实现,主要功能包括:
- 记录中断监控事务到磁盘
- 支持文本和JSON两种格式
- 提供自定义日志头功能
- 实现事务格式转换
2. 接口介绍
2.1 基类定义
class uvma_interrupt_mon_trn_logger_c extends uvml_logs_mon_trn_logger_c#(
.T_TRN(uvma_interrupt_mon_trn_c),
.T_CFG(uvma_interrupt_cfg_c),
.T_CNTXT(uvma_interrupt_cntxt_c)
);
- 代码介绍:定义基础日志记录器类
- 模板参数:
- T_TRN:监控事务类型
- T_CFG:配置类型
- T_CNTXT:上下文类型
2.2 JSON记录器
class uvma_interrupt_mon_trn_logger_json_c extends uvma_interrupt_mon_trn_logger_c;
function new(string name="uvma_interrupt_mon_trn_logger_json", uvm_component parent=null);
fextension = "json";
endfunction
endclass
- 代码介绍:定义JSON格式记录器
- 特点:设置文件扩展名为.json
3. 参数介绍
3.1 构造函数
function new(string name="uvma_interrupt_mon_trn_logger", uvm_component parent=null);
super.new(name, parent);
endfunction
- 参数说明:初始化日志记录器
- 关键点:调用父类构造函数
4. 模块实现介绍
4.1 事务写入函数
virtual function void write(uvma_interrupt_mon_trn_c t);
// TODO Implement write logic
// Ex: fwrite($sformatf(" %t | %08h |", $realtime(), t.a));
endfunction
- 代码分析:
- 预留事务写入实现
- 示例展示格式化输出
4.2 日志头函数
virtual function void print_header();
// TODO Implement header
// Ex: fwrite("---------------------");
endfunction
- 代码分析:定义日志头格式
- 设计特点:可自定义分隔线
5. 总结
该日志记录器组件具有以下特点:
- 标准化的UVM实现
- 灵活的输出格式支持
- 清晰的接口定义
- 可扩展的设计架构
作为验证环境的辅助组件,它为中断监控事务提供了可靠的记录能力,便于后续分析和调试。
// Copyright 2020 OpenHW Group
// Copyright 2020 Datum Technology Corporation
// Copyright 2020 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.
`ifndef __UVMA_INTERRUPT_MON_TRN_SV__
`define __UVMA_INTERRUPT_MON_TRN_SV__
/**
* Object rebuilt from the Interrupt monitor Analog of uvma_interrupt_seq_item_c.
*/
class uvma_interrupt_mon_trn_c extends uvml_trn_mon_trn_c;
uvma_interrupt_mon_action_enum action;
int unsigned id;
`uvm_object_utils_begin(uvma_interrupt_mon_trn_c)
`uvm_field_enum(uvma_interrupt_mon_action_enum, action, UVM_DEFAULT)
`uvm_field_int(id, UVM_DEFAULT)
`uvm_object_utils_end
/**
* Default constructor.
*/
extern function new(string name="uvma_interrupt_mon_trn");
endclass : uvma_interrupt_mon_trn_c
`pragma protect begin
function uvma_interrupt_mon_trn_c::new(string name="uvma_interrupt_mon_trn");
super.new(name);
endfunction : new
`pragma protect end
`endif // __UVMA_INTERRUPT_MON_TRN_SV__
lib/uvm_agents/uvma_interrupt/uvma_interrupt_mon_trn.sv
1. 简要介绍
该文件是中断验证环境的监控事务类实现,主要功能包括:
- 封装中断监控事务数据
- 记录中断动作类型
- 存储中断ID标识
- 提供UVM自动化支持
2. 接口介绍
2.1 类定义
class uvma_interrupt_mon_trn_c extends uvml_trn_mon_trn_c;
- 代码介绍:定义监控事务类,继承自基础监控事务类
- 功能:作为中断监控数据的容器
2.2 UVM宏
`uvm_object_utils_begin(uvma_interrupt_mon_trn_c)
`uvm_field_enum(uvma_interrupt_mon_action_enum, action, UVM_DEFAULT)
`uvm_field_int(id, UVM_DEFAULT)
`uvm_object_utils_end
- 代码介绍:注册UVM对象
- 功能:支持自动化操作如复制、比较等
3. 参数介绍
3.1 动作类型
uvma_interrupt_mon_action_enum action;
- 参数说明:记录中断动作类型
- 数据类型:枚举类型
3.2 中断ID
int unsigned id;
- 参数说明:存储中断标识符
- 范围:无符号整型
4. 模块实现介绍
4.1 构造函数
function uvma_interrupt_mon_trn_c::new(string name="uvma_interrupt_mon_trn");
super.new(name);
endfunction
- 代码分析:
- 调用父类构造函数
- 初始化事务对象
- 关键点:确保正确继承父类行为
5. 总结
该监控事务类具有以下特点:
- 标准的UVM实现
- 简洁的数据封装
- 完善的自化支持
- 可扩展的设计架构
作为验证环境的基础数据结构,它为中断监控提供了可靠的数据表示能力,确保监控数据能够正确传递和处理。
//
// Copyright 2020 OpenHW Group
// Copyright 2020 Datum Technology Corporation
// Copyright 2020 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.
//
`ifndef __UVMA_INTERRUPT_MON_SV__
`define __UVMA_INTERRUPT_MON_SV__
/**
* Component sampling transactions from a Clock & Reset virtual interface
* (uvma_interrupt_if).
*/
class uvma_interrupt_mon_c extends uvm_monitor;
// Objects
uvma_interrupt_cfg_c cfg;
uvma_interrupt_cntxt_c cntxt;
// TLM
// This analysis port will fire when the irq_ack_o is seen (core acknowledges the interrupt)
uvm_analysis_port#(uvma_interrupt_mon_trn_c) ap;
// This analysis port will fire when the first instruction in the ISR is retired (i.e. the MTVEC location)
uvm_analysis_port#(uvma_interrupt_mon_trn_c) ap_iss;
`uvm_component_utils_begin(uvma_interrupt_mon_c)
`uvm_field_object(cfg , UVM_DEFAULT)
`uvm_field_object(cntxt, UVM_DEFAULT)
`uvm_component_utils_end
/**
* Default constructor.
*/
extern function new(string name="uvma_interrupt_mon", uvm_component parent=null);
/**
* 1. Ensures cfg & cntxt handles are not null.
* 2. Builds ap.
*/
extern virtual function void build_phase(uvm_phase phase);
/**
* Oversees monitoring via monitor_clk() and monitor_reset() tasks in parallel
* forks.
*/
extern virtual task run_phase(uvm_phase phase);
/**
* Publish a monitor transactin when interrupt is taken.
*/
extern virtual task monitor_irq();
/**
* Publish a monitor transaction when interrupt is taken (delayed until the first instruction of the ISR is retired)
*/
extern virtual task monitor_irq_iss();
endclass : uvma_interrupt_mon_c
function uvma_interrupt_mon_c::new(string name="uvma_interrupt_mon", uvm_component parent=null);
super.new(name, parent);
endfunction : new
function void uvma_interrupt_mon_c::build_phase(uvm_phase phase);
super.build_phase(phase);
void'(uvm_config_db#(uvma_interrupt_cfg_c)::get(this, "", "cfg", cfg));
if (cfg == null) begin
`uvm_fatal("CFG", "Configuration handle is null")
end
void'(uvm_config_db#(uvma_interrupt_cntxt_c)::get(this, "", "cntxt", cntxt));
if (cntxt == null) begin
`uvm_fatal("CNTXT", "Context handle is null")
end
ap = new("ap", this);
ap_iss = new("ap_iss", this);
endfunction : build_phase
task uvma_interrupt_mon_c::run_phase(uvm_phase phase);
super.run_phase(phase);
if (cfg.enabled) begin
while (1) begin
wait (cntxt.vif.reset_n === 1'b0);
wait (cntxt.vif.reset_n === 1'b1);
fork begin
// To maintain random thread stability launch iss thread always, but it will exit immediately if no iss configured
fork
monitor_irq();
monitor_irq_iss();
join_none
wait (cntxt.vif.reset_n === 1'b0);
disable fork;
end
join
end
end
endtask : run_phase
task uvma_interrupt_mon_c::monitor_irq();
while(1) begin
@(cntxt.vif.mon_cb);
if (cntxt.vif.mon_cb.irq_ack) begin
uvma_interrupt_mon_trn_c mon_trn = uvma_interrupt_mon_trn_c::type_id::create("mon_irq_trn");
mon_trn.action = UVMA_INTERRUPT_MON_ACTION_IRQ;
mon_trn.id = cntxt.vif.mon_cb.irq_id;
ap.write(mon_trn);
end
end
endtask : monitor_irq
task uvma_interrupt_mon_c::monitor_irq_iss();
if ($test$plusargs("USE_ISS")) begin
while(1) begin
@(cntxt.vif.mon_cb);
if (cntxt.vif.mon_cb.irq_ack) begin
uvma_interrupt_mon_trn_c mon_trn = uvma_interrupt_mon_trn_c::type_id::create("mon_irq_trn");
mon_trn.action = UVMA_INTERRUPT_MON_ACTION_IRQ;
mon_trn.id = cntxt.vif.mon_cb.irq_id;
// Wait for the ISS to enter
wait (cntxt.vif.deferint == 1'b0);
wait (cntxt.vif.ovp_cpu_state_stepi == 1'b1);
ap_iss.write(mon_trn);
end
end
end
endtask : monitor_irq_iss
`endif // __UVMA_INTERRUPT_MON_SV__
lib/uvm_agents/uvma_interrupt/uvma_interrupt_mon.sv
1. 简要介绍
该文件是中断验证环境的监控器实现,主要功能包括:
- 采样中断接口信号
- 生成监控事务
- 通过TLM端口发送监控数据
- 支持指令集模拟器(ISS)集成
2. 接口介绍
2.1 类定义
class uvma_interrupt_mon_c extends uvm_monitor;
- 代码介绍:定义监控器类,继承自UVM基础监控器类
- 功能:作为标准UVM组件实现接口监控
2.2 TLM端口
uvm_analysis_port#(uvma_interrupt_mon_trn_c) ap;
uvm_analysis_port#(uvma_interrupt_mon_trn_c) ap_iss;
- 代码介绍:定义两个分析端口
- 功能:
ap
:用于中断响应监控ap_iss
:用于ISS集成监控
3. 参数介绍
3.1 配置对象
uvma_interrupt_cfg_c cfg;
- 参数说明:存储验证配置
- 获取方式:通过UVM配置数据库获取
3.2 上下文对象
uvma_interrupt_cntxt_c cntxt;
- 参数说明:存储运行时状态
- 包含内容:虚拟接口和事件触发器
4. 模块实现介绍
4.1 run_phase实现
task run_phase(uvm_phase phase);
while (1) begin
wait (cntxt.vif.reset_n === 1'b0);
wait (cntxt.vif.reset_n === 1'b1);
fork
monitor_irq();
monitor_irq_iss();
join_none
end
endtask
- 代码分析:
- 等待复位信号变化
- 并行启动监控任务
- 确保复位时终止监控
4.2 中断监控任务
task monitor_irq();
if (cntxt.vif.mon_cb.irq_ack) begin
uvma_interrupt_mon_trn_c mon_trn = uvma_interrupt_mon_trn_c::type_id::create("mon_irq_trn");
mon_trn.action = UVMA_INTERRUPT_MON_ACTION_IRQ;
mon_trn.id = cntxt.vif.mon_cb.irq_id;
ap.write(mon_trn);
end
endtask
- 代码分析:
- 检测中断响应信号
- 创建监控事务
- 通过端口发送事务
5. 总结
该监控器组件具有以下特点:
- 完整的UVM标准实现
- 双通道监控架构
- 可靠的复位处理机制
- 灵活的ISS集成支持
- 可扩展的设计架构
作为验证环境的关键组件,它为中断接口提供了全面的监控能力,确保验证过程能够正确捕获DUT行为。
//
// Copyright 2020 OpenHW Group
// Copyright 2020 Datum Technology Corporation
// Copyright 2020 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.
//
`ifndef __UVMA_INTERRUPT_SQR_SV__
`define __UVMA_INTERRUPT_SQR_SV__
/**
* Component running Clock & Reset sequences extending uvma_interrupt_seq_base_c.
* Provides sequence items for uvma_interrupt_drv_c.
*/
class uvma_interrupt_sqr_c extends uvm_sequencer#(
.REQ(uvma_interrupt_seq_item_c),
.RSP(uvma_interrupt_seq_item_c)
);
// Objects
uvma_interrupt_cfg_c cfg;
uvma_interrupt_cntxt_c cntxt;
`uvm_component_utils_begin(uvma_interrupt_sqr_c)
`uvm_field_object(cfg , UVM_DEFAULT)
`uvm_field_object(cntxt, UVM_DEFAULT)
`uvm_component_utils_end
/**
* Default constructor.
*/
extern function new(string name="uvma_interrupt_sqr", uvm_component parent=null);
/**
* Ensures cfg & cntxt handles are not null
*/
extern virtual function void build_phase(uvm_phase phase);
endclass : uvma_interrupt_sqr_c
function uvma_interrupt_sqr_c::new(string name="uvma_interrupt_sqr", uvm_component parent=null);
super.new(name, parent);
endfunction : new
function void uvma_interrupt_sqr_c::build_phase(uvm_phase phase);
super.build_phase(phase);
void'(uvm_config_db#(uvma_interrupt_cfg_c)::get(this, "", "cfg", cfg));
if (cfg == null) begin
`uvm_fatal("CFG", "Configuration handle is null")
end
void'(uvm_config_db#(uvma_interrupt_cntxt_c)::get(this, "", "cntxt", cntxt));
if (cntxt == null) begin
`uvm_fatal("CNTXT", "Context handle is null")
end
endfunction : build_phase
`endif // __UVMA_INTERRUPT_SQR_SV__
lib/uvm_agents/uvma_interrupt/uvma_interrupt_sqr.sv
1. 简要介绍
该文件是中断验证环境的序列器实现,主要功能包括:
- 运行中断序列
- 为驱动器提供序列项
- 管理配置和上下文
- 协调序列执行流程
2. 接口介绍
2.1 类定义
class uvma_interrupt_sqr_c extends uvm_sequencer#(
.REQ(uvma_interrupt_seq_item_c),
.RSP(uvma_interrupt_seq_item_c)
);
- 代码介绍:定义序列器类,继承自参数化的UVM序列器基类
- 模板参数:
- REQ:请求序列项类型
- RSP:响应序列项类型
3. 参数介绍
3.1 配置对象
uvma_interrupt_cfg_c cfg;
- 参数说明:存储验证配置
- 获取方式:通过UVM配置数据库获取
3.2 上下文对象
uvma_interrupt_cntxt_c cntxt;
- 参数说明:存储运行时状态
- 包含内容:虚拟接口和事件触发器
4. 模块实现介绍
4.1 build_phase实现
function void build_phase(uvm_phase phase);
void'(uvm_config_db#(uvma_interrupt_cfg_c)::get(this, "", "cfg", cfg));
if (cfg == null) begin
`uvm_fatal("CFG", "Configuration handle is null")
end
endfunction
- 代码分析:
- 从UVM数据库获取配置
- 空指针检查报fatal错误
- 关键点:确保配置有效性
5. 总结
该序列器组件具有以下特点:
- 完整的UVM标准实现
- 清晰的序列管理接口
- 可靠的配置管理
- 可扩展的设计架构
作为验证环境的关键组件,它为中断序列执行提供了可靠的基础设施,确保验证激励能够正确生成和传递。
// Copyright 2021 OpenHW Group
// Copyright 2021 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.
//
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
covergroup cg_executed_type(
string name,
instr_name_t instr_name
) with function sample (
uvma_isacov_instr_c instr
);
option.per_instance = 1;
option.name = name;
cp_executed: coverpoint instr.name {
bins EXECUTED = {
[0:$]};
}
endgroup : cg_executed_type
// There isn't a defined instruction type/format (yet in Zbb)
// The 2-source register format is mapped to R=type (from I spec)
// The 1-source register format is encompassed here
covergroup cg_zb_rstype(
string name,
bit reg_crosses_enabled,
bit reg_hazards_enabled,
bit rs_is_signed,
bit rd_is_signed
) with function sample (
uvma_isacov_instr_c instr
);
option.per_instance = 1;
option.name = name;
cp_rs: coverpoint instr.rs1;
cp_rd: coverpoint instr.rd;
cp_rd_rs_hazard: coverpoint instr.rd {
ignore_bins IGN_RS_HAZARD_OFF = {
[0:$]} with (!reg_hazards_enabled);
bins RD[] = {
[0:31]} iff (instr.rd == instr.rs1);
}
cross_rd_rs: cross cp_rd, cp_rs {
ignore_bins IGN_OFF = cross_rd_rs with (!reg_crosses_enabled);
}
cp_rs_value: coverpoint instr.rs1_value_type {
ignore_bins POS_OFF = {
POSITIVE} with (!rs_is_signed);
ignore_bins NEG_OFF = {
NEGATIVE} with (!rs_is_signed);
ignore_bins NON_ZERO_OFF = {
NON_ZERO} with (rs_is_signed);
}
cp_rd_value: coverpoint instr.rd_value_type {
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_rs_toggle, instr.rs1_value, 1)
`ISACOV_CP_BITWISE(cp_rd_toggle, instr.rd_value, 1)
endgroup : cg_zb_rstype
covergroup cg_zb_itype_shift (
string name,
bit reg_crosses_enabled,
bit reg_hazards_enabled,
bit rs_is_signed,
bit rd_is_signed
) with function sample (
uvma_isacov_instr_c instr
);
option.per_instance = 1;
option.name = name;
cp_rs: coverpoint instr.rs1;
cp_rd: coverpoint instr.rd;
cp_rd_rs_hazard: coverpoint instr.rd {
ignore_bins IGN_RS1_HAZARD_OFF = {
[0:$]} with (!reg_hazards_enabled);
bins RD[] = {
[0:31]} iff (instr.rd == instr.rs1);
}
cross_rd_rs: cross cp_rd, cp_rs {
ignore_bins IGN_OFF = cross_rd_rs with (!reg_crosses_enabled);
}
cp_rs_value: coverpoint instr.rs1_value_type {
ignore_bins POS_OFF = {
POSITIVE} with (!rs_is_signed);
ignore_bins NEG_OFF = {
NEGATIVE} with (!rs_is_signed);
ignore_bins NON_ZERO_OFF = {
NON_ZERO} with (rs_is_signed);
}
cp_shamt: coverpoint instr.immi[4:0] {
bins SHAMT[] = {
[0:31]};
}
cp_rd_value: coverpoint instr.rd_value_type {
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_rs_toggle, instr.rs1_value, 1)
`ISACOV_CP_BITWISE(cp_rd_toggle, instr.rd_value, 1)
endgroup : cg_zb_itype_shift
covergroup cg_zb_rstype_ext(
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.rs1;
cp_rs2: coverpoint instr.rs2;
cp_rd: coverpoint instr.rd;
cp_rd_rs1_hazard: coverpoint instr.rd {
ignore_bins IGN_RS1_HAZARD_OFF = {
[0:$]} with (!reg_hazards_enabled);
bins RD[] = {
[0:31]} iff (instr.rd == instr.rs1);
}
cp_rd_rs2_hazard: coverpoint instr.rd {
ignore_bins IGN_RS1_HAZARD_OFF = {
[0:$]} with (!reg_hazards_enabled);
bins RD[] = {
[0:31]} iff (instr.rd == instr.rs2);
}
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.rs1_value_type {
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_index: coverpoint instr.rs2[4:0] {
bins INDEX[] = {
[0:31]};
}
cp_rd_value: coverpoint instr.rd_value {
bins ZERO = {
0};
bins ONE = {
1};
}
`ISACOV_CP_BITWISE(cp_rs1_toggle, instr.rs1_value, 1)
`ISACOV_CP_BITWISE(cp_rs2_toggle, instr.rs2_value, 1)
endgroup : cg_zb_rstype_ext
covergroup cg_zb_itype_ext(
string name,
bit reg_crosses_enabled,
bit reg_hazards_enabled,
bit rs_is_signed,
bit rd_is_signed
) with function sample (
uvma_isacov_instr_c instr
);
option.per_instance = 1;
option.name = name;
cp_rs: coverpoint instr.rs1;
cp_rd: coverpoint instr.rd;
cp_rd_rs_hazard: coverpoint instr.rd {
ignore_bins IGN_RS1_HAZARD_OFF = {
[0:$]} with (!reg_hazards_enabled);
bins RD[] = {
[0:31]} iff (instr.rd == instr.rs1);
}
cross_rd_rs: cross cp_rd, cp_rs {
ignore_bins IGN_OFF = cross_rd_rs with (!reg_crosses_enabled);
}
cp_rs_value: coverpoint instr.rs1_value_type {
ignore_bins POS_OFF = {
POSITIVE} with (!rs_is_signed);
ignore_bins NEG_OFF = {
NEGATIVE} with (!rs_is_signed);
ignore_bins NON_ZERO_OFF = {
NON_ZERO} with (rs_is_signed);
}
cp_shift: coverpoint instr.immi[4:0] {
bins SHIFT[] = {
[0:31]};
}
cp_rd_value: coverpoint instr.rd_value {
bins ZERO = {
0};
bins ONE = {
1};
}
`ISACOV_CP_BITWISE(cp_rs_toggle, instr.rs1_value, 1)
endgroup : cg_zb_itype_ext
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.rs1;
cp_rs2: coverpoint instr.rs2;
cp_rd: coverpoint instr.rd;
cp_rd_rs1_hazard: coverpoint instr.rd {
ignore_bins IGN_RS1_HAZARD_OFF = {
[0:$]} with (!reg_hazards_enabled);
bins RD[] = {
[0:31]} iff (instr.rd == instr.rs1);
}
cp_rd_rs2_hazard: coverpoint instr.rd {
ignore_bins IGN_RS2_HAZARD_OFF = {
[0:$]} with (!reg_hazards_enabled);
bins RD[] = {
[0:31]} iff (instr.rd == instr.rs2);
}
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.rs1_value_type {
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.rs2_value_type {
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.rd_value_type {
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.rs1_value, 1)
`ISACOV_CP_BITWISE(cp_rs2_toggle, instr.rs2_value, 1)
`ISACOV_CP_BITWISE(cp_rd_toggle, instr.rd_value, 1)
endgroup : cg_rtype
covergroup cg_rtype_lr_w(
string name,
bit reg_hazards_enabled,
bit rs1_is_signed,
bit rd_is_signed,
bit unaligned_access_amo_supported
) with function sample (
uvma_isacov_instr_c instr
);
option.per_instance = 1;
option.name = name;
cp_rs1: coverpoint instr.rs1;
cp_rd: coverpoint instr.rd;
cp_rd_rs1_hazard: coverpoint instr.rd {
ignore_bins IGN_RS1_HAZARD_OFF = {
[0:$]} with (!reg_hazards_enabled);
bins RD[] = {
[0:31]} iff (instr.rd == instr.rs1);
}
cp_rs1_value: coverpoint instr.rs1_value_type {
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_rd_value: coverpoint instr.rd_value_type {
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);
}
cp_align_word: coverpoint (instr.rvfi.mem_addr[1:0]) {
ignore_bins IGN_OFF = {
[0:$]} with (!unaligned_access_amo_supported);
bins ALIGNED = {
0};
bins UNALIGNED[] = {
[1:3]};
}
`ISACOV_CP_BITWISE(cp_rs1_toggle, instr.rs1_value, 1)
`ISACOV_CP_BITWISE(cp_rd_toggle, instr.rd_value, 1)
endgroup : cg_rtype_lr_w
covergroup cg_rtype_sc_w (
string name,
bit reg_crosses_enabled,
bit reg_hazards_enabled,
bit rs1_is_signed,
bit rs2_is_signed,
bit unaligned_access_amo_supported
) with function sample (
uvma_isacov_instr_c instr
);
option.per_instance = 1;
option.name = name;
cp_rs1: coverpoint instr.rs1;
cp_rs2: coverpoint instr.rs2;
cp_rd: coverpoint instr.rd;
cp_rd_rs1_hazard: coverpoint instr.rd {
ignore_bins IGN_RS1_HAZARD_OFF = {
[0:$]} with (!reg_hazards_enabled);
bins RD[] = {
[0:31]} iff (instr.rd == instr.rs1);
}
cp_rd_rs2_hazard: coverpoint instr.rd {
ignore_bins IGN_RS2_HAZARD_OFF = {
[0:$]} with (!reg_hazards_enabled);
bins RD[] = {
[0:31]} iff (instr.rd == instr.rs2);
}
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.rs1_value_type {
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.rs2_value_type {
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_align_word: coverpoint (instr.rvfi.mem_addr[1:0]) {
ignore_bins IGN_OFF = {
[0:$]} with (!unaligned_access_amo_supported);
bins ALIGNED = {
0};
bins UNALIGNED[] = {
[1:3]};
}
`ISACOV_CP_BITWISE(cp_rs1_toggle, instr.rs1_value, 1)
`ISACOV_CP_BITWISE(cp_rs2_toggle, instr.rs2_value, 1)
`ISACOV_CP_BITWISE_0_0(cp_rd_toggle, instr.rd_value, 1)
// Note: "More specific failure codes might be defined in future versions or extensions to the ISA."
endgroup : cg_rtype_sc_w
covergroup cg_rtype_amo (
string name,
bit reg_crosses_enabled,
bit reg_hazards_enabled,
bit rs1_is_signed,
bit rd_is_signed,
bit unaligned_access_amo_supported
) with function sample (
uvma_isacov_instr_c instr
);
option.per_instance = 1;
option.name = name;
cp_rs1: coverpoint instr.rs1;
cp_rs2: coverpoint instr.rs2;
cp_rd: coverpoint instr.rd;
cp_rd_rs1_hazard: coverpoint instr.rd {
ignore_bins IGN_RS1_HAZARD_OFF = {
[0:$]} with (!reg_hazards_enabled);
bins RD[] = {
[0:31]} iff (instr.rd == instr.rs1);
}
cp_rd_rs2_hazard: coverpoint instr.rd {
ignore_bins IGN_RS2_HAZARD_OFF = {
[0:$]} with (!reg_hazards_enabled);
bins RD[] = {
[0:31]} iff (instr.rd == instr.rs2);
}
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.rs1_value_type {
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_align_word: coverpoint (instr.rvfi.mem_addr[1:0]) {
ignore_bins IGN_OFF = {
[0:$]} with (!unaligned_access_amo_supported);
bins ALIGNED = {
0};
bins UNALIGNED[] = {
[1:3]};
}
`ISACOV_CP_BITWISE(cp_rs1_toggle, instr.rs1_value, 1)
`ISACOV_CP_BITWISE(cp_rs2_toggle, instr.rs2_value, 1)
`ISACOV_CP_BITWISE(cp_rd_toggle, instr.rd_value, 1)
endgroup : cg_rtype_amo
covergroup cg_rtype_slt(
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.rs1;
cp_rs2: coverpoint instr.rs2;
cp_rd: coverpoint instr.rd;
cp_rd_rs1_hazard: coverpoint instr.rd {
ignore_bins IGN_RS1_HAZARD_OFF = {
[0:$]} with (!reg_hazards_enabled);
bins RD[] = {
[0:31]} iff (instr.rd == instr.rs1);
}
cp_rd_rs2_hazard: coverpoint instr.rd {
ignore_bins IGN_RS2_HAZARD_OFF = {
[0:$]} with (!reg_hazards_enabled);
bins RD[] = {
[0:31]} iff (instr.rd == instr.rs2);
}
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.rs1_value_type {
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.rs2_value_type {
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.rd_value {
bins SLT[] = {
[0:1]};
}
`ISACOV_CP_BITWISE(cp_rs1_toggle<