diff options
| -rw-r--r-- | icebox/icebox.py | 27 | ||||
| -rwxr-xr-x | icebox/icebox_explain.py | 6 | ||||
| -rw-r--r-- | icepack/Makefile | 20 | ||||
| -rw-r--r-- | icepack/icepack.cc | 1031 | ||||
| -rw-r--r-- | icepack/iceunpack.c | 368 | 
5 files changed, 1074 insertions, 378 deletions
| diff --git a/icebox/icebox.py b/icebox/icebox.py index f3dc113..01cda0d 100644 --- a/icebox/icebox.py +++ b/icebox/icebox.py @@ -27,10 +27,12 @@ class iceconfig:      def clear(self):          self.max_x = 0          self.max_y = 0 +        self.device = ""          self.logic_tiles = dict()          self.io_tiles = dict()          self.ram_tiles = dict()          self.ram_init = dict() +        self.extra_bits = set()      def setup_empty_1k(self):          self.clear() @@ -52,6 +54,12 @@ class iceconfig:              self.io_tiles[(0, y)] = ["0" * 18 for i in range(16)]              self.io_tiles[(self.max_x, y)] = ["0" * 18 for i in range(16)] +    def lookup_extra_bit(self, bit): +        assert self.device in extra_bits_db +        if bit in extra_bits_db[self.device]: +            return extra_bits_db[self.device][bit] +        return ("UNKNOWN_FUNCTION",) +      def tile(self, x, y):          if (x, y) in self.io_tiles: return self.io_tiles[(x, y)]          if (x, y) in self.logic_tiles: return self.logic_tiles[(x, y)] @@ -354,6 +362,8 @@ class iceconfig:                      assert expected_data_lines == 0                      continue                  if line[0][0] != ".": +                    if expected_data_lines == -1: +                        continue                      if line[0][0] != "0" and line[0][0] != "1":                          print("%sWarning: ignoring data block in line %d: %s" % (logprefix, linenum, linetext.strip()))                          expected_data_lines = 0 @@ -362,7 +372,7 @@ class iceconfig:                      current_data.append(line[0])                      expected_data_lines -= 1                      continue -                assert expected_data_lines == 0 +                assert expected_data_lines <= 0                  if line[0] in (".io_tile", ".logic_tile", ".ram_tile"):                      current_data = list()                      expected_data_lines = 16 @@ -377,8 +387,15 @@ class iceconfig:                  if line[0] == ".ram_tile":                      self.ram_tiles[(int(line[1]), int(line[2]))] = current_data                      continue +                if line[0] == ".extra_bit": +                    self.extra_bits.add((int(line[1]), int(line[2]), int(line[3]))) +                    continue                  if line[0] == ".device": -                    assert line[1] == "1k" +                    assert line[1] in ["1k"] +                    self.device = line[1] +                    continue +                if line[0] == ".comment": +                    expected_data_lines = -1                      continue                  print("%sWarning: ignoring line %d: %s" % (logprefix, linenum, linetext.strip())) @@ -770,6 +787,12 @@ def parse_db(text):          db.append(line)      return db +extra_bits_db = { +    "1k": { +        (0, 331, 142): ("routing", "padin_1", "glb_netwk_1") +    } +} +  iotile_full_db = parse_db(iceboxdb.database_io_txt)  logictile_db = parse_db(iceboxdb.database_logic_txt)  ramtile_db = parse_db(iceboxdb.database_ram_txt) diff --git a/icebox/icebox_explain.py b/icebox/icebox_explain.py index 26575f1..e2ca0e8 100755 --- a/icebox/icebox_explain.py +++ b/icebox/icebox_explain.py @@ -153,5 +153,11 @@ for idx in ic.logic_tiles:  for idx in ic.ram_tiles:      print_tile(".ram_tile %d %d" % idx, ic, idx[0], idx[1], ic.ram_tiles[idx], ic.tile_db(idx[0], idx[1])) + +for bit in ic.extra_bits: +    print() +    print(".extra_bit %d %d %d" % bit) +    print(" ".join(ic.lookup_extra_bit(bit))) +  print() 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; -} | 
