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

全部评论

相关推荐

不如趁早摆摊:你跟他说我八小时七小时都是在使用夸克学习
点赞 评论 收藏
分享
ProMonkey2024:5个oc?厉害! 但是有一个小问题:谁问你了?😡我的意思是,谁在意?我告诉你,根本没人问你,在我们之中0人问了你,我把所有问你的人都请来 party 了,到场人数是0个人,誰问你了?WHO ASKED?谁问汝矣?誰があなたに聞きましたか?누가 물어봤어?我爬上了珠穆朗玛峰也没找到谁问你了,我刚刚潜入了世界上最大的射电望远镜也没开到那个问你的人的盒,在找到谁问你之前我连癌症的解药都发明了出来,我开了最大距离渲染也没找到谁问你了我活在这个被辐射蹂躏了多年的破碎世界的坟墓里目睹全球核战争把人类文明毁灭也没见到谁问你了(别的帖子偷来的,现学现卖😋)
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务