forked from M-Labs/artiq-zynq
155 lines
5.0 KiB
Python
155 lines
5.0 KiB
Python
from migen import *
|
|
from migen.genlib.cdc import MultiReg
|
|
from migen.genlib.resetsync import AsyncResetSynchronizer
|
|
from misoc.interconnect.csr import *
|
|
|
|
|
|
class ClockSwitchFSM(Module):
|
|
def __init__(self):
|
|
self.i_clk_sw = Signal()
|
|
|
|
self.o_clk_sw = Signal()
|
|
self.o_reset = Signal()
|
|
|
|
###
|
|
|
|
i_switch = Signal()
|
|
o_switch = Signal()
|
|
reset = Signal()
|
|
|
|
# at 125MHz bootstrap cd, will get around 0.5ms
|
|
delay_counter = Signal(16, reset=0xFFFF)
|
|
|
|
# register to prevent glitches
|
|
self.sync.bootstrap += [
|
|
self.o_clk_sw.eq(o_switch),
|
|
self.o_reset.eq(reset),
|
|
]
|
|
|
|
self.o_clk_sw.attr.add("no_retiming")
|
|
self.o_reset.attr.add("no_retiming")
|
|
self.i_clk_sw.attr.add("no_retiming")
|
|
i_switch.attr.add("no_retiming")
|
|
|
|
self.specials += MultiReg(self.i_clk_sw, i_switch, "bootstrap")
|
|
|
|
fsm = ClockDomainsRenamer("bootstrap")(FSM(reset_state="START"))
|
|
|
|
self.submodules += fsm
|
|
|
|
fsm.act("START",
|
|
If(i_switch & ~o_switch,
|
|
NextState("RESET_START"))
|
|
)
|
|
|
|
fsm.act("RESET_START",
|
|
reset.eq(1),
|
|
If(delay_counter == 0,
|
|
NextValue(delay_counter, 0xFFFF),
|
|
NextState("CLOCK_SWITCH")
|
|
).Else(
|
|
NextValue(delay_counter, delay_counter-1),
|
|
)
|
|
)
|
|
|
|
fsm.act("CLOCK_SWITCH",
|
|
reset.eq(1),
|
|
NextValue(o_switch, 1),
|
|
NextValue(delay_counter, delay_counter-1),
|
|
If(delay_counter == 0,
|
|
NextState("END"))
|
|
)
|
|
fsm.act("END",
|
|
NextValue(o_switch, 1),
|
|
reset.eq(0))
|
|
|
|
|
|
class SYSCRG(Module, AutoCSR):
|
|
def __init__(self, platform, ps7, main_clk, clk_sw=None, clk_sw_status=None, freq=125e6, ext_async_rst=None, ):
|
|
# assumes bootstrap clock is same freq as main and sys output
|
|
self.clock_domains.cd_sys = ClockDomain()
|
|
self.clock_domains.cd_sys4x = ClockDomain(reset_less=True)
|
|
self.clock_domains.cd_sys5x = ClockDomain(reset_less=True)
|
|
self.clock_domains.cd_clk200 = ClockDomain()
|
|
|
|
self.current_clock = CSRStatus()
|
|
|
|
self.cd_sys.clk.attr.add("keep")
|
|
|
|
bootstrap_clk = ClockSignal("bootstrap")
|
|
|
|
period = 1e9/freq
|
|
|
|
self.submodules.clk_sw_fsm = ClockSwitchFSM()
|
|
|
|
if clk_sw is None:
|
|
self.clock_switch = CSRStorage()
|
|
self.comb += self.clk_sw_fsm.i_clk_sw.eq(self.clock_switch.storage)
|
|
else:
|
|
self.comb += self.clk_sw_fsm.i_clk_sw.eq(clk_sw)
|
|
|
|
self.mmcm_locked = Signal()
|
|
mmcm_sys = Signal()
|
|
mmcm_sys4x = Signal()
|
|
mmcm_sys5x = Signal()
|
|
mmcm_clk208 = Signal()
|
|
mmcm_fb_clk = Signal()
|
|
self.specials += [
|
|
Instance("MMCME2_ADV",
|
|
p_STARTUP_WAIT="FALSE", o_LOCKED=self.mmcm_locked,
|
|
p_BANDWIDTH="HIGH",
|
|
p_REF_JITTER1=0.001,
|
|
p_CLKIN1_PERIOD=period, i_CLKIN1=main_clk,
|
|
p_CLKIN2_PERIOD=period, i_CLKIN2=bootstrap_clk,
|
|
i_CLKINSEL=self.clk_sw_fsm.o_clk_sw,
|
|
|
|
# VCO @ 1.25GHz
|
|
p_CLKFBOUT_MULT_F=10, p_DIVCLK_DIVIDE=1,
|
|
i_CLKFBIN=mmcm_fb_clk,
|
|
i_RST=self.clk_sw_fsm.o_reset,
|
|
|
|
o_CLKFBOUT=mmcm_fb_clk,
|
|
|
|
p_CLKOUT0_DIVIDE_F=2.5, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=mmcm_sys4x,
|
|
|
|
# 125MHz
|
|
p_CLKOUT1_DIVIDE=10, p_CLKOUT1_PHASE=0.0, o_CLKOUT1=mmcm_sys,
|
|
|
|
# 625MHz
|
|
p_CLKOUT2_DIVIDE=2, p_CLKOUT2_PHASE=0.0, o_CLKOUT2=mmcm_sys5x,
|
|
|
|
# 208MHz
|
|
p_CLKOUT3_DIVIDE=6, p_CLKOUT3_PHASE=0.0, o_CLKOUT3=mmcm_clk208,
|
|
),
|
|
Instance("BUFG", i_I=mmcm_sys5x, o_O=self.cd_sys5x.clk),
|
|
Instance("BUFG", i_I=mmcm_sys, o_O=self.cd_sys.clk),
|
|
Instance("BUFG", i_I=mmcm_sys4x, o_O=self.cd_sys4x.clk),
|
|
Instance("BUFG", i_I=mmcm_clk208, o_O=self.cd_clk200.clk),
|
|
]
|
|
|
|
if ext_async_rst is not None:
|
|
self.specials += [
|
|
AsyncResetSynchronizer(self.cd_sys, ~self.mmcm_locked | ext_async_rst),
|
|
AsyncResetSynchronizer(self.cd_clk200, ~self.mmcm_locked | ext_async_rst),
|
|
]
|
|
else:
|
|
self.specials += [
|
|
AsyncResetSynchronizer(self.cd_sys, ~self.mmcm_locked),
|
|
AsyncResetSynchronizer(self.cd_clk200, ~self.mmcm_locked),
|
|
]
|
|
|
|
reset_counter = Signal(4, reset=15)
|
|
ic_reset = Signal(reset=1)
|
|
self.sync.clk200 += \
|
|
If(reset_counter != 0,
|
|
reset_counter.eq(reset_counter - 1)
|
|
).Else(
|
|
ic_reset.eq(0)
|
|
)
|
|
self.specials += Instance("IDELAYCTRL", i_REFCLK=ClockSignal("clk200"), i_RST=ic_reset)
|
|
|
|
if clk_sw_status is None:
|
|
self.comb += self.current_clock.status.eq(self.clk_sw_fsm.o_clk_sw)
|
|
else:
|
|
self.comb += self.current_clock.status.eq(clk_sw_status)
|