题解 | #同步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 ); parameter DEPTH_WK=$clog2(DEPTH); //深度对2取对数,得到地址的位宽 reg [DEPTH_WK-1:0] waddr, raddr; reg [DEPTH_WK :0] cnt; //计数器,判断空满 wire wenc, renc; assign wenc=winc&&~wfull; //写使能 assign renc=rinc&&~rempty; //读使能 //读地址(waddr)变化 always@(posedge clk or negedge rst_n)begin if (!rst_n) waddr<='d0; else if( wenc) waddr<=waddr+1'b1; end //写地址(raddr)变化 always@(posedge clk or negedge rst_n)begin if (!rst_n) raddr<='d0; else if(renc) raddr<=raddr+1'b1; end // cnt计数模块 always @ (posedge clk, negedge rst_n) begin if(!rst_n) cnt <= 0; else if(wenc&&~renc) //写入的时候计数器加一 cnt <= cnt + 1; else if(renc&&~wenc) cnt <= cnt - 1; //读出的时候计数器减一 else cnt <= cnt; end //通过cnt判断空满 always @ (posedge clk, negedge rst_n) begin if(!rst_n) begin wfull <= 1'b0; rempty <= 1'b0; end else if(cnt == DEPTH) begin wfull <= 1'b1; end else if(cnt == 'd0) begin rempty <= 1'b1; end else begin wfull <= 1'b0; rempty <= 1'b0; end end dual_port_RAM #( .DEPTH (DEPTH ), .WIDTH (WIDTH ) ) dual_port_RAM_inst ( .wclk (clk ), .wenc (wenc ), .waddr (waddr ), .wdata (wdata ), .rclk (clk ), .renc (renc ), .raddr (raddr ), .rdata (rdata ) ); endmodule