| # Top level keywords defining the begin of a cell definition. | |
| top_level = [ | |
| "model", | |
| "inputs", | |
| "outputs", | |
| "names", | |
| "latch", | |
| "subckt", | |
| ] | |
| # Keywords defining cell attributes / parameters. Those can be specified for | |
| # each cell multiple times. Parameter names and values are stored in a dict | |
| # under the parsed blif data. | |
| # | |
| # For example: the construct ".param MODE SYNC" will add to the dict under | |
| # the key "param" entry "MODE":"SYNC". | |
| # | |
| sub_level = [ | |
| "attr", | |
| "param", | |
| ] | |
| def parse_blif(f): | |
| current = None | |
| data = {} | |
| def add(d): | |
| if d['type'] not in data: | |
| data[d['type']] = [] | |
| data[d['type']].append(d) | |
| current = None | |
| for oline in f: | |
| line = oline | |
| if '#' in line: | |
| line = line[:line.find('#')] | |
| line = line.strip() | |
| if not line: | |
| continue | |
| if line.startswith("."): | |
| args = line.split(" ", maxsplit=1) | |
| if len(args) < 2: | |
| args.append("") | |
| ctype = args.pop(0) | |
| assert ctype.startswith("."), ctype | |
| ctype = ctype[1:] | |
| if ctype in top_level: | |
| if current: | |
| add(current) | |
| current = { | |
| 'type': ctype, | |
| 'args': args[-1].split(), | |
| 'data': [], | |
| } | |
| elif ctype in sub_level: | |
| if ctype not in current: | |
| current[ctype] = {} | |
| key, value = args[-1].split(maxsplit=1) | |
| current[ctype][key] = value | |
| else: | |
| current[ctype] = args[-1].split() | |
| continue | |
| current['data'].append(line.strip().split()) | |
| if current: | |
| add(current) | |
| assert len(data['inputs']) == 1 | |
| data['inputs'] = data['inputs'][0] | |
| assert len(data['outputs']) == 1 | |
| data['outputs'] = data['outputs'][0] | |
| return data |