路科V0P19P22随机变量-随机约束-约束控制-任务和函数

随机变量

  • 随着设计越来越大,要产生完整的激励来测试设计的功能变得越来越困难;
  • 定向激励的测试方法已经无法满足检查功能完整性的要求;
  • Soc集成度提高带来的模块之间交互的复杂性也指数提高,验证工程师无法预测用户使用过程中发生什么样的情况;

概述:

  • 随机-约束: 构成目前动态仿真验证的主流方法;
  • 随机约束测试:CRT, constrained-random test,即能够产生感兴趣的、想不到的测试向量,通过回归测试、替换随机种子的方式来提高单位测试用例的覆盖率收集效率
  • 随机测试带来的负担是验证环境的复杂度提高,不再只需要发送激励的组件,还包括监测器、比较器等;
  • 对环境复杂度还包括环境的复用和测试的复用,带来组件封装要求,使得代码量增大;

产生一个随机数

利用系统函数产生一个随机数

  • randomize函数产生随机数,如果随机成功,返回1,否则0;
  • 通过系统函数std::randomize()对一些变量完成随机化,即产生随机数并赋值给这些向量;
  • 还有一些其他的系统函数:
    • $urandom() 产生一个32位无符号的随机数;
    • $urandom_range(max_val, minval=0), 可以生成介于maxval和minval之间的随机数;
1
2
3
4
5
6
7
8
9
module stim;
bit [15:0] addr;
bit [31:0] data;
function bit get_stim();
bit success, rd_wr;
success = randomize(add, data, rd_wr);
return rd_wr;
endfunction
endmodule

系统有机的组织随机变量

  • 比起独立的产生随机数,在向DUT产生随机激励时,为了符合协议、满足测试需求,还需要添加一些约束;
  • 这些约束会使得变量朝着希望他们变化的方向去随机;
  • 这些约束也会对变量和变量之间的关系生效;
  • 需要一个载体去容纳变量和他们之间的约束;
  • 这个载体是类,类的成员变量可以声明“随机”属性,用rand或者randc表示

随机变量

  • 任何类中的整型(bit、byte、int)变量都可以声明为rand、randc;
  • 定长数组、动态数组、关联数组和队列都可以声明为rand、randc;
  • 可以对动态数组和队列的长度加以约束;
  • 指向对象的句柄,也可以声明为rand,不能randc,随机时该句柄指向的对象中的随机变量会一起被随机化
  • 非组合型结构体可以声明为rand,非组合型的成员也可以声明为rand、randc;
1
2
3
4
5
6
7
8
9
10
rand bit [7:0] len;
rand integer data[];
constraint db {data.size == len;}

typedef struct {
randc int addr = 1 + constant;
int crc;
rand byte data [] = {1,2,3,4};
} header;
rand header h1;

rand和randc

  • rand: 表示在可生成范围内,每个值得可能性是相同的–>每次都是有放回!!
    • rand bit [7:0] y;
  • randc: 它的值会随机,并且遍历可取值范围,–>无放回!!

随机约束

带有随机约束的简单类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Packet;
rand bit [31:0] src, dst, data[8];
randc bit [7:0] kind;
// src的约束
constraint c {src > 10; src < 15;}
endclass

Packet p;
initial begin
p = new();
if (!p.randomize())
$finish;
transmit(p);
end

约束块

  • 有用的激励不仅会约束随机变量,变量之间也存在互相约束关系;
  • 没有约束的随机变量会包含很多无效的和非法的值,会使得有效激励变得低效;
  • 类需要用一个或者多个约束块来描述变量之间的关系
  • 约束块支持整型通过inside操作符来设置可取值的范围
1
2
3
4
5
6
7
8
9
rand integer x,y,z;
constraint c1 {x inside {3, 5, [9:15], [24:32], [y:2*y], z};}

rand integer a,b,c;
constraint c2 {a inside {b, c};}

integer fives[4] = '{5, 10, 15, 20};
rand integer v;
constraint c3 {v inside {fives};}

权重分布

  • 除了成员集合设置,约束块也支持设置可取值的同事为其设置随机时的权重;
  • := : 表示每个值的权重都是相同的;
  • :/ : 表示权重会平均分配到每一个值;
1
2
x dist { [100:102] := 1, 200 := 2, 300 := 5};   // 权重分布:1 1 1 2 5
x dist { [100:102] :/ 1, 200 := 2, 300 := 5}; // 权重分布:1/3 1/3 1/3 2 5

唯一标识

  • unique : 可以用来约束一组变量,使得其随机后变量之间不会有相同的数值;
1
2
3
4
5
6
rand byte a[5];
rand byte b;
rand byte excluded;

constraint u {unique {b, a[2:3], excluded};}
constraint exclusion {excluded == 5;}

条件约束

  • 可以使用if-else或者->操作符表示条件约束;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
constraint c1 {
mode == little -> len < 10;
mode == big -> len > 100;
}

bit [3:0] a, b;
constraint c2 {(a==0) -> (b==1);}

constraint c3 {
if (mode == little)
len < 10;
else if (mode == big)
len > 100;
}

迭代约束

  • foreach可以用来迭代约束数组中的元素,这些数组可以是定长数组、动态数组、关联数组或者队列;
