improved iob config

This commit is contained in:
Wolfgang Spraul 2012-09-23 03:10:01 +02:00
parent 62db4b6911
commit 1621628e6d
7 changed files with 366 additions and 45 deletions

View File

@ -24,6 +24,7 @@ struct test_state
int cmdline_skip;
char cmdline_diff_exec[1024];
int dry_run;
int diff_to_null;
struct fpga_model* model;
// test filenames are: tmp_dir/autotest_<base_name>_<diff_counter>.???
@ -81,7 +82,8 @@ static int diff_printf(struct test_state* tstate)
snprintf(path, sizeof(path), "%s/autotest_%s_%06i", tstate->tmp_dir,
tstate->base_name, tstate->next_diff_counter);
path_base = strlen(path);
if (tstate->next_diff_counter == tstate->cmdline_skip + 1)
if (tstate->diff_to_null
|| tstate->next_diff_counter == tstate->cmdline_skip + 1)
strcpy(prior_fp, "/dev/null");
else {
snprintf(prior_fp, sizeof(prior_fp), "%s/autotest_%s_%06i.fp",
@ -872,6 +874,118 @@ fail:
return rc;
}
static int test_iob_config(struct test_state* tstate)
{
int iob_y, iob_x, iob_type_idx, rc;
net_idx_t net_idx;
struct fpga_device* dev;
tstate->diff_to_null = 1;
// P45 is an IOBS
rc = fpga_find_iob(tstate->model, "P45", &iob_y, &iob_x, &iob_type_idx);
if (rc) FAIL(rc);
rc = fdev_iob_input(tstate->model, iob_y, iob_x, iob_type_idx);
if (rc) FAIL(rc);
dev = fdev_p(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
if (!dev) FAIL(EINVAL);
if ((rc = diff_printf(tstate))) FAIL(rc);
dev->u.iob.I_mux = IMUX_I_B;
if ((rc = diff_printf(tstate))) FAIL(rc);
fdev_delete(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
// P46 is an IOBM
rc = fpga_find_iob(tstate->model, "P46", &iob_y, &iob_x, &iob_type_idx);
if (rc) FAIL(rc);
rc = fdev_iob_input(tstate->model, iob_y, iob_x, iob_type_idx);
if (rc) FAIL(rc);
if ((rc = diff_printf(tstate))) FAIL(rc);
fdev_delete(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
// P47 is an IOBS
rc = fpga_find_iob(tstate->model, "P47", &iob_y, &iob_x, &iob_type_idx);
if (rc) FAIL(rc);
rc = fdev_iob_output(tstate->model, iob_y, iob_x, iob_type_idx);
if (rc) FAIL(rc);
dev = fdev_p(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
if (!dev) FAIL(EINVAL);
// least amount of bits:
dev->u.iob.slew = SLEW_SLOW;
dev->u.iob.drive_strength = 8;
dev->u.iob.suspend = SUSP_3STATE;
dev->u.iob.suspend = SUSP_3STATE;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.suspend = SUSP_3STATE_OCT_ON;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.suspend = SUSP_3STATE_KEEPER;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.suspend = SUSP_3STATE_PULLUP;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.suspend = SUSP_3STATE_PULLDOWN;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.suspend = SUSP_LAST_VAL;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.suspend = SUSP_3STATE;
dev->u.iob.drive_strength = 2;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.drive_strength = 4;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.drive_strength = 6;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.drive_strength = 8;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.drive_strength = 12;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.drive_strength = 16;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.drive_strength = 24;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.drive_strength = 8;
dev->u.iob.slew = SLEW_SLOW;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.slew = SLEW_FAST;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.slew = SLEW_QUIETIO;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.slew = SLEW_SLOW;
fdev_delete(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
// P48 is an IOBM
rc = fpga_find_iob(tstate->model, "P48", &iob_y, &iob_x, &iob_type_idx);
if (rc) FAIL(rc);
rc = fdev_iob_output(tstate->model, iob_y, iob_x, iob_type_idx);
if (rc) FAIL(rc);
dev = fdev_p(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
if (!dev) FAIL(EINVAL);
// least bits
dev->u.iob.slew = SLEW_SLOW;
dev->u.iob.drive_strength = 8;
dev->u.iob.suspend = SUSP_3STATE;
// new net
rc = fnet_new(tstate->model, &net_idx);
if (rc) FAIL(rc);
// add iob port
rc = fnet_add_port(tstate->model, net_idx, iob_y, iob_x,
DEV_IOB, iob_type_idx, IOB_IN_O);
if (rc) FAIL(rc);
if ((rc = diff_printf(tstate))) FAIL(rc);
fdev_delete(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
return 0;
fail:
return rc;
}
#define DEFAULT_DIFF_EXEC "./autotest_diff.sh"
static void printf_help(const char* argv_0, const char** available_tests)
@ -879,8 +993,8 @@ static void printf_help(const char* argv_0, const char** available_tests)
printf( "\n"
"fpgatools automatic test suite\n"
"\n"
"Usage: %s [--test=<name>] [--diff=<diff executable>] [--skip=<num>]\n"
" %*s [--dry-run]\n"
"Usage: %s [--test=<name>] [--skip=<num>] [--dry-run]\n"
" %*s [--diff=<diff executable>]\n"
"Default diff executable: " DEFAULT_DIFF_EXEC "\n", argv_0, (int) strlen(argv_0), "");
if (available_tests) {
@ -902,7 +1016,7 @@ int main(int argc, char** argv)
char param[1024], cmdline_test[1024];
int i, param_skip, rc;
const char* available_tests[] =
{ "logic_cfg", "routing_sw", "io_sw", 0 };
{ "logic_cfg", "routing_sw", "io_sw", "iob_cfg", 0 };
// flush after every line is better for the autotest
// output, tee, etc.
@ -923,6 +1037,7 @@ int main(int argc, char** argv)
tstate.cmdline_diff_exec[0] = 0;
cmdline_test[0] = 0;
tstate.dry_run = -1;
tstate.diff_to_null = 0;
for (i = 1; i < argc; i++) {
memset(param, 0, sizeof(param));
if (sscanf(argv[i], "--test=%1023c", param) == 1) {
@ -1022,6 +1137,10 @@ int main(int argc, char** argv)
rc = test_iologic_switches(&tstate);
if (rc) FAIL(rc);
}
if (!strcmp(cmdline_test, "iob_cfg")) {
rc = test_iob_config(&tstate);
if (rc) FAIL(rc);
}
printf("\n");
printf("O Test completed.\n");

View File

@ -94,11 +94,12 @@ struct extract_state
static int write_iobs(struct fpga_bits* bits, struct fpga_model* model)
{
int i, y, x, type_idx, part_idx, dev_idx, rc;
int i, y, x, type_idx, part_idx, dev_idx, first_iob, rc;
struct fpga_device* dev;
uint32_t* u32_p;
uint64_t u64;
const char* name;
first_iob = 0;
for (i = 0; (name = fpga_enum_iob(model, i, &y, &x, &type_idx)); i++) {
dev_idx = fpga_dev_idx(model, y, x, DEV_IOB, type_idx);
if (dev_idx == NO_DEV) FAIL(EINVAL);
@ -112,15 +113,71 @@ static int write_iobs(struct fpga_bits* bits, struct fpga_model* model)
continue;
}
u32_p = (uint32_t*)
&bits->d[IOB_DATA_START + part_idx*IOB_ENTRY_LEN];
if (dev->u.iob.O_used) {
u32_p[0] = 0x00000180;
u32_p[1] = 0x06001100;
} else if (dev->u.iob.I_mux == IMUX_I) {
u32_p[0] = 0x00000107;
u32_p[1] = 0x0B002400;
if (!first_iob) {
first_iob = 1;
// todo: is this right on the other sides?
set_bit(bits, /*row*/ 0, get_rightside_major(XC6SLX9),
/*minor*/ 22, 64*15+XC6_HCLK_BITS+4);
}
if (dev->u.iob.istandard[0]) {
if (!dev->u.iob.I_mux
|| !dev->u.iob.bypass_mux
|| strcmp(dev->u.iob.istandard, IO_LVCMOS33)
|| dev->u.iob.ostandard[0])
HERE();
u64 = XC6_IOB_INSTANTIATED;
u64 |= XC6_IOB_INPUT_LVCMOS33;
if (dev->u.iob.I_mux == IMUX_I)
u64 |= XC6_IOB_IMUX_I;
else if (dev->u.iob.I_mux == IMUX_I_B)
u64 |= XC6_IOB_IMUX_I_B;
else HERE();
frame_set_u64(&bits->d[IOB_DATA_START
+ part_idx*IOB_ENTRY_LEN], u64);
} else if (dev->u.iob.ostandard[0]) {
if (!dev->u.iob.drive_strength
|| !dev->u.iob.slew
|| !dev->u.iob.suspend
|| strcmp(dev->u.iob.ostandard, IO_LVCMOS33)
|| dev->u.iob.istandard[0])
HERE();
u64 = XC6_IOB_INSTANTIATED;
// for now we always turn on O_PINW even if no net
// is connected to the pinw
u64 |= XC6_IOB_MASK_O_PINW;
switch (dev->u.iob.drive_strength) {
case 2: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_2; break;
case 4: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_4; break;
case 6: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_6; break;
case 8: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_8; break;
case 12: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_12; break;
case 16: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_16; break;
case 24: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_24; break;
default: HERE();
}
switch (dev->u.iob.slew) {
case SLEW_SLOW: u64 |= XC6_IOB_SLEW_SLOW; break;
case SLEW_QUIETIO: u64 |= XC6_IOB_SLEW_QUIETIO; break;
case SLEW_FAST: u64 |= XC6_IOB_SLEW_FAST; break;
default: HERE();
}
switch (dev->u.iob.suspend) {
case SUSP_LAST_VAL: u64 |= XC6_IOB_SUSP_LAST_VAL; break;
case SUSP_3STATE: u64 |= XC6_IOB_SUSP_3STATE; break;
case SUSP_3STATE_PULLUP: u64 |= XC6_IOB_SUSP_3STATE_PULLUP; break;
case SUSP_3STATE_PULLDOWN: u64 |= XC6_IOB_SUSP_3STATE_PULLDOWN; break;
case SUSP_3STATE_KEEPER: u64 |= XC6_IOB_SUSP_3STATE_KEEPER; break;
case SUSP_3STATE_OCT_ON: u64 |= XC6_IOB_SUSP_3STATE_OCT_ON; break;
default: HERE();
}
frame_set_u64(&bits->d[IOB_DATA_START
+ part_idx*IOB_ENTRY_LEN], u64);
} else HERE();
}
return 0;
fail:
@ -129,16 +186,18 @@ fail:
static int extract_iobs(struct fpga_model* model, struct fpga_bits* bits)
{
int i, num_iobs, iob_y, iob_x, iob_idx, dev_idx, rc;
uint32_t* u32_p;
int i, num_iobs, iob_y, iob_x, iob_idx, dev_idx, first_iob, rc;
uint64_t u64;
const char* iob_sitename;
struct fpga_device* dev;
struct fpgadev_iob cfg;
num_iobs = get_num_iobs(XC6SLX9);
first_iob = 0;
for (i = 0; i < num_iobs; i++) {
u32_p = (uint32_t*) &bits->d[IOB_DATA_START + i*IOB_ENTRY_LEN];
if (!u32_p[0] && !u32_p[1])
continue;
u64 = frame_get_u64(&bits->d[IOB_DATA_START + i*IOB_ENTRY_LEN]);
if (!u64) continue;
iob_sitename = get_iob_sitename(XC6SLX9, i);
if (!iob_sitename) {
HERE();
@ -149,27 +208,118 @@ static int extract_iobs(struct fpga_model* model, struct fpga_bits* bits)
dev_idx = fpga_dev_idx(model, iob_y, iob_x, DEV_IOB, iob_idx);
if (dev_idx == NO_DEV) FAIL(EINVAL);
dev = FPGA_DEV(model, iob_y, iob_x, dev_idx);
memset(&cfg, 0, sizeof(cfg));
// we only support 2 hardcoded types of IOB right now
// todo: bit 7 goes on when out-net connected?
if ((u32_p[0] & 0xFFFFFF7F) == 0x00000100
&& u32_p[1] == 0x06001100) {
if (!first_iob) {
first_iob = 1;
// todo: is this right on the other sides?
if (!get_bit(bits, /*row*/ 0, get_rightside_major(XC6SLX9),
/*minor*/ 22, 64*15+XC6_HCLK_BITS+4))
HERE();
clear_bit(bits, /*row*/ 0, get_rightside_major(XC6SLX9),
/*minor*/ 22, 64*15+XC6_HCLK_BITS+4);
}
if ((u64 & XC6_IOB_MASK_INSTANTIATED) == XC6_IOB_INSTANTIATED)
u64 &= ~XC6_IOB_MASK_INSTANTIATED;
else
HERE();
switch (u64 & XC6_IOB_MASK_IO) {
case XC6_IOB_INPUT_LVCMOS33:
u64 &= ~XC6_IOB_MASK_IO;
strcpy(cfg.istandard, IO_LVCMOS33);
cfg.bypass_mux = BYPASS_MUX_I;
switch (u64 & XC6_IOB_MASK_I_MUX) {
case XC6_IOB_IMUX_I:
u64 &= ~XC6_IOB_MASK_I_MUX;
cfg.I_mux = IMUX_I;
break;
case XC6_IOB_IMUX_I_B:
u64 &= ~XC6_IOB_MASK_I_MUX;
cfg.I_mux = IMUX_I_B;
break;
default: HERE();
}
break;
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_2:
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_4:
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_6:
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_8:
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_12:
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_16:
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_24:
u64 &= ~XC6_IOB_MASK_IO;
u64 &= ~XC6_IOB_MASK_O_PINW;
strcpy(cfg.ostandard, IO_LVCMOS33);
cfg.O_used = 1;
switch (u64 & XC6_IOB_MASK_IO) {
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_2:
cfg.drive_strength = 2; break;
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_4:
cfg.drive_strength = 4; break;
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_6:
cfg.drive_strength = 6; break;
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_8:
cfg.drive_strength = 8; break;
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_12:
cfg.drive_strength = 12; break;
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_16:
cfg.drive_strength = 16; break;
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_24:
cfg.drive_strength = 24; break;
default: HERE();
}
switch (u64 & XC6_IOB_MASK_SLEW) {
case XC6_IOB_SLEW_SLOW:
u64 &= ~XC6_IOB_MASK_SLEW;
cfg.slew = SLEW_SLOW;
break;
case XC6_IOB_SLEW_QUIETIO:
u64 &= ~XC6_IOB_MASK_SLEW;
cfg.slew = SLEW_QUIETIO;
break;
case XC6_IOB_SLEW_FAST:
u64 &= ~XC6_IOB_MASK_SLEW;
cfg.slew = SLEW_FAST;
break;
default: HERE();
}
switch (u64 & XC6_IOB_MASK_SUSPEND) {
case XC6_IOB_SUSP_3STATE:
u64 &= ~XC6_IOB_MASK_SUSPEND;
cfg.suspend = SUSP_3STATE;
break;
case XC6_IOB_SUSP_3STATE_OCT_ON:
u64 &= ~XC6_IOB_MASK_SUSPEND;
cfg.suspend = SUSP_3STATE_OCT_ON;
break;
case XC6_IOB_SUSP_3STATE_KEEPER:
u64 &= ~XC6_IOB_MASK_SUSPEND;
cfg.suspend = SUSP_3STATE_KEEPER;
break;
case XC6_IOB_SUSP_3STATE_PULLUP:
u64 &= ~XC6_IOB_MASK_SUSPEND;
cfg.suspend = SUSP_3STATE_PULLUP;
break;
case XC6_IOB_SUSP_3STATE_PULLDOWN:
u64 &= ~XC6_IOB_MASK_SUSPEND;
cfg.suspend = SUSP_3STATE_PULLDOWN;
break;
case XC6_IOB_SUSP_LAST_VAL:
u64 &= ~XC6_IOB_MASK_SUSPEND;
cfg.suspend = SUSP_LAST_VAL;
break;
default: HERE();
}
break;
default: HERE(); break;
}
if (!u64) {
dev->instantiated = 1;
strcpy(dev->u.iob.ostandard, IO_LVCMOS33);
dev->u.iob.drive_strength = 12;
dev->u.iob.O_used = 1;
dev->u.iob.slew = SLEW_SLOW;
dev->u.iob.suspend = SUSP_3STATE;
u32_p[0] = 0;
u32_p[1] = 0;
} else if (u32_p[0] == 0x00000107
&& u32_p[1] == 0x0B002400) {
dev->instantiated = 1;
strcpy(dev->u.iob.istandard, IO_LVCMOS33);
dev->u.iob.bypass_mux = BYPASS_MUX_I;
dev->u.iob.I_mux = IMUX_I;
u32_p[0] = 0;
u32_p[1] = 0;
dev->u.iob = cfg;
} else HERE();
}
return 0;

View File

@ -579,9 +579,9 @@ int fdev_iob_output(struct fpga_model* model, int y, int x, int type_idx)
if (rc) FAIL(rc);
strcpy(dev->u.iob.ostandard, IO_LVCMOS33);
dev->u.iob.drive_strength = 12;
dev->u.iob.drive_strength = 8;
dev->u.iob.O_used = 1;
dev->u.iob.slew = SLEW_SLOW;
dev->u.iob.slew = SLEW_QUIETIO;
dev->u.iob.suspend = SUSP_3STATE;
dev->instantiated = 1;
return 0;

View File

@ -364,14 +364,18 @@ const char* lut2bool(const uint64_t lut, int bits,
int printf_iob(uint8_t* d, int len, int inpos, int num_entries)
{
int i, j, num_printed;
uint64_t u64;
num_printed = 0;
for (i = 0; i < num_entries; i++) {
if (*(uint32_t*)&d[inpos+i*8] || *(uint32_t*)&d[inpos+i*8+4]) {
printf("iob i%i", i);
for (j = 0; j < 8; j++)
printf(" %02X", d[inpos+i*8+j]);
printf("\n");
u64 = frame_get_u64(&d[inpos+i*8]);
if (u64) {
printf("iob i%i 0x%016llX\n", i,
(long long unsigned) u64);
for (j = 0; j < 64; j++) {
if (u64 & (1ULL << j))
printf("iob i%i b%i\n", i, j);
}
num_printed++;
}
}

View File

@ -446,6 +446,7 @@ struct fpgadev_logic
enum { IOBM = 1, IOBS };
typedef char IOSTANDARD[32];
#define IO_LVCMOS33 "LVCMOS33"
#define IO_SSTL2_I "SSTL2_I" // drive attr and slew not used here?
enum { BYPASS_MUX_I = 1, BYPASS_MUX_O, BYPASS_MUX_T };
enum { IMUX_I_B = 1, IMUX_I };
enum { SLEW_SLOW = 1, SLEW_FAST, SLEW_QUIETIO };

View File

@ -150,6 +150,15 @@ enum major_type get_major_type(int idcode, int major)
return major_types[major];
}
int get_rightside_major(int idcode)
{
if ((idcode & IDCODE_MASK) != XC6SLX9) {
HERE();
return -1;
}
return XC6_SLX9_RIGHTMOST_MAJOR;
}
//
// routing switches
//

View File

@ -38,12 +38,50 @@
#define IOB_ENTRY_LEN 8
#define BITS_LEN (IOB_DATA_START+IOB_DATA_LEN)
#define XC6_HCLK_BYTES 2
#define XC6_HCLK_BITS (XC6_HCLK_BYTES*8)
#define XC6_IOB_MASK_INSTANTIATED 0x0000000000000080
#define XC6_IOB_MASK_IO 0x00FF00FF00000000
#define XC6_IOB_MASK_O_PINW 0x0000000000000100
#define XC6_IOB_MASK_I_MUX 0x000000000000E400
#define XC6_IOB_MASK_SLEW 0x0000000000FF0000
#define XC6_IOB_MASK_SUSPEND 0x000000000000001F
#define XC6_IOB_INSTANTIATED 0x0000000000000080
#define XC6_IOB_INPUT_LVCMOS33 0x00D0024000000000
#define XC6_IOB_OUTPUT_LVCMOS33_DRIVE_2 0x00100B4000000000
#define XC6_IOB_OUTPUT_LVCMOS33_DRIVE_4 0x007006C000000000
#define XC6_IOB_OUTPUT_LVCMOS33_DRIVE_6 0x00300FC000000000
#define XC6_IOB_OUTPUT_LVCMOS33_DRIVE_8 0x0040000000000000
#define XC6_IOB_OUTPUT_LVCMOS33_DRIVE_12 0x0060088000000000
#define XC6_IOB_OUTPUT_LVCMOS33_DRIVE_16 0x00980C6000000000
#define XC6_IOB_OUTPUT_LVCMOS33_DRIVE_24 0x0088072000000000
#define XC6_IOB_O_PINW 0x0000000000000100
#define XC6_IOB_IMUX_I 0x000000000000E000
#define XC6_IOB_IMUX_I_B 0x000000000000E400
#define XC6_IOB_SLEW_SLOW 0x0000000000000000
#define XC6_IOB_SLEW_QUIETIO 0x0000000000330000
#define XC6_IOB_SLEW_FAST 0x0000000000660000
#define XC6_IOB_SUSP_3STATE 0x0000000000000000
#define XC6_IOB_SUSP_3STATE_OCT_ON 0x0000000000000001
#define XC6_IOB_SUSP_3STATE_KEEPER 0x0000000000000002
#define XC6_IOB_SUSP_3STATE_PULLUP 0x0000000000000004
#define XC6_IOB_SUSP_3STATE_PULLDOWN 0x0000000000000008
#define XC6_IOB_SUSP_LAST_VAL 0x0000000000000010
int get_major_minors(int idcode, int major);
enum major_type { MAJ_ZERO, MAJ_LEFT, MAJ_RIGHT, MAJ_CENTER,
MAJ_LOGIC_XM, MAJ_LOGIC_XL, MAJ_BRAM, MAJ_MACC };
enum major_type get_major_type(int idcode, int major);
#define XC6_ZERO_MAJOR 0
#define XC6_LEFTSIDE_MAJOR 1
#define XC6_SLX9_RIGHTMOST_MAJOR 17
int get_rightside_major(int idcode);
int get_num_iobs(int idcode);
const char* get_iob_sitename(int idcode, int idx);
// returns -1 if sitename not found