513 lines
16 KiB
Python
513 lines
16 KiB
Python
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"),
|
|
)
|