// // 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; }