/* * 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