From b2adabbece770c80a7a0126ecbe717b4dfa59f8d Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Mon, 25 Jul 2022 21:58:18 +0200 Subject: [PATCH] build/yosys_wrapper: a Yosys wrapper --- litex/build/yosys_wrapper.py | 136 +++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100755 litex/build/yosys_wrapper.py diff --git a/litex/build/yosys_wrapper.py b/litex/build/yosys_wrapper.py new file mode 100755 index 000000000..0769447b3 --- /dev/null +++ b/litex/build/yosys_wrapper.py @@ -0,0 +1,136 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2022 Gwenhael Goavec-Merou +# SPDX-License-Identifier: BSD-2-Clause + + +from litex.build import tools + + +class YosysWrapper(): + """ + YosysWrapper synthesis wrapper + """ + + def __init__(self, platform, build_name, target="", output_name="", + template=[], yosys_opts="", + yosys_cmds=[], + synth_format="json", + **kwargs): + """ + Parameters + ========== + platform : GenericPlatform subclass + current platform. + build_name : str + gateware name. + target: str + target model (ice40, ecp5, nexus, ...). + output_name: str + output name if different to build_name [optional] + template: str + yosys template to use instead of default. + yosys_opts : str + Yosys options to use for synth_xxx + yosys_cmds : list + optionals commands called before synth_xxx + synth_format : str + Yosys ouptput format + kwargs: dict + list of key/value for yosys_opts [optional] + """ + + assert platform != "" + assert build_name != "" + assert target != "" + assert synth_format != "" + + self._template = self._default_template if template == [] else template + self._output_name = build_name if output_name == "" else output_name + + self._platform = platform + self._build_name = build_name + self._synth_format = synth_format + self._yosys_opts = yosys_opts + self._yosys_cmds = yosys_cmds + + self._target=target + + for key,value in kwargs.items(): + key = key.replace("_","-") + if isinstance(value, bool): + self._yosys_opts += f"-{key} " if value else "" + else: + self._yosys_opts += f"-{key} {value} " + + def _import_sources(self): + """built a list of sources to read + Return + ====== + a string containing all read_xxx lines + """ + includes = "" + reads = [] + for path in self._platform.verilog_include_paths: + includes += " -I" + path + for filename, language, library, *copy in self._platform.sources: + # yosys has no such function read_systemverilog + if language == "systemverilog": + language = "verilog -sv" + reads.append(f"read_{language}{includes} {filename}") + return "\n".join(reads) + + _default_template = [ + "verilog_defaults -push", + "verilog_defaults -add -defer", + "{read_files}", + "verilog_defaults -pop", + "attrmap -tocase keep -imap keep=\"true\" keep=1 -imap keep=\"false\" keep=0 -remove keep=0", + "{yosys_cmds}", + "synth_{target} {synth_opts} -top {build_name}", + "write_{write_fmt} {write_opts} {output_name}.{synth_fmt}", + ] + + def build_script(self): + """fill and write ys script. + """ + read_files = self._import_sources() + + format_dict = { + "build_name" : self._build_name, + "read_files" : read_files, + "synth_opts" : self._yosys_opts, + "target" : self._target, + "synth_fmt" : self._synth_format, + "write_fmt" : "verilog" if self._synth_format[0] == "v" else self._synth_format, + "write_opts" : "-pvector bra -attrprop" if self._synth_format == "edif" else "", + "output_name" : self._output_name, + } + + yosys_cmds = [l.format(**format_dict) for l in self._yosys_cmds] + format_dict["yosys_cmds"] = "\n".join(yosys_cmds) + + ys = [l.format(**format_dict) for l in self._template] + + tools.write_to_file(self._build_name + ".ys", "\n".join(ys)) + + def get_yosys_call(self, target="script"): + """built the script command or Makefile rule + command + + Parameters + ========== + target : str + selects if it's a script command or a Makefile rule to be returned + + Returns + ======= + str containing instruction and/or rule + """ + base_cmd = f"yosys -l {self._build_name}.rpt {self._build_name}.ys\n" + if target == "makefile": + return f"{self._build_name}.{self._synth_format}:\n\t" + base_cmd + elif target == "script": + return base_cmd + else: + raise ValueError("Invalid script type")