litex/milkymist/dvisampler/datacapture.py

137 lines
3.6 KiB
Python
Raw Normal View History

from migen.fhdl.structure import *
from migen.fhdl.module import Module
from migen.fhdl.specials import Instance
from migen.genlib.cdc import PulseSynchronizer
from migen.bank.description import *
class DataCapture(Module, AutoReg):
def __init__(self, ntbits, debug=False):
self.pad = Signal()
self.serdesstrobe = Signal()
self.delay_rst = Signal() # system clock domain
self.d0 = Signal() # pix5x clock domain
self.d1 = Signal() # pix5x clock domain
if debug:
self._r_delay_rst = RegisterRaw()
self._r_current_tap = RegisterField(8, READ_ONLY, WRITE_ONLY)
###
# IO
pad_delayed = Signal()
delay_inc = Signal()
delay_ce = Signal()
delay_rst = Signal()
delay_init = Signal()
2013-03-17 10:41:50 -04:00
self.specials += Instance("IODELAY2",
Instance.Parameter("DELAY_SRC", "IDATAIN"),
Instance.Parameter("IDELAY_TYPE", "VARIABLE_FROM_ZERO"),
2013-03-17 10:41:50 -04:00
Instance.Parameter("COUNTER_WRAPAROUND", "STAY_AT_LIMIT"),
Instance.Input("IDATAIN", self.pad),
Instance.Output("DATAOUT", pad_delayed),
Instance.Input("INC", delay_inc | delay_init),
Instance.Input("CE", delay_ce | delay_init),
Instance.Input("RST", delay_rst),
Instance.ClockPort("CLK"),
Instance.Input("CAL", 0),
Instance.Input("T", 1)
)
# initialize delay to 127 taps
delay_init_count = Signal(7, reset=127)
self.comb += delay_init.eq(delay_init_count != 0)
self.sync += If(delay_rst,
delay_init_count.eq(127)
).Elif(delay_init,
delay_init_count.eq(delay_init_count - 1)
)
d0p = Signal()
d1p = Signal()
self.specials += Instance("ISERDES2",
Instance.Parameter("BITSLIP_ENABLE", "FALSE"),
Instance.Parameter("DATA_RATE", "SDR"),
Instance.Parameter("DATA_WIDTH", 4),
Instance.Parameter("INTERFACE_TYPE", "RETIMED"),
Instance.Parameter("SERDES_MODE", "NONE"),
Instance.Output("Q4", self.d0),
Instance.Output("Q3", d0p),
Instance.Output("Q2", self.d1),
Instance.Output("Q1", d1p),
Instance.Input("BITSLIP", 0),
Instance.Input("CE0", 1),
Instance.ClockPort("CLK0", "pix20x"),
Instance.ClockPort("CLKDIV", "pix5x"),
Instance.Input("D", pad_delayed),
Instance.Input("IOCE", self.serdesstrobe),
Instance.Input("RST", 0)
)
# Transition counter
transitions = Signal(ntbits)
lateness = Signal((ntbits + 1, True))
pulse_inc = Signal()
pulse_dec = Signal()
self.sync.pix5x += [
pulse_inc.eq(0),
pulse_dec.eq(0),
If(transitions == 2**ntbits - 1,
If(lateness[ntbits],
pulse_inc.eq(1)
).Else(
pulse_dec.eq(1)
),
lateness.eq(0),
transitions.eq(0)
).Elif(self.d0 != self.d1,
If(self.d0,
# 1 -----> 0
# d0p
If(d0p,
lateness.eq(lateness - 1)
).Else(
lateness.eq(lateness + 1)
)
).Else(
# 0 -----> 1
# d0p
If(d0p,
lateness.eq(lateness + 1)
).Else(
lateness.eq(lateness - 1)
)
),
transitions.eq(transitions + 1)
)
]
# Send delay update commands to system (IDELAY) clock domain
self.submodules.xf_inc = PulseSynchronizer("pix5x", "sys")
self.submodules.xf_dec = PulseSynchronizer("pix5x", "sys")
self.comb += [
self.xf_inc.i.eq(pulse_inc),
delay_inc.eq(self.xf_inc.o),
self.xf_dec.i.eq(pulse_dec),
delay_ce.eq(self.xf_inc.o | self.xf_dec.o)
]
# Debug
if debug:
self.comb += delay_rst.eq(self.delay_rst | self._r_delay_rst.re)
current_tap = self._r_current_tap.field.w
self.sync += If(delay_rst,
current_tap.eq(0)
).Elif(delay_ce,
If(delay_inc,
If(current_tap != 0xff,
current_tap.eq(current_tap + 1)
)
).Else(
If(current_tap != 0,
current_tap.eq(current_tap - 1)
)
)
)
else:
self.comb += delay_rst.eq(self.delay_rst)