【FPGA学习笔记】VL45 异步FIFO
作者:互联网
请根据题目中给出的双口RAM代码和接口描述,实现异步FIFO,要求FIFO位宽和深度参数化可配置。
input rclk ,
input wrstn ,
input rrstn ,
input winc ,
input rinc ,
input [WIDTH-1:0] wdata
output wire rempty ,
output wire [WIDTH-1:0] rdata
电路的接口如下图所示。
双口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