题解 | #同步FIFO#

同步FIFO

https://www.nowcoder.com/practice/3ece2bed6f044ceebd172a7bf5cfb416

`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  

/**********************************SFIFO************************************/
module sfifo#(
	parameter	WIDTH = 8,
	parameter 	DEPTH = 16
)(
	input 					clk		, 
	input 					rst_n	,
	input 					winc	,
	input 			 		rinc	,
	input 		[WIDTH-1:0]	wdata	,

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

reg [$clog2(DEPTH) :0] fifo_cnt;
reg [$clog2(DEPTH)-1:0] waddr_fifo;
reg [$clog2(DEPTH)-1:0] raddr_fifo;

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		waddr_fifo <= 0;
	else if(!wfull && winc)
		waddr_fifo <= waddr_fifo + 1'd1;
	else
		waddr_fifo <= waddr_fifo;
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		raddr_fifo <= 0;
	else if(!rempty && rinc)
		raddr_fifo <= raddr_fifo + 1'd1;
	else 
		raddr_fifo <= raddr_fifo;
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		fifo_cnt <= 0;
	else begin
		case({winc,rinc})
			2'b00:fifo_cnt <= fifo_cnt;						//不读不写
			2'b01:	                               			//仅仅读
				if(fifo_cnt != 0)				   			//fifo没有被读空
					fifo_cnt <= fifo_cnt - 1'b1;   			//fifo个数-1
			2'b10:                                 			//仅仅写
				if(fifo_cnt != DEPTH)         			//fifo没有被写满
					fifo_cnt <= fifo_cnt + 1'b1;   			//fifo个数+1
			2'b11:fifo_cnt <= fifo_cnt;	           			//读写同时
			default:;                              	
		endcase
	end
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		wfull <= 1'b0;
		rempty <= 1'b0;
	end else begin
		wfull  = (fifo_cnt == DEPTH) ? 1'b1 : 1'b0;
		rempty = (fifo_cnt == 0)? 1'b1 : 1'b0;
	end
end

dual_port_RAM #(
	.DEPTH (16),
	.WIDTH (8)
)uut(
	 .wclk(clk),
	 .wenc(winc&~wfull),
	 .waddr(waddr_fifo),  
	 .wdata(wdata),     	
	 .rclk(clk),
	 .renc(rinc&~rempty),
	 .raddr(raddr_fifo),
	 .rdata(rdata)
);
endmodule

需要注意:

1、在端口连接时需统一时钟信号clk;

2、使用计数器fifo_cnt来控制满空状态,在计数器写满时为满,反之;

3、例化信号wenc应该与主模块winc&!wfull 即写使能与非满,同理renc;

4、地址控制时,读写地址分别根据使能信号与空满状态进行递增与清零

全部评论

相关推荐

Yki_:你要算时间成本呀,研究生两三年,博士三四年,加起来就五六年了,如果你本科去腾讯干五年,多领五年的年薪,加上公司内涨薪,可能到时候十五年总薪资也跟博士差不多
点赞 评论 收藏
分享
06-26 17:24
已编辑
宁波大学 golang
迷失西雅图:别给,纯kpi,别问我为什么知道
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务