在接口任务中使用 force 语句的意外行为

Unexpected behavior with force statement inside interface task

当我在任务中使用强制时,我看到其他不相关信号的副作用受到影响。在下面的示例中,我尝试在模块 "dut" 中强制使用 2 个自变量 "a" 和 "b"。为此,我在界面 'intf' 中使用了辅助任务 "force1"。但是我发现更改 'b' 也会导致 'a' 发生更改,如输出所示。

edaplayground 上的测试用例。 https://www.edaplayground.com/x/23LM


    module dut(intf i1);
        logic a;
        logic b;
    endmodule
    interface intf;
       task force1(bit sel, int value);
         if(sel == 0) begin
            $display("[%0t]:forcing a to %0d", $stime, value);
            force dut1.a = value;
        end
        else begin
            $display("[%0t]:forcing b to %0d", $stime, value);
            force dut1.b = value;
        end
       endtask
    endinterface
    module test();
       intf intf1();
       dut dut1(intf1);
       always@(dut1.a) begin
           $display("[%0t]:Changing value of a=%0d", $stime, dut1.a);
       end
       always@(dut1.b) begin
           $display("[%0t]:Changing value of b=%0d", $stime, dut1.b);
       end
       initial begin
            intf1.force1(.sel(0), .value(1));// Change value of a to 1
            #10;
            intf1.force1(.sel(1), .value(0));// Change value of b to 0
            #10;
            $finish;
        end
    endmodule

[0]:forcing a to 1
[0]:Changing value of a=1
[10]:forcing b to 0
[10]:Changing value of a=0     ----------> WHY DID THIS CHANGE?
[10]:Changing value of b=0

I expected the output 'a' not to change to 0.

问题是value是一个静态变量。当您在 Verilog 中声明一个任务时,除非您将任务指定为 automatic,否则任务中的所有变量都将是静态的,这意味着对修改变量的任务的每次调用都会对对该任务的所有调用执行此操作(就像在 C 中创建静态局部变量一样。

同样重要的是要注意 force 程序分配不只是解析 RHS 并将 LHS 设置为该值,而是强制将 LHS 设置为 RHS 上的表达式。因此,像 force A = B; 这样的赋值将使 A 等于 B 在应用 force 时以及 B 之后可能更新的任何时间。将其与上面的信息放在一起(value 是静态的),您没有将 dut1.a 设置为 1 而您的 force,而是将其设置为 value。一旦 value 随您下一次调用您的任务而变化,dut1.a 也会随之变化以匹配它。

现在,不幸的是,您不能只创建任务 automatic 或只创建 value automatic 来解决问题,因为 force 需要静态表达式(即,只有静态变量或常量的表达式)才能工作。一种解决方案是为您想要的值创建一个静态占位符,将您的 force 与您的任务输入 value 断开连接;你可以用一个数组来做到这一点:

task force1(bit sel, int value);
  static int values[1 << $bits(sel)]; // <- Make sure no matter the width of sel, there are enough places in the array, could just be values[2]
  values[sel] = value;
  if(sel == 0) begin
    $display("[%0t]:forcing a to %0d", $stime, value);
    force dut1.a = values[0];
  end
  else begin
    $display("[%0t]:forcing b to %0d", $stime, value);
    force dut1.b = values[1];
  end
endtask