mirror of https://github.com/YosysHQ/icestorm.git
Import of icestorm-snapshot-150322.zip
This commit is contained in:
commit
dfeb92a46b
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
all:
|
||||
|
||||
install:
|
||||
cp icebox.py /usr/local/bin/icebox.py
|
||||
cp iceboxdb.py /usr/local/bin/iceboxdb.py
|
||||
cp icebox_chipdb.py /usr/local/bin/icebox_chipdb
|
||||
cp icebox_diff.py /usr/local/bin/icebox_diff
|
||||
cp icebox_explain.py /usr/local/bin/icebox_explain
|
||||
cp icebox_html.py /usr/local/bin/icebox_html
|
||||
cp icebox_maps.py /usr/local/bin/icebox_maps
|
||||
cp icebox_vlog.py /usr/local/bin/icebox_vlog
|
||||
|
||||
uninstall:
|
||||
rm -f /usr/local/bin/icebox.py
|
||||
rm -f /usr/local/bin/iceboxdb.py
|
||||
rm -f /usr/local/bin/icebox_chipdb
|
||||
rm -f /usr/local/bin/icebox_diff
|
||||
rm -f /usr/local/bin/icebox_explain
|
||||
rm -f /usr/local/bin/icebox_html
|
||||
rm -f /usr/local/bin/icebox_maps
|
||||
rm -f /usr/local/bin/icebox_vlog
|
||||
|
||||
.PHONY: install uninstall
|
||||
|
||||
|
|
@ -0,0 +1,824 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
import iceboxdb
|
||||
import re, sys
|
||||
|
||||
class iceconfig:
|
||||
def __init__(self):
|
||||
self.clear()
|
||||
|
||||
def clear(self):
|
||||
self.max_x = 0
|
||||
self.max_y = 0
|
||||
self.logic_tiles = dict()
|
||||
self.io_tiles = dict()
|
||||
self.ram_tiles = dict()
|
||||
self.ram_init = dict()
|
||||
|
||||
def setup_empty_1k(self):
|
||||
self.clear()
|
||||
self.max_x = 13
|
||||
self.max_y = 17
|
||||
|
||||
for x in range(1, self.max_x):
|
||||
for y in range(1, self.max_y):
|
||||
if x in (3, 10):
|
||||
self.ram_tiles[(x, y)] = ["0" * 42 for i in range(16)]
|
||||
else:
|
||||
self.logic_tiles[(x, y)] = ["0" * 54 for i in range(16)]
|
||||
|
||||
for x in range(1, self.max_x):
|
||||
self.io_tiles[(x, 0)] = ["0" * 18 for i in range(16)]
|
||||
self.io_tiles[(x, self.max_y)] = ["0" * 18 for i in range(16)]
|
||||
|
||||
for y in range(1, self.max_y):
|
||||
self.io_tiles[(0, y)] = ["0" * 18 for i in range(16)]
|
||||
self.io_tiles[(self.max_x, y)] = ["0" * 18 for i in range(16)]
|
||||
|
||||
def tile(self, x, y):
|
||||
if (x, y) in self.io_tiles: return self.io_tiles[(x, y)]
|
||||
if (x, y) in self.logic_tiles: return self.logic_tiles[(x, y)]
|
||||
if (x, y) in self.ram_tiles: return self.ram_tiles[(x, y)]
|
||||
return None
|
||||
|
||||
def tile_db(self, x, y):
|
||||
if x == 0: return iotile_l_db
|
||||
if y == 0: return iotile_b_db
|
||||
if x == self.max_x: return iotile_r_db
|
||||
if y == self.max_y: return iotile_t_db
|
||||
if (x, y) in self.ram_tiles: return ramtile_db
|
||||
if (x, y) in self.logic_tiles: return logictile_db
|
||||
assert False
|
||||
|
||||
def tile_type(self, x, y):
|
||||
if x == 0: return "IO"
|
||||
if y == 0: return "IO"
|
||||
if x == self.max_x: return "IO"
|
||||
if y == self.max_y: return "IO"
|
||||
if (x, y) in self.ram_tiles: return "RAM"
|
||||
if (x, y) in self.logic_tiles: return "LOGIC"
|
||||
assert False
|
||||
|
||||
def tile_pos(self, x, y):
|
||||
if x == 0 and 0 < y < self.max_y: return "l"
|
||||
if y == 0 and 0 < x < self.max_x: return "b"
|
||||
if x == self.max_x and 0 < y < self.max_y: return "r"
|
||||
if y == self.max_y and 0 < x < self.max_x: return "t"
|
||||
if 0 < x < self.max_x and 0 < y < self.max_y: return "x"
|
||||
return None
|
||||
|
||||
def tile_has_entry(self, x, y, entry):
|
||||
if entry[1] in ("routing", "buffer"):
|
||||
return self.tile_has_net(x, y, entry[2]) and self.tile_has_net(x, y, entry[3])
|
||||
return True
|
||||
|
||||
|
||||
def tile_has_net(self, x, y, netname):
|
||||
if netname.startswith("logic_op_"):
|
||||
if netname.startswith("logic_op_bot_"):
|
||||
if y == self.max_y and 0 < x < self.max_x: return True
|
||||
if netname.startswith("logic_op_bnl_"):
|
||||
if x == self.max_x and 1 < y < self.max_y: return True
|
||||
if y == self.max_y and 1 < x < self.max_x: return True
|
||||
if netname.startswith("logic_op_bnr_"):
|
||||
if x == 0 and 1 < y < self.max_y: return True
|
||||
if y == self.max_y and 0 < x < self.max_x-1: return True
|
||||
|
||||
if netname.startswith("logic_op_top_"):
|
||||
if y == 0 and 0 < x < self.max_x: return True
|
||||
if netname.startswith("logic_op_tnl_"):
|
||||
if x == self.max_x and 0 < y < self.max_y-1: return True
|
||||
if y == 0 and 1 < x < self.max_x: return True
|
||||
if netname.startswith("logic_op_tnr_"):
|
||||
if x == 0 and 0 < y < self.max_y-1: return True
|
||||
if y == 0 and 0 < x < self.max_x-1: return True
|
||||
|
||||
if netname.startswith("logic_op_lft_"):
|
||||
if x == self.max_x: return True
|
||||
if netname.startswith("logic_op_rgt_"):
|
||||
if x == 0: return True
|
||||
|
||||
return False
|
||||
|
||||
if not 0 <= x <= self.max_x: return False
|
||||
if not 0 <= y <= self.max_y: return False
|
||||
return pos_has_net(self.tile_pos(x, y), netname)
|
||||
|
||||
def tile_follow_net(self, x, y, direction, netname):
|
||||
if x == 1 and y not in (0, self.max_y) and direction == 'l': return pos_follow_net("x", "L", netname)
|
||||
if y == 1 and x not in (0, self.max_x) and direction == 'b': return pos_follow_net("x", "B", netname)
|
||||
if x == self.max_x-1 and y not in (0, self.max_y) and direction == 'r': return pos_follow_net("x", "R", netname)
|
||||
if y == self.max_y-1 and x not in (0, self.max_x) and direction == 't': return pos_follow_net("x", "T", netname)
|
||||
return pos_follow_net(self.tile_pos(x, y), direction, netname)
|
||||
|
||||
def follow_funcnet(self, x, y, func):
|
||||
neighbours = set()
|
||||
def do_direction(name, nx, ny):
|
||||
if 0 < nx < self.max_x and 0 < ny < self.max_y:
|
||||
neighbours.add((nx, ny, "neigh_op_%s_%d" % (name, func)))
|
||||
if nx in (0, self.max_x) and 0 < ny < self.max_y and nx != x:
|
||||
neighbours.add((nx, ny, "logic_op_%s_%d" % (name, func)))
|
||||
if ny in (0, self.max_y) and 0 < nx < self.max_x and ny != y:
|
||||
neighbours.add((nx, ny, "logic_op_%s_%d" % (name, func)))
|
||||
do_direction("bot", x, y+1)
|
||||
do_direction("bnl", x+1, y+1)
|
||||
do_direction("bnr", x-1, y+1)
|
||||
do_direction("top", x, y-1)
|
||||
do_direction("tnl", x+1, y-1)
|
||||
do_direction("tnr", x-1, y-1)
|
||||
do_direction("lft", x+1, y )
|
||||
do_direction("rgt", x-1, y )
|
||||
return neighbours
|
||||
|
||||
def lookup_funcnet(self, nx, ny, x, y, func):
|
||||
npos = self.tile_pos(nx, ny)
|
||||
pos = self.tile_pos(x, y)
|
||||
|
||||
if npos is not None and pos is not None:
|
||||
if npos == "x":
|
||||
return (nx, ny, "lutff_%d/out" % func)
|
||||
|
||||
elif pos == "x" and npos in ("l", "r", "t", "b"):
|
||||
if func in (0, 4): return (nx, ny, "io_0/D_IN_0")
|
||||
if func in (1, 5): return (nx, ny, "io_0/D_IN_1")
|
||||
if func in (2, 6): return (nx, ny, "io_1/D_IN_0")
|
||||
if func in (3, 7): return (nx, ny, "io_1/D_IN_1")
|
||||
|
||||
return None
|
||||
|
||||
def rlookup_funcnet(self, x, y, netname):
|
||||
funcnets = set()
|
||||
|
||||
if netname == "io_0/D_IN_0":
|
||||
for net in self.follow_funcnet(x, y, 0) | self.follow_funcnet(x, y, 4):
|
||||
if self.tile_pos(net[0], net[1]) == "x": funcnets.add(net)
|
||||
|
||||
if netname == "io_0/D_IN_1":
|
||||
for net in self.follow_funcnet(x, y, 1) | self.follow_funcnet(x, y, 5):
|
||||
if self.tile_pos(net[0], net[1]) == "x": funcnets.add(net)
|
||||
|
||||
if netname == "io_1/D_IN_0":
|
||||
for net in self.follow_funcnet(x, y, 2) | self.follow_funcnet(x, y, 6):
|
||||
if self.tile_pos(net[0], net[1]) == "x": funcnets.add(net)
|
||||
|
||||
if netname == "io_1/D_IN_1":
|
||||
for net in self.follow_funcnet(x, y, 3) | self.follow_funcnet(x, y, 7):
|
||||
if self.tile_pos(net[0], net[1]) == "x": funcnets.add(net)
|
||||
|
||||
match = re.match(r"lutff_(\d+)/out", netname)
|
||||
if match:
|
||||
funcnets |= self.follow_funcnet(x, y, int(match.group(1)))
|
||||
|
||||
return funcnets
|
||||
|
||||
def follow_net(self, netspec):
|
||||
x, y, netname = netspec
|
||||
neighbours = self.rlookup_funcnet(x, y, netname)
|
||||
|
||||
if netname == "carry_in" and y > 1:
|
||||
neighbours.add((x, y-1, "lutff_7/cout"))
|
||||
|
||||
if netname == "lutff_7/cout" and y+1 < self.max_y:
|
||||
neighbours.add((x, y+1, "carry_in"))
|
||||
|
||||
if netname.startswith("glb_netwk_"):
|
||||
for nx in range(self.max_x+1):
|
||||
for ny in range(self.max_y+1):
|
||||
if self.tile_pos(nx, ny) is not None:
|
||||
neighbours.add((nx, ny, netname))
|
||||
|
||||
match = re.match(r"sp4_r_v_b_(\d+)", netname)
|
||||
if match and 0 < x < self.max_x-1:
|
||||
neighbours.add((x+1, y, sp4v_normalize("sp4_v_b_" + match.group(1))))
|
||||
|
||||
match = re.match(r"sp4_v_[bt]_(\d+)", netname)
|
||||
if match and 1 < x < self.max_x:
|
||||
n = sp4v_normalize(netname, "b")
|
||||
if n is not None:
|
||||
n = n.replace("sp4_", "sp4_r_")
|
||||
neighbours.add((x-1, y, n))
|
||||
|
||||
match = re.match(r"(logic|neigh)_op_(...)_(\d+)", netname)
|
||||
if match:
|
||||
if match.group(2) == "bot": nx, ny = (x, y-1)
|
||||
if match.group(2) == "bnl": nx, ny = (x-1, y-1)
|
||||
if match.group(2) == "bnr": nx, ny = (x+1, y-1)
|
||||
if match.group(2) == "top": nx, ny = (x, y+1)
|
||||
if match.group(2) == "tnl": nx, ny = (x-1, y+1)
|
||||
if match.group(2) == "tnr": nx, ny = (x+1, y+1)
|
||||
if match.group(2) == "lft": nx, ny = (x-1, y )
|
||||
if match.group(2) == "rgt": nx, ny = (x+1, y )
|
||||
n = self.lookup_funcnet(nx, ny, x, y, int(match.group(3)))
|
||||
if n is not None:
|
||||
neighbours.add(n)
|
||||
|
||||
for direction in ["l", "r", "t", "b"]:
|
||||
n = self.tile_follow_net(x, y, direction, netname)
|
||||
if n is not None:
|
||||
if direction == "l": s = (x-1, y, n)
|
||||
if direction == "r": s = (x+1, y, n)
|
||||
if direction == "t": s = (x, y+1, n)
|
||||
if direction == "b": s = (x, y-1, n)
|
||||
|
||||
if s[0] in (0, self.max_x) and s[1] in (0, self.max_y):
|
||||
if re.match("span4_(vert|horz)_[lrtb]_\d+$", n):
|
||||
vert_net = n.replace("_l_", "_t_").replace("_r_", "_b_").replace("_horz_", "_vert_")
|
||||
horz_net = n.replace("_t_", "_l_").replace("_b_", "_r_").replace("_vert_", "_horz_")
|
||||
|
||||
if s[0] == 0 and s[1] == 0:
|
||||
if direction == "l": s = (0, 1, vert_net)
|
||||
if direction == "b": s = (1, 0, horz_net)
|
||||
|
||||
if s[0] == self.max_x and s[1] == self.max_y:
|
||||
if direction == "r": s = (self.max_x, self.max_y-1, vert_net)
|
||||
if direction == "t": s = (self.max_x-1, self.max_y, horz_net)
|
||||
|
||||
vert_net = netname.replace("_l_", "_t_").replace("_r_", "_b_").replace("_horz_", "_vert_")
|
||||
horz_net = netname.replace("_t_", "_l_").replace("_b_", "_r_").replace("_vert_", "_horz_")
|
||||
|
||||
if s[0] == 0 and s[1] == self.max_y:
|
||||
if direction == "l": s = (0, self.max_y-1, vert_net)
|
||||
if direction == "t": s = (1, self.max_y, horz_net)
|
||||
|
||||
if s[0] == self.max_x and s[1] == 0:
|
||||
if direction == "r": s = (self.max_x, 1, vert_net)
|
||||
if direction == "b": s = (self.max_x-1, 0, horz_net)
|
||||
|
||||
if self.tile_has_net(s[0], s[1], s[2]):
|
||||
neighbours.add((s[0], s[1], s[2]))
|
||||
return neighbours
|
||||
|
||||
def group_segments(self, all_from_tiles=set()):
|
||||
seed_segments = set()
|
||||
seen_segments = set()
|
||||
connected_segments = dict()
|
||||
grouped_segments = set()
|
||||
|
||||
for idx, tile in self.io_tiles.items():
|
||||
tc = tileconfig(tile)
|
||||
pintypes = [ list("000000"), list("000000") ]
|
||||
for entry in self.tile_db(idx[0], idx[1]):
|
||||
if entry[1].startswith("IOB_") and entry[2].startswith("PINTYPE_") and tc.match(entry[0]):
|
||||
pintypes[int(entry[1][-1])][int(entry[2][-1])] = "1"
|
||||
if "".join(pintypes[0][2:6]) != "0000":
|
||||
seed_segments.add((idx[0], idx[1], "io_0/D_OUT_0"))
|
||||
if "".join(pintypes[1][2:6]) != "0000":
|
||||
seed_segments.add((idx[0], idx[1], "io_1/D_OUT_0"))
|
||||
|
||||
def add_seed_segments(idx, tile, db):
|
||||
tc = tileconfig(tile)
|
||||
for entry in db:
|
||||
if entry[1] in ("routing", "buffer"):
|
||||
config_match = tc.match(entry[0])
|
||||
if idx in all_from_tiles or config_match:
|
||||
if not self.tile_has_net(idx[0], idx[1], entry[2]): continue
|
||||
if not self.tile_has_net(idx[0], idx[1], entry[3]): continue
|
||||
s1 = (idx[0], idx[1], entry[2])
|
||||
s2 = (idx[0], idx[1], entry[3])
|
||||
if config_match:
|
||||
connected_segments.setdefault(s1, set()).add(s2)
|
||||
connected_segments.setdefault(s2, set()).add(s1)
|
||||
seed_segments.add(s1)
|
||||
seed_segments.add(s2)
|
||||
|
||||
for idx, tile in self.io_tiles.items():
|
||||
add_seed_segments(idx, tile, self.tile_db(idx[0], idx[1]))
|
||||
|
||||
for idx, tile in self.logic_tiles.items():
|
||||
if idx in all_from_tiles:
|
||||
seed_segments.add((idx[0], idx[1], "lutff_7/cout"))
|
||||
add_seed_segments(idx, tile, logictile_db)
|
||||
|
||||
for idx, tile in self.ram_tiles.items():
|
||||
add_seed_segments(idx, tile, ramtile_db)
|
||||
|
||||
while seed_segments:
|
||||
queue = set()
|
||||
segments = set()
|
||||
queue.add(seed_segments.pop())
|
||||
while queue:
|
||||
for s in self.expand_net(queue.pop()):
|
||||
if s not in segments:
|
||||
segments.add(s)
|
||||
assert s not in seen_segments
|
||||
seen_segments.add(s)
|
||||
seed_segments.discard(s)
|
||||
if s in connected_segments:
|
||||
for cs in connected_segments[s]:
|
||||
if not cs in segments:
|
||||
queue.add(cs)
|
||||
for s in segments:
|
||||
assert s not in seed_segments
|
||||
grouped_segments.add(tuple(sorted(segments)))
|
||||
|
||||
return grouped_segments
|
||||
|
||||
def expand_net(self, netspec):
|
||||
queue = set()
|
||||
segments = set()
|
||||
queue.add(netspec)
|
||||
while queue:
|
||||
n = queue.pop()
|
||||
segments.add(n)
|
||||
for k in self.follow_net(n):
|
||||
if k not in segments:
|
||||
queue.add(k)
|
||||
return segments
|
||||
|
||||
def read_file(self, filename, logprefix=""):
|
||||
self.clear()
|
||||
current_data = None
|
||||
expected_data_lines = 0
|
||||
with open(filename, "r") as f:
|
||||
for linenum, linetext in enumerate(f):
|
||||
# print("DEBUG: input line %d: %s" % (linenum, linetext.strip()))
|
||||
line = linetext.strip().split()
|
||||
if len(line) == 0:
|
||||
assert expected_data_lines == 0
|
||||
continue
|
||||
if line[0][0] != ".":
|
||||
if line[0][0] != "0" and line[0][0] != "1":
|
||||
print("%sWarning: ignoring data block in line %d: %s" % (logprefix, linenum, linetext.strip()))
|
||||
expected_data_lines = 0
|
||||
continue
|
||||
assert expected_data_lines != 0
|
||||
current_data.append(line[0])
|
||||
expected_data_lines -= 1
|
||||
continue
|
||||
assert expected_data_lines == 0
|
||||
if line[0] in (".io_tile", ".logic_tile", ".ram_tile"):
|
||||
current_data = list()
|
||||
expected_data_lines = 16
|
||||
self.max_x = max(self.max_x, int(line[1]))
|
||||
self.max_y = max(self.max_y, int(line[2]))
|
||||
if line[0] == ".io_tile":
|
||||
self.io_tiles[(int(line[1]), int(line[2]))] = current_data
|
||||
continue
|
||||
if line[0] == ".logic_tile":
|
||||
self.logic_tiles[(int(line[1]), int(line[2]))] = current_data
|
||||
continue
|
||||
if line[0] == ".ram_tile":
|
||||
self.ram_tiles[(int(line[1]), int(line[2]))] = current_data
|
||||
continue
|
||||
if line[0] == ".device":
|
||||
assert line[1] == "1k"
|
||||
continue
|
||||
print("%sWarning: ignoring line %d: %s" % (logprefix, linenum, linetext.strip()))
|
||||
|
||||
class tileconfig:
|
||||
def __init__(self, tile):
|
||||
self.bits = set()
|
||||
for k, line in enumerate(tile):
|
||||
for i in range(len(line)):
|
||||
if line[i] == "1":
|
||||
self.bits.add("B%d[%d]" % (k, i))
|
||||
else:
|
||||
self.bits.add("!B%d[%d]" % (k, i))
|
||||
def match(self, pattern):
|
||||
for bit in pattern:
|
||||
if not bit in self.bits:
|
||||
return False
|
||||
return True
|
||||
|
||||
if False:
|
||||
## Lattice span net name normalization
|
||||
|
||||
valid_sp4_h_l = set([1, 2, 4, 5, 7, 9, 10, 11, 15, 16, 17, 21, 24, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47])
|
||||
valid_sp4_h_r = set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 19, 21, 24, 25, 27, 30, 31, 33, 34, 35, 36, 38, 39, 40, 41, 42, 43, 44, 45, 46])
|
||||
|
||||
valid_sp4_v_t = set([1, 3, 5, 9, 12, 14, 16, 17, 18, 21, 22, 23, 26, 28, 29, 30, 32, 33, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47])
|
||||
valid_sp4_v_b = set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 18, 19, 21, 22, 23, 24, 26, 30, 33, 36, 37, 38, 42, 46, 47])
|
||||
|
||||
valid_sp12_h_l = set([3, 4, 5, 12, 14, 16, 17, 18, 21, 22, 23])
|
||||
valid_sp12_h_r = set([0, 1, 2, 3, 5, 8, 9, 10, 11, 12, 13, 14, 16, 20, 23])
|
||||
|
||||
valid_sp12_v_t = set([0, 1, 2, 3, 6, 9, 10, 12, 14, 21, 22, 23])
|
||||
valid_sp12_v_b = set([0, 1, 6, 7, 8, 11, 12, 14, 16, 18, 19, 20, 21, 23])
|
||||
|
||||
else:
|
||||
## IceStorm span net name normalization
|
||||
|
||||
valid_sp4_h_l = set(range(36, 48))
|
||||
valid_sp4_h_r = set(range(48))
|
||||
|
||||
valid_sp4_v_t = set(range(36, 48))
|
||||
valid_sp4_v_b = set(range(48))
|
||||
|
||||
valid_sp12_h_l = set(range(22, 24))
|
||||
valid_sp12_h_r = set(range(24))
|
||||
|
||||
valid_sp12_v_t = set(range(22, 24))
|
||||
valid_sp12_v_b = set(range(24))
|
||||
|
||||
def sp4h_normalize(netname, edge=""):
|
||||
m = re.match("sp4_h_([lr])_(\d+)$", netname)
|
||||
assert m
|
||||
if not m: return None
|
||||
cur_edge = m.group(1)
|
||||
cur_index = int(m.group(2))
|
||||
|
||||
if cur_edge == edge:
|
||||
return netname
|
||||
|
||||
if cur_edge == "r" and (edge == "l" or (edge == "" and cur_index not in valid_sp4_h_r)):
|
||||
if cur_index < 12:
|
||||
return None
|
||||
return "sp4_h_l_%d" % ((cur_index-12)^1)
|
||||
|
||||
if cur_edge == "l" and (edge == "r" or (edge == "" and cur_index not in valid_sp4_h_l)):
|
||||
if cur_index >= 36:
|
||||
return None
|
||||
return "sp4_h_r_%d" % ((cur_index+12)^1)
|
||||
|
||||
return netname
|
||||
|
||||
def sp4v_normalize(netname, edge=""):
|
||||
m = re.match("sp4_v_([bt])_(\d+)$", netname)
|
||||
assert m
|
||||
if not m: return None
|
||||
cur_edge = m.group(1)
|
||||
cur_index = int(m.group(2))
|
||||
|
||||
if cur_edge == edge:
|
||||
return netname
|
||||
|
||||
if cur_edge == "b" and (edge == "t" or (edge == "" and cur_index not in valid_sp4_v_b)):
|
||||
if cur_index < 12:
|
||||
return None
|
||||
return "sp4_v_t_%d" % ((cur_index-12)^1)
|
||||
|
||||
if cur_edge == "t" and (edge == "b" or (edge == "" and cur_index not in valid_sp4_v_t)):
|
||||
if cur_index >= 36:
|
||||
return None
|
||||
return "sp4_v_b_%d" % ((cur_index+12)^1)
|
||||
|
||||
return netname
|
||||
|
||||
def sp12h_normalize(netname, edge=""):
|
||||
m = re.match("sp12_h_([lr])_(\d+)$", netname)
|
||||
assert m
|
||||
if not m: return None
|
||||
cur_edge = m.group(1)
|
||||
cur_index = int(m.group(2))
|
||||
|
||||
if cur_edge == edge:
|
||||
return netname
|
||||
|
||||
if cur_edge == "r" and (edge == "l" or (edge == "" and cur_index not in valid_sp12_h_r)):
|
||||
if cur_index < 2:
|
||||
return None
|
||||
return "sp12_h_l_%d" % ((cur_index-2)^1)
|
||||
|
||||
if cur_edge == "l" and (edge == "r" or (edge == "" and cur_index not in valid_sp12_h_l)):
|
||||
if cur_index >= 22:
|
||||
return None
|
||||
return "sp12_h_r_%d" % ((cur_index+2)^1)
|
||||
|
||||
return netname
|
||||
|
||||
def sp12v_normalize(netname, edge=""):
|
||||
m = re.match("sp12_v_([bt])_(\d+)$", netname)
|
||||
assert m
|
||||
if not m: return None
|
||||
cur_edge = m.group(1)
|
||||
cur_index = int(m.group(2))
|
||||
|
||||
if cur_edge == edge:
|
||||
return netname
|
||||
|
||||
if cur_edge == "b" and (edge == "t" or (edge == "" and cur_index not in valid_sp12_v_b)):
|
||||
if cur_index < 2:
|
||||
return None
|
||||
return "sp12_v_t_%d" % ((cur_index-2)^1)
|
||||
|
||||
if cur_edge == "t" and (edge == "b" or (edge == "" and cur_index not in valid_sp12_v_t)):
|
||||
if cur_index >= 22:
|
||||
return None
|
||||
return "sp12_v_b_%d" % ((cur_index+2)^1)
|
||||
|
||||
return netname
|
||||
|
||||
def netname_normalize(netname, edge=""):
|
||||
if netname.startswith("sp4_v_"): return sp4v_normalize(netname, edge)
|
||||
if netname.startswith("sp4_h_"): return sp4h_normalize(netname, edge)
|
||||
if netname.startswith("sp12_v_"): return sp12v_normalize(netname, edge)
|
||||
if netname.startswith("sp12_h_"): return sp12h_normalize(netname, edge)
|
||||
if netname.startswith("input_2_"): netname = netname.replace("input_2_", "wire_logic_cluster/lc_") + "/in_2"
|
||||
netname = netname.replace("lc_trk_", "local_")
|
||||
netname = netname.replace("lc_", "lutff_")
|
||||
netname = netname.replace("wire_logic_cluster/", "")
|
||||
netname = netname.replace("wire_io_cluster/", "")
|
||||
match = re.match(r"(...)_op_(.*)", netname)
|
||||
if match:
|
||||
netname = "neigh_op_%s_%s" % (match.group(1), match.group(2))
|
||||
if re.match(r"lutff_7/(cen|clk|s_r)", netname):
|
||||
netname = netname.replace("lutff_7/", "lutff_global/")
|
||||
if re.match(r"io_1/(cen|inclk|outclk)", netname):
|
||||
netname = netname.replace("io_1/", "io_global/")
|
||||
if netname == "carry_in_mux/cout":
|
||||
return "carry_in_mux"
|
||||
return netname
|
||||
|
||||
def pos_has_net(pos, netname):
|
||||
if pos in ("l", "r"):
|
||||
if re.search(r"_vert_\d+$", netname): return False
|
||||
if re.search(r"_horz_[rl]_\d+$", netname): return False
|
||||
if pos in ("t", "b"):
|
||||
if re.search(r"_horz_\d+$", netname): return False
|
||||
if re.search(r"_vert_[bt]_\d+$", netname): return False
|
||||
return True
|
||||
|
||||
def pos_follow_net(pos, direction, netname):
|
||||
if pos == "x":
|
||||
m = re.match("sp4_h_[lr]_(\d+)$", netname)
|
||||
if m and direction in ("l", "L"):
|
||||
n = sp4h_normalize(netname, "l")
|
||||
if n is not None:
|
||||
if direction == "l":
|
||||
n = re.sub("_l_", "_r_", n)
|
||||
n = sp4h_normalize(n)
|
||||
else:
|
||||
n = re.sub("_l_", "_", n)
|
||||
n = re.sub("sp4_h_", "span4_horz_", n)
|
||||
return n
|
||||
if m and direction in ("r", "R"):
|
||||
n = sp4h_normalize(netname, "r")
|
||||
if n is not None:
|
||||
if direction == "r":
|
||||
n = re.sub("_r_", "_l_", n)
|
||||
n = sp4h_normalize(n)
|
||||
else:
|
||||
n = re.sub("_r_", "_", n)
|
||||
n = re.sub("sp4_h_", "span4_horz_", n)
|
||||
return n
|
||||
|
||||
m = re.match("sp4_v_[tb]_(\d+)$", netname)
|
||||
if m and direction in ("t", "T"):
|
||||
n = sp4v_normalize(netname, "t")
|
||||
if n is not None:
|
||||
if direction == "t":
|
||||
n = re.sub("_t_", "_b_", n)
|
||||
n = sp4v_normalize(n)
|
||||
else:
|
||||
n = re.sub("_t_", "_", n)
|
||||
n = re.sub("sp4_v_", "span4_vert_", n)
|
||||
return n
|
||||
if m and direction in ("b", "B"):
|
||||
n = sp4v_normalize(netname, "b")
|
||||
if n is not None:
|
||||
if direction == "b":
|
||||
n = re.sub("_b_", "_t_", n)
|
||||
n = sp4v_normalize(n)
|
||||
else:
|
||||
n = re.sub("_b_", "_", n)
|
||||
n = re.sub("sp4_v_", "span4_vert_", n)
|
||||
return n
|
||||
|
||||
m = re.match("sp12_h_[lr]_(\d+)$", netname)
|
||||
if m and direction in ("l", "L"):
|
||||
n = sp12h_normalize(netname, "l")
|
||||
if n is not None:
|
||||
if direction == "l":
|
||||
n = re.sub("_l_", "_r_", n)
|
||||
n = sp12h_normalize(n)
|
||||
else:
|
||||
n = re.sub("_l_", "_", n)
|
||||
n = re.sub("sp12_h_", "span12_horz_", n)
|
||||
return n
|
||||
if m and direction in ("r", "R"):
|
||||
n = sp12h_normalize(netname, "r")
|
||||
if n is not None:
|
||||
if direction == "r":
|
||||
n = re.sub("_r_", "_l_", n)
|
||||
n = sp12h_normalize(n)
|
||||
else:
|
||||
n = re.sub("_r_", "_", n)
|
||||
n = re.sub("sp12_h_", "span12_horz_", n)
|
||||
return n
|
||||
|
||||
m = re.match("sp12_v_[tb]_(\d+)$", netname)
|
||||
if m and direction in ("t", "T"):
|
||||
n = sp12v_normalize(netname, "t")
|
||||
if n is not None:
|
||||
if direction == "t":
|
||||
n = re.sub("_t_", "_b_", n)
|
||||
n = sp12v_normalize(n)
|
||||
else:
|
||||
n = re.sub("_t_", "_", n)
|
||||
n = re.sub("sp12_v_", "span12_vert_", n)
|
||||
return n
|
||||
if m and direction in ("b", "B"):
|
||||
n = sp12v_normalize(netname, "b")
|
||||
if n is not None:
|
||||
if direction == "b":
|
||||
n = re.sub("_b_", "_t_", n)
|
||||
n = sp12v_normalize(n)
|
||||
else:
|
||||
n = re.sub("_b_", "_", n)
|
||||
n = re.sub("sp12_v_", "span12_vert_", n)
|
||||
return n
|
||||
|
||||
if pos in ("l", "r" ):
|
||||
m = re.match("span4_vert_([bt])_(\d+)$", netname)
|
||||
if m:
|
||||
case, idx = direction + m.group(1), int(m.group(2))
|
||||
if case == "tt":
|
||||
return "span4_vert_b_%d" % idx
|
||||
if case == "tb" and idx >= 4:
|
||||
return "span4_vert_b_%d" % (idx-4)
|
||||
if case == "bb" and idx < 12:
|
||||
return "span4_vert_b_%d" % (idx+4)
|
||||
if case == "bb" and idx >= 12:
|
||||
return "span4_vert_t_%d" % idx
|
||||
|
||||
if pos in ("t", "b" ):
|
||||
m = re.match("span4_horz_([rl])_(\d+)$", netname)
|
||||
if m:
|
||||
case, idx = direction + m.group(1), int(m.group(2))
|
||||
if case == "ll":
|
||||
return "span4_horz_r_%d" % idx
|
||||
if case == "lr" and idx >= 4:
|
||||
return "span4_horz_r_%d" % (idx-4)
|
||||
if case == "rr" and idx < 12:
|
||||
return "span4_horz_r_%d" % (idx+4)
|
||||
if case == "rr" and idx >= 12:
|
||||
return "span4_horz_l_%d" % idx
|
||||
|
||||
if pos == "l" and direction == "r":
|
||||
m = re.match("span4_horz_(\d+)$", netname)
|
||||
if m: return sp4h_normalize("sp4_h_l_%s" % m.group(1))
|
||||
m = re.match("span12_horz_(\d+)$", netname)
|
||||
if m: return sp12h_normalize("sp12_h_l_%s" % m.group(1))
|
||||
|
||||
if pos == "r" and direction == "l":
|
||||
m = re.match("span4_horz_(\d+)$", netname)
|
||||
if m: return sp4h_normalize("sp4_h_r_%s" % m.group(1))
|
||||
m = re.match("span12_horz_(\d+)$", netname)
|
||||
if m: return sp12h_normalize("sp12_h_r_%s" % m.group(1))
|
||||
|
||||
if pos == "t" and direction == "b":
|
||||
m = re.match("span4_vert_(\d+)$", netname)
|
||||
if m: return sp4v_normalize("sp4_v_t_%s" % m.group(1))
|
||||
m = re.match("span12_vert_(\d+)$", netname)
|
||||
if m: return sp12v_normalize("sp12_v_t_%s" % m.group(1))
|
||||
|
||||
if pos == "b" and direction == "t":
|
||||
m = re.match("span4_vert_(\d+)$", netname)
|
||||
if m: return sp4v_normalize("sp4_v_b_%s" % m.group(1))
|
||||
m = re.match("span12_vert_(\d+)$", netname)
|
||||
if m: return sp12v_normalize("sp12_v_b_%s" % m.group(1))
|
||||
|
||||
return None
|
||||
|
||||
def get_lutff_bits(tile, index):
|
||||
bits = list("--------------------")
|
||||
for k, line in enumerate(tile):
|
||||
for i in range(36, 46):
|
||||
lutff_idx = k // 2
|
||||
lutff_bitnum = (i-36) + 10*(k%2)
|
||||
if lutff_idx == index:
|
||||
bits[lutff_bitnum] = line[i];
|
||||
return bits
|
||||
|
||||
def get_lutff_lut_bits(tile, index):
|
||||
lutff_bits = get_lutff_bits(tile, index)
|
||||
return [lutff_bits[i] for i in [4, 14, 15, 5, 6, 16, 17, 7, 3, 13, 12, 2, 1, 11, 10, 0]]
|
||||
|
||||
def get_lutff_seq_bits(tile, index):
|
||||
lutff_bits = get_lutff_bits(tile, index)
|
||||
return [lutff_bits[i] for i in [8, 9, 18, 19]]
|
||||
|
||||
def get_carry_cascade_bit(tile):
|
||||
return tile[1][49]
|
||||
|
||||
def get_carry_bit(tile):
|
||||
return tile[1][50]
|
||||
|
||||
def get_negclk_bit(tile):
|
||||
return tile[0][0]
|
||||
|
||||
def cmp_netnames(a, b):
|
||||
a = re.sub(r"\d+", lambda m: "%09d" % int(m.group(0)), a)
|
||||
b = re.sub(r"\d+", lambda m: "%09d" % int(m.group(0)), b)
|
||||
return cmp(a, b)
|
||||
|
||||
def run_checks_neigh():
|
||||
print("Running consistency checks on neighbour finder..")
|
||||
ic = iceconfig()
|
||||
ic.max_x = 6
|
||||
ic.max_y = 6
|
||||
|
||||
all_segments = set()
|
||||
|
||||
def add_segments(idx, db):
|
||||
for entry in db:
|
||||
if entry[1] in ("routing", "buffer"):
|
||||
if not ic.tile_has_net(idx[0], idx[1], entry[2]): continue
|
||||
if not ic.tile_has_net(idx[0], idx[1], entry[3]): continue
|
||||
all_segments.add((idx[0], idx[1], entry[2]))
|
||||
all_segments.add((idx[0], idx[1], entry[3]))
|
||||
|
||||
for x in range(ic.max_x+1):
|
||||
for y in range(ic.max_x+1):
|
||||
if x in (0, ic.max_x) and y in (0, ic.max_y):
|
||||
continue
|
||||
if x in (0, ic.max_x) or y in (0, ic.max_y):
|
||||
add_segments((x, y), ic.tile_db(x, y))
|
||||
else:
|
||||
add_segments((x, y), logictile_db)
|
||||
all_segments.add((x, y, "lutff_7/cout"))
|
||||
|
||||
for s1 in all_segments:
|
||||
for s2 in ic.follow_net(s1):
|
||||
if s1 not in ic.follow_net(s2):
|
||||
print("ERROR: %s -> %s, but not vice versa!" % (s1, s2))
|
||||
print("Neighbours of %s:" % (s1,))
|
||||
for s in ic.follow_net(s1):
|
||||
print(" ", s)
|
||||
print("Neighbours of %s:" % (s2,))
|
||||
for s in ic.follow_net(s2):
|
||||
print(" ", s)
|
||||
print()
|
||||
|
||||
def run_checks():
|
||||
run_checks_neigh()
|
||||
|
||||
def parse_db(text):
|
||||
db = list()
|
||||
for line in text.split("\n"):
|
||||
line = line.split("\t")
|
||||
if len(line) == 0 or line[0] == "":
|
||||
continue
|
||||
line[0] = line[0].split(",")
|
||||
db.append(line)
|
||||
return db
|
||||
|
||||
iotile_full_db = parse_db(iceboxdb.database_io_txt)
|
||||
logictile_db = parse_db(iceboxdb.database_logic_txt)
|
||||
ramtile_db = parse_db(iceboxdb.database_ram_txt)
|
||||
pinloc_db = [[int(s) for s in line.split()] for line in iceboxdb.pinloc_txt.split("\n") if line != ""]
|
||||
|
||||
iotile_l_db = list()
|
||||
iotile_r_db = list()
|
||||
iotile_t_db = list()
|
||||
iotile_b_db = list()
|
||||
|
||||
for entry in iotile_full_db:
|
||||
if entry[1] == "buffer" and entry[2].startswith("IO_L."):
|
||||
new_entry = entry[:]
|
||||
new_entry[2] = new_entry[2][5:]
|
||||
iotile_l_db.append(new_entry)
|
||||
elif entry[1] == "buffer" and entry[2].startswith("IO_R."):
|
||||
new_entry = entry[:]
|
||||
new_entry[2] = new_entry[2][5:]
|
||||
iotile_r_db.append(new_entry)
|
||||
elif entry[1] == "buffer" and entry[2].startswith("IO_T."):
|
||||
new_entry = entry[:]
|
||||
new_entry[2] = new_entry[2][5:]
|
||||
iotile_t_db.append(new_entry)
|
||||
elif entry[1] == "buffer" and entry[2].startswith("IO_B."):
|
||||
new_entry = entry[:]
|
||||
new_entry[2] = new_entry[2][5:]
|
||||
iotile_b_db.append(new_entry)
|
||||
else:
|
||||
iotile_l_db.append(entry)
|
||||
iotile_r_db.append(entry)
|
||||
iotile_t_db.append(entry)
|
||||
iotile_b_db.append(entry)
|
||||
|
||||
logictile_db.append([["B1[49]"], "buffer", "carry_in", "carry_in_mux"])
|
||||
logictile_db.append([["B1[50]"], "CarryInSet"])
|
||||
|
||||
for db in [iotile_l_db, iotile_r_db, iotile_t_db, iotile_b_db, logictile_db, ramtile_db]:
|
||||
for entry in db:
|
||||
if entry[1] in ("buffer", "routing"):
|
||||
entry[2] = netname_normalize(entry[2])
|
||||
entry[3] = netname_normalize(entry[3])
|
||||
unique_entries = dict()
|
||||
while db:
|
||||
entry = db.pop()
|
||||
key = " ".join(entry[1:]) + str(entry)
|
||||
unique_entries[key] = entry
|
||||
for key in sorted(unique_entries):
|
||||
db.append(unique_entries[key])
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_checks()
|
||||
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import icebox
|
||||
import getopt, sys, re
|
||||
|
||||
ic = icebox.iceconfig()
|
||||
ic.setup_empty_1k()
|
||||
|
||||
all_tiles = set()
|
||||
for x in range(ic.max_x+1):
|
||||
for y in range(ic.max_y+1):
|
||||
if ic.tile(x, y) is not None:
|
||||
all_tiles.add((x, y))
|
||||
|
||||
seg_to_net = dict()
|
||||
net_to_segs = list()
|
||||
|
||||
print("""#
|
||||
# IceBox Database Dump for iCE40 HX1K / LP1K
|
||||
#
|
||||
#
|
||||
# Quick File Format Reference:
|
||||
# ----------------------------
|
||||
#
|
||||
#
|
||||
# .io_tile X Y
|
||||
# .logic_tile X Y
|
||||
# .ram_tile X Y
|
||||
#
|
||||
# declares the existence of a IO/LOGIC/RAM tile with the given coordinates
|
||||
#
|
||||
#
|
||||
# .net NET_INDEX
|
||||
# X1 Y1 name1
|
||||
# X2 Y2 name2
|
||||
# ...
|
||||
#
|
||||
# declares a net on the chip and lists its various names in different tiles
|
||||
#
|
||||
#
|
||||
# .buffer X Y DST_NET_INDEX CONFIG_BITS_NAMES
|
||||
# CONFIG_BITS_VALUES_1 SRC_NET_INDEX_1
|
||||
# CONFIG_BITS_VALUES_2 SRC_NET_INDEX_2
|
||||
# ...
|
||||
#
|
||||
# declares a buffer in the specified tile
|
||||
#
|
||||
#
|
||||
# .routing X Y DST_NET_INDEX CONFIG_BITS_NAMES
|
||||
# CONFIG_BITS_VALUES_1 SRC_NET_INDEX_1
|
||||
# CONFIG_BITS_VALUES_2 SRC_NET_INDEX_2
|
||||
# ...
|
||||
#
|
||||
# declares a routing switch in the specified tile
|
||||
#
|
||||
""")
|
||||
|
||||
for idx in sorted(ic.io_tiles):
|
||||
print(".io_tile %d %d" % idx)
|
||||
print()
|
||||
|
||||
for idx in sorted(ic.logic_tiles):
|
||||
print(".logic_tile %d %d" % idx)
|
||||
print()
|
||||
|
||||
for idx in sorted(ic.ram_tiles):
|
||||
print(".ram_tile %d %d" % idx)
|
||||
print()
|
||||
|
||||
for group in sorted(ic.group_segments(all_tiles)):
|
||||
netidx = len(net_to_segs)
|
||||
net_to_segs.append(group)
|
||||
print(".net %d" % netidx)
|
||||
for seg in group:
|
||||
print("%d %d %s" % seg)
|
||||
assert seg not in seg_to_net
|
||||
seg_to_net[seg] = netidx
|
||||
print()
|
||||
|
||||
for idx in sorted(all_tiles):
|
||||
db = ic.tile_db(idx[0], idx[1])
|
||||
db_by_bits = dict()
|
||||
for entry in db:
|
||||
if entry[1] in ("buffer", "routing") and ic.tile_has_net(idx[0], idx[1], entry[2]) and ic.tile_has_net(idx[0], idx[1], entry[3]):
|
||||
bits = tuple([entry[1]] + sorted([bit.replace("!", "") for bit in entry[0]]))
|
||||
db_by_bits.setdefault(bits, list()).append(entry)
|
||||
for bits in sorted(db_by_bits):
|
||||
dst_net = None
|
||||
for entry in sorted(db_by_bits[bits]):
|
||||
assert (idx[0], idx[1], entry[3]) in seg_to_net
|
||||
if dst_net is None:
|
||||
dst_net = seg_to_net[(idx[0], idx[1], entry[3])]
|
||||
else:
|
||||
assert dst_net == seg_to_net[(idx[0], idx[1], entry[3])]
|
||||
print(".%s %d %d %d %s" % (bits[0], idx[0], idx[1], dst_net, " ".join(bits[1:])))
|
||||
for entry in sorted(db_by_bits[bits]):
|
||||
pattern = ""
|
||||
for bit in bits[1:]:
|
||||
pattern += "1" if bit in entry[0] else "0"
|
||||
assert (idx[0], idx[1], entry[2]) in seg_to_net
|
||||
print("%s %d" % (pattern, seg_to_net[(idx[0], idx[1], entry[2])]))
|
||||
print()
|
||||
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import icebox
|
||||
import sys
|
||||
|
||||
print("Reading file '%s'.." % sys.argv[1])
|
||||
ic1 = icebox.iceconfig()
|
||||
ic1.read_file(sys.argv[1])
|
||||
|
||||
print("Reading file '%s'.." % sys.argv[2])
|
||||
ic2 = icebox.iceconfig()
|
||||
ic2.read_file(sys.argv[2])
|
||||
|
||||
def diff_tiles(stmt, tiles1, tiles2):
|
||||
for i in sorted(set(tiles1.keys() + tiles2.keys())):
|
||||
if not i in tiles1:
|
||||
print("+ %s %d %d" % (stmt, i[0], i[1]))
|
||||
for line in tiles2[i]:
|
||||
print("+ %s" % line)
|
||||
continue
|
||||
if not i in tiles2:
|
||||
print("- %s %d %d" % (stmt, i[0], i[1]))
|
||||
for line in tiles1[i]:
|
||||
print("- %s" % line)
|
||||
continue
|
||||
if tiles1[i] == tiles2[i]:
|
||||
continue
|
||||
print(" %s %d %d" % (stmt, i[0], i[1]))
|
||||
for c in range(len(tiles1[i])):
|
||||
if tiles1[i][c] == tiles2[i][c]:
|
||||
print(" %s" % tiles1[i][c])
|
||||
else:
|
||||
print("- %s" % tiles1[i][c])
|
||||
print("+ %s" % tiles2[i][c])
|
||||
|
||||
diff_tiles(".io_tile", ic1.io_tiles, ic2.io_tiles)
|
||||
diff_tiles(".logic_tile", ic1.logic_tiles, ic2.logic_tiles)
|
||||
diff_tiles(".ram_tile", ic1.ram_tiles, ic2.ram_tiles)
|
||||
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import icebox
|
||||
import getopt, sys, re
|
||||
|
||||
print_bits = False
|
||||
print_map = False
|
||||
single_tile = None
|
||||
|
||||
def usage():
|
||||
print("""
|
||||
Usage: icebox_explain [options] <bitmap.txt>
|
||||
|
||||
-b
|
||||
print config bit names for each config statement
|
||||
|
||||
-m
|
||||
print tile config bitmaps
|
||||
|
||||
-t '<x-coordinate> <y-coordinate>'
|
||||
print only the specified tile
|
||||
""")
|
||||
sys.exit(0)
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], "bmt:")
|
||||
except:
|
||||
usage()
|
||||
|
||||
for o, a in opts:
|
||||
if o == "-b":
|
||||
print_bits = True
|
||||
elif o == "-m":
|
||||
print_map = True
|
||||
elif o == "-t":
|
||||
single_tile = tuple([int(s) for s in a.split()])
|
||||
else:
|
||||
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] == "MEMB_Power_Up_Control":
|
||||
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", 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:
|
||||
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:
|
||||
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.ram_tiles:
|
||||
print_tile(".ram_tile %d %d" % idx, ic, idx[0], idx[1], ic.ram_tiles[idx], ic.tile_db(idx[0], idx[1]))
|
||||
print()
|
||||
|
||||
|
|
@ -0,0 +1,523 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
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('<a id="exph%d" href="#" onclick="document.getElementById(\'exph%d\').style.display=\'none\'; document.getElementById(\'exp%d\').style.display=\'block\'; return false">[+] Show %s</a><div id="exp%d" style="display:none">' % (expand_count[0], expand_count[0], expand_count[0], title, expand_count[0]))
|
||||
expand_count[0] += 1
|
||||
|
||||
def print_expand_end():
|
||||
print('</div>')
|
||||
|
||||
def print_expand_all():
|
||||
print('<a id="exph%d" href="#" onclick="for (i = 0; i < 100; i++) { document.getElementById(\'exph\'+i).style.display=\'none\'; document.getElementById(\'exp\'+i).style.display=\'block\'; }; return false">[+] Expand All</a><span id="exp%d" style="display:none"></span>' % (expand_count[0], expand_count[0]))
|
||||
expand_count[0] += 1
|
||||
|
||||
def print_index():
|
||||
print("<title>Project IceStorm – %s Overview</title>" % chipname)
|
||||
print("<h1>Project IceStorm – %s Overview</h1>" % chipname)
|
||||
|
||||
print("""<i><a href="http://www.clifford.at/icestorm/">Project IceStorm</a> 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.</i>""")
|
||||
|
||||
print("""<p>This documentation is auto-generated by <tt>icebox_html.py</tt> from IceBox.<br/>
|
||||
A machine-readable form of the database can be downloaded <a href="chipdb.txt">here</a>.</p>""")
|
||||
|
||||
print("""<p>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.</p>""")
|
||||
|
||||
print("""<p>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.</p>""")
|
||||
|
||||
print('<p><table border="1">')
|
||||
for y in range(ic.max_y, -1, -1):
|
||||
print("<tr>")
|
||||
for x in range(ic.max_x + 1):
|
||||
print('<td style="width:50px; height:50px;" align="center" valign="center"', end="")
|
||||
if ic.tile_pos(x, y) == None:
|
||||
print('> </td>')
|
||||
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"><small><a style="color:#000; text-decoration:none" href="tile_%d_%d.html"><b>%s<br/>(%d %d)</b></a></small></td>' % (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"><small>%s<br/>(%d %d)</small></td>' % (color, ic.tile_type(x, y), x, y))
|
||||
print("</tr>")
|
||||
print("</table></p>")
|
||||
|
||||
def print_tile(tx, ty):
|
||||
tile = ic.tile(tx, ty)
|
||||
tile_type = ic.tile_type(tx, ty)
|
||||
|
||||
print("<title>Project IceStorm – %s %s Tile (%d %d)</title>" % (chipname, tile_type, tx, ty))
|
||||
print("<h1>Project IceStorm – %s %s Tile (%d %d)</h1>" % (chipname, tile_type, tx, ty))
|
||||
|
||||
print("""<i><a href="http://www.clifford.at/icestorm/">Project IceStorm</a> 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.</i>""")
|
||||
|
||||
print("""<p>This page describes the %s Tile (%d %d), what nets and
|
||||
configuration bits it has and how it is connected to its neighbourhood.</p>""" % (tile_type, tx, ty))
|
||||
|
||||
visible_tiles = set()
|
||||
|
||||
print('<p><table border="1">')
|
||||
for y in range(ty+2, ty-3, -1):
|
||||
print("<tr>")
|
||||
for x in range(tx-2, tx+3):
|
||||
print('<td style="width:100px; height:70px;" align="center" valign="center"', end="")
|
||||
if ic.tile_pos(x, y) == None:
|
||||
print('> </td>')
|
||||
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"><a style="color:#000; text-decoration:none" href="tile_%d_%d.html"><b>%s Tile<br/>(%d %d)</b></a></td>' % (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<br/>(%d %d)</td>' % (color, ic.tile_type(x, y), x, y))
|
||||
visible_tiles.add((x, y))
|
||||
print("</tr>")
|
||||
print("</table></p>")
|
||||
|
||||
# print_expand_all()
|
||||
|
||||
print("<h2>Configuration Bitmap</h2>")
|
||||
|
||||
print("<p>A %s Tile has %d config bits in %d groups of %d bits each:<br/>" % (tile_type, len(tile)*len(tile[0]), len(tile), len(tile[0])))
|
||||
print(("<tt>%s</tt></p>" % (", ".join(['%sB%d[%d:0]' % (" " if i < 10 else "", i, len(tile[i])-1) for i in range(len(tile))]))).replace(" B8", "<br/> 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"] = '<a style="color:#666; text-decoration:none" href="#B.%d.%d">%s</a>' % (idx1, idx2, bitmap_cells[idx1][idx2]["label"])
|
||||
|
||||
print('<table style="font-size:small">')
|
||||
print("<tr><td></td>")
|
||||
for cell_nr in range(len(line)):
|
||||
print('<td align="center" width="15">%d</td>' % cell_nr)
|
||||
print("<td></td></tr>")
|
||||
for line_nr, line in enumerate(bitmap_cells):
|
||||
print("<tr>")
|
||||
print('<td>B%d</td>' % line_nr)
|
||||
for cell in line:
|
||||
print('<td align="center" bgcolor="%s" style="color:#666;">%s</td>' % (cell["bgcolor"], cell["label"]))
|
||||
print('<td>B%d</td>' % line_nr)
|
||||
print("</tr>")
|
||||
print("<tr><td></td>")
|
||||
for cell_nr in range(len(line)):
|
||||
print('<td align="center">%d</td>' % cell_nr)
|
||||
print("<td></td></tr>")
|
||||
print("</table>")
|
||||
|
||||
print("<h2>Nets and Connectivity</h2>")
|
||||
|
||||
print("""<p>This section lists all nets in the tile and how this
|
||||
nets are connected with nets from cells in its neighbourhood.</p>""")
|
||||
|
||||
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("<h3>List of nets in %s Tile (%d %d)</h3>" % (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('<h4>%s</h4>' % cat[1])
|
||||
print('<p><ul style="margin:0">')
|
||||
for this_name in sorted(nets_in_cats[cat]):
|
||||
indices = [i for i in this_tile_nets[this_name] if i >= 0]
|
||||
if -1 in this_tile_nets[this_name]:
|
||||
print("<li><tt>%s</tt></li>" % this_name)
|
||||
if len(indices) == 1:
|
||||
print("<li><tt>%s</tt></li>" % this_name.replace("*", "%d" % indices[0]))
|
||||
elif len(indices) > 0:
|
||||
print("<li><tt>%s</tt></li>" % this_name.replace("*", "{" + ",".join(["%d" % i for i in sorted(indices)]) + "}"))
|
||||
print("</ul></p>")
|
||||
|
||||
print("<h3>Nets and their permanent connections to nets in neighbour tiles</h3>")
|
||||
|
||||
# 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('<h4>%s</h4>' % cat[1])
|
||||
print('<p><div style="-webkit-column-count: 3; -moz-column-count: 3; column-count: 3;"><ul style="margin:0">')
|
||||
for this_name in sorted(groups_indexed):
|
||||
if net2cat(this_name) == cat:
|
||||
neighbour_segs = groups_indexed[this_name]
|
||||
print("<li><tt><b>%s</b></tt>" % this_name)
|
||||
if neighbour_segs:
|
||||
print("<ul>")
|
||||
for nidx in sorted(neighbour_segs):
|
||||
if nidx == (tx, ty):
|
||||
print("<li><tt><b>(%d %d)</b> %s</tt></li>" % (nidx[0], nidx[1], ", ".join(sorted(neighbour_segs[nidx]))))
|
||||
else:
|
||||
print("<li><tt>(%d %d) %s</tt></li>" % (nidx[0], nidx[1], ", ".join(sorted(neighbour_segs[nidx]))))
|
||||
print("</ul>")
|
||||
print("</li>")
|
||||
print("</ul></div></p>")
|
||||
|
||||
# print_expand_end()
|
||||
|
||||
print("<h2>Routing Configuration</h2>")
|
||||
|
||||
print("""<p>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.</p>""")
|
||||
|
||||
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('<h4>%s</h4>' % 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('<table style="font-size:x-small">')
|
||||
print("<tr><td></td>")
|
||||
for cell_nr in range(len(bitmap_cells[0])):
|
||||
print('<td align="center" width="15">%d</td>' % cell_nr)
|
||||
print("<td></td></tr>")
|
||||
for line_nr, line in enumerate(bitmap_cells):
|
||||
print("<tr>")
|
||||
print('<td>B%d</td>' % 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('<td align="center" bgcolor="%s" style="color:#666;">%s</td>' % (color, cell["label"]))
|
||||
print('<td>B%d</td>' % line_nr)
|
||||
print("</tr>")
|
||||
print("<tr><td></td>")
|
||||
for cell_nr in range(len(line)):
|
||||
print('<td align="center">%d</td>' % cell_nr)
|
||||
print("<td></td></tr>")
|
||||
print("</table>")
|
||||
|
||||
# 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])] = '<td align="center" bgcolor="#afa" style="color:#666;">B</td>'
|
||||
else:
|
||||
assert (entry[2], entry[3]) not in links
|
||||
links[(entry[2], entry[3])] = '<td align="center" bgcolor="#faa" style="color:#666;">R</td>'
|
||||
|
||||
print('<h5>Connectivity Matrix</h5>')
|
||||
print('<table style="font-size:x-small">')
|
||||
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('<tr><td></td><td colspan="%d" align="center">%s</td></tr>' % (len(dst_net_list), dst_net_prefix))
|
||||
print('<tr><td></td>')
|
||||
for dn in dst_net_list:
|
||||
print('<td>%s</td>' % dn)
|
||||
print("</tr>")
|
||||
for sn in sorted(src_nets, icebox.cmp_netnames):
|
||||
print("<tr>")
|
||||
print('<td>%s</td>' % sn)
|
||||
for dn in sorted(dst_nets, icebox.cmp_netnames):
|
||||
if (sn, dn) in links:
|
||||
print(links[(sn, dn)])
|
||||
else:
|
||||
print('<td align="center" bgcolor="#aaa" style="color:#666;"> </td>')
|
||||
print("</tr>")
|
||||
print("</table>")
|
||||
|
||||
print('<h5>Configuration Stamps</h5>')
|
||||
for cfggrp in sorted(grpgrp[cat]):
|
||||
grp = config_groups[cfggrp]
|
||||
bits = cfggrp.split(",")[1:]
|
||||
print('<p><table style="font-size:small" border><tr>')
|
||||
for bit in bits:
|
||||
print('<th style="width:5em"><a name="%s">%s</a></th>' % (re.sub(r"B(\d+)\[(\d+)\]", r"B.\1.\2", bit), bit))
|
||||
group_lines = list()
|
||||
is_buffer = True
|
||||
for entry in grp:
|
||||
line = '<tr>'
|
||||
for bit in bits:
|
||||
if bit in entry[0]:
|
||||
line += '<td align="center">1</td>'
|
||||
else:
|
||||
line += '<td align="center">0</td>'
|
||||
is_buffer = entry[1] == "buffer"
|
||||
line += '<td align="center">%s</td><td><tt>%s</tt></td><td><tt>%s</tt></td></tr>' % (entry[1], entry[2], entry[3])
|
||||
group_lines.append(line)
|
||||
if is_buffer:
|
||||
print('<th style="width:5em">Function</th><th style="width:15em">Source-Net</th><th style="width:15em">Destination-Net</th></tr>')
|
||||
else:
|
||||
print('<th style="width:5em">Function</th><th style="width:15em">Net</th><th style="width:15em">Net</th></tr>')
|
||||
for line in sorted(group_lines):
|
||||
print(line)
|
||||
print('</table></p>')
|
||||
|
||||
# print_expand_end()
|
||||
|
||||
print("<h2>Non-routing Configuration</h2>")
|
||||
|
||||
print("<p>This section lists the non-routing configuration bits in the tile.</p>")
|
||||
|
||||
print('<table style="font-size:x-small">')
|
||||
print("<tr><td></td>")
|
||||
for cell_nr in range(len(bitmap_cells[0])):
|
||||
print('<td align="center" width="15">%d</td>' % cell_nr)
|
||||
print("<td></td></tr>")
|
||||
for line_nr, line in enumerate(bitmap_cells):
|
||||
print("<tr>")
|
||||
print('<td>B%d</td>' % line_nr)
|
||||
for cell_nr, cell in enumerate(line):
|
||||
color = cell["bgcolor"]
|
||||
if "is_routing" in cell: color="#aaa"
|
||||
print('<td align="center" bgcolor="%s" style="color:#666;">%s</td>' % (color, cell["label"]))
|
||||
print('<td>B%d</td>' % line_nr)
|
||||
print("</tr>")
|
||||
print("<tr><td></td>")
|
||||
for cell_nr in range(len(line)):
|
||||
print('<td align="center">%d</td>' % cell_nr)
|
||||
print("<td></td></tr>")
|
||||
print("</table>")
|
||||
|
||||
print('<p><table style="font-size:small" border><tr><th>Function</th><th>Bits</th></tr>')
|
||||
for cfggrp in sorted(other_config_groups):
|
||||
bits = " ".join(['<a name="%s">%s</a>' % (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('<tr><td>%s</td><td>%s</td></tr>' % (cfggrp, bits))
|
||||
print('</table></p>')
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import icebox
|
||||
import getopt, sys, re
|
||||
|
||||
mode = None
|
||||
|
||||
def usage():
|
||||
print("Usage:")
|
||||
print(" icebox_maps -m bitmaps")
|
||||
print(" icebox_maps -m io_tile_nets_l")
|
||||
print(" icebox_maps -m io_tile_nets_r")
|
||||
print(" icebox_maps -m io_tile_nets_t")
|
||||
print(" icebox_maps -m io_tile_nets_b")
|
||||
print(" icebox_maps -m logic_tile_nets")
|
||||
print(" icebox_maps -m ram_tile_nets")
|
||||
sys.exit(0)
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], "m:")
|
||||
except:
|
||||
usage()
|
||||
|
||||
for o, a in opts:
|
||||
if o == "-m":
|
||||
mode = a.strip()
|
||||
else:
|
||||
usage()
|
||||
|
||||
def get_bit_group(x, y, db):
|
||||
bit = "B%d[%d]" % (y, x)
|
||||
nbit = "!B%d[%d]" % (y, x)
|
||||
funcs = set()
|
||||
for entry in db:
|
||||
if bit in entry[0] or nbit in entry[0]:
|
||||
if entry[1] in ("IOB_0", "IOB_1", "IoCtrl"):
|
||||
funcs.add("i")
|
||||
elif entry[1] == "routing":
|
||||
funcs.add("r")
|
||||
elif entry[1] == "buffer":
|
||||
funcs.add("b")
|
||||
elif re.match("LC_", entry[1]):
|
||||
funcs.add("l")
|
||||
elif entry[1] == "NegClk":
|
||||
funcs.add("N")
|
||||
elif entry[1] == "ColBufCtrl":
|
||||
funcs.add("o")
|
||||
elif entry[1] == "CarryInSet":
|
||||
funcs.add("C")
|
||||
elif entry[1] == "Cascade":
|
||||
funcs.add("a")
|
||||
else:
|
||||
funcs.add("?")
|
||||
if len(funcs) == 1:
|
||||
return funcs.pop()
|
||||
if len(funcs) > 1:
|
||||
return "X"
|
||||
return "-"
|
||||
|
||||
def print_tilemap(stmt, db, n):
|
||||
print()
|
||||
print(stmt)
|
||||
for y in range(16):
|
||||
for x in range(n):
|
||||
print(get_bit_group(x, y, db), end="")
|
||||
print()
|
||||
|
||||
def print_db_nets(stmt, db, pos):
|
||||
print()
|
||||
print(stmt, end="")
|
||||
netnames = set()
|
||||
for entry in db:
|
||||
if entry[1] in ("routing", "buffer"):
|
||||
if icebox.pos_has_net(pos[0], entry[2]): netnames.add(entry[2])
|
||||
if icebox.pos_has_net(pos[0], entry[3]): netnames.add(entry[3])
|
||||
last_prefix = ""
|
||||
for net in sorted(netnames, icebox.cmp_netnames):
|
||||
match = re.match(r"(.*?)(\d+)$", net)
|
||||
if match:
|
||||
if last_prefix == match.group(1):
|
||||
print(",%s" % match.group(2), end="")
|
||||
else:
|
||||
print()
|
||||
print(net, end="")
|
||||
last_prefix = match.group(1)
|
||||
else:
|
||||
print()
|
||||
print(net, end="")
|
||||
last_prefix = "*"
|
||||
print()
|
||||
|
||||
if mode == "bitmaps":
|
||||
print_tilemap(".io_tile_bitmap_l", icebox.iotile_l_db, 18)
|
||||
print_tilemap(".io_tile_bitmap_r", icebox.iotile_r_db, 18)
|
||||
print_tilemap(".io_tile_bitmap_t", icebox.iotile_t_db, 18)
|
||||
print_tilemap(".io_tile_bitmap_b", icebox.iotile_b_db, 18)
|
||||
print_tilemap(".logic_tile_bitmap", icebox.logictile_db, 54)
|
||||
print_tilemap(".ram_tile_bitmap", icebox.ramtile_db, 42)
|
||||
print()
|
||||
print(".bitmap_legend")
|
||||
print("- ... unknown bit")
|
||||
print("? ... unknown bit type")
|
||||
print("X ... database conflict")
|
||||
print("i ... IOB_0 IOB_1 IoCtrl")
|
||||
print("a ... Carry_In_Mux Cascade")
|
||||
print("r ... routing")
|
||||
print("b ... buffer")
|
||||
print("l ... logic bits")
|
||||
print("o ... ColBufCtrl")
|
||||
print("C ... CarryInSet")
|
||||
print("N ... NegClk")
|
||||
print()
|
||||
|
||||
elif mode == "io_tile_nets_l":
|
||||
print_db_nets(".io_tile_nets_l", icebox.iotile_l_db, "l")
|
||||
|
||||
elif mode == "io_tile_nets_r":
|
||||
print_db_nets(".io_tile_nets_r", icebox.iotile_r_db, "r")
|
||||
|
||||
elif mode == "io_tile_nets_t":
|
||||
print_db_nets(".io_tile_nets_t", icebox.iotile_t_db, "t")
|
||||
|
||||
elif mode == "io_tile_nets_b":
|
||||
print_db_nets(".io_tile_nets_b", icebox.iotile_b_db, "b")
|
||||
|
||||
elif mode == "logic_tile_nets":
|
||||
print_db_nets(".logic_tile_nets", icebox.logictile_db, "c")
|
||||
|
||||
elif mode == "ram_tile_nets":
|
||||
print_db_nets(".ram_tile_nets", icebox.ramtile_db, "c")
|
||||
|
||||
else:
|
||||
usage()
|
||||
|
||||
|
|
@ -0,0 +1,367 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import icebox
|
||||
import getopt, sys, re
|
||||
|
||||
strip_comments = False
|
||||
strip_interconn = False
|
||||
lookup_pins = False
|
||||
pcf_data = dict()
|
||||
portnames = set()
|
||||
unmatched_ports = set()
|
||||
auto_clk = False
|
||||
auto_en = False
|
||||
|
||||
def usage():
|
||||
print("""
|
||||
Usage: icebox_vlog [options] <bitmap.txt>
|
||||
|
||||
-s
|
||||
strip comments from output
|
||||
|
||||
-S
|
||||
strip comments about interconn wires from output
|
||||
|
||||
-a
|
||||
auto-detect global clock and enable signals
|
||||
(require ports "clk" and "en" in pcf file)
|
||||
|
||||
-l
|
||||
convert io tile port names to chip pin numbers
|
||||
|
||||
-p <pcf-file>
|
||||
use the set_io command from the specified pcf file
|
||||
|
||||
-P <pcf-file>
|
||||
like -p, enable some hacks for pcf files created
|
||||
by the iCEcube2 placer.
|
||||
""")
|
||||
sys.exit(0)
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], "sSlap:P:")
|
||||
except:
|
||||
usage()
|
||||
|
||||
for o, a in opts:
|
||||
if o == "-s":
|
||||
strip_comments = True
|
||||
elif o == "-S":
|
||||
strip_interconn = True
|
||||
elif o == "-l":
|
||||
lookup_pins = True
|
||||
elif o == "-a":
|
||||
auto_clk = True
|
||||
auto_en = True
|
||||
elif o in ("-p", "-P"):
|
||||
with open(a, "r") as f:
|
||||
for line in f:
|
||||
line = re.sub(r"#.*", "", line.strip()).split()
|
||||
if len(line) and line[0] == "set_io":
|
||||
p = line[1]
|
||||
if o == "-P":
|
||||
p = p.lower()
|
||||
p = p.replace("_ibuf", "")
|
||||
p = p.replace("_obuf", "")
|
||||
p = p.replace("_gb_io", "")
|
||||
portnames.add(p)
|
||||
if not re.match(r"[a-zA-Z_][a-zA-Z0-9_]*$", p):
|
||||
p = "\\%s " % p
|
||||
unmatched_ports.add(p)
|
||||
pinloc = tuple([int(s) for s in line[2:]])
|
||||
pcf_data[pinloc] = p
|
||||
else:
|
||||
usage()
|
||||
|
||||
if not strip_comments:
|
||||
print("// Reading file '%s'.." % args[0])
|
||||
ic = icebox.iceconfig()
|
||||
ic.read_file(args[0])
|
||||
print()
|
||||
|
||||
text_wires = list()
|
||||
text_ports = list()
|
||||
|
||||
luts_queue = set()
|
||||
text_func = list()
|
||||
|
||||
netidx = [0]
|
||||
nets = dict()
|
||||
seg2net = dict()
|
||||
|
||||
auto_clk_nets = set()
|
||||
auto_en_nets = set()
|
||||
|
||||
def is_interconn(netname):
|
||||
if netname.startswith("sp4_"): return True
|
||||
if netname.startswith("sp12_"): return True
|
||||
if netname.startswith("span4_"): return True
|
||||
if netname.startswith("span12_"): return True
|
||||
if netname.startswith("logic_op_"): return True
|
||||
if netname.startswith("neigh_op_"): return True
|
||||
if netname.startswith("local_"): return True
|
||||
return False
|
||||
|
||||
for segs in sorted(ic.group_segments()):
|
||||
while True:
|
||||
netidx[0] += 1
|
||||
n = "n%d" % netidx[0]
|
||||
if n not in portnames: break
|
||||
|
||||
net_segs = set()
|
||||
renamed_net_to_port = False
|
||||
|
||||
for s in segs:
|
||||
match = re.match("io_(\d+)/D_(IN|OUT)_(\d+)$", s[2])
|
||||
if match:
|
||||
if match.group(2) == "IN":
|
||||
p = "io_%d_%d_%s_din_%s" % (s[0], s[1], match.group(1), match.group(3))
|
||||
net_segs.add(p)
|
||||
else:
|
||||
p = "io_%d_%d_%s_dout_%s" % (s[0], s[1], match.group(1), match.group(3))
|
||||
net_segs.add(p)
|
||||
if lookup_pins or pcf_data:
|
||||
for entry in icebox.pinloc_db:
|
||||
if s[0] == entry[1] and s[1] == entry[2] and int(match.group(1)) == entry[3]:
|
||||
if (entry[0],) in pcf_data:
|
||||
p = pcf_data[(entry[0],)]
|
||||
unmatched_ports.discard(p)
|
||||
elif (entry[1], entry[2], entry[3]) in pcf_data:
|
||||
p = pcf_data[(entry[1], entry[2], entry[3])]
|
||||
unmatched_ports.discard(p)
|
||||
elif lookup_pins:
|
||||
p = "pin_%d" % entry[0]
|
||||
if p == "clk":
|
||||
auto_clk = False
|
||||
if p == "en":
|
||||
auto_en = False
|
||||
if not renamed_net_to_port:
|
||||
n = p
|
||||
if match.group(2) == "IN":
|
||||
text_ports.append("input %s" % p)
|
||||
else:
|
||||
text_ports.append("output %s" % p)
|
||||
text_wires.append("wire %s;" % n)
|
||||
renamed_net_to_port = True
|
||||
elif match.group(2) == "IN":
|
||||
text_ports.append("input %s" % p)
|
||||
text_wires.append("assign %s = %s;" % (n, p))
|
||||
else:
|
||||
text_ports.append("output %s" % p)
|
||||
text_wires.append("assign %s = %s;" % (p, n))
|
||||
|
||||
match = re.match("lutff_(\d+)/", s[2])
|
||||
if match:
|
||||
luts_queue.add((s[0], s[1], int(match.group(1))))
|
||||
|
||||
nets[n] = segs
|
||||
|
||||
for s in segs:
|
||||
seg2net[s] = n
|
||||
|
||||
if not renamed_net_to_port:
|
||||
text_wires.append("wire %s;" % n)
|
||||
|
||||
for s in segs:
|
||||
if not strip_interconn or not is_interconn(s[2]):
|
||||
if s[2].startswith("glb_netwk_"):
|
||||
net_segs.add((0, 0, s[2]))
|
||||
else:
|
||||
net_segs.add(s)
|
||||
|
||||
if not renamed_net_to_port:
|
||||
has_clk = False
|
||||
has_cen = False
|
||||
has_global = False
|
||||
has_driver = False
|
||||
for s in sorted(net_segs):
|
||||
if s[2].startswith("glb_netwk_"):
|
||||
has_global = True
|
||||
elif re.search(r"/out", s[2]):
|
||||
has_driver = True
|
||||
elif s[2] == "lutff_global/clk":
|
||||
has_clk = True
|
||||
elif s[2] == "lutff_global/cen":
|
||||
has_cen = True
|
||||
if has_global and not has_driver:
|
||||
if has_clk:
|
||||
auto_clk_nets.add(n)
|
||||
if has_cen and not has_clk:
|
||||
auto_en_nets.add(n)
|
||||
|
||||
if not strip_comments:
|
||||
for s in sorted(net_segs):
|
||||
text_wires.append("// %s" % (s,))
|
||||
text_wires.append("")
|
||||
|
||||
for p in unmatched_ports:
|
||||
text_ports.append("input %s" % p)
|
||||
|
||||
if auto_clk and auto_clk_nets and "clk" in unmatched_ports:
|
||||
assert len(auto_clk_nets) == 1
|
||||
if not strip_comments:
|
||||
text_wires.append("// automatically detected clock network")
|
||||
text_wires.append("assign %s = clk;" % auto_clk_nets.pop())
|
||||
if not strip_comments:
|
||||
text_wires.append("")
|
||||
unmatched_ports.remove("clk")
|
||||
|
||||
if auto_en and auto_en_nets and "en" in unmatched_ports:
|
||||
assert len(auto_en_nets) == 1
|
||||
if not strip_comments:
|
||||
text_wires.append("// automatically detected enable network")
|
||||
text_wires.append("assign %s = en;" % auto_en_nets.pop())
|
||||
if not strip_comments:
|
||||
text_wires.append("")
|
||||
unmatched_ports.remove("en")
|
||||
|
||||
def seg_to_net(seg, default=None):
|
||||
if seg not in seg2net:
|
||||
if default is not None:
|
||||
return default
|
||||
while True:
|
||||
netidx[0] += 1
|
||||
n = "n%d" % netidx[0]
|
||||
if n not in portnames: break
|
||||
nets[n] = set([seg])
|
||||
seg2net[seg] = n
|
||||
text_wires.append("wire %s;" % n)
|
||||
if not strip_comments:
|
||||
if not strip_interconn or not is_interconn(seg[2]):
|
||||
text_wires.append("// %s" % (seg,))
|
||||
text_wires.append("")
|
||||
return seg2net[seg]
|
||||
|
||||
wire_to_reg = set()
|
||||
lut_assigns = list()
|
||||
const_assigns = list()
|
||||
carry_assigns = list()
|
||||
always_stmts = list()
|
||||
max_net_len = 0
|
||||
|
||||
for lut in luts_queue:
|
||||
seq_bits = icebox.get_lutff_seq_bits(ic.logic_tiles[(lut[0], lut[1])], lut[2])
|
||||
if seq_bits[0] == "1":
|
||||
seg_to_net((lut[0], lut[1], "lutff_%d/cout" % lut[2]))
|
||||
|
||||
for lut in luts_queue:
|
||||
tile = ic.logic_tiles[(lut[0], lut[1])]
|
||||
lut_bits = icebox.get_lutff_lut_bits(tile, lut[2])
|
||||
seq_bits = icebox.get_lutff_seq_bits(tile, lut[2])
|
||||
net_in0 = seg_to_net((lut[0], lut[1], "lutff_%d/in_0" % lut[2]), "0")
|
||||
net_in1 = seg_to_net((lut[0], lut[1], "lutff_%d/in_1" % lut[2]), "0")
|
||||
net_in2 = seg_to_net((lut[0], lut[1], "lutff_%d/in_2" % lut[2]), "0")
|
||||
net_in3 = seg_to_net((lut[0], lut[1], "lutff_%d/in_3" % lut[2]), "0")
|
||||
net_out = seg_to_net((lut[0], lut[1], "lutff_%d/out" % lut[2]))
|
||||
if seq_bits[0] == "1":
|
||||
net_cout = seg_to_net((lut[0], lut[1], "lutff_%d/cout" % lut[2]))
|
||||
net_in1 = seg_to_net((lut[0], lut[1], "lutff_%d/in_1" % lut[2]), "0")
|
||||
net_in2 = seg_to_net((lut[0], lut[1], "lutff_%d/in_2" % lut[2]), "0")
|
||||
if lut[2] == 0:
|
||||
net_cin = seg_to_net((lut[0], lut[1], "carry_in_mux"))
|
||||
if icebox.get_carry_cascade_bit(tile) == "0":
|
||||
if not strip_comments:
|
||||
text_wires.append("// Carry-In for (%d %d)" % (lut[0], lut[1]))
|
||||
text_wires.append("assign %s = %s;" % (net_cin, icebox.get_carry_bit(tile)))
|
||||
if not strip_comments:
|
||||
text_wires.append("")
|
||||
else:
|
||||
net_cin = seg_to_net((lut[0], lut[1], "lutff_%d/cout" % (lut[2]-1)), "0")
|
||||
carry_assigns.append([net_cout, "/* CARRY %2d %2d %2d */ (%s & %s) | ((%s | %s) & %s)" %
|
||||
(lut[0], lut[1], lut[2], net_in1, net_in2, net_in1, net_in2, net_cin)])
|
||||
if seq_bits[1] == "1":
|
||||
while True:
|
||||
netidx[0] += 1
|
||||
n = "n%d" % netidx[0]
|
||||
if n not in portnames: break
|
||||
text_wires.append("wire %s;" % n)
|
||||
if not strip_comments:
|
||||
text_wires.append("// FF %s" % (lut,))
|
||||
text_wires.append("")
|
||||
net_cen = seg_to_net((lut[0], lut[1], "lutff_global/cen"), "1")
|
||||
net_clk = seg_to_net((lut[0], lut[1], "lutff_global/clk"), "0")
|
||||
net_sr = seg_to_net((lut[0], lut[1], "lutff_global/s_r"), "0")
|
||||
if seq_bits[3] == "0":
|
||||
always_stmts.append("/* FF %2d %2d %2d */ always @(%sedge %s) if (%s) %s <= %s ? %s : %s;" %
|
||||
(lut[0], lut[1], lut[2], "neg" if icebox.get_negclk_bit(tile) == "1" else "pos",
|
||||
net_clk, net_cen, net_out, net_sr, seq_bits[2], n))
|
||||
else:
|
||||
always_stmts.append("/* FF %2d %2d %2d */ always @(%sedge %s, posedge %s) if (%s) %s <= %s; else if (%s) %s <= %s;" %
|
||||
(lut[0], lut[1], lut[2], "neg" if icebox.get_negclk_bit(tile) == "1" else "pos",
|
||||
net_clk, net_sr, net_sr, net_out, seq_bits[2], net_cen, net_out, n))
|
||||
wire_to_reg.add(net_out)
|
||||
net_out = n
|
||||
if not "1" in lut_bits:
|
||||
const_assigns.append([net_out, "1'b0"])
|
||||
elif not "0" in lut_bits:
|
||||
const_assigns.append([net_out, "1'b1"])
|
||||
else:
|
||||
def make_lut_expr(bits, sigs):
|
||||
if not sigs:
|
||||
return "%s" % bits[0]
|
||||
l_expr = make_lut_expr(bits[0:len(bits)//2], sigs[1:])
|
||||
h_expr = make_lut_expr(bits[len(bits)//2:len(bits)], sigs[1:])
|
||||
if h_expr == l_expr: return h_expr
|
||||
if sigs[0] == "0": return l_expr
|
||||
if sigs[0] == "1": return h_expr
|
||||
if h_expr == "1" and l_expr == "0": return sigs[0]
|
||||
if h_expr == "0" and l_expr == "1": return "!" + sigs[0]
|
||||
return "%s ? %s : %s" % (sigs[0], h_expr, l_expr)
|
||||
lut_expr = make_lut_expr(lut_bits, [net_in3, net_in2, net_in1, net_in0])
|
||||
lut_assigns.append([net_out, "/* LUT %2d %2d %2d */ %s" % (lut[0], lut[1], lut[2], lut_expr)])
|
||||
max_net_len = max(max_net_len, len(net_out))
|
||||
|
||||
for a in const_assigns + lut_assigns + carry_assigns:
|
||||
text_func.append("assign %-*s = %s;" % (max_net_len, a[0], a[1]))
|
||||
|
||||
print("module chip (%s);\n" % ", ".join(text_ports))
|
||||
|
||||
new_text_wires = list()
|
||||
for line in text_wires:
|
||||
match = re.match(r"wire ([^ ;]+)(.*)", line)
|
||||
if match and match.group(1) in wire_to_reg:
|
||||
line = "reg " + match.group(1) + match.group(2)
|
||||
if strip_comments:
|
||||
if new_text_wires and new_text_wires[-1].split()[0] == line.split()[0] and new_text_wires[-1][-1] == ";":
|
||||
new_text_wires[-1] = new_text_wires[-1][0:-1] + "," + line[len(line.split()[0]):]
|
||||
else:
|
||||
new_text_wires.append(line)
|
||||
else:
|
||||
print(line)
|
||||
for line in new_text_wires:
|
||||
print(line)
|
||||
if strip_comments:
|
||||
print()
|
||||
|
||||
for line in text_func:
|
||||
print(line)
|
||||
for line in always_stmts:
|
||||
print(line)
|
||||
print()
|
||||
|
||||
for p in unmatched_ports:
|
||||
print("// Warning: unmatched port '%s'" %p)
|
||||
if unmatched_ports:
|
||||
print()
|
||||
|
||||
print("endmodule")
|
||||
print()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
CC = clang
|
||||
CXX = clang
|
||||
LDFLAGS = -lm -lstdc++
|
||||
CFLAGS = -MD -Os -Wall -std=c99
|
||||
CXXFLAGS = -MD -Os -Wall -std=c99
|
||||
|
||||
all: iceunpack
|
||||
|
||||
iceunpack: iceunpack.o
|
||||
|
||||
install: all
|
||||
cp iceunpack /usr/local/bin/iceunpack
|
||||
|
||||
uninstall:
|
||||
rm -f /usr/local/bin/iceunpack
|
||||
|
||||
clean:
|
||||
rm -f iceunpack
|
||||
rm -f *.o *.d
|
||||
|
||||
-include *.d
|
||||
|
||||
.PHONY: install uninstall clean
|
||||
|
||||
|
|
@ -0,0 +1,368 @@
|
|||
// Written by Mathias Lasser
|
||||
// License terms are unclear at the moment
|
||||
|
||||
#include<stdio.h>
|
||||
#include<stdbool.h>
|
||||
#include<stdlib.h>
|
||||
#include<stdint.h>
|
||||
#include<string.h>
|
||||
|
||||
int enable_debug=0;
|
||||
#define debugf(...) do{if(enable_debug)fprintf(stderr,__VA_ARGS__);}while(0)
|
||||
|
||||
#pragma pack(2)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t bfType;
|
||||
uint32_t bfSize;
|
||||
uint16_t bfReserved1;
|
||||
uint16_t bfReserved2;
|
||||
uint32_t bfOffBits;
|
||||
}BITMAPFILEHEADER;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t biSize;
|
||||
uint32_t biWidth;
|
||||
uint32_t biHeight;
|
||||
uint16_t biPlanes;
|
||||
uint16_t biBitCount;
|
||||
uint32_t biCompression;
|
||||
uint32_t biSizeImage;
|
||||
uint32_t biXPelsPerMeter;
|
||||
uint32_t biYPelsPerMeter;
|
||||
uint32_t biClrUsed;
|
||||
uint32_t biClrImportant;
|
||||
}BITMAPINFOHEADER;
|
||||
|
||||
typedef struct{
|
||||
uint16_t boot_mode;
|
||||
uint16_t crc;
|
||||
uint8_t freq;
|
||||
uint8_t bank;
|
||||
uint32_t write_pointer;
|
||||
|
||||
uint32_t CRAM_rowsize;
|
||||
uint32_t CRAM_colsize;
|
||||
uint8_t* CRAM[4];
|
||||
uint32_t BRAM_rowsize;
|
||||
uint32_t BRAM_colsize;
|
||||
uint8_t* BRAM[4];
|
||||
}FPGA_t;
|
||||
|
||||
typedef struct{
|
||||
uint32_t len;
|
||||
uint32_t pointer;
|
||||
uint16_t crc;
|
||||
uint8_t payload[0];
|
||||
}bitstream_t;
|
||||
|
||||
typedef union{
|
||||
struct{
|
||||
uint8_t lo:4;
|
||||
uint8_t hi:4;
|
||||
};
|
||||
uint8_t full;
|
||||
}nibble_t;
|
||||
|
||||
const char* freq_settings[]={"low","medium","high"};
|
||||
const char* boot_settings[]={"Disable","Enable"};
|
||||
|
||||
uint16_t crc16(uint32_t crc,uint8_t in){
|
||||
for(int i=7;i>=0;i--){
|
||||
crc<<=1;
|
||||
if((crc^(in<<(16-i)))&0x10000)
|
||||
crc^=0x1021;
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
uint32_t get_byte(bitstream_t* bitstream){
|
||||
if(bitstream->pointer>=bitstream->len)return 0xFFFFFF;
|
||||
uint8_t data=bitstream->payload[bitstream->pointer++];
|
||||
bitstream->crc=crc16(bitstream->crc,data);
|
||||
return data;
|
||||
}
|
||||
|
||||
uint32_t get_payload(bitstream_t* bitstream,int len){
|
||||
uint32_t ret=get_byte(bitstream);
|
||||
for(int i=1;i<len&&ret!=0xFFFFFFFF;i++){
|
||||
ret<<=8;
|
||||
ret|=get_byte(bitstream);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void FPGA_write(FPGA_t* FPGA,bitstream_t* bitstream){
|
||||
int n=FPGA->CRAM_colsize*FPGA->CRAM_rowsize/8;
|
||||
uint8_t* temp=(uint8_t*)malloc(n);
|
||||
for(int i=0;i<n;i++)
|
||||
temp[i]=get_byte(bitstream);
|
||||
FPGA->CRAM[FPGA->bank]=temp;
|
||||
}
|
||||
|
||||
void FPGA_EBR_write(FPGA_t* FPGA,bitstream_t* bitstream){
|
||||
int n=FPGA->BRAM_colsize*FPGA->BRAM_rowsize/8;
|
||||
uint8_t* temp=(uint8_t*)malloc(FPGA->write_pointer+n);
|
||||
if(FPGA->write_pointer!=0){
|
||||
uint8_t* old_data=FPGA->BRAM[FPGA->bank];
|
||||
memcpy(temp,old_data,FPGA->write_pointer);
|
||||
free(old_data);
|
||||
}
|
||||
for(int i=0;i<n;i++)temp[FPGA->write_pointer++]=get_byte(bitstream);
|
||||
FPGA->BRAM[FPGA->bank]=temp;
|
||||
}
|
||||
|
||||
int parse(bitstream_t* bitstream, FPGA_t* FPGA) {
|
||||
uint32_t preamble=0;
|
||||
while(1){
|
||||
preamble<<=8;
|
||||
preamble|=get_byte(bitstream);
|
||||
if(preamble==0x7EAA997E){
|
||||
debugf("Got preamble\n");
|
||||
break;
|
||||
}
|
||||
if(preamble==0xFFFFFFFF){
|
||||
fprintf(stderr,"Error: could not find preamble...\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
nibble_t command;
|
||||
uint32_t payload;
|
||||
uint16_t crc;
|
||||
while(1){
|
||||
crc=bitstream->crc;
|
||||
command.full=get_byte(bitstream);
|
||||
if(command.full==0xFF){
|
||||
payload=get_byte(bitstream);
|
||||
if(payload!=0x00)goto err;
|
||||
char*comment=(char*)&bitstream->payload[bitstream->pointer];
|
||||
debugf("Got comment section start\n");
|
||||
while(1){
|
||||
payload<<=8;
|
||||
payload|=get_byte(bitstream);
|
||||
if((payload&0xFFFF)==0x00FF)break;
|
||||
if(payload==0xFFFFFFFF){
|
||||
fprintf(stderr,"Error: could not find comment section end\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
debugf("\n%s\n\n",comment);
|
||||
debugf("Got comment section end\n");
|
||||
continue;
|
||||
}
|
||||
payload=get_payload(bitstream,command.lo);
|
||||
switch(command.hi){
|
||||
case 0x0:
|
||||
if(command.lo!=0x01)goto err;
|
||||
switch(payload){
|
||||
case 0x01:
|
||||
debugf("Write to CRAM!!!\n");
|
||||
FPGA_write(FPGA,bitstream);
|
||||
get_payload(bitstream,2);
|
||||
break;
|
||||
case 0x03:
|
||||
debugf("Write to BRAM!!!\n");
|
||||
FPGA_EBR_write(FPGA,bitstream);
|
||||
get_payload(bitstream,2);
|
||||
break;
|
||||
case 0x05:
|
||||
debugf("Resetting CRC\n");
|
||||
bitstream->crc=0;
|
||||
break;
|
||||
case 0x06:
|
||||
debugf("Wake up\n");
|
||||
return 0;
|
||||
default:
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
case 0x1:
|
||||
if(command.lo!=0x01)goto err;
|
||||
if(payload>3){
|
||||
fprintf(stderr,"Error: bank %u does not exist...\n",payload);
|
||||
}
|
||||
debugf("Set bank to %u\n",payload);
|
||||
FPGA->bank=payload;
|
||||
break;
|
||||
case 0x2:
|
||||
if(command.lo!=0x02)goto err;
|
||||
debugf("CRC check: %04X %04X\n",payload,crc);
|
||||
break;
|
||||
case 0x5:
|
||||
if(command.lo!=0x01)goto err;
|
||||
if(payload>2){
|
||||
fprintf(stderr,"Error: unknown frequency setting...\n");
|
||||
return -1;
|
||||
}
|
||||
debugf("Boot frequency set to %s\n",freq_settings[payload]);
|
||||
FPGA->freq=payload;
|
||||
break;
|
||||
case 0x6:
|
||||
if(command.lo!=0x02)goto err;
|
||||
payload++;
|
||||
debugf("Row size: %i\n",payload);
|
||||
if(FPGA->CRAM_rowsize)FPGA->BRAM_rowsize=payload;
|
||||
else FPGA->CRAM_rowsize=payload;
|
||||
break;
|
||||
case 0x7:
|
||||
if(command.lo!=0x02)goto err;
|
||||
debugf("Column size: %i\n",payload);
|
||||
if(FPGA->CRAM_colsize)FPGA->BRAM_colsize=payload;
|
||||
else FPGA->CRAM_colsize=payload;
|
||||
break;
|
||||
case 0x8:
|
||||
if(command.lo!=0x02)goto err;
|
||||
if(payload==0x0000){
|
||||
debugf("Reset write pointer\n");
|
||||
FPGA->write_pointer=0;
|
||||
}
|
||||
else if(payload==0x0080){
|
||||
debugf("Don't reset write pointer\n");
|
||||
}
|
||||
else goto err;
|
||||
break;
|
||||
case 0x9:
|
||||
if(command.lo!=0x02)goto err;
|
||||
if(payload&0xFFDF){
|
||||
fprintf(stderr,"Error: Unknown warmboot setting... %04X\n",payload);
|
||||
return -1;
|
||||
}
|
||||
debugf("%s warmboot\n",boot_settings[payload?1:0]);
|
||||
FPGA->boot_mode=payload;
|
||||
break;
|
||||
default:
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
err:
|
||||
fprintf(stderr,"Error: unkown command... %08X\n",bitstream->pointer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t get_CRAM_bit_from_sector(FPGA_t* FPGA,int bank,int x,int y){
|
||||
if(x<0||x>=FPGA->CRAM_rowsize)return 0xFF;
|
||||
if(y<0||y>=FPGA->CRAM_colsize)return 0xFF;
|
||||
if(bank<0||bank>=4)return 0xFF;
|
||||
|
||||
|
||||
int bit=y*FPGA->CRAM_rowsize+x;
|
||||
int pointer=bit>>3;
|
||||
int shifts=7-(bit&7);
|
||||
return (FPGA->CRAM[bank][pointer]>>shifts)&1;
|
||||
}
|
||||
|
||||
int tiles[2][20]={
|
||||
{18,54,54,42,54,54,54},
|
||||
{18,2,54,54,54,54,54,54,54,42,54,54,54,54,54,54,54,54}
|
||||
};
|
||||
|
||||
int permx[2][18]={
|
||||
{23,25,26,27,16,17,18,19,20,14,32,33,34,35,36,37,4,5},
|
||||
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17}};
|
||||
int permy[4][16]={
|
||||
{0,1,3,2,4,5,7,6,8,9,11,10,12,13,15,14},
|
||||
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15},
|
||||
};
|
||||
|
||||
int tile_row_size[2]={7,17};
|
||||
int tile_col_size[2]={9,17};
|
||||
|
||||
void print_tile(FPGA_t* FPGA,int x,int y){
|
||||
int type=FPGA->CRAM_rowsize==872;
|
||||
int dirx=0;
|
||||
int diry=0;
|
||||
int tx=x;
|
||||
int ty=y;
|
||||
|
||||
int corner_flags=0;
|
||||
if(x==0)corner_flags|=1;
|
||||
if(y==0)corner_flags|=2;
|
||||
if(x==tile_row_size[type]*2-1)corner_flags|=4;
|
||||
if(y==tile_col_size[type]*2-1)corner_flags|=8;
|
||||
if(corner_flags&(corner_flags-1))
|
||||
return;
|
||||
|
||||
if(x>=tile_row_size[type]){
|
||||
dirx=1;
|
||||
tx=tile_row_size[type]*2-1-x;
|
||||
}
|
||||
if(y>=tile_col_size[type]){
|
||||
diry=1;
|
||||
ty=tile_col_size[type]*2-1-y;
|
||||
}
|
||||
int sector=(diry|dirx<<1);
|
||||
int offx=0;for(int i=0;i<tx;i++)offx+=tiles[type][i];
|
||||
if(corner_flags){
|
||||
printf(".io_tile %i %i\n",x,y);
|
||||
for(int cy=0;cy<16;cy++){
|
||||
for(int cx=0;cx<18;cx++){
|
||||
int val;
|
||||
if(corner_flags&5){
|
||||
if(diry){
|
||||
val=get_CRAM_bit_from_sector(FPGA,sector,offx+tiles[type][tx]-1-permx[1][cx],ty*16+15-permy[1][cy]);
|
||||
}else{
|
||||
val=get_CRAM_bit_from_sector(FPGA,sector,offx+tiles[type][tx]-1-permx[1][cx],ty*16+permy[1][cy]);
|
||||
}
|
||||
}else{
|
||||
if(dirx){
|
||||
val=get_CRAM_bit_from_sector(FPGA,sector,offx+tiles[type][tx]-1-permx[0][cx],ty*16+15-permy[0][cy]);
|
||||
}else{
|
||||
val=get_CRAM_bit_from_sector(FPGA,sector,offx+permx[0][cx],ty*16+15-permy[0][cy]);
|
||||
}
|
||||
}
|
||||
printf("%i",val);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(tiles[type][tx]==20)printf(".io_tile %i %i\n",x,y);
|
||||
if(tiles[type][tx]==42)printf(".ram_tile %i %i\n",x,y);
|
||||
if(tiles[type][tx]==54)printf(".logic_tile %i %i\n",x,y);
|
||||
for(int cy=0;cy<16;cy++){
|
||||
for(int cx=0;cx<tiles[type][tx];cx++){
|
||||
printf("%i",get_CRAM_bit_from_sector(FPGA,sector,(dirx?(offx+tiles[type][tx]-1-cx):(offx+cx)),(diry?(ty*16+(15-cy)):(ty*16+cy))));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc,char**argv) {
|
||||
if(argc>=2&&!strcmp(argv[1], "-v")) {
|
||||
enable_debug=1;
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
if(argc!=2) {
|
||||
fprintf(stderr,"iceunpack [-v] input\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
FILE*r_file=fopen(argv[1],"rb");
|
||||
if(r_file==NULL) {
|
||||
fprintf(stderr,"could not open %s\n",argv[1]);
|
||||
return 1;
|
||||
}
|
||||
fseek(r_file,0,SEEK_END);
|
||||
size_t r_size=ftell(r_file);
|
||||
fseek(r_file,0,SEEK_SET);
|
||||
|
||||
bitstream_t* bitstream=(bitstream_t*)malloc(sizeof(bitstream_t)+r_size);
|
||||
bitstream->len=r_size;
|
||||
bitstream->pointer=0;
|
||||
fread(bitstream->payload,1,r_size,r_file);
|
||||
fclose(r_file);
|
||||
|
||||
FPGA_t FPGA;
|
||||
memset(&FPGA,0,sizeof(FPGA));
|
||||
|
||||
parse(bitstream,&FPGA);
|
||||
free(bitstream);
|
||||
|
||||
printf(".device 1k\n");
|
||||
for(int y=0;y<18;y++)for(int x=0;x<14;x++)print_tile(&FPGA,x,y);
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue