Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

dvisampler: add clocking and phase detector

  • Loading branch information...
commit 9f02ced39e89b829504744f5f03558b6933ff1ea 1 parent 0168f83
Sébastien Bourdeauducq authored March 17, 2013
11  build.py
@@ -43,10 +43,19 @@ def main():
43 43
 NET "asfifo*/counter_read/gray_count*" TIG;
44 44
 NET "asfifo*/counter_write/gray_count*" TIG;
45 45
 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%;
46 53
 """,
47 54
 		clk50=soc.crg.clk50_pad,
48 55
 		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)
50 59
 	
51 60
 	# add Verilog sources
52 61
 	for d in ["generic", "m1crg", "s6ddrphy", "minimac3"]:
26  milkymist/dvisampler/__init__.py
@@ -3,16 +3,28 @@
3 3
 from migen.bank.description import *
4 4
 
5 5
 from milkymist.dvisampler.edid import EDID
  6
+from milkymist.dvisampler.clocking import Clocking
  7
+from milkymist.dvisampler.datacapture import DataCapture
6 8
 
7 9
 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
+
10 18
 		for datan in "012":
11 19
 			name = "data" + str(datan)
  20
+			cap = DataCapture(8, debug_data_capture)
  21
+			setattr(self.submodules, name + "_cap", cap)
12 22
 			if datan in inversions:
13 23
 				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
+			]
60  milkymist/dvisampler/clocking.py
... ...
@@ -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)
136  milkymist/dvisampler/datacapture.py
... ...
@@ -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 notes on commit 9f02ced

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