dvisampler: use hard differential phase detector
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Sat, 14 Sep 2013 15:14:20 +0000 (17:14 +0200)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Sat, 14 Sep 2013 15:14:20 +0000 (17:14 +0200)
milkymist/dvisampler/__init__.py
milkymist/dvisampler/clocking.py
milkymist/dvisampler/datacapture.py
software/include/hw/flags.h
software/videomixer/dvisamplerX.c

index a752f1a32ff56c5abe3fab283a4d02c0505b1450..c0227c129f6da102bf17bbc4162bf02f0a5e09a0 100644 (file)
@@ -18,27 +18,10 @@ class DVISampler(Module, AutoCSR):
 
                for datan in range(3):
                        name = "data" + str(datan)
-                       invert = False
-                       if hasattr(pads, name + "_p"):
-                               s = Signal()
-                               self.specials += Instance("IBUFDS",
-                                       Instance.Input("I", getattr(pads, name + "_p")),
-                                       Instance.Input("IB", getattr(pads, name + "_n")),
-                                       Instance.Output("O", s)         
-                               )
-                       else:
-                               try:
-                                       s = getattr(pads, name)
-                               except AttributeError:
-                                       s = getattr(pads, name + "_n")
-                                       invert = True
                        
-                       cap = DataCapture(8, invert)
+                       cap = DataCapture(getattr(pads, name + "_p"), getattr(pads, name + "_n"), 8)
                        setattr(self.submodules, name + "_cap", cap)
-                       self.comb += [
-                               cap.pad.eq(s),
-                               cap.serdesstrobe.eq(self.clocking.serdesstrobe)
-                       ]
+                       self.comb += cap.serdesstrobe.eq(self.clocking.serdesstrobe)
 
                        charsync = CharSync()
                        setattr(self.submodules, name + "_charsync", charsync)
@@ -64,8 +47,6 @@ class DVISampler(Module, AutoCSR):
                        self.chansync.data_in2.eq(self.data2_decod.output),
                ]
 
-               ###
-
                self.submodules.syncpol = SyncPolarity()
                self.comb += [
                        self.syncpol.valid_i.eq(self.chansync.chan_synced),
index 9e261d05c114bec8dce1a3ecf155d522a942f0a3..9fcad685aa57fcdccfe4dd9483e38deb510b540c 100644 (file)
@@ -12,77 +12,46 @@ class Clocking(Module, AutoCSR):
                self.clock_domains._cd_pix = ClockDomain()
                self.clock_domains._cd_pix5x = ClockDomain()
                self.clock_domains._cd_pix10x = ClockDomain(reset_less=True)
-               self.clock_domains._cd_pix20x = ClockDomain(reset_less=True)
 
                ###
 
-               if hasattr(pads, "clk_p"):
-                       clkin = Signal()
-                       self.specials += Instance("IBUFDS",
-                               Instance.Input("I", pads.clk_p),
-                               Instance.Input("IB", pads.clk_n),
-                               Instance.Output("O", clkin)             
-                       )
-               else:
-                       clkin = pads.clk
+               clk_se = Signal()
+               self.specials += Instance("IBUFDS", i_I=pads.clk_p, i_IB=pads.clk_n, o_O=clk_se)
 
                clkfbout = Signal()
                pll_locked = Signal()
                pll_clk0 = Signal()
                pll_clk1 = Signal()
                pll_clk2 = Signal()
-               pll_clk3 = Signal()
                self.specials += Instance("PLL_BASE",
-                       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", clkin),
-                       Instance.Input("RST", self._r_pll_reset.storage)
-               )
+                       p_CLKIN_PERIOD=26.7,
+                       p_CLKFBOUT_MULT=20,
+                       p_CLKOUT0_DIVIDE=2,  # pix10x
+                       p_CLKOUT1_DIVIDE=4,  # pix5x
+                       p_CLKOUT2_DIVIDE=20, # pix
+                       p_COMPENSATION="INTERNAL",
+                       
+                       i_CLKIN=clk_se,
+                       o_CLKOUT0=pll_clk0, o_CLKOUT1=pll_clk1, o_CLKOUT2=pll_clk2,
+                       o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbout,
+                       o_LOCKED=pll_locked, i_RST=self._r_pll_reset.storage)
 
                locked_async = Signal()
