// // 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 "model.h" #include "bit.h" static int parse_header(struct fpga_config* config, uint8_t* d, int len, int inpos, int* outdelta); static int parse_commands(struct fpga_config* config, uint8_t* d, int len, int inpos); #define SYNC_WORD 0xAA995566 #define PACKET_HDR_TYPE_S 13 #define PACKET_HDR_OPCODE_S 11 #define PACKET_HDR_REG_S 5 #define PACKET_TYPE_1 1 #define PACKET_TYPE_2 2 #define PACKET_HDR_OPCODE_NOOP 0 #define PACKET_HDR_OPCODE_READ 1 #define PACKET_HDR_OPCODE_WRITE 2 #define PACKET_HDR_OPCODE_RSRV 3 #define BITSTREAM_READ_PAGESIZE 4096 int read_bitfile(struct fpga_config* cfg, FILE* f, int verbose_read) { uint8_t* bit_data = 0; int rc, file_len, bit_len, bit_cur; memset(cfg, 0, sizeof(*cfg)); cfg->verbose_read = verbose_read; cfg->num_regs_before_bits = -1; cfg->idcode_reg = -1; cfg->FLR_reg = -1; // read .bit into memory if (fseek(f, 0, SEEK_END) == -1) FAIL(errno); if ((file_len = ftell(f)) == -1) FAIL(errno); if (fseek(f, 0, SEEK_SET) == -1) FAIL(errno); if (!file_len) FAIL(EINVAL); if (!(bit_data = malloc(file_len))) FAIL(ENOMEM); bit_len = 0; while (bit_len < file_len) { size_t num_read = fread(&bit_data[bit_len], sizeof(uint8_t), BITSTREAM_READ_PAGESIZE, f); bit_len += num_read; if (num_read != BITSTREAM_READ_PAGESIZE) break; } if (bit_len != file_len) FAIL(EINVAL); // parse header and commands if ((rc = parse_header(cfg, bit_data, bit_len, /*inpos*/ 0, &bit_cur))) FAIL(rc); if ((rc = parse_commands(cfg, bit_data, bit_len, bit_cur))) FAIL(rc); free(bit_data); return 0; fail: free(bit_data); return rc; } static void dump_header(struct fpga_config* cfg) { int i; for (i = 0; i < sizeof(cfg->header_str) /sizeof(cfg->header_str[0]); i++) { printf("header_str_%c %s\n", 'a'+i, cfg->header_str[i]); } } static int dump_regs(struct fpga_config* cfg, int start, int end, int dump_crc) { uint16_t u16; int i, rc; for (i = start; i < end; i++) { if (cfg->reg[i].reg == REG_NOOP) { int times = 1; while (i+times < end && cfg->reg[i+times].reg == REG_NOOP) times++; if (times > 1) printf("noop times %i\n", times); else printf("noop\n"); i += times-1; continue; } if (cfg->reg[i].reg == IDCODE) { switch (cfg->reg[i].int_v & IDCODE_MASK) { case XC6SLX4: printf("T1 IDCODE XC6SLX4\n"); break; case XC6SLX9: printf("T1 IDCODE XC6SLX9\n"); break; case XC6SLX16: printf("T1 IDCODE XC6SLX16\n"); break; case XC6SLX25: printf("T1 IDCODE XC6SLX25\n"); break; case XC6SLX25T: printf("T1 IDCODE XC6SLX25T\n"); break; case XC6SLX45: printf("T1 IDCODE XC6SLX45\n"); break; case XC6SLX45T: printf("T1 IDCODE XC6SLX45T\n"); break; case XC6SLX75: printf("T1 IDCODE XC6SLX75\n"); break; case XC6SLX75T: printf("T1 IDCODE XC6SLX75T\n"); break; case XC6SLX100: printf("T1 IDCODE XC6SLX100\n"); break; case XC6SLX100T: printf("T1 IDCODE XC6SLX100T\n"); break; case XC6SLX150: printf("T1 IDCODE XC6SLX150\n"); break; default: printf("#W Unknown IDCODE 0x%X.\n", cfg->reg[i].int_v); break; } continue; } if (cfg->reg[i].reg == CMD) { static 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" }; if (cfg->reg[i].int_v >= sizeof(cmds)/sizeof(cmds[0]) || cmds[cfg->reg[i].int_v] == 0) printf("#W Unknown CMD 0x%X.\n", cfg->reg[i].int_v); else printf("T1 CMD %s\n", cmds[cfg->reg[i].int_v]); continue; } if (cfg->reg[i].reg == FDRI) { printf("T2 FDRI %i\n", cfg->reg[i].int_v); continue; } if (cfg->reg[i].reg == FLR) { printf("T1 FLR %i\n", cfg->reg[i].int_v); continue; } if (cfg->reg[i].reg == CRC) { if (dump_crc) printf("T1 CRC 0x%X\n", cfg->reg[i].int_v); else printf("T1 CRC\n"); continue; } if (cfg->reg[i].reg == COR1) { int unexpected_clk11 = 0; u16 = cfg->reg[i].int_v; 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 (cfg->reg[i].reg == COR2) { int unexpected_done_cycle = 0; int unexpected_lck_cycle = 0; unsigned cycle; u16 = cfg->reg[i].int_v; 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 (cfg->reg[i].reg == FAR_MAJ) { uint16_t maj, min; int unexpected_blk_bit4 = 0; maj = cfg->reg[i].far[FAR_MAJ_O]; min = cfg->reg[i].far[FAR_MIN_O]; 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 (cfg->reg[i].reg == MFWR) { printf("T1 MFWR\n"); continue; } if (cfg->reg[i].reg == CTL) { u16 = cfg->reg[i].int_v; 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 (cfg->reg[i].reg == MASK) { u16 = cfg->reg[i].int_v; printf("T1 MASK"); if (u16 & 0x0040) { printf(" DECRYPT"); u16 &= ~0x0040; } if ((u16 & MASK_SECURITY) == MASK_SECURITY) { printf(" SECURITY"); u16 &= ~MASK_SECURITY; } 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 (cfg->reg[i].reg == PWRDN_REG) { u16 = cfg->reg[i].int_v; 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 (cfg->reg[i].reg == HC_OPT_REG) { u16 = cfg->reg[i].int_v; 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 (cfg->reg[i].reg == PU_GWE) { printf("T1 PU_GWE 0x%03X\n", cfg->reg[i].int_v); continue; } if (cfg->reg[i].reg == PU_GTS) { printf("T1 PU_GTS 0x%03X\n", cfg->reg[i].int_v); continue; } if (cfg->reg[i].reg == CWDT) { printf("T1 CWDT 0x%X\n", cfg->reg[i].int_v); if (cfg->reg[i].int_v < 0x0201) printf("#W Watchdog timer clock below" " minimum value of 0x0201.\n"); continue; } if (cfg->reg[i].reg == MODE_REG) { int unexpected_buswidth = 0; u16 = cfg->reg[i].int_v; 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 (cfg->reg[i].reg == CCLK_FREQ) { u16 = cfg->reg[i].int_v; 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 (cfg->reg[i].reg == EYE_MASK) { printf("T1 EYE_MASK 0x%X\n", cfg->reg[i].int_v); continue; } if (cfg->reg[i].reg == GENERAL1) { printf("T1 GENERAL1 0x%X\n", cfg->reg[i].int_v); continue; } if (cfg->reg[i].reg == GENERAL2) { printf("T1 GENERAL2 0x%X\n", cfg->reg[i].int_v); continue; } if (cfg->reg[i].reg == GENERAL3) { printf("T1 GENERAL3 0x%X\n", cfg->reg[i].int_v); continue; } if (cfg->reg[i].reg == GENERAL4) { printf("T1 GENERAL4 0x%X\n", cfg->reg[i].int_v); continue; } if (cfg->reg[i].reg == GENERAL5) { printf("T1 GENERAL5 0x%X\n", cfg->reg[i].int_v); continue; } if (cfg->reg[i].reg == EXP_SIGN) { printf("T1 EXP_SIGN 0x%X\n", cfg->reg[i].int_v); continue; } if (cfg->reg[i].reg == SEU_OPT) { int seu_freq; u16 = cfg->reg[i].int_v; 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; } FAIL(EINVAL); } return 0; fail: return rc; } static int dump_maj_zero(const uint8_t* bits, int row, int major) { int minor; for (minor = 0; minor < get_major_minors(XC6SLX9, major); minor++) printf_clock(&bits[minor*FRAME_SIZE], row, major, minor); for (minor = 0; minor < get_major_minors(XC6SLX9, major); minor++) printf_frames(&bits[minor*FRAME_SIZE], /*max_frames*/ 1, row, major, minor, /*print_empty*/ 0, /*no_clock*/ 1); return 0; } static int dump_maj_left(const uint8_t* bits, int row, int major) { int minor; for (minor = 0; minor < get_major_minors(XC6SLX9, major); minor++) printf_clock(&bits[minor*FRAME_SIZE], row, major, minor); for (minor = 0; minor < get_major_minors(XC6SLX9, major); minor++) printf_frames(&bits[minor*FRAME_SIZE], /*max_frames*/ 1, row, major, minor, /*print_empty*/ 0, /*no_clock*/ 1); return 0; } static int dump_maj_right(const uint8_t* bits, int row, int major) { int minor; for (minor = 0; minor < get_major_minors(XC6SLX9, major); minor++) printf_clock(&bits[minor*FRAME_SIZE], row, major, minor); for (minor = 0; minor < get_major_minors(XC6SLX9, major); minor++) printf_frames(&bits[minor*FRAME_SIZE], /*max_frames*/ 1, row, major, minor, /*print_empty*/ 0, /*no_clock*/ 1); return 0; } static int dump_maj_logic(const uint8_t* bits, int row, int major) { const struct xc_die* xci = xc_die_info(XC6SLX9); int minor, i, logdev_start, logdev_end; for (minor = 0; minor < xci->majors[major].minors; minor++) printf_clock(&bits[minor*FRAME_SIZE], row, major, minor); // 0:19 routing minor pairs for (i = 0; i < 10; i++) printf_routing_2minors(&bits[i*2*FRAME_SIZE], row, major, i*2); // mi20 as 64-char 0/1 string printf_v64_mi20(&bits[20*FRAME_SIZE], row, major); logdev_start = 0; logdev_end = 15; if (xci->majors[major].flags & XC_MAJ_TOP_BOT_IO) { if (row == xc_die_info(XC6SLX9)->num_rows-1) logdev_start += TOPBOT_IO_ROWS; else if (!row) logdev_end -= TOPBOT_IO_ROWS; } if (xci->majors[major].flags & XC_MAJ_XM) { if (xci->majors[major].minors != 31) HERE(); // M devices if (logdev_start) printf_extrabits(bits, 21, 2, 0, logdev_start*64, row, major); for (i = logdev_start; i <= logdev_end; i++) { printf_lut_words(bits, row, major, 21, i*4); printf_lut_words(bits, row, major, 21, i*4+2); } if (logdev_end < 15) printf_extrabits(bits, 21, 2, i*64 + XC6_HCLK_BITS, (15-logdev_end)*64, row, major); printf_frames(&bits[23*FRAME_SIZE], /*max_frames*/ 1, row, major, 23, /*print_empty*/ 0, /*no_clock*/ 1); if (logdev_start) printf_extrabits(bits, 24, 2, 0, logdev_start*64, row, major); for (i = logdev_start; i <= logdev_end; i++) { printf_lut_words(bits, row, major, 24, i*4); printf_lut_words(bits, row, major, 24, i*4+2); } if (logdev_end < 15) printf_extrabits(bits, 24, 2, i*64 + XC6_HCLK_BITS, (15-logdev_end)*64, row, major); // X devices printf_frames(&bits[26*FRAME_SIZE], /*max_frames*/ 1, row, major, 26, /*print_empty*/ 0, /*no_clock*/ 1); if (logdev_start) printf_extrabits(bits, 27, 4, 0, logdev_start*64, row, major); for (i = logdev_start; i <= logdev_end; i++) { printf_lut_words(bits, row, major, 27, i*4); printf_lut_words(bits, row, major, 29, i*4); printf_lut_words(bits, row, major, 27, i*4+2); printf_lut_words(bits, row, major, 29, i*4+2); } if (logdev_end < 15) printf_extrabits(bits, 27, 4, i*64 + XC6_HCLK_BITS, (15-logdev_end)*64, row, major); } else if (xci->majors[major].flags & (XC_MAJ_XL|XC_MAJ_CENTER)) { // L devices if (logdev_start) printf_extrabits(bits, 21, 4, 0, logdev_start*64, row, major); for (i = logdev_start; i <= logdev_end; i++) { printf_lut_words(bits, row, major, 21, i*4); printf_lut_words(bits, row, major, 23, i*4); printf_lut_words(bits, row, major, 21, i*4+2); printf_lut_words(bits, row, major, 23, i*4+2); } if (logdev_end < 15) printf_extrabits(bits, 21, 4, i*64 + XC6_HCLK_BITS, (15-logdev_end)*64, row, major); printf_frames(&bits[25*FRAME_SIZE], /*max_frames*/ 1, row, major, 25, /*print_empty*/ 0, /*no_clock*/ 1); // X devices if (logdev_start) printf_extrabits(bits, 26, 4, 0, logdev_start*64, row, major); for (i = logdev_start; i <= logdev_end; i++) { printf_lut_words(bits, row, major, 26, i*4); printf_lut_words(bits, row, major, 28, i*4); printf_lut_words(bits, row, major, 26, i*4+2); printf_lut_words(bits, row, major, 28, i*4+2); } if (logdev_end < 15) printf_extrabits(bits, 26, 4, i*64 + XC6_HCLK_BITS, (15-logdev_end)*64, row, major); // one extra minor in the center major if (xci->majors[major].flags & XC_MAJ_CENTER) { if (xci->majors[major].minors != 31) HERE(); printf_frames(&bits[30*FRAME_SIZE], /*max_frames*/ 1, row, major, 30, /*print_empty*/ 0, /*no_clock*/ 1); } else { // XL if (xci->majors[major].minors != 30) HERE(); } } else HERE(); return 0; } static void printf_minor_diff(int row, int major, int minor, const uint8_t *old_minor_bits, const uint8_t *new_minor_bits) { int word_i, w_old, w_new; char v16_str[32]; // print words as bits (cpu bit ordering) for (word_i = 0; word_i < FRAME_SIZE/XC6_WORD_BYTES; word_i++) { if (word_i == XC6_HCLK_POS/XC6_WORD_BYTES) sprintf(v16_str, "v16_clk"); else sprintf(v16_str, "v16_%i", word_ir%i ma%i %s mi%i %s", row, major, v16_str, minor, fmt_word(w_new)); } } static void printf_minors(int row, int major, int minor, int num_minors, const uint8_t *major_bits) { int word_i, minor_i, w; char v16_str[32]; // print words as bits (cpu bit ordering) for (word_i = 0; word_i < FRAME_SIZE/XC6_WORD_BYTES; word_i++) { if (word_i == XC6_HCLK_POS/XC6_WORD_BYTES) sprintf(v16_str, "v16_clk"); else sprintf(v16_str, "v16_%i", word_iidcode_reg == -1) FAIL(EINVAL); idcode = cfg->reg[cfg->idcode_reg].int_v; die_info = xc_die_info(idcode); if (!die_info) FAIL(EINVAL); num_rows = die_info->num_rows; // type0 for (major = 0; major <= get_rightside_major(idcode); major++) { for (row = num_rows-1; row >= 0; row--) { off = (row*get_frames_per_row(idcode) + get_major_framestart(idcode, major)) * FRAME_SIZE; switch (get_major_type(idcode, major)) { case MAJ_ZERO: rc = dump_maj_zero(&cfg->bits.d[off], row, major); if (rc) FAIL(rc); break; case MAJ_LEFT: rc = dump_maj_left(&cfg->bits.d[off], row, major); if (rc) FAIL(rc); break; case MAJ_RIGHT: rc = dump_maj_right(&cfg->bits.d[off], row, major); if (rc) FAIL(rc); break; case MAJ_LOGIC_XM: case MAJ_LOGIC_XL: case MAJ_CENTER: rc = dump_maj_logic(&cfg->bits.d[off], row, major); if (rc) FAIL(rc); break; case MAJ_BRAM: rc = dump_maj_bram(&cfg->bits.d[off], row, major); if (rc) FAIL(rc); break; case MAJ_MACC: rc = dump_maj_macc(&cfg->bits.d[off], row, major); if (rc) FAIL(rc); break; default: HERE(); break; } } } return 0; fail: return rc; } static int dump_bram(struct fpga_config *cfg) { int row, i; for (row = 3; row >= 0; row--) { for (i = XC6_BRAM16_DEVS_PER_ROW-1; i >= 0; i--) { printf_ramb_data(&cfg->bits.d[BRAM_DATA_START + (row*XC6_BRAM16_DEVS_PER_ROW+i) *XC6_BRAM_DATA_FRAMES_PER_DEV*FRAME_SIZE], row, i); } } return 0; } int dump_config(struct fpga_config* cfg, int flags) { int rc; if (flags & DUMP_HEADER_STR) dump_header(cfg); if (flags & DUMP_REGS) { rc = dump_regs(cfg, /*start*/ 0, cfg->num_regs_before_bits, flags & DUMP_CRC); if (rc) FAIL(rc); } if (flags & DUMP_BITS) { rc = dump_bits(cfg); if (rc) FAIL(rc); rc = dump_bram(cfg); if (rc) FAIL(rc); printf_type2(cfg->bits.d, cfg->bits.len, BRAM_DATA_START + BRAM_DATA_LEN, IOB_WORDS*2/8); if (flags & DUMP_CRC) printf("auto-crc 0x%X\n", cfg->auto_crc); } if (flags & DUMP_REGS) { rc = dump_regs(cfg, cfg->num_regs_before_bits, cfg->num_regs, flags & DUMP_CRC); if (rc) FAIL(rc); } return 0; fail: return rc; } void free_config(struct fpga_config* cfg) { free(cfg->bits.d); cfg->bits.d = 0; memset(cfg, 0, sizeof(*cfg)); } static const uint8_t s_bit_bof[] = { 0x00, 0x09, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x00, 0x00, 0x01 }; static const uint8_t s_0xFF_words[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; static int parse_header(struct fpga_config* cfg, uint8_t* d, int len, int inpos, int* outdelta) { int i, str_len; *outdelta = 0; if (inpos + 13 > len) { fprintf(stderr, "#E File size %i below minimum of 13 bytes.\n", len); return -1; } for (i = 0; i < 13; i++) { if (d[inpos+*outdelta+i] == s_bit_bof[i]) continue; fprintf(stderr, "#E Expected 0x%x, got 0x%x at off %i\n", s_bit_bof[i], d[inpos+*outdelta+i], inpos+*outdelta+i); } *outdelta += 13; // 4 strings 'a' - 'd', 16-bit length for (i = 'a'; i <= 'd'; i++) { if (inpos + *outdelta + 3 > len) { fprintf(stderr, "#E Unexpected EOF at %i.\n", len); return -1; } if (d[inpos + *outdelta] != i) { fprintf(stderr, "#E Expected string code '%c', got " "'%c'.\n", i, d[inpos + *outdelta]); return -1; } str_len = __be16_to_cpu(*(uint16_t*)&d[inpos + *outdelta + 1]); if (inpos + *outdelta + 3 + str_len > len) { fprintf(stderr, "#E Unexpected EOF at %i.\n", len); return -1; } if (d[inpos + *outdelta + 3 + str_len - 1]) { fprintf(stderr, "#E z-terminated string ends with %0xh" ".\n", d[inpos + *outdelta + 3 + str_len - 1]); return -1; } strcpy(cfg->header_str[i-'a'], (char*) &d[inpos + *outdelta + 3]); *outdelta += 3 + str_len; } return 0; } static 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 >= get_major_minors(XC6SLX9, FAR_major)) return -1; result = FAR_row * 505*FRAME_SIZE; for (i = 0; i < FAR_major; i++) result += get_major_minors(XC6SLX9, i)*FRAME_SIZE; return result + FAR_minor*FRAME_SIZE; } static int read_bits(struct fpga_config* cfg, uint8_t* d, int len, int inpos, 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, rc, MFW_src_off; int offset_in_bits, block0_words, padding_frames, last_FDRI_pos; uint16_t u16; uint32_t u32; last_FDRI_pos = -1; *outdelta = 0; if (cfg->idcode_reg == -1 || cfg->FLR_reg == -1 || (cfg->reg[cfg->idcode_reg].int_v != XC6SLX4 && cfg->reg[cfg->idcode_reg].int_v != XC6SLX9) || cfg->reg[cfg->FLR_reg].int_v != IOB_WORDS) FAIL(EINVAL); cfg->bits.len = (4*505 + 4*144) * FRAME_SIZE + IOB_WORDS*2; cfg->bits.d = calloc(cfg->bits.len, 1 /* elsize */); if (!cfg->bits.d) FAIL(ENOMEM); cfg->auto_crc = 0; POUT(cfg->verbose_read, ("#D expected bits length is %i bytes\n", cfg->bits.len)); FAR_block = -1; FAR_row = -1; FAR_major = -1; FAR_minor = -1; MFW_src_off = -1; // Go through bit_file from first_FAR_off (inpos) until last byte // of IOB was read, plus padding, plus CRC verification. src_off = inpos; while (src_off < len) { if (src_off + 2 > len) FAIL(EINVAL); u16 = __be16_to_cpu(*(uint16_t*)&d[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) FAIL(EINVAL); // 2 bits: 00 = noop; 01 = read; 10 = write; 11 = reserved packet_hdr_opcode = (u16 & 0x1800) >> 11; if (packet_hdr_opcode == 3) FAIL(EINVAL); if (packet_hdr_opcode == 0) { // noop if (packet_hdr_type != 1 || u16 & 0x07FF) FAIL(EINVAL); 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 > len) FAIL(EINVAL); if (packet_hdr_type == 1) { if (packet_hdr_register == CMD) { if (packet_hdr_wordcount != 1) FAIL(EINVAL); u16 = __be16_to_cpu( *(uint16_t*)&d[src_off]); if (u16 == CMD_GRESTORE || u16 == CMD_LFRM) { if (last_FDRI_pos == -1) FAIL(EINVAL); src_off = last_FDRI_pos; goto success; } if (u16 != CMD_MFW && u16 != CMD_WCFG) FAIL(EINVAL); if (u16 == CMD_MFW) { if (FAR_block != 0) FAIL(EINVAL); MFW_src_off = FAR_pos(FAR_row, FAR_major, FAR_minor); if (MFW_src_off == -1) FAIL(EINVAL); } src_off += 2; continue; } if (packet_hdr_register == FAR_MAJ) { uint16_t maj, min; if (packet_hdr_wordcount != 2) FAIL(EINVAL); maj = __be16_to_cpu(*(uint16_t*) &d[src_off]); min = __be16_to_cpu(*(uint16_t*) &d[src_off+2]); FAR_block = (maj & 0xF000) >> 12; if (FAR_block > 7) FAIL(EINVAL); 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) FAIL(EINVAL); first_dword = __be32_to_cpu( *(uint32_t*)&d[src_off]); second_dword = __be32_to_cpu( *(uint32_t*)&d[src_off+4]); if (first_dword || second_dword) FAIL(EINVAL); // The first MFWR will overwrite itself, so // use memmove(). if (FAR_block != 0) FAIL(EINVAL); offset_in_bits = FAR_pos(FAR_row, FAR_major, FAR_minor); if (offset_in_bits == -1) FAIL(EINVAL); memmove(&cfg->bits.d[offset_in_bits], &cfg->bits.d[MFW_src_off], 130); src_off += 8; continue; } FAIL(EINVAL); } // packet type must be 2 here if (packet_hdr_wordcount != 0) FAIL(EINVAL); if (packet_hdr_register != FDRI) FAIL(EINVAL); if (src_off + 4 > len) FAIL(EINVAL); u32 = __be32_to_cpu(*(uint32_t*)&d[src_off]); src_off += 4; if (src_off+2*u32 > len) FAIL(EINVAL); if (2*u32 < 130) FAIL(EINVAL); last_FDRI_pos = src_off+u32*2+/*auto-crc*/4; POUT(cfg->verbose_read, ("#D src 0x%X: %i fdri words, last_FDRI_pos %i\n", src_off-4, u32, last_FDRI_pos)); // fdri words u32 if (FAR_block == -1 || FAR_block > 1 || FAR_row == -1 || FAR_major == -1 || FAR_minor == -1) FAIL(EINVAL); block0_words = 0; if (!FAR_block) { offset_in_bits = FAR_pos(FAR_row, FAR_major, FAR_minor); if (offset_in_bits == -1) FAIL(EINVAL); POUT(cfg->verbose_read, ("#D FAR_pos r%i ma%i mi%i = %i bytes\n", FAR_row, FAR_major, FAR_minor, offset_in_bits)); if (!FAR_row && !FAR_major && !FAR_minor && u32 > 4*(505+2)*XC6_FRAME_WORDS) block0_words = 4*(505+2)*XC6_FRAME_WORDS; else { block0_words = u32; if (block0_words % XC6_FRAME_WORDS) FAIL(EINVAL); } POUT(cfg->verbose_read, ("#D %i block0 words\n", block0_words)); padding_frames = 0; for (i = 0; i < block0_words/XC6_FRAME_WORDS; i++) { if (i && i+1 == block0_words/XC6_FRAME_WORDS) { for (j = 0; j < FRAME_SIZE; j++) { if (d[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 >= FRAME_SIZE) break; } if (!FAR_major && !FAR_minor && (i%507 == 505)) { for (j = 0; j < 2*FRAME_SIZE; j++) { if (d[src_off+i*FRAME_SIZE+j] != 0xFF) FAIL(EINVAL); } i++; padding_frames += 2; continue; } if (cfg->verbose_read && offset_in_bits) { printf("#D copying %i bytes from file_off 0x%X to bits_off %i\n", FRAME_SIZE, src_off+i*FRAME_SIZE, offset_in_bits + (i-padding_frames)*FRAME_SIZE); for (j = 0; j < FRAME_SIZE; j++) { if (cfg->bits.d[offset_in_bits + (i-padding_frames)*FRAME_SIZE + j]) break; } if (j >= FRAME_SIZE) printf("dest all-0\n"); else { printf("dest {\n"); dump_data(1, &cfg->bits.d[offset_in_bits + (i-padding_frames)*FRAME_SIZE], FRAME_SIZE, 16); printf("}\n"); } printf("src {\n"); dump_data(1, &d[src_off + i*FRAME_SIZE], FRAME_SIZE, 16); printf("}\n"); } if (offset_in_bits) printf_minor_diff(FAR_row, FAR_major, FAR_minor, &cfg->bits.d[offset_in_bits + (i-padding_frames)*FRAME_SIZE], &d[src_off + i*FRAME_SIZE]); memcpy(&cfg->bits.d[offset_in_bits + (i-padding_frames)*FRAME_SIZE], &d[src_off + i*FRAME_SIZE], FRAME_SIZE); } } if (u32 - block0_words > 0) { int bram_data_words = 4*144*XC6_FRAME_WORDS + IOB_WORDS; POUT(cfg->verbose_read, ("#D block0 words: %i bram_data words: %i fdri words: %i\n", block0_words, bram_data_words, u32)); if (u32 - block0_words != bram_data_words + 1) FAIL(EINVAL); offset_in_bits = BRAM_DATA_START; memcpy(&cfg->bits.d[offset_in_bits], &d[src_off+block0_words*2], bram_data_words*2); u16 = __be16_to_cpu(*(uint16_t*)&d[ (src_off+block0_words+bram_data_words)*2]); if (u16) { if (u16 != 0xFFFF) { PERR(("#E %s:%i post-bram word 0x%Xh (expected 0 or 0xFFFF).\n", __FILE__, __LINE__, u16)); rc = EINVAL; goto fail; } POUT(cfg->verbose_read, ("#D post-bram word 0xFFFF\n")); } } src_off += 2*u32; cfg->auto_crc = __be32_to_cpu(*(uint32_t*)&d[src_off]); src_off += 4; } rc = EINVAL; fail: free(cfg->bits.d); cfg->bits.d = 0; return rc; success: *outdelta = src_off - inpos; return 0; } static int parse_commands(struct fpga_config* cfg, uint8_t* d, int len, int inpos) { int curpos, cmd_len, first_FAR_off, u16_off, rc; int packet_hdr_type, packet_hdr_opcode, packet_hdr_register; int packet_hdr_wordcount, i; uint32_t u32; uint16_t u16; curpos = inpos; if (curpos + 5 > len || d[curpos] != 'e') FAIL(EINVAL); cmd_len = __be32_to_cpu(*(uint32_t*)&d[curpos + 1]); curpos += 5; if (curpos + cmd_len > len) FAIL(EINVAL); if (curpos + cmd_len < len) { printf("#W Unexpected continuation after offset " "%i (len %i).\n", curpos + cmd_len, len); } if (curpos >= len) FAIL(EINVAL); if (d[curpos] != 0xAA) { while (curpos < len && d[curpos] != 0xAA) { if (d[curpos] != 0xFF) { printf("#W Expected 0xFF, but got 0x%X at " "offset %i\n", d[curpos], curpos); } curpos++; if (curpos >= len) FAIL(EINVAL); } } if (curpos + 4 > len) FAIL(EINVAL); u32 = __be32_to_cpu(*(uint32_t*)&d[curpos]); curpos += 4; if (u32 != SYNC_WORD) { fprintf(stderr, "#E Unexpected sync word 0x%x.\n", u32); FAIL(EINVAL); } first_FAR_off = -1; while (curpos < len) { // packet header: ug380, Configuration Packets (p88) if (curpos + 2 > len) FAIL(EINVAL); u16 = __be16_to_cpu(*(uint16_t*)&d[curpos]); u16_off = curpos; curpos += 2; // 3 bits: 001 = Type 1; 010 = Type 2 packet_hdr_type = (u16 & 0xE000) >> 13; if (packet_hdr_type != 1 && packet_hdr_type != 2) FAIL(EINVAL); // 2 bits: 00 = noop; 01 = read; 10 = write; 11 = reserved packet_hdr_opcode = (u16 & 0x1800) >> 11; if (packet_hdr_opcode == 3) FAIL(EINVAL); if (packet_hdr_opcode == 0) { // noop if (packet_hdr_type != 1 || u16 & 0x07FF) FAIL(EINVAL); cfg->reg[cfg->num_regs++].reg = REG_NOOP; continue; } packet_hdr_register = (u16 & 0x07E0) >> 5; packet_hdr_wordcount = u16 & 0x001F; if (curpos + packet_hdr_wordcount*2 > len) FAIL(EINVAL); curpos += packet_hdr_wordcount*2; if (packet_hdr_type == 2) { int outdelta; if (packet_hdr_wordcount != 0) { printf("#W 0x%x=0x%x Unexpected Type 2 " "wordcount.\n", u16_off, u16); } if (packet_hdr_register != FDRI) FAIL(EINVAL); // first FAR must be before FDRI, and we should only // execute the FDRI code here once. if (first_FAR_off == -1) FAIL(EINVAL); if (cfg->num_regs_before_bits != -1) FAIL(EINVAL); if (curpos + 4 > len) FAIL(EINVAL); u32 = __be32_to_cpu(*(uint32_t*)&d[curpos]); curpos += 4; if (curpos+2*u32 > len) FAIL(EINVAL); if (2*u32 < 130) FAIL(EINVAL); cfg->reg[cfg->num_regs].reg = FDRI; cfg->reg[cfg->num_regs].int_v = u32; cfg->num_regs++; cfg->num_regs_before_bits = cfg->num_regs; rc = read_bits(cfg, d, len, first_FAR_off, &outdelta); if (rc) FAIL(rc); curpos = first_FAR_off + outdelta; continue; } if (packet_hdr_type != 1) FAIL(EINVAL); if (packet_hdr_register == IDCODE) { if (packet_hdr_wordcount != 2) FAIL(EINVAL); if (cfg->idcode_reg != -1) FAIL(EINVAL); cfg->idcode_reg = cfg->num_regs; cfg->reg[cfg->num_regs].reg = IDCODE; cfg->reg[cfg->num_regs].int_v = __be32_to_cpu(*(uint32_t*)&d[u16_off+2]); cfg->num_regs++; if ((cfg->reg[cfg->idcode_reg].int_v == XC6SLX4 || cfg->reg[cfg->idcode_reg].int_v == XC6SLX9) && cfg->reg[cfg->FLR_reg].int_v != IOB_WORDS) printf("#W Unexpected FLR value %i on " "idcode 0x%X.\n", cfg->reg[cfg->FLR_reg].int_v, cfg->reg[cfg->idcode_reg].int_v); continue; } if (packet_hdr_register == FLR) { if (packet_hdr_wordcount != 1) FAIL(EINVAL); if (cfg->FLR_reg != -1) FAIL(EINVAL); cfg->FLR_reg = cfg->num_regs; // // First come the type 0 frames (clb, bram // cfg, dsp, etc). Then type 1 (bram data), // then type 2, the IOB cfg data block. // FLR is counted in 16-bit words, and there is // 1 extra dummy 0x0000 after that. // cfg->reg[cfg->num_regs].reg = FLR; cfg->reg[cfg->num_regs].int_v = __be16_to_cpu(*(uint16_t*)&d[u16_off+2]); cfg->num_regs++; if ((cfg->reg[cfg->FLR_reg].int_v*2) % 8) printf("#W FLR*2 should be multiple of " "8, but modulo 8 is %i\n", (cfg->reg[cfg->FLR_reg].int_v*2) % 8); continue; } if (packet_hdr_register == FAR_MAJ) { if (packet_hdr_wordcount != 2) FAIL(EINVAL); if (first_FAR_off == -1) first_FAR_off = u16_off; cfg->reg[cfg->num_regs].reg = FAR_MAJ; cfg->reg[cfg->num_regs].far[FAR_MAJ_O] = __be16_to_cpu(*(uint16_t*)&d[u16_off+2]); cfg->reg[cfg->num_regs].far[FAR_MIN_O] = __be16_to_cpu(*(uint16_t*)&d[u16_off+4]); cfg->num_regs++; continue; } if (packet_hdr_register == MFWR) { uint32_t first_dword, second_dword; if (packet_hdr_wordcount != 4) FAIL(EINVAL); first_dword = __be32_to_cpu(*(uint32_t*)&d[u16_off+2]); second_dword = __be32_to_cpu(*(uint32_t*)&d[u16_off+6]); if (first_dword || second_dword) FAIL(EINVAL); cfg->reg[cfg->num_regs++].reg = MFWR; continue; } if (packet_hdr_register == CRC || packet_hdr_register == EXP_SIGN) { if (packet_hdr_wordcount != 2) FAIL(EINVAL); cfg->reg[cfg->num_regs].reg = packet_hdr_register; cfg->reg[cfg->num_regs].int_v = __be32_to_cpu(*(uint32_t*)&d[u16_off+2]); cfg->num_regs++; continue; } if (packet_hdr_register == CMD || packet_hdr_register == COR1 || packet_hdr_register == COR2 || packet_hdr_register == CTL || packet_hdr_register == MASK || packet_hdr_register == PWRDN_REG || packet_hdr_register == HC_OPT_REG || packet_hdr_register == PU_GWE || packet_hdr_register == PU_GTS || packet_hdr_register == CWDT || packet_hdr_register == MODE_REG || packet_hdr_register == CCLK_FREQ || packet_hdr_register == EYE_MASK || packet_hdr_register == GENERAL1 || packet_hdr_register == GENERAL2 || packet_hdr_register == GENERAL3 || packet_hdr_register == GENERAL4 || packet_hdr_register == GENERAL5 || packet_hdr_register == SEU_OPT) { if (packet_hdr_wordcount != 1) FAIL(EINVAL); cfg->reg[cfg->num_regs].reg = packet_hdr_register; cfg->reg[cfg->num_regs].int_v = __be16_to_cpu(*(uint16_t*)&d[u16_off+2]); cfg->num_regs++; 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*) &d[u16_off+2+i*2])); printf("\n"); } return 0; fail: return rc; } static int write_header_str(FILE* f, int code, const char* s) { uint16_t be16_len; int s_len, nwritten, rc; // format: 8-bit code 'a' - 'd' // 16-bit string len, including '\0' // z-terminated string if (fputc(code, f) == EOF) FAIL(errno); s_len = strlen(s)+1; be16_len = __cpu_to_be16(s_len); nwritten = fwrite(&be16_len, /*size*/ 1, sizeof(be16_len), f); if (nwritten != sizeof(be16_len)) FAIL(errno); nwritten = fwrite(s, /*size*/ 1, s_len, f); if (nwritten != s_len) FAIL(errno); return 0; fail: return rc; } static int write_header(FILE* f, const char* str_a, const char* str_b, const char* str_c, const char* str_d) { int nwritten, rc; nwritten = fwrite(s_bit_bof, /*size*/ 1, sizeof(s_bit_bof), f); if (nwritten != sizeof(s_bit_bof)) FAIL(errno); rc = write_header_str(f, 'a', str_a); if (rc) FAIL(rc); rc = write_header_str(f, 'b', str_b); if (rc) FAIL(rc); rc = write_header_str(f, 'c', str_c); if (rc) FAIL(rc); rc = write_header_str(f, 'd', str_d); if (rc) FAIL(rc); return 0; fail: return rc; } static struct fpga_config_reg_rw s_defregs_before_bits[] = {{ CMD, .int_v = CMD_RCRC }, { REG_NOOP }, { FLR, .int_v = IOB_WORDS }, { COR1, .int_v = COR1_DEF | COR1_CRC_BYPASS }, { COR2, .int_v = COR2_DEF }, { IDCODE, .int_v = XC6SLX9 }, { MASK, .int_v = MASK_DEF }, { CTL, .int_v = CTL_DEF }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { CCLK_FREQ, .int_v = CCLK_FREQ_DEF }, { PWRDN_REG, .int_v = PWRDN_REG_DEF }, { EYE_MASK, .int_v = EYE_MASK_DEF }, { HC_OPT_REG, .int_v = HC_OPT_REG_DEF }, { CWDT, .int_v = CWDT_DEF }, { PU_GWE, .int_v = PU_GWE_DEF }, { PU_GTS, .int_v = PU_GTS_DEF }, { MODE_REG, .int_v = MODE_REG_DEF }, { GENERAL1, .int_v = GENERAL1_DEF }, { GENERAL2, .int_v = GENERAL2_DEF }, { GENERAL3, .int_v = GENERAL3_DEF }, { GENERAL4, .int_v = GENERAL4_DEF }, { GENERAL5, .int_v = GENERAL5_DEF }, { SEU_OPT, .int_v = SEU_OPT_DEF }, { EXP_SIGN, .int_v = EXP_SIGN_DEF }, { REG_NOOP }, { REG_NOOP }, { FAR_MAJ, .far = { 0, 0 }}, { CMD, .int_v = CMD_WCFG }}; static struct fpga_config_reg_rw s_defregs_after_bits[] = {{ REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { CMD, .int_v = CMD_GRESTORE }, { CMD, .int_v = CMD_LFRM }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { CMD, .int_v = CMD_GRESTORE }, { CMD, .int_v = CMD_START }, { MASK, .int_v = MASK_DEF | MASK_SECURITY }, { CTL, .int_v = CTL_DEF }, { CRC, .int_v = DEFAULT_AUTO_CRC }, { CMD, .int_v = CMD_DESYNC }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP }}; static int write_reg_action(FILE* f, const struct fpga_config_reg_rw* reg) { uint16_t u16; int nwritten, i, rc; if (reg->reg == REG_NOOP) { u16 = __cpu_to_be16(1 << PACKET_HDR_TYPE_S); nwritten = fwrite(&u16, /*size*/ 1, sizeof(u16), f); if (nwritten != sizeof(u16)) FAIL(errno); return 0; } if (reg->reg == MFWR) { u16 = PACKET_TYPE_1 << PACKET_HDR_TYPE_S; u16 |= PACKET_HDR_OPCODE_WRITE << PACKET_HDR_OPCODE_S; u16 |= reg->reg << PACKET_HDR_REG_S; u16 |= 4; // four 16-bit words u16 = __cpu_to_be16(u16); nwritten = fwrite(&u16, /*size*/ 1, sizeof(u16), f); if (nwritten != sizeof(u16)) FAIL(errno); u16 = 0; for (i = 0; i < 4; i++) { nwritten = fwrite(&u16, /*size*/ 1, sizeof(u16), f); if (nwritten != sizeof(u16)) FAIL(errno); } return 0; } if (reg->reg == FAR_MAJ) { u16 = PACKET_TYPE_1 << PACKET_HDR_TYPE_S; u16 |= PACKET_HDR_OPCODE_WRITE << PACKET_HDR_OPCODE_S; u16 |= reg->reg << PACKET_HDR_REG_S; u16 |= 2; // two 16-bit words u16 = __cpu_to_be16(u16); nwritten = fwrite(&u16, /*size*/ 1, sizeof(u16), f); if (nwritten != sizeof(u16)) FAIL(errno); if (reg->far[FAR_MAJ_O] > 0xFFFF || reg->far[FAR_MIN_O] > 0xFFF) FAIL(EINVAL); u16 = __cpu_to_be16(reg->far[FAR_MAJ_O]); nwritten = fwrite(&u16, /*size*/ 1, sizeof(u16), f); if (nwritten != sizeof(u16)) FAIL(errno); u16 = __cpu_to_be16(reg->far[FAR_MIN_O]); nwritten = fwrite(&u16, /*size*/ 1, sizeof(u16), f); if (nwritten != sizeof(u16)) FAIL(errno); return 0; } if (reg->reg == CRC || reg->reg == IDCODE || reg->reg == EXP_SIGN) { uint32_t u32; u16 = PACKET_TYPE_1 << PACKET_HDR_TYPE_S; u16 |= PACKET_HDR_OPCODE_WRITE << PACKET_HDR_OPCODE_S; u16 |= reg->reg << PACKET_HDR_REG_S; u16 |= 2; // two 16-bit words u16 = __cpu_to_be16(u16); nwritten = fwrite(&u16, /*size*/ 1, sizeof(u16), f); if (nwritten != sizeof(u16)) FAIL(errno); u32 = __cpu_to_be32(reg->int_v); nwritten = fwrite(&u32, /*size*/ 1, sizeof(u32), f); if (nwritten != sizeof(u32)) FAIL(errno); return 0; } static const int t1_oneword_regs[] = { CMD, COR1, COR2, CTL, FLR, MASK, PWRDN_REG, HC_OPT_REG, PU_GWE, PU_GTS, CWDT, MODE_REG, CCLK_FREQ, EYE_MASK, GENERAL1, GENERAL2, GENERAL3, GENERAL4, GENERAL5, SEU_OPT }; for (i = 0; i < sizeof(t1_oneword_regs)/sizeof(t1_oneword_regs[0]); i++) { if (reg->reg == t1_oneword_regs[i]) break; } if (i >= sizeof(t1_oneword_regs)/sizeof(t1_oneword_regs[0])) FAIL(EINVAL); u16 = PACKET_TYPE_1 << PACKET_HDR_TYPE_S; u16 |= PACKET_HDR_OPCODE_WRITE << PACKET_HDR_OPCODE_S; u16 |= reg->reg << PACKET_HDR_REG_S; u16 |= 1; // one word u16 = __cpu_to_be16(u16); nwritten = fwrite(&u16, /*size*/ 1, sizeof(u16), f); if (nwritten != sizeof(u16)) FAIL(errno); if (reg->int_v > 0xFFFF) FAIL(EINVAL); u16 = __cpu_to_be16(reg->int_v); nwritten = fwrite(&u16, /*size*/ 1, sizeof(u16), f); if (nwritten != sizeof(u16)) FAIL(errno); return 0; fail: return rc; } static int write_bits(FILE* f, struct fpga_model* model) { struct fpga_bits bits; uint16_t u16; uint32_t u32; int nwritten, i, j, rc; char padding_frame[FRAME_SIZE]; RC_CHECK(model); bits.len = IOB_DATA_START + IOB_DATA_LEN; bits.d = calloc(bits.len, /*elsize*/ 1); if (!bits.d) FAIL(ENOMEM); rc = write_model(&bits, model); if (rc) FAIL(rc); u16 = PACKET_TYPE_2 << PACKET_HDR_TYPE_S; u16 |= PACKET_HDR_OPCODE_WRITE << PACKET_HDR_OPCODE_S; u16 |= FDRI << PACKET_HDR_REG_S; u16 |= 0; // zero 16-bit words u16 = __cpu_to_be16(u16); nwritten = fwrite(&u16, /*size*/ 1, sizeof(u16), f); if (nwritten != sizeof(u16)) FAIL(errno); u32 = (FRAMES_DATA_LEN + NUM_ROWS*PADDING_FRAMES_PER_ROW*FRAME_SIZE + BRAM_DATA_LEN + IOB_DATA_LEN)/2; u32++; // there is one extra 16-bit 0x0000 padding at the end u32 = __cpu_to_be32(u32); nwritten = fwrite(&u32, /*size*/ 1, sizeof(u32), f); if (nwritten != sizeof(u32)) FAIL(errno); // initialize padding frame to 0xFF for (i = 0; i < FRAME_SIZE; i++) padding_frame[i] = 0xFF; // write rows with padding frames for (i = 0; i < NUM_ROWS; i++) { nwritten = fwrite(&bits.d[i*FRAMES_PER_ROW*FRAME_SIZE], /*size*/ 1, FRAMES_PER_ROW*FRAME_SIZE, f); if (nwritten != FRAMES_PER_ROW*FRAME_SIZE) FAIL(errno); for (j = 0; j < PADDING_FRAMES_PER_ROW; j++) { nwritten = fwrite(padding_frame, /*size*/ 1, FRAME_SIZE, f); if (nwritten != FRAME_SIZE) FAIL(errno); } } // write bram data nwritten = fwrite(&bits.d[BRAM_DATA_START], /*size*/ 1, BRAM_DATA_LEN, f); if (nwritten != BRAM_DATA_LEN) FAIL(errno); // write IOB data nwritten = fwrite(&bits.d[IOB_DATA_START], /*size*/ 1, IOB_DATA_LEN, f); if (nwritten != IOB_DATA_LEN) FAIL(errno); // write extra 0x0000 padding at end of FDRI block u16 = 0; nwritten = fwrite(&u16, /*size*/ 1, sizeof(u16), f); if (nwritten != sizeof(u16)) FAIL(errno); // todo: support real auto-crc calculation u32 = DEFAULT_AUTO_CRC; u32 = __cpu_to_be32(u32); nwritten = fwrite(&u32, /*size*/ 1, sizeof(u32), f); if (nwritten != sizeof(u32)) FAIL(errno); free(bits.d); return 0; fail: free(bits.d); return rc; } int write_bitfile(FILE* f, struct fpga_model* model) { uint32_t u32; int len_to_eof_pos, eof_pos, nwritten, i, rc; RC_CHECK(model); rc = write_header(f, "fpgatools.fp;UserID=0xFFFFFFFF", "6slx9tqg144", "2010/05/26", "08:00:00"); if (rc) FAIL(rc); if (fputc('e', f) == EOF) FAIL(errno); if ((len_to_eof_pos = ftell(f)) == -1) FAIL(errno); u32 = 0; nwritten = fwrite(&u32, /*size*/ 1, sizeof(u32), f); if (nwritten != sizeof(u32)) FAIL(errno); nwritten = fwrite(s_0xFF_words, /*size*/ 1, sizeof(s_0xFF_words), f); if (nwritten != sizeof(s_0xFF_words)) FAIL(errno); u32 = __cpu_to_be32(SYNC_WORD); nwritten = fwrite(&u32, /*size*/ 1, sizeof(u32), f); if (nwritten != sizeof(u32)) FAIL(errno); for (i = 0; i < sizeof(s_defregs_before_bits)/sizeof(s_defregs_before_bits[0]); i++) { rc = write_reg_action(f, &s_defregs_before_bits[i]); if (rc) FAIL(rc); } rc = write_bits(f, model); if (rc) FAIL(rc); for (i = 0; i < sizeof(s_defregs_after_bits)/sizeof(s_defregs_after_bits[0]); i++) { rc = write_reg_action(f, &s_defregs_after_bits[i]); if (rc) FAIL(rc); } // write len to eof at offset len_to_eof_pos if ((eof_pos = ftell(f)) == -1) FAIL(errno); if (fseek(f, len_to_eof_pos, SEEK_SET) == -1) FAIL(errno); u32 = __cpu_to_be32(eof_pos - len_to_eof_pos - sizeof(u32)); nwritten = fwrite(&u32, /*size*/ 1, sizeof(u32), f); if (nwritten != sizeof(u32)) FAIL(errno); if (fseek(f, eof_pos, SEEK_SET) == -1) FAIL(errno); return 0; fail: return rc; }