一种异步类型FTFW FIFO的实现

编程入门 行业动态 更新时间:2024-10-23 09:40:59

一种异步<a href=https://www.elefans.com/category/jswz/34/1771355.html style=类型FTFW FIFO的实现"/>

一种异步类型FTFW FIFO的实现

本FIFO特点:

异步、带有将满和将空信号,将空、将满阈值和数据宽度FIFO深度均参数化,FWFT类型。

FIFO代码段如下:

`timescale 1ns / 1ps
//
// Company:nssc
// Engineer:liumeng
// Create Date: 2021/12/17 14:11:19
// Module Name: ftfw_async_fifo
// Revision 0.01 - File Created
//
module ftfw_async_fifo #(parameter ADDR_WIDTH = 6,DATA_WIDTH = 9) (input rst_n,		//复位input wr_clk,	//写时钟input wr_en,		//写使能信号input [DATA_WIDTH-1:0] data_in,		//外部输入数据input rd_clk,	//读时钟input rd_en,		//读使能output [DATA_WIDTH-1:0] data_out,	//数据输出output full,output empty,output almost_full,output almost_empty);
localparam DEPTH = power2(ADDR_WIDTH);
localparam ALMOST_EMPTY_GAP = 1;
localparam ALMOST_FULL_GAP = DEPTH - 1;
function integer power2;input integer number;beginpower2 = (number<=0) ? 1 : 2**number;end
endfunctionwire fifo_empty;
reg dout_valid;reg [ADDR_WIDTH:0] wr_addr_ptr,wr_addr_ptr_next; 		//write address pointer
reg [ADDR_WIDTH:0] rd_addr_ptr,rd_addr_ptr_next;		//read address pointer
wire [ADDR_WIDTH:0] wr_addr_ptr_gray;
wire [ADDR_WIDTH:0] rd_addr_ptr_gray;
reg [ADDR_WIDTH:0] wr_addr_ptr_gray_1,wr_addr_ptr_gray_2;
reg [ADDR_WIDTH:0] rd_addr_ptr_gray_1,rd_addr_ptr_gray_2;reg [ADDR_WIDTH-1:0] wr_addr;							//write address
wire [ADDR_WIDTH-1:0] wr_addr_next;
reg [ADDR_WIDTH-1:0] rd_addr;							//read address
wire [ADDR_WIDTH-1:0] rd_addr_next;assign SRAM_wr_en = wr_en && !full;
assign SRAM_rd_en = !fifo_empty && (!dout_valid || rd_en);
assign empty = !dout_valid;//write address pointer update
always @ (*)if (!rst_n)wr_addr_ptr_next = 'b0;else if (wr_en && !full)wr_addr_ptr_next = wr_addr_ptr + 1'b1;elsewr_addr_ptr_next = wr_addr_ptr;//read address pointer update
always @ (*)if (!rst_n)rd_addr_ptr_next = 'b0;else if (rd_en && !fifo_empty)rd_addr_ptr_next = rd_addr_ptr + 1'b1;elserd_addr_ptr_next = rd_addr_ptr;//write and read address update
assign wr_addr_next = wr_addr_ptr_next[ADDR_WIDTH-1:0];
assign rd_addr_next = rd_addr_ptr_next[ADDR_WIDTH-1:0];//写地址指针格雷码转换
assign wr_addr_ptr_gray = (wr_addr_ptr >> 1) ^ wr_addr_ptr;
//读地址指针格雷码转换
assign rd_addr_ptr_gray = (rd_addr_ptr >> 1) ^ rd_addr_ptr;//写地址指针格雷码同步到读时钟域
always @ (posedge rd_clk or negedge rst_n)if (!rst_n)beginwr_addr_ptr_gray_1 <= 'b0;wr_addr_ptr_gray_2 <= 'b0;endelsebeginwr_addr_ptr_gray_1 <= wr_addr_ptr_gray;wr_addr_ptr_gray_2 <= wr_addr_ptr_gray_1;end//读地址指针格雷码同步到写时钟域
always @ (posedge wr_clk or negedge rst_n)if (!rst_n)beginrd_addr_ptr_gray_1 <= 'b0;rd_addr_ptr_gray_2 <= 'b0;endelsebeginrd_addr_ptr_gray_1 <= rd_addr_ptr_gray;rd_addr_ptr_gray_2 <= rd_addr_ptr_gray_1;end//同步过后的格雷码进行二进制转换,用于产生将空将满
wire [ADDR_WIDTH:0] wr_addr_ptr_gray_to_bin;
wire [ADDR_WIDTH:0] rd_addr_ptr_gray_to_bin;assign	wr_addr_ptr_gray_to_bin[ADDR_WIDTH] = wr_addr_ptr_gray_2[ADDR_WIDTH];
assign  rd_addr_ptr_gray_to_bin[ADDR_WIDTH] = rd_addr_ptr_gray_2[ADDR_WIDTH];
genvar i;
generatefor (i=0;i<ADDR_WIDTH;i=i+1)beginassign wr_addr_ptr_gray_to_bin[i] = wr_addr_ptr_gray_2[i]^wr_addr_ptr_gray_to_bin[i+1];assign rd_addr_ptr_gray_to_bin[i] = rd_addr_ptr_gray_2[i]^rd_addr_ptr_gray_to_bin[i+1];end
endgenerate//full信号产生
assign full = ({~wr_addr_ptr_gray[ADDR_WIDTH:ADDR_WIDTH-1],wr_addr_ptr_gray[ADDR_WIDTH-2:0]}) == rd_addr_ptr_gray_2 ? 1'b1:1'b0;//fifo_empty信号产生
assign fifo_empty = wr_addr_ptr_gray_2 == rd_addr_ptr_gray ? 1'b1: 1'b0;reg [ADDR_WIDTH-1:0] data_avail;
reg [ADDR_WIDTH-1:0] room_avail;//data_avail信号生成,用于进行将满判断
always @ (*)
beginif (wr_addr_ptr[ADDR_WIDTH]!=rd_addr_ptr_gray_to_bin[ADDR_WIDTH])beginif (wr_addr_ptr[ADDR_WIDTH-1:0]==rd_addr_ptr_gray_to_bin[ADDR_WIDTH-1:0])data_avail = DEPTH-1;elsedata_avail = DEPTH-(rd_addr_ptr_gray_to_bin[ADDR_WIDTH-1:0]-wr_addr_ptr[ADDR_WIDTH-1:0]);endelsedata_avail = wr_addr_ptr[ADDR_WIDTH-1:0]-rd_addr_ptr_gray_to_bin[ADDR_WIDTH-1:0];
endassign almost_full = (data_avail >= ALMOST_FULL_GAP)? 1'b1: 1'b0;//room_avail信号生成,用于进行将空判断
always @ (*)
beginif (rd_addr_ptr[ADDR_WIDTH]==wr_addr_ptr_gray_to_bin[ADDR_WIDTH])beginif (wr_addr_ptr_gray_to_bin[ADDR_WIDTH-1:0]==rd_addr_ptr[ADDR_WIDTH-1:0])room_avail = DEPTH-1;elseroom_avail = DEPTH-(wr_addr_ptr_gray_to_bin[ADDR_WIDTH-1:0]-rd_addr_ptr[ADDR_WIDTH-1:0]);endelseroom_avail = rd_addr_ptr[ADDR_WIDTH-1:0]-wr_addr_ptr_gray_to_bin[ADDR_WIDTH-1:0];
end
assign almost_empty = (room_avail >= (DEPTH-ALMOST_EMPTY_GAP))? 1'b1:1'b0;//输出信号打拍
always @ (posedge wr_clk or negedge rst_n)if (!rst_n)beginwr_addr_ptr <= 'b0;wr_addr <= 'b0;endelsebeginwr_addr_ptr <= wr_addr_ptr_next;wr_addr <= wr_addr_next;endalways @ (posedge rd_clk or negedge rst_n)if (!rst_n)beginrd_addr_ptr <= 'b0;rd_addr <= 'b0;endelsebeginrd_addr_ptr <= rd_addr_ptr_next;rd_addr <= rd_addr_next;endalways @(posedge rd_clk)if (~rst_n) begindout_valid <= 0;end else if (SRAM_rd_en) begindout_valid <= 1;end else if (rd_en) begindout_valid <= 0;end//模块例化
sram #(.ADDR_WIDTH(ADDR_WIDTH),.DATA_WIDTH(DATA_WIDTH))m0 (.rst_n (rst_n),.wr_clk (wr_clk),.wr_en (SRAM_wr_en ),.wr_addr (wr_addr),.rd_clk (rd_clk),.rd_en (SRAM_rd_en ),.rd_addr (rd_addr),.data_in (data_in),.data_out (data_out));endmodule

 其中使用到的SRAM代码段如下:

`timescale 1ns / 1ps
//
// Company:nssc
// Engineer:liumeng
// Create Date: 2021/12/17 14:11:53
// Module Name: sram
// Revision 0.01 - File Created
//
module 	sram #(parameter ADDR_WIDTH = 6,DATA_WIDTH = 9)(input 	rst_n,input 	wr_clk,input 	wr_en,input   [ADDR_WIDTH-1:0] wr_addr,input   rd_clk,input   rd_en,input   [ADDR_WIDTH-1:0] rd_addr,input   [DATA_WIDTH-1:0] data_in,output reg [DATA_WIDTH-1:0] data_out);
function integer power2;input integer number;beginpower2 = (number<=0) ? 1 : 2**number;end
endfunction
localparam DEPTH = power2(ADDR_WIDTH);//存储阵列定义
reg [DATA_WIDTH-1:0] SRAM_MEM [DEPTH-1:0];//数据写入
always @ (posedge wr_clk) beginif (wr_en) beginSRAM_MEM [wr_addr] <= data_in;endelse beginSRAM_MEM [wr_addr] <= SRAM_MEM [wr_addr];end
end//数据读出
always @ (posedge rd_clk) beginif (~rst_n) begindata_out <= {DATA_WIDTH{1'b0}};end else if (rd_en) begindata_out <= SRAM_MEM [rd_addr];end else begindata_out <= data_out;end
endendmodule

测试代码如下:

//
// Company: nssc
// Engineer: liumeng
// Create Date: 2021/12/17 14:13:51
// Module Name: sim_ftfw_async_fifo
// Revision 0.01 - File Created
//
`timescale 1ns / 1ps
module sim_ftfw_async_fifo;localparam ADDR_WIDTH = 4;
localparam DATA_WIDTH = 9;reg rst_n;
reg wr_clk;
reg wr_en;
reg [DATA_WIDTH-1:0] data_in;
reg rd_clk;
reg rd_en;
wire [DATA_WIDTH-1:0] data_out;
wire full;
wire empty;
wire almost_empty;
wire almost_full;reg[1:0] op_code;
assign wr_sig = op_code[1];
assign rd_sig = op_code[0];ftfw_async_fifo #(.ADDR_WIDTH(ADDR_WIDTH),.DATA_WIDTH(DATA_WIDTH))uut(.rst_n(rst_n),.wr_clk(wr_clk),.wr_en(wr_en),.data_in(data_in),.rd_clk(rd_clk),.rd_en(rd_en),.data_out(data_out),.full(full),.empty(empty),.almost_full(almost_full),.almost_empty(almost_empty));
always #10 wr_clk = ~wr_clk;
always #15 rd_clk = ~rd_clk;
initial beginwr_clk	= 1'b0;rst_n	= 1'b1;rd_clk	= 1'b0;#200;rst_n	= 1'b0;#200;rst_n	= 1'b1;
endalways @(posedge wr_clk) beginif(~rst_n)data_in <= {DATA_WIDTH{1'b0}}+1'b1;else if (wr_en) begindata_in <= data_in + 1'b1;end
endalways @(posedge wr_clk) beginif(~rst_n)wr_en <= 1'b0;else if (wr_sig) beginif (wr_en) beginwr_en <= ~almost_full;end else beginwr_en <= ~full;endend else beginwr_en <= 1'b0;end
endalways @(posedge rd_clk) beginif(~rst_n)rd_en <= 1'b0;else if (rd_sig) beginif (rd_en) beginrd_en <= ~almost_empty;end else beginrd_en <= ~empty;endend else beginrd_en <= 1'b0;end
endinitial beginop_code = 2'b00;#500;op_code = 2'b10;#1000;op_code = 2'b01;#1000;op_code = 2'b00;#1000;op_code = 2'b11;#5000;op_code = 2'b01;#1000;op_code = 2'b00;endendmodule

 测试结果见图:

 写部分:

 读部分:

 整体:

更多推荐

一种异步类型FTFW FIFO的实现

本文发布于:2024-03-10 13:54:25,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1728161.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:类型   FTFW   FIFO

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!