4

在 SystemVerilog 中,可以使用该disable构造来终止命名块或任务。但是我今天发现禁用类实例中的任务会影响所有类实例中任务的所有副本。

考虑一个在其中定义了一些任务的类。如果在类内部调用disable <taskname>,这将禁用该类的所有实例中的所有任务副本这不是我所期望的行为,但根据 LRM 是正确的:

如果多次启用任务,则禁用此类任务将禁用该任务的所有激活。

是否有一种机制或解决方法来禁用类的特定实例中的任务?

下面的代码突出了我面临的问题。基本上,我有一个计时器任务,由于其他一些事件,我想禁用它。这都包含在一个类中。在我的验证环境中,我有这个类的多个实例,它们完全独立运行。因此,在一个实例中禁用计时器不应影响其他实例。但是它的disable工作方式正在影响其他实例。

我试过disable this.timer了,但没有编译。

在这个例子中,我有两个实例,class c其中包含一个timer任务。有一个disabler并行启动的任务调用disable timer. 此示例中的目的是在timer计数中途禁用。所以c1会在时间 5c2被禁用,并在时间 10 被禁用。但是,它们都在时间 5 被禁用,因为disable timer发起的调用在和c1中都禁用了任务。c1c2

module top();

  class c;

    string name;
    int    count;

    function new(string _name, int _count);
      name  = _name;
      count = _count;
    endfunction

    task t1();
      timer();
      $display("%t %s timer completed", $time, name);
    endtask

    task run();
      fork
        t1();
        disabler();
      join
    endtask

    task timer();
      $display("%t %s starting timer with count=%0d", $time, name, count);
      repeat(count) #1;
    endtask

    task disabler();
      repeat(count/2) #1;
      disable timer;
    endtask

  endclass

  class ex;

    c c1;
    c c2;

    function new();
      c1 = new("c1", 10);
      c2 = new("c2", 20);
    endfunction

    task run();
      fork
        c1.run();
        c2.run();
      join_none
    endtask

  endclass

  ex e = new;

  initial begin
    e.run();
  end

endmodule

输出:

               0 c1 starting timer with count=10
               0 c2 starting timer with count=20
               5 c2 timer completed
               5 c1 timer completed

我知道我可以重写它以使其在不使用的情况下工作disable,但这是一种提前终止任务的简单方法,我希望我缺少一些东西。

4

3 回答 3

3

我不认为这是可能的。即使在命名块上使用禁用仍然会停止该任务的所有实例。

禁用自动任务或自动任务内的块会继续执行所有并发执行任务的常规任务。

您可以尝试使用流程类。我自己从未使用过它们,因此此代码可能包含错误。

class c;
process p1;

task run();
  fork
    begin
      p1 = process::self(); //Get process of this begin..end block
      $display("%t %s starting timer with count=%0d", $time, name, count);
      repeat(count) #1;
    end
    disabler()
  join_none
endtask

task disabler();
  wait (p1 != null);
  repeat(count/2) #1;
  p1.kill();
endtask
于 2012-10-03T14:58:29.473 回答
2
class a1; 
  process p1; 

  task timer();
    p1=process::self();
    begin
      while(1)
      begin
        $display("example data %t",$time);
        #10;
      end 
    end 
  endtask

  task timer2();
    for(int i = 0; i < 10; i ++) 
    begin
      #20;
      $display("shouldnot killed",i);
    end
  endtask

endclass

module example_kill;
  a1 ab,bc;
  initial begin 
    ab = new();
    bc= new();
    fork 
    ab.timer();
    ab.timer2();
    bc.timer();
    join_none
    #50; 
    ab.p1.kill();
    #100;
    bc.p1.kill();
    wait fork;
  end
endmodule
于 2013-11-25T13:41:31.737 回答
0

我认为任务可以在线程内部隔离。这个想法是你将你的任务隔离在一个线程中。您应该仅对一个特定实例应用禁用分叉。因此,您必须询问我们所在的实例。如果我们有问题,因为 systemverilog 不允许您例如

fork begin yourtaskcall; end join_none if (class_instance_disable_member_id==1) begin disable fork; end 之后,您可以再次包装前面的代码,以便您仅针对该任务隔离禁用分叉。例如

fork begin fork begin yourtaskcall; end join_none if (class_instance_disable_member_id==1) begin disable fork; end end join

最后,从您的顶部开始,您应该将变量“ class_instance_disable_member_id ”设置为 1(默认值=0),以用于您要禁用的特定实例。这可以从外部类或顶级类中完成。

例如 top.class1.class_instance_disable_member_id=1;

该任务将在任务被调用时被禁用。因此,您必须在调用发生之前设置“class_instance_disable_member_id=1 变量”。如果您使用 UVM,您可以使用阶段(在运行阶段之前构建或连接)。如果它是简单的 systemverilog,那么您可以使用 new() 构造函数从顶部为正确的实例设置该变量。

如果您想“动态/动态地”激活/停用任务,那么您应该在顶部有另一个线程/任务,在调用您要禁用的任务之前为您的特定实例修改“class_instance_disable_member_id”。

您还可以检测 class_instance_disable_member_id 上的更改以允许在中间杀死任务,使用以下基本块

fork begin yourtaskcall; end begin if (class_instance_disable_member_id==0) begin @(posedge class_instance_disable_member_id); end end join_any if (class_instance_disable_member_id==1) begin disable fork; end

我希望它可以帮助 BR

于 2016-10-12T07:36:33.040 回答