From 1eb87164be8dad5e82f27083f007cabd41ad36b6 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Fri, 28 Oct 2022 16:47:56 +0800 Subject: [PATCH 01/85] kasli: remove rtiocrg, use rtio/sys merge --- artiq/gateware/targets/kasli.py | 63 ++------------------------------- 1 file changed, 2 insertions(+), 61 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 7ed52052b..f080b4fd0 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -27,59 +27,6 @@ from artiq.gateware.drtio import * from artiq.build_soc import * -class _RTIOCRG(Module, AutoCSR): - def __init__(self, platform): - 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) - - if platform.hw_rev == "v2.0": - clk_synth = platform.request("cdr_clk_clean_fabric") - else: - clk_synth = platform.request("si5324_clkout_fabric") - clk_synth_se = Signal() - platform.add_period_constraint(clk_synth.p, 8.0) - self.specials += [ - Instance("IBUFGDS", - p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="FALSE", - i_I=clk_synth.p, i_IB=clk_synth.n, o_O=clk_synth_se), - ] - - pll_locked = Signal() - rtio_clk = Signal() - rtiox4_clk = Signal() - fb_clk = Signal() - self.specials += [ - Instance("PLLE2_ADV", - p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, - p_BANDWIDTH="HIGH", - p_REF_JITTER1=0.001, - p_CLKIN1_PERIOD=8.0, p_CLKIN2_PERIOD=8.0, - i_CLKIN2=clk_synth_se, - # Warning: CLKINSEL=0 means CLKIN2 is selected - i_CLKINSEL=0, - - # VCO @ 1.5GHz when using 125MHz input - p_CLKFBOUT_MULT=12, p_DIVCLK_DIVIDE=1, - i_CLKFBIN=fb_clk, - i_RST=self.pll_reset.storage, - - o_CLKFBOUT=fb_clk, - - p_CLKOUT0_DIVIDE=3, p_CLKOUT0_PHASE=0.0, - o_CLKOUT0=rtiox4_clk, - - p_CLKOUT1_DIVIDE=12, p_CLKOUT1_PHASE=0.0, - o_CLKOUT1=rtio_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), - - AsyncResetSynchronizer(self.cd_rtio, ~pll_locked), - MultiReg(pll_locked, self.pll_locked.status) - ] - - class SMAClkinForward(Module): def __init__(self, platform): sma_clkin = platform.request("sma_clkin") @@ -118,6 +65,8 @@ class StandaloneBase(MiniSoC, AMPSoC): integrated_sram_size=8192, ethmac_nrxslots=4, ethmac_ntxslots=4, + clk_freq=kwargs.get("rtio_frequency", 125.0e6), + rtio_sys_merge=True, **kwargs) AMPSoC.__init__(self) add_identifier(self, gateware_identifier_str=gateware_identifier_str) @@ -136,8 +85,6 @@ class StandaloneBase(MiniSoC, AMPSoC): self.config["SI5324_SOFT_RESET"] = None def add_rtio(self, rtio_channels, sed_lanes=8): - self.submodules.rtio_crg = _RTIOCRG(self.platform) - self.csr_devices.append("rtio_crg") fix_serdes_timing_path(self.platform) self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels, lane_count=sed_lanes) @@ -157,10 +104,6 @@ class StandaloneBase(MiniSoC, AMPSoC): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") - 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") @@ -247,8 +190,6 @@ class SUServo(StandaloneBase): self.add_rtio(self.rtio_channels) pads = self.platform.lookup_request("sampler3_adc_data_p") - self.platform.add_false_path_constraints( - pads.clkout, self.rtio_crg.cd_rtio.clk) self.platform.add_false_path_constraints( pads.clkout, self.crg.cd_sys.clk) From a6856a5e4adc3abc424c92c671b44f9033721dd3 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Fri, 28 Oct 2022 16:50:10 +0800 Subject: [PATCH 02/85] rtio: remove rtio clock, use sys instead --- artiq/gateware/rtio/cdc.py | 2 +- artiq/gateware/rtio/core.py | 23 ++++++++----------- artiq/gateware/rtio/cri.py | 10 ++------ artiq/gateware/rtio/input_collector.py | 6 ++--- artiq/gateware/rtio/phy/fastino.py | 2 +- artiq/gateware/rtio/phy/grabber.py | 10 ++++---- artiq/gateware/rtio/phy/phaser.py | 4 ++-- artiq/gateware/rtio/phy/ttl_serdes_7series.py | 6 ++--- .../rtio/phy/ttl_serdes_ultrascale.py | 8 +++---- artiq/gateware/rtio/sed/core.py | 4 ++-- artiq/gateware/rtio/tsc.py | 2 +- artiq/gateware/rtio/xilinx_clocking.py | 2 +- 12 files changed, 33 insertions(+), 46 deletions(-) diff --git a/artiq/gateware/rtio/cdc.py b/artiq/gateware/rtio/cdc.py index bd0b11d37..cc0201969 100644 --- a/artiq/gateware/rtio/cdc.py +++ b/artiq/gateware/rtio/cdc.py @@ -15,7 +15,7 @@ class GrayCodeTransfer(Module): # convert to Gray code value_gray_rtio = Signal(width, reset_less=True) - self.sync.rtio += value_gray_rtio.eq(self.i ^ self.i[1:]) + self.sync += value_gray_rtio.eq(self.i ^ self.i[1:]) # transfer to system clock domain value_gray_sys = Signal(width) value_gray_rtio.attr.add("no_retiming") diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index 0b26a1126..7b3b6d6fa 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -24,7 +24,7 @@ class Core(Module, AutoCSR): self.sequence_error_channel = CSRStatus(16) # Clocking/Reset - # Create rsys, rio and rio_phy domains based on sys and rtio + # Create rio and rio_phy domains based on sys # with reset controlled by CSR. # # The `rio` CD contains logic that is reset with `core.reset()`. @@ -40,20 +40,15 @@ class Core(Module, AutoCSR): cmd_reset.eq(self.reset.re), cmd_reset_phy.eq(self.reset_phy.re) ] - cmd_reset.attr.add("no_retiming") - cmd_reset_phy.attr.add("no_retiming") - self.clock_domains.cd_rsys = ClockDomain() self.clock_domains.cd_rio = ClockDomain() self.clock_domains.cd_rio_phy = ClockDomain() self.comb += [ - self.cd_rsys.clk.eq(ClockSignal()), - self.cd_rsys.rst.eq(cmd_reset), - self.cd_rio.clk.eq(ClockSignal("rtio")), - self.cd_rio_phy.clk.eq(ClockSignal("rtio")) + self.cd_rio.clk.eq(ClockSignal()), + self.cd_rio.rst.eq(cmd_reset), + self.cd_rio_phy.clk.eq(ClockSignal()), + self.cd_rio_phy.rst.eq(cmd_reset_phy) ] - self.specials += AsyncResetSynchronizer(self.cd_rio, cmd_reset) - self.specials += AsyncResetSynchronizer(self.cd_rio_phy, cmd_reset_phy) # TSC chan_fine_ts_width = max(max(rtlink.get_fine_ts_width(channel.interface.o) @@ -65,7 +60,7 @@ class Core(Module, AutoCSR): # Outputs/Inputs quash_channels = [n for n, c in enumerate(channels) if isinstance(c, LogChannel)] - outputs = SED(channels, tsc.glbl_fine_ts_width, "async", + outputs = SED(channels, tsc.glbl_fine_ts_width, "sync", quash_channels=quash_channels, lane_count=lane_count, fifo_depth=fifo_depth, interface=self.cri) @@ -73,14 +68,14 @@ class Core(Module, AutoCSR): self.comb += outputs.coarse_timestamp.eq(tsc.coarse_ts) self.sync += outputs.minimum_coarse_timestamp.eq(tsc.coarse_ts_sys + 16) - inputs = InputCollector(tsc, channels, "async", + inputs = InputCollector(tsc, channels, "sync", quash_channels=quash_channels, interface=self.cri) self.submodules += inputs # Asychronous output errors - o_collision_sync = BlindTransfer("rio", "rsys", data_width=16) - o_busy_sync = BlindTransfer("rio", "rsys", data_width=16) + o_collision_sync = BlindTransfer("rio", "sys", data_width=16) + o_busy_sync = BlindTransfer("rio", "sys", data_width=16) self.submodules += o_collision_sync, o_busy_sync o_collision = Signal() o_busy = Signal() diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index c735b9e5f..8b38f4529 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -155,10 +155,8 @@ class CRIDecoder(Module): if enable_routing: self.specials.routing_table = Memory(slave_bits, 256) - if mode == "async": + if mode == "async" or mode == "sync": rtp_decoder = self.routing_table.get_port() - elif mode == "sync": - rtp_decoder = self.routing_table.get_port(clock_domain="rtio") else: raise ValueError self.specials += rtp_decoder @@ -199,12 +197,8 @@ class CRISwitch(Module, AutoCSR): # # # - if mode == "async": + if mode == "async" or mode == "sync": selected = self.selected.storage - elif mode == "sync": - self.selected.storage.attr.add("no_retiming") - selected = Signal.like(self.selected.storage) - self.specials += MultiReg(self.selected.storage, selected, "rtio") else: raise ValueError diff --git a/artiq/gateware/rtio/input_collector.py b/artiq/gateware/rtio/input_collector.py index a68f5a7ff..a65fe6d9d 100644 --- a/artiq/gateware/rtio/input_collector.py +++ b/artiq/gateware/rtio/input_collector.py @@ -36,9 +36,9 @@ class InputCollector(Module): sync_io = self.sync sync_cri = self.sync elif mode == "async": - fifo_factory = lambda *args: ClockDomainsRenamer({"write": "rio", "read": "rsys"})(AsyncFIFO(*args)) + fifo_factory = lambda *args: ClockDomainsRenamer({"write": "rio", "read": "sys"})(AsyncFIFO(*args)) sync_io = self.sync.rio - sync_cri = self.sync.rsys + sync_cri = self.sync.sys else: raise ValueError @@ -85,7 +85,7 @@ class InputCollector(Module): if mode == "sync": overflow_trigger = overflow_io elif mode == "async": - overflow_transfer = BlindTransfer("rio", "rsys") + overflow_transfer = BlindTransfer("rio", "sys") self.submodules += overflow_transfer self.comb += overflow_transfer.i.eq(overflow_io) overflow_trigger = overflow_transfer.o diff --git a/artiq/gateware/rtio/phy/fastino.py b/artiq/gateware/rtio/phy/fastino.py index 474bab0f3..9fcc71390 100644 --- a/artiq/gateware/rtio/phy/fastino.py +++ b/artiq/gateware/rtio/phy/fastino.py @@ -120,7 +120,7 @@ class Fastino(Module): ), ] - self.sync.rtio += [ + self.sync += [ self.rtlink.i.stb.eq(self.rtlink.o.stb & self.rtlink.o.address[-1]), self.rtlink.i.data.eq( diff --git a/artiq/gateware/rtio/phy/grabber.py b/artiq/gateware/rtio/phy/grabber.py index 520450c76..f0783fa42 100644 --- a/artiq/gateware/rtio/phy/grabber.py +++ b/artiq/gateware/rtio/phy/grabber.py @@ -21,14 +21,12 @@ class Synchronizer(Module): # # # - for count in counts_in: - count.attr.add("no_retiming") - self.specials += [MultiReg(i, o, "rtio") for i, o in zip(counts_in, self.counts)] + self.comb += [o.eq(i) for i, o in zip(counts_in, self.counts)] - ps = PulseSynchronizer("cl", "rtio") + ps = PulseSynchronizer("cl", "sys") self.submodules += ps self.comb += ps.i.eq(roi_engines[0].out.update) - self.sync.rtio += self.update.eq(ps.o) + self.sync += self.update.eq(ps.o) class Serializer(Module): @@ -85,7 +83,7 @@ class Grabber(Module): roi_engine.cfg.x1, roi_engine.cfg.y1]): roi_boundary = Signal.like(target) roi_boundary.attr.add("no_retiming") - self.sync.rtio += If(self.config.o.stb & (self.config.o.address == 4*n+offset), + self.sync += If(self.config.o.stb & (self.config.o.address == 4*n+offset), roi_boundary.eq(self.config.o.data)) self.specials += MultiReg(roi_boundary, target, "cl") diff --git a/artiq/gateware/rtio/phy/phaser.py b/artiq/gateware/rtio/phy/phaser.py index 557a65d74..94a5400d5 100644 --- a/artiq/gateware/rtio/phy/phaser.py +++ b/artiq/gateware/rtio/phy/phaser.py @@ -10,7 +10,7 @@ class Phy(Module): self.rtlink = rtlink.Interface( rtlink.OInterface(data_width=32, address_width=4, enable_replace=True)) - self.sync.rtio += [ + self.sync += [ If(self.rtlink.o.stb, Array(regs)[self.rtlink.o.address].eq(self.rtlink.o.data) ) @@ -70,7 +70,7 @@ class Base(Module): self.comb += self.serializer.payload.eq(Cat(header.raw_bits(), body)) re_dly = Signal(3) # stage, send, respond - self.sync.rtio += [ + self.sync += [ header.type.eq(1), # body type is baseband data If(self.serializer.stb, self.ch0.dds.stb.eq(1), # synchronize diff --git a/artiq/gateware/rtio/phy/ttl_serdes_7series.py b/artiq/gateware/rtio/phy/ttl_serdes_7series.py index 841032c63..1f467d565 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_7series.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_7series.py @@ -19,7 +19,7 @@ class _OSERDESE2_8X(Module): p_INIT_OQ=0b11111111 if invert else 0b00000000, o_OQ=self.ser_out, o_TQ=self.t_out, i_RST=ResetSignal("rio_phy"), - i_CLK=ClockSignal("rtiox4"), + i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("rio_phy"), i_D1=o[0] ^ invert, i_D2=o[1] ^ invert, i_D3=o[2] ^ invert, i_D4=o[3] ^ invert, i_D5=o[4] ^ invert, i_D6=o[5] ^ invert, i_D7=o[6] ^ invert, i_D8=o[7] ^ invert, @@ -43,8 +43,8 @@ class _ISERDESE2_8X(Module): o_Q1=i[7], o_Q2=i[6], o_Q3=i[5], o_Q4=i[4], o_Q5=i[3], o_Q6=i[2], o_Q7=i[1], o_Q8=i[0], i_D=self.ser_in, - i_CLK=ClockSignal("rtiox4"), - i_CLKB=~ClockSignal("rtiox4"), + i_CLK=ClockSignal("sys4x"), + i_CLKB=~ClockSignal("sys4x"), i_CE1=1, i_RST=ResetSignal("rio_phy"), i_CLKDIV=ClockSignal("rio_phy")) diff --git a/artiq/gateware/rtio/phy/ttl_serdes_ultrascale.py b/artiq/gateware/rtio/phy/ttl_serdes_ultrascale.py index 0dbe613ac..3cc0f02ef 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_ultrascale.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_ultrascale.py @@ -18,8 +18,8 @@ class _OSERDESE3(Module): p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, p_IS_RST_INVERTED=0, o_OQ=self.ser_out, o_T_OUT=self.t_out, - i_RST=ResetSignal("rtio"), - i_CLK=ClockSignal("rtiox"), i_CLKDIV=ClockSignal("rtio"), + i_RST=ResetSignal("sys"), + i_CLK=ClockSignal("rtiox"), i_CLKDIV=ClockSignal("sys"), i_D=self.o, i_T=self.t_in) @@ -39,11 +39,11 @@ class _ISERDESE3(Module): p_DATA_WIDTH=dw, i_D=self.ser_in, - i_RST=ResetSignal("rtio"), + i_RST=ResetSignal("sys"), i_FIFO_RD_EN=0, i_CLK=ClockSignal("rtiox"), i_CLK_B=ClockSignal("rtiox"), # locally inverted - i_CLKDIV=ClockSignal("rtio"), + i_CLKDIV=ClockSignal("sys"), o_Q=Cat(*[self.i[i] for i in reversed(range(dw))])) diff --git a/artiq/gateware/rtio/sed/core.py b/artiq/gateware/rtio/sed/core.py index 7d0b0de4e..2b3611854 100644 --- a/artiq/gateware/rtio/sed/core.py +++ b/artiq/gateware/rtio/sed/core.py @@ -20,8 +20,8 @@ class SED(Module): gates_cdr = lambda x: x output_driver_cdr = lambda x: x elif mode == "async": - lane_dist_cdr = ClockDomainsRenamer("rsys") - fifos_cdr = ClockDomainsRenamer({"write": "rsys", "read": "rio"}) + lane_dist_cdr = ClockDomainsRenamer("sys") + fifos_cdr = ClockDomainsRenamer({"write": "sys", "read": "rio"}) gates_cdr = ClockDomainsRenamer("rio") output_driver_cdr = ClockDomainsRenamer("rio") else: diff --git a/artiq/gateware/rtio/tsc.py b/artiq/gateware/rtio/tsc.py index e93744553..d12c69044 100644 --- a/artiq/gateware/rtio/tsc.py +++ b/artiq/gateware/rtio/tsc.py @@ -30,7 +30,7 @@ class TSC(Module): # # # - self.sync.rtio += If(self.load, + self.sync += If(self.load, self.coarse_ts.eq(self.load_value) ).Else( self.coarse_ts.eq(self.coarse_ts + 1) diff --git a/artiq/gateware/rtio/xilinx_clocking.py b/artiq/gateware/rtio/xilinx_clocking.py index 57e6683c4..20e0c36c6 100644 --- a/artiq/gateware/rtio/xilinx_clocking.py +++ b/artiq/gateware/rtio/xilinx_clocking.py @@ -17,7 +17,7 @@ class RTIOClockMultiplier(Module, AutoCSR): self.specials += [ Instance("MMCME2_BASE", p_CLKIN1_PERIOD=1e9/rtio_clk_freq, - i_CLKIN1=ClockSignal("rtio"), + i_CLKIN1=ClockSignal("sys"), i_RST=self.pll_reset.storage, o_LOCKED=pll_locked, From 458bd8a9278ba3b388019f69e5bdf5ea167371a1 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Fri, 28 Oct 2022 16:51:41 +0800 Subject: [PATCH 03/85] kasli_generic: remove rtio clockdomain reference --- artiq/gateware/targets/kasli_generic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli_generic.py b/artiq/gateware/targets/kasli_generic.py index bb822f41e..a356aaba1 100755 --- a/artiq/gateware/targets/kasli_generic.py +++ b/artiq/gateware/targets/kasli_generic.py @@ -64,7 +64,7 @@ class GenericStandalone(StandaloneBase): self.add_csr_group("grabber", self.grabber_csr_group) for grabber in self.grabber_csr_group: self.platform.add_false_path_constraints( - self.rtio_crg.cd_rtio.clk, getattr(self, grabber).deserializer.cd_cl.clk) + self.crg.cd_sys.clk, getattr(self, grabber).deserializer.cd_cl.clk) class GenericMaster(MasterBase): From f8eb695c0f8a6423e36403ce7339f8a4b854483c Mon Sep 17 00:00:00 2001 From: mwojcik Date: Fri, 28 Oct 2022 16:53:08 +0800 Subject: [PATCH 04/85] dma test: no more rsys or rtio domains --- artiq/gateware/test/rtio/test_dma.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/test/rtio/test_dma.py b/artiq/gateware/test/rtio/test_dma.py index c5d220a9f..a8ccac564 100644 --- a/artiq/gateware/test/rtio/test_dma.py +++ b/artiq/gateware/test/rtio/test_dma.py @@ -203,11 +203,11 @@ class TestDMA(unittest.TestCase): run_simulation(tb[32], {"sys": [ do_dma(tb[32].dut, 0), monitor(32), (None for _ in range(70)), - ]}, {"sys": 8, "rsys": 8, "rtio": 8, "rio": 8, "rio_phy": 8}) + ]}, {"sys": 8, "sys": 8, "rio": 8, "rio_phy": 8}) run_simulation(tb[64], {"sys": [ do_dma(tb[64].dut, 0), monitor(64), (None for _ in range(70)), - ]}, {"sys": 8, "rsys": 8, "rtio": 8, "rio": 8, "rio_phy": 8}) + ]}, {"sys": 8, "sys": 8, "rio": 8, "rio_phy": 8}) correct_changes = [(timestamp + 11, channel) for channel, timestamp, _, _ in test_writes_full_stack] From 5cd57e8688226ae1e1b642d7dcfdc84c01868288 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Fri, 28 Oct 2022 17:31:34 +0800 Subject: [PATCH 05/85] rtio_clocking: switch clocks and reboot --- artiq/firmware/runtime/rtio_clocking.rs | 72 +++++++++++++++++-------- 1 file changed, 49 insertions(+), 23 deletions(-) diff --git a/artiq/firmware/runtime/rtio_clocking.rs b/artiq/firmware/runtime/rtio_clocking.rs index f0330b4d9..1c61437d9 100644 --- a/artiq/firmware/runtime/rtio_clocking.rs +++ b/artiq/firmware/runtime/rtio_clocking.rs @@ -1,8 +1,10 @@ use board_misoc::config; #[cfg(si5324_as_synthesizer)] use board_artiq::si5324; +#[cfg(any(soc_platform = "kasli", has_drtio))] +use board_misoc::csr; #[cfg(has_drtio)] -use board_misoc::{csr, clock}; +use board_misoc::clock; #[derive(Debug, PartialEq)] #[allow(non_camel_case_types)] @@ -54,9 +56,9 @@ fn get_rtio_clock_cfg() -> RtioClock { return RtioClock::Ext0_Synth0_125to125; #[cfg(all(rtio_frequency = "125.0", not(si5324_ext_ref)))] return RtioClock::Int_125; - #[cfg(all(rtio_frequency = "150.0", not(si5324_ext_ref)))] + #[cfg(all(rtio_frequency = "150.0", not(si5324_ext_ref), not(soc_platform = "kasli")))] return RtioClock::Int_150; - #[cfg(all(rtio_frequency = "100.0", not(si5324_ext_ref)))] + #[cfg(all(rtio_frequency = "100.0", not(si5324_ext_ref), not(soc_platform = "kasli")))] return RtioClock::Int_100; //in case nothing is set return RtioClock::Int_125; @@ -134,7 +136,7 @@ fn setup_si5324_as_synthesizer(cfg: RtioClock) { } }, RtioClock::Ext0_Synth0_100to125 => { // 125MHz output, from 100MHz CLKINx reference, 586 Hz loop bandwidth - info!("using 10MHz reference to make 125MHz RTIO clock with PLL"); + info!("using 100MHz reference to make 125MHz RTIO clock with PLL"); si5324::FrequencySettings { n1_hs : 10, nc1_ls : 4, @@ -147,7 +149,7 @@ fn setup_si5324_as_synthesizer(cfg: RtioClock) { } }, RtioClock::Ext0_Synth0_125to125 => { // 125MHz output, from 125MHz CLKINx reference, 606 Hz loop bandwidth - info!("using 10MHz reference to make 125MHz RTIO clock with PLL"); + info!("using 125MHz reference to make 125MHz RTIO clock with PLL"); si5324::FrequencySettings { n1_hs : 5, nc1_ls : 8, @@ -197,7 +199,7 @@ fn setup_si5324_as_synthesizer(cfg: RtioClock) { bwsel : 4, crystal_ref: true } - } + }, _ => { // 125MHz output like above, default (if chosen option is not supported) warn!("rtio_clock setting '{:?}' is not supported. Falling back to default internal 125MHz RTIO clock.", cfg); si5324::FrequencySettings { @@ -225,26 +227,50 @@ fn setup_si5324_as_synthesizer(cfg: RtioClock) { si5324::setup(&si5324_settings, si5324_ref_input).expect("cannot initialize Si5324"); } +#[cfg(si5324_as_synthesizer)] +fn setup_si5324(clock_cfg: RtioClock) { + #[cfg(soc_platform = "kasli")] + { + let switched = unsafe { + csr::crg::switch_done_read() + }; + if switched == 1 { + info!("Clocking has already been set up."); + return; + } + } + #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] + let si5324_ext_input = si5324::Input::Ckin1; + #[cfg(all(soc_platform = "kasli", not(hw_rev = "v2.0")))] + let si5324_ext_input = si5324::Input::Ckin2; + #[cfg(soc_platform = "metlino")] + let si5324_ext_input = si5324::Input::Ckin2; + #[cfg(soc_platform = "kc705")] + let si5324_ext_input = si5324::Input::Ckin2; + match clock_cfg { + RtioClock::Ext0_Bypass => { + info!("using external RTIO clock with PLL bypass"); + si5324::bypass(si5324_ext_input).expect("cannot bypass Si5324") + }, + _ => setup_si5324_as_synthesizer(clock_cfg), + } + + // switch sysclk source to si5324 + #[cfg(soc_platform = "kasli")] + { + // excessive dots will be cut off by the reboot + info!("Switching sys clock, rebooting.................."); + unsafe { + csr::crg::clock_sel_write(1); + } + } +} + + pub fn init() { let clock_cfg = get_rtio_clock_cfg(); #[cfg(si5324_as_synthesizer)] - { - #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] - let si5324_ext_input = si5324::Input::Ckin1; - #[cfg(all(soc_platform = "kasli", not(hw_rev = "v2.0")))] - let si5324_ext_input = si5324::Input::Ckin2; - #[cfg(soc_platform = "metlino")] - let si5324_ext_input = si5324::Input::Ckin2; - #[cfg(soc_platform = "kc705")] - let si5324_ext_input = si5324::Input::Ckin2; - match clock_cfg { - RtioClock::Ext0_Bypass => { - info!("using external RTIO clock with PLL bypass"); - si5324::bypass(si5324_ext_input).expect("cannot bypass Si5324") - }, - _ => setup_si5324_as_synthesizer(clock_cfg), - } - } + setup_si5324(clock_cfg); #[cfg(has_drtio)] { From af0b94bb348c40875e7032b8dd50098de922b377 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Fri, 28 Oct 2022 17:32:12 +0800 Subject: [PATCH 06/85] rtio_clock: remove 150MHz support --- artiq/firmware/runtime/rtio_clocking.rs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/artiq/firmware/runtime/rtio_clocking.rs b/artiq/firmware/runtime/rtio_clocking.rs index 1c61437d9..8c44cca4f 100644 --- a/artiq/firmware/runtime/rtio_clocking.rs +++ b/artiq/firmware/runtime/rtio_clocking.rs @@ -12,7 +12,6 @@ pub enum RtioClock { Default, Int_125, Int_100, - Int_150, Ext0_Bypass, Ext0_Synth0_10to125, Ext0_Synth0_100to125, @@ -25,7 +24,6 @@ fn get_rtio_clock_cfg() -> RtioClock { let res = match result { Ok("int_125") => RtioClock::Int_125, Ok("int_100") => RtioClock::Int_100, - Ok("int_150") => RtioClock::Int_150, Ok("ext0_bypass") => RtioClock::Ext0_Bypass, Ok("ext0_bypass_125") => RtioClock::Ext0_Bypass, Ok("ext0_bypass_100") => RtioClock::Ext0_Bypass, @@ -56,8 +54,6 @@ fn get_rtio_clock_cfg() -> RtioClock { return RtioClock::Ext0_Synth0_125to125; #[cfg(all(rtio_frequency = "125.0", not(si5324_ext_ref)))] return RtioClock::Int_125; - #[cfg(all(rtio_frequency = "150.0", not(si5324_ext_ref), not(soc_platform = "kasli")))] - return RtioClock::Int_150; #[cfg(all(rtio_frequency = "100.0", not(si5324_ext_ref), not(soc_platform = "kasli")))] return RtioClock::Int_100; //in case nothing is set @@ -161,19 +157,6 @@ fn setup_si5324_as_synthesizer(cfg: RtioClock) { crystal_ref: false } }, - RtioClock::Int_150 => { // 150MHz output, from crystal - info!("using internal 150MHz RTIO clock"); - si5324::FrequencySettings { - n1_hs : 9, - nc1_ls : 4, - n2_hs : 10, - n2_ls : 33732, - n31 : 7139, - n32 : 7139, - bwsel : 3, - crystal_ref: true - } - }, RtioClock::Int_100 => { // 100MHz output, from crystal. Also used as reference for Sayma HMC830. info!("using internal 100MHz RTIO clock"); si5324::FrequencySettings { From ad000609ced68ab84457265bd5b12b28429cf0a4 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Mon, 31 Oct 2022 15:25:51 +0800 Subject: [PATCH 07/85] simplify tsc with no rtio/sys clk distinction --- artiq/gateware/rtio/cdc.py | 2 +- artiq/gateware/rtio/core.py | 2 +- artiq/gateware/rtio/tsc.py | 24 +----------------------- 3 files changed, 3 insertions(+), 25 deletions(-) diff --git a/artiq/gateware/rtio/cdc.py b/artiq/gateware/rtio/cdc.py index cc0201969..bd0b11d37 100644 --- a/artiq/gateware/rtio/cdc.py +++ b/artiq/gateware/rtio/cdc.py @@ -15,7 +15,7 @@ class GrayCodeTransfer(Module): # convert to Gray code value_gray_rtio = Signal(width, reset_less=True) - self.sync += value_gray_rtio.eq(self.i ^ self.i[1:]) + self.sync.rtio += value_gray_rtio.eq(self.i ^ self.i[1:]) # transfer to system clock domain value_gray_sys = Signal(width) value_gray_rtio.attr.add("no_retiming") diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index 7b3b6d6fa..66144ceca 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -66,7 +66,7 @@ class Core(Module, AutoCSR): interface=self.cri) self.submodules += outputs self.comb += outputs.coarse_timestamp.eq(tsc.coarse_ts) - self.sync += outputs.minimum_coarse_timestamp.eq(tsc.coarse_ts_sys + 16) + self.sync += outputs.minimum_coarse_timestamp.eq(tsc.coarse_ts + 16) inputs = InputCollector(tsc, channels, "sync", quash_channels=quash_channels, diff --git a/artiq/gateware/rtio/tsc.py b/artiq/gateware/rtio/tsc.py index d12c69044..f2c316047 100644 --- a/artiq/gateware/rtio/tsc.py +++ b/artiq/gateware/rtio/tsc.py @@ -1,8 +1,5 @@ from migen import * -from artiq.gateware.rtio.cdc import GrayCodeTransfer - - class TSC(Module): def __init__(self, mode, glbl_fine_ts_width=0): self.glbl_fine_ts_width = glbl_fine_ts_width @@ -11,22 +8,10 @@ class TSC(Module): self.coarse_ts = Signal(64 - glbl_fine_ts_width) self.full_ts = Signal(64) - # in sys domain - # monotonic, may lag behind the counter in the IO clock domain, but - # not be ahead of it. - self.coarse_ts_sys = Signal.like(self.coarse_ts) - self.full_ts_sys = Signal(64) - - # in rtio domain self.load = Signal() self.load_value = Signal.like(self.coarse_ts) - if mode == "async": - self.full_ts_cri = self.full_ts_sys - elif mode == "sync": - self.full_ts_cri = self.full_ts - else: - raise ValueError + self.full_ts_cri = self.full_ts # # # @@ -35,14 +20,7 @@ class TSC(Module): ).Else( self.coarse_ts.eq(self.coarse_ts + 1) ) - coarse_ts_cdc = GrayCodeTransfer(len(self.coarse_ts)) # from rtio to sys - self.submodules += coarse_ts_cdc - self.comb += [ - coarse_ts_cdc.i.eq(self.coarse_ts), - self.coarse_ts_sys.eq(coarse_ts_cdc.o) - ] self.comb += [ self.full_ts.eq(self.coarse_ts << glbl_fine_ts_width), - self.full_ts_sys.eq(self.coarse_ts_sys << glbl_fine_ts_width) ] From 0b3c232819cdf2b766336c20a64ebf57ba4b0bbb Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 22 Nov 2022 11:19:05 +0000 Subject: [PATCH 08/85] language: Clarify error message for unprocessed arguments "Unexpected argument(s)" would be another less ambiguous, shorter phrasing. --- artiq/language/environment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/language/environment.py b/artiq/language/environment.py index 9ce7034cc..1147e2333 100644 --- a/artiq/language/environment.py +++ b/artiq/language/environment.py @@ -229,7 +229,7 @@ class ProcessArgumentManager: unprocessed = set(self.unprocessed_arguments.keys()) -\ self._processed_arguments if unprocessed: - raise AttributeError("Invalid argument(s): " + + raise AttributeError("Supplied argument(s) not queried in experiment: " + ", ".join(unprocessed)) class HasEnvironment: From f7f027001efeb63fed490bb72a540f541a65aea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=81=AB=E7=84=9A=20=E5=AF=8C=E8=89=AF?= Date: Wed, 23 Nov 2022 12:10:32 +0800 Subject: [PATCH 09/85] compiler: insert new lines into long synthesized code (#1986) --- artiq/compiler/embedding.py | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/artiq/compiler/embedding.py b/artiq/compiler/embedding.py index 359584d6d..8eb5cfae2 100644 --- a/artiq/compiler/embedding.py +++ b/artiq/compiler/embedding.py @@ -169,6 +169,7 @@ class EmbeddingMap: class ASTSynthesizer: def __init__(self, embedding_map, value_map, quote_function=None, expanded_from=None): self.source = "" + self.source_last_new_line = 0 self.source_buffer = source.Buffer(self.source, "") self.embedding_map = embedding_map self.value_map = value_map @@ -187,6 +188,14 @@ class ASTSynthesizer: return source.Range(self.source_buffer, range_from, range_to, expanded_from=self.expanded_from) + def _add_iterable(self, fragment): + # Since DILocation points on the beginning of the piece of source + # we don't care if the fragment's end will overflow LLVM's limit. + if len(self.source) - self.source_last_new_line >= 2**16: + fragment = "\\\n" + fragment + self.source_last_new_line = len(self.source) + 2 + return self._add(fragment) + def fast_quote_list(self, value): elts = [None] * len(value) is_T = False @@ -245,7 +254,7 @@ class ASTSynthesizer: for index, elt in enumerate(value): elts[index] = self.quote(elt) if index < len(value) - 1: - self._add(", ") + self._add_iterable(", ") return elts def quote(self, value): @@ -296,28 +305,28 @@ class ASTSynthesizer: loc=self._add(repr(value))) elif isinstance(value, str): return asttyped.StrT(s=value, ctx=None, type=builtins.TStr(), - loc=self._add(repr(value))) + loc=self._add_iterable(repr(value))) elif isinstance(value, bytes): return asttyped.StrT(s=value, ctx=None, type=builtins.TBytes(), - loc=self._add(repr(value))) + loc=self._add_iterable(repr(value))) elif isinstance(value, bytearray): - quote_loc = self._add('`') - repr_loc = self._add(repr(value)) - unquote_loc = self._add('`') + quote_loc = self._add_iterable('`') + repr_loc = self._add_iterable(repr(value)) + unquote_loc = self._add_iterable('`') loc = quote_loc.join(unquote_loc) return asttyped.QuoteT(value=value, type=builtins.TByteArray(), loc=loc) elif isinstance(value, list): - begin_loc = self._add("[") + begin_loc = self._add_iterable("[") elts = self.fast_quote_list(value) - end_loc = self._add("]") + end_loc = self._add_iterable("]") return asttyped.ListT(elts=elts, ctx=None, type=builtins.TList(), begin_loc=begin_loc, end_loc=end_loc, loc=begin_loc.join(end_loc)) elif isinstance(value, tuple): - begin_loc = self._add("(") + begin_loc = self._add_iterable("(") elts = self.fast_quote_list(value) - end_loc = self._add(")") + end_loc = self._add_iterable(")") return asttyped.TupleT(elts=elts, ctx=None, type=types.TTuple([e.type for e in elts]), begin_loc=begin_loc, end_loc=end_loc, From f2c1e663a7e206241f05b4c7d6a37b122ebb4e2d Mon Sep 17 00:00:00 2001 From: mwojcik Date: Wed, 9 Nov 2022 12:56:33 +0800 Subject: [PATCH 10/85] regenerate suservo_coherent patch with var_urukul base --- .../suservo_coherent_after_var.diff | 1813 +++++++++++++++++ 1 file changed, 1813 insertions(+) create mode 100644 experimental-features/suservo_coherent_after_var.diff diff --git a/experimental-features/suservo_coherent_after_var.diff b/experimental-features/suservo_coherent_after_var.diff new file mode 100644 index 000000000..961289814 --- /dev/null +++ b/experimental-features/suservo_coherent_after_var.diff @@ -0,0 +1,1813 @@ +diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py +index 801b689c..bc19afe2 100644 +--- a/artiq/coredevice/ad9910.py ++++ b/artiq/coredevice/ad9910.py +@@ -277,6 +277,10 @@ class AD9910: + + :param addr: Register address + """ ++ return self.read32_impl(addr) ++ ++ @kernel ++ def read32_impl(self, addr): + self.bus.set_config_mu(urukul.SPI_CONFIG, 8, + urukul.SPIT_DDS_WR, self.chip_select) + self.bus.write((addr | 0x80) << 24) +@@ -981,7 +985,8 @@ class AD9910: + + @kernel + def tune_sync_delay(self, +- search_seed: TInt32 = 15) -> TTuple([TInt32, TInt32]): ++ search_seed: TInt32 = 15, ++ cpld_channel_idx: TInt32 = -1) -> TTuple([TInt32, TInt32]): + """Find a stable SYNC_IN delay. + + This method first locates a valid SYNC_IN delay at zero validation +@@ -997,6 +1002,9 @@ class AD9910: + Defaults to 15 (half range). + :return: Tuple of optimal delay and window size. + """ ++ if cpld_channel_idx == -1: ++ cpld_channel_idx = self.chip_select - 4 ++ assert 0 <= cpld_channel_idx < 4, "Invalid channel index" + if not self.cpld.sync_div: + raise ValueError("parent cpld does not drive SYNC") + search_span = 31 +@@ -1019,7 +1027,7 @@ class AD9910: + delay(100 * us) + err = urukul_sta_smp_err(self.cpld.sta_read()) + delay(100 * us) # slack +- if not (err >> (self.chip_select - 4)) & 1: ++ if not (err >> cpld_channel_idx) & 1: + next_seed = in_delay + break + if next_seed >= 0: # valid delay found, scan next window +diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py +index a89cdcca..f7b516a4 100644 +--- a/artiq/coredevice/suservo.py ++++ b/artiq/coredevice/suservo.py +@@ -1,9 +1,11 @@ + from artiq.language.core import kernel, delay, delay_mu, portable + from artiq.language.units import us, ns ++from artiq.language import * + from artiq.coredevice.rtio import rtio_output, rtio_input_data + from artiq.coredevice import spi2 as spi +-from artiq.coredevice import urukul, sampler ++from artiq.coredevice import urukul, sampler, ad9910 + from math import ceil, log2 ++from numpy import int32, int64 + + + COEFF_WIDTH = 18 # Must match gateware IIRWidths.coeff +@@ -11,6 +13,7 @@ Y_FULL_SCALE_MU = (1 << (COEFF_WIDTH - 1)) - 1 + T_CYCLE = (2*(8 + 64) + 2)*8*ns # Must match gateware Servo.t_cycle. + COEFF_SHIFT = 11 # Must match gateware IIRWidths.shift + PROFILE_WIDTH = 5 # Must match gateware IIRWidths.profile ++FINE_TS_WIDTH = 3 # Must match gateware IIRWidths.ioup_dly + + + @portable +@@ -39,7 +42,7 @@ class SUServo: + and a photodetector connected to Sampler. + + Additionally SU Servo supports multiple preconfigured profiles per channel +- and features like automatic integrator hold. ++ and features like automatic integrator hold and coherent phase tracking. + + Notes: + +@@ -63,7 +66,8 @@ class SUServo: + """ + kernel_invariants = {"channel", "core", "pgia", "cplds", "ddses", + "ref_period_mu", "num_channels", "coeff_sel", +- "state_sel", "config_addr", "write_enable"} ++ "state_sel", "io_dly_addr", "config_addr", ++ "write_enable"} + + def __init__(self, dmgr, channel, pgia_device, + cpld_devices, dds_devices, +@@ -86,6 +90,7 @@ class SUServo: + self.num_channels = 4 * len(dds_devices) + channel_width = ceil(log2(self.num_channels)) + coeff_depth = PROFILE_WIDTH + channel_width + 3 ++ self.io_dly_addr = 1 << (coeff_depth - 2) + self.state_sel = 2 << (coeff_depth - 2) + self.config_addr = 3 << (coeff_depth - 2) + self.coeff_sel = 1 << coeff_depth +@@ -119,8 +124,20 @@ class SUServo: + prev_cpld_cfg = cpld.cfg_reg + cpld.cfg_write(prev_cpld_cfg | (0xf << urukul.CFG_MASK_NU)) + dds.init(blind=True) ++ ++ if dds.sync_data.sync_delay_seed != -1: ++ for channel_idx in range(4): ++ mask_nu_this = 1 << (urukul.CFG_MASK_NU + channel_idx) ++ cpld.cfg_write(prev_cpld_cfg | mask_nu_this) ++ delay(8 * us) ++ dds.tune_sync_delay(dds.sync_data.sync_delay_seed, ++ cpld_channel_idx=channel_idx) ++ delay(50 * us) + cpld.cfg_write(prev_cpld_cfg) + ++ self.set_io_update_delays( ++ [dds.sync_data.io_update_delay for dds in self.ddses]) ++ + @kernel + def write(self, addr, value): + """Write to servo memory. +@@ -245,6 +262,18 @@ class SUServo: + gain = (self.gains >> (channel*2)) & 0b11 + return adc_mu_to_volts(val, gain) + ++ @kernel ++ def set_io_update_delays(self, dlys): ++ """Set IO_UPDATE pulse alignment delays. ++ ++ :param dlys: List of delays for each Urukul ++ """ ++ bits = 0 ++ mask_fine_ts = (1 << FINE_TS_WIDTH) - 1 ++ for i in range(len(dlys)): ++ bits |= (dlys[i] & mask_fine_ts) << (FINE_TS_WIDTH * i) ++ self.write(self.io_dly_addr, bits) ++ + + class Channel: + """Sampler-Urukul Servo channel +@@ -265,7 +294,7 @@ class Channel: + self.dds = self.servo.ddses[self.servo_channel // 4] + + @kernel +- def set(self, en_out, en_iir=0, profile=0): ++ def set(self, en_out, en_iir=0, profile=0, en_pt=0): + """Operate channel. + + This method does not advance the timeline. Output RF switch setting +@@ -279,9 +308,26 @@ class Channel: + :param en_out: RF switch enable + :param en_iir: IIR updates enable + :param profile: Active profile (0-31) ++ :param en_pt: Coherent phase tracking enable ++ * en_pt=1: "coherent phase mode" ++ * en_pt=0: "continuous phase mode" ++ (see :func:`artiq.coredevice.ad9910.AD9910.set_phase_mode` for a ++ definition of the phase modes) + """ + rtio_output(self.channel << 8, +- en_out | (en_iir << 1) | (profile << 2)) ++ en_out | (en_iir << 1) | (en_pt << 2) | (profile << 3)) ++ ++ @kernel ++ def set_reference_time(self): ++ """Set reference time for "coherent phase mode" (see :meth:`set`). ++ ++ This method does not advance the timeline. ++ With en_pt=1 (see :meth:`set`), the tracked DDS output phase of ++ this channel will refer to the current timeline position. ++ ++ """ ++ fine_ts = now_mu() & ((1 << FINE_TS_WIDTH) - 1) ++ rtio_output(self.channel << 8 | 1, self.dds.sysclk_per_mu * fine_ts) + + @kernel + def set_dds_mu(self, profile, ftw, offs, pow_=0): +@@ -592,3 +638,217 @@ class Channel: + raise ValueError("Invalid SUServo y-value!") + self.set_y_mu(profile, y_mu) + return y_mu ++ ++ ++class CPLD(urukul.CPLD): ++ """ ++ This module contains a subclass of the Urukul driver class in artiq.coredevice ++ adapted to use CPLD read-back via half-duplex SPI. Only the 8 LSBs can be read ++ back as the read-back buffer on the CPLD is 8 bits wide. ++ """ ++ ++ def __init__(self, dmgr, spi_device, io_update_device=None, ++ **kwargs): ++ # Separate IO_UPDATE TTL output device used by SUServo core, ++ # if active, else by artiq.coredevice.suservo.AD9910 ++ # :meth:`measure_io_update_alignment`. ++ # The urukul.CPLD driver utilises the CPLD CFG register ++ # option instead for pulsing IO_UPDATE of masked DDSs. ++ self.io_update_ttl = dmgr.get(io_update_device) ++ urukul.CPLD.__init__(self, dmgr, spi_device, **kwargs) ++ ++ @kernel ++ def enable_readback(self): ++ """ ++ This method sets the RB_EN flag in the Urukul CPLD configuration ++ register. Once set, the CPLD expects an alternating sequence of ++ two SPI transactions: ++ ++ * 1: Any transaction. If returning data, the 8 LSBs ++ of that will be stored in the CPLD. ++ ++ * 2: One read transaction in half-duplex SPI mode shifting ++ out data from the CPLD over MOSI (use :meth:`readback`). ++ ++ To end this protocol, call :meth:`disable_readback` during step 1. ++ """ ++ self.cfg_write(self.cfg_reg | (1 << urukul.CFG_RB_EN)) ++ ++ @kernel ++ def disable_readback(self): ++ """ ++ This method clears the RB_EN flag in the Urukul CPLD configuration ++ register. This marks the end of the readback protocol (see ++ :meth:`enable_readback`). ++ """ ++ self.cfg_write(self.cfg_reg & ~(1 << urukul.CFG_RB_EN)) ++ ++ @kernel ++ def sta_read(self, full=False): ++ """ ++ Read from status register ++ ++ :param full: retrieve status register by concatenating data from ++ several readback transactions. ++ """ ++ self.enable_readback() ++ self.sta_read_impl() ++ delay(16 * us) # slack ++ r = self.readback() << urukul.STA_RF_SW ++ delay(16 * us) # slack ++ if full: ++ self.enable_readback() # dummy write ++ r |= self.readback(urukul.CS_RB_PLL_LOCK) << urukul.STA_PLL_LOCK ++ delay(16 * us) # slack ++ self.enable_readback() # dummy write ++ r |= self.readback(urukul.CS_RB_PROTO_REV) << urukul.STA_PROTO_REV ++ delay(16 * us) # slack ++ self.disable_readback() ++ return r ++ ++ @kernel ++ def proto_rev_read(self): ++ """Read 8 LSBs of proto_rev""" ++ self.enable_readback() ++ self.enable_readback() # dummy write ++ r = self.readback(urukul.CS_RB_PROTO_REV) ++ self.disable_readback() ++ return r ++ ++ @kernel ++ def pll_lock_read(self): ++ """Read PLL lock status""" ++ self.enable_readback() ++ self.enable_readback() # dummy write ++ r = self.readback(urukul.CS_RB_PLL_LOCK) ++ self.disable_readback() ++ return r & 0xf ++ ++ @kernel ++ def get_att_mu(self): ++ # Different behaviour to urukul.CPLD.get_att_mu: Here, the ++ # latch enable of the attenuators activates 31.5dB ++ # attenuation during the transactions. ++ att_reg = int32(0) ++ self.enable_readback() ++ for i in range(4): ++ self.core.break_realtime() ++ self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 8, ++ urukul.SPIT_ATT_RD, urukul.CS_ATT) ++ self.bus.write(0) # shift in zeros, shift out next 8 bits ++ r = self.readback() & 0xff ++ att_reg |= r << (8 * i) ++ ++ delay(16 * us) # slack ++ self.disable_readback() ++ ++ self.att_reg = int32(att_reg) ++ delay(8 * us) # slack ++ self.set_all_att_mu(self.att_reg) # shift and latch current value again ++ return self.att_reg ++ ++ @kernel ++ def readback(self, cs=urukul.CS_RB_LSBS): ++ """Read from the readback register in half-duplex SPI mode ++ See :meth:`enable_readback` for usage instructions. ++ ++ :param cs: Select data to be returned from the readback register. ++ - urukul.CS_RB_LSBS does not modify the readback register upon readback ++ - urukul.CS_RB_PROTO_REV loads the 8 LSBs of proto_rev ++ - urukul.CS_PLL_LOCK loads the PLL lock status bits concatenated with the ++ IFC mode bits ++ :return: CPLD readback register. ++ """ ++ self.bus.set_config_mu( ++ urukul.SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT | spi.SPI_HALF_DUPLEX, ++ 8, urukul.SPIT_CFG_RD, cs) ++ self.bus.write(0) ++ return int32(self.bus.read()) ++ ++ ++class AD9910(ad9910.AD9910): ++ """ ++ This module contains a subclass of the AD9910 driver class in artiq.coredevice ++ using CPLD read-back via half-duplex SPI. ++ """ ++ ++ # Re-declare set of kernel invariants to avoid warning about non-existent ++ # `sw` attribute, as the AD9910 (instance) constructor writes to the ++ # class attributes. ++ kernel_invariants = { ++ "chip_select", "cpld", "core", "bus", "ftw_per_hz", "sysclk_per_mu" ++ } ++ ++ @kernel ++ def read32(self, addr): ++ """ Read from a 32-bit register ++ ++ This method returns only the 8 LSBs of the return value. ++ """ ++ self.cpld.enable_readback() ++ self.read32_impl(addr) ++ delay(12 * us) # slack ++ r = self.cpld.readback() ++ delay(12 * us) # slack ++ self.cpld.disable_readback() ++ return r ++ ++ @kernel ++ def read64(self, addr): ++ # 3-wire SPI transactions consisting of multiple transfers are not supported. ++ raise NotImplementedError ++ ++ @kernel ++ def read_ram(self, data): ++ # 3-wire SPI transactions consisting of multiple transfers are not supported. ++ raise NotImplementedError ++ ++ @kernel ++ def measure_io_update_alignment(self, delay_start, delay_stop): ++ """Use the digital ramp generator to locate the alignment between ++ IO_UPDATE and SYNC_CLK. ++ ++ Refer to `artiq.coredevice.ad9910` :meth:`measure_io_update_alignment`. ++ In order that this method can operate the io_update_ttl also used by the SUServo ++ core, deactivate the servo before (see :meth:`set_config`). ++ """ ++ # set up DRG ++ self.set_cfr1(drg_load_lrr=1, drg_autoclear=1) ++ # DRG -> FTW, DRG enable ++ self.set_cfr2(drg_enable=1) ++ # no limits ++ self.write64(ad9910._AD9910_REG_RAMP_LIMIT, -1, 0) ++ # DRCTL=0, dt=1 t_SYNC_CLK ++ self.write32(ad9910._AD9910_REG_RAMP_RATE, 0x00010000) ++ # dFTW = 1, (work around negative slope) ++ self.write64(ad9910._AD9910_REG_RAMP_STEP, -1, 0) ++ # un-mask DDS ++ cfg_masked = self.cpld.cfg_reg ++ self.cpld.cfg_write(cfg_masked & ~(0xf << urukul.CFG_MASK_NU)) ++ delay(70 * us) # slack ++ # delay io_update after RTIO edge ++ t = now_mu() + 8 & ~7 ++ at_mu(t + delay_start) ++ # assumes a maximum t_SYNC_CLK period ++ self.cpld.io_update_ttl.pulse(self.core.mu_to_seconds(16 - delay_start)) # realign ++ # re-mask DDS ++ self.cpld.cfg_write(cfg_masked) ++ delay(10 * us) # slack ++ # disable DRG autoclear and LRR on io_update ++ self.set_cfr1() ++ delay(10 * us) # slack ++ # stop DRG ++ self.write64(ad9910._AD9910_REG_RAMP_STEP, 0, 0) ++ delay(10 * us) # slack ++ # un-mask DDS ++ self.cpld.cfg_write(cfg_masked & ~(0xf << urukul.CFG_MASK_NU)) ++ at_mu(t + 0x20000 + delay_stop) ++ self.cpld.io_update_ttl.pulse_mu(16 - delay_stop) # realign ++ # re-mask DDS ++ self.cpld.cfg_write(cfg_masked) ++ ftw = self.read32(ad9910._AD9910_REG_FTW) # read out effective FTW ++ delay(100 * us) # slack ++ # disable DRG ++ self.set_cfr2(drg_enable=0) ++ self.cpld.io_update.pulse_mu(16) ++ return ftw & 1 +diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py +index 2fd66bd6..61fd4762 100644 +--- a/artiq/coredevice/urukul.py ++++ b/artiq/coredevice/urukul.py +@@ -24,6 +24,7 @@ SPIT_DDS_RD = 16 + CFG_RF_SW = 0 + CFG_LED = 4 + CFG_PROFILE = 8 ++CFG_RB_EN = 11 + CFG_IO_UPDATE = 12 + CFG_MASK_NU = 13 + CFG_CLK_SEL0 = 17 +@@ -51,18 +52,23 @@ CS_DDS_CH0 = 4 + CS_DDS_CH1 = 5 + CS_DDS_CH2 = 6 + CS_DDS_CH3 = 7 ++# chip selects for readback ++CS_RB_PROTO_REV = 1 ++CS_RB_PLL_LOCK = 2 ++CS_RB_LSBS = 3 + + # Default profile + DEFAULT_PROFILE = 7 + + + @portable +-def urukul_cfg(rf_sw, led, profile, io_update, mask_nu, ++def urukul_cfg(rf_sw, led, profile, rb_en, io_update, mask_nu, + clk_sel, sync_sel, rst, io_rst, clk_div): + """Build Urukul CPLD configuration register""" + return ((rf_sw << CFG_RF_SW) | + (led << CFG_LED) | + (profile << CFG_PROFILE) | ++ (rb_en << CFG_RB_EN) | + (io_update << CFG_IO_UPDATE) | + (mask_nu << CFG_MASK_NU) | + ((clk_sel & 0x01) << CFG_CLK_SEL0) | +@@ -191,7 +197,7 @@ class CPLD: + assert sync_div is None + sync_div = 0 + +- self.cfg_reg = urukul_cfg(rf_sw=rf_sw, led=0, profile=DEFAULT_PROFILE, ++ self.cfg_reg = urukul_cfg(rf_sw=rf_sw, led=0, profile=DEFAULT_PROFILE, rb_en=0, + io_update=0, mask_nu=0, clk_sel=clk_sel, + sync_sel=sync_sel, + rst=0, io_rst=0, clk_div=clk_div) +@@ -226,6 +232,10 @@ class CPLD: + + :return: The status register value. + """ ++ return self.sta_read_impl() ++ ++ @kernel ++ def sta_read_impl(self): + self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, 24, + SPIT_CFG_RD, CS_CFG) + self.bus.write(self.cfg_reg << 8) +diff --git a/artiq/examples/kasli_suservo/device_db.py b/artiq/examples/kasli_suservo/device_db.py +index c52b82a9..8e9d8752 100644 +--- a/artiq/examples/kasli_suservo/device_db.py ++++ b/artiq/examples/kasli_suservo/device_db.py +@@ -142,53 +142,66 @@ device_db = { + "arguments": {"channel": 15}, + }, + ++ "ttl_urukul0_io_update": { ++ "type": "local", ++ "module": "artiq.coredevice.ttl", ++ "class": "TTLOut", ++ "arguments": {"channel": 16} ++ }, ++ "ttl_urukul1_io_update": { ++ "type": "local", ++ "module": "artiq.coredevice.ttl", ++ "class": "TTLOut", ++ "arguments": {"channel": 17} ++ }, ++ + "suservo0_ch0": { + "type": "local", + "module": "artiq.coredevice.suservo", + "class": "Channel", +- "arguments": {"channel": 16, "servo_device": "suservo0"} ++ "arguments": {"channel": 18, "servo_device": "suservo0"} + }, + "suservo0_ch1": { + "type": "local", + "module": "artiq.coredevice.suservo", + "class": "Channel", +- "arguments": {"channel": 17, "servo_device": "suservo0"} ++ "arguments": {"channel": 19, "servo_device": "suservo0"} + }, + "suservo0_ch2": { + "type": "local", + "module": "artiq.coredevice.suservo", + "class": "Channel", +- "arguments": {"channel": 18, "servo_device": "suservo0"} ++ "arguments": {"channel": 20, "servo_device": "suservo0"} + }, + "suservo0_ch3": { + "type": "local", + "module": "artiq.coredevice.suservo", + "class": "Channel", +- "arguments": {"channel": 19, "servo_device": "suservo0"} ++ "arguments": {"channel": 21, "servo_device": "suservo0"} + }, + "suservo0_ch4": { + "type": "local", + "module": "artiq.coredevice.suservo", + "class": "Channel", +- "arguments": {"channel": 20, "servo_device": "suservo0"} ++ "arguments": {"channel": 22, "servo_device": "suservo0"} + }, + "suservo0_ch5": { + "type": "local", + "module": "artiq.coredevice.suservo", + "class": "Channel", +- "arguments": {"channel": 21, "servo_device": "suservo0"} ++ "arguments": {"channel": 23, "servo_device": "suservo0"} + }, + "suservo0_ch6": { + "type": "local", + "module": "artiq.coredevice.suservo", + "class": "Channel", +- "arguments": {"channel": 22, "servo_device": "suservo0"} ++ "arguments": {"channel": 24, "servo_device": "suservo0"} + }, + "suservo0_ch7": { + "type": "local", + "module": "artiq.coredevice.suservo", + "class": "Channel", +- "arguments": {"channel": 23, "servo_device": "suservo0"} ++ "arguments": {"channel": 25, "servo_device": "suservo0"} + }, + + "suservo0": { +@@ -196,7 +209,7 @@ device_db = { + "module": "artiq.coredevice.suservo", + "class": "SUServo", + "arguments": { +- "channel": 24, ++ "channel": 26, + "pgia_device": "spi_sampler0_pgia", + "cpld_devices": ["urukul0_cpld", "urukul1_cpld"], + "dds_devices": ["urukul0_dds", "urukul1_dds"], +@@ -207,33 +220,37 @@ device_db = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", +- "arguments": {"channel": 25} ++ "arguments": {"channel": 27} + }, + + "spi_urukul0": { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", +- "arguments": {"channel": 26} ++ "arguments": {"channel": 28} + }, + "urukul0_cpld": { + "type": "local", +- "module": "artiq.coredevice.urukul", ++ "module": "artiq.coredevice.suservo", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul0", ++ "io_update_device": "ttl_urukul0_io_update", ++ "sync_device": "clkgen_dds_sync_in", + "refclk": 100e6, + "clk_sel": 0 + } + }, + "urukul0_dds": { + "type": "local", +- "module": "artiq.coredevice.ad9910", ++ "module": "artiq.coredevice.suservo", + "class": "AD9910", + "arguments": { + "pll_n": 40, + "chip_select": 3, + "cpld_device": "urukul0_cpld", ++ "io_update_delay": 0, ++ "sync_delay_seed": -1, + } + }, + +@@ -241,26 +258,40 @@ device_db = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", +- "arguments": {"channel": 27} ++ "arguments": {"channel": 29} + }, + "urukul1_cpld": { + "type": "local", +- "module": "artiq.coredevice.urukul", ++ "module": "artiq.coredevice.suservo", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul1", ++ "io_update_device": "ttl_urukul1_io_update", ++ "sync_device": "clkgen_dds_sync_in", + "refclk": 100e6, + "clk_sel": 0 + } + }, + "urukul1_dds": { + "type": "local", +- "module": "artiq.coredevice.ad9910", ++ "module": "artiq.coredevice.suservo", + "class": "AD9910", + "arguments": { + "pll_n": 40, + "chip_select": 3, + "cpld_device": "urukul1_cpld", ++ "io_update_delay": 0, ++ "sync_delay_seed": -1, ++ } ++ }, ++ ++ "clkgen_dds_sync_in": { ++ "type": "local", ++ "module": "artiq.coredevice.ttl", ++ "class": "TTLClockGen", ++ "arguments": { ++ "channel": 30, ++ "acc_width": 4 + } + }, + +diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py +index 5459756f..75eaadcb 100755 +--- a/artiq/frontend/artiq_ddb_template.py ++++ b/artiq/frontend/artiq_ddb_template.py +@@ -424,6 +424,16 @@ class PeripheralManager: + sampler_name = self.get_name("sampler") + urukul_names = [self.get_name("urukul") for _ in range(2)] + channel = count(0) ++ for urukul_name in urukul_names: ++ self.gen(""" ++ device_db["ttl_{urukul_name}_io_update"] = {{ ++ "type": "local", ++ "module": "artiq.coredevice.ttl", ++ "class": "TTLOut", ++ "arguments": {{"channel": 0x{ttl_channel:06x}}} ++ }}""", ++ urukul_name=urukul_name, ++ ttl_channel=rtio_offset+next(channel)) + for i in range(8): + self.gen(""" + device_db["{suservo_name}_ch{suservo_chn}"] = {{ +@@ -472,17 +482,19 @@ class PeripheralManager: + }} + device_db["{urukul_name}_cpld"] = {{ + "type": "local", +- "module": "artiq.coredevice.urukul", ++ "module": "artiq.coredevice.suservo", + "class": "CPLD", + "arguments": {{ + "spi_device": "spi_{urukul_name}", ++ "io_update_device": "ttl_{urukul_name}_io_update", ++ "sync_device": "clkgen_{suservo_name}_dds_sync_in", + "refclk": {refclk}, + "clk_sel": {clk_sel} + }} + }} + device_db["{urukul_name}_dds"] = {{ + "type": "local", +- "module": "artiq.coredevice.ad9910", ++ "module": "artiq.coredevice.suservo", + "class": "AD9910", + "arguments": {{ + "pll_n": {pll_n}, +@@ -490,12 +502,25 @@ class PeripheralManager: + "cpld_device": "{urukul_name}_cpld"{pll_vco} + }} + }}""", ++ suservo_name=suservo_name, + urukul_name=urukul_name, + urukul_channel=rtio_offset+next(channel), + refclk=peripheral.get("refclk", self.master_description["rtio_frequency"]), + clk_sel=peripheral["clk_sel"], + pll_vco=",\n \"pll_vco\": {}".format(pll_vco) if pll_vco is not None else "", + pll_n=peripheral["pll_n"]) ++ self.gen(""" ++ device_db["clkgen_{suservo_name}_dds_sync_in"] = {{ ++ "type": "local", ++ "module": "artiq.coredevice.ttl", ++ "class": "TTLClockGen", ++ "arguments": {{ ++ "channel": 0x{clkgen_channel:06x}, ++ "acc_width": 4 ++ }} ++ }}""", ++ suservo_name=suservo_name, ++ clkgen_channel=rtio_offset+next(channel)) + return next(channel) + + def process_zotino(self, rtio_offset, peripheral): +diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py +index ce00f94f..93d01c07 100644 +--- a/artiq/gateware/eem.py ++++ b/artiq/gateware/eem.py +@@ -6,6 +6,7 @@ from artiq.gateware import rtio + from artiq.gateware.rtio.phy import spi2, ad53xx_monitor, dds, grabber + from artiq.gateware.suservo import servo, pads as servo_pads + from artiq.gateware.rtio.phy import servo as rtservo, fastino, phaser ++from artiq.gateware.rtio.phy import ttl_simple + + + def _eem_signal(i): +@@ -545,7 +546,8 @@ class SUServo(_EEM): + @classmethod + def add_std(cls, target, eems_sampler, eems_urukul, + t_rtt=4, clk=1, shift=11, profile=5, +- iostandard=default_iostandard): ++ sync_gen_cls=ttl_simple.ClockGen, ++ iostandard=default_iostandard, sysclk_per_clk=8): + """Add a 8-channel Sampler-Urukul Servo + + :param t_rtt: upper estimate for clock round-trip propagation time from +@@ -561,6 +563,8 @@ class SUServo(_EEM): + (default: 11) + :param profile: log2 of the number of profiles for each DDS channel + (default: 5) ++ :param sysclk_per_clk: DDS "sysclk" (4*refclk = 1GHz typ.) cycles per ++ FPGA "sys" clock (125MHz typ.) cycles (default: 8) + """ + cls.add_extension( + target, *(eems_sampler + sum(eems_urukul, [])), +@@ -572,6 +576,8 @@ class SUServo(_EEM): + urukul_pads = servo_pads.UrukulPads( + target.platform, *eem_urukul) + target.submodules += sampler_pads, urukul_pads ++ target.rtio_channels.extend( ++ rtio.Channel.from_phy(phy) for phy in urukul_pads.io_update_phys) + # timings in units of RTIO coarse period + adc_p = servo.ADCParams(width=16, channels=8, lanes=4, t_cnvh=4, + # account for SCK DDR to CONV latency +@@ -579,19 +585,20 @@ class SUServo(_EEM): + t_conv=57 - 4, t_rtt=t_rtt + 4) + iir_p = servo.IIRWidths(state=25, coeff=18, adc=16, asf=14, word=16, + accu=48, shift=shift, profile=profile, dly=8) +- dds_p = servo.DDSParams(width=8 + 32 + 16 + 16, +- channels=4 * len(eem_urukul), clk=clk) ++ dds_p = servo.DDSParams(width=8 + 32 + 16 + 16, sysclk_per_clk=sysclk_per_clk, ++ channels=4*len(eem_urukul), clk=clk) + su = servo.Servo(sampler_pads, urukul_pads, adc_p, iir_p, dds_p) + su = ClockDomainsRenamer("rio_phy")(su) + # explicitly name the servo submodule to enable the migen namer to derive + # a name for the adc return clock domain + setattr(target.submodules, "suservo_eem{}".format(eems_sampler[0]), su) + +- ctrls = [rtservo.RTServoCtrl(ctrl) for ctrl in su.iir.ctrl] ++ ctrls = [rtservo.RTServoCtrl(ctrl, ctrl_reftime) ++ for ctrl, ctrl_reftime in zip(su.iir.ctrl, su.iir.ctrl_reftime)] + target.submodules += ctrls + target.rtio_channels.extend( + rtio.Channel.from_phy(ctrl) for ctrl in ctrls) +- mem = rtservo.RTServoMem(iir_p, su) ++ mem = rtservo.RTServoMem(iir_p, su, urukul_pads.io_update_phys) + target.submodules += mem + target.rtio_channels.append(rtio.Channel.from_phy(mem, ififo_depth=4)) + +@@ -601,19 +608,20 @@ class SUServo(_EEM): + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + +- dds_sync = Signal(reset=0) +- for j, eem_urukuli in enumerate(eem_urukul): +- # connect quad-SPI ++ for eem_urukuli in eem_urukul: + spi_p, spi_n = ( + target.platform.request("{}_spi_p".format(eem_urukuli)), + target.platform.request("{}_spi_n".format(eem_urukuli))) + phy = spi2.SPIMaster(spi_p, spi_n) + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) +- # connect `reset_sync_in` +- pads = target.platform.request("{}_dds_reset_sync_in".format(eem_urukuli)) +- target.specials += DifferentialOutput(dds_sync, pads.p, pads.n) +- # connect RF switches ++ ++ if sync_gen_cls is not None: # AD9910 variant and SYNC_IN from EEM ++ phy = sync_gen_cls(urukul_pads.dds_reset_sync_in, ftw_width=4) ++ target.submodules += phy ++ target.rtio_channels.append(rtio.Channel.from_phy(phy)) ++ ++ for j, eem_urukuli in enumerate(eem_urukul): + for i, signal in enumerate("sw0 sw1 sw2 sw3".split()): + pads = target.platform.request("{}_{}".format(eem_urukuli, signal)) + target.specials += DifferentialOutput( +diff --git a/artiq/gateware/rtio/phy/servo.py b/artiq/gateware/rtio/phy/servo.py +index 379e7ba3..246208c8 100644 +--- a/artiq/gateware/rtio/phy/servo.py ++++ b/artiq/gateware/rtio/phy/servo.py +@@ -1,25 +1,32 @@ + from migen import * +- + from artiq.gateware.rtio import rtlink + + + class RTServoCtrl(Module): + """Per channel RTIO control interface""" +- def __init__(self, ctrl): ++ def __init__(self, ctrl, ctrl_reftime): + self.rtlink = rtlink.Interface( +- rtlink.OInterface(len(ctrl.profile) + 2)) ++ rtlink.OInterface( ++ data_width=max(len(ctrl.profile) + 3, ++ len(ctrl_reftime.sysclks_fine)), ++ address_width=1) ++ ) + + # # # + ++ sel_ref = self.rtlink.o.address[0] + self.comb += [ +- ctrl.stb.eq(self.rtlink.o.stb), +- self.rtlink.o.busy.eq(0) ++ ctrl.stb.eq(self.rtlink.o.stb & ~sel_ref), ++ self.rtlink.o.busy.eq(0), ++ ctrl_reftime.stb.eq(self.rtlink.o.stb & sel_ref), + ] ++ ctrl_cases = { ++ 0: Cat(ctrl.en_out, ctrl.en_iir, ctrl.en_pt, ctrl.profile).eq( ++ self.rtlink.o.data), ++ 1: ctrl_reftime.sysclks_fine.eq(self.rtlink.o.data), ++ } + self.sync.rio_phy += [ +- If(self.rtlink.o.stb, +- Cat(ctrl.en_out, ctrl.en_iir, ctrl.profile).eq( +- self.rtlink.o.data) +- ) ++ If(self.rtlink.o.stb, Case(self.rtlink.o.address, ctrl_cases)) + ] + + +@@ -53,7 +60,7 @@ class RTServoMem(Module): + destination | sel | sel_coeff | + ----------------|-------|--------------| + IIR coeff mem | - | 1 | +- Reserved | 1 | 0 | ++ DDS delay mem | 1 | 0 | + IIR state mem | 2 | 0 | + config (write) | 3 | 0 | + status (read) | 3 | 0 | +@@ -72,7 +79,7 @@ class RTServoMem(Module): + (instead of having to decide whether to sign- or zero-extend per address), as + all unsigned values are less wide than w.coeff. + """ +- def __init__(self, w, servo): ++ def __init__(self, w, servo, io_update_phys): + m_coeff = servo.iir.m_coeff.get_port(write_capable=True, + mode=READ_FIRST, + we_granularity=w.coeff, clock_domain="rio") +@@ -110,7 +117,7 @@ class RTServoMem(Module): + # # # + + config = Signal(w.coeff, reset=0) +- status = Signal(8 + len(servo.iir.ctrl)) ++ status = Signal(len(self.rtlink.i.data)) + pad = Signal(6) + assert len(status) <= len(self.rtlink.i.data) + self.comb += [ +@@ -124,7 +131,7 @@ class RTServoMem(Module): + 1 + # sel_coeff + 1 + # high_coeff + len(m_coeff.adr)) +- # ensure that we can fit config/status into the state address space ++ # ensure that we can fit config/io_dly/status into the state address space + assert len(self.rtlink.o.address) + len(self.rtlink.o.data) - w.coeff >= ( + 1 + # we + 1 + # sel_coeff +@@ -172,6 +179,11 @@ class RTServoMem(Module): + read_high.eq(high_coeff), + ) + ] ++ ++ # I/O update alignment delays ++ ioup_dlys = Cat(*[phy.fine_ts for phy in io_update_phys]) ++ assert w.coeff >= len(ioup_dlys) ++ + self.sync.rio_phy += [ + If(self.rtlink.o.stb & we & (sel == 3), + config.eq(self.rtlink.o.data) +@@ -179,11 +191,15 @@ class RTServoMem(Module): + If(read & (read_sel == 3), + [_.clip.eq(0) for _ in servo.iir.ctrl] + ), ++ If(self.rtlink.o.stb & we & (sel == 1), ++ ioup_dlys.eq(self.rtlink.o.data) ++ ), + ] ++ + # read return value by destination + read_acts = Array([ + Mux(read_high, m_coeff.dat_r[w.coeff:], m_coeff.dat_r[:w.coeff]), +- 0, ++ ioup_dlys, + m_state.dat_r[w.state - w.coeff:], + status + ]) +diff --git a/artiq/gateware/suservo/dds_ser.py b/artiq/gateware/suservo/dds_ser.py +index 38d1f6d9..cdccfcc9 100644 +--- a/artiq/gateware/suservo/dds_ser.py ++++ b/artiq/gateware/suservo/dds_ser.py +@@ -1,4 +1,5 @@ + import logging ++from collections import namedtuple + + from migen import * + +@@ -6,11 +7,11 @@ from artiq.coredevice.urukul import DEFAULT_PROFILE + + from . import spi + +- + logger = logging.getLogger(__name__) + +- +-DDSParams = spi.SPIParams ++DDSParams = namedtuple("DDSParams", spi.SPIParams._fields + ( ++ "sysclk_per_clk", # DDS_CLK per FPGA system clock ++)) + + + class DDS(spi.SPISimple): +diff --git a/artiq/gateware/suservo/iir.py b/artiq/gateware/suservo/iir.py +index 6b975b75..3fad77a6 100644 +--- a/artiq/gateware/suservo/iir.py ++++ b/artiq/gateware/suservo/iir.py +@@ -1,6 +1,7 @@ + from collections import namedtuple + import logging + from migen import * ++from migen.genlib.coding import Encoder + + logger = logging.getLogger(__name__) + +@@ -98,14 +99,14 @@ class IIR(Module): + This module implements a multi-channel IIR (infinite impulse response) + filter processor optimized for synthesis on FPGAs. + +- The module is parametrized by passing a ``IIRWidths()`` object which +- will be abbreviated W here. ++ The module is parametrized by passing a ``IIRWidths()`` object, and ++ two more objects which will be abbreviated W, W_O and W_I here. + +- It reads 1 << W.channels input channels (typically from an ADC) ++ It reads W_I.channels input channels (typically from an ADC) + and on each iteration processes the data using a first-order IIR filter. + At the end of the cycle each the output of the filter together with + additional data (typically frequency tunning word and phase offset word +- for a DDS) are presented at the 1 << W.channels outputs of the module. ++ for a DDS) are presented at the W_O.channels outputs of the module. + + Profile memory + ============== +@@ -144,10 +145,10 @@ class IIR(Module): + ------------- + + The state memory holds all Y1 values (IIR processor outputs) for all +- profiles of all channels in the lower half (1 << W.profile + W.channel +- addresses) and the pairs of old and new ADC input values X1, and X0, +- in the upper half (1 << W.channel addresses). Each memory location is +- W.state bits wide. ++ profiles of all channels in the lower half (1 << W.profile)*W_O.channels ++ addresses, and the pairs of old and new ADC input values X1, and X0, ++ in the upper half (W_I.channels addresses). ++ Each memory location is W.state bits wide. + + Real-time control + ================= +@@ -156,15 +157,16 @@ class IIR(Module): + + * The active profile, PROFILE + * Whether to perform IIR filter iterations, EN_IIR ++ * Whether to track the DDS phase coherently, EN_PT + * The RF switch state enabling output from the channel, EN_OUT + + Delayed IIR processing + ====================== + +- The IIR filter iterations on a given channel are only performed all of the +- following are true: ++ The IIR filter iterations on a given channel are only performed if all of ++ the following are true: + +- * PROFILE, EN_IIR, EN_OUT have not been updated in the within the ++ * PROFILE, EN_IIR, EN_OUT have not been updated within the + last DLY cycles + * EN_IIR is asserted + * EN_OUT is asserted +@@ -175,9 +177,8 @@ class IIR(Module): + Typical design at the DSP level. This does not include the description of + the pipelining or the overall latency involved. + +- IIRWidths(state=25, coeff=18, adc=16, +- asf=14, word=16, accu=48, shift=11, +- channel=3, profile=5, dly=8) ++ IIRWidths(state=25, coeff=18, adc=16, asf=14, ++ word=16, accu=48, shift=11, profile=5, dly=8) + + X0 = ADC * 2^(25 - 1 - 16) + X1 = X0 delayed by one cycle +@@ -212,13 +213,23 @@ class IIR(Module): + --/--: signal with a given bit width always includes a sign bit + -->--: flow is to the right and down unless otherwise indicated + """ +- def __init__(self, w, w_i, w_o): ++ def __init__(self, w, w_i, w_o, t_cycle): + for v in (w, w_i, w_o): + for i, j in enumerate(v): + assert j > 0, (i, j, v) + assert w.word <= w.coeff # same memory + assert w.state + w.coeff + 3 <= w.accu + ++ # Reference counter for coherent phase tracking (we assume this doesn't ++ # roll over – a good assumption, as the period is, for a typical clock ++ # frequency, 2^48 / 125 MHz = ~26 days). ++ self.t_running = Signal(48, reset_less=True) ++ ++ # If true, internal DDS phase tracking state is reset, matching DDS ++ # chips with phase cleared (and zero FTW) before the start of the ++ # iteration. Automatically reset at the end of the iteration. ++ self.reset_dds_phase = Signal() ++ + # m_coeff of active profiles should only be accessed externally during + # ~processing + self.specials.m_coeff = Memory( +@@ -235,9 +246,24 @@ class IIR(Module): + ("profile", w.profile), + ("en_out", 1), + ("en_iir", 1), ++ ("en_pt", 1), + ("clip", 1), + ("stb", 1)]) + for i in range(w_o.channels)] ++ # "Shadow copy" of phase accumulator in DDS accumulator for each output ++ # channel. ++ self.specials.m_accum_ftw = Memory( ++ width=2 * w.word, ++ depth=w_o.channels) ++ # ctrl_reftime should only be updated synchronously ++ self.ctrl_reftime = [Record([ ++ ("sysclks_fine", bits_for(w_o.sysclk_per_clk - 1)), ++ ("stb", 1)]) ++ for i in range(w_o.channels)] ++ # Reference time for each output channel. ++ self.specials.m_t_ref = Memory( ++ width=len(self.t_running), ++ depth=w_o.channels) + # only update during ~loading + self.adc = [Signal((w.adc, True), reset_less=True) + for i in range(w_i.channels)] +@@ -264,8 +290,15 @@ class IIR(Module): + profiles = Array([ch.profile for ch in self.ctrl]) + en_outs = Array([ch.en_out for ch in self.ctrl]) + en_iirs = Array([ch.en_iir for ch in self.ctrl]) ++ en_pts = Array([ch.en_pt for ch in self.ctrl]) + clips = Array([ch.clip for ch in self.ctrl]) + ++ # Sample of the reference counter at the start of the current iteration, ++ # such that a common reference time is used for phase calculations ++ # across all channels, in DDS sysclk units. ++ sysclks_to_iter_start = Signal( ++ len(self.t_running) + bits_for(w_o.sysclk_per_clk - 1)) ++ + # Main state machine sequencing the steps of each servo iteration. The + # module IDLEs until self.start is asserted, and then runs through LOAD, + # PROCESS and SHIFT in order (see description of corresponding flags +@@ -292,6 +325,7 @@ class IIR(Module): + self.done.eq(1), + t_current_step_clr.eq(1), + If(self.start, ++ NextValue(sysclks_to_iter_start, self.t_running * w_o.sysclk_per_clk), + NextState("LOAD") + ) + ) +@@ -310,6 +344,7 @@ class IIR(Module): + If(stages_active == 0, + t_current_step_clr.eq(1), + NextState("SHIFT"), ++ NextValue(self.reset_dds_phase, 0) + ) + ) + fsm.act("SHIFT", +@@ -479,25 +514,81 @@ class IIR(Module): + }), + ] + ++ # Update coarse reference time from t_running upon ctrl_reftime strobe ++ ref_stb_encoder = Encoder(w_o.channels) ++ m_t_ref_stb = self.m_t_ref.get_port(write_capable=True) ++ self.specials += m_t_ref_stb ++ self.submodules += ref_stb_encoder ++ self.comb += [ ++ ref_stb_encoder.i.eq(Cat([ch.stb for ch in self.ctrl_reftime])), ++ m_t_ref_stb.adr.eq(ref_stb_encoder.o), ++ m_t_ref_stb.we.eq(~ref_stb_encoder.n), ++ m_t_ref_stb.dat_w.eq(self.t_running), ++ ] ++ + # +- # Update DDS profile with FTW/POW/ASF +- # Stage 0 loads the POW, stage 1 the FTW, and stage 2 writes +- # the ASF computed by the IIR filter. ++ # Update DDS profile with FTW/POW/ASF (including phase tracking, if ++ # enabled). Stage 0 loads the POW, stage 1 the FTW, and stage 2 writes ++ # the ASF computed by the IIR filter (and adds any phase correction). + # + + # muxing + ddss = Array(self.dds) ++ sysclks_ref_fine = Array([ch.sysclks_fine for ch in self.ctrl_reftime]) ++ ++ # registered copy of FTW on channel[1] ++ current_ftw = Signal(2 * w.word, reset_less=True) ++ # target effective DDS phase (accumulator + POW) at the coming io_update ++ target_dds_phase = Signal.like(current_ftw) ++ # DDS-internal phase accumulated until the coming io_update ++ accum_dds_phase = Signal.like(current_ftw) ++ # correction to add to the bare POW to yield a phase-coherent DDS output ++ correcting_pow = Signal(w.word, reset_less=True) ++ # sum of all FTWs on channel[1], updated with current FTW during the ++ # calculation ++ accum_ftw = Signal.like(current_ftw) ++ # sum of previous FTWs on channel[1] (or 0 on phase coherence reference ++ # reset) ++ prev_accum_ftw = Signal.like(current_ftw) ++ # time since reference time at coming io_update in DDS sysclk units ++ sysclks_to_ref = Signal.like(sysclks_to_iter_start) ++ # t_ref in DDS sysclk units ++ sysclks_ref_to_iter_start = Signal.like(sysclks_to_iter_start) ++ ++ m_t_ref = self.m_t_ref.get_port() ++ m_accum_ftw = self.m_accum_ftw.get_port(write_capable=True, mode=READ_FIRST) ++ self.specials += m_accum_ftw, m_t_ref ++ prev_accum_ftw = Signal.like(accum_ftw) ++ self.comb += [ ++ prev_accum_ftw.eq(Mux(self.reset_dds_phase, 0, m_accum_ftw.dat_r)), ++ m_accum_ftw.adr.eq(channel[1]), ++ m_accum_ftw.we.eq((pipeline_phase == 3) & stages_active[1]), ++ m_accum_ftw.dat_w.eq(accum_ftw), ++ m_t_ref.adr.eq(channel[0]), ++ ] + ++ sysclks_per_iter = t_cycle * w_o.sysclk_per_clk + self.sync += [ + Case(pipeline_phase, { + 0: [ + If(stages_active[1], + ddss[channel[1]][:w.word].eq(m_coeff.dat_r), # ftw0 ++ current_ftw[:w.word].eq(m_coeff.dat_r), ++ sysclks_ref_to_iter_start.eq(m_t_ref.dat_r * w_o.sysclk_per_clk), ++ ), ++ If(stages_active[2] & en_pts[channel[2]], ++ # add pow correction if phase tracking enabled ++ ddss[channel[2]][2*w.word:3*w.word].eq( ++ ddss[channel[2]][2*w.word:3*w.word] + correcting_pow), + ), + ], + 1: [ + If(stages_active[1], + ddss[channel[1]][w.word:2 * w.word].eq(m_coeff.dat_r), # ftw1 ++ current_ftw[w.word:].eq(m_coeff.dat_r), ++ sysclks_to_ref.eq(sysclks_to_iter_start - ( ++ sysclks_ref_to_iter_start + sysclks_ref_fine[channel[1]])), ++ accum_dds_phase.eq(prev_accum_ftw * sysclks_per_iter), + ), + If(stages_active[2], + ddss[channel[2]][3*w.word:].eq( # asf +@@ -506,10 +597,21 @@ class IIR(Module): + ], + 2: [ + If(stages_active[0], +- ddss[channel[0]][2*w.word:3*w.word].eq(m_coeff.dat_r), # pow ++ # Load bare POW from profile memory. ++ ddss[channel[0]][2*w.word:3*w.word].eq(m_coeff.dat_r), ++ ), ++ If(stages_active[1], ++ target_dds_phase.eq(current_ftw * sysclks_to_ref), ++ accum_ftw.eq(prev_accum_ftw + current_ftw), + ), + ], + 3: [ ++ If(stages_active[1], ++ # Prepare most-significant word to add to POW from ++ # profile for phase tracking. ++ correcting_pow.eq( ++ (target_dds_phase - accum_dds_phase)[w.word:]), ++ ), + ], + }), + ] +@@ -518,6 +620,15 @@ class IIR(Module): + self.widths = w + self.widths_adc = w_i + self.widths_dds = w_o ++ self.t_cycle = t_cycle ++ self._state = t_current_step ++ self._stages = stages_active ++ self._dt_start = sysclks_to_iter_start ++ self._sysclks_to_ref = sysclks_to_ref ++ self._sysclks_ref_to_iter_start = sysclks_ref_to_iter_start ++ self._sysclks_ref_fine = sysclks_ref_fine ++ self._ph_acc = accum_dds_phase ++ self._ph_coh = target_dds_phase + self._dlys = dlys + + def _coeff(self, channel, profile, coeff): +@@ -598,6 +709,14 @@ class IIR(Module): + raise ValueError("no such state", coeff) + return signed(val, w.state) + ++ def get_accum_ftw(self, channel): ++ val = yield self.m_accum_ftw[channel] ++ return val ++ ++ def get_t_ref(self, channel): ++ val = yield self.m_t_ref[channel] ++ return val ++ + def fast_iter(self): + """Perform a single processing iteration.""" + assert (yield self.done) +@@ -633,18 +752,26 @@ class IIR(Module): + v_adc = signed((yield self.adc[i]), w.adc) + x0 = yield from self.get_state(i, coeff="x0") + x0s.append(x0) +- assert v_adc << (w.state - w.adc - 1) == x0, (hex(v_adc), hex(x0)) + logger.debug("adc[%d] adc=%x x0=%x", i, v_adc, x0) ++ assert v_adc << (w.state - w.adc - 1) == x0, (hex(v_adc), hex(x0)) + + data = [] + # predict output + for i in range(w_o.channels): ++ t0 = yield self._dt_start ++ dds_ftw_accu = yield from self.get_accum_ftw(i) ++ sysclks_ref = (yield from self.get_t_ref(i)) * self.widths_dds.sysclk_per_clk\ ++ + (yield self.ctrl_reftime[i].sysclks_fine) ++ logger.debug("dt_start=%d dt_ref=%d t_cycle=%d ftw_accu=%#x", ++ t0, sysclks_ref, self.t_cycle, dds_ftw_accu) ++ + j = yield self.ctrl[i].profile + en_iir = yield self.ctrl[i].en_iir + en_out = yield self.ctrl[i].en_out ++ en_pt = yield self.ctrl[i].en_pt + dly_i = yield self._dlys[i] +- logger.debug("ctrl[%d] profile=%d en_iir=%d en_out=%d dly=%d", +- i, j, en_iir, en_out, dly_i) ++ logger.debug("ctrl[%d] profile=%d en_iir=%d en_out=%d en_pt=%d dly=%d", ++ i, j, en_iir, en_out, en_pt, dly_i) + + cfg = yield from self.get_coeff(i, j, "cfg") + k_j = cfg & ((1 << bits_for(w_i.channels - 1)) - 1) +@@ -664,9 +791,13 @@ class IIR(Module): + + ftw0 = yield from self.get_coeff(i, j, "ftw0") + ftw1 = yield from self.get_coeff(i, j, "ftw1") +- pow = yield from self.get_coeff(i, j, "pow") +- logger.debug("dds[%d,%d] ftw0=%#x ftw1=%#x pow=%#x", +- i, j, ftw0, ftw1, pow) ++ _pow = yield from self.get_coeff(i, j, "pow") ++ ph_coh = ((ftw0 | (ftw1 << w.word)) * (t0 - sysclks_ref)) ++ ph_accu = dds_ftw_accu * self.t_cycle * self.widths_dds.sysclk_per_clk ++ ph = ph_coh - ph_accu ++ pow = (_pow + (ph >> w.word)) & 0xffff if en_pt else _pow ++ logger.debug("dds[%d,%d] ftw0=%#x ftw1=%#x ph_coh=%#x _pow=%#x pow=%#x", ++ i, j, ftw0, ftw1, ph_coh, _pow, pow) + + y1 = yield from self.get_state(i, j, "y1") + x1 = yield from self.get_state(k_j, coeff="x1") +@@ -688,6 +819,10 @@ class IIR(Module): + # wait for output + assert (yield self.processing) + while (yield self.processing): ++ logger.debug("sysclks_to_ref=%d sysclks_ref_to_iter_start=%d", ++ (yield self._sysclks_to_ref), ++ (yield self._sysclks_ref_to_iter_start)) ++ # logger.debug("%d %d %d %d", *[x for x in (yield self._sysclks_ref_fine)]) + yield + + assert (yield self.shifting) +diff --git a/artiq/gateware/suservo/pads.py b/artiq/gateware/suservo/pads.py +index 778f05d0..bdae8ee3 100644 +--- a/artiq/gateware/suservo/pads.py ++++ b/artiq/gateware/suservo/pads.py +@@ -1,5 +1,7 @@ + from migen import * + from migen.genlib.io import DifferentialOutput, DifferentialInput, DDROutput ++from artiq.gateware.rtio.phy import ttl_serdes_7series, ttl_serdes_generic ++from artiq.gateware.rtio import rtlink + + + class SamplerPads(Module): +@@ -57,20 +59,79 @@ class SamplerPads(Module): + clk=dp.clkout, port=sdop) + + ++class OutIoUpdate_8X(Module): ++ def __init__(self, pad): ++ serdes = ttl_serdes_7series._OSERDESE2_8X() ++ self.submodules += serdes ++ ++ self.passthrough = Signal() ++ self.data = Signal() ++ self.fine_ts = Signal(3) ++ ++ self.rtlink = rtlink.Interface( ++ rtlink.OInterface(1, fine_ts_width=3)) ++ self.probes = [serdes.o[-1]] ++ override_en = Signal() ++ override_o = Signal() ++ self.overrides = [override_en, override_o] ++ ++ # # # ++ ++ self.specials += Instance("IOBUFDS", ++ i_I=serdes.ser_out, ++ i_T=serdes.t_out, ++ io_IO=pad.p, ++ io_IOB=pad.n) ++ ++ # Just strobe always in non-passthrough mode, as self.data is supposed ++ # to be always valid. ++ self.submodules += ttl_serdes_generic._SerdesDriver( ++ serdes.o, ++ Mux(self.passthrough, self.rtlink.o.stb, 1), ++ Mux(self.passthrough, self.rtlink.o.data, self.data), ++ Mux(self.passthrough, self.rtlink.o.fine_ts, self.fine_ts), ++ override_en, override_o) ++ ++ self.comb += self.rtlink.o.busy.eq(~self.passthrough) ++ ++ + class UrukulPads(Module): + def __init__(self, platform, *eems): + spip, spin = [[ + platform.request("{}_qspi_{}".format(eem, pol), 0) + for eem in eems] for pol in "pn"] +- ioup = [platform.request("{}_io_update".format(eem), 0) +- for eem in eems] ++ + self.cs_n = Signal() + self.clk = Signal() + self.io_update = Signal() ++ self.passthrough = Signal() ++ self.dds_reset_sync_in = Signal(reset=0) # sync_in phy (one for all) ++ ++ # # # ++ ++ self.io_update_phys = [] ++ for eem in eems: ++ phy = OutIoUpdate_8X(platform.request("{}_io_update".format(eem), 0)) ++ self.io_update_phys.append(phy) ++ setattr(self.submodules, "{}_io_update_phy".format(eem), phy) ++ self.comb += [ ++ phy.data.eq(self.io_update), ++ phy.passthrough.eq(self.passthrough), ++ ] ++ ++ sync_in_pads = platform.request("{}_dds_reset_sync_in".format(eem)) ++ sync_in_r = Signal() ++ self.sync.rio_phy += sync_in_r.eq(self.dds_reset_sync_in) ++ sync_in_o = Signal() ++ self.specials += Instance("ODDR", ++ p_DDR_CLK_EDGE="SAME_EDGE", ++ i_C=ClockSignal("rio_phy"), i_CE=1, i_S=0, i_R=0, ++ i_D1=sync_in_r, i_D2=sync_in_r, o_Q=sync_in_o) ++ self.specials += DifferentialOutput(sync_in_o, sync_in_pads.p, sync_in_pads.n) ++ + self.specials += [( + DifferentialOutput(~self.cs_n, spip[i].cs, spin[i].cs), +- DifferentialOutput(self.clk, spip[i].clk, spin[i].clk), +- DifferentialOutput(self.io_update, ioup[i].p, ioup[i].n)) ++ DifferentialOutput(self.clk, spip[i].clk, spin[i].clk)) + for i in range(len(eems))] + for i in range(4 * len(eems)): + mosi = Signal() +diff --git a/artiq/gateware/suservo/servo.py b/artiq/gateware/suservo/servo.py +index 59529320..15d31027 100644 +--- a/artiq/gateware/suservo/servo.py ++++ b/artiq/gateware/suservo/servo.py +@@ -42,7 +42,7 @@ class Servo(Module): + assert t_iir + 2*adc_p.channels < t_cycle, "need shifting time" + + self.submodules.adc = ADC(adc_pads, adc_p) +- self.submodules.iir = IIR(iir_p, adc_p, dds_p) ++ self.submodules.iir = IIR(iir_p, adc_p, dds_p, t_cycle) + self.submodules.dds = DDS(dds_pads, dds_p) + + # adc channels are reversed on Sampler +@@ -63,7 +63,6 @@ class Servo(Module): + assert t_restart > 1 + cnt = Signal(max=t_restart) + cnt_done = Signal() +- active = Signal(3) + + # Indicates whether different steps (0: ADC, 1: IIR, 2: DDS) are + # currently active (exposed for simulation only), with each bit being +@@ -71,6 +70,8 @@ class Servo(Module): + # timing details of the different steps, any number can be concurrently + # active (e.g. ADC read from iteration n, IIR computation from iteration + # n - 1, and DDS write from iteration n - 2). ++ active = Signal(3) ++ self._active = active # Exposed for debugging only. + + # Asserted once per cycle when the DDS write has been completed. + self.done = Signal() +@@ -95,6 +96,17 @@ class Servo(Module): + cnt.eq(t_restart - 1) + ) + ] ++ ++ # Count number of cycles since the servo was last started from idle. ++ self.sync += If(active == 0, ++ self.iir.t_running.eq(0), ++ self.iir.reset_dds_phase.eq(1) ++ ).Else( ++ self.iir.t_running.eq(self.iir.t_running + 1) ++ ) ++ ++ self.sync += dds_pads.passthrough.eq(active == 0) ++ + self.comb += [ + cnt_done.eq(cnt == 0), + self.adc.start.eq(self.start & cnt_done), +diff --git a/artiq/gateware/test/suservo/__init__.py b/artiq/gateware/test/suservo/__init__.py +index e69de29b..7a1df77a 100644 +--- a/artiq/gateware/test/suservo/__init__.py ++++ b/artiq/gateware/test/suservo/__init__.py +@@ -0,0 +1,10 @@ ++"""Gateware implementation of the Sampler-Urukul (AD9910) DDS amplitude servo. ++ ++General conventions: ++ ++ - ``t_...`` signals and constants refer to time spans measured in the gateware ++ module's default clock (typically a 125 MHz RTIO clock). ++ - ``start`` signals cause modules to proceed with the next servo iteration iff ++ they are currently idle (i.e. their value is irrelevant while the module is ++ busy, so they are not necessarily one-clock-period strobes). ++""" +diff --git a/artiq/gateware/test/suservo/test_dds.py b/artiq/gateware/test/suservo/test_dds.py +index a666f14c..d9a81675 100644 +--- a/artiq/gateware/test/suservo/test_dds.py ++++ b/artiq/gateware/test/suservo/test_dds.py +@@ -5,6 +5,9 @@ from migen import * + + from artiq.gateware.suservo.dds_ser import DDSParams, DDS + ++class OutIoUpdateTB(Module): ++ def __init__(self): ++ self.fine_ts = Signal(3) + + class TB(Module): + def __init__(self, p): +@@ -15,6 +18,12 @@ class TB(Module): + setattr(self, "mosi{}".format(i), m) + self.miso = Signal() + self.io_update = Signal() ++ self.passthrough = Signal() ++ ++ self.io_update_phys = [] ++ for i in range(p.channels//4): ++ phy = OutIoUpdateTB() ++ self.io_update_phys.append(phy) + + clk0 = Signal() + self.sync += clk0.eq(self.clk) +@@ -23,16 +32,19 @@ class TB(Module): + + self.ddss = [] + for i in range(p.channels): +- dds = Record([("ftw", 32), ("pow", 16), ("asf", 16), ("cmd", 8)]) +- sr = Signal(len(dds)) ++ dds = Record([("ftw", 32), ("pow", 16), ("asf", 16), ++ ("cmd", 8), ("accu", 32), ("phase", 19)]) ++ sr = Signal(32 + 16 + 16 + 8) + self.sync += [ ++ dds.accu.eq(dds.accu + p.sysclk_per_clk * dds.ftw), + If(~self.cs_n & sample, + sr.eq(Cat(self.mosi[i], sr)) + ), + If(self.io_update, +- dds.raw_bits().eq(sr) ++ dds.raw_bits()[:len(sr)].eq(sr) + ) + ] ++ self.comb += dds.phase.eq((dds.pow << 3) + (dds.accu >> 13)) + self.ddss.append(dds) + + @passive +@@ -55,7 +67,7 @@ class TB(Module): + + + def main(): +- p = DDSParams(channels=4, width=8 + 32 + 16 + 16, clk=1) ++ p = DDSParams(channels=4, width=8 + 32 + 16 + 16, clk=1, sysclk_per_clk=8) + tb = TB(p) + dds = DDS(tb, p) + tb.submodules += dds +diff --git a/artiq/gateware/test/suservo/test_iir.py b/artiq/gateware/test/suservo/test_iir.py +index 919e7a6b..ab8a9a4a 100644 +--- a/artiq/gateware/test/suservo/test_iir.py ++++ b/artiq/gateware/test/suservo/test_iir.py +@@ -2,48 +2,67 @@ import logging + import unittest + + from migen import * +-from artiq.gateware.suservo import iir ++from artiq.gateware.suservo import servo ++from collections import namedtuple + ++logger = logging.getLogger(__name__) ++ ++ADCParamsSim = namedtuple("ADCParams", ["channels"]) ++DDSParamsSim = namedtuple("ADCParams", ["channels", "sysclk_per_clk"]) + + def main(): +- w_kasli = iir.IIRWidths(state=25, coeff=18, adc=16, +- asf=14, word=16, accu=48, shift=11, +- channel=3, profile=5, dly=8) +- w = iir.IIRWidths(state=17, coeff=16, adc=16, +- asf=14, word=16, accu=48, shift=11, +- channel=2, profile=1, dly=8) ++ w_kasli = servo.IIRWidths(state=25, coeff=18, adc=16, asf=14, ++ word=16, accu=48, shift=11, profile=5, dly=8) ++ p_adc = ADCParamsSim(channels=8) ++ p_dds = DDSParamsSim(channels=4, sysclk_per_clk=8) ++ w = servo.IIRWidths(state=17, coeff=16, adc=16, asf=14, ++ word=16, accu=48, shift=11, profile=2, dly=8) + ++ t_iir = p_adc.channels + 4*p_dds.channels + 8 + 1 + def run(dut): ++ yield dut.t_running.eq(0) + for i, ch in enumerate(dut.adc): + yield ch.eq(i) + for i, ch in enumerate(dut.ctrl): + yield ch.en_iir.eq(1) + yield ch.en_out.eq(1) + yield ch.profile.eq(i) +- for i in range(1 << w.channel): ++ yield ch.en_pt.eq(i) ++ for i, ch in enumerate(dut.ctrl_reftime): ++ yield ch.sysclks_fine.eq(i) ++ yield ch.stb.eq(1) ++ yield ++ yield dut.t_running.eq(dut.t_running + 1) ++ yield ch.stb.eq(0) ++ yield ++ yield dut.t_running.eq(dut.t_running + 1) ++ for i in range(p_adc.channels): + yield from dut.set_state(i, i << 8, coeff="x1") + yield from dut.set_state(i, i << 8, coeff="x0") ++ for i in range(p_dds.channels): + for j in range(1 << w.profile): + yield from dut.set_state(i, + (j << 1) | (i << 8), profile=j, coeff="y1") + for k, l in enumerate("pow offset ftw0 ftw1".split()): + yield from dut.set_coeff(i, profile=j, coeff=l, +- value=(i << 12) | (j << 8) | (k << 4)) ++ value=(i << 10) | (j << 8) | (k << 4)) + yield +- for i in range(1 << w.channel): ++ for i in range(p_dds.channels): + for j in range(1 << w.profile): +- for k, l in enumerate("cfg a1 b0 b1".split()): ++ for k, l in enumerate("a1 b0 b1".split()): + yield from dut.set_coeff(i, profile=j, coeff=l, +- value=(i << 12) | (j << 8) | (k << 4)) ++ value=(i << 10) | (j << 8) | (k << 4)) + yield from dut.set_coeff(i, profile=j, coeff="cfg", +- value=(i << 0) | (j << 8)) # sel, dly ++ value=(i % p_adc.channels) | (j << 8)) # sel, dly + yield +- for i in range(10): ++ for i in range(4): ++ logger.debug("check_iter {}".format(i)) + yield from dut.check_iter() ++ yield dut.t_running.eq((yield dut.t_running) + t_iir) + yield + +- dut = iir.IIR(w) +- run_simulation(dut, [run(dut)], vcd_name="iir.vcd") ++ dut = servo.IIR(w, p_adc, p_dds, t_iir) ++ run_simulation(dut, [run(dut)], vcd_name="servo.vcd") + + + class IIRTest(unittest.TestCase): +diff --git a/artiq/gateware/test/suservo/test_servo.py b/artiq/gateware/test/suservo/test_servo.py +index cc1a73a2..fe1708d0 100644 +--- a/artiq/gateware/test/suservo/test_servo.py ++++ b/artiq/gateware/test/suservo/test_servo.py +@@ -1,5 +1,6 @@ + import logging + import unittest ++import numpy as np + + from migen import * + from migen.genlib import io +@@ -7,15 +8,17 @@ from migen.genlib import io + from artiq.gateware.test.suservo import test_adc, test_dds + from artiq.gateware.suservo import servo + ++logger = logging.getLogger(__name__) ++ + + class ServoSim(servo.Servo): + def __init__(self): + adc_p = servo.ADCParams(width=16, channels=8, lanes=4, + t_cnvh=4, t_conv=57 - 4, t_rtt=4 + 4) + iir_p = servo.IIRWidths(state=25, coeff=18, adc=16, asf=14, word=16, +- accu=48, shift=11, channel=3, profile=5, dly=8) ++ accu=48, shift=11, profile=5, dly=8) + dds_p = servo.DDSParams(width=8 + 32 + 16 + 16, +- channels=adc_p.channels, clk=1) ++ channels=4, clk=1, sysclk_per_clk=8) + + self.submodules.adc_tb = test_adc.TB(adc_p) + self.submodules.dds_tb = test_dds.TB(dds_p) +@@ -23,37 +26,156 @@ class ServoSim(servo.Servo): + servo.Servo.__init__(self, self.adc_tb, self.dds_tb, + adc_p, iir_p, dds_p) + ++ self.dds_output = [] ++ ++ def log_flow(self, cycle): ++ su_start = yield self.start ++ adc_start = yield self.adc.start ++ iir_start = yield self.iir.start ++ dds_start = yield self.dds.start ++ su_done = yield self.done ++ adc_done = yield self.adc.done ++ iir_done = yield self.iir.done ++ dds_done = yield self.dds.done ++ active = yield self._active ++ io_update = yield self.dds_tb.io_update ++ passthrough = yield self.dds_tb.passthrough ++ iir_loading = yield self.iir.loading ++ iir_processing = yield self.iir.processing ++ iir_shifting = yield self.iir.shifting ++ dt = yield self.iir.t_running ++ dt_iir = yield self.iir._dt_start ++ state = yield self.iir._state ++ stage0 = yield self.iir._stages[0] ++ stage1 = yield self.iir._stages[1] ++ stage2 = yield self.iir._stages[2] ++ logger.debug( ++ "cycle=%d " ++ #"start=[su=%d adc=%d iir=%d dds=%d] " ++ #"done=[su=%d adc=%d iir=%d dds=%d] " ++ "active=%s load_proc_shft=%d%d%d stages_active=%d%d%d " ++ "io_update=%d passthrough=%d " ++ "dt=%d dt_iir=%d state=%d", ++ cycle, ++ #su_start, adc_start, iir_start, dds_start, ++ #su_done, adc_done, iir_done, dds_done, ++ '{:03b}'.format(active), iir_loading, iir_processing, iir_shifting, stage0, stage1, stage2, ++ io_update, passthrough, ++ dt, dt_iir//8, state ++ ) ++ ++ def log_state(self, channel, profile, calls=[0]): ++ calls[0] += 1 ++ # if not (yield self._active[1]): ++ # return ++ yield from self.log_flow(calls[0] - 2) ++ return ++ cfg = yield from self.iir.get_coeff(channel, profile, "cfg") ++ sel = cfg & 0x7 ++ x0 = yield from self.iir.get_state(sel, coeff="x0") ++ x1 = yield from self.iir.get_state(sel, coeff="x1") ++ y1 = yield from self.iir.get_state(channel, profile, coeff="y1") ++ _pow = yield from self.iir.get_coeff(channel, profile, "pow") ++ pow_iir = yield self.iir.dds[channel][2*self.iir.widths.word:3*self.iir.widths.word] ++ pow_dds = yield self.dds_tb.ddss[channel].pow ++ asf_dds = yield self.dds_tb.ddss[channel].asf ++ ftw_dds = yield self.dds_tb.ddss[channel].ftw ++ accu_dds = yield self.dds_tb.ddss[channel].accu ++ phase_dds = (yield self.dds_tb.ddss[channel].phase) ++ dds_output = np.cos(2*np.pi*phase_dds/2**19) ++ ph_coh = yield self.iir._ph_coh ++ ph_acc = yield self.iir._ph_acc ++ offset = yield from self.iir.get_coeff(channel, profile, "offset") ++ ftw0 = yield from self.iir.get_coeff(channel, profile, "ftw0") ++ ftw1 = yield from self.iir.get_coeff(channel, profile, "ftw1") ++ m_phase = yield from self.iir.get_accum_ftw(channel) ++ iir_adc = yield self.iir.adc[sel] ++ logger.debug("\t" ++ "ch=%d pr=%d " ++ # "x0=%d x1=%d adc=%d y1=%d sel=%d " ++ "ftw=%#x pow_coeff=%#x ftw_accu=%#x " ++ "ph_coh=%#x ph_acc=%#x " ++ "pow_iir=%#x pow_dds=%#x ftw_dds=%#x asf_dds=%#x accu_dds=%#x phase_dds=%#x dds_output=%04.3f", ++ channel, profile, ++ # x0, x1, iir_adc, y1, sel, ++ ftw0 | (ftw1 << 16), _pow, m_phase, ++ ph_coh, ph_acc, ++ pow_iir, pow_dds, ftw_dds, asf_dds, accu_dds, phase_dds >> 3, dds_output ++ ) ++ self.dds_output.append(dds_output) ++ # yield from self.log_registers(profile) ++ ++ def log_registers(self, profile): ++ adc_channels = self.iir.widths_adc.channels ++ dds_channels = self.iir.widths_dds.channels ++ x0s = [0]*adc_channels ++ x1s = [0]*adc_channels ++ y1s = [0]*dds_channels ++ for ch in range(adc_channels): ++ x0s[ch] = yield from self.iir.get_state(ch, coeff="x0") ++ x1s[ch] = yield from self.iir.get_state(ch, coeff="x1") ++ for ch in range(dds_channels): ++ y1s[ch] = yield from self.iir.get_state(ch, profile, coeff="y1") ++ ++ logger.debug(("x0s = " + '{:05X} ' * adc_channels).format(*x0s)) ++ logger.debug(("x1s = " + '{:05X} ' * adc_channels).format(*x1s)) ++ logger.debug(("y1s = " + '{:05X} ' * dds_channels).format(*y1s)) ++ + def test(self): + assert (yield self.done) + +- adc = 1 ++ adc = 7 + x0 = 0x0141 + yield self.adc_tb.data[-adc-1].eq(x0) +- channel = 3 +- yield self.iir.adc[channel].eq(adc) ++ channel = 0 + yield self.iir.ctrl[channel].en_iir.eq(1) + yield self.iir.ctrl[channel].en_out.eq(1) +- profile = 5 ++ yield self.iir.ctrl[channel].en_pt.eq(1) ++ profile = 31 + yield self.iir.ctrl[channel].profile.eq(profile) + x1 = 0x0743 + yield from self.iir.set_state(adc, x1, coeff="x1") + y1 = 0x1145 + yield from self.iir.set_state(channel, y1, + profile=profile, coeff="y1") +- coeff = dict(pow=0x1333, offset=0x1531, ftw0=0x1727, ftw1=0x1929, +- a1=0x0135, b0=0x0337, b1=0x0539, cfg=adc | (0 << 3)) ++ coeff = dict(pow=0, offset=0x1531, ftw0=0xeb85, ftw1=0x51, ++ a1=0x0135, b0=0x0337, b1=0x0539, cfg=adc) + for ks in "pow offset ftw0 ftw1", "a1 b0 b1 cfg": + for k in ks.split(): + yield from self.iir.set_coeff(channel, value=coeff[k], + profile=profile, coeff=k) + yield + ++ num_it = 1 ++ num_proc_its = [0]*num_it # number of iterations while iir.processing ++ yield from self.log_state(channel, profile) + yield self.start.eq(1) + yield +- yield self.start.eq(0) +- while not (yield self.dds_tb.io_update): +- yield +- yield # io_update ++ for i in range(num_it): ++ if i == 1: # change ftw ++ yield from self.iir.set_coeff(channel, ++ profile=profile, coeff='ftw0', value=coeff['ftw1']) ++ yield from self.iir.set_coeff(channel, ++ profile=profile, coeff='ftw1', value=coeff['ftw0']) ++ if i == 2: # change ftw back ++ yield from self.iir.set_coeff(channel, ++ profile=profile, coeff='ftw0', value=coeff['ftw0']) ++ yield from self.iir.set_coeff(channel, ++ profile=profile, coeff='ftw1', value=coeff['ftw1']) ++ logger.debug("iteration {}".format(i)) ++ yield from self.log_state(channel, profile) ++ if i == num_it-1: ++ yield self.start.eq(0) ++ while not (yield self.dds_tb.io_update): ++ yield ++ if (yield self.iir.processing): ++ num_proc_its[i] += 1 ++ if (yield self.iir._stages) != 0: ++ yield from self.log_state(channel, profile) ++ yield # io_update ++ yield from self.log_state(channel, profile) ++ yield ++ yield from self.log_state(channel, profile) + + w = self.iir.widths + +@@ -63,6 +185,8 @@ class ServoSim(servo.Servo): + + offset = coeff["offset"] << (w.state - w.coeff - 1) + a1, b0, b1 = coeff["a1"], coeff["b0"], coeff["b1"] ++ ++ # works only for 1 iteration + out = ( + 0*(1 << w.shift - 1) + # rounding + a1*(y1 + 0) + b0*(x0 + offset) + b1*(x1 + offset) +@@ -76,8 +200,15 @@ class ServoSim(servo.Servo): + ftw = (coeff["ftw1"] << 16) | coeff["ftw0"] + assert _ == ftw, (hex(_), hex(ftw)) + ++ t0 = yield self.iir._dt_start ++ # todo: include phase accumulator ++ ph = (ftw * t0) >> 16 ++ if (yield self.iir.ctrl[channel].en_pt): ++ pow = (coeff["pow"] + ph) & 0xffff ++ else: ++ pow = coeff["pow"] + _ = yield self.dds_tb.ddss[channel].pow +- assert _ == coeff["pow"], (hex(_), hex(coeff["pow"])) ++ assert _ == pow, (hex(_), hex(pow)) + + _ = yield self.dds_tb.ddss[channel].asf + asf = y1 >> (w.state - w.asf - 1) +@@ -101,4 +232,5 @@ class ServoTest(unittest.TestCase): + + + if __name__ == "__main__": ++ logging.basicConfig(level=logging.DEBUG) + main() From 6c47aac760b905fc7b82e0883317fd274192b049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=81=AB=E7=84=9A=20=E5=AF=8C=E8=89=AF?= Date: Wed, 23 Nov 2022 18:22:53 +0800 Subject: [PATCH 11/85] dashboard: merge create dataset and edit dataset features --- artiq/dashboard/datasets.py | 116 +++++++----------------------------- 1 file changed, 23 insertions(+), 93 deletions(-) diff --git a/artiq/dashboard/datasets.py b/artiq/dashboard/datasets.py index 674e653e9..1052e03d1 100644 --- a/artiq/dashboard/datasets.py +++ b/artiq/dashboard/datasets.py @@ -14,92 +14,18 @@ from artiq.gui.scientific_spinbox import ScientificSpinBox logger = logging.getLogger(__name__) -async def rename(key, newkey, value, dataset_ctl): - if key != newkey: +async def rename(key, new_key, value, persist, dataset_ctl): + if key != new_key: await dataset_ctl.delete(key) - await dataset_ctl.set(newkey, value) + await dataset_ctl.set(new_key, value, persist) -class Editor(QtWidgets.QDialog): - def __init__(self, parent, dataset_ctl, key, value): - QtWidgets.QDialog.__init__(self, parent=parent) - self.dataset_ctl = dataset_ctl - self.key = key - self.initial_type = type(value) - - self.setWindowTitle("Edit dataset") - grid = QtWidgets.QGridLayout() - self.setLayout(grid) - - grid.addWidget(QtWidgets.QLabel("Name:"), 0, 0) - - self.name_widget = QtWidgets.QLineEdit() - self.name_widget.setText(key) - - grid.addWidget(self.name_widget, 0, 1) - - grid.addWidget(QtWidgets.QLabel("Value:"), 1, 0) - grid.addWidget(self.get_edit_widget(value), 1, 1) - - buttons = QtWidgets.QDialogButtonBox( - QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel) - grid.setRowStretch(2, 1) - grid.addWidget(buttons, 3, 0, 1, 2) - buttons.accepted.connect(self.accept) - buttons.rejected.connect(self.reject) - - def accept(self): - newkey = self.name_widget.text() - value = self.initial_type(self.get_edit_widget_value()) - asyncio.ensure_future(rename(self.key, newkey, value, self.dataset_ctl)) - QtWidgets.QDialog.accept(self) - - def get_edit_widget(self, initial_value): - raise NotImplementedError - - def get_edit_widget_value(self): - raise NotImplementedError - - -class NumberEditor(Editor): - def get_edit_widget(self, initial_value): - self.edit_widget = ScientificSpinBox() - self.edit_widget.setDecimals(13) - self.edit_widget.setPrecision() - self.edit_widget.setRelativeStep() - self.edit_widget.setValue(float(initial_value)) - return self.edit_widget - - def get_edit_widget_value(self): - return self.edit_widget.value() - - -class BoolEditor(Editor): - def get_edit_widget(self, initial_value): - self.edit_widget = QtWidgets.QCheckBox() - self.edit_widget.setChecked(bool(initial_value)) - return self.edit_widget - - def get_edit_widget_value(self): - return self.edit_widget.isChecked() - - -class StringEditor(Editor): - def get_edit_widget(self, initial_value): - self.edit_widget = QtWidgets.QLineEdit() - self.edit_widget.setText(initial_value) - return self.edit_widget - - def get_edit_widget_value(self): - return self.edit_widget.text() - - -class Creator(QtWidgets.QDialog): - def __init__(self, parent, dataset_ctl): +class CreateEditDialog(QtWidgets.QDialog): + def __init__(self, parent, dataset_ctl, key=None, value=None, persist=False): QtWidgets.QDialog.__init__(self, parent=parent) self.dataset_ctl = dataset_ctl - self.setWindowTitle("Create dataset") + self.setWindowTitle("Create dataset" if key is None else "Edit dataset") grid = QtWidgets.QGridLayout() grid.setRowMinimumHeight(1, 40) grid.setColumnMinimumWidth(2, 60) @@ -130,16 +56,24 @@ class Creator(QtWidgets.QDialog): self.buttons.addButton( self.cancel, QtWidgets.QDialogButtonBox.RejectRole) grid.setRowStretch(3, 1) - grid.addWidget(self.buttons, 4, 0, 1, 3) + grid.addWidget(self.buttons, 4, 0, 1, 3, alignment=QtCore.Qt.AlignHCenter) self.buttons.accepted.connect(self.accept) self.buttons.rejected.connect(self.reject) + self.key = key + self.name_widget.setText(key) + self.value_widget.setText(value) + self.box_widget.setChecked(persist) + def accept(self): key = self.name_widget.text() value = self.value_widget.text() persist = self.box_widget.isChecked() - asyncio.ensure_future(exc_to_warning(self.dataset_ctl.set( - key, pyon.decode(value), persist))) + if self.key and self.key != key: + asyncio.ensure_future(exc_to_warning(rename(self.key, key, pyon.decode(value), persist, self.dataset_ctl))) + else: + asyncio.ensure_future(exc_to_warning(self.dataset_ctl.set(key, pyon.decode(value), persist))) + self.key = key QtWidgets.QDialog.accept(self) def dtype(self): @@ -226,7 +160,7 @@ class DatasetsDock(QtWidgets.QDockWidget): self.table.setModel(self.table_model_filter) def create_clicked(self): - Creator(self, self.dataset_ctl).open() + CreateEditDialog(self, self.dataset_ctl).open() def edit_clicked(self): idx = self.table.selectedIndexes() @@ -236,17 +170,13 @@ class DatasetsDock(QtWidgets.QDockWidget): if key is not None: persist, value = self.table_model.backing_store[key] t = type(value) - if np.issubdtype(t, np.number): - dialog_cls = NumberEditor - elif np.issubdtype(t, np.bool_): - dialog_cls = BoolEditor + if np.issubdtype(t, np.number) or np.issubdtype(t, np.bool_): + value = str(value) elif np.issubdtype(t, np.unicode_): - dialog_cls = StringEditor + value = '"{}"'.format(str(value)) else: - logger.error("Cannot edit dataset %s: " - "type %s is not supported", key, t) - return - dialog_cls(self, self.dataset_ctl, key, value).open() + value = pyon.encode(value) + CreateEditDialog(self, self.dataset_ctl, key, value, persist).open() def delete_clicked(self): idx = self.table.selectedIndexes() From 950b9ac4d68286585e4369efcf904704d8de9c53 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 24 Nov 2022 16:54:49 +0000 Subject: [PATCH 12/85] firmware: More explicit panic message if stack guard is tripped This should give even only mildly technical users a chance to figure out what's going on, which empirically is not the case for a plain Exception(LoadFault) without further context. --- artiq/firmware/ksupport/lib.rs | 15 ++++++++++++++- artiq/firmware/libboard_misoc/riscv32/pmp.rs | 2 ++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index d9786ae3c..7bb1e675a 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -471,6 +471,8 @@ unsafe fn attribute_writeback(typeinfo: *const ()) { } } +static mut STACK_GUARD_BASE: usize = 0x0; + #[no_mangle] pub unsafe fn main() { eh_artiq::reset_exception_buffer(KERNELCPU_PAYLOAD_ADDRESS); @@ -502,6 +504,7 @@ pub unsafe fn main() { ptr::write_bytes(__bss_start as *mut u8, 0, (_end - __bss_start) as usize); board_misoc::pmp::init_stack_guard(_sstack_guard as usize); + STACK_GUARD_BASE = _sstack_guard as usize; board_misoc::cache::flush_cpu_dcache(); board_misoc::cache::flush_cpu_icache(); @@ -531,10 +534,20 @@ pub unsafe fn main() { #[no_mangle] #[unwind(allowed)] -pub extern fn exception(_regs: *const u32) { +pub unsafe extern fn exception(_regs: *const u32) { let pc = mepc::read(); let cause = mcause::read().cause(); let mtval = mtval::read(); + if let mcause::Trap::Exception(mcause::Exception::LoadFault) + | mcause::Trap::Exception(mcause::Exception::StoreFault) = cause + { + if mtval >= STACK_GUARD_BASE + && mtval < (STACK_GUARD_BASE + board_misoc::pmp::STACK_GUARD_SIZE) + { + panic!("{:?} at PC {:#08x} in stack guard page ({:#08x}); stack overflow in user kernel code?", + cause, u32::try_from(pc).unwrap(), mtval); + } + } panic!("{:?} at PC {:#08x}, trap value {:#08x}", cause, u32::try_from(pc).unwrap(), mtval); } diff --git a/artiq/firmware/libboard_misoc/riscv32/pmp.rs b/artiq/firmware/libboard_misoc/riscv32/pmp.rs index 9ac80b9e3..976f257b1 100644 --- a/artiq/firmware/libboard_misoc/riscv32/pmp.rs +++ b/artiq/firmware/libboard_misoc/riscv32/pmp.rs @@ -9,6 +9,8 @@ const PMP_W : usize = 0b00000010; const PMP_R : usize = 0b00000001; const PMP_OFF : usize = 0b00000000; +pub const STACK_GUARD_SIZE: usize = 0x1000; + #[inline(always)] pub unsafe fn init_stack_guard(guard_base: usize) { pmpaddr2::write((guard_base >> 2) | ((0x1000 - 1) >> 3)); From dee154b35b001892ea81c1c640ad607ca817299f Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 24 Nov 2022 16:57:31 +0000 Subject: [PATCH 13/85] compiler: Add missing sections to kernel linker script This caused sporadic LoadFaults with LLD 14 and above, as they happened to lay out the (not otherwise mentioned) GOT/PLT such that they would overlap with the stack guard page. LLD does support the --orphan-handling=error option, which would be useful to avoid similar problems in the future, but then we'd need to mention all the other misc sections (symbol table, comments) in the linker script as well. GitHub: Fixes #1975. --- artiq/compiler/kernel.ld | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/artiq/compiler/kernel.ld b/artiq/compiler/kernel.ld index fafbea2af..bf080c37a 100644 --- a/artiq/compiler/kernel.ld +++ b/artiq/compiler/kernel.ld @@ -33,9 +33,19 @@ SECTIONS KEEP(*(.eh_frame_hdr)) } : text : eh_frame + .got : + { + *(.got) + } : text + + .got.plt : + { + *(.got.plt) + } : text + .data : { - *(.data) + *(.data .data.*) } : data .dynamic : @@ -51,6 +61,10 @@ SECTIONS _end = .; } + /* Kernel stack grows downward from end of memory, so put guard page after + * all the program contents. Note: This requires all loaded sections (at + * least those accessed) to be explicitly listed in the above! + */ . = ALIGN(0x1000); _sstack_guard = .; } From 88c5109627fb27794ff844c51a48c353061c90bf Mon Sep 17 00:00:00 2001 From: Nico Pulido Date: Wed, 23 Nov 2022 15:34:21 +0100 Subject: [PATCH 14/85] language: check_unprocessed_arguments after constructing experiment Signed-off-by: Nico Pulido-Mateo --- artiq/frontend/artiq_compile.py | 2 ++ artiq/frontend/artiq_run.py | 4 +++- artiq/language/environment.py | 4 ---- artiq/master/worker_impl.py | 1 + 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/artiq/frontend/artiq_compile.py b/artiq/frontend/artiq_compile.py index 1609971e0..918a58c65 100755 --- a/artiq/frontend/artiq_compile.py +++ b/artiq/frontend/artiq_compile.py @@ -53,6 +53,8 @@ def main(): arguments = parse_arguments(args.arguments) argument_mgr = ProcessArgumentManager(arguments) exp_inst = exp((device_mgr, dataset_mgr, argument_mgr, {})) + argument_mgr.check_unprocessed_arguments() + if not hasattr(exp.run, "artiq_embedded"): raise ValueError("Experiment entry point must be a kernel") diff --git a/artiq/frontend/artiq_run.py b/artiq/frontend/artiq_run.py index 21baf3f05..c3d548c26 100755 --- a/artiq/frontend/artiq_run.py +++ b/artiq/frontend/artiq_run.py @@ -184,7 +184,9 @@ def _build_experiment(device_mgr, dataset_mgr, args): "arguments": arguments } device_mgr.virtual_devices["scheduler"].expid = expid - return get_experiment(module, args.class_name)(managers) + exp_inst = get_experiment(module, args.class_name)(managers) + argument_mgr.check_unprocessed_arguments() + return exp_inst def run(with_file=False): diff --git a/artiq/language/environment.py b/artiq/language/environment.py index 1147e2333..d3ccaf77d 100644 --- a/artiq/language/environment.py +++ b/artiq/language/environment.py @@ -209,8 +209,6 @@ class TraceArgumentManager: self.requested_args[key] = processor, group, tooltip return None - def check_unprocessed_arguments(self): - pass class ProcessArgumentManager: def __init__(self, unprocessed_arguments): @@ -252,8 +250,6 @@ class HasEnvironment: self.__in_build = True self.build(*args, **kwargs) self.__in_build = False - if self.__argument_mgr is not None: - self.__argument_mgr.check_unprocessed_arguments() def register_child(self, child): self.children.append(child) diff --git a/artiq/master/worker_impl.py b/artiq/master/worker_impl.py index 33d34ddf8..45c7308c0 100644 --- a/artiq/master/worker_impl.py +++ b/artiq/master/worker_impl.py @@ -333,6 +333,7 @@ def main(): os.chdir(dirname) argument_mgr = ProcessArgumentManager(expid["arguments"]) exp_inst = exp((device_mgr, dataset_mgr, argument_mgr, {})) + argument_mgr.check_unprocessed_arguments() put_completed() elif action == "prepare": exp_inst.prepare() From b8b6ce14cc6a297f4cb4c55491ed0c4eb26b6300 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Mon, 28 Nov 2022 11:15:41 +0000 Subject: [PATCH 15/85] Update smoltcp to 0.8.2 This fixes an issue where TCP issues are not retransmitted when only some packets in a burst are acknowledged. This causes smoltcp to never make progress and hang. Signed-off-by: Jonathan Coates --- artiq/firmware/Cargo.lock | 4 ++-- artiq/firmware/bootloader/Cargo.toml | 2 +- artiq/firmware/libboard_misoc/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 8e0c7f95a..c6f71926e 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -371,9 +371,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "smoltcp" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2308a1657c8db1f5b4993bab4e620bdbe5623bd81f254cf60326767bb243237" +checksum = "ee34c1e1bfc7e9206cc0fb8030a90129b4e319ab53856249bb27642cab914fb3" dependencies = [ "bitflags", "byteorder", diff --git a/artiq/firmware/bootloader/Cargo.toml b/artiq/firmware/bootloader/Cargo.toml index 9e5ba820a..ac0df1001 100644 --- a/artiq/firmware/bootloader/Cargo.toml +++ b/artiq/firmware/bootloader/Cargo.toml @@ -16,5 +16,5 @@ build_misoc = { path = "../libbuild_misoc" } byteorder = { version = "1.0", default-features = false } crc = { version = "1.7", default-features = false } board_misoc = { path = "../libboard_misoc", features = ["uart_console", "smoltcp"] } -smoltcp = { version = "0.8.0", default-features = false, features = ["medium-ethernet", "proto-ipv4", "proto-ipv6", "socket-tcp"] } +smoltcp = { version = "0.8.2", default-features = false, features = ["medium-ethernet", "proto-ipv4", "proto-ipv6", "socket-tcp"] } riscv = { version = "0.6.0", features = ["inline-asm"] } diff --git a/artiq/firmware/libboard_misoc/Cargo.toml b/artiq/firmware/libboard_misoc/Cargo.toml index 69c1d46d3..7b4951ea7 100644 --- a/artiq/firmware/libboard_misoc/Cargo.toml +++ b/artiq/firmware/libboard_misoc/Cargo.toml @@ -15,7 +15,7 @@ build_misoc = { path = "../libbuild_misoc" } [dependencies] byteorder = { version = "1.0", default-features = false } log = { version = "0.4", default-features = false, optional = true } -smoltcp = { version = "0.8.0", default-features = false, optional = true } +smoltcp = { version = "0.8.2", default-features = false, optional = true } riscv = { version = "0.6.0", features = ["inline-asm"] } [features] From 275b00bfc2d6fec647b16c2724ec2b815efc8073 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 18 Nov 2022 18:11:48 +0800 Subject: [PATCH 16/85] flake: fix libcrypt.so.1 not found by vivado --- flake.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/flake.nix b/flake.nix index a00f41016..cec1d123a 100644 --- a/flake.nix +++ b/flake.nix @@ -44,6 +44,7 @@ }); vivadoDeps = pkgs: with pkgs; [ + libxcrypt ncurses5 zlib libuuid From 6d179b2bf53d9c0692405a5c9fbc5e53e0ffaea6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 30 Nov 2022 21:36:36 +0800 Subject: [PATCH 17/85] flake: nixos 22.11 --- flake.lock | 22 +++++++++++----------- flake.nix | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/flake.lock b/flake.lock index d138f372c..269fa6209 100644 --- a/flake.lock +++ b/flake.lock @@ -57,16 +57,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1666056570, - "narHash": "sha256-e7EkIY68Tp7NKyp9JSHh6CgPPdsKYYWxiL4wZQN8Cwg=", + "lastModified": 1669735802, + "narHash": "sha256-qtG/o/i5ZWZLmXw108N2aPiVsxOcidpHJYNkT45ry9Q=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "47edaa313fc3767ce3026037a5b62352f22f3602", + "rev": "731cc710aeebecbf45a258e977e8b68350549522", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-22.05", + "ref": "nixos-22.11", "repo": "nixpkgs", "type": "github" } @@ -89,11 +89,11 @@ ] }, "locked": { - "lastModified": 1664319253, - "narHash": "sha256-hycJAgy+NFF9f5I6++7yo8KdhMSyKCPKJazRPxeedI4=", + "lastModified": 1669369686, + "narHash": "sha256-YHez+S3PTUgtuliUNB5WM+RXcj8RKLbHVRvOgELSkwU=", "owner": "m-labs", "repo": "sipyco", - "rev": "d58ded7280e0f020be2446d4fee70f4393e6045f", + "rev": "98db6eacb084c2c5280fb653bee3d313e3ca6df8", "type": "github" }, "original": { @@ -121,11 +121,11 @@ "src-misoc": { "flake": false, "locked": { - "lastModified": 1665395741, - "narHash": "sha256-7ULMGBPPn5NxZX6rdxU5GheoSNBiJklHQEVf04jU9tI=", + "lastModified": 1669779825, + "narHash": "sha256-l3lyy6dmbivo9Tppb08KHSyU89ZZG1CCcSjPlNRD210=", "ref": "master", - "rev": "4fb0730db4c5de7e86f82fa3bd204e6c4608af85", - "revCount": 2427, + "rev": "2c255775f732a41ba1a512ab3d2547af4e25f674", + "revCount": 2435, "submodules": true, "type": "git", "url": "https://github.com/m-labs/misoc.git" diff --git a/flake.nix b/flake.nix index cec1d123a..25216ea28 100644 --- a/flake.nix +++ b/flake.nix @@ -1,7 +1,7 @@ { description = "A leading-edge control system for quantum information experiments"; - inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-22.05; + inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-22.11; inputs.mozilla-overlay = { url = github:mozilla/nixpkgs-mozilla; flake = false; }; inputs.sipyco.url = github:m-labs/sipyco; inputs.sipyco.inputs.nixpkgs.follows = "nixpkgs"; From 195d2aea6a3a521d40fc2a4e5875dde3ac71d39a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 30 Nov 2022 21:47:53 +0800 Subject: [PATCH 18/85] flake: update cargo-xbuild --- flake.nix | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/flake.nix b/flake.nix index 25216ea28..90b931107 100644 --- a/flake.nix +++ b/flake.nix @@ -209,16 +209,18 @@ cargo-xbuild = rustPlatform.buildRustPackage rec { pname = "cargo-xbuild"; - version = "0.6.5"; + version = "0.6.6"; src = pkgs.fetchFromGitHub { owner = "rust-osdev"; repo = pname; rev = "v${version}"; - sha256 = "18djvygq9v8rmfchvi2hfj0i6fhn36m716vqndqnj56fiqviwxvf"; + sha256 = "sha256-29rCjmzxxIjR5nBN2J3xxP+r8NnPIJV90FkSQQEBbo4="; }; - cargoSha256 = "13sj9j9kl6js75h9xq0yidxy63vixxm9q3f8jil6ymarml5wkhx8"; + cargoLock = { + lockFile = "${src}/Cargo.lock"; + }; }; vivadoEnv = pkgs.buildFHSUserEnv { From 3735b7ea9d428fc124dff0b5000c362790227a50 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 30 Nov 2022 22:19:27 +0800 Subject: [PATCH 19/85] Revert "flake: update cargo-xbuild" This reverts commit 195d2aea6a3a521d40fc2a4e5875dde3ac71d39a. --- flake.nix | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/flake.nix b/flake.nix index 90b931107..25216ea28 100644 --- a/flake.nix +++ b/flake.nix @@ -209,18 +209,16 @@ cargo-xbuild = rustPlatform.buildRustPackage rec { pname = "cargo-xbuild"; - version = "0.6.6"; + version = "0.6.5"; src = pkgs.fetchFromGitHub { owner = "rust-osdev"; repo = pname; rev = "v${version}"; - sha256 = "sha256-29rCjmzxxIjR5nBN2J3xxP+r8NnPIJV90FkSQQEBbo4="; + sha256 = "18djvygq9v8rmfchvi2hfj0i6fhn36m716vqndqnj56fiqviwxvf"; }; - cargoLock = { - lockFile = "${src}/Cargo.lock"; - }; + cargoSha256 = "13sj9j9kl6js75h9xq0yidxy63vixxm9q3f8jil6ymarml5wkhx8"; }; vivadoEnv = pkgs.buildFHSUserEnv { From 3f93f169555fadfe78901ec8c217c1eaa54a656f Mon Sep 17 00:00:00 2001 From: wlph17 <55318763+wlph17@users.noreply.github.com> Date: Thu, 1 Dec 2022 17:23:51 +0800 Subject: [PATCH 20/85] manual: add msys2 openocd instructions (#2014) --- doc/manual/installing.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 19fe706a8..485c573f4 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -186,6 +186,10 @@ OpenOCD can be used to write the binary images into the core device FPGA board's With Nix, add ``aqmain.openocd-bscanspi`` to the shell packages. Be careful not to add ``pkgs.openocd`` instead - this would install OpenOCD from the NixOS package collection, which does not support ARTIQ boards. +With MSYS2, install ``openocd`` and ``bscan-spi-bitstreams`` as follows:: + + pacman -S mingw-w64-x86_64-openocd mingw-w64-x86_64-bscan-spi-bitstreams + With Conda, install ``openocd`` as follows:: $ conda install -c m-labs openocd From d60a96a71516be79173e59a2e3c8090b0f099af4 Mon Sep 17 00:00:00 2001 From: Egor Savkin Date: Thu, 1 Dec 2022 17:26:52 +0800 Subject: [PATCH 21/85] Fix deprecated warnings on nix develop Signed-off-by: Egor Savkin --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 09159d80d..b730e6798 100755 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -from setuptools import setup, find_packages +from setuptools import setup, find_namespace_packages import sys import versioneer @@ -66,7 +66,7 @@ Topic :: System :: Hardware """.splitlines(), install_requires=requirements, extras_require={}, - packages=find_packages(), + packages=find_namespace_packages(exclude=["artiq.test.lit", "artiq.test.lit.*", "doc.manual"], ), namespace_packages=[], include_package_data=True, ext_modules=[], From aa2febca53878fb3d77306df73a3382a3ca3505a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=81=AB=E7=84=9A=20=E5=AF=8C=E8=89=AF?= Date: Thu, 1 Dec 2022 17:45:02 +0800 Subject: [PATCH 22/85] browser: fix dummy device creation failure on analyze --- artiq/browser/experiments.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/browser/experiments.py b/artiq/browser/experiments.py index 6b580a7ed..a67b93736 100644 --- a/artiq/browser/experiments.py +++ b/artiq/browser/experiments.py @@ -406,7 +406,7 @@ class ExperimentsArea(QtWidgets.QMdiArea): self.worker_handlers = { "get_device_db": lambda: {}, - "get_device": lambda k: {"type": "dummy"}, + "get_device": lambda key, resolve_alias=False: {"type": "dummy"}, "get_dataset": self._ddb.get, "update_dataset": self._ddb.update, } From 1abedba6dc126e690766d73420e44cdc583b7994 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 1 Dec 2022 12:11:35 +0000 Subject: [PATCH 23/85] coredevice/fastino: Fix stray punctuation [nfc] --- artiq/coredevice/fastino.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/fastino.py b/artiq/coredevice/fastino.py index c2ea4ad2c..7d5c1cd34 100644 --- a/artiq/coredevice/fastino.py +++ b/artiq/coredevice/fastino.py @@ -21,7 +21,7 @@ class Fastino: DAC updates synchronized to a frame edge. The `log2_width=0` RTIO layout uses one DAC channel per RTIO address and a - dense RTIO address space. The RTIO words are narrow. (32 bit) and + dense RTIO address space. The RTIO words are narrow (32 bit) and few-channel updates are efficient. There is the least amount of DAC state tracking in kernels, at the cost of more DMA and RTIO data. The setting here and in the RTIO PHY (gateware) must match. From 261dc6b9330e831720bcb0de116fab4ece2c8bf4 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 2 Dec 2022 01:37:56 +0000 Subject: [PATCH 24/85] firmware/runtime: Fix Ext0_Synth0_*to125 log messages --- artiq/firmware/runtime/rtio_clocking.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/runtime/rtio_clocking.rs b/artiq/firmware/runtime/rtio_clocking.rs index f0330b4d9..a7259bc66 100644 --- a/artiq/firmware/runtime/rtio_clocking.rs +++ b/artiq/firmware/runtime/rtio_clocking.rs @@ -134,7 +134,7 @@ fn setup_si5324_as_synthesizer(cfg: RtioClock) { } }, RtioClock::Ext0_Synth0_100to125 => { // 125MHz output, from 100MHz CLKINx reference, 586 Hz loop bandwidth - info!("using 10MHz reference to make 125MHz RTIO clock with PLL"); + info!("using 100MHz reference to make 125MHz RTIO clock with PLL"); si5324::FrequencySettings { n1_hs : 10, nc1_ls : 4, @@ -147,7 +147,7 @@ fn setup_si5324_as_synthesizer(cfg: RtioClock) { } }, RtioClock::Ext0_Synth0_125to125 => { // 125MHz output, from 125MHz CLKINx reference, 606 Hz loop bandwidth - info!("using 10MHz reference to make 125MHz RTIO clock with PLL"); + info!("using 125MHz reference to make 125MHz RTIO clock with PLL"); si5324::FrequencySettings { n1_hs : 5, nc1_ls : 8, From c591e7e305e98475fd293676cef19a030f7a260f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=81=AB=E7=84=9A=20=E5=AF=8C=E8=89=AF?= Date: Fri, 2 Dec 2022 10:45:40 +0800 Subject: [PATCH 25/85] sampler: fix reference voltage of recent hardware --- RELEASE_NOTES.rst | 3 +++ .../coredevice/coredevice_generic.schema.json | 3 +++ artiq/coredevice/sampler.py | 26 ++++++++++++------- artiq/coredevice/suservo.py | 12 +++++---- artiq/frontend/artiq_ddb_template.py | 8 ++++-- 5 files changed, 36 insertions(+), 16 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 28e06bdd6..6c891909a 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -12,6 +12,9 @@ Highlights: * Implemented Phaser-MIQRO support. This requires the Phaser MIQRO gateware variant. * MSYS2 packaging for Windows. +* Sampler: adjusted ADC MU to Volt conversion base for Sampler since v2.2. + For earlier version please explicitly define it as an argument in the device database file + (e.g. ``"hw_rev": "v2.1"``). ARTIQ-7 ------- diff --git a/artiq/coredevice/coredevice_generic.schema.json b/artiq/coredevice/coredevice_generic.schema.json index 79527cf31..e29f76511 100644 --- a/artiq/coredevice/coredevice_generic.schema.json +++ b/artiq/coredevice/coredevice_generic.schema.json @@ -376,6 +376,9 @@ "minItems": 2, "maxItems": 2 }, + "sampler_hw_rev": { + "type": "string" + }, "urukul0_ports": { "type": "array", "items": { diff --git a/artiq/coredevice/sampler.py b/artiq/coredevice/sampler.py index 8679ad93c..caba223fe 100644 --- a/artiq/coredevice/sampler.py +++ b/artiq/coredevice/sampler.py @@ -15,24 +15,26 @@ SPI_CS_PGIA = 1 # separate SPI bus, CS used as RCLK @portable -def adc_mu_to_volt(data, gain=0): +def adc_mu_to_volt(data, gain=0, corrected_fs=True): """Convert ADC data in machine units to Volts. :param data: 16 bit signed ADC word :param gain: PGIA gain setting (0: 1, ..., 3: 1000) + :param corrected_fs: use corrected ADC FS reference. + Should be True for Samplers' revisions after v2.1. False for v2.1 and earlier. :return: Voltage in Volts """ if gain == 0: - volt_per_lsb = 20./(1 << 16) + volt_per_lsb = 20.48 / (1 << 16) if corrected_fs else 20. / (1 << 16) elif gain == 1: - volt_per_lsb = 2./(1 << 16) + volt_per_lsb = 2.048 / (1 << 16) if corrected_fs else 2. / (1 << 16) elif gain == 2: - volt_per_lsb = .2/(1 << 16) + volt_per_lsb = .2048 / (1 << 16) if corrected_fs else .2 / (1 << 16) elif gain == 3: - volt_per_lsb = .02/(1 << 16) + volt_per_lsb = 0.02048 / (1 << 16) if corrected_fs else .02 / (1 << 16) else: raise ValueError("invalid gain") - return data*volt_per_lsb + return data * volt_per_lsb class Sampler: @@ -48,12 +50,13 @@ class Sampler: :param gains: Initial value for PGIA gains shift register (default: 0x0000). Knowledge of this state is not transferred between experiments. + :param hw_rev: Sampler's hardware revision string (default 'v2.2') :param core_device: Core device name """ - kernel_invariants = {"bus_adc", "bus_pgia", "core", "cnv", "div"} + kernel_invariants = {"bus_adc", "bus_pgia", "core", "cnv", "div", "corrected_fs"} def __init__(self, dmgr, spi_adc_device, spi_pgia_device, cnv_device, - div=8, gains=0x0000, core_device="core"): + div=8, gains=0x0000, hw_rev="v2.2", core_device="core"): self.bus_adc = dmgr.get(spi_adc_device) self.bus_adc.update_xfer_duration_mu(div, 32) self.bus_pgia = dmgr.get(spi_pgia_device) @@ -62,6 +65,11 @@ class Sampler: self.cnv = dmgr.get(cnv_device) self.div = div self.gains = gains + self.corrected_fs = self.use_corrected_fs(hw_rev) + + @staticmethod + def use_corrected_fs(hw_rev): + return hw_rev != "v2.1" @kernel def init(self): @@ -144,4 +152,4 @@ class Sampler: for i in range(n): channel = i + 8 - len(data) gain = (self.gains >> (channel*2)) & 0b11 - data[i] = adc_mu_to_volt(adc_data[i], gain) + data[i] = adc_mu_to_volt(adc_data[i], gain, self.revision) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 1d0a72dad..26df13532 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -23,12 +23,12 @@ def y_mu_to_full_scale(y): @portable -def adc_mu_to_volts(x, gain): +def adc_mu_to_volts(x, gain, corrected_fs=True): """Convert servo ADC data from machine units to Volt.""" val = (x >> 1) & 0xffff mask = 1 << 15 val = -(val & mask) + (val & ~mask) - return sampler.adc_mu_to_volt(val, gain) + return sampler.adc_mu_to_volt(val, gain, corrected_fs) class SUServo: @@ -62,14 +62,15 @@ class SUServo: :param gains: Initial value for PGIA gains shift register (default: 0x0000). Knowledge of this state is not transferred between experiments. + :param sampler_hw_rev: Sampler's revision string :param core_device: Core device name """ kernel_invariants = {"channel", "core", "pgia", "cplds", "ddses", - "ref_period_mu"} + "ref_period_mu", "corrected_fs"} def __init__(self, dmgr, channel, pgia_device, cpld_devices, dds_devices, - gains=0x0000, core_device="core"): + gains=0x0000, sampler_hw_rev="v2.2", core_device="core"): self.core = dmgr.get(core_device) self.pgia = dmgr.get(pgia_device) @@ -81,6 +82,7 @@ class SUServo: self.gains = gains self.ref_period_mu = self.core.seconds_to_mu( self.core.coarse_ref_period) + self.corrected_fs = sampler.Sampler.use_corrected_fs(sampler_hw_rev) assert self.ref_period_mu == self.core.ref_multiplier @kernel @@ -234,7 +236,7 @@ class SUServo: """ val = self.get_adc_mu(channel) gain = (self.gains >> (channel*2)) & 0b11 - return adc_mu_to_volts(val, gain) + return adc_mu_to_volts(val, gain, self.corrected_fs) class Channel: diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index 275c6e42e..f359b65f0 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -410,10 +410,12 @@ class PeripheralManager: "arguments": {{ "spi_adc_device": "spi_{name}_adc", "spi_pgia_device": "spi_{name}_pgia", - "cnv_device": "ttl_{name}_cnv" + "cnv_device": "ttl_{name}_cnv", + "hw_rev": "{hw_rev}" }} }}""", name=self.get_name("sampler"), + hw_rev=peripheral.get("hw_rev", "v2.2"), adc_channel=rtio_offset, pgia_channel=rtio_offset + 1, cnv_channel=rtio_offset + 2) @@ -444,11 +446,13 @@ class PeripheralManager: "channel": 0x{suservo_channel:06x}, "pgia_device": "spi_{sampler_name}_pgia", "cpld_devices": {cpld_names_list}, - "dds_devices": {dds_names_list} + "dds_devices": {dds_names_list}, + "sampler_hw_rev": "{sampler_hw_rev}" }} }}""", suservo_name=suservo_name, sampler_name=sampler_name, + sampler_hw_rev=peripheral.get("sampler_hw_rev", "v2.2"), cpld_names_list=[urukul_name + "_cpld" for urukul_name in urukul_names], dds_names_list=[urukul_name + "_dds" for urukul_name in urukul_names], suservo_channel=rtio_offset+next(channel)) From 1852491102752c83f6689a316e61b8000454d4fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=81=AB=E7=84=9A=20=E5=AF=8C=E8=89=AF?= Date: Fri, 2 Dec 2022 16:27:03 +0800 Subject: [PATCH 26/85] add channel names to RTIO errors --- RELEASE_NOTES.rst | 1 + artiq/coredevice/ad9914.py | 4 ++ artiq/coredevice/adf5356.py | 4 ++ artiq/coredevice/edge_counter.py | 4 ++ artiq/coredevice/fastino.py | 4 ++ artiq/coredevice/grabber.py | 4 ++ artiq/coredevice/phaser.py | 19 +++++- artiq/coredevice/sawg.py | 13 ++++ artiq/coredevice/spi2.py | 4 ++ artiq/coredevice/spline.py | 4 ++ artiq/coredevice/suservo.py | 8 +++ artiq/coredevice/ttl.py | 12 ++++ artiq/firmware/ksupport/lib.rs | 8 +-- artiq/firmware/ksupport/rtio.rs | 20 +++---- artiq/firmware/runtime/main.rs | 2 +- artiq/firmware/runtime/rtio_mgt.rs | 63 ++++++++++++++++---- artiq/firmware/runtime/session.rs | 25 +++++++- artiq/frontend/artiq_ddb_template.py | 5 +- artiq/frontend/artiq_rtiomap.py | 89 ++++++++++++++++++++++++++++ artiq/test/test_frontends.py | 2 +- doc/manual/installing.rst | 10 ++++ doc/manual/utilities.rst | 9 +++ setup.py | 1 + 23 files changed, 281 insertions(+), 34 deletions(-) create mode 100755 artiq/frontend/artiq_rtiomap.py diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 6c891909a..4c3e1732e 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -15,6 +15,7 @@ Highlights: * Sampler: adjusted ADC MU to Volt conversion base for Sampler since v2.2. For earlier version please explicitly define it as an argument in the device database file (e.g. ``"hw_rev": "v2.1"``). +* Added channel names to RTIO errors. ARTIQ-7 ------- diff --git a/artiq/coredevice/ad9914.py b/artiq/coredevice/ad9914.py index ce7e3b1a2..9466b90d8 100644 --- a/artiq/coredevice/ad9914.py +++ b/artiq/coredevice/ad9914.py @@ -80,6 +80,10 @@ class AD9914: self.set_x_duration_mu = 7 * self.write_duration_mu self.exit_x_duration_mu = 3 * self.write_duration_mu + @staticmethod + def get_rtio_channels(bus_channel, **kwargs): + return [(bus_channel, None)] + @kernel def write(self, addr, data): rtio_output((self.bus_channel << 8) | addr, data) diff --git a/artiq/coredevice/adf5356.py b/artiq/coredevice/adf5356.py index f20ead804..f2b594dbf 100644 --- a/artiq/coredevice/adf5356.py +++ b/artiq/coredevice/adf5356.py @@ -73,6 +73,10 @@ class ADF5356: self._init_registers() + @staticmethod + def get_rtio_channels(channel, **kwargs): + return [(channel, None)] + @kernel def init(self, blind=False): """ diff --git a/artiq/coredevice/edge_counter.py b/artiq/coredevice/edge_counter.py index e7782064e..a3200d3dd 100644 --- a/artiq/coredevice/edge_counter.py +++ b/artiq/coredevice/edge_counter.py @@ -91,6 +91,10 @@ class EdgeCounter: self.channel = channel self.counter_max = (1 << (gateware_width - 1)) - 1 + @staticmethod + def get_rtio_channels(channel, **kwargs): + return [(channel, None)] + @kernel def gate_rising(self, duration): """Count rising edges for the given duration and request the total at diff --git a/artiq/coredevice/fastino.py b/artiq/coredevice/fastino.py index 7d5c1cd34..84cc0500b 100644 --- a/artiq/coredevice/fastino.py +++ b/artiq/coredevice/fastino.py @@ -52,6 +52,10 @@ class Fastino: assert self.core.ref_period == 1*ns self.t_frame = int64(14*7*4) + @staticmethod + def get_rtio_channels(channel, **kwargs): + return [(channel, None)] + @kernel def init(self): """Initialize the device. diff --git a/artiq/coredevice/grabber.py b/artiq/coredevice/grabber.py index 6f29debe3..518a5b12a 100644 --- a/artiq/coredevice/grabber.py +++ b/artiq/coredevice/grabber.py @@ -25,6 +25,10 @@ class Grabber: # ROI engine outputs for one video frame. self.sentinel = int32(int64(2**count_width)) + @staticmethod + def get_rtio_channels(channel_base, **kwargs): + return [(channel_base, "ROI coordinates"), (channel_base + 1, "ROI mask")] + @kernel def setup_roi(self, n, x0, y0, x1, y1): """ diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 5ee3124b0..ebe5e047d 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -229,7 +229,7 @@ class Phaser: "dac_mmap"} def __init__(self, dmgr, channel_base, miso_delay=1, tune_fifo_offset=True, - clk_sel=0, sync_dly=0, dac=None, trf0=None, trf1=None, + clk_sel=0, sync_dly=0, dac=None, trf0=None, trf1=None, gw_rev=PHASER_GW_BASE, core_device="core"): self.channel_base = channel_base self.core = dmgr.get(core_device) @@ -243,13 +243,25 @@ class Phaser: self.clk_sel = clk_sel self.tune_fifo_offset = tune_fifo_offset self.sync_dly = sync_dly - self.gw_rev = -1 # discovered in init() + self.gw_rev = gw_rev # verified in init() self.dac_mmap = DAC34H84(dac).get_mmap() self.channel = [PhaserChannel(self, ch, trf) for ch, trf in enumerate([trf0, trf1])] + @staticmethod + def get_rtio_channels(channel_base, gw_rev=PHASER_GW_BASE, **kwargs): + if gw_rev == PHASER_GW_MIQRO: + return [(channel_base, "base"), (channel_base + 1, "ch0"), (channel_base + 2, "ch1")] + elif gw_rev == PHASER_GW_BASE: + return [(channel_base, "base"), + (channel_base + 1, "ch0 frequency"), + (channel_base + 2, "ch0 phase amplitude"), + (channel_base + 3, "ch1 frequency"), + (channel_base + 4, "ch1 phase amplitude")] + raise ValueError("invalid gw_rev `{}`".format(gw_rev)) + @kernel def init(self, debug=False): """Initialize the board. @@ -267,10 +279,11 @@ class Phaser: delay(.1*ms) # slack is_baseband = hw_rev & PHASER_HW_REV_VARIANT - self.gw_rev = self.read8(PHASER_ADDR_GW_REV) + gw_rev = self.read8(PHASER_ADDR_GW_REV) if debug: print("gw_rev:", self.gw_rev) self.core.break_realtime() + assert gw_rev == self.gw_rev delay(.1*ms) # slack # allow a few errors during startup and alignment since boot diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index 0a5905fa7..0d181ed78 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -334,6 +334,19 @@ class SAWG: self.phase0 = Spline(width, time_width, channel_base + 9, self.core, 1.) + @staticmethod + def get_rtio_channels(channel_base, **kwargs): + return [(channel_base, "base"), + (channel_base+1, "offset"), + (channel_base+2, "amplitude 1"), + (channel_base+3, "frequency 1"), + (channel_base+4, "phase 1"), + (channel_base+5, "amplitude 2"), + (channel_base+6, "frequency 2"), + (channel_base+7, "phase 2"), + (channel_base+8, "frequency 0"), + (channel_base+9, "phase0")] + @kernel def reset(self): """Re-establish initial conditions. diff --git a/artiq/coredevice/spi2.py b/artiq/coredevice/spi2.py index aa1045973..1a788d88f 100644 --- a/artiq/coredevice/spi2.py +++ b/artiq/coredevice/spi2.py @@ -72,6 +72,10 @@ class SPIMaster: self.channel = channel self.update_xfer_duration_mu(div, length) + @staticmethod + def get_rtio_channels(channel, **kwargs): + return [(channel, None)] + @portable def frequency_to_div(self, f): """Convert a SPI clock frequency to the closest SPI clock divider.""" diff --git a/artiq/coredevice/spline.py b/artiq/coredevice/spline.py index 9f8310d1e..4a77e0261 100644 --- a/artiq/coredevice/spline.py +++ b/artiq/coredevice/spline.py @@ -41,6 +41,10 @@ class Spline: self.time_scale = float((1 << time_width) * core_device.coarse_ref_period) + @staticmethod + def get_rtio_channels(channel, **kwargs): + return [(channel, None)] + @portable(flags={"fast-math"}) def to_mu(self, value: TFloat) -> TInt32: """Convert floating point ``value`` from physical units to 32 bit diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 26df13532..5214e5a30 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -85,6 +85,10 @@ class SUServo: self.corrected_fs = sampler.Sampler.use_corrected_fs(sampler_hw_rev) assert self.ref_period_mu == self.core.ref_multiplier + @staticmethod + def get_rtio_channels(channel, **kwargs): + return [(channel, None)] + @kernel def init(self): """Initialize the servo, Sampler and both Urukuls. @@ -257,6 +261,10 @@ class Channel: self.servo.channel) self.dds = self.servo.ddses[self.servo_channel // 4] + @staticmethod + def get_rtio_channels(channel, **kwargs): + return [(channel, None)] + @kernel def set(self, en_out, en_iir=0, profile=0): """Operate channel. diff --git a/artiq/coredevice/ttl.py b/artiq/coredevice/ttl.py index 2bc40ed58..eafec1797 100644 --- a/artiq/coredevice/ttl.py +++ b/artiq/coredevice/ttl.py @@ -36,6 +36,10 @@ class TTLOut: self.channel = channel self.target_o = channel << 8 + @staticmethod + def get_rtio_channels(channel, **kwargs): + return [(channel, None)] + @kernel def output(self): pass @@ -128,6 +132,10 @@ class TTLInOut: self.target_sens = (channel << 8) + 2 self.target_sample = (channel << 8) + 3 + @staticmethod + def get_rtio_channels(channel, **kwargs): + return [(channel, None)] + @kernel def set_oe(self, oe): rtio_output(self.target_oe, 1 if oe else 0) @@ -465,6 +473,10 @@ class TTLClockGen: self.acc_width = numpy.int64(acc_width) + @staticmethod + def get_rtio_channels(channel, **kwargs): + return [(channel, None)] + @portable def frequency_to_ftw(self, frequency): """Returns the frequency tuning word corresponding to the given diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index 7bb1e675a..acb461f88 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -414,13 +414,13 @@ extern fn dma_playback(timestamp: i64, ptr: i32) { csr::rtio_dma::error_write(1); if error & 1 != 0 { raise!("RTIOUnderflow", - "RTIO underflow at {0} mu, channel {1}", - timestamp as i64, channel as i64, 0); + "RTIO underflow at channel {rtio_channel_info:0}, {1} mu", + channel as i64, timestamp as i64, 0); } if error & 2 != 0 { raise!("RTIODestinationUnreachable", - "RTIO destination unreachable, output, at {0} mu, channel {1}", - timestamp as i64, channel as i64, 0); + "RTIO destination unreachable, output, at channel {rtio_channel_info:0}, {1} mu", + channel as i64, timestamp as i64, 0); } } } diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index d9f568f75..b0168ba03 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -67,13 +67,13 @@ mod imp { } if status & RTIO_O_STATUS_UNDERFLOW != 0 { raise!("RTIOUnderflow", - "RTIO underflow at {0} mu, channel {1}, slack {2} mu", - timestamp, channel as i64, timestamp - get_counter()); + "RTIO underflow at channel {rtio_channel_info:0}, {1} mu, slack {2} mu", + channel as i64, timestamp, timestamp - get_counter()); } if status & RTIO_O_STATUS_DESTINATION_UNREACHABLE != 0 { raise!("RTIODestinationUnreachable", - "RTIO destination unreachable, output, at {0} mu, channel {1}", - timestamp, channel as i64, 0); + "RTIO destination unreachable, output, at channel {rtio_channel_info:0}, {1} mu", + channel as i64, timestamp, 0); } } @@ -115,7 +115,7 @@ mod imp { if status & RTIO_I_STATUS_OVERFLOW != 0 { raise!("RTIOOverflow", - "RTIO input overflow on channel {0}", + "RTIO input overflow on channel {rtio_channel_info:0}", channel as i64, 0, 0); } if status & RTIO_I_STATUS_WAIT_EVENT != 0 { @@ -123,7 +123,7 @@ mod imp { } if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 { raise!("RTIODestinationUnreachable", - "RTIO destination unreachable, input, on channel {0}", + "RTIO destination unreachable, input, on channel {rtio_channel_info:0}", channel as i64, 0, 0); } @@ -143,12 +143,12 @@ mod imp { if status & RTIO_I_STATUS_OVERFLOW != 0 { raise!("RTIOOverflow", - "RTIO input overflow on channel {0}", + "RTIO input overflow on channel {rtio_channel_info:0}", channel as i64, 0, 0); } if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 { raise!("RTIODestinationUnreachable", - "RTIO destination unreachable, input, on channel {0}", + "RTIO destination unreachable, input, on channel {rtio_channel_info:0}", channel as i64, 0, 0); } @@ -168,7 +168,7 @@ mod imp { if status & RTIO_I_STATUS_OVERFLOW != 0 { raise!("RTIOOverflow", - "RTIO input overflow on channel {0}", + "RTIO input overflow on channel {rtio_channel_info:0}", channel as i64, 0, 0); } if status & RTIO_I_STATUS_WAIT_EVENT != 0 { @@ -176,7 +176,7 @@ mod imp { } if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 { raise!("RTIODestinationUnreachable", - "RTIO destination unreachable, input, on channel {0}", + "RTIO destination unreachable, input, on channel {rtio_channel_info:0}", channel as i64, 0, 0); } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index b36fd9251..8715de959 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -1,4 +1,4 @@ -#![feature(lang_items, panic_info_message)] +#![feature(lang_items, panic_info_message, const_btree_new, iter_advance_by)] #![no_std] extern crate eh; diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index c4ca665d4..41dbcb42a 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -1,15 +1,20 @@ +use alloc::collections::BTreeMap; +use alloc::string::String; use core::cell::RefCell; use urc::Urc; -use board_misoc::csr; +use board_misoc::{csr, config}; #[cfg(has_drtio)] use board_misoc::clock; use board_artiq::drtio_routing; use sched::Io; use sched::Mutex; +use io::{Cursor, ProtoRead}; const ASYNC_ERROR_COLLISION: u8 = 1 << 0; const ASYNC_ERROR_BUSY: u8 = 1 << 1; const ASYNC_ERROR_SEQUENCE_ERROR: u8 = 1 << 2; +static mut RTIO_DEVICE_MAP: BTreeMap = BTreeMap::new(); + #[cfg(has_drtio)] pub mod drtio { use super::*; @@ -215,15 +220,15 @@ pub mod drtio { destination_set_up(routing_table, up_destinations, destination, false), Ok(drtioaux::Packet::DestinationOkReply) => (), Ok(drtioaux::Packet::DestinationSequenceErrorReply { channel }) => { - error!("[DEST#{}] RTIO sequence error involving channel 0x{:04x}", destination, channel); + error!("[DEST#{}] RTIO sequence error involving channel {} 0x{:04x}", destination, resolve_channel_name(channel as u32), channel); unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_SEQUENCE_ERROR }; } Ok(drtioaux::Packet::DestinationCollisionReply { channel }) => { - error!("[DEST#{}] RTIO collision involving channel 0x{:04x}", destination, channel); + error!("[DEST#{}] RTIO collision involving channel {} 0x{:04x}", destination, resolve_channel_name(channel as u32), channel); unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_COLLISION }; } Ok(drtioaux::Packet::DestinationBusyReply { channel }) => { - error!("[DEST#{}] RTIO busy error involving channel 0x{:04x}", destination, channel); + error!("[DEST#{}] RTIO busy error involving channel {} 0x{:04x}", destination, resolve_channel_name(channel as u32), channel); unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_BUSY }; } Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet), @@ -349,16 +354,16 @@ fn async_error_thread(io: Io) { io.until(|| csr::rtio_core::async_error_read() != 0).unwrap(); let errors = csr::rtio_core::async_error_read(); if errors & ASYNC_ERROR_COLLISION != 0 { - error!("RTIO collision involving channel {}", - csr::rtio_core::collision_channel_read()); + let channel = csr::rtio_core::collision_channel_read(); + error!("RTIO collision involving channel {}:{}", channel, resolve_channel_name(channel as u32)); } if errors & ASYNC_ERROR_BUSY != 0 { - error!("RTIO busy error involving channel {}", - csr::rtio_core::busy_channel_read()); + let channel = csr::rtio_core::busy_channel_read(); + error!("RTIO busy error involving channel {}:{}", channel, resolve_channel_name(channel as u32)); } if errors & ASYNC_ERROR_SEQUENCE_ERROR != 0 { - error!("RTIO sequence error involving channel {}", - csr::rtio_core::sequence_error_channel_read()); + let channel = csr::rtio_core::sequence_error_channel_read(); + error!("RTIO sequence error involving channel {}:{}", channel, resolve_channel_name(channel as u32)); } SEEN_ASYNC_ERRORS = errors; csr::rtio_core::async_error_write(errors); @@ -366,9 +371,47 @@ fn async_error_thread(io: Io) { } } +fn read_device_map() -> BTreeMap { + let mut device_map: BTreeMap = BTreeMap::new(); + config::read("device_map", |value: Result<&[u8], config::Error>| { + let mut bytes = match value { + Ok(val) => if val.len() > 0 { Cursor::new(val) } else { + error!("read_device_map: `device_map` was not found in the config"); + return; + }, + Err(err) => { + error!("read_device_map: error reading `device_map` from config: {}", err); + return; + } + }; + let size = bytes.read_u32().unwrap(); + for _ in 0..size { + let channel = bytes.read_u32().unwrap(); + let device_name= bytes.read_string().unwrap(); + if let Some(old_entry) = device_map.insert(channel, device_name.clone()) { + error!("conflicting entries for channel {}: `{}` and `{}`", + channel, old_entry, device_name); + } + } + }); + device_map +} + +fn _resolve_channel_name(channel: u32, device_map: &BTreeMap) -> String { + match device_map.get(&channel) { + Some(val) => val.clone(), + None => String::from("unknown") + } +} + +pub fn resolve_channel_name(channel: u32) -> String { + _resolve_channel_name(channel, unsafe{&RTIO_DEVICE_MAP}) +} + pub fn startup(io: &Io, aux_mutex: &Mutex, routing_table: &Urc>, up_destinations: &Urc>) { + unsafe { RTIO_DEVICE_MAP = read_device_map(); } drtio::startup(io, aux_mutex, routing_table, up_destinations); unsafe { csr::rtio_core::reset_phy_write(1); diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index c6d745545..c9d1af4ee 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -1,4 +1,4 @@ -use core::{mem, str, cell::{Cell, RefCell}, fmt::Write as FmtWrite}; +use core::{mem, str, cell::{Cell, RefCell}, fmt::Write as FmtWrite, slice}; use alloc::{vec::Vec, string::String}; use byteorder::{ByteOrder, NativeEndian}; use cslice::CSlice; @@ -10,7 +10,7 @@ use urc::Urc; use sched::{ThreadHandle, Io, Mutex, TcpListener, TcpStream, Error as SchedError}; use rtio_clocking; use rtio_dma::Manager as DmaManager; -use rtio_mgt::get_async_errors; +use rtio_mgt::{get_async_errors, resolve_channel_name}; use cache::Cache; use kern_hwreq; use board_artiq::drtio_routing; @@ -449,6 +449,25 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex, session.kernel_state = KernelState::Absent; unsafe { session.congress.cache.unborrow() } + let exceptions_with_channel: Vec> = exceptions.iter() + .map(|exception| { + if let Some(exn) = exception { + let msg = str::from_utf8(unsafe{slice::from_raw_parts(exn.message.as_ptr(), exn.message.len())}) + .unwrap() + .replace("{rtio_channel_info:0}", &format!("{}:{}", exn.param[0], resolve_channel_name(exn.param[0] as u32))); + Some(eh::eh_artiq::Exception { + id: exn.id, + file: exn.file, + line: exn.line, + column: exn.column, + function: exn.function, + message: unsafe {CSlice::new(msg.as_ptr(), msg.len())}, + param: exn.param + }) + } else { None } + }) + .collect(); + match stream { None => { error!("exception in flash kernel"); @@ -459,7 +478,7 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex, }, Some(ref mut stream) => { host_write(stream, host::Reply::KernelException { - exceptions: exceptions, + exceptions: &exceptions_with_channel, stack_pointers: stack_pointers, backtrace: backtrace, async_errors: unsafe { get_async_errors() } diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index f359b65f0..6d8f13719 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -8,6 +8,7 @@ from itertools import count from artiq import __version__ as artiq_version from artiq.coredevice import jsondesc +from artiq.coredevice.phaser import PHASER_GW_MIQRO, PHASER_GW_BASE def process_header(output, description): @@ -566,10 +567,10 @@ class PeripheralManager: def process_phaser(self, rtio_offset, peripheral): mode = peripheral.get("mode", "base") if mode == "miqro": - dac = ', "dac": {"pll_m": 16, "pll_n": 3, "interpolation": 2}' + dac = f', "dac": {{"pll_m": 16, "pll_n": 3, "interpolation": 2}}, "gw_rev"={PHASER_GW_MIQRO}' n_channels = 3 else: - dac = "" + dac = f', "gw_rev"={PHASER_GW_BASE}' n_channels = 5 self.gen(""" device_db["{name}"] = {{ diff --git a/artiq/frontend/artiq_rtiomap.py b/artiq/frontend/artiq_rtiomap.py new file mode 100755 index 000000000..21326988d --- /dev/null +++ b/artiq/frontend/artiq_rtiomap.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 + +import argparse +import importlib +import struct + +from sipyco import common_args + +from artiq import __version__ as artiq_version +from artiq.master.databases import DeviceDB + + +def get_argparser(): + parser = argparse.ArgumentParser(description="ARTIQ RTIO channel name map encoder tool") + + parser.add_argument("--version", action="version", + version="ARTIQ v{}".format(artiq_version), + help="print the ARTIQ version number") + + common_args.verbosity_args(parser) + parser.add_argument("--device-db", default="device_db.py", + help="device database file (default: '%(default)s')") + parser.add_argument("file", metavar="FILE", default=None, + help="write the result into the specified file, or read from it to show the map (see `--show`)") + parser.add_argument("--show", default=False, action="store_true", + help="show the channel mapping from the specified file, instead of writing to it") + + return parser + + +def get_rtio_channels(desc): + if desc["type"] == "local": + module = importlib.import_module(desc["module"]) + device_class = getattr(module, desc["class"]) + return getattr(device_class, "get_rtio_channels", lambda **kwargs: [])(**desc.get("arguments", {})) + return [] + + +def get_channel_map(device_db): + reversed_map = {} + for dev_name, device in device_db.items(): + try: + channels = get_rtio_channels(device) + except Exception as e: + raise Exception(f"failed to process the device `{dev_name}`") from e + for chan, suffix in channels: + assert chan not in reversed_map + reversed_map[chan] = dev_name + (" " + suffix if suffix is not None else "") + + return reversed_map + + +def serialize_device_map(channel_map, outfile): + outfile.write(struct.pack(" {device}") + else: + ddb = DeviceDB(args.device_db) + chan_map = get_channel_map(ddb.get_device_db()) + + with open(args.file, "wb") as outfile: + serialize_device_map(chan_map, outfile) + + +if __name__ == "__main__": + main() diff --git a/artiq/test/test_frontends.py b/artiq/test/test_frontends.py index 622c7a010..caef4839c 100644 --- a/artiq/test/test_frontends.py +++ b/artiq/test/test_frontends.py @@ -13,7 +13,7 @@ class TestFrontends(unittest.TestCase): ], "artiq": [ "client", "compile", "coreanalyzer", "coremgmt", - "flash", "master", "mkfs", "route", + "flash", "master", "mkfs", "route", "rtiomap", "rtiomon", "run", "session", "browser", "dashboard" ] } diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 485c573f4..ef0106172 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -340,3 +340,13 @@ Other options include: - ``ext0_bypass_125`` and ``ext0_bypass_100`` - explicit aliases for ``ext0_bypass``. Availability of these options depends on the board and their configuration - specific setting may or may not be supported. + +* Setup resolving RTIO channels to their names + +This feature allows you to print the channels' respective names alongside with their numbers in RTIO error messages. To enable it, run the ``artiq_rtiomap`` tool and write its result into the device config at the ``device_map`` key: :: + + $ artiq_rtiomap dev_map.bin + $ artiq_coremgmt config write -f device_map dev_map.bin + +.. note:: You can find more information about how to use the ``artiq_rtiomap`` utility on the :ref:`Utilities ` page. + diff --git a/doc/manual/utilities.rst b/doc/manual/utilities.rst index d66d91342..fb08cb990 100644 --- a/doc/manual/utilities.rst +++ b/doc/manual/utilities.rst @@ -116,6 +116,15 @@ Moninj proxy :ref: artiq.frontend.aqctl_moninj_proxy.get_argparser :prog: aqctl_moninj_proxy +.. _rtiomap-tool: + +RTIO channel name map tool +-------------------------- + +.. argparse:: + :ref: artiq.frontend.artiq_rtiomap.get_argparser + :prog: artiq_rtiomap + .. _core-device-rtio-analyzer-tool: diff --git a/setup.py b/setup.py index b730e6798..93d4d2c35 100755 --- a/setup.py +++ b/setup.py @@ -23,6 +23,7 @@ console_scripts = [ "artiq_compile = artiq.frontend.artiq_compile:main", "artiq_coreanalyzer = artiq.frontend.artiq_coreanalyzer:main", "artiq_coremgmt = artiq.frontend.artiq_coremgmt:main", + "artiq_rtiomap = artiq.frontend.artiq_rtiomap:main", "artiq_ddb_template = artiq.frontend.artiq_ddb_template:main", "artiq_master = artiq.frontend.artiq_master:main", "artiq_mkfs = artiq.frontend.artiq_mkfs:main", From b2b559e73b67427861491dd3c10a8eecb541d66b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=81=AB=E7=84=9A=20=E5=AF=8C=E8=89=AF?= Date: Fri, 2 Dec 2022 16:30:58 +0800 Subject: [PATCH 27/85] browser: tolerate missing HDF5 metadata --- artiq/browser/files.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/artiq/browser/files.py b/artiq/browser/files.py index 46bf10b3f..4e3dd581a 100644 --- a/artiq/browser/files.py +++ b/artiq/browser/files.py @@ -102,13 +102,14 @@ class Hdf5FileSystemModel(QtWidgets.QFileSystemModel): h5 = open_h5(info) if h5 is not None: try: - expid = pyon.decode(h5["expid"][()]) - start_time = datetime.fromtimestamp(h5["start_time"][()]) + expid = pyon.decode(h5["expid"][()]) if "expid" in h5 else dict() + start_time = datetime.fromtimestamp(h5["start_time"][()]) if "start_time" in h5 else "" v = ("artiq_version: {}\nrepo_rev: {}\nfile: {}\n" "class_name: {}\nrid: {}\nstart_time: {}").format( - h5["artiq_version"][()], expid["repo_rev"], - expid.get("file", ""), expid["class_name"], - h5["rid"][()], start_time) + h5["artiq_version"][()] if "artiq_version" in h5 else "", + expid.get("repo_rev", ""), + expid.get("file", ""), expid.get("class_name", ""), + h5["rid"][()] if "rid" in h5 else "", start_time) return v except: logger.warning("unable to read metadata from %s", @@ -174,14 +175,14 @@ class FilesDock(QtWidgets.QDockWidget): logger.debug("loading datasets from %s", info.filePath()) with f: try: - expid = pyon.decode(f["expid"][()]) - start_time = datetime.fromtimestamp(f["start_time"][()]) + expid = pyon.decode(f["expid"][()]) if "expid" in f else dict() + start_time = datetime.fromtimestamp(f["start_time"][()]) if "start_time" in f else "" v = { - "artiq_version": f["artiq_version"][()], - "repo_rev": expid["repo_rev"], + "artiq_version": f["artiq_version"][()] if "artiq_version" in f else "", + "repo_rev": expid.get("repo_rev", ""), "file": expid.get("file", ""), - "class_name": expid["class_name"], - "rid": f["rid"][()], + "class_name": expid.get("class_name", ""), + "rid": f["rid"][()] if "rid" in f else "", "start_time": start_time, } self.metadata_changed.emit(v) From 740543d4e284245248e3ff838c46505938dcae7a Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 4 Dec 2022 02:23:38 +0000 Subject: [PATCH 28/85] firmware: Fix Kasli v2 runtime rtio_clock selection SI5324_EXT_REF now only controls the (deprecated) fallbacks for when the rtio_clock option is not set. --- artiq/firmware/libboard_artiq/si5324.rs | 5 ++++- artiq/firmware/runtime/rtio_clocking.rs | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index 3b1103d99..bc4930c96 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -214,8 +214,11 @@ pub fn bypass(input: Input) -> Result<()> { Ok(()) } -pub fn setup(settings: &FrequencySettings, input: Input) -> Result<()> { +pub fn setup(settings: &FrequencySettings, ext_input: Input) -> Result<()> { let s = map_frequency_settings(settings)?; + + // FREE_RUN=1 routes XA/XB to CKIN2. + let input = if settings.crystal_ref { Input::Ckin2 } else { ext_input }; let cksel_reg = match input { Input::Ckin1 => 0b00, Input::Ckin2 => 0b01, diff --git a/artiq/firmware/runtime/rtio_clocking.rs b/artiq/firmware/runtime/rtio_clocking.rs index a7259bc66..bb2c6b88d 100644 --- a/artiq/firmware/runtime/rtio_clocking.rs +++ b/artiq/firmware/runtime/rtio_clocking.rs @@ -212,9 +212,8 @@ fn setup_si5324_as_synthesizer(cfg: RtioClock) { } } }; - #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0", not(si5324_ext_ref)))] - let si5324_ref_input = si5324::Input::Ckin2; - #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0", si5324_ext_ref))] + + #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] let si5324_ref_input = si5324::Input::Ckin1; #[cfg(all(soc_platform = "kasli", not(hw_rev = "v2.0")))] let si5324_ref_input = si5324::Input::Ckin2; @@ -222,6 +221,7 @@ fn setup_si5324_as_synthesizer(cfg: RtioClock) { let si5324_ref_input = si5324::Input::Ckin2; #[cfg(soc_platform = "kc705")] let si5324_ref_input = si5324::Input::Ckin2; + si5324::setup(&si5324_settings, si5324_ref_input).expect("cannot initialize Si5324"); } From 3c7a394eff553ab75a7ea78bdd17830366504dc6 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 4 Dec 2022 04:00:48 +0000 Subject: [PATCH 29/85] runtime/rtio_clocking: Deduplicate/document input selection [nfc] --- artiq/firmware/runtime/rtio_clocking.rs | 33 ++++++++++--------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/artiq/firmware/runtime/rtio_clocking.rs b/artiq/firmware/runtime/rtio_clocking.rs index bb2c6b88d..bd227a5b0 100644 --- a/artiq/firmware/runtime/rtio_clocking.rs +++ b/artiq/firmware/runtime/rtio_clocking.rs @@ -117,6 +117,17 @@ pub mod crg { pub fn check() -> bool { true } } +// Si5324 input to select for locking to an external clock (as opposed to +// a recovered link clock in DRTIO satellites, which is handled elsewhere). +#[cfg(all(si5324_as_synthesizer, soc_platform = "kasli", hw_rev = "v2.0"))] +const SI5324_EXT_INPUT: si5324::Input = si5324::Input::Ckin1; +#[cfg(all(si5324_as_synthesizer, soc_platform = "kasli", not(hw_rev = "v2.0")))] +const SI5324_EXT_INPUT: si5324::Input = si5324::Input::Ckin2; +#[cfg(all(si5324_as_synthesizer, soc_platform = "metlino"))] +const SI5324_EXT_INPUT: si5324::Input = si5324::Input::Ckin2; +#[cfg(all(si5324_as_synthesizer, soc_platform = "kc705"))] +const SI5324_EXT_INPUT: si5324::Input = si5324::Input::Ckin2; + #[cfg(si5324_as_synthesizer)] fn setup_si5324_as_synthesizer(cfg: RtioClock) { let si5324_settings = match cfg { @@ -212,35 +223,17 @@ fn setup_si5324_as_synthesizer(cfg: RtioClock) { } } }; - - #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] - let si5324_ref_input = si5324::Input::Ckin1; - #[cfg(all(soc_platform = "kasli", not(hw_rev = "v2.0")))] - let si5324_ref_input = si5324::Input::Ckin2; - #[cfg(soc_platform = "metlino")] - let si5324_ref_input = si5324::Input::Ckin2; - #[cfg(soc_platform = "kc705")] - let si5324_ref_input = si5324::Input::Ckin2; - - si5324::setup(&si5324_settings, si5324_ref_input).expect("cannot initialize Si5324"); + si5324::setup(&si5324_settings, SI5324_EXT_INPUT).expect("cannot initialize Si5324"); } pub fn init() { let clock_cfg = get_rtio_clock_cfg(); #[cfg(si5324_as_synthesizer)] { - #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] - let si5324_ext_input = si5324::Input::Ckin1; - #[cfg(all(soc_platform = "kasli", not(hw_rev = "v2.0")))] - let si5324_ext_input = si5324::Input::Ckin2; - #[cfg(soc_platform = "metlino")] - let si5324_ext_input = si5324::Input::Ckin2; - #[cfg(soc_platform = "kc705")] - let si5324_ext_input = si5324::Input::Ckin2; match clock_cfg { RtioClock::Ext0_Bypass => { info!("using external RTIO clock with PLL bypass"); - si5324::bypass(si5324_ext_input).expect("cannot bypass Si5324") + si5324::bypass(SI5324_EXT_INPUT).expect("cannot bypass Si5324") }, _ => setup_si5324_as_synthesizer(clock_cfg), } From 454ae39c5dcd31ef80fa189ea866f99e205d2bb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=81=AB=E7=84=9A=20=E5=AF=8C=E8=89=AF?= Date: Wed, 7 Dec 2022 10:41:43 +0800 Subject: [PATCH 30/85] firmware: fix crash on exception with host message (#2017) --- artiq/firmware/runtime/session.rs | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index c9d1af4ee..e942d7bd9 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -452,18 +452,22 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex, let exceptions_with_channel: Vec> = exceptions.iter() .map(|exception| { if let Some(exn) = exception { - let msg = str::from_utf8(unsafe{slice::from_raw_parts(exn.message.as_ptr(), exn.message.len())}) - .unwrap() - .replace("{rtio_channel_info:0}", &format!("{}:{}", exn.param[0], resolve_channel_name(exn.param[0] as u32))); - Some(eh::eh_artiq::Exception { - id: exn.id, - file: exn.file, - line: exn.line, - column: exn.column, - function: exn.function, - message: unsafe {CSlice::new(msg.as_ptr(), msg.len())}, - param: exn.param - }) + if exn.message.len() == usize::MAX { // host string + Some(exn.clone()) + } else { + let msg = str::from_utf8(unsafe { slice::from_raw_parts(exn.message.as_ptr(), exn.message.len()) }) + .unwrap() + .replace("{rtio_channel_info:0}", &format!("{}:{}", exn.param[0], resolve_channel_name(exn.param[0] as u32))); + Some(eh::eh_artiq::Exception { + id: exn.id, + file: exn.file, + line: exn.line, + column: exn.column, + function: exn.function, + message: unsafe { CSlice::new(msg.as_ptr(), msg.len()) }, + param: exn.param, + }) + } } else { None } }) .collect(); From 12649720f1d696af0683a9b9a8de153c7860c590 Mon Sep 17 00:00:00 2001 From: Egor Savkin Date: Wed, 7 Dec 2022 12:11:31 +0800 Subject: [PATCH 31/85] browser: read artiq_version from HDF5 as string Signed-off-by: Egor Savkin --- artiq/browser/files.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/browser/files.py b/artiq/browser/files.py index 4e3dd581a..a714cb696 100644 --- a/artiq/browser/files.py +++ b/artiq/browser/files.py @@ -106,7 +106,7 @@ class Hdf5FileSystemModel(QtWidgets.QFileSystemModel): start_time = datetime.fromtimestamp(h5["start_time"][()]) if "start_time" in h5 else "" v = ("artiq_version: {}\nrepo_rev: {}\nfile: {}\n" "class_name: {}\nrid: {}\nstart_time: {}").format( - h5["artiq_version"][()] if "artiq_version" in h5 else "", + h5["artiq_version"].asstr()[()] if "artiq_version" in h5 else "", expid.get("repo_rev", ""), expid.get("file", ""), expid.get("class_name", ""), h5["rid"][()] if "rid" in h5 else "", start_time) @@ -178,7 +178,7 @@ class FilesDock(QtWidgets.QDockWidget): expid = pyon.decode(f["expid"][()]) if "expid" in f else dict() start_time = datetime.fromtimestamp(f["start_time"][()]) if "start_time" in f else "" v = { - "artiq_version": f["artiq_version"][()] if "artiq_version" in f else "", + "artiq_version": f["artiq_version"].asstr()[()] if "artiq_version" in f else "", "repo_rev": expid.get("repo_rev", ""), "file": expid.get("file", ""), "class_name": expid.get("class_name", ""), From e80442811e0d0bf5513017dd0bdaad1058663f2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=81=AB=E7=84=9A=20=E5=AF=8C=E8=89=AF?= Date: Fri, 9 Dec 2022 16:18:28 +0800 Subject: [PATCH 32/85] worker_impl: do not write results without rid (#2020) --- artiq/master/worker_impl.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/artiq/master/worker_impl.py b/artiq/master/worker_impl.py index 45c7308c0..719ff40a8 100644 --- a/artiq/master/worker_impl.py +++ b/artiq/master/worker_impl.py @@ -353,7 +353,10 @@ def main(): exp_inst.analyze() put_completed() finally: - write_results() + # browser's analyze shouldn't write results, + # since it doesn't run the experiment and cannot have rid + if rid is not None: + write_results() elif action == "examine": examine(ExamineDeviceMgr, ExamineDatasetMgr, obj["file"]) put_completed() From 2a58981822b1abee3ac6db090334a429a9f52b94 Mon Sep 17 00:00:00 2001 From: Egor Savkin Date: Fri, 9 Dec 2022 12:23:19 +0800 Subject: [PATCH 33/85] Scheduler: replace relative path to absolute Signed-off-by: Egor Savkin --- artiq/master/scheduler.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/artiq/master/scheduler.py b/artiq/master/scheduler.py index eea832a17..6d53ae97e 100644 --- a/artiq/master/scheduler.py +++ b/artiq/master/scheduler.py @@ -1,6 +1,7 @@ import asyncio import logging import csv +import os.path from enum import Enum from time import time @@ -131,7 +132,8 @@ class RunPool: writer.writerow([rid, start_time, expid["file"]]) def submit(self, expid, priority, due_date, flush, pipeline_name): - # mutates expid to insert head repository revision if None. + # mutates expid to insert head repository revision if None and + # replaces relative path with the absolute one. # called through scheduler. rid = self.ridc.get() if "repo_rev" in expid: @@ -141,6 +143,9 @@ class RunPool: expid["repo_rev"]) else: wd, repo_msg = None, None + + if "file" in expid: + expid["file"] = os.path.abspath(expid["file"]) run = Run(rid, pipeline_name, wd, expid, priority, due_date, flush, self, repo_msg=repo_msg) if self.log_submissions is not None: @@ -425,7 +430,8 @@ class Scheduler: When called through an experiment, the default values of ``pipeline_name``, ``expid`` and ``priority`` correspond to those of the current run.""" - # mutates expid to insert head repository revision if None + # mutates expid to insert head repository revision if None, and + # replaces relative file path with absolute one if self._terminated: return try: From d75ade7be621aea408e5d03e929a5f21ef39cca4 Mon Sep 17 00:00:00 2001 From: Egor Savkin Date: Tue, 13 Dec 2022 11:11:15 +0800 Subject: [PATCH 34/85] Fix rtiomap failure on device aliases Signed-off-by: Egor Savkin --- artiq/frontend/artiq_rtiomap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_rtiomap.py b/artiq/frontend/artiq_rtiomap.py index 21326988d..e35b61156 100755 --- a/artiq/frontend/artiq_rtiomap.py +++ b/artiq/frontend/artiq_rtiomap.py @@ -29,7 +29,7 @@ def get_argparser(): def get_rtio_channels(desc): - if desc["type"] == "local": + if isinstance(desc, dict) and desc["type"] == "local": module = importlib.import_module(desc["module"]) device_class = getattr(module, desc["class"]) return getattr(device_class, "get_rtio_channels", lambda **kwargs: [])(**desc.get("arguments", {})) From 874d298ceb68ffa776592f855365ca5e2e885575 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 13 Dec 2022 14:58:23 +0000 Subject: [PATCH 35/85] master/scheduler: Unbreak submitting from repository This is a fix-up to commit 2a58981822b. --- artiq/master/scheduler.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/master/scheduler.py b/artiq/master/scheduler.py index 6d53ae97e..0d007954a 100644 --- a/artiq/master/scheduler.py +++ b/artiq/master/scheduler.py @@ -142,10 +142,10 @@ class RunPool: wd, repo_msg = self.experiment_db.repo_backend.request_rev( expid["repo_rev"]) else: + if "file" in expid: + expid["file"] = os.path.abspath(expid["file"]) wd, repo_msg = None, None - if "file" in expid: - expid["file"] = os.path.abspath(expid["file"]) run = Run(rid, pipeline_name, wd, expid, priority, due_date, flush, self, repo_msg=repo_msg) if self.log_submissions is not None: From 8e476dd502800b3a39a826de366a8cf77a3386fb Mon Sep 17 00:00:00 2001 From: SingularitySurfer Date: Mon, 12 Dec 2022 17:24:32 +0000 Subject: [PATCH 36/85] implement pca9539 and runtime io-expander chip selection better comments and address translation fix spurious }; unwrap init in runtime and return err instead of panic propagate error del unnecessary use Signed-off-by: SingularitySurfer --- artiq/firmware/libboard_misoc/io_expander.rs | 74 ++++++++++++++++---- artiq/firmware/runtime/main.rs | 4 +- artiq/firmware/satman/main.rs | 4 +- 3 files changed, 65 insertions(+), 17 deletions(-) diff --git a/artiq/firmware/libboard_misoc/io_expander.rs b/artiq/firmware/libboard_misoc/io_expander.rs index 19baf5364..edf2ce666 100644 --- a/artiq/firmware/libboard_misoc/io_expander.rs +++ b/artiq/firmware/libboard_misoc/io_expander.rs @@ -1,5 +1,14 @@ -use i2c; use csr; +use i2c; + +// Only the bare minimum registers. Bits/IO connections equivalent between IC types. +struct Registers { + // PCA9539 equivalent register names in comments + iodira: u8, // Configuration Port 0 + iodirb: u8, // Configuration Port 1 + gpioa: u8, // Output Port 0 + gpiob: u8, // Output Port 1 +} pub struct IoExpander { busno: u8, @@ -9,15 +18,17 @@ pub struct IoExpander { iodir: [u8; 2], out_current: [u8; 2], out_target: [u8; 2], + registers: Registers, } impl IoExpander { #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] - pub fn new(index: u8) -> Self { + pub fn new(index: u8) -> Result { const VIRTUAL_LED_MAPPING0: [(u8, u8, u8); 2] = [(0, 0, 6), (1, 1, 6)]; const VIRTUAL_LED_MAPPING1: [(u8, u8, u8); 2] = [(2, 0, 6), (3, 1, 6)]; + // Both expanders on SHARED I2C bus - match index { + let mut io_expander = match index { 0 => IoExpander { busno: 0, port: 11, @@ -26,6 +37,12 @@ impl IoExpander { iodir: [0xff; 2], out_current: [0; 2], out_target: [0; 2], + registers: Registers { + iodira: 0x00, + iodirb: 0x01, + gpioa: 0x12, + gpiob: 0x13, + }, }, 1 => IoExpander { busno: 0, @@ -35,9 +52,33 @@ impl IoExpander { iodir: [0xff; 2], out_current: [0; 2], out_target: [0; 2], + registers: Registers { + iodira: 0x00, + iodirb: 0x01, + gpioa: 0x12, + gpiob: 0x13, + }, }, - _ => panic!("incorrect I/O expander index"), + _ => return Err("incorrect I/O expander index"), + }; + if !io_expander.check_ack()? { + #[cfg(feature = "log")] + log::info!( + "MCP23017 io expander {} not found. Checking for PCA9539.", + index + ); + io_expander.address += 0xa8; // translate to PCA9539 addresses (see schematic) + io_expander.registers = Registers { + iodira: 0x06, + iodirb: 0x07, + gpioa: 0x02, + gpiob: 0x03, + }; + if !io_expander.check_ack()? { + return Err("Neither MCP23017 nor PCA9539 io expander found."); + }; } + Ok(io_expander) } #[cfg(soc_platform = "kasli")] @@ -57,9 +98,18 @@ impl IoExpander { Ok(()) } + fn check_ack(&self) -> Result { + // Check for ack from io expander + self.select()?; + i2c::start(self.busno)?; + let ack = i2c::write(self.busno, self.address)?; + i2c::stop(self.busno)?; + Ok(ack) + } + fn update_iodir(&self) -> Result<(), &'static str> { - self.write(0x00, self.iodir[0])?; - self.write(0x01, self.iodir[1])?; + self.write(self.registers.iodira, self.iodir[0])?; + self.write(self.registers.iodirb, self.iodir[1])?; Ok(()) } @@ -72,9 +122,9 @@ impl IoExpander { self.update_iodir()?; self.out_current[0] = 0x00; - self.write(0x12, 0x00)?; + self.write(self.registers.gpioa, 0x00)?; self.out_current[1] = 0x00; - self.write(0x13, 0x00)?; + self.write(self.registers.gpiob, 0x00)?; Ok(()) } @@ -94,20 +144,18 @@ impl IoExpander { pub fn service(&mut self) -> Result<(), &'static str> { for (led, port, bit) in self.virtual_led_mapping.iter() { - let level = unsafe { - (csr::virtual_leds::status_read() >> led) & 1 - }; + let level = unsafe { (csr::virtual_leds::status_read() >> led) & 1 }; self.set(*port, *bit, level != 0); } if self.out_target != self.out_current { self.select()?; if self.out_target[0] != self.out_current[0] { - self.write(0x12, self.out_target[0])?; + self.write(self.registers.gpioa, self.out_target[0])?; self.out_current[0] = self.out_target[0]; } if self.out_target[1] != self.out_current[1] { - self.write(0x13, self.out_target[1])?; + self.write(self.registers.gpiob, self.out_target[1])?; self.out_current[1] = self.out_target[1]; } } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 8715de959..0d76bd78a 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -104,8 +104,8 @@ fn startup() { let (mut io_expander0, mut io_expander1); #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] { - io_expander0 = board_misoc::io_expander::IoExpander::new(0); - io_expander1 = board_misoc::io_expander::IoExpander::new(1); + io_expander0 = board_misoc::io_expander::IoExpander::new(0).unwrap(); + io_expander1 = board_misoc::io_expander::IoExpander::new(1).unwrap(); io_expander0.init().expect("I2C I/O expander #0 initialization failed"); io_expander1.init().expect("I2C I/O expander #1 initialization failed"); diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 10beb6695..7dde13f3f 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -488,8 +488,8 @@ pub extern fn main() -> i32 { let (mut io_expander0, mut io_expander1); #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] { - io_expander0 = board_misoc::io_expander::IoExpander::new(0); - io_expander1 = board_misoc::io_expander::IoExpander::new(1); + io_expander0 = board_misoc::io_expander::IoExpander::new(0).unwrap(); + io_expander1 = board_misoc::io_expander::IoExpander::new(1).unwrap(); io_expander0.init().expect("I2C I/O expander #0 initialization failed"); io_expander1.init().expect("I2C I/O expander #1 initialization failed"); #[cfg(has_wrpll)] From ceabeb8d84c9ba1fab0eb04a9ea6e4c8335b9c20 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 17 Dec 2022 02:06:22 +0000 Subject: [PATCH 37/85] firmware: Fix Si5324 initialisation for satellites Commit 740543d4e28424 had unintentionally broken DRTIO satellites, as si5324::setup is also used there. This imports setup_si5324_as_synthesizer() from artiq-zynq, where the input selection was already explicitly done. GitHub: Fixes #2028. --- artiq/firmware/libboard_artiq/si5324.rs | 4 +- artiq/firmware/runtime/rtio_clocking.rs | 169 +++++++++++++----------- 2 files changed, 96 insertions(+), 77 deletions(-) diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index bc4930c96..22b452d54 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -214,11 +214,9 @@ pub fn bypass(input: Input) -> Result<()> { Ok(()) } -pub fn setup(settings: &FrequencySettings, ext_input: Input) -> Result<()> { +pub fn setup(settings: &FrequencySettings, input: Input) -> Result<()> { let s = map_frequency_settings(settings)?; - // FREE_RUN=1 routes XA/XB to CKIN2. - let input = if settings.crystal_ref { Input::Ckin2 } else { ext_input }; let cksel_reg = match input { Input::Ckin1 => 0b00, Input::Ckin2 => 0b01, diff --git a/artiq/firmware/runtime/rtio_clocking.rs b/artiq/firmware/runtime/rtio_clocking.rs index bd227a5b0..da4d8ad92 100644 --- a/artiq/firmware/runtime/rtio_clocking.rs +++ b/artiq/firmware/runtime/rtio_clocking.rs @@ -130,100 +130,121 @@ const SI5324_EXT_INPUT: si5324::Input = si5324::Input::Ckin2; #[cfg(si5324_as_synthesizer)] fn setup_si5324_as_synthesizer(cfg: RtioClock) { - let si5324_settings = match cfg { + let (si5324_settings, si5324_ref_input) = match cfg { RtioClock::Ext0_Synth0_10to125 => { // 125 MHz output from 10 MHz CLKINx reference, 504 Hz BW info!("using 10MHz reference to make 125MHz RTIO clock with PLL"); - si5324::FrequencySettings { - n1_hs : 10, - nc1_ls : 4, - n2_hs : 10, - n2_ls : 300, - n31 : 6, - n32 : 6, - bwsel : 4, - crystal_ref: false - } + ( + si5324::FrequencySettings { + n1_hs : 10, + nc1_ls : 4, + n2_hs : 10, + n2_ls : 300, + n31 : 6, + n32 : 6, + bwsel : 4, + crystal_ref: false + }, + SI5324_EXT_INPUT + ) }, RtioClock::Ext0_Synth0_100to125 => { // 125MHz output, from 100MHz CLKINx reference, 586 Hz loop bandwidth info!("using 100MHz reference to make 125MHz RTIO clock with PLL"); - si5324::FrequencySettings { - n1_hs : 10, - nc1_ls : 4, - n2_hs : 10, - n2_ls : 260, - n31 : 52, - n32 : 52, - bwsel : 4, - crystal_ref: false - } + ( + si5324::FrequencySettings { + n1_hs : 10, + nc1_ls : 4, + n2_hs : 10, + n2_ls : 260, + n31 : 52, + n32 : 52, + bwsel : 4, + crystal_ref: false + }, + SI5324_EXT_INPUT + ) }, RtioClock::Ext0_Synth0_125to125 => { // 125MHz output, from 125MHz CLKINx reference, 606 Hz loop bandwidth info!("using 125MHz reference to make 125MHz RTIO clock with PLL"); - si5324::FrequencySettings { - n1_hs : 5, - nc1_ls : 8, - n2_hs : 7, - n2_ls : 360, - n31 : 63, - n32 : 63, - bwsel : 4, - crystal_ref: false - } + ( + si5324::FrequencySettings { + n1_hs : 5, + nc1_ls : 8, + n2_hs : 7, + n2_ls : 360, + n31 : 63, + n32 : 63, + bwsel : 4, + crystal_ref: false + }, + SI5324_EXT_INPUT + ) }, RtioClock::Int_150 => { // 150MHz output, from crystal info!("using internal 150MHz RTIO clock"); - si5324::FrequencySettings { - n1_hs : 9, - nc1_ls : 4, - n2_hs : 10, - n2_ls : 33732, - n31 : 7139, - n32 : 7139, - bwsel : 3, - crystal_ref: true - } + ( + si5324::FrequencySettings { + n1_hs : 9, + nc1_ls : 4, + n2_hs : 10, + n2_ls : 33732, + n31 : 7139, + n32 : 7139, + bwsel : 3, + crystal_ref: true + }, + si5324::Input::Ckin2 + ) }, - RtioClock::Int_100 => { // 100MHz output, from crystal. Also used as reference for Sayma HMC830. + RtioClock::Int_100 => { // 100MHz output, from crystal info!("using internal 100MHz RTIO clock"); - si5324::FrequencySettings { - n1_hs : 9, - nc1_ls : 6, - n2_hs : 10, - n2_ls : 33732, - n31 : 7139, - n32 : 7139, - bwsel : 3, - crystal_ref: true - } + ( + si5324::FrequencySettings { + n1_hs : 9, + nc1_ls : 6, + n2_hs : 10, + n2_ls : 33732, + n31 : 7139, + n32 : 7139, + bwsel : 3, + crystal_ref: true + }, + si5324::Input::Ckin2 + ) }, RtioClock::Int_125 => { // 125MHz output, from crystal, 7 Hz info!("using internal 125MHz RTIO clock"); - si5324::FrequencySettings { - n1_hs : 10, - nc1_ls : 4, - n2_hs : 10, - n2_ls : 19972, - n31 : 4565, - n32 : 4565, - bwsel : 4, - crystal_ref: true - } - } + ( + si5324::FrequencySettings { + n1_hs : 10, + nc1_ls : 4, + n2_hs : 10, + n2_ls : 19972, + n31 : 4565, + n32 : 4565, + bwsel : 4, + crystal_ref: true + }, + si5324::Input::Ckin2 + ) + }, _ => { // 125MHz output like above, default (if chosen option is not supported) warn!("rtio_clock setting '{:?}' is not supported. Falling back to default internal 125MHz RTIO clock.", cfg); - si5324::FrequencySettings { - n1_hs : 10, - nc1_ls : 4, - n2_hs : 10, - n2_ls : 19972, - n31 : 4565, - n32 : 4565, - bwsel : 4, - crystal_ref: true - } + ( + si5324::FrequencySettings { + n1_hs : 10, + nc1_ls : 4, + n2_hs : 10, + n2_ls : 19972, + n31 : 4565, + n32 : 4565, + bwsel : 4, + crystal_ref: true + }, + si5324::Input::Ckin2 + ) } }; - si5324::setup(&si5324_settings, SI5324_EXT_INPUT).expect("cannot initialize Si5324"); + si5324::setup(&si5324_settings, si5324_ref_input).expect("cannot initialize Si5324"); } pub fn init() { From 1e0102379ba7001c329ef36f0e2af125e3a9fc70 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 17 Dec 2022 02:09:20 +0000 Subject: [PATCH 38/85] firmware: Rename si5324 crystal_{ref -> as_ckin2} [nfc] This would have made the issue in the pre-740543d4e code much more obvious (the config option by itself does not have any effect on the choice of active reference input). --- artiq/firmware/libboard_artiq/si5324.rs | 6 +++--- artiq/firmware/runtime/rtio_clocking.rs | 14 +++++++------- artiq/firmware/satman/main.rs | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index 22b452d54..ee3feb1a1 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -28,7 +28,7 @@ pub struct FrequencySettings { pub n31: u32, pub n32: u32, pub bwsel: u8, - pub crystal_ref: bool + pub crystal_as_ckin2: bool } pub enum Input { @@ -83,7 +83,7 @@ fn map_frequency_settings(settings: &FrequencySettings) -> Result Result<()> { }; init()?; - if settings.crystal_ref { + if settings.crystal_as_ckin2 { write(0, read(0)? | 0x40)?; // FREE_RUN=1 } write(2, (read(2)? & 0x0f) | (s.bwsel << 4))?; diff --git a/artiq/firmware/runtime/rtio_clocking.rs b/artiq/firmware/runtime/rtio_clocking.rs index da4d8ad92..ffe1de082 100644 --- a/artiq/firmware/runtime/rtio_clocking.rs +++ b/artiq/firmware/runtime/rtio_clocking.rs @@ -142,7 +142,7 @@ fn setup_si5324_as_synthesizer(cfg: RtioClock) { n31 : 6, n32 : 6, bwsel : 4, - crystal_ref: false + crystal_as_ckin2: false }, SI5324_EXT_INPUT ) @@ -158,7 +158,7 @@ fn setup_si5324_as_synthesizer(cfg: RtioClock) { n31 : 52, n32 : 52, bwsel : 4, - crystal_ref: false + crystal_as_ckin2: false }, SI5324_EXT_INPUT ) @@ -174,7 +174,7 @@ fn setup_si5324_as_synthesizer(cfg: RtioClock) { n31 : 63, n32 : 63, bwsel : 4, - crystal_ref: false + crystal_as_ckin2: false }, SI5324_EXT_INPUT ) @@ -190,7 +190,7 @@ fn setup_si5324_as_synthesizer(cfg: RtioClock) { n31 : 7139, n32 : 7139, bwsel : 3, - crystal_ref: true + crystal_as_ckin2: true }, si5324::Input::Ckin2 ) @@ -206,7 +206,7 @@ fn setup_si5324_as_synthesizer(cfg: RtioClock) { n31 : 7139, n32 : 7139, bwsel : 3, - crystal_ref: true + crystal_as_ckin2: true }, si5324::Input::Ckin2 ) @@ -222,7 +222,7 @@ fn setup_si5324_as_synthesizer(cfg: RtioClock) { n31 : 4565, n32 : 4565, bwsel : 4, - crystal_ref: true + crystal_as_ckin2: true }, si5324::Input::Ckin2 ) @@ -238,7 +238,7 @@ fn setup_si5324_as_synthesizer(cfg: RtioClock) { n31 : 4565, n32 : 4565, bwsel : 4, - crystal_ref: true + crystal_as_ckin2: true }, si5324::Input::Ckin2 ) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 7dde13f3f..72510d19c 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -436,7 +436,7 @@ const SI5324_SETTINGS: si5324::FrequencySettings n31 : 75, n32 : 75, bwsel : 4, - crystal_ref: true + crystal_as_ckin2: true }; #[cfg(all(has_si5324, rtio_frequency = "125.0"))] @@ -449,7 +449,7 @@ const SI5324_SETTINGS: si5324::FrequencySettings n31 : 63, n32 : 63, bwsel : 4, - crystal_ref: true + crystal_as_ckin2: true }; #[cfg(all(has_si5324, rtio_frequency = "100.0"))] @@ -462,7 +462,7 @@ const SI5324_SETTINGS: si5324::FrequencySettings n31 : 50, n32 : 50, bwsel : 4, - crystal_ref: true + crystal_as_ckin2: true }; #[no_mangle] From 17efc28dbe8664cb0dd7f2f767ef3ae8636b0c7e Mon Sep 17 00:00:00 2001 From: Spaqin Date: Sat, 17 Dec 2022 15:39:54 +0800 Subject: [PATCH 39/85] DRTIO: RTIO/SYS clock merge --- artiq/firmware/runtime/rtio_clocking.rs | 51 +++++++----- artiq/firmware/satman/main.rs | 34 ++++++-- artiq/gateware/drtio/aux_controller.py | 31 +++---- artiq/gateware/drtio/core.py | 19 ++--- artiq/gateware/drtio/link_layer.py | 24 ++---- artiq/gateware/drtio/rt_controller_master.py | 2 +- .../gateware/drtio/rt_controller_repeater.py | 12 +-- artiq/gateware/drtio/rt_packet_master.py | 55 +++++-------- artiq/gateware/drtio/rt_packet_repeater.py | 28 +++---- artiq/gateware/drtio/rx_synchronizer.py | 4 +- artiq/gateware/drtio/siphaser.py | 19 ++--- .../drtio/transceiver/clock_aligner.py | 6 +- .../gateware/drtio/transceiver/gtp_7series.py | 38 +++------ artiq/gateware/drtio/wrpll/core.py | 2 +- artiq/gateware/rtio/phy/phaser.py | 4 +- artiq/gateware/targets/kasli.py | 82 ++++++++++++------- .../test/drtio/test_aux_controller.py | 2 +- artiq/gateware/test/drtio/test_full_stack.py | 8 +- .../test/drtio/test_rt_packet_repeater.py | 2 +- artiq/gateware/test/drtio/test_switching.py | 6 +- 20 files changed, 210 insertions(+), 219 deletions(-) diff --git a/artiq/firmware/runtime/rtio_clocking.rs b/artiq/firmware/runtime/rtio_clocking.rs index 8c44cca4f..6af4ea3e9 100644 --- a/artiq/firmware/runtime/rtio_clocking.rs +++ b/artiq/firmware/runtime/rtio_clocking.rs @@ -1,10 +1,7 @@ use board_misoc::config; #[cfg(si5324_as_synthesizer)] use board_artiq::si5324; -#[cfg(any(soc_platform = "kasli", has_drtio))] -use board_misoc::csr; -#[cfg(has_drtio)] -use board_misoc::clock; +use board_misoc::{csr, clock}; #[derive(Debug, PartialEq)] #[allow(non_camel_case_types)] @@ -212,15 +209,12 @@ fn setup_si5324_as_synthesizer(cfg: RtioClock) { #[cfg(si5324_as_synthesizer)] fn setup_si5324(clock_cfg: RtioClock) { - #[cfg(soc_platform = "kasli")] - { - let switched = unsafe { - csr::crg::switch_done_read() - }; - if switched == 1 { - info!("Clocking has already been set up."); - return; - } + let switched = unsafe { + csr::crg::switch_done_read() + }; + if switched == 1 { + info!("Clocking has already been set up."); + return; } #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] let si5324_ext_input = si5324::Input::Ckin1; @@ -239,12 +233,14 @@ fn setup_si5324(clock_cfg: RtioClock) { } // switch sysclk source to si5324 - #[cfg(soc_platform = "kasli")] + #[cfg(not(has_drtio))] { - // excessive dots will be cut off by the reboot - info!("Switching sys clock, rebooting.................."); + info!("Switching sys clock, rebooting..."); + // delay for clean UART log, wait until UART FIFO is empty + clock::spin_us(1300); unsafe { csr::crg::clock_sel_write(1); + loop {} } } } @@ -257,15 +253,28 @@ pub fn init() { #[cfg(has_drtio)] { - unsafe { - csr::drtio_transceiver::stable_clkin_write(1); + let switched = unsafe { + csr::crg::switch_done_read() + }; + if switched == 0 { + info!("Switching sys clock, rebooting..."); + clock::spin_us(500); // delay for clean UART log + unsafe { + // clock switch and reboot will begin after TX is initialized + // and TX will be initialized after this + csr::drtio_transceiver::stable_clkin_write(1); + } + loop {} } - clock::spin_us(1500); // wait for CPLL/QPLL lock - unsafe { - csr::drtio_transceiver::txenable_write(0xffffffffu32 as _); + else { + // enable TX after the reboot, with stable clock + unsafe { + csr::drtio_transceiver::txenable_write(0xffffffffu32 as _); + } } } + #[cfg(has_rtio_crg)] { #[cfg(has_rtio_clock_switch)] diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 10beb6695..7ac232827 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -465,6 +465,30 @@ const SI5324_SETTINGS: si5324::FrequencySettings crystal_ref: true }; +fn sysclk_setup() { + let switched = unsafe { + csr::crg::switch_done_read() + }; + if switched == 1 { + info!("Clocking has already been set up."); + return; + } + else { + #[cfg(has_si5324)] + si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324"); + #[cfg(has_wrpll)] + wrpll::init(); + info!("Switching sys clock, rebooting..."); + // delay for clean UART log, wait until UART FIFO is empty + clock::spin_us(1300); + unsafe { + csr::drtio_transceiver::stable_clkin_write(1); + } + loop {} + } +} + + #[no_mangle] pub extern fn main() -> i32 { extern { @@ -517,21 +541,15 @@ pub extern fn main() -> i32 { io_expander1.service().unwrap(); } - #[cfg(has_si5324)] - si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324"); - #[cfg(has_wrpll)] - wrpll::init(); + sysclk_setup(); - unsafe { - csr::drtio_transceiver::stable_clkin_write(1); - } - clock::spin_us(1500); // wait for CPLL/QPLL lock #[cfg(not(has_jdcg))] unsafe { csr::drtio_transceiver::txenable_write(0xffffffffu32 as _); } #[cfg(has_wrpll)] wrpll::diagnostics(); + init_rtio_crg(); #[cfg(has_hmc830_7043)] diff --git a/artiq/gateware/drtio/aux_controller.py b/artiq/gateware/drtio/aux_controller.py index 051a03a20..5f91b1f45 100644 --- a/artiq/gateware/drtio/aux_controller.py +++ b/artiq/gateware/drtio/aux_controller.py @@ -22,8 +22,7 @@ class Transmitter(Module, AutoCSR): self.aux_tx = CSR() self.specials.mem = Memory(mem_dw, max_packet//(mem_dw//8)) - converter = ClockDomainsRenamer("rtio")( - stream.Converter(mem_dw, ll_dw)) + converter = stream.Converter(mem_dw, ll_dw) self.submodules += converter # when continuously fed, the Converter outputs data continuously @@ -36,7 +35,7 @@ class Transmitter(Module, AutoCSR): seen_eop_rst = Signal() frame_r = Signal() seen_eop = Signal() - self.sync.rtio += [ + self.sync += [ If(link_layer.tx_aux_ack, frame_r.eq(link_layer.tx_aux_frame), If(frame_r & ~link_layer.tx_aux_frame, seen_eop.eq(1)) @@ -44,13 +43,9 @@ class Transmitter(Module, AutoCSR): If(seen_eop_rst, seen_eop.eq(0)) ] - mem_port = self.mem.get_port(clock_domain="rtio") + mem_port = self.mem.get_port() self.specials += mem_port - self.aux_tx_length.storage.attr.add("no_retiming") - tx_length = Signal(bits_for(max_packet)) - self.specials += MultiReg(self.aux_tx_length.storage, tx_length, "rtio") - frame_counter_nbits = bits_for(max_packet) - log2_int(mem_dw//8) frame_counter = Signal(frame_counter_nbits) frame_counter_next = Signal(frame_counter_nbits) @@ -66,35 +61,33 @@ class Transmitter(Module, AutoCSR): mem_port.adr.eq(frame_counter_next), converter.sink.data.eq(mem_port.dat_r) ] - self.sync.rtio += frame_counter.eq(frame_counter_next) - start_tx = PulseSynchronizer("sys", "rtio") - tx_done = PulseSynchronizer("rtio", "sys") - self.submodules += start_tx, tx_done - self.comb += start_tx.i.eq(self.aux_tx.re) + tx_done = Signal() self.sync += [ - If(tx_done.o, self.aux_tx.w.eq(0)), - If(self.aux_tx.re, self.aux_tx.w.eq(1)) + frame_counter.eq(frame_counter_next), + If(self.aux_tx.re, self.aux_tx.w.eq(1)), + If(tx_done, self.aux_tx.w.eq(0)) ] - fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE")) + fsm = FSM(reset_state="IDLE") self.submodules += fsm fsm.act("IDLE", frame_counter_rst.eq(1), seen_eop_rst.eq(1), - If(start_tx.o, NextState("TRANSMIT")) + If(self.aux_tx.re, NextState("TRANSMIT")) ) fsm.act("TRANSMIT", converter.sink.stb.eq(1), If(converter.sink.ack, frame_counter_ce.eq(1) ), - If(frame_counter_next == tx_length, NextState("WAIT_INTERFRAME")) + If(frame_counter_next == self.aux_tx_length.storage, + NextState("WAIT_INTERFRAME")) ) fsm.act("WAIT_INTERFRAME", If(seen_eop, - tx_done.i.eq(1), + tx_done.eq(1), NextState("IDLE") ) ) diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index 6311456e4..e8ca07e3f 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -2,7 +2,6 @@ from types import SimpleNamespace from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer -from migen.genlib.cdc import PulseSynchronizer from misoc.interconnect.csr import * from artiq.gateware.rtio import cri, rtlink @@ -31,7 +30,6 @@ class TransceiverInterface(AutoCSR): def __init__(self, channel_interfaces): self.stable_clkin = CSRStorage() self.txenable = CSRStorage(len(channel_interfaces)) - self.clock_domains.cd_rtio = ClockDomain() for i in range(len(channel_interfaces)): name = "rtio_rx" + str(i) setattr(self.clock_domains, "cd_"+name, ClockDomain(name=name)) @@ -65,7 +63,7 @@ class SyncRTIO(Module): enable_spread=False, report_buffer_space=True, interface=self.cri)) self.comb += self.outputs.coarse_timestamp.eq(tsc.coarse_ts) - self.sync.rtio += self.outputs.minimum_coarse_timestamp.eq(tsc.coarse_ts + 16) + self.sync += self.outputs.minimum_coarse_timestamp.eq(tsc.coarse_ts + 16) self.submodules.inputs = ClockDomainsRenamer("rio")( InputCollector(tsc, channels, "sync", interface=self.cri)) @@ -86,8 +84,8 @@ class DRTIOSatellite(Module): self.clock_domains.cd_rio = ClockDomain() self.clock_domains.cd_rio_phy = ClockDomain() self.comb += [ - self.cd_rio.clk.eq(ClockSignal("rtio")), - self.cd_rio_phy.clk.eq(ClockSignal("rtio")) + self.cd_rio.clk.eq(ClockSignal("sys")), + self.cd_rio_phy.clk.eq(ClockSignal("sys")) ] reset = Signal() reset_phy = Signal() @@ -125,9 +123,9 @@ class DRTIOSatellite(Module): rx_rt_frame_perm=rx_synchronizer.resync(self.link_layer.rx_rt_frame_perm), rx_rt_data=rx_synchronizer.resync(self.link_layer.rx_rt_data) ) - self.submodules.link_stats = link_layer.LinkLayerStats(link_layer_sync, "rtio") - self.submodules.rt_packet = ClockDomainsRenamer("rtio")( - rt_packet_satellite.RTPacketSatellite(link_layer_sync, interface=self.cri)) + self.submodules.link_stats = link_layer.LinkLayerStats(link_layer_sync, "sys") + self.submodules.rt_packet = rt_packet_satellite.RTPacketSatellite( + link_layer_sync, interface=self.cri) self.comb += self.rt_packet.reset.eq(self.cd_rio.rst) self.comb += [ @@ -135,12 +133,9 @@ class DRTIOSatellite(Module): tsc.load_value.eq(self.rt_packet.tsc_load_value) ] - ps_tsc_load = PulseSynchronizer("rtio", "sys") - self.submodules += ps_tsc_load - self.comb += ps_tsc_load.i.eq(self.rt_packet.tsc_load) self.sync += [ If(self.tsc_loaded.re, self.tsc_loaded.w.eq(0)), - If(ps_tsc_load.o, self.tsc_loaded.w.eq(1)) + If(self.rt_packet.tsc_load, self.tsc_loaded.w.eq(1)) ] self.submodules.rt_errors = rt_errors_satellite.RTErrorsSatellite( diff --git a/artiq/gateware/drtio/link_layer.py b/artiq/gateware/drtio/link_layer.py index a4779e912..367830067 100644 --- a/artiq/gateware/drtio/link_layer.py +++ b/artiq/gateware/drtio/link_layer.py @@ -232,7 +232,7 @@ class LinkLayer(Module, AutoCSR): # receiver locked, comma aligned, receiving valid 8b10b symbols self.rx_ready = Signal() - tx = ClockDomainsRenamer("rtio")(LinkLayerTX(encoder)) + tx = LinkLayerTX(encoder) rx = ClockDomainsRenamer("rtio_rx")(LinkLayerRX(decoders)) self.submodules += tx, rx @@ -256,31 +256,23 @@ class LinkLayer(Module, AutoCSR): rx_up = Signal() rx_up_r = Signal() - self.sync.rtio += rx_up_r.eq(rx_up) + self.sync += rx_up_r.eq(rx_up) rx_up_rx = Signal() rx_up_r.attr.add("no_retiming") self.specials += [ MultiReg(rx_up_r, rx_up_rx, "rtio_rx"), MultiReg(rx_up_r, self.rx_up.status)] - tx_force_aux_zero_rtio = Signal() - tx_force_rt_zero_rtio = Signal() - self.tx_force_aux_zero.storage.attr.add("no_retiming") - self.tx_force_rt_zero.storage.attr.add("no_retiming") - self.specials += [ - MultiReg(self.tx_force_aux_zero.storage, tx_force_aux_zero_rtio, "rtio"), - MultiReg(self.tx_force_rt_zero.storage, tx_force_rt_zero_rtio, "rtio")] - rx_disable_rx = Signal() self.rx_disable.storage.attr.add("no_retiming") self.specials += MultiReg(self.rx_disable.storage, rx_disable_rx, "rtio_rx") self.comb += [ - tx.aux_frame.eq(self.tx_aux_frame | tx_force_aux_zero_rtio), - tx.aux_data.eq(Mux(tx_force_aux_zero_rtio, 0, self.tx_aux_data)), + tx.aux_frame.eq(self.tx_aux_frame | self.tx_force_aux_zero.storage), + tx.aux_data.eq(Mux(self.tx_force_aux_zero.storage, 0, self.tx_aux_data)), self.tx_aux_ack.eq(tx.aux_ack), - tx.rt_frame.eq(self.tx_rt_frame | tx_force_rt_zero_rtio), - tx.rt_data.eq(Mux(tx_force_rt_zero_rtio, 0, self.tx_rt_data)) + tx.rt_frame.eq(self.tx_rt_frame | self.tx_force_rt_zero.storage), + tx.rt_data.eq(Mux(self.tx_force_rt_zero.storage, 0, self.tx_rt_data)) ] # we register those to improve timing margins, as the data may need # to be recaptured by RXSynchronizer. @@ -294,10 +286,10 @@ class LinkLayer(Module, AutoCSR): self.rx_rt_data.eq(rx.rt_data) ] - wait_scrambler = ClockDomainsRenamer("rtio")(WaitTimer(15)) + wait_scrambler = WaitTimer(15) self.submodules += wait_scrambler - fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="WAIT_RX_READY")) + fsm = FSM(reset_state="WAIT_RX_READY") self.submodules += fsm fsm.act("WAIT_RX_READY", diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index fdd340be8..3ed22dbe7 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -108,7 +108,7 @@ class RTController(Module): cond_underflow = Signal() self.comb += cond_underflow.eq((self.cri.o_timestamp[tsc.glbl_fine_ts_width:] - - self.csrs.underflow_margin.storage[tsc.glbl_fine_ts_width:]) < tsc.coarse_ts_sys) + - self.csrs.underflow_margin.storage[tsc.glbl_fine_ts_width:]) < tsc.coarse_ts) # buffer space buffer_space = Memory(16, 256) diff --git a/artiq/gateware/drtio/rt_controller_repeater.py b/artiq/gateware/drtio/rt_controller_repeater.py index 0fe10d1de..53b2b1b07 100644 --- a/artiq/gateware/drtio/rt_controller_repeater.py +++ b/artiq/gateware/drtio/rt_controller_repeater.py @@ -15,15 +15,11 @@ class RTController(Module, AutoCSR): self.command_missed_chan_sel = CSRStatus(24) self.buffer_space_timeout_dest = CSRStatus(8) - self.specials += MultiReg(self.reset.storage, rt_packet.reset, "rtio") + self.sync += rt_packet.reset.eq(self.reset.storage) set_time_stb = Signal() - set_time_ack = Signal() - self.submodules += CrossDomainRequest("rtio", - set_time_stb, set_time_ack, None, - rt_packet.set_time_stb, rt_packet.set_time_ack, None) self.sync += [ - If(set_time_ack, set_time_stb.eq(0)), + If(rt_packet.set_time_stb, set_time_stb.eq(0)), If(self.set_time.re, set_time_stb.eq(1)) ] self.comb += self.set_time.w.eq(set_time_stb) @@ -31,10 +27,10 @@ class RTController(Module, AutoCSR): errors = [ (rt_packet.err_unknown_packet_type, "rtio_rx", None, None), (rt_packet.err_packet_truncated, "rtio_rx", None, None), - (rt_packet.err_command_missed, "rtio", + (rt_packet.err_command_missed, "sys", Cat(rt_packet.command_missed_cmd, rt_packet.command_missed_chan_sel), Cat(self.command_missed_cmd.status, self.command_missed_chan_sel.status)), - (rt_packet.err_buffer_space_timeout, "rtio", + (rt_packet.err_buffer_space_timeout, "sys", rt_packet.buffer_space_destination, self.buffer_space_timeout_dest.status) ] diff --git a/artiq/gateware/drtio/rt_packet_master.py b/artiq/gateware/drtio/rt_packet_master.py index 4fd26f85d..70d44ecaf 100644 --- a/artiq/gateware/drtio/rt_packet_master.py +++ b/artiq/gateware/drtio/rt_packet_master.py @@ -2,7 +2,7 @@ from migen import * from migen.genlib.fsm import * -from migen.genlib.fifo import AsyncFIFO +from migen.genlib.fifo import SyncFIFO from migen.genlib.cdc import BlindTransfer from artiq.gateware.rtio.cdc import GrayCodeTransfer @@ -76,8 +76,8 @@ class RTPacketMaster(Module): assert len(link_layer.tx_rt_data) % 8 == 0 ws = len(link_layer.tx_rt_data) tx_plm = get_m2s_layouts(ws) - tx_dp = ClockDomainsRenamer("rtio")(TransmitDatapath( - link_layer.tx_rt_frame, link_layer.tx_rt_data, tx_plm)) + tx_dp = TransmitDatapath( + link_layer.tx_rt_frame, link_layer.tx_rt_data, tx_plm) self.submodules += tx_dp rx_plm = get_s2m_layouts(ws) rx_dp = ClockDomainsRenamer("rtio_rx")(ReceiveDatapath( @@ -85,8 +85,7 @@ class RTPacketMaster(Module): self.submodules += rx_dp # Write FIFO and extra data count - sr_fifo = ClockDomainsRenamer({"write": "sys", "read": "rtio"})( - AsyncFIFO(1+64+24+8+512, sr_fifo_depth)) + sr_fifo = SyncFIFO(1+64+24+8+512, sr_fifo_depth) self.submodules += sr_fifo sr_notwrite_d = Signal() sr_timestamp_d = Signal(64) @@ -106,7 +105,7 @@ class RTPacketMaster(Module): sr_buf_re = Signal() self.comb += sr_fifo.re.eq(sr_fifo.readable & (~sr_buf_readable | sr_buf_re)) - self.sync.rtio += \ + self.sync += \ If(sr_fifo.re, sr_buf_readable.eq(1), ).Elif(sr_buf_re, @@ -120,7 +119,7 @@ class RTPacketMaster(Module): sr_extra_data_cnt = Signal(8) sr_data = Signal(512) - self.sync.rtio += If(sr_fifo.re, + self.sync += If(sr_fifo.re, sr_notwrite.eq(sr_notwrite_d), sr_timestamp.eq(sr_timestamp_d), sr_chan_sel.eq(sr_chan_sel_d), @@ -131,11 +130,11 @@ class RTPacketMaster(Module): sr_extra_data_d = Signal(512) self.comb += sr_extra_data_d.eq(sr_data_d[short_data_len:]) for i in range(512//ws): - self.sync.rtio += If(sr_fifo.re, + self.sync += If(sr_fifo.re, If(sr_extra_data_d[ws*i:ws*(i+1)] != 0, sr_extra_data_cnt.eq(i+1))) sr_extra_data = Signal(512) - self.sync.rtio += If(sr_fifo.re, sr_extra_data.eq(sr_extra_data_d)) + self.sync += If(sr_fifo.re, sr_extra_data.eq(sr_extra_data_d)) extra_data_ce = Signal() extra_data_last = Signal() @@ -146,7 +145,7 @@ class RTPacketMaster(Module): for i in range(512//ws)}), extra_data_last.eq(extra_data_counter == sr_extra_data_cnt) ] - self.sync.rtio += \ + self.sync += \ If(extra_data_ce, extra_data_counter.eq(extra_data_counter + 1), ).Else( @@ -160,18 +159,6 @@ class RTPacketMaster(Module): buffer_space_not, buffer_space, self.buffer_space_not, self.buffer_space_not_ack, self.buffer_space) - set_time_stb = Signal() - set_time_ack = Signal() - self.submodules += CrossDomainRequest("rtio", - self.set_time_stb, self.set_time_ack, None, - set_time_stb, set_time_ack, None) - - echo_stb = Signal() - echo_ack = Signal() - self.submodules += CrossDomainRequest("rtio", - self.echo_stb, self.echo_ack, None, - echo_stb, echo_ack, None) - read_not = Signal() read_no_event = Signal() read_is_overflow = Signal() @@ -199,14 +186,14 @@ class RTPacketMaster(Module): ] # TX FSM - tx_fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE")) + tx_fsm = FSM(reset_state="IDLE") self.submodules += tx_fsm echo_sent_now = Signal() - self.sync.rtio += self.echo_sent_now.eq(echo_sent_now) + self.sync += self.echo_sent_now.eq(echo_sent_now) tsc_value = Signal(64) tsc_value_load = Signal() - self.sync.rtio += If(tsc_value_load, tsc_value.eq(self.tsc_value)) + self.sync += If(tsc_value_load, tsc_value.eq(self.tsc_value)) tx_fsm.act("IDLE", # Ensure 2 cycles between frames on the link. @@ -223,10 +210,10 @@ class RTPacketMaster(Module): NextState("WRITE") ) ).Else( - If(echo_stb, + If(self.echo_stb, echo_sent_now.eq(1), NextState("ECHO") - ).Elif(set_time_stb, + ).Elif(self.set_time_stb, tsc_value_load.eq(1), NextState("SET_TIME") ) @@ -273,14 +260,14 @@ class RTPacketMaster(Module): tx_fsm.act("ECHO", tx_dp.send("echo_request"), If(tx_dp.packet_last, - echo_ack.eq(1), + self.echo_ack.eq(1), NextState("IDLE") ) ) tx_fsm.act("SET_TIME", tx_dp.send("set_time", timestamp=tsc_value), If(tx_dp.packet_last, - set_time_ack.eq(1), + self.set_time_ack.eq(1), NextState("IDLE") ) ) @@ -334,16 +321,14 @@ class RTPacketMaster(Module): # packet counters tx_frame_r = Signal() packet_cnt_tx = Signal(32) - self.sync.rtio += [ + self.sync += [ tx_frame_r.eq(link_layer.tx_rt_frame), If(link_layer.tx_rt_frame & ~tx_frame_r, packet_cnt_tx.eq(packet_cnt_tx + 1)) ] - cdc_packet_cnt_tx = GrayCodeTransfer(32) - self.submodules += cdc_packet_cnt_tx + self.comb += [ - cdc_packet_cnt_tx.i.eq(packet_cnt_tx), - self.packet_cnt_tx.eq(cdc_packet_cnt_tx.o) + self.packet_cnt_tx.eq(packet_cnt_tx) ] rx_frame_r = Signal() @@ -353,7 +338,7 @@ class RTPacketMaster(Module): If(link_layer.rx_rt_frame & ~rx_frame_r, packet_cnt_rx.eq(packet_cnt_rx + 1)) ] - cdc_packet_cnt_rx = ClockDomainsRenamer({"rtio": "rtio_rx"})( + cdc_packet_cnt_rx = ClockDomainsRenamer({"rtio": "sys", "sys": "rtio_rx"})( GrayCodeTransfer(32)) self.submodules += cdc_packet_cnt_rx self.comb += [ diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 9374d1a18..728c24ae8 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -38,8 +38,8 @@ class RTPacketRepeater(Module): assert len(link_layer.tx_rt_data) % 8 == 0 ws = len(link_layer.tx_rt_data) tx_plm = get_m2s_layouts(ws) - tx_dp = ClockDomainsRenamer("rtio")(TransmitDatapath( - link_layer.tx_rt_frame, link_layer.tx_rt_data, tx_plm)) + tx_dp = TransmitDatapath( + link_layer.tx_rt_frame, link_layer.tx_rt_data, tx_plm) self.submodules += tx_dp rx_plm = get_s2m_layouts(ws) rx_dp = ClockDomainsRenamer("rtio_rx")(ReceiveDatapath( @@ -49,7 +49,7 @@ class RTPacketRepeater(Module): # TSC sync tsc_value = Signal(64) tsc_value_load = Signal() - self.sync.rtio += If(tsc_value_load, tsc_value.eq(tsc.coarse_ts)) + self.sync += If(tsc_value_load, tsc_value.eq(tsc.coarse_ts)) # CRI buffer stage 1 cb0_loaded = Signal() @@ -60,7 +60,7 @@ class RTPacketRepeater(Module): cb0_chan_sel = Signal(24) cb0_o_address = Signal(8) cb0_o_data = Signal(512) - self.sync.rtio += [ + self.sync += [ If(self.reset | cb0_ack, cb0_loaded.eq(0), cb0_cmd.eq(cri.commands["nop"]) @@ -91,7 +91,7 @@ class RTPacketRepeater(Module): cb_chan_sel = Signal(24) cb_o_address = Signal(8) cb_o_data = Signal(512) - self.sync.rtio += [ + self.sync += [ If(self.reset | cb_ack, cb_loaded.eq(0), cb_cmd.eq(cri.commands["nop"]) @@ -112,11 +112,11 @@ class RTPacketRepeater(Module): wb_extra_data_a = Signal(512) self.comb += wb_extra_data_a.eq(self.cri.o_data[short_data_len:]) for i in range(512//ws): - self.sync.rtio += If(self.cri.cmd == cri.commands["write"], + self.sync += If(self.cri.cmd == cri.commands["write"], If(wb_extra_data_a[ws*i:ws*(i+1)] != 0, wb_extra_data_cnt.eq(i+1))) wb_extra_data = Signal(512) - self.sync.rtio += If(self.cri.cmd == cri.commands["write"], + self.sync += If(self.cri.cmd == cri.commands["write"], wb_extra_data.eq(wb_extra_data_a)) extra_data_ce = Signal() @@ -128,7 +128,7 @@ class RTPacketRepeater(Module): for i in range(512//ws)}), extra_data_last.eq(extra_data_counter == wb_extra_data_cnt) ] - self.sync.rtio += \ + self.sync += \ If(extra_data_ce, extra_data_counter.eq(extra_data_counter + 1), ).Else( @@ -136,19 +136,19 @@ class RTPacketRepeater(Module): ) # Buffer space - self.sync.rtio += If(self.cri.cmd == cri.commands["get_buffer_space"], + self.sync += If(self.cri.cmd == cri.commands["get_buffer_space"], self.buffer_space_destination.eq(self.cri.chan_sel[16:])) rx_buffer_space_not = Signal() rx_buffer_space = Signal(16) buffer_space_not = Signal() buffer_space_not_ack = Signal() - self.submodules += CrossDomainNotification("rtio_rx", "rtio", + self.submodules += CrossDomainNotification("rtio_rx", "sys", rx_buffer_space_not, rx_buffer_space, buffer_space_not, buffer_space_not_ack, self.cri.o_buffer_space) - timeout_counter = ClockDomainsRenamer("rtio")(WaitTimer(8191)) + timeout_counter = WaitTimer(8191) self.submodules += timeout_counter # Read @@ -163,7 +163,7 @@ class RTPacketRepeater(Module): rtio_read_is_overflow = Signal() rtio_read_data = Signal(32) rtio_read_timestamp = Signal(64) - self.submodules += CrossDomainNotification("rtio_rx", "rtio", + self.submodules += CrossDomainNotification("rtio_rx", "sys", read_not, Cat(read_no_event, read_is_overflow, read_data, read_timestamp), @@ -183,7 +183,7 @@ class RTPacketRepeater(Module): i_status_wait_event, i_status_overflow, cb0_loaded | cb_loaded)) load_read_reply = Signal() - self.sync.rtio += [ + self.sync += [ If(load_read_reply, i_status_wait_event.eq(0), i_status_overflow.eq(0), @@ -200,7 +200,7 @@ class RTPacketRepeater(Module): ] # TX and CRI FSM - tx_fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE")) + tx_fsm = FSM(reset_state="IDLE") self.submodules += tx_fsm tx_fsm.act("IDLE", diff --git a/artiq/gateware/drtio/rx_synchronizer.py b/artiq/gateware/drtio/rx_synchronizer.py index 90fddb97c..055d1d70b 100644 --- a/artiq/gateware/drtio/rx_synchronizer.py +++ b/artiq/gateware/drtio/rx_synchronizer.py @@ -17,7 +17,7 @@ class GenericRXSynchronizer(Module): return synchronized def do_finalize(self): - eb = ElasticBuffer(sum(len(s[0]) for s in self.signals), 4, "rtio_rx", "rtio") + eb = ElasticBuffer(sum(len(s[0]) for s in self.signals), 4, "rtio_rx", "sys") self.submodules += eb self.comb += [ eb.din.eq(Cat(*[s[0] for s in self.signals])), @@ -57,6 +57,6 @@ class XilinxRXSynchronizer(Module): self.specials += [ Instance("FD", i_C=ClockSignal("rtio_rx"), i_D=din[i], o_Q=inter[i], attr={hu_set, ("RLOC", "X0Y{}".format(i))}), - Instance("FD", i_C=ClockSignal("rtio"), i_D=inter[i], o_Q=dout[i], + Instance("FD", i_C=ClockSignal("sys"), i_D=inter[i], o_Q=dout[i], attr={hu_set, ("RLOC", "X1Y{}".format(i))}) ] diff --git a/artiq/gateware/drtio/siphaser.py b/artiq/gateware/drtio/siphaser.py index 5237b7453..c4054c127 100644 --- a/artiq/gateware/drtio/siphaser.py +++ b/artiq/gateware/drtio/siphaser.py @@ -1,23 +1,23 @@ from migen import * -from migen.genlib.cdc import MultiReg, PulseSynchronizer +from migen.genlib.cdc import MultiReg from misoc.interconnect.csr import * -# This code assumes 125/62.5MHz reference clock and 100MHz, 125MHz or 150MHz RTIO +# This code assumes 125/62.5MHz reference clock and 100MHz or 125MHz RTIO # frequency. class SiPhaser7Series(Module, AutoCSR): def __init__(self, si5324_clkin, rx_synchronizer, - ref_clk=None, ref_div2=False, ultrascale=False, rtio_clk_freq=150e6): + ref_clk=None, ref_div2=False, ultrascale=False, rtio_clk_freq=125e6): self.switch_clocks = CSRStorage() self.phase_shift = CSR() self.phase_shift_done = CSRStatus(reset=1) self.error = CSR() - assert rtio_clk_freq in (100e6, 125e6, 150e6) + assert rtio_clk_freq in (100e6, 125e6) - # 125MHz/62.5MHz reference clock to 100MHz/125MHz/150MHz. VCO @ 750MHz. + # 125MHz/62.5MHz reference clock to 100MHz/125MHz. VCO @ 750MHz. # Used to provide a startup clock to the transceiver through the Si, # we do not use the crystal reference so that the PFD (f3) frequency # can be high. @@ -97,17 +97,14 @@ class SiPhaser7Series(Module, AutoCSR): toggle_out = rx_synchronizer.resync(toggle_in) toggle_out_expected = Signal() - self.sync.rtio += toggle_out_expected.eq(~toggle_out) + self.sync += toggle_out_expected.eq(~toggle_out) error = Signal() - error_clear = PulseSynchronizer("sys", "rtio") - self.submodules += error_clear - self.sync.rtio += [ + self.sync += [ If(toggle_out != toggle_out_expected, error.eq(1)), - If(error_clear.o, error.eq(0)) + If(self.error.re, error.eq(0)) ] self.specials += MultiReg(error, self.error.w) - self.comb += error_clear.i.eq(self.error.re) # expose MMCM outputs - used for clock constraints self.mmcm_freerun_output = mmcm_freerun_output diff --git a/artiq/gateware/drtio/transceiver/clock_aligner.py b/artiq/gateware/drtio/transceiver/clock_aligner.py index 9d17d2b77..b0649a148 100644 --- a/artiq/gateware/drtio/transceiver/clock_aligner.py +++ b/artiq/gateware/drtio/transceiver/clock_aligner.py @@ -33,7 +33,7 @@ class BruteforceClockAligner(Module): check_counter = Signal(max=check_max_val+1) check = Signal() reset_check_counter = Signal() - self.sync.rtio_tx += [ + self.sync += [ check.eq(0), If(reset_check_counter, check_counter.eq(check_max_val) @@ -47,7 +47,7 @@ class BruteforceClockAligner(Module): ) ] - checks_reset = PulseSynchronizer("rtio_tx", "rtio_rx") + checks_reset = PulseSynchronizer("sys", "rtio_rx") self.submodules += checks_reset comma_n = ~comma & 0b1111111111 @@ -76,7 +76,7 @@ class BruteforceClockAligner(Module): ) ] - fsm = ClockDomainsRenamer("rtio_tx")(FSM(reset_state="WAIT_COMMA")) + fsm = FSM(reset_state="WAIT_COMMA") self.submodules += fsm fsm.act("WAIT_COMMA", diff --git a/artiq/gateware/drtio/transceiver/gtp_7series.py b/artiq/gateware/drtio/transceiver/gtp_7series.py index 5da42b22b..75c31a486 100644 --- a/artiq/gateware/drtio/transceiver/gtp_7series.py +++ b/artiq/gateware/drtio/transceiver/gtp_7series.py @@ -20,8 +20,7 @@ class GTPSingle(Module): self.stable_clkin = Signal() self.txenable = Signal() - self.submodules.encoder = encoder = ClockDomainsRenamer("rtio_tx")( - Encoder(2, True)) + self.submodules.encoder = encoder = Encoder(2, True) self.submodules.decoders = decoders = [ClockDomainsRenamer("rtio_rx")( (Decoder(True))) for _ in range(2)] self.rx_ready = Signal() @@ -33,10 +32,11 @@ class GTPSingle(Module): # # # - # TX generates RTIO clock, init must be in system domain - self.submodules.tx_init = tx_init = GTPTXInit(sys_clk_freq, mode) - # RX receives restart commands from RTIO domain - rx_init = ClockDomainsRenamer("rtio_tx")(GTPRXInit(rtio_clk_freq)) + # TX generates RTIO clock, init must be in bootstrap domain + self.submodules.tx_init = tx_init = ClockDomainsRenamer("bootstrap")( + GTPTXInit(125e6, mode)) + # RX receives restart commands from SYS domain + rx_init = GTPRXInit(rtio_clk_freq) self.submodules += rx_init self.comb += [ @@ -367,7 +367,7 @@ class GTPSingle(Module): # Channel - DRP Ports i_DRPADDR=rx_init.drpaddr, - i_DRPCLK=ClockSignal("rtio_tx"), + i_DRPCLK=ClockSignal("sys"), i_DRPDI=rx_init.drpdi, o_DRPDO=rx_init.drpdo, i_DRPEN=rx_init.drpen, @@ -566,8 +566,8 @@ class GTPSingle(Module): i_PMARSVDIN1 =0b0, # Transmit Ports - FPGA TX Interface Ports 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"), # Transmit Ports - PCI Express Ports i_TXELECIDLE =0, @@ -665,19 +665,10 @@ class GTPSingle(Module): raise ValueError self.specials += Instance("GTPE2_CHANNEL", **gtp_params) - # 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 mode == "master" or mode == "single": - 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_tx += rx_reset_deglitched.eq(~rx_init.done) + self.sync += rx_reset_deglitched.eq(~rx_init.done) self.clock_domains.cd_rtio_rx = ClockDomain() self.specials += [ Instance("BUFG", i_I=self.rxoutclk, o_O=self.cd_rtio_rx.clk), @@ -727,7 +718,6 @@ class GTP(Module, TransceiverInterface): # # # - rtio_tx_clk = Signal() channel_interfaces = [] for i in range(nchannels): if nchannels == 1: @@ -735,10 +725,6 @@ class GTP(Module, TransceiverInterface): else: mode = "master" if i == master else "slave" gtp = GTPSingle(qpll_channel, data_pads[i], sys_clk_freq, rtio_clk_freq, mode) - if mode == "slave": - self.comb += gtp.cd_rtio_tx.clk.eq(rtio_tx_clk) - else: - self.comb += rtio_tx_clk.eq(gtp.cd_rtio_tx.clk) self.gtps.append(gtp) setattr(self.submodules, "gtp"+str(i), gtp) channel_interface = ChannelInterface(gtp.encoder, gtp.decoders) @@ -754,10 +740,6 @@ class GTP(Module, TransceiverInterface): gtp.txenable.eq(self.txenable.storage[n]) ] - self.comb += [ - self.cd_rtio.clk.eq(self.gtps[master].cd_rtio_tx.clk), - self.cd_rtio.rst.eq(reduce(or_, [gtp.cd_rtio_tx.rst for gtp in self.gtps])) - ] for i in range(nchannels): self.comb += [ getattr(self, "cd_rtio_rx" + str(i)).clk.eq(self.gtps[i].cd_rtio_rx.clk), diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index 52bc91ab7..3003d4848 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -9,7 +9,7 @@ from artiq.gateware.drtio.wrpll import thls, filters class FrequencyCounter(Module, AutoCSR): - def __init__(self, timer_width=23, counter_width=23, domains=["helper", "rtio", "rtio_rx0"]): + def __init__(self, timer_width=23, counter_width=23, domains=["helper", "sys", "rtio_rx0"]): for domain in domains: name = "counter_" + domain counter = CSRStatus(counter_width, name=name) diff --git a/artiq/gateware/rtio/phy/phaser.py b/artiq/gateware/rtio/phy/phaser.py index 94a5400d5..d4771d9ed 100644 --- a/artiq/gateware/rtio/phy/phaser.py +++ b/artiq/gateware/rtio/phy/phaser.py @@ -105,7 +105,7 @@ class MiqroChannel(Module): self.pulse.eq(pulse), self.rtlink.o.busy.eq(stb & ~self.ack), ] - self.sync.rtio += [ + self.sync += [ If(~stb, dt.eq(dt + 2), ), @@ -162,7 +162,7 @@ class Miqro(Module): ] re_dly = Signal(3) # stage, send, respond - self.sync.rtio += [ + self.sync += [ header.type.eq(3), # body type is miqro pulse data If(self.serializer.stb, header.we.eq(0), diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index f080b4fd0..9adfac0a2 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -17,7 +17,7 @@ from misoc.integration.builder import builder_args, builder_argdict from artiq.gateware.amp import AMPSoC from artiq.gateware import rtio from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, edge_counter -from artiq.gateware.rtio.xilinx_clocking import RTIOClockMultiplier, fix_serdes_timing_path +from artiq.gateware.rtio.xilinx_clocking import fix_serdes_timing_path from artiq.gateware import eem from artiq.gateware.drtio.transceiver import gtp_7series from artiq.gateware.drtio.siphaser import SiPhaser7Series @@ -76,6 +76,23 @@ class StandaloneBase(MiniSoC, AMPSoC): self.platform.request("error_led"))) self.csr_devices.append("error_led") self.submodules += SMAClkinForward(self.platform) + cdr_clk_out = self.platform.request("cdr_clk_clean") + else: + cdr_clk_out = self.platform.request("si5324_clkout") + + cdr_clk = Signal() + cdr_clk_buf = Signal() + self.platform.add_period_constraint(cdr_clk_out, 8.) + + self.specials += [ + Instance("IBUFDS_GTE2", + i_CEB=0, + i_I=cdr_clk_out.p, i_IB=cdr_clk_out.n, + o_O=cdr_clk), + Instance("BUFG", i_I=cdr_clk, o_O=cdr_clk_buf) + ] + + self.crg.configure(cdr_clk_buf) i2c = self.platform.request("i2c") self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) @@ -218,6 +235,8 @@ class MasterBase(MiniSoC, AMPSoC): integrated_sram_size=8192, ethmac_nrxslots=4, ethmac_ntxslots=4, + clk_freq=rtio_clk_freq, + rtio_sys_merge=True, **kwargs) AMPSoC.__init__(self) add_identifier(self, gateware_identifier_str=gateware_identifier_str) @@ -256,8 +275,6 @@ class MasterBase(MiniSoC, AMPSoC): sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") - self.sync += self.disable_cdr_clk_ibuf.eq( - ~self.drtio_transceiver.stable_clkin.storage) if enable_sata: sfp_channels = self.drtio_transceiver.channels[1:] @@ -307,8 +324,14 @@ class MasterBase(MiniSoC, AMPSoC): rtio_clk_period = 1e9/rtio_clk_freq gtp = self.drtio_transceiver.gtps[0] + + txout_buf = Signal() + self.specials += Instance("BUFG", i_I=gtp.txoutclk, o_O=txout_buf) + self.crg.configure(txout_buf, clk_sw=gtp.tx_init.done) + platform.add_period_constraint(gtp.txoutclk, rtio_clk_period) platform.add_period_constraint(gtp.rxoutclk, rtio_clk_period) + platform.add_false_path_constraints( self.crg.cd_sys.clk, gtp.txoutclk, gtp.rxoutclk) @@ -317,8 +340,6 @@ class MasterBase(MiniSoC, AMPSoC): platform.add_false_path_constraints( self.crg.cd_sys.clk, gtp.rxoutclk) - self.submodules.rtio_crg = RTIOClockMultiplier(rtio_clk_freq) - self.csr_devices.append("rtio_crg") fix_serdes_timing_path(platform) def add_rtio(self, rtio_channels, sed_lanes=8): @@ -350,19 +371,18 @@ class MasterBase(MiniSoC, AMPSoC): # Never running out of stupid features, GTs on A7 make you pack # unrelated transceiver PLLs into one GTPE2_COMMON yourself. def create_qpll(self): - # The GTP acts up if you send any glitch to its - # clock input, even while the PLL is held in reset. - self.disable_cdr_clk_ibuf = Signal(reset=1) - self.disable_cdr_clk_ibuf.attr.add("no_retiming") if self.platform.hw_rev == "v2.0": - cdr_clk_clean = self.platform.request("cdr_clk_clean") + cdr_clk_out = self.platform.request("cdr_clk_clean") else: - cdr_clk_clean = self.platform.request("si5324_clkout") - cdr_clk_clean_buf = Signal() + cdr_clk_out = self.platform.request("si5324_clkout") + + cdr_clk = Signal() + self.platform.add_period_constraint(cdr_clk_out, 8.) + self.specials += Instance("IBUFDS_GTE2", - i_CEB=self.disable_cdr_clk_ibuf, - i_I=cdr_clk_clean.p, i_IB=cdr_clk_clean.n, - o_O=cdr_clk_clean_buf) + i_CEB=0, + i_I=cdr_clk_out.p, i_IB=cdr_clk_out.n, + o_O=cdr_clk) # Note precisely the rules Xilinx made up: # refclksel=0b001 GTREFCLK0 selected # refclksel=0b010 GTREFCLK1 selected @@ -377,7 +397,8 @@ class MasterBase(MiniSoC, AMPSoC): fbdiv=4, fbdiv_45=5, refclk_div=1) - qpll = QPLL(cdr_clk_clean_buf, qpll_drtio_settings, + + qpll = QPLL(cdr_clk, qpll_drtio_settings, self.crg.clk125_buf, qpll_eth_settings) self.submodules += qpll self.drtio_qpll_channel, self.ethphy_qpll_channel = qpll.channels @@ -400,6 +421,8 @@ class SatelliteBase(BaseSoC): cpu_bus_width=cpu_bus_width, sdram_controller_type="minicon", l2_size=128*1024, + clk_freq=rtio_clk_freq, + rtio_sys_merge=True, **kwargs) add_identifier(self, gateware_identifier_str=gateware_identifier_str) @@ -410,23 +433,24 @@ class SatelliteBase(BaseSoC): self.platform.request("error_led"))) self.csr_devices.append("error_led") - disable_cdr_clk_ibuf = Signal(reset=1) - disable_cdr_clk_ibuf.attr.add("no_retiming") if self.platform.hw_rev == "v2.0": - cdr_clk_clean = self.platform.request("cdr_clk_clean") + cdr_clk_out = self.platform.request("cdr_clk_clean") else: - cdr_clk_clean = self.platform.request("si5324_clkout") - cdr_clk_clean_buf = Signal() + cdr_clk_out = self.platform.request("si5324_clkout") + + cdr_clk = Signal() + self.platform.add_period_constraint(cdr_clk_out, 8.) + self.specials += Instance("IBUFDS_GTE2", - i_CEB=disable_cdr_clk_ibuf, - i_I=cdr_clk_clean.p, i_IB=cdr_clk_clean.n, - o_O=cdr_clk_clean_buf) + i_CEB=0, + i_I=cdr_clk_out.p, i_IB=cdr_clk_out.n, + o_O=cdr_clk) qpll_drtio_settings = QPLLSettings( refclksel=0b001, fbdiv=4, fbdiv_45=5, refclk_div=1) - qpll = QPLL(cdr_clk_clean_buf, qpll_drtio_settings) + qpll = QPLL(cdr_clk, qpll_drtio_settings) self.submodules += qpll drtio_data_pads = [] @@ -445,8 +469,6 @@ class SatelliteBase(BaseSoC): sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") - self.sync += disable_cdr_clk_ibuf.eq( - ~self.drtio_transceiver.stable_clkin.storage) if enable_sata: sfp_channels = self.drtio_transceiver.channels[1:] @@ -542,6 +564,10 @@ class SatelliteBase(BaseSoC): self.config["SI5324_SOFT_RESET"] = None gtp = self.drtio_transceiver.gtps[0] + txout_buf = Signal() + self.specials += Instance("BUFG", i_I=gtp.txoutclk, o_O=txout_buf) + self.crg.configure(txout_buf, clk_sw=gtp.tx_init.done) + platform.add_period_constraint(gtp.txoutclk, rtio_clk_period) platform.add_period_constraint(gtp.rxoutclk, rtio_clk_period) platform.add_false_path_constraints( @@ -555,8 +581,6 @@ class SatelliteBase(BaseSoC): platform.add_false_path_constraints( self.crg.cd_sys.clk, gtp.rxoutclk) - self.submodules.rtio_crg = RTIOClockMultiplier(rtio_clk_freq) - self.csr_devices.append("rtio_crg") fix_serdes_timing_path(platform) def add_rtio(self, rtio_channels, sed_lanes=8): diff --git a/artiq/gateware/test/drtio/test_aux_controller.py b/artiq/gateware/test/drtio/test_aux_controller.py index 68c9f3bbd..6c65307ed 100644 --- a/artiq/gateware/test/drtio/test_aux_controller.py +++ b/artiq/gateware/test/drtio/test_aux_controller.py @@ -36,7 +36,7 @@ class TB(Module): def __init__(self, nwords, dw): self.submodules.link_layer = Loopback(nwords) self.submodules.aux_controller = ClockDomainsRenamer( - {"rtio": "sys", "rtio_rx": "sys"})(DRTIOAuxController(self.link_layer, dw)) + {"rtio_rx": "sys"})(DRTIOAuxController(self.link_layer, dw)) class TestAuxController(unittest.TestCase): diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index 02535b7e6..7cafe16a1 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -144,7 +144,7 @@ class OutputsTestbench: class TestFullStack(unittest.TestCase): - clocks = {"sys": 8, "rtio": 5, "rtio_rx": 5, + clocks = {"sys": 8, "rtio_rx": 5, "rio": 5, "rio_phy": 5} def test_pulses(self): @@ -169,7 +169,7 @@ class TestFullStack(unittest.TestCase): yield from tb.sync() run_simulation(tb.dut, - {"sys": test(), "rtio": tb.check_ttls(ttl_changes)}, self.clocks) + {"sys": test()}, self.clocks) self.assertEqual(ttl_changes, correct_ttl_changes) def test_underflow(self): @@ -214,7 +214,7 @@ class TestFullStack(unittest.TestCase): yield from tb.sync() run_simulation(tb.dut, - {"sys": test(), "rtio": tb.check_ttls(ttl_changes)}, self.clocks) + {"sys": test()}, self.clocks) self.assertEqual(ttl_changes, correct_ttl_changes) def test_write_underflow(self): @@ -284,7 +284,7 @@ class TestFullStack(unittest.TestCase): yield dut.phy2.rtlink.i.stb.eq(0) run_simulation(dut, - {"sys": test(), "rtio": generate_input()}, self.clocks) + {"sys": test()}, self.clocks) def test_echo(self): dut = DUT(2) diff --git a/artiq/gateware/test/drtio/test_rt_packet_repeater.py b/artiq/gateware/test/drtio/test_rt_packet_repeater.py index 9c73af625..21a28ae47 100644 --- a/artiq/gateware/test/drtio/test_rt_packet_repeater.py +++ b/artiq/gateware/test/drtio/test_rt_packet_repeater.py @@ -12,7 +12,7 @@ def create_dut(nwords): pt = PacketInterface("s2m", nwords*8) pr = PacketInterface("m2s", nwords*8) ts = Signal(64) - dut = ClockDomainsRenamer({"rtio": "sys", "rtio_rx": "sys"})( + dut = ClockDomainsRenamer({"rtio_rx": "sys"})( RTPacketRepeater( SimpleNamespace(coarse_ts=ts), SimpleNamespace( diff --git a/artiq/gateware/test/drtio/test_switching.py b/artiq/gateware/test/drtio/test_switching.py index dddfb9bd2..1f7876ade 100644 --- a/artiq/gateware/test/drtio/test_switching.py +++ b/artiq/gateware/test/drtio/test_switching.py @@ -130,7 +130,7 @@ class Testbench: class TestSwitching(unittest.TestCase): - clocks = {"sys": 8, "rtio": 5, "rtio_rx": 5, + clocks = {"sys": 8, "rtio_rx": 5, "rio": 5, "rio_phy": 5} def test_outputs(self): @@ -183,7 +183,7 @@ class TestSwitching(unittest.TestCase): current_request = (packet_type, field_dict, trailer) run_simulation(tb.dut, - {"sys": test(), "rtio": tb.dut.pr.receive(receive), "rtio_rx": send_replies()}, self.clocks) + {"sys": test(), "sys": tb.dut.pr.receive(receive), "rtio_rx": send_replies()}, self.clocks) def test_inputs(self): @@ -244,4 +244,4 @@ class TestSwitching(unittest.TestCase): current_request = (packet_type, field_dict, trailer) run_simulation(tb.dut, - {"sys": test(), "rtio": tb.dut.pr.receive(receive), "rtio_rx": send_replies()}, self.clocks) + {"sys": test(), "sys": tb.dut.pr.receive(receive), "rtio_rx": send_replies()}, self.clocks) From 4be7f302e42edc5d1d3e7c1697d48e1e2ade9e43 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 18 Dec 2022 16:51:02 +0800 Subject: [PATCH 40/85] flake: vivado 2022.2 --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 25216ea28..fe351a3cb 100644 --- a/flake.nix +++ b/flake.nix @@ -229,7 +229,7 @@ vivado = pkgs.buildFHSUserEnv { name = "vivado"; targetPkgs = vivadoDeps; - profile = "set -e; source /opt/Xilinx/Vivado/2021.2/settings64.sh"; + profile = "set -e; source /opt/Xilinx/Vivado/2022.2/settings64.sh"; runScript = "vivado"; }; From f5c408d8d97fc2e543fcddede5cbef9835c4d279 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 18 Dec 2022 17:11:08 +0000 Subject: [PATCH 41/85] RELEASE_NOTES: Fix up punctuation --- RELEASE_NOTES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 4c3e1732e..d0b8262b1 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -31,7 +31,7 @@ Highlights: - Almazny mezzanine board for Mirny - Phaser: improved documentation, exposed the DAC coarse mixer and ``sif_sync``, exposed upconverter calibration and enabling/disabling of upconverter LO & RF outputs, added helpers to align Phaser updates to the - RTIO timeline (``get_next_frame_mu()`` + RTIO timeline (``get_next_frame_mu()``). - Urukul: ``get()``, ``get_mu()``, ``get_att()``, and ``get_att_mu()`` functions added for AD9910 and AD9912. * Softcore targets now use the RISC-V architecture (VexRiscv) instead of OR1K (mor1kx). * Gateware FPU is supported on KC705 and Kasli 2.0. From 4bb2a3b9e02469311243a0b70f2b9a5fa0301bc2 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 18 Dec 2022 17:26:58 +0000 Subject: [PATCH 42/85] RELEASE_NOTES: Two typo/formatting fixes --- RELEASE_NOTES.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index d0b8262b1..bf25afadf 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -81,9 +81,9 @@ Breaking changes: generated for some configurations. * Phaser: fixed coarse mixer frequency configuration * Mirny: Added extra delays in ``ADF5356.sync()``. This avoids the need of an extra delay before - calling `ADF5356.init()`. + calling ``ADF5356.init()``. * The deprecated ``set_dataset(..., save=...)`` is no longer supported. -* The ``PCA9548`` I2C switch class was renamed to ``I2CSwitch``, to accomodate support for PCA9547, +* The ``PCA9548`` I2C switch class was renamed to ``I2CSwitch``, to accommodate support for PCA9547, and possibly other switches in future. Readback has been removed, and now only one channel per switch is supported. From b9f13d48aa7e2c0652210152b971b21c3c419347 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 19 Dec 2022 00:57:46 +0000 Subject: [PATCH 43/85] firmware: Fix object references in tuples Sine 8740ec3dd, the alignment() information from "run-time type information" (i.e. the Tag type) is also used when sending tuples to the host. --- artiq/firmware/libproto_artiq/rpc_proto.rs | 4 ++-- artiq/test/coredevice/test_embedding.py | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libproto_artiq/rpc_proto.rs b/artiq/firmware/libproto_artiq/rpc_proto.rs index 85fc902ba..49b78e633 100644 --- a/artiq/firmware/libproto_artiq/rpc_proto.rs +++ b/artiq/firmware/libproto_artiq/rpc_proto.rs @@ -429,8 +429,8 @@ mod tag { // the ptr/length(s) pair is basically CSlice Tag::Bytes | Tag::String | Tag::ByteArray | Tag::List(_) | Tag::Array(_, _) => core::mem::align_of::>(), - // will not be sent from the host - _ => unreachable!("unexpected tag from host") + Tag::Keyword(_) => unreachable!("Tag::Keyword should not appear in composite types"), + Tag::Object => core::mem::align_of::(), } } diff --git a/artiq/test/coredevice/test_embedding.py b/artiq/test/coredevice/test_embedding.py index 537cec113..807bc4896 100644 --- a/artiq/test/coredevice/test_embedding.py +++ b/artiq/test/coredevice/test_embedding.py @@ -74,6 +74,9 @@ class RoundtripTest(ExperimentCase): def test_object_list(self): self.assertRoundtrip([object(), object()]) + def test_object_tuple(self): + self.assertRoundtrip((False, object(), True, 0x12345678)) + def test_list_tuple(self): self.assertRoundtrip(([1, 2], [3, 4])) From 88684dbd2a367605d3d72a6bab647a886b433ffe Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 19 Dec 2022 01:02:51 +0000 Subject: [PATCH 44/85] test_embedding: Fix up spelling in FIXME comment [nfc] --- artiq/test/coredevice/test_embedding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/test/coredevice/test_embedding.py b/artiq/test/coredevice/test_embedding.py index 807bc4896..f5ec95451 100644 --- a/artiq/test/coredevice/test_embedding.py +++ b/artiq/test/coredevice/test_embedding.py @@ -98,7 +98,7 @@ class RoundtripTest(ExperimentCase): self.assertArrayRoundtrip(numpy.array([["a", "b"], ["c", "d"]])) # FIXME: This should work, but currently passes as the argument is just - # synthesised as a call to array() without forwarding the dype form the host + # synthesised as a call to array() without forwarding the dtype from the host # NumPy object. @unittest.expectedFailure def test_array_jagged(self): From 1fc127c7701cca117584e3ce88d6259c04c7d247 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 20 Dec 2022 12:56:43 +0800 Subject: [PATCH 45/85] fix default version --- artiq/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/_version.py b/artiq/_version.py index 87dc270e3..e308ce8c2 100644 --- a/artiq/_version.py +++ b/artiq/_version.py @@ -1,4 +1,4 @@ import os def get_version(): - return os.getenv("VERSIONEER_OVERRIDE", default="7.0.beta") + return os.getenv("VERSIONEER_OVERRIDE", default="8.0.beta") From dbb77b53566ff8751e05ce67a8f9249a121249ab Mon Sep 17 00:00:00 2001 From: Norman Krackow Date: Wed, 21 Dec 2022 02:47:47 +0100 Subject: [PATCH 46/85] artiq_sinara_tester: change mirny frequencies --- artiq/frontend/artiq_sinara_tester.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_sinara_tester.py b/artiq/frontend/artiq_sinara_tester.py index aeb7f3720..34bafea4b 100755 --- a/artiq/frontend/artiq_sinara_tester.py +++ b/artiq/frontend/artiq_sinara_tester.py @@ -431,7 +431,7 @@ class SinaraTester(EnvExperiment): print("Frequencies:") for card_n, channels in enumerate(chunker(self.mirnies, 4)): for channel_n, (channel_name, channel_dev) in enumerate(channels): - frequency = 1000*(card_n + 1) + channel_n * 100 + frequency = 1000 + 100 * (card_n + 1) + channel_n * 10 print("{}\t{}MHz".format(channel_name, frequency)) self.setup_mirny(channel_dev, frequency) print("{} info: {}".format(channel_name, channel_dev.info())) From 8dc6902c23fb9f0462fe079f2ced5719aa085568 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Tue, 20 Dec 2022 14:18:44 +0800 Subject: [PATCH 47/85] AD9912: Add PLL bypass option (pll_en) like AD9910 --- artiq/coredevice/ad9912.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index cb018c103..159bfd137 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -25,12 +25,14 @@ class AD9912: f_ref/clk_div*pll_n where f_ref is the reference frequency and clk_div is the reference clock divider (both set in the parent Urukul CPLD instance). + :param pll_en: PLL enable bit, set to 0 to bypass PLL (default: 1). + Note that when bypassing the PLL the red front panel LED may remain on. """ def __init__(self, dmgr, chip_select, cpld_device, sw_device=None, - pll_n=10): + pll_n=10, pll_en=1): self.kernel_invariants = {"cpld", "core", "bus", "chip_select", - "pll_n", "ftw_per_hz"} + "pll_n", "pll_en", "ftw_per_hz"} self.cpld = dmgr.get(cpld_device) self.core = self.cpld.core self.bus = self.cpld.bus @@ -39,8 +41,12 @@ class AD9912: if sw_device: self.sw = dmgr.get(sw_device) self.kernel_invariants.add("sw") + self.pll_en = pll_en self.pll_n = pll_n - sysclk = self.cpld.refclk / [1, 1, 2, 4][self.cpld.clk_div] * pll_n + if pll_en: + sysclk = self.cpld.refclk / [1, 1, 2, 4][self.cpld.clk_div] * pll_n + else: + sysclk = self.cpld.refclk assert sysclk <= 1e9 self.ftw_per_hz = 1 / sysclk * (int64(1) << 48) @@ -102,13 +108,15 @@ class AD9912: raise ValueError("Urukul AD9912 product id mismatch") delay(50 * us) # HSTL power down, CMOS power down - self.write(AD9912_PWRCNTRL1, 0x80, length=1) - self.cpld.io_update.pulse(2 * us) - self.write(AD9912_N_DIV, self.pll_n // 2 - 2, length=1) - self.cpld.io_update.pulse(2 * us) - # I_cp = 375 µA, VCO high range - self.write(AD9912_PLLCFG, 0b00000101, length=1) + pwrcntrl1 = 0x80 | ((~self.pll_en & 1) << 4) + self.write(AD9912_PWRCNTRL1, pwrcntrl1, length=1) self.cpld.io_update.pulse(2 * us) + if self.pll_en: + self.write(AD9912_N_DIV, self.pll_n // 2 - 2, length=1) + self.cpld.io_update.pulse(2 * us) + # I_cp = 375 µA, VCO high range + self.write(AD9912_PLLCFG, 0b00000101, length=1) + self.cpld.io_update.pulse(2 * us) delay(1 * ms) @kernel From bdae594c79eb67cc924a79a2f24db937d8a21c4e Mon Sep 17 00:00:00 2001 From: mwojcik Date: Wed, 4 Jan 2023 14:28:42 +0800 Subject: [PATCH 48/85] suservo experimentals: fix rtio ch name changes --- experimental-features/suservo_coherent.diff | 18 +++++++++++------- .../suservo_coherent_after_var.diff | 8 ++++---- experimental-features/suservo_var_urukul.diff | 12 ++++++++---- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/experimental-features/suservo_coherent.diff b/experimental-features/suservo_coherent.diff index 74a528795..12e222729 100644 --- a/experimental-features/suservo_coherent.diff +++ b/experimental-features/suservo_coherent.diff @@ -104,15 +104,15 @@ index 1d0a72dad1..f7b516a4e7 100644 :param core_device: Core device name """ kernel_invariants = {"channel", "core", "pgia", "cplds", "ddses", -- "ref_period_mu"} +- "ref_period_mu", "corrected_fs"} + "ref_period_mu", "num_channels", "coeff_sel", + "state_sel", "io_dly_addr", "config_addr", -+ "write_enable"} ++ "corrected_fs", "write_enable"} def __init__(self, dmgr, channel, pgia_device, cpld_devices, dds_devices, -@@ -83,9 +85,20 @@ def __init__(self, dmgr, channel, pgia_device, - self.core.coarse_ref_period) +@@ -83,13 +85,24 @@ def __init__(self, dmgr, channel, pgia_device, + self.corrected_fs = sampler.Sampler.use_corrected_fs(sampler_hw_rev) assert self.ref_period_mu == self.core.ref_multiplier + # The width of parts of the servo memory address depends on the number @@ -126,6 +126,10 @@ index 1d0a72dad1..f7b516a4e7 100644 + self.coeff_sel = 1 << coeff_depth + self.write_enable = 1 << (coeff_depth + 1) + + @staticmethod + def get_rtio_channels(channel, **kwargs): + return [(channel, None)] + @kernel def init(self): - """Initialize the servo, Sampler and both Urukuls. @@ -191,9 +195,9 @@ index 1d0a72dad1..f7b516a4e7 100644 @kernel def set_pgia_mu(self, channel, gain): -@@ -236,6 +262,18 @@ def get_adc(self, channel): +@@ -242,6 +268,18 @@ def get_adc(self, channel): gain = (self.gains >> (channel*2)) & 0b11 - return adc_mu_to_volts(val, gain) + return adc_mu_to_volts(val, gain, self.corrected_fs) + @kernel + def set_io_update_delays(self, dlys): @@ -211,7 +215,7 @@ index 1d0a72dad1..f7b516a4e7 100644 class Channel: """Sampler-Urukul Servo channel @@ -256,7 +294,7 @@ def __init__(self, dmgr, channel, servo_device): - self.dds = self.servo.ddses[self.servo_channel // 4] + return [(channel, None)] @kernel - def set(self, en_out, en_iir=0, profile=0): diff --git a/experimental-features/suservo_coherent_after_var.diff b/experimental-features/suservo_coherent_after_var.diff index 961289814..a1b262ebb 100644 --- a/experimental-features/suservo_coherent_after_var.diff +++ b/experimental-features/suservo_coherent_after_var.diff @@ -80,9 +80,9 @@ index a89cdcca..f7b516a4 100644 """ kernel_invariants = {"channel", "core", "pgia", "cplds", "ddses", "ref_period_mu", "num_channels", "coeff_sel", -- "state_sel", "config_addr", "write_enable"} +- "corrected_fs", "state_sel", "config_addr", "write_enable"} + "state_sel", "io_dly_addr", "config_addr", -+ "write_enable"} ++ "corrected_fs", "write_enable"} def __init__(self, dmgr, channel, pgia_device, cpld_devices, dds_devices, @@ -117,7 +117,7 @@ index a89cdcca..f7b516a4 100644 """Write to servo memory. @@ -245,6 +262,18 @@ class SUServo: gain = (self.gains >> (channel*2)) & 0b11 - return adc_mu_to_volts(val, gain) + return adc_mu_to_volts(val, gain, self.corrected_fs) + @kernel + def set_io_update_delays(self, dlys): @@ -135,7 +135,7 @@ index a89cdcca..f7b516a4 100644 class Channel: """Sampler-Urukul Servo channel @@ -265,7 +294,7 @@ class Channel: - self.dds = self.servo.ddses[self.servo_channel // 4] + return [(channel, None)] @kernel - def set(self, en_out, en_iir=0, profile=0): diff --git a/experimental-features/suservo_var_urukul.diff b/experimental-features/suservo_var_urukul.diff index e4f5a749a..ce981ba66 100644 --- a/experimental-features/suservo_var_urukul.diff +++ b/experimental-features/suservo_var_urukul.diff @@ -48,14 +48,14 @@ index 1d0a72dad..a89cdcca4 100644 :param core_device: Core device name """ kernel_invariants = {"channel", "core", "pgia", "cplds", "ddses", -- "ref_period_mu"} +- "ref_period_mu", "corrected_fs"} + "ref_period_mu", "num_channels", "coeff_sel", -+ "state_sel", "config_addr", "write_enable"} ++ "corrected_fs", "state_sel", "config_addr", "write_enable"} def __init__(self, dmgr, channel, pgia_device, cpld_devices, dds_devices, -@@ -83,9 +81,19 @@ def __init__(self, dmgr, channel, pgia_device, - self.core.coarse_ref_period) +@@ -83,13 +81,23 @@ def __init__(self, dmgr, channel, pgia_device, + self.corrected_fs = sampler.Sampler.use_corrected_fs(sampler_hw_rev) assert self.ref_period_mu == self.core.ref_multiplier + # The width of parts of the servo memory address depends on the number @@ -68,6 +68,10 @@ index 1d0a72dad..a89cdcca4 100644 + self.coeff_sel = 1 << coeff_depth + self.write_enable = 1 << (coeff_depth + 1) + + @staticmethod + def get_rtio_channels(channel, **kwargs): + return [(channel, None)] + @kernel def init(self): - """Initialize the servo, Sampler and both Urukuls. From 1bf7188decddec60c9771a4fb72247ad8769025d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 4 Jan 2023 15:07:56 +0800 Subject: [PATCH 49/85] gui: update version in logo --- artiq/gui/logo_ver.svg | 50 +++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/artiq/gui/logo_ver.svg b/artiq/gui/logo_ver.svg index fd0b3eb28..4ebd46eed 100644 --- a/artiq/gui/logo_ver.svg +++ b/artiq/gui/logo_ver.svg @@ -1,14 +1,7 @@ image/svg+xml + aria-label="7">8 From 1be7e2a2e1d142802a52792865b19c8874fd0e9d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 4 Jan 2023 15:13:55 +0800 Subject: [PATCH 50/85] doc: duplicate nixConfig --- doc/manual/installing.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index ef0106172..44b79c5d3 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -73,6 +73,10 @@ Installing multiple packages and making them visible to the ARTIQ commands requi ]; }; }; + nixConfig = { # work around https://github.com/NixOS/nix/issues/6771 + extra-trusted-public-keys = "nixbld.m-labs.hk-1:5aSRVA5b320xbNvu30tqxVPXpld73bhtOeH6uAjRyHc="; + extra-substituters = "https://nixbld.m-labs.hk"; + }; } From 3838dfc1d108cf3c08984bfd455f94365819f526 Mon Sep 17 00:00:00 2001 From: Spaqin Date: Fri, 6 Jan 2023 07:13:38 +0800 Subject: [PATCH 51/85] DRTIO: RTIO/SYS clock merge, KC705 --- artiq/firmware/runtime/rtio_clocking.rs | 33 +--- artiq/firmware/satman/main.rs | 13 -- .../gateware/drtio/transceiver/gtx_7series.py | 65 +++---- .../drtio/transceiver/gtx_7series_init.py | 10 +- artiq/gateware/targets/kc705.py | 161 ++++++++---------- 5 files changed, 102 insertions(+), 180 deletions(-) diff --git a/artiq/firmware/runtime/rtio_clocking.rs b/artiq/firmware/runtime/rtio_clocking.rs index 6af4ea3e9..52ab35915 100644 --- a/artiq/firmware/runtime/rtio_clocking.rs +++ b/artiq/firmware/runtime/rtio_clocking.rs @@ -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"); diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 7ac232827..366aa1d5b 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -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 { diff --git a/artiq/gateware/drtio/transceiver/gtx_7series.py b/artiq/gateware/drtio/transceiver/gtx_7series.py index 3d96971ca..fe901d90c 100644 --- a/artiq/gateware/drtio/transceiver/gtx_7series.py +++ b/artiq/gateware/drtio/transceiver/gtx_7series.py @@ -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 += [ diff --git a/artiq/gateware/drtio/transceiver/gtx_7series_init.py b/artiq/gateware/drtio/transceiver/gtx_7series_init.py index 70c69a19c..5552c308f 100644 --- a/artiq/gateware/drtio/transceiver/gtx_7series_init.py +++ b/artiq/gateware/drtio/transceiver/gtx_7series_init.py @@ -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), diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index e04088a92..3ad5f5bdf 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -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): From 5da9794895e04214c11da9bf03b42e73671cad7c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 6 Jan 2023 17:41:12 +0800 Subject: [PATCH 52/85] remove Sayma and Metlino support --- artiq/coredevice/ad9154_reg.py | 2996 ----------------- artiq/coredevice/ad9154_spi.py | 23 - artiq/coredevice/basemod_att.py | 79 - artiq/coredevice/sawg.py | 372 -- artiq/coredevice/shiftreg.py | 54 - artiq/coredevice/spline.py | 228 -- artiq/examples/kasli_sawgmaster/device_db.py | 184 - .../kasli_sawgmaster/repository/basemod.py | 25 - .../repository/sines_2sayma.py | 37 - .../repository/sines_urukul_sayma.py | 89 - artiq/examples/metlino_sayma_ttl/device_db.py | 102 - .../metlino_sayma_ttl/repository/demo.py | 129 - artiq/examples/sayma_master/device_db.py | 173 - .../examples/sayma_master/repository/demo.py | 41 - artiq/firmware/libboard_artiq/ad9154.rs | 549 --- artiq/firmware/libboard_artiq/ad9154_reg.rs | 826 ----- artiq/firmware/libboard_artiq/hmc830_7043.rs | 419 --- artiq/firmware/libboard_artiq/lib.rs | 7 - artiq/firmware/libboard_artiq/si5324.rs | 6 - artiq/firmware/libboard_artiq/wrpll.rs | 2 - artiq/firmware/libboard_misoc/net_settings.rs | 4 - artiq/firmware/libboard_misoc/spiflash.rs | 2 +- artiq/firmware/runtime/main.rs | 2 +- artiq/firmware/runtime/rtio_clocking.rs | 6 +- artiq/firmware/satman/jdac_common.rs | 74 - artiq/firmware/satman/jdcg.rs | 589 ---- artiq/firmware/satman/main.rs | 104 - artiq/frontend/artiq_flash.py | 138 +- .../drtio/transceiver/gth_ultrascale.py | 704 ---- .../drtio/transceiver/gth_ultrascale_init.py | 157 - artiq/gateware/dsp/__init__.py | 0 artiq/gateware/dsp/accu.py | 112 - artiq/gateware/dsp/fir.py | 172 - artiq/gateware/dsp/sawg.py | 220 -- artiq/gateware/dsp/spline.py | 47 - artiq/gateware/dsp/tools.py | 69 - artiq/gateware/fmcdio_vhdci_eem.py | 29 - artiq/gateware/jesd204_tools.py | 290 -- artiq/gateware/rtio/phy/sawg.py | 39 - artiq/gateware/targets/metlino.py | 180 - artiq/gateware/targets/sayma_amc.py | 462 --- artiq/gateware/targets/sayma_rtm.py | 280 -- artiq/gateware/test/dsp/__init__.py | 0 artiq/gateware/test/dsp/fir.py | 112 - artiq/gateware/test/dsp/test_accu.py | 46 - artiq/gateware/test/dsp/test_satadd.py | 71 - artiq/gateware/test/dsp/test_sawg.py | 36 - artiq/gateware/test/dsp/test_sawg_fe.py | 255 -- artiq/gateware/test/dsp/test_sawg_phy.py | 70 - artiq/gateware/test/dsp/test_spline.py | 31 - artiq/gateware/test/dsp/tools.py | 49 - artiq/test/test_coefficients.py | 49 - doc/manual/core_drivers_reference.rst | 25 - doc/manual/utilities.rst | 3 - flake.nix | 14 +- 55 files changed, 12 insertions(+), 10770 deletions(-) delete mode 100644 artiq/coredevice/ad9154_reg.py delete mode 100644 artiq/coredevice/ad9154_spi.py delete mode 100644 artiq/coredevice/basemod_att.py delete mode 100644 artiq/coredevice/sawg.py delete mode 100644 artiq/coredevice/shiftreg.py delete mode 100644 artiq/coredevice/spline.py delete mode 100644 artiq/examples/kasli_sawgmaster/device_db.py delete mode 100644 artiq/examples/kasli_sawgmaster/repository/basemod.py delete mode 100644 artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py delete mode 100644 artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py delete mode 100644 artiq/examples/metlino_sayma_ttl/device_db.py delete mode 100644 artiq/examples/metlino_sayma_ttl/repository/demo.py delete mode 100644 artiq/examples/sayma_master/device_db.py delete mode 100644 artiq/examples/sayma_master/repository/demo.py delete mode 100644 artiq/firmware/libboard_artiq/ad9154.rs delete mode 100644 artiq/firmware/libboard_artiq/ad9154_reg.rs delete mode 100644 artiq/firmware/libboard_artiq/hmc830_7043.rs delete mode 100644 artiq/firmware/satman/jdac_common.rs delete mode 100644 artiq/firmware/satman/jdcg.rs delete mode 100644 artiq/gateware/drtio/transceiver/gth_ultrascale.py delete mode 100644 artiq/gateware/drtio/transceiver/gth_ultrascale_init.py delete mode 100644 artiq/gateware/dsp/__init__.py delete mode 100644 artiq/gateware/dsp/accu.py delete mode 100644 artiq/gateware/dsp/fir.py delete mode 100644 artiq/gateware/dsp/sawg.py delete mode 100644 artiq/gateware/dsp/spline.py delete mode 100644 artiq/gateware/dsp/tools.py delete mode 100644 artiq/gateware/fmcdio_vhdci_eem.py delete mode 100644 artiq/gateware/jesd204_tools.py delete mode 100644 artiq/gateware/rtio/phy/sawg.py delete mode 100755 artiq/gateware/targets/metlino.py delete mode 100755 artiq/gateware/targets/sayma_amc.py delete mode 100755 artiq/gateware/targets/sayma_rtm.py delete mode 100644 artiq/gateware/test/dsp/__init__.py delete mode 100644 artiq/gateware/test/dsp/fir.py delete mode 100644 artiq/gateware/test/dsp/test_accu.py delete mode 100644 artiq/gateware/test/dsp/test_satadd.py delete mode 100644 artiq/gateware/test/dsp/test_sawg.py delete mode 100644 artiq/gateware/test/dsp/test_sawg_fe.py delete mode 100644 artiq/gateware/test/dsp/test_sawg_phy.py delete mode 100644 artiq/gateware/test/dsp/test_spline.py delete mode 100644 artiq/gateware/test/dsp/tools.py delete mode 100644 artiq/test/test_coefficients.py diff --git a/artiq/coredevice/ad9154_reg.py b/artiq/coredevice/ad9154_reg.py deleted file mode 100644 index a7d414e96..000000000 --- a/artiq/coredevice/ad9154_reg.py +++ /dev/null @@ -1,2996 +0,0 @@ -# auto-generated, do not edit -from artiq.language.core import portable -from artiq.language.types import TInt32 - -AD9154_SPI_INTFCONFA = 0x000 -# default: 0x00, access: R/W -@portable -def AD9154_SOFTRESET_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_SOFTRESET_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_LSBFIRST_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_LSBFIRST_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_ADDRINC_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_ADDRINC_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SDOACTIVE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_SDOACTIVE_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SDOACTIVE_M_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_SDOACTIVE_M_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_ADDRINC_M_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_ADDRINC_M_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_LSBFIRST_M_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_LSBFIRST_M_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SOFTRESET_M_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_SOFTRESET_M_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_CHIPTYPE = 0x003 - -AD9154_PRODIDL = 0x004 - -AD9154_PRODIDH = 0x005 - -AD9154_CHIPGRADE = 0x006 -# default: 0x02, access: R -@portable -def AD9154_DEV_REVISION_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x00, access: R -@portable -def AD9154_PROD_GRADE_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0xf - - -AD9154_SPI_PAGEINDX = 0x008 - -AD9154_PWRCNTRL0 = 0x011 -# default: 0x01, access: R/W -@portable -def AD9154_PD_DAC3_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_PD_DAC3_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_PD_DAC2_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_PD_DAC2_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_PD_DAC1_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_PD_DAC1_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_PD_DAC0_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_PD_DAC0_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_PD_BG_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_PD_BG_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_TXENMASK1 = 0x012 -# default: 0x00, access: R/W -@portable -def AD9154_DACA_MASK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_DACA_MASK_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_DACB_MASK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_DACB_MASK_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_PWRCNTRL3 = 0x013 -# default: 0x00, access: R/W -@portable -def AD9154_SPI_TXEN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_SPI_TXEN_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_ENA_SPI_TXEN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_ENA_SPI_TXEN_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_PA_CTRL_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_SPI_PA_CTRL_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_ENA_PA_CTRL_FROM_SPI_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_ENA_PA_CTRL_FROM_SPI_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_ENA_PA_CTRL_FROM_BLSM_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_ENA_PA_CTRL_FROM_BLSM_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_ENA_PA_CTRL_FROM_TXENSM_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_ENA_PA_CTRL_FROM_TXENSM_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_ENA_PA_CTRL_FROM_PARROT_ERR_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_ENA_PA_CTRL_FROM_PARROT_ERR_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - - -AD9154_GROUP_DLY = 0x014 -# default: 0x08, access: R/W -@portable -def AD9154_COARSE_GROUP_DELAY_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 0 - -@portable -def AD9154_COARSE_GROUP_DELAY_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x08, access: R/W -@portable -def AD9154_GROUP_DELAY_RESERVED_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 4 - -@portable -def AD9154_GROUP_DELAY_RESERVED_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0xf - - -AD9154_IRQEN_STATUSMODE0 = 0x01f -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_LANEFIFOERR_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_IRQEN_SMODE_LANEFIFOERR_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_SERPLLLOCK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_IRQEN_SMODE_SERPLLLOCK_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_SERPLLLOST_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_IRQEN_SMODE_SERPLLLOST_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_DACPLLLOCK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_IRQEN_SMODE_DACPLLLOCK_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_DACPLLLOST_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_IRQEN_SMODE_DACPLLLOST_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - - -AD9154_IRQEN_STATUSMODE1 = 0x020 -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_PRBS0_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_IRQEN_SMODE_PRBS0_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_PRBS1_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_IRQEN_SMODE_PRBS1_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_PRBS2_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_IRQEN_SMODE_PRBS2_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_PRBS3_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_IRQEN_SMODE_PRBS3_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - - -AD9154_IRQEN_STATUSMODE2 = 0x021 -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_SYNC_TRIP0_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_IRQEN_SMODE_SYNC_TRIP0_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_SYNC_WLIM0_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_IRQEN_SMODE_SYNC_WLIM0_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_SYNC_ROTATE0_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_IRQEN_SMODE_SYNC_ROTATE0_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_SYNC_LOCK0_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_IRQEN_SMODE_SYNC_LOCK0_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_NCO_ALIGN0_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_IRQEN_SMODE_NCO_ALIGN0_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_BLNKDONE0_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_IRQEN_SMODE_BLNKDONE0_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_PDPERR0_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_IRQEN_SMODE_PDPERR0_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_IRQEN_STATUSMODE3 = 0x022 -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_SYNC_TRIP1_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_IRQEN_SMODE_SYNC_TRIP1_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_SYNC_WLIM1_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_IRQEN_SMODE_SYNC_WLIM1_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_SYNC_ROTATE1_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_IRQEN_SMODE_SYNC_ROTATE1_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_SYNC_LOCK1_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_IRQEN_SMODE_SYNC_LOCK1_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_NCO_ALIGN1_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_IRQEN_SMODE_NCO_ALIGN1_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_BLNKDONE1_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_IRQEN_SMODE_BLNKDONE1_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_IRQEN_SMODE_PDPERR1_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_IRQEN_SMODE_PDPERR1_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_IRQ_STATUS0 = 0x023 -# default: 0x00, access: R -@portable -def AD9154_LANEFIFOERR_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SERPLLLOCK_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SERPLLLOST_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_DACPLLLOCK_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_DACPLLLOST_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - - -AD9154_IRQ_STATUS1 = 0x024 -# default: 0x00, access: R -@portable -def AD9154_PRBS0_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_PRBS1_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_PRBS2_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_PRBS3_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - - -AD9154_IRQ_STATUS2 = 0x025 -# default: 0x00, access: R -@portable -def AD9154_SYNC_TRIP0_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SYNC_WLIM0_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SYNC_ROTATE0_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SYNC_LOCK0_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_NCO_ALIGN0_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_BLNKDONE0_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_PDPERR0_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_IRQ_STATUS3 = 0x026 -# default: 0x00, access: R -@portable -def AD9154_SYNC_TRIP1_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SYNC_WLIM1_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SYNC_ROTATE1_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SYNC_LOCK1_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_NCO_ALIGN1_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_BLNKDONE1_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_PDPERR1_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_JESD_CHECKS = 0x030 -# default: 0x00, access: R -@portable -def AD9154_ERR_INTSUPP_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_ERR_SUBCLASS_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_ERR_KUNSUPP_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_ERR_JESDBAD_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_ERR_WINLIMIT_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_ERR_DLYOVER_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - - -AD9154_SYNC_ERRWINDOW = 0x034 - -AD9154_SYNC_LASTERR_L = 0x038 - -AD9154_SYNC_LASTERR_H = 0x039 -# default: 0x00, access: R -@portable -def AD9154_LASTERROR_H_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_LASTOVER_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_LASTUNDER_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_SYNC_CONTROL = 0x03a -# default: 0x00, access: R/W -@portable -def AD9154_SYNCMODE_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 0 - -@portable -def AD9154_SYNCMODE_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x00, access: R/W -@portable -def AD9154_SYNCCLRLAST_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_SYNCCLRLAST_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SYNCCLRSTKY_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_SYNCCLRSTKY_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SYNCARM_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_SYNCARM_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SYNCENABLE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_SYNCENABLE_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_SYNC_STATUS = 0x03b -# default: 0x00, access: R -@portable -def AD9154_SYNC_TRIP_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SYNC_WLIM_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SYNC_ROTATE_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SYNC_LOCK_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SYNC_BUSY_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_SYNC_CURRERR_L = 0x03c - -AD9154_SYNC_CURRERR_H = 0x03d -# default: 0x00, access: R -@portable -def AD9154_CURRERROR_H_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_CURROVER_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_CURRUNDER_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_DACGAIN0_I = 0x040 - -AD9154_DACGAIN1_I = 0x041 - -AD9154_DACGAIN0_Q = 0x042 - -AD9154_DACGAIN1_Q = 0x043 - -AD9154_GROUPDELAY_COMP_I = 0x044 - -AD9154_GROUPDELAY_COMP_Q = 0x045 - -AD9154_GROUPDELAY_COMP_BYP = 0x046 -# default: 0x01, access: R/W -@portable -def AD9154_GROUPCOMP_BYPQ_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_GROUPCOMP_BYPQ_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_GROUPCOMP_BYPI_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_GROUPCOMP_BYPI_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - - -AD9154_MIX_MODE = 0x04a - -AD9154_NCOALIGN_MODE = 0x050 -# default: 0x00, access: R/W -@portable -def AD9154_NCO_ALIGN_MODE_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 0 - -@portable -def AD9154_NCO_ALIGN_MODE_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3 - -# default: 0x00, access: R -@portable -def AD9154_NCO_ALIGN_FAIL_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_NCO_ALIGN_PASS_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_NCO_ALIGN_MTCH_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_NCO_ALIGN_ARM_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_NCO_ALIGN_ARM_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_NCOKEY_ILSB = 0x051 - -AD9154_NCOKEY_IMSB = 0x052 - -AD9154_NCOKEY_QLSB = 0x053 - -AD9154_NCOKEY_QMSB = 0x054 - -AD9154_PDP_THRES0 = 0x060 - -AD9154_PDP_THRES1 = 0x061 - -AD9154_PDP_AVG_TIME = 0x062 -# default: 0x00, access: R/W -@portable -def AD9154_PDP_AVG_TIME__SET(x: TInt32) -> TInt32: - return (x & 0xf) << 0 - -@portable -def AD9154_PDP_AVG_TIME__GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x00, access: R/W -@portable -def AD9154_PA_BUS_SWAP_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_PA_BUS_SWAP_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_PDP_ENABLE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_PDP_ENABLE_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_PDP_POWER0 = 0x063 - -AD9154_PDP_POWER1 = 0x064 - -AD9154_CLKCFG0 = 0x080 -# default: 0x00, access: R/W -@portable -def AD9154_REF_CLKDIV_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_REF_CLKDIV_EN_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_RF_SYNC_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_RF_SYNC_EN_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_DUTY_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_DUTY_EN_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_PD_CLK_REC_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_PD_CLK_REC_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_PD_SERDES_PCLK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_PD_SERDES_PCLK_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_PD_CLK_DIG_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_PD_CLK_DIG_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_PD_CLK23_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_PD_CLK23_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_PD_CLK01_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_PD_CLK01_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_SYSREF_ACTRL0 = 0x081 -# default: 0x00, access: R/W -@portable -def AD9154_HYS_CNTRL1_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 0 - -@portable -def AD9154_HYS_CNTRL1_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3 - -# default: 0x00, access: R/W -@portable -def AD9154_SYSREF_RISE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_SYSREF_RISE_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_HYS_ON_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_HYS_ON_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_PD_SYSREF_BUFFER_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_PD_SYSREF_BUFFER_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - - -AD9154_SYSREF_ACTRL1 = 0x082 - -AD9154_DACPLLCNTRL = 0x083 -# default: 0x00, access: R/W -@portable -def AD9154_ENABLE_DACPLL_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_ENABLE_DACPLL_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_RECAL_DACPLL_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_RECAL_DACPLL_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_DACPLLSTATUS = 0x084 -# default: 0x00, access: R -@portable -def AD9154_DACPLL_LOCK_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_VCO_CAL_PROGRESS_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_CP_CAL_VALID_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_CP_OVERRANGE_L_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_CP_OVERRANGE_H_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x3 - - -AD9154_DACINTEGERWORD0 = 0x085 - -AD9154_DACLOOPFILT1 = 0x087 -# default: 0x08, access: R/W -@portable -def AD9154_LF_C1_WORD_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 0 - -@portable -def AD9154_LF_C1_WORD_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x08, access: R/W -@portable -def AD9154_LF_C2_WORD_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 4 - -@portable -def AD9154_LF_C2_WORD_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0xf - - -AD9154_DACLOOPFILT2 = 0x088 -# default: 0x08, access: R/W -@portable -def AD9154_LF_C3_WORD_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 0 - -@portable -def AD9154_LF_C3_WORD_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x08, access: R/W -@portable -def AD9154_LF_R1_WORD_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 4 - -@portable -def AD9154_LF_R1_WORD_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0xf - - -AD9154_DACLOOPFILT3 = 0x089 -# default: 0x08, access: R/W -@portable -def AD9154_LF_R3_WORD_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 0 - -@portable -def AD9154_LF_R3_WORD_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x00, access: R/W -@portable -def AD9154_LF_BYPASS_C1_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_LF_BYPASS_C1_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_LF_BYPASS_C2_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_LF_BYPASS_C2_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_LF_BYPASS_R1_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_LF_BYPASS_R1_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_LF_BYPASS_R3_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_LF_BYPASS_R3_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_DACCPCNTRL = 0x08a -# default: 0x20, access: R/W -@portable -def AD9154_CP_CURRENT_SET(x: TInt32) -> TInt32: - return (x & 0x3f) << 0 - -@portable -def AD9154_CP_CURRENT_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3f - -# default: 0x00, access: R/W -@portable -def AD9154_VT_FORCE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_VT_FORCE_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - - -AD9154_DACLOGENCNTRL = 0x08b -# default: 0x00, access: R/W -@portable -def AD9154_LODIVMODE_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 0 - -@portable -def AD9154_LODIVMODE_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3 - -# default: 0x00, access: R/W -@portable -def AD9154_LO_POWER_MODE_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 4 - -@portable -def AD9154_LO_POWER_MODE_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x3 - - -AD9154_DACLDOCNTRL1 = 0x08c -# default: 0x00, access: R/W -@portable -def AD9154_REFDIVMODE_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 0 - -@portable -def AD9154_REFDIVMODE_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x7 - -# default: 0x00, access: R/W -@portable -def AD9154_LDO_BYPASS_FLT_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_LDO_BYPASS_FLT_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_LDO_REF_SEL_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_LDO_REF_SEL_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_DACLDOCNTRL2 = 0x08d -# default: 0x03, access: R/W -@portable -def AD9154_LDO_VDROP_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 0 - -@portable -def AD9154_LDO_VDROP_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3 - -# default: 0x02, access: R/W -@portable -def AD9154_LDO_SEL_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 2 - -@portable -def AD9154_LDO_SEL_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x7 - -# default: 0x01, access: R/W -@portable -def AD9154_LDO_INRUSH_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 5 - -@portable -def AD9154_LDO_INRUSH_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x3 - -# default: 0x00, access: R/W -@portable -def AD9154_LDO_BYPASS_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_LDO_BYPASS_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_DATA_FORMAT = 0x110 -# default: 0x00, access: R/W -@portable -def AD9154_BINARY_FORMAT_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_BINARY_FORMAT_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_DATAPATH_CTRL = 0x111 -# default: 0x00, access: R/W -@portable -def AD9154_I_TO_Q_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_I_TO_Q_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SEL_SIDEBAND_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_SEL_SIDEBAND_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_MODULATION_TYPE_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 2 - -@portable -def AD9154_MODULATION_TYPE_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x3 - -# default: 0x00, access: R/W -@portable -def AD9154_PHASE_ADJ_ENABLE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_PHASE_ADJ_ENABLE_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_DIG_GAIN_ENABLE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_DIG_GAIN_ENABLE_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_INVSINC_ENABLE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_INVSINC_ENABLE_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_INTERP_MODE = 0x112 - -AD9154_NCO_FTW_UPDATE = 0x113 -# default: 0x00, access: R/W -@portable -def AD9154_FTW_UPDATE_REQ_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_FTW_UPDATE_REQ_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_FTW_UPDATE_ACK_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - - -AD9154_FTW0 = 0x114 - -AD9154_FTW1 = 0x115 - -AD9154_FTW2 = 0x116 - -AD9154_FTW3 = 0x117 - -AD9154_FTW4 = 0x118 - -AD9154_FTW5 = 0x119 - -AD9154_NCO_PHASE_OFFSET0 = 0x11a - -AD9154_NCO_PHASE_OFFSET1 = 0x11b - -AD9154_PHASE_ADJ0 = 0x11c - -AD9154_PHASE_ADJ1 = 0x11d - -AD9154_TXEN_SM_0 = 0x11f -# default: 0x01, access: R/W -@portable -def AD9154_TXEN_SM_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_TXEN_SM_EN_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_GP_PA_CTRL_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_GP_PA_CTRL_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_GP_PA_ON_INVERT_SET(x: TInt32) -> TInt32: - return (x & 0x0) << 2 - -@portable -def AD9154_GP_PA_ON_INVERT_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x0 - -# default: 0x00, access: R/W -@portable -def AD9154_RISE_COUNTERS_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 4 - -@portable -def AD9154_RISE_COUNTERS_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x3 - -# default: 0x02, access: R/W -@portable -def AD9154_FALL_COUNTERS_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 6 - -@portable -def AD9154_FALL_COUNTERS_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x3 - - -AD9154_TXEN_RISE_COUNT_0 = 0x121 - -AD9154_TXEN_RISE_COUNT_1 = 0x122 - -AD9154_TXEN_FALL_COUNT_0 = 0x123 - -AD9154_TXEN_FALL_COUNT_1 = 0x124 - -AD9154_DEVICE_CONFIG_REG_0 = 0x12d - -AD9154_DIE_TEMP_CTRL0 = 0x12f -# default: 0x00, access: R/W -@portable -def AD9154_AUXADC_ENABLE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_AUXADC_ENABLE_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x10, access: R/W -@portable -def AD9154_AUXADC_RESERVED_SET(x: TInt32) -> TInt32: - return (x & 0x7f) << 1 - -@portable -def AD9154_AUXADC_RESERVED_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x7f - - -AD9154_DIE_TEMP0 = 0x132 - -AD9154_DIE_TEMP1 = 0x133 - -AD9154_DIE_TEMP_UPDATE = 0x134 - -AD9154_DC_OFFSET_CTRL = 0x135 - -AD9154_IPATH_DC_OFFSET_1PART0 = 0x136 - -AD9154_IPATH_DC_OFFSET_1PART1 = 0x137 - -AD9154_QPATH_DC_OFFSET_1PART0 = 0x138 - -AD9154_QPATH_DC_OFFSET_1PART1 = 0x139 - -AD9154_IPATH_DC_OFFSET_2PART = 0x13a - -AD9154_QPATH_DC_OFFSET_2PART = 0x13b - -AD9154_IDAC_DIG_GAIN0 = 0x13c - -AD9154_IDAC_DIG_GAIN1 = 0x13d - -AD9154_QDAC_DIG_GAIN0 = 0x13e - -AD9154_QDAC_DIG_GAIN1 = 0x13f - -AD9154_GAIN_RAMP_UP_STEP0 = 0x140 - -AD9154_GAIN_RAMP_UP_STEP1 = 0x141 - -AD9154_GAIN_RAMP_DOWN_STEP0 = 0x142 - -AD9154_GAIN_RAMP_DOWN_STEP1 = 0x143 - -AD9154_DEVICE_CONFIG_REG_1 = 0x146 - -AD9154_BSM_STAT = 0x147 -# default: 0x00, access: R -@portable -def AD9154_SOFTBLANKRB_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x3 - - -AD9154_PRBS = 0x14b -# default: 0x00, access: R/W -@portable -def AD9154_PRBS_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_PRBS_EN_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_PRBS_RESET_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_PRBS_RESET_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_PRBS_MODE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_PRBS_MODE_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_PRBS_GOOD_I_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_PRBS_GOOD_Q_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_PRBS_ERROR_I = 0x14c - -AD9154_PRBS_ERROR_Q = 0x14d - -AD9154_DACPLLT0 = 0x1b0 -# default: 0x01, access: R/W -@portable -def AD9154_LOGEN_PD_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_LOGEN_PD_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_LDO_PD_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_LDO_PD_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_SYNTH_PD_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_SYNTH_PD_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_VCO_PD_ALC_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_VCO_PD_ALC_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_VCO_PD_PTAT_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_VCO_PD_PTAT_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_VCO_PD_IN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_VCO_PD_IN_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_DACPLLT1 = 0x1b1 -# default: 0x00, access: R/W -@portable -def AD9154_PFD_EDGE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_PFD_EDGE_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_PFD_DELAY_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 2 - -@portable -def AD9154_PFD_DELAY_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x3 - - -AD9154_DACPLLT2 = 0x1b2 -# default: 0x00, access: R/W -@portable -def AD9154_EXT_ALC_WORD_SET(x: TInt32) -> TInt32: - return (x & 0x7f) << 0 - -@portable -def AD9154_EXT_ALC_WORD_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x7f - -# default: 0x00, access: R/W -@portable -def AD9154_EXT_ALC_WORD_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_EXT_ALC_WORD_EN_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_DACPLLT3 = 0x1b3 -# default: 0x00, access: W -@portable -def AD9154_EXT_BAND1_SET(x: TInt32) -> TInt32: - return (x & 0xff) << 0 - - -AD9154_DACPLLT4 = 0x1b4 -# default: 0x00, access: R/W -@portable -def AD9154_EXT_BAND2_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_EXT_BAND2_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_EXT_BAND_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_EXT_BAND_EN_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x0f, access: R/W -@portable -def AD9154_VCO_CAL_OFFSET_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 3 - -@portable -def AD9154_VCO_CAL_OFFSET_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0xf - -# default: 0x00, access: R/W -@portable -def AD9154_BYP_LOAD_DELAY_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_BYP_LOAD_DELAY_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_DACPLLT5 = 0x1b5 - -AD9154_DACPLLT6 = 0x1b6 - -AD9154_DACPLLT7 = 0x1b7 - -AD9154_DACPLLT8 = 0x1b8 - -AD9154_DACPLLT9 = 0x1b9 - -AD9154_DACPLLTA = 0x1ba - -AD9154_DACPLLTB = 0x1bb -# default: 0x04, access: R/W -@portable -def AD9154_VCO_BIAS_REF_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 0 - -@portable -def AD9154_VCO_BIAS_REF_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x7 - -# default: 0x01, access: R/W -@portable -def AD9154_VCO_BIAS_TCF_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 3 - -@portable -def AD9154_VCO_BIAS_TCF_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x3 - - -AD9154_DACPLLTC = 0x1bc - -AD9154_DACPLLTD = 0x1bd - -AD9154_DACPLLTE = 0x1be - -AD9154_DACPLLTF = 0x1bf - -AD9154_DACPLLT10 = 0x1c0 - -AD9154_DACPLLT11 = 0x1c1 - -AD9154_DACPLLT15 = 0x1c2 - -AD9154_DACPLLT16 = 0x1c3 - -AD9154_DACPLLT17 = 0x1c4 - -AD9154_DACPLLT18 = 0x1c5 - -AD9154_MASTER_PD = 0x200 - -AD9154_PHY_PD = 0x201 - -AD9154_GENERIC_PD = 0x203 -# default: 0x00, access: R/W -@portable -def AD9154_PD_SYNCOUT1B_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_PD_SYNCOUT1B_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_PD_SYNCOUT0B_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_PD_SYNCOUT0B_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - - -AD9154_CDR_RESET = 0x206 - -AD9154_CDR_OPERATING_MODE_REG_0 = 0x230 -# default: 0x00, access: R/W -@portable -def AD9154_CDR_OVERSAMP_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_CDR_OVERSAMP_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x02, access: R/W -@portable -def AD9154_CDR_RESERVED_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 2 - -@portable -def AD9154_CDR_RESERVED_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x7 - -# default: 0x01, access: R/W -@portable -def AD9154_ENHALFRATE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_ENHALFRATE_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - - -AD9154_EQ_BIAS_REG = 0x268 -# default: 0x22, access: R/W -@portable -def AD9154_EQ_BIAS_RESERVED_SET(x: TInt32) -> TInt32: - return (x & 0x3f) << 0 - -@portable -def AD9154_EQ_BIAS_RESERVED_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3f - -# default: 0x01, access: R/W -@portable -def AD9154_EQ_POWER_MODE_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 6 - -@portable -def AD9154_EQ_POWER_MODE_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x3 - - -AD9154_SERDESPLL_ENABLE_CNTRL = 0x280 -# default: 0x00, access: R/W -@portable -def AD9154_ENABLE_SERDESPLL_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_ENABLE_SERDESPLL_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_RECAL_SERDESPLL_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_RECAL_SERDESPLL_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - - -AD9154_PLL_STATUS = 0x281 -# default: 0x00, access: R -@portable -def AD9154_SERDES_PLL_LOCK_RB_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SERDES_CURRENTS_READY_RB_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SERDES_VCO_CAL_IN_PROGRESS_RB_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SERDES_PLL_CAL_VALID_RB_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SERDES_PLL_OVERRANGE_L_RB_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_SERDES_PLL_OVERRANGE_H_RB_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - - -AD9154_LDO_FILTER_1 = 0x284 - -AD9154_LDO_FILTER_2 = 0x285 - -AD9154_LDO_FILTER_3 = 0x286 - -AD9154_CP_CURRENT_SPI = 0x287 -# default: 0x3f, access: R/W -@portable -def AD9154_SPI_CP_CURRENT_SET(x: TInt32) -> TInt32: - return (x & 0x3f) << 0 - -@portable -def AD9154_SPI_CP_CURRENT_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3f - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_SERDES_LOGEN_POWER_MODE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_SPI_SERDES_LOGEN_POWER_MODE_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - - -AD9154_REF_CLK_DIVIDER_LDO = 0x289 -# default: 0x00, access: R/W -@portable -def AD9154_SPI_CDR_OVERSAMP_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 0 - -@portable -def AD9154_SPI_CDR_OVERSAMP_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3 - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_LDO_BYPASS_FILT_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_SPI_LDO_BYPASS_FILT_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_LDO_REF_SEL_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_SPI_LDO_REF_SEL_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - - -AD9154_VCO_LDO = 0x28a - -AD9154_PLL_RD_REG = 0x28b -# default: 0x01, access: R/W -@portable -def AD9154_SPI_SERDES_LOGEN_PD_CORE_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 0 - -@portable -def AD9154_SPI_SERDES_LOGEN_PD_CORE_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3 - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_SERDES_LDO_PD_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_SPI_SERDES_LDO_PD_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_SYN_PD_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_SPI_SYN_PD_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_VCO_PD_ALC_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_SPI_VCO_PD_ALC_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_VCO_PD_PTAT_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_SPI_VCO_PD_PTAT_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_VCO_PD_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_SPI_VCO_PD_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - - -AD9154_ALC_VARACTOR = 0x290 -# default: 0x03, access: R/W -@portable -def AD9154_SPI_VCO_VARACTOR_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 0 - -@portable -def AD9154_SPI_VCO_VARACTOR_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x08, access: R/W -@portable -def AD9154_SPI_INIT_ALC_VALUE_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 4 - -@portable -def AD9154_SPI_INIT_ALC_VALUE_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0xf - - -AD9154_VCO_OUTPUT = 0x291 -# default: 0x09, access: R/W -@portable -def AD9154_SPI_VCO_OUTPUT_LEVEL_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 0 - -@portable -def AD9154_SPI_VCO_OUTPUT_LEVEL_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x04, access: R/W -@portable -def AD9154_SPI_VCO_OUTPUT_RESERVED_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 4 - -@portable -def AD9154_SPI_VCO_OUTPUT_RESERVED_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0xf - - -AD9154_CP_CONFIG = 0x294 -# default: 0x00, access: R/W -@portable -def AD9154_SPI_CP_TEST_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 0 - -@portable -def AD9154_SPI_CP_TEST_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_CP_CAL_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_SPI_CP_CAL_EN_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_CP_FORCE_CALBITS_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_SPI_CP_FORCE_CALBITS_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_CP_OFFSET_OFF_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_SPI_CP_OFFSET_OFF_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_CP_ENABLE_MACHINE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_SPI_CP_ENABLE_MACHINE_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_CP_DITHER_MODE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_SPI_CP_DITHER_MODE_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_CP_HALF_VCO_CAL_CLK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_SPI_CP_HALF_VCO_CAL_CLK_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_VCO_BIAS_1 = 0x296 -# default: 0x04, access: R/W -@portable -def AD9154_SPI_VCO_BIAS_REF_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 0 - -@portable -def AD9154_SPI_VCO_BIAS_REF_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x7 - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_VCO_BIAS_TCF_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 3 - -@portable -def AD9154_SPI_VCO_BIAS_TCF_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x3 - - -AD9154_VCO_BIAS_2 = 0x297 -# default: 0x00, access: R/W -@portable -def AD9154_SPI_PRESCALE_BIAS_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 0 - -@portable -def AD9154_SPI_PRESCALE_BIAS_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_LAST_ALC_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_SPI_LAST_ALC_EN_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_PRESCALE_BYPASS_R_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_SPI_PRESCALE_BYPASS_R_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_VCO_COMP_BYPASS_BIASR_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_SPI_VCO_COMP_BYPASS_BIASR_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_VCO_BYPASS_DAC_R_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_SPI_VCO_BYPASS_DAC_R_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - - -AD9154_VCO_PD_OVERRIDES = 0x299 -# default: 0x00, access: R/W -@portable -def AD9154_SPI_VCO_PD_OVERRIDE_VCO_BUF_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_SPI_VCO_PD_OVERRIDE_VCO_BUF_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_VCO_PD_OVERRIDE_CAL_TCF_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_SPI_VCO_PD_OVERRIDE_CAL_TCF_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_VCO_PD_OVERRIDE_VAR_REF_TCF_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_SPI_VCO_PD_OVERRIDE_VAR_REF_TCF_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_VCO_PD_OVERRIDE_VAR_REF_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_SPI_VCO_PD_OVERRIDE_VAR_REF_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - - -AD9154_VCO_CAL = 0x29a -# default: 0x02, access: R/W -@portable -def AD9154_SPI_FB_CLOCK_ADV_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 0 - -@portable -def AD9154_SPI_FB_CLOCK_ADV_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3 - -# default: 0x03, access: R/W -@portable -def AD9154_SPI_VCO_CAL_COUNT_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 2 - -@portable -def AD9154_SPI_VCO_CAL_COUNT_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x3 - -# default: 0x07, access: R/W -@portable -def AD9154_SPI_VCO_CAL_ALC_WAIT_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 4 - -@portable -def AD9154_SPI_VCO_CAL_ALC_WAIT_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x7 - -# default: 0x01, access: R/W -@portable -def AD9154_SPI_VCO_CAL_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_SPI_VCO_CAL_EN_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_CP_LEVEL_DETECT = 0x29c -# default: 0x07, access: R/W -@portable -def AD9154_SPI_CP_LEVEL_THRESHOLD_HIGH_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 0 - -@portable -def AD9154_SPI_CP_LEVEL_THRESHOLD_HIGH_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x7 - -# default: 0x02, access: R/W -@portable -def AD9154_SPI_CP_LEVEL_THRESHOLD_LOW_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 3 - -@portable -def AD9154_SPI_CP_LEVEL_THRESHOLD_LOW_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x7 - -# default: 0x00, access: R/W -@portable -def AD9154_SPI_CP_LEVEL_DET_PD_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_SPI_CP_LEVEL_DET_PD_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - - -AD9154_VCO_VARACTOR_CTRL_0 = 0x29f -# default: 0x03, access: R/W -@portable -def AD9154_SPI_VCO_VARACTOR_OFFSET_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 0 - -@portable -def AD9154_SPI_VCO_VARACTOR_OFFSET_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x03, access: R/W -@portable -def AD9154_SPI_VCO_VARACTOR_REF_TCF_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 4 - -@portable -def AD9154_SPI_VCO_VARACTOR_REF_TCF_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x7 - - -AD9154_VCO_VARACTOR_CTRL_1 = 0x2a0 -# default: 0x08, access: R/W -@portable -def AD9154_SPI_VCO_VARACTOR_REF_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 0 - -@portable -def AD9154_SPI_VCO_VARACTOR_REF_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - - -AD9154_TERM_BLK1_CTRLREG0 = 0x2a7 - -AD9154_TERM_BLK2_CTRLREG0 = 0x2ae - -AD9154_GENERAL_JRX_CTRL_0 = 0x300 -# default: 0x00, access: R/W -@portable -def AD9154_LINK_EN_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 0 - -@portable -def AD9154_LINK_EN_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x3 - -# default: 0x00, access: R/W -@portable -def AD9154_LINK_PAGE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -@portable -def AD9154_LINK_PAGE_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_LINK_MODE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_LINK_MODE_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_CHECKSUM_MODE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_CHECKSUM_MODE_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - - -AD9154_GENERAL_JRX_CTRL_1 = 0x301 - -AD9154_DYN_LINK_LATENCY_0 = 0x302 - -AD9154_DYN_LINK_LATENCY_1 = 0x303 - -AD9154_LMFC_DELAY_0 = 0x304 - -AD9154_LMFC_DELAY_1 = 0x305 - -AD9154_LMFC_VAR_0 = 0x306 - -AD9154_LMFC_VAR_1 = 0x307 - -AD9154_XBAR_LN_0_1 = 0x308 -# default: 0x00, access: R/W -@portable -def AD9154_LOGICAL_LANE0_SRC_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 0 - -@portable -def AD9154_LOGICAL_LANE0_SRC_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x7 - -# default: 0x01, access: R/W -@portable -def AD9154_LOGICAL_LANE1_SRC_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 3 - -@portable -def AD9154_LOGICAL_LANE1_SRC_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x7 - - -AD9154_XBAR_LN_2_3 = 0x309 -# default: 0x02, access: R/W -@portable -def AD9154_LOGICAL_LANE2_SRC_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 0 - -@portable -def AD9154_LOGICAL_LANE2_SRC_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x7 - -# default: 0x03, access: R/W -@portable -def AD9154_LOGICAL_LANE3_SRC_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 3 - -@portable -def AD9154_LOGICAL_LANE3_SRC_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x7 - - -AD9154_XBAR_LN_4_5 = 0x30a -# default: 0x04, access: R/W -@portable -def AD9154_LOGICAL_LANE4_SRC_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 0 - -@portable -def AD9154_LOGICAL_LANE4_SRC_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x7 - -# default: 0x05, access: R/W -@portable -def AD9154_LOGICAL_LANE5_SRC_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 3 - -@portable -def AD9154_LOGICAL_LANE5_SRC_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x7 - - -AD9154_XBAR_LN_6_7 = 0x30b -# default: 0x06, access: R/W -@portable -def AD9154_LOGICAL_LANE6_SRC_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 0 - -@portable -def AD9154_LOGICAL_LANE6_SRC_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x7 - -# default: 0x07, access: R/W -@portable -def AD9154_LOGICAL_LANE7_SRC_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 3 - -@portable -def AD9154_LOGICAL_LANE7_SRC_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x7 - - -AD9154_FIFO_STATUS_REG_0 = 0x30c - -AD9154_FIFO_STATUS_REG_1 = 0x30d - -AD9154_SYNCB_GEN_1 = 0x312 -# default: 0x00, access: R/W -@portable -def AD9154_SYNCB_ERR_DUR_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 4 - -@portable -def AD9154_SYNCB_ERR_DUR_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x7 - - -AD9154_SERDES_SPI_REG = 0x314 - -AD9154_PHY_PRBS_TEST_EN = 0x315 - -AD9154_PHY_PRBS_TEST_CTRL = 0x316 -# default: 0x00, access: R/W -@portable -def AD9154_PHY_TEST_RESET_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_PHY_TEST_RESET_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_PHY_TEST_START_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_PHY_TEST_START_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_PHY_PRBS_PAT_SEL_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 2 - -@portable -def AD9154_PHY_PRBS_PAT_SEL_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x3 - -# default: 0x00, access: R/W -@portable -def AD9154_PHY_SRC_ERR_CNT_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 4 - -@portable -def AD9154_PHY_SRC_ERR_CNT_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x7 - - -AD9154_PHY_PRBS_TEST_THRESHOLD_LOBITS = 0x317 - -AD9154_PHY_PRBS_TEST_THRESHOLD_MIDBITS = 0x318 - -AD9154_PHY_PRBS_TEST_THRESHOLD_HIBITS = 0x319 - -AD9154_PHY_PRBS_TEST_ERRCNT_LOBITS = 0x31a - -AD9154_PHY_PRBS_TEST_ERRCNT_MIDBITS = 0x31b - -AD9154_PHY_PRBS_TEST_ERRCNT_HIBITS = 0x31c - -AD9154_PHY_PRBS_TEST_STATUS = 0x31d - -AD9154_SHORT_TPL_TEST_0 = 0x32c -# default: 0x00, access: R/W -@portable -def AD9154_SHORT_TPL_TEST_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -@portable -def AD9154_SHORT_TPL_TEST_EN_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SHORT_TPL_TEST_RESET_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_SHORT_TPL_TEST_RESET_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_SHORT_TPL_DAC_SEL_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 2 - -@portable -def AD9154_SHORT_TPL_DAC_SEL_GET(x: TInt32) -> TInt32: - return (x >> 2) & 0x3 - -# default: 0x00, access: R/W -@portable -def AD9154_SHORT_TPL_SP_SEL_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 4 - -@portable -def AD9154_SHORT_TPL_SP_SEL_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x3 - - -AD9154_SHORT_TPL_TEST_1 = 0x32d - -AD9154_SHORT_TPL_TEST_2 = 0x32e - -AD9154_SHORT_TPL_TEST_3 = 0x32f - -AD9154_DEVICE_CONFIG_REG_2 = 0x333 - -AD9154_JESD_BIT_INVERSE_CTRL = 0x334 - -AD9154_DID_REG = 0x400 - -AD9154_BID_REG = 0x401 -# default: 0x00, access: R -@portable -def AD9154_BID_RD_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x00, access: R -@portable -def AD9154_ADJCNT_RD_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0xf - - -AD9154_LID0_REG = 0x402 -# default: 0x00, access: R -@portable -def AD9154_LID0_RD_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x00, access: R -@portable -def AD9154_PHADJ_RD_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R -@portable -def AD9154_ADJDIR_RD_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - - -AD9154_SCR_L_REG = 0x403 -# default: 0x00, access: R -@portable -def AD9154_L_1_RD_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x00, access: R -@portable -def AD9154_SCR_RD_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_F_REG = 0x404 - -AD9154_K_REG = 0x405 - -AD9154_M_REG = 0x406 - -AD9154_CS_N_REG = 0x407 -# default: 0x00, access: R -@portable -def AD9154_N_1_RD_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x00, access: R -@portable -def AD9154_CS_RD_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x3 - - -AD9154_NP_REG = 0x408 -# default: 0x00, access: R -@portable -def AD9154_NP_1_RD_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x00, access: R -@portable -def AD9154_SUBCLASSV_RD_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x7 - - -AD9154_S_REG = 0x409 -# default: 0x00, access: R -@portable -def AD9154_S_1_RD_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x00, access: R -@portable -def AD9154_JESDV_RD_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x7 - - -AD9154_HD_CF_REG = 0x40a -# default: 0x00, access: R -@portable -def AD9154_CF_RD_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x00, access: R -@portable -def AD9154_HD_RD_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_RES1_REG = 0x40b - -AD9154_RES2_REG = 0x40c - -AD9154_CHECKSUM0_REG = 0x40d - -AD9154_COMPSUM0_REG = 0x40e - -AD9154_LID1_REG = 0x412 - -AD9154_CHECKSUM1_REG = 0x415 - -AD9154_COMPSUM1_REG = 0x416 - -AD9154_LID2_REG = 0x41a - -AD9154_CHECKSUM2_REG = 0x41d - -AD9154_COMPSUM2_REG = 0x41e - -AD9154_LID3_REG = 0x422 - -AD9154_CHECKSUM3_REG = 0x425 - -AD9154_COMPSUM3_REG = 0x426 - -AD9154_LID4_REG = 0x42a - -AD9154_CHECKSUM4_REG = 0x42d - -AD9154_COMPSUM4_REG = 0x42e - -AD9154_LID5_REG = 0x432 - -AD9154_CHECKSUM5_REG = 0x435 - -AD9154_COMPSUM5_REG = 0x436 - -AD9154_LID6_REG = 0x43a - -AD9154_CHECKSUM6_REG = 0x43d - -AD9154_COMPSUM6_REG = 0x43e - -AD9154_LID7_REG = 0x442 - -AD9154_CHECKSUM7_REG = 0x445 - -AD9154_COMPSUM7_REG = 0x446 - -AD9154_ILS_DID = 0x450 - -AD9154_ILS_BID = 0x451 -# default: 0x00, access: R/W -@portable -def AD9154_BID_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 0 - -@portable -def AD9154_BID_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0xf - -# default: 0x00, access: R/W -@portable -def AD9154_ADJCNT_SET(x: TInt32) -> TInt32: - return (x & 0xf) << 4 - -@portable -def AD9154_ADJCNT_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0xf - - -AD9154_ILS_LID0 = 0x452 -# default: 0x00, access: R/W -@portable -def AD9154_LID0_SET(x: TInt32) -> TInt32: - return (x & 0x1f) << 0 - -@portable -def AD9154_LID0_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x00, access: R/W -@portable -def AD9154_PHADJ_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_PHADJ_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_ADJDIR_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_ADJDIR_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - - -AD9154_ILS_SCR_L = 0x453 -# default: 0x03, access: R/W -@portable -def AD9154_L_1_SET(x: TInt32) -> TInt32: - return (x & 0x1f) << 0 - -@portable -def AD9154_L_1_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x01, access: R/W -@portable -def AD9154_SCR_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_SCR_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_ILS_F = 0x454 - -AD9154_ILS_K = 0x455 - -AD9154_ILS_M = 0x456 - -AD9154_ILS_CS_N = 0x457 -# default: 0x0f, access: R/W -@portable -def AD9154_N_1_SET(x: TInt32) -> TInt32: - return (x & 0x1f) << 0 - -@portable -def AD9154_N_1_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x00, access: R/W -@portable -def AD9154_CS_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 6 - -@portable -def AD9154_CS_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x3 - - -AD9154_ILS_NP = 0x458 -# default: 0x0f, access: R/W -@portable -def AD9154_NP_1_SET(x: TInt32) -> TInt32: - return (x & 0x1f) << 0 - -@portable -def AD9154_NP_1_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x01, access: R/W -@portable -def AD9154_SUBCLASSV_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 5 - -@portable -def AD9154_SUBCLASSV_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x7 - - -AD9154_ILS_S = 0x459 -# default: 0x00, access: R/W -@portable -def AD9154_S_1_SET(x: TInt32) -> TInt32: - return (x & 0x1f) << 0 - -@portable -def AD9154_S_1_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x01, access: R/W -@portable -def AD9154_JESDV_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 5 - -@portable -def AD9154_JESDV_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x7 - - -AD9154_ILS_HD_CF = 0x45a -# default: 0x00, access: R/W -@portable -def AD9154_CF_SET(x: TInt32) -> TInt32: - return (x & 0x1f) << 0 - -@portable -def AD9154_CF_GET(x: TInt32) -> TInt32: - return (x >> 0) & 0x1f - -# default: 0x01, access: R/W -@portable -def AD9154_HD_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_HD_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_ILS_RES1 = 0x45b - -AD9154_ILS_RES2 = 0x45c - -AD9154_ILS_CHECKSUM = 0x45d - -AD9154_ERRCNTRMON = 0x46b -# default: 0x00, access: W -@portable -def AD9154_CNTRSEL_SET(x: TInt32) -> TInt32: - return (x & 0x3) << 0 - -# default: 0x00, access: W -@portable -def AD9154_LANESEL_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 4 - - -AD9154_LANEDESKEW = 0x46c - -AD9154_BADDISPARITY = 0x46d -# default: 0x00, access: W -@portable -def AD9154_LANE_ADDR_DIS_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 0 - -# default: 0x00, access: W -@portable -def AD9154_RST_ERR_CNTR_DIS_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -# default: 0x00, access: W -@portable -def AD9154_DISABLE_ERR_CNTR_DIS_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -# default: 0x00, access: W -@portable -def AD9154_RST_IRQ_DIS_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - - -AD9154_NIT_W = 0x46e -# default: 0x00, access: W -@portable -def AD9154_LANE_ADDR_NIT_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 0 - -# default: 0x00, access: W -@portable -def AD9154_RST_ERR_CNTR_NIT_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -# default: 0x00, access: W -@portable -def AD9154_DISABLE_ERR_CNTR_NIT_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -# default: 0x00, access: W -@portable -def AD9154_RST_IRQ_NIT_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - - -AD9154_UNEXPECTEDCONTROL_W = 0x46f -# default: 0x00, access: W -@portable -def AD9154_LANE_ADDR_UCC_SET(x: TInt32) -> TInt32: - return (x & 0x7) << 0 - -# default: 0x00, access: W -@portable -def AD9154_RST_ERR_CNTR_UCC_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -# default: 0x00, access: W -@portable -def AD9154_DISABLE_ERR_CNTR_UCC_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -# default: 0x00, access: W -@portable -def AD9154_RST_IRQ_UCC_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - - -AD9154_CODEGRPSYNCFLG = 0x470 - -AD9154_FRAMESYNCFLG = 0x471 - -AD9154_GOODCHKSUMFLG = 0x472 - -AD9154_INITLANESYNCFLG = 0x473 - -AD9154_CTRLREG1 = 0x476 - -AD9154_CTRLREG2 = 0x477 -# default: 0x00, access: R/W -@portable -def AD9154_THRESHOLD_MASK_EN_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_THRESHOLD_MASK_EN_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_ILAS_MODE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_ILAS_MODE_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_KVAL = 0x478 - -AD9154_IRQVECTOR_MASK = 0x47a -# default: 0x00, access: W -@portable -def AD9154_CODEGRPSYNC_MASK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 0 - -# default: 0x00, access: W -@portable -def AD9154_BADCHECKSUM_MASK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 2 - -# default: 0x00, access: W -@portable -def AD9154_INITIALLANESYNC_MASK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -# default: 0x00, access: W -@portable -def AD9154_UCC_MASK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -# default: 0x00, access: W -@portable -def AD9154_NIT_MASK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -# default: 0x00, access: W -@portable -def AD9154_BADDIS_MASK_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - - -AD9154_SYNCASSERTIONMASK = 0x47b -# default: 0x01, access: R/W -@portable -def AD9154_CMM_ENABLE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 3 - -@portable -def AD9154_CMM_ENABLE_GET(x: TInt32) -> TInt32: - return (x >> 3) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_CMM_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 4 - -@portable -def AD9154_CMM_GET(x: TInt32) -> TInt32: - return (x >> 4) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_UCC_S_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 5 - -@portable -def AD9154_UCC_S_GET(x: TInt32) -> TInt32: - return (x >> 5) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_NIT_S_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 6 - -@portable -def AD9154_NIT_S_GET(x: TInt32) -> TInt32: - return (x >> 6) & 0x1 - -# default: 0x00, access: R/W -@portable -def AD9154_BADDIS_S_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 7 - -@portable -def AD9154_BADDIS_S_GET(x: TInt32) -> TInt32: - return (x >> 7) & 0x1 - - -AD9154_ERRORTHRES = 0x47c - -AD9154_LANEENABLE = 0x47d - -AD9154_RAMP_ENA = 0x47e - -AD9154_DIG_TEST0 = 0x520 -# default: 0x00, access: R/W -@portable -def AD9154_DC_TEST_MODE_SET(x: TInt32) -> TInt32: - return (x & 0x1) << 1 - -@portable -def AD9154_DC_TEST_MODE_GET(x: TInt32) -> TInt32: - return (x >> 1) & 0x1 - - -AD9154_DC_TEST_VALUEI0 = 0x521 - -AD9154_DC_TEST_VALUEI1 = 0x522 - -AD9154_DC_TEST_VALUEQ0 = 0x523 - -AD9154_DC_TEST_VALUEQ1 = 0x524 diff --git a/artiq/coredevice/ad9154_spi.py b/artiq/coredevice/ad9154_spi.py deleted file mode 100644 index d83a85ff6..000000000 --- a/artiq/coredevice/ad9154_spi.py +++ /dev/null @@ -1,23 +0,0 @@ -from artiq.language.core import kernel - - -class AD9154: - """Kernel interface to AD9154 registers, using non-realtime SPI.""" - - def __init__(self, dmgr, spi_device, chip_select): - self.core = dmgr.get("core") - self.bus = dmgr.get(spi_device) - self.chip_select = chip_select - - @kernel - def setup_bus(self, div=16): - self.bus.set_config_mu(0, 24, div, self.chip_select) - - @kernel - def write(self, addr, data): - self.bus.write((addr << 16) | (data<< 8)) - - @kernel - def read(self, addr): - self.write((1 << 15) | addr, 0) - return self.bus.read() diff --git a/artiq/coredevice/basemod_att.py b/artiq/coredevice/basemod_att.py deleted file mode 100644 index 5015324ff..000000000 --- a/artiq/coredevice/basemod_att.py +++ /dev/null @@ -1,79 +0,0 @@ -from artiq.language.core import kernel, portable, delay -from artiq.language.units import us, ms -from artiq.coredevice.shiftreg import ShiftReg - - -@portable -def to_mu(att): - return round(att*2.0) ^ 0x3f - -@portable -def from_mu(att_mu): - return 0.5*(att_mu ^ 0x3f) - - -class BaseModAtt: - def __init__(self, dmgr, rst_n, clk, le, mosi, miso): - self.rst_n = dmgr.get(rst_n) - self.shift_reg = ShiftReg(dmgr, - clk=clk, ser=mosi, latch=le, ser_in=miso, n=8*4) - - @kernel - def reset(self): - # HMC's incompetence in digital design and interfaces means that - # the HMC542 needs a level low on RST_N and then a rising edge - # on Latch Enable. Their "latch" isn't a latch but a DFF. - # Of course, it also powers up with a random attenuation, and - # that cannot be fixed with simple pull-ups/pull-downs. - self.rst_n.off() - self.shift_reg.latch.off() - delay(1*us) - self.shift_reg.latch.on() - delay(1*us) - self.shift_reg.latch.off() - self.rst_n.on() - delay(1*us) - - @kernel - def set_mu(self, att0, att1, att2, att3): - """ - Sets the four attenuators on BaseMod. - The values are in half decibels, between 0 (no attenuation) - and 63 (31.5dB attenuation). - """ - word = ( - (att0 << 2) | - (att1 << 10) | - (att2 << 18) | - (att3 << 26) - ) - self.shift_reg.set(word) - - @kernel - def get_mu(self): - """ - Retrieves the current settings of the four attenuators on BaseMod. - """ - word = self.shift_reg.get() - att0 = (word >> 2) & 0x3f - att1 = (word >> 10) & 0x3f - att2 = (word >> 18) & 0x3f - att3 = (word >> 26) & 0x3f - return att0, att1, att2, att3 - - @kernel - def set(self, att0, att1, att2, att3): - """ - Sets the four attenuators on BaseMod. - The values are in decibels. - """ - self.set_mu(to_mu(att0), to_mu(att1), to_mu(att2), to_mu(att3)) - - @kernel - def get(self): - """ - Retrieves the current settings of the four attenuators on BaseMod. - The values are in decibels. - """ - att0, att1, att2, att3 = self.get_mu() - return from_mu(att0), from_mu(att1), from_mu(att2), from_mu(att3) diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py deleted file mode 100644 index 0a5905fa7..000000000 --- a/artiq/coredevice/sawg.py +++ /dev/null @@ -1,372 +0,0 @@ -""" -Driver for the Smart Arbitrary Waveform Generator (SAWG) on RTIO. - -The SAWG is an "improved DDS" built in gateware and interfacing to -high-speed DACs. - -Output event replacement is supported except on the configuration channel. -""" - - -from artiq.language.types import TInt32, TFloat -from numpy import int32, int64 -from artiq.language.core import kernel -from artiq.coredevice.spline import Spline -from artiq.coredevice.rtio import rtio_output - - -# sawg.Config addresses -_SAWG_DIV = 0 -_SAWG_CLR = 1 -_SAWG_IQ_EN = 2 -# _SAWF_PAD = 3 # reserved -_SAWG_OUT_MIN = 4 -_SAWG_OUT_MAX = 5 -_SAWG_DUC_MIN = 6 -_SAWG_DUC_MAX = 7 - - -class Config: - """SAWG configuration. - - Exposes the configurable quantities of a single SAWG channel. - - Access to the configuration registers for a SAWG channel can not - be concurrent. There must be at least :attr:`_rtio_interval` machine - units of delay between accesses. Replacement is not supported and will be - lead to an ``RTIOCollision`` as this is likely a programming error. - All methods therefore advance the timeline by the duration of one - configuration register transfer. - - :param channel: RTIO channel number of the channel. - :param core: Core device. - """ - kernel_invariants = {"channel", "core", "_out_scale", "_duc_scale", - "_rtio_interval"} - - def __init__(self, channel, core, cordic_gain=1.): - self.channel = channel - self.core = core - # normalized DAC output - self._out_scale = (1 << 15) - 1. - # normalized DAC output including DUC cordic gain - self._duc_scale = self._out_scale/cordic_gain - # configuration channel access interval - self._rtio_interval = int64(3*self.core.ref_multiplier) - - @kernel - def set_div(self, div: TInt32, n: TInt32=0): - """Set the spline evolution divider and current counter value. - - The divider and the spline evolution are synchronized across all - spline channels within a SAWG channel. The DDS/DUC phase accumulators - always evolves at full speed. - - .. note:: The spline evolution divider has not been tested extensively - and is currently considered a technological preview only. - - :param div: Spline evolution divider, such that - ``t_sawg_spline/t_rtio_coarse = div + 1``. Default: ``0``. - :param n: Current value of the counter. Default: ``0``. - """ - rtio_output((self.channel << 8) | _SAWG_DIV, div | (n << 16)) - delay_mu(self._rtio_interval) - - @kernel - def set_clr(self, clr0: TInt32, clr1: TInt32, clr2: TInt32): - """Set the accumulator clear mode for the three phase accumulators. - - When the ``clr`` bit for a given DDS/DUC phase accumulator is - set, that phase accumulator will be cleared with every phase offset - RTIO command and the output phase of the DDS/DUC will be - exactly the phase RTIO value ("absolute phase update mode"). - - .. math:: - q^\prime(t) = p^\prime + (t - t^\prime) f^\prime - - In turn, when the bit is cleared, the phase RTIO channels - determine a phase offset to the current (carrier-) value of the - DDS/DUC phase accumulator. This "relative phase update mode" is - sometimes also called “continuous phase mode”. - - .. math:: - q^\prime(t) = q(t^\prime) + (p^\prime - p) + - (t - t^\prime) f^\prime - - Where: - - * :math:`q`, :math:`q^\prime`: old/new phase accumulator - * :math:`p`, :math:`p^\prime`: old/new phase offset - * :math:`f^\prime`: new frequency - * :math:`t^\prime`: timestamp of setting new :math:`p`, :math:`f` - * :math:`t`: running time - - :param clr0: Auto-clear phase accumulator of the ``phase0``/ - ``frequency0`` DUC. Default: ``True`` - :param clr1: Auto-clear phase accumulator of the ``phase1``/ - ``frequency1`` DDS. Default: ``True`` - :param clr2: Auto-clear phase accumulator of the ``phase2``/ - ``frequency2`` DDS. Default: ``True`` - """ - rtio_output((self.channel << 8) | _SAWG_CLR, clr0 | - (clr1 << 1) | (clr2 << 2)) - delay_mu(self._rtio_interval) - - @kernel - def set_iq_en(self, i_enable: TInt32, q_enable: TInt32): - """Enable I/Q data on this DAC channel. - - Every pair of SAWG channels forms a buddy pair. - The ``iq_en`` configuration controls which DDS data is emitted to the - DACs. - - Refer to the documentation of :class:`SAWG` for a mathematical - description of ``i_enable`` and ``q_enable``. - - .. note:: Quadrature data from the buddy channel is currently - a technological preview only. The data is ignored in the SAWG - gateware and not added to the DAC output. - This is equivalent to the ``q_enable`` switch always being ``0``. - - :param i_enable: Controls adding the in-phase - DUC-DDS data of *this* SAWG channel to *this* DAC channel. - Default: ``1``. - :param q_enable: controls adding the quadrature - DUC-DDS data of this SAWG's *buddy* channel to *this* DAC - channel. Default: ``0``. - """ - rtio_output((self.channel << 8) | _SAWG_IQ_EN, i_enable | - (q_enable << 1)) - delay_mu(self._rtio_interval) - - @kernel - def set_duc_max_mu(self, limit: TInt32): - """Set the digital up-converter (DUC) I and Q data summing junctions - upper limit. In machine units. - - The default limits are chosen to reach maximum and minimum DAC output - amplitude. - - For a description of the limiter functions in normalized units see: - - .. seealso:: :meth:`set_duc_max` - """ - rtio_output((self.channel << 8) | _SAWG_DUC_MAX, limit) - delay_mu(self._rtio_interval) - - @kernel - def set_duc_min_mu(self, limit: TInt32): - """.. seealso:: :meth:`set_duc_max_mu`""" - rtio_output((self.channel << 8) | _SAWG_DUC_MIN, limit) - delay_mu(self._rtio_interval) - - @kernel - def set_out_max_mu(self, limit: TInt32): - """.. seealso:: :meth:`set_duc_max_mu`""" - rtio_output((self.channel << 8) | _SAWG_OUT_MAX, limit) - delay_mu(self._rtio_interval) - - @kernel - def set_out_min_mu(self, limit: TInt32): - """.. seealso:: :meth:`set_duc_max_mu`""" - rtio_output((self.channel << 8) | _SAWG_OUT_MIN, limit) - delay_mu(self._rtio_interval) - - @kernel - def set_duc_max(self, limit: TFloat): - """Set the digital up-converter (DUC) I and Q data summing junctions - upper limit. - - Each of the three summing junctions has a saturating adder with - configurable upper and lower limits. The three summing junctions are: - - * At the in-phase input to the ``phase0``/``frequency0`` fast DUC, - after the anti-aliasing FIR filter. - * At the quadrature input to the ``phase0``/``frequency0`` - fast DUC, after the anti-aliasing FIR filter. The in-phase and - quadrature data paths both use the same limits. - * Before the DAC, where the following three data streams - are added together: - - * the output of the ``offset`` spline, - * (optionally, depending on ``i_enable``) the in-phase output - of the ``phase0``/``frequency0`` fast DUC, and - * (optionally, depending on ``q_enable``) the quadrature - output of the ``phase0``/``frequency0`` fast DUC of the - buddy channel. - - Refer to the documentation of :class:`SAWG` for a mathematical - description of the summing junctions. - - :param limit: Limit value ``[-1, 1]``. The output of the limiter will - never exceed this limit. The default limits are the full range - ``[-1, 1]``. - - .. seealso:: - * :meth:`set_duc_max`: Upper limit of the in-phase and quadrature - inputs to the DUC. - * :meth:`set_duc_min`: Lower limit of the in-phase and quadrature - inputs to the DUC. - * :meth:`set_out_max`: Upper limit of the DAC output. - * :meth:`set_out_min`: Lower limit of the DAC output. - """ - self.set_duc_max_mu(int32(round(limit*self._duc_scale))) - - @kernel - def set_duc_min(self, limit: TFloat): - """.. seealso:: :meth:`set_duc_max`""" - self.set_duc_min_mu(int32(round(limit*self._duc_scale))) - - @kernel - def set_out_max(self, limit: TFloat): - """.. seealso:: :meth:`set_duc_max`""" - self.set_out_max_mu(int32(round(limit*self._out_scale))) - - @kernel - def set_out_min(self, limit: TFloat): - """.. seealso:: :meth:`set_duc_max`""" - self.set_out_min_mu(int32(round(limit*self._out_scale))) - - -class SAWG: - """Smart arbitrary waveform generator channel. - The channel is parametrized as: :: - - oscillators = exp(2j*pi*(frequency0*t + phase0))*( - amplitude1*exp(2j*pi*(frequency1*t + phase1)) + - amplitude2*exp(2j*pi*(frequency2*t + phase2))) - - output = (offset + - i_enable*Re(oscillators) + - q_enable*Im(buddy_oscillators)) - - This parametrization can be viewed as two complex (quadrature) oscillators - (``frequency1``/``phase1`` and ``frequency2``/``phase2``) that are - executing and sampling at the coarse RTIO frequency. They can represent - frequencies within the first Nyquist zone from ``-f_rtio_coarse/2`` to - ``f_rtio_coarse/2``. - - .. note:: The coarse RTIO frequency ``f_rtio_coarse`` is the inverse of - ``ref_period*multiplier``. Both are arguments of the ``Core`` device, - specified in the device database ``device_db.py``. - - The sum of their outputs is then interpolated by a factor of - :attr:`parallelism` (2, 4, 8 depending on the bitstream) using a - finite-impulse-response (FIR) anti-aliasing filter (more accurately - a half-band filter). - - The filter is followed by a configurable saturating limiter. - - After the limiter, the data is shifted in frequency using a complex - digital up-converter (DUC, ``frequency0``/``phase0``) running at - :attr:`parallelism` times the coarse RTIO frequency. The first Nyquist - zone of the DUC extends from ``-f_rtio_coarse*parallelism/2`` to - ``f_rtio_coarse*parallelism/2``. Other Nyquist zones are usable depending - on the interpolation/modulation options configured in the DAC. - - The real/in-phase data after digital up-conversion can be offset using - another spline interpolator ``offset``. - - The ``i_enable``/``q_enable`` switches enable emission of quadrature - signals for later analog quadrature mixing distinguishing upper and lower - sidebands and thus doubling the bandwidth. They can also be used to emit - four-tone signals. - - .. note:: Quadrature data from the buddy channel is currently - ignored in the SAWG gateware and not added to the DAC output. - This is equivalent to the ``q_enable`` switch always being ``0``. - - The configuration channel and the nine - :class:`artiq.coredevice.spline.Spline` interpolators are accessible as - attributes: - - * :attr:`config`: :class:`Config` - * :attr:`offset`, :attr:`amplitude1`, :attr:`amplitude2`: in units - of full scale - * :attr:`phase0`, :attr:`phase1`, :attr:`phase2`: in units of turns - * :attr:`frequency0`, :attr:`frequency1`, :attr:`frequency2`: in units - of Hz - - .. note:: The latencies (pipeline depths) of the nine data channels (i.e. - all except :attr:`config`) are matched. Equivalent channels (e.g. - :attr:`phase1` and :attr:`phase2`) are exactly matched. Channels of - different type or functionality (e.g. :attr:`offset` vs - :attr:`amplitude1`, DDS vs DUC, :attr:`phase0` vs :attr:`phase1`) are - only matched to within one coarse RTIO cycle. - - :param channel_base: RTIO channel number of the first channel (amplitude). - The configuration channel and frequency/phase/amplitude channels are - then assumed to be successive channels. - :param parallelism: Number of output samples per coarse RTIO clock cycle. - :param core_device: Name of the core device that this SAWG is on. - """ - kernel_invariants = {"channel_base", "core", "parallelism", - "amplitude1", "frequency1", "phase1", - "amplitude2", "frequency2", "phase2", - "frequency0", "phase0", "offset"} - - def __init__(self, dmgr, channel_base, parallelism, core_device="core"): - self.core = dmgr.get(core_device) - self.channel_base = channel_base - self.parallelism = parallelism - width = 16 - time_width = 16 - cordic_gain = 1.646760258057163 # Cordic(width=16, guard=None).gain - head_room = 1.001 - self.config = Config(channel_base, self.core, cordic_gain) - self.offset = Spline(width, time_width, channel_base + 1, - self.core, 2.*head_room) - self.amplitude1 = Spline(width, time_width, channel_base + 2, - self.core, 2*head_room*cordic_gain**2) - self.frequency1 = Spline(3*width, time_width, channel_base + 3, - self.core, 1/self.core.coarse_ref_period) - self.phase1 = Spline(width, time_width, channel_base + 4, - self.core, 1.) - self.amplitude2 = Spline(width, time_width, channel_base + 5, - self.core, 2*head_room*cordic_gain**2) - self.frequency2 = Spline(3*width, time_width, channel_base + 6, - self.core, 1/self.core.coarse_ref_period) - self.phase2 = Spline(width, time_width, channel_base + 7, - self.core, 1.) - self.frequency0 = Spline(2*width, time_width, channel_base + 8, - self.core, - parallelism/self.core.coarse_ref_period) - self.phase0 = Spline(width, time_width, channel_base + 9, - self.core, 1.) - - @kernel - def reset(self): - """Re-establish initial conditions. - - This clears all spline interpolators, accumulators and configuration - settings. - - This method advances the timeline by the time required to perform all - 7 writes to the configuration channel, plus 9 coarse RTIO cycles. - """ - self.config.set_div(0, 0) - self.config.set_clr(1, 1, 1) - self.config.set_iq_en(1, 0) - self.config.set_duc_min(-1.) - self.config.set_duc_max(1.) - self.config.set_out_min(-1.) - self.config.set_out_max(1.) - self.frequency0.set_mu(0) - coarse_cycle = int64(self.core.ref_multiplier) - delay_mu(coarse_cycle) - self.frequency1.set_mu(0) - delay_mu(coarse_cycle) - self.frequency2.set_mu(0) - delay_mu(coarse_cycle) - self.phase0.set_mu(0) - delay_mu(coarse_cycle) - self.phase1.set_mu(0) - delay_mu(coarse_cycle) - self.phase2.set_mu(0) - delay_mu(coarse_cycle) - self.amplitude1.set_mu(0) - delay_mu(coarse_cycle) - self.amplitude2.set_mu(0) - delay_mu(coarse_cycle) - self.offset.set_mu(0) - delay_mu(coarse_cycle) diff --git a/artiq/coredevice/shiftreg.py b/artiq/coredevice/shiftreg.py deleted file mode 100644 index 79000eba3..000000000 --- a/artiq/coredevice/shiftreg.py +++ /dev/null @@ -1,54 +0,0 @@ -from artiq.language.core import kernel, delay -from artiq.language.units import us - - -class ShiftReg: - """Driver for shift registers/latch combos connected to TTLs""" - kernel_invariants = {"dt", "n"} - - def __init__(self, dmgr, clk, ser, latch, n=32, dt=10*us, ser_in=None): - self.core = dmgr.get("core") - self.clk = dmgr.get(clk) - self.ser = dmgr.get(ser) - self.latch = dmgr.get(latch) - self.n = n - self.dt = dt - if ser_in is not None: - self.ser_in = dmgr.get(ser_in) - - @kernel - def set(self, data): - """Sets the values of the latch outputs. This does not - advance the timeline and the waveform is generated before - `now`.""" - delay(-2*(self.n + 1)*self.dt) - for i in range(self.n): - if (data >> (self.n-i-1)) & 1 == 0: - self.ser.off() - else: - self.ser.on() - self.clk.off() - delay(self.dt) - self.clk.on() - delay(self.dt) - self.clk.off() - self.latch.on() - delay(self.dt) - self.latch.off() - delay(self.dt) - - @kernel - def get(self): - delay(-2*(self.n + 1)*self.dt) - data = 0 - for i in range(self.n): - data <<= 1 - self.ser_in.sample_input() - if self.ser_in.sample_get(): - data |= 1 - delay(self.dt) - self.clk.on() - delay(self.dt) - self.clk.off() - delay(self.dt) - return data diff --git a/artiq/coredevice/spline.py b/artiq/coredevice/spline.py deleted file mode 100644 index 9f8310d1e..000000000 --- a/artiq/coredevice/spline.py +++ /dev/null @@ -1,228 +0,0 @@ -from numpy import int32, int64 -from artiq.language.core import kernel, portable, delay -from artiq.coredevice.rtio import rtio_output, rtio_output_wide -from artiq.language.types import TInt32, TInt64, TFloat - - -class Spline: - r"""Spline interpolating RTIO channel. - - One knot of a polynomial basis spline (B-spline) :math:`u(t)` - is defined by the coefficients :math:`u_n` up to order :math:`n = k`. - If the coefficients are evaluated starting at time :math:`t_0`, - the output :math:`u(t)` for :math:`t > t_0, t_0` is: - - .. math:: - u(t) &= \sum_{n=0}^k \frac{u_n}{n!} (t - t_0)^n \\ - &= u_0 + u_1 (t - t_0) + \frac{u_2}{2} (t - t_0)^2 + \dots - - This class contains multiple methods to convert spline knot data from SI - to machine units and multiple methods that set the current spline - coefficient data. None of these advance the timeline. The :meth:`smooth` - method is the only method that advances the timeline. - - :param width: Width in bits of the quantity that this spline controls - :param time_width: Width in bits of the time counter of this spline - :param channel: RTIO channel number - :param core_device: Core device that this spline is attached to - :param scale: Scale for conversion between machine units and physical - units; to be given as the "full scale physical value". - """ - - kernel_invariants = {"channel", "core", "scale", "width", - "time_width", "time_scale"} - - def __init__(self, width, time_width, channel, core_device, scale=1.): - self.core = core_device - self.channel = channel - self.width = width - self.scale = float((int64(1) << width) / scale) - self.time_width = time_width - self.time_scale = float((1 << time_width) * - core_device.coarse_ref_period) - - @portable(flags={"fast-math"}) - def to_mu(self, value: TFloat) -> TInt32: - """Convert floating point ``value`` from physical units to 32 bit - integer machine units.""" - return int32(round(value*self.scale)) - - @portable(flags={"fast-math"}) - def from_mu(self, value: TInt32) -> TFloat: - """Convert 32 bit integer ``value`` from machine units to floating - point physical units.""" - return value/self.scale - - @portable(flags={"fast-math"}) - def to_mu64(self, value: TFloat) -> TInt64: - """Convert floating point ``value`` from physical units to 64 bit - integer machine units.""" - return int64(round(value*self.scale)) - - @kernel - def set_mu(self, value: TInt32): - """Set spline value (machine units). - - :param value: Spline value in integer machine units. - """ - rtio_output(self.channel << 8, value) - - @kernel(flags={"fast-math"}) - def set(self, value: TFloat): - """Set spline value. - - :param value: Spline value relative to full-scale. - """ - if self.width > 32: - l = [int32(0)] * 2 - self.pack_coeff_mu([self.to_mu64(value)], l) - rtio_output_wide(self.channel << 8, l) - else: - rtio_output(self.channel << 8, self.to_mu(value)) - - @kernel - def set_coeff_mu(self, value): # TList(TInt32) - """Set spline raw values. - - :param value: Spline packed raw values. - """ - rtio_output_wide(self.channel << 8, value) - - @portable(flags={"fast-math"}) - def pack_coeff_mu(self, coeff, packed): # TList(TInt64), TList(TInt32) - """Pack coefficients into RTIO data - - :param coeff: TList(TInt64) list of machine units spline coefficients. - Lowest (zeroth) order first. The coefficient list is zero-extended - by the RTIO gateware. - :param packed: TList(TInt32) list for packed RTIO data. Must be - pre-allocated. Length in bits is - ``n*width + (n - 1)*n//2*time_width`` - """ - pos = 0 - for i in range(len(coeff)): - wi = self.width + i*self.time_width - ci = coeff[i] - while wi != 0: - j = pos//32 - used = pos - 32*j - avail = 32 - used - if avail > wi: - avail = wi - cij = int32(ci) - if avail != 32: - cij &= (1 << avail) - 1 - packed[j] |= cij << used - ci >>= avail - wi -= avail - pos += avail - - @portable(flags={"fast-math"}) - def coeff_to_mu(self, coeff, coeff64): # TList(TFloat), TList(TInt64) - """Convert a floating point list of coefficients into a 64 bit - integer (preallocated). - - :param coeff: TList(TFloat) list of coefficients in physical units. - :param coeff64: TList(TInt64) preallocated list of coefficients in - machine units. - """ - for i in range(len(coeff)): - vi = coeff[i] * self.scale - for j in range(i): - vi *= self.time_scale - ci = int64(round(vi)) - coeff64[i] = ci - # artiq.wavesynth.coefficients.discrete_compensate: - if i == 2: - coeff64[1] += ci >> self.time_width + 1 - elif i == 3: - coeff64[2] += ci >> self.time_width - coeff64[1] += ci // 6 >> 2*self.time_width - - def coeff_as_packed_mu(self, coeff64): - """Pack 64 bit integer machine units coefficients into 32 bit integer - RTIO data list. - - This is a host-only method that can be used to generate packed - spline coefficient data to be frozen into kernels at compile time. - """ - n = len(coeff64) - width = n*self.width + (n - 1)*n//2*self.time_width - packed = [int32(0)] * ((width + 31)//32) - self.pack_coeff_mu(coeff64, packed) - return packed - - def coeff_as_packed(self, coeff): - """Convert floating point spline coefficients into 32 bit integer - packed data. - - This is a host-only method that can be used to generate packed - spline coefficient data to be frozen into kernels at compile time. - """ - coeff64 = [int64(0)] * len(coeff) - self.coeff_to_mu(coeff, coeff64) - return self.coeff_as_packed_mu(coeff64) - - @kernel(flags={"fast-math"}) - def set_coeff(self, coeff): # TList(TFloat) - """Set spline coefficients. - - Missing coefficients (high order) are zero-extended byt the RTIO - gateware. - - If more coefficients are supplied than the gateware supports the extra - coefficients are ignored. - - :param value: List of floating point spline coefficients, - lowest order (constant) coefficient first. Units are the - unit of this spline's value times increasing powers of 1/s. - """ - n = len(coeff) - coeff64 = [int64(0)] * n - self.coeff_to_mu(coeff, coeff64) - width = n*self.width + (n - 1)*n//2*self.time_width - packed = [int32(0)] * ((width + 31)//32) - self.pack_coeff_mu(coeff64, packed) - self.set_coeff_mu(packed) - - @kernel(flags={"fast-math"}) - def smooth(self, start: TFloat, stop: TFloat, duration: TFloat, - order: TInt32): - """Initiate an interpolated value change. - - For zeroth order (step) interpolation, the step is at - ``start + duration/2``. - - First order interpolation corresponds to a linear value ramp from - ``start`` to ``stop`` over ``duration``. - - The third order interpolation is constrained to have zero first - order derivative at both `start` and `stop`. - - For first order and third order interpolation (linear and cubic) - the interpolator needs to be stopped explicitly at the stop time - (e.g. by setting spline coefficient data or starting a new - :meth:`smooth` interpolation). - - This method advances the timeline by ``duration``. - - :param start: Initial value of the change. In physical units. - :param stop: Final value of the change. In physical units. - :param duration: Duration of the interpolation. In physical units. - :param order: Order of the interpolation. Only 0, 1, - and 3 are valid: step, linear, cubic. - """ - if order == 0: - delay(duration/2.) - self.set_coeff([stop]) - delay(duration/2.) - elif order == 1: - self.set_coeff([start, (stop - start)/duration]) - delay(duration) - elif order == 3: - v2 = 6.*(stop - start)/(duration*duration) - self.set_coeff([start, 0., v2, -2.*v2/duration]) - delay(duration) - else: - raise ValueError("Invalid interpolation order. " - "Supported orders are: 0, 1, 3.") diff --git a/artiq/examples/kasli_sawgmaster/device_db.py b/artiq/examples/kasli_sawgmaster/device_db.py deleted file mode 100644 index 1c555fdea..000000000 --- a/artiq/examples/kasli_sawgmaster/device_db.py +++ /dev/null @@ -1,184 +0,0 @@ -core_addr = "192.168.1.70" - -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": core_addr, "ref_period": 1/(8*150e6)} - }, - "core_log": { - "type": "controller", - "host": "::1", - "port": 1068, - "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr - }, - "core_moninj": { - "type": "controller", - "host": "::1", - "port_proxy": 1383, - "port": 1384, - "command": "aqctl_moninj_proxy --port-proxy {port_proxy} --port-control {port} --bind {bind} " + core_addr - }, - "core_cache": { - "type": "local", - "module": "artiq.coredevice.cache", - "class": "CoreCache" - }, - "core_dma": { - "type": "local", - "module": "artiq.coredevice.dma", - "class": "CoreDMA" - }, -} - -device_db.update( - spi_urukul0={ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 0} - }, - ttl_urukul0_io_update={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 1} - }, - ttl_urukul0_sw0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 2} - }, - ttl_urukul0_sw1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 3} - }, - ttl_urukul0_sw2={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 4} - }, - ttl_urukul0_sw3={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 5} - }, - urukul0_cpld={ - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul0", - "io_update_device": "ttl_urukul0_io_update", - "refclk": 150e6, - "clk_sel": 2 - } - } -) - -for i in range(4): - device_db["urukul0_ch" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 16, # 600MHz sample rate - "pll_vco": 2, - "chip_select": 4 + i, - "cpld_device": "urukul0_cpld", - "sw_device": "ttl_urukul0_sw" + str(i) - } - } - -""" -artiq_route routing.bin init -artiq_route routing.bin set 0 0 -artiq_route routing.bin set 1 1 0 -artiq_route routing.bin set 2 1 1 0 -artiq_route routing.bin set 3 2 0 -artiq_route routing.bin set 4 2 1 0 -artiq_coremgmt -D kasli config write -f routing_table routing.bin -""" - -for sayma in range(2): - amc_base = 0x010000 + sayma*0x020000 - rtm_base = 0x020000 + sayma*0x020000 - for i in range(4): - device_db["led" + str(4*sayma+i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": amc_base + i} - } - for i in range(2): - device_db["ttl_mcx" + str(2*sayma+i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLInOut", - "arguments": {"channel": amc_base + 4 + i} - } - for i in range(8): - device_db["sawg" + str(8*sayma+i)] = { - "type": "local", - "module": "artiq.coredevice.sawg", - "class": "SAWG", - "arguments": {"channel_base": amc_base + 6 + i*10, "parallelism": 4} - } - for basemod in range(2): - for i in range(4): - device_db["sawg_sw" + str(8*sayma+4*basemod+i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": rtm_base + basemod*9 + i} - } - att_idx = 2*sayma + basemod - device_db["basemod_att_rst_n"+str(att_idx)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": rtm_base + basemod*9 + 4} - } - device_db["basemod_att_clk"+str(att_idx)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": rtm_base + basemod*9 + 5} - } - device_db["basemod_att_le"+str(att_idx)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": rtm_base + basemod*9 + 6} - } - device_db["basemod_att_mosi"+str(att_idx)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": rtm_base + basemod*9 + 7} - } - device_db["basemod_att_miso"+str(att_idx)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLInOut", - "arguments": {"channel": rtm_base + basemod*9 + 8} - } - device_db["basemod_att"+str(att_idx)] = { - "type": "local", - "module": "artiq.coredevice.basemod_att", - "class": "BaseModAtt", - "arguments": { - "rst_n": "basemod_att_rst_n"+str(att_idx), - "clk": "basemod_att_clk"+str(att_idx), - "le": "basemod_att_le"+str(att_idx), - "mosi": "basemod_att_mosi"+str(att_idx), - "miso": "basemod_att_miso"+str(att_idx), - } - } - diff --git a/artiq/examples/kasli_sawgmaster/repository/basemod.py b/artiq/examples/kasli_sawgmaster/repository/basemod.py deleted file mode 100644 index 3ca9a1c86..000000000 --- a/artiq/examples/kasli_sawgmaster/repository/basemod.py +++ /dev/null @@ -1,25 +0,0 @@ -from artiq.experiment import * - - -class BaseMod(EnvExperiment): - def build(self): - self.setattr_device("core") - self.basemods = [self.get_device("basemod_att0"), self.get_device("basemod_att1")] - self.rfsws = [self.get_device("sawg_sw"+str(i)) for i in range(8)] - - @kernel - def run(self): - self.core.reset() - for basemod in self.basemods: - self.core.break_realtime() - delay(10*ms) - basemod.reset() - delay(10*ms) - basemod.set(0.0, 0.0, 0.0, 0.0) - delay(10*ms) - print(basemod.get_mu()) - - self.core.break_realtime() - for rfsw in self.rfsws: - rfsw.on() - delay(1*ms) diff --git a/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py b/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py deleted file mode 100644 index 3a8204941..000000000 --- a/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py +++ /dev/null @@ -1,37 +0,0 @@ -from artiq.experiment import * - - -class Sines2Sayma(EnvExperiment): - def build(self): - self.setattr_device("core") - self.sawgs = [self.get_device("sawg"+str(i)) for i in range(16)] - - @kernel - def drtio_is_up(self): - for i in range(5): - if not self.core.get_rtio_destination_status(i): - return False - return True - - @kernel - def run(self): - while True: - print("waiting for DRTIO ready...") - while not self.drtio_is_up(): - pass - print("OK") - - self.core.reset() - - for sawg in self.sawgs: - delay(1*ms) - sawg.reset() - - for sawg in self.sawgs: - delay(1*ms) - sawg.amplitude1.set(.4) - # Do not use a sub-multiple of oscilloscope sample rates. - sawg.frequency0.set(9*MHz) - - while self.drtio_is_up(): - pass diff --git a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py deleted file mode 100644 index dfd8e46c9..000000000 --- a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py +++ /dev/null @@ -1,89 +0,0 @@ -from artiq.experiment import * - - -class SinesUrukulSayma(EnvExperiment): - def build(self): - self.setattr_device("core") - self.setattr_device("urukul0_cpld") - - # Urukul clock output syntonized to the RTIO clock. - # Can be used as HMC830 reference on Sayma RTM. - # When using this reference, Sayma must be recalibrated every time Urukul - # is rebooted, as Urukul is not synchronized to the Kasli. - self.urukul_hmc_ref = self.get_device("urukul0_ch3") - - # Urukul measurement channels - compare with SAWG outputs. - # When testing sync, do not reboot Urukul, as it is not - # synchronized to the Kasli. - self.urukul_meas = [self.get_device("urukul0_ch" + str(i)) for i in range(3)] - # The same waveform is output on all first 4 SAWG channels (first DAC). - self.sawgs = [self.get_device("sawg"+str(i)) for i in range(4)] - self.basemod = self.get_device("basemod_att0") - self.rfsws = [self.get_device("sawg_sw"+str(i)) for i in range(4)] - - - # DRTIO destinations: - # 0: local - # 1: Sayma AMC - # 2: Sayma RTM - @kernel - def drtio_is_up(self): - for i in range(3): - if not self.core.get_rtio_destination_status(i): - return False - return True - - @kernel - def run(self): - f = 9*MHz - dds_ftw = self.urukul_meas[0].frequency_to_ftw(f) - sawg_ftw = self.sawgs[0].frequency0.to_mu(f) - if dds_ftw != sawg_ftw: - print("DDS and SAWG FTWs do not match:", dds_ftw, sawg_ftw) - return - - self.core.reset() - self.urukul0_cpld.init() - - delay(1*ms) - self.urukul_hmc_ref.init() - self.urukul_hmc_ref.set_mu(0x40000000, asf=self.urukul_hmc_ref.amplitude_to_asf(0.6)) - self.urukul_hmc_ref.set_att(6.) - self.urukul_hmc_ref.sw.on() - - for urukul_ch in self.urukul_meas: - delay(1*ms) - urukul_ch.init() - urukul_ch.set_mu(dds_ftw, asf=urukul_ch.amplitude_to_asf(0.5)) - urukul_ch.set_att(6.) - urukul_ch.sw.on() - - while True: - print("waiting for DRTIO ready...") - while not self.drtio_is_up(): - pass - print("OK") - - self.core.reset() - - delay(10*ms) - self.basemod.reset() - delay(10*ms) - self.basemod.set(3.0, 3.0, 3.0, 3.0) - delay(10*ms) - for rfsw in self.rfsws: - delay(1*ms) - rfsw.on() - - for sawg in self.sawgs: - delay(1*ms) - sawg.reset() - - for sawg in self.sawgs: - delay(1*ms) - sawg.amplitude1.set(.4) - sawg.frequency0.set_mu(sawg_ftw) - sawg.phase0.set_mu(sawg_ftw*now_mu() >> 17) - - while self.drtio_is_up(): - pass diff --git a/artiq/examples/metlino_sayma_ttl/device_db.py b/artiq/examples/metlino_sayma_ttl/device_db.py deleted file mode 100644 index 317173cd3..000000000 --- a/artiq/examples/metlino_sayma_ttl/device_db.py +++ /dev/null @@ -1,102 +0,0 @@ -core_addr = "192.168.1.65" - -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": core_addr, "ref_period": 1/(8*150e6)} - }, - "core_log": { - "type": "controller", - "host": "::1", - "port": 1068, - "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr - }, - "core_moninj": { - "type": "controller", - "host": "::1", - "port_proxy": 1383, - "port": 1384, - "command": "aqctl_moninj_proxy --port-proxy {port_proxy} --port-control {port} --bind {bind} " + core_addr - }, - "core_cache": { - "type": "local", - "module": "artiq.coredevice.cache", - "class": "CoreCache" - }, - "core_dma": { - "type": "local", - "module": "artiq.coredevice.dma", - "class": "CoreDMA" - } -} - -# master peripherals -for i in range(4): - device_db["led" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": i}, -} - -# DEST#1 peripherals -amc_base = 0x070000 -rtm_base = 0x020000 - -for i in range(4): - device_db["led" + str(4+i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": amc_base + i}, - } - -#DIO (EEM0) starting at RTIO channel 0x000056 -for i in range(8): - device_db["ttl" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": amc_base + 0x000056 + i}, - } - -#DIO (EEM1) starting at RTIO channel 0x00005e -for i in range(8): - device_db["ttl" + str(8+i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": amc_base + 0x00005e + i}, - } - -device_db["fmcdio_dirctl_clk"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": amc_base + 0x000066} -} - -device_db["fmcdio_dirctl_ser"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": amc_base + 0x000067} -} - -device_db["fmcdio_dirctl_latch"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": amc_base + 0x000068} -} - -device_db["fmcdio_dirctl"] = { - "type": "local", - "module": "artiq.coredevice.shiftreg", - "class": "ShiftReg", - "arguments": {"clk": "fmcdio_dirctl_clk", - "ser": "fmcdio_dirctl_ser", - "latch": "fmcdio_dirctl_latch"} -} diff --git a/artiq/examples/metlino_sayma_ttl/repository/demo.py b/artiq/examples/metlino_sayma_ttl/repository/demo.py deleted file mode 100644 index bb273ce2c..000000000 --- a/artiq/examples/metlino_sayma_ttl/repository/demo.py +++ /dev/null @@ -1,129 +0,0 @@ -import sys -import os -import select - -from artiq.experiment import * -from artiq.coredevice.fmcdio_vhdci_eem import * - - -def chunker(seq, size): - res = [] - for el in seq: - res.append(el) - if len(res) == size: - yield res - res = [] - if res: - yield res - - -def is_enter_pressed() -> TBool: - if os.name == "nt": - if msvcrt.kbhit() and msvcrt.getch() == b"\r": - return True - else: - return False - else: - if select.select([sys.stdin, ], [], [], 0.0)[0]: - sys.stdin.read(1) - return True - else: - return False - - -class Demo(EnvExperiment): - def build(self): - self.setattr_device("core") - self.setattr_device("fmcdio_dirctl") - - self.leds = dict() - self.ttl_outs = dict() - - ddb = self.get_device_db() - for name, desc in ddb.items(): - if isinstance(desc, dict) and desc["type"] == "local": - module, cls = desc["module"], desc["class"] - if (module, cls) == ("artiq.coredevice.ttl", "TTLOut"): - dev = self.get_device(name) - if "led" in name: # guess - self.leds[name] = dev - elif "ttl" in name: # to exclude fmcdio_dirctl - self.ttl_outs[name] = dev - - self.leds = sorted(self.leds.items(), key=lambda x: x[1].channel) - self.ttl_outs = sorted(self.ttl_outs.items(), key=lambda x: x[1].channel) - - self.dirctl_word = ( - shiftreg_bits(0, dio_bank0_out_pins | dio_bank1_out_pins) | - shiftreg_bits(1, dio_bank0_out_pins | dio_bank1_out_pins) - ) - - @kernel - def init(self): - self.core.break_realtime() - print("*** Waiting for DRTIO ready...") - drtio_indices = [7] - for i in drtio_indices: - while not self.drtio_is_up(i): - pass - - self.fmcdio_dirctl.set(self.dirctl_word) - - @kernel - def drtio_is_up(self, drtio_index): - if not self.core.get_rtio_destination_status(drtio_index): - return False - print("DRTIO #", drtio_index, "is ready\n") - return True - - @kernel - def test_led(self, led): - while not is_enter_pressed(): - self.core.break_realtime() - # do not fill the FIFOs too much to avoid long response times - t = now_mu() - self.core.seconds_to_mu(0.2) - while self.core.get_rtio_counter_mu() < t: - pass - for i in range(3): - led.pulse(100*ms) - delay(100*ms) - - def test_leds(self): - print("*** Testing LEDs.") - print("Check for blinking. Press ENTER when done.") - - for led_name, led_dev in self.leds: - print("Testing LED: {}".format(led_name)) - self.test_led(led_dev) - - @kernel - def test_ttl_out_chunk(self, ttl_chunk): - while not is_enter_pressed(): - self.core.break_realtime() - for _ in range(50000): - i = 0 - for ttl in ttl_chunk: - i += 1 - for _ in range(i): - ttl.pulse(1*us) - delay(1*us) - delay(10*us) - - def test_ttl_outs(self): - print("*** Testing TTL outputs.") - print("Outputs are tested in groups of 4. Touch each TTL connector") - print("with the oscilloscope probe tip, and check that the number of") - print("pulses corresponds to its number in the group.") - print("Press ENTER when done.") - - for ttl_chunk in chunker(self.ttl_outs, 4): - print("Testing TTL outputs: {}.".format(", ".join(name for name, dev in ttl_chunk))) - self.test_ttl_out_chunk([dev for name, dev in ttl_chunk]) - - def run(self): - self.core.reset() - - if self.leds: - self.test_leds() - if self.ttl_outs: - self.test_ttl_outs() diff --git a/artiq/examples/sayma_master/device_db.py b/artiq/examples/sayma_master/device_db.py deleted file mode 100644 index 4ce3f1be0..000000000 --- a/artiq/examples/sayma_master/device_db.py +++ /dev/null @@ -1,173 +0,0 @@ -core_addr = "192.168.1.60" - -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": core_addr, "ref_period": 1/(8*150e6)} - }, - "core_log": { - "type": "controller", - "host": "::1", - "port": 1068, - "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr - }, - "core_moninj": { - "type": "controller", - "host": "::1", - "port_proxy": 1383, - "port": 1384, - "command": "aqctl_moninj_proxy --port-proxy {port_proxy} --port-control {port} --bind {bind} " + core_addr - }, - "core_cache": { - "type": "local", - "module": "artiq.coredevice.cache", - "class": "CoreCache" - }, - "core_dma": { - "type": "local", - "module": "artiq.coredevice.dma", - "class": "CoreDMA" - }, -} - -for i in range(4): - device_db["led" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": i}, - } - - -for i in range(2): - device_db["ttl" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLInOut", - "arguments": {"channel": 4 + i}, - } - - -device_db.update( - fmcdio_dirctl_clk={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 6} - }, - fmcdio_dirctl_ser={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 7} - }, - fmcdio_dirctl_latch={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 8} - }, - fmcdio_dirctl={ - "type": "local", - "module": "artiq.coredevice.shiftreg", - "class": "ShiftReg", - "arguments": {"clk": "fmcdio_dirctl_clk", - "ser": "fmcdio_dirctl_ser", - "latch": "fmcdio_dirctl_latch"} - } -) - -device_db.update( - spi_urukul0={ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 17} - }, - ttl_urukul0_io_update={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 18} - }, - ttl_urukul0_sw0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 19} - }, - ttl_urukul0_sw1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 20} - }, - ttl_urukul0_sw2={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 21} - }, - ttl_urukul0_sw3={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 22} - }, - urukul0_cpld={ - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul0", - "io_update_device": "ttl_urukul0_io_update", - "refclk": 125e6, - "clk_sel": 0 - } - } -) - -for i in range(4): - device_db["urukul0_ch" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 32, - "chip_select": 4 + i, - "cpld_device": "urukul0_cpld", - "sw_device": "ttl_urukul0_sw" + str(i) - } - } - - -device_db["spi_zotino0"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 23} -} -device_db["ttl_zotino0_ldac"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 24} -} -device_db["ttl_zotino0_clr"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 25} -} -device_db["zotino0"] = { - "type": "local", - "module": "artiq.coredevice.zotino", - "class": "Zotino", - "arguments": { - "spi_device": "spi_zotino0", - "ldac_device": "ttl_zotino0_ldac", - "clr_device": "ttl_zotino0_clr" - } -} diff --git a/artiq/examples/sayma_master/repository/demo.py b/artiq/examples/sayma_master/repository/demo.py deleted file mode 100644 index 9b40f4b42..000000000 --- a/artiq/examples/sayma_master/repository/demo.py +++ /dev/null @@ -1,41 +0,0 @@ -from artiq.experiment import * -from artiq.coredevice.fmcdio_vhdci_eem import * - - -class Demo(EnvExperiment): - def build(self): - self.setattr_device("core") - self.setattr_device("fmcdio_dirctl") - - self.ttls = [self.get_device("ttl" + str(i)) for i in range(8)] - self.setattr_device("urukul0_cpld") - self.urukul_chs = [self.get_device("urukul0_ch" + str(i)) for i in range(4)] - self.setattr_device("zotino0") - - self.dirctl_word = ( - shiftreg_bits(1, urukul_out_pins) | - shiftreg_bits(0, urukul_aux_out_pins) | - shiftreg_bits(2, dio_bank0_out_pins | dio_bank1_out_pins) | - shiftreg_bits(3, zotino_out_pins)) - - @kernel - def run(self): - self.core.reset() - delay(10*ms) - self.fmcdio_dirctl.set(self.dirctl_word) - delay(10*ms) - - self.urukul0_cpld.init() - delay(10*ms) - - self.zotino0.init() - delay(1*ms) - for i in range(32): - self.zotino0.write_dac(i, i/4) - delay(1*ms) - - while True: - for ttl in self.ttls: - ttl.pulse(100*ms) - for urukul_ch in self.urukul_chs: - urukul_ch.sw.pulse(100*ms) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs deleted file mode 100644 index de32ff2e2..000000000 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ /dev/null @@ -1,549 +0,0 @@ -use board_misoc::{csr, clock}; -use ad9154_reg; - -fn spi_setup(dacno: u8) { - unsafe { - while csr::converter_spi::idle_read() == 0 {} - csr::converter_spi::offline_write(0); - csr::converter_spi::end_write(1); - csr::converter_spi::cs_polarity_write(0b0001); - csr::converter_spi::clk_polarity_write(0); - csr::converter_spi::clk_phase_write(0); - csr::converter_spi::lsb_first_write(0); - csr::converter_spi::half_duplex_write(0); - csr::converter_spi::length_write(24 - 1); - csr::converter_spi::div_write(16 - 2); - csr::converter_spi::cs_write(1 << (csr::CONFIG_CONVERTER_SPI_FIRST_AD9154_CS + dacno as u32)); - } -} - -fn write(addr: u16, data: u8) { - unsafe { - while csr::converter_spi::writable_read() == 0 {} - csr::converter_spi::data_write( - ((addr as u32) << 16) | ((data as u32) << 8)); - } -} - -fn read(addr: u16) -> u8 { - unsafe { - write((1 << 15) | addr, 0); - while csr::converter_spi::writable_read() == 0 {} - csr::converter_spi::data_read() as u8 - } -} - -// ad9154 mode 1 -// linerate 5Gbps or 6Gbps -// deviceclock_fpga 125MHz or 150MHz -// deviceclock_dac 500MHz or 600MHz - -struct JESDSettings { - did: u8, - bid: u8, - - l: u8, // lanes - m: u8, // converters - n: u8, // bits/converter - np: u8, // bits/sample - - f: u8, // octets/(lane and frame) - s: u8, // samples/(converter and frame) - k: u8, // frames/multiframe - cs: u8, // control bits/sample - - subclassv: u8, - jesdv: u8 -} - -fn jesd_checksum(settings: &JESDSettings) -> u8 { - let mut r: u8 = 0; - for field in [ - settings.did, - settings.bid, - settings.l - 1, - settings.f - 1, - settings.k - 1, - settings.m - 1, - settings.n - 1, - settings.cs, - settings.np - 1, - settings.subclassv, - settings.s - 1, - settings.jesdv, - ].iter() { - r = r.overflowing_add(*field).0; - } - r -} - -const JESD_SETTINGS: JESDSettings = JESDSettings { - did: 0x5a, - bid: 0x5, - - l: 8, - m: 4, - n: 16, - np: 16, - f: 2, - s: 2, - k: 16, - cs: 0, - - subclassv: 1, - jesdv: 1 -}; - -pub fn reset_and_detect(dacno: u8) -> Result<(), &'static str> { - spi_setup(dacno); - // reset - write(ad9154_reg::SPI_INTFCONFA, - 1*ad9154_reg::SOFTRESET_M | 1*ad9154_reg::SOFTRESET | - 0*ad9154_reg::LSBFIRST_M | 0*ad9154_reg::LSBFIRST | - 0*ad9154_reg::ADDRINC_M | 0*ad9154_reg::ADDRINC | - 1*ad9154_reg::SDOACTIVE_M | 1*ad9154_reg::SDOACTIVE); - clock::spin_us(100); - write(ad9154_reg::SPI_INTFCONFA, - 0*ad9154_reg::SOFTRESET_M | 0*ad9154_reg::SOFTRESET | - 0*ad9154_reg::LSBFIRST_M | 0*ad9154_reg::LSBFIRST | - 0*ad9154_reg::ADDRINC_M | 0*ad9154_reg::ADDRINC | - 1*ad9154_reg::SDOACTIVE_M | 1*ad9154_reg::SDOACTIVE); - clock::spin_us(100); - if (read(ad9154_reg::PRODIDH) as u16) << 8 | (read(ad9154_reg::PRODIDL) as u16) != 0x9154 { - return Err("invalid AD9154 identification"); - } else { - info!("AD9154-{} found", dacno); - } - Ok(()) -} - -pub fn setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { - spi_setup(dacno); - info!("AD9154-{} initializing...", dacno); - write(ad9154_reg::PWRCNTRL0, - 0*ad9154_reg::PD_DAC0 | 0*ad9154_reg::PD_DAC1 | - 0*ad9154_reg::PD_DAC2 | 0*ad9154_reg::PD_DAC3 | - 0*ad9154_reg::PD_BG); - clock::spin_us(100); - write(ad9154_reg::TXENMASK1, 0*ad9154_reg::DACA_MASK | - 0*ad9154_reg::DACB_MASK); // DAC PD not controlled by TXEN pins - write(ad9154_reg::PWRCNTRL3, 1*ad9154_reg::ENA_SPI_TXEN | - 1*ad9154_reg::SPI_TXEN); - write(ad9154_reg::CLKCFG0, - 0*ad9154_reg::REF_CLKDIV_EN | 1*ad9154_reg::RF_SYNC_EN | - 1*ad9154_reg::DUTY_EN | 0*ad9154_reg::PD_CLK_REC | - 0*ad9154_reg::PD_SERDES_PCLK | 0*ad9154_reg::PD_CLK_DIG | - 0*ad9154_reg::PD_CLK23 | 0*ad9154_reg::PD_CLK01); - write(ad9154_reg::DACPLLCNTRL, - 0*ad9154_reg::ENABLE_DACPLL | 0*ad9154_reg::RECAL_DACPLL); - write(ad9154_reg::SYSREF_ACTRL0, // jesd204b subclass 1 - 0*ad9154_reg::HYS_CNTRL1 | 0*ad9154_reg::SYSREF_RISE | - 0*ad9154_reg::HYS_ON | 0*ad9154_reg::PD_SYSREF_BUFFER); - - write(ad9154_reg::DEVICE_CONFIG_REG_0, 0x8b); // magic - write(ad9154_reg::DEVICE_CONFIG_REG_1, 0x01); // magic - write(ad9154_reg::DEVICE_CONFIG_REG_2, 0x01); // magic - - write(ad9154_reg::SPI_PAGEINDX, 0x3); // A and B dual - - write(ad9154_reg::INTERP_MODE, 0x03); // 4x - write(ad9154_reg::MIX_MODE, 0); - write(ad9154_reg::DATA_FORMAT, 0*ad9154_reg::BINARY_FORMAT); // s16 - write(ad9154_reg::DATAPATH_CTRL, - 0*ad9154_reg::I_TO_Q | 0*ad9154_reg::SEL_SIDEBAND | - 0*ad9154_reg::MODULATION_TYPE | 0*ad9154_reg::PHASE_ADJ_ENABLE | - 1*ad9154_reg::DIG_GAIN_ENABLE | 0*ad9154_reg::INVSINC_ENABLE); - write(ad9154_reg::IDAC_DIG_GAIN0, 0x00); - write(ad9154_reg::IDAC_DIG_GAIN1, 0x8); - write(ad9154_reg::QDAC_DIG_GAIN0, 0x00); - write(ad9154_reg::QDAC_DIG_GAIN1, 0x8); - write(ad9154_reg::DC_OFFSET_CTRL, 0); - write(ad9154_reg::IPATH_DC_OFFSET_1PART0, 0x00); - write(ad9154_reg::IPATH_DC_OFFSET_1PART1, 0x00); - write(ad9154_reg::IPATH_DC_OFFSET_2PART, 0x00); - write(ad9154_reg::QPATH_DC_OFFSET_1PART0, 0x00); - write(ad9154_reg::QPATH_DC_OFFSET_1PART1, 0x00); - write(ad9154_reg::QPATH_DC_OFFSET_2PART, 0x00); - write(ad9154_reg::PHASE_ADJ0, 0); - write(ad9154_reg::PHASE_ADJ1, 0); - write(ad9154_reg::GROUP_DLY, 0x8*ad9154_reg::COARSE_GROUP_DELAY | - 0x8*ad9154_reg::GROUP_DELAY_RESERVED); - write(ad9154_reg::GROUPDELAY_COMP_BYP, - 1*ad9154_reg::GROUPCOMP_BYPQ | - 1*ad9154_reg::GROUPCOMP_BYPI); - write(ad9154_reg::GROUPDELAY_COMP_I, 0); - write(ad9154_reg::GROUPDELAY_COMP_Q, 0); - write(ad9154_reg::PDP_AVG_TIME, 0*ad9154_reg::PDP_ENABLE); - - write(ad9154_reg::MASTER_PD, 0); - write(ad9154_reg::PHY_PD, 0x00); // lanes 0-7 enabled - write(ad9154_reg::GENERIC_PD, - 0*ad9154_reg::PD_SYNCOUT0B | - 1*ad9154_reg::PD_SYNCOUT1B); - write(ad9154_reg::GENERAL_JRX_CTRL_0, - 0x0*ad9154_reg::LINK_EN | 0*ad9154_reg::LINK_PAGE | - 0*ad9154_reg::LINK_MODE | 0*ad9154_reg::CHECKSUM_MODE); - write(ad9154_reg::ILS_DID, JESD_SETTINGS.did); - write(ad9154_reg::ILS_BID, JESD_SETTINGS.bid); - write(ad9154_reg::ILS_LID0, 0x00); // lane id - write(ad9154_reg::ILS_SCR_L, - (JESD_SETTINGS.l - 1)*ad9154_reg::L_1 | - 1*ad9154_reg::SCR); - write(ad9154_reg::ILS_F, JESD_SETTINGS.f - 1); - write(ad9154_reg::ILS_K, JESD_SETTINGS.k - 1); - write(ad9154_reg::ILS_M, JESD_SETTINGS.m - 1); - write(ad9154_reg::ILS_CS_N, - (JESD_SETTINGS.n - 1)*ad9154_reg::N_1 | - 0*ad9154_reg::CS); - write(ad9154_reg::ILS_NP, - (JESD_SETTINGS.np - 1)*ad9154_reg::NP_1 | - JESD_SETTINGS.subclassv*ad9154_reg::SUBCLASSV); - write(ad9154_reg::ILS_S, - (JESD_SETTINGS.s - 1)*ad9154_reg::S_1 | - JESD_SETTINGS.jesdv*ad9154_reg::JESDV); - write(ad9154_reg::ILS_HD_CF, - 0*ad9154_reg::HD | 0*ad9154_reg::CF); - write(ad9154_reg::ILS_CHECKSUM, jesd_checksum(&JESD_SETTINGS)); - write(ad9154_reg::LANEDESKEW, 0xff); - for i in 0..8 { - write(ad9154_reg::BADDISPARITY, 0*ad9154_reg::RST_IRQ_DIS | - 0*ad9154_reg::DISABLE_ERR_CNTR_DIS | - 1*ad9154_reg::RST_ERR_CNTR_DIS | i*ad9154_reg::LANE_ADDR_DIS); - write(ad9154_reg::BADDISPARITY, 0*ad9154_reg::RST_IRQ_DIS | - 0*ad9154_reg::DISABLE_ERR_CNTR_DIS | - 0*ad9154_reg::RST_ERR_CNTR_DIS | i*ad9154_reg::LANE_ADDR_DIS); - write(ad9154_reg::NIT_W, 0*ad9154_reg::RST_IRQ_NIT | - 0*ad9154_reg::DISABLE_ERR_CNTR_NIT | - 1*ad9154_reg::RST_ERR_CNTR_NIT | i*ad9154_reg::LANE_ADDR_NIT); - write(ad9154_reg::NIT_W, 0*ad9154_reg::RST_IRQ_NIT | - 0*ad9154_reg::DISABLE_ERR_CNTR_NIT | - 0*ad9154_reg::RST_ERR_CNTR_NIT | i*ad9154_reg::LANE_ADDR_NIT); - write(ad9154_reg::UNEXPECTEDCONTROL_W, 0*ad9154_reg::RST_IRQ_UCC | - 0*ad9154_reg::DISABLE_ERR_CNTR_UCC | - 1*ad9154_reg::RST_ERR_CNTR_UCC | i*ad9154_reg::LANE_ADDR_UCC); - write(ad9154_reg::BADDISPARITY, 0*ad9154_reg::RST_IRQ_UCC | - 0*ad9154_reg::DISABLE_ERR_CNTR_UCC | - 0*ad9154_reg::RST_ERR_CNTR_UCC | i*ad9154_reg::LANE_ADDR_UCC); - } - write(ad9154_reg::CTRLREG1, JESD_SETTINGS.f); - write(ad9154_reg::CTRLREG2, 0*ad9154_reg::ILAS_MODE | - 0*ad9154_reg::THRESHOLD_MASK_EN); - write(ad9154_reg::KVAL, 1); // *4*K multiframes during ILAS - write(ad9154_reg::LANEENABLE, 0xff); // CGS _after_ this - - write(ad9154_reg::TERM_BLK1_CTRLREG0, 1); - write(ad9154_reg::TERM_BLK2_CTRLREG0, 1); - write(ad9154_reg::SERDES_SPI_REG, 1); - if linerate > 5_650_000_000 { - write(ad9154_reg::CDR_OPERATING_MODE_REG_0, - 0*ad9154_reg::CDR_OVERSAMP | 0x2*ad9154_reg::CDR_RESERVED | - 1*ad9154_reg::ENHALFRATE); - } else { - write(ad9154_reg::CDR_OPERATING_MODE_REG_0, - 0*ad9154_reg::CDR_OVERSAMP | 0x2*ad9154_reg::CDR_RESERVED | - 0*ad9154_reg::ENHALFRATE); - } - write(ad9154_reg::CDR_RESET, 0); - write(ad9154_reg::CDR_RESET, 1); - if linerate > 5_650_000_000 { - write(ad9154_reg::REF_CLK_DIVIDER_LDO, - 0*ad9154_reg::SPI_CDR_OVERSAMP | - 1*ad9154_reg::SPI_LDO_BYPASS_FILT | - 0*ad9154_reg::SPI_LDO_REF_SEL); - } else { - write(ad9154_reg::REF_CLK_DIVIDER_LDO, - 1*ad9154_reg::SPI_CDR_OVERSAMP | - 1*ad9154_reg::SPI_LDO_BYPASS_FILT | - 0*ad9154_reg::SPI_LDO_REF_SEL); - } - write(ad9154_reg::LDO_FILTER_1, 0x62); // magic - write(ad9154_reg::LDO_FILTER_2, 0xc9); // magic - write(ad9154_reg::LDO_FILTER_3, 0x0e); // magic - write(ad9154_reg::CP_CURRENT_SPI, - 0x12*ad9154_reg::SPI_CP_CURRENT | - 0*ad9154_reg::SPI_SERDES_LOGEN_POWER_MODE); - write(ad9154_reg::VCO_LDO, 0x7b); // magic - write(ad9154_reg::PLL_RD_REG, - 0*ad9154_reg::SPI_SERDES_LOGEN_PD_CORE | - 0*ad9154_reg::SPI_SERDES_LDO_PD | 0*ad9154_reg::SPI_SYN_PD | - 0*ad9154_reg::SPI_VCO_PD_ALC | 0*ad9154_reg::SPI_VCO_PD_PTAT | - 0*ad9154_reg::SPI_VCO_PD); - write(ad9154_reg::ALC_VARACTOR, - 0x9*ad9154_reg::SPI_VCO_VARACTOR | - 0x8*ad9154_reg::SPI_INIT_ALC_VALUE); - write(ad9154_reg::VCO_OUTPUT, - 0xc*ad9154_reg::SPI_VCO_OUTPUT_LEVEL | - 0x4*ad9154_reg::SPI_VCO_OUTPUT_RESERVED); - write(ad9154_reg::CP_CONFIG, - 0*ad9154_reg::SPI_CP_TEST | - 1*ad9154_reg::SPI_CP_CAL_EN | - 0*ad9154_reg::SPI_CP_FORCE_CALBITS | - 0*ad9154_reg::SPI_CP_OFFSET_OFF | - 1*ad9154_reg::SPI_CP_ENABLE_MACHINE | - 0*ad9154_reg::SPI_CP_DITHER_MODE | - 0*ad9154_reg::SPI_CP_HALF_VCO_CAL_CLK); - write(ad9154_reg::VCO_BIAS_1, - 0x3*ad9154_reg::SPI_VCO_BIAS_REF | - 0x3*ad9154_reg::SPI_VCO_BIAS_TCF); - write(ad9154_reg::VCO_BIAS_2, - 0x1*ad9154_reg::SPI_PRESCALE_BIAS | - 1*ad9154_reg::SPI_LAST_ALC_EN | - 0x1*ad9154_reg::SPI_PRESCALE_BYPASS_R | - 0*ad9154_reg::SPI_VCO_COMP_BYPASS_BIASR | - 0*ad9154_reg::SPI_VCO_BYPASS_DAC_R); - write(ad9154_reg::VCO_PD_OVERRIDES, - 0*ad9154_reg::SPI_VCO_PD_OVERRIDE_VCO_BUF | - 1*ad9154_reg::SPI_VCO_PD_OVERRIDE_CAL_TCF | - 0*ad9154_reg::SPI_VCO_PD_OVERRIDE_VAR_REF_TCF | - 0*ad9154_reg::SPI_VCO_PD_OVERRIDE_VAR_REF); - write(ad9154_reg::VCO_CAL, - 0x2*ad9154_reg::SPI_FB_CLOCK_ADV | - 0x3*ad9154_reg::SPI_VCO_CAL_COUNT | - 0*ad9154_reg::SPI_VCO_CAL_ALC_WAIT | - 1*ad9154_reg::SPI_VCO_CAL_EN); - write(ad9154_reg::CP_LEVEL_DETECT, - 0x2*ad9154_reg::SPI_CP_LEVEL_THRESHOLD_HIGH | - 0x5*ad9154_reg::SPI_CP_LEVEL_THRESHOLD_LOW | - 0*ad9154_reg::SPI_CP_LEVEL_DET_PD); - write(ad9154_reg::VCO_VARACTOR_CTRL_0, - 0xe*ad9154_reg::SPI_VCO_VARACTOR_OFFSET | - 0x7*ad9154_reg::SPI_VCO_VARACTOR_REF_TCF); - write(ad9154_reg::VCO_VARACTOR_CTRL_1, - 0x6*ad9154_reg::SPI_VCO_VARACTOR_REF); - // ensure link is txing - //write(ad9154_reg::SERDESPLL_ENABLE_CNTRL, - // 1*ad9154_reg::ENABLE_SERDESPLL | 1*ad9154_reg::RECAL_SERDESPLL) - write(ad9154_reg::SERDESPLL_ENABLE_CNTRL, - 1*ad9154_reg::ENABLE_SERDESPLL | 0*ad9154_reg::RECAL_SERDESPLL); - let t = clock::get_ms(); - while read(ad9154_reg::PLL_STATUS) & ad9154_reg::SERDES_PLL_LOCK_RB == 0 { - if clock::get_ms() > t + 200 { - return Err("SERDES PLL lock timeout"); - } - } - - write(ad9154_reg::EQ_BIAS_REG, 0x22*ad9154_reg::EQ_BIAS_RESERVED | - 1*ad9154_reg::EQ_POWER_MODE); - - write(ad9154_reg::GENERAL_JRX_CTRL_1, 1); // subclass 1 - write(ad9154_reg::LMFC_DELAY_0, 0); - write(ad9154_reg::LMFC_DELAY_1, 0); - write(ad9154_reg::LMFC_VAR_0, 0x0a); // receive buffer delay - write(ad9154_reg::LMFC_VAR_1, 0x0a); - write(ad9154_reg::SYNC_ERRWINDOW, 0); // +- 1/2 DAC clock - // datasheet seems to say ENABLE and ARM should be separate steps, - // so enable now so it can be armed in sync(). - write(ad9154_reg::SYNC_CONTROL, - 0x1*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE | - 0*ad9154_reg::SYNCARM | 0*ad9154_reg::SYNCCLRSTKY); - - write(ad9154_reg::XBAR_LN_0_1, - 0*ad9154_reg::LOGICAL_LANE0_SRC | 1*ad9154_reg::LOGICAL_LANE1_SRC); - write(ad9154_reg::XBAR_LN_2_3, - 2*ad9154_reg::LOGICAL_LANE2_SRC | 3*ad9154_reg::LOGICAL_LANE3_SRC); - write(ad9154_reg::XBAR_LN_4_5, - 4*ad9154_reg::LOGICAL_LANE4_SRC | 5*ad9154_reg::LOGICAL_LANE5_SRC); - write(ad9154_reg::XBAR_LN_6_7, - 6*ad9154_reg::LOGICAL_LANE6_SRC | 7*ad9154_reg::LOGICAL_LANE7_SRC); - write(ad9154_reg::JESD_BIT_INVERSE_CTRL, 0x00); - write(ad9154_reg::GENERAL_JRX_CTRL_0, - 0x1*ad9154_reg::LINK_EN | 0*ad9154_reg::LINK_PAGE | - 0*ad9154_reg::LINK_MODE | 0*ad9154_reg::CHECKSUM_MODE); - info!(" ...done"); - Ok(()) -} - -pub fn status(dacno: u8) { - spi_setup(dacno); - info!("Printing status of AD9154-{}", dacno); - info!("PRODID: 0x{:04x}", (read(ad9154_reg::PRODIDH) as u16) << 8 | (read(ad9154_reg::PRODIDL) as u16)); - info!("SERDES_PLL_LOCK: {}", - (read(ad9154_reg::PLL_STATUS) & ad9154_reg::SERDES_PLL_LOCK_RB)); - info!(""); - info!("CODEGRPSYNC: 0x{:02x}", read(ad9154_reg::CODEGRPSYNCFLG)); - info!("FRAMESYNC: 0x{:02x}", read(ad9154_reg::FRAMESYNCFLG)); - info!("GOODCHECKSUM: 0x{:02x}", read(ad9154_reg::GOODCHKSUMFLG)); - info!("INITLANESYNC: 0x{:02x}", read(ad9154_reg::INITLANESYNCFLG)); - info!(""); - info!("DID_REG: 0x{:02x}", read(ad9154_reg::DID_REG)); - info!("BID_REG: 0x{:02x}", read(ad9154_reg::BID_REG)); - info!("SCR_L_REG: 0x{:02x}", read(ad9154_reg::SCR_L_REG)); - info!("F_REG: 0x{:02x}", read(ad9154_reg::F_REG)); - info!("K_REG: 0x{:02x}", read(ad9154_reg::K_REG)); - info!("M_REG: 0x{:02x}", read(ad9154_reg::M_REG)); - info!("CS_N_REG: 0x{:02x}", read(ad9154_reg::CS_N_REG)); - info!("NP_REG: 0x{:02x}", read(ad9154_reg::NP_REG)); - info!("S_REG: 0x{:02x}", read(ad9154_reg::S_REG)); - info!("HD_CF_REG: 0x{:02x}", read(ad9154_reg::HD_CF_REG)); - info!("RES1_REG: 0x{:02x}", read(ad9154_reg::RES1_REG)); - info!("RES2_REG: 0x{:02x}", read(ad9154_reg::RES2_REG)); - info!("LIDx_REG: 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x}", - read(ad9154_reg::LID0_REG), - read(ad9154_reg::LID1_REG), - read(ad9154_reg::LID2_REG), - read(ad9154_reg::LID3_REG), - read(ad9154_reg::LID4_REG), - read(ad9154_reg::LID5_REG), - read(ad9154_reg::LID6_REG), - read(ad9154_reg::LID7_REG)); - info!("CHECKSUMx_REG: 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x}", - read(ad9154_reg::CHECKSUM0_REG), - read(ad9154_reg::CHECKSUM1_REG), - read(ad9154_reg::CHECKSUM2_REG), - read(ad9154_reg::CHECKSUM3_REG), - read(ad9154_reg::CHECKSUM4_REG), - read(ad9154_reg::CHECKSUM5_REG), - read(ad9154_reg::CHECKSUM6_REG), - read(ad9154_reg::CHECKSUM7_REG)); - info!("COMPSUMx_REG: 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x}", - read(ad9154_reg::COMPSUM0_REG), - read(ad9154_reg::COMPSUM1_REG), - read(ad9154_reg::COMPSUM2_REG), - read(ad9154_reg::COMPSUM3_REG), - read(ad9154_reg::COMPSUM4_REG), - read(ad9154_reg::COMPSUM5_REG), - read(ad9154_reg::COMPSUM6_REG), - read(ad9154_reg::COMPSUM7_REG)); - info!("BADDISPARITY: 0x{:02x}", read(ad9154_reg::BADDISPARITY)); - info!("NITDISPARITY: 0x{:02x}", read(ad9154_reg::NIT_W)); -} - -pub fn prbs(dacno: u8) -> Result<(), &'static str> { - let mut prbs_errors: u32 = 0; - spi_setup(dacno); - - /* follow phy prbs testing (p58 of ad9154 datasheet) */ - info!("AD9154-{} running PRBS test...", dacno); - - /* step 2: select prbs mode */ - write(ad9154_reg::PHY_PRBS_TEST_CTRL, - 0b00*ad9154_reg::PHY_PRBS_PAT_SEL); - - /* step 3: enable test for all lanes */ - write(ad9154_reg::PHY_PRBS_TEST_EN, 0xff); - - /* step 4: reset */ - write(ad9154_reg::PHY_PRBS_TEST_CTRL, - 0b00*ad9154_reg::PHY_PRBS_PAT_SEL | - 1*ad9154_reg::PHY_TEST_RESET); - write(ad9154_reg::PHY_PRBS_TEST_CTRL, - 0b00*ad9154_reg::PHY_PRBS_PAT_SEL); - - /* step 5: prbs threshold */ - write(ad9154_reg::PHY_PRBS_TEST_THRESHOLD_LOBITS, 0); - write(ad9154_reg::PHY_PRBS_TEST_THRESHOLD_MIDBITS, 0); - write(ad9154_reg::PHY_PRBS_TEST_THRESHOLD_HIBITS, 0); - - /* step 6: start */ - write(ad9154_reg::PHY_PRBS_TEST_CTRL, - 0b00*ad9154_reg::PHY_PRBS_PAT_SEL); - write(ad9154_reg::PHY_PRBS_TEST_CTRL, - 0b00*ad9154_reg::PHY_PRBS_PAT_SEL | - 1*ad9154_reg::PHY_TEST_START); - - /* step 7: wait 500 ms */ - clock::spin_us(500000); - - /* step 8 : stop */ - write(ad9154_reg::PHY_PRBS_TEST_CTRL, - 0b00*ad9154_reg::PHY_PRBS_PAT_SEL); - - for i in 0..8 { - /* step 9.a: select src err */ - write(ad9154_reg::PHY_PRBS_TEST_CTRL, - i*ad9154_reg::PHY_SRC_ERR_CNT); - /* step 9.b: retrieve number of errors */ - let lane_errors = (read(ad9154_reg::PHY_PRBS_TEST_ERRCNT_LOBITS) as u32) | - ((read(ad9154_reg::PHY_PRBS_TEST_ERRCNT_MIDBITS) as u32) << 8) | - ((read(ad9154_reg::PHY_PRBS_TEST_ERRCNT_HIBITS) as u32) << 16); - if lane_errors > 0 { - warn!(" PRBS errors on lane{}: {:06x}", i, lane_errors); - } - prbs_errors += lane_errors - } - - if prbs_errors > 0 { - return Err("PRBS failed") - } - info!(" ...passed"); - Ok(()) -} - -pub fn stpl(dacno: u8, m: u8, s: u8) -> Result<(), &'static str> { - spi_setup(dacno); - - info!("AD9154-{} running STPL test...", dacno); - - fn prng(seed: u32) -> u32 { - return ((seed + 1)*0x31415979 + 1) & 0xffff; - } - - for i in 0..m { - let mut data: u32; - let mut errors: u8 = 0; - for j in 0..s { - /* select converter */ - write(ad9154_reg::SHORT_TPL_TEST_0, - 0b0*ad9154_reg::SHORT_TPL_TEST_EN | - 0b0*ad9154_reg::SHORT_TPL_TEST_RESET | - i*ad9154_reg::SHORT_TPL_DAC_SEL | - j*ad9154_reg::SHORT_TPL_SP_SEL); - - /* set expected value */ - data = prng(((i as u32) << 8) | (j as u32)); - write(ad9154_reg::SHORT_TPL_TEST_1, (data & 0x00ff) as u8); - write(ad9154_reg::SHORT_TPL_TEST_2, ((data & 0xff00) >> 8) as u8); - - /* enable stpl */ - write(ad9154_reg::SHORT_TPL_TEST_0, - 0b1*ad9154_reg::SHORT_TPL_TEST_EN | - 0b0*ad9154_reg::SHORT_TPL_TEST_RESET | - i*ad9154_reg::SHORT_TPL_DAC_SEL | - j*ad9154_reg::SHORT_TPL_SP_SEL); - - /* reset stpl */ - write(ad9154_reg::SHORT_TPL_TEST_0, - 0b1*ad9154_reg::SHORT_TPL_TEST_EN | - 0b1*ad9154_reg::SHORT_TPL_TEST_RESET | - i*ad9154_reg::SHORT_TPL_DAC_SEL | - j*ad9154_reg::SHORT_TPL_SP_SEL); - - /* release reset stpl */ - write(ad9154_reg::SHORT_TPL_TEST_0, - 0b1*ad9154_reg::SHORT_TPL_TEST_EN | - 0b0*ad9154_reg::SHORT_TPL_TEST_RESET | - i*ad9154_reg::SHORT_TPL_DAC_SEL | - j*ad9154_reg::SHORT_TPL_SP_SEL); - errors += read(ad9154_reg::SHORT_TPL_TEST_3); - } - info!(" c{} errors: {}", i, errors); - if errors > 0 { - return Err("STPL failed") - } - } - - info!(" ...passed"); - Ok(()) -} - -pub fn sync(dacno: u8) -> Result { - spi_setup(dacno); - - write(ad9154_reg::SYNC_CONTROL, - 0x1*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE | - 1*ad9154_reg::SYNCARM | 1*ad9154_reg::SYNCCLRSTKY); - clock::spin_us(1000); // ensure at least one sysref edge - let sync_status = read(ad9154_reg::SYNC_STATUS); - - if sync_status & ad9154_reg::SYNC_BUSY != 0 { - return Err("sync logic busy"); - } - if sync_status & ad9154_reg::SYNC_LOCK == 0 { - return Err("no sync lock"); - } - if sync_status & ad9154_reg::SYNC_TRIP == 0 { - return Err("no sysref edge"); - } - let realign_occured = sync_status & ad9154_reg::SYNC_ROTATE != 0; - Ok(realign_occured) -} diff --git a/artiq/firmware/libboard_artiq/ad9154_reg.rs b/artiq/firmware/libboard_artiq/ad9154_reg.rs deleted file mode 100644 index 3af180496..000000000 --- a/artiq/firmware/libboard_artiq/ad9154_reg.rs +++ /dev/null @@ -1,826 +0,0 @@ -#![allow(dead_code)] - -pub const SPI_INTFCONFA : u16 = 0x000; -pub const SOFTRESET : u8 = 1 << 0; -pub const LSBFIRST : u8 = 1 << 1; -pub const ADDRINC : u8 = 1 << 2; -pub const SDOACTIVE : u8 = 1 << 3; -pub const SDOACTIVE_M : u8 = 1 << 4; -pub const ADDRINC_M : u8 = 1 << 5; -pub const LSBFIRST_M : u8 = 1 << 6; -pub const SOFTRESET_M : u8 = 1 << 7; - -pub const CHIPTYPE : u16 = 0x003; - -pub const PRODIDL : u16 = 0x004; - -pub const PRODIDH : u16 = 0x005; - -pub const CHIPGRADE : u16 = 0x006; -pub const DEV_REVISION : u8 = 1 << 0; -pub const PROD_GRADE : u8 = 1 << 4; - -pub const SPI_PAGEINDX : u16 = 0x008; - -pub const PWRCNTRL0 : u16 = 0x011; -pub const PD_DAC3 : u8 = 1 << 3; -pub const PD_DAC2 : u8 = 1 << 4; -pub const PD_DAC1 : u8 = 1 << 5; -pub const PD_DAC0 : u8 = 1 << 6; -pub const PD_BG : u8 = 1 << 7; - -pub const TXENMASK1 : u16 = 0x012; -pub const DACA_MASK : u8 = 1 << 6; -pub const DACB_MASK : u8 = 1 << 7; - -pub const PWRCNTRL3 : u16 = 0x013; -pub const SPI_TXEN : u8 = 1 << 0; -pub const ENA_SPI_TXEN : u8 = 1 << 1; -pub const SPI_PA_CTRL : u8 = 1 << 2; -pub const ENA_PA_CTRL_FROM_SPI : u8 = 1 << 3; -pub const ENA_PA_CTRL_FROM_BLSM : u8 = 1 << 4; -pub const ENA_PA_CTRL_FROM_TXENSM : u8 = 1 << 5; -pub const ENA_PA_CTRL_FROM_PARROT_ERR : u8 = 1 << 6; - -pub const GROUP_DLY : u16 = 0x014; -pub const COARSE_GROUP_DELAY : u8 = 1 << 0; -pub const GROUP_DELAY_RESERVED : u8 = 1 << 4; - -pub const IRQEN_STATUSMODE0 : u16 = 0x01f; -pub const IRQEN_SMODE_LANEFIFOERR : u8 = 1 << 1; -pub const IRQEN_SMODE_SERPLLLOCK : u8 = 1 << 2; -pub const IRQEN_SMODE_SERPLLLOST : u8 = 1 << 3; -pub const IRQEN_SMODE_DACPLLLOCK : u8 = 1 << 4; -pub const IRQEN_SMODE_DACPLLLOST : u8 = 1 << 5; - -pub const IRQEN_STATUSMODE1 : u16 = 0x020; -pub const IRQEN_SMODE_PRBS0 : u8 = 1 << 0; -pub const IRQEN_SMODE_PRBS1 : u8 = 1 << 1; -pub const IRQEN_SMODE_PRBS2 : u8 = 1 << 2; -pub const IRQEN_SMODE_PRBS3 : u8 = 1 << 3; - -pub const IRQEN_STATUSMODE2 : u16 = 0x021; -pub const IRQEN_SMODE_SYNC_TRIP0 : u8 = 1 << 0; -pub const IRQEN_SMODE_SYNC_WLIM0 : u8 = 1 << 1; -pub const IRQEN_SMODE_SYNC_ROTATE0 : u8 = 1 << 2; -pub const IRQEN_SMODE_SYNC_LOCK0 : u8 = 1 << 3; -pub const IRQEN_SMODE_NCO_ALIGN0 : u8 = 1 << 4; -pub const IRQEN_SMODE_BLNKDONE0 : u8 = 1 << 5; -pub const IRQEN_SMODE_PDPERR0 : u8 = 1 << 7; - -pub const IRQEN_STATUSMODE3 : u16 = 0x022; -pub const IRQEN_SMODE_SYNC_TRIP1 : u8 = 1 << 0; -pub const IRQEN_SMODE_SYNC_WLIM1 : u8 = 1 << 1; -pub const IRQEN_SMODE_SYNC_ROTATE1 : u8 = 1 << 2; -pub const IRQEN_SMODE_SYNC_LOCK1 : u8 = 1 << 3; -pub const IRQEN_SMODE_NCO_ALIGN1 : u8 = 1 << 4; -pub const IRQEN_SMODE_BLNKDONE1 : u8 = 1 << 5; -pub const IRQEN_SMODE_PDPERR1 : u8 = 1 << 7; - -pub const IRQ_STATUS0 : u16 = 0x023; -pub const LANEFIFOERR : u8 = 1 << 1; -pub const SERPLLLOCK : u8 = 1 << 2; -pub const SERPLLLOST : u8 = 1 << 3; -pub const DACPLLLOCK : u8 = 1 << 4; -pub const DACPLLLOST : u8 = 1 << 5; - -pub const IRQ_STATUS1 : u16 = 0x024; -pub const PRBS0 : u8 = 1 << 0; -pub const PRBS1 : u8 = 1 << 1; -pub const PRBS2 : u8 = 1 << 2; -pub const PRBS3 : u8 = 1 << 3; - -pub const IRQ_STATUS2 : u16 = 0x025; -pub const SYNC_TRIP0 : u8 = 1 << 0; -pub const SYNC_WLIM0 : u8 = 1 << 1; -pub const SYNC_ROTATE0 : u8 = 1 << 2; -pub const SYNC_LOCK0 : u8 = 1 << 3; -pub const NCO_ALIGN0 : u8 = 1 << 4; -pub const BLNKDONE0 : u8 = 1 << 5; -pub const PDPERR0 : u8 = 1 << 7; - -pub const IRQ_STATUS3 : u16 = 0x026; -pub const SYNC_TRIP1 : u8 = 1 << 0; -pub const SYNC_WLIM1 : u8 = 1 << 1; -pub const SYNC_ROTATE1 : u8 = 1 << 2; -pub const SYNC_LOCK1 : u8 = 1 << 3; -pub const NCO_ALIGN1 : u8 = 1 << 4; -pub const BLNKDONE1 : u8 = 1 << 5; -pub const PDPERR1 : u8 = 1 << 7; - -pub const JESD_CHECKS : u16 = 0x030; -pub const ERR_INTSUPP : u8 = 1 << 0; -pub const ERR_SUBCLASS : u8 = 1 << 1; -pub const ERR_KUNSUPP : u8 = 1 << 2; -pub const ERR_JESDBAD : u8 = 1 << 3; -pub const ERR_WINLIMIT : u8 = 1 << 4; -pub const ERR_DLYOVER : u8 = 1 << 5; - -pub const SYNC_ERRWINDOW : u16 = 0x034; - -pub const SYNC_LASTERR_L : u16 = 0x038; - -pub const SYNC_LASTERR_H : u16 = 0x039; -pub const LASTERROR_H : u8 = 1 << 0; -pub const LASTOVER : u8 = 1 << 6; -pub const LASTUNDER : u8 = 1 << 7; - -pub const SYNC_CONTROL : u16 = 0x03a; -pub const SYNCMODE : u8 = 1 << 0; -pub const SYNCCLRLAST : u8 = 1 << 4; -pub const SYNCCLRSTKY : u8 = 1 << 5; -pub const SYNCARM : u8 = 1 << 6; -pub const SYNCENABLE : u8 = 1 << 7; - -pub const SYNC_STATUS : u16 = 0x03b; -pub const SYNC_TRIP : u8 = 1 << 0; -pub const SYNC_WLIM : u8 = 1 << 1; -pub const SYNC_ROTATE : u8 = 1 << 2; -pub const SYNC_LOCK : u8 = 1 << 3; -pub const SYNC_BUSY : u8 = 1 << 7; - -pub const SYNC_CURRERR_L : u16 = 0x03c; - -pub const SYNC_CURRERR_H : u16 = 0x03d; -pub const CURRERROR_H : u8 = 1 << 0; -pub const CURROVER : u8 = 1 << 6; -pub const CURRUNDER : u8 = 1 << 7; - -pub const DACGAIN0_I : u16 = 0x040; - -pub const DACGAIN1_I : u16 = 0x041; - -pub const DACGAIN0_Q : u16 = 0x042; - -pub const DACGAIN1_Q : u16 = 0x043; - -pub const GROUPDELAY_COMP_I : u16 = 0x044; - -pub const GROUPDELAY_COMP_Q : u16 = 0x045; - -pub const GROUPDELAY_COMP_BYP : u16 = 0x046; -pub const GROUPCOMP_BYPQ : u8 = 1 << 0; -pub const GROUPCOMP_BYPI : u8 = 1 << 1; - -pub const MIX_MODE : u16 = 0x04a; - -pub const NCOALIGN_MODE : u16 = 0x050; -pub const NCO_ALIGN_MODE : u8 = 1 << 0; -pub const NCO_ALIGN_FAIL : u8 = 1 << 3; -pub const NCO_ALIGN_PASS : u8 = 1 << 4; -pub const NCO_ALIGN_MTCH : u8 = 1 << 5; -pub const NCO_ALIGN_ARM : u8 = 1 << 7; - -pub const NCOKEY_ILSB : u16 = 0x051; - -pub const NCOKEY_IMSB : u16 = 0x052; - -pub const NCOKEY_QLSB : u16 = 0x053; - -pub const NCOKEY_QMSB : u16 = 0x054; - -pub const PDP_THRES0 : u16 = 0x060; - -pub const PDP_THRES1 : u16 = 0x061; - -pub const PDP_AVG_TIME : u16 = 0x062; -pub const PDP_AVG_TIME_ : u8 = 1 << 0; -pub const PA_BUS_SWAP : u8 = 1 << 6; -pub const PDP_ENABLE : u8 = 1 << 7; - -pub const PDP_POWER0 : u16 = 0x063; - -pub const PDP_POWER1 : u16 = 0x064; - -pub const CLKCFG0 : u16 = 0x080; -pub const REF_CLKDIV_EN : u8 = 1 << 0; -pub const RF_SYNC_EN : u8 = 1 << 1; -pub const DUTY_EN : u8 = 1 << 2; -pub const PD_CLK_REC : u8 = 1 << 3; -pub const PD_SERDES_PCLK : u8 = 1 << 4; -pub const PD_CLK_DIG : u8 = 1 << 5; -pub const PD_CLK23 : u8 = 1 << 6; -pub const PD_CLK01 : u8 = 1 << 7; - -pub const SYSREF_ACTRL0 : u16 = 0x081; -pub const HYS_CNTRL1 : u8 = 1 << 0; -pub const SYSREF_RISE : u8 = 1 << 2; -pub const HYS_ON : u8 = 1 << 3; -pub const PD_SYSREF_BUFFER : u8 = 1 << 4; - -pub const SYSREF_ACTRL1 : u16 = 0x082; - -pub const DACPLLCNTRL : u16 = 0x083; -pub const ENABLE_DACPLL : u8 = 1 << 4; -pub const RECAL_DACPLL : u8 = 1 << 7; - -pub const DACPLLSTATUS : u16 = 0x084; -pub const DACPLL_LOCK : u8 = 1 << 1; -pub const VCO_CAL_PROGRESS : u8 = 1 << 3; -pub const CP_CAL_VALID : u8 = 1 << 4; -pub const CP_OVERRANGE_L : u8 = 1 << 5; -pub const CP_OVERRANGE_H : u8 = 1 << 6; - -pub const DACINTEGERWORD0 : u16 = 0x085; - -pub const DACLOOPFILT1 : u16 = 0x087; -pub const LF_C1_WORD : u8 = 1 << 0; -pub const LF_C2_WORD : u8 = 1 << 4; - -pub const DACLOOPFILT2 : u16 = 0x088; -pub const LF_C3_WORD : u8 = 1 << 0; -pub const LF_R1_WORD : u8 = 1 << 4; - -pub const DACLOOPFILT3 : u16 = 0x089; -pub const LF_R3_WORD : u8 = 1 << 0; -pub const LF_BYPASS_C1 : u8 = 1 << 4; -pub const LF_BYPASS_C2 : u8 = 1 << 5; -pub const LF_BYPASS_R1 : u8 = 1 << 6; -pub const LF_BYPASS_R3 : u8 = 1 << 7; - -pub const DACCPCNTRL : u16 = 0x08a; -pub const CP_CURRENT : u8 = 1 << 0; -pub const VT_FORCE : u8 = 1 << 6; - -pub const DACLOGENCNTRL : u16 = 0x08b; -pub const LODIVMODE : u8 = 1 << 0; -pub const LO_POWER_MODE : u8 = 1 << 4; - -pub const DACLDOCNTRL1 : u16 = 0x08c; -pub const REFDIVMODE : u8 = 1 << 0; -pub const LDO_BYPASS_FLT : u8 = 1 << 6; -pub const LDO_REF_SEL : u8 = 1 << 7; - -pub const DACLDOCNTRL2 : u16 = 0x08d; -pub const LDO_VDROP : u8 = 1 << 0; -pub const LDO_SEL : u8 = 1 << 2; -pub const LDO_INRUSH : u8 = 1 << 5; -pub const LDO_BYPASS : u8 = 1 << 7; - -pub const DATA_FORMAT : u16 = 0x110; -pub const BINARY_FORMAT : u8 = 1 << 7; - -pub const DATAPATH_CTRL : u16 = 0x111; -pub const I_TO_Q : u8 = 1 << 0; -pub const SEL_SIDEBAND : u8 = 1 << 1; -pub const MODULATION_TYPE : u8 = 1 << 2; -pub const PHASE_ADJ_ENABLE : u8 = 1 << 4; -pub const DIG_GAIN_ENABLE : u8 = 1 << 5; -pub const INVSINC_ENABLE : u8 = 1 << 7; - -pub const INTERP_MODE : u16 = 0x112; - -pub const NCO_FTW_UPDATE : u16 = 0x113; -pub const FTW_UPDATE_REQ : u8 = 1 << 0; -pub const FTW_UPDATE_ACK : u8 = 1 << 1; - -pub const FTW0 : u16 = 0x114; - -pub const FTW1 : u16 = 0x115; - -pub const FTW2 : u16 = 0x116; - -pub const FTW3 : u16 = 0x117; - -pub const FTW4 : u16 = 0x118; - -pub const FTW5 : u16 = 0x119; - -pub const NCO_PHASE_OFFSET0 : u16 = 0x11a; - -pub const NCO_PHASE_OFFSET1 : u16 = 0x11b; - -pub const PHASE_ADJ0 : u16 = 0x11c; - -pub const PHASE_ADJ1 : u16 = 0x11d; - -pub const TXEN_SM_0 : u16 = 0x11f; -pub const TXEN_SM_EN : u8 = 1 << 0; -pub const GP_PA_CTRL : u8 = 1 << 1; -pub const GP_PA_ON_INVERT : u8 = 1 << 2; -pub const RISE_COUNTERS : u8 = 1 << 4; -pub const FALL_COUNTERS : u8 = 1 << 6; - -pub const TXEN_RISE_COUNT_0 : u16 = 0x121; - -pub const TXEN_RISE_COUNT_1 : u16 = 0x122; - -pub const TXEN_FALL_COUNT_0 : u16 = 0x123; - -pub const TXEN_FALL_COUNT_1 : u16 = 0x124; - -pub const DEVICE_CONFIG_REG_0 : u16 = 0x12d; - -pub const DIE_TEMP_CTRL0 : u16 = 0x12f; -pub const AUXADC_ENABLE : u8 = 1 << 0; -pub const AUXADC_RESERVED : u8 = 1 << 1; - -pub const DIE_TEMP0 : u16 = 0x132; - -pub const DIE_TEMP1 : u16 = 0x133; - -pub const DIE_TEMP_UPDATE : u16 = 0x134; - -pub const DC_OFFSET_CTRL : u16 = 0x135; - -pub const IPATH_DC_OFFSET_1PART0 : u16 = 0x136; - -pub const IPATH_DC_OFFSET_1PART1 : u16 = 0x137; - -pub const QPATH_DC_OFFSET_1PART0 : u16 = 0x138; - -pub const QPATH_DC_OFFSET_1PART1 : u16 = 0x139; - -pub const IPATH_DC_OFFSET_2PART : u16 = 0x13a; - -pub const QPATH_DC_OFFSET_2PART : u16 = 0x13b; - -pub const IDAC_DIG_GAIN0 : u16 = 0x13c; - -pub const IDAC_DIG_GAIN1 : u16 = 0x13d; - -pub const QDAC_DIG_GAIN0 : u16 = 0x13e; - -pub const QDAC_DIG_GAIN1 : u16 = 0x13f; - -pub const GAIN_RAMP_UP_STEP0 : u16 = 0x140; - -pub const GAIN_RAMP_UP_STEP1 : u16 = 0x141; - -pub const GAIN_RAMP_DOWN_STEP0 : u16 = 0x142; - -pub const GAIN_RAMP_DOWN_STEP1 : u16 = 0x143; - -pub const DEVICE_CONFIG_REG_1 : u16 = 0x146; - -pub const BSM_STAT : u16 = 0x147; -pub const SOFTBLANKRB : u8 = 1 << 6; - -pub const PRBS : u16 = 0x14b; -pub const PRBS_EN : u8 = 1 << 0; -pub const PRBS_RESET : u8 = 1 << 1; -pub const PRBS_MODE : u8 = 1 << 2; -pub const PRBS_GOOD_I : u8 = 1 << 6; -pub const PRBS_GOOD_Q : u8 = 1 << 7; - -pub const PRBS_ERROR_I : u16 = 0x14c; - -pub const PRBS_ERROR_Q : u16 = 0x14d; - -pub const DACPLLT0 : u16 = 0x1b0; -pub const LOGEN_PD : u8 = 1 << 1; -pub const LDO_PD : u8 = 1 << 3; -pub const SYNTH_PD : u8 = 1 << 4; -pub const VCO_PD_ALC : u8 = 1 << 5; -pub const VCO_PD_PTAT : u8 = 1 << 6; -pub const VCO_PD_IN : u8 = 1 << 7; - -pub const DACPLLT1 : u16 = 0x1b1; -pub const PFD_EDGE : u8 = 1 << 1; -pub const PFD_DELAY : u8 = 1 << 2; - -pub const DACPLLT2 : u16 = 0x1b2; -pub const EXT_ALC_WORD : u8 = 1 << 0; -pub const EXT_ALC_WORD_EN : u8 = 1 << 7; - -pub const DACPLLT3 : u16 = 0x1b3; -pub const EXT_BAND1 : u8 = 1 << 0; - -pub const DACPLLT4 : u16 = 0x1b4; -pub const EXT_BAND2 : u8 = 1 << 0; -pub const EXT_BAND_EN : u8 = 1 << 1; -pub const VCO_CAL_OFFSET : u8 = 1 << 3; -pub const BYP_LOAD_DELAY : u8 = 1 << 7; - -pub const DACPLLT5 : u16 = 0x1b5; - -pub const DACPLLT6 : u16 = 0x1b6; - -pub const DACPLLT7 : u16 = 0x1b7; - -pub const DACPLLT8 : u16 = 0x1b8; - -pub const DACPLLT9 : u16 = 0x1b9; - -pub const DACPLLTA : u16 = 0x1ba; - -pub const DACPLLTB : u16 = 0x1bb; -pub const VCO_BIAS_REF : u8 = 1 << 0; -pub const VCO_BIAS_TCF : u8 = 1 << 3; - -pub const DACPLLTC : u16 = 0x1bc; - -pub const DACPLLTD : u16 = 0x1bd; - -pub const DACPLLTE : u16 = 0x1be; - -pub const DACPLLTF : u16 = 0x1bf; - -pub const DACPLLT10 : u16 = 0x1c0; - -pub const DACPLLT11 : u16 = 0x1c1; - -pub const DACPLLT15 : u16 = 0x1c2; - -pub const DACPLLT16 : u16 = 0x1c3; - -pub const DACPLLT17 : u16 = 0x1c4; - -pub const DACPLLT18 : u16 = 0x1c5; - -pub const MASTER_PD : u16 = 0x200; - -pub const PHY_PD : u16 = 0x201; - -pub const GENERIC_PD : u16 = 0x203; -pub const PD_SYNCOUT1B : u8 = 1 << 0; -pub const PD_SYNCOUT0B : u8 = 1 << 1; - -pub const CDR_RESET : u16 = 0x206; - -pub const CDR_OPERATING_MODE_REG_0 : u16 = 0x230; -pub const CDR_OVERSAMP : u8 = 1 << 1; -pub const CDR_RESERVED : u8 = 1 << 2; -pub const ENHALFRATE : u8 = 1 << 5; - -pub const EQ_BIAS_REG : u16 = 0x268; -pub const EQ_BIAS_RESERVED : u8 = 1 << 0; -pub const EQ_POWER_MODE : u8 = 1 << 6; - -pub const SERDESPLL_ENABLE_CNTRL : u16 = 0x280; -pub const ENABLE_SERDESPLL : u8 = 1 << 0; -pub const RECAL_SERDESPLL : u8 = 1 << 2; - -pub const PLL_STATUS : u16 = 0x281; -pub const SERDES_PLL_LOCK_RB : u8 = 1 << 0; -pub const SERDES_CURRENTS_READY_RB : u8 = 1 << 1; -pub const SERDES_VCO_CAL_IN_PROGRESS_RB : u8 = 1 << 2; -pub const SERDES_PLL_CAL_VALID_RB : u8 = 1 << 3; -pub const SERDES_PLL_OVERRANGE_L_RB : u8 = 1 << 4; -pub const SERDES_PLL_OVERRANGE_H_RB : u8 = 1 << 5; - -pub const LDO_FILTER_1 : u16 = 0x284; - -pub const LDO_FILTER_2 : u16 = 0x285; - -pub const LDO_FILTER_3 : u16 = 0x286; - -pub const CP_CURRENT_SPI : u16 = 0x287; -pub const SPI_CP_CURRENT : u8 = 1 << 0; -pub const SPI_SERDES_LOGEN_POWER_MODE : u8 = 1 << 6; - -pub const REF_CLK_DIVIDER_LDO : u16 = 0x289; -pub const SPI_CDR_OVERSAMP : u8 = 1 << 0; -pub const SPI_LDO_BYPASS_FILT : u8 = 1 << 2; -pub const SPI_LDO_REF_SEL : u8 = 1 << 3; - -pub const VCO_LDO : u16 = 0x28a; - -pub const PLL_RD_REG : u16 = 0x28b; -pub const SPI_SERDES_LOGEN_PD_CORE : u8 = 1 << 0; -pub const SPI_SERDES_LDO_PD : u8 = 1 << 2; -pub const SPI_SYN_PD : u8 = 1 << 3; -pub const SPI_VCO_PD_ALC : u8 = 1 << 4; -pub const SPI_VCO_PD_PTAT : u8 = 1 << 5; -pub const SPI_VCO_PD : u8 = 1 << 6; - -pub const ALC_VARACTOR : u16 = 0x290; -pub const SPI_VCO_VARACTOR : u8 = 1 << 0; -pub const SPI_INIT_ALC_VALUE : u8 = 1 << 4; - -pub const VCO_OUTPUT : u16 = 0x291; -pub const SPI_VCO_OUTPUT_LEVEL : u8 = 1 << 0; -pub const SPI_VCO_OUTPUT_RESERVED : u8 = 1 << 4; - -pub const CP_CONFIG : u16 = 0x294; -pub const SPI_CP_TEST : u8 = 1 << 0; -pub const SPI_CP_CAL_EN : u8 = 1 << 2; -pub const SPI_CP_FORCE_CALBITS : u8 = 1 << 3; -pub const SPI_CP_OFFSET_OFF : u8 = 1 << 4; -pub const SPI_CP_ENABLE_MACHINE : u8 = 1 << 5; -pub const SPI_CP_DITHER_MODE : u8 = 1 << 6; -pub const SPI_CP_HALF_VCO_CAL_CLK : u8 = 1 << 7; - -pub const VCO_BIAS_1 : u16 = 0x296; -pub const SPI_VCO_BIAS_REF : u8 = 1 << 0; -pub const SPI_VCO_BIAS_TCF : u8 = 1 << 3; - -pub const VCO_BIAS_2 : u16 = 0x297; -pub const SPI_PRESCALE_BIAS : u8 = 1 << 0; -pub const SPI_LAST_ALC_EN : u8 = 1 << 2; -pub const SPI_PRESCALE_BYPASS_R : u8 = 1 << 3; -pub const SPI_VCO_COMP_BYPASS_BIASR : u8 = 1 << 4; -pub const SPI_VCO_BYPASS_DAC_R : u8 = 1 << 5; - -pub const VCO_PD_OVERRIDES : u16 = 0x299; -pub const SPI_VCO_PD_OVERRIDE_VCO_BUF : u8 = 1 << 0; -pub const SPI_VCO_PD_OVERRIDE_CAL_TCF : u8 = 1 << 1; -pub const SPI_VCO_PD_OVERRIDE_VAR_REF_TCF : u8 = 1 << 2; -pub const SPI_VCO_PD_OVERRIDE_VAR_REF : u8 = 1 << 3; - -pub const VCO_CAL : u16 = 0x29a; -pub const SPI_FB_CLOCK_ADV : u8 = 1 << 0; -pub const SPI_VCO_CAL_COUNT : u8 = 1 << 2; -pub const SPI_VCO_CAL_ALC_WAIT : u8 = 1 << 4; -pub const SPI_VCO_CAL_EN : u8 = 1 << 7; - -pub const CP_LEVEL_DETECT : u16 = 0x29c; -pub const SPI_CP_LEVEL_THRESHOLD_HIGH : u8 = 1 << 0; -pub const SPI_CP_LEVEL_THRESHOLD_LOW : u8 = 1 << 3; -pub const SPI_CP_LEVEL_DET_PD : u8 = 1 << 6; - -pub const VCO_VARACTOR_CTRL_0 : u16 = 0x29f; -pub const SPI_VCO_VARACTOR_OFFSET : u8 = 1 << 0; -pub const SPI_VCO_VARACTOR_REF_TCF : u8 = 1 << 4; - -pub const VCO_VARACTOR_CTRL_1 : u16 = 0x2a0; -pub const SPI_VCO_VARACTOR_REF : u8 = 1 << 0; - -pub const TERM_BLK1_CTRLREG0 : u16 = 0x2a7; - -pub const TERM_BLK2_CTRLREG0 : u16 = 0x2ae; - -pub const GENERAL_JRX_CTRL_0 : u16 = 0x300; -pub const LINK_EN : u8 = 1 << 0; -pub const LINK_PAGE : u8 = 1 << 2; -pub const LINK_MODE : u8 = 1 << 3; -pub const CHECKSUM_MODE : u8 = 1 << 6; - -pub const GENERAL_JRX_CTRL_1 : u16 = 0x301; - -pub const DYN_LINK_LATENCY_0 : u16 = 0x302; - -pub const DYN_LINK_LATENCY_1 : u16 = 0x303; - -pub const LMFC_DELAY_0 : u16 = 0x304; - -pub const LMFC_DELAY_1 : u16 = 0x305; - -pub const LMFC_VAR_0 : u16 = 0x306; - -pub const LMFC_VAR_1 : u16 = 0x307; - -pub const XBAR_LN_0_1 : u16 = 0x308; -pub const LOGICAL_LANE0_SRC : u8 = 1 << 0; -pub const LOGICAL_LANE1_SRC : u8 = 1 << 3; - -pub const XBAR_LN_2_3 : u16 = 0x309; -pub const LOGICAL_LANE2_SRC : u8 = 1 << 0; -pub const LOGICAL_LANE3_SRC : u8 = 1 << 3; - -pub const XBAR_LN_4_5 : u16 = 0x30a; -pub const LOGICAL_LANE4_SRC : u8 = 1 << 0; -pub const LOGICAL_LANE5_SRC : u8 = 1 << 3; - -pub const XBAR_LN_6_7 : u16 = 0x30b; -pub const LOGICAL_LANE6_SRC : u8 = 1 << 0; -pub const LOGICAL_LANE7_SRC : u8 = 1 << 3; - -pub const FIFO_STATUS_REG_0 : u16 = 0x30c; - -pub const FIFO_STATUS_REG_1 : u16 = 0x30d; - -pub const SYNCB_GEN_1 : u16 = 0x312; -pub const SYNCB_ERR_DUR : u8 = 1 << 4; - -pub const SERDES_SPI_REG : u16 = 0x314; - -pub const PHY_PRBS_TEST_EN : u16 = 0x315; - -pub const PHY_PRBS_TEST_CTRL : u16 = 0x316; -pub const PHY_TEST_RESET : u8 = 1 << 0; -pub const PHY_TEST_START : u8 = 1 << 1; -pub const PHY_PRBS_PAT_SEL : u8 = 1 << 2; -pub const PHY_SRC_ERR_CNT : u8 = 1 << 4; - -pub const PHY_PRBS_TEST_THRESHOLD_LOBITS : u16 = 0x317; - -pub const PHY_PRBS_TEST_THRESHOLD_MIDBITS : u16 = 0x318; - -pub const PHY_PRBS_TEST_THRESHOLD_HIBITS : u16 = 0x319; - -pub const PHY_PRBS_TEST_ERRCNT_LOBITS : u16 = 0x31a; - -pub const PHY_PRBS_TEST_ERRCNT_MIDBITS : u16 = 0x31b; - -pub const PHY_PRBS_TEST_ERRCNT_HIBITS : u16 = 0x31c; - -pub const PHY_PRBS_TEST_STATUS : u16 = 0x31d; - -pub const SHORT_TPL_TEST_0 : u16 = 0x32c; -pub const SHORT_TPL_TEST_EN : u8 = 1 << 0; -pub const SHORT_TPL_TEST_RESET : u8 = 1 << 1; -pub const SHORT_TPL_DAC_SEL : u8 = 1 << 2; -pub const SHORT_TPL_SP_SEL : u8 = 1 << 4; - -pub const SHORT_TPL_TEST_1 : u16 = 0x32d; - -pub const SHORT_TPL_TEST_2 : u16 = 0x32e; - -pub const SHORT_TPL_TEST_3 : u16 = 0x32f; - -pub const DEVICE_CONFIG_REG_2 : u16 = 0x333; - -pub const JESD_BIT_INVERSE_CTRL : u16 = 0x334; - -pub const DID_REG : u16 = 0x400; - -pub const BID_REG : u16 = 0x401; -pub const BID_RD : u8 = 1 << 0; -pub const ADJCNT_RD : u8 = 1 << 4; - -pub const LID0_REG : u16 = 0x402; -pub const LID0_RD : u8 = 1 << 0; -pub const PHADJ_RD : u8 = 1 << 5; -pub const ADJDIR_RD : u8 = 1 << 6; - -pub const SCR_L_REG : u16 = 0x403; -pub const L_1_RD : u8 = 1 << 0; -pub const SCR_RD : u8 = 1 << 7; - -pub const F_REG : u16 = 0x404; - -pub const K_REG : u16 = 0x405; - -pub const M_REG : u16 = 0x406; - -pub const CS_N_REG : u16 = 0x407; -pub const N_1_RD : u8 = 1 << 0; -pub const CS_RD : u8 = 1 << 6; - -pub const NP_REG : u16 = 0x408; -pub const NP_1_RD : u8 = 1 << 0; -pub const SUBCLASSV_RD : u8 = 1 << 5; - -pub const S_REG : u16 = 0x409; -pub const S_1_RD : u8 = 1 << 0; -pub const JESDV_RD : u8 = 1 << 5; - -pub const HD_CF_REG : u16 = 0x40a; -pub const CF_RD : u8 = 1 << 0; -pub const HD_RD : u8 = 1 << 7; - -pub const RES1_REG : u16 = 0x40b; - -pub const RES2_REG : u16 = 0x40c; - -pub const CHECKSUM0_REG : u16 = 0x40d; - -pub const COMPSUM0_REG : u16 = 0x40e; - -pub const LID1_REG : u16 = 0x412; - -pub const CHECKSUM1_REG : u16 = 0x415; - -pub const COMPSUM1_REG : u16 = 0x416; - -pub const LID2_REG : u16 = 0x41a; - -pub const CHECKSUM2_REG : u16 = 0x41d; - -pub const COMPSUM2_REG : u16 = 0x41e; - -pub const LID3_REG : u16 = 0x422; - -pub const CHECKSUM3_REG : u16 = 0x425; - -pub const COMPSUM3_REG : u16 = 0x426; - -pub const LID4_REG : u16 = 0x42a; - -pub const CHECKSUM4_REG : u16 = 0x42d; - -pub const COMPSUM4_REG : u16 = 0x42e; - -pub const LID5_REG : u16 = 0x432; - -pub const CHECKSUM5_REG : u16 = 0x435; - -pub const COMPSUM5_REG : u16 = 0x436; - -pub const LID6_REG : u16 = 0x43a; - -pub const CHECKSUM6_REG : u16 = 0x43d; - -pub const COMPSUM6_REG : u16 = 0x43e; - -pub const LID7_REG : u16 = 0x442; - -pub const CHECKSUM7_REG : u16 = 0x445; - -pub const COMPSUM7_REG : u16 = 0x446; - -pub const ILS_DID : u16 = 0x450; - -pub const ILS_BID : u16 = 0x451; -pub const BID : u8 = 1 << 0; -pub const ADJCNT : u8 = 1 << 4; - -pub const ILS_LID0 : u16 = 0x452; -pub const LID0 : u8 = 1 << 0; -pub const PHADJ : u8 = 1 << 5; -pub const ADJDIR : u8 = 1 << 6; - -pub const ILS_SCR_L : u16 = 0x453; -pub const L_1 : u8 = 1 << 0; -pub const SCR : u8 = 1 << 7; - -pub const ILS_F : u16 = 0x454; - -pub const ILS_K : u16 = 0x455; - -pub const ILS_M : u16 = 0x456; - -pub const ILS_CS_N : u16 = 0x457; -pub const N_1 : u8 = 1 << 0; -pub const CS : u8 = 1 << 6; - -pub const ILS_NP : u16 = 0x458; -pub const NP_1 : u8 = 1 << 0; -pub const SUBCLASSV : u8 = 1 << 5; - -pub const ILS_S : u16 = 0x459; -pub const S_1 : u8 = 1 << 0; -pub const JESDV : u8 = 1 << 5; - -pub const ILS_HD_CF : u16 = 0x45a; -pub const CF : u8 = 1 << 0; -pub const HD : u8 = 1 << 7; - -pub const ILS_RES1 : u16 = 0x45b; - -pub const ILS_RES2 : u16 = 0x45c; - -pub const ILS_CHECKSUM : u16 = 0x45d; - -pub const ERRCNTRMON : u16 = 0x46b; -pub const CNTRSEL : u8 = 1 << 0; -pub const LANESEL : u8 = 1 << 4; - -pub const LANEDESKEW : u16 = 0x46c; - -pub const BADDISPARITY : u16 = 0x46d; -pub const LANE_ADDR_DIS : u8 = 1 << 0; -pub const RST_ERR_CNTR_DIS : u8 = 1 << 5; -pub const DISABLE_ERR_CNTR_DIS : u8 = 1 << 6; -pub const RST_IRQ_DIS : u8 = 1 << 7; - -pub const NIT_W : u16 = 0x46e; -pub const LANE_ADDR_NIT : u8 = 1 << 0; -pub const RST_ERR_CNTR_NIT : u8 = 1 << 5; -pub const DISABLE_ERR_CNTR_NIT : u8 = 1 << 6; -pub const RST_IRQ_NIT : u8 = 1 << 7; - -pub const UNEXPECTEDCONTROL_W : u16 = 0x46f; -pub const LANE_ADDR_UCC : u8 = 1 << 0; -pub const RST_ERR_CNTR_UCC : u8 = 1 << 5; -pub const DISABLE_ERR_CNTR_UCC : u8 = 1 << 6; -pub const RST_IRQ_UCC : u8 = 1 << 7; - -pub const CODEGRPSYNCFLG : u16 = 0x470; - -pub const FRAMESYNCFLG : u16 = 0x471; - -pub const GOODCHKSUMFLG : u16 = 0x472; - -pub const INITLANESYNCFLG : u16 = 0x473; - -pub const CTRLREG1 : u16 = 0x476; - -pub const CTRLREG2 : u16 = 0x477; -pub const THRESHOLD_MASK_EN : u8 = 1 << 3; -pub const ILAS_MODE : u8 = 1 << 7; - -pub const KVAL : u16 = 0x478; - -pub const IRQVECTOR_MASK : u16 = 0x47a; -pub const CODEGRPSYNC_MASK : u8 = 1 << 0; -pub const BADCHECKSUM_MASK : u8 = 1 << 2; -pub const INITIALLANESYNC_MASK : u8 = 1 << 3; -pub const UCC_MASK : u8 = 1 << 5; -pub const NIT_MASK : u8 = 1 << 6; -pub const BADDIS_MASK : u8 = 1 << 7; - -pub const SYNCASSERTIONMASK : u16 = 0x47b; -pub const CMM_ENABLE : u8 = 1 << 3; -pub const CMM : u8 = 1 << 4; -pub const UCC_S : u8 = 1 << 5; -pub const NIT_S : u8 = 1 << 6; -pub const BADDIS_S : u8 = 1 << 7; - -pub const ERRORTHRES : u16 = 0x47c; - -pub const LANEENABLE : u16 = 0x47d; - -pub const RAMP_ENA : u16 = 0x47e; - -pub const DIG_TEST0 : u16 = 0x520; -pub const DC_TEST_MODE : u8 = 1 << 1; - -pub const DC_TEST_VALUEI0 : u16 = 0x521; - -pub const DC_TEST_VALUEI1 : u16 = 0x522; - -pub const DC_TEST_VALUEQ0 : u16 = 0x523; - -pub const DC_TEST_VALUEQ1 : u16 = 0x524; diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs deleted file mode 100644 index adf753141..000000000 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ /dev/null @@ -1,419 +0,0 @@ -mod hmc830 { - use board_misoc::{csr, clock}; - - fn spi_setup() { - unsafe { - while csr::converter_spi::idle_read() == 0 {} - csr::converter_spi::offline_write(0); - csr::converter_spi::end_write(1); - csr::converter_spi::cs_polarity_write(0b0001); - csr::converter_spi::clk_polarity_write(0); - csr::converter_spi::clk_phase_write(0); - csr::converter_spi::lsb_first_write(0); - csr::converter_spi::half_duplex_write(0); - csr::converter_spi::length_write(32 - 1); - csr::converter_spi::div_write(16 - 2); - csr::converter_spi::cs_write(1 << csr::CONFIG_CONVERTER_SPI_HMC830_CS); - } - } - - pub fn select_spi_mode() { - spi_setup(); - unsafe { - // rising egde on CS since cs_polarity still 0 - // selects "HMC Mode" - // do a dummy cycle with cs still high to clear CS - csr::converter_spi::length_write(0); - csr::converter_spi::data_write(0); - while csr::converter_spi::writable_read() == 0 {} - csr::converter_spi::length_write(32 - 1); - } - } - - fn write(addr: u8, data: u32) { - let val = ((addr as u32) << 24) | data; - unsafe { - while csr::converter_spi::writable_read() == 0 {} - csr::converter_spi::data_write(val << 1); // last clk cycle loads data - } - } - - fn read(addr: u8) -> u32 { - // SDO (miso/read bits) is technically CPHA=1, while SDI is CPHA=0 - // trust that the 8.2ns+0.2ns/pF provide enough hold time on top of - // the SPI round trip delay and stick with CPHA=0 - write((1 << 6) | addr, 0); - unsafe { - while csr::converter_spi::writable_read() == 0 {} - csr::converter_spi::data_read() & 0xffffff - } - } - - pub fn detect() -> Result<(), &'static str> { - spi_setup(); - let id = read(0x00); - if id != 0xa7975 { - error!("invalid HMC830 ID: 0x{:08x}", id); - return Err("invalid HMC830 identification"); - } - - Ok(()) - } - - pub fn init() { - // Configure HMC830 for integer-N operation - // See "PLLs with integrated VCO- RF Applications Product & Operating - // Guide" - spi_setup(); - info!("loading HMC830 configuration..."); - - write(0x0, 0x20); // software reset - write(0x0, 0x00); // normal operation - write(0x6, 0x307ca); // integer-N mode (NB data sheet table 5.8 not self-consistent) - write(0x7, 0x4d); // digital lock detect, 1/2 cycle window (6.5ns window) - write(0x9, 0x2850); // charge pump: 1.6mA, no offset - write(0xa, 0x2045); // for wideband devices like the HMC830 - write(0xb, 0x7c061); // for HMC830 - - // VCO subsystem registers - // NB software reset does not seem to reset these registers, so always - // program them all! - write(0x5, 0xf88); // 1: defaults - write(0x5, 0x6010); // 2: mute output until output divider set - write(0x5, 0x2818); // 3: wideband PLL defaults - write(0x5, 0x60a0); // 4: HMC830 magic value - write(0x5, 0x1628); // 5: HMC830 magic value - write(0x5, 0x7fb0); // 6: HMC830 magic value - write(0x5, 0x0); // ready for VCO auto-cal - - info!(" ...done"); - } - - pub fn set_dividers(r_div: u32, n_div: u32, m_div: u32, out_div: u32) { - // VCO frequency: f_vco = (f_ref/r_div)*(n_int + n_frac/2**24) - // VCO frequency range [1.5GHz, 3GHz] - // Output frequency: f_out = f_vco/out_div - // Max PFD frequency: 125MHz for integer-N, 100MHz for fractional - // (mode B) - // Max reference frequency: 350MHz, however f_ref >= 200MHz requires - // setting 0x08[21]=1 - // - // Warning: Output divider is not synchronized! Set to 1 for deterministic - // phase at the output. - // - // :param r_div: reference divider [1, 16383] - // :param n_div: VCO divider, integer part. Integer-N mode: [16, 2**19-1] - // fractional mode: [20, 2**19-4] - // :param m_div: VCO divider, fractional part [0, 2**24-1] - // :param out_div: output divider [1, 62] (0 mutes output) - info!("setting HMC830 dividers..."); - write(0x5, 0x6010 + (out_div << 7) + (((out_div <= 2) as u32) << 15)); - write(0x5, 0x0); // ready for VCO auto-cal - write(0x2, r_div); - write(0x4, m_div); - write(0x3, n_div); - - info!(" ...done"); - } - - pub fn check_locked() -> Result<(), &'static str> { - info!("waiting for HMC830 lock..."); - let t = clock::get_ms(); - while read(0x12) & 0x02 == 0 { - if clock::get_ms() > t + 2000 { - error!("lock timeout. Register dump:"); - for addr in 0x00..0x14 { - // These registers don't exist (in the data sheet at least) - if addr == 0x0d || addr == 0x0e { continue; } - error!(" [0x{:02x}] = 0x{:04x}", addr, read(addr)); - } - return Err("lock timeout"); - } - } - info!(" ...locked"); - - Ok(()) - } -} - -pub mod hmc7043 { - use board_misoc::{csr, clock}; - - // Warning: dividers are not synchronized with HMC830 clock input! - // Set DAC_CLK_DIV to 1 or 0 for deterministic phase. - // (0 bypasses the divider and reduces noise) - const DAC_CLK_DIV: u16 = 0; - const FPGA_CLK_DIV: u16 = 16; // Keep in sync with jdcg.rs - const SYSREF_DIV: u16 = 256; // Keep in sync with jdcg.rs - const HMC_SYSREF_DIV: u16 = SYSREF_DIV*8; // must be <= 4MHz - - // enabled, divider, output config, is sysref - const OUTPUT_CONFIG: [(bool, u16, u8, bool); 14] = [ - (true, DAC_CLK_DIV, 0x08, false), // 0: DAC1_CLK - (true, SYSREF_DIV, 0x01, true), // 1: DAC1_SYSREF - (true, DAC_CLK_DIV, 0x08, false), // 2: DAC0_CLK - (true, SYSREF_DIV, 0x01, true), // 3: DAC0_SYSREF - (true, SYSREF_DIV, 0x10, true), // 4: AMC_FPGA_SYSREF0 - (false, FPGA_CLK_DIV, 0x10, true), // 5: AMC_FPGA_SYSREF1 - (false, 0, 0x10, false), // 6: unused - (true, FPGA_CLK_DIV, 0x10, true), // 7: RTM_FPGA_SYSREF0 - (true, FPGA_CLK_DIV, 0x08, false), // 8: GTP_CLK0_IN - (false, 0, 0x10, false), // 9: unused - (false, 0, 0x10, false), // 10: unused - (false, 0, 0x08, false), // 11: unused / uFL - (false, 0, 0x10, false), // 12: unused - (false, FPGA_CLK_DIV, 0x10, true), // 13: RTM_FPGA_SYSREF1 - ]; - - fn spi_setup() { - unsafe { - while csr::converter_spi::idle_read() == 0 {} - csr::converter_spi::offline_write(0); - csr::converter_spi::end_write(1); - csr::converter_spi::cs_polarity_write(0b0001); - csr::converter_spi::clk_polarity_write(0); - csr::converter_spi::clk_phase_write(0); - csr::converter_spi::lsb_first_write(0); - csr::converter_spi::half_duplex_write(0); // change mid-transaction for reads - csr::converter_spi::length_write(24 - 1); - csr::converter_spi::div_write(16 - 2); - csr::converter_spi::cs_write(1 << csr::CONFIG_CONVERTER_SPI_HMC7043_CS); - } - } - - fn spi_wait_idle() { - unsafe { - while csr::converter_spi::idle_read() == 0 {} - } - } - - fn write(addr: u16, data: u8) { - let cmd = (0 << 15) | addr; - let val = ((cmd as u32) << 8) | data as u32; - unsafe { - while csr::converter_spi::writable_read() == 0 {} - csr::converter_spi::data_write(val << 8); - } - } - - fn read(addr: u16) -> u8 { - let cmd = (1 << 15) | addr; - let val = cmd as u32; - unsafe { - while csr::converter_spi::writable_read() == 0 {} - csr::converter_spi::end_write(0); - csr::converter_spi::length_write(16 - 1); - csr::converter_spi::data_write(val << 16); - while csr::converter_spi::writable_read() == 0 {} - csr::converter_spi::end_write(1); - csr::converter_spi::half_duplex_write(1); - csr::converter_spi::length_write(8 - 1); - csr::converter_spi::data_write(0); - while csr::converter_spi::writable_read() == 0 {} - csr::converter_spi::half_duplex_write(0); - csr::converter_spi::length_write(24 - 1); - csr::converter_spi::data_read() as u8 - } - } - - pub const CHIP_ID: u32 = 0xf17904; - - pub fn get_id() -> u32 { - spi_setup(); - (read(0x78) as u32) << 16 | (read(0x79) as u32) << 8 | read(0x7a) as u32 - } - - pub fn detect() -> Result<(), &'static str> { - let id = get_id(); - if id != CHIP_ID { - error!("invalid HMC7043 ID: 0x{:08x}", id); - return Err("invalid HMC7043 identification"); - } - - Ok(()) - } - - pub fn enable() { - info!("enabling HMC7043"); - - unsafe { - csr::hmc7043_reset::out_write(0); - } - clock::spin_us(10_000); - - spi_setup(); - write(0x0, 0x1); // Software reset - write(0x0, 0x0); // Normal operation - write(0x1, 0x48); // mute all outputs - } - - const GPO_MUX_CLK_OUT_PHASE: u8 = 3; - const GPO_MUX_FORCE1: u8 = 10; - const GPO_MUX_FORCE0: u8 = 11; - - /* Read an HMC7043 internal status bit through the GPO interface. - * This method is required to work around bugs in the register interface. - */ - fn gpo_indirect_read(mux_setting: u8) -> bool { - write(0x50, (mux_setting << 2) | 0x3); - spi_wait_idle(); - unsafe { - csr::hmc7043_gpo::in_read() == 1 - } - } - - pub fn init() { - spi_setup(); - info!("loading configuration..."); - - write(0x3, 0x14); // Disable the RFSYNCIN reseeder - write(0xA, 0x06); // Disable the RFSYNCIN input buffer - write(0xB, 0x07); // Enable the CLKIN input as LVPECL - write(0x9F, 0x4d); // Unexplained high-performance mode - write(0xA0, 0xdf); // Unexplained high-performance mode - - // Enable required output groups - let mut output_group_en = 0; - for channel in 0..OUTPUT_CONFIG.len() { - let enabled = OUTPUT_CONFIG[channel].0; - if enabled { - let group = channel/2; - output_group_en |= 1 << group; - } - } - write(0x4, output_group_en); - - // Set SYSREF timer divider. - // We don't need this "feature", but the HMC7043 won't work without. - write(0x5c, (HMC_SYSREF_DIV & 0xff) as u8); - write(0x5d, ((HMC_SYSREF_DIV & 0xf00) >> 8) as u8); - - for channel in 0..OUTPUT_CONFIG.len() { - let channel_base = 0xc8 + 0x0a*(channel as u16); - let (enabled, divider, outcfg, is_sysref) = OUTPUT_CONFIG[channel]; - - if enabled { - if !is_sysref { - // DCLK channel: enable high-performance mode - write(channel_base, 0xd1); - } else { - // SYSREF channel: disable hi-perf mode, enable slip - write(channel_base, 0x71); - } - } else { - write(channel_base, 0x10); - } - write(channel_base + 0x1, (divider & 0xff) as u8); - write(channel_base + 0x2, ((divider & 0xf00) >> 8) as u8); - - // bypass analog phase shift on DCLK channels to reduce noise - if !is_sysref { - if divider != 0 { - write(channel_base + 0x7, 0x00); // enable divider - } else { - write(channel_base + 0x7, 0x03); // bypass divider for lowest noise - } - } else { - write(channel_base + 0x7, 0x01); - } - - write(channel_base + 0x8, outcfg) - } - - write(0x1, 0x4a); // Reset dividers and FSMs - write(0x1, 0x48); - write(0x1, 0xc8); // Synchronize dividers - write(0x1, 0x40); // Unmute, high-performance/low-noise mode - - clock::spin_us(10_000); - - info!(" ...done"); - } - - pub fn test_gpo() -> Result<(), &'static str> { - info!("testing GPO..."); - for trial in 0..10 { - if !gpo_indirect_read(GPO_MUX_FORCE1) { - info!(" ...failed. GPO I/O did not go high (#{})", trial + 1); - return Err("GPO is not functioning"); - } - if gpo_indirect_read(GPO_MUX_FORCE0) { - info!(" ...failed. GPO I/O did not return low (#{})", trial + 1); - return Err("GPO is not functioning"); - } - } - info!(" ...passed"); - Ok(()) - } - - pub fn check_phased() -> Result<(), &'static str> { - if !gpo_indirect_read(GPO_MUX_CLK_OUT_PHASE) { - return Err("GPO reported phases did not align"); - } - // Should be the same as the GPO read - let sysref_fsm_status = read(0x91); - if sysref_fsm_status != 0x2 { - error!("Bad SYSREF FSM status: {:02x}", sysref_fsm_status); - return Err("Bad SYSREF FSM status"); - } - Ok(()) - } - - pub fn unmute() { - /* - * Never missing an opportunity to be awful, the HMC7043 produces broadband noise - * prior to intialization, which can upset the AMC FPGA. - * External circuitry mutes it. - */ - unsafe { - csr::hmc7043_out_en::out_write(1); - } - } - - pub fn sysref_delay_dac(dacno: u8, phase_offset: u8) { - spi_setup(); - if dacno == 0 { - write(0x00e9, phase_offset); - } else if dacno == 1 { - write(0x00d5, phase_offset); - } else { - unimplemented!(); - } - clock::spin_us(100); - } - - pub fn sysref_slip() { - spi_setup(); - write(0x0002, 0x02); - write(0x0002, 0x00); - clock::spin_us(100); - } -} - -pub fn init() -> Result<(), &'static str> { - #[cfg(all(hmc830_ref = "125", rtio_frequency = "125.0"))] - const DIV: (u32, u32, u32, u32) = (2, 32, 0, 1); // 125MHz -> 2.0GHz - #[cfg(all(hmc830_ref = "150", rtio_frequency = "150.0"))] - const DIV: (u32, u32, u32, u32) = (2, 32, 0, 1); // 150MHz -> 2.4GHz - - /* do not use other SPI devices before HMC830 SPI mode selection */ - hmc830::select_spi_mode(); - hmc830::detect()?; - hmc830::init(); - - hmc830::set_dividers(DIV.0, DIV.1, DIV.2, DIV.3); - - hmc830::check_locked()?; - - if hmc7043::get_id() == hmc7043::CHIP_ID { - error!("HMC7043 detected while in reset (board rework missing?)"); - } - hmc7043::enable(); - hmc7043::detect()?; - hmc7043::init(); - hmc7043::test_gpo()?; - hmc7043::check_phased()?; - hmc7043::unmute(); - - Ok(()) -} diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 694805cfa..7436fc8c5 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -25,13 +25,6 @@ pub mod si5324; #[cfg(has_wrpll)] pub mod wrpll; -#[cfg(has_hmc830_7043)] -pub mod hmc830_7043; -#[cfg(has_ad9154)] -mod ad9154_reg; -#[cfg(has_ad9154)] -pub mod ad9154; - #[cfg(has_grabber)] pub mod grabber; diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index 3b1103d99..63e49bd5e 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -182,12 +182,6 @@ fn init() -> Result<()> { i2c::switch_select(BUSNO, 0x70, 0)?; i2c::switch_select(BUSNO, 0x71, 1 << 3)?; } - #[cfg(soc_platform = "sayma_amc")] - i2c::switch_select(BUSNO, 0x70, 1 << 4)?; - #[cfg(soc_platform = "sayma_rtm")] - i2c::switch_select(BUSNO, 0x77, 1 << 5)?; - #[cfg(soc_platform = "metlino")] - i2c::switch_select(BUSNO, 0x70, 1 << 4)?; #[cfg(soc_platform = "kc705")] i2c::switch_select(BUSNO, 0x74, 1 << 7)?; diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index 4b0fa9754..a9c9a702f 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -175,8 +175,6 @@ mod si549 { use board_misoc::clock; use super::i2c; - #[cfg(any(soc_platform = "metlino", soc_platform = "sayma_amc", soc_platform = "sayma_rtm"))] - pub const ADDRESS: u8 = 0x55; #[cfg(soc_platform = "kasli")] pub const ADDRESS: u8 = 0x67; diff --git a/artiq/firmware/libboard_misoc/net_settings.rs b/artiq/firmware/libboard_misoc/net_settings.rs index 2b69d9262..36c85319f 100644 --- a/artiq/firmware/libboard_misoc/net_settings.rs +++ b/artiq/firmware/libboard_misoc/net_settings.rs @@ -67,10 +67,6 @@ pub fn get_adresses() -> NetAddresses { .map(|addr_buf| EthernetAddress(addr_buf)) .unwrap_or_else(|_e| EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x21])); } - #[cfg(soc_platform = "sayma_amc")] - { hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x11]); } - #[cfg(soc_platform = "metlino")] - { hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x19]); } #[cfg(soc_platform = "kc705")] { hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]); } } diff --git a/artiq/firmware/libboard_misoc/spiflash.rs b/artiq/firmware/libboard_misoc/spiflash.rs index 9b5ca31f5..598d96633 100644 --- a/artiq/firmware/libboard_misoc/spiflash.rs +++ b/artiq/firmware/libboard_misoc/spiflash.rs @@ -114,7 +114,7 @@ pub unsafe fn write(mut addr: usize, mut data: &[u8]) { } } -#[cfg(any(soc_platform = "kasli", soc_platform = "metlino", soc_platform = "kc705"))] +#[cfg(any(soc_platform = "kasli", soc_platform = "kc705"))] pub unsafe fn reload () -> ! { csr::icap::iprog_write(1); loop {} diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index b36fd9251..f91f4d391 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -341,7 +341,7 @@ pub fn panic_impl(info: &core::panic::PanicInfo) -> ! { }); if config::read_str("panic_reset", |r| r == Ok("1")) && - cfg!(any(soc_platform = "kasli", soc_platform = "metlino", soc_platform = "kc705")) { + cfg!(any(soc_platform = "kasli", soc_platform = "kc705")) { println!("restarting..."); unsafe { kernel::stop(); diff --git a/artiq/firmware/runtime/rtio_clocking.rs b/artiq/firmware/runtime/rtio_clocking.rs index 52ab35915..e23934e33 100644 --- a/artiq/firmware/runtime/rtio_clocking.rs +++ b/artiq/firmware/runtime/rtio_clocking.rs @@ -126,7 +126,7 @@ fn setup_si5324_as_synthesizer(cfg: RtioClock) { crystal_ref: false } }, - RtioClock::Int_100 => { // 100MHz output, from crystal. Also used as reference for Sayma HMC830. + RtioClock::Int_100 => { // 100MHz output, from crystal info!("using internal 100MHz RTIO clock"); si5324::FrequencySettings { n1_hs : 9, @@ -172,8 +172,6 @@ fn setup_si5324_as_synthesizer(cfg: RtioClock) { let si5324_ref_input = si5324::Input::Ckin1; #[cfg(all(soc_platform = "kasli", not(hw_rev = "v2.0")))] let si5324_ref_input = si5324::Input::Ckin2; - #[cfg(soc_platform = "metlino")] - let si5324_ref_input = si5324::Input::Ckin2; #[cfg(soc_platform = "kc705")] let si5324_ref_input = si5324::Input::Ckin2; si5324::setup(&si5324_settings, si5324_ref_input).expect("cannot initialize Si5324"); @@ -192,8 +190,6 @@ fn setup_si5324(clock_cfg: RtioClock) { let si5324_ext_input = si5324::Input::Ckin1; #[cfg(all(soc_platform = "kasli", not(hw_rev = "v2.0")))] let si5324_ext_input = si5324::Input::Ckin2; - #[cfg(soc_platform = "metlino")] - let si5324_ext_input = si5324::Input::Ckin2; #[cfg(soc_platform = "kc705")] let si5324_ext_input = si5324::Input::Ckin1; match clock_cfg { diff --git a/artiq/firmware/satman/jdac_common.rs b/artiq/firmware/satman/jdac_common.rs deleted file mode 100644 index 3c185516f..000000000 --- a/artiq/firmware/satman/jdac_common.rs +++ /dev/null @@ -1,74 +0,0 @@ -pub const INIT: u8 = 0x00; -pub const PRINT_STATUS: u8 = 0x01; -pub const PRBS: u8 = 0x02; -pub const STPL: u8 = 0x03; - -pub const SYSREF_DELAY_DAC: u8 = 0x10; -pub const SYSREF_SLIP: u8 = 0x11; -pub const SYNC: u8 = 0x12; - -pub const DDMTD_SYSREF_RAW: u8 = 0x20; -pub const DDMTD_SYSREF: u8 = 0x21; - - -fn average_2phases(a: i32, b: i32, modulo: i32) -> i32 { - let diff = ((a - b + modulo/2 + modulo) % modulo) - modulo/2; - return (modulo + b + diff/2) % modulo; -} - -pub fn average_phases(phases: &[i32], modulo: i32) -> i32 { - if phases.len() == 1 { - panic!("input array length must be a power of 2"); - } else if phases.len() == 2 { - average_2phases(phases[0], phases[1], modulo) - } else { - let cut = phases.len()/2; - average_2phases( - average_phases(&phases[..cut], modulo), - average_phases(&phases[cut..], modulo), - modulo) - } -} - -pub const RAW_DDMTD_N_SHIFT: i32 = 6; -pub const RAW_DDMTD_N: i32 = 1 << RAW_DDMTD_N_SHIFT; -pub const DDMTD_DITHER_BITS: i32 = 1; -pub const DDMTD_N_SHIFT: i32 = RAW_DDMTD_N_SHIFT + DDMTD_DITHER_BITS; -pub const DDMTD_N: i32 = 1 << DDMTD_N_SHIFT; - -#[cfg(has_ad9154)] -use board_misoc::{clock, csr}; - -#[cfg(has_ad9154)] -pub fn init_ddmtd() -> Result<(), &'static str> { - unsafe { - csr::sysref_ddmtd::reset_write(1); - clock::spin_us(1); - csr::sysref_ddmtd::reset_write(0); - clock::spin_us(100); - if csr::sysref_ddmtd::locked_read() != 0 { - Ok(()) - } else { - Err("DDMTD helper PLL failed to lock") - } - } -} - -#[cfg(has_ad9154)] -pub fn measure_ddmdt_phase_raw() -> i32 { - unsafe { csr::sysref_ddmtd::dt_read() as i32 } -} - -#[cfg(has_ad9154)] -pub fn measure_ddmdt_phase() -> i32 { - const AVG_PRECISION_SHIFT: i32 = 6; - const AVG_PRECISION: i32 = 1 << AVG_PRECISION_SHIFT; - const AVG_MOD: i32 = 1 << (RAW_DDMTD_N_SHIFT + AVG_PRECISION_SHIFT + DDMTD_DITHER_BITS); - - let mut measurements = [0; AVG_PRECISION as usize]; - for i in 0..AVG_PRECISION { - measurements[i as usize] = measure_ddmdt_phase_raw() << (AVG_PRECISION_SHIFT + DDMTD_DITHER_BITS); - clock::spin_us(10); - } - average_phases(&measurements, AVG_MOD) >> AVG_PRECISION_SHIFT -} diff --git a/artiq/firmware/satman/jdcg.rs b/artiq/firmware/satman/jdcg.rs deleted file mode 100644 index c8a34827b..000000000 --- a/artiq/firmware/satman/jdcg.rs +++ /dev/null @@ -1,589 +0,0 @@ -pub mod jesd { - use board_misoc::{csr, clock}; - - pub fn reset(reset: bool) { - unsafe { - csr::jesd_crg::jreset_write(if reset {1} else {0}); - } - } - - pub fn enable(dacno: u8, en: bool) { - unsafe { - (csr::JDCG[dacno as usize].jesd_control_enable_write)(if en {1} else {0}) - } - } - - pub fn phy_done(dacno: u8) -> bool { - unsafe { - (csr::JDCG[dacno as usize].jesd_control_phy_done_read)() != 0 - } - } - - pub fn ready(dacno: u8) -> bool { - unsafe { - (csr::JDCG[dacno as usize].jesd_control_ready_read)() != 0 - } - } - - pub fn prbs(dacno: u8, en: bool) { - unsafe { - (csr::JDCG[dacno as usize].jesd_control_prbs_config_write)(if en {0b01} else {0b00}) - } - clock::spin_us(5000); - } - - pub fn stpl(dacno: u8, en: bool) { - unsafe { - (csr::JDCG[dacno as usize].jesd_control_stpl_enable_write)(if en {1} else {0}) - } - clock::spin_us(5000); - } - - pub fn jsync(dacno: u8) -> bool { - unsafe { - (csr::JDCG[dacno as usize].jesd_control_jsync_read)() != 0 - } - } -} - -pub mod jdac { - use board_misoc::{csr, clock}; - use board_artiq::drtioaux; - - use super::jesd; - use super::super::jdac_common; - - pub fn basic_request(dacno: u8, reqno: u8, param: u8) -> Result { - if let Err(e) = drtioaux::send(1, &drtioaux::Packet::JdacBasicRequest { - destination: 0, - dacno: dacno, - reqno: reqno, - param: param - }) { - error!("aux packet error ({})", e); - return Err("aux packet error while sending for JESD DAC basic request"); - } - match drtioaux::recv_timeout(1, Some(1000)) { - Ok(drtioaux::Packet::JdacBasicReply { succeeded, retval }) => { - if succeeded { - Ok(retval) - } else { - error!("JESD DAC basic request failed (dacno={}, reqno={})", dacno, reqno); - Err("remote error status to JESD DAC basic request") - } - }, - Ok(packet) => { - error!("received unexpected aux packet: {:?}", packet); - Err("unexpected aux packet in reply to JESD DAC basic request") - }, - Err(e) => { - error!("aux packet error ({})", e); - Err("aux packet error while waiting for JESD DAC basic reply") - } - } - } - - pub fn init() -> Result<(), &'static str> { - for dacno in 0..csr::JDCG.len() { - let dacno = dacno as u8; - info!("DAC-{} initializing...", dacno); - - jesd::enable(dacno, true); - clock::spin_us(10_000); - if !jesd::phy_done(dacno) { - error!("JESD core PHY not done"); - return Err("JESD core PHY not done"); - } - - basic_request(dacno, jdac_common::INIT, 0)?; - - // JESD ready depends on JSYNC being valid, so DAC init needs to happen first - if !jesd::ready(dacno) { - error!("JESD core reported not ready, sending DAC status print request"); - basic_request(dacno, jdac_common::PRINT_STATUS, 0)?; - return Err("JESD core reported not ready"); - } - - jesd::prbs(dacno, true); - basic_request(dacno, jdac_common::PRBS, 0)?; - jesd::prbs(dacno, false); - - basic_request(dacno, jdac_common::INIT, 0)?; - clock::spin_us(5000); - - if !jesd::jsync(dacno) { - error!("JESD core reported bad SYNC"); - return Err("JESD core reported bad SYNC"); - } - - info!(" ...done initializing"); - } - Ok(()) - } - - pub fn stpl() -> Result<(), &'static str> { - for dacno in 0..csr::JDCG.len() { - let dacno = dacno as u8; - - info!("Running STPL test on DAC-{}...", dacno); - - jesd::stpl(dacno, true); - basic_request(dacno, jdac_common::STPL, 0)?; - jesd::stpl(dacno, false); - - info!(" ...done STPL test"); - } - Ok(()) - } -} - -pub mod jesd204sync { - use board_misoc::{csr, clock, config}; - - use super::jdac; - use super::super::jdac_common; - - const HMC7043_ANALOG_DELAY_RANGE: u8 = 24; - - const FPGA_CLK_DIV: u16 = 16; // Keep in sync with hmc830_7043.rs - const SYSREF_DIV: u16 = 256; // Keep in sync with hmc830_7043.rs - - fn hmc7043_sysref_delay_dac(dacno: u8, phase_offset: u8) -> Result<(), &'static str> { - match jdac::basic_request(dacno, jdac_common::SYSREF_DELAY_DAC, phase_offset) { - Ok(_) => Ok(()), - Err(e) => Err(e) - } - } - - - fn hmc7043_sysref_slip() -> Result<(), &'static str> { - match jdac::basic_request(0, jdac_common::SYSREF_SLIP, 0) { - Ok(_) => Ok(()), - Err(e) => Err(e) - } - } - - fn ad9154_sync(dacno: u8) -> Result { - match jdac::basic_request(dacno, jdac_common::SYNC, 0) { - Ok(0) => Ok(false), - Ok(_) => Ok(true), - Err(e) => Err(e) - } - } - - fn measure_ddmdt_phase_raw() -> Result { - Ok(jdac::basic_request(0, jdac_common::DDMTD_SYSREF_RAW, 0)? as i32) - } - - fn measure_ddmdt_phase() -> Result { - Ok(jdac::basic_request(0, jdac_common::DDMTD_SYSREF, 0)? as i32) - } - - fn test_ddmtd_stability(raw: bool, tolerance: i32) -> Result<(), &'static str> { - info!("testing DDMTD stability (raw={}, tolerance={})...", raw, tolerance); - - let modulo = if raw { jdac_common::RAW_DDMTD_N } else { jdac_common::DDMTD_N }; - let measurement = if raw { measure_ddmdt_phase_raw } else { measure_ddmdt_phase }; - let ntests = if raw { 150 } else { 15 }; - - let mut max_pkpk = 0; - for _ in 0..32 { - // If we are near the edges, wraparound can throw off the simple min/max computation. - // In this case, add an offset to get near the center. - let quadrant = measure_ddmdt_phase()?; - let center_offset = - if quadrant < jdac_common::DDMTD_N/4 || quadrant > 3*jdac_common::DDMTD_N/4 { - modulo/2 - } else { - 0 - }; - - let mut min = modulo; - let mut max = 0; - for _ in 0..ntests { - let m = (measurement()? + center_offset) % modulo; - if m < min { - min = m; - } - if m > max { - max = m; - } - } - let pkpk = max - min; - if pkpk > max_pkpk { - max_pkpk = pkpk; - } - if pkpk > tolerance { - error!(" ...excessive peak-peak jitter: {} (min={} max={} center_offset={})", pkpk, - min, max, center_offset); - return Err("excessive DDMTD peak-peak jitter"); - } - hmc7043_sysref_slip(); - } - - info!(" ...passed, peak-peak jitter: {}", max_pkpk); - Ok(()) - } - - fn test_slip_ddmtd() -> Result<(), &'static str> { - // expected_step = (RTIO clock frequency)*(DDMTD N)/(HMC7043 CLKIN frequency) - let expected_step = 8; - let tolerance = 1; - - info!("testing HMC7043 SYSREF slip against DDMTD..."); - let mut old_phase = measure_ddmdt_phase()?; - for _ in 0..1024 { - hmc7043_sysref_slip(); - let phase = measure_ddmdt_phase()?; - let step = (jdac_common::DDMTD_N + old_phase - phase) % jdac_common::DDMTD_N; - if (step - expected_step).abs() > tolerance { - error!(" ...got unexpected step: {} ({} -> {})", step, old_phase, phase); - return Err("HMC7043 SYSREF slip produced unexpected DDMTD step"); - } - old_phase = phase; - } - info!(" ...passed"); - Ok(()) - } - - 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 - } - } - - const SYSREF_SH_PRECISION_SHIFT: i32 = 5; - const SYSREF_SH_PRECISION: i32 = 1 << SYSREF_SH_PRECISION_SHIFT; - const SYSREF_SH_MOD: i32 = 1 << (jdac_common::DDMTD_N_SHIFT + SYSREF_SH_PRECISION_SHIFT); - - #[derive(Default)] - struct SysrefShLimits { - rising_phases: [i32; SYSREF_SH_PRECISION as usize], - falling_phases: [i32; SYSREF_SH_PRECISION as usize], - } - - fn measure_sysref_sh_limits() -> Result { - let mut ret = SysrefShLimits::default(); - let mut nslips = 0; - let mut rising_n = 0; - let mut falling_n = 0; - - let mut previous = sysref_sh_error(); - while rising_n < SYSREF_SH_PRECISION || falling_n < SYSREF_SH_PRECISION { - hmc7043_sysref_slip(); - nslips += 1; - if nslips > 1024 { - return Err("too many slips and not enough SYSREF S/H error transitions"); - } - - let current = sysref_sh_error(); - let phase = measure_ddmdt_phase()?; - if current && !previous && rising_n < SYSREF_SH_PRECISION { - ret.rising_phases[rising_n as usize] = phase << SYSREF_SH_PRECISION_SHIFT; - rising_n += 1; - } - if !current && previous && falling_n < SYSREF_SH_PRECISION { - ret.falling_phases[falling_n as usize] = phase << SYSREF_SH_PRECISION_SHIFT; - falling_n += 1; - } - previous = current; - } - Ok(ret) - } - - fn max_phase_deviation(average: i32, phases: &[i32]) -> i32 { - let mut ret = 0; - for phase in phases.iter() { - let deviation = (phase - average + jdac_common::DDMTD_N) % jdac_common::DDMTD_N; - if deviation > ret { - ret = deviation; - } - } - return ret; - } - - fn reach_sysref_ddmtd_target(target: i32, tolerance: i32) -> Result { - for _ in 0..1024 { - let delta = (measure_ddmdt_phase()? - target + jdac_common::DDMTD_N) % jdac_common::DDMTD_N; - if delta <= tolerance { - return Ok(delta) - } - hmc7043_sysref_slip(); - } - Err("failed to reach SYSREF DDMTD phase target") - } - - fn calibrate_sysref_target(rising_average: i32, falling_average: i32) -> Result { - info!("calibrating SYSREF DDMTD target phase..."); - let coarse_target = - if rising_average < falling_average { - (rising_average + falling_average)/2 - } else { - ((falling_average - (jdac_common::DDMTD_N - rising_average))/2 + jdac_common::DDMTD_N) % jdac_common::DDMTD_N - }; - info!(" SYSREF calibration coarse target: {}", coarse_target); - reach_sysref_ddmtd_target(coarse_target, 8)?; - let target = measure_ddmdt_phase()?; - info!(" ...done, target={}", target); - Ok(target) - } - - fn sysref_get_tsc_phase_raw() -> Result { - if sysref_sh_error() { - return Err("SYSREF failed S/H timing"); - } - let ret = unsafe { csr::sysref_sampler::sysref_phase_read() }; - Ok(ret) - } - - // Note: the code below assumes RTIO/SYSREF frequency ratio is a power of 2 - - fn sysref_get_tsc_phase() -> Result { - let mask = (SYSREF_DIV/FPGA_CLK_DIV - 1) as u8; - Ok((sysref_get_tsc_phase_raw()? & mask) as i32) - } - - pub fn test_sysref_frequency() -> Result<(), &'static str> { - info!("testing SYSREF frequency against raw TSC phase bit toggles..."); - - let mut all_toggles = 0; - let initial_phase = sysref_get_tsc_phase_raw()?; - for _ in 0..20000 { - clock::spin_us(1); - all_toggles |= sysref_get_tsc_phase_raw()? ^ initial_phase; - } - - let ratio = (SYSREF_DIV/FPGA_CLK_DIV) as u8; - let expected_toggles = 0xff ^ (ratio - 1); - if all_toggles == expected_toggles { - info!(" ...done (0x{:02x})", all_toggles); - Ok(()) - } else { - error!(" ...unexpected toggles: got 0x{:02x}, expected 0x{:02x}", - all_toggles, expected_toggles); - Err("unexpected toggles") - } - } - - fn sysref_slip_rtio_cycle() { - for _ in 0..FPGA_CLK_DIV { - hmc7043_sysref_slip(); - } - } - - pub fn test_slip_tsc() -> Result<(), &'static str> { - info!("testing HMC7043 SYSREF slip against TSC phase..."); - let initial_phase = sysref_get_tsc_phase()?; - let modulo = (SYSREF_DIV/FPGA_CLK_DIV) as i32; - for i in 0..128 { - sysref_slip_rtio_cycle(); - let expected_phase = (initial_phase + i + 1) % modulo; - let phase = sysref_get_tsc_phase()?; - if phase != expected_phase { - error!(" ...unexpected TSC phase: got {}, expected {} ", phase, expected_phase); - return Err("HMC7043 SYSREF slip produced unexpected TSC phase"); - } - } - info!(" ...done"); - Ok(()) - } - - pub fn sysref_rtio_align() -> Result<(), &'static str> { - info!("aligning SYSREF with RTIO TSC..."); - let mut nslips = 0; - loop { - sysref_slip_rtio_cycle(); - if sysref_get_tsc_phase()? == 0 { - info!(" ...done"); - return Ok(()) - } - - nslips += 1; - if nslips > SYSREF_DIV/FPGA_CLK_DIV { - return Err("failed to find SYSREF transition aligned with RTIO TSC"); - } - } - } - - pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { - test_ddmtd_stability(true, 4)?; - test_ddmtd_stability(false, 1)?; - test_slip_ddmtd()?; - - info!("determining SYSREF S/H limits..."); - let sysref_sh_limits = measure_sysref_sh_limits()?; - let rising_average = jdac_common::average_phases(&sysref_sh_limits.rising_phases, SYSREF_SH_MOD); - let falling_average = jdac_common::average_phases(&sysref_sh_limits.falling_phases, SYSREF_SH_MOD); - let rising_max_deviation = max_phase_deviation(rising_average, &sysref_sh_limits.rising_phases); - let falling_max_deviation = max_phase_deviation(falling_average, &sysref_sh_limits.falling_phases); - - let rising_average = rising_average >> SYSREF_SH_PRECISION_SHIFT; - let falling_average = falling_average >> SYSREF_SH_PRECISION_SHIFT; - let rising_max_deviation = rising_max_deviation >> SYSREF_SH_PRECISION_SHIFT; - let falling_max_deviation = falling_max_deviation >> SYSREF_SH_PRECISION_SHIFT; - - info!(" SYSREF S/H average limits (DDMTD phases): {} {}", rising_average, falling_average); - info!(" SYSREF S/H maximum limit deviation: {} {}", rising_max_deviation, falling_max_deviation); - if rising_max_deviation > 8 || falling_max_deviation > 8 { - return Err("excessive SYSREF S/H limit deviation"); - } - info!(" ...done"); - - let entry = config::read_str("sysref_ddmtd_phase_fpga", |r| r.map(|s| s.parse())); - let target_phase = match entry { - Ok(Ok(phase)) => { - info!("using FPGA SYSREF DDMTD phase target from config: {}", phase); - phase - } - _ => { - let phase = calibrate_sysref_target(rising_average, falling_average)?; - if let Err(e) = config::write_int("sysref_ddmtd_phase_fpga", phase as u32) { - error!("failed to update FPGA SYSREF DDMTD phase target in config: {}", e); - } - phase - } - }; - - info!("aligning SYSREF with RTIO clock..."); - let delta = reach_sysref_ddmtd_target(target_phase, 3)?; - if sysref_sh_error() { - return Err("SYSREF does not meet S/H timing at DDMTD phase target"); - } - info!(" ...done, delta={}", delta); - - test_sysref_frequency()?; - test_slip_tsc()?; - sysref_rtio_align()?; - - Ok(()) - } - - fn sysref_cal_dac(dacno: u8) -> Result { - info!("calibrating SYSREF delay at DAC-{}...", dacno); - - // Allocate for more than expected as jitter may create spurious entries. - let mut limits_buf = [0; 8]; - let mut n_limits = 0; - - limits_buf[n_limits] = -1; - n_limits += 1; - - // avoid spurious rotation at delay=0 - hmc7043_sysref_delay_dac(dacno, 0); - ad9154_sync(dacno)?; - - for scan_delay in 0..HMC7043_ANALOG_DELAY_RANGE { - hmc7043_sysref_delay_dac(dacno, scan_delay); - if ad9154_sync(dacno)? { - limits_buf[n_limits] = scan_delay as i16; - n_limits += 1; - if n_limits >= limits_buf.len() - 1 { - break; - } - } - } - - limits_buf[n_limits] = HMC7043_ANALOG_DELAY_RANGE as i16; - n_limits += 1; - - info!(" using limits: {:?}", &limits_buf[..n_limits]); - - let mut delay = 0; - let mut best_margin = 0; - - for i in 0..(n_limits-1) { - let margin = limits_buf[i+1] - limits_buf[i]; - if margin > best_margin { - best_margin = margin; - delay = ((limits_buf[i+1] + limits_buf[i])/2) as u8; - } - } - - info!(" ...done, delay={}", delay); - Ok(delay) - } - - fn sysref_dac_align(dacno: u8, delay: u8) -> Result<(), &'static str> { - let tolerance = 5; - - info!("verifying SYSREF margins at DAC-{}...", dacno); - - // avoid spurious rotation at delay=0 - hmc7043_sysref_delay_dac(dacno, 0); - ad9154_sync(dacno)?; - - let mut rotation_seen = false; - for scan_delay in 0..HMC7043_ANALOG_DELAY_RANGE { - hmc7043_sysref_delay_dac(dacno, scan_delay); - if ad9154_sync(dacno)? { - rotation_seen = true; - let distance = (scan_delay as i16 - delay as i16).abs(); - if distance < tolerance { - error!(" rotation at delay={} is {} delay steps from target (FAIL)", scan_delay, distance); - return Err("insufficient SYSREF margin at DAC"); - } else { - info!(" rotation at delay={} is {} delay steps from target (PASS)", scan_delay, distance); - } - } - } - - if !rotation_seen { - return Err("no rotation seen when scanning DAC SYSREF delay"); - } - - info!(" ...done"); - - // We tested that the value is correct - now use it - info!("synchronizing DAC-{}", dacno); - hmc7043_sysref_delay_dac(dacno, delay); - ad9154_sync(dacno)?; - - Ok(()) - } - - pub fn sysref_auto_dac_align() -> Result<(), &'static str> { - // We assume that DAC SYSREF traces are length-matched so only one delay - // value is needed, and we use DAC-0 as calibration reference. - - let entry = config::read_str("sysref_7043_delay_dac", |r| r.map(|s| s.parse())); - let delay = match entry { - Ok(Ok(delay)) => { - info!("using DAC SYSREF delay from config: {}", delay); - delay - }, - _ => { - let delay = sysref_cal_dac(0)?; - if let Err(e) = config::write_int("sysref_7043_delay_dac", delay as u32) { - error!("failed to update DAC SYSREF delay in config: {}", e); - } - delay - } - }; - - for dacno in 0..csr::JDCG.len() { - sysref_dac_align(dacno as u8, delay)?; - } - Ok(()) - } - - pub fn sysref_auto_align() { - if let Err(e) = sysref_auto_rtio_align() { - error!("failed to align SYSREF at FPGA: {}", e); - } - if let Err(e) = sysref_auto_dac_align() { - error!("failed to align SYSREF at DAC: {}", e); - } - } - - pub fn resync_dacs() -> Result<(), &'static str> { - for dacno in 0..csr::JDCG.len() { - info!("resynchronizing DAC-{}", dacno); - ad9154_sync(dacno as u8)?; - } - Ok(()) - } -} diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 366aa1d5b..7d69f7d0d 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -16,15 +16,9 @@ use board_artiq::si5324; use board_artiq::wrpll; use board_artiq::{spi, drtioaux}; use board_artiq::drtio_routing; -#[cfg(has_hmc830_7043)] -use board_artiq::hmc830_7043; use riscv::register::{mcause, mepc, mtval}; mod repeater; -#[cfg(has_jdcg)] -mod jdcg; -#[cfg(any(has_ad9154, has_jdcg))] -pub mod jdac_common; fn drtiosat_reset(reset: bool) { unsafe { @@ -303,43 +297,6 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], } } - drtioaux::Packet::JdacBasicRequest { destination: _destination, dacno: _dacno, - reqno: _reqno, param: _param } => { - forward!(_routing_table, _destination, *_rank, _repeaters, &packet); - #[cfg(has_ad9154)] - let (succeeded, retval) = { - #[cfg(rtio_frequency = "125.0")] - const LINERATE: u64 = 5_000_000_000; - #[cfg(rtio_frequency = "150.0")] - const LINERATE: u64 = 6_000_000_000; - match _reqno { - jdac_common::INIT => (board_artiq::ad9154::setup(_dacno, LINERATE).is_ok(), 0), - jdac_common::PRINT_STATUS => { board_artiq::ad9154::status(_dacno); (true, 0) }, - jdac_common::PRBS => (board_artiq::ad9154::prbs(_dacno).is_ok(), 0), - jdac_common::STPL => (board_artiq::ad9154::stpl(_dacno, 4, 2).is_ok(), 0), - jdac_common::SYSREF_DELAY_DAC => { board_artiq::hmc830_7043::hmc7043::sysref_delay_dac(_dacno, _param); (true, 0) }, - jdac_common::SYSREF_SLIP => { board_artiq::hmc830_7043::hmc7043::sysref_slip(); (true, 0) }, - jdac_common::SYNC => { - match board_artiq::ad9154::sync(_dacno) { - Ok(false) => (true, 0), - Ok(true) => (true, 1), - Err(e) => { - error!("DAC sync failed: {}", e); - (false, 0) - } - } - }, - jdac_common::DDMTD_SYSREF_RAW => (true, jdac_common::measure_ddmdt_phase_raw() as u8), - jdac_common::DDMTD_SYSREF => (true, jdac_common::measure_ddmdt_phase() as u8), - _ => (false, 0) - } - }; - #[cfg(not(has_ad9154))] - let (succeeded, retval) = (false, 0); - drtioaux::send(0, - &drtioaux::Packet::JdacBasicReply { succeeded: succeeded, retval: retval }) - } - _ => { warn!("received unexpected aux packet"); Ok(()) @@ -530,7 +487,6 @@ pub extern fn main() -> i32 { sysclk_setup(); - #[cfg(not(has_jdcg))] unsafe { csr::drtio_transceiver::txenable_write(0xffffffffu32 as _); } @@ -539,17 +495,6 @@ pub extern fn main() -> i32 { init_rtio_crg(); - #[cfg(has_hmc830_7043)] - /* must be the first SPI init because of HMC830 SPI mode selection */ - hmc830_7043::init().expect("cannot initialize HMC830/7043"); - #[cfg(has_ad9154)] - { - jdac_common::init_ddmtd().expect("failed to initialize SYSREF DDMTD core"); - for dacno in 0..csr::CONFIG_AD9154_COUNT { - board_artiq::ad9154::reset_and_detect(dacno as u8).expect("AD9154 DAC not detected"); - } - } - #[cfg(has_drtio_routing)] let mut repeaters = [repeater::Repeater::default(); csr::DRTIOREP.len()]; #[cfg(not(has_drtio_routing))] @@ -563,11 +508,6 @@ pub extern fn main() -> i32 { let mut hardware_tick_ts = 0; loop { - #[cfg(has_jdcg)] - unsafe { - // Hide from uplink until RTM is ready - csr::drtio_transceiver::txenable_write(0xfffffffeu32 as _); - } while !drtiosat_link_rx_up() { drtiosat_process_errors(); for rep in repeaters.iter_mut() { @@ -594,8 +534,6 @@ pub extern fn main() -> i32 { drtiosat_reset(false); drtiosat_reset_phy(false); - #[cfg(has_jdcg)] - let mut was_up = false; while drtiosat_link_rx_up() { drtiosat_process_errors(); process_aux_packets(&mut repeaters, &mut routing_table, &mut rank); @@ -610,18 +548,6 @@ pub extern fn main() -> i32 { hardware_tick(&mut hardware_tick_ts); if drtiosat_tsc_loaded() { info!("TSC loaded from uplink"); - #[cfg(has_jdcg)] - { - // We assume that the RTM on repeater0 is up. - // Uplink should not send a TSC load command unless the link is - // up, and we are hiding when the RTM is down. - if let Err(e) = jdcg::jesd204sync::sysref_rtio_align() { - error!("failed to align SYSREF with TSC ({})", e); - } - if let Err(e) = jdcg::jesd204sync::resync_dacs() { - error!("DAC resync failed after SYSREF/TSC realignment ({})", e); - } - } for rep in repeaters.iter() { if let Err(e) = rep.sync_tsc() { error!("failed to sync TSC ({})", e); @@ -631,38 +557,8 @@ pub extern fn main() -> i32 { error!("aux packet error: {}", e); } } - #[cfg(has_jdcg)] - { - let is_up = repeaters[0].is_up(); - if is_up && !was_up { - /* - * One side of the JESD204 elastic buffer is clocked by the jitter filter - * (Si5324 or WRPLL), the other by the RTM. - * The elastic buffer can operate only when those two clocks are derived from - * the same oscillator. - * This is the case when either of those conditions is true: - * (1) The DRTIO master and the RTM are clocked directly from a common external - * source, *and* the jitter filter has locked to the recovered clock. - * This clocking scheme may provide less noise and phase drift at the DACs. - * (2) The RTM clock is connected to the jitter filter output. - * To handle those cases, we simply keep the JESD204 core in reset unless the - * jitter filter is locked to the recovered clock. - */ - jdcg::jesd::reset(false); - let _ = jdcg::jdac::init(); - jdcg::jesd204sync::sysref_auto_align(); - jdcg::jdac::stpl(); - unsafe { - csr::drtio_transceiver::txenable_write(0xffffffffu32 as _); // unhide - } - } - was_up = is_up; - } } - #[cfg(has_jdcg)] - jdcg::jesd::reset(true); - drtiosat_reset_phy(true); drtiosat_reset(true); drtiosat_tsc_loaded(); diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 1462ec83e..96203fa83 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -25,12 +25,10 @@ def get_argparser(): Valid actions: * gateware: write main gateware bitstream to flash - * rtm_gateware: write RTM gateware bitstream to flash * bootloader: write bootloader to flash * storage: write storage image to flash * firmware: write firmware to flash * load: load main gateware bitstream into device (volatile but fast) - * rtm_load: load RTM gateware bitstream into device * erase: erase flash memory * start: trigger the target to (re)load its gateware bitstream from flash @@ -61,7 +59,7 @@ Prerequisites: help="SSH host to jump through") parser.add_argument("-t", "--target", default="kasli", help="target board, default: %(default)s, one of: " - "kasli sayma metlino kc705") + "kasli kc705") parser.add_argument("-I", "--preinit-command", default=[], action="append", help="add a pre-initialization OpenOCD command. " "Useful for selecting a board when several are connected.") @@ -69,8 +67,6 @@ Prerequisites: parser.add_argument("-d", "--dir", default=None, help="look for board binaries in this directory") parser.add_argument("--srcbuild", help="board binaries directory is laid out as a source build tree", default=False, action="store_true") - parser.add_argument("--no-rtm-jtag", help="do not attempt JTAG to the RTM", - default=False, action="store_true") parser.add_argument("action", metavar="ACTION", nargs="*", default=[], help="actions to perform, default: flash everything") @@ -234,76 +230,6 @@ class ProgrammerXC7(Programmer): "xc7_program xc7.tap") -class ProgrammerAMCRTM(Programmer): - _sector_size = 0x10000 - - def __init__(self, client, preinit_script): - Programmer.__init__(self, client, preinit_script) - - add_commands(self._board_script, - "source {}".format(self._transfer_script("fpga/xilinx-xadc.cfg")), - - "interface ftdi", - "ftdi_device_desc \"Quad RS232-HS\"", - "ftdi_vid_pid 0x0403 0x6011", - "ftdi_channel 0", - # EN_USB_JTAG on ADBUS7: out, high - # nTRST on ADBUS4: out, high, but R46 is DNP - "ftdi_layout_init 0x0098 0x008b", - "reset_config none", - "adapter_khz 5000", - "transport select jtag", - # tap 0, pld 0 - "source {}".format(self._transfer_script("cpld/xilinx-xc7.cfg")), - # tap 1, pld 1 - "set CHIP XCKU040", - "source {}".format(self._transfer_script("cpld/xilinx-xcu.cfg"))) - self.add_flash_bank("spi0", "xcu", index=0) - self.add_flash_bank("spi1", "xcu", index=1) - - add_commands(self._script, "echo \"RTM FPGA XADC:\"", "xadc_report xc7.tap") - add_commands(self._script, "echo \"AMC FPGA XADC:\"", "xadc_report xcu.tap") - - def load_proxy(self): - self.load(find_proxy_bitfile("bscan_spi_xcku040.bit"), pld=1) - - def start(self): - add_commands(self._script, "xcu_program xcu.tap") - - -class ProgrammerAMC(Programmer): - _sector_size = 0x10000 - - def __init__(self, client, preinit_script): - Programmer.__init__(self, client, preinit_script) - - add_commands(self._board_script, - "source {}".format(self._transfer_script("fpga/xilinx-xadc.cfg")), - - "interface ftdi", - "ftdi_device_desc \"Quad RS232-HS\"", - "ftdi_vid_pid 0x0403 0x6011", - "ftdi_channel 0", - # EN_USB_JTAG on ADBUS7: out, high - # nTRST on ADBUS4: out, high, but R46 is DNP - "ftdi_layout_init 0x0098 0x008b", - "reset_config none", - "adapter_khz 5000", - "transport select jtag", - "set CHIP XCKU040", - "source {}".format(self._transfer_script("cpld/xilinx-xcu.cfg"))) - self.add_flash_bank("spi0", "xcu", index=0) - self.add_flash_bank("spi1", "xcu", index=1) - - add_commands(self._script, "echo \"AMC FPGA XADC:\"", "xadc_report xcu.tap") - - def load_proxy(self): - self.load(find_proxy_bitfile("bscan_spi_xcku040.bit"), pld=0) - - def start(self): - add_commands(self._script, "xcu_program xcu.tap") - - def main(): args = get_argparser().parse_args() common_args.init_logger_from_args(args) @@ -316,21 +242,6 @@ def main(): "storage": ("spi0", 0x440000), "firmware": ("spi0", 0x450000), }, - "sayma": { - "programmer": ProgrammerAMCRTM, - "gateware": ("spi0", 0x000000), - "bootloader": ("spi1", 0x000000), - "storage": ("spi1", 0x040000), - "firmware": ("spi1", 0x050000), - "rtm_gateware": ("spi1", 0x200000), - }, - "metlino": { - "programmer": ProgrammerAMC, - "gateware": ("spi0", 0x000000), - "bootloader": ("spi1", 0x000000), - "storage": ("spi1", 0x040000), - "firmware": ("spi1", 0x050000), - }, "kc705": { "programmer": partial(ProgrammerXC7, board="kc705", proxy="bscan_spi_xc7k325t.bit"), "gateware": ("spi0", 0x000000), @@ -341,32 +252,21 @@ def main(): }[args.target] if not args.action: - if args.target == "sayma": - args.action = "gateware rtm_gateware bootloader firmware start".split() - else: - args.action = "gateware bootloader firmware start".split() + args.action = "gateware bootloader firmware start".split() needs_artifacts = any( action in args.action - for action in ["gateware", "rtm_gateware", "bootloader", "firmware", "load", "rtm_load"]) + for action in ["gateware", "bootloader", "firmware", "load"]) if needs_artifacts and args.dir is None: raise ValueError("the directory containing the binaries need to be specified using -d.") binary_dir = args.dir - if binary_dir is not None: - rtm_binary_dir = os.path.join(binary_dir, "rtm") - else: - rtm_binary_dir = None if args.host is None: client = LocalClient() else: client = SSHClient(args.host, args.jump) - if args.target == "sayma" and args.no_rtm_jtag: - programmer_cls = ProgrammerAMC - else: - programmer_cls = config["programmer"] - programmer = programmer_cls(client, preinit_script=args.preinit_command) + programmer = config["programmer"](client, preinit_script=args.preinit_command) def artifact_path(this_binary_dir, *path_filename): if args.srcbuild: @@ -377,7 +277,7 @@ def main(): *_, filename = path_filename return os.path.join(this_binary_dir, filename) - def convert_gateware(bit_filename, header=False): + def convert_gateware(bit_filename): bin_handle, bin_filename = tempfile.mkstemp( prefix="artiq_", suffix="_" + os.path.basename(bit_filename)) with open(bit_filename, "rb") as bit_file, \ @@ -385,12 +285,6 @@ def main(): if header: bin_file.write(b"\x00"*8) bit2bin(bit_file, bin_file) - if header: - magic = 0x5352544d # "SRTM", see sayma_rtm target - length = bin_file.tell() - 8 - bin_file.seek(0) - bin_file.write(magic.to_bytes(4, byteorder="little")) - bin_file.write(length.to_bytes(4, byteorder="little")) atexit.register(lambda: os.unlink(bin_filename)) return bin_filename @@ -399,11 +293,6 @@ def main(): gateware_bin = convert_gateware( artifact_path(binary_dir, "gateware", "top.bit")) programmer.write_binary(*config["gateware"], gateware_bin) - elif action == "rtm_gateware": - rtm_gateware_bin = convert_gateware( - artifact_path(rtm_binary_dir, "gateware", "top.bit"), header=True) - programmer.write_binary(*config["rtm_gateware"], - rtm_gateware_bin) elif action == "bootloader": bootloader_bin = artifact_path(binary_dir, "software", "bootloader", "bootloader.bin") programmer.write_binary(*config["bootloader"], bootloader_bin) @@ -423,23 +312,12 @@ def main(): "Found firmware files: {}".format(" ".join(firmware_fbis))) programmer.write_binary(*config["firmware"], firmware_fbis[0]) elif action == "load": - if args.target == "sayma": - gateware_bit = artifact_path(binary_dir, "gateware", "top.bit") - programmer.load(gateware_bit, 1) - else: - gateware_bit = artifact_path(binary_dir, "gateware", "top.bit") - programmer.load(gateware_bit, 0) - elif action == "rtm_load": - rtm_gateware_bit = artifact_path(rtm_binary_dir, "gateware", "top.bit") - programmer.load(rtm_gateware_bit, 0) + gateware_bit = artifact_path(binary_dir, "gateware", "top.bit") + programmer.load(gateware_bit, 0) elif action == "start": programmer.start() elif action == "erase": - if args.target == "sayma" or args.target == "metlino": - programmer.erase_flash("spi0") - programmer.erase_flash("spi1") - else: - programmer.erase_flash("spi0") + programmer.erase_flash("spi0") else: raise ValueError("invalid action", action) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py deleted file mode 100644 index ddc88037a..000000000 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale.py +++ /dev/null @@ -1,704 +0,0 @@ -from functools import reduce -from operator import or_, and_ - -from migen import * -from migen.genlib.resetsync import AsyncResetSynchronizer - -from misoc.cores.code_8b10b import Encoder, Decoder - -from microscope import * - -from artiq.gateware.drtio.core import TransceiverInterface, ChannelInterface -from artiq.gateware.drtio.transceiver.clock_aligner import BruteforceClockAligner -from artiq.gateware.drtio.transceiver.gth_ultrascale_init import * - - -class GTHSingle(Module): - def __init__(self, refclk, pads, sys_clk_freq, rtio_clk_freq, rtiox_mul, dw, mode): - assert (dw == 20) or (dw == 40) - assert mode in ["single", "master", "slave"] - self.mode = mode - - # phase alignment - self.txsyncallin = Signal() - self.txphaligndone = Signal() - self.txsyncallin = Signal() - self.txsyncin = Signal() - self.txsyncout = Signal() - self.txdlysreset = Signal() - - # # # - - self.txenable = Signal() - nwords = dw//10 - self.submodules.encoder = encoder = ClockDomainsRenamer("rtio_tx")( - Encoder(nwords, True)) - self.submodules.decoders = decoders = [ClockDomainsRenamer("rtio_rx")( - (Decoder(True))) for _ in range(nwords)] - self.rx_ready = Signal() - - # transceiver direct clock outputs - # for OBUFDS_GTE3 - self.rxrecclkout = Signal() - # useful to specify clock constraints in a way palatable to Vivado - self.txoutclk = Signal() - self.rxoutclk = Signal() - - # # # - - # TX generates RTIO clock, init must be in system domain - self.submodules.tx_init = tx_init = GTHInit(sys_clk_freq, False, mode) - # RX receives restart commands from RTIO domain - rx_init = ClockDomainsRenamer("rtio_tx")(GTHInit(rtio_clk_freq, True)) - self.submodules += rx_init - - cpll_reset = Signal() - cpll_lock = Signal() - self.comb += [ - cpll_reset.eq(tx_init.pllreset), - tx_init.plllock.eq(cpll_lock), - rx_init.plllock.eq(cpll_lock) - ] - - txdata = Signal(dw) - rxdata = Signal(dw) - rxphaligndone = Signal() - gth_params = dict( - p_ACJTAG_DEBUG_MODE =0b0, - p_ACJTAG_MODE =0b0, - p_ACJTAG_RESET =0b0, - p_ADAPT_CFG0 =0b1111100000000000, - p_ADAPT_CFG1 =0b0000000000000000, - p_ALIGN_COMMA_DOUBLE ="FALSE", - p_ALIGN_COMMA_ENABLE =0b0000000000, - p_ALIGN_COMMA_WORD =1, - p_ALIGN_MCOMMA_DET ="FALSE", - p_ALIGN_MCOMMA_VALUE =0b1010000011, - p_ALIGN_PCOMMA_DET ="FALSE", - p_ALIGN_PCOMMA_VALUE =0b0101111100, - p_A_RXOSCALRESET =0b0, - p_A_RXPROGDIVRESET =0b0, - p_A_TXPROGDIVRESET =0b0, - p_CBCC_DATA_SOURCE_SEL ="ENCODED", - p_CDR_SWAP_MODE_EN =0b0, - p_CHAN_BOND_KEEP_ALIGN ="FALSE", - p_CHAN_BOND_MAX_SKEW =1, - p_CHAN_BOND_SEQ_1_1 =0b0000000000, - p_CHAN_BOND_SEQ_1_2 =0b0000000000, - p_CHAN_BOND_SEQ_1_3 =0b0000000000, - p_CHAN_BOND_SEQ_1_4 =0b0000000000, - p_CHAN_BOND_SEQ_1_ENABLE =0b1111, - p_CHAN_BOND_SEQ_2_1 =0b0000000000, - p_CHAN_BOND_SEQ_2_2 =0b0000000000, - p_CHAN_BOND_SEQ_2_3 =0b0000000000, - p_CHAN_BOND_SEQ_2_4 =0b0000000000, - p_CHAN_BOND_SEQ_2_ENABLE =0b1111, - p_CHAN_BOND_SEQ_2_USE ="FALSE", - p_CHAN_BOND_SEQ_LEN =1, - p_CLK_CORRECT_USE ="FALSE", - p_CLK_COR_KEEP_IDLE ="FALSE", - p_CLK_COR_MAX_LAT =20, - p_CLK_COR_MIN_LAT =18, - p_CLK_COR_PRECEDENCE ="TRUE", - p_CLK_COR_REPEAT_WAIT =0, - p_CLK_COR_SEQ_1_1 =0b0000000000, - p_CLK_COR_SEQ_1_2 =0b0000000000, - p_CLK_COR_SEQ_1_3 =0b0000000000, - p_CLK_COR_SEQ_1_4 =0b0000000000, - p_CLK_COR_SEQ_1_ENABLE =0b1111, - p_CLK_COR_SEQ_2_1 =0b0000000000, - p_CLK_COR_SEQ_2_2 =0b0000000000, - p_CLK_COR_SEQ_2_3 =0b0000000000, - p_CLK_COR_SEQ_2_4 =0b0000000000, - p_CLK_COR_SEQ_2_ENABLE =0b1111, - p_CLK_COR_SEQ_2_USE ="FALSE", - p_CLK_COR_SEQ_LEN =1, - p_CPLL_CFG0 =0b0110011111111000, - p_CPLL_CFG1 =0b1010010010101100, - p_CPLL_CFG2 =0b0000000000000111, - p_CPLL_CFG3 =0b000000, - p_CPLL_FBDIV =5, - p_CPLL_FBDIV_45 =4, - p_CPLL_INIT_CFG0 =0b0000001010110010, - p_CPLL_INIT_CFG1 =0b00000000, - p_CPLL_LOCK_CFG =0b0000000111101000, - p_CPLL_REFCLK_DIV =1, - p_DDI_CTRL =0b00, - p_DDI_REALIGN_WAIT =15, - p_DEC_MCOMMA_DETECT ="FALSE", - p_DEC_PCOMMA_DETECT ="FALSE", - p_DEC_VALID_COMMA_ONLY ="FALSE", - p_DFE_D_X_REL_POS =0b0, - p_DFE_VCM_COMP_EN =0b0, - p_DMONITOR_CFG0 =0b0000000000, - p_DMONITOR_CFG1 =0b00000000, - p_ES_CLK_PHASE_SEL =0b0, - p_ES_CONTROL =0b000000, - p_ES_ERRDET_EN ="FALSE", - p_ES_EYE_SCAN_EN ="FALSE", - p_ES_HORZ_OFFSET =0b000000000000, - p_ES_PMA_CFG =0b0000000000, - p_ES_PRESCALE =0b00000, - p_ES_QUALIFIER0 =0b0000000000000000, - p_ES_QUALIFIER1 =0b0000000000000000, - p_ES_QUALIFIER2 =0b0000000000000000, - p_ES_QUALIFIER3 =0b0000000000000000, - p_ES_QUALIFIER4 =0b0000000000000000, - p_ES_QUAL_MASK0 =0b0000000000000000, - p_ES_QUAL_MASK1 =0b0000000000000000, - p_ES_QUAL_MASK2 =0b0000000000000000, - p_ES_QUAL_MASK3 =0b0000000000000000, - p_ES_QUAL_MASK4 =0b0000000000000000, - p_ES_SDATA_MASK0 =0b0000000000000000, - p_ES_SDATA_MASK1 =0b0000000000000000, - p_ES_SDATA_MASK2 =0b0000000000000000, - p_ES_SDATA_MASK3 =0b0000000000000000, - p_ES_SDATA_MASK4 =0b0000000000000000, - p_EVODD_PHI_CFG =0b00000000000, - p_EYE_SCAN_SWAP_EN =0b0, - p_FTS_DESKEW_SEQ_ENABLE =0b1111, - p_FTS_LANE_DESKEW_CFG =0b1111, - p_FTS_LANE_DESKEW_EN ="FALSE", - p_GEARBOX_MODE =0b00000, - p_GM_BIAS_SELECT =0b0, - p_LOCAL_MASTER =0b1, - p_OOBDIVCTL =0b00, - p_OOB_PWRUP =0b0, - p_PCI3_AUTO_REALIGN ="OVR_1K_BLK", - p_PCI3_PIPE_RX_ELECIDLE =0b0, - p_PCI3_RX_ASYNC_EBUF_BYPASS =0b00, - p_PCI3_RX_ELECIDLE_EI2_ENABLE =0b0, - p_PCI3_RX_ELECIDLE_H2L_COUNT =0b000000, - p_PCI3_RX_ELECIDLE_H2L_DISABLE =0b000, - p_PCI3_RX_ELECIDLE_HI_COUNT =0b000000, - p_PCI3_RX_ELECIDLE_LP4_DISABLE =0b0, - p_PCI3_RX_FIFO_DISABLE =0b0, - p_PCIE_BUFG_DIV_CTRL =0b0001000000000000, - p_PCIE_RXPCS_CFG_GEN3 =0b0000001010100100, - p_PCIE_RXPMA_CFG =0b0000000000001010, - p_PCIE_TXPCS_CFG_GEN3 =0b0010010010100100, - p_PCIE_TXPMA_CFG =0b0000000000001010, - p_PCS_PCIE_EN ="FALSE", - p_PCS_RSVD0 =0b0000000000000000, - p_PCS_RSVD1 =0b000, - p_PD_TRANS_TIME_FROM_P2 =0b000000111100, - p_PD_TRANS_TIME_NONE_P2 =0b00011001, - p_PD_TRANS_TIME_TO_P2 =0b01100100, - p_PLL_SEL_MODE_GEN12 =0b00, - p_PLL_SEL_MODE_GEN3 =0b11, - p_PMA_RSV1 =0b1111000000000000, - p_PROCESS_PAR =0b010, - p_RATE_SW_USE_DRP =0b1, - p_RESET_POWERSAVE_DISABLE =0b0, - ) - gth_params.update( - p_RXBUFRESET_TIME =0b00011, - p_RXBUF_ADDR_MODE ="FAST", - p_RXBUF_EIDLE_HI_CNT =0b1000, - p_RXBUF_EIDLE_LO_CNT =0b0000, - p_RXBUF_EN ="FALSE", - p_RXBUF_RESET_ON_CB_CHANGE ="TRUE", - p_RXBUF_RESET_ON_COMMAALIGN ="FALSE", - p_RXBUF_RESET_ON_EIDLE ="FALSE", - p_RXBUF_RESET_ON_RATE_CHANGE ="TRUE", - p_RXBUF_THRESH_OVFLW =0, - p_RXBUF_THRESH_OVRD ="FALSE", - p_RXBUF_THRESH_UNDFLW =0, - p_RXCDRFREQRESET_TIME =0b00001, - p_RXCDRPHRESET_TIME =0b00001, - p_RXCDR_CFG0 =0b0000000000000000, - p_RXCDR_CFG0_GEN3 =0b0000000000000000, - p_RXCDR_CFG1 =0b0000000000000000, - p_RXCDR_CFG1_GEN3 =0b0000000000000000, - p_RXCDR_CFG2 =0b0000011111010110, - p_RXCDR_CFG2_GEN3 =0b0000011111100110, - p_RXCDR_CFG3 =0b0000000000000000, - p_RXCDR_CFG3_GEN3 =0b0000000000000000, - p_RXCDR_CFG4 =0b0000000000000000, - p_RXCDR_CFG4_GEN3 =0b0000000000000000, - p_RXCDR_CFG5 =0b0000000000000000, - p_RXCDR_CFG5_GEN3 =0b0000000000000000, - p_RXCDR_FR_RESET_ON_EIDLE =0b0, - p_RXCDR_HOLD_DURING_EIDLE =0b0, - p_RXCDR_LOCK_CFG0 =0b0100010010000000, - p_RXCDR_LOCK_CFG1 =0b0101111111111111, - p_RXCDR_LOCK_CFG2 =0b0111011111000011, - p_RXCDR_PH_RESET_ON_EIDLE =0b0, - p_RXCFOK_CFG0 =0b0100000000000000, - p_RXCFOK_CFG1 =0b0000000001100101, - p_RXCFOK_CFG2 =0b0000000000101110, - p_RXDFELPMRESET_TIME =0b0001111, - p_RXDFELPM_KL_CFG0 =0b0000000000000000, - p_RXDFELPM_KL_CFG1 =0b0000000000000010, - p_RXDFELPM_KL_CFG2 =0b0000000000000000, - p_RXDFE_CFG0 =0b0000101000000000, - p_RXDFE_CFG1 =0b0000000000000000, - p_RXDFE_GC_CFG0 =0b0000000000000000, - p_RXDFE_GC_CFG1 =0b0111100001110000, - p_RXDFE_GC_CFG2 =0b0000000000000000, - p_RXDFE_H2_CFG0 =0b0000000000000000, - p_RXDFE_H2_CFG1 =0b0000000000000000, - p_RXDFE_H3_CFG0 =0b0100000000000000, - p_RXDFE_H3_CFG1 =0b0000000000000000, - p_RXDFE_H4_CFG0 =0b0010000000000000, - p_RXDFE_H4_CFG1 =0b0000000000000011, - p_RXDFE_H5_CFG0 =0b0010000000000000, - p_RXDFE_H5_CFG1 =0b0000000000000011, - p_RXDFE_H6_CFG0 =0b0010000000000000, - p_RXDFE_H6_CFG1 =0b0000000000000000, - p_RXDFE_H7_CFG0 =0b0010000000000000, - p_RXDFE_H7_CFG1 =0b0000000000000000, - p_RXDFE_H8_CFG0 =0b0010000000000000, - p_RXDFE_H8_CFG1 =0b0000000000000000, - p_RXDFE_H9_CFG0 =0b0010000000000000, - p_RXDFE_H9_CFG1 =0b0000000000000000, - p_RXDFE_HA_CFG0 =0b0010000000000000, - p_RXDFE_HA_CFG1 =0b0000000000000000, - p_RXDFE_HB_CFG0 =0b0010000000000000, - p_RXDFE_HB_CFG1 =0b0000000000000000, - p_RXDFE_HC_CFG0 =0b0000000000000000, - p_RXDFE_HC_CFG1 =0b0000000000000000, - p_RXDFE_HD_CFG0 =0b0000000000000000, - p_RXDFE_HD_CFG1 =0b0000000000000000, - p_RXDFE_HE_CFG0 =0b0000000000000000, - p_RXDFE_HE_CFG1 =0b0000000000000000, - p_RXDFE_HF_CFG0 =0b0000000000000000, - p_RXDFE_HF_CFG1 =0b0000000000000000, - p_RXDFE_OS_CFG0 =0b1000000000000000, - p_RXDFE_OS_CFG1 =0b0000000000000000, - p_RXDFE_UT_CFG0 =0b1000000000000000, - p_RXDFE_UT_CFG1 =0b0000000000000011, - p_RXDFE_VP_CFG0 =0b1010101000000000, - p_RXDFE_VP_CFG1 =0b0000000000110011, - p_RXDLY_CFG =0b0000000000011111, - p_RXDLY_LCFG =0b0000000000110000, - p_RXELECIDLE_CFG ="SIGCFG_4", - p_RXGBOX_FIFO_INIT_RD_ADDR =4, - p_RXGEARBOX_EN ="FALSE", - p_RXISCANRESET_TIME =0b00001, - p_RXLPM_CFG =0b0000000000000000, - p_RXLPM_GC_CFG =0b0001000000000000, - p_RXLPM_KH_CFG0 =0b0000000000000000, - p_RXLPM_KH_CFG1 =0b0000000000000010, - p_RXLPM_OS_CFG0 =0b1000000000000000, - p_RXLPM_OS_CFG1 =0b0000000000000010, - p_RXOOB_CFG =0b000000110, - p_RXOOB_CLK_CFG ="PMA", - p_RXOSCALRESET_TIME =0b00011, - p_RXOUT_DIV =2, - p_RXPCSRESET_TIME =0b00011, - p_RXPHBEACON_CFG =0b0000000000000000, - p_RXPHDLY_CFG =0b0010000000100000, - p_RXPHSAMP_CFG =0b0010000100000000, - p_RXPHSLIP_CFG =0b0110011000100010, - p_RXPH_MONITOR_SEL =0b00000, - p_RXPI_CFG0 =0b00, - p_RXPI_CFG1 =0b00, - p_RXPI_CFG2 =0b00, - p_RXPI_CFG3 =0b00, - p_RXPI_CFG4 =0b1, - p_RXPI_CFG5 =0b1, - p_RXPI_CFG6 =0b000, - p_RXPI_LPM =0b0, - p_RXPI_VREFSEL =0b0, - p_RXPMACLK_SEL ="DATA", - p_RXPMARESET_TIME =0b00011, - p_RXPRBS_ERR_LOOPBACK =0b0, - p_RXPRBS_LINKACQ_CNT =15, - p_RXSLIDE_AUTO_WAIT =7, - p_RXSLIDE_MODE ="OFF", - p_RXSYNC_MULTILANE =0b0, - p_RXSYNC_OVRD =0b0, - p_RXSYNC_SKIP_DA =0b0, - p_RX_AFE_CM_EN =0b0, - p_RX_BIAS_CFG0 =0b0000101010110100, - p_RX_BUFFER_CFG =0b000000, - p_RX_CAPFF_SARC_ENB =0b0, - p_RX_CLK25_DIV =6, - p_RX_CLKMUX_EN =0b1, - p_RX_CLK_SLIP_OVRD =0b00000, - p_RX_CM_BUF_CFG =0b1010, - p_RX_CM_BUF_PD =0b0, - p_RX_CM_SEL =0b11, - p_RX_CM_TRIM =0b1010, - p_RX_CTLE3_LPF =0b00000001, - p_RX_DATA_WIDTH =dw, - p_RX_DDI_SEL =0b000000, - p_RX_DEFER_RESET_BUF_EN ="TRUE", - p_RX_DFELPM_CFG0 =0b0110, - p_RX_DFELPM_CFG1 =0b1, - p_RX_DFELPM_KLKH_AGC_STUP_EN =0b1, - p_RX_DFE_AGC_CFG0 =0b10, - p_RX_DFE_AGC_CFG1 =0b100, - p_RX_DFE_KL_LPM_KH_CFG0 =0b01, - p_RX_DFE_KL_LPM_KH_CFG1 =0b100, - p_RX_DFE_KL_LPM_KL_CFG0 =0b01, - p_RX_DFE_KL_LPM_KL_CFG1 =0b100, - p_RX_DFE_LPM_HOLD_DURING_EIDLE =0b0, - p_RX_DISPERR_SEQ_MATCH ="TRUE", - p_RX_DIVRESET_TIME =0b00001, - p_RX_EN_HI_LR =0b0, - p_RX_EYESCAN_VS_CODE =0b0000000, - p_RX_EYESCAN_VS_NEG_DIR =0b0, - p_RX_EYESCAN_VS_RANGE =0b00, - p_RX_EYESCAN_VS_UT_SIGN =0b0, - p_RX_FABINT_USRCLK_FLOP =0b0, - p_RX_INT_DATAWIDTH =dw==40, - p_RX_PMA_POWER_SAVE =0b0, - p_RX_PROGDIV_CFG =0.0, - p_RX_SAMPLE_PERIOD =0b111, - p_RX_SIG_VALID_DLY =11, - p_RX_SUM_DFETAPREP_EN =0b0, - p_RX_SUM_IREF_TUNE =0b0000, - p_RX_SUM_RES_CTRL =0b00, - p_RX_SUM_VCMTUNE =0b0000, - p_RX_SUM_VCM_OVWR =0b0, - p_RX_SUM_VREF_TUNE =0b000, - p_RX_TUNE_AFE_OS =0b10, - p_RX_WIDEMODE_CDR =0b0, - p_RX_XCLK_SEL ="RXUSR", - p_SAS_MAX_COM =64, - p_SAS_MIN_COM =36, - p_SATA_BURST_SEQ_LEN =0b1110, - p_SATA_CPLL_CFG ="VCO_3000MHZ", - p_SATA_MAX_BURST =8, - p_SATA_MAX_INIT =21, - p_SATA_MAX_WAKE =7, - p_SATA_MIN_BURST =4, - p_SATA_MIN_INIT =12, - p_SATA_MIN_WAKE =4, - p_SHOW_REALIGN_COMMA ="TRUE", - p_SIM_RECEIVER_DETECT_PASS ="TRUE", - p_SIM_RESET_SPEEDUP ="TRUE", - p_SIM_TX_EIDLE_DRIVE_LEVEL =0b0, - p_SIM_VERSION =2, - p_TAPDLY_SET_TX =0b00, - p_TEMPERATUR_PAR =0b0010, - p_TERM_RCAL_CFG =0b100001000010000, - p_TERM_RCAL_OVRD =0b000, - p_TRANS_TIME_RATE =0b00001110, - p_TST_RSV0 =0b00000000, - p_TST_RSV1 =0b00000000, - ) - gth_params.update( - p_TXBUF_EN ="FALSE", - p_TXBUF_RESET_ON_RATE_CHANGE ="TRUE", - p_TXDLY_CFG =0b0000000000001001, - p_TXDLY_LCFG =0b0000000001010000, - p_TXDRVBIAS_N =0b1010, - p_TXDRVBIAS_P =0b1010, - p_TXFIFO_ADDR_CFG ="LOW", - p_TXGBOX_FIFO_INIT_RD_ADDR =4, - p_TXGEARBOX_EN ="FALSE", - p_TXOUT_DIV =2, - p_TXPCSRESET_TIME =0b00011, - p_TXPHDLY_CFG0 =0b0010000000100000, - p_TXPHDLY_CFG1 =0b0000000001110101, - p_TXPH_CFG =0b0000100110000000, - p_TXPH_MONITOR_SEL =0b00000, - p_TXPI_CFG0 =0b00, - p_TXPI_CFG1 =0b00, - p_TXPI_CFG2 =0b00, - p_TXPI_CFG3 =0b1, - p_TXPI_CFG4 =0b1, - p_TXPI_CFG5 =0b000, - p_TXPI_GRAY_SEL =0b0, - p_TXPI_INVSTROBE_SEL =0b0, - p_TXPI_LPM =0b0, - p_TXPI_PPMCLK_SEL ="TXUSRCLK2", - p_TXPI_PPM_CFG =0b00000000, - p_TXPI_SYNFREQ_PPM =0b001, - p_TXPI_VREFSEL =0b0, - p_TXPMARESET_TIME =0b00011, - p_TXSYNC_MULTILANE =0 if mode == "single" else 1, - p_TXSYNC_OVRD =0b0, - p_TXSYNC_SKIP_DA =0b0, - p_TX_CLK25_DIV =6, - p_TX_CLKMUX_EN =0b1, - p_TX_DATA_WIDTH =dw, - p_TX_DCD_CFG =0b000010, - p_TX_DCD_EN =0b0, - p_TX_DEEMPH0 =0b000000, - p_TX_DEEMPH1 =0b000000, - p_TX_DIVRESET_TIME =0b00001, - p_TX_DRIVE_MODE ="DIRECT", - p_TX_EIDLE_ASSERT_DELAY =0b100, - p_TX_EIDLE_DEASSERT_DELAY =0b011, - p_TX_EML_PHI_TUNE =0b0, - p_TX_FABINT_USRCLK_FLOP =0b0, - p_TX_IDLE_DATA_ZERO =0b0, - p_TX_INT_DATAWIDTH =dw==40, - p_TX_LOOPBACK_DRIVE_HIZ ="FALSE", - p_TX_MAINCURSOR_SEL =0b0, - p_TX_MARGIN_FULL_0 =0b1001111, - p_TX_MARGIN_FULL_1 =0b1001110, - p_TX_MARGIN_FULL_2 =0b1001100, - p_TX_MARGIN_FULL_3 =0b1001010, - p_TX_MARGIN_FULL_4 =0b1001000, - p_TX_MARGIN_LOW_0 =0b1000110, - p_TX_MARGIN_LOW_1 =0b1000101, - p_TX_MARGIN_LOW_2 =0b1000011, - p_TX_MARGIN_LOW_3 =0b1000010, - p_TX_MARGIN_LOW_4 =0b1000000, - p_TX_MODE_SEL =0b000, - p_TX_PMADATA_OPT =0b0, - p_TX_PMA_POWER_SAVE =0b0, - p_TX_PROGCLK_SEL ="PREPI", - p_TX_PROGDIV_CFG =dw/rtiox_mul, - p_TX_QPI_STATUS_EN =0b0, - p_TX_RXDETECT_CFG =0b00000000110010, - p_TX_RXDETECT_REF =0b100, - p_TX_SAMPLE_PERIOD =0b111, - p_TX_SARC_LPBK_ENB =0b0, - p_TX_XCLK_SEL ="TXUSR", - p_USE_PCS_CLK_PHASE_SEL =0b0, - p_WB_MODE =0b00, - ) - gth_params.update( - # Reset modes - i_GTRESETSEL=0, - i_RESETOVRD=0, - - i_CPLLRESET=0, - i_CPLLPD=cpll_reset, - o_CPLLLOCK=cpll_lock, - i_CPLLLOCKEN=1, - i_CPLLREFCLKSEL=0b001, - i_TSTIN=2**20-1, - i_GTREFCLK0=refclk, - - # TX clock - o_TXOUTCLK=self.txoutclk, - i_TXSYSCLKSEL=0b00, - i_TXPLLCLKSEL=0b00, - i_TXOUTCLKSEL=0b101, - - # TX Startup/Reset - i_GTTXRESET=tx_init.gtXxreset, - o_TXRESETDONE=tx_init.Xxresetdone, - i_TXDLYSRESET=tx_init.Xxdlysreset if mode != "slave" else self.txdlysreset, - o_TXDLYSRESETDONE=tx_init.Xxdlysresetdone, - o_TXPHALIGNDONE=tx_init.Xxphaligndone, - i_TXUSERRDY=tx_init.Xxuserrdy, - i_TXSYNCMODE=mode != "slave", - - i_TXSYNCALLIN=self.txsyncallin, - i_TXSYNCIN=self.txsyncin, - o_TXSYNCOUT=self.txsyncout, - - # TX data - i_TXINHIBIT=~self.txenable, - i_TXCTRL0=Cat(*[txdata[10*i+8] for i in range(nwords)]), - i_TXCTRL1=Cat(*[txdata[10*i+9] for i in range(nwords)]), - i_TXDATA=Cat(*[txdata[10*i:10*i+8] for i in range(nwords)]), - i_TXUSRCLK=ClockSignal("rtio_tx"), - i_TXUSRCLK2=ClockSignal("rtio_tx"), - - # TX electrical - i_TXPD=0b00, - i_TXBUFDIFFCTRL=0b000, - i_TXDIFFCTRL=0b1100, - - # RX Startup/Reset - i_GTRXRESET=rx_init.gtXxreset, - o_RXRESETDONE=rx_init.Xxresetdone, - i_RXDLYSRESET=rx_init.Xxdlysreset, - o_RXPHALIGNDONE=rxphaligndone, - i_RXSYNCALLIN=rxphaligndone, - i_RXUSERRDY=rx_init.Xxuserrdy, - i_RXSYNCIN=0, - i_RXSYNCMODE=1, - o_RXSYNCDONE=rx_init.Xxsyncdone, - - # RX AFE - i_RXDFEAGCCTRL=1, - i_RXDFEXYDEN=1, - i_RXLPMEN=1, - i_RXOSINTCFG=0xd, - i_RXOSINTEN=1, - - # RX clock - i_RXRATE=0, - i_RXDLYBYPASS=0, - i_RXSYSCLKSEL=0b00, - i_RXOUTCLKSEL=0b010, - i_RXPLLCLKSEL=0b00, - o_RXRECCLKOUT=self.rxrecclkout, - o_RXOUTCLK=self.rxoutclk, - i_RXUSRCLK=ClockSignal("rtio_rx"), - i_RXUSRCLK2=ClockSignal("rtio_rx"), - - # RX data - o_RXCTRL0=Cat(*[rxdata[10*i+8] for i in range(nwords)]), - o_RXCTRL1=Cat(*[rxdata[10*i+9] for i in range(nwords)]), - o_RXDATA=Cat(*[rxdata[10*i:10*i+8] for i in range(nwords)]), - - # RX electrical - i_RXPD=Replicate(rx_init.restart, 2), - i_RXELECIDLEMODE=0b11, - - # Pads - i_GTHRXP=pads.rxp, - i_GTHRXN=pads.rxn, - o_GTHTXP=pads.txp, - o_GTHTXN=pads.txn - ) - self.specials += Instance("GTHE3_CHANNEL", **gth_params) - self.comb += self.txphaligndone.eq(tx_init.Xxphaligndone) - - self.submodules += [ - add_probe_async("drtio_gth", "cpll_lock", cpll_lock), - add_probe_async("drtio_gth", "txuserrdy", tx_init.Xxuserrdy), - add_probe_async("drtio_gth", "tx_init_done", tx_init.done), - add_probe_async("drtio_gth", "rxuserrdy", rx_init.Xxuserrdy), - add_probe_async("drtio_gth", "rx_init_done", rx_init.done), - add_probe_buffer("drtio_gth", "txdata", txdata, clock_domain="rtio_tx"), - add_probe_buffer("drtio_gth", "rxdata", rxdata, clock_domain="rtio_rx") - ] - - # 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() - self.clock_domains.cd_rtiox_tx = ClockDomain() - if mode == "master" or mode == "single": - self.specials += [ - Instance("BUFG_GT", i_I=self.txoutclk, o_O=self.cd_rtiox_tx.clk, i_DIV=0), - Instance("BUFG_GT", i_I=self.txoutclk, o_O=self.cd_rtio_tx.clk, i_DIV=rtiox_mul-1) - ] - 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_tx += rx_reset_deglitched.eq(~rx_init.done) - self.clock_domains.cd_rtio_rx = ClockDomain() - self.specials += [ - Instance("BUFG_GT", i_I=self.rxoutclk, o_O=self.cd_rtio_rx.clk), - AsyncResetSynchronizer(self.cd_rtio_rx, rx_reset_deglitched) - ] - - # tx data - self.comb += txdata.eq(Cat(*[encoder.output[i] for i in range(nwords)])) - - # rx data - for i in range(nwords): - self.comb += decoders[i].input.eq(rxdata[10*i:10*(i+1)]) - - # clock alignment - clock_aligner = BruteforceClockAligner(0b0101111100, rtio_clk_freq) - self.submodules += clock_aligner - self.comb += [ - clock_aligner.rxdata.eq(rxdata), - rx_init.restart.eq(clock_aligner.restart), - self.rx_ready.eq(clock_aligner.ready) - ] - self.submodules += add_probe_async("drtio_gth", "clock_aligner_ready", clock_aligner.ready) - - -class GTHTXPhaseAlignement(Module): - # TX Buffer Bypass in Single-Lane/Multi-Lane Auto Mode (ug576) - def __init__(self, gths): - txsyncallin = Signal() - txsync = Signal() - txphaligndone = Signal(len(gths)) - txdlysreset = Signal() - ready_for_align = Signal(len(gths)) - all_ready_for_align = Signal() - - for i, gth in enumerate(gths): - # Common to all transceivers - self.comb += [ - ready_for_align[i].eq(1), - gth.txsyncin.eq(txsync), - gth.txsyncallin.eq(txsyncallin), - txphaligndone[i].eq(gth.txphaligndone) - ] - # Specific to Master or Single transceivers - if gth.mode == "master" or gth.mode == "single": - self.comb += [ - gth.tx_init.all_ready_for_align.eq(all_ready_for_align), - txsync.eq(gth.txsyncout), - txdlysreset.eq(gth.tx_init.Xxdlysreset) - ] - # Specific to Slave transceivers - else: - self.comb += [ - ready_for_align[i].eq(gth.tx_init.ready_for_align), - gth.txdlysreset.eq(txdlysreset), - ] - - self.comb += [ - txsyncallin.eq(reduce(and_, [txphaligndone[i] for i in range(len(gths))])), - all_ready_for_align.eq(reduce(and_, [ready_for_align[i] for i in range(len(gths))])) - ] - - -class GTH(Module, TransceiverInterface): - def __init__(self, clock_pads, data_pads, sys_clk_freq, rtio_clk_freq, rtiox_mul=2, dw=20, master=0, clock_recout_pads=None): - self.nchannels = nchannels = len(data_pads) - self.gths = [] - - # # # - - create_buf = hasattr(clock_pads, "p") - if create_buf: - refclk = Signal() - ibufds_ceb = Signal() - self.specials += Instance("IBUFDS_GTE3", - i_CEB=ibufds_ceb, - i_I=clock_pads.p, - i_IB=clock_pads.n, - o_O=refclk) - else: - refclk = clock_pads - - rtio_tx_clk = Signal() - channel_interfaces = [] - for i in range(nchannels): - if nchannels == 1: - mode = "single" - else: - mode = "master" if i == master else "slave" - gth = GTHSingle(refclk, data_pads[i], sys_clk_freq, rtio_clk_freq, rtiox_mul, dw, mode) - if mode == "master": - self.comb += rtio_tx_clk.eq(gth.cd_rtio_tx.clk) - elif mode == "slave": - self.comb += gth.cd_rtio_tx.clk.eq(rtio_tx_clk) - self.gths.append(gth) - setattr(self.submodules, "gth"+str(i), gth) - channel_interface = ChannelInterface(gth.encoder, gth.decoders) - self.comb += channel_interface.rx_ready.eq(gth.rx_ready) - channel_interfaces.append(channel_interface) - - self.submodules.tx_phase_alignment = GTHTXPhaseAlignement(self.gths) - - TransceiverInterface.__init__(self, channel_interfaces) - for n, gth in enumerate(self.gths): - self.comb += gth.txenable.eq(self.txenable.storage[n]) - self.clock_domains.cd_rtiox = ClockDomain(reset_less=True) - if create_buf: - # GTH PLLs recover on their own from an interrupted clock input, - # but be paranoid about HMC7043 noise. - self.stable_clkin.storage.attr.add("no_retiming") - self.comb += ibufds_ceb.eq(~self.stable_clkin.storage) - - self.comb += [ - self.cd_rtio.clk.eq(self.gths[master].cd_rtio_tx.clk), - self.cd_rtiox.clk.eq(self.gths[master].cd_rtiox_tx.clk), - self.cd_rtio.rst.eq(reduce(or_, [gth.cd_rtio_tx.rst for gth in self.gths])) - ] - for i in range(nchannels): - self.comb += [ - getattr(self, "cd_rtio_rx" + str(i)).clk.eq(self.gths[i].cd_rtio_rx.clk), - getattr(self, "cd_rtio_rx" + str(i)).rst.eq(self.gths[i].cd_rtio_rx.rst) - ] - - if clock_recout_pads is not None: - self.specials += Instance("OBUFDS_GTE3", - p_REFCLK_EN_TX_PATH=0b1, - p_REFCLK_ICNTL_TX=0b00111, - i_I=self.gths[0].rxrecclkout, - i_CEB=0, - o_O=clock_recout_pads.p, o_OB=clock_recout_pads.n) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py b/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py deleted file mode 100644 index 30645b876..000000000 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py +++ /dev/null @@ -1,157 +0,0 @@ -from math import ceil - -from migen import * -from migen.genlib.cdc import MultiReg -from migen.genlib.misc import WaitTimer - - -__all__ = ["GTHInit"] - - -class GTHInit(Module): - def __init__(self, sys_clk_freq, rx, mode="master"): - assert not (rx and mode != "master") - self.done = Signal() - self.restart = Signal() - - # GTH signals - self.plllock = Signal() - self.pllreset = Signal() - self.gtXxreset = Signal() - self.Xxresetdone = Signal() - self.Xxdlysreset = Signal() - self.Xxdlysresetdone = Signal() - self.Xxphaligndone = Signal() - self.Xxsyncdone = Signal() - self.Xxuserrdy = Signal() - - self.all_ready_for_align = Signal(reset=1) - self.ready_for_align = Signal() - - # # # - - # Double-latch transceiver asynch outputs - plllock = Signal() - Xxresetdone = Signal() - Xxdlysresetdone = Signal() - Xxphaligndone = Signal() - Xxsyncdone = Signal() - self.specials += [ - MultiReg(self.plllock, plllock), - MultiReg(self.Xxresetdone, Xxresetdone), - MultiReg(self.Xxdlysresetdone, Xxdlysresetdone), - MultiReg(self.Xxphaligndone, Xxphaligndone), - MultiReg(self.Xxsyncdone, Xxsyncdone) - ] - - # Deglitch FSM outputs driving transceiver asynch inputs - gtXxreset = Signal() - Xxdlysreset = Signal() - Xxuserrdy = Signal() - self.sync += [ - self.gtXxreset.eq(gtXxreset), - self.Xxdlysreset.eq(Xxdlysreset), - self.Xxuserrdy.eq(Xxuserrdy) - ] - - # PLL reset must be at least 2us - pll_reset_cycles = ceil(2000*sys_clk_freq/1000000000) - pll_reset_timer = WaitTimer(pll_reset_cycles) - self.submodules += pll_reset_timer - - startup_fsm = ResetInserter()(FSM(reset_state="RESET_ALL")) - self.submodules += startup_fsm - - ready_timer = WaitTimer(int(sys_clk_freq/1000)) - self.submodules += ready_timer - self.comb += [ - ready_timer.wait.eq(~self.done & ~startup_fsm.reset), - startup_fsm.reset.eq(self.restart | ready_timer.done) - ] - - if rx: - cdr_stable_timer = WaitTimer(1024) - self.submodules += cdr_stable_timer - - Xxphaligndone_r = Signal(reset=1) - Xxphaligndone_rising = Signal() - self.sync += Xxphaligndone_r.eq(Xxphaligndone) - self.comb += Xxphaligndone_rising.eq(Xxphaligndone & ~Xxphaligndone_r) - - startup_fsm.act("RESET_ALL", - gtXxreset.eq(1), - self.pllreset.eq(1), - pll_reset_timer.wait.eq(1), - If(pll_reset_timer.done, - NextState("RELEASE_PLL_RESET") - ) - ) - startup_fsm.act("RELEASE_PLL_RESET", - gtXxreset.eq(1), - If(plllock, NextState("RELEASE_GTH_RESET")) - ) - # Release GTH reset and wait for GTH resetdone - # (from UG476, GTH is reset on falling edge - # of gtXxreset) - if rx: - startup_fsm.act("RELEASE_GTH_RESET", - Xxuserrdy.eq(1), - cdr_stable_timer.wait.eq(1), - If(Xxresetdone & cdr_stable_timer.done, NextState("ALIGN")) - ) - else: - startup_fsm.act("RELEASE_GTH_RESET", - Xxuserrdy.eq(1), - If(Xxresetdone, - If(mode == "slave", - NextState("WAIT_ALIGN") - ).Else( - NextState("ALIGN") - ) - ) - ) - # Start delay alignment (pulse) - startup_fsm.act("ALIGN", - Xxuserrdy.eq(1), - If(self.all_ready_for_align, - Xxdlysreset.eq(1), - NextState("WAIT_ALIGN") - ) - ) - if rx: - # Wait for delay alignment - startup_fsm.act("WAIT_ALIGN", - Xxuserrdy.eq(1), - If(Xxsyncdone, - NextState("READY") - ) - ) - else: - # Wait for delay alignment - startup_fsm.act("WAIT_ALIGN", - Xxuserrdy.eq(1), - self.ready_for_align.eq(1), - If(Xxdlysresetdone, - If(mode == "slave", - NextState("WAIT_LAST_ALIGN_DONE") - ).Else( - NextState("WAIT_FIRST_ALIGN_DONE") - ) - ) - ) - - # Wait 2 rising edges of Xxphaligndone - # (from UG576 in TX Buffer Bypass in Single-Lane Auto Mode) - startup_fsm.act("WAIT_FIRST_ALIGN_DONE", - Xxuserrdy.eq(1), - If(Xxphaligndone_rising, NextState("WAIT_LAST_ALIGN_DONE")) - ) - startup_fsm.act("WAIT_LAST_ALIGN_DONE", - Xxuserrdy.eq(1), - If(Xxphaligndone_rising, NextState("READY")) - ) - startup_fsm.act("READY", - Xxuserrdy.eq(1), - self.done.eq(1), - If(self.restart, NextState("RESET_ALL")) - ) diff --git a/artiq/gateware/dsp/__init__.py b/artiq/gateware/dsp/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/artiq/gateware/dsp/accu.py b/artiq/gateware/dsp/accu.py deleted file mode 100644 index 79e297883..000000000 --- a/artiq/gateware/dsp/accu.py +++ /dev/null @@ -1,112 +0,0 @@ -from migen import * -from misoc.interconnect.stream import Endpoint - - -class Accu(Module): - def __init__(self, width, meta=[]): - self.i = Endpoint([("p", width), ("f", width), ("clr", 1)]) - self.o = Endpoint([("z", width)]) - self.latency = 1 - - ### - - f = Signal.like(self.i.f) - p = Signal.like(self.i.p) - self.comb += self.i.ack.eq(~self.o.stb | self.o.ack) - self.sync += [ - If(self.o.ack, - self.o.stb.eq(0), - ), - If(self.i.ack, - self.o.stb.eq(1), - If(self.i.stb, - self.o.z.eq(self.i.p + Mux(self.i.clr, 0, self.o.z + p)), - f.eq(self.i.f), - p.eq(self.i.f - self.i.p), - ).Else( - self.o.z.eq(self.o.z + f), - ) - ) - ] - - -class MCM(Module): - def __init__(self, width, constants): - n = len(constants) - self.i = i = Signal(width) - self.o = o = [Signal.like(self.i) for i in range(n)] - - ### - - # TODO: improve MCM - assert range(n) == constants - assert n <= 9 - - if n > 0: - self.comb += o[0].eq(0) - if n > 1: - self.comb += o[1].eq(i) - if n > 2: - self.comb += o[2].eq(i << 1) - if n > 3: - self.comb += o[3].eq(i + (i << 1)) - if n > 4: - self.comb += o[4].eq(i << 2) - if n > 5: - self.comb += o[5].eq(i + (i << 2)) - if n > 6: - self.comb += o[6].eq(o[3] << 1) - if n > 7: - self.comb += o[7].eq((i << 3) - i) - if n > 8: - self.comb += o[8].eq(i << 3) - - -class PhasedAccu(Module): - def __init__(self, width, parallelism=8): - self.i = Endpoint([("p", width), ("f", width), ("clr", 1)]) - self.o = Endpoint([("z{}".format(i), width) for i in - range(parallelism)]) - self.parallelism = parallelism - self.latency = 2 - - ### - - a = MCM(width, range(parallelism + 1)) - self.submodules += a - z = [Signal(width, reset_less=True) for i in range(parallelism)] - o = self.o.payload.flatten() - load = Signal(reset_less=True) - clr = Signal(reset_less=True) - p = Signal.like(self.i.p) - f = Signal.like(self.i.f, reset_less=True) - fp = Signal.like(self.i.f) - self.comb += [ - self.i.ack.eq(self.o.ack), - a.i.eq(self.i.f), - ] - - self.sync += [ - If(self.o.ack, - self.o.stb.eq(0), - ), - If(~self.o.stb | self.o.ack, - self.o.stb.eq(1), - If(load, - load.eq(0), - [oi.eq(Mux(clr, 0, o[0] + fp) + zi) - for oi, zi in zip(o, z)], - fp.eq(f), - ).Else( - [oi.eq(oi + fp) for oi in o], - ), - ), - If(self.i.stb & self.i.ack, - [zi.eq(self.i.p - Mux(self.i.clr, 0, p) + aoi) - for zi, aoi in zip(z, a.o)], - clr.eq(self.i.clr), - p.eq(self.i.p), - f.eq(a.o[parallelism]), - load.eq(1), - ), - ] diff --git a/artiq/gateware/dsp/fir.py b/artiq/gateware/dsp/fir.py deleted file mode 100644 index 002487e32..000000000 --- a/artiq/gateware/dsp/fir.py +++ /dev/null @@ -1,172 +0,0 @@ -from math import floor -from operator import add -from functools import reduce -from collections import namedtuple - -import numpy as np - -from migen import * - - -def halfgen4(width, n, df=1e-3): - """ - http://recycle.lbl.gov/~ldoolitt/halfband - - params: - * `up` is the passband/stopband width, as a fraction of - input sampling rate - * `n is the order of half-band filter to generate - returns: - * `a` is the full set of FIR coefficients, `4*n-1` long. - implement wisely. - """ - - npt = n*40 - wmax = 2*np.pi*width - wfit = (1 - np.linspace(0, 1, npt)[:, None]**2)*wmax - - target = .5*np.ones_like(wfit) - basis = np.cos(wfit*np.arange(1, 2*n, 2)) - weight = np.ones_like(wfit) - - f0 = None - - for i in range(40): - l = np.linalg.pinv(basis*weight)@(target*weight) - err = np.fabs(basis@l - .5) - f = np.max(err)/np.mean(err) - if f0 and (f0 - f)/(f0 + f) < df/2: - break - f0 = f - weight[err > (1 - df)*np.max(err)] *= 1 + 1.5/(i + 11) - a = np.c_[l, np.zeros_like(l)].ravel()[:-1] - a = np.r_[a[::-1], 1, a]/2 - return a - - -_Widths = namedtuple("_Widths", "A B P") - -_widths = { - "DSP48E1": _Widths(25, 18, 48), -} - - -class ParallelFIR(Module): - """Full-rate parallelized finite impulse response filter. - - Tries to use transposed form as much as possible. - - :param coefficients: tap coefficients (normalized to 1.), - increasing delay. - :param parallelism: number of samples per cycle. - :param width: bit width of input and output. - :param arch: architecture (default: "DSP48E1"). - """ - def __init__(self, coefficients, parallelism, width=16, - arch="DSP48E1", cull_delays=()): - self.width = width - self.parallelism = p = parallelism - n = len(coefficients) - # input and output: old to new, decreasing delay - self.i = [Signal((width, True)) for i in range(p)] - self.o = [Signal((width, True), reset_less=True) for i in range(p)] - self.latency = (n + 1)//2//p + 2 - w = _widths[arch] - - c_max = max(abs(c) for c in coefficients) - c_shift = bits_for(floor((1 << w.B - 2) / c_max)) - self.coefficients = cs = [int(round(c*(1 << c_shift))) - for c in coefficients] - assert max(bits_for(c) for c in cs) <= w.B - max_out = sum(abs(c)*(1 << w.A - 1) for c in cs) - assert max_out <= (1 << w.P - 1) - 1, (bits_for(max_out), w) - - ### - - # Delay line: increasing delay - x = [Signal((w.A, True), reset_less=True) for _ in range(n + p - 1)] - - for xi, xj in zip(x, self.i[::-1]): - self.comb += xi.eq(xj) - for xi, xj in zip(x[len(self.i):], x): - self.sync += xi.eq(xj) - - for delay in range(p): - o = Signal((w.P, True), reset_less=True) - self.sync += self.o[delay].eq(o >> c_shift) - # Make products - tap = delay - for i, c in enumerate(cs): - # simplify for halfband and symmetric filters - if not c or c in cs[:i]: - continue - js = [j + p - 1 for j, cj in enumerate(cs) if cj == c] - m = Signal.like(o) - o0, o = o, Signal.like(o) - q = Signal.like(x[0]) - if tap + p <= js[0]: - self.sync += o0.eq(o + m) - tap += p - else: - self.comb += o0.eq(o + m) - assert min(js) - tap >= 0 - js = [j for j in js - if (p - 1 - j - tap) % p not in cull_delays] - if not js: - continue - self.comb += q.eq(reduce(add, [x[j - tap] for j in js])) - self.sync += m.eq(c*q) - # symmetric rounding - if c_shift > 1 and delay not in cull_delays: - self.comb += o.eq((1 << c_shift - 1) - 1) - - -class FIR(ParallelFIR): - def __init__(self, *args, **kwargs): - super().__init__(self, *args, parallelism=1, **kwargs) - self.i = self.i[0] - self.o = self.o[0] - - -def halfgen4_cascade(rate, width, order=None): - """Generate coefficients for cascaded half-band filters. - - Coefficients are normalized to a gain of two per stage to compensate for - the zero stuffing. - - :param rate: upsampling rate. power of two - :param width: passband/stopband width in units of input sampling rate. - :param order: highest order, defaults to :param:`rate`""" - if order is None: - order = rate - coeff = [] - p = 1 - while p < rate: - p *= 2 - coeff.append(2*halfgen4(width*p/rate/2, order*p//rate)) - return coeff - - -class ParallelHBFUpsampler(Module): - """Parallel, power-of-two, half-band, cascading upsampler. - - Coefficients should be normalized to overall gain of 2 - (highest/center coefficient being 1).""" - def __init__(self, coefficients, width=16, **kwargs): - self.parallelism = 1 # accumulate - self.latency = 0 # accumulate - self.width = width - self.i = Signal((width, True)) - - ### - - i = [self.i] - for coeff in coefficients: - self.parallelism *= 2 - hbf = ParallelFIR(coeff, self.parallelism, width=width, - cull_delays={0}, **kwargs) - self.submodules += hbf - self.comb += [a.eq(b) for a, b in zip(hbf.i[1::2], i)] - i = hbf.o - self.latency += hbf.latency - self.o = i diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py deleted file mode 100644 index e0e9d1db4..000000000 --- a/artiq/gateware/dsp/sawg.py +++ /dev/null @@ -1,220 +0,0 @@ -from collections import namedtuple - -from migen import * -from misoc.interconnect.stream import Endpoint -from misoc.cores.cordic import Cordic - -from .accu import PhasedAccu -from .tools import eqh, SatAddMixin -from .spline import Spline -from .fir import ParallelHBFUpsampler, halfgen4_cascade - - -_Widths = namedtuple("_Widths", "t a p f") -_Orders = namedtuple("_Orders", "a p f") - - -class SplineParallelDUC(Module): - def __init__(self, widths, orders, parallelism=1, **kwargs): - self.parallelism = parallelism - self.widths = widths - p = Spline(order=orders.p, width=widths.p) - f = Spline(order=orders.f, width=widths.f) - self.f = f.tri(widths.t) - self.p = p.tri(widths.t) - self.submodules += p, f - self.ce = Signal(reset=1) - self.clr = Signal() - - ### - accu = PhasedAccu(len(self.f.a0), parallelism) - cordic = [Cordic(width=widths.a, widthz=len(self.p.a0), guard=None, - eval_mode="pipelined") for i in range(parallelism)] - self.submodules += accu, cordic - - self.xi = [c.xi for c in cordic] - self.yi = [c.yi for c in cordic] - self.xo = [c.xo for c in cordic] - self.yo = [c.yo for c in cordic] - self.latency = cordic[0].latency - self.gain = cordic[0].gain - self.f.latency += accu.latency + self.latency - self.p.latency += accu.latency + self.latency - - ### - - assert p.latency == f.latency - self.comb += [ - p.o.ack.eq(self.ce), - f.o.ack.eq(self.ce), - eqh(accu.i.f, f.o.a0), - eqh(accu.i.p, p.o.a0), - accu.i.stb.eq(p.o.stb | f.o.stb), - accu.o.ack.eq(1), - [eqh(c.zi, zi) for c, zi in - zip(cordic, accu.o.payload.flatten())] - ] - - assert p.latency == 1 - accu.i.clr.reset_less = True - self.sync += [ - accu.i.clr.eq(0), - If(p.i.stb, - accu.i.clr.eq(self.clr), - ), - ] - - -class SplineParallelDDS(SplineParallelDUC): - def __init__(self, widths, orders, **kwargs): - a = Spline(order=orders.a, width=widths.a) - self.a = a.tri(widths.t) - self.submodules += a - super().__init__(widths._replace(a=len(self.a.a0)), orders, **kwargs) - - self.a.latency += self.latency - - ### - - self.comb += [ - a.o.ack.eq(self.ce), - [eqh(x, a.o.a0) for x in self.xi], - [y.eq(0) for y in self.yi], - ] - del self.xi - del self.yi - - -class Config(Module): - def __init__(self, width, cordic_gain): - self.clr = Signal(3, reset=0b111) - self.iq_en = Signal(2, reset=0b01) - self.limits = [[Signal((width, True)), Signal((width, True))] - for i in range(2)] - limit = (1 << width - 1) - 1 - limit_cordic = int(limit/cordic_gain) - self.limits[0][0].reset = Constant(-limit, (width, True)) - self.limits[0][1].reset = Constant(limit, (width, True)) - self.limits[1][0].reset = Constant(-limit_cordic, (width, True)) - self.limits[1][1].reset = Constant(limit_cordic, (width, True)) - # TODO make persistent, add read-out/notification/clear - self.clipped = [Signal(2) for i in range(2)] - self.i = Endpoint([("addr", bits_for(4 + 2*len(self.limits) - 1)), - ("data", width)]) - assert len(self.i.addr) == 3 - self.ce = Signal() - - ### - - div = Signal(16, reset=0) - n = Signal.like(div) - - self.comb += self.ce.eq(n == 0) - self.sync += [ - n.eq(n - 1), - If(self.ce, - n.eq(div), - ) - ] - - pad = Signal() - - reg = Array(sum(self.limits, - [Cat(div, n), self.clr, self.iq_en, pad])) - - self.comb += self.i.ack.eq(1) - self.sync += [ - If(self.i.stb, - reg[self.i.addr].eq(self.i.data), - ), - ] - - -class Channel(Module, SatAddMixin): - def __init__(self, width=16, parallelism=4, widths=None, orders=None): - if orders is None: - orders = _Orders(a=4, f=2, p=1) - if widths is None: - widths = _Widths(t=width, a=orders.a*width, p=orders.p*width, - f=(orders.f + 2)*width) - - self.submodules.a1 = a1 = SplineParallelDDS(widths, orders) - self.submodules.a2 = a2 = SplineParallelDDS(widths, orders) - coeff = halfgen4_cascade(parallelism, width=.4, order=8) - hbf = [ParallelHBFUpsampler(coeff, width=width + 1) for i in range(2)] - self.submodules.b = b = SplineParallelDUC( - widths._replace(a=len(hbf[0].o[0]), f=widths.f - width), orders, - parallelism=parallelism) - cfg = Config(width, b.gain) - u = Spline(width=widths.a, order=orders.a) - self.submodules += cfg, u, hbf - self.u = u.tri(widths.t) - self.i = [cfg.i, self.u, a1.a, a1.f, a1.p, a2.a, a2.f, a2.p, b.f, b.p] - self.i_names = "cfg u a1 f1 p1 a2 f2 p2 f0 p0".split() - self.i_named = dict(zip(self.i_names, self.i)) - self.y_in = [Signal.like(b.yo[0]) for i in range(parallelism)] - self.o = [Signal((width, True), reset_less=True) - for i in range(parallelism)] - self.widths = widths - self.orders = orders - self.parallelism = parallelism - self.cordic_gain = a2.gain*b.gain - - self.u.latency += 1 # self.o - b.p.latency += 1 # self.o - b.f.latency += 1 # self.o - a_latency_delta = hbf[0].latency + b.latency + 2 # hbf.i, self.o - for a in a1, a2: - a.a.latency += a_latency_delta - a.p.latency += a_latency_delta - a.f.latency += a_latency_delta - - self.latency = max(_.latency for _ in self.i[1:]) - for i in self.i[1:]: - i.latency -= self.latency - assert i.latency <= 0 - cfg.i.latency = 0 - - ### - - self.comb += [ - a1.ce.eq(cfg.ce), - a2.ce.eq(cfg.ce), - b.ce.eq(cfg.ce), - u.o.ack.eq(cfg.ce), - Cat(b.clr, a1.clr, a2.clr).eq(cfg.clr), - [i.eq(j) for i, j in zip(b.xi, hbf[0].o)], - [i.eq(j) for i, j in zip(b.yi, hbf[1].o)], - ] - hbf[0].i.reset_less = True - hbf[1].i.reset_less = True - self.sync += [ - hbf[0].i.eq(self.sat_add((a1.xo[0], a2.xo[0]), - width=len(hbf[0].i), - limits=cfg.limits[1], clipped=cfg.clipped[1])), - hbf[1].i.eq(self.sat_add((a1.yo[0], a2.yo[0]), - width=len(hbf[1].i), - limits=cfg.limits[1])), - ] - # wire up outputs and q_{i,o} exchange - for o, x, y in zip(self.o, b.xo, self.y_in): - o_offset = Signal.like(o) - o_x = Signal.like(x) - o_y = Signal.like(y) - self.comb += [ - o_offset.eq(u.o.a0[-len(o):]), - If(cfg.iq_en[0], - o_x.eq(x) - ), - If(cfg.iq_en[1], - o_y.eq(y) - ), - ] - self.sync += [ - o.eq(self.sat_add((o_offset, o_x, o_y), - width=len(o), - limits=cfg.limits[0], clipped=cfg.clipped[0])), - ] - - def connect_y(self, buddy): - self.comb += [i.eq(j) for i, j in zip(buddy.y_in, self.b.yo)] diff --git a/artiq/gateware/dsp/spline.py b/artiq/gateware/dsp/spline.py deleted file mode 100644 index 8185ae856..000000000 --- a/artiq/gateware/dsp/spline.py +++ /dev/null @@ -1,47 +0,0 @@ -from migen import * -from misoc.interconnect.stream import Endpoint - - -class Spline(Module): - def __init__(self, order, width, step=1, time_width=None): - if not (step == 1 or order <= 2): - raise ValueError("For non-linear splines, " - "`step` needs to be one.") - layout = [("a{}".format(i), (width, True)) for i in range(order)] - self.i = Endpoint(layout) - self.o = Endpoint(layout) - self.latency = 1 - - ### - - o = self.o.payload.flatten() - - self.comb += self.i.ack.eq(~self.o.stb | self.o.ack) - self.sync += [ - If(self.o.ack, - self.o.stb.eq(0), - ), - If(self.i.ack, - self.o.stb.eq(1), - [o[i].eq(o[i] + (o[i + 1] << log2_int(step))) - for i in range(order - 1)], - If(self.i.stb, - self.o.payload.eq(self.i.payload), - ), - ), - ] - - def tri(self, time_width): - layout = [(name, (length - i*time_width, signed)) - for i, (name, (length, signed), dir) in - enumerate(self.i.payload.layout[::-1])] - layout.reverse() - i = Endpoint(layout) - i.latency = self.latency - self.comb += [ - self.i.stb.eq(i.stb), - i.ack.eq(self.i.ack), - [i0[-len(i1):].eq(i1) for i0, i1 in - zip(self.i.payload.flatten(), i.payload.flatten())] - ] - return i diff --git a/artiq/gateware/dsp/tools.py b/artiq/gateware/dsp/tools.py deleted file mode 100644 index c198d1706..000000000 --- a/artiq/gateware/dsp/tools.py +++ /dev/null @@ -1,69 +0,0 @@ -from operator import add -from functools import reduce - -from migen import * - - -class Delay(Module): - def __init__(self, i, delay, o=None): - if isinstance(i, (int, tuple)): - z = [Signal(i) for j in range(delay + 1)] - elif isinstance(i, list): - z = [Record(i) for j in range(delay + 1)] - elif isinstance(i, Record): - z = [Record(i.layout) for j in range(delay + 1)] - else: - z = [Signal.like(i) for j in range(delay + 1)] - self.i = z[0] - self.o = z[-1] - if not isinstance(i, (int, list, tuple)): - self.comb += self.i.eq(i) - if o is not None: - self.comb += o.eq(self.o) - self.latency = delay - self.sync += [z[j + 1].eq(z[j]) for j in range(delay)] - - -def eqh(a, b): - return a[-len(b):].eq(b[-len(a):]) - - -class SatAddMixin: - """Signed saturating addition mixin""" - def sat_add(self, a, width, limits=None, clipped=None): - a = list(a) - # assert all(value_bits_sign(ai)[1] for ai in a) - max_width = max(value_bits_sign(ai)[0] for ai in a) - carry = log2_int(len(a), need_pow2=False) - full = Signal((max_width + carry, True)) - limited = Signal((width, True)) - carry = len(full) - width - assert carry >= 0 - clip = Signal(2) - sign = Signal() - if clipped is not None: - self.comb += clipped.eq(clip) - self.comb += [ - full.eq(reduce(add, a)), - sign.eq(full[-1]), - limited.eq(full) - ] - if limits is None: - self.comb += [ - If(full[-1-carry:] != Replicate(sign, carry + 1), - clip.eq(Cat(sign, ~sign)), - limited.eq(Cat(Replicate(~sign, width - 1), sign)), - ) - ] - else: - self.comb += [ - If(full < limits[0], - clip.eq(0b01), - limited.eq(limits[0]) - ), - If(full > limits[1], - clip.eq(0b10), - limited.eq(limits[1]), - ) - ] - return limited diff --git a/artiq/gateware/fmcdio_vhdci_eem.py b/artiq/gateware/fmcdio_vhdci_eem.py deleted file mode 100644 index 0296efe8e..000000000 --- a/artiq/gateware/fmcdio_vhdci_eem.py +++ /dev/null @@ -1,29 +0,0 @@ -from migen.build.generic_platform import * - -from artiq.coredevice.fmcdio_vhdci_eem import * - - -io = [ - ("fmcdio_dirctl", 0, - Subsignal("clk", Pins("LPC:LA32_N")), - Subsignal("ser", Pins("LPC:LA33_P")), - Subsignal("latch", Pins("LPC:LA32_P")), - IOStandard("LVCMOS18") - ), -] - -def _get_connectors(): - connectors = [] - for i in range(4): - connections = dict() - for j, pair in enumerate(eem_fmc_connections[i]): - for pn in "n", "p": - cc = "cc_" if j == 0 else "" - lpc_cc = "CC_" if eem_fmc_connections[i][j] in (0, 1, 17, 18) else "" - connections["d{}_{}{}".format(j, cc, pn)] = \ - "LPC:LA{:02d}_{}{}".format(pair, lpc_cc, pn.upper()) - connectors.append(("eem{}".format(i), connections)) - return connectors - - -connectors = _get_connectors() diff --git a/artiq/gateware/jesd204_tools.py b/artiq/gateware/jesd204_tools.py deleted file mode 100644 index d05d6432f..000000000 --- a/artiq/gateware/jesd204_tools.py +++ /dev/null @@ -1,290 +0,0 @@ -from collections import namedtuple - -from migen import * -from migen.genlib.cdc import MultiReg, BusSynchronizer -from migen.genlib.resetsync import AsyncResetSynchronizer -from misoc.interconnect.csr import * - -from jesd204b.common import (JESD204BTransportSettings, - JESD204BPhysicalSettings, - JESD204BSettings) -from jesd204b.phy.gth import (GTHChannelPLL as JESD204BGTHChannelPLL, - GTHQuadPLL as JESD204BGTHQuadPLL, - GTHTransmitter as JESD204BGTHTransmitter, - GTHInit as JESD204BGTHInit, - GTHTransmitterInterconnect as JESD204BGTHTransmitterInterconnect) -from jesd204b.phy import JESD204BPhyTX -from jesd204b.core import JESD204BCoreTX -from jesd204b.core import JESD204BCoreTXControl - - -class UltrascaleCRG(Module, AutoCSR): - linerate = int(6e9) # linerate = 20*data_rate*4/8 = data_rate*10 - # data_rate = dac_rate/interp_factor - refclk_freq = int(150e6) - fabric_freq = int(125e6) - - def __init__(self, platform, use_rtio_clock=False): - self.jreset = CSRStorage(reset=1) - self.refclk = Signal() - self.clock_domains.cd_jesd = ClockDomain() - - refclk2 = Signal() - refclk_pads = platform.request("dac_refclk", 0) - platform.add_period_constraint(refclk_pads.p, 1e9/self.refclk_freq) - self.specials += [ - Instance("IBUFDS_GTE3", i_CEB=0, p_REFCLK_HROW_CK_SEL=0b00, - i_I=refclk_pads.p, i_IB=refclk_pads.n, - o_O=self.refclk, o_ODIV2=refclk2), - AsyncResetSynchronizer(self.cd_jesd, self.jreset.storage), - ] - - if use_rtio_clock: - self.cd_jesd.clk.attr.add("keep") - self.comb += self.cd_jesd.clk.eq(ClockSignal("rtio")) - else: - self.specials += Instance("BUFG_GT", i_I=refclk2, o_O=self.cd_jesd.clk) - - -PhyPads = namedtuple("PhyPads", "txp txn") - - -class UltrascaleTX(Module, AutoCSR): - def __init__(self, platform, sys_crg, jesd_crg, dac, pll_type="cpll", tx_half=False): - # Note: In general, the choice between channel and quad PLLs can be made based on the "nominal operating ranges", which are (see UG576, Ch.2): - # CPLL: 2.0 - 6.25 GHz - # QPLL0: 9.8 - 16.375 GHz - # QPLL1: 8.0 - 13.0 GHz - # However, the exact frequency and/or linerate range should be checked according to the model and speed grade from their corresponding datasheets. - pll_cls = { - "cpll": JESD204BGTHChannelPLL, - "qpll": JESD204BGTHQuadPLL - }[pll_type] - ps = JESD204BPhysicalSettings(l=8, m=4, n=16, np=16) - ts = JESD204BTransportSettings(f=2, s=2, k=16, cs=0) - settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) - - jesd_pads = platform.request("dac_jesd", dac) - plls = [] - phys = [] - for i in range(len(jesd_pads.txp)): - pll = pll_cls( - jesd_crg.refclk, jesd_crg.refclk_freq, jesd_crg.linerate) - self.submodules += pll - plls.append(pll) - # QPLL quads - if pll_type == "qpll": - gthe3_common_cfgs = [] - for i in range(0, len(plls), 4): - # GTHE3_COMMON common signals - qpll_clk = Signal() - qpll_refclk = Signal() - qpll_reset = Signal() - qpll_lock = Signal() - # GTHE3_COMMON - self.specials += pll_cls.get_gthe3_common( - jesd_crg.refclk, jesd_crg.refclk_freq, jesd_crg.linerate, - qpll_clk, qpll_refclk, qpll_reset, qpll_lock) - gthe3_common_cfgs.append({ - "clk": qpll_clk, - "refclk": qpll_refclk, - "reset": qpll_reset, - "lock": qpll_lock - }) - # Per-channel PLL phys - for i, pll in enumerate(plls): - # PhyTX - phy = JESD204BPhyTX( - pll, jesd_crg.refclk, PhyPads(jesd_pads.txp[i], jesd_pads.txn[i]), - jesd_crg.fabric_freq, transceiver="gth", tx_half=tx_half) - phys.append(phy) - if tx_half: - platform.add_period_constraint(phy.transmitter.cd_tx_half.clk, - 80*1e9/jesd_crg.linerate) - platform.add_false_path_constraints( - sys_crg.cd_sys.clk, - jesd_crg.cd_jesd.clk, - phy.transmitter.cd_tx_half.clk) - else: - platform.add_period_constraint(phy.transmitter.cd_tx.clk, - 40*1e9/jesd_crg.linerate) - platform.add_false_path_constraints( - sys_crg.cd_sys.clk, - jesd_crg.cd_jesd.clk, - phy.transmitter.cd_tx.clk) - # CHANNEL & init interconnects - for i, (pll, phy) in enumerate(zip(plls, phys)): - # CPLLs: 1 init per channel - if pll_type == "cpll": - phy_channel_cfg = {} - # Connect reset/lock to init - pll_reset = pll.reset - pll_lock = pll.lock - self.submodules += JESD204BGTHTransmitterInterconnect( - pll_reset, pll_lock, phy.transmitter, phy.transmitter.init) - # QPLL: 4 inits and 4 channels per quad - elif pll_type == "qpll": - # Connect clk/refclk to CHANNEL - phy_cfg = gthe3_common_cfgs[int(i//4)] - phy_channel_cfg = { - "qpll_clk": phy_cfg["clk"], - "qpll_refclk": phy_cfg["refclk"] - } - # Connect reset/lock to init - pll_reset = phy_cfg["reset"] - pll_lock = phy_cfg["lock"] - if i % 4 == 0: - self.submodules += JESD204BGTHTransmitterInterconnect( - pll_reset, pll_lock, phy.transmitter, - [phys[j].transmitter.init for j in range(i, min(len(phys), i+4))]) - # GTHE3_CHANNEL - self.specials += JESD204BGTHTransmitter.get_gthe3_channel( - pll, phy.transmitter, **phy_channel_cfg) - - self.submodules.core = JESD204BCoreTX( - phys, settings, converter_data_width=64) - self.submodules.control = JESD204BCoreTXControl(self.core) - self.core.register_jsync(platform.request("dac_sync", dac)) - - -class DDMTDEdgeDetector(Module): - def __init__(self, i): - self.rising = Signal() - - history = Signal(4) - deglitched = Signal() - self.sync.helper += history.eq(Cat(history[1:], i)) - self.comb += deglitched.eq(i | history[0] | history[1] | history[2] | history[3]) - - deglitched_r = Signal() - self.sync.helper += [ - deglitched_r.eq(deglitched), - self.rising.eq(deglitched & ~deglitched_r) - ] - - -# See "Digital femtosecond time difference circuit for CERN's timing system" -# by P. Moreira and I. Darwazeh -class DDMTD(Module, AutoCSR): - def __init__(self, input_pads, rtio_clk_freq=150e6): - N = 64 - self.reset = CSRStorage(reset=1) - self.locked = CSRStatus() - self.dt = CSRStatus(N.bit_length()) - - # # # - - self.clock_domains.cd_helper = ClockDomain(reset_less=True) - helper_locked = Signal() - helper_fb = Signal() - helper_output = Signal() - - input_se = Signal() - beat1 = Signal() - beat2 = Signal() - self.specials += [ - Instance("MMCME2_BASE", - p_CLKIN1_PERIOD=1e9/rtio_clk_freq, - i_CLKIN1=ClockSignal("rtio"), - i_RST=self.reset.storage, - o_LOCKED=helper_locked, - - # VCO at 1200MHz with 150MHz RTIO frequency - p_CLKFBOUT_MULT_F=8.0, - p_DIVCLK_DIVIDE=1, - - o_CLKFBOUT=helper_fb, i_CLKFBIN=helper_fb, - - # helper PLL ratio: 64/65 (N=64) - p_CLKOUT0_DIVIDE_F=8.125, - o_CLKOUT0=helper_output, - ), - MultiReg(helper_locked, self.locked.status), - Instance("BUFG", i_I=helper_output, o_O=self.cd_helper.clk), - Instance("IBUFDS", i_I=input_pads.p, i_IB=input_pads.n, o_O=input_se), - Instance("FD", i_C=self.cd_helper.clk, i_D=input_se, o_Q=beat1, attr={("IOB", "TRUE")}), - Instance("FD", i_C=self.cd_helper.clk, i_D=ClockSignal("rtio"), o_Q=beat2), - ] - - ed1 = DDMTDEdgeDetector(beat1) - ed2 = DDMTDEdgeDetector(beat2) - self.submodules += ed1, ed2 - - counting = Signal() - counter = Signal(N.bit_length()) - result = Signal.like(counter) - self.sync.helper += [ - If(counting, - counter.eq(counter + 1) - ).Else( - result.eq(counter) - ), - - If(ed1.rising, counting.eq(1), counter.eq(0)), - If(ed2.rising, counting.eq(0)) - ] - - bsync = BusSynchronizer(len(result), "helper", "sys") - self.submodules += bsync - self.comb += [ - bsync.i.eq(result), - self.dt.status.eq(bsync.o) - ] - - -# This assumes: -# * fine RTIO frequency (rtiox) = 2*RTIO frequency -# * JESD and coarse RTIO clocks are the same -# (only reset may differ). -class SysrefSampler(Module, AutoCSR): - def __init__(self, sysref_pads, coarse_ts, sysref_phase_bits=8): - self.sh_error = CSRStatus() - self.sh_error_reset = CSRStorage() - # Note: only the lower log2(RTIO frequency / SYSREF frequency) bits are stable - self.sysref_phase = CSRStatus(8) - - 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) - ] - - jref_r = Signal() - sysref_phase_rtio = Signal(sysref_phase_bits) - self.sync.rtio += [ - jref_r.eq(self.jref), - If(self.jref & ~jref_r, sysref_phase_rtio.eq(coarse_ts)) - ] - sysref_phase_rtio.attr.add("no_retiming") - self.specials += MultiReg(sysref_phase_rtio, self.sysref_phase.status) diff --git a/artiq/gateware/rtio/phy/sawg.py b/artiq/gateware/rtio/phy/sawg.py deleted file mode 100644 index 7968eb2b6..000000000 --- a/artiq/gateware/rtio/phy/sawg.py +++ /dev/null @@ -1,39 +0,0 @@ -from collections import namedtuple - -from migen import * -from artiq.gateware.rtio import rtlink - -from artiq.gateware.dsp.sawg import Channel as _Channel - - -_Phy = namedtuple("Phy", "rtlink probes overrides") - -_ChannelPHY = ClockDomainsRenamer("rio_phy")(_Channel) - - -class Channel(_ChannelPHY): - def __init__(self, *args, **kwargs): - _ChannelPHY.__init__(self, *args, **kwargs) - self.phys = [] - cfg = self.i[0] - rl = rtlink.Interface(rtlink.OInterface( - data_width=len(cfg.data), address_width=len(cfg.addr), - enable_replace=False)) - self.comb += [ - cfg.stb.eq(rl.o.stb), - rl.o.busy.eq(~cfg.ack), - cfg.data.eq(rl.o.data), - cfg.addr.eq(rl.o.address), - ] - self.phys.append(_Phy(rl, [], [])) - for i in self.i[1:]: - rl = rtlink.Interface(rtlink.OInterface(len(i.payload), - delay=-i.latency)) - self.comb += [ - i.stb.eq(rl.o.stb), - rl.o.busy.eq(~i.ack), - i.payload.raw_bits().eq(rl.o.data), - ] - # TODO probes, overrides - self.phys.append(_Phy(rl, [], [])) - self.phys_named = dict(zip(self.i_names, self.phys)) diff --git a/artiq/gateware/targets/metlino.py b/artiq/gateware/targets/metlino.py deleted file mode 100755 index ffb2b38b9..000000000 --- a/artiq/gateware/targets/metlino.py +++ /dev/null @@ -1,180 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -from functools import partial - -from migen import * -from migen.build.generic_platform import IOStandard - -from misoc.cores import gpio -from misoc.integration.builder import builder_args, builder_argdict -from misoc.interconnect.csr import * -from misoc.targets.metlino import * - -from artiq.gateware.amp import AMPSoC -from artiq.gateware import eem -from artiq.gateware import rtio -from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_ultrascale -from artiq.gateware.drtio.transceiver import gth_ultrascale -from artiq.gateware.drtio import * -from artiq.build_soc import * - - -def workaround_us_lvds_tristate(platform): - # Those shoddy Kintex Ultrascale FPGAs take almost a microsecond to change the direction of a - # LVDS I/O buffer. The application has to cope with it and this cannot be handled at static - # timing analysis. Disable the latter for IOBUFDS. - # See: - # https://forums.xilinx.com/t5/Timing-Analysis/Delay-890-ns-in-OBUFTDS-in-Kintex-UltraScale/td-p/868364 - platform.add_platform_command( - "set_false_path -through [get_pins -filter {{REF_PIN_NAME == T}} -of [get_cells -filter {{REF_NAME == IOBUFDS}}]]") - - -class Master(MiniSoC, AMPSoC): - mem_map = { - "cri_con": 0x10000000, - "rtio": 0x11000000, - "rtio_dma": 0x12000000, - "drtioaux": 0x14000000, - "mailbox": 0x70000000 - } - mem_map.update(MiniSoC.mem_map) - - def __init__(self, gateware_identifier_str=None, **kwargs): - MiniSoC.__init__(self, - cpu_type="vexriscv", - cpu_bus_width=64, - sdram_controller_type="minicon", - l2_size=128*1024, - integrated_sram_size=8192, - ethmac_nrxslots=4, - ethmac_ntxslots=4, - csr_address_width=15, - **kwargs) - AMPSoC.__init__(self) - add_identifier(self, gateware_identifier_str=gateware_identifier_str) - - platform = self.platform - rtio_clk_freq = 150e6 - - self.comb += platform.request("input_clk_sel").eq(1) - self.comb += platform.request("filtered_clk_sel").eq(1) - 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["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - - self.submodules.drtio_transceiver = gth_ultrascale.GTH( - clock_pads=platform.request("cdr_clk_clean", 0), - data_pads=[platform.request("mch_fabric_d", i) for i in range(11)], - sys_clk_freq=self.clk_freq, - rtio_clk_freq=rtio_clk_freq) - self.csr_devices.append("drtio_transceiver") - - self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) - - drtio_csr_group = [] - drtioaux_csr_group = [] - drtioaux_memory_group = [] - drtio_cri = [] - for i in range(len(self.drtio_transceiver.channels)): - core_name = "drtio" + str(i) - coreaux_name = "drtioaux" + str(i) - memory_name = "drtioaux" + str(i) + "_mem" - drtio_csr_group.append(core_name) - drtioaux_csr_group.append(coreaux_name) - drtioaux_memory_group.append(memory_name) - - cdr = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)}) - - core = cdr(DRTIOMaster(self.rtio_tsc, self.drtio_transceiver.channels[i])) - setattr(self.submodules, core_name, core) - drtio_cri.append(core.cri) - self.csr_devices.append(core_name) - - coreaux = cdr(DRTIOAuxController(core.link_layer, self.cpu_dw)) - setattr(self.submodules, coreaux_name, coreaux) - self.csr_devices.append(coreaux_name) - - memory_address = self.mem_map["drtioaux"] + 0x800*i - self.add_wb_slave(memory_address, 0x800, - coreaux.bus) - self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) - self.config["HAS_DRTIO"] = None - self.config["HAS_DRTIO_ROUTING"] = None - self.add_csr_group("drtio", drtio_csr_group) - self.add_csr_group("drtioaux", drtioaux_csr_group) - self.add_memory_group("drtioaux_mem", drtioaux_memory_group) - - rtio_clk_period = 1e9/rtio_clk_freq - gth0 = self.drtio_transceiver.gths[0] - platform.add_period_constraint(gth0.txoutclk, rtio_clk_period/2) - platform.add_period_constraint(gth0.rxoutclk, rtio_clk_period) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, - gth0.txoutclk, gth0.rxoutclk) - for gth in self.drtio_transceiver.gths[1:]: - platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, gth0.txoutclk, gth.rxoutclk) - - self.rtio_channels = 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)) - - output_4x = partial(ttl_serdes_ultrascale.Output, 4) - eem.DIO.add_std(self, 2, output_4x, output_4x, - iostandard=lambda eem: IOStandard("LVDS")) - eem.Urukul.add_std(self, 0, 1, output_4x, - iostandard=lambda eem: IOStandard("LVDS")) - eem.Zotino.add_std(self, 3, output_4x, - iostandard=lambda eem: IOStandard("LVDS")) - workaround_us_lvds_tristate(platform) - - self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) - rtio_channels.append(rtio.LogChannel()) - - self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) - self.csr_devices.append("rtio_moninj") - - 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.cpu_dw)) - 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] + drtio_cri, - enable_routing=True) - self.register_kernel_cpu_csrdevice("cri_con") - self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con) - self.csr_devices.append("routing_table") - - -def main(): - parser = argparse.ArgumentParser( - description="Metlino gateware and firmware builder") - builder_args(parser) - soc_sdram_args(parser) - parser.set_defaults(output_dir="artiq_metlino") - parser.add_argument("--gateware-identifier-str", default=None, - help="Override ROM identifier") - args = parser.parse_args() - args.variant = "master" - soc = Master(gateware_identifier_str=args.gateware_identifier_str, **soc_sdram_argdict(args)) - build_artiq_soc(soc, builder_argdict(args)) - - -if __name__ == "__main__": - main() diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py deleted file mode 100755 index 527d37b5c..000000000 --- a/artiq/gateware/targets/sayma_amc.py +++ /dev/null @@ -1,462 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import os -import warnings -from functools import partial - -from migen import * -from migen.build.generic_platform import IOStandard - -from misoc.cores import gpio -from misoc.integration.builder import builder_args, builder_argdict -from misoc.interconnect.csr import * -from misoc.targets.sayma_amc import * - -from artiq.gateware.amp import AMPSoC -from artiq.gateware import eem -from artiq.gateware import rtio -from artiq.gateware import jesd204_tools -from artiq.gateware import fmcdio_vhdci_eem -from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_ultrascale, sawg -from artiq.gateware.drtio.transceiver import gth_ultrascale -from artiq.gateware.drtio.siphaser import SiPhaser7Series -from artiq.gateware.drtio.wrpll import WRPLL, DDMTDSamplerExtFF -from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer -from artiq.gateware.drtio import * -from artiq.build_soc import * - - -def workaround_us_lvds_tristate(platform): - # Those shoddy Kintex Ultrascale FPGAs take almost a microsecond to change the direction of a - # LVDS I/O buffer. The application has to cope with it and this cannot be handled at static - # timing analysis. Disable the latter for IOBUFDS. - # See: - # https://forums.xilinx.com/t5/Timing-Analysis/Delay-890-ns-in-OBUFTDS-in-Kintex-UltraScale/td-p/868364 - platform.add_platform_command( - "set_false_path -through [get_pins -filter {{REF_PIN_NAME == T}} -of [get_cells -filter {{REF_NAME == IOBUFDS}}]]") - - -class RTMUARTForward(Module): - def __init__(self, platform): - # forward RTM UART to second FTDI UART channel - serial_1 = platform.request("serial", 1) - serial_rtm = platform.request("serial_rtm") - self.comb += [ - serial_1.tx.eq(serial_rtm.rx), - serial_rtm.tx.eq(serial_1.rx) - ] - - -class SatelliteBase(MiniSoC): - mem_map = { - "drtioaux": 0x14000000, - } - mem_map.update(MiniSoC.mem_map) - - def __init__(self, rtio_clk_freq=125e6, identifier_suffix="", gateware_identifier_str=None, with_sfp=False, *, with_wrpll, **kwargs): - MiniSoC.__init__(self, - cpu_type="vexriscv", - cpu_bus_width=64, - sdram_controller_type="minicon", - l2_size=128*1024, - integrated_sram_size=8192, - ethmac_nrxslots=4, - ethmac_ntxslots=4, - **kwargs) - add_identifier(self, suffix=identifier_suffix, gateware_identifier_str=gateware_identifier_str) - self.rtio_clk_freq = rtio_clk_freq - - platform = self.platform - - if with_wrpll: - clock_recout_pads = platform.request("ddmtd_rec_clk") - else: - clock_recout_pads = None - if with_sfp: - # Use SFP0 to connect to master (Kasli) - self.comb += platform.request("sfp_tx_disable", 0).eq(0) - drtio_uplink = platform.request("sfp", 0) - else: - drtio_uplink = platform.request("fat_pipe", 0) - self.submodules.drtio_transceiver = gth_ultrascale.GTH( - clock_pads=platform.request("cdr_clk_clean"), - data_pads=[drtio_uplink, platform.request("rtm_amc_link")], - sys_clk_freq=self.clk_freq, - rtio_clk_freq=rtio_clk_freq, - clock_recout_pads=clock_recout_pads) - self.csr_devices.append("drtio_transceiver") - - self.submodules.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) - - drtioaux_csr_group = [] - drtioaux_memory_group = [] - drtiorep_csr_group = [] - self.drtio_cri = [] - for i in range(len(self.drtio_transceiver.channels)): - coreaux_name = "drtioaux" + str(i) - memory_name = "drtioaux" + str(i) + "_mem" - drtioaux_csr_group.append(coreaux_name) - drtioaux_memory_group.append(memory_name) - - cdr = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)}) - - if i == 0: - self.submodules.rx_synchronizer = cdr(XilinxRXSynchronizer()) - core = cdr(DRTIOSatellite( - self.rtio_tsc, self.drtio_transceiver.channels[i], - self.rx_synchronizer)) - self.submodules.drtiosat = core - self.csr_devices.append("drtiosat") - else: - corerep_name = "drtiorep" + str(i-1) - drtiorep_csr_group.append(corerep_name) - - core = cdr(DRTIORepeater( - self.rtio_tsc, self.drtio_transceiver.channels[i])) - setattr(self.submodules, corerep_name, core) - self.drtio_cri.append(core.cri) - self.csr_devices.append(corerep_name) - - coreaux = cdr(DRTIOAuxController(core.link_layer, self.cpu_dw)) - setattr(self.submodules, coreaux_name, coreaux) - self.csr_devices.append(coreaux_name) - - memory_address = self.mem_map["drtioaux"] + 0x800*i - self.add_wb_slave(memory_address, 0x800, - coreaux.bus) - self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) - self.config["HAS_DRTIO"] = None - self.config["HAS_DRTIO_ROUTING"] = None - self.add_csr_group("drtioaux", drtioaux_csr_group) - self.add_memory_group("drtioaux_mem", drtioaux_memory_group) - self.add_csr_group("drtiorep", drtiorep_csr_group) - - rtio_clk_period = 1e9/rtio_clk_freq - self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - if with_wrpll: - self.comb += [ - platform.request("filtered_clk_sel").eq(0), - platform.request("ddmtd_main_dcxo_oe").eq(1), - platform.request("ddmtd_helper_dcxo_oe").eq(1) - ] - self.submodules.wrpll_sampler = DDMTDSamplerExtFF( - platform.request("ddmtd_inputs")) - self.submodules.wrpll = WRPLL( - helper_clk_pads=platform.request("ddmtd_helper_clk"), - main_dcxo_i2c=platform.request("ddmtd_main_dcxo_i2c"), - helper_dxco_i2c=platform.request("ddmtd_helper_dcxo_i2c"), - ddmtd_inputs=self.wrpll_sampler) - self.csr_devices.append("wrpll") - platform.add_period_constraint(self.wrpll.cd_helper.clk, rtio_clk_period*0.99) - platform.add_false_path_constraints(self.crg.cd_sys.clk, self.wrpll.cd_helper.clk) - else: - self.comb += platform.request("filtered_clk_sel").eq(1) - self.submodules.siphaser = SiPhaser7Series( - si5324_clkin=platform.request("si5324_clkin"), - rx_synchronizer=self.rx_synchronizer, - ultrascale=True, - rtio_clk_freq=rtio_clk_freq) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) - self.csr_devices.append("siphaser") - 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 - - gth = self.drtio_transceiver.gths[0] - platform.add_period_constraint(gth.txoutclk, rtio_clk_period/2) - platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, - gth.txoutclk, gth.rxoutclk) - - def add_rtio(self, rtio_channels): - # Only add MonInj core if there is anything to monitor - if any([len(c.probes) for c in rtio_channels]): - self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) - self.csr_devices.append("rtio_moninj") - - self.submodules.local_io = SyncRTIO(self.rtio_tsc, rtio_channels) - self.comb += self.drtiosat.async_errors.eq(self.local_io.async_errors) - self.submodules.cri_con = rtio.CRIInterconnectShared( - [self.drtiosat.cri], - [self.local_io.cri] + self.drtio_cri, - mode="sync", enable_routing=True) - self.csr_devices.append("cri_con") - self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con) - self.csr_devices.append("routing_table") - - -# JESD204 DAC Channel Group -class JDCGSAWG(Module, AutoCSR): - def __init__(self, platform, sys_crg, jesd_crg, dac): - # Kintex Ultrascale GTH, speed grade -1C: - # CPLL linerate (D=1): 4.0 - 8.5 Gb/s - self.submodules.jesd = jesd204_tools.UltrascaleTX( - platform, sys_crg, jesd_crg, dac) - - self.submodules.sawgs = [sawg.Channel(width=16, parallelism=4) for i in range(4)] - - for conv, ch in zip(self.jesd.core.sink.flatten(), self.sawgs): - assert len(Cat(ch.o)) == len(conv) - self.sync.jesd += conv.eq(Cat(ch.o)) - - -class JDCGPattern(Module, AutoCSR): - def __init__(self, platform, sys_crg, jesd_crg, dac): - self.submodules.jesd = jesd204_tools.UltrascaleTX( - platform, sys_crg, jesd_crg, dac) - - self.sawgs = [] - - ramp = Signal(4) - self.sync.rtio += ramp.eq(ramp + 1) - - samples = [[Signal(16) for i in range(4)] for j in range(4)] - self.comb += [ - a.eq(Cat(b)) for a, b in zip( - self.jesd.core.sink.flatten(), samples) - ] - # ch0: 16-step ramp with big carry toggles - for i in range(4): - self.comb += [ - samples[0][i][-4:].eq(ramp), - samples[0][i][:-4].eq(0x7ff if i % 2 else 0x800) - ] - # ch1: 50 MHz - from math import pi, cos - data = [int(round(cos(i/12*2*pi)*((1 << 15) - 1))) - for i in range(12)] - k = Signal(2) - self.sync.rtio += If(k == 2, k.eq(0)).Else(k.eq(k + 1)) - self.comb += [ - Case(k, { - i: [samples[1][j].eq(data[i*4 + j]) for j in range(4)] - for i in range(3) - }) - ] - # ch2: ch0, ch3: ch1 - self.comb += [ - Cat(samples[2]).eq(Cat(samples[0])), - Cat(samples[3]).eq(Cat(samples[1])) - ] - - -class JDCGSyncDDS(Module, AutoCSR): - def __init__(self, platform, sys_crg, jesd_crg, dac): - self.submodules.jesd = jesd204_tools.UltrascaleTX( - platform, sys_crg, jesd_crg, dac) - self.coarse_ts = Signal(32) - - self.sawgs = [] - - ftw = round(2**len(self.coarse_ts)*9e6/600e6) - parallelism = 4 - - mul_1 = Signal.like(self.coarse_ts) - mul_2 = Signal.like(self.coarse_ts) - mul_3 = Signal.like(self.coarse_ts) - self.sync.rtio += [ - mul_1.eq(self.coarse_ts*ftw*parallelism), - mul_2.eq(mul_1), - mul_3.eq(mul_2) - ] - - phases = [Signal.like(self.coarse_ts) for i in range(parallelism)] - self.sync.rtio += [phases[i].eq(mul_3 + i*ftw) for i in range(parallelism)] - - resolution = 10 - steps = 2**resolution - from math import pi, cos - data = [(2**16 + round(cos(i/steps*2*pi)*((1 << 15) - 1))) & 0xffff - for i in range(steps)] - samples = [Signal(16) for i in range(4)] - for phase, sample in zip(phases, samples): - table = Memory(16, steps, init=data) - table_port = table.get_port(clock_domain="rtio") - self.specials += table, table_port - self.comb += [ - table_port.adr.eq(phase >> (len(self.coarse_ts) - resolution)), - sample.eq(table_port.dat_r) - ] - - self.sync.rtio += [sink.eq(Cat(samples)) - for sink in self.jesd.core.sink.flatten()] - - -class Satellite(SatelliteBase): - """ - DRTIO satellite with local DAC/SAWG channels, as well as TTL channels via FMC and VHDCI carrier. - """ - def __init__(self, jdcg_type, **kwargs): - SatelliteBase.__init__(self, 150e6, - identifier_suffix="." + jdcg_type, - **kwargs) - - platform = self.platform - - self.submodules += RTMUARTForward(platform) - - # RTM bitstream upload - slave_fpga_cfg = self.platform.request("rtm_fpga_cfg") - self.submodules.slave_fpga_cfg = gpio.GPIOTristate([ - slave_fpga_cfg.cclk, - slave_fpga_cfg.din, - slave_fpga_cfg.done, - slave_fpga_cfg.init_b, - slave_fpga_cfg.program_b, - ]) - self.csr_devices.append("slave_fpga_cfg") - self.config["SLAVE_FPGA_GATEWARE"] = 0x200000 - - self.rtio_channels = 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)) - mcx_io = platform.request("mcx_io", 0) - phy = ttl_serdes_ultrascale.InOut(4, mcx_io.level) - self.comb += mcx_io.direction.eq(phy.oe) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - mcx_io = platform.request("mcx_io", 1) - phy = ttl_serdes_ultrascale.InOut(4, mcx_io.level) - self.comb += mcx_io.direction.eq(phy.oe) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - self.submodules.jesd_crg = jesd204_tools.UltrascaleCRG( - platform, use_rtio_clock=True) - cls = { - "sawg": JDCGSAWG, - "pattern": JDCGPattern, - "syncdds": JDCGSyncDDS - }[jdcg_type] - self.submodules.jdcg_0 = cls(platform, self.crg, self.jesd_crg, 0) - self.submodules.jdcg_1 = cls(platform, self.crg, self.jesd_crg, 1) - self.csr_devices.append("jesd_crg") - self.csr_devices.append("jdcg_0") - self.csr_devices.append("jdcg_1") - self.config["HAS_JDCG"] = None - self.add_csr_group("jdcg", ["jdcg_0", "jdcg_1"]) - self.config["RTIO_FIRST_SAWG_CHANNEL"] = len(rtio_channels) - rtio_channels.extend(rtio.Channel.from_phy(phy) - for sawg in self.jdcg_0.sawgs + - self.jdcg_1.sawgs - for phy in sawg.phys) - - # FMC-VHDCI-EEM DIOs x 2 (all OUTPUTs) - platform.add_connectors(fmcdio_vhdci_eem.connectors) - output_4x = partial(ttl_serdes_ultrascale.Output, 4) - eem.DIO.add_std(self, 0, - output_4x, output_4x, - iostandard=lambda eem: IOStandard("LVDS")) - eem.DIO.add_std(self, 1, - output_4x, output_4x, - iostandard=lambda eem: IOStandard("LVDS")) - # FMC-DIO-32ch-LVDS-a Direction Control Pins (via shift register) as TTLs x 3 - platform.add_extension(fmcdio_vhdci_eem.io) - print("fmcdio_vhdci_eem.[CLK, SER, LATCH] starting at RTIO channel 0x{:06x}" - .format(len(rtio_channels))) - fmcdio_dirctl = platform.request("fmcdio_dirctl", 0) - fmcdio_dirctl_phys = [ - ttl_simple.Output(fmcdio_dirctl.clk), - ttl_simple.Output(fmcdio_dirctl.ser), - ttl_simple.Output(fmcdio_dirctl.latch) - ] - for phy in fmcdio_dirctl_phys: - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - workaround_us_lvds_tristate(platform) - - self.add_rtio(rtio_channels) - - self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( - platform.request("amc_fpga_sysref", 0), self.rtio_tsc.coarse_ts) - self.csr_devices.append("sysref_sampler") - self.jdcg_0.jesd.core.register_jref(self.sysref_sampler.jref) - self.jdcg_1.jesd.core.register_jref(self.sysref_sampler.jref) - if jdcg_type == "syncdds": - self.comb += [ - self.jdcg_0.coarse_ts.eq(self.rtio_tsc.coarse_ts), - self.jdcg_1.coarse_ts.eq(self.rtio_tsc.coarse_ts), - ] - - -class SimpleSatellite(SatelliteBase): - def __init__(self, **kwargs): - SatelliteBase.__init__(self, **kwargs) - - platform = self.platform - - self.submodules += RTMUARTForward(platform) - - 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)) - mcx_io = platform.request("mcx_io", 0) - phy = ttl_serdes_ultrascale.InOut(4, mcx_io.level) - self.comb += mcx_io.direction.eq(phy.oe) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - mcx_io = platform.request("mcx_io", 1) - phy = ttl_serdes_ultrascale.InOut(4, mcx_io.level) - self.comb += mcx_io.direction.eq(phy.oe) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - self.add_rtio(rtio_channels) - - -def main(): - parser = argparse.ArgumentParser( - description="Sayma AMC gateware and firmware builder") - builder_args(parser) - soc_sayma_amc_args(parser) - parser.set_defaults(output_dir="artiq_sayma") - parser.add_argument("-V", "--variant", default="satellite", - help="variant: satellite/simplesatellite " - "(default: %(default)s)") - parser.add_argument("--sfp", default=False, action="store_true", - help="use SFP port for DRTIO instead of uTCA backplane") - parser.add_argument("--rtm-csr-csv", - default=os.path.join("artiq_sayma", "rtm_gateware", "rtm_csr.csv"), - help="CSV file listing remote CSRs on RTM (default: %(default)s)") - parser.add_argument("--jdcg-type", - default="sawg", - help="Change type of signal generator. This is used exclusively for " - "development and debugging.") - parser.add_argument("--with-wrpll", default=False, action="store_true") - parser.add_argument("--gateware-identifier-str", default=None, - help="Override ROM identifier") - args = parser.parse_args() - - variant = args.variant.lower() - if variant == "satellite": - soc = Satellite( - with_sfp=args.sfp, - jdcg_type=args.jdcg_type, - with_wrpll=args.with_wrpll, - gateware_identifier_str=args.gateware_identifier_str, - **soc_sayma_amc_argdict(args)) - elif variant == "simplesatellite": - soc = SimpleSatellite( - with_sfp=args.sfp, - with_wrpll=args.with_wrpll, - gateware_identifier_str=args.gateware_identifier_str, - **soc_sayma_amc_argdict(args)) - else: - raise SystemExit("Invalid variant (-V/--variant)") - - build_artiq_soc(soc, builder_argdict(args)) - - -if __name__ == "__main__": - main() diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py deleted file mode 100755 index 9d8a818b4..000000000 --- a/artiq/gateware/targets/sayma_rtm.py +++ /dev/null @@ -1,280 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import os -import subprocess -import struct - -from migen import * -from migen.genlib.cdc import MultiReg - -from misoc.interconnect.csr import * -from misoc.cores import gpio -from misoc.cores import spi2 -from misoc.cores.a7_gtp import * -from misoc.targets.sayma_rtm import BaseSoC, soc_sayma_rtm_args, soc_sayma_rtm_argdict -from misoc.integration.builder import Builder, builder_args, builder_argdict - -from artiq.gateware import rtio -from artiq.gateware import jesd204_tools -from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series -from artiq.gateware.rtio.xilinx_clocking import RTIOClockMultiplier, fix_serdes_timing_path -from artiq.gateware.drtio.transceiver import gtp_7series -from artiq.gateware.drtio.siphaser import SiPhaser7Series -from artiq.gateware.drtio.wrpll import WRPLL, DDMTDSamplerGTP -from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer -from artiq.gateware.drtio import * -from artiq.build_soc import add_identifier -from artiq import __artiq_dir__ as artiq_dir - - -class _SatelliteBase(BaseSoC): - mem_map = { - "drtioaux": 0x50000000, - } - mem_map.update(BaseSoC.mem_map) - - def __init__(self, rtio_clk_freq, *, with_wrpll, gateware_identifier_str, **kwargs): - BaseSoC.__init__(self, - cpu_type="vexriscv", - cpu_bus_width=64, - **kwargs) - add_identifier(self, gateware_identifier_str=gateware_identifier_str) - self.rtio_clk_freq = rtio_clk_freq - - platform = self.platform - - disable_cdrclkc_ibuf = Signal(reset=1) - disable_cdrclkc_ibuf.attr.add("no_retiming") - cdrclkc_clkout = platform.request("cdr_clk_clean") - cdrclkc_clkout_buf = Signal() - self.specials += Instance("IBUFDS_GTE2", - i_CEB=disable_cdrclkc_ibuf, - i_I=cdrclkc_clkout.p, i_IB=cdrclkc_clkout.n, - o_O=cdrclkc_clkout_buf) - qpll_drtio_settings = QPLLSettings( - refclksel=0b001, - fbdiv=4, - fbdiv_45=5, - refclk_div=1) - qpll = QPLL(cdrclkc_clkout_buf, qpll_drtio_settings) - self.submodules += qpll - - self.submodules.drtio_transceiver = gtp_7series.GTP( - qpll_channel=qpll.channels[0], - data_pads=[platform.request("rtm_amc_link", 0)], - sys_clk_freq=self.clk_freq, - rtio_clk_freq=rtio_clk_freq) - self.csr_devices.append("drtio_transceiver") - self.sync += disable_cdrclkc_ibuf.eq( - ~self.drtio_transceiver.stable_clkin.storage) - - self.submodules.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) - - cdr = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) - - self.submodules.rx_synchronizer = cdr(XilinxRXSynchronizer()) - core = cdr(DRTIOSatellite( - self.rtio_tsc, self.drtio_transceiver.channels[0], - self.rx_synchronizer)) - self.submodules.drtiosat = core - self.csr_devices.append("drtiosat") - - coreaux = cdr(DRTIOAuxController(core.link_layer, self.cpu_dw)) - self.submodules.drtioaux0 = coreaux - self.csr_devices.append("drtioaux0") - - memory_address = self.mem_map["drtioaux"] - self.add_wb_slave(memory_address, 0x800, - coreaux.bus) - self.add_memory_region("drtioaux0_mem", memory_address | self.shadow_base, 0x800) - - self.config["HAS_DRTIO"] = None - self.add_csr_group("drtioaux", ["drtioaux0"]) - self.add_memory_group("drtioaux_mem", ["drtioaux0_mem"]) - - gtp = self.drtio_transceiver.gtps[0] - rtio_clk_period = 1e9/rtio_clk_freq - self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - if with_wrpll: - self.comb += [ - platform.request("filtered_clk_sel").eq(0), - platform.request("ddmtd_main_dcxo_oe").eq(1), - platform.request("ddmtd_helper_dcxo_oe").eq(1) - ] - self.submodules.wrpll_sampler = DDMTDSamplerGTP( - self.drtio_transceiver, - platform.request("cdr_clk_clean_fabric")) - self.submodules.wrpll = WRPLL( - helper_clk_pads=platform.request("ddmtd_helper_clk"), - main_dcxo_i2c=platform.request("ddmtd_main_dcxo_i2c"), - helper_dxco_i2c=platform.request("ddmtd_helper_dcxo_i2c"), - ddmtd_inputs=self.wrpll_sampler) - self.csr_devices.append("wrpll") - platform.add_period_constraint(self.wrpll.cd_helper.clk, rtio_clk_period*0.99) - platform.add_false_path_constraints(self.crg.cd_sys.clk, self.wrpll.cd_helper.clk) - platform.add_false_path_constraints(self.wrpll.cd_helper.clk, gtp.rxoutclk) - else: - self.comb += platform.request("filtered_clk_sel").eq(1) - self.submodules.siphaser = SiPhaser7Series( - si5324_clkin=platform.request("si5324_clkin"), - rx_synchronizer=self.rx_synchronizer, - ref_clk=self.crg.cd_sys.clk, ref_div2=True, - rtio_clk_freq=rtio_clk_freq) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) - self.csr_devices.append("siphaser") - 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 - - platform.add_period_constraint(gtp.txoutclk, rtio_clk_period) - platform.add_period_constraint(gtp.rxoutclk, rtio_clk_period) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, - gtp.txoutclk, gtp.rxoutclk) - - self.submodules.rtio_crg = RTIOClockMultiplier(rtio_clk_freq) - self.csr_devices.append("rtio_crg") - fix_serdes_timing_path(platform) - - def add_rtio(self, rtio_channels): - self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) - self.csr_devices.append("rtio_moninj") - - self.submodules.local_io = SyncRTIO(self.rtio_tsc, rtio_channels) - self.comb += self.drtiosat.async_errors.eq(self.local_io.async_errors) - self.comb += self.drtiosat.cri.connect(self.local_io.cri) - - -class Satellite(_SatelliteBase): - def __init__(self, **kwargs): - _SatelliteBase.__init__(self, **kwargs) - - platform = self.platform - - rtio_channels = [] - for bm in range(2): - print("BaseMod{} RF switches starting at RTIO channel 0x{:06x}" - .format(bm, len(rtio_channels))) - for i in range(4): - phy = ttl_serdes_7series.Output_8X(platform.request("basemod{}_rfsw".format(bm), i), - invert=True) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - print("BaseMod{} attenuator starting at RTIO channel 0x{:06x}" - .format(bm, len(rtio_channels))) - basemod_att = platform.request("basemod{}_att".format(bm)) - for name in "rst_n clk le".split(): - signal = getattr(basemod_att, name) - for i in range(len(signal)): - phy = ttl_simple.Output(signal[i]) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - phy = ttl_simple.Output(basemod_att.mosi[0]) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - for i in range(3): - self.comb += basemod_att.mosi[i+1].eq(basemod_att.miso[i]) - phy = ttl_simple.InOut(basemod_att.miso[3]) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - self.add_rtio(rtio_channels) - - self.comb += platform.request("clk_src_ext_sel").eq(0) - - # HMC clock chip and DAC control - self.comb += [ - platform.request("ad9154_rst_n", 0).eq(1), - platform.request("ad9154_rst_n", 1).eq(1) - ] - self.submodules.converter_spi = spi2.SPIMaster(spi2.SPIInterface( - platform.request("hmc_spi"), - platform.request("ad9154_spi", 0), - platform.request("ad9154_spi", 1))) - self.csr_devices.append("converter_spi") - self.submodules.hmc7043_reset = gpio.GPIOOut( - platform.request("hmc7043_reset"), reset_out=1) - self.csr_devices.append("hmc7043_reset") - self.submodules.hmc7043_gpo = gpio.GPIOIn( - platform.request("hmc7043_gpo")) - self.csr_devices.append("hmc7043_gpo") - self.config["HAS_HMC830_7043"] = None - self.config["HAS_AD9154"] = None - self.config["AD9154_COUNT"] = 2 - self.config["CONVERTER_SPI_HMC830_CS"] = 0 - self.config["CONVERTER_SPI_HMC7043_CS"] = 1 - self.config["CONVERTER_SPI_FIRST_AD9154_CS"] = 2 - self.config["HMC830_REF"] = str(int(self.rtio_clk_freq/1e6)) - - # HMC workarounds - self.comb += platform.request("hmc830_pwr_en").eq(1) - self.submodules.hmc7043_out_en = gpio.GPIOOut( - platform.request("hmc7043_out_en")) - self.csr_devices.append("hmc7043_out_en") - - # DDMTD - sysref_pads = platform.request("rtm_fpga_sysref", 0) - self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(sysref_pads, self.rtio_clk_freq) - self.csr_devices.append("sysref_ddmtd") - platform.add_false_path_constraints( - self.sysref_ddmtd.cd_helper.clk, self.drtio_transceiver.gtps[0].txoutclk) - platform.add_false_path_constraints( - self.sysref_ddmtd.cd_helper.clk, self.crg.cd_sys.clk) - - -class SatmanSoCBuilder(Builder): - def __init__(self, *args, **kwargs): - Builder.__init__(self, *args, **kwargs) - firmware_dir = os.path.join(artiq_dir, "firmware") - self.software_packages = [] - self.add_software_package("satman", os.path.join(firmware_dir, "satman")) - - def initialize_memory(self): - satman = os.path.join(self.output_dir, "software", "satman", - "satman.bin") - with open(satman, "rb") as boot_file: - boot_data = [] - unpack_endian = " l1: - lim = l1 - clip = 2 - with self.subTest(i0=i0, i1=i1): - self.assertEqual(lim, o) - self.assertEqual(clip, c) - yield - - mg.run_simulation(self.dut, (gen(), rec())) - - def test_inst(self): - pass - - def test_run(self): - self._sweep() - - def test_limits(self): - for l0 in -8, 0, 1, 7: - for l1 in -8, 0, 1, 7: - self.setUp() - self.dut.l0.reset = l0 - self.dut.l1.reset = l1 - with self.subTest(l0=l0, l1=l1): - self._sweep() diff --git a/artiq/gateware/test/dsp/test_sawg.py b/artiq/gateware/test/dsp/test_sawg.py deleted file mode 100644 index fd392607d..000000000 --- a/artiq/gateware/test/dsp/test_sawg.py +++ /dev/null @@ -1,36 +0,0 @@ -import numpy as np - -from migen import * -from migen.fhdl.verilog import convert - -from artiq.gateware.dsp import sawg -from artiq.gateware.test.dsp.tools import xfer - - -def _test_gen_dds(dut, o): - yield from xfer(dut, - a=dict(a0=10), - p=dict(a0=0), - f=dict(a0=1), - ) - for i in range(256//dut.parallelism): - yield - o.append((yield from [(yield _) for _ in dut.xo])) - - -def _test_channel(): - widths = sawg._Widths(t=8, a=4*8, p=8, f=16) - orders = sawg._Orders(a=4, p=1, f=2) - dut = sawg.SplineParallelDDS(widths, orders, parallelism=2) - - if False: - print(convert(dut)) - else: - o = [] - run_simulation(dut, _test_gen_dds(dut, o), vcd_name="dds.vcd") - o = np.array(o) - print(o[:, :]) - - -if __name__ == "__main__": - _test_channel() diff --git a/artiq/gateware/test/dsp/test_sawg_fe.py b/artiq/gateware/test/dsp/test_sawg_fe.py deleted file mode 100644 index 1f7cdc08c..000000000 --- a/artiq/gateware/test/dsp/test_sawg_fe.py +++ /dev/null @@ -1,255 +0,0 @@ -import unittest - -import migen as mg -from numpy import int32 - -from artiq.coredevice import sawg, spline -from artiq.language import (at_mu, now_mu, delay, - core as core_language) -from artiq.gateware.rtio.phy.sawg import Channel -from artiq.sim import devices as sim_devices, time as sim_time - - -class RTIOManager: - def __init__(self): - self.outputs = [] - - def rtio_output(self, target, data): - channel = target >> 8 - addr = target & 0xff - self.outputs.append((now_mu(), channel, addr, data)) - - def rtio_output_wide(self, *args, **kwargs): - self.rtio_output(*args, **kwargs) - - def delay_mu(self, t): - delay(t) - - def patch(self, mod): - assert not hasattr(mod, "_saved") - mod._saved = {} - for name in "rtio_output rtio_output_wide delay_mu".split(): - mod._saved[name] = getattr(mod, name, None) - setattr(mod, name, getattr(self, name)) - - def unpatch(self, mod): - mod.__dict__.update(mod._saved) - del mod._saved - - -class SAWGTest(unittest.TestCase): - def setUp(self): - core_language.set_time_manager(sim_time.Manager()) - self.rtio_manager = RTIOManager() - self.rtio_manager.patch(spline) - self.rtio_manager.patch(sawg) - self.core = sim_devices.Core({}) - self.core.coarse_ref_period = 20/3 - self.core.ref_multiplier = 1 - self.t = self.core.coarse_ref_period - self.channel = mg.ClockDomainsRenamer({"rio_phy": "sys"})( - Channel(width=16, parallelism=2)) - self.driver = sawg.SAWG({"core": self.core}, channel_base=0, - parallelism=self.channel.parallelism) - - def tearDown(self): - self.rtio_manager.unpatch(spline) - self.rtio_manager.unpatch(sawg) - - def test_instantiate(self): - pass - - def test_make_events(self): - d = self.driver - d.offset.set(.9) - delay(2*self.t) - d.frequency0.set(.1) - d.frequency1.set(.1) - delay(2*self.t) - d.offset.set(0) - v = int(round((1 << 48) * .1 * self.t)) - self.assertEqual( - self.rtio_manager.outputs, [ - (0., 1, 0, int(round(self.driver.offset.scale*.9))), - (2.*self.t, 8, 0, int(round( - (1 << self.driver.frequency0.width) * - self.t/self.channel.parallelism*.1))), - (2.*self.t, 3, 0, [int32(v), int32(v >> 32)]), - (4.*self.t, 1, 0, 0), - ]) - - def run_channel(self, events): - def gen(dut, events): - c = 0 - for time, channel, address, data in events: - time //= self.t - assert c <= time - while c < time: - yield - c += 1 - for phy in dut.phys: - yield phy.rtlink.o.stb.eq(0) - rt = dut.phys[channel].rtlink.o - if isinstance(data, list): - data = sum(int(d) << (i*32) for i, d in enumerate(data)) - yield rt.data.eq(int(data)) - if hasattr(rt, "address"): - yield rt.address.eq(address) - yield rt.stb.eq(1) - assert not (yield rt.busy) - # print("{}: set ch {} to {}".format(time, channel, hex(data))) - - def log(dut, data, n): - for i in range(n + dut.latency): - yield - data.append((yield from [(yield _) for _ in dut.o])) - - data = [] - # print(int(events[-1][0]) + 1) - mg.run_simulation(self.channel, [ - gen(self.channel, events), - log(self.channel, data, int(events[-1][0]//self.t) + 1)], - vcd_name="dds.vcd") - return data - - def test_run_channel(self): - self.test_make_events() - self.run_channel(self.rtio_manager.outputs) - - def test_coeff(self): - import struct - # these get discrete_compensate - # [.1, .01, -.00001], [.1, .01, .00001, -.000000001] - for v in [-.1], [.1, -.01]: - ch = self.driver.offset - p = ch.coeff_as_packed(v) - t = ch.time_width - w = ch.width - p = [_ & 0xffffffff for _ in p] - p0 = [int(round(vi*ch.scale*ch.time_scale**i)) - for i, vi in enumerate(v)] - p0 = [struct.pack("<" + "_bhiiqqqq"[(w + i*t)//8], vi - )[:(w + i*t)//8] - for i, vi in enumerate(p0)] - p0 = b"".join(p0) - if len(p0) % 4: - p0 += b"\x00"*(4 - len(p0) % 4) - p0 = list(struct.unpack("<" + "I"*((len(p0) + 3)//4), p0)) - with self.subTest(v): - self.assertEqual(p, p0) - - def test_linear(self): - d = self.driver - d.offset.set_coeff_mu([100, 10]) - delay(10*self.t) - d.offset.set_coeff([0]) - delay(1*self.t) - out = self.run_channel(self.rtio_manager.outputs) - out = out[self.channel.latency + self.channel.u.latency:][:11] - for i in range(len(out) - 1): - with self.subTest(i): - v = 100 + i*10 - self.assertEqual(out[i], [v, v]) - self.assertEqual(out[-1], [0, 0]) - - def test_pack(self): - ch = self.driver.offset - self.assertEqual(ch.coeff_as_packed_mu([1]), [1]) - self.assertEqual(ch.coeff_as_packed_mu([1, 1 << 16]), [1, 1]) - self.assertEqual(ch.coeff_as_packed_mu([1, 1 << 32]), [1, 0]) - self.assertEqual(ch.coeff_as_packed_mu([0x1234, 0xa5a5a5a5]), - [0xa5a51234, 0xa5a5]) - self.assertEqual(ch.coeff_as_packed_mu([1, 2, 3, 4]), - [0x20001, 0x30000, 0, 4, 0]) - self.assertEqual(ch.coeff_as_packed_mu([-1, -2, -3, -4]), - [0xfffeffff, 0xfffdffff, -1, -4, -1]) - self.assertEqual(ch.coeff_as_packed_mu([0, -1, 0, -1]), - [0xffff0000, 0x0000ffff, 0, -1, -1]) - - def test_smooth_linear(self): - ch = self.driver.offset - ch.smooth(.1, .2, 13*self.t, 1) - ch.set(.2) - delay(1*self.t) - out = self.run_channel(self.rtio_manager.outputs) - out = out[self.channel.latency + self.channel.u.latency:][:14] - a = int(round(.1*ch.scale)) - da = int(round(.1*ch.scale*(1 << ch.width)//13)) - for i in range(len(out) - 1): - with self.subTest(i): - v = a + (i*da >> ch.width) - self.assertEqual(out[i], [v, v]) - a = int(round(.2*ch.scale)) - self.assertEqual(out[-1], [a, a]) - - def test_smooth_cubic(self): - ch = self.driver.offset - ch.smooth(.1, .2, 13*self.t, 3) - ch.set(.2) - delay(1*self.t) - out = self.run_channel(self.rtio_manager.outputs) - out = out[self.channel.latency + self.channel.u.latency:][:14] - if False: - import matplotlib.pyplot as plt - plt.plot(sum(out, [])) - plt.show() - - @unittest.skip("needs artiq.sim.time.TimeManager tweak for " - "reverse timeline jumps") - def test_demo_2tone(self): - MHz = 1e-3 - ns = 1. - self.sawg0 = self.driver - - t_up = t_hold = t_down = 400*ns - a1 = .3 - a2 = .4 - order = 3 - - self.sawg0.frequency0.set(10*MHz) - self.sawg0.phase0.set(0.) - self.sawg0.frequency1.set(1*MHz) - self.sawg0.phase1.set(0.) - self.sawg0.frequency2.set(13*MHz) - self.sawg0.phase2.set(0.) - t = now_mu() - self.sawg0.amplitude1.smooth(.0, a1, t_up, order) - at_mu(t) - self.sawg0.amplitude2.smooth(.0, a2, t_up, order) - self.sawg0.amplitude1.set(a1) - self.sawg0.amplitude2.set(a2) - delay(t_hold) - t = now_mu() - self.sawg0.amplitude1.smooth(a1, .0, t_down, order) - at_mu(t) - self.sawg0.amplitude2.smooth(a2, .0, t_down, order) - self.sawg0.amplitude1.set(.0) - self.sawg0.amplitude2.set(.0) - - out = self.run_channel(self.rtio_manager.outputs) - out = sum(out, []) - if True: - import matplotlib.pyplot as plt - plt.plot(out) - plt.show() - - def test_fir_overflow(self): - MHz = 1e-3 - ns = 1. - f1 = self.driver.frequency1 - a1 = self.driver.amplitude1 - p1 = self.driver.phase1 - cfg = self.driver.config - f1.set(1*MHz) - a1.set(.99) - delay(100*ns) - p1.set(.5) - delay(100*ns) - a1.set(0) - - out = self.run_channel(self.rtio_manager.outputs) - out = sum(out, []) - if False: - import matplotlib.pyplot as plt - plt.plot(out) - plt.show() diff --git a/artiq/gateware/test/dsp/test_sawg_phy.py b/artiq/gateware/test/dsp/test_sawg_phy.py deleted file mode 100644 index 35666a5f6..000000000 --- a/artiq/gateware/test/dsp/test_sawg_phy.py +++ /dev/null @@ -1,70 +0,0 @@ -import numpy as np -from operator import or_ - -from migen import * -from migen.fhdl.verilog import convert - -from artiq.gateware.rtio.phy.sawg import Channel -from .tools import rtio_xfer - - -def pack_tri(port, *v): - r = 0 - w = 0 - for vi, p in zip(v, port.payload.flatten()): - w += len(p) - r |= int(vi*(1 << w)) - return r - - -def gen_rtio(dut): - yield - yield from rtio_xfer( - dut, - a1=pack_tri(dut.a1.a, .1), - f0=pack_tri(dut.b.f, .01234567), - f1=pack_tri(dut.a1.f, .01234567), - a2=pack_tri(dut.a1.a, .05), - f2=pack_tri(dut.a1.f, .00534567), - ) - - -def gen_log(dut, o, n): - for i in range(3 + dut.latency): - yield - for i in range(n): - yield - o.append((yield from [(yield _) for _ in dut.o])) - #o.append([(yield dut.a1.xo[0])]) - - -def _test_channel(): - width = 16 - - dut = ClockDomainsRenamer({"rio_phy": "sys"})( - Channel(width=width, parallelism=4) - ) - - if False: - print(convert(dut)) - return - - o = [] - run_simulation( - dut, - [gen_rtio(dut), gen_log(dut, o, 128)], - vcd_name="dds.vcd") - o = np.array(o)/(1 << (width - 1)) - o = o.ravel() - np.savez_compressed("dds.npz", o=o) - - import matplotlib.pyplot as plt - fig, ax = plt.subplots(2) - ax[0].step(np.arange(o.size), o) - ax[1].psd(o, 1 << 10, Fs=1, noverlap=1 << 9, scale_by_freq=False) - fig.savefig("dds.pdf") - plt.show() - - -if __name__ == "__main__": - _test_channel() diff --git a/artiq/gateware/test/dsp/test_spline.py b/artiq/gateware/test/dsp/test_spline.py deleted file mode 100644 index fe2d82c28..000000000 --- a/artiq/gateware/test/dsp/test_spline.py +++ /dev/null @@ -1,31 +0,0 @@ -import numpy as np - -from migen import * -from migen.fhdl.verilog import convert - -from artiq.gateware.dsp.spline import Spline -from .tools import xfer - - -def _test_gen_spline(dut, o): - yield dut.o.ack.eq(1) - yield from xfer(dut, i=dict(a0=0, a1=1, a2=2)) - for i in range(20): - yield - o.append((yield dut.o.a0)) - - -def _test_spline(): - dut = Spline(order=3, width=16, step=1) - - if False: - print(convert(dut)) - else: - o = [] - run_simulation(dut, _test_gen_spline(dut, o), vcd_name="spline.vcd") - o = np.array(o) - print(o) - - -if __name__ == "__main__": - _test_spline() diff --git a/artiq/gateware/test/dsp/tools.py b/artiq/gateware/test/dsp/tools.py deleted file mode 100644 index 8d22ad475..000000000 --- a/artiq/gateware/test/dsp/tools.py +++ /dev/null @@ -1,49 +0,0 @@ -def set_dict(e, **k): - for k, v in k.items(): - if isinstance(v, dict): - yield from set_dict(getattr(e, k), **v) - else: - yield getattr(e, k).eq(v) - - -def xfer(dut, **kw): - ep = [] - for e, v in kw.items(): - e = getattr(dut, e) - yield from set_dict(e, **v) - ep.append(e) - for e in ep: - yield e.stb.eq(1) - while ep: - yield - for e in ep[:]: - if hasattr(e, "busy") and (yield e.busy): - raise ValueError(e, "busy") - if not hasattr(e, "ack") or (yield e.ack): - yield e.stb.eq(0) - ep.remove(e) - - -def szip(*iters): - active = {it: None for it in iters} - while active: - for it in list(active): - while True: - try: - val = it.send(active[it]) - except StopIteration: - del active[it] - break - if val is None: - break - else: - active[it] = (yield val) - val = (yield None) - for it in active: - active[it] = val - - -def rtio_xfer(dut, **kwargs): - yield from szip(*( - xfer(dut.phys_named[k].rtlink, o={"data": v}) - for k, v in kwargs.items())) diff --git a/artiq/test/test_coefficients.py b/artiq/test/test_coefficients.py deleted file mode 100644 index 138e0a86a..000000000 --- a/artiq/test/test_coefficients.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright (C) 2014, 2015 Robert Jordens - -import unittest - -import numpy as np - -from artiq.wavesynth import coefficients, compute_samples - - -class TestSplineCoef(unittest.TestCase): - def setUp(self): - self.x = np.arange(5.) - self.y = np.sin(2*np.pi*self.x/5) + np.arange(2)[:, None] - self.s = coefficients.SplineSource(self.x, self.y, order=4) - - def test_get_segment(self): - return list(self.s.get_segment(start=1.5, stop=3.2, scale=.01)) - - def test_synth(self): - d = self.test_get_segment() - d[0]["trigger"] = True - return compute_samples.Synthesizer(self.y.shape[0], [d, d + d]) - - def drive(self, s): - y = [] - for f in 0, 1, None, 0: - if f is not None: - s.select(f) - y += s.trigger()[0] - return y - - def test_run(self): - return self.drive(self.test_synth()) - - def test_compare(self): - scale = 100 - d = list(self.s.get_segment(start=0, stop=4, scale=1/scale)) - d[0]["trigger"] = True - s = compute_samples.Synthesizer(self.y.shape[0], [d]) - s.select(0) - y = s.trigger()[0] - np.testing.assert_almost_equal(y[::scale], self.y[0, :-1]) - - @unittest.skip("manual/visual test") - def test_plot(self): - import matplotlib.pyplot as plt - y = self.test_run() - plt.step(np.arange(len(y)), y) - plt.show() diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index 175039862..38cf25e45 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -47,12 +47,6 @@ Digital I/O drivers .. automodule:: artiq.coredevice.edge_counter :members: -:mod:`artiq.coredevice.shiftreg` module -+++++++++++++++++++++++++++++++++++++++ - -.. automodule:: artiq.coredevice.shiftreg - :members: - :mod:`artiq.coredevice.spi2` module +++++++++++++++++++++++++++++++++++ @@ -104,25 +98,6 @@ RF generation drivers .. automodule:: artiq.coredevice.adf5356 :members: -:mod:`artiq.coredevice.spline` module -+++++++++++++++++++++++++++++++++++++ - -.. automodule:: artiq.coredevice.spline - :members: - -:mod:`artiq.coredevice.sawg` module -+++++++++++++++++++++++++++++++++++ - -.. automodule:: artiq.coredevice.sawg - :members: - - -:mod:`artiq.coredevice.basemod_att` module -++++++++++++++++++++++++++++++++++++++++++ - -.. automodule:: artiq.coredevice.basemod_att - :members: - :mod:`artiq.coredevice.phaser` module +++++++++++++++++++++++++++++++++++++ diff --git a/doc/manual/utilities.rst b/doc/manual/utilities.rst index d66d91342..11745dc34 100644 --- a/doc/manual/utilities.rst +++ b/doc/manual/utilities.rst @@ -128,9 +128,6 @@ Core device RTIO analyzer tool :ref: artiq.frontend.artiq_coreanalyzer.get_argparser :prog: artiq_coreanalyzer -.. note:: - The RTIO analyzer does not support SAWG. - .. _routing-table-tool: DRTIO routing table manipulation tool diff --git a/flake.nix b/flake.nix index 4c5178a83..e10d005b3 100644 --- a/flake.nix +++ b/flake.nix @@ -182,18 +182,6 @@ propagatedBuildInputs = with pkgs.python3Packages; [ jinja2 numpy migen pyserial asyncserial ]; }; - jesd204b = pkgs.python3Packages.buildPythonPackage rec { - pname = "jesd204b"; - version = "unstable-2021-05-05"; - src = pkgs.fetchFromGitHub { - owner = "m-labs"; - repo = "jesd204b"; - rev = "bf1cd9014c8b7a9db67609f653634daaf3bcd39b"; - sha256 = "sha256-wyYOCRIPANReeCl+KaIpiAStsn2mzfMlK+cSrUzVrAw="; - }; - propagatedBuildInputs = with pkgs.python3Packages; [ migen misoc ]; - }; - microscope = pkgs.python3Packages.buildPythonPackage rec { pname = "microscope"; version = "unstable-2020-12-28"; @@ -404,7 +392,7 @@ devShell.x86_64-linux = pkgs.mkShell { name = "artiq-dev-shell"; buildInputs = [ - (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ migen misoc jesd204b artiq ps.paramiko ps.jsonschema microscope ])) + (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ migen misoc artiq ps.paramiko ps.jsonschema microscope ])) rustPlatform.rust.rustc rustPlatform.rust.cargo cargo-xbuild From 668997a4510242f1f3a7b44762fd509dab06b65c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 6 Jan 2023 17:49:13 +0800 Subject: [PATCH 53/85] flake: update dependencies --- flake.lock | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/flake.lock b/flake.lock index d138f372c..0c8bcd6d0 100644 --- a/flake.lock +++ b/flake.lock @@ -42,11 +42,11 @@ "mozilla-overlay": { "flake": false, "locked": { - "lastModified": 1664789696, - "narHash": "sha256-UGWJHQShiwLCr4/DysMVFrYdYYHcOqAOVsWNUu+l6YU=", + "lastModified": 1672878308, + "narHash": "sha256-0+fl6PHokhtSV+w58z2QD2rTf8QhcOGsT9o4LwHHZHE=", "owner": "mozilla", "repo": "nixpkgs-mozilla", - "rev": "80627b282705101e7b38e19ca6e8df105031b072", + "rev": "d38863db88e100866b3e494a651ee4962b762fcc", "type": "github" }, "original": { @@ -57,11 +57,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1666056570, - "narHash": "sha256-e7EkIY68Tp7NKyp9JSHh6CgPPdsKYYWxiL4wZQN8Cwg=", + "lastModified": 1672580127, + "narHash": "sha256-3lW3xZslREhJogoOkjeZtlBtvFMyxHku7I/9IVehhT8=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "47edaa313fc3767ce3026037a5b62352f22f3602", + "rev": "0874168639713f547c05947c76124f78441ea46c", "type": "github" }, "original": { @@ -89,11 +89,11 @@ ] }, "locked": { - "lastModified": 1664319253, - "narHash": "sha256-hycJAgy+NFF9f5I6++7yo8KdhMSyKCPKJazRPxeedI4=", + "lastModified": 1669369686, + "narHash": "sha256-YHez+S3PTUgtuliUNB5WM+RXcj8RKLbHVRvOgELSkwU=", "owner": "m-labs", "repo": "sipyco", - "rev": "d58ded7280e0f020be2446d4fee70f4393e6045f", + "rev": "98db6eacb084c2c5280fb653bee3d313e3ca6df8", "type": "github" }, "original": { @@ -105,11 +105,11 @@ "src-migen": { "flake": false, "locked": { - "lastModified": 1662111470, - "narHash": "sha256-IPyhoFZLhY8d3jHB8jyvGdbey7V+X5eCzBZYSrJ18ec=", + "lastModified": 1671263827, + "narHash": "sha256-hqvzLivGwc/4qMoyiwzmIpHEfLmwX0AmkiS0kVQojg8=", "owner": "m-labs", "repo": "migen", - "rev": "639e66f4f453438e83d86dc13491b9403bbd8ec6", + "rev": "12eb563e89ffc4a5e046239171207c9476f8f665", "type": "github" }, "original": { @@ -121,11 +121,11 @@ "src-misoc": { "flake": false, "locked": { - "lastModified": 1665395741, - "narHash": "sha256-7ULMGBPPn5NxZX6rdxU5GheoSNBiJklHQEVf04jU9tI=", - "ref": "master", - "rev": "4fb0730db4c5de7e86f82fa3bd204e6c4608af85", - "revCount": 2427, + "lastModified": 1671158014, + "narHash": "sha256-50w0K2E2ympYrG1Tte/HVbsp4FS2U+yohqZByXTOo4I=", + "ref": "refs/heads/master", + "rev": "26f039f9f6931a20a04ccd0f0a5402f67f553916", + "revCount": 2436, "submodules": true, "type": "git", "url": "https://github.com/m-labs/misoc.git" From cf2a4972f742c87d300305e1a75c08e97e6568a4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 6 Jan 2023 17:53:11 +0800 Subject: [PATCH 54/85] remove WRPLL --- artiq/firmware/libboard_artiq/lib.rs | 2 - artiq/firmware/libboard_artiq/wrpll.rs | 536 --------------------- artiq/firmware/satman/main.rs | 21 - artiq/gateware/drtio/wrpll/__init__.py | 2 - artiq/gateware/drtio/wrpll/core.py | 156 ------- artiq/gateware/drtio/wrpll/ddmtd.py | 221 --------- artiq/gateware/drtio/wrpll/filters.py | 61 --- artiq/gateware/drtio/wrpll/si549.py | 340 -------------- artiq/gateware/drtio/wrpll/thls.py | 618 ------------------------- artiq/gateware/targets/kasli.py | 50 +- artiq/gateware/test/wrpll/__init__.py | 0 artiq/gateware/test/wrpll/test_dsp.py | 158 ------- artiq/gateware/test/wrpll/test_thls.py | 55 --- doc/wrpll_diagram.png | Bin 58653 -> 0 bytes 14 files changed, 13 insertions(+), 2207 deletions(-) delete mode 100644 artiq/firmware/libboard_artiq/wrpll.rs delete mode 100644 artiq/gateware/drtio/wrpll/__init__.py delete mode 100644 artiq/gateware/drtio/wrpll/core.py delete mode 100644 artiq/gateware/drtio/wrpll/ddmtd.py delete mode 100644 artiq/gateware/drtio/wrpll/filters.py delete mode 100644 artiq/gateware/drtio/wrpll/si549.py delete mode 100644 artiq/gateware/drtio/wrpll/thls.py delete mode 100644 artiq/gateware/test/wrpll/__init__.py delete mode 100644 artiq/gateware/test/wrpll/test_dsp.py delete mode 100644 artiq/gateware/test/wrpll/test_thls.py delete mode 100644 doc/wrpll_diagram.png diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 7436fc8c5..209da3048 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -22,8 +22,6 @@ pub mod rpc_queue; #[cfg(has_si5324)] pub mod si5324; -#[cfg(has_wrpll)] -pub mod wrpll; #[cfg(has_grabber)] pub mod grabber; diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs deleted file mode 100644 index a9c9a702f..000000000 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ /dev/null @@ -1,536 +0,0 @@ -use board_misoc::{csr, clock}; - -mod i2c { - use board_misoc::{csr, clock}; - - #[derive(Debug, Clone, Copy)] - pub enum Dcxo { - Main, - Helper - } - - fn half_period() { clock::spin_us(1) } - const SDA_MASK: u8 = 2; - const SCL_MASK: u8 = 1; - - fn sda_i(dcxo: Dcxo) -> bool { - let reg = match dcxo { - Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_in_read() }, - Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_in_read() }, - }; - reg & SDA_MASK != 0 - } - - fn sda_oe(dcxo: Dcxo, oe: bool) { - let reg = match dcxo { - Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_oe_read() }, - Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_oe_read() }, - }; - let reg = if oe { reg | SDA_MASK } else { reg & !SDA_MASK }; - match dcxo { - Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_oe_write(reg) }, - Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_oe_write(reg) } - } - } - - fn sda_o(dcxo: Dcxo, o: bool) { - let reg = match dcxo { - Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_out_read() }, - Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_out_read() }, - }; - let reg = if o { reg | SDA_MASK } else { reg & !SDA_MASK }; - match dcxo { - Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_out_write(reg) }, - Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_out_write(reg) } - } - } - - fn scl_oe(dcxo: Dcxo, oe: bool) { - let reg = match dcxo { - Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_oe_read() }, - Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_oe_read() }, - }; - let reg = if oe { reg | SCL_MASK } else { reg & !SCL_MASK }; - match dcxo { - Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_oe_write(reg) }, - Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_oe_write(reg) } - } - } - - fn scl_o(dcxo: Dcxo, o: bool) { - let reg = match dcxo { - Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_out_read() }, - Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_out_read() }, - }; - let reg = if o { reg | SCL_MASK } else { reg & !SCL_MASK }; - match dcxo { - Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_out_write(reg) }, - Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_out_write(reg) } - } - } - - pub fn init(dcxo: Dcxo) -> Result<(), &'static str> { - // Set SCL as output, and high level - scl_o(dcxo, true); - scl_oe(dcxo, true); - // Prepare a zero level on SDA so that sda_oe pulls it down - sda_o(dcxo, false); - // Release SDA - sda_oe(dcxo, false); - - // Check the I2C bus is ready - half_period(); - half_period(); - if !sda_i(dcxo) { - // Try toggling SCL a few times - for _bit in 0..8 { - scl_o(dcxo, false); - half_period(); - scl_o(dcxo, true); - half_period(); - } - } - - if !sda_i(dcxo) { - return Err("SDA is stuck low and doesn't get unstuck"); - } - Ok(()) - } - - pub fn start(dcxo: Dcxo) { - // Set SCL high then SDA low - scl_o(dcxo, true); - half_period(); - sda_oe(dcxo, true); - half_period(); - } - - pub fn stop(dcxo: Dcxo) { - // First, make sure SCL is low, so that the target releases the SDA line - scl_o(dcxo, false); - half_period(); - // Set SCL high then SDA high - sda_oe(dcxo, true); - scl_o(dcxo, true); - half_period(); - sda_oe(dcxo, false); - half_period(); - } - - pub fn write(dcxo: Dcxo, data: u8) -> bool { - // MSB first - for bit in (0..8).rev() { - // Set SCL low and set our bit on SDA - scl_o(dcxo, false); - sda_oe(dcxo, data & (1 << bit) == 0); - half_period(); - // Set SCL high ; data is shifted on the rising edge of SCL - scl_o(dcxo, true); - half_period(); - } - // Check ack - // Set SCL low, then release SDA so that the I2C target can respond - scl_o(dcxo, false); - half_period(); - sda_oe(dcxo, false); - // Set SCL high and check for ack - scl_o(dcxo, true); - half_period(); - // returns true if acked (I2C target pulled SDA low) - !sda_i(dcxo) - } - - pub fn read(dcxo: Dcxo, ack: bool) -> u8 { - // Set SCL low first, otherwise setting SDA as input may cause a transition - // on SDA with SCL high which will be interpreted as START/STOP condition. - scl_o(dcxo, false); - half_period(); // make sure SCL has settled low - sda_oe(dcxo, false); - - let mut data: u8 = 0; - - // MSB first - for bit in (0..8).rev() { - scl_o(dcxo, false); - half_period(); - // Set SCL high and shift data - scl_o(dcxo, true); - half_period(); - if sda_i(dcxo) { data |= 1 << bit } - } - // Send ack - // Set SCL low and pull SDA low when acking - scl_o(dcxo, false); - if ack { sda_oe(dcxo, true) } - half_period(); - // then set SCL high - scl_o(dcxo, true); - half_period(); - - data - } -} - -mod si549 { - use board_misoc::clock; - use super::i2c; - - #[cfg(soc_platform = "kasli")] - pub const ADDRESS: u8 = 0x67; - - pub fn write(dcxo: i2c::Dcxo, reg: u8, val: u8) -> Result<(), &'static str> { - i2c::start(dcxo); - if !i2c::write(dcxo, ADDRESS << 1) { - return Err("Si549 failed to ack write address") - } - if !i2c::write(dcxo, reg) { - return Err("Si549 failed to ack register") - } - if !i2c::write(dcxo, val) { - return Err("Si549 failed to ack value") - } - i2c::stop(dcxo); - Ok(()) - } - - pub fn write_no_ack_value(dcxo: i2c::Dcxo, reg: u8, val: u8) -> Result<(), &'static str> { - i2c::start(dcxo); - if !i2c::write(dcxo, ADDRESS << 1) { - return Err("Si549 failed to ack write address") - } - if !i2c::write(dcxo, reg) { - return Err("Si549 failed to ack register") - } - i2c::write(dcxo, val); - i2c::stop(dcxo); - Ok(()) - } - - pub fn read(dcxo: i2c::Dcxo, reg: u8) -> Result { - i2c::start(dcxo); - if !i2c::write(dcxo, ADDRESS << 1) { - return Err("Si549 failed to ack write address") - } - if !i2c::write(dcxo, reg) { - return Err("Si549 failed to ack register") - } - i2c::stop(dcxo); - - i2c::start(dcxo); - if !i2c::write(dcxo, (ADDRESS << 1) | 1) { - return Err("Si549 failed to ack read address") - } - let val = i2c::read(dcxo, false); - i2c::stop(dcxo); - - Ok(val) - } - - pub fn program(dcxo: i2c::Dcxo, hsdiv: u16, lsdiv: u8, fbdiv: u64) -> Result<(), &'static str> { - i2c::init(dcxo)?; - - write(dcxo, 255, 0x00)?; // PAGE - write_no_ack_value(dcxo, 7, 0x80)?; // RESET - clock::spin_us(100_000); // required? not specified in datasheet. - - write(dcxo, 255, 0x00)?; // PAGE - write(dcxo, 69, 0x00)?; // Disable FCAL override. - // Note: Value 0x00 from Table 5.6 is inconsistent with Table 5.7, - // which shows bit 0 as reserved and =1. - write(dcxo, 17, 0x00)?; // Synchronously disable output - - // The Si549 has no ID register, so we check that it responds correctly - // by writing values to a RAM-like register and reading them back. - for test_value in 0..255 { - write(dcxo, 23, test_value)?; - let readback = read(dcxo, 23)?; - if readback != test_value { - return Err("Si549 detection failed"); - } - } - - write(dcxo, 23, hsdiv as u8)?; - write(dcxo, 24, (hsdiv >> 8) as u8 | (lsdiv << 4))?; - write(dcxo, 26, fbdiv as u8)?; - write(dcxo, 27, (fbdiv >> 8) as u8)?; - write(dcxo, 28, (fbdiv >> 16) as u8)?; - write(dcxo, 29, (fbdiv >> 24) as u8)?; - write(dcxo, 30, (fbdiv >> 32) as u8)?; - write(dcxo, 31, (fbdiv >> 40) as u8)?; - - write(dcxo, 7, 0x08)?; // Start FCAL - write(dcxo, 17, 0x01)?; // Synchronously enable output - - Ok(()) - } - - // Si549 digital frequency trim ("all-digital PLL" register) - // ∆ f_out = adpll * 0.0001164e-6 (0.1164 ppb/lsb) - // max trim range is +- 950 ppm - pub fn set_adpll(dcxo: i2c::Dcxo, adpll: i32) -> Result<(), &'static str> { - write(dcxo, 231, adpll as u8)?; - write(dcxo, 232, (adpll >> 8) as u8)?; - write(dcxo, 233, (adpll >> 16) as u8)?; - clock::spin_us(100); - Ok(()) - } - - pub fn get_adpll(dcxo: i2c::Dcxo) -> Result { - let b1 = read(dcxo, 231)? as i32; - let b2 = read(dcxo, 232)? as i32; - let b3 = read(dcxo, 233)? as i8 as i32; - Ok(b3 << 16 | b2 << 8 | b1) - } -} - -// to do: load from gateware config -const DDMTD_COUNTER_N: u32 = 15; -const DDMTD_COUNTER_M: u32 = (1 << DDMTD_COUNTER_N); -const F_SYS: f64 = csr::CONFIG_CLOCK_FREQUENCY as f64; - -const F_MAIN: f64 = 125.0e6; -const F_HELPER: f64 = F_MAIN * DDMTD_COUNTER_M as f64 / (DDMTD_COUNTER_M + 1) as f64; -const F_BEAT: f64 = F_MAIN - F_HELPER; -const TIME_STEP: f32 = 1./F_BEAT as f32; - -fn ddmtd_tag_to_s(mu: f32) -> f32 { - return (mu as f32)*TIME_STEP; -} - -fn get_frequencies() -> (u32, u32, u32) { - unsafe { - csr::wrpll::frequency_counter_update_en_write(1); - // wait for at least one full update cycle (> 2 timer periods) - clock::spin_us(200_000); - csr::wrpll::frequency_counter_update_en_write(0); - let helper = csr::wrpll::frequency_counter_counter_helper_read(); - let main = csr::wrpll::frequency_counter_counter_rtio_read(); - let cdr = csr::wrpll::frequency_counter_counter_rtio_rx0_read(); - (helper, main, cdr) - } -} - -fn log_frequencies() -> (u32, u32, u32) { - let (f_helper, f_main, f_cdr) = get_frequencies(); - let conv_khz = |f| 4*(f as u64)*(csr::CONFIG_CLOCK_FREQUENCY as u64)/(1000*(1 << 23)); - info!("helper clock frequency: {}kHz ({})", conv_khz(f_helper), f_helper); - info!("main clock frequency: {}kHz ({})", conv_khz(f_main), f_main); - info!("CDR clock frequency: {}kHz ({})", conv_khz(f_cdr), f_cdr); - (f_helper, f_main, f_cdr) -} - -fn get_tags() -> (i32, i32, u16, u16) { - unsafe { - csr::wrpll::tag_arm_write(1); - while csr::wrpll::tag_arm_read() != 0 {} - - let main_diff = csr::wrpll::main_diff_tag_read() as i32; - let helper_diff = csr::wrpll::helper_diff_tag_read() as i32; - let ref_tag = csr::wrpll::ref_tag_read(); - let main_tag = csr::wrpll::main_tag_read(); - (main_diff, helper_diff, ref_tag, main_tag) - } -} - -fn print_tags() { - const NUM_TAGS: usize = 30; - let mut main_diffs = [0; NUM_TAGS]; // input to main loop filter - let mut helper_diffs = [0; NUM_TAGS]; // input to helper loop filter - let mut ref_tags = [0; NUM_TAGS]; - let mut main_tags = [0; NUM_TAGS]; - let mut jitter = [0 as f32; NUM_TAGS]; - - for i in 0..NUM_TAGS { - let (main_diff, helper_diff, ref_tag, main_tag) = get_tags(); - main_diffs[i] = main_diff; - helper_diffs[i] = helper_diff; - ref_tags[i] = ref_tag; - main_tags[i] = main_tag; - } - info!("DDMTD ref tags: {:?}", ref_tags); - info!("DDMTD main tags: {:?}", main_tags); - info!("DDMTD main diffs: {:?}", main_diffs); - info!("DDMTD helper diffs: {:?}", helper_diffs); - - // look at the difference between the main DCXO and reference... - let t0 = main_diffs[0]; - main_diffs.iter_mut().for_each(|x| *x -= t0); - - // crude estimate of the max difference across our sample set (assumes no unwrapping issues...) - let delta = main_diffs[main_diffs.len()-1] as f32 / (main_diffs.len()-1) as f32; - info!("detla: {:?} tags", delta); - let delta_f: f32 = delta/DDMTD_COUNTER_M as f32 * F_BEAT as f32; - info!("MAIN <-> ref frequency difference: {:?} Hz ({:?} ppm)", delta_f, delta_f/F_HELPER as f32 * 1e6); - - jitter.iter_mut().enumerate().for_each(|(i, x)| *x = main_diffs[i] as f32 - delta*(i as f32)); - info!("jitter: {:?} tags", jitter); - - let var = jitter.iter().map(|x| x*x).fold(0 as f32, |acc, x| acc + x as f32) / NUM_TAGS as f32; - info!("variance: {:?} tags^2", var); -} - -pub fn init() { - info!("initializing WR PLL..."); - - unsafe { csr::wrpll::helper_reset_write(1); } - - unsafe { - csr::wrpll::helper_dcxo_i2c_address_write(si549::ADDRESS); - csr::wrpll::main_dcxo_i2c_address_write(si549::ADDRESS); - } - - #[cfg(rtio_frequency = "125.0")] - let (h_hsdiv, h_lsdiv, h_fbdiv) = (0x05c, 0, 0x04b5badb98a); - #[cfg(rtio_frequency = "125.0")] - let (m_hsdiv, m_lsdiv, m_fbdiv) = (0x05c, 0, 0x04b5c447213); - - si549::program(i2c::Dcxo::Main, m_hsdiv, m_lsdiv, m_fbdiv) - .expect("cannot initialize main Si549"); - si549::program(i2c::Dcxo::Helper, h_hsdiv, h_lsdiv, h_fbdiv) - .expect("cannot initialize helper Si549"); - // Si549 Settling Time for Large Frequency Change. - // Datasheet said 10ms but it lied. - clock::spin_us(50_000); - - unsafe { csr::wrpll::helper_reset_write(0); } - clock::spin_us(1); -} - -pub fn diagnostics() { - info!("WRPLL diagnostics..."); - info!("Untrimmed oscillator frequencies:"); - log_frequencies(); - - info!("Increase helper DCXO frequency by +10ppm (1.25kHz):"); - si549::set_adpll(i2c::Dcxo::Helper, 85911).expect("ADPLL write failed"); - // to do: add check on frequency? - log_frequencies(); -} - -fn trim_dcxos(f_helper: u32, f_main: u32, f_cdr: u32) -> Result<(i32, i32), &'static str> { - info!("Trimming oscillator frequencies..."); - const DCXO_STEP: i64 = (1.0e6/0.0001164) as i64; - const ADPLL_MAX: i64 = (950.0/0.0001164) as i64; - - const TIMER_WIDTH: u32 = 23; - const COUNTER_DIV: u32 = 2; - - // how many counts we expect to measure - const SYS_COUNTS: i64 = (1 << (TIMER_WIDTH - COUNTER_DIV)) as i64; - const EXP_MAIN_COUNTS: i64 = ((SYS_COUNTS as f64) * (F_MAIN/F_SYS)) as i64; - const EXP_HELPER_COUNTS: i64 = ((SYS_COUNTS as f64) * (F_HELPER/F_SYS)) as i64; - - // calibrate the SYS clock to the CDR clock and correct the measured counts - // assume frequency errors are small so we can make an additive correction - // positive error means sys clock is too fast - let sys_err: i64 = EXP_MAIN_COUNTS - (f_cdr as i64); - let main_err: i64 = EXP_MAIN_COUNTS - (f_main as i64) - sys_err; - let helper_err: i64 = EXP_HELPER_COUNTS - (f_helper as i64) - sys_err; - - info!("sys count err {}", sys_err); - info!("main counts err {}", main_err); - info!("helper counts err {}", helper_err); - - // calculate required adjustment to the ADPLL register see - // https://www.silabs.com/documents/public/data-sheets/si549-datasheet.pdf - // section 5.6 - let helper_adpll: i64 = helper_err*DCXO_STEP/EXP_HELPER_COUNTS; - let main_adpll: i64 = main_err*DCXO_STEP/EXP_MAIN_COUNTS; - if helper_adpll.abs() > ADPLL_MAX { - return Err("helper DCXO offset too large"); - } - if main_adpll.abs() > ADPLL_MAX { - return Err("main DCXO offset too large"); - } - - info!("ADPLL offsets: helper={} main={}", helper_adpll, main_adpll); - Ok((helper_adpll as i32, main_adpll as i32)) -} - -fn statistics(data: &[u16]) -> (f32, f32) { - let sum = data.iter().fold(0 as u32, |acc, x| acc + *x as u32); - let mean = sum as f32 / data.len() as f32; - - let squared_sum = data.iter().fold(0 as u32, |acc, x| acc + (*x as u32).pow(2)); - let variance = (squared_sum as f32 / data.len() as f32) - mean; - return (mean, variance) -} - -fn select_recovered_clock_int(rc: bool) -> Result<(), &'static str> { - info!("Untrimmed oscillator frequencies:"); - let (f_helper, f_main, f_cdr) = log_frequencies(); - if rc { - let (helper_adpll, main_adpll) = trim_dcxos(f_helper, f_main, f_cdr)?; - // to do: add assertion on max frequency shift here? - si549::set_adpll(i2c::Dcxo::Helper, helper_adpll).expect("ADPLL write failed"); - si549::set_adpll(i2c::Dcxo::Main, main_adpll).expect("ADPLL write failed"); - - log_frequencies(); - clock::spin_us(100_000); // TO DO: remove/reduce! - print_tags(); - - info!("increasing main DCXO by 1ppm (125Hz):"); - si549::set_adpll(i2c::Dcxo::Main, main_adpll + 8591).expect("ADPLL write failed"); - clock::spin_us(100_000); - print_tags(); - - si549::set_adpll(i2c::Dcxo::Main, main_adpll).expect("ADPLL write failed"); - - unsafe { - csr::wrpll::adpll_offset_helper_write(helper_adpll as u32); - csr::wrpll::adpll_offset_main_write(main_adpll as u32); - csr::wrpll::helper_dcxo_gpio_enable_write(0); - csr::wrpll::main_dcxo_gpio_enable_write(0); - csr::wrpll::helper_dcxo_errors_write(0xff); - csr::wrpll::main_dcxo_errors_write(0xff); - csr::wrpll::collector_reset_write(0); - } - clock::spin_us(1_000); // wait for the collector to produce meaningful output - unsafe { - csr::wrpll::filter_reset_write(0); - } - - clock::spin_us(100_000); - - print_tags(); -// let mut tags = [0; 10]; -// for i in 0..tags.len() { -// tags[i] = get_ddmtd_helper_tag(); -// } -// info!("DDMTD helper tags: {:?}", tags); - - unsafe { - csr::wrpll::filter_reset_write(1); - csr::wrpll::collector_reset_write(1); - } - clock::spin_us(50_000); - unsafe { - csr::wrpll::helper_dcxo_gpio_enable_write(1); - csr::wrpll::main_dcxo_gpio_enable_write(1); - } - unsafe { - info!("error {} {}", - csr::wrpll::helper_dcxo_errors_read(), - csr::wrpll::main_dcxo_errors_read()); - } - info!("new ADPLL: {} {}", - si549::get_adpll(i2c::Dcxo::Helper)?, - si549::get_adpll(i2c::Dcxo::Main)?); - } else { - si549::set_adpll(i2c::Dcxo::Helper, 0).expect("ADPLL write failed"); - si549::set_adpll(i2c::Dcxo::Main, 0).expect("ADPLL write failed"); - } - Ok(()) -} - -pub fn select_recovered_clock(rc: bool) { - if rc { - info!("switching to recovered clock"); - } else { - info!("switching to local XO clock"); - } - match select_recovered_clock_int(rc) { - Ok(()) => info!("clock transition completed"), - Err(e) => error!("clock transition failed: {}", e) - } -} diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 7d69f7d0d..365131b7a 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -12,8 +12,6 @@ use core::convert::TryFrom; use board_misoc::{csr, ident, clock, uart_logger, i2c, pmp}; #[cfg(has_si5324)] use board_artiq::si5324; -#[cfg(has_wrpll)] -use board_artiq::wrpll; use board_artiq::{spi, drtioaux}; use board_artiq::drtio_routing; use riscv::register::{mcause, mepc, mtval}; @@ -420,8 +418,6 @@ fn sysclk_setup() { else { #[cfg(has_si5324)] si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324"); - #[cfg(has_wrpll)] - wrpll::init(); info!("Switching sys clock, rebooting..."); // delay for clean UART log, wait until UART FIFO is empty clock::spin_us(1300); @@ -460,17 +456,6 @@ pub extern fn main() -> i32 { io_expander1 = board_misoc::io_expander::IoExpander::new(1); io_expander0.init().expect("I2C I/O expander #0 initialization failed"); io_expander1.init().expect("I2C I/O expander #1 initialization failed"); - #[cfg(has_wrpll)] - { - io_expander0.set_oe(1, 1 << 7).unwrap(); - io_expander0.set(1, 7, true); - io_expander0.service().unwrap(); - io_expander1.set_oe(0, 1 << 7).unwrap(); - io_expander1.set_oe(1, 1 << 7).unwrap(); - io_expander1.set(0, 7, true); - io_expander1.set(1, 7, true); - io_expander1.service().unwrap(); - } // Actively drive TX_DISABLE to false on SFP0..3 io_expander0.set_oe(0, 1 << 1).unwrap(); @@ -490,8 +475,6 @@ pub extern fn main() -> i32 { unsafe { csr::drtio_transceiver::txenable_write(0xffffffffu32 as _); } - #[cfg(has_wrpll)] - wrpll::diagnostics(); init_rtio_crg(); @@ -527,8 +510,6 @@ pub extern fn main() -> i32 { si5324::siphaser::select_recovered_clock(true).expect("failed to switch clocks"); si5324::siphaser::calibrate_skew().expect("failed to calibrate skew"); } - #[cfg(has_wrpll)] - wrpll::select_recovered_clock(true); drtioaux::reset(0); drtiosat_reset(false); @@ -565,8 +546,6 @@ pub extern fn main() -> i32 { info!("uplink is down, switching to local oscillator clock"); #[cfg(has_si5324)] si5324::siphaser::select_recovered_clock(false).expect("failed to switch clocks"); - #[cfg(has_wrpll)] - wrpll::select_recovered_clock(false); } } diff --git a/artiq/gateware/drtio/wrpll/__init__.py b/artiq/gateware/drtio/wrpll/__init__.py deleted file mode 100644 index 25e510f4c..000000000 --- a/artiq/gateware/drtio/wrpll/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from artiq.gateware.drtio.wrpll.core import WRPLL -from artiq.gateware.drtio.wrpll.ddmtd import DDMTDSamplerExtFF, DDMTDSamplerGTP diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py deleted file mode 100644 index 3003d4848..000000000 --- a/artiq/gateware/drtio/wrpll/core.py +++ /dev/null @@ -1,156 +0,0 @@ -from migen import * -from migen.genlib.resetsync import AsyncResetSynchronizer -from migen.genlib.cdc import MultiReg, PulseSynchronizer -from misoc.interconnect.csr import * - -from artiq.gateware.drtio.wrpll.si549 import Si549 -from artiq.gateware.drtio.wrpll.ddmtd import DDMTD, Collector -from artiq.gateware.drtio.wrpll import thls, filters - - -class FrequencyCounter(Module, AutoCSR): - def __init__(self, timer_width=23, counter_width=23, domains=["helper", "sys", "rtio_rx0"]): - for domain in domains: - name = "counter_" + domain - counter = CSRStatus(counter_width, name=name) - setattr(self, name, counter) - self.update_en = CSRStorage() - - timer = Signal(timer_width) - timer_tick = Signal() - self.sync += Cat(timer, timer_tick).eq(timer + 1) - - for domain in domains: - sync_domain = getattr(self.sync, domain) - divider = Signal(2) - sync_domain += divider.eq(divider + 1) - - divided = Signal() - divided.attr.add("no_retiming") - sync_domain += divided.eq(divider[-1]) - divided_sys = Signal() - self.specials += MultiReg(divided, divided_sys) - - divided_sys_r = Signal() - divided_tick = Signal() - self.sync += divided_sys_r.eq(divided_sys) - self.comb += divided_tick.eq(divided_sys & ~divided_sys_r) - - counter = Signal(counter_width) - counter_csr = getattr(self, "counter_" + domain) - self.sync += [ - If(timer_tick, - If(self.update_en.storage, counter_csr.status.eq(counter)), - counter.eq(0), - ).Else( - If(divided_tick, counter.eq(counter + 1)) - ) - ] - - -class WRPLL(Module, AutoCSR): - def __init__(self, helper_clk_pads, main_dcxo_i2c, helper_dxco_i2c, ddmtd_inputs, N=15): - self.helper_reset = CSRStorage(reset=1) - self.collector_reset = CSRStorage(reset=1) - self.filter_reset = CSRStorage(reset=1) - self.adpll_offset_helper = CSRStorage(24) - self.adpll_offset_main = CSRStorage(24) - - self.tag_arm = CSR() - self.main_diff_tag = CSRStatus(32) - self.helper_diff_tag = CSRStatus(32) - self.ref_tag = CSRStatus(N) - self.main_tag = CSRStatus(N) - - main_diff_tag_32 = Signal((32, True)) - helper_diff_tag_32 = Signal((32, True)) - self.comb += [ - self.main_diff_tag.status.eq(main_diff_tag_32), - self.helper_diff_tag.status.eq(helper_diff_tag_32) - ] - - self.clock_domains.cd_helper = ClockDomain() - self.clock_domains.cd_collector = ClockDomain() - self.clock_domains.cd_filter = ClockDomain() - self.helper_reset.storage.attr.add("no_retiming") - self.filter_reset.storage.attr.add("no_retiming") - self.specials += Instance("IBUFGDS", - i_I=helper_clk_pads.p, i_IB=helper_clk_pads.n, - o_O=self.cd_helper.clk) - self.comb += [ - self.cd_collector.clk.eq(self.cd_collector.clk), - self.cd_filter.clk.eq(self.cd_helper.clk), - ] - self.specials += [ - AsyncResetSynchronizer(self.cd_helper, self.helper_reset.storage), - AsyncResetSynchronizer(self.cd_collector, self.collector_reset.storage), - AsyncResetSynchronizer(self.cd_filter, self.filter_reset.storage) - ] - - self.submodules.helper_dcxo = Si549(helper_dxco_i2c) - self.submodules.main_dcxo = Si549(main_dcxo_i2c) - - # for diagnostics and PLL initialization - self.submodules.frequency_counter = FrequencyCounter() - - ddmtd_counter = Signal(N) - self.sync.helper += ddmtd_counter.eq(ddmtd_counter + 1) - self.submodules.ddmtd_ref = DDMTD(ddmtd_counter, ddmtd_inputs.rec_clk) - self.submodules.ddmtd_main = DDMTD(ddmtd_counter, ddmtd_inputs.main_xo) - - collector_cd = ClockDomainsRenamer("collector") - filter_cd = ClockDomainsRenamer("filter") - self.submodules.collector = collector_cd(Collector(N)) - self.submodules.filter_helper = filter_cd( - thls.make(filters.helper, data_width=48)) - self.submodules.filter_main = filter_cd( - thls.make(filters.main, data_width=48)) - - self.comb += [ - self.collector.tag_ref.eq(self.ddmtd_ref.h_tag), - self.collector.ref_stb.eq(self.ddmtd_ref.h_tag_update), - self.collector.tag_main.eq(self.ddmtd_main.h_tag), - self.collector.main_stb.eq(self.ddmtd_main.h_tag_update) - ] - - collector_stb_ps = PulseSynchronizer("helper", "sys") - self.submodules += collector_stb_ps - self.sync.helper += collector_stb_ps.i.eq(self.collector.out_stb) - collector_stb_sys = Signal() - self.sync += collector_stb_sys.eq(collector_stb_ps.o) - - main_diff_tag_sys = Signal((N+2, True)) - helper_diff_tag_sys = Signal((N+2, True)) - ref_tag_sys = Signal(N) - main_tag_sys = Signal(N) - self.specials += MultiReg(self.collector.out_main, main_diff_tag_sys) - self.specials += MultiReg(self.collector.out_helper, helper_diff_tag_sys) - self.specials += MultiReg(self.collector.tag_ref, ref_tag_sys) - self.specials += MultiReg(self.collector.tag_main, main_tag_sys) - - self.sync += [ - If(self.tag_arm.re & self.tag_arm.r, self.tag_arm.w.eq(1)), - If(collector_stb_sys, - self.tag_arm.w.eq(0), - If(self.tag_arm.w, - main_diff_tag_32.eq(main_diff_tag_sys), - helper_diff_tag_32.eq(helper_diff_tag_sys), - self.ref_tag.status.eq(ref_tag_sys), - self.main_tag.status.eq(main_tag_sys) - ) - ) - ] - - self.comb += [ - self.filter_helper.input.eq(self.collector.out_helper << 22), - self.filter_helper.input_stb.eq(self.collector.out_stb), - self.filter_main.input.eq(self.collector.out_main), - self.filter_main.input_stb.eq(self.collector.out_stb) - ] - - self.sync.helper += [ - self.helper_dcxo.adpll_stb.eq(self.filter_helper.output_stb), - self.helper_dcxo.adpll.eq(self.filter_helper.output + self.adpll_offset_helper.storage), - self.main_dcxo.adpll_stb.eq(self.filter_main.output_stb), - self.main_dcxo.adpll.eq(self.filter_main.output + self.adpll_offset_main.storage) - ] diff --git a/artiq/gateware/drtio/wrpll/ddmtd.py b/artiq/gateware/drtio/wrpll/ddmtd.py deleted file mode 100644 index ddeeac54e..000000000 --- a/artiq/gateware/drtio/wrpll/ddmtd.py +++ /dev/null @@ -1,221 +0,0 @@ -from migen import * -from migen.genlib.cdc import PulseSynchronizer, MultiReg -from migen.genlib.fsm import FSM -from misoc.interconnect.csr import * - - -class DDMTDSamplerExtFF(Module): - def __init__(self, ddmtd_inputs): - self.rec_clk = Signal() - self.main_xo = Signal() - - # # # - - # TODO: s/h timing at FPGA pads - if hasattr(ddmtd_inputs, "rec_clk"): - rec_clk_1 = ddmtd_inputs.rec_clk - else: - rec_clk_1 = Signal() - self.specials += Instance("IBUFDS", - i_I=ddmtd_inputs.rec_clk_p, i_IB=ddmtd_inputs.rec_clk_n, - o_O=rec_clk_1) - if hasattr(ddmtd_inputs, "main_xo"): - main_xo_1 = ddmtd_inputs.main_xo - else: - main_xo_1 = Signal() - self.specials += Instance("IBUFDS", - i_I=ddmtd_inputs.main_xo_p, i_IB=ddmtd_inputs.main_xo_n, - o_O=main_xo_1) - self.specials += [ - Instance("FD", i_C=ClockSignal("helper"), - i_D=rec_clk_1, o_Q=self.rec_clk, - attr={("IOB", "TRUE")}), - Instance("FD", i_C=ClockSignal("helper"), - i_D=main_xo_1, o_Q=self.main_xo, - attr={("IOB", "TRUE")}), - ] - - -class DDMTDSamplerGTP(Module): - def __init__(self, gtp, main_xo_pads): - self.rec_clk = Signal() - self.main_xo = Signal() - - # # # - - # Getting the main XO signal from IBUFDS_GTE2 is problematic because - # the transceiver PLL craps out if an improper clock signal is applied, - # so we are disabling the buffer until the clock is stable. - main_xo_se = Signal() - rec_clk_1 = Signal() - main_xo_1 = Signal() - self.specials += [ - Instance("IBUFDS", - i_I=main_xo_pads.p, i_IB=main_xo_pads.n, - o_O=main_xo_se), - Instance("FD", i_C=ClockSignal("helper"), - i_D=gtp.cd_rtio_rx0.clk, o_Q=rec_clk_1, - attr={("DONT_TOUCH", "TRUE")}), - Instance("FD", i_C=ClockSignal("helper"), - i_D=rec_clk_1, o_Q=self.rec_clk, - attr={("DONT_TOUCH", "TRUE")}), - Instance("FD", i_C=ClockSignal("helper"), - i_D=main_xo_se, o_Q=main_xo_1, - attr={("IOB", "TRUE")}), - Instance("FD", i_C=ClockSignal("helper"), - i_D=main_xo_1, o_Q=self.main_xo, - attr={("DONT_TOUCH", "TRUE")}), - ] - - -class DDMTDDeglitcherFirstEdge(Module): - def __init__(self, input_signal, blind_period=128): - self.detect = Signal() - self.tag_correction = 0 - - rising = Signal() - input_signal_r = Signal() - self.sync.helper += [ - input_signal_r.eq(input_signal), - rising.eq(input_signal & ~input_signal_r) - ] - - blind_counter = Signal(max=blind_period) - self.sync.helper += [ - If(blind_counter != 0, blind_counter.eq(blind_counter - 1)), - If(input_signal_r, blind_counter.eq(blind_period - 1)), - self.detect.eq(rising & (blind_counter == 0)) - ] - - -class DDMTD(Module): - def __init__(self, counter, input_signal): - - # in helper clock domain - self.h_tag = Signal(len(counter)) - self.h_tag_update = Signal() - - # # # - - deglitcher = DDMTDDeglitcherFirstEdge(input_signal) - self.submodules += deglitcher - - self.sync.helper += [ - self.h_tag_update.eq(0), - If(deglitcher.detect, - self.h_tag_update.eq(1), - self.h_tag.eq(counter + deglitcher.tag_correction) - ) - ] - - -class Collector(Module): - """Generates loop filter inputs from DDMTD outputs. - - The input to the main DCXO lock loop filter is the difference between the - reference and main tags after unwrapping (see below). - - The input to the helper DCXO lock loop filter is the difference between the - current reference tag and the previous reference tag after unwrapping. - - When the WR PLL is locked, the following ideally (no noise/jitter) obtain: - - f_main = f_ref - - f_helper = f_ref * 2^N/(2^N+1) - - f_beat = f_ref - f_helper = f_ref / (2^N + 1) (cycle time is: dt=1/f_beat) - - the reference and main DCXO tags are equal to each other at every cycle - (the main DCXO lock drives this difference to 0) - - the reference and main DCXO tags both have the same value at each cycle - (the tag difference for each DDMTD is given by - f_helper*dt = f_helper/f_beat = 2^N, which causes the N-bit DDMTD counter - to wrap around and come back to its previous value) - - Note that we currently lock the frequency of the helper DCXO to the - reference clock, not it's phase. As a result, while the tag differences are - controlled, their absolute values are arbitrary. We could consider moving - the helper lock to a phase lock at some point in the future... - - Since the DDMTD counter is only N bits, it is possible for tag values to - wrap around. This will happen frequently if the locked tags happens to be - near the edges of the counter, so that jitter can easily cause a phase wrap. - But, it can also easily happen during lock acquisition or other transients. - To avoid glitches in the output, we unwrap the tag differences. Currently - we do this in hardware, but we should consider extending the processor to - allow us to do it inside the filters. Since the processor uses wider - signals, this would significantly extend the overall glitch-free - range of the PLL and may aid lock acquisition. - """ - def __init__(self, N): - self.ref_stb = Signal() - self.main_stb = Signal() - self.tag_ref = Signal(N) - self.tag_main = Signal(N) - - self.out_stb = Signal() - self.out_main = Signal((N+2, True)) - self.out_helper = Signal((N+2, True)) - self.out_tag_ref = Signal(N) - self.out_tag_main = Signal(N) - - tag_ref_r = Signal(N) - tag_main_r = Signal(N) - main_tag_diff = Signal((N+2, True)) - helper_tag_diff = Signal((N+2, True)) - - # # # - - fsm = FSM(reset_state="IDLE") - self.submodules += fsm - - fsm.act("IDLE", - NextValue(self.out_stb, 0), - If(self.ref_stb & self.main_stb, - NextValue(tag_ref_r, self.tag_ref), - NextValue(tag_main_r, self.tag_main), - NextState("DIFF") - ).Elif(self.ref_stb, - NextValue(tag_ref_r, self.tag_ref), - NextState("WAITMAIN") - ).Elif(self.main_stb, - NextValue(tag_main_r, self.tag_main), - NextState("WAITREF") - ) - ) - fsm.act("WAITREF", - If(self.ref_stb, - NextValue(tag_ref_r, self.tag_ref), - NextState("DIFF") - ) - ) - fsm.act("WAITMAIN", - If(self.main_stb, - NextValue(tag_main_r, self.tag_main), - NextState("DIFF") - ) - ) - fsm.act("DIFF", - NextValue(main_tag_diff, tag_main_r - tag_ref_r), - NextValue(helper_tag_diff, tag_ref_r - self.out_tag_ref), - NextState("UNWRAP") - ) - fsm.act("UNWRAP", - If(main_tag_diff - self.out_main > 2**(N-1), - NextValue(main_tag_diff, main_tag_diff - 2**N) - ).Elif(self.out_main - main_tag_diff > 2**(N-1), - NextValue(main_tag_diff, main_tag_diff + 2**N) - ), - - If(helper_tag_diff - self.out_helper > 2**(N-1), - NextValue(helper_tag_diff, helper_tag_diff - 2**N) - ).Elif(self.out_helper - helper_tag_diff > 2**(N-1), - NextValue(helper_tag_diff, helper_tag_diff + 2**N) - ), - NextState("OUTPUT") - ) - fsm.act("OUTPUT", - NextValue(self.out_tag_ref, tag_ref_r), - NextValue(self.out_tag_main, tag_main_r), - NextValue(self.out_main, main_tag_diff), - NextValue(self.out_helper, helper_tag_diff), - NextValue(self.out_stb, 1), - NextState("IDLE") - ) diff --git a/artiq/gateware/drtio/wrpll/filters.py b/artiq/gateware/drtio/wrpll/filters.py deleted file mode 100644 index 470f17bf3..000000000 --- a/artiq/gateware/drtio/wrpll/filters.py +++ /dev/null @@ -1,61 +0,0 @@ -helper_xn1 = 0 -helper_xn2 = 0 -helper_yn0 = 0 -helper_yn1 = 0 -helper_yn2 = 0 -helper_out = 0 - -main_xn1 = 0 -main_xn2 = 0 -main_yn0 = 0 -main_yn1 = 0 -main_yn2 = 0 - - -def helper(tag_diff): - global helper_xn1, helper_xn2, helper_yn0, \ - helper_yn1, helper_yn2, helper_out - - helper_xn0 = 0 - tag_diff # *(2**22) - - helper_yr = 4294967296 - - helper_yn2 = helper_yn1 - helper_yn1 = helper_yn0 - - helper_yn0 = (284885690 * (helper_xn0 - + (217319150 * helper_xn1 >> 44) - - (17591968725108 * helper_xn2 >> 44) - ) >> 44 - ) + (35184372088832*helper_yn1 >> 44) - helper_yn2 - - helper_xn2 = helper_xn1 - helper_xn1 = helper_xn0 - - helper_out = 268435456*helper_yn0 >> 44 - helper_out = min(helper_out, helper_yr) - helper_out = max(helper_out, 0 - helper_yr) - - return helper_out - - -def main(main_xn0): - global main_xn1, main_xn2, main_yn0, main_yn1, main_yn2 - - main_yr = 4294967296 - - main_yn2 = main_yn1 - main_yn1 = main_yn0 - main_yn0 = ( - ((133450380908*(((35184372088832*main_xn0) >> 44) + - ((17592186044417*main_xn1) >> 44))) >> 44) + - ((29455872930889*main_yn1) >> 44) - - ((12673794781453*main_yn2) >> 44)) - - main_xn2 = main_xn1 - main_xn1 = main_xn0 - - main_yn0 = min(main_yn0, main_yr) - main_yn0 = max(main_yn0, 0 - main_yr) - - return main_yn0 diff --git a/artiq/gateware/drtio/wrpll/si549.py b/artiq/gateware/drtio/wrpll/si549.py deleted file mode 100644 index 46ce0c138..000000000 --- a/artiq/gateware/drtio/wrpll/si549.py +++ /dev/null @@ -1,340 +0,0 @@ -from migen import * -from migen.genlib.fsm import * -from migen.genlib.cdc import MultiReg, PulseSynchronizer, BlindTransfer - -from misoc.interconnect.csr import * - - -class I2CClockGen(Module): - def __init__(self, width): - self.load = Signal(width) - self.clk2x = Signal() - - cnt = Signal.like(self.load) - self.comb += [ - self.clk2x.eq(cnt == 0), - ] - self.sync += [ - If(self.clk2x, - cnt.eq(self.load), - ).Else( - cnt.eq(cnt - 1), - ) - ] - - -class I2CMasterMachine(Module): - def __init__(self, clock_width): - self.scl = Signal(reset=1) - self.sda_o = Signal(reset=1) - self.sda_i = Signal() - - self.submodules.cg = CEInserter()(I2CClockGen(clock_width)) - self.start = Signal() - self.stop = Signal() - self.write = Signal() - self.ack = Signal() - self.data = Signal(8) - self.ready = Signal() - - ### - - bits = Signal(4) - data = Signal(8) - - fsm = CEInserter()(FSM("IDLE")) - self.submodules += fsm - - fsm.act("IDLE", - self.ready.eq(1), - If(self.start, - NextState("START0"), - ).Elif(self.stop, - NextState("STOP0"), - ).Elif(self.write, - NextValue(bits, 8), - NextValue(data, self.data), - NextState("WRITE0") - ) - ) - - fsm.act("START0", - NextValue(self.scl, 1), - NextState("START1") - ) - fsm.act("START1", - NextValue(self.sda_o, 0), - NextState("IDLE") - ) - - fsm.act("STOP0", - NextValue(self.scl, 0), - NextState("STOP1") - ) - fsm.act("STOP1", - NextValue(self.sda_o, 0), - NextState("STOP2") - ) - fsm.act("STOP2", - NextValue(self.scl, 1), - NextState("STOP3") - ) - fsm.act("STOP3", - NextValue(self.sda_o, 1), - NextState("IDLE") - ) - - fsm.act("WRITE0", - NextValue(self.scl, 0), - NextState("WRITE1") - ) - fsm.act("WRITE1", - If(bits == 0, - NextValue(self.sda_o, 1), - NextState("READACK0"), - ).Else( - NextValue(self.sda_o, data[7]), - NextState("WRITE2"), - ) - ) - fsm.act("WRITE2", - NextValue(self.scl, 1), - NextValue(data[1:], data[:-1]), - NextValue(bits, bits - 1), - NextState("WRITE0"), - ) - fsm.act("READACK0", - NextValue(self.scl, 1), - NextState("READACK1"), - ) - fsm.act("READACK1", - NextValue(self.ack, ~self.sda_i), - NextState("IDLE") - ) - - run = Signal() - idle = Signal() - self.comb += [ - run.eq((self.start | self.stop | self.write) & self.ready), - idle.eq(~run & fsm.ongoing("IDLE")), - self.cg.ce.eq(~idle), - fsm.ce.eq(run | self.cg.clk2x), - ] - - -class ADPLLProgrammer(Module): - def __init__(self): - self.i2c_divider = Signal(16) - self.i2c_address = Signal(7) - - self.adpll = Signal(24) - self.stb = Signal() - self.busy = Signal() - self.nack = Signal() - - self.scl = Signal() - self.sda_i = Signal() - self.sda_o = Signal() - - self.scl.attr.add("no_retiming") - self.sda_o.attr.add("no_retiming") - - # # # - - master = I2CMasterMachine(16) - self.submodules += master - - self.comb += [ - master.cg.load.eq(self.i2c_divider), - self.scl.eq(master.scl), - master.sda_i.eq(self.sda_i), - self.sda_o.eq(master.sda_o) - ] - - fsm = FSM() - self.submodules += fsm - - adpll = Signal.like(self.adpll) - - fsm.act("IDLE", - If(self.stb, - NextValue(adpll, self.adpll), - NextState("START") - ) - ) - fsm.act("START", - master.start.eq(1), - If(master.ready, NextState("DEVADDRESS")) - ) - fsm.act("DEVADDRESS", - master.data.eq(self.i2c_address << 1), - master.write.eq(1), - If(master.ready, NextState("REGADRESS")) - ) - fsm.act("REGADRESS", - master.data.eq(231), - master.write.eq(1), - If(master.ready, - If(master.ack, - NextState("DATA0") - ).Else( - self.nack.eq(1), - NextState("STOP") - ) - ) - ) - fsm.act("DATA0", - master.data.eq(adpll[0:8]), - master.write.eq(1), - If(master.ready, - If(master.ack, - NextState("DATA1") - ).Else( - self.nack.eq(1), - NextState("STOP") - ) - ) - ) - fsm.act("DATA1", - master.data.eq(adpll[8:16]), - master.write.eq(1), - If(master.ready, - If(master.ack, - NextState("DATA2") - ).Else( - self.nack.eq(1), - NextState("STOP") - ) - ) - ) - fsm.act("DATA2", - master.data.eq(adpll[16:24]), - master.write.eq(1), - If(master.ready, - If(~master.ack, self.nack.eq(1)), - NextState("STOP") - ) - ) - fsm.act("STOP", - master.stop.eq(1), - If(master.ready, - If(~master.ack, self.nack.eq(1)), - NextState("IDLE") - ) - ) - - self.comb += self.busy.eq(~fsm.ongoing("IDLE")) - - -def simulate_programmer(): - from migen.sim.core import run_simulation - - dut = ADPLLProgrammer() - - def generator(): - yield dut.i2c_divider.eq(4) - yield dut.i2c_address.eq(0x55) - yield - yield dut.adpll.eq(0x123456) - yield dut.stb.eq(1) - yield - yield dut.stb.eq(0) - yield - while (yield dut.busy): - yield - for _ in range(20): - yield - - run_simulation(dut, generator(), vcd_name="tb.vcd") - - -class Si549(Module, AutoCSR): - def __init__(self, pads): - self.gpio_enable = CSRStorage(reset=1) - self.gpio_in = CSRStatus(2) - self.gpio_out = CSRStorage(2) - self.gpio_oe = CSRStorage(2) - - self.i2c_divider = CSRStorage(16, reset=75) - self.i2c_address = CSRStorage(7) - self.errors = CSR(2) - - # in helper clock domain - self.adpll = Signal(24) - self.adpll_stb = Signal() - - # # # - - programmer = ClockDomainsRenamer("helper")(ADPLLProgrammer()) - self.submodules += programmer - - self.i2c_divider.storage.attr.add("no_retiming") - self.i2c_address.storage.attr.add("no_retiming") - self.specials += [ - MultiReg(self.i2c_divider.storage, programmer.i2c_divider, "helper"), - MultiReg(self.i2c_address.storage, programmer.i2c_address, "helper") - ] - self.comb += [ - programmer.adpll.eq(self.adpll), - programmer.stb.eq(self.adpll_stb) - ] - - self.gpio_enable.storage.attr.add("no_retiming") - self.gpio_out.storage.attr.add("no_retiming") - self.gpio_oe.storage.attr.add("no_retiming") - - # SCL GPIO and mux - ts_scl = TSTriple(1) - self.specials += ts_scl.get_tristate(pads.scl) - - status = Signal() - self.comb += self.gpio_in.status[0].eq(status) - - self.specials += MultiReg(ts_scl.i, status) - self.comb += [ - If(self.gpio_enable.storage, - ts_scl.o.eq(self.gpio_out.storage[0]), - ts_scl.oe.eq(self.gpio_oe.storage[0]) - ).Else( - ts_scl.o.eq(0), - ts_scl.oe.eq(~programmer.scl) - ) - ] - - # SDA GPIO and mux - ts_sda = TSTriple(1) - self.specials += ts_sda.get_tristate(pads.sda) - - status = Signal() - self.comb += self.gpio_in.status[1].eq(status) - - self.specials += MultiReg(ts_sda.i, status) - self.comb += [ - If(self.gpio_enable.storage, - ts_sda.o.eq(self.gpio_out.storage[1]), - ts_sda.oe.eq(self.gpio_oe.storage[1]) - ).Else( - ts_sda.o.eq(0), - ts_sda.oe.eq(~programmer.sda_o) - ) - ] - self.specials += MultiReg(ts_sda.i, programmer.sda_i, "helper") - - # Error reporting - collision_cdc = BlindTransfer("helper", "sys") - self.submodules += collision_cdc - self.comb += collision_cdc.i.eq(programmer.stb & programmer.busy) - - nack_cdc = PulseSynchronizer("helper", "sys") - self.submodules += nack_cdc - self.comb += nack_cdc.i.eq(programmer.nack) - - for n, trig in enumerate([collision_cdc.o, nack_cdc.o]): - self.sync += [ - If(self.errors.re & self.errors.r[n], self.errors.w[n].eq(0)), - If(trig, self.errors.w[n].eq(1)) - ] - - -if __name__ == "__main__": - simulate_programmer() diff --git a/artiq/gateware/drtio/wrpll/thls.py b/artiq/gateware/drtio/wrpll/thls.py deleted file mode 100644 index b11459692..000000000 --- a/artiq/gateware/drtio/wrpll/thls.py +++ /dev/null @@ -1,618 +0,0 @@ -import inspect -import ast -from copy import copy -import operator -from functools import reduce -from collections import OrderedDict - -from migen import * -from migen.genlib.fsm import * - - -class Isn: - def __init__(self, immediate=None, inputs=None, outputs=None): - if inputs is None: - inputs = [] - if outputs is None: - outputs = [] - self.immediate = immediate - self.inputs = inputs - self.outputs = outputs - - def __repr__(self): - r = "<" - r += self.__class__.__name__ - if self.immediate is not None: - r += " (" + str(self.immediate) + ")" - for inp in self.inputs: - r += " r" + str(inp) - if self.outputs: - r += " ->" - for outp in self.outputs: - r += " r" + str(outp) - r += ">" - return r - - -class NopIsn(Isn): - opcode = 0 - -class AddIsn(Isn): - opcode = 1 - -class SubIsn(Isn): - opcode = 2 - -class MulShiftIsn(Isn): - opcode = 3 - -# opcode = 4: MulShift with alternate shift - -class MinIsn(Isn): - opcode = 5 - -class MaxIsn(Isn): - opcode = 6 - -class CopyIsn(Isn): - opcode = 7 - -class InputIsn(Isn): - opcode = 8 - -class OutputIsn(Isn): - opcode = 9 - -class EndIsn(Isn): - opcode = 10 - - -class ASTCompiler: - def __init__(self): - self.program = [] - self.data = [] - self.next_ssa_reg = -1 - self.constants = dict() - self.names = dict() - self.globals = OrderedDict() - - def get_ssa_reg(self): - r = self.next_ssa_reg - self.next_ssa_reg -= 1 - return r - - def add_global(self, name): - if name not in self.globals: - r = len(self.data) - self.data.append(0) - self.names[name] = r - self.globals[name] = r - - def input(self, name): - target = self.get_ssa_reg() - self.program.append(InputIsn(outputs=[target])) - self.names[name] = target - - def emit(self, node): - if isinstance(node, ast.BinOp): - if isinstance(node.op, ast.RShift): - if not isinstance(node.left, ast.BinOp) or not isinstance(node.left.op, ast.Mult): - raise NotImplementedError - if not isinstance(node.right, ast.Num): - raise NotImplementedError - left = self.emit(node.left.left) - right = self.emit(node.left.right) - cons = lambda **kwargs: MulShiftIsn(immediate=node.right.n, **kwargs) - else: - left = self.emit(node.left) - right = self.emit(node.right) - if isinstance(node.op, ast.Add): - cons = AddIsn - elif isinstance(node.op, ast.Sub): - cons = SubIsn - elif isinstance(node.op, ast.Mult): - cons = lambda **kwargs: MulShiftIsn(immediate=0, **kwargs) - else: - raise NotImplementedError - output = self.get_ssa_reg() - self.program.append(cons(inputs=[left, right], outputs=[output])) - return output - elif isinstance(node, ast.Call): - if not isinstance(node.func, ast.Name): - raise NotImplementedError - funcname = node.func.id - if node.keywords: - raise NotImplementedError - inputs = [self.emit(x) for x in node.args] - if funcname == "min": - cons = MinIsn - elif funcname == "max": - cons = MaxIsn - else: - raise NotImplementedError - output = self.get_ssa_reg() - self.program.append(cons(inputs=inputs, outputs=[output])) - return output - elif isinstance(node, (ast.Num, ast.UnaryOp)): - if isinstance(node, ast.UnaryOp): - if not isinstance(node.operand, ast.Num): - raise NotImplementedError - if isinstance(node.op, ast.UAdd): - transform = lambda x: x - elif isinstance(node.op, ast.USub): - transform = operator.neg - elif isinstance(node.op, ast.Invert): - transform = operator.invert - else: - raise NotImplementedError - node = node.operand - else: - transform = lambda x: x - n = transform(node.n) - if n in self.constants: - return self.constants[n] - else: - r = len(self.data) - self.data.append(n) - self.constants[n] = r - return r - elif isinstance(node, ast.Name): - return self.names[node.id] - elif isinstance(node, ast.Assign): - output = self.emit(node.value) - for target in node.targets: - assert isinstance(target, ast.Name) - self.names[target.id] = output - elif isinstance(node, ast.Return): - value = self.emit(node.value) - self.program.append(OutputIsn(inputs=[value])) - elif isinstance(node, ast.Global): - pass - else: - raise NotImplementedError - - -class Processor: - def __init__(self, data_width=32, multiplier_stages=2): - self.data_width = data_width - self.multiplier_stages = multiplier_stages - self.multiplier_shifts = [] - self.program_rom_size = None - self.data_ram_size = None - self.opcode_bits = 4 - self.reg_bits = None - - def get_instruction_latency(self, isn): - return { - AddIsn: 2, - SubIsn: 2, - MulShiftIsn: 1 + self.multiplier_stages, - MinIsn: 2, - MaxIsn: 2, - CopyIsn: 1, - InputIsn: 1 - }[isn.__class__] - - def encode_instruction(self, isn, exit): - opcode = isn.opcode - if isn.immediate is not None and not isinstance(isn, MulShiftIsn): - r0 = isn.immediate - if len(isn.inputs) >= 1: - r1 = isn.inputs[0] - else: - r1 = 0 - else: - if len(isn.inputs) >= 1: - r0 = isn.inputs[0] - else: - r0 = 0 - if len(isn.inputs) >= 2: - r1 = isn.inputs[1] - else: - r1 = 0 - r = 0 - for value, bits in ((exit, self.reg_bits), (r1, self.reg_bits), (r0, self.reg_bits), (opcode, self.opcode_bits)): - r <<= bits - r |= value - return r - - def instruction_bits(self): - return 3*self.reg_bits + self.opcode_bits - - def implement(self, program, data): - return ProcessorImpl(self, program, data) - - -class Scheduler: - def __init__(self, processor, reserved_data, program): - self.processor = processor - self.reserved_data = reserved_data - self.used_registers = set(range(self.reserved_data)) - self.exits = dict() - self.program = program - self.remaining = copy(program) - self.output = [] - - def allocate_register(self): - r = min(set(range(max(self.used_registers) + 2)) - self.used_registers) - self.used_registers.add(r) - return r - - def free_register(self, r): - assert r >= self.reserved_data - self.used_registers.discard(r) - - def find_inputs(self, cycle, isn): - mapped_inputs = [] - for inp in isn.inputs: - if inp >= 0: - mapped_inputs.append(inp) - else: - found = False - for i in range(cycle): - if i in self.exits: - r, rm = self.exits[i] - if r == inp: - mapped_inputs.append(rm) - found = True - break - if not found: - return None - return mapped_inputs - - def schedule_one(self, isn): - cycle = len(self.output) - mapped_inputs = self.find_inputs(cycle, isn) - if mapped_inputs is None: - return False - - if isn.outputs: - # check that exit slot is free - latency = self.processor.get_instruction_latency(isn) - exit = cycle + latency - if exit in self.exits: - return False - - # avoid RAW hazard with global writeback - for output in isn.outputs: - if output >= 0: - for risn in self.remaining: - for inp in risn.inputs: - if inp == output: - return False - - # Instruction can be scheduled - - self.remaining.remove(isn) - - for inp, minp in zip(isn.inputs, mapped_inputs): - can_free = inp < 0 and all(inp != rinp for risn in self.remaining for rinp in risn.inputs) - if can_free: - self.free_register(minp) - - if isn.outputs: - assert len(isn.outputs) == 1 - if isn.outputs[0] < 0: - output = self.allocate_register() - else: - output = isn.outputs[0] - self.exits[exit] = (isn.outputs[0], output) - self.output.append(isn.__class__(immediate=isn.immediate, inputs=mapped_inputs)) - - return True - - def schedule(self): - while self.remaining: - success = False - for isn in self.remaining: - if self.schedule_one(isn): - success = True - break - if not success: - self.output.append(NopIsn()) - self.output += [NopIsn()]*(max(self.exits.keys()) - len(self.output) + 1) - return self.output - - -class CompiledProgram: - def __init__(self, processor, program, exits, data, glbs): - self.processor = processor - self.program = program - self.exits = exits - self.data = data - self.globals = glbs - - def pretty_print(self): - for cycle, isn in enumerate(self.program): - l = "{:4d} {:15}".format(cycle, str(isn)) - if cycle in self.exits: - l += " -> r{}".format(self.exits[cycle]) - print(l) - - def dimension_processor(self): - self.processor.program_rom_size = len(self.program) - self.processor.data_ram_size = len(self.data) - self.processor.reg_bits = (self.processor.data_ram_size - 1).bit_length() - for isn in self.program: - if isinstance(isn, MulShiftIsn) and isn.immediate not in self.processor.multiplier_shifts: - self.processor.multiplier_shifts.append(isn.immediate) - - def encode(self): - r = [] - for i, isn in enumerate(self.program): - exit = self.exits.get(i, 0) - r.append(self.processor.encode_instruction(isn, exit)) - return r - - -def compile(processor, function): - node = ast.parse(inspect.getsource(function)) - assert isinstance(node, ast.Module) - assert len(node.body) == 1 - node = node.body[0] - assert isinstance(node, ast.FunctionDef) - assert len(node.args.args) == 1 - arg = node.args.args[0].arg - body = node.body - - astcompiler = ASTCompiler() - for node in body: - if isinstance(node, ast.Global): - for name in node.names: - astcompiler.add_global(name) - arg_r = astcompiler.input(arg) - for node in body: - astcompiler.emit(node) - if isinstance(node, ast.Return): - break - for glbl, location in astcompiler.globals.items(): - new_location = astcompiler.names[glbl] - if new_location != location: - astcompiler.program.append(CopyIsn(inputs=[new_location], outputs=[location])) - - scheduler = Scheduler(processor, len(astcompiler.data), astcompiler.program) - scheduler.schedule() - - program = copy(scheduler.output) - program.append(EndIsn()) - - max_reg = max(max(max(isn.inputs + [0]) for isn in program), max(v[1] for k, v in scheduler.exits.items())) - - return CompiledProgram( - processor=processor, - program=program, - exits={k: v[1] for k, v in scheduler.exits.items()}, - data=astcompiler.data + [0]*(max_reg - len(astcompiler.data) + 1), - glbs=astcompiler.globals) - - -class BaseUnit(Module): - def __init__(self, data_width): - self.stb_i = Signal() - self.i0 = Signal((data_width, True)) - self.i1 = Signal((data_width, True)) - self.stb_o = Signal() - self.o = Signal((data_width, True)) - - -class NopUnit(BaseUnit): - pass - - -class OpUnit(BaseUnit): - def __init__(self, op, data_width, stages, op_data_width=None): - BaseUnit.__init__(self, data_width) - # work around Migen's mishandling of Verilog's cretinous operator width rules - if op_data_width is None: - op_data_width = data_width - - if stages > 1: - # Vivado backward retiming for DSP does not work correctly if DSP inputs - # are not registered. - i0 = Signal.like(self.i0) - i1 = Signal.like(self.i1) - stb_i = Signal() - self.sync += [ - i0.eq(self.i0), - i1.eq(self.i1), - stb_i.eq(self.stb_i) - ] - output_stages = stages - 1 - else: - i0, i1, stb_i = self.i0, self.i1, self.stb_i - output_stages = stages - - o = Signal((op_data_width, True)) - self.comb += o.eq(op(i0, i1)) - stb_o = stb_i - for i in range(output_stages): - n_o = Signal((data_width, True)) - if stages > 1: - n_o.attr.add(("retiming_backward", 1)) - n_stb_o = Signal() - self.sync += [ - n_o.eq(o), - n_stb_o.eq(stb_o) - ] - o = n_o - stb_o = n_stb_o - self.comb += [ - self.o.eq(o), - self.stb_o.eq(stb_o) - ] - - -class SelectUnit(BaseUnit): - def __init__(self, op, data_width): - BaseUnit.__init__(self, data_width) - - self.sync += [ - self.stb_o.eq(self.stb_i), - If(op(self.i0, self.i1), - self.o.eq(self.i0) - ).Else( - self.o.eq(self.i1) - ) - ] - - -class CopyUnit(BaseUnit): - def __init__(self, data_width): - BaseUnit.__init__(self, data_width) - - self.comb += [ - self.stb_o.eq(self.stb_i), - self.o.eq(self.i0) - ] - - -class InputUnit(BaseUnit): - def __init__(self, data_width, input_stb, input): - BaseUnit.__init__(self, data_width) - self.buffer = Signal(data_width) - - self.comb += [ - self.stb_o.eq(self.stb_i), - self.o.eq(self.buffer) - ] - - -class OutputUnit(BaseUnit): - def __init__(self, data_width, output_stb, output): - BaseUnit.__init__(self, data_width) - - self.sync += [ - output_stb.eq(self.stb_i), - output.eq(self.i0) - ] - - -class ProcessorImpl(Module): - def __init__(self, pd, program, data): - self.input_stb = Signal() - self.input = Signal((pd.data_width, True)) - - self.output_stb = Signal() - self.output = Signal((pd.data_width, True)) - - self.busy = Signal() - - # # # - - program_mem = Memory(pd.instruction_bits(), pd.program_rom_size, init=program) - data_mem0 = Memory(pd.data_width, pd.data_ram_size, init=data) - data_mem1 = Memory(pd.data_width, pd.data_ram_size, init=data) - self.specials += program_mem, data_mem0, data_mem1 - - pc = Signal(pd.instruction_bits()) - pc_next = Signal.like(pc) - pc_en = Signal() - self.sync += pc.eq(pc_next) - self.comb += [ - If(pc_en, - pc_next.eq(pc + 1) - ).Else( - pc_next.eq(0) - ) - ] - program_mem_port = program_mem.get_port() - self.specials += program_mem_port - self.comb += program_mem_port.adr.eq(pc_next) - - s = 0 - opcode = Signal(pd.opcode_bits) - self.comb += opcode.eq(program_mem_port.dat_r[s:s+pd.opcode_bits]) - s += pd.opcode_bits - r0 = Signal(pd.reg_bits) - self.comb += r0.eq(program_mem_port.dat_r[s:s+pd.reg_bits]) - s += pd.reg_bits - r1 = Signal(pd.reg_bits) - self.comb += r1.eq(program_mem_port.dat_r[s:s+pd.reg_bits]) - s += pd.reg_bits - exit = Signal(pd.reg_bits) - self.comb += exit.eq(program_mem_port.dat_r[s:s+pd.reg_bits]) - - data_read_port0 = data_mem0.get_port() - data_read_port1 = data_mem1.get_port() - self.specials += data_read_port0, data_read_port1 - self.comb += [ - data_read_port0.adr.eq(r0), - data_read_port1.adr.eq(r1) - ] - - data_write_port = data_mem0.get_port(write_capable=True) - data_write_port_dup = data_mem1.get_port(write_capable=True) - self.specials += data_write_port, data_write_port_dup - self.comb += [ - data_write_port_dup.we.eq(data_write_port.we), - data_write_port_dup.adr.eq(data_write_port.adr), - data_write_port_dup.dat_w.eq(data_write_port.dat_w), - data_write_port.adr.eq(exit) - ] - - nop = NopUnit(pd.data_width) - adder = OpUnit(operator.add, pd.data_width, 1) - subtractor = OpUnit(operator.sub, pd.data_width, 1) - if pd.multiplier_shifts: - if len(pd.multiplier_shifts) != 1: - raise NotImplementedError - multiplier = OpUnit(lambda a, b: a * b >> pd.multiplier_shifts[0], - pd.data_width, pd.multiplier_stages, op_data_width=2*pd.data_width) - else: - multiplier = NopUnit(pd.data_width) - minu = SelectUnit(operator.lt, pd.data_width) - maxu = SelectUnit(operator.gt, pd.data_width) - copier = CopyUnit(pd.data_width) - inu = InputUnit(pd.data_width, self.input_stb, self.input) - outu = OutputUnit(pd.data_width, self.output_stb, self.output) - units = [nop, adder, subtractor, multiplier, minu, maxu, copier, inu, outu] - self.submodules += units - - for unit in units: - self.sync += unit.stb_i.eq(0) - self.comb += [ - unit.i0.eq(data_read_port0.dat_r), - unit.i1.eq(data_read_port1.dat_r), - If(unit.stb_o, - data_write_port.we.eq(1), - data_write_port.dat_w.eq(unit.o) - ) - ] - - decode_table = [ - (NopIsn.opcode, nop), - (AddIsn.opcode, adder), - (SubIsn.opcode, subtractor), - (MulShiftIsn.opcode, multiplier), - (MulShiftIsn.opcode + 1, multiplier), - (MinIsn.opcode, minu), - (MaxIsn.opcode, maxu), - (CopyIsn.opcode, copier), - (InputIsn.opcode, inu), - (OutputIsn.opcode, outu) - ] - for allocated_opcode, unit in decode_table: - self.sync += If(pc_en & (opcode == allocated_opcode), unit.stb_i.eq(1)) - - fsm = FSM() - self.submodules += fsm - fsm.act("IDLE", - pc_en.eq(0), - NextValue(inu.buffer, self.input), - If(self.input_stb, NextState("PROCESSING")) - ) - fsm.act("PROCESSING", - self.busy.eq(1), - pc_en.eq(1), - If(opcode == EndIsn.opcode, - pc_en.eq(0), - NextState("IDLE") - ) - ) - - -def make(function, **kwargs): - proc = Processor(**kwargs) - cp = compile(proc, function) - cp.dimension_processor() - return proc.implement(cp.encode(), cp.data) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 9adfac0a2..448faefd7 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -21,7 +21,6 @@ from artiq.gateware.rtio.xilinx_clocking import fix_serdes_timing_path from artiq.gateware import eem from artiq.gateware.drtio.transceiver import gtp_7series from artiq.gateware.drtio.siphaser import SiPhaser7Series -from artiq.gateware.drtio.wrpll import WRPLL, DDMTDSamplerGTP from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer from artiq.gateware.drtio import * from artiq.build_soc import * @@ -410,7 +409,7 @@ class SatelliteBase(BaseSoC): } mem_map.update(BaseSoC.mem_map) - def __init__(self, rtio_clk_freq=125e6, enable_sata=False, *, with_wrpll=False, gateware_identifier_str=None, hw_rev="v2.0", **kwargs): + def __init__(self, rtio_clk_freq=125e6, enable_sata=False, *, gateware_identifier_str=None, hw_rev="v2.0", **kwargs): if hw_rev in ("v1.0", "v1.1"): cpu_bus_width = 32 else: @@ -533,35 +532,18 @@ class SatelliteBase(BaseSoC): rtio_clk_period = 1e9/rtio_clk_freq self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - if with_wrpll: - self.submodules.wrpll_sampler = DDMTDSamplerGTP( - self.drtio_transceiver, - platform.request("cdr_clk_clean_fabric")) - helper_clk_pads = platform.request("ddmtd_helper_clk") - self.submodules.wrpll = WRPLL( - helper_clk_pads=helper_clk_pads, - main_dcxo_i2c=platform.request("ddmtd_main_dcxo_i2c"), - helper_dxco_i2c=platform.request("ddmtd_helper_dcxo_i2c"), - ddmtd_inputs=self.wrpll_sampler) - self.csr_devices.append("wrpll") - # note: do not use self.wrpll.cd_helper.clk; otherwise, vivado craps out with: - # critical warning: create_clock attempting to set clock on an unknown port/pin - # command: "create_clock -period 7.920000 -waveform {0.000000 3.960000} -name - # helper_clk [get_xlnx_outside_genome_inst_pin 20 0] - platform.add_period_constraint(helper_clk_pads.p, rtio_clk_period*0.99) - platform.add_false_path_constraints(self.crg.cd_sys.clk, helper_clk_pads.p) - else: - self.submodules.siphaser = SiPhaser7Series( - si5324_clkin=platform.request("cdr_clk") if platform.hw_rev == "v2.0" - else platform.request("si5324_clkin"), - rx_synchronizer=self.rx_synchronizer, - ref_clk=self.crg.clk125_div2, ref_div2=True, - rtio_clk_freq=rtio_clk_freq) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) - self.csr_devices.append("siphaser") - self.config["HAS_SI5324"] = None - self.config["SI5324_SOFT_RESET"] = None + + self.submodules.siphaser = SiPhaser7Series( + si5324_clkin=platform.request("cdr_clk") if platform.hw_rev == "v2.0" + else platform.request("si5324_clkin"), + rx_synchronizer=self.rx_synchronizer, + ref_clk=self.crg.clk125_div2, ref_div2=True, + rtio_clk_freq=rtio_clk_freq) + platform.add_false_path_constraints( + self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) + self.csr_devices.append("siphaser") + self.config["HAS_SI5324"] = None + self.config["SI5324_SOFT_RESET"] = None gtp = self.drtio_transceiver.gtps[0] txout_buf = Signal() @@ -573,9 +555,6 @@ class SatelliteBase(BaseSoC): platform.add_false_path_constraints( self.crg.cd_sys.clk, gtp.txoutclk, gtp.rxoutclk) - if with_wrpll: - platform.add_false_path_constraints( - helper_clk_pads.p, gtp.rxoutclk) for gtp in self.drtio_transceiver.gtps[1:]: platform.add_period_constraint(gtp.rxoutclk, rtio_clk_period) platform.add_false_path_constraints( @@ -652,7 +631,6 @@ def main(): parser.add_argument("-V", "--variant", default="tester", help="variant: {} (default: %(default)s)".format( "/".join(sorted(VARIANTS.keys())))) - parser.add_argument("--with-wrpll", default=False, action="store_true") parser.add_argument("--tester-dds", default=None, help="Tester variant DDS type: ad9910/ad9912 " "(default: ad9910)") @@ -661,8 +639,6 @@ def main(): args = parser.parse_args() argdict = dict() - if args.with_wrpll: - argdict["with_wrpll"] = True argdict["gateware_identifier_str"] = args.gateware_identifier_str argdict["dds"] = args.tester_dds diff --git a/artiq/gateware/test/wrpll/__init__.py b/artiq/gateware/test/wrpll/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/artiq/gateware/test/wrpll/test_dsp.py b/artiq/gateware/test/wrpll/test_dsp.py deleted file mode 100644 index 033e69853..000000000 --- a/artiq/gateware/test/wrpll/test_dsp.py +++ /dev/null @@ -1,158 +0,0 @@ -import unittest - -import numpy as np - -from migen import * - -from artiq.gateware.drtio.wrpll.ddmtd import Collector -from artiq.gateware.drtio.wrpll import thls, filters - - -class HelperChainTB(Module): - def __init__(self, N): - self.tag_ref = Signal(N) - self.input_stb = Signal() - self.adpll = Signal((24, True)) - self.out_stb = Signal() - - ### - - self.submodules.collector = Collector(N) - self.submodules.loop_filter = thls.make(filters.helper, data_width=48) - - self.comb += [ - self.collector.tag_ref.eq(self.tag_ref), - self.collector.ref_stb.eq(self.input_stb), - self.collector.main_stb.eq(self.input_stb), - self.loop_filter.input.eq(self.collector.out_helper << 22), - self.loop_filter.input_stb.eq(self.collector.out_stb), - self.adpll.eq(self.loop_filter.output), - self.out_stb.eq(self.loop_filter.output_stb), - ] - - -class TestDSP(unittest.TestCase): - def test_main_collector(self): - N = 2 - collector = Collector(N=N) - # check collector phase unwrapping - tags = [(0, 0, 0), - (0, 1, 1), - (2, 1, -1), - (3, 1, -2), - (0, 1, -3), - (1, 1, -4), - (2, 1, -5), - (3, 1, -6), - (3, 3, -4), - (0, 0, -4), - (0, 1, -3), - (0, 2, -2), - (0, 3, -1), - (0, 0, 0)] - for i in range(10): - tags.append((i % (2**N), (i+1) % (2**N), 1)) - - def generator(): - for tag_ref, tag_main, out in tags: - yield collector.tag_ref.eq(tag_ref) - yield collector.tag_main.eq(tag_main) - yield collector.main_stb.eq(1) - yield collector.ref_stb.eq(1) - - yield - - yield collector.main_stb.eq(0) - yield collector.ref_stb.eq(0) - - while not (yield collector.out_stb): - yield - - out_main = yield collector.out_main - self.assertEqual(out_main, out) - - run_simulation(collector, generator()) - - def test_helper_collector(self): - N = 3 - collector = Collector(N=N) - # check collector phase unwrapping - tags = [((2**N - 1 - tag) % (2**N), -1) for tag in range(20)] - tags += [((tags[-1][0] + 1 + tag) % (2**N), 1) for tag in range(20)] - tags += [((tags[-1][0] - 2 - 2*tag) % (2**N), -2) for tag in range(20)] - - def generator(): - for tag_ref, out in tags: - yield collector.tag_ref.eq(tag_ref) - yield collector.main_stb.eq(1) - yield collector.ref_stb.eq(1) - - yield - - yield collector.main_stb.eq(0) - yield collector.ref_stb.eq(0) - - while not (yield collector.out_stb): - yield - - out_helper = yield collector.out_helper - self.assertEqual(out_helper, out) - - run_simulation(collector, generator()) - - # test helper collector + filter against output from MATLAB model - def test_helper_chain(self): - pll = HelperChainTB(15) - - initial_helper_out = -8000 - ref_tags = np.array([ - 24778, 16789, 8801, 814, 25596, 17612, 9628, 1646, - 26433, 18453, 10474, 2496, 27287, 19311, 11337, 3364, 28160, - 20190, 12221, 4253, 29054, 21088, 13124, 5161, 29966, 22005, - 14045, 6087, 30897, 22940, 14985, 7031, 31847, 23895, 15944, - 7995, 47, 24869, 16923, 8978, 1035, 25861, 17920, 9981, - 2042, 26873, 18937, 11002, 3069, 27904, 19973, 12042, 4113, - 28953, 21026, 13100, 5175, 30020, 22098, 14177, 6257, 31106, - 23189, 15273, 7358, 32212, 24300, 16388, 8478, 569, 25429, - 17522, 9617, 1712, 26577, 18675, 10774, 2875, 27745, 19848, - 11951, 4056, 28930, 21038, 13147, 5256, 30135, 22247, 14361, - 6475, 31359, 23476, 15595, 7714, 32603, 24725, 16847, 8971, - 1096 - ]) - adpll_sim = np.array([ - 8, 24, 41, 57, 74, 91, 107, 124, 140, 157, 173, - 190, 206, 223, 239, 256, 273, 289, 306, 322, 339, 355, - 372, 388, 405, 421, 438, 454, 471, 487, 504, 520, 537, - 553, 570, 586, 603, 619, 636, 652, 668, 685, 701, 718, - 734, 751, 767, 784, 800, 817, 833, 850, 866, 882, 899, - 915, 932, 948, 965, 981, 998, 1014, 1030, 1047, 1063, 1080, - 1096, 1112, 1129, 1145, 1162, 1178, 1194, 1211, 1227, 1244, 1260, - 1276, 1293, 1309, 1326, 1342, 1358, 1375, 1391, 1407, 1424, 1440, - 1457, 1473, 1489, 1506, 1522, 1538, 1555, 1571, 1587, 1604, 1620, - 1636]) - - def sim(): - yield pll.collector.out_helper.eq(initial_helper_out) - for ref_tag, adpll_matlab in zip(ref_tags, adpll_sim): - # feed collector - yield pll.tag_ref.eq(int(ref_tag)) - yield pll.input_stb.eq(1) - - yield - - yield pll.input_stb.eq(0) - - while not (yield pll.collector.out_stb): - yield - - tag_diff = yield pll.collector.out_helper - - while not (yield pll.loop_filter.output_stb): - yield - - adpll_migen = yield pll.adpll - self.assertEqual(adpll_migen, adpll_matlab) - - yield - - run_simulation(pll, [sim()]) diff --git a/artiq/gateware/test/wrpll/test_thls.py b/artiq/gateware/test/wrpll/test_thls.py deleted file mode 100644 index c1013de30..000000000 --- a/artiq/gateware/test/wrpll/test_thls.py +++ /dev/null @@ -1,55 +0,0 @@ -import unittest - -from migen import * - -from artiq.gateware.drtio.wrpll import thls - - -a = 0 - -def simple_test(x): - global a - a = a + (x*4 >> 1) - return a - - -class TestTHLS(unittest.TestCase): - def test_thls(self): - global a - - proc = thls.Processor() - a = 0 - cp = thls.compile(proc, simple_test) - print("Program:") - cp.pretty_print() - cp.dimension_processor() - print("Encoded program:", cp.encode()) - proc_impl = proc.implement(cp.encode(), cp.data) - - def send_values(values): - for value in values: - yield proc_impl.input.eq(value) - yield proc_impl.input_stb.eq(1) - yield - yield proc_impl.input.eq(0) - yield proc_impl.input_stb.eq(0) - yield - while (yield proc_impl.busy): - yield - @passive - def receive_values(callback): - while True: - while not (yield proc_impl.output_stb): - yield - callback((yield proc_impl.output)) - yield - - send_list = [42, 40, 10, 10] - receive_list = [] - - run_simulation(proc_impl, [send_values(send_list), receive_values(receive_list.append)]) - print("Execution:", send_list, "->", receive_list) - - a = 0 - expected_list = [simple_test(x) for x in send_list] - self.assertEqual(receive_list, expected_list) diff --git a/doc/wrpll_diagram.png b/doc/wrpll_diagram.png deleted file mode 100644 index 1085e0b15335dc913758370250c819caa810a42a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58653 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

25xcf?lM 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 Date: Fri, 6 Jan 2023 17:59:18 +0800 Subject: [PATCH 55/85] remove RTIOClockMultiplier --- artiq/gateware/rtio/xilinx_clocking.py | 36 -------------------------- artiq/gateware/targets/kc705.py | 2 +- 2 files changed, 1 insertion(+), 37 deletions(-) diff --git a/artiq/gateware/rtio/xilinx_clocking.py b/artiq/gateware/rtio/xilinx_clocking.py index 20e0c36c6..aff4786bf 100644 --- a/artiq/gateware/rtio/xilinx_clocking.py +++ b/artiq/gateware/rtio/xilinx_clocking.py @@ -1,39 +1,3 @@ -from migen import * -from migen.genlib.cdc import MultiReg -from misoc.interconnect.csr import * - - -class RTIOClockMultiplier(Module, AutoCSR): - def __init__(self, rtio_clk_freq): - self.pll_reset = CSRStorage(reset=1) - self.pll_locked = CSRStatus() - self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) - - # See "Global Clock Network Deskew Using Two BUFGs" in ug472. - clkfbout = Signal() - clkfbin = Signal() - rtiox4_clk = Signal() - pll_locked = Signal() - self.specials += [ - Instance("MMCME2_BASE", - p_CLKIN1_PERIOD=1e9/rtio_clk_freq, - i_CLKIN1=ClockSignal("sys"), - i_RST=self.pll_reset.storage, - o_LOCKED=pll_locked, - - p_CLKFBOUT_MULT_F=8.0, p_DIVCLK_DIVIDE=1, - - o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbin, - - p_CLKOUT0_DIVIDE_F=2.0, o_CLKOUT0=rtiox4_clk, - ), - Instance("BUFG", i_I=clkfbout, o_O=clkfbin), - Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk), - - MultiReg(pll_locked, self.pll_locked.status) - ] - - def fix_serdes_timing_path(platform): # ignore timing of path from OSERDESE2 through the pad to ISERDESE2 platform.add_platform_command( diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 3ad5f5bdf..037b9f108 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -17,7 +17,7 @@ from misoc.integration.builder import builder_args, builder_argdict from artiq.gateware.amp import AMPSoC from artiq.gateware import rtio, nist_clock, nist_qc2 from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, dds, spi2 -from artiq.gateware.rtio.xilinx_clocking import RTIOClockMultiplier, fix_serdes_timing_path +from artiq.gateware.rtio.xilinx_clocking import fix_serdes_timing_path from artiq.gateware.drtio.transceiver import gtx_7series from artiq.gateware.drtio.siphaser import SiPhaser7Series from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer From ec893222a444dee480d05e6d4e526d03cd4acafd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 6 Jan 2023 18:22:05 +0800 Subject: [PATCH 56/85] rtio: remove support for async mode --- artiq/gateware/drtio/core.py | 4 +- artiq/gateware/rtio/core.py | 4 +- artiq/gateware/rtio/cri.py | 22 +++------ artiq/gateware/rtio/input_collector.py | 36 ++++----------- artiq/gateware/rtio/sed/core.py | 46 ++++++------------- artiq/gateware/rtio/sed/fifos.py | 16 ++----- artiq/gateware/rtio/tsc.py | 2 +- artiq/gateware/targets/kasli.py | 8 ++-- artiq/gateware/targets/kc705.py | 8 ++-- artiq/gateware/test/drtio/test_full_stack.py | 2 +- artiq/gateware/test/drtio/test_switching.py | 4 +- artiq/gateware/test/rtio/test_dma.py | 2 +- .../test/rtio/test_input_collector.py | 4 +- artiq/gateware/test/rtio/test_sed_top.py | 2 +- 14 files changed, 53 insertions(+), 107 deletions(-) diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index e8ca07e3f..434751ccc 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -58,7 +58,7 @@ class SyncRTIO(Module): assert tsc.glbl_fine_ts_width >= chan_fine_ts_width self.submodules.outputs = ClockDomainsRenamer("rio")( - SED(channels, tsc.glbl_fine_ts_width, "sync", + SED(channels, tsc.glbl_fine_ts_width, lane_count=lane_count, fifo_depth=fifo_depth, enable_spread=False, report_buffer_space=True, interface=self.cri)) @@ -66,7 +66,7 @@ class SyncRTIO(Module): self.sync += self.outputs.minimum_coarse_timestamp.eq(tsc.coarse_ts + 16) self.submodules.inputs = ClockDomainsRenamer("rio")( - InputCollector(tsc, channels, "sync", interface=self.cri)) + InputCollector(tsc, channels, interface=self.cri)) for attr, _ in async_errors_layout: self.comb += getattr(self.async_errors, attr).eq(getattr(self.outputs, attr)) diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index 66144ceca..c4dae4dc1 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -60,7 +60,7 @@ class Core(Module, AutoCSR): # Outputs/Inputs quash_channels = [n for n, c in enumerate(channels) if isinstance(c, LogChannel)] - outputs = SED(channels, tsc.glbl_fine_ts_width, "sync", + outputs = SED(channels, tsc.glbl_fine_ts_width, quash_channels=quash_channels, lane_count=lane_count, fifo_depth=fifo_depth, interface=self.cri) @@ -68,7 +68,7 @@ class Core(Module, AutoCSR): self.comb += outputs.coarse_timestamp.eq(tsc.coarse_ts) self.sync += outputs.minimum_coarse_timestamp.eq(tsc.coarse_ts + 16) - inputs = InputCollector(tsc, channels, "sync", + inputs = InputCollector(tsc, channels, quash_channels=quash_channels, interface=self.cri) self.submodules += inputs diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index 8b38f4529..41bd20eeb 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -127,7 +127,7 @@ class KernelInitiator(Module, AutoCSR): class CRIDecoder(Module): - def __init__(self, slaves=2, master=None, mode="async", enable_routing=False): + def __init__(self, slaves=2, master=None, enable_routing=False): if isinstance(slaves, int): slaves = [Interface() for _ in range(slaves)] if master is None: @@ -155,10 +155,7 @@ class CRIDecoder(Module): if enable_routing: self.specials.routing_table = Memory(slave_bits, 256) - if mode == "async" or mode == "sync": - rtp_decoder = self.routing_table.get_port() - else: - raise ValueError + rtp_decoder = self.routing_table.get_port() self.specials += rtp_decoder self.comb += [ rtp_decoder.adr.eq(self.master.chan_sel[16:]), @@ -185,7 +182,7 @@ class CRIDecoder(Module): class CRISwitch(Module, AutoCSR): - def __init__(self, masters=2, slave=None, mode="async"): + def __init__(self, masters=2, slave=None): if isinstance(masters, int): masters = [Interface() for _ in range(masters)] if slave is None: @@ -197,11 +194,6 @@ class CRISwitch(Module, AutoCSR): # # # - if mode == "async" or mode == "sync": - selected = self.selected.storage - else: - raise ValueError - if len(masters) == 1: self.comb += masters[0].connect(slave) else: @@ -209,7 +201,7 @@ class CRISwitch(Module, AutoCSR): for name, size, direction in layout: if direction == DIR_M_TO_S: choices = Array(getattr(m, name) for m in masters) - self.comb += getattr(slave, name).eq(choices[selected]) + self.comb += getattr(slave, name).eq(choices[self.selected.storage]) # connect slave->master signals for name, size, direction in layout: @@ -221,10 +213,10 @@ class CRISwitch(Module, AutoCSR): class CRIInterconnectShared(Module): - def __init__(self, masters=2, slaves=2, mode="async", enable_routing=False): + def __init__(self, masters=2, slaves=2, enable_routing=False): shared = Interface() - self.submodules.switch = CRISwitch(masters, shared, mode) - self.submodules.decoder = CRIDecoder(slaves, shared, mode, enable_routing) + self.submodules.switch = CRISwitch(masters, shared) + self.submodules.decoder = CRIDecoder(slaves, shared, enable_routing) def get_csrs(self): return self.switch.get_csrs() diff --git a/artiq/gateware/rtio/input_collector.py b/artiq/gateware/rtio/input_collector.py index a65fe6d9d..75c018c06 100644 --- a/artiq/gateware/rtio/input_collector.py +++ b/artiq/gateware/rtio/input_collector.py @@ -1,6 +1,6 @@ from migen import * from migen.genlib.record import Record -from migen.genlib.fifo import * +from migen.genlib.fifo import SyncFIFOBuffered from migen.genlib.cdc import BlindTransfer from artiq.gateware.rtio import cri @@ -24,24 +24,13 @@ def get_channel_layout(coarse_ts_width, interface): class InputCollector(Module): - def __init__(self, tsc, channels, mode, quash_channels=[], interface=None): + def __init__(self, tsc, channels, quash_channels=[], interface=None): if interface is None: interface = cri.Interface() self.cri = interface # # # - if mode == "sync": - fifo_factory = SyncFIFOBuffered - sync_io = self.sync - sync_cri = self.sync - elif mode == "async": - fifo_factory = lambda *args: ClockDomainsRenamer({"write": "rio", "read": "sys"})(AsyncFIFO(*args)) - sync_io = self.sync.rio - sync_cri = self.sync.sys - else: - raise ValueError - i_statuses, i_datas, i_timestamps = [], [], [] i_ack = Signal() sel = self.cri.chan_sel[:16] @@ -55,7 +44,7 @@ class InputCollector(Module): # FIFO layout = get_channel_layout(len(tsc.coarse_ts), iif) - fifo = fifo_factory(layout_len(layout), channel.ififo_depth) + fifo = SyncFIFOBuffered(layout_len(layout), channel.ififo_depth) self.submodules += fifo fifo_in = Record(layout) fifo_out = Record(layout) @@ -67,7 +56,7 @@ class InputCollector(Module): # FIFO write if iif.delay: counter_rtio = Signal.like(tsc.coarse_ts, reset_less=True) - sync_io += counter_rtio.eq(tsc.coarse_ts - (iif.delay + 1)) + self.sync += counter_rtio.eq(tsc.coarse_ts - (iif.delay + 1)) else: counter_rtio = tsc.coarse_ts if hasattr(fifo_in, "data"): @@ -80,17 +69,8 @@ class InputCollector(Module): self.comb += fifo_in.timestamp.eq(full_ts) self.comb += fifo.we.eq(iif.stb) - overflow_io = Signal() - self.comb += overflow_io.eq(fifo.we & ~fifo.writable) - if mode == "sync": - overflow_trigger = overflow_io - elif mode == "async": - overflow_transfer = BlindTransfer("rio", "sys") - self.submodules += overflow_transfer - self.comb += overflow_transfer.i.eq(overflow_io) - overflow_trigger = overflow_transfer.o - else: - raise ValueError + overflow_trigger = Signal() + self.comb += overflow_trigger.eq(fifo.we & ~fifo.writable) # FIFO read, CRI connection if hasattr(fifo_out, "data"): @@ -107,7 +87,7 @@ class InputCollector(Module): self.comb += selected.eq(sel == n) overflow = Signal() - sync_cri += [ + self.sync += [ If(selected & i_ack, overflow.eq(0)), If(overflow_trigger, @@ -122,7 +102,7 @@ class InputCollector(Module): input_pending = Signal() self.cri.i_data.reset_less = True self.cri.i_timestamp.reset_less = True - sync_cri += [ + self.sync += [ i_ack.eq(0), If(i_ack, self.cri.i_status.eq(Cat(~i_status_raw[0], i_status_raw[1], 0)), diff --git a/artiq/gateware/rtio/sed/core.py b/artiq/gateware/rtio/sed/core.py index 2b3611854..8953ff9d2 100644 --- a/artiq/gateware/rtio/sed/core.py +++ b/artiq/gateware/rtio/sed/core.py @@ -11,41 +11,25 @@ __all__ = ["SED"] class SED(Module): - def __init__(self, channels, glbl_fine_ts_width, mode, + def __init__(self, channels, glbl_fine_ts_width, lane_count=8, fifo_depth=128, enable_spread=True, quash_channels=[], report_buffer_space=False, interface=None): - if mode == "sync": - lane_dist_cdr = lambda x: x - fifos_cdr = lambda x: x - gates_cdr = lambda x: x - output_driver_cdr = lambda x: x - elif mode == "async": - lane_dist_cdr = ClockDomainsRenamer("sys") - fifos_cdr = ClockDomainsRenamer({"write": "sys", "read": "rio"}) - gates_cdr = ClockDomainsRenamer("rio") - output_driver_cdr = ClockDomainsRenamer("rio") - else: - raise ValueError - seqn_width = layouts.seqn_width(lane_count, fifo_depth) - self.submodules.lane_dist = lane_dist_cdr( - LaneDistributor(lane_count, seqn_width, - layouts.fifo_payload(channels), - [channel.interface.o.delay for channel in channels], - glbl_fine_ts_width, - enable_spread=enable_spread, - quash_channels=quash_channels, - interface=interface)) - self.submodules.fifos = fifos_cdr( - FIFOs(lane_count, fifo_depth, - layouts.fifo_payload(channels), mode, report_buffer_space)) - self.submodules.gates = gates_cdr( - Gates(lane_count, seqn_width, - layouts.fifo_payload(channels), - layouts.output_network_payload(channels, glbl_fine_ts_width))) - self.submodules.output_driver = output_driver_cdr( - OutputDriver(channels, glbl_fine_ts_width, lane_count, seqn_width)) + self.submodules.lane_dist = LaneDistributor(lane_count, seqn_width, + layouts.fifo_payload(channels), + [channel.interface.o.delay for channel in channels], + glbl_fine_ts_width, + enable_spread=enable_spread, + quash_channels=quash_channels, + interface=interface) + self.submodules.fifos = FIFOs(lane_count, fifo_depth, + layouts.fifo_payload(channels), report_buffer_space) + self.submodules.gates = Gates(lane_count, seqn_width, + layouts.fifo_payload(channels), + layouts.output_network_payload(channels, glbl_fine_ts_width)) + self.submodules.output_driver = OutputDriver(channels, glbl_fine_ts_width, + lane_count, seqn_width) for o, i in zip(self.lane_dist.output, self.fifos.input): self.comb += o.connect(i) diff --git a/artiq/gateware/rtio/sed/fifos.py b/artiq/gateware/rtio/sed/fifos.py index cbecccf07..3bf1bfc5a 100644 --- a/artiq/gateware/rtio/sed/fifos.py +++ b/artiq/gateware/rtio/sed/fifos.py @@ -2,7 +2,7 @@ from operator import or_ from functools import reduce from migen import * -from migen.genlib.fifo import * +from migen.genlib.fifo import SyncFIFOBuffered from artiq.gateware.rtio.sed import layouts @@ -11,7 +11,7 @@ __all__ = ["FIFOs"] class FIFOs(Module): - def __init__(self, lane_count, fifo_depth, layout_payload, mode, report_buffer_space=False): + def __init__(self, lane_count, fifo_depth, layout_payload, report_buffer_space=False): seqn_width = layouts.seqn_width(lane_count, fifo_depth) self.input = [Record(layouts.fifo_ingress(seqn_width, layout_payload)) for _ in range(lane_count)] @@ -23,16 +23,9 @@ class FIFOs(Module): # # # - if mode == "sync": - fifo_cls = SyncFIFOBuffered - elif mode == "async": - fifo_cls = AsyncFIFOBuffered - else: - raise ValueError - fifos = [] for input, output in zip(self.input, self.output): - fifo = fifo_cls(seqn_width + layout_len(layout_payload), fifo_depth) + fifo = SyncFIFOBuffered(seqn_width + layout_len(layout_payload), fifo_depth) self.submodules += fifo fifos.append(fifo) @@ -47,9 +40,6 @@ class FIFOs(Module): ] if report_buffer_space: - if mode != "sync": - raise NotImplementedError - def compute_max(elts): l = len(elts) if l == 1: diff --git a/artiq/gateware/rtio/tsc.py b/artiq/gateware/rtio/tsc.py index f2c316047..063583a3d 100644 --- a/artiq/gateware/rtio/tsc.py +++ b/artiq/gateware/rtio/tsc.py @@ -1,7 +1,7 @@ from migen import * class TSC(Module): - def __init__(self, mode, glbl_fine_ts_width=0): + def __init__(self, glbl_fine_ts_width=0): self.glbl_fine_ts_width = glbl_fine_ts_width # in rtio domain diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 448faefd7..1d33c6e2a 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -102,7 +102,7 @@ class StandaloneBase(MiniSoC, AMPSoC): def add_rtio(self, rtio_channels, sed_lanes=8): fix_serdes_timing_path(self.platform) - self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) + self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3) self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels, lane_count=sed_lanes) self.csr_devices.append("rtio_core") self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc) @@ -286,7 +286,7 @@ class MasterBase(MiniSoC, AMPSoC): self.comb += [self.virtual_leds.get(i + 1).eq(channel.rx_ready) for i, channel in enumerate(sfp_channels)] - self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) + self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3) drtio_csr_group = [] drtioaux_csr_group = [] @@ -480,7 +480,7 @@ class SatelliteBase(BaseSoC): self.comb += [self.virtual_leds.get(i).eq(channel.rx_ready) for i, channel in enumerate(sfp_channels)] - self.submodules.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) + self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3) drtioaux_csr_group = [] drtioaux_memory_group = [] @@ -573,7 +573,7 @@ class SatelliteBase(BaseSoC): self.submodules.cri_con = rtio.CRIInterconnectShared( [self.drtiosat.cri], [self.local_io.cri] + self.drtio_cri, - mode="sync", enable_routing=True) + enable_routing=True) self.csr_devices.append("cri_con") self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con) self.csr_devices.append("routing_table") diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 037b9f108..4aac6e2ce 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -149,7 +149,7 @@ class _StandaloneBase(MiniSoC, AMPSoC): self.config["HAS_DDS"] = None def add_rtio(self, rtio_channels): - self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) + self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3) 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) @@ -218,7 +218,7 @@ class _MasterBase(MiniSoC, AMPSoC): clk_freq=self.clk_freq) self.csr_devices.append("drtio_transceiver") - self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) + self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3) drtio_csr_group = [] drtioaux_csr_group = [] @@ -358,7 +358,7 @@ class _SatelliteBase(BaseSoC): clk_freq=self.clk_freq) self.csr_devices.append("drtio_transceiver") - self.submodules.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) + self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3) drtioaux_csr_group = [] drtioaux_memory_group = [] @@ -456,7 +456,7 @@ class _SatelliteBase(BaseSoC): self.submodules.cri_con = rtio.CRIInterconnectShared( [self.drtiosat.cri], [self.local_io.cri] + self.drtio_cri, - mode="sync", enable_routing=True) + enable_routing=True) self.csr_devices.append("cri_con") self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con) self.csr_devices.append("routing_table") diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index 7cafe16a1..ade67f5a9 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -67,7 +67,7 @@ class DUT(Module): rtio.Channel.from_phy(self.phy1), rtio.Channel.from_phy(self.phy2), ] - self.submodules.tsc_satellite = rtio.TSC("sync") + self.submodules.tsc_satellite = rtio.TSC() self.submodules.satellite = DRTIOSatellite( self.tsc_satellite, self.transceivers.bob, rx_synchronizer) self.satellite.reset.storage.reset = 0 diff --git a/artiq/gateware/test/drtio/test_switching.py b/artiq/gateware/test/drtio/test_switching.py index 1f7876ade..942ff0c0e 100644 --- a/artiq/gateware/test/drtio/test_switching.py +++ b/artiq/gateware/test/drtio/test_switching.py @@ -40,12 +40,12 @@ class DUT(Module): def __init__(self, nwords): self.transceivers = DummyTransceiverPair(nwords) - self.submodules.tsc_master = rtio.TSC("async") + self.submodules.tsc_master = rtio.TSC() self.submodules.master = DRTIOMaster(self.tsc_master, self.transceivers.alice) rx_synchronizer = DummyRXSynchronizer() - self.submodules.tsc_satellite = rtio.TSC("sync") + self.submodules.tsc_satellite = rtio.TSC() self.submodules.satellite = DRTIOSatellite( self.tsc_satellite, self.transceivers.bob, rx_synchronizer) self.satellite.reset.storage.reset = 0 diff --git a/artiq/gateware/test/rtio/test_dma.py b/artiq/gateware/test/rtio/test_dma.py index a8ccac564..692e5be17 100644 --- a/artiq/gateware/test/rtio/test_dma.py +++ b/artiq/gateware/test/rtio/test_dma.py @@ -128,7 +128,7 @@ class FullStackTB(Module): self.submodules.memory = wishbone.SRAM( 256, init=sequence, bus=bus) self.submodules.dut = dma.DMA(bus, dw) - self.submodules.tsc = rtio.TSC("async") + self.submodules.tsc = rtio.TSC() self.submodules.rtio = rtio.Core(self.tsc, rtio_channels) self.comb += self.dut.cri.connect(self.rtio.cri) diff --git a/artiq/gateware/test/rtio/test_input_collector.py b/artiq/gateware/test/rtio/test_input_collector.py index bf68a17e4..5f8c7b262 100644 --- a/artiq/gateware/test/rtio/test_input_collector.py +++ b/artiq/gateware/test/rtio/test_input_collector.py @@ -38,8 +38,8 @@ class DUT(Module): rtio.Channel.from_phy(self.phy0, ififo_depth=4), rtio.Channel.from_phy(self.phy1, ififo_depth=4) ] - self.submodules.tsc = ClockDomainsRenamer({"rtio": "sys"})(rtio.TSC("sync")) - self.submodules.input_collector = InputCollector(self.tsc, rtio_channels, "sync") + self.submodules.tsc = rtio.TSC() + self.submodules.input_collector = InputCollector(self.tsc, rtio_channels) @property def cri(self): diff --git a/artiq/gateware/test/rtio/test_sed_top.py b/artiq/gateware/test/rtio/test_sed_top.py index 5efc257a0..5c5002fd3 100644 --- a/artiq/gateware/test/rtio/test_sed_top.py +++ b/artiq/gateware/test/rtio/test_sed_top.py @@ -22,7 +22,7 @@ class DUT(Module): rtio.Channel.from_phy(self.phy1) ] - self.submodules.sed = SED(rtio_channels, 0, "sync", **kwargs) + self.submodules.sed = SED(rtio_channels, 0, **kwargs) self.sync += [ self.sed.coarse_timestamp.eq(self.sed.coarse_timestamp + 1), self.sed.minimum_coarse_timestamp.eq(self.sed.coarse_timestamp + 16) From 7dafdfe2f7d2ba26bfc090f9d630563c955bea0f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 5 Mar 2022 22:43:25 +0800 Subject: [PATCH 57/85] artiq_flash: fix bit2bin --- artiq/frontend/artiq_flash.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 96203fa83..136b58c71 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -280,10 +280,7 @@ def main(): def convert_gateware(bit_filename): bin_handle, bin_filename = tempfile.mkstemp( prefix="artiq_", suffix="_" + os.path.basename(bit_filename)) - with open(bit_filename, "rb") as bit_file, \ - open(bin_handle, "wb") as bin_file: - if header: - bin_file.write(b"\x00"*8) + with open(bit_filename, "rb") as bit_file, open(bin_handle, "wb") as bin_file: bit2bin(bit_file, bin_file) atexit.register(lambda: os.unlink(bin_filename)) return bin_filename From 63f1a6d197b823e054c5c58125e94485bfc17e73 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 6 Jan 2023 18:33:13 +0800 Subject: [PATCH 58/85] drtio: partially fix tests --- artiq/gateware/test/drtio/test_full_stack.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index ade67f5a9..4c7d367b2 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -52,7 +52,7 @@ class DUT(Module): self.ttl1 = Signal() self.transceivers = DummyTransceiverPair(nwords) - self.submodules.tsc_master = rtio.TSC("async") + self.submodules.tsc_master = rtio.TSC() self.submodules.master = DRTIOMaster(self.tsc_master, self.transceivers.alice) self.submodules.master_ki = rtio.KernelInitiator(self.tsc_master, @@ -144,8 +144,8 @@ class OutputsTestbench: class TestFullStack(unittest.TestCase): - clocks = {"sys": 8, "rtio_rx": 5, - "rio": 5, "rio_phy": 5} + clocks = {"sys": 8, "rtio_rx": 8, + "rio": 8, "rio_phy": 8} def test_pulses(self): tb = OutputsTestbench() From 070fed755bd1817ed2bb292d4a14a2ead5fc12e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=81=AB=E7=84=9A=20=E5=AF=8C=E8=89=AF?= Date: Mon, 9 Jan 2023 16:13:05 +0800 Subject: [PATCH 59/85] firmware: unify RTIO error message format --- artiq/firmware/runtime/rtio_mgt.rs | 12 ++++++------ artiq/firmware/runtime/session.rs | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 41dbcb42a..92aaaf66a 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -220,15 +220,15 @@ pub mod drtio { destination_set_up(routing_table, up_destinations, destination, false), Ok(drtioaux::Packet::DestinationOkReply) => (), Ok(drtioaux::Packet::DestinationSequenceErrorReply { channel }) => { - error!("[DEST#{}] RTIO sequence error involving channel {} 0x{:04x}", destination, resolve_channel_name(channel as u32), channel); + error!("[DEST#{}] RTIO sequence error involving channel 0x{:04x}:{}", destination, channel, resolve_channel_name(channel as u32)); unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_SEQUENCE_ERROR }; } Ok(drtioaux::Packet::DestinationCollisionReply { channel }) => { - error!("[DEST#{}] RTIO collision involving channel {} 0x{:04x}", destination, resolve_channel_name(channel as u32), channel); + error!("[DEST#{}] RTIO collision involving channel 0x{:04x}:{}", destination, channel, resolve_channel_name(channel as u32)); unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_COLLISION }; } Ok(drtioaux::Packet::DestinationBusyReply { channel }) => { - error!("[DEST#{}] RTIO busy error involving channel {} 0x{:04x}", destination, resolve_channel_name(channel as u32), channel); + error!("[DEST#{}] RTIO busy error involving channel 0x{:04x}:{}", destination, channel, resolve_channel_name(channel as u32)); unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_BUSY }; } Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet), @@ -355,15 +355,15 @@ fn async_error_thread(io: Io) { let errors = csr::rtio_core::async_error_read(); if errors & ASYNC_ERROR_COLLISION != 0 { let channel = csr::rtio_core::collision_channel_read(); - error!("RTIO collision involving channel {}:{}", channel, resolve_channel_name(channel as u32)); + error!("RTIO collision involving channel 0x{:04x}:{}", channel, resolve_channel_name(channel as u32)); } if errors & ASYNC_ERROR_BUSY != 0 { let channel = csr::rtio_core::busy_channel_read(); - error!("RTIO busy error involving channel {}:{}", channel, resolve_channel_name(channel as u32)); + error!("RTIO busy error involving channel 0x{:04x}:{}", channel, resolve_channel_name(channel as u32)); } if errors & ASYNC_ERROR_SEQUENCE_ERROR != 0 { let channel = csr::rtio_core::sequence_error_channel_read(); - error!("RTIO sequence error involving channel {}:{}", channel, resolve_channel_name(channel as u32)); + error!("RTIO sequence error involving channel 0x{:04x}:{}", channel, resolve_channel_name(channel as u32)); } SEEN_ASYNC_ERRORS = errors; csr::rtio_core::async_error_write(errors); diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index e942d7bd9..c0f009a96 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -457,7 +457,7 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex, } else { let msg = str::from_utf8(unsafe { slice::from_raw_parts(exn.message.as_ptr(), exn.message.len()) }) .unwrap() - .replace("{rtio_channel_info:0}", &format!("{}:{}", exn.param[0], resolve_channel_name(exn.param[0] as u32))); + .replace("{rtio_channel_info:0}", &format!("0x{:04x}:{}", exn.param[0], resolve_channel_name(exn.param[0] as u32))); Some(eh::eh_artiq::Exception { id: exn.id, file: exn.file, From eb3742fb08e0b2f1f3b294fd76cf7a51dc42a253 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Mon, 9 Jan 2023 18:15:58 +0800 Subject: [PATCH 60/85] kc705: do not reset si5324 during clock switch --- artiq/gateware/targets/kc705.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 4aac6e2ce..a686622b0 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -113,7 +113,7 @@ class _StandaloneBase(MiniSoC, AMPSoC): 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.submodules.si5324_rst_n = gpio.GPIOOut(self.platform.request("si5324_33").rst_n, reset_out=1) self.csr_devices.append("si5324_rst_n") self.specials += [ Instance("IBUFDS_GTE2", @@ -255,7 +255,7 @@ class _MasterBase(MiniSoC, AMPSoC): self.add_memory_group("drtioaux_mem", drtioaux_memory_group) self.config["RTIO_FREQUENCY"] = str(self.drtio_transceiver.rtio_clk_freq/1e6) - self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324_33").rst_n) + self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324_33").rst_n, reset_out=1) self.csr_devices.append("si5324_rst_n") i2c = self.platform.request("i2c") self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) @@ -414,7 +414,7 @@ class _SatelliteBase(BaseSoC): platform.add_false_path_constraints( self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) self.csr_devices.append("siphaser") - self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324_33").rst_n) + self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324_33").rst_n, reset_out=1) self.csr_devices.append("si5324_rst_n") i2c = self.platform.request("i2c") self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) From b9bfe090f4f356c8bfb46d255c88fb99cc9b70d7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 9 Jan 2023 18:22:05 +0800 Subject: [PATCH 61/85] flake: cleanup --- flake.nix | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index fe351a3cb..e9eab352b 100644 --- a/flake.nix +++ b/flake.nix @@ -436,7 +436,7 @@ hydraJobs = { inherit (packages.x86_64-linux) artiq artiq-board-kc705-nist_clock openocd-bscanspi; - kc705-hitl = pkgs.stdenv.mkDerivation { + kc705-hitl = pkgs.stdenvNoCC.mkDerivation { name = "kc705-hitl"; __networked = true; # compatibility with old patched Nix @@ -453,7 +453,6 @@ phases = [ "buildPhase" ]; buildPhase = '' - whoami export HOME=`mktemp -d` mkdir $HOME/.ssh cp /opt/hydra_id_ed25519 $HOME/.ssh/id_ed25519 From cee9f3f44e2cd12562d56a289670927c04f641c9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 9 Jan 2023 18:36:55 +0800 Subject: [PATCH 62/85] flake: run gateware simulations --- flake.nix | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/flake.nix b/flake.nix index e9eab352b..8bcb6a21a 100644 --- a/flake.nix +++ b/flake.nix @@ -436,6 +436,18 @@ hydraJobs = { inherit (packages.x86_64-linux) artiq artiq-board-kc705-nist_clock openocd-bscanspi; + gateware-sim = pkgs.stdenvNoCC.mkDerivation { + name = "gateware-sim"; + buildInputs = [ + (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ migen misoc artiq ])) + ]; + phases = [ "buildPhase" ]; + buildPhase = + '' + python -m unittest discover -v artiq.gateware.test + touch $out + ''; + }; kc705-hitl = pkgs.stdenvNoCC.mkDerivation { name = "kc705-hitl"; From ea21f474a7fb3066626ea72a60cd93d3037c3376 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 9 Jan 2023 18:37:19 +0800 Subject: [PATCH 63/85] gateware: remove SAWG simulations --- artiq/gateware/test/dsp/__init__.py | 0 artiq/gateware/test/dsp/fir.py | 112 ---------- artiq/gateware/test/dsp/test_accu.py | 46 ---- artiq/gateware/test/dsp/test_satadd.py | 71 ------- artiq/gateware/test/dsp/test_sawg.py | 36 ---- artiq/gateware/test/dsp/test_sawg_fe.py | 255 ----------------------- artiq/gateware/test/dsp/test_sawg_phy.py | 70 ------- artiq/gateware/test/dsp/test_spline.py | 31 --- artiq/gateware/test/dsp/tools.py | 49 ----- 9 files changed, 670 deletions(-) delete mode 100644 artiq/gateware/test/dsp/__init__.py delete mode 100644 artiq/gateware/test/dsp/fir.py delete mode 100644 artiq/gateware/test/dsp/test_accu.py delete mode 100644 artiq/gateware/test/dsp/test_satadd.py delete mode 100644 artiq/gateware/test/dsp/test_sawg.py delete mode 100644 artiq/gateware/test/dsp/test_sawg_fe.py delete mode 100644 artiq/gateware/test/dsp/test_sawg_phy.py delete mode 100644 artiq/gateware/test/dsp/test_spline.py delete mode 100644 artiq/gateware/test/dsp/tools.py diff --git a/artiq/gateware/test/dsp/__init__.py b/artiq/gateware/test/dsp/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/artiq/gateware/test/dsp/fir.py b/artiq/gateware/test/dsp/fir.py deleted file mode 100644 index 31f5740b2..000000000 --- a/artiq/gateware/test/dsp/fir.py +++ /dev/null @@ -1,112 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt - -from migen import * -from migen.fhdl import verilog -from artiq.gateware.dsp import fir - - -class Transfer(Module): - def __init__(self, dut): - self.submodules.dut = dut - - def drive(self, x): - for xi in x.reshape(-1, self.dut.parallelism): - yield [ij.eq(int(xj)) for ij, xj in zip(self.dut.i, xi)] - yield - - def record(self, y): - for i in range(self.dut.latency): - yield - for yi in y.reshape(-1, self.dut.parallelism): - yield - yi[:] = (yield from [(yield o) for o in self.dut.o]) - - def run(self, samples, amplitude=1., seed=None): - if seed is not None: - np.random.seed(seed) - w = 2**(self.dut.width - 1) - 1 - x = np.round(np.random.uniform( - -amplitude*w, amplitude*w, samples)) - y = self.run_data(x) - x /= w - y /= w - return x, y - - def run_data(self, x): - y = np.empty_like(x) - run_simulation(self, [self.drive(x), self.record(y)], - vcd_name="fir.vcd") - return y - - def analyze(self, x, y): - fig, ax = plt.subplots(3) - ax[0].plot(x, "c-.", label="input") - ax[0].plot(y, "r-", label="output") - ax[0].legend(loc="right") - ax[0].set_xlabel("time (1/fs)") - ax[0].set_ylabel("signal") - n = len(x) - w = np.hanning(n) - x = (x.reshape(-1, n)*w).sum(0) - y = (y.reshape(-1, n)*w).sum(0) - t = (np.fft.rfft(y)/np.fft.rfft(x)) - f = np.fft.rfftfreq(n)*2 - fmin = f[1] - ax[1].plot(f, 20*np.log10(np.abs(t)), "r-") - ax[1].set_ylim(-70, 3) - ax[1].set_xlim(fmin, 1.) - # ax[1].set_xscale("log") - ax[1].set_xlabel("frequency (fs/2)") - ax[1].set_ylabel("magnitude (dB)") - ax[1].grid(True) - ax[2].plot(f, np.rad2deg(np.angle(t)), "r-") - ax[2].set_xlim(fmin, 1.) - # ax[2].set_xscale("log") - ax[2].set_xlabel("frequency (fs/2)") - ax[2].set_ylabel("phase (deg)") - ax[2].grid(True) - return fig - - -class UpTransfer(Transfer): - def drive(self, x): - x = x.reshape(-1, len(self.dut.o)) - x[:, 1:] = 0 - for xi in x: - yield self.dut.i.eq(int(xi[0])) - yield - - def record(self, y): - for i in range(self.dut.latency): - yield - for yi in y.reshape(-1, len(self.dut.o)): - yield - yi[:] = (yield from [(yield o) for o in self.dut.o]) - - -def _main(): - if True: - coeff = fir.halfgen4_cascade(2, width=.4, order=8) - dut = fir.ParallelHBFUpsampler(coeff, width=16) - # print(verilog.convert(dut, ios=set([dut.i] + dut.o))) - tb = UpTransfer(dut) - else: - coeff = fir.halfgen4(.4/2, 8) - dut = fir.ParallelFIR(coeff, parallelism=4, width=16) - # print(verilog.convert(dut, ios=set(dut.i + dut.o))) - tb = Transfer(dut) - - if True: - x, y = tb.run(samples=1 << 10, amplitude=.5, seed=0x1234567) - else: - x = np.zeros(100) - x[:50] = 1 << 8 - x[50:] = 1 << 13 - y = tb.run_data(x) - tb.analyze(x, y) - plt.show() - - -if __name__ == "__main__": - _main() diff --git a/artiq/gateware/test/dsp/test_accu.py b/artiq/gateware/test/dsp/test_accu.py deleted file mode 100644 index 384fba9cc..000000000 --- a/artiq/gateware/test/dsp/test_accu.py +++ /dev/null @@ -1,46 +0,0 @@ -import numpy as np - -from migen import * -from migen.fhdl.verilog import convert - -from artiq.gateware.dsp.accu import Accu, PhasedAccu -from .tools import xfer - - -def read(o, n): - p = [] - for i in range(n): - p.append((yield from [(yield pi) for pi in o.payload.flatten()])) - yield - return p - - -def _test_gen_accu(dut, o): - yield dut.o.ack.eq(1) - yield from xfer(dut, i=dict(p=0, f=1, clr=1)) - o.extend((yield from read(dut.o, 8))) - yield from xfer(dut, i=dict(p=0, f=2, clr=0)) - o.extend((yield from read(dut.o, 8))) - yield from xfer(dut, i=dict(p=0, f=2, clr=1)) - o.extend((yield from read(dut.o, 8))) - yield from xfer(dut, i=dict(p=8, f=-1, clr=1)) - o.extend((yield from read(dut.o, 8))) - yield from xfer(dut, i=dict(p=0, f=0, clr=1)) - yield from xfer(dut, i=dict(p=1, f=0, clr=0)) - o.extend((yield from read(dut.o, 8))) - - -def _test_accu(): - dut = PhasedAccu(8, parallelism=8) - - if False: - print(convert(dut)) - else: - o = [] - run_simulation(dut, _test_gen_accu(dut, o), vcd_name="accu.vcd") - o = np.array(o) - print(o) - - -if __name__ == "__main__": - _test_accu() diff --git a/artiq/gateware/test/dsp/test_satadd.py b/artiq/gateware/test/dsp/test_satadd.py deleted file mode 100644 index 2121d4287..000000000 --- a/artiq/gateware/test/dsp/test_satadd.py +++ /dev/null @@ -1,71 +0,0 @@ -import unittest -import migen as mg - -from artiq.gateware.dsp.tools import SatAddMixin - - -class DUT(mg.Module, SatAddMixin): - def __init__(self, width): - self.o = mg.Signal((width, True)) - self.i0 = mg.Signal.like(self.o) - self.i1 = mg.Signal.like(self.o) - self.l0 = mg.Signal.like(self.o) - self.l1 = mg.Signal.like(self.o) - self.c = mg.Signal(2) - self.comb += self.o.eq(self.sat_add((self.i0, self.i1), - width=4, limits=(self.l0, self.l1), clipped=self.c)) - - -class SatAddTest(unittest.TestCase): - def setUp(self): - self.dut = DUT(width=4) - # import migen.fhdl.verilog - # print(mg.fhdl.verilog.convert(self.dut)) - - def _sweep(self): - def gen(): - for i0 in range(-8, 8): - yield self.dut.i0.eq(i0) - for i1 in range(-8, 8): - yield self.dut.i1.eq(i1) - yield - - def rec(): - l0 = yield self.dut.l0 - l1 = yield self.dut.l1 - for i in range(1 << 8): - i0 = yield self.dut.i0 - i1 = yield self.dut.i1 - o = yield self.dut.o - c = yield self.dut.c - - full = i0 + i1 - lim = full - clip = 0 - if full < l0: - lim = l0 - clip = 1 - if full > l1: - lim = l1 - clip = 2 - with self.subTest(i0=i0, i1=i1): - self.assertEqual(lim, o) - self.assertEqual(clip, c) - yield - - mg.run_simulation(self.dut, (gen(), rec())) - - def test_inst(self): - pass - - def test_run(self): - self._sweep() - - def test_limits(self): - for l0 in -8, 0, 1, 7: - for l1 in -8, 0, 1, 7: - self.setUp() - self.dut.l0.reset = l0 - self.dut.l1.reset = l1 - with self.subTest(l0=l0, l1=l1): - self._sweep() diff --git a/artiq/gateware/test/dsp/test_sawg.py b/artiq/gateware/test/dsp/test_sawg.py deleted file mode 100644 index fd392607d..000000000 --- a/artiq/gateware/test/dsp/test_sawg.py +++ /dev/null @@ -1,36 +0,0 @@ -import numpy as np - -from migen import * -from migen.fhdl.verilog import convert - -from artiq.gateware.dsp import sawg -from artiq.gateware.test.dsp.tools import xfer - - -def _test_gen_dds(dut, o): - yield from xfer(dut, - a=dict(a0=10), - p=dict(a0=0), - f=dict(a0=1), - ) - for i in range(256//dut.parallelism): - yield - o.append((yield from [(yield _) for _ in dut.xo])) - - -def _test_channel(): - widths = sawg._Widths(t=8, a=4*8, p=8, f=16) - orders = sawg._Orders(a=4, p=1, f=2) - dut = sawg.SplineParallelDDS(widths, orders, parallelism=2) - - if False: - print(convert(dut)) - else: - o = [] - run_simulation(dut, _test_gen_dds(dut, o), vcd_name="dds.vcd") - o = np.array(o) - print(o[:, :]) - - -if __name__ == "__main__": - _test_channel() diff --git a/artiq/gateware/test/dsp/test_sawg_fe.py b/artiq/gateware/test/dsp/test_sawg_fe.py deleted file mode 100644 index 1f7cdc08c..000000000 --- a/artiq/gateware/test/dsp/test_sawg_fe.py +++ /dev/null @@ -1,255 +0,0 @@ -import unittest - -import migen as mg -from numpy import int32 - -from artiq.coredevice import sawg, spline -from artiq.language import (at_mu, now_mu, delay, - core as core_language) -from artiq.gateware.rtio.phy.sawg import Channel -from artiq.sim import devices as sim_devices, time as sim_time - - -class RTIOManager: - def __init__(self): - self.outputs = [] - - def rtio_output(self, target, data): - channel = target >> 8 - addr = target & 0xff - self.outputs.append((now_mu(), channel, addr, data)) - - def rtio_output_wide(self, *args, **kwargs): - self.rtio_output(*args, **kwargs) - - def delay_mu(self, t): - delay(t) - - def patch(self, mod): - assert not hasattr(mod, "_saved") - mod._saved = {} - for name in "rtio_output rtio_output_wide delay_mu".split(): - mod._saved[name] = getattr(mod, name, None) - setattr(mod, name, getattr(self, name)) - - def unpatch(self, mod): - mod.__dict__.update(mod._saved) - del mod._saved - - -class SAWGTest(unittest.TestCase): - def setUp(self): - core_language.set_time_manager(sim_time.Manager()) - self.rtio_manager = RTIOManager() - self.rtio_manager.patch(spline) - self.rtio_manager.patch(sawg) - self.core = sim_devices.Core({}) - self.core.coarse_ref_period = 20/3 - self.core.ref_multiplier = 1 - self.t = self.core.coarse_ref_period - self.channel = mg.ClockDomainsRenamer({"rio_phy": "sys"})( - Channel(width=16, parallelism=2)) - self.driver = sawg.SAWG({"core": self.core}, channel_base=0, - parallelism=self.channel.parallelism) - - def tearDown(self): - self.rtio_manager.unpatch(spline) - self.rtio_manager.unpatch(sawg) - - def test_instantiate(self): - pass - - def test_make_events(self): - d = self.driver - d.offset.set(.9) - delay(2*self.t) - d.frequency0.set(.1) - d.frequency1.set(.1) - delay(2*self.t) - d.offset.set(0) - v = int(round((1 << 48) * .1 * self.t)) - self.assertEqual( - self.rtio_manager.outputs, [ - (0., 1, 0, int(round(self.driver.offset.scale*.9))), - (2.*self.t, 8, 0, int(round( - (1 << self.driver.frequency0.width) * - self.t/self.channel.parallelism*.1))), - (2.*self.t, 3, 0, [int32(v), int32(v >> 32)]), - (4.*self.t, 1, 0, 0), - ]) - - def run_channel(self, events): - def gen(dut, events): - c = 0 - for time, channel, address, data in events: - time //= self.t - assert c <= time - while c < time: - yield - c += 1 - for phy in dut.phys: - yield phy.rtlink.o.stb.eq(0) - rt = dut.phys[channel].rtlink.o - if isinstance(data, list): - data = sum(int(d) << (i*32) for i, d in enumerate(data)) - yield rt.data.eq(int(data)) - if hasattr(rt, "address"): - yield rt.address.eq(address) - yield rt.stb.eq(1) - assert not (yield rt.busy) - # print("{}: set ch {} to {}".format(time, channel, hex(data))) - - def log(dut, data, n): - for i in range(n + dut.latency): - yield - data.append((yield from [(yield _) for _ in dut.o])) - - data = [] - # print(int(events[-1][0]) + 1) - mg.run_simulation(self.channel, [ - gen(self.channel, events), - log(self.channel, data, int(events[-1][0]//self.t) + 1)], - vcd_name="dds.vcd") - return data - - def test_run_channel(self): - self.test_make_events() - self.run_channel(self.rtio_manager.outputs) - - def test_coeff(self): - import struct - # these get discrete_compensate - # [.1, .01, -.00001], [.1, .01, .00001, -.000000001] - for v in [-.1], [.1, -.01]: - ch = self.driver.offset - p = ch.coeff_as_packed(v) - t = ch.time_width - w = ch.width - p = [_ & 0xffffffff for _ in p] - p0 = [int(round(vi*ch.scale*ch.time_scale**i)) - for i, vi in enumerate(v)] - p0 = [struct.pack("<" + "_bhiiqqqq"[(w + i*t)//8], vi - )[:(w + i*t)//8] - for i, vi in enumerate(p0)] - p0 = b"".join(p0) - if len(p0) % 4: - p0 += b"\x00"*(4 - len(p0) % 4) - p0 = list(struct.unpack("<" + "I"*((len(p0) + 3)//4), p0)) - with self.subTest(v): - self.assertEqual(p, p0) - - def test_linear(self): - d = self.driver - d.offset.set_coeff_mu([100, 10]) - delay(10*self.t) - d.offset.set_coeff([0]) - delay(1*self.t) - out = self.run_channel(self.rtio_manager.outputs) - out = out[self.channel.latency + self.channel.u.latency:][:11] - for i in range(len(out) - 1): - with self.subTest(i): - v = 100 + i*10 - self.assertEqual(out[i], [v, v]) - self.assertEqual(out[-1], [0, 0]) - - def test_pack(self): - ch = self.driver.offset - self.assertEqual(ch.coeff_as_packed_mu([1]), [1]) - self.assertEqual(ch.coeff_as_packed_mu([1, 1 << 16]), [1, 1]) - self.assertEqual(ch.coeff_as_packed_mu([1, 1 << 32]), [1, 0]) - self.assertEqual(ch.coeff_as_packed_mu([0x1234, 0xa5a5a5a5]), - [0xa5a51234, 0xa5a5]) - self.assertEqual(ch.coeff_as_packed_mu([1, 2, 3, 4]), - [0x20001, 0x30000, 0, 4, 0]) - self.assertEqual(ch.coeff_as_packed_mu([-1, -2, -3, -4]), - [0xfffeffff, 0xfffdffff, -1, -4, -1]) - self.assertEqual(ch.coeff_as_packed_mu([0, -1, 0, -1]), - [0xffff0000, 0x0000ffff, 0, -1, -1]) - - def test_smooth_linear(self): - ch = self.driver.offset - ch.smooth(.1, .2, 13*self.t, 1) - ch.set(.2) - delay(1*self.t) - out = self.run_channel(self.rtio_manager.outputs) - out = out[self.channel.latency + self.channel.u.latency:][:14] - a = int(round(.1*ch.scale)) - da = int(round(.1*ch.scale*(1 << ch.width)//13)) - for i in range(len(out) - 1): - with self.subTest(i): - v = a + (i*da >> ch.width) - self.assertEqual(out[i], [v, v]) - a = int(round(.2*ch.scale)) - self.assertEqual(out[-1], [a, a]) - - def test_smooth_cubic(self): - ch = self.driver.offset - ch.smooth(.1, .2, 13*self.t, 3) - ch.set(.2) - delay(1*self.t) - out = self.run_channel(self.rtio_manager.outputs) - out = out[self.channel.latency + self.channel.u.latency:][:14] - if False: - import matplotlib.pyplot as plt - plt.plot(sum(out, [])) - plt.show() - - @unittest.skip("needs artiq.sim.time.TimeManager tweak for " - "reverse timeline jumps") - def test_demo_2tone(self): - MHz = 1e-3 - ns = 1. - self.sawg0 = self.driver - - t_up = t_hold = t_down = 400*ns - a1 = .3 - a2 = .4 - order = 3 - - self.sawg0.frequency0.set(10*MHz) - self.sawg0.phase0.set(0.) - self.sawg0.frequency1.set(1*MHz) - self.sawg0.phase1.set(0.) - self.sawg0.frequency2.set(13*MHz) - self.sawg0.phase2.set(0.) - t = now_mu() - self.sawg0.amplitude1.smooth(.0, a1, t_up, order) - at_mu(t) - self.sawg0.amplitude2.smooth(.0, a2, t_up, order) - self.sawg0.amplitude1.set(a1) - self.sawg0.amplitude2.set(a2) - delay(t_hold) - t = now_mu() - self.sawg0.amplitude1.smooth(a1, .0, t_down, order) - at_mu(t) - self.sawg0.amplitude2.smooth(a2, .0, t_down, order) - self.sawg0.amplitude1.set(.0) - self.sawg0.amplitude2.set(.0) - - out = self.run_channel(self.rtio_manager.outputs) - out = sum(out, []) - if True: - import matplotlib.pyplot as plt - plt.plot(out) - plt.show() - - def test_fir_overflow(self): - MHz = 1e-3 - ns = 1. - f1 = self.driver.frequency1 - a1 = self.driver.amplitude1 - p1 = self.driver.phase1 - cfg = self.driver.config - f1.set(1*MHz) - a1.set(.99) - delay(100*ns) - p1.set(.5) - delay(100*ns) - a1.set(0) - - out = self.run_channel(self.rtio_manager.outputs) - out = sum(out, []) - if False: - import matplotlib.pyplot as plt - plt.plot(out) - plt.show() diff --git a/artiq/gateware/test/dsp/test_sawg_phy.py b/artiq/gateware/test/dsp/test_sawg_phy.py deleted file mode 100644 index 35666a5f6..000000000 --- a/artiq/gateware/test/dsp/test_sawg_phy.py +++ /dev/null @@ -1,70 +0,0 @@ -import numpy as np -from operator import or_ - -from migen import * -from migen.fhdl.verilog import convert - -from artiq.gateware.rtio.phy.sawg import Channel -from .tools import rtio_xfer - - -def pack_tri(port, *v): - r = 0 - w = 0 - for vi, p in zip(v, port.payload.flatten()): - w += len(p) - r |= int(vi*(1 << w)) - return r - - -def gen_rtio(dut): - yield - yield from rtio_xfer( - dut, - a1=pack_tri(dut.a1.a, .1), - f0=pack_tri(dut.b.f, .01234567), - f1=pack_tri(dut.a1.f, .01234567), - a2=pack_tri(dut.a1.a, .05), - f2=pack_tri(dut.a1.f, .00534567), - ) - - -def gen_log(dut, o, n): - for i in range(3 + dut.latency): - yield - for i in range(n): - yield - o.append((yield from [(yield _) for _ in dut.o])) - #o.append([(yield dut.a1.xo[0])]) - - -def _test_channel(): - width = 16 - - dut = ClockDomainsRenamer({"rio_phy": "sys"})( - Channel(width=width, parallelism=4) - ) - - if False: - print(convert(dut)) - return - - o = [] - run_simulation( - dut, - [gen_rtio(dut), gen_log(dut, o, 128)], - vcd_name="dds.vcd") - o = np.array(o)/(1 << (width - 1)) - o = o.ravel() - np.savez_compressed("dds.npz", o=o) - - import matplotlib.pyplot as plt - fig, ax = plt.subplots(2) - ax[0].step(np.arange(o.size), o) - ax[1].psd(o, 1 << 10, Fs=1, noverlap=1 << 9, scale_by_freq=False) - fig.savefig("dds.pdf") - plt.show() - - -if __name__ == "__main__": - _test_channel() diff --git a/artiq/gateware/test/dsp/test_spline.py b/artiq/gateware/test/dsp/test_spline.py deleted file mode 100644 index fe2d82c28..000000000 --- a/artiq/gateware/test/dsp/test_spline.py +++ /dev/null @@ -1,31 +0,0 @@ -import numpy as np - -from migen import * -from migen.fhdl.verilog import convert - -from artiq.gateware.dsp.spline import Spline -from .tools import xfer - - -def _test_gen_spline(dut, o): - yield dut.o.ack.eq(1) - yield from xfer(dut, i=dict(a0=0, a1=1, a2=2)) - for i in range(20): - yield - o.append((yield dut.o.a0)) - - -def _test_spline(): - dut = Spline(order=3, width=16, step=1) - - if False: - print(convert(dut)) - else: - o = [] - run_simulation(dut, _test_gen_spline(dut, o), vcd_name="spline.vcd") - o = np.array(o) - print(o) - - -if __name__ == "__main__": - _test_spline() diff --git a/artiq/gateware/test/dsp/tools.py b/artiq/gateware/test/dsp/tools.py deleted file mode 100644 index 8d22ad475..000000000 --- a/artiq/gateware/test/dsp/tools.py +++ /dev/null @@ -1,49 +0,0 @@ -def set_dict(e, **k): - for k, v in k.items(): - if isinstance(v, dict): - yield from set_dict(getattr(e, k), **v) - else: - yield getattr(e, k).eq(v) - - -def xfer(dut, **kw): - ep = [] - for e, v in kw.items(): - e = getattr(dut, e) - yield from set_dict(e, **v) - ep.append(e) - for e in ep: - yield e.stb.eq(1) - while ep: - yield - for e in ep[:]: - if hasattr(e, "busy") and (yield e.busy): - raise ValueError(e, "busy") - if not hasattr(e, "ack") or (yield e.ack): - yield e.stb.eq(0) - ep.remove(e) - - -def szip(*iters): - active = {it: None for it in iters} - while active: - for it in list(active): - while True: - try: - val = it.send(active[it]) - except StopIteration: - del active[it] - break - if val is None: - break - else: - active[it] = (yield val) - val = (yield None) - for it in active: - active[it] = val - - -def rtio_xfer(dut, **kwargs): - yield from szip(*( - xfer(dut.phys_named[k].rtlink, o={"data": v}) - for k, v in kwargs.items())) From c401559ed5306ed21b3694adb35e2594b305bc41 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 10 Jan 2023 12:07:20 +0800 Subject: [PATCH 64/85] flake: update dependencies --- flake.lock | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/flake.lock b/flake.lock index 269fa6209..1d6c10dae 100644 --- a/flake.lock +++ b/flake.lock @@ -42,11 +42,11 @@ "mozilla-overlay": { "flake": false, "locked": { - "lastModified": 1664789696, - "narHash": "sha256-UGWJHQShiwLCr4/DysMVFrYdYYHcOqAOVsWNUu+l6YU=", + "lastModified": 1672878308, + "narHash": "sha256-0+fl6PHokhtSV+w58z2QD2rTf8QhcOGsT9o4LwHHZHE=", "owner": "mozilla", "repo": "nixpkgs-mozilla", - "rev": "80627b282705101e7b38e19ca6e8df105031b072", + "rev": "d38863db88e100866b3e494a651ee4962b762fcc", "type": "github" }, "original": { @@ -57,11 +57,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1669735802, - "narHash": "sha256-qtG/o/i5ZWZLmXw108N2aPiVsxOcidpHJYNkT45ry9Q=", + "lastModified": 1673163619, + "narHash": "sha256-B33PFBL64ZgTWgMnhFL3jgheAN/DjHPsZ1Ih3z0VE5I=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "731cc710aeebecbf45a258e977e8b68350549522", + "rev": "8c54d842d9544361aac5f5b212ba04e4089e8efe", "type": "github" }, "original": { @@ -89,11 +89,11 @@ ] }, "locked": { - "lastModified": 1669369686, - "narHash": "sha256-YHez+S3PTUgtuliUNB5WM+RXcj8RKLbHVRvOgELSkwU=", + "lastModified": 1673324735, + "narHash": "sha256-5F66T1m4aY+kyWhwCzByb6Kbl/zHOCuxAOt035UIXC4=", "owner": "m-labs", "repo": "sipyco", - "rev": "98db6eacb084c2c5280fb653bee3d313e3ca6df8", + "rev": "ea57d8c948d56f126b9b2ef276a25ca630329532", "type": "github" }, "original": { @@ -105,11 +105,11 @@ "src-migen": { "flake": false, "locked": { - "lastModified": 1662111470, - "narHash": "sha256-IPyhoFZLhY8d3jHB8jyvGdbey7V+X5eCzBZYSrJ18ec=", + "lastModified": 1671263827, + "narHash": "sha256-hqvzLivGwc/4qMoyiwzmIpHEfLmwX0AmkiS0kVQojg8=", "owner": "m-labs", "repo": "migen", - "rev": "639e66f4f453438e83d86dc13491b9403bbd8ec6", + "rev": "12eb563e89ffc4a5e046239171207c9476f8f665", "type": "github" }, "original": { @@ -121,11 +121,11 @@ "src-misoc": { "flake": false, "locked": { - "lastModified": 1669779825, - "narHash": "sha256-l3lyy6dmbivo9Tppb08KHSyU89ZZG1CCcSjPlNRD210=", - "ref": "master", - "rev": "2c255775f732a41ba1a512ab3d2547af4e25f674", - "revCount": 2435, + "lastModified": 1671158014, + "narHash": "sha256-50w0K2E2ympYrG1Tte/HVbsp4FS2U+yohqZByXTOo4I=", + "ref": "refs/heads/master", + "rev": "26f039f9f6931a20a04ccd0f0a5402f67f553916", + "revCount": 2436, "submodules": true, "type": "git", "url": "https://github.com/m-labs/misoc.git" From 6cfd1480a79981e55825a5e07c66c613db7ec5a7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 10 Jan 2023 12:26:24 +0800 Subject: [PATCH 65/85] scheduler: support passing event loop --- artiq/master/scheduler.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/artiq/master/scheduler.py b/artiq/master/scheduler.py index 0d007954a..d849880fe 100644 --- a/artiq/master/scheduler.py +++ b/artiq/master/scheduler.py @@ -332,10 +332,10 @@ class Pipeline: self._run = RunStage(self.pool, deleter.delete) self._analyze = AnalyzeStage(self.pool, deleter.delete) - def start(self): - self._prepare.start() - self._run.start() - self._analyze.start() + def start(self, loop=None): + self._prepare.start(loop) + self._run.start(loop) + self._analyze.start(loop) async def stop(self): # NB: restart of a stopped pipeline is not supported @@ -410,8 +410,9 @@ class Scheduler: self._deleter = Deleter(self._pipelines) self._log_submissions = log_submissions - def start(self): - self._deleter.start() + def start(self, loop=None): + self._loop = loop + self._deleter.start(self._loop) async def stop(self): # NB: restart of a stopped scheduler is not supported @@ -442,7 +443,7 @@ class Scheduler: self._worker_handlers, self.notifier, self._experiment_db, self._log_submissions) self._pipelines[pipeline_name] = pipeline - pipeline.start() + pipeline.start(self._loop) return pipeline.pool.submit(expid, priority, due_date, flush, pipeline_name) def delete(self, rid): From a96bbd8508dcfd0777b518131bd7f2ad85d1b20d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 10 Jan 2023 12:30:08 +0800 Subject: [PATCH 66/85] test_scheduler: fix asyncio event loop management --- artiq/test/test_scheduler.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/artiq/test/test_scheduler.py b/artiq/test/test_scheduler.py index 854f17a93..5ed6cc01a 100644 --- a/artiq/test/test_scheduler.py +++ b/artiq/test/test_scheduler.py @@ -104,7 +104,7 @@ class SchedulerCase(unittest.TestCase): done.set() scheduler.notifier.publish = notify - scheduler.start() + scheduler.start(loop) # Verify that a timed experiment far in the future does not # get run, even if it has high priority. @@ -269,7 +269,7 @@ class SchedulerCase(unittest.TestCase): done.set() scheduler.notifier.publish = notify - scheduler.start() + scheduler.start(loop) scheduler.submit("main", expid_bg, low_priority) scheduler.submit("main", expid_empty, high_priority, late) @@ -328,7 +328,7 @@ class SchedulerCase(unittest.TestCase): empty_completed.set() scheduler.notifier.publish = notify - scheduler.start() + scheduler.start(loop) scheduler.submit("main", expid_bg, -99, None, False) loop.run_until_complete(background_running.wait()) self.assertFalse(scheduler.check_pause(0)) @@ -379,7 +379,7 @@ class SchedulerCase(unittest.TestCase): empty_ready.set() scheduler.notifier.publish = notify - scheduler.start() + scheduler.start(loop) scheduler.submit("main", expid_bg, -99, None, False) loop.run_until_complete(background_running.wait()) @@ -417,7 +417,7 @@ class SchedulerCase(unittest.TestCase): done.set() scheduler.notifier.publish = notify - scheduler.start() + scheduler.start(loop) scheduler.submit("main", expid, 0, None, False) loop.run_until_complete(first_preparing.wait()) scheduler.submit("main", expid, 1, None, True) From c8ab6c1b2b364123019f271ad5002c612d01b718 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 10 Jan 2023 12:36:33 +0800 Subject: [PATCH 67/85] test_worker: fix asyncio event loop management --- artiq/test/test_worker.py | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/artiq/test/test_worker.py b/artiq/test/test_worker.py index c33daf430..9667e69ea 100644 --- a/artiq/test/test_worker.py +++ b/artiq/test/test_worker.py @@ -62,44 +62,42 @@ async def _call_worker(worker, expid): await worker.close() -def _run_experiment(class_name): - expid = { - "log_level": logging.WARNING, - "file": sys.modules[__name__].__file__, - "class_name": class_name, - "arguments": dict() - } - loop = asyncio.get_event_loop() - worker = Worker({}) - loop.run_until_complete(_call_worker(worker, expid)) - - class WorkerCase(unittest.TestCase): def setUp(self): self.loop = asyncio.new_event_loop() asyncio.set_event_loop(self.loop) + def _run_experiment(self, class_name): + expid = { + "log_level": logging.WARNING, + "file": sys.modules[__name__].__file__, + "class_name": class_name, + "arguments": dict() + } + worker = Worker({}) + self.loop.run_until_complete(_call_worker(worker, expid)) + def test_simple_run(self): - _run_experiment("SimpleExperiment") + self._run_experiment("SimpleExperiment") def test_exception(self): with self.assertLogs() as logs: with self.assertRaises(WorkerInternalException): - _run_experiment("ExceptionTermination") + self._run_experiment("ExceptionTermination") self.assertGreater(len(logs.records), 0) self.assertIn("Terminating with exception (TypeError)", logs.output[-1]) def test_watchdog_no_timeout(self): - _run_experiment("WatchdogNoTimeout") + self._run_experiment("WatchdogNoTimeout") def test_watchdog_timeout(self): with self.assertRaises(WorkerWatchdogTimeout): - _run_experiment("WatchdogTimeout") + self._run_experiment("WatchdogTimeout") def test_watchdog_timeout_in_build(self): with self.assertRaises(WorkerWatchdogTimeout): - _run_experiment("WatchdogTimeoutInBuild") + self._run_experiment("WatchdogTimeoutInBuild") def tearDown(self): self.loop.close() From 627504b60e09f9380c2c327928593a205a8a6b0b Mon Sep 17 00:00:00 2001 From: mwojcik Date: Tue, 10 Jan 2023 16:54:45 +0800 Subject: [PATCH 68/85] test_dma: remove redundant clock --- artiq/gateware/test/rtio/test_dma.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/test/rtio/test_dma.py b/artiq/gateware/test/rtio/test_dma.py index 692e5be17..54b996b4f 100644 --- a/artiq/gateware/test/rtio/test_dma.py +++ b/artiq/gateware/test/rtio/test_dma.py @@ -203,11 +203,11 @@ class TestDMA(unittest.TestCase): run_simulation(tb[32], {"sys": [ do_dma(tb[32].dut, 0), monitor(32), (None for _ in range(70)), - ]}, {"sys": 8, "sys": 8, "rio": 8, "rio_phy": 8}) + ]}, {"sys": 8, "rio": 8, "rio_phy": 8}) run_simulation(tb[64], {"sys": [ do_dma(tb[64].dut, 0), monitor(64), (None for _ in range(70)), - ]}, {"sys": 8, "sys": 8, "rio": 8, "rio_phy": 8}) + ]}, {"sys": 8, "rio": 8, "rio_phy": 8}) correct_changes = [(timestamp + 11, channel) for channel, timestamp, _, _ in test_writes_full_stack] From cd860beda24eac6da418254cdc61db9d83945bae Mon Sep 17 00:00:00 2001 From: mwojcik Date: Tue, 10 Jan 2023 17:09:27 +0800 Subject: [PATCH 69/85] test_full_stack: restore missing check_ttls --- artiq/gateware/test/drtio/test_full_stack.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index 4c7d367b2..61fb43d2a 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -169,7 +169,7 @@ class TestFullStack(unittest.TestCase): yield from tb.sync() run_simulation(tb.dut, - {"sys": test()}, self.clocks) + {"sys": [test(), tb.check_ttls(ttl_changes)]}, self.clocks) self.assertEqual(ttl_changes, correct_ttl_changes) def test_underflow(self): @@ -214,7 +214,7 @@ class TestFullStack(unittest.TestCase): yield from tb.sync() run_simulation(tb.dut, - {"sys": test()}, self.clocks) + {"sys": [test(), tb.check_ttls(ttl_changes)]}, self.clocks) self.assertEqual(ttl_changes, correct_ttl_changes) def test_write_underflow(self): @@ -284,7 +284,7 @@ class TestFullStack(unittest.TestCase): yield dut.phy2.rtlink.i.stb.eq(0) run_simulation(dut, - {"sys": test()}, self.clocks) + {"sys": [test(), generate_input()]}, self.clocks) def test_echo(self): dut = DUT(2) From 90424268725a3cda3f34de5aa29670f308f64ce3 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Tue, 10 Jan 2023 17:17:39 +0800 Subject: [PATCH 70/85] echo test: add two more yields --- artiq/gateware/test/drtio/test_full_stack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index 61fb43d2a..e55bb536a 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -303,7 +303,7 @@ class TestFullStack(unittest.TestCase): yield yield dut.master.rt_packet.echo_stb.eq(0) - for i in range(15): + for i in range(17): yield self.assertEqual((yield dut.master.rt_packet.packet_cnt_tx), 1) From 70edc9c5c61edcf802932bd3fe542d1518f938d7 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Wed, 11 Jan 2023 11:56:21 +0800 Subject: [PATCH 71/85] test_write_underflow: decrease underflow delay --- artiq/gateware/drtio/core.py | 2 +- artiq/gateware/test/drtio/test_full_stack.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index 434751ccc..1af7fa7b4 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -77,7 +77,7 @@ class DRTIOSatellite(Module): self.reset = CSRStorage(reset=1) self.reset_phy = CSRStorage(reset=1) self.tsc_loaded = CSR() - # master interface in the rtio domain + # master interface in the sys domain self.cri = cri.Interface() self.async_errors = Record(async_errors_layout) diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index e55bb536a..ecae7644b 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -227,16 +227,16 @@ class TestFullStack(unittest.TestCase): errors = yield from saterr.protocol_error.read() self.assertEqual(errors, 0) yield from csrs.underflow_margin.write(0) - tb.delay(100) + tb.delay(80) yield from tb.write(42, 1) - for i in range(12): + for i in range(21): yield errors = yield from saterr.protocol_error.read() underflow_channel = yield from saterr.underflow_channel.read() underflow_timestamp_event = yield from saterr.underflow_timestamp_event.read() self.assertEqual(errors, 8) # write underflow self.assertEqual(underflow_channel, 42) - self.assertEqual(underflow_timestamp_event, 100) + self.assertEqual(underflow_timestamp_event, 80) yield from saterr.protocol_error.write(errors) yield errors = yield from saterr.protocol_error.read() From 73a4ef89ec3dd5a4dbdcde22fcd83340d8869d4c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 11 Jan 2023 18:45:35 +0800 Subject: [PATCH 72/85] scheduler: make asyncio loop a keyword-only argument, like in other asyncio APIs --- artiq/master/scheduler.py | 12 ++++++------ artiq/test/test_scheduler.py | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/artiq/master/scheduler.py b/artiq/master/scheduler.py index d849880fe..1a18c0720 100644 --- a/artiq/master/scheduler.py +++ b/artiq/master/scheduler.py @@ -332,10 +332,10 @@ class Pipeline: self._run = RunStage(self.pool, deleter.delete) self._analyze = AnalyzeStage(self.pool, deleter.delete) - def start(self, loop=None): - self._prepare.start(loop) - self._run.start(loop) - self._analyze.start(loop) + def start(self, *, loop=None): + self._prepare.start(loop=loop) + self._run.start(loop=loop) + self._analyze.start(loop=loop) async def stop(self): # NB: restart of a stopped pipeline is not supported @@ -410,9 +410,9 @@ class Scheduler: self._deleter = Deleter(self._pipelines) self._log_submissions = log_submissions - def start(self, loop=None): + def start(self, *, loop=None): self._loop = loop - self._deleter.start(self._loop) + self._deleter.start(loop=self._loop) async def stop(self): # NB: restart of a stopped scheduler is not supported diff --git a/artiq/test/test_scheduler.py b/artiq/test/test_scheduler.py index 5ed6cc01a..9726190ed 100644 --- a/artiq/test/test_scheduler.py +++ b/artiq/test/test_scheduler.py @@ -104,7 +104,7 @@ class SchedulerCase(unittest.TestCase): done.set() scheduler.notifier.publish = notify - scheduler.start(loop) + scheduler.start(loop=loop) # Verify that a timed experiment far in the future does not # get run, even if it has high priority. @@ -269,7 +269,7 @@ class SchedulerCase(unittest.TestCase): done.set() scheduler.notifier.publish = notify - scheduler.start(loop) + scheduler.start(loop=loop) scheduler.submit("main", expid_bg, low_priority) scheduler.submit("main", expid_empty, high_priority, late) @@ -328,7 +328,7 @@ class SchedulerCase(unittest.TestCase): empty_completed.set() scheduler.notifier.publish = notify - scheduler.start(loop) + scheduler.start(loop=loop) scheduler.submit("main", expid_bg, -99, None, False) loop.run_until_complete(background_running.wait()) self.assertFalse(scheduler.check_pause(0)) @@ -379,7 +379,7 @@ class SchedulerCase(unittest.TestCase): empty_ready.set() scheduler.notifier.publish = notify - scheduler.start(loop) + scheduler.start(loop=loop) scheduler.submit("main", expid_bg, -99, None, False) loop.run_until_complete(background_running.wait()) @@ -417,7 +417,7 @@ class SchedulerCase(unittest.TestCase): done.set() scheduler.notifier.publish = notify - scheduler.start(loop) + scheduler.start(loop=loop) scheduler.submit("main", expid, 0, None, False) loop.run_until_complete(first_preparing.wait()) scheduler.submit("main", expid, 1, None, True) From 7fd6dead8fd98798f2d023af921dfe65279e49e2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 11 Jan 2023 18:46:54 +0800 Subject: [PATCH 73/85] master: fix asyncio loop management --- artiq/frontend/artiq_master.py | 18 +++++++++--------- artiq/master/experiments.py | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/artiq/frontend/artiq_master.py b/artiq/frontend/artiq_master.py index da57e6b3d..ced3c828c 100755 --- a/artiq/frontend/artiq_master.py +++ b/artiq/frontend/artiq_master.py @@ -86,7 +86,7 @@ def main(): server_broadcast = Broadcaster() loop.run_until_complete(server_broadcast.start( bind, args.port_broadcast)) - atexit_register_coroutine(server_broadcast.stop) + atexit_register_coroutine(server_broadcast.stop, loop=loop) log_forwarder.callback = (lambda msg: server_broadcast.broadcast("log", msg)) @@ -100,8 +100,8 @@ def main(): device_db = DeviceDB(args.device_db) dataset_db = DatasetDB(args.dataset_db) - dataset_db.start() - atexit_register_coroutine(dataset_db.stop) + dataset_db.start(loop=loop) + atexit_register_coroutine(dataset_db.stop, loop=loop) worker_handlers = dict() if args.git: @@ -113,8 +113,8 @@ def main(): atexit.register(experiment_db.close) scheduler = Scheduler(RIDCounter(), worker_handlers, experiment_db, args.log_submissions) - scheduler.start() - atexit_register_coroutine(scheduler.stop) + scheduler.start(loop=loop) + atexit_register_coroutine(scheduler.stop, loop=loop) config = MasterConfig(args.name) @@ -131,7 +131,7 @@ def main(): "scheduler_check_termination": scheduler.check_termination, "ccb_issue": ccb_issue, }) - experiment_db.scan_repository_async() + experiment_db.scan_repository_async(loop=loop) server_control = RPCServer({ "master_config": config, @@ -142,7 +142,7 @@ def main(): }, allow_parallel=True) loop.run_until_complete(server_control.start( bind, args.port_control)) - atexit_register_coroutine(server_control.stop) + atexit_register_coroutine(server_control.stop, loop=loop) server_notify = Publisher({ "schedule": scheduler.notifier, @@ -153,12 +153,12 @@ def main(): }) loop.run_until_complete(server_notify.start( bind, args.port_notify)) - atexit_register_coroutine(server_notify.stop) + atexit_register_coroutine(server_notify.stop, loop=loop) server_logging = LoggingServer() loop.run_until_complete(server_logging.start( bind, args.port_logging)) - atexit_register_coroutine(server_logging.stop) + atexit_register_coroutine(server_logging.stop, loop=loop) print("ARTIQ master is now ready.") loop.run_until_complete(signal_handler.wait_terminate()) diff --git a/artiq/master/experiments.py b/artiq/master/experiments.py index 098ddc334..df29f2a6b 100644 --- a/artiq/master/experiments.py +++ b/artiq/master/experiments.py @@ -124,9 +124,9 @@ class ExperimentDB: self._scanning = False self.status["scanning"] = False - def scan_repository_async(self, new_cur_rev=None): + def scan_repository_async(self, new_cur_rev=None, loop=None): asyncio.ensure_future( - exc_to_warning(self.scan_repository(new_cur_rev))) + exc_to_warning(self.scan_repository(new_cur_rev)), loop=loop) async def examine(self, filename, use_repository=True, revision=None): if use_repository: From 80f261437a33d9d0bdd764e7948db65e06de633c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 11 Jan 2023 18:47:30 +0800 Subject: [PATCH 74/85] flake: update dependencies --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index 1d6c10dae..c846559f1 100644 --- a/flake.lock +++ b/flake.lock @@ -57,11 +57,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1673163619, - "narHash": "sha256-B33PFBL64ZgTWgMnhFL3jgheAN/DjHPsZ1Ih3z0VE5I=", + "lastModified": 1673345971, + "narHash": "sha256-4DfFcKLRfVUTyuGrGNNmw37IeIZSoku9tgTVmu/iD98=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "8c54d842d9544361aac5f5b212ba04e4089e8efe", + "rev": "54644f409ab471e87014bb305eac8c50190bcf48", "type": "github" }, "original": { @@ -89,11 +89,11 @@ ] }, "locked": { - "lastModified": 1673324735, - "narHash": "sha256-5F66T1m4aY+kyWhwCzByb6Kbl/zHOCuxAOt035UIXC4=", + "lastModified": 1673433867, + "narHash": "sha256-a7Oq35YoDzPtISbqAsaT+2/v15HZ7G1q0ukXmKWdb7Q=", "owner": "m-labs", "repo": "sipyco", - "rev": "ea57d8c948d56f126b9b2ef276a25ca630329532", + "rev": "38f8f4185d7db6b68bd7f71546da9077b1e2561c", "type": "github" }, "original": { @@ -105,11 +105,11 @@ "src-migen": { "flake": false, "locked": { - "lastModified": 1671263827, - "narHash": "sha256-hqvzLivGwc/4qMoyiwzmIpHEfLmwX0AmkiS0kVQojg8=", + "lastModified": 1673433200, + "narHash": "sha256-ribBG06gsucz5oBS+O6aL8s2oJjx+qfl+vXmspts8gg=", "owner": "m-labs", "repo": "migen", - "rev": "12eb563e89ffc4a5e046239171207c9476f8f665", + "rev": "f3e9145c9825514a1b4225378936569da4df8e12", "type": "github" }, "original": { From daad3d263a9883e5e057b4c22a800c2e9639f47f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 12 Jan 2023 10:39:53 +0800 Subject: [PATCH 75/85] master: commit missing part of 7fd6dead8 --- artiq/master/scheduler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/master/scheduler.py b/artiq/master/scheduler.py index 1a18c0720..bc264964e 100644 --- a/artiq/master/scheduler.py +++ b/artiq/master/scheduler.py @@ -443,7 +443,7 @@ class Scheduler: self._worker_handlers, self.notifier, self._experiment_db, self._log_submissions) self._pipelines[pipeline_name] = pipeline - pipeline.start(self._loop) + pipeline.start(loop=self._loop) return pipeline.pool.submit(expid, priority, due_date, flush, pipeline_name) def delete(self, rid): From 628b6714338bad663c8114a251e1e8ca58a62569 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 12 Jan 2023 10:41:10 +0800 Subject: [PATCH 76/85] update copyright year --- README.rst | 2 +- artiq/firmware/bootloader/main.rs | 2 +- doc/manual/conf.py | 2 +- doc/manual/introduction.rst | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index cef2fb286..9ec774741 100644 --- a/README.rst +++ b/README.rst @@ -29,7 +29,7 @@ Website: https://m-labs.hk/artiq License ======= -Copyright (C) 2014-2022 M-Labs Limited. +Copyright (C) 2014-2023 M-Labs Limited. ARTIQ is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index c496a79b7..89d2002e1 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -497,7 +497,7 @@ pub extern fn main() -> i32 { println!(r"|_| |_|_|____/ \___/ \____|"); println!(""); println!("MiSoC Bootloader"); - println!("Copyright (c) 2017-2022 M-Labs Limited"); + println!("Copyright (c) 2017-2023 M-Labs Limited"); println!(""); #[cfg(has_ethmac)] diff --git a/doc/manual/conf.py b/doc/manual/conf.py index 03a6dc105..df603b7b2 100644 --- a/doc/manual/conf.py +++ b/doc/manual/conf.py @@ -95,7 +95,7 @@ master_doc = 'index' # General information about the project. project = 'ARTIQ' -copyright = '2014-2022, M-Labs Limited' +copyright = '2014-2023, M-Labs Limited' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/doc/manual/introduction.rst b/doc/manual/introduction.rst index 23eaa98a9..eff537f67 100644 --- a/doc/manual/introduction.rst +++ b/doc/manual/introduction.rst @@ -27,4 +27,4 @@ Website: https://m-labs.hk/artiq `Cite ARTIQ `_ as ``Bourdeauducq, Sébastien et al. (2016). ARTIQ 1.0. Zenodo. 10.5281/zenodo.51303``. -Copyright (C) 2014-2022 M-Labs Limited. Licensed under GNU LGPL version 3+. +Copyright (C) 2014-2023 M-Labs Limited. Licensed under GNU LGPL version 3+. From f8d93813e9885a4c5d9cb003a17211b7a2871ab8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 12 Jan 2023 10:52:26 +0800 Subject: [PATCH 77/85] aqctl_corelog: fix asyncio loop management --- artiq/frontend/aqctl_corelog.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/artiq/frontend/aqctl_corelog.py b/artiq/frontend/aqctl_corelog.py index 8c766ecf5..c5f5a8eee 100755 --- a/artiq/frontend/aqctl_corelog.py +++ b/artiq/frontend/aqctl_corelog.py @@ -96,14 +96,15 @@ def main(): signal_handler.setup() try: get_logs_task = asyncio.ensure_future( - get_logs_sim(args.core_addr) if args.simulation else get_logs(args.core_addr)) + get_logs_sim(args.core_addr) if args.simulation else get_logs(args.core_addr), + loop=loop) try: server = Server({"corelog": PingTarget()}, None, True) loop.run_until_complete(server.start(common_args.bind_address_from_args(args), args.port)) try: _, pending = loop.run_until_complete(asyncio.wait( - [signal_handler.wait_terminate(), - server.wait_terminate(), + [loop.create_task(signal_handler.wait_terminate()), + loop.create_task(server.wait_terminate()), get_logs_task], return_when=asyncio.FIRST_COMPLETED)) for task in pending: From d872c3ab4dbea0bee8b91a58c0b360de0e95eefb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 12 Jan 2023 12:16:53 +0800 Subject: [PATCH 78/85] aqctl_moninj_proxy: fix asyncio loop management --- artiq/frontend/aqctl_moninj_proxy.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/aqctl_moninj_proxy.py b/artiq/frontend/aqctl_moninj_proxy.py index fcf9e259d..d1e8774bd 100755 --- a/artiq/frontend/aqctl_moninj_proxy.py +++ b/artiq/frontend/aqctl_moninj_proxy.py @@ -219,8 +219,8 @@ def main(): loop.run_until_complete(server.start(bind_address, args.port_control)) try: _, pending = loop.run_until_complete(asyncio.wait( - [signal_handler.wait_terminate(), - server.wait_terminate(), + [loop.create_task(signal_handler.wait_terminate()), + loop.create_task(server.wait_terminate()), comm_moninj.wait_terminate()], return_when=asyncio.FIRST_COMPLETED)) for task in pending: From 9e8bb3c70140438b205a7bfc83ff5ae94cfcce94 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 12 Jan 2023 12:17:16 +0800 Subject: [PATCH 79/85] browser,dashboard: fix asyncio loop management --- artiq/frontend/artiq_browser.py | 4 ++-- artiq/frontend/artiq_dashboard.py | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/artiq/frontend/artiq_browser.py b/artiq/frontend/artiq_browser.py index 204ac2382..49517f9cb 100755 --- a/artiq/frontend/artiq_browser.py +++ b/artiq/frontend/artiq_browser.py @@ -83,7 +83,7 @@ class Browser(QtWidgets.QMainWindow): self.applets = applets.AppletsDock(self, datasets_sub) smgr.register(self.applets) - atexit_register_coroutine(self.applets.stop) + atexit_register_coroutine(self.applets.stop, loop=loop) self.datasets = datasets.DatasetsDock( datasets_sub, master_host, master_port) @@ -162,7 +162,7 @@ def main(): browser.show() smgr.load() smgr.start() - atexit_register_coroutine(smgr.stop) + atexit_register_coroutine(smgr.stop, loop=loop) if args.select is not None: browser.files.select(args.select) diff --git a/artiq/frontend/artiq_dashboard.py b/artiq/frontend/artiq_dashboard.py index dfe1e82d6..31060fb81 100755 --- a/artiq/frontend/artiq_dashboard.py +++ b/artiq/frontend/artiq_dashboard.py @@ -148,7 +148,7 @@ def main(): report_disconnect) loop.run_until_complete(subscriber.connect( args.server, args.port_notify)) - atexit_register_coroutine(subscriber.close) + atexit_register_coroutine(subscriber.close, loop=loop) sub_clients[notifier_name] = subscriber broadcast_clients = dict() @@ -156,7 +156,7 @@ def main(): client = Receiver(target, [], report_disconnect) loop.run_until_complete(client.connect( args.server, args.port_broadcast)) - atexit_register_coroutine(client.close) + atexit_register_coroutine(client.close, loop=loop) broadcast_clients[target] = client # initialize main window @@ -196,13 +196,13 @@ def main(): "port_notify": args.port_notify, "port_control": args.port_control, }) - atexit_register_coroutine(d_applets.stop) + atexit_register_coroutine(d_applets.stop, loop=loop) smgr.register(d_applets) broadcast_clients["ccb"].notify_cbs.append(d_applets.ccb_notify) d_ttl_dds = moninj.MonInj(rpc_clients["schedule"]) loop.run_until_complete(d_ttl_dds.start(args.server, args.port_notify)) - atexit_register_coroutine(d_ttl_dds.stop) + atexit_register_coroutine(d_ttl_dds.stop, loop=loop) d_schedule = schedule.ScheduleDock( rpc_clients["schedule"], sub_clients["schedule"]) @@ -232,7 +232,7 @@ def main(): main_window.show() smgr.load() smgr.start() - atexit_register_coroutine(smgr.stop) + atexit_register_coroutine(smgr.stop, loop=loop) # work around for https://github.com/m-labs/artiq/issues/1307 d_ttl_dds.ttl_dock.show() From 2f289c552f357a47778e86d2d061224a464bbafd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 12 Jan 2023 12:18:17 +0800 Subject: [PATCH 80/85] remove unused import --- artiq/gui/log.py | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/gui/log.py b/artiq/gui/log.py index 3fd05d80d..3b5095f98 100644 --- a/artiq/gui/log.py +++ b/artiq/gui/log.py @@ -1,4 +1,3 @@ -import asyncio import logging import time import re From 5f77d4f5fa4e9657a5ab0e2fea4fe906d33f8e52 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 12 Jan 2023 12:35:02 +0800 Subject: [PATCH 81/85] applets: fix asyncio loop management --- artiq/frontend/artiq_browser.py | 6 +++--- artiq/frontend/artiq_dashboard.py | 3 ++- artiq/gui/applets.py | 14 ++++++++------ 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/artiq/frontend/artiq_browser.py b/artiq/frontend/artiq_browser.py index 49517f9cb..853b8ed31 100755 --- a/artiq/frontend/artiq_browser.py +++ b/artiq/frontend/artiq_browser.py @@ -49,7 +49,7 @@ def get_argparser(): class Browser(QtWidgets.QMainWindow): def __init__(self, smgr, datasets_sub, browse_root, - master_host, master_port): + master_host, master_port, *, loop=None): QtWidgets.QMainWindow.__init__(self) smgr.register(self) @@ -81,7 +81,7 @@ class Browser(QtWidgets.QMainWindow): self.files.dataset_changed.connect( self.experiments.dataset_changed) - self.applets = applets.AppletsDock(self, datasets_sub) + self.applets = applets.AppletsDock(self, datasets_sub, loop=loop) smgr.register(self.applets) atexit_register_coroutine(self.applets.stop, loop=loop) @@ -152,7 +152,7 @@ def main(): smgr = state.StateManager(args.db_file) browser = Browser(smgr, datasets_sub, args.browse_root, - args.server, args.port) + args.server, args.port, loop=loop) widget_log_handler.callback = browser.log.model.append if os.name == "nt": diff --git a/artiq/frontend/artiq_dashboard.py b/artiq/frontend/artiq_dashboard.py index 31060fb81..e6ea6ad0a 100755 --- a/artiq/frontend/artiq_dashboard.py +++ b/artiq/frontend/artiq_dashboard.py @@ -195,7 +195,8 @@ def main(): "server": args.server, "port_notify": args.port_notify, "port_control": args.port_control, - }) + }, + loop=loop) atexit_register_coroutine(d_applets.stop, loop=loop) smgr.register(d_applets) broadcast_clients["ccb"].notify_cbs.append(d_applets.ccb_notify) diff --git a/artiq/gui/applets.py b/artiq/gui/applets.py index b119d14bc..275e61ba7 100644 --- a/artiq/gui/applets.py +++ b/artiq/gui/applets.py @@ -92,9 +92,9 @@ class AppletIPCServer(AsyncioParentComm): finally: self.datasets_sub.notify_cbs.remove(self._on_mod) - def start_server(self, embed_cb, fix_initial_size_cb): + def start_server(self, embed_cb, fix_initial_size_cb, *, loop=None): self.server_task = asyncio.ensure_future( - self.serve(embed_cb, fix_initial_size_cb)) + self.serve(embed_cb, fix_initial_size_cb), loop=loop) async def stop_server(self): if hasattr(self, "server_task"): @@ -327,7 +327,7 @@ class _CompleterDelegate(QtWidgets.QStyledItemDelegate): class AppletsDock(QtWidgets.QDockWidget): - def __init__(self, main_window, datasets_sub, extra_substitutes={}): + def __init__(self, main_window, datasets_sub, extra_substitutes={}, *, loop=None): """ :param extra_substitutes: Map of extra ``${strings}`` to substitute in applet commands to their respective values. @@ -342,6 +342,8 @@ class AppletsDock(QtWidgets.QDockWidget): self.extra_substitutes = extra_substitutes self.applet_uids = set() + self._loop = loop + self.table = QtWidgets.QTreeWidget() self.table.setColumnCount(2) self.table.setHeaderLabels(["Name", "Command"]) @@ -441,7 +443,7 @@ class AppletsDock(QtWidgets.QDockWidget): dock = _AppletDock(self.datasets_sub, item.applet_uid, name, spec, self.extra_substitutes) self.main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock) dock.setFloating(True) - asyncio.ensure_future(dock.start()) + asyncio.ensure_future(dock.start(), loop=self._loop) dock.sigClosed.connect(partial(self.on_dock_closed, item, dock)) return dock @@ -480,7 +482,7 @@ class AppletsDock(QtWidgets.QDockWidget): def on_dock_closed(self, item, dock): item.applet_geometry = dock.saveGeometry() - asyncio.ensure_future(dock.terminate()) + asyncio.ensure_future(dock.terminate(), loop=self._loop) item.setCheckState(0, QtCore.Qt.Unchecked) def get_untitled(self): @@ -569,7 +571,7 @@ class AppletsDock(QtWidgets.QDockWidget): if wi.ty == "applet": dock = wi.applet_dock if dock is not None: - asyncio.ensure_future(dock.restart()) + asyncio.ensure_future(dock.restart(), loop=self._loop) elif wi.ty == "group": for i in range(wi.childCount()): walk(wi.child(i)) From 6d37d9d52cc2140f19f59b4b22cdda434f04cbdd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 12 Jan 2023 12:41:08 +0800 Subject: [PATCH 82/85] gui/state: fix asyncio loop management --- artiq/frontend/artiq_browser.py | 2 +- artiq/frontend/artiq_dashboard.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/artiq_browser.py b/artiq/frontend/artiq_browser.py index 853b8ed31..398244b0e 100755 --- a/artiq/frontend/artiq_browser.py +++ b/artiq/frontend/artiq_browser.py @@ -161,7 +161,7 @@ def main(): # QDockWidgets fail to be embedded. browser.show() smgr.load() - smgr.start() + smgr.start(loop=loop) atexit_register_coroutine(smgr.stop, loop=loop) if args.select is not None: diff --git a/artiq/frontend/artiq_dashboard.py b/artiq/frontend/artiq_dashboard.py index e6ea6ad0a..033d58ee7 100755 --- a/artiq/frontend/artiq_dashboard.py +++ b/artiq/frontend/artiq_dashboard.py @@ -232,7 +232,7 @@ def main(): # QDockWidgets fail to be embedded. main_window.show() smgr.load() - smgr.start() + smgr.start(loop=loop) atexit_register_coroutine(smgr.stop, loop=loop) # work around for https://github.com/m-labs/artiq/issues/1307 From 514ac953cea3f48758aaddab2a2efbac7bf2db03 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 12 Jan 2023 13:01:08 +0800 Subject: [PATCH 83/85] remove obsolete SI5324_AS_SYNTHESIZER config option --- artiq/firmware/runtime/rtio_clocking.rs | 12 +++++------- artiq/gateware/targets/kasli.py | 3 --- artiq/gateware/targets/kasli_generic.py | 1 - artiq/gateware/targets/kc705.py | 2 -- 4 files changed, 5 insertions(+), 13 deletions(-) diff --git a/artiq/firmware/runtime/rtio_clocking.rs b/artiq/firmware/runtime/rtio_clocking.rs index 1123b3d1a..f094e5383 100644 --- a/artiq/firmware/runtime/rtio_clocking.rs +++ b/artiq/firmware/runtime/rtio_clocking.rs @@ -1,5 +1,4 @@ use board_misoc::config; -#[cfg(si5324_as_synthesizer)] use board_artiq::si5324; use board_misoc::{csr, clock}; @@ -86,15 +85,14 @@ pub mod crg { // Si5324 input to select for locking to an external clock (as opposed to // a recovered link clock in DRTIO satellites, which is handled elsewhere). -#[cfg(all(si5324_as_synthesizer, soc_platform = "kasli", hw_rev = "v2.0"))] +#[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] const SI5324_EXT_INPUT: si5324::Input = si5324::Input::Ckin1; -#[cfg(all(si5324_as_synthesizer, soc_platform = "kasli", not(hw_rev = "v2.0")))] +#[cfg(all(soc_platform = "kasli", not(hw_rev = "v2.0")))] const SI5324_EXT_INPUT: si5324::Input = si5324::Input::Ckin2; -#[cfg(all(si5324_as_synthesizer, soc_platform = "kc705"))] +#[cfg(all(soc_platform = "kc705"))] const SI5324_EXT_INPUT: si5324::Input = si5324::Input::Ckin2; -#[cfg(si5324_as_synthesizer)] -fn setup_si5324_as_synthesizer(cfg: RtioClock) { +fn setup_si5324_pll(cfg: RtioClock) { let (si5324_settings, si5324_ref_input) = match cfg { RtioClock::Ext0_Synth0_10to125 => { // 125 MHz output from 10 MHz CLKINx reference, 504 Hz BW info!("using 10MHz reference to make 125MHz RTIO clock with PLL"); @@ -209,7 +207,7 @@ fn setup_si5324(clock_cfg: RtioClock) { info!("using external RTIO clock with PLL bypass"); si5324::bypass(SI5324_EXT_INPUT).expect("cannot bypass Si5324") }, - _ => setup_si5324_as_synthesizer(clock_cfg), + _ => setup_si5324_pll(clock_cfg), } // switch sysclk source to si5324 diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 1d33c6e2a..f26e839dd 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -136,7 +136,6 @@ class Tester(StandaloneBase): dds = "ad9910" StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) - self.config["SI5324_AS_SYNTHESIZER"] = None # self.config["SI5324_EXT_REF"] = None self.config["RTIO_FREQUENCY"] = "125.0" if hw_rev == "v1.0": @@ -174,7 +173,6 @@ class SUServo(StandaloneBase): hw_rev = "v2.0" StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) - self.config["SI5324_AS_SYNTHESIZER"] = None # self.config["SI5324_EXT_REF"] = None self.config["RTIO_FREQUENCY"] = "125.0" if hw_rev == "v1.0": @@ -254,7 +252,6 @@ class MasterBase(MiniSoC, AMPSoC): self.config["I2C_BUS_COUNT"] = 1 self.config["HAS_SI5324"] = None self.config["SI5324_SOFT_RESET"] = None - self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) drtio_data_pads = [] diff --git a/artiq/gateware/targets/kasli_generic.py b/artiq/gateware/targets/kasli_generic.py index a356aaba1..910ff46ca 100755 --- a/artiq/gateware/targets/kasli_generic.py +++ b/artiq/gateware/targets/kasli_generic.py @@ -23,7 +23,6 @@ class GenericStandalone(StandaloneBase): self.class_name_override = description["variant"] StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) - self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = "{:.1f}".format(description["rtio_frequency"]/1e6) if "ext_ref_frequency" in description: self.config["SI5324_EXT_REF"] = None diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 4aac6e2ce..d80af96be 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -112,7 +112,6 @@ class _StandaloneBase(MiniSoC, AMPSoC): 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 += [ @@ -262,7 +261,6 @@ class _MasterBase(MiniSoC, AMPSoC): self.csr_devices.append("i2c") self.config["I2C_BUS_COUNT"] = 1 self.config["HAS_SI5324"] = None - self.config["SI5324_AS_SYNTHESIZER"] = None rtio_clk_period = 1e9/self.drtio_transceiver.rtio_clk_freq # Constrain TX & RX timing for the first transceiver channel From babbbfadb3768882c121e276fc82c261e62180d6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 12 Jan 2023 13:12:05 +0800 Subject: [PATCH 84/85] update release notes --- RELEASE_NOTES.rst | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index bf25afadf..f9922a5cf 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -8,14 +8,21 @@ ARTIQ-8 (Unreleased) Highlights: -* Implemented Phaser-servo. This requires recent gateware on Phaser. -* Implemented Phaser-MIQRO support. This requires the Phaser MIQRO gateware - variant. -* MSYS2 packaging for Windows. -* Sampler: adjusted ADC MU to Volt conversion base for Sampler since v2.2. - For earlier version please explicitly define it as an argument in the device database file - (e.g. ``"hw_rev": "v2.1"``). +* Hardware support: + - Implemented Phaser-servo. This requires recent gateware on Phaser. + - Implemented Phaser-MIQRO support. This requires the Phaser MIQRO gateware + variant. + - Sampler: fixed ADC MU to Volt conversion factor for Sampler v2.2+. + For earlier hardware versions, specify the hardware version in the device + database file (e.g. ``"hw_rev": "v2.1"``) to use the correct conversion factor. + - Metlino and Sayma support has been dropped due to complications with synchronous RTIO clocking. +* CPU (on softcore platforms) and AXI bus (on Zynq) are now clocked synchronously with the RTIO + clock, to facilitate implementation of local processing on DRTIO satellites, and to slightly + reduce RTIO latency. +* MSYS2 packaging for Windows, which replaces Conda. Conda packages are still available to + support legacy installations, but may be removed in a future release. * Added channel names to RTIO errors. +* Full Python 3.10 support. ARTIQ-7 ------- From 248cd69673719c1a6bc6a8e94f53bd97faffea63 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 12 Jan 2023 18:03:46 +0800 Subject: [PATCH 85/85] flake: use nixpkgs cargo-xbuild --- flake.nix | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/flake.nix b/flake.nix index 2b126bf83..2b2ae17fe 100644 --- a/flake.nix +++ b/flake.nix @@ -195,20 +195,6 @@ propagatedBuildInputs = with pkgs.python3Packages; [ pyserial prettytable msgpack migen ]; }; - cargo-xbuild = rustPlatform.buildRustPackage rec { - pname = "cargo-xbuild"; - version = "0.6.5"; - - src = pkgs.fetchFromGitHub { - owner = "rust-osdev"; - repo = pname; - rev = "v${version}"; - sha256 = "18djvygq9v8rmfchvi2hfj0i6fhn36m716vqndqnj56fiqviwxvf"; - }; - - cargoSha256 = "13sj9j9kl6js75h9xq0yidxy63vixxm9q3f8jil6ymarml5wkhx8"; - }; - vivadoEnv = pkgs.buildFHSUserEnv { name = "vivado-env"; targetPkgs = vivadoDeps; @@ -235,12 +221,12 @@ (pkgs.python3.withPackages(ps: [ ps.jsonschema migen misoc (artiq.withExperimentalFeatures experimentalFeatures) ])) rustPlatform.rust.rustc rustPlatform.rust.cargo + pkgs.cargo-xbuild pkgs.llvmPackages_11.clang-unwrapped pkgs.llvm_11 pkgs.lld_11 vivado rustPlatform.cargoSetupHook - cargo-xbuild ]; buildPhase = '' @@ -396,7 +382,7 @@ (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ migen misoc artiq ps.paramiko ps.jsonschema microscope ])) rustPlatform.rust.rustc rustPlatform.rust.cargo - cargo-xbuild + pkgs.cargo-xbuild pkgs.llvmPackages_11.clang-unwrapped pkgs.llvm_11 pkgs.lld_11