题解 | #同步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  



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     //读数据
);



localparam WIDTH_ADDR = $clog2(DEPTH);   //定义地址位宽

reg [WIDTH_ADDR-1:0] waddr,raddr; //读写地址



reg [WIDTH_ADDR:0] cnt;//这个用来计ram储存器有多少个数据未读,切记不能[WIDTH-1:0],个人理解因为是16个数据,16个状态,还要加上初始状态

wire wenc,renc; //读写使能



//地址计数器(计算当前读写地址之间的差值)
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		cnt <= 'd0;
	else if(winc && !rinc && !wfull && (cnt < DEPTH))  //如果写使能拉高,读使能拉低并且未写满情况下,cnt加1,也就多了一个未读的数据  
		cnt <= cnt + 1'd1;
	else if(!winc && rinc && !rempty && (cnt > 0))//如果读使能拉高,写使能拉低并且非空情况下,cnt减1,也就少了一个未读的数据
		cnt <= cnt - 1'd1;
	else
		cnt <= cnt;//其他情况下不变,包括边读边写的时候他也不变
end


//写满读空标志
always @(posedge clk or negedge rst_n)begin
	if(~rst_n)begin
		wfull <= 1'b0;
		rempty <= 1'b0;//复位情况下不应该是1吗这里?感觉这里应该是1,但可能会影响后面的逻辑,所以出错
	end
	else if(cnt == DEPTH)//如果ram已经有了DEPTH(16)个未读数据,则拉高写满标志
	wfull <= 1'b1;
	else if(cnt == 0)//如果ram只有0个数据,则拉高读空标志
	rempty <= 1'b1;
	else begin   //以后这样的还是分开写吧,忘了写这个else,找了大半天的问题
		wfull <= 1'b0;
		rempty <= 1'b0;
	end
end





//写地址控制
always @(posedge clk or negedge rst_n)begin
	if(~rst_n)
	waddr <= 'd0;
	else if(!wfull && winc)  //如果未满且写使能拉高,如果waddr已经到最大了DEPTH-1则置0,否则加1
	waddr <= (waddr==(DEPTH-1))?('d0):(waddr+1'b1);
	else
	waddr <= waddr;
end

//读地址控制
always @(posedge clk or negedge rst_n)begin
	if(~rst_n)
	raddr <= 'd0;
	else if(!rempty && rinc)
	raddr <= (raddr==(DEPTH-1))?'d0:(raddr+1'b1);
	else
	raddr <= raddr;
end



dual_port_RAM inst(

	.wclk(clk),
	.wenc(wenc),
	.waddr(waddr), 
	.wdata(wdata),      	
	.rclk(clk),
	.renc(renc),
	.raddr(raddr),  
	.rdata(rdata) 		
);



assign wenc = winc && !wfull;//只有ram非满且写使能,fifo的写使能才拉高
assign renc = rinc && !rempty;




endmodule

全部评论

相关推荐

04-30 21:35
已编辑
长安大学 C++
晓沐咕咕咕:评论区没被女朋友好好对待过的计小将可真多。觉得可惜可以理解,毕竟一线大厂sp。但是骂楼主糊涂的大可不必,说什么会被社会毒打更是丢人。女朋友体制内生活有保障,读研女朋友还供着,都准备订婚了人家两情相悦,二线本地以后两口子日子美滋滋,哪轮到你一个一线城市房子都买不起的996清高计小将在这说人家傻😅
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务