summaryrefslogtreecommitdiffhomepage
path: root/src/half_fifo.v
diff options
context:
space:
mode:
Diffstat (limited to 'src/half_fifo.v')
-rw-r--r--src/half_fifo.v219
1 files changed, 219 insertions, 0 deletions
diff --git a/src/half_fifo.v b/src/half_fifo.v
new file mode 100644
index 0000000..c85f6ac
--- /dev/null
+++ b/src/half_fifo.v
@@ -0,0 +1,219 @@
+/*
+ * half_fifo.v
+ *
+ * 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.
+ * 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.
+ *
+ * Internal Controller / FIFO interface for accessing Ethernet Switch
+ *
+ *
+ */
+
+module half_fifo #(parameter DATA_WIDTH = 9, DPRAM_DEPTH=11)
+(
+ input rstn,
+ 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,
+
+ // controller interface
+ input [DPRAM_DEPTH-1:0] dpram_addr,
+ 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,
+ input dpram_ptrs_sel,
+ input dpram_tx_sel,
+ input dpram_rx_sel,
+
+ // FIFO RX (switch -> hfifo -> controller)
+ input fifo_we,
+ input [DATA_WIDTH-1:0] fifo_d_in,
+
+ // FIFO TX (controller -> hfifo -> switch)
+ input fifo_re,
+ output reg [10:0] tx_byte_cnt,
+ output [DATA_WIDTH-1:0] fifo_d_out,
+ output tx_empty
+
+);
+
+`define INCLUDED
+`include "cont_params.v"
+`undef INCLUDED
+
+/*
+ * Pointers for accessing memory.
+ * 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, rx_wr_ptr_latched;
+
+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_tx_dout, dpram_rx_dout;
+
+/* read data mux, refer to addr params above */
+always @(*)
+ 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)
+ reset_ptrs <= 1'b0;
+ else if (dpram_ptrs_sel && dpram_we && dpram_addr[2:0] == HF_RESET_PTRS)
+ reset_ptrs <= dpram_din[0];
+
+always @(posedge uc_clk, negedge rstn)
+ 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) 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;
+
+always @(posedge fifo_clk, negedge rstn)
+ 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_latched <= 8'h00;
+ else if (tx_wr_ptr_written_m2)
+ tx_wr_ptr_latched <= tx_wr_ptr;
+
+/* 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) */
+always @(posedge fifo_clk, negedge 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) 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;
+
+/* 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(tx_rd_ptr),
+ .b_din(9'h0),
+ .b_dout(fifo_d_out)
+);
+
+// 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(rx_wr_ptr),
+ .b_din(fifo_d_in),
+ .b_dout()
+);
+
+endmodule

Highly Recommended Verilog Books