cores/clock: add initial iCE40 support
This commit is contained in:
parent
6d54335839
commit
edf8aa8cfd
|
@ -382,6 +382,101 @@ class USIDELAYCTRL(Module):
|
||||||
i_REFCLK=cd.clk,
|
i_REFCLK=cd.clk,
|
||||||
i_RST=ic_reset)
|
i_RST=ic_reset)
|
||||||
|
|
||||||
|
# Lattice / iCE40 ----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# TODO:
|
||||||
|
# - add phase support.
|
||||||
|
# - add support for GENCLK_HALF to be able to generate clock down to 8MHz.
|
||||||
|
|
||||||
|
class iCE40PLL(Module):
|
||||||
|
nclkouts_max = 1
|
||||||
|
divr_range = (0, 16)
|
||||||
|
divf_range = (0, 128)
|
||||||
|
divq_range = (0, 7)
|
||||||
|
clki_freq_range = ( 10e6, 133e9)
|
||||||
|
clko_freq_range = ( 16e6, 275e9)
|
||||||
|
vco_freq_range = (533e6, 1066e6)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.reset = Signal()
|
||||||
|
self.locked = Signal()
|
||||||
|
self.clkin_freq = None
|
||||||
|
self.vcxo_freq = None
|
||||||
|
self.nclkouts = 0
|
||||||
|
self.clkouts = {}
|
||||||
|
self.config = {}
|
||||||
|
self.params = {}
|
||||||
|
|
||||||
|
def register_clkin(self, clkin, freq):
|
||||||
|
(clki_freq_min, clki_freq_max) = self.clki_freq_range
|
||||||
|
assert freq >= clki_freq_min
|
||||||
|
assert freq <= clki_freq_max
|
||||||
|
self.clkin = Signal()
|
||||||
|
if isinstance(clkin, (Signal, ClockSignal)):
|
||||||
|
self.comb += self.clkin.eq(clkin)
|
||||||
|
else:
|
||||||
|
raise ValueError
|
||||||
|
self.clkin_freq = freq
|
||||||
|
|
||||||
|
def create_clkout(self, cd, freq, margin=1e-2):
|
||||||
|
(clko_freq_min, clko_freq_max) = self.clko_freq_range
|
||||||
|
assert freq >= clko_freq_min
|
||||||
|
assert freq <= clko_freq_max
|
||||||
|
assert self.nclkouts < self.nclkouts_max
|
||||||
|
clkout = Signal()
|
||||||
|
self.clkouts[self.nclkouts] = (clkout, freq, 0, margin)
|
||||||
|
self.nclkouts += 1
|
||||||
|
self.comb += cd.clk.eq(clkout)
|
||||||
|
|
||||||
|
def compute_config(self):
|
||||||
|
config = {}
|
||||||
|
for divr in range(*self.divr_range):
|
||||||
|
for divf in range(*self.divf_range):
|
||||||
|
all_valid = True
|
||||||
|
vco_freq = self.clkin_freq/(divr + 1)*(divf + 1)
|
||||||
|
(vco_freq_min, vco_freq_max) = self.vco_freq_range
|
||||||
|
if vco_freq >= vco_freq_min and vco_freq <= vco_freq_max:
|
||||||
|
for n, (clk, f, p, m) in sorted(self.clkouts.items()):
|
||||||
|
valid = False
|
||||||
|
for divq in range(*self.divq_range):
|
||||||
|
clk_freq = vco_freq/(2**divq)
|
||||||
|
if abs(clk_freq - f) < f*m:
|
||||||
|
config["divq"] = divq
|
||||||
|
valid = True
|
||||||
|
break
|
||||||
|
if not valid:
|
||||||
|
all_valid = False
|
||||||
|
else:
|
||||||
|
all_valid = False
|
||||||
|
if all_valid:
|
||||||
|
config["vco"] = vco_freq
|
||||||
|
config["divr"] = divr
|
||||||
|
config["divf"] = divf
|
||||||
|
return config
|
||||||
|
raise ValueError("No PLL config found")
|
||||||
|
|
||||||
|
def do_finalize(self):
|
||||||
|
config = self.compute_config()
|
||||||
|
clkfb = Signal()
|
||||||
|
for f, v in [(17e6, 1), (26e6, 2), (44e6, 3), (66e6, 4), (101e6, 5), (133e6, 6)]:
|
||||||
|
pfd_freq = self.clkin_freq/(config["divr"] + 1)
|
||||||
|
if pfd_freq < f:
|
||||||
|
filter_range = v
|
||||||
|
break
|
||||||
|
self.params.update(
|
||||||
|
p_FEEDBACK_PATH="SIMPLE",
|
||||||
|
p_FILTER_RANGE=filter_range,
|
||||||
|
i_RESETB=~self.reset,
|
||||||
|
i_REFERENCECLK=self.clkin,
|
||||||
|
o_LOCK=self.locked,
|
||||||
|
)
|
||||||
|
for n, (clk, f, p, m) in sorted(self.clkouts.items()):
|
||||||
|
self.params["p_DIVR"] = config["divr"]
|
||||||
|
self.params["p_DIVF"] = config["divf"]
|
||||||
|
self.params["p_DIVQ"] = config["divq"]
|
||||||
|
self.params["o_PLLOUTGLOBAL"] = clk
|
||||||
|
self.specials += Instance("SB_PLL40_CORE", **self.params)
|
||||||
|
|
||||||
# Lattice / ECP5 -----------------------------------------------------------------------------------
|
# Lattice / ECP5 -----------------------------------------------------------------------------------
|
||||||
|
|
||||||
# TODO:
|
# TODO:
|
||||||
|
|
Loading…
Reference in New Issue