優先エンコーダで if/case を理解する

このページで学ぶ内容

  • 概要:プライオリティエンコーダを例にして、優先順位つきの回路記述を学ぶ
  • 目標:プライオリティエンコーダとは何か/if文を使った記述/casex文を使った記述
  • 修了判定:各種エンコーダの記述を論理合成し、結果を比較する

(2)プライオリティエンコーダとは

エンコード回路にも優先順位があります。これをプライオリティエンコーダといいます。

プライオリティエンコーダを簡単な例で説明します。A・B・C の 3 つのキーを入力し、2 ビットの信号を出力するエンコーダを考えます。

graph LR subgraph プライオリティエンコーダ ENC[ENCODER] end A[A] --> ENC B[B] --> ENC C[C] --> ENC ENC -->|2| OUT[ENC_OUT
2bit] style ENC fill:#e3f2fd,stroke:#1976d2,stroke-width:2px;
基本エンコーダの端子構成

入力:A, B, C(3本) → 出力:ENC_OUT(2bit)

キーが押されていない状態(A=B=C=0)では出力は 00。A が押されると 01、B が押されると 10、C が押されると 11 になります。

もふねこ

もふねこ:
「優先順位」ってなんだか難しそうに聞こえるけど、要は「同時にボタンが押されたとき、どっちを優先するか」を決めるだけだよ🐾!
if文と casex文、最終的な回路は同じになるけど、シミュレーションでの「不定値(x)」の扱いが違うから、トラブルシュートの時は気をつけてね!

ABCENC_OUT
00000
10001
01010
00111

ところがこの真理値表では、複数の入力が同時に 1 になった場合に出力が決まりません。そこでキーに優先順位をつけて真理値表を作り直します。

ここでは A の優先順位が最も高く、LSB 側に行くほど優先順位が低くなるように設計します。

  • A が押されているとき、B と C の値は出力に影響しない
  • B と C が同時に押されても、出力は 10(B が優先)

このように入力に優先順位のあるエンコーダをプライオリティエンコーダと呼びます。

出力に影響を与えない入力部分を don't care(x) で表すと、優先順位を真理値表でシンプルに表現できます。

ABCENC_OUT備考
00000入力なし
1xx01A が最優先
01x10B が次に優先
00111C は最低優先
x: don't care(1 でも 0 でもかまわない)

don't care の入力は出力に影響しないため、どちらの値でも同じ出力が得られます。

(3)if 文によるエンコーダ記述

入力が 8 本、出力が 3 本のプライオリティエンコーダを考えます。MSB 側(DIN[7])の優先順位が最も高く、LSB 側に行くほど低くなります。

DIN[7:0]DOUT[2:0]優先順位
1xxxxxxx7高(最優先)
01xxxxxx6
001xxxxx5|
0001xxxx4|
00001xxx3|
000001xx2|
0000001x1
000000010低(最低)
if 文の優先順位ルール

if・else if の構造は先に書いた条件が優先されます。優先順位の高い条件から順に記述します。

