| #!/usr/bin/env python3 | |
| import json | |
| import util as localutil | |
| import os.path | |
| def check_frames(tagstr, addrlist): | |
| frames = set() | |
| for addrstr in addrlist: | |
| frame = parse_addr(addrstr, get_base_frame=True) | |
| frames.add(frame) | |
| assert len(frames) == 1, ( | |
| "{}: More than one base address".format(tagstr), map(hex, frames)) | |
| def parse_addr(line, only_frame=False, get_base_frame=False): | |
| # 00020027_003_03 | |
| line = line.split("_") | |
| frame = int(line[0], 16) | |
| wordidx = int(line[1], 10) | |
| bitidx = int(line[2], 10) | |
| if get_base_frame: | |
| delta = frame % 128 | |
| frame -= delta | |
| return frame | |
| return frame, wordidx, bitidx | |
| def load_db(fn): | |
| for l in open(fn, "r"): | |
| l = l.strip() | |
| # FIXME: add offset to name | |
| # IOB_X0Y101.DFRAME:27.DWORD:3.DBIT:3 00020027_003_03 | |
| parts = l.split(' ') | |
| tagstr = parts[0] | |
| addrlist = parts[1:] | |
| check_frames(tagstr, addrlist) | |
| # Take the first address in the list | |
| frame, wordidx, bitidx = parse_addr(addrlist[0]) | |
| bitidx_up = False | |
| tparts = tagstr.split('.') | |
| tile = tparts[0] | |
| for part in tparts[1:]: | |
| k, v = part.split(':') | |
| if k == "DFRAME": | |
| frame -= int(v, 16) | |
| elif k == "DWORD": | |
| wordidx -= int(v, 10) | |
| elif k == "DBIT": | |
| bitidx -= int(v, 10) | |
| bitidx_up = True | |
| else: | |
| assert 0, (l, part) | |
| # XXX: maybe just ignore bitidx and always set to 0 instead of allowing explicit | |
| # or detect the first delta auto and assert they are all the same | |
| if not bitidx_up: | |
| bitidx = 0 | |
| assert bitidx == 0, l | |
| assert frame % 0x80 == 0, "Unaligned frame at 0x%08X" % frame | |
| yield (tile, frame, wordidx) | |
| def run(fn_in, fn_out, verbose=False): | |
| database = json.load(open(fn_in, "r")) | |
| # Load a map of sites to base addresses | |
| # Need to figure out the | |
| # FIXME: generate frames from part file (or equivilent) | |
| # See https://github.com/SymbiFlow/prjxray/issues/327 | |
| # FIXME: generate words from pitch | |
| int_frames, int_words = localutil.get_int_params() | |
| tdb_fns = [ | |
| ("iob/build/segbits_tilegrid.tdb", 42, 4), | |
| ("ioi/build/segbits_tilegrid.tdb", 42, 4), | |
| ("mmcm/build/segbits_tilegrid.tdb", 30, 101), | |
| ("pll/build/segbits_tilegrid.tdb", 30, 26), | |
| ("monitor/build/segbits_tilegrid.tdb", 30, 101), | |
| ("bram/build/segbits_tilegrid.tdb", 28, 10), | |
| ("bram_block/build/segbits_tilegrid.tdb", 128, 10), | |
| ("clb/build/segbits_tilegrid.tdb", 36, 2), | |
| ("cfg/build/segbits_tilegrid.tdb", 30, 101), | |
| ("dsp/build/segbits_tilegrid.tdb", 28, 10), | |
| ("clk_hrow/build/segbits_tilegrid.tdb", 30, 18), | |
| ("clk_bufg/build/segbits_tilegrid.tdb", 30, 8), | |
| ("hclk_cmt/build/segbits_tilegrid.tdb", 30, 10), | |
| ("hclk_ioi/build/segbits_tilegrid.tdb", 42, 1), | |
| ("clb_int/build/segbits_tilegrid.tdb", int_frames, int_words), | |
| ("iob_int/build/segbits_tilegrid.tdb", int_frames, int_words), | |
| ("bram_int/build/segbits_tilegrid.tdb", int_frames, int_words), | |
| ("dsp_int/build/segbits_tilegrid.tdb", int_frames, int_words), | |
| ("fifo_int/build/segbits_tilegrid.tdb", int_frames, int_words), | |
| ("ps7_int/build/segbits_tilegrid.tdb", int_frames, int_words), | |
| ("cfg_int/build/segbits_tilegrid.tdb", int_frames, int_words), | |
| ("monitor_int/build/segbits_tilegrid.tdb", int_frames, int_words), | |
| ( | |
| "orphan_int_column/build/segbits_tilegrid.tdb", int_frames, | |
| int_words), | |
| ] | |
| for (tdb_fn, frames, words) in tdb_fns: | |
| if not os.path.exists(tdb_fn): | |
| verbose and print('Skipping {}, file not found!'.format(tdb_fn)) | |
| continue | |
| for (tile, frame, wordidx) in load_db(tdb_fn): | |
| tilej = database[tile] | |
| verbose and print("Add %s %08X_%03u" % (tile, frame, wordidx)) | |
| localutil.add_tile_bits(tile, tilej, frame, wordidx, frames, words) | |
| # Save | |
| json.dump( | |
| database, | |
| open(fn_out, "w"), | |
| sort_keys=True, | |
| indent=4, | |
| separators=(",", ": ")) | |
| def main(): | |
| import argparse | |
| parser = argparse.ArgumentParser( | |
| description="Annotate tilegrid addresses using solved base addresses") | |
| parser.add_argument("--verbose", action="store_true", help="") | |
| parser.add_argument("--fn-in", required=True, help="") | |
| parser.add_argument("--fn-out", required=True, help="") | |
| args = parser.parse_args() | |
| run(args.fn_in, args.fn_out, verbose=args.verbose) | |
| if __name__ == "__main__": | |
| main() |