ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【FPGA学习笔记】VL45 异步FIFO

2022-07-15 20:03:33  阅读:165  来源: 互联网

标签:begin waddr end ADDR FPGA VL45 FIFO WIDTH input


请根据题目中给出的双口RAM代码和接口描述,实现异步FIFO,要求FIFO位宽和深度参数化可配置。

 

电路的接口如下图所示。

 

 

双口RAM端口说明:

端口名

I/O

描述

wclk

input

写数据时钟

wenc

input

写使能

waddr

input

写地址

wdata

input

输入数据

rclk

input

读数据时钟

renc

input

读使能

raddr

input

读地址

rdata

output

输出数据

同步FIFO端口说明:

端口名

I/O

描述

wclk

input

写时钟

rclk

input

读时钟

wrstn

input

写时钟域异步复位

rrstn

input

读时钟域异步复位

winc

input

写使能

rinc

input

读使能

wdata

input

写数据

wfull

output

写满信号

rempty

output

读空信号

rdata

output

读数据

 

双口RAM代码如下,可在本题答案中添加并例化此代码。
module dual_port_RAM #(parameter DEPTH = 16,
   parameter WIDTH = 8)(
 input wclk
,input wenc
,input [$clog2(DEPTH)-1:0] waddr  //深度对2取对数,得到地址的位宽。
,input [WIDTH-1:0] wdata      //数据写入
,input rclk
,input renc
,input [$clog2(DEPTH)-1:0] raddr  //深度对2取对数,得到地址的位宽。
,output reg [WIDTH-1:0] rdata //数据输出
);

reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];

always @(posedge wclk) begin
if(wenc)
RAM_MEM[waddr] <= wdata;
end 

always @(posedge rclk) begin
if(renc)
rdata <= RAM_MEM[raddr];
end 

endmodule  
 

 

输入描述:

    input                     wclk    , 
    input                     rclk    ,   
    input                     wrstn    ,
    input                    rrstn    ,
    input                     winc    ,
    input                      rinc    ,
    input         [WIDTH-1:0]    wdata    

输出描述:

    output wire                wfull    ,
    output wire                rempty    ,
    output wire [WIDTH-1:0]    rdata          

题意整理

本题要求实现异步FIFO,FIFO的位宽和深度可配置。

题解主体

 

 

 

 

 

异步FIFO结构如上图所示

1. 第1部分是双口RAM,用于数据的存储。

2. 第2部分是数据写入控制器

3. 第3部分是数据读取控制器

4. 读指针同步器

   使用写时钟的两级触发器采集读指针,输出到数据写入控制器。

5. 写指针同步器

   使用读时钟的两级触发器采集写指针,输出到数据读取控制器。

本题解采用的空满判断的方式是用格雷码的比较来产生空满信号。使用4位格雷码作为深度为8的FIFO的读写指针。

将格雷码转换成四位二进制数,使用二进制数低三位作为访问RAM的地址。

