efinix: support PLL, add dbparser and ifacewriter
This commit is contained in:
parent
0278d3eee8
commit
9b6ae2ff03
|
@ -1 +1,3 @@
|
||||||
from litex.build.efinix.programmer import EfinixProgrammer
|
from litex.build.efinix.programmer import EfinixProgrammer
|
||||||
|
from litex.build.efinix.dbparser import EfinixDbParser
|
||||||
|
from litex.build.efinix.ifacewriter import InterfaceWriter
|
|
@ -0,0 +1,96 @@
|
||||||
|
import os
|
||||||
|
import csv
|
||||||
|
import re
|
||||||
|
|
||||||
|
import xml.etree.ElementTree as et
|
||||||
|
|
||||||
|
namespaces = { 'efxpt' : 'http://www.efinixinc.com/peri_device_db',
|
||||||
|
'xi' : 'http://www.w3.org/2001/XInclude'
|
||||||
|
}
|
||||||
|
|
||||||
|
class EfinixDbParser():
|
||||||
|
def __init__(self, efinity_path, device):
|
||||||
|
self.efinity_db_path = efinity_path + '/pt/db/'
|
||||||
|
self.device = device
|
||||||
|
|
||||||
|
def get_device_map(self, device):
|
||||||
|
with open(self.efinity_db_path + 'devicemap.csv') as f:
|
||||||
|
reader = csv.reader(f)
|
||||||
|
data = list(reader)
|
||||||
|
|
||||||
|
for d in data:
|
||||||
|
if d[0] == device:
|
||||||
|
print(d)
|
||||||
|
return d
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_package_file_name(self, dmap):
|
||||||
|
tree = et.parse(self.efinity_db_path + dmap[2])
|
||||||
|
root = tree.getroot()
|
||||||
|
inc = root.findall('xi:include', namespaces)
|
||||||
|
for i in inc:
|
||||||
|
if 'package' in i.get('href'):
|
||||||
|
return i.get('href').split('/')[1]
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_die_file_name(self, dmap):
|
||||||
|
tree = et.parse(self.efinity_db_path + dmap[2])
|
||||||
|
root = tree.getroot()
|
||||||
|
inc = root.findall('xi:include', namespaces)
|
||||||
|
for i in inc:
|
||||||
|
if 'die' in i.get('href'):
|
||||||
|
return i.get('href').split('/')[1]
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_pad_name_xml(self, dmap, pin):
|
||||||
|
package_file = self.get_package_file_name(dmap)
|
||||||
|
tree = et.parse(self.efinity_db_path + 'package/' + package_file)
|
||||||
|
root = tree.getroot()
|
||||||
|
|
||||||
|
pm = root.findall('efxpt:package_map', namespaces)
|
||||||
|
for p in pm:
|
||||||
|
if p.get('package_pin') == pin:
|
||||||
|
return (p.get('pad_name'))
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_instance_name_xml(self, dmap, pad):
|
||||||
|
die = self.get_die_file_name(dmap)
|
||||||
|
tree = et.parse(self.efinity_db_path + 'die/' + die)
|
||||||
|
root = tree.getroot()
|
||||||
|
|
||||||
|
ipd = root.find('efxpt:io_pad_definition', namespaces)
|
||||||
|
ios = ipd.findall('efxpt:io_pad_map', namespaces)
|
||||||
|
for io in ios:
|
||||||
|
if io.get('pad_name') == pad:
|
||||||
|
return (io.get('instance'))
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_pll_inst_from_gpio_inst(self, dmap, inst):
|
||||||
|
die = self.get_die_file_name(dmap)
|
||||||
|
tree = et.parse(self.efinity_db_path + 'die/' + die)
|
||||||
|
root = tree.getroot()
|
||||||
|
|
||||||
|
peri = root.findall('efxpt:periphery_instance', namespaces)
|
||||||
|
for p in peri:
|
||||||
|
if p.get('block') == 'pll':
|
||||||
|
conn = p.findall('efxpt:single_conn', namespaces)
|
||||||
|
for c in conn:
|
||||||
|
if c.get('instance') == inst:
|
||||||
|
refclk_no = 0
|
||||||
|
if c.get('index') == '3':
|
||||||
|
refclk_no = 1
|
||||||
|
return (p.get('name'), refclk_no)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_pll_inst_from_pin(self, pin):
|
||||||
|
dmap = self.get_device_map(self.device)
|
||||||
|
pad = self.get_pad_name_xml(dmap, pin)
|
||||||
|
inst = self.get_instance_name_xml(dmap, pad)
|
||||||
|
|
||||||
|
return self.get_pll_inst_from_gpio_inst(dmap, inst)
|
|
@ -25,6 +25,8 @@ from migen.fhdl.namer import build_namespace
|
||||||
from litex.build.generic_platform import Pins, IOStandard, Misc
|
from litex.build.generic_platform import Pins, IOStandard, Misc
|
||||||
from litex.build import tools
|
from litex.build import tools
|
||||||
|
|
||||||
|
from litex.build.efinix import InterfaceWriter
|
||||||
|
|
||||||
_reserved_keywords = {
|
_reserved_keywords = {
|
||||||
"always", "and", "assign", "automatic", "begin", "buf", "bufif0", "bufif1",
|
"always", "and", "assign", "automatic", "begin", "buf", "bufif0", "bufif1",
|
||||||
"case", "casex", "casez", "cell", "cmos", "config", "deassign", "default",
|
"case", "casex", "casez", "cell", "cmos", "config", "deassign", "default",
|
||||||
|
@ -108,7 +110,7 @@ def _create_gpio_instance(fragment, platform, sig, pins):
|
||||||
if len(pins) > 1:
|
if len(pins) > 1:
|
||||||
l = ',{},0'.format(len(pins) - 1)
|
l = ',{},0'.format(len(pins) - 1)
|
||||||
d = get_pin_direction(fragment, platform, sig)
|
d = get_pin_direction(fragment, platform, sig)
|
||||||
return 'design.create_{d}_gpio("{name}"{len})'.format(d =d, name=sig, len=l)
|
return 'design.create_{d}_gpio("{name}"{len})'.format(d=d, name=sig, len=l)
|
||||||
|
|
||||||
def _format_constraint(c, signame, fmt_r, fragment, platform):
|
def _format_constraint(c, signame, fmt_r, fragment, platform):
|
||||||
# IO location constraints
|
# IO location constraints
|
||||||
|
@ -157,13 +159,16 @@ def _format_conf_constraint(signame, pin, others, resname, fragment, platform):
|
||||||
fmt_c = [_format_constraint(c, signame, fmt_r, fragment, platform) for c in ([Pins(pin)] + others)]
|
fmt_c = [_format_constraint(c, signame, fmt_r, fragment, platform) for c in ([Pins(pin)] + others)]
|
||||||
return ''.join(fmt_c)
|
return ''.join(fmt_c)
|
||||||
|
|
||||||
def _build_iface_conf(named_sc, named_pc, fragment, platform):
|
def _build_iface_gpio(named_sc, named_pc, fragment, platform, specials_gpios):
|
||||||
conf = []
|
conf = []
|
||||||
inst = []
|
inst = []
|
||||||
|
|
||||||
# GPIO
|
# GPIO
|
||||||
for sig, pins, others, resname in named_sc:
|
for sig, pins, others, resname in named_sc:
|
||||||
inst.append(_create_gpio_instance(fragment, platform, sig, pins))
|
if sig not in specials_gpios:
|
||||||
|
inst.append(_create_gpio_instance(fragment, platform, sig, pins))
|
||||||
|
else:
|
||||||
|
continue
|
||||||
if len(pins) > 1:
|
if len(pins) > 1:
|
||||||
for i, p in enumerate(pins):
|
for i, p in enumerate(pins):
|
||||||
conf.append(_format_conf_constraint("{}[{}]".format(sig, i), p, others, resname, fragment, platform))
|
conf.append(_format_conf_constraint("{}[{}]".format(sig, i), p, others, resname, fragment, platform))
|
||||||
|
@ -172,56 +177,20 @@ def _build_iface_conf(named_sc, named_pc, fragment, platform):
|
||||||
if named_pc:
|
if named_pc:
|
||||||
conf.append("\n\n".join(named_pc))
|
conf.append("\n\n".join(named_pc))
|
||||||
|
|
||||||
# PLL
|
|
||||||
#inst.append()
|
|
||||||
|
|
||||||
conf = inst + conf
|
conf = inst + conf
|
||||||
|
|
||||||
return "\n".join(conf)
|
return "\n".join(conf)
|
||||||
|
|
||||||
def _build_peri(efinity_path, build_name, partnumber, named_sc, named_pc, fragment, platform):
|
def _build_peri(efinity_path, build_name, partnumber, named_sc, named_pc, fragment, platform, additional_iface_commands, specials_gpios):
|
||||||
pythonpath = ""
|
pythonpath = ""
|
||||||
|
|
||||||
header = "# Autogenerated by LiteX / git: " + tools.get_litex_git_revision()
|
header = platform.toolchain.ifacewriter.header(build_name, partnumber)
|
||||||
|
gen = platform.toolchain.ifacewriter.generate()
|
||||||
|
gpio = _build_iface_gpio(named_sc, named_pc, fragment, platform, specials_gpios)
|
||||||
|
add = '\n'.join(additional_iface_commands)
|
||||||
|
footer = platform.toolchain.ifacewriter.footer()
|
||||||
|
|
||||||
header += """
|
tools.write_to_file("iface.py", header + gen + gpio + add + footer)
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
home = '{0}'
|
|
||||||
|
|
||||||
os.environ['EFXPT_HOME'] = home + '/pt'
|
|
||||||
os.environ['EFXPGM_HOME'] = home + '/pgm'
|
|
||||||
os.environ['EFXDBG_HOME'] = home + '/debugger'
|
|
||||||
os.environ['EFXIPM_HOME'] = home + '/ipm'
|
|
||||||
|
|
||||||
sys.path.append(home + '/pt/bin')
|
|
||||||
sys.path.append(home + '/lib/python3.8/site-packages')
|
|
||||||
|
|
||||||
from api_service.design import DesignAPI
|
|
||||||
from api_service.device import DeviceAPI
|
|
||||||
|
|
||||||
is_verbose = {1}
|
|
||||||
|
|
||||||
design = DesignAPI(is_verbose)
|
|
||||||
device = DeviceAPI(is_verbose)
|
|
||||||
|
|
||||||
design.create('{2}', '{3}', './../build', overwrite=True)
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
header = header.format(efinity_path, 'True', build_name, partnumber)
|
|
||||||
|
|
||||||
conf = _build_iface_conf(named_sc, named_pc, fragment, platform)
|
|
||||||
|
|
||||||
footer = """
|
|
||||||
# Check design, generate constraints and reports
|
|
||||||
#design.generate(enable_bitstream=True)
|
|
||||||
# Save the configured periphery design
|
|
||||||
design.save()
|
|
||||||
"""
|
|
||||||
|
|
||||||
tools.write_to_file("iface.py", header + conf + footer)
|
|
||||||
|
|
||||||
subprocess.call([efinity_path + '/bin/python3', 'iface.py'])
|
subprocess.call([efinity_path + '/bin/python3', 'iface.py'])
|
||||||
|
|
||||||
|
@ -295,6 +264,9 @@ class EfinityToolchain():
|
||||||
self.efinity_path = efinity_path
|
self.efinity_path = efinity_path
|
||||||
self.additional_sdc_commands = []
|
self.additional_sdc_commands = []
|
||||||
self.additional_xml_commands = []
|
self.additional_xml_commands = []
|
||||||
|
self.ifacewriter = InterfaceWriter("iface.py", efinity_path)
|
||||||
|
self.specials_gpios = []
|
||||||
|
self.additional_iface_commands = []
|
||||||
|
|
||||||
def build(self, platform, fragment,
|
def build(self, platform, fragment,
|
||||||
build_dir = "build",
|
build_dir = "build",
|
||||||
|
@ -319,6 +291,9 @@ class EfinityToolchain():
|
||||||
v_output.write(v_file)
|
v_output.write(v_file)
|
||||||
platform.add_source(v_file)
|
platform.add_source(v_file)
|
||||||
|
|
||||||
|
sc = platform.constraint_manager.get_sig_constraints()
|
||||||
|
self.specials_gpios = [(v_output.ns.get_name(sig)) for sig in self.specials_gpios]
|
||||||
|
|
||||||
if platform.verilog_include_paths:
|
if platform.verilog_include_paths:
|
||||||
self.options['includ_path'] = '{' + ';'.join(platform.verilog_include_paths) + '}'
|
self.options['includ_path'] = '{' + ';'.join(platform.verilog_include_paths) + '}'
|
||||||
|
|
||||||
|
@ -343,13 +318,15 @@ class EfinityToolchain():
|
||||||
|
|
||||||
# Generate constraints file (.peri.xml)
|
# Generate constraints file (.peri.xml)
|
||||||
_build_peri(
|
_build_peri(
|
||||||
efinity_path = self.efinity_path,
|
efinity_path = self.efinity_path,
|
||||||
build_name = build_name,
|
build_name = build_name,
|
||||||
partnumber = platform.device,
|
partnumber = platform.device,
|
||||||
named_sc = named_sc,
|
named_sc = named_sc,
|
||||||
named_pc = named_pc,
|
named_pc = named_pc,
|
||||||
fragment = fragment,
|
fragment = fragment,
|
||||||
platform = platform)
|
platform = platform,
|
||||||
|
additional_iface_commands = self.additional_iface_commands,
|
||||||
|
specials_gpios = self.specials_gpios)
|
||||||
|
|
||||||
# Run
|
# Run
|
||||||
if run:
|
if run:
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
import os
|
||||||
|
from litex.build import tools
|
||||||
|
|
||||||
|
class InterfaceWriter():
|
||||||
|
def __init__(self, filename, efinity_path):
|
||||||
|
self.file = filename
|
||||||
|
self.efinity_path = efinity_path
|
||||||
|
self.blocks = []
|
||||||
|
|
||||||
|
def header(self, build_name, partnumber):
|
||||||
|
header = "# Autogenerated by LiteX / git: " + tools.get_litex_git_revision()
|
||||||
|
header += """
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import pprint
|
||||||
|
|
||||||
|
home = '{0}'
|
||||||
|
|
||||||
|
os.environ['EFXPT_HOME'] = home + '/pt'
|
||||||
|
os.environ['EFXPGM_HOME'] = home + '/pgm'
|
||||||
|
os.environ['EFXDBG_HOME'] = home + '/debugger'
|
||||||
|
os.environ['EFXIPM_HOME'] = home + '/ipm'
|
||||||
|
|
||||||
|
sys.path.append(home + '/pt/bin')
|
||||||
|
sys.path.append(home + '/lib/python3.8/site-packages')
|
||||||
|
|
||||||
|
from api_service.design import DesignAPI
|
||||||
|
from api_service.device import DeviceAPI
|
||||||
|
|
||||||
|
is_verbose = {1}
|
||||||
|
|
||||||
|
design = DesignAPI(is_verbose)
|
||||||
|
device = DeviceAPI(is_verbose)
|
||||||
|
|
||||||
|
design.create('{2}', '{3}', './../build', overwrite=True)
|
||||||
|
|
||||||
|
"""
|
||||||
|
return header.format(self.efinity_path, 'True', build_name, partnumber)
|
||||||
|
|
||||||
|
def get_block(self, name):
|
||||||
|
for b in self.blocks:
|
||||||
|
if b['name'] == name:
|
||||||
|
return b
|
||||||
|
return None
|
||||||
|
|
||||||
|
def generate_pll(self, block, verbose=True):
|
||||||
|
name = block['name']
|
||||||
|
cmd = '# ---------- PLL {} ---------\n'.format(name)
|
||||||
|
cmd += 'design.create_block("{}", block_type="PLL")\n'.format(name)
|
||||||
|
cmd += 'design.gen_pll_ref_clock("{}", pll_res="{}", refclk_src="{}", refclk_name="{}", ext_refclk_no="{}")\n\n' \
|
||||||
|
.format(name, block['resource'], block['input_clock'], block['input_clock_name'], block['clock_no'])
|
||||||
|
|
||||||
|
cmd += 'pll_config = {{ "REFCLK_FREQ":"{}" }}\n'.format(block['input_freq'] / 1e6)
|
||||||
|
cmd += 'design.set_property("{}", pll_config, block_type="PLL")\n\n'.format(name)
|
||||||
|
|
||||||
|
# Output clock 0 is enabled by default
|
||||||
|
for i, clock in enumerate(block['clk_out']):
|
||||||
|
if i > 0:
|
||||||
|
cmd += 'pll_config = {{ "CLKOUT{}_EN":"1", "CLKOUT{}_PIN":"{}" }}\n'.format(i, i, clock[0])
|
||||||
|
cmd += 'design.set_property("{}", pll_config, block_type="PLL")\n\n'.format(name)
|
||||||
|
|
||||||
|
cmd += 'target_freq = {\n'
|
||||||
|
for i, clock in enumerate(block['clk_out']):
|
||||||
|
cmd += ' "CLKOUT{}_FREQ": "{}",\n'.format(i, clock[1] / 1e6)
|
||||||
|
cmd += ' "CLKOUT{}_PHASE": "{}",\n'.format(i, clock[2])
|
||||||
|
cmd += '}\n'
|
||||||
|
cmd += 'calc_result = design.auto_calc_pll_clock("{}", target_freq)\n\n'.format(name)
|
||||||
|
|
||||||
|
|
||||||
|
if verbose:
|
||||||
|
cmd += 'print("#### {} ####")\n'.format(name)
|
||||||
|
cmd += 'clksrc_info = design.trace_ref_clock("{}", block_type="PLL")\n'.format(name)
|
||||||
|
cmd += 'pprint.pprint(clksrc_info)\n'
|
||||||
|
cmd += 'clock_source_prop = ["REFCLK_SOURCE", "EXT_CLK", "CLKOUT0_EN", "CLKOUT1_EN","REFCLK_FREQ", "RESOURCE"]\n'
|
||||||
|
cmd += 'clock_source_prop += ["M", "N", "O", "CLKOUT0_DIV", "CLKOUT2_DIV", "VCO_FREQ", "PLL_FREQ"]\n'
|
||||||
|
cmd += 'prop_map = design.get_property("{}", clock_source_prop, block_type="PLL")\n'.format(name)
|
||||||
|
cmd += 'pprint.pprint(prop_map)\n'
|
||||||
|
|
||||||
|
cmd += '# ---------- END PLL {} ---------\n\n'.format(name)
|
||||||
|
return cmd
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
output = ''
|
||||||
|
for b in self.blocks:
|
||||||
|
if b['type'] == 'PLL':
|
||||||
|
output += self.generate_pll(b)
|
||||||
|
return output
|
||||||
|
|
||||||
|
def footer(self):
|
||||||
|
return """
|
||||||
|
# Check design, generate constraints and reports
|
||||||
|
#design.generate(enable_bitstream=True)
|
||||||
|
# Save the configured periphery design
|
||||||
|
design.save()"""
|
||||||
|
|
|
@ -50,3 +50,20 @@ class EfinixPlatform(GenericPlatform):
|
||||||
if hasattr(to, "p"):
|
if hasattr(to, "p"):
|
||||||
to = to.p
|
to = to.p
|
||||||
self.toolchain.add_false_path_constraint(self, from_, to)
|
self.toolchain.add_false_path_constraint(self, from_, to)
|
||||||
|
|
||||||
|
# TODO: fix this when pin is like p = platform.request("sdios")
|
||||||
|
# get_pin_location(p[1])
|
||||||
|
# not tested with subsignal like get_pin_location(p.clk)
|
||||||
|
def get_pin_location(self, sig):
|
||||||
|
sc = self.constraint_manager.get_sig_constraints()
|
||||||
|
for s, pins, others, resource in sc:
|
||||||
|
if s == sig:
|
||||||
|
return pins[0]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_pin_name(self, sig):
|
||||||
|
sc = self.constraint_manager.get_sig_constraints()
|
||||||
|
for s, pins, others, resource in sc:
|
||||||
|
if s == sig:
|
||||||
|
return resource[0]
|
||||||
|
return None
|
|
@ -14,3 +14,6 @@ from litex.soc.cores.clock.intel_cyclone10 import Cyclone10LPPLL
|
||||||
from litex.soc.cores.clock.lattice_ice40 import iCE40PLL
|
from litex.soc.cores.clock.lattice_ice40 import iCE40PLL
|
||||||
from litex.soc.cores.clock.lattice_ecp5 import ECP5PLL
|
from litex.soc.cores.clock.lattice_ecp5 import ECP5PLL
|
||||||
from litex.soc.cores.clock.lattice_nx import NXOSCA, NXPLL
|
from litex.soc.cores.clock.lattice_nx import NXOSCA, NXPLL
|
||||||
|
|
||||||
|
# Efinix
|
||||||
|
from litex.soc.cores.clock.efinix_trion import TRIONPLL
|
|
@ -0,0 +1,92 @@
|
||||||
|
#
|
||||||
|
# This file is part of LiteX.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2021 Franck Jullien <franck.jullien@collshade.fr>
|
||||||
|
# Copyright (c) 2021 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
from migen import *
|
||||||
|
from migen.genlib.resetsync import AsyncResetSynchronizer
|
||||||
|
|
||||||
|
from litex.build.generic_platform import *
|
||||||
|
from litex.soc.cores.clock.common import *
|
||||||
|
|
||||||
|
from litex.build.efinix import EfinixDbParser
|
||||||
|
|
||||||
|
class Open(Signal): pass
|
||||||
|
|
||||||
|
#TODO: do somthing else
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
# Efinix / TRIONPLL ----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class TRIONPLL(Module):
|
||||||
|
nclkouts_max = 4
|
||||||
|
def __init__(self, platform):
|
||||||
|
global count
|
||||||
|
self.logger = logging.getLogger("TRIONPLL")
|
||||||
|
self.logger.info("Creating TRIONPLL.".format())
|
||||||
|
self.platform = platform
|
||||||
|
self.nclkouts = 0
|
||||||
|
self.pll_name = "pll{}".format(count)
|
||||||
|
|
||||||
|
block = {}
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
block['type'] = 'PLL'
|
||||||
|
block['name'] = self.pll_name
|
||||||
|
block['clk_out'] = []
|
||||||
|
|
||||||
|
self.platform.toolchain.ifacewriter.blocks.append(block)
|
||||||
|
|
||||||
|
def register_clkin(self, clkin, freq):
|
||||||
|
block = self.platform.toolchain.ifacewriter.get_block(self.pll_name)
|
||||||
|
|
||||||
|
# If clkin has resource, PLL clock input is EXTERNAL
|
||||||
|
# When PLL clock is external, it must not be present in the top file
|
||||||
|
# Add a test on clkin resource here
|
||||||
|
block['input_clock_name'] = self.platform.get_pin_name(clkin)
|
||||||
|
pin_name = self.platform.get_pin_location(clkin)
|
||||||
|
|
||||||
|
self.platform.delete(clkin)
|
||||||
|
|
||||||
|
#tpl = "create_clock -name {clk} -period {period} [get_ports {{{clk}}}]"
|
||||||
|
#sdc = self.platform.toolchain.additional_sdc_commands
|
||||||
|
#sdc.append(tpl.format(clk=block['input_clock_name'], period=1/freq))
|
||||||
|
|
||||||
|
parser = EfinixDbParser(self.platform.efinity_path, self.platform.device)
|
||||||
|
(pll_res, clock_no) = parser.get_pll_inst_from_pin(pin_name)
|
||||||
|
|
||||||
|
block['input_clock'] = 'EXTERNAL'
|
||||||
|
block['input_freq'] = freq
|
||||||
|
block['resource'] = pll_res
|
||||||
|
block['clock_no'] = clock_no
|
||||||
|
|
||||||
|
self.logger.info("Using {}".format(pll_res))
|
||||||
|
self.logger.info("Clock source: {}, using EXT_CLK{}".format(block['input_clock'], clock_no))
|
||||||
|
|
||||||
|
def create_clkout(self, cd, freq, phase=0, margin=1e-2, with_reset=True):
|
||||||
|
assert self.nclkouts < self.nclkouts_max
|
||||||
|
|
||||||
|
clk_out_name = '{}_CLKOUT{}'.format(self.pll_name, self.nclkouts)
|
||||||
|
|
||||||
|
self.platform.add_extension([(clk_out_name, 0, Pins(1))])
|
||||||
|
tmp = self.platform.request(clk_out_name)
|
||||||
|
|
||||||
|
# We don't want this IO to be in the interface configuration file as a simple GPIO
|
||||||
|
self.platform.toolchain.specials_gpios.append(tmp)
|
||||||
|
self.comb += cd.clk.eq(tmp)
|
||||||
|
create_clkout_log(self.logger, cd.name, freq, margin, self.nclkouts)
|
||||||
|
self.nclkouts += 1
|
||||||
|
|
||||||
|
block = self.platform.toolchain.ifacewriter.get_block(self.pll_name)
|
||||||
|
block['clk_out'].append([clk_out_name, freq, phase, margin])
|
||||||
|
|
||||||
|
def compute_config(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def set_configuration(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def do_finalize(self):
|
||||||
|
pass
|
Loading…
Reference in New Issue