diff --git a/litex/soc/cores/clock/__init__.py b/litex/soc/cores/clock/__init__.py index ce6473668..72fc8c75c 100644 --- a/litex/soc/cores/clock/__init__.py +++ b/litex/soc/cores/clock/__init__.py @@ -12,7 +12,7 @@ from litex.soc.cores.clock.intel_cyclone10 import Cyclone10LPPLL # Lattice from litex.soc.cores.clock.lattice_ice40 import iCE40PLL -from litex.soc.cores.clock.lattice_ecp5 import ECP5PLL, ECP5Delay +from litex.soc.cores.clock.lattice_ecp5 import ECP5PLL, ECP5DynamicDelay from litex.soc.cores.clock.lattice_nx import NXOSCA, NXPLL # Efinix diff --git a/litex/soc/cores/clock/lattice_ecp5.py b/litex/soc/cores/clock/lattice_ecp5.py index 4c0f704e9..1bf613199 100644 --- a/litex/soc/cores/clock/lattice_ecp5.py +++ b/litex/soc/cores/clock/lattice_ecp5.py @@ -10,7 +10,7 @@ from migen.genlib.resetsync import AsyncResetSynchronizer from litex.soc.cores.clock.common import * -# Lattice / ECP5 ----------------------------------------------------------------------------------- +# Lattice / ECP5 PLL ------------------------------------------------------------------------------- class ECP5PLL(Module): nclkouts_max = 4 @@ -166,50 +166,60 @@ class ECP5PLL(Module): self.params["attr"].append((f"FREQUENCY_PIN_CLKO{n_to_l[n]}", str(f/1e6))) self.specials += Instance("EHXPLLL", **self.params) +# Lattice / ECP5 Dynamic Delay --------------------------------------------------------------------- -class ECP5Delay(Module): - # from ECP5 docs - delay_step_s = 25e-12 - n_steps = 128 +class ECP5DynamicDelay(Module): + tap_delay = 25e-12 + ntaps = 128 - def __init__(self): - self.i = Signal() - self.o = Signal() - self.value = Signal(max=self.n_steps) + def __init__(self, i=None, o=None, taps=None): + self.i = Signal() if i is None else i + self.o = Signal() if o is None else o + self.taps = Signal(max=self.ntaps) if taps is None else taps - def do_finalize(self): - rst = Signal() - move = Signal() - current_value = Signal(max=self.n_steps) + # # # - self.specials += Instance( - "DELAYF", - p_DEL_MODE="USER_DEFINED", - p_DEL_VALUE=self.value.reset, - i_A=self.i, - o_Z=self.o, - i_LOADN=~(ResetSignal() | rst), - i_MOVE=move, - i_DIRECTION=0, - o_CFLAG=Signal() + rst = Signal() + move = Signal() + done = Signal() + change = Signal() + curr_taps = Signal(max=self.ntaps) + + # DELAYF Instance. + self.specials += Instance("DELAYF", + p_DEL_MODE = "USER_DEFINED", + p_DEL_VALUE = self.taps.reset, + i_A = self.i, + o_Z = self.o, + i_LOADN = ~(ResetSignal() | rst), + i_MOVE = move, + i_DIRECTION = 0, + o_CFLAG = Signal() ) - self.submodules.fsm = fsm = FSM() - fsm.act("WAIT", - If(self.value != current_value, - NextState('RST')) + # FSM. + self.comb += done.eq( self.taps == curr_taps) + self.comb += change.eq(self.taps != curr_taps) + self.submodules.fsm = fsm = FSM(reset_state="IDLE") + fsm.act("IDLE", + If(change, + NextState("DELAYF-RST") + ) + ) + fsm.act("DELAYF-RST", + rst.eq(1), + NextValue(move, 0), + NextValue(curr_taps, 0), + NextState("DELAYF-MOVE") + ) + fsm.act("DELAYF-MOVE", + If(done, + NextValue(move, 0), + NextState("IDLE") + ).Else( + NextValue(move, ~move), + If(move, + NextValue(curr_taps, curr_taps + 1) ) - fsm.act("RST", - rst.eq(1), - NextValue(current_value, 0), - NextState("MOVE") - ) - fsm.act("MOVE", - If(current_value == self.value, - NextValue(move, 0), - NextState("WAIT") - ).Else( - NextValue(move, ~move), - If(move, - NextValue(current_value, current_value + 1)), - )) + ) + ) diff --git a/test/test_clock.py b/test/test_clock.py index ed5f58ae5..1e4128a2e 100644 --- a/test/test_clock.py +++ b/test/test_clock.py @@ -130,8 +130,9 @@ class TestClock(unittest.TestCase): pll.create_clkout(ClockDomain("clkout4"), 175e6) pll.compute_config() - def test_ecp5_delay(self): - delay = ECP5Delay() + def test_ecp5_dynamic_delay(self): + delay = ECP5DynamicDelay(i=Signal(), o=Signal(), taps=Signal(7)) + delay = ECP5DynamicDelay() # Lattice / NX def test_nxpll(self):