与同步FIFO类似,当读写指针相等时,得出FIFO为空。 当写指针比读指针多循环RAM一周时,此时读写指针的最高位和次高位都相反,其余位相同,FIFO为满。  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 `timescale 1ns/1ns   /***************************************RAM*****************************************/ module dual_port_RAM #(parameter DEPTH = 16,                        parameter WIDTH = 8)(      input wclk     ,input wenc     ,input [$clog2(DEPTH)-1:0] waddr  //深度对2取对数,得到地址的位宽。     ,input [WIDTH-1:0] wdata        //数据写入     ,input rclk     ,input renc     ,input [$clog2(DEPTH)-1:0] raddr  //深度对2取对数,得到地址的位宽。     ,output reg [WIDTH-1:0] rdata       //数据输出 );   reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];   always @(posedge wclk) begin     if(wenc)         RAM_MEM[waddr] <= wdata; end    always @(posedge rclk) begin     if(renc)         rdata <= RAM_MEM[raddr]; end    endmodule     /***************************************AFIFO*****************************************/ module asyn_fifo#(     parameter   WIDTH = 8,     parameter  DEPTH = 16 )(     input                  wclk    ,      input                  rclk    ,        input                  wrstn   ,     input                   rrstn   ,     input                  winc    ,     input                 rinc    ,     input      [WIDTH-1:0] wdata   ,       output wire                wfull   ,     output wire                rempty  ,     output wire [WIDTH-1:0]   rdata );   parameter ADDR_WIDTH = $clog2(DEPTH);   /**********************addr bin gen*************************/ reg    [ADDR_WIDTH:0]  waddr_bin; reg    [ADDR_WIDTH:0]  raddr_bin;   always @(posedge wclk or negedge wrstn) begin     if(~wrstn) begin         waddr_bin <= 'd0;     end      else if(!wfull && winc)begin         waddr_bin <= waddr_bin + 1'd1;     end end always @(posedge rclk or negedge rrstn) begin     if(~rrstn) begin         raddr_bin <= 'd0;     end      else if(!rempty && rinc)begin         raddr_bin <= raddr_bin + 1'd1;     end end   /**********************addr gray gen*************************/ wire   [ADDR_WIDTH:0]  waddr_gray; wire   [ADDR_WIDTH:0]  raddr_gray; reg    [ADDR_WIDTH:0]  wptr; reg    [ADDR_WIDTH:0]  rptr; assign waddr_gray = waddr_bin ^ (waddr_bin>>1); assign raddr_gray = raddr_bin ^ (raddr_bin>>1); always @(posedge wclk or negedge wrstn) begin      if(~wrstn) begin         wptr <= 'd0;     end      else begin         wptr <= waddr_gray;     end end always @(posedge rclk or negedge rrstn) begin      if(~rrstn) begin         rptr <= 'd0;     end      else begin         rptr <= raddr_gray;     end end /**********************syn addr gray*************************/ reg     [ADDR_WIDTH:0]  wptr_buff; reg     [ADDR_WIDTH:0]  wptr_syn; reg     [ADDR_WIDTH:0]  rptr_buff; reg     [ADDR_WIDTH:0]  rptr_syn; always @(posedge wclk or negedge wrstn) begin      if(~wrstn) begin         rptr_buff <= 'd0;         rptr_syn <= 'd0;     end      else begin         rptr_buff <= rptr;         rptr_syn <= rptr_buff;     end end always @(posedge rclk or negedge rrstn) begin      if(~rrstn) begin         wptr_buff <= 'd0;         wptr_syn <= 'd0;     end      else begin         wptr_buff <= wptr;         wptr_syn <= wptr_buff;     end end /**********************full empty gen*************************/ assign wfull = (wptr == {~rptr_syn[ADDR_WIDTH:ADDR_WIDTH-1],rptr_syn[ADDR_WIDTH-2:0]}); assign rempty = (rptr == wptr_syn);   /**********************RAM*************************/ wire   wen ; wire    ren ; wire   wren;//high write wire [ADDR_WIDTH-1:0]  waddr; wire [ADDR_WIDTH-1:0]  raddr; assign wen = winc & !wfull; assign ren = rinc & !rempty; assign waddr = waddr_bin[ADDR_WIDTH-1:0]; assign raddr = raddr_bin[ADDR_WIDTH-1:0];   dual_port_RAM #(.DEPTH(DEPTH),                 .WIDTH(WIDTH) )dual_port_RAM(     .wclk (wclk),       .wenc (wen),       .waddr(waddr[ADDR_WIDTH-1:0]),  //深度对2取对数,得到地址的位宽。     .wdata(wdata),           //数据写入     .rclk (rclk),      .renc (ren),      .raddr(raddr[ADDR_WIDTH-1:0]),   //深度对2取对数,得到地址的位宽。     .rdata(rdata)         //数据输出 );   endmodule

标签:begin,waddr,end,ADDR,FPGA,VL45,FIFO,WIDTH,input
来源: https://www.cnblogs.com/mahaidong/p/16482661.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有