From 0595990c8d2b86b67e4facbfa3d3941c528de5c5 Mon Sep 17 00:00:00 2001 From: David Michaeli Date: Tue, 30 May 2023 14:33:08 +0300 Subject: [PATCH] Tx side integration firmware --- firmware/complex_fifo.v | 59 +-- firmware/dual_clock_fifo.v | 122 ------ firmware/io.pcf | 98 ++--- firmware/io_ctrl.v | 4 +- firmware/lvds_rx.v | 158 ++++---- firmware/lvds_tx.v | 79 ++-- firmware/smi_ctrl.v | 211 +++++++--- firmware/spi_if.v | 184 +++++---- firmware/spi_slave.v | 58 +-- firmware/top.v | 794 ++++++++++++++++++++++--------------- 10 files changed, 945 insertions(+), 822 deletions(-) delete mode 100644 firmware/dual_clock_fifo.v diff --git a/firmware/complex_fifo.v b/firmware/complex_fifo.v index 75f0d6f..d978d53 100644 --- a/firmware/complex_fifo.v +++ b/firmware/complex_fifo.v @@ -2,23 +2,23 @@ module complex_fifo #( parameter ADDR_WIDTH = 10, parameter DATA_WIDTH = 16 ) - ( - input wire wr_rst_b_i, - input wire wr_clk_i, - input wire wr_en_i, - input wire [2*DATA_WIDTH-1:0] wr_data_i, +( + input wire wr_rst_b_i, + input wire wr_clk_i, + input wire wr_en_i, + input wire [2*DATA_WIDTH-1:0] wr_data_i, - input wire rd_rst_b_i, - input wire rd_clk_i, - input wire rd_en_i, - output reg [2*DATA_WIDTH-1:0] rd_data_o, + input wire rd_rst_b_i, + input wire rd_clk_i, + input wire rd_en_i, + output reg [2*DATA_WIDTH-1:0] rd_data_o, - output reg full_o, - output reg empty_o, + output reg full_o, + output reg empty_o, - input wire debug_pull, - input wire debug_push, - ); + input wire debug_pull, + input wire debug_push, +); reg [ADDR_WIDTH-1:0] wr_addr; reg [ADDR_WIDTH-1:0] wr_addr_gray; @@ -32,11 +32,10 @@ module complex_fifo #( reg [2*DATA_WIDTH-1:0] debug_buffer; function [ADDR_WIDTH-1:0] gray_conv; - input [ADDR_WIDTH-1:0] in; - begin - gray_conv = {in[ADDR_WIDTH-1], - in[ADDR_WIDTH-2:0] ^ in[ADDR_WIDTH-1:1]}; - end + input [ADDR_WIDTH-1:0] in; + begin + gray_conv = {in[ADDR_WIDTH-1], in[ADDR_WIDTH-2:0] ^ in[ADDR_WIDTH-1:1]}; + end endfunction always @(posedge wr_clk_i) begin @@ -55,13 +54,15 @@ module complex_fifo #( rd_addr_gray_wr_r <= rd_addr_gray_wr; end - always @(posedge wr_clk_i) - if (wr_rst_b_i == 1'b0) + always @(posedge wr_clk_i) begin + if (wr_rst_b_i == 1'b0) begin full_o <= 0; - else if (wr_en_i) + end else if (wr_en_i) begin full_o <= gray_conv(wr_addr + 2) == rd_addr_gray_wr_r; - else + end else begin full_o <= full_o & (gray_conv(wr_addr + 1'b1) == rd_addr_gray_wr_r); + end + end always @(posedge rd_clk_i) begin if (rd_rst_b_i == 1'b0) begin @@ -80,15 +81,15 @@ module complex_fifo #( wr_addr_gray_rd_r <= wr_addr_gray_rd; end - always @(posedge rd_clk_i) - if (rd_rst_b_i == 1'b0) + always @(posedge rd_clk_i) begin + if (rd_rst_b_i == 1'b0) begin empty_o <= 1'b1; - else if (rd_en_i) + end else if (rd_en_i) begin empty_o <= gray_conv(rd_addr + 1) == wr_addr_gray_rd_r; - else + end else begin empty_o <= empty_o & (gray_conv(rd_addr) == wr_addr_gray_rd_r); - - //reg [DATA_WIDTH-1:0] mem[(1< - * All rights reserved. - * - * Based on vga_fifo_dc.v in Richard Herveille's VGA/LCD core - * Copyright (C) 2001 Richard Herveille - * - * Redistribution and use in source and non-source forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in non-source form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS WORK IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * WORK, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -module dual_clock_fifo #( - parameter ADDR_WIDTH = 8, - parameter DATA_WIDTH = 16 -) -( - input wire wr_rst_i, - input wire wr_clk_i, - input wire wr_en_i, - input wire [DATA_WIDTH-1:0] wr_data_i, - - input wire rd_rst_i, - input wire rd_clk_i, - input wire rd_en_i, - output reg [DATA_WIDTH-1:0] rd_data_o, - - output reg full_o, - output reg empty_o -); - -reg [ADDR_WIDTH-1:0] wr_addr; -reg [ADDR_WIDTH-1:0] wr_addr_gray; -reg [ADDR_WIDTH-1:0] wr_addr_gray_rd; -reg [ADDR_WIDTH-1:0] wr_addr_gray_rd_r; -reg [ADDR_WIDTH-1:0] rd_addr; -reg [ADDR_WIDTH-1:0] rd_addr_gray; -reg [ADDR_WIDTH-1:0] rd_addr_gray_wr; -reg [ADDR_WIDTH-1:0] rd_addr_gray_wr_r; - -function [ADDR_WIDTH-1:0] gray_conv; -input [ADDR_WIDTH-1:0] in; -begin - gray_conv = {in[ADDR_WIDTH-1], - in[ADDR_WIDTH-2:0] ^ in[ADDR_WIDTH-1:1]}; -end -endfunction - -always @(posedge wr_clk_i) begin - if (wr_rst_i) begin - wr_addr <= 0; - wr_addr_gray <= 0; - end else if (wr_en_i) begin - wr_addr <= wr_addr + 1'b1; - wr_addr_gray <= gray_conv(wr_addr + 1'b1); - end -end - -// synchronize read address to write clock domain -always @(posedge wr_clk_i) begin - rd_addr_gray_wr <= rd_addr_gray; - rd_addr_gray_wr_r <= rd_addr_gray_wr; -end - -always @(posedge wr_clk_i) - if (wr_rst_i) - full_o <= 0; - else if (wr_en_i) - full_o <= gray_conv(wr_addr + 2) == rd_addr_gray_wr_r; - else - full_o <= full_o & (gray_conv(wr_addr + 1'b1) == rd_addr_gray_wr_r); - -always @(posedge rd_clk_i) begin - if (rd_rst_i) begin - rd_addr <= 0; - rd_addr_gray <= 0; - end else if (rd_en_i) begin - rd_addr <= rd_addr + 1'b1; - rd_addr_gray <= gray_conv(rd_addr + 1'b1); - end -end - -// synchronize write address to read clock domain -always @(posedge rd_clk_i) begin - wr_addr_gray_rd <= wr_addr_gray; - wr_addr_gray_rd_r <= wr_addr_gray_rd; -end - -always @(posedge rd_clk_i) - if (rd_rst_i) - empty_o <= 1'b1; - else if (rd_en_i) - empty_o <= gray_conv(rd_addr + 1) == wr_addr_gray_rd_r; - else - empty_o <= empty_o & (gray_conv(rd_addr) == wr_addr_gray_rd_r); - -reg [DATA_WIDTH-1:0] mem[(1< FPGA - // direction, and the DATA bus is highZ (recessive mode). - // The signal a[2] selects the RX source (900 MHZ or 2.4GHz) - // The signal a[1] can be used in the future for other purposes - // - // Description | a[2] (SA3)| a[1] (SA2) | - // -------------|------------|---------------| - // | 0 | 0 | - // TX |------------| RPI => FPGA | - // | 1 | Data HighZ | - // -------------|------------|---------------| - // RX09 | 0 | 1 | - // -------------|------------| FPGA => RPI | - // RX24 | 1 | Data PushPull | - // -------------|------------|---------------| - input i_smi_a2, - input i_smi_a3, + // DIGITAL I/F + input [3:0] i_config, + input i_button, + inout [7:0] io_pmod, + output o_led0, + output o_led1, - input i_smi_soe_se, - input i_smi_swe_srw, - inout [7:0] io_smi_data, - output o_smi_write_req, - output o_smi_read_req, + // SMI Addressing description + // ========================== + // In CaribouLite, the SMI addresses are connected as follows: + // + // RPI PIN | FPGA TOP-LEVEL SIGNAL + // ------------------------------------------------------------------------ + // GPIO2_SA3 | i_smi_a[2] - RX09 / RX24 channel select + // GPIO3_SA2 | i_smi_a[1] - Tx SMI (0) / Rx SMI (1) select + // GPIO4_SA1 | i_smi_a[0] - used as a sys async reset (GBIN1) + // GPIO5_SA0 | Not connected to FPGA (MixerRst) + // + // In order to perform SMI data bus direction selection (highZ / PushPull) + // signal a[0] was chosen, while the '0' level (default) denotes RPI => FPGA + // direction, and the DATA bus is highZ (recessive mode). + // The signal a[2] selects the RX source (900 MHZ or 2.4GHz) + // The signal a[1] can be used in the future for other purposes + // + // Description | a[2] (SA3)| a[1] (SA2) | + // -------------|------------|---------------| + // | 0 | 0 | + // TX |------------| RPI => FPGA | + // | 1 | Data HighZ | + // -------------|------------|---------------| + // RX09 | 0 | 1 | + // -------------|------------| FPGA => RPI | + // RX24 | 1 | Data PushPull | + // -------------|------------|---------------| + input i_smi_a2, + input i_smi_a3, - // SPI - input i_mosi, - input i_sck, - input i_ss, - output o_miso - ); + input i_smi_soe_se, + input i_smi_swe_srw, + inout [7:0] io_smi_data, + output o_smi_write_req, + output o_smi_read_req, + + // SPI + input i_mosi, + input i_sck, + input i_ss, + output o_miso +); - //========================================================================= - // INNER SIGNALS - //========================================================================= - reg r_counter; - wire w_clock_spi; - wire w_clock_sys; - wire [4:0] w_ioc; - wire [7:0] w_rx_data; - reg [7:0] r_tx_data; - wire [3:0] w_cs; - wire w_fetch; - wire w_load; + //========================================================================= + // INNER SIGNALS + //========================================================================= + reg r_counter; + wire w_clock_spi; + wire w_clock_sys; + wire [4:0] w_ioc; + wire [7:0] w_rx_data; + reg [7:0] r_tx_data; + wire [3:0] w_cs; + wire w_fetch; + wire w_load; - wire [7:0] w_tx_data_sys; - wire [7:0] w_tx_data_io; - wire [7:0] w_tx_data_smi; + wire [7:0] w_tx_data_sys; + wire [7:0] w_tx_data_io; + wire [7:0] w_tx_data_smi; - //========================================================================= - // INSTANCES - //========================================================================= - spi_if spi_if_ins - ( - .i_rst_b (i_rst_b), - .i_sys_clk (w_clock_sys), - .o_ioc (w_ioc), - .o_data_in (w_rx_data), - .i_data_out (r_tx_data), - .o_cs (w_cs), - .o_fetch_cmd (w_fetch), - .o_load_cmd (w_load), + //========================================================================= + // INSTANCES + //========================================================================= + spi_if spi_if_ins ( + .i_rst_b(i_rst_b), + .i_sys_clk(w_clock_sys), + .o_ioc(w_ioc), + .o_data_in(w_rx_data), + .i_data_out(r_tx_data), + .o_cs(w_cs), + .o_fetch_cmd(w_fetch), + .o_load_cmd(w_load), - // SPI Interface - .i_spi_sck (i_sck), - .o_spi_miso (int_miso), - .i_spi_mosi (i_mosi), - .i_spi_cs_b (i_ss) - ); + // SPI Interface + .i_spi_sck (i_sck), + .o_spi_miso(int_miso), + .i_spi_mosi(i_mosi), + .i_spi_cs_b(i_ss) + ); - wire int_miso; - assign o_miso = (i_ss)?1'bZ:int_miso; + wire int_miso; + assign o_miso = (i_ss) ? 1'bZ : int_miso; - // SYSTEM CTRL - sys_ctrl sys_ctrl_ins - ( - .i_rst_b (i_rst_b), - .i_sys_clk (w_clock_sys), - .i_ioc (w_ioc), - .i_data_in (w_rx_data), - .o_data_out (w_tx_data_sys), - .i_cs (w_cs[0]), - .i_fetch_cmd (w_fetch), - .i_load_cmd (w_load), + // SYSTEM CTRL + sys_ctrl sys_ctrl_ins ( + .i_rst_b(i_rst_b), + .i_sys_clk(w_clock_sys), + .i_ioc(w_ioc), + .i_data_in(w_rx_data), + .o_data_out(w_tx_data_sys), + .i_cs(w_cs[0]), + .i_fetch_cmd(w_fetch), + .i_load_cmd(w_load), - .i_error_list (8'b00000000), - .o_debug_fifo_push (w_debug_fifo_push), - .o_debug_fifo_pull (w_debug_fifo_pull), - .o_debug_smi_test (w_debug_smi_test) - ); + .i_error_list(8'b00000000), + .o_debug_fifo_push(w_debug_fifo_push), + .o_debug_fifo_pull(w_debug_fifo_pull), + .o_debug_smi_test(w_debug_smi_test), + ); - wire w_debug_fifo_push; - wire w_debug_fifo_pull; - wire w_debug_smi_test; - - // IO CTRL - io_ctrl io_ctrl_ins - ( - .i_rst_b (i_rst_b), - .i_sys_clk (w_clock_sys), - .i_ioc (w_ioc), - .i_data_in (w_rx_data), - .o_data_out (w_tx_data_io), - .i_cs (w_cs[1]), - .i_fetch_cmd (w_fetch), - .i_load_cmd (w_load), + wire w_debug_fifo_push; + wire w_debug_fifo_pull; + wire w_debug_smi_test; - // Digital interfaces - .i_button (i_button), - .i_config (i_config), - .o_led0 (o_led0), - .o_led1 (o_led1), - .o_pmod (), + // IO CTRL + io_ctrl io_ctrl_ins ( + .i_rst_b(i_rst_b), + .i_sys_clk(w_clock_sys), + .i_ioc(w_ioc), + .i_data_in(w_rx_data), + .o_data_out(w_tx_data_io), + .i_cs(w_cs[1]), + .i_fetch_cmd(w_fetch), + .i_load_cmd(w_load), - // Analog interfaces - .o_mixer_fm (o_mixer_fm), - .o_rx_h_tx_l (o_rx_h_tx_l), - .o_rx_h_tx_l_b (o_rx_h_tx_l_b), - .o_tr_vc1 (o_tr_vc1), - .o_tr_vc1_b (o_tr_vc1_b), - .o_tr_vc2 (o_tr_vc2), - .o_shdn_tx_lna (o_shdn_tx_lna), - .o_shdn_rx_lna (o_shdn_rx_lna), - .o_mixer_en (o_mixer_en) - ); + // Digital interfaces + .i_button(i_button), + .i_config(i_config), + .o_led0 (o_led0), + .o_led1 (o_led1), + .o_pmod (), - //========================================================================= - // CLOCK AND DATA-FLOW - //========================================================================= - assign w_clock_sys = r_counter; + // Analog interfaces + .o_mixer_fm(o_mixer_fm), + .o_rx_h_tx_l(o_rx_h_tx_l), + .o_rx_h_tx_l_b(o_rx_h_tx_l_b), + .o_tr_vc1(o_tr_vc1), + .o_tr_vc1_b(o_tr_vc1_b), + .o_tr_vc2(o_tr_vc2), + .o_shdn_tx_lna(o_shdn_tx_lna), + .o_shdn_rx_lna(o_shdn_rx_lna), + .o_mixer_en(o_mixer_en) + ); - //========================================================================= - // CLOCK AND DATA-FLOW - //========================================================================= - always @(posedge i_glob_clock) - begin - if (i_rst_b == 1'b0) begin - r_counter <= 1'b0; - end else begin - r_counter <= !r_counter; + //========================================================================= + // CONBINATORIAL ASSIGNMENTS + //========================================================================= + assign w_clock_sys = r_counter; - case (w_cs) - 4'b0001: r_tx_data <= w_tx_data_sys; - 4'b0010: r_tx_data <= w_tx_data_io; - 4'b0100: r_tx_data <= w_tx_data_smi; - 4'b1000: r_tx_data <= 8'b10100101; // 0xA5: reserved - 4'b0000: r_tx_data <= 8'b00000000; // no module selected - endcase - end - end + //========================================================================= + // CLOCK AND DATA-FLOW + //========================================================================= + always @(posedge i_glob_clock) begin + if (i_rst_b == 1'b0) begin + r_counter <= 1'b0; + end else begin + r_counter <= !r_counter; - //========================================================================= - // I/O (SB_IO, SB_GB) DIFFERENTIAL LINES - //========================================================================= + case (w_cs) + 4'b0001: r_tx_data <= w_tx_data_sys; + 4'b0010: r_tx_data <= w_tx_data_io; + 4'b0100: r_tx_data <= w_tx_data_smi; + 4'b1000: r_tx_data <= 8'b10100101; // 0xA5: reserved + 4'b0000: r_tx_data <= 8'b00000000; // no module selected + endcase + end + end - // Differential clock signal (DDR) - wire lvds_clock; // The direct clock input - wire lvds_clock_buf; // The clock input after global buffer (improved fanout) + //========================================================================= + // I/O (SB_IO, SB_GB) DIFFERENTIAL LINES + //========================================================================= - SB_IO #(.PIN_TYPE(6'b000001), // Input only, direct mode - .IO_STANDARD("SB_LVDS_INPUT")) // LVDS input - iq_rx_clk ( .PACKAGE_PIN(i_iq_rx_clk_p), // Physical connection to 'i_iq_rx_clk_p' - .D_IN_0 ( lvds_clock )); // Wire out to 'lvds_clock' + //--------------------------------------------- + // LVDS CLOCK + //--------------------------------------------- + // Differential clock signal (DDR) + wire lvds_clock; // The direct clock input + wire lvds_clock_buf; // The clock input after global buffer (improved fanout) - assign lvds_clock_buf = lvds_clock; + SB_IO #( + .PIN_TYPE (6'b000001), // Input only, direct mode + .IO_STANDARD("SB_LVDS_INPUT") + ) // LVDS input + iq_rx_clk ( + .PACKAGE_PIN(i_iq_rx_clk_p), // Physical connection to 'i_iq_rx_clk_p' + .D_IN_0(lvds_clock) + ); // Wire out to 'lvds_clock' + + assign lvds_clock_buf = lvds_clock; + + //--------------------------------------------- + // LVDS RX - I/Q Data + //--------------------------------------------- + + // Differential 2.4GHz I/Q DDR signal + SB_IO #( + .PIN_TYPE (6'b000000), // Input only, DDR mode (sample on both pos edge and + // negedge of the input clock) + .IO_STANDARD("SB_LVDS_INPUT"), // LVDS standard + .NEG_TRIGGER(1'b0) + ) // The signal is not negated + iq_rx_24 ( + .PACKAGE_PIN(i_iq_rx_24_n), // Attention: this is the 'n' input, thus the actual values + // will need to be negated (PCB layout constraint) + .INPUT_CLK(lvds_clock_buf), // The I/O sampling clock with DDR + .D_IN_0(w_lvds_rx_24_d0), // the 0 deg data output + .D_IN_1(w_lvds_rx_24_d1) + ); // the 180 deg data output - // Differential 2.4GHz I/Q DDR signal - SB_IO #(.PIN_TYPE(6'b000000), // Input only, DDR mode (sample on both pos edge and - // negedge of the input clock) - .IO_STANDARD("SB_LVDS_INPUT"), // LVDS standard - .NEG_TRIGGER(1'b0)) // The signal is not negated - iq_rx_24 ( .PACKAGE_PIN(i_iq_rx_24_n), // Attention: this is the 'n' input, thus the actual values - // will need to be negated (PCB layout constraint) - .INPUT_CLK (lvds_clock_buf), // The I/O sampling clock with DDR - .D_IN_0 ( w_lvds_rx_24_d1 ), // the 0 deg data output - .D_IN_1 ( w_lvds_rx_24_d0 )); // the 180 deg data output + // Differential 0.9GHz I/Q DDR signal + SB_IO #( + .PIN_TYPE (6'b000000), // Input only, DDR mode (sample on both pos edge and + // negedge of the input clock) + .IO_STANDARD("SB_LVDS_INPUT"), // LVDS standard + .NEG_TRIGGER(1'b0) + ) // The signal is negated in hardware + iq_rx_09 ( + .PACKAGE_PIN(i_iq_rx_09_p), + .INPUT_CLK(lvds_clock_buf), // The I/O sampling clock with DDR + .D_IN_0(w_lvds_rx_09_d0), // the 0 deg data output + .D_IN_1(w_lvds_rx_09_d1) + ); // the 180 deg data output + + //---------------------------------------------- + // LVDS TX - I/Q Data + //---------------------------------------------- + + // Non-inverting, P-side of pair + SB_IO #( + .PIN_TYPE (6'b010000), // {PIN_OUTPUT_DDR, PIN_INPUT_REGISTER } + .IO_STANDARD("SB_LVCMOS"), + ) iq_tx_p ( + .PACKAGE_PIN(o_iq_tx_p), + .OUTPUT_CLK(lvds_clock_buf), + .D_OUT_0(~w_lvds_tx_d1), + .D_OUT_1(~w_lvds_tx_d0) + ); + + // Inverting, N-side of pair + SB_IO #( + .PIN_TYPE (6'b010000), // {PIN_OUTPUT_DDR, PIN_INPUT_REGISTER } + .IO_STANDARD("SB_LVCMOS"), + ) iq_tx_n ( + .PACKAGE_PIN(o_iq_tx_n), + .OUTPUT_CLK(lvds_clock_buf), + .D_OUT_0(w_lvds_tx_d1), + .D_OUT_1(w_lvds_tx_d0) + ); + + assign o_iq_tx_clk_p = lvds_clock_buf; + assign o_iq_tx_clk_n = ~lvds_clock_buf; + + //========================================================================= + // LVDS RX SIGNAL FROM MODEM + //========================================================================= + wire w_lvds_rx_09_d0; // 0 degree + wire w_lvds_rx_09_d1; // 180 degree + wire w_lvds_rx_24_d0; // 0 degree + wire w_lvds_rx_24_d1; // 180 degree + + wire w_lvds_tx_d0; // 0 degree + wire w_lvds_tx_d1; // 180 degree + + // RX FIFO Internals + wire w_rx_09_fifo_write_clk; + wire w_rx_09_fifo_push; + wire [31:0] w_rx_09_fifo_data; + + wire w_rx_24_fifo_write_clk; + wire w_rx_24_fifo_push; + wire [31:0] w_rx_24_fifo_data; + + lvds_rx lvds_rx_09_inst ( + .i_rst_b (i_rst_b), + .i_ddr_clk(lvds_clock_buf), + + .i_ddr_data({w_lvds_rx_09_d0, w_lvds_rx_09_d1}), + + .i_fifo_full(w_rx_fifo_full), + .o_fifo_write_clk(w_rx_09_fifo_write_clk), + .o_fifo_push(w_rx_09_fifo_push), + + .o_fifo_data (w_rx_09_fifo_data), + .i_sync_input (1'b0), + .o_debug_state() + ); + + lvds_rx lvds_rx_24_inst ( + .i_rst_b (i_rst_b), + .i_ddr_clk(lvds_clock_buf), + + .i_ddr_data({w_lvds_rx_24_d0, w_lvds_rx_24_d1}), + + .i_fifo_full(w_rx_fifo_full), + .o_fifo_write_clk(w_rx_24_fifo_write_clk), + .o_fifo_push(w_rx_24_fifo_push), + + .o_fifo_data (w_rx_24_fifo_data), + .i_sync_input (1'b0), + .o_debug_state() + ); + + wire w_rx_fifo_write_clk = (channel == 1'b0) ? w_rx_09_fifo_write_clk : w_rx_24_fifo_write_clk; + wire w_rx_fifo_push = (channel == 1'b0) ? w_rx_09_fifo_push : w_rx_24_fifo_push; + wire [31:0] w_rx_fifo_data = (channel == 1'b0) ? w_rx_09_fifo_data : w_rx_24_fifo_data; + wire w_rx_fifo_pull; + wire [31:0] w_rx_fifo_pulled_data; + wire w_rx_fifo_full; + wire w_rx_fifo_empty; + wire channel; - // Differential 0.9GHz I/Q DDR signal - SB_IO #(.PIN_TYPE(6'b000000), // Input only, DDR mode (sample on both pos edge and - // negedge of the input clock) - .IO_STANDARD("SB_LVDS_INPUT"), // LVDS standard - .NEG_TRIGGER(1'b0)) // The signal is negated in hardware - iq_rx_09 ( .PACKAGE_PIN(i_iq_rx_09_p), - .INPUT_CLK (lvds_clock_buf), // The I/O sampling clock with DDR - .D_IN_0 ( w_lvds_rx_09_d1 ), // the 0 deg data output - .D_IN_1 ( w_lvds_rx_09_d0 ) ); // the 180 deg data output + complex_fifo rx_fifo ( + .wr_rst_b_i(i_rst_b), + .wr_clk_i(w_rx_fifo_write_clk), + .wr_en_i(w_rx_fifo_push), + .wr_data_i(w_rx_fifo_data), + .rd_rst_b_i(i_rst_b), + .rd_clk_i(w_clock_sys), + .rd_en_i(w_rx_fifo_pull), + .rd_data_o(w_rx_fifo_pulled_data), + .full_o(w_rx_fifo_full), + .empty_o(w_rx_fifo_empty), + .debug_pull(w_debug_fifo_pull), + .debug_push(w_debug_fifo_push) + ); + complex_fifo tx_fifo ( + // smi clock is writing + .wr_rst_b_i(i_rst_b), + .wr_clk_i(w_tx_fifo_clock), + .wr_en_i(w_tx_fifo_push), + .wr_data_i(w_tx_fifo_data), + + // lvds clock is pulling (reading) + .rd_rst_b_i(i_rst_b), + .rd_clk_i(w_tx_fifo_read_clk), + .rd_en_i(w_tx_fifo_pull), + .rd_data_o(w_tx_fifo_pulled_data), + .full_o(w_tx_fifo_full), + .empty_o(w_tx_fifo_empty), + .debug_pull(1'b0), + .debug_push(1'b0) + ); + smi_ctrl smi_ctrl_ins ( + .i_rst_b(i_rst_b), + .i_sys_clk(w_clock_sys), + .i_fast_clk(i_glob_clock), + .i_ioc(w_ioc), + .i_data_in(w_rx_data), + .o_data_out(w_tx_data_smi), + .i_cs(w_cs[2]), + .i_fetch_cmd(w_fetch), + .i_load_cmd(w_load), - //========================================================================= - // LVDS RX SIGNAL FROM MODEM - //========================================================================= - wire w_lvds_rx_09_d0; // 0 degree - wire w_lvds_rx_09_d1; // 180 degree - wire w_lvds_rx_24_d0; // 0 degree - wire w_lvds_rx_24_d1; // 180 degree + // FIFO RX + .o_rx_fifo_pull(w_rx_fifo_pull), + .i_rx_fifo_pulled_data(w_rx_fifo_pulled_data), + .i_rx_fifo_empty(w_rx_fifo_empty), + // FIFO TX + .o_tx_fifo_push(w_tx_fifo_push), + .o_tx_fifo_pushed_data(w_tx_fifo_data), + .i_tx_fifo_full(w_tx_fifo_full), + .o_tx_fifo_clock(w_tx_fifo_clock), - wire w_rx_09_fifo_write_clk; - wire w_rx_09_fifo_push; - wire [31:0] w_rx_09_fifo_data; + .i_smi_soe_se(i_smi_soe_se), + .i_smi_swe_srw(i_smi_swe_srw), + .o_smi_data_out(w_smi_data_output), + .i_smi_data_in(w_smi_data_input), + .o_smi_read_req(w_smi_read_req), + .o_smi_write_req(w_smi_write_req), + .o_channel(channel), + .i_smi_test(w_debug_smi_test), + .o_address_error() + ); - wire w_rx_24_fifo_write_clk; - wire w_rx_24_fifo_push; - wire [31:0] w_rx_24_fifo_data; + wire [7:0] w_smi_data_output; + wire [7:0] w_smi_data_input; + wire w_smi_read_req; + wire w_smi_write_req; - lvds_rx lvds_rx_09_inst - ( - .i_rst_b (i_rst_b), - .i_ddr_clk (lvds_clock_buf), + // the "Writing" flag indicates that the data[7:0] direction (inout) + // from the FPGA's SMI module should be "output". This happens when the + // SMI is in the READ mode - data flows from the FPGA to the RPI (RX mode) + // The address has the MSB '1' when in RX mode. otherwise (when IDLE or TX) + // the data is high-z, which is the more "recessive" mode + SB_IO #( + .PIN_TYPE(6'b1010_01), + .PULLUP (1'b0) + ) smi_io0 ( + .PACKAGE_PIN(io_smi_data[0]), + .OUTPUT_ENABLE(i_smi_a2), + .D_OUT_0(w_smi_data_output[0]), + .D_IN_0(w_smi_data_input[0]) + ); + SB_IO #( + .PIN_TYPE(6'b1010_01), + .PULLUP (1'b0) + ) smi_io1 ( + .PACKAGE_PIN(io_smi_data[1]), + .OUTPUT_ENABLE(i_smi_a2), + .D_OUT_0(w_smi_data_output[1]), + .D_IN_0(w_smi_data_input[1]) + ); + SB_IO #( + .PIN_TYPE(6'b1010_01), + .PULLUP (1'b0) + ) smi_io2 ( + .PACKAGE_PIN(io_smi_data[2]), + .OUTPUT_ENABLE(i_smi_a2), + .D_OUT_0(w_smi_data_output[2]), + .D_IN_0(w_smi_data_input[2]) + ); + SB_IO #( + .PIN_TYPE(6'b1010_01), + .PULLUP (1'b0) + ) smi_io3 ( + .PACKAGE_PIN(io_smi_data[3]), + .OUTPUT_ENABLE(i_smi_a2), + .D_OUT_0(w_smi_data_output[3]), + .D_IN_0(w_smi_data_input[3]) + ); + SB_IO #( + .PIN_TYPE(6'b1010_01), + .PULLUP (1'b0) + ) smi_io4 ( + .PACKAGE_PIN(io_smi_data[4]), + .OUTPUT_ENABLE(i_smi_a2), + .D_OUT_0(w_smi_data_output[4]), + .D_IN_0(w_smi_data_input[4]) + ); + SB_IO #( + .PIN_TYPE(6'b1010_01), + .PULLUP (1'b0) + ) smi_io5 ( + .PACKAGE_PIN(io_smi_data[5]), + .OUTPUT_ENABLE(i_smi_a2), + .D_OUT_0(w_smi_data_output[5]), + .D_IN_0(w_smi_data_input[5]) + ); + SB_IO #( + .PIN_TYPE(6'b1010_01), + .PULLUP (1'b0) + ) smi_io6 ( + .PACKAGE_PIN(io_smi_data[6]), + .OUTPUT_ENABLE(i_smi_a2), + .D_OUT_0(w_smi_data_output[6]), + .D_IN_0(w_smi_data_input[6]) + ); + SB_IO #( + .PIN_TYPE(6'b1010_01), + .PULLUP (1'b0) + ) smi_io7 ( + .PACKAGE_PIN(io_smi_data[7]), + .OUTPUT_ENABLE(i_smi_a2), + .D_OUT_0(w_smi_data_output[7]), + .D_IN_0(w_smi_data_input[7]) + ); + //assign io_smi_data = (i_smi_a2)?w_smi_data_output:8'bZ; + //assign w_smi_data_input = io_smi_data; + // We need the 'o_smi_write_req' to be 1 only when the direction is TX + // (i_smi_a2 == 0) and the write fifo is not full + assign o_smi_read_req = (i_smi_a2) ? w_smi_read_req : w_smi_write_req; + assign o_smi_write_req = 1'bZ; - .i_ddr_data ({w_lvds_rx_09_d1, w_lvds_rx_09_d0}), + //assign io_pmod[0] = w_rx_fifo_push; + //assign io_pmod[1] = w_rx_fifo_pull; + //assign io_pmod[2] = w_smi_read_req; + //assign io_pmod[3] = w_rx_fifo_full; + //assign io_pmod[4] = w_rx_fifo_empty; + //assign io_pmod[5] = i_smi_a2; + //assign io_pmod[6] = channel; + //assign io_pmod[7] = ...; - .i_fifo_full (w_rx_fifo_full), - .o_fifo_write_clk (w_rx_09_fifo_write_clk), - .o_fifo_push (w_rx_09_fifo_push), - - .o_fifo_data (w_rx_09_fifo_data), - .i_sync_input (1'b0), - .o_debug_state () - ); - - lvds_rx lvds_rx_24_inst - ( - .i_rst_b (i_rst_b), - .i_ddr_clk (lvds_clock_buf), - - .i_ddr_data ({!w_lvds_rx_24_d1, !w_lvds_rx_24_d0}), - - .i_fifo_full (w_rx_fifo_full), - .o_fifo_write_clk (w_rx_24_fifo_write_clk), - .o_fifo_push (w_rx_24_fifo_push), - - .o_fifo_data (w_rx_24_fifo_data), - .i_sync_input (1'b0), - .o_debug_state () - ); - - wire w_rx_fifo_write_clk = (channel == 1'b0)?w_rx_09_fifo_write_clk:w_rx_24_fifo_write_clk; - wire w_rx_fifo_push = (channel == 1'b0)?w_rx_09_fifo_push:w_rx_24_fifo_push; - wire [31:0] w_rx_fifo_data = (channel == 1'b0)?w_rx_09_fifo_data:w_rx_24_fifo_data; - wire w_rx_fifo_pull; - wire [31:0] w_rx_fifo_pulled_data; - wire w_rx_fifo_full; - wire w_rx_fifo_empty; - wire channel; - - - complex_fifo rx_fifo( - .wr_rst_b_i (i_rst_b), - .wr_clk_i (w_rx_fifo_write_clk), - .wr_en_i (w_rx_fifo_push), - .wr_data_i (w_rx_fifo_data), - .rd_rst_b_i (i_rst_b), - .rd_clk_i (w_clock_sys), - .rd_en_i (w_rx_fifo_pull), - .rd_data_o (w_rx_fifo_pulled_data), - .full_o (w_rx_fifo_full), - .empty_o (w_rx_fifo_empty), - .debug_pull (w_debug_fifo_pull), - .debug_push (w_debug_fifo_push) - ); - - smi_ctrl smi_ctrl_ins - ( - .i_rst_b (i_rst_b), - .i_sys_clk (w_clock_sys), - .i_fast_clk (i_glob_clock), - .i_ioc (w_ioc), - .i_data_in (w_rx_data), - .o_data_out (w_tx_data_smi), - .i_cs (w_cs[2]), - .i_fetch_cmd (w_fetch), - .i_load_cmd (w_load), - - .o_fifo_pull (w_rx_fifo_pull), - .i_fifo_pulled_data (w_rx_fifo_pulled_data), - .i_fifo_full (w_rx_fifo_full), - .i_fifo_empty (w_rx_fifo_empty), - - .i_smi_soe_se (i_smi_soe_se), - .i_smi_swe_srw (i_smi_swe_srw), - .o_smi_data_out (w_smi_data_output), - .i_smi_data_in (w_smi_data_input), - .o_smi_read_req (w_smi_read_req), - .o_smi_write_req (w_smi_write_req), - .o_channel (channel), - .i_smi_test (w_debug_smi_test), - .o_address_error () - ); - - wire [7:0] w_smi_data_output; - wire [7:0] w_smi_data_input; - wire w_smi_read_req; - wire w_smi_write_req; - - assign io_smi_data = (i_smi_a2)?w_smi_data_output:8'bZ; - assign w_smi_data_input = io_smi_data; - assign o_smi_write_req = w_smi_write_req; - assign o_smi_read_req = w_smi_read_req; - - assign io_pmod[0] = w_rx_fifo_push; - assign io_pmod[1] = w_rx_fifo_pull; - assign io_pmod[2] = w_smi_read_req; - assign io_pmod[3] = w_rx_fifo_full; - assign io_pmod[4] = w_rx_fifo_empty; - assign io_pmod[5] = i_smi_a2; - assign io_pmod[6] = channel; - //assign io_pmod[7] = ...; - -endmodule // top +endmodule // top