gateware

A collection of little open source FPGA hobby projects
git clone http://frotz.net/git/gateware.git
Log | Files | Refs | README

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