返回介绍

12.2 概述

发布于 2020-09-09 22:55:50 字数 3813 浏览 875 评论 0 收藏 0

本章介绍了在对象内产生随机激励的基本概念和用法。SystemVerilog使用一个面向对象的方法来为对象的成员变量赋随机值,它以用户定义的约束为准。例如:

class Bus;
    rand bit[15:0] addr;
    rand bit[31:0] data;
    constraint word_align {addr[1:0] == 2’b0;}
endclass

Bus类建模了一个简化的总线,它具有两个随机变量:addrdata,分别代表总线上的地址和数据。word_align约束指出:addr的随机值必须能够使addr字对齐(低两位为0)。

randomize()方法被调用以便为一个总线对象产生新的随机值:

Bus bus = new;

repeat (50) begin
    if (bus.randomize() == 1)
        $display ("addr = %16h data = %h\n", bus.addr, bus.data);
    else
        $display ("Randomization failed.\n");
end

调用randomize()会为一个对象中的所有的随机变量选择新的值以便所有的约束都为真(满足约束)。在上面的程序test中产生了一个总线对象,接着将这个对象随机化50次。每一次随机化都会检查结果是否成功。如果随机化成功,那么会打印addrdata的新值;如果随机化失败,那么会打印一条错误信息。在这个例子中,仅仅约束了addr的值,而data的值未被约束。未被约束的变量被赋值为它们声明范围内的任意值。

约束编程是一个强大的方法,它使得用户能够构建通用的、可服用的对象,这些对象在以后可以被扩展或约束以便执行特定的功能。这个方法与传统的过程化和面向对象的编程不同,例如在下面这个扩展Bus类的例子中:

typedef enum {low, mid, high} AddrType;

class MyBus extends Bus;
    rand AddrType atype;

    constraint addr_range
    {
        (atype == low ) -> addr inside {[0:15]};
        (atype == mid ) -> addr inside {[16:127]};
        (atype == high) -> addr inside {[128:255]};
    }
endclass

MyBus类从Bus类中继承了所有的随机变量和约束,并加入了一个被称为atype的随机变量,这个随机变量被用来使用另外一个约束控制地址的范围。addr_range约束根据atype的随机值隐含地选择三个范围约束中的一个。当一个MyBus对象被随机化的时候会计算addrdata、和atype的值以便所有的约束都能够满足。使用继承来构建分层的约束系统能够开发通用的模型,这些模型可以被约束以便执行专用的功能。

对象还可以使用randomize() with作进一步约束,这个结构调用randomize()并声明了额外的内联约束:

task exercise_bus (MyBus bus);
    int res;

    // 例子1:限制低地址
    res = bus.randomize() with {atype == low;};

    // 例子2:将地址限制在10和20之间
    res = bus.randomize() with {10 <= addr && addr <= 20;};

    // 例子3: 将数据值限制成2的n次方
    res = bus.randomize() with {data & (data-1) == 0;};
endtask

这个例子演示了有关约束的几个重要特性:

  • 约束可以是任何带有integral类型(bit、reg、logic、integer、enum、压缩结构体等等)的变量和常量表达式。
  • 约束解决器必须能够处理多种等式,例如代数因式分解、复杂的布尔表达式、以及混合整数和位的表达式。在上面的例子中,2的n次方约束使用算术表达式。它还可以用使用移位操作的表达式来定义。例如,1 << n,其中n是一个5位的随机变量。
  • 如果约束存在一个解的话,那么约束求解器必须找到这个解。求解器只有在问题被过约束并且没有随机值的组合能够满足约束的时候才可以失败。
  • 约束双向地影响。在这个例子中,addr的值的选择依赖于atype以及它怎样被约束,并且atype值的选择依赖于addr以及它怎样被约束。所有的表达式操作符都被双向地对待,包括蕴含操作符(->)。
  • 约束仅仅支持两态值。四态值(X或Z)或四态操作符(例如,===、!==)是非法的并且会导致错误。

有时我们希望关闭随机变量的约束。例如,为了故意地产生一个非法的地址(非字对齐的地址):

task exercise_illegal(MyBus bus, int cycles);
    int res;

    // 关闭字对齐约束
    bus.word_align.constraint_mode(0);

    repeat (cycles) begin
        // 情况1: 限制到小地址
        res = bus.randomize() with {addr[0] || addr[1];};
        ...
    end

    // 重新使能字对齐约束
    bus.word_align.constraint_mode(1);
endtask

constraint_mode()可以用来使能或关闭一个对象中任何命名的约束。在这个例子中,字对齐约束被关闭,接着对象使用其它的约束来随机化以便将低位地址强制成非零值(不再字对齐)。

使能或关闭约束的能力使得用户能够设计约束层次。在这些层次中,最底层的约束可以代表物理限制,这些物理限制通过公用的特性分组成命名的约束块,它们可以独立地使能或关闭。

类似地,rand_mode()方法可以用来使能或关闭任何随机变量。当一个随机变量被关闭的时候,它与其它非随机的变量具有完全一致的行为。

偶尔我们也希望在随机化之前或之后立即执行一些操作。这种功能可以通过两个内建方法完成:pre_randomize()和post_randomize(),这两个方法在随机化之前或之后被自动调用。这些方法可以使用希望的功能来过载:

class XYPair;
    rand integer x, y;
endclass

class MyXYPair extends XYPair
    function void pre_randomize();
        super.pre_randomize();
        $display("Before randomize x=%0d, y=%0d", x, y);
    endfunction

    function void post_randomize();
        super.post_randomize();
        $display("After randomize x=%0d, y=%0d", x, y);
    endfunction
endclass

缺省情况下,pre_randomize()和post_randomize()调用它们过载的父类方法。当pre_randomize()或post_randomize()被过载的时候,必须小心地调用父类方法,除非父类是一个基类(没有父类),否则应该调用基类方法。

随机激励产生能力以及面向对象的基于约束的验证方法使得用户能够快速地开发覆盖了复杂功能的测试,并能够更好地保证设计的正确性。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文