Skip to content

Commit

Permalink
Merge pull request #1627 from trabucayre/CC_PLL
Browse files Browse the repository at this point in the history
soc/cores/clock: adding CologneChip CC_PLL
  • Loading branch information
enjoy-digital authored Oct 5, 2023
2 parents ffc38c0 + 5fd5195 commit 2d1072b
Showing 1 changed file with 151 additions and 0 deletions.
151 changes: 151 additions & 0 deletions litex/soc/cores/clock/colognechip.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#
# This file is part of LiteX.
#
# Copyright (c) 2023 Gwenhael Goavec-merou<[email protected]>
# SPDX-License-Identifier: BSD-2-Clause

from migen import *
from migen.genlib.resetsync import AsyncResetSynchronizer

from litex.gen import *

from litex.soc.cores.clock.common import *

# CologneChip GateMate CC_PLL ---------------------------------------------------------------------

class GateMatePLL(LiteXModule):
"""
CC_PLL generator for CologneChip GateMate FPGAs (UG1001 7.3)
Parameters
----------
perf_mode: str
FPGA operation mode for VDD_PLL (UNDEFINED, LOWPOWER, ECONOMY, SPEED) (default: UNDEFINED)
low_jitter: int
Low Jitter Mode (0,1) (default: 1)
lock_req: int
Lock status required before PLL output enable (0,1) (default: 0)
Attributes
----------
reset: Signal in
locked: Signal out
"""

def __init__(self,
perf_mode = "undefined",
low_jitter = 1,
lock_req = 0):

assert perf_mode.lower() in ["undefined", "lowpower", "economy", "speed"]
assert low_jitter in [0, 1]
assert lock_req in [0, 1]

self.logger = logging.getLogger("CC_PLL")
self.reset = Signal()
self.locked = Signal()
self._clkin_freq = None
self._clkouts = {}
self._perf_mode = perf_mode.upper()
self._low_jitter = low_jitter
self._lock_req = lock_req

self._max_freq = {
"undefined" : 250e6,
"lowpower" : 250e6,
"economy" : 312.5e6,
"speed" : 416.75e6
}[perf_mode.lower()]

def register_clkin(self, clkin, freq, usr_clk_ref=False):
"""
Register clkin signal as input PLL input signal
Parameters
----------
clkin: ClockSignal / Signal
input clock signal
freq: float
input clock frequency (Hz)
usr_clk_ref: bool
select if clkin is connected to CLK_REF or USR_CLK_REF
"""
self._usr_clk_ref = usr_clk_ref
self._clkin = Signal()
if isinstance(clkin, (Signal, ClockSignal)):
self.comb += self._clkin.eq(clkin)
else:
raise ValueError
self._clkin_freq = freq
register_clkin_log(self.logger, clkin, freq)

def create_clkout(self, cd, freq, phase=0, with_reset=True):
"""
Register cd ClockDomain as PLL output signal
Parameters
----------
cd: ClockDomain
input clock signal
freq: float
output clock frequency (Hz)
phase: int
must be 0, 90, 180, 270
with_reset: bool
drive cd reset
"""
assert phase in [0, 90, 180, 270]
assert phase not in self._clkouts
assert freq <= self._max_freq

clkout = Signal()
self._clkouts[phase] = (clkout, freq)
if with_reset:
self.specials += AsyncResetSynchronizer(cd, ~self.locked)
self.comb += cd.clk.eq(clkout)
create_clkout_log(self.logger, cd.name, freq, 0, phase)

def do_finalize(self):
assert hasattr(self, "_clkin")
assert len(self._clkouts) > 0

# set/unset frequency doubler for CLK180/CLK270
clk_doub = {180:0, 270:0}
# extract slowest frequency -> ref
clkout_freq = min([f for (_, f) in self._clkouts.values()])

for phase in [0, 90, 180, 270]:
(clk, freq) = self._clkouts.get(phase, (Open(), 0))
self._clkouts[phase] = (clk, freq) # force update (add unselected output)
if freq != 0:
# clk0 and clk90 frequency must be equal to clkout freq
if phase in [0, 90]:
assert freq == clkout_freq
else:
# clk180 and clk270 must be x1 or x2 clkout frequency
assert freq in [clkout_freq, 2 * clkout_freq]
# when clk180 or clk270 == x2 clkout: CLKxx_DOUB must be set
if freq == 2 * clkout_freq:
clk_doub[phase] = 1

assert clkout_freq is not None

freqInMHz = self._clkin_freq/1e6
freqOutMHz = clkout_freq/1e6

self.specials += Instance("CC_PLL",
p_REF_CLK = freqInMHz, # reference input in MHz
p_OUT_CLK = freqOutMHz, # pll output frequency in MHz
p_LOW_JITTER = self._low_jitter, # 0: disable, 1: enable low jitter mode
p_PERF_MD = self._perf_mode, # FPGA operation mode for VDD_PLL
p_LOCK_REQ = self._lock_req, # Lock status required before PLL output enable
p_CI_FILTER_CONST = 2, # optional CI filter constant
p_CP_FILTER_CONST = 4, # optional CP filter constant
i_CLK_REF = self._clkin if not self._usr_clk_ref else Open(),
i_USR_CLK_REF = self._clkin if self._usr_clk_ref else Open(),
i_CLK_FEEDBACK = 0,
i_USR_LOCKED_STDY_RST = self.reset,
o_CLK_REF_OUT = Open(),
o_USR_PLL_LOCKED_STDY = Open(),
o_USR_PLL_LOCKED = self.locked,
**{f"o_CLK{p}" : c for (p, (c, _)) in self._clkouts.items()},
**{f"p_CLK{p}_DOUB" : v for (p, v) in clk_doub.items()},
)

0 comments on commit 2d1072b

Please sign in to comment.