| #!/usr/bin/env python3 |
| # |
| # Copyright (C) 2015 Clifford Wolf <clifford@clifford.at> |
| # |
| # Permission to use, copy, modify, and/or distribute this software for any |
| # purpose with or without fee is hereby granted, provided that the above |
| # copyright notice and this permission notice appear in all copies. |
| # |
| # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| # |
| |
| import icebox |
| import getopt, sys, re |
| |
| print_bits = False |
| print_map = False |
| single_tile = None |
| print_all = False |
| |
| def usage(): |
| print(""" |
| Usage: icebox_explain [options] [bitmap.asc] |
| |
| -b |
| print config bit names for each config statement |
| |
| -m |
| print tile config bitmaps |
| |
| -A |
| don't skip uninteresting tiles |
| |
| -t '<x-coordinate> <y-coordinate>' |
| print only the specified tile |
| """) |
| sys.exit(0) |
| |
| try: |
| opts, args = getopt.getopt(sys.argv[1:], "bmAt:") |
| except: |
| usage() |
| |
| for o, a in opts: |
| if o == "-b": |
| print_bits = True |
| elif o == "-m": |
| print_map = True |
| elif o == "-A": |
| print_all = True |
| elif o == "-t": |
| single_tile = tuple([int(s) for s in a.split()]) |
| else: |
| usage() |
| |
| if len(args) == 0: |
| args.append("/dev/stdin") |
| |
| if len(args) != 1: |
| usage() |
| |
| print("Reading file '%s'.." % args[0]) |
| ic = icebox.iceconfig() |
| ic.read_file(args[0]) |
| print("Fabric size (without IO tiles): %d x %d" % (ic.max_x-1, ic.max_y-1)) |
| |
| def print_tile(stmt, ic, x, y, tile, db): |
| if single_tile is not None and single_tile != (x, y): |
| return |
| |
| bits = set() |
| mapped_bits = set() |
| for k, line in enumerate(tile): |
| for i in range(len(line)): |
| if line[i] == "1": |
| bits.add("B%d[%d]" % (k, i)) |
| else: |
| bits.add("!B%d[%d]" % (k, i)) |
| |
| if re.search(r"logic_tile", stmt): |
| active_luts = set([i for i in range(8) if "1" in icebox.get_lutff_bits(tile, i)]) |
| |
| text = set() |
| used_lc = set() |
| text_default_mask = 0 |
| for entry in db: |
| if re.match(r"LC_", entry[1]): |
| continue |
| if entry[1] in ("routing", "buffer"): |
| if not ic.tile_has_net(x, y, entry[2]): continue |
| if not ic.tile_has_net(x, y, entry[3]): continue |
| match = True |
| for bit in entry[0]: |
| if not bit in bits: |
| match = False |
| if match: |
| for bit in entry[0]: |
| mapped_bits.add(bit) |
| if entry[1] == "IoCtrl" and entry[2] == "IE_0": |
| text_default_mask |= 1 |
| if entry[1] == "IoCtrl" and entry[2] == "IE_1": |
| text_default_mask |= 2 |
| if entry[1] == "RamConfig" and entry[2] == "PowerUp": |
| text_default_mask |= 4 |
| if print_bits: |
| text.add("<%s> %s" % (" ".join(entry[0]), " ".join(entry[1:]))) |
| else: |
| text.add(" ".join(entry[1:])) |
| bitinfo = list() |
| print_bitinfo = False |
| for k, line in enumerate(tile): |
| bitinfo.append("") |
| extra_text = "" |
| for i in range(len(line)): |
| if 36 <= i <= 45 and re.search(r"(logic_tile|dsp\d_tile|ipcon_tile)", stmt): |
| lutff_idx = k // 2 |
| lutff_bitnum = (i-36) + 10*(k%2) |
| if line[i] == "1": |
| used_lc.add(lutff_idx) |
| bitinfo[-1] += "*" |
| else: |
| bitinfo[-1] += "-" |
| elif line[i] == "1" and "B%d[%d]" % (k, i) not in mapped_bits: |
| print_bitinfo = True |
| extra_text += " B%d[%d]" % (k, i) |
| bitinfo[-1] += "?" |
| else: |
| bitinfo[-1] += "+" if line[i] == "1" else "-" |
| bitinfo[-1] += extra_text |
| for lcidx in sorted(used_lc): |
| lutff_options = "".join(icebox.get_lutff_seq_bits(tile, lcidx)) |
| if lutff_options[0] == "1": lutff_options += " CarryEnable" |
| if lutff_options[1] == "1": lutff_options += " DffEnable" |
| if lutff_options[2] == "1": lutff_options += " Set_NoReset" |
| if lutff_options[3] == "1": lutff_options += " AsyncSetReset" |
| text.add("LC_%d %s %s" % (lcidx, "".join(icebox.get_lutff_lut_bits(tile, lcidx)), lutff_options)) |
| if not print_bitinfo and not print_all: |
| if text_default_mask == 3 and len(text) == 2: |
| return |
| if text_default_mask == 4 and len(text) == 1: |
| return |
| if len(text) or print_bitinfo or print_all: |
| print("\n%s" % stmt) |
| if print_bitinfo: |
| print("Warning: No DB entries for some bits:") |
| if print_bitinfo or print_map: |
| for k, line in enumerate(bitinfo): |
| print("%4s %s" % ("B%d" % k, line)) |
| for line in sorted(text): |
| print(line) |
| |
| for idx in ic.io_tiles: |
| print_tile(".io_tile %d %d" % idx, ic, idx[0], idx[1], ic.io_tiles[idx], ic.tile_db(idx[0], idx[1])) |
| |
| for idx in ic.logic_tiles: |
| print_tile(".logic_tile %d %d" % idx, ic, idx[0], idx[1], ic.logic_tiles[idx], ic.tile_db(idx[0], idx[1])) |
| |
| for idx in ic.ramb_tiles: |
| print_tile(".ramb_tile %d %d" % idx, ic, idx[0], idx[1], ic.ramb_tiles[idx], ic.tile_db(idx[0], idx[1])) |
| |
| for idx in ic.ramt_tiles: |
| print_tile(".ramt_tile %d %d" % idx, ic, idx[0], idx[1], ic.ramt_tiles[idx], ic.tile_db(idx[0], idx[1])) |
| |
| for i in range(4): |
| for idx in ic.dsp_tiles[i]: |
| print_tile(".dsp%d_tile %d %d" % (i, idx[0], idx[1]), ic, idx[0], idx[1], ic.dsp_tiles[i][idx], ic.tile_db(idx[0], idx[1])) |
| |
| for idx in ic.ipcon_tiles: |
| print_tile(".ipcon_tile %d %d" % idx, ic, idx[0], idx[1], ic.ipcon_tiles[idx], ic.tile_db(idx[0], idx[1])) |
| |
| for bit in ic.extra_bits: |
| print() |
| print(".extra_bit %d %d %d" % bit) |
| print(" ".join(ic.lookup_extra_bit(bit))) |
| |
| print() |
| |