From 5723ec1a34181f1cfef9b8e870ab2e9a0362487c Mon Sep 17 00:00:00 2001 From: mindchasers Date: Wed, 1 May 2019 18:16:45 -0400 Subject: initial commit, all basic functions work on Darsena V02 --- source/sync4_fifo.v | 206 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 source/sync4_fifo.v (limited to 'source/sync4_fifo.v') 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 -- cgit v1.2.3-8-gadcc