diff options
Diffstat (limited to 'fpga/usrp3/top/x300/x300.v')
-rw-r--r-- | fpga/usrp3/top/x300/x300.v | 1483 |
1 files changed, 1483 insertions, 0 deletions
diff --git a/fpga/usrp3/top/x300/x300.v b/fpga/usrp3/top/x300/x300.v new file mode 100644 index 000000000..8fbfa39b9 --- /dev/null +++ b/fpga/usrp3/top/x300/x300.v @@ -0,0 +1,1483 @@ +/////////////////////////////////// +// +// Copyright 2016-2017 Ettus Research LLC +// Copyright 2017 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// NOTE: A set of precompiler directives configure the features in an FPGA build +// and are listed here. These should be set exclusively using the Makefile mechanism provided. +// +// SFP0_10GBE - Ethernet Port0 is configured for 10G (default is 1G) +// SFP1_10GBE - Ethernet Port1 is configured for 10G (default is 1G) +// DEBUG_UART - Adds 115kbaud UART to GPIO pins 10 & 11 for firmware debug +// +/////////////////////////////////// + +//Defines `LVFPGA_IFACE constants +`include "../../lib/io_port2/LvFpga_Chinch_Interface.vh" + +module x300 + + ( + /////////////////////////////////// + // + // Clock sources for main FPGA clocks + // + /////////////////////////////////// + input FPGA_CLK_p, input FPGA_CLK_n, + input FPGA_125MHz_CLK, + + /////////////////////////////////// + // + // High Speed SPF+ signals and clocking + // + /////////////////////////////////// + +`ifdef BUILD_1G + input ETH_CLK_p, input ETH_CLK_n, +`endif + +`ifdef BUILD_10G + `define BUILD_10G_OR_AURORA +`endif +`ifdef BUILD_AURORA + `define BUILD_10G_OR_AURORA +`endif +`ifdef BUILD_10G_OR_AURORA + input XG_CLK_p, input XG_CLK_n, +`endif + + input SFP0_RX_p, input SFP0_RX_n, + output SFP0_TX_p, output SFP0_TX_n, + input SFP1_RX_p, input SFP1_RX_n, + output SFP1_TX_p, output SFP1_TX_n, + + /////////////////////////////////// + // + // DRAM Interface + // + /////////////////////////////////// + inout [31:0] ddr3_dq, // Data pins. Input for Reads, Output for Writes. + inout [3:0] ddr3_dqs_n, // Data Strobes. Input for Reads, Output for Writes. + inout [3:0] ddr3_dqs_p, + // + output [14:0] ddr3_addr, // Address + output [2:0] ddr3_ba, // Bank Address + output ddr3_ras_n, // Row Address Strobe. + output ddr3_cas_n, // Column address select + output ddr3_we_n, // Write Enable + output ddr3_reset_n, // SDRAM reset pin. + output [0:0] ddr3_ck_p, // Differential clock + output [0:0] ddr3_ck_n, + output [0:0] ddr3_cke, // Clock Enable + output [0:0] ddr3_cs_n, // Chip Select + output [3:0] ddr3_dm, // Data Mask [3] = UDM.U26, [2] = LDM.U26, ... + output [0:0] ddr3_odt, // On-Die termination enable. + // + input sys_clk_i, // 100MHz clock source to generate DDR3 clocking. + /////////////////////////////////// + // + // IOPORT2 + // + /////////////////////////////////// + + //-- The IO_Port2 asynchronous handshaking pins + input aIoResetIn_n, + output aIoReadyOut, + input aIoReadyIn, + output aIoPort2Restart, + input aStc3Gpio7, + + //-- The IO_Port2 high speed receiver pins + input IoRxClock, + input IoRxClock_n, + input [15:0] irIoRxData, + input [15:0] irIoRxData_n, + input irIoRxHeader, + input irIoRxHeader_n, + + //-- The IO_Port2 high speed transmitter interface pins + output IoTxClock, + output IoTxClock_n, + output [15:0] itIoTxData, + output [15:0] itIoTxData_n, + output itIoTxHeader, + output itIoTxHeader_n, + + output aIrq, + + /////////////////////////////////// + // + // ADC and DAC interfaces + // + /////////////////////////////////// + + input DB0_ADC_DCLK_P, input DB0_ADC_DCLK_N, + input DB0_ADC_DA0_P, input DB0_ADC_DA0_N, input DB0_ADC_DB0_P, input DB0_ADC_DB0_N, + input DB0_ADC_DA1_P, input DB0_ADC_DA1_N, input DB0_ADC_DB1_P, input DB0_ADC_DB1_N, + input DB0_ADC_DA2_P, input DB0_ADC_DA2_N, input DB0_ADC_DB2_P, input DB0_ADC_DB2_N, + input DB0_ADC_DA3_P, input DB0_ADC_DA3_N, input DB0_ADC_DB3_P, input DB0_ADC_DB3_N, + input DB0_ADC_DA4_P, input DB0_ADC_DA4_N, input DB0_ADC_DB4_P, input DB0_ADC_DB4_N, + input DB0_ADC_DA5_P, input DB0_ADC_DA5_N, input DB0_ADC_DB5_P, input DB0_ADC_DB5_N, + input DB0_ADC_DA6_P, input DB0_ADC_DA6_N, input DB0_ADC_DB6_P, input DB0_ADC_DB6_N, + + input DB1_ADC_DCLK_P, input DB1_ADC_DCLK_N, + input DB1_ADC_DA0_P, input DB1_ADC_DA0_N, input DB1_ADC_DB0_P, input DB1_ADC_DB0_N, + input DB1_ADC_DA1_P, input DB1_ADC_DA1_N, input DB1_ADC_DB1_P, input DB1_ADC_DB1_N, + input DB1_ADC_DA2_P, input DB1_ADC_DA2_N, input DB1_ADC_DB2_P, input DB1_ADC_DB2_N, + input DB1_ADC_DA3_P, input DB1_ADC_DA3_N, input DB1_ADC_DB3_P, input DB1_ADC_DB3_N, + input DB1_ADC_DA4_P, input DB1_ADC_DA4_N, input DB1_ADC_DB4_P, input DB1_ADC_DB4_N, + input DB1_ADC_DA5_P, input DB1_ADC_DA5_N, input DB1_ADC_DB5_P, input DB1_ADC_DB5_N, + input DB1_ADC_DA6_P, input DB1_ADC_DA6_N, input DB1_ADC_DB6_P, input DB1_ADC_DB6_N, + + output DB0_DAC_DCI_P, output DB0_DAC_DCI_N, + output DB0_DAC_FRAME_P, output DB0_DAC_FRAME_N, + output DB0_DAC_D0_P, output DB0_DAC_D0_N, output DB0_DAC_D1_P, output DB0_DAC_D1_N, + output DB0_DAC_D2_P, output DB0_DAC_D2_N, output DB0_DAC_D3_P, output DB0_DAC_D3_N, + output DB0_DAC_D4_P, output DB0_DAC_D4_N, output DB0_DAC_D5_P, output DB0_DAC_D5_N, + output DB0_DAC_D6_P, output DB0_DAC_D6_N, output DB0_DAC_D7_P, output DB0_DAC_D7_N, + output DB0_DAC_ENABLE, + + output DB1_DAC_DCI_P, output DB1_DAC_DCI_N, + output DB1_DAC_FRAME_P, output DB1_DAC_FRAME_N, + output DB1_DAC_D0_P, output DB1_DAC_D0_N, output DB1_DAC_D1_P, output DB1_DAC_D1_N, + output DB1_DAC_D2_P, output DB1_DAC_D2_N, output DB1_DAC_D3_P, output DB1_DAC_D3_N, + output DB1_DAC_D4_P, output DB1_DAC_D4_N, output DB1_DAC_D5_P, output DB1_DAC_D5_N, + output DB1_DAC_D6_P, output DB1_DAC_D6_N, output DB1_DAC_D7_P, output DB1_DAC_D7_N, + output DB1_DAC_ENABLE, + + output DB0_SCLK, output DB0_MOSI, + output DB0_ADC_SEN, output DB0_DAC_SEN, output DB0_TX_SEN, output DB0_RX_SEN, + output DB0_RX_LSADC_SEN, output DB0_RX_LSDAC_SEN, output DB0_TX_LSADC_SEN, output DB0_TX_LSDAC_SEN, + input DB0_RX_LSADC_MISO, input DB0_RX_MISO, input DB0_TX_LSADC_MISO, input DB0_TX_MISO, + + output DB1_SCLK, output DB1_MOSI, + output DB1_ADC_SEN, output DB1_DAC_SEN, output DB1_TX_SEN, output DB1_RX_SEN, + output DB1_RX_LSADC_SEN, output DB1_RX_LSDAC_SEN, output DB1_TX_LSADC_SEN, output DB1_TX_LSDAC_SEN, + input DB1_RX_LSADC_MISO, input DB1_RX_MISO, input DB1_TX_LSADC_MISO, input DB1_TX_MISO, + output DB_DAC_SCLK, inout DB_DAC_MOSI, + + output DB_ADC_RESET, output DB_DAC_RESET, + + inout DB_SCL, inout DB_SDA, + + /////////////////////////////////// + // + // GPIO/LEDS/Etc + // + /////////////////////////////////// + + inout [11:0] FrontPanelGpio, + + output LED_ACT1, output LED_ACT2, + output LED_LINK1, output LED_LINK2, + + output LED_PPS, output LED_REFLOCK, output LED_GPSLOCK, + output LED_LINKSTAT, output LED_LINKACT, + output LED_RX1_RX, output LED_RX2_RX, + output LED_TXRX1_RX, output LED_TXRX1_TX, + output LED_TXRX2_RX, output LED_TXRX2_TX, + inout [15:0] DB0_TX_IO, + inout [15:0] DB0_RX_IO, + inout [15:0] DB1_TX_IO, + inout [15:0] DB1_RX_IO, + + /////////////////////////////////// + // + // LMK CLock chip + // + /////////////////////////////////// + + input [1:0] LMK_Status, + input LMK_Holdover, + input LMK_Lock, + input LMK_Sync, //not used, we do soft sync + output LMK_SEN, output LMK_MOSI, output LMK_SCLK, + + /////////////////////////////////// + // + // GPSDO and Clock Refs + // + /////////////////////////////////// + + output [1:0] ClockRefSelect, + output GPS_SER_IN, input GPS_SER_OUT, + input GPS_PPS_OUT, input EXT_PPS_IN, + output EXT_PPS_OUT, input GPS_LOCK_OK, + output GPSDO_PWR_ENA, output TCXO_ENA, + + output CPRI_CLK_OUT_P, output CPRI_CLK_OUT_N, + + input FPGA_REFCLK_10MHz_p, input FPGA_REFCLK_10MHz_n, + + /////////////////////////////////// + // + // Supporting I/O for SPF+ interfaces + // (non high speed stuff) + // + /////////////////////////////////// + + inout SFPP0_SCL, inout SFPP0_SDA, + input SFPP0_ModAbs, + input SFPP0_RxLOS, // High if module asserts Loss of Signal + input SFPP0_TxFault, // Current 10G PMA/PCS apparently ignores this signal. + output SFPP0_RS0, // These are actually open drain outputs + output SFPP0_RS1, // CAUTION! Take great care, this signal shorted to VeeR on SFP module. + output SFPP0_TxDisable, // These are actually open drain outputs + + inout SFPP1_SCL, inout SFPP1_SDA, + input SFPP1_ModAbs, + input SFPP1_RxLOS, // High if module asserts Loss of Signal + input SFPP1_TxFault, // Current 10G PMA/PCS apparently ignores this signal. + output SFPP1_RS0, // These are actually open drain outputs + output SFPP1_RS1, // CAUTION! Take great care, this signal shorted to VeeR on SFP module. + output SFPP1_TxDisable, // These are actually open drain outputs + + /////////////////////////////////// + // + // Misc. + // + /////////////////////////////////// + + input FPGA_PUDC_B +); + + wire radio_clk, radio_clk_2x, dac_dci_clk; + wire global_rst, radio_rst, bus_rst, bus_rst_div2, ce_rst, adc_idlyctrl_rst; + wire [3:0] sw_rst; + wire [2:0] led0, led1; + + //////////////////////////////////////////////////////////////////// + // + // Generate Bus Clock and PCIe Clocks. + // Source clock comes from U19 which is fixed freq + // and bufferd to be used by STC3 also (Page17 schematics). + // + //////////////////////////////////////////////////////////////////// + + wire fpga_clk125, bus_clk, bus_clk_div2, ce_clk, ioport2_clk, rio40_clk, ioport2_idelay_ref_clk; + wire bus_clk_locked, rio40_clk_locked, rio40_clk_reset; + + IBUFG fpga_125MHz_clk_buf ( + .I(FPGA_125MHz_CLK), + .O(fpga_clk125)); + + //---------------------------------------------------------------------------- + // Output Output Phase Duty Cycle Pk-to-Pk Phase + // Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps) + //---------------------------------------------------------------------------- + // CLK_OUT1___187.500______0.000______50.0_______85.263_____73.940 + // CLK_OUT2___125.000______0.000______50.0_______91.831_____73.940 + // CLK_OUT3____93.750______0.000______50.0_______96.813_____73.940 + // CLK_OUT4___214.286______0.000______50.0_______83.210_____73.940 + // + //---------------------------------------------------------------------------- + // Input Clock Freq (MHz) Input Jitter (UI) + //---------------------------------------------------------------------------- + // __primary_________125.000____________0.010 + + localparam BUS_CLK_RATE = 32'd187500000; + + wire ioport2_clk_unbuf; + + bus_clk_gen bus_clk_gen ( + .CLK_IN1(fpga_clk125), + .CLKFB_IN(ioport2_clk), + .CLK_OUT1(bus_clk), + .CLK_OUT2_UNBUF(/* unused */), //This exists to make the IP generate a 125MHz FB clock + .CLK_OUT3(bus_clk_div2), //bus_clk divided by 2. used by sc/zpu + .CLK_OUT4(ce_clk), + .CLKFB_OUT(ioport2_clk_unbuf), + .LOCKED(bus_clk_locked)); + + BUFG ioport2_clk_bufg_i ( + .O(ioport2_clk), + .I(ioport2_clk_unbuf)); + + //---------------------------------------------------------------------------- + // Output Output Phase Duty Cycle Pk-to-Pk Phase + // Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps) + //---------------------------------------------------------------------------- + // CLK_OUT1____40.000______0.000______50.0______353.417_____96.948 + // CLK_OUT2___200.000______0.000______50.0______192.299_____96.948 + // + //---------------------------------------------------------------------------- + // Input Clock Freq (MHz) Input Jitter (UI) + //---------------------------------------------------------------------------- + // __primary_________125.000____________0.100 + + //rio40_clk and ioport2_idelay_ref_clk cannot share a PLL/MMCM reset with ioport2_clk + //so they have to come from a different clocking primitive instance + pcie_clk_gen pcie_clk_gen ( + .CLK_IN1(fpga_clk125), + .CLK_OUT1(rio40_clk), + .CLK_OUT2(ioport2_idelay_ref_clk), + .RESET(rio40_clk_reset), + .LOCKED(rio40_clk_locked)); + + ///////////////////////////////////////////////////////////////////// + // + // 10MHz Reference clock + // + ////////////////////////////////////////////////////////////////////// + wire ref_clk; + IBUFDS IBUFDS_ref_clk ( + .O(ref_clk), + .I(FPGA_REFCLK_10MHz_p), + .IB(FPGA_REFCLK_10MHz_n) + ); + + ////////////////////////////////////////////////////////////////////// + // CPRI Clock output -- this is the dirty recovered clock from the MGT + // This goes to the LMK04816 which locks to it and cleans it up + // We get the clean versions back as CPRI_CLK (for the CPRI MGT) + // and FPGA_CLK (for our main rfclk) + ////////////////////////////////////////////////////////////////////// + + wire cpri_clk_out = 1'b0; // FIXME - connect to CPRI clock recovery when implemented + OBUFDS OBUFDS_cpri (.I(cpri_clk_out), .O(CPRI_CLK_OUT_P), .OB(CPRI_CLK_OUT_N)); + + ///////////////////////////////////////////////////////////////////// + // + // power-on-reset logic. + // + ////////////////////////////////////////////////////////////////////// + por_gen por_gen(.clk(bus_clk), .reset_out(global_rst)); + + ////////////////////////////////////////////////////////////////////// + wire [31:0] rx0, rx1; + wire [31:0] tx0, tx1; + wire sclk0, mosi0, miso0, sclk1, mosi1, miso1; + wire [7:0] sen0, sen1; + + wire set_stb; + wire [7:0] set_addr; + wire [31:0] set_data; + + //////////////////////////////////////////////////////////////////// + // + // Generate Radio Clocks from LMK04816 + // Radio clock is normally 200MHz, radio_clk_2x 400MHz. + // In CPRI or LTE mode, radio clock is 184.32 MHz. + // radio_clk_2x is only to be used for clocking out TX samples to DAC + // + //---------------------------------------------------------------------------- + // Output Output Phase Duty Cycle Pk-to-Pk Phase + // Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps) + //---------------------------------------------------------------------------- + // CLK_OUT1___200.000______0.000______50.0_______92.799_____82.655 + // CLK_OUT2___400.000____-45.000______50.0_______81.254_____82.655 + // CLK_OUT3___400.000_____60.000______50.0_______81.254_____82.655 + // + //---------------------------------------------------------------------------- + // Input Clock Freq (MHz) Input Jitter (UI) + //---------------------------------------------------------------------------- + // __primary_________200.000____________0.010 + // + //////////////////////////////////////////////////////////////////// + + wire radio_clk_locked; + radio_clk_gen radio_clk_gen ( + .clk_in1_p(FPGA_CLK_p), .clk_in1_n(FPGA_CLK_n), + .CLK_OUT1(radio_clk), .CLK_OUT2(radio_clk_2x), .CLK_OUT3(dac_dci_clk), + .RESET(sw_rst[2]), .LOCKED(radio_clk_locked)); + + //////////////////////////////////////////////////////////////////// + // + // IJB. Radio PLL doesn't seem to lock at power up. + // Probably needs AD9610 to be programmed to 120 or 200MHz to get + // an input clock thats in the ball park for PLL configuration. + // Currently use busclk PLL lock signal to control this reset, + // but we should find a better solution, perhaps a S/W controllable + // reset like the ETH PHY uses so that we can reset this clock domain + // after programming the AD9610. + // + //////////////////////////////////////////////////////////////////// + + reset_sync radio_reset_sync ( + .clk(radio_clk), + .reset_in(global_rst || !bus_clk_locked || sw_rst[1]), + .reset_out(radio_rst) + ); + + reset_sync int_reset_sync ( + .clk(bus_clk), + .reset_in(global_rst || !bus_clk_locked), + .reset_out(bus_rst) + ); + + reset_sync int_div2_reset_sync ( + .clk(bus_clk_div2), + .reset_in(global_rst || !bus_clk_locked), + .reset_out(bus_rst_div2) + ); + + reset_sync adc_idlyctrl_reset_sync ( + .clk(bus_clk), + .reset_in(global_rst || !bus_clk_locked || sw_rst[3]), + .reset_out(adc_idlyctrl_rst) + ); + + reset_sync ce_reset_sync ( + .clk(ce_clk), + .reset_in(global_rst || !bus_clk_locked), + .reset_out(ce_rst) + ); + + //////////////////////////////////////////////////////////////////// + // PPS + // Support for internal, external, and GPSDO PPS inputs + // Every attempt to minimize propagation between the external PPS + // input and outputs to support daisy-chaining the signal. + //////////////////////////////////////////////////////////////////// + + wire int_pps; + wire [31:0] ref_freq; + wire ref_freq_changed; + wire ref_freq_sync_empty; + wire [71:0] ref_freq_sync_out; + reg new_ref_freq = 0; + reg [31:0] ref_freq_refclk = 10_000_000; // Default to 10 MHz reference + + // Synchronize ref_freq to ref_clk + fifo_short_2clk ref_freq_sync + ( + .rst(bus_rst), + .wr_clk(bus_clk), + .rd_clk(ref_clk), + .din({40'd0,ref_freq}), + .wr_en(ref_freq_changed), + .rd_en(new_ref_freq), + .dout(ref_freq_sync_out), + .full( /* unused */ ), + .empty(ref_freq_sync_empty), + .rd_data_count( /* unused */ ), + .wr_data_count( /* unused */ ) + ); + + // Capture the new reference frequency + always @(posedge ref_clk) begin + if (~ref_freq_sync_empty) begin + ref_freq_refclk <= ref_freq_sync_out[31:0]; + new_ref_freq <= 1'b1; + end else + new_ref_freq <= 1'b0; + end + + // Generate an internal PPS signal with a 25% duty cycle + pulse_generator #(.WIDTH(32)) pps_gen + ( + .clk(ref_clk), + .reset(new_ref_freq), + .period(ref_freq_refclk), + //shift frequency by 2 bits (divide by 4) for a 25% duty cycle + .pulse_width({2'b00,ref_freq_refclk[31:2]}), + .pulse(int_pps) + ); + + // PPS MUX - selects internal, external, or gpsdo PPS + reg pps; + wire [1:0] pps_select; + wire pps_out_enb; + always @(*) begin + case(pps_select) + 2'b00 : pps = EXT_PPS_IN; + 2'b01 : pps = 1'b0; + 2'b10 : pps = int_pps; + 2'b11 : pps = GPS_PPS_OUT; + default: pps = 1'b0; + endcase + end + + // PPS out and LED + assign EXT_PPS_OUT = pps & pps_out_enb; + assign LED_PPS = ~pps; // active low LED driver + + assign LED_GPSLOCK = ~GPS_LOCK_OK; + assign LED_REFLOCK = ~LMK_Lock; + assign {LED_RX1_RX,LED_TXRX1_TX,LED_TXRX1_RX} = ~led0; // active low LED driver + assign {LED_RX2_RX,LED_TXRX2_TX,LED_TXRX2_RX} = ~led1; // active low LED driver + // Allocate SPI chip selects to various slaves. + assign {DB1_DAC_SEN, DB1_ADC_SEN, DB1_RX_LSADC_SEN, DB1_RX_LSDAC_SEN, DB1_TX_LSADC_SEN, DB1_TX_LSDAC_SEN, DB1_RX_SEN, DB1_TX_SEN} = sen1; + assign {DB0_DAC_SEN, DB0_ADC_SEN, DB0_RX_LSADC_SEN, DB0_RX_LSDAC_SEN, DB0_TX_LSADC_SEN, DB0_TX_LSDAC_SEN, DB0_RX_SEN, DB0_TX_SEN} = sen0; + + wire db_dac_mosi_int, db_dac_miso; + wire drive_dac_pin; + reg drop_dac_pin; + reg [5:0] bitcount; + reg sclk_d1; + + // Register copy of outgoing DAC clock to do synchronous edge detect. + always @(posedge radio_clk) sclk_d1 <= DB_DAC_SCLK; + + always @(posedge radio_clk) + // If neither DAC is selected keep counter reset + if(DB0_DAC_SEN & DB1_DAC_SEN) + begin + bitcount <= 6'd0; + drop_dac_pin <= 1'b0; + end + else if(~DB_DAC_SCLK & sclk_d1) + // Falling edge of SCLK detected. + begin + bitcount <= bitcount + 6'd1; + end + else if(bitcount == 0 & DB_DAC_SCLK & ~sclk_d1) + // On first rising edge store R/W bit to determine if we tristate after 8bits for a Read. + drop_dac_pin <= db_dac_mosi_int; + + assign drive_dac_pin = (bitcount < 8) | ~drop_dac_pin; + + // Both DAC's use a single SPI bus on PCB. Select appriate Radio to drive the SPi bus by looking at chip selects. + assign { DB_DAC_SCLK, db_dac_mosi_int } = ~DB0_DAC_SEN ? {sclk0, mosi0} : ~DB1_DAC_SEN ? {sclk1,mosi1} : 2'b0; + // Data to/from DAC's is bi-dir so tristate driver when reading. + assign DB_DAC_MOSI = drive_dac_pin ? db_dac_mosi_int : 1'bz; + // I/O Input buffer + assign db_dac_miso = DB_DAC_MOSI; + + // If any SPI Slave is selected (except DAC) then drive SPI clk and MOSI out onto duaghterboard. + assign { DB0_SCLK, DB0_MOSI } = (~&sen0[6:0]) ? {sclk0,mosi0} : 2'b0; + assign { DB1_SCLK, DB1_MOSI } = (~&sen1[6:0]) ? {sclk1,mosi1} : 2'b0; + + // Wired OR Mux together the possible sources of read data from SPI devices. + assign miso0 = (~DB0_RX_LSADC_SEN & DB0_RX_LSADC_MISO) | + (~DB0_RX_SEN & DB0_RX_MISO) | + (~DB0_TX_LSADC_SEN & DB0_TX_LSADC_MISO) | + (~DB0_TX_SEN & DB0_TX_MISO) | + (~DB0_DAC_SEN & db_dac_miso); + + assign miso1 = (~DB1_RX_LSADC_SEN & DB1_RX_LSADC_MISO) | + (~DB1_RX_SEN & DB1_RX_MISO) | + (~DB1_TX_LSADC_SEN & DB1_TX_LSADC_MISO) | + (~DB1_TX_SEN & DB1_TX_MISO) | + (~DB1_DAC_SEN & db_dac_miso); + + + wire [31:0] radio0_misc_out, radio1_misc_out; + wire [31:0] radio0_misc_in, radio1_misc_in; + + ///////////////////////////////////////////////////////////////////// + // + // ADC Interface for ADS62P48 + // + ///////////////////////////////////////////////////////////////////// + wire [13:0] rx0_q_inv, rx1_q_inv, rx0_i, rx1_i; + // Analog diff pairs on I side of ADC are inverted for layout reasons, but data diff pairs are all swapped as well + // so I gets a double negative, and is unchanged. Q must be inverted. + + capture_ddrlvds #( + .WIDTH(14), + .PATT_CHECKER("TRUE"), + .DATA_IDELAY_MODE("DYNAMIC"), .DATA_IDELAY_VAL(16), .DATA_IDELAY_FREF(200.0) + ) cap_db0 ( + .adc_clk_p(DB0_ADC_DCLK_P), .adc_clk_n(DB0_ADC_DCLK_N), + .adc_data_p( + {{DB0_ADC_DA6_P, DB0_ADC_DA5_P, DB0_ADC_DA4_P, DB0_ADC_DA3_P, DB0_ADC_DA2_P, DB0_ADC_DA1_P, DB0_ADC_DA0_P}, + {DB0_ADC_DB6_P, DB0_ADC_DB5_P, DB0_ADC_DB4_P, DB0_ADC_DB3_P, DB0_ADC_DB2_P, DB0_ADC_DB1_P, DB0_ADC_DB0_P}}), + .adc_data_n( + {{DB0_ADC_DA6_N, DB0_ADC_DA5_N, DB0_ADC_DA4_N, DB0_ADC_DA3_N, DB0_ADC_DA2_N, DB0_ADC_DA1_N, DB0_ADC_DA0_N}, + {DB0_ADC_DB6_N, DB0_ADC_DB5_N, DB0_ADC_DB4_N, DB0_ADC_DB3_N, DB0_ADC_DB2_N, DB0_ADC_DB1_N, DB0_ADC_DB0_N}}), + .radio_clk(radio_clk), + .data_delay_stb(radio0_misc_out[3]), .data_delay_val(radio0_misc_out[8:4]), + .adc_cap_clk(), + .data_out({rx0_i,rx0_q_inv}), + .checker_en(radio0_misc_out[9]), .checker_locked(radio0_misc_in[3:0]), .checker_failed(radio0_misc_in[7:4]) + ); + assign rx0[31:0] = { rx0_i, 2'b00, ~rx0_q_inv, 2'b00 }; + + capture_ddrlvds #( + .WIDTH(14), + .PATT_CHECKER("TRUE"), + .DATA_IDELAY_MODE("DYNAMIC"), .DATA_IDELAY_VAL(16), .DATA_IDELAY_FREF(200.0) + ) cap_db1 ( + .adc_clk_p(DB1_ADC_DCLK_P), .adc_clk_n(DB1_ADC_DCLK_N), + .adc_data_p( + {{DB1_ADC_DA6_P, DB1_ADC_DA5_P, DB1_ADC_DA4_P, DB1_ADC_DA3_P, DB1_ADC_DA2_P, DB1_ADC_DA1_P, DB1_ADC_DA0_P}, + {DB1_ADC_DB6_P, DB1_ADC_DB5_P, DB1_ADC_DB4_P, DB1_ADC_DB3_P, DB1_ADC_DB2_P, DB1_ADC_DB1_P, DB1_ADC_DB0_P}}), + .adc_data_n( + {{DB1_ADC_DA6_N, DB1_ADC_DA5_N, DB1_ADC_DA4_N, DB1_ADC_DA3_N, DB1_ADC_DA2_N, DB1_ADC_DA1_N, DB1_ADC_DA0_N}, + {DB1_ADC_DB6_N, DB1_ADC_DB5_N, DB1_ADC_DB4_N, DB1_ADC_DB3_N, DB1_ADC_DB2_N, DB1_ADC_DB1_N, DB1_ADC_DB0_N}}), + .radio_clk(radio_clk), + .data_delay_stb(radio1_misc_out[3]), .data_delay_val(radio1_misc_out[8:4]), + .adc_cap_clk(), + .data_out({rx1_i,rx1_q_inv}), + .checker_en(radio1_misc_out[9]), .checker_locked(radio1_misc_in[3:0]), .checker_failed(radio1_misc_in[7:4]) + ); + assign rx1[31:0] = { rx1_i, 2'b00, ~rx1_q_inv, 2'b00 }; + + // IDELAYCTRL to calibrate all IDELAYE2 instances in capture_ddrlvds for both sides + wire adc_idlyctrl_rdy; + IDELAYCTRL adc_cap_idelayctrl_i (.RDY(adc_idlyctrl_rdy), .REFCLK(radio_clk), .RST(adc_idlyctrl_rst)); + + ///////////////////////////////////////////////////////////////////// + // + // DAC Interface for AD9146 + // + ///////////////////////////////////////////////////////////////////// + gen_ddrlvds gen_db0 + ( + .reset(radio_rst), + .tx_clk_2x_p(DB0_DAC_DCI_P), .tx_clk_2x_n(DB0_DAC_DCI_N), + .tx_frame_p(DB0_DAC_FRAME_P), .tx_frame_n(DB0_DAC_FRAME_N), + .tx_d_p({DB0_DAC_D7_P,DB0_DAC_D6_P,DB0_DAC_D5_P,DB0_DAC_D4_P,DB0_DAC_D3_P,DB0_DAC_D2_P,DB0_DAC_D1_P,DB0_DAC_D0_P}), + .tx_d_n({DB0_DAC_D7_N,DB0_DAC_D6_N,DB0_DAC_D5_N,DB0_DAC_D4_N,DB0_DAC_D3_N,DB0_DAC_D2_N,DB0_DAC_D1_N,DB0_DAC_D0_N}), + .tx_clk_2x(radio_clk_2x), .tx_clk_1x(radio_clk), .tx_dci_clk(dac_dci_clk), + .i(~tx0[31:16]), .q(~tx0[15:0]), // invert b/c Analog diff pairs are swapped for layout + .sync_dacs(radio0_misc_out[10]|radio1_misc_out[10]) + ); + + + gen_ddrlvds gen_db1 + ( + .reset(radio_rst), + .tx_clk_2x_p(DB1_DAC_DCI_P), .tx_clk_2x_n(DB1_DAC_DCI_N), + .tx_frame_p(DB1_DAC_FRAME_P), .tx_frame_n(DB1_DAC_FRAME_N), + .tx_d_p({DB1_DAC_D7_P,DB1_DAC_D6_P,DB1_DAC_D5_P,DB1_DAC_D4_P,DB1_DAC_D3_P,DB1_DAC_D2_P,DB1_DAC_D1_P,DB1_DAC_D0_P}), + .tx_d_n({DB1_DAC_D7_N,DB1_DAC_D6_N,DB1_DAC_D5_N,DB1_DAC_D4_N,DB1_DAC_D3_N,DB1_DAC_D2_N,DB1_DAC_D1_N,DB1_DAC_D0_N}), + .tx_clk_2x(radio_clk_2x), .tx_clk_1x(radio_clk), .tx_dci_clk(dac_dci_clk), + .i(~tx1[31:16]), .q(~tx1[15:0]), // invert b/c Analog diff pairs are swapped for layout + .sync_dacs(radio0_misc_out[10]|radio1_misc_out[10]) + ); + + + wire [1:0] leds; + assign {LED_LINKSTAT, LED_LINKACT} = ~leds; + + wire [31:0] debug; + + ////////////////////////////////////////////////////////////////////// + // + // PCIe Stuff + // + ////////////////////////////////////////////////////////////////////// + + localparam IOP2_MSG_WIDTH = 64; + localparam DMA_STREAM_WIDTH = `LVFPGA_IFACE_DMA_CHAN_WIDTH; + localparam DMA_COUNT_WIDTH = `LVFPGA_IFACE_DMA_SIZE_WIDTH; + localparam NUM_TX_STREAMS = `LVFPGA_IFACE_NUM_TX_DMA_CNT; + localparam NUM_RX_STREAMS = `LVFPGA_IFACE_NUM_RX_DMA_CNT; + localparam TX_STREAM_START_IDX = `LVFPGA_IFACE_TX_DMA_INDEX; + localparam RX_STREAM_START_IDX = `LVFPGA_IFACE_RX_DMA_INDEX; + localparam DMA_DEST_WIDTH = 3; + + wire [DMA_STREAM_WIDTH-1:0] dmatx_tdata, dmarx_tdata, pcii_tdata, pcio_tdata; + wire [DMA_DEST_WIDTH-1:0] dmatx_tuser, dmarx_tuser, pcii_tuser, pcio_tuser; + wire dmatx_tvalid, dmarx_tvalid, pcii_tvalid, pcio_tvalid; + wire dmatx_tlast, dmarx_tlast, pcii_tlast, pcio_tlast; + wire dmatx_tready, dmarx_tready, pcii_tready, pcio_tready; + + wire [IOP2_MSG_WIDTH-1:0] o_iop2_msg_tdata, i_iop2_msg_tdata; + wire o_iop2_msg_tvalid, o_iop2_msg_tlast, o_iop2_msg_tready; + wire i_iop2_msg_tvalid, i_iop2_msg_tlast, i_iop2_msg_tready; + + wire pcie_usr_reg_wr, pcie_usr_reg_rd, pcie_usr_reg_rc, pcie_usr_reg_rdy; + wire [1:0] pcie_usr_reg_len; + wire [19:0] pcie_usr_reg_addr; + wire [31:0] pcie_usr_reg_data_in, pcie_usr_reg_data_out; + + wire chinch_reg_wr, chinch_reg_rd, chinch_reg_rc, chinch_reg_rdy; + wire [1:0] chinch_reg_len; + wire [19:0] chinch_reg_addr; + wire [31:0] chinch_reg_data_out; + wire [63:0] chinch_reg_data_in; + + wire [(NUM_TX_STREAMS*DMA_STREAM_WIDTH)-1:0] dmatx_tdata_iop2; + wire [NUM_TX_STREAMS-1:0] dmatx_tvalid_iop2, dmatx_tready_iop2; + + wire [(NUM_RX_STREAMS*DMA_STREAM_WIDTH)-1:0] dmarx_tdata_iop2; + wire [NUM_RX_STREAMS-1:0] dmarx_tvalid_iop2, dmarx_tready_iop2; + + //PCIe Express "Physical" DMA and Register logic + LvFpga_Chinch_Interface lvfpga_chinch_inst + ( + .aIoResetIn_n(aIoResetIn_n), + .bBusReset(), //Output + + // Clocks + .BusClk(ioport2_clk), + .Rio40Clk(rio40_clk), + .IDelayRefClk(ioport2_idelay_ref_clk), + .aRioClkPllLocked(rio40_clk_locked), + .aRioClkPllReset(rio40_clk_reset), + + // The IO_Port2 asynchronous handshaking pins + .aIoReadyOut(aIoReadyOut), + .aIoReadyIn(aIoReadyIn), + .aIoPort2Restart(aIoPort2Restart), + + // The IO_Port2 high speed receiver pins + .IoRxClock(IoRxClock), + .IoRxClock_n(IoRxClock_n), + .irIoRxData(irIoRxData), + .irIoRxData_n(irIoRxData_n), + .irIoRxHeader(irIoRxHeader), + .irIoRxHeader_n(irIoRxHeader_n), + + // The IO_Port2 high speed transmitter interface pins + .IoTxClock(IoTxClock), + .IoTxClock_n(IoTxClock_n), + .itIoTxData(itIoTxData), + .itIoTxData_n(itIoTxData_n), + .itIoTxHeader(itIoTxHeader), + .itIoTxHeader_n(itIoTxHeader_n), + + // DMA TX Fifos + .bDmaTxData(dmatx_tdata_iop2), + .bDmaTxValid(dmatx_tvalid_iop2), + .bDmaTxReady(dmatx_tready_iop2), + .bDmaTxEnabled(), + .bDmaTxFifoFullCnt(), + + // DMA RX Fifos + .bDmaRxData(dmarx_tdata_iop2), + .bDmaRxValid(dmarx_tvalid_iop2), + .bDmaRxReady(dmarx_tready_iop2), + .bDmaRxEnabled(), + .bDmaRxFifoFreeCnt(), + + // User Register Port In + .bUserRegPortInWt(pcie_usr_reg_wr), + .bUserRegPortInRd(pcie_usr_reg_rd), + .bUserRegPortInAddr(pcie_usr_reg_addr), + .bUserRegPortInData(pcie_usr_reg_data_in), + .bUserRegPortInSize(pcie_usr_reg_len), + + // User Register Port Out + .bUserRegPortOutData(pcie_usr_reg_data_out), + .bUserRegPortOutDataValid(pcie_usr_reg_rc), + .bUserRegPortOutReady(pcie_usr_reg_rdy), + + // Chinch Register Port Out + .bChinchRegPortOutWt(chinch_reg_wr), + .bChinchRegPortOutRd(chinch_reg_rd), + .bChinchRegPortOutAddr({12'h0, chinch_reg_addr}), + .bChinchRegPortOutData({32'h0, chinch_reg_data_out}), + .bChinchRegPortOutSize(chinch_reg_len), + + // User Register Port In + .bChinchRegPortInData(chinch_reg_data_in), + .bChinchRegPortInDataValid(chinch_reg_rc), + .bChinchRegPortInReady(chinch_reg_rdy), + + // Level interrupt + .aIrq(aIrq) + ); + + //PCIe Express adapter logic to link to the AXI crossbar and the WB bus + x300_pcie_int #( + .DMA_STREAM_WIDTH(DMA_STREAM_WIDTH), + .NUM_TX_STREAMS(NUM_TX_STREAMS), + .NUM_RX_STREAMS(NUM_RX_STREAMS), + .REGPORT_ADDR_WIDTH(20), + .REGPORT_DATA_WIDTH(32), + .IOP2_MSG_WIDTH(IOP2_MSG_WIDTH), + .BUS_CLK_RATE(BUS_CLK_RATE) + ) x300_pcie_int ( + .ioport2_clk(ioport2_clk), + .bus_clk(bus_clk), + .bus_rst(bus_rst), + + //DMA TX FIFOs (IoPort2 Clock Domain) + .dmatx_tdata_iop2(dmatx_tdata_iop2), + .dmatx_tvalid_iop2(dmatx_tvalid_iop2), + .dmatx_tready_iop2(dmatx_tready_iop2), + + //DMA TX FIFOs (IoPort2 Clock Domain) + .dmarx_tdata_iop2(dmarx_tdata_iop2), + .dmarx_tvalid_iop2(dmarx_tvalid_iop2), + .dmarx_tready_iop2(dmarx_tready_iop2), + + //PCIe User Regport + .pcie_usr_reg_wr(pcie_usr_reg_wr), + .pcie_usr_reg_rd(pcie_usr_reg_rd), + .pcie_usr_reg_addr(pcie_usr_reg_addr), + .pcie_usr_reg_data_in(pcie_usr_reg_data_in), + .pcie_usr_reg_len(pcie_usr_reg_len), + .pcie_usr_reg_data_out(pcie_usr_reg_data_out), + .pcie_usr_reg_rc(pcie_usr_reg_rc), + .pcie_usr_reg_rdy(pcie_usr_reg_rdy), + + //Chinch Regport + .chinch_reg_wr(chinch_reg_wr), + .chinch_reg_rd(chinch_reg_rd), + .chinch_reg_addr(chinch_reg_addr), + .chinch_reg_data_out(chinch_reg_data_out), + .chinch_reg_len(chinch_reg_len), + .chinch_reg_data_in(chinch_reg_data_in[31:0]), + .chinch_reg_rc(chinch_reg_rc), + .chinch_reg_rdy(chinch_reg_rdy), + + //DMA TX FIFO (Bus Clock Domain). Note: tuser is used for muxing. + .dmatx_tdata(dmatx_tdata), + .dmatx_tuser(dmatx_tuser), + .dmatx_tlast(dmatx_tlast), + .dmatx_tvalid(dmatx_tvalid), + .dmatx_tready(dmatx_tready), + + //DMA RX FIFO (Bus Clock Domain). Note: tuser is used for muxing. + .dmarx_tdata(dmarx_tdata), + .dmarx_tuser(dmarx_tuser), + .dmarx_tlast(dmarx_tlast), + .dmarx_tvalid(dmarx_tvalid), + .dmarx_tready(dmarx_tready), + + //Message FIFO Out (Bus Clock Domain) + .rego_tdata(o_iop2_msg_tdata), + .rego_tvalid(o_iop2_msg_tvalid), + .rego_tlast(o_iop2_msg_tlast), + .rego_tready(o_iop2_msg_tready), + + //Message FIFO In (Bus Clock Domain) + .regi_tdata(i_iop2_msg_tdata), + .regi_tvalid(i_iop2_msg_tvalid), + .regi_tlast(i_iop2_msg_tlast), + .regi_tready(i_iop2_msg_tready), + + //Misc + .misc_status({15'h0, aStc3Gpio7}), + .debug() + ); + + // The PCIe logic will tend to stay close to the physical IoPort2 pins + // so add an additional stage of pipelining to give the tool more routing + // slack. This is significantly help timing closure. + + axi_fifo_short #(.WIDTH(DMA_STREAM_WIDTH+1+DMA_DEST_WIDTH)) pcii_pipeline_srl ( + .clk(bus_clk), .reset(bus_rst), .clear(1'b0), + .i_tdata({dmatx_tuser, dmatx_tlast, dmatx_tdata}), .i_tvalid(dmatx_tvalid), .i_tready(dmatx_tready), + .o_tdata({pcii_tuser, pcii_tlast, pcii_tdata}), .o_tvalid(pcii_tvalid), .o_tready(pcii_tready), + .space(), .occupied()); + + axi_fifo_short #(.WIDTH(DMA_STREAM_WIDTH+1+DMA_DEST_WIDTH)) pcio_pipeline_srl ( + .clk(bus_clk), .reset(bus_rst), .clear(1'b0), + .i_tdata({pcio_tuser, pcio_tlast, pcio_tdata}), .i_tvalid(pcio_tvalid), .i_tready(pcio_tready), + .o_tdata({dmarx_tuser, dmarx_tlast, dmarx_tdata}), .o_tvalid(dmarx_tvalid), .o_tready(dmarx_tready), + .space(), .occupied()); + + ////////////////////////////////////////////////////////////////////// + // + // Configure SFP+ clocking + // + ////////////////////////////////////////////////////////////////////// +`ifdef BUILD_1G + wire gige_refclk, gige_refclk_bufg; + + one_gige_phy_clk_gen gige_clk_gen_i ( + .refclk_p(ETH_CLK_p), + .refclk_n(ETH_CLK_n), + .refclk(gige_refclk), + .refclk_bufg(gige_refclk_bufg) + ); +`endif +`ifdef BUILD_10G + wire xgige_refclk; + wire xgige_clk156; + wire xgige_dclk; + + ten_gige_phy_clk_gen xgige_clk_gen_i ( + .areset(global_rst | sw_rst[0]), + .refclk_p(XG_CLK_p), + .refclk_n(XG_CLK_n), + .refclk(xgige_refclk), + .clk156(xgige_clk156), + .dclk(xgige_dclk) + ); + `ifdef BUILD_AURORA + wire aurora_refclk = xgige_refclk; + wire aurora_refclk_bufg = xgige_clk156; + wire aurora_init_clk = xgige_dclk; + `endif +`else + `ifdef BUILD_AURORA + wire aurora_refclk; + wire aurora_refclk_bufg; + wire aurora_init_clk; + + aurora_phy_clk_gen aurora_clk_gen_i ( + .areset(global_rst | sw_rst[0]), + .refclk_p(XG_CLK_p), + .refclk_n(XG_CLK_n), + .refclk(aurora_refclk), + .clk156(aurora_refclk_bufg), + .init_clk(aurora_init_clk) + ); + `endif +`endif + + wire sfp0_gt_refclk, sfp1_gt_refclk; + wire sfp0_gb_refclk, sfp1_gb_refclk; + wire sfp0_misc_clk, sfp1_misc_clk; + +`ifdef SFP0_10GBE + assign sfp0_gt_refclk = xgige_refclk; + assign sfp0_gb_refclk = xgige_clk156; + assign sfp0_misc_clk = xgige_dclk; +`endif +`ifdef SFP0_1GBE + assign sfp0_gt_refclk = gige_refclk; + assign sfp0_gb_refclk = gige_refclk_bufg; + assign sfp0_misc_clk = gige_refclk_bufg; +`endif +`ifdef SFP0_AURORA + assign sfp0_gt_refclk = aurora_refclk; + assign sfp0_gb_refclk = aurora_refclk_bufg; + assign sfp0_misc_clk = aurora_init_clk; +`endif + +`ifdef SFP1_10GBE + assign sfp1_gt_refclk = xgige_refclk; + assign sfp1_gb_refclk = xgige_clk156; + assign sfp1_misc_clk = xgige_dclk; +`endif +`ifdef SFP1_1GBE + assign sfp1_gt_refclk = gige_refclk; + assign sfp1_gb_refclk = gige_refclk_bufg; + assign sfp1_misc_clk = gige_refclk_bufg; +`endif +`ifdef SFP1_AURORA + assign sfp1_gt_refclk = aurora_refclk; + assign sfp1_gb_refclk = aurora_refclk_bufg; + assign sfp1_misc_clk = aurora_init_clk; +`endif + + ////////////////////////////////////////////////////////////////////// + // + // SFP+ PORT0 + // + ////////////////////////////////////////////////////////////////////// + + wire [63:0] sfp0_rx_tdata, sfp0_tx_tdata; + wire [3:0] sfp0_rx_tuser, sfp0_tx_tuser; + wire sfp0_rx_tlast, sfp0_tx_tlast, sfp0_rx_tvalid, sfp0_tx_tvalid, sfp0_rx_tready, sfp0_tx_tready; + wire [15:0] sfp0_phy_status; + + wire [31:0] sfp0_wb_dat_i; + wire [31:0] sfp0_wb_dat_o; + wire [15:0] sfp0_wb_adr; + wire sfp0_wb_ack, sfp0_wb_stb, sfp0_wb_cyc, sfp0_wb_we, sfp0_wb_int; + + wire sfp0_link_up, sfp0_activity; + + x300_sfpp_io_core #( +`ifdef SFP0_10GBE + .PROTOCOL("10GbE"), +`endif +`ifdef SFP0_1GBE + .PROTOCOL("1GbE"), +`endif +`ifdef SFP0_AURORA + .PROTOCOL("Aurora"), +`endif + .PORTNUM(8'd0) + ) sfpp_io_i0 ( + .areset(global_rst | sw_rst[0]), + .gt_refclk(sfp0_gt_refclk), + .gb_refclk(sfp0_gb_refclk), + .misc_clk(sfp0_misc_clk), + + .bus_rst(bus_rst), + .bus_clk(bus_clk), + .bus_rst_div2(bus_rst_div2), + .bus_clk_div2(bus_clk_div2), + + .txp(SFP0_TX_p), + .txn(SFP0_TX_n), + .rxp(SFP0_RX_p), + .rxn(SFP0_RX_n), + + .sfpp_rxlos(SFPP0_RxLOS), + .sfpp_tx_fault(SFPP0_TxFault), + .sfpp_tx_disable(SFPP0_TxDisable), + + .s_axis_tdata(sfp0_tx_tdata), + .s_axis_tuser(sfp0_tx_tuser), + .s_axis_tlast(sfp0_tx_tlast), + .s_axis_tvalid(sfp0_tx_tvalid), + .s_axis_tready(sfp0_tx_tready), + + .m_axis_tdata(sfp0_rx_tdata), + .m_axis_tuser(sfp0_rx_tuser), + .m_axis_tlast(sfp0_rx_tlast), + .m_axis_tvalid(sfp0_rx_tvalid), + .m_axis_tready(sfp0_rx_tready), + + .wb_adr_i(sfp0_wb_adr), + .wb_cyc_i(sfp0_wb_cyc), + .wb_dat_i(sfp0_wb_dat_o), + .wb_stb_i(sfp0_wb_stb), + .wb_we_i(sfp0_wb_we), + .wb_ack_o(sfp0_wb_ack), + .wb_dat_o(sfp0_wb_dat_i), + .wb_int_o(sfp0_wb_int), + + .phy_status(sfp0_phy_status), + .link_up(sfp0_link_up), + .activity(sfp0_activity) + ); + + // LEDs are driven with negative logic. + assign LED_LINK2 = ~sfp0_link_up; + assign LED_ACT2 = ~sfp0_activity; + + + ////////////////////////////////////////////////////////////////////// + // + // SFP+ PORT1 + // + ////////////////////////////////////////////////////////////////////// + + wire [63:0] sfp1_rx_tdata, sfp1_tx_tdata; + wire [3:0] sfp1_rx_tuser, sfp1_tx_tuser; + wire sfp1_rx_tlast, sfp1_tx_tlast, sfp1_rx_tvalid, sfp1_tx_tvalid, sfp1_rx_tready, sfp1_tx_tready; + wire [15:0] sfp1_phy_status; + + wire [31:0] sfp1_wb_dat_i; + wire [31:0] sfp1_wb_dat_o; + wire [15:0] sfp1_wb_adr; + wire sfp1_wb_ack, sfp1_wb_stb, sfp1_wb_cyc, sfp1_wb_we, sfp1_wb_int; + + wire sfp1_link_up, sfp1_activity; + + x300_sfpp_io_core #( +`ifdef SFP1_10GBE + .PROTOCOL("10GbE"), +`endif +`ifdef SFP1_1GBE + .PROTOCOL("1GbE"), +`endif +`ifdef SFP1_AURORA + .PROTOCOL("Aurora"), +`endif + .PORTNUM(8'd1) + ) sfpp_io_i1 ( + .areset(global_rst | sw_rst[0]), + .gt_refclk(sfp1_gt_refclk), + .gb_refclk(sfp1_gb_refclk), + .misc_clk(sfp1_misc_clk), + + .bus_rst(bus_rst), + .bus_clk(bus_clk), + .bus_rst_div2(bus_rst_div2), + .bus_clk_div2(bus_clk_div2), + + .txp(SFP1_TX_p), + .txn(SFP1_TX_n), + .rxp(SFP1_RX_p), + .rxn(SFP1_RX_n), + + .sfpp_rxlos(SFPP1_RxLOS), + .sfpp_tx_fault(SFPP1_TxFault), + .sfpp_tx_disable(SFPP1_TxDisable), + + .s_axis_tdata(sfp1_tx_tdata), + .s_axis_tuser(sfp1_tx_tuser), + .s_axis_tlast(sfp1_tx_tlast), + .s_axis_tvalid(sfp1_tx_tvalid), + .s_axis_tready(sfp1_tx_tready), + + .m_axis_tdata(sfp1_rx_tdata), + .m_axis_tuser(sfp1_rx_tuser), + .m_axis_tlast(sfp1_rx_tlast), + .m_axis_tvalid(sfp1_rx_tvalid), + .m_axis_tready(sfp1_rx_tready), + + .wb_adr_i(sfp1_wb_adr), + .wb_cyc_i(sfp1_wb_cyc), + .wb_dat_i(sfp1_wb_dat_o), + .wb_stb_i(sfp1_wb_stb), + .wb_we_i(sfp1_wb_we), + .wb_ack_o(sfp1_wb_ack), + .wb_dat_o(sfp1_wb_dat_i), + .wb_int_o(sfp1_wb_int), + + .phy_status(sfp1_phy_status), + .link_up(sfp1_link_up), + .activity(sfp1_activity) + ); + + // LEDs are driven with negative logic. + assign LED_LINK1 = ~sfp1_link_up; + assign LED_ACT1 = ~sfp1_activity; + + /////////////////////////////////////////////////////////////////////////////////// + // + // Synchronize misc asynchronous signals + // + /////////////////////////////////////////////////////////////////////////////////// + wire LMK_Holdover_sync, LMK_Lock_sync, LMK_Sync_sync; + wire LMK_Status0_sync, LMK_Status1_sync; + wire radio_clk_locked_sync; + wire adc_idlyctrl_rdy_sync; + + //Sync all LMK_* signals to bus_clk + synchronizer #(.INITIAL_VAL(1'b0)) LMK_Holdover_sync_inst ( + .clk(bus_clk), .rst(1'b0 /* no reset */), .in(LMK_Holdover), .out(LMK_Holdover_sync)); + synchronizer #(.INITIAL_VAL(1'b0)) LMK_Lock_sync_inst ( + .clk(bus_clk), .rst(1'b0 /* no reset */), .in(LMK_Lock), .out(LMK_Lock_sync)); + synchronizer #(.INITIAL_VAL(1'b0)) LMK_Sync_sync_inst ( + .clk(bus_clk), .rst(1'b0 /* no reset */), .in(LMK_Sync), .out(LMK_Sync_sync)); + //The status bits (although in a bus) are really independent + synchronizer #(.INITIAL_VAL(1'b0)) LMK_Status0_sync_inst ( + .clk(bus_clk), .rst(1'b0 /* no reset */), .in(LMK_Status[0]), .out(LMK_Status0_sync)); + synchronizer #(.INITIAL_VAL(1'b0)) LMK_Status1_sync_inst ( + .clk(bus_clk), .rst(1'b0 /* no reset */), .in(LMK_Status[1]), .out(LMK_Status1_sync)); + + synchronizer #(.INITIAL_VAL(1'b0)) radio_clk_locked_sync_inst ( + .clk(bus_clk), .rst(1'b0 /* no reset */), .in(radio_clk_locked), .out(radio_clk_locked_sync)); + synchronizer #(.INITIAL_VAL(1'b0)) adc_idlyctrl_rdy_sync_inst ( + .clk(bus_clk), .rst(1'b0 /* no reset */), .in(adc_idlyctrl_rdy), .out(adc_idlyctrl_rdy_sync)); + + /////////////////////////////////////////////////////////////////////////////////// + // + // Xilinx DDR3 Controller and PHY. + // + /////////////////////////////////////////////////////////////////////////////////// + + + wire ddr3_axi_clk; // 1/4 DDR external clock rate (150MHz) + wire ddr3_axi_clk_x2; // 1/2 DDR external clock rate (300MHz) + wire ddr3_axi_rst; // Synchronized to ddr_sys_clk + wire ddr3_running; // DRAM calibration complete. + wire [11:0] device_temp; + + // Slave Interface Write Address Ports + wire s_axi_awid; + wire [31:0] s_axi_awaddr; + wire [7:0] s_axi_awlen; + wire [2:0] s_axi_awsize; + wire [1:0] s_axi_awburst; + wire [0:0] s_axi_awlock; + wire [3:0] s_axi_awcache; + wire [2:0] s_axi_awprot; + wire [3:0] s_axi_awqos; + wire s_axi_awvalid; + wire s_axi_awready; + // Slave Interface Write Data Ports + wire [255:0] s_axi_wdata; + wire [31:0] s_axi_wstrb; + wire s_axi_wlast; + wire s_axi_wvalid; + wire s_axi_wready; + // Slave Interface Write Response Ports + wire s_axi_bready; + wire s_axi_bid; + wire [1:0] s_axi_bresp; + wire s_axi_bvalid; + // Slave Interface Read Address Ports + wire s_axi_arid; + wire [31:0] s_axi_araddr; + wire [7:0] s_axi_arlen; + wire [2:0] s_axi_arsize; + wire [1:0] s_axi_arburst; + wire [0:0] s_axi_arlock; + wire [3:0] s_axi_arcache; + wire [2:0] s_axi_arprot; + wire [3:0] s_axi_arqos; + wire s_axi_arvalid; + wire s_axi_arready; + // Slave Interface Read Data Ports + wire s_axi_rready; + wire s_axi_rid; + wire [255:0] s_axi_rdata; + wire [1:0] s_axi_rresp; + wire s_axi_rlast; + wire s_axi_rvalid; + + wire ddr3_idelay_refclk; + reg ddr3_axi_rst_reg_n; + + // Copied this reset circuit from example design. + always @(posedge ddr3_axi_clk) + ddr3_axi_rst_reg_n <= ~ddr3_axi_rst; + + // Instantiate the DDR3 MIG core + ddr3_32bit u_ddr3_32bit ( + // Memory interface ports + .ddr3_addr (ddr3_addr), + .ddr3_ba (ddr3_ba), + .ddr3_cas_n (ddr3_cas_n), + .ddr3_ck_n (ddr3_ck_n), + .ddr3_ck_p (ddr3_ck_p), + .ddr3_cke (ddr3_cke), + .ddr3_ras_n (ddr3_ras_n), + .ddr3_reset_n (ddr3_reset_n), + .ddr3_we_n (ddr3_we_n), + .ddr3_dq (ddr3_dq), + .ddr3_dqs_n (ddr3_dqs_n), + .ddr3_dqs_p (ddr3_dqs_p), + .ddr3_cs_n (ddr3_cs_n), + .ddr3_dm (ddr3_dm), + .ddr3_odt (ddr3_odt), + .init_calib_complete (ddr3_running), + .device_temp_i (device_temp), + // Application interface ports + .ui_clk (ddr3_axi_clk), // 150MHz clock out + .ui_addn_clk_0 (ddr3_axi_clk_x2), // 300MHz clock out + .ui_addn_clk_1 (ddr3_idelay_refclk), + .ui_addn_clk_2 (), + .ui_addn_clk_3 (), + .ui_addn_clk_4 (), + .clk_ref_i (ddr3_idelay_refclk), + .ui_clk_sync_rst (ddr3_axi_rst), // Active high Reset signal synchronised to 150MHz + .aresetn (ddr3_axi_rst_reg_n), + .app_sr_req (1'b0), + .app_sr_active (), + .app_ref_req (1'b0), + .app_ref_ack (), + .app_zq_req (1'b0), + .app_zq_ack (), + + // Slave Interface Write Address Ports + .s_axi_awid (s_axi_awid), + .s_axi_awaddr (s_axi_awaddr), + .s_axi_awlen (s_axi_awlen), + .s_axi_awsize (s_axi_awsize), + .s_axi_awburst (s_axi_awburst), + .s_axi_awlock (s_axi_awlock), + .s_axi_awcache (s_axi_awcache), + .s_axi_awprot (s_axi_awprot), + .s_axi_awqos (s_axi_awqos), + .s_axi_awvalid (s_axi_awvalid), + .s_axi_awready (s_axi_awready), + // Slave Interface Write Data Ports + .s_axi_wdata (s_axi_wdata), + .s_axi_wstrb (s_axi_wstrb), + .s_axi_wlast (s_axi_wlast), + .s_axi_wvalid (s_axi_wvalid), + .s_axi_wready (s_axi_wready), + // Slave Interface Write Response Ports + .s_axi_bid (s_axi_bid), + .s_axi_bresp (s_axi_bresp), + .s_axi_bvalid (s_axi_bvalid), + .s_axi_bready (s_axi_bready), + // Slave Interface Read Address Ports + .s_axi_arid (s_axi_arid), + .s_axi_araddr (s_axi_araddr), + .s_axi_arlen (s_axi_arlen), + .s_axi_arsize (s_axi_arsize), + .s_axi_arburst (s_axi_arburst), + .s_axi_arlock (s_axi_arlock), + .s_axi_arcache (s_axi_arcache), + .s_axi_arprot (s_axi_arprot), + .s_axi_arqos (s_axi_arqos), + .s_axi_arvalid (s_axi_arvalid), + .s_axi_arready (s_axi_arready), + // Slave Interface Read Data Ports + .s_axi_rid (s_axi_rid), + .s_axi_rdata (s_axi_rdata), + .s_axi_rresp (s_axi_rresp), + .s_axi_rlast (s_axi_rlast), + .s_axi_rvalid (s_axi_rvalid), + .s_axi_rready (s_axi_rready), + // System Clock Ports + .sys_clk_i (sys_clk_i), // From external 100MHz source. + .sys_rst (global_rst) + ); + + // Temperature monitor module + mig_7series_v4_2_tempmon #( + .TEMP_MON_CONTROL("INTERNAL"), .XADC_CLK_PERIOD(8000 /* 125MHz clock period in ps */) + ) tempmon_i ( + .clk(bus_clk), .xadc_clk(ioport2_clk), .rst(bus_rst), + .device_temp_i(12'd0 /* ignored */), .device_temp(device_temp) + ); + + ///////////////////////////////////////////////////////////////////// + // + // Daughterboard GPIO and Debug UART + // + ////////////////////////////////////////////////////////////////////// + + wire [31:0] db0_gpio_in, db0_gpio_out, db0_gpio_ddr; + wire [31:0] db1_gpio_in, db1_gpio_out, db1_gpio_ddr; + wire [31:0] fp_gpio_in, fp_gpio_out, fp_gpio_ddr; + wire debug_txd, debug_rxd; + + gpio_atr_io #(.WIDTH(32)) gpio_atr_db0_inst ( + .clk(radio_clk), .gpio_pins({DB0_TX_IO,DB0_RX_IO}), + .gpio_ddr(db0_gpio_ddr), .gpio_out(db0_gpio_out), .gpio_in(db0_gpio_in) + ); + + gpio_atr_io #(.WIDTH(32)) gpio_atr_db1_inst ( + .clk(radio_clk), .gpio_pins({DB1_TX_IO,DB1_RX_IO}), + .gpio_ddr(db1_gpio_ddr), .gpio_out(db1_gpio_out), .gpio_in(db1_gpio_in) + ); + +`ifdef DEBUG_UART + gpio_atr_io #(.WIDTH(10)) fp_gpio_atr_inst ( + .clk(radio_clk), .gpio_pins(FrontPanelGpio[9:0]), + .gpio_ddr(fp_gpio_ddr[9:0]), .gpio_out(fp_gpio_out[9:0]), .gpio_in(fp_gpio_in[9:0]) + ); + assign FrontPanelGpio[11] = debug_txd; + assign debug_rxd = FrontPanelGpio[10]; +`else + gpio_atr_io #(.WIDTH(12)) fp_gpio_atr_inst ( + .clk(radio_clk), .gpio_pins(FrontPanelGpio[11:0]), + .gpio_ddr(fp_gpio_ddr[11:0]), .gpio_out(fp_gpio_out[11:0]), .gpio_in(fp_gpio_in[11:0]) + ); + assign debug_rxd = 1'b0; +`endif + assign fp_gpio_in[31:12] = 20'h0; + + /////////////////////////////////////////////////////////////////////////////////// + // + // X300 Core + // + /////////////////////////////////////////////////////////////////////////////////// + + x300_core #( .BUS_CLK_RATE(BUS_CLK_RATE) ) x300_core ( + .radio_clk(radio_clk), .radio_rst(radio_rst), + .bus_clk(bus_clk), .bus_rst(bus_rst), .sw_rst(sw_rst), + .bus_clk_div2(bus_clk_div2), + .ce_clk(ce_clk), + .ce_rst(ce_rst), + // Radio0 signals + .rx0(rx0), .tx0(tx0), + .db0_gpio_in(db0_gpio_in), .db0_gpio_out(db0_gpio_out), .db0_gpio_ddr(db0_gpio_ddr), + .fp_gpio_in(fp_gpio_in), .fp_gpio_out(fp_gpio_out), .fp_gpio_ddr(fp_gpio_ddr), + .sen0(sen0), .sclk0(sclk0), .mosi0(mosi0), .miso0(miso0), + .radio_led0(led0), .radio0_misc_out(radio0_misc_out), .radio0_misc_in(radio0_misc_in), + // Radio1 signals + .rx1(rx1), .tx1(tx1), + .db1_gpio_in(db1_gpio_in), .db1_gpio_out(db1_gpio_out), .db1_gpio_ddr(db1_gpio_ddr), + .sen1(sen1), .sclk1(sclk1), .mosi1(mosi1), .miso1(miso1), + .radio_led1(led1), .radio1_misc_out(radio1_misc_out), .radio1_misc_in(radio1_misc_in), + // I2C bus + .db_scl(DB_SCL), .db_sda(DB_SDA), + // External clock gen + .ext_ref_clk(ref_clk), + .clock_ref_sel(ClockRefSelect), + .clock_misc_opt({GPSDO_PWR_ENA, TCXO_ENA}), + .LMK_Status({LMK_Status1_sync, LMK_Status0_sync}), .LMK_Holdover(LMK_Holdover_sync), .LMK_Lock(LMK_Lock_sync), .LMK_Sync(LMK_Sync_sync), + .LMK_SEN(LMK_SEN), .LMK_SCLK(LMK_SCLK), .LMK_MOSI(LMK_MOSI), + .misc_clock_status({1'b0, adc_idlyctrl_rdy_sync, radio_clk_locked_sync}), + // SFP+ 0 flags + .SFPP0_SCL(SFPP0_SCL), .SFPP0_SDA(SFPP0_SDA), .SFPP0_ModAbs(SFPP0_ModAbs), .SFPP0_TxFault(SFPP0_TxFault), + .SFPP0_RxLOS(SFPP0_RxLOS), .SFPP0_RS1(SFPP0_RS1), .SFPP0_RS0(SFPP0_RS0), + // SFP+ 1 flags + .SFPP1_SCL(SFPP1_SCL), .SFPP1_SDA(SFPP1_SDA), .SFPP1_ModAbs(SFPP1_ModAbs), .SFPP1_TxFault(SFPP1_TxFault), + .SFPP1_RxLOS(SFPP1_RxLOS), .SFPP1_RS1(SFPP1_RS1), .SFPP1_RS0(SFPP1_RS0), + // SFP+ 0 data stream + .sfp0_tx_tdata(sfp0_tx_tdata), .sfp0_tx_tuser(sfp0_tx_tuser), .sfp0_tx_tlast(sfp0_tx_tlast), + .sfp0_tx_tvalid(sfp0_tx_tvalid), .sfp0_tx_tready(sfp0_tx_tready), + .sfp0_rx_tdata(sfp0_rx_tdata), .sfp0_rx_tuser(sfp0_rx_tuser), .sfp0_rx_tlast(sfp0_rx_tlast), + .sfp0_rx_tvalid(sfp0_rx_tvalid), .sfp0_rx_tready(sfp0_rx_tready), + .sfp0_phy_status(sfp0_phy_status), + // SFP+ 1 data stream + .sfp1_tx_tdata(sfp1_tx_tdata), .sfp1_tx_tuser(sfp1_tx_tuser), .sfp1_tx_tlast(sfp1_tx_tlast), + .sfp1_tx_tvalid(sfp1_tx_tvalid), .sfp1_tx_tready(sfp1_tx_tready), + .sfp1_rx_tdata(sfp1_rx_tdata), .sfp1_rx_tuser(sfp1_rx_tuser), .sfp1_rx_tlast(sfp1_rx_tlast), + .sfp1_rx_tvalid(sfp1_rx_tvalid), .sfp1_rx_tready(sfp1_rx_tready), + .sfp1_phy_status(sfp1_phy_status), + // Wishbone Slave Interface(s) + .sfp0_wb_dat_i(sfp0_wb_dat_i), .sfp0_wb_dat_o(sfp0_wb_dat_o), .sfp0_wb_adr(sfp0_wb_adr), + .sfp0_wb_sel(), .sfp0_wb_ack(sfp0_wb_ack), .sfp0_wb_stb(sfp0_wb_stb), + .sfp0_wb_cyc(sfp0_wb_cyc), .sfp0_wb_we(sfp0_wb_we), .sfp0_wb_int(sfp0_wb_int), + .sfp1_wb_dat_i(sfp1_wb_dat_i), .sfp1_wb_dat_o(sfp1_wb_dat_o), .sfp1_wb_adr(sfp1_wb_adr), + .sfp1_wb_sel(), .sfp1_wb_ack(sfp1_wb_ack), .sfp1_wb_stb(sfp1_wb_stb), + .sfp1_wb_cyc(sfp1_wb_cyc), .sfp1_wb_we(sfp1_wb_we), .sfp1_wb_int(sfp1_wb_int), + // Time + .pps(pps),.pps_select(pps_select), .pps_out_enb(pps_out_enb), + .ref_freq(ref_freq), .ref_freq_changed(ref_freq_changed), + // GPS Signals + .gps_txd(GPS_SER_IN), .gps_rxd(GPS_SER_OUT), + // Debug UART + .debug_rxd(debug_rxd), .debug_txd(debug_txd), + // Misc. + .led_misc(leds), + .xadc_readback({20'h0, device_temp}), + .debug0(), .debug1(), .debug2(), + // DRAM signals. + .ddr3_axi_clk (ddr3_axi_clk), + .ddr3_axi_clk_x2 (ddr3_axi_clk_x2), + .ddr3_axi_rst (ddr3_axi_rst), + // Slave Interface Write Address Ports + .ddr3_axi_awid (s_axi_awid), + .ddr3_axi_awaddr (s_axi_awaddr), + .ddr3_axi_awlen (s_axi_awlen), + .ddr3_axi_awsize (s_axi_awsize), + .ddr3_axi_awburst (s_axi_awburst), + .ddr3_axi_awlock (s_axi_awlock), + .ddr3_axi_awcache (s_axi_awcache), + .ddr3_axi_awprot (s_axi_awprot), + .ddr3_axi_awqos (s_axi_awqos), + .ddr3_axi_awvalid (s_axi_awvalid), + .ddr3_axi_awready (s_axi_awready), + // Slave Interface Write Data Ports + .ddr3_axi_wdata (s_axi_wdata), + .ddr3_axi_wstrb (s_axi_wstrb), + .ddr3_axi_wlast (s_axi_wlast), + .ddr3_axi_wvalid (s_axi_wvalid), + .ddr3_axi_wready (s_axi_wready), + // Slave Interface Write Response Ports + .ddr3_axi_bid (s_axi_bid), + .ddr3_axi_bresp (s_axi_bresp), + .ddr3_axi_bvalid (s_axi_bvalid), + .ddr3_axi_bready (s_axi_bready), + // Slave Interface Read Address Ports + .ddr3_axi_arid (s_axi_arid), + .ddr3_axi_araddr (s_axi_araddr), + .ddr3_axi_arlen (s_axi_arlen), + .ddr3_axi_arsize (s_axi_arsize), + .ddr3_axi_arburst (s_axi_arburst), + .ddr3_axi_arlock (s_axi_arlock), + .ddr3_axi_arcache (s_axi_arcache), + .ddr3_axi_arprot (s_axi_arprot), + .ddr3_axi_arqos (s_axi_arqos), + .ddr3_axi_arvalid (s_axi_arvalid), + .ddr3_axi_arready (s_axi_arready), + // Slave Interface Read Data Ports + .ddr3_axi_rid (s_axi_rid), + .ddr3_axi_rdata (s_axi_rdata), + .ddr3_axi_rresp (s_axi_rresp), + .ddr3_axi_rlast (s_axi_rlast), + .ddr3_axi_rvalid (s_axi_rvalid), + .ddr3_axi_rready (s_axi_rready), + // IoPort2 Message FIFOs + .o_iop2_msg_tdata (o_iop2_msg_tdata), + .o_iop2_msg_tvalid (o_iop2_msg_tvalid), + .o_iop2_msg_tlast (o_iop2_msg_tlast), + .o_iop2_msg_tready (o_iop2_msg_tready), + .i_iop2_msg_tdata (i_iop2_msg_tdata), + .i_iop2_msg_tvalid (i_iop2_msg_tvalid), + .i_iop2_msg_tlast (i_iop2_msg_tlast), + .i_iop2_msg_tready (i_iop2_msg_tready), + // PCIe DMA Data + .pcio_tdata (pcio_tdata), + .pcio_tuser (pcio_tuser), + .pcio_tlast (pcio_tlast), + .pcio_tvalid (pcio_tvalid), + .pcio_tready (pcio_tready), + .pcii_tdata (pcii_tdata), + .pcii_tuser (pcii_tuser), + .pcii_tlast (pcii_tlast), + .pcii_tvalid (pcii_tvalid), + .pcii_tready (pcii_tready) + ); + + assign {DB_ADC_RESET, DB_DAC_RESET,DB0_DAC_ENABLE} = radio0_misc_out[2:0]; + assign {DB1_DAC_ENABLE} = radio1_misc_out[0]; //[2:1] unused + + ///////////////////////////////////////////////////////////////////// + // + // PUDC Workaround + // + ////////////////////////////////////////////////////////////////////// + // This is a workaround for a silicon bug in Series 7 FPGA where a + // race condition with the reading of PUDC during the erase of the FPGA + // image cause glitches on output IO pins. This glitch happens even if + // you have PUDC correctly pulled high!! When PUDC is high the pull up + // resistor should never be enabled on the IO lines, however there is a + // race condition that causes this to not be the case. + // + // Workaround: + // - Define the PUDC pin in the XDC file with a pullup. + // - Implements an IBUF on the PUDC input and make sure that it does + // not get optimized out. + (* dont_touch = "true" *) wire fpga_pudc_b_buf; + IBUF pudc_ibuf_i ( + .I(FPGA_PUDC_B), + .O(fpga_pudc_b_buf)); + +endmodule // x300 |