mirror of https://github.com/m-labs/artiq.git
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:
parent
3356717316
commit
cb04230f86
|
@ -1,13 +1,24 @@
|
|||
use board_misoc::{csr, config};
|
||||
use board_misoc::{csr, clock, config};
|
||||
|
||||
use hmc830_7043::hmc7043;
|
||||
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> {
|
||||
for _ in 0..256 {
|
||||
hmc7043::sysref_slip();
|
||||
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(())
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ class UltrascaleCRG(Module, AutoCSR):
|
|||
def __init__(self, platform, use_rtio_clock=False):
|
||||
self.ibuf_disable = CSRStorage(reset=1)
|
||||
self.jreset = CSRStorage(reset=1)
|
||||
self.jref = Signal()
|
||||
self.refclk = Signal()
|
||||
self.clock_domains.cd_jesd = ClockDomain()
|
||||
|
||||
|
@ -42,23 +41,6 @@ class UltrascaleCRG(Module, AutoCSR):
|
|||
else:
|
||||
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")
|
||||
|
||||
|
@ -90,7 +72,6 @@ class UltrascaleTX(Module, AutoCSR):
|
|||
phys, settings, converter_data_width=64)
|
||||
self.submodules.control = JESD204BCoreTXControl(self.core)
|
||||
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"
|
||||
|
@ -157,3 +138,60 @@ class DDMTD(Module, AutoCSR):
|
|||
bsync.i.eq(result),
|
||||
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)
|
||||
|
|
|
@ -114,119 +114,6 @@ class RTMCommon:
|
|||
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):
|
||||
"""
|
||||
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.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):
|
||||
|
@ -684,6 +576,11 @@ class Satellite(BaseSoC, RTMCommon):
|
|||
|
||||
self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(platform.request("adc_sysref"))
|
||||
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
|
||||
gth = self.drtio_transceiver.gths[0]
|
||||
|
@ -700,9 +597,8 @@ def main():
|
|||
builder_args(parser)
|
||||
soc_sdram_args(parser)
|
||||
parser.set_defaults(output_dir="artiq_sayma")
|
||||
parser.add_argument("-V", "--variant", default="standalone",
|
||||
help="variant: "
|
||||
"standalone/masterdac/master/satellite "
|
||||
parser.add_argument("-V", "--variant", default="masterdac",
|
||||
help="variant: masterdac/master/satellite "
|
||||
"(default: %(default)s)")
|
||||
parser.add_argument("--rtm-csr-csv",
|
||||
default=os.path.join("artiq_sayma", "rtm_gateware", "rtm_csr.csv"),
|
||||
|
@ -714,9 +610,7 @@ def main():
|
|||
args = parser.parse_args()
|
||||
|
||||
variant = args.variant.lower()
|
||||
if variant == "standalone":
|
||||
cls = Standalone
|
||||
elif variant == "masterdac":
|
||||
if variant == "masterdac":
|
||||
cls = MasterDAC
|
||||
elif variant == "master":
|
||||
cls = lambda with_sawg, **kwargs: Master(**kwargs)
|
||||
|
|
Loading…
Reference in New Issue