-               self.specials += Instance("BUFPLL",
-                       Instance.Parameter("DIVIDE", 4),
-                       Instance.Input("PLLIN", pll_clk0),
-                       Instance.Input("GCLK", ClockSignal("pix5x")),
-                       Instance.Input("LOCKED", pll_locked),
-                       Instance.Output("IOCLK", self._cd_pix20x.clk),
-                       Instance.Output("LOCK", locked_async),
-                       Instance.Output("SERDESSTROBE", self.serdesstrobe)
-               )
-               self.specials += Instance("BUFG",
-                       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.specials += [
+                       Instance("BUFPLL", p_DIVIDE=2,
+                               i_PLLIN=pll_clk0, i_GCLK=ClockSignal("pix5x"), i_LOCKED=pll_locked,
+                               o_IOCLK=self._cd_pix10x.clk, o_LOCK=locked_async, o_SERDESSTROBE=self.serdesstrobe),
+                       Instance("BUFG", i_I=pll_clk1, o_O=self._cd_pix5x.clk),
+                       Instance("BUFG", i_I=pll_clk2, o_O=self._cd_pix.clk),
+                       MultiReg(locked_async, self.locked, "sys")
+               ]
                self.comb += self._r_locked.status.eq(self.locked)
 
                # sychronize pix+pix5x reset
                pix_rst_n = 1
                for i in range(2):
                        new_pix_rst_n = Signal()
-                       self.specials += Instance("FDCE",
-                               Instance.Input("D", pix_rst_n),
-                               Instance.Input("CE", 1),
-                               Instance.Input("C", ClockSignal("pix")),
-                               Instance.Input("CLR", ~locked_async),
-                               Instance.Output("Q", new_pix_rst_n)
-                       )
+                       self.specials += Instance("FDCE", i_D=pix_rst_n, i_CE=1, i_C=ClockSignal("pix"),
+                               i_CLR=~locked_async, o_Q=new_pix_rst_n)
                        pix_rst_n = new_pix_rst_n
-               self.comb += self._cd_pix.rst.eq(~pix_rst_n)
-               self.comb += self._cd_pix5x.rst.eq(~pix_rst_n)
+               self.comb += self._cd_pix.rst.eq(~pix_rst_n), self._cd_pix5x.rst.eq(~pix_rst_n)
index 8cb060c7e500839d54a9281d7f75f42c93bf9ab7..50a92e445f332188bc5163e596253d8df2fa776f 100644 (file)
@@ -3,66 +3,88 @@ from migen.genlib.cdc import MultiReg, PulseSynchronizer
 from migen.bank.description import *
 
 class DataCapture(Module, AutoCSR):
-       def __init__(self, ntbits, invert):
-               self.pad = Signal()
+       def __init__(self, pad_p, pad_n, ntbits):
                self.serdesstrobe = Signal()
                self.d = Signal(10)
 
-               self._r_dly_ctl = CSR(4)
-               self._r_dly_busy = CSRStatus()
+               self._r_dly_ctl = CSR(6)
+               self._r_dly_busy = CSRStatus(2)
                self._r_phase = CSRStatus(2)
                self._r_phase_reset = CSR()
 
                ###
 
                # IO
-               pad_delayed = Signal()
+               pad_se = Signal()
+               self.specials += Instance("IBUFDS", i_I=pad_p, i_IB=pad_n, o_O=pad_se)
+
+               pad_delayed_master = Signal()
+               pad_delayed_slave = Signal()
                delay_inc = Signal()
                delay_ce = Signal()
-               delay_cal = Signal()
-               delay_rst = Signal()
-               delay_busy = Signal()
+               delay_master_cal = Signal()
+               delay_master_rst = Signal()
+               delay_master_busy = Signal()
+               delay_slave_cal = Signal()
+               delay_slave_rst = Signal()
+               delay_slave_busy = Signal()
+               self.specials += Instance("IODELAY2",
+                       p_SERDES_MODE="MASTER",
+                       p_DELAY_SRC="IDATAIN", p_IDELAY_TYPE="DIFF_PHASE_DETECTOR",
+                       p_COUNTER_WRAPAROUND="STAY_AT_LIMIT", p_DATA_RATE="SDR",
+
+                       i_IDATAIN=pad_se, o_DATAOUT=pad_delayed_master,
+                       i_CLK=ClockSignal("pix5x"), i_IOCLK0=ClockSignal("pix10x"),
+
+                       i_INC=delay_inc, i_CE=delay_ce,
+                       i_CAL=delay_master_cal, i_RST=delay_master_rst, o_BUSY=delay_master_busy,
+                       i_T=1)
                self.specials += Instance("IODELAY2",
-                       Instance.Parameter("DELAY_SRC", "IDATAIN"),
-                       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("CAL", delay_cal),
-                       Instance.Input("RST", delay_rst),
-                       Instance.Output("BUSY", delay_busy),
-                       Instance.Input("T", 1)
-               )
+                       p_SERDES_MODE="SLAVE",
+                       p_DELAY_SRC="IDATAIN", p_IDELAY_TYPE="DIFF_PHASE_DETECTOR",
+                       p_COUNTER_WRAPAROUND="STAY_AT_LIMIT", p_DATA_RATE="SDR",
+
+                       i_IDATAIN=pad_se, o_DATAOUT=pad_delayed_slave,
+                       i_CLK=ClockSignal("pix5x"), i_IOCLK0=ClockSignal("pix10x"),
+
+                       i_INC=delay_inc, i_CE=delay_ce,
+                       i_CAL=delay_slave_cal, i_RST=delay_slave_rst, o_BUSY=delay_slave_busy,
+                       i_T=1)
 
                d0 = Signal()
