summaryrefslogtreecommitdiffhomepage
path: root/src/half_fifo.v
diff options
context:
space:
mode:
authorPrivate Island Networks <opensource@privateisland.tech>2025-09-01 12:37:36 -0400
committerPrivate Island Networks <opensource@privateisland.tech>2025-09-01 12:37:36 -0400
commit8363d90c7e3fe116d3a4ce12c3037d875f133a47 (patch)
tree3a8f1aa587dbb38f64bc40a50fd025a6cde9ec5b /src/half_fifo.v
parentc8b273c80abe98e53828f46079a187975938a56a (diff)
cont: update controller complex for Betsy: see privateisland.tech/dev/pi-controllerHEADmaster
Diffstat (limited to 'src/half_fifo.v')
-rw-r--r--src/half_fifo.v263
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

Highly Recommended Verilog Books