From 6d8b8065dd406ba567da3d957c69fc2342ec9845 Mon Sep 17 00:00:00 2001 From: Saviour Owolabi <42647840+Seyviour@users.noreply.github.com> Date: Wed, 27 Mar 2024 19:27:29 +0100 Subject: [PATCH] Add exact_table_cover and parse_tile_exact functions for more specific tile parsing (#237) --- apycula/fuse_h4x.py | 61 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/apycula/fuse_h4x.py b/apycula/fuse_h4x.py index 75e397e7..8b895756 100644 --- a/apycula/fuse_h4x.py +++ b/apycula/fuse_h4x.py @@ -217,6 +217,67 @@ def parse_tile(d, ttyp, tile): return res +def parse_tile_exact(d, ttyp, tile, fuse_loc=True): + w = d[ttyp]['width'] + h = d[ttyp]['height'] + res = {} + for start, table in [(2, 'shortval'), (2, 'wire'), (16, 'longval'), + (1, 'longfuse'), (0, 'const')]: + if table in d[ttyp]: # skip missing entries + for subtyp, tablerows in d[ttyp][table].items(): + pos_items, neg_items = {}, {} + active_rows = [] + for row in tablerows: + if row[0] > 0: + row_fuses = [fuse for fuse in row[start:] if fuse >= 0] + locs = [fuse_lookup(d,ttyp, fuse) for fuse in row_fuses] + test = [tile[loc[0]][loc[1]] == 1 for loc in locs] + if all(test): + full_row = row[:start] + full_row.extend(row_fuses) + active_rows.append(full_row) + + # report fuse locations + if (active_rows): + exact_cover = exact_table_cover(active_rows, start, table) + if fuse_loc: + for cover_row in exact_cover: + cover_row[start:] = [fuse_lookup(d, ttyp, fuse) for fuse in cover_row[start:]] + + res.setdefault(table, {})[subtyp] = exact_cover + return res + + +def exact_table_cover(t_rows, start, table=None): + try: + import xcover + except: + raise ModuleNotFoundError ("The xcover package needs to be installed to use the exact_cover function.\ + \nYou may install it via pip: `pip install xcover`") + + row_fuses = [set ([fuse for fuse in row[start:] if fuse!=-1]) for row in t_rows] + primary = set() + for row in row_fuses: + primary.update(row) + secondary = set() + + # Enforce that every destination node has a single source + if table == 'wire': + for id, row in enumerate(t_rows): + # Casting the wire_id to a string ensures that it doesn't conflict with fuse_ids + row_fuses[id].add(str(row[1])) + secondary.add(str(row[1])) + + g = xcover.covers(row_fuses, primary=primary, secondary=secondary, colored=False) + if g: + for r in g: + #g is an iterator, so this is just a hack to return the first solution. + #A future commit might introduce a heuristic for determining what solution is most plausible + #where there are multiple solutions + return [t_rows[idx] for idx in r] + else: + return [] + def scan_fuses(d, ttyp, tile): w = d[ttyp]['width'] h = d[ttyp]['height']