blob: b9a933b2a7a1211eee8711a88eb3a2d4f1755945 [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 re
import os
import argparse
from pathlib import Path
from common import convert_libname, lib_extract_from_path, files
from verilog2simple import print_cont
from verilog2full import Copyright_header
debug = False
debug_print = lambda x: print(x) if debug else 0
def main(in_file, out_file = None):
with open(in_file, 'r') as in_f:
contents = in_f.read()
if contents.find('endmodule') == -1 and contents.find('endprimitive') == -1:
return
lib = lib_extract_from_path(in_file)
# user defined primitives to modules
contents = re.sub(r"primitive ", "module ", contents)
contents = re.sub(r"endprimitive", "endmodule", contents)
# # remove alias modules
# contents = re.sub(r"(?s)module\s*\w*alias\(.*[\n]endmodule", "", contents)
# contents = re.sub(r"(?<!^)\s*\\.*?[\n]", "", contents)
re_mod_def_libname = re.compile(fr"\s*module\s*{lib}__")
contents = re.sub(r'(?<=,) *(?P<type>(input|outpu|inout))', '\n \g<type>', contents)
lines = contents.split("\n")
in_module = False
in_module_header = False
in_port_def = False
ports_decl = []
module_sep = re.compile(r"[\t ]*,[\t\n ]*")
module_regexp = re.compile(r"^\W*module.*?")
port_def_regexp = re.compile(r"^\s*(,\s*)?(inout|input|output) ")
output = ""
for line in lines:
module_def = module_regexp.search(line)
module_end = line.find("endmodule") != -1
port_def = port_def_regexp.search(line)
if port_def:
p = re.sub(r"(,|;|\);)$", "", line.strip())
ports_decl.append(p)
debug_print(f"# port found: '{p}'")
if any([module_end,
port_def,
module_def]):
output += line + "\n"
# hack- remove 'addr' input definition from s8fmlt files
# this input is not defined in module header
output = re.sub(r"[\n].* addr;", "", output)
# output = re.sub(r"\^\\n", "", output)
# strip empty ifdef/else/endif
output = re.sub(r"[`]ifdef.*[\n]([`]else\W*(//.*)?[\n])?[`]endif\W*(//.*)?[\n]", "", output)
# move commas from begining of line to end of previous
output = re.sub(r"(?s)[\n],", r",\n", output)
#move closing bracket to end of line
output = re.sub(r"\s*[\n]\s*\);", ");\n", output)
# remove empty modules definition
output = re.sub(r"(?s)\(\* blackbox \*\)\s*[\n]module\s*[a-z0-9_]*\s\(\s*\);\s*[\n]\s*endmodule\s*[\n]", "", output)
# split some weird ports_decl
temp = ports_decl
ports_decl = []
for x in temp:
if len(re.findall(r'(input|output|inout)', x)) > 1:
ports_decl.extend([y.strip() for y in x.split(',')])
else:
ports_decl.append(x)
port_names = []
for x in ports_decl :
x = re.sub(r',? ?(input|output|inout) ([\[\]:0-9]+)?', '', x)
if x.find(',') != -1:
for name in x.split(','):
port_names.append(name.strip())
else:
port_names.append(x.strip())
# assumes one module per file - which is now asserted by splitting
new_output = '\n(* blackbox *)\n'
new_output += re.search(r'module\s*\w*', output)[0]
new_output += ' (\n'
for x in port_names[:-1]:
new_output += ' ' + x + ',\n'
new_output += ' ' + port_names[-1] + ');\n'
for x in ports_decl:
new_output += ' ' + x + ';\n'
new_output += 'endmodule\n'
output = Copyright_header + new_output
if out_file is not None:
with open(out_file, 'w') as out_f:
out_f.write(output)
else:
print(">>> Output:")
print_cont(output)
def create_mod_header(module_header):
module_header = [x.replace("\t", "") for x in module_header if x.strip() != ""]
return ",\n ".join(module_header)
if __name__ == "__main__":
import doctest
fails, _ = doctest.testmod()
if fails>0:
exit()
else:
print("Tests Passed")
parser = argparse.ArgumentParser()
parser.add_argument(
"input",
help="The path to the source directory/file. If file is passed it will run in debug mode with no output file" +
"If dir is passed it will find '.full.v' files generate '.simple.v' in the same directory",
type=Path)
args = parser.parse_args()
if not os.path.isdir(args.input):
debug = True
main(str(args.input))
else:
files = args.input.rglob('*.full.v')
for f in files:
f = str(f)
print(f)
main(f, f[:-7] + ".blackbox.v")