-               d0p = Signal()
                d1 = Signal()
-               d1p = Signal()
+               pd_valid = Signal()
+               pd_incdec = Signal()
+               pd_edge = Signal()
+               pd_cascade = Signal()
                self.specials += Instance("ISERDES2",
-                       Instance.Parameter("BITSLIP_ENABLE", "FALSE"),
-                       Instance.Parameter("DATA_RATE", "SDR"),
-                       Instance.Parameter("DATA_WIDTH", 4),
-                       Instance.Parameter("INTERFACE_TYPE", "RETIMED"),
-                       Instance.Parameter("SERDES_MODE", "NONE"),
-                       Instance.Output("Q4", d0),
-                       Instance.Output("Q3", d0p),
-                       Instance.Output("Q2", d1),
-                       Instance.Output("Q1", d1p),
-                       Instance.Input("BITSLIP", 0),
-                       Instance.Input("CE0", 1),
-                       Instance.Input("CLK0", ClockSignal("pix20x")),
-                       Instance.Input("CLKDIV", ClockSignal("pix5x")),
-                       Instance.Input("D", pad_delayed),
-                       Instance.Input("IOCE", self.serdesstrobe),
-                       Instance.Input("RST", 0)
-               )
-
-               # Phase detector
+                       p_SERDES_MODE="MASTER",
+                       p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR", p_DATA_WIDTH=2,
+                       p_INTERFACE_TYPE="RETIMED",
+
+                       i_D=pad_delayed_master,
+                       o_Q4=d0, o_Q3=d1,
+
+                       i_BITSLIP=0, i_CE0=1, i_RST=0,
+                       i_CLK0=ClockSignal("pix10x"), i_CLKDIV=ClockSignal("pix5x"),
+                       i_IOCE=self.serdesstrobe,
+
+                       o_VALID=pd_valid, o_INCDEC=pd_incdec,
+                       i_SHIFTIN=pd_edge, o_SHIFTOUT=pd_cascade)
+               self.specials += Instance("ISERDES2",
+                       p_SERDES_MODE="SLAVE",
+                       p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR", p_DATA_WIDTH=2,
+                       p_INTERFACE_TYPE="RETIMED",
+
+                       i_D=pad_delayed_slave,
+
+                       i_BITSLIP=0, i_CE0=1, i_RST=0,
+                       i_CLK0=ClockSignal("pix10x"), i_CLKDIV=ClockSignal("pix5x"),
+                       i_IOCE=self.serdesstrobe,
+
+                       i_SHIFTIN=pd_cascade, o_SHIFTOUT=pd_edge)
+
+               # Phase error accumulator
                lateness = Signal(ntbits, reset=2**(ntbits - 1))
                too_late = Signal()
                too_early = Signal()
