# 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))