12

这个问题不是 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,我都无法做到这一点。你能帮我得到那个并行序列启动行为吗?

谢谢。

更新以澄清我要解决的问题:以下代码结构的结果与上面没有分叉连接的结果完全相同。


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

4

4 回答 4

13

问题是 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 control options”。

使用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

于 2013-11-05T17:06:35.900 回答
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

这在过去对我有用。

于 2013-11-07T12:32:21.957 回答
1

以下 Greg 的解决方案帮助我获得了基于 UVM 的问题的解决方案。这是我的解决方案:

下面的 fork-join 块驻留在测试用例类的 main_phase 任务中。该wait fork;语句等待其范围内的所有 fork 语句(= foreach_fork begin-end 块)完成,然后再继续进行。需要注意的重要一点是,将范围设置为wait fork;foreach_fork 块需要在 begin-end 周围进行包装 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

我意识到我还需要为我想要并行运行的每个序列创建一个新的序列对象。

感谢 Dave 指出 System Verilog 类中的属性默认是自动的。

替代解决方案的注意事项:由于我没有使用wait fork;序列本身中提出的 UVM 反对来完成推迟模拟$finish调用的工作。为了能够在序列中提出反对意见,我使用了seq[j].starting_phase = phase;构造。

于 2013-11-05T22:07:07.463 回答
-1

尝试

int i = 0
foreach (env.agt)
  begin
    seq.start(env.agt[i].sqr);
    i++;
end
于 2013-11-05T16:18:28.430 回答