Skip to content

Commit 0a14c37

Browse files
author
Sebastien Bourdeauducq
committedMar 20, 2013
dvisampler: software controlled phase detector
1 parent 28cb970 commit 0a14c37

File tree

4 files changed

+86
-59
lines changed

4 files changed

+86
-59
lines changed
 

‎build.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ def main():
4646
4747
NET "{dviclk0}" TNM_NET = "GRPdviclk0";
4848
NET "{dviclk0}" CLOCK_DEDICATED_ROUTE = FALSE;
49-
TIMESPEC "TSdviclk0" = PERIOD "GRPdviclk0" 22 ns HIGH 50%;
49+
TIMESPEC "TSdviclk0" = PERIOD "GRPdviclk0" 26.7 ns HIGH 50%;
5050
NET "{dviclk1}" TNM_NET = "GRPdviclk1";
5151
NET "{dviclk1}" CLOCK_DEDICATED_ROUTE = FALSE;
52-
TIMESPEC "TSdviclk1" = PERIOD "GRPdviclk1" 22 ns HIGH 50%;
52+
TIMESPEC "TSdviclk1" = PERIOD "GRPdviclk1" 26.7 ns HIGH 50%;
5353
""",
5454
clk50=soc.crg.clk50_pad,
5555
phy_rx_clk=soc.crg.eth_rx_clk_pad,

‎milkymist/dvisampler/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from milkymist.dvisampler.datacapture import DataCapture
88

99
class DVISampler(Module, AutoReg):
10-
def __init__(self, inversions="", debug_data_capture=True):
10+
def __init__(self, inversions=""):
1111
self.submodules.edid = EDID()
1212
self.sda = self.edid.sda
1313
self.scl = self.edid.scl
@@ -17,7 +17,7 @@ def __init__(self, inversions="", debug_data_capture=True):
1717

1818
for datan in "012":
1919
name = "data" + str(datan)
20-
cap = DataCapture(8, debug_data_capture)
20+
cap = DataCapture(8)
2121
setattr(self.submodules, name + "_cap", cap)
2222
if datan in inversions:
2323
name += "_n"

‎milkymist/dvisampler/clocking.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ def __init__(self):
1515
self.serdesstrobe = Signal()
1616
self.clock_domains._cd_pix = ClockDomain()
1717
self.clock_domains._cd_pix5x = ClockDomain()
18+
self.clock_domains._cd_pix10x = ClockDomain()
1819
self.clock_domains._cd_pix20x = ClockDomain()
1920

2021
###
@@ -24,18 +25,22 @@ def __init__(self):
2425
pll_clk0 = Signal()
2526
pll_clk1 = Signal()
2627
pll_clk2 = Signal()
28+
pll_clk3 = Signal()
2729
self.specials += Instance("PLL_BASE",
28-
Instance.Parameter("CLKIN_PERIOD", 22.0),
30+
Instance.Parameter("CLKIN_PERIOD", 26.7),
2931
Instance.Parameter("CLKFBOUT_MULT", 20),
3032
Instance.Parameter("CLKOUT0_DIVIDE", 1), # pix20x
3133
Instance.Parameter("CLKOUT1_DIVIDE", 4), # pix5x
3234
Instance.Parameter("CLKOUT2_DIVIDE", 20), # pix
35+
Instance.Parameter("CLKOUT3_DIVIDE", 2), # pix10x
3336
Instance.Parameter("COMPENSATION", "INTERNAL"),
3437

3538
Instance.Output("CLKFBOUT", clkfbout),
39+
# WARNING: Do not touch the order of those clocks, or PAR fails.
3640
Instance.Output("CLKOUT0", pll_clk0),
3741
Instance.Output("CLKOUT1", pll_clk1),
3842
Instance.Output("CLKOUT2", pll_clk2),
43+
Instance.Output("CLKOUT3", pll_clk3),
3944
Instance.Output("LOCKED", pll_locked),
4045
Instance.Input("CLKFBIN", clkfbout),
4146
Instance.Input("CLKIN", self.clkin),
@@ -56,6 +61,8 @@ def __init__(self):
5661
Instance.Input("I", pll_clk1), Instance.Output("O", self._cd_pix5x.clk))
5762
self.specials += Instance("BUFG",
5863
Instance.Input("I", pll_clk2), Instance.Output("O", self._cd_pix.clk))
64+
self.specials += Instance("BUFG",
65+
Instance.Input("I", pll_clk3), Instance.Output("O", self._cd_pix10x.clk))
5966
self.specials += MultiReg(locked_async, self.locked, "sys")
6067
self.comb += self._r_locked.field.w.eq(self.locked)
6168

‎milkymist/dvisampler/datacapture.py

+74-54
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,40 @@
55
from migen.bank.description import *
66

77
class DataCapture(Module, AutoReg):
8-
def __init__(self, ntbits, debug=False):
8+
def __init__(self, ntbits):
99
self.pad = Signal()
1010
self.serdesstrobe = Signal()
1111
self.d0 = Signal() # pix5x clock domain
1212
self.d1 = Signal() # pix5x clock domain
1313

14-
if debug:
15-
self._r_current_tap = RegisterField(8, READ_ONLY, WRITE_ONLY)
14+
self._r_dly_ctl = RegisterRaw(4)
15+
self._r_dly_busy = RegisterField(1, READ_ONLY, WRITE_ONLY)
16+
self._r_phase = RegisterField(2, READ_ONLY, WRITE_ONLY)
17+
self._r_phase_reset = RegisterRaw()
1618

1719
###
1820

1921
# IO
2022
pad_delayed = Signal()
2123
delay_inc = Signal()
2224
delay_ce = Signal()
25+
delay_cal = Signal()
26+
delay_rst = Signal()
27+
delay_busy = Signal()
2328
self.specials += Instance("IODELAY2",
2429
Instance.Parameter("DELAY_SRC", "IDATAIN"),
25-
Instance.Parameter("IDELAY_TYPE", "VARIABLE_FROM_ZERO"),
30+
Instance.Parameter("IDELAY_TYPE", "VARIABLE_FROM_HALF_MAX"),
2631
Instance.Parameter("COUNTER_WRAPAROUND", "STAY_AT_LIMIT"),
2732
Instance.Parameter("DATA_RATE", "SDR"),
2833
Instance.Input("IDATAIN", self.pad),
2934
Instance.Output("DATAOUT", pad_delayed),
35+
Instance.Input("CLK", ClockSignal("pix5x")),
36+
Instance.Input("IOCLK0", ClockSignal("pix10x")),
3037
Instance.Input("INC", delay_inc),
3138
Instance.Input("CE", delay_ce),
32-
Instance.Input("RST", ResetSignal("pix5x")),
33-
Instance.Input("CLK", ClockSignal("pix5x")),
34-
Instance.Input("IOCLK0", ClockSignal("pix20x")),
35-
Instance.Input("CAL", 0),
39+
Instance.Input("CAL", delay_cal),
40+
Instance.Input("RST", delay_rst),
41+
Instance.Output("BUSY", delay_busy),
3642
Instance.Input("T", 1)
3743
)
3844

@@ -57,23 +63,19 @@ def __init__(self, ntbits, debug=False):
5763
Instance.Input("RST", 0)
5864
)
5965

60-
# Transition counter
61-
transitions = Signal(ntbits)
62-
lateness = Signal((ntbits + 1, True))
63-
pulse_inc = Signal()
64-
pulse_dec = Signal()
66+
# Phase detector
67+
lateness = Signal(ntbits, reset=2**(ntbits - 1))
68+
too_late = Signal()
69+
too_early = Signal()
70+
reset_lateness = Signal()
71+
self.comb += [
72+
too_late.eq(lateness == (2**ntbits - 1)),
73+
too_early.eq(lateness == 0)
74+
]
6575
self.sync.pix5x += [
66-
pulse_inc.eq(0),
67-
pulse_dec.eq(0),
68-
If(transitions == 2**ntbits - 1,
69-
If(lateness[ntbits],
70-
pulse_inc.eq(1)
71-
).Else(
72-
pulse_dec.eq(1)
73-
),
74-
lateness.eq(0),
75-
transitions.eq(0)
76-
).Elif(self.d0 != self.d1,
76+
If(reset_lateness,
77+
lateness.eq(2**(ntbits - 1))
78+
).Elif(~delay_busy & ~too_late & ~too_early & (self.d0 != self.d1),
7779
If(self.d0,
7880
# 1 -----> 0
7981
# d0p
@@ -90,39 +92,57 @@ def __init__(self, ntbits, debug=False):
9092
).Else(
9193
lateness.eq(lateness - 1)
9294
)
93-
),
94-
transitions.eq(transitions + 1)
95+
)
96+
)
97+
]
98+
99+
# Delay control
100+
self.submodules.delay_done = PulseSynchronizer("pix5x", "sys")
101+
delay_pending = Signal()
102+
self.sync.pix5x += [
103+
self.delay_done.i.eq(0),
104+
If(~delay_pending,
105+
If(delay_cal | delay_ce, delay_pending.eq(1))
106+
).Else(
107+
If(~delay_busy,
108+
self.delay_done.i.eq(1),
109+
delay_pending.eq(0)
110+
)
95111
)
96112
]
97113

98-
# Drive IODELAY controls
99-
delay_init = Signal()
100-
delay_init_count = Signal(7, reset=127)
101-
self.comb += delay_init.eq(delay_init_count != 0)
102-
self.sync.pix5x += If(delay_init, delay_init_count.eq(delay_init_count - 1))
114+
self.submodules.do_delay_cal = PulseSynchronizer("sys", "pix5x")
115+
self.submodules.do_delay_rst = PulseSynchronizer("sys", "pix5x")
116+
self.submodules.do_delay_inc = PulseSynchronizer("sys", "pix5x")
117+
self.submodules.do_delay_dec = PulseSynchronizer("sys", "pix5x")
103118
self.comb += [
104-
delay_ce.eq(delay_init | pulse_inc | pulse_dec),
105-
delay_inc.eq(delay_init | pulse_inc)
119+
delay_cal.eq(self.do_delay_cal.o),
120+
delay_rst.eq(self.do_delay_rst.o),
121+
delay_inc.eq(self.do_delay_inc.o),
122+
delay_ce.eq(self.do_delay_inc.o | self.do_delay_dec.o),
106123
]
107124

108-
# Debug
109-
if debug:
110-
# Transfer delay update commands to system clock domain
111-
pix5x_reset_sys = Signal()
112-
self.specials += MultiReg(ResetSignal("pix5x"), pix5x_reset_sys, "sys")
113-
self.submodules.xf_inc = PulseSynchronizer("pix5x", "sys")
114-
self.submodules.xf_dec = PulseSynchronizer("pix5x", "sys")
115-
self.comb += [
116-
self.xf_inc.i.eq(pulse_inc),
117-
self.xf_dec.i.eq(pulse_dec)
118-
]
119-
# Update tap count in system clock domain
120-
current_tap = Signal(8, reset=127)
121-
self.comb += self._r_current_tap.field.w.eq(current_tap)
122-
self.sync += If(pix5x_reset_sys,
123-
current_tap.eq(127)
124-
).Elif(self.xf_inc.o & (current_tap != 0xff),
125-
current_tap.eq(current_tap + 1)
126-
).Elif(self.xf_dec.o & (current_tap != 0),
127-
current_tap.eq(current_tap - 1)
128-
)
125+
sys_delay_pending = Signal()
126+
self.sync += [
127+
If(self.do_delay_cal.i | self.do_delay_inc.i | self.do_delay_dec.i,
128+
sys_delay_pending.eq(1)
129+
).Elif(self.delay_done.o,
130+
sys_delay_pending.eq(0)
131+
)
132+
]
133+
134+
self.comb += [
135+
self.do_delay_cal.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[0]),
136+
self.do_delay_rst.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[1]),
137+
self.do_delay_inc.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[2]),
138+
self.do_delay_dec.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[3]),
139+
self._r_dly_busy.field.w.eq(sys_delay_pending)
140+
]
141+
142+
# Phase detector control
143+
self.specials += MultiReg(Cat(too_late, too_early), self._r_phase.field.w)
144+
self.submodules.do_reset_lateness = PulseSynchronizer("sys", "pix5x")
145+
self.comb += [
146+
reset_lateness.eq(self.do_reset_lateness.o),
147+
self.do_reset_lateness.i.eq(self._r_phase_reset.re)
148+
]

0 commit comments

Comments
 (0)
Please sign in to comment.