题解 | #同步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 ); reg [$clog2(DEPTH)-1:0] w_pointer,r_pointer; // 读写指针 always@(posedge clk or negedge rst_n)begin if(~rst_n)begin w_pointer <= 'b0; end else if(winc && w_pointer < 4'd15 && ~wfull)begin w_pointer <= w_pointer + 1'b1; end else if(winc && w_pointer == 4'd15 && ~wfull)begin w_pointer <= 'b0; end end always@(posedge clk or negedge rst_n)begin if(~rst_n)begin r_pointer <= 'b0; end else if(rinc && r_pointer < 4'd15 && ~rempty)begin r_pointer <= r_pointer + 1'b1; end else if(rinc && r_pointer == 4'd15 && ~rempty)begin r_pointer <= 'b0; end end //写使能,读使能打一拍去看当pointer相等时,是哪个使能达到的,来驱动full empty 并不行,不知道哪有问题 // reg winc_d,rinc_d; // always@(posedge clk or negedge rst_n)begin // if(~rst_n)begin // winc_d <= 1'b0; // end // else begin // winc_d <= winc; // end // end // always@(posedge clk or negedge rst_n)begin // if(~rst_n)begin // rinc_d <= 1'b0; // end // else begin // rinc_d <= rinc; // end // end // always@(posedge clk or negedge rst_n)begin // if(~rst_n)begin // wfull <= 1'b0; // end // else if(w_pointer != r_pointer)begin // wfull <= 1'b0; // end // else if(w_pointer == r_pointer && winc_d)begin // wfull <= 1'b1; // end // end // always@(posedge clk or negedge rst_n)begin // if(~rst_n)begin // rempty <= 1'b0; // end // else if(w_pointer != r_pointer)begin // rempty <= 1'b0; // end // else if(w_pointer == r_pointer && rinc_d)begin // rempty <= 1'b1; // end // end //看答案,地址的变化写的没问题,空满状态的判断有点问题,答案采用的计数器的形式,写就加1,读减一 reg [$clog2(DEPTH):0] cnt; always@(posedge clk or negedge rst_n)begin if(~rst_n)begin cnt<= 1'b0; end else if(winc&~wfull) cnt <= cnt + 1; else if(rinc&~rempty) cnt <= cnt - 1; else cnt <= cnt; end always@(posedge clk or negedge rst_n) begin if(~rst_n) begin wfull = 0; rempty = 0; end else begin wfull = cnt == DEPTH; rempty = cnt == 0; end end dual_port_RAM dual_port_RAM_u0 ( .wclk(clk), .wenc(winc), .waddr(w_pointer), .wdata(wdata), .rclk(clk), .renc(rinc), .raddr(r_pointer), .rdata(rdata) ); endmodule