diff options
author | Max Köhler <max.koehler@ni.com> | 2021-02-05 13:14:41 -0600 |
---|---|---|
committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2021-06-10 11:56:58 -0500 |
commit | 7015f5ed2d495f3908773b7c7d74864d0cc3871a (patch) | |
tree | e9c9f7d95f5c35c089bfc9534707934bfe41344a /fpga/usrp3/top/x400/cpld/mb_cpld.v | |
parent | 6d3765605262016a80f71e36357f749ea35cbe5a (diff) | |
download | uhd-7015f5ed2d495f3908773b7c7d74864d0cc3871a.tar.gz uhd-7015f5ed2d495f3908773b7c7d74864d0cc3871a.tar.bz2 uhd-7015f5ed2d495f3908773b7c7d74864d0cc3871a.zip |
fpga: x400: cpld: Add support for X410 motherboard CPLD
Co-authored-by: Humberto Jimenez <humberto.jimenez@ni.com>
Co-authored-by: Javier Valenzuela <javier.valenzuela@ni.com>
Diffstat (limited to 'fpga/usrp3/top/x400/cpld/mb_cpld.v')
-rw-r--r-- | fpga/usrp3/top/x400/cpld/mb_cpld.v | 1033 |
1 files changed, 1033 insertions, 0 deletions
diff --git a/fpga/usrp3/top/x400/cpld/mb_cpld.v b/fpga/usrp3/top/x400/cpld/mb_cpld.v new file mode 100644 index 000000000..4ea5dc574 --- /dev/null +++ b/fpga/usrp3/top/x400/cpld/mb_cpld.v @@ -0,0 +1,1033 @@ +// +// Copyright 2021 Ettus Research, A National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: mb_cpld +// +// Description: +// +// Top level file for the X4xx motherboard CPLD. +// +// Parameters: +// +// SIMULATION : Set to 1 to speed up simulation. +// + +`default_nettype none + + +module mb_cpld #( + parameter SIMULATION = 0 +) ( + //--------------------------------------------------------------------------- + // Clocking + //--------------------------------------------------------------------------- + + // CPLD's PLL reference clock (differential input; abbreviation: pclk) + input wire PLL_REF_CLK, + + // Reliable clock (100 MHz; differential input) + input wire CLK_100, + + //--------------------------------------------------------------------------- + // Power Supplies + //--------------------------------------------------------------------------- + + // Power supply clocks + output wire PWR_SUPPLY_CLK_CORE, + output wire PWR_SUPPLY_CLK_DDR4_S, + output wire PWR_SUPPLY_CLK_DDR4_N, + output wire PWR_SUPPLY_CLK_0P9V, + output wire PWR_SUPPLY_CLK_1P8V, + output wire PWR_SUPPLY_CLK_2P5V, + output wire PWR_SUPPLY_CLK_3P3V, + output wire PWR_SUPPLY_CLK_3P6V, + + // Power supply control + output wire PWR_EN_5V_OSC_100, + output wire PWR_EN_5V_OSC_122_88, + output wire IPASS_POWER_DISABLE, + input wire [1:0] IPASS_POWER_EN_FAULT, + + //--------------------------------------------------------------------------- + // Interfaces from/to RFSoC + //--------------------------------------------------------------------------- + + // PL SPI slave interface + input wire PL_CPLD_SCLK, + input wire PL_CPLD_MOSI, + output reg PL_CPLD_MISO, + input wire [1:0] PL_CPLD_CS_N, + + // IRQ to PL + output wire PL_CPLD_IRQ, + + // PS SPI slave interface + // Chip Selects: + // PS_CPLD_CS_N(2:0) -> binary encoded chip select + // PS_CPLD_CS_N(3) -> chip select "enable" + input wire PS_CPLD_SCLK, + input wire PS_CPLD_MOSI, + output wire PS_CPLD_MISO, + input wire [3:0] PS_CPLD_CS_N, + + //--------------------------------------------------------------------------- + // PL Interfaces to/from Motherboard + //--------------------------------------------------------------------------- + + // Clocking AUX board SPI master interface + output wire CLK_DB_SCLK, + output wire CLK_DB_MOSI, + input wire CLK_DB_MISO, + output wire CLK_DB_CS_N, + + // QSFP LEDs + // Port 0 + output wire [3:0] QSFP0_LED_ACTIVE, + output wire [3:0] QSFP0_LED_LINK, + // Port 1 + output wire [3:0] QSFP1_LED_ACTIVE, + output wire [3:0] QSFP1_LED_LINK, + + // Daughterboard control interface + // 1 -> DB1 / 0 -> DB0 + output reg [1:0] DB_CTRL_SCLK, + output reg [1:0] DB_CTRL_MOSI, + input wire [1:0] DB_CTRL_MISO, + output reg [1:0] DB_CTRL_CS_N, + output wire [1:0] DB_REF_CLK, + output wire [1:0] DB_ARST, + + // Daughterboards' JTAG master interfaces. + // 1 -> DB1 / 0 -> DB0 + output wire [1:0] DB_JTAG_TCK, + output wire [1:0] DB_JTAG_TDI, // from CPLD to DB + input wire [1:0] DB_JTAG_TDO, // from DB to CPLD + output wire [1:0] DB_JTAG_TMS, + + //--------------------------------------------------------------------------- + // PS Interfaces to/from Motherboard + //--------------------------------------------------------------------------- + + // LMK04832 SPI master interface + output wire LMK32_SCLK, + output wire LMK32_MOSI, + input wire LMK32_MISO, + output wire LMK32_CS_N, + + // TPM 2.0 SPI master interface + // Note: TPM is not currently supported + output wire TPM_SCLK, + output wire TPM_MOSI, + input wire TPM_MISO, + output wire TPM_CS_N, + + // Phase DAC SPI master interface + output wire PHASE_DAC_SCLK, + output wire PHASE_DAC_MOSI, + output wire PHASE_DAC_CS_N, + + // DIO direction control + output wire [11:0] DIO_DIRECTION_A, + output wire [11:0] DIO_DIRECTION_B, + + // Daughterboard calibration EEPROM SPI + // 1 -> DB1 / 0 -> DB0 + output wire [1:0] DB_CALEEPROM_SCLK, + output wire [1:0] DB_CALEEPROM_MOSI, + input wire [1:0] DB_CALEEPROM_MISO, + output wire [1:0] DB_CALEEPROM_CS_N, + + //--------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------- + + // This signal enables the 1.8 V and 3.3 V power supply clocks. + output wire PS_CLK_ON_CPLD, + + // iPASS control interface + input wire [1:0] IPASS_PRESENT_N, + inout wire [1:0] IPASS_SCL, + inout wire [1:0] IPASS_SDA, + + // PCIe reset to FPGA + output wire PCIE_RESET, + + // TPM reset + output wire TPM_RESET_n +); + + // SPI masters (spi_top) are limited to 64 bit transmission length + `define SPI_MAX_CHAR_64 + + `include "../../../lib/rfnoc/core/ctrlport.vh" + `include "regmap/mb_cpld_ps_regmap_utils.vh" + `include "regmap/mb_cpld_pl_regmap_utils.vh" + + //--------------------------------------------------------------------------- + // Clocks and Resets + //--------------------------------------------------------------------------- + + wire clk40, clk50, clk250; + wire pll_ref_clk_int; + + wire reset_clk50; + wire reset_clk40; + wire power_on_reset_clk100; + + wire [0:0] pll_locked_async; + wire [0:0] pll_locked_clk50; + wire [0:0] pll_locked_clk40; + + wire pll_ref_clk_en_clk50; + wire pll_ref_clk_en_pclk; + + reset_generator reliable_reset_gen_inst ( + .clk (CLK_100), + .power_on_reset (power_on_reset_clk100) + ); + + // Divide reliable clock by 2 since the design is not capable of running at + // 100 MHz. Multiple by 2.5 to get a fast clock to handle PS SPI chip select + // decoding. + pll pll_inst ( + .inclk0 (CLK_100), + .c0 (clk50), + .c1 (clk250), + .c2 (clk40), + .locked (pll_locked_async) + ); + + // Bring pll_ref_clk enable signal to the same clock domain. + synchronizer #( + .WIDTH (1), + .STAGES (2), + .INITIAL_VAL (1'b0), + .FALSE_PATH_TO_IN (1) + ) pll_ref_clk_en_sync ( + .clk (PLL_REF_CLK), + .rst (1'b0), + .in (pll_ref_clk_en_clk50), + .out (pll_ref_clk_en_pclk) + ); + + // Enable clock using ALTCLKCTRL IP. + clkctrl pll_ref_clk_ctrl_inst ( + .inclk (PLL_REF_CLK), + .ena (pll_ref_clk_en_pclk), + .outclk (pll_ref_clk_int) + ); + + // Use locked signal as reset for clk50 and clk40 clock domain + synchronizer #( + .WIDTH (1), + .STAGES (2), + .INITIAL_VAL (1'b0), + .FALSE_PATH_TO_IN (1) + ) clk50_reset_sync ( + .clk (clk50), + .rst (1'b0), + .in (pll_locked_async), + .out (pll_locked_clk50) + ); + + assign reset_clk50 = ~pll_locked_clk50; + + synchronizer #( + .WIDTH (1), + .STAGES (2), + .INITIAL_VAL (1'b0), + .FALSE_PATH_TO_IN (1) + ) clk40_reset_sync ( + .clk (clk40), + .rst (1'b0), + .in (pll_locked_async), + .out (pll_locked_clk40) + ); + + assign reset_clk40 = ~pll_locked_clk40; + + //--------------------------------------------------------------------------- + // Power Supply Clock + //--------------------------------------------------------------------------- + + // Frequency definitions + localparam SOUCE_CLOCK_FREQUENCY = 100_000_000; + localparam TARGET_FREQUENCY_350k = 350_000; + localparam TARGET_FREQUENCY_450k = 450_000; + localparam TARGET_FREQUENCY_500k = 500_000; + localparam TARGET_FREQUENCY_600k = 600_000; + localparam TARGET_FREQUENCY_800k = 800_000; + localparam TARGET_FREQUENCY_1M = 1_000_000; + + pwr_supply_clk_gen #( + .SOURCE_CLK_FREQ (SOUCE_CLOCK_FREQUENCY), + .TARGET_CLK_FREQ (TARGET_FREQUENCY_350k) + ) freq_gen_350k ( + .clk (CLK_100), + .rst (power_on_reset_clk100), + .pwr_supply_clk (PWR_SUPPLY_CLK_0P9V) + ); + + wire pwr_supply_clk_450k; + pwr_supply_clk_gen #( + .SOURCE_CLK_FREQ (SOUCE_CLOCK_FREQUENCY), + .TARGET_CLK_FREQ (TARGET_FREQUENCY_450k) + ) freq_gen_450k ( + .clk (CLK_100), + .rst (power_on_reset_clk100), + .pwr_supply_clk (pwr_supply_clk_450k) + ); + + assign PWR_SUPPLY_CLK_DDR4_S = pwr_supply_clk_450k; + assign PWR_SUPPLY_CLK_DDR4_N = pwr_supply_clk_450k; + + pwr_supply_clk_gen #( + .SOURCE_CLK_FREQ (SOUCE_CLOCK_FREQUENCY), + .TARGET_CLK_FREQ (TARGET_FREQUENCY_500k) + ) freq_gen_500k ( + .clk (CLK_100), + .rst (power_on_reset_clk100), + .pwr_supply_clk (PWR_SUPPLY_CLK_CORE) + ); + + pwr_supply_clk_gen #( + .SOURCE_CLK_FREQ (SOUCE_CLOCK_FREQUENCY), + .TARGET_CLK_FREQ (TARGET_FREQUENCY_600k) + ) freq_gen_600k ( + .clk (CLK_100), + .rst (power_on_reset_clk100), + .pwr_supply_clk (PWR_SUPPLY_CLK_1P8V) + ); + + pwr_supply_clk_gen #( + .SOURCE_CLK_FREQ (SOUCE_CLOCK_FREQUENCY), + .TARGET_CLK_FREQ (TARGET_FREQUENCY_800k) + ) freq_gen_800k ( + .clk (CLK_100), + .rst (power_on_reset_clk100), + .pwr_supply_clk (PWR_SUPPLY_CLK_2P5V) + ); + + wire pwr_supply_clk_1M; + pwr_supply_clk_gen #( + .SOURCE_CLK_FREQ (SOUCE_CLOCK_FREQUENCY), + .TARGET_CLK_FREQ (TARGET_FREQUENCY_1M) + ) freq_gen_1M ( + .clk (CLK_100), + .rst (power_on_reset_clk100), + .pwr_supply_clk (pwr_supply_clk_1M) + ); + + assign PWR_SUPPLY_CLK_3P3V = pwr_supply_clk_1M; + assign PWR_SUPPLY_CLK_3P6V = pwr_supply_clk_1M; + + //--------------------------------------------------------------------------- + // PL Interfaces + //--------------------------------------------------------------------------- + + wire [1:0] db_clk_enable; + wire [1:0] db_reset; + wire [1:0] ipass_cable_present; + + // Clocks and reset + oddr db0_clk_out ( + .outclock (clk50), + .din ({1'b0, db_clk_enable[0]}), + .pad_out (DB_REF_CLK[0]), + .aclr (reset_clk50) + ); + + oddr db1_clk_out ( + .outclock (clk50), + .din ({1'b0, db_clk_enable[1]}), + .pad_out (DB_REF_CLK[1]), + .aclr (reset_clk50) + ); + + assign DB_ARST[0] = db_reset[0]; + assign DB_ARST[1] = db_reset[1]; + + // PL SPI FPGA -> DB CPLD + reg mb_cpld_sclk, mb_cpld_mosi, mb_cpld_cs_n; + wire mb_cpld_miso; + + // PL SPI chip select decoding + localparam PL_CS_MB_CPLD = 2'b00; + localparam PL_CS_DB0 = 2'b10; + localparam PL_CS_DB1 = 2'b01; + localparam PL_CS_IDLE = 2'b11; + + // PL SPI registers do not have a separate reset. + // SW is expected to properly setup the DBs before issuing SPI transactions. + always @(posedge pll_ref_clk_int) begin : to_db + // Default chip selects + DB_CTRL_CS_N[0] <= 1'b1; + DB_CTRL_CS_N[1] <= 1'b1; + mb_cpld_cs_n <= 1'b1; + + // DB 0 + DB_CTRL_SCLK[0] <= PL_CPLD_SCLK; + DB_CTRL_MOSI[0] <= PL_CPLD_MOSI; + if (PL_CPLD_CS_N == PL_CS_DB0) begin + DB_CTRL_CS_N[0] <= 1'b0; + end + + // DB 1 + DB_CTRL_SCLK[1] <= PL_CPLD_SCLK; + DB_CTRL_MOSI[1] <= PL_CPLD_MOSI; + if (PL_CPLD_CS_N == PL_CS_DB1) begin + DB_CTRL_CS_N[1] <= 1'b0; + end + + // MB CPLD + mb_cpld_sclk <= PL_CPLD_SCLK; + mb_cpld_mosi <= PL_CPLD_MOSI; + if (PL_CPLD_CS_N == PL_CS_MB_CPLD) begin + mb_cpld_cs_n <= 1'b0; + end + end + + // SPI DB CPLD -> FPGA + always @(posedge pll_ref_clk_int) begin : from_db + case (PL_CPLD_CS_N) + PL_CS_MB_CPLD : PL_CPLD_MISO <= mb_cpld_miso; // MB CPLD + PL_CS_DB1 : PL_CPLD_MISO <= DB_CTRL_MISO[1]; // DB 1 + PL_CS_DB0 : PL_CPLD_MISO <= DB_CTRL_MISO[0]; // DB 0 + PL_CS_IDLE : PL_CPLD_MISO <= 1'bz; // Inactive + endcase + end + + // Local PL SPI target + wire [19:0] pl_ctrlport_req_addr; + wire [31:0] pl_ctrlport_req_data; + wire pl_ctrlport_req_rd; + wire pl_ctrlport_req_wr; + wire pl_ctrlport_resp_ack; + wire [31:0] pl_ctrlport_resp_data; + wire [ 1:0] pl_ctrlport_resp_status; + spi_slave_to_ctrlport_master #( + .CLK_FREQUENCY (50_000_000), + .SPI_FREQUENCY (10_666_667) + ) pl_spi_endpoint ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .m_ctrlport_req_wr (pl_ctrlport_req_wr), + .m_ctrlport_req_rd (pl_ctrlport_req_rd), + .m_ctrlport_req_addr (pl_ctrlport_req_addr), + .m_ctrlport_req_data (pl_ctrlport_req_data), + .m_ctrlport_resp_ack (pl_ctrlport_resp_ack), + .m_ctrlport_resp_status (pl_ctrlport_resp_status), + .m_ctrlport_resp_data (pl_ctrlport_resp_data), + .sclk (mb_cpld_sclk), + .cs_n (mb_cpld_cs_n), + .mosi (mb_cpld_mosi), + .miso (mb_cpld_miso) + ); + + // Split up the PL control port + wire [19:0] pl_regs_ctrlport_req_addr; + wire [31:0] pl_regs_ctrlport_req_data; + wire pl_regs_ctrlport_req_rd; + wire pl_regs_ctrlport_req_wr; + wire pl_regs_ctrlport_resp_ack; + wire [31:0] pl_regs_ctrlport_resp_data; + wire [ 1:0] pl_regs_ctrlport_resp_status; + + wire [19:0] pl_term_ctrlport_req_addr; + wire [31:0] pl_term_ctrlport_req_data; + wire pl_term_ctrlport_req_rd; + wire pl_term_ctrlport_req_wr; + wire pl_term_ctrlport_resp_ack; + wire [31:0] pl_term_ctrlport_resp_data; + wire [ 1:0] pl_term_ctrlport_resp_status; + + wire pl_jtag0_ctrlport_req_rd; + wire pl_jtag0_ctrlport_req_wr; + wire pl_jtag0_ctrlport_resp_ack; + wire [31:0] pl_jtag0_ctrlport_resp_data; + wire [ 1:0] pl_jtag0_ctrlport_resp_status; + wire [19:0] pl_jtag0_ctrlport_req_addr; + wire [31:0] pl_jtag0_ctrlport_req_data; + + wire [19:0] pl_jtag1_ctrlport_req_addr; + wire [31:0] pl_jtag1_ctrlport_req_data; + wire pl_jtag1_ctrlport_req_rd; + wire pl_jtag1_ctrlport_req_wr; + wire pl_jtag1_ctrlport_resp_ack; + wire [31:0] pl_jtag1_ctrlport_resp_data; + wire [1:0] pl_jtag1_ctrlport_resp_status; + + ctrlport_splitter #( + .NUM_SLAVES (4) + ) pl_ctrlport_splitter ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .s_ctrlport_req_wr (pl_ctrlport_req_wr), + .s_ctrlport_req_rd (pl_ctrlport_req_rd), + .s_ctrlport_req_addr (pl_ctrlport_req_addr), + .s_ctrlport_req_data (pl_ctrlport_req_data), + .s_ctrlport_req_byte_en (), + .s_ctrlport_req_has_time (), + .s_ctrlport_req_time (), + .s_ctrlport_resp_ack (pl_ctrlport_resp_ack), + .s_ctrlport_resp_status (pl_ctrlport_resp_status), + .s_ctrlport_resp_data (pl_ctrlport_resp_data), + .m_ctrlport_req_wr ({pl_regs_ctrlport_req_wr, pl_term_ctrlport_req_wr, pl_jtag0_ctrlport_req_wr, pl_jtag1_ctrlport_req_wr}), + .m_ctrlport_req_rd ({pl_regs_ctrlport_req_rd, pl_term_ctrlport_req_rd, pl_jtag0_ctrlport_req_rd, pl_jtag1_ctrlport_req_rd}), + .m_ctrlport_req_addr ({pl_regs_ctrlport_req_addr, pl_term_ctrlport_req_addr, pl_jtag0_ctrlport_req_addr, pl_jtag1_ctrlport_req_addr}), + .m_ctrlport_req_data ({pl_regs_ctrlport_req_data, pl_term_ctrlport_req_data, pl_jtag0_ctrlport_req_data, pl_jtag1_ctrlport_req_data}), + .m_ctrlport_req_byte_en (), + .m_ctrlport_req_has_time (), + .m_ctrlport_req_time (), + .m_ctrlport_resp_ack ({pl_regs_ctrlport_resp_ack, pl_term_ctrlport_resp_ack, pl_jtag0_ctrlport_resp_ack, pl_jtag1_ctrlport_resp_ack}), + .m_ctrlport_resp_status ({pl_regs_ctrlport_resp_status, pl_term_ctrlport_resp_status, pl_jtag0_ctrlport_resp_status, pl_jtag1_ctrlport_resp_status}), + .m_ctrlport_resp_data ({pl_regs_ctrlport_resp_data, pl_term_ctrlport_resp_data, pl_jtag0_ctrlport_resp_data, pl_jtag1_ctrlport_resp_data}) + ); + + pl_cpld_regs #( + .BASE_ADDRESS (PL_REGISTERS) + ) pl_regs ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .s_ctrlport_req_wr (pl_regs_ctrlport_req_wr), + .s_ctrlport_req_rd (pl_regs_ctrlport_req_rd), + .s_ctrlport_req_addr (pl_regs_ctrlport_req_addr), + .s_ctrlport_req_data (pl_regs_ctrlport_req_data), + .s_ctrlport_resp_ack (pl_regs_ctrlport_resp_ack), + .s_ctrlport_resp_status (pl_regs_ctrlport_resp_status), + .s_ctrlport_resp_data (pl_regs_ctrlport_resp_data), + .qsfp0_led_active (QSFP0_LED_ACTIVE), + .qsfp0_led_link (QSFP0_LED_LINK), + .qsfp1_led_active (QSFP1_LED_ACTIVE), + .qsfp1_led_link (QSFP1_LED_LINK), + .ipass_cable_present (ipass_cable_present) + ); + + ctrlport_to_jtag #( + .BASE_ADDRESS (JTAG_DB0), + .DEFAULT_PRESCALAR (1) + ) db0_jtag ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .s_ctrlport_req_wr (pl_jtag0_ctrlport_req_wr), + .s_ctrlport_req_rd (pl_jtag0_ctrlport_req_rd), + .s_ctrlport_req_addr (pl_jtag0_ctrlport_req_addr), + .s_ctrlport_req_data (pl_jtag0_ctrlport_req_data), + .s_ctrlport_resp_ack (pl_jtag0_ctrlport_resp_ack), + .s_ctrlport_resp_status (pl_jtag0_ctrlport_resp_status), + .s_ctrlport_resp_data (pl_jtag0_ctrlport_resp_data), + .tck (DB_JTAG_TCK[0]), + .tdi (DB_JTAG_TDI[0]), + .tdo (DB_JTAG_TDO[0]), + .tms (DB_JTAG_TMS[0]) + ); + + ctrlport_to_jtag #( + .BASE_ADDRESS (JTAG_DB1), + .DEFAULT_PRESCALAR (1) + ) db1_jtag ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .s_ctrlport_req_wr (pl_jtag1_ctrlport_req_wr), + .s_ctrlport_req_rd (pl_jtag1_ctrlport_req_rd), + .s_ctrlport_req_addr (pl_jtag1_ctrlport_req_addr), + .s_ctrlport_req_data (pl_jtag1_ctrlport_req_data), + .s_ctrlport_resp_ack (pl_jtag1_ctrlport_resp_ack), + .s_ctrlport_resp_status (pl_jtag1_ctrlport_resp_status), + .s_ctrlport_resp_data (pl_jtag1_ctrlport_resp_data), + .tck (DB_JTAG_TCK[1]), + .tdi (DB_JTAG_TDI[1]), + .tdo (DB_JTAG_TDO[1]), + .tms (DB_JTAG_TMS[1]) + ); + + // Termination of ctrlport request + ctrlport_terminator #( + .START_ADDRESS (JTAG_DB1 + JTAG_DB1_SIZE), + .LAST_ADDRESS (2**CTRLPORT_ADDR_W-1) + ) pl_terminator ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .s_ctrlport_req_wr (pl_term_ctrlport_req_wr), + .s_ctrlport_req_rd (pl_term_ctrlport_req_rd), + .s_ctrlport_req_addr (pl_term_ctrlport_req_addr), + .s_ctrlport_req_data (pl_term_ctrlport_req_data), + .s_ctrlport_resp_ack (pl_term_ctrlport_resp_ack), + .s_ctrlport_resp_status (pl_term_ctrlport_resp_status), + .s_ctrlport_resp_data (pl_term_ctrlport_resp_data) + ); + + //--------------------------------------------------------------------------- + // PS Interfaces + //--------------------------------------------------------------------------- + + // Local PS SPI target + wire [19:0] ps_ctrlport_req_addr; + wire [31:0] ps_ctrlport_req_data; + wire ps_ctrlport_req_rd; + wire ps_ctrlport_req_wr; + wire ps_ctrlport_resp_ack; + wire [31:0] ps_ctrlport_resp_data; + wire [ 1:0] ps_ctrlport_resp_status; + + wire ps_spi_endpoint_sclk; + wire ps_spi_endpoint_mosi; + wire ps_spi_endpoint_miso; + wire ps_spi_endpoint_cs_n; + spi_slave_to_ctrlport_master #( + .CLK_FREQUENCY (50_000_000), + .SPI_FREQUENCY (5_000_000) + ) ps_spi_endpoint ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .m_ctrlport_req_wr (ps_ctrlport_req_wr), + .m_ctrlport_req_rd (ps_ctrlport_req_rd), + .m_ctrlport_req_addr (ps_ctrlport_req_addr), + .m_ctrlport_req_data (ps_ctrlport_req_data), + .m_ctrlport_resp_ack (ps_ctrlport_resp_ack), + .m_ctrlport_resp_status (ps_ctrlport_resp_status), + .m_ctrlport_resp_data (ps_ctrlport_resp_data), + .sclk (ps_spi_endpoint_sclk), + .cs_n (ps_spi_endpoint_cs_n), + .mosi (ps_spi_endpoint_mosi), + .miso (ps_spi_endpoint_miso) + ); + + // The PS SPI chip select signals are binary encoded. + // + // The internal SPI slaves as well as external slaves like the LMK04832 + // trigger actions or resets based on edges of the chip select signal. + // Therefore this implementation has to avoid glitches on the chip select + // signal although the SPI protocol is synchronous. + // + // The chip signals are double synchronized to make sure there is no + // meta-stability. Due to different traces lengths there is no guarantee for + // the chip select signals to change at the same time. To overcome this issue + // register stage 2 and 3 are compared. Only in case of matching values the + // change is propagated to the slaves' chip select lines. Once the IDLE state + // (all ones) is detected in register stage 2 the slaves' chip select lines + // will be deasserted. + + // Input sync registers (3 stages) + wire [3:0] ps_cpld_cs_n_shift2; // Resolving meta-stability, reset on IDLE + reg [3:0] ps_cpld_cs_n_shift3 = {4 {1'b1}}; // Stable state detection + synchronizer #( + .WIDTH (4), + .STAGES (2), + .INITIAL_VAL (4'b1111), + .FALSE_PATH_TO_IN (0) + ) ps_spi_input_sync_inst ( + .clk (clk250), + .rst (1'b0), + .in (PS_CPLD_CS_N), + .out (ps_cpld_cs_n_shift2) + ); + always @(posedge clk250) begin + ps_cpld_cs_n_shift3 <= ps_cpld_cs_n_shift2; + end + + // SPI binary decoding + reg [SPI_ENDPOINT_SIZE-2:0] ps_spi_cs_n_decoded = {SPI_ENDPOINT_SIZE-1 {1'b1}}; + always @(posedge clk250) begin + // reset in case of IDLE state + if (ps_cpld_cs_n_shift2[2:0] == PS_CS_IDLE) begin + ps_spi_cs_n_decoded <= {SPI_ENDPOINT_SIZE-1 {1'b1}}; + // only apply changes when stable state is detected + end else if (ps_cpld_cs_n_shift3[2:0] == ps_cpld_cs_n_shift2[2:0]) begin + ps_spi_cs_n_decoded[PS_CS_MB_CPLD] <= ps_cpld_cs_n_shift3[2:0] != PS_CS_MB_CPLD; + ps_spi_cs_n_decoded[PS_CS_LMK32] <= ps_cpld_cs_n_shift3[2:0] != PS_CS_LMK32; + ps_spi_cs_n_decoded[PS_CS_TPM] <= ps_cpld_cs_n_shift3[2:0] != PS_CS_TPM; + ps_spi_cs_n_decoded[PS_CS_PHASE_DAC] <= ps_cpld_cs_n_shift3[2:0] != PS_CS_PHASE_DAC; + ps_spi_cs_n_decoded[PS_CS_DB0_CAL_EEPROM] <= ps_cpld_cs_n_shift3[2:0] != PS_CS_DB0_CAL_EEPROM; + ps_spi_cs_n_decoded[PS_CS_DB1_CAL_EEPROM] <= ps_cpld_cs_n_shift3[2:0] != PS_CS_DB1_CAL_EEPROM; + ps_spi_cs_n_decoded[PS_CS_CLK_AUX_DB] <= ps_cpld_cs_n_shift3[2:0] != PS_CS_CLK_AUX_DB; + end + end + + // Local SPI slave + assign ps_spi_endpoint_sclk = PS_CPLD_SCLK; + assign ps_spi_endpoint_mosi = PS_CPLD_MOSI; + assign ps_spi_endpoint_cs_n = ps_spi_cs_n_decoded[PS_CS_MB_CPLD]; + + // LMK04832 SPI signals + assign LMK32_SCLK = PS_CPLD_SCLK; + assign LMK32_MOSI = PS_CPLD_MOSI; + assign LMK32_CS_N = ps_spi_cs_n_decoded[PS_CS_LMK32]; + + // TPM SPI signals + // Note: TPM is not currently supported + assign TPM_SCLK = PS_CPLD_SCLK; + assign TPM_MOSI = PS_CPLD_MOSI; + assign TPM_CS_N = ps_spi_cs_n_decoded[PS_CS_TPM]; + + // Phase DAC SPI signals + assign PHASE_DAC_SCLK = PS_CPLD_SCLK; + assign PHASE_DAC_MOSI = PS_CPLD_MOSI; + assign PHASE_DAC_CS_N = ps_spi_cs_n_decoded[PS_CS_PHASE_DAC]; + + // DB EEPROM 0 SPI signals + assign DB_CALEEPROM_SCLK[0] = PS_CPLD_SCLK; + assign DB_CALEEPROM_MOSI[0] = PS_CPLD_MOSI; + assign DB_CALEEPROM_CS_N[0] = ps_spi_cs_n_decoded[PS_CS_DB0_CAL_EEPROM]; + + // DB EEPROM 1 SPI signals + assign DB_CALEEPROM_SCLK[1] = PS_CPLD_SCLK; + assign DB_CALEEPROM_MOSI[1] = PS_CPLD_MOSI; + assign DB_CALEEPROM_CS_N[1] = ps_spi_cs_n_decoded[PS_CS_DB1_CAL_EEPROM]; + + // CLK AUX DB SPI signals + assign CLK_DB_SCLK = PS_CPLD_SCLK; + assign CLK_DB_MOSI = PS_CPLD_MOSI; + assign CLK_DB_CS_N = ps_spi_cs_n_decoded[PS_CS_CLK_AUX_DB]; + + // Combine SPI responses based on inputs only as this path is captured + // synchronously to PS_CPLD_SCLK by the SPI master. + assign PS_CPLD_MISO = (PS_CPLD_CS_N[2:0] == PS_CS_MB_CPLD) ? ps_spi_endpoint_miso : + (PS_CPLD_CS_N[2:0] == PS_CS_LMK32) ? LMK32_MISO : + (PS_CPLD_CS_N[2:0] == PS_CS_TPM) ? TPM_MISO : + (PS_CPLD_CS_N[2:0] == PS_CS_DB0_CAL_EEPROM) ? DB_CALEEPROM_MISO[0] : + (PS_CPLD_CS_N[2:0] == PS_CS_DB1_CAL_EEPROM) ? DB_CALEEPROM_MISO[1] : + (PS_CPLD_CS_N[2:0] == PS_CS_CLK_AUX_DB) ? CLK_DB_MISO : + 1'bz; // Default case and PHASE_DAC + + // Split up the PS control port + wire [19:0] ps_regs_ctrlport_req_addr; + wire [31:0] ps_regs_ctrlport_req_data; + wire ps_regs_ctrlport_req_rd; + wire ps_regs_ctrlport_req_wr; + wire ps_regs_ctrlport_resp_ack; + wire [31:0] ps_regs_ctrlport_resp_data; + wire [ 1:0] ps_regs_ctrlport_resp_status; + + wire [19:0] ps_term_ctrlport_req_addr; + wire [31:0] ps_term_ctrlport_req_data; + wire ps_term_ctrlport_req_rd; + wire ps_term_ctrlport_req_wr; + wire ps_term_ctrlport_resp_ack; + wire [31:0] ps_term_ctrlport_resp_data; + wire [ 1:0] ps_term_ctrlport_resp_status; + + wire [19:0] ps_reconfig_ctrlport_req_addr; + wire [31:0] ps_reconfig_ctrlport_req_data; + wire ps_reconfig_ctrlport_req_rd; + wire ps_reconfig_ctrlport_req_wr; + wire ps_reconfig_ctrlport_resp_ack; + wire [31:0] ps_reconfig_ctrlport_resp_data; + wire [ 1:0] ps_reconfig_ctrlport_resp_status; + + wire [19:0] ps_power_ctrlport_req_addr; + wire [31:0] ps_power_ctrlport_req_data; + wire ps_power_ctrlport_req_rd; + wire ps_power_ctrlport_req_wr; + wire ps_power_ctrlport_resp_ack; + wire [31:0] ps_power_ctrlport_resp_data; + wire [ 1:0] ps_power_ctrlport_resp_status; + + ctrlport_splitter #( + .NUM_SLAVES (4) + ) ps_ctrlport_splitter ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .s_ctrlport_req_wr (ps_ctrlport_req_wr), + .s_ctrlport_req_rd (ps_ctrlport_req_rd), + .s_ctrlport_req_addr (ps_ctrlport_req_addr), + .s_ctrlport_req_data (ps_ctrlport_req_data), + .s_ctrlport_req_byte_en (), + .s_ctrlport_req_has_time (), + .s_ctrlport_req_time (), + .s_ctrlport_resp_ack (ps_ctrlport_resp_ack), + .s_ctrlport_resp_status (ps_ctrlport_resp_status), + .s_ctrlport_resp_data (ps_ctrlport_resp_data), + .m_ctrlport_req_wr ({ps_power_ctrlport_req_wr, ps_regs_ctrlport_req_wr, ps_term_ctrlport_req_wr, ps_reconfig_ctrlport_req_wr}), + .m_ctrlport_req_rd ({ps_power_ctrlport_req_rd, ps_regs_ctrlport_req_rd, ps_term_ctrlport_req_rd, ps_reconfig_ctrlport_req_rd}), + .m_ctrlport_req_addr ({ps_power_ctrlport_req_addr, ps_regs_ctrlport_req_addr, ps_term_ctrlport_req_addr, ps_reconfig_ctrlport_req_addr}), + .m_ctrlport_req_data ({ps_power_ctrlport_req_data, ps_regs_ctrlport_req_data, ps_term_ctrlport_req_data, ps_reconfig_ctrlport_req_data}), + .m_ctrlport_req_byte_en (), + .m_ctrlport_req_has_time (), + .m_ctrlport_req_time (), + .m_ctrlport_resp_ack ({ps_power_ctrlport_resp_ack, ps_regs_ctrlport_resp_ack, ps_term_ctrlport_resp_ack, ps_reconfig_ctrlport_resp_ack}), + .m_ctrlport_resp_status ({ps_power_ctrlport_resp_status, ps_regs_ctrlport_resp_status, ps_term_ctrlport_resp_status, ps_reconfig_ctrlport_resp_status}), + .m_ctrlport_resp_data ({ps_power_ctrlport_resp_data, ps_regs_ctrlport_resp_data, ps_term_ctrlport_resp_data, ps_reconfig_ctrlport_resp_data}) + ); + + wire [39:0] serial_num_clk50; + wire cmi_ready_clk50; + wire cmi_other_side_detected_clk50; + ps_cpld_regs #( + .BASE_ADDRESS (PS_REGISTERS) + ) ps_regs ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .s_ctrlport_req_wr (ps_regs_ctrlport_req_wr), + .s_ctrlport_req_rd (ps_regs_ctrlport_req_rd), + .s_ctrlport_req_addr (ps_regs_ctrlport_req_addr), + .s_ctrlport_req_data (ps_regs_ctrlport_req_data), + .s_ctrlport_resp_ack (ps_regs_ctrlport_resp_ack), + .s_ctrlport_resp_status (ps_regs_ctrlport_resp_status), + .s_ctrlport_resp_data (ps_regs_ctrlport_resp_data), + .db_clk_enable (db_clk_enable), + .db_reset (db_reset), + .pll_ref_clk_enable (pll_ref_clk_en_clk50), + .dio_direction_a (DIO_DIRECTION_A), + .dio_direction_b (DIO_DIRECTION_B), + .serial_num (serial_num_clk50), + .cmi_ready (cmi_ready_clk50), + .cmi_other_side_detected (cmi_other_side_detected_clk50) + ); + + ps_power_regs #( + .BASE_ADDRESS (POWER_REGISTERS), + .NUM_ADDRESSES (POWER_REGISTERS_SIZE) + ) ps_power_regs_inst ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .s_ctrlport_req_wr (ps_power_ctrlport_req_wr), + .s_ctrlport_req_rd (ps_power_ctrlport_req_rd), + .s_ctrlport_req_addr (ps_power_ctrlport_req_addr), + .s_ctrlport_req_data (ps_power_ctrlport_req_data), + .s_ctrlport_resp_ack (ps_power_ctrlport_resp_ack), + .s_ctrlport_resp_status (ps_power_ctrlport_resp_status), + .s_ctrlport_resp_data (ps_power_ctrlport_resp_data), + .ipass_power_disable (IPASS_POWER_DISABLE), + .ipass_power_fault_n (IPASS_POWER_EN_FAULT), + .osc_100_en (PWR_EN_5V_OSC_100), + .osc_122_88_en (PWR_EN_5V_OSC_122_88) + ); + + // Termination of ctrlport request + ctrlport_terminator #( + .START_ADDRESS (POWER_REGISTERS + POWER_REGISTERS_SIZE), + .LAST_ADDRESS (2**CTRLPORT_ADDR_W-1) + ) ps_terminator ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .s_ctrlport_req_wr (ps_term_ctrlport_req_wr), + .s_ctrlport_req_rd (ps_term_ctrlport_req_rd), + .s_ctrlport_req_addr (ps_term_ctrlport_req_addr), + .s_ctrlport_req_data (ps_term_ctrlport_req_data), + .s_ctrlport_resp_ack (ps_term_ctrlport_resp_ack), + .s_ctrlport_resp_status (ps_term_ctrlport_resp_status), + .s_ctrlport_resp_data (ps_term_ctrlport_resp_data) + ); + + + //--------------------------------------------------------------------------- + // Reconfiguration + //--------------------------------------------------------------------------- + // On-chip flash interface + // + // Naming is according to Avalon Memory-Mapped Interfaces: + // https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/manual/mnl_avalon_spec.pdf + + wire csr_addr; + wire csr_read; + wire [31:0] csr_readdata; + wire csr_write; + wire [31:0] csr_writedata; + wire [16:0] data_addr; + wire data_read; + wire [31:0] data_readdata; + wire data_readdatavalid; + wire data_waitrequest; + wire data_write; + wire [31:0] data_writedata; + wire reset_clk50_n; + + assign reset_clk50_n = ~reset_clk50; + on_chip_flash flash_inst ( + .clock (clk50), + .avmm_csr_addr (csr_addr), + .avmm_csr_read (csr_read), + .avmm_csr_writedata (csr_writedata), + .avmm_csr_write (csr_write), + .avmm_csr_readdata (csr_readdata), + .avmm_data_addr (data_addr), + .avmm_data_read (data_read), + .avmm_data_writedata (data_writedata), + .avmm_data_write (data_write), + .avmm_data_readdata (data_readdata), + .avmm_data_waitrequest (data_waitrequest), + .avmm_data_readdatavalid (data_readdatavalid), + .avmm_data_burstcount (4'b0001), + .reset_n (reset_clk50_n) + ); + + reconfig_engine #( + .BASE_ADDRESS (RECONFIG), + .NUM_ADDRESSES (RECONFIG_SIZE), + .MEM_INIT (0) + ) reconfig_engine_inst ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .s_ctrlport_req_wr (ps_reconfig_ctrlport_req_wr), + .s_ctrlport_req_rd (ps_reconfig_ctrlport_req_rd), + .s_ctrlport_req_addr (ps_reconfig_ctrlport_req_addr), + .s_ctrlport_req_data (ps_reconfig_ctrlport_req_data), + .s_ctrlport_resp_ack (ps_reconfig_ctrlport_resp_ack), + .s_ctrlport_resp_status (ps_reconfig_ctrlport_resp_status), + .s_ctrlport_resp_data (ps_reconfig_ctrlport_resp_data), + .csr_addr (csr_addr), + .csr_read (csr_read), + .csr_writedata (csr_writedata), + .csr_write (csr_write), + .csr_readdata (csr_readdata), + .data_addr (data_addr), + .data_read (data_read), + .data_writedata (data_writedata), + .data_write (data_write), + .data_readdata (data_readdata), + .data_waitrequest (data_waitrequest), + .data_readdatavalid (data_readdatavalid) + ); + + //--------------------------------------------------------------------------- + // CMI Interface + //--------------------------------------------------------------------------- + + // Control and status information clock transition + wire [39:0] serial_num_clk40; + wire cmi_ready_clk40; + wire cmi_other_side_detected_clk40; + + handshake #( + .WIDTH (41) + ) cmi_control_hs ( + .clk_a (clk50), + .rst_a (reset_clk50), + .valid_a (1'b1), + .data_a ({cmi_ready_clk50, serial_num_clk50}), + .busy_a (), + .clk_b (clk40), + .valid_b (), + .data_b ({cmi_ready_clk40, serial_num_clk40}) + ); + + synchronizer #( + .WIDTH (1), + .STAGES (2), + .INITIAL_VAL (1'b0), + .FALSE_PATH_TO_IN (1) + ) cmi_status_sync ( + .clk (clk50), + .rst (reset_clk50), + .in (cmi_other_side_detected_clk40), + .out (cmi_other_side_detected_clk50) + ); + + wire scl_out; + wire sda_out; + wire [1:0] ipass_cable_present_n = ~ipass_cable_present; + + PcieCmiWrapper #( + .kSimulation (SIMULATION) + ) pcie_cmi_inst ( + .Clk (clk40), + .acReset (reset_clk40), + .cSerialNumber (serial_num_clk40), + .cBoardIsReady (cmi_ready_clk40), + .cCmiReset (PCIE_RESET), + .cOtherSideDetected (cmi_other_side_detected_clk40), + .aCblPrsnt_n (ipass_cable_present_n[0]), + .aSdaIn (IPASS_SDA[0]), + .aSdaOut (sda_out), + .aSclIn (IPASS_SCL[0]), + .aSclOut (scl_out) + ); + + // External pull-ups are used to drive the signal high + assign IPASS_SDA[0] = sda_out ? 1'bz : 1'b0; + assign IPASS_SCL[0] = scl_out ? 1'bz : 1'b0; + + // No CMI controller for second interface + assign IPASS_SCL[1] = 1'bz; + assign IPASS_SDA[1] = 1'bz; + + //--------------------------------------------------------------------------- + // Miscellaneous + //--------------------------------------------------------------------------- + + // Constants + assign PS_CLK_ON_CPLD = 1'b0; // Active-low driving of PS clocks + assign TPM_RESET_n = 1'b1; + + // Currently unused ports + assign PL_CPLD_IRQ = 1'b0; + +endmodule + + +`default_nettype wire + + +//XmlParse xml_on +//<top name="X4XX_MB_CPLD"> +// <regmapcfg readablestrobes="false"> +// <map name="MB_CPLD_PS_REGMAP"/> +// <map name="MB_CPLD_PL_REGMAP"/> +// </regmapcfg> +//</top> +//<regmap name="MB_CPLD_PS_REGMAP" readablestrobes="false" markdown="true" generatevhdl="true" ettusguidelines="true"> +// <info> +// This register map is available using the PS CPLD SPI interface. +// </info> +// <group name="MB_CPLD_PS_WINDOWS"> +// <window name="PS_REGISTERS" offset="0x00" size="0x40" targetregmap="PS_CPLD_BASE_REGMAP"/> +// <window name="RECONFIG" offset="0x40" size="0x20" targetregmap="RECONFIG_REGMAP"/> +// <window name="POWER_REGISTERS" offset="0x60" size="0x20" targetregmap="PS_POWER_REGMAP"/> +// </group> +// <group name="PS_SPI_ENDPOINTS"> +// <enumeratedtype name="SPI_ENDPOINT"> +// <value name="PS_CS_MB_CPLD" integer="0"/> +// <value name="PS_CS_LMK32" integer="1"/> +// <value name="PS_CS_TPM" integer="2"/> +// <value name="PS_CS_PHASE_DAC" integer="3"/> +// <value name="PS_CS_DB0_CAL_EEPROM" integer="4"/> +// <value name="PS_CS_DB1_CAL_EEPROM" integer="5"/> +// <value name="PS_CS_CLK_AUX_DB" integer="6"/> +// <value name="PS_CS_IDLE" integer="7"/> +// </enumeratedtype> +// </group> +//</regmap> +//<regmap name="MB_CPLD_PL_REGMAP" readablestrobes="false" markdown="true" generatevhdl="true" ettusguidelines="true"> +// <info> +// This register map is available using the PL CPLD SPI interface. +// All protocol masters controller by this register map are running with a clock frequency of 50 MHz. +// </info> +// <group name="MB_CPLD_PL_WINDOWS"> +// <window name="PL_REGISTERS" offset="0x0" size="0x40" targetregmap="PL_CPLD_BASE_REGMAP"/> +// <window name="JTAG_DB0" offset="0x60" size="0x20" targetregmap="JTAG_REGMAP"> +// <info> +// JTAG Master connected to first daugherboard's CPLD JTAG interface. +// +// **Use minimum value of 1 for @.JTAG_REGMAP.prescalar because the DB CPLD JTAG interface maximum clock frequency is 20 MHz.** +// </info> +// </window> +// <window name="JTAG_DB1" offset="0x80" size="0x20" targetregmap="JTAG_REGMAP"> +// <info> +// JTAG Master connected to second daugherboard's CPLD JTAG interface. +// +// **Use minimum value of 1 for @.JTAG_REGMAP.prescalar because the DB CPLD JTAG interface maximum clock frequency is 20 MHz.** +// </info> +// </window> +// </group> +//</regmap> +//<regmap name="CONSTANTS_REGMAP" readablestrobes="false" generatevhdl="true" ettusguidelines="true"> +// <group name="CONSTANTS_GROUP"> +// <info> +// Basic registers containing version and capabilities information. +// </info> + +// <enumeratedtype name="CONSTANTS_ENUM" showhexvalue="true"> +// <info> +// This enumeration is used to create the constants held in the basic registers. +// </info> +// <value name="PS_CPLD_SIGNATURE" integer="0x0A522D27"/> +// <value name="PL_CPLD_SIGNATURE" integer="0x3FDC5C47"/> +// <value name="CPLD_REVISION" integer="0x21012015"/> +// <value name="OLDEST_CPLD_REVISION" integer="0x20122114"/> +// </enumeratedtype> +// </group> +//</regmap> +//XmlParse xml_off |