from migen import * from migen.genlib.misc import WaitTimer from util import PriorityEncoderMSB class SingleLineTX(Module): def __init__(self): self.txdata = Signal(5) self.ser_out = Signal() self.t_out = Signal() # TX SERDES self.specials += Instance("OSERDESE2", p_DATA_RATE_OQ="SDR", p_DATA_RATE_TQ="BUF", p_DATA_WIDTH=5, p_TRISTATE_WIDTH=1, p_INIT_OQ=0b00000, o_OQ=self.ser_out, o_TQ=self.t_out, i_RST=ResetSignal(), i_CLK=ClockSignal("sys5x"), i_CLKDIV=ClockSignal(), i_D1=self.txdata[0], i_D2=self.txdata[1], i_D3=self.txdata[2], i_D4=self.txdata[3], i_D5=self.txdata[4], i_TCE=1, i_OCE=1, # TODO: Hardcode t_in? Output disable is always unnecessary? i_T1=0) class SingleLineRX(Module): def __init__(self): self.rxdata = Signal(10) self.ser_in_no_dly = Signal() self.ce = Signal() self.cnt_out = Signal(5) self.opt_delay = Signal(5) self.master_bitslip = Signal() self.slave_bitslip = Signal() ser_in = Signal() shifts = Signal(2) self.specials += [ # Master deserializer Instance("ISERDESE2", p_DATA_RATE="DDR", p_DATA_WIDTH=10, p_INTERFACE_TYPE="NETWORKING", p_NUM_CE=1, p_SERDES_MODE="MASTER", p_IOBDELAY="IFD", o_Q1=self.rxdata[9], o_Q2=self.rxdata[8], o_Q3=self.rxdata[7], o_Q4=self.rxdata[6], o_Q5=self.rxdata[5], o_Q6=self.rxdata[4], o_Q7=self.rxdata[3], o_Q8=self.rxdata[2], o_SHIFTOUT1=shifts[0], o_SHIFTOUT2=shifts[1], i_DDLY=ser_in, i_BITSLIP=self.master_bitslip, i_CLK=ClockSignal("rx_sys5x"), i_CLKB=~ClockSignal("rx_sys5x"), i_CE1=1, i_RST=ResetSignal("rx_sys"), i_CLKDIV=ClockSignal("rx_sys")), # Slave deserializer Instance("ISERDESE2", p_DATA_RATE="DDR", p_DATA_WIDTH=10, p_INTERFACE_TYPE="NETWORKING", p_NUM_CE=1, p_SERDES_MODE="SLAVE", p_IOBDELAY="IFD", o_Q3=self.rxdata[1], o_Q4=self.rxdata[0], # i_DDLY=ser_in, i_BITSLIP=self.slave_bitslip, i_CLK=ClockSignal("rx_sys5x"), i_CLKB=~ClockSignal("rx_sys5x"), i_CE1=1, i_RST=ResetSignal("rx_sys"), i_CLKDIV=ClockSignal("rx_sys"), i_SHIFTIN1=shifts[0], i_SHIFTIN2=shifts[1]), # Tunable delay Instance("IDELAYE2", p_DELAY_SRC="IDATAIN", p_SIGNAL_PATTERN="DATA", p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", # REFCLK refers to the clock source of IDELAYCTRL p_REFCLK_FREQUENCY=200.0, p_PIPE_SEL="FALSE", p_IDELAY_TYPE="VARIABLE", p_IDELAY_VALUE=0, i_C=ClockSignal("rx_sys"), # i_LD=self._dly_sel.storage[i//8] & self._rdly_dq_rst.re, # i_CE=self._dly_sel.storage[i//8] & self._rdly_dq_inc.re, i_LD=0, i_CE=self.ce, # TODO: Port output i_LDPIPEEN=0, i_INC=1, # Always increment # Allow aligner to check delay tap value o_CNTVALUEOUT=self.cnt_out, i_IDATAIN=self.ser_in_no_dly, o_DATAOUT=ser_in ), # IDELAYCTRL is with the clocking ] class BitSlipReader(Module): def __init__(self): # IN self.loopback_rxdata = Signal(10) self.start = Signal() # Wait for stabilization after bitslip self.submodules.stab_timer = WaitTimer(511) # OUT self.done = Signal() self.bitslip = Signal() self.data_result = Array(Signal(10) for _ in range(5)) self.slip_count = Signal(3) fsm = FSM(reset_state="WAIT_START") self.submodules += fsm fsm.act("WAIT_START", If(self.start, NextState("WAIT_TIMER"), ).Else( NextState("WAIT_START"), ) ) fsm.act("WAIT_TIMER", self.stab_timer.wait.eq(1), If(self.stab_timer.done, NextState("SAMPLE"), ) ) fsm.act("SAMPLE", # Wait is reset now # Explicit assignment is unnecessary, as combinatorial statement # falls back to he default value when not driven # Keep result alive until reset NextValue(self.data_result[self.slip_count], self.loopback_rxdata), NextValue(self.slip_count, self.slip_count + 1), NextState("HIGH_BITSLIP_FIRST"), ) # Pulsing BITSLIP alternate between 1 right shift and 3 left shifts # We are trying to figure out which 2-bits are the slave copying from # Hence, we only want shifts by 2. Pulsing twice does exactly that. fsm.act("HIGH_BITSLIP_FIRST", self.bitslip.eq(1), NextState("LOW_BITSLIP"), ) fsm.act("LOW_BITSLIP", # bitslip signal is auto-reset NextState("HIGH_BITSLIP_SECOND"), ) fsm.act("HIGH_BITSLIP_SECOND", self.bitslip.eq(1), If(self.slip_count == 5, NextState("TERMINATE"), ).Else( NextState("WAIT_TIMER"), ) ) fsm.act("TERMINATE", self.done.eq(1), NextState("TERMINATE"), ) class SlaveAligner(Module): def __init__(self): # IN self.loopback_rxdata = Signal(10) self.start = Signal() # Wait for stabilization after bitslip self.submodules.stab_timer = WaitTimer(511) # OUT self.done = Signal() self.master_bitslip = Signal() self.slave_bitslip = Signal() # self.data_result = Array(Signal(10) for _ in range(5)) self.slip_count = Signal(3) check_odd = Signal() check_even = Signal() fsm = FSM(reset_state="WAIT_START") self.submodules += fsm fsm.act("WAIT_START", If(self.start, NextState("WAIT_TIMER"), ).Else( NextState("WAIT_START"), ) ) fsm.act("WAIT_TIMER", self.stab_timer.wait.eq(1), If(self.stab_timer.done, NextState("SAMPLE"), ) ) fsm.act("SAMPLE", # Wait is reset now # Explicit assignment is unnecessary, as combinatorial statement # falls back to he default value when not driven # Detect the last 2 bits # If signal is received, detune the master bitslip if necessary If(self.loopback_rxdata[0] | self.loopback_rxdata[1], NextValue(check_odd, self.loopback_rxdata[1]), NextValue(check_even, self.loopback_rxdata[0]), NextState("CHECK_MASTER_BITSLIP"), ).Else( NextValue(self.slip_count, self.slip_count + 1), NextState("HIGH_BITSLIP_FIRST"), ) ) # Pulsing BITSLIP alternate between 1 right shift and 3 left shifts # We are trying to figure out which 2-bits are the slave copying from # Hence, we only want shifts by 2. Pulsing twice does exactly that. fsm.act("HIGH_BITSLIP_FIRST", self.master_bitslip.eq(1), self.slave_bitslip.eq(1), NextState("LOW_BITSLIP"), ) fsm.act("LOW_BITSLIP", # bitslip signal is auto-reset NextState("HIGH_BITSLIP_SECOND"), ) fsm.act("HIGH_BITSLIP_SECOND", self.master_bitslip.eq(1), self.slave_bitslip.eq(1), If(self.slip_count == 5, NextState("TERMINATE"), ).Else( NextState("WAIT_TIMER"), ) ) odd_master_rxdata = self.loopback_rxdata[3::2] even_master_rxdata = self.loopback_rxdata[2::2] # Alternatively, we align the master with the slave fsm.act("CHECK_MASTER_BITSLIP", # At any point if the odd and/or even bits from the master reads 0 # It implies the detuning is completed NextState("TERMINATE"), If(check_odd & (odd_master_rxdata != 0), NextState("MASTER_HIGH_BITSLIP_FIRST"), ), If(check_even & (even_master_rxdata != 0), NextState("MASTER_HIGH_BITSLIP_FIRST"), ), ) fsm.act("MASTER_HIGH_BITSLIP_FIRST", self.master_bitslip.eq(1), NextState("MASTER_LOW_BITSLIP"), ) fsm.act("MASTER_LOW_BITSLIP", # bitslip signal is auto-reset NextState("MASTER_HIGH_BITSLIP_SECOND"), ) fsm.act("MASTER_HIGH_BITSLIP_SECOND", self.master_bitslip.eq(1), NextState("MASTER_WAIT_TIMER"), ) fsm.act("MASTER_WAIT_TIMER", self.stab_timer.wait.eq(1), If(self.stab_timer.done, NextState("CHECK_MASTER_BITSLIP"), ) ) fsm.act("TERMINATE", self.done.eq(1), NextState("TERMINATE"), ) class PhaseReader(Module): def __init__(self): # Drive IDELAYE2 CE pin to increment delay # The signal should only last for 1 cycle self.inc_en = Signal() self.loopback_rxdata = Signal(10) self.delay_tap = Signal(5) # Pull up to start the phase reader self.start = Signal() self.data_result = Array(Signal(10) for _ in range(32)) self.done = Signal() # Wait for stabilization after increment self.submodules.stab_timer = WaitTimer(511) fsm = FSM(reset_state="WAIT_START") self.submodules += fsm fsm.act("WAIT_START", If(self.start, NextState("WAIT_TIMER"), ).Else( NextState("WAIT_START"), ) ) fsm.act("WAIT_TIMER", self.stab_timer.wait.eq(1), If(self.stab_timer.done, NextState("SAMPLE"), ) ) fsm.act("SAMPLE", # Wait is reset now # Explicit assignment is unnecessary, as combinatorial statement # falls back to he default value when not driven # Keep result alive until reset NextValue(self.data_result[self.delay_tap], self.loopback_rxdata), NextState("HIGH_CE"), ) fsm.act("HIGH_CE", self.inc_en.eq(1), NextState("LOW_CE"), ) fsm.act("LOW_CE", # TAP OUT is available 1 cycle after the pulse # Explicit signal reset is unnecessary, as signal assigned by # combinatorial logic in FSM is after leaving the setting block NextState("READ_TAP"), ) fsm.act("READ_TAP", If(self.delay_tap != 0, NextState("WAIT_TIMER"), ).Else( NextState("PROBE_FIN"), ) ) fsm.act("PROBE_FIN", self.done.eq(1), NextState("PROBE_FIN"), ) class DelayOptimizer(Module): def __init__(self): # IN # Signals from the channel self.loopback_rxdata = Signal(10) self.delay_tap = Signal(5) # IN # Signal to start the calculation self.start = Signal() # OUT # Signal for controlling the channel delay tap self.inc_en = Signal() # OUT # The optimal delay self.opt_delay_tap = Signal(5) # OUT # Optimal delay is calculated self.done = Signal() # Priority encoder for finding the pulse location self.submodules.pulse_encoder = PriorityEncoderMSB(10) # Wait for stabilization after increment self.submodules.stab_timer = WaitTimer(511) # Intermediate signals self.expected_pulse = Signal(max=9) self.min_delay = Signal(5) self.max_offset = Signal(5) # Translate rxdata into array to allow indexing self.rxdata_array = Array(Signal() for _ in range(10)) self.comb += [ self.rxdata_array[i].eq(self.loopback_rxdata[i]) for i in range(10) ] fsm = FSM(reset_state="WAIT_START") self.submodules += fsm fsm.act("WAIT_START", If(self.start, NextState("WAIT_ZERO"), ).Else( NextState("WAIT_START"), ) ) fsm.act("WAIT_ZERO", self.stab_timer.wait.eq(1), If(self.stab_timer.done, NextState("SAMPLE_ZERO"), ) ) fsm.act("SAMPLE_ZERO", # Oversampling should guarantee the detection # However, priority encoder itself does not wraparound # So, we need to avoid passing wrapped around pulse signal into # the priority encoder. If(self.loopback_rxdata[0] & self.loopback_rxdata[-1], NextValue(self.expected_pulse, 1), ).Else( self.pulse_encoder.i.eq(self.loopback_rxdata), If(self.pulse_encoder.o == 9, NextValue(self.expected_pulse, 0), ).Else( NextValue(self.expected_pulse, self.pulse_encoder.o + 1), ) ), # Goto the next delay tap and wait for the pulse. NextState("INC_PULSE_DELAY_IN"), ) fsm.act("WAIT_PULSE_IN", self.stab_timer.wait.eq(1), If(self.stab_timer.done, NextState("SAMPLE_PULSE_IN"), ) ) fsm.act("SAMPLE_PULSE_IN", If(self.rxdata_array[self.expected_pulse], NextValue(self.min_delay, self.delay_tap), NextState("INC_PULSE_DELAY_OUT"), ).Else( NextState("INC_PULSE_DELAY_IN"), ) ) fsm.act("INC_PULSE_DELAY_IN", # This signal is automatically deasserted after this state self.inc_en.eq(1), NextState("WAIT_PULSE_IN"), ) fsm.act("WAIT_PULSE_OUT", self.stab_timer.wait.eq(1), If(self.stab_timer.done, NextState("SAMPLE_PULSE_OUT"), ) ) fsm.act("SAMPLE_PULSE_OUT", If(~self.rxdata_array[self.expected_pulse], NextValue(self.opt_delay_tap, self.min_delay + (self.max_offset >> 1)), NextState("TERMINATE"), ).Else( NextValue(self.max_offset, self.max_offset + 1), NextState("INC_PULSE_DELAY_OUT"), ) ) fsm.act("INC_PULSE_DELAY_OUT", # This signal is automatically deasserted after this state self.inc_en.eq(1), NextState("WAIT_PULSE_OUT"), ) fsm.act("TERMINATE", self.done.eq(1), NextState("TERMINATE"), )