mirror of https://github.com/YosysHQ/icestorm.git
Import of icestorm-snapshot-150526.zip
This commit is contained in:
parent
c41701ca3a
commit
13e63e6b65
|
|
@ -0,0 +1,18 @@
|
|||
|
||||
all:
|
||||
$(MAKE) -C icebox
|
||||
$(MAKE) -C icepack
|
||||
$(MAKE) -C iceprog
|
||||
|
||||
install:
|
||||
$(MAKE) -C icebox install
|
||||
$(MAKE) -C icepack install
|
||||
$(MAKE) -C iceprog install
|
||||
|
||||
uninstall:
|
||||
$(MAKE) -C icebox uninstall
|
||||
$(MAKE) -C icepack uninstall
|
||||
$(MAKE) -C iceprog uninstall
|
||||
|
||||
.PHONY: all install uninstall
|
||||
|
||||
|
|
@ -1,7 +1,13 @@
|
|||
|
||||
all:
|
||||
chipdb: chipdb-1k.txt
|
||||
|
||||
install:
|
||||
chipdb-1k.txt: icebox.py iceboxdb.py icebox_chipdb.py
|
||||
python icebox_chipdb.py > chipdb-1k.new
|
||||
mv chipdb-1k.new chipdb-1k.txt
|
||||
|
||||
install: chipdb
|
||||
mkdir -p /usr/local/share/icebox
|
||||
cp chipdb-1k.txt /usr/local/share/icebox/
|
||||
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
|
||||
|
|
@ -20,6 +26,8 @@ uninstall:
|
|||
rm -f /usr/local/bin/icebox_html
|
||||
rm -f /usr/local/bin/icebox_maps
|
||||
rm -f /usr/local/bin/icebox_vlog
|
||||
rm -f /usr/local/share/icebox/chipdb-1k.txt
|
||||
-rmdir /usr/local/share/icebox
|
||||
|
||||
.PHONY: install uninstall
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ class iceconfig:
|
|||
self.io_tiles = dict()
|
||||
self.ramb_tiles = dict()
|
||||
self.ramt_tiles = dict()
|
||||
self.ram_data = dict()
|
||||
self.extra_bits = set()
|
||||
|
||||
def setup_empty_1k(self):
|
||||
|
|
@ -78,8 +79,8 @@ class iceconfig:
|
|||
def gbufin_db(self):
|
||||
return gbufin_db[self.device]
|
||||
|
||||
def icegate_db(self):
|
||||
return icegate_db[self.device]
|
||||
def iolatch_db(self):
|
||||
return iolatch_db[self.device]
|
||||
|
||||
def padin_pio_db(self):
|
||||
return padin_pio_db[self.device]
|
||||
|
|
@ -90,6 +91,21 @@ class iceconfig:
|
|||
def ieren_db(self):
|
||||
return ieren_db[self.device]
|
||||
|
||||
def colbuf_db(self):
|
||||
assert self.device == "1k"
|
||||
entries = list()
|
||||
for x in range(self.max_x+1):
|
||||
for y in range(self.max_y+1):
|
||||
src_y = None
|
||||
if 0 <= y <= 4: src_y = 4
|
||||
if 5 <= y <= 8: src_y = 5
|
||||
if 9 <= y <= 12: src_y = 12
|
||||
if 13 <= y <= 17: src_y = 13
|
||||
if x in [3, 10] and src_y == 4: src_y = 3
|
||||
if x in [3, 10] and src_y == 12: src_y = 11
|
||||
entries.append((x, src_y, x, y))
|
||||
return entries
|
||||
|
||||
def tile_db(self, x, y):
|
||||
if x == 0: return iotile_l_db
|
||||
if y == 0: return iotile_b_db
|
||||
|
|
@ -307,7 +323,7 @@ class iceconfig:
|
|||
neighbours.add((s[0], s[1], s[2]))
|
||||
return neighbours
|
||||
|
||||
def group_segments(self, all_from_tiles=set(), extra_connections=list(), extra_segments=list()):
|
||||
def group_segments(self, all_from_tiles=set(), extra_connections=list(), extra_segments=list(), connect_gb=True):
|
||||
seed_segments = set()
|
||||
seen_segments = set()
|
||||
connected_segments = dict()
|
||||
|
|
@ -373,7 +389,7 @@ class iceconfig:
|
|||
seed_segments.add(s1)
|
||||
seed_segments.add(s2)
|
||||
|
||||
for entry in self.icegate_db():
|
||||
for entry in self.iolatch_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:
|
||||
|
|
@ -388,14 +404,15 @@ class iceconfig:
|
|||
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)
|
||||
if connect_gb:
|
||||
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()
|
||||
|
|
@ -444,7 +461,7 @@ class iceconfig:
|
|||
if line[0][0] != ".":
|
||||
if expected_data_lines == -1:
|
||||
continue
|
||||
if line[0][0] != "0" and line[0][0] != "1":
|
||||
if line[0][0] not in "0123456789abcdef":
|
||||
print("%sWarning: ignoring data block in line %d: %s" % (logprefix, linenum, linetext.strip()))
|
||||
expected_data_lines = 0
|
||||
continue
|
||||
|
|
@ -453,7 +470,7 @@ class iceconfig:
|
|||
expected_data_lines -= 1
|
||||
continue
|
||||
assert expected_data_lines <= 0
|
||||
if line[0] in (".io_tile", ".logic_tile", ".ramb_tile", ".ramt_tile"):
|
||||
if line[0] in (".io_tile", ".logic_tile", ".ramb_tile", ".ramt_tile", ".ram_data"):
|
||||
current_data = list()
|
||||
expected_data_lines = 16
|
||||
self.max_x = max(self.max_x, int(line[1]))
|
||||
|
|
@ -470,6 +487,9 @@ class iceconfig:
|
|||
if line[0] == ".ramt_tile":
|
||||
self.ramt_tiles[(int(line[1]), int(line[2]))] = current_data
|
||||
continue
|
||||
if line[0] == ".ram_data":
|
||||
self.ram_data[(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])))
|
||||
continue
|
||||
|
|
@ -481,6 +501,7 @@ class iceconfig:
|
|||
expected_data_lines = -1
|
||||
continue
|
||||
print("%sWarning: ignoring line %d: %s" % (logprefix, linenum, linetext.strip()))
|
||||
expected_data_lines = -1
|
||||
|
||||
class tileconfig:
|
||||
def __init__(self, tile):
|
||||
|
|
@ -905,7 +926,7 @@ gbufin_db = {
|
|||
]
|
||||
}
|
||||
|
||||
icegate_db = {
|
||||
iolatch_db = {
|
||||
"1k": [
|
||||
( 0, 7),
|
||||
(13, 10),
|
||||
|
|
@ -914,6 +935,39 @@ icegate_db = {
|
|||
]
|
||||
}
|
||||
|
||||
pllinfo_db = {
|
||||
"1k": {
|
||||
"SHIFTREG_DIV_MODE": (0, 3, "B2[2]"),
|
||||
"FDA_FEEDBACK_0": (0, 3, "B7[3]"),
|
||||
"FDA_FEEDBACK_1": (0, 4, "B0[2]"),
|
||||
"FDA_FEEDBACK_2": (0, 4, "B0[3]"),
|
||||
"FDA_FEEDBACK_3": (0, 4, "B3[3]"),
|
||||
"FDA_RELATIVE_0": (0, 4, "B2[3]"),
|
||||
"FDA_RELATIVE_1": (0, 4, "B5[3]"),
|
||||
"FDA_RELATIVE_2": (0, 4, "B4[2]"),
|
||||
"FDA_RELATIVE_3": (0, 4, "B4[3]"),
|
||||
"DIVR_0": (0, 1, "B0[2]"),
|
||||
"DIVR_1": (0, 1, "B0[3]"),
|
||||
"DIVR_2": (0, 1, "B3[3]"),
|
||||
"DIVR_3": (0, 1, "B2[2]"),
|
||||
"DIVF_0": (0, 1, "B2[3]"),
|
||||
"DIVF_1": (0, 1, "B5[3]"),
|
||||
"DIVF_2": (0, 1, "B4[2]"),
|
||||
"DIVF_3": (0, 1, "B4[3]"),
|
||||
"DIVF_4": (0, 1, "B7[3]"),
|
||||
"DIVF_5": (0, 2, "B0[2]"),
|
||||
"DIVF_6": (0, 2, "B0[3]"),
|
||||
"DIVQ_0": (0, 0, "?"),
|
||||
"DIVQ_1": (0, 0, "?"),
|
||||
"DIVQ_2": (0, 0, "?"),
|
||||
"FILTER_RANGE_0": (0, 2, "B5[3]"),
|
||||
"FILTER_RANGE_1": (0, 2, "B4[2]"),
|
||||
"FILTER_RANGE_2": (0, 2, "B4[3]"),
|
||||
"ENABLE_ICEGATE": (0, 0, "?"),
|
||||
"TEST_MODE": (0, 3, "B4[3]"),
|
||||
}
|
||||
}
|
||||
|
||||
padin_pio_db = {
|
||||
"1k": [
|
||||
(13, 8, 1), # glb_netwk_0
|
||||
|
|
@ -941,6 +995,8 @@ ieren_db = {
|
|||
( 0, 10, 1, 0, 10, 0),
|
||||
( 0, 10, 0, 0, 10, 1),
|
||||
( 0, 9, 1, 0, 9, 0),
|
||||
( 0, 9, 0, 0, 9, 1),
|
||||
( 0, 8, 1, 0, 8, 0),
|
||||
( 0, 8, 0, 0, 8, 1),
|
||||
( 0, 6, 1, 0, 6, 0),
|
||||
( 0, 6, 0, 0, 6, 1),
|
||||
|
|
@ -954,6 +1010,7 @@ ieren_db = {
|
|||
( 0, 2, 0, 0, 2, 1),
|
||||
( 1, 0, 0, 1, 0, 0),
|
||||
( 1, 0, 1, 1, 0, 1),
|
||||
( 2, 0, 0, 2, 0, 0),
|
||||
( 2, 0, 1, 2, 0, 1),
|
||||
( 3, 0, 0, 3, 0, 0),
|
||||
( 3, 0, 1, 3, 0, 1),
|
||||
|
|
@ -961,6 +1018,8 @@ ieren_db = {
|
|||
( 4, 0, 1, 4, 0, 1),
|
||||
( 5, 0, 0, 5, 0, 0),
|
||||
( 5, 0, 1, 5, 0, 1),
|
||||
( 6, 0, 1, 6, 0, 0),
|
||||
( 7, 0, 0, 6, 0, 1),
|
||||
( 6, 0, 0, 7, 0, 0),
|
||||
( 7, 0, 1, 7, 0, 1),
|
||||
( 8, 0, 0, 8, 0, 0),
|
||||
|
|
@ -969,6 +1028,10 @@ ieren_db = {
|
|||
( 9, 0, 1, 9, 0, 1),
|
||||
(10, 0, 0, 10, 0, 0),
|
||||
(10, 0, 1, 10, 0, 1),
|
||||
(11, 0, 0, 11, 0, 0),
|
||||
(11, 0, 1, 11, 0, 1),
|
||||
(12, 0, 0, 12, 0, 0),
|
||||
(12, 0, 1, 12, 0, 1),
|
||||
(13, 1, 0, 13, 1, 0),
|
||||
(13, 1, 1, 13, 1, 1),
|
||||
(13, 2, 0, 13, 2, 0),
|
||||
|
|
@ -981,10 +1044,13 @@ ieren_db = {
|
|||
(13, 7, 0, 13, 7, 0),
|
||||
(13, 7, 1, 13, 7, 1),
|
||||
(13, 8, 0, 13, 8, 0),
|
||||
(13, 8, 1, 13, 8, 1),
|
||||
(13, 9, 0, 13, 9, 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, 12, 1, 13, 11, 1),
|
||||
(13, 13, 0, 13, 13, 0),
|
||||
(13, 13, 1, 13, 13, 1),
|
||||
(13, 14, 0, 13, 14, 0),
|
||||
|
|
@ -1002,6 +1068,8 @@ ieren_db = {
|
|||
( 8, 17, 1, 8, 17, 1),
|
||||
( 8, 17, 0, 8, 17, 0),
|
||||
( 7, 17, 1, 7, 17, 1),
|
||||
( 7, 17, 0, 7, 17, 0),
|
||||
( 6, 17, 1, 6, 17, 1),
|
||||
( 5, 17, 1, 5, 17, 1),
|
||||
( 5, 17, 0, 5, 17, 0),
|
||||
( 4, 17, 1, 4, 17, 1),
|
||||
|
|
|
|||
|
|
@ -40,16 +40,44 @@ print("""#
|
|||
# Quick File Format Reference:
|
||||
# ----------------------------
|
||||
#
|
||||
# .device DEVICE
|
||||
# .device DEVICE WIDTH HEIGHT NUM_NETS
|
||||
#
|
||||
# declares the device type (e.g. "1k")
|
||||
#
|
||||
#
|
||||
# .pins PACKAGE
|
||||
# PIN_NUM TILE_X TILE_Y PIO_NUM PADIN_NUM
|
||||
# PIN_NUM TILE_X TILE_Y PIO_NUM GLB_NUM
|
||||
# ...
|
||||
#
|
||||
# associates a package pin with an IO tile and block
|
||||
# associates a package pin with an IO tile and block, and global network
|
||||
#
|
||||
#
|
||||
# .gbufin
|
||||
# TILE_X TILE_Y GLB_NUM
|
||||
# ...
|
||||
#
|
||||
# associates an IO tile with the global network it drives via wire_gbuf/in
|
||||
#
|
||||
#
|
||||
# .iolatch
|
||||
# TILE_X TILE_Y
|
||||
# ...
|
||||
#
|
||||
# specifies the IO tiles that drive the latch signal for the bank via wire_gbuf/in
|
||||
#
|
||||
#
|
||||
# .ieren
|
||||
# PIO_TILE_X PIO_TILE_Y PIO_NUM IEREN_TILE_X IEREN_TILE_Y IEREN_NUM
|
||||
# ...
|
||||
#
|
||||
# associates an IO block with an IeRen-block
|
||||
#
|
||||
#
|
||||
# .colbuf
|
||||
# SOURCE_TILE_X SOURCE_TILE_Y DEST_TILE_X DEST_TILE_Y
|
||||
# ...
|
||||
#
|
||||
# declares the positions of the column buffers
|
||||
#
|
||||
#
|
||||
# .io_tile X Y
|
||||
|
|
@ -60,6 +88,24 @@ print("""#
|
|||
# declares the existence of a IO/LOGIC/RAM tile with the given coordinates
|
||||
#
|
||||
#
|
||||
# .io_tile_bits COLUMNS ROWS
|
||||
# .logic_tile_bits COLUMNS ROWS
|
||||
# .ramb_tile_bits COLUMNS ROWS
|
||||
# .ramt_tile_bits COLUMNS ROWS
|
||||
# FUNCTION_1 CONFIG_BITS_NAMES_1
|
||||
# FUNCTION_2 CONFIG_BITS_NAMES_2
|
||||
# ...
|
||||
#
|
||||
# declares non-routing configuration bits of IO/LOGIC/RAM tiles
|
||||
#
|
||||
#
|
||||
# .extra_bits
|
||||
# FUNCTION BANK_NUM ADDR_X ADDR_Y
|
||||
# ...
|
||||
#
|
||||
# declares non-routing global configuration bits
|
||||
#
|
||||
#
|
||||
# .net NET_INDEX
|
||||
# X1 Y1 name1
|
||||
# X2 Y2 name2
|
||||
|
|
@ -85,7 +131,9 @@ print("""#
|
|||
#
|
||||
""")
|
||||
|
||||
print(".device 1k")
|
||||
all_group_segments = ic.group_segments(all_tiles, connect_gb=False)
|
||||
|
||||
print(".device 1k %d %d %d" % (ic.max_x+1, ic.max_y+1, len(all_group_segments)))
|
||||
print()
|
||||
|
||||
print(".pins tq144")
|
||||
|
|
@ -97,6 +145,26 @@ for entry in sorted(ic.pinloc_db()):
|
|||
print("%d %d %d %d %d" % tuple(entry + [pio_to_padin[pio] if pio in pio_to_padin else -1]))
|
||||
print()
|
||||
|
||||
print(".gbufin")
|
||||
for entry in sorted(ic.gbufin_db()):
|
||||
print(" ".join(["%d" % k for k in entry]))
|
||||
print()
|
||||
|
||||
print(".iolatch")
|
||||
for entry in sorted(ic.iolatch_db()):
|
||||
print(" ".join(["%d" % k for k in entry]))
|
||||
print()
|
||||
|
||||
print(".ieren")
|
||||
for entry in sorted(ic.ieren_db()):
|
||||
print(" ".join(["%d" % k for k in entry]))
|
||||
print()
|
||||
|
||||
print(".colbuf")
|
||||
for entry in sorted(ic.colbuf_db()):
|
||||
print(" ".join(["%d" % k for k in entry]))
|
||||
print()
|
||||
|
||||
for idx in sorted(ic.io_tiles):
|
||||
print(".io_tile %d %d" % idx)
|
||||
print()
|
||||
|
|
@ -113,7 +181,42 @@ for idx in sorted(ic.ramt_tiles):
|
|||
print(".ramt_tile %d %d" % idx)
|
||||
print()
|
||||
|
||||
for group in sorted(ic.group_segments(all_tiles)):
|
||||
def print_tile_nonrouting_bits(tile_type, idx):
|
||||
tx = idx[0]
|
||||
ty = idx[1]
|
||||
|
||||
tile = ic.tile(tx, ty)
|
||||
|
||||
print(".%s_tile_bits %d %d" % (tile_type, len(tile[0]), len(tile)))
|
||||
|
||||
function_bits = 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"):
|
||||
continue
|
||||
|
||||
func = ".".join(entry[1:])
|
||||
function_bits[func] = entry[0]
|
||||
|
||||
for x in sorted(function_bits):
|
||||
print(" ".join([x] + function_bits[x]))
|
||||
print()
|
||||
|
||||
print_tile_nonrouting_bits("logic", ic.logic_tiles.keys()[0])
|
||||
print_tile_nonrouting_bits("io", ic.io_tiles.keys()[0])
|
||||
print_tile_nonrouting_bits("ramb", ic.ramb_tiles.keys()[0])
|
||||
print_tile_nonrouting_bits("ramt", ic.ramt_tiles.keys()[0])
|
||||
|
||||
print(".extra_bits")
|
||||
extra_bits = dict()
|
||||
for idx in sorted(ic.extra_bits_db()):
|
||||
extra_bits[".".join(ic.extra_bits_db()[idx])] = " ".join(["%d" % k for k in idx])
|
||||
for idx in sorted(extra_bits):
|
||||
print("%s %s" % (idx, extra_bits[idx]))
|
||||
print()
|
||||
|
||||
for group in sorted(all_group_segments):
|
||||
netidx = len(net_to_segs)
|
||||
net_to_segs.append(group)
|
||||
print(".net %d" % netidx)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,17 @@ print("Reading file '%s'.." % sys.argv[2])
|
|||
ic2 = icebox.iceconfig()
|
||||
ic2.read_file(sys.argv[2])
|
||||
|
||||
def format_bits(line_nr, this_line, other_line):
|
||||
text = ""
|
||||
for i in range(len(this_line)):
|
||||
if this_line[i] != other_line[i]:
|
||||
if this_line[i] == "1":
|
||||
text += "%8s" % ("B%d[%d]" % (line_nr, i))
|
||||
else:
|
||||
text += "%8s" % ""
|
||||
return text
|
||||
|
||||
|
||||
def diff_tiles(stmt, tiles1, tiles2):
|
||||
for i in sorted(set(tiles1.keys() + tiles2.keys())):
|
||||
if not i in tiles1:
|
||||
|
|
@ -48,8 +59,8 @@ def diff_tiles(stmt, tiles1, tiles2):
|
|||
if tiles1[i][c] == tiles2[i][c]:
|
||||
print(" %s" % tiles1[i][c])
|
||||
else:
|
||||
print("- %s" % tiles1[i][c])
|
||||
print("+ %s" % tiles2[i][c])
|
||||
print("- %s%s" % (tiles1[i][c], format_bits(c, tiles1[i][c], tiles2[i][c])))
|
||||
print("+ %s%s" % (tiles2[i][c], format_bits(c, tiles2[i][c], tiles1[i][c])))
|
||||
|
||||
diff_tiles(".io_tile", ic1.io_tiles, ic2.io_tiles)
|
||||
diff_tiles(".logic_tile", ic1.logic_tiles, ic2.logic_tiles)
|
||||
|
|
|
|||
|
|
@ -218,6 +218,8 @@ configuration bits it has and how it is connected to its neighbourhood.</p>""" %
|
|||
bitmap_cells[idx1][idx2]["label"] = "A"
|
||||
elif entry[1].startswith("RamConfig"):
|
||||
bitmap_cells[idx1][idx2]["label"] = "M"
|
||||
elif entry[1].startswith("PLL"):
|
||||
bitmap_cells[idx1][idx2]["label"] = "P"
|
||||
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"])
|
||||
|
|
|
|||
|
|
@ -26,6 +26,15 @@ B8[2] IoCtrl LVDS
|
|||
B6[2] IoCtrl REN_0
|
||||
B1[3] IoCtrl REN_1
|
||||
B9[13],B15[13] NegClk
|
||||
B0[2] PLL pll_cf_bit_1
|
||||
B0[3] PLL pll_cf_bit_2
|
||||
B3[3] PLL pll_cf_bit_3
|
||||
B2[2] PLL pll_cf_bit_4
|
||||
B2[3] PLL pll_cf_bit_5
|
||||
B5[3] PLL pll_cf_bit_6
|
||||
B4[2] PLL pll_cf_bit_7
|
||||
B4[3] PLL pll_cf_bit_8
|
||||
B7[3] PLL pll_cf_bit_9
|
||||
B0[4],!B1[4],!B1[5],!B1[6],B1[7] buffer IO_B.logic_op_tnl_0 lc_trk_g0_0
|
||||
B8[4],!B9[4],!B9[5],!B9[6],B9[7] buffer IO_B.logic_op_tnl_0 lc_trk_g1_0
|
||||
!B0[5],!B0[6],B0[7],B0[8],!B1[8] buffer IO_B.logic_op_tnl_1 lc_trk_g0_1
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
|
||||
CXX = clang
|
||||
# CXX = clang
|
||||
LDLIBS = -lm -lstdc++
|
||||
CXXFLAGS = -MD -O0 -ggdb -Wall -std=c++11
|
||||
|
||||
|
|
@ -12,7 +11,7 @@ iceunpack: icepack
|
|||
|
||||
install: all
|
||||
cp icepack /usr/local/bin/icepack
|
||||
ln -s icepack /usr/local/bin/iceunpack
|
||||
ln -sf icepack /usr/local/bin/iceunpack
|
||||
|
||||
uninstall:
|
||||
rm -f /usr/local/bin/icepack
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ struct FpgaConfig
|
|||
|
||||
// netpbm i/o
|
||||
void write_cram_pbm(std::ostream &ofs, int bank_num = -1) const;
|
||||
void write_bram_pbm(std::ostream &ofs, int bank_num = -1) const;
|
||||
|
||||
// query chip type metadata
|
||||
int chip_width() const;
|
||||
|
|
@ -149,11 +150,23 @@ struct CramIndexConverter
|
|||
void get_cram_index(int bit_x, int bit_y, int &cram_bank, int &cram_x, int &cram_y) const;
|
||||
};
|
||||
|
||||
struct BramIndexConverter
|
||||
{
|
||||
const FpgaConfig *fpga;
|
||||
int tile_x, tile_y;
|
||||
|
||||
int bank_num;
|
||||
int bank_off;
|
||||
|
||||
BramIndexConverter(const FpgaConfig *fpga, int tile_x, int tile_y);
|
||||
void get_bram_index(int bit_x, int bit_y, int &bram_bank, int &bram_x, int &bram_y) const;
|
||||
};
|
||||
|
||||
static void update_crc16(uint16_t &crc, uint8_t byte)
|
||||
{
|
||||
// CRC-16-CCITT, Initialize to 0xFFFF, No zero padding
|
||||
for (int i = 7; i >= 0; i--) {
|
||||
uint16_t xor_value = ((crc >> 15) ^ (byte >> i) & 1) ? 0x1021 : 0;
|
||||
uint16_t xor_value = ((crc >> 15) ^ ((byte >> i) & 1)) ? 0x1021 : 0;
|
||||
crc = (crc << 1) ^ xor_value;
|
||||
}
|
||||
}
|
||||
|
|
@ -450,7 +463,7 @@ void FpgaConfig::write_bits(std::ostream &ofs) const
|
|||
debug("CRAM: Writing bank %d data.\n", cram_bank);
|
||||
write_byte(ofs, crc_value, file_offset, 0x01);
|
||||
write_byte(ofs, crc_value, file_offset, 0x01);
|
||||
for (int i = 0; i < cram_bits.size(); i += 8) {
|
||||
for (int i = 0; i < int(cram_bits.size()); i += 8) {
|
||||
uint8_t byte = 0;
|
||||
for (int j = 0; j < 8; j++)
|
||||
byte = (byte << 1) | (cram_bits[i+j] ? 1 : 0);
|
||||
|
|
@ -494,7 +507,7 @@ void FpgaConfig::write_bits(std::ostream &ofs) const
|
|||
debug("BRAM: Writing bank %d data.\n", bram_bank);
|
||||
write_byte(ofs, crc_value, file_offset, 0x01);
|
||||
write_byte(ofs, crc_value, file_offset, 0x03);
|
||||
for (int i = 0; i < bram_bits.size(); i += 8) {
|
||||
for (int i = 0; i < int(bram_bits.size()); i += 8) {
|
||||
uint8_t byte = 0;
|
||||
for (int j = 0; j < 8; j++)
|
||||
byte = (byte << 1) | (bram_bits[i+j] ? 1 : 0);
|
||||
|
|
@ -571,6 +584,9 @@ void FpgaConfig::read_ascii(std::istream &ifs)
|
|||
|
||||
if (command == ".device")
|
||||
{
|
||||
if (got_device)
|
||||
error("More than one .device statement.\n");
|
||||
|
||||
is >> this->device;
|
||||
|
||||
if (this->device == "1k") {
|
||||
|
|
@ -620,7 +636,7 @@ void FpgaConfig::read_ascii(std::istream &ifs)
|
|||
break;
|
||||
}
|
||||
|
||||
for (int bit_x = 0; bit_x < line.size() && bit_x < cic.tile_width; bit_x++)
|
||||
for (int bit_x = 0; bit_x < int(line.size()) && bit_x < cic.tile_width; bit_x++)
|
||||
if (line[bit_x] == '1') {
|
||||
int cram_bank, cram_x, cram_y;
|
||||
cic.get_cram_index(bit_x, bit_y, cram_bank, cram_x, cram_y);
|
||||
|
|
@ -631,6 +647,47 @@ void FpgaConfig::read_ascii(std::istream &ifs)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (command == ".ram_data")
|
||||
{
|
||||
if (!got_device)
|
||||
error("Missing .device statement before %s.\n", command.c_str());
|
||||
|
||||
int tile_x, tile_y;
|
||||
is >> tile_x >> tile_y;
|
||||
|
||||
BramIndexConverter bic(this, tile_x, tile_y);
|
||||
|
||||
for (int bit_y = 0; bit_y < 16 && getline(ifs, line); bit_y++)
|
||||
{
|
||||
if (line.substr(0, 1) == ".") {
|
||||
reuse_line = true;
|
||||
break;
|
||||
}
|
||||
|
||||
for (int bit_x = 256-4, ch_idx = 0; ch_idx < int(line.size()) && bit_x >= 0; bit_x -= 4, ch_idx++)
|
||||
{
|
||||
int value = -1;
|
||||
if ('0' <= line[ch_idx] && line[ch_idx] <= '9')
|
||||
value = line[ch_idx] - '0';
|
||||
if ('a' <= line[ch_idx] && line[ch_idx] <= 'f')
|
||||
value = line[ch_idx] - 'a' + 10;
|
||||
if ('A' <= line[ch_idx] && line[ch_idx] <= 'F')
|
||||
value = line[ch_idx] - 'A' + 10;
|
||||
if (value < 0)
|
||||
error("Not a hex character: '%c' (in line '%s')\n", line[ch_idx], line.c_str());
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
if ((value & (1 << i)) != 0) {
|
||||
int bram_bank, bram_x, bram_y;
|
||||
bic.get_bram_index(bit_x+i, bit_y, bram_bank, bram_x, bram_y);
|
||||
this->bram[bram_bank][bram_x][bram_y] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (command == ".extra_bit")
|
||||
{
|
||||
if (!got_device)
|
||||
|
|
@ -643,6 +700,9 @@ void FpgaConfig::read_ascii(std::istream &ifs)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (command == ".sym")
|
||||
continue;
|
||||
|
||||
if (command.substr(0, 1) == ".")
|
||||
error("Unknown statement: %s\n", command.c_str());
|
||||
error("Unexpected data line: %s\n", line.c_str());
|
||||
|
|
@ -693,6 +753,26 @@ void FpgaConfig::write_ascii(std::ostream &ofs) const
|
|||
}
|
||||
ofs << '\n';
|
||||
}
|
||||
|
||||
if (cic.tile_type == "ramb")
|
||||
{
|
||||
BramIndexConverter bic(this, x, y);
|
||||
ofs << stringf(".ram_data %d %d\n", x, y);
|
||||
|
||||
for (int bit_y = 0; bit_y < 16; bit_y++) {
|
||||
for (int bit_x = 256-4; bit_x >= 0; bit_x -= 4) {
|
||||
int value = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int bram_bank, bram_x, bram_y;
|
||||
bic.get_bram_index(bit_x+i, bit_y, bram_bank, bram_x, bram_y);
|
||||
if (this->bram[bram_bank][bram_x][bram_y])
|
||||
value += 1 << i;
|
||||
}
|
||||
ofs << "0123456789abcdef"[value];
|
||||
}
|
||||
ofs << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
|
|
@ -717,7 +797,7 @@ void FpgaConfig::write_ascii(std::ostream &ofs) const
|
|||
void FpgaConfig::write_cram_pbm(std::ostream &ofs, int bank_num) const
|
||||
{
|
||||
debug("## %s\n", __PRETTY_FUNCTION__);
|
||||
info("Writing pbm file..\n");
|
||||
info("Writing cram pbm file..\n");
|
||||
|
||||
ofs << "P1\n";
|
||||
ofs << stringf("%d %d\n", 2*this->cram_width, 2*this->cram_height);
|
||||
|
|
@ -737,6 +817,29 @@ void FpgaConfig::write_cram_pbm(std::ostream &ofs, int bank_num) const
|
|||
}
|
||||
}
|
||||
|
||||
void FpgaConfig::write_bram_pbm(std::ostream &ofs, int bank_num) const
|
||||
{
|
||||
debug("## %s\n", __PRETTY_FUNCTION__);
|
||||
info("Writing bram pbm file..\n");
|
||||
|
||||
ofs << "P1\n";
|
||||
ofs << stringf("%d %d\n", 2*this->bram_width, 2*this->bram_height);
|
||||
for (int y = 2*this->bram_height-1; y >= 0; y--) {
|
||||
for (int x = 0; x < 2*this->bram_width; x++) {
|
||||
int bank = 0, bank_x = x, bank_y = y;
|
||||
if (bank_x >= this->bram_width)
|
||||
bank |= 1, bank_x = 2*this->bram_width - bank_x - 1;
|
||||
if (bank_y >= this->bram_height)
|
||||
bank |= 2, bank_y = 2*this->bram_height - bank_y - 1;
|
||||
if (bank_num >= 0 && bank != bank_num)
|
||||
ofs << " 0";
|
||||
else
|
||||
ofs << (this->bram[bank][bank_x][bank_y] ? " 1" : " 0");
|
||||
}
|
||||
ofs << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
int FpgaConfig::chip_width() const
|
||||
{
|
||||
if (this->device == "384") return 6;
|
||||
|
|
@ -901,6 +1004,33 @@ void CramIndexConverter::get_cram_index(int bit_x, int bit_y, int &cram_bank, in
|
|||
}
|
||||
}
|
||||
|
||||
BramIndexConverter::BramIndexConverter(const FpgaConfig *fpga, int tile_x, int tile_y)
|
||||
{
|
||||
this->fpga = fpga;
|
||||
this->tile_x = tile_x;
|
||||
this->tile_y = tile_y;
|
||||
|
||||
auto chip_width = fpga->chip_width();
|
||||
auto chip_height = fpga->chip_height();
|
||||
|
||||
bool right_half = this->tile_x > chip_width / 2;
|
||||
bool top_half = this->tile_y > chip_height / 2;
|
||||
|
||||
this->bank_num = 0;
|
||||
if (top_half) this->bank_num |= 1;
|
||||
if (right_half) this->bank_num |= 2;
|
||||
|
||||
this->bank_off = 16 * ((top_half ? this->tile_y - chip_height / 2 : this->tile_y - 1) / 2);
|
||||
}
|
||||
|
||||
void BramIndexConverter::get_bram_index(int bit_x, int bit_y, int &bram_bank, int &bram_x, int &bram_y) const
|
||||
{
|
||||
int index = 256 * bit_y + (16*(bit_x/16) + 15 - bit_x%16);
|
||||
bram_bank = bank_num;
|
||||
bram_x = bank_off + index % 16;
|
||||
bram_y = index / 16;
|
||||
}
|
||||
|
||||
|
||||
// ==================================================================
|
||||
// Main program
|
||||
|
|
@ -926,6 +1056,9 @@ void usage()
|
|||
log(" write cram bitmap (checkerboard) as netpbm file\n");
|
||||
log(" repeat to flip the selection of tiles\n");
|
||||
log("\n");
|
||||
log(" -r\n");
|
||||
log(" write bram data, not cram, to the netpbm file\n");
|
||||
log("\n");
|
||||
log(" -B0, -B1, -B2, -B3\n");
|
||||
log(" only include the specified bank in the netpbm file\n");
|
||||
log("\n");
|
||||
|
|
@ -937,6 +1070,7 @@ int main(int argc, char **argv)
|
|||
vector<string> parameters;
|
||||
bool unpack_mode = false;
|
||||
bool netpbm_mode = false;
|
||||
bool netpbm_bram = false;
|
||||
bool netpbm_fill_tiles = false;
|
||||
bool netpbm_checkerboard = false;
|
||||
int netpbm_banknum = -1;
|
||||
|
|
@ -951,11 +1085,14 @@ int main(int argc, char **argv)
|
|||
string arg(argv[i]);
|
||||
|
||||
if (arg[0] == '-' && arg.size() > 1) {
|
||||
for (int i = 1; i < arg.size(); i++)
|
||||
for (int i = 1; i < int(arg.size()); i++)
|
||||
if (arg[i] == 'u') {
|
||||
unpack_mode = true;
|
||||
} else if (arg[i] == 'b') {
|
||||
netpbm_mode = true;
|
||||
} else if (arg[i] == 'r') {
|
||||
netpbm_mode = true;
|
||||
netpbm_bram = true;
|
||||
} else if (arg[i] == 'f') {
|
||||
netpbm_mode = true;
|
||||
netpbm_fill_tiles = true;
|
||||
|
|
@ -1023,8 +1160,12 @@ int main(int argc, char **argv)
|
|||
if (netpbm_fill_tiles)
|
||||
fpga_config.cram_fill_tiles();
|
||||
|
||||
if (netpbm_mode)
|
||||
fpga_config.write_cram_pbm(*osp, netpbm_banknum);
|
||||
if (netpbm_mode) {
|
||||
if (netpbm_bram)
|
||||
fpga_config.write_bram_pbm(*osp, netpbm_banknum);
|
||||
else
|
||||
fpga_config.write_cram_pbm(*osp, netpbm_banknum);
|
||||
}
|
||||
|
||||
info("Done.\n");
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
# CC = clang
|
||||
LDLIBS = -lftdi -lm
|
||||
CFLAGS = -MD -O0 -ggdb -Wall -std=c99
|
||||
|
||||
all: iceprog
|
||||
|
||||
iceprog: iceprog.o
|
||||
|
||||
install: all
|
||||
cp iceprog /usr/local/bin/iceprog
|
||||
|
||||
uninstall:
|
||||
rm -f /usr/local/bin/iceprog
|
||||
|
||||
clean:
|
||||
rm -f iceprog
|
||||
rm -f *.o *.d
|
||||
|
||||
-include *.d
|
||||
|
||||
.PHONY: all install uninstall clean
|
||||
|
||||
|
|
@ -0,0 +1,598 @@
|
|||
/*
|
||||
* iceprog -- simple programming tool for FTDI-based Lattice iCE programmers
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Relevant Documents:
|
||||
* -------------------
|
||||
* http://www.latticesemi.com/~/media/Documents/UserManuals/EI/icestickusermanual.pdf
|
||||
* http://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/n25q/n25q_32mb_3v_65nm.pdf
|
||||
* http://www.ftdichip.com/Support/Documents/AppNotes/AN_108_Command_Processor_for_MPSSE_and_MCU_Host_Bus_Emulation_Modes.pdf
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <ftdi.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
struct ftdi_context ftdic;
|
||||
bool ftdic_open = false;
|
||||
bool verbose = false;
|
||||
|
||||
void check_rx()
|
||||
{
|
||||
while (1) {
|
||||
uint8_t data;
|
||||
int rc = ftdi_read_data(&ftdic, &data, 1);
|
||||
if (rc <= 0) break;
|
||||
printf("unexpected rx byte: %02X\n", data);
|
||||
}
|
||||
}
|
||||
|
||||
void error()
|
||||
{
|
||||
check_rx();
|
||||
printf("ABORT.\n");
|
||||
if (ftdic_open)
|
||||
ftdi_usb_close(&ftdic);
|
||||
ftdi_deinit(&ftdic);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uint8_t recv_byte()
|
||||
{
|
||||
uint8_t data;
|
||||
while (1) {
|
||||
int rc = ftdi_read_data(&ftdic, &data, 1);
|
||||
if (rc < 0) {
|
||||
printf("Read error.\n");
|
||||
error();
|
||||
}
|
||||
if (rc == 1)
|
||||
break;
|
||||
usleep(100);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
void send_byte(uint8_t data)
|
||||
{
|
||||
int rc = ftdi_write_data(&ftdic, &data, 1);
|
||||
if (rc != 1) {
|
||||
printf("Write error (single byte, rc=%d, expected %d).\n", rc, 1);
|
||||
error();
|
||||
}
|
||||
}
|
||||
|
||||
void send_spi(uint8_t *data, int n)
|
||||
{
|
||||
if (n < 1)
|
||||
return;
|
||||
|
||||
send_byte(0x11);
|
||||
send_byte(n-1);
|
||||
send_byte((n-1) >> 8);
|
||||
|
||||
int rc = ftdi_write_data(&ftdic, data, n);
|
||||
if (rc != n) {
|
||||
printf("Write error (chunk, rc=%d, expected %d).\n", rc, n);
|
||||
error();
|
||||
}
|
||||
}
|
||||
|
||||
void xfer_spi(uint8_t *data, int n)
|
||||
{
|
||||
if (n < 1)
|
||||
return;
|
||||
|
||||
send_byte(0x31);
|
||||
send_byte(n-1);
|
||||
send_byte((n-1) >> 8);
|
||||
|
||||
int rc = ftdi_write_data(&ftdic, data, n);
|
||||
if (rc != n) {
|
||||
printf("Write error (chunk, rc=%d, expected %d).\n", rc, n);
|
||||
error();
|
||||
}
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
data[i] = recv_byte();
|
||||
}
|
||||
|
||||
void set_gpio(int slavesel_b, int creset_b)
|
||||
{
|
||||
uint8_t gpio = 1;
|
||||
|
||||
if (slavesel_b) {
|
||||
// ADBUS4 (GPIOL0)
|
||||
gpio |= 0x10;
|
||||
}
|
||||
|
||||
if (creset_b) {
|
||||
// ADBUS7 (GPIOL3)
|
||||
gpio |= 0x80;
|
||||
}
|
||||
|
||||
send_byte(0x80);
|
||||
send_byte(gpio);
|
||||
send_byte(0x93);
|
||||
}
|
||||
|
||||
int get_cdone()
|
||||
{
|
||||
uint8_t data;
|
||||
send_byte(0x81);
|
||||
data = recv_byte();
|
||||
// ADBUS6 (GPIOL2)
|
||||
return (data & 0x40) != 0;
|
||||
}
|
||||
|
||||
void flash_read_id()
|
||||
{
|
||||
// printf("read flash ID..\n");
|
||||
|
||||
uint8_t data[21] = { 0x9E };
|
||||
set_gpio(0, 0);
|
||||
xfer_spi(data, 21);
|
||||
set_gpio(1, 0);
|
||||
|
||||
printf("flash ID:");
|
||||
for (int i = 1; i < 21; i++)
|
||||
printf(" 0x%02X", data[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void flash_write_enable()
|
||||
{
|
||||
if (verbose)
|
||||
printf("write enable..\n");
|
||||
|
||||
uint8_t data[1] = { 0x06 };
|
||||
set_gpio(0, 0);
|
||||
xfer_spi(data, 1);
|
||||
set_gpio(1, 0);
|
||||
}
|
||||
|
||||
void flash_bulk_erase()
|
||||
{
|
||||
printf("bulk erase..\n");
|
||||
|
||||
uint8_t data[1] = { 0xc7 };
|
||||
set_gpio(0, 0);
|
||||
xfer_spi(data, 1);
|
||||
set_gpio(1, 0);
|
||||
}
|
||||
|
||||
void flash_sector_erase(int addr)
|
||||
{
|
||||
printf("sector erase 0x%06X..\n", addr);
|
||||
|
||||
uint8_t command[4] = { 0xd8, addr >> 16, addr >> 8, addr };
|
||||
set_gpio(0, 0);
|
||||
send_spi(command, 4);
|
||||
set_gpio(1, 0);
|
||||
}
|
||||
|
||||
void flash_prog(int addr, uint8_t *data, int n)
|
||||
{
|
||||
if (verbose)
|
||||
printf("prog 0x%06X +0x%03X..\n", addr, n);
|
||||
|
||||
uint8_t command[4] = { 0x02, addr >> 16, addr >> 8, addr };
|
||||
set_gpio(0, 0);
|
||||
send_spi(command, 4);
|
||||
send_spi(data, n);
|
||||
set_gpio(1, 0);
|
||||
|
||||
if (verbose)
|
||||
for (int i = 0; i < n; i++)
|
||||
printf("%02x%c", data[i], i == n-1 || i % 32 == 31 ? '\n' : ' ');
|
||||
}
|
||||
|
||||
void flash_read(int addr, uint8_t *data, int n)
|
||||
{
|
||||
if (verbose)
|
||||
printf("read 0x%06X +0x%03X..\n", addr, n);
|
||||
|
||||
uint8_t command[4] = { 0x03, addr >> 16, addr >> 8, addr };
|
||||
set_gpio(0, 0);
|
||||
send_spi(command, 4);
|
||||
memset(data, 0, n);
|
||||
xfer_spi(data, n);
|
||||
set_gpio(1, 0);
|
||||
|
||||
if (verbose)
|
||||
for (int i = 0; i < n; i++)
|
||||
printf("%02x%c", data[i], i == n-1 || i % 32 == 31 ? '\n' : ' ');
|
||||
}
|
||||
|
||||
void flash_wait()
|
||||
{
|
||||
if (verbose)
|
||||
printf("waiting..");
|
||||
|
||||
while (1)
|
||||
{
|
||||
uint8_t data[2] = { 0x05 };
|
||||
|
||||
set_gpio(0, 0);
|
||||
xfer_spi(data, 2);
|
||||
set_gpio(1, 0);
|
||||
|
||||
if ((data[1] & 0x01) == 0)
|
||||
break;
|
||||
|
||||
if (verbose) {
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
}
|
||||
usleep(250000);
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void help(const char *progname)
|
||||
{
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "iceprog -- simple programming tool for FTDI-based Lattice iCE programmers\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Notes for iCEstick (iCE40HX-1k devel board):\n");
|
||||
fprintf(stderr, " An unmodified iCEstick can only be programmed via the serial flash.\n");
|
||||
fprintf(stderr, " Direct programming of the SRAM is not supported. For direct SRAM\n");
|
||||
fprintf(stderr, " programming the flash chip and one zero ohm resistor must be desoldered\n");
|
||||
fprintf(stderr, " and the FT2232H SI pin must be connected to the iCE SPI_SI pin, as shown\n");
|
||||
fprintf(stderr, " in this picture: http://www.clifford.at/gallery/2014-elektronik/IMG_20141115_183838\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Notes for the iCE40-HX8K Breakout Board:\n");
|
||||
fprintf(stderr, " Make sure that the jumper settings on the board match the selected\n");
|
||||
fprintf(stderr, " mode (SRAM or FLASH). See the iCE40-HX8K user manual for details.\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Usage: %s [options] <filename>\n", progname);
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -d <device-string>\n");
|
||||
fprintf(stderr, " use the specified USB device:\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " d:<devicenode> (e.g. d:002/005)\n");
|
||||
fprintf(stderr, " i:<vendor>:<product> (e.g. i:0x0403:0x6010)\n");
|
||||
fprintf(stderr, " i:<vendor>:<product>:<index> (e.g. i:0x0403:0x6010:0)\n");
|
||||
fprintf(stderr, " s:<vendor>:<product>:<serial-string>\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -r\n");
|
||||
fprintf(stderr, " read entire flash (32Mb / 4MB) and write to file\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -R\n");
|
||||
fprintf(stderr, " read first 256 kB from flash and write to file\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -c\n");
|
||||
fprintf(stderr, " do not write flash, only verify (check)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -b\n");
|
||||
fprintf(stderr, " bulk erase entire flash before writing\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -n\n");
|
||||
fprintf(stderr, " do not erase flash before writing\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -S\n");
|
||||
fprintf(stderr, " perform SRAM programming\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -v\n");
|
||||
fprintf(stderr, " verbose output\n");
|
||||
fprintf(stderr, "\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int max_read_size = 4 * 1024 * 1024;
|
||||
bool read_mode = false;
|
||||
bool check_mode = false;
|
||||
bool bulk_erase = false;
|
||||
bool dont_erase = false;
|
||||
bool prog_sram = false;
|
||||
const char *filename = NULL;
|
||||
const char *devstr = NULL;
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "d:rRcbnSv")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'd':
|
||||
devstr = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
read_mode = true;
|
||||
break;
|
||||
case 'R':
|
||||
read_mode = true;
|
||||
max_read_size = 256 * 1024;
|
||||
break;
|
||||
case 'c':
|
||||
check_mode = true;
|
||||
break;
|
||||
case 'b':
|
||||
bulk_erase = true;
|
||||
break;
|
||||
case 'n':
|
||||
dont_erase = true;
|
||||
break;
|
||||
case 'S':
|
||||
prog_sram = true;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
default:
|
||||
help(argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if (read_mode && check_mode)
|
||||
help(argv[0]);
|
||||
|
||||
if (bulk_erase && dont_erase)
|
||||
help(argv[0]);
|
||||
|
||||
if (optind+1 != argc)
|
||||
help(argv[0]);
|
||||
|
||||
filename = argv[optind];
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Initialize USB connection to FT2232H
|
||||
// ---------------------------------------------------------
|
||||
|
||||
printf("init..\n");
|
||||
|
||||
ftdi_init(&ftdic);
|
||||
ftdi_set_interface(&ftdic, INTERFACE_A);
|
||||
|
||||
if (devstr != NULL) {
|
||||
if (ftdi_usb_open_string(&ftdic, devstr)) {
|
||||
printf("Can't find iCE FTDI USB device (device string %s).\n", devstr);
|
||||
error();
|
||||
}
|
||||
} else {
|
||||
if (ftdi_usb_open(&ftdic, 0x0403, 0x6010)) {
|
||||
printf("Can't find iCE FTDI USB device (vedor_id 0x0403, device_id 0x6010).\n");
|
||||
error();
|
||||
}
|
||||
}
|
||||
|
||||
ftdic_open = true;
|
||||
|
||||
if (ftdi_usb_reset(&ftdic)) {
|
||||
printf("Failed to reset iCE FTDI USB device.\n");
|
||||
error();
|
||||
}
|
||||
|
||||
if (ftdi_usb_purge_buffers(&ftdic)) {
|
||||
printf("Failed to purge buffers on iCE FTDI USB device.\n");
|
||||
error();
|
||||
}
|
||||
|
||||
if (ftdi_set_bitmode(&ftdic, 0xff, BITMODE_MPSSE) < 0) {
|
||||
printf("Failed set BITMODE_MPSSE on iCE FTDI USB device.\n");
|
||||
error();
|
||||
}
|
||||
|
||||
// enable clock divide by 5
|
||||
send_byte(0x8b);
|
||||
|
||||
// set 6 MHz clock
|
||||
send_byte(0x86);
|
||||
send_byte(0x00);
|
||||
send_byte(0x00);
|
||||
|
||||
printf("cdone: %s\n", get_cdone() ? "high" : "low");
|
||||
|
||||
set_gpio(1, 1);
|
||||
usleep(100000);
|
||||
|
||||
|
||||
if (prog_sram)
|
||||
{
|
||||
// ---------------------------------------------------------
|
||||
// Reset
|
||||
// ---------------------------------------------------------
|
||||
|
||||
printf("reset..\n");
|
||||
|
||||
set_gpio(0, 0);
|
||||
usleep(100);
|
||||
|
||||
set_gpio(0, 1);
|
||||
usleep(2000);
|
||||
|
||||
printf("cdone: %s\n", get_cdone() ? "high" : "low");
|
||||
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Program
|
||||
// ---------------------------------------------------------
|
||||
|
||||
FILE *f = fopen(filename, "r");
|
||||
if (f == NULL) {
|
||||
fprintf(stderr, "Error: Can't open '%s' for reading: %s\n", filename, strerror(errno));
|
||||
error();
|
||||
}
|
||||
|
||||
printf("programming..\n");
|
||||
while (1)
|
||||
{
|
||||
static unsigned char buffer[4096];
|
||||
int rc = fread(buffer, 1, 4096, f);
|
||||
if (rc <= 0) break;
|
||||
if (verbose)
|
||||
printf("sending %d bytes.\n", rc);
|
||||
send_spi(buffer, rc);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
// add 48 dummy bits
|
||||
send_byte(0x8f);
|
||||
send_byte(0x05);
|
||||
send_byte(0x00);
|
||||
|
||||
// add 1 more dummy bit
|
||||
send_byte(0x8e);
|
||||
send_byte(0x00);
|
||||
|
||||
printf("cdone: %s\n", get_cdone() ? "high" : "low");
|
||||
}
|
||||
else
|
||||
{
|
||||
// ---------------------------------------------------------
|
||||
// Reset
|
||||
// ---------------------------------------------------------
|
||||
|
||||
printf("reset..\n");
|
||||
|
||||
set_gpio(1, 0);
|
||||
usleep(250000);
|
||||
|
||||
printf("cdone: %s\n", get_cdone() ? "high" : "low");
|
||||
|
||||
flash_read_id();
|
||||
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Program
|
||||
// ---------------------------------------------------------
|
||||
|
||||
if (!read_mode && !check_mode)
|
||||
{
|
||||
FILE *f = fopen(filename, "r");
|
||||
if (f == NULL) {
|
||||
fprintf(stderr, "Error: Can't open '%s' for reading: %s\n", filename, strerror(errno));
|
||||
error();
|
||||
}
|
||||
|
||||
if (!dont_erase)
|
||||
{
|
||||
if (bulk_erase)
|
||||
{
|
||||
flash_write_enable();
|
||||
flash_bulk_erase();
|
||||
flash_wait();
|
||||
}
|
||||
else
|
||||
{
|
||||
fseek(f, SEEK_END, 0);
|
||||
int file_size = ftell(f);
|
||||
rewind(f);
|
||||
|
||||
for (int addr = 0; addr < file_size; addr += 0x1000) {
|
||||
flash_write_enable();
|
||||
flash_sector_erase(addr);
|
||||
flash_wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("programming..\n");
|
||||
for (int addr = 0; true; addr += 256) {
|
||||
uint8_t buffer[256];
|
||||
int rc = fread(buffer, 1, 256, f);
|
||||
if (rc <= 0) break;
|
||||
flash_write_enable();
|
||||
flash_prog(addr, buffer, rc);
|
||||
flash_wait();
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Read/Verify
|
||||
// ---------------------------------------------------------
|
||||
|
||||
if (read_mode)
|
||||
{
|
||||
FILE *f = fopen(filename, "w");
|
||||
if (f == NULL) {
|
||||
fprintf(stderr, "Error: Can't open '%s' for writing: %s\n", filename, strerror(errno));
|
||||
error();
|
||||
}
|
||||
|
||||
printf("reading..\n");
|
||||
for (int addr = 0; addr < max_read_size; addr += 256) {
|
||||
uint8_t buffer[256];
|
||||
flash_read(addr, buffer, 256);
|
||||
fwrite(buffer, 256, 1, f);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
FILE *f = fopen(filename, "r");
|
||||
if (f == NULL) {
|
||||
fprintf(stderr, "Error: Can't open '%s' for reading: %s\n", filename, strerror(errno));
|
||||
error();
|
||||
}
|
||||
|
||||
printf("reading..\n");
|
||||
for (int addr = 0; true; addr += 256) {
|
||||
uint8_t buffer_flash[256], buffer_file[256];
|
||||
int rc = fread(buffer_file, 1, 256, f);
|
||||
if (rc <= 0) break;
|
||||
flash_read(addr, buffer_flash, 256);
|
||||
if (memcmp(buffer_file, buffer_flash, rc)) {
|
||||
fprintf(stderr, "Found difference between flash and file!\n");
|
||||
error();
|
||||
}
|
||||
}
|
||||
|
||||
printf("VERIFY OK\n");
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Reset
|
||||
// ---------------------------------------------------------
|
||||
|
||||
set_gpio(1, 1);
|
||||
usleep(250000);
|
||||
|
||||
printf("cdone: %s\n", get_cdone() ? "high" : "low");
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Exit
|
||||
// ---------------------------------------------------------
|
||||
|
||||
printf("Bye.\n");
|
||||
ftdi_disable_bitbang(&ftdic);
|
||||
ftdi_usb_close(&ftdic);
|
||||
ftdi_deinit(&ftdic);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue