aboutsummaryrefslogtreecommitdiffstats
path: root/icepack
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2015-07-18 13:05:51 +0200
committerClifford Wolf <clifford@clifford.at>2015-07-18 13:05:51 +0200
commit0347c37d56374447d170e9a8f59e56f84cbefcce (patch)
treeada78ec11a4c109168dca3cc7aff1af2c3cda093 /icepack
parentdfeb92a46b2228b4f3886a9c06502ccd0dde5562 (diff)
downloadicestorm-0347c37d56374447d170e9a8f59e56f84cbefcce.tar.gz
icestorm-0347c37d56374447d170e9a8f59e56f84cbefcce.tar.bz2
icestorm-0347c37d56374447d170e9a8f59e56f84cbefcce.zip
Import of icestorm-snapshot-150401.zip
Diffstat (limited to 'icepack')
-rw-r--r--icepack/Makefile20
-rw-r--r--icepack/icepack.cc1031
-rw-r--r--icepack/iceunpack.c368
3 files changed, 1043 insertions, 376 deletions
diff --git a/icepack/Makefile b/icepack/Makefile
index 06aeaeb..75f81e7 100644
--- a/icepack/Makefile
+++ b/icepack/Makefile
@@ -1,25 +1,29 @@
-CC = clang
CXX = clang
-LDFLAGS = -lm -lstdc++
-CFLAGS = -MD -Os -Wall -std=c99
-CXXFLAGS = -MD -Os -Wall -std=c99
+LDLIBS = -lm -lstdc++
+CXXFLAGS = -MD -O0 -ggdb -Wall -std=c++11
-all: iceunpack
+all: icepack iceunpack
-iceunpack: iceunpack.o
+icepack: icepack.o
+
+iceunpack: icepack
+ ln -sf icepack iceunpack
install: all
- cp iceunpack /usr/local/bin/iceunpack
+ cp icepack /usr/local/bin/icepack
+ ln -s icepack /usr/local/bin/iceunpack
uninstall:
+ rm -f /usr/local/bin/icepack
rm -f /usr/local/bin/iceunpack
clean:
+ rm -f icepack
rm -f iceunpack
rm -f *.o *.d
-include *.d
-.PHONY: install uninstall clean
+.PHONY: all install uninstall clean
diff --git a/icepack/icepack.cc b/icepack/icepack.cc
new file mode 100644
index 0000000..1614c5e
--- /dev/null
+++ b/icepack/icepack.cc
@@ -0,0 +1,1031 @@
+//
+// Copyright (C) 2015 Clifford Wolf <clifford@clifford.at>
+//
+// Based on a reference implementation provided by Mathias Lasser
+//
+// 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.
+//
+
+#include <set>
+#include <tuple>
+#include <vector>
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <cstdint>
+
+#include <stdio.h>
+#include <stdarg.h>
+
+using std::vector;
+using std::string;
+
+int log_level = 0;
+#define log(...) fprintf(stderr, __VA_ARGS__);
+#define info(...) do { if (log_level > 0) fprintf(stderr, __VA_ARGS__); } while (0)
+#define debug(...) do { if (log_level > 1) fprintf(stderr, __VA_ARGS__); } while (0)
+#define error(...) do { fprintf(stderr, "Error: " __VA_ARGS__); exit(1); } while (0)
+#define panic(fmt, ...) do { fprintf(stderr, "Internal Error at %s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__); abort(); } while (0)
+
+string vstringf(const char *fmt, va_list ap)
+{
+ string string;
+ char *str = NULL;
+
+#ifdef _WIN32
+ int sz = 64, rc;
+ while (1) {
+ va_list apc;
+ va_copy(apc, ap);
+ str = (char*)realloc(str, sz);
+ rc = vsnprintf(str, sz, fmt, apc);
+ va_end(apc);
+ if (rc >= 0 && rc < sz)
+ break;
+ sz *= 2;
+ }
+#else
+ if (vasprintf(&str, fmt, ap) < 0)
+ str = NULL;
+#endif
+
+ if (str != NULL) {
+ string = str;
+ free(str);
+ }
+
+ return string;
+}
+
+string stringf(const char *fmt, ...)
+{
+ string string;
+ va_list ap;
+
+ va_start(ap, fmt);
+ string = vstringf(fmt, ap);
+ va_end(ap);
+
+ return string;
+}
+
+// ==================================================================
+// FpgaConfig stuff
+
+struct FpgaConfig
+{
+ string device;
+ string freqrange;
+ string warmboot;
+
+ // cram[BANK][X][Y]
+ int cram_width, cram_height;
+ vector<vector<vector<bool>>> cram;
+
+ // bram[BANK][X][Y]
+ int bram_width, bram_height;
+ vector<vector<vector<bool>>> bram;
+
+ // data before preamble
+ vector<uint8_t> initblop;
+
+ // bitstream i/o
+ void read_bits(std::istream &ifs);
+ void write_bits(std::ostream &ofs) const;
+
+ // icebox i/o
+ void read_ascii(std::istream &ifs);
+ void write_ascii(std::ostream &ofs) const;
+
+ // netpbm i/o
+ void write_cram_pbm(std::ostream &ofs, int bank_num = -1) const;
+
+ // query chip type metadata
+ int chip_width() const;
+ int chip_height() const;
+ vector<int> chip_cols() const;
+
+ // query tile metadata
+ string tile_type(int x, int y) const;
+ int tile_width(const string &type) const;
+
+ // cram bit manipulation
+ void cram_clear();
+ void cram_fill_tiles();
+ void cram_checkerboard(int m = 0);
+};
+
+struct CramIndexConverter
+{
+ const FpgaConfig *fpga;
+ int tile_x, tile_y;
+
+ string tile_type;
+ int tile_width;
+ int column_width;
+
+ bool left_right_io;
+ bool right_half;
+ bool top_half;
+
+ int bank_num;
+ int bank_tx;
+ int bank_ty;
+ int bank_xoff;
+ int bank_yoff;
+
+ CramIndexConverter(const FpgaConfig *fpga, int tile_x, int tile_y);
+ void get_cram_index(int bit_x, int bit_y, int &cram_bank, int &cram_x, int &cram_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;
+ crc = (crc << 1) ^ xor_value;
+ }
+}
+
+static uint8_t read_byte(std::istream &ifs, uint16_t &crc_value, int &file_offset)
+{
+ int byte = ifs.get();
+
+ if (byte < 0)
+ error("Unexpected end of file.\n");
+
+ file_offset++;
+ update_crc16(crc_value, byte);
+
+ return byte;
+}
+
+static void write_byte(std::ostream &ofs, uint16_t &crc_value, int &file_offset, uint8_t byte)
+{
+ ofs << byte;
+ file_offset++;
+ update_crc16(crc_value, byte);
+}
+
+void FpgaConfig::read_bits(std::istream &ifs)
+{
+ int file_offset = 0;
+ uint16_t crc_value = 0;
+
+ debug("## %s\n", __PRETTY_FUNCTION__);
+ info("Parsing bitstream file..\n");
+
+ // skip initial comments until preamble is found
+
+ uint32_t preamble = 0;
+
+ while (1)
+ {
+ uint8_t byte = read_byte(ifs, crc_value, file_offset);
+ preamble = (preamble << 8) | byte;
+ if (preamble == 0xffffffff)
+ error("No preamble found in bitstream.\n");
+ if (preamble == 0x7EAA997E) {
+ info("Found preamble at offset %d.\n", file_offset-4);
+ break;
+ }
+ initblop.push_back(byte);
+ }
+
+ initblop.pop_back();
+ initblop.pop_back();
+ initblop.pop_back();
+
+ // main parser loop
+
+ int current_bank = 0;
+ int current_width = 0;
+ int current_height = 0;
+ int current_offset = 0;
+ bool wakeup = false;
+
+ this->cram_width = 0;
+ this->cram_height = 0;
+
+ this->bram_width = 0;
+ this->bram_height = 0;
+
+ while (!wakeup)
+ {
+ // one command byte. the lower 4 bits of the command byte specify
+ // the length of the command payload.
+
+ uint8_t command = read_byte(ifs, crc_value, file_offset);
+ uint32_t payload = 0;
+
+ for (int i = 0; i < (command & 0x0f); i++)
+ payload = (payload << 8) | read_byte(ifs, crc_value, file_offset);
+
+ debug("Next command at offset %d: 0x%02x 0x%0*x\n", file_offset - 1 - (command & 0x0f),
+ command, 2*(command & 0x0f), payload);
+
+ uint16_t end_token;
+
+ switch (command & 0xf0)
+ {
+ case 0x00:
+ switch (payload)
+ {
+ case 0x01:
+ info("CRAM Data [%d]: %d x %d bits = %d bits = %d bytes\n",
+ current_bank, current_width, current_height,
+ current_height*current_width, (current_height*current_width)/8);
+
+ this->cram_width = std::max(this->cram_width, current_width);
+ this->cram_height = std::max(this->cram_height, current_offset + current_height);
+
+ this->cram.resize(4);
+ this->cram[current_bank].resize(this->cram_width);
+ for (int x = 0; x < current_width; x++)
+ this->cram[current_bank][x].resize(this->cram_height);
+
+ for (int i = 0; i < (current_height*current_width)/8; i++) {
+ uint8_t byte = read_byte(ifs, crc_value, file_offset);
+ for (int j = 0; j < 8; j++) {
+ int x = (i*8 + j) % current_width;
+ int y = (i*8 + j) / current_width + current_offset;
+ this->cram[current_bank][x][y] = ((byte << j) & 0x80) != 0;
+ }
+ }
+
+ end_token = read_byte(ifs, crc_value, file_offset);
+ end_token = (end_token << 8) | read_byte(ifs, crc_value, file_offset);
+ if (end_token)
+ error("Expeded 0x0000 after CRAM data, got 0x%04x\n", end_token);
+ break;
+
+ case 0x03:
+ info("BRAM Data [%d]: %d x %d bits = %d bits = %d bytes\n",
+ current_bank, current_width, current_height,
+ current_height*current_width, (current_height*current_width)/8);
+
+ this->bram_width = std::max(this->bram_width, current_width);
+ this->bram_height = std::max(this->bram_height, current_offset + current_height);
+
+ this->bram.resize(4);
+ this->bram[current_bank].resize(this->bram_width);
+ for (int x = 0; x < current_width; x++)
+ this->bram[current_bank][x].resize(this->bram_height);
+
+ for (int i = 0; i < (current_height*current_width)/8; i++) {
+ uint8_t byte = read_byte(ifs, crc_value, file_offset);
+ for (int j = 0; j < 8; j++) {
+ int x = (i*8 + j) % current_width;
+ int y = (i*8 + j) / current_width + current_offset;
+ this->bram[current_bank][x][y] = ((byte << j) & 0x80) != 0;
+ }
+ }
+
+ end_token = read_byte(ifs, crc_value, file_offset);
+ end_token = (end_token << 8) | read_byte(ifs, crc_value, file_offset);
+ if (end_token)
+ error("Expeded 0x0000 after BRAM data, got 0x%04x\n", end_token);
+ break;
+
+ case 0x05:
+ debug("Resetting CRC.\n");
+ crc_value = 0xffff;
+ break;
+
+ case 0x06:
+ info("Wakeup.\n");
+ wakeup = true;
+ break;
+
+ default:
+ error("Unkown command: 0x%02x 0x%02x\n", command, payload);
+ }
+ break;
+
+ case 0x10:
+ current_bank = payload;
+ debug("Set bank to %d.\n", current_bank);
+ break;
+
+ case 0x20:
+ if (crc_value != 0)
+ error("CRC Check FAILED.\n");
+ info("CRC Check OK.\n");
+ break;
+
+ case 0x50:
+ if (payload == 0)
+ this->freqrange = "low";
+ else if (payload == 1)
+ this->freqrange = "medium";
+ else if (payload == 2)
+ this->freqrange = "high";
+ else
+ error("Unknown freqrange payload 0x%02x\n", payload);
+ info("Setting freqrange to '%s'.\n", this->freqrange.c_str());
+ break;
+
+ case 0x60:
+ current_width = payload + 1;
+ debug("Setting bank width to %d.\n", current_width);
+ break;
+
+ case 0x70:
+ current_height = payload;
+ debug("Setting bank height to %d.\n", current_height);
+ break;
+
+ case 0x80:
+ current_offset = payload;
+ debug("Setting bank offset to %d.\n", current_offset);
+ break;
+
+ case 0x90:
+ if (payload == 0)
+ this->warmboot = "disabled";
+ else if (payload == 32)
+ this->warmboot = "enabled";
+ else
+ error("Unknown warmboot payload 0x%02x\n", payload);
+ info("Setting warmboot to '%s'.\n", this->warmboot.c_str());
+ break;
+
+ default:
+ error("Unkown command: 0x%02x 0x%02x\n", command, payload);
+ }
+ }
+
+ if (this->cram_width == 182 && this->cram_height == 80)
+ this->device = "384";
+ else if (this->cram_width == 332 && this->cram_height == 144)
+ this->device = "1k";
+ else if (this->cram_width == 872 && this->cram_height == 272)
+ this->device = "4k8k";
+ else
+ error("Failed to detect chip type.\n");
+
+ info("Chip type is '%s'.\n", this->device.c_str());
+}
+
+void FpgaConfig::write_bits(std::ostream &ofs) const
+{
+ int file_offset = 0;
+ uint16_t crc_value = 0;
+
+ debug("## %s\n", __PRETTY_FUNCTION__);
+ info("Writing bitstream file..\n");
+
+ for (auto byte : this->initblop)
+ ofs << byte;
+
+ debug("Writing preamble.\n");
+ write_byte(ofs, crc_value, file_offset, 0x7E);
+ write_byte(ofs, crc_value, file_offset, 0xAA);
+ write_byte(ofs, crc_value, file_offset, 0x99);
+ write_byte(ofs, crc_value, file_offset, 0x7E);
+
+ debug("Setting freqrange to '%s'.\n", this->freqrange.c_str());
+ write_byte(ofs, crc_value, file_offset, 0x51);
+ if (this->freqrange == "low")
+ write_byte(ofs, crc_value, file_offset, 0x00);
+ else if (this->freqrange == "medium")
+ write_byte(ofs, crc_value, file_offset, 0x01);
+ else if (this->freqrange == "high")
+ write_byte(ofs, crc_value, file_offset, 0x02);
+ else
+ error("Unknown freqrange '%s'.\n", this->freqrange.c_str());
+
+ debug("Resetting CRC.\n");
+ write_byte(ofs, crc_value, file_offset, 0x01);
+ write_byte(ofs, crc_value, file_offset, 0x05);
+ crc_value = 0xffff;
+
+ debug("Setting warmboot to '%s'.\n", this->warmboot.c_str());
+ write_byte(ofs, crc_value, file_offset, 0x92);
+ write_byte(ofs, crc_value, file_offset, 0x00);
+ if (this->warmboot == "disabled")
+ write_byte(ofs, crc_value, file_offset, 0x00);
+ else if (this->warmboot == "enabled")
+ write_byte(ofs, crc_value, file_offset, 0x20);
+ else
+ error("Unknown warmboot setting '%s'.\n", this->warmboot.c_str());
+
+ debug("CRAM: Setting bank width to %d.\n", this->cram_width);
+ write_byte(ofs, crc_value, file_offset, 0x62);
+ write_byte(ofs, crc_value, file_offset, (this->cram_width-1) >> 8);
+ write_byte(ofs, crc_value, file_offset, (this->cram_width-1));
+
+ debug("CRAM: Setting bank height to %d.\n", this->cram_height);
+ write_byte(ofs, crc_value, file_offset, 0x72);
+ write_byte(ofs, crc_value, file_offset, this->cram_height >> 8);
+ write_byte(ofs, crc_value, file_offset, this->cram_height);
+
+ debug("CRAM: Setting bank offset to 0.\n");
+ write_byte(ofs, crc_value, file_offset, 0x82);
+ write_byte(ofs, crc_value, file_offset, 0x00);
+ write_byte(ofs, crc_value, file_offset, 0x00);
+
+ for (int cram_bank = 0; cram_bank < 4; cram_bank++)
+ {
+ vector<bool> cram_bits;
+ for (int cram_y = 0; cram_y < this->cram_height; cram_y++)
+ for (int cram_x = 0; cram_x < this->cram_width; cram_x++)
+ cram_bits.push_back(this->cram[cram_bank][cram_x][cram_y]);
+
+ debug("CRAM: Setting bank %d.\n", cram_bank);
+ write_byte(ofs, crc_value, file_offset, 0x11);
+ write_byte(ofs, crc_value, file_offset, cram_bank);
+
+ 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) {
+ uint8_t byte = 0;
+ for (int j = 0; j < 8; j++)
+ byte = (byte << 1) | (cram_bits[i+j] ? 1 : 0);
+ write_byte(ofs, crc_value, file_offset, byte);
+ }
+
+ write_byte(ofs, crc_value, file_offset, 0x00);
+ write_byte(ofs, crc_value, file_offset, 0x00);
+ }
+
+ int bram_chunk_size = 128;
+
+ debug("BRAM: Setting bank width to %d.\n", this->bram_width);
+ write_byte(ofs, crc_value, file_offset, 0x62);
+ write_byte(ofs, crc_value, file_offset, (this->bram_width-1) >> 8);
+ write_byte(ofs, crc_value, file_offset, (this->bram_width-1));
+
+ debug("BRAM: Setting bank height to %d.\n", this->bram_height);
+ write_byte(ofs, crc_value, file_offset, 0x72);
+ write_byte(ofs, crc_value, file_offset, bram_chunk_size >> 8);
+ write_byte(ofs, crc_value, file_offset, bram_chunk_size);
+
+ for (int bram_bank = 0; bram_bank < 4; bram_bank++)
+ {
+ debug("BRAM: Setting bank %d.\n", bram_bank);
+ write_byte(ofs, crc_value, file_offset, 0x11);
+ write_byte(ofs, crc_value, file_offset, bram_bank);
+
+ for (int offset = 0; offset < this->bram_height; offset += bram_chunk_size)
+ {
+ vector<bool> bram_bits;
+ for (int bram_y = 0; bram_y < bram_chunk_size; bram_y++)
+ for (int bram_x = 0; bram_x < this->bram_width; bram_x++)
+ bram_bits.push_back(this->bram[bram_bank][bram_x][bram_y+offset]);
+
+ debug("BRAM: Setting bank offset to %d.\n", offset);
+ write_byte(ofs, crc_value, file_offset, 0x82);
+ write_byte(ofs, crc_value, file_offset, offset >> 8);
+ write_byte(ofs, crc_value, file_offset, offset);
+
+ 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) {
+ uint8_t byte = 0;
+ for (int j = 0; j < 8; j++)
+ byte = (byte << 1) | (bram_bits[i+j] ? 1 : 0);
+ write_byte(ofs, crc_value, file_offset, byte);
+ }
+
+ write_byte(ofs, crc_value, file_offset, 0x00);
+ write_byte(ofs, crc_value, file_offset, 0x00);
+ }
+ }
+
+ debug("Writing CRC value.\n");
+ write_byte(ofs, crc_value, file_offset, 0x22);
+ uint8_t crc_hi = crc_value >> 8, crc_lo = crc_value;
+ write_byte(ofs, crc_value, file_offset, crc_hi);
+ write_byte(ofs, crc_value, file_offset, crc_lo);
+
+ debug("Wakeup.\n");
+ write_byte(ofs, crc_value, file_offset, 0x01);
+ write_byte(ofs, crc_value, file_offset, 0x06);
+
+ debug("Padding byte.\n");
+ write_byte(ofs, crc_value, file_offset, 0x00);
+}
+
+void FpgaConfig::read_ascii(std::istream &ifs)
+{
+ debug("## %s\n", __PRETTY_FUNCTION__);
+ info("Parsing ascii file..\n");
+
+ bool got_device = false;
+ this->cram.clear();
+ this->bram.clear();
+ this->freqrange = "low";
+ this->warmboot = "enabled";
+
+ bool reuse_line = true;
+ string line, command;
+
+ while (reuse_line || getline(ifs, line))
+ {
+ reuse_line = false;
+
+ std::istringstream is(line);
+ is >> command;
+
+ if (command.empty())
+ continue;
+
+ debug("Next command: %s\n", line.c_str());
+
+ if (command == ".comment")
+ {
+ this->initblop.clear();
+ this->initblop.push_back(0xff);
+ this->initblop.push_back(0x00);
+
+ while (getline(ifs, line))
+ {
+ if (line.substr(0, 1) == ".") {
+ reuse_line = true;
+ break;
+ }
+
+ for (auto ch : line)
+ this->initblop.push_back(ch);
+ this->initblop.push_back(0);
+ }
+
+ this->initblop.push_back(0x00);
+ this->initblop.push_back(0xff);
+ continue;
+ }
+
+ if (command == ".device")
+ {
+ is >> this->device;
+
+ if (this->device == "1k") {
+ this->cram_width = 332;
+ this->cram_height = 144;
+ this->bram_width = 64;
+ this->bram_height = 2 * 128;
+ } else
+ error("Unsupported chip type '%s'.\n", this->device.c_str());
+
+ this->cram.resize(4);
+ for (int i = 0; i < 4; i++) {
+ this->cram[i].resize(this->cram_width);
+ for (int x = 0; x < this->cram_width; x++)
+ this->cram[i][x].resize(this->cram_height);
+ }
+
+ this->bram.resize(4);
+ for (int i = 0; i < 4; i++) {
+ this->bram[i].resize(this->bram_width);
+ for (int x = 0; x < this->bram_width; x++)
+ this->bram[i][x].resize(this->bram_height);
+ }
+
+ got_device = true;
+ continue;
+ }
+
+ if (command == ".io_tile" || command == ".logic_tile" || command == ".ram_tile")
+ {
+ if (!got_device)
+ error("Missing .device statement before %s.\n", command.c_str());
+
+ int tile_x, tile_y;
+ is >> tile_x >> tile_y;
+
+ CramIndexConverter cic(this, tile_x, tile_y);
+
+ if (("." + cic.tile_type + "_tile") != command)
+ error("Got %s statement for %s tile %d %d.\n",
+ command.c_str(), cic.tile_type.c_str(), 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 = 0; bit_x < 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);
+ this->cram[cram_bank][cram_x][cram_y] = true;
+ }
+ }
+
+ continue;
+ }
+
+ if (command == ".extra_bit")
+ {
+ if (!got_device)
+ error("Missing .device statement before %s.\n", command.c_str());
+
+ int cram_bank, cram_x, cram_y;
+ is >> cram_bank >> cram_x >> cram_y;
+ this->cram[cram_bank][cram_x][cram_y] = true;
+
+ continue;
+ }
+
+ if (command.substr(0, 1) == ".")
+ error("Unknown statement: %s\n", command.c_str());
+ error("Unexpected data line: %s\n", line.c_str());
+ }
+}
+
+void FpgaConfig::write_ascii(std::ostream &ofs) const
+{
+ debug("## %s\n", __PRETTY_FUNCTION__);
+ info("Writing ascii file..\n");
+
+ ofs << ".comment";
+ bool insert_newline = true;
+ for (auto ch : this->initblop) {
+ if (ch == 0) {
+ insert_newline = true;
+ } else if (ch == 0xff) {
+ insert_newline = false;
+ } else {
+ if (insert_newline)
+ ofs << '\n';
+ ofs << ch;
+ insert_newline = false;
+ }
+ }
+
+ ofs << stringf("\n.device %s\n", this->device.c_str());
+
+ typedef std::tuple<int, int, int> tile_bit_t;
+ std::set<tile_bit_t> tile_bits;
+
+ for (int y = 0; y <= this->chip_height()+1; y++)
+ for (int x = 0; x <= this->chip_width()+1; x++)
+ {
+ CramIndexConverter cic(this, x, y);
+
+ if (cic.tile_type == "corner")
+ continue;
+
+ ofs << stringf(".%s_tile %d %d\n", cic.tile_type.c_str(), x, y);
+
+ for (int bit_y = 0; bit_y < 16; bit_y++) {
+ for (int bit_x = 0; bit_x < cic.tile_width; bit_x++) {
+ int cram_bank, cram_x, cram_y;
+ cic.get_cram_index(bit_x, bit_y, cram_bank, cram_x, cram_y);
+ tile_bits.insert(tile_bit_t(cram_bank, cram_x, cram_y));
+ ofs << (this->cram[cram_bank][cram_x][cram_y] ? '1' : '0');
+ }
+ ofs << '\n';
+ }
+ }
+
+ for (int i = 0; i < 4; i++)
+ for (int x = 0; x < this->cram_width; x++)
+ for (int y = 0; y < this->cram_height; y++)
+ if (this->cram[i][x][y] && tile_bits.count(tile_bit_t(i, x, y)) == 0)
+ ofs << stringf(".extra_bit %d %d %d\n", i, x, y);
+
+#if 0
+ for (int i = 0; i < 4; i++) {
+ ofs << stringf(".bram_bank %d\n", i);
+ for (int x = 0; x < this->bram_width; x++) {
+ for (int y = 0; y < this->bram_height; y += 4)
+ ofs << "0123456789abcdef"[(this->bram[i][x][y] ? 1 : 0) + (this->bram[i][x][y+1] ? 2 : 0) +
+ (this->bram[i][x][y+2] ? 4 : 0) + (this->bram[i][x][y+3] ? 8 : 0)];
+ ofs << '\n';
+ }
+ }
+#endif
+}
+
+void FpgaConfig::write_cram_pbm(std::ostream &ofs, int bank_num) const
+{
+ debug("## %s\n", __PRETTY_FUNCTION__);
+ info("Writing pbm file..\n");
+
+ ofs << "P1\n";
+ ofs << stringf("%d %d\n", 2*this->cram_width, 2*this->cram_height);
+ for (int y = 2*this->cram_height-1; y >= 0; y--) {
+ for (int x = 0; x < 2*this->cram_width; x++) {
+ int bank = 0, bank_x = x, bank_y = y;
+ if (bank_x >= this->cram_width)
+ bank |= 1, bank_x = 2*this->cram_width - bank_x - 1;
+ if (bank_y >= this->cram_height)
+ bank |= 2, bank_y = 2*this->cram_height - bank_y - 1;
+ if (bank_num >= 0 && bank != bank_num)
+ ofs << " 0";
+ else
+ ofs << (this->cram[bank][bank_x][bank_y] ? " 1" : " 0");
+ }
+ ofs << '\n';
+ }
+}
+
+int FpgaConfig::chip_width() const
+{
+ if (this->device == "384") return 6;
+ if (this->device == "1k") return 12;
+ if (this->device == "4k8k") return 32;
+ panic("Unkown chip type '%s'.\n", this->device.c_str());
+}
+
+int FpgaConfig::chip_height() const
+{
+ if (this->device == "384") return 8;
+ if (this->device == "1k") return 16;
+ if (this->device == "4k8k") return 32;
+ panic("Unkown chip type '%s'.\n", this->device.c_str());
+}
+
+vector<int> FpgaConfig::chip_cols() const
+{
+ if (this->device == "384") return vector<int>({18, 54, 54, 54});
+ if (this->device == "1k") return vector<int>({18, 54, 54, 42, 54, 54, 54});
+ if (this->device == "4k8k") return vector<int>({18, 2, 54, 54, 54, 54, 54, 54, 54, 42, 54, 54, 54, 54, 54, 54, 54, 54});
+ panic("Unkown chip type '%s'.\n", this->device.c_str());
+}
+
+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";
+ return "logic";
+ }
+ panic("Unkown chip type '%s'.\n", this->device.c_str());
+}
+
+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 == "io") return 18;
+ panic("Unkown tile type '%s'.\n", type.c_str());
+}
+
+void FpgaConfig::cram_clear()
+{
+ for (int i = 0; i < 4; i++)
+ for (int x = 0; x < this->cram_width; x++)
+ for (int y = 0; y < this->cram_height; y++)
+ this->cram[i][x][y] = false;
+}
+
+void FpgaConfig::cram_fill_tiles()
+{
+ for (int y = 0; y <= this->chip_height()+1; y++)
+ for (int x = 0; x <= this->chip_width()+1; x++)
+ {
+ CramIndexConverter cic(this, x, y);
+
+ for (int bit_y = 0; bit_y < 16; bit_y++)
+ for (int bit_x = 0; bit_x < cic.tile_width; bit_x++) {
+ int cram_bank, cram_x, cram_y;
+ cic.get_cram_index(bit_x, bit_y, cram_bank, cram_x, cram_y);
+ this->cram[cram_bank][cram_x][cram_y] = true;
+ }
+ }
+}
+
+void FpgaConfig::cram_checkerboard(int m)
+{
+ for (int y = 0; y <= this->chip_height()+1; y++)
+ for (int x = 0; x <= this->chip_width()+1; x++)
+ {
+ if ((x+y) % 2 == m)
+ continue;
+
+ CramIndexConverter cic(this, x, y);
+
+ for (int bit_y = 0; bit_y < 16; bit_y++)
+ for (int bit_x = 0; bit_x < cic.tile_width; bit_x++) {
+ int cram_bank, cram_x, cram_y;
+ cic.get_cram_index(bit_x, bit_y, cram_bank, cram_x, cram_y);
+ this->cram[cram_bank][cram_x][cram_y] = true;
+ }
+ }
+}
+
+CramIndexConverter::CramIndexConverter(const FpgaConfig *fpga, int tile_x, int tile_y)
+{
+ this->fpga = fpga;
+ this->tile_x = tile_x;
+ this->tile_y = tile_y;
+
+
+ this->tile_type = fpga->tile_type(this->tile_x, this->tile_y);
+ this->tile_width = fpga->tile_width(this->tile_type);
+
+ auto chip_width = fpga->chip_width();
+ auto chip_height = fpga->chip_height();
+ auto chip_cols = fpga->chip_cols();
+
+ this->left_right_io = this->tile_x == 0 || this->tile_x == chip_width+1;
+ this->right_half = this->tile_x > chip_width / 2;
+ this->top_half = this->tile_y > chip_height / 2;
+
+ this->bank_num = 0;
+ if (this->top_half) this->bank_num |= 1;
+ if (this->right_half) this->bank_num |= 2;
+
+ this->bank_tx = this->right_half ? chip_width + 1 - this->tile_x : this->tile_x;
+ this->bank_ty = this->top_half ? chip_height + 1 - this->tile_y : this->tile_y;
+
+ this->bank_xoff = 0;
+ for (int i = 0; i < this->bank_tx; i++)
+ this->bank_xoff += chip_cols.at(i);
+
+ this->bank_yoff = 16 * this->bank_ty;
+
+ this->column_width = chip_cols.at(this->bank_tx);
+}
+
+void CramIndexConverter::get_cram_index(int bit_x, int bit_y, int &cram_bank, int &cram_x, int &cram_y) const
+{
+ static const int io_top_bottom_permx[18] = {23, 25, 26, 27, 16, 17, 18, 19, 20, 14, 32, 33, 34, 35, 36, 37, 4, 5};
+ static const int io_top_bottom_permy[16] = {0, 1, 3, 2, 4, 5, 7, 6, 8, 9, 11, 10, 12, 13, 15, 14};
+
+ cram_bank = bank_num;
+
+ if (tile_type == "io")
+ {
+ if (left_right_io)
+ {
+ cram_x = bank_xoff + column_width - 1 - bit_x;
+
+ if (top_half)
+ cram_y = bank_yoff + 15 - bit_y;
+ else
+ cram_y = bank_yoff + bit_y;
+ }
+ else
+ {
+ cram_y = bank_yoff + 15 - io_top_bottom_permy[bit_y];
+
+ if (right_half)
+ cram_x = bank_xoff + column_width - 1 - io_top_bottom_permx[bit_x];
+ else
+ cram_x = bank_xoff + io_top_bottom_permx[bit_x];
+ }
+ }
+ else
+ {
+ if (right_half)
+ cram_x = bank_xoff + column_width - 1 - bit_x;
+ else
+ cram_x = bank_xoff + bit_x;
+
+ if (top_half)
+ cram_y = bank_yoff + (15 - bit_y);
+ else
+ cram_y = bank_yoff + bit_y;
+ }
+}
+
+
+// ==================================================================
+// Main program
+
+void usage()
+{
+ log("\n");
+ log("Usage: icepack [options] [input-file [output-file]]\n");
+ log("\n");
+ log(" -u\n");
+ log(" unpack mode (implied when called as 'iceunpack')\n");
+ log("\n");
+ log(" -v\n");
+ log(" verbose (repeat to increase verbosity)\n");
+ log("\n");
+ log(" -b\n");
+ log(" write cram bitmap as netpbm file\n");
+ log("\n");
+ log(" -f\n");
+ log(" write cram bitmap (fill tiles) as netpbm file\n");
+ log("\n");
+ log(" -c\n");
+ log(" write cram bitmap (checkerboard) as netpbm file\n");
+ log(" repeat to flip the selection of tiles\n");
+ log("\n");
+ log(" -B0, -B1, -B2, -B3\n");
+ log(" only include the specified bank in the netpbm file\n");
+ log("\n");
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ vector<string> parameters;
+ bool unpack_mode = false;
+ bool netpbm_mode = false;
+ bool netpbm_fill_tiles = false;
+ bool netpbm_checkerboard = false;
+ int netpbm_banknum = -1;
+ int checkerboard_m = 1;
+
+ for (int i = 0; argv[0][i]; i++)
+ if (string(argv[0]+i) == "iceunpack")
+ unpack_mode = true;
+
+ for (int i = 1; i < argc; i++)
+ {
+ string arg(argv[i]);
+
+ if (arg[0] == '-' && arg.size() > 1) {
+ for (int i = 1; i < arg.size(); i++)
+ if (arg[i] == 'u') {
+ unpack_mode = true;
+ } else if (arg[i] == 'b') {
+ netpbm_mode = true;
+ } else if (arg[i] == 'f') {
+ netpbm_mode = true;
+ netpbm_fill_tiles = true;
+ } else if (arg[i] == 'c') {
+ netpbm_mode = true;
+ netpbm_checkerboard = true;
+ checkerboard_m = !checkerboard_m;
+ } else if (arg[i] == 'B') {
+ netpbm_mode = true;
+ netpbm_banknum = arg[++i] - '0';
+ } else if (arg[i] == 'v') {
+ log_level++;
+ } else
+ usage();
+ continue;
+ }
+
+ parameters.push_back(arg);
+ }
+
+ std::ifstream ifs;
+ std::ofstream ofs;
+
+ std::istream *isp;
+ std::ostream *osp;
+
+ if (parameters.size() >= 1 && parameters[0] != "-") {
+ ifs.open(parameters[0]);
+ if (!ifs.is_open())
+ error("Failed to open input file.\n");
+ isp = &ifs;
+ } else {
+ isp = &std::cin;
+ }
+
+ if (parameters.size() >= 2 && parameters[1] != "-") {
+ ofs.open(parameters[1]);
+ if (!ofs.is_open())
+ error("Failed to open output file.\n");
+ osp = &ofs;
+ } else {
+ osp = &std::cout;
+ }
+
+ if (parameters.size() > 2)
+ usage();
+
+ FpgaConfig fpga_config;
+
+ if (unpack_mode) {
+ fpga_config.read_bits(*isp);
+ if (!netpbm_mode)
+ fpga_config.write_ascii(*osp);
+ } else {
+ fpga_config.read_ascii(*isp);
+ if (!netpbm_mode)
+ fpga_config.write_bits(*osp);
+ }
+
+ if (netpbm_checkerboard) {
+ fpga_config.cram_clear();
+ fpga_config.cram_checkerboard(checkerboard_m);
+ }
+
+ if (netpbm_fill_tiles)
+ fpga_config.cram_fill_tiles();
+
+ if (netpbm_mode)
+ fpga_config.write_cram_pbm(*osp, netpbm_banknum);
+
+ info("Done.\n");
+ return 0;
+}
+
diff --git a/icepack/iceunpack.c b/icepack/iceunpack.c
deleted file mode 100644
index ce8a2fa..0000000
--- a/icepack/iceunpack.c
+++ /dev/null
@@ -1,368 +0,0 @@
-// Written by Mathias Lasser
-// License terms are unclear at the moment
-
-#include<stdio.h>
-#include<stdbool.h>
-#include<stdlib.h>
-#include<stdint.h>
-#include<string.h>
-
-int enable_debug=0;
-#define debugf(...) do{if(enable_debug)fprintf(stderr,__VA_ARGS__);}while(0)
-
-#pragma pack(2)
-
-typedef struct
-{
- uint16_t bfType;
- uint32_t bfSize;
- uint16_t bfReserved1;
- uint16_t bfReserved2;
- uint32_t bfOffBits;
-}BITMAPFILEHEADER;
-
-typedef struct
-{
- uint32_t biSize;
- uint32_t biWidth;
- uint32_t biHeight;
- uint16_t biPlanes;
- uint16_t biBitCount;
- uint32_t biCompression;
- uint32_t biSizeImage;
- uint32_t biXPelsPerMeter;
- uint32_t biYPelsPerMeter;
- uint32_t biClrUsed;
- uint32_t biClrImportant;
-}BITMAPINFOHEADER;
-
-typedef struct{
- uint16_t boot_mode;
- uint16_t crc;
- uint8_t freq;
- uint8_t bank;
- uint32_t write_pointer;
-
- uint32_t CRAM_rowsize;
- uint32_t CRAM_colsize;
- uint8_t* CRAM[4];
- uint32_t BRAM_rowsize;
- uint32_t BRAM_colsize;
- uint8_t* BRAM[4];
-}FPGA_t;
-
-typedef struct{
- uint32_t len;
- uint32_t pointer;
- uint16_t crc;
- uint8_t payload[0];
-}bitstream_t;
-
-typedef union{
- struct{
- uint8_t lo:4;
- uint8_t hi:4;
- };
- uint8_t full;
-}nibble_t;
-
-const char* freq_settings[]={"low","medium","high"};
-const char* boot_settings[]={"Disable","Enable"};
-
-uint16_t crc16(uint32_t crc,uint8_t in){
- for(int i=7;i>=0;i--){
- crc<<=1;
- if((crc^(in<<(16-i)))&0x10000)
- crc^=0x1021;
- }
- return crc;
-}
-
-uint32_t get_byte(bitstream_t* bitstream){
- if(bitstream->pointer>=bitstream->len)return 0xFFFFFF;
- uint8_t data=bitstream->payload[bitstream->pointer++];
- bitstream->crc=crc16(bitstream->crc,data);
- return data;
-}
-
-uint32_t get_payload(bitstream_t* bitstream,int len){
- uint32_t ret=get_byte(bitstream);
- for(int i=1;i<len&&ret!=0xFFFFFFFF;i++){
- ret<<=8;
- ret|=get_byte(bitstream);
- }
- return ret;
-}
-
-void FPGA_write(FPGA_t* FPGA,bitstream_t* bitstream){
- int n=FPGA->CRAM_colsize*FPGA->CRAM_rowsize/8;
- uint8_t* temp=(uint8_t*)malloc(n);
- for(int i=0;i<n;i++)
- temp[i]=get_byte(bitstream);
- FPGA->CRAM[FPGA->bank]=temp;
-}
-
-void FPGA_EBR_write(FPGA_t* FPGA,bitstream_t* bitstream){
- int n=FPGA->BRAM_colsize*FPGA->BRAM_rowsize/8;
- uint8_t* temp=(uint8_t*)malloc(FPGA->write_pointer+n);
- if(FPGA->write_pointer!=0){
- uint8_t* old_data=FPGA->BRAM[FPGA->bank];
- memcpy(temp,old_data,FPGA->write_pointer);
- free(old_data);
- }
- for(int i=0;i<n;i++)temp[FPGA->write_pointer++]=get_byte(bitstream);
- FPGA->BRAM[FPGA->bank]=temp;
-}
-
-int parse(bitstream_t* bitstream, FPGA_t* FPGA) {
- uint32_t preamble=0;
- while(1){
- preamble<<=8;
- preamble|=get_byte(bitstream);
- if(preamble==0x7EAA997E){
- debugf("Got preamble\n");
- break;
- }
- if(preamble==0xFFFFFFFF){
- fprintf(stderr,"Error: could not find preamble...\n");
- return -1;
- }
- }
- nibble_t command;
- uint32_t payload;
- uint16_t crc;
- while(1){
- crc=bitstream->crc;
- command.full=get_byte(bitstream);
- if(command.full==0xFF){
- payload=get_byte(bitstream);
- if(payload!=0x00)goto err;
- char*comment=(char*)&bitstream->payload[bitstream->pointer];
- debugf("Got comment section start\n");
- while(1){
- payload<<=8;
- payload|=get_byte(bitstream);
- if((payload&0xFFFF)==0x00FF)break;
- if(payload==0xFFFFFFFF){
- fprintf(stderr,"Error: could not find comment section end\n");
- return -1;
- }
- }
- debugf("\n%s\n\n",comment);
- debugf("Got comment section end\n");
- continue;
- }
- payload=get_payload(bitstream,command.lo);
- switch(command.hi){
- case 0x0:
- if(command.lo!=0x01)goto err;
- switch(payload){
- case 0x01:
- debugf("Write to CRAM!!!\n");
- FPGA_write(FPGA,bitstream);
- get_payload(bitstream,2);
- break;
- case 0x03:
- debugf("Write to BRAM!!!\n");
- FPGA_EBR_write(FPGA,bitstream);
- get_payload(bitstream,2);
- break;
- case 0x05:
- debugf("Resetting CRC\n");
- bitstream->crc=0;
- break;
- case 0x06:
- debugf("Wake up\n");
- return 0;
- default:
- goto err;
- }
- break;
- case 0x1:
- if(command.lo!=0x01)goto err;
- if(payload>3){
- fprintf(stderr,"Error: bank %u does not exist...\n",payload);
- }
- debugf("Set bank to %u\n",payload);
- FPGA->bank=payload;
- break;
- case 0x2:
- if(command.lo!=0x02)goto err;
- debugf("CRC check: %04X %04X\n",payload,crc);
- break;
- case 0x5:
- if(command.lo!=0x01)goto err;
- if(payload>2){
- fprintf(stderr,"Error: unknown frequency setting...\n");
- return -1;
- }
- debugf("Boot frequency set to %s\n",freq_settings[payload]);
- FPGA->freq=payload;
- break;
- case 0x6:
- if(command.lo!=0x02)goto err;
- payload++;
- debugf("Row size: %i\n",payload);
- if(FPGA->CRAM_rowsize)FPGA->BRAM_rowsize=payload;
- else FPGA->CRAM_rowsize=payload;
- break;
- case 0x7:
- if(command.lo!=0x02)goto err;
- debugf("Column size: %i\n",payload);
- if(FPGA->CRAM_colsize)FPGA->BRAM_colsize=payload;
- else FPGA->CRAM_colsize=payload;
- break;
- case 0x8:
- if(command.lo!=0x02)goto err;
- if(payload==0x0000){
- debugf("Reset write pointer\n");
- FPGA->write_pointer=0;
- }
- else if(payload==0x0080){
- debugf("Don't reset write pointer\n");
- }
- else goto err;
- break;
- case 0x9:
- if(command.lo!=0x02)goto err;
- if(payload&0xFFDF){
- fprintf(stderr,"Error: Unknown warmboot setting... %04X\n",payload);
- return -1;
- }
- debugf("%s warmboot\n",boot_settings[payload?1:0]);
- FPGA->boot_mode=payload;
- break;
- default:
- goto err;
- }
- }
-err:
- fprintf(stderr,"Error: unkown command... %08X\n",bitstream->pointer);
- return -1;
-}
-
-uint8_t get_CRAM_bit_from_sector(FPGA_t* FPGA,int bank,int x,int y){
- if(x<0||x>=FPGA->CRAM_rowsize)return 0xFF;
- if(y<0||y>=FPGA->CRAM_colsize)return 0xFF;
- if(bank<0||bank>=4)return 0xFF;
-
-
- int bit=y*FPGA->CRAM_rowsize+x;
- int pointer=bit>>3;
- int shifts=7-(bit&7);
- return (FPGA->CRAM[bank][pointer]>>shifts)&1;
-}
-
-int tiles[2][20]={
- {18,54,54,42,54,54,54},
- {18,2,54,54,54,54,54,54,54,42,54,54,54,54,54,54,54,54}
-};
-
-int permx[2][18]={
- {23,25,26,27,16,17,18,19,20,14,32,33,34,35,36,37,4,5},
- {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17}};
-int permy[4][16]={
- {0,1,3,2,4,5,7,6,8,9,11,10,12,13,15,14},
- {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15},
-};
-
-int tile_row_size[2]={7,17};
-int tile_col_size[2]={9,17};
-
-void print_tile(FPGA_t* FPGA,int x,int y){
- int type=FPGA->CRAM_rowsize==872;
- int dirx=0;
- int diry=0;
- int tx=x;
- int ty=y;
-
- int corner_flags=0;
- if(x==0)corner_flags|=1;
- if(y==0)corner_flags|=2;
- if(x==tile_row_size[type]*2-1)corner_flags|=4;
- if(y==tile_col_size[type]*2-1)corner_flags|=8;
- if(corner_flags&(corner_flags-1))
- return;
-
- if(x>=tile_row_size[type]){
- dirx=1;
- tx=tile_row_size[type]*2-1-x;
- }
- if(y>=tile_col_size[type]){
- diry=1;
- ty=tile_col_size[type]*2-1-y;
- }
- int sector=(diry|dirx<<1);
- int offx=0;for(int i=0;i<tx;i++)offx+=tiles[type][i];
- if(corner_flags){
- printf(".io_tile %i %i\n",x,y);
- for(int cy=0;cy<16;cy++){
- for(int cx=0;cx<18;cx++){
- int val;
- if(corner_flags&5){
- if(diry){
- val=get_CRAM_bit_from_sector(FPGA,sector,offx+tiles[type][tx]-1-permx[1][cx],ty*16+15-permy[1][cy]);
- }else{
- val=get_CRAM_bit_from_sector(FPGA,sector,offx+tiles[type][tx]-1-permx[1][cx],ty*16+permy[1][cy]);
- }
- }else{
- if(dirx){
- val=get_CRAM_bit_from_sector(FPGA,sector,offx+tiles[type][tx]-1-permx[0][cx],ty*16+15-permy[0][cy]);
- }else{
- val=get_CRAM_bit_from_sector(FPGA,sector,offx+permx[0][cx],ty*16+15-permy[0][cy]);
- }
- }
- printf("%i",val);
- }
- printf("\n");
- }
- }
- else{
- if(tiles[type][tx]==20)printf(".io_tile %i %i\n",x,y);
- if(tiles[type][tx]==42)printf(".ram_tile %i %i\n",x,y);
- if(tiles[type][tx]==54)printf(".logic_tile %i %i\n",x,y);
- for(int cy=0;cy<16;cy++){
- for(int cx=0;cx<tiles[type][tx];cx++){
- printf("%i",get_CRAM_bit_from_sector(FPGA,sector,(dirx?(offx+tiles[type][tx]-1-cx):(offx+cx)),(diry?(ty*16+(15-cy)):(ty*16+cy))));
- }
- printf("\n");
- }
- }
-}
-
-int main(int argc,char**argv) {
- if(argc>=2&&!strcmp(argv[1], "-v")) {
- enable_debug=1;
- argc--;
- argv++;
- }
- if(argc!=2) {
- fprintf(stderr,"iceunpack [-v] input\n");
- return 1;
- }
-
- FILE*r_file=fopen(argv[1],"rb");
- if(r_file==NULL) {
- fprintf(stderr,"could not open %s\n",argv[1]);
- return 1;
- }
- fseek(r_file,0,SEEK_END);
- size_t r_size=ftell(r_file);
- fseek(r_file,0,SEEK_SET);
-
- bitstream_t* bitstream=(bitstream_t*)malloc(sizeof(bitstream_t)+r_size);
- bitstream->len=r_size;
- bitstream->pointer=0;
- fread(bitstream->payload,1,r_size,r_file);
- fclose(r_file);
-
- FPGA_t FPGA;
- memset(&FPGA,0,sizeof(FPGA));
-
- parse(bitstream,&FPGA);
- free(bitstream);
-
- printf(".device 1k\n");
- for(int y=0;y<18;y++)for(int x=0;x<14;x++)print_tile(&FPGA,x,y);
- return 0;
-}