def __init__(self, data_clk_i, frame_signals_i, data_signals_i): # Outputs # ========================================== self.data_clk_o = Signal(name="data_clk_o") self.data_o = [] self.data_stb_o = [] # Design # ========================================== data_clk_to_bufr = Signal() self.clock_domains.cd_dclk = cd_dclk = ClockDomain() # !!!! Inverted! self.specials += DifferentialInput(data_clk_i.p, data_clk_i.n, data_clk_to_bufr) self.specials += Instance("BUFG", i_I=~data_clk_to_bufr, o_O=cd_dclk.clk) # !!!! Inverted! # platform.add_period_constraint(cd_dclk.clk, 4.) self.specials += [AsyncResetSynchronizer(cd_dclk, ResetSignal("sys"))] self.phy_channels = [] for channel, (frame, data) in enumerate(zip(frame_signals_i, data_signals_i)): frame_se = Signal() data_se = Signal() self.specials += DifferentialInput(frame.p, frame.n, frame_se) self.specials += DifferentialInput(data.p, data.n, data_se) channel_phy = ClockDomainsRenamer("dclk")(TdcGpx2ChannelPhy(frame_i=frame_se, data_i=data_se)) self.phy_channels.append(channel_phy) setattr(self.submodules, "channel{}".format(channel), channel_phy) self.data_o.append(channel_phy.data_o) self.data_stb_o.append(channel_phy.stb_o)
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, pad, pad_n=None): self.rtlink = rtlink.Interface(rtlink.OInterface(2, 2), rtlink.IInterface(1)) self.overrides = [] self.probes = [] # # # sensitivity = Signal(2) sample = Signal() self.sync.rio += [ sample.eq(0), If(self.rtlink.o.stb & self.rtlink.o.address[1], sensitivity.eq(self.rtlink.o.data), If(self.rtlink.o.address[0], sample.eq(1))) ] i = Signal() i_d = Signal(reset_less=True) pad_i = Signal() if pad_n is None: self.comb += pad_i.eq(pad) else: self.specials += DifferentialInput(pad, pad_n, pad_i) self.specials += MultiReg(pad_i, i, "rio_phy") self.sync.rio_phy += i_d.eq(i) self.comb += [ self.rtlink.i.stb.eq(sample | (sensitivity[0] & (i & ~i_d)) | (sensitivity[1] & (~i & i_d))), self.rtlink.i.data.eq(i) ] self.probes += [i]
def __init__(self, pad, pad_n=None, name="external_trigger"): super().__init__(name) # Outputs self.trigger_re = Signal() # CD: sys self.trigger_fe = Signal() # CD: sys # FIXME: Revise trigger registration self.register_trigger(self.trigger_re, "re", "rio_phy") self.register_trigger(self.trigger_fe, "fe", "rio_phy") # # # if pad_n is not None: external_trigger = Signal() self.specials += DifferentialInput(pad, pad_n, external_trigger) else: external_trigger = pad trigger_ext_d = Signal() trigger_ext_prev = Signal() self.sync += [ trigger_ext_prev.eq(trigger_ext_d), trigger_ext_d.eq(external_trigger) ] self.comb += [ self.trigger_re.eq(~trigger_ext_prev & trigger_ext_d), self.trigger_fe.eq(trigger_ext_prev & ~trigger_ext_d) ]
def register_jref(self, jref): self.jref_registered = True if isinstance(jref, Signal): self.comb += self.jref.eq(jref) elif isinstance(jref, Record): self.specials += DifferentialInput(jref.p, jref.n, self.jref) else: raise ValueError
def register_jsync(self, jsync): self.jsync_registered = True if isinstance(jsync, Signal): self.comb += self.jsync.eq(jsync) elif isinstance(jsync, Record): self.specials += DifferentialInput(jsync.p, jsync.n, self.jsync) 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 register_clkin(self, clkin, freq): self.clkin = Signal() if isinstance(clkin, (Signal, ClockSignal)): self.comb += self.clkin.eq(clkin) elif isinstance(clkin, Record): self.specials += DifferentialInput(clkin.p, clkin.n, self.clkin) else: raise ValueError self.clkin_freq = freq
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 __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, platform): self.jreset = CSRStorage(reset=1) self.jref = Signal() self.refclk = Signal() refclk2 = Signal() self.clock_domains.cd_jesd = ClockDomain() 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), Instance("BUFG_GT", i_I=refclk2, o_O=self.cd_jesd.clk), AsyncResetSynchronizer(self.cd_jesd, self.jreset.storage), ] jref = platform.request("dac_sysref") self.specials += DifferentialInput(jref.p, jref.n, self.jref)
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, adclk_i, lclk_i, dat_i): """ADS5296A ADC phy for Xilinx Series 7 Args: adclk_i (differential signal): frame clock lclk_i (differential signal): bit clock dat_i (array of differential signals): data lines """ # Module constants # ========================================== DAT_O_LEN = 10 BUFR_DIVIDE = 5 VALID_FRAME_OUT = 0b1111100000 # Outputs # ========================================== self.data_clk_o = Signal() self.bitslip_done = Signal() self.data_o = [Signal(DAT_O_LEN, name="data_{}_o".format(i)) for i in range(9)] # RTLink Control Status Registers # ========================================== regs = [ *[("data{}_delay_value".format(x), 5) for x in range(9)], ("adclk_delay_value", 5), ("phy_reset", 1, 1), ("bitslip_done", 1, 0, "ro") ] csr = RtLinkCSR(regs, "ads5296a_phy") self.submodules.csr = csr # Design # ========================================== input_lines = [*dat_i, adclk_i] lines_delayed = [Signal(name="line_delayed_{}".format(i)) for i in range(9)] # 0 - data[0] # 1 - data[1] # ... # 7 - data[7] # 8 - adclk for idx, (input_line, line_delayed) in enumerate(zip(input_lines, lines_delayed)): line_buffer = Signal() self.specials += DifferentialInput(i_p=input_line.p, i_n=input_line.n, o=line_buffer) self.submodules += XilinxIdelayE2( data_i=line_buffer, data_o=line_delayed, delay_value_i=getattr(csr, regs[idx][0]), delay_value_ld_i=getattr(csr, regs[idx][0]+"_ld") ) # Clocking lclk_ibuf = Signal() lclk_bufg = Signal() self.lclk = lclk_bufg self.lclk_bufio = lclk_bufio = Signal() self.clock_domains.cd_adclk_clkdiv = cd_adclk_clkdiv = ClockDomain() self.specials += [AsyncResetSynchronizer(cd_adclk_clkdiv, csr.phy_reset)] self.specials += DifferentialInput(i_p=lclk_i.p, i_n=lclk_i.n, o=lclk_ibuf) self.specials += Instance("BUFIO", i_I=lclk_ibuf, o_O=lclk_bufio) self.specials += Instance("BUFR", p_BUFR_DIVIDE=str(BUFR_DIVIDE), i_I=lclk_ibuf, i_CE=1, i_CLR=0, o_O=lclk_bufg) self.specials += Instance("BUFG", i_I=lclk_bufg, o_O=cd_adclk_clkdiv.clk) # Bitslip logic bitslip = Signal() bitslip_cnt = Signal(4) self.sync.adclk_clkdiv += [ bitslip.eq(0), bitslip_cnt.eq(bitslip_cnt + 1), self.bitslip_done.eq(self.data_o[8] == VALID_FRAME_OUT), If(bitslip_cnt == 0x0, If(~self.bitslip_done, bitslip.eq(1))), ] self.specials += MultiReg(i=self.bitslip_done, o=csr.bitslip_done, odomain="rio_phy") # ISERDES # For 10b deserialization we'll be using two ISERDES modules connected in MASTER-SLAVE mode. self.specials += Instance("BUFG", i_I=cd_adclk_clkdiv.clk, o_O=self.data_clk_o) for idx, (line_delayed, dat_o) in enumerate(zip(lines_delayed, self.data_o)): shift1 = Signal(name="shift1_{}".format(idx)) shift2 = Signal(name="shift2_{}".format(idx)) self.specials += Instance("ISERDESE2", p_DATA_RATE="DDR", p_DATA_WIDTH=10, p_INTERFACE_TYPE="NETWORKING", p_NUM_CE=1, p_SERDES_MODE="MASTER", p_IOBDELAY="BOTH", o_Q1=dat_o[0], o_Q2=dat_o[1], o_Q3=dat_o[2], o_Q4=dat_o[3], o_Q5=dat_o[4], o_Q6=dat_o[5], o_Q7=dat_o[6], o_Q8=dat_o[7], o_SHIFTOUT1=shift1, o_SHIFTOUT2=shift2, o_O=Signal(name="output_test_master_{}".format(idx)), i_DDLY=line_delayed, i_CLK=lclk_bufio, i_CLKB=~lclk_bufio, i_CE1=1, i_RST=ResetSignal("adclk_clkdiv"), i_CLKDIV=lclk_bufg, i_CLKDIVP=0, i_BITSLIP=bitslip, i_DYNCLKDIVSEL=0, i_DYNCLKSEL=0) self.specials += Instance("ISERDESE2", p_DATA_RATE="DDR", p_DATA_WIDTH=10, p_INTERFACE_TYPE="NETWORKING", p_NUM_CE=1, p_SERDES_MODE="SLAVE", p_IOBDELAY="BOTH", o_Q3=dat_o[8], o_Q4=dat_o[9], i_SHIFTIN1=shift1, i_SHIFTIN2=shift2, i_CLK=lclk_bufio, i_CLKB=~lclk_bufio, i_CE1=1, i_RST=ResetSignal("adclk_clkdiv"), i_CLKDIV=lclk_bufg, i_CLKDIVP=0, i_BITSLIP=bitslip, i_DYNCLKDIVSEL=0, i_DYNCLKSEL=0)
def __init__(self, platform): self.jreset = CSRStorage(reset=1) self.jsync = CSRStatus() ps = JESD204BPhysicalSettings(l=4, m=4, n=16, np=16) ts = JESD204BTransportSettings(f=2, s=1, k=16, cs=1) settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) linerate = 6e9 refclk_freq = 150e6 fabric_freq = 150 * 1000 * 1000 refclk = Signal() self.clock_domains.cd_jesd = ClockDomain() refclk_pads = platform.request("ad9154_refclk") self.specials += [ Instance("IBUFDS_GTE2", i_CEB=0, i_I=refclk_pads.p, i_IB=refclk_pads.n, o_O=refclk), Instance("BUFG", i_I=refclk, o_O=self.cd_jesd.clk), AsyncResetSynchronizer(self.cd_jesd, self.jreset.storage), ] self.cd_jesd.clk.attr.add("keep") platform.add_period_constraint(self.cd_jesd.clk, 1e9 / refclk_freq) qpll = GTXQuadPLL(refclk, refclk_freq, linerate) self.submodules += qpll self.phys = [] for i in range(4): phy = JESD204BPhyTX(qpll, platform.request("ad9154_jesd", i), fabric_freq) phy.gtx.cd_tx.clk.attr.add("keep") platform.add_period_constraint(phy.gtx.cd_tx.clk, 40 * 1e9 / linerate) platform.add_false_path_constraints(self.cd_jesd.clk, phy.gtx.cd_tx.clk) self.phys.append(phy) to_jesd = ClockDomainsRenamer("jesd") self.submodules.core = to_jesd( JESD204BCoreTX(self.phys, settings, converter_data_width=32)) self.submodules.control = to_jesd(JESD204BCoreTXControl(self.core)) sync_pads = platform.request("ad9154_sync") jsync = Signal() self.specials += [ DifferentialInput(sync_pads.p, sync_pads.n, jsync), MultiReg(jsync, self.jsync.status) ] self.comb += [ platform.request("ad9154_txen", 0).eq(1), platform.request("ad9154_txen", 1).eq(1), self.core.start.eq(jsync), platform.request("user_led", 3).eq(jsync), ] # blinking leds for transceiver reset status for i in range(4): counter = Signal(max=fabric_freq) self.comb += platform.request("user_led", 4 + i).eq(counter[-1]) sync = getattr(self.sync, "phy{}_tx".format(i)) sync += [ counter.eq(counter - 1), If(counter == 0, counter.eq(fabric_freq - 1)) ]
def __init__(self, S, D, MIRROR_BITS, BITSLIPS, idelay_overrides={}, iserdes_overrides={}): """ Generates all logic necessary for the data lanes, calibration and phase detection / adjustment Does not do anything related to clocking. Inherit and add you own clock. """ # LVDS DDR bit clock self.dco_p = Signal() self.dco_n = Signal() # data lanes self.lvds_data_p = Signal(D) self.lvds_data_n = Signal(D) # Control signals (on sample clock domain) self.bitslip = Signal() # Pulse to rotate # Phase detector readout (on sample clock domain) # input for number of sample clock cycles to integrate self.pd_int_period = Signal(32, reset=2**23) # outputs integrated Phase detector values (int32) self.pd_int_phases = [Signal((32, True)) for i in range(D)] # input to enable auto increment / decrement IDELAY based on PD value self.id_auto_control = Signal() # Idelay control inputs (on sample clock domain) self.id_mux = Signal(max=D + 1) # select a LVDS lane self.id_inc = Signal(1) self.id_dec = Signal(1) # parallel data out, S-bit serdes on D-lanes (on sample clock domain) self.data_outs = [Signal(S) for i in range(D)] # Async Reset for clock generation and `sample` clock domain self.reset = Signal(reset=1) ### # Common internal signals which must be driven by child self.clock_domains.sample = ClockDomain( "sample") # received ADC sample clock self.ioclk_p = Signal() self.ioclk_n = Signal() self.serdesstrobe = Signal() # ----------------------------- # IDELAY calibration # ----------------------------- self.idelay_rst = Signal() self.idelay_cal_m = Signal() self.idelay_cal_s = Signal() # High when IDELAY initialization complete self.initial_tl_done = Signal() bitslip_initial = Signal() self.sync.sample += [ self.idelay_cal_m.eq(0), self.idelay_cal_s.eq(0), self.idelay_rst.eq(0), bitslip_initial.eq(0) ] # Initially calibrate and reset all IDELAY2s tl = [ (20, [self.idelay_cal_m.eq(1), self.idelay_cal_s.eq(1)]), (40, [self.idelay_rst.eq(1)]), (60, [self.initial_tl_done.eq(1)]), # Add initial bitslips starting from clk 100. Have I gone too far? *zip([100 + i * 10 for i in range(BITSLIPS)], [[bitslip_initial.eq(1)]] * BITSLIPS) ] # print(tl) self.sync.sample += timeline(~self.initial_tl_done, tl) # Periodically re-calibrate all slave IDELAY2s self.sync.sample += timeline( self.initial_tl_done, [(2**26, [self.idelay_cal_s.eq(1)]) # every 0.54 s at 125 MHz ]) # Accumulator regs for phase detector pd_int_accus = [Signal.like(s) for s in self.pd_int_phases] pd_int_cnt = Signal(32) self.sync.sample += [ If( pd_int_cnt >= self.pd_int_period, pd_int_cnt.eq(0), ).Elif( self. initial_tl_done, # only start counting when idelays are calibrated pd_int_cnt.eq(pd_int_cnt + 1)) ] # ----------------------------- # Default block parameters # ----------------------------- self.idelay_default = { "p_SIM_TAPDELAY_VALUE": 49, "p_IDELAY_VALUE": 0, # A faire: make CSR "p_IDELAY2_VALUE": 0, "p_ODELAY_VALUE": 0, "p_IDELAY_MODE": "NORMAL", "p_COUNTER_WRAPAROUND": "WRAPAROUND", "p_DELAY_SRC": "IDATAIN", "i_T": 1, "i_ODATAIN": 0, "i_IOCLK0": self.ioclk_p, "i_IOCLK1": self.ioclk_n, "i_CLK": ClockSignal("sample"), "i_RST": self.idelay_rst } self.idelay_default.update(idelay_overrides) self.iserdes_default = { "p_DATA_WIDTH": S, "p_BITSLIP_ENABLE": "TRUE", "p_INTERFACE_TYPE": "RETIMED", "i_CE0": 1, "i_CLK0": self.ioclk_p, "i_CLK1": self.ioclk_n, "i_IOCE": self.serdesstrobe, "i_RST": ~self.initial_tl_done, "i_CLKDIV": ClockSignal("sample"), "i_BITSLIP": self.bitslip | bitslip_initial } self.iserdes_default.update(iserdes_overrides) for i in range(D): lvds_data = Signal() lvds_data_m = Signal() lvds_data_s = Signal() id_CE = Signal() id_INC = Signal() # ------------------------------------- # Idelay control (auto / manual) # ------------------------------------- self.sync.sample += [ # Mux the IDELAY control inputs If( self.id_auto_control, id_CE. eq((pd_int_cnt == 1) & # Adjust IDELAYS at end of each accumulator cycle (self.pd_int_phases[i] != 0) # Adjust IDELAYs when consistently early / late # during _all_ accumulator cycles # ((self.pd_int_phases[i] >= self.pd_int_period) | # (self.pd_int_phases[i] <= -self.pd_int_period)) ), id_INC.eq(self.pd_int_phases[i] < 0)).Else( id_CE.eq((self.id_mux == i) & (self.id_inc ^ self.id_dec)), id_INC.eq(self.id_inc)) ] self.specials += DifferentialInput(self.lvds_data_p[i], self.lvds_data_n[i], lvds_data) self.specials += Instance("IODELAY2", p_SERDES_MODE="MASTER", p_IDELAY_TYPE="DIFF_PHASE_DETECTOR", i_IDATAIN=lvds_data, i_CAL=self.idelay_cal_m, i_CE=id_CE, i_INC=id_INC, o_DATAOUT=lvds_data_m, **self.idelay_default) self.specials += Instance("IODELAY2", p_SERDES_MODE="SLAVE", p_IDELAY_TYPE="DIFF_PHASE_DETECTOR", i_IDATAIN=lvds_data, i_CAL=self.idelay_cal_s, i_CE=id_CE, i_INC=id_INC, o_DATAOUT=lvds_data_s, **self.idelay_default) cascade_up = Signal() cascade_down = Signal() tempData = Signal(8) pdValid = Signal() pdInc = Signal() pdAcc = pd_int_accus[i] self.specials += Instance( "ISERDES2", p_SERDES_MODE="MASTER", i_D=lvds_data_m, i_SHIFTIN=cascade_up, o_Q4=tempData[7], o_Q3=tempData[6], o_Q2=tempData[5], o_Q1=tempData[4], o_SHIFTOUT=cascade_down, # The phase detector outputs o_VALID=pdValid, o_INCDEC=pdInc, **self.iserdes_default) # Accumulate increment / decrement pulses self.sync.sample += [ If( pd_int_cnt >= self.pd_int_period, # Latch accumulator value into output registers self.pd_int_phases[i].eq(pdAcc), # Reset accumulators pdAcc.eq(0)).Elif( pdValid & self.initial_tl_done, # Accumulate If(pdInc, pdAcc.eq(pdAcc - 1)).Else(pdAcc.eq(pdAcc + 1))) ] self.specials += Instance("ISERDES2", p_SERDES_MODE="SLAVE", i_D=lvds_data_s, i_SHIFTIN=cascade_down, o_Q4=tempData[3], o_Q3=tempData[2], o_Q2=tempData[1], o_Q1=tempData[0], o_SHIFTOUT=cascade_up, **self.iserdes_default) if MIRROR_BITS: self.comb += self.data_outs[i].eq(tempData[::-1]) else: self.comb += self.data_outs[i].eq(tempData)
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), ]