牛客网verilog刷题_VL47 格雷码计数器

格雷码(gray code)的使用

在产生FIFO满信号时,要将写指针和读指针进行比较,由于两个指针分别在各自的时钟域,彼此之间是异步的,在使用二进制进行计数器实现指针时,就会导致用于比较的指针取样错误。

使用自然二进制码计数时,相邻数据之间可能会产生多bit的变化。这会产生较大的尖峰电流以及其他问题。

比如,二进制计数器的值会从FFF变为000。这时所有位会同时改变。虽然能通过同步计数器避免亚稳态,但是仍然能得到极不相关的取样值,所以同步计数器不是最终的解决方案。

从FFF 到000可能的转换:

  • FFF→000
  • FFF→001
  • FFF→010
  • FFF→011
  • FFF→100
  • FFF→101
  • FFF→110
  • FFF→111

如果同步时钟边沿在FFF向000转换的中间位置到来,就可能将三位二进制数的任何值取样并同步到新的时钟域中。鉴于以上情况,强烈建议避免使用二进制计数器实现读、写指针

格雷码是一种相邻数据只有1bit变化的码制。因此可以使用格雷码去取代二进制计数器,并且用打拍的方式去同步(跨时钟域问题(二)(单bit信号跨时钟域 1. 电平同步器 2. 边沿同步器 3. 脉冲检测器))(只有深度为2的n次方才能用格雷码的方式去同步,这样才能保证最大值和最小值只有一位的变化)。我们可以将指针转为格雷码同步到另一个时钟域再进行比较。如果同步时钟在计数值转换期间到来,这种编码能够消除绝大部分的错误。
牛客网verilog刷题_VL47 格雷码计数器_第1张图片

图2 格雷码编码计数器

格雷码编码的verilog的实现

自然二进制编码转换为格雷码如下:
牛客网verilog刷题_VL47 格雷码计数器_第2张图片

图3 二进制转化为格雷码

g r a y _ c o d e = b i n a r y _ c o d e ⊕ ( b i n a r y _ c o d e > > 1 ) gray\_code = binary\_code \oplus (binary\_code > > 1) gray_code=binary_code(binary_code>>1)

格雷码转化为自然二进制
牛客网verilog刷题_VL47 格雷码计数器_第3张图片

图4 格雷码转化为自然二进制

在这里插入图片描述
我们以牛客网VL47 格雷码计数器为例!

牛客网verilog刷题_VL47 格雷码计数器_第4张图片
代码

`timescale 1ns/1ns

module gray_counter(
    input                               clk                        ,
    input                               rst_n                      ,

    output reg         [   3:0]         gray_out                    
);

reg                    [   3:0]         binary_cnt                 ;
reg                                     flag                       ;


always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        flag <= 1'd0;
    end
    else begin
        flag <= ~flag;
    end
end
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        binary_cnt <= 1'd0;
    end else begin
        if (flag == 1'd1) begin
            binary_cnt <= binary_cnt + 1'd1;
        end else begin
            binary_cnt <= binary_cnt;
        end
    end
end

always @(*) begin
    gray_out <= binary_cnt ^ (binary_cnt >> 1);
end

endmodule

你可能感兴趣的:(#,Verilog学习,FPGA,fpga开发)