From dfeb92a46b2228b4f3886a9c06502ccd0dde5562 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 18 Jul 2015 13:05:02 +0200 Subject: Import of icestorm-snapshot-150322.zip --- icebox/icebox_html.py | 523 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 523 insertions(+) create mode 100755 icebox/icebox_html.py (limited to 'icebox/icebox_html.py') diff --git a/icebox/icebox_html.py b/icebox/icebox_html.py new file mode 100755 index 0000000..f7ebd67 --- /dev/null +++ b/icebox/icebox_html.py @@ -0,0 +1,523 @@ +#!/usr/bin/python +# +# Copyright (C) 2015 Clifford Wolf +# +# 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. +# + +from __future__ import division +from __future__ import print_function + +import icebox +import getopt, sys, os, re + +chipname = "iCE40 HX1K" +outdir = None +tx, ty = 0, 0 + +def usage(): + print("Usage: %s [options]" % sys.argv[0]) + print(" -x tile_x_coordinate") + print(" -y tile_y_coordinate") + print(" -d outdir") + sys.exit(0) + +try: + opts, args = getopt.getopt(sys.argv[1:], "x:y:d:") +except: + usage() + +for o, a in opts: + if o == "-x": + tx = int(a) + elif o == "-y": + ty = int(a) + elif o == "-d": + outdir = a + else: + usage() + +ic = icebox.iceconfig() +ic.setup_empty_1k() + +mktiles = set() + +for x in range(1, 6) + range(8, 13): + mktiles.add((x, 0)) + mktiles.add((x, 17)) + +for x in range(0, 6) + range(8, 14): + mktiles.add((x, 1)) + mktiles.add((x, 16)) + +for x in range(0, 5) + range(9, 14): + mktiles.add((x, 2)) + mktiles.add((x, 15)) + +for x in range(6, 8): + for y in range(8, 10): + mktiles.add((x, y)) + +expand_count=[0] + +def print_expand_div(title): + print('[+] Show %s') + +def print_expand_all(): + print('[+] Expand All' % (expand_count[0], expand_count[0])) + expand_count[0] += 1 + +def print_index(): + print("Project IceStorm – %s Overview" % chipname) + print("

Project IceStorm – %s Overview

" % chipname) + + print("""Project IceStorm aims at documenting the bitstream format of Lattice iCE40 FPGAs +and providing simple tools for analyzing and creating bitstream files. This is work in progress.""") + + print("""

This documentation is auto-generated by icebox_html.py from IceBox.
+A machine-readable form of the database can be downloaded here.

""") + + print("""

The iCE40 FPGA fabric is organized into tiles. The configuration bits +themself have the same meaning in all tiles of the same type. But the way the tiles +are connected to each other depends on the types of neighbouring cells. Furthermore, +some wire names are different for (e.g.) a IO tile on the left border and an IO tile on +the top border.

""") + + print("""

Click on a highlighted tile below to view the bitstream details for the +tile. The highlighted tiles cover all combinations of neighbouring cells that can be found +in iCE40 FPGAs.

""") + + print('

') + for y in range(ic.max_y, -1, -1): + print("") + for x in range(ic.max_x + 1): + print('') + elif (x, y) in mktiles: + if ic.tile_type(x, y) == "IO": color = "#aee" + if ic.tile_type(x, y) == "LOGIC": color = "#eae" + if ic.tile_type(x, y) == "RAM": color = "#eea" + print('bgcolor="%s">%s
(%d %d)
' % (color, x, y, ic.tile_type(x, y), x, y)) + else: + if ic.tile_type(x, y) == "IO": color = "#8aa" + if ic.tile_type(x, y) == "LOGIC": color = "#a8a" + if ic.tile_type(x, y) == "RAM": color = "#aa8" + print('bgcolor="%s">%s
(%d %d)
' % (color, ic.tile_type(x, y), x, y)) + print("") + print("
 

") + +def print_tile(tx, ty): + tile = ic.tile(tx, ty) + tile_type = ic.tile_type(tx, ty) + + print("Project IceStorm – %s %s Tile (%d %d)" % (chipname, tile_type, tx, ty)) + print("

Project IceStorm – %s %s Tile (%d %d)

" % (chipname, tile_type, tx, ty)) + + print("""Project IceStorm aims at documenting the bitstream format of Lattice iCE40 FPGAs +and providing simple tools for analyzing and creating bitstream files. This is work in progress.""") + + print("""

