verilog 同异步FIFO 格雷码

1、定义
FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据, 其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。
  FIFO一般用于不同时钟域之间的数据传输,比如FIFO的一端是AD数据采集, 另一端是计算机的PCI总线,假设其AD采集的速率为16位 100K SPS,那么每秒的数据量为100K×16bit=1.6Mbps,而PCI总线的速度为33MHz,总线宽度32bit,其最大传输速率为 1056Mbps,在两个不同的时钟域间就可以采用FIFO来作为数据缓冲。另外对于不同宽度的数据接口也可以用FIFO,例如单片机位8位数据输出,而 DSP可能是16位数据输入,在单片机与DSP连接时就可以使用FIFO来达到数据匹配的目的。

2、空/满检测
  FIFO设计的关键:产生可靠的FIFO读写指针和生成FIFO“空”/“满”状态标志。
  当读写指针相等时,表明FIFO为
,这种情况发生在复位操作时,或者当读指针读出FIFO中最后一个字后,追赶上了写指针: 在这里插入图片描述
  当读写指针再次相等时,表明FIFO为,这种情况发生在,当写指针转了一圈,折回来(wrapped around)又追上了读指针:
在这里插入图片描述
异步fifo空/满区分方法:
在指针中添加一个额外的位(extra bit),当读写指针增加并越过最后一个FIFO地址时,就将读写指针这个未用的MSB加1,其它位回零,MSB作为折回标志位,而低3位作为地址指针。

  • 如果两个指针的MSB不同,说明写指针比读指针多折回了一次;如r_addr=0000,而w_addr = 1000,为满。
  • 如果两个指针的MSB相同,则说明两个指针折回的次数相等。其余位相等,说明FIFO为空;

gray码判断“空”与“满”

  • 判断读空时:需要读时钟域的格雷码和被同步到读时钟域的写指针每一位完全相同;
  • 判断写满时:需要写时钟域的格雷码和被同步到写时钟域的读指针高两位不相同,其余各位完全相同;

3、同步FIFO

module fifo_syn_test(
    input clk,
    input rst_n,
    input wr_req,
    input rd_req,
    input [7:0] data_in,
    output reg [7:0] data_out,
    output reg full,
    output reg empty
    );
    
reg [7:0] mem [15:0];
reg [3:0] wr_addr,rd_addr;

always @(posedge clk)begin
    if(wr_req && !full)
        mem[wr_addr] <= data_in;
end   

always @(posedge clk)begin
    if(~rst_n)
        data_out <= 8'd0;
    if(rd_req && !empty)
        data_out <= mem[rd_addr];
end 

always @(posedge clk)begin
    if(~rst_n)
        wr_addr <= 4'd0;
    else if(wr_req && !full)
        wr_addr <= wr_addr + 4'd1;
end

always @(posedge clk)begin
    if(~rst_n)
        rd_addr <= 4'd0;
    else if(rd_req && !empty)
        rd_addr <= rd_addr + 4'd1;
end

always @(posedge clk)begin
    if(~rst_n)
        full <= 1'd0;
    else if(wr_req && rd_addr == wr_addr + 1)
        full <= 1'd1;
    else
        full <= 1'd0;
end

always @(posedge clk)begin
    if(~rst_n)
        empty <= 1'd0;
    else if(rd_req && wr_addr == rd_addr + 1)
        empty <= 1'd1;
    else
        empty <= 1'd0;
end
endmodule

4、异步FIFO

module fifo_asyn_test(
    input wclk,
	input rclk,
	input rst_n,
	input [7:0] data_in,
	input wr_req,
	input rd_req,
	output reg [7:0] data_out,
	output fifo_empty,
	output fifo_full
);

reg [7:0] ram [15:0];
reg [4:0] wr_addr;
wire [4:0] wr_addr_g;
reg [4:0]  wr_addr_g_r, wr_addr_g_rr;
reg [4:0] rd_addr;
wire [4:0] rd_addr_g;
reg [4:0] rd_addr_g_r, rd_addr_g_rr;
 
always @(posedge wclk or negedge rst_n)begin
    if(wr_req && !fifo_full)begin
		ram[wr_addr] <= data_in;
    end    
end

always @(posedge wclk or negedge rst_n)begin
    if(~rst_n)begin
		wr_addr <= 5'd0;
    end
    else if(wr_req && !fifo_full)
		wr_addr <= wr_addr + 5'd1;    
end

assign wr_addr_g = wr_addr^(wr_addr>>1);
always @(posedge rclk or negedge rst_n)begin
    if(~rst_n)begin
		wr_addr_g_r <= 5'd0;
		wr_addr_g_rr <= 5'd0;
    end
    else begin
        wr_addr_g_r <= wr_addr_g;
		wr_addr_g_rr <= wr_addr_g_r;
    end  
end


always @(posedge rclk or negedge rst_n)begin
    if(~rst_n)begin
		rd_addr <= 5'd0;
    end
    else if(rd_req && !fifo_empty)
		rd_addr <= rd_addr + 5'd1;
