f4pga/sfbuild/sf_common_modules/synth.py
Krzysztof Boronski cd2ad7144c Up-to-date version of sfbuild
Signed-off-by: Krzysztof Boronski <kboronski@antmicro.com>
2022-04-26 12:16:36 +02:00

162 lines
5.2 KiB
Python
Executable file

#!/usr/bin/python3
# Symbiflow Stage Module
# ----------------------------------------------------------------------------- #
import os
from sf_common import *
from sf_module import *
# ----------------------------------------------------------------------------- #
# Setup environmental variables for YOSYS TCL scripts
def yosys_setup_tcl_env(tcl_env_def):
env = {}
for key, value in tcl_env_def.items():
if value is None:
continue
v = value
if type(value) is list:
v = ' '.join(value)
env[key] = v
return env
def yosys_synth(tcl, tcl_env, verilog_files=[], read_verilog_args=None, log=None):
# Set up environment for TCL weirdness
optional = []
if log:
optional += ['-l', log]
env = os.environ.copy()
env.update(tcl_env)
tcl = f'tcl {tcl}'
# Use append read_verilog commands to the scripts for more sophisticated
# input if arguments are specified. Omit direct input throught `yosys` command.
if read_verilog_args:
args_str = ' '.join(read_verilog_args)
for verilog in verilog_files:
tcl = f'read_verilog {args_str} {verilog}; {tcl}'
verilog_files = []
# Execute YOSYS command
return sub(*(['yosys', '-p', tcl] + optional + verilog_files),
env=env)
def yosys_conv(tcl, tcl_env, synth_json):
# Set up environment for TCL weirdness
env = os.environ.copy()
env.update(tcl_env)
# Execute YOSYS command
return sub('yosys', '-p', 'read_json ' + synth_json + '; tcl ' + tcl,
env=env)
# ----------------------------------------------------------------------------- #
class SynthModule(Module):
extra_products: 'list[str]'
def map_io(self, ctx: ModuleContext):
mapping = {}
top = ctx.values.top
if ctx.takes.build_dir:
top = os.path.join(ctx.takes.build_dir, top)
mapping['eblif'] = top + '.eblif'
mapping['fasm_extra'] = top + '_fasm_extra.fasm'
mapping['json'] = top + '.json'
mapping['synth_json'] = top + '_io.json'
b_path = os.path.dirname(top)
for extra in self.extra_products:
name, spec = decompose_depname(extra)
if spec == 'maybe':
raise ModuleRuntimeException(
f'Yosys synth extra products can\'t use \'maybe\ '
f'(?) specifier. Product causing this error: `{extra}`.'
)
elif spec == 'req':
mapping[name] = \
os.path.join(b_path,
ctx.values.device + '_' + name + '.' + name)
return mapping
def execute(self, ctx: ModuleContext):
split_inouts = os.path.join(ctx.share, 'scripts/split_inouts.py')
synth_tcl = os.path.join(ctx.values.tcl_scripts, 'synth.tcl')
conv_tcl = os.path.join(ctx.values.tcl_scripts, 'conv.tcl')
tcl_env = yosys_setup_tcl_env(ctx.values.yosys_tcl_env) \
if ctx.values.yosys_tcl_env else {}
if get_verbosity_level() >= 2:
yield f'Synthesizing sources: {ctx.takes.sources}...'
else:
yield f'Synthesizing sources...'
yosys_synth(synth_tcl, tcl_env, ctx.takes.sources,
ctx.values.read_verilog_args, ctx.outputs.synth_log)
yield f'Splitting in/outs...'
sub('python3', split_inouts, '-i', ctx.outputs.json, '-o',
ctx.outputs.synth_json)
if not os.path.isfile(ctx.produces.fasm_extra):
with open(ctx.produces.fasm_extra, 'w') as f:
f.write('')
yield f'Converting...'
yosys_conv(conv_tcl, tcl_env, ctx.outputs.synth_json)
def __init__(self, params):
self.name = 'synthesize'
self.no_of_phases = 3
self.takes = [
'sources',
'build_dir?'
]
# Extra takes for use with TCL scripts
extra_takes = params.get('takes')
if extra_takes:
self.takes += extra_takes
self.produces = [
'eblif',
'fasm_extra',
'json',
'synth_json',
'synth_log!'
]
# Extra products for use with TCL scripts
extra_products = params.get('produces')
if extra_products:
self.produces += extra_products
self.extra_products = extra_products
else:
self.extra_products = []
self.values = [
'top',
'device',
'tcl_scripts',
'yosys_tcl_env?',
'read_verilog_args?'
]
self.prod_meta = {
'eblif': 'Extended BLIF hierarchical sequential designs file\n'
'generated by YOSYS',
'json': 'JSON file containing a design generated by YOSYS',
'synth_log': 'YOSYS synthesis log',
'fasm_extra': 'Extra FASM generated during sythesis stage. Needed in '
'some designs.\nIn case it\'s not necessary, the file '
'will be empty.'
}
extra_meta = params.get('prod_meta')
if extra_meta:
self.prod_meta.update(extra_meta)
ModuleClass = SynthModule