Bootstrap

[UVM] sv约束到`uvm_do_with

Title:

[UVM] sv约束到`uvm_do_with

1- 前言

​ transition 文件中对变量进行了范围约束,那么某个tc需要进一步约束,并且这个约束是和之前的约束条件是背驰的,那么应该怎么做?

2- 概念引入

2.1- SV约束

​ 在 SystemVerilog 中,约束(constraints)用于在随机化对象时施加特定的条件,以生成符合期望范围或模式的随机值。约束通常与类的随机变量一起使用,并通过 randconstraint 关键字进行定义。以下是 SystemVerilog 中约束方法的简要介绍:

定义随机变量

首先,要使变量可以被随机化,需要使用 randrandc 关键字声明变量:

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 宏会执行以下操作:

  1. 创建 ITEM 对象(如果尚未创建)。
  2. ITEM 应用 CONSTRAINTS 进行随机化。
  3. 启动 ITEMstart_item() 方法(对于 uvm_sequence_item)。
  4. 执行 ITEMfinish_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 > 128req.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- 小结

📨认知有限欢迎指导,本文持续更新中…

;