diff options
-rw-r--r-- | Makefile | 18 | ||||
-rw-r--r-- | icebox/Makefile | 12 | ||||
-rw-r--r-- | icebox/icebox.py | 98 | ||||
-rwxr-xr-x | icebox/icebox_chipdb.py | 113 | ||||
-rwxr-xr-x | icebox/icebox_diff.py | 15 | ||||
-rwxr-xr-x | icebox/icebox_html.py | 2 | ||||
-rw-r--r-- | icebox/iceboxdb.py | 9 | ||||
-rw-r--r-- | icepack/Makefile | 5 | ||||
-rw-r--r-- | icepack/icepack.cc | 159 | ||||
-rw-r--r-- | iceprog/Makefile | 22 | ||||
-rw-r--r-- | iceprog/iceprog.c | 598 |
11 files changed, 1015 insertions, 36 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a070dc3 --- /dev/null +++ b/Makefile @@ -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 + diff --git a/icebox/Makefile b/icebox/Makefile index 3f74e18..64549b3 100644 --- a/icebox/Makefile +++ b/icebox/Makefile @@ -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 diff --git a/icebox/icebox.py b/icebox/icebox.py index 60b5dc2..cad6831 100644 --- a/icebox/icebox.py +++ b/icebox/icebox.py @@ -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), diff --git a/icebox/icebox_chipdb.py b/icebox/icebox_chipdb.py index 12ccfa8..c673f54 100755 --- a/icebox/icebox_chipdb.py +++ b/icebox/icebox_chipdb.py @@ -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) diff --git a/icebox/icebox_diff.py b/icebox/icebox_diff.py index da7962b..59fa0a8 100755 --- a/icebox/icebox_diff.py +++ b/icebox/icebox_diff.py @@ -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) diff --git a/icebox/icebox_html.py b/icebox/icebox_html.py index 880714f..d3779ab 100755 --- a/icebox/icebox_html.py +++ b/icebox/icebox_html.py @@ -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"]) diff --git a/icebox/iceboxdb.py b/icebox/iceboxdb.py index 2159b8d..52aa3d0 100644 --- a/icebox/iceboxdb.py +++ b/icebox/iceboxdb.py @@ -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 diff --git a/icepack/Makefile b/icepack/Makefile index 75f81e7..469e34a 100644 --- a/icepack/Makefile +++ b/icepack/Makefile @@ -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 diff --git a/icepack/icepack.cc b/icepack/icepack.cc index f243e15..85531b1 100644 --- a/icepack/icepack.cc +++ b/icepack/icepack.cc @@ -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) @@ -642,7 +699,10 @@ 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; diff --git a/iceprog/Makefile b/iceprog/Makefile new file mode 100644 index 0000000..b0d735a --- /dev/null +++ b/iceprog/Makefile @@ -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 + diff --git a/iceprog/iceprog.c b/iceprog/iceprog.c new file mode 100644 index 0000000..5d03dc9 --- /dev/null +++ b/iceprog/iceprog.c @@ -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; +} + |