| #!/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() | |