DRTIO: RTIO/SYS clock merge, KC705

This commit is contained in:
Spaqin 2023-01-06 07:13:38 +08:00 committed by GitHub
parent 17efc28dbe
commit 3838dfc1d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 102 additions and 180 deletions

View File

@ -63,40 +63,12 @@ fn get_rtio_clock_cfg() -> RtioClock {
#[cfg(has_rtio_crg)]
pub mod crg {
#[cfg(has_rtio_clock_switch)]
use super::RtioClock;
use board_misoc::{clock, csr};
pub fn check() -> bool {
unsafe { csr::rtio_crg::pll_locked_read() != 0 }
}
#[cfg(has_rtio_clock_switch)]
pub fn init(clk: RtioClock) -> bool {
let clk_sel: u8 = match clk {
RtioClock::Ext0_Bypass => {
info!("Using external clock");
1
},
RtioClock::Int_125 => {
info!("Using internal RTIO clock");
0
},
_ => {
warn!("rtio_clock setting '{:?}' is not supported. Using default internal RTIO clock instead", clk);
0
}
};
unsafe {
csr::rtio_crg::pll_reset_write(1);
csr::rtio_crg::clock_sel_write(clk_sel);
csr::rtio_crg::pll_reset_write(0);
}
clock::spin_us(150);
return check()
}
#[cfg(not(has_rtio_clock_switch))]
pub fn init() -> bool {
info!("Using internal RTIO clock");
unsafe {
@ -223,7 +195,7 @@ fn setup_si5324(clock_cfg: RtioClock) {
#[cfg(soc_platform = "metlino")]
let si5324_ext_input = si5324::Input::Ckin2;
#[cfg(soc_platform = "kc705")]
let si5324_ext_input = si5324::Input::Ckin2;
let si5324_ext_input = si5324::Input::Ckin1;
match clock_cfg {
RtioClock::Ext0_Bypass => {
info!("using external RTIO clock with PLL bypass");
@ -277,9 +249,6 @@ pub fn init() {
#[cfg(has_rtio_crg)]
{
#[cfg(has_rtio_clock_switch)]
let result = crg::init(clock_cfg);
#[cfg(not(has_rtio_clock_switch))]
let result = crg::init();
if !result {
error!("RTIO clock failed");

View File

@ -426,19 +426,6 @@ fn hardware_tick(ts: &mut u64) {
}
}
#[cfg(all(has_si5324, rtio_frequency = "150.0"))]
const SI5324_SETTINGS: si5324::FrequencySettings
= si5324::FrequencySettings {
n1_hs : 6,
nc1_ls : 6,
n2_hs : 10,
n2_ls : 270,
n31 : 75,
n32 : 75,
bwsel : 4,
crystal_ref: true
};
#[cfg(all(has_si5324, rtio_frequency = "125.0"))]
const SI5324_SETTINGS: si5324::FrequencySettings
= si5324::FrequencySettings {

View File

@ -1,5 +1,6 @@
from migen import *
from migen.genlib.resetsync import AsyncResetSynchronizer
from migen.genlib.cdc import MultiReg
from misoc.cores.code_8b10b import Encoder, Decoder
from misoc.interconnect.csr import *
@ -16,13 +17,12 @@ class GTX_20X(Module):
# * GTX PLL frequency @ 2.5GHz
# * GTX line rate (TX & RX) @ 2.5Gb/s
# * GTX TX/RX USRCLK @ 125MHz == coarse RTIO frequency
def __init__(self, refclk, pads, sys_clk_freq, rtio_clk_freq=125e6, tx_mode="single", rx_mode="single"):
def __init__(self, refclk, pads, clk_freq=125e6, tx_mode="single", rx_mode="single"):
assert tx_mode in ["single", "master", "slave"]
assert rx_mode in ["single", "master", "slave"]
self.txenable = Signal()
self.submodules.encoder = ClockDomainsRenamer("rtio_tx")(
Encoder(2, True))
self.submodules.encoder = Encoder(2, True)
self.submodules.decoders = [ClockDomainsRenamer("rtio_rx")(
(Decoder(True))) for _ in range(2)]
self.rx_ready = Signal()
@ -36,11 +36,11 @@ class GTX_20X(Module):
cpllreset = Signal()
cplllock = Signal()
# TX generates RTIO clock, init must be in system domain
self.submodules.tx_init = tx_init = GTXInit(sys_clk_freq, False, mode=tx_mode)
# RX receives restart commands from RTIO domain
self.submodules.rx_init = rx_init = ClockDomainsRenamer("rtio_tx")(
GTXInit(rtio_clk_freq, True, mode=rx_mode))
# TX generates SYS clock, init must be in bootstrap domain
self.submodules.tx_init = tx_init = ClockDomainsRenamer("bootstrap")(
GTXInit(clk_freq, False, mode=tx_mode))
# RX receives restart commands from SYS domain
self.submodules.rx_init = rx_init = GTXInit(clk_freq, True, mode=rx_mode)
self.comb += [
cpllreset.eq(tx_init.cpllreset),
tx_init.cplllock.eq(cplllock),
@ -113,8 +113,8 @@ class GTX_20X(Module):
i_TXCHARDISPMODE=Cat(txdata[9], txdata[19]),
i_TXCHARDISPVAL=Cat(txdata[8], txdata[18]),
i_TXDATA=Cat(txdata[:8], txdata[10:18]),
i_TXUSRCLK=ClockSignal("rtio_tx"),
i_TXUSRCLK2=ClockSignal("rtio_tx"),
i_TXUSRCLK=ClockSignal("sys"),
i_TXUSRCLK2=ClockSignal("sys"),
# TX electrical
i_TXBUFDIFFCTRL=0b100,
@ -247,19 +247,10 @@ class GTX_20X(Module):
p_ES_EYE_SCAN_EN="TRUE", # Must be TRUE for GTX
)
# TX clocking
tx_reset_deglitched = Signal()
tx_reset_deglitched.attr.add("no_retiming")
self.sync += tx_reset_deglitched.eq(~tx_init.done)
self.clock_domains.cd_rtio_tx = ClockDomain()
if tx_mode == "single" or tx_mode == "master":
self.specials += Instance("BUFG", i_I=self.txoutclk, o_O=self.cd_rtio_tx.clk)
self.specials += AsyncResetSynchronizer(self.cd_rtio_tx, tx_reset_deglitched)
# RX clocking
rx_reset_deglitched = Signal()
rx_reset_deglitched.attr.add("no_retiming")
self.sync.rtio += rx_reset_deglitched.eq(~rx_init.done)
self.sync += rx_reset_deglitched.eq(~rx_init.done)
self.clock_domains.cd_rtio_rx = ClockDomain()
if rx_mode == "single" or rx_mode == "master":
self.specials += Instance("BUFG", i_I=self.rxoutclk, o_O=self.cd_rtio_rx.clk),
@ -271,7 +262,7 @@ class GTX_20X(Module):
self.decoders[1].input.eq(rxdata[10:])
]
clock_aligner = BruteforceClockAligner(0b0101111100, rtio_clk_freq)
clock_aligner = BruteforceClockAligner(0b0101111100, clk_freq)
self.submodules += clock_aligner
self.comb += [
clock_aligner.rxdata.eq(rxdata),
@ -282,17 +273,18 @@ class GTX_20X(Module):
class GTX(Module, TransceiverInterface):
def __init__(self, clock_pads, pads, sys_clk_freq, rtio_clk_freq=125e6, master=0):
def __init__(self, clock_pads, pads, clk_freq=125e6, master=0):
self.nchannels = nchannels = len(pads)
self.gtxs = []
self.rtio_clk_freq = rtio_clk_freq
self.rtio_clk_freq = clk_freq
# # #
refclk = Signal()
stable_clkin_n = Signal()
clk_enable = Signal()
self.specials += Instance("IBUFDS_GTE2",
i_CEB=stable_clkin_n,
i_CEB=~clk_enable,
i_I=clock_pads.p,
i_IB=clock_pads.n,
o_O=refclk,
@ -301,7 +293,6 @@ class GTX(Module, TransceiverInterface):
p_CLKSWING_CFG="0b11"
)
rtio_tx_clk = Signal()
channel_interfaces = []
for i in range(nchannels):
if nchannels == 1:
@ -309,12 +300,7 @@ class GTX(Module, TransceiverInterface):
else:
mode = "master" if i == master else "slave"
# Note: RX phase alignment is to be done on individual lanes, not multi-lane.
gtx = GTX_20X(refclk, pads[i], sys_clk_freq, rtio_clk_freq=rtio_clk_freq, tx_mode=mode, rx_mode="single")
# Fan-out (to slave) / Fan-in (from master) of the TXUSRCLK
if mode == "slave":
self.comb += gtx.cd_rtio_tx.clk.eq(rtio_tx_clk)
else:
self.comb += rtio_tx_clk.eq(gtx.cd_rtio_tx.clk)
gtx = GTX_20X(refclk, pads[i], clk_freq, tx_mode=mode, rx_mode="single")
self.gtxs.append(gtx)
setattr(self.submodules, "gtx"+str(i), gtx)
channel_interface = ChannelInterface(gtx.encoder, gtx.decoders)
@ -326,15 +312,16 @@ class GTX(Module, TransceiverInterface):
TransceiverInterface.__init__(self, channel_interfaces)
for n, gtx in enumerate(self.gtxs):
self.comb += [
stable_clkin_n.eq(~self.stable_clkin.storage),
gtx.txenable.eq(self.txenable.storage[n])
gtx.txenable.eq(self.txenable.storage[n]),
gtx.tx_init.stable_clkin.eq(clk_enable)
]
# rx_init is in SYS domain, rather than bootstrap
self.specials += MultiReg(clk_enable, gtx.rx_init.stable_clkin)
# stable_clkin resets after reboot since it's in SYS domain
# still need to keep clk_enable high after this
self.sync.bootstrap += clk_enable.eq(self.stable_clkin.storage | self.gtxs[0].tx_init.done)
# Connect master's `rtio_tx` clock to `rtio` clock
self.comb += [
self.cd_rtio.clk.eq(self.gtxs[master].cd_rtio_tx.clk),
self.cd_rtio.rst.eq(reduce(or_, [gtx.cd_rtio_tx.rst for gtx in self.gtxs]))
]
# Connect slave i's `rtio_rx` clock to `rtio_rxi` clock
for i in range(nchannels):
self.comb += [

View File

@ -11,11 +11,13 @@ class GTXInit(Module):
# Choose between Auto Mode and Manual Mode for TX/RX phase alignment with buffer bypassed:
# * Auto Mode: When only single lane is involved, as suggested by Xilinx (AR59612)
# * Manual Mode: When only multi-lane is involved, as suggested by Xilinx (AR59612)
def __init__(self, sys_clk_freq, rx, mode="single"):
def __init__(self, clk_freq, rx, mode="single"):
assert isinstance(rx, bool)
assert mode in ["single", "master", "slave"]
self.mode = mode
self.stable_clkin = Signal()
self.done = Signal()
self.restart = Signal()
@ -83,13 +85,13 @@ class GTXInit(Module):
# After configuration, transceiver resets have to stay low for
# at least 500ns (see AR43482)
startup_cycles = ceil(500*sys_clk_freq/1000000000)
startup_cycles = ceil(500*clk_freq/1000000000)
startup_timer = WaitTimer(startup_cycles)
self.submodules += startup_timer
# PLL reset should be 1 period of refclk
# (i.e. 1/(125MHz) for the case of RTIO @ 125MHz)
pll_reset_cycles = ceil(sys_clk_freq/125e6)
pll_reset_cycles = ceil(clk_freq/125e6)
pll_reset_timer = WaitTimer(pll_reset_cycles)
self.submodules += pll_reset_timer
@ -108,7 +110,7 @@ class GTXInit(Module):
startup_fsm.act("INITIAL",
startup_timer.wait.eq(1),
If(startup_timer.done, NextState("RESET_ALL"))
If(startup_timer.done & self.stable_clkin, NextState("RESET_ALL"))
)
startup_fsm.act("RESET_ALL",
gtXxreset.eq(1),

View File

@ -24,65 +24,20 @@ from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer
from artiq.gateware.drtio import *
from artiq.build_soc import *
class _RTIOCRG(Module, AutoCSR):
def __init__(self, platform, rtio_internal_clk, use_sma=True):
self._clock_sel = CSRStorage()
self._pll_reset = CSRStorage(reset=1)
self._pll_locked = CSRStatus()
self.clock_domains.cd_rtio = ClockDomain()
self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True)
# 100 MHz when using 125MHz input
self.clock_domains.cd_ext_clkout = ClockDomain(reset_less=True)
platform.add_period_constraint(self.cd_ext_clkout.clk, 5.0)
if use_sma:
ext_clkout = platform.request("user_sma_gpio_p_33")
self.sync.ext_clkout += ext_clkout.eq(~ext_clkout)
rtio_external_clk = Signal()
if use_sma:
user_sma_clock = platform.request("user_sma_clock")
platform.add_period_constraint(user_sma_clock.p, 8.0)
self.specials += Instance("IBUFDS",
i_I=user_sma_clock.p, i_IB=user_sma_clock.n,
o_O=rtio_external_clk)
pll_locked = Signal()
rtio_clk = Signal()
rtiox4_clk = Signal()
ext_clkout_clk = Signal()
class SMAClkinForward(Module):
def __init__(self, platform):
sma_clkin = platform.request("user_sma_clock")
sma_clkin_se = Signal()
sma_clkin_buffered = Signal()
cdr_clk_se = Signal()
cdr_clk = platform.request("si5324_clkin_33")
self.specials += [
Instance("PLLE2_ADV",
p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked,
p_REF_JITTER1=0.01,
p_CLKIN1_PERIOD=8.0, p_CLKIN2_PERIOD=8.0,
i_CLKIN1=rtio_internal_clk, i_CLKIN2=rtio_external_clk,
# Warning: CLKINSEL=0 means CLKIN2 is selected
i_CLKINSEL=~self._clock_sel.storage,
# VCO @ 1GHz when using 125MHz input
p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1,
i_CLKFBIN=self.cd_rtio.clk,
i_RST=self._pll_reset.storage,
o_CLKFBOUT=rtio_clk,
p_CLKOUT0_DIVIDE=2, p_CLKOUT0_PHASE=0.0,
o_CLKOUT0=rtiox4_clk,
p_CLKOUT1_DIVIDE=5, p_CLKOUT1_PHASE=0.0,
o_CLKOUT1=ext_clkout_clk),
Instance("BUFG", i_I=rtio_clk, o_O=self.cd_rtio.clk),
Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk),
Instance("BUFG", i_I=ext_clkout_clk, o_O=self.cd_ext_clkout.clk),
AsyncResetSynchronizer(self.cd_rtio, ~pll_locked),
MultiReg(pll_locked, self._pll_locked.status)
Instance("IBUFDS", i_I=sma_clkin.p, i_IB=sma_clkin.n, o_O=sma_clkin_se),
Instance("BUFG", i_I=sma_clkin_se, o_O=sma_clkin_buffered),
Instance("ODDR", i_C=sma_clkin_buffered, i_CE=1, i_D1=0, i_D2=1, o_Q=cdr_clk_se),
Instance("OBUFDS", i_I=cdr_clk_se, o_O=cdr_clk.p, o_OB=cdr_clk.n)
]
# The default voltage for these signals on KC705 is 2.5V, and the Migen platform
# follows this default. But since the SMAs are on the same bank as the DDS,
# which is set to 3.3V by reprogramming the KC705 power ICs, we need to
@ -138,6 +93,7 @@ class _StandaloneBase(MiniSoC, AMPSoC):
integrated_sram_size=8192,
ethmac_nrxslots=4,
ethmac_ntxslots=4,
rtio_sys_merge=True,
**kwargs)
AMPSoC.__init__(self)
add_identifier(self, gateware_identifier_str=gateware_identifier_str)
@ -149,6 +105,31 @@ class _StandaloneBase(MiniSoC, AMPSoC):
if isinstance(self.platform.toolchain, XilinxISEToolchain):
self.platform.toolchain.bitgen_opt += " -g compress"
self.platform.add_extension(_reprogrammed3v3_io)
cdr_clk_out = self.platform.request("si5324_clkout")
cdr_clk = Signal()
cdr_clk_buf = Signal()
self.config["HAS_SI5324"] = None
self.config["SI5324_AS_SYNTHESIZER"] = None
self.submodules.si5324_rst_n = gpio.GPIOOut(self.platform.request("si5324_33").rst_n)
self.csr_devices.append("si5324_rst_n")
self.specials += [
Instance("IBUFDS_GTE2",
i_CEB=0,
i_I=cdr_clk_out.p, i_IB=cdr_clk_out.n,
o_O=cdr_clk,
p_CLKCM_CFG=1,
p_CLKRCV_TRST=1,
p_CLKSWING_CFG="2'b11"),
Instance("BUFG", i_I=cdr_clk, o_O=cdr_clk_buf)
]
self.crg.configure(cdr_clk_buf)
self.submodules += SMAClkinForward(self.platform)
self.submodules.timer1 = timer.Timer()
self.csr_devices.append("timer1")
self.interrupt_devices.append("timer1")
@ -158,7 +139,6 @@ class _StandaloneBase(MiniSoC, AMPSoC):
self.platform.request("user_led", 1)))
self.csr_devices.append("leds")
self.platform.add_extension(_reprogrammed3v3_io)
self.platform.add_extension(_ams101_dac)
i2c = self.platform.request("i2c")
@ -169,9 +149,6 @@ class _StandaloneBase(MiniSoC, AMPSoC):
self.config["HAS_DDS"] = None
def add_rtio(self, rtio_channels):
self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk)
self.csr_devices.append("rtio_crg")
self.config["HAS_RTIO_CLOCK_SWITCH"] = None
self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3)
self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels)
self.csr_devices.append("rtio_core")
@ -187,11 +164,6 @@ class _StandaloneBase(MiniSoC, AMPSoC):
self.submodules.rtio_moninj = rtio.MonInj(rtio_channels)
self.csr_devices.append("rtio_moninj")
self.platform.add_period_constraint(self.rtio_crg.cd_rtio.clk, 8.)
self.platform.add_false_path_constraints(
self.crg.cd_sys.clk,
self.rtio_crg.cd_rtio.clk)
self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_tsc, self.rtio_core.cri,
self.get_native_sdram_if(), cpu_dw=self.cpu_dw)
self.csr_devices.append("rtio_analyzer")
@ -208,6 +180,7 @@ class _MasterBase(MiniSoC, AMPSoC):
mem_map.update(MiniSoC.mem_map)
def __init__(self, gateware_identifier_str=None, drtio_100mhz=False, **kwargs):
clk_freq = 100e6 if drtio_100mhz else 125e6
MiniSoC.__init__(self,
cpu_type="vexriscv",
cpu_bus_width=64,
@ -216,6 +189,8 @@ class _MasterBase(MiniSoC, AMPSoC):
integrated_sram_size=8192,
ethmac_nrxslots=4,
ethmac_ntxslots=4,
clk_freq=clk_freq,
rtio_sys_merge=True,
**kwargs)
AMPSoC.__init__(self)
add_identifier(self, gateware_identifier_str=gateware_identifier_str)
@ -236,14 +211,11 @@ class _MasterBase(MiniSoC, AMPSoC):
platform.request("sfp"), platform.request("user_sma_mgt")
]
rtio_clk_freq = 100e6 if drtio_100mhz else 125e6
# 1000BASE_BX10 Ethernet compatible, 100/125MHz RTIO clock
self.submodules.drtio_transceiver = gtx_7series.GTX(
clock_pads=platform.request("si5324_clkout"),
pads=data_pads,
sys_clk_freq=self.clk_freq,
rtio_clk_freq=rtio_clk_freq)
clk_freq=self.clk_freq)
self.csr_devices.append("drtio_transceiver")
self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3)
@ -292,29 +264,31 @@ class _MasterBase(MiniSoC, AMPSoC):
self.config["HAS_SI5324"] = None
self.config["SI5324_AS_SYNTHESIZER"] = None
self.comb += [
platform.request("user_sma_clock_p").eq(ClockSignal("rtio_rx0")),
platform.request("user_sma_clock_n").eq(ClockSignal("rtio"))
]
rtio_clk_period = 1e9/self.drtio_transceiver.rtio_clk_freq
# Constrain TX & RX timing for the first transceiver channel
# (First channel acts as master for phase alignment for all channels' TX)
gtx0 = self.drtio_transceiver.gtxs[0]
txout_buf = Signal()
self.specials += Instance("BUFG", i_I=gtx0.txoutclk, o_O=txout_buf)
self.crg.configure(txout_buf, clk_sw=gtx0.tx_init.done)
self.comb += [
platform.request("user_sma_clock_p").eq(ClockSignal("rtio_rx0")),
platform.request("user_sma_clock_n").eq(gtx0.txoutclk)
]
platform.add_period_constraint(gtx0.txoutclk, rtio_clk_period)
platform.add_period_constraint(gtx0.rxoutclk, rtio_clk_period)
platform.add_false_path_constraints(
self.crg.cd_sys.clk,
gtx0.txoutclk, gtx0.rxoutclk)
self.crg.cd_sys.clk, gtx0.rxoutclk)
# Constrain RX timing for the each transceiver channel
# (Each channel performs single-lane phase alignment for RX)
for gtx in self.drtio_transceiver.gtxs[1:]:
platform.add_period_constraint(gtx.rxoutclk, rtio_clk_period)
platform.add_false_path_constraints(
self.crg.cd_sys.clk, gtx0.txoutclk, gtx.rxoutclk)
self.crg.cd_sys.clk, gtx.rxoutclk)
self.submodules.rtio_crg = RTIOClockMultiplier(self.drtio_transceiver.rtio_clk_freq)
self.csr_devices.append("rtio_crg")
fix_serdes_timing_path(platform)
def add_rtio(self, rtio_channels):
@ -345,12 +319,15 @@ class _SatelliteBase(BaseSoC):
mem_map.update(BaseSoC.mem_map)
def __init__(self, gateware_identifier_str=None, sma_as_sat=False, drtio_100mhz=False, **kwargs):
clk_freq = 100e6 if drtio_100mhz else 125e6
BaseSoC.__init__(self,
cpu_type="vexriscv",
cpu_bus_width=64,
sdram_controller_type="minicon",
l2_size=128*1024,
integrated_sram_size=8192,
clk_freq=clk_freq,
rtio_sys_merge=True,
**kwargs)
add_identifier(self, gateware_identifier_str=gateware_identifier_str)
@ -372,14 +349,13 @@ class _SatelliteBase(BaseSoC):
if sma_as_sat:
data_pads = data_pads[::-1]
rtio_clk_freq = 100e6 if drtio_100mhz else 125e6
rtio_clk_freq = clk_freq
# 1000BASE_BX10 Ethernet compatible, 100/125MHz RTIO clock
self.submodules.drtio_transceiver = gtx_7series.GTX(
clock_pads=platform.request("si5324_clkout"),
pads=data_pads,
sys_clk_freq=self.clk_freq,
rtio_clk_freq=rtio_clk_freq)
clk_freq=self.clk_freq)
self.csr_devices.append("drtio_transceiver")
self.submodules.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3)
@ -432,6 +408,7 @@ class _SatelliteBase(BaseSoC):
self.submodules.siphaser = SiPhaser7Series(
si5324_clkin=platform.request("si5324_clkin_33"),
rx_synchronizer=self.rx_synchronizer,
ref_clk=ClockSignal("bootstrap"),
ultrascale=False,
rtio_clk_freq=self.drtio_transceiver.rtio_clk_freq)
platform.add_false_path_constraints(
@ -445,20 +422,22 @@ class _SatelliteBase(BaseSoC):
self.config["I2C_BUS_COUNT"] = 1
self.config["HAS_SI5324"] = None
self.comb += [
platform.request("user_sma_clock_p").eq(ClockSignal("rtio_rx0")),
platform.request("user_sma_clock_n").eq(ClockSignal("rtio"))
]
rtio_clk_period = 1e9/self.drtio_transceiver.rtio_clk_freq
# Constrain TX & RX timing for the first transceiver channel
# (First channel acts as master for phase alignment for all channels' TX)
gtx0 = self.drtio_transceiver.gtxs[0]
txout_buf = Signal()
self.specials += Instance("BUFG", i_I=gtx0.txoutclk, o_O=txout_buf)
self.crg.configure(txout_buf, clk_sw=gtx0.tx_init.done)
self.comb += [
platform.request("user_sma_clock_p").eq(ClockSignal("rtio_rx0")),
platform.request("user_sma_clock_n").eq(gtx0.txoutclk)
]
platform.add_period_constraint(gtx0.txoutclk, rtio_clk_period)
platform.add_period_constraint(gtx0.rxoutclk, rtio_clk_period)
platform.add_false_path_constraints(
self.crg.cd_sys.clk,
gtx0.txoutclk, gtx0.rxoutclk)
# Constrain RX timing for the each transceiver channel
# (Each channel performs single-lane phase alignment for RX)
for gtx in self.drtio_transceiver.gtxs[1:]:
@ -466,8 +445,6 @@ class _SatelliteBase(BaseSoC):
platform.add_false_path_constraints(
self.crg.cd_sys.clk, gtx.rxoutclk)
self.submodules.rtio_crg = RTIOClockMultiplier(self.drtio_transceiver.rtio_clk_freq)
self.csr_devices.append("rtio_crg")
fix_serdes_timing_path(platform)
def add_rtio(self, rtio_channels):