Skip to content

Commit 9f02ced

Browse files
author
Sebastien Bourdeauducq
committedMar 17, 2013
dvisampler: add clocking and phase detector
1 parent 0168f83 commit 9f02ced

File tree

4 files changed

+225
-8
lines changed

4 files changed

+225
-8
lines changed
 

‎build.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,19 @@ def main():
4343
NET "asfifo*/counter_read/gray_count*" TIG;
4444
NET "asfifo*/counter_write/gray_count*" TIG;
4545
NET "asfifo*/preset_empty*" TIG;
46+
47+
NET "{dviclk0}" TNM_NET = "GRPdviclk0";
48+
NET "{dviclk0}" CLOCK_DEDICATED_ROUTE = FALSE;
49+
TIMESPEC "TSdviclk0" = PERIOD "GRPdviclk0" 22 ns HIGH 50%;
50+
NET "{dviclk1}" TNM_NET = "GRPdviclk1";
51+
NET "{dviclk1}" CLOCK_DEDICATED_ROUTE = FALSE;
52+
TIMESPEC "TSdviclk1" = PERIOD "GRPdviclk1" 22 ns HIGH 50%;
4653
""",
4754
clk50=soc.crg.clk50_pad,
4855
phy_rx_clk=soc.crg.eth_rx_clk_pad,
49-
phy_tx_clk=soc.crg.eth_tx_clk_pad)
56+
phy_tx_clk=soc.crg.eth_tx_clk_pad,
57+
dviclk0=soc.dvisampler0.clk,
58+
dviclk1=soc.dvisampler1.clk)
5059

5160
# add Verilog sources
5261
for d in ["generic", "m1crg", "s6ddrphy", "minimac3"]:

‎milkymist/dvisampler/__init__.py

+19-7
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,28 @@
33
from migen.bank.description import *
44

55
from milkymist.dvisampler.edid import EDID
6+
from milkymist.dvisampler.clocking import Clocking
7+
from milkymist.dvisampler.datacapture import DataCapture
68

79
class DVISampler(Module, AutoReg):
8-
def __init__(self, inversions=""):
9-
self.clk = Signal()
10+
def __init__(self, inversions="", debug_data_capture=True):
11+
self.submodules.edid = EDID()
12+
self.sda = self.edid.sda
13+
self.scl = self.edid.scl
14+
15+
self.submodules.clocking = Clocking()
16+
self.clk = self.clocking.clkin
17+
1018
for datan in "012":
1119
name = "data" + str(datan)
20+
cap = DataCapture(8, debug_data_capture)
21+
setattr(self.submodules, name + "_cap", cap)
1222
if datan in inversions:
1323
name += "_n"
14-
setattr(self, name, Signal(name=name))
15-
16-
self.submodules.edid = EDID()
17-
self.sda = self.edid.sda
18-
self.scl = self.edid.scl
24+
s = Signal(name=name)
25+
setattr(self, name, s)
26+
self.comb += [
27+
cap.pad.eq(s),
28+
cap.serdesstrobe.eq(self.clocking.serdesstrobe),
29+
cap.delay_rst.eq(~self.clocking.locked)
30+
]

‎milkymist/dvisampler/clocking.py

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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 MultiReg
5+
from migen.bank.description import *
6+
7+
class Clocking(Module, AutoReg):
8+
def __init__(self):
9+
self.clkin = Signal()
10+
11+
self._r_pll_reset = RegisterField(reset=1)
12+
self._r_locked = RegisterField(1, READ_ONLY, WRITE_ONLY)
13+
14+
self.locked = Signal()
15+
self.serdesstrobe = Signal()
16+
self._cd_pix = ClockDomain()
17+
self._cd_pix5x = ClockDomain()
18+
self._cd_pix20x = ClockDomain()
19+
20+
###
21+
22+
clkfbout = Signal()
23+
pll_locked = Signal()
24+
pll_clk0 = Signal()
25+
pll_clk1 = Signal()
26+
pll_clk2 = Signal()
27+
self.specials += Instance("PLL_BASE",
28+
Instance.Parameter("CLKIN_PERIOD", 22.0),
29+
Instance.Parameter("CLKFBOUT_MULT", 20),
30+
Instance.Parameter("CLKOUT0_DIVIDE", 20), # pix
31+
Instance.Parameter("CLKOUT1_DIVIDE", 4), # pix5x
32+
Instance.Parameter("CLKOUT2_DIVIDE", 1), # pix20x
33+
Instance.Parameter("COMPENSATION", "INTERNAL"),
34+
35+
Instance.Output("CLKFBOUT", clkfbout),
36+
Instance.Output("CLKOUT0", pll_clk0),
37+
Instance.Output("CLKOUT1", pll_clk1),
38+
Instance.Output("CLKOUT2", pll_clk2),
39+
Instance.Output("LOCKED", pll_locked),
40+
Instance.Input("CLKFBIN", clkfbout),
41+
Instance.Input("CLKIN", self.clkin),
42+
Instance.Input("RST", self._r_pll_reset.field.r)
43+
)
44+
45+
self.specials += Instance("BUFG",
46+
Instance.Input("I", pll_clk0), Instance.Output("O", self._cd_pix.clk))
47+
self.specials += Instance("BUFG",
48+
Instance.Input("I", pll_clk1), Instance.Output("O", self._cd_pix5x.clk))
49+
locked_async = Signal()
50+
self.specials += Instance("BUFPLL",
51+
Instance.Parameter("DIVIDE", 4),
52+
Instance.Input("PLLIN", pll_clk2),
53+
Instance.ClockPort("GCLK", "pix5x"),
54+
Instance.Input("LOCKED", pll_locked),
55+
Instance.Output("IOCLK", self._cd_pix20x.clk),
56+
Instance.Output("LOCK", locked_async),
57+
Instance.Output("SERDESSTROBE", self.serdesstrobe)
58+
)
59+
self.specials += MultiReg(locked_async, self.locked, "sys")
60+
self.comb += self._r_locked.field.w.eq(self.locked)

‎milkymist/dvisampler/datacapture.py

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
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("IDELAY2",
28+
Instance.Parameter("DELAY_SRC", "IDATAIN"),
29+
Instance.Parameter("IDELAY_TYPE", "VARIABLE_FROM_ZERO"),
30+
Instance.Parameter("COUNTER_WRAP_AROUND", "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+
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)

0 commit comments

Comments
 (0)
Please sign in to comment.