kasli soc: add coaxpress-sfp support to standalone

cxp-sfp: add IBUFDS_GTE2
cxp-sfp: add CXPGrabber with its memory region and CSR
cxp-sfp: add `CXPGrabber` rtio interface to self.rtio_channels
cxp-sfp: add timing requirement for cd_cxp_gt_rx
master/satellite: raise warning when using coaxpress-sfp
This commit is contained in:
morgan 2025-04-24 14:47:50 +08:00
parent 04856e66d0
commit 0717003c42

View File

@ -15,7 +15,7 @@ from misoc.cores import virtual_leds
from artiq.coredevice import jsondesc
from artiq.gateware import rtio, eem_7series
from artiq.gateware.rtio.xilinx_clocking import fix_serdes_timing_path
from artiq.gateware.rtio.phy import ttl_simple
from artiq.gateware.rtio.phy import ttl_simple, cxp_grabber
from artiq.gateware.drtio.transceiver import gtx_7series, eem_serdes
from artiq.gateware.drtio.siphaser import SiPhaser7Series
from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer
@ -161,12 +161,20 @@ class GenericStandalone(SoCCore):
self.config["HAS_SI5324"] = None
self.config["SI5324_SOFT_RESET"] = None
self.rtio_channels = []
has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"])
if has_grabber:
self.grabber_csr_group = []
eem_7series.add_peripherals(self, description["peripherals"], iostandard=eem_iostandard)
has_grabber = False
eem_peripherals = []
for peripheral in description["peripherals"]:
if peripheral["type"] == "coaxpress_sfp":
self.add_coaxpress_sfp(clk_freq, peripheral["roi_engine_count"])
elif peripheral["type"] == "grabber":
has_grabber = True
self.grabber_csr_group = []
eem_peripherals.append(peripheral)
else:
eem_peripherals.append(peripheral)
eem_7series.add_peripherals(self, eem_peripherals, iostandard=eem_iostandard)
for i in (0, 1):
print("USER LED at RTIO channel 0x{:06x}".format(len(self.rtio_channels)))
user_led = self.platform.request("user_led", i)
@ -216,6 +224,46 @@ class GenericStandalone(SoCCore):
self.platform.add_false_path_constraints(
self.sys_crg.cd_sys.clk, getattr(self, grabber).deserializer.cd_cl.clk)
def add_coaxpress_sfp(self, clk_freq, roi_engine_count):
refclk = Signal()
gt_refclk_pad = self.platform.request("clk_gtp")
self.platform.add_period_constraint(gt_refclk_pad.p, 8.0)
self.specials += Instance("IBUFDS_GTE2",
i_CEB=0,
i_I=gt_refclk_pad.p,
i_IB=gt_refclk_pad.n,
o_O=refclk,
p_CLKCM_CFG="TRUE",
p_CLKRCV_TRST="TRUE",
p_CLKSWING_CFG=3
)
sfp_slot = 0
self.submodules.cxp_grabber = cxp_grabber.CXPGrabber(
refclk=refclk,
gt_pads=[self.platform.request("sfp", sfp_slot)],
sys_clk_freq=clk_freq,
roi_engine_count=roi_engine_count
)
mem_size = self.cxp_grabber.core.get_mem_size()
# upper half is tx while lower half is rx
memory_address = self.axi2csr.register_port(self.cxp_grabber.core.get_tx_port(), mem_size)
self.axi2csr.register_port(self.cxp_grabber.core.get_rx_port(), mem_size)
self.add_memory_region("cxp_mem", self.mem_map["csr"] + memory_address, mem_size * 2)
self.csr_devices.append("cxp_grabber")
print("CoaXPress-SFP (SFP{}) at RTIO channel 0x{:06x}".format(sfp_slot, len(self.rtio_channels)))
self.rtio_channels += [
rtio.Channel(self.cxp_grabber.trigger),
rtio.Channel(self.cxp_grabber.config),
rtio.Channel(self.cxp_grabber.gate_data),
]
# max freq of cxp_gt_rx = linerate/internal_datawidth = 12.5Gbps/40 = 312.5MHz
rx = self.cxp_grabber.phy.phys[0]
self.platform.add_period_constraint(rx.gtx.cd_cxp_gt_rx.clk, 3.2)
# constraint the clk path
self.platform.add_false_path_constraints(self.sys_crg.cd_sys.clk, rx.gtx.cd_cxp_gt_rx.clk)
class GenericMaster(SoCCore):
def __init__(self, description, acpki=False):
@ -690,6 +738,9 @@ def main():
args = parser.parse_args()
description = jsondesc.load(args.description)
has_coaxpress_sfp = any(peripheral["type"] == "coaxpress_sfp" for peripheral in description["peripherals"])
if has_coaxpress_sfp and description["drtio_role"] != "standalone":
raise ValueError("CoaXPress-SFP requires free SFP ports, please switch role to standalone")
if description["target"] != "kasli_soc":
raise ValueError("Description is for a different target")