出木杉君演算子 inside
石谷 @PEZY Computing です。SystemVerilog Advent Calendar 2020 と言うことで、inside 演算子の紹介をしたいと思います。
inside 演算子とは
inside 演算子は SystemVerilog で導入された演算子です。LRM 上は Set membership operator として説明されています。
出木杉君と言っても過言ではないぐ便利な演算子で、以下の3つの機能を有しています。
- 複数個の比較値との比較
- 範囲の比較
- ワイルドカード比較
では、サンプルコードとともに、これらの機能を紹介していきます。
なお、サンプルコードは GitHub 上のリポジトリに置いてあります。
複数個の比較値との比較
「比較値が複数あり、どれかに一致するか」を調べる場合、従来の Verilog では、
is_matched = (v == 0) || (v == 1) || (v == 2);
のように書く必要があります。inside 演算子を使うと、これらを纏めることができて、
is_matched = v inside {0, 1, 2};
のように書くことができます。また、{} の中に配列を指定することもできて、
int valid_values[3] = '{0, 1, 2};
is_matched = v inside {valid_values};
と書くこともできます。
- 注意
- Synopsys 社の Design Compiler は、上記の比較要素を配列に詰める方法をサポートしていないようです。
以下のサンプルコードを Vivado 合成すると、
module sample_1 (
input var [1:0] i_d,
input var [1:0] i_a,
input var [1:0] i_b,
input var [1:0] i_c,
output var o_matched
);
always_comb begin
o_matched = i_d inside {i_a, i_b, i_c};
end
endmodule
以下のようになります。想像通り、3個の == の出力の OR になりました。
範囲の比較
inside 演算子は出木杉君なので、範囲の比較もすることができます。
min <= v <= max のような比較を行う場合、Verilog では、
in_range = (v >= 4) && (v <= 7);
のように書く必要があります。inside 演算子では {} の中に [min:max] のように値域を指定することができて、
in_range = v inside {[4:7]};
のように書くことができます。[min:max] の min/max は定数だけではなく、変数 (信号) を指定することもできて、
int min = 4;
int max = 7;
in_range = v inside {[min:max]};
と書くこともできます。
また、$ を : の左側に置くと inside の左辺値の最小値、右側に置くと最大値を表します。以下のような場合は、
bit [2:0] a;
range_0_to_3 = a inside {[$:3]};
range_4_to_7 = a inside {[4:$]};
a inside {[0:3]} および a inside {[4:7]} と等価になります。
範囲比較の場合も合成してみましょう。以下のサンプルコードを合成してみると、
module sample_2 (
input var [1:0] i_d,
input var [1:0] i_min,
input var [1:0] i_max,
output var [3:0] o_in_range
);
always_comb begin
o_in_range[0] = i_d inside {[i_min:i_max]};
o_in_range[1] = i_d inside {[ $:i_max]};
o_in_range[2] = i_d inside {[i_min: $]};
o_in_range[3] = i_d inside {[ $: $]};
end
endmodule
案の定な結果になります。
ワイルドカード比較
{} の中の値の ?/x/z は don't care として扱われ、ワイルドカードとして振舞います。有能ですね。
例えば、以下のような場合、
bit [3:0] v;
bit is_matched;
is_matched = v inside {4'b1?0?};
v が 4'b1000/4'b1001/4'b1100/4'b1101 の場合に、is_matched が 1 になります。それ以外では、0 です。
では、さっそく Vivado に食わせてみましょう。
module samaple_3 (
input var [3:0] i_d,
output var o_matched
);
always_comb begin
o_matched = i_d inside {4'b1?0?};
end
endmodule
ワルドカードを使った場合も合成可能で、以下のような結果になりました。
なるほど、マスクをかけてから、比較するのですか。
補足
SystemVerilog では、右辺値にワイルドカードを取れる演算子として ==? と !=? (Wildcard equality operators) が追加されています。inside 演算子における整数値の比較は ==? を使って行われています。
合わせ技
上述の3つを、1つの {} の中に入れることもできます。超絶便利ですね。
合わせ技の場合も合成可能です。
module sample_4 (
input var [3:0] i_d,
input var [3:0] i_a,
input var [3:0] i_b,
input var [3:0] i_min,
input var [3:0] i_max,
output var o_result
);
always_comb begin
o_result = i_d inside {i_a, i_b, [i_min:i_max], 4'b11??};
end
endmodule
それぞれの結果の OR が最終結果になります。予想通りですね。
注意事項
inside 演算の結果を否定 (!) する場合は注意が必要ですつ。
inside 演算子は、論理否定演算子より結合度が低いので、
result = !v inside {0, 1};
のように書くと、
result = (!v) inside {0, 1};
のようになり、v に ! を適用した結果に inside 演算子が適用されてしまいます。
なので、このような場合は、() で囲ってあげましょう。
result = !(v inside {0, 1});
最後に
inside 演算子がいかに出木杉君かをご理解いただけたかと思います。論理合成可能な演算子なので、どんどん使っていきましょう。
(ただし Quartus ユーザーは除く。)
宣伝
YAML とか Excel で記述したレジスタマップから、RTL 等を自動生成するツール (RgGen) を作っています。
面倒な CSR のコーディングをせずに済むので、手前味噌ですが、便利なツールです。
生成された RTL は、ダメっ子 Quartus でも合成できることを確認しています。
よかったら、使ってみてください。
Qiita にも紹介記事を載せてあります。
- https://qiita.com/taichi-ishitani/items/5155b2928b7d85370ae6
- https://qiita.com/taichi-ishitani/items/d89738b5376503c813d8
UVM で記述した AMBA AXI/APB の VIP (モドキ) も公開しています。
こちらも、よければ、見てみてください。
SystenVerilog で記述した Network On Chip (NoC) も公開しています。
Design Compiler および Vivado でエラボレーションできるところまでは確認しています。
RTL 中で SystemVerilog をどこまで使えるのかの参考になると思います。
(ただし Quartus は知らない。)
UVM を使った検証環境も同梱しているので、UVM を使った検証環境の参考にもなると思います。



