这个问题不是针对UVM的,但我正在研究的例子是UVM相关的。 我在UVM环境中有一系列代理,我想在所有这些代理上并行启动一个序列。
如果我这样做:
foreach (env.agt[i])
begin
seq.start(env.agt[i].sqr);
end
,序列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
答案 0 :(得分: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 end
IEEE std 1800-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;
end
输出:
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
答案 1 :(得分:2)
我认为更接近“UVM”的方法是使用虚拟序列。假设您已经有一个虚拟序列器实例化一个代理序列发生器数组,那么您的虚拟序列的主体将如下所示:
fork
begin: isolation_thread
foreach(p_sequencer.agent_sqr[i])
automatic int j = i;
fork
begin
`uvm_do_on(seq, p_sequencer.agent_sqr[j]);
end
join_none
end
wait fork;
end: isolation_thread
join
过去这对我有用。
答案 2 :(得分:1)
Greg的解决方案帮助我找到了基于UVM的问题的解决方案。这是我的解决方案:
下面的fork-join块驻留在测试用例类的main_phase任务中。 wait fork;
语句在继续进行之前等待其范围(= foreach_fork开始结束块)中的所有fork语句完成。需要注意的一点是,将wait fork;
的范围设置为foreach_fork块需要在开始端周围包装fork-join。
fork
foreach_fork : 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].start(env.agt[j].sqr);
end
join_none // non-blocking thread
end
wait fork;
end : foreach_fork
join
使用顺序异议来延迟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
我意识到我还需要为每个想要并行运行的seq创建一个新的序列对象。
感谢Dave指出System Verilog类中的属性默认是自动的。
注意替代解决方案:
由于我没有使用wait fork;
,我使用序列本身中提出的UVM异议来完成阻止模拟$finish
调用的工作。为了提高序列中的异议,我使用seq[j].starting_phase = phase;
构造。
答案 3 :(得分:-1)
尝试
int i = 0
foreach (env.agt)
begin
seq.start(env.agt[i].sqr);
i++;
end