cores/clock: simplify Fractional Divide support on S7MMCM.
Specific clkoutn_divide_range can now be provided by specialized XilinxClocking classes. When provided, the specific range will be used. Floats are also now supported in the range definition/iteration.
This commit is contained in:
parent
f34593a17d
commit
aec1bfbeb4
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
"""Clock Abstraction Modules"""
|
"""Clock Abstraction Modules"""
|
||||||
|
|
||||||
|
import math
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from migen import *
|
from migen import *
|
||||||
|
@ -48,12 +49,22 @@ def compute_config_log(logger, config):
|
||||||
log = log[:-1]
|
log = log[:-1]
|
||||||
logger.info(log)
|
logger.info(log)
|
||||||
|
|
||||||
|
# Helpers ------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def clkdiv_range(start, stop, step=1):
|
||||||
|
start = float(start)
|
||||||
|
stop = float(stop)
|
||||||
|
step = float(step)
|
||||||
|
current = start
|
||||||
|
while current < stop:
|
||||||
|
yield int(current) if math.floor(current) == current else current
|
||||||
|
current += step
|
||||||
|
|
||||||
# Xilinx / Generic ---------------------------------------------------------------------------------
|
# Xilinx / Generic ---------------------------------------------------------------------------------
|
||||||
|
|
||||||
class XilinxClocking(Module, AutoCSR):
|
class XilinxClocking(Module, AutoCSR):
|
||||||
clkfbout_mult_frange = (2, 64+1)
|
clkfbout_mult_frange = (2, 64+1)
|
||||||
clkout_divide_range = (1, 128+1)
|
clkout_divide_range = (1, 128+1)
|
||||||
clkout0_divide_range = (2, (128+0.125), 0.125)
|
|
||||||
|
|
||||||
def __init__(self, vco_margin=0):
|
def __init__(self, vco_margin=0):
|
||||||
self.vco_margin = vco_margin
|
self.vco_margin = vco_margin
|
||||||
|
@ -115,7 +126,9 @@ class XilinxClocking(Module, AutoCSR):
|
||||||
vco_freq <= vco_freq_max*(1 - self.vco_margin)):
|
vco_freq <= vco_freq_max*(1 - self.vco_margin)):
|
||||||
for n, (clk, f, p, m) in sorted(self.clkouts.items()):
|
for n, (clk, f, p, m) in sorted(self.clkouts.items()):
|
||||||
valid = False
|
valid = False
|
||||||
for d in range(*self.clkout_divide_range):
|
d_range = self.clkout_divide_range
|
||||||
|
d_range = getattr(self, "clkout{}_divide_range".format(n), d_range)
|
||||||
|
for d in clkdiv_range(*d_range):
|
||||||
clk_freq = vco_freq/d
|
clk_freq = vco_freq/d
|
||||||
if abs(clk_freq - f) <= f*m:
|
if abs(clk_freq - f) <= f*m:
|
||||||
config["clkout{}_freq".format(n)] = clk_freq
|
config["clkout{}_freq".format(n)] = clk_freq
|
||||||
|
@ -123,19 +136,6 @@ class XilinxClocking(Module, AutoCSR):
|
||||||
config["clkout{}_phase".format(n)] = p
|
config["clkout{}_phase".format(n)] = p
|
||||||
valid = True
|
valid = True
|
||||||
break
|
break
|
||||||
if not valid and n == 0:
|
|
||||||
# clkout0 supports fractional division, try the fractional range as a fallback
|
|
||||||
(start, stop, step) = self.clkout0_divide_range
|
|
||||||
d = start
|
|
||||||
while d < stop:
|
|
||||||
clk_freq = vco_freq / d
|
|
||||||
if abs(clk_freq - f) <= f * m:
|
|
||||||
config["clkout{}_freq".format(n)] = clk_freq
|
|
||||||
config["clkout{}_divide".format(n)] = d
|
|
||||||
config["clkout{}_phase".format(n)] = p
|
|
||||||
valid = True
|
|
||||||
break
|
|
||||||
d += step
|
|
||||||
if not valid:
|
if not valid:
|
||||||
all_valid = False
|
all_valid = False
|
||||||
else:
|
else:
|
||||||
|
@ -310,7 +310,8 @@ class S7PLL(XilinxClocking):
|
||||||
|
|
||||||
|
|
||||||
class S7MMCM(XilinxClocking):
|
class S7MMCM(XilinxClocking):
|
||||||
nclkouts_max = 7
|
nclkouts_max = 7
|
||||||
|
clkout0_divide_range = (1, (128 + 1/8), 1/8) # Fractional Divide available on CLKOUT0
|
||||||
|
|
||||||
def __init__(self, speedgrade=-1):
|
def __init__(self, speedgrade=-1):
|
||||||
self.logger = logging.getLogger("S7MMCM")
|
self.logger = logging.getLogger("S7MMCM")
|
||||||
|
|
Loading…
Reference in New Issue