Title:
[UVM] sv约束到`uvm_do_with
文章目录
1- 前言
transition 文件中对变量进行了范围约束,那么某个tc需要进一步约束,并且这个约束是和之前的约束条件是背驰的,那么应该怎么做?
2- 概念引入
2.1- SV约束
在 SystemVerilog 中,约束(constraints)用于在随机化对象时施加特定的条件,以生成符合期望范围或模式的随机值。约束通常与类的随机变量一起使用,并通过 rand
和 constraint
关键字进行定义。以下是 SystemVerilog 中约束方法的简要介绍:
定义随机变量
首先,要使变量可以被随机化,需要使用 rand
或 randc
关键字声明变量:
class MyClass;
rand bit [7:0] data; // 可随机化的变量
randc bit [3:0] addr; // 可循环随机化的变量
endclass
rand
:声明可随机化的变量。randc
:声明可循环随机化的变量。
定义约束
约束使用 constraint
关键字定义,可以在类内部或外部进行约束:
class MyClass;
rand bit [7:0] data;
rand bit [3:0] addr;
constraint data_c {
data > 100;
data < 200;
}
constraint addr_c {
addr != 0;
}
endclass
内联约束
内联约束是指在调用 randomize
方法时直接指定的约束条件:
MyClass obj = new();
if (!obj.randomize() with { data > 150; addr == 5; }) begin
$display("Randomization failed.");
en
软约束
软约束使用 soft
关键字定义,当其他约束与软约束冲突时,软约束可以被忽略:
constraint soft data_c {
data > 100;
data < 200;
}
禁用约束
可以通过调用 constraint_mode
方法来禁用或启用特定的约束:
obj.data_c.constraint_mode(0); // 禁用 data_c 约束
obj.data_c.constraint_mode(1); // 启用 data_c 约束
约束表达式
约束表达式可以包括条件(if-else)、逻辑操作(&&、||)、算术操作(+、-、*、/)等。例如:
constraint addr_c {
if (data > 150) {
addr == 5;
} else {
addr inside {1, 2, 3, 4};
}
}
使用约束的方法
- 调用
randomize
方法:在类实例上调用randomize
方法时,所有定义的约束会自动应用。
MyClass obj = new();
if (!obj.randomize()) begin
$display("Randomization failed.");
end
- 随机化指定变量:可以在
randomize
方法中指定具体的变量进行随机化。
if (!obj.randomize() with { data > 150; addr == 5; }) begin
$display("Randomization failed.");
end
通过使用这些方法,SystemVerilog 提供了强大的随机化和约束机制,能够在硬件验证中生成符合特定条件的随机输入,从而提高验证的覆盖率和有效性。
2.2- UVM中的``uvm_do_with`
uvm_do_with
是 SystemVerilog UVM (Universal Verification Methodology) 中的一个宏,主要用于简化生成和配置对象(如 transactions)并进行相应的操作。它允许你在一条语句中创建一个对象、应用约束并启动相应的操作。
以下是 uvm_do_with
的使用方式和简要介绍:
语法
uvm_do_with(ITEM, CONSTRAINTS)
ITEM
:指的是要生成和操作的对象。CONSTRAINTS
:是一组附加的约束条件,用于在对象生成时应用。
功能
uvm_do_with
宏会执行以下操作:
- 创建
ITEM
对象(如果尚未创建)。 - 对
ITEM
应用CONSTRAINTS
进行随机化。 - 启动
ITEM
的start_item()
方法(对于uvm_sequence_item
)。 - 执行
ITEM
的finish_item()
方法。
示例
假设你有一个 uvm_sequence_item
派生类 my_sequence_item
,可以使用 uvm_do_with
创建该类的对象并应用约束:
class my_sequence_item extends uvm_sequence_item;
rand bit [7:0] data;
rand bit [3:0] addr;
function new(string name = "my_sequence_item");
super.new(name);
endfunction
endclass
class my_sequence extends uvm_sequence #(my_sequence_item);
function void body();
uvm_do_with(req, {req.data > 128; req.addr < 10;});
endfunction
endclass
在上述示例中:
uvm_do_with(req, {req.data > 128; req.addr < 10;});
会创建req
对象并应用约束req.data > 128
和req.addr < 10
进行随机化,然后启动该对象并完成相应的操作。
3- 实际案例
对于UART协议通讯来说,物理层的UI是很重要的验证功能点,已知ui的协议合理区间是[144us,176us],首先会在transition文件中对ui进行约束。
代码如下:
`ifndef uart_TRANSACTION__SV
`define uart_TRANSACTION__SV
import common_pkg::*;
class uart_transaction extends uvm_sequence_item;
//---> 1-Define variable
rand int ui_ns;//TYP 144~176 us 160_000 ns
//---> 2-Define uvm field
`uvm_object_utils_begin(uart_transaction)
`uvm_field_int(ui_ns,UVM_ALL_ON|UVM_DEC|UVM_NOCOMPARE)
`uvm_object_utils_end
//---> 3-Define constraint block
constraint uart_cfg1_c
{
soft ui_ns inside {[144_000:176_000]};
}
//---> 4-Define function
function new (string name = "");
super.new(name);
endfunction:new
endclass:uart_transaction
`endif
🤔现在需要创建异常TC,产生约束之外的transition,比如产生[144us,176us]大小之外ui_ns:
`ifndef TC_6_SEQUENCE__SV
`define TC_6_SEQUENCE__SV
class tc_6_sequence extends tc_uart_base_sequence /*#(uart_transaction)*/;
string name;
uart_transaction uart_tr;
`uvm_object_utils(tc_6_sequence)
function new (string name = "");
super.new(name);
this.name = name;
endfunction:new
extern virtual task pre_body ();
extern virtual task body ();
extern virtual task post_body();
endclass:tc_6_sequence
task tc_6_sequence::pre_body();
if(starting_phase != null)begin
starting_phase.raise_objection(this);
end
endtask:pre_body
task tc_6_sequence::body();
int num;
begin
//>>> SEQ1
`uvm_do_with(uart_tr,{role==mst; ui_ns inside {[100_000:144_000],[176_000:200_000]};})
end
endtask:body
task tc_6_sequence::post_body();
if(starting_phase != null)begin
starting_phase.drop_objection(this);
end
endtask:post_body
`endif
`ifndef TC_6__SV
`define TC_6__SV
class tc_6 extends tc_uart_base;
`uvm_component_utils(tc_6)
function new (string name = "", uvm_component parent = null);
super.new(name,parent);
endfunction:new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
set_report_max_quit_count(1);
endfunction:build_phase
virtual task main_phase (uvm_phase phase);
tc_6_sequence seq;
seq = tc_6_sequence::type_id::create();
seq.starting_phase = phase;
seq.start(this.env.uart_rx_agt.uart_rx_sqr);
endtask:main_phase
endclass
`endif
如果这样约束,那么ui结果为144_000或 176_000,
需要进行如下更改才有效:
//FAILL
`uvm_do_with(uart_tr,{role==mst; ui_ns inside {[100_000:144_000],[176_000:200_000]};})
//PASS
`uvm_do_with(uart_tr,{role==mst; ui_ns inside {[100_000:143_999],[176_001:200_000]};})
4- 小结
📨认知有限欢迎指导,本文持续更新中…