Verilog基本文法(後編)

📌 このページについて VerilogHDLにはいろいろな演算があります。C言語に似た演算が多いですが、HDL特有の演算(リダクション演算・連接演算)もあります。一つ一つ確実に理解しましょう。

1. 論理値と定数表現

もふねこ

ソフトウェアと違って、ハードウェアの信号には「不定値(X)」と「ハイインピーダンス(Z)」があるんだ🐾
この4つの状態と、ちょっと変わった「数字の書き方」を覚えよう!

VerilogHDLで扱える論理値は以下の4値のみです。

意味用途
0論理0(Low)通常の論理値
1論理1(High)通常の論理値
x不定値初期化前・競合状態
zハイインピーダンストライステートバッファ出力

定数の書式

定数は <ビット幅>'<基数><数値> の形式で表現します。

要素内容省略時のデフォルト
ビット幅10進数でビット幅を指定32ビット
基数b/B=2進、o/O=8進、d/D=10進、h/H=16進10進(d)
数値基数に対応した値。xとzも使用可(10進を除く)
4'b1010      // 4ビット2進数: 1010
8'hFF        // 8ビット16進数: 255
8'b1111_1111 // アンダースコアで区切り可(読みやすく)
8'hxx        // 不定値
1'bz         // 1ビットハイインピーダンス
255          // ビット幅指定なし→32ビット10進数

2. 演算子一覧

種類演算子説明
算術演算+ - * / %加減乗除・余り
ビット演算& | ~ ^ ~^AND/OR/NOT/XOR/XNOR(ビット単位)
リダクション演算&A |A ^A全ビットに作用→1ビット出力
等号演算== != === !==等値・不等値比較(===はx/zも比較)
関係演算< > <= >=大小比較
論理演算&& || !AND/OR/NOT(条件判別・1ビット出力)
シフト演算<< >>左シフト・右シフト
条件演算式1 ? 式2 : 式32方向分岐(セレクタ)
連接演算{A, B}信号を結合して複数ビット信号を作成

3. 算術演算

assign SUM  = A + B;   // 8ビット加算
assign DIFF = A - B;   // 減算
assign PROD = A * B;   // 乗算
⚠️ 除算・余り演算の注意 /(除算)と %(余り)は多くの論理合成ツールが対応していません。シミュレーション専用と考えてください。

4. ビット演算

対応するビット同士で演算します。演算結果のビット幅は入力と同じです。

assign AND_out = A & B;   // ビットAND(bit0同士、bit1同士…と演算)
assign OR_out  = A | B;   // ビットOR
assign NOT_out = ~A;      // ビットNOT(反転)
assign XOR_out = A ^ B;   // ビットXOR(排他的論理和)
assign XNOR_out= A ~^ B;  // ビットXNOR

5. リダクション演算

複数ビット信号の全ビットに演算を作用させ、1ビットの結果を得る演算です。演算子を信号の前に置きます。

reg [7:0] cnt;
wire all_one = &cnt;   // cntの全ビットがAND → 全部1のとき1
wire any_one = |cnt;   // cntの全ビットがOR  → 1つでも1なら1
wire parity  = ^cnt;   // cntの全ビットがXOR → パリティビット生成
💡 リダクション演算の利点 ビットごとに演算したものと等価ですが、簡潔に記述できるため誤りが少なくなります。パリティ生成・全ビット一致チェックに特に有効です。

6. 等号演算・関係演算

演算結果は常に1ビット(成立=1、不成立=0)です。

演算子意味x/z の扱い
==等値x/zが含まれると不成立(0)
!=不等値x/zが含まれると不成立(0)
===完全等値(case等値)x/zも比較対象(論理合成不可)
!==完全不等値x/zも比較対象(論理合成不可)
< > <= >=大小比較x/zが含まれると不成立(0)

7. 論理演算

複数の条件判別を組み合わせる演算です。演算対象を1ビットの値として扱い、結果も1ビットです。主にif文などの条件判別に使います。

// 例:AがFFhでかつBが0でない場合に処理を実行
if ((A == 8'hFF) && (B != 8'h00)) begin
    // 両方の条件が成立したときに実行
end else begin
    // いずれか不成立のとき
end
⚠️ ビット演算(&)と論理演算(&&)を混同しない &はビット単位演算(結果はNビット)、&&は条件判別(結果は1ビット)です。詳細は「ビット演算 vs 論理演算」の節を参照。