This page describes the %s Tile (%d %d), what nets and +configuration bits it has and how it is connected to its neighbourhood.

""" % (tile_type, tx, ty)) + + visible_tiles = set() + + print('

') + for y in range(ty+2, ty-3, -1): + print("") + for x in range(tx-2, tx+3): + print('') + else: + if (x, y) in mktiles: + if ic.tile_type(x, y) == "IO": color = "#aee" + if ic.tile_type(x, y) == "LOGIC": color = "#eae" + if ic.tile_type(x, y) == "RAM": color = "#eea" + print('bgcolor="%s">%s Tile
(%d %d)
' % (color, x, y, ic.tile_type(x, y), x, y)) + else: + if ic.tile_type(x, y) == "IO": color = "#8aa" + if ic.tile_type(x, y) == "LOGIC": color = "#a8a" + if ic.tile_type(x, y) == "RAM": color = "#aa8" + print('bgcolor="%s">%s Tile
(%d %d)' % (color, ic.tile_type(x, y), x, y)) + visible_tiles.add((x, y)) + print("") + print("
 

") + + # print_expand_all() + + print("

Configuration Bitmap

") + + print("

A %s Tile has %d config bits in %d groups of %d bits each:
" % (tile_type, len(tile)*len(tile[0]), len(tile), len(tile[0]))) + print(("%s

" % (", ".join(['%sB%d[%d:0]' % (" " if i < 10 else "", i, len(tile[i])-1) for i in range(len(tile))]))).replace(" B8", "
 B8")) + + bitmap_cells = list() + for line_nr in range(len(tile)): + line = list() + bitmap_cells.append(line) + for bit_nr in range(len(tile[line_nr])): + line.append({"bgcolor": "#aaa", "label": "?"}) + + for entry in ic.tile_db(tx, ty): + if not ic.tile_has_entry(tx, ty, entry): + continue + for bit in [bit.replace("!", "") for bit in entry[0]]: + match = re.match(r"B(\d+)\[(\d+)\]$", bit) + idx1 = int(match.group(1)) + idx2 = int(match.group(2)) + if entry[1] == "routing": + bitmap_cells[idx1][idx2]["bgcolor"] = "#faa" + bitmap_cells[idx1][idx2]["label"] = "R" + bitmap_cells[idx1][idx2]["is_routing"] = True + elif entry[1] == "buffer": + bitmap_cells[idx1][idx2]["bgcolor"] = "#afa" + bitmap_cells[idx1][idx2]["label"] = "B" + bitmap_cells[idx1][idx2]["is_routing"] = True + else: + bitmap_cells[idx1][idx2]["bgcolor"] = "#aaf" + if entry[1] == "ColBufCtrl": + bitmap_cells[idx1][idx2]["label"] = "O" + elif entry[1].startswith("LC_"): + bitmap_cells[idx1][idx2]["label"] = "L" + elif entry[1].startswith("NegClk"): + bitmap_cells[idx1][idx2]["label"] = "N" + elif entry[1].startswith("CarryInSet"): + bitmap_cells[idx1][idx2]["label"] = "C" + elif entry[1].startswith("IOB_"): + bitmap_cells[idx1][idx2]["label"] = "I" + elif entry[1].startswith("IoCtrl"): + bitmap_cells[idx1][idx2]["label"] = "I" + elif entry[1].startswith("Cascade"): + bitmap_cells[idx1][idx2]["label"] = "A" + elif entry[1].startswith("RamConfig"): + bitmap_cells[idx1][idx2]["label"] = "R" + else: + assert False + bitmap_cells[idx1][idx2]["label"] = '%s' % (idx1, idx2, bitmap_cells[idx1][idx2]["label"]) + + print('') + print("") + for cell_nr in range(len(line)): + print('' % cell_nr) + print("") + for line_nr, line in enumerate(bitmap_cells): + print("") + print('' % line_nr) + for cell in line: + print('' % (cell["bgcolor"], cell["label"])) + print('' % line_nr) + print("") + print("") + for cell_nr in range(len(line)): + print('' % cell_nr) + print("") + print("
%d
B%d%sB%d
%d
") + + print("

Nets and Connectivity

") + + print("""

