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

// 1.二进制地址
	reg [$clog2(DEPTH)-1:0] waddr_bin;
	reg [$clog2(DEPTH)-1:0]	raddr_bin;

	always@(posedge clk,negedge rst_n)begin
		if(!rst_n)
			waddr_bin <= 'd0;
		else if(winc && !wfull)
			waddr_bin <= waddr_bin + 'd1;
	end

	always@(posedge clk,negedge rst_n)begin
		if(!rst_n)
			raddr_bin <= 'd0;
		else if(rinc && !rempty)
			raddr_bin <= raddr_bin + 'd1;
	end

// 2.计数器,控制空满flag
	reg [$clog2(DEPTH):0] cnt;

	always@(posedge clk,negedge rst_n)begin
		if(!rst_n)
			cnt <=  'd0;
		else if(winc && !wfull && rinc && !rempty)
			cnt <= cnt;
		else if(winc && !wfull)
			cnt <= cnt + 'd1;
		else if(rinc && !rempty)
			cnt <= cnt - 'd1;
	end

//3. 空满flag
	always@(posedge clk,negedge rst_n)begin
		if(!rst_n)
			wfull <= 'd0;
		else if(cnt == DEPTH)
			wfull <= 'd1;
		else
			wfull <= 'd0;
	end

	always@(posedge clk,negedge rst_n)begin
		if(!rst_n)
			rempty <= 'd0;
		else if(cnt == 'd0)
			rempty <= 'd1;
		else
		 	rempty <= 'd0;
	end


//4. RAM
dual_port_RAM #(.DEPTH(DEPTH),
				.WIDTH(WIDTH))
				u_dual_port_RAM(
	.wclk(clk),
	.wenc(winc && !wfull),
	.waddr(waddr_bin),  //深度对2取对数,得到地址的位宽。
	.wdata(wdata),      	//数据写入
	.rclk(clk),
	.renc(rinc && !rempty),
	.raddr(raddr_bin),  //深度对2取对数,得到地址的位宽。
	.rdata(rdata) 		//数据输出
);


/*
//读写地址模块
	reg [$clog2(DEPTH)-1:0]	waddr_bin;
	reg [$clog2(DEPTH)-1:0]	raddr_bin;

	always@(posedge clk,negedge rst_n)begin
		if(!rst_n)
			waddr_bin <= 'd0;
		else if(~wfull && winc)
			waddr_bin <= waddr_bin + 'd1;
	end

	always@(posedge clk,negedge rst_n)begin
		if(!rst_n)
			raddr_bin <= 'd0;
		else if(~rempty && rinc)
			raddr_bin <= raddr_bin + 'd1;
	end

//计数模块,控制空满
	reg [$clog2(DEPTH)-1:0]	cnt;

	always@(posedge clk, negedge rst_n)begin
		if(!rst_n)
			cnt <= 'd0;
		else if(winc & ~wfull & rinc & ~rempty)
			cnt <= cnt;
		else if(winc & ~wfull)
			cnt <= cnt + 'd1;
		else if(rinc & ~rempty)
			cnt <= cnt - 'd1;
		else
			cnt <= cnt;
	end

//空满 必须和cnt临界值一起拉高 只需要判断cnt即可不需要判断winc了(类比异步FIFO只用判断读写指针)

	always@(*)begin
		if(!rst_n)begin
			wfull <= 'd0;
			rempty <= 'd0;
		end
		else begin
			wfull <= ( cnt == (DEPTH))? 1'd1: 1'd0; //计数到DEPTH-1拉高,会少写一个数... 因为这是组合逻辑
			rempty <= ( cnt == 'd0 )? 1'd1: 1'd0;
		end			
	end


//RAM


	dual_port_RAM #(	.DEPTH(DEPTH),
					    .WIDTH(WIDTH)
	) u_dual_port_RAM(
	.wclk(clk),
	.wenc(~wfull && winc),
	.waddr(waddr_bin),  //深度对2取对数,得到地址的位宽。
	.wdata(wdata),      	//数据写入
	.rclk(clk),
	.renc(rinc & ~rempty),
	.raddr(raddr_bin),  //深度对2取对数,得到地址的位宽。
	.rdata(rdata) 		//数据输出
	);
	*/




endmodule

全部评论

相关推荐

09-04 21:05
已编辑
西南科技大学 Java
点赞 评论 收藏
分享
10-17 16:04
已编辑
南京大学 C++
陈启鸣:恭喜
投递腾讯等公司10个岗位
点赞 评论 收藏
分享
头像
10-21 14:00
已编辑
中南大学 后端
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务