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