This section lists all nets in the tile and how this +nets are connected with nets from cells in its neighbourhood.

""") + + grouped_segs = ic.group_segments(set([(tx, ty)])) + groups_indexed = dict() + this_tile_nets = dict() + + for segs in sorted(grouped_segs): + this_segs = list() + neighbour_segs = dict() + for s in segs: + if s[0] == tx and s[1] == ty: + this_segs.append(s[2]) + match = re.match(r"(.*?_)(\d+)(.*)", s[2]) + if match: + this_tile_nets.setdefault(match.group(1) + "*" + match.group(3), set()).add(int(match.group(2))) + else: + this_tile_nets.setdefault(s[2], set()).add(-1) + if (s[0], s[1]) in visible_tiles: + neighbour_segs.setdefault((s[0], s[1]), list()).append(s[2]) + if this_segs: + this_name = ", ".join(sorted(this_segs)) + assert this_name not in groups_indexed + groups_indexed[this_name] = neighbour_segs + + print("

List of nets in %s Tile (%d %d)

" % (tile_type, tx, ty)) + + def net2cat(netname): + cat = (99, "Unsorted") + if netname.startswith("glb_netwk_"): cat = (10, "Global Networks") + if netname.startswith("glb2local_"): cat = (10, "Global Networks") + if netname.startswith("wire_gbuf"): cat = (10, "Global Networks") + if netname.startswith("local_"): cat = (20, "Local Tracks") + if netname.startswith("carry_in"): cat = (25, "Logic Block") + if netname.startswith("io_"): cat = (25, "IO Block") + if netname.startswith("lutff_"): cat = (25, "Logic Block") + if netname.startswith("lutff_0"): cat = (30, "Logic Unit 0") + if netname.startswith("lutff_1"): cat = (30, "Logic Unit 1") + if netname.startswith("lutff_2"): cat = (30, "Logic Unit 2") + if netname.startswith("lutff_3"): cat = (30, "Logic Unit 3") + if netname.startswith("lutff_4"): cat = (30, "Logic Unit 4") + if netname.startswith("lutff_5"): cat = (30, "Logic Unit 5") + if netname.startswith("lutff_6"): cat = (30, "Logic Unit 6") + if netname.startswith("lutff_7"): cat = (30, "Logic Unit 7") + if netname.startswith("neigh_op_"): cat = (40, "Neighbourhood") + if netname.startswith("logic_op_"): cat = (40, "Neighbourhood") + if netname.startswith("sp4_v_"): cat = (50, "Span-4 Vertical") + if netname.startswith("span4_vert_"): cat = (50, "Span-4 Vertical") + if netname.startswith("sp4_r_v_"): cat = (55, "Span-4 Right Vertical") + if netname.startswith("sp4_h_"): cat = (60, "Span-4 Horizontal") + if netname.startswith("span4_horz_"): cat = (60, "Span-4 Horizontal") + if netname.startswith("sp12_v_"): cat = (70, "Span-12 Vertical") + if netname.startswith("span12_vert_"): cat = (70, "Span-12 Vertical") + if netname.startswith("sp12_h_"): cat = (80, "Span-12 Horizontal") + if netname.startswith("span12_horz_"): cat = (80, "Span-12 Horizontal") + return cat + + nets_in_cats = dict() + + for this_name in sorted(this_tile_nets): + nets_in_cats.setdefault(net2cat(this_name), list()).append(this_name) + + for cat in sorted(nets_in_cats): + print('

%s

' % cat[1]) + print('

") + + print("

Nets and their permanent connections to nets in neighbour tiles

") + + # print_expand_div("connection details") + + all_cats = set() + for this_name in sorted(groups_indexed): + all_cats.add(net2cat(this_name)) + + for cat in sorted(all_cats): + print('

%s

' % cat[1]) + print('

    ') + for this_name in sorted(groups_indexed): + if net2cat(this_name) == cat: + neighbour_segs = groups_indexed[this_name] + print("
  • %s" % this_name) + if neighbour_segs: + print("
      ") + for nidx in sorted(neighbour_segs): + if nidx == (tx, ty): + print("
    • (%d %d) %s
    • " % (nidx[0], nidx[1], ", ".join(sorted(neighbour_segs[nidx])))) + else: + print("
    • (%d %d) %s
    • " % (nidx[0], nidx[1], ", ".join(sorted(neighbour_segs[nidx])))) + print("
    ") + print("
  • ") + print("

") + + # print_expand_end() + + print("

Routing Configuration

") + + print("""

