| #!/usr/bin/env python3 |
| |
| import pprint |
| from collections import defaultdict |
| |
| REPLACEMENTS = { |
| #'NOTIFIER': 'NOTIFY', |
| 'NOTI_REG': 'NOTIFIER_REG', |
| 'NFR': 'NOTIFIER', |
| 'ntfy': 'NOTIFIER', |
| 'R': 'RESET', |
| 'S': 'SET', |
| 'SB': 'SET_ASYNC', |
| 'DE': 'DATA_ENABLE', |
| 'KAPWR': 'VKAPWR', |
| 'LVPWR': 'VLPWR', |
| } |
| |
| YOSYS_ARGS = { |
| 'RESET': 'R', |
| 'CLK_N': 'C', |
| 'CLK_P': 'C', |
| 'G': 'E', |
| 'Q': 'Q', |
| } |
| |
| # DFF_{C:N|P}_ (D, C, Q); |
| # DFFE_{C:N|P}{E:N|P}_ (D, C, E, Q); |
| # DFF_{C:N|P}{R:N|P}{V:0|1}_ (D, C, R, Q); |
| # DFFSR_{C:N|P}{S:N|P}{R:N|P}_ (C, S, R, D, Q); |
| # DLATCH_{E:N|P}_ (E, D, Q); |
| # DLATCHSR_{E:N|P}{S:N|P}{R:N|P}_ (E, S, R, D, Q); |
| |
| def pp(args): |
| args = list(args) |
| pp = [] |
| po = [] |
| for a in reversed(list(sorted(args))): |
| if a.startswith('V'): |
| args.remove(a) |
| pp.append(a[1]) |
| elif a == 'NOTIFIER': |
| args.remove(a) |
| po.append('N') |
| elif a == 'NOTIFIER_REG': |
| args.remove(a) |
| po.append('N') |
| elif a == 'SLEEP': |
| args.remove(a) |
| po.append('S') |
| elif a == 'SLEEPB': |
| args.remove(a) |
| po.append('s') |
| a = [] |
| if pp: |
| a.append(''.join(pp)) |
| if po: |
| a.append(''.join(po)) |
| if a: |
| a.insert(0, 'pp') |
| return '$'.join(a), args |
| |
| |
| RESET_SET_NAME = { |
| # Reset, Set |
| (None, None ): None, |
| ('RESET', None ): 'R' , |
| ('RESET', 'SET_DOM' ): 'SR', |
| ('RESET_DOM', 'SET' ): 'RS', |
| ('RESET_DOM', None ): 'R' , |
| (None, 'SET_DOM' ): 'S' , |
| (None, 'SET' ): 'S' , |
| (None, 'SET_ASYNC'): 'Sa', |
| } |
| |
| def n(args): |
| args = list(args) |
| n = [] |
| if 'CLK_P' in args: |
| args.remove('CLK_P') |
| n.append('P') |
| if 'CLK_N' in args: |
| args.remove('CLK_N') |
| n.append('N') |
| if 'GATE_P' in args: |
| args.remove('GATE_P') |
| n.append('P') |
| if 'GATE_N' in args: |
| args.remove('GATE_N') |
| n.append('N') |
| |
| if 'DATA_ENABLE' in args: |
| args.remove('DATA_ENABLE') |
| n.append('E') |
| |
| if "LOW_POWER" in args: |
| args.remove('LOW_POWER') |
| n.insert(0, 'l') |
| if "UDB" in args: |
| args.remove('UDB') |
| n.insert(0, 'u') |
| |
| reset_set = [None, None] |
| if args and args[0].startswith('RESET'): |
| reset_set[0] = args.pop(0) |
| if args and args[0].startswith('SET'): |
| reset_set[1] = args.pop(0) |
| reset_set = tuple(reset_set) |
| n.append(RESET_SET_NAME[reset_set]) |
| if not n[-1]: |
| n.pop(-1) |
| |
| return "".join(n), args |
| |
| |
| |
| outmap = defaultdict(lambda: list()) |
| outargs = {} |
| routmap = {} |
| |
| for i, l in enumerate(open('primitive_map.csv')): |
| name, args = l.strip().split(' ', 1) |
| |
| assert args[0] == '(', (i, l, name, args) |
| assert args[-2:] == ');', (i, l, name, args) |
| args = args[1:-2].split(', ') |
| |
| oargs = [] |
| for a in args: |
| if a in REPLACEMENTS and 'MUX' not in name: |
| oargs.append(REPLACEMENTS[a]) |
| else: |
| oargs.append(a) |
| args = list(oargs) |
| |
| ppa = None |
| ppn = None |
| |
| new_name = None |
| to_remove = [] |
| |
| if 'lpflow' in name: |
| args.append('LOW_POWER') |
| if 'udb' in name: |
| args.append('UDB') |
| |
| if 'DF' in name: |
| new_name = 'dff' |
| to_remove = ['Q', 'D'] |
| elif 'ISOLATCH' in name: |
| new_name = 'isolatch' |
| to_remove = ['Q', 'D'] |
| elif 'isosrchv' in name: |
| new_name = 'isolatchhv' |
| to_remove = ['UDP_OUT', 'UDP_IN'] |
| elif 'DL' in name: |
| new_name = 'dlatch' |
| to_remove = ['Q', 'D'] |
| elif 'MUX' in name: |
| new_name = 'mux' |
| |
| args = [] |
| |
| bits = name.split('MUX_', 1)[1].split('_') |
| from_n = int(bits.pop(0)) |
| to_n = int(bits.pop(0)) |
| assert to_n in (1, 2), to_n |
| |
| args.append('%ito%i'%(from_n, to_n)) |
| # FIXME: Hack for scs8ls_udb_pg_U_MUX_2_1_SEL_X |
| while len(bits) > 0 and (bits[0] == 'SEL' or bits[0] == 'X'): |
| bits.pop(0) |
| if bits: |
| assert bits[0] == 'INV', (bits[0], i, l) |
| args.append(bits.pop(0)) |
| |
| else: |
| new_name = 'pwrgood' |
| to_remove = ['UDP_OUT', 'UDP_IN'] |
| |
| for j in to_remove: |
| assert j in args, (j, i, l, name, args) |
| args.remove(j) |
| |
| if 'SETDOM' in name: |
| assert args[0] == 'SET', (i, l, name, args) |
| args[0] = 'SET_DOM' |
| else: |
| for j, v in enumerate(args): |
| if v == 'RESET': |
| args[j] = 'RESET_DOM' |
| |
| if 'DL_N' in name: |
| assert 'G' in args, (i, l, name, args) |
| args[args.index('G')] = 'GATE_N' |
| if 'DL_P' in name: |
| assert 'G' in args, (i, l, name, args) |
| args[args.index('G')] = 'GATE_P' |
| if 'DF_N' in name: |
| assert 'CK' in args, (i, l, name, args) |
| args[args.index('CK')] = 'CLK_N' |
| if 'DFB' in name: |
| assert 'CK' in args, (i, l, name, args) |
| args[args.index('CK')] = 'CLK_N' |
| if 'DF_P' in name: |
| assert 'CP' in args, (i, l, name, args) |
| args[args.index('CP')] = 'CLK_P' |
| |
| args.sort() |
| if 'MUX' not in name: |
| ppa, remains = pp(args) |
| ppn, remains = n(remains) |
| else: |
| ppa = args.pop(0) |
| if 'SEL_X' in l: |
| ppn = 'x' |
| if args: |
| assert args.pop(0) == 'INV' |
| ppa += '_N' |
| remains = [] |
| |
| assert not remains, (name, remains, oargs) |
| |
| fullname = 'udp_'+new_name |
| if ppn: |
| fullname += '$'+ppn |
| if ppa: |
| fullname += '_'+ppa |
| |
| outmap[fullname].append(name) |
| assert name not in routmap |
| routmap[name] = fullname |
| if fullname not in outargs: |
| outargs[fullname] = tuple(oargs) |
| else: |
| assert outargs[fullname] == tuple(oargs), (fullname, outargs[fullname], oargs) |
| |
| outmap = dict(outmap) |
| |
| if __name__ == "__main__": |
| maxlenk = max(len(s) for s in routmap) |
| maxlenv = max(len(s) for s in routmap.values()) |
| for k, v in routmap.items(): |
| print(k.ljust(maxlenk), v.ljust(maxlenv), outargs[v]) |