Jeff DiCorpo | d825376 | 2021-01-24 23:46:40 -0800 | [diff] [blame] | 1 | import sys |
| 2 | import os |
| 3 | import subprocess |
| 4 | from pathlib import Path |
| 5 | import argparse |
| 6 | from tempfile import mkstemp |
| 7 | import re |
| 8 | |
| 9 | |
| 10 | def remove_inouts(jsonpath, replacewith='input'): |
| 11 | """Replaces inouts with either input or output statements. |
| 12 | |
| 13 | Netlistsvg does not parse inout ports as for now, so they need to be |
| 14 | replaced with either input or output to produce a diagram. |
| 15 | |
| 16 | Parameters |
| 17 | ---------- |
| 18 | jsonpath : str |
| 19 | Path to JSON file to fix |
| 20 | replacewith : str |
| 21 | The string to replace 'inout', can be 'input' or 'output' |
| 22 | """ |
| 23 | assert replacewith in ['input', 'output'] |
| 24 | with open(jsonpath, 'r') as withinouts: |
| 25 | lines = withinouts.readlines() |
| 26 | with open(jsonpath, 'w') as withoutinouts: |
| 27 | for line in lines: |
| 28 | withoutinouts.write(re.sub('inout', replacewith, line)) |
| 29 | |
| 30 | |
| 31 | def main(argv): |
| 32 | parser = argparse.ArgumentParser(argv[0]) |
| 33 | parser.add_argument( |
| 34 | 'verilog_rtl_dir', |
| 35 | help="Path to the project's verilog/rtl directory", |
| 36 | type=Path) |
| 37 | parser.add_argument( |
| 38 | 'output', |
| 39 | help="Path to the output SVG file", |
| 40 | type=Path) |
| 41 | parser.add_argument( |
| 42 | '--num-iopads', |
| 43 | help='Number of iopads to render', |
| 44 | type=int, |
| 45 | default=38) |
| 46 | parser.add_argument( |
| 47 | '--yosys-executable', |
| 48 | help='Path to yosys executable', |
| 49 | type=Path, |
| 50 | default='yosys') |
| 51 | parser.add_argument( |
| 52 | '--netlistsvg-executable', |
| 53 | help='Path to netlistsvg executable', |
| 54 | type=Path, |
| 55 | default='netlistsvg') |
| 56 | parser.add_argument( |
| 57 | '--inouts-as', |
| 58 | help='To what kind of IO should inout ports be replaced', |
| 59 | choices=['input', 'output'], |
| 60 | default='input' |
| 61 | ) |
| 62 | |
| 63 | args = parser.parse_args(argv[1:]) |
| 64 | |
| 65 | fd, jsonpath = mkstemp(suffix='-yosys.json') |
| 66 | os.close(fd) |
| 67 | |
| 68 | yosyscommand = [ |
| 69 | f'{str(args.yosys_executable)}', |
| 70 | '-p', |
| 71 | 'read_verilog pads.v defines.v; ' + |
| 72 | 'read_verilog -lib -overwrite *.v; ' + |
| 73 | f'verilog_defines -DMPRJ_IO_PADS={args.num_iopads}; ' + |
| 74 | 'read_verilog -overwrite caravel.v; ' + |
| 75 | 'hierarchy -top caravel; ' + |
| 76 | 'proc; ' + |
| 77 | 'opt; ' + |
| 78 | f'write_json {jsonpath}; ' |
| 79 | ] |
| 80 | |
| 81 | result = subprocess.run( |
| 82 | yosyscommand, |
| 83 | cwd=args.verilog_rtl_dir, |
| 84 | stdout=subprocess.PIPE, |
| 85 | stderr=subprocess.STDOUT |
| 86 | ) |
| 87 | |
| 88 | exitcode = 0 |
| 89 | if result.returncode != 0: |
| 90 | print(f'Failed to run: {" ".join(yosyscommand)}', file=sys.stderr) |
| 91 | print(result.stdout.decode()) |
| 92 | exitcode = result.returncode |
| 93 | else: |
| 94 | # TODO once netlistsvg supports inout ports, this should be removed |
| 95 | remove_inouts(jsonpath, args.inouts_as) |
| 96 | command = f'{args.netlistsvg_executable} {jsonpath} -o {args.output}' |
| 97 | result = subprocess.run( |
| 98 | command.split(), |
| 99 | stdout=subprocess.PIPE, |
| 100 | stderr=subprocess.STDOUT |
| 101 | ) |
| 102 | if result.returncode != 0: |
| 103 | print(f'Failed to run: {command}', file=sys.stderr) |
| 104 | print(result.stdout.decode()) |
| 105 | exitcode = result.returncode |
| 106 | |
| 107 | os.unlink(jsonpath) |
| 108 | sys.exit(exitcode) |
| 109 | |
| 110 | |
| 111 | if __name__ == '__main__': |
| 112 | sys.exit(main(sys.argv)) |