優先エンコーダで if/case を理解する
このページで学ぶ内容
- 概要:プライオリティエンコーダを例にして、優先順位つきの回路記述を学ぶ
- 目標:プライオリティエンコーダとは何か/if文を使った記述/casex文を使った記述
- 修了判定:各種エンコーダの記述を論理合成し、結果を比較する
(2)プライオリティエンコーダとは
エンコード回路にも優先順位があります。これをプライオリティエンコーダといいます。
プライオリティエンコーダを簡単な例で説明します。A・B・C の 3 つのキーを入力し、2 ビットの信号を出力するエンコーダを考えます。
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)」の扱いが違うから、トラブルシュートの時は気をつけてね!
| A | B | C | ENC_OUT |
|---|---|---|---|
| 0 | 0 | 0 | 00 |
| 1 | 0 | 0 | 01 |
| 0 | 1 | 0 | 10 |
| 0 | 0 | 1 | 11 |
ところがこの真理値表では、複数の入力が同時に 1 になった場合に出力が決まりません。そこでキーに優先順位をつけて真理値表を作り直します。
ここでは A の優先順位が最も高く、LSB 側に行くほど優先順位が低くなるように設計します。
- A が押されているとき、B と C の値は出力に影響しない
- B と C が同時に押されても、出力は
10(B が優先)
このように入力に優先順位のあるエンコーダをプライオリティエンコーダと呼びます。
出力に影響を与えない入力部分を don't care(x) で表すと、優先順位を真理値表でシンプルに表現できます。
| A | B | C | ENC_OUT | 備考 |
|---|---|---|---|---|
| 0 | 0 | 0 | 00 | 入力なし |
| 1 | x | x | 01 | A が最優先 |
| 0 | 1 | x | 10 | B が次に優先 |
| 0 | 0 | 1 | 11 | C は最低優先 |
don't care の入力は出力に影響しないため、どちらの値でも同じ出力が得られます。
(3)if 文によるエンコーダ記述
入力が 8 本、出力が 3 本のプライオリティエンコーダを考えます。MSB 側(DIN[7])の優先順位が最も高く、LSB 側に行くほど低くなります。
| DIN[7:0] | DOUT[2:0] | 優先順位 |
|---|---|---|
| 1xxxxxxx | 7 | 高(最優先) |
| 01xxxxxx | 6 | ↑ |
| 001xxxxx | 5 | | |
| 0001xxxx | 4 | | |
| 00001xxx | 3 | | |
| 000001xx | 2 | | |
| 0000001x | 1 | ↓ |
| 00000001 | 0 | 低(最低) |
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 文は不定値 x やハイインピーダンス z を don'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] |
|---|---|
| 10000000 | 7 |
| 01000000 | 6 |
| 00100000 | 5 |
| 00010000 | 4 |
| 00001000 | 3 |
| 00000100 | 2 |
| 00000010 | 1 |
| 00000001 | 0 |
// 優先順位のないエンコーダ
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 の出力値は
3'hx(不定値)にしてください - 固定値(例:
3'h0)を書くと回路規模が大きくなります
(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) | 17 | 2.51 |
| encoder_casex.v(ENCODER_CASEX) | 17 | 2.51 |
| enc_nonprior.v(ENC_NONPRIOR) | 9 | 1.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本の入力信号 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