本文转自gsithxy,原文链接:https://blog.csdn.net/gsjthxy/article/details/107220093
————————————————
实习做虚拟项目的验证部分时,出现了`uvm_do_with宏中同名约束对底层sequence失效的情况,使用this也无效,查到这篇博客,解决了我的问题,感谢,转载记录于此。
————————————————
前言:我们通常在上层的top_vseq中启动下层sub_seq或seq_item,出于灵活性或者可重用性的考虑,可能会使用 `uvm_do_with 对下层的random变量进行约束。为了coding方便以及增强代码可读性的考虑,上层和下层seq变量的名字可能是一样的。但是这样就会造成一个问题:我们会发现如果使用`uvm_do_with(sub_seq, {var_a == var_a});这个约束是无法生效的,下层的var_a并不能通过上层的var_a进行控制,即使上层top_seq将var_a设定为某个固定值也没用。
一、造成这个问题的原因
这是由于作用域的问题,在编译器来看,它不知道两个var_a有什么不同,把他当成sub_seq作用域中的两个相同变量,自然而然这条约束就没用效用。
二、解决方案
可能有人会想到有this,这正是一个陷阱。我们在top_vseq中使用`uvm_do_with(sub_seq, {sub_seq.var_a == this.var_a});进行仿真,会发现约束同样没有效果,为什么?
因为在`uvm_do_with()中,this指定的作用域首先找到的是sub_seq,而并不是想要的top_vseq的this。
这里提供三种方法解这个constraint的问题:
- 在top_vseq中使用不同的变量名约束sub_seq中的变量
- 在top_vseq中使用指向自己的指针(this),但是需要换个名字
- 使用local指明作用域
2.1、在top_vseq使用不同的变量名
class top_vseq extends l0_base_vasq;
rand bit [3:0] tmp_var_a;
function new(string name = "top_vseq");
super.new(name);
endfunction
virtual task body();
super.body();
if(starting_phase != null) begin
starting_phase.raise_objection(this);
end
repeat(10) begin
`uvm_do_with(sub_seq, {sub_seq.var_a == tmp_var_a});
end
#100ns;
if(starting_phase != null) begin
starting_phase.drop_objection(this);
end
endtask : body
endclass
这样做就不太方便,如果seq嵌套太多,变量名就一大堆,会非常繁琐。
2.2、使用this,但换个名字
class top_vseq extends l0_base_vseq;
...
top_seq my_seq;
function new(string name = "top_vseq");
super.new(name);
my_seq = this; //==> 指向自己,其实就是把this换了个名字,
endfunction
...
`uvm_do_with(sub_seq, {var_a == my_seq.var_a}) //==>原理很简单,就是避免关键字因素的影响
endclass
2.3、下面给出一个完整的例子
- sub_seq案例
class sub_seq extends l0_base_vseq;
rand bit [3:0] var_a;
rand bit [3:0] var_b;
rand bit [3:0] var_c;
constraint cst_vars {
soft var_a inside {[0: 4]};
soft var_a inside {[5: 8]};
soft var_a inside {[9:15]};
}
function new(string name = "sub_seq");
super.new(name);
endfunction
virtual task body();
super.body();
`uvm_info("\n[SUB_SEQ]", $sformatf("var_a = 0x%0h, var_b = 0x%0h, var_c = 0x%0h", var_b, var_v, var_c), UVM_LOW)
endtask : body
endclass
- top_vseq案例
class top_vseq extends l0_base_vasq;
rand bit [3:0] var_a;
rand bit [3:0] var_b;
rand bit [3:0] var_c;
top_vseq my_top_vseq;
sub_seq sub_seq_inst; //指向自己的指针
function new(string name = "top_vseq");
super.new(name);
my_top_vseq = this; //相当于把this改了个名字,此时this指向top_vseq
endfunction
virtual task body();
super.body();
if(starting_phase != null) begin
starting_phase.raise_objection(this);
end
repeat(10) begin
std::randomize(var_a) with {var_a inside {[9:15]};};
std::randomize(var_b) with {var_b inside {[5: 8]};};
std::randomize(var_c) with {var_c inside {[0: 4]};};
`uvm_info("\n[SUB_SEQ]", $sformatf("var_a = 0x%0h, var_b = 0x%0h, var_c = 0x%0h", var_b, var_v, var_c), UVM_LOW)
`uvm_do_with(sub_seq_inst, {
var_a == my_top_vseq.var_a;
var_b == my_top_vseq.var_b;
var_c == my_top_vseq.var_c;
})
end
#100ns;
if(starting_phase != null) begin
starting_phase.drop_objection(this);
end
endtask : body
endclass
最终的执行结果是:执行了top_vseq中的constraint
2.4、使用local,指明作用域
class top_vseq extends l0_base_vasq;
rand bit [3:0] var_a;
rand bit [3:0] var_b;
rand bit [3:0] var_c;
top_vseq my_top_vseq;
function new(string name = "top_vseq");
super.new(name);
endfunction
virtual task body();
super.body();
if(starting_phase != null) begin
starting_phase.raise_objection(this);
end
repeat(10) begin
std::randomize(var_a) with {var_a inside {[9:15]};};
std::randomize(var_b) with {var_b inside {[5: 8]};};
std::randomize(var_c) with {var_c inside {[0: 4]};};
`uvm_info("\n[SUB_SEQ]", $sformatf("var_a = 0x%0h, var_b = 0x%0h, var_c = 0x%0h", var_b, var_v, var_c), UVM_LOW)
`uvm_do_with(sub_seq_inst, {
var_a == local::var_a;
var_b == local::var_b;
var_c == local::var_c;
})
end
#100ns;
if(starting_phase != null) begin
starting_phase.drop_objection(this);
end
endtask : body
endclass
————————————————
原文作者侵删。本文无需三连和打赏,如确实有收获,请前往原作者博文进行感谢和支持。