【牛客】VL45 异步FIFO

描述

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

电路的接口如下图所示。
在这里插入图片描述
双口RAM端口说明:

在这里插入图片描述

同步FIFO端口说明:
在这里插入图片描述

双口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

代码

`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
);
	localparam PTR_WIDTH = $clog2(DEPTH);

	reg [PTR_WIDTH : 0] wr_ptr, rd_ptr;
	reg [PTR_WIDTH : 0] wr_ptr_gray, rd_ptr_gray; // xpm_cdc_gray
	reg [PTR_WIDTH : 0] wr_ptr_gray_cdc[1:0], rd_ptr_gray_cdc[1:0];
	reg [PTR_WIDTH : 0] wr_ptr_rclk, rd_ptr_wclk;

//========================================================
//=                    gray encode                      
//========================================================
	integer i, j, k, l;  // ......
	always @(posedge rclk or negedge rrstn) begin
		if (~rrstn) begin
			rd_ptr_gray <= 'd0;
		end else begin
			rd_ptr_gray[PTR_WIDTH] <= rd_ptr[PTR_WIDTH];
			for (i = 0; i < PTR_WIDTH; i = i + 1) begin
				rd_ptr_gray[i] <= rd_ptr[i + 1] ^ rd_ptr[i];
			end
		end
	end

	always @(posedge wclk or negedge wrstn) begin
		if (~wrstn) begin
			wr_ptr_gray <= 'd0;
		end else begin
			wr_ptr_gray[PTR_WIDTH] <= wr_ptr[PTR_WIDTH];
			for (j = 0; j < PTR_WIDTH; j = j + 1) begin
				wr_ptr_gray[j] <= wr_ptr[j + 1] ^ wr_ptr[j];
			end
		end
	end

//========================================================
//=              clock domain crossing                      
//========================================================
	always @(posedge wclk or negedge wrstn) begin
		if (~wrstn) begin
			rd_ptr_gray_cdc[1] <= 'd0;
			rd_ptr_gray_cdc[0] <= 'd0;
		end else begin
			rd_ptr_gray_cdc[1] <= rd_ptr_gray_cdc[0];
			rd_ptr_gray_cdc[0] <= rd_ptr_gray;
		end
	end
	
	always @(posedge rclk or negedge rrstn) begin
		if (~rrstn) begin
			wr_ptr_gray_cdc[1] <= 'd0;
			wr_ptr_gray_cdc[0] <= 'd0;
		end else begin
			wr_ptr_gray_cdc[1] <= wr_ptr_gray_cdc[0];
			wr_ptr_gray_cdc[0] <= wr_ptr_gray;
		end
	end
	
//========================================================
//=                gray decode                      
//========================================================
	always @(*) begin
		rd_ptr_wclk[PTR_WIDTH] = rd_ptr_gray_cdc[1][PTR_WIDTH];
		for (k = PTR_WIDTH - 1; k >= 0; k = k - 1) begin // blocking assignment, [i + 1] need update before [i]
			rd_ptr_wclk[k] = rd_ptr_wclk[k + 1] ^ rd_ptr_gray_cdc[1][k];
		end
	end

	always @(*) begin
		wr_ptr_rclk[PTR_WIDTH] = wr_ptr_gray_cdc[1][PTR_WIDTH];
		for (l = PTR_WIDTH - 1; l >= 0; l = l - 1) begin
			wr_ptr_rclk[l] = wr_ptr_rclk[l + 1] ^ wr_ptr_gray_cdc[1][l];
		end
	end

//========================================================
//=       fifo pointer (clog2(DEPTH) ** 2 == DEPTH)                     
//========================================================
	always @(posedge wclk or negedge wrstn) begin
		if (~wrstn) begin
			wr_ptr <= 'd0;
		end else begin
			if (winc & ~wfull) begin
				wr_ptr <= wr_ptr + 'd1;
			end
		end
	end

	always @(posedge rclk or negedge rrstn) begin
		if (~rrstn) begin
			rd_ptr <= 'd0;
		end else begin
			if (rinc & ~rempty) begin
				rd_ptr <= rd_ptr + 'd1;
			end
		end
	end

	reg wfull_s, rempty_s;

	assign wfull = wfull_s;
	assign rempty = rempty_s;

	always @(*) begin
		// if (~wrstn) begin
		// 	wfull_s = 1'b0;
		// end else begin
			// wfull_s = (wr_ptr[PTR_WIDTH] != rd_ptr_wclk[PTR_WIDTH]) && (wr_ptr[PTR_WIDTH - 1 : 0] == rd_ptr_wclk[PTR_WIDTH - 1 : 0]);
			wfull_s = (wr_ptr_gray[PTR_WIDTH] != rd_ptr_gray_cdc[1][PTR_WIDTH]) && 
						(wr_ptr_gray[PTR_WIDTH - 1] != rd_ptr_gray_cdc[1][PTR_WIDTH - 1]) &&
						(wr_ptr_gray[PTR_WIDTH - 2 : 0] == rd_ptr_gray_cdc[1][PTR_WIDTH - 2 : 0]); //比较格雷码大小
		// end
	end

	always @(*) begin
		// if (~rrstn) begin
		// 	rempty_s = 1'b1;
		// end else begin
			// rempty_s = (rd_ptr == wr_ptr_rclk);
			rempty_s = (rd_ptr_gray == wr_ptr_gray_cdc[1]);
		// end
	end

	wire [WIDTH-1:0] ram_rdata;
	// assign rdata = (~rrstn) ? 'd0 : ram_rdata;

	assign rdata = ram_rdata;

	dual_port_RAM #(
		.DEPTH(DEPTH),
		.WIDTH(WIDTH)
	) dual_port_RAM_inst(
		.wclk (wclk                     ),
		.wenc (winc & ~wfull            ),
		.waddr(wr_ptr[PTR_WIDTH - 1 : 0]),
		.wdata(wdata                    ),
		.rclk (rclk                     ),
		.renc (rinc & ~rempty           ),
		.raddr(rd_ptr[PTR_WIDTH - 1 : 0]),
		.rdata(ram_rdata                ) 		
	);
    
endmodule
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wjh776a68

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值