blob: 80c236d79935cedd2bd68c847c567e800ae5e0d8 [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2020 The Skywater PDK Authors
#
# 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
#
# https://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.
import argparse
import os
import re
import simplejson as json
import subprocess
import sys
from multiprocessing import Pool
from pathlib import Path
def call_with_retcode(cmd):
print(cmd)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
stdout = stdout.decode("utf-8")
stderr = stderr.decode("utf-8")
retcode = p.wait()
print()
print('='*5)
print(stdout)
print('-'*5)
print(stderr)
print(retcode, '='*5)
print()
return retcode, stderr
def use_netlistsvg(json_file, out_file):
"""Draw module schematics using netlistsvg. Operates on json files. returns retcode"""
cmd = ["netlistsvg", json_file, "-o", out_file]
return call_with_retcode(cmd)
def use_yosys(command, files):
"""Execute yosys command, returns retcode"""
defines = {
'FUNCTIONAL': '=1', # Want the functional model
'NO_PRIMITIVES': '=1', # Yosys doesn't support primitives
'UNIT_DELAY': '', # Yosys doesn't support delays
}
actions = " ".join([
"verilog_defines " + " ".join("-D{}{}".format(a, b) for a, b in defines.items()) + ";",
"read_verilog " + " ".join(files) + ";",
"hierarchy -check -auto-top; " + command,
])
cmd = ["yosys", "-f", "verilog", "-p", actions]
return call_with_retcode(cmd)
def draw_schematics(verilog_path):
"""Draw module schematics using yosys+netlistsvg. Operates on verilog files.
Output file is placed in same directory as input"""
verilog_path = str(verilog_path)
verilog_dir = os.path.dirname(verilog_path)
verilog_file = os.path.basename(verilog_path)
verilog_base = verilog_file.split('.', 1)[0]
verilog_json = os.path.join(verilog_dir, verilog_base+".json")
verilog_schematic = os.path.join(verilog_dir, verilog_base+".schematic.svg")
print("Generating schematic for", str(verilog_path))
retcode, err = use_yosys(
#"prep; splitinout; write_json {}.json" % verilog_base,
"prep; write_json -compat-int {}".format(verilog_json),
[verilog_path],
)
if retcode != 0:
return verilog_path, err
json_data = ""
with open(verilog_json, "r") as f:
contents = f.read()
contents = re.sub('"type": "[^/"]+__', '"type": "', contents)
contents = re.sub('("[^"]*)\\.\\./[^/]*/skywater-pdk/libraries/[^/]*/v[^/]*/', '\\1./', contents)
with open(verilog_json, "w") as f:
f.write(contents)
retcode, err = use_netlistsvg(verilog_json, verilog_schematic)
if retcode != 0:
return verilog_path, err
return verilog_path, None
def files(p):
for f in p.rglob("*.v"):
d = str(f).split('/')
filename = d.pop(-1)
cell = d.pop(-1)
x = d.pop(-1)
if x != 'cells':
continue
ver = d.pop(-1)
lib = d.pop(-1)
o = lib + '__' + cell + '.v'
if filename != o:
continue
yield str(f)
# def split_inouts(in_file, out_file = None):
# """Split inout ports into inputs and outputs. Operates on yosys json files"""
# if out_file == None:
# out_file = in_file
# with open(in_file, 'r') as in_f:
# design = json.load(in_f)
# top_name = split_io.find_top_module(design)
# port_map, net_map = split_io.find_and_split_inout_ports_and_nets(design, top_name)
# output = json.dumps(design, sort_keys=True, indent=2)
# output = re.sub(r'"00000000000000000000000000000001"', "1", output)
# with open(out_file, 'w') as out_f:
# out_f.write(output)
if __name__ == "__main__":
for a in sys.argv[1:]:
if os.path.isfile(a):
draw_schematics(a)
continue
assert os.path.exists(a), a
p = Path(a)
print(p)
pool = Pool()
for verilog_path, err in pool.imap_unordered(draw_schematics, files(p)):
if err is not None:
msg = err + "\nError creating schematic file for:" + verilog_path+'\n\n'
print(msg, file=sys.stderr, flush=True)
else:
print("Finished creating schematic file for:", verilog_path)
pool.close()
pool.join()