This section lists the routing configuration bits in the tile. +The entries titled "routing" configure transfer gates, the entries titled +"buffer" configure tri-state drivers.

""") + + grpgrp = dict() + config_groups = dict() + other_config_groups = dict() + + for entry in ic.tile_db(tx, ty): + if not ic.tile_has_entry(tx, ty, entry): + continue + if entry[1] in ("routing", "buffer"): + cfggrp = entry[1] + " " + entry[3] + "," + ",".join(sorted([bit.replace("!", "") for bit in entry[0]])) + config_groups.setdefault(cfggrp, list()).append(entry) + grpgrp.setdefault(net2cat(entry[3]), set()).add(cfggrp) + else: + grp = other_config_groups.setdefault(" ".join(entry[1:]), set()) + for bit in entry[0]: grp.add(bit) + + for cat in sorted(grpgrp): + print('

%s

' % cat[1]) + + bits_in_cat = set() + + for cfggrp in sorted(grpgrp[cat]): + grp = config_groups[cfggrp] + for bit in cfggrp.split(",")[1:]: + match = re.match(r"B(\d+)\[(\d+)\]", bit) + bits_in_cat.add((int(match.group(1)), int(match.group(2)))) + + print('') + print("") + for cell_nr in range(len(bitmap_cells[0])): + print('' % cell_nr) + print("") + for line_nr, line in enumerate(bitmap_cells): + print("") + print('' % line_nr) + for cell_nr, cell in enumerate(line): + color = cell["bgcolor"] + if (line_nr, cell_nr) not in bits_in_cat: color="#aaa" + print('' % (color, cell["label"])) + print('' % line_nr) + print("") + print("") + for cell_nr in range(len(line)): + print('' % cell_nr) + print("") + print("
%d
B%d%sB%d
%d
") + + # print_expand_div("details") + + src_nets = set() + dst_nets = set() + links = dict() + + for cfggrp in sorted(grpgrp[cat]): + grp = config_groups[cfggrp] + for entry in grp: + src_nets.add(entry[2]) + dst_nets.add(entry[3]) + if entry[1] == "buffer": + assert (entry[2], entry[3]) not in links + links[(entry[2], entry[3])] = 'B' + else: + assert (entry[2], entry[3]) not in links + links[(entry[2], entry[3])] = 'R' + + print('
Connectivity Matrix
') + print('') + dst_net_prefix = "" + dst_net_list = sorted(dst_nets, icebox.cmp_netnames) + if len(dst_net_list) > 1: + while len(set([n[0] for n in dst_net_list])) == 1: + dst_net_prefix += dst_net_list[0][0] + for i in range(len(dst_net_list)): + dst_net_list[i] = dst_net_list[i][1:] + while dst_net_prefix != "" and dst_net_prefix[-1] != "_": + for i in range(len(dst_net_list)): + dst_net_list[i] = dst_net_prefix[-1] + dst_net_list[i] + dst_net_prefix = dst_net_prefix[0:-1] + print('' % (len(dst_net_list), dst_net_prefix)) + print('') + for dn in dst_net_list: + print('' % dn) + print("") + for sn in sorted(src_nets, icebox.cmp_netnames): + print("") + print('' % sn) + for dn in sorted(dst_nets, icebox.cmp_netnames): + if (sn, dn) in links: + print(links[(sn, dn)]) + else: + print('') + print("") + print("
%s
%s
%s 
") + + print('
Configuration Stamps
') + for cfggrp in sorted(grpgrp[cat]): + grp = config_groups[cfggrp] + bits = cfggrp.split(",")[1:] + print('

') + for bit in bits: + print('' % (re.sub(r"B(\d+)\[(\d+)\]", r"B.\1.\2", bit), bit)) + group_lines = list() + is_buffer = True + for entry in grp: + line = '' + for bit in bits: + if bit in entry[0]: + line += '' + else: + line += '' + is_buffer = entry[1] == "buffer" + line += '' % (entry[1], entry[2], entry[3]) + group_lines.append(line) + if is_buffer: + print('') + else: + print('') + for line in sorted(group_lines): + print(line) + print('
%s
10%s%s%s
FunctionSource-NetDestination-Net
FunctionNetNet

') + + # print_expand_end() + + print("

Non-routing Configuration

") + + print("

This section lists the non-routing configuration bits in the tile.

") + + print('') + print("") + for cell_nr in range(len(bitmap_cells[0])): + print('' % cell_nr) + print("") + for line_nr, line in enumerate(bitmap_cells): + print("") + print('' % line_nr) + for cell_nr, cell in enumerate(line): + color = cell["bgcolor"] + if "is_routing" in cell: color="#aaa" + print('' % (color, cell["label"])) + print('' % line_nr) + print("") + print("") + for cell_nr in range(len(line)): + print('' % cell_nr) + print("") + print("
%d
B%d%sB%d
%d
") + + print('

') + for cfggrp in sorted(other_config_groups): + bits = " ".join(['%s' % (re.sub(r"B(\d+)\[(\d+)\]", r"B.\1.\2", bit), bit) for bit in sorted(other_config_groups[cfggrp])]) + cfggrp = cfggrp.replace(" " + list(other_config_groups[cfggrp])[0], "") + print('' % (cfggrp, bits)) + print('
FunctionBits
%s%s

') + + +if outdir is not None: + stdout = sys.stdout + + if not os.path.exists(outdir): + print("Creating %s/" % outdir, file=stdout) + os.makedirs(outdir) + + print("Writing %s/index.html.." % outdir, file=stdout) + sys.stdout = open("%s/index.html" % outdir, "w") + print_index() + + for x in range(ic.max_x+1): + for y in range(ic.max_y+1): + if (x, y) in mktiles: + print("Writing %s/tile_%d_%d.html.." % (outdir, x, y), file=stdout) + sys.stdout = open("%s/tile_%d_%d.html" % (outdir, x, y), "w") + print_tile(x, y) + + print("Writing %s/chipdb.txt..." % outdir, file=stdout) + os.system("python icebox_chipdb.py > %s/chipdb.txt" % outdir) + + sys.stdout = stdout + +elif (tx, ty) == (0, 0): + print_index() + +else: + print_tile(tx, ty) + -- cgit v1.2.3