moduleおよびinterfaceのbindと信号の参照方法

主にAssertion等の用途でmoduleやinterfaceを他のmoduleにbindする事がある。その際に必要な信号を参照する方法を紹介する。

### bindのポート接続で参照
bindされるmoduleにinput portを定義し、bind時に参照する信号を接続する。その際に`.*`による暗黙的ポート接続が使える。いちいち手で繋ぐのも面倒なので`.*`で繋ぐことをお勧めする。
下位モジュールの信号はポート接続の所で階層参照で接続する。
```verilog:checker.sv
bind tb.i_dut checker i_checker( .*, .signal_b(i_sub.signal_b) );

module checker ( input clk, rst_n, signal_a, signal_b );

  a_AB : assert property (@(posedge clk) disable iff(!rst_n) signal_a |=> signal_b);

endmodule 
```

### 絶対パスで指定 
ポートで接続せずとも当然絶対パスで信号を参照する事ができる。しかし、絶対パスは階層が変わったりすると使えなくなり、再利用性が悪いのでお勧めしない。そもそも絶対パスで参照するならbindなんてする必要はない。
```verilog:checker.sv
bind tb.i_dut checker i_checker( .*);

module checker ( input clk, rst_n);

  // Absolute signal path referencing
  wire aignal_a = $root.tb.i_dut.signal_a;
  wire aignal_b = $root.tb.i_dut.i_sub.signal_b;
//wire aignal_a =       tb.i_dut.signal_a;
//wire aignal_b =       tb.i_dut.i_sub.signal_b;

  a_AB : assert property (@(posedge clk) disable iff(!rst_n) signal_a |=> signal_b);

endmodule 
```

### 相対パスで指定
あまり知られてはいない様だがbindしたmoduleからの相対パスで信号を参照できる。相対パスでの信号の参照方法にも２種類あり、bindしたmoduleのインスタンス名から含める方法と含めない方法がある。
bindしたmodule以下のサブモジュール以下の信号への参照であればどちらの方法でも良いが、bindしたmodule内の直下の信号を参照する場合には必ずそのmoduleのインスタンス名から指定する必要がある。
```verilog:checker.sv
bind tb.i_dut checker i_checker( .*);

module checker ( input clk, rst_n);

  //-- 1. Relative signal path referencing with bound module instance name
  wire signal_a = i_dut.signal_a;
  wire signal_b = i_dut.i_sub.signal_b;

  //-- 2. Relative signal path referencing without bound module instance name
//wire signal_a2 = signal_a;        // NG !
  wire signal_b2 = i_sub.signal_b;  // OK 

  a_AB  : assert property (@(posedge clk) disable iff(!rst_n) signal_a |=> signal_b );
  a_AB2 : assert property (@(posedge clk) disable iff(!rst_n) signal_a |=> signal_b2);

endmodule 
```

### interfaceのbind
interfaceもmoduleと同様なので全く同様にbindが可能。
```verilog:dut_if.sv
bind tb.i_dut dut_if i_if( .*);

interface dut_if ( input clk, rst_n, signal_a);

  wire signal_b = i_sub.signal_b; 

  a_AB : assert property (@(posedge clk) disable iff(!rst_n) signal_a |=> signal_b);

endinterface 
```

interfaceをbindすると何が良いのかと言うとvirtual interfaceとしてそのinterfaceのハンドル（？）をcalssの様なダイナミックオブジェクトにも渡す事ができる。
```verilog:tb.sv
module tb;

  class aaa;
    virtual dut_if v_if;
    
    virtual task run();
      wait(v_if.signal_a);
      ...
    endtask

  endclass

  initial begin
    aaa a = new(); 
    a.v_if = i_dut.i_if;  // <==== Passing the handle to a class
    a.run();
    ...
  end

  dut i_dut(.*);

endmodule 
```

これはmoduleではできず、interfaceにしかする事ができない。なので特に理由が無ければmoduleではなくinterfaceをbindする事をお勧めする。

moduleは完全にstaticな世界の住人なのだが、interfaceはvirtual interfaceによりstaticな世界をdynamicな世界に結ぶ事ができる存在なのである。

UVMではSequenceとかでDUTの内部信号を参照したい場合に、このinterfaceのbindを使う事でそれが可能となる。（あるいはbindせずともテストベンチでinterfaceをinstance化して階層参照で信号を参照してinterface内の信号にassignしてもできる。）
以下のWhitebox verificationをご参考

https://verificationacademy.com/resources/technical-papers/the-missing-link-the-testbench-to-dut-connection

[Paper in PDF](https://verificationacademy.com/resource/77022?download_refer=/resources/technical-papers/the-missing-link-the-testbench-to-dut-connection " The Missing Link: The Testbench to DUT Connection")

以下、Virtual Interfaceを使ってDUTのstaticな世界をUVMのdyamicな世界を繋げるQiita内の記事。ただしこれではbindは使っていない。

https://qiita.com/yakiraicho/items/442078b652e04733d69c

この記事では既存のBFMのfunction/taskにアクセスする方法としてVirtual Class(Abstract Class)を紹介しているが、必ずしもVirtual Classを使う必要はなくVirtual Interfaceでやる事も可能。その場合にはinterfaceをBFM moduleにbindしてinterfaceからBFM内にアクセス可能にするとか、あるいはテストベンチトップにbindしてBFM module instanceにアクセスするとか考えられる。もしくはbindせずとも絶対パス参照でBFMにアクセスするようにしても良い。

***
### 参考
https://qiita.com/triggerfish/items/0185b0edbe3e4feaae99

https://qiita.com/gc_cic/items/12a023d17a7f55172f51

https://www.progresstype.com/2019/06/sva-5.html

https://sites.google.com/site/playsystemverilog/others/interface