Menu

Verilog ビット単位演算子とreduction演算子

Verilogのビットレベル演算子。ビット単位AND/OR/XOR、その反転形、そしてvector全体を1ビットに畳むreduction演算子。

このページのコードはエディタで実行できます - 編集してすぐに結果を確認できます。

同じ記号、2つの役割

&|^とその反転兄弟は2つの異なる形で現れます:

  • 二項形式(2オペランド):a & b - 同じ幅のvector間のビット単位演算。
  • 単項形式(1オペランド):&a - aの全ビットを単一ビットに畳むreduction。

コンパイラはオペランド数で区別します。命名規則として、二項形式を「ビット単位演算子」、単項形式を「reduction演算子」と呼びます。

ビット単位:1ビットずつ

フルセット:

Operator名前位置Nでの出力ビット
a & bANDa[N] AND b[N]
a | bORa[N] OR b[N]
a ^ bXORa[N] XOR b[N]
a ~& bNANDNOT (a[N] AND b[N])
a ~| bNORNOT (a[N] OR b[N])
a ~^ bXNORNOT (a[N] XOR b[N])
~aNOTNOT a[N]

~&~|~^はチルダが先、演算子が後で綴られることに注意してください。これらは1つのトークンで、間にスペースはありません。

2つのオペランドの幅が異なるとき、狭い方が一致するように 左側にゼロ拡張 されます。符号拡張が欲しい場合は、$signed()でsignedオペランドを明示的に使ってください。

Reduction:多ビットから1ビットへ

同じ演算子の単項形式は、vectorを1ビットに畳みます:

各々の意味:

  • &datadataすべてのビット が1なら1を返し、そうでなければ0を返します。「これは全部1か?」のチェックに有用。
  • |datadataいずれかのビット が1なら1を返し、そうでなければ0を返します。「これは非0か?」のチェックに有用。
  • ^dataパリティ (全ビットのXOR)を返します。1の数が奇数なら1、偶数なら0
  • ~&data~|data~^dataは上記の逆。

実際のコードで至るところで見ます:

wire empty       = ~|fifo_count;       // countが0なら空
wire all_ones    = &mask;              // すべてのビットがセット
wire parity_bit  = ^data;              // バイトのパリティ
wire any_request = |request_vector;    // 何かリクエストされている?

reduction形式は簡潔で、自明なgate treeに合成されます:&は多入力ANDに、|は多入力ORに、^はXOR tree(ハードウェアではパリティジェネレータでもあります)に。

一般的なパターン

ビットのセットとクリア

wire [7:0] data;
wire [7:0] mask = 8'b0000_1000;

wire [7:0] set     = data | mask;     // ビット3を1に強制
wire [7:0] cleared = data & ~mask;    // ビット3を0に強制
wire [7:0] toggled = data ^ mask;     // ビット3を反転
wire [7:0] tested  = data & mask;     // ビット3が0なら0、非0なら非0

これらはCで使うのと同じビット操作の慣用句です。単一gate演算に合成されます。

値が全1かチェック

wire is_max = &counter;       // counterの各ビットが1なら1

1個のgateでのreduction AND vs counter == 8'hFFを書く方法(後者も動きます。合成ツールは通常同じハードウェアを生成します)。

パリティビットの生成

アクティブsignalの検出

wire any_pending = |request_vector;

request_vectorが幅広い場合(例えば64のリクエスタ)、reduction ORが優先エンコーダや調停器に供給できる1本のsignalに畳みます。

シフト演算子

ビットレベルの演算子の話のついでに、シフト:

  • a << NaNビット位置左にシフトし、右側をゼロで埋める。
  • a >> NaNビット位置右にシフトし、左側をゼロで埋める。
  • a <<< Nは算術左シフト(unsignedでは<<と同じ)。
  • a >>> Nは算術右シフト、aがsignedなら符号ビットで埋める。

定数のべきによるシフトはハードウェアで無料(単なる配線変更)です。ランタイム変数によるシフトはバレルシフタを生成し、より大きいですが依然として安価です。

次に読むもの

これで1つの値を返すすべての演算子を見ました。次のドキュメント連結と繰り返しは、ピースから広いvectorを構築する{}{N{...}}構文を扱います。異なる幅のmodule間のインターフェースで常に使うことになります。

よくある質問

Verilogのビット単位演算子とは?

ビット単位演算子は同じ幅の2つのvectorを位置ごとに組み合わせます。a & baのビット0とbのビット0をAND、ビット1とビット1、というふうにし、入力と同じ幅のvectorを生成します。フルセットは&(AND)、|(OR)、^(XOR)、~(NOT)、そして反転形~&~|~^(NAND、NOR、XNOR)です。

Verilogのreduction演算子とは?

reduction演算子はビット単位演算子の単項形式で、vector全体を1ビットに畳みます。&datadataの各ビットが1のときだけ1を返します。|dataはいずれかのビットが1なら1を返します。^dataはすべてのビットのXOR、つまりパリティを返します。reduction形式は左にオペランドがなく、右側だけです。

Verilogの&と&&の違いは?

&はビット単位ANDで、ビットを位置ごとにペアにし、結果はオペランドと同じ幅です。&&は論理ANDで、各オペランドをブール(0か非0)として扱い、1ビット結果を返します。4'b1100 & 4'b00114'b00004'b1100 && 4'b00111です。

Verilogでパリティを計算するには?

reduction XOR演算子を使います:parity = ^datadataの各ビットをすべてXORします。8ビットvectorならdata[7] ^ data[6] ^ ... ^ data[0]です。立っているビット数が奇数なら結果は1、偶数なら0です。~^で反転すれば偶数パリティになります。

Verilogの~の働きは?

~はビット単位NOTで、オペランドの各ビットを反転します。~4'b11004'b0011です。オペランドを1ビットブールに畳んで反転する!(論理NOT)と混同しないでください。!4'b11001'b0です(オペランドが非0、その真理値をNOTすると0)。

Coddy programming languages illustration

Coddyでコードを学ぼう

始める