verilog设计
同步FIFO设计

[!note]
同步FIFO可以解决位宽,速率的匹配

[!note]
重点在于读写指针的控制

[!important]
怎么具体判断FIFO是空还是满:
设计fifo_cnt,当为深度的时候,为满
wr_en的时候+1,rd_en的时候-1,wr_en和rd_en同时为高的时候counter不变
当fifo_cnt等于DEPTH的时候为满,否则为空
指针多扩展1bit,当标志位不一样的时候就是满标志,否则是空标志

补充
当FIFO的读写位宽不匹配的时候
[!important]
实现代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
| `timescale 1ns/1ns
module dual_port_RAM #(parameter DEPTH = 16, parameter WIDTH = 8)( input wclk ,input wenc ,input [$clog2(DEPTH)-1:0] waddr ,input [WIDTH-1:0] wdata ,input rclk ,input renc ,input [$clog2(DEPTH)-1:0] raddr ,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
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 );
localparam AWIDTH = $clog2(DEPTH);
reg [AWIDTH:0] fifo_wr_addr; reg [AWIDTH:0] fifo_rd_addr;
wire fifo_wren ;
assign fifo_wren = winc & !wfull; assign fifo_rden = rinc & !rempty;
always @(posedge clk or negedge rst_n)begin if(!rst_n) rempty <= 1'b0; else if((fifo_wr_addr[AWIDTH] == fifo_rd_addr[AWIDTH]) && (fifo_rd_addr[AWIDTH-1:0] == fifo_wr_addr[AWIDTH-1: 0])) rempty <= 1'b1; else rempty <= 1'b0; end
always @(posedge clk or negedge rst_n)begin if(!rst_n) wfull <= 1'b0; else if((fifo_wr_addr[AWIDTH] != fifo_rd_addr[AWIDTH]) && (fifo_rd_addr[AWIDTH-1:0] == fifo_wr_addr[AWIDTH-1: 0])) wfull <= 1'b1; else wfull <= 1'b0; end
always @(posedge clk or negedge rst_n)begin if(!rst_n) fifo_wr_addr <= {AWIDTH+1{1'B0}}; else if(winc && !wfull) fifo_wr_addr <= fifo_wr_addr + 1'b1; else fifo_wr_addr <= fifo_wr_addr; end
always @(posedge clk or negedge rst_n)begin if(!rst_n) fifo_rd_addr <= {AWIDTH+1{1'B0}}; else if(rinc && !rempty) fifo_rd_addr <= fifo_rd_addr + 1'b1; else fifo_rd_addr <= fifo_rd_addr; end
dual_port_RAM #( .DEPTH ( DEPTH ), .WIDTH ( WIDTH ) )fifo_ram( .wclk ( clk ), .wenc ( fifo_wren ), .waddr ( fifo_wr_addr[AWIDTH-1: 0] ), .wdata ( wdata ), .rclk ( clk ), .renc ( fifo_rden ), .raddr ( fifo_rd_addr[AWIDTH-1: 0] ), .rdata ( rdata )
); endmodule
|