Verilogグレイカウンタ:4ビットグレイコード生成モジュール
グレイコードとは
グレイコード(反射2進コード)は、隣り合うコード語のビット差が常に1ビットのみとなる符号化方式です。通常のバイナリカウントでは複数ビットが同時に変化する(例:0111→1000で4ビット変化)ため、非同期クロックドメイン間での値受け渡しや、機械的エンコーダ、カーネルマップ簡略化などでグレイコードが用いられます。
バイナリ→グレイ変換の公式
nビットバイナリ値B[n-1:0]からグレイコードG[n-1:0]への変換:
G[n-1] = B[n-1] G[i] = B[i+1] ^ B[i] (i = n-2 ... 0)
Verilogでは連結演算子で簡潔に記述できます:{B[N-1], B[N-1:1] ^ B[N-2:0]}
設計
内部にバイナリカウンタqを持ち、毎クロックインクリメントしつつグレイ変換した値をoutに出力します。`ifdef FOR_LOOPでforループ版とベクトル演算版を切替可能にしています。
module gray_ctr #(
parameter N = 4
)(
input clk,
input rstn,
output reg [N-1:0] out
);
reg [N-1:0] q; // 内部バイナリカウンタ
always @(posedge clk) begin
if (!rstn) begin
q <= 0;
out <= 0;
end else begin
q <= q + 1; // バイナリカウント
// グレイ変換:ベクトル演算版(推奨:シンプルで高速)
`ifdef FOR_LOOP
for (int i = 0; i < N-1; i = i + 1)
out[i] <= q[i+1] ^ q[i];
out[N-1] <= q[N-1];
`else
out <= {q[N-1], q[N-1:1] ^ q[N-2:0]};
`endif
end
end
endmodule
テストベンチ
module tb;
parameter N = 4;
reg clk;
reg rstn;
wire [N-1:0] out;
gray_ctr u0 (
.clk(clk),
.rstn(rstn),
.out(out)
);
always #10 clk = ~clk; // 20ns周期
initial begin
{clk, rstn} <= 0;
$monitor("T=%0t rstn=%0b out=0x%0h", $time, rstn, out);
repeat(2) @(posedge clk);
rstn <= 1;
repeat(20) @(posedge clk);
$finish;
end
endmodule
シミュレーション結果(4ビットグレイコード列)
ncsim> run T=0 rstn=0 out=0xx T=10 rstn=0 out=0x0 T=30 rstn=1 out=0x0 // 0000 T=50 rstn=1 out=0x1 // 0001 T=70 rstn=1 out=0x3 // 0011 (1ビット変化: 0001→0011) T=90 rstn=1 out=0x2 // 0010 (1ビット変化: 0011→0010) T=110 rstn=1 out=0x6 // 0110 T=130 rstn=1 out=0x7 // 0111 T=150 rstn=1 out=0x5 // 0101 T=170 rstn=1 out=0x4 // 0100 T=190 rstn=1 out=0xc // 1100 T=210 rstn=1 out=0xd // 1101 T=230 rstn=1 out=0xf // 1111 T=250 rstn=1 out=0xe // 1110 T=270 rstn=1 out=0xa // 1010 T=290 rstn=1 out=0xb // 1011 T=310 rstn=1 out=0x9 // 1001 T=330 rstn=1 out=0x8 // 1000 T=350 rstn=1 out=0x0 // 16ステートで巡回完了 ... Simulation complete via $finish(1) at time 430 NS + 0
グレイコード列の確認(4ビット)
| 10進 | バイナリ | グレイ | 変化ビット |
|---|---|---|---|
| 0 | 0000 | 0000 | - |
| 1 | 0001 | 0001 | bit0 |
| 2 | 0010 | 0011 | bit1 |
| 3 | 0011 | 0010 | bit0 |
| 4 | 0100 | 0110 | bit2 |
| 5 | 0101 | 0111 | bit0 |
| 6 | 0110 | 0101 | bit1 |
| 7 | 0111 | 0100 | bit0 |
| 8 | 1000 | 1100 | bit3 |
| 9 | 1001 | 1101 | bit0 |
| 10 | 1010 | 1111 | bit1 |
| 11 | 1011 | 1110 | bit0 |
| 12 | 1100 | 1010 | bit2 |
| 13 | 1101 | 1011 | bit0 |
| 14 | 1110 | 1001 | bit1 |
| 15 | 1111 | 1000 | bit0 |
グレイカウンタの用途
- クロックドメイン跨ぎ(CDC):ポインタ値をグレイコードで渡すと、メタステーブリティ時でも1ビット誤差のみに限定可能
- FIFOポインタ:読み/書きポインタをグレイコードで管理
- ロータリエンコーダ:機械的接点のチャタリング対策
- カーネルマップ:論理式簡略化の隣接条件を満たす
グレイ→バイナリ逆変換
受信側でグレイコードからバイナリに戻す場合:
function [N-1:0] gray2bin(input [N-1:0] g);
integer i;
begin
gray2bin[N-1] = g[N-1];
for (i = N-2; i >= 0; i = i - 1)
gray2bin[i] = gray2bin[i+1] ^ g[i];
end
endfunction
Verilog
- Verilogマスター:デジタル回路設計のための完全チュートリアル
- Verilog連結マスター:実践ガイド
- Verilog代入文の理解:種類、構文、ベストプラクティス
- Verilogブロッキング代入とノンブロッキング代入:違いを徹底解説
- Verilog関数のマスター:効率的なRTL設計のために
- Verilogタスクの理解:関数との違い、構文、使用法
- Verilogクロックジェネレータ:設計と実装ガイド
- Verilog数学関数のマスター:効率的なハードウェア設計のために
- Verilog $timeformatのマスター:精度と表示制御
- Verilog Tフリップフロップ:RTL実装とテストベンチ完全解説
- Verilog Mod-Nカウンタ:パラメータ化モジュールとテストベンチ