@@ -74,68 +96,80 @@ class DataCapture(Module, AutoCSR):
                self.sync.pix5x += [
                        If(reset_lateness,
                                lateness.eq(2**(ntbits - 1))
-                       ).Elif(~delay_busy & ~too_late & ~too_early & (d0 != d1),
-                               If(d0,
-                                       # 1 -----> 0
-                                       #    d0p
-                                       If(d0p,
-                                               lateness.eq(lateness - 1)
-                                       ).Else(
-                                               lateness.eq(lateness + 1)
-                                       )
-                               ).Else(
-                                       # 0 -----> 1
-                                       #    d0p
-                                       If(d0p,
-                                               lateness.eq(lateness + 1)
-                                       ).Else(
-                                               lateness.eq(lateness - 1)
-                                       )
-                               )
+                       ).Elif(~delay_master_busy & ~delay_slave_busy & ~too_late & ~too_early,
+                               If(pd_valid &  pd_incdec, lateness.eq(lateness - 1)),
+                               If(pd_valid & ~pd_incdec, lateness.eq(lateness + 1))
                        )
                ]
 
                # Delay control
-               self.submodules.delay_done = PulseSynchronizer("pix5x", "sys")
-               delay_pending = Signal()
+               self.submodules.delay_master_done = PulseSynchronizer("pix5x", "sys")
+               delay_master_pending = Signal()
+               self.sync.pix5x += [
+                       self.delay_master_done.i.eq(0),
+                       If(~delay_master_pending,
+                               If(delay_master_cal | delay_ce, delay_master_pending.eq(1))
+                       ).Else(
+                               If(~delay_master_busy,
+                                       self.delay_master_done.i.eq(1),
+                                       delay_master_pending.eq(0)
+                               )
+                       )
+               ]
+               self.submodules.delay_slave_done = PulseSynchronizer("pix5x", "sys")
+               delay_slave_pending = Signal()
                self.sync.pix5x += [
-                       self.delay_done.i.eq(0),
-                       If(~delay_pending,
-                               If(delay_cal | delay_ce, delay_pending.eq(1))
+                       self.delay_slave_done.i.eq(0),
+                       If(~delay_slave_pending,
+                               If(delay_slave_cal | delay_ce, delay_slave_pending.eq(1))
                        ).Else(
-                               If(~delay_busy,
-                                       self.delay_done.i.eq(1),
-                                       delay_pending.eq(0)
+                               If(~delay_slave_busy,
+                                       self.delay_slave_done.i.eq(1),
+                                       delay_slave_pending.eq(0)
                                )
                        )
                ]
 
-               self.submodules.do_delay_cal = PulseSynchronizer("sys", "pix5x")
-               self.submodules.do_delay_rst = PulseSynchronizer("sys", "pix5x")
+               self.submodules.do_delay_master_cal = PulseSynchronizer("sys", "pix5x")
+               self.submodules.do_delay_master_rst = PulseSynchronizer("sys", "pix5x")
+               self.submodules.do_delay_slave_cal = PulseSynchronizer("sys", "pix5x")
+               self.submodules.do_delay_slave_rst = PulseSynchronizer("sys", "pix5x")
                self.submodules.do_delay_inc = PulseSynchronizer("sys", "pix5x")
                self.submodules.do_delay_dec = PulseSynchronizer("sys", "pix5x")
                self.comb += [
-                       delay_cal.eq(self.do_delay_cal.o),
-                       delay_rst.eq(self.do_delay_rst.o),
+                       delay_master_cal.eq(self.do_delay_master_cal.o),
+                       delay_master_rst.eq(self.do_delay_master_rst.o),
+                       delay_slave_cal.eq(self.do_delay_slave_cal.o),
+                       delay_slave_rst.eq(self.do_delay_slave_rst.o),
                        delay_inc.eq(self.do_delay_inc.o),
                        delay_ce.eq(self.do_delay_inc.o | self.do_delay_dec.o),
                ]
 
-               sys_delay_pending = Signal()
+               sys_delay_master_pending = Signal()
+               self.sync += [
+                       If(self.do_delay_master_cal.i | self.do_delay_inc.i | self.do_delay_dec.i,
+                               sys_delay_master_pending.eq(1)
+                       ).Elif(self.delay_master_done.o,
+                               sys_delay_master_pending.eq(0)
+                       )
+               ]
+               sys_delay_slave_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)
+                       If(self.do_delay_slave_cal.i | self.do_delay_inc.i | self.do_delay_dec.i,
+                               sys_delay_slave_pending.eq(1)
+                       ).Elif(self.delay_slave_done.o,
+                               sys_delay_slave_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.status.eq(sys_delay_pending)
+                       self.do_delay_master_cal.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[0]),
+                       self.do_delay_master_rst.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[1]),
+                       self.do_delay_slave_cal.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[2]),
+                       self.do_delay_slave_rst.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[3]),
+                       self.do_delay_inc.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[4]),
+                       self.do_delay_dec.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[5]),
+                       self._r_dly_busy.status.eq(Cat(sys_delay_master_pending, sys_delay_slave_pending))
                ]
 
                # Phase detector control
