add asyn_fifo.v

This commit is contained in:
yunlongLi 2024-11-20 13:29:07 +08:00
parent 89392690ec
commit 4f6af7f995
1 changed files with 262 additions and 0 deletions

262
common/asyn_fifo.v Normal file
View File

@ -0,0 +1,262 @@
//==========================================================
//--Author : colonel
//--Date : 11-20
//--Module : async_fifo
//--Function: async_fifo
//==========================================================
//深度为8数据位宽为8的异步FIFO
module async_fifo #(
parameter DATA_DEPTH = 8, //深度为8
parameter DATA_WIDTH = 8, //数据位宽为8
parameter PTR_WIDTH = 3 //读写指针位宽为3
)(
input [DATA_WIDTH - 1 : 0] wr_data, //写数据
input wr_clk, //写时钟
input wr_rst_n, //写时钟复位
input wr_en, //写使能
input rd_clk, //读数据
input rd_rst_n, //读时钟复位
input rd_en, //读使能
output reg fifo_full, //标志位
output reg fifo_empty, //标志位
output reg [DATA_WIDTH - 1 : 0] rd_data //写时钟
);
/*-----------------------------------------------------------------
-----------------------------伪双口RAM模块--------------------------
------------------------------------------------------------------*/
//定义一个宽度为8深度为DEPTH的8的RAM_FIFO
reg [DATA_WIDTH - 1 : 0] ram_fifo [DATA_DEPTH - 1 : 0];
//写指针计数
reg [PTR_WIDTH : 0] wr_ptr; //信息位+地址位所以指针位宽为4
always@ (posedge wr_clk or negedge wr_rst_n) begin
if(!wr_rst_n) begin
wr_ptr <= 0;
end
else if(wr_en && !fifo_full) begin
wr_ptr <= wr_ptr + 1;
end
else begin
wr_ptr <= wr_ptr;
end
end
//RAM写入数据
wire [PTR_WIDTH -1 : 0] wr_addr;
assign wr_addr = wr_ptr[PTR_WIDTH -1 : 0]; //RAM写数据只需要地址位不需要信息位所以寻址地址位宽为3
always@ (posedge wr_clk or negedge wr_rst_n) begin
if(!wr_rst_n) begin
ram_fifo[wr_addr] <= 0; //复位
end
else if(wr_en && !fifo_full) begin
ram_fifo[wr_addr] <= wr_data; //数据写入
end
else begin
ram_fifo[wr_addr] <= ram_fifo[wr_addr]; //保持不变
end
end
//读指针计数
reg [PTR_WIDTH : 0] rd_ptr;
always@ (posedge rd_clk or negedge rd_rst_n) begin
if(!rd_rst_n) begin
rd_ptr <= 0;
end
else if(rd_en && !fifo_empty) begin
rd_ptr <= rd_ptr + 1;
end
else begin
rd_ptr <= rd_ptr;
end
end
//RAM读出数据
wire [PTR_WIDTH -1 : 0] rd_addr;
assign rd_addr = rd_ptr[PTR_WIDTH -1 : 0];//RAM读数据只需要地址位不需要信息位所以寻址地址位宽为3
always@ (posedge rd_clk or negedge rd_rst_n) begin
if(!rd_rst_n) begin
rd_data <= 0; //复位
end
else if(rd_en && !fifo_empty) begin
rd_data <= ram_fifo[rd_addr]; //读数据
end
else begin
rd_data <= rd_data; //保持不变
end
end
/*--------------------------------------------------------------------------------------
---------------------------读写指针格雷码转换与跨时钟域同步模块------------------------
---------------------------------------------------------------------------------------*/
//读写指针转换成格雷码
wire [PTR_WIDTH : 0] wr_ptr_gray;
wire [PTR_WIDTH : 0] rd_ptr_gray;
assign wr_ptr_gray = wr_ptr ^ (wr_ptr >> 1);
assign rd_ptr_gray = rd_ptr ^ (rd_ptr >> 1);
//写指针同步到读时钟域
//打两拍
reg [PTR_WIDTH : 0] wr_ptr_gray_r1;
reg [PTR_WIDTH : 0] wr_ptr_gray_r2;
always@ (posedge rd_clk or negedge rd_rst_n) begin
if(!rd_rst_n) begin
wr_ptr_gray_r1 <= 0;
wr_ptr_gray_r2 <= 0;
end
else begin
wr_ptr_gray_r1 <= wr_ptr_gray;
wr_ptr_gray_r2 <= wr_ptr_gray_r1;
end
end
//读指针同步到写时钟域
//打两拍
reg [PTR_WIDTH : 0] rd_ptr_gray_r1;
reg [PTR_WIDTH : 0] rd_ptr_gray_r2;
always@ (posedge wr_clk or negedge wr_rst_n) begin
if(!wr_rst_n) begin
rd_ptr_gray_r1 <= 0;
rd_ptr_gray_r2 <= 0;
end
else begin
rd_ptr_gray_r1 <= rd_ptr_gray;
rd_ptr_gray_r2 <= rd_ptr_gray_r1;
end
end
/*--------------------------------------------------------------------------------------
--------------------------------------空满信号判断模块-----------------------------------
---------------------------------------------------------------------------------------*/
//组合逻辑判断写满
always@ (*) begin
if(!wr_rst_n) begin
fifo_full <= 0;
end
else if( wr_ptr_gray == { ~rd_ptr_gray_r2[PTR_WIDTH : PTR_WIDTH - 1],
rd_ptr_gray_r2[PTR_WIDTH - 2 : 0] }) begin
fifo_full <= 1;
end
else begin
fifo_full <= 0;
end
end
//组合逻辑判断读空
always@ (*) begin
if(!rd_rst_n) begin
fifo_empty <= 0;
end
else if(rd_ptr_gray == wr_ptr_gray_r2) begin
fifo_empty <= 1;
end
else begin
fifo_empty <= 0;
end
end
endmodule
//==========================================================
//--Author : colonel
//--Date : 11-20
//--Module : fifo_testbench
//--Function: fifo_testbench
//==========================================================
`timescale 1ns/1ps;//仿真时间单位1ns 仿真时间精度1ps
module async_fifo_tb #(
parameter DATA_DEPTH = 8,
parameter DATA_WIDTH = 8,
parameter PTR_WIDTH = 3
);
//信号申明
reg [DATA_WIDTH - 1 : 0] wr_data;
reg wr_clk;
reg wr_rst_n;
reg wr_en;
reg rd_clk;
reg rd_rst_n;
reg rd_en;
wire fifo_full;
wire fifo_empty;
wire [DATA_WIDTH - 1 : 0] rd_data;
//例化
async_fifo u_async_fifo (
.wr_clk (wr_clk),
.rd_clk (rd_clk),
.wr_rst_n (wr_rst_n),
.rd_rst_n (rd_rst_n),
.wr_en (wr_en),
.rd_en (rd_en),
.wr_data (wr_data),
.rd_data (rd_data),
.fifo_empty (fifo_empty),
.fifo_full (fifo_full)
);
//读写时钟信号生成
always #10 rd_clk = ~rd_clk;
always #5 wr_clk = ~wr_clk;
//信号初始化和赋值
initial begin
wr_clk = 0;
wr_rst_n = 1;
wr_en = 0;
rd_clk = 0;
rd_rst_n = 1;
rd_en = 0;
#10;
wr_rst_n = 0;
rd_rst_n = 0;
#10;
wr_rst_n = 1;
rd_rst_n = 1;
//only write
wr_en = 1;
rd_en = 0;
repeat(10) begin
@(negedge wr_clk) begin
wr_data = {$random}%30;
end
end
//only read
wr_en = 0;
rd_en = 1;
repeat(10) begin
@(negedge rd_clk);
end
rd_en =0;
//read and write
wr_en = 0;
rd_en = 0;
#80;
wr_en = 1;
rd_en = 1;
repeat(20) begin
@(negedge wr_clk) begin
wr_data = {$random}%30;
end
end
end
endmodule