异步FIFO的实现

[复制链接]
 楼主| 星星之火红 发表于 2012-11-6 22:40 | 显示全部楼层 |阅读模式
以下是一个异步FIFO的实现代码,实现的是一个FWFT的异步FIFO功能,与Xilinx CORE Generator生成FIFO功能、时序一模一样。其中 ,simple_dual_port_ram 是一个Xilinx的简单双端口RAM,可以很简单的移植到其他厂商的FPGA中。在产生空满信号的判断时,需要将读操作侧的地址传递到写操作侧,将写操作地址传递读操作侧,为了减少读写地址的位翻转率,从而减少亚稳态的发生,在将地址跨越时钟域之前首先转换成格雷码,跨越时钟域并正常采样以后再恢复成二进制的地址。由于模块中多次使用到将格雷码转换成二进制码以及将二进制码转换成格雷码,所以将格雷码与二进制码的转换使用了两个函数(function)来实现,方便在代码中不同处调用。跨越时钟域时,为了隔断亚稳态的传递,首先要用两级寄存器对另一时钟域产生的地址打两拍,这样子即使有亚稳态发生,也能被阻隔在两级寄存器中。尽管打两拍能阻断亚稳态的传递,但是不能避免跨时钟域时采样错误的发生,使用格雷码的作用是使得错误仅发生在其中一个位上。
       代码中RAM输入和输出都没有使用到寄存器,读者可以根据自己的需要定制满足自己要求的FIFO,在写操作侧或读操作侧加寄存器。代码中数据的位宽和地址的位宽,亦可以根据读者的需要修改。尽管本文提供了异步FIFO的完整实现代码,博主还是建议各位读者在使用FIFO时尽量多用CORE Generator生成的FIFO,那样会更加可靠稳定,使用起来也更方便。
 楼主| 星星之火红 发表于 2012-11-6 22:40 | 显示全部楼层
  1. // ****************************************************************************************************************
  2. // Copyright(c) 2012,  Technology Endless - Creative Boundless , All right reserved
  3. // Filename        :    asynfifo.v
  4. // Author            :    lucien
  5. // Email             :    intellectuallib@126.com
  6. // Date              :    Apr 22th, 2012
  7. // Version          :    1.0
  8. // Company       :   
  9. // Description     :    asynchronous FIFO(first in first out)
  10. // Modification History
  11. // Date            By            Revision        Change Description
  12. // ---------------------------------------------------------------------------------------
  13. // 2012/04/22      Lucien        1.0             Original
  14. // ****************************************************************************************************************

  15. `timescale 1ns/1ps

  16. module asynfifo(
  17.           rst                 ,
  18.           wr_clk           ,
  19.           wr_en            ,
  20.           din                ,
  21.           full                ,

  22.           rd_clk           ,
  23.           rd_en            ,
  24.           dout             ,
  25.           empty
  26.          );

  27. input   wire            rst      ;//reset signal
  28. input   wire            wr_clk ;//clock of read clock field
  29. input   wire            wr_en  ;//write enable
  30. input   wire [7:0]     din      ;
  31. output  wire            full     ;

  32. input   wire            rd_clk  ;//clock of write clock field
  33. input   wire            rd_en   ;
  34. output  wire [7:0]   dout     ;
  35. output  wire           empty  ;

  36. /**************************************************************************************************************/
  37. /**************************************************************************************************************\
  38. *        define internal signals                                                                                                  *
  39. \**************************************************************************************************************/

  40. reg     [7:0]   waddr;                     //write address in write clock field
  41. reg     [7:0]   raddr;                      //read  address in read  clock field
  42. wire    [7:0]   waddr_gray_wclk;    //the gray code of write address in write clock field
  43. wire    [7:0]   raddr_gray_rclk;       //the gray code of read address in read clock field
  44. reg     [7:0]   waddr_gray_rclk_0;  //the dealyed gray codes of write address in read clock field
  45. reg     [7:0]   waddr_gray_rclk_1;
  46. reg     [7:0]   raddr_gray_wclk_0;  //the dealyed gray codes of read address in write clock field
  47. reg     [7:0]   raddr_gray_wclk_1;
  48. wire    [7:0]   waddr_rclk;             //write address in read clock field
  49. wire    [7:0]   raddr_wclk;             //read address in write clock field
  50. reg     [8:0]   count_wclk;            //the data counter in write clock field
  51. reg     [8:0]   count_rclk;             //the data counter in read clock field

  52. function [7:0] binary_to_gray;
  53. input   [7:0]   binary_code ;
  54. begin
  55.       binary_to_gray[0]=binary_code[0]^binary_code[1];
  56.       binary_to_gray[1]=binary_code[1]^binary_code[2];
  57.       binary_to_gray[2]=binary_code[2]^binary_code[3];
  58.       binary_to_gray[3]=binary_code[3]^binary_code[4];
  59.       binary_to_gray[4]=binary_code[4]^binary_code[5];
  60.       binary_to_gray[5]=binary_code[5]^binary_code[6];
  61.       binary_to_gray[6]=binary_code[6]^binary_code[7];
  62.       binary_to_gray[7]=binary_code[7];
  63. end
  64. endfunction

  65. function [7:0] gray_to_binary;
  66. input   [7:0]   gray_code ;
  67. begin
  68.       gray_to_binary[7]=waddr_gray_rclk_1[7];
  69.       gray_to_binary[6]=waddr_gray_rclk_1[6]^gray_to_binary[7];
  70.       gray_to_binary[5]=waddr_gray_rclk_1[5]^gray_to_binary[6];
  71.       gray_to_binary[4]=waddr_gray_rclk_1[4]^gray_to_binary[5];
  72.       gray_to_binary[3]=waddr_gray_rclk_1[3]^gray_to_binary[4];
  73.       gray_to_binary[2]=waddr_gray_rclk_1[2]^gray_to_binary[3];
  74.       gray_to_binary[1]=waddr_gray_rclk_1[1]^gray_to_binary[2];  
  75.       gray_to_binary[0]=waddr_gray_rclk_1[0]^gray_to_binary[1];   
  76. end
  77. endfunction

  78. simple_dual_port_ram U_simple_dual_port_ram(
  79.             .clka     (wr_clk            ),
  80.             .wea      (wr_en            ),
  81.             .addra    (waddr            ),
  82.             .dina      (din                ),
  83.             .clkb      (rd_clk            ),
  84.             .addrb    (raddr             ),
  85.             .doutb    (dout              )
  86.             );

  87. assign empty = (count_rclk[8:0] == 9'h0);
  88. assign full  = (count_rclk[8:0] == 9'h100);

  89. assign waddr_gray_wclk = binary_to_gray(waddr);
  90. assign raddr_gray_rclk = binary_to_gray(raddr);
  91. assign waddr_rclk = gray_to_binary(waddr_gray_rclk_1);
  92. assign raddr_wclk = gray_to_binary(raddr_gray_wclk_1);

  93. always@(posedge wr_clk or posedge rst)
  94. begin
  95.       if(rst == 1'b1)
  96.            waddr <= 8'h0;
  97.      else
  98.            if(wr_en==1'b1)
  99.                 waddr <= waddr + 8'h1;
  100.            else
  101.                 waddr <= waddr;
  102. end

  103. always@(posedge rd_clk or posedge rst)
  104. begin
  105.       if(rst == 1'b1)
  106.           raddr <= 8'h0;
  107.     else
  108.           if(wr_en==1'b1)
  109.                 raddr <= raddr + 8'h1;
  110.           else
  111.                 raddr <= raddr;
  112. end

  113. always@(posedge wr_clk or posedge rst)
  114. begin
  115.       if(rst == 1'b1)
  116.           begin  
  117.                 raddr_gray_wclk_0<=8'b0;
  118.                 raddr_gray_wclk_1<=8'b0;
  119.           end
  120.     else
  121.          begin
  122.                raddr_gray_wclk_0<=raddr_gray_rclk;
  123.                raddr_gray_wclk_1<=raddr_gray_wclk_0;
  124.         end
  125. end

  126. always@(posedge rd_clk or posedge rst)
  127. begin
  128.       if(rst == 1'b1)
  129.            begin
  130.                  waddr_gray_rclk_0<=8'b0;
  131.                  waddr_gray_rclk_1<=8'b0;
  132.            end
  133.     else
  134.            begin
  135.                  waddr_gray_rclk_0<=waddr_gray_wclk;
  136.                  waddr_gray_rclk_1<=waddr_gray_rclk_0;
  137.            end
  138. end

  139. always@(posedge wr_clk or posedge rst)
  140. begin
  141.       if(rst == 1'b1)
  142.             count_wclk <= 9'h0;
  143.       else
  144.             if(waddr < raddr_wclk)
  145.                   count_wclk <= waddr + 9'h100 - raddr_wclk;
  146.             else if((count_wclk > 9'h0) && (waddr == raddr_wclk))
  147.                   count_wclk <= 9'h100;
  148.             else
  149.                   count_wclk <= waddr - raddr_wclk;
  150. end

  151. always@(posedge rd_clk or posedge rst)
  152. begin
  153.        if(rst == 1'b1)
  154.             count_rclk <= 9'h0;
  155.        else
  156.             if(waddr_rclk < raddr)
  157.                   count_rclk <= waddr_rclk + 9'h100 - raddr;
  158.             else if((count_rclk > 9'h0) && (waddr_rclk == raddr))
  159.                   count_rclk <= 9'h100;
  160.             else
  161.                   count_rclk <= waddr_rclk - raddr;
  162. end

  163. endmodule

GoldSunMonkey 发表于 2012-11-6 23:06 | 显示全部楼层
直接例化IP不好么?
drentsi 发表于 2012-11-7 12:52 | 显示全部楼层
直接例化IP不好么?
GoldSunMonkey 发表于 2012-11-6 23:06

我已经抛弃xilinx的异步fifo了,
使用BLOCK FIFO要占用BRAM,划不来,多数情况下不需要那么大的深度。
使用cg生成的fifo,不够灵活,而且占的资源也多,速度也慢。

这个fifo控制器,关于full和empty的赋值需要改进,会严重影响速度的。
wmsk 发表于 2012-11-8 00:21 | 显示全部楼层
我已经抛弃xilinx的异步fifo了,
使用BLOCK FIFO要占用BRAM,划不来,多数情况下不需要那么大的深度。
使用cg生成的fifo,不够灵活,而且占的资源也多,速度也慢。

这个fifo控制器,关于full和empty的赋值需要改进 ...
drentsi 发表于 2012-11-7 12:52
厉害
GoldSunMonkey 发表于 2012-11-8 00:31 | 显示全部楼层
我已经抛弃xilinx的异步fifo了,
使用BLOCK FIFO要占用BRAM,划不来,多数情况下不需要那么大的深度。
使用cg生成的fifo,不够灵活,而且占的资源也多,速度也慢。

这个fifo控制器,关于full和empty的赋值需要改进 ...
drentsi 发表于 2012-11-7 12:52
小FIFO肯定不值得一用
您需要登录后才可以回帖 登录 | 注册

本版积分规则

101

主题

1782

帖子

22

粉丝
快速回复 在线客服 返回列表 返回顶部

101

主题

1782

帖子

22

粉丝
快速回复 在线客服 返回列表 返回顶部