1620 lines
45 KiB
C
1620 lines
45 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 "helper.h"
|
|
|
|
// 120 MB max bitstream size is enough for now
|
|
#define BITSTREAM_READ_PAGESIZE 4096
|
|
#define BITSTREAM_READ_MAXPAGES 30000 // 120 MB max bitstream
|
|
|
|
//
|
|
// 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
|
|
};
|
|
|
|
// 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;
|
|
|
|
#define XC6SLX4 0x04000093
|
|
#define XC6SLX9 0x04001093
|
|
#define XC6SLX16 0x04002093
|
|
#define XC6SLX25 0x04004093
|
|
#define XC6SLX25T 0x04024093
|
|
#define XC6SLX45 0x04008093
|
|
#define XC6SLX45T 0x04028093
|
|
#define XC6SLX75 0x0400E093
|
|
#define XC6SLX75T 0x0402E093
|
|
#define XC6SLX100 0x04011093
|
|
#define XC6SLX100T 0x04031093
|
|
#define XC6SLX150 0x0401D093
|
|
|
|
const IDCODE_S idcodes[] =
|
|
{
|
|
{"XC6SLX4", XC6SLX4},
|
|
{"XC6SLX9", XC6SLX9},
|
|
{"XC6SLX16", XC6SLX16},
|
|
{"XC6SLX25", XC6SLX25},
|
|
{"XC6SLX25T", XC6SLX25T},
|
|
{"XC6SLX45", XC6SLX45},
|
|
{"XC6SLX45T", XC6SLX45T},
|
|
{"XC6SLX75", XC6SLX75},
|
|
{"XC6SLX75T", XC6SLX75T},
|
|
{"XC6SLX100", XC6SLX100},
|
|
{"XC6SLX100T", XC6SLX100T},
|
|
{"XC6SLX150", XC6SLX150}
|
|
};
|
|
|
|
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 enum {
|
|
MAJ_EXTRA = -1,
|
|
MAJ_CLB, MAJ_BRAM, MAJ_DSP
|
|
} major_t;
|
|
|
|
typedef struct
|
|
{
|
|
char* name;
|
|
int minors;
|
|
major_t type;
|
|
} MAJOR;
|
|
|
|
const MAJOR majors[] =
|
|
{
|
|
/* 0 */ { 0, 4, MAJ_EXTRA }, // 505 bytes = middle 8-bit
|
|
// for each minor?
|
|
/* 1 */ { 0, 30, MAJ_EXTRA },
|
|
/* 2 */ { "clb", 31, MAJ_CLB },
|
|
/* 3 */ { 0, 30, MAJ_EXTRA },
|
|
/* 4 */ { "bram", 25, MAJ_BRAM },
|
|
/* 5 */ { "clb", 31, MAJ_CLB },
|
|
/* 6 */ { 0, 30, MAJ_EXTRA },
|
|
/* 7 */ { "dsp", 24, MAJ_DSP },
|
|
/* 8 */ { "clb", 31, MAJ_CLB },
|
|
/* 9 */ { 0, 31, MAJ_EXTRA },
|
|
/* 10 */ { "clb", 31, MAJ_CLB },
|
|
/* 11 */ { 0, 30, MAJ_EXTRA },
|
|
/* 12 */ { 0, 31, MAJ_EXTRA },
|
|
/* 13 */ { 0, 30, MAJ_EXTRA },
|
|
/* 14 */ { 0, 25, MAJ_EXTRA },
|
|
/* 15 */ { "clb", 31, MAJ_CLB },
|
|
/* 16 */ { 0, 30, MAJ_EXTRA },
|
|
/* 17 */ { 0, 30, MAJ_EXTRA }
|
|
};
|
|
|
|
typedef struct ramb16_cfg
|
|
{
|
|
uint8_t byte[64];
|
|
} __attribute((packed)) ramb16_cfg_t;
|
|
|
|
static const cfg_atom_t ramb16_instance =
|
|
{
|
|
{-1}, {12,13, 274,275,276,277,316,317,318,319,
|
|
420,421,422,423,-1}, "default_bits"
|
|
};
|
|
|
|
static cfg_atom_t ramb16_atoms[] =
|
|
{
|
|
// data_width_a
|
|
{{264,265,260,261,256,257,-1},{ -1},"data_width_a 1"},
|
|
{{264,265,260,261, -1},{ 256,257,-1},"data_width_a 2"},
|
|
{{264,265, 256,257,-1},{ 260,261, -1},"data_width_a 4"},
|
|
{{264,265, -1},{ 260,261,256,257,-1},"data_width_a 9"},
|
|
{{ 260,261,256,257,-1},{264,265, -1},"data_width_a 18"},
|
|
{{ 260,261, -1},{264,265, 256,257,-1},"data_width_a 36"},
|
|
{{ -1},{264,265,260,261,256,257,-1},"data_width_a 0"},
|
|
|
|
// data_width_b
|
|
{{262,263,286,287,258,259,-1},{ -1},"data_width_b 1"},
|
|
{{262,263,286,287, -1},{ 258,259,-1},"data_width_b 2"},
|
|
{{262,263, 258,259,-1},{ 286,287, -1},"data_width_b 4"},
|
|
{{262,263, -1},{ 286,287,258,259,-1},"data_width_b 9"},
|
|
{{ 286,287,258,259,-1},{262,263, -1},"data_width_b 18"},
|
|
{{ 286,287, -1},{262,263, 258,259,-1},"data_width_b 36"},
|
|
{{ -1},{262,263,286,287,258,259,-1},"data_width_b 0"},
|
|
|
|
// required
|
|
{ { -1}, {266, 267, -1}, "RST_PRIORITY_B:CE" },
|
|
{ {266, 267, -1}, { -1}, "RST_PRIORITY_B:SR" },
|
|
{ { -1}, {268, 269, -1}, "RST_PRIORITY_A:CE" },
|
|
{ {268, 269, -1}, { -1}, "RST_PRIORITY_A:SR" },
|
|
{ { -1}, {290, 291, -1}, "EN_RSTRAM_A:TRUE" },
|
|
{ {290, 291, -1}, { -1}, "EN_RSTRAM_A:FALSE" },
|
|
{ { -1}, {444, 445, -1}, "EN_RSTRAM_B:TRUE" },
|
|
{ {444, 445, -1}, { -1}, "EN_RSTRAM_B:FALSE" },
|
|
|
|
// optional
|
|
{ { -1}, { 26, 27, -1}, "CLKAINV:CLKA" },
|
|
{ { 26, 27, -1}, { -1}, "CLKAINV:CLKA_B" }, // def
|
|
{ { -1}, { 30, 31, -1}, "CLKBINV:CLKB" },
|
|
{ { 30, 31, -1}, { -1}, "CLKBINV:CLKB_B" }, // def
|
|
{ { -1}, {270, 271, -1}, "RSTTYPE:ASYNC" },
|
|
{ {270, 271, -1}, { -1}, "RSTTYPE:SYNC" }, // def
|
|
{ { -1}, {278, 279, -1}, "WRITE_MODE_B:READ_FIRST" },
|
|
{ { -1}, {280, 281, -1}, "WRITE_MODE_A:READ_FIRST" },
|
|
{ { -1}, {282, 283, -1}, "WRITE_MODE_B:NO_CHANGE" },
|
|
{ { -1}, {284, 285, -1}, "WRITE_MODE_A:NO_CHANGE" },
|
|
{ {278, 279, 282, 283, -1}, {-1}, "WRITE_MODE_B:WRITE_FIRST" }, //def
|
|
{ {280, 281, 284, 285, -1}, {-1}, "WRITE_MODE_A:WRITE_FIRST" }, //def
|
|
{ { -1}, {306, 307, -1}, "DOB_REG:1" },
|
|
{ {306, 306, -1}, { -1}, "DOB_REG:0" }, // def
|
|
{ { -1}, {308, 309, -1}, "DOA_REG:1" },
|
|
{ {308, 309, -1}, { -1}, "DOA_REG:0" }, // def
|
|
{ {431, 467, -1}, {430, 466, -1}, "ENAINV:ENA" }, // def
|
|
{ {430, 431, 466, 467, -1}, {-1}, "ENAINV:ENA_B" },
|
|
{ {465, 469, -1}, {464, 468, -1}, "ENBINV:ENB" }, // def
|
|
{ {464, 465, 468, 469, -1}, {-1}, "ENBINV:ENB_B" },
|
|
{ { -1}, { 20, 21, -1}, "REGCEAINV:REGCEA" }, // def
|
|
{ { 20, 21, -1}, { -1}, "REGCEAINV:REGCEA_B" },
|
|
{ { -1}, { 8, 9, -1}, "REGCEBINV:REGCEB" },
|
|
{ { 8, 9, -1}, { -1}, "REGCEBINV:REGCEB_B" }, // def
|
|
{ { 24, 25, -1}, { -1}, "RSTAINV:RSTA" }, // def
|
|
{ { -1}, { 24, 25, -1}, "RSTAINV:RSTA_B" },
|
|
{ { -1}, { 4, 5, -1}, "RSTBINV:RSTB" }, // def
|
|
{ { 4, 5, -1}, { -1}, "RSTBINV:RSTB_B" },
|
|
{ { -1}, { 19, -1}, "WEA0INV:WEA0" }, // def
|
|
{ { 19, -1}, { -1}, "WEA0INV:WEA0_B" },
|
|
{ { -1}, { 23, -1}, "WEA2INV:WEA1" }, // def
|
|
{ { 23, -1}, { -1}, "WEA2INV:WEA1_B" },
|
|
{ { -1}, { 18, -1}, "WEA2INV:WEA2" }, // def
|
|
{ { 18, -1}, { -1}, "WEA2INV:WEA2_B" },
|
|
{ { -1}, { 22, -1}, "WEA2INV:WEA3" }, // def
|
|
{ { 22, -1}, { -1}, "WEA2INV:WEA3_B" },
|
|
{ { -1}, { 7, -1}, "WEB0INV:WEB0" }, // def
|
|
{ { 7, -1}, { -1}, "WEB0INV:WEB0_B" },
|
|
{ { -1}, { 3, -1}, "WEB1INV:WEB1" }, // def
|
|
{ { 3, -1}, { -1}, "WEB1INV:WEB1_B" },
|
|
{ { -1}, { 6, -1}, "WEB2INV:WEB2" }, // def
|
|
{ { 6, -1}, { -1}, "WEB2INV:WEB2_B" },
|
|
{ { -1}, { 2, -1}, "WEB3INV:WEB3" }, // def
|
|
{ { 2, -1}, { -1}, "WEB3INV:WEB3_B" },
|
|
};
|
|
|
|
int g_cmd_frames = 0;
|
|
int g_cmd_info = 0; // whether to print #I info messages (offsets and others)
|
|
|
|
void print_ramb16_cfg(ramb16_cfg_t* cfg)
|
|
{
|
|
char bits[512];
|
|
uint8_t u8;
|
|
int i, first_extra;
|
|
|
|
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;
|
|
}
|
|
|
|
//
|
|
// Bits 0..255 come from minor 23, Bits 256..511 from minor 24.
|
|
// Each set of 256 bits is divided into two halfs of 128 bits
|
|
// that are swept forward and backward to form 2-bit pairs,
|
|
// pairs 0..127 are formed out of bits 0..127 and 255..128,
|
|
// p128..p255 are formed out of b256..b383 and b511..b384.
|
|
// Since so much bit twiddling is already happening, we are sorting
|
|
// the bits so that pairs are next to each other.
|
|
// The notation for a pair is "p8=01".
|
|
|
|
// minor 23
|
|
for (i = 0; i < 128; i++) {
|
|
bits[i*2] = (cfg->byte[i/8] & (1<<(i%8))) != 0;
|
|
bits[i*2+1] = (cfg->byte[(255-i)/8]
|
|
& (1<<(7-(i%8)))) != 0;
|
|
}
|
|
// minor 24
|
|
for (i = 0; i < 128; i++) {
|
|
bits[256+i*2] = (cfg->byte[32+i/8] & (1<<(i%8))) != 0;
|
|
bits[256+i*2+1] = (cfg->byte[32+(255-i)/8]
|
|
& (1<<(7-(i%8)))) != 0;
|
|
}
|
|
|
|
printf("{\n");
|
|
// hexdump(1 /* indent */, &cfg->byte[0], 64 /* len */);
|
|
for (i = 0; i < sizeof(ramb16_atoms)/sizeof(ramb16_atoms[0]); i++) {
|
|
if (atom_found(bits, &ramb16_atoms[i])
|
|
&& ramb16_atoms[i].must_1[0] != -1) {
|
|
printf(" %s\n", ramb16_atoms[i].str);
|
|
ramb16_atoms[i].flag = 1;
|
|
} else
|
|
ramb16_atoms[i].flag = 0;
|
|
}
|
|
for (i = 0; i < sizeof(ramb16_atoms)/sizeof(ramb16_atoms[0]); i++) {
|
|
if (ramb16_atoms[i].flag)
|
|
atom_remove(bits, &ramb16_atoms[i]);
|
|
}
|
|
// instantiation bits
|
|
if (ramb16_instance.must_1[0] != -1) {
|
|
if (atom_found(bits, &ramb16_instance)) {
|
|
for (i = 0; ramb16_instance.must_1[i] != -1; i++)
|
|
printf(" b%i\n", ramb16_instance.must_1[i]);
|
|
atom_remove(bits, &ramb16_instance);
|
|
} else
|
|
printf(" #W Not all instantiation bits set.\n");
|
|
}
|
|
// extra bits
|
|
first_extra = 1;
|
|
for (i = 0; i < 512; i++) {
|
|
if (bits[i]) {
|
|
if (first_extra) {
|
|
printf(" #W Extra bits set.\n");
|
|
first_extra = 0;
|
|
}
|
|
printf(" b%i\n", i);
|
|
}
|
|
}
|
|
printf("}\n");
|
|
}
|
|
|
|
int FAR_pos(int FAR_row, int FAR_major, int FAR_minor)
|
|
{
|
|
int result, i;
|
|
|
|
if (FAR_row < 0 || FAR_major < 0 || FAR_minor < 0)
|
|
return -1;
|
|
if (FAR_row > 3 || FAR_major > 17
|
|
|| FAR_minor >= majors[FAR_major].minors)
|
|
return -1;
|
|
result = FAR_row * 505*130;
|
|
for (i = 0; i < FAR_major; i++)
|
|
result += majors[i].minors*130;
|
|
return result + FAR_minor*130;
|
|
}
|
|
|
|
int full_map(uint8_t* bit_file, int bf_len, int first_FAR_off,
|
|
uint8_t** bits, int* bits_len, int idcode, int FLR_len, int* outdelta)
|
|
{
|
|
int src_off, packet_hdr_type, packet_hdr_opcode;
|
|
int packet_hdr_register, packet_hdr_wordcount;
|
|
int FAR_block, FAR_row, FAR_major, FAR_minor, i, j, MFW_src_off;
|
|
int offset_in_bits, block0_words, padding_frames;
|
|
uint16_t u16;
|
|
uint32_t u32;
|
|
|
|
*bits = 0;
|
|
if (idcode != XC6SLX4) goto fail;
|
|
if (FLR_len != 896) goto fail;
|
|
|
|
*bits_len = (4*505 + 4*144) * 130 + 896*2;
|
|
*bits = calloc(*bits_len, 1 /* elsize */);
|
|
if (!(*bits)) {
|
|
fprintf(stderr, "#E Cannot allocate %i bytes for bits.\n",
|
|
*bits_len);
|
|
goto fail;
|
|
}
|
|
FAR_block = -1;
|
|
FAR_row = -1;
|
|
FAR_major = -1;
|
|
FAR_minor = -1;
|
|
MFW_src_off = -1;
|
|
// Go through bit_file from first_FAR_off until last byte of
|
|
// IOB was read, plus padding, plus CRC verification.
|
|
src_off = first_FAR_off;
|
|
while (src_off < bf_len) {
|
|
if (src_off + 2 > bf_len) goto fail;
|
|
u16 = __be16_to_cpu(*(uint16_t*)&bit_file[src_off]);
|
|
src_off += 2;
|
|
|
|
// 3 bits: 001 = Type 1; 010 = Type 2
|
|
packet_hdr_type = (u16 & 0xE000) >> 13;
|
|
if (packet_hdr_type != 1 && packet_hdr_type != 2)
|
|
goto fail;
|
|
|
|
// 2 bits: 00 = noop; 01 = read; 10 = write; 11 = reserved
|
|
packet_hdr_opcode = (u16 & 0x1800) >> 11;
|
|
if (packet_hdr_opcode == 3) goto fail;
|
|
|
|
if (packet_hdr_opcode == 0) { // noop
|
|
if (packet_hdr_type != 1 || u16 & 0x07FF) goto fail;
|
|
continue;
|
|
}
|
|
|
|
// Now we must look at a Type 1 command
|
|
packet_hdr_register = (u16 & 0x07E0) >> 5;
|
|
packet_hdr_wordcount = u16 & 0x001F;
|
|
if (src_off + packet_hdr_wordcount*2 > bf_len) goto fail;
|
|
|
|
if (packet_hdr_type == 1) {
|
|
if (packet_hdr_register == CMD) {
|
|
if (packet_hdr_wordcount != 1) goto fail;
|
|
u16 = __be16_to_cpu(
|
|
*(uint16_t*)&bit_file[src_off]);
|
|
if (u16 == CMD_GRESTORE || u16 == CMD_LFRM) {
|
|
src_off -= 2;
|
|
goto success;
|
|
}
|
|
if (u16 != CMD_MFW && u16 != CMD_WCFG)
|
|
goto fail;
|
|
if (u16 == CMD_MFW) {
|
|
if (FAR_block != 0) goto fail;
|
|
MFW_src_off = FAR_pos(FAR_row, FAR_major, FAR_minor);
|
|
if (MFW_src_off == -1) goto fail;
|
|
}
|
|
src_off += 2;
|
|
continue;
|
|
}
|
|
if (packet_hdr_register == FAR_MAJ) {
|
|
uint16_t maj, min;
|
|
|
|
if (packet_hdr_wordcount != 2) goto fail;
|
|
maj = __be16_to_cpu(*(uint16_t*)
|
|
&bit_file[src_off]);
|
|
min = __be16_to_cpu(*(uint16_t*)
|
|
&bit_file[src_off+2]);
|
|
|
|
FAR_block = (maj & 0xF000) >> 12;
|
|
if (FAR_block > 7) goto fail;
|
|
FAR_row = (maj & 0x0F00) >> 8;
|
|
FAR_major = maj & 0x00FF;
|
|
FAR_minor = min & 0x03FF;
|
|
src_off += 4;
|
|
continue;
|
|
}
|
|
if (packet_hdr_register == MFWR) {
|
|
uint32_t first_dword, second_dword;
|
|
|
|
if (packet_hdr_wordcount != 4) goto fail;
|
|
first_dword = __be32_to_cpu(
|
|
*(uint32_t*)&bit_file[src_off]);
|
|
second_dword = __be32_to_cpu(
|
|
*(uint32_t*)&bit_file[src_off+4]);
|
|
if (first_dword || second_dword) goto fail;
|
|
// The first MFWR will overwrite itself, so
|
|
// use memmove().
|
|
if (FAR_block != 0) goto fail;
|
|
offset_in_bits = FAR_pos(FAR_row, FAR_major, FAR_minor);
|
|
if (offset_in_bits == -1) goto fail;
|
|
memmove(&(*bits)[offset_in_bits], &(*bits)[MFW_src_off], 130);
|
|
|
|
src_off += 8;
|
|
continue;
|
|
}
|
|
goto fail;
|
|
}
|
|
|
|
// packet type must be 2 here
|
|
if (packet_hdr_wordcount != 0) goto fail;
|
|
if (packet_hdr_register != FDRI) goto fail;
|
|
|
|
if (src_off + 4 > bf_len) goto fail;
|
|
u32 = __be32_to_cpu(*(uint32_t*)&bit_file[src_off]);
|
|
src_off += 4;
|
|
if (src_off+2*u32 > bf_len) goto fail;
|
|
if (2*u32 < 130) goto fail;
|
|
|
|
// fdri words u32
|
|
if (FAR_block == -1 || FAR_block > 1 || FAR_row == -1
|
|
|| FAR_major == -1 || FAR_minor == -1)
|
|
goto fail;
|
|
|
|
block0_words = 0;
|
|
if (!FAR_block) {
|
|
|
|
offset_in_bits = FAR_pos(FAR_row, FAR_major, FAR_minor);
|
|
if (offset_in_bits == -1) goto fail;
|
|
if (!FAR_row && !FAR_major && !FAR_minor
|
|
&& u32 > 4*(505+2)*65)
|
|
block0_words = 4*(505+2)*65;
|
|
else {
|
|
block0_words = u32;
|
|
if (block0_words % 65) goto fail;
|
|
}
|
|
padding_frames = 0;
|
|
for (i = 0; i < block0_words/65; i++) {
|
|
if (i && i+1 == block0_words/65) {
|
|
for (j = 0; j < 130; j++) {
|
|
if (bit_file[src_off+i*130+j]
|
|
!= 0xFF) break;
|
|
}
|
|
// Not sure about the exact logic to
|
|
// determine a padding frame. Maybe
|
|
// first word all 1? For now we skip
|
|
// the frame as a padding frame when
|
|
// it's the last frame of a block and
|
|
// all-1.
|
|
if (j >= 130)
|
|
break;
|
|
}
|
|
if (!FAR_major && !FAR_minor
|
|
&& (i%507 == 505)) {
|
|
for (j = 0; j < 2*130; j++) {
|
|
if (bit_file[src_off+i*130+j]
|
|
!= 0xFF) goto fail;
|
|
}
|
|
i++;
|
|
padding_frames += 2;
|
|
continue;
|
|
}
|
|
memcpy(&(*bits)[offset_in_bits
|
|
+ (i-padding_frames)*130],
|
|
&bit_file[src_off
|
|
+ i*130], 130);
|
|
}
|
|
}
|
|
if (u32 - block0_words > 0) {
|
|
int bram_data_words = 4*144*65 + 896;
|
|
if (u32 - block0_words != bram_data_words + 1) goto fail;
|
|
offset_in_bits = 4*505*130;
|
|
memcpy(&(*bits)[offset_in_bits],
|
|
&bit_file[src_off+block0_words*2],
|
|
bram_data_words*2);
|
|
u16 = __be16_to_cpu(*(uint16_t*)&bit_file[
|
|
(src_off+block0_words+bram_data_words)*2]);
|
|
if (u16) goto fail;
|
|
}
|
|
src_off += 2*u32;
|
|
// two CRC words
|
|
u32 = __be32_to_cpu(*(uint32_t*)&bit_file[src_off]);
|
|
src_off += 4;
|
|
}
|
|
fail:
|
|
free(*bits);
|
|
*bits = 0;
|
|
return -1;
|
|
success:
|
|
*outdelta = src_off - first_FAR_off;
|
|
return 0;
|
|
}
|
|
|
|
void printf_clb(uint8_t* maj_bits, int row, int major)
|
|
{
|
|
int i, j, start, max_idx, frame_off;
|
|
const char* lut_str;
|
|
uint64_t lut64;
|
|
|
|
// the first two slots on top and bottom row are not used for clb
|
|
if (!row) {
|
|
start = 0;
|
|
max_idx = 14;
|
|
} else if (row == 3) {
|
|
start = 2;
|
|
max_idx = 16;
|
|
} else {
|
|
start = 0;
|
|
max_idx = 16;
|
|
}
|
|
|
|
for (i = start; i < max_idx; i++) {
|
|
if (clb_empty(maj_bits, i))
|
|
continue;
|
|
frame_off = i*64;
|
|
if (i >= 8)
|
|
frame_off += 16; // skip clock bits for idx >= 8
|
|
|
|
// LUTs
|
|
lut64 = read_lut64(&maj_bits[24*130], frame_off+32);
|
|
{ int logic_base[6] = {0,1,0,0,1,0};
|
|
lut_str = lut2bool(lut64, 64, &logic_base, 1 /* flip_b0 */); }
|
|
if (*lut_str)
|
|
printf("r%i ma%i clb i%i s0_A6LUT \"%s\"\n",
|
|
row, major, i-start, lut_str);
|
|
|
|
lut64 = read_lut64(&maj_bits[21*130], frame_off+32);
|
|
{ int logic_base[6] = {1,1,0,1,0,1};
|
|
lut_str = lut2bool(lut64, 64, &logic_base, 1 /* flip_b0 */); }
|
|
if (*lut_str)
|
|
printf("r%i ma%i clb i%i s0_B6LUT \"%s\"\n",
|
|
row, major, i-start, lut_str);
|
|
|
|
lut64 = read_lut64(&maj_bits[24*130], frame_off);
|
|
{ int logic_base[6] = {0,1,0,0,1,0};
|
|
lut_str = lut2bool(lut64, 64, &logic_base, 1 /* flip_b0 */); }
|
|
if (*lut_str)
|
|
printf("r%i ma%i clb i%i s0_C6LUT \"%s\"\n",
|
|
row, major, i-start, lut_str);
|
|
|
|
lut64 = read_lut64(&maj_bits[21*130], frame_off);
|
|
{ int logic_base[6] = {1,1,0,1,0,1};
|
|
lut_str = lut2bool(lut64, 64, &logic_base, 1 /* flip_b0 */); }
|
|
if (*lut_str)
|
|
printf("r%i ma%i clb i%i s0_D6LUT \"%s\"\n",
|
|
row, major, i-start, lut_str);
|
|
|
|
lut64 = read_lut64(&maj_bits[27*130], frame_off+32);
|
|
{ int logic_base[6] = {1,1,0,1,1,0};
|
|
lut_str = lut2bool(lut64, 64, &logic_base, 0 /* flip_b0 */); }
|
|
if (*lut_str)
|
|
printf("r%i ma%i clb i%i s1_A6LUT \"%s\"\n",
|
|
row, major, i-start, lut_str);
|
|
|
|
lut64 = read_lut64(&maj_bits[29*130], frame_off+32);
|
|
{ int logic_base[6] = {1,1,0,1,1,0};
|
|
lut_str = lut2bool(lut64, 64, &logic_base, 0 /* flip_b0 */); }
|
|
if (*lut_str)
|
|
printf("r%i ma%i clb i%i s1_B6LUT \"%s\"\n",
|
|
row, major, i-start, lut_str);
|
|
|
|
lut64 = read_lut64(&maj_bits[27*130], frame_off);
|
|
{ int logic_base[6] = {0,1,0,0,0,1};
|
|
lut_str = lut2bool(lut64, 64, &logic_base, 0 /* flip_b0 */); }
|
|
if (*lut_str)
|
|
printf("r%i ma%i clb i%i s1_C6LUT \"%s\"\n",
|
|
row, major, i-start, lut_str);
|
|
|
|
lut64 = read_lut64(&maj_bits[29*130], frame_off);
|
|
{ int logic_base[6] = {0,1,0,0,0,1};
|
|
lut_str = lut2bool(lut64, 64, &logic_base, 0 /* flip_b0 */); }
|
|
if (*lut_str)
|
|
printf("r%i ma%i clb i%i s1_D6LUT \"%s\"\n",
|
|
row, major, i-start, lut_str);
|
|
|
|
// bits
|
|
for (j = 0; j < 64; j++) {
|
|
if (bit_set(&maj_bits[20*130], frame_off + j))
|
|
printf("r%i ma%i clb i%i mi20 bit %i\n",
|
|
row, major, i-start, j);
|
|
}
|
|
for (j = 0; j < 64; j++) {
|
|
if (bit_set(&maj_bits[23*130], frame_off + j))
|
|
printf("r%i ma%i clb i%i mi23 bit %i\n",
|
|
row, major, i-start, j);
|
|
}
|
|
for (j = 0; j < 64; j++) {
|
|
if (bit_set(&maj_bits[26*130], frame_off + j))
|
|
printf("r%i ma%i clb i%i mi26 bit %i\n",
|
|
row, major, i-start, j);
|
|
}
|
|
}
|
|
}
|
|
|
|
void printf_bits(uint8_t* bits, int bits_len, int idcode)
|
|
{
|
|
int row, major, minor, i, j, off, bram_data_start;
|
|
int offset_in_frame, newline;
|
|
|
|
// type0
|
|
off = 0;
|
|
printf("\n");
|
|
for (row = 0; row < 4; row++) {
|
|
for (major = 0; major < 18; major++) {
|
|
if (majors[major].type == MAJ_DSP) {
|
|
int last_extra_minor;
|
|
|
|
if (!row || row == 3)
|
|
last_extra_minor = 23;
|
|
else
|
|
last_extra_minor = 21;
|
|
minor = 0;
|
|
while (minor <= last_extra_minor) {
|
|
minor += printf_frames(&bits[off
|
|
+minor*130], 31 - minor, row,
|
|
major, minor, g_cmd_info);
|
|
}
|
|
|
|
// clock
|
|
for (; minor < 24; minor++)
|
|
printf_clock(&bits[off+minor*130],
|
|
row, major, minor);
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
for (minor = last_extra_minor+1; minor < 24;
|
|
minor++) {
|
|
for (j = 0; j < 256; j++) {
|
|
if (bit_set(&bits[off+minor*130], i*256 + ((i>=2)?16:0) + j))
|
|
printf("r%i ma%i dsp i%i mi%i bit %i\n", row, major, i, minor, i*256+j);
|
|
}
|
|
}
|
|
}
|
|
} else if (majors[major].type == MAJ_CLB) {
|
|
minor = 0;
|
|
while (minor < 20) {
|
|
minor += printf_frames(&bits[off
|
|
+minor*130], 31 - minor, row,
|
|
major, minor, g_cmd_info);
|
|
}
|
|
|
|
// clock
|
|
for (minor = 20; minor < 31; minor++)
|
|
printf_clock(&bits[off+minor*130],
|
|
row, major, minor);
|
|
// extra bits at bottom of row0 and top of row3
|
|
if (row == 3)
|
|
printf_extrabits(&bits[off], 20, 11,
|
|
0, 128, row, major);
|
|
else if (!row)
|
|
printf_extrabits(&bits[off], 20, 11,
|
|
14*64 + 16, 128, row, major);
|
|
|
|
// clbs
|
|
printf_clb(&bits[off], row, major);
|
|
} else if (majors[major].type == MAJ_BRAM) {
|
|
ramb16_cfg_t ramb16_cfg[4];
|
|
|
|
// minors 0..22
|
|
minor = 0;
|
|
while (minor < 23) {
|
|
minor += printf_frames(&bits[off
|
|
+minor*130], 23 - minor, row,
|
|
major, minor, g_cmd_info);
|
|
}
|
|
|
|
// minors 23&24
|
|
printf_clock(&bits[off+23*130], row, major, 23);
|
|
printf_clock(&bits[off+24*130], row, major, 24);
|
|
for (i = 0; i < 4; i++) {
|
|
offset_in_frame = i*32;
|
|
if (offset_in_frame >= 64)
|
|
offset_in_frame += 2;
|
|
for (j = 0; j < 32; j++) {
|
|
ramb16_cfg[i].byte[j] = bits[off+23*130+offset_in_frame+j];
|
|
ramb16_cfg[i].byte[j+32] = bits[off+24*130+offset_in_frame+j];
|
|
}
|
|
}
|
|
for (i = 0; i < 4; i++) {
|
|
for (j = 0; j < 64; j++) {
|
|
if (ramb16_cfg[i].byte[j])
|
|
break;
|
|
}
|
|
if (j >= 64)
|
|
continue;
|
|
printf("r%i ma%i ramb16 i%i\n",
|
|
row, major, i);
|
|
print_ramb16_cfg(&ramb16_cfg[i]);
|
|
}
|
|
} else {
|
|
minor = 0;
|
|
while (minor < majors[major].minors) {
|
|
minor += printf_frames(&bits[off
|
|
+minor*130], majors[major].minors
|
|
- minor, row, major, minor, g_cmd_info);
|
|
}
|
|
}
|
|
off += majors[major].minors * 130;
|
|
}
|
|
}
|
|
|
|
// bram
|
|
bram_data_start = 4*505*130;
|
|
newline = 0;
|
|
for (row = 0; row < 4; row++) {
|
|
for (i = 0; i < 8; i++) {
|
|
for (j = 0; j < 18*130; j++) {
|
|
if (bits[bram_data_start + row*144*130
|
|
+ i*18*130 + j])
|
|
break;
|
|
}
|
|
if (j >= 18*130)
|
|
continue;
|
|
if (!newline) {
|
|
newline = 1;
|
|
printf("\n");
|
|
}
|
|
printf("br%i ramb16 i%i\n", row, i);
|
|
printf("{\n");
|
|
off = bram_data_start + row*144*130 + i*18*130;
|
|
printf_ramb16_data(bits, off);
|
|
printf("}\n");
|
|
}
|
|
}
|
|
|
|
// iob
|
|
printf("\n");
|
|
if (printf_iob(bits, bits_len, bram_data_start + 4*144*130, 896*2/8))
|
|
printf("\n");
|
|
}
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
uint8_t* bit_data = 0; // file contents
|
|
uint8_t* bits = 0; // bits in chip layout
|
|
FILE* bitf = 0;
|
|
int bit_cur, try_full_map, first_FAR_off, bits_len;
|
|
uint32_t bit_eof, cmd_len, u32, u16_off;
|
|
uint16_t u16, packet_hdr_type, packet_hdr_opcode;
|
|
uint16_t packet_hdr_register, packet_hdr_wordcount;
|
|
char* bit_path = 0;
|
|
int i, num_frames, times;
|
|
|
|
// state machine driven from file input
|
|
int m_FLR_value = -1;
|
|
int m_idcode = -1; // offset into idcodes
|
|
|
|
//
|
|
// parse command line
|
|
//
|
|
|
|
if (argc < 2) {
|
|
printf_help();
|
|
return EXIT_SUCCESS;
|
|
}
|
|
for (i = 1; i < argc; i++) {
|
|
if (!strcmp(argv[i], "--help")) {
|
|
printf_help();
|
|
return EXIT_SUCCESS;
|
|
}
|
|
if (!strcmp(argv[i], "--version")) {
|
|
printf("%s\n", PROGRAM_REVISION);
|
|
return EXIT_SUCCESS;
|
|
}
|
|
if (!strcmp(argv[i], "--info"))
|
|
g_cmd_info = 1;
|
|
else if (!strcmp(argv[i], "--frames"))
|
|
g_cmd_frames = 1;
|
|
else {
|
|
bit_path = argv[i];
|
|
if (argc > i+1) { // only 1 path supported
|
|
printf_help();
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
}
|
|
if (!bit_path) { // shouldn't get here, just in case
|
|
printf_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 filebuf.\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");
|
|
|
|
if (printf_header(bit_data, bit_eof, 0 /* inpos */, &bit_cur))
|
|
goto fail;
|
|
|
|
//
|
|
// 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 (g_cmd_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");
|
|
|
|
try_full_map = !g_cmd_frames;
|
|
first_FAR_off = -1;
|
|
while (bit_cur < bit_eof) {
|
|
// packet header: ug380, Configuration Packets (p88)
|
|
if (g_cmd_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;
|
|
|
|
if (packet_hdr_type == 1) {
|
|
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);
|
|
m_idcode = i;
|
|
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);
|
|
if (idcodes[m_idcode].code == XC6SLX4
|
|
&& m_FLR_value != 896)
|
|
printf("#W Unexpected FLR value %i on "
|
|
"idcode %s.\n", m_FLR_value,
|
|
idcodes[m_idcode].name);
|
|
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);
|
|
m_FLR_value = u16;
|
|
if ((m_FLR_value*2) % 8)
|
|
printf("#W FLR*2 should be multiple of "
|
|
"8, but modulo 8 is %i\n", (m_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;
|
|
|
|
if (first_FAR_off == -1)
|
|
first_FAR_off = u16_off;
|
|
|
|
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.
|
|
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;
|
|
}
|
|
if (packet_hdr_register == EYE_MASK) {
|
|
if (packet_hdr_wordcount != 1) {
|
|
fprintf(stderr, "#E 0x%x=0x%x Unexpected EYE_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 EYE_MASK 0x%X\n", u16);
|
|
continue;
|
|
}
|
|
if (packet_hdr_register == GENERAL1) {
|
|
if (packet_hdr_wordcount != 1) {
|
|
fprintf(stderr, "#E 0x%x=0x%x Unexpected GENERAL1"
|
|
" 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 GENERAL1 0x%X\n", u16);
|
|
continue;
|
|
}
|
|
if (packet_hdr_register == GENERAL2) {
|
|
if (packet_hdr_wordcount != 1) {
|
|
fprintf(stderr, "#E 0x%x=0x%x Unexpected GENERAL1"
|
|
" 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 GENERAL2 0x%X\n", u16);
|
|
continue;
|
|
}
|
|
if (packet_hdr_register == GENERAL3) {
|
|
if (packet_hdr_wordcount != 1) {
|
|
fprintf(stderr, "#E 0x%x=0x%x Unexpected GENERAL1"
|
|
" 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 GENERAL3 0x%X\n", u16);
|
|
continue;
|
|
}
|
|
if (packet_hdr_register == GENERAL4) {
|
|
if (packet_hdr_wordcount != 1) {
|
|
fprintf(stderr, "#E 0x%x=0x%x Unexpected GENERAL1"
|
|
" 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 GENERAL4 0x%X\n", u16);
|
|
continue;
|
|
}
|
|
if (packet_hdr_register == GENERAL5) {
|
|
if (packet_hdr_wordcount != 1) {
|
|
fprintf(stderr, "#E 0x%x=0x%x Unexpected GENERAL1"
|
|
" 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 GENERAL5 0x%X\n", u16);
|
|
continue;
|
|
}
|
|
if (packet_hdr_register == EXP_SIGN) {
|
|
if (packet_hdr_wordcount != 2) {
|
|
fprintf(stderr, "#E 0x%x=0x%x Unexpected EXP_SIGN"
|
|
" wordcount %u.\n", u16_off,
|
|
u16, packet_hdr_wordcount);
|
|
goto fail;
|
|
}
|
|
u32 = __be32_to_cpu(*(uint32_t*)&bit_data[u16_off+2]);
|
|
u16_off+=4;
|
|
printf("T1 EXP_SIGN 0x%X\n", u32);
|
|
continue;
|
|
}
|
|
if (packet_hdr_register == SEU_OPT) {
|
|
int seu_freq;
|
|
|
|
if (packet_hdr_wordcount != 1) {
|
|
fprintf(stderr, "#E 0x%x=0x%x Unexpected SEU_OPT"
|
|
" 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;
|
|
seu_freq = (u16 & 0x3FF0) >> 4;
|
|
printf("T1 SEU_OPT SEU_FREQ=0x%X", seu_freq);
|
|
u16 &= ~(0x3FF0);
|
|
if (u16 & (1<<3)) {
|
|
printf(" SEU_RUN_ON_ERR");
|
|
u16 &= ~(1<<3);
|
|
}
|
|
if (u16 & (1<<1)) {
|
|
printf(" GLUT_MASK");
|
|
u16 &= ~(1<<1);
|
|
}
|
|
if (u16 & (1<<0)) {
|
|
printf(" SEU_ENABLE");
|
|
u16 &= ~(1<<0);
|
|
}
|
|
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 == CRC) {
|
|
// Don't print CRC value for cleaner diff.
|
|
printf("#W T1 CRC (%u words)\n",
|
|
packet_hdr_wordcount);
|
|
continue;
|
|
}
|
|
printf("#W 0x%x=0x%x T1 %i (%u words)", u16_off, u16,
|
|
packet_hdr_register, packet_hdr_wordcount);
|
|
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]);
|
|
if (bit_cur+4+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;
|
|
}
|
|
|
|
printf("T2 FDRI words=%i\n", u32);
|
|
bit_cur += 4;
|
|
if (try_full_map) {
|
|
try_full_map = 0;
|
|
if (first_FAR_off != -1) {
|
|
int outdelta;
|
|
if (!full_map(bit_data, bit_eof, first_FAR_off,
|
|
&bits, &bits_len, idcodes[m_idcode].code,
|
|
m_FLR_value, &outdelta)) {
|
|
printf_bits(bits, bits_len,
|
|
idcodes[m_idcode].code);
|
|
bit_cur = first_FAR_off + outdelta;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
num_frames = (2*u32)/130;
|
|
i = 0;
|
|
printf("\n");
|
|
while (i < num_frames) {
|
|
i += printf_frames(&bit_data[bit_cur+i*130],
|
|
num_frames-i, -i /* row */, 0 /* major */,
|
|
0 /* minor */, 1 /* print_empty */);
|
|
}
|
|
printf("\n");
|
|
if (num_frames*130 < 2*u32) {
|
|
int dump_len = 2*u32 - num_frames*130;
|
|
printf("#D hexdump offset 0x%x, len 0x%x (%i)\n",
|
|
num_frames*130, dump_len, dump_len);
|
|
hexdump(1, &bit_data[bit_cur+num_frames*130], dump_len);
|
|
printf("\n");
|
|
}
|
|
bit_cur += u32*2;
|
|
|
|
if (bit_cur + 4 > bit_eof) goto fail_eof;
|
|
u32 = __be32_to_cpu(*(uint32_t*)&bit_data[bit_cur]);
|
|
if (g_cmd_info) printf("#I 0x%x=0x%x Ignoring Auto-CRC.\n", bit_cur, u32);
|
|
bit_cur += 4;
|
|
}
|
|
free(bits);
|
|
free(bit_data);
|
|
return EXIT_SUCCESS;
|
|
|
|
fail_eof:
|
|
fprintf(stderr, "#E Unexpected EOF.\n");
|
|
fail:
|
|
free(bits);
|
|
free(bit_data);
|
|
return EXIT_FAILURE;
|
|
}
|