forked from M-Labs/artiq
1
0
Fork 0

sayma: SYSREF setup/hold validation demonstration

This also removes the standalone target as the ISERDES used
for setup/hold check requires the fine RTIO clock, which in turn
requires a DRTIO transceiver due to the Ultrascale TPWS bug.
This commit is contained in:
Sebastien Bourdeauducq 2019-01-25 16:58:58 +08:00
parent 3356717316
commit cb04230f86
3 changed files with 83 additions and 140 deletions

View File

@ -1,13 +1,24 @@
use board_misoc::{csr, config}; use board_misoc::{csr, clock, config};
use hmc830_7043::hmc7043; use hmc830_7043::hmc7043;
use ad9154; use ad9154;
fn sysref_sh_error() -> bool {
unsafe {
csr::sysref_sampler::sh_error_reset_write(1);
clock::spin_us(1);
csr::sysref_sampler::sh_error_reset_write(0);
clock::spin_us(10);
csr::sysref_sampler::sh_error_read() != 0
}
}
pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { pub fn sysref_auto_rtio_align() -> Result<(), &'static str> {
for _ in 0..256 { for _ in 0..256 {
hmc7043::sysref_slip(); hmc7043::sysref_slip();
let dt = unsafe { csr::sysref_ddmtd::dt_read() }; let dt = unsafe { csr::sysref_ddmtd::dt_read() };
info!("dt={}", dt); let sh_error = sysref_sh_error();
info!("dt={} sysref_sh_error={}", dt, sh_error);
} }
Ok(()) Ok(())
} }

View File

@ -22,7 +22,6 @@ class UltrascaleCRG(Module, AutoCSR):
def __init__(self, platform, use_rtio_clock=False): def __init__(self, platform, use_rtio_clock=False):
self.ibuf_disable = CSRStorage(reset=1) self.ibuf_disable = CSRStorage(reset=1)
self.jreset = CSRStorage(reset=1) self.jreset = CSRStorage(reset=1)
self.jref = Signal()
self.refclk = Signal() self.refclk = Signal()
self.clock_domains.cd_jesd = ClockDomain() self.clock_domains.cd_jesd = ClockDomain()
@ -42,23 +41,6 @@ class UltrascaleCRG(Module, AutoCSR):
else: else:
self.specials += Instance("BUFG_GT", i_I=refclk2, o_O=self.cd_jesd.clk) self.specials += Instance("BUFG_GT", i_I=refclk2, o_O=self.cd_jesd.clk)
jref = platform.request("dac_sysref")
jref_se = Signal()
jref_r = Signal()
self.specials += [
Instance("IBUFDS_IBUFDISABLE",
p_USE_IBUFDISABLE="TRUE", p_SIM_DEVICE="ULTRASCALE",
i_IBUFDISABLE=self.ibuf_disable.storage,
i_I=jref.p, i_IB=jref.n,
o_O=jref_se),
# SYSREF normally meets s/h at the FPGA, except during margin
# scan and before full initialization.
# Be paranoid and use a double-register anyway.
Instance("FD", i_C=ClockSignal("jesd"), i_D=jref_se, o_Q=jref_r,
attr={("IOB", "TRUE")}),
Instance("FD", i_C=ClockSignal("jesd"), i_D=jref_r, o_Q=self.jref)
]
PhyPads = namedtuple("PhyPads", "txp txn") PhyPads = namedtuple("PhyPads", "txp txn")
@ -90,7 +72,6 @@ class UltrascaleTX(Module, AutoCSR):
phys, settings, converter_data_width=64) phys, settings, converter_data_width=64)
self.submodules.control = JESD204BCoreTXControl(self.core) self.submodules.control = JESD204BCoreTXControl(self.core)
self.core.register_jsync(platform.request("dac_sync", dac)) self.core.register_jsync(platform.request("dac_sync", dac))
self.core.register_jref(jesd_crg.jref)
# See "Digital femtosecond time difference circuit for CERN's timing system" # See "Digital femtosecond time difference circuit for CERN's timing system"
@ -157,3 +138,60 @@ class DDMTD(Module, AutoCSR):
bsync.i.eq(result), bsync.i.eq(result),
self.dt.status.eq(bsync.o) self.dt.status.eq(bsync.o)
] ]
# This assumes:
# * coarse RTIO frequency = 16*SYSREF frequency
# * fine RTIO frequency (rtiox) = 2*RTIO frequency
# * JESD and coarse RTIO clocks are the same
# (only reset may differ).
#
# Look at the 4 LSBs of the coarse RTIO timestamp counter
# to determine SYSREF phase.
class SysrefSampler(Module, AutoCSR):
def __init__(self, sysref_pads, coarse_ts):
self.sh_error = CSRStatus()
self.sh_error_reset = CSRStorage()
self.sample_result = CSRStatus()
self.jref = Signal()
# # #
sysref_se = Signal()
sysref_oversample = Signal(4)
self.specials += [
Instance("IBUFDS", i_I=sysref_pads.p, i_IB=sysref_pads.n, o_O=sysref_se),
Instance("ISERDESE3",
p_IS_CLK_INVERTED=0,
p_IS_CLK_B_INVERTED=1,
p_DATA_WIDTH=4,
i_D=sysref_se,
i_RST=ResetSignal("rtio"),
i_FIFO_RD_EN=0,
i_CLK=ClockSignal("rtiox"),
i_CLK_B=ClockSignal("rtiox"), # locally inverted
i_CLKDIV=ClockSignal("rtio"),
o_Q=sysref_oversample)
]
self.comb += self.jref.eq(sysref_oversample[1])
sh_error = Signal()
sh_error_reset = Signal()
self.sync.rtio += [
If(~( (sysref_oversample[0] == sysref_oversample[1])
& (sysref_oversample[1] == sysref_oversample[2])),
sh_error.eq(1)
),
If(sh_error_reset, sh_error.eq(0))
]
self.specials += [
MultiReg(self.sh_error_reset.storage, sh_error_reset, "rtio"),
MultiReg(sh_error, self.sh_error.status)
]
sample = Signal()
self.sync.rtio += If(coarse_ts[:4] == 0, sample.eq(self.jref))
self.specials += MultiReg(sample, self.sample_result.status)

