From 6cef4187563d5fede8f05567dd5ce789a97012bf Mon Sep 17 00:00:00 2001 From: linuswck Date: Fri, 8 Nov 2024 12:35:13 +0800 Subject: [PATCH] gateware: Add CSR Ctrl to PL's MMCM - Generate 45 Degree Phase Shifted DDR Clock - PLLE2_Base -> MMCM_ADV for ddr clock dynamic phase shift - Add mmcm_rst, ddr_clk_ps, mmcm_locked status to CSR - Generate dco2d rst signal from mmcm and connect to the related logic --- fast-servo/linien-gateware/cores/adc.py | 57 +++++++++++++++++++------ fast-servo/linien-gateware/cores/dac.py | 34 +++++++-------- 2 files changed, 60 insertions(+), 31 deletions(-) diff --git a/fast-servo/linien-gateware/cores/adc.py b/fast-servo/linien-gateware/cores/adc.py index 75d7837..ff66003 100644 --- a/fast-servo/linien-gateware/cores/adc.py +++ b/fast-servo/linien-gateware/cores/adc.py @@ -22,11 +22,12 @@ from migen.genlib.cdc import MultiReg from misoc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage -class _CRG(Module): +class CRG(Module): def __init__(self, platform, dco_clk, dco_freq=200e6): self.clock_domains.cd_dco = ClockDomain() self.clock_domains.cd_dco2x = ClockDomain() self.clock_domains.cd_dco2d = ClockDomain() + self.clock_domains.cd_dco2d_45_degree = ClockDomain() dco_clk_p, dco_clk_n = dco_clk dco_clk_buf = Signal() @@ -41,59 +42,83 @@ class _CRG(Module): clk_dco = Signal() clk_dco2x = Signal() clk_dco2d = Signal() + clk_dco2d_45_degree = Signal() + mmcm_ps_psdone = Signal() + self.locked = Signal() + self.mmcm_rst = Signal() + self.ddr_clk_phase_shift_en = Signal() + self.ddr_clk_phase_incdec = Signal() platform.add_period_constraint(dco_clk_p, 1e9 / dco_freq) self.specials += [ Instance( - "PLLE2_BASE", + "MMCME2_ADV", p_BANDWIDTH="OPTIMIZED", p_DIVCLK_DIVIDE=1, p_CLKFBOUT_PHASE=0.0, - p_CLKFBOUT_MULT=4, # VCO @ 800 MHz + p_CLKFBOUT_MULT_F=4, # VCO @ 800 MHz p_CLKIN1_PERIOD=(1e9 / dco_freq), p_REF_JITTER1=0.01, p_STARTUP_WAIT="FALSE", i_CLKIN1=dco_clk_buf, i_PWRDWN=0, - i_RST=ResetSignal("sys"), + i_RST=ResetSignal("sys") | self.mmcm_rst, i_CLKFBIN=clk_feedback_buf, o_CLKFBOUT=clk_feedback, - p_CLKOUT0_DIVIDE=4, - p_CLKOUT0_PHASE=0.0, + + p_CLKOUT0_USE_FINE_PS="TRUE", + p_CLKOUT0_DIVIDE_F=8, + p_CLKOUT0_PHASE=45.0, p_CLKOUT0_DUTY_CYCLE=0.5, - o_CLKOUT0=clk_dco, # 200 MHz <- dco_clk + o_CLKOUT0=clk_dco2d_45_degree, # 100 MHz <- dco_clk / 2 = 200 MHz / 2 + o_LOCKED=self.locked, + p_CLKOUT1_DIVIDE=2, p_CLKOUT1_PHASE=0.0, p_CLKOUT1_DUTY_CYCLE=0.5, o_CLKOUT1=clk_dco2x, # 400 MHZ <- 2 * dco_clk = 2*200 MHz + p_CLKOUT2_DIVIDE=8, p_CLKOUT2_PHASE=0.0, p_CLKOUT2_DUTY_CYCLE=0.5, o_CLKOUT2=clk_dco2d, # 100 MHz <- dco_clk / 2 = 200 MHz / 2 - o_LOCKED=self.locked, + + p_CLKOUT3_DIVIDE=4, + p_CLKOUT3_PHASE=0.0, + p_CLKOUT3_DUTY_CYCLE=0.5, + o_CLKOUT3=clk_dco, # 200 MHz <- dco_clk + + i_PSCLK=ClockSignal(), + i_PSEN=self.ddr_clk_phase_shift_en, + i_PSINCDEC=self.ddr_clk_phase_incdec, + o_PSDONE=mmcm_ps_psdone, ) ] self.specials += Instance("BUFG", i_I=clk_feedback, o_O=clk_feedback_buf) self.specials += Instance("BUFG", i_I=clk_dco, o_O=self.cd_dco.clk) self.specials += Instance("BUFG", i_I=clk_dco2d, o_O=self.cd_dco2d.clk) + self.specials += Instance("BUFG", i_I=clk_dco2d_45_degree, o_O=self.cd_dco2d_45_degree.clk) self.specials += Instance("BUFG", i_I=clk_dco2x, o_O=self.cd_dco2x.clk) + # Ignore dco2d to mmcm dco_clk path created by SoC's rst. + platform.add_false_path_constraints(self.cd_dco2d.clk, dco_clk_buf) + self.specials += Instance("FD", p_INIT=1, i_D=~self.locked, i_C=self.cd_dco2d.clk, o_Q=self.cd_dco2d.rst) class ADC(Module, AutoCSR): def __init__(self, platform, dco_freq=200e6): adc_pads = platform.request("adc") afe_pads = platform.request("adc_afe") - self.frame_csr = CSRStatus(4) + self.frame_csr = CSRStatus(5) self.data_ch0 = CSRStatus(16) self.data_ch1 = CSRStatus(16) self.tap_delay = CSRStorage(5) self.bitslip_csr = CSRStorage(1) - self.afe_ctrl = CSRStorage(4) + self.afe_ctrl = CSRStorage(7) tap_delay_val = Signal(5) bitslip = Signal() @@ -117,11 +142,14 @@ class ADC(Module, AutoCSR): # dco_clk.n.eq(adc_pads.dco_n), tap_delay_val.eq(self.tap_delay.storage), Cat(ch1_gain_x10, ch2_gain_x10, ch1_shdn, ch2_shdn).eq( - self.afe_ctrl.storage + self.afe_ctrl.storage[0:4] ), ] - self.submodules._crg = _CRG(platform, dco_clk, dco_freq) + self.submodules.crg = CRG(platform, dco_clk, dco_freq) + self.comb += self.afe_ctrl.storage[4].eq(self.crg.mmcm_rst) + self.comb += self.afe_ctrl.storage[5].eq(self.crg.ddr_clk_phase_shift_en) + self.comb += self.afe_ctrl.storage[6].eq(self.crg.ddr_clk_phase_incdec) self.specials += MultiReg(self.bitslip_csr.re, bitslip_re_dco_2d, "dco2d") self.sync.dco2d += [ @@ -129,7 +157,8 @@ class ADC(Module, AutoCSR): ] self.comb += [ - self.frame_csr.status.eq(self.s_frame), + self.frame_csr.status[0:4].eq(self.s_frame[0:4]), + self.frame_csr.status[4].eq(self.crg.locked), self.data_ch0.status.eq(self.data_out[0]), self.data_ch1.status.eq(self.data_out[1]), ] @@ -146,7 +175,7 @@ class ADC(Module, AutoCSR): self.specials += Instance( "LTC2195", - i_rst_in=ResetSignal("sys"), + i_rst_in=ResetSignal("dco2d"), i_clk200=ClockSignal("idelay"), i_DCO=ClockSignal("dco"), i_DCO_2D=ClockSignal("dco2d"), diff --git a/fast-servo/linien-gateware/cores/dac.py b/fast-servo/linien-gateware/cores/dac.py index 9090ad4..993b062 100644 --- a/fast-servo/linien-gateware/cores/dac.py +++ b/fast-servo/linien-gateware/cores/dac.py @@ -42,7 +42,7 @@ class DAC(Module, AutoCSR): self.comb += [ Cat(manual_override, ch0_pd, ch1_pd).eq(self.dac_ctrl.storage), - dac_pads.rst.eq(ResetSignal("sys")), + dac_pads.rst.eq(ResetSignal("dco2d")), dac_afe_pads.ch1_pd_n.eq(~ch0_pd), dac_afe_pads.ch2_pd_n.eq(~ch1_pd), output_data_ch0.eq( @@ -53,22 +53,22 @@ class DAC(Module, AutoCSR): ), ] - # data - for lane in range(14): - self.specials += DDROutput( - i1 = output_data_ch0[lane], - i2 = output_data_ch1[lane], - o = dac_pads.data[lane], - clk = ClockSignal("dco2d") - ) - - # clock forwarding - self.specials += DDROutput( - i1 = 0b0, - i2 = 0b1, - o = dac_pads.dclkio, - clk = ClockSignal("dco2d"), - ) + self.specials += [ + Instance("ODDR", + i_C=ClockSignal("dco2d"), + i_CE=~ResetSignal("dco2d"), + i_D1=output_data_ch0[lane], # DDR CLK Rising Edge + i_D2=output_data_ch1[lane], # DDR CLK Falling Edge + o_Q=dac_pads.data[lane], + p_DDR_CLK_EDGE="SAME_EDGE") + for lane in range(14)] + self.specials += Instance("ODDR", + i_C=ClockSignal("dco2d_45_degree"), + i_CE=~ResetSignal("dco2d"), + i_D1=0, + i_D2=1, + o_Q=dac_pads.dclkio, + p_DDR_CLK_EDGE="SAME_EDGE") class AUX_DAC_CTRL(Module, AutoCSR):