各種比較演算(==, !=, ===, !==, ==?, !=?)の比較

Verilogからある従来の比較演算(==,!=)とSystemVerilogで新たに加わったExact Match(===, !===)とWildcard Match(==?, !=?)について動作の違いについて調べてみたのでメモ。

#### テストベンチ
```verilog:tb.sv
module tb;
  logic [3:0] aaa, bbb;
  initial begin
    $display( "Conventional Match");
    $display( " ----------------------------- ");
    #10 aaa = '0; bbb = 'bxxxx; $display( " (%b == %b) --> %b " , aaa, bbb, aaa == bbb );
    #10 aaa = '1; bbb = 'bxxxx; $display( " (%b == %b) --> %b " , aaa, bbb, aaa == bbb );
    #10 aaa = 'x; bbb = 'bxxxx; $display( " (%b == %b) --> %b " , aaa, bbb, aaa == bbb );
    #10 aaa = 'z; bbb = 'bxxxx; $display( " (%b == %b) --> %b " , aaa, bbb, aaa == bbb );
    $display( " ----------------------------- ");
    #10 aaa = '0; bbb = 'b00xx; $display( " (%b == %b) --> %b " , aaa, bbb, aaa == bbb );
    #10 aaa = '1; bbb = 'b00xx; $display( " (%b == %b) --> %b " , aaa, bbb, aaa == bbb );
    #10 aaa = 'x; bbb = 'b00xx; $display( " (%b == %b) --> %b " , aaa, bbb, aaa == bbb );
    #10 aaa = 'z; bbb = 'b00xx; $display( " (%b == %b) --> %b " , aaa, bbb, aaa == bbb );
    $display( " ----------------------------- ");
    #10 aaa = '0; bbb = 'bxxxx; $display( " (%b != %b) --> %b " , aaa, bbb, aaa != bbb );
    #10 aaa = '1; bbb = 'bxxxx; $display( " (%b != %b) --> %b " , aaa, bbb, aaa != bbb );
    #10 aaa = 'x; bbb = 'bxxxx; $display( " (%b != %b) --> %b " , aaa, bbb, aaa != bbb );
    #10 aaa = 'z; bbb = 'bxxxx; $display( " (%b != %b) --> %b " , aaa, bbb, aaa != bbb );
    $display( " ----------------------------- ");
    #10 aaa = '0; bbb = 'b00xx; $display( " (%b != %b) --> %b " , aaa, bbb, aaa != bbb );
    #10 aaa = '1; bbb = 'b00xx; $display( " (%b != %b) --> %b " , aaa, bbb, aaa != bbb );
    #10 aaa = 'x; bbb = 'b00xx; $display( " (%b != %b) --> %b " , aaa, bbb, aaa != bbb );
    #10 aaa = 'z; bbb = 'b00xx; $display( " (%b != %b) --> %b " , aaa, bbb, aaa != bbb );
    $display( " ----------------------------- ");
    $display( " ");
    $display( "Exact Match");
    $display( " ----------------------------- ");
    #10 aaa = '0; bbb = 'bxxxx; $display( " (%b === %b) --> %b " , aaa, bbb, aaa === bbb );
    #10 aaa = '1; bbb = 'bxxxx; $display( " (%b === %b) --> %b " , aaa, bbb, aaa === bbb );
    #10 aaa = 'x; bbb = 'bxxxx; $display( " (%b === %b) --> %b " , aaa, bbb, aaa === bbb );
    #10 aaa = 'z; bbb = 'bxxxx; $display( " (%b === %b) --> %b " , aaa, bbb, aaa === bbb );
    $display( " ----------------------------- ");
    #10 aaa = '0; bbb = 'b00xx; $display( " (%b === %b) --> %b " , aaa, bbb, aaa === bbb );
    #10 aaa = '1; bbb = 'b00xx; $display( " (%b === %b) --> %b " , aaa, bbb, aaa === bbb );
    #10 aaa = 'x; bbb = 'b00xx; $display( " (%b === %b) --> %b " , aaa, bbb, aaa === bbb );
    #10 aaa = 'z; bbb = 'b00xx; $display( " (%b === %b) --> %b " , aaa, bbb, aaa === bbb );
    $display( " ----------------------------- ");
    #10 aaa = '0; bbb = 'bxxxx; $display( " (%b !== %b) --> %b " , aaa, bbb, aaa !== bbb );
    #10 aaa = '1; bbb = 'bxxxx; $display( " (%b !== %b) --> %b " , aaa, bbb, aaa !== bbb );
    #10 aaa = 'x; bbb = 'bxxxx; $display( " (%b !== %b) --> %b " , aaa, bbb, aaa !== bbb );
    #10 aaa = 'z; bbb = 'bxxxx; $display( " (%b !== %b) --> %b " , aaa, bbb, aaa !== bbb );
    $display( " ----------------------------- ");
    #10 aaa = '0; bbb = 'b00xx; $display( " (%b !== %b) --> %b " , aaa, bbb, aaa !== bbb );
    #10 aaa = '1; bbb = 'b00xx; $display( " (%b !== %b) --> %b " , aaa, bbb, aaa !== bbb );
    #10 aaa = 'x; bbb = 'b00xx; $display( " (%b !== %b) --> %b " , aaa, bbb, aaa !== bbb );
    #10 aaa = 'z; bbb = 'b00xx; $display( " (%b !== %b) --> %b " , aaa, bbb, aaa !== bbb );
    $display( " ----------------------------- ");
    $display( " ");
    $display( "Wildcard Match");
    $display( " ----------------------------- ");
    #10 aaa = '0; bbb = 'bxxxx; $display( " (%b ==? %b) --> %b " , aaa, bbb, aaa ==? bbb );
    #10 aaa = '1; bbb = 'bxxxx; $display( " (%b ==? %b) --> %b " , aaa, bbb, aaa ==? bbb );
    #10 aaa = 'x; bbb = 'bxxxx; $display( " (%b ==? %b) --> %b " , aaa, bbb, aaa ==? bbb );
    #10 aaa = 'z; bbb = 'bxxxx; $display( " (%b ==? %b) --> %b " , aaa, bbb, aaa ==? bbb );
    $display( " ----------------------------- ");
    #10 aaa = '0; bbb = 'b00xx; $display( " (%b ==? %b) --> %b " , aaa, bbb, aaa ==? bbb );
    #10 aaa = '1; bbb = 'b00xx; $display( " (%b ==? %b) --> %b " , aaa, bbb, aaa ==? bbb );
    #10 aaa = 'x; bbb = 'b00xx; $display( " (%b ==? %b) --> %b " , aaa, bbb, aaa ==? bbb );
    #10 aaa = 'z; bbb = 'b00xx; $display( " (%b ==? %b) --> %b " , aaa, bbb, aaa ==? bbb );
    $display( " ----------------------------- ");
    #10 aaa = '0; bbb = 'bxxxx; $display( " (%b !=? %b) --> %b " , aaa, bbb, aaa !=? bbb );
    #10 aaa = '1; bbb = 'bxxxx; $display( " (%b !=? %b) --> %b " , aaa, bbb, aaa !=? bbb );
    #10 aaa = 'x; bbb = 'bxxxx; $display( " (%b !=? %b) --> %b " , aaa, bbb, aaa !=? bbb );
    #10 aaa = 'z; bbb = 'bxxxx; $display( " (%b !=? %b) --> %b " , aaa, bbb, aaa !=? bbb );
    $display( " ----------------------------- ");
    #10 aaa = '0; bbb = 'b00xx; $display( " (%b !=? %b) --> %b " , aaa, bbb, aaa !=? bbb );
    #10 aaa = '1; bbb = 'b00xx; $display( " (%b !=? %b) --> %b " , aaa, bbb, aaa !=? bbb );
    #10 aaa = 'x; bbb = 'b00xx; $display( " (%b !=? %b) --> %b " , aaa, bbb, aaa !=? bbb );
    #10 aaa = 'z; bbb = 'b00xx; $display( " (%b !=? %b) --> %b " , aaa, bbb, aaa !=? bbb );
    $display( " ----------------------------- ");
    $finish();
  end
endmodule
```

#### 結果
```:
Conventional Match
 -----------------------------
 (0000 == xxxx) --> x
 (1111 == xxxx) --> x
 (xxxx == xxxx) --> x
 (zzzz == xxxx) --> x
 -----------------------------
 (0000 == 00xx) --> x
 (1111 == 00xx) --> 0
 (xxxx == 00xx) --> x
 (zzzz == 00xx) --> x
 -----------------------------
 (0000 != xxxx) --> x
 (1111 != xxxx) --> x
 (xxxx != xxxx) --> x
 (zzzz != xxxx) --> x
 -----------------------------
 (0000 != 00xx) --> x
 (1111 != 00xx) --> 1
 (xxxx != 00xx) --> x
 (zzzz != 00xx) --> x
 -----------------------------

Exact Match
 -----------------------------
 (0000 === xxxx) --> 0
 (1111 === xxxx) --> 0
 (xxxx === xxxx) --> 1
 (zzzz === xxxx) --> 0
 -----------------------------
 (0000 === 00xx) --> 0
 (1111 === 00xx) --> 0
 (xxxx === 00xx) --> 0
 (zzzz === 00xx) --> 0
 -----------------------------
 (0000 !== xxxx) --> 1
 (1111 !== xxxx) --> 1
 (xxxx !== xxxx) --> 0
 (zzzz !== xxxx) --> 1
 -----------------------------
 (0000 !== 00xx) --> 1
 (1111 !== 00xx) --> 1
 (xxxx !== 00xx) --> 1
 (zzzz !== 00xx) --> 1
 -----------------------------

Wildcard Match
 -----------------------------
 (0000 ==? xxxx) --> 1
 (1111 ==? xxxx) --> 1
 (xxxx ==? xxxx) --> 1
 (zzzz ==? xxxx) --> 1
 -----------------------------
 (0000 ==? 00xx) --> 1
 (1111 ==? 00xx) --> 0
 (xxxx ==? 00xx) --> x
 (zzzz ==? 00xx) --> x
 -----------------------------
 (0000 !=? xxxx) --> 0
 (1111 !=? xxxx) --> 0
 (xxxx !=? xxxx) --> 0
 (zzzz !=? xxxx) --> 0
 -----------------------------
 (0000 !=? 00xx) --> 0
 (1111 !=? 00xx) --> 1
 (xxxx !=? 00xx) --> x
 (zzzz !=? 00xx) --> x
 -----------------------------
```

#### まとめ
+ 従来の比較演算(==,!=)
左右のどちらかの比較ビットにxが含まれると比較結果を判断できず結果はx。
ただし一部ビットがxでなく確実に不一致を判定できれば==では0,!=では1。
逆に一部ビットが一致のみでは確実に一致／不一致を判断できないので==と!=の両方ともx。

+ Exact Match(===,!==)
x,zを含めてぴったり一致／不一致を判定。xとzは別物。
結果は0か1のみでxはない。

+ Wildcard Match(==?,!=?)
右辺と左辺でxの意味が違う。右辺はWildcard。
!=?は不一致を検出なので右辺が全部xだと結果は0。
Exact Matchではないので結果がxになりうる。
右辺のwildcardビットでない位置の左辺のビット位置にx,zが入ると結果はx。

#### 使用シミュレータ
Icarus Verilog version 11.0 (stable) (v11_0-132-gb2f2414f4)