题解 | #同步FIFO#
同步FIFO
https://www.nowcoder.com/practice/3ece2bed6f044ceebd172a7bf5cfb416
//$clog2(DEPTH) 取位宽 //主要是注意address以及cnt `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 ADDR_WIDTH=$clog2(DEPTH); reg[ADDR_WIDTH:0]cnt; wire wenc=winc&(~wfull); wire renc=rinc&(~rempty); //addr reg[ADDR_WIDTH-1:0]waddr,raddr; always@(posedge clk or negedge rst_n)begin if(!rst_n)begin waddr<=0; raddr<=0; end else begin waddr<=winc&~wfull?waddr+1:waddr; raddr<=rinc&~rempty?raddr+1:raddr; end end //cnt always@(posedge clk or negedge rst_n)begin if(!rst_n) cnt<=0; else if(winc&!wfull) cnt<=cnt+1; else if(rinc&!rempty) cnt<=cnt-1; else cnt<=cnt; end // full empty always@(posedge clk or negedge rst_n)begin if(!rst_n) wfull<=0; else if(cnt==DEPTH)//$clog2(DEPTH)将10进制换为二进制 即位宽 wfull<=1; else wfull<=0; end always@(posedge clk or negedge rst_n)begin if(!rst_n) rempty<=0; else if(cnt==0) rempty<=1; else rempty<=0; end //双端口ram dual_port_ram dual_port_RAM #( .DEPTH(DEPTH), .WIDTH(WIDTH) ) ram1( . wclk(clk), . wenc(wenc), . waddr(waddr), //深度对2取对数,得到地址的位宽。 . wdata(wdata) , //数据写入 . rclk(clk), . renc(renc), . raddr (raddr), //深度对2取对数,得到地址的位宽。 . rdata (rdata)//数据输出 ); endmodule