フリップフロップを書く
概要: 標準IC時代のFF選択手法とHDL設計の違いを理解し、T-FF・JK-FFをVerilogで記述する方法を学ぶ。
目標:
- HDLでFFを記述する際のalways文の基本構造を理解できる
- 非同期リセット・非同期セット付きFFを記述できる
- TフリップフロップをHDLで記述できる
- JKフリップフロップをHDLで記述できる
- QB出力付きDFFをassign文を用いて効率よく記述できる
1. HDLによるフリップフロップ記述の概要
昔は「JKフリップフロップ」などのIC部品を組み合わせて回路を作っていたけど、今はHDLで好きなように書けるんだ🐾
便利な時代になったからこそ、中身の仕組みをしっかり理解して書くのが大事だよ!
フリップフロップはいろいろな種類があります。HDLで記述したらどうなるか試してみると面白いと思います。
標準IC時代の設計手法
HDLが論理回路の設計に使用されるようになる前は、標準ICである74HCシリーズ・74LSシリーズを使用して論理回路の設計の大半を行っていました。
この時代の設計者は、標準ICに使用されているフリップフロップから仕様に近いものを選択し、足りない機能は他のゲートICを組み合わせて仕様を満足する設計を行っていました。
非同期リセット付きDフリップフロップ(標準IC)とANDゲートを組み合わせて、同期リセット付きDフリップフロップを実現していました。
- 標準ICから「既存のFF」を選ぶ → 仕様に合わない場合はゲートで補う
- HDL設計では → 仕様を満足するFFを直接記述できる
2. always文によるFF記述の基本構造
HDLでフリップフロップを記述する場合はalways文を使用します。
| 種類 | イベント式の記述 | ポイント |
|---|---|---|
| 非同期リセット付きFF | @(posedge CK or negedge RB) | イベント式にリセット信号を含める |
| 同期リセット付きFF | @(posedge CK) | イベント式にリセット信号を含めない |
| 非同期リセット(アクティブH) | posedge R をイベント式に追加 | 1でリセット |
| 非同期リセット(アクティブL) | negedge RB をイベント式に追加 | 0でリセット |
FF記述の基本テンプレート
// ① 非同期リセット付きFF(アクティブLow リセット)
always @( posedge CK or negedge RB )
begin
if ( RB == 1'b0 ) // リセット条件を最初に記述
Q <= 1'b0;
else // リセット条件以外の動作をelse項に記述
Q <= D;
end
// ② 同期リセット付きFF
always @( posedge CK )
begin
if ( RB == 1'b0 )
Q <= 1'b0;
else
Q <= D;
end
// ③ リセットなしFF
always @( posedge CK )
begin
Q <= D; // beginの直後から動作記述を始める
end
- イベント式の有無でリセット種類(非同期/同期)が決まる
- リセット条件がある場合は
begin直後に最初に記述する - リセット条件以外の動作は
else項に記述する
3. TフリップフロップのHDL記述
TフリップフロップはクロックCKが入力するたびに出力Qが反転する回路で、「トグルフリップフロップ」とも呼ばれます。
T-FFの真理値表
| RB | CK | Q (次の状態) |
|---|---|---|
| 0 | x(任意) | 0(非同期リセット) |
| 1 | ↑(立ち上がり) | ~Q(前の状態を反転) |
module TFF ( CK, Q, RB );
input CK, RB;
output Q;
reg Q;
always @( posedge CK or negedge RB )
begin
if ( RB == 1'b0 )
Q <= 1'b0; // 非同期リセット: RBが0でQを0に
else
Q <= ~Q; // CKの立ち上がりで出力を反転
end
endmodule
- この回路は非同期リセット付きなので、
negedge RBをイベント式に記述 - RBが0のとき → Qに0を代入(リセット)
- RBが1かつCKの立ち上がりのとき →
~Q(Qの反転値)を代入 - 真理値表の「次の状態 = ~Q」は「前の状態の反転」を意味する
4. JKフリップフロップのHDL記述
JKフリップフロップは、標準ICを使ってデジタル回路を設計していた時代に多く利用されたフリップフロップです。わずかなゲートを付加するだけで容易にカウンタその他の順序回路を作成できます。
JK-FFの真理値表
クロックCKの立ち上がりで変化する出力Qは、二つの入力JとKの値により4通りの異なる動作をします。
| RB | SB | J | K | CK | Q (次の状態) |
|---|---|---|---|---|---|
| 0 | x | x | x | x | 0(非同期リセット:RBを優先) |
| 1 | 0 | x | x | x | 1(非同期セット) |
| 1 | 1 | 0 | 0 | ↑ | Q(保持) |
| 1 | 1 | 0 | 1 | ↑ | 0(リセット) |
| 1 | 1 | 1 | 0 | ↑ | 1(セット) |
| 1 | 1 | 1 | 1 | ↑ | ~Q(トグル) |
RBが0のときSBはX(DONT CARE)→ リセット動作を優先します。
module JKFF ( CK, J, K, Q, RB, SB );
input CK, J, K, RB, SB;
output Q;
reg Q;
// イベント式: クロック + 非同期リセット + 非同期セットをorで接続
always @( posedge CK or negedge RB or negedge SB )
begin
if ( RB == 1'b0 ) // RBが0: 非同期リセット(優先)
Q <= 1'b0;
else if ( SB == 1'b0 ) // RB以外でSBが0: 非同期セット
Q <= 1'b1;
else begin
case ( {J, K} ) // JとKを連接して2ビット条件
2'b00: Q <= Q; // 保持
2'b01: Q <= 1'b0; // リセット
2'b10: Q <= 1'b1; // セット
2'b11: Q <= ~Q; // トグル
default: Q <= Q; // 不定値対策(必ず記述)
endcase
end
end
endmodule
- イベント式には クロック・非同期リセット・非同期セット の3つをorで接続
- if-else if の順番で優先順位を表現(RBリセット → SBセット → 通常動作)
{J, K}でJ・Kを連接して2ビットのcase条件にする- J・Kが不定値になる場合もあるため
defaultの記述を忘れずに
5. QB出力付きDFFの記述
反転出力(QB)を作る時、一つのalways文の中で一緒に書いちゃうと、論理合成ツールが「FFが2つ必要だ!」って勘違いしちゃうことがあるんだ🐾
「FFは1つ!反転はassignで!」って覚えておいてね!
フリップフロップには、クロック立ち上がりで入力Dの値を出力するQと、Dの値の反転を出力するQBの両方を持つものがあります。
✅ 推奨:assign文でQBを記述
module DFF_QB ( CK, D, Q, QB );
input CK, D;
output Q, QB;
reg Q;
always @( posedge CK )
begin
Q <= D; // Qはalways文で記述
end
assign QB = ~Q; // QBはassign文でQの反転を代入(推奨)
endmodule
❌ 非推奨:always文でQBも記述
module DFF_QB_NG ( CK, D, Q, QB );
input CK, D;
output Q, QB;
reg Q, QB;
always @( posedge CK )
begin
Q <= D;
QB <= ~D; // NG: 論理合成ツールはFFが2つあると解釈する
end
endmodule
✅ assign文を使った場合
- ASICライブラリにQB付きFFがある場合 → QB付きFFとして合成
- ない場合 → QにインバータをつけてQBを生成
- 回路規模が小さい
⚠️ always文でQBも記述した場合
- 論理合成ツールはフリップフロップが2つあると解釈する
- 動作上の問題は生じないが、論理合成で余分な回路が生成される可能性があるため推奨されません。
- 回路規模がassign文より大きくなる
assign QB = ~Q; を使って記述することを推奨します。
📝 C5 まとめ: フリップフロップの記述
| FF種類 | イベント式の例 | 動作の特徴 |
|---|---|---|
| T-FF(非同期リセット付き) | @(posedge CK or negedge RB) | CK立ち上がりで出力を反転(トグル) |
| JK-FF(非同期リセット・セット付き) | @(posedge CK or negedge RB or negedge SB) | J,Kの組み合わせで保持/リセット/セット/トグル |
| QB付きDFF(推奨) | @(posedge CK) + assign QB=~Q | QはFF、QBはassign文で反転 |
| 非同期リセットの判定 | イベント式にリセット信号を含む | CKに関係なくリセット動作 |
| 同期リセットの判定 | イベント式にリセット信号を含まない | CKエッジ時のみリセット動作 |
