forked from M-Labs/artiq
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 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(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue