Import of icestorm-snapshot-150413.zip

This commit is contained in:
Clifford Wolf 2015-07-18 13:06:48 +02:00
parent 0347c37d56
commit c41701ca3a
9 changed files with 3106 additions and 203 deletions

View File

@ -30,19 +30,23 @@ class iceconfig:
self.device = ""
self.logic_tiles = dict()
self.io_tiles = dict()
self.ram_tiles = dict()
self.ram_init = dict()
self.ramb_tiles = dict()
self.ramt_tiles = dict()
self.extra_bits = set()
def setup_empty_1k(self):
self.clear()
self.device = "1k"
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)]
if y % 2 == 1:
self.ramb_tiles[(x, y)] = ["0" * 42 for i in range(16)]
else:
self.ramt_tiles[(x, y)] = ["0" * 42 for i in range(16)]
else:
self.logic_tiles[(x, y)] = ["0" * 54 for i in range(16)]
@ -63,15 +67,36 @@ class iceconfig:
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)]
if (x, y) in self.ramb_tiles: return self.ramb_tiles[(x, y)]
if (x, y) in self.ramt_tiles: return self.ramt_tiles[(x, y)]
return None
def pinloc_db(self):
assert self.device == "1k"
return pinloc_db
def gbufin_db(self):
return gbufin_db[self.device]
def icegate_db(self):
return icegate_db[self.device]
def padin_pio_db(self):
return padin_pio_db[self.device]
def extra_bits_db(self):
return extra_bits_db[self.device]
def ieren_db(self):
return ieren_db[self.device]
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.ramb_tiles: return rambtile_db
if (x, y) in self.ramt_tiles: return ramttile_db
if (x, y) in self.logic_tiles: return logictile_db
assert False
@ -80,7 +105,8 @@ class iceconfig:
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.ramb_tiles: return "RAMB"
if (x, y) in self.ramt_tiles: return "RAMT"
if (x, y) in self.logic_tiles: return "LOGIC"
assert False
@ -96,7 +122,6 @@ class iceconfig:
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_"):
@ -161,7 +186,12 @@ class iceconfig:
if npos is not None and pos is not None:
if npos == "x":
return (nx, ny, "lutff_%d/out" % func)
if (nx, ny) in self.logic_tiles:
return (nx, ny, "lutff_%d/out" % func)
if (nx, ny) in self.ramb_tiles:
return (nx, ny, "ram/RDATA_%d" % func)
if (nx, ny) in self.ramt_tiles:
return (nx, ny, "ram/RDATA_%d" % (8+func))
elif pos == "x" and npos in ("l", "r", "t", "b"):
if func in (0, 4): return (nx, ny, "io_0/D_IN_0")
@ -194,6 +224,10 @@ class iceconfig:
if match:
funcnets |= self.follow_funcnet(x, y, int(match.group(1)))
match = re.match(r"ram/RDATA_(\d+)", netname)
if match:
funcnets |= self.follow_funcnet(x, y, int(match.group(1)) % 8)
return funcnets
def follow_net(self, netspec):
@ -273,12 +307,22 @@ class iceconfig:
neighbours.add((s[0], s[1], s[2]))
return neighbours
def group_segments(self, all_from_tiles=set()):
def group_segments(self, all_from_tiles=set(), extra_connections=list(), extra_segments=list()):
seed_segments = set()
seen_segments = set()
connected_segments = dict()
grouped_segments = set()
for seg in extra_segments:
seed_segments.add(seg)
for conn in extra_connections:
s1, s2 = conn
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():
tc = tileconfig(tile)
pintypes = [ list("000000"), list("000000") ]
@ -314,8 +358,44 @@ class iceconfig:
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)
for idx, tile in self.ramb_tiles.items():
add_seed_segments(idx, tile, rambtile_db)
for idx, tile in self.ramt_tiles.items():
add_seed_segments(idx, tile, ramttile_db)
for padin, pio in enumerate(self.padin_pio_db()):
s1 = (pio[0], pio[1], "wire_gbuf/padin_%d" % pio[2])
s2 = (pio[0], pio[1], "glb_netwk_%d" % padin)
if s1 in seed_segments or (pio[0], pio[1]) in all_from_tiles:
connected_segments.setdefault(s1, set()).add(s2)
connected_segments.setdefault(s2, set()).add(s1)
seed_segments.add(s1)
seed_segments.add(s2)
for entry in self.icegate_db():
if entry[0] == 0 or entry[0] == self.max_x:
iocells = [(entry[0], i) for i in range(1, self.max_y)]
if entry[1] == 0 or entry[1] == self.max_y:
iocells = [(i, entry[1]) for i in range(1, self.max_x)]
for cell in iocells:
s1 = (entry[0], entry[1], "wire_gbuf/in")
s2 = (cell[0], cell[1], "io_global/latch")
if s1 in seed_segments or s2 in seed_segments or \
(entry[0], entry[1]) in all_from_tiles or (cell[0], cell[1]) in all_from_tiles:
connected_segments.setdefault(s1, set()).add(s2)
connected_segments.setdefault(s2, set()).add(s1)
seed_segments.add(s1)
seed_segments.add(s2)
for entry in self.gbufin_db():
s1 = (entry[0], entry[1], "wire_gbuf/in")
s2 = (entry[0], entry[1], "glb_netwk_%d" % entry[2])
if s1 in seed_segments or (pio[0], pio[1]) in all_from_tiles:
connected_segments.setdefault(s1, set()).add(s2)
connected_segments.setdefault(s2, set()).add(s1)
seed_segments.add(s1)
seed_segments.add(s2)
while seed_segments:
queue = set()
@ -373,7 +453,7 @@ class iceconfig:
expected_data_lines -= 1
continue
assert expected_data_lines <= 0
if line[0] in (".io_tile", ".logic_tile", ".ram_tile"):
if line[0] in (".io_tile", ".logic_tile", ".ramb_tile", ".ramt_tile"):
current_data = list()
expected_data_lines = 16
self.max_x = max(self.max_x, int(line[1]))
@ -384,8 +464,11 @@ class iceconfig:
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
if line[0] == ".ramb_tile":
self.ramb_tiles[(int(line[1]), int(line[2]))] = current_data
continue
if line[0] == ".ramt_tile":
self.ramt_tiles[(int(line[1]), int(line[2]))] = current_data
continue
if line[0] == ".extra_bit":
self.extra_bits.add((int(line[1]), int(line[2]), int(line[3])))
@ -394,7 +477,7 @@ class iceconfig:
assert line[1] in ["1k"]
self.device = line[1]
continue
if line[0] == ".comment":
if line[0] in [".comment", ".sym"]:
expected_data_lines = -1
continue
print("%sWarning: ignoring line %d: %s" % (logprefix, linenum, linetext.strip()))
@ -532,7 +615,7 @@ def sp12v_normalize(netname, edge=""):
return netname
def netname_normalize(netname, edge=""):
def netname_normalize(netname, edge="", ramb=False, ramt=False):
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)
@ -542,6 +625,12 @@ def netname_normalize(netname, edge=""):
netname = netname.replace("lc_", "lutff_")
netname = netname.replace("wire_logic_cluster/", "")
netname = netname.replace("wire_io_cluster/", "")
netname = netname.replace("wire_bram/", "")
if (ramb or ramt) and netname.startswith("input"):
match = re.match(r"input(\d)_(\d)", netname)
idx1, idx2 = (int(match.group(1)), int(match.group(2)))
if ramb: netname="ram/WADDR_%d" % (idx1*4 + idx2)
if ramt: netname="ram/RADDR_%d" % (idx1*4 + idx2)
match = re.match(r"(...)_op_(.*)", netname)
if match:
netname = "neigh_op_%s_%s" % (match.group(1), match.group(2))
@ -739,8 +828,7 @@ def cmp_netnames(a, b):
def run_checks_neigh():
print("Running consistency checks on neighbour finder..")
ic = iceconfig()
ic.max_x = 6
ic.max_y = 6
ic.setup_empty_1k()
all_segments = set()
@ -758,6 +846,10 @@ def run_checks_neigh():
continue
if x in (0, ic.max_x) or y in (0, ic.max_y):
add_segments((x, y), ic.tile_db(x, y))
elif (x, y) in ic.ramb_tiles:
add_segments((x, y), ic.tile_db(x, y))
elif (x, y) in ic.ramt_tiles:
add_segments((x, y), ic.tile_db(x, y))
else:
add_segments((x, y), logictile_db)
all_segments.add((x, y, "lutff_7/cout"))
@ -789,13 +881,144 @@ def parse_db(text):
extra_bits_db = {
"1k": {
(0, 331, 142): ("routing", "padin_1", "glb_netwk_1")
(0, 330, 142): ("padin_glb_netwk", "0"),
(0, 331, 142): ("padin_glb_netwk", "1"),
(1, 330, 143): ("padin_glb_netwk", "2"),
(1, 331, 143): ("padin_glb_netwk", "3"),
(1, 330, 142): ("padin_glb_netwk", "4"),
(1, 331, 142): ("padin_glb_netwk", "5"),
(0, 330, 143): ("padin_glb_netwk", "6"),
(0, 331, 143): ("padin_glb_netwk", "7"),
}
}
gbufin_db = {
"1k": [
(13, 8, 7),
( 0, 8, 6),
( 7, 17, 1),
( 7, 0, 0),
( 0, 9, 3),
(13, 9, 2),
( 6, 0, 5),
( 6, 17, 4),
]
}
icegate_db = {
"1k": [
( 0, 7),
(13, 10),
( 5, 0),
( 8, 17)
]
}
padin_pio_db = {
"1k": [
(13, 8, 1), # glb_netwk_0
( 0, 8, 1), # glb_netwk_1
( 7, 17, 0), # glb_netwk_2
( 7, 0, 0), # glb_netwk_3
( 0, 9, 0), # glb_netwk_4
(13, 9, 0), # glb_netwk_5
( 6, 0, 1), # glb_netwk_6
( 6, 17, 1), # glb_netwk_7
]
}
ieren_db = {
"1k": [
# IO-block (X, Y, Z) <-> IeRen-block (X, Y, Z)
( 0, 14, 1, 0, 14, 0),
( 0, 14, 0, 0, 14, 1),
( 0, 13, 1, 0, 13, 0),
( 0, 13, 0, 0, 13, 1),
( 0, 12, 1, 0, 12, 0),
( 0, 12, 0, 0, 12, 1),
( 0, 11, 1, 0, 11, 0),
( 0, 11, 0, 0, 11, 1),
( 0, 10, 1, 0, 10, 0),
( 0, 10, 0, 0, 10, 1),
( 0, 9, 1, 0, 9, 0),
( 0, 8, 0, 0, 8, 1),
( 0, 6, 1, 0, 6, 0),
( 0, 6, 0, 0, 6, 1),
( 0, 5, 1, 0, 5, 0),
( 0, 5, 0, 0, 5, 1),
( 0, 4, 1, 0, 4, 0),
( 0, 4, 0, 0, 4, 1),
( 0, 3, 1, 0, 3, 0),
( 0, 3, 0, 0, 3, 1),
( 0, 2, 1, 0, 2, 0),
( 0, 2, 0, 0, 2, 1),
( 1, 0, 0, 1, 0, 0),
( 1, 0, 1, 1, 0, 1),
( 2, 0, 1, 2, 0, 1),
( 3, 0, 0, 3, 0, 0),
( 3, 0, 1, 3, 0, 1),
( 4, 0, 0, 4, 0, 0),
( 4, 0, 1, 4, 0, 1),
( 5, 0, 0, 5, 0, 0),
( 5, 0, 1, 5, 0, 1),
( 6, 0, 0, 7, 0, 0),
( 7, 0, 1, 7, 0, 1),
( 8, 0, 0, 8, 0, 0),
( 8, 0, 1, 8, 0, 1),
( 9, 0, 0, 9, 0, 0),
( 9, 0, 1, 9, 0, 1),
(10, 0, 0, 10, 0, 0),
(10, 0, 1, 10, 0, 1),
(13, 1, 0, 13, 1, 0),
(13, 1, 1, 13, 1, 1),
(13, 2, 0, 13, 2, 0),
(13, 2, 1, 13, 2, 1),
(13, 3, 1, 13, 3, 1),
(13, 4, 0, 13, 4, 0),
(13, 4, 1, 13, 4, 1),
(13, 6, 0, 13, 6, 0),
(13, 6, 1, 13, 6, 1),
(13, 7, 0, 13, 7, 0),
(13, 7, 1, 13, 7, 1),
(13, 8, 0, 13, 8, 0),
(13, 9, 1, 13, 9, 1),
(13, 11, 0, 13, 10, 0),
(13, 11, 1, 13, 10, 1),
(13, 12, 0, 13, 11, 0),
(13, 13, 0, 13, 13, 0),
(13, 13, 1, 13, 13, 1),
(13, 14, 0, 13, 14, 0),
(13, 14, 1, 13, 14, 1),
(13, 15, 0, 13, 15, 0),
(13, 15, 1, 13, 15, 1),
(12, 17, 1, 12, 17, 1),
(12, 17, 0, 12, 17, 0),
(11, 17, 1, 11, 17, 1),
(11, 17, 0, 11, 17, 0),
(10, 17, 1, 9, 17, 1),
(10, 17, 0, 9, 17, 0),
( 9, 17, 1, 10, 17, 1),
( 9, 17, 0, 10, 17, 0),
( 8, 17, 1, 8, 17, 1),
( 8, 17, 0, 8, 17, 0),
( 7, 17, 1, 7, 17, 1),
( 5, 17, 1, 5, 17, 1),
( 5, 17, 0, 5, 17, 0),
( 4, 17, 1, 4, 17, 1),
( 4, 17, 0, 4, 17, 0),
( 3, 17, 1, 3, 17, 1),
( 3, 17, 0, 3, 17, 0),
( 2, 17, 1, 2, 17, 1),
( 2, 17, 0, 2, 17, 0),
( 1, 17, 1, 1, 17, 1),
( 1, 17, 0, 1, 17, 0)
]
}
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)
rambtile_db = parse_db(iceboxdb.database_ramb_txt)
ramttile_db = parse_db(iceboxdb.database_ramt_txt)
pinloc_db = [[int(s) for s in line.split()] for line in iceboxdb.pinloc_txt.split("\n") if line != ""]
iotile_l_db = list()
@ -829,11 +1052,11 @@ for entry in iotile_full_db:
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 db in [iotile_l_db, iotile_r_db, iotile_t_db, iotile_b_db, logictile_db, rambtile_db, ramttile_db]:
for entry in db:
if entry[1] in ("buffer", "routing"):
entry[2] = netname_normalize(entry[2])
entry[3] = netname_normalize(entry[3])
entry[2] = netname_normalize(entry[2], ramb=(db == rambtile_db), ramt=(db == ramttile_db))
entry[3] = netname_normalize(entry[3], ramb=(db == rambtile_db), ramt=(db == ramttile_db))
unique_entries = dict()
while db:
entry = db.pop()

