Lot more hacks.
diff --git a/scripts/python-skywater-pdk/generate_metadata_json.py b/scripts/python-skywater-pdk/generate_metadata_json.py
index e057762..e02bfa1 100755
--- a/scripts/python-skywater-pdk/generate_metadata_json.py
+++ b/scripts/python-skywater-pdk/generate_metadata_json.py
@@ -16,6 +16,7 @@
import re
import sys
import traceback
+from collections import defaultdict
from skywater_pdk import base, corners, drives
@@ -73,6 +74,8 @@
re.compile('lpflow_'),
re.compile('macro_sparecell'),
re.compile('macro_sync'),
+ re.compile('lsbuflv2hv_simple'),
+ re.compile('_lp'),
]
def should_ignore(f, x=IGNORE):
@@ -131,10 +134,11 @@
assert fname is None, (cellpath, dcell, fname)
extensions = set()
- dcorners = set()
+ dcorners = defaultdict(list)
ddrives = set()
checksums = {}
errors = []
+ warnings = []
for fname, fpath in files:
if should_ignore(fpath):
continue
@@ -159,8 +163,9 @@
continue
try:
- fcorner = corners.parse_filename(fextra)
- dcorners.add(fcorner)
+ fcorner, corner_extra = corners.parse_filename(fextra)
+ corner_extra = "_".join(corner_extra)
+ dcorners[corner_extra].append(fcorner)
except Exception as e:
traceback.print_exc()
errors.append('Invalid corner: {} -- {} (from {})'.format(e, fextra, fpath))
@@ -184,18 +189,18 @@
if 'full.v' in extensions:
o = None
- for ext in ['full.v', 'simple.v']:
- fname = os.path.join(cellpath, "{}.{}".format(dcell.fullname, ext))
+ for ext in ['.full.v', '.simple.v', '_1.full.v', '_1.simple.v']:
+ fname = os.path.join(cellpath, "{}{}".format(dcell.fullname, ext))
if not os.path.exists(fname):
- errors.append("Missing {} file".format(fname))
+ warnings.append("Missing {} file".format(fname))
continue
o = vlog_ex.extract_objects(fname)
if not o or len(o) != 1:
- errors.append("Invalid {} file ({})".format(fname, o))
+ warnings.append("Invalid {} file ({})".format(fname, o))
continue
o = o[0]
if not o:
- errors.append("Invalid {} file ({})".format(fname, o))
+ warnings.append("Invalid {} file ({})".format(fname, o))
break
if o:
assert dcell.fullname in o.name, (dcell.fullname, o)
@@ -222,6 +227,9 @@
'signal': non_pwr,
'power': pwr,
}
+ else:
+ errors.extend(warnings)
+ warnings.clear()
extensions.add('metadata.json')
@@ -230,7 +238,16 @@
else:
metadata['files'] = checksums
if dcorners:
- metadata['corners'] = [d.to_dict() for d in sorted(dcorners)]
+ if len(dcorners) > 1:
+ print(dcorners.keys())
+ o = []
+ for k in dcorners:
+ x = [d.to_dict() for d in sorted(dcorners[k])]
+ if k != '':
+ for i in range(0, len(x)):
+ x[i]['extra'] = k
+ o.extend(x)
+ metadata['corners'] = o
else:
errors.append('Missing corners for: {}\n'.format(cellpath))
@@ -246,6 +263,15 @@
json.dump(metadata, f, sort_keys=True, indent=" ")
print("Wrote:", mdata_file)
+ if warnings:
+ sys.stderr.flush()
+ sys.stdout.flush()
+ print("Warnings:")
+ print(" ", "\n ".join(warnings))
+ print()
+ sys.stderr.flush()
+ sys.stdout.flush()
+
if errors:
raise ValueError("\n".join(str(e) for e in errors))
@@ -259,9 +285,20 @@
process(p)
except Exception as e:
if not should_ignore(p, ALLOW_ERRORS):
+ sys.stderr.flush()
+ sys.stdout.flush()
+ print('\n'*4, file=sys.stderr)
+ print("FATAL ERROR while processing:", p, file=sys.stderr)
+ print('-'*75, file=sys.stderr)
+ sys.stderr.flush()
+ sys.stdout.flush()
raise
- print("Failed to process ignorable:", p)
+ print(file=sys.stderr)
+ print("Failed to process ignorable:", p, file=sys.stderr)
+ print('-'*75, file=sys.stderr)
traceback.print_exc()
+ print('-'*75, file=sys.stderr)
+ sys.stderr.flush()
if __name__ == "__main__":
diff --git a/scripts/python-skywater-pdk/generate_top_verilog.py b/scripts/python-skywater-pdk/generate_top_verilog.py
index e2df032..ef8d07c 100755
--- a/scripts/python-skywater-pdk/generate_top_verilog.py
+++ b/scripts/python-skywater-pdk/generate_top_verilog.py
@@ -145,6 +145,19 @@
assert len(d) == 1, d
drive_name = list(d.keys())[0]
drive_value = list(d.values())[0]
+ if drive_name == 'units':
+ pass
+ elif drive_name == 'lp_variant':
+ if drive_value == 0:
+ drive_value = 'lp'
+ else:
+ drive_value = 'lp'+str(drive_value+1)
+ elif drive_name == "minimum":
+ assert drive_value is None
+ drive_value = "m"
+ else:
+ raise TypeError("Unknown drive:"+repr(d))
+
dvfile = os.path.join(cellpath, "{}_{}.v".format(mdata['fullname'], drive_value))
write_verilog(mdata, dvfile, list(d.items())[0])
echo_file(dvfile)
diff --git a/scripts/python-skywater-pdk/skywater_pdk/analyze.py b/scripts/python-skywater-pdk/skywater_pdk/analyze.py
index 44c0ce8..148cc3c 100644
--- a/scripts/python-skywater-pdk/skywater_pdk/analyze.py
+++ b/scripts/python-skywater-pdk/skywater_pdk/analyze.py
@@ -42,8 +42,8 @@
if extension in ('wrap.lib', 'wrap.json', 'cell.lib', 'cell.json'):
try:
- corners = parse_filename_corners(extra)
- print(corners)
+ corners, extra = parse_filename_corners(extra)
+ print(corners, extra)
except Exception as e:
traceback.print_exc()
return
diff --git a/scripts/python-skywater-pdk/skywater_pdk/base.py b/scripts/python-skywater-pdk/skywater_pdk/base.py
index 07b4708..6c6c561 100644
--- a/scripts/python-skywater-pdk/skywater_pdk/base.py
+++ b/scripts/python-skywater-pdk/skywater_pdk/base.py
@@ -172,7 +172,7 @@
Cell(name='top_powerhv_hvc_wpad', library=Library(node=LibraryNode.SKY130, source=LibrarySource('fd'), type=LibraryType.io, name='', version=LibraryVersion(milestone=0, major=1, minor=0, commits=0, hash='')))
>>> from skywater_pdk.corners import parse_filename as pf_corners
>>> pf_corners(t.pop(0))
- Corner(corner=(CornerType.t, CornerType.t), volts=(1.8, 3.3), temps=(100,), flags=None)
+ (Corner(corner=(CornerType.t, CornerType.t), volts=(1.8, 3.3), temps=(100,), flags=None), [])
>>> t.pop(0)
'wrap.json'
diff --git a/scripts/python-skywater-pdk/skywater_pdk/corners.py b/scripts/python-skywater-pdk/skywater_pdk/corners.py
index 184218b..214a8fb 100644
--- a/scripts/python-skywater-pdk/skywater_pdk/corners.py
+++ b/scripts/python-skywater-pdk/skywater_pdk/corners.py
@@ -33,6 +33,15 @@
# "ws" is "worst-case speed" and corresponds to "ss"
CornerTypeMappings["ws"] = "ss"
+CornerTypeValues = [
+ 'ff',
+ 'ss',
+ 'tt',
+ 'fs',
+ 'sf',
+]
+CORNER_TYPE_REGEX = re.compile('[tfs][tfs]')
+
class CornerType(OrderedFlag):
"""
@@ -77,6 +86,7 @@
nointpr = 'No internal power'
lv = 'Low voltage'
hv = 'High voltage'
+ lowhv = 'Low High Voltage'
ccsnoise = 'Composite Current Source Noise'
pwr = 'Power'
xx = 'xx'
@@ -124,34 +134,40 @@
"""Extract corner information from a filename.
>>> parse_filename('tt_1p80V_3p30V_3p30V_25C')
- Corner(corner=(CornerType.t, CornerType.t), volts=(1.8, 3.3, 3.3), temps=(25,), flags=None)
+ (Corner(corner=(CornerType.t, CornerType.t), volts=(1.8, 3.3, 3.3), temps=(25,), flags=None), [])
>>> parse_filename('sky130_fd_io__top_ground_padonlyv2__tt_1p80V_3p30V_3p30V_25C.wrap.lib')
- Corner(corner=(CornerType.t, CornerType.t), volts=(1.8, 3.3, 3.3), temps=(25,), flags=None)
+ (Corner(corner=(CornerType.t, CornerType.t), volts=(1.8, 3.3, 3.3), temps=(25,), flags=None), [])
>>> parse_filename('sky130_fd_sc_ms__tt_1p80V_100C.wrap.json')
- Corner(corner=(CornerType.t, CornerType.t), volts=(1.8,), temps=(100,), flags=None)
+ (Corner(corner=(CornerType.t, CornerType.t), volts=(1.8,), temps=(100,), flags=None), [])
>>> parse_filename('sky130_fd_sc_ms__tt_1p80V_100C.wrap.lib')
- Corner(corner=(CornerType.t, CornerType.t), volts=(1.8,), temps=(100,), flags=None)
+ (Corner(corner=(CornerType.t, CornerType.t), volts=(1.8,), temps=(100,), flags=None), [])
>>> parse_filename('sky130_fd_sc_ms__tt_1p80V_25C_ccsnoise.wrap.json')
- Corner(corner=(CornerType.t, CornerType.t), volts=(1.8,), temps=(25,), flags=(CornerFlag.ccsnoise,))
+ (Corner(corner=(CornerType.t, CornerType.t), volts=(1.8,), temps=(25,), flags=(CornerFlag.ccsnoise,)), [])
>>> parse_filename('sky130_fd_sc_ms__wp_1p65V_n40C.wrap.json')
- Corner(corner=(CornerType.f, CornerType.f), volts=(1.65,), temps=(-40,), flags=None)
+ (Corner(corner=(CornerType.f, CornerType.f), volts=(1.65,), temps=(-40,), flags=None), [])
>>> parse_filename('sky130_fd_sc_ms__wp_1p95V_85C_pwr.wrap.lib')
- Corner(corner=(CornerType.f, CornerType.f), volts=(1.95,), temps=(85,), flags=(CornerFlag.pwr,))
+ (Corner(corner=(CornerType.f, CornerType.f), volts=(1.95,), temps=(85,), flags=(CornerFlag.pwr,)), [])
>>> parse_filename('sky130_fd_sc_ms__wp_1p95V_n40C_ccsnoise.wrap.json')
- Corner(corner=(CornerType.f, CornerType.f), volts=(1.95,), temps=(-40,), flags=(CornerFlag.ccsnoise,))
+ (Corner(corner=(CornerType.f, CornerType.f), volts=(1.95,), temps=(-40,), flags=(CornerFlag.ccsnoise,)), [])
>>> parse_filename('sky130_fd_sc_ms__wp_1p95V_n40C_pwr.wrap.lib')
- Corner(corner=(CornerType.f, CornerType.f), volts=(1.95,), temps=(-40,), flags=(CornerFlag.pwr,))
+ (Corner(corner=(CornerType.f, CornerType.f), volts=(1.95,), temps=(-40,), flags=(CornerFlag.pwr,)), [])
>>> parse_filename('sky130_fd_sc_hd__a2111o_4__ss_1p76V_n40C.cell.json')
- Corner(corner=(CornerType.s, CornerType.s), volts=(1.76,), temps=(-40,), flags=None)
+ (Corner(corner=(CornerType.s, CornerType.s), volts=(1.76,), temps=(-40,), flags=None), [])
+
+ >>> parse_filename('sky130_fd_sc_ls__lpflow_lsbuf_lh_1__lpflow_wc_lh_level_shifters_ss_1p95V_n40C.cell.json')
+ (Corner(corner=(CornerType.s, CornerType.s), volts=(1.95,), temps=(-40,), flags=None), ['wc', 'lh', 'level', 'shifters'])
+
+ >>> parse_filename('sky130_fd_sc_hvl__lsbufhv2hv_hl_1__ff_5p50V_lowhv_1p65V_lv_ss_1p60V_100C.cell.json')
+ (Corner(corner=(CornerType.f, CornerType.s), volts=(5.5, 1.65, 1.6), temps=(100,), flags=(CornerFlag.lowhv, CornerFlag.lv)), [])
"""
if base.SEPERATOR in pathname:
@@ -178,6 +194,15 @@
kw['temps'] = []
bits = extra.split("_")
+ random = []
+ while len(bits) > 0:
+ b = bits.pop(0)
+ try:
+ kw['corner'] = CornerType.parse(b)
+ break
+ except TypeError as e:
+ random.append(b)
+
while len(bits) > 0:
b = bits.pop(0)
@@ -187,11 +212,19 @@
elif TEMP_REGEX.match(b):
assert b.endswith('C'), b
kw['temps'].append(int(b[:-1].replace('n', '-')))
+ elif CORNER_TYPE_REGEX.match(b):
+ # FIXME: These are horrible hacks that should be removed.
+ assert len(b) == 2, b
+ assert b[0] == b[1], b
+ assert 'corner' in kw, kw['corners']
+ assert len(kw['corner']) == 2, kw['corners']
+ assert kw['corner'][0] == kw['corner'][1], kw['corners']
+ other_corner = CornerType.parse(b)
+ assert len(other_corner) == 2, other_corner
+ assert other_corner[0] == other_corner[1], other_corner
+ kw['corner'][1] = other_corner[0]
else:
- if 'corner' not in kw:
- kw['corner'] = CornerType.parse(b)
- else:
- kw['flags'].append(CornerFlag.parse(b))
+ kw['flags'].append(CornerFlag.parse(b))
for k, v in kw.items():
kw[k] = tuple(v)
@@ -199,7 +232,10 @@
if not kw['flags']:
del kw['flags']
- return Corner(**kw)
+ if 'corner' not in kw:
+ raise TypeError('Invalid corner value: '+extra)
+
+ return Corner(**kw), random
diff --git a/scripts/python-skywater-pdk/skywater_pdk/drives.py b/scripts/python-skywater-pdk/skywater_pdk/drives.py
index b26c2d4..e2db6c5 100644
--- a/scripts/python-skywater-pdk/skywater_pdk/drives.py
+++ b/scripts/python-skywater-pdk/skywater_pdk/drives.py
@@ -39,10 +39,10 @@
InvalidSuffixError: Invalid suffix: _abc
>>> l = [d1, d2, d3, d4]
>>> l
- [DriveStrengthNumeric(units=1), DriveStrengthLowPower(variant=0), DriveStrengthMinimum(), DriveStrengthNumeric(units=2)]
+ [DriveStrengthNumeric(units=1), DriveStrengthLowPower(lp_variant=0), DriveStrengthMinimum(), DriveStrengthNumeric(units=2)]
>>> l.sort()
>>> l
- [DriveStrengthNumeric(units=1), DriveStrengthNumeric(units=2), DriveStrengthLowPower(variant=0), DriveStrengthMinimum()]
+ [DriveStrengthNumeric(units=1), DriveStrengthNumeric(units=2), DriveStrengthLowPower(lp_variant=0), DriveStrengthMinimum()]
"""
@abc.abstractmethod
@@ -171,11 +171,11 @@
...
InvalidSuffixError: Invalid suffix: _ld
>>> lp
- DriveStrengthLowPower(variant=0)
+ DriveStrengthLowPower(lp_variant=0)
>>> lp2
- DriveStrengthLowPower(variant=1)
+ DriveStrengthLowPower(lp_variant=1)
>>> lp3
- DriveStrengthLowPower(variant=2)
+ DriveStrengthLowPower(lp_variant=2)
>>> str(lp)
'drive strength Low Power'
>>> str(lp2)
@@ -195,25 +195,25 @@
>>> lp3.suffix
'_lp3'
"""
- variant: int = 0
+ lp_variant: int = 0
def describe(self):
- if self.variant == 0:
+ if self.lp_variant == 0:
suffix = ""
- elif self.variant == 1:
+ elif self.lp_variant == 1:
suffix = " (alternative)"
else:
- assert self.variant >= 2, self.variant
- suffix = " (extra alternative {})".format(self.variant-2)
+ assert self.lp_variant >= 2, self.lp_variant
+ suffix = " (extra alternative {})".format(self.lp_variant-2)
return "Low Power"+suffix
@property
def suffix(self):
- if self.variant == 0:
+ if self.lp_variant == 0:
return "_lp"
else:
- assert self.variant > 0, self.variant
- return "_lp{}".format(self.variant+1)
+ assert self.lp_variant > 0, self.lp_variant
+ return "_lp{}".format(self.lp_variant+1)
@classmethod
def from_suffix(cls, s):
@@ -277,6 +277,10 @@
def __hash__(self):
return id(self)
+ def to_dict(self):
+ return {'minimum': None}
+
+
DriveStrengthMinimum._object = DriveStrengthMinimum()