fpgatools/libs/bit_regs.c
2015-04-01 17:13:32 -04:00

1705 lines
48 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 "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_i<XC6_HCLK_POS/XC6_WORD_BYTES ? word_i : word_i - 1);
w_old = frame_get_cpuword(&old_minor_bits[word_i*XC6_WORD_BYTES]);
w_new = frame_get_cpuword(&new_minor_bits[word_i*XC6_WORD_BYTES]);
if (w_old == w_new) continue;
printf("#I <r%i ma%i %s mi%i %s", row, major, v16_str, minor, fmt_word(w_old));
printf("#I >r%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_i<XC6_HCLK_POS/XC6_WORD_BYTES ? word_i : word_i - 1);
for (minor_i = minor; minor_i < minor + num_minors; minor_i++) {
w = frame_get_cpuword(&major_bits[minor_i*FRAME_SIZE
+ word_i*XC6_WORD_BYTES]);
if (!w) continue;
printf("r%i ma%i %s mi%i %s", row, major, v16_str, minor_i, fmt_word(w));
}
}
}
static int dump_maj_bram(const uint8_t *bits, int row, int major)
{
int minor, i;
for (minor = 0; minor < get_major_minors(XC6SLX9, major); 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);
printf_minors(row, major, /*minor*/ 21, /*num_minors*/ 4, bits);
return 0;
}
static int dump_maj_macc(const uint8_t* bits, int row, int major)
{
int minor, i;
for (minor = 0; minor < get_major_minors(XC6SLX9, major); 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);
for (minor = 21; 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_bits(struct fpga_config* cfg)
{
int idcode, num_rows, row, major, off, rc;
const struct xc_die* die_info;
if (cfg->idcode_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;
}