Abstract: Verilog 同步及异步 FIFO 设计
FIFO:F irst I nput F irst O utput
同步 FIFO 解析 (原理很简单所以不写了)
示例代码 题目见:同步FIFO_牛客题霸_牛客网 (nowcoder.com)
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 109 110 111 `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 ); reg [$clog2 (DEPTH)-1 :0 ] waddr, raddr; reg [$clog2 (DEPTH):0 ] cnt; always @(posedge clk or negedge rst_n) begin if (~rst_n) begin waddr <= 'd0 ; end else begin waddr <= (winc&&(~wfull))? waddr+'d1 : waddr; end end always @(posedge clk or negedge rst_n) begin if (~rst_n) begin raddr <= 'd0 ; end else begin raddr <= (rinc&&(~rempty))? raddr+'d1 : raddr; end end always @(posedge clk or negedge rst_n) begin if (~rst_n) begin cnt <= 'd0 ; end else begin if (winc&&(~wfull)) begin cnt <= cnt + 'd1 ; end else if (rinc&&(~rempty)) begin cnt <= cnt - 'd1 ; end else if (winc&&(~wfull) && rinc&&(~rempty)) begin cnt <= cnt; end else begin cnt <= cnt; end end end always @(posedge clk or negedge rst_n) begin if (~rst_n) begin wfull = 'd0 ; rempty = 'd0 ; end else begin wfull = (cnt==DEPTH); rempty = (cnt=='d0 ); end end dual_port_RAM #( .DEPTH (DEPTH), .WIDTH (WIDTH) ) u_ram ( .wclk (clk), .wenc (winc&&(~wfull)), .waddr (waddr), .wdata (wdata), .rclk (clk), .renc (rinc&&(~rempty)), .raddr (raddr), .rdata (rdata) ); endmodule
异步 FIFO 解析 (其他人写的非常好了)
使用格雷码进行地址比较很有借鉴价值
题解 | #异步FIFO#_牛客博客 (nowcoder.net)
示例代码 题目见:异步FIFO_牛客题霸_牛客网 (nowcoder.com)
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 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 `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 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 ); parameter ADDR_WIDTH = $clog2 (DEPTH); reg [ADDR_WIDTH:0 ] waddr_bin, raddr_bin; always @(posedge wclk or negedge wrstn) begin if (~wrstn) begin waddr_bin <= 'b0 ; end else begin waddr_bin <= (winc&&(~wfull))? waddr_bin+'d1 : waddr_bin; end end always @(posedge rclk or negedge rrstn) begin if (~rrstn) begin raddr_bin <= 'b0 ; end else begin raddr_bin <= (rinc&&(~rempty))? raddr_bin+'d1 : raddr_bin; end end reg [ADDR_WIDTH:0 ] waddr_gray, raddr_gray; always @(posedge wclk or negedge wrstn) begin if (~wrstn) begin waddr_gray <= 'b0 ; end else begin waddr_gray <= waddr_bin^(waddr_bin>>1 ); end end always @(posedge rclk or negedge rrstn) begin if (~rrstn) begin raddr_gray <= 'b0 ; end else begin raddr_gray <= raddr_bin^(raddr_bin>>1 ); end end reg [ADDR_WIDTH:0 ] waddr_gray_sync, waddr_gray_sync_r1; reg [ADDR_WIDTH:0 ] raddr_gray_sync, raddr_gray_sync_r1; always @(posedge rclk or negedge rrstn) begin if (~rrstn) begin waddr_gray_sync_r1 <= 'b0 ; waddr_gray_sync <= 'b0 ; end else begin waddr_gray_sync_r1 <= waddr_gray; waddr_gray_sync <= waddr_gray_sync_r1; end end always @(posedge wclk or negedge wrstn) begin if (~wrstn) begin raddr_gray_sync_r1 <= 'b0 ; raddr_gray_sync <= 'b0 ; end else begin raddr_gray_sync_r1 <= raddr_gray; raddr_gray_sync <= raddr_gray_sync_r1; end end assign wfull = (waddr_gray == {~raddr_gray_sync[ADDR_WIDTH:ADDR_WIDTH-1 ], raddr_gray_sync[ADDR_WIDTH-2 :0 ]}); assign rempty = (raddr_gray == waddr_gray_sync); dual_port_RAM #( .WIDTH (WIDTH), .DEPTH (DEPTH) ) u_ram ( .wclk (wclk), .wenc (winc&&(~wfull)), .waddr (waddr_bin[ADDR_WIDTH-1 :0 ]), .wdata (wdata), .rclk (rclk), .renc (rinc&&(~rempty)), .raddr (raddr_bin[ADDR_WIDTH-1 :0 ]), .rdata (rdata) ); endmodule