dvisampler: software controlled phase detector
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Wed, 20 Mar 2013 23:46:29 +0000 (00:46 +0100)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Wed, 20 Mar 2013 23:46:29 +0000 (00:46 +0100)
build.py
milkymist/dvisampler/__init__.py
milkymist/dvisampler/clocking.py
milkymist/dvisampler/datacapture.py

index 21f8fd128157a0a4bab41f0749879ea74fce82e5..ed48d3e7608cdc0c55f6886b50369cdb7a39c5a8 100755 (executable)
--- a/build.py
+++ b/build.py
@@ -46,10 +46,10 @@ NET "asfifo*/preset_empty*" TIG;
 
 NET "{dviclk0}" TNM_NET = "GRPdviclk0";
 NET "{dviclk0}" CLOCK_DEDICATED_ROUTE = FALSE;
-TIMESPEC "TSdviclk0" = PERIOD "GRPdviclk0" 22 ns HIGH 50%;
+TIMESPEC "TSdviclk0" = PERIOD "GRPdviclk0" 26.7 ns HIGH 50%;
 NET "{dviclk1}" TNM_NET = "GRPdviclk1";
 NET "{dviclk1}" CLOCK_DEDICATED_ROUTE = FALSE;
-TIMESPEC "TSdviclk1" = PERIOD "GRPdviclk1" 22 ns HIGH 50%;
+TIMESPEC "TSdviclk1" = PERIOD "GRPdviclk1" 26.7 ns HIGH 50%;
 """,
                clk50=soc.crg.clk50_pad,
                phy_rx_clk=soc.crg.eth_rx_clk_pad,
index 477585f03b1621241411c65872e092cbf41dec38..278b5b4e027d7a7792e86ec98961970cf33f2a70 100644 (file)
@@ -7,7 +7,7 @@ from milkymist.dvisampler.clocking import Clocking
 from milkymist.dvisampler.datacapture import DataCapture
 
 class DVISampler(Module, AutoReg):
-       def __init__(self, inversions="", debug_data_capture=True):
+       def __init__(self, inversions=""):
                self.submodules.edid = EDID()
                self.sda = self.edid.sda
                self.scl = self.edid.scl
@@ -17,7 +17,7 @@ class DVISampler(Module, AutoReg):
 
                for datan in "012":
                        name = "data" + str(datan)
-                       cap = DataCapture(8, debug_data_capture)
+                       cap = DataCapture(8)
                        setattr(self.submodules, name + "_cap", cap)
                        if datan in inversions:
                                name += "_n"
index a7c1598da14c55fe5ef03c32fa8eea263a5be72e..b20dfd9b06a15365196760a2023bf7faf9147106 100644 (file)
@@ -15,6 +15,7 @@ class Clocking(Module, AutoReg):
                self.serdesstrobe = Signal()
                self.clock_domains._cd_pix = ClockDomain()
                self.clock_domains._cd_pix5x = ClockDomain()
+               self.clock_domains._cd_pix10x = ClockDomain()
                self.clock_domains._cd_pix20x = ClockDomain()
 
                ###
@@ -24,18 +25,22 @@ class Clocking(Module, AutoReg):
                pll_clk0 = Signal()
                pll_clk1 = Signal()
                pll_clk2 = Signal()
+               pll_clk3 = Signal()
                self.specials += Instance("PLL_BASE",
-                       Instance.Parameter("CLKIN_PERIOD", 22.0),
+                       Instance.Parameter("CLKIN_PERIOD", 26.7),
                        Instance.Parameter("CLKFBOUT_MULT", 20),
                        Instance.Parameter("CLKOUT0_DIVIDE", 1),  # pix20x
                        Instance.Parameter("CLKOUT1_DIVIDE", 4),  # pix5x
                        Instance.Parameter("CLKOUT2_DIVIDE", 20), # pix
+                       Instance.Parameter("CLKOUT3_DIVIDE", 2),  # pix10x
                        Instance.Parameter("COMPENSATION", "INTERNAL"),
 
                        Instance.Output("CLKFBOUT", clkfbout),
+                       # WARNING: Do not touch the order of those clocks, or PAR fails.
                        Instance.Output("CLKOUT0", pll_clk0),
                        Instance.Output("CLKOUT1", pll_clk1),
                        Instance.Output("CLKOUT2", pll_clk2),
+                       Instance.Output("CLKOUT3", pll_clk3),
                        Instance.Output("LOCKED", pll_locked),
                        Instance.Input("CLKFBIN", clkfbout),
                        Instance.Input("CLKIN", self.clkin),
@@ -56,6 +61,8 @@ class Clocking(Module, AutoReg):
                        Instance.Input("I", pll_clk1), Instance.Output("O", self._cd_pix5x.clk))
                self.specials += Instance("BUFG",
                        Instance.Input("I", pll_clk2), Instance.Output("O", self._cd_pix.clk))
+               self.specials += Instance("BUFG",
+                       Instance.Input("I", pll_clk3), Instance.Output("O", self._cd_pix10x.clk))
                self.specials += MultiReg(locked_async, self.locked, "sys")
                self.comb += self._r_locked.field.w.eq(self.locked)
 
index 6a534987505929b0cafaae426ee1eb48c2b9939f..7943a173f29fd8a67d4e0dcd6c8501aeb8a14b77 100644 (file)
@@ -5,14 +5,16 @@ from migen.genlib.cdc import MultiReg, PulseSynchronizer
 from migen.bank.description import *
 
 class DataCapture(Module, AutoReg):
-       def __init__(self, ntbits, debug=False):
+       def __init__(self, ntbits):
                self.pad = Signal()
                self.serdesstrobe = Signal()
                self.d0 = Signal() # pix5x clock domain
                self.d1 = Signal() # pix5x clock domain
 
-               if debug:
-                       self._r_current_tap = RegisterField(8, READ_ONLY, WRITE_ONLY)
+               self._r_dly_ctl = RegisterRaw(4)
+               self._r_dly_busy = RegisterField(1, READ_ONLY, WRITE_ONLY)
+               self._r_phase = RegisterField(2, READ_ONLY, WRITE_ONLY)
+               self._r_phase_reset = RegisterRaw()
 
                ###
 
@@ -20,19 +22,23 @@ class DataCapture(Module, AutoReg):
                pad_delayed = Signal()
                delay_inc = Signal()
                delay_ce = Signal()
+               delay_cal = Signal()
+               delay_rst = Signal()
+               delay_busy = Signal()
                self.specials += Instance("IODELAY2",
                        Instance.Parameter("DELAY_SRC", "IDATAIN"),
-                       Instance.Parameter("IDELAY_TYPE", "VARIABLE_FROM_ZERO"),
+                       Instance.Parameter("IDELAY_TYPE", "VARIABLE_FROM_HALF_MAX"),
                        Instance.Parameter("COUNTER_WRAPAROUND", "STAY_AT_LIMIT"),
                        Instance.Parameter("DATA_RATE", "SDR"),
                        Instance.Input("IDATAIN", self.pad),
                        Instance.Output("DATAOUT", pad_delayed),
+                       Instance.Input("CLK", ClockSignal("pix5x")),
+                       Instance.Input("IOCLK0", ClockSignal("pix10x")),
                        Instance.Input("INC", delay_inc),
                        Instance.Input("CE", delay_ce),
-                       Instance.Input("RST", ResetSignal("pix5x")),
-                       Instance.Input("CLK", ClockSignal("pix5x")),
-                       Instance.Input("IOCLK0", ClockSignal("pix20x")),
-                       Instance.Input("CAL", 0),
+                       Instance.Input("CAL", delay_cal),
+                       Instance.Input("RST", delay_rst),
+                       Instance.Output("BUSY", delay_busy),
                        Instance.Input("T", 1)
                )
 
@@ -57,23 +63,19 @@ class DataCapture(Module, AutoReg):
                        Instance.Input("RST", 0)
                )
 
-               # Transition counter
-               transitions = Signal(ntbits)
-               lateness = Signal((ntbits + 1, True))
-               pulse_inc = Signal()
-               pulse_dec = Signal()
+               # Phase detector
+               lateness = Signal(ntbits, reset=2**(ntbits - 1))
+               too_late = Signal()
+               too_early = Signal()
+               reset_lateness = Signal()
+               self.comb += [
+                       too_late.eq(lateness == (2**ntbits - 1)),
+                       too_early.eq(lateness == 0)
+               ]
                self.sync.pix5x += [
-                       pulse_inc.eq(0),
-                       pulse_dec.eq(0),
-                       If(transitions ==  2**ntbits - 1,
-                               If(lateness[ntbits],
-                                       pulse_inc.eq(1)
-                               ).Else(
-                                       pulse_dec.eq(1)
-                               ),
-                               lateness.eq(0),
-                               transitions.eq(0)
-                       ).Elif(self.d0 != self.d1,
+                       If(reset_lateness,
+                               lateness.eq(2**(ntbits - 1))
+                       ).Elif(~delay_busy & ~too_late & ~too_early & (self.d0 != self.d1),
                                If(self.d0,
                                        # 1 -----> 0
                                        #    d0p
@@ -90,39 +92,57 @@ class DataCapture(Module, AutoReg):
                                        ).Else(
                                                lateness.eq(lateness - 1)
                                        )
-                               ),
-                               transitions.eq(transitions + 1)
+                               )
+                       )
+               ]
+
+               # Delay control
+               self.submodules.delay_done = PulseSynchronizer("pix5x", "sys")
+               delay_pending = Signal()
+               self.sync.pix5x += [
+                       self.delay_done.i.eq(0),
+                       If(~delay_pending,
+                               If(delay_cal | delay_ce, delay_pending.eq(1))
+                       ).Else(
+                               If(~delay_busy,
+                                       self.delay_done.i.eq(1),
+                                       delay_pending.eq(0)
+                               )
                        )
                ]
 
-               # Drive IODELAY controls
-               delay_init = Signal()
-               delay_init_count = Signal(7, reset=127)
-               self.comb += delay_init.eq(delay_init_count != 0)
-               self.sync.pix5x += If(delay_init, delay_init_count.eq(delay_init_count - 1))
+               self.submodules.do_delay_cal = PulseSynchronizer("sys", "pix5x")
+               self.submodules.do_delay_rst = PulseSynchronizer("sys", "pix5x")
+               self.submodules.do_delay_inc = PulseSynchronizer("sys", "pix5x")
+               self.submodules.do_delay_dec = PulseSynchronizer("sys", "pix5x")
                self.comb += [
-                       delay_ce.eq(delay_init | pulse_inc | pulse_dec),
-                       delay_inc.eq(delay_init | pulse_inc)
+                       delay_cal.eq(self.do_delay_cal.o),
+                       delay_rst.eq(self.do_delay_rst.o),
+                       delay_inc.eq(self.do_delay_inc.o),
+                       delay_ce.eq(self.do_delay_inc.o | self.do_delay_dec.o),
                ]
 
-               # Debug
-               if debug:
-                       # Transfer delay update commands to system clock domain
-                       pix5x_reset_sys = Signal()
-                       self.specials += MultiReg(ResetSignal("pix5x"), pix5x_reset_sys, "sys")
-                       self.submodules.xf_inc = PulseSynchronizer("pix5x", "sys")
-                       self.submodules.xf_dec = PulseSynchronizer("pix5x", "sys")
-                       self.comb += [
-                               self.xf_inc.i.eq(pulse_inc),
-                               self.xf_dec.i.eq(pulse_dec)
-                       ]
-                       # Update tap count in system clock domain
-                       current_tap = Signal(8, reset=127)
-                       self.comb += self._r_current_tap.field.w.eq(current_tap)
-                       self.sync += If(pix5x_reset_sys,
-                                       current_tap.eq(127)
-                               ).Elif(self.xf_inc.o & (current_tap != 0xff),
-                                       current_tap.eq(current_tap + 1)
-                               ).Elif(self.xf_dec.o & (current_tap != 0),
-                                       current_tap.eq(current_tap - 1)
-                               )
+               sys_delay_pending = Signal()
+               self.sync += [
+                       If(self.do_delay_cal.i | self.do_delay_inc.i | self.do_delay_dec.i,
+                               sys_delay_pending.eq(1)
+                       ).Elif(self.delay_done.o,
+                               sys_delay_pending.eq(0)
+                       )
+               ]
+
+               self.comb += [
+                       self.do_delay_cal.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[0]),
+                       self.do_delay_rst.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[1]),
+                       self.do_delay_inc.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[2]),
+                       self.do_delay_dec.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[3]),
+                       self._r_dly_busy.field.w.eq(sys_delay_pending)
+               ]
+
+               # Phase detector control
+               self.specials += MultiReg(Cat(too_late, too_early), self._r_phase.field.w)
+               self.submodules.do_reset_lateness = PulseSynchronizer("sys", "pix5x")
+               self.comb += [
+                       reset_lateness.eq(self.do_reset_lateness.o),
+                       self.do_reset_lateness.i.eq(self._r_phase_reset.re)
+               ]