@@ -147,12 +181,6 @@ class DataCapture(Module, AutoCSR):
                ]
 
                # 2:10 deserialization
-               d0i = Signal()
-               d1i = Signal()
-               self.comb += [
-                       d0i.eq(d0 ^ invert),
-                       d1i.eq(d1 ^ invert)
-               ]
                dsr = Signal(10)
-               self.sync.pix5x += dsr.eq(Cat(dsr[2:], d1i, d0i))
+               self.sync.pix5x += dsr.eq(Cat(dsr[2:], d1, d0))
                self.sync.pix += self.d.eq(dsr)
index fe3afd36fd5fb5ae3f0097ab0af8fc782007b129..7b0db6eb46b37aa7f349655ffbd39f3eda7ef7de 100644 (file)
 #define DVISAMPLER_TOO_LATE            0x1
 #define DVISAMPLER_TOO_EARLY   0x2
 
-#define DVISAMPLER_DELAY_CAL   0x1
-#define DVISAMPLER_DELAY_RST   0x2
-#define DVISAMPLER_DELAY_INC   0x4
-#define DVISAMPLER_DELAY_DEC   0x8
+#define DVISAMPLER_DELAY_MASTER_CAL    0x01
+#define DVISAMPLER_DELAY_MASTER_RST    0x02
+#define DVISAMPLER_DELAY_SLAVE_CAL     0x04
+#define DVISAMPLER_DELAY_SLAVE_RST     0x08
+#define DVISAMPLER_DELAY_INC           0x10
+#define DVISAMPLER_DELAY_DEC           0x20
 
 #define DVISAMPLER_SLOT_EMPTY  0
 #define DVISAMPLER_SLOT_LOADED 1
index 043f88f4556ac3b1133c3fe15f350de0a349f165..19ebbbf67f42328eab6ddb08d37ae3b514065e44 100644 (file)
@@ -106,14 +106,14 @@ static int wait_idelays(void)
 
 int dvisamplerX_calibrate_delays(void)
 {
-       dvisamplerX_data0_cap_dly_ctl_write(DVISAMPLER_DELAY_CAL);
-       dvisamplerX_data1_cap_dly_ctl_write(DVISAMPLER_DELAY_CAL);
-       dvisamplerX_data2_cap_dly_ctl_write(DVISAMPLER_DELAY_CAL);
+       dvisamplerX_data0_cap_dly_ctl_write(DVISAMPLER_DELAY_MASTER_CAL|DVISAMPLER_DELAY_SLAVE_CAL);
+       dvisamplerX_data1_cap_dly_ctl_write(DVISAMPLER_DELAY_MASTER_CAL|DVISAMPLER_DELAY_SLAVE_CAL);
+       dvisamplerX_data2_cap_dly_ctl_write(DVISAMPLER_DELAY_MASTER_CAL|DVISAMPLER_DELAY_SLAVE_CAL);
        if(!wait_idelays())
                return 0;
-       dvisamplerX_data0_cap_dly_ctl_write(DVISAMPLER_DELAY_RST);
-       dvisamplerX_data1_cap_dly_ctl_write(DVISAMPLER_DELAY_RST);
-       dvisamplerX_data2_cap_dly_ctl_write(DVISAMPLER_DELAY_RST);
+       dvisamplerX_data0_cap_dly_ctl_write(DVISAMPLER_DELAY_MASTER_RST|DVISAMPLER_DELAY_SLAVE_RST);
+       dvisamplerX_data1_cap_dly_ctl_write(DVISAMPLER_DELAY_MASTER_RST|DVISAMPLER_DELAY_SLAVE_RST);
+       dvisamplerX_data2_cap_dly_ctl_write(DVISAMPLER_DELAY_MASTER_RST|DVISAMPLER_DELAY_SLAVE_RST);
        dvisamplerX_data0_cap_phase_reset_write(1);
        dvisamplerX_data1_cap_phase_reset_write(1);
        dvisamplerX_data2_cap_phase_reset_write(1);