View File

@ -40,10 +40,22 @@ print("""#
# Quick File Format Reference:
# ----------------------------
#
# .device DEVICE
#
# declares the device type (e.g. "1k")
#
#
# .pins PACKAGE
# PIN_NUM TILE_X TILE_Y PIO_NUM PADIN_NUM
# ...
#
# associates a package pin with an IO tile and block
#
#
# .io_tile X Y
# .logic_tile X Y
# .ram_tile X Y
# .ramb_tile X Y
# .ramt_tile X Y
#
# declares the existence of a IO/LOGIC/RAM tile with the given coordinates
#
@ -73,6 +85,18 @@ print("""#
#
""")
print(".device 1k")
print()
print(".pins tq144")
pio_to_padin = dict()
for padin, pio in enumerate(ic.padin_pio_db()):
pio_to_padin[pio] = padin
for entry in sorted(ic.pinloc_db()):
pio = (entry[1], entry[2], entry[3])
print("%d %d %d %d %d" % tuple(entry + [pio_to_padin[pio] if pio in pio_to_padin else -1]))
print()
for idx in sorted(ic.io_tiles):
print(".io_tile %d %d" % idx)
print()
@ -81,8 +105,12 @@ 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)
for idx in sorted(ic.ramb_tiles):
print(".ramb_tile %d %d" % idx)
print()
for idx in sorted(ic.ramt_tiles):
print(".ramt_tile %d %d" % idx)
print()
for group in sorted(ic.group_segments(all_tiles)):

View File

@ -53,5 +53,6 @@ def diff_tiles(stmt, tiles1, tiles2):
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)
diff_tiles(".ramb_tile", ic1.ramb_tiles, ic2.ramb_tiles)
diff_tiles(".ramt_tile", ic1.ramt_tiles, ic2.ramt_tiles)

View File

@ -24,10 +24,11 @@ import getopt, sys, re
print_bits = False
print_map = False
single_tile = None
print_all = False
def usage():
print("""
Usage: icebox_explain [options] <bitmap.txt>
Usage: icebox_explain [options] [bitmap.txt]
-b
print config bit names for each config statement
@ -35,13 +36,16 @@ Usage: icebox_explain [options] <bitmap.txt>
-m
print tile config bitmaps
-A
don't skip uninteresting tiles
-t '<x-coordinate> <y-coordinate>'
print only the specified tile
""")
sys.exit(0)
try:
opts, args = getopt.getopt(sys.argv[1:], "bmt:")
opts, args = getopt.getopt(sys.argv[1:], "bmAt:")
except:
usage()
@ -50,11 +54,19 @@ for o, a in opts:
print_bits = True
elif o == "-m":
print_map = True
elif o == "-A":
print_all = True
elif o == "-t":
single_tile = tuple([int(s) for s in a.split()])
else:
usage()
if len(args) == 0:
args.append("/dev/stdin")
if len(args) != 1:
usage()
print("Reading file '%s'.." % args[0])
ic = icebox.iceconfig()
ic.read_file(args[0])
@ -96,7 +108,7 @@ def print_tile(stmt, ic, x, y, tile, db):
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":
if entry[1] == "RamConfig" and entry[2] == "PowerUp":
text_default_mask |= 4
if print_bits:
text.add("<%s> %s" % (" ".join(entry[0]), " ".join(entry[1:])))
@ -130,12 +142,12 @@ def print_tile(stmt, ic, x, y, tile, db):
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 not print_bitinfo and not print_all:
if text_default_mask == 3 and len(text) == 2:
return
if text_default_mask == 4 and len(text) == 1:
return
if len(text) or print_bitinfo:
if len(text) or print_bitinfo or print_all:
print("\n%s" % stmt)
if print_bitinfo:
print("Warning: No DB entries for some bits:")
@ -151,8 +163,11 @@ for idx in ic.io_tiles:
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]))
for idx in ic.ramb_tiles:
print_tile(".ramb_tile %d %d" % idx, ic, idx[0], idx[1], ic.ramb_tiles[idx], ic.tile_db(idx[0], idx[1]))
for idx in ic.ramt_tiles:
print_tile(".ramt_tile %d %d" % idx, ic, idx[0], idx[1], ic.ramt_tiles[idx], ic.tile_db(idx[0], idx[1]))
for bit in ic.extra_bits:
print()

View File

@ -47,12 +47,15 @@ for o, a in opts:
else:
usage()
if len(args) != 0:
usage()
ic = icebox.iceconfig()
ic.setup_empty_1k()
mktiles = set()
for x in range(1, 6) + range(8, 13):
for x in range(1, 13):
mktiles.add((x, 0))
mktiles.add((x, 17))
@ -64,6 +67,10 @@ for x in range(0, 5) + range(9, 14):
mktiles.add((x, 2))
mktiles.add((x, 15))
for y in range(7, 11):
mktiles.add((0, y))
mktiles.add((13, y))
for x in range(6, 8):
for y in range(8, 10):
mktiles.add((x, y))
@ -94,7 +101,7 @@ A machine-readable form of the database can be downloaded <a href="chipdb.txt">h
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
some wire names are different for e.g. an 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
@ -111,12 +118,14 @@ in iCE40 FPGAs.</p>""")
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"
if ic.tile_type(x, y) == "RAMB": color = "#eea"
if ic.tile_type(x, y) == "RAMT": 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"
if ic.tile_type(x, y) == "RAMB": color = "#aa8"
if ic.tile_type(x, y) == "RAMT": 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>")
@ -147,12 +156,14 @@ configuration bits it has and how it is connected to its neighbourhood.</p>""" %
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"
if ic.tile_type(x, y) == "RAMB": color = "#eea"
if ic.tile_type(x, y) == "RAMT": 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"
if ic.tile_type(x, y) == "RAMB": color = "#aa8"
if ic.tile_type(x, y) == "RAMT": 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>")
@ -200,11 +211,13 @@ configuration bits it has and how it is connected to its neighbourhood.</p>""" %
elif entry[1].startswith("IOB_"):
bitmap_cells[idx1][idx2]["label"] = "I"
elif entry[1].startswith("IoCtrl"):
bitmap_cells[idx1][idx2]["label"] = "I"
bitmap_cells[idx1][idx2]["label"] = "T"
elif entry[1] == "Icegate":
bitmap_cells[idx1][idx2]["label"] = "G"
elif entry[1].startswith("Cascade"):
bitmap_cells[idx1][idx2]["label"] = "A"
elif entry[1].startswith("RamConfig"):
bitmap_cells[idx1][idx2]["label"] = "R"
bitmap_cells[idx1][idx2]["label"] = "M"
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"])
@ -264,6 +277,7 @@ nets are connected with nets from cells in its neighbourhood.</p>""")
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("ram"): cat = (25, "RAM 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")

View File

@ -31,7 +31,8 @@ def usage():
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")
print(" icebox_maps -m ramb_tile_nets")
print(" icebox_maps -m ramt_tile_nets")
sys.exit(0)
try:
@ -45,6 +46,9 @@ for o, a in opts:
else:
usage()
if len(args) != 0:
usage()
def get_bit_group(x, y, db):
bit = "B%d[%d]" % (y, x)
nbit = "!B%d[%d]" % (y, x)
@ -113,7 +117,8 @@ if mode == "bitmaps":
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_tilemap(".ramb_tile_bitmap", icebox.rambtile_db, 42)
print_tilemap(".ramt_tile_bitmap", icebox.ramttile_db, 42)
print()
print(".bitmap_legend")
print("- ... unknown bit")
@ -144,8 +149,11 @@ elif mode == "io_tile_nets_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")
elif mode == "ramb_tile_nets":
print_db_nets(".ramb_tile_nets", icebox.ramtile_db, "c")
elif mode == "ramt_tile_nets":
print_db_nets(".ramt_tile_nets", icebox.ramtile_db, "c")
else:
usage()

View File

@ -24,15 +24,16 @@ import getopt, sys, re
strip_comments = False
strip_interconn = False
lookup_pins = False
check_ieren = False
check_driver = False
pcf_data = dict()
portnames = set()
unmatched_ports = set()
auto_clk = False
auto_en = False
modname = "chip"
def usage():
print("""
Usage: icebox_vlog [options] <bitmap.txt>
Usage: icebox_vlog [options] [bitmap.txt]
-s
strip comments from output
@ -40,24 +41,29 @@ Usage: icebox_vlog [options] <bitmap.txt>
-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
-n <module-name>
name for the exported module (default: "chip")
-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.
-R
enable IeRen database checks
-D
enable exactly-one-driver checks
""")
sys.exit(0)
try:
opts, args = getopt.getopt(sys.argv[1:], "sSlap:P:")
opts, args = getopt.getopt(sys.argv[1:], "sSlap:P:n:RD")
except:
usage()
@ -68,18 +74,22 @@ for o, a in opts:
strip_interconn = True
elif o == "-l":
lookup_pins = True
elif o == "-n":
modname = a
elif o == "-a":
auto_clk = True
auto_en = True
pass # ignored for backward compatibility
elif o in ("-p", "-P"):
with open(a, "r") as f:
for line in f:
if o == "-P" and not re.search(" # ICE_(GB_)?IO", line):
continue
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("_obuft", "")
p = p.replace("_obuf", "")
p = p.replace("_gb_io", "")
portnames.add(p)
@ -88,9 +98,19 @@ for o, a in opts:
unmatched_ports.add(p)
pinloc = tuple([int(s) for s in line[2:]])
pcf_data[pinloc] = p
elif o == "-R":
check_ieren = True
elif o == "-D":
check_driver = True
else:
usage()
if len(args) == 0:
args.append("/dev/stdin")
if len(args) != 1:
usage()
if not strip_comments:
print("// Reading file '%s'.." % args[0])
ic = icebox.iceconfig()
@ -102,13 +122,19 @@ text_ports = list()
luts_queue = set()
text_func = list()
failed_drivers_check = list()
netidx = [0]
nets = dict()
seg2net = dict()
auto_clk_nets = set()
auto_en_nets = set()
iocells = set()
iocells_in = set()
iocells_out = set()
iocells_special = set()
iocells_type = dict()
iocells_negclk = set()
iocells_inbufs = set()
def is_interconn(netname):
if netname.startswith("sp4_"): return True
@ -120,27 +146,93 @@ def is_interconn(netname):
if netname.startswith("local_"): return True
return False
extra_connections = list()
extra_segments = list()
for bit in ic.extra_bits:
entry = ic.lookup_extra_bit(bit)
if entry[0] == "padin_glb_netwk":
glb = int(entry[1])
pin_entry = ic.padin_pio_db()[glb]
iocells.add((pin_entry[0], pin_entry[1], pin_entry[2]))
iocells_in.add((pin_entry[0], pin_entry[1], pin_entry[2]))
s1 = (pin_entry[0], pin_entry[1], "io_%d/PAD" % pin_entry[2])
s2 = (pin_entry[0], pin_entry[1], "wire_gbuf/padin_%d" % pin_entry[2])
extra_connections.append((s1, s2))
for idx, tile in ic.io_tiles.items():
tc = icebox.tileconfig(tile)
iocells_type[(idx[0], idx[1], 0)] = ["0" for i in range(6)]
iocells_type[(idx[0], idx[1], 1)] = ["0" for i in range(6)]
for entry in ic.tile_db(idx[0], idx[1]):
if check_ieren and entry[1] == "IoCtrl" and entry[2].startswith("IE_") and not tc.match(entry[0]):
iren_idx = (idx[0], idx[1], 0 if entry[2] == "IE_0" else 1)
for iren_entry in ic.ieren_db():
if iren_idx[0] == iren_entry[3] and iren_idx[1] == iren_entry[4] and iren_idx[2] == iren_entry[5]:
iocells_inbufs.add((iren_entry[0], iren_entry[1], iren_entry[2]))
if entry[1] == "NegClk" and tc.match(entry[0]):
iocells_negclk.add((idx[0], idx[1], 0))
iocells_negclk.add((idx[0], idx[1], 1))
if entry[1].startswith("IOB_") and entry[2].startswith("PINTYPE_") and tc.match(entry[0]):
match1 = re.match("IOB_(\d+)", entry[1])
match2 = re.match("PINTYPE_(\d+)", entry[2])
assert match1 and match2
iocells_type[(idx[0], idx[1], int(match1.group(1)))][int(match2.group(1))] = "1"
iocells_type[(idx[0], idx[1], 0)] = "".join(iocells_type[(idx[0], idx[1], 0)])
iocells_type[(idx[0], idx[1], 1)] = "".join(iocells_type[(idx[0], idx[1], 1)])
for segs in sorted(ic.group_segments()):
for seg in segs:
if ic.tile_type(seg[0], seg[1]) == "IO":
match = re.match("io_(\d+)/D_(IN|OUT)_(\d+)", seg[2])
if match:
cell = (seg[0], seg[1], int(match.group(1)))
iocells.add(cell)
if match.group(2) == "IN":
if check_ieren:
assert cell in iocells_inbufs
if iocells_type[cell] != "100000" or match.group(3) != "0":
iocells_special.add(cell)
iocells_in.add(cell)
if match.group(2) == "OUT" and iocells_type[cell][2:6] != "0000":
if iocells_type[cell] != "100110" or match.group(3) != "0":
iocells_special.add(cell)
iocells_out.add(cell)
extra_segments.append((seg[0], seg[1], "io_%d/PAD" % int(match.group(1))))
for cell in iocells:
if iocells_type[cell] == "100110" and not cell in iocells_special:
s1 = (cell[0], cell[1], "io_%d/PAD" % cell[2])
s2 = (cell[0], cell[1], "io_%d/D_OUT_0" % cell[2])
extra_connections.append((s1, s2))
del iocells_type[cell]
elif iocells_type[cell] == "100000" and not cell in iocells_special:
s1 = (cell[0], cell[1], "io_%d/PAD" % cell[2])
s2 = (cell[0], cell[1], "io_%d/D_IN_0" % cell[2])
extra_connections.append((s1, s2))
del iocells_type[cell]
def next_netname():
while True:
netidx[0] += 1
n = "n%d" % netidx[0]
if n not in portnames: break
if n not in portnames:
return n
for segs in sorted(ic.group_segments(extra_connections=extra_connections, extra_segments=extra_segments)):
n = next_netname()
net_segs = set()
renamed_net_to_port = False
for s in segs:
match = re.match("io_(\d+)/D_(IN|OUT)_(\d+)$", s[2])
match = re.match("io_(\d+)/PAD", 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)
idx = (s[0], s[1], int(match.group(1)))
p = "io_%d_%d_%d" % idx
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 idx[0] == entry[1] and idx[1] == entry[2] and idx[2] == entry[3]:
if (entry[0],) in pcf_data:
p = pcf_data[(entry[0],)]
unmatched_ports.discard(p)
@ -149,24 +241,25 @@ for segs in sorted(ic.group_segments()):
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":
if idx in iocells_in and idx not in iocells_out:
text_ports.append("input %s" % p)
else:
elif idx not in iocells_in and idx in iocells_out:
text_ports.append("output %s" % p)
else:
text_ports.append("inout %s" % p)
text_wires.append("wire %s;" % n)
renamed_net_to_port = True
elif match.group(2) == "IN":
elif idx in iocells_in and idx not in iocells_out:
text_ports.append("input %s" % p)
text_wires.append("assign %s = %s;" % (n, p))
else:
elif idx not in iocells_in and idx in iocells_out:
text_ports.append("output %s" % p)
text_wires.append("assign %s = %s;" % (p, n))
else:
text_ports.append("inout %s" % p)
text_wires.append("assign %s = %s;" % (p, n))
match = re.match("lutff_(\d+)/", s[2])
if match:
@ -187,60 +280,27 @@ for segs in sorted(ic.group_segments()):
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)
count_drivers = 0
for s in segs:
if re.match(r"ram/RDATA_", s[2]): count_drivers += 1
if re.match(r"io_./D_IN_", s[2]): count_drivers += 1
if re.match(r"lutff_./out", s[2]): count_drivers += 1
if count_drivers != 1 and check_driver:
failed_drivers_check.append(n)
if not strip_comments:
for s in sorted(net_segs):
text_wires.append("// %s" % (s,))
if count_drivers != 1 and check_driver:
text_wires.append("// Number of drivers: %d" % count_drivers)
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
n = next_netname()
nets[n] = set([seg])
seg2net[seg] = n
text_wires.append("wire %s;" % n)
@ -250,6 +310,134 @@ def seg_to_net(seg, default=None):
text_wires.append("")
return seg2net[seg]
for cell in iocells:
if cell in iocells_type:
net_pad = seg_to_net((cell[0], cell[1], "io_%d/PAD" % cell[2]))
net_din0 = seg_to_net((cell[0], cell[1], "io_%d/D_IN_0" % cell[2]), "")
net_din1 = seg_to_net((cell[0], cell[1], "io_%d/D_IN_1" % cell[2]), "")
net_dout0 = seg_to_net((cell[0], cell[1], "io_%d/D_OUT_0" % cell[2]), "0")
net_dout1 = seg_to_net((cell[0], cell[1], "io_%d/D_OUT_1" % cell[2]), "0")
net_oen = seg_to_net((cell[0], cell[1], "io_%d/OUT_ENB" % cell[2]), "1")
net_cen = seg_to_net((cell[0], cell[1], "io_global/cen"), "1")
net_iclk = seg_to_net((cell[0], cell[1], "io_global/inclk"), "0")
net_oclk = seg_to_net((cell[0], cell[1], "io_global/outclk"), "0")
net_latch = seg_to_net((cell[0], cell[1], "io_global/latch"), "0")
iotype = iocells_type[cell]
if cell in iocells_negclk:
posedge = "negedge"
negedge = "posedge"
else:
posedge = "posedge"
negedge = "negedge"
text_func.append("// IO Cell %s" % (cell,))
if not strip_comments:
text_func.append("// PAD = %s" % net_pad)
text_func.append("// D_IN_0 = %s" % net_din0)
text_func.append("// D_IN_1 = %s" % net_din1)
text_func.append("// D_OUT_0 = %s" % net_dout0)
text_func.append("// D_OUT_1 = %s" % net_dout1)
text_func.append("// OUT_ENB = %s" % net_oen)
text_func.append("// CLK_EN = %s" % net_cen)
text_func.append("// IN_CLK = %s" % net_iclk)
text_func.append("// OUT_CLK = %s" % net_oclk)
text_func.append("// LATCH = %s" % net_latch)
text_func.append("// TYPE = %s (LSB:MSB)" % iotype)
if net_din0 != "" or net_din1 != "":
if net_cen == "1":
icen_cond = ""
else:
icen_cond = "if (%s) " % net_cen
if net_din0 != "":
if iotype[1] == "0" and iotype[0] == "0":
reg_din0 = next_netname()
text_func.append("reg %s;" % reg_din0)
text_func.append("always @(%s %s) %s%s <= %s;" % (posedge, net_iclk, icen_cond, reg_din0, net_pad))
text_func.append("assign %s = %s;" % (net_din0, reg_din0))
if iotype[1] == "0" and iotype[0] == "1":
text_func.append("assign %s = %s;" % (net_din0, net_pad))
if iotype[1] == "1" and iotype[0] == "0":
reg_din0 = next_netname()
reg_din0_latched = next_netname()
text_func.append("reg %s, %s;" % (reg_din0, reg_din0_latched))
text_func.append("always @(%s %s) %s%s <= %s;" % (posedge, net_iclk, icen_cond, reg_din0, net_pad))
text_func.append("always @* if (!%s) %s = %s;" % (net_latch, reg_din0_latched, reg_din0))
text_func.append("assign %s = %s;" % (net_din0, reg_din0_latched))
if iotype[1] == "1" and iotype[0] == "1":
reg_din0 = next_netname()
text_func.append("reg %s;" % reg_din0)
text_func.append("always @* if (!%s) %s = %s;" % (net_latch, reg_din0, net_pad))
text_func.append("assign %s = %s;" % (net_din0, reg_din0))
if net_din1 != "":
reg_din1 = next_netname()
text_func.append("reg %s;" % reg_din1)
text_func.append("always @(%s %s) %s%s <= %s;" % (negedge, net_iclk, icen_cond, reg_din1, net_pad))
text_func.append("assign %s = %s;" % (net_din1, reg_din1))
if iotype[5] != "0" or iotype[4] != "0":
if net_cen == "1":
ocen_cond = ""
else:
ocen_cond = "if (%s) " % net_cen
# effective OEN: iotype[4], iotype[5]
if iotype[5] == "0" and iotype[4] == "1":
eff_oen = "1"
if iotype[5] == "1" and iotype[4] == "0":
eff_oen = net_oen
if iotype[5] == "1" and iotype[4] == "1":
eff_oen = next_netname()
text_func.append("reg %s;" % eff_oen)
text_func.append("always @(%s %s) %s%s <= %s;" % (posedge, net_oclk, ocen_cond, eff_oen, net_oen))
# effective DOUT: iotype[2], iotype[3]
if iotype[2] == "0" and iotype[3] == "0":
ddr_posedge = next_netname()
ddr_negedge = next_netname()
text_func.append("reg %s, %s;" % (ddr_posedge, ddr_negedge))
text_func.append("always @(%s %s) %s%s <= %s;" % (posedge, net_oclk, ocen_cond, ddr_posedge, net_dout0))
text_func.append("always @(%s %s) %s%s <= %s;" % (negedge, net_oclk, ocen_cond, ddr_negedge, net_dout1))
eff_dout = next_netname()
text_func.append("wire %s;" % (eff_dout))
if cell in iocells_negclk:
text_func.append("assign %s = %s ? %s : %s;" % (eff_dout, net_oclk, ddr_negedge, ddr_posedge))
else:
text_func.append("assign %s = %s ? %s : %s;" % (eff_dout, net_oclk, ddr_posedge, ddr_negedge))
if iotype[2] == "0" and iotype[3] == "1":
eff_dout = net_dout0
if iotype[2] == "1" and iotype[3] == "0":
eff_dout = next_netname()
text_func.append("reg %s;" % eff_dout)
text_func.append("always @(%s %s) %s%s <= %s;" % (posedge, net_oclk, ocen_cond, eff_dout, net_dout0))
if iotype[2] == "1" and iotype[3] == "1":
eff_dout = next_netname()
text_func.append("reg %s;" % eff_dout)
text_func.append("always @(%s %s) %s%s <= !%s;" % (posedge, net_oclk, ocen_cond, eff_dout, net_dout0))
if eff_oen == "1":
text_func.append("assign %s = %s;" % (net_pad, eff_dout))
else:
text_func.append("assign %s = %s ? %s : 1'bz;" % (net_pad, eff_oen, eff_dout))
text_func.append("")
for p in unmatched_ports:
text_ports.append("input %s" % p)
wire_to_reg = set()
lut_assigns = list()
const_assigns = list()
@ -288,10 +476,7 @@ for lut in luts_queue:
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
n = next_netname()
text_wires.append("wire %s;" % n)
if not strip_comments:
text_wires.append("// FF %s" % (lut,))
@ -332,7 +517,7 @@ for lut in luts_queue:
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))
print("module %s (%s);\n" % (modname, ", ".join(text_ports)))
new_text_wires = list()
for line in text_wires:
@ -365,3 +550,8 @@ if unmatched_ports:
print("endmodule")
print()
if failed_drivers_check:
print("// Single-driver-check failed for %d nets:" % len(failed_drivers_check))
print("// %s" % " ".join(failed_drivers_check))
assert False

File diff suppressed because it is too large Load Diff

View File

@ -599,7 +599,7 @@ void FpgaConfig::read_ascii(std::istream &ifs)
continue;
}
if (command == ".io_tile" || command == ".logic_tile" || command == ".ram_tile")
if (command == ".io_tile" || command == ".logic_tile" || command == ".ramb_tile" || command == ".ramt_tile")
{
if (!got_device)
error("Missing .device statement before %s.\n", command.c_str());
@ -766,7 +766,7 @@ string FpgaConfig::tile_type(int x, int y) const
if (this->device == "1k") {
if ((x == 0 || x == this->chip_width()+1) && (y == 0 || y == this->chip_height()+1)) return "corner";
if ((x == 0 || x == this->chip_width()+1) || (y == 0 || y == this->chip_height()+1)) return "io";
if (x == 3 || x == 10) return "ram";
if (x == 3 || x == 10) return y % 2 == 1 ? "ramb" : "ramt";
return "logic";
}
panic("Unkown chip type '%s'.\n", this->device.c_str());
@ -776,7 +776,8 @@ int FpgaConfig::tile_width(const string &type) const
{
if (type == "corner") return 0;
if (type == "logic") return 54;
if (type == "ram") return 42;
if (type == "ramb") return 42;
if (type == "ramt") return 42;
if (type == "io") return 18;
panic("Unkown tile type '%s'.\n", type.c_str());
}