今天我们继续修改之前的例子,你会有意想不到的收获。程序源代码,和上一节文章一样。
症状3:
这里,我们没有显式调用类的randomize() 函数,而是定义了一个类函数。在函数中 ,重新约束了类内的随机变量。请看如下代码:
`timescale 1ns/1ps
`include "uvm_macros.svh"
import uvm_pkg::*;class my_obj1 extends uvm_test;`uvm_component_utils(my_obj1)rand int src=4;rand int dst;constraint dst_c {dst inside {[7:9]};}rand bit [3:0] crc = 4'b0111;constraint crc_c {crc inside {5,6,7,8};}function new(string name = "my_obj1" , uvm_component parent = null );super.new(name, parent);endfunction // newextern virtual function print ();extern virtual function pure_print ();virtual task run_phase(uvm_phase phase);super.run_phase(phase);endtask endclass //function my_obj1::print();randomize (src) with {(src) inside {[5:5]};} ; // 新增代码,意图重新约束src变量`uvm_info(get_type_name(),$psprintf("%0h,%0h,%0h",src,dst,crc),UVM_LOW)
endfunctionfunction my_obj1::pure_print();`uvm_info(get_type_name(),$psprintf("%0h,%0h,%0h",src,dst,crc),UVM_LOW)
endfunction
//module tb();import uvm_pkg::*;
`include "uvm_macros.svh"initial beginrun_test("my_obj1");endendmodule // tb
运行仿真代码,得到如下仿真结果: dst 结果为0, 也即是声明初始化的初始化值; 而且仿真抛出异常Error-。
奇怪? 为什么没有进行预期[7:9]的随机取值呢?而且,我们明明是在调用randomize(src) 进行随机src 变量,为什么报错的是 dst 变量呢?
源代码修改:
修改前:
randomize (src) with {(src) inside {[5:5]};} ;
修改后方案A:
std::randomize (src) with {(src) inside {[5:5]};} ;
修改后的仿真结果:符合预期。
修改后方案B: 增加this.randomize() 的类函数显式调用,并保持程序源代码其它一致。
仿真结果: PASS。 通过增加 this.randomize() 的调用,其它代码均没有改变。我们得到预期的仿真结果。这里为什么?因为:首先如前面文章讲述,经过显式randomize() 调用之后,dst 的取值为8;后执行 randomize (src) with {(src) inside {[5:5]};} ; 时候,会重新对 randomize() 的所有对象进行随机求解,此时 dst = 8, 在 【7:9】范围之内,所有不会报错。最后,经过此次随机,只会更改 src 的数值。
分析3:
(1)其实,这里我们犯了一个错误,在systemverilog 标准语法说中,从头至尾没有提到: randomize (src) with {(src) inside {[5:5]};} ; 该随机化方式。也即是:通过调用类的内置函数 randomize(xxx) with {},可以去单独随机类中的某一个变量。
(2)所以,我们很自然想到一种解决办法,那就是调用 systemverilog 的内置 std::randomize() with 的方式,去随机特定某一个变量。这样做,仿真预期,没有发生错误。
(3)再分析:为什么我们调用的是 randmozie(src), 而报错的是 dst 求解失败呢?
答: 这里虽然是对src变量特定去随机,但是求解器,内部还是会对类的所有随机变量进行求解评估的。如果某些变量求解失败,会抛出异常错误的。
这个问题是关于SystemVerilog中的约束随机化。在你的代码中,你尝试对
src
进行随机化,但是报错是关于dst
的约束求解失败。出现这个错误的原因可能是在
my_obj1
类的实例化或随机化过程中,dst
的约束dst_c
与dst
的初始值或其他约束产生了冲突。SystemVerilog的约束求解器试图满足所有约束,但当它不能满足所有约束时,就会报错。在你的代码中,
dst
的约束dst_c
要求其值在7到9之间,但如果dst
的初始值0(在你的代码中未显示)不在这个范围内,或者在随机化过程中其他约束改变了dst
的值并使其超出了这个范围,那么约束求解器就会失败。(4)再分析:针对增加 this.randomize()的方案,在最后一次 randomize(src)的时候,返回结果并没有更新 dst.。说明:randmoize(xxx) with {} 还是可以针对某一随机变量进行随机化操作的。这里与(1)描述似乎存在矛盾,而又不矛盾。
(5)另外,需要注意:这里我们发现 dst 的两次随机,结果没有发生更改。 因为:调用randomize(src)的时候,只会评估dst 的约束求解,并不会更改上一次的随机值。
症状4:
我们在源代码基础之上,修改如下代码:增加对 src 随机变量的 constraint 块约束。
`timescale 1ns/1ps
`include "uvm_macros.svh"
import uvm_pkg::*;class my_obj1 extends uvm_test;`uvm_component_utils(my_obj1)rand int src=4;constraint src_c {src inside {[0:3]};}rand int dst=0;constraint dst_c {dst inside {[7:9]};}rand bit [3:0] crc = 4'b0111;constraint crc_c {crc inside {5,6,7,8};}function new(string name = "my_obj1" , uvm_component parent = null );super.new(name, parent); endfunction // newextern virtual function print ();extern virtual function pure_print ();virtual task run_phase(uvm_phase phase);super.run_phase(phase);this.print();endtask endclass //function my_obj1::print();randomize (src) with {(src) inside {[5:5]};} ;`uvm_info(get_type_name(),$psprintf("%0h,%0h,%0h",src,dst,crc),UVM_LOW)
endfunctionfunction my_obj1::pure_print();`uvm_info(get_type_name(),$psprintf("%0h,%0h,%0h",src,dst,crc),UVM_LOW)
endfunction
//module tb();import uvm_pkg::*;
`include "uvm_macros.svh"initial beginrun_test("my_obj1");endendmodule // tb
聪明的朋友们,对于上面的错误,相比大家都已经很清楚了。因为本篇内容的症状3已经做了分析。
但是,我们还是想做点什么。
修改后:
分析4:
通过增加this.randomzie(), 仿真可以跑通。这里不过多解释。我们想知道,为什么会发生冲突呢?
这个问题是因为SystemVerilog中的约束随机化的时候,会对相应随机变量的所有牵连约束,进行综合考量。如下三处之间产生了冲突。
第一处:
rand int src=4;
第二处:
constraint src_c {
src inside {[0:3]};
}
第三处:
randomize (src) with {(src) inside {[5:5]};} ;
所以,我们不要认为:后面的约束会覆盖前面的约束。也即是:第三处约束,会覆盖第二处的约束。这是错误的认识。 覆盖的问题,我们稍后讲解。