Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

dvisampler: software controlled phase detector

  • Loading branch information...
commit 0a14c3714b26dcf451cd9dd541d071ac3b538ce3 1 parent 28cb970
Sébastien Bourdeauducq authored March 21, 2013
4  build.py
@@ -46,10 +46,10 @@ def main():
46 46
 
47 47
 NET "{dviclk0}" TNM_NET = "GRPdviclk0";
48 48
 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%;
50 50
 NET "{dviclk1}" TNM_NET = "GRPdviclk1";
51 51
 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%;
53 53
 """,
54 54
 		clk50=soc.crg.clk50_pad,
55 55
 		phy_rx_clk=soc.crg.eth_rx_clk_pad,
4  milkymist/dvisampler/__init__.py
@@ -7,7 +7,7 @@
7 7
 from milkymist.dvisampler.datacapture import DataCapture
8 8
 
9 9
 class DVISampler(Module, AutoReg):
10  
-	def __init__(self, inversions="", debug_data_capture=True):
  10
+	def __init__(self, inversions=""):
11 11
 		self.submodules.edid = EDID()
12 12
 		self.sda = self.edid.sda
13 13
 		self.scl = self.edid.scl
@@ -17,7 +17,7 @@ def __init__(self, inversions="", debug_data_capture=True):
17 17
 
18 18
 		for datan in "012":
19 19
 			name = "data" + str(datan)
20  
-			cap = DataCapture(8, debug_data_capture)
  20
+			cap = DataCapture(8)
21 21
 			setattr(self.submodules, name + "_cap", cap)
22 22
 			if datan in inversions:
23 23
 				name += "_n"
9  milkymist/dvisampler/clocking.py
@@ -15,6 +15,7 @@ def __init__(self):
15 15
 		self.serdesstrobe = Signal()
16 16
 		self.clock_domains._cd_pix = ClockDomain()
17 17
 		self.clock_domains._cd_pix5x = ClockDomain()
  18
+		self.clock_domains._cd_pix10x = ClockDomain()
18 19
 		self.clock_domains._cd_pix20x = ClockDomain()
19 20
 
20 21
 		###
@@ -24,18 +25,22 @@ def __init__(self):
24 25
 		pll_clk0 = Signal()
25 26
 		pll_clk1 = Signal()
26 27
 		pll_clk2 = Signal()
  28
+		pll_clk3 = Signal()
27 29
 		self.specials += Instance("PLL_BASE",
28  
-			Instance.Parameter("CLKIN_PERIOD", 22.0),
  30
+			Instance.Parameter("CLKIN_PERIOD", 26.7),
29 31
 			Instance.Parameter("CLKFBOUT_MULT", 20),
30 32
 			Instance.Parameter("CLKOUT0_DIVIDE", 1),  # pix20x
31 33
 			Instance.Parameter("CLKOUT1_DIVIDE", 4),  # pix5x
32 34
 			Instance.Parameter("CLKOUT2_DIVIDE", 20), # pix
  35
+			Instance.Parameter("CLKOUT3_DIVIDE", 2),  # pix10x
33 36
 			Instance.Parameter("COMPENSATION", "INTERNAL"),
34 37
 
35 38
 			Instance.Output("CLKFBOUT", clkfbout),
  39
+			# WARNING: Do not touch the order of those clocks, or PAR fails.
36 40
 			Instance.Output("CLKOUT0", pll_clk0),
37 41
 			Instance.Output("CLKOUT1", pll_clk1),
38 42
 			Instance.Output("CLKOUT2", pll_clk2),
  43
+			Instance.Output("CLKOUT3", pll_clk3),
39 44
 			Instance.Output("LOCKED", pll_locked),
40 45
 			Instance.Input("CLKFBIN", clkfbout),
41 46
 			Instance.Input("CLKIN", self.clkin),
@@ -56,6 +61,8 @@ def __init__(self):
56 61
 			Instance.Input("I", pll_clk1), Instance.Output("O", self._cd_pix5x.clk))
57 62
 		self.specials += Instance("BUFG",
58 63
 			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))
59 66
 		self.specials += MultiReg(locked_async, self.locked, "sys")
60 67
 		self.comb += self._r_locked.field.w.eq(self.locked)
61 68
 
128  milkymist/dvisampler/datacapture.py
@@ -5,14 +5,16 @@
5 5
 from migen.bank.description import *
6 6
 
7 7
 class DataCapture(Module, AutoReg):
8  
-	def __init__(self, ntbits, debug=False):
  8
+	def __init__(self, ntbits):
9 9
 		self.pad = Signal()
10 10
 		self.serdesstrobe = Signal()
11 11
 		self.d0 = Signal() # pix5x clock domain
12 12
 		self.d1 = Signal() # pix5x clock domain
13 13
 
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()
16 18
 
17 19
 		###
18 20
 
@@ -20,19 +22,23 @@ def __init__(self, ntbits, debug=False):
20 22
 		pad_delayed = Signal()
21 23
 		delay_inc = Signal()
22 24
 		delay_ce = Signal()
  25
+		delay_cal = Signal()
  26
+		delay_rst = Signal()
  27
+		delay_busy = Signal()
23 28
 		self.specials += Instance("IODELAY2",
24 29
 			Instance.Parameter("DELAY_SRC", "IDATAIN"),
25  
-			Instance.Parameter("IDELAY_TYPE", "VARIABLE_FROM_ZERO"),
  30
+			Instance.Parameter("IDELAY_TYPE", "VARIABLE_FROM_HALF_MAX"),
26 31
 			Instance.Parameter("COUNTER_WRAPAROUND", "STAY_AT_LIMIT"),
27 32
 			Instance.Parameter("DATA_RATE", "SDR"),
28 33
 			Instance.Input("IDATAIN", self.pad),
29 34
 			Instance.Output("DATAOUT", pad_delayed),
  35
+			Instance.Input("CLK", ClockSignal("pix5x")),
  36
+			Instance.Input("IOCLK0", ClockSignal("pix10x")),
30 37
 			Instance.Input("INC", delay_inc),
31 38
 			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),
36 42
 			Instance.Input("T", 1)
37 43
 		)
38 44
 
@@ -57,23 +63,19 @@ def __init__(self, ntbits, debug=False):
57 63
 			Instance.Input("RST", 0)
58 64
 		)
59 65
 
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
+		]
65 75
 		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),
77 79
 				If(self.d0,
78 80
 					# 1 -----> 0
79 81
 					#    d0p
@@ -90,39 +92,57 @@ def __init__(self, ntbits, debug=False):
90 92
 					).Else(
91 93
 						lateness.eq(lateness - 1)
92 94
 					)
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
+				)
95 111
 			)
96 112
 		]
97 113
 
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")
103 118
 		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),
106 123
 		]
107 124
 
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 notes on commit 0a14c37

Please sign in to comment.
Something went wrong with that request. Please try again.