sync_fifo.sv (3179B)
1 // Copyright 2020, Brian Swetland <swetland@frotz.net> 2 // Licensed under the Apache License, Version 2.0. 3 4 `default_nettype none 5 6 // basic fifo with power-of-two storage elements 7 8 // bypass register allows written data to be available 9 // the cycle after a write in all cases. 10 `define SYNC_FIFO_WITH_BYPASS 11 12 module sync_fifo #( 13 // fifo entry data width in bits 14 parameter WIDTH = 8, 15 16 // fifo depth in 2 ^ DEPTH 17 parameter DEPTH = 8 18 ) ( 19 input wire clk, 20 21 input wire [WIDTH-1:0]wr_data, 22 input wire wr_valid, 23 output reg wr_ready = 0, 24 25 output wire [WIDTH-1:0]rd_data, 26 output reg rd_valid = 0, 27 input wire rd_ready 28 ); 29 30 localparam PTRONE = { {DEPTH{1'b0}}, 1'b1 }; 31 32 wire do_wr = (wr_valid & wr_ready); 33 wire do_rd = (rd_valid & rd_ready); 34 35 // pointers are one bit wider so the high bit 36 // can help compute full / empty 37 reg [DEPTH:0]wr_ptr = 0; 38 reg [DEPTH:0]rd_ptr = 0; 39 40 // prepare the new r/w pointer values 41 wire [DEPTH:0]wr_ptr_next = do_wr ? (wr_ptr + PTRONE) : wr_ptr; 42 wire [DEPTH:0]rd_ptr_next = do_rd ? (rd_ptr + PTRONE) : rd_ptr; 43 44 // compute the new full/empty states 45 wire full_or_empty_next = (rd_ptr_next[DEPTH-1:0] == wr_ptr_next[DEPTH-1:0]); 46 wire full_next = full_or_empty_next & (rd_ptr_next[DEPTH] != wr_ptr_next[DEPTH]); 47 wire empty_next = full_or_empty_next & (rd_ptr_next[DEPTH] == wr_ptr_next[DEPTH]); 48 wire one_next = ((wr_ptr_next - rd_ptr_next) == PTRONE); 49 50 localparam EMPTY = 2'd0; 51 localparam ONE = 2'd1; 52 localparam MANY = 2'd2; 53 localparam FULL = 2'd3; 54 55 reg [1:0]state = EMPTY; 56 reg [1:0]state_next; 57 reg rd_valid_next; 58 reg wr_ready_next; 59 60 `ifdef SYNC_FIFO_WITH_BYPASS 61 reg [WIDTH-1:0]bypass; 62 reg use_bypass = 0; 63 reg use_bypass_next; 64 `endif 65 66 always_comb begin 67 state_next = state; 68 rd_valid_next = rd_valid; 69 wr_ready_next = wr_ready; 70 `ifdef SYNC_FIFO_WITH_BYPASS 71 use_bypass_next = 0; 72 `endif 73 74 case (state) 75 EMPTY: begin 76 wr_ready_next = 1; 77 if (do_wr) begin 78 state_next = ONE; 79 `ifdef SYNC_FIFO_WITH_BYPASS 80 rd_valid_next = 1; 81 use_bypass_next = 1; 82 `endif 83 end 84 end 85 ONE: begin 86 if (do_rd & do_wr) begin 87 `ifdef SYNC_FIFO_WITH_BYPASS 88 use_bypass_next = 1; 89 `else 90 rd_valid_next = 0; 91 `endif 92 end else if (do_rd) begin 93 state_next = EMPTY; 94 rd_valid_next = 0; 95 end else if (do_wr) begin 96 state_next = MANY; 97 rd_valid_next = 1; 98 end else begin 99 rd_valid_next = 1; 100 end 101 end 102 MANY: begin 103 if (one_next) begin 104 state_next = ONE; 105 end else if (full_next) begin 106 state_next = FULL; 107 wr_ready_next = 0; 108 end 109 end 110 FULL: begin 111 if (do_rd) begin 112 state_next = MANY; 113 wr_ready_next = 1; 114 end 115 end 116 endcase 117 end 118 119 always_ff @(posedge clk) begin 120 state <= state_next; 121 rd_ptr <= rd_ptr_next; 122 wr_ptr <= wr_ptr_next; 123 wr_ready <= wr_ready_next; 124 rd_valid <= rd_valid_next; 125 `ifdef SYNC_FIFO_WITH_BYPASS 126 bypass <= use_bypass_next ? wr_data : bypass; 127 use_bypass <= use_bypass_next; 128 `endif 129 end 130 131 // fifo storage 132 reg [WIDTH-1:0]memory[0:2**DEPTH-1]; 133 reg [WIDTH-1:0]data; 134 135 always_ff @(posedge clk) begin 136 if (wr_valid & wr_ready) 137 memory[wr_ptr[DEPTH-1:0]] <= wr_data; 138 139 data <= memory[rd_ptr_next[DEPTH-1:0]]; 140 end 141 142 `ifdef SYNC_FIFO_WITH_BYPASS 143 assign rd_data = use_bypass ? bypass : data; 144 `else 145 assign rd_data = data; 146 `endif 147 148 endmodule 149