aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fpga/usrp3/top/x400/cpld/.gitignore7
-rw-r--r--fpga/usrp3/top/x400/cpld/Makefile77
-rw-r--r--fpga/usrp3/top/x400/cpld/ctrlport_to_jtag.v275
-rw-r--r--fpga/usrp3/top/x400/cpld/ctrlport_to_spi.v276
-rw-r--r--fpga/usrp3/top/x400/cpld/db_spi_shared_constants.sdc20
-rw-r--r--fpga/usrp3/top/x400/cpld/ip/clkctrl/.gitignore3
-rw-r--r--fpga/usrp3/top/x400/cpld/ip/clkctrl/clkctrl.qsys73
-rw-r--r--fpga/usrp3/top/x400/cpld/ip/cmi/.gitignore2
-rw-r--r--fpga/usrp3/top/x400/cpld/ip/cmi/PcieCmi.qxpbin0 -> 234390 bytes
-rw-r--r--fpga/usrp3/top/x400/cpld/ip/cmi/PcieCmi.vhd38
-rw-r--r--fpga/usrp3/top/x400/cpld/ip/cmi/PcieCmiWrapper.vhd93
-rw-r--r--fpga/usrp3/top/x400/cpld/ip/flash/.gitignore3
-rw-r--r--fpga/usrp3/top/x400/cpld/ip/flash/on_chip_flash.qsys90
-rw-r--r--fpga/usrp3/top/x400/cpld/ip/oddr/oddr.qip74
-rw-r--r--fpga/usrp3/top/x400/cpld/ip/oddr/oddr.v124
-rw-r--r--fpga/usrp3/top/x400/cpld/ip/oddr/oddr/altera_gpio_lite.sv1200
-rw-r--r--fpga/usrp3/top/x400/cpld/ip/pll/pll.ppf12
-rw-r--r--fpga/usrp3/top/x400/cpld/ip/pll/pll.qip5
-rw-r--r--fpga/usrp3/top/x400/cpld/ip/pll/pll.v368
-rw-r--r--fpga/usrp3/top/x400/cpld/mb_cpld.qpf30
-rw-r--r--fpga/usrp3/top/x400/cpld/mb_cpld.qsf431
-rw-r--r--fpga/usrp3/top/x400/cpld/mb_cpld.sdc689
-rw-r--r--fpga/usrp3/top/x400/cpld/mb_cpld.v1033
-rw-r--r--fpga/usrp3/top/x400/cpld/pl_cpld_regs.v297
-rw-r--r--fpga/usrp3/top/x400/cpld/ps_cpld_regs.v404
-rw-r--r--fpga/usrp3/top/x400/cpld/ps_power_regs.v231
-rw-r--r--fpga/usrp3/top/x400/cpld/pwr_supply_clk_gen.v73
-rw-r--r--fpga/usrp3/top/x400/cpld/raw_conversion.cof39
-rw-r--r--fpga/usrp3/top/x400/cpld/reconfig_engine.v1024
-rw-r--r--fpga/usrp3/top/x400/cpld/regmap/constants_regmap_utils.vh28
-rw-r--r--fpga/usrp3/top/x400/cpld/regmap/jtag_regmap_utils.vh57
-rw-r--r--fpga/usrp3/top/x400/cpld/regmap/mb_cpld_pl_regmap_utils.vh36
-rw-r--r--fpga/usrp3/top/x400/cpld/regmap/mb_cpld_ps_regmap_utils.vh51
-rw-r--r--fpga/usrp3/top/x400/cpld/regmap/pl_cpld_base_regmap_utils.vh122
-rw-r--r--fpga/usrp3/top/x400/cpld/regmap/ps_cpld_base_regmap_utils.vh183
-rw-r--r--fpga/usrp3/top/x400/cpld/regmap/ps_power_regmap_utils.vh54
-rw-r--r--fpga/usrp3/top/x400/cpld/regmap/reconfig_regmap_utils.vh135
-rw-r--r--fpga/usrp3/top/x400/cpld/regmap/spi_regmap_utils.vh69
-rw-r--r--fpga/usrp3/top/x400/cpld/reset_generator.v93
-rw-r--r--fpga/usrp3/top/x400/cpld/scripts/ps_cs_analysis.tcl32
-rw-r--r--fpga/usrp3/top/x400/cpld/spi_slave.v288
-rw-r--r--fpga/usrp3/top/x400/cpld/spi_slave_to_ctrlport_master.v238
42 files changed, 8377 insertions, 0 deletions
diff --git a/fpga/usrp3/top/x400/cpld/.gitignore b/fpga/usrp3/top/x400/cpld/.gitignore
new file mode 100644
index 000000000..fcdcdf540
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/.gitignore
@@ -0,0 +1,7 @@
+# Ignore Quartus generated files upon project opening.
+*.qws
+db/
+incremental_db/
+output_files/
+*.sopcinfo
+build/
diff --git a/fpga/usrp3/top/x400/cpld/Makefile b/fpga/usrp3/top/x400/cpld/Makefile
new file mode 100644
index 000000000..68c6c8908
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/Makefile
@@ -0,0 +1,77 @@
+#
+# Copyright 2021 Ettus Research, a National Instruments Brand
+#
+# SPDX-License-Identifier: LGPL-3.0-or-later
+#
+
+GIT_HASH = $(shell ../../../tools/scripts/git-hash.sh)
+
+build: ip
+ @echo -ne "\n---- Make: Synthesis ...\n\n";
+ @quartus_map mb_cpld --verilog_macro="GIT_HASH=32'h$(GIT_HASH)";
+ @echo -ne "\n---- Make: Partition Merge ...\n\n";
+ @quartus_cdb mb_cpld --merge=on --incremental_compilation_import
+ @echo -ne "\n\n---- Make: Implementation ...\n\n";
+ @quartus_fit mb_cpld;
+ @echo -ne "\n\n---- Make: Analyzing timing ...\n\n";
+ @quartus_sta mb_cpld;
+ @# grep for unconstrained path warning
+ @grep "332102" output_files/mb_cpld.sta.rpt; \
+ if [ $$? -eq 0 ]; then false; else true; fi
+ @# grep for timing closure critical warning
+ @grep "332148" output_files/mb_cpld.sta.rpt; \
+ if [ $$? -eq 0 ]; then false; else true; fi
+ @# expect no warnings
+ @grep -iw "warning" output_files/mb_cpld.sta.rpt; \
+ if [ $$? -eq 0 ]; then false; else true; fi
+ @# expect no critical warning except "review power analyzer report file"
+ @grep -i "critical warning" output_files/* | grep -v 16562; \
+ if [ $$? -eq 0 ]; then false; else true; fi
+ @# PS chip select analysis
+ @quartus_sta -t scripts/ps_cs_analysis.tcl
+ @echo -ne "\n\n---- Make: Generating bitfile...\n\n";
+ @quartus_asm mb_cpld;
+ @echo -ne "\n\n---- Make: Converting bitfile to svf format (ISP enabled)...\n\n";
+ @quartus_cpf --convert \
+ --frequency 10.0MHz \
+ --voltage 2.5 \
+ --operation p \
+ ./output_files/mb_cpld.pof ./output_files/mb_cpld_isp_on.svf -o background_programming=on;
+ @echo -ne "\n\n---- Make: Converting bitfile to svf format (ISP disabled)...\n\n";
+ @quartus_cpf --convert \
+ --frequency 10.0MHz \
+ --voltage 2.5 \
+ --operation p \
+ ./output_files/mb_cpld.pof ./output_files/mb_cpld_isp_off.svf;
+ @echo -ne "\n\n---- Make: Converting bitfile to rdp format...\n\n";
+ @quartus_cpf -c raw_conversion.cof
+ @echo -ne "\n\n---- Make: Copy final files...\n\n";
+ @mkdir -p build
+ @cp output_files/mb_cpld.pof build/usrp_x410_cpld.pof
+ @cp output_files/mb_cpld_isp_off.svf build/usrp_x410_cpld_isp_off.svf
+ @cp output_files/mb_cpld_isp_on.svf build/usrp_x410_cpld.svf
+ @cp output_files/mb_cpld_converted_cfm0_auto.rpd build/usrp_x410_cpld.rpd
+ @echo -ne "\n\n---- Make: MB CPLD ready!\n";
+ @echo -ne " Use build/usrp_x410_cpld.pof via JTAG programmer or\n"
+ @echo -ne " build/usrp_x410_cpld.svf (ISP on) via PS JTAG-engine (background programming) or\n"
+ @echo -ne " build/usrp_x410_cpld.rpd via reconfig engine or\n"
+ @echo -ne " build/usrp_x410_cpld_isp_off.svf via JTAG test points (initial programming)\n"
+
+clean:
+ @echo -ne "\nCleaning MB CPLD...\n";
+ @git clean -Xdf
+
+QSYS_PATH=$(subst \,/,$(QSYS_ROOTDIR))
+
+ip: ip/flash/on_chip_flash/simulation/on_chip_flash.v \
+ ip/clkctrl/clkctrl/simulation/clkctrl.v
+
+ip/flash/on_chip_flash/simulation/on_chip_flash.v:
+ $(QSYS_PATH)/qsys-generate ip/flash/on_chip_flash.qsys --simulation=VERILOG
+
+ip/clkctrl/clkctrl/simulation/clkctrl.v:
+ $(QSYS_PATH)/qsys-generate ip/clkctrl/clkctrl.qsys --simulation=VERILOG
+
+all: build
+
+.PHONY: all build clean ip
diff --git a/fpga/usrp3/top/x400/cpld/ctrlport_to_jtag.v b/fpga/usrp3/top/x400/cpld/ctrlport_to_jtag.v
new file mode 100644
index 000000000..dedc66e36
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/ctrlport_to_jtag.v
@@ -0,0 +1,275 @@
+//
+// Copyright 2021 Ettus Research, A National Instruments Brand
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: ctrlport_to_jtag
+//
+// Description:
+//
+// This module wraps a JTAG master and provides a ControlPort slave
+// interface.
+//
+// Parameters:
+//
+// BASE_ADDRESS : Base address for CtrlPort registers
+// DEFAULT_PRESCALAR : Default clock divider to use
+//
+
+`default_nettype none
+
+
+module ctrlport_to_jtag #(
+ parameter BASE_ADDRESS = 0,
+ parameter DEFAULT_PRESCALAR = 0
+) (
+ //---------------------------------------------------------------------------
+ // ControlPort Slave
+ //---------------------------------------------------------------------------
+
+ input wire ctrlport_clk,
+ input wire ctrlport_rst,
+
+ input wire s_ctrlport_req_wr,
+ input wire s_ctrlport_req_rd,
+ input wire [19:0] s_ctrlport_req_addr,
+ input wire [31:0] s_ctrlport_req_data,
+ output reg s_ctrlport_resp_ack,
+
+ output reg [ 1:0] s_ctrlport_resp_status = 0,
+ output reg [31:0] s_ctrlport_resp_data = 0,
+
+ //---------------------------------------------------------------------------
+ // JTAG Signals
+ //---------------------------------------------------------------------------
+
+ output wire tck,
+ output wire tdi,
+ input wire tdo,
+ output wire tms
+);
+
+ `include "../../../lib/rfnoc/core/ctrlport.vh"
+ `include "./regmap/jtag_regmap_utils.vh"
+
+ //---------------------------------------------------------------------------
+ // Local Registers
+ //---------------------------------------------------------------------------
+
+ reg [ TX_DATA_SIZE-1:0] tx_data_reg;
+ reg [ STB_DATA_SIZE-1:0] stb_data_reg;
+ reg [PRESCALAR_SIZE-1:0] prescalar_reg = DEFAULT_PRESCALAR;
+ reg [ LENGTH_SIZE-1:0] length_reg;
+ reg start_reg;
+ reg soft_rst_stb_reg;
+
+ //---------------------------------------------------------------------------
+ // Readback Signals from JTAG Master
+ //---------------------------------------------------------------------------
+
+ wire [31:0] rd_data;
+ wire ready;
+
+ //---------------------------------------------------------------------------
+ // Handling of CtrlPort
+ //---------------------------------------------------------------------------
+
+ localparam NUM_ADDRESSES = 32;
+ wire address_in_range = (s_ctrlport_req_addr >= BASE_ADDRESS) &&
+ (s_ctrlport_req_addr < BASE_ADDRESS + NUM_ADDRESSES);
+ wire soft_rst_requested = (s_ctrlport_req_addr == BASE_ADDRESS + CONTROL) &&
+ (s_ctrlport_req_data[RESET] == 1'b1);
+
+ always @(posedge ctrlport_clk) begin
+ // Reset internal registers and responses
+ if (ctrlport_rst) begin
+ tx_data_reg <= {TX_DATA_SIZE {1'b0}};
+ stb_data_reg <= {STB_DATA_SIZE {1'b0}};
+ prescalar_reg <= DEFAULT_PRESCALAR;
+ length_reg <= {LENGTH_SIZE {1'b0}};
+ start_reg <= 1'b0;
+ soft_rst_stb_reg <= 1'b0;
+ s_ctrlport_resp_ack <= 1'b0;
+
+ end else begin
+ // Request independent default assignments
+ start_reg <= 1'b0;
+ soft_rst_stb_reg <= 1'b0; // self-clearing strobe
+
+ // Write requests
+ if (s_ctrlport_req_wr) begin
+ // Always issue an ack and no data
+ s_ctrlport_resp_ack <= 1'b1;
+ s_ctrlport_resp_data <= {CTRLPORT_DATA_W{1'bx}};
+ s_ctrlport_resp_status <= CTRL_STS_OKAY;
+
+ // Process write requests only in case ready is asserted because JTAG
+ // module requires these values to be stable when it is not ready.
+ //
+ // The one exception is when a soft-reset is requested to reset the
+ // bitq_fsm, in that case that is a valid write.
+ if (soft_rst_requested) begin
+ soft_rst_stb_reg <= 1'b1;
+
+ end else if (ready) begin
+ case (s_ctrlport_req_addr)
+ BASE_ADDRESS + TX_DATA: begin
+ tx_data_reg <= s_ctrlport_req_data;
+ end
+
+ BASE_ADDRESS + STB_DATA: begin
+ stb_data_reg <= s_ctrlport_req_data;
+ end
+
+ BASE_ADDRESS + CONTROL: begin
+ length_reg <= s_ctrlport_req_data[LENGTH_MSB:LENGTH];
+ prescalar_reg <= s_ctrlport_req_data[PRESCALAR_MSB:PRESCALAR];
+ // When the RESET bit is high, a soft-reset (i.e. no start strobe)
+ // must take place, which is handled by the default assignment.
+ // Otherwise, if the RESET bit is low, a start strobe should be
+ // issued, triggering a transaction.
+ start_reg <= (s_ctrlport_req_data[RESET] == 1'b0);
+ end
+
+ // Error on undefined address
+ default: begin
+ if (address_in_range) begin
+ s_ctrlport_resp_status <= CTRL_STS_CMDERR;
+
+ // No response if out of range
+ end else begin
+ s_ctrlport_resp_ack <= 1'b0;
+ end
+ end
+ endcase
+
+ // Error in case ready is not asserted
+ end else begin
+ s_ctrlport_resp_status <= CTRL_STS_CMDERR;
+ end
+
+ // Read requests
+ end else if (s_ctrlport_req_rd) begin
+ // Default assumption: valid request
+ s_ctrlport_resp_ack <= 1'b1;
+ s_ctrlport_resp_status <= CTRL_STS_OKAY;
+
+ case (s_ctrlport_req_addr)
+ BASE_ADDRESS + RX_DATA: begin
+ s_ctrlport_resp_data <= rd_data;
+ end
+
+ BASE_ADDRESS + CONTROL: begin
+ s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'b0}};
+ s_ctrlport_resp_data[LENGTH_MSB:LENGTH] <= length_reg;
+ s_ctrlport_resp_data[PRESCALAR_MSB:PRESCALAR] <= prescalar_reg;
+ s_ctrlport_resp_data[READY] <= ready;
+ end
+
+ // Error on undefined address
+ default: begin
+ s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'bx}};
+ if (address_in_range) begin
+ s_ctrlport_resp_status <= CTRL_STS_CMDERR;
+
+ // No response if out of range
+ end else begin
+ s_ctrlport_resp_ack <= 1'b0;
+ end
+ end
+ endcase
+
+ // No request
+ end else begin
+ s_ctrlport_resp_ack <= 1'b0;
+ end
+ end
+ end
+
+ //---------------------------------------------------------------------------
+ // JTAG Master
+ //---------------------------------------------------------------------------
+
+ // bitq_fsm reset is asserted by either the ctrlport_rst or the soft-reset
+ // strobe triggered through software.
+ wire bitq_resetn = ~(ctrlport_rst | soft_rst_stb_reg);
+
+ bitq_fsm #(
+ .IDLE_VALUE (1'b0)
+ ) jtag_master (
+ .clk (ctrlport_clk),
+ .rstn (bitq_resetn),
+ .prescalar (prescalar_reg),
+ .bit_clk (tck),
+ .bit_in (tdo),
+ .bit_out (tdi),
+ .bit_stb (tms),
+ .start (start_reg),
+ .ready (ready),
+ .len (length_reg),
+ .wr_data (tx_data_reg),
+ .stb_data (stb_data_reg),
+ .rd_data (rd_data)
+ );
+
+endmodule
+
+
+`default_nettype wire
+
+
+//XmlParse xml_on
+//<regmap name="JTAG_REGMAP" readablestrobes="false" markdown="true" generatevhdl="true" ettusguidelines="true">
+//
+// <group name="JTAG_REGS">
+// <info>
+// This register map is present for each JTAG module.
+//
+// Basic operation would be:
+//
+// - poll @.ready until asserted
+// - write / read data
+// - write @.CONTROL register along with @.reset deasserted to start a transaction
+//
+// For resetting the BITQ FSM, simply assert @.reset.
+//
+// This operation seems a little strange, but it is what the axi_bitq driver
+// expects. This behavior has been implemented in previous products.
+//
+// </info>
+//
+// <register name="TX_DATA" readable="false" offset="0x00" size="32">
+// <info>Data to be transmitted (TDI)</info>
+// </register>
+//
+// <register name="STB_DATA" readable="false" offset="0x04" size="32">
+// <info>Data to be transmitted (TMS)</info>
+// </register>
+//
+// <register name="CONTROL" offset="0x08" size="32">
+// <info>JTAG module status and control</info>
+// <bitfield name="prescalar" range="7..0" initialvalue="true">
+// <info>Clock divider. Resulting JTAG frequency will be f_ctrlport / (2*(prescalar + 1)). See window description for details on the initial/minimum value.</info>
+// </bitfield>
+// <bitfield name="length" range="12..8">
+// <info>(Number of bits - 1) to be transferred</info>
+// </bitfield>
+// <bitfield name="reset" readable="false" range="31">
+// <info>When asserted ('1') a soft-reset for the bitq FSM is triggered,
+// preventing any transactions to take place.
+//
+// Deassert this bit, along with values for @.prescalar and @.length
+// to trigger a new transaction (start strobe).</info>
+// </bitfield>
+// <bitfield name="ready" writable="false" range="31">
+// <info>Bitq FSM is ready for input (no data transmission in progress).</info>
+// </bitfield>
+// </register>
+//
+// <register name="RX_DATA" offset="0x0C" writable="false" size="32">
+// <info>Received data (TDO)</info>
+// </register>
+//
+// </group>
+//</regmap>
+//XmlParse xml_off
diff --git a/fpga/usrp3/top/x400/cpld/ctrlport_to_spi.v b/fpga/usrp3/top/x400/cpld/ctrlport_to_spi.v
new file mode 100644
index 000000000..d4b72a72d
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/ctrlport_to_spi.v
@@ -0,0 +1,276 @@
+//
+// Copyright 2021 Ettus Research, A National Instruments Brand
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: ctrlport_to_spi
+//
+// Description:
+//
+// This module wraps a SPI master and provides a ControlPort interface.
+//
+// Parameters:
+//
+// BASE_ADDRESS : Base address for CtrlPort registers.
+//
+
+`default_nettype none
+
+
+module ctrlport_to_spi #(
+ parameter BASE_ADDRESS = 0
+) (
+ //---------------------------------------------------------------
+ // ControlPort Slave
+ //---------------------------------------------------------------
+
+ input wire ctrlport_clk,
+ input wire ctrlport_rst,
+
+ input wire s_ctrlport_req_wr,
+ input wire s_ctrlport_req_rd,
+ input wire [19:0] s_ctrlport_req_addr,
+ input wire [31:0] s_ctrlport_req_data,
+
+ output reg s_ctrlport_resp_ack,
+ output reg [ 1:0] s_ctrlport_resp_status = 0,
+ output reg [31:0] s_ctrlport_resp_data = 0,
+
+ //---------------------------------------------------------------
+ // SPI Signals
+ //---------------------------------------------------------------
+
+ output wire sclk,
+ output wire mosi,
+ output wire [15:0] ss,
+ input wire miso
+);
+
+ `include "../../../lib/rfnoc/core/ctrlport.vh"
+ `include "./regmap/spi_regmap_utils.vh"
+
+ //---------------------------------------------------------------
+ // Translating CtrlPort <-> Wishbone
+ //---------------------------------------------------------------
+
+ reg wb_cyc_i; // Active bus cycle
+ reg wb_we_i = 1'b0; // Write access
+ reg [ 4:0] wb_adr_i = 5'b0;
+ reg [31:0] wb_dat_i = 32'b0;
+ wire wb_ack_o;
+ wire [31:0] wb_dat_o;
+ wire wb_err_o;
+
+ // Check for address to be in range [base_addr..base_addr+32)
+ localparam NUM_ADDRESSES = 32;
+ wire address_in_range = (s_ctrlport_req_addr >= BASE_ADDRESS) &&
+ (s_ctrlport_req_addr < BASE_ADDRESS + NUM_ADDRESSES);
+
+ // Following chapter 3.2.3 (classic standard SINGLE WRITE cycle) of
+ // https://cdn.opencores.org/downloads/wbspec_b4.pdf
+ always @(posedge ctrlport_clk) begin
+ // Reset internal registers and responses
+ if (ctrlport_rst) begin
+ wb_cyc_i <= 1'b0;
+ s_ctrlport_resp_ack <= 1'b0;
+
+ end else begin
+ // Request independent default assignments
+ s_ctrlport_resp_ack <= 1'b0;
+
+ // Wait for ack on active bus transactions
+ if (wb_cyc_i) begin
+ if (wb_ack_o) begin
+ // End bus cycle and generate response
+ wb_cyc_i <= 1'b0;
+ s_ctrlport_resp_ack <= 1'b1;
+ s_ctrlport_resp_data <= wb_dat_o;
+
+ if (wb_err_o) begin
+ s_ctrlport_resp_status <= CTRL_STS_CMDERR;
+ end else begin
+ s_ctrlport_resp_status <= CTRL_STS_OKAY;
+ end
+ end
+
+ // Write requests
+ end else if (s_ctrlport_req_wr) begin
+ // Assume there is a valid address
+ wb_cyc_i <= 1'b1;
+ wb_we_i <= 1'b1;
+ wb_dat_i <= s_ctrlport_req_data;
+
+ case (s_ctrlport_req_addr)
+ BASE_ADDRESS + TX_DATA_LOW: begin
+ wb_adr_i <= 5'h00;
+ end
+
+ BASE_ADDRESS + TX_DATA_HIGH: begin
+ wb_adr_i <= 5'h04;
+ end
+
+ BASE_ADDRESS + CONTROL: begin
+ wb_adr_i <= 5'h10;
+ end
+
+ BASE_ADDRESS + CLOCK_DIVIDER: begin
+ wb_adr_i <= 5'h14;
+ end
+
+ BASE_ADDRESS + SLAVE_SELECT: begin
+ wb_adr_i <= 5'h18;
+ end
+
+ // Error on undefined address
+ default: begin
+ wb_cyc_i <= 1'b0;
+
+ if (address_in_range) begin
+ s_ctrlport_resp_status <= CTRL_STS_CMDERR;
+
+ // No response if out of range
+ end else begin
+ s_ctrlport_resp_ack <= 1'b0;
+ end
+ end
+ endcase
+
+ // Read requests
+ end else if (s_ctrlport_req_rd) begin
+ // Assume there is a valid address
+ wb_cyc_i <= 1'b1;
+ wb_we_i <= 1'b0;
+
+ case (s_ctrlport_req_addr)
+ BASE_ADDRESS + RX_DATA_LOW: begin
+ wb_adr_i <= 5'h00;
+ end
+
+ BASE_ADDRESS + RX_DATA_HIGH: begin
+ wb_adr_i <= 5'h04;
+ end
+
+ BASE_ADDRESS + CONTROL: begin
+ wb_adr_i <= 5'h10;
+ end
+
+ BASE_ADDRESS + CLOCK_DIVIDER: begin
+ wb_adr_i <= 5'h14;
+ end
+
+ BASE_ADDRESS + SLAVE_SELECT: begin
+ wb_adr_i <= 5'h18;
+ end
+
+ // Error on undefined address
+ default: begin
+ wb_cyc_i <= 1'b0;
+
+ if (address_in_range) begin
+ s_ctrlport_resp_status <= CTRL_STS_CMDERR;
+
+ // No response if out of range
+ end else begin
+ s_ctrlport_resp_ack <= 1'b0;
+ end
+ end
+ endcase
+
+ // No request
+ end else begin
+ s_ctrlport_resp_ack <= 1'b0;
+ end
+ end
+ end
+
+ //---------------------------------------------------------------
+ // SPI Master
+ //---------------------------------------------------------------
+
+ spi_top spi_master (
+ .wb_clk_i (ctrlport_clk),
+ .wb_rst_i (ctrlport_rst),
+ .wb_adr_i (wb_adr_i),
+ .wb_dat_i (wb_dat_i),
+ .wb_dat_o (wb_dat_o),
+ .wb_sel_i (4'hF),
+ .wb_we_i (wb_we_i),
+ .wb_stb_i (wb_cyc_i),
+ .wb_cyc_i (wb_cyc_i),
+ .wb_ack_o (wb_ack_o),
+ .wb_err_o (wb_err_o),
+ .wb_int_o (),
+ .ss_pad_o (ss),
+ .sclk_pad_o (sclk),
+ .mosi_pad_o (mosi),
+ .miso_pad_i (miso)
+ );
+
+endmodule
+
+
+`default_nettype wire
+
+
+//XmlParse xml_on
+//<regmap name="SPI_REGMAP" readablestrobes="false" markdown="true" generatevhdl="true" ettusguidelines="true">
+//
+// <group name="SPI_REGS">
+// <info>
+// This register map is present for each SPI master.
+//
+// For information about the register content and the way to interact with the core see the
+// <a href="https://opencores.org/websvn/filedetails?repname=spi&path=%2Fspi%2Ftrunk%2Fdoc%2Fspi.pdf" target="_blank">documentation</a>
+// of the SPI master from opencores used internally.
+//
+// The core is configured to operate with 16 slave signal signals, up to 128 bits per transmission and 8 bit clock divider.
+// Only 64 bits of data are available via this register interface.
+//
+// For the different SPI modes use the following table to derive the bits in @.CONTROL register. Only option 0 (CPOL=0, CPHA=0) has been tested.
+//
+//| CPOL | CPHA | TX_NEG | RX_NEG |
+//| ------- | -------- | -------- | ------- |
+//| 0 | 0 | 1 | 0 |
+//| 0 | 1 | 0 | 1 |
+//| 1 | 0 | 0 | 1 |
+//| 1 | 1 | 1 | 0 |
+// </info>
+//
+// <register name="RX_DATA_LOW" offset="0x00" writable="false" size="32">
+// <info>Lower 32 bits of the received word. (RxWord[31:0])</info>
+// </register>
+//
+// <register name="RX_DATA_HIGH" offset="0x04" writable="false" size="32">
+// <info>Higher 32 bits of the received word. (RxWord[63:32])</info>
+// </register>
+//
+// <register name="TX_DATA_LOW" offset="0x08" readable="false" size="32">
+// <info>Lower 32 bits of the received word. (TxWord[31:0])</info>
+// </register>
+//
+// <register name="TX_DATA_HIGH" offset="0x0C" readable="false" size="32">
+// <info>Higher 32 bits of the received word. (TxWord[63:32])</info>
+// </register>
+//
+// <register name="CONTROL" offset="0x10" size="32">
+// <info>Control register</info>
+// </register>
+
+// <register name="CLOCK_DIVIDER" offset="0x14" size="8">
+// <bitfield name="Divider" range="7..0">
+// <info>
+// Clock Divider.
+// </info>
+// </bitfield>
+// </register>
+// <register name="SLAVE_SELECT" offset="0x18" size="16">
+// <bitfield name="SS" range="15..0">
+// <info>
+// Slave select.
+// </info>
+// </bitfield>
+// </register>
+//
+// </group>
+//</regmap>
+//XmlParse xml_off
diff --git a/fpga/usrp3/top/x400/cpld/db_spi_shared_constants.sdc b/fpga/usrp3/top/x400/cpld/db_spi_shared_constants.sdc
new file mode 100644
index 000000000..21935c2e7
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/db_spi_shared_constants.sdc
@@ -0,0 +1,20 @@
+#
+# Copyright 2021 Ettus Research, a National Instruments Brand
+#
+# SPDX-License-Identifier: LGPL-3.0-or-later
+#
+# Description:
+#
+# Timing constants for the MB CPLD <-> DB CPLD SPI interface
+#
+
+# Delays are rounded to integer values which leave a slack of >1ns on each setup
+# and hold path without requirement for adding hold delays (as reported
+# by Quartus fitter report).
+# The signal might change before the SCLK edge as the internal
+# registers are driven by PLL reference clock rather than the SPI clock used
+# for the port timing constaints.
+set db_cpld_spi_max_out 14.000
+set db_cpld_spi_min_out 2.000
+set db_cpld_spi_max_in 2.000
+set db_cpld_spi_min_in -2.000
diff --git a/fpga/usrp3/top/x400/cpld/ip/clkctrl/.gitignore b/fpga/usrp3/top/x400/cpld/ip/clkctrl/.gitignore
new file mode 100644
index 000000000..9776d9b81
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/ip/clkctrl/.gitignore
@@ -0,0 +1,3 @@
+# generate files
+clkctrl/
+clkctrl.sopcinfo \ No newline at end of file
diff --git a/fpga/usrp3/top/x400/cpld/ip/clkctrl/clkctrl.qsys b/fpga/usrp3/top/x400/cpld/ip/clkctrl/clkctrl.qsys
new file mode 100644
index 000000000..b9fc219fa
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/ip/clkctrl/clkctrl.qsys
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<system name="$${FILENAME}">
+ <component
+ name="$${FILENAME}"
+ displayName="$${FILENAME}"
+ version="1.0"
+ description=""
+ tags="INTERNAL_COMPONENT=true"
+ categories="" />
+ <parameter name="bonusData"><![CDATA[bonusData
+{
+ element altclkctrl_0
+ {
+ datum _sortIndex
+ {
+ value = "0";
+ type = "int";
+ }
+ }
+}
+]]></parameter>
+ <parameter name="clockCrossingAdapter" value="HANDSHAKE" />
+ <parameter name="device" value="10M04SAU169I7G" />
+ <parameter name="deviceFamily" value="MAX 10" />
+ <parameter name="deviceSpeedGrade" value="7" />
+ <parameter name="fabricMode" value="QSYS" />
+ <parameter name="generateLegacySim" value="false" />
+ <parameter name="generationId" value="0" />
+ <parameter name="globalResetBus" value="false" />
+ <parameter name="hdlLanguage" value="VERILOG" />
+ <parameter name="hideFromIPCatalog" value="true" />
+ <parameter name="lockedInterfaceDefinition" value="" />
+ <parameter name="maxAdditionalLatency" value="1" />
+ <parameter name="projectName" value="" />
+ <parameter name="sopcBorderPoints" value="false" />
+ <parameter name="systemHash" value="0" />
+ <parameter name="testBenchDutName" value="" />
+ <parameter name="timeStamp" value="0" />
+ <parameter name="useTestBenchNamingPattern" value="false" />
+ <instanceScript></instanceScript>
+ <interface
+ name="altclkctrl_input"
+ internal="altclkctrl_0.altclkctrl_input"
+ type="conduit"
+ dir="end">
+ <port name="inclk" internal="inclk" />
+ <port name="ena" internal="ena" />
+ </interface>
+ <interface
+ name="altclkctrl_output"
+ internal="altclkctrl_0.altclkctrl_output"
+ type="conduit"
+ dir="end">
+ <port name="outclk" internal="outclk" />
+ </interface>
+ <module
+ name="altclkctrl_0"
+ kind="altclkctrl"
+ version="18.1"
+ enabled="1"
+ autoexport="1">
+ <parameter name="CLOCK_TYPE" value="1" />
+ <parameter name="DEVICE_FAMILY" value="MAX 10" />
+ <parameter name="ENA_REGISTER_MODE" value="1" />
+ <parameter name="GUI_USE_ENA" value="true" />
+ <parameter name="NUMBER_OF_CLOCKS" value="1" />
+ <parameter name="USE_GLITCH_FREE_SWITCH_OVER_IMPLEMENTATION" value="false" />
+ </module>
+ <interconnectRequirement for="$system" name="qsys_mm.clockCrossingAdapter" value="HANDSHAKE" />
+ <interconnectRequirement for="$system" name="qsys_mm.enableEccProtection" value="FALSE" />
+ <interconnectRequirement for="$system" name="qsys_mm.insertDefaultSlave" value="FALSE" />
+ <interconnectRequirement for="$system" name="qsys_mm.maxAdditionalLatency" value="1" />
+</system>
diff --git a/fpga/usrp3/top/x400/cpld/ip/cmi/.gitignore b/fpga/usrp3/top/x400/cpld/ip/cmi/.gitignore
new file mode 100644
index 000000000..f479dbc97
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/ip/cmi/.gitignore
@@ -0,0 +1,2 @@
+# GUI logfile
+PcieCmi.qarlog
diff --git a/fpga/usrp3/top/x400/cpld/ip/cmi/PcieCmi.qxp b/fpga/usrp3/top/x400/cpld/ip/cmi/PcieCmi.qxp
new file mode 100644
index 000000000..c03dfd331
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/ip/cmi/PcieCmi.qxp
Binary files differ
diff --git a/fpga/usrp3/top/x400/cpld/ip/cmi/PcieCmi.vhd b/fpga/usrp3/top/x400/cpld/ip/cmi/PcieCmi.vhd
new file mode 100644
index 000000000..8bd0fbb1b
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/ip/cmi/PcieCmi.vhd
@@ -0,0 +1,38 @@
+--
+-- Copyright 2021 Ettus Research, a National Instruments Brand
+--
+-- SPDX-License-Identifier: LGPL-3.0-or-later
+--
+-- Module: PcieCmi
+--
+-- Description:
+--
+-- This is an automatically generated file.
+-- Do not modify this file directly!
+--
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+
+entity PcieCmi is
+ generic (
+ kSimulation : natural := 0
+ );
+ port (
+ Clk : in std_logic ;
+ acReset : in std_logic ;
+ cSerialNumber : in std_logic_vector (39 downto 0);
+ cBoardIsReady : in std_logic ;
+ cCmiReset : out std_logic ;
+ cOtherSideDetected : out std_logic ;
+ aCblPrsnt_n : in std_logic ;
+ aSdaIn : in std_logic ;
+ aSdaOut : out std_logic ;
+ aSclIn : in std_logic ;
+ aSclOut : out std_logic
+ );
+end entity PcieCmi;
+architecture rtl of PcieCmi is
+begin
+end architecture rtl;
diff --git a/fpga/usrp3/top/x400/cpld/ip/cmi/PcieCmiWrapper.vhd b/fpga/usrp3/top/x400/cpld/ip/cmi/PcieCmiWrapper.vhd
new file mode 100644
index 000000000..2037d10ed
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/ip/cmi/PcieCmiWrapper.vhd
@@ -0,0 +1,93 @@
+--
+-- Copyright 2021 Ettus Research, a National Instruments Brand
+--
+-- SPDX-License-Identifier: LGPL-3.0-or-later
+--
+-- Module: PcieCmiWrapper
+--
+-- Description:
+--
+-- This is an automatically generated file.
+-- Do not modify this file directly!
+--
+
+
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+
+--synopsys translate_off
+--For synthesis, netlist comes from an qxp and there is no external library
+--For simulation in client, netlist comes from PcieCmiLib external library
+--For simulation in dev branch, netlist comes from work library.
+--Binding will work fine in both simulation cases as long as PcieCmi is compiled
+-- to either library. In dev branch PcieCmiLib will be an empty library just so
+-- ModelSim doesn't complain.
+library PcieCmiLib;
+--synopsys translate_on
+
+entity PcieCmiWrapper is
+ generic (
+ kSimulation : natural := 0 -- set to 1 to speedup simulation
+ );
+ port (
+ Clk : in std_logic; -- 40 MHz clock
+ acReset : in std_logic;
+
+ cSerialNumber : in std_logic_vector(39 downto 0);
+ cBoardIsReady : in std_logic;
+ cCmiReset : out std_logic;
+ cOtherSideDetected : out std_logic;
+
+ aCblPrsnt_n : in std_logic;
+
+ aSdaIn : in std_logic;
+ aSdaOut : out std_logic;
+ aSclIn : in std_logic;
+ aSclOut : out std_logic
+ );
+end PcieCmiWrapper;
+
+architecture rtl of PcieCmiWrapper is
+
+ component PcieCmi
+ generic (kSimulation : natural := 0);
+ port (
+ Clk : in std_logic;
+ acReset : in std_logic;
+ cSerialNumber : in std_logic_vector(39 downto 0);
+ cBoardIsReady : in std_logic;
+ cCmiReset : out std_logic;
+ cOtherSideDetected : out std_logic;
+ aCblPrsnt_n : in std_logic;
+ aSdaIn : in std_logic;
+ aSdaOut : out std_logic;
+ aSclIn : in std_logic;
+ aSclOut : out std_logic);
+ end component;
+
+begin
+
+ -- Just forward all signals to lower level entity.
+ -- Leave the simulation generic in place as it important to be able to
+ -- simulate the netlist in reasonable time. For the synthesis in the client
+ -- the generic is ignored as the netlist is translated with kSimulation set to
+ -- default value and "overwrites" it.
+
+ --vhook PcieCmi
+ PcieCmix: PcieCmi
+ generic map (kSimulation => kSimulation) --natural:=0
+ port map (
+ Clk => Clk, --in std_logic
+ acReset => acReset, --in std_logic
+ cSerialNumber => cSerialNumber, --in std_logic_vector(39:0)
+ cBoardIsReady => cBoardIsReady, --in std_logic
+ cCmiReset => cCmiReset, --out std_logic
+ cOtherSideDetected => cOtherSideDetected, --out std_logic
+ aCblPrsnt_n => aCblPrsnt_n, --in std_logic
+ aSdaIn => aSdaIn, --in std_logic
+ aSdaOut => aSdaOut, --out std_logic
+ aSclIn => aSclIn, --in std_logic
+ aSclOut => aSclOut); --out std_logic
+
+end architecture rtl; \ No newline at end of file
diff --git a/fpga/usrp3/top/x400/cpld/ip/flash/.gitignore b/fpga/usrp3/top/x400/cpld/ip/flash/.gitignore
new file mode 100644
index 000000000..585bc126d
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/ip/flash/.gitignore
@@ -0,0 +1,3 @@
+# generate files
+on_chip_flash/
+on_chip_flash.sopcinfo
diff --git a/fpga/usrp3/top/x400/cpld/ip/flash/on_chip_flash.qsys b/fpga/usrp3/top/x400/cpld/ip/flash/on_chip_flash.qsys
new file mode 100644
index 000000000..4cbe8726a
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/ip/flash/on_chip_flash.qsys
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<system name="$${FILENAME}">
+ <component
+ name="$${FILENAME}"
+ displayName="$${FILENAME}"
+ version="1.0"
+ description=""
+ tags="INTERNAL_COMPONENT=true"
+ categories="System" />
+ <parameter name="bonusData"><![CDATA[bonusData
+{
+ element onchip_flash_0
+ {
+ datum _sortIndex
+ {
+ value = "0";
+ type = "int";
+ }
+ }
+}
+]]></parameter>
+ <parameter name="clockCrossingAdapter" value="HANDSHAKE" />
+ <parameter name="device" value="10M04SAU169I7G" />
+ <parameter name="deviceFamily" value="MAX 10" />
+ <parameter name="deviceSpeedGrade" value="7" />
+ <parameter name="fabricMode" value="QSYS" />
+ <parameter name="generateLegacySim" value="false" />
+ <parameter name="generationId" value="0" />
+ <parameter name="globalResetBus" value="false" />
+ <parameter name="hdlLanguage" value="VERILOG" />
+ <parameter name="hideFromIPCatalog" value="true" />
+ <parameter name="lockedInterfaceDefinition" value="" />
+ <parameter name="maxAdditionalLatency" value="1" />
+ <parameter name="projectName" value="" />
+ <parameter name="sopcBorderPoints" value="false" />
+ <parameter name="systemHash" value="0" />
+ <parameter name="testBenchDutName" value="" />
+ <parameter name="timeStamp" value="0" />
+ <parameter name="useTestBenchNamingPattern" value="false" />
+ <instanceScript></instanceScript>
+ <interface name="clk" internal="onchip_flash_0.clk" type="clock" dir="end">
+ <port name="clock" internal="clock" />
+ </interface>
+ <interface name="csr" internal="onchip_flash_0.csr" type="avalon" dir="end">
+ <port name="avmm_csr_addr" internal="avmm_csr_addr" />
+ <port name="avmm_csr_read" internal="avmm_csr_read" />
+ <port name="avmm_csr_writedata" internal="avmm_csr_writedata" />
+ <port name="avmm_csr_write" internal="avmm_csr_write" />
+ <port name="avmm_csr_readdata" internal="avmm_csr_readdata" />
+ </interface>
+ <interface name="data" internal="onchip_flash_0.data" type="avalon" dir="end">
+ <port name="avmm_data_addr" internal="avmm_data_addr" />
+ <port name="avmm_data_read" internal="avmm_data_read" />
+ <port name="avmm_data_writedata" internal="avmm_data_writedata" />
+ <port name="avmm_data_write" internal="avmm_data_write" />
+ <port name="avmm_data_readdata" internal="avmm_data_readdata" />
+ <port name="avmm_data_waitrequest" internal="avmm_data_waitrequest" />
+ <port name="avmm_data_readdatavalid" internal="avmm_data_readdatavalid" />
+ <port name="avmm_data_burstcount" internal="avmm_data_burstcount" />
+ </interface>
+ <interface name="nreset" internal="onchip_flash_0.nreset" type="reset" dir="end">
+ <port name="reset_n" internal="reset_n" />
+ </interface>
+ <module
+ name="onchip_flash_0"
+ kind="altera_onchip_flash"
+ version="18.1"
+ enabled="1"
+ autoexport="1">
+ <parameter name="AUTO_CLOCK_RATE" value="0" />
+ <parameter name="CLOCK_FREQUENCY" value="50.0" />
+ <parameter name="CONFIGURATION_MODE">Single Compressed Image</parameter>
+ <parameter name="CONFIGURATION_SCHEME">Internal Configuration</parameter>
+ <parameter name="DATA_INTERFACE" value="Parallel" />
+ <parameter name="DEVICE_FAMILY" value="MAX 10" />
+ <parameter name="PART_NAME" value="10M04SAU169I7G" />
+ <parameter name="READ_BURST_COUNT" value="8" />
+ <parameter name="READ_BURST_MODE" value="Incrementing" />
+ <parameter name="SECTOR_ACCESS_MODE">Read and write,Read and write,Read and write,Read and write,Read and write</parameter>
+ <parameter name="autoInitializationFileName">$${FILENAME}_onchip_flash_0</parameter>
+ <parameter name="initFlashContent" value="false" />
+ <parameter name="initializationFileName">altera_onchip_flash.hex</parameter>
+ <parameter name="initializationFileNameForSim">altera_onchip_flash.dat</parameter>
+ <parameter name="useNonDefaultInitFile" value="false" />
+ </module>
+ <interconnectRequirement for="$system" name="qsys_mm.clockCrossingAdapter" value="HANDSHAKE" />
+ <interconnectRequirement for="$system" name="qsys_mm.enableEccProtection" value="FALSE" />
+ <interconnectRequirement for="$system" name="qsys_mm.insertDefaultSlave" value="FALSE" />
+ <interconnectRequirement for="$system" name="qsys_mm.maxAdditionalLatency" value="1" />
+</system>
diff --git a/fpga/usrp3/top/x400/cpld/ip/oddr/oddr.qip b/fpga/usrp3/top/x400/cpld/ip/oddr/oddr.qip
new file mode 100644
index 000000000..206cf7b45
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/ip/oddr/oddr.qip
@@ -0,0 +1,74 @@
+set_global_assignment -entity "oddr" -library "oddr" -name IP_TOOL_NAME "altera_gpio_lite"
+set_global_assignment -entity "oddr" -library "oddr" -name IP_TOOL_VERSION "20.1"
+set_global_assignment -entity "oddr" -library "oddr" -name IP_TOOL_ENV "mwpim"
+set_global_assignment -library "oddr" -name MISC_FILE [file join $::quartus(qip_path) "oddr.cmp"]
+set_global_assignment -entity "oddr" -library "oddr" -name IP_TARGETED_DEVICE_FAMILY "MAX 10"
+set_global_assignment -entity "oddr" -library "oddr" -name IP_GENERATED_DEVICE_FAMILY "{MAX 10}"
+set_global_assignment -entity "oddr" -library "oddr" -name IP_QSYS_MODE "UNKNOWN"
+set_global_assignment -name SYNTHESIS_ONLY_QIP ON
+set_global_assignment -entity "oddr" -library "oddr" -name IP_COMPONENT_NAME "b2Rkcg=="
+set_global_assignment -entity "oddr" -library "oddr" -name IP_COMPONENT_DISPLAY_NAME "R1BJTyBMaXRlIEludGVsIEZQR0EgSVA="
+set_global_assignment -entity "oddr" -library "oddr" -name IP_COMPONENT_REPORT_HIERARCHY "Off"
+set_global_assignment -entity "oddr" -library "oddr" -name IP_COMPONENT_INTERNAL "Off"
+set_global_assignment -entity "oddr" -library "oddr" -name IP_COMPONENT_AUTHOR "SW50ZWwgQ29ycG9yYXRpb24="
+set_global_assignment -entity "oddr" -library "oddr" -name IP_COMPONENT_VERSION "MjAuMQ=="
+set_global_assignment -entity "oddr" -library "oddr" -name IP_COMPONENT_DESCRIPTION "R1BJTyBMaXRlIEludGVsIEZQR0EgSVA="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_NAME "YWx0ZXJhX2dwaW9fbGl0ZQ=="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_DISPLAY_NAME "R1BJTyBMaXRlIEludGVsIEZQR0EgSVA="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_REPORT_HIERARCHY "Off"
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_INTERNAL "Off"
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_AUTHOR "SW50ZWwgQ29ycG9yYXRpb24="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_VERSION "MjAuMQ=="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_DESCRIPTION "R1BJTyBMaXRlIEludGVsIEZQR0EgSVA="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "REVWSUNFX0ZBTUlMWQ==::TUFYIDEw::RGV2aWNlIGZhbWlseQ=="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "UElOX1RZUEU=::b3V0cHV0::RGF0YSBkaXJlY3Rpb24="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "U0laRQ==::MQ==::RGF0YSB3aWR0aA=="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX3RydWVfZGlmZl9idWY=::ZmFsc2U=::VXNlIHRydWUgZGlmZmVyZW50aWFsIGJ1ZmZlcg=="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX3BzZXVkb19kaWZmX2J1Zg==::ZmFsc2U=::VXNlIHBzZXVkbyBkaWZmZXJlbnRpYWwgYnVmZmVy"
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2J1c19ob2xk::ZmFsc2U=::VXNlIGJ1cy1ob2xkIGNpcmN1aXRyeQ=="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX29wZW5fZHJhaW4=::ZmFsc2U=::VXNlIG9wZW4gZHJhaW4gb3V0cHV0"
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9vZV9wb3J0::ZmFsc2U=::RW5hYmxlIG9lIHBvcnQ="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2lvX3JlZ19tb2Rl::ZGRy::UmVnaXN0ZXIgbW9kZQ=="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9hY2xyX3BvcnQ=::dHJ1ZQ==::RW5hYmxlIGFjbHIgcG9ydA=="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2Nsb2NrX2VuYWJsZQ==::ZmFsc2U=::RW5hYmxlIGluY2xvY2tlbi9vdXRjbG9ja2VuIHBvcnRz"
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2ludmVydF9vdXRwdXQ=::ZmFsc2U=::SW52ZXJ0IGRpbg=="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX3VzZV9yZWdpc3Rlcl90b19kcml2ZV9vYnVmX29l::ZmFsc2U=::VXNlIGEgc2luZ2xlIHJlZ2lzdGVyIHRvIGRyaXZlIHRoZSBvdXRwdXQgZW5hYmxlIChvZSkgc2lnbmFsIGF0IHRoZSBJL08gYnVmZmVy"
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX3VzZV9kZGlvX3JlZ190b19kcml2ZV9vZQ==::ZmFsc2U=::VXNlIERESU8gcmVnaXN0ZXJzIHRvIGRyaXZlIHRoZSBvdXRwdXQgZW5hYmxlIChvZSkgc2lnbmFsIGF0IHRoZSBJL08gYnVmZmVy"
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX3VzZV9hZHZhbmNlZF9kZHJfZmVhdHVyZXM=::ZmFsc2U=::RW5hYmxlIGFkdmFuY2VkIEREUiBmZWF0dXJlcw=="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9waGFzZV9kZXRlY3Rvcl9mb3JfY2s=::ZmFsc2U=::RW5hYmxlIFBoYXNlIERldGVjdG9yIGZyb20gQ0sgbG9vcGJhY2sgc2lnbmFs"
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9vZV9oYWxmX2N5Y2xlX2RlbGF5::dHJ1ZQ==::QWRkIGhhbGYtY3ljbGUgZGVsYXkgdG8gT0Ugc2lnbmFs"
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9ocl9jbG9jaw==::ZmFsc2U=::RW5hYmxlIGhhbGYtcmF0ZSBjbG9jayBwb3J0"
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9pbnZlcnRfaHJfY2xvY2tfcG9ydA==::ZmFsc2U=::RW5hYmxlIGludmVydF9ocl9jbG9jayBwb3J0"
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2ludmVydF9jbGtkaXZfaW5wdXRfY2xvY2s=::ZmFsc2U=::SW52ZXJ0IGNsb2NrIGRpdmlkZXIgaW5wdXQgY2xvY2s="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2ludmVydF9vdXRwdXRfY2xvY2s=::ZmFsc2U=::SW52ZXJ0IERESU8gb3V0Y2xvY2s="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "Z3VpX2ludmVydF9vZV9pbmNsb2Nr::ZmFsc2U=::SW52ZXJ0IG91dHB1dCBlbmFibGUgKG9lKSByZWdpc3RlciBpbmNsb2Nr"
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "UkVHSVNURVJfTU9ERQ==::ZGRy::UkVHSVNURVJfTU9ERQ=="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "QlVGRkVSX1RZUEU=::c2luZ2xlLWVuZGVk::QlVGRkVSX1RZUEU="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "QVNZTkNfTU9ERQ==::Y2xlYXI=::QVNZTkNfTU9ERQ=="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "U1lOQ19NT0RF::bm9uZQ==::U1lOQ19NT0RF"
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "QlVTX0hPTEQ=::ZmFsc2U=::QlVTX0hPTEQ="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "T1BFTl9EUkFJTl9PVVRQVVQ=::ZmFsc2U=::T1BFTl9EUkFJTl9PVVRQVVQ="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "RU5BQkxFX09FX1BPUlQ=::ZmFsc2U=::RU5BQkxFX09FX1BPUlQ="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "RU5BQkxFX05TTEVFUF9QT1JU::ZmFsc2U=::RU5BQkxFX05TTEVFUF9QT1JU"
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "RU5BQkxFX0NMT0NLX0VOQV9QT1JU::ZmFsc2U=::RU5BQkxFX0NMT0NLX0VOQV9QT1JU"
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "U0VUX1JFR0lTVEVSX09VVFBVVFNfSElHSA==::ZmFsc2U=::U0VUX1JFR0lTVEVSX09VVFBVVFNfSElHSA=="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "SU5WRVJUX09VVFBVVA==::ZmFsc2U=::SU5WRVJUX09VVFBVVA=="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "SU5WRVJUX0lOUFVUX0NMT0NL::ZmFsc2U=::SU5WRVJUX0lOUFVUX0NMT0NL"
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "VVNFX09ORV9SRUdfVE9fRFJJVkVfT0U=::ZmFsc2U=::VVNFX09ORV9SRUdfVE9fRFJJVkVfT0U="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "VVNFX0RESU9fUkVHX1RPX0RSSVZFX09F::ZmFsc2U=::VVNFX0RESU9fUkVHX1RPX0RSSVZFX09F"
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "VVNFX0FEVkFOQ0VEX0REUl9GRUFUVVJFUw==::ZmFsc2U=::VVNFX0FEVkFOQ0VEX0REUl9GRUFUVVJFUw=="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "VVNFX0FEVkFOQ0VEX0REUl9GRUFUVVJFU19GT1JfSU5QVVRfT05MWQ==::ZmFsc2U=::VVNFX0FEVkFOQ0VEX0REUl9GRUFUVVJFU19GT1JfSU5QVVRfT05MWQ=="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "RU5BQkxFX09FX0hBTEZfQ1lDTEVfREVMQVk=::dHJ1ZQ==::RU5BQkxFX09FX0hBTEZfQ1lDTEVfREVMQVk="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "SU5WRVJUX0NMS0RJVl9JTlBVVF9DTE9DSw==::ZmFsc2U=::SU5WRVJUX0NMS0RJVl9JTlBVVF9DTE9DSw=="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "RU5BQkxFX1BIQVNFX0lOVkVSVF9DVFJMX1BPUlQ=::ZmFsc2U=::RU5BQkxFX1BIQVNFX0lOVkVSVF9DVFJMX1BPUlQ="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "RU5BQkxFX0hSX0NMT0NL::ZmFsc2U=::RU5BQkxFX0hSX0NMT0NL"
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "SU5WRVJUX09VVFBVVF9DTE9DSw==::ZmFsc2U=::SU5WRVJUX09VVFBVVF9DTE9DSw=="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "SU5WRVJUX09FX0lOQ0xPQ0s=::ZmFsc2U=::SU5WRVJUX09FX0lOQ0xPQ0s="
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_COMPONENT_PARAMETER "RU5BQkxFX1BIQVNFX0RFVEVDVE9SX0ZPUl9DSw==::ZmFsc2U=::RU5BQkxFX1BIQVNFX0RFVEVDVE9SX0ZPUl9DSw=="
+
+set_global_assignment -library "oddr" -name VERILOG_FILE [file join $::quartus(qip_path) "oddr.v"]
+set_global_assignment -library "oddr" -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "oddr/altera_gpio_lite.sv"]
+
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_TOOL_NAME "altera_gpio_lite"
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_TOOL_VERSION "20.1"
+set_global_assignment -entity "altera_gpio_lite" -library "oddr" -name IP_TOOL_ENV "mwpim"
diff --git a/fpga/usrp3/top/x400/cpld/ip/oddr/oddr.v b/fpga/usrp3/top/x400/cpld/ip/oddr/oddr.v
new file mode 100644
index 000000000..7888cbcf5
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/ip/oddr/oddr.v
@@ -0,0 +1,124 @@
+// megafunction wizard: %GPIO Lite Intel FPGA IP v20.1%
+// GENERATION: XML
+// oddr.v
+
+// Generated using ACDS version 20.1 711
+
+`timescale 1 ps / 1 ps
+module oddr (
+ input wire outclock, // outclock.export
+ input wire [1:0] din, // din.export
+ output wire [0:0] pad_out, // pad_out.export
+ input wire aclr // aclr.export
+ );
+
+ altera_gpio_lite #(
+ .PIN_TYPE ("output"),
+ .SIZE (1),
+ .REGISTER_MODE ("ddr"),
+ .BUFFER_TYPE ("single-ended"),
+ .ASYNC_MODE ("clear"),
+ .SYNC_MODE ("none"),
+ .BUS_HOLD ("false"),
+ .OPEN_DRAIN_OUTPUT ("false"),
+ .ENABLE_OE_PORT ("false"),
+ .ENABLE_NSLEEP_PORT ("false"),
+ .ENABLE_CLOCK_ENA_PORT ("false"),
+ .SET_REGISTER_OUTPUTS_HIGH ("false"),
+ .INVERT_OUTPUT ("false"),
+ .INVERT_INPUT_CLOCK ("false"),
+ .USE_ONE_REG_TO_DRIVE_OE ("false"),
+ .USE_DDIO_REG_TO_DRIVE_OE ("false"),
+ .USE_ADVANCED_DDR_FEATURES ("false"),
+ .USE_ADVANCED_DDR_FEATURES_FOR_INPUT_ONLY ("false"),
+ .ENABLE_OE_HALF_CYCLE_DELAY ("true"),
+ .INVERT_CLKDIV_INPUT_CLOCK ("false"),
+ .ENABLE_PHASE_INVERT_CTRL_PORT ("false"),
+ .ENABLE_HR_CLOCK ("false"),
+ .INVERT_OUTPUT_CLOCK ("false"),
+ .INVERT_OE_INCLOCK ("false"),
+ .ENABLE_PHASE_DETECTOR_FOR_CK ("false")
+ ) oddr_inst (
+ .outclock (outclock), // outclock.export
+ .din (din), // din.export
+ .pad_out (pad_out), // pad_out.export
+ .aclr (aclr), // aclr.export
+ .outclocken (1'b1), // (terminated)
+ .inclock (1'b0), // (terminated)
+ .inclocken (1'b0), // (terminated)
+ .fr_clock (), // (terminated)
+ .hr_clock (), // (terminated)
+ .invert_hr_clock (1'b0), // (terminated)
+ .phy_mem_clock (1'b0), // (terminated)
+ .mimic_clock (), // (terminated)
+ .dout (), // (terminated)
+ .pad_io (), // (terminated)
+ .pad_io_b (), // (terminated)
+ .pad_in (1'b0), // (terminated)
+ .pad_in_b (1'b0), // (terminated)
+ .pad_out_b (), // (terminated)
+ .aset (1'b0), // (terminated)
+ .sclr (1'b0), // (terminated)
+ .nsleep (1'b0), // (terminated)
+ .oe (1'b0) // (terminated)
+ );
+
+endmodule
+// Retrieval info: <?xml version="1.0"?>
+//<!--
+// Generated by Altera MegaWizard Launcher Utility version 1.0
+// ************************************************************
+// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
+// ************************************************************
+// Copyright (C) 1991-2020 Altera Corporation
+// Any megafunction design, and related net list (encrypted or decrypted),
+// support information, device programming or simulation file, and any other
+// associated documentation or information provided by Altera or a partner
+// under Altera's Megafunction Partnership Program may be used only to
+// program PLD devices (but not masked PLD devices) from Altera. Any other
+// use of such megafunction design, net list, support information, device
+// programming or simulation file, or any other related documentation or
+// information is prohibited for any other purpose, including, but not
+// limited to modification, reverse engineering, de-compiling, or use with
+// any other silicon devices, unless such use is explicitly licensed under
+// a separate agreement with Altera or a megafunction partner. Title to
+// the intellectual property, including patents, copyrights, trademarks,
+// trade secrets, or maskworks, embodied in any such megafunction design,
+// net list, support information, device programming or simulation file, or
+// any other related documentation or information provided by Altera or a
+// megafunction partner, remains with Altera, the megafunction partner, or
+// their respective licensors. No other licenses, including any licenses
+// needed under any third party's intellectual property, are provided herein.
+//-->
+// Retrieval info: <instance entity-name="altera_gpio_lite" version="20.1" >
+// Retrieval info: <generic name="DEVICE_FAMILY" value="MAX 10" />
+// Retrieval info: <generic name="PIN_TYPE" value="output" />
+// Retrieval info: <generic name="SIZE" value="1" />
+// Retrieval info: <generic name="gui_true_diff_buf" value="false" />
+// Retrieval info: <generic name="gui_pseudo_diff_buf" value="false" />
+// Retrieval info: <generic name="gui_bus_hold" value="false" />
+// Retrieval info: <generic name="gui_open_drain" value="false" />
+// Retrieval info: <generic name="gui_enable_oe_port" value="false" />
+// Retrieval info: <generic name="gui_enable_nsleep_port" value="false" />
+// Retrieval info: <generic name="gui_io_reg_mode" value="ddr" />
+// Retrieval info: <generic name="gui_enable_aclr_port" value="true" />
+// Retrieval info: <generic name="gui_enable_aset_port" value="false" />
+// Retrieval info: <generic name="gui_enable_sclr_port" value="false" />
+// Retrieval info: <generic name="gui_set_registers_to_power_up_high" value="false" />
+// Retrieval info: <generic name="gui_clock_enable" value="false" />
+// Retrieval info: <generic name="gui_invert_output" value="false" />
+// Retrieval info: <generic name="gui_invert_input_clock" value="false" />
+// Retrieval info: <generic name="gui_use_register_to_drive_obuf_oe" value="false" />
+// Retrieval info: <generic name="gui_use_ddio_reg_to_drive_oe" value="false" />
+// Retrieval info: <generic name="gui_use_advanced_ddr_features" value="false" />
+// Retrieval info: <generic name="gui_enable_phase_detector_for_ck" value="false" />
+// Retrieval info: <generic name="gui_enable_oe_half_cycle_delay" value="true" />
+// Retrieval info: <generic name="gui_enable_hr_clock" value="false" />
+// Retrieval info: <generic name="gui_enable_invert_hr_clock_port" value="false" />
+// Retrieval info: <generic name="gui_invert_clkdiv_input_clock" value="false" />
+// Retrieval info: <generic name="gui_invert_output_clock" value="false" />
+// Retrieval info: <generic name="gui_invert_oe_inclock" value="false" />
+// Retrieval info: <generic name="gui_use_hardened_ddio_input_registers" value="false" />
+// Retrieval info: </instance>
+// IPFS_FILES : oddr.vo
+// RELATED_FILES: oddr.v, altera_gpio_lite.sv
diff --git a/fpga/usrp3/top/x400/cpld/ip/oddr/oddr/altera_gpio_lite.sv b/fpga/usrp3/top/x400/cpld/ip/oddr/oddr/altera_gpio_lite.sv
new file mode 100644
index 000000000..7db369453
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/ip/oddr/oddr/altera_gpio_lite.sv
@@ -0,0 +1,1200 @@
+// (C) 2001-2020 Intel Corporation. All rights reserved.
+// Your use of Intel Corporation's design tools, logic functions and other
+// software and tools, and its AMPP partner logic functions, and any output
+// files from any of the foregoing (including device programming or simulation
+// files), and any associated documentation or information are expressly subject
+// to the terms and conditions of the Intel Program License Subscription
+// Agreement, Intel FPGA IP License Agreement, or other applicable
+// license agreement, including, without limitation, that your use is for the
+// sole purpose of programming logic devices manufactured by Intel and sold by
+// Intel or its authorized distributors. Please refer to the applicable
+// agreement for further details.
+
+
+`timescale 1 ps / 1 ps
+
+module altgpio_one_bit(
+ inclock,
+ outclock,
+ phy_mem_clock,
+ inclocken,
+ outclocken,
+ oe,
+ din,
+ dout,
+ pad,
+ pad_b,
+ aset,
+ sclr,
+ hr_clock,
+ fr_clock,
+ mimic_clock,
+ nsleep
+);
+
+ parameter PIN_TYPE = "output";
+ parameter BUFFER_TYPE = "single-ended";
+ parameter REGISTER_MODE = "bypass";
+ parameter ASYNC_MODE = "none";
+ parameter SYNC_MODE = "none";
+ parameter BUS_HOLD = "false";
+ parameter SET_REGISTER_OUTPUTS_HIGH = "false";
+ parameter USE_ENHANCED_DDR_HIO_REGISTER = "false";
+ parameter BYPASS_THREE_QUARTER_REGISTER = "true";
+ parameter INVERT_OUTPUT = "false";
+ parameter INVERT_INPUT_CLOCK = "false";
+ parameter INVERT_OUTPUT_CLOCK = "false";
+ parameter INVERT_OE_INCLOCK = "false";
+ parameter USE_ONE_REG_TO_DRIVE_OE = "false";
+ parameter USE_DDIO_REG_TO_DRIVE_OE = "false";
+ parameter OPEN_DRAIN_OUTPUT = "false";
+ parameter ENABLE_OE_HALF_CYCLE_DELAY = "true";
+ parameter USE_ADVANCED_DDR_FEATURES_FOR_INPUT_ONLY = "false";
+ parameter ENABLE_CLOCK_ENA_PORT = "false";
+ parameter ENABLE_HR_CLOCK = "false";
+ parameter ENABLE_PHASE_DETECTOR_FOR_CK = "false";
+ parameter ENABLE_NSLEEP_PORT = "false";
+
+ localparam DATA_SIZE = (REGISTER_MODE == "ddr") ? 2:1;
+ localparam DDIO_REG_POWER_UP = (ASYNC_MODE == "preset" || SET_REGISTER_OUTPUTS_HIGH == "true") ? "high" : "low";
+
+ input inclock;
+ input outclock;
+ input inclocken;
+ input outclocken;
+ input oe;
+ input nsleep;
+ input [DATA_SIZE - 1:0] din;
+ output [DATA_SIZE - 1:0] dout;
+ inout pad;
+ inout pad_b;
+ input aset;
+ input sclr;
+ input phy_mem_clock;
+ input hr_clock;
+ (* altera_attribute = "-name GLOBAL_SIGNAL\"OFF\"" *) output fr_clock;
+ output mimic_clock;
+
+ wire din_ddr;
+ wire buf_in;
+
+ wire oe_out;
+ wire nsleep_in;
+
+ generate
+ if (PIN_TYPE == "output" || PIN_TYPE == "bidir")
+ begin
+ wire [1:0] din_fr;
+ if (INVERT_OUTPUT == "false")
+ begin
+ assign din_fr = din;
+ end
+ else
+ begin
+ assign din_fr = ~din;
+ end
+
+ wire outclock_wire;
+ if (REGISTER_MODE != "bypass")
+ begin
+ if (INVERT_OUTPUT_CLOCK == "false")
+ begin: normal_input_clock
+ assign outclock_wire = outclock;
+ end
+ else
+ begin: inverted_output_clock
+ assign outclock_wire = ~outclock;
+ end
+ end
+
+ wire outclocken_wire;
+ assign outclocken_wire = (ENABLE_CLOCK_ENA_PORT == "true") ? outclocken : 1'b1;
+
+ if (REGISTER_MODE == "ddr" && USE_ENHANCED_DDR_HIO_REGISTER == "true")
+ begin
+ if (ASYNC_MODE != "none")
+ begin: async_mode_out_path_enhanced_ddr
+ fiftyfivenm_ddio_out
+ #(
+ .async_mode(ASYNC_MODE),
+ .sync_mode(SYNC_MODE),
+ .use_enhanced_ddr_hio(USE_ENHANCED_DDR_HIO_REGISTER),
+ .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER),
+ .power_up(DDIO_REG_POWER_UP),
+ .use_new_clocking_model("true")
+ ) fr_out_data_ddio (
+ .datainhi(din_fr[0]),
+ .datainlo(din_fr[1]),
+ .dataout(din_ddr),
+ .clkhi(outclock_wire),
+ .clklo(outclock_wire),
+ .muxsel(outclock_wire),
+ .areset(aset),
+ .ena(outclocken_wire),
+ .phymemclock(phy_mem_clock)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .clk (outclock_wire),
+ .sreset(1'b0),
+ .dfflo(),
+ .dffhi(),
+ .devpor(1'b1),
+ .devclrn(1'b1)
+ `endif
+ );
+ end
+ else if (SYNC_MODE != "none")
+ begin: sync_mode_out_path_enhanced_ddr
+ fiftyfivenm_ddio_out
+ #(
+ .async_mode(ASYNC_MODE),
+ .sync_mode(SYNC_MODE),
+ .use_enhanced_ddr_hio(USE_ENHANCED_DDR_HIO_REGISTER),
+ .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER),
+ .power_up(DDIO_REG_POWER_UP),
+ .use_new_clocking_model("true")
+ ) fr_out_data_ddio (
+ .datainhi(din_fr[0]),
+ .datainlo(din_fr[1]),
+ .dataout(din_ddr),
+ .clkhi(outclock_wire),
+ .clklo(outclock_wire),
+ .muxsel(outclock_wire),
+ .sreset(sclr),
+ .ena(outclocken_wire),
+ .phymemclock(phy_mem_clock)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .clk (outclock_wire),
+ .areset(1'b0),
+ .dfflo(),
+ .dffhi(),
+ .devpor(1'b1),
+ .devclrn(1'b1)
+ `endif
+ );
+ end
+ else
+ begin: out_path_enhanced_ddr
+ fiftyfivenm_ddio_out
+ #(
+ .async_mode(ASYNC_MODE),
+ .sync_mode(SYNC_MODE),
+ .use_enhanced_ddr_hio(USE_ENHANCED_DDR_HIO_REGISTER),
+ .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER),
+ .power_up(DDIO_REG_POWER_UP),
+ .use_new_clocking_model("true")
+ ) fr_out_data_ddio (
+ .datainhi(din_fr[0]),
+ .datainlo(din_fr[1]),
+ .dataout(din_ddr),
+ .clkhi(outclock_wire),
+ .clklo(outclock_wire),
+ .muxsel(outclock_wire),
+ .ena(outclocken_wire),
+ .phymemclock(phy_mem_clock)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .areset(1'b0),
+ .clk(1'b0),
+ .sreset(1'b0),
+ .dfflo(),
+ .dffhi(),
+ .devpor(1'b1),
+ .devclrn(1'b1)
+ `endif
+ );
+ end
+ end
+ else if (REGISTER_MODE == "ddr" && USE_ENHANCED_DDR_HIO_REGISTER == "false")
+ begin
+ if (ASYNC_MODE != "none")
+ begin: async_mode_out_path_ddr
+ fiftyfivenm_ddio_out
+ #(
+ .async_mode(ASYNC_MODE),
+ .sync_mode(SYNC_MODE),
+ .power_up(DDIO_REG_POWER_UP),
+ .use_new_clocking_model("true"),
+ .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER)
+ ) fr_out_data_ddio (
+ .datainhi(din_fr[0]),
+ .datainlo(din_fr[1]),
+ .dataout(din_ddr),
+ .clkhi(outclock_wire),
+ .clklo(outclock_wire),
+ .muxsel(outclock_wire),
+ .areset(aset),
+ .ena(outclocken_wire)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .clk(1'b0),
+ .phymemclock(1'b0),
+ .sreset(1'b0),
+ .dfflo(),
+ .dffhi(),
+ .devpor(1'b1),
+ .devclrn(1'b1)
+ `endif
+ );
+ end
+ else if (SYNC_MODE != "none")
+ begin: sync_mode_out_path_ddr
+ fiftyfivenm_ddio_out
+ #(
+ .async_mode(ASYNC_MODE),
+ .sync_mode(SYNC_MODE),
+ .power_up(DDIO_REG_POWER_UP),
+ .use_new_clocking_model("true"),
+ .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER)
+ ) fr_out_data_ddio (
+ .datainhi(din_fr[0]),
+ .datainlo(din_fr[1]),
+ .dataout(din_ddr),
+ .clkhi(outclock_wire),
+ .clklo(outclock_wire),
+ .muxsel(outclock_wire),
+ .sreset(sclr),
+ .ena(outclocken_wire)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .areset(1'b0),
+ .clk(1'b0),
+ .phymemclock(1'b0),
+ .dfflo(),
+ .dffhi(),
+ .devpor(1'b1),
+ .devclrn(1'b1)
+ `endif
+ );
+ end
+ else
+ begin: out_path_ddr
+ fiftyfivenm_ddio_out
+ #(
+ .async_mode(ASYNC_MODE),
+ .sync_mode(SYNC_MODE),
+ .power_up(DDIO_REG_POWER_UP),
+ .use_new_clocking_model("true"),
+ .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER)
+ ) fr_out_data_ddio (
+ .datainhi(din_fr[0]),
+ .datainlo(din_fr[1]),
+ .dataout(din_ddr),
+ .clkhi(outclock_wire),
+ .clklo(outclock_wire),
+ .muxsel(outclock_wire),
+ .ena(outclocken_wire)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .areset(1'b0),
+ .clk(1'b0),
+ .phymemclock(1'b0),
+ .sreset(1'b0),
+ .dfflo(),
+ .dffhi(),
+ .devpor(1'b1),
+ .devclrn(1'b1)
+ `endif
+ );
+ end
+ end
+ else if (REGISTER_MODE == "single-register")
+ begin: out_path_sdr
+ reg reg_data_out /* synthesis altera_attribute="FAST_OUTPUT_REGISTER=on" */;
+ always @(posedge outclock_wire)
+ reg_data_out <= din_fr[0];
+
+ assign din_ddr = reg_data_out;
+ end
+ else
+ begin: out_path_reg_none
+ assign din_ddr = din_fr[0];
+ end
+ end
+ endgenerate
+
+ generate
+
+ if (PIN_TYPE == "bidir" || PIN_TYPE == "output")
+ begin
+ wire oe_inclk_wire;
+ if (USE_ONE_REG_TO_DRIVE_OE == "true" || USE_DDIO_REG_TO_DRIVE_OE == "true")
+ begin
+ if (INVERT_OE_INCLOCK == "false")
+ begin: normal_oe_inclock
+ assign oe_inclk_wire = outclock;
+ end
+ else
+ begin: inverted_oe_inclock
+ assign oe_inclk_wire = ~outclock;
+ end
+ end
+
+ wire oe_outclocken_wire;
+ assign oe_outclocken_wire = (ENABLE_CLOCK_ENA_PORT == "true") ? outclocken : 1'b1;
+
+ if (USE_DDIO_REG_TO_DRIVE_OE == "true")
+ begin
+ if (REGISTER_MODE == "ddr" && USE_ENHANCED_DDR_HIO_REGISTER == "true")
+ begin
+ if (ASYNC_MODE != "none")
+ begin: async_mode_oe_path_enhanced_ddr
+ fiftyfivenm_ddio_oe
+ #(
+ .async_mode(ASYNC_MODE),
+ .sync_mode(SYNC_MODE),
+ .use_enhanced_ddr_hio(USE_ENHANCED_DDR_HIO_REGISTER),
+ .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER),
+ .enable_half_cycle_delay(ENABLE_OE_HALF_CYCLE_DELAY),
+ .power_up(DDIO_REG_POWER_UP)
+ ) fr_oe_data_ddio (
+ .oe(~oe),
+ .dataout(oe_out),
+ .clk(oe_inclk_wire),
+ .areset(aset),
+ .ena(oe_outclocken_wire),
+ .phymemclock(phy_mem_clock)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .sreset(1'b0),
+ .dfflo(),
+ .dffhi(),
+ .devpor(1'b1),
+ .devclrn(1'b1)
+ `endif
+ );
+ end
+ else if (SYNC_MODE != "none")
+ begin: sync_mode_oe_path_enhanced_ddr
+ fiftyfivenm_ddio_oe
+ #(
+ .async_mode(ASYNC_MODE),
+ .sync_mode(SYNC_MODE),
+ .use_enhanced_ddr_hio(USE_ENHANCED_DDR_HIO_REGISTER),
+ .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER),
+ .enable_half_cycle_delay(ENABLE_OE_HALF_CYCLE_DELAY),
+ .power_up(DDIO_REG_POWER_UP)
+ ) fr_oe_data_ddio (
+ .oe(~oe),
+ .dataout(oe_out),
+ .clk(oe_inclk_wire),
+ .sreset(sclr),
+ .ena(oe_outclocken_wire),
+ .phymemclock(phy_mem_clock)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .areset(1'b0),
+ .dfflo(),
+ .dffhi(),
+ .devpor(1'b1),
+ .devclrn(1'b1)
+ `endif
+ );
+ end
+ else
+ begin: oe_path_enhanced_ddr
+ fiftyfivenm_ddio_oe
+ #(
+ .async_mode(ASYNC_MODE),
+ .sync_mode(SYNC_MODE),
+ .use_enhanced_ddr_hio(USE_ENHANCED_DDR_HIO_REGISTER),
+ .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER),
+ .enable_half_cycle_delay(ENABLE_OE_HALF_CYCLE_DELAY),
+ .power_up(DDIO_REG_POWER_UP)
+ ) fr_oe_data_ddio (
+ .oe(~oe),
+ .dataout(oe_out),
+ .clk(oe_inclk_wire),
+ .ena(oe_outclocken_wire),
+ .phymemclock(phy_mem_clock)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .areset(1'b0),
+ .sreset(1'b0),
+ .dfflo(),
+ .dffhi(),
+ .devpor(1'b1),
+ .devclrn(1'b1)
+ `endif
+ );
+ end
+ end
+ else if (REGISTER_MODE == "ddr" && USE_ENHANCED_DDR_HIO_REGISTER == "false")
+ begin
+ if (ASYNC_MODE != "none")
+ begin: async_mode_oe_path_ddr
+ fiftyfivenm_ddio_oe
+ #(
+ .async_mode(ASYNC_MODE),
+ .sync_mode(SYNC_MODE),
+ .enable_half_cycle_delay(ENABLE_OE_HALF_CYCLE_DELAY),
+ .power_up(DDIO_REG_POWER_UP),
+ .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER)
+ ) fr_oe_data_ddio (
+ .oe(~oe),
+ .dataout(oe_out),
+ .clk(oe_inclk_wire),
+ .areset(aset),
+ .ena(oe_outclocken_wire)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .phymemclock(1'b0),
+ .sreset(1'b0),
+ .dfflo(),
+ .dffhi(),
+ .devpor(1'b1),
+ .devclrn(1'b1)
+ `endif
+ );
+ end
+ else if (SYNC_MODE != "none")
+ begin: sync_mode_oe_path_ddr
+ fiftyfivenm_ddio_oe
+ #(
+ .async_mode(ASYNC_MODE),
+ .sync_mode(SYNC_MODE),
+ .enable_half_cycle_delay(ENABLE_OE_HALF_CYCLE_DELAY),
+ .power_up(DDIO_REG_POWER_UP),
+ .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER)
+ ) fr_oe_data_ddio (
+ .oe(~oe),
+ .dataout(oe_out),
+ .clk(oe_inclk_wire),
+ .sreset(sclr),
+ .ena(oe_outclocken_wire)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .areset(1'b0),
+ .phymemclock(1'b0),
+ .dfflo(),
+ .dffhi(),
+ .devpor(1'b1),
+ .devclrn(1'b1)
+ `endif
+ );
+ end
+ else
+ begin: oe_path_ddr
+ fiftyfivenm_ddio_oe
+ #(
+ .async_mode(ASYNC_MODE),
+ .sync_mode(SYNC_MODE),
+ .enable_half_cycle_delay(ENABLE_OE_HALF_CYCLE_DELAY),
+ .power_up(DDIO_REG_POWER_UP),
+ .bypass_three_quarter_register(BYPASS_THREE_QUARTER_REGISTER)
+ ) fr_oe_data_ddio (
+ .oe(~oe),
+ .dataout(oe_out),
+ .clk(oe_inclk_wire),
+ .ena(oe_outclocken_wire)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .areset(1'b0),
+ .phymemclock(1'b0),
+ .sreset(1'b0),
+ .dfflo(),
+ .dffhi(),
+ .devpor(1'b1),
+ .devclrn(1'b1)
+ `endif
+ );
+ end
+ end
+ end
+ else if (USE_ONE_REG_TO_DRIVE_OE == "true")
+ begin: oe_path_sdr
+ fiftyfivenm_ff oe_reg (
+ .clk(oe_inclk_wire),
+ .d(~oe),
+ .clrn(1'b1),
+ .ena(1'b1),
+ .q(oe_out)
+ );
+ end
+ else if (USE_ONE_REG_TO_DRIVE_OE == "false" && USE_DDIO_REG_TO_DRIVE_OE == "false")
+ begin: oe_path_reg_none
+ assign oe_out = ~oe;
+ end
+ end
+ endgenerate
+
+ generate
+ if (PIN_TYPE == "input" || PIN_TYPE == "bidir")
+ begin
+ wire [1:0] ddr_input;
+ wire inclock_wire;
+
+ if (REGISTER_MODE != "bypass")
+ begin
+ if (INVERT_INPUT_CLOCK == "false")
+ begin: normal_input_clock
+ assign inclock_wire = inclock;
+ end
+ else
+ begin: inverted_input_clock
+ assign inclock_wire = ~inclock;
+ end
+ end
+
+ wire inclocken_wire;
+ assign inclocken_wire = (ENABLE_CLOCK_ENA_PORT == "true") ? inclocken : 1'b1;
+
+ if (REGISTER_MODE == "ddr")
+ begin
+ if (USE_ENHANCED_DDR_HIO_REGISTER == "true" || USE_ADVANCED_DDR_FEATURES_FOR_INPUT_ONLY == "true")
+ begin
+ if (ENABLE_HR_CLOCK == "true")
+ begin
+ if (ASYNC_MODE != "none")
+ begin: async_mode_in_path_enhanced_ddr_with_halfrateresyncclk
+ fiftyfivenm_ddio_in
+ #(
+ .async_mode(ASYNC_MODE),
+ .sync_mode(SYNC_MODE),
+ .power_up(DDIO_REG_POWER_UP),
+ .invert_input_clock(INVERT_INPUT_CLOCK)
+ ) fr_in_ddio (
+ .datain(buf_in),
+ .clk(inclock_wire),
+ .ena(inclocken_wire),
+ .halfrateresyncclk(hr_clock),
+ .regouthi(ddr_input[1]),
+ .regoutlo(ddr_input[0]),
+ .clkout(fr_clock),
+ .areset(aset)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .sreset(1'b0),
+ .dfflo(),
+ .devpor(1'b1),
+ .devclrn(1'b1)
+ `endif
+ );
+ end
+ else if (SYNC_MODE != "none")
+ begin:sync_mode_in_path_enhanced_ddr_with_halfrateresyncclk
+ fiftyfivenm_ddio_in
+ #(
+ .async_mode(ASYNC_MODE),
+ .sync_mode(SYNC_MODE),
+ .power_up(DDIO_REG_POWER_UP),
+ .invert_input_clock(INVERT_INPUT_CLOCK)
+ ) fr_in_ddio (
+ .datain(buf_in),
+ .clk (inclock_wire),
+ .ena(inclocken_wire),
+ .sreset(sclr),
+ .halfrateresyncclk(hr_clock),
+ .regouthi(ddr_input[1]),
+ .regoutlo(ddr_input[0]),
+ .clkout(fr_clock)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .areset(1'b0),
+ .dfflo(),
+ .devpor(1'b1),
+ .devclrn(1'b1)
+ `endif
+ );
+ end
+ else
+ begin:in_path_enhanced_ddr_with_halfrateresyncclk
+ fiftyfivenm_ddio_in
+ #(
+ .async_mode(ASYNC_MODE),
+ .sync_mode(SYNC_MODE),
+ .power_up(DDIO_REG_POWER_UP),
+ .invert_input_clock(INVERT_INPUT_CLOCK)
+ ) fr_in_ddio (
+ .datain(buf_in),
+ .clk (inclock_wire),
+ .ena(inclocken_wire),
+ .halfrateresyncclk(hr_clock),
+ .regouthi(ddr_input[1]),
+ .regoutlo(ddr_input[0]),
+ .clkout(fr_clock)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .sreset(1'b0),
+ .areset(1'b0),
+ .dfflo(),
+ .devpor(1'b1),
+ .devclrn(1'b1)
+ `endif
+ );
+ end
+ end
+ else
+ begin
+ if (ASYNC_MODE != "none")
+ begin: async_mode_in_path_enhanced_ddr
+ fiftyfivenm_ddio_in
+ #(
+ .async_mode(ASYNC_MODE),
+ .sync_mode(SYNC_MODE),
+ .power_up(DDIO_REG_POWER_UP),
+ .invert_input_clock(INVERT_INPUT_CLOCK)
+ ) fr_in_ddio (
+ .datain(buf_in),
+ .clk(inclock_wire),
+ .ena(inclocken_wire),
+ .regouthi(ddr_input[1]),
+ .regoutlo(ddr_input[0]),
+ .clkout(fr_clock),
+ .areset(aset)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .sreset(1'b0),
+ .dfflo(),
+ .devpor(1'b1),
+ .devclrn(1'b1),
+ .halfrateresyncclk(1'b0)
+ `endif
+ );
+ end
+ else if (SYNC_MODE != "none")
+ begin:sync_mode_in_path_enhanced_ddr
+ fiftyfivenm_ddio_in
+ #(
+ .async_mode(ASYNC_MODE),
+ .sync_mode(SYNC_MODE),
+ .power_up(DDIO_REG_POWER_UP),
+ .invert_input_clock(INVERT_INPUT_CLOCK)
+ ) fr_in_ddio (
+ .datain(buf_in),
+ .clk (inclock_wire),
+ .ena(inclocken_wire),
+ .sreset(sclr),
+ .regouthi(ddr_input[1]),
+ .regoutlo(ddr_input[0]),
+ .clkout(fr_clock)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .areset(1'b0),
+ .dfflo(),
+ .devpor(1'b1),
+ .devclrn(1'b1),
+ .halfrateresyncclk(1'b0)
+ `endif
+ );
+ end
+ else
+ begin:in_path_enhanced_ddr
+ fiftyfivenm_ddio_in
+ #(
+ .async_mode(ASYNC_MODE),
+ .sync_mode(SYNC_MODE),
+ .power_up(DDIO_REG_POWER_UP),
+ .invert_input_clock(INVERT_INPUT_CLOCK)
+ ) fr_in_ddio (
+ .datain(buf_in),
+ .clk (inclock_wire),
+ .ena(inclocken_wire),
+ .regouthi(ddr_input[1]),
+ .regoutlo(ddr_input[0]),
+ .clkout(fr_clock)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .sreset(1'b0),
+ .areset(1'b0),
+ .dfflo(),
+ .devpor(1'b1),
+ .devclrn(1'b1),
+ .halfrateresyncclk(1'b0)
+ `endif
+ );
+ end
+ end
+ end
+ else if (ENABLE_PHASE_DETECTOR_FOR_CK == "true")
+ begin
+ assign mimic_clock = buf_in;
+ end
+ else
+ begin: in_path_ddr
+ wire input_cell_l_q;
+ wire input_aset;
+
+ assign input_aset = ( ASYNC_MODE == "clear") ? !aset : aset;
+
+ fiftyfivenm_ff input_cell_l (
+ .clk(inclock_wire),
+ .d(buf_in),
+ .clrn(input_aset),
+ .ena(inclocken_wire),
+ .q(input_cell_l_q)
+ );
+
+ fiftyfivenm_ff input_latch_l (
+ .clk(~inclock_wire),
+ .d(input_cell_l_q),
+ .clrn(input_aset),
+ .ena(inclocken_wire),
+ .q(ddr_input[0])
+ );
+
+ fiftyfivenm_ff input_cell_h (
+ .clk(~inclock_wire),
+ .d(buf_in),
+ .clrn(input_aset),
+ .ena(inclocken_wire),
+ .q(ddr_input[1])
+ );
+
+ end
+ end
+ else if (REGISTER_MODE == "single-register")
+ begin: in_path_sdr
+ reg reg_data_in /* synthesis altera_attribute="FAST_INPUT_REGISTER=on" */;
+ always @(posedge inclock_wire) begin
+ reg_data_in <= buf_in;
+ end
+ assign ddr_input[0] = reg_data_in;
+ end
+ else
+ begin: in_path_reg_none
+ assign ddr_input[0] = buf_in;
+ end
+
+ assign dout[DATA_SIZE - 1:0] = ddr_input[DATA_SIZE - 1:0];
+
+ end
+ endgenerate
+
+ generate
+ if (PIN_TYPE == "output" || PIN_TYPE == "bidir")
+ begin
+ if(BUFFER_TYPE == "pseudo_differential")
+ begin: pseudo_diff_output_buf
+
+ wire wire_pseudo_diff_o;
+ wire wire_pseudo_diff_o_bar;
+
+ fiftyfivenm_io_obuf
+ #(
+ .bus_hold(BUS_HOLD),
+ .open_drain_output(OPEN_DRAIN_OUTPUT)
+ ) obuf_a (
+ .i(wire_pseudo_diff_o),
+ .oe(~oe_out),
+ .o(pad),
+ .obar()
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .seriesterminationcontrol(16'b0),
+ .devoe(1'b1)
+ `endif
+ );
+
+ fiftyfivenm_io_obuf
+ #(
+ .bus_hold(BUS_HOLD),
+ .open_drain_output(OPEN_DRAIN_OUTPUT)
+ ) obuf_a_bar (
+ .i(wire_pseudo_diff_o_bar),
+ .oe(~oe_out),
+ .o(pad_b),
+ .obar()
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .seriesterminationcontrol(16'b0),
+ .devoe(1'b1)
+ `endif
+ );
+
+ fiftyfivenm_pseudo_diff_out pseudo_diff_a
+ (
+ .i(din_ddr),
+ .o(wire_pseudo_diff_o),
+ .obar(wire_pseudo_diff_o_bar)
+ );
+
+
+
+ end
+ else if (BUFFER_TYPE == "true_differential")
+ begin: true_diff_output_buf
+ fiftyfivenm_io_obuf
+ #(
+ .bus_hold(BUS_HOLD),
+ .open_drain_output(OPEN_DRAIN_OUTPUT)
+ ) obuf (
+ .i(din_ddr),
+ .oe(~oe_out),
+ .o(pad),
+ .obar(pad_b)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .seriesterminationcontrol(16'b0),
+ .devoe(1'b1)
+ `endif
+ );
+ end
+ else
+ begin: output_buf
+ fiftyfivenm_io_obuf
+ #(
+ .bus_hold(BUS_HOLD),
+ .open_drain_output(OPEN_DRAIN_OUTPUT)
+ ) obuf (
+ .i(din_ddr),
+ .oe(~oe_out),
+ .o(pad),
+ .obar()
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .seriesterminationcontrol(16'b0),
+ .devoe(1'b1)
+ `endif
+ );
+ end
+ end
+ endgenerate
+
+ assign nsleep_in = (ENABLE_NSLEEP_PORT == "true") ? nsleep : 1'b1;
+
+ generate
+ if (PIN_TYPE == "input" || PIN_TYPE == "bidir")
+ begin
+ if(BUFFER_TYPE == "true_differential" || BUFFER_TYPE == "pseudo_differential")
+ begin: diff_input_buf
+ if (ENABLE_NSLEEP_PORT == "true")
+ begin: diff_input_buf_with_nsleep
+ fiftyfivenm_io_ibuf
+ #(
+ .bus_hold(BUS_HOLD)
+ ) ibuf (
+ .i(pad),
+ .ibar(pad_b),
+ .o(buf_in),
+ .nsleep(nsleep_in)
+ );
+ end
+ else
+ begin: diff_input_buf_without_nsleep
+ fiftyfivenm_io_ibuf
+ #(
+ .bus_hold(BUS_HOLD)
+ ) ibuf (
+ .i(pad),
+ .ibar(pad_b),
+ .o(buf_in)
+ );
+ end
+ end
+ else
+ begin:input_buf
+ if (ENABLE_NSLEEP_PORT == "true")
+ begin: input_buf_with_nsleep
+ fiftyfivenm_io_ibuf
+ #(
+ .bus_hold(BUS_HOLD)
+ ) ibuf (
+ .i(pad),
+ .o(buf_in),
+ .nsleep(nsleep_in)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .ibar(1'b0)
+ `endif
+ );
+ end
+ else
+ begin: input_buf_without_nsleep
+ fiftyfivenm_io_ibuf
+ #(
+ .bus_hold(BUS_HOLD)
+ ) ibuf (
+ .i(pad),
+ .o(buf_in)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .ibar(1'b0)
+ `endif
+ );
+ end
+ end
+ end
+ endgenerate
+
+ generate
+ if (PIN_TYPE == "output")
+ begin
+ assign dout = {DATA_SIZE{1'b0}};
+ end
+
+ if (PIN_TYPE == "output" || REGISTER_MODE != "ddr" || USE_ENHANCED_DDR_HIO_REGISTER == "false")
+ begin
+ assign fr_clock = 1'b0;
+ end
+
+ if (PIN_TYPE == "input" || PIN_TYPE == "output" || REGISTER_MODE != "ddr" || ENABLE_PHASE_DETECTOR_FOR_CK == "false")
+ begin
+ assign mimic_clock = 1'b0;
+ end
+ endgenerate
+
+endmodule
+
+module altera_gpio_lite(
+ inclock,
+ outclock,
+ inclocken,
+ outclocken,
+ oe,
+ din,
+ dout,
+ pad_io,
+ pad_io_b,
+ pad_in,
+ pad_in_b,
+ pad_out,
+ pad_out_b,
+ aset,
+ aclr,
+ phy_mem_clock,
+ sclr,
+ hr_clock,
+ fr_clock,
+ invert_hr_clock,
+ mimic_clock,
+ nsleep
+);
+
+ parameter PIN_TYPE = "output";
+ parameter BUFFER_TYPE = "single-ended";
+ parameter REGISTER_MODE = "bypass";
+ parameter SIZE = 4;
+ parameter ASYNC_MODE = "none";
+ parameter SYNC_MODE = "none";
+ parameter BUS_HOLD = "false";
+ parameter SET_REGISTER_OUTPUTS_HIGH = "false";
+ parameter INVERT_OUTPUT = "false";
+ parameter INVERT_INPUT_CLOCK = "false";
+ parameter INVERT_OUTPUT_CLOCK = "false";
+ parameter INVERT_OE_INCLOCK = "false";
+ parameter USE_ONE_REG_TO_DRIVE_OE = "false";
+ parameter USE_DDIO_REG_TO_DRIVE_OE = "false";
+ parameter OPEN_DRAIN_OUTPUT = "false";
+ parameter USE_ADVANCED_DDR_FEATURES = "false";
+ parameter USE_ADVANCED_DDR_FEATURES_FOR_INPUT_ONLY = "false";
+ parameter INVERT_CLKDIV_INPUT_CLOCK = "false";
+ parameter ENABLE_HR_CLOCK = "false";
+ parameter ENABLE_OE_HALF_CYCLE_DELAY = "true";
+ parameter ENABLE_OE_PORT = "false";
+ parameter ENABLE_CLOCK_ENA_PORT = "false";
+ parameter ENABLE_PHASE_INVERT_CTRL_PORT = "false";
+ parameter ENABLE_PHASE_DETECTOR_FOR_CK = "false";
+ parameter ENABLE_NSLEEP_PORT = "false";
+
+ localparam USE_ENHANCED_DDR_HIO_REGISTER = USE_ADVANCED_DDR_FEATURES;
+ localparam BYPASS_THREE_QUARTER_REGISTER = (USE_ADVANCED_DDR_FEATURES == "true") ? "false" : "true";
+ localparam DATA_SIZE = (REGISTER_MODE == "ddr") ? 2 : 1;
+
+ input inclock;
+ input outclock;
+ input inclocken;
+ input outclocken;
+ input [SIZE - 1:0] oe;
+ input [SIZE - 1:0] nsleep;
+ input [SIZE * DATA_SIZE - 1:0] din;
+ output [SIZE * DATA_SIZE - 1:0] dout;
+ inout [SIZE - 1:0] pad_io;
+ inout [SIZE - 1:0] pad_io_b;
+ input [SIZE - 1:0] pad_in;
+ input [SIZE - 1:0] pad_in_b;
+ output [SIZE - 1:0] pad_out;
+ output [SIZE - 1:0] pad_out_b;
+ input aset;
+ input aclr;
+ input sclr;
+ input phy_mem_clock;
+ input invert_hr_clock;
+ output [SIZE - 1:0] fr_clock;
+ output wire hr_clock;
+ output [SIZE - 1:0] mimic_clock;
+
+ wire [SIZE * DATA_SIZE - 1:0] din_reordered;
+ wire [SIZE * DATA_SIZE - 1:0] dout_reordered;
+ wire aclr_aset_wire;
+ wire sclr_wire;
+ wire [SIZE - 1:0] pad_io;
+ wire [SIZE - 1:0] pad_io_b;
+
+
+ assign aclr_aset_wire = (ASYNC_MODE == "clear") ? aclr : (ASYNC_MODE == "preset") ? aset : 1'b1;
+ assign sclr_wire = (SYNC_MODE == "clear") ? sclr : 1'b0;
+
+ generate
+ if (PIN_TYPE == "input")
+ begin
+ assign pad_io = pad_in;
+ assign pad_io_b = pad_in_b;
+ assign pad_out = {SIZE{1'b0}};
+ assign pad_out_b = {SIZE{1'b0}};
+ end
+ else if (PIN_TYPE == "output")
+ begin
+ assign pad_out = pad_io;
+ assign pad_out_b = pad_io_b;
+ end
+ else begin
+ assign pad_out = {SIZE{1'b0}};
+ assign pad_out_b = {SIZE{1'b0}};
+ end
+ endgenerate
+
+ genvar j, k;
+ generate
+ begin : reorder
+ for(j = 0; j < SIZE ; j = j + 1) begin : j_loop
+ for(k = 0; k < DATA_SIZE; k = k + 1) begin : k_d_loop
+ assign din_reordered[j * DATA_SIZE + k] = din[j + k * SIZE];
+ assign dout[j + k * SIZE] = dout_reordered[j * DATA_SIZE + k];
+ end
+ end
+ end
+ endgenerate
+
+ genvar i;
+ generate
+ begin : gpio_one_bit
+ for(i = 0 ; i < SIZE ; i = i + 1) begin : i_loop
+ wire oe_wire;
+ wire nsleep_wire;
+
+
+ assign oe_wire = (PIN_TYPE == "output" && ENABLE_OE_PORT == "false") ? 1'b1 :
+ (PIN_TYPE == "input") ? 1'b0 : oe[i];
+
+
+ assign nsleep_wire = (PIN_TYPE == "input" && ENABLE_NSLEEP_PORT == "false") ? 1'b1 :
+ (PIN_TYPE == "output") ? 1'b0 : nsleep[i];
+
+ altgpio_one_bit #(
+ .PIN_TYPE(PIN_TYPE),
+ .BUFFER_TYPE(BUFFER_TYPE),
+ .REGISTER_MODE(REGISTER_MODE),
+ .ASYNC_MODE(ASYNC_MODE),
+ .SYNC_MODE(SYNC_MODE),
+ .BUS_HOLD(BUS_HOLD),
+ .SET_REGISTER_OUTPUTS_HIGH(SET_REGISTER_OUTPUTS_HIGH),
+ .USE_ENHANCED_DDR_HIO_REGISTER(USE_ENHANCED_DDR_HIO_REGISTER),
+ .USE_ADVANCED_DDR_FEATURES_FOR_INPUT_ONLY(USE_ADVANCED_DDR_FEATURES_FOR_INPUT_ONLY),
+ .BYPASS_THREE_QUARTER_REGISTER(BYPASS_THREE_QUARTER_REGISTER),
+ .INVERT_OUTPUT(INVERT_OUTPUT),
+ .INVERT_INPUT_CLOCK(INVERT_INPUT_CLOCK),
+ .INVERT_OUTPUT_CLOCK(INVERT_OUTPUT_CLOCK),
+ .INVERT_OE_INCLOCK(INVERT_OE_INCLOCK),
+ .USE_ONE_REG_TO_DRIVE_OE(USE_ONE_REG_TO_DRIVE_OE),
+ .USE_DDIO_REG_TO_DRIVE_OE(USE_DDIO_REG_TO_DRIVE_OE),
+ .OPEN_DRAIN_OUTPUT(OPEN_DRAIN_OUTPUT),
+ .ENABLE_OE_HALF_CYCLE_DELAY(ENABLE_OE_HALF_CYCLE_DELAY),
+ .ENABLE_CLOCK_ENA_PORT(ENABLE_CLOCK_ENA_PORT),
+ .ENABLE_HR_CLOCK(ENABLE_HR_CLOCK),
+ .ENABLE_PHASE_DETECTOR_FOR_CK(ENABLE_PHASE_DETECTOR_FOR_CK),
+ .ENABLE_NSLEEP_PORT(ENABLE_NSLEEP_PORT)
+ ) altgpio_bit_i (
+ .inclock(inclock),
+ .outclock(outclock),
+ .phy_mem_clock(phy_mem_clock),
+ .inclocken(inclocken),
+ .outclocken(outclocken),
+ .oe(oe_wire),
+ .din(din_reordered[(i + 1) * DATA_SIZE - 1 : i * DATA_SIZE]),
+ .dout(dout_reordered[(i + 1) * DATA_SIZE - 1 : i * DATA_SIZE]),
+ .pad(pad_io[i]),
+ .pad_b(pad_io_b[i]),
+ .aset(aclr_aset_wire),
+ .sclr(sclr_wire),
+ .fr_clock(fr_clock[i]),
+ .hr_clock(hr_clock),
+ .mimic_clock(mimic_clock[i]),
+ .nsleep(nsleep_wire)
+ );
+ end
+ end
+ endgenerate
+
+ generate
+ if ((PIN_TYPE == "input" || PIN_TYPE == "bidir") && (ENABLE_HR_CLOCK == "true"))
+ begin
+ if (ENABLE_PHASE_INVERT_CTRL_PORT == "true")
+ begin
+ if (SYNC_MODE == "clear")
+ begin : clock_divider_sync_mode_invert_hr_clock
+ fiftyfivenm_io_clock_divider
+ #(
+ .invert_input_clock_phase(INVERT_CLKDIV_INPUT_CLOCK),
+ .use_phasectrlin(ENABLE_PHASE_INVERT_CTRL_PORT),
+ .sync_mode(SYNC_MODE)
+ ) io_clkdiv (
+ .clk(inclock),
+ .phaseinvertctrl(invert_hr_clock),
+ .sreset(sclr_wire),
+ .clkout(hr_clock)
+ );
+ end
+ else
+ begin : clock_divider_invert_hr_clock
+ fiftyfivenm_io_clock_divider
+ #(
+ .invert_input_clock_phase(INVERT_CLKDIV_INPUT_CLOCK),
+ .use_phasectrlin(ENABLE_PHASE_INVERT_CTRL_PORT),
+ .sync_mode(SYNC_MODE)
+ ) io_clkdiv (
+ .clk(inclock),
+ .phaseinvertctrl(invert_hr_clock),
+ .clkout(hr_clock)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .sreset(1'b0)
+ `endif
+ );
+ end
+ end
+ else
+ begin
+ if (SYNC_MODE == "clear")
+ begin : clock_divider_sync_mode
+ fiftyfivenm_io_clock_divider
+ #(
+ .invert_input_clock_phase(INVERT_CLKDIV_INPUT_CLOCK),
+ .use_phasectrlin(ENABLE_PHASE_INVERT_CTRL_PORT),
+ .sync_mode(SYNC_MODE)
+ ) io_clkdiv (
+ .clk(inclock),
+ .sreset(sclr_wire),
+ .clkout(hr_clock)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .phaseinvertctrl(1'b0)
+ `endif
+ );
+ end
+ else
+ begin : clock_divider
+ fiftyfivenm_io_clock_divider
+ #(
+ .invert_input_clock_phase(INVERT_CLKDIV_INPUT_CLOCK),
+ .use_phasectrlin(ENABLE_PHASE_INVERT_CTRL_PORT),
+ .sync_mode(SYNC_MODE)
+ ) io_clkdiv (
+ .clk(inclock),
+ .clkout(hr_clock)
+ `ifndef ALTERA_RESERVED_QIS
+ ,
+ .sreset(1'b0),
+ .phaseinvertctrl(1'b0)
+ `endif
+ );
+ end
+ end
+ end
+ else begin
+ assign hr_clock = 1'b0;
+ end
+ endgenerate
+
+endmodule
diff --git a/fpga/usrp3/top/x400/cpld/ip/pll/pll.ppf b/fpga/usrp3/top/x400/cpld/ip/pll/pll.ppf
new file mode 100644
index 000000000..a48517653
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/ip/pll/pll.ppf
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE pinplan>
+<pinplan intended_family="MAX 10" variation_name="pll" megafunction_name="ALTPLL" specifies="all_ports">
+<global>
+<pin name="inclk0" direction="input" scope="external" source="clock" />
+<pin name="c0" direction="output" scope="external" source="clock" />
+<pin name="c1" direction="output" scope="external" source="clock" />
+<pin name="c2" direction="output" scope="external" source="clock" />
+<pin name="locked" direction="output" scope="external" />
+
+</global>
+</pinplan>
diff --git a/fpga/usrp3/top/x400/cpld/ip/pll/pll.qip b/fpga/usrp3/top/x400/cpld/ip/pll/pll.qip
new file mode 100644
index 000000000..6bafc09f8
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/ip/pll/pll.qip
@@ -0,0 +1,5 @@
+set_global_assignment -name IP_TOOL_NAME "ALTPLL"
+set_global_assignment -name IP_TOOL_VERSION "20.1"
+set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{MAX 10}"
+set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "pll.v"]
+set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll.ppf"]
diff --git a/fpga/usrp3/top/x400/cpld/ip/pll/pll.v b/fpga/usrp3/top/x400/cpld/ip/pll/pll.v
new file mode 100644
index 000000000..36b96bda9
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/ip/pll/pll.v
@@ -0,0 +1,368 @@
+// megafunction wizard: %ALTPLL%
+// GENERATION: STANDARD
+// VERSION: WM1.0
+// MODULE: altpll
+
+// ============================================================
+// File Name: pll.v
+// Megafunction Name(s):
+// altpll
+//
+// Simulation Library Files(s):
+// altera_mf
+// ============================================================
+// ************************************************************
+// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
+//
+// 20.1.0 Build 711 06/05/2020 SJ Standard Edition
+// ************************************************************
+
+
+//Copyright (C) 2020 Intel Corporation. All rights reserved.
+//Your use of Intel Corporation's design tools, logic functions
+//and other software and tools, and any partner logic
+//functions, and any output files from any of the foregoing
+//(including device programming or simulation files), and any
+//associated documentation or information are expressly subject
+//to the terms and conditions of the Intel Program License
+//Subscription Agreement, the Intel Quartus Prime License Agreement,
+//the Intel FPGA IP License Agreement, or other applicable license
+//agreement, including, without limitation, that your use is for
+//the sole purpose of programming logic devices manufactured by
+//Intel and sold by Intel or its authorized distributors. Please
+//refer to the applicable agreement for further details, at
+//https://fpgasoftware.intel.com/eula.
+
+
+// synopsys translate_off
+`timescale 1 ps / 1 ps
+// synopsys translate_on
+module pll (
+ inclk0,
+ c0,
+ c1,
+ c2,
+ locked);
+
+ input inclk0;
+ output c0;
+ output c1;
+ output c2;
+ output locked;
+
+ wire [0:0] sub_wire2 = 1'h0;
+ wire [4:0] sub_wire3;
+ wire sub_wire7;
+ wire sub_wire0 = inclk0;
+ wire [1:0] sub_wire1 = {sub_wire2, sub_wire0};
+ wire [2:2] sub_wire6 = sub_wire3[2:2];
+ wire [1:1] sub_wire5 = sub_wire3[1:1];
+ wire [0:0] sub_wire4 = sub_wire3[0:0];
+ wire c0 = sub_wire4;
+ wire c1 = sub_wire5;
+ wire c2 = sub_wire6;
+ wire locked = sub_wire7;
+
+ altpll altpll_component (
+ .inclk (sub_wire1),
+ .clk (sub_wire3),
+ .locked (sub_wire7),
+ .activeclock (),
+ .areset (1'b0),
+ .clkbad (),
+ .clkena ({6{1'b1}}),
+ .clkloss (),
+ .clkswitch (1'b0),
+ .configupdate (1'b0),
+ .enable0 (),
+ .enable1 (),
+ .extclk (),
+ .extclkena ({4{1'b1}}),
+ .fbin (1'b1),
+ .fbmimicbidir (),
+ .fbout (),
+ .fref (),
+ .icdrclk (),
+ .pfdena (1'b1),
+ .phasecounterselect ({4{1'b1}}),
+ .phasedone (),
+ .phasestep (1'b1),
+ .phaseupdown (1'b1),
+ .pllena (1'b1),
+ .scanaclr (1'b0),
+ .scanclk (1'b0),
+ .scanclkena (1'b1),
+ .scandata (1'b0),
+ .scandataout (),
+ .scandone (),
+ .scanread (1'b0),
+ .scanwrite (1'b0),
+ .sclkout0 (),
+ .sclkout1 (),
+ .vcooverrange (),
+ .vcounderrange ());
+ defparam
+ altpll_component.bandwidth_type = "AUTO",
+ altpll_component.clk0_divide_by = 2,
+ altpll_component.clk0_duty_cycle = 50,
+ altpll_component.clk0_multiply_by = 1,
+ altpll_component.clk0_phase_shift = "0",
+ altpll_component.clk1_divide_by = 2,
+ altpll_component.clk1_duty_cycle = 50,
+ altpll_component.clk1_multiply_by = 5,
+ altpll_component.clk1_phase_shift = "0",
+ altpll_component.clk2_divide_by = 5,
+ altpll_component.clk2_duty_cycle = 50,
+ altpll_component.clk2_multiply_by = 2,
+ altpll_component.clk2_phase_shift = "0",
+ altpll_component.compensate_clock = "CLK0",
+ altpll_component.inclk0_input_frequency = 10000,
+ altpll_component.intended_device_family = "MAX 10",
+ altpll_component.lpm_hint = "CBX_MODULE_PREFIX=pll",
+ altpll_component.lpm_type = "altpll",
+ altpll_component.operation_mode = "NORMAL",
+ altpll_component.pll_type = "AUTO",
+ altpll_component.port_activeclock = "PORT_UNUSED",
+ altpll_component.port_areset = "PORT_UNUSED",
+ altpll_component.port_clkbad0 = "PORT_UNUSED",
+ altpll_component.port_clkbad1 = "PORT_UNUSED",
+ altpll_component.port_clkloss = "PORT_UNUSED",
+ altpll_component.port_clkswitch = "PORT_UNUSED",
+ altpll_component.port_configupdate = "PORT_UNUSED",
+ altpll_component.port_fbin = "PORT_UNUSED",
+ altpll_component.port_inclk0 = "PORT_USED",
+ altpll_component.port_inclk1 = "PORT_UNUSED",
+ altpll_component.port_locked = "PORT_USED",
+ altpll_component.port_pfdena = "PORT_UNUSED",
+ altpll_component.port_phasecounterselect = "PORT_UNUSED",
+ altpll_component.port_phasedone = "PORT_UNUSED",
+ altpll_component.port_phasestep = "PORT_UNUSED",
+ altpll_component.port_phaseupdown = "PORT_UNUSED",
+ altpll_component.port_pllena = "PORT_UNUSED",
+ altpll_component.port_scanaclr = "PORT_UNUSED",
+ altpll_component.port_scanclk = "PORT_UNUSED",
+ altpll_component.port_scanclkena = "PORT_UNUSED",
+ altpll_component.port_scandata = "PORT_UNUSED",
+ altpll_component.port_scandataout = "PORT_UNUSED",
+ altpll_component.port_scandone = "PORT_UNUSED",
+ altpll_component.port_scanread = "PORT_UNUSED",
+ altpll_component.port_scanwrite = "PORT_UNUSED",
+ altpll_component.port_clk0 = "PORT_USED",
+ altpll_component.port_clk1 = "PORT_USED",
+ altpll_component.port_clk2 = "PORT_USED",
+ altpll_component.port_clk3 = "PORT_UNUSED",
+ altpll_component.port_clk4 = "PORT_UNUSED",
+ altpll_component.port_clk5 = "PORT_UNUSED",
+ altpll_component.port_clkena0 = "PORT_UNUSED",
+ altpll_component.port_clkena1 = "PORT_UNUSED",
+ altpll_component.port_clkena2 = "PORT_UNUSED",
+ altpll_component.port_clkena3 = "PORT_UNUSED",
+ altpll_component.port_clkena4 = "PORT_UNUSED",
+ altpll_component.port_clkena5 = "PORT_UNUSED",
+ altpll_component.port_extclk0 = "PORT_UNUSED",
+ altpll_component.port_extclk1 = "PORT_UNUSED",
+ altpll_component.port_extclk2 = "PORT_UNUSED",
+ altpll_component.port_extclk3 = "PORT_UNUSED",
+ altpll_component.self_reset_on_loss_lock = "OFF",
+ altpll_component.width_clock = 5;
+
+
+endmodule
+
+// ============================================================
+// CNX file retrieval info
+// ============================================================
+// Retrieval info: PRIVATE: ACTIVECLK_CHECK STRING "0"
+// Retrieval info: PRIVATE: BANDWIDTH STRING "1.000"
+// Retrieval info: PRIVATE: BANDWIDTH_FEATURE_ENABLED STRING "1"
+// Retrieval info: PRIVATE: BANDWIDTH_FREQ_UNIT STRING "MHz"
+// Retrieval info: PRIVATE: BANDWIDTH_PRESET STRING "Low"
+// Retrieval info: PRIVATE: BANDWIDTH_USE_AUTO STRING "1"
+// Retrieval info: PRIVATE: BANDWIDTH_USE_PRESET STRING "0"
+// Retrieval info: PRIVATE: CLKBAD_SWITCHOVER_CHECK STRING "0"
+// Retrieval info: PRIVATE: CLKLOSS_CHECK STRING "0"
+// Retrieval info: PRIVATE: CLKSWITCH_CHECK STRING "0"
+// Retrieval info: PRIVATE: CNX_NO_COMPENSATE_RADIO STRING "0"
+// Retrieval info: PRIVATE: CREATE_CLKBAD_CHECK STRING "0"
+// Retrieval info: PRIVATE: CREATE_INCLK1_CHECK STRING "0"
+// Retrieval info: PRIVATE: CUR_DEDICATED_CLK STRING "c0"
+// Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "c0"
+// Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "7"
+// Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "2"
+// Retrieval info: PRIVATE: DIV_FACTOR1 NUMERIC "2"
+// Retrieval info: PRIVATE: DIV_FACTOR2 NUMERIC "1"
+// Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000"
+// Retrieval info: PRIVATE: DUTY_CYCLE1 STRING "50.00000000"
+// Retrieval info: PRIVATE: DUTY_CYCLE2 STRING "50.00000000"
+// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "50.000000"
+// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE1 STRING "250.000000"
+// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE2 STRING "40.000000"
+// Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0"
+// Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0"
+// Retrieval info: PRIVATE: GLOCKED_COUNTER_EDIT_CHANGED STRING "1"
+// Retrieval info: PRIVATE: GLOCKED_FEATURE_ENABLED STRING "0"
+// Retrieval info: PRIVATE: GLOCKED_MODE_CHECK STRING "0"
+// Retrieval info: PRIVATE: GLOCK_COUNTER_EDIT NUMERIC "1048575"
+// Retrieval info: PRIVATE: HAS_MANUAL_SWITCHOVER STRING "1"
+// Retrieval info: PRIVATE: INCLK0_FREQ_EDIT STRING "100.000"
+// Retrieval info: PRIVATE: INCLK0_FREQ_UNIT_COMBO STRING "MHz"
+// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT STRING "100.000"
+// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT_CHANGED STRING "1"
+// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_CHANGED STRING "1"
+// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_COMBO STRING "MHz"
+// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "MAX 10"
+// Retrieval info: PRIVATE: INT_FEEDBACK__MODE_RADIO STRING "1"
+// Retrieval info: PRIVATE: LOCKED_OUTPUT_CHECK STRING "1"
+// Retrieval info: PRIVATE: LONG_SCAN_RADIO STRING "1"
+// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE STRING "Not Available"
+// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE_DIRTY NUMERIC "0"
+// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT0 STRING "deg"
+// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT1 STRING "deg"
+// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT2 STRING "ps"
+// Retrieval info: PRIVATE: MIG_DEVICE_SPEED_GRADE STRING "Any"
+// Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0"
+// Retrieval info: PRIVATE: MIRROR_CLK1 STRING "0"
+// Retrieval info: PRIVATE: MIRROR_CLK2 STRING "0"
+// Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "1"
+// Retrieval info: PRIVATE: MULT_FACTOR1 NUMERIC "5"
+// Retrieval info: PRIVATE: MULT_FACTOR2 NUMERIC "1"
+// Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1"
+// Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "100.00000000"
+// Retrieval info: PRIVATE: OUTPUT_FREQ1 STRING "100.00000000"
+// Retrieval info: PRIVATE: OUTPUT_FREQ2 STRING "40.00000000"
+// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "0"
+// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE1 STRING "0"
+// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE2 STRING "1"
+// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz"
+// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT1 STRING "MHz"
+// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT2 STRING "MHz"
+// Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "1"
+// Retrieval info: PRIVATE: PHASE_RECONFIG_INPUTS_CHECK STRING "0"
+// Retrieval info: PRIVATE: PHASE_SHIFT0 STRING "0.00000000"
+// Retrieval info: PRIVATE: PHASE_SHIFT1 STRING "0.00000000"
+// Retrieval info: PRIVATE: PHASE_SHIFT2 STRING "0.00000000"
+// Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0"
+// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg"
+// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT1 STRING "deg"
+// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT2 STRING "ps"
+// Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0"
+// Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "0"
+// Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1"
+// Retrieval info: PRIVATE: PLL_ENHPLL_CHECK NUMERIC "0"
+// Retrieval info: PRIVATE: PLL_FASTPLL_CHECK NUMERIC "0"
+// Retrieval info: PRIVATE: PLL_FBMIMIC_CHECK STRING "0"
+// Retrieval info: PRIVATE: PLL_LVDS_PLL_CHECK NUMERIC "0"
+// Retrieval info: PRIVATE: PLL_PFDENA_CHECK STRING "0"
+// Retrieval info: PRIVATE: PLL_TARGET_HARCOPY_CHECK NUMERIC "0"
+// Retrieval info: PRIVATE: PRIMARY_CLK_COMBO STRING "inclk0"
+// Retrieval info: PRIVATE: RECONFIG_FILE STRING "pll.mif"
+// Retrieval info: PRIVATE: SACN_INPUTS_CHECK STRING "0"
+// Retrieval info: PRIVATE: SCAN_FEATURE_ENABLED STRING "1"
+// Retrieval info: PRIVATE: SELF_RESET_LOCK_LOSS STRING "0"
+// Retrieval info: PRIVATE: SHORT_SCAN_RADIO STRING "0"
+// Retrieval info: PRIVATE: SPREAD_FEATURE_ENABLED STRING "0"
+// Retrieval info: PRIVATE: SPREAD_FREQ STRING "50.000"
+// Retrieval info: PRIVATE: SPREAD_FREQ_UNIT STRING "KHz"
+// Retrieval info: PRIVATE: SPREAD_PERCENT STRING "0.500"
+// Retrieval info: PRIVATE: SPREAD_USE STRING "0"
+// Retrieval info: PRIVATE: SRC_SYNCH_COMP_RADIO STRING "0"
+// Retrieval info: PRIVATE: STICKY_CLK0 STRING "1"
+// Retrieval info: PRIVATE: STICKY_CLK1 STRING "1"
+// Retrieval info: PRIVATE: STICKY_CLK2 STRING "1"
+// Retrieval info: PRIVATE: STICKY_CLK3 STRING "0"
+// Retrieval info: PRIVATE: STICKY_CLK4 STRING "0"
+// Retrieval info: PRIVATE: SWITCHOVER_COUNT_EDIT NUMERIC "1"
+// Retrieval info: PRIVATE: SWITCHOVER_FEATURE_ENABLED STRING "1"
+// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0"
+// Retrieval info: PRIVATE: USE_CLK0 STRING "1"
+// Retrieval info: PRIVATE: USE_CLK1 STRING "1"
+// Retrieval info: PRIVATE: USE_CLK2 STRING "1"
+// Retrieval info: PRIVATE: USE_CLKENA0 STRING "0"
+// Retrieval info: PRIVATE: USE_CLKENA1 STRING "0"
+// Retrieval info: PRIVATE: USE_CLKENA2 STRING "0"
+// Retrieval info: PRIVATE: USE_MIL_SPEED_GRADE NUMERIC "0"
+// Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0"
+// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
+// Retrieval info: CONSTANT: BANDWIDTH_TYPE STRING "AUTO"
+// Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "2"
+// Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50"
+// Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "1"
+// Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0"
+// Retrieval info: CONSTANT: CLK1_DIVIDE_BY NUMERIC "2"
+// Retrieval info: CONSTANT: CLK1_DUTY_CYCLE NUMERIC "50"
+// Retrieval info: CONSTANT: CLK1_MULTIPLY_BY NUMERIC "5"
+// Retrieval info: CONSTANT: CLK1_PHASE_SHIFT STRING "0"
+// Retrieval info: CONSTANT: CLK2_DIVIDE_BY NUMERIC "5"
+// Retrieval info: CONSTANT: CLK2_DUTY_CYCLE NUMERIC "50"
+// Retrieval info: CONSTANT: CLK2_MULTIPLY_BY NUMERIC "2"
+// Retrieval info: CONSTANT: CLK2_PHASE_SHIFT STRING "0"
+// Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK0"
+// Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "10000"
+// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "MAX 10"
+// Retrieval info: CONSTANT: LPM_TYPE STRING "altpll"
+// Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL"
+// Retrieval info: CONSTANT: PLL_TYPE STRING "AUTO"
+// Retrieval info: CONSTANT: PORT_ACTIVECLOCK STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_ARESET STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_CLKBAD0 STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_CLKBAD1 STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_CLKLOSS STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_CLKSWITCH STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_CONFIGUPDATE STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_FBIN STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_INCLK0 STRING "PORT_USED"
+// Retrieval info: CONSTANT: PORT_INCLK1 STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_LOCKED STRING "PORT_USED"
+// Retrieval info: CONSTANT: PORT_PFDENA STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_PHASECOUNTERSELECT STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_PHASEDONE STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_PHASESTEP STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_PHASEUPDOWN STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_PLLENA STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_SCANACLR STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_SCANCLK STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_SCANCLKENA STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_SCANDATA STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_SCANDATAOUT STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_SCANDONE STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_SCANREAD STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_SCANWRITE STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_clk0 STRING "PORT_USED"
+// Retrieval info: CONSTANT: PORT_clk1 STRING "PORT_USED"
+// Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_USED"
+// Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_clk5 STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_clkena0 STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_clkena1 STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_clkena2 STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_clkena3 STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_clkena4 STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_clkena5 STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_extclk0 STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_extclk1 STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_extclk2 STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: PORT_extclk3 STRING "PORT_UNUSED"
+// Retrieval info: CONSTANT: SELF_RESET_ON_LOSS_LOCK STRING "OFF"
+// Retrieval info: CONSTANT: WIDTH_CLOCK NUMERIC "5"
+// Retrieval info: USED_PORT: @clk 0 0 5 0 OUTPUT_CLK_EXT VCC "@clk[4..0]"
+// Retrieval info: USED_PORT: c0 0 0 0 0 OUTPUT_CLK_EXT VCC "c0"
+// Retrieval info: USED_PORT: c1 0 0 0 0 OUTPUT_CLK_EXT VCC "c1"
+// Retrieval info: USED_PORT: c2 0 0 0 0 OUTPUT_CLK_EXT VCC "c2"
+// Retrieval info: USED_PORT: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0"
+// Retrieval info: USED_PORT: locked 0 0 0 0 OUTPUT GND "locked"
+// Retrieval info: CONNECT: @inclk 0 0 1 1 GND 0 0 0 0
+// Retrieval info: CONNECT: @inclk 0 0 1 0 inclk0 0 0 0 0
+// Retrieval info: CONNECT: c0 0 0 0 0 @clk 0 0 1 0
+// Retrieval info: CONNECT: c1 0 0 0 0 @clk 0 0 1 1
+// Retrieval info: CONNECT: c2 0 0 0 0 @clk 0 0 1 2
+// Retrieval info: CONNECT: locked 0 0 0 0 @locked 0 0 0 0
+// Retrieval info: GEN_FILE: TYPE_NORMAL pll.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL pll.ppf TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL pll.inc FALSE
+// Retrieval info: GEN_FILE: TYPE_NORMAL pll.cmp FALSE
+// Retrieval info: GEN_FILE: TYPE_NORMAL pll.bsf FALSE
+// Retrieval info: GEN_FILE: TYPE_NORMAL pll_inst.v FALSE
+// Retrieval info: GEN_FILE: TYPE_NORMAL pll_bb.v FALSE
+// Retrieval info: LIB_FILE: altera_mf
+// Retrieval info: CBX_MODULE_PREFIX: ON
diff --git a/fpga/usrp3/top/x400/cpld/mb_cpld.qpf b/fpga/usrp3/top/x400/cpld/mb_cpld.qpf
new file mode 100644
index 000000000..0e34c0ac5
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/mb_cpld.qpf
@@ -0,0 +1,30 @@
+# -------------------------------------------------------------------------- #
+#
+# Copyright (C) 2018 Intel Corporation. All rights reserved.
+# Your use of Intel Corporation's design tools, logic functions
+# and other software and tools, and its AMPP partner logic
+# functions, and any output files from any of the foregoing
+# (including device programming or simulation files), and any
+# associated documentation or information are expressly subject
+# to the terms and conditions of the Intel Program License
+# Subscription Agreement, the Intel Quartus Prime License Agreement,
+# the Intel FPGA IP License Agreement, or other applicable license
+# agreement, including, without limitation, that your use is for
+# the sole purpose of programming logic devices manufactured by
+# Intel and sold by Intel or its authorized distributors. Please
+# refer to the applicable agreement for further details.
+#
+# -------------------------------------------------------------------------- #
+#
+# Quartus Prime
+# Version 18.1.0 Build 625 09/12/2018 SJ Lite Edition
+# Date created = 13:40:17 August 15, 2019
+#
+# -------------------------------------------------------------------------- #
+
+QUARTUS_VERSION = "18.1"
+DATE = "13:40:17 August 15, 2019"
+
+# Revisions
+
+PROJECT_REVISION = "mb_cpld"
diff --git a/fpga/usrp3/top/x400/cpld/mb_cpld.qsf b/fpga/usrp3/top/x400/cpld/mb_cpld.qsf
new file mode 100644
index 000000000..47ab072ce
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/mb_cpld.qsf
@@ -0,0 +1,431 @@
+# -------------------------------------------------------------------------- #
+#
+# Copyright (C) 2018 Intel Corporation. All rights reserved.
+# Your use of Intel Corporation's design tools, logic functions
+# and other software and tools, and its AMPP partner logic
+# functions, and any output files from any of the foregoing
+# (including device programming or simulation files), and any
+# associated documentation or information are expressly subject
+# to the terms and conditions of the Intel Program License
+# Subscription Agreement, the Intel Quartus Prime License Agreement,
+# the Intel FPGA IP License Agreement, or other applicable license
+# agreement, including, without limitation, that your use is for
+# the sole purpose of programming logic devices manufactured by
+# Intel and sold by Intel or its authorized distributors. Please
+# refer to the applicable agreement for further details.
+#
+# -------------------------------------------------------------------------- #
+#
+# Quartus Prime
+# Version 18.1.0 Build 625 09/12/2018 SJ Lite Edition
+# Date created = 12:02:17 February 20, 2019
+#
+# -------------------------------------------------------------------------- #
+#
+# Notes:
+#
+# 1) The default values for assignments are stored in the file:
+# TopCpld_assignment_defaults.qdf
+# If this file doesn't exist, see file:
+# assignment_defaults.qdf
+#
+# 2) Altera recommends that you do not modify this file. This
+# file is updated automatically by the Quartus Prime software
+# and any changes you make may be lost or overwritten.
+#
+# -------------------------------------------------------------------------- #
+
+
+
+#--------------------------------------------------------------------------
+# Project properties/settings
+#--------------------------------------------------------------------------
+set_global_assignment -name FAMILY "MAX 10"
+set_global_assignment -name DEVICE 10M04SAU169I7G
+set_global_assignment -name TOP_LEVEL_ENTITY mb_cpld
+set_global_assignment -name ORIGINAL_QUARTUS_VERSION 18.1.0
+set_global_assignment -name PROJECT_CREATION_TIME_DATE "12:02:17 FEBRUARY 20, 2019"
+set_global_assignment -name LAST_QUARTUS_VERSION "20.1.0 Standard Edition"
+set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
+set_global_assignment -name MIN_CORE_JUNCTION_TEMP "-40"
+set_global_assignment -name MAX_CORE_JUNCTION_TEMP 100
+set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 256
+set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "23 MM HEAT SINK WITH 200 LFPM AIRFLOW"
+set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)"
+set_global_assignment -name FLOW_ENABLE_POWER_ANALYZER ON
+set_global_assignment -name POWER_DEFAULT_INPUT_IO_TOGGLE_RATE "12.5 %"
+set_global_assignment -name ENABLE_OCT_DONE OFF
+set_global_assignment -name ENABLE_CONFIGURATION_PINS OFF
+set_global_assignment -name ENABLE_JTAG_PIN_SHARING ON
+set_global_assignment -name GENERATE_SVF_FILE OFF
+set_global_assignment -name USE_CONFIGURATION_DEVICE OFF
+set_global_assignment -name CRC_ERROR_OPEN_DRAIN OFF
+set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -rise
+set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -fall
+set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -rise
+set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -fall
+
+set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
+set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
+set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
+
+set_global_assignment -name NUM_PARALLEL_PROCESSORS 2
+
+#--------------------------------------------------------------------------
+# Pin constraints
+#--------------------------------------------------------------------------
+
+# Clocking.
+#------------------------------------------
+
+# CPLD's PLL reference clock.
+set_location_assignment PIN_H6 -to PLL_REF_CLK
+set_location_assignment PIN_G5 -to "PLL_REF_CLK(n)"
+set_instance_assignment -name IO_STANDARD "DIFFERENTIAL LVPECL" -to PLL_REF_CLK
+
+# Reliable clock (100 MHz).
+set_location_assignment PIN_H4 -to CLK_100
+set_location_assignment PIN_H5 -to "CLK_100(n)"
+set_instance_assignment -name IO_STANDARD "DIFFERENTIAL LVPECL" -to CLK_100
+
+# Power supply clocks.
+set_location_assignment PIN_H8 -to PWR_SUPPLY_CLK_CORE
+set_location_assignment PIN_H9 -to PWR_SUPPLY_CLK_DDR4_S
+set_location_assignment PIN_G12 -to PWR_SUPPLY_CLK_DDR4_N
+set_location_assignment PIN_L13 -to PWR_SUPPLY_CLK_0P9V
+set_location_assignment PIN_G13 -to PWR_SUPPLY_CLK_1P8V
+set_location_assignment PIN_K10 -to PWR_SUPPLY_CLK_2P5V
+set_location_assignment PIN_J10 -to PWR_SUPPLY_CLK_3P3V
+set_location_assignment PIN_L12 -to PWR_SUPPLY_CLK_3P6V
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to PWR_SUPPLY_CLK_0P9V
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to PWR_SUPPLY_CLK_1P8V
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to PWR_SUPPLY_CLK_2P5V
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to PWR_SUPPLY_CLK_3P3V
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to PWR_SUPPLY_CLK_3P6V
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to PWR_SUPPLY_CLK_CORE
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to PWR_SUPPLY_CLK_DDR4_N
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to PWR_SUPPLY_CLK_DDR4_S
+
+# Oscillator power supply
+set_location_assignment PIN_L2 -to PWR_EN_5V_OSC_100
+set_location_assignment PIN_N2 -to PWR_EN_5V_OSC_122_88
+set_instance_assignment -name IO_STANDARD "2.5 V" -to PWR_EN_5V_OSC_100
+set_instance_assignment -name IO_STANDARD "2.5 V" -to PWR_EN_5V_OSC_122_88
+
+
+# Interfaces from/to RFSoC.
+#------------------------------------------
+
+# PL SPI slave interface.
+set_location_assignment PIN_G2 -to PL_CPLD_SCLK
+set_location_assignment PIN_F5 -to PL_CPLD_MOSI
+set_location_assignment PIN_F6 -to PL_CPLD_MISO
+set_location_assignment PIN_G1 -to PL_CPLD_CS_N[0]
+set_location_assignment PIN_G4 -to PL_CPLD_CS_N[1]
+set_instance_assignment -name IO_STANDARD "1.8 V" -to PL_CPLD_SCLK
+set_instance_assignment -name IO_STANDARD "1.8 V" -to PL_CPLD_MOSI
+set_instance_assignment -name IO_STANDARD "1.8 V" -to PL_CPLD_MISO
+set_instance_assignment -name IO_STANDARD "1.8 V" -to PL_CPLD_CS_N[0]
+set_instance_assignment -name IO_STANDARD "1.8 V" -to PL_CPLD_CS_N[1]
+
+# IRQ to PL.
+set_location_assignment PIN_F4 -to PL_CPLD_IRQ
+set_instance_assignment -name IO_STANDARD "1.8 V" -to PL_CPLD_IRQ
+
+# PS SPI slave interface.
+set_location_assignment PIN_E3 -to PS_CPLD_SCLK
+set_location_assignment PIN_E1 -to PS_CPLD_MOSI
+set_location_assignment PIN_F1 -to PS_CPLD_MISO
+set_location_assignment PIN_B1 -to PS_CPLD_CS_N[0]
+set_location_assignment PIN_C1 -to PS_CPLD_CS_N[1]
+set_location_assignment PIN_E4 -to PS_CPLD_CS_N[2]
+set_location_assignment PIN_D1 -to PS_CPLD_CS_N[3]
+set_instance_assignment -name IO_STANDARD "1.8-V" -to PS_CPLD_SCLK
+set_instance_assignment -name IO_STANDARD "1.8-V" -to PS_CPLD_MOSI
+set_instance_assignment -name IO_STANDARD "1.8-V" -to PS_CPLD_MISO
+set_instance_assignment -name IO_STANDARD "1.8-V" -to PS_CPLD_CS_N[0]
+set_instance_assignment -name IO_STANDARD "1.8-V" -to PS_CPLD_CS_N[1]
+set_instance_assignment -name IO_STANDARD "1.8-V" -to PS_CPLD_CS_N[2]
+set_instance_assignment -name IO_STANDARD "1.8-V" -to PS_CPLD_CS_N[3]
+
+
+# PL Interfaces to/from motherboard.
+#------------------------------------------
+
+# White Rabbit DAC SPI master interface.
+set_location_assignment PIN_A12 -to CLK_DB_SCLK
+set_location_assignment PIN_B13 -to CLK_DB_MOSI
+set_location_assignment PIN_D12 -to CLK_DB_MISO
+set_location_assignment PIN_D9 -to CLK_DB_CS_N
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to CLK_DB_SCLK
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to CLK_DB_MOSI
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to CLK_DB_MISO
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to CLK_DB_CS_N
+
+# iPASS interfaces.
+set_location_assignment PIN_A6 -to IPASS_SCL[0]
+set_location_assignment PIN_H2 -to IPASS_SCL[1]
+set_location_assignment PIN_A7 -to IPASS_SDA[0]
+set_location_assignment PIN_H3 -to IPASS_SDA[1]
+set_instance_assignment -name IO_STANDARD "1.8 V" -to IPASS_SCL[0]
+set_instance_assignment -name IO_STANDARD "1.8 V" -to IPASS_SCL[1]
+set_instance_assignment -name IO_STANDARD "1.8 V" -to IPASS_SDA[0]
+set_instance_assignment -name IO_STANDARD "1.8 V" -to IPASS_SDA[1]
+
+set_location_assignment PIN_B11 -to IPASS_PRESENT_N[0]
+set_location_assignment PIN_F8 -to IPASS_PRESENT_N[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to IPASS_PRESENT_N[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to IPASS_PRESENT_N[1]
+
+# QSFP LEDs.
+set_location_assignment PIN_E12 -to QSFP0_LED_ACTIVE[0]
+set_location_assignment PIN_F12 -to QSFP0_LED_ACTIVE[1]
+set_location_assignment PIN_E9 -to QSFP0_LED_ACTIVE[2]
+set_location_assignment PIN_J1 -to QSFP0_LED_ACTIVE[3]
+set_location_assignment PIN_F10 -to QSFP0_LED_LINK[0]
+set_location_assignment PIN_F9 -to QSFP0_LED_LINK[1]
+set_location_assignment PIN_N11 -to QSFP0_LED_LINK[2]
+set_location_assignment PIN_D13 -to QSFP0_LED_LINK[3]
+set_location_assignment PIN_M1 -to QSFP1_LED_ACTIVE[0]
+set_location_assignment PIN_N3 -to QSFP1_LED_ACTIVE[1]
+set_location_assignment PIN_L3 -to QSFP1_LED_ACTIVE[2]
+set_location_assignment PIN_K2 -to QSFP1_LED_ACTIVE[3]
+set_location_assignment PIN_M2 -to QSFP1_LED_LINK[0]
+set_location_assignment PIN_M3 -to QSFP1_LED_LINK[1]
+set_location_assignment PIN_K1 -to QSFP1_LED_LINK[2]
+set_location_assignment PIN_L1 -to QSFP1_LED_LINK[3]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to QSFP0_LED_ACTIVE[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to QSFP0_LED_ACTIVE[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to QSFP0_LED_ACTIVE[2]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to QSFP0_LED_ACTIVE[3]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to QSFP0_LED_LINK[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to QSFP0_LED_LINK[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to QSFP0_LED_LINK[2]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to QSFP0_LED_LINK[3]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to QSFP1_LED_ACTIVE[0]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to QSFP1_LED_ACTIVE[1]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to QSFP1_LED_ACTIVE[2]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to QSFP1_LED_ACTIVE[3]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to QSFP1_LED_LINK[0]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to QSFP1_LED_LINK[1]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to QSFP1_LED_LINK[2]
+set_instance_assignment -name IO_STANDARD "2.5 V" -to QSFP1_LED_LINK[3]
+
+# DIO direction control.
+set_location_assignment PIN_N12 -to DIO_DIRECTION_A[0]
+set_location_assignment PIN_N10 -to DIO_DIRECTION_A[1]
+set_location_assignment PIN_N9 -to DIO_DIRECTION_A[2]
+set_location_assignment PIN_M4 -to DIO_DIRECTION_A[3]
+set_location_assignment PIN_M5 -to DIO_DIRECTION_A[4]
+set_location_assignment PIN_N4 -to DIO_DIRECTION_A[5]
+set_location_assignment PIN_N5 -to DIO_DIRECTION_A[6]
+set_location_assignment PIN_N7 -to DIO_DIRECTION_A[7]
+set_location_assignment PIN_N8 -to DIO_DIRECTION_A[8]
+set_location_assignment PIN_M8 -to DIO_DIRECTION_A[9]
+set_location_assignment PIN_M9 -to DIO_DIRECTION_A[10]
+set_location_assignment PIN_M13 -to DIO_DIRECTION_A[11]
+set_location_assignment PIN_L5 -to DIO_DIRECTION_B[0]
+set_location_assignment PIN_L4 -to DIO_DIRECTION_B[1]
+set_location_assignment PIN_K5 -to DIO_DIRECTION_B[2]
+set_location_assignment PIN_J5 -to DIO_DIRECTION_B[3]
+set_location_assignment PIN_N6 -to DIO_DIRECTION_B[4]
+set_location_assignment PIN_M7 -to DIO_DIRECTION_B[5]
+set_location_assignment PIN_J6 -to DIO_DIRECTION_B[6]
+set_location_assignment PIN_K6 -to DIO_DIRECTION_B[7]
+set_location_assignment PIN_J7 -to DIO_DIRECTION_B[8]
+set_location_assignment PIN_K7 -to DIO_DIRECTION_B[9]
+set_location_assignment PIN_M12 -to DIO_DIRECTION_B[10]
+set_location_assignment PIN_M11 -to DIO_DIRECTION_B[11]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[2]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[3]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[4]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[5]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[6]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[7]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[8]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[9]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[10]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_A[11]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[2]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[3]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[4]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[5]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[6]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[7]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[8]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[9]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[10]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DIO_DIRECTION_B[11]
+
+
+# PS Interfaces to/from motherboard.
+#------------------------------------------
+
+# LMK04832 SPI master interface.
+set_location_assignment PIN_J9 -to LMK32_SCLK
+set_location_assignment PIN_H13 -to LMK32_MOSI
+set_location_assignment PIN_L11 -to LMK32_MISO
+set_location_assignment PIN_J13 -to LMK32_CS_N
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to LMK32_SCLK
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to LMK32_MOSI
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to LMK32_MISO
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to LMK32_CS_N
+
+# TPM 2.0 SPI master interface.
+set_location_assignment PIN_D11 -to TPM_SCLK
+set_location_assignment PIN_E10 -to TPM_MOSI
+set_location_assignment PIN_C13 -to TPM_MISO
+set_location_assignment PIN_L10 -to TPM_CS_N
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to TPM_SCLK
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to TPM_MOSI
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to TPM_MISO
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to TPM_CS_N
+
+# Phase DAC SPI master interface.
+set_location_assignment PIN_K8 -to PHASE_DAC_SCLK
+set_location_assignment PIN_J8 -to PHASE_DAC_MOSI
+set_location_assignment PIN_M10 -to PHASE_DAC_CS_N
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to PHASE_DAC_SCLK
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to PHASE_DAC_MOSI
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to PHASE_DAC_CS_N
+
+# Daughterboards' JTAG master interfaces.
+set_location_assignment PIN_J12 -to DB_JTAG_TCK[0]
+set_location_assignment PIN_G9 -to DB_JTAG_TCK[1]
+set_location_assignment PIN_K12 -to DB_JTAG_TDI[0]
+set_location_assignment PIN_E13 -to DB_JTAG_TDI[1]
+set_location_assignment PIN_H10 -to DB_JTAG_TDO[0]
+set_location_assignment PIN_F13 -to DB_JTAG_TDO[1]
+set_location_assignment PIN_K11 -to DB_JTAG_TMS[0]
+set_location_assignment PIN_G10 -to DB_JTAG_TMS[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DB_JTAG_TCK[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DB_JTAG_TCK[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DB_JTAG_TDI[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DB_JTAG_TDI[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DB_JTAG_TDO[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DB_JTAG_TDO[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DB_JTAG_TMS[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to DB_JTAG_TMS[1]
+
+# Daughterboards' Calibration EEPROM SPI interfaces.
+set_location_assignment PIN_C9 -to DB_CALEEPROM_CS_N[0]
+set_location_assignment PIN_B9 -to DB_CALEEPROM_MISO[0]
+set_location_assignment PIN_B10 -to DB_CALEEPROM_MOSI[0]
+set_location_assignment PIN_A10 -to DB_CALEEPROM_SCLK[0]
+
+set_location_assignment PIN_B5 -to DB_CALEEPROM_MOSI[1]
+set_location_assignment PIN_B6 -to DB_CALEEPROM_SCLK[1]
+set_location_assignment PIN_B4 -to DB_CALEEPROM_MISO[1]
+set_location_assignment PIN_B3 -to DB_CALEEPROM_CS_N[1]
+
+set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CALEEPROM_CS_N[0]
+set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CALEEPROM_MISO[0]
+set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CALEEPROM_MOSI[0]
+set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CALEEPROM_SCLK[0]
+
+set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CALEEPROM_MOSI[1]
+set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CALEEPROM_SCLK[1]
+set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CALEEPROM_MISO[1]
+set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CALEEPROM_CS_N[1]
+
+# Daughterboards' Control interfaces.
+set_location_assignment PIN_C10 -to DB_CTRL_SCLK[0]
+set_location_assignment PIN_A9 -to DB_CTRL_MISO[0]
+set_location_assignment PIN_A8 -to DB_ARST[0]
+set_location_assignment PIN_A11 -to DB_CTRL_CS_N[0]
+set_location_assignment PIN_E8 -to DB_CTRL_MOSI[0]
+set_location_assignment PIN_D8 -to DB_REF_CLK[0]
+
+set_location_assignment PIN_A3 -to DB_REF_CLK[1]
+set_location_assignment PIN_A4 -to DB_CTRL_MISO[1]
+set_location_assignment PIN_D6 -to DB_CTRL_CS_N[1]
+set_location_assignment PIN_E6 -to DB_CTRL_SCLK[1]
+set_location_assignment PIN_A5 -to DB_CTRL_MOSI[1]
+set_location_assignment PIN_B2 -to DB_ARST[1]
+
+set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CTRL_SCLK[0]
+set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CTRL_MISO[0]
+set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_ARST[0]
+set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CTRL_CS_N[0]
+set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CTRL_MOSI[0]
+set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_REF_CLK[0]
+
+set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_REF_CLK[1]
+set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CTRL_MISO[1]
+set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CTRL_CS_N[1]
+set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CTRL_SCLK[1]
+set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_CTRL_MOSI[1]
+set_instance_assignment -name IO_STANDARD "1.8 V" -to DB_ARST[1]
+
+
+# Miscellaneous.
+#------------------------------------------
+
+# Power supply clocks switch.
+set_location_assignment PIN_J2 -to PS_CLK_ON_CPLD
+set_instance_assignment -name IO_STANDARD "2.5 V" -to PS_CLK_ON_CPLD
+
+# iPASS misc.
+set_location_assignment PIN_B12 -to IPASS_POWER_DISABLE
+set_location_assignment PIN_C11 -to IPASS_POWER_EN_FAULT[0]
+set_location_assignment PIN_C12 -to IPASS_POWER_EN_FAULT[1]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to IPASS_POWER_DISABLE
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to IPASS_POWER_EN_FAULT[0]
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to IPASS_POWER_EN_FAULT[1]
+
+# PCIe reset to FPGA.
+set_location_assignment PIN_A2 -to PCIE_RESET
+set_instance_assignment -name IO_STANDARD "1.8 V" -to PCIE_RESET
+
+# TPM reset.
+set_location_assignment PIN_K13 -to TPM_RESET_n
+set_instance_assignment -name IO_STANDARD "3.3-V LVCMOS" -to TPM_RESET_n
+
+# File list.
+set_global_assignment -name EXTERNAL_FLASH_FALLBACK_ADDRESS 00000000
+set_global_assignment -name INTERNAL_FLASH_UPDATE_MODE "SINGLE COMP IMAGE"
+set_global_assignment -name EN_USER_IO_WEAK_PULLUP OFF
+set_global_assignment -name EN_SPI_IO_WEAK_PULLUP OFF
+
+set_global_assignment -name VHDL_FILE ip/cmi/PcieCmiWrapper.vhd
+set_global_assignment -name VHDL_FILE ip/cmi/PcieCmi.vhd
+set_global_assignment -name QSYS_FILE ip/clkctrl/clkctrl.qsys
+set_global_assignment -name QSYS_FILE ip/flash/on_chip_flash.qsys
+set_global_assignment -name SDC_FILE db_spi_shared_constants.sdc
+set_global_assignment -name SDC_FILE mb_cpld.sdc
+set_global_assignment -name VERILOG_FILE reconfig_engine.v
+set_global_assignment -name VERILOG_FILE mb_cpld.v
+set_global_assignment -name VERILOG_FILE ctrlport_to_spi.v
+set_global_assignment -name VERILOG_FILE ctrlport_to_jtag.v
+set_global_assignment -name VERILOG_FILE pl_cpld_regs.v
+set_global_assignment -name VERILOG_FILE pwr_supply_clk_gen.v
+set_global_assignment -name VERILOG_FILE ps_cpld_regs.v
+set_global_assignment -name VERILOG_FILE reset_generator.v
+set_global_assignment -name VERILOG_FILE spi_slave_to_ctrlport_master.v
+set_global_assignment -name VERILOG_FILE spi_slave.v
+set_global_assignment -name QIP_FILE ip/pll/pll.qip
+set_global_assignment -name VERILOG_FILE ../../../lib/control/synchronizer_impl.v
+set_global_assignment -name VERILOG_FILE ../../../lib/control/synchronizer.v
+set_global_assignment -name VERILOG_FILE ../../../lib/rfnoc/utils/ctrlport_splitter.v
+set_global_assignment -name VERILOG_FILE ../../../lib/rfnoc/utils/ctrlport_terminator.v
+set_global_assignment -name VERILOG_FILE ../../../lib/wb_spi/rtl/verilog/spi_top.v
+set_global_assignment -name VERILOG_FILE ../../../lib/wb_spi/rtl/verilog/spi_shift.v
+set_global_assignment -name VERILOG_FILE ../../../lib/wb_spi/rtl/verilog/spi_defines.v
+set_global_assignment -name VERILOG_FILE ../../../lib/wb_spi/rtl/verilog/spi_clgen.v
+set_global_assignment -name VERILOG_FILE ../../../lib/control/pulse_synchronizer.v
+set_global_assignment -name VERILOG_FILE ../../../lib/control/handshake.v
+set_global_assignment -name VHDL_FILE ../../../lib/vivado_ipi/axi_bitq/bitq_fsm.vhd
+set_global_assignment -name VHDL_FILE ../../../lib/vivado_ipi/axi_bitq/axi_bitq.vhd
+set_global_assignment -name QIP_FILE ip/oddr/oddr.qip
+set_global_assignment -name SOURCE_FILE db/mb_cpld.cmp.rdb
+set_global_assignment -name PARTITION_NETLIST_TYPE POST_FIT -section_id "PcieCmi:PcieCmix"
+set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id "PcieCmi:PcieCmix"
+set_global_assignment -name PARTITION_COLOR 52377 -section_id "PcieCmi:PcieCmix"
+set_global_assignment -name PARTITION_IMPORT_FILE ip/cmi/PcieCmi.qxp -section_id "PcieCmi:PcieCmix"
+set_global_assignment -name PARTITION_LAST_IMPORTED_FILE ip/cmi/PcieCmi.qxp -section_id "PcieCmi:PcieCmix"
+set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
+set_instance_assignment -name PARTITION_HIERARCHY pciec_5b6b1 -to "PcieCmiWrapper:pcie_cmi_inst|PcieCmi:PcieCmix" -section_id "PcieCmi:PcieCmix" \ No newline at end of file
diff --git a/fpga/usrp3/top/x400/cpld/mb_cpld.sdc b/fpga/usrp3/top/x400/cpld/mb_cpld.sdc
new file mode 100644
index 000000000..af291a994
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/mb_cpld.sdc
@@ -0,0 +1,689 @@
+#
+# Copyright 2021 Ettus Research, a National Instruments Brand
+#
+# SPDX-License-Identifier: LGPL-3.0-or-later
+#
+# Description:
+#
+# Timing constraints for the X4xx's motherboard CPLD.
+#
+
+set_time_format -unit ns -decimal_places 3
+
+#####################################################################
+# General
+#####################################################################
+# For a couple of 3.3V interfaces the buffer SN74AVC4T774RSVR is used to
+# increase the drive strength. For reuse we define the timings constants here.
+# For direction A to B and B to A the maximum timing varies by 0.1 ns. Taking
+# the maximum of both.
+set buffer_prop_min 0.100
+set buffer_prop_max 2.400
+
+#####################################################################
+# Main Clocks
+#####################################################################
+## Input clocks.
+# Reliable clock: 100.0 MHz
+set CLK_100_period 10.000
+create_clock -name CLK_100 -period $CLK_100_period [get_ports CLK_100]
+
+# internal PLL derived clock
+derive_pll_clocks
+# provide name for derived clocks
+set CLK_250 [get_clocks {*clk[1]}]
+
+# PLL output pins of the generated 50 MHz clock for internal processing
+set clk50_period 20.000
+set pll_clk_out_pin [get_pins {pll_inst|altpll_component|auto_generated|pll1|clk[0]}]
+
+set clk250_period 4.000
+
+# PLL reference clock: 64 MHz (maximum)
+set prc_clock_period 15.625
+create_clock -name PLL_REF_CLK -period $prc_clock_period [get_ports PLL_REF_CLK]
+
+#####################################################################
+# Timing exceptions
+#####################################################################
+## SPI slaves
+# Delay path for all synchronizers is based on the period of the
+# faster clock domain (50 MHz derived by the PLL from 100 MHz reliable clock).
+set clk50_period [expr {$CLK_100_period * 2}]
+
+set_max_delay -to [get_registers *synchronizer_false_path\|value\[0\]\[*\]] \
+ $clk50_period
+
+# sclk data to CLK_100
+set_max_delay -from [get_registers *spi_slave_async\|received_word\[*\]] \
+ -to [get_registers *spi_slave_async\|data_out\[*\]] \
+ $clk50_period
+# PLL driven data to sclk
+set_max_delay -from [get_clocks {pll_inst*}] \
+ -to [get_registers *spi_slave_async\|transmit_bits\[*\]] \
+ $clk50_period
+
+#####################################################################
+# JTAG to daughterboards
+#####################################################################
+# Use the worst-case board propagation delays.
+# Assuming 170.0 ps/in and usage of X410 DB.
+# Longest trace | Trace length | Trace delay
+# TDI to DB 0 | 7.625 in | 1.296 ns
+# --------------------------------------------
+
+# JTAG parameters
+# see https://www.intel.com/content/www/us/en/programmable/documentation/mcn1397700832153.html#mcn1399899915639
+set db_jtag_board_delay 1.296
+set db_jtag_setup 3.000
+set db_jtag_hold 10.000
+set db_jtag_clk_to_out 20.000
+
+set db0_jtag_outputs [get_ports {DB_JTAG_TDI[0] DB_JTAG_TMS[0]}]
+set db0_jtag_inputs [get_ports {DB_JTAG_TDO[0]}]
+set db1_jtag_outputs [get_ports {DB_JTAG_TDI[1] DB_JTAG_TMS[1]}]
+set db1_jtag_inputs [get_ports {DB_JTAG_TDO[1]}]
+
+##### DB 0 #####
+# generated jtag clock is at least divided by 4
+# max JTAG clock rate = 20 MHz
+# source clock rate = 50 MHz
+# only even dividers -> minimum value = 4
+set db0_jtag_clk_register [get_registers {ctrlport_to_jtag:db0_jtag|bitq_fsm:jtag_master|bitq_state.HIGH}]
+create_generated_clock -source $pll_clk_out_pin \
+ -name db0_jtag_clk $db0_jtag_clk_register \
+ -divide_by 4
+
+# see White Rabbit DAC for futher explanation
+set_false_path -from $db0_jtag_clk_register -to $db0_jtag_clk_register
+
+create_generated_clock \
+ -source $db0_jtag_clk_register \
+ -name db0_jtag_out_clk [get_ports {DB_JTAG_TCK[0]}]
+
+set_output_delay -clock db0_jtag_out_clk \
+ -max [expr {$db_jtag_setup + $db_jtag_board_delay + $buffer_prop_max}] \
+ $db0_jtag_outputs
+set_output_delay -clock db0_jtag_out_clk \
+ -min [expr {-$db_jtag_hold - $db_jtag_board_delay - $buffer_prop_min}] \
+ $db0_jtag_outputs
+# data is driven on CPLD on falling edge, which is 2 clock cycles ahead
+# of the latch edge
+set_multicycle_path -setup -start -to $db0_jtag_outputs 2
+set_multicycle_path -hold -start -to $db0_jtag_outputs 3
+
+# maximum delay accounts for slow clock and data propagation as
+# well as clock to out time
+set_input_delay -clock_fall -clock db0_jtag_out_clk \
+ -max [expr {$db_jtag_clk_to_out + 2*$db_jtag_board_delay + 2*$buffer_prop_max}] \
+ $db0_jtag_inputs
+# worst-case everything changes immediatelly
+set_input_delay -clock_fall -clock db0_jtag_out_clk \
+ -min [expr {2*$buffer_prop_min}] \
+ $db0_jtag_inputs
+set_multicycle_path -setup -end -from $db0_jtag_inputs 2
+set_multicycle_path -hold -end -from $db0_jtag_inputs 3
+
+##### DB 1 #####
+# generated jtag clock is at least divided by 4
+set db1_jtag_clk_register [get_registers {ctrlport_to_jtag:db1_jtag|bitq_fsm:jtag_master|bitq_state.HIGH}]
+create_generated_clock -source $pll_clk_out_pin \
+ -name db1_jtag_clk $db1_jtag_clk_register \
+ -divide_by 4
+# see White Rabbit DAC for futher explanation
+set_false_path -from $db1_jtag_clk_register -to $db1_jtag_clk_register
+create_generated_clock \
+ -source $db1_jtag_clk_register \
+ -name db1_jtag_out_clk [get_ports {DB_JTAG_TCK[1]}]
+
+set_output_delay -clock db1_jtag_out_clk \
+ -max [expr {$db_jtag_setup + $db_jtag_board_delay + $buffer_prop_max}] \
+ $db1_jtag_outputs
+set_output_delay -clock db1_jtag_out_clk \
+ -min [expr {-$db_jtag_hold - $db_jtag_board_delay - $buffer_prop_min}] \
+ $db1_jtag_outputs
+set_multicycle_path -setup -start -to $db1_jtag_outputs 2
+set_multicycle_path -hold -start -to $db1_jtag_outputs 3
+
+# maximum delay accounts for slow clock and data propagation as
+# well as clock to out time
+set_input_delay -clock_fall -clock db1_jtag_out_clk \
+ -max [expr {$db_jtag_clk_to_out + 2*$db_jtag_board_delay + 2*$buffer_prop_max}] \
+ $db1_jtag_inputs
+# ideally everything changes immediatelly
+set_input_delay -clock_fall -clock db1_jtag_out_clk \
+ -min [expr {2*$buffer_prop_min}] \
+ $db1_jtag_inputs
+set_multicycle_path -setup -end -from $db1_jtag_inputs 2
+set_multicycle_path -hold -end -from $db1_jtag_inputs 3
+
+#####################################################################
+# FPGA <-> MB CPLD PL SPI interface
+#####################################################################
+# Create clock for the PL's SPI interface.
+# PRC at least divided by 2 by the SPI Master on FPGA
+set pl_sclk_period [expr {2 * $prc_clock_period}]
+create_clock -name pl_sclk -period $pl_sclk_period [get_registers mb_cpld_sclk]
+
+# The SPI PL master (on the FPGA) is designed as a system synchronous
+# interface using PLL_REF_CLK.
+# The FPGA output constraints are required to calculate the windows
+# at CPLD of valid data
+# They are derived iteratively from the FPGA design ensuring a large
+# valid data period.
+set pl_spi_fpga_min_out 0.000
+set pl_spi_fpga_max_out 11.000
+
+# The longest trace on the PL SPI interface is (sssuming 170.0 ps/in)
+# Longest trace | Trace length | Trace delay
+# CS_0 | 7.143 in | 1.215 ns
+set pl_spi_board_delay 1.215
+
+# This path also contains a level translator which has a typical
+# switching time of 2.7 ns. Let's add a margin of 1 ns as worst
+# case estimation
+set pl_level_trans_delay 3.700
+
+# CPLD and FPGA both use PLL reference clock from a common clock chip.
+# The traces from that clock chip to the ICs are not length matched
+# Assume a worst case clock difference of 0.5 ns at the IC inputs.
+# There is no direction defined. The clock can arrive faster or slower
+# on one IC.
+set pl_clock_diff 0.500
+
+set pl_slave_inputs [get_ports {PL_CPLD_SCLK PL_CPLD_MOSI PL_CPLD_CS_N[*]}]
+# calculate output delays back from capturing edge, add board delay, level translator and clock difference
+set_input_delay -clock PLL_REF_CLK \
+ -max [expr {$prc_clock_period - $pl_spi_fpga_max_out + $pl_spi_board_delay + $pl_level_trans_delay + $pl_clock_diff}] \
+ $pl_slave_inputs
+# Assuming data is going without any delay, clock is arriving early at CPLD.
+# Negate minimum output delay as it is defined from the change to the start clock edge.
+set_input_delay -clock PLL_REF_CLK \
+ -min [expr {- $pl_spi_fpga_min_out - $pl_clock_diff}] \
+ $pl_slave_inputs
+
+# ensure large data valid window for the FPGA
+# those values are used in the FPGA / DB CPLDs
+# to calculate the input delay
+# those values are maximum integer values to still meet timing
+set pl_spi_cpld_min_out -1.000
+set pl_spi_cpld_max_out 8.000
+
+set pl_slave_outputs [get_ports {PL_CPLD_MISO}]
+set_output_delay -clock PLL_REF_CLK -max $pl_spi_cpld_max_out $pl_slave_outputs
+set_output_delay -clock PLL_REF_CLK -min $pl_spi_cpld_min_out $pl_slave_outputs
+
+#####################################################################
+# DB clock and reset
+#####################################################################
+# Output clocks for the daughterboards (SPI control)
+create_generated_clock -source $pll_clk_out_pin \
+ -name db0_ref_clk [get_ports {DB_REF_CLK[0]}]
+create_generated_clock -source $pll_clk_out_pin \
+ -name db1_ref_clk [get_ports {DB_REF_CLK[1]}]
+
+# output reset within one clock period
+set_max_delay -to [get_ports {DB_ARST[0] DB_ARST[1]}] $CLK_100_period
+set_min_delay -to [get_ports {DB_ARST[0] DB_ARST[1]}] 0
+
+#####################################################################
+# DB SPI interfaces
+#####################################################################
+# --------- ----------------- -----------------
+# FPGA | CS/SCLK/ | MB CPLD | | DB |
+# |-- MOSI ->|--------> R1 ->|--------->| |
+# SPI | | | | SPI |
+# master |<- MISO --|<- R2 <--------|<---------| slave |
+# --------- ----------------- -----------------
+#
+# The output clocks are derived from the PLL reference clock (PRC). The SCLK
+# edges are aligned with the rising edge of PLL reference clock. There are two
+# registers R1 and R2 in the SPI path between FPGA and DB.
+# For the transmission of data from master to slave those registers are
+# transparent. The overall reception is just delayed by 1 PLL reference clock
+# cycle. In the other direction the MISO timing is different. The falling edge
+# of SCLK is used for changing the data signals. The propagation of this signal
+# to the DB is delayed by 1 PLL reference clock period because of register R1.
+# The MISO signal is captured on the rising edge of SCLK on the FPGA. Register
+# R2 in the MB CPLD changes the timing in a way that MISO has to be stable on
+# the rising edge of PLL reference clock before the SCLK rising edge.
+# Additionally a minimum of two PLL reference clock cycles are required for
+# processing in the SPI slave. The number of processing cycles is denoted by n.
+
+# Here is an example for n=2 and SPI bus with CPHA=0 and CPOL=0.
+# Data is driven on the falling edge and captured on the rising edge of the
+# clock signal. The falling edge of the SCLK@DB is delayed by a clock cycle
+# because of R1. The FPGA as SPI master is capturing the data on the rising edge
+# of SCLK. The register R2 on the MB CPLD is capturing the data one clock cycle
+# earlier. Therefore MISO has to be stable one clock cycle earlier then the
+# original SCLK at the MB CPLD input. The effective SCLK signal to use for the
+# timing constraints of the DB therefore has a low period which is reduced by 2
+# clock cycles (R1 + R2) of PLL reference clock. It still has the same period as
+# SCLK. In this example the low period would be 2 PRC cycles and the high period
+# would be 6 PRC cycles.
+# The following waveform illustrates the timing for n=2. Based on the defined
+# delays <XXXX> denotes the time when the signal is not stable.
+#
+# <--- R1 --->|<-------- n=2 -------->|<--- R2 --->
+# PRC ___/-----\_____/-----\_____/-----\_____/-----\_____/----
+# SCLK ---\_______________________________________________/----
+# SCLK @ DB (ideal) ---------------\________________________________________
+# SCLK @ DB (effective) ---------------\_______________________/----------------
+# MOSI output @ MB CPLD --------------<XXXX>------------------------------------
+# MISO input @ MB CPLD -------------------------<XXXX>-------------------------
+# DB propagation and processing <--------->
+# MOSI change @ FPGA ^
+# MOSI change @ MB CPLD ^
+# MISO capture @ MB CPLD ^
+# MISO capture @ FPGA ^
+#
+# Although the delays are defined based on PLL reference clock the SPI bus clock
+# must be divided by at least n+2, where n>1 to be functional. Increase n in
+# case the DB propagation and processing time does not fit into n PLL reference
+# clock cycles taking the delays from below into account (see waveform above).
+# Make sure you defined the SPI bus clock frequency for the slave to n*PLL clock
+# period (effective SPI clock). Set the required SPI DB clock divider on the
+# FPGA before starting data transfer.
+#
+# The constants for this interface are defined in db_spi_shared_constants.sdc
+
+#### DB 0 ####
+create_generated_clock -source [get_ports {PLL_REF_CLK}] \
+ -name db0_ctrl_clk_int [get_registers {DB_CTRL_SCLK[0]~reg0}]
+create_generated_clock -source [get_registers {DB_CTRL_SCLK[0]~reg0}] \
+ -name db0_ctrl_clk [get_ports {DB_CTRL_SCLK[0]}]
+
+set db0_ctrl_outputs [get_ports {DB_CTRL_MOSI[0] DB_CTRL_CS_N[0]}]
+set_output_delay -clock db0_ctrl_clk -max $db_cpld_spi_max_out $db0_ctrl_outputs
+set_output_delay -clock db0_ctrl_clk -min $db_cpld_spi_min_out $db0_ctrl_outputs
+
+set db0_ctrl_inputs [get_ports {DB_CTRL_MISO[0]}]
+set_input_delay -clock db0_ctrl_clk -max $db_cpld_spi_max_in $db0_ctrl_inputs
+set_input_delay -clock db0_ctrl_clk -min $db_cpld_spi_min_in $db0_ctrl_inputs
+
+#### DB 1 ####
+create_generated_clock -source [get_ports {PLL_REF_CLK}] \
+ -name db1_ctrl_clk_int [get_registers {DB_CTRL_SCLK[1]~reg0}]
+create_generated_clock -source [get_registers {DB_CTRL_SCLK[1]~reg0}] \
+ -name db1_ctrl_clk [get_ports DB_CTRL_SCLK[1]]
+
+set db1_ctrl_outputs [get_ports {DB_CTRL_MOSI[1] DB_CTRL_CS_N[1]}]
+set_output_delay -clock db1_ctrl_clk -max $db_cpld_spi_max_out $db1_ctrl_outputs
+set_output_delay -clock db1_ctrl_clk -min $db_cpld_spi_min_out $db1_ctrl_outputs
+
+set db1_ctrl_inputs [get_ports {DB_CTRL_MISO[1]}]
+set_input_delay -clock db1_ctrl_clk -max $db_cpld_spi_max_in $db1_ctrl_inputs
+set_input_delay -clock db1_ctrl_clk -min $db_cpld_spi_min_in $db1_ctrl_inputs
+
+#####################################################################
+# Power supply clocks, LEDs, DIO direction
+#####################################################################
+# Change all output signals in this section within one clock period of the
+# driving clocks.
+
+# Power supply clocks
+set power_supply_clocks_outputs [get_ports {PWR_SUPPLY_CLK_*}]
+set_min_delay -to $power_supply_clocks_outputs 0
+set_max_delay -to $power_supply_clocks_outputs $CLK_100_period
+
+# LED signals
+set led_outputs [get_ports {QSFP0_LED_ACTIVE[*] QSFP0_LED_LINK[*] \
+ QSFP1_LED_ACTIVE[*] QSFP1_LED_LINK[*]}]
+set_min_delay -to $led_outputs 0
+set_max_delay -to $led_outputs $prc_clock_period
+
+# DIO direction
+set dio_outputs [get_ports {DIO_DIRECTION_A[*] DIO_DIRECTION_B[*]}]
+set_min_delay -to $dio_outputs 0
+set_max_delay -to $dio_outputs $clk50_period
+
+# Power control
+set pwr_ctrl_outputs [get_ports {IPASS_POWER_DISABLE PWR_EN_5V_OSC_100 PWR_EN_5V_OSC_122_88}]
+set_min_delay -to $pwr_ctrl_outputs 0
+set_max_delay -to $pwr_ctrl_outputs $clk50_period
+
+# Power fault inputs
+# Virtual clocks for constraining inputs. Using an odd clock period to
+# make sure any uncovered paths will result in timing errors due to short setup
+# or hold path.
+set power_fault_inputs [get_ports {IPASS_POWER_EN_FAULT[*]}]
+create_clock -name virtual_async_in_clk -period 4.567
+set_input_delay -clock virtual_async_in_clk 0 $power_fault_inputs
+
+#####################################################################
+# FPGA <-> MB CPLD PS SPI interface
+#####################################################################
+# Assume the PS SPI clock is maximum 5 MHz.
+# It is driven from another source and provided with the data.
+set ps_sclk_period 200.000
+create_clock -name ps_sclk -period $ps_sclk_period [get_ports PS_CPLD_SCLK]
+
+# The SPI PS master (on the FPGA) is wired through the MIO (Multiplexed I/O)
+# pins, meaning that the timing characteristics of the interface come from
+# the controller itself (i.e. no timed routing through PL).
+# Based on the SPI master controller specification (DS925: Table 48),
+# one may define the min/max input/output delay constraints.
+set ps_spi_tco_min -2.000
+set ps_spi_tco_max 5.000
+set ps_spi_miso_setup -2.000
+set ps_spi_miso_hold [expr {0.3 * $ps_sclk_period}]
+
+# Use the worst-case board propagation delays.
+# Assuming 170.0 ps/in.
+# Longest trace | Trace length | Trace delay
+# CS0_n | 4.735 in | 0.805 ns
+# --------------------------------------------
+set ps_spi_board_delay 0.805
+
+set ps_slave_inputs [get_ports {PS_CPLD_MOSI PS_CPLD_CS_N[*]}]
+# clock is immediately available, data is taking maximum time
+# SPI data in CPOL=CPHA=1 is driven on the falling sclk edge
+set ps_sclk_max_in_delay [expr {$ps_spi_tco_max + $ps_spi_board_delay}]
+set_input_delay -clock ps_sclk -clock_fall \
+ -max $ps_sclk_max_in_delay \
+ $ps_slave_inputs
+# fast data and clock delayed (reducing data delay)
+set_input_delay -clock ps_sclk -clock_fall \
+ -min [expr {$ps_spi_tco_min - $ps_spi_board_delay}] \
+ $ps_slave_inputs
+
+set ps_slave_outputs [get_ports {PS_CPLD_MISO}]
+# use only half the frequency because falling edge is driving data
+set_output_delay -clock ps_sclk \
+ -max [expr {$ps_spi_miso_setup + 2*$ps_spi_board_delay}] \
+ $ps_slave_outputs
+# use hold requirement only as clock and data propagation further
+# delay the signal
+set_output_delay -clock ps_sclk \
+ -min [expr {-$ps_spi_miso_hold}] \
+ $ps_slave_outputs
+
+# Chip select signals are captured for binary decoding in 250 MHz clock domain.
+# To be able to specify a maximum delay for the data path only a second set of
+# input delays is added to the root clock of the 250 MHz domain.
+set_input_delay -add_delay -clock CLK_100 0 [get_ports {PS_CPLD_CS_N[*]}]
+# Declare paths between the 2 clock domains as false paths
+set_false_path -from [get_clocks {CLK_100}] -to [get_ports {PS_CPLD_MISO}]
+set_false_path -from [get_clocks {ps_sclk}] -to [get_registers {synchronizer:ps_spi_input_sync_inst*}]
+# Specify maximum data path delay
+set_max_delay -from [get_ports {PS_CPLD_CS_N[*]}] -to $CLK_250 $clk250_period
+
+#####################################################################
+# MB CPLD PS SPI passthrough
+#####################################################################
+###### Binary CS decoding ######
+# The CS outputs for the external SPI slaves are driven from a 250 MHz clock to
+# ensure glitch free switching after binary encoding. Additionally those signals
+# have to meet the setup and hold requirements of the SPI slaves operating at
+# ps_sclk (5 MHz). CS lines typically are asserted half a clock period of sclk
+# before any active edge of sclk. The constraints below are using multi-cycle
+# paths to provide the placer with information about the clock multiplier from
+# ps_sclk to 250 MHz. Furthermore they incorporate the time required for
+# decoding by lowering the clock multiplier as shown in the waveform below
+# (multiplier is not shown correctly).
+#
+# ps_sclk -\__________________________________________________/--------
+# 250 MHz _/-\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_/-\-
+# CS @ CPLD input X>--------------- stable ------------------------------------
+# CS @ CPLD output ---------<XXXXXXX>-------------- stable ---------------------
+# |<----->| min decoding delay
+# |<----->| change window
+# --------------->| SPI slave hold requirement
+# SPI slave setup requirement |<-------------------------------->|
+#
+# Get port to apply the multi-cycle constraint.
+set binary_cs_ports [get_ports {LMK32_CS_N TPM_CS_N PHASE_DAC_CS_N DB_CALEEPROM_CS_N[*] CLK_DB_CS_N}]
+# Determine number of full 250 MHz periods within half a period of ps_sclk.
+set ps_spi_clock_divider [expr {int($ps_sclk_period/$clk250_period/2)}]
+# Setup multi-cycle accounts for
+# - one clock cycle data path delay from port to first register stage
+# - one clock cycle to resolve meta-stability
+# - up to 3 register stages internally (port to ps_cpld_cs_n_shift3)
+# - one output register stage (registers on each $binary_cs_ports)
+# Static timing analysis will take the data path from register to output port
+# into account.
+# The number of 250 MHz periods is reduced by a total of 7 clock cycles (listed
+# above) to match the SPI slave setup requirement time shown in the waveform
+# above. The slave's setup time in ps_sclk domain is specified below for each
+# individual slave.
+set ps_spi_setup_multicycle [expr {$ps_spi_clock_divider - 7}]
+set_multicycle_path -setup -start -to $binary_cs_ports $ps_spi_setup_multicycle
+# Hold multicycle accounts for
+# - min 2 synchronization register stages internally (ps_cpld_cs_n_shift2)
+# (= min one clock cycle delay as data could arrive just before setup
+# requirement of first register stages assuming no data delay)
+# - one output register stage
+# Static timing analysis will take the data path from register to output port
+# into account.
+# As the clock edge for hold analysis is shifted with the setup edge the number
+# of multi cycles has to be increased by this amount of cycles to get back to
+# the falling edge of ps_sclk. Furthermore CS lines are released one half
+# ps_sclk period after the last data transfer. So hold delay is increased by an
+# additional half clock cycle.
+set ps_spi_hold_multicycle [expr {$ps_spi_clock_divider + $ps_spi_setup_multicycle - 2}]
+set_multicycle_path -hold -start -to $binary_cs_ports $ps_spi_hold_multicycle
+
+###### local SPI slave ######
+# The chip select path for the MB CPLD itself is driven in the 250 MHz clock
+# domain and captured by registers operating at ps_sclk. Therefore setting the
+# path as false path preventing the placer from adding additional routing delay
+# to ensure hold timing. The setup path is limited to a maximum extend of one
+# clock period. As this path crosses clock domains clock propagation is included
+# in this path during static timing analysis. The TCL analysis in
+# scripts/ps_cs_analysis.tcl ensures a maximum value for data excluding the
+# clocking network.
+set_false_path -from [get_registers {ps_spi_cs_n_decoded[0]}] -hold
+set_max_delay -from [get_registers {ps_spi_cs_n_decoded[0]}] $clk250_period
+
+###### LMK04832 ######
+create_generated_clock -source [get_ports PS_CPLD_SCLK] \
+ -name lmk_spi_sclk [get_ports LMK32_SCLK]
+
+# Use the worst-case board propagation delays.
+# Assuming 170.0 ps/in.
+# Longest trace | Trace length | Trace delay
+# LMK32_SCLK | 8.259 in | 1.404 ns
+# --------------------------------------------
+set lmk_board_delay 1.404
+
+# setup and hold dominated by CS <-> SCK relationship
+set lmk_setup 20.000
+set lmk_hold 20.000
+set lmk_tco_max 60.000
+
+set lmk_outputs [get_ports {LMK32_MOSI LMK32_CS_N}]
+set_output_delay -clock lmk_spi_sclk \
+ -max [expr {$lmk_setup + $lmk_board_delay + $buffer_prop_max}] \
+ $lmk_outputs
+set_output_delay -clock lmk_spi_sclk \
+ -min [expr {-$lmk_hold - $lmk_board_delay - $buffer_prop_min}] \
+ $lmk_outputs
+
+set lmk_inputs [get_ports {LMK32_MISO}]
+set_input_delay -clock lmk_spi_sclk -clock_fall \
+ -max [expr {$lmk_tco_max + 2*$lmk_board_delay + 2*$buffer_prop_max}] \
+ $lmk_inputs
+set_input_delay -clock lmk_spi_sclk -clock_fall \
+ -min [expr {2*$buffer_prop_min}] \
+ $lmk_inputs
+
+###### Phase DAC ######
+create_generated_clock -source [get_ports PS_CPLD_SCLK] \
+ -name phase_dac_spi_sclk [get_ports PHASE_DAC_SCLK]
+
+# Use the worst-case board propagation delays.
+# Assuming 170.0 ps/in.
+# Longest trace | Trace length | Trace delay
+# SpiDCs3v3_n | 8.322 in | 1.415 ns
+# --------------------------------------------
+set phase_dac_board_delay 1.415
+
+#setup dominated by SYNC signal
+set phase_dac_setup 13.000
+set phase_dac_hold 5.000
+
+# device captures data on falling clock edge (CPOL = 1)
+# constraining it as it would be like all the other SPI modules
+# PS SPI master is responsible for changing SPI mode when talking
+# to this device
+set phase_dac_outputs [get_ports {PHASE_DAC_MOSI PHASE_DAC_CS_N}]
+set_output_delay -clock phase_dac_spi_sclk -clock_fall \
+ -max [expr {$phase_dac_setup + $phase_dac_board_delay}] \
+ $phase_dac_outputs
+set_output_delay -clock phase_dac_spi_sclk -clock_fall \
+ -min [expr {-$phase_dac_hold - $phase_dac_board_delay}] \
+ $phase_dac_outputs
+
+###### TPM ######
+create_generated_clock -source [get_ports PS_CPLD_SCLK] \
+ -name tpm_spi_sclk [get_ports TPM_SCLK]
+
+# Use the worst-case board propagation delays.
+# Assuming 170.0 ps/in.
+# Longest trace | Trace length | Trace delay
+# TPM_CS_n | 1.128 in | 0.196 ns
+# --------------------------------------------
+set tpm_board_delay 0.196
+
+#tco dominated by NSS signal
+set tpm_setup 5.000
+set tpm_hold 5.000
+set tpm_tco_max 25.000
+
+set tpm_outputs [get_ports {TPM_MOSI TPM_CS_N}]
+set_output_delay -clock tpm_spi_sclk \
+ -max [expr {$tpm_setup + $tpm_board_delay}] \
+ $tpm_outputs
+set_output_delay -clock tpm_spi_sclk \
+ -min [expr {-$tpm_hold - $tpm_board_delay}] \
+ $tpm_outputs
+
+set tpm_inputs [get_ports {TPM_MISO}]
+set_input_delay -clock tpm_spi_sclk -clock_fall \
+ -max [expr {$tpm_tco_max + 2*$tpm_board_delay}] \
+ $tpm_inputs
+set_input_delay -clock tpm_spi_sclk -clock_fall \
+ -min 0 \
+ $tpm_inputs
+
+###### DB Calibration EEPROM ######
+# Use worst case board propagation delays to estimate input and output
+# timing. The longest path assuming 170 ps/in is:
+# db0_caleeprom_spi_cs_n | 4.387 in | 0.746 ns
+set eeprom_board_prop_delay 0.746
+# Within the path to the EEPROM on the DB there is a level-transistor.
+# The maximum propagation delays are 0.1..3.3 ns to the DB and 3.7 ns from the DB.
+set eeprom_lvl_trans_to_db_delay_min 0.1
+set eeprom_lvl_trans_to_db_delay_max 3.3
+set eeprom_lvl_trans_from_db_delay_max 3.7
+# Data in setup and hold times of the EEPROM are 5ns (based on the
+# CS_N setup and hold times).
+set db_eeprom_setup 5
+set db_eeprom_hold 5
+# Ouput valid from SCK is min 0 ns and max 8 ns.
+set db_eeprom_output_valid 8
+
+# max out path assuming clock delay is 0 and data delay is maximum value
+set eeprom_max_out [expr {$eeprom_board_prop_delay + $eeprom_lvl_trans_to_db_delay_max + $db_eeprom_setup}]
+# min out path assuming clock delay is maximal and data delay is 0
+set eeprom_min_out [expr {-($eeprom_board_prop_delay + $eeprom_lvl_trans_to_db_delay_min + $db_eeprom_hold)}]
+# board propagation to eeprom and back + lvl_translator back and forth + clock to data on eeprom
+set eeprom_max_in [expr {$eeprom_board_prop_delay*2 + $eeprom_lvl_trans_to_db_delay_max + $eeprom_lvl_trans_from_db_delay_max + $db_eeprom_output_valid}]
+# assuming no delay for everything
+set eeprom_min_in 0
+
+### DB 0
+create_generated_clock -source [get_ports PS_CPLD_SCLK] \
+ -name db0_eeprom_clk [get_ports {DB_CALEEPROM_SCLK[0]}]
+
+set db0_eeprom_outputs [get_ports {DB_CALEEPROM_MOSI[0] DB_CALEEPROM_CS_N[0]}]
+set_output_delay -clock db0_eeprom_clk -max $eeprom_max_out $db0_eeprom_outputs
+set_output_delay -clock db0_eeprom_clk -min $eeprom_min_out $db0_eeprom_outputs
+
+set db0_eeprom_inputs [get_ports {DB_CALEEPROM_MISO[0]}]
+# data is changed on the falling edge
+set_input_delay -clock db0_eeprom_clk -clock_fall -max $eeprom_max_in $db0_eeprom_inputs
+set_input_delay -clock db0_eeprom_clk -clock_fall -min $eeprom_min_in $db0_eeprom_inputs
+
+### DB 1
+create_generated_clock -source [get_ports PS_CPLD_SCLK] \
+ -name db1_eeprom_clk [get_ports {DB_CALEEPROM_SCLK[1]}]
+
+set db1_eeprom_outputs [get_ports {DB_CALEEPROM_MOSI[1] DB_CALEEPROM_CS_N[1]}]
+set_output_delay -clock db1_eeprom_clk -max $eeprom_max_out $db1_eeprom_outputs
+set_output_delay -clock db1_eeprom_clk -min $eeprom_min_out $db1_eeprom_outputs
+
+set db1_eeprom_inputs [get_ports {DB_CALEEPROM_MISO[1]}]
+# data is changed on the falling edge
+set_input_delay -clock db1_eeprom_clk -clock_fall -max $eeprom_max_in $db1_eeprom_inputs
+set_input_delay -clock db1_eeprom_clk -clock_fall -min $eeprom_min_in $db1_eeprom_inputs
+
+#### Clocking AUX board SPI interface ####
+# Rev B clocking aux board uses a LMK05318 connected to this interface
+# Using its timing for this interface.
+create_generated_clock -source [get_ports PS_CPLD_SCLK] \
+ -name clk_db_clk_out [get_ports CLK_DB_SCLK]
+set clk_db_setup 10.000
+set clk_db_hold 10.000
+set clk_db_tco_max 20.000
+# Just a worst case assumption based on 2 times the MB trace length CLK_DB_MOSI.
+# The multiplier 2 accounts for any traces on the CLK AUX board.
+set clk_db_board_delay 4.000
+
+set clk_db_outputs [get_ports {CLK_DB_CS_N CLK_DB_MOSI}]
+# Output signals have to stable for max setup and propagation time. Clock delay
+# to device is expected to be 0 in this equation.
+set_output_delay -clock clk_db_clk_out \
+ -max [expr {$clk_db_setup + $clk_db_board_delay + $buffer_prop_max}] $clk_db_outputs
+# The min output delay is comprised of:
+# - device required hold time ($clk_db_hold)
+# - max clock propagation delay ($clk_db_board_delay)
+# - min data propagation time (0)
+# All terms have to be negated as min output delay is defined in opposite
+# direction (positive into the past).
+set_output_delay -clock clk_db_clk_out \
+ -min [expr {-$clk_db_hold - $clk_db_board_delay - $buffer_prop_min}] $clk_db_outputs
+
+set clk_db_inputs [get_ports {CLK_DB_MISO}]
+# Max delay calculated is based on
+# - max clock delay ($clk_db_board_delay)
+# - max clock to out LMK ($clk_db_tco_max)
+# - max data path delay ($clk_db_board_delay)
+set_input_delay -clock clk_db_clk_out -clock_fall \
+ -max [expr {$clk_db_tco_max + $clk_db_board_delay*2 + 2*$buffer_prop_max}] $clk_db_inputs
+# Min delay assumes clock propagates to device and data propagates to CPLD
+# without any delays.
+set_input_delay -clock clk_db_clk_out -clock_fall \
+ -min [expr {2*$buffer_prop_min}] $clk_db_inputs
+
+#####################################################################
+# PCIe signals
+#####################################################################
+# I²C bus is operated at 100kHz. Constraints would not improve timing
+# significantly (typically in the order of nanoseconds, which is negligible
+# given the SCL period of 10 us).
+# PCI-Express reset signal is not timing critical as it is received
+# asynchronously by the FPGA.
+set_false_path -to [get_ports {IPASS_SDA[0] IPASS_SCL[0] PCIE_RESET}]
+# I²C inputs are only consumed by synchronizers.
+# Add exceptions for all known consumers.
+set_false_path -to [get_registers {PcieCmiWrapper:pcie_cmi_inst|PcieCmi:PcieCmix|UsfCablePort:UsfCablePortx|CablePort:CablePortx|I2cTop:CableI2cx|I2cMonitor:I2cMonitorx|I2cFilter:I2cFilterx|I2cSigFilter:SclFilterx|fSig_ms}]
+set_false_path -to [get_registers {PcieCmiWrapper:pcie_cmi_inst|PcieCmi:PcieCmix|UsfCablePort:UsfCablePortx|CablePort:CablePortx|I2cTop:CableI2cx|I2cMonitor:I2cMonitorx|I2cFilter:I2cFilterx|I2cSigFilter:SdaFilterx|fSig_ms}]
+set_false_path -to [get_registers {PcieCmiWrapper:pcie_cmi_inst|PcieCmi:PcieCmix|UsfCablePort:UsfCablePortx|CablePort:CablePortx|StuckBusFixer:StuckBusFixerx|DoubleSyncSlAsyncIn:DoubleSclkx|DoubleSyncAsyncInBase:DoubleSyncAsyncInBasex|DFlopAsync:oSig_msx|lpm_ff:LPM_FFx|dffs[0]}]
+set_false_path -to [get_registers {PcieCmiWrapper:pcie_cmi_inst|PcieCmi:PcieCmix|UsfCablePort:UsfCablePortx|CablePort:CablePortx|StuckBusFixer:StuckBusFixerx|DoubleSyncSlAsyncIn:DoubleSdax|DoubleSyncAsyncInBase:DoubleSyncAsyncInBasex|DFlopAsync:oSig_msx|lpm_ff:LPM_FFx|dffs[0]}]
+
+#####################################################################
+# Known Issue of On-Chip Flash
+#####################################################################
+# see https://www.intel.com/content/www/us/en/programmable/support/support-resources/knowledge-base/tools/2016/warning--332060---node---alteraonchipflash-onchipflash-alteraonc.html
+create_generated_clock -name flash_se_neg_reg \
+ -source [get_pins { on_chip_flash:flash_inst|altera_onchip_flash:onchip_flash_0|altera_onchip_flash_avmm_data_controller:avmm_data_controller|flash_se_neg_reg|clk }] \
+ -divide_by 2 [get_pins { on_chip_flash:flash_inst|altera_onchip_flash:onchip_flash_0|altera_onchip_flash_avmm_data_controller:avmm_data_controller|flash_se_neg_reg|q } ]
+
+#####################################################################
+# Clock uncertainty
+#####################################################################
+# Assign some uncertainty to all clocks
+set clock_uncertainty 0.150
+set_clock_uncertainty -to [get_clocks *] $clock_uncertainty
+derive_clock_uncertainty
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
diff --git a/fpga/usrp3/top/x400/cpld/pl_cpld_regs.v b/fpga/usrp3/top/x400/cpld/pl_cpld_regs.v
new file mode 100644
index 000000000..19acdea67
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/pl_cpld_regs.v
@@ -0,0 +1,297 @@
+//
+// Copyright 2021 Ettus Research, A National Instruments Brand
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: pl_cpld_regs
+//
+// Description:
+//
+// Basic Registers to inform software about version and capabilities.
+//
+// Parameters:
+//
+// BASE_ADDRESS : Base address for CtrlPort registers
+//
+
+`default_nettype none
+
+
+module pl_cpld_regs #(
+ parameter BASE_ADDRESS = 0
+) (
+ input wire ctrlport_clk,
+ input wire ctrlport_rst,
+
+ // Request
+ input wire s_ctrlport_req_wr,
+ input wire s_ctrlport_req_rd,
+ input wire [19:0] s_ctrlport_req_addr,
+ input wire [31:0] s_ctrlport_req_data,
+ // Response
+ output reg s_ctrlport_resp_ack,
+ output reg [ 1:0] s_ctrlport_resp_status,
+ output reg [31:0] s_ctrlport_resp_data,
+
+ // 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,
+
+ // iPass status
+ output wire [ 1:0] ipass_cable_present
+);
+
+ `include "regmap/constants_regmap_utils.vh"
+ `include "regmap/pl_cpld_base_regmap_utils.vh"
+ `include "../../../lib/rfnoc/core/ctrlport.vh"
+
+ //---------------------------------------------------------------------------
+ // Address Calculation
+ //---------------------------------------------------------------------------
+
+ localparam NUM_ADDRESSES = 64;
+ wire address_in_range = (s_ctrlport_req_addr >= BASE_ADDRESS) &&
+ (s_ctrlport_req_addr < BASE_ADDRESS + NUM_ADDRESSES);
+
+ //---------------------------------------------------------------------------
+ // Internal Registers
+ //---------------------------------------------------------------------------
+
+ reg [SCRATCH_REGISTER_SIZE-1:0] scratch_reg;
+ reg [LED_REGISTER_SIZE-1:0] led_reg;
+ reg [CABLE_PRESENT_REG_SIZE-1:0] ipass_reg;
+
+ //---------------------------------------------------------------------------
+ // Assign Outputs
+ //---------------------------------------------------------------------------
+
+ assign qsfp0_led_active = led_reg[QSFP0_LED_ACTIVE+:QSFP0_LED_ACTIVE_SIZE];
+ assign qsfp0_led_link = led_reg[QSFP0_LED_LINK+:QSFP0_LED_LINK_SIZE];
+
+ assign qsfp1_led_active = led_reg[QSFP1_LED_ACTIVE+:QSFP1_LED_ACTIVE_SIZE];
+ assign qsfp1_led_link = led_reg[QSFP1_LED_LINK+:QSFP1_LED_LINK_SIZE];
+
+ assign ipass_cable_present = ipass_reg;
+
+ //---------------------------------------------------------------------------
+ // Handling of ControlPort Requests
+ //---------------------------------------------------------------------------
+
+ always @(posedge ctrlport_clk) begin
+ // Reset internal registers and responses
+ if (ctrlport_rst) begin
+ scratch_reg <= 0;
+ led_reg <= 0;
+ ipass_reg <= 0;
+ s_ctrlport_resp_ack <= 1'b0;
+
+ // Write requests
+ end else if (s_ctrlport_req_wr) begin
+ // Always issue an ack and no data
+ s_ctrlport_resp_ack <= 1'b1;
+ s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'bx}};
+ s_ctrlport_resp_status <= CTRL_STS_OKAY;
+
+ case (s_ctrlport_req_addr)
+ BASE_ADDRESS + SCRATCH_REGISTER:
+ scratch_reg <= s_ctrlport_req_data;
+
+ BASE_ADDRESS + LED_REGISTER:
+ led_reg <= s_ctrlport_req_data[LED_REGISTER_SIZE-1:0];
+
+ BASE_ADDRESS + CABLE_PRESENT_REG: begin
+ ipass_reg[0] <= s_ctrlport_req_data[IPASS0_CABLE_PRESENT];
+ ipass_reg[1] <= s_ctrlport_req_data[IPASS1_CABLE_PRESENT];
+ end
+
+ // Error on undefined address
+ default: begin
+ if (address_in_range) begin
+ s_ctrlport_resp_status <= CTRL_STS_CMDERR;
+
+ // No response if out of range
+ end else begin
+ s_ctrlport_resp_ack <= 1'b0;
+ end
+ end
+ endcase
+
+ // Read request
+ end else if (s_ctrlport_req_rd) begin
+ // Default assumption: valid request
+ s_ctrlport_resp_ack <= 1'b1;
+ s_ctrlport_resp_status <= CTRL_STS_OKAY;
+
+ case (s_ctrlport_req_addr)
+ BASE_ADDRESS + SIGNATURE_REGISTER:
+ s_ctrlport_resp_data <= PL_CPLD_SIGNATURE;
+
+ BASE_ADDRESS + REVISION_REGISTER:
+ s_ctrlport_resp_data <= CPLD_REVISION;
+
+ BASE_ADDRESS + OLDEST_COMPATIBLE_REVISION_REGISTER:
+ s_ctrlport_resp_data <= OLDEST_CPLD_REVISION;
+
+ BASE_ADDRESS + SCRATCH_REGISTER:
+ s_ctrlport_resp_data <= scratch_reg;
+
+ BASE_ADDRESS + GIT_HASH_REGISTER:
+ `ifdef GIT_HASH
+ s_ctrlport_resp_data <= `GIT_HASH;
+ `else
+ s_ctrlport_resp_data <= 32'hDEADBEEF;
+ `endif
+
+ BASE_ADDRESS + LED_REGISTER:
+ s_ctrlport_resp_data <= {{(CTRLPORT_DATA_W - LED_REGISTER_SIZE){1'b0}}, led_reg};
+
+ BASE_ADDRESS + CABLE_PRESENT_REG: begin
+ s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'b0}};
+ s_ctrlport_resp_data[IPASS0_CABLE_PRESENT] <= ipass_reg[0];
+ s_ctrlport_resp_data[IPASS1_CABLE_PRESENT] <= ipass_reg[1];
+ end
+
+ // Error on undefined address
+ default: begin
+ s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'bx}};
+ if (address_in_range) begin
+ s_ctrlport_resp_status <= CTRL_STS_CMDERR;
+
+ // No response if out of range
+ end else begin
+ s_ctrlport_resp_ack <= 1'b0;
+ end
+ end
+ endcase
+
+ // No request
+ end else begin
+ s_ctrlport_resp_ack <= 1'b0;
+ end
+ end
+
+endmodule
+
+
+`default_nettype wire
+
+
+//XmlParse xml_on
+//<regmap name="PL_CPLD_BASE_REGMAP" readablestrobes="false" generatevhdl="true" ettusguidelines="true">
+// <group name="PL_CPLD_BASE_REGS">
+// <info>
+// Basic registers containing version and capabilities information.
+// </info>
+//
+// <register name="SIGNATURE_REGISTER" offset="0x00" writable="false" size="32">
+// <info>Contains the product's signature.</info>
+// <bitfield name="PRODUCT_SIGNATURE" range="31..0">
+// <info>Fixed value PL_CPLD_SIGNATURE of @.CONSTANTS_REGMAP</info>
+// </bitfield>
+// </register>
+//
+// <register name="REVISION_REGISTER" offset="0x04" writable="false" size="32">
+// <info>Contains the CPLD revision (see CPLD_REVISION of @.CONSTANTS_REGMAP)</info>
+// <bitfield name="REVISION_HH" range="7..0">
+// <info>Contains revision hour code.</info>
+// </bitfield>
+// <bitfield name="REVISION_DD" range="15..8">
+// <info>Contains revision day code.</info>
+// </bitfield>
+// <bitfield name="REVISION_MM" range="23..16">
+// <info>Contains revision month code.</info>
+// </bitfield>
+// <bitfield name="REVISION_YY" range="31..24">
+// <info>Contains revision year code.</info>
+// </bitfield>
+// </register>
+//
+// <register name="OLDEST_COMPATIBLE_REVISION_REGISTER" offset="0x08" writable="false" size="32">
+// <info>
+// This register returns (in YYMMDDHH format) the oldest revision
+// that is still compatible with this one. Compatible means that
+// registers or register bits may have been added, but not
+// modified or deleted (see OLDEST_CPLD_REVISION of @.CONSTANTS_REGMAP).
+// </info>
+// <bitfield name="OLD_REVISION_HH" range="7..0">
+// <info>Contains revision hour code.</info>
+// </bitfield>
+// <bitfield name="OLD_REVISION_DD" range="15..8">
+// <info>Contains revision day code.</info>
+// </bitfield>
+// <bitfield name="OLD_REVISION_MM" range="23..16">
+// <info>Contains revision month code.</info>
+// </bitfield>
+// <bitfield name="OLD_REVISION_YY" range="31..24">
+// <info>Contains revision year code.</info>
+// </bitfield>
+// </register>
+//
+// <register name="SCRATCH_REGISTER" offset="0x0C" size="32">
+// <info>Read/write register for general software use.</info>
+// </register>
+//
+// <register name="GIT_HASH_REGISTER" offset="0x10" size="32" writable="false">
+// <info>
+// Git hash of commit used to build this image.{br}
+// Value equals 0xDEADBEEF if the git hash was not used during synthesis.
+// </info>
+// <bitfield name="GIT_CLEAN" range="31..28">
+// <info>
+// 0x0 in case the git status was clean{br}
+// 0xF in case there were uncommitted changes
+// </info>
+// </bitfield>
+// <bitfield name="GIT_HASH" range="27..0">
+// <info>7 hex digit hash code of the commit</info>
+// </bitfield>
+// </register>
+// </group>
+//
+// <group name="MB_CPLD_LED_REGS">
+// <info>
+// Register Map to control QSFP LEDs.
+// </info>
+// <register name="LED_REGISTER" offset="0x20" size="16">
+// <info>
+// Provides to the LEDs of the QSFP ports.
+// Write access will directly change the LED status.
+// The LED lights up if the corresponding bit is set.
+// </info>
+// <bitfield name="QSFP0_LED_LINK" range="3..0">
+// <info>Link LEDs of QSFP port 0</info>
+// </bitfield>
+// <bitfield name="QSFP0_LED_ACTIVE" range="7..4">
+// <info>Active LEDs of QSFP port 0</info>
+// </bitfield>
+// <bitfield name="QSFP1_LED_LINK" range="11..8">
+// <info>Link LEDs of QSFP port 1</info>
+// </bitfield>
+// <bitfield name="QSFP1_LED_ACTIVE" range="15..12">
+// <info>Active LEDs of QSFP port 1</info>
+// </bitfield>
+// </register>
+// </group>
+//
+// <group name="PL_CMI_REGS">
+// <info>
+// Cable present status register.
+// </info>
+// <register name="CABLE_PRESENT_REG" offset="0x30" size="2">
+// <info>
+// Information from FPGA about the cable present status.
+// </info>
+// <bitfield name="IPASS0_CABLE_PRESENT" range="0">
+// <info>Set to 1 if cable present in iPass 0 connector.</info>
+// </bitfield>
+// <bitfield name="IPASS1_CABLE_PRESENT" range="1">
+// <info>Set to 1 if cable present in iPass 1 connector.</info>
+// </bitfield>
+// </register>
+// </group>
+//</regmap>
+//XmlParse xml_off
diff --git a/fpga/usrp3/top/x400/cpld/ps_cpld_regs.v b/fpga/usrp3/top/x400/cpld/ps_cpld_regs.v
new file mode 100644
index 000000000..d5f9b1d5f
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/ps_cpld_regs.v
@@ -0,0 +1,404 @@
+//
+// Copyright 2021 Ettus Research, A National Instruments Brand
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: ps_cpld_regs
+//
+// Description:
+//
+// Basic registers to inform software about version and capabilities.
+//
+// Parameters:
+//
+// BASE_ADDRESS : Base address for CtrlPort registers
+//
+
+`default_nettype none
+
+
+module ps_cpld_regs #(
+ parameter BASE_ADDRESS = 0
+) (
+ input wire ctrlport_clk,
+ input wire ctrlport_rst,
+
+ // Request
+ input wire s_ctrlport_req_wr,
+ input wire s_ctrlport_req_rd,
+ input wire [19:0] s_ctrlport_req_addr,
+ input wire [31:0] s_ctrlport_req_data,
+ // Response
+ output reg s_ctrlport_resp_ack,
+ output reg [ 1:0] s_ctrlport_resp_status,
+ output reg [31:0] s_ctrlport_resp_data,
+
+ // Configuration outputs
+ output reg [ 1:0] db_clk_enable = 2'b00,
+ output reg [ 1:0] db_reset = 2'b11,
+ output reg pll_ref_clk_enable = 1'b0,
+
+ output reg [11:0] dio_direction_a = 12'b0,
+ output reg [11:0] dio_direction_b = 12'b0,
+
+ output reg [39:0] serial_num = 40'b0,
+ output reg cmi_ready = 1'b0,
+ input wire cmi_other_side_detected
+);
+
+`include "regmap/constants_regmap_utils.vh"
+`include "regmap/ps_cpld_base_regmap_utils.vh"
+`include "../../../lib/rfnoc/core/ctrlport.vh"
+
+//-----------------------------------------------------------------------------
+// Address Calculation
+//-----------------------------------------------------------------------------
+
+localparam NUM_ADDRESSES = 64;
+wire address_in_range = (s_ctrlport_req_addr >= BASE_ADDRESS) &&
+ (s_ctrlport_req_addr < BASE_ADDRESS + NUM_ADDRESSES);
+
+//-----------------------------------------------------------------------------
+// Internal Registers
+//-----------------------------------------------------------------------------
+
+reg [SCRATCH_REGISTER_SIZE-1:0] scratch_reg;
+
+//-----------------------------------------------------------------------------
+// Handling of ControlPort Requests
+//-----------------------------------------------------------------------------
+
+always @(posedge ctrlport_clk) begin
+ // Reset internal registers and responses
+ if (ctrlport_rst) begin
+ scratch_reg <= 0;
+ db_clk_enable <= 2'b00;
+ db_reset <= 2'b11;
+ pll_ref_clk_enable <= 1'b0;
+ dio_direction_a <= {DIO_DIRECTION_A_SIZE{1'b0}};
+ dio_direction_b <= {DIO_DIRECTION_B_SIZE{1'b0}};
+ s_ctrlport_resp_ack <= 1'b0;
+ s_ctrlport_resp_data <= {CTRLPORT_ADDR_W {1'bx}};
+ s_ctrlport_resp_status <= CTRL_STS_OKAY;
+
+ // Write requests
+ end else begin
+ if (s_ctrlport_req_wr) begin
+ // Always issue an ack and no data
+ s_ctrlport_resp_ack <= 1'b1;
+ s_ctrlport_resp_data <= {CTRLPORT_ADDR_W {1'bx}};
+ s_ctrlport_resp_status <= CTRL_STS_OKAY;
+
+ case (s_ctrlport_req_addr)
+ BASE_ADDRESS + SCRATCH_REGISTER:
+ scratch_reg <= s_ctrlport_req_data;
+
+ BASE_ADDRESS + PL_DB_REGISTER: begin
+ if (s_ctrlport_req_data[DISABLE_CLOCK_DB0]) begin
+ db_clk_enable[0] <= 1'b0;
+ end else if (s_ctrlport_req_data[ENABLE_CLOCK_DB0]) begin
+ db_clk_enable[0] <= 1'b1;
+ end
+ if (s_ctrlport_req_data[DISABLE_CLOCK_DB1]) begin
+ db_clk_enable[1] <= 1'b0;
+ end else if (s_ctrlport_req_data[ENABLE_CLOCK_DB1]) begin
+ db_clk_enable[1] <= 1'b1;
+ end
+ if (s_ctrlport_req_data[DISABLE_PLL_REF_CLOCK]) begin
+ pll_ref_clk_enable <= 1'b0;
+ end else if (s_ctrlport_req_data[ENABLE_PLL_REF_CLOCK]) begin
+ pll_ref_clk_enable <= 1'b1;
+ end
+ if (s_ctrlport_req_data[ASSERT_RESET_DB0]) begin
+ db_reset[0] <= 1'b1;
+ end else if (s_ctrlport_req_data[RELEASE_RESET_DB0]) begin
+ db_reset[0] <= 1'b0;
+ end
+ if (s_ctrlport_req_data[ASSERT_RESET_DB1]) begin
+ db_reset[1] <= 1'b1;
+ end else if (s_ctrlport_req_data[RELEASE_RESET_DB1]) begin
+ db_reset[1] <= 1'b0;
+ end
+ end
+
+ BASE_ADDRESS + DIO_DIRECTION_REGISTER: begin
+ dio_direction_a <= s_ctrlport_req_data[DIO_DIRECTION_A_MSB:DIO_DIRECTION_A];
+ dio_direction_b <= s_ctrlport_req_data[DIO_DIRECTION_B_MSB:DIO_DIRECTION_B];
+ end
+
+ BASE_ADDRESS + SERIAL_NUM_LOW_REG: begin
+ serial_num[31:0] <= s_ctrlport_req_data;
+ end
+
+ BASE_ADDRESS + SERIAL_NUM_HIGH_REG: begin
+ serial_num[39:32] <= s_ctrlport_req_data[SERIAL_NUM_HIGH_REG_SIZE-1:0];
+ end
+
+ BASE_ADDRESS + CMI_CONTROL_STATUS: begin
+ cmi_ready <= s_ctrlport_req_data[CMI_READY];
+ end
+
+ // Error on undefined address
+ default: begin
+ if (address_in_range) begin
+ s_ctrlport_resp_status <= CTRL_STS_CMDERR;
+
+ // No response if out of range
+ end else begin
+ s_ctrlport_resp_ack <= 1'b0;
+ end
+ end
+ endcase
+
+ // Read request
+ end else if (s_ctrlport_req_rd) begin
+ // Default assumption: valid request
+ s_ctrlport_resp_ack <= 1'b1;
+ s_ctrlport_resp_status <= CTRL_STS_OKAY;
+ s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'b0}};
+
+ case (s_ctrlport_req_addr)
+ BASE_ADDRESS + SIGNATURE_REGISTER:
+ s_ctrlport_resp_data <= PS_CPLD_SIGNATURE;
+
+ BASE_ADDRESS + REVISION_REGISTER:
+ s_ctrlport_resp_data <= CPLD_REVISION;
+
+ BASE_ADDRESS + OLDEST_COMPATIBLE_REVISION_REGISTER:
+ s_ctrlport_resp_data <= OLDEST_CPLD_REVISION;
+
+ BASE_ADDRESS + SCRATCH_REGISTER:
+ s_ctrlport_resp_data <= scratch_reg;
+
+ BASE_ADDRESS + GIT_HASH_REGISTER:
+ `ifdef GIT_HASH
+ s_ctrlport_resp_data <= `GIT_HASH;
+ `else
+ s_ctrlport_resp_data <= 32'hDEADBEEF;
+ `endif
+
+ BASE_ADDRESS + PL_DB_REGISTER: begin
+ s_ctrlport_resp_data[DB0_CLOCK_ENABLED] <= db_clk_enable[0];
+ s_ctrlport_resp_data[DB1_CLOCK_ENABLED] <= db_clk_enable[1];
+ s_ctrlport_resp_data[PLL_REF_CLOCK_ENABLED] <= pll_ref_clk_enable;
+ s_ctrlport_resp_data[DB0_RESET_ASSERTED] <= db_reset[0];
+ s_ctrlport_resp_data[DB1_RESET_ASSERTED] <= db_reset[1];
+ end
+
+ BASE_ADDRESS + DIO_DIRECTION_REGISTER: begin
+ s_ctrlport_resp_data[DIO_DIRECTION_A_MSB:DIO_DIRECTION_A] <= dio_direction_a;
+ s_ctrlport_resp_data[DIO_DIRECTION_B_MSB:DIO_DIRECTION_B] <= dio_direction_b;
+ end
+
+ BASE_ADDRESS + SERIAL_NUM_LOW_REG: begin
+ s_ctrlport_resp_data <= serial_num[31:0];
+ end
+
+ BASE_ADDRESS + SERIAL_NUM_HIGH_REG: begin
+ s_ctrlport_resp_data[SERIAL_NUM_HIGH_REG_SIZE-1:0] <= serial_num[39:32];
+ end
+
+ BASE_ADDRESS + CMI_CONTROL_STATUS: begin
+ s_ctrlport_resp_data[CMI_READY] <= cmi_ready;
+ s_ctrlport_resp_data[OTHER_SIDE_DETECTED] <= cmi_other_side_detected;
+ end
+
+ // Error on undefined address
+ default: begin
+ s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'bx}};
+ if (address_in_range) begin
+ s_ctrlport_resp_status <= CTRL_STS_CMDERR;
+
+ // No response if out of range
+ end else begin
+ s_ctrlport_resp_ack <= 1'b0;
+ end
+ end
+ endcase
+
+ // No request
+ end else begin
+ s_ctrlport_resp_ack <= 1'b0;
+ end
+ end
+end
+
+endmodule
+
+
+`default_nettype wire
+
+
+//XmlParse xml_on
+//<regmap name="PS_CPLD_BASE_REGMAP" readablestrobes="false" generatevhdl="true" ettusguidelines="true">
+// <group name="PS_CPLD_BASE_REGS">
+// <info>
+// Basic registers containing version and capabilites information.
+// </info>
+//
+// <register name="SIGNATURE_REGISTER" offset="0x00" writable="false" size="32">
+// <info>Contains the product's signature.</info>
+// <bitfield name="PRODUCT_SIGNATURE" range="31..0">
+// <info>Fixed value PS_CPLD_SIGNATURE of @.CONSTANTS_REGMAP</info>
+// </bitfield>
+// </register>
+//
+// <register name="REVISION_REGISTER" offset="0x04" writable="false" size="32">
+// <info>Contains the CPLD revision (see CPLD_REVISION of @.CONSTANTS_REGMAP).</info>
+// <bitfield name="REVISION_HH" range="7..0">
+// <info>Contains revision hour code.</info>
+// </bitfield>
+// <bitfield name="REVISION_DD" range="15..8">
+// <info>Contains revision day code.</info>
+// </bitfield>
+// <bitfield name="REVISION_MM" range="23..16">
+// <info>Contains revision month code.</info>
+// </bitfield>
+// <bitfield name="REVISION_YY" range="31..24">
+// <info>Contains revision year code.</info>
+// </bitfield>
+// </register>
+//
+// <register name="OLDEST_COMPATIBLE_REVISION_REGISTER" offset="0x08" writable="false" size="32">
+// <info>
+// This register returns (in YYMMDDHH format) the oldest revision
+// that is still compatible with this one. Compatible means that
+// registers or register bits may have been added, but not
+// modified or deleted (see OLDEST_CPLD_REVISION of @.CONSTANTS_REGMAP).
+// </info>
+// <bitfield name="OLD_REVISION_HH" range="7..0">
+// <info>Contains revision hour code.</info>
+// </bitfield>
+// <bitfield name="OLD_REVISION_DD" range="15..8">
+// <info>Contains revision day code.</info>
+// </bitfield>
+// <bitfield name="OLD_REVISION_MM" range="23..16">
+// <info>Contains revision month code.</info>
+// </bitfield>
+// <bitfield name="OLD_REVISION_YY" range="31..24">
+// <info>Contains revision year code.</info>
+// </bitfield>
+// </register>
+//
+// <register name="SCRATCH_REGISTER" offset="0x0C" size="32">
+// <info>Read/write register for general software use.</info>
+// </register>
+//
+// <register name="GIT_HASH_REGISTER" offset="0x10" size="32" writable="false">
+// <info>
+// Git hash of commit used to build this image.{br}
+// Value equals 0xDEADBEEF if the git hash was not used during synthesis.
+// </info>
+// <bitfield name="GIT_CLEAN" range="31..28">
+// <info>
+// 0x0 in case the git status was clean{br}
+// 0xF in case there were uncommitted changes
+// </info>
+// </bitfield>
+// <bitfield name="GIT_HASH" range="27..0">
+// <info>7 hex digit hash code of the commit</info>
+// </bitfield>
+// </register>
+// </group>
+//
+// <group name="PS_CONTROL_REGS">
+// <info>
+// Register Map to control MB CPLD functions.
+// </info>
+// <register name="PL_DB_REGISTER" offset="0x20" size="32">
+// <info>
+// Register to control the PL part DB SPI connection and reset generation.
+// The DB connection is clocked with PLL reference clock. Ensure this clock is stable
+// and enabled before starting any SPI request.
+// The PLL reference clock can be disabled if both DB connections are disabled or inactive.
+// To enable the DB connection, enable clock with one write access and release
+// reset with the next write access.
+// To disable the DB connection, assert reset with one write access and
+// disable clocks with the next write access.
+// </info>
+// <bitfield name="DB0_CLOCK_ENABLED" range="0" writable="false">
+// <info>Indicates if a clock is forwarded to DB 0.</info>
+// </bitfield>
+// <bitfield name="DB1_CLOCK_ENABLED" range="1" writable="false">
+// <info>Indicates if a clock is forwarded to DB 1.</info>
+// </bitfield>
+// <bitfield name="PLL_REF_CLOCK_ENABLED" range="2" writable="false">
+// <info>Indicates if the PLL reference clock for the PL interface is enabled.</info>
+// </bitfield>
+// <bitfield name="DB0_RESET_ASSERTED" range="4" writable="false">
+// <info>Indicates that reset is asserted for DB 0.</info>
+// </bitfield>
+// <bitfield name="DB1_RESET_ASSERTED" range="5" writable="false">
+// <info>Indicates that reset is asserted for DB 1.</info>
+// </bitfield>
+// <bitfield name="ENABLE_CLOCK_DB0" range="8" readable="false">
+// <info>Writing with this flag set enables DB 0 clock forwarding. (may be overwritten by @.DISABLE_CLOCK_DB0)</info>
+// </bitfield>
+// <bitfield name="ENABLE_CLOCK_DB1" range="9" readable="false">
+// <info>Writing with this flag set enables DB 1 clock forwarding. (may be overwritten by @.DISABLE_CLOCK_DB1)</info>
+// </bitfield>
+// <bitfield name="ENABLE_PLL_REF_CLOCK" range="10" readable="false">
+// <info>Writing with this flag set enables the PLL reference clock. Assert this flag after PLL reference clock is stable. (may be overwritten by @.DISABLE_PLL_REF_CLOCK)</info>
+// </bitfield>
+// <bitfield name="DISABLE_CLOCK_DB0" range="12" readable="false">
+// <info>Writing with this flag set disables DB 0 clock forwarding (overrides @.ENABLE_CLOCK_DB0)</info>
+// </bitfield>
+// <bitfield name="DISABLE_CLOCK_DB1" range="13" readable="false">
+// <info>Writing with this flag set disables DB 1 clock forwarding (overrides @.ENABLE_CLOCK_DB1)</info>
+// </bitfield>
+// <bitfield name="DISABLE_PLL_REF_CLOCK" range="14" readable="false">
+// <info>Writing with this flag set disables the PLL reference clock (overrides @.ENABLE_PLL_REF_CLOCK). Assert this flag to reconfigure the clock.</info>
+// </bitfield>
+// <bitfield name="RELEASE_RESET_DB0" range="16" readable="false">
+// <info>Writing with this flag set releases DB 0 reset. (may be overwritten by @.ASSERT_RESET_DB0)</info>
+// </bitfield>
+// <bitfield name="RELEASE_RESET_DB1" range="17" readable="false">
+// <info>Writing with this flag set releases DB 1 reset. (may be overwritten by @.ASSERT_RESET_DB1)</info>
+// </bitfield>
+// <bitfield name="ASSERT_RESET_DB0" range="20" readable="false">
+// <info>Writing with this flag set asserts reset for DB 0 (overrides @.RELEASE_RESET_DB0)</info>
+// </bitfield>
+// <bitfield name="ASSERT_RESET_DB1" range="21" readable="false">
+// <info>Writing with this flag set asserts reset for DB 1 (overrides @.RELEASE_RESET_DB1)</info>
+// </bitfield>
+// </register>
+// </group>
+//
+// <group name="DIO_REGS">
+// <info>
+// Registers to control the GPIO buffer direction on the DIO board connected to the FPGA.
+// Make sure the GPIO lines between FPGA and GPIO board are not driven by two drivers.
+// Set the direction in the FPGA's DIO register appropriately.
+// </info>
+// <register name="DIO_DIRECTION_REGISTER" offset="0x30" size="32">
+// <info>
+// Set the direction of FPGA buffer connected to DIO ports on the DIO board.{br/}
+// Each bit represents one signal line. 0 = line is an input to the FPGA, 1 = line is an output driven by the FPGA.
+// </info>
+// <bitfield name="DIO_DIRECTION_A" range="11..0" initialvalue="0"/>
+// <bitfield name="DIO_DIRECTION_B" range="27..16" initialvalue="0"/>
+// </register>
+// </group>
+//
+// <group name="PS_CMI_REGS">
+// <info>
+// Cable present status register.
+// </info>
+// <register name="SERIAL_NUM_LOW_REG" offset="0x34" size="32">
+// <info>Least significant bytes of 5 byte serial number.</info>
+// </register>
+// <register name="SERIAL_NUM_HIGH_REG" offset="0x38" size="8">
+// <info>Most significant byte of 5 byte serial number.</info>
+// </register>
+// <register name="CMI_CONTROL_STATUS" offset="0x3C" size="32">
+// <info>Control CMI communication and delivers information on the CMI link status.</info>
+// <bitfield name="CMI_READY" range="0">
+// <info>Set if the device is ready to establish a PCI-Express link (affects CMI_CLP_READY bit).</info>
+// </bitfield>
+// <bitfield name="OTHER_SIDE_DETECTED" range="31" writable="false">
+// <info>1 if an upstream CMI device has been detected.</info>
+// </bitfield>
+// </register>
+// </group>
+//</regmap>
+//XmlParse xml_off
diff --git a/fpga/usrp3/top/x400/cpld/ps_power_regs.v b/fpga/usrp3/top/x400/cpld/ps_power_regs.v
new file mode 100644
index 000000000..3e1a25206
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/ps_power_regs.v
@@ -0,0 +1,231 @@
+//
+// Copyright 2021 Ettus Research, A National Instruments Brand
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: ps_power_regs
+//
+// Description:
+//
+// Registers to control power supplies on the motherboard.
+//
+// Parameters:
+//
+// BASE_ADDRESS : Base address for CtrlPort registers.
+// NUM_ADDRESSES : Number of bytes of address space to use.
+//
+
+`default_nettype none
+
+
+module ps_power_regs #(
+ parameter BASE_ADDRESS = 0,
+ parameter NUM_ADDRESSES = 32
+) (
+ input wire ctrlport_clk,
+ input wire ctrlport_rst,
+
+ // Request
+ input wire s_ctrlport_req_wr,
+ input wire s_ctrlport_req_rd,
+ input wire [19:0] s_ctrlport_req_addr,
+ input wire [31:0] s_ctrlport_req_data,
+ // Response
+ output reg s_ctrlport_resp_ack,
+ output reg [ 1:0] s_ctrlport_resp_status,
+ output reg [31:0] s_ctrlport_resp_data,
+
+ // iPass
+ output reg ipass_power_disable = 1'b0,
+ input wire [ 1:0] ipass_power_fault_n,
+
+ // Oscillators
+ output reg osc_100_en,
+ output reg osc_122_88_en
+);
+
+ `include "regmap/ps_power_regmap_utils.vh"
+ `include "../../../lib/rfnoc/core/ctrlport.vh"
+
+ //----------------------------------------------------------
+ // Address Calculation
+ //----------------------------------------------------------
+
+ wire address_in_range = (s_ctrlport_req_addr >= BASE_ADDRESS) &&
+ (s_ctrlport_req_addr < BASE_ADDRESS + NUM_ADDRESSES);
+
+ //----------------------------------------------------------
+ // Internal Registers
+ //----------------------------------------------------------
+
+ reg [1:0] ipass_power_sticky = 2'b00;
+ reg [1:0] ipass_clear_sticky = 2'b00;
+
+ //----------------------------------------------------------
+ // Handling of ControlPort Requests
+ //----------------------------------------------------------
+
+ always @(posedge ctrlport_clk) begin
+ // Reset internal registers and responses
+ if (ctrlport_rst) begin
+ ipass_power_disable <= 1'b0;
+ s_ctrlport_resp_ack <= 1'b0;
+ s_ctrlport_resp_status <= CTRL_STS_OKAY;
+ s_ctrlport_resp_data <= {CTRLPORT_ADDR_W {1'bx}};
+
+ osc_100_en <= 1'b0;
+ osc_122_88_en <= 1'b0;
+
+ end else begin
+ // Default assignments
+ ipass_clear_sticky <= 2'b00;
+
+ // Write requests
+ if (s_ctrlport_req_wr) begin
+ // Always issue an ack and no data
+ s_ctrlport_resp_ack <= 1'b1;
+ s_ctrlport_resp_status <= CTRL_STS_OKAY;
+ s_ctrlport_resp_data <= {CTRLPORT_ADDR_W {1'bx}};
+
+ case (s_ctrlport_req_addr)
+ BASE_ADDRESS + IPASS_POWER_REG: begin
+ ipass_power_disable <= s_ctrlport_req_data[IPASS_DISABLE_POWER_BIT];
+ ipass_clear_sticky[0] <= s_ctrlport_req_data[IPASS_CLEAR_POWER_FAULT0];
+ ipass_clear_sticky[1] <= s_ctrlport_req_data[IPASS_CLEAR_POWER_FAULT1];
+ end
+
+ BASE_ADDRESS + OSC_POWER_REG: begin
+ osc_100_en <= s_ctrlport_req_data[OSC_100];
+ osc_122_88_en <= s_ctrlport_req_data[OSC_122_88];
+ end
+
+ // Error on undefined address
+ default: begin
+ if (address_in_range) begin
+ s_ctrlport_resp_status <= CTRL_STS_CMDERR;
+
+ // No response if out of range
+ end else begin
+ s_ctrlport_resp_ack <= 1'b0;
+ end
+ end
+ endcase
+
+ // Read request
+ end else if (s_ctrlport_req_rd) begin
+ // Default assumption: valid request
+ s_ctrlport_resp_ack <= 1'b1;
+ s_ctrlport_resp_status <= CTRL_STS_OKAY;
+ s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'b0}};
+
+ case (s_ctrlport_req_addr)
+ BASE_ADDRESS + IPASS_POWER_REG: begin
+ s_ctrlport_resp_data[IPASS_DISABLE_POWER_BIT] <= ipass_power_disable;
+ s_ctrlport_resp_data[IPASS_POWER_FAULT0] <= ipass_power_sticky[0];
+ s_ctrlport_resp_data[IPASS_POWER_FAULT1] <= ipass_power_sticky[1];
+ end
+
+ BASE_ADDRESS + OSC_POWER_REG: begin
+ s_ctrlport_resp_data[OSC_100] <= osc_100_en;
+ s_ctrlport_resp_data[OSC_122_88] <= osc_122_88_en;
+ end
+
+ // Error on undefined address
+ default: begin
+ s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'bx}};
+ if (address_in_range) begin
+ s_ctrlport_resp_status <= CTRL_STS_CMDERR;
+
+ // No response if out of range
+ end else begin
+ s_ctrlport_resp_ack <= 1'b0;
+ end
+ end
+ endcase
+
+ // No request
+ end else begin
+ s_ctrlport_resp_ack <= 1'b0;
+ end
+ end
+ end
+
+ //----------------------------------------------------------
+ // Sticky Logic of Power Registers
+ //----------------------------------------------------------
+
+ // Synchronize asynchronous inputs
+ wire [1:0] ipass_power_fault_lcl_n;
+ synchronizer #(
+ .WIDTH (2),
+ .STAGES (2),
+ .INITIAL_VAL (1'b0),
+ .FALSE_PATH_TO_IN (1)
+ ) power_fault_sync (
+ .clk (ctrlport_clk),
+ .rst (ctrlport_rst),
+ .in (ipass_power_fault_n),
+ .out (ipass_power_fault_lcl_n)
+ );
+
+ always @(posedge ctrlport_clk) begin
+ if (ctrlport_rst) begin
+ ipass_power_sticky <= 2'b00;
+ end else begin
+ // Keep value if not cleared or set in case of fault
+ ipass_power_sticky <= (ipass_power_sticky & ~ipass_clear_sticky) | ~ipass_power_fault_lcl_n;
+ end
+ end
+
+endmodule
+
+
+`default_nettype wire
+
+
+//XmlParse xml_on
+//<regmap name="PS_POWER_REGMAP" readablestrobes="false" generatevhdl="true" ettusguidelines="true">
+// <group name="PS_POWER_REGS">
+// <info>
+// Registers to control power supplies on the motherboard.
+// </info>
+//
+// <register name="IPASS_POWER_REG" offset="0x00" size="32">
+// <info>Controls the power supplies for the iPass connectors.</info>
+// <bitfield name="IPASS_DISABLE_POWER_BIT" range="0">
+// <info>Set to 1 to disable power for both iPass connectors.</info>
+// </bitfield>
+// <bitfield name="IPASS_CLEAR_POWER_FAULT0" range="30" readable="false">
+// <info>Clear @.IPASS_POWER_FAULT0.</info>
+// </bitfield>
+// <bitfield name="IPASS_CLEAR_POWER_FAULT1" range="31" readable="false">
+// <info>Clear @.IPASS_POWER_FAULT1.</info>
+// </bitfield>
+// <bitfield name="IPASS_POWER_FAULT0" range="30" writable="false">
+// <info>
+// Asserted signal indicates a power fault in power switch for iPass
+// connector 0. Sticky bit. Asserted on occurrence. Reset using
+// @.IPASS_CLEAR_POWER_FAULT0.
+// </info>
+// </bitfield>
+// <bitfield name="IPASS_POWER_FAULT1" range="31" writable="false">
+// <info>
+// Asserted signal indicates a power fault in power switch for iPass
+// connector 1. Sticky bit. Asserted on occurrence. Reset using
+// @.IPASS_CLEAR_POWER_FAULT1.
+// </info>
+// </bitfield>
+// </register>
+//
+// <register name="OSC_POWER_REG" offset="0x04" size="32">
+// <info>Controls the power supplies for the oscillators.</info>
+// <bitfield name="OSC_100" range="0">
+// <info>Enables 5V power switch for the 100 MHz oscillator.</info>
+// </bitfield>
+// <bitfield name="OSC_122_88" range="1">
+// <info>Enables 5V power switch for the 122.88 MHz oscillator.</info>
+// </bitfield>
+// </register>
+// </group>
+//</regmap>
+//XmlParse xml_off
diff --git a/fpga/usrp3/top/x400/cpld/pwr_supply_clk_gen.v b/fpga/usrp3/top/x400/cpld/pwr_supply_clk_gen.v
new file mode 100644
index 000000000..e69db9dfc
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/pwr_supply_clk_gen.v
@@ -0,0 +1,73 @@
+//
+// Copyright 2021 Ettus Research, A National Instruments Brand
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: pwr_supply_clk_gen
+//
+// Description:
+//
+// Generates a clock for one motherboard power supply.
+//
+// Parameters:
+//
+// BASE_ADDRESS : Base address for CtrlPort registers.
+// NUM_ADDRESSES : Number of bytes of address space to use.
+//
+
+`default_nettype none
+
+
+module pwr_supply_clk_gen#(
+ parameter SOURCE_CLK_FREQ = 100_000_000,
+ parameter TARGET_CLK_FREQ = 100_000
+) (
+ // Base clock and reset
+ input wire clk,
+ input wire rst,
+
+ // Power supply clocks
+ output reg pwr_supply_clk
+);
+
+//-----------------------------------------------------------------------------
+// Counter Calculation / Definition
+//-----------------------------------------------------------------------------
+// Counter to generate the power supply switching clock
+
+// Assumption: the ratio between the generated clock and the source clock is
+// even, therefore we can produce a 50% DC clock output.
+localparam MAX_COUNT = SOURCE_CLK_FREQ / TARGET_CLK_FREQ / 2;
+localparam COUNTER_W = $clog2(MAX_COUNT);
+reg [COUNTER_W-1:0] counter = 0;
+
+//-----------------------------------------------------------------------------
+// Clock Generation
+//-----------------------------------------------------------------------------
+// This process implements a simple clock divider for the power supply
+// switcher.
+
+// SAFE COUNTER START! rst is a synchronous reset generated in the
+// clk domain; therefore, inherently safe.
+always @(posedge clk) begin
+ if (rst) begin
+ counter <= 0;
+ pwr_supply_clk <= 1'b0;
+ end
+ else begin
+ // Add one every cycle to the counter
+ counter <= counter + 1'b1;
+
+ // When the counter reaches its mid value, it is reset and the output clock
+ // output is toggled.
+ if (counter == MAX_COUNT-1) begin
+ counter <= 0;
+ pwr_supply_clk <= ~pwr_supply_clk;
+ end
+ end
+end
+
+endmodule
+
+
+`default_nettype wire
diff --git a/fpga/usrp3/top/x400/cpld/raw_conversion.cof b/fpga/usrp3/top/x400/cpld/raw_conversion.cof
new file mode 100644
index 000000000..87ecb15d8
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/raw_conversion.cof
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="US-ASCII" standalone="yes"?>
+<cof>
+ <output_filename>output_files/mb_cpld_converted.pof</output_filename>
+ <n_pages>1</n_pages>
+ <width>1</width>
+ <mode>14</mode>
+ <sof_data>
+ <user_name>Page_0</user_name>
+ <page_flags>1</page_flags>
+ <bit0>
+ <sof_filename>output_files/mb_cpld.sof<compress_bitstream>1</compress_bitstream></sof_filename>
+ </bit0>
+ </sof_data>
+ <version>10</version>
+ <create_cvp_file>0</create_cvp_file>
+ <create_hps_iocsr>0</create_hps_iocsr>
+ <auto_create_rpd>1</auto_create_rpd>
+ <rpd_little_endian>1</rpd_little_endian>
+ <options>
+ <map_file>1</map_file>
+ </options>
+ <MAX10_device_options>
+ <por>0</por>
+ <io_pullup>1</io_pullup>
+ <config_from_cfm0_only>0</config_from_cfm0_only>
+ <isp_source>0</isp_source>
+ <verify_protect>0</verify_protect>
+ <epof>0</epof>
+ <ufm_source>0</ufm_source>
+ </MAX10_device_options>
+ <advanced_options>
+ <ignore_epcs_id_check>1</ignore_epcs_id_check>
+ <ignore_condone_check>2</ignore_condone_check>
+ <plc_adjustment>0</plc_adjustment>
+ <post_chain_bitstream_pad_bytes>-1</post_chain_bitstream_pad_bytes>
+ <post_device_bitstream_pad_bytes>-1</post_device_bitstream_pad_bytes>
+ <bitslice_pre_padding>1</bitslice_pre_padding>
+ </advanced_options>
+</cof> \ No newline at end of file
diff --git a/fpga/usrp3/top/x400/cpld/reconfig_engine.v b/fpga/usrp3/top/x400/cpld/reconfig_engine.v
new file mode 100644
index 000000000..a7c94b4a2
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/reconfig_engine.v
@@ -0,0 +1,1024 @@
+//
+// Copyright 2021 Ettus Research, A National Instruments Brand
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: reconfig_engine
+//
+// Description:
+//
+// This file implements the registers and the state machine to interface with
+// Intel's IP for the Max 10 FPGA that allows in-field updates to the primary
+// FPGA image. This state machine has been designed to provide a level of
+// abstraction between the register interface provided to user and the
+// details of interfacing with Intel's On-Chip Flash IP block. The user
+// simply needs to instruct this state machine to enable/disable write
+// protection and perform read/write/erase operations accordingly to load and
+// verify a new primary FPGA image. Since the purpose of this file is to
+// allow modification to an FPGA image care has been taken to mitigate data
+// corruption.
+//
+// The interface to Intel's On-Chip Flash IP block implemented in this file
+// is based on the information found in the Max 10 User Flash Memory User
+// Guide found at the link below.
+//
+// https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/hb/max-10/ug_m10_ufm.pdf
+//
+// Parameters:
+//
+// BASE_ADDRESS : Base address for CtrlPort registers.
+// NUM_ADDRESSES : Number of bytes of address space to use.
+// MEM_INIT : Memory initialization enabled. Set to 0 if MAX10 internal
+// configuration set to single compressed image. Set to 1 if
+// MAX10 internal configuration set to single compressed
+// image with memory initialization.
+//
+
+`default_nettype none
+
+
+module reconfig_engine #(
+ parameter BASE_ADDRESS = 0,
+ parameter NUM_ADDRESSES = 32,
+ parameter MEM_INIT = 0
+) (
+ input wire ctrlport_clk,
+ input wire ctrlport_rst,
+
+ /// Request
+ input wire s_ctrlport_req_wr,
+ input wire s_ctrlport_req_rd,
+ input wire [19:0] s_ctrlport_req_addr,
+ input wire [31:0] s_ctrlport_req_data,
+ // Response
+ output reg s_ctrlport_resp_ack,
+ output reg [ 1:0] s_ctrlport_resp_status,
+ output reg [31:0] s_ctrlport_resp_data,
+
+ // Interface to On-Chip Flash IP
+ output reg csr_addr,
+ output reg csr_read,
+ output reg [31:0] csr_writedata,
+ output reg csr_write,
+ input wire [31:0] csr_readdata,
+ output reg [16:0] data_addr,
+ output reg data_read,
+ output reg [31:0] data_writedata,
+ output reg data_write,
+ input wire [31:0] data_readdata,
+ input wire data_waitrequest,
+ input wire data_readdatavalid
+);
+
+ `include "regmap/reconfig_regmap_utils.vh"
+ `include "../../../lib/rfnoc/core/ctrlport.vh"
+
+ //----------------------------------------------------------
+ // Flash Interface between Registers and State Machine
+ //----------------------------------------------------------
+
+ // Flash Data Interface
+ reg [16:0] flash_addr = 0;
+ reg [31:0] flash_write_data = 0;
+ reg [31:0] flash_read_data;
+
+ // Flash Control Interface - Control
+ reg flash_read_stb = 1'b0;
+ reg flash_write_stb = 1'b0;
+ reg flash_erase_stb = 1'b0;
+ reg flash_enable_wp_stb = 1'b0;
+ reg flash_disable_wp_stb = 1'b0;
+ reg [2:0] flash_sector = 3'b0;
+
+ // Flash Control Interface - Status
+ reg flash_wp_enabled;
+ reg flash_read_idle;
+ reg flash_write_idle;
+ reg flash_erase_idle;
+ reg flash_read_err;
+ reg flash_write_err;
+ reg flash_erase_err;
+ reg clear_flash_read_err_stb = 1'b0;
+ reg clear_flash_write_err_stb = 1'b0;
+ reg clear_flash_erase_err_stb = 1'b0;
+
+ //----------------------------------------------------------
+ // Address Calculation
+ //----------------------------------------------------------
+
+ wire address_in_range = (s_ctrlport_req_addr >= BASE_ADDRESS) &&
+ (s_ctrlport_req_addr < BASE_ADDRESS + NUM_ADDRESSES);
+
+ //----------------------------------------------------------
+ // Handling of ControlPort Requests
+ //----------------------------------------------------------
+
+ always @(posedge ctrlport_clk) begin
+ // Default assignments
+ s_ctrlport_resp_ack <= 1'b0;
+
+ flash_read_stb <= 1'b0;
+ flash_write_stb <= 1'b0;
+ flash_erase_stb <= 1'b0;
+ flash_enable_wp_stb <= 1'b0;
+ flash_disable_wp_stb <= 1'b0;
+ clear_flash_read_err_stb <= 1'b0;
+ clear_flash_write_err_stb <= 1'b0;
+ clear_flash_erase_err_stb <= 1'b0;
+
+ // Do not acknowledge on reset
+ if (ctrlport_rst) begin
+ s_ctrlport_resp_ack <= 1'b0;
+ s_ctrlport_resp_data <= {32{1'bx}};
+ s_ctrlport_resp_status <= CTRL_STS_OKAY;
+
+ // Write requests
+ end else begin
+ if (s_ctrlport_req_wr) begin
+ // Always issue an ack and no data
+ s_ctrlport_resp_ack <= 1'b1;
+ s_ctrlport_resp_data <= {32{1'bx}};
+ s_ctrlport_resp_status <= CTRL_STS_OKAY;
+
+ case (s_ctrlport_req_addr)
+ BASE_ADDRESS + FLASH_CONTROL_REG: begin
+ flash_read_stb <= s_ctrlport_req_data[FLASH_READ_STB];
+ flash_write_stb <= s_ctrlport_req_data[FLASH_WRITE_STB];
+ flash_erase_stb <= s_ctrlport_req_data[FLASH_ERASE_STB];
+ flash_enable_wp_stb <= s_ctrlport_req_data[FLASH_ENABLE_WP_STB];
+ flash_disable_wp_stb <= s_ctrlport_req_data[FLASH_DISABLE_WP_STB];
+ clear_flash_read_err_stb <= s_ctrlport_req_data[CLEAR_FLASH_READ_ERROR_STB];
+ clear_flash_write_err_stb <= s_ctrlport_req_data[CLEAR_FLASH_WRITE_ERROR_STB];
+ clear_flash_erase_err_stb <= s_ctrlport_req_data[CLEAR_FLASH_ERASE_ERROR_STB];
+ flash_sector <= s_ctrlport_req_data[FLASH_ERASE_SECTOR_MSB:FLASH_ERASE_SECTOR];
+ end
+
+ BASE_ADDRESS + FLASH_ADDR_REG: begin
+ flash_addr <= s_ctrlport_req_data[FLASH_ADDR_MSB:FLASH_ADDR];
+ end
+
+ BASE_ADDRESS + FLASH_WRITE_DATA_REG: begin
+ flash_write_data <= s_ctrlport_req_data[FLASH_WRITE_DATA_MSB:FLASH_WRITE_DATA];
+ end
+
+ // Error on undefined address
+ default: begin
+ if (address_in_range) begin
+ s_ctrlport_resp_status <= CTRL_STS_CMDERR;
+
+ // No response if out of range
+ end else begin
+ s_ctrlport_resp_ack <= 1'b0;
+ end
+ end
+ endcase
+
+ // Read request
+ end else if (s_ctrlport_req_rd) begin
+ // Default assumption: valid request
+ s_ctrlport_resp_ack <= 1'b1;
+ s_ctrlport_resp_status <= CTRL_STS_OKAY;
+
+ case (s_ctrlport_req_addr)
+ BASE_ADDRESS + FLASH_STATUS_REG: begin
+ s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'b0}};
+ s_ctrlport_resp_data[FLASH_WP_ENABLED] <= flash_wp_enabled;
+ s_ctrlport_resp_data[FLASH_READ_IDLE] <= flash_read_idle;
+ s_ctrlport_resp_data[FLASH_READ_ERR] <= flash_read_err;
+ s_ctrlport_resp_data[FLASH_ERASE_IDLE] <= flash_erase_idle;
+ s_ctrlport_resp_data[FLASH_ERASE_ERR] <= flash_erase_err;
+ s_ctrlport_resp_data[FLASH_WRITE_IDLE] <= flash_write_idle;
+ s_ctrlport_resp_data[FLASH_WRITE_ERR] <= flash_write_err;
+ s_ctrlport_resp_data[FLASH_MEM_INIT_ENABLED] <= MEM_INIT ? 1'b1 : 1'b0;
+ end
+
+ BASE_ADDRESS + FLASH_ADDR_REG: begin
+ s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'b0}};
+ s_ctrlport_resp_data[FLASH_ADDR_MSB:FLASH_ADDR] <= flash_addr;
+ end
+
+ BASE_ADDRESS + FLASH_READ_DATA_REG: begin
+ s_ctrlport_resp_data <= flash_read_data;
+ end
+
+ BASE_ADDRESS + FLASH_CFM0_START_ADDR_REG: begin
+ s_ctrlport_resp_data <= MEM_INIT ? FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT :
+ FLASH_PRIMARY_IMAGE_START_ADDR;
+ end
+
+ BASE_ADDRESS + FLASH_CFM0_END_ADDR_REG: begin
+ s_ctrlport_resp_data <= FLASH_PRIMARY_IMAGE_END_ADDR;
+ end
+
+ // Error on undefined address
+ default: begin
+ s_ctrlport_resp_data <= {32{1'bx}};
+ if (address_in_range) begin
+ s_ctrlport_resp_status <= CTRL_STS_CMDERR;
+
+ // No response if out of range
+ end else begin
+ s_ctrlport_resp_ack <= 1'b0;
+ end
+ end
+ endcase
+ end
+ end
+ end
+
+ //----------------------------------------------------------
+ // State Machine Constants
+ //----------------------------------------------------------
+
+ // Local state
+ localparam IDLE = 4'h0;
+ localparam WP_DISABLED = 4'h1;
+ localparam WAIT_FOR_READ_DATA_VALID = 4'h2;
+ localparam GET_READ_STATUS = 4'h3;
+ localparam CHECK_READ_STATUS = 4'h4;
+ localparam WAIT_FOR_WRITE_COMPLETE = 4'h5;
+ localparam GET_WRITE_STATUS = 4'h6;
+ localparam CHECK_WRITE_STATUS = 4'h7;
+ localparam ERASE_SECTOR = 4'h8;
+ localparam GET_ERASE_BUSY = 4'h9;
+ localparam CHECK_ERASE_BUSY = 4'hA;
+ localparam GET_ERASE_IDLE = 4'hB;
+ localparam CHECK_ERASE_IDLE = 4'hC;
+
+ // The Intel on-chip flash control interface has two registers, a Status
+ // Register at address 0 and a Control Register at address 1. The constants
+ // defined below identify fields and values of interest in each register.
+ // These are taken directly from the Max 10 Flash Memory User Guide.
+ localparam STATUS_REG_ADDR = 1'b0;
+ localparam STATUS_REG_BUSY_STATUS_MSB = 1;
+ localparam STATUS_REG_BUSY_STATUS_LSB = 0;
+ localparam STATUS_REG_IDLE = 2'b00;
+ localparam STATUS_REG_ERASE_BUSY = 2'b01;
+ localparam STATUS_REG_WRITE_BUSY = 2'b10;
+ localparam STATUS_REG_READ_BUSY = 2'b11;
+ localparam STATUS_REG_READ_STATUS = 2;
+ localparam STATUS_REG_WRITE_STATUS = 3;
+ localparam STATUS_REG_ERASE_STATUS = 4;
+ localparam OPERATION_FAILED = 0;
+
+ localparam CONTROL_REG_ADDR = 1'b1;
+ localparam SECTOR_ERASE_ADDR_MSB = 22;
+ localparam SECTOR_ERASE_ADDR_LSB = 20;
+ localparam CFM0_WP_OFFSET_MSB = 26;
+ localparam CFM0_WP_OFFSET_LSB = 24;
+ localparam ENABLE_WP = MEM_INIT ? 3'b111 : 3'b100;
+ localparam DISABLE_WP = 3'b000;
+
+ //----------------------------------------------------------
+ // State Machine
+ //----------------------------------------------------------
+
+ reg [3:0] state = IDLE;
+ wire flash_no_errors_detected;
+
+ assign flash_no_errors_detected = ~(flash_read_err | flash_write_err | flash_erase_err);
+
+ always @(posedge ctrlport_clk) begin
+ if (ctrlport_rst) begin
+ state <= IDLE;
+
+ // Signals to config registers
+ flash_wp_enabled <= 1'b1;
+ flash_read_idle <= 1'b1;
+ flash_write_idle <= 1'b1;
+ flash_erase_idle <= 1'b1;
+ flash_read_err <= 1'b0;
+ flash_write_err <= 1'b0;
+ flash_erase_err <= 1'b0;
+ flash_read_data <= 32'b0;
+
+ // Signals to flash control interface
+ csr_addr <= 1'b0;
+ csr_writedata <= {32 {1'b1}};
+ csr_read <= 1'b0;
+ csr_write <= 1'b0;
+
+ // Signals to flash data interface
+ data_addr <= 17'b0;
+ data_writedata <= 32'b0;
+ data_read <= 1'b0;
+ data_write <= 1'b0;
+ end
+ // Rising edge clock
+ else begin
+ // Default values
+ csr_read <= 1'b0;
+ csr_write <= 1'b0;
+ csr_addr <= STATUS_REG_ADDR;
+ csr_writedata <= {32 {1'b1}};
+
+ data_read <= 1'b0;
+ data_write <= 1'b0;
+
+ // State handling
+ case(state)
+
+ // When in IDLE:
+ // * No operations are in progress and write protection is enabled.
+ // * Allowed transitions are to either read data from flash or
+ // disable write protection.
+ // * Transitions are only allowed if no error bits are asserted.
+ // * In the event both the *read_stb and *disable_wp_stb bits are
+ // asserted read operations take priority as these do not open the
+ // flash to modification.
+ // * Attempts to both enable and disable write protection
+ // simultaneously result in the state machine remaining in IDLE
+ // write protection enabled.
+ IDLE: begin
+ flash_wp_enabled <= 1'b1;
+
+ if (flash_read_stb && flash_no_errors_detected) begin
+ state <= WAIT_FOR_READ_DATA_VALID;
+ flash_read_idle <= 1'b0;
+ data_read <= 1'b1;
+ data_addr <= flash_addr;
+ end else if (flash_disable_wp_stb && ~flash_enable_wp_stb && flash_no_errors_detected) begin
+ state <= WP_DISABLED;
+ csr_write <= 1'b1;
+ csr_addr <= CONTROL_REG_ADDR;
+ csr_writedata[CFM0_WP_OFFSET_MSB:CFM0_WP_OFFSET_LSB] <= DISABLE_WP;
+ end
+ end
+
+ // Transition from WP_DISABLED when write protection is enabled or when
+ // write/erase operations are initiated. A few things to note:
+ // * Enabling write protection takes priority, regardless of what
+ // other control bits may be asserted simultaneously, followed by
+ // writes, and lastly erases.
+ // * The user should not strobe both the *write_stb and *erase_stb
+ // bits simultaneously, but if they do the state machine returns to
+ // IDLE (thereby enabling write protection) and the *write_err and
+ // *erase_err bits are asserted.
+ // * Performing a write or erase operation is only allowed from
+ // WP_DISABLED. This allows some mitigation against data corruption
+ // as multiple steps are required to change the data in the flash.
+ // First write protection must be disabled, and only then can the
+ // flash be erased or written.
+ WP_DISABLED: begin
+ flash_wp_enabled <= 1'b0;
+
+ if (flash_erase_stb && flash_write_stb) begin
+ flash_erase_err <= 1'b1;
+ flash_write_err <= 1'b1;
+ end
+
+ if (flash_enable_wp_stb || (flash_erase_stb && flash_write_stb)) begin
+ state <= IDLE;
+ csr_write <= 1'b1;
+ csr_addr <= CONTROL_REG_ADDR;
+ csr_writedata[CFM0_WP_OFFSET_MSB:CFM0_WP_OFFSET_LSB] <= ENABLE_WP;
+ end else if (flash_write_stb) begin
+ state <= WAIT_FOR_WRITE_COMPLETE;
+ flash_write_idle <= 1'b0;
+ data_write <= 1'b1;
+ data_writedata <= flash_write_data;
+ data_addr <= flash_addr;
+ end else if (flash_erase_stb) begin
+ state <= ERASE_SECTOR;
+ flash_erase_idle <= 1'b0;
+ csr_write <= 1'b1;
+ csr_addr <= CONTROL_REG_ADDR;
+ csr_writedata[CFM0_WP_OFFSET_MSB:CFM0_WP_OFFSET_LSB] <= DISABLE_WP;
+ csr_writedata[SECTOR_ERASE_ADDR_MSB:SECTOR_ERASE_ADDR_LSB] <= flash_sector;
+ end
+ end
+
+
+ // Read Flash
+ // --------------
+ // Per Intel's Max 10 User Flash Memory User Guide, the Read bit of the
+ // flash data interface should be pulsed for one clock cycle to start
+ // the read process from flash. This pulse occurs upon transition from
+ // IDLE to WAIT_FOR_READ_DATA_VALID. The state machine then waits in
+ // WAIT_FOR_READ_DATA_VALID until the flash data interface
+ // data_readdatavalid signal asserts, indicating the data is now valid.
+ // Intel's documentation does not provide guidance on the expected time
+ // for data_readdatavalid to assert. From simulation, however,
+ // data_readdatavalid asserts four clock cycles after the Read pulse
+ // ends. The data_readdatavalid signal from the flash data interface
+ // pulses for one clock cycle. Only during this pulse is the data valid.
+ WAIT_FOR_READ_DATA_VALID: begin
+ if (data_readdatavalid) begin
+ state <= GET_READ_STATUS;
+ flash_read_data <= data_readdata;
+ csr_read <= 1'b1;
+ end
+ end
+
+ // The data_readdatavalid signal determines when the read operation has
+ // completed in the flash data interface, but Intel's documentation
+ // does not indicate the relation of this bit to the 'busy' field in
+ // the flash control interface Status Register. To verify that the read
+ // operation is complete, the StatusRegister is polled until the 'busy'
+ // field indicates the flash is idle. This polling operation is
+ // implemented with CHECK_READ_STATUS below. GET_READ_STATUS exists to
+ // set the address of the flash control interface to the Status
+ // Register and pulse the read bit of the flash control interface.
+ // CHECK_READ_STATUS evaluates the resulting Status Register data and
+ // steer the state machine accordingly. See Figure 6 in Intel's Max 10
+ // User Flash Memory User Guide for a waveform on this request and
+ // check mechanism. Successful read operations result in the state
+ // machine returning to IDLE. Failing read operations assert the
+ // flash_read_err bit before returning to IDLE. From simulation, the
+ // 'busy' field returns to IDLE on the third read.
+ GET_READ_STATUS: begin
+ state <= CHECK_READ_STATUS;
+ // csr_read set in transactions into this state
+ // CSR address set as default assignment
+ end
+ CHECK_READ_STATUS: begin
+ if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_IDLE) begin
+ state <= IDLE;
+ flash_read_idle <= 1'b1;
+ flash_read_err <= (csr_readdata[STATUS_REG_READ_STATUS] == OPERATION_FAILED) ? 1'b1 : 1'b0;
+ end else if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_READ_BUSY) begin
+ state <= GET_READ_STATUS;
+ csr_read <= 1'b1;
+ end
+ end
+
+
+ // Write Flash
+ //---------------
+ // Per Intel's Max 10 User Flash Memory User Guide, the Write bit of
+ // the flash data interface should be asserted while maintaining
+ // address and data until the flash interface deasserts the
+ // data_waitrequest bit. Transition from WP_DISABLED to
+ // WAIT_FOR_WRITE_COMPLETE causes the write bit to assert and address
+ // and data to be set. The state machine remains in this state until
+ // the data_waitrequest bit deasserts. Per Intel's Max 10 User Flash
+ // Memory User Guide, the data_waitrequest signal is expected to
+ // deassert within 555 usec.
+ WAIT_FOR_WRITE_COMPLETE: begin
+ if (~data_waitrequest) begin
+ state <= GET_WRITE_STATUS;
+ csr_read <= 1'b1;
+ end else begin
+ // Flash writes require asserting the Write bit of the flash data
+ // interface until the write is complete.
+ data_write <= 1'b1;
+ end
+ end
+
+ // The data_waitrequest signal determines when the write operation has
+ // completed in the flash data interface, but Intel's documentation does
+ // not indicate the relation of this bit to the 'busy' field in the flash
+ // control interface Status Register. To verify that the write operation
+ // is complete the StatusRegister is polled until the 'busy' field
+ // indicates the flash is idle. This polling operation is implemented with
+ // GET_WRITE_STATUS and CHECK_WRITE_STATUS below, and follows the same
+ // methodology as the polling operation for reads described above with the
+ // following two changes:
+ // * Upon successful completion of a write operation the state
+ // machine returns to WP_DISABLED. This allows repeated writes of
+ // new data without having to disable/enable for each write.
+ // * When a failure is detected the state machine transitions to to
+ // IDLE thereby enabling write protection. Failure of a write is
+ // not expected. Write protection is enabled in the event of a
+ // failure to mitigate further data corruption.
+ GET_WRITE_STATUS: begin
+ state <= CHECK_WRITE_STATUS;
+ // csr_read set in transactions into this state
+ // CSR address set as default assignment
+ end
+ CHECK_WRITE_STATUS: begin
+ if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_IDLE) begin
+ if (csr_readdata[STATUS_REG_WRITE_STATUS] == OPERATION_FAILED) begin
+ state <= IDLE;
+ csr_write <= 1'b1;
+ csr_addr <= CONTROL_REG_ADDR;
+ csr_writedata[CFM0_WP_OFFSET_MSB:CFM0_WP_OFFSET_LSB] <= ENABLE_WP;
+ end else begin // SUCCESS
+ state <= WP_DISABLED;
+ end
+ flash_write_idle <= 1'b1;
+ flash_write_err <= (csr_readdata[STATUS_REG_WRITE_STATUS] == OPERATION_FAILED) ? 1'b1 : 1'b0;
+ end else if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_WRITE_BUSY) begin
+ state <= GET_WRITE_STATUS;
+ csr_read <= 1'b1;
+ end
+ end
+
+ // Erase Flash
+ //-------------
+ // Erasing the primary configuration image requires a single write to
+ // the flash control interface Control Register. Only one sector needs
+ // to be erased to erase the entire primary configuration image.
+ // Transition from WP_DISABLED to ERASE_SECTOR causes data to be
+ // written to the Control Register to erase this sector and pulse the
+ // flash control interface write bit.
+ ERASE_SECTOR: begin
+ state <= GET_ERASE_BUSY;
+ csr_read <= 1'b1;
+ end
+
+ // There is some latency between writing the Control Register and the
+ // 'busy' field of the flash control interface Status Register
+ // indicating the erase operation is in progress. After initiating the
+ // erase operation, GET_ERASE_BUSY and CHECK_ERASE_BUSY implement a
+ // polling operation to determine when the erase operation has started.
+ // GET_ERASE_BUSY exists to set the address of the flash control
+ // interface to the Status Register and pulse the read bit of the flash
+ // control interface. CHECK_ERASE_BUSY exists to evaluate the resulting
+ // Status Register data and steer the state machine accordingly. The
+ // polling operation continues until the 'busy' field indicates the
+ // erase operation is in progress. Intel's documentation does not
+ // indicate how long it takes for the Status Register to indicate the
+ // erase is in progress, but simulation shows the erase is in progress
+ // after the second read.
+ GET_ERASE_BUSY: begin
+ state <= CHECK_ERASE_BUSY;
+ // csr_read set in transactions into this state
+ // CSR address set as default assignment
+ end
+ CHECK_ERASE_BUSY: begin
+ if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_ERASE_BUSY) begin
+ state <= GET_ERASE_IDLE;
+ csr_read <= 1'b1;
+ end else if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_IDLE) begin
+ state <= GET_ERASE_BUSY;
+ csr_read <= 1'b1;
+ end
+ end
+
+ // Once the erase operation is in progress a second polling operation
+ // defined by GET_ERASE_IDLE and CHECK_ERASE_IDLE is implemented to
+ // determine when the operation has completed. This polling operation
+ // follows the same methodology as the polling operation for erase busy
+ // described above. Intel's documentation indicates that erase
+ // operations take a maximum of 350 msec.
+ GET_ERASE_IDLE: begin
+ state <= CHECK_ERASE_IDLE;
+ // csr_read set in transactions into this state
+ // CSR address set as default assignment
+ end
+ CHECK_ERASE_IDLE: begin
+ if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_IDLE) begin
+ if (csr_readdata[STATUS_REG_ERASE_STATUS] == OPERATION_FAILED) begin
+ state <= IDLE;
+ csr_write <= 1'b1;
+ csr_addr <= CONTROL_REG_ADDR;
+ csr_writedata[CFM0_WP_OFFSET_MSB:CFM0_WP_OFFSET_LSB] <= ENABLE_WP;
+ end else begin // SUCCESS
+ state <= WP_DISABLED;
+ end
+ flash_erase_idle <= 1'b1;
+ flash_erase_err <= (csr_readdata[STATUS_REG_ERASE_STATUS] == OPERATION_FAILED) ? 1'b1 : 1'b0;
+ end else if (csr_readdata[STATUS_REG_BUSY_STATUS_MSB:STATUS_REG_BUSY_STATUS_LSB] == STATUS_REG_ERASE_BUSY) begin
+ state <= GET_ERASE_IDLE;
+ csr_read <= 1'b1;
+ end
+ end
+
+ // Default to IDLE in other cases
+ default: begin
+ state <= IDLE;
+ end
+ endcase
+
+ // Reset errors
+ if (clear_flash_read_err_stb) begin
+ flash_read_err <= 1'b0;
+ end
+ if (clear_flash_write_err_stb) begin
+ flash_write_err <= 1'b0;
+ end
+ if (clear_flash_erase_err_stb) begin
+ flash_erase_err <= 1'b0;
+ end
+ end
+ end
+
+endmodule
+
+
+`default_nettype wire
+
+
+//XmlParse xml_on
+//<regmap name="RECONFIG_REGMAP" readablestrobes="false" generatevhdl="true" ettusguidelines="true">
+// <group name="RECONFIG_REGS">
+// <info>
+// These registers are used to upload and verify a new primary image to the
+// Max 10 FPGA on-chip flash when configured to support dual configuration
+// images. The steps below outline the process of verifying/preparing the
+// new image to be written, erasing the current image, writing the new
+// image, and verifying the new image was successfully written.
+// {p}{b}Prepare the data...{/b}
+// {ol}{li}{p}The Max 10 FPGA build should generate a *cfm0_auto.rpd
+// file The *.rpd file is a "raw programming
+// data" file holding all data related to the
+// configuration image (CFM0). There are two
+// important items to note regarding the addresses.
+// First the *rpd data uses {b}byte{/b} addresses.
+// Second, the start/end addresses defined by
+// FLASH_PRIMARY_IMAGE_ADDR_ENUM are 32-bit word addresses{/p}{/li}
+// {li}{p}As a sanity check, verify the size of the raw
+// programming data for CFM0 correspond to the address
+// range of FLASH_PRIMARY_IMAGE_ADDR_ENUM. Do this by
+// reading the values from FLASH_CFM0_START_ADDR_REG and
+// FLASH_CFM0_END_ADDR, subtract both values, add one and
+// multiply by four.
+// {/p}{/li}
+// {li}{p}Having passed the sanity check the *.rpd data must
+// now be manipulated into the form required by Altera's
+// on-chip flash IP. Two operations must be performed.
+// First the data must be converted from bytes to 32-bit
+// words. Second the bit order must be reversed. This is
+// illustrated in in the following table which shows byte
+// address and data from the *.rpd file compared to the
+// word address and data to be written to the on-chip
+// flash.
+// {table border=1}
+// {tr}{td}.Map Addr{/td}{td}.Map Data{/td}{td}Flash Addr{/td}{td}Flash Data{/td}{/tr}
+// {tr}{td}0x2B800{/td}{td}0x01{/td}{td rowspan=4}0xAC00{/td}{td rowspan=4}0x8040C020{/td}{/tr}
+// {tr}{td}0x2B801{/td}{td}0x02{/td}{/tr}
+// {tr}{td}0x2B802{/td}{td}0x03{/td}{/tr}
+// {tr}{td}0x2B803{/td}{td}0x04{/td}{/tr}
+// {tr}{td}0x2B804{/td}{td}0x05{/td}{td rowspan=4}0xAC01{/td}{td rowspan=4}0xA060E010{/td}{/tr}
+// {tr}{td}0x2B805{/td}{td}0x06{/td}{/tr}
+// {tr}{td}0x2B806{/td}{td}0x07{/td}{/tr}
+// {tr}{td}0x2B807{/td}{td}0x08{/td}{/tr}
+// {/table}
+// {/p}{/li}
+// {li}{p}The resulting set of flash address data pairs should
+// be used when writing FLASH_ADDR_REG and
+// FLASH_WRITE_DATA_REG to update the CFM0 image.
+// However, prior to writing the new image the old image
+// must be erased.
+// {/p}{/li}
+// {/ol}
+// {/p}
+// {p}{b}Erase the current primary flash image...{/b}
+// {ol}{p}{li}Read FLASH_STATUS_REG and verify no error bits are
+// asserted and that all read, write, and erase operations
+// are idle.{/p}{/li}
+// {p}{li}Disable write protection of the flash by strobing the
+// FLASH_DISABLE_WP_STB bit of FLASH_CONTROL_REG.
+// {/p}{/li}
+// {p}{li}Verify write protection is disabled and no errors are
+// present by reading FLASH_STATUS_REG.{/p}{/li}
+// {p}{li}Initiate the erase operation by setting
+// @.FLASH_ERASE_SECTOR and strobing FLASH_ERASE_STB of
+// FLASH_CONTROL_REG.{/p}{/li}
+// {p}{li}Poll the FLASH_ERASE_IDLE bit of
+// FLASH_STATUS_REG until it de-asserts indicating the
+// erase operation is complete, then verify the operation
+// was successful by checking that the FLASH_ERASE_ERR
+// bit is de-asserted. Erase operations are expected to
+// take a maximum of 350 msec. Upon completion of the erase
+// operation write protection will remain disabled.
+// {/p}{/li}
+// {p}{li}Erase additional sectors as required (see
+// @.FLASH_ERASE_SECTOR for details) by restarting with first
+// step.{/p}{/li}
+// {/ol}
+// {/p}
+// {p}{b}Write the new primary flash image...{/b}
+// {ol}{p}{li}Read FLASH_STATUS_REG and verify no error bits are
+// asserted, all read, write, and erase operations are
+// idle, and write protection is disabled.{/li}
+// {p}{li}Set the target address for the write to the Max 10
+// on-chip flash by writing value from
+// FLASH_CFM0_START_ADDR_REG to FLASH_ADDR_REG.{/li}{/p}
+// {p}{li}Set the data to be written to this address by writing
+// the new 32-bit word of the new image to
+// FLASH_WRITE_DATA_REG.{/li}{/p}
+// {p}{li}Initiate the write by strobing FLASH_WRITE_STB of
+// FLASH_CONTROL_REG.{/li}{/p}
+// {p}{li}Poll the FLASH_WRITE_IDLE bit of
+// FLASH_STATUS_REG until it de-asserts indicating the
+// write operation is complete, then verify the operation
+// was successful by checking that the FLASH_WRITE_ERR
+// bit is de-asserted. Write operations are expected to
+// take a maximum of 550 usec.{/li}{/p}
+// {p}{li}Upon completion of the write operation return to step
+// 2, incrementing the target address by one, and writing
+// the next 32-bit word to Max10FlashWriteDatReg. If this
+// was the last write, indicated by writing to
+// FLASH_PRIMARY_IMAGE_END_ADDR, proceed to the next step
+// to enable write protection.{/li}{/p}
+// {p}{li}After writing the new image enable write protection
+// by strobing the FLASH_ENABLE_WP_STB bit of
+// FLASH_CONTROL_REG.{/li}{/p}
+// {/ol}
+// {/p}
+// {p}{b}Verify the new primary flash image...{/b}
+// {ol}{p}{li}Read FLASH_STATUS_REG and verify no error bits are
+// asserted and that all read, write, and erase operations
+// are idle.{/li}{/p}
+// {p}{li}Set the target address for the read in the Max 10
+// on-chip flash by writing value from
+// FLASH_CFM0_START_ADDR_REG to FLASH_ADDR_REG.{/li}{/p}
+// {p}{li}Initiate the read by strobing FLASH_READ_STB of
+// FLASH_CONTROL_REG.{/li}{/p}
+// {p}{li}Poll the FLASH_READ_IDLE bit of
+// FLASH_STATUS_REG until it de-asserts indicating the
+// read operation is complete, then verify the operation
+// was successful by checking that the FLASH_READ_ERR
+// bit is de-asserted. There is no guidance on exactly how
+// long reads take to complete, but they are expected to be
+// fairly quick. A very conservative timeout on this
+// polling would be similar to that used for write
+// operations.{/li}{/p}
+// {p}{li}Upon completion of the read operation the resulting
+// data returned by the on-chip flash will be available in
+// Max10FlashReadDatReg. Read this register, compare to
+// expected value previously written, and ensure they
+// match.{/li}{/p}
+// {p}{li}Return to step 2, incrementing the target
+// address by one. If this was the last read verification
+// is complete and no further action is required.{/li}{/p}
+// {/ol}
+// {/p}
+// {p}After the flash has been erased, programmed, and verified, a power
+// cycle is required for the new image to become active.
+// {/p}
+// </info>
+// <enumeratedtype name="FLASH_PRIMARY_IMAGE_ADDR_ENUM" showhexvalue="true">
+// <info>
+// Those values are the start and end address of the CFM image flash
+// sector from Intel's On-Chip Flash IP Generator. Note that the values
+// given in the IP generator are byte based where the values of this enum
+// are U32 based (divided by 4).
+// </info>
+// <value name="FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT"
+// integer="4096"/>
+// <value name="FLASH_PRIMARY_IMAGE_START_ADDR"
+// integer="39936"/>
+// <value name="FLASH_PRIMARY_IMAGE_END_ADDR"
+// integer="75775"/>
+// </enumeratedtype>
+// <register name="FLASH_STATUS_REG" offset="0x000" size="32"
+// attributes="Readable">
+// <bitfield name="FLASH_WP_ENABLED" range="0">
+// <info>
+// This bit is asserted when the flash is write protected and
+// de-asserted when write protection is disabled.
+// {li}Write protection must be enabled prior to performing read
+// operations.{/li}
+// {li}Write protection must be disabled prior to performing write and
+// erase operations.{/li}
+// </info>
+// </bitfield>
+// <bitfield name="FLASH_READ_IDLE" range="4">
+// <info>
+// This bit is de-asserted when a read operation is in progress. Poll
+// this bit after strobing the FLASH_READ_STB bit of
+// FLASH_CONTROL_REG to determine when the read operation has
+// completed, then check the FLASH_READ_ERR bit to verify the
+// operation was successful.
+// </info>
+// </bitfield>
+// <bitfield name="FLASH_READ_ERR" range="5">
+// <info>
+// This bit is asserted when a read operation fails. Clear this error
+// by strobing the CLEAR_FLASH_READ_ERROR_STB of this register. In the
+// event of a read error...
+// {li}the data in FLASH_READ_DATA_REG is invalid.{/li}
+// {li}attempts to disable write protection will be ignored.{/li}
+// {li}attempts to read/write/erase the flash will be ignored.{/li}
+// </info>
+// </bitfield>
+// <bitfield name="FLASH_ERASE_IDLE" range="8">
+// <info>
+// This bit is de-asserted when an erase operation is in progress. Poll
+// this bit after strobing the FLASH_ERASE_STB bit of
+// FLASH_CONTROL_REG to determine when the erase operation has
+// completed, then check the FLASH_ERASE_ERR bit to verify the
+// operation was successful.
+// </info>
+// </bitfield>
+// <bitfield name="FLASH_ERASE_ERR" range="9">
+// <info>
+// This bit is asserted when an erase operation fails. Clear this
+// error by strobing CLEAR_FLASH_ERASE_ERROR_STB of this register. In
+// the event of an erase error...
+// {li}{b}the primary configuration image may be corrupted,{/b} and
+// power cycling the board may result in unknown behavior.{/li}
+// {li}write protection of the flash will automatically be
+// re-enabled.{/li}
+// {li}attempts to disable write protection will be ignored.{/li}
+// {li}attempts to read/write/erase the flash will be ignored.{/li}
+// </info>
+// </bitfield>
+// <bitfield name="FLASH_WRITE_IDLE" range="12">
+// <info>
+// This bit is de-asserted when a write operation is in progress. Poll
+// this bit after strobing the FLASH_WRITE_STB bit of
+// FLASH_CONTROL_REG to determine when the write operation has
+// completed, then check the FLASH_WRITE_ERR bit to verify the
+// operation was successful.
+// </info>
+// </bitfield>
+// <bitfield name="FLASH_WRITE_ERR" range="13">
+// <info>
+// This bit is asserted when write operation fails. Clear this error
+// by strobing the CLEAR_FLASH_WRITE_ERROR_STB bit of this register. In
+// the event of a write error...
+// {li}{b}the primary configuration image may be corrupted,{/b} and
+// power cycling the board may result unknown behavior.{/li}
+// {li}write protection of the flash will automatically be
+// re-enabled.{/li}
+// {li}attempts to disable write protection will be ignored.{/li}
+// {li}attempts to read/write/erase the flash will be ignored.{/li}
+// </info>
+// </bitfield>
+// <bitfield name="FLASH_MEM_INIT_ENABLED" range="16">
+// <info>
+// This bit is asserted when the flash can hold an image with memory
+// initialization.
+// </info>
+// </bitfield>
+// </register>
+// <register name="FLASH_CONTROL_REG" offset="0x04" size="32"
+// attributes="Writable">
+// <bitfield name="FLASH_ENABLE_WP_STB" range="0"
+// attributes="strobe">
+// <info>
+// Strobe this bit to enable write protection to the section of the
+// Max 10 on-chip flash storing the primary configuration image
+// (CFM0).
+// {li}Read the FLASH_WP_ENABLED bit of FLASH_STATUS_REG to
+// determine the current state of write protection.{/li}
+// {li}Prior to strobing this bit verify no write or erase operations
+// are in progress and no error bits are asserted by reading
+// FLASH_STATUS_REG.{/li}
+// {li}Attempts to enable write protection while erase or write
+// operations are in progress will be ignored.{/li}
+// {li}Write protection must be enabled prior to performing
+// read operations.{/li}
+// {li}Write protection should be enabled after completing
+// write or erase operations to prevent data corruption.{/li}
+// </info>
+// </bitfield>
+// <bitfield name="FLASH_DISABLE_WP_STB" range="1"
+// attributes="strobe">
+// <info>
+// Strobe this bit to disable write protection to the section of the
+// Max 10 on-chip flash storing the primary configuration image
+// (CFM0).
+// {li}Read the FLASH_WP_ENABLED bit of FLASH_STATUS_REG to
+// determine the current state of write protection.{/li}
+// {li}Prior to strobing this bit verify no read operations are in
+// progress and no error bits are asserted by reading
+// FLASH_STATUS_REG.{/li}
+// {li}Attempts to disable write protection while a read is in
+// progress will be ignored.{/li}
+// {li}Attempts to disable write protection will be ignored if
+// this bit is strobed simultaneously with either FLASH_READ_STB
+// or FLASH_ENABLE_WP_STB.{/li}
+// {li}Write protection must be disabled prior to performing erase or
+// write operations.{/li}
+// {li}Upon completion of erase/write operations write protection
+// will remain disabled. When not actively erasing or writing a new
+// image write protection should be enabled to avoid data
+// corruption.{/li}
+// </info>
+// </bitfield>
+// <bitfield name="FLASH_READ_STB" range="2"
+// attributes="strobe">
+// <info>
+// Strobe this bit to read data from the flash address identified in
+// FLASH_ADDR_REG.
+// {li}Prior to strobing this bit verify no read, write, or erase
+// operations are in progress, no error bits are asserted, and
+// write protection is enabled by reading FLASH_STATUS_REG.{/li}
+// {li}Attempts to read data while other operations are in progress
+// or while write protection is disabled will be ignored.{/li}
+// {li}After strobing this bit poll the FLASH_READ_IDLE and
+// FLASH_READ_ERR bits of FLASH_STATUS_REG to determine when
+// the read operation is complete and if it was successful.{/li}
+// {li}Upon successful completion the data read from flash will be
+// available in FLASH_READ_DATA_REG.{/li}
+// </info>
+// </bitfield>
+// <bitfield name="FLASH_WRITE_STB" range="3"
+// attributes="strobe">
+// <info>
+// Strobe this bit to write the data contained in
+// FLASH_WRITE_DATA_REG to the flash address identified in
+// FLASH_ADDR_REG.
+// {li}The flash must be erased before writing new data.{/li}
+// {li}Prior to strobing this bit verify write protection is
+// disabled, no other write or erase operations are in progress, and
+// no error bits are asserted by reading FLASH_STATUS_REG.{/li}
+// {li}Attempts to write data while other write or erase operations
+// are in progress will be ignored.{/li}
+// {li}Attempts to write data with write protection enabled will be
+// ignored.{/li}
+// {li}Strobing this bit and FLASH_ERASE_STB simultaneously will
+// result in both the write and erase operation being ignored,
+// both corresponding error bits being set, and write protection
+// being re-enabled.{/li}
+// {li}After strobing this bit poll theMax10FlashWriteIdle and
+// FLASH_WRITE_ERR bits of FLASH_STATUS_REG to determine when
+// the write operation is complete and if it was successful.{/li}
+// </info>
+// </bitfield>
+// <bitfield name="FLASH_ERASE_STB" range="4"
+// attributes="strobe">
+// <info>
+// Strobe this bit to erase the primary Max10 configuration image
+// (CFM0).
+// {li}Prior to strobing this bit verify no other write or erase
+// operations are in progress, write protection is disabled, and no
+// error bits are asserted by reading FLASH_STATUS_REG.{/li}
+// {li}Attempts to erase the primary image while other write or erase
+// operations are in progress will be ignored.
+// {li}Attempts to erase the primary image when write protection is
+// enabled will be ignored.{/li}
+// {li}Strobing this bit and FLASH_WRITE_STB simultaneously will
+// result both the erase and the write operation being ignored, both
+// corresponding error bits being set, and write protection being
+// re-enabled.{/li}
+// {li}After strobing this bit poll the FLASH_ERASE_IDLE and
+// FLASH_ERASE_ERR bits of FLASH_STATUS_REG to determine when
+// the erase operation is complete and if it was successful.{/li}
+// </info>
+// </bitfield>
+// <bitfield name="FLASH_ERASE_SECTOR" range="7..5"
+// attributes="strobe">
+// <info>
+// Defines the sector to be erased. Has to be set latest with the
+// write access which starts the erase operation by strobing
+// @.FLASH_ERASE_STB.{br}
+// If the flash is configured to support memory initialization (see
+// @.FLASH_MEM_INIT_ENABLED flag) the sectors 2 to 4 have to be erased.
+// If the flag is not asserted only sector 4 has to be erased.
+// </info>
+// </bitfield>
+// <bitfield name="CLEAR_FLASH_READ_ERROR_STB" range="8"
+// attributes="strobe">
+// <info>
+// Strobe this bit to clear a read error.
+// </info>
+// </bitfield>
+// <bitfield name="CLEAR_FLASH_WRITE_ERROR_STB" range="9"
+// attributes="strobe">
+// <info>
+// Strobe this bit to clear a write error.
+// </info>
+// </bitfield>
+// <bitfield name="CLEAR_FLASH_ERASE_ERROR_STB" range="10"
+// attributes="strobe">
+// <info>
+// Strobe this bit to clear an erase error.
+// </info>
+// </bitfield>
+// </register>
+// <register name="FLASH_ADDR_REG" offset="0x08" size="32"
+// attributes="Readable|Writable">
+// <bitfield name="FLASH_ADDR" range="16..0">
+// <info>
+// This field holds the target address for the next read or
+// write operation. Set this field prior to strobing the
+// FLASH_WRITE_STB and FLASH_READ_STB bits of
+// FLASH_CONTROL_REG. Valid addresses are defined by the
+// FLASH_PRIMARY_IMAGE_ADDR_ENUM enumeration.
+// </info>
+// </bitfield>
+// </register>
+// <register name="FLASH_WRITE_DATA_REG" offset="0x0C" size="32"
+// attributes="Writable">
+// <bitfield name="FLASH_WRITE_DATA" range="31..0">
+// <info>
+// Data in this register will be written to the flash at the address
+// identified in FLASH_ADDR_REG when a successful write operation
+// is executed.
+// </info>
+// </bitfield>
+// </register>
+// <register name="FLASH_READ_DATA_REG" offset="0x10" size="32"
+// attributes="Readable">
+// <bitfield name="FLASH_READ_DATA" range="31..0">
+// <info>
+// This register contains data read from the flash address identified
+// in FLASH_ADDR_REG after a successful read operation is executed.
+// </info>
+// </bitfield>
+// </register>
+// <register name="FLASH_CFM0_START_ADDR_REG" offset="0x14" size="32"
+// attributes="Readable">
+// <bitfield name="FLASH_CFM0_START_ADDR" range="31..0">
+// <info>
+// Start address of CFM0 image within flash memory (as defined in FLASH_PRIMARY_IMAGE_ADDR_ENUM).
+// </info>
+// </bitfield>
+// </register>
+// <register name="FLASH_CFM0_END_ADDR_REG" offset="0x18" size="32"
+// attributes="Readable">
+// <bitfield name="FLASH_CFM0_END_ADDR" range="31..0">
+// <info>
+// Last address of CFM0 image within flash memory (as defined in FLASH_PRIMARY_IMAGE_ADDR_ENUM).
+// </info>
+// </bitfield>
+// </register>
+// </group>
+//</regmap>
+//XmlParse xml_off
diff --git a/fpga/usrp3/top/x400/cpld/regmap/constants_regmap_utils.vh b/fpga/usrp3/top/x400/cpld/regmap/constants_regmap_utils.vh
new file mode 100644
index 000000000..4e5921f4c
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/regmap/constants_regmap_utils.vh
@@ -0,0 +1,28 @@
+//
+// Copyright 2021 Ettus Research, A National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: constants_regmap_utils.vh
+// Description:
+// The constants in this file are autogenerated by XmlParse.
+
+//===============================================================================
+// A numerically ordered list of registers and their HDL source files
+//===============================================================================
+
+
+//===============================================================================
+// RegTypes
+//===============================================================================
+
+//===============================================================================
+// Register Group CONSTANTS_GROUP
+//===============================================================================
+
+ // Enumerated type CONSTANTS_ENUM
+ localparam CONSTANTS_ENUM_SIZE = 4;
+ localparam PS_CPLD_SIGNATURE = 'hA522D27; // CONSTANTS_ENUM:PS_CPLD_SIGNATURE
+ localparam OLDEST_CPLD_REVISION = 'h20122114; // CONSTANTS_ENUM:OLDEST_CPLD_REVISION
+ localparam CPLD_REVISION = 'h21012015; // CONSTANTS_ENUM:CPLD_REVISION
+ localparam PL_CPLD_SIGNATURE = 'h3FDC5C47; // CONSTANTS_ENUM:PL_CPLD_SIGNATURE
diff --git a/fpga/usrp3/top/x400/cpld/regmap/jtag_regmap_utils.vh b/fpga/usrp3/top/x400/cpld/regmap/jtag_regmap_utils.vh
new file mode 100644
index 000000000..f57e28ea9
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/regmap/jtag_regmap_utils.vh
@@ -0,0 +1,57 @@
+//
+// Copyright 2021 Ettus Research, A National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: jtag_regmap_utils.vh
+// Description:
+// The constants in this file are autogenerated by XmlParse.
+
+//===============================================================================
+// A numerically ordered list of registers and their HDL source files
+//===============================================================================
+
+ // TX_DATA : 0x0 (ctrlport_to_jtag.v)
+ // STB_DATA : 0x4 (ctrlport_to_jtag.v)
+ // CONTROL : 0x8 (ctrlport_to_jtag.v)
+ // RX_DATA : 0xC (ctrlport_to_jtag.v)
+
+//===============================================================================
+// RegTypes
+//===============================================================================
+
+//===============================================================================
+// Register Group JTAG_REGS
+//===============================================================================
+
+ // TX_DATA Register (from ctrlport_to_jtag.v)
+ localparam TX_DATA = 'h0; // Register Offset
+ localparam TX_DATA_SIZE = 32; // register width in bits
+ localparam TX_DATA_MASK = 32'h0;
+
+ // STB_DATA Register (from ctrlport_to_jtag.v)
+ localparam STB_DATA = 'h4; // Register Offset
+ localparam STB_DATA_SIZE = 32; // register width in bits
+ localparam STB_DATA_MASK = 32'h0;
+
+ // CONTROL Register (from ctrlport_to_jtag.v)
+ localparam CONTROL = 'h8; // Register Offset
+ localparam CONTROL_SIZE = 32; // register width in bits
+ localparam CONTROL_MASK = 32'h80001FFF;
+ localparam PRESCALAR_SIZE = 8; //CONTROL:prescalar
+ localparam PRESCALAR_MSB = 7; //CONTROL:prescalar
+ localparam PRESCALAR = 0; //CONTROL:prescalar
+ localparam LENGTH_SIZE = 5; //CONTROL:length
+ localparam LENGTH_MSB = 12; //CONTROL:length
+ localparam LENGTH = 8; //CONTROL:length
+ localparam RESET_SIZE = 1; //CONTROL:reset
+ localparam RESET_MSB = 31; //CONTROL:reset
+ localparam RESET = 31; //CONTROL:reset
+ localparam READY_SIZE = 1; //CONTROL:ready
+ localparam READY_MSB = 31; //CONTROL:ready
+ localparam READY = 31; //CONTROL:ready
+
+ // RX_DATA Register (from ctrlport_to_jtag.v)
+ localparam RX_DATA = 'hC; // Register Offset
+ localparam RX_DATA_SIZE = 32; // register width in bits
+ localparam RX_DATA_MASK = 32'h0;
diff --git a/fpga/usrp3/top/x400/cpld/regmap/mb_cpld_pl_regmap_utils.vh b/fpga/usrp3/top/x400/cpld/regmap/mb_cpld_pl_regmap_utils.vh
new file mode 100644
index 000000000..d70590690
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/regmap/mb_cpld_pl_regmap_utils.vh
@@ -0,0 +1,36 @@
+//
+// Copyright 2021 Ettus Research, A National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: mb_cpld_pl_regmap_utils.vh
+// Description:
+// The constants in this file are autogenerated by XmlParse.
+
+//===============================================================================
+// A numerically ordered list of registers and their HDL source files
+//===============================================================================
+
+ // PL_REGISTERS : 0x0 (mb_cpld.v)
+ // JTAG_DB0 : 0x60 (mb_cpld.v)
+ // JTAG_DB1 : 0x80 (mb_cpld.v)
+
+//===============================================================================
+// RegTypes
+//===============================================================================
+
+//===============================================================================
+// Register Group MB_CPLD_PL_WINDOWS
+//===============================================================================
+
+ // PL_REGISTERS Window (from mb_cpld.v)
+ localparam PL_REGISTERS = 'h0; // Window Offset
+ localparam PL_REGISTERS_SIZE = 'h40; // size in bytes
+
+ // JTAG_DB0 Window (from mb_cpld.v)
+ localparam JTAG_DB0 = 'h60; // Window Offset
+ localparam JTAG_DB0_SIZE = 'h20; // size in bytes
+
+ // JTAG_DB1 Window (from mb_cpld.v)
+ localparam JTAG_DB1 = 'h80; // Window Offset
+ localparam JTAG_DB1_SIZE = 'h20; // size in bytes
diff --git a/fpga/usrp3/top/x400/cpld/regmap/mb_cpld_ps_regmap_utils.vh b/fpga/usrp3/top/x400/cpld/regmap/mb_cpld_ps_regmap_utils.vh
new file mode 100644
index 000000000..9eb044c10
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/regmap/mb_cpld_ps_regmap_utils.vh
@@ -0,0 +1,51 @@
+//
+// Copyright 2021 Ettus Research, A National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: mb_cpld_ps_regmap_utils.vh
+// Description:
+// The constants in this file are autogenerated by XmlParse.
+
+//===============================================================================
+// A numerically ordered list of registers and their HDL source files
+//===============================================================================
+
+ // PS_REGISTERS : 0x0 (mb_cpld.v)
+ // RECONFIG : 0x40 (mb_cpld.v)
+ // POWER_REGISTERS : 0x60 (mb_cpld.v)
+
+//===============================================================================
+// RegTypes
+//===============================================================================
+
+//===============================================================================
+// Register Group MB_CPLD_PS_WINDOWS
+//===============================================================================
+
+ // PS_REGISTERS Window (from mb_cpld.v)
+ localparam PS_REGISTERS = 'h0; // Window Offset
+ localparam PS_REGISTERS_SIZE = 'h40; // size in bytes
+
+ // RECONFIG Window (from mb_cpld.v)
+ localparam RECONFIG = 'h40; // Window Offset
+ localparam RECONFIG_SIZE = 'h20; // size in bytes
+
+ // POWER_REGISTERS Window (from mb_cpld.v)
+ localparam POWER_REGISTERS = 'h60; // Window Offset
+ localparam POWER_REGISTERS_SIZE = 'h20; // size in bytes
+
+//===============================================================================
+// Register Group PS_SPI_ENDPOINTS
+//===============================================================================
+
+ // Enumerated type SPI_ENDPOINT
+ localparam SPI_ENDPOINT_SIZE = 8;
+ localparam PS_CS_MB_CPLD = 'h0; // SPI_ENDPOINT:PS_CS_MB_CPLD
+ localparam PS_CS_LMK32 = 'h1; // SPI_ENDPOINT:PS_CS_LMK32
+ localparam PS_CS_TPM = 'h2; // SPI_ENDPOINT:PS_CS_TPM
+ localparam PS_CS_PHASE_DAC = 'h3; // SPI_ENDPOINT:PS_CS_PHASE_DAC
+ localparam PS_CS_DB0_CAL_EEPROM = 'h4; // SPI_ENDPOINT:PS_CS_DB0_CAL_EEPROM
+ localparam PS_CS_DB1_CAL_EEPROM = 'h5; // SPI_ENDPOINT:PS_CS_DB1_CAL_EEPROM
+ localparam PS_CS_CLK_AUX_DB = 'h6; // SPI_ENDPOINT:PS_CS_CLK_AUX_DB
+ localparam PS_CS_IDLE = 'h7; // SPI_ENDPOINT:PS_CS_IDLE
diff --git a/fpga/usrp3/top/x400/cpld/regmap/pl_cpld_base_regmap_utils.vh b/fpga/usrp3/top/x400/cpld/regmap/pl_cpld_base_regmap_utils.vh
new file mode 100644
index 000000000..820216d71
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/regmap/pl_cpld_base_regmap_utils.vh
@@ -0,0 +1,122 @@
+//
+// Copyright 2021 Ettus Research, A National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: pl_cpld_base_regmap_utils.vh
+// Description:
+// The constants in this file are autogenerated by XmlParse.
+
+//===============================================================================
+// A numerically ordered list of registers and their HDL source files
+//===============================================================================
+
+ // SIGNATURE_REGISTER : 0x0 (pl_cpld_regs.v)
+ // REVISION_REGISTER : 0x4 (pl_cpld_regs.v)
+ // OLDEST_COMPATIBLE_REVISION_REGISTER : 0x8 (pl_cpld_regs.v)
+ // SCRATCH_REGISTER : 0xC (pl_cpld_regs.v)
+ // GIT_HASH_REGISTER : 0x10 (pl_cpld_regs.v)
+ // LED_REGISTER : 0x20 (pl_cpld_regs.v)
+ // CABLE_PRESENT_REG : 0x30 (pl_cpld_regs.v)
+
+//===============================================================================
+// RegTypes
+//===============================================================================
+
+//===============================================================================
+// Register Group MB_CPLD_LED_REGS
+//===============================================================================
+
+ // LED_REGISTER Register (from pl_cpld_regs.v)
+ localparam LED_REGISTER = 'h20; // Register Offset
+ localparam LED_REGISTER_SIZE = 16; // register width in bits
+ localparam LED_REGISTER_MASK = 16'hFFFF;
+ localparam QSFP0_LED_LINK_SIZE = 4; //LED_REGISTER:QSFP0_LED_LINK
+ localparam QSFP0_LED_LINK_MSB = 3; //LED_REGISTER:QSFP0_LED_LINK
+ localparam QSFP0_LED_LINK = 0; //LED_REGISTER:QSFP0_LED_LINK
+ localparam QSFP0_LED_ACTIVE_SIZE = 4; //LED_REGISTER:QSFP0_LED_ACTIVE
+ localparam QSFP0_LED_ACTIVE_MSB = 7; //LED_REGISTER:QSFP0_LED_ACTIVE
+ localparam QSFP0_LED_ACTIVE = 4; //LED_REGISTER:QSFP0_LED_ACTIVE
+ localparam QSFP1_LED_LINK_SIZE = 4; //LED_REGISTER:QSFP1_LED_LINK
+ localparam QSFP1_LED_LINK_MSB = 11; //LED_REGISTER:QSFP1_LED_LINK
+ localparam QSFP1_LED_LINK = 8; //LED_REGISTER:QSFP1_LED_LINK
+ localparam QSFP1_LED_ACTIVE_SIZE = 4; //LED_REGISTER:QSFP1_LED_ACTIVE
+ localparam QSFP1_LED_ACTIVE_MSB = 15; //LED_REGISTER:QSFP1_LED_ACTIVE
+ localparam QSFP1_LED_ACTIVE = 12; //LED_REGISTER:QSFP1_LED_ACTIVE
+
+//===============================================================================
+// Register Group PL_CMI_REGS
+//===============================================================================
+
+ // CABLE_PRESENT_REG Register (from pl_cpld_regs.v)
+ localparam CABLE_PRESENT_REG = 'h30; // Register Offset
+ localparam CABLE_PRESENT_REG_SIZE = 2; // register width in bits
+ localparam CABLE_PRESENT_REG_MASK = 2'h3;
+ localparam IPASS0_CABLE_PRESENT_SIZE = 1; //CABLE_PRESENT_REG:IPASS0_CABLE_PRESENT
+ localparam IPASS0_CABLE_PRESENT_MSB = 0; //CABLE_PRESENT_REG:IPASS0_CABLE_PRESENT
+ localparam IPASS0_CABLE_PRESENT = 0; //CABLE_PRESENT_REG:IPASS0_CABLE_PRESENT
+ localparam IPASS1_CABLE_PRESENT_SIZE = 1; //CABLE_PRESENT_REG:IPASS1_CABLE_PRESENT
+ localparam IPASS1_CABLE_PRESENT_MSB = 1; //CABLE_PRESENT_REG:IPASS1_CABLE_PRESENT
+ localparam IPASS1_CABLE_PRESENT = 1; //CABLE_PRESENT_REG:IPASS1_CABLE_PRESENT
+
+//===============================================================================
+// Register Group PL_CPLD_BASE_REGS
+//===============================================================================
+
+ // SIGNATURE_REGISTER Register (from pl_cpld_regs.v)
+ localparam SIGNATURE_REGISTER = 'h0; // Register Offset
+ localparam SIGNATURE_REGISTER_SIZE = 32; // register width in bits
+ localparam SIGNATURE_REGISTER_MASK = 32'hFFFFFFFF;
+ localparam PRODUCT_SIGNATURE_SIZE = 32; //SIGNATURE_REGISTER:PRODUCT_SIGNATURE
+ localparam PRODUCT_SIGNATURE_MSB = 31; //SIGNATURE_REGISTER:PRODUCT_SIGNATURE
+ localparam PRODUCT_SIGNATURE = 0; //SIGNATURE_REGISTER:PRODUCT_SIGNATURE
+
+ // REVISION_REGISTER Register (from pl_cpld_regs.v)
+ localparam REVISION_REGISTER = 'h4; // Register Offset
+ localparam REVISION_REGISTER_SIZE = 32; // register width in bits
+ localparam REVISION_REGISTER_MASK = 32'hFFFFFFFF;
+ localparam REVISION_HH_SIZE = 8; //REVISION_REGISTER:REVISION_HH
+ localparam REVISION_HH_MSB = 7; //REVISION_REGISTER:REVISION_HH
+ localparam REVISION_HH = 0; //REVISION_REGISTER:REVISION_HH
+ localparam REVISION_DD_SIZE = 8; //REVISION_REGISTER:REVISION_DD
+ localparam REVISION_DD_MSB = 15; //REVISION_REGISTER:REVISION_DD
+ localparam REVISION_DD = 8; //REVISION_REGISTER:REVISION_DD
+ localparam REVISION_MM_SIZE = 8; //REVISION_REGISTER:REVISION_MM
+ localparam REVISION_MM_MSB = 23; //REVISION_REGISTER:REVISION_MM
+ localparam REVISION_MM = 16; //REVISION_REGISTER:REVISION_MM
+ localparam REVISION_YY_SIZE = 8; //REVISION_REGISTER:REVISION_YY
+ localparam REVISION_YY_MSB = 31; //REVISION_REGISTER:REVISION_YY
+ localparam REVISION_YY = 24; //REVISION_REGISTER:REVISION_YY
+
+ // OLDEST_COMPATIBLE_REVISION_REGISTER Register (from pl_cpld_regs.v)
+ localparam OLDEST_COMPATIBLE_REVISION_REGISTER = 'h8; // Register Offset
+ localparam OLDEST_COMPATIBLE_REVISION_REGISTER_SIZE = 32; // register width in bits
+ localparam OLDEST_COMPATIBLE_REVISION_REGISTER_MASK = 32'hFFFFFFFF;
+ localparam OLD_REVISION_HH_SIZE = 8; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_HH
+ localparam OLD_REVISION_HH_MSB = 7; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_HH
+ localparam OLD_REVISION_HH = 0; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_HH
+ localparam OLD_REVISION_DD_SIZE = 8; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_DD
+ localparam OLD_REVISION_DD_MSB = 15; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_DD
+ localparam OLD_REVISION_DD = 8; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_DD
+ localparam OLD_REVISION_MM_SIZE = 8; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_MM
+ localparam OLD_REVISION_MM_MSB = 23; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_MM
+ localparam OLD_REVISION_MM = 16; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_MM
+ localparam OLD_REVISION_YY_SIZE = 8; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_YY
+ localparam OLD_REVISION_YY_MSB = 31; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_YY
+ localparam OLD_REVISION_YY = 24; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_YY
+
+ // SCRATCH_REGISTER Register (from pl_cpld_regs.v)
+ localparam SCRATCH_REGISTER = 'hC; // Register Offset
+ localparam SCRATCH_REGISTER_SIZE = 32; // register width in bits
+ localparam SCRATCH_REGISTER_MASK = 32'h0;
+
+ // GIT_HASH_REGISTER Register (from pl_cpld_regs.v)
+ localparam GIT_HASH_REGISTER = 'h10; // Register Offset
+ localparam GIT_HASH_REGISTER_SIZE = 32; // register width in bits
+ localparam GIT_HASH_REGISTER_MASK = 32'hFFFFFFFF;
+ localparam GIT_HASH_SIZE = 28; //GIT_HASH_REGISTER:GIT_HASH
+ localparam GIT_HASH_MSB = 27; //GIT_HASH_REGISTER:GIT_HASH
+ localparam GIT_HASH = 0; //GIT_HASH_REGISTER:GIT_HASH
+ localparam GIT_CLEAN_SIZE = 4; //GIT_HASH_REGISTER:GIT_CLEAN
+ localparam GIT_CLEAN_MSB = 31; //GIT_HASH_REGISTER:GIT_CLEAN
+ localparam GIT_CLEAN = 28; //GIT_HASH_REGISTER:GIT_CLEAN
diff --git a/fpga/usrp3/top/x400/cpld/regmap/ps_cpld_base_regmap_utils.vh b/fpga/usrp3/top/x400/cpld/regmap/ps_cpld_base_regmap_utils.vh
new file mode 100644
index 000000000..a5a067bb4
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/regmap/ps_cpld_base_regmap_utils.vh
@@ -0,0 +1,183 @@
+//
+// Copyright 2021 Ettus Research, A National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: ps_cpld_base_regmap_utils.vh
+// Description:
+// The constants in this file are autogenerated by XmlParse.
+
+//===============================================================================
+// A numerically ordered list of registers and their HDL source files
+//===============================================================================
+
+ // SIGNATURE_REGISTER : 0x0 (ps_cpld_regs.v)
+ // REVISION_REGISTER : 0x4 (ps_cpld_regs.v)
+ // OLDEST_COMPATIBLE_REVISION_REGISTER : 0x8 (ps_cpld_regs.v)
+ // SCRATCH_REGISTER : 0xC (ps_cpld_regs.v)
+ // GIT_HASH_REGISTER : 0x10 (ps_cpld_regs.v)
+ // PL_DB_REGISTER : 0x20 (ps_cpld_regs.v)
+ // DIO_DIRECTION_REGISTER : 0x30 (ps_cpld_regs.v)
+ // SERIAL_NUM_LOW_REG : 0x34 (ps_cpld_regs.v)
+ // SERIAL_NUM_HIGH_REG : 0x38 (ps_cpld_regs.v)
+ // CMI_CONTROL_STATUS : 0x3C (ps_cpld_regs.v)
+
+//===============================================================================
+// RegTypes
+//===============================================================================
+
+//===============================================================================
+// Register Group DIO_REGS
+//===============================================================================
+
+ // DIO_DIRECTION_REGISTER Register (from ps_cpld_regs.v)
+ localparam DIO_DIRECTION_REGISTER = 'h30; // Register Offset
+ localparam DIO_DIRECTION_REGISTER_SIZE = 32; // register width in bits
+ localparam DIO_DIRECTION_REGISTER_MASK = 32'hFFF0FFF;
+ localparam DIO_DIRECTION_A_SIZE = 12; //DIO_DIRECTION_REGISTER:DIO_DIRECTION_A
+ localparam DIO_DIRECTION_A_MSB = 11; //DIO_DIRECTION_REGISTER:DIO_DIRECTION_A
+ localparam DIO_DIRECTION_A = 0; //DIO_DIRECTION_REGISTER:DIO_DIRECTION_A
+ localparam DIO_DIRECTION_B_SIZE = 12; //DIO_DIRECTION_REGISTER:DIO_DIRECTION_B
+ localparam DIO_DIRECTION_B_MSB = 27; //DIO_DIRECTION_REGISTER:DIO_DIRECTION_B
+ localparam DIO_DIRECTION_B = 16; //DIO_DIRECTION_REGISTER:DIO_DIRECTION_B
+
+//===============================================================================
+// Register Group PS_CMI_REGS
+//===============================================================================
+
+ // SERIAL_NUM_LOW_REG Register (from ps_cpld_regs.v)
+ localparam SERIAL_NUM_LOW_REG = 'h34; // Register Offset
+ localparam SERIAL_NUM_LOW_REG_SIZE = 32; // register width in bits
+ localparam SERIAL_NUM_LOW_REG_MASK = 32'h0;
+
+ // SERIAL_NUM_HIGH_REG Register (from ps_cpld_regs.v)
+ localparam SERIAL_NUM_HIGH_REG = 'h38; // Register Offset
+ localparam SERIAL_NUM_HIGH_REG_SIZE = 8; // register width in bits
+ localparam SERIAL_NUM_HIGH_REG_MASK = 8'h0;
+
+ // CMI_CONTROL_STATUS Register (from ps_cpld_regs.v)
+ localparam CMI_CONTROL_STATUS = 'h3C; // Register Offset
+ localparam CMI_CONTROL_STATUS_SIZE = 32; // register width in bits
+ localparam CMI_CONTROL_STATUS_MASK = 32'h80000001;
+ localparam CMI_READY_SIZE = 1; //CMI_CONTROL_STATUS:CMI_READY
+ localparam CMI_READY_MSB = 0; //CMI_CONTROL_STATUS:CMI_READY
+ localparam CMI_READY = 0; //CMI_CONTROL_STATUS:CMI_READY
+ localparam OTHER_SIDE_DETECTED_SIZE = 1; //CMI_CONTROL_STATUS:OTHER_SIDE_DETECTED
+ localparam OTHER_SIDE_DETECTED_MSB = 31; //CMI_CONTROL_STATUS:OTHER_SIDE_DETECTED
+ localparam OTHER_SIDE_DETECTED = 31; //CMI_CONTROL_STATUS:OTHER_SIDE_DETECTED
+
+//===============================================================================
+// Register Group PS_CONTROL_REGS
+//===============================================================================
+
+ // PL_DB_REGISTER Register (from ps_cpld_regs.v)
+ localparam PL_DB_REGISTER = 'h20; // Register Offset
+ localparam PL_DB_REGISTER_SIZE = 32; // register width in bits
+ localparam PL_DB_REGISTER_MASK = 32'h337737;
+ localparam DB0_CLOCK_ENABLED_SIZE = 1; //PL_DB_REGISTER:DB0_CLOCK_ENABLED
+ localparam DB0_CLOCK_ENABLED_MSB = 0; //PL_DB_REGISTER:DB0_CLOCK_ENABLED
+ localparam DB0_CLOCK_ENABLED = 0; //PL_DB_REGISTER:DB0_CLOCK_ENABLED
+ localparam DB1_CLOCK_ENABLED_SIZE = 1; //PL_DB_REGISTER:DB1_CLOCK_ENABLED
+ localparam DB1_CLOCK_ENABLED_MSB = 1; //PL_DB_REGISTER:DB1_CLOCK_ENABLED
+ localparam DB1_CLOCK_ENABLED = 1; //PL_DB_REGISTER:DB1_CLOCK_ENABLED
+ localparam PLL_REF_CLOCK_ENABLED_SIZE = 1; //PL_DB_REGISTER:PLL_REF_CLOCK_ENABLED
+ localparam PLL_REF_CLOCK_ENABLED_MSB = 2; //PL_DB_REGISTER:PLL_REF_CLOCK_ENABLED
+ localparam PLL_REF_CLOCK_ENABLED = 2; //PL_DB_REGISTER:PLL_REF_CLOCK_ENABLED
+ localparam DB0_RESET_ASSERTED_SIZE = 1; //PL_DB_REGISTER:DB0_RESET_ASSERTED
+ localparam DB0_RESET_ASSERTED_MSB = 4; //PL_DB_REGISTER:DB0_RESET_ASSERTED
+ localparam DB0_RESET_ASSERTED = 4; //PL_DB_REGISTER:DB0_RESET_ASSERTED
+ localparam DB1_RESET_ASSERTED_SIZE = 1; //PL_DB_REGISTER:DB1_RESET_ASSERTED
+ localparam DB1_RESET_ASSERTED_MSB = 5; //PL_DB_REGISTER:DB1_RESET_ASSERTED
+ localparam DB1_RESET_ASSERTED = 5; //PL_DB_REGISTER:DB1_RESET_ASSERTED
+ localparam ENABLE_CLOCK_DB0_SIZE = 1; //PL_DB_REGISTER:ENABLE_CLOCK_DB0
+ localparam ENABLE_CLOCK_DB0_MSB = 8; //PL_DB_REGISTER:ENABLE_CLOCK_DB0
+ localparam ENABLE_CLOCK_DB0 = 8; //PL_DB_REGISTER:ENABLE_CLOCK_DB0
+ localparam ENABLE_CLOCK_DB1_SIZE = 1; //PL_DB_REGISTER:ENABLE_CLOCK_DB1
+ localparam ENABLE_CLOCK_DB1_MSB = 9; //PL_DB_REGISTER:ENABLE_CLOCK_DB1
+ localparam ENABLE_CLOCK_DB1 = 9; //PL_DB_REGISTER:ENABLE_CLOCK_DB1
+ localparam ENABLE_PLL_REF_CLOCK_SIZE = 1; //PL_DB_REGISTER:ENABLE_PLL_REF_CLOCK
+ localparam ENABLE_PLL_REF_CLOCK_MSB = 10; //PL_DB_REGISTER:ENABLE_PLL_REF_CLOCK
+ localparam ENABLE_PLL_REF_CLOCK = 10; //PL_DB_REGISTER:ENABLE_PLL_REF_CLOCK
+ localparam DISABLE_CLOCK_DB0_SIZE = 1; //PL_DB_REGISTER:DISABLE_CLOCK_DB0
+ localparam DISABLE_CLOCK_DB0_MSB = 12; //PL_DB_REGISTER:DISABLE_CLOCK_DB0
+ localparam DISABLE_CLOCK_DB0 = 12; //PL_DB_REGISTER:DISABLE_CLOCK_DB0
+ localparam DISABLE_CLOCK_DB1_SIZE = 1; //PL_DB_REGISTER:DISABLE_CLOCK_DB1
+ localparam DISABLE_CLOCK_DB1_MSB = 13; //PL_DB_REGISTER:DISABLE_CLOCK_DB1
+ localparam DISABLE_CLOCK_DB1 = 13; //PL_DB_REGISTER:DISABLE_CLOCK_DB1
+ localparam DISABLE_PLL_REF_CLOCK_SIZE = 1; //PL_DB_REGISTER:DISABLE_PLL_REF_CLOCK
+ localparam DISABLE_PLL_REF_CLOCK_MSB = 14; //PL_DB_REGISTER:DISABLE_PLL_REF_CLOCK
+ localparam DISABLE_PLL_REF_CLOCK = 14; //PL_DB_REGISTER:DISABLE_PLL_REF_CLOCK
+ localparam RELEASE_RESET_DB0_SIZE = 1; //PL_DB_REGISTER:RELEASE_RESET_DB0
+ localparam RELEASE_RESET_DB0_MSB = 16; //PL_DB_REGISTER:RELEASE_RESET_DB0
+ localparam RELEASE_RESET_DB0 = 16; //PL_DB_REGISTER:RELEASE_RESET_DB0
+ localparam RELEASE_RESET_DB1_SIZE = 1; //PL_DB_REGISTER:RELEASE_RESET_DB1
+ localparam RELEASE_RESET_DB1_MSB = 17; //PL_DB_REGISTER:RELEASE_RESET_DB1
+ localparam RELEASE_RESET_DB1 = 17; //PL_DB_REGISTER:RELEASE_RESET_DB1
+ localparam ASSERT_RESET_DB0_SIZE = 1; //PL_DB_REGISTER:ASSERT_RESET_DB0
+ localparam ASSERT_RESET_DB0_MSB = 20; //PL_DB_REGISTER:ASSERT_RESET_DB0
+ localparam ASSERT_RESET_DB0 = 20; //PL_DB_REGISTER:ASSERT_RESET_DB0
+ localparam ASSERT_RESET_DB1_SIZE = 1; //PL_DB_REGISTER:ASSERT_RESET_DB1
+ localparam ASSERT_RESET_DB1_MSB = 21; //PL_DB_REGISTER:ASSERT_RESET_DB1
+ localparam ASSERT_RESET_DB1 = 21; //PL_DB_REGISTER:ASSERT_RESET_DB1
+
+//===============================================================================
+// Register Group PS_CPLD_BASE_REGS
+//===============================================================================
+
+ // SIGNATURE_REGISTER Register (from ps_cpld_regs.v)
+ localparam SIGNATURE_REGISTER = 'h0; // Register Offset
+ localparam SIGNATURE_REGISTER_SIZE = 32; // register width in bits
+ localparam SIGNATURE_REGISTER_MASK = 32'hFFFFFFFF;
+ localparam PRODUCT_SIGNATURE_SIZE = 32; //SIGNATURE_REGISTER:PRODUCT_SIGNATURE
+ localparam PRODUCT_SIGNATURE_MSB = 31; //SIGNATURE_REGISTER:PRODUCT_SIGNATURE
+ localparam PRODUCT_SIGNATURE = 0; //SIGNATURE_REGISTER:PRODUCT_SIGNATURE
+
+ // REVISION_REGISTER Register (from ps_cpld_regs.v)
+ localparam REVISION_REGISTER = 'h4; // Register Offset
+ localparam REVISION_REGISTER_SIZE = 32; // register width in bits
+ localparam REVISION_REGISTER_MASK = 32'hFFFFFFFF;
+ localparam REVISION_HH_SIZE = 8; //REVISION_REGISTER:REVISION_HH
+ localparam REVISION_HH_MSB = 7; //REVISION_REGISTER:REVISION_HH
+ localparam REVISION_HH = 0; //REVISION_REGISTER:REVISION_HH
+ localparam REVISION_DD_SIZE = 8; //REVISION_REGISTER:REVISION_DD
+ localparam REVISION_DD_MSB = 15; //REVISION_REGISTER:REVISION_DD
+ localparam REVISION_DD = 8; //REVISION_REGISTER:REVISION_DD
+ localparam REVISION_MM_SIZE = 8; //REVISION_REGISTER:REVISION_MM
+ localparam REVISION_MM_MSB = 23; //REVISION_REGISTER:REVISION_MM
+ localparam REVISION_MM = 16; //REVISION_REGISTER:REVISION_MM
+ localparam REVISION_YY_SIZE = 8; //REVISION_REGISTER:REVISION_YY
+ localparam REVISION_YY_MSB = 31; //REVISION_REGISTER:REVISION_YY
+ localparam REVISION_YY = 24; //REVISION_REGISTER:REVISION_YY
+
+ // OLDEST_COMPATIBLE_REVISION_REGISTER Register (from ps_cpld_regs.v)
+ localparam OLDEST_COMPATIBLE_REVISION_REGISTER = 'h8; // Register Offset
+ localparam OLDEST_COMPATIBLE_REVISION_REGISTER_SIZE = 32; // register width in bits
+ localparam OLDEST_COMPATIBLE_REVISION_REGISTER_MASK = 32'hFFFFFFFF;
+ localparam OLD_REVISION_HH_SIZE = 8; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_HH
+ localparam OLD_REVISION_HH_MSB = 7; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_HH
+ localparam OLD_REVISION_HH = 0; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_HH
+ localparam OLD_REVISION_DD_SIZE = 8; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_DD
+ localparam OLD_REVISION_DD_MSB = 15; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_DD
+ localparam OLD_REVISION_DD = 8; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_DD
+ localparam OLD_REVISION_MM_SIZE = 8; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_MM
+ localparam OLD_REVISION_MM_MSB = 23; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_MM
+ localparam OLD_REVISION_MM = 16; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_MM
+ localparam OLD_REVISION_YY_SIZE = 8; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_YY
+ localparam OLD_REVISION_YY_MSB = 31; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_YY
+ localparam OLD_REVISION_YY = 24; //OLDEST_COMPATIBLE_REVISION_REGISTER:OLD_REVISION_YY
+
+ // SCRATCH_REGISTER Register (from ps_cpld_regs.v)
+ localparam SCRATCH_REGISTER = 'hC; // Register Offset
+ localparam SCRATCH_REGISTER_SIZE = 32; // register width in bits
+ localparam SCRATCH_REGISTER_MASK = 32'h0;
+
+ // GIT_HASH_REGISTER Register (from ps_cpld_regs.v)
+ localparam GIT_HASH_REGISTER = 'h10; // Register Offset
+ localparam GIT_HASH_REGISTER_SIZE = 32; // register width in bits
+ localparam GIT_HASH_REGISTER_MASK = 32'hFFFFFFFF;
+ localparam GIT_HASH_SIZE = 28; //GIT_HASH_REGISTER:GIT_HASH
+ localparam GIT_HASH_MSB = 27; //GIT_HASH_REGISTER:GIT_HASH
+ localparam GIT_HASH = 0; //GIT_HASH_REGISTER:GIT_HASH
+ localparam GIT_CLEAN_SIZE = 4; //GIT_HASH_REGISTER:GIT_CLEAN
+ localparam GIT_CLEAN_MSB = 31; //GIT_HASH_REGISTER:GIT_CLEAN
+ localparam GIT_CLEAN = 28; //GIT_HASH_REGISTER:GIT_CLEAN
diff --git a/fpga/usrp3/top/x400/cpld/regmap/ps_power_regmap_utils.vh b/fpga/usrp3/top/x400/cpld/regmap/ps_power_regmap_utils.vh
new file mode 100644
index 000000000..e4021b29e
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/regmap/ps_power_regmap_utils.vh
@@ -0,0 +1,54 @@
+//
+// Copyright 2021 Ettus Research, A National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: ps_power_regmap_utils.vh
+// Description:
+// The constants in this file are autogenerated by XmlParse.
+
+//===============================================================================
+// A numerically ordered list of registers and their HDL source files
+//===============================================================================
+
+ // IPASS_POWER_REG : 0x0 (ps_power_regs.v)
+ // OSC_POWER_REG : 0x4 (ps_power_regs.v)
+
+//===============================================================================
+// RegTypes
+//===============================================================================
+
+//===============================================================================
+// Register Group PS_POWER_REGS
+//===============================================================================
+
+ // IPASS_POWER_REG Register (from ps_power_regs.v)
+ localparam IPASS_POWER_REG = 'h0; // Register Offset
+ localparam IPASS_POWER_REG_SIZE = 32; // register width in bits
+ localparam IPASS_POWER_REG_MASK = 32'hC0000001;
+ localparam IPASS_DISABLE_POWER_BIT_SIZE = 1; //IPASS_POWER_REG:IPASS_DISABLE_POWER_BIT
+ localparam IPASS_DISABLE_POWER_BIT_MSB = 0; //IPASS_POWER_REG:IPASS_DISABLE_POWER_BIT
+ localparam IPASS_DISABLE_POWER_BIT = 0; //IPASS_POWER_REG:IPASS_DISABLE_POWER_BIT
+ localparam IPASS_CLEAR_POWER_FAULT0_SIZE = 1; //IPASS_POWER_REG:IPASS_CLEAR_POWER_FAULT0
+ localparam IPASS_CLEAR_POWER_FAULT0_MSB = 30; //IPASS_POWER_REG:IPASS_CLEAR_POWER_FAULT0
+ localparam IPASS_CLEAR_POWER_FAULT0 = 30; //IPASS_POWER_REG:IPASS_CLEAR_POWER_FAULT0
+ localparam IPASS_POWER_FAULT0_SIZE = 1; //IPASS_POWER_REG:IPASS_POWER_FAULT0
+ localparam IPASS_POWER_FAULT0_MSB = 30; //IPASS_POWER_REG:IPASS_POWER_FAULT0
+ localparam IPASS_POWER_FAULT0 = 30; //IPASS_POWER_REG:IPASS_POWER_FAULT0
+ localparam IPASS_CLEAR_POWER_FAULT1_SIZE = 1; //IPASS_POWER_REG:IPASS_CLEAR_POWER_FAULT1
+ localparam IPASS_CLEAR_POWER_FAULT1_MSB = 31; //IPASS_POWER_REG:IPASS_CLEAR_POWER_FAULT1
+ localparam IPASS_CLEAR_POWER_FAULT1 = 31; //IPASS_POWER_REG:IPASS_CLEAR_POWER_FAULT1
+ localparam IPASS_POWER_FAULT1_SIZE = 1; //IPASS_POWER_REG:IPASS_POWER_FAULT1
+ localparam IPASS_POWER_FAULT1_MSB = 31; //IPASS_POWER_REG:IPASS_POWER_FAULT1
+ localparam IPASS_POWER_FAULT1 = 31; //IPASS_POWER_REG:IPASS_POWER_FAULT1
+
+ // OSC_POWER_REG Register (from ps_power_regs.v)
+ localparam OSC_POWER_REG = 'h4; // Register Offset
+ localparam OSC_POWER_REG_SIZE = 32; // register width in bits
+ localparam OSC_POWER_REG_MASK = 32'h3;
+ localparam OSC_100_SIZE = 1; //OSC_POWER_REG:OSC_100
+ localparam OSC_100_MSB = 0; //OSC_POWER_REG:OSC_100
+ localparam OSC_100 = 0; //OSC_POWER_REG:OSC_100
+ localparam OSC_122_88_SIZE = 1; //OSC_POWER_REG:OSC_122_88
+ localparam OSC_122_88_MSB = 1; //OSC_POWER_REG:OSC_122_88
+ localparam OSC_122_88 = 1; //OSC_POWER_REG:OSC_122_88
diff --git a/fpga/usrp3/top/x400/cpld/regmap/reconfig_regmap_utils.vh b/fpga/usrp3/top/x400/cpld/regmap/reconfig_regmap_utils.vh
new file mode 100644
index 000000000..2ddc6a8b9
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/regmap/reconfig_regmap_utils.vh
@@ -0,0 +1,135 @@
+//
+// Copyright 2021 Ettus Research, A National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: reconfig_regmap_utils.vh
+// Description:
+// The constants in this file are autogenerated by XmlParse.
+
+//===============================================================================
+// A numerically ordered list of registers and their HDL source files
+//===============================================================================
+
+ // FLASH_STATUS_REG : 0x0 (reconfig_engine.v)
+ // FLASH_CONTROL_REG : 0x4 (reconfig_engine.v)
+ // FLASH_ADDR_REG : 0x8 (reconfig_engine.v)
+ // FLASH_WRITE_DATA_REG : 0xC (reconfig_engine.v)
+ // FLASH_READ_DATA_REG : 0x10 (reconfig_engine.v)
+ // FLASH_CFM0_START_ADDR_REG : 0x14 (reconfig_engine.v)
+ // FLASH_CFM0_END_ADDR_REG : 0x18 (reconfig_engine.v)
+
+//===============================================================================
+// RegTypes
+//===============================================================================
+
+//===============================================================================
+// Register Group RECONFIG_REGS
+//===============================================================================
+
+ // Enumerated type FLASH_PRIMARY_IMAGE_ADDR_ENUM
+ localparam FLASH_PRIMARY_IMAGE_ADDR_ENUM_SIZE = 3;
+ localparam FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT = 'h1000; // FLASH_PRIMARY_IMAGE_ADDR_ENUM:FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT
+ localparam FLASH_PRIMARY_IMAGE_START_ADDR = 'h9C00; // FLASH_PRIMARY_IMAGE_ADDR_ENUM:FLASH_PRIMARY_IMAGE_START_ADDR
+ localparam FLASH_PRIMARY_IMAGE_END_ADDR = 'h127FF; // FLASH_PRIMARY_IMAGE_ADDR_ENUM:FLASH_PRIMARY_IMAGE_END_ADDR
+
+ // FLASH_STATUS_REG Register (from reconfig_engine.v)
+ localparam FLASH_STATUS_REG = 'h0; // Register Offset
+ localparam FLASH_STATUS_REG_SIZE = 32; // register width in bits
+ localparam FLASH_STATUS_REG_MASK = 32'h13331;
+ localparam FLASH_WP_ENABLED_SIZE = 1; //FLASH_STATUS_REG:FLASH_WP_ENABLED
+ localparam FLASH_WP_ENABLED_MSB = 0; //FLASH_STATUS_REG:FLASH_WP_ENABLED
+ localparam FLASH_WP_ENABLED = 0; //FLASH_STATUS_REG:FLASH_WP_ENABLED
+ localparam FLASH_READ_IDLE_SIZE = 1; //FLASH_STATUS_REG:FLASH_READ_IDLE
+ localparam FLASH_READ_IDLE_MSB = 4; //FLASH_STATUS_REG:FLASH_READ_IDLE
+ localparam FLASH_READ_IDLE = 4; //FLASH_STATUS_REG:FLASH_READ_IDLE
+ localparam FLASH_READ_ERR_SIZE = 1; //FLASH_STATUS_REG:FLASH_READ_ERR
+ localparam FLASH_READ_ERR_MSB = 5; //FLASH_STATUS_REG:FLASH_READ_ERR
+ localparam FLASH_READ_ERR = 5; //FLASH_STATUS_REG:FLASH_READ_ERR
+ localparam FLASH_ERASE_IDLE_SIZE = 1; //FLASH_STATUS_REG:FLASH_ERASE_IDLE
+ localparam FLASH_ERASE_IDLE_MSB = 8; //FLASH_STATUS_REG:FLASH_ERASE_IDLE
+ localparam FLASH_ERASE_IDLE = 8; //FLASH_STATUS_REG:FLASH_ERASE_IDLE
+ localparam FLASH_ERASE_ERR_SIZE = 1; //FLASH_STATUS_REG:FLASH_ERASE_ERR
+ localparam FLASH_ERASE_ERR_MSB = 9; //FLASH_STATUS_REG:FLASH_ERASE_ERR
+ localparam FLASH_ERASE_ERR = 9; //FLASH_STATUS_REG:FLASH_ERASE_ERR
+ localparam FLASH_WRITE_IDLE_SIZE = 1; //FLASH_STATUS_REG:FLASH_WRITE_IDLE
+ localparam FLASH_WRITE_IDLE_MSB = 12; //FLASH_STATUS_REG:FLASH_WRITE_IDLE
+ localparam FLASH_WRITE_IDLE = 12; //FLASH_STATUS_REG:FLASH_WRITE_IDLE
+ localparam FLASH_WRITE_ERR_SIZE = 1; //FLASH_STATUS_REG:FLASH_WRITE_ERR
+ localparam FLASH_WRITE_ERR_MSB = 13; //FLASH_STATUS_REG:FLASH_WRITE_ERR
+ localparam FLASH_WRITE_ERR = 13; //FLASH_STATUS_REG:FLASH_WRITE_ERR
+ localparam FLASH_MEM_INIT_ENABLED_SIZE = 1; //FLASH_STATUS_REG:FLASH_MEM_INIT_ENABLED
+ localparam FLASH_MEM_INIT_ENABLED_MSB = 16; //FLASH_STATUS_REG:FLASH_MEM_INIT_ENABLED
+ localparam FLASH_MEM_INIT_ENABLED = 16; //FLASH_STATUS_REG:FLASH_MEM_INIT_ENABLED
+
+ // FLASH_CONTROL_REG Register (from reconfig_engine.v)
+ localparam FLASH_CONTROL_REG = 'h4; // Register Offset
+ localparam FLASH_CONTROL_REG_SIZE = 32; // register width in bits
+ localparam FLASH_CONTROL_REG_MASK = 32'h7FF;
+ localparam FLASH_ENABLE_WP_STB_SIZE = 1; //FLASH_CONTROL_REG:FLASH_ENABLE_WP_STB
+ localparam FLASH_ENABLE_WP_STB_MSB = 0; //FLASH_CONTROL_REG:FLASH_ENABLE_WP_STB
+ localparam FLASH_ENABLE_WP_STB = 0; //FLASH_CONTROL_REG:FLASH_ENABLE_WP_STB
+ localparam FLASH_DISABLE_WP_STB_SIZE = 1; //FLASH_CONTROL_REG:FLASH_DISABLE_WP_STB
+ localparam FLASH_DISABLE_WP_STB_MSB = 1; //FLASH_CONTROL_REG:FLASH_DISABLE_WP_STB
+ localparam FLASH_DISABLE_WP_STB = 1; //FLASH_CONTROL_REG:FLASH_DISABLE_WP_STB
+ localparam FLASH_READ_STB_SIZE = 1; //FLASH_CONTROL_REG:FLASH_READ_STB
+ localparam FLASH_READ_STB_MSB = 2; //FLASH_CONTROL_REG:FLASH_READ_STB
+ localparam FLASH_READ_STB = 2; //FLASH_CONTROL_REG:FLASH_READ_STB
+ localparam FLASH_WRITE_STB_SIZE = 1; //FLASH_CONTROL_REG:FLASH_WRITE_STB
+ localparam FLASH_WRITE_STB_MSB = 3; //FLASH_CONTROL_REG:FLASH_WRITE_STB
+ localparam FLASH_WRITE_STB = 3; //FLASH_CONTROL_REG:FLASH_WRITE_STB
+ localparam FLASH_ERASE_STB_SIZE = 1; //FLASH_CONTROL_REG:FLASH_ERASE_STB
+ localparam FLASH_ERASE_STB_MSB = 4; //FLASH_CONTROL_REG:FLASH_ERASE_STB
+ localparam FLASH_ERASE_STB = 4; //FLASH_CONTROL_REG:FLASH_ERASE_STB
+ localparam FLASH_ERASE_SECTOR_SIZE = 3; //FLASH_CONTROL_REG:FLASH_ERASE_SECTOR
+ localparam FLASH_ERASE_SECTOR_MSB = 7; //FLASH_CONTROL_REG:FLASH_ERASE_SECTOR
+ localparam FLASH_ERASE_SECTOR = 5; //FLASH_CONTROL_REG:FLASH_ERASE_SECTOR
+ localparam CLEAR_FLASH_READ_ERROR_STB_SIZE = 1; //FLASH_CONTROL_REG:CLEAR_FLASH_READ_ERROR_STB
+ localparam CLEAR_FLASH_READ_ERROR_STB_MSB = 8; //FLASH_CONTROL_REG:CLEAR_FLASH_READ_ERROR_STB
+ localparam CLEAR_FLASH_READ_ERROR_STB = 8; //FLASH_CONTROL_REG:CLEAR_FLASH_READ_ERROR_STB
+ localparam CLEAR_FLASH_WRITE_ERROR_STB_SIZE = 1; //FLASH_CONTROL_REG:CLEAR_FLASH_WRITE_ERROR_STB
+ localparam CLEAR_FLASH_WRITE_ERROR_STB_MSB = 9; //FLASH_CONTROL_REG:CLEAR_FLASH_WRITE_ERROR_STB
+ localparam CLEAR_FLASH_WRITE_ERROR_STB = 9; //FLASH_CONTROL_REG:CLEAR_FLASH_WRITE_ERROR_STB
+ localparam CLEAR_FLASH_ERASE_ERROR_STB_SIZE = 1; //FLASH_CONTROL_REG:CLEAR_FLASH_ERASE_ERROR_STB
+ localparam CLEAR_FLASH_ERASE_ERROR_STB_MSB = 10; //FLASH_CONTROL_REG:CLEAR_FLASH_ERASE_ERROR_STB
+ localparam CLEAR_FLASH_ERASE_ERROR_STB = 10; //FLASH_CONTROL_REG:CLEAR_FLASH_ERASE_ERROR_STB
+
+ // FLASH_ADDR_REG Register (from reconfig_engine.v)
+ localparam FLASH_ADDR_REG = 'h8; // Register Offset
+ localparam FLASH_ADDR_REG_SIZE = 32; // register width in bits
+ localparam FLASH_ADDR_REG_MASK = 32'h1FFFF;
+ localparam FLASH_ADDR_SIZE = 17; //FLASH_ADDR_REG:FLASH_ADDR
+ localparam FLASH_ADDR_MSB = 16; //FLASH_ADDR_REG:FLASH_ADDR
+ localparam FLASH_ADDR = 0; //FLASH_ADDR_REG:FLASH_ADDR
+
+ // FLASH_WRITE_DATA_REG Register (from reconfig_engine.v)
+ localparam FLASH_WRITE_DATA_REG = 'hC; // Register Offset
+ localparam FLASH_WRITE_DATA_REG_SIZE = 32; // register width in bits
+ localparam FLASH_WRITE_DATA_REG_MASK = 32'hFFFFFFFF;
+ localparam FLASH_WRITE_DATA_SIZE = 32; //FLASH_WRITE_DATA_REG:FLASH_WRITE_DATA
+ localparam FLASH_WRITE_DATA_MSB = 31; //FLASH_WRITE_DATA_REG:FLASH_WRITE_DATA
+ localparam FLASH_WRITE_DATA = 0; //FLASH_WRITE_DATA_REG:FLASH_WRITE_DATA
+
+ // FLASH_READ_DATA_REG Register (from reconfig_engine.v)
+ localparam FLASH_READ_DATA_REG = 'h10; // Register Offset
+ localparam FLASH_READ_DATA_REG_SIZE = 32; // register width in bits
+ localparam FLASH_READ_DATA_REG_MASK = 32'hFFFFFFFF;
+ localparam FLASH_READ_DATA_SIZE = 32; //FLASH_READ_DATA_REG:FLASH_READ_DATA
+ localparam FLASH_READ_DATA_MSB = 31; //FLASH_READ_DATA_REG:FLASH_READ_DATA
+ localparam FLASH_READ_DATA = 0; //FLASH_READ_DATA_REG:FLASH_READ_DATA
+
+ // FLASH_CFM0_START_ADDR_REG Register (from reconfig_engine.v)
+ localparam FLASH_CFM0_START_ADDR_REG = 'h14; // Register Offset
+ localparam FLASH_CFM0_START_ADDR_REG_SIZE = 32; // register width in bits
+ localparam FLASH_CFM0_START_ADDR_REG_MASK = 32'hFFFFFFFF;
+ localparam FLASH_CFM0_START_ADDR_SIZE = 32; //FLASH_CFM0_START_ADDR_REG:FLASH_CFM0_START_ADDR
+ localparam FLASH_CFM0_START_ADDR_MSB = 31; //FLASH_CFM0_START_ADDR_REG:FLASH_CFM0_START_ADDR
+ localparam FLASH_CFM0_START_ADDR = 0; //FLASH_CFM0_START_ADDR_REG:FLASH_CFM0_START_ADDR
+
+ // FLASH_CFM0_END_ADDR_REG Register (from reconfig_engine.v)
+ localparam FLASH_CFM0_END_ADDR_REG = 'h18; // Register Offset
+ localparam FLASH_CFM0_END_ADDR_REG_SIZE = 32; // register width in bits
+ localparam FLASH_CFM0_END_ADDR_REG_MASK = 32'hFFFFFFFF;
+ localparam FLASH_CFM0_END_ADDR_SIZE = 32; //FLASH_CFM0_END_ADDR_REG:FLASH_CFM0_END_ADDR
+ localparam FLASH_CFM0_END_ADDR_MSB = 31; //FLASH_CFM0_END_ADDR_REG:FLASH_CFM0_END_ADDR
+ localparam FLASH_CFM0_END_ADDR = 0; //FLASH_CFM0_END_ADDR_REG:FLASH_CFM0_END_ADDR
diff --git a/fpga/usrp3/top/x400/cpld/regmap/spi_regmap_utils.vh b/fpga/usrp3/top/x400/cpld/regmap/spi_regmap_utils.vh
new file mode 100644
index 000000000..bf25b6fd3
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/regmap/spi_regmap_utils.vh
@@ -0,0 +1,69 @@
+//
+// Copyright 2021 Ettus Research, A National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: spi_regmap_utils.vh
+// Description:
+// The constants in this file are autogenerated by XmlParse.
+
+//===============================================================================
+// A numerically ordered list of registers and their HDL source files
+//===============================================================================
+
+ // RX_DATA_LOW : 0x0 (ctrlport_to_spi.v)
+ // RX_DATA_HIGH : 0x4 (ctrlport_to_spi.v)
+ // TX_DATA_LOW : 0x8 (ctrlport_to_spi.v)
+ // TX_DATA_HIGH : 0xC (ctrlport_to_spi.v)
+ // CONTROL : 0x10 (ctrlport_to_spi.v)
+ // CLOCK_DIVIDER : 0x14 (ctrlport_to_spi.v)
+ // SLAVE_SELECT : 0x18 (ctrlport_to_spi.v)
+
+//===============================================================================
+// RegTypes
+//===============================================================================
+
+//===============================================================================
+// Register Group SPI_REGS
+//===============================================================================
+
+ // RX_DATA_LOW Register (from ctrlport_to_spi.v)
+ localparam RX_DATA_LOW = 'h0; // Register Offset
+ localparam RX_DATA_LOW_SIZE = 32; // register width in bits
+ localparam RX_DATA_LOW_MASK = 32'h0;
+
+ // RX_DATA_HIGH Register (from ctrlport_to_spi.v)
+ localparam RX_DATA_HIGH = 'h4; // Register Offset
+ localparam RX_DATA_HIGH_SIZE = 32; // register width in bits
+ localparam RX_DATA_HIGH_MASK = 32'h0;
+
+ // TX_DATA_LOW Register (from ctrlport_to_spi.v)
+ localparam TX_DATA_LOW = 'h8; // Register Offset
+ localparam TX_DATA_LOW_SIZE = 32; // register width in bits
+ localparam TX_DATA_LOW_MASK = 32'h0;
+
+ // TX_DATA_HIGH Register (from ctrlport_to_spi.v)
+ localparam TX_DATA_HIGH = 'hC; // Register Offset
+ localparam TX_DATA_HIGH_SIZE = 32; // register width in bits
+ localparam TX_DATA_HIGH_MASK = 32'h0;
+
+ // CONTROL Register (from ctrlport_to_spi.v)
+ localparam CONTROL = 'h10; // Register Offset
+ localparam CONTROL_SIZE = 32; // register width in bits
+ localparam CONTROL_MASK = 32'h0;
+
+ // CLOCK_DIVIDER Register (from ctrlport_to_spi.v)
+ localparam CLOCK_DIVIDER = 'h14; // Register Offset
+ localparam CLOCK_DIVIDER_SIZE = 8; // register width in bits
+ localparam CLOCK_DIVIDER_MASK = 8'hFF;
+ localparam DIVIDER_SIZE = 8; //CLOCK_DIVIDER:Divider
+ localparam DIVIDER_MSB = 7; //CLOCK_DIVIDER:Divider
+ localparam DIVIDER = 0; //CLOCK_DIVIDER:Divider
+
+ // SLAVE_SELECT Register (from ctrlport_to_spi.v)
+ localparam SLAVE_SELECT = 'h18; // Register Offset
+ localparam SLAVE_SELECT_SIZE = 16; // register width in bits
+ localparam SLAVE_SELECT_MASK = 16'hFFFF;
+ localparam SS_SIZE = 16; //SLAVE_SELECT:SS
+ localparam SS_MSB = 15; //SLAVE_SELECT:SS
+ localparam SS = 0; //SLAVE_SELECT:SS
diff --git a/fpga/usrp3/top/x400/cpld/reset_generator.v b/fpga/usrp3/top/x400/cpld/reset_generator.v
new file mode 100644
index 000000000..dd3a56022
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/reset_generator.v
@@ -0,0 +1,93 @@
+//
+// Copyright 2021 Ettus Research, A National Instruments Brand
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: reset_generator
+//
+// Description:
+//
+// Generates a power-on reset signal that is asserted at startup and stays
+// asserted for at least CYCLES_IN_RESET clock cycles.
+//
+// Internally, it generates a 1-bit synchronous signal (initialize) to safely
+// initialize the power_on_reset_counter incremental counter to 0's.
+//
+// A delayed version of the initializing signal is also generated
+// (counter_enable) to start counting.
+//
+// 1_ 2_ 3_ 4_ 5_ 6_ 7_ 8_ 9_
+// clk _| |_| |_| |_| |_| |_| |_| |_| |_|
+// _____________________
+// initialize _____________|
+// _________
+// counter_enable _________________________|
+//
+
+`default_nettype none
+
+
+module reset_generator (
+ input wire clk,
+ output reg power_on_reset = 1'b1
+);
+
+ wire [0:0] counter_enable;
+ wire [0:0] initialize;
+
+ synchronizer #(
+ .WIDTH (1),
+ .STAGES (3),
+ .INITIAL_VAL (1'b0),
+ .FALSE_PATH_TO_IN (0)
+ ) init_sync_inst (
+ .clk (clk),
+ .rst (1'b0),
+ .in (1'b1),
+ .out (initialize)
+ );
+
+ synchronizer #(
+ .WIDTH (1),
+ .STAGES (3),
+ .INITIAL_VAL (1'b0),
+ .FALSE_PATH_TO_IN (0)
+ ) counter_en_sync_inst (
+ .clk (clk),
+ .rst (1'b0),
+ .in (initialize),
+ .out (counter_enable)
+ );
+
+ // Internal synchronous reset generator.
+ localparam CYCLES_IN_RESET = 20;
+ reg [7:0] power_on_reset_counter = 8'b0;
+
+ // This block generates a synchronous reset in the clk domain that can be
+ // used by downstream logic.
+ //
+ // power_on_reset_counter is first initialized to 0's upon assertion of
+ // initialize. Some cycles later (3), upon assertion if counter_enable,
+ // power_on_reset_counter starts to increment.
+ //
+ // power_on_reset will remain asserted until power_on_reset_counter reaches
+ // cycles_in_reset, resulting in the deassertion of power_on_reset.
+ always @(posedge clk) begin : power_on_reset_gen
+ if (counter_enable) begin
+ if (power_on_reset_counter == CYCLES_IN_RESET-1) begin
+ power_on_reset <= 1'b0;
+ end else begin
+ power_on_reset_counter <= power_on_reset_counter + 1'b1;
+ power_on_reset <= 1'b1;
+ end
+ end
+ else if (initialize) begin
+ power_on_reset_counter <= 8'b0;
+ power_on_reset <= 1'b1;
+ end
+ end
+
+endmodule
+
+
+`default_nettype wire
diff --git a/fpga/usrp3/top/x400/cpld/scripts/ps_cs_analysis.tcl b/fpga/usrp3/top/x400/cpld/scripts/ps_cs_analysis.tcl
new file mode 100644
index 000000000..03ff77d2c
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/scripts/ps_cs_analysis.tcl
@@ -0,0 +1,32 @@
+#
+# Copyright 2021 Ettus Research, a National Instruments Brand
+#
+# SPDX-License-Identifier: LGPL-3.0-or-later
+#
+# Module: ps_cs_analysis
+#
+# Description:
+#
+# Analyze false path in PS SPI logic to ensure an upper delay boundary.
+#
+
+# get project to a working state
+project_open -force "mb_cpld.qpf"
+create_timing_netlist
+update_timing_netlist
+
+# Determine data path delay from MB CPLD chip select signal to MB CPLD internal
+# SPI slave
+set paths [report_path -from [get_registers {ps_spi_cs_n_decoded[0]}] -multi_corner]
+set spiSlaveCsPathDelay [lindex $paths 1]
+
+# clock period at 250 MHz (clock driving the decoding registers)
+set maxDelay 4
+
+# compare path from above with maximum delay
+if ([expr {$maxDelay < $spiSlaveCsPathDelay}]) {
+ puts "MB CPLD SPI CS line longer than expected."
+ exit 1
+}
+
+exit 0
diff --git a/fpga/usrp3/top/x400/cpld/spi_slave.v b/fpga/usrp3/top/x400/cpld/spi_slave.v
new file mode 100644
index 000000000..ab2f16fea
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/spi_slave.v
@@ -0,0 +1,288 @@
+//
+// Copyright 2021 Ettus Research, A National Instruments Brand
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: spi_slave
+//
+// Description:
+//
+// SPI slave for configuration CPOL = CPHA = 0.
+// Transfers 8 bit = 1 byte MSB first. Parallel data has to be
+// provided and consumed immediately when flags are asserted.
+//
+// Limitation: clk frequency <= 2*sclk frequency
+//
+// Data request from sclk domain is triggered towards the clk domain ahead of
+// time. This is due to the clock domain crossing using the synchronizer and
+// processing pipeline stages.
+//
+// The worst case propagation delay of the used synchronizer is:
+//
+// 4 'clk' clock cycles:
+// 1 clock cycle of signal propagation to synchronizer
+// (data_request_sclk assertion)
+// 1 clock cycle to capture data with instability in first stage
+// 1 clock cycle to stabilize first stage
+// 1 clock cycle to capture data in second stage
+// (data_request_clk available in 'clk' domain)
+//
+// Once synchronized in 'clk' domain, there is one additional clock cycle to
+// derive data_out_valid and data_in_required. To ensure that transmit data
+// is registered a 'clk' cycle ahead of the actual transmission we need 2
+// more 'clk' clock cycles. This ensures that transmit_word has changed and
+// is stable for at least one 'clk' cycle before 'sclk' asserts again. Any
+// additional time required externally to respond to the control port
+// requests should be considered in this crossing as well. This is a total of
+// 7 clock cycles (+ctrlport response margin) @ clk domain. The minimum
+// required time in sclk domain to issue the request is calculated based on
+// the clock frequencies.
+//
+// Parameters:
+//
+// CLK_FREQUENCY : Frequency of "clk"
+// SPI_FREQUENCY : Frequency of "sclk"
+//
+
+`default_nettype none
+
+
+module spi_slave #(
+ parameter CLK_FREQUENCY = 50000000,
+ parameter SPI_FREQUENCY = 10000000
+) (
+ //---------------------------------------------------------------
+ // SPI Interface
+ //---------------------------------------------------------------
+
+ input wire sclk,
+ input wire cs_n,
+ input wire mosi,
+ output wire miso,
+
+ //---------------------------------------------------------------
+ // Parallel Interface
+ //---------------------------------------------------------------
+
+ input wire clk,
+ input wire rst,
+
+ output reg data_in_required,
+ input wire data_in_valid,
+ input wire [7:0] data_in,
+
+ output reg data_out_valid,
+ output reg [7:0] data_out,
+
+ output wire active
+);
+
+ wire [0:0] data_request_clk;
+ wire [0:0] reception_complete_clk;
+
+ //---------------------------------------------------------------
+ // SPI Receiver @ sclk
+ //---------------------------------------------------------------
+
+ reg [7:0] receiver_reg;
+ reg [2:0] current_bit_index;
+ reg reception_complete_sclk = 1'b0;
+ reg [7:0] received_word;
+
+ always @(posedge sclk or posedge cs_n) begin
+ // Reset logic on positive cs_n edge = slave idle
+ if (cs_n) begin
+ receiver_reg <= 8'b0;
+ end
+ // Rising edge of sclk
+ else begin
+ // Capture bits into shift register MSBs first
+ receiver_reg <= {receiver_reg[6:0], mosi};
+ end
+ end
+
+ // Reset with cs_n might occur too early during clk sync.
+ // Reset half way through the reception.
+ always @(posedge sclk) begin
+ // Complete word was received
+ if (current_bit_index == 7) begin
+ reception_complete_sclk <= 1'b1;
+ received_word <= {receiver_reg[6:0], mosi};
+
+ // Reset after half transaction
+ end else if (current_bit_index == 3) begin
+ reception_complete_sclk <= 1'b0;
+ end
+ end
+
+ //---------------------------------------------------------------
+ // Handover of data sclk -> clk
+ //---------------------------------------------------------------
+
+ synchronizer #(
+ .WIDTH (1),
+ .STAGES (2),
+ .INITIAL_VAL (1'b0),
+ .FALSE_PATH_TO_IN (1)
+ ) data_sync_inst (
+ .clk (clk),
+ .rst (1'b0),
+ .in (reception_complete_sclk),
+ .out (reception_complete_clk)
+ );
+
+ //---------------------------------------------------------------
+ // Parallel interface data output @ clk
+ //---------------------------------------------------------------
+
+ reg reception_complete_clk_delayed = 1'b0;
+
+ // Propagate toggling signal without reset to ensure stability on reset
+ always @(posedge clk) begin
+ // Capture last state of reception
+ reception_complete_clk_delayed <= reception_complete_clk;
+ end
+
+ // Derive data and control signal
+ always @(posedge clk) begin
+ if (rst) begin
+ data_out_valid <= 1'b0;
+ data_out <= 8'b0;
+ end
+ else begin
+ // Default assignment
+ data_out_valid <= 1'b0;
+
+ // Provide data to output on rising_edge
+ if (reception_complete_clk & ~reception_complete_clk_delayed) begin
+ // Data can simply be captured as the reception complete signal
+ // indicates stable values in received_word.
+ data_out <= received_word;
+ data_out_valid <= 1'b1;
+ end
+ end
+ end
+
+ //---------------------------------------------------------------
+ // SPI Transmitter @ sclk
+ //---------------------------------------------------------------
+
+ // Data request calculation:
+ // SCLK_CYCLES_DURING_DATA_REQ = 8 clk period / sclk period
+ // Clock periods are expressed by reciprocal of frequencies.
+ // Term "+CLK_FREQUENCY-1" is used to round up the result in integer logic.
+ localparam SCLK_CYCLES_DURING_DATA_REQ = (8*SPI_FREQUENCY + CLK_FREQUENCY-1)/CLK_FREQUENCY;
+ // subtract from 8 bits per transfer to get target index
+ localparam DATA_REQ_BIT_INDEX = 8 - SCLK_CYCLES_DURING_DATA_REQ;
+
+ reg [7:0] transmit_bits;
+ reg [7:0] transmit_word;
+ reg data_request_sclk = 1'b0;
+
+ always @(negedge sclk or posedge cs_n) begin
+ // Reset logic on positive cs_n edge = slave idle
+ if (cs_n) begin
+ current_bit_index <= 3'b0;
+ data_request_sclk <= 1'b0;
+ transmit_bits <= 8'b0;
+ end
+ // Falling edge of sclk
+ else begin
+ // Fill or move shift register for byte transmissions
+ if (current_bit_index == 7) begin
+ transmit_bits <= transmit_word;
+ end else begin
+ transmit_bits <= {transmit_bits[6:0], 1'b0};
+ end
+
+ // Update bit index
+ current_bit_index <= current_bit_index + 1'b1;
+
+ // Trigger request for new word at start of calculated index
+ if (current_bit_index == DATA_REQ_BIT_INDEX-1) begin
+ data_request_sclk <= 1'b1;
+ // Reset after half the reception in case cs_n is not changed in between
+ // two transactions.
+ end else if (current_bit_index == (DATA_REQ_BIT_INDEX+4-1)%8) begin
+ data_request_sclk <= 1'b0;
+ end
+ end
+ end
+
+ // Drive miso output with data when cs_n low
+ assign miso = cs_n ? 1'bz : transmit_bits[7];
+
+ //---------------------------------------------------------------
+ // Handover of Data Request sclk -> clk
+ //---------------------------------------------------------------
+
+ synchronizer #(
+ .WIDTH (1),
+ .STAGES (2),
+ .INITIAL_VAL (1'b0),
+ .FALSE_PATH_TO_IN (1)
+ ) request_sync_inst (
+ .clk (clk),
+ .rst (rst),
+ .in (data_request_sclk),
+ .out (data_request_clk)
+ );
+
+ //---------------------------------------------------------------
+ // Parallel Interface Data Input Control
+ //---------------------------------------------------------------
+
+ reg data_request_clk_delayed;
+
+ always @(posedge clk) begin
+ if (rst) begin
+ data_request_clk_delayed <= 1'b0;
+ data_in_required <= 1'b0;
+ transmit_word <= 8'b0;
+ end
+ else begin
+ // Default assignment
+ data_in_required <= 1'b0;
+
+ // Capture last state of data request
+ data_request_clk_delayed <= data_request_clk;
+
+ // Request data from input
+ if (~data_request_clk_delayed & data_request_clk) begin
+ data_in_required <= 1'b1;
+ end
+
+ // Capture new data if valid data available, 0 otherwise.
+ if (data_in_required) begin
+ if (data_in_valid) begin
+ transmit_word <= data_in;
+ end else begin
+ transmit_word <= 8'b0;
+ end
+ end
+ end
+ end
+
+ //---------------------------------------------------------------
+ // Chip Select
+ //---------------------------------------------------------------
+ // Driven as active signal in parallel clock domain
+
+ wire cs_n_clk;
+ assign active = ~cs_n_clk;
+ synchronizer #(
+ .WIDTH (1),
+ .STAGES (2),
+ .INITIAL_VAL (1'b1),
+ .FALSE_PATH_TO_IN (1)
+ ) active_sync_inst (
+ .clk (clk),
+ .rst (rst),
+ .in (cs_n),
+ .out (cs_n_clk)
+ );
+
+endmodule
+
+
+`default_nettype wire
diff --git a/fpga/usrp3/top/x400/cpld/spi_slave_to_ctrlport_master.v b/fpga/usrp3/top/x400/cpld/spi_slave_to_ctrlport_master.v
new file mode 100644
index 000000000..6f624fe17
--- /dev/null
+++ b/fpga/usrp3/top/x400/cpld/spi_slave_to_ctrlport_master.v
@@ -0,0 +1,238 @@
+//
+// Copyright 2021 Ettus Research, A National Instruments Brand
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: spi_slave_to_ctrlport_master
+//
+// Description:
+//
+// SPI slave to ContolPort master conversion in order to tunnel control port
+// request through an SPI bus.
+//
+// The request format on SPI is defined as:
+//
+// Write request:
+// 1'b1 = write, 15 bit address, 32 bit data (MOSI), 8 bit processing gap,
+// 5 bit padding, 1 bit ack, 2 bit status
+//
+// Read request:
+// 1'b0 = read, 15 bit address, 8 bit processing gap, 32 bit data (MISO),
+// 5 bit padding, 1 bit ack, 2 bit status
+//
+// Parameters:
+//
+// CLK_FREQUENCY : Frequency of "clk"
+// SPI_FREQUENCY : Frequency of "sclk"
+//
+
+`default_nettype none
+
+
+module spi_slave_to_ctrlport_master #(
+ parameter CLK_FREQUENCY = 50000000,
+ parameter SPI_FREQUENCY = 10000000
+) (
+ //---------------------------------------------------------------
+ // ControlPort Master
+ //---------------------------------------------------------------
+
+ input wire ctrlport_clk,
+ input wire ctrlport_rst,
+
+ output wire m_ctrlport_req_wr,
+ output wire m_ctrlport_req_rd,
+ output wire [19:0] m_ctrlport_req_addr,
+ output wire [31:0] m_ctrlport_req_data,
+
+ input wire m_ctrlport_resp_ack,
+ input wire [ 1:0] m_ctrlport_resp_status,
+ input wire [31:0] m_ctrlport_resp_data,
+
+ //---------------------------------------------------------------
+ // SPI Slave
+ //---------------------------------------------------------------
+
+ input wire sclk,
+ input wire cs_n,
+ input wire mosi,
+ output wire miso
+);
+
+ `include "../../../lib/rfnoc/core/ctrlport.vh"
+
+ //---------------------------------------------------------------
+ // SPI Slave
+ //---------------------------------------------------------------
+
+ wire [7:0] data_in;
+ wire [7:0] data_out;
+ wire data_in_valid;
+ wire data_out_valid;
+ wire data_in_required;
+ wire spi_slave_active;
+
+ spi_slave #(
+ .CLK_FREQUENCY (CLK_FREQUENCY),
+ .SPI_FREQUENCY (SPI_FREQUENCY)
+ ) spi_slave_async (
+ .sclk (sclk),
+ .cs_n (cs_n),
+ .mosi (mosi),
+ .miso (miso),
+ .clk (ctrlport_clk),
+ .rst (ctrlport_rst),
+ .data_in_required (data_in_required),
+ .data_in_valid (data_in_valid),
+ .data_in (data_in),
+ .data_out_valid (data_out_valid),
+ .data_out (data_out),
+ .active (spi_slave_active)
+ );
+
+ //---------------------------------------------------------------
+ // Reset Generation from SPI Slave
+ //---------------------------------------------------------------
+
+ reg spi_slave_active_delayed = 1'b0;
+ always @(posedge ctrlport_clk) begin
+ if (ctrlport_rst) begin
+ spi_slave_active_delayed <= 1'b0;
+ end
+ else begin
+ spi_slave_active_delayed <= spi_slave_active;
+ end
+ end
+
+ // Trigger reset on falling edge of active signal (rising edge of cs_n)
+ wire spi_slave_reset;
+ assign spi_slave_reset = spi_slave_active_delayed & (~spi_slave_active);
+
+ //---------------------------------------------------------------
+ // Transfer Constants
+ //---------------------------------------------------------------
+
+ localparam NUM_BYTES_TRANSACTION = 8;
+ localparam NUM_BYTES_WRITE_REQUEST_PAYLOAD = 6;
+ localparam NUM_BYTES_READ_REQUEST_PAYLOAD = 2;
+ localparam MAX_BYTES_RESPONSE_PAYLOAD = 5;
+
+ //---------------------------------------------------------------
+ // Data Receiver
+ //---------------------------------------------------------------
+
+ reg [3:0] num_bytes_received;
+ reg request_received;
+ reg write_request;
+ reg provide_response;
+ reg [NUM_BYTES_WRITE_REQUEST_PAYLOAD*8-1:0] request_reg = {NUM_BYTES_WRITE_REQUEST_PAYLOAD*8 {1'b0}};
+
+ always @(posedge ctrlport_clk) begin
+ if (ctrlport_rst || spi_slave_reset) begin
+ num_bytes_received <= 4'b0;
+ request_received <= 1'b0;
+ write_request <= 1'b0;
+ provide_response <= 1'b0;
+ end
+ else begin
+ // Counter number of received bytes
+ if (data_out_valid) begin
+ // Increment counter
+ num_bytes_received <= num_bytes_received + 1'b1;
+
+ if (num_bytes_received == NUM_BYTES_TRANSACTION-1) begin
+ num_bytes_received <= 4'b0;
+ end
+ end
+
+ // Check for read / write on first received byte's MSB
+ if (data_out_valid && (num_bytes_received == 0)) begin
+ write_request <= data_out[7];
+ end
+
+ // Detect complete request
+ request_received <= 1'b0;
+ if (data_out_valid) begin
+ if (write_request && (num_bytes_received == NUM_BYTES_WRITE_REQUEST_PAYLOAD-1)) begin
+ request_received <= 1'b1;
+ provide_response <= 1'b1;
+ end else if (~write_request && (num_bytes_received == NUM_BYTES_READ_REQUEST_PAYLOAD-1)) begin
+ request_received <= 1'b1;
+ provide_response <= 1'b1;
+ end
+ end
+
+ // Detect end of response on last received byte
+ if (num_bytes_received == NUM_BYTES_TRANSACTION-1) begin
+ provide_response <= 1'b0;
+ end
+
+ // Capture data into shift register
+ if (data_out_valid) begin
+ request_reg <= {request_reg[NUM_BYTES_WRITE_REQUEST_PAYLOAD*8-8-1:0], data_out};
+ end
+ end
+ end
+
+ // Drive ControlPort
+ localparam SPI_TRANSFER_ADDRESS_WIDTH = 15;
+ assign m_ctrlport_req_wr = request_received && write_request;
+ assign m_ctrlport_req_rd = request_received && ~write_request;
+ assign m_ctrlport_req_data = request_reg[CTRLPORT_DATA_W-1:0];
+ assign m_ctrlport_req_addr = (write_request) ?
+ {5'b0, request_reg[CTRLPORT_DATA_W+:SPI_TRANSFER_ADDRESS_WIDTH]} :
+ {5'b0, request_reg[0+:SPI_TRANSFER_ADDRESS_WIDTH]};
+
+ //---------------------------------------------------------------
+ // Response Handling
+ //---------------------------------------------------------------
+
+ reg [MAX_BYTES_RESPONSE_PAYLOAD*8-1:0] response_reg;
+ reg ready_for_response; // active during processing gap
+ wire write_response_byte;
+
+ always @(posedge ctrlport_clk) begin
+ if (ctrlport_rst || spi_slave_reset) begin
+ response_reg <= {8*MAX_BYTES_RESPONSE_PAYLOAD {1'b0}};
+ ready_for_response <= 1'b0;
+ end
+ else begin
+ // Reset response on new request
+ if (request_received) begin
+ ready_for_response <= 1'b1;
+ if (write_request) begin
+ // Just last byte -> padding, ack flag, CMDERR, padding (data length)
+ response_reg <= {5'b0, 1'b1, CTRL_STS_CMDERR, {CTRLPORT_DATA_W{1'b0}}};
+ end else begin
+ // Last 5 bytes -> data = 0, Padding, ack flag, CMDERR
+ response_reg <= {{CTRLPORT_DATA_W{1'b0}}, 5'b0, 1'b1, CTRL_STS_CMDERR};
+ end
+
+ // Capture response within processing gap, leave default response from above otherwise
+ end else if (m_ctrlport_resp_ack && ready_for_response) begin
+ if (write_request) begin
+ response_reg <= {5'b0, m_ctrlport_resp_ack, m_ctrlport_resp_status, {CTRLPORT_DATA_W{1'b0}}};
+ end else begin
+ response_reg <= {m_ctrlport_resp_data, 5'b0, m_ctrlport_resp_ack, m_ctrlport_resp_status};
+ end
+ end
+
+ // Shift data after writing to slave
+ if (write_response_byte) begin
+ response_reg <= {response_reg[0+:(MAX_BYTES_RESPONSE_PAYLOAD-1)*8], 8'b0};
+ ready_for_response <= 1'b0;
+ end
+ end
+ end
+
+ // Response is written after request part has been transferred
+ assign write_response_byte = data_in_required && provide_response;
+
+ // Assign SPI slave inputs
+ assign data_in = response_reg[(MAX_BYTES_RESPONSE_PAYLOAD-1)*8+:8];
+ assign data_in_valid = write_response_byte;
+
+endmodule
+
+
+`default_nettype wire