summaryrefslogtreecommitdiff
path: root/icebox/icebox.py
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2015-07-18 13:05:02 +0200
committerClifford Wolf <clifford@clifford.at>2015-07-18 13:05:02 +0200
commitdfeb92a46b2228b4f3886a9c06502ccd0dde5562 (patch)
tree20cebe482ae2954f4597489658b27828f5316921 /icebox/icebox.py
Import of icestorm-snapshot-150322.zip
Diffstat (limited to 'icebox/icebox.py')
-rw-r--r--icebox/icebox.py824
1 files changed, 824 insertions, 0 deletions
diff --git a/icebox/icebox.py b/icebox/icebox.py
new file mode 100644
index 0000000..f3dc113
--- /dev/null
+++ b/icebox/icebox.py
@@ -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()
+