当前位置:   article > 正文

System Verilog学习笔记—随机化约束的控制_assert(p.randomize())

assert(p.randomize())

目录

1.控制多个约束块儿constraint_mode()

2.控制随机变量

2.1 rand_mode()

2.2 randomize() with {}

2.3 randomize单独控制变量

3.回调函数 pre_randomize和post_randomize

4.约束的重载(覆盖 )

4.1使用constraint_mode(0)关闭约束后用randomize_with{}重新定义约束

4.2子类extends父类,然后定义同名约束覆盖父类的约束 


1.控制多个约束块儿constraint_mode()

       如果在一个类中定义了多个约束块儿,以便为了后续根据实际需要打开所需的约束块儿时,该如何操作?(就像一个筋膜枪,你要根据实际需要调节频率(约束频率范围))

       具体讲解在代码注释中讲解

  1. class Packet;
  2. rand int length;
  3. //以下2个约束块儿互相排斥,切不可将2个约束块儿同时打开,否则会随机出错误结果
  4. constraint c_short//定义约束1<=length<=32
  5. {
  6. length inside {[1:32]};
  7. }
  8. constraint c_long //定义约束1000<=length<=1023
  9. {
  10. length inside {[1000:1023]};
  11. }
  12. endclass
  13. program test
  14. Packet p;
  15. initial begin
  16. p = new();
  17. p.c_short.constraint_mode(0); //关闭c_short约束块儿
  18. assert(p.randomize());//此时length只在1000-1023中随机
  19. $display("P:length is %d",p.length);//1000-1023
  20. p.constraint_mode(0); //关闭所有约束条件
  21. p.c_short.constraint_mode(1); //打开c_short约束
  22. assert(p.randomize());//此时length只在1-32中随机
  23. $display("P:length is %d",p.length);//1-32
  24. end
  25. endprogram

2.控制随机变量

2.1 rand_mode()

     如果我们在一个类中定义了n个随机变量,在后续调用该类的时候,我们想根据实际需要控制类中的某个变量是否要随机化,该如何操作?

     关键词:类实例化名.变量名.rand_mode(0关闭/1开启)

  1. class Packet;
  2. rand bit [7:0] length, payload[];
  3. constraint c_valid
  4. {
  5. length > 0;
  6. payload.size() == length;
  7. }
  8. endclass
  9. program test
  10. Packet p;
  11. initial begin
  12. p = new();
  13. p.length.rand_mode(0); //关闭length的随机功能
  14. p.length = 42; //未现在不随机的length赋值
  15. $display("P:length is %d",p.length);//42
  16. assert (p.randomize());
  17. p.length.rand_mode(1); //打开length的随机功能
  18. $display("P:length is %d",p.length);//0-255
  19. end
  20. endprogram

2.2 randomize() with {}

        如果我们定义了一个类,在后续调用时想在原来约束的基础上进一步加约束该如何操作?

        关键词:类实例化名.randomize()with{所需约束}

  1. class Transaction;
  2. rand bit [31:0] addr, data;
  3. constraint c1
  4. {
  5. addr inside{[0:100],[1000:2000]};
  6. }
  7. endclass
  8. program test;
  9. Transaction t;
  10. initial begin
  11. t = new();
  12. assert(t.randomize() with {addr >= 50; addr <= 1500; data < 10;});//在c1的基础上进一步约束范围
  13. $display("t::addr=%d,data=%d",t.addr,t.data);//addr is 50-100 or 1500-2000data is 0-10
  14. assert(t.randomize() with {addr == 2000; data > 10;});//addr赋值2000data大于10
  15. $display("t::addr=%d,data=%d",t.addr,t.data);//addr is 2000data 大于10
  16. end
  17. endprogram

若外部所加约束与内部约束冲突,则看内部约束是否加了soft关键字,若加了则以外部约束为准,若没加则报错 

