/* * 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