Kau*_*odi 9 foreach fork system-verilog uvm
这个问题不是UVM特定的,但我正在研究的例子是UVM相关的.我在我的UVM环境中有一系列代理,我想在所有这些代理上并行启动一个序列.
如果我这样做:
foreach (env.agt[i])
begin
seq.start(env.agt[i].sqr);
end
Run Code Online (Sandbox Code Playgroud)
,序列seq首先执行env.agt[0].sqr.一旦结束,它就会执行env.agt[1].sqr,依此类推.
我想实现一个foreach-fork语句,以便seq在所有agt[i]顺控程序上并行执行.
无论我如何订购fork-join和foreach,我都无法实现这一目标.能帮我解决并行序列启动行为吗?
谢谢.
更新以澄清我试图解决的问题:下面的代码结构的结果与上面没有fork-join完全相同.
foreach (env.agt[i])
fork
seq.start(env.agt[i].sqr);
join
fork
foreach (env.agt[i])
seq.start(env.agt[i].sqr);
join
// As per example in § 9.3.2 of IEEE SystemVerilog 2012 standard
for (int i=0; i<`CONST; ++i)
begin
fork
automatic int var_i = i;
seq.start(env.agt[var_i].sqr);
join
end
Gre*_*reg 10
问题是fork的每个线程都指向同一个静态变量i.每个线程都需要自己唯一的副本,这可以通过automatic关键字实现.
foreach (env.agt[i])
begin
automatic int var_i = i;
fork
seq.start(env.agt[var_i].sqr);
join_none // non_blocking, allow next operation to start
end
wait fork;// wait for all forked threads in current scope to endRun Code Online (Sandbox Code Playgroud)
IEEE std1800-2012§6.21 "范围和寿命"给出了静态和自动使用的示例.另请参阅§9.3.2"并行块",最后一个示例演示了for循环中的并行线程.
使用join_none创建新线程; §9.3.2"并行块",表9-1-"fork-join控制选项".
使用fork wait语句等待当前作用域中的所有线程完成; §9.6.1"等待叉语句"
例:
byte a[4];
initial begin
foreach(a[i]) begin
automatic int j =i;
fork
begin
a[j] = j;
#($urandom_range(3,1));
$display("%t :: a[i:%0d]:%h a[j:%0d]:%h",
$time, i,a[i], j,a[j]);
end
join_none // non-blocking thread
end
wait fork; // wait for all forked threads in current scope to end
$finish;
endRun Code Online (Sandbox Code Playgroud)
输出:
2 :: a [i:4]:00 a [j:3]:03
2 :: a [i:4]:00 a [j:0]:00
3 :: a [i:4]:00 a [j:2]:02
3 :: a [i:4]:00 a [j:1]:01
下面 Greg 的解决方案帮助我找到了基于 UVM 的问题的解决方案。这是我的解决方案:
下面的 fork-join 块位于测试用例类的 main_phase 任务中。该wait fork;语句等待其范围内的所有 fork 语句(= foreach_fork begin-end 块)完成,然后再继续进行。wait fork;需要注意的重要一点是,为了设置foreach_fork 块的范围,需要在 begin-end 周围包装 fork-join 。
fork
begin : foreach_fork
seq_class seq **[`CONST]**;
foreach(env.agt[i])
begin
int j = i;
**seq[j] = seq_class::type_id::create
(.name($sformatf("seq_%0d", j)), .contxt(get_full_name()));**
fork
begin
seq[j].start(env.agt[j].sqr);
end
join_none // non-blocking thread
end
**wait fork;**
end : foreach_fork
join
Run Code Online (Sandbox Code Playgroud)
替代解决方案利用顺序反对来延迟 sim 结束。
begin
seq_class seq **[`CONST]**;
foreach(env.agt[i])
begin
int j = i;
**seq[j] = seq_class::type_id::create
(.name($sformatf("seq_%0d", j)), .contxt(get_full_name()));**
fork
begin
**seq[j].starting_phase = phase;**
seq[j].start(env.agt[j].sqr);
end
join_none // non-blocking thread
end
end
Run Code Online (Sandbox Code Playgroud)
我意识到我还需要为我想要并行运行的每个 seq 创建一个新的序列对象。
感谢 Dave 指出 System Verilog 类中的属性默认情况下是自动的。
替代解决方案的注意事项:由于我没有使用,所以wait fork;我使用序列本身中提出的 UVM 反对来完成推迟模拟调用的工作$finish。为了能够在序列中提出反对意见,我使用了该seq[j].starting_phase = phase;构造。