summaryrefslogtreecommitdiffhomepage
path: root/source/half_fifo.v
diff options
context:
space:
mode:
Diffstat (limited to 'source/half_fifo.v')
-rw-r--r--source/half_fifo.v194
1 files changed, 194 insertions, 0 deletions
diff --git a/source/half_fifo.v b/source/half_fifo.v
new file mode 100644
index 0000000..e18f543
--- /dev/null
+++ b/source/half_fifo.v
@@ -0,0 +1,194 @@
+/*
+ * half_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: micro / FIFO interface
+ *
+ */
+
+`timescale 1ns /10ps
+
+module half_fifo #(parameter DATA_WIDTH = 9, DPRAM_DEPTH=11 )
+(
+ input rstn,
+ input uc_clk,
+ input fifo_clk,
+
+ // UC interrupt support
+ output reg fifo_we_int,
+
+ // tx_mode
+ input tx_mode,
+
+ // UC side: common DPRAM signals for RX and TX
+ input [DPRAM_DEPTH-1:0] dpram_addr,
+ input [DATA_WIDTH-1:0] dpram_din,
+ output reg [DATA_WIDTH-1:0] dpram_dout,
+ input dpram_we,
+ input dpram_oe,
+ // UC select signals
+ input dpram_ptrs_sel,
+ input dpram_rx_sel,
+ input dpram_tx_sel,
+
+ // FIFO TX (input)
+ input fifo_we,
+ input [DATA_WIDTH-1:0] fifo_d_in,
+
+ // FIFO RX (output)
+ input fifo_re,
+ output [DATA_WIDTH-1:0] fifo_d_out,
+
+ // FIFO flags
+ output rx_empty, // dpram 0 (reader)
+ output tx_full
+
+);
+
+/*
+ * Pointers for accessing memory.
+ * UC writes RX and reads TX
+ * Switch writes (via FIFO I/F) TX and reads RX
+ */
+reg [DPRAM_DEPTH-1:0] rx_wr_ptr;
+reg [DPRAM_DEPTH-1:0] rx_rd_ptr;
+
+reg [DPRAM_DEPTH-1:0] tx_wr_ptr;
+reg [DPRAM_DEPTH-1:0] tx_rd_ptr;
+
+reg fifo_we_m1;
+
+reg reset_ptrs;
+wire [DATA_WIDTH-1:0] dpram_rx_dout, dpram_tx_dout;
+
+/* read data mux */
+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;
+ endcase
+
+always @(posedge uc_clk, negedge rstn)
+ if ( !rstn )
+ reset_ptrs <= 1'b0;
+ else if ( dpram_ptrs_sel && dpram_we && dpram_addr[2:0] == 3'h4 )
+ 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) */
+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;
+
+/* 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) */
+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;
+
+
+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;
+
+
+
+/* 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;
+
+
+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;
+
+
+/* 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 ),
+ // 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 )
+);
+
+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 ),
+ // 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( )
+);
+
+endmodule

Highly Recommended Verilog Books