题解 | #异步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 wire [WIDTH-1:0] rdata ); //write reg [4:0] count_w, count_w_gray; reg [4:0] address_r_t, address_r; wire wen; always@(posedge wclk or negedge wrstn) begin if(~wrstn) begin count_w <= 0; end else count_w <= (!wfull && winc)? count_w+1 : count_w; end // assign count_w_gray = count_w ^ (count_w>>1); always@(posedge wclk or negedge wrstn) begin if(~wrstn) count_w_gray <= 0; else count_w_gray <= count_w ^ (count_w>>1); end always@(posedge wclk or negedge wrstn) begin if(~wrstn) begin address_r_t <= 0; address_r <= 0; end else begin address_r_t <= count_r_gray; address_r <= address_r_t; end end // assign wfull = ((count_w_gray[4:3]!=address_r[4:3]) && (count_w_gray[2:0] == address_r[2:0])); assign wfull = ({~count_w_gray[4:3],count_w_gray[2:0]}==address_r); assign wen = (!wfull && winc); //read reg [4:0] count_r, count_r_gray; reg [4:0] address_w_t, address_w; wire ren; always@(posedge rclk or negedge rrstn) begin if(~rrstn) begin count_r <= 0; end else count_r <= (!rempty && rinc)? count_r+1 : count_r; end // assign count_r_gray = count_r ^ (count_r>>1); always@(posedge rclk or negedge rrstn) begin if(~rrstn) count_r_gray <= 0; else count_r_gray <= count_r ^ (count_r>>1); end always@(posedge rclk or negedge rrstn) begin if(~rrstn) begin address_w_t <= 0; address_w <= 0; end else begin address_w_t <= count_w_gray; address_w <= address_w_t; end end assign rempty = (address_w==count_r_gray); assign ren = (!rempty && rinc); dual_port_RAM #(.DEPTH(16),.WIDTH(8)) dpram( .wclk (wclk), .wenc (wen), .waddr (count_w[3:0]), .wdata (wdata), .rclk (rclk), .renc (ren), .raddr (count_r[3:0]), .rdata (rdata) ); endmodule