Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add constraint for ref clock on FPGAs to be related to core clock #157

Merged
merged 3 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion adijif/clocks/hmc7044.py
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ def set_requested_clocks(
od = self.model.Intermediate(eo * odd + (1 - eo) * even * 2)

elif self.solver == "CPLEX":
od = self._convert_input(self._d, "d_" + str(out_freq))
od = self._convert_input(self._d, f"d_{out_freq}_{d_n}")

self._add_equation(
[
Expand Down
3 changes: 3 additions & 0 deletions adijif/converters/ad9081.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ class ad9081_rx(adc, ad9081_core):
"""AD9081 Receive model."""

name = "AD9081_RX"
converter_type = "adc"

converter_clock_min = 1.45e9
converter_clock_max = 4e9
Expand Down Expand Up @@ -393,6 +394,7 @@ class ad9081_tx(dac, ad9081_core):
"""AD9081 Transmit model."""

name = "AD9081_TX"
converter_type = "dac"

converter_clock_min = 2.9e9
converter_clock_max = 12e9
Expand Down Expand Up @@ -480,6 +482,7 @@ class ad9081(ad9081_core):
converter_clock_max = ad9081_rx.converter_clock_max
quick_configuration_modes: Dict[str, Any] = {}
_nested = ["adc", "dac"]
converter_type = "adc_dac"

def __init__(
self, model: Union[GEKKO, CpoModel] = None, solver: str = None
Expand Down
1 change: 1 addition & 0 deletions adijif/converters/ad9144.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class ad9144(ad9144_bf):
"""

name = "AD9144"
converter_type = "DAC"

# JESD parameters
_jesd_params_to_skip_check = ["DualLink", "K"]
Expand Down
1 change: 1 addition & 0 deletions adijif/converters/ad9680.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class ad9680(ad9680_bf):
"""

name = "AD9680"
converter_type = "adc"

# JESD parameters
_jesd_params_to_skip_check = ["DualLink", "CS", "N", "HD"]
Expand Down
3 changes: 3 additions & 0 deletions adijif/converters/adrv9009.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ class adrv9009_rx(adc, adrv9009_clock_common, adrv9009_core):

quick_configuration_modes = {"jesd204b": quick_configuration_modes_rx}
name = "ADRV9009_RX"
converter_type = "adc"

# JESD configurations
K_available = [*np.arange(1, 32 + 1)]
Expand Down Expand Up @@ -232,6 +233,7 @@ class adrv9009_tx(dac, adrv9009_clock_common, adrv9009_core):

quick_configuration_modes = {"jesd204b": quick_configuration_modes_tx}
name = "ADRV9009_TX"
converter_type = "dac"

# JESD configurations
K_available = [*np.arange(1, 32 + 1)]
Expand Down Expand Up @@ -269,6 +271,7 @@ class adrv9009(adrv9009_core):
name = "ADRV9009"
solver = "CPLEX"
_nested = ["adc", "dac"]
converter_type = "adc_dac"

def __init__(
self, model: Union[GEKKO, CpoModel] = None, solver: str = None
Expand Down
10 changes: 10 additions & 0 deletions adijif/converters/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,16 @@ def get_current_jesd_mode_settings(self) -> Dict:
current_config[attr] = getattr(self, attr)
return current_config

@property
@abstractmethod
def converter_type(self) -> str:
"""Type of converter. ADC or DAC.

Returns:
str: Type of converter
"""
raise NotImplementedError

@property
@abstractmethod
def clocking_option_available(self) -> List[str]:
Expand Down
53 changes: 53 additions & 0 deletions adijif/fpgas/xilinx.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ class xilinx(xilinx_bf):
cases, the ref clock and device clock can be the same."""
force_separate_device_clock: bool = False

"""Constrain reference clock to be specific values. Options:
- CORE_CLOCK: Make reference clock the same as the core clock (LR/40 or LR/66)
- CORE_CLOCK_DIV2: Make reference clock the same as the core clock divided by 2
- Unconstrained: No constraints on reference clock. Simply meet PLL constraints
"""
_ref_clock_constraint = "CORE_CLOCK"

max_serdes_lanes = 24

hdl_core_version = 2.1
Expand Down Expand Up @@ -122,6 +129,42 @@ class xilinx(xilinx_bf):

configs = [] # type: ignore

@property
def ref_clock_constraint(self) -> str:
"""Get reference clock constraint.

Reference clock constraint can be set to:
- CORE_CLOCK: Make reference clock the same as the core clock (LR/40 or LR/66)
- CORE_CLOCK_DIV2: Make reference clock the same as the core clock divided by 2
- Unconstrained: No constraints on reference clock. Simply meet PLL constraints

Returns:
str: Reference clock constraint.
"""
return self._ref_clock_constraint

@ref_clock_constraint.setter
def ref_clock_constraint(self, value: str) -> None:
"""Set reference clock constraint.

Reference clock constraint can be set to:
- CORE_CLOCK: Make reference clock the same as the core clock (LR/40 or LR/66)
- CORE_CLOCK_DIV2: Make reference clock the same as the core clock divided by 2
- Unconstrained: No constraints on reference clock. Simply meet PLL constraints

Args:
value (str): Reference clock constraint.

Raises:
Exception: Invalid ref_clock_constraint selection.
"""
if value not in ["CORE_CLOCK", "CORE_CLOCK_DIV2", "Unconstrained"]:
raise Exception(
f"Invalid ref_clock_constraint {value}, "
+ "options are CORE_CLOCK, CORE_CLOCK_DIV2, Unconstrained"
)
self._ref_clock_constraint = value

@property
def out_clk_select(self) -> Union[int, float]:
"""Get current PLL clock output mux options for link layer clock.
Expand Down Expand Up @@ -848,6 +891,16 @@ def _setup_quad_tile(
[fpga_ref >= self.ref_clock_min, fpga_ref <= self.ref_clock_max]
)

if converter.jesd_class == "jesd204b":
core_clock = converter.bit_clock / 40
else:
core_clock = converter.bit_clock / 66

if self.ref_clock_constraint == "CORE_CLOCK":
self._add_equation([fpga_ref == core_clock])
elif self.ref_clock_constraint == "CORE_CLOCK_DIV2":
self._add_equation([fpga_ref == core_clock / 2])

# CPLL -> VCO = FPGA_REF * N1*N2/M
# PLLOUT = VCO
# LR = PLLOUT * 2/D
Expand Down
24 changes: 20 additions & 4 deletions adijif/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,17 +314,33 @@ def solve(self) -> Dict:
# Setup clock chip
self.clock._setup(self.vcxo)
self.fpga.configs = [] # reset
serdes_used: float = 0
serdes_used_tx: int = 0
serdes_used_rx: int = 0
sys_refs = []

for conv in convs:
if conv._nested: # MxFE, Transceivers
for name in conv._nested:
serdes_used += getattr(conv, name).L
ctype = getattr(conv, name).converter_type.lower()
if ctype == "adc":
serdes_used_rx += getattr(conv, name).L
elif ctype == "dac":
serdes_used_tx += getattr(conv, name).L
else:
raise Exception(f"Unknown converter type {ctype}")
else:
serdes_used += conv.L
ctype = conv.converter_type.lower()
if ctype == "adc":
serdes_used_rx += conv.L
elif ctype == "dac":
serdes_used_tx += conv.L
else:
raise Exception(f"Unknown converter type: {ctype}")

if serdes_used > self.fpga.max_serdes_lanes:
if (
serdes_used_rx > self.fpga.max_serdes_lanes
or serdes_used_tx > self.fpga.max_serdes_lanes
):
raise Exception(
"Max SERDES lanes exceeded. {} only available".format(
self.fpga.max_serdes_lanes
Expand Down
1 change: 1 addition & 0 deletions examples/ad9081_rx_hmc7044_ext_pll_adf4371.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

sys = adijif.system("ad9081", "hmc7044", "xilinx", vcxo, solver="CPLEX")
sys.fpga.setup_by_dev_kit_name("zcu102")
sys.fpga.ref_clock_constraint = "Unconstrained"
sys.fpga.sys_clk_select = "GTH34_SYSCLK_QPLL0" # Use faster QPLL
sys.fpga.out_clk_select = "XCVR_PROGDIV_CLK" # force reference to be core clock rate
sys.converter.adc.sample_clock = 2900000000 / (8 * 6)
Expand Down
1 change: 1 addition & 0 deletions examples/ad9081_rxtx_hmc7044.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

sys = adijif.system("ad9081", "hmc7044", "xilinx", vcxo, solver="CPLEX")
sys.fpga.setup_by_dev_kit_name("zcu102")
sys.fpga.ref_clock_constraint = "Unconstrained"
sys.fpga.sys_clk_select = "GTH34_SYSCLK_QPLL0" # Use faster QPLL
sys.converter.clocking_option = "integrated_pll"
sys.fpga.out_clk_select = "XCVR_PROGDIV_CLK" # force reference to be core clock rate
Expand Down
1 change: 1 addition & 0 deletions examples/ad9082_rxtx_hmc7044.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

sys = adijif.system("ad9082", "hmc7044", "xilinx", vcxo, solver="CPLEX")
sys.fpga.setup_by_dev_kit_name("zcu102")
sys.fpga.ref_clock_constraint = "Unconstrained"
sys.fpga.sys_clk_select = "GTH34_SYSCLK_QPLL0" # Use faster QPLL
sys.converter.clocking_option = "integrated_pll"
sys.fpga.out_clk_select = "XCVR_PROGDIV_CLK" # force reference to be core clock rate
Expand Down
1 change: 1 addition & 0 deletions tests/test_adf4371.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def test_adf4371_ad9081_sys_example():

sys = adijif.system("ad9081", "hmc7044", "xilinx", vcxo, solver="CPLEX")
sys.fpga.setup_by_dev_kit_name("zcu102")
sys.fpga.ref_clock_constraint = "Unconstrained"
sys.fpga.sys_clk_select = "GTH34_SYSCLK_QPLL0" # Use faster QPLL
sys.fpga.out_clk_select = (
"XCVR_PROGDIV_CLK" # force reference to be core clock rate
Expand Down
2 changes: 1 addition & 1 deletion tests/test_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def test_nested_converter_lane_count_valid():


def test_nested_converter_lane_count_exceeds_fpga_lane_count():
fpga_L = 2
fpga_L = 1

sys = adijif.system("adrv9009", "ad9528", "xilinx", 122.88e6)

Expand Down
Loading