View File

@ -114,119 +114,6 @@ class RTMCommon:
self.add_wb_slave(self.mem_map["serwb"], 8192, serwb_core.etherbone.wishbone.bus) self.add_wb_slave(self.mem_map["serwb"], 8192, serwb_core.etherbone.wishbone.bus)
class Standalone(MiniSoC, AMPSoC, RTMCommon):
"""
Local DAC/SAWG channels only.
"""
mem_map = {
"cri_con": 0x10000000,
"rtio": 0x11000000,
"rtio_dma": 0x12000000,
"serwb": 0x13000000,
"mailbox": 0x70000000
}
mem_map.update(MiniSoC.mem_map)
def __init__(self, with_sawg, **kwargs):
MiniSoC.__init__(self,
cpu_type="or1k",
sdram_controller_type="minicon",
l2_size=128*1024,
ethmac_nrxslots=4,
ethmac_ntxslots=4,
**kwargs)
AMPSoC.__init__(self)
RTMCommon.__init__(self)
add_identifier(self, suffix=".without-sawg" if not with_sawg else "")
self.config["HMC830_REF"] = "100"
platform = self.platform
self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n)
self.csr_devices.append("si5324_rst_n")
i2c = self.platform.request("i2c")
self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda])
self.csr_devices.append("i2c")
self.config["I2C_BUS_COUNT"] = 1
self.config["HAS_SI5324"] = None
self.config["SI5324_AS_SYNTHESIZER"] = None
self.config["SI5324_SAYMA_REF"] = None
# ensure pins are properly biased and terminated
si5324_clkout = platform.request("si5324_clkout", 0)
self.specials += Instance(
"IBUFDS_GTE3", i_CEB=0, i_I=si5324_clkout.p, i_IB=si5324_clkout.n,
attr={("DONT_TOUCH", "true")})
# RTIO
rtio_channels = []
for i in range(4):
phy = ttl_simple.Output(platform.request("user_led", i))
self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy))
# To work around Ultrascale issues (https://www.xilinx.com/support/answers/67885.html),
# we generate the multiplied RTIO clock using the DRTIO GTH transceiver.
# Since there is no DRTIO here and therefoere no multiplied clock, we use ttl_simple.
sma_io = platform.request("sma_io", 0)
self.comb += sma_io.direction.eq(1)
phy = ttl_simple.Output(sma_io.level)
self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy))
sma_io = platform.request("sma_io", 1)
self.comb += sma_io.direction.eq(0)
phy = ttl_simple.InOut(sma_io.level)
self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy))
self.submodules.ad9154_crg = jesd204_tools.UltrascaleCRG(platform)
if with_sawg:
cls = AD9154
else:
cls = AD9154NoSAWG
self.submodules.ad9154_0 = cls(platform, self.crg, self.ad9154_crg, 0)
self.submodules.ad9154_1 = cls(platform, self.crg, self.ad9154_crg, 1)
self.csr_devices.append("ad9154_crg")
self.csr_devices.append("ad9154_0")
self.csr_devices.append("ad9154_1")
self.config["HAS_AD9154"] = None
self.add_csr_group("ad9154", ["ad9154_0", "ad9154_1"])
self.config["RTIO_FIRST_SAWG_CHANNEL"] = len(rtio_channels)
rtio_channels.extend(rtio.Channel.from_phy(phy)
for sawg in self.ad9154_0.sawgs +
self.ad9154_1.sawgs
for phy in sawg.phys)
self.config["HAS_RTIO_LOG"] = None
self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels)
rtio_channels.append(rtio.LogChannel())
self.clock_domains.cd_rtio = ClockDomain()
self.comb += [
self.cd_rtio.clk.eq(ClockSignal("jesd")),
self.cd_rtio.rst.eq(ResetSignal("jesd"))
]
self.submodules.rtio_tsc = rtio.TSC("async")
self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels)
self.csr_devices.append("rtio_core")
self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc)
self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")(
rtio.DMA(self.get_native_sdram_if()))
self.register_kernel_cpu_csrdevice("rtio")
self.register_kernel_cpu_csrdevice("rtio_dma")
self.submodules.cri_con = rtio.CRIInterconnectShared(
[self.rtio.cri, self.rtio_dma.cri],
[self.rtio_core.cri])
self.register_kernel_cpu_csrdevice("cri_con")
self.submodules.rtio_moninj = rtio.MonInj(rtio_channels)
self.csr_devices.append("rtio_moninj")
self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_tsc, self.rtio_core.cri,
self.get_native_sdram_if())
self.csr_devices.append("rtio_analyzer")
self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(platform.request("adc_sysref"))
self.csr_devices.append("sysref_ddmtd")
class MasterDAC(MiniSoC, AMPSoC, RTMCommon): class MasterDAC(MiniSoC, AMPSoC, RTMCommon):
""" """
DRTIO master with local DAC/SAWG channels. DRTIO master with local DAC/SAWG channels.
@ -396,6 +283,11 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon):
self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(platform.request("adc_sysref")) self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(platform.request("adc_sysref"))
self.csr_devices.append("sysref_ddmtd") self.csr_devices.append("sysref_ddmtd")
self.submodules.sysref_sampler = jesd204_tools.SysrefSampler(
platform.request("dac_sysref"), self.rtio_tsc.coarse_ts)
self.csr_devices.append("sysref_sampler")
self.ad9154_0.jesd.core.register_jref(self.sysref_sampler.jref)
self.ad9154_1.jesd.core.register_jref(self.sysref_sampler.jref)
def workaround_us_lvds_tristate(platform): def workaround_us_lvds_tristate(platform):
@ -684,6 +576,11 @@ class Satellite(BaseSoC, RTMCommon):
self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(platform.request("adc_sysref")) self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(platform.request("adc_sysref"))
self.csr_devices.append("sysref_ddmtd") self.csr_devices.append("sysref_ddmtd")
self.submodules.sysref_sampler = jesd204_tools.SysrefSampler(
platform.request("dac_sysref"), self.rtio_tsc.coarse_ts)
self.csr_devices.append("sysref_sampler")
self.ad9154_0.jesd.core.register_jref(self.sysref_sampler.jref)
self.ad9154_1.jesd.core.register_jref(self.sysref_sampler.jref)
rtio_clk_period = 1e9/rtio_clk_freq rtio_clk_period = 1e9/rtio_clk_freq
gth = self.drtio_transceiver.gths[0] gth = self.drtio_transceiver.gths[0]
@ -700,9 +597,8 @@ def main():
builder_args(parser) builder_args(parser)
soc_sdram_args(parser) soc_sdram_args(parser)
parser.set_defaults(output_dir="artiq_sayma") parser.set_defaults(output_dir="artiq_sayma")
parser.add_argument("-V", "--variant", default="standalone", parser.add_argument("-V", "--variant", default="masterdac",
help="variant: " help="variant: masterdac/master/satellite "
"standalone/masterdac/master/satellite "
"(default: %(default)s)") "(default: %(default)s)")
parser.add_argument("--rtm-csr-csv", parser.add_argument("--rtm-csr-csv",
default=os.path.join("artiq_sayma", "rtm_gateware", "rtm_csr.csv"), default=os.path.join("artiq_sayma", "rtm_gateware", "rtm_csr.csv"),
@ -714,9 +610,7 @@ def main():
args = parser.parse_args() args = parser.parse_args()
variant = args.variant.lower() variant = args.variant.lower()
if variant == "standalone": if variant == "masterdac":
cls = Standalone
elif variant == "masterdac":
cls = MasterDAC cls = MasterDAC
elif variant == "master": elif variant == "master":
cls = lambda with_sawg, **kwargs: Master(**kwargs) cls = lambda with_sawg, **kwargs: Master(**kwargs)