From: Sebastien Bourdeauducq Date: Sat, 14 Sep 2013 15:14:20 +0000 (+0200) Subject: dvisampler: use hard differential phase detector X-Git-Tag: 24jan2021_ls180~2837 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=ffe4bff396f74e50317e526ca9459c5ea4c19053;p=litex.git dvisampler: use hard differential phase detector --- diff --git a/milkymist/dvisampler/__init__.py b/milkymist/dvisampler/__init__.py index a752f1a3..c0227c12 100644 --- a/milkymist/dvisampler/__init__.py +++ b/milkymist/dvisampler/__init__.py @@ -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), diff --git a/milkymist/dvisampler/clocking.py b/milkymist/dvisampler/clocking.py index 9e261d05..9fcad685 100644 --- a/milkymist/dvisampler/clocking.py +++ b/milkymist/dvisampler/clocking.py @@ -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) diff --git a/milkymist/dvisampler/datacapture.py b/milkymist/dvisampler/datacapture.py index 8cb060c7..50a92e44 100644 --- a/milkymist/dvisampler/datacapture.py +++ b/milkymist/dvisampler/datacapture.py @@ -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) diff --git a/software/include/hw/flags.h b/software/include/hw/flags.h index fe3afd36..7b0db6eb 100644 --- a/software/include/hw/flags.h +++ b/software/include/hw/flags.h @@ -25,10 +25,12 @@ #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 diff --git a/software/videomixer/dvisamplerX.c b/software/videomixer/dvisamplerX.c index 043f88f4..19ebbbf6 100644 --- a/software/videomixer/dvisamplerX.c +++ b/software/videomixer/dvisamplerX.c @@ -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);