2.3 randomize单独控制变量

         该方法和2.1类似,都是对单个变量是否随机化进行操作,所不同的是操作方式

         关键词:类句柄.randomize(变量名)。表示只随机该变量,其它变量不随机

  1. class Rising;
  2. byte low;
  3. rand byte med, hi;
  4. constraint c_up
  5. {
  6. low < med;
  7. med < hi;
  8. }
  9. endclass
  10. program test;
  11. Rising r;
  12. initial begin
  13. r = new();
  14. r.randomize(); //对所有随机变量在约束上进行随机
  15. r.randomize(med); //只随机med,hi保持上一个值
  16. r.randomize(low); //只随机low,但low不是随机变量,med和hi保持上一个值
  17. end
  18. endprogram

3.回调函数 pre_randomize和post_randomize

     回调函数是指在父类中定义一个空方法,然后在不同子类中实现这些空方法

     他们都是function, 不消耗仿真时间;

     只要调用了randomize函数,在执行randomize函数之前先执行pre_randomize函数,再执行randomize函数,最后执行post_randomize函数。他们通常用来设置一些非随机的变量或者计算随机数据中的错误,如果如randomize调用失败,那么post_randomize将不会被执行,但是pre_randomize不管 randomize是否成功都会执行。

  1. class wr_tran;
  2. int constraint_en;
  3. int broadcast;
  4. rand int wr_addr;
  5. rand int wr_data;
  6. rand bit valid;
  7. constraint generic_c
  8. {
  9. valid ==1;
  10. wr_addr<100;
  11. }
  12. function void pre_randomize();//定义预处理函数
  13. $display("call the pre_randomize !");
  14. if(!constraint_en)
  15. generic_c.constraint_mode(0);
  16. endfunction
  17. function void post_randomize();//定义后处理函数
  18. $display("call post_randomize !");
  19. if(wr_addr ==1)
  20. broadcast =1;
  21. else
  22. broadcast =0;
  23. endfunction
  24. endclass
  25. module m1;
  26. wr_tran tr;
  27. initial begin
  28. tr =new();
  29. tr.constraint_en=0;//为pre_randomize提供条件
  30. tr.randomize() with {tr.wr_addr==200;tr.wr_data==3;tr.valid==0;};
  31. $display("tr.wr_addr=%d,tr.wr_data=%d,tr.valid=%d,tr.broadcast=%d",tr.wr_addr, tr.wr_addr,tr.valid,tr.broadcast);
  32. end
  33. endmodule

执行结果如图所示: 

 可见先打印了pre中的字符串,然后执行randomize为几个变量定值,然后执行post函数打印字符串,由于wr_addr 赋值为3,所以broadcas为0。

4.约束的重载(覆盖 )

4.1使用constraint_mode(0)关闭约束后用randomize_with{}重新定义约束

       具体解释见下面代码注释

  1. class constrainend;
  2. rand bit x;
  3. rand bit [1:0] y;
  4. constraint c_xy //对x,y定义约束
  5. {
  6. (x==0)-> y==0
  7. }
  8. endclass
  9. program test;
  10. constrainend p;
  11. initial begin
  12. p=new();
  13. p.c_xy.constraint_mode(0); 将实例p中对x,y的约束关闭
  14. assert(p.randomize() with {x==0; y==0;});//随机化x,y,并添加一个新约束
  15. $display("x = %d",p.x);//不会再被原类中的约束限制,而是被randomzie_with约束限制
  16. $display("y = %d",p.y);
  17. end
  18. endprogram

4.2子类extends父类,然后定义同名约束覆盖父类的约束 

        具体解释见下面代码注释

  1. class constrainend;
  2. rand bit x;
  3. rand bit [1:0] y;
  4. constraint c_xy
  5. {
  6. (x==0)-> y==0
  7. }
  8. endclass
  9. class overwrite extends constrainend;//子类继承父类,会继承属性和方法,所以父类的约束也继承了
  10. constraint c_xy//子类如果想定义一个新约束覆盖父类,则需要定义一个同名约束
  11. {
  12. x==0;
  13. y==0
  14. }
  15. endclass
  16. program test;
  17. overwrite p;
  18. initial begin
  19. p=new();
  20. assert(p.randomize());//在子类约束的基础上随机化
  21. $display("x = %d",p.x);
  22. $display("y = %d",p.y);
  23. end
  24. endprogram

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/107092
推荐阅读
相关标签
  

闽ICP备14008679号