|  | # SPDX-FileCopyrightText: 2020 Efabless Corporation | 
|  | # | 
|  | # Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | # you may not use this file except in compliance with the License. | 
|  | # You may obtain a copy of the License at | 
|  | # | 
|  | #      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | # | 
|  | # Unless required by applicable law or agreed to in writing, software | 
|  | # distributed under the License is distributed on an "AS IS" BASIS, | 
|  | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | # See the License for the specific language governing permissions and | 
|  | # limitations under the License. | 
|  | # SPDX-License-Identifier: Apache-2.0 | 
|  | import sys | 
|  | import os | 
|  | import subprocess | 
|  | from pathlib import Path | 
|  | import argparse | 
|  | from tempfile import mkstemp | 
|  | import re | 
|  |  | 
|  |  | 
|  | def remove_inouts(jsonpath, replacewith='input'): | 
|  | """Replaces inouts with either input or output statements. | 
|  |  | 
|  | Netlistsvg does not parse inout ports as for now, so they need to be | 
|  | replaced with either input or output to produce a diagram. | 
|  |  | 
|  | Parameters | 
|  | ---------- | 
|  | jsonpath : str | 
|  | Path to JSON file to fix | 
|  | replacewith : str | 
|  | The string to replace 'inout', can be 'input' or 'output' | 
|  | """ | 
|  | assert replacewith in ['input', 'output'] | 
|  | with open(jsonpath, 'r') as withinouts: | 
|  | lines = withinouts.readlines() | 
|  | with open(jsonpath, 'w') as withoutinouts: | 
|  | for line in lines: | 
|  | withoutinouts.write(re.sub('inout', replacewith, line)) | 
|  |  | 
|  |  | 
|  | def main(argv): | 
|  | parser = argparse.ArgumentParser(argv[0]) | 
|  | parser.add_argument( | 
|  | 'verilog_rtl_dir', | 
|  | help="Path to the project's verilog/rtl directory", | 
|  | type=Path) | 
|  | parser.add_argument( | 
|  | 'output', | 
|  | help="Path to the output SVG file", | 
|  | type=Path) | 
|  | parser.add_argument( | 
|  | '--num-iopads', | 
|  | help='Number of iopads to render', | 
|  | type=int, | 
|  | default=38) | 
|  | parser.add_argument( | 
|  | '--yosys-executable', | 
|  | help='Path to yosys executable', | 
|  | type=Path, | 
|  | default='yosys') | 
|  | parser.add_argument( | 
|  | '--netlistsvg-executable', | 
|  | help='Path to netlistsvg executable', | 
|  | type=Path, | 
|  | default='netlistsvg') | 
|  | parser.add_argument( | 
|  | '--inouts-as', | 
|  | help='To what kind of IO should inout ports be replaced', | 
|  | choices=['input', 'output'], | 
|  | default='input' | 
|  | ) | 
|  |  | 
|  | args = parser.parse_args(argv[1:]) | 
|  |  | 
|  | fd, jsonpath = mkstemp(suffix='-yosys.json') | 
|  | os.close(fd) | 
|  |  | 
|  | yosyscommand = [ | 
|  | f'{str(args.yosys_executable)}', | 
|  | '-p', | 
|  | 'read_verilog pads.v defines.v; ' + | 
|  | 'read_verilog -lib -overwrite *.v; ' + | 
|  | f'verilog_defines -DMPRJ_IO_PADS={args.num_iopads}; ' + | 
|  | 'read_verilog -overwrite caravel.v; ' + | 
|  | 'hierarchy -top caravel; ' + | 
|  | 'proc; ' + | 
|  | 'opt; ' + | 
|  | f'write_json {jsonpath}; ' | 
|  | ] | 
|  |  | 
|  | result = subprocess.run( | 
|  | yosyscommand, | 
|  | cwd=args.verilog_rtl_dir, | 
|  | stdout=subprocess.PIPE, | 
|  | stderr=subprocess.STDOUT | 
|  | ) | 
|  |  | 
|  | exitcode = 0 | 
|  | if result.returncode != 0: | 
|  | print(f'Failed to run: {" ".join(yosyscommand)}', file=sys.stderr) | 
|  | print(result.stdout.decode()) | 
|  | exitcode = result.returncode | 
|  | else: | 
|  | # TODO once netlistsvg supports inout ports, this should be removed | 
|  | remove_inouts(jsonpath, args.inouts_as) | 
|  | command = f'{args.netlistsvg_executable} {jsonpath} -o {args.output}' | 
|  | result = subprocess.run( | 
|  | command.split(), | 
|  | stdout=subprocess.PIPE, | 
|  | stderr=subprocess.STDOUT | 
|  | ) | 
|  | if result.returncode != 0: | 
|  | print(f'Failed to run: {command}', file=sys.stderr) | 
|  | print(result.stdout.decode()) | 
|  | exitcode = result.returncode | 
|  |  | 
|  | os.unlink(jsonpath) | 
|  | sys.exit(exitcode) | 
|  |  | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | sys.exit(main(sys.argv)) |