1
0
Fork 0

zc706: add CXP_DEMO variant

zc706: add fmc pads
zc706: add constraint to fix comma alignment & setup/hold time issue
zc706: add csr & mem group for cxp
zc706: add CXP to rtio_channel
This commit is contained in:
morgan 2024-06-03 15:58:44 +08:00
parent 4f5dbf05a4
commit e9750d1848
1 changed files with 134 additions and 4 deletions

View File

@ -25,6 +25,8 @@ import analyzer
import acpki import acpki
import drtio_aux_controller import drtio_aux_controller
import zynq_clocking import zynq_clocking
import cxp_4r_fmc
import cxp
from config import write_csr_file, write_mem_file, write_rustc_cfg_file from config import write_csr_file, write_mem_file, write_rustc_cfg_file
class SMAClkinForward(Module): class SMAClkinForward(Module):
@ -138,7 +140,7 @@ class ZC706(SoCCore):
platform.add_extension(si5324_fmc33) platform.add_extension(si5324_fmc33)
self.comb += platform.request("si5324_33").rst_n.eq(1) self.comb += platform.request("si5324_33").rst_n.eq(1)
cdr_clk = Signal() self.cdr_clk = Signal()
cdr_clk_buf = Signal() cdr_clk_buf = Signal()
si5324_out = platform.request("si5324_clkout") si5324_out = platform.request("si5324_clkout")
platform.add_period_constraint(si5324_out.p, 8.0) platform.add_period_constraint(si5324_out.p, 8.0)
@ -146,11 +148,11 @@ class ZC706(SoCCore):
Instance("IBUFDS_GTE2", Instance("IBUFDS_GTE2",
i_CEB=0, i_CEB=0,
i_I=si5324_out.p, i_IB=si5324_out.n, i_I=si5324_out.p, i_IB=si5324_out.n,
o_O=cdr_clk, o_O=self.cdr_clk,
p_CLKCM_CFG="TRUE", p_CLKCM_CFG="TRUE",
p_CLKRCV_TRST="TRUE", p_CLKRCV_TRST="TRUE",
p_CLKSWING_CFG=3), p_CLKSWING_CFG=3),
Instance("BUFG", i_I=cdr_clk, o_O=cdr_clk_buf) Instance("BUFG", i_I=self.cdr_clk, o_O=cdr_clk_buf)
] ]
self.config["HAS_SI5324"] = None self.config["HAS_SI5324"] = None
self.config["SI5324_AS_SYNTHESIZER"] = None self.config["SI5324_AS_SYNTHESIZER"] = None
@ -652,6 +654,129 @@ class _NIST_QC2_RTIO:
self.add_rtio(rtio_channels) self.add_rtio(rtio_channels)
class CXP_FMC():
"""
CoaXpress FMC with 4 CXP channel and 1 SMA trigger
"""
def __init__(self):
platform = self.platform
platform.add_extension(cxp_4r_fmc.fmc_adapter_io)
platform.add_extension(leds_fmc33)
debug_sma = [
("user_sma_clock_33", 0,
Subsignal("p_tx", Pins("AD18"), IOStandard("LVCMOS33")),
Subsignal("n_rx", Pins("AD19"), IOStandard("LVCMOS33")),
),
]
pmod1_33 = [
("pmod1_33", 0, Pins("AJ21"), IOStandard("LVCMOS33")),
("pmod1_33", 1, Pins("AK21"), IOStandard("LVCMOS33")),
("pmod1_33", 2, Pins("AB21"), IOStandard("LVCMOS33")),
("pmod1_33", 3, Pins("AB16"), IOStandard("LVCMOS33")),
("pmod1_33", 4, Pins("Y20"), IOStandard("LVCMOS33")),
("pmod1_33", 5, Pins("AA20"), IOStandard("LVCMOS33")),
("pmod1_33", 6, Pins("AC18"), IOStandard("LVCMOS33")),
("pmod1_33", 7, Pins("AC19"), IOStandard("LVCMOS33")),
]
platform.add_extension(debug_sma)
platform.add_extension(pmod1_33)
debug_sma_pad = platform.request("user_sma_clock_33")
pmod_pads = [platform.request("pmod1_33", i) for i in range(8)]
clk_freq = 125e6
links = 1
cxp_downconn_pads = [platform.request("CXP_HS", i) for i in range(links)]
cxp_upconn_pads = [platform.request("CXP_LS", i) for i in range(links)]
self.submodules.cxp_phys = cxp_phys = cxp.CXP_PHYS(
refclk=self.cdr_clk,
upconn_pads=cxp_upconn_pads,
downconn_pads=cxp_downconn_pads,
sys_clk_freq=clk_freq,
debug_sma=debug_sma_pad,
pmod_pads = pmod_pads
)
self.csr_devices.append("cxp_phys")
rtio_channels = []
cxp_csr_group = []
cxp_tx_mem_group = []
cxp_rx_mem_group = []
cxp_loopback_mem_group = []
for i, (tx, rx) in enumerate(zip(cxp_phys.upconn.tx_phys, cxp_phys.downconn.rx_phys)):
cxp_name = "cxp" + str(i)
cdr = ClockDomainsRenamer({"cxp_gtx_rx": "cxp_gtx_rx" + str(i)})
if i == 0:
cxp_interface = cdr(cxp.CXP_Master(tx, rx, debug_sma_pad, pmod_pads))
# Add rtlink for Master Connection only
print("CoaXPress at RTIO channel 0x{:06x}".format(len(rtio_channels)))
rtio_channels.append(rtio.Channel.from_phy(cxp_interface))
else:
cxp_interface = cdr(cxp.CXP_Extension(tx, rx, debug_sma_pad, pmod_pads))
setattr(self.submodules, cxp_name, cxp_interface)
self.csr_devices.append(cxp_name)
cxp_csr_group.append(cxp_name)
# Add memory group
rx_mem_name = "cxp_rx" + str(i) + "_mem"
rx_mem_size = cxp_interface.get_rx_mem_size()
cxp_rx_mem_group.append(rx_mem_name)
memory_address = self.axi2csr.register_port(cxp_interface.get_rx_port(), rx_mem_size)
self.add_memory_region(rx_mem_name, self.mem_map["csr"] + memory_address, rx_mem_size)
tx_mem_name = "cxp_tx" + str(i) + "_mem"
tx_mem_size = cxp_interface.get_tx_mem_size()
cxp_tx_mem_group.append(tx_mem_name)
memory_address = self.axi2csr.register_port(cxp_interface.get_tx_port(), tx_mem_size)
self.add_memory_region(tx_mem_name, self.mem_map["csr"] + memory_address, tx_mem_size)
# DEBUG loopback tx memory
loopback_mem_name = "cxp_loopback_tx" + str(i) + "_mem"
loopback_mem_size = cxp_interface.get_loopback_tx_mem_size()
cxp_loopback_mem_group.append(loopback_mem_name)
memory_address = self.axi2csr.register_port(cxp_interface.get_loopback_tx_port(), loopback_mem_size)
self.add_memory_region(loopback_mem_name, self.mem_map["csr"] + memory_address, loopback_mem_size)
self.add_memory_group("cxp_tx_mem", cxp_tx_mem_group)
self.add_memory_group("cxp_rx_mem", cxp_rx_mem_group)
self.add_memory_group("cxp_loopback_mem", cxp_loopback_mem_group)
self.add_csr_group("cxp", cxp_csr_group)
# max freq of cxp_gtx_rx = linerate/internal_datawidth = 12.5Gbps/40 = 312.5MHz
# zc706 use speed grade 2 which only support up to 10.3125Gbps (4ns)
# pushing to 12.5Gbps (3.2ns) will result in Pulse width violation but setup/hold times are met
for rx in cxp_phys.downconn.rx_phys :
platform.add_period_constraint(rx.gtx.cd_cxp_gtx_tx.clk, 3.2)
platform.add_period_constraint(rx.gtx.cd_cxp_gtx_rx.clk, 3.2)
# constraint the CLK path
platform.add_false_path_constraints(self.sys_crg.cd_sys.clk, rx.gtx.cd_cxp_gtx_tx.clk, rx.gtx.cd_cxp_gtx_rx.clk)
# FIXME remove this placeholder RTIO channel
# There are too few RTIO channels and cannot be compiled (adr width issue of the lane distributor)
# see https://github.com/m-labs/artiq/pull/2158 for similar issue
print("USER LED at RTIO channel 0x{:06x}".format(len(rtio_channels)))
phy = ttl_simple.Output(self.platform.request("user_led_33", 0))
self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy))
self.config["HAS_RTIO_LOG"] = None
rtio_channels.append(rtio.LogChannel())
self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels)
self.add_rtio(rtio_channels)
class NIST_CLOCK(ZC706, _NIST_CLOCK_RTIO): class NIST_CLOCK(ZC706, _NIST_CLOCK_RTIO):
def __init__(self, acpki, drtio100mhz): def __init__(self, acpki, drtio100mhz):
ZC706.__init__(self, acpki) ZC706.__init__(self, acpki)
@ -684,8 +809,13 @@ class NIST_QC2_Satellite(_SatelliteBase, _NIST_QC2_RTIO):
_SatelliteBase.__init__(self, acpki, drtio100mhz) _SatelliteBase.__init__(self, acpki, drtio100mhz)
_NIST_QC2_RTIO.__init__(self) _NIST_QC2_RTIO.__init__(self)
class CXP_Demo(ZC706, CXP_FMC):
def __init__(self, acpki, drtio100mhz):
ZC706.__init__(self, acpki)
CXP_FMC.__init__(self)
VARIANTS = {cls.__name__.lower(): cls for cls in [NIST_CLOCK, NIST_CLOCK_Master, NIST_CLOCK_Satellite, VARIANTS = {cls.__name__.lower(): cls for cls in [NIST_CLOCK, NIST_CLOCK_Master, NIST_CLOCK_Satellite,
NIST_QC2, NIST_QC2_Master, NIST_QC2_Satellite]} NIST_QC2, NIST_QC2_Master, NIST_QC2_Satellite, CXP_Demo]}
def main(): def main():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(