1. 程式人生 > >Verilog——格雷碼計數器

Verilog——格雷碼計數器

- 格雷碼(Gray code):
第一次接觸格雷碼是在本科的數電課本上,其在可靠性編碼佔據重要位置。後來所學的卡諾圖與格雷碼關係密切。
格雷碼特點在於相鄰性和單位距離性。在程式碼傳輸過程中,彼此相鄰位置僅有一位數碼不同,故有著較好的可靠性。
4位格雷碼:

十進位制 二進位制 格雷碼
0 0000 0000
1 0001 0001
2 0010 0011
3 0011 0010
4 0100 0110
5 0101 0111
6 0110 0101
7 0111 0100
8 1000 1100
9 1001 1101
10 1010 1111
11 1011 1110
12 1100 1010
13 1101 1011
14 1110 1001
15 1111 1000

- Verilog的實現:
格雷碼計數器的Verilog實現,即用格雷碼計數的方式,完成資料的累加。
實現方式有多種,參考J.Bhasker的書,此處貼上第一種。
程式碼的基本流程為:首先將初始化的格雷碼轉變為二級制碼,二進位制完成累加,最後再講二級制碼轉化為格雷碼。

  1. 格雷碼轉二進位制碼的基本思路:
    最高位不變,次高位往下依次完成自異或運算,得到對應二進位制碼的各位資料,運算次數為位寬-1
  2. 二進位制碼轉格雷碼的基本思路:
    最高位不變,最低位依次往前完成自異或運算,得到對應二進位制碼的各位資料,運算次數為位寬-1
  3. 注:這樣的自異或運算與其他人給出的格雷碼+二進位制共同運算的方式不同,前一種可能存在侷限性,待發現後說明

非同步復位的N位格雷碼計數器

`timescale 1ns/1ns
module gray_counter1(ck,preclear,q);

parameter NBITS = 4;    //決定格雷碼計數的頻寬
input ck,preclear;
output [0:NBITS-1] q;

reg [0:NBITS-1] q;
reg [0:NBITS-1] gray_cnt;
integer k;

always @(posedge ck or negedge preclear)
begin
    if(!preclear)   //非同步清零訊號,訊號為低時,計數清零
        q <= 0;
    else 
    begin
        gray_cnt = q;
        //將資料存在在臨時變數中

    for(k=1;k<NBITS;k=k+1)
        if(gray_cnt[k-1])
            gray_cnt[k] = !gray_cnt[k];//高位為高,低位取反,本質上是異或操作
        //完成格雷碼到二進位制的轉換,二進位制計數

    gray_cnt = gray_cnt + 1;

    for(k=NBITS-1;k>0;k=k-1)
        if(gray_cnt[k-1])
            gray_cnt[k] = !gray_cnt[k];
        //二進位制轉回格雷碼

    q <= gray_cnt;
    end
end
endmodule       

module gray_counter1_tb;    //測試檔案
parameter NBITS = 4;

reg ck,preclear;
wire [0:NBITS-1] q;

gray_counter1 U1(ck,preclear,q);

always #50 ck = !ck;    //計數時鐘,週期100ns

initial 
begin
    ck = 0;
    preclear = 1;
    #70 preclear = 0;
    #70 preclear = 1;
end

endmodule