fpgatools/bit2txt.c
2012-06-26 01:45:43 +02:00

2034 lines
50 KiB
C

//
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#define PROGRAM_REVISION "2012-06-01"
// 120 MB max bitstream size is enough for now
#define BITSTREAM_READ_PAGESIZE 4096
#define BITSTREAM_READ_MAXPAGES 30000 // 120 MB max bitstream
__inline uint16_t __swab16(uint16_t x)
{
return (((x & 0x00ffU) << 8) | \
((x & 0xff00U) >> 8)); \
}
__inline uint32_t __swab32(uint32_t x)
{
return (((x & 0x000000ffUL) << 24) | \
((x & 0x0000ff00UL) << 8) | \
((x & 0x00ff0000UL) >> 8) | \
((x & 0xff000000UL) >> 24)); \
}
#define __be32_to_cpu(x) __swab32((uint32_t)(x))
#define __be16_to_cpu(x) __swab16((uint16_t)(x))
#define __cpu_to_be32(x) __swab32((uint32_t)(x))
#define __cpu_to_be16(x) __swab16((uint16_t)(x))
#define __le32_to_cpu(x) ((uint32_t)(x))
#define __le16_to_cpu(x) ((uint16_t)(x))
#define __cpu_to_le32(x) ((uint32_t)(x))
#define __cpu_to_le16(x) ((uint16_t)(x))
void help();
//
// xc6 configuration registers, documentation in ug380, page90
//
enum {
CRC = 0, FAR_MAJ, FAR_MIN, FDRI, FDRO, CMD, CTL, MASK, STAT, LOUT, COR1,
COR2, PWRDN_REG, FLR, IDCODE, CWDT, HC_OPT_REG, CSBO = 18,
GENERAL1, GENERAL2, GENERAL3, GENERAL4, GENERAL5, MODE_REG, PU_GWE,
PU_GTS, MFWR, CCLK_FREQ, SEU_OPT, EXP_SIGN, RDBK_SIGN, BOOTSTS,
EYE_MASK, CBC_REG
};
#define REG_R 0x01
#define REG_W 0x02
#define REG_RW (REG_R | REG_W)
typedef struct
{
char* name;
int rw; // REG_READ / REG_WRITE
} REG_INFO;
const REG_INFO xc6_regs[] =
{
[CRC] = {"CRC", REG_W},
[FAR_MAJ] = {"FAR_MAJ", REG_W}, // frame address register block and major
[FAR_MIN] = {"FAR_MIN", REG_W}, // frame address register minor
[FDRI] = {"FDRI", REG_W}, // frame data input
[FDRO] = {"FDRO", REG_R}, // frame data output
[CMD] = {"CMD", REG_RW}, // command
[CTL] = {"CTL", REG_RW}, // control
[MASK] = {"MASK", REG_RW}, // control mask
[STAT] = {"STAT", REG_R}, // status
[LOUT] = {"LOUT", REG_W}, // legacy output for serial daisy-chain
[COR1] = {"COR1", REG_RW}, // configuration option 1
[COR2] = {"COR2", REG_RW}, // configuration option 2
[PWRDN_REG] = {"PWRDN_REG", REG_RW}, // power-down option register
[FLR] = {"FLR", REG_W}, // frame length register
[IDCODE] = {"IDCODE", REG_RW}, // product IDCODE
[CWDT] = {"CWDT", REG_RW}, // configuration watchdog timer
[HC_OPT_REG] = {"HC_OPT_REG", REG_RW}, // house clean option register
[CSBO] = {"CSBO", REG_W}, // CSB output for parallel daisy-chaining
[GENERAL1] = {"GENERAL1", REG_RW}, // power-up self test or loadable
// program addr
[GENERAL2] = {"GENERAL2", REG_RW}, // power-up self test or loadable
// program addr and new SPI opcode
[GENERAL3] = {"GENERAL3", REG_RW}, // golden bitstream address
[GENERAL4] = {"GENERAL4", REG_RW}, // golden bitstream address and new
// SPI opcode
[GENERAL5] = {"GENERAL5", REG_RW}, // user-defined register for
// fail-safe scheme
[MODE_REG] = {"MODE_REG", REG_RW}, // reboot mode
[PU_GWE] = {"PU_GWE", REG_W}, // GWE cycle during wake-up from suspend
[PU_GTS] = {"PU_GTS", REG_W}, // GTS cycle during wake-up from suspend
[MFWR] = {"MFWR", REG_W}, // multi-frame write register
[CCLK_FREQ] = {"CCLK_FREQ", REG_W}, // CCLK frequency select for
// master mode
[SEU_OPT] = {"SEU_OPT", REG_RW}, // SEU frequency, enable and status
[EXP_SIGN] = {"EXP_SIGN", REG_RW}, // expected readback signature for
// SEU detect
[RDBK_SIGN] = {"RDBK_SIGN", REG_W}, // readback signature for readback
// cmd and SEU
[BOOTSTS] = {"BOOTSTS", REG_R}, // boot history register
[EYE_MASK] = {"EYE_MASK", REG_RW}, // mask pins for multi-pin wake-up
[CBC_REG] = {"CBC_REG", REG_W} // initial CBC value register
};
// The highest 4 bits are the binary revision and not
// used when performing IDCODE verification.
// ug380, Configuration Sequence, page 78
typedef struct
{
char* name;
uint32_t code;
} IDCODE_S;
const IDCODE_S idcodes[] =
{
{"XC6SLX4", 0x04000093},
{"XC6SLX9", 0x04001093},
{"XC6SLX16", 0x04002093},
{"XC6SLX25", 0x04004093},
{"XC6SLX25T", 0x04024093},
{"XC6SLX45", 0x04008093},
{"XC6SLX45T", 0x04028093},
{"XC6SLX75", 0x0400E093},
{"XC6SLX75T", 0x0402E093},
{"XC6SLX100", 0x04011093},
{"XC6SLX100T", 0x04031093},
{"XC6SLX150", 0x0401D093}
};
// CMD register - ug380, page 92
enum {
CMD_NULL = 0, CMD_WCFG, CMD_MFW, CMD_LFRM, CMD_RCFG, CMD_START,
CMD_RCRC = 7, CMD_AGHIGH, CMD_GRESTORE = 10, CMD_SHUTDOWN,
CMD_DESYNC = 13, CMD_IPROG
};
const char* cmds[] =
{
[CMD_NULL] = "NULL",
[CMD_WCFG] = "WCFG",
[CMD_MFW] = "MFW",
[CMD_LFRM] = "LFRM",
[CMD_RCFG] = "RCFG",
[CMD_START] = "START",
[CMD_RCRC] = "RCRC",
[CMD_AGHIGH] = "AGHIGH",
[CMD_GRESTORE] = "GRESTORE",
[CMD_SHUTDOWN] = "SHUTDOWN",
[CMD_DESYNC] = "DESYNC",
[CMD_IPROG] = "IPROG"
};
typedef struct
{
char* name;
int minors;
} MAJOR;
const MAJOR majors[] =
{
/* 0 */ { 0, 4 }, // clock?
/* 1 */ { 0, 30 },
/* 2 */ { "clb", 31 },
/* 3 */ { 0, 30 },
/* 4 */ { "bram", 25 },
/* 5 */ { "clb", 31 },
/* 6 */ { 0, 30 },
/* 7 */ { 0, 24 }, // dsp?
/* 8 */ { "clb", 31 },
/* 9 */ { 0, 31 },
/* 10 */ { "clb", 31 },
/* 11 */ { 0, 30 },
/* 12 */ { 0, 31 },
/* 13 */ { 0, 30 },
/* 14 */ { 0, 25 },
/* 15 */ { "clb", 31 },
/* 16 */ { 0, 30 },
/* 17 */ { 0, 30 }
};
static const char* bitstr(uint32_t value, int digits)
{
static char str[2 /* "0b" */ + 32 + 1 /* '\0' */];
int i;
str[0] = '0';
str[1] = 'b';
for (i = 0; i < digits; i++)
str[digits-i+1] = (value & (1<<i)) ? '1' : '0';
str[digits+2] = 0;
return str;
}
void hexdump(int indent, const uint8_t* data, int len)
{
int i, j;
char fmt_str[16] = "%s@%05x %02x";
char indent_str[16];
if (indent > 15)
indent = 15;
for (i = 0; i < indent; i++)
indent_str[i] = ' ';
indent_str[i] = 0;
i = 0;
if (len <= 0x100)
fmt_str[5] = '2';
else if (len <= 0x10000)
fmt_str[5] = '4';
else
fmt_str[5] = '6';
while (i < len) {
printf(fmt_str, indent_str, i, data[i]);
for (j = 1; (j < 8) && (i + j < len); j++) {
if (i + j >= len) break;
printf(" %02x", data[i+j]);
}
printf("\n");
i += 8;
}
}
static const char* iob_xc6slx4_sitenames[896*2/8] =
{
[0x0000/8] "P70",
"P69",
"P67",
"P66",
"P65",
"P64",
"P62",
"P61",
"P60",
"P59",
"P58",
"P57",
0,
0,
0,
0,
[0x0080/8] 0,
0,
"P56",
"P55",
0,
0,
0,
0,
0,
0,
"P51",
"P50",
0,
0,
0,
0,
[0x0100/8] 0,
0,
0,
0,
"UNB131",
"UNB132",
"P48",
"P47",
"P46",
"P45",
"P44",
"P43",
0,
0,
"P41",
"P40",
[0x0180/8] "P39",
"P38",
"P35",
"P34",
"P33",
"P32",
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
[0x0200/8] "P30",
"P29",
"P27",
"P26",
0,
0,
0,
0,
0,
0,
"P24",
"P23",
"P22",
"P21",
0,
0,
[0x0280/8] 0,
0,
0,
0,
"P17",
"P16",
"P15",
"P14",
0,
0,
0,
0,
0,
0,
0,
0,
[0x0300/8] "P12",
"P11",
"P10",
"P9",
"P8",
"P7",
"P6",
"P5",
0,
0,
0,
0,
0,
0,
"P2",
"P1",
[0x0380/8] "P144",
"P143",
"P142",
"P141",
"P140",
"P139",
"P138",
"P137",
0,
0,
0,
0,
0,
0,
0,
0,
[0x0400/8] 0,
0,
0,
0,
"P134",
"P133",
"P132",
"P131",
0,
0,
0,
0,
0,
0,
"P127",
"P126",
[0x0480/8] "P124",
"P123",
0,
0,
0,
0,
0,
0,
"P121",
"P120",
"P119",
"P118",
"P117",
"P116",
"P115",
"P114",
[0x0500/8] "P112",
"P111",
"P105",
"P104",
0,
0,
0,
0,
0,
0,
"P102",
"P101",
"P99",
"P98",
"P97",
[0x0580/8] 0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
"P95",
"P94",
"P93",
"P92",
0,
0,
[0x0600/8] 0,
0,
0,
"P88",
"P87",
0,
"P85",
"P84",
0,
0,
"P83",
"P82",
"P81",
"P80",
"P79",
"P78",
[0x0680/8] 0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
"P75",
"P74"
};
typedef struct ramb16_cfg
{
uint8_t byte[64];
} __attribute((packed)) ramb16_cfg_t;
static const int ramb_data_width_encoding[8] =
{
/* 000 */ 1,
/* 001 */ 2,
/* 010 */ 4,
/* 011 */ 9,
/* 100 */ 18,
/* 101 */ 36,
/* 110 */ -1, // unsupported
/* 111 */ 0
};
static const char* ramb16_cfg_str_min24[128] =
{
[261 - 256] "RST_PRIORITY_B_CE",
[262 - 256] "RST_PRIORITY_A_CE",
[263 - 256] "RSTTYPE_ASYNC",
[269 - 256] "WRITE_MODE_B_NO_CHANGE",
[270 - 256] "WRITE_MODE_A_NO_CHANGE",
[267 - 256] "WRITE_MODE_B_READ_FIRST",
[268 - 256] "WRITE_MODE_A_READ_FIRST",
[273 - 256] "EN_RSTRAM_A",
[281 - 256] "DOB_REG",
[282 - 256] "DOA_REG",
[350 - 256] "EN_RSTRAM_B",
};
void print_ramb16_cfg(ramb16_cfg_t* cfg)
{
int i;
uint8_t u8;
char forward_bits[128], reverse_bits[128];
for (i = 0; i < 32; i++) {
u8 = cfg->byte[i*2];
cfg->byte[i*2] = cfg->byte[i*2+1];
cfg->byte[i*2+1] = u8;
}
for (i = 0; i < 64; i++) {
u8 = 0;
if (cfg->byte[i] & 0x01) u8 |= 0x80;
if (cfg->byte[i] & 0x02) u8 |= 0x40;
if (cfg->byte[i] & 0x04) u8 |= 0x20;
if (cfg->byte[i] & 0x08) u8 |= 0x10;
if (cfg->byte[i] & 0x10) u8 |= 0x08;
if (cfg->byte[i] & 0x20) u8 |= 0x04;
if (cfg->byte[i] & 0x40) u8 |= 0x02;
if (cfg->byte[i] & 0x80) u8 |= 0x01;
cfg->byte[i] = u8;
}
printf("{\n");
// hexdump(1 /* indent */, &cfg->byte[0], 64 /* len */);
//
// Bits 0..255 come from minor 23, Bits 256..511 from minor 24.
// It looks like each set of 256 bits is divided into two halfs
// of 128 bits that are swept across the same memory locations
// in the chip. On the first sweep, some bits are turned on.
// On the second sweep, reverse from the end, most/all of the
// enabled bits stay on, some more are enabled, some disabled.
//
for (i = 0; i < 128; i++) {
forward_bits[i] = (cfg->byte[i/8] & (1<<(i%8))) != 0;
reverse_bits[i] = (cfg->byte[(255-i)/8]
& (1<<(7-(i%8)))) != 0;
}
//
// "fe" = forward enable (enable in forward sweep)
// "re" = reverse enable (enable in reverse sweep)
// "rd" = reverse disable (disable in reverse sweep)
//
for (i = 0; i < 128; i++) {
if (forward_bits[i])
printf(" fe%i ?\n", i);
}
for (i = 127; i >= 0; i--) {
if (reverse_bits[i] != forward_bits[i]) {
printf(" r%c%i ?\n",
reverse_bits[i] ? 'e' : 'd', i);
}
}
// minor 24
printf("\n");
for (i = 0; i < 128; i++) {
forward_bits[i] = (cfg->byte[32+i/8] & (1<<(i%8))) != 0;
reverse_bits[i] = (cfg->byte[32+(255-i)/8]
& (1<<(7-(i%8)))) != 0;
}
// data width
{
int encoding;
if (forward_bits[256-256] == reverse_bits[256-256]
&& forward_bits[258-256] == reverse_bits[258-256]
&& forward_bits[260-256] == reverse_bits[260-256]) {
encoding = 0;
if (forward_bits[256-256])
encoding |= 0x01;
if (forward_bits[258-256])
encoding |= 0x02;
if (forward_bits[260-256])
encoding |= 0x04;
if (encoding < sizeof(ramb_data_width_encoding) / sizeof(ramb_data_width_encoding[0])
&& ramb_data_width_encoding[encoding] != -1) {
printf(" data_width_a %i\n", ramb_data_width_encoding[encoding]);
forward_bits[256-256] = 0;
reverse_bits[256-256] = 0;
forward_bits[258-256] = 0;
reverse_bits[258-256] = 0;
forward_bits[260-256] = 0;
reverse_bits[260-256] = 0;
}
}
if (forward_bits[257-256] == reverse_bits[257-256]
&& forward_bits[259-256] == reverse_bits[259-256]
&& forward_bits[271-256] == reverse_bits[271-256]) {
encoding = 0;
if (forward_bits[257-256])
encoding |= 0x01;
if (forward_bits[259-256])
encoding |= 0x04;
if (forward_bits[271-256])
encoding |= 0x02;
if (encoding < sizeof(ramb_data_width_encoding) / sizeof(ramb_data_width_encoding[0])
&& ramb_data_width_encoding[encoding] != -1) {
printf(" data_width_b %i\n",
ramb_data_width_encoding[encoding]);
forward_bits[257-256] = 0;
reverse_bits[257-256] = 0;
forward_bits[259-256] = 0;
reverse_bits[259-256] = 0;
forward_bits[271-256] = 0;
reverse_bits[271-256] = 0;
}
}
}
for (i = 0; i < 128; i++) {
if (forward_bits[i])
printf(" fe%i %s\n", 256+i, ramb16_cfg_str_min24[i] ?
ramb16_cfg_str_min24[i] : "?");
}
for (i = 127; i >= 0; i--) {
if (reverse_bits[i] != forward_bits[i]) {
printf(" r%c%i %s\n",
reverse_bits[i] ? 'e' : 'd', 256+i,
ramb16_cfg_str_min24[i]
? ramb16_cfg_str_min24[i] : "?");
}
}
printf("}\n");
}
// for an equivalent schematic, see lut.svg
const int lut_base_vars[6] = {0 /* A1 */, 1, 0, 0, 0, 1 /* A6 */};
int bool_nextlen(const char* expr, int len)
{
int i, depth;
if (!len) return -1;
i = 0;
if (expr[i] == '~') {
i++;
if (i >= len) return -1;
}
if (expr[i] == '(') {
if (i+2 >= len) return -1;
i++;
for (depth = 1; depth && i < len; i++) {
if (expr[i] == '(')
depth++;
else if (expr[i] == ')')
depth--;
}
if (depth) return -1;
return i;
}
if (expr[i] == 'A') {
i++;
if (i >= len) return -1;
if (expr[i] < '1' || expr[i] > '6') return -1;
return i+1;
}
return -1;
}
// + or, * and, @ xor, ~ not
// var must point to array of A1..A6 variables
int bool_eval(const char* expr, int len, const int* var)
{
int i, negate, result, oplen;
oplen = bool_nextlen(expr, len);
if (oplen < 1) goto fail;
i = 0;
negate = 0;
if (expr[i] == '~') {
negate = 1;
if (++i >= oplen) goto fail;
}
if (expr[i] == '(') {
if (i+2 >= oplen) goto fail;
result = bool_eval(&expr[i+1], oplen-i-2, var);
if (result == -1) goto fail;
} else if (expr[i] == 'A') {
if (i+1 >= oplen) goto fail;
if (expr[i+1] < '1' || expr[i+1] > '6')
goto fail;
result = var[expr[i+1]-'1'];
if (oplen != i+2) goto fail;
} else goto fail;
if (negate) result = !result;
i = oplen;
while (i < len) {
if (expr[i] == '+') {
if (result) return 1;
return bool_eval(&expr[i+1], len-i-1, var);
}
if (expr[i] == '@') {
int right_side = bool_eval(&expr[i+1], len-i-1, var);
if (right_side == -1) goto fail;
return (result && !right_side) || (!result && right_side);
}
if (expr[i] != '*') goto fail;
if (!result) break;
if (++i >= len) goto fail;
oplen = bool_nextlen(&expr[i], len-i);
if (oplen < 1) goto fail;
result = bool_eval(&expr[i], oplen, var);
if (result == -1) goto fail;
i += oplen;
}
return result;
fail:
return -1;
}
int parse_boolexpr(const char* expr, uint64_t* lut)
{
int i, j, result, vars[6];
*lut = 0;
for (i = 0; i < 64; i++) {
memcpy(vars, lut_base_vars, sizeof(vars));
for (j = 0; j < 6; j++) {
if (i & (1<<j))
vars[j] = !vars[j];
}
result = bool_eval(expr, strlen(expr), vars);
if (result == -1) return -1;
if (result) *lut |= 1LL<<i;
}
return 0;
}
void printf_lut6(const char* cfg)
{
uint64_t lut;
uint32_t first_major, second_major;
int i;
first_major = 0;
second_major = 0;
parse_boolexpr(cfg, &lut);
for (i = 0; i < 16; i++) {
if (lut & (1LL<<(i*4)))
first_major |= 1<<(i*2);
if (lut & (1LL<<(i*4+1)))
first_major |= 1<<(i*2+1);
if (lut & (1LL<<(i*4+2)))
second_major |= 1<<(i*2);
if (lut & (1LL<<(i*4+3)))
second_major |= 1<<(i*2+1);
}
printf("first_major 0x%X second_major 0x%X\n", first_major, second_major);
}
typedef struct _minterm_entry
{
char a[6]; // 0=A1, 5=A6. value can be 0, 1 or 2 for 'removed'
int merged;
} minterm_entry;
// bits is tested only for 32 and 64
void lut2bool(const uint64_t lut, int bits, char* str)
{
// round 0 needs 64 entries
// round 1 (size2): 192
// round 2 (size4): 240
// round 3 (size8): 160
// round 4 (size16): 60
// round 5 (size32): 12
// round 6 (size64): 1
minterm_entry mt[7][256];
int mt_size[7];
int i, j, k, round, only_diff_bit;
int str_end, first_op;
memset(mt, 0, sizeof(mt));
memset(mt_size, 0, sizeof(mt_size));
for (i = 0; i < bits; i++) {
if (lut & (1LL<<i)) {
mt[0][mt_size[0]].a[0] = lut_base_vars[0];
mt[0][mt_size[0]].a[1] = lut_base_vars[1];
mt[0][mt_size[0]].a[2] = lut_base_vars[2];
mt[0][mt_size[0]].a[3] = lut_base_vars[3];
mt[0][mt_size[0]].a[4] = lut_base_vars[4];
mt[0][mt_size[0]].a[5] = lut_base_vars[5];
for (j = 0; j < 6; j++) {
if (i & (1<<j))
mt[0][mt_size[0]].a[j]
= !mt[0][mt_size[0]].a[j];
}
mt_size[0]++;
}
}
// special case: no minterms -> empty string
if (mt_size[0] == 0) {
str[0] = 0;
return;
}
// go through five rounds of merging
for (round = 1; round < 7; round++) {
for (i = 0; i < mt_size[round-1]; i++) {
for (j = i+1; j < mt_size[round-1]; j++) {
only_diff_bit = -1;
for (k = 0; k < 6; k++) {
if (mt[round-1][i].a[k] != mt[round-1][j].a[k]) {
if (only_diff_bit != -1) {
only_diff_bit = -1;
break;
}
only_diff_bit = k;
}
}
if (only_diff_bit != -1) {
char new_term[6];
for (k = 0; k < 6; k++)
new_term[k] =
(k == only_diff_bit) ? 2
: mt[round-1][i].a[k];
for (k = 0; k < mt_size[round]; k++) {
if (new_term[0] == mt[round][k].a[0]
&& new_term[1] == mt[round][k].a[1]
&& new_term[2] == mt[round][k].a[2]
&& new_term[3] == mt[round][k].a[3]
&& new_term[4] == mt[round][k].a[4]
&& new_term[5] == mt[round][k].a[5])
break;
}
if (k >= mt_size[round]) {
mt[round][mt_size[round]].a[0] = new_term[0];
mt[round][mt_size[round]].a[1] = new_term[1];
mt[round][mt_size[round]].a[2] = new_term[2];
mt[round][mt_size[round]].a[3] = new_term[3];
mt[round][mt_size[round]].a[4] = new_term[4];
mt[round][mt_size[round]].a[5] = new_term[5];
mt_size[round]++;
}
mt[round-1][i].merged = 1;
mt[round-1][j].merged = 1;
}
}
}
}
// special case: 222222 -> (A6+~A6)
for (i = 0; i < mt_size[6]; i++) {
if (mt[6][i].a[0] == 2
&& mt[6][i].a[1] == 2
&& mt[6][i].a[2] == 2
&& mt[6][i].a[3] == 2
&& mt[6][i].a[4] == 2
&& mt[6][i].a[5] == 2) {
strcpy(str, "A6+~A6");
return;
}
}
str_end = 0;
for (round = 0; round < 7; round++) {
for (i = 0; i < mt_size[round]; i++) {
if (!mt[round][i].merged) {
if (str_end)
str[str_end++] = '+';
first_op = 1;
for (j = 0; j < 6; j++) {
if (mt[round][i].a[j] != 2) {
if (!first_op)
str[str_end++] = '*';
if (!mt[round][i].a[j])
str[str_end++] = '~';
str[str_end++] = 'A';
str[str_end++] = '1' + j;
first_op = 0;
}
}
}
}
}
str[str_end] = 0;
// TODO: This could be further simplified, see Petrick's method.
// XOR don't simplify well, try A2@A3
}
int g_FLR_value = -1;
int main(int argc, char** argv)
{
uint8_t* bit_data = 0;
FILE* bitf = 0;
uint32_t bit_cur, bit_eof, cmd_len, u32, u16_off, bit_off;
uint32_t last_processed_pos;
uint16_t str_len, u16, packet_hdr_type, packet_hdr_opcode;
uint16_t packet_hdr_register, packet_hdr_wordcount;
int info = 0; // whether to print #I info messages (offsets and others)
char* bit_path = 0;
int i, j, k, l, num_frames, max_frames_to_scan, offset_in_frame, times;
//
// parse command line
//
if (argc < 2) {
help();
return EXIT_SUCCESS;
}
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "--help")) {
help();
return EXIT_SUCCESS;
}
if (!strcmp(argv[i], "--version")) {
printf("%s\n", PROGRAM_REVISION);
return EXIT_SUCCESS;
}
if (!strcmp(argv[i], "--info")) {
info = 1;
} else {
bit_path = argv[i];
if (argc > i+1) { // only 1 path supported
help();
return EXIT_FAILURE;
}
}
}
if (!bit_path) { // shouldn't get here, just in case
help();
return EXIT_FAILURE;
}
//
// read .bit into memory
//
bit_data = malloc(BITSTREAM_READ_MAXPAGES * BITSTREAM_READ_PAGESIZE);
if (!bit_data) {
fprintf(stderr, "#E Cannot allocate %i bytes for bitstream.\n",
BITSTREAM_READ_MAXPAGES * BITSTREAM_READ_PAGESIZE);
goto fail;
}
if (!(bitf = fopen(bit_path, "rb"))) {
fprintf(stderr, "#E Error opening %s.\n", bit_path);
goto fail;
}
bit_eof = 0;
while (bit_eof < BITSTREAM_READ_MAXPAGES * BITSTREAM_READ_PAGESIZE) {
size_t num_read = fread(&bit_data[bit_eof], sizeof(uint8_t),
BITSTREAM_READ_PAGESIZE, bitf);
bit_eof += num_read;
if (num_read != BITSTREAM_READ_PAGESIZE)
break;
}
fclose(bitf);
if (bit_eof >= BITSTREAM_READ_MAXPAGES * BITSTREAM_READ_PAGESIZE) {
fprintf(stderr, "#E Bitstream size above maximum of "
"%i bytes.\n", BITSTREAM_READ_MAXPAGES *
BITSTREAM_READ_PAGESIZE);
goto fail;
}
//
// header
//
printf("bit2txt_format 1\n");
// offset 0 - magic header
if (bit_eof < 13) {
fprintf(stderr, "#E File size %i below minimum of 13 bytes.\n",
bit_eof);
goto fail;
}
printf("hex");
for (i = 0; i < 13; i++)
printf(" %.02x", bit_data[i]);
printf("\n");
// 4 strings 'a' - 'd', 16-bit length
bit_cur = 13;
for (i = 'a'; i <= 'd'; i++) {
if (bit_eof < bit_cur + 3) {
fprintf(stderr, "#E Unexpected EOF at %i.\n", bit_eof);
goto fail;
}
if (bit_data[bit_cur] != i) {
fprintf(stderr, "#E Expected string code '%c', got "
"'%c'.\n", i, bit_data[bit_cur]);
goto fail;
}
str_len = __be16_to_cpu(*(uint16_t*)&bit_data[bit_cur + 1]);
if (bit_eof < bit_cur + 3 + str_len) {
fprintf(stderr, "#E Unexpected EOF at %i.\n", bit_eof);
goto fail;
}
if (bit_data[bit_cur + 3 + str_len - 1] != 0) {
fprintf(stderr, "#E z-terminated string ends with %0xh"
".\n", bit_data[bit_cur + 3 + str_len - 1]);
goto fail;
}
printf("header_str_%c %s\n", i, &bit_data[bit_cur + 3]);
bit_cur += 3 + str_len;
}
//
// commands
//
if (bit_cur + 5 > bit_eof) goto fail_eof;
if (bit_data[bit_cur] != 'e') {
fprintf(stderr, "#E Expected string code 'e', got '%c'.\n",
bit_data[bit_cur]);
goto fail;
}
cmd_len = __be32_to_cpu(*(uint32_t*)&bit_data[bit_cur + 1]);
bit_cur += 5;
if (bit_cur + cmd_len > bit_eof) goto fail_eof;
if (bit_cur + cmd_len < bit_eof) {
printf("#W Unexpected continuation after offset "
"%i.\n", bit_cur + 5 + cmd_len);
}
// hex-dump everything until 0xAA (sync word: 0xAA995566)
if (bit_cur >= bit_eof) goto fail_eof;
if (bit_data[bit_cur] != 0xAA) {
printf("hex");
while (bit_cur < bit_eof && bit_data[bit_cur] != 0xAA) {
printf(" %.02x", bit_data[bit_cur]);
bit_cur++; if (bit_cur >= bit_eof) goto fail_eof;
}
printf("\n");
}
if (bit_cur + 4 > bit_eof) goto fail_eof;
if (info) printf("#I sync word at offset 0x%x.\n", bit_cur);
u32 = __be32_to_cpu(*(uint32_t*)&bit_data[bit_cur]);
bit_cur += 4;
if (u32 != 0xAA995566) {
fprintf(stderr, "#E Unexpected sync word 0x%x.\n", u32);
goto fail;
}
printf("sync_word\n");
while (bit_cur < bit_eof) {
// 8 is 2 padding frames between each row and 2 at the end
static const int type1_bram_data_start_frame = 4*505+8;
static const int type2_iob_start_frame = 4*505+8 + 4*144;
// packet header: ug380, Configuration Packets (p88)
if (info) printf("#I Packet header at off 0x%x.\n", bit_cur);
if (bit_cur + 2 > bit_eof) goto fail_eof;
u16 = __be16_to_cpu(*(uint16_t*)&bit_data[bit_cur]);
u16_off = bit_cur; bit_cur += 2;
// 3 bits: 001 = Type 1; 010 = Type 2
packet_hdr_type = (u16 & 0xE000) >> 13;
if (packet_hdr_type != 1 && packet_hdr_type != 2) {
fprintf(stderr, "#E 0x%x=0x%x Unexpected packet type "
"%u.\n", u16_off, u16, packet_hdr_type);
goto fail;
}
// 2 bits: 00 = noop; 01 = read; 10 = write; 11 = reserved
packet_hdr_opcode = (u16 & 0x1800) >> 11;
if (packet_hdr_opcode == 3) {
fprintf(stderr, "#E 0x%x=0x%x Unexpected packet opcode "
"3.\n", u16_off, u16);
goto fail;
}
if (packet_hdr_opcode == 0) { // noop
if (packet_hdr_type != 1)
printf("#W 0x%x=0x%x Unexpected packet"
" type %u noop.\n", u16_off,
u16, packet_hdr_type);
if (u16 & 0x07FF)
printf("#W 0x%x=0x%x Unexpected noop "
"header.\n", u16_off, u16);
if (packet_hdr_type != 1 || (u16&0x07FF))
times = 1;
else { // lookahead for more good noops
i = bit_cur;
while (i+1 < bit_eof) {
u16 = __be16_to_cpu(*(uint16_t*)&bit_data[i]);
if (((u16 & 0xE000) >> 13) != 1
|| ((u16 & 0x1800) >> 11)
|| (u16 & 0x7FF))
break;
i += 2;
}
times = 1 + (i - bit_cur)/2;
if (times > 1)
bit_cur += (times-1)*2;
}
if (times > 1)
printf("noop times %i\n", times);
else
printf("noop\n");
continue;
}
// Now we must look at a Type 1 read or write command
packet_hdr_register = (u16 & 0x07E0) >> 5;
packet_hdr_wordcount = u16 & 0x001F;
if (bit_cur + packet_hdr_wordcount*2 > bit_eof) goto fail_eof;
bit_cur += packet_hdr_wordcount*2;
// Check whether register and r/w action on register
// looks valid.
if (packet_hdr_type == 1) {
if (packet_hdr_register >= sizeof(xc6_regs)
/ sizeof(xc6_regs[0])
|| xc6_regs[packet_hdr_register].name[0] == 0) {
printf("#W 0x%x=0x%x unknown T1 reg %u, "
"skipping %d words.\n", u16_off, u16,
packet_hdr_register, packet_hdr_wordcount);
continue;
}
if (packet_hdr_register == IDCODE) {
if (packet_hdr_wordcount != 2) {
fprintf(stderr, "#E 0x%x=0x%x Unexpected IDCODE"
" wordcount %u.\n", u16_off,
u16, packet_hdr_wordcount);
goto fail;
}
u32 = __be32_to_cpu(*(uint32_t*)&bit_data[u16_off+2]);
for (i = 0; i < sizeof(idcodes)/sizeof(idcodes[0]); i++) {
if ((u32 & 0x0FFFFFFF) == idcodes[i].code) {
printf("T1 IDCODE %s\n", idcodes[i].name);
break;
}
}
if (i >= sizeof(idcodes)/sizeof(idcodes[0]))
printf("#W Unknown IDCODE 0x%x.\n", u32);
else if (u32 & 0xF0000000)
printf("#W Unexpected revision bits in IDCODE 0x%x.\n", u32);
continue;
}
if (packet_hdr_register == CMD) {
if (packet_hdr_wordcount != 1) {
fprintf(stderr, "#E 0x%x=0x%x Unexpected CMD"
" wordcount %u.\n", u16_off,
u16, packet_hdr_wordcount);
goto fail;
}
u16 = __be16_to_cpu(*(uint16_t*)&bit_data[u16_off+2]);
u16_off+=2;
if (u16 >= sizeof(cmds) / sizeof(cmds[0])
|| cmds[u16][0] == 0)
printf("#W 0x%x=0x%x Unknown CMD.\n",
u16_off, u16);
else
printf("T1 CMD %s\n", cmds[u16]);
continue;
}
if (packet_hdr_register == FLR) {
if (packet_hdr_wordcount != 1) {
fprintf(stderr, "#E 0x%x=0x%x Unexpected FLR"
" wordcount %u.\n", u16_off,
u16, packet_hdr_wordcount);
goto fail;
}
u16 = __be16_to_cpu(*(uint16_t*)&bit_data[u16_off+2]);
u16_off+=2;
printf("T1 FLR %u\n", u16);
g_FLR_value = u16;
if ((g_FLR_value*2) % 8)
printf("#W FLR*2 should be multiple of "
"8, but modulo 8 is %i\n", (g_FLR_value*2) % 8);
// First come the type 0 frames (clb, bram
// config, dsp, etc). Then type 1 (bram data),
// then type 2, the IOB config data block.
// FLR is counted in 16-bit words, and there is
// 1 extra dummy 0x0000 after that.
continue;
}
if (packet_hdr_register == COR1) {
int unexpected_clk11 = 0;
if (packet_hdr_wordcount != 1) {
fprintf(stderr, "#E 0x%x=0x%x Unexpected COR1"
" wordcount %u.\n", u16_off,
u16, packet_hdr_wordcount);
goto fail;
}
u16 = __be16_to_cpu(*(uint16_t*)&bit_data[u16_off+2]);
u16_off+=2;
printf("T1 COR1");
if (u16 & 0x8000) {
printf(" DRIVE_AWAKE");
u16 &= ~0x8000;
}
if (u16 & 0x0010) {
printf(" CRC_BYPASS");
u16 &= ~0x0010;
}
if (u16 & 0x0008) {
printf(" DONE_PIPE");
u16 &= ~0x0008;
}
if (u16 & 0x0004) {
printf(" DRIVE_DONE");
u16 &= ~0x0004;
}
if (u16 & 0x0003) {
if (u16 & 0x0002) {
if (u16 & 0x0001)
unexpected_clk11 = 1;
printf(" SSCLKSRC=TCK");
} else
printf(" SSCLKSRC=UserClk");
u16 &= ~0x0003;
}
if (u16)
printf(" 0x%x", u16);
printf("\n");
if (unexpected_clk11)
printf("#W Unexpected SSCLKSRC 11.\n");
// Reserved bits 14:5 should be 0110111000
// according to documentation.
if (u16 != 0x3700)
printf("#W Expected reserved 0x%x, got 0x%x.\n", 0x3700, u16);
continue;
}
if (packet_hdr_register == COR2) {
int unexpected_done_cycle = 0;
int unexpected_lck_cycle = 0;
unsigned cycle;
if (packet_hdr_wordcount != 1) {
fprintf(stderr, "#E 0x%x=0x%x Unexpected COR2"
" wordcount %u.\n", u16_off,
u16, packet_hdr_wordcount);
goto fail;
}
u16 = __be16_to_cpu(*(uint16_t*)&bit_data[u16_off+2]);
u16_off+=2;
printf("T1 COR2");
if (u16 & 0x8000) {
printf(" RESET_ON_ERROR");
u16 &= ~0x8000;
}
// DONE_CYCLE
cycle = (u16 & 0x0E00) >> 9;
printf(" DONE_CYCLE=%s", bitstr(cycle, 3));
if (!cycle || cycle == 7)
unexpected_done_cycle = 1;
u16 &= ~0x0E00;
// LCK_CYCLE
cycle = (u16 & 0x01C0) >> 6;
printf(" LCK_CYCLE=%s", bitstr(cycle, 3));
if (!cycle)
unexpected_lck_cycle = 1;
u16 &= ~0x01C0;
// GTS_CYCLE
cycle = (u16 & 0x0038) >> 3;
printf(" GTS_CYCLE=%s", bitstr(cycle, 3));
u16 &= ~0x0038;
// GWE_CYCLE
cycle = u16 & 0x0007;
printf(" GWE_CYCLE=%s", bitstr(cycle, 3));
u16 &= ~0x0007;
if (u16)
printf(" 0x%x", u16);
printf("\n");
if (unexpected_done_cycle)
printf("#W Unexpected DONE_CYCLE %s.\n",
bitstr((u16 & 0x01C0) >> 6, 3));
if (unexpected_lck_cycle)
printf("#W Unexpected LCK_CYCLE 0b000.\n");
// Reserved bits 14:12 should be 000
// according to documentation.
if (u16)
printf("#W Expected reserved 0, got 0x%x.\n", u16);
continue;
}
if (packet_hdr_register == FAR_MAJ
&& packet_hdr_wordcount == 2) {
uint16_t maj, min;
int unexpected_blk_bit4 = 0;
maj = __be16_to_cpu(*(uint16_t*)&bit_data[u16_off+2]);
min = __be16_to_cpu(*(uint16_t*)&bit_data[u16_off+4]);
printf("T1 FAR_MAJ");
// BLK
u16 = (maj & 0xF000) >> 12;
printf(" BLK=%u", u16);
if (u16 > 7)
unexpected_blk_bit4 = 1;
// ROW
u16 = (maj & 0x0F00) >> 8;
printf(" ROW=%u", u16);
// MAJOR
u16 = maj & 0x00FF;
printf(" MAJOR=%u", u16);
// Block RAM
u16 = (min & 0xC000) >> 14;
printf(" BRAM=%u", u16);
// MINOR
u16 = min & 0x03FF;
printf(" MINOR=%u", u16);
if (min & 0x3C00)
printf(" 0x%x", min & 0x3C00);
printf("\n");
if (unexpected_blk_bit4)
printf("#W Unexpected BLK bit 4 set.\n");
// Reserved min bits 13:10 should be 000
// according to documentation.
if (min & 0x3C00)
printf("#W Expected reserved 0, got 0x%x.\n", (min & 0x3C00) > 10);
continue;
}
if (packet_hdr_register == MFWR) {
uint32_t first_dword, second_dword;
if (packet_hdr_wordcount != 4) {
fprintf(stderr, "#E 0x%x=0x%x Unexpected "
"MFWR wordcount %u.\n", u16_off,
u16, packet_hdr_wordcount);
goto fail;
}
first_dword = __be32_to_cpu(*(uint32_t*)&bit_data[u16_off+2]);
second_dword = __be32_to_cpu(*(uint32_t*)&bit_data[u16_off+6]);
if (first_dword || second_dword) {
fprintf(stderr, "#E 0x%x=0x%x Unexpected "
"MFWR data 0x%x 0x%x.\n", u16_off,
u16, first_dword, second_dword);
goto fail;
}
printf("T1 MFWR\n");
continue;
}
if (packet_hdr_register == CTL) {
if (packet_hdr_wordcount != 1) {
fprintf(stderr, "#E 0x%x=0x%x Unexpected CTL"
" wordcount %u.\n", u16_off,
u16, packet_hdr_wordcount);
goto fail;
}
u16 = __be16_to_cpu(*(uint16_t*)&bit_data[u16_off+2]);
u16_off+=2;
printf("T1 CTL");
if (u16 & 0x0040) {
printf(" DECRYPT");
u16 &= ~0x0040;
}
if (u16 & 0x0020) {
if (u16 & 0x0010)
printf(" SBITS=NO_RW");
else
printf(" SBITS=NO_READ");
u16 &= ~0x0030;
} else if (u16 & 0x0010) {
printf(" SBITS=ICAP_READ");
u16 &= ~0x0010;
}
if (u16 & 0x0008) {
printf(" PERSIST");
u16 &= ~0x0008;
}
if (u16 & 0x0004) {
printf(" USE_EFUSE_KEY");
u16 &= ~0x0004;
}
if (u16 & 0x0002) {
printf(" CRC_EXTSTAT_DISABLE");
u16 &= ~0x0002;
}
if (u16)
printf(" 0x%x", u16);
printf("\n");
// bit0 is reserved as 1, and we have seen
// bit7 on as well.
if (u16 != 0x81)
printf("#W Expected reserved 0x%x, got 0x%x.\n", 0x0081, u16);
continue;
}
if (packet_hdr_register == MASK) {
if (packet_hdr_wordcount != 1) {
fprintf(stderr, "#E 0x%x=0x%x Unexpected MASK"
" wordcount %u.\n", u16_off,
u16, packet_hdr_wordcount);
goto fail;
}
u16 = __be16_to_cpu(*(uint16_t*)&bit_data[u16_off+2]);
u16_off+=2;
printf("T1 MASK");
if (u16 & 0x0040) {
printf(" DECRYPT");
u16 &= ~0x0040;
}
if ((u16 & 0x0030) == 0x0030) {
printf(" SECURITY");
u16 &= ~0x0030;
}
if (u16 & 0x0008) {
printf(" PERSIST");
u16 &= ~0x0008;
}
if (u16 & 0x0004) {
printf(" USE_EFUSE_KEY");
u16 &= ~0x0004;
}
if (u16 & 0x0002) {
printf(" CRC_EXTSTAT_DISABLE");
u16 &= ~0x0002;
}
if (u16)
printf(" 0x%x", u16);
printf("\n");
// It seems bit7 and bit0 are always masked in.
if (u16 != 0x81)
printf("#W Expected reserved 0x%x, got 0x%x.\n", 0x0081, u16);
continue;
}
if (packet_hdr_register == PWRDN_REG) {
if (packet_hdr_wordcount != 1) {
fprintf(stderr, "#E 0x%x=0x%x Unexpected PWRDN_REG"
" wordcount %u.\n", u16_off,
u16, packet_hdr_wordcount);
goto fail;
}
u16 = __be16_to_cpu(*(uint16_t*)&bit_data[u16_off+2]);
u16_off+=2;
printf("T1 PWRDN_REG");
if (u16 & 0x4000) {
printf(" EN_EYES");
u16 &= ~0x4000;
}
if (u16 & 0x0020) {
printf(" FILTER_B");
u16 &= ~0x0020;
}
if (u16 & 0x0010) {
printf(" EN_PGSR");
u16 &= ~0x0010;
}
if (u16 & 0x0004) {
printf(" EN_PWRDN");
u16 &= ~0x0004;
}
if (u16 & 0x0001) {
printf(" KEEP_SCLK");
u16 &= ~0x0001;
}
if (u16)
printf(" 0x%x", u16);
printf("\n");
// Reserved bits 13:6 should be 00100010
// according to documentation.
if (u16 != 0x0880)
printf("#W Expected reserved 0x%x, got 0x%x.\n", 0x0880, u16);
continue;
}
if (packet_hdr_register == HC_OPT_REG) {
if (packet_hdr_wordcount != 1) {
fprintf(stderr, "#E 0x%x=0x%x Unexpected HC_OPT_REG"
" wordcount %u.\n", u16_off,
u16, packet_hdr_wordcount);
goto fail;
}
u16 = __be16_to_cpu(*(uint16_t*)&bit_data[u16_off+2]);
u16_off+=2;
printf("T1 HC_OPT_REG");
if (u16 & 0x0040) {
printf(" INIT_SKIP");
u16 &= ~0x0040;
}
if (u16)
printf(" 0x%x", u16);
printf("\n");
// Reserved bits 5:0 should be 011111
// according to documentation.
if (u16 != 0x001F)
printf("#W Expected reserved 0x%x, got 0x%x.\n", 0x001F, u16);
continue;
}
if (packet_hdr_register == PU_GWE) {
if (packet_hdr_wordcount != 1) {
fprintf(stderr, "#E 0x%x=0x%x Unexpected PU_GWE"
" wordcount %u.\n", u16_off,
u16, packet_hdr_wordcount);
goto fail;
}
u16 = __be16_to_cpu(*(uint16_t*)&bit_data[u16_off+2]);
u16_off+=2;
printf("T1 PU_GWE 0x%03X\n", u16);
continue;
}
if (packet_hdr_register == PU_GTS) {
if (packet_hdr_wordcount != 1) {
fprintf(stderr, "#E 0x%x=0x%x Unexpected PU_GTS"
" wordcount %u.\n", u16_off,
u16, packet_hdr_wordcount);
goto fail;
}
u16 = __be16_to_cpu(*(uint16_t*)&bit_data[u16_off+2]);
u16_off+=2;
printf("T1 PU_GTS 0x%03X\n", u16);
continue;
}
if (packet_hdr_register == CWDT) {
if (packet_hdr_wordcount != 1) {
fprintf(stderr, "#E 0x%x=0x%x Unexpected CWDT"
" wordcount %u.\n", u16_off,
u16, packet_hdr_wordcount);
goto fail;
}
u16 = __be16_to_cpu(*(uint16_t*)&bit_data[u16_off+2]);
u16_off+=2;
printf("T1 CWDT 0x%X\n", u16);
if (u16 < 0x0201)
printf("#W Watchdog timer clock below"
" minimum value of 0x0201.\n");
continue;
}
if (packet_hdr_register == MODE_REG) {
int unexpected_buswidth = 0;
if (packet_hdr_wordcount != 1) {
fprintf(stderr, "#E 0x%x=0x%x Unexpected MODE_REG"
" wordcount %u.\n", u16_off,
u16, packet_hdr_wordcount);
goto fail;
}
u16 = __be16_to_cpu(*(uint16_t*)&bit_data[u16_off+2]);
u16_off+=2;
printf("T1 MODE_REG");
if (u16 & (1<<13)) {
printf(" NEW_MODE=BITSTREAM");
u16 &= ~(1<<13);
}
if ((u16 & (1<<12))
&& (u16 & (1<<11)))
unexpected_buswidth = 1;
else if (u16 & (1<<12)) {
printf(" BUSWIDTH=4");
u16 &= ~(1<<12);
} else if (u16 & (1<<11)) {
printf(" BUSWIDTH=2");
u16 &= ~(1<<11);
}
// BUSWIDTH=1 is the default and not displayed
if (u16 & (1<<9)) {
printf(" BOOTMODE_1");
u16 &= ~(1<<9);
}
if (u16 & (1<<8)) {
printf(" BOOTMODE_0");
u16 &= ~(1<<8);
}
if (unexpected_buswidth)
printf("#W Unexpected bus width 0b11.\n");
if (u16)
printf(" 0x%x", u16);
printf("\n");
if (u16)
printf("#W Expected reserved 0, got 0x%x.\n", u16);
continue;
}
if (packet_hdr_register == CCLK_FREQ) {
if (packet_hdr_wordcount != 1) {
fprintf(stderr, "#E 0x%x=0x%x Unexpected CCLK_FREQ"
" wordcount %u.\n", u16_off,
u16, packet_hdr_wordcount);
goto fail;
}
u16 = __be16_to_cpu(*(uint16_t*)&bit_data[u16_off+2]);
u16_off+=2;
printf("T1 CCLK_FREQ");
if (u16 & (1<<14)) {
printf(" EXT_MCLK");
u16 &= ~(1<<14);
}
printf(" MCLK_FREQ=0x%03X", u16 & 0x03FF);
u16 &= ~(0x03FF);
if (u16)
printf(" 0x%x", u16);
printf("\n");
if (u16)
printf("#W Expected reserved 0, got 0x%x.\n", u16);
continue;
}
printf("#W T1 %s (%u words)",
xc6_regs[packet_hdr_register].name,
packet_hdr_wordcount);
if (packet_hdr_register == CRC) {
printf("\n"); // omit CRC for diff beauty
continue;
}
for (i = 0; (i < 8) && (i < packet_hdr_wordcount); i++)
printf(" 0x%x", __be16_to_cpu(*(uint16_t*)
&bit_data[u16_off+2+i*2]));
printf("\n");
continue;
}
// packet type must be 2 here
if (packet_hdr_wordcount != 0) {
printf("#W 0x%x=0x%x Unexpected Type 2 "
"wordcount.\n", u16_off, u16);
}
if (packet_hdr_register != FDRI) {
fprintf(stderr, "#E 0x%x=0x%x Unexpected Type 2 "
"register.\n", u16_off, u16);
goto fail;
}
if (bit_cur + 4 > bit_eof) goto fail_eof;
u32 = __be32_to_cpu(*(uint32_t*)&bit_data[bit_cur]);
bit_cur += 4;
printf("T2 FDRI\n");
if (bit_cur + 2*u32 > bit_eof) goto fail_eof;
if (2*u32 < 130) {
fprintf(stderr, "#E 0x%x=0x%x Unexpected Type2"
" length %u.\n", u16_off, u16, 2*u32);
goto fail;
}
num_frames = (2*u32)/130;
for (i = 0; i < num_frames; i++) {
int first64_all_zero, last64_all_zero;
uint8_t middle_byte0, middle_byte1;
int count, cur_row, cur_major, cur_minor;
if (i >= type1_bram_data_start_frame) break;
if (i%(505+2) == 0 && info)
printf("\n#D row %i\n", i/505);
else if (!i)
printf("\n");
cur_row = i/(505+2);
if (i%(505+2) == 505) {
// If two frames of all one are following,
// it's standard padding and we don't need
// to display anything.
if (i + 2 < num_frames) {
for (j = 0; j < 2*130; j++) {
if (bit_data[bit_cur+i*130+j]
!= 0xFF)
break;
}
if (j >= 2*130) {
i++;
continue;
}
}
printf("\n#D padding\n");
}
cur_major = 0;
cur_minor = 0;
count = 0;
for (j = 0; j < sizeof(majors)/sizeof(majors[0]); j++) {
if (count + majors[j].minors > i%(505+2)) {
cur_major = j;
cur_minor = i%(505+2) - count;
break;
}
count += majors[j].minors;
}
if (!cur_minor) {
if (i+majors[cur_major].minors <= num_frames) {
for (j = 0; j <
majors[cur_major].minors * 130; j++) {
if (bit_data[bit_cur+i*130+j])
break;
}
if (j >= majors[cur_major].minors*130) {
if (majors[cur_major].minors > 1)
i += majors[cur_major].minors - 1;
continue;
}
}
if (info) {
printf("\n#D r%i major %i (%s) minors "
"%i\n", cur_row, cur_major,
majors[cur_major].name ?
majors[cur_major].name : "?",
majors[cur_major].minors);
}
}
if (cur_major == 4 && cur_minor == 23
&& i+1 < num_frames
&& !(__be16_to_cpu(*(uint16_t*)&bit_data[bit_cur+i*130+64]))
&& !(__be16_to_cpu(*(uint16_t*)&bit_data[bit_cur+i*130+130+64]))
&& (cur_row > 0)) {
ramb16_cfg_t ramb16_cfg;
for (j = 0; j < 4; j++) {
offset_in_frame = (3-j)*32;
if (offset_in_frame >= 64)
offset_in_frame += 2;
for (k = 0; k < 32; k++) {
ramb16_cfg.byte[k] = bit_data[bit_cur+i*130+offset_in_frame+k];
ramb16_cfg.byte[k+32] = bit_data[bit_cur+i*130+130+offset_in_frame+k];
}
for (k = 0; k < 64; k++) {
if (ramb16_cfg.byte[k])
break;
}
if (k >= 64) continue; // empty
printf("RAMB16_X0Y%i config\n", ((cur_row-1)*4 + j)*2);
print_ramb16_cfg(&ramb16_cfg);
}
i++; // we processed two frames
continue;
}
middle_byte0 = bit_data[bit_cur+i*130+64];
middle_byte1 = bit_data[bit_cur+i*130+65];
first64_all_zero = 1;
last64_all_zero = 1;
for (j = 0; j < 64; j++) {
if (bit_data[bit_cur+i*130+j] != 0) {
first64_all_zero = 0;
break;
}
}
for (j = 66; j < 130; j++) {
if (bit_data[bit_cur+i*130+j] != 0) {
last64_all_zero = 0;
break;
}
}
if (!(first64_all_zero && !middle_byte0 &&
!middle_byte1 && last64_all_zero)) {
for (j = 0; j < 16; j++) {
if ((j < 8 && middle_byte1 & (1<<(7-j)))
|| (j >= 8 && middle_byte0 & (1<<(7-j-8))))
printf("cfg r%i m%i-%i/%i c%i ?\n",
cur_row, cur_major,
cur_minor,
majors[cur_major].minors, j);
}
for (j = 0; j < 1024; j++) {
int word_o, byte_o, bit_o;
word_o = j / 16;
if (word_o >= 64)
word_o++;
byte_o = !((j/8)%2);
bit_o = 7-(j%8);
if (bit_data[bit_cur+i*130+word_o*2+byte_o] & (1<<bit_o))
printf("cfg r%i m%i-%i/%i b%i ?\n",
cur_row, cur_major,
cur_minor,
majors[cur_major].minors, j);
}
if (info) {
printf("hex r%i m%i-%i/%i\n", cur_row,
cur_major, cur_minor,
majors[cur_major].minors);
hexdump(1, &bit_data[bit_cur+i*130], 130);
}
continue;
}
max_frames_to_scan = num_frames - i - 1;
if (i + 1 + max_frames_to_scan >= ((i/507)+1)*507 - 2)
max_frames_to_scan = ((i/507)+1)*507 - i - 3;
count = 0;
for (j = 0; j < sizeof(majors)/sizeof(majors[0]); j++) {
if ((i/507)*507 + count > i
&& (i/507)*507 + count <= i+1+max_frames_to_scan) {
max_frames_to_scan = (i/507)*507 + count - i - 1;
break;
}
count += majors[j].minors;
}
for (j = 0; j < max_frames_to_scan*130; j++) {
if (bit_data[bit_cur+i*130+130+j] != 0)
break;
}
if (j/130) {
if (info)
printf("frame_130 times %i all_0\n", 1+j/130);
i += j/130;
continue;
}
if (info)
printf("frame_130 all_0\n");
continue;
}
for (i = type1_bram_data_start_frame; i < num_frames; i++) {
static const int ram_starts[] =
{ 144, 162, 180, 198,
288, 306, 324, 342,
432, 450, 468, 486 };
if (i >= type2_iob_start_frame)
break;
if (i == type1_bram_data_start_frame) {
if (info) printf("#D type 1 bram data start "
"frame %i", i);
}
if (((i-type1_bram_data_start_frame) % 144) == 0
&& info)
printf("\n#D bram row %i\n", (i-type1_bram_data_start_frame)/144);
for (j = 0; j < sizeof(ram_starts) / sizeof(ram_starts[0]); j++) {
if (i == type1_bram_data_start_frame + ram_starts[j]
&& num_frames >= i+18)
break;
}
if (j < sizeof(ram_starts) / sizeof(ram_starts[0])) {
uint8_t init_byte;
char init_str[65];
int print_header = j*2;
// We are at the beginning of a RAMB16 block
// (or two RAMB8 blocks), and have the full
// 18 frames available.
// Verify that the first and last 18 bytes are
// all 0. If not, hexdump them.
for (j = 0; j < 18; j++) {
if (bit_data[bit_cur+i*130+j] != 0)
break;
}
if (j < 18) {
if (print_header != -1) {
printf("\nRAMB16_X0Y%i data\n",
print_header);
print_header = -1;
}
printf("ramb16_head");
for (j = 0; j < 18; j++)
printf(" %02x", bit_data[bit_cur+i*130+j]);
printf("\n");
}
for (j = 0; j < 18; j++) {
if (bit_data[bit_cur+(i+18)*130-18+j] != 0)
break;
}
if (j < 18) {
if (print_header != -1) {
printf("\nRAMB16_X0Y%i data\n",
print_header);
print_header = -1;
}
printf("ramb16_tail");
for (j = 0; j < 18; j++)
printf(" %02x", bit_data[bit_cur+(i+18)*130-18+j]);
printf("\n");
}
for (j = 0; j < 8; j++) { // 8 parity configs
for (k = 0; k < 32; k++) { // 32 bytes per config
init_byte = 0;
for (l = 0; l < 8; l++) {
bit_off = (j*(2048+256)) + (31-k)*4*18;
bit_off += 1+(l/2)*18-(l&1);
if (bit_data[bit_cur+i*130+18+bit_off/8] & (1<<(7-(bit_off%8))))
init_byte |= 1<<l;
}
sprintf(&init_str[k*2], "%02x", init_byte);
}
for (k = 0; k < 64; k++) {
if (init_str[k] != '0')
break;
}
if (k < 64) {
if (print_header != -1) {
printf("\nRAMB16_X0Y%i "
"data\n",
print_header);
print_header = -1;
}
printf("initp_%02i \"%s\"\n",
j, init_str);
}
}
for (j = 0; j < 32; j++) {
for (k = 0; k < 32; k++) { // 32 bytes per config
init_byte = 0;
for (l = 0; l < 8; l++) {
bit_off = (j*(2048+256)) + ((31-k)/2)*18 + (8-((31-k)&1)*8) + 2 + l;
if (bit_data[bit_cur+i*130+18+bit_off/8] & (1<<(7-(bit_off%8))))
init_byte |= 1<<(7-l);
}
sprintf(&init_str[k*2], "%02x", init_byte);
}
for (k = 0; k < 64; k++) {
if (init_str[k] != '0')
break;
}
if (k < 64) {
if (print_header != -1) {
printf("\nRAMB16_X0Y%i "
"data\n",
print_header);
print_header = -1;
}
printf("init_%02i \"%s\"\n",
j, init_str);
}
}
i += 17; // 17 (+1) frames have been processed
continue;
}
// everything from now on should be 0
for (j = 0; j < 130; j++) {
if (bit_data[bit_cur+i*130+j]) {
printf("frame_130 %i frames into "
"content, file off 0x%xh (%i)\n",
i-type1_bram_data_start_frame,
bit_cur+i*130, bit_cur+i*130);
hexdump(1, &bit_data[bit_cur+i*130],
130);
continue;
}
}
// Check whether more all zero frames are following.
// That way we can make the output more readable.
max_frames_to_scan = num_frames - i - 1;
if (max_frames_to_scan > type2_iob_start_frame - i - 1)
max_frames_to_scan = type2_iob_start_frame - i - 1;
for (j = 0; j < sizeof(ram_starts) / sizeof(ram_starts[0]); j++) {
if ((type1_bram_data_start_frame + ram_starts[j] > i)
&& (type1_bram_data_start_frame + ram_starts[j] <= i+1+max_frames_to_scan)) {
max_frames_to_scan = type1_bram_data_start_frame+ram_starts[j] - i - 1;
// ram_starts is sorted in ascending order
break;
}
}
for (j = 0; j < max_frames_to_scan*130; j++) {
if (bit_data[bit_cur+i*130+130+j] != 0)
break;
}
if (j/130) {
if (info)
printf("frame_130 times %i all_0\n",
1+j/130);
i += j/130;
continue;
}
printf("frame_130 all_0\n");
continue;
}
last_processed_pos = i*130;
if (i == type2_iob_start_frame) {
int iob_end_pos;
printf("\n");
if (info) printf("#D type 2 iob start frame %i\n", i);
iob_end_pos = (type2_iob_start_frame*130 + (g_FLR_value+1)*2);
if (g_FLR_value == -1)
printf("#W No FLR value set, cannot process IOB block.\n");
else if (iob_end_pos > 2*u32)
printf("#W Expected %i bytes IOB data, only got %i.\n",
(g_FLR_value+1)*2, 2*u32 - (g_FLR_value+1)*2);
else {
uint16_t post_iob_padding;
if (g_FLR_value*2/8 != sizeof(iob_xc6slx4_sitenames)/sizeof(iob_xc6slx4_sitenames[0]))
printf("#W Expected %li IOB entries but got %i.\n",
sizeof(iob_xc6slx4_sitenames)/sizeof(iob_xc6slx4_sitenames[0]),
g_FLR_value*2/8);
for (j = 0; j < g_FLR_value*2/8; j++) {
if (*(uint32_t*)&bit_data[bit_cur+type2_iob_start_frame*130+j*8]
|| *(uint32_t*)&bit_data[bit_cur+type2_iob_start_frame*130+j*8+4]) {
if (j < sizeof(iob_xc6slx4_sitenames)/sizeof(iob_xc6slx4_sitenames[0])
&& iob_xc6slx4_sitenames[j]) {
printf("iob %s", iob_xc6slx4_sitenames[j]);
} else
printf("iob %i", j);
for (k = 0; k < 8; k++)
printf(" %02X", bit_data[bit_cur+type2_iob_start_frame*130+j*8+k]);
printf("\n");
}
}
if (info) hexdump(1, &bit_data[bit_cur+type2_iob_start_frame*130], g_FLR_value*2);
post_iob_padding = __be16_to_cpu(*(uint16_t*)&bit_data[bit_cur+type2_iob_start_frame*130+g_FLR_value*2]);
if (post_iob_padding)
printf("#W Unexpected post IOB padding 0x%x.\n", post_iob_padding);
if (iob_end_pos < 2*u32)
printf("#W Extra data after IOB.\n");
printf("\n");
last_processed_pos = iob_end_pos;
}
}
if (last_processed_pos < 2*u32) {
int dump_len = 2*u32 - last_processed_pos;
printf("#D hexdump offset 0x%x, len 0x%x (%i)\n",
last_processed_pos, dump_len, dump_len);
hexdump(1, &bit_data[bit_cur+last_processed_pos], dump_len);
}
bit_cur += u32*2;
if (bit_cur + 4 > bit_eof) goto fail_eof;
u32 = __be32_to_cpu(*(uint32_t*)&bit_data[bit_cur]);
if (info) printf("#I 0x%x=0x%x Ignoring Auto-CRC.\n", bit_cur, u32);
bit_cur += 4;
}
free(bit_data);
return EXIT_SUCCESS;
fail_eof:
fprintf(stderr, "#E Unexpected EOF.\n");
fail:
free(bit_data);
return EXIT_FAILURE;
}
void help()
{
printf("\n"
"bit2txt %s - convert FPGA bitstream to text\n"
"(c) 2012 Wolfgang Spraul\n"
"\n"
"bit2txt [options] <path to .bit file>\n"
" --help print help message\n"
" --version print version number\n"
" --info add extra info to output (marked #I)\n"
" <path to .bit file> bitstream to print on stdout\n"
" (proposing extension .b2t)\n"
"\n", PROGRAM_REVISION);
}