1
0
Fork 0
artiq-zynq/src/gateware/wrpll.py

186 lines
6.2 KiB
Python

from migen import *
from migen.genlib.cdc import MultiReg, AsyncResetSynchronizer, PulseSynchronizer
from misoc.interconnect.csr import *
from misoc.interconnect.csr_eventmanager import *
from ddmtd import DDMTDSampler, DDMTD
class FrequencyCounter(Module, AutoCSR):
def __init__(self, domains, counter_width=24):
for domain in domains:
name = "counter_" + domain
counter = CSRStatus(counter_width, name=name)
setattr(self, name, counter)
self.update_en = CSRStorage()
timer = Signal(counter_width)
timer_tick = Signal()
self.sync += Cat(timer, timer_tick).eq(timer + 1)
for domain in domains:
sync_domain = getattr(self.sync, domain)
divider = Signal(2)
sync_domain += divider.eq(divider + 1)
divided = Signal()
sync_domain += divided.eq(divider[-1])
divided_sys = Signal()
self.specials += MultiReg(divided, divided_sys)
divided_sys_r = Signal()
divided_tick = Signal()
self.sync += divided_sys_r.eq(divided_sys)
self.comb += divided_tick.eq(divided_sys & ~divided_sys_r)
counter = Signal(counter_width)
counter_csr = getattr(self, "counter_" + domain)
self.sync += [
If(timer_tick,
If(self.update_en.storage, counter_csr.status.eq(counter)),
counter.eq(0),
).Else(
If(divided_tick, counter.eq(counter + 1))
)
]
class WRPLL(Module, AutoCSR):
def __init__(self, cd_ref, main_dcxo_pads, helper_dcxo_pads, COUNTER_BIT=32):
self.ref_tag = CSRStatus(COUNTER_BIT)
self.main_tag = CSRStatus(COUNTER_BIT)
ddmtd_counter = Signal(COUNTER_BIT)
ref_tag_sys = Signal(COUNTER_BIT)
main_tag_sys = Signal(COUNTER_BIT)
ref_tag_stb_sys = Signal()
main_tag_stb_sys = Signal()
# # #
self.helper_reset = CSRStorage()
self.clock_domains.cd_helper = ClockDomain()
self.specials += [
Instance("IBUFGDS",
i_I=helper_dcxo_pads.p, i_IB=helper_dcxo_pads.n,
o_O=self.cd_helper.clk),
AsyncResetSynchronizer(self.cd_helper, self.helper_reset.storage)
]
self.submodules.frequency_counter = FrequencyCounter(["sys", cd_ref.name])
self.submodules.ddmtd_sampler = DDMTDSampler(cd_ref, main_dcxo_pads)
self.sync.helper += ddmtd_counter.eq(ddmtd_counter + 1)
self.submodules.ddmtd_ref = DDMTD(ddmtd_counter, self.ddmtd_sampler.ref_beating)
self.submodules.ddmtd_main = DDMTD(ddmtd_counter, self.ddmtd_sampler.main_beating)
# DDMTD tags collection
self.specials += [
MultiReg(self.ddmtd_ref.h_tag, ref_tag_sys),
MultiReg(self.ddmtd_main.h_tag, main_tag_sys)
]
ref_tag_stb_ps = PulseSynchronizer("helper", "sys")
main_tag_stb_ps = PulseSynchronizer("helper", "sys")
self.submodules += [
ref_tag_stb_ps,
main_tag_stb_ps
]
self.sync.helper += [
ref_tag_stb_ps.i.eq(self.ddmtd_ref.h_tag_update),
main_tag_stb_ps.i.eq(self.ddmtd_main.h_tag_update)
]
self.sync += [
ref_tag_stb_sys.eq(ref_tag_stb_ps.o),
main_tag_stb_sys.eq(main_tag_stb_ps.o)
]
self.sync += [
If(ref_tag_stb_sys,
self.ref_tag.status.eq(ref_tag_sys),
),
If(main_tag_stb_sys,
self.main_tag.status.eq(main_tag_sys)
)
]
# PL->PS interrupt
self.submodules.ref_tag_ev = EventManager()
self.ref_tag_ev.stb = EventSourcePulse()
self.ref_tag_ev.finalize()
self.submodules.main_tag_ev = EventManager()
self.main_tag_ev.stb = EventSourcePulse()
self.main_tag_ev.finalize()
self.sync += [
self.ref_tag_ev.stb.trigger.eq(ref_tag_stb_sys),
self.main_tag_ev.stb.trigger.eq(main_tag_stb_sys)
]
self.submodules.ev = SharedIRQ(self.ref_tag_ev, self.main_tag_ev)
class SMAFrequencyMultiplier(Module, AutoCSR):
def __init__(self, sma_clkin):
freq = 125e6
period = 1e9/freq # ns
sma_clkin_se = Signal()
mmcm_locked = Signal()
mmcm_fb_clk = Signal()
ref_clk = Signal()
self.clock_domains.cd_ref = ClockDomain()
self.mmcm_locked = CSRStatus()
self.mmcm_reset = CSRStorage()
self.mmcm_daddr = CSRStorage(7)
self.mmcm_din = CSRStorage(16)
self.mmcm_dwen = CSRStorage()
self.mmcm_den = CSRStorage()
self.mmcm_dclk = CSRStorage()
self.mmcm_dout = CSRStatus(16)
self.mmcm_dready = CSRStatus()
# # #
self.specials += [
Instance("IBUFDS",
i_I=sma_clkin.p, i_IB=sma_clkin.n,
o_O=sma_clkin_se),
# MMCME2 is capable to accept 10Mhz input while PLLE2 only support down to 19Mhz input (DS191)
Instance("MMCME2_ADV",
p_BANDWIDTH="LOW", # lower jitter
o_LOCKED=self.mmcm_locked.status,
i_RST=self.mmcm_reset.storage,
p_CLKIN1_PERIOD=period,
i_CLKIN1=sma_clkin_se,
i_CLKINSEL=1, # 1=CLKIN1 0=CLKIN2
# VCO @ 1.25Ghz
p_CLKFBOUT_MULT_F=10, p_DIVCLK_DIVIDE=1,
i_CLKFBIN=mmcm_fb_clk, o_CLKFBOUT=mmcm_fb_clk,
# 125Mhz for WRPLL
p_CLKOUT0_DIVIDE_F=10, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=ref_clk,
# Dynamic Reconfiguration Port
i_DADDR = self.mmcm_daddr.storage,
i_DI = self.mmcm_din.storage,
i_DWE = self.mmcm_dwen.storage,
i_DEN = self.mmcm_den.storage,
i_DCLK = self.mmcm_dclk.storage,
o_DO = self.mmcm_dout.status,
o_DRDY = self.mmcm_dready.status
),
Instance("BUFG", i_I=ref_clk, o_O=self.cd_ref.clk),
AsyncResetSynchronizer(self.cd_ref, ~self.mmcm_locked.status),
]