// if文によるプライオリティエンコーダ
module ENCODER_IF( DIN, DOUT );
    input  [7:0] DIN;
    output [2:0] DOUT;
    reg    [2:0] DOUT;

    always @( DIN ) begin
        if      ( DIN[7]==1'b1 )  DOUT <= 3'h7;
        else if ( DIN[6]==1'b1 )  DOUT <= 3'h6;
        else if ( DIN[5]==1'b1 )  DOUT <= 3'h5;
        else if ( DIN[4]==1'b1 )  DOUT <= 3'h4;
        else if ( DIN[3]==1'b1 )  DOUT <= 3'h3;
        else if ( DIN[2]==1'b1 )  DOUT <= 3'h2;
        else if ( DIN[1]==1'b1 )  DOUT <= 3'h1;
        else                      DOUT <= 3'h0;
    end
endmodule

(4)casex 文によるエンコーダ記述

同じ真理値表を、今度は casex 文を使って表現します。

casex 文の特徴

casex 文は不定値 x やハイインピーダンス zdon't care として扱います。真理値表の x をそのまま記述でき、非常にわかりやすい記述になります。

// casex文によるプライオリティエンコーダ
module encoder_casex( DIN, DOUT );
    input  [7:0] DIN;
    output [2:0] DOUT;
    reg    [2:0] DOUT;

    always @( DIN ) begin
        casex( DIN )
            8'b1xxxxxxx:  DOUT <= 3'h7;
            8'b01xxxxxx:  DOUT <= 3'h6;
            8'b001xxxxx:  DOUT <= 3'h5;
            8'b0001xxxx:  DOUT <= 3'h4;
            8'b00001xxx:  DOUT <= 3'h3;
            8'b000001xx:  DOUT <= 3'h2;
            8'b0000001x:  DOUT <= 3'h1;
            8'b00000000x: DOUT <= 3'h0;
            default:      DOUT <= 3'hx;
        endcase
    end
endmodule

(5)優先順位のないエンコーダ

今度は優先順位のないエンコーダを記述します。このエンコーダは「入力 DIN のいずれか 1 ビットだけが常に 1」という前提のエンコーダです。複数の信号が同時に 1 になることはないものとして考えます。

DIN[7:0]DOUT[2:0]
100000007
010000006
001000005
000100004
000010003
000001002
000000101
000000010
// 優先順位のないエンコーダ
module enc_nonprior( DIN, DOUT );
    input  [7:0] DIN;
    output [2:0] DOUT;
    reg    [2:0] DOUT;

    always @( DIN ) begin
        case( DIN )
            8'b1000_0000:  DOUT <= 3'h7;
            8'b0100_0000:  DOUT <= 3'h6;
            8'b0010_0000:  DOUT <= 3'h5;
            8'b0001_0000:  DOUT <= 3'h4;
            8'b0000_1000:  DOUT <= 3'h3;
            8'b0000_0100:  DOUT <= 3'h2;
            8'b0000_0010:  DOUT <= 3'h1;
            8'b0000_0001:  DOUT <= 3'h0;
            default:       DOUT <= 3'hx;
        endcase
    end
endmodule
⚠️ default の記述を忘れずに!
  • default を省略するとラッチが生成されてしまいます
  • default の出力値は 3'hx(不定値)にしてください
  • 固定値(例: 3'h0)を書くと回路規模が大きくなります
graph LR subgraph 論理合成結果(優先順位回路) direction LR A[A] --> OR1{{OR}} B[B] --> OR1 C[C] --> AND1{{AND}} NOT_A{{NOT}} --> AND1 A -.-> NOT_A AND1 --> OR2{{OR}} B -.-> OR2 OR1 --> OUT1[ENC_OUT_1] OR2 --> OUT0[ENC_OUT_0] end style OR1 fill:#fff3e0,stroke:#f57c00; style OR2 fill:#fff3e0,stroke:#f57c00; style AND1 fill:#e8f5e9,stroke:#388e3c; style NOT_A fill:#e3f2fd,stroke:#1976d2;

(6)ワンポイント・アドバイス:if 文と casex 文の動作の違い

本文中の 2 つのプライオリティエンコーダ(if 文版・casex 文版)は論理合成すると同じ回路が生成されます。しかし、シミュレーションの結果は必ずしも同じではありません。

if 文(ENCODER_IF)

入力のすべてのビットが不定値になると → 0 が出力

(else 節が実行されるため)

casex 文(encoder_casex)

入力のすべてのビットが不定値になると → 7 が出力

(casex は x をdon't care として扱い、最初のパターン 8'b1xxxxxxx にマッチするため)

まとめ

if 文と casex 文による記述は基本的な動作は同じでも、不定値入力時の細かい挙動が異なります。シミュレーションの正確性が重要な場面では、この違いを意識して記述方法を選んでください。

(7)修了判定

設問

本文の各記述を論理合成する。論理合成後のレポートで結果を比較する。

  • if 文を使ったプライオリティエンコーダ:encoder_if.v
  • casex 文を使ったプライオリティエンコーダ:encoder_casex.v
  • 優先順位の無いエンコーダ:enc_nonprior.v

論理合成結果

モジュール回路規模(ゲート数)遅延時間(ns)
encoder_if.v(ENCODER_IF)172.51
encoder_casex.v(ENCODER_CASEX)172.51
enc_nonprior.v(ENC_NONPRIOR)91.35

ENCODER_IF 論理合成レポート

************************************
レポート : area
回路    : ENCODER_IF
************************************
ポート数:           11
ネット数:           19
セル数:             12
セル種類:            7
組み合わせ回路:     17
非組み合わせ回路:    0
合計:               17

************************************
レポート : timing
回路    : ENCODER_IF
************************************
ライブラリ:         hd350s
配線遅延モデル:     hd350s_05k
コンディション:     MAX567
--------------------------------------
DIN[2] (in)      0.00    0.00
DOUT[0] (out)    0.00    2.51
データ到着時刻          2.51

ENCODER_CASEX 論理合成レポート

************************************
レポート : area
回路    : ENCODER_CASEX
************************************
ポート数:           11
ネット数:           19
セル数:             12
セル種類:            7
組み合わせ回路:     17
非組み合わせ回路:    0
合計:               17

************************************
レポート : timing
回路    : ENCODER_CASEX
************************************
ライブラリ:         hd350s
配線遅延モデル:     hd350s_05k
コンディション:     MAX567
--------------------------------------
DIN[2] (in)      0.00    0.00
DOUT[0] (out)    0.00    2.51
データ到着時刻          2.51

ENC_NONPRIOR 論理合成レポート

************************************
レポート : area
回路    : ENC_NONPRIOR
************************************
ポート数:           11
ネット数:           10
セル数:              3
セル種類:            1
組み合わせ回路:      9
非組み合わせ回路:    0
合計:                9

************************************
レポート : timing
回路    : ENC_NONPRIOR
************************************
ライブラリ:         hd350s
配線遅延モデル:     hd350s_05k
コンディション:     MAX567
--------------------------------------
DIN[5] (in)      0.00    0.00
DOUT[2] (out)    0.00    1.35
データ到着時刻          1.35

O1 まとめ

  • プライオリティエンコーダ:複数の入力が 1 になったとき、優先順位の高い入力のみを有効にするエンコーダ
  • if 文:優先順位の高い条件を先に書く → if/else if の構造が優先順位を表現
  • casex 文:don't care(x/z)を使った真理値表をそのまま記述できる → 可読性が高い
  • if 文と casex 文は論理合成後は同一回路(規模 17、遅延 2.51ns)になる
  • 優先順位なしエンコーダ(case 文)は回路規模が小さい(規模 9、遅延 1.35ns)
  • case 文では default に必ず 3'hx を書くこと(ラッチ生成と回路肥大化を防ぐ)
  • 不定値入力時のシミュレーション挙動は if 文と casex 文で異なるため注意が必要

(6)修了判定

⚠️ 修了判定:8-to-3 プライオリティエンコーダ

設問:8本の入力信号 DIN[7:0] を受け取り、3ビットの出力 DOUT[2:0] にエンコードする回路を記述せよ。MSB(DIN[7])が最も優先度が高いものとする。if文 または casex文のいずれかを用いて記述すること。

解答例:casex文を用いた記述

module PRI_ENC8 ( DIN, DOUT );
input  [7:0] DIN;
output [2:0] DOUT;
reg    [2:0] DOUT;

always @( DIN ) begin
    casex ( DIN )
        8'b1xxx_xxxx : DOUT <= 3'd7;
        8'b01xx_xxxx : DOUT <= 3'd6;
        8'b001x_xxxx : DOUT <= 3'd5;
        8'b0001_xxxx : DOUT <= 3'd4;
        8'b0000_1xxx : DOUT <= 3'd3;
        8'b0000_01xx : DOUT <= 3'd2;
        8'b0000_001x : DOUT <= 3'd1;
        8'b0000_0001 : DOUT <= 3'd0;
        default      : DOUT <= 3'dX;
    endcase
end
endmodule