summaryrefslogtreecommitdiffhomepage
path: root/source/sync4_fifo.v
diff options
context:
space:
mode:
Diffstat (limited to 'source/sync4_fifo.v')
-rw-r--r--source/sync4_fifo.v206
1 files changed, 206 insertions, 0 deletions
diff --git a/source/sync4_fifo.v b/source/sync4_fifo.v
new file mode 100644
index 0000000..c7c1fb6
--- /dev/null
+++ b/source/sync4_fifo.v
@@ -0,0 +1,206 @@
+/*
+ * sync4_fifo.v
+ *
+ * Copyright (C) 2018, 2019 Mind Chasers Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * function: FIFO / data store between RX and TX for each path
+ *
+ */
+
+`timescale 1ns /10ps
+
+module sync4_fifo #(parameter FIFO_PTR = 13,
+ FIFO_WIDTH = 9,
+ FIFO_DEPTH = 8192 )
+(
+ input rstn,
+ input clk,
+
+ // input
+ input we,
+ input [FIFO_WIDTH-1:0] d_in,
+
+ // output
+ input re,
+ output reg [FIFO_WIDTH-1:0] d_out,
+ output empty,
+ output almost_full,
+
+ // fifo_control
+ input reset_ptrs,
+
+ // debug
+ output active
+
+);
+
+`include "ethernet_params.v"
+
+reg [FIFO_PTR-1:0] wr_ptr;
+reg [FIFO_PTR-1:0] rd_ptr;
+reg [FIFO_PTR-1:0] wr_bytes_available; // use for size calculation below
+
+wire [FIFO_WIDTH-1:0] d_out_0, d_out_1, d_out_2, d_out_3;
+
+wire dpram0_a_clk_e, dpram1_a_clk_e, dpram2_a_clk_e, dpram3_a_clk_e;
+wire dpram0_b_clk_e, dpram1_b_clk_e, dpram2_b_clk_e, dpram3_b_clk_e;
+reg dpram0_b_clk_e_m1, dpram1_b_clk_e_m1, dpram2_b_clk_e_m1, dpram3_b_clk_e_m1;
+
+
+always @(posedge clk, negedge rstn)
+ if( !rstn ) begin
+ dpram0_b_clk_e_m1 <= 1'b0;
+ dpram1_b_clk_e_m1 <= 1'b0;
+ dpram2_b_clk_e_m1 <= 1'b0;
+ dpram3_b_clk_e_m1 <= 1'b0;
+ end
+ else begin
+ dpram0_b_clk_e_m1 <= dpram0_b_clk_e;
+ dpram1_b_clk_e_m1 <= dpram1_b_clk_e;
+ dpram2_b_clk_e_m1 <= dpram2_b_clk_e;
+ dpram3_b_clk_e_m1 <= dpram3_b_clk_e;
+ end
+
+always @(posedge clk, negedge rstn)
+ if( !rstn )
+ wr_ptr <= 'd0;
+ else if ( reset_ptrs )
+ wr_ptr <= 'd0;
+ else if ( we )
+ wr_ptr <= wr_ptr + 1;
+
+/*
+ * rd_ptr
+ * use empty flag to make sure rd_ptr doesn't advance when empty ( error condition )
+ */
+always @(posedge clk, negedge rstn)
+ if( !rstn )
+ rd_ptr <= 'd0;
+ else if ( reset_ptrs )
+ rd_ptr <= 'd0;
+ else if ( re && !empty )
+ rd_ptr <= rd_ptr + 1;
+
+assign empty = ( rd_ptr == wr_ptr ) ? 1'b1 : 1'b0;
+assign almost_full = wr_bytes_available < MTU ? 1'b1 : 1'b0;
+
+always @(posedge clk, negedge rstn)
+ if( !rstn )
+ wr_bytes_available <= FIFO_DEPTH-1;
+ else if ( wr_ptr >= rd_ptr )
+ wr_bytes_available <= FIFO_DEPTH-1 - (wr_ptr - rd_ptr);
+ else
+ wr_bytes_available <= rd_ptr - wr_ptr;
+
+assign dpram0_a_clk_e = wr_ptr[FIFO_PTR-1:FIFO_PTR-2] == 2'b00 ? 1'b1 : 1'b0;
+assign dpram1_a_clk_e = wr_ptr[FIFO_PTR-1:FIFO_PTR-2] == 2'b01 ? 1'b1 : 1'b0;
+assign dpram2_a_clk_e = wr_ptr[FIFO_PTR-1:FIFO_PTR-2] == 2'b10 ? 1'b1 : 1'b0;
+assign dpram3_a_clk_e = wr_ptr[FIFO_PTR-1:FIFO_PTR-2] == 2'b11 ? 1'b1 : 1'b0;
+
+assign dpram0_b_clk_e = rd_ptr[FIFO_PTR-1:FIFO_PTR-2] == 2'b00 ? 1'b1 : 1'b0;
+assign dpram1_b_clk_e = rd_ptr[FIFO_PTR-1:FIFO_PTR-2] == 2'b01 ? 1'b1 : 1'b0;
+assign dpram2_b_clk_e = rd_ptr[FIFO_PTR-1:FIFO_PTR-2] == 2'b10 ? 1'b1 : 1'b0;
+assign dpram3_b_clk_e = rd_ptr[FIFO_PTR-1:FIFO_PTR-2] == 2'b11 ? 1'b1 : 1'b0;
+
+// we have to delay the mux one bit for when the DPRAM switches. Otherwise, we read from the wrong DPRAM for one time slot
+always @(*)
+ if (dpram0_b_clk_e_m1)
+ d_out = d_out_0;
+ else if (dpram1_b_clk_e_m1)
+ d_out = d_out_1;
+ else if (dpram2_b_clk_e_m1)
+ d_out = d_out_2;
+ else if (dpram3_b_clk_e_m1)
+ d_out = d_out_3;
+
+assign active = ~empty;
+
+dpram dpram_fifo0(
+ .rstn( rstn ),
+ .a_clk( clk ),
+ .a_clk_e( dpram0_a_clk_e ),
+ .a_we( we ),
+ .a_oe( 1'b0 ),
+ .a_addr( wr_ptr[10:0] ),
+ .a_din( d_in ),
+ .a_dout( ),
+ // port B
+ .b_clk( clk ),
+ .b_clk_e( dpram0_b_clk_e ),
+ .b_we( 1'b0 ),
+ .b_oe( 1'b1 ),
+ .b_addr( rd_ptr[10:0] ),
+ .b_din( 9'h0 ),
+ .b_dout( d_out_0 )
+);
+
+dpram dpram_fifo1(
+ .rstn( rstn ),
+ .a_clk( clk ),
+ .a_clk_e( dpram1_a_clk_e ),
+ .a_we( we ),
+ .a_oe( 1'b0 ),
+ .a_addr( wr_ptr[10:0] ),
+ .a_din( d_in ),
+ .a_dout( ),
+ // port B
+ .b_clk( clk ),
+ .b_clk_e( dpram1_b_clk_e ),
+ .b_we( 1'b0 ),
+ .b_oe( 1'b1 ),
+ .b_addr( rd_ptr[10:0] ),
+ .b_din( 9'h0 ),
+ .b_dout( d_out_1 )
+ );
+
+dpram dpram_fifo2(
+ .rstn( rstn ),
+ .a_clk( clk ),
+ .a_clk_e( dpram2_a_clk_e ),
+ .a_we( we ),
+ .a_oe( 1'b0 ),
+ .a_addr( wr_ptr[10:0] ),
+ .a_din( d_in ),
+ .a_dout( ),
+ // port B
+ .b_clk( clk ),
+ .b_clk_e( dpram2_b_clk_e ),
+ .b_we( 1'b0 ),
+ .b_oe( 1'b1 ),
+ .b_addr( rd_ptr[10:0] ),
+ .b_din( 9'h0 ),
+ .b_dout( d_out_2 )
+ );
+
+dpram dpram_fifo3(
+ .rstn( rstn ),
+ .a_clk( clk ),
+ .a_clk_e( dpram3_a_clk_e ),
+ .a_we( we ),
+ .a_oe( 1'b0 ),
+ .a_addr( wr_ptr[10:0] ),
+ .a_din( d_in ),
+ .a_dout( ),
+ // port B
+ .b_clk( clk ),
+ .b_clk_e( dpram3_b_clk_e ),
+ .b_we( 1'b0 ),
+ .b_oe( 1'b1 ),
+ .b_addr( rd_ptr[10:0] ),
+ .b_din( 9'h0 ),
+ .b_dout( d_out_3 )
+ );
+
+endmodule