diff options
Diffstat (limited to 'src/half_fifo.v')
| -rw-r--r-- | src/half_fifo.v | 263 |
1 files changed, 144 insertions, 119 deletions
diff --git a/src/half_fifo.v b/src/half_fifo.v index e18f543..c85f6ac 100644 --- a/src/half_fifo.v +++ b/src/half_fifo.v @@ -1,7 +1,8 @@ /* * half_fifo.v * - * Copyright (C) 2018, 2019 Mind Chasers Inc. + * Copyright (C) 2024-2025 Private Island Networks Inc. + * Copyright (C) 2018-2022 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. @@ -15,180 +16,204 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * function: micro / FIFO interface + * Internal Controller / FIFO interface for accessing Ethernet Switch + * * */ -`timescale 1ns /10ps - -module half_fifo #(parameter DATA_WIDTH = 9, DPRAM_DEPTH=11 ) +module half_fifo #(parameter DATA_WIDTH = 9, DPRAM_DEPTH=11) ( input rstn, - input uc_clk, input fifo_clk, + input uc_clk, + + // controller interrupt support + output reg rx_fifo_int, // signals that a complete packet has arrived + input rx_fifo_int_acked, - // UC interrupt support - output reg fifo_we_int, - - // tx_mode - input tx_mode, - - // UC side: common DPRAM signals for RX and TX + // controller interface input [DPRAM_DEPTH-1:0] dpram_addr, - input [DATA_WIDTH-1:0] dpram_din, - output reg [DATA_WIDTH-1:0] dpram_dout, + input [DPRAM_DEPTH-1:0] dpram_din, // size it to include 11-bit pointers + output reg [DPRAM_DEPTH-1:0] dpram_dout, // size it to include 11-bit pointers input dpram_we, input dpram_oe, - // UC select signals input dpram_ptrs_sel, - input dpram_rx_sel, input dpram_tx_sel, + input dpram_rx_sel, - // FIFO TX (input) + // FIFO RX (switch -> hfifo -> controller) input fifo_we, input [DATA_WIDTH-1:0] fifo_d_in, - // FIFO RX (output) + // FIFO TX (controller -> hfifo -> switch) input fifo_re, + output reg [10:0] tx_byte_cnt, output [DATA_WIDTH-1:0] fifo_d_out, - - // FIFO flags - output rx_empty, // dpram 0 (reader) - output tx_full + output tx_empty ); +`define INCLUDED +`include "cont_params.v" +`undef INCLUDED + /* * Pointers for accessing memory. - * UC writes RX and reads TX - * Switch writes (via FIFO I/F) TX and reads RX + * UC writes TX and reads RX + * Switch writes (via FIFO I/F) RX and reads TX + * This is the opposite of the system view */ -reg [DPRAM_DEPTH-1:0] rx_wr_ptr; -reg [DPRAM_DEPTH-1:0] rx_rd_ptr; +reg [DPRAM_DEPTH-1:0] rx_wr_ptr, rx_wr_ptr_latched; -reg [DPRAM_DEPTH-1:0] tx_wr_ptr; +reg [DPRAM_DEPTH-1:0] tx_wr_ptr, tx_wr_ptr_latched; reg [DPRAM_DEPTH-1:0] tx_rd_ptr; +reg tx_wr_ptr_written, tx_wr_ptr_written_m1, tx_wr_ptr_written_m2; + reg fifo_we_m1; reg reset_ptrs; -wire [DATA_WIDTH-1:0] dpram_rx_dout, dpram_tx_dout; +wire [DATA_WIDTH-1:0] dpram_tx_dout, dpram_rx_dout; -/* read data mux */ +/* read data mux, refer to addr params above */ always @(*) - casez({ dpram_rx_sel, dpram_tx_sel, dpram_ptrs_sel, dpram_addr[2:0] } ) - 6'b001000: dpram_dout = rx_wr_ptr; - 6'b001001: dpram_dout = rx_rd_ptr; - 6'b001010: dpram_dout = tx_wr_ptr; - 6'b001011: dpram_dout = tx_rd_ptr; - 6'b001100: dpram_dout = reset_ptrs; - 6'b010???: dpram_dout = dpram_tx_dout; - 6'b100???: dpram_dout = dpram_rx_dout; - default: dpram_dout = dpram_tx_dout; + casez({ dpram_tx_sel, dpram_rx_sel, dpram_ptrs_sel, dpram_addr[2:0] }) + 6'b001000: dpram_dout = tx_wr_ptr; + 6'b001001: dpram_dout = tx_rd_ptr; // meta stable + 6'b001010: dpram_dout = rx_wr_ptr_latched; + 6'b001011: dpram_dout = 11'd0; + 6'b001100: dpram_dout = {10'd0, reset_ptrs}; + 6'b010???: dpram_dout = {2'b00, dpram_rx_dout}; + 6'b100???: dpram_dout = {2'b00, dpram_tx_dout}; + default: dpram_dout = {2'b00, dpram_rx_dout}; endcase always @(posedge uc_clk, negedge rstn) - if ( !rstn ) + if (!rstn) reset_ptrs <= 1'b0; - else if ( dpram_ptrs_sel && dpram_we && dpram_addr[2:0] == 3'h4 ) + else if (dpram_ptrs_sel && dpram_we && dpram_addr[2:0] == HF_RESET_PTRS) reset_ptrs <= dpram_din[0]; - -/* RX wr ptr (UC writes) */ + always @(posedge uc_clk, negedge rstn) - if ( !rstn ) - rx_wr_ptr <= 'h0; - else if ( reset_ptrs ) - rx_wr_ptr <= 'h0; - else if ( dpram_ptrs_sel && dpram_we && dpram_addr[2:0] == 3'h0 ) - rx_wr_ptr <= dpram_din; - -/* TX rd ptr (uP reads) */ + if (!rstn) + tx_byte_cnt <= 11'd0; + else if (dpram_ptrs_sel && dpram_we && dpram_addr[2:0] == HF_TX_BYTE_CNT_ADDR) + tx_byte_cnt <= dpram_din; + +/* TX wr ptr (UC writes) */ always @(posedge uc_clk, negedge rstn) - if ( !rstn ) - tx_rd_ptr <= 'h0; - else if ( reset_ptrs ) - tx_rd_ptr <= 'h0; - else if ( dpram_ptrs_sel && dpram_we && dpram_addr[2:0] == 3'h3 ) - tx_rd_ptr <= dpram_din; + if (!rstn) begin + tx_wr_ptr <= 'h0; + tx_wr_ptr_written <= 1'b0; + end + else if (reset_ptrs) begin + tx_wr_ptr <= 'h0; + tx_wr_ptr_written <= 1'b1; + end + else if (dpram_ptrs_sel && dpram_we && dpram_addr[2:0] == HF_TX_WR_PTR_ADDR) begin + tx_wr_ptr <= dpram_din; + tx_wr_ptr_written <= 1'b1; + end + else + tx_wr_ptr_written <= 1'b0; -/* RX rd ptr (switch reads via FIFO), auto increment */ always @(posedge fifo_clk, negedge rstn) - if( !rstn ) - rx_rd_ptr <= 'd0; - else if ( reset_ptrs ) - rx_rd_ptr <= 'd0; - else if ( fifo_re && !rx_empty ) // advance the pointer if FIFO isn't empty - rx_rd_ptr <= rx_rd_ptr + 1; - - /* TX wr ptr (switch writes via FIFO) */ + if (!rstn) begin + tx_wr_ptr_written_m1 <= 1'b0; + tx_wr_ptr_written_m2 <= 1'b0; + end + else begin + tx_wr_ptr_written_m1 <= tx_wr_ptr_written; + tx_wr_ptr_written_m2 <= tx_wr_ptr_written_m1; + end + + always @(posedge fifo_clk, negedge rstn) - if( !rstn ) - tx_wr_ptr <= 'd0; - else if ( reset_ptrs ) - tx_wr_ptr <= 'd0; - else if ( fifo_we ) - tx_wr_ptr <= tx_wr_ptr + 1; + if(!rstn) + tx_wr_ptr_latched <= 8'h00; + else if (tx_wr_ptr_written_m2) + tx_wr_ptr_latched <= tx_wr_ptr; - -assign rx_empty = (rx_rd_ptr == rx_wr_ptr) ? 1'b1 : 1'b0; -assign tx_full = (tx_rd_ptr != tx_wr_ptr) ? 1'b1 : 1'b0; +/* TX rd ptr (switch reads via FIFO), auto increment */ +always @(posedge fifo_clk, negedge rstn) + if(!rstn) + tx_rd_ptr <= 11'd0; + else if (reset_ptrs) + tx_rd_ptr <= 11'd0; + else if (fifo_re && !tx_empty) // advance the pointer if FIFO isn't empty + tx_rd_ptr <= tx_rd_ptr + 1'b1; + +/* RX wr ptr (switch writes via FIFO) */ +always @(posedge fifo_clk, negedge rstn) + if(!rstn) + rx_wr_ptr <= 11'd0; + else if (reset_ptrs) + rx_wr_ptr <= 11'd0; + else if (fifo_we) + rx_wr_ptr <= rx_wr_ptr + 1'b1; +assign tx_empty = (tx_rd_ptr == tx_wr_ptr_latched); - -/* Assert interrupt whenever fifo_we is negated ( writing is done ) */ +/* Assert interrupt whenever fifo_we is negated (writing is done) */ always @(posedge fifo_clk, negedge rstn) - if ( !rstn ) + if (!rstn) fifo_we_m1 <= 1'b0; else fifo_we_m1 <= fifo_we; - +// Metastability note: rx_wr_ptr_latched should be read one or more clock cycles after rx_fifo_int asserts always @(posedge fifo_clk, negedge rstn) - if ( !rstn ) - fifo_we_int <= 1'b0; - else if ( !fifo_we & fifo_we_m1 ) - fifo_we_int <= 1'b1; - else - fifo_we_int <= 1'b0; + if (!rstn) begin + rx_fifo_int <= 1'b0; + rx_wr_ptr_latched <= 11'd0; + end + else if (!fifo_we & fifo_we_m1) begin // end of write + rx_fifo_int <= 1'b1; + rx_wr_ptr_latched <= rx_wr_ptr; + end + else if (rx_fifo_int_acked) // clear interrupt + rx_fifo_int <= 1'b0; - -/* micro uses A side, FIFO uses B side */ -dpram dpram_rx( - .rstn( rstn ), - .a_clk( uc_clk ), - .a_clk_e( dpram_rx_sel ), - .a_we( dpram_we ), - .a_oe( 1'b1 ), - .a_addr( { 2'b00, dpram_addr } ), - .a_din( dpram_din ), - .a_dout( dpram_rx_dout ), +/* controller uses A side, FIFO uses B side + * controller writes TX path and reads RX path */ +// 2K DPRAM +dpram_inf dpram_tx( + .rstn(rstn), + .a_clk(uc_clk), + .a_clk_e(dpram_tx_sel), + .a_we(dpram_we), + .a_oe(1'b1), + .a_addr(dpram_addr), + .a_din(dpram_din[8:0]), + .a_dout(dpram_tx_dout), // port B - .b_clk( fifo_clk ), - .b_clk_e( 1'b1 ), - .b_we( 1'b0 ), - .b_oe( fifo_re ), - .b_addr( { 2'b00, rx_rd_ptr } ), - .b_din( 9'h0 ), - .b_dout( fifo_d_out ) + .b_clk(fifo_clk), + .b_clk_e(1'b1), + .b_we(1'b0), + .b_oe(fifo_re), + .b_addr(tx_rd_ptr), + .b_din(9'h0), + .b_dout(fifo_d_out) ); -dpram dpram_tx( - .rstn( rstn ), - .a_clk( uc_clk ), - .a_clk_e( dpram_tx_sel ), - .a_we( dpram_we ), - .a_oe( 1'b1 ), - .a_addr( { 2'b00, dpram_addr } ), - .a_din( dpram_din ), - .a_dout( dpram_tx_dout ), +// 2K DPRAM +dpram_inf dpram_rx( + .rstn(rstn), + .a_clk(uc_clk), + .a_clk_e(dpram_rx_sel), + .a_we(1'b0), + .a_oe(1'b1), + .a_addr(dpram_addr), + .a_din(9'h000), + .a_dout(dpram_rx_dout), // port B - .b_clk( fifo_clk ), - .b_clk_e( 1'b1 ), - .b_we( fifo_we ), - .b_oe( 1'b0 ), - .b_addr( { 2'b00, tx_wr_ptr } ), - .b_din( fifo_d_in ), - .b_dout( ) + .b_clk(fifo_clk), + .b_clk_e(1'b1), + .b_we(fifo_we), + .b_oe(1'b0), + .b_addr(rx_wr_ptr), + .b_din(fifo_d_in), + .b_dout() ); endmodule |



