diff --git a/src/gateware/zc706.py b/src/gateware/zc706.py index 395d6c6..3832f90 100755 --- a/src/gateware/zc706.py +++ b/src/gateware/zc706.py @@ -25,6 +25,8 @@ import analyzer import acpki import drtio_aux_controller import zynq_clocking +import cxp_4r_fmc +import cxp from config import write_csr_file, write_mem_file, write_rustc_cfg_file class SMAClkinForward(Module): @@ -138,7 +140,7 @@ class ZC706(SoCCore): platform.add_extension(si5324_fmc33) self.comb += platform.request("si5324_33").rst_n.eq(1) - cdr_clk = Signal() + self.cdr_clk = Signal() cdr_clk_buf = Signal() si5324_out = platform.request("si5324_clkout") platform.add_period_constraint(si5324_out.p, 8.0) @@ -146,11 +148,11 @@ class ZC706(SoCCore): Instance("IBUFDS_GTE2", i_CEB=0, i_I=si5324_out.p, i_IB=si5324_out.n, - o_O=cdr_clk, + o_O=self.cdr_clk, p_CLKCM_CFG="TRUE", p_CLKRCV_TRST="TRUE", 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["SI5324_AS_SYNTHESIZER"] = None @@ -652,6 +654,129 @@ class _NIST_QC2_RTIO: 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): def __init__(self, acpki, drtio100mhz): ZC706.__init__(self, acpki) @@ -684,8 +809,13 @@ class NIST_QC2_Satellite(_SatelliteBase, _NIST_QC2_RTIO): _SatelliteBase.__init__(self, acpki, drtio100mhz) _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, - NIST_QC2, NIST_QC2_Master, NIST_QC2_Satellite]} + NIST_QC2, NIST_QC2_Master, NIST_QC2_Satellite, CXP_Demo]} def main(): parser = argparse.ArgumentParser(