| #!/usr/bin/env python3 | |
| # -*- coding: utf-8 -*- | |
| # | |
| # Copyright (C) 2020 The SymbiFlow Authors. | |
| # | |
| # Use of this source code is governed by a ISC-style | |
| # license that can be found in the LICENSE file or at | |
| # https://opensource.org/licenses/ISC | |
| # | |
| # SPDX-License-Identifier: ISC | |
| import argparse | |
| import os | |
| import shlex | |
| from v2x import vlog_to_model | |
| from v2x import vlog_to_pbtype | |
| from v2x.xmlinc import xmlinc | |
| from vtr_xml_utils.convert import vtr_stylize_xml | |
| # ============================================================================= | |
| def make_xml_for_docs(vlog_src, output_dir): | |
| """ | |
| Recursively runs V2X (model and pb_type) on the given Verilog file and | |
| all its includes. Output XMLs are stylized using vtr-xml-utils. | |
| The Verilog file is copied to the output_dir. All include paths are | |
| updated so that they reflect the module hierarchy. It is assumed that | |
| a Verilog file is named <module>.sim.v. Next V2X is run followed by XML | |
| stylization using vtr-xml-utils. | |
| The process continues recursively (depth-first). | |
| """ | |
| # Make absolute paths | |
| vlog_src = os.path.abspath(vlog_src) | |
| output_dir = os.path.abspath(output_dir) | |
| # Make the output directory | |
| os.makedirs(output_dir, exist_ok=True) | |
| # Copy the verilog file, rearrange includes | |
| vlog_title = os.path.basename(vlog_src) | |
| vlog_dir = os.path.dirname(vlog_src) | |
| vlog_dst = os.path.join(output_dir, vlog_title) | |
| # Scan it for dependencies (includes), rewrite them | |
| vlog_deps = [] | |
| with open(vlog_src, "r") as fsrc, open(vlog_dst, "w") as fdst: | |
| for src_line in fsrc: | |
| # Modify included file path | |
| line = src_line.strip() | |
| if line.startswith("`include"): | |
| fields = shlex.split(line) | |
| assert len(fields) == 2, fields | |
| dep_src = fields[1] | |
| dep_mod = os.path.basename(dep_src).split(".")[0] | |
| dep_dst = "./{f}/{f}.sim.v".format(f=dep_mod) | |
| vlog_deps.append((dep_src, dep_dst,)) | |
| dst_line = "`include \"{}\"\n".format(dep_dst) | |
| # Pass unchanges | |
| else: | |
| dst_line = src_line | |
| # Write the line | |
| fdst.write(dst_line) | |
| # Process dependencies recursively first | |
| for dep_src, dep_dst in vlog_deps: | |
| dep_file = os.path.join(vlog_dir, dep_src) | |
| dep_dir = os.path.join(output_dir, os.path.dirname(dep_dst)) | |
| make_xml_for_docs(dep_file, dep_dir) | |
| # Run V2X, but only if an XML is not already provided | |
| vlog_mod = vlog_title.split(".")[0] | |
| model_file = os.path.join(output_dir, vlog_mod + ".model.xml") | |
| pbtype_file = os.path.join(output_dir, vlog_mod + ".pb_type.xml") | |
| if not os.path.isfile(model_file): | |
| xml = vlog_to_model.vlog_to_model([vlog_dst], None, None, model_file) | |
| with open(model_file, "w") as fp: | |
| fp.write(xml) | |
| xml = vtr_stylize_xml(model_file) | |
| with open(model_file, "w") as fp: | |
| fp.write(xml) | |
| if not os.path.isfile(pbtype_file): | |
| xml = vlog_to_pbtype.vlog_to_pbtype([vlog_dst], pbtype_file, None) | |
| with open(pbtype_file, "w") as fp: | |
| fp.write(xml) | |
| xml = vtr_stylize_xml(pbtype_file) | |
| with open(pbtype_file, "w") as fp: | |
| fp.write(xml) | |
| # ============================================================================= | |
| if __name__ == "__main__": | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument( | |
| "verilog", | |
| help="Input Verilog file" | |
| ) | |
| parser.add_argument( | |
| "path", | |
| help="Output path" | |
| ) | |
| args = parser.parse_args() | |
| make_xml_for_docs(args.verilog, args.path) |