如何在随机化过程中生成递增值

时间:2016-06-15 06:20:59

标签: system-verilog uvm

请帮助解决我所面临的一个与随机化约束相关的问题。

所以在我的seqItem中,我有一个write_addr随机变量。此变量控制应在其中写入数据的内存中的位置。 我想实现不同的写地址更改模式,如随机地址,给定范围地址,升序和降序类型。 我有params_pkg,其中用户定义地址更改类型,我的TB相应地生成write_addr值。

我正在考虑使用约束来实现这一点,比如通过启用/禁用约束来获得所需的行为:

class seqItem extends uvm_sequence_item;
    `uvm_object_param_utils(seqItem)

    randc logic [541-1:515] wfifo_addr;
   if (params_pkg::writeAddressType == "WriteGivenRangeAddress") begin
        constraint wArrdGivnRangCnstr {
            this.wfifo_addr  inside {[params_pkg::addrLowValue:params_pkg::addrHighValue]};
       }
 end
  function new (string name="seqItem");
        super.new(name);
        this.wArrdGivnRangCnstr.constraint_mode(0);
    endfunction

endclass

但是,无法使用约束生成升序或降序地址值。因为要具有升序地址,所以seqitem代码需要知道先前随机化中的write_addr变量值,这是我无法实现的。

我的问题是:是否可以使用约束来提升write_addr值?

第二,我发布的示例代码不起作用,模拟器给出错误说不允许生成约束。最有可能这是System Verilog不支持的。我是对的吗?

3 个答案:

答案 0 :(得分:3)

第二部分第一部分:我怀疑"产生约束"是generate块中包含的约束。生成块仅允许在modulesprogramscheckers内,而不是类,因此"生成约束"是非法的(虽然这个词非常具体。我预计会出现一个错误说"在课程中不允许生成")。您可以通过在约束块内移动条件来重写约束:

constraint wArrdGivnRangCnstr {
    if (params_pkg::writeAddressType == "WriteGivenRangeAddress") {
        this.wfifo_addr inside {[params_pkg::addrLowValue:params_pkg::addrHighValue]
    };
}

BTW:您可能要考虑enum变量的writeAddressType。这样就可以在编译时捕获拼写错误。

另一件事......

您将随机变量定义为randc

  

使用randc关键字声明的变量是随机循环变量,循环遍历其声明范围的随机排列中的所有值。

如果您限制randc变量的范围,则无法循环浏览[it's]声明的范围"的所有值...。从SystemVerilog LRM中不清楚这里会发生什么,但我怀疑一旦低和高之间的所有值都耗尽,随机化就会失败。

此外,变量的大小为26位。这是67,108,864个不同的值,您要求模拟器跟踪以查看它们之前是否已被使用过。它只需要8MB的标志就可用于这个变量。

我希望您真正想要的是将变量定义为rand而不是randc

关于你的主要问题......

你说得对,你需要对最后一个值进行某种存储以获得递增值,因为这是一个序列项我怀疑你每次都在创建一个新实例,因此我们可以&# 39; t将最后一个值存储在实例变量中,因为所有实例变量都被销毁。

所以有两个选择:

  1. 将最后一个值存储在静态实例变量中。

    class seqItem extends uvm_sequence_item;
        `uvm_object_param_utils(seqItem)
    
        rand logic [541-1:515] write_addr;
        static logic [541-1:515] last_write_addr = 0;
        constraint wAddrIncr {
            write_addr > last_write_addr;
        }
        function new (string name="seqItem");
            super.new(name);
        endfunction
    
        function post_randomize();
            last_write_add = write_addr;
        endfunction
    endclass
    
  2. 在随机化序列项

    时,在序列中添加约束
    class someSequence extends uvm_sequence;
    
        ...stuff omitted...
    
        task body();
            seqItem item;
            seqItem last_item;
    
            last_item = null;
    
            repeat (4728346) begin
                item = new(); // or create to use factory
                if (last_item) begin
                    item.randomize() with {
                        write_addr > last_item.write_addr
                    };
                end else begin
                    item.randomize();
                end
                last_item = item;
    
                // Send to driver or whatever
            end
        endtask
    endclass
    
  3. 在我看来,数字2更好,因为它没有将增加的地址行为烘焙到序列项中。递增地址实际上是项目序列的属性,而不是任何单个项目的属性。我现在可以编写一些具有增加地址,减少地址或任何其他模式的序列。

答案 1 :(得分:0)

生成升序(或降序)地址问题的一个解决方案是记下生成的最后一个值,并将其用作约束的下限:

  class seqItem;

    randc logic [0:15] wfifo_addr;
    static logic [0:15] last_wfifo_addr = '0;

    constraint wArrdGivnRangCnstr {
      this.wfifo_addr  inside {[last_wfifo_addr:params_pkg::addrHighValue]};
    }

    function void post_randomize;
      last_wfifo_addr = wfifo_addr;
      if (last_wfifo_addr >= params_pkg::addrHighValue)
        last_wfifo_addr= params_pkg::addrLowValue;
    endfunction

  endclass

http://www.edaplayground.com/x/3QxX

post_randomize函数是一种可以覆盖的内置方法。它是在(内置)randomize方法之后隐式调用的。还有一个内置的pre_randomize,当然你也可以覆盖它。

答案 2 :(得分:0)

改变随机化模式问题的一个解决方案是打开和关闭约束:

您可以使用隐式constraint_mode方法关闭约束:

s.wArrdGivnRangCnstr.constraint_mode(0);

然后再打开它:

s.wArrdGivnRangCnstr.constraint_mode(1);

(其中s是对seqItem类的引用)。您不能在if语句中添加约束,如您的错误消息所示。