diff options
Diffstat (limited to 'source/half_fifo.v')
-rw-r--r-- | source/half_fifo.v | 194 |
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 |