diff --git a/top/x400/cpld/Makefile b/top/x400/cpld/Makefile index fb147d0..4224d11 100644 --- a/top/x400/cpld/Makefile +++ b/top/x400/cpld/Makefile @@ -21,16 +21,20 @@ 10M04_ID = "10M04SAU169I7G" 10M08_ID = "10M08SAU169I7G" +# Project directories +X410_DIR = $(abspath ./x410) + # Target specific variables -X410_CPLD_10M04: DEFS = VARIANT_`echo $(10M04_ID) | cut -c1-5`=1 -X410_CPLD_10M08: DEFS = VARIANT_`echo $(10M08_ID) | cut -c1-5`=1 -X410_CPLD_MFG_10M08: DEFS = VARIANT_`echo $(10M08_ID) | cut -c1-5`=1 MFG_SUPPORT=1 +X410_CPLD_10M04: DEFS = VARIANT_`echo $(10M04_ID) | cut -c1-5`=1 PROJECT_DIR=$(X410_DIR) X410=1 +X410_CPLD_10M08: DEFS = VARIANT_`echo $(10M08_ID) | cut -c1-5`=1 PROJECT_DIR=$(X410_DIR) X410=1 +X410_CPLD_MFG_10M08: DEFS = VARIANT_`echo $(10M08_ID) | cut -c1-5`=1 MFG_SUPPORT=1 PROJECT_DIR=$(X410_DIR) + TARGET = bin TOP ?= mb_cpld # quartus_build($1=Device, $2=Definitions) -quartus_build = make -f Makefile.cpld.inc $(TARGET) NAME=$@ ARCH="MAX10" PART_ID="$1" $2 TOP_MODULE=$(TOP) EXTRA_DEFS="$2" POST_STA_TCL="ps_cs_analysis.tcl" +quartus_build = make -f Makefile.cpld.inc $(TARGET) NAME=$@ ARCH="MAX10" PART_ID="$1" $2 TOP_MODULE=$(TOP) EXTRA_DEFS="$2" POST_STA_TCL="../../common/quartus/ps_cs_analysis.tcl" # quartus_ip($1=Device, $2=Definitions) quartus_ip = make -f Makefile.cpld.inc quar_ip NAME=$@ ARCH="MAX10" PART_ID="$1" $2 TOP_MODULE=$(TOP) EXTRA_DEFS="$2" diff --git a/top/x400/cpld/Makefile.cpld.inc b/top/x400/cpld/Makefile.cpld.inc index bc3c6c9..f788f7a 100644 --- a/top/x400/cpld/Makefile.cpld.inc +++ b/top/x400/cpld/Makefile.cpld.inc @@ -44,7 +44,7 @@ bin: .prereqs --operation p \ output_files/$(TOP_MODULE).pof output_files/$(TOP_MODULE)_isp_off.svf; \ echo "Converting bitfile to rpd format..."; \ - quartus_cpf -c raw_conversion.cof; \ + quartus_cpf -c ../common/quartus/raw_conversion.cof; \ popd; quar_ip: .prereqs ip diff --git a/top/x400/cpld/common/common.sdc b/top/x400/cpld/common/common.sdc new file mode 100644 index 0000000..f98a24e --- /dev/null +++ b/top/x400/cpld/common/common.sdc @@ -0,0 +1,437 @@ +# +# Copyright 2021 Ettus Research, a National Instruments Brand +# +# SPDX-License-Identifier: LGPL-3.0-or-later +# +# Description: +# +# Common 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 + +##################################################################### +# 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 in db specific sdc + +# 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 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 + +##################################################################### +# 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 common +##################################################################### +###### 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 ----------------------- 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 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 + +#### 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/top/x400/cpld/common/ctrlport_to_spi.v b/top/x400/cpld/common/ctrlport_to_spi.v new file mode 100644 index 0000000..ee10da5 --- /dev/null +++ b/top/x400/cpld/common/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 +// +// +// +// +// 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 +// documentation +// 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 | +// +// +// +// Lower 32 bits of the received word. (RxWord[31:0]) +// +// +// +// Higher 32 bits of the received word. (RxWord[63:32]) +// +// +// +// Lower 32 bits of the received word. (TxWord[31:0]) +// +// +// +// Higher 32 bits of the received word. (TxWord[63:32]) +// +// +// +// Control register +// + +// +// +// +// Clock Divider. +// +// +// +// +// +// +// Slave select. +// +// +// +// +// +// +//XmlParse xml_off diff --git a/top/x400/cpld/common/pl_cpld_regs.v b/top/x400/cpld/common/pl_cpld_regs.v new file mode 100644 index 0000000..0640b50 --- /dev/null +++ b/top/x400/cpld/common/pl_cpld_regs.v @@ -0,0 +1,299 @@ +// +// 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 +); + + `ifdef X410 + `include "../regmap/x410/constants_regmap_utils.vh" + `endif + `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 +// +// +// +// Basic registers containing version and capabilities information. +// +// +// +// Contains the product's signature. +// +// Fixed value PL_CPLD_SIGNATURE of @.CONSTANTS_REGMAP +// +// +// +// +// Contains the CPLD revision (see CPLD_REVISION of @.CONSTANTS_REGMAP) +// +// Contains revision hour code. +// +// +// Contains revision day code. +// +// +// Contains revision month code. +// +// +// Contains revision year code. +// +// +// +// +// +// 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). +// +// +// Contains revision hour code. +// +// +// Contains revision day code. +// +// +// Contains revision month code. +// +// +// Contains revision year code. +// +// +// +// +// Read/write register for general software use. +// +// +// +// +// Git hash of commit used to build this image.{br} +// Value equals 0xDEADBEEF if the git hash was not used during synthesis. +// +// +// +// 0x0 in case the git status was clean{br} +// 0xF in case there were uncommitted changes +// +// +// +// 7 hex digit hash code of the commit +// +// +// +// +// +// +// Register Map to control QSFP LEDs. +// +// +// +// 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. +// +// +// Link LEDs of QSFP port 0 +// +// +// Active LEDs of QSFP port 0 +// +// +// Link LEDs of QSFP port 1 +// +// +// Active LEDs of QSFP port 1 +// +// +// +// +// +// +// Cable present status register. +// +// +// +// Information from FPGA about the cable present status. +// +// +// Set to 1 if cable present in iPass 0 connector. +// +// +// Set to 1 if cable present in iPass 1 connector. +// +// +// +// +//XmlParse xml_off diff --git a/top/x400/cpld/common/ps_cpld_regs.v b/top/x400/cpld/common/ps_cpld_regs.v new file mode 100644 index 0000000..d09c499 --- /dev/null +++ b/top/x400/cpld/common/ps_cpld_regs.v @@ -0,0 +1,405 @@ +// +// 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 +); +`ifdef X410 +`include "../regmap/x410/constants_regmap_utils.vh" +`endif +`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 +// +// +// +// Basic registers containing version and capabilites information. +// +// +// +// Contains the product's signature. +// +// Fixed value PS_CPLD_SIGNATURE of @.CONSTANTS_REGMAP +// +// +// +// +// Contains the CPLD revision (see CPLD_REVISION of @.CONSTANTS_REGMAP). +// +// Contains revision hour code. +// +// +// Contains revision day code. +// +// +// Contains revision month code. +// +// +// Contains revision year code. +// +// +// +// +// +// 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). +// +// +// Contains revision hour code. +// +// +// Contains revision day code. +// +// +// Contains revision month code. +// +// +// Contains revision year code. +// +// +// +// +// Read/write register for general software use. +// +// +// +// +// Git hash of commit used to build this image.{br} +// Value equals 0xDEADBEEF if the git hash was not used during synthesis. +// +// +// +// 0x0 in case the git status was clean{br} +// 0xF in case there were uncommitted changes +// +// +// +// 7 hex digit hash code of the commit +// +// +// +// +// +// +// Register Map to control MB CPLD functions. +// +// +// +// 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. +// +// +// Indicates if a clock is forwarded to DB 0. +// +// +// Indicates if a clock is forwarded to DB 1. +// +// +// Indicates if the PLL reference clock for the PL interface is enabled. +// +// +// Indicates that reset is asserted for DB 0. +// +// +// Indicates that reset is asserted for DB 1. +// +// +// Writing with this flag set enables DB 0 clock forwarding. (may be overwritten by @.DISABLE_CLOCK_DB0) +// +// +// Writing with this flag set enables DB 1 clock forwarding. (may be overwritten by @.DISABLE_CLOCK_DB1) +// +// +// 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) +// +// +// Writing with this flag set disables DB 0 clock forwarding (overrides @.ENABLE_CLOCK_DB0) +// +// +// Writing with this flag set disables DB 1 clock forwarding (overrides @.ENABLE_CLOCK_DB1) +// +// +// Writing with this flag set disables the PLL reference clock (overrides @.ENABLE_PLL_REF_CLOCK). Assert this flag to reconfigure the clock. +// +// +// Writing with this flag set releases DB 0 reset. (may be overwritten by @.ASSERT_RESET_DB0) +// +// +// Writing with this flag set releases DB 1 reset. (may be overwritten by @.ASSERT_RESET_DB1) +// +// +// Writing with this flag set asserts reset for DB 0 (overrides @.RELEASE_RESET_DB0) +// +// +// Writing with this flag set asserts reset for DB 1 (overrides @.RELEASE_RESET_DB1) +// +// +// +// +// +// +// 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. +// +// +// +// 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. +// +// +// +// +// +// +// +// +// Cable present status register. +// +// +// Least significant bytes of 5 byte serial number. +// +// +// Most significant byte of 5 byte serial number. +// +// +// Control CMI communication and delivers information on the CMI link status. +// +// Set if the device is ready to establish a PCI-Express link (affects CMI_CLP_READY bit). +// +// +// 1 if an upstream CMI device has been detected. +// +// +// +// +//XmlParse xml_off diff --git a/top/x400/cpld/common/ps_power_regs.v b/top/x400/cpld/common/ps_power_regs.v new file mode 100644 index 0000000..33965f0 --- /dev/null +++ b/top/x400/cpld/common/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 +// +// +// +// Registers to control power supplies on the motherboard. +// +// +// +// Controls the power supplies for the iPass connectors. +// +// Set to 1 to disable power for both iPass connectors. +// +// +// Clear @.IPASS_POWER_FAULT0. +// +// +// Clear @.IPASS_POWER_FAULT1. +// +// +// +// Asserted signal indicates a power fault in power switch for iPass +// connector 0. Sticky bit. Asserted on occurrence. Reset using +// @.IPASS_CLEAR_POWER_FAULT0. +// +// +// +// +// Asserted signal indicates a power fault in power switch for iPass +// connector 1. Sticky bit. Asserted on occurrence. Reset using +// @.IPASS_CLEAR_POWER_FAULT1. +// +// +// +// +// +// Controls the power supplies for the oscillators. +// +// Enables 5V power switch for the 100 MHz oscillator. +// +// +// Enables 5V power switch for the 122.88 MHz oscillator. +// +// +// +// +//XmlParse xml_off diff --git a/top/x400/cpld/common/pwr_supply_clk_gen.v b/top/x400/cpld/common/pwr_supply_clk_gen.v new file mode 100644 index 0000000..e69db9d --- /dev/null +++ b/top/x400/cpld/common/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/top/x400/cpld/common/quartus/ps_cs_analysis.tcl b/top/x400/cpld/common/quartus/ps_cs_analysis.tcl new file mode 100644 index 0000000..03ff77d --- /dev/null +++ b/top/x400/cpld/common/quartus/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/top/x400/cpld/common/quartus/raw_conversion.cof b/top/x400/cpld/common/quartus/raw_conversion.cof new file mode 100644 index 0000000..87ecb15 --- /dev/null +++ b/top/x400/cpld/common/quartus/raw_conversion.cof @@ -0,0 +1,39 @@ + + + output_files/mb_cpld_converted.pof + 1 + 1 + 14 + + Page_0 + 1 + + output_files/mb_cpld.sof1 + + + 10 + 0 + 0 + 1 + 1 + + 1 + + + 0 + 1 + 0 + 0 + 0 + 0 + 0 + + + 1 + 2 + 0 + -1 + -1 + 1 + + \ No newline at end of file diff --git a/top/x400/cpld/common/reconfig_engine.v b/top/x400/cpld/common/reconfig_engine.v new file mode 100644 index 0000000..0eaf6d9 --- /dev/null +++ b/top/x400/cpld/common/reconfig_engine.v @@ -0,0 +1,1065 @@ +// +// 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" + + // Check MAX10 variant target (10M04, 10M08 or XO3) + `ifdef VARIANT_10M04 + localparam FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT = FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT_10M04; + localparam FLASH_PRIMARY_IMAGE_START_ADDR = FLASH_PRIMARY_IMAGE_START_ADDR_10M04; + localparam FLASH_PRIMARY_IMAGE_END_ADDR = FLASH_PRIMARY_IMAGE_END_ADDR_10M04; + localparam CFM0_WP_OFFSET_MSB = 26; // From Max 10 Flash Memory User Guide. + localparam CFM0_WP_OFFSET_LSB = 24; // From Max 10 Flash Memory User Guide. + `elsif VARIANT_10M08 + localparam FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT = FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT_10M08; + localparam FLASH_PRIMARY_IMAGE_START_ADDR = FLASH_PRIMARY_IMAGE_START_ADDR_10M08; + localparam FLASH_PRIMARY_IMAGE_END_ADDR = FLASH_PRIMARY_IMAGE_END_ADDR_10M08; + localparam CFM0_WP_OFFSET_MSB = 27; // From Max 10 Flash Memory User Guide. + localparam CFM0_WP_OFFSET_LSB = 25; // From Max 10 Flash Memory User Guide. + // The reconfiguration engine via flash is not supported in the XO3 variant. + `elsif VARIANT_XO3 + localparam FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT = 0; + localparam FLASH_PRIMARY_IMAGE_START_ADDR = 0; + localparam FLASH_PRIMARY_IMAGE_END_ADDR = 0; + localparam CFM0_WP_OFFSET_MSB = 0; + localparam CFM0_WP_OFFSET_LSB = 0; + `else + ERROR_MAX10_variant_must_be_defined(); + localparam FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT = FLASH_PRIMARY_IMAGE_START_ADDR_MEM_INIT_10M04; + localparam FLASH_PRIMARY_IMAGE_START_ADDR = FLASH_PRIMARY_IMAGE_START_ADDR_10M04; + localparam FLASH_PRIMARY_IMAGE_END_ADDR = FLASH_PRIMARY_IMAGE_END_ADDR_10M04; + localparam CFM0_WP_OFFSET_MSB = 26; // From Max 10 Flash Memory User Guide. + localparam CFM0_WP_OFFSET_LSB = 24; // From Max 10 Flash Memory User Guide. + `endif + + + //---------------------------------------------------------- + // 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; + // CFM0_WP_OFFSET_MSB and CFM0_WP_OFFSET_LSB are MAX10 variant dependent. + 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 +// +// +// +// 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} +// +// +// +// These values are the start and end address of the CFM image flash +// sector from Intel's On-Chip Flash IP Generator. +// Be aware that three different values exist per each of the two +// supported MAX10 variants: 10M04 and 10M08 +// Note that the values given in the IP generator are byte based where +// the values of this enum are U32 based (divided by 4). +// +// +// +// +// +// +// +// +// +// +// +// +// 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} +// +// +// +// +// 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. +// +// +// +// +// 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} +// +// +// +// +// 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. +// +// +// +// +// 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} +// +// +// +// +// 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. +// +// +// +// +// 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} +// +// +// +// +// This bit is asserted when the flash can hold an image with memory +// initialization. +// +// +// +// +// +// +// 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} +// +// +// +// +// 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} +// +// +// +// +// 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} +// +// +// +// +// 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} +// +// +// +// +// 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} +// +// +// +// +// 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} +// With 10M04 variants, 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. +// With 10M08 variants, the sectors to be erased are 3 to 5 when +// using memory initialization or only sector 5 otherwise. +// +// +// +// +// Strobe this bit to clear a read error. +// +// +// +// +// Strobe this bit to clear a write error. +// +// +// +// +// Strobe this bit to clear an erase error. +// +// +// +// +// +// +// 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. +// +// +// +// +// +// +// 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. +// +// +// +// +// +// +// This register contains data read from the flash address identified +// in FLASH_ADDR_REG after a successful read operation is executed. +// +// +// +// +// +// +// Start address of CFM0 image within flash memory (as defined in FLASH_PRIMARY_IMAGE_ADDR_ENUM). +// +// +// +// +// +// +// Last address of CFM0 image within flash memory (as defined in FLASH_PRIMARY_IMAGE_ADDR_ENUM). +// +// +// +// +// +//XmlParse xml_off diff --git a/top/x400/cpld/common/reset_generator.v b/top/x400/cpld/common/reset_generator.v new file mode 100644 index 0000000..dd3a560 --- /dev/null +++ b/top/x400/cpld/common/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/top/x400/cpld/common/spi_slave.v b/top/x400/cpld/common/spi_slave.v new file mode 100644 index 0000000..ab2f16f --- /dev/null +++ b/top/x400/cpld/common/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/top/x400/cpld/common/spi_slave_to_ctrlport_master.v b/top/x400/cpld/common/spi_slave_to_ctrlport_master.v new file mode 100644 index 0000000..accdc21 --- /dev/null +++ b/top/x400/cpld/common/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 diff --git a/top/x400/cpld/ip/cmi/PcieCmi.vhd b/top/x400/cpld/ip/cmi/PcieCmi.vhd index 88a7da8..f347ad9 100644 --- a/top/x400/cpld/ip/cmi/PcieCmi.vhd +++ b/top/x400/cpld/ip/cmi/PcieCmi.vhd @@ -1,5 +1,5 @@ -- --- Copyright 2022 Ettus Research, a National Instruments Brand +-- Copyright 2023 Ettus Research, a National Instruments Brand -- -- SPDX-License-Identifier: LGPL-3.0-or-later -- diff --git a/top/x400/cpld/ip/cmi/PcieCmiWrapper.vhd b/top/x400/cpld/ip/cmi/PcieCmiWrapper.vhd index c579f5e..2d1c990 100644 --- a/top/x400/cpld/ip/cmi/PcieCmiWrapper.vhd +++ b/top/x400/cpld/ip/cmi/PcieCmiWrapper.vhd @@ -1,5 +1,5 @@ -- --- Copyright 2022 Ettus Research, a National Instruments Brand +-- Copyright 2023 Ettus Research, a National Instruments Brand -- -- SPDX-License-Identifier: LGPL-3.0-or-later -- diff --git a/top/x400/cpld/regmap/i2c_regmap_utils.vh b/top/x400/cpld/regmap/i2c_regmap_utils.vh new file mode 100644 index 0000000..c5c83d0 --- /dev/null +++ b/top/x400/cpld/regmap/i2c_regmap_utils.vh @@ -0,0 +1,57 @@ +// +// Copyright 2022 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 +//=============================================================================== + + // ID EEPROM : 0x0 : 0x50 (ctrlport_to_i2c.v) + // Top Side Temp Sensor : 0x4 : 0x48 (ctrlport_to_i2c.v) + // Bottom Side Temp Sensor : 0x8 : 0x49 (ctrlport_to_i2c.v) + // LED GPIO Expander : 0xC : 0x20 (ctrlport_to_i2c.v) + +//=============================================================================== +// RegTypes +//=============================================================================== + +//=============================================================================== +// Register Group JTAG_REGS TODO update these +//=============================================================================== + + // TX_DATA Register (from ctrlport_to_jtag.v) + localparam ID_EEPROM = '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/top/x400/cpld/regmap/jtag_regmap_utils.vh b/top/x400/cpld/regmap/jtag_regmap_utils.vh index 66e1343..06283df 100644 --- a/top/x400/cpld/regmap/jtag_regmap_utils.vh +++ b/top/x400/cpld/regmap/jtag_regmap_utils.vh @@ -1,5 +1,5 @@ // -// Copyright 2022 Ettus Research, A National Instruments Company +// Copyright 2023 Ettus Research, A National Instruments Company // // SPDX-License-Identifier: LGPL-3.0-or-later // diff --git a/top/x400/cpld/regmap/mb_cpld_ps_regmap_utils.vh b/top/x400/cpld/regmap/mb_cpld_ps_regmap_utils.vh index ecfb0f7..35b7783 100644 --- a/top/x400/cpld/regmap/mb_cpld_ps_regmap_utils.vh +++ b/top/x400/cpld/regmap/mb_cpld_ps_regmap_utils.vh @@ -1,5 +1,5 @@ // -// Copyright 2022 Ettus Research, A National Instruments Company +// Copyright 2023 Ettus Research, A National Instruments Company // // SPDX-License-Identifier: LGPL-3.0-or-later // diff --git a/top/x400/cpld/regmap/pl_cpld_base_regmap_utils.vh b/top/x400/cpld/regmap/pl_cpld_base_regmap_utils.vh index d216382..b066f99 100644 --- a/top/x400/cpld/regmap/pl_cpld_base_regmap_utils.vh +++ b/top/x400/cpld/regmap/pl_cpld_base_regmap_utils.vh @@ -1,5 +1,5 @@ // -// Copyright 2022 Ettus Research, A National Instruments Company +// Copyright 2023 Ettus Research, A National Instruments Company // // SPDX-License-Identifier: LGPL-3.0-or-later // diff --git a/top/x400/cpld/regmap/ps_cpld_base_regmap_utils.vh b/top/x400/cpld/regmap/ps_cpld_base_regmap_utils.vh index ad0d98d..521c8e2 100644 --- a/top/x400/cpld/regmap/ps_cpld_base_regmap_utils.vh +++ b/top/x400/cpld/regmap/ps_cpld_base_regmap_utils.vh @@ -1,5 +1,5 @@ // -// Copyright 2022 Ettus Research, A National Instruments Company +// Copyright 2023 Ettus Research, A National Instruments Company // // SPDX-License-Identifier: LGPL-3.0-or-later // diff --git a/top/x400/cpld/regmap/ps_power_regmap_utils.vh b/top/x400/cpld/regmap/ps_power_regmap_utils.vh index e47a70d..3db4dda 100644 --- a/top/x400/cpld/regmap/ps_power_regmap_utils.vh +++ b/top/x400/cpld/regmap/ps_power_regmap_utils.vh @@ -1,5 +1,5 @@ // -// Copyright 2022 Ettus Research, A National Instruments Company +// Copyright 2023 Ettus Research, A National Instruments Company // // SPDX-License-Identifier: LGPL-3.0-or-later // diff --git a/top/x400/cpld/regmap/reconfig_regmap_utils.vh b/top/x400/cpld/regmap/reconfig_regmap_utils.vh index 96efecf..021e3b5 100644 --- a/top/x400/cpld/regmap/reconfig_regmap_utils.vh +++ b/top/x400/cpld/regmap/reconfig_regmap_utils.vh @@ -1,5 +1,5 @@ // -// Copyright 2022 Ettus Research, A National Instruments Company +// Copyright 2023 Ettus Research, A National Instruments Company // // SPDX-License-Identifier: LGPL-3.0-or-later // diff --git a/top/x400/cpld/regmap/spi_regmap_utils.vh b/top/x400/cpld/regmap/spi_regmap_utils.vh index aca66da..a299e50 100644 --- a/top/x400/cpld/regmap/spi_regmap_utils.vh +++ b/top/x400/cpld/regmap/spi_regmap_utils.vh @@ -1,5 +1,5 @@ // -// Copyright 2022 Ettus Research, A National Instruments Company +// Copyright 2023 Ettus Research, A National Instruments Company // // SPDX-License-Identifier: LGPL-3.0-or-later // diff --git a/top/x400/cpld/regmap/x410/constants_regmap_utils.vh b/top/x400/cpld/regmap/x410/constants_regmap_utils.vh new file mode 100644 index 0000000..492146e --- /dev/null +++ b/top/x400/cpld/regmap/x410/constants_regmap_utils.vh @@ -0,0 +1,28 @@ +// +// Copyright 2023 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 = 'h22080414; // CONSTANTS_ENUM:CPLD_REVISION + localparam PL_CPLD_SIGNATURE = 'h3FDC5C47; // CONSTANTS_ENUM:PL_CPLD_SIGNATURE diff --git a/top/x400/cpld/regmap/x410/mb_cpld_pl_regmap_utils.vh b/top/x400/cpld/regmap/x410/mb_cpld_pl_regmap_utils.vh new file mode 100644 index 0000000..ab925a3 --- /dev/null +++ b/top/x400/cpld/regmap/x410/mb_cpld_pl_regmap_utils.vh @@ -0,0 +1,36 @@ +// +// Copyright 2023 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/top/x400/cpld/sim/led_control_tb.v b/top/x400/cpld/sim/led_control_tb.v new file mode 100644 index 0000000..c44bbf7 --- /dev/null +++ b/top/x400/cpld/sim/led_control_tb.v @@ -0,0 +1,192 @@ +// +// Copyright 2022 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: led_control_tb +// +// Description: +// Simulates LED control module. +// +`timescale 1ns / 1ps + +module led_control_tb(); + +reg clk50; +reg reset_clk50; +reg s_ctrlport_req_wr; +reg s_ctrlport_req_rd; +reg [19:0] s_ctrlport_req_addr; +reg [31:0] s_ctrlport_req_data; + +// Response +wire s_ctrlport_resp_ack; +wire [ 1:0] s_ctrlport_resp_status; +wire [31:0] s_ctrlport_resp_data; + +// LED Control (domain: ctrlport_clk) +wire ch0_rx2_led; +wire ch0_tx_led; +wire ch0_rx_led; +wire ch1_rx2_led; +wire ch1_tx_led; +wire ch1_rx_led; +wire ch2_rx2_led; +wire ch2_tx_led; +wire ch2_rx_led; +wire ch3_rx2_led; +wire ch3_tx_led; +wire ch3_rx_led; + +led_control #( + .BASE_ADDRESS (32'h10) + ) led_control_db1 ( + .ctrlport_clk (clk50), + .ctrlport_rst (reset_clk50), + .s_ctrlport_req_wr (s_ctrlport_req_wr), + .s_ctrlport_req_rd (s_ctrlport_req_rd), + .s_ctrlport_req_addr (s_ctrlport_req_addr), + .s_ctrlport_req_data (s_ctrlport_req_data), + .s_ctrlport_resp_ack (s_ctrlport_resp_ack), + .s_ctrlport_resp_status (s_ctrlport_resp_status), + .s_ctrlport_resp_data (s_ctrlport_resp_data), + .ch0_rx2_led (ch0_rx2_led), + .ch0_tx_led (ch0_tx_led), + .ch0_rx_led (ch0_rx_led), + .ch1_rx2_led (ch1_rx2_led), + .ch1_tx_led (ch1_tx_led), + .ch1_rx_led (ch1_rx_led), + .ch2_rx2_led (ch2_rx2_led), + .ch2_tx_led (ch2_tx_led), + .ch2_rx_led (ch2_rx_led), + .ch3_rx2_led (ch3_rx2_led), + .ch3_tx_led (ch3_tx_led), + .ch3_rx_led (ch3_rx_led) + ); + +always #20 clk50 = ~clk50; + +initial begin + clk50 = 0; + reset_clk50 = 0; + s_ctrlport_req_wr = 0; + s_ctrlport_req_rd = 0; + s_ctrlport_req_addr = 0; + s_ctrlport_req_data = 0; + #100; + s_ctrlport_req_wr = 1; + s_ctrlport_req_addr = 'h10; + s_ctrlport_req_data = 32'hFFFFFFFF; + #100; + s_ctrlport_req_wr = 0; + s_ctrlport_req_rd = 1; + s_ctrlport_req_addr = 'h10; + s_ctrlport_req_data = 32'h00000000; + #100; + s_ctrlport_req_rd = 0; + s_ctrlport_req_wr = 1; + s_ctrlport_req_addr = 'h20; + s_ctrlport_req_data = 32'h00000000; + #100; + s_ctrlport_req_wr = 1; + s_ctrlport_req_addr = 'h10; + s_ctrlport_req_data = 32'h00000000; + #100; + s_ctrlport_req_wr = 1; + s_ctrlport_req_addr = 'h10; + s_ctrlport_req_data = 32'h1; + #100; + s_ctrlport_req_wr = 0; + s_ctrlport_req_rd = 1; + s_ctrlport_req_addr = 'h10; + #100; + s_ctrlport_req_wr = 1; + s_ctrlport_req_addr = 'h10; + s_ctrlport_req_data = 32'h3; + #100; + s_ctrlport_req_wr = 0; + s_ctrlport_req_rd = 1; + s_ctrlport_req_addr = 'h10; + #100; + s_ctrlport_req_wr = 1; + s_ctrlport_req_addr = 'h10; + s_ctrlport_req_data = 32'h7; + #100; + s_ctrlport_req_wr = 0; + s_ctrlport_req_rd = 1; + s_ctrlport_req_addr = 'h10; + #100; + s_ctrlport_req_wr = 1; + s_ctrlport_req_addr = 'h10; + s_ctrlport_req_data = 32'h107; + #100; + s_ctrlport_req_wr = 0; + s_ctrlport_req_rd = 1; + s_ctrlport_req_addr = 'h10; + #100; + s_ctrlport_req_wr = 1; + s_ctrlport_req_addr = 'h10; + s_ctrlport_req_data = 32'h307; + #100; + s_ctrlport_req_wr = 0; + s_ctrlport_req_rd = 1; + s_ctrlport_req_addr = 'h10; + #100; + s_ctrlport_req_wr = 1; + s_ctrlport_req_addr = 'h10; + s_ctrlport_req_data = 32'h707; + #100; + s_ctrlport_req_wr = 0; + s_ctrlport_req_rd = 1; + s_ctrlport_req_addr = 'h10; + #100; + s_ctrlport_req_wr = 1; + s_ctrlport_req_addr = 'h10; + s_ctrlport_req_data = 32'h10707; + #100; + s_ctrlport_req_wr = 0; + s_ctrlport_req_rd = 1; + s_ctrlport_req_addr = 'h10; + #100; + s_ctrlport_req_wr = 1; + s_ctrlport_req_addr = 'h10; + s_ctrlport_req_data = 32'h30707; + #100; + s_ctrlport_req_wr = 0; + s_ctrlport_req_rd = 1; + s_ctrlport_req_addr = 'h10; + #100; + s_ctrlport_req_wr = 1; + s_ctrlport_req_addr = 'h10; + s_ctrlport_req_data = 32'h70707; + #100; + s_ctrlport_req_wr = 0; + s_ctrlport_req_rd = 1; + s_ctrlport_req_addr = 'h10; + #100; + s_ctrlport_req_wr = 1; + s_ctrlport_req_addr = 'h10; + s_ctrlport_req_data = 32'h1070707; + #100; + s_ctrlport_req_wr = 0; + s_ctrlport_req_rd = 1; + s_ctrlport_req_addr = 'h10; + #100; + s_ctrlport_req_wr = 1; + s_ctrlport_req_addr = 'h10; + s_ctrlport_req_data = 32'h3070707; + #100; + s_ctrlport_req_wr = 0; + s_ctrlport_req_rd = 1; + s_ctrlport_req_addr = 'h10; + #100; + s_ctrlport_req_wr = 1; + s_ctrlport_req_addr = 'h10; + s_ctrlport_req_data = 32'h7070707; + #100; + s_ctrlport_req_wr = 0; + s_ctrlport_req_rd = 1; + s_ctrlport_req_addr = 'h10; +end + +endmodule diff --git a/top/x400/cpld/x410/ctrlport_to_jtag.v b/top/x400/cpld/x410/ctrlport_to_jtag.v new file mode 100644 index 0000000..8ef6341 --- /dev/null +++ b/top/x400/cpld/x410/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 +// +// +// +// +// 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. +// +// +// +// +// Data to be transmitted (TDI) +// +// +// +// Data to be transmitted (TMS) +// +// +// +// JTAG module status and control +// +// Clock divider. Resulting JTAG frequency will be f_ctrlport / (2*(prescalar + 1)). See window description for details on the initial/minimum value. +// +// +// (Number of bits - 1) to be transferred +// +// +// 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). +// +// +// Bitq FSM is ready for input (no data transmission in progress). +// +// +// +// +// Received data (TDO) +// +// +// +// +//XmlParse xml_off diff --git a/top/x400/cpld/x410/db_spi_shared_constants.sdc b/top/x400/cpld/x410/db_spi_shared_constants.sdc new file mode 100644 index 0000000..21935c2 --- /dev/null +++ b/top/x400/cpld/x410/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/top/x400/cpld/x410/mb_cpld.sdc b/top/x400/cpld/x410/mb_cpld.sdc new file mode 100644 index 0000000..aa3c3c0 --- /dev/null +++ b/top/x400/cpld/x410/mb_cpld.sdc @@ -0,0 +1,282 @@ +# +# Copyright 2021 Ettus Research, a National Instruments Brand +# +# SPDX-License-Identifier: LGPL-3.0-or-later +# +# Description: +# +# Timing constraints for the x410's motherboard CPLD. +# + + +##################################################################### +# 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 + + + +##################################################################### +# 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 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 -------------------------------------------------- +# MISO input @ MB CPLD -------------------------------------------------- +# 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 + +##################################################################### +# DB specific LED constraints +##################################################################### + +# 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 + +##################################################################### +# MB CPLD PS SPI passthrough x410 specific +##################################################################### +# +# Get port to apply the multi-cycle constraint for x410 specific port. +# see common.sdc for more extensive doc and explanation +set binary_cs_ports_ti [get_ports {DB_CALEEPROM_CS_N[*]}] +set_multicycle_path -setup -start -to $binary_cs_ports_ti $ps_spi_setup_multicycle +set_multicycle_path -hold -start -to $binary_cs_ports_ti $ps_spi_hold_multicycle + +###### 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 + + diff --git a/top/x400/cpld/x410/mb_cpld.v b/top/x400/cpld/x410/mb_cpld.v new file mode 100644 index 0000000..f39a8e8 --- /dev/null +++ b/top/x400/cpld/x410/mb_cpld.v @@ -0,0 +1,1048 @@ +// +// 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 X410 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/x410/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 + //--------------------------------------------------------------------------- + +`ifdef MFG_SUPPORT + + assign PWR_SUPPLY_CLK_CORE = 1'b0; + assign PWR_SUPPLY_CLK_DDR4_S = 1'b0; + assign PWR_SUPPLY_CLK_DDR4_N = 1'b0; + assign PWR_SUPPLY_CLK_0P9V = 1'b0; + assign PWR_SUPPLY_CLK_1P8V = 1'b0; + assign PWR_SUPPLY_CLK_2P5V = 1'b0; + assign PWR_SUPPLY_CLK_3P3V = 1'b0; + assign PWR_SUPPLY_CLK_3P6V = 1'b0; + +`else + + // 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; + +`endif + + //--------------------------------------------------------------------------- + // 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 +// +// +// +// +// +// +// +// +// This register map is available using the PS CPLD SPI interface. +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// 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. +// +// +// +// +// +// 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.** +// +// +// +// +// 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.** +// +// +// +// +// +// +// +// Basic registers containing version and capabilities information. +// + +// +// +// This enumeration is used to create the constants held in the basic registers. +// +// +// +// +// +// +// +// +//XmlParse xml_off diff --git a/top/x400/cpld/x410/quartus/mb_cpld.qpf b/top/x400/cpld/x410/quartus/mb_cpld.qpf new file mode 100644 index 0000000..0e34c0a --- /dev/null +++ b/top/x400/cpld/x410/quartus/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/top/x400/cpld/x410/quartus/mb_cpld.qsf b/top/x400/cpld/x410/quartus/mb_cpld.qsf new file mode 100644 index 0000000..f2aec5a --- /dev/null +++ b/top/x400/cpld/x410/quartus/mb_cpld.qsf @@ -0,0 +1,433 @@ +# -------------------------------------------------------------------------- # +# +# 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/on_chip_flash/on_chip_flash.qsys +set_global_assignment -name SDC_FILE ../common/common.sdc +set_global_assignment -name SDC_FILE ../x410/db_spi_shared_constants.sdc +set_global_assignment -name SDC_FILE ../x410/mb_cpld.sdc +set_global_assignment -name VERILOG_FILE ../x410/mb_cpld.v +set_global_assignment -name VERILOG_FILE ../x410/ctrlport_to_jtag.v +set_global_assignment -name VERILOG_FILE ../common/reconfig_engine.v +set_global_assignment -name VERILOG_FILE ../common/ctrlport_to_spi.v +set_global_assignment -name VERILOG_FILE ../common/pl_cpld_regs.v +set_global_assignment -name VERILOG_FILE ../common/pwr_supply_clk_gen.v +set_global_assignment -name VERILOG_FILE ../common/ps_cpld_regs.v +set_global_assignment -name VERILOG_FILE ../common/ps_power_regs.v +set_global_assignment -name VERILOG_FILE ../common/reset_generator.v +set_global_assignment -name VERILOG_FILE ../common/spi_slave_to_ctrlport_master.v +set_global_assignment -name VERILOG_FILE ../common/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"