グレイコードカウンタ

[] [] []


多ビットの信号を非同期クロック間転送するとき、変化がランダムではなく順番が決まっているカウンタ値であれば、MUXシンクロナイザを使わなくても、もっと簡単な方法がある。

通常のバイナリカウンタはカウントアップするとき複数のビットが変化するので、そのままダブルFFシンクロナイザでサンプリングすると過渡値を取る可能性があるが、1ビットづつしか変化しないように順番を並び変えたグレイコードカウンタを使えば、そのままダブルFFシンクロナイザでサンプリングできる

バイナリ

グレイ

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

0000

0001

0010

0011

0100

0101

0110

0111

1000

1001

1010

1011

1100

1101

1110

1111

0000

0001

0011

0010

0110

0111

0101

0100

1100

1101

1111

1110

1010

1011

1001

1000

ただしグレイコードカウンタをカウントアップする単純なアルゴリズムはないので、ビット幅が小さければRTL記述でコードを書き下せばよいが、一般にはバイナリコードでカウントアップしてからグレイコードに変換することになる。

バイナリコードからグレイコードへの変換回路の遅延時間はビット幅に依らない。

/* binary to gray */

wire[N-1:0] bin,gray;

assign gray = bin ^ (bin >> 1'b1);

一方、グレイコードからバイナリコードへの変換回路の遅延時間はビット幅に比例して大きくなるので、なるべく使わずに済ませた方がよい。

/* gray to binary */

wire[N-1:0] bin,gray;

genvar i;

generate for(i=0; i<N; i=i+1) begin: gray2bin

  assign bin[i] = ^gray[N-1:i];

end endgenerate

このグレイコードカウンタを使った例はあまり知らないのだが、非同期FIFOを作るときは有効である。(非同期FIFOの作り方)

なお、1ビットづつしか変化しないカウンタとしては回路が単純なジョンソンカウンタもある。ただし、これはNビットで2Nまでしかカウントできないので、大きいカウント数が必要な場合は不利である。

ジョンソン

0

1

2

3

4

5

6

7

0000

0001

0011

0111

1111

1110

1100

1000

 

/* Johnson counter */

reg[N-1:0] count_reg;

always @(posedge clk or posedge rst)

    begin

    if(rst)

        count_reg <= {N{1'b0}};

    else if(en)

        count_reg <= {count_reg[N-2:0],~count_reg[N-1]};

    end


[] [] []