blob: 15f0727d9edc3737c2bedb1826727971e68f9948 [file] [log] [blame] [edit]
#!/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 common
from common import mod_extract_from_path, convert_libname, version_extract_from_path
import subprocess
import re
import os
import argparse
import sys
import json
import datetime
import glob
from stat import S_IREAD, S_IRGRP, S_IROTH
from collections import defaultdict
from multiprocessing import Pool
from pathlib import Path
try:
from subprocess import DEVNULL
except ImportError:
DEVNULL = open(os.devnull, 'wb')
DEBUG = 0
Copyright_header = ('-- Copyright 2020 The Skywater PDK Authors\n'
'--\n'
'-- Licensed under the Apache License, Version 2.0 (the "License");\n'
'-- you may not use this file except in compliance with the License.\n'
'-- You may obtain a copy of the License at\n'
'--\n'
'-- https://www.apache.org/licenses/LICENSE-2.0\n'
'--\n'
'-- Unless required by applicable law or agreed to in writing, software\n'
'-- distributed under the License is distributed on an "AS IS" BASIS,\n'
'-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n'
'-- See the License for the specific language governing permissions and\n'
'-- limitations under the License.\n'
'\n')
skips = ["s8sram", "s8fmlt", "osu130", "openfpga", "sram",
"QA_s8_drc" #issue #145
]
diff_path = ["s8iom0s8", "scs8hd", "scs8hdll", "scs8hs", "scs8hvl", "scs8lp", "scs8ls", "scs8ms"]
INVALID_CELLVIEW = 110
OUTPUTFILE_EXISTS = 109
CELLVIEW_NOTFOUND = 108
MISSING_LIBRARY = 107
MISSING_FILE = 106
MULTIPLE_CELL_DEF = 105
TRANSLATION_ERROR = 104
SKIPPED = 103
COPY_ERROR = 102
PLUGIN_ERROR = 101
UNKNOWN_ERROR = 100
errors_msg = {UNKNOWN_ERROR: "unknown error",
PLUGIN_ERROR: "missing plugin",
COPY_ERROR: "error while coping",
SKIPPED: "skipped (due to filters)",
MULTIPLE_CELL_DEF: "multiple cell definitions",
MISSING_FILE: "file is missing",
MISSING_LIBRARY: "missing library",
CELLVIEW_NOTFOUND: "not found cellview",
OUTPUTFILE_EXISTS: "output file exists",
INVALID_CELLVIEW: "invalid cell view",
TRANSLATION_ERROR: "error while translating"}
TMP_OARESULT_DIR = "oaresults"
sourcetodests = defaultdict(list)
def remap_path(old_path, input_dir, output_dir):
"""
>>> remap_path('/home/fullpath/Documents/skywater-src-nda/scs8hdll/V0.1.0/oa/scs8hdll_dv/hrpoly_1p41/symbolic/layout.oa', 'skywater-src-nda', 'tmp')
'tmp/skywater-pdk/libraries/sky130_fd_sc_hdll/V0.1.0/cells/hrpoly_1p41/dv/oa/symbolic/sky130_fd_sc_hdll-hrpoly_1p41.layout.oa'
>>> remap_path('/home/fullpath/Documents/skywater-src-nda/s8/V2.0.1/VirtuosoOA/libs/s8rf/Aura_blocking/layout/layout.oa', 'skywater-src-nda', 'tmp')
'tmp/skywater-pdk/libraries/sky130_fd_pr_rf/V2.0.1/cells/aura_blocking/oa/layout/sky130_fd_pr_rf-aura_blocking.layout.oa'
>>> remap_path('/home/fullpath/Documents/skywater-src-nda/s8/V2.0.1/VirtuosoOA/libs/s8rf/Aura_blocking/layout/master.tag', 'skywater-src-nda', 'tmp')
'tmp/skywater-pdk/libraries/sky130_fd_pr_rf/V2.0.1/cells/aura_blocking/oa/layout/sky130_fd_pr_rf-aura_blocking.master.tag'
>>> remap_path('/home/fullpath/Documents/skywater-src-nda/s8/V2.0.1/VirtuosoOA/libs/s8rf/Aura_blocking/data.dm', 'skywater-src-nda', 'tmp')
'tmp/skywater-pdk/libraries/sky130_fd_pr_rf/V2.0.1/cells/aura_blocking/oa/Aura_blocking/sky130_fd_pr_rf-aura_blocking.data.dm'
>>> remap_path('/home/fullpath/Documents/skywater-src-nda/s8/V2.0.0/VirtuosoOA/libs/tech/condiode_grid/ads/data.dm', 'skywater-src-nda', 'tmp')
'tmp/skywater-pdk/libraries/sky130_fd_pr_base/V2.0.0/tech/condiode_grid/ads/data.dm'
>>> remap_path('/home/fullpath/Documents/skywater-src-nda/s8/V2.0.1/VirtuosoOA/libs/s8rf/Aura_blocking/data.dm', 'skywater-src-nda', 'tmp')
'tmp/skywater-pdk/libraries/sky130_fd_pr_rf/V2.0.1/cells/aura_blocking/oa/Aura_blocking/sky130_fd_pr_rf-aura_blocking.data.dm'
"""
parent_dir = str(input_dir).split("/")[-1]
output_dir = str(output_dir)
lib, mod = mod_extract_from_path(old_path)
new_lib = convert_libname(lib)
file_name = os.path.basename(old_path)
try:
ver = "V" + ".".join([str(v) for v in version_extract_from_path(old_path)])
except TypeError:
ver = ""
if lib != None and ver != "" and lib != "???":
if mod == None:
mod = lib
rest, f_name= os.path.split(old_path)
if mod not in old_path:
# Letter case was changed
temp = mod
mod = mod.lower()
f_name = f_name.lower().replace(temp, mod)
clean_mod = re.sub(r'_([0-9]{1,2}|m|lp|lp2)$', '', mod)
_, d_name = os.path.split(rest)
old_path = f"{output_dir}/skywater-pdk/libraries/{lib}/{ver}/cells/{clean_mod}/{'dv/' if '_dv/' in old_path else''}oa/{d_name}/{lib}-{mod}.{file_name}"
else:
index = old_path.find(parent_dir) + len(parent_dir)
old_path = output_dir +"/skywater-pdk/libraries" + old_path[index:]
old_path = old_path.replace("/s8iom0s8/", "/sky130_fd_io/")
old_path = old_path.replace("/s8/", "/sky130_fd_pr_base/")
old_path = old_path.replace("/VirtuosoOA/libs", "")
if lib != None and new_lib != None:
new_path = old_path.replace(lib, new_lib)
else:
new_path = old_path
return new_path
def filter(pn):
for skip in skips:
if skip in pn:
return True
return False
def check_status(output, call=None):
call_to_key = {
call_verilog2oa: "OAVLG",
call_def2oa: "OALEFDEF",
call_strm2oa: "OASTRM",
call_lef2oa: "OALEFDEF",
call_verilogAnnotate: "OAVLG"}
if call is not None:
key = call_to_key[call]
else:
key = "OA"
error_code_start = len(key) + 2
for s in output.split():
if key in s:
return s[error_code_start:-2]
if key != "OA":
return check_status(output)
return -100 # return unknown error code
def call_oa2verilog(libDefFile, lib, cell, view, verilog, pdk_home, sw_pdk_root):
verilog += ".v"
convert_cmd = ["bash", "oa_wrappers/oa2verilog_wrapper", f"{libDefFile}", f"{lib}", cell, f"{view}", f"{verilog}",
f"{pdk_home}", f"{sw_pdk_root}"]
return subprocess.Popen(convert_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def call_verilog2oa(libDefFile, lib, view, viewType, verilog, pdk_home, tmp_pdk_home, sw_pdk_root):
verilog += ".v"
convert_cmd = ["bash", "oa_wrappers/verilog2oa_wrapper", f"{libDefFile}", f"{lib}", f"{view}", f"{viewType}", f"{verilog}",
f"{pdk_home}", f"{tmp_pdk_home}", f"{sw_pdk_root}"]
return subprocess.Popen(convert_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def call_oa2def(libDefFile, lib, cell, view, def_file, pdk_home, tmp_pdk_home, sw_pdk_root):
def_file += ".def"
convert_cmd = ["bash", "oa_wrappers/oa2def_wrapper", f"{libDefFile}", f"{lib}", f"{cell}", f"{view}", f"{def_file}",
f"{pdk_home}", f"{tmp_pdk_home}", f"{sw_pdk_root}"]
return subprocess.Popen(convert_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def call_def2oa(libDefFile, lib, cell, view, def_file, pdk_home, tmp_pdk_home, sw_pdk_root):
def_file += ".def"
convert_cmd = ["bash", "oa_wrappers/def2oa_wrapper", f"{libDefFile}", f"{lib}", f"{cell}", f"{def_file}",
f"{pdk_home}", f"{tmp_pdk_home}", f"{sw_pdk_root}"]
return subprocess.Popen(convert_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def call_oa2lef(libDefFile, lib, cell, view, lef, pdk_home, tmp_pdk_home, sw_pdk_root):
lef += ".lef"
convert_cmd = ["bash", "oa_wrappers/oa2lef_wrapper", f"{libDefFile}", f"{lib}", f"{cell}", f"{lef}",
f"{pdk_home}", f"{tmp_pdk_home}", f"{sw_pdk_root}"]
return subprocess.Popen(convert_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def call_oa2strm(libDefFile, lib, cell, view, gds, pdk_home, tmp_pdk_home, sw_pdk_root):
gds += ".gds"
convert_cmd = ["bash", "oa_wrappers/oa2strm_wrapper", f"{libDefFile}", f"{lib}", f"{gds}",
f"{pdk_home}", f"{tmp_pdk_home}", f"{sw_pdk_root}"]
return subprocess.Popen(convert_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def call_lef2oa(libDefFile, lib, cell, view, lef, pdk_home, tmp_pdk_home, sw_pdk_root):
lef += ".lef"
convert_cmd = ["bash", "oa_wrappers/lef2oa_wrapper", f"{libDefFile}", f"{lib}", f"{lef}",
f"{pdk_home}", f"{tmp_pdk_home}", f"{sw_pdk_root}"]
return subprocess.Popen(convert_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def call_strm2oa(libDefFile, lib, cell, view, gds, pdk_home, tmp_pdk_home, sw_pdk_root):
gds += ".gds"
convert_cmd = ["bash", "oa_wrappers/strm2oa_wrapper", f"{libDefFile}", f"{lib}", f"{gds}",
f"{pdk_home}", f"{tmp_pdk_home}", f"{sw_pdk_root}"]
return subprocess.Popen(convert_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def call_verilogAnnotate(libDefFile, reflibs, refviews, cell, verilog, pdk_home, tmp_pdk_home, sw_pdk_root):
verilog += ".v"
convert_cmd = ["bash", "oa_wrappers/verilogAnnotate_wrapper", f"{libDefFile}", f"{reflibs}", f"{refviews}", f"{verilog}",
f"{pdk_home}", f"{tmp_pdk_home}", f"{sw_pdk_root}"]
return subprocess.Popen(convert_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def decode_rc(rc):
if int(rc) == 40106:
return MULTIPLE_CELL_DEF
elif int(rc) == 40058:
return OUTPUTFILE_EXISTS
elif int(rc) == 40002:
return TRANSLATION_ERROR
elif int(rc) == 40001:
return MISSING_FILE
elif int(rc) == 10055:
return PLUGIN_ERROR
elif int(rc) == 10032:
return PLUGIN_ERROR
elif int(rc) == 50103:
return PLUGIN_ERROR
elif int(rc) == 10022:
return MISSING_LIBRARY
elif int(rc) == 10016:
return MISSING_FILE
elif int(rc) == 1422:
return OUTPUTFILE_EXISTS
elif int(rc) == 1005:
return CELLVIEW_NOTFOUND
elif int(rc) == 1014:
return INVALID_CELLVIEW
elif int(rc) != 0:
return UNKNOWN_ERROR
return None
def copy_file(input_path, output_path):
if DEBUG:
print(f"Copy from: {input_path} to {output_path}")
if not os.path.exists(input_path):
return COPY_ERROR
output_folder = os.path.dirname(output_path)
os.makedirs(output_folder, exist_ok=True) #create output folder if not exists
cp_cmd = ["cp", f"{input_path}", f"{output_path}"]
proc = subprocess.run(cp_cmd)
return proc.returncode
def move_file(input_path, output_path):
if DEBUG:
print(f"Move from: {input_path} to {output_path}")
if not os.path.exists(input_path):
return COPY_ERROR
output_folder = os.path.dirname(output_path)
os.makedirs(output_folder, exist_ok=True) #create output folder if not exists
mv_cmd = ["mv", f"{input_path}", f"{output_path}"]
proc = subprocess.run(mv_cmd)
return proc.returncode
def copy_folder(input_path, output_path):
print(f"Copy from: {input_path} to {output_path}")
if not os.path.exists(input_path):
return COPY_ERROR
if os.path.exists(output_path):
return 0
output_folder = os.path.dirname(output_path)
os.makedirs(output_folder, exist_ok=True) #create output folder if not exists
cp_cmd = ["cp", "-r", f"{input_path}", f"{output_path}"]
proc = subprocess.run(cp_cmd)
return proc.returncode
return {"return_code": 0, "path": pn}
def pack(pn, pack_function):
if filter(pn):
return None
pn_copy = pn
pn_version = pn_copy.replace(str(args.input), "").split("/")
pn_version = f"{pn_version[1]}/{pn_version[2]}"
skip = False
for diff in diff_path:
if diff in str(pn):
skip = True
if not skip:
PDK_HOME = ENV_PDK_HOME = f'{args.tmp}/{TMP_OARESULT_DIR}/{pn_version}/'
TMP_PDK_HOME = f'.'
else:
ENV_PDK_HOME = f'{args.tmp}/{TMP_OARESULT_DIR}/s8/V1.3.0/'
TMP_PDK_HOME = PDK_HOME = f'{args.tmp}{TMP_OARESULT_DIR}/{pn_version}/oa'
input_dir = os.path.dirname(pn)
view = os.path.basename(input_dir)
cell = os.path.basename(os.path.split(input_dir)[0])
lib = os.path.basename(os.path.split(os.path.split(input_dir)[0])[0])
output_path = remap_path(pn, args.input, args.tmp)
output_file, ext = os.path.splitext(output_path)
os.makedirs(os.path.dirname(output_path), exist_ok=True)
viewType_dict = { "layout.oa": "maskLayout",
"sch.oa": "schematic",
"symbol.oa": "schematicSymbol",
"netlist.oa": "netlist"}
filename = os.path.basename(pn)
viewType = viewType_dict[filename]
SW_PDK_ROOT = f"{str(args.tmp)}/{TMP_OARESULT_DIR}"
#Change output dir
if not skip:
result_path = pn.replace(f'{args.input}/', f'{args.tmp}/{TMP_OARESULT_DIR}/')
os.makedirs(os.path.dirname(result_path), exist_ok=True)
os.makedirs(f"{PDK_HOME}/VirtuosoOA/libs/s8phirs_10r", exist_ok=True)
os.makedirs(f"{PDK_HOME}/VirtuosoOA/libs/tech", exist_ok=True)
os.makedirs(f"{PDK_HOME}/VirtuosoOA/libs/technology_library", exist_ok=True)
os.makedirs(f"{PDK_HOME}/VirtuosoOA/libs/s8rf2", exist_ok=True)
os.makedirs(f"{PDK_HOME}/VirtuosoOA/libs/s8rf2_dv", exist_ok=True)
else:
PDK_HOME = ENV_PDK_HOME = f'{args.input}/{pn_version}/'
output_dir = os.path.dirname(pn.replace(str(args.input), f"{str(args.tmp)}/{TMP_OARESULT_DIR}"))
os.makedirs(f"{output_dir}", exist_ok=True)
libDefFile_path = f"{args.tmp}/{TMP_OARESULT_DIR}/lib.defs"
proc = None
if pack_function is call_verilog2oa:
proc = pack_function(libDefFile_path, lib, view, viewType, output_file, ENV_PDK_HOME, TMP_PDK_HOME, SW_PDK_ROOT)
elif pack_function is not None:
proc = pack_function(libDefFile_path, lib, view, cell, output_file, ENV_PDK_HOME, TMP_PDK_HOME, SW_PDK_ROOT)
return proc
def unpack(pn, unpack_function):
if filter(pn):
return None
pn_copy = pn
pn_version = pn_copy.replace(str(args.input), "").split("/")
pn_version = f"{pn_version[1]}/{pn_version[2]}"
skip = False
#For libraries that are not in s8 folder, we need to set explicite PDK_HOME to s8
#It should not be used anyway, but oa tools needs to find all libraries
#Even if it is not using them
for diff in diff_path:
if diff in str(pn):
skip = True
if not skip:
PDK_HOME = ENV_PDK_HOME = f'{args.input}/{pn_version}/'
else:
ENV_PDK_HOME = f'{args.input}/s8/V1.3.0/'
SW_PDK_ROOT = args.input
input_dir = os.path.dirname(pn)
view = os.path.basename(input_dir)
cell = os.path.basename(os.path.split(input_dir)[0])
lib = os.path.basename(os.path.split(os.path.split(input_dir)[0])[0])
output_path = remap_path(pn, args.input, args.tmp)
output_file, ext = os.path.splitext(output_path)
os.makedirs(os.path.dirname(output_path), exist_ok=True)
viewType_dict = { "layout.oa": "maskLayout",
"sch.oa": "schematic",
"symbol.oa": "schematicSymbol",
"netlist.oa": "netlist"}
filename = os.path.basename(pn)
viewType = viewType_dict[filename]
libDefFile_path = f"{args.input}/lib.defs"
proc = None
if unpack_function is not None:
proc = unpack_function(libDefFile_path, lib, cell, view, output_file, ENV_PDK_HOME, SW_PDK_ROOT)
return proc
def copy_repacked_to_output():
global sourcetodests
oa_files = glob.glob(f"{args.tmp}/{TMP_OARESULT_DIR}/**/*.oa", recursive=True)
dm_files = glob.glob(f"{args.tmp}/{TMP_OARESULT_DIR}/**/*.dm", recursive=True)
print(f"Found {len(oa_files)} oa files in {args.tmp}/{TMP_OARESULT_DIR}!")
print(f"Found {len(dm_files)} dm files in {args.tmp}/{TMP_OARESULT_DIR}!")
for oa_file in oa_files:
output_path = remap_path(oa_file, args.input, args.tmp)
output_dir = os.path.dirname(oa_file)
filename = os.path.basename(oa_file)
master_tag_content = [Copyright_header, filename]
with open(f"{output_dir}/master.tag", "w+") as master_tag:
master_tag.writelines(master_tag_content)
sourcetodests[f"{os.path.dirname(oa_file)}/master.tag"].append(f"{output_dir}/master.tag")
if copy_file(oa_file, output_path):
return {"return_code": COPY_ERROR, "path": oa_file}
else:
sourcetodests[oa_file].append(output_path)
for dm_file in dm_files:
output_path = remap_path(dm_file, args.input, args.tmp)
if copy_file(dm_file, output_path):
return {"return_code": COPY_ERROR, "path": dm_file}
else:
sourcetodests[dm_file].append(output_path)
def absolute_path(path):
return path.resolve()
def make_readonly_oalib():
oa_files = glob.glob(f"{args.input}/**/.oalib", recursive=True)
for oa_file in oa_files:
os.chmod(oa_file, S_IREAD|S_IRGRP|S_IROTH)
os.system(f"chattr +i {oa_file}")
def make_readagain_oalib():
oa_files = glob.glob(f"{args.input}/**/.oalib", recursive=True)
for oa_file in oa_files:
os.system(f"chattr -i {oa_file}")
if __name__ == "__main__":
import doctest
fails, _ = doctest.testmod()
if fails>0:
exit(1)
parser = argparse.ArgumentParser()
parser.add_argument(
"input",
help="The path to the source directory/file",
type=Path)
parser.add_argument(
"output",
help="The path to the output directory",
type=Path)
parser.add_argument(
"tmp",
help="The path to the output directory",
type=Path)
parser.add_argument(
"--sourcetodests",
help="Mapping from source files to destination files",
type=Path)
parser.add_argument(
"--cpus",
help="Number od CPUs in the system",
type=int)
args = parser.parse_args()
args.input = args.input.resolve()
args.output = args.output.resolve()
args.tmp = args.tmp.resolve()
make_readonly_oalib()
# FIXME: set sys.argv as common.files echos back command-line args if sys.argv is > 1
sys.argv = [sys.argv[0]]
os.environ["SW_PDK_ROOT"] = str(args.input)
os.environ["PDK_HOME"] = f"{str(args.input)}/s8/V2.0.1/"
def copy_lib_defs():
copy_dict = [{"from": f"{args.input}/lib.defs", "to": f"{args.tmp}/{TMP_OARESULT_DIR}/lib.defs"},
{"from": f"{args.input}/s8iom0s8/V0.2.0/oa/cds.lib", "to": f"{args.tmp}/{TMP_OARESULT_DIR}/s8iom0s8/V0.2.0/oa/cds.lib"},
{"from": f"{args.input}/s8iom0s8/V0.2.1/oa/cds.lib", "to": f"{args.tmp}/{TMP_OARESULT_DIR}/s8iom0s8/V0.2.1/oa/cds.lib"},
{"from": f"{args.input}/s8iom0s8/V0.0.0/oa/cds.lib", "to": f"{args.tmp}/{TMP_OARESULT_DIR}/s8iom0s8/V0.0.0/oa/cds.lib"},
{"from": f"{args.input}/s8iom0s8/V0.1.0/oa/cds.lib", "to": f"{args.tmp}/{TMP_OARESULT_DIR}/s8iom0s8/V0.1.0/oa/cds.lib"},
{"from": f"{args.input}/scs8hdll/V0.1.0/oa/cds.lib", "to": f"{args.tmp}/{TMP_OARESULT_DIR}/scs8hdll/V0.1.0/oa/cds.lib"},
{"from": f"{args.input}/scs8lp/V0.0.0/oa/cds.lib", "to": f"{args.tmp}/{TMP_OARESULT_DIR}/scs8lp/V0.0.0/oa/cds.lib"},
{"from": f"{args.input}/scs8ms/V0.0.0/oa/cds.lib", "to": f"{args.tmp}/{TMP_OARESULT_DIR}/scs8ms/V0.0.0/oa/cds.lib"},
{"from": f"{args.input}/scs8ls/V0.1.0/oa/cds.lib", "to": f"{args.tmp}/{TMP_OARESULT_DIR}/scs8ls/V0.1.0/oa/cds.lib"},
{"from": f"{args.input}/scs8hd/V0.0.1/oa/cds.lib", "to": f"{args.tmp}/{TMP_OARESULT_DIR}/scs8hd/V0.0.1/oa/cds.lib"},
{"from": f"{args.input}/scs8hs/V0.0.0/oa/cds.lib", "to": f"{args.tmp}/{TMP_OARESULT_DIR}/scs8hs/V0.0.0/oa/cds.lib"},
{"from": f"{args.input}/scs8hvl/V0.0.0/oa/cds.lib", "to": f"{args.tmp}/{TMP_OARESULT_DIR}/scs8hvl/V0.0.0/oa/cds.lib"},
{"from": f"{args.input}/scs8hvl/V0.0.1/oa/cds.lib", "to": f"{args.tmp}/{TMP_OARESULT_DIR}/scs8hvl/V0.0.1/oa/cds.lib"},
{"from": f"{args.input}/s8/V1.0.1/VirtuosoOA/examples/cds.lib", "to": f"{args.tmp}/{TMP_OARESULT_DIR}/s8/V1.0.1/VirtuosoOA/examples/cds.lib"},
{"from": f"{args.input}/s8/V1.1.0/VirtuosoOA/examples/cds.lib", "to": f"{args.tmp}/{TMP_OARESULT_DIR}/s8/V1.1.0/VirtuosoOA/examples/cds.lib"},
{"from": f"{args.input}/s8/V1.2.1/VirtuosoOA/examples/cds.lib", "to": f"{args.tmp}/{TMP_OARESULT_DIR}/s8/V1.2.1/VirtuosoOA/examples/cds.lib"},
{"from": f"{args.input}/s8/V1.2.0/VirtuosoOA/examples/cds.lib", "to": f"{args.tmp}/{TMP_OARESULT_DIR}/s8/V1.2.0/VirtuosoOA/examples/cds.lib"},
{"from": f"{args.input}/s8/V2.0.1/VirtuosoOA/examples/cds.lib", "to": f"{args.tmp}/{TMP_OARESULT_DIR}/s8/V2.0.1/VirtuosoOA/examples/cds.lib"},
{"from": f"{args.input}/s8/V1.0.0/VirtuosoOA/examples/cds.lib", "to": f"{args.tmp}/{TMP_OARESULT_DIR}/s8/V1.0.0/VirtuosoOA/examples/cds.lib"},
{"from": f"{args.input}/s8/V1.3.0/VirtuosoOA/examples/cds.lib", "to": f"{args.tmp}/{TMP_OARESULT_DIR}/s8/V1.3.0/VirtuosoOA/examples/cds.lib"},
{"from": f"{args.input}/s8/V2.0.0/VirtuosoOA/examples/cds.lib", "to": f"{args.tmp}/{TMP_OARESULT_DIR}/s8/V2.0.0/VirtuosoOA/examples/cds.lib"},
{"from": f"{args.input}/s8/V2.0.1/DRC/dev/libs/cds.lib", "to": f"{args.tmp}/{TMP_OARESULT_DIR}/s8/V2.0.1/DRC/dev/libs/cds.lib"}
]
for copy in copy_dict:
if not os.path.exists(copy["to"]):
if copy_file(copy["from"], copy["to"]):
print(f"Error copying {copy['from']} to {copy['to']}! Exiting.")
sys.exit(1)
copy_lib_defs()
os.system(f"find {args.tmp}/{TMP_OARESULT_DIR} -name cds.lib | xargs sed -i 's/\.\//$TMP_PDK_HOME\//g'") #Add $TMP_PDK_HOME to s8iom0s8, scs8hdll, scs8lp, scs8ms, scs8ls, scs8hd, scs8hs, scs8hvl to redirect output files
#Not needed as QA_s8_drc is now skipped #145
#copy_folder(str(args.input), f"{args.tmp}/skywater-src-nda")
#args_input_old = str(args.input)
#args.input = f"{args.tmp}/skywater-src-nda"
# Move skywater-src-nda to tmp and rename files with #
#for file_path in common.files([".oa"]):
# if "#" in str(file_path):
# copy_file(file_path, str(file_path).replace(args_input_old, f"{str(args.tmp)}/skywater-src-nda").replace("#", "_"))
begin_time = datetime.datetime.now()
repack_sequence = [
{"unpack": call_oa2verilog, "pack": call_verilog2oa, "name": "oa2verilog"},
#{"unpack": call_oa2strm, "pack": call_strm2oa, "name": "oa2strm"},
#{"unpack": None, "pack": call_verilogAnnotate, "name": "verilogAnnotate"},
#{"unpack": call_oa2def, "pack": call_def2oa, "name": "oa2def"},
#{"unpack": call_oa2lef, "pack": call_lef2oa, "name": "oa2lef"}
]
max_parallel_jobs = 2 * args.cpus
file_paths = [f for f in common.files([".oa"])]
# fix paths to point to tmp dir
#fixed_paths = []
#for path in file_paths:
# fixed_paths.append(path.replace(args_input_old, f"{str(args.tmp)}/skywater-src-nda"))
def run_unpack_job(file_path, sequence):
#if "#" in str(file_path):
# file_path = str(file_path).replace("#", "_")
return unpack(file_path, sequence["unpack"])
def run_pack_job(file_path, sequence):
#if "#" in str(file_path):
# file_path = str(file_path).replace("#", "_")
global TMP_OARESULT_DIR
if sequence["pack"] is call_verilog2oa:
TMP_OARESULT_DIR = f"oaresults{job}"
copy_lib_defs()
else:
TMP_OARESULT_DIR = "oaresults"
return pack(file_path, sequence["pack"])
import time
import sys
for sequence in repack_sequence:
errored = defaultdict(list)
skipped = defaultdict(list)
unpack_job_success = []
for oa_job in [run_unpack_job, run_pack_job]:
print(f"Starting {sequence['name']} {'pack' if oa_job is run_pack_job else 'unpack'} job")
files_left = len(file_paths)
all_files = files_left
running_jobs = [None for i in range(max_parallel_jobs)]
current_file = 0
error_count = 0
good_count = 0
skipped_count = 0
error_map = defaultdict(list)
job_to_file_path = {}
while files_left > 0:
for job in range(max_parallel_jobs):
# empty slot - start a new job
if running_jobs[job] is None:
if current_file < all_files:
file_path = file_paths[current_file]
if (oa_job is run_pack_job and file_path in unpack_job_success) or oa_job is run_unpack_job:
running_jobs[job] = oa_job(file_path, sequence)
job_to_file_path[job] = file_path
current_file += 1
# check if this job was skipped
if running_jobs[job] is None:
files_left -= 1
skipped_count += 1
else:
#check if the job finished
if running_jobs[job].poll() is not None:
files_left -= 1
if running_jobs[job].returncode != 0:
error_count += 1
stderr = running_jobs[job].stderr.read().decode('utf-8')
error_map[errors_msg[decode_rc(check_status(stderr, sequence["pack"]))]].append({file_path: stderr})
print(f"Job: {job}: {stderr}")
else:
good_count += 1
if oa_job is run_unpack_job:
unpack_job_success.append(job_to_file_path[job])
if sequence["pack"] is call_verilog2oa and running_jobs[job].returncode == 0: # only copy if we produced correct oa file and sequence is verilog2oa
file_path_copy = job_to_file_path[job]
move_file_path = file_path_copy.replace(str(args.input), f"{args.tmp}/oaresults{job}")
move_output_path = file_path_copy.replace(str(args.input), f"{args.tmp}/oaresults")
move_file(move_file_path, move_output_path)
#start a new job
if current_file < all_files:
file_path = file_paths[current_file]
if (oa_job is run_pack_job and file_path in unpack_job_success) or oa_job is run_unpack_job:
running_jobs[job] = oa_job(file_path, sequence)
job_to_file_path[job] = file_path
current_file += 1
# check if this job was skipped
if running_jobs[job] is None:
files_left -= 1
skipped_count += 1
else:
running_jobs[job] = None
#time.sleep(0.00001)
runname = sequence["name"]
if oa_job == run_unpack_job:
runname += "[unpack]"
else:
runname += "[pack]"
if sequence["name"] == "oa2verilog":
log_name = f"errored-{runname.replace('[', '-').replace(']', '')}.txt"
with open(log_name, mode='wt', encoding='utf-8') as myfile:
json.dump(error_map, myfile, indent=2)
sys.stderr.write(" >>> OA |%s|: [%s] Error count = %d -- %.2f %%\n" % (runname,time.strftime('%H:%M:%S'),error_count,100.0 * error_count / all_files))
sys.stderr.write(" >>> OA |%s|: [%s] Success count = %d -- %.2f %%\n" % (runname,time.strftime('%H:%M:%S'),good_count, 100.0 * good_count / all_files))
sys.stderr.write(" >>> OA |%s|: [%s] Skipped count = %d -- %.2f %%\n" % (runname,time.strftime('%H:%M:%S'),skipped_count, 100.0 * skipped_count / all_files))
sys.stderr.flush()
with open(f'errored-{sequence["name"]}.txt', mode='wt', encoding='utf-8') as myfile:
json.dump(errored, myfile, indent=2)
with open(f'skipped-{sequence["name"]}.txt', mode='wt', encoding='utf-8') as myfile:
json.dump(skipped, myfile, indent=2)
TMP_OARESULT_DIR = "oaresults"
copy_repacked_to_output()
with open(args.sourcetodests, 'w') as srctodst:
json.dump(sourcetodests, srctodst, indent=2)
print("Done!")
print(f"Took: {datetime.datetime.now() - begin_time}")
make_readagain_oalib()