| #!/usr/bin/env python3 |
| import parse_sdf |
| from os import path |
| import json |
| import sys |
| |
| |
| def include_cell(name, type): |
| return type.isupper() and "_" not in type |
| |
| |
| def rewrite_celltype(name, type): |
| return type |
| |
| |
| def rewrite_pin(name, type, pin): |
| return pin |
| |
| |
| def tupleise(x): |
| if type(x) is list: |
| return tuple(tupleise(_) for _ in x) |
| elif type(x) is tuple: |
| return tuple(tupleise(_) for _ in x) |
| elif type(x) is dict: |
| return "dict", tuple([(k, tupleise(v)) for k, v in sorted(x.items())]) |
| else: |
| return x |
| |
| |
| def load_database(dbfile): |
| if not path.exists(dbfile): |
| database = {} |
| else: |
| database = {} |
| with open(dbfile, 'r') as dbf: |
| jsondb = json.load(dbf) |
| for cell, cdata in jsondb.items(): |
| database[cell] = set() |
| for item in cdata: |
| database[cell].add(tupleise(item)) |
| return database |
| |
| |
| def make_key(x): |
| if type(x) is tuple: |
| return ",".join(make_key(_) for _ in x) |
| else: |
| return str(x) |
| |
| |
| def save_database(dbfile, database): |
| jdb = {} |
| for cell, cdata in database.items(): |
| jcdata = [] |
| for dtype, dat in sorted(cdata, key=lambda x: make_key(x)): |
| assert dtype == "dict" |
| jcdata.append({k: v for k, v in dat}) |
| jdb[cell] = jcdata |
| with open(dbfile, 'w') as dbf: |
| json.dump(jdb, dbf, indent=4, sort_keys=True) |
| |
| |
| def delay_tuple(delay): |
| return delay.minv, delay.typv, delay.maxv |
| |
| |
| def add_sdf_to_database(dbfile, sdffile, include_cell_predicate=include_cell, rewrite_cell_func=rewrite_celltype, |
| rewrite_pin_func=rewrite_pin): |
| db = load_database(dbfile) |
| sdf = parse_sdf.parse_sdf_file(sdffile) |
| for instname, cell in sdf.cells.items(): |
| if not include_cell_predicate(cell.inst, cell.type): |
| continue |
| celltype = rewrite_cell_func(cell.inst, cell.type) |
| if celltype not in db: |
| db[celltype] = set() |
| for entry in cell.entries: |
| if type(entry) is parse_sdf.IOPath: |
| db[celltype].add(tupleise( |
| dict(type="IOPath", from_pin=rewrite_pin_func(cell.inst, cell.type, entry.from_pin), |
| to_pin=rewrite_pin_func(cell.inst, cell.type, entry.to_pin), rising=delay_tuple(entry.rising), |
| falling=delay_tuple(entry.falling)))) |
| elif type(entry) is parse_sdf.SetupHoldCheck: |
| db[celltype].add( |
| tupleise(dict(type="SetupHold", pin=rewrite_pin_func(cell.inst, cell.type, entry.pin), |
| clock=rewrite_pin_func(cell.inst, cell.type, entry.clock), |
| setup=delay_tuple(entry.setup), |
| hold=delay_tuple(entry.hold)))) |
| elif type(entry) is parse_sdf.WidthCheck: |
| db[celltype].add(tupleise(dict(type="Width", clock=rewrite_pin_func(cell.inst, cell.type, entry.clock), |
| width=delay_tuple(entry.width)))) |
| else: |
| assert False |
| save_database(dbfile, db) |
| |
| |
| def main(argv): |
| if len(argv) < 3: |
| print("Usage: cell_timings.py database.json design.sdf") |
| return 2 |
| add_sdf_to_database(argv[1], argv[2]) |
| return 0 |
| |
| |
| if __name__ == "__main__": |
| sys.exit(main(sys.argv)) |