forked from M-Labs/artiq-zynq
WRPLL gateware
kasli_soc satellite: add wrpll kasli_soc satellite: add gtx & main tag nFIQ for satellite ddmtd: add DDMTD and deglitcher wrpll: add helper clockdomain wrpll: add frequency counter wrpll: add gtx & main tag collection wrpll: add gtx & main tag eventmanager for shared peripheral interrupt
This commit is contained in:
parent
3972efc61e
commit
90890e39e0
72
src/gateware/ddmtd.py
Normal file
72
src/gateware/ddmtd.py
Normal file
@ -0,0 +1,72 @@
|
||||
from migen import *
|
||||
from migen.genlib.cdc import PulseSynchronizer, MultiReg
|
||||
from migen.genlib.fsm import FSM
|
||||
from misoc.interconnect.csr import *
|
||||
|
||||
|
||||
class DDMTDSampler(Module):
|
||||
def __init__(self, cd_ref, main_dcxo_pads):
|
||||
self.ref_beating = Signal()
|
||||
self.main_beating = Signal()
|
||||
|
||||
# # #
|
||||
|
||||
main_clk_se = Signal()
|
||||
ref_beating_FF = Signal()
|
||||
main_beating_FF = Signal()
|
||||
self.specials += [
|
||||
Instance("IBUFDS",
|
||||
i_I=main_dcxo_pads.p, i_IB=main_dcxo_pads.n,
|
||||
o_O=main_clk_se),
|
||||
# Two back to back FFs are used to prevent metastability
|
||||
Instance("FD", i_C=ClockSignal("helper"),
|
||||
i_D=cd_ref.clk, o_Q=ref_beating_FF),
|
||||
Instance("FD", i_C=ClockSignal("helper"),
|
||||
i_D=ref_beating_FF, o_Q=self.ref_beating),
|
||||
Instance("FD", i_C=ClockSignal("helper"),
|
||||
i_D=main_clk_se, o_Q=main_beating_FF),
|
||||
Instance("FD", i_C=ClockSignal("helper"),
|
||||
i_D=main_beating_FF, o_Q=self.main_beating)
|
||||
]
|
||||
|
||||
|
||||
class DDMTDDeglitcherFirstEdge(Module):
|
||||
def __init__(self, input_signal, blind_period=300):
|
||||
self.detect = Signal()
|
||||
rising = Signal()
|
||||
input_signal_r = Signal()
|
||||
|
||||
# # #
|
||||
|
||||
self.sync.helper += [
|
||||
input_signal_r.eq(input_signal),
|
||||
rising.eq(input_signal & ~input_signal_r)
|
||||
]
|
||||
|
||||
blind_counter = Signal(max=blind_period)
|
||||
self.sync.helper += [
|
||||
If(blind_counter != 0, blind_counter.eq(blind_counter - 1)),
|
||||
If(input_signal_r, blind_counter.eq(blind_period - 1)),
|
||||
self.detect.eq(rising & (blind_counter == 0))
|
||||
]
|
||||
|
||||
|
||||
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 = DDMTDDeglitcherFirstEdge(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(counter)
|
||||
)
|
||||
]
|
@ -26,6 +26,7 @@ import analyzer
|
||||
import acpki
|
||||
import drtio_aux_controller
|
||||
import zynq_clocking
|
||||
import wrpll
|
||||
import si549
|
||||
from config import write_csr_file, write_mem_file, write_rustc_cfg_file
|
||||
|
||||
@ -555,6 +556,14 @@ class GenericSatellite(SoCCore):
|
||||
if with_wrpll:
|
||||
self.submodules.main_dcxo = si549.Si549(platform.request("ddmtd_main_dcxo_i2c"))
|
||||
self.submodules.helper_dcxo = si549.Si549(platform.request("ddmtd_helper_dcxo_i2c"))
|
||||
self.submodules.wrpll = wrpll.WRPLL(
|
||||
cd_ref=self.gt_drtio.cd_rtio_rx0,
|
||||
main_dcxo_pads=platform.request("cdr_clk_clean_fabric"),
|
||||
helper_dcxo_pads=platform.request("ddmtd_helper_clk"))
|
||||
self.csr_devices.append("main_dcxo")
|
||||
self.csr_devices.append("helper_dcxo")
|
||||
self.csr_devices.append("wrpll")
|
||||
self.comb += self.ps7.core.core0.nfiq.eq(self.wrpll.ev.irq)
|
||||
self.config["HAS_SI549"] = None
|
||||
else:
|
||||
self.submodules.siphaser = SiPhaser7Series(
|
||||
|
126
src/gateware/wrpll.py
Normal file
126
src/gateware/wrpll.py
Normal file
@ -0,0 +1,126 @@
|
||||
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(reset=1)
|
||||
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)
|
Loading…
Reference in New Issue
Block a user