1
2
3
4
5
6
7
8
9
10
11
class C;
rand byte A[];
constraint c1 {
foreach (A[i])
A[i] inside {2,4,6,8};
}
constraint c2 {
foreach (A[j])
A[j] > 2*j;
}
endclass
  • 也可以用数组的缩减方法进行迭代约束
1
2
3
4
5
class C;
rand bit [7:0] A[];
constraint c1 {A.size() == 5;}
constraint c2 {A.sum() < 1000;}
endclass

函数调用

  • 有时候,在一些表达式中不能简单的描述约束,比如计算一个组合数组中的’1’;
  • 可以写成一个函数,然后约束调用这个函数;
1
2
3
4
5
6
function int count_ones (bit [9:0] w);
for (count_onts=0; w!=0; w = w>>1)
count_ones += w & 1'b1;
endfunction

constraint C1 {length == count_ones(v);}

软约束 和 硬约束

  • 为了防止约束冲突时执行失败,分为软约束和硬约束;
  • soft : soft描述的约束是软,没有soft是硬;
  • 如果用户在使用时,制订了外部约束对同一个变量做了二次约束,或者用户定义了子类,也对同一个变量做了二次约束,那么硬约束可以覆盖软约束,不会导致随机失败;
1
2
3
4
5
6
7
class Packet;
rand int length;
constraint deflt {soft length inside {32, 1024};}
endclass

Packet p = new();
p.randomize() with {length == 1512;} // 覆盖了内部的软约束,执行成功

约束控制

随机方法

  • 类的声明中的随机变量,需要伴随类的句柄的调用randomize(),这是SV的内建方法virtual function int randomize();
  • 随机化成功返回1,否则0;
  • 随机化之前需要先对对象完成例化,例化时没有随机的过程;

内嵌约束

  • 在调用randomize()时伴随with,称为内嵌约束;
1
2
3
4
5
6
7
class C;
rand integer x;
endclass

function int F(C obj, integer y);
F = obj.randomize() with (x) {x < y;}; //这种方式对x的指向明确了,不在参数列表中,所以是C的x
endfunction

local域指向

  • 同名的变量处于不同的域中,可能出现指向模糊,可以使用上文的方法;
  • 也可以使用local::域索引到方式;
1
2
3
4
5
6
7
class C;
rand integer x;
endclass

function int F(C obj, integer x);
F = obj.randomize() with{x < local::x;}; //第一个x是C的,第二个local的x是参数
endfunction

随机控制

  • rand_mode可以用来使能或者禁止成员变量的随机属性;
    • 当随机模式被禁止时,就相当于一个普通变量了;
    • 可以禁止某个变量的随机模式,也可以对整个对象调用rand_mode进行控制;
  • constraint_mode()用来关闭或者使能约束块;
1
2
task object[.random_variable]::rand_mode(bit on_off);
function int object.rand_variable::rand_mode();

内嵌变量控制

  • 一个有意思的点,如果在randomize()中有参数,则只会对这个参数进行随机化,别的就算是rand也不随机化了;

任务和函数

概述

  • function和task都是提高代码复用性和整洁度;
  • function:
    • 首要目的在于为运算表达式提供返回值,便于简化原有代码,提高维护性;
    • void函数无返回值;
    • 一个function只能有一个返回值,所以函数可以作为表达式的操作数,因为就一个值;
    • 函数的参数方向可以声明为:input、output、inout、ref
    • 函数可以调用函数,但是必须立即返回,不能阻塞等待
    • 函数返回方式有两种,一个是return直接返回,一个是将值或者表达式赋给函数的同名变量
    • 区别在于return会立即返回,但是赋值同名变量之后,后续的代码还会执行下去;
    • 可以对有返回值的函数进行类型转换,void'(func1),这时候用不到函数的返回值;
  • task:
    • 同样的参数列表指名四个方向;
    • task无返回值!
    • task可以用来消耗仿真时间,内置一些阻塞语句;
    • 可以使用return立刻结束task;
    • task可以调用task和function,但是function只能调用function,不能调用task;
1
2
3
4
5
6
7
8
9
10
11
logic red;
parameter red_tics = 100;
always begin
red = on;
light(red, red_tics);
end

task light(output color, input [31:0] tics);
repeat(tics) @(posedge clock);
color = off;
endtask: light

参数传递

  • input : 在方法调用时,属于值传递,在传递的过程中,外部变量的值经过拷贝,赋值给输入参数;
  • output、inout都是值传递,发生在方法调用和返回时;
  • ref参数不会传递值拷贝,而是将变量指针传递到方法中,所以方法内部的操作会影响到外部的变量;
  • 为了避免外部传入的ref参数被方法修改,可以添加const修饰符
  • SV允许在声明输入参数时,指定参数的默认值;
  • 除了按照参数位置传递参数,SV也允许像module例化一样,用参数名字映射的方式传递参数
1
2
3
4
5
6
7
8
9
task read(int j=0, int k, int data=1);
endtask

read(,5); // 即0 5 1

function int func(int j=1, string s= "no");
endfunction

func(.j(2), .s("yes")); // 即2 yes
作者

Gavin

发布于

2022-05-13

更新于

2022-05-13

许可协议

CC BY-NC-SA 4.0

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×