artiq-zynq/src/gateware/ddmtd.py

119 lines
3.7 KiB
Python

from migen import *
from migen.genlib.cdc import PulseSynchronizer, MultiReg
from misoc.interconnect.csr import *
class DDMTDSampler(Module):
def __init__(self, cd_ref, main_clk_se):
self.ref_beating = Signal()
self.main_beating = Signal()
# # #
ref_clk = Signal()
self.specials +=[
# ISERDESE2 can only be driven from fabric via IDELAYE2 (see UG471)
Instance("IDELAYE2",
p_DELAY_SRC="DATAIN",
p_HIGH_PERFORMANCE_MODE="TRUE",
p_REFCLK_FREQUENCY=208.3, # REFCLK frequency from IDELAYCTRL
p_IDELAY_VALUE=0,
i_DATAIN=cd_ref.clk,
o_DATAOUT=ref_clk
),
Instance("ISERDESE2",
p_IOBDELAY="IFD", # use DDLY as input
p_DATA_RATE="SDR",
p_DATA_WIDTH=2, # min is 2
p_NUM_CE=1,
i_DDLY=ref_clk,
i_CE1=1,
i_CLK=ClockSignal("helper"),
i_CLKDIV=ClockSignal("helper"),
o_Q1=self.ref_beating
),
Instance("ISERDESE2",
p_DATA_RATE="SDR",
p_DATA_WIDTH=2, # min is 2
p_NUM_CE=1,
i_D=main_clk_se,
i_CE1=1,
i_CLK=ClockSignal("helper"),
i_CLKDIV=ClockSignal("helper"),
o_Q1=self.main_beating,
),
]
class DDMTDDeglitcherMedianEdge(Module):
def __init__(self, counter, input_signal, stable_0_period=100, stable_1_period=100):
self.tag = Signal(len(counter))
self.detect = Signal()
stable_0_counter = Signal(reset=stable_0_period - 1, max=stable_0_period)
stable_1_counter = Signal(reset=stable_1_period - 1, max=stable_1_period)
# # #
# Based on CERN's median edge deglitcher FSM
# https://white-rabbit.web.cern.ch/documents/Precise_time_and_frequency_transfer_in_a_White_Rabbit_network.pdf (p.72)
fsm = ClockDomainsRenamer("helper")(FSM(reset_state="WAIT_STABLE_0"))
self.submodules += fsm
fsm.act("WAIT_STABLE_0",
If(stable_0_counter != 0,
NextValue(stable_0_counter, stable_0_counter - 1)
).Else(
NextValue(stable_0_counter, stable_0_period - 1),
NextState("WAIT_EDGE")
),
If(input_signal,
NextValue(stable_0_counter, stable_0_period - 1)
),
)
fsm.act("WAIT_EDGE",
If(input_signal,
NextValue(self.tag, counter),
NextState("GOT_EDGE")
)
)
fsm.act("GOT_EDGE",
If(stable_1_counter != 0,
NextValue(stable_1_counter, stable_1_counter - 1)
).Else(
NextValue(stable_1_counter, stable_1_period - 1),
self.detect.eq(1),
NextState("WAIT_STABLE_0")
),
If(~input_signal,
NextValue(self.tag, self.tag + 1),
NextValue(stable_1_counter, stable_1_period - 1)
),
)
class DDMTD(Module):
def __init__(self, counter, input_signal):
# in helper clock domain
self.h_tag = Signal(len(counter))
self.h_tag_update = Signal()
# # #
deglitcher = DDMTDDeglitcherMedianEdge(counter, input_signal)
self.submodules += deglitcher
self.sync.helper += [
self.h_tag_update.eq(0),
If(deglitcher.detect,
self.h_tag_update.eq(1),
self.h_tag.eq(deglitcher.tag)
)
]