def __init__(self, platform, eem0, eem1): spip, spin = [[ platform.request("{}_qspi_{}".format(eem, pol), 0) for eem in (eem0, eem1) ] for pol in "pn"] ioup = [ platform.request("{}_io_update".format(eem), 0) for eem in (eem0, eem1) ] self.cs_n = Signal() self.clk = Signal() self.io_update = Signal() 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)) for i in range(2)] for i in range(8): mosi = Signal() setattr(self, "mosi{}".format(i), mosi) self.specials += [ DifferentialOutput( mosi, getattr(spip[i // 4], "mosi{}".format(i % 4)), getattr(spin[i // 4], "mosi{}".format(i % 4))) ]
def __init__(self, platform, eem): self.sck_en = Signal() self.cnv = Signal() self.clkout = Signal() spip = platform.request("{}_adc_spi_p".format(eem)) spin = platform.request("{}_adc_spi_n".format(eem)) cnv = platform.request("{}_cnv".format(eem)) sdr = platform.request("{}_sdr".format(eem)) dp = platform.request("{}_adc_data_p".format(eem)) dn = platform.request("{}_adc_data_n".format(eem)) clkout_se = Signal() clkout_inv = Signal() sck = Signal() self.specials += [ DifferentialOutput(self.cnv, cnv.p, cnv.n), DifferentialOutput(1, sdr.p, sdr.n), DDROutput(self.sck_en, 0, sck, ClockSignal("sys")), DifferentialOutput(sck, spip.clk, spin.clk), DifferentialInput(dp.clkout, dn.clkout, clkout_se), # FIXME (hardware): CLKOUT is inverted # (Sampler v2.0, v2.1) out on rising, in on falling Instance("BUFR", i_I=clkout_se, o_O=clkout_inv) ] self.comb += self.clkout.eq(~clkout_inv) # define clock here before the input delays below self.clkout_p = dp.clkout # available for false paths platform.add_platform_command( "create_clock -name {clk} -period 8 [get_nets {clk}]", clk=dp.clkout) # platform.add_period_constraint(sampler_pads.clkout_p, 8.) for i in "abcd": sdo = Signal() setattr(self, "sdo{}".format(i), sdo) if i != "a": # FIXME (hardware): sdob, sdoc, sdod are inverted # (Sampler v2.0, v2.1) sdo, sdo_inv = Signal(), sdo self.comb += sdo_inv.eq(~sdo) sdop = getattr(dp, "sdo{}".format(i)) sdon = getattr(dn, "sdo{}".format(i)) self.specials += [ DifferentialInput(sdop, sdon, sdo), ] # -0+1.5 hold (t_HSDO_SDR), -0.5+0.5 skew platform.add_platform_command( "set_input_delay -clock {clk} -max 2 [get_ports {port}]\n" "set_input_delay -clock {clk} -min -0.5 [get_ports {port}]", clk=dp.clkout, port=sdop)
def __init__(self, platform, eem): self.sdi = Signal() self.srclk = Signal() self.rclk = Signal() pgia_spip = platform.request("{}_pgia_spi_p".format(eem)) pgia_spin = platform.request("{}_pgia_spi_n".format(eem)) self.specials += [ DifferentialOutput(self.sdi, pgia_spip.mosi, pgia_spin.mosi), DifferentialOutput(self.srclk, pgia_spip.clk, pgia_spin.clk), DifferentialOutput(self.rclk, pgia_spip.cs_n, pgia_spin.cs_n), ]
def __init__(self, pad, pad_n=None, ftw_width=24, dci=False): self.rtlink = rtlink.Interface(rtlink.OInterface(ftw_width)) # # # pad_o = Signal() if pad_n is None: self.comb += pad.eq(pad_o) else: self.specials += DifferentialOutput(pad_o, pad, pad_n) ftw = Signal(ftw_width) acc = Signal(ftw_width) self.sync.rio += If(self.rtlink.o.stb, ftw.eq(self.rtlink.o.data)) self.sync.rio_phy += [ acc.eq(acc + ftw), # rtlink takes precedence over regular acc increments If( self.rtlink.o.stb, If( self.rtlink.o.data != 0, # known phase on frequency write: at rising edge acc.eq(2**(ftw_width - 1))).Else( # set output to 0 on stop acc.eq(0))), pad_o.eq(acc[-1]) ]
def add_std(cls, target, eem, eem_aux, ttl_out_cls, sync_gen_cls=None, iostandard="LVDS_25"): cls.add_extension(target, eem, eem_aux, iostandard=iostandard) phy = spi2.SPIMaster( target.platform.request("urukul{}_spi_p".format(eem)), target.platform.request("urukul{}_spi_n".format(eem))) target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) pads = target.platform.request( "urukul{}_dds_reset_sync_in".format(eem)) pad = Signal(reset=0) target.specials += DifferentialOutput(pad, pads.p, pads.n) if sync_gen_cls is not None: # AD9910 variant and SYNC_IN from EEM phy = sync_gen_cls(pad, ftw_width=4) target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy)) pads = target.platform.request("urukul{}_io_update".format(eem)) phy = ttl_out_cls(pads.p, pads.n) target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy)) if eem_aux is not None: for signal in "sw0 sw1 sw2 sw3".split(): pads = target.platform.request("urukul{}_{}".format( eem, signal)) phy = ttl_out_cls(pads.p, pads.n) target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy))
def register_jsync(self, jsync): self.jsync_registered = True if isinstance(jsync, Signal): self.comb += jsync.eq(self.jsync) elif isinstance(jsync, Record): self.specials += DifferentialOutput(self.jsync, jsync.p, jsync.n) else: raise ValueError
def __init__(self, platform, eem): self.sck_en = Signal() self.cnv = Signal() self.clkout = Signal() spip = platform.request("{}_adc_spi_p".format(eem)) spin = platform.request("{}_adc_spi_n".format(eem)) cnv = platform.request("{}_cnv".format(eem)) sdr = platform.request("{}_sdr".format(eem)) dp = platform.request("{}_adc_data_p".format(eem)) dn = platform.request("{}_adc_data_n".format(eem)) clkout_se = Signal() sck = Signal() self.specials += [ DifferentialOutput(self.cnv, cnv.p, cnv.n), DifferentialOutput(1, sdr.p, sdr.n), DDROutput(0, self.sck_en, sck, ClockSignal("rio_phy")), DifferentialOutput(sck, spip.clk, spin.clk), DifferentialInput(dp.clkout, dn.clkout, clkout_se), Instance("BUFR", i_I=clkout_se, o_O=self.clkout) ] # here to be early before the input delays below to have the clock # available self.clkout_p = dp.clkout # availabel for false paths platform.add_platform_command( "create_clock -name {clk} -period 8 [get_nets {clk}]", clk=dp.clkout) # platform.add_period_constraint(sampler_pads.clkout_p, 8.) for i in "abcd": sdo = Signal() setattr(self, "sdo{}".format(i), sdo) sdop = getattr(dp, "sdo{}".format(i)) sdon = getattr(dn, "sdo{}".format(i)) self.specials += [ DifferentialInput(sdop, sdon, sdo), ] # 8, -0+1.5 hold (t_HSDO_DDR), -0.5+0.5 skew platform.add_platform_command( "set_input_delay -clock {clk} " "-max 2 [get_ports {port}] -clock_fall\n" "set_input_delay -clock {clk} " "-min -0.5 [get_ports {port}] -clock_fall", clk=dp.clkout, port=sdop)
def __init__(self, **kwargs): _StandaloneBase.__init__(self, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = "125.0" platform = self.platform platform.add_extension(_urukul("eem1", "eem0")) platform.add_extension(_dio("eem2")) platform.add_extension(_dio("eem3")) platform.add_extension(_dio("eem4")) platform.add_extension(_dio("eem5")) platform.add_extension(_dio("eem6")) # EEM clock fan-out from Si5324, not MMCX self.comb += platform.request("clk_sel").eq(1) # EEM2-6: TTL rtio_channels = [] for i in range(40): eem_offset, port = divmod(i, 8) pads = platform.request("eem{}".format(2 + eem_offset), port) phy = ttl_serdes_7series.InOut_8X(pads.p, pads.n) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) # EEM0, EEM1: Urukul phy = spi2.SPIMaster(self.platform.request("eem1_spi_p"), self.platform.request("eem1_spi_n")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) pads = platform.request("eem1_dds_reset") self.specials += DifferentialOutput(0, pads.p, pads.n) for signal in "io_update sw0 sw1 sw2 sw3".split(): pads = platform.request("eem1_{}".format(signal)) phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) for i in (1, 2): sfp_ctl = platform.request("sfp_ctl", i) phy = ttl_simple.Output(sfp_ctl.led) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) rtio_channels.append(rtio.LogChannel()) self.add_rtio(rtio_channels)
def _oserdes(self, data, pin_p, pin_n, clk="sys2", attr=set()): pin = Signal() self.specials += [ Instance("OSERDESE2", attr=attr, p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", p_DATA_WIDTH=4, p_TRISTATE_WIDTH=1, i_RST=ResetSignal(), i_CLK=ClockSignal(clk), i_CLKDIV=ClockSignal(), # LSB first, D1 is closest to Q i_D1=data[0], i_D2=data[1], i_D3=data[2], i_D4=data[3], i_TCE=1, i_OCE=1, i_T1=0, o_OQ=pin), DifferentialOutput(pin, pin_p, pin_n), ]
def __init__(self, platform, eem): self.sdi = Signal() self.ldac = Signal() self.busy = Signal(reset=1) self.syncr = Signal(reset=1) self.rst = Signal(reset=1) self.clr = Signal(reset=1) self.sclk = Signal() spip = platform.request("{}_spi_p".format(eem)) spin = platform.request("{}_spi_n".format(eem)) ldacn = platform.request("{}_ldac_n".format(eem)) busy = platform.request("{}_busy".format(eem)) clrn = platform.request("{}_clr_n".format(eem)) self.specials += [ DifferentialOutput(self.ldac, ldacn.p, ldacn.n), DifferentialOutput(self.sdi, spip.mosi, spin.mosi), DifferentialOutput(self.sclk, spip.clk, spin.clk), DifferentialOutput(self.syncr, spip.cs_n, spin.cs_n), DifferentialOutput(self.clr, clrn.p, clrn.n), DifferentialInput(busy.p, busy.n, self.busy), ]
def __init__(self, pins, pins_n): self.data = [Signal(2) for _ in range(2 + len(pins.mosi))] for d, pp, pn in zip(self.data, [pins.clk] + list(pins.mosi), [pins_n.clk] + list(pins_n.mosi)): ddr = Signal() self.specials += [ # d1 closer to q DDROutput(d[1], d[0], ddr, ClockSignal("rio_phy")), DifferentialOutput(ddr, pp, pn), ] ddr = Signal() self.specials += [ DifferentialInput(pins.miso, pins_n.miso, ddr), # q1 closer to d DDRInput(ddr, self.data[-1][0], self.data[-1][1], ClockSignal("rio_phy")), ]
def __init__(self, pad, pad_n=None): self.rtlink = rtlink.Interface(rtlink.OInterface(1)) pad_o = Signal(reset_less=True) self.probes = [pad_o] override_en = Signal() override_o = Signal() self.overrides = [override_en, override_o] # # # pad_k = Signal() self.sync.rio_phy += [ If(self.rtlink.o.stb, pad_k.eq(self.rtlink.o.data)), If(override_en, pad_o.eq(override_o)).Else(pad_o.eq(pad_k)) ] if pad_n is None: self.comb += pad.eq(pad_o) else: self.specials += DifferentialOutput(pad_o, pad, pad_n)
def __init__(self, p, sys_clk_freq, f_sample_tx=None): # ---------------------------- # Clock and Reset Generation # ---------------------------- xtal_pads = p.request(p.default_clk_name) xtal = Signal() self.specials += DifferentialInput(xtal_pads.p, xtal_pads.n, xtal) xtal_f = 1e9 / p.default_clk_period rst = p.request("cpu_reset") cds = [("cd_sys", sys_clk_freq)] if f_sample_tx is not None: cds.append(("cd_sample_tx", f_sample_tx)) for cd, f in cds: setattr(self.clock_domains, cd, ClockDomain(cd)) pll = S6PLL(speedgrade=-3) self.comb += pll.reset.eq(rst) pll.register_clkin(xtal, xtal_f) pll.create_clkout(getattr(self, cd), f) self.submodules += pll if f_sample_tx is not None: # Provide a ENC clock signal on SMA_GPIO enc_out = Signal() self.specials += Instance( "ODDR2", o_Q=enc_out, i_C0=ClockSignal("sample_tx"), i_C1=~ClockSignal("sample_tx"), i_CE=1, i_D0=1, i_D1=0 ) p.add_extension( # Connect GPIO_SMA on SP605 with CLK input on 1525A [("ENC_CLK", 0, Subsignal("p", Pins("SMA_GPIO:P")), Subsignal("n", Pins("SMA_GPIO:N")), # Note: the LTC eval board needs to be modded # to accept a differential clock IOStandard("LVDS_25") )] ) gpio_pads = p.request("ENC_CLK") self.specials += DifferentialOutput(enc_out, gpio_pads.p, gpio_pads.n)
def add_std(cls, target, eem, eem_aux, ttl_out_cls, iostandard="LVDS_25"): cls.add_extension(target, eem, eem_aux, iostandard=iostandard) phy = spi2.SPIMaster( target.platform.request("sampler{}_adc_spi_p".format(eem)), target.platform.request("sampler{}_adc_spi_n".format(eem))) target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) phy = spi2.SPIMaster( target.platform.request("sampler{}_pgia_spi_p".format(eem)), target.platform.request("sampler{}_pgia_spi_n".format(eem))) target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) pads = target.platform.request("sampler{}_cnv".format(eem)) phy = ttl_out_cls(pads.p, pads.n) target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy)) sdr = target.platform.request("sampler{}_sdr".format(eem)) target.specials += DifferentialOutput(1, sdr.p, sdr.n)
def add_std(cls, target, eem, eem_aux, ttl_out_cls): cls.add_extension(target, eem, eem_aux) phy = spi2.SPIMaster( target.platform.request("urukul{}_spi_p".format(eem)), target.platform.request("urukul{}_spi_n".format(eem))) target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) pads = target.platform.request("urukul{}_dds_reset".format(eem)) target.specials += DifferentialOutput(0, pads.p, pads.n) pads = target.platform.request("urukul{}_io_update".format(eem)) phy = ttl_out_cls(pads.p, pads.n) target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy)) if eem_aux is not None: for signal in "sw0 sw1 sw2 sw3".split(): pads = target.platform.request("urukul{}_{}".format( eem, signal)) phy = ttl_out_cls(pads.p, pads.n) target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy))
def add_std(cls, target, eems_sampler, eems_urukul0, eems_urukul1, t_rtt=4, clk=1, shift=11, profile=5): """Add a 8-channel Sampler-Urukul Servo :param t_rtt: upper estimate for clock round-trip propagation time from ``sck`` at the FPGA to ``clkout`` at the FPGA, measured in RTIO coarse cycles (default: 4). This is the sum of the round-trip cabling delay and the 8 ns max propagation delay on Sampler (ADC and LVDS drivers). Increasing ``t_rtt`` increases servo latency. With all other parameters at their default values, ``t_rtt`` values above 4 also increase the servo period (reduce servo bandwidth). :param clk: DDS SPI clock cycle half-width in RTIO coarse cycles (default: 1) :param shift: fixed-point scaling factor for IIR coefficients (default: 11) :param profile: log2 of the number of profiles for each DDS channel (default: 5) """ cls.add_extension(target, *(eems_sampler + eems_urukul0 + eems_urukul1)) eem_sampler = "sampler{}".format(eems_sampler[0]) eem_urukul0 = "urukul{}".format(eems_urukul0[0]) eem_urukul1 = "urukul{}".format(eems_urukul1[0]) sampler_pads = servo_pads.SamplerPads(target.platform, eem_sampler) urukul_pads = servo_pads.UrukulPads(target.platform, eem_urukul0, eem_urukul1) # 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 # difference (4 cycles measured) 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, channel=3, profile=profile) dds_p = servo.DDSParams(width=8 + 32 + 16 + 16, channels=adc_p.channels, clk=clk) su = servo.Servo(sampler_pads, urukul_pads, adc_p, iir_p, dds_p) su = ClockDomainsRenamer("rio_phy")(su) target.submodules += sampler_pads, urukul_pads, su ctrls = [rtservo.RTServoCtrl(ctrl) for ctrl in su.iir.ctrl] target.submodules += ctrls target.rtio_channels.extend( rtio.Channel.from_phy(ctrl) for ctrl in ctrls) mem = rtservo.RTServoMem(iir_p, su) target.submodules += mem target.rtio_channels.append(rtio.Channel.from_phy(mem, ififo_depth=4)) phy = spi2.SPIMaster( target.platform.request("{}_pgia_spi_p".format(eem_sampler)), target.platform.request("{}_pgia_spi_n".format(eem_sampler))) target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) phy = spi2.SPIMaster( target.platform.request("{}_spi_p".format(eem_urukul0)), target.platform.request("{}_spi_n".format(eem_urukul0))) target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) pads = target.platform.request("{}_dds_reset".format(eem_urukul0)) target.specials += DifferentialOutput(0, pads.p, pads.n) for i, signal in enumerate("sw0 sw1 sw2 sw3".split()): pads = target.platform.request("{}_{}".format(eem_urukul0, signal)) target.specials += DifferentialOutput(su.iir.ctrl[i].en_out, pads.p, pads.n) phy = spi2.SPIMaster( target.platform.request("{}_spi_p".format(eem_urukul1)), target.platform.request("{}_spi_n".format(eem_urukul1))) target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) pads = target.platform.request("{}_dds_reset".format(eem_urukul1)) target.specials += DifferentialOutput(0, pads.p, pads.n) for i, signal in enumerate("sw0 sw1 sw2 sw3".split()): pads = target.platform.request("{}_{}".format(eem_urukul1, signal)) target.specials += DifferentialOutput(su.iir.ctrl[i + 4].en_out, pads.p, pads.n)
def __init__(self, pins, pins_n): n_bits = 16 # bits per dac data word n_channels = 32 # channels per fastino n_div = 7 # bits per lane and word assert n_div == 7 n_frame = 14 # word per frame n_lanes = len(pins.mosi) # number of data lanes n_checksum = 12 # checksum bits n_addr = 4 # readback address bits n_word = n_lanes*n_div n_body = n_word*n_frame - (n_frame//2 + 1) - n_checksum # dac data words self.dacs = [Signal(n_bits) for i in range(n_channels)] # dac update enable self.enable = Signal(n_channels) # configuration word self.cfg = Signal(20) # readback data self.dat_r = Signal(n_frame//2*(1 << n_addr)) # data load synchronization event self.stb = Signal() # # # # crc-12 telco self.submodules.crc = LiteEthMACCRCEngine( data_width=2*n_lanes, width=n_checksum, polynom=0x80f) addr = Signal(4) body_ = Cat(self.cfg, addr, self.enable, self.dacs) assert len(body_) == n_body body = Signal(n_body) self.comb += body.eq(body_) words_ = [] j = 0 for i in range(n_frame): # iterate over words if i == 0: # data and checksum k = n_word - n_checksum elif i == 1: # marker words_.append(C(1)) k = n_word - 1 elif i < n_frame//2 + 2: # marker words_.append(C(0)) k = n_word - 1 else: # full word k = n_word # append corresponding frame body bits words_.append(body[j:j + k]) j += k words_ = Cat(words_) assert len(words_) == n_frame*n_word - n_checksum words = Signal(len(words_)) self.comb += words.eq(words_) clk = Signal(n_div, reset=0b1100011) clk_stb = Signal() i_frame = Signal(max=n_div*n_frame//2) # DDR frame_stb = Signal() sr = [Signal(n_frame*n_div - n_checksum//n_lanes, reset_less=True) for i in range(n_lanes)] assert len(Cat(sr)) == len(words) # DDR bits for each register ddr_data = Cat([sri[-2] for sri in sr], [sri[-1] for sri in sr]) self.comb += [ # assert one cycle ahead clk_stb.eq(~clk[0] & clk[-1]), # double period because of DDR frame_stb.eq(i_frame == n_div*n_frame//2 - 1), # LiteETHMACCRCEngine takes data LSB first self.crc.data[::-1].eq(ddr_data), self.stb.eq(frame_stb & clk_stb), ] miso = Signal() miso_sr = Signal(n_frame, reset_less=True) self.sync.rio_phy += [ # shift 7 bit clock pattern by two bits each DDR cycle clk.eq(Cat(clk[-2:], clk)), [sri[2:].eq(sri) for sri in sr], self.crc.last.eq(self.crc.next), If(clk[:2] == 0, # TODO: tweak MISO sampling miso_sr.eq(Cat(miso, miso_sr)), ), If(~frame_stb, i_frame.eq(i_frame + 1), ), If(frame_stb & clk_stb, i_frame.eq(0), self.crc.last.eq(0), # transpose, load Cat(sr).eq(Cat(words[mm::n_lanes] for mm in range(n_lanes))), Array([self.dat_r[i*n_frame//2:(i + 1)*n_frame//2] for i in range(1 << len(addr))])[addr].eq(miso_sr), addr.eq(addr + 1), ), If(i_frame == n_div*n_frame//2 - 2, # inject crc ddr_data.eq(self.crc.next), ), ] clk_ddr = Signal() miso0 = Signal() self.specials += [ DDROutput(clk[-1], clk[-2], clk_ddr, ClockSignal("rio_phy")), DifferentialOutput(clk_ddr, pins.clk, pins_n.clk), DifferentialInput(pins.miso, pins_n.miso, miso0), MultiReg(miso0, miso, "rio_phy"), ] for sri, ddr, mp, mn in zip( sr, Signal(n_lanes), pins.mosi, pins_n.mosi): self.specials += [ DDROutput(sri[-1], sri[-2], ddr, ClockSignal("rio_phy")), DifferentialOutput(ddr, mp, mn), ]
def __init__(self, **kwargs): _StandaloneBase.__init__(self, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None # self.config["SI5324_EXT_REF"] = None self.config["RTIO_FREQUENCY"] = "125.0" platform = self.platform platform.add_extension(_dio("eem0")) platform.add_extension(_dio("eem1")) platform.add_extension(_dio("eem2")) platform.add_extension(_novogorny("eem3")) platform.add_extension(_urukul("eem5", "eem4")) platform.add_extension(_urukul("eem6")) platform.add_extension(_zotino("eem7")) # EEM clock fan-out from Si5324, not MMCX try: self.comb += platform.request("clk_sel").eq(1) except ConstraintError: pass rtio_channels = [] for i in range(24): eem, port = divmod(i, 8) pads = platform.request("eem{}".format(eem), port) if i < 4: cls = ttl_serdes_7series.InOut_8X else: cls = ttl_serdes_7series.Output_8X phy = cls(pads.p, pads.n) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) # EEM3: Novogorny phy = spi2.SPIMaster(self.platform.request("eem3_spi_p"), self.platform.request("eem3_spi_n")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=16)) for signal in "conv".split(): pads = platform.request("eem3_{}".format(signal)) phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) # EEM5 + EEM4: Urukul phy = spi2.SPIMaster(self.platform.request("eem5_spi_p"), self.platform.request("eem5_spi_n")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) pads = platform.request("eem5_dds_reset") self.specials += DifferentialOutput(0, pads.p, pads.n) for signal in "io_update sw0 sw1 sw2 sw3".split(): pads = platform.request("eem5_{}".format(signal)) phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) for i in (1, 2): sfp_ctl = platform.request("sfp_ctl", i) phy = ttl_simple.Output(sfp_ctl.led) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) # EEM6: Urukul phy = spi2.SPIMaster(self.platform.request("eem6_spi_p"), self.platform.request("eem6_spi_n")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) for signal in "io_update".split(): pads = platform.request("eem6_{}".format(signal)) phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) pads = platform.request("eem6_dds_reset") self.specials += DifferentialOutput(0, pads.p, pads.n) # EEM7: Zotino phy = spi2.SPIMaster(self.platform.request("eem7_spi_p"), self.platform.request("eem7_spi_n")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) for signal in "ldac_n clr_n".split(): pads = platform.request("eem7_{}".format(signal)) phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) rtio_channels.append(rtio.LogChannel()) self.add_rtio(rtio_channels)
def add_std(cls, target, eems_sampler, eems_urukul, t_rtt=4, clk=1, shift=11, profile=5, iostandard="LVDS_25"): """Add a 8-channel Sampler-Urukul Servo :param t_rtt: upper estimate for clock round-trip propagation time from ``sck`` at the FPGA to ``clkout`` at the FPGA, measured in RTIO coarse cycles (default: 4). This is the sum of the round-trip cabling delay and the 8 ns max propagation delay on Sampler (ADC and LVDS drivers). Increasing ``t_rtt`` increases servo latency. With all other parameters at their default values, ``t_rtt`` values above 4 also increase the servo period (reduce servo bandwidth). :param clk: DDS SPI clock cycle half-width in RTIO coarse cycles (default: 1) :param shift: fixed-point scaling factor for IIR coefficients (default: 11) :param profile: log2 of the number of profiles for each DDS channel (default: 5) """ cls.add_extension(target, *(eems_sampler + sum(eems_urukul, [])), iostandard=iostandard) eem_sampler = "sampler{}".format(eems_sampler[0]) eem_urukul = ["urukul{}".format(i[0]) for i in eems_urukul] sampler_pads = servo_pads.SamplerPads(target.platform, eem_sampler) urukul_pads = servo_pads.UrukulPads(target.platform, *eem_urukul) target.submodules += sampler_pads, urukul_pads # 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 # difference (4 cycles measured) 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, channel=3, profile=profile, dly=8) dds_p = servo.DDSParams(width=8 + 32 + 16 + 16, channels=adc_p.channels, 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] target.submodules += ctrls target.rtio_channels.extend( rtio.Channel.from_phy(ctrl) for ctrl in ctrls) mem = rtservo.RTServoMem(iir_p, su) target.submodules += mem target.rtio_channels.append(rtio.Channel.from_phy(mem, ififo_depth=4)) phy = spi2.SPIMaster( target.platform.request("{}_pgia_spi_p".format(eem_sampler)), target.platform.request("{}_pgia_spi_n".format(eem_sampler))) target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) for i in range(2): if len(eem_urukul) > i: spi_p, spi_n = (target.platform.request("{}_spi_p".format( eem_urukul[i])), target.platform.request("{}_spi_n".format( eem_urukul[i]))) else: # create a dummy bus spi_p = Record([("clk", 1), ("cs_n", 1)]) # mosi, cs_n spi_n = None phy = spi2.SPIMaster(spi_p, spi_n) target.submodules += phy target.rtio_channels.append( rtio.Channel.from_phy(phy, ififo_depth=4)) for j, eem_urukuli in enumerate(eem_urukul): pads = target.platform.request( "{}_dds_reset_sync_in".format(eem_urukuli)) target.specials += DifferentialOutput(0, pads.p, pads.n) for i, signal in enumerate("sw0 sw1 sw2 sw3".split()): pads = target.platform.request("{}_{}".format( eem_urukuli, signal)) target.specials += DifferentialOutput( su.iir.ctrl[j * 4 + i].en_out, pads.p, pads.n)
def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = "v1.1" _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": # EEM clock fan-out from Si5324, not MMCX self.comb += self.platform.request("clk_sel").eq(1) self.rtio_channels = [] # EEM0, EEM1: DIO eem.DIO.add_std(self, 0, ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) eem.DIO.add_std(self, 1, ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) # EEM3, EEM2: Sampler self.platform.add_extension(eem.Sampler.io(3, 2)) sampler_pads = servo_pads.SamplerPads(self.platform, "sampler3") # EEM5, EEM4 and EEM7, EEM6: Urukul self.platform.add_extension(eem.Urukul.io_qspi(5, 4)) self.platform.add_extension(eem.Urukul.io_qspi(7, 6)) urukul_pads = servo_pads.UrukulPads(self.platform, "urukul5", "urukul7") adc_p = servo.ADCParams(width=16, channels=8, lanes=4, t_cnvh=4, # account for SCK pipeline latency 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) dds_p = servo.DDSParams(width=8 + 32 + 16 + 16, channels=adc_p.channels, clk=1) su = servo.Servo(sampler_pads, urukul_pads, adc_p, iir_p, dds_p) su = ClockDomainsRenamer("rio_phy")(su) self.submodules += sampler_pads, urukul_pads, su ctrls = [rtservo.RTServoCtrl(ctrl) for ctrl in su.iir.ctrl] self.submodules += ctrls self.rtio_channels.extend(rtio.Channel.from_phy(ctrl) for ctrl in ctrls) mem = rtservo.RTServoMem(iir_p, su) self.submodules += mem self.rtio_channels.append(rtio.Channel.from_phy(mem, ififo_depth=4)) # EEM3: Sampler phy = spi2.SPIMaster(self.platform.request("sampler3_pgia_spi_p"), self.platform.request("sampler3_pgia_spi_n")) self.submodules += phy self.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) # EEM5 + EEM4: Urukul phy = spi2.SPIMaster(self.platform.request("urukul5_spi_p"), self.platform.request("urukul5_spi_n")) self.submodules += phy self.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) pads = self.platform.request("urukul5_dds_reset") self.specials += DifferentialOutput(0, pads.p, pads.n) for i, signal in enumerate("sw0 sw1 sw2 sw3".split()): pads = self.platform.request("urukul5_{}".format(signal)) self.specials += DifferentialOutput( su.iir.ctrl[i].en_out, pads.p, pads.n) # EEM7 + EEM6: Urukul phy = spi2.SPIMaster(self.platform.request("urukul7_spi_p"), self.platform.request("urukul7_spi_n")) self.submodules += phy self.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) pads = self.platform.request("urukul7_dds_reset") self.specials += DifferentialOutput(0, pads.p, pads.n) for i, signal in enumerate("sw0 sw1 sw2 sw3".split()): pads = self.platform.request("urukul7_{}".format(signal)) self.specials += DifferentialOutput( su.iir.ctrl[i + 4].en_out, pads.p, pads.n) for i in (1, 2): sfp_ctl = self.platform.request("sfp_ctl", i) phy = ttl_simple.Output(sfp_ctl.led) self.submodules += phy self.rtio_channels.append(rtio.Channel.from_phy(phy)) self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) self.rtio_channels.append(rtio.LogChannel()) self.add_rtio(self.rtio_channels) self.platform.add_false_path_constraints( sampler_pads.clkout_p, self.rtio_crg.cd_rtio.clk) self.platform.add_false_path_constraints( sampler_pads.clkout_p, self.crg.cd_sys.clk)
def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = "v1.1" _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = "125.0" platform = self.platform # TODO: grabber on eem0->eemB eem1->eemA platform.add_extension(_urukul("eem3", "eem2")) platform.add_extension(_dio("eem4")) platform.add_extension(_zotino("eem5")) platform.add_extension(_zotino("eem6")) # EEM4: TTL rtio_channels = [] for i in range(8): pads = platform.request("eem4", i) phy = ttl_serdes_7series.InOut_8X(pads.p, pads.n) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) # EEM2, EEM3: Urukul phy = spi2.SPIMaster(self.platform.request("eem3_spi_p"), self.platform.request("eem3_spi_n")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) pads = platform.request("eem3_dds_reset") self.specials += DifferentialOutput(0, pads.p, pads.n) for signal in "io_update sw0 sw1 sw2 sw3".split(): pads = platform.request("eem3_{}".format(signal)) phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) # EEM5, EEM6: Zotino for i in (5, 6): phy = spi2.SPIMaster( self.platform.request("eem{}_spi_p".format(i)), self.platform.request("eem{}_spi_n".format(i))) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) for signal in "ldac_n clr_n".split(): pads = platform.request("eem{}_{}".format(i, signal)) phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) for i in (1, 2): sfp_ctl = platform.request("sfp_ctl", i) phy = ttl_simple.Output(sfp_ctl.led) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) rtio_channels.append(rtio.LogChannel()) self.add_rtio(rtio_channels)
def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = "v1.1" _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" platform = self.platform platform.add_extension(_dio("eem0")) platform.add_extension(_dio("eem1")) platform.add_extension(_sampler("eem3", "eem2")) platform.add_extension(_urukul_qspi("eem5", "eem4")) platform.add_extension(_urukul_qspi("eem7", "eem6")) try: # EEM clock fan-out from Si5324, not MMCX, only Kasli/v1.0 self.comb += platform.request("clk_sel").eq(1) except ConstraintError: pass rtio_channels = [] for i in range(16): eem, port = divmod(i, 8) pads = platform.request("eem{}".format(eem), port) if i < 4: cls = ttl_serdes_7series.InOut_8X else: cls = ttl_serdes_7series.Output_8X phy = cls(pads.p, pads.n) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) # EEM3, EEM2: Sampler sampler_pads = servo_pads.SamplerPads(self.platform, "eem3") # EEM5, EEM4 and EEM7, EEM6: Urukul urukul_pads = servo_pads.UrukulPads(self.platform, "eem5", "eem7") adc_p = servo.ADCParams( width=16, channels=8, lanes=4, t_cnvh=4, # account for SCK pipeline latency 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) dds_p = servo.DDSParams(width=8 + 32 + 16 + 16, channels=adc_p.channels, clk=1) su = servo.Servo(sampler_pads, urukul_pads, adc_p, iir_p, dds_p) su = ClockDomainsRenamer("rio_phy")(su) self.submodules += sampler_pads, urukul_pads, su ctrls = [rtservo.RTServoCtrl(ctrl) for ctrl in su.iir.ctrl] self.submodules += ctrls rtio_channels.extend(rtio.Channel.from_phy(ctrl) for ctrl in ctrls) mem = rtservo.RTServoMem(iir_p, su) self.submodules += mem rtio_channels.append(rtio.Channel.from_phy(mem, ififo_depth=4)) # EEM3: Sampler phy = spi2.SPIMaster(self.platform.request("eem3_pgia_spi_p"), self.platform.request("eem3_pgia_spi_n")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) # EEM5 + EEM4: Urukul phy = spi2.SPIMaster(self.platform.request("eem5_spi_p"), self.platform.request("eem5_spi_n")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) pads = platform.request("eem5_dds_reset") self.specials += DifferentialOutput(0, pads.p, pads.n) for i, signal in enumerate("sw0 sw1 sw2 sw3".split()): pads = platform.request("eem5_{}".format(signal)) self.specials += DifferentialOutput(su.iir.ctrl[i].en_out, pads.p, pads.n) # EEM7 + EEM6: Urukul phy = spi2.SPIMaster(self.platform.request("eem7_spi_p"), self.platform.request("eem7_spi_n")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) pads = platform.request("eem7_dds_reset") self.specials += DifferentialOutput(0, pads.p, pads.n) for i, signal in enumerate("sw0 sw1 sw2 sw3".split()): pads = platform.request("eem7_{}".format(signal)) self.specials += DifferentialOutput(su.iir.ctrl[i + 4].en_out, pads.p, pads.n) for i in (1, 2): sfp_ctl = platform.request("sfp_ctl", i) phy = ttl_simple.Output(sfp_ctl.led) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) rtio_channels.append(rtio.LogChannel()) self.add_rtio(rtio_channels) platform.add_false_path_constraints(sampler_pads.clkout_p, self.rtio_crg.cd_rtio.clk) platform.add_false_path_constraints(sampler_pads.clkout_p, self.crg.cd_sys.clk)
def __init__(self, pads): self.pads = pads self.bus = bus = wishbone.Interface() # # # clk = Signal() clk_phase = Signal(2) cs = Signal() ca = Signal(48) sr = Signal(48) dq = self.add_tristate( pads.dq) if not hasattr(pads.dq, "oe") else pads.dq rwds = self.add_tristate( pads.rwds) if not hasattr(pads.rwds, "oe") else pads.rwds # Drive rst_n, cs_n, clk from internal signals --------------------------------------------- if hasattr(pads, "rst_n"): self.comb += pads.rst_n.eq(1) self.comb += pads.cs_n[0].eq(~cs) assert len(pads.cs_n) <= 2 if len(pads.cs_n) == 2: self.comb += pads.cs_n[1].eq(1) if hasattr(pads, "clk"): self.comb += pads.clk.eq(clk) else: self.specials += DifferentialOutput(clk, pads.clk_p, pads.clk_n) # Clock Generation (sys_clk/4) ------------------------------------------------------------- self.sync += clk_phase.eq(clk_phase + 1) cases = {} cases[1] = clk.eq(cs) # Set pads clk on 90° (if cs is set) cases[3] = clk.eq(0) # Clear pads clk on 270° self.sync += Case(clk_phase, cases) # Data Shift Register (for write and read) ------------------------------------------------- dqi = Signal(8) self.sync += dqi.eq(dq.i) # Sample on 90° and 270° cases = {} cases[0] = sr.eq(Cat(dqi, sr[:-8])) # Shift on 0° cases[2] = sr.eq(Cat(dqi, sr[:-8])) # Shift on 180° self.sync += Case(clk_phase, cases) self.comb += [ bus.dat_r.eq(sr), # To Wisbone dq.o.eq(sr[-8:]), # To HyperRAM ] # Command generation ----------------------------------------------------------------------- self.comb += [ ca[47].eq(~self.bus.we), # R/W# ca[45].eq(1), # Burst Type (Linear) ca[16:35].eq(self.bus.adr[2:21]), # Row & Upper Column Address ca[1:3].eq(self.bus.adr[0:2]), # Lower Column Address ca[0].eq(0), # Lower Column Address ] # Sequencer -------------------------------------------------------------------------------- dt_seq = [ # DT, Action (3, []), (12, [cs.eq(1), dq.oe.eq(1), sr.eq(ca)]), # Command: 6 clk (44, [dq.oe.eq(0)]), # Latency(default): 2*6 clk ( 2, [ dq.oe.eq(self.bus.we), # Write/Read data byte: 2 clk sr[:16].eq(0), sr[16:].eq(self.bus.dat_w), rwds.oe.eq(self.bus.we), rwds.o.eq(~bus.sel[0]) ]), (2, [rwds.o.eq(~bus.sel[1])]), # Write/Read data byte: 2 clk (2, [rwds.o.eq(~bus.sel[2])]), # Write/Read data byte: 2 clk (2, [rwds.o.eq(~bus.sel[3])]), # Write/Read data byte: 2 clk (2, [cs.eq(0), rwds.oe.eq(0), dq.oe.eq(0)]), (1, [bus.ack.eq(1)]), (1, [bus.ack.eq(0)]), (0, []), ] # Convert delta-time sequencer to time sequencer t_seq = [] t_seq_start = (clk_phase == 1) t = 0 for dt, a in dt_seq: t_seq.append((t, a)) t += dt self.sync += timeline(bus.cyc & bus.stb & t_seq_start, t_seq)