请帮助解决我所面临的一个与随机化约束相关的问题。
所以在我的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不支持的。我是对的吗?
答案 0 :(得分:3)
第二部分第一部分:我怀疑"产生约束"是generate
块中包含的约束。生成块仅允许在modules
,programs
和checkers
内,而不是类,因此"生成约束"是非法的(虽然这个词非常具体。我预计会出现一个错误说"在课程中不允许生成")。您可以通过在约束块内移动条件来重写约束:
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将最后一个值存储在实例变量中,因为所有实例变量都被销毁。
所以有两个选择:
将最后一个值存储在静态实例变量中。
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
在随机化序列项
时,在序列中添加约束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
在我看来,数字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
语句中添加约束,如您的错误消息所示。