是否可以在单个特定类实例中禁用SystemVerilog任务?

是否可以在单个特定类实例中禁用SystemVerilog任务?,verilog,system-verilog,Verilog,System Verilog,在SystemVerilog中,可以使用禁用构造终止命名块或任务。但我今天发现,禁用类实例中的任务会影响所有类实例中任务的所有副本 考虑一个类,其中定义了一些任务。如果在类的内部调用了disable,这将在类的所有实例中禁用任务的所有副本。这不是我预期的行为,但根据LRM,这是正确的: 如果一项任务被启用多次,则禁用该任务应禁用该任务的所有激活 是否有一种机制或解决方法,仅在类的特定实例中禁用任务? 下面的代码突出了我面临的问题。基本上,我有一个计时器任务,我想禁用由于一些其他事件。这些都包含在

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

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

如果一项任务被启用多次,则禁用该任务应禁用该任务的所有激活

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

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

我试图禁用这个。计时器,但没有编译

在本例中,我有两个
类c
的实例,其中包含一个
计时器
任务。有一个并行启动的
disabler
任务调用
disable timer
。本例中的目的是使
计时器在计数的中途被禁用。因此,
c1
将在时间5被禁用,
c2
将在时间10被禁用。但是,它们在时间5都被禁用,因为源于
c1
disable timer
调用禁用了
c1
c2
中的任务

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,也会停止该任务的所有实例

禁用自动任务或自动任务内的块 对于所有并发执行的 任务

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

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
a1类;
过程p1;
任务计时器();
p1=进程::self();
开始
而(1)
开始
$display(“示例数据%t”,$time);
#10;
结束
结束
结束任务
任务计时器2();
对于(int i=0;i<10;i++)
开始
#20;
$display(“shouldnotkilled”,i);
结束
结束任务
末级
模块示例_kill;
a1 ab,bc;
初始开始
ab=新的();
bc=新的();
叉
ab.定时器();
ab.timer2();
bc.timer();
加入
#50; 
ab.p1.kill();
#100;
bc.p1.kill();
等待叉;
结束
端模

我认为任务可以在线程内部隔离。其思想是将任务隔离在线程中。您应该只对一个特定实例应用disable fork。所以你必须问问我们现在的情况。 在我们遇到问题之前,因为systemverilog不允许您 e、 g

fork
开始
你的任务呼叫;
结束
加入
如果(类\实例\禁用\成员\ id==1)开始
禁用分叉;
结束
之后,您可以再次包装前面的代码,以便仅为该任务隔离disable fork。e、 g

fork
开始
叉
开始
你的任务呼叫;
结束
加入
如果(类\实例\禁用\成员\ id==1)开始
禁用分叉;
结束
结束
加入

最后,对于要禁用的特定实例,应该从顶部将变量“class\u instance\u disable\u member\u id”设置为1(default value=0)。这可以从外部类或顶级类完成

例如top.class1.class\u实例\u禁用\u成员\u id=1

在调用该任务时,该任务将被禁用。因此,必须在调用之前设置“class\u instance\u disable\u member\u id=1变量”。 如果使用UVM,则可以使用阶段(在运行阶段之前构建或连接)。如果是simple systemverilog,则可以使用new()构造函数从顶部为正确的实例设置该变量

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

还可以检测CaseSuthAsdixDeable成员的ID,以允许在中间杀死任务,使用以下基本块

fork
开始
你的任务呼叫;
结束
开始
如果(类\实例\禁用\成员\ id==0)开始
@(posedge类\实例\禁用\成员\ id);
结束
结束
加入任何
如果(类\实例\禁用\成员\ id==1)开始
禁用分叉;
结束

我希望有帮助
BR

谢谢。我已经尝试过使用process类,但无法使其正常工作。我重新审视了这一点,并能够使其发挥作用;关键是应该终止的任务/过程需要位于它们自己的fork/join中,这样它们就处于一个单独的进程中。所以-这是可能的,但不使用
禁用
。但我不确定这是否值得付出努力和复杂。
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