dvisampler/datacapture: fix tap counter reg
[litex.git] / milkymist / dvisampler / datacapture.py
1 from migen.fhdl.structure import *
2 from migen.fhdl.module import Module
3 from migen.fhdl.specials import Instance
4 from migen.genlib.cdc import PulseSynchronizer
5 from migen.bank.description import *
6
7 class DataCapture(Module, AutoReg):
8 def __init__(self, ntbits, debug=False):
9 self.pad = Signal()
10 self.serdesstrobe = Signal()
11 self.delay_rst = Signal() # system clock domain
12 self.d0 = Signal() # pix5x clock domain
13 self.d1 = Signal() # pix5x clock domain
14
15 if debug:
16 self._r_delay_rst = RegisterRaw()
17 self._r_current_tap = RegisterField(8, READ_ONLY, WRITE_ONLY)
18
19 ###
20
21 # IO
22 pad_delayed = Signal()
23 delay_inc = Signal()
24 delay_ce = Signal()
25 delay_rst = Signal()
26 delay_init = Signal()
27 self.specials += Instance("IODELAY2",
28 Instance.Parameter("DELAY_SRC", "IDATAIN"),
29 Instance.Parameter("IDELAY_TYPE", "VARIABLE_FROM_ZERO"),
30 Instance.Parameter("COUNTER_WRAPAROUND", "STAY_AT_LIMIT"),
31 Instance.Input("IDATAIN", self.pad),
32 Instance.Output("DATAOUT", pad_delayed),
33 Instance.Input("INC", delay_inc | delay_init),
34 Instance.Input("CE", delay_ce | delay_init),
35 Instance.Input("RST", delay_rst),
36 Instance.ClockPort("CLK"),
37 Instance.Input("CAL", 0),
38 Instance.Input("T", 1)
39 )
40 # initialize delay to 127 taps
41 delay_init_count = Signal(7, reset=127)
42 self.comb += delay_init.eq(delay_init_count != 0)
43 self.sync += If(delay_rst,
44 delay_init_count.eq(127)
45 ).Elif(delay_init,
46 delay_init_count.eq(delay_init_count - 1)
47 )
48
49 d0p = Signal()
50 d1p = Signal()
51 self.specials += Instance("ISERDES2",
52 Instance.Parameter("BITSLIP_ENABLE", "FALSE"),
53 Instance.Parameter("DATA_RATE", "SDR"),
54 Instance.Parameter("DATA_WIDTH", 4),
55 Instance.Parameter("INTERFACE_TYPE", "RETIMED"),
56 Instance.Parameter("SERDES_MODE", "NONE"),
57 Instance.Output("Q4", self.d0),
58 Instance.Output("Q3", d0p),
59 Instance.Output("Q2", self.d1),
60 Instance.Output("Q1", d1p),
61 Instance.Input("BITSLIP", 0),
62 Instance.Input("CE0", 1),
63 Instance.ClockPort("CLK0", "pix20x"),
64 Instance.ClockPort("CLKDIV", "pix5x"),
65 Instance.Input("D", pad_delayed),
66 Instance.Input("IOCE", self.serdesstrobe),
67 Instance.Input("RST", 0)
68 )
69
70 # Transition counter
71 transitions = Signal(ntbits)
72 lateness = Signal((ntbits + 1, True))
73 pulse_inc = Signal()
74 pulse_dec = Signal()
75 self.sync.pix5x += [
76 pulse_inc.eq(0),
77 pulse_dec.eq(0),
78 If(transitions == 2**ntbits - 1,
79 If(lateness[ntbits],
80 pulse_inc.eq(1)
81 ).Else(
82 pulse_dec.eq(1)
83 ),
84 lateness.eq(0),
85 transitions.eq(0)
86 ).Elif(self.d0 != self.d1,
87 If(self.d0,
88 # 1 -----> 0
89 # d0p
90 If(d0p,
91 lateness.eq(lateness - 1)
92 ).Else(
93 lateness.eq(lateness + 1)
94 )
95 ).Else(
96 # 0 -----> 1
97 # d0p
98 If(d0p,
99 lateness.eq(lateness + 1)
100 ).Else(
101 lateness.eq(lateness - 1)
102 )
103 ),
104 transitions.eq(transitions + 1)
105 )
106 ]
107
108 # Send delay update commands to system (IDELAY) clock domain
109 self.submodules.xf_inc = PulseSynchronizer("pix5x", "sys")
110 self.submodules.xf_dec = PulseSynchronizer("pix5x", "sys")
111 self.comb += [
112 self.xf_inc.i.eq(pulse_inc),
113 delay_inc.eq(self.xf_inc.o),
114 self.xf_dec.i.eq(pulse_dec),
115 delay_ce.eq(self.xf_inc.o | self.xf_dec.o)
116 ]
117
118 # Debug
119 if debug:
120 self.comb += delay_rst.eq(self.delay_rst | self._r_delay_rst.re)
121 current_tap = self._r_current_tap.field.w
122 self.sync += If(delay_rst,
123 current_tap.eq(0)
124 ).Elif(delay_ce,
125 If(delay_inc,
126 If(current_tap != 0xff,
127 current_tap.eq(current_tap + 1)
128 )
129 ).Else(
130 If(current_tap != 0,
131 current_tap.eq(current_tap - 1)
132 )
133 )
134 )
135 else:
136 self.comb += delay_rst.eq(self.delay_rst)