题解 | #异步FIFO#

异步FIFO

https://www.nowcoder.com/practice/40246577a1a04c08b3b7f529f9a268cf

`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 reg [WIDTH-1:0]	rdata
);
parameter WIDTH_ptr= 5;
parameter WIDTH_addr= 4;

//读写模块
integer i ;
reg [WIDTH-1:0]buff[DEPTH-1:0];
reg [WIDTH_ptr-1:0]w_ptr;
wire [WIDTH_addr-1:0] w_addr;
assign w_addr=w_ptr[WIDTH_addr-1:0];
always@(posedge wclk or negedge wrstn)
   begin if(!wrstn)
      begin w_ptr<=0;
	  end
	else if(winc&(!wfull))
	  begin w_ptr<=w_ptr+1;
	        buff[w_addr]<=wdata;
	  end
   end
reg [WIDTH_ptr-1:0]r_ptr;
wire [WIDTH_addr-1:0] r_addr;
assign r_addr=r_ptr[WIDTH_addr-1:0];
always@(posedge rclk or negedge rrstn)
   begin if(!rrstn)
      begin  r_ptr<=0;
	        
	  end
	else if(rinc&(!rempty))
	  begin r_ptr<=r_ptr+1;
	        rdata<=buff[r_addr];
	  end
   end 
//指针同步
 wire [WIDTH_ptr-1:0]w_gray_ptr;   
 wire [WIDTH_ptr-1:0]r_gray_ptr;       
 reg  [WIDTH_ptr-1:0]w_gray_ptr_d0;       
 reg  [WIDTH_ptr-1:0]w_gray_ptr_d1; 
 reg  [WIDTH_ptr-1:0]w_gray_ptr_d2; 
 reg  [WIDTH_ptr-1:0]r_gray_ptr_d0;       
 reg  [WIDTH_ptr-1:0]r_gray_ptr_d1;   
 reg  [WIDTH_ptr-1:0]r_gray_ptr_d2;    
 assign w_gray_ptr=w_ptr^(w_ptr>>1);
 assign r_gray_ptr=r_ptr^(r_ptr>>1);
always@(posedge wclk or negedge wrstn)   //此在原时钟域打排非必要环节
 begin if(!wrstn)
    w_gray_ptr_d0<=0;
	else w_gray_ptr_d0<=w_gray_ptr;
 end
 always@(posedge rclk or negedge rrstn)
 begin if(!rrstn)
      {w_gray_ptr_d2,w_gray_ptr_d1}<=0;
	  else  {w_gray_ptr_d2,w_gray_ptr_d1}<={w_gray_ptr_d1,w_gray_ptr_d0};
 end
 always@(posedge rclk or negedge rrstn)        //此在原时钟域打排非必要环节
 begin if(!rrstn)
    r_gray_ptr_d0<=0;
	else r_gray_ptr_d0<=r_gray_ptr;
 end
 always@(posedge wclk or negedge wrstn)
 begin if(!wrstn)
      {r_gray_ptr_d2,r_gray_ptr_d1}<=0;
	  else  {r_gray_ptr_d2,r_gray_ptr_d1}<={r_gray_ptr_d1,r_gray_ptr_d0};
 end
//空满标志位产生
assign rempty=(w_gray_ptr_d2==r_gray_ptr_d0);
assign wfull=(r_gray_ptr_d2[WIDTH_ptr-1]!=w_gray_ptr_d0[WIDTH_ptr-1])&(r_gray_ptr_d2[WIDTH_ptr-2]!=w_gray_ptr_d0[WIDTH_ptr-2])&(r_gray_ptr_d2[WIDTH_ptr-3:0]==w_gray_ptr_d0[WIDTH_ptr-3:0]);
endmodule

全部评论

相关推荐

自由水:这HR已经很好了,多的是已读不回和不读了
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

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