Efinix: improve ifacewriter + misc

This commit is contained in:
Franck Jullien 2021-09-28 18:06:57 +02:00
parent 45961f733b
commit a08c5201ad
3 changed files with 93 additions and 23 deletions

View File

@ -287,6 +287,8 @@ class EfinityToolchain():
run = True, run = True,
**kwargs): **kwargs):
self.ifacewriter.set_build_params(platform, build_name)
# Create build directory # Create build directory
cwd = os.getcwd() cwd = os.getcwd()
os.makedirs(build_dir, exist_ok=True) os.makedirs(build_dir, exist_ok=True)
@ -342,7 +344,8 @@ class EfinityToolchain():
# DDR doesn't have Python API so we need to configure it # DDR doesn't have Python API so we need to configure it
# directly in the peri.xml file # directly in the peri.xml file
# self.ifacewriter.add_ddr_xml(build_name) if self.ifacewriter.xml_blocks:
self.ifacewriter.generate_xml_blocks()
# Run # Run
if run: if run:

View File

@ -16,11 +16,72 @@ class InterfaceWriter():
def __init__(self, efinity_path): def __init__(self, efinity_path):
self.efinity_path = efinity_path self.efinity_path = efinity_path
self.blocks = [] self.blocks = []
self.xml_blocks = []
self.filename = ''
self.platform = None
def add_ddr_xml(self, filename): def set_build_params(self, platform, build_name):
self.filename = build_name
self.platform = platform
def generate_xml_blocks(self):
et.register_namespace('efxpt', "http://www.efinixinc.com/peri_design_db") et.register_namespace('efxpt', "http://www.efinixinc.com/peri_design_db")
tree = et.parse(filename + '.peri.xml') tree = et.parse(self.filename + '.peri.xml')
root = tree.getroot() root = tree.getroot()
for block in self.xml_blocks:
if block['type'] == 'DDR':
self.add_ddr_xml(root, block)
if block['type'] == 'LVDS':
self.add_ddr_lvds(root, block)
xml_string = et.tostring(root, 'utf-8')
reparsed = expatbuilder.parseString(xml_string, False)
print_string = reparsed.toprettyxml(indent=" ")
# Remove lines with only whitespaces. Not sure why they are here
print_string = os.linesep.join([s for s in print_string.splitlines() if s.strip()])
tools.write_to_file("{}.peri.xml".format(self.filename), print_string)
def add_ddr_lvds(self, root, params):
lvds_info = root.find('efxpt:lvds_info', namespaces)
if params['mode'] == 'OUTPUT':
dir = 'tx'
mode = 'out'
else:
dir = 'rx'
mode = 'in'
pad = self.platform.parser.get_gpio_instance_from_pin(params['location'][0])
pad = pad.replace('TXP', 'TX')
pad = pad.replace('TXN', 'TX')
pad = pad.replace('RXP', 'RX')
pad = pad.replace('RXN', 'RX')
# Sometimes there is an extra identifier at the end
# TODO: do a better parser
if pad.count('_') == 2:
pad = pad.rsplit('_', 1)[0]
lvds = et.SubElement(lvds_info, 'efxpt:lvds',
name = params['name'],
lvds_def = pad,
ops_type = dir)
et.SubElement(lvds, 'efxpt:ltx_info', pll_instance = '',
fast_clock_name = '{}'.format(params['fast_clk']),
slow_clock_name = '{}'.format(params['slow_clk']),
reset_name = '',
out_bname = '{}'.format(params['name']),
oe_name = '',
clock_div = '1',
mode = '{}'.format(mode),
serialization = '{}'.format(params['serialisation']),
reduced_swing = 'false',
load = '3')
def add_ddr_xml(self, root, params):
ddr_info = root.find('efxpt:ddr_info', namespaces) ddr_info = root.find('efxpt:ddr_info', namespaces)
ddr = et.SubElement(ddr_info, 'efxpt:ddr', ddr = et.SubElement(ddr_info, 'efxpt:ddr',
@ -135,15 +196,6 @@ class InterfaceWriter():
et.SubElement(cs_gate_delay, 'efxpt:param', name='GATE_C_DLY', value= '3', value_type='int') et.SubElement(cs_gate_delay, 'efxpt:param', name='GATE_C_DLY', value= '3', value_type='int')
et.SubElement(cs_gate_delay, 'efxpt:param', name='GATE_F_DLY', value= '0', value_type='int') et.SubElement(cs_gate_delay, 'efxpt:param', name='GATE_F_DLY', value= '0', value_type='int')
xml_string = et.tostring(root, 'utf-8')
reparsed = expatbuilder.parseString(xml_string, False)
print_string = reparsed.toprettyxml(indent=" ")
# Remove lines with only whitespaces. Not sure why they are here
print_string = os.linesep.join([s for s in print_string.splitlines() if s.strip()])
tools.write_to_file("{}.peri.xml".format(filename), print_string)
def header(self, build_name, partnumber): def header(self, build_name, partnumber):
header = "# Autogenerated by LiteX / git: " + tools.get_litex_git_revision() header = "# Autogenerated by LiteX / git: " + tools.get_litex_git_revision()
header += """ header += """
@ -185,8 +237,16 @@ design.create('{2}', '{3}', './../gateware', overwrite=True)
mode = block['mode'] mode = block['mode']
cmd = '' cmd = ''
if mode == 'INOUT':
# TODO: {'type': 'GPIO', 'mode': 'OUTPUT', 'location': 'U16', 'size': 4, 'in_reg': 'DDIO_RESYNC', 'out_clk_pin': '', 'is_inclk_inverted': False, 'name': 'auto_ethtx_tx_data_d1', 'name_d2': 'auto_ethtx_tx_data_d2'} if len(block['location']) == 1:
cmd += 'design.create_inout_gpio("{}")\n'.format(name)
cmd += 'design.assign_pkg_pin("{}","{}")\n'.format(name, block['location'][0])
else:
cmd += 'design.create_inout_gpio("{}",{},0)\n'.format(name, block['size']-1)
for i, pad in enumerate(block['location']):
cmd += 'design.assign_pkg_pin("{}[{}]","{}")\n'.format(name, i, pad)
cmd += '\n'
return cmd
if mode == 'INPUT': if mode == 'INPUT':
if len(block['location']) == 1: if len(block['location']) == 1:
@ -198,7 +258,7 @@ design.create('{2}', '{3}', './../gateware', overwrite=True)
cmd += 'design.assign_pkg_pin("{}[{}]","{}")\n'.format(name, i, pad) cmd += 'design.assign_pkg_pin("{}[{}]","{}")\n'.format(name, i, pad)
if 'in_reg' in block: if 'in_reg' in block:
cmd += 'design.set_property("{}","IN_REG","{}")\n'.format(name, block['in_reg']) cmd += 'design.set_property("{}","IN_REG","{}")\n'.format(name, block['in_reg'])
cmd += 'design.set_property("{}","IN_CLK_PIN","{}")\n\n'.format(name, block['in_clk_pin']) cmd += 'design.set_property("{}","IN_CLK_PIN","{}")\n'.format(name, block['in_clk_pin'])
return cmd return cmd
if mode == 'OUTPUT': if mode == 'OUTPUT':
@ -262,20 +322,26 @@ design.create('{2}', '{3}', './../gateware', overwrite=True)
cmd += 'design.set_property("{}", pll_config, block_type="PLL")\n\n'.format(name) cmd += 'design.set_property("{}", pll_config, block_type="PLL")\n\n'.format(name)
for i, clock in enumerate(block['clk_out']):
cmd += 'design.set_property("{}","CLKOUT{}_PHASE","{}","PLL")\n'.format(name, i, clock[2])
cmd += 'target_freq = {\n' cmd += 'target_freq = {\n'
for i, clock in enumerate(block['clk_out']): for i, clock in enumerate(block['clk_out']):
cmd += ' "CLKOUT{}_FREQ": "{}",\n'.format(i, clock[1] / 1e6) cmd += ' "CLKOUT{}_FREQ": "{}",\n'.format(i, clock[1] / 1e6)
cmd += ' "CLKOUT{}_PHASE": "{}",\n'.format(i, clock[2])
cmd += '}\n' cmd += '}\n'
cmd += 'calc_result = design.auto_calc_pll_clock("{}", target_freq)\n\n'.format(name) cmd += 'calc_result = design.auto_calc_pll_clock("{}", target_freq)\n'.format(name)
if 'extra' in block:
cmd += block['extra']
cmd += '\n'
if verbose: if verbose:
cmd += 'print("#### {} ####")\n'.format(name) cmd += 'print("#### {} ####")\n'.format(name)
cmd += 'clksrc_info = design.trace_ref_clock("{}", block_type="PLL")\n'.format(name) cmd += 'clksrc_info = design.trace_ref_clock("{}", block_type="PLL")\n'.format(name)
cmd += 'pprint.pprint(clksrc_info)\n' cmd += 'pprint.pprint(clksrc_info)\n'
cmd += 'clock_source_prop = ["REFCLK_SOURCE", "CORE_CLK_PIN", "EXT_CLK", "CLKOUT0_EN", "CLKOUT1_EN","REFCLK_FREQ", "RESOURCE"]\n' cmd += 'clock_source_prop = ["REFCLK_SOURCE", "CORE_CLK_PIN", "EXT_CLK", "CLKOUT1_EN", "CLKOUT2_EN","REFCLK_FREQ", "RESOURCE"]\n'
cmd += 'clock_source_prop += ["CLKOUT0_FREQ", "CLKOUT1_FREQ", "CLKOUT2_FREQ"]\n' cmd += 'clock_source_prop += ["CLKOUT0_FREQ", "CLKOUT1_FREQ", "CLKOUT2_FREQ"]\n'
cmd += 'clock_source_prop += ["CLKOUT0_PHASE", "CLKOUT1_PHASE", "CLKOUT2_PHASE"]\n'
cmd += 'prop_map = design.get_property("{}", clock_source_prop, block_type="PLL")\n'.format(name) cmd += 'prop_map = design.get_property("{}", clock_source_prop, block_type="PLL")\n'.format(name)
cmd += 'pprint.pprint(prop_map)\n' cmd += 'pprint.pprint(prop_map)\n'

View File

@ -11,8 +11,6 @@ from migen.genlib.resetsync import AsyncResetSynchronizer
from litex.build.generic_platform import * from litex.build.generic_platform import *
from litex.soc.cores.clock.common import * from litex.soc.cores.clock.common import *
from litex.build.efinix import EfinixDbParser
class Open(Signal): pass class Open(Signal): pass
#TODO: do somthing else #TODO: do somthing else
@ -61,16 +59,15 @@ class TRIONPLL(Module):
# If clkin has a pin number, PLL clock input is EXTERNAL # If clkin has a pin number, PLL clock input is EXTERNAL
if self.platform.get_pin_location(clkin): if self.platform.get_pin_location(clkin):
pad_name = self.platform.get_pin_location(clkin) pad_name = self.platform.get_pin_location(clkin)[0]
self.platform.delete(clkin) self.platform.delete(clkin)
#tpl = "create_clock -name {clk} -period {period} [get_ports {{{clk}}}]" #tpl = "create_clock -name {clk} -period {period} [get_ports {{{clk}}}]"
#sdc = self.platform.toolchain.additional_sdc_commands #sdc = self.platform.toolchain.additional_sdc_commands
#sdc.append(tpl.format(clk=block['input_clock_name'], period=1/freq)) #sdc.append(tpl.format(clk=block['input_clock_name'], period=1/freq))
parser = EfinixDbParser(self.platform.efinity_path, self.platform.device)
try: try:
(pll_res, clock_no) = parser.get_pll_inst_from_pin(pad_name) (pll_res, clock_no) = self.platform.parser.get_pll_inst_from_pin(pad_name)
except: except:
self.logger.error("Cannot find a pll with {} as input".format(pad_name)) self.logger.error("Cannot find a pll with {} as input".format(pad_name))
quit() quit()
@ -115,6 +112,10 @@ class TRIONPLL(Module):
block = self.platform.toolchain.ifacewriter.get_block(self.pll_name) block = self.platform.toolchain.ifacewriter.get_block(self.pll_name)
block['clk_out'].append([clk_out_name, freq, phase, margin]) block['clk_out'].append([clk_out_name, freq, phase, margin])
def extra(self, extra):
block = self.platform.toolchain.ifacewriter.get_block(self.pll_name)
block['extra'] = extra
def compute_config(self): def compute_config(self):
pass pass