end

assign rd_addr_g = rd_addr^(rd_addr>>1);
always @(posedge wclk or negedge rst_n)begin
    if(~rst_n)begin
		rd_addr_g_r <= 5'd0;
		rd_addr_g_rr <= 5'd0;
    end
    else begin
        rd_addr_g_r <= rd_addr_g;
		rd_addr_g_rr <= rd_addr_g_r;
    end  
end

always @(posedge rclk or negedge rst_n)begin
    if(~rst_n)begin
		data_out <= 8'd0;
    end
    else if(rd_req && !fifo_empty)
		data_out <= ram[rd_addr];
	else 
		data_out <= data_out;
end

assign fifo_empty = (rd_addr_g == wr_addr_g_rr);
assign fifo_full = (wr_addr_g  == {~rd_addr_g_rr[4:3],rd_addr_g_rr[2:0]});
endmodule

仿真

module tb(

    );

reg wclk;
reg rclk;
reg rst_n;
reg [7:0] data_in;
reg wr_req;
reg rd_req;
wire [7:0] data_out;
wire fifo_empty;
wire fifo_full;

initial begin
    rst_n = 0;
    wclk = 0;
    rclk = 0;
    wr_req = 0;
    rd_req = 0;
    #20;
    rst_n = 1;
    wr_req = 1;
    #360;
    rd_req = 1; 
    #80;
    wr_req = 0; 
end

always @(posedge wclk or negedge rst_n)begin
    if(~rst_n)begin
		data_in <= 8'd1;
    end
    else 
		data_in <= data_in + 1 ;    
end

initial begin
    forever 
        #10 wclk = ~wclk;
end
initial begin
    forever 
        #20 rclk = ~rclk;
end

fifo_syn fifo_syn(
	.wclk       (wclk       ),
	.rclk       (rclk       ),
	.rst_n     (rst_n     ),
	.data_in   (data_in   ),
	.wr_req    (wr_req    ),
	.rd_req    (rd_req    ),
	.data_out  (data_out  ) ,
	.fifo_empty(fifo_empty) ,
	.fifo_full (fifo_full )
);
endmodule

在这里插入图片描述

5、自然二进制码转格雷码
在这里插入图片描述

gray=(binary>>1)^binary;

6、格雷码转自然二进制码
在这里插入图片描述

integer i;    
always @(data_gray) begin 
    data_bin[n-1] = data_gray[n-1];
    for(i=n-1; i>0; i=i-1)
        data_bin[i-1] = data_gray[i-1]^data_bin[i];
end

补充

1、判断是否写满时,需要将读指针转换成格雷码形式,再同步到写时钟域,与写指针比较,判断是否写满!
当读指针转换成格雷码以及同步到写时钟域的过程中,读写指针可能还都在递增,这样的话,等同步后的读指针与写指针相等时(不包括最高位),实际的读指针可能已经变了,这样的话其实还有几个空间没有写满!这叫保守设计,可以增加FIFO的安全性。
2、当判断是否读空时,需要把写指针同步到读时钟域,具体过程是先将写指针转换为格雷码,再同步到读时钟域,之后和读指针比较,如果二者相等,则空标志置位!
当写指针转换成格雷码以及同步到读时钟域的过程中,写指针和读指针都可能还在递增,这样当二者判断相等的时候,则写指针可能还多写了几个空间,实际上并没有读空。这样也保证了FIFO的安全,防止被读空。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
异步FIFO是一种用于在两个异步时钟域之间传输数据的解决方案。在Verilog中实现异步FIFO可以采用以下步骤: 1. 定义FIFO的输入和输出接口:包括读写时钟、读写使能信号、读写数据和读写指针等。 2. 使用两个时钟域的寄存器同步输入信号:由于读写时钟不同,需要使用两级寄存器级联来同步输入信号,以消除亚稳态。 3. 实现FIFO的读写逻辑:根据读写使能信号和读写指针,确定读写操作的时机和数据。 4. 实现FIFO的存储器:可以使用RAM或者其他存储结构来存储数据。 5. 实现FIFO的读写指针逻辑:根据读写操作的完成情况,更新读写指针的值。 6. 添加互斥逻辑:为了避免读写冲突,可以使用互斥逻辑来控制读写操作的互斥性。 需要注意的是,在实现异步FIFO时,需要考虑跨时钟域的问题。可以使用两级寄存器同步和格雷码等方法来解决跨时钟域的问题,确保读写指针的比较正确。 总之,通过定义接口、同步输入信号、实现读写逻辑和存储器、更新读写指针以及添加互斥逻辑等步骤,可以在Verilog中实现异步FIFO。 #### 引用[.reference_title] - *1* *3* [异步FIFO---Verilog实现](https://blog.csdn.net/alangaixiaoxiao/article/details/81432144)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [基于Verilog实现的异步FIFO](https://blog.csdn.net/ZHOUJIAN1997/article/details/121597269)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值