Merge pull request #81 from mithro/libfixes

Fix a number of issues with the generated liberty output
This commit is contained in:
Tim Ansell 2020-07-15 08:00:07 -07:00 committed by GitHub
commit 4e5e318e0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 250 additions and 17 deletions

View File

@ -343,7 +343,8 @@ def generate(library_dir, lib, corner, ocorner_type, icorner_type, cells):
if ocorner_type != TimingType.ccsnoise:
remove_ccsnoise_from_library(common_data, "library")
output = liberty_dict("library", lib+"__"+corner, common_data)
attribute_types = {}
output = liberty_dict("library", lib+"__"+corner, common_data, attribute_types)
assert output[-1] == '}', output
top_write(output[:-1])
@ -360,7 +361,13 @@ def generate(library_dir, lib, corner, ocorner_type, icorner_type, cells):
remove_ccsnoise_from_cell(cell_data, cell_with_size)
top_write([''])
top_write(liberty_dict("cell", "%s__%s" % (lib, cell_with_size), cell_data, [cell_with_size]))
top_write(liberty_dict(
"cell",
"%s__%s" % (lib, cell_with_size),
cell_data,
[cell_with_size],
attribute_types,
))
top_write([''])
top_write(['}'])
@ -602,6 +609,135 @@ def is_liberty_list(k):
return k in ('variable', 'index', 'values')
def liberty_guess(o):
"""
>>> liberty_guess('hello') # doctest: +ELLIPSIS
<function liberty_str at ...>
>>> liberty_guess(1.0) # doctest: +ELLIPSIS
<function liberty_float at ...>
>>> liberty_guess(1) # doctest: +ELLIPSIS
<function liberty_float at ...>
>>> liberty_guess(None)
Traceback (most recent call last):
...
ValueError: None has unguessable type: <class 'NoneType'>
"""
if isinstance(o, str):
return liberty_str
elif isinstance(o, (float,int)):
return liberty_float
else:
raise ValueError("%r has unguessable type: %s" % (o, type(o)))
def liberty_bool(b):
"""
>>> liberty_bool(True)
'true'
>>> liberty_bool(False)
'false'
>>> liberty_bool(1.0)
'true'
>>> liberty_bool(1.5)
Traceback (most recent call last):
...
ValueError: 1.5 is not a bool
>>> liberty_bool(0.0)
'false'
>>> liberty_bool(0)
'false'
>>> liberty_bool(1)
'true'
>>> liberty_bool("error")
Traceback (most recent call last):
...
ValueError: 'error' is not a bool
"""
try:
b2 = bool(b)
except ValueError:
b2 = None
if b2 != b:
raise ValueError("%r is not a bool" % b)
return {True: 'true', False: 'false'}[b]
def liberty_str(s):
"""
>>> liberty_str("hello")
'"hello"'
>>> liberty_str('he"llo')
Traceback (most recent call last):
...
ValueError: '"' is not allow in the string: 'he"llo'
>>> liberty_str(1.0)
'"1.0000000000"'
>>> liberty_str(1)
'"1.0000000000"'
>>> liberty_str([])
Traceback (most recent call last):
...
ValueError: [] is not a string
>>> liberty_str(True)
Traceback (most recent call last):
...
ValueError: True is not a string
"""
try:
if isinstance(s, (int, float)):
s = liberty_float(s)
except ValueError:
pass
if not isinstance(s, str):
raise ValueError("%r is not a string" % s)
if '"' in s:
raise ValueError("'\"' is not allow in the string: %r" % s)
return '"'+s+'"'
def liberty_int(f):
"""
>>> liberty_int(1.0)
1
>>> liberty_int(1.5)
Traceback (most recent call last):
...
ValueError: 1.5 is not an int
>>> liberty_int("error")
Traceback (most recent call last):
...
ValueError: 'error' is not an int
"""
try:
f2 = int(f)
except ValueError as e:
f2 = None
if f2 is None or f2 != f:
raise ValueError("%r is not an int" % f)
return int(f)
def liberty_float(f):
"""
@ -617,7 +753,42 @@ def liberty_float(f):
>>> liberty_float(1)
'1.0000000000'
>>> liberty_float(True)
Traceback (most recent call last):
...
ValueError: True is not a float
>>> liberty_float(False)
Traceback (most recent call last):
...
ValueError: False is not a float
>>> liberty_float(0)
'0.0000000000'
>>> liberty_float(None)
Traceback (most recent call last):
...
ValueError: None is not a float
>>> liberty_float('hello')
Traceback (most recent call last):
...
ValueError: 'hello' is not a float
"""
try:
f2 = float(f)
except (ValueError, TypeError):
f2 = None
if isinstance(f, bool):
f2 = None
if f is None or f2 != f:
raise ValueError("%r is not a float" % f)
WIDTH = len(str(0.0083333333))
s = json.dumps(f)
@ -639,6 +810,14 @@ def liberty_float(f):
return s
LIBERTY_ATTRIBUTE_TYPES = {
'boolean': liberty_bool,
'string': liberty_str,
'int': liberty_int,
'float': liberty_float,
}
INDENT=" "
@ -738,8 +917,42 @@ def liberty_list(k, v, i=tuple()):
return o
def liberty_dict(dtype, dvalue, data, indent=tuple()):
def liberty_dict(dtype, dvalue, data, indent=tuple(), attribute_types=None):
"""
>>> def g(a, b, c):
... return {"group_name": a, "attribute_name":b, "attribute_type": c}
>>> d = {'float': 1.0, "str": "str"}
>>> print('\\n'.join(liberty_dict("library", "test", d)))
library ("test") {
float : 1.0000000000;
str : "str";
}
>>> d['define'] = [g("cell", "float", "string")]
>>> print('\\n'.join(liberty_dict("library", "test", d)))
library ("test") {
define(float,cell,string);
float : 1.0000000000;
str : "str";
}
>>> d['define'] = [g("library", "float", "string")]
>>> print('\\n'.join(liberty_dict("library", "test", d)))
library ("test") {
define(float,library,string);
float : "1.0000000000";
str : "str";
}
"""
assert isinstance(data, dict), (dtype, dvalue, data)
if attribute_types is None:
attribute_types = {}
assert isinstance(attribute_types, dict), (dtype, dvalue, attribute_types)
o = []
if dvalue:
@ -773,28 +986,47 @@ def liberty_dict(dtype, dvalue, data, indent=tuple()):
di = [attr_sort_key(i) for i in data.items()]
di.sort()
if debug:
print(" "*len(str(indent)), "s1 s2 ", "%-40s" % "ktype", '%-40r' % "kvalue", "value")
print("-"*len(str(indent)), "---- ---- ", "-"*40, "-"*40, "-"*44)
for sk, kt, skv, kv, k, v in di:
print(str(indent), "%4.0f %4.0f -- " % sk, "%-40s" % kt, '%-40r' % kv, str(v)[:40], '...')
print(str(indent), "%4.0f %4.0f --" % sk, "%-40s" % kt, '%-40r' % kv, end=" ")
sv = str(v)
print(sv[:40], end=" ")
if len(sv) > 40:
print('...', end=" ")
print()
# Output all the attributes
if dtype not in attribute_types:
dtype_attribute_types = {}
attribute_types[dtype] = dtype_attribute_types
dtype_attribute_types = attribute_types[dtype]
for _, ktype, _, kvalue, k, v in di:
indent_n = list(indent)+[k]
if ktype == 'define':
for d in sorted(data['define'], key=lambda d: d['group_name']+'.'+d['attribute_name']):
aname = d['attribute_name']
gname = d['group_name']
atype = d['attribute_type']
o.append('%sdefine(%s,%s,%s);' % (
INDENT*len(indent_n),
d['attribute_name'],
d['group_name'],
d['attribute_type']),
)
INDENT*len(indent_n), aname, gname, atype))
assert atype in LIBERTY_ATTRIBUTE_TYPES, (atype, d)
if gname not in attribute_types:
attribute_types[gname] = {}
attribute_types[gname][aname] = LIBERTY_ATTRIBUTE_TYPES[atype]
elif ktype == "comp_attribute":
o.extend(liberty_composite(kvalue, v, indent_n))
elif isinstance(v, dict):
assert isinstance(v, dict), (dtype, dvalue, k, v)
o.extend(liberty_dict(ktype, kvalue, v, indent_n))
o.extend(liberty_dict(ktype, kvalue, v, indent_n, attribute_types))
elif isinstance(v, list):
assert len(v) > 0, (dtype, dvalue, k, v)
@ -803,24 +1035,25 @@ def liberty_dict(dtype, dvalue, data, indent=tuple()):
return o.items()
for l in sorted(v, key=sk):
o.extend(liberty_dict(ktype, kvalue, l, indent_n))
o.extend(liberty_dict(ktype, kvalue, l, indent_n, attribute_types))
elif is_liberty_list(ktype):
o.extend(liberty_list(ktype, v, indent_n))
elif "clk_width" == ktype:
for l in sorted(v):
o.append("%s%s : %s;" % (INDENT*len(indent_n), k, l))
o.append('%s%s : "%s";' % (INDENT*len(indent_n), k, l))
else:
raise ValueError("Unknown %s: %r\n%s" % (k, v, indent_n))
else:
if isinstance(v, str):
v = '"%s"' % v
elif isinstance(v, (float,int)):
v = liberty_float(v)
o.append("%s%s : %s;" % (INDENT*len(indent_n), k, v))
if ktype in dtype_attribute_types:
liberty_out = dtype_attribute_types[ktype]
else:
liberty_out = liberty_guess(v)
ov = liberty_out(v)
o.append("%s%s : %s;" % (INDENT*len(indent_n), k, ov))
o.append("%s}" % (INDENT*len(indent)))
return o