8. シフト演算

assign Q = A << SFT;  // Aを SFT ビット分だけ左シフト
assign R = A >> SFT;  // Aを SFT ビット分だけ右シフト
方向空いたビット溢れたビット
左シフト(<<)LSB側に0を挿入MSB側が欠落
右シフト(>>)MSB側に0を挿入LSB側が欠落

9. 条件演算(? :)

1行で2方向分岐を記述できる演算です。式1 ? 式2 : 式3 の形式で、式1が成立なら式2を、不成立なら式3を選びます。

条件演算(assign文1行)
// sel=1ならd1、0ならd0を選ぶ
assign dout = sel ? d1 : d0;
if文(always/function内)
reg dout;
always @(*) begin
  if (sel) dout = d1;
  else     dout = d0;
end
💡 使い分けの目安 シンプルなセレクタなら条件演算が簡潔です。複雑な分岐や複数の代入が必要な場合はif文/case文を使います。

10. 連接演算({})

複数の信号を {} で囲んで結合し、複数ビットの信号を作る演算です。左側が上位ビットになります。

// 右辺での使用:2つの8ビット信号を連接して16ビットに
wire [15:0] addr_bus = {addr_hi, addr_lo}; // 上位8bit=addr_hi, 下位8bit=addr_lo

// 左辺での使用:16ビットの演算結果を2つの8ビット信号に分配
{addr_hi, addr_lo} = addr_bus + 1;

// 繰り返し連接:enable信号を8回繰り返して8ビット信号を生成
wire [7:0] dout = din & {8{enable}};  // dinの全ビットにenableをAND
⚠️ ビット幅の違う信号をANDするとき 1ビットの enable 信号をそのまま8ビット信号にANDすると、下位1ビットにしか影響しません。{8{enable}} で8ビットに拡張してからANDすることで全ビットに作用します。

11. ビット演算 vs 論理演算

項目ビット演算(&)論理演算(&&)
演算対象対応するビット同士値全体を1ビットとして扱う
結果のビット幅入力と同じNビット常に1ビット
主な用途回路記述(信号のマスク等)条件判別(if文等)
wire [7:0] A = 8'hAA; // 1010_1010
wire [7:0] B = 8'h0F; // 0000_1111

wire [7:0] bit_and = A & B;   // ビット演算 → 8'h0A (0000_1010)
wire       log_and = A && B;  // 論理演算 → 1'b1 (AもBも0でないため)
⚠️ 使い分けを誤ると誤動作 数値の演算にはビット演算(&)、条件判別には論理演算(&&)を使います。混同すると意図しない値が代入されます。
もふねこ

「&」と「&&」の使い間違いは、コンパイルエラーにならないからバグ探しが大変なんだ🐾
条件分岐(if)には『2つ重ねる(&&)』ってルールにしておくと安全だよ!

12. 演算の優先順位

優先度演算子種類
1(最高)! ~ & | ^(単項)論理NOT・ビットNOT・リダクション演算・符号
2* / %乗除算
3+ -加減算
4<< >>シフト演算
5< > <= >=関係演算
6== != === !==等号演算
7&ビットAND
8^ ~^ビットXOR/XNOR
9|ビットOR
10&&論理AND
11||論理OR
12(最低)? :条件演算

優先順位の例

// 例1:* は + より優先
assign Y = A * B + C;    // (A*B) + C として演算
assign Y = A * (B + C);  // +を優先させたければ括弧で囲む

// 例2:+ は << より優先
assign Y = A << B + C;   // A << (B+C) として演算 ← 意図と異なる可能性
assign Y = (A << B) + C; // <<を優先させたければ括弧で囲む

// 例3:同優先度は左から
assign Y = a ^ b & c;   // (a^b) & c (左側が優先)
assign Y = a ^ (b & c); // &を優先させたければ括弧で囲む

13. 演算の注意事項

📝 E5 演算の注意事項まとめ

注意点内容
ビット幅の不一致足りない側は上位に0を補う。多い側は上位が欠落する
定数のビット幅ビット幅を明示して記述すること(省略すると32ビット)
符号付き演算VerilogHDLは符号を直接記述できない。符号処理回路を別途設計する
演算優先順位優先順位に頼らず括弧で明示する方が安全・可読性が高い
除算・余り論理合成ツール非対応のことが多い。シミュレーション専用
===演算子x/zも比較可能だが論理合成不可。テストベンチ専用