fpgatools/libs/bit_frames.c
2013-02-14 08:42:08 -05:00

3098 lines
96 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"
#include "control.h"
#undef DBG_EXTRACT_T2
#undef DBG_EXTRACT_LOGIC_SW
#undef DBG_EXTRACT_ROUTING_SW
static uint8_t* get_first_minor(struct fpga_bits* bits, int row, int major)
{
int i, num_frames;
if (row < 0) { HERE(); return 0; }
num_frames = 0;
for (i = 0; i < major; i++)
num_frames += get_major_minors(XC6SLX9, i);
return &bits->d[(row*FRAMES_PER_ROW + num_frames)*FRAME_SIZE];
}
static int get_bit(struct fpga_bits* bits,
int row, int major, int minor, int bit_i)
{
return frame_get_bit(get_first_minor(bits, row, major)
+ minor*FRAME_SIZE, bit_i);
}
static void set_bit(struct fpga_bits* bits,
int row, int major, int minor, int bit_i)
{
return frame_set_bit(get_first_minor(bits, row, major)
+ minor*FRAME_SIZE, bit_i);
}
static void clear_bit(struct fpga_bits* bits,
int row, int major, int minor, int bit_i)
{
return frame_clear_bit(get_first_minor(bits, row, major)
+ minor*FRAME_SIZE, bit_i);
}
struct bit_pos
{
int row;
int major;
int minor;
int bit_i;
};
static int get_bitp(struct fpga_bits* bits, struct bit_pos* pos)
{
return get_bit(bits, pos->row, pos->major, pos->minor, pos->bit_i);
}
static void set_bitp(struct fpga_bits* bits, struct bit_pos* pos)
{
set_bit(bits, pos->row, pos->major, pos->minor, pos->bit_i);
}
static void clear_bitp(struct fpga_bits* bits, struct bit_pos* pos)
{
clear_bit(bits, pos->row, pos->major, pos->minor, pos->bit_i);
}
static struct bit_pos s_default_bits[] = {
{ 0, 0, 3, 66 },
{ 0, 1, 23, 1034 },
{ 0, 1, 23, 1035 },
{ 0, 1, 23, 1039 },
{ 2, 0, 3, 66 }};
struct sw_yxpos
{
int y;
int x;
swidx_t idx;
};
// random value of about 10kk switches for now, meaning
// about 100MB memory usage
#define MAX_YX_SWITCHES 10*1024*1024
struct extract_state
{
struct fpga_model* model;
struct fpga_bits* bits;
// yx switches are fully extracted ones pointing into the
// model, stored here for later processing into nets.
int num_yx_pos;
struct sw_yxpos *yx_pos;
};
static int find_es_switch(struct extract_state* es, int y, int x, swidx_t sw)
{
int i;
RC_CHECK(es->model);
if (sw == NO_SWITCH) { HERE(); return 0; }
for (i = 0; i < es->num_yx_pos; i++) {
if (es->yx_pos[i].y == y
&& es->yx_pos[i].x == x
&& es->yx_pos[i].idx == sw)
return 1;
}
return 0;
}
static int write_type2(struct fpga_bits* bits, struct fpga_model* model)
{
int y, x, type_idx, t2_idx, first_iob, rc;
struct fpga_device* dev;
uint64_t u64;
RC_CHECK(model);
first_iob = 0;
for (t2_idx = 0; t2_idx < model->die->num_t2_ios; t2_idx++) {
if (!model->die->t2_io[t2_idx].pair)
continue;
y = model->die->t2_io[t2_idx].y;
x = model->die->t2_io[t2_idx].x;
type_idx = model->die->t2_io[t2_idx].type_idx;
dev = fdev_p(model, y, x, DEV_IOB, type_idx);
RC_ASSERT(model, dev);
if (!dev->instantiated)
continue;
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
|| dev->u.iob.ostandard[0])
HERE();
u64 = XC6_IOB_INPUT | XC6_IOB_INSTANTIATED;
if (dev->u.iob.I_mux == IMUX_I_B)
u64 |= XC6_IOB_IMUX_I_B;
if (!strcmp(dev->u.iob.istandard, IO_LVCMOS33)
|| !strcmp(dev->u.iob.istandard, IO_LVCMOS25)
|| !strcmp(dev->u.iob.istandard, IO_LVTTL))
u64 |= XC6_IOB_INPUT_LVCMOS33_25_LVTTL;
else if (!strcmp(dev->u.iob.istandard, IO_LVCMOS18)
|| !strcmp(dev->u.iob.istandard, IO_LVCMOS15)
|| !strcmp(dev->u.iob.istandard, IO_LVCMOS12))
u64 |= XC6_IOB_INPUT_LVCMOS18_15_12;
else if (!strcmp(dev->u.iob.istandard, IO_LVCMOS18_JEDEC)
|| !strcmp(dev->u.iob.istandard, IO_LVCMOS15_JEDEC)
|| !strcmp(dev->u.iob.istandard, IO_LVCMOS12_JEDEC))
u64 |= XC6_IOB_INPUT_LVCMOS18_15_12_JEDEC;
else if (!strcmp(dev->u.iob.istandard, IO_SSTL2_I))
u64 |= XC6_IOB_INPUT_SSTL2_I;
else
HERE();
frame_set_u64(&bits->d[IOB_DATA_START
+ t2_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
|| 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_O_PINW;
if (!strcmp(dev->u.iob.ostandard, IO_LVTTL)) {
switch (dev->u.iob.drive_strength) {
case 2: u64 |= XC6_IOB_OUTPUT_LVTTL_DRIVE_2; break;
case 4: u64 |= XC6_IOB_OUTPUT_LVTTL_DRIVE_4; break;
case 6: u64 |= XC6_IOB_OUTPUT_LVTTL_DRIVE_6; break;
case 8: u64 |= XC6_IOB_OUTPUT_LVTTL_DRIVE_8; break;
case 12: u64 |= XC6_IOB_OUTPUT_LVTTL_DRIVE_12; break;
case 16: u64 |= XC6_IOB_OUTPUT_LVTTL_DRIVE_16; break;
case 24: u64 |= XC6_IOB_OUTPUT_LVTTL_DRIVE_24; break;
default: FAIL(EINVAL);
}
} else if (!strcmp(dev->u.iob.ostandard, IO_LVCMOS33)) {
switch (dev->u.iob.drive_strength) {
case 2: u64 |= XC6_IOB_OUTPUT_LVCMOS33_25_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: FAIL(EINVAL);
}
} else if (!strcmp(dev->u.iob.ostandard, IO_LVCMOS25)) {
switch (dev->u.iob.drive_strength) {
case 2: u64 |= XC6_IOB_OUTPUT_LVCMOS33_25_DRIVE_2; break;
case 4: u64 |= XC6_IOB_OUTPUT_LVCMOS25_DRIVE_4; break;
case 6: u64 |= XC6_IOB_OUTPUT_LVCMOS25_DRIVE_6; break;
case 8: u64 |= XC6_IOB_OUTPUT_LVCMOS25_DRIVE_8; break;
case 12: u64 |= XC6_IOB_OUTPUT_LVCMOS25_DRIVE_12; break;
case 16: u64 |= XC6_IOB_OUTPUT_LVCMOS25_DRIVE_16; break;
case 24: u64 |= XC6_IOB_OUTPUT_LVCMOS25_DRIVE_24; break;
default: FAIL(EINVAL);
}
} else if (!strcmp(dev->u.iob.ostandard, IO_LVCMOS18)
|| !strcmp(dev->u.iob.ostandard, IO_LVCMOS18_JEDEC)) {
switch (dev->u.iob.drive_strength) {
case 2: u64 |= XC6_IOB_OUTPUT_LVCMOS18_DRIVE_2; break;
case 4: u64 |= XC6_IOB_OUTPUT_LVCMOS18_DRIVE_4; break;
case 6: u64 |= XC6_IOB_OUTPUT_LVCMOS18_DRIVE_6; break;
case 8: u64 |= XC6_IOB_OUTPUT_LVCMOS18_DRIVE_8; break;
case 12: u64 |= XC6_IOB_OUTPUT_LVCMOS18_DRIVE_12; break;
case 16: u64 |= XC6_IOB_OUTPUT_LVCMOS18_DRIVE_16; break;
case 24: u64 |= XC6_IOB_OUTPUT_LVCMOS18_DRIVE_24; break;
default: FAIL(EINVAL);
}
} else if (!strcmp(dev->u.iob.ostandard, IO_LVCMOS15)
|| !strcmp(dev->u.iob.ostandard, IO_LVCMOS15_JEDEC)) {
switch (dev->u.iob.drive_strength) {
case 2: u64 |= XC6_IOB_OUTPUT_LVCMOS15_DRIVE_2; break;
case 4: u64 |= XC6_IOB_OUTPUT_LVCMOS15_DRIVE_4; break;
case 6: u64 |= XC6_IOB_OUTPUT_LVCMOS15_DRIVE_6; break;
case 8: u64 |= XC6_IOB_OUTPUT_LVCMOS15_DRIVE_8; break;
case 12: u64 |= XC6_IOB_OUTPUT_LVCMOS15_DRIVE_12; break;
case 16: u64 |= XC6_IOB_OUTPUT_LVCMOS15_DRIVE_16; break;
default: FAIL(EINVAL);
}
} else if (!strcmp(dev->u.iob.ostandard, IO_LVCMOS12)
|| !strcmp(dev->u.iob.ostandard, IO_LVCMOS12_JEDEC)) {
switch (dev->u.iob.drive_strength) {
case 2: u64 |= XC6_IOB_OUTPUT_LVCMOS12_DRIVE_2; break;
case 4: u64 |= XC6_IOB_OUTPUT_LVCMOS12_DRIVE_4; break;
case 6: u64 |= XC6_IOB_OUTPUT_LVCMOS12_DRIVE_6; break;
case 8: u64 |= XC6_IOB_OUTPUT_LVCMOS12_DRIVE_8; break;
case 12: u64 |= XC6_IOB_OUTPUT_LVCMOS12_DRIVE_12; break;
default: FAIL(EINVAL);
}
} else FAIL(EINVAL);
switch (dev->u.iob.slew) {
case SLEW_SLOW: u64 |= XC6_IOB_SLEW_SLOW; break;
case SLEW_FAST: u64 |= XC6_IOB_SLEW_FAST; break;
case SLEW_QUIETIO: u64 |= XC6_IOB_SLEW_QUIETIO; break;
default: FAIL(EINVAL);
}
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: FAIL(EINVAL);
}
frame_set_u64(&bits->d[IOB_DATA_START
+ t2_idx*IOB_ENTRY_LEN], u64);
} else HERE();
}
return 0;
fail:
return rc;
}
static int extract_iobs(struct extract_state* es)
{
int i, iob_y, iob_x, iob_type_idx, first_iob;
uint64_t u64;
struct fpga_device *dev;
struct fpgadev_iob cfg;
RC_CHECK(es->model);
first_iob = 0;
for (i = 0; i < es->model->die->num_t2_ios; i++) {
if (!es->model->die->t2_io[i].pair)
continue;
u64 = frame_get_u64(&es->bits->d[
IOB_DATA_START + i*IOB_ENTRY_LEN]);
if (!u64) continue;
iob_y = es->model->die->t2_io[i].y;
iob_x = es->model->die->t2_io[i].x;
iob_type_idx = es->model->die->t2_io[i].type_idx;
dev = fdev_p(es->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
RC_ASSERT(es->model, dev);
memset(&cfg, 0, sizeof(cfg));
if (!first_iob) {
first_iob = 1;
// todo: is this right on the other sides?
if (!get_bit(es->bits, /*row*/ 0, get_rightside_major(XC6SLX9),
/*minor*/ 22, 64*15+XC6_HCLK_BITS+4))
HERE();
clear_bit(es->bits, /*row*/ 0, get_rightside_major(XC6SLX9),
/*minor*/ 22, 64*15+XC6_HCLK_BITS+4);
}
if (u64 & XC6_IOB_INSTANTIATED)
u64 &= ~XC6_IOB_INSTANTIATED;
else
HERE();
switch (u64 & XC6_IOB_MASK_IO) {
case XC6_IOB_INPUT:
cfg.bypass_mux = BYPASS_MUX_I;
if (u64 & XC6_IOB_IMUX_I_B) {
cfg.I_mux = IMUX_I_B;
u64 &= ~XC6_IOB_IMUX_I_B;
} else
cfg.I_mux = IMUX_I;
switch (u64 & XC6_IOB_MASK_IN_TYPE) {
case XC6_IOB_INPUT_LVCMOS33_25_LVTTL:
u64 &= ~XC6_IOB_MASK_IN_TYPE;
strcpy(cfg.istandard, IO_LVCMOS25);
break;
case XC6_IOB_INPUT_LVCMOS18_15_12:
u64 &= ~XC6_IOB_MASK_IN_TYPE;
strcpy(cfg.istandard, IO_LVCMOS12);
break;
case XC6_IOB_INPUT_LVCMOS18_15_12_JEDEC:
u64 &= ~XC6_IOB_MASK_IN_TYPE;
strcpy(cfg.istandard, IO_LVCMOS12_JEDEC);
break;
case XC6_IOB_INPUT_SSTL2_I:
u64 &= ~XC6_IOB_MASK_IN_TYPE;
strcpy(cfg.istandard, IO_SSTL2_I);
break;
default: HERE(); break;
}
break;
case XC6_IOB_OUTPUT_LVCMOS33_25_DRIVE_2:
cfg.drive_strength = 2;
strcpy(cfg.ostandard, IO_LVCMOS25);
break;
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_4:
cfg.drive_strength = 4;
strcpy(cfg.ostandard, IO_LVCMOS33);
break;
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_6:
cfg.drive_strength = 6;
strcpy(cfg.ostandard, IO_LVCMOS33);
break;
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_8:
cfg.drive_strength = 8;
strcpy(cfg.ostandard, IO_LVCMOS33);
break;
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_12:
cfg.drive_strength = 12;
strcpy(cfg.ostandard, IO_LVCMOS33);
break;
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_16:
cfg.drive_strength = 16;
strcpy(cfg.ostandard, IO_LVCMOS33);
break;
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_24:
cfg.drive_strength = 24;
strcpy(cfg.ostandard, IO_LVCMOS33);
break;
case XC6_IOB_OUTPUT_LVCMOS25_DRIVE_4:
cfg.drive_strength = 4;
strcpy(cfg.ostandard, IO_LVCMOS25);
break;
case XC6_IOB_OUTPUT_LVCMOS25_DRIVE_6:
cfg.drive_strength = 6;
strcpy(cfg.ostandard, IO_LVCMOS25);
break;
case XC6_IOB_OUTPUT_LVCMOS25_DRIVE_8:
cfg.drive_strength = 8;
strcpy(cfg.ostandard, IO_LVCMOS25);
break;
case XC6_IOB_OUTPUT_LVCMOS25_DRIVE_12:
cfg.drive_strength = 12;
strcpy(cfg.ostandard, IO_LVCMOS25);
break;
case XC6_IOB_OUTPUT_LVCMOS25_DRIVE_16:
cfg.drive_strength = 16;
strcpy(cfg.ostandard, IO_LVCMOS25);
break;
case XC6_IOB_OUTPUT_LVCMOS25_DRIVE_24:
cfg.drive_strength = 24;
strcpy(cfg.ostandard, IO_LVCMOS25);
break;
case XC6_IOB_OUTPUT_LVTTL_DRIVE_2:
cfg.drive_strength = 2;
strcpy(cfg.ostandard, IO_LVTTL);
break;
case XC6_IOB_OUTPUT_LVTTL_DRIVE_4:
cfg.drive_strength = 4;
strcpy(cfg.ostandard, IO_LVTTL);
break;
case XC6_IOB_OUTPUT_LVTTL_DRIVE_6:
cfg.drive_strength = 6;
strcpy(cfg.ostandard, IO_LVTTL);
break;
case XC6_IOB_OUTPUT_LVTTL_DRIVE_8:
cfg.drive_strength = 8;
strcpy(cfg.ostandard, IO_LVTTL);
break;
case XC6_IOB_OUTPUT_LVTTL_DRIVE_12:
cfg.drive_strength = 12;
strcpy(cfg.ostandard, IO_LVTTL);
break;
case XC6_IOB_OUTPUT_LVTTL_DRIVE_16:
cfg.drive_strength = 16;
strcpy(cfg.ostandard, IO_LVTTL);
break;
case XC6_IOB_OUTPUT_LVTTL_DRIVE_24:
cfg.drive_strength = 24;
strcpy(cfg.ostandard, IO_LVTTL);
break;
case XC6_IOB_OUTPUT_LVCMOS18_DRIVE_2:
cfg.drive_strength = 2;
strcpy(cfg.ostandard, IO_LVCMOS18);
break;
case XC6_IOB_OUTPUT_LVCMOS18_DRIVE_4:
cfg.drive_strength = 4;
strcpy(cfg.ostandard, IO_LVCMOS18);
break;
case XC6_IOB_OUTPUT_LVCMOS18_DRIVE_6:
cfg.drive_strength = 6;
strcpy(cfg.ostandard, IO_LVCMOS18);
break;
case XC6_IOB_OUTPUT_LVCMOS18_DRIVE_8:
cfg.drive_strength = 8;
strcpy(cfg.ostandard, IO_LVCMOS18);
break;
case XC6_IOB_OUTPUT_LVCMOS18_DRIVE_12:
cfg.drive_strength = 12;
strcpy(cfg.ostandard, IO_LVCMOS18);
break;
case XC6_IOB_OUTPUT_LVCMOS18_DRIVE_16:
cfg.drive_strength = 16;
strcpy(cfg.ostandard, IO_LVCMOS18);
break;
case XC6_IOB_OUTPUT_LVCMOS18_DRIVE_24:
cfg.drive_strength = 24;
strcpy(cfg.ostandard, IO_LVCMOS18);
break;
case XC6_IOB_OUTPUT_LVCMOS15_DRIVE_2:
cfg.drive_strength = 2;
strcpy(cfg.ostandard, IO_LVCMOS15);
break;
case XC6_IOB_OUTPUT_LVCMOS15_DRIVE_4:
cfg.drive_strength = 4;
strcpy(cfg.ostandard, IO_LVCMOS15);
break;
case XC6_IOB_OUTPUT_LVCMOS15_DRIVE_6:
cfg.drive_strength = 6;
strcpy(cfg.ostandard, IO_LVCMOS15);
break;
case XC6_IOB_OUTPUT_LVCMOS15_DRIVE_8:
cfg.drive_strength = 8;
strcpy(cfg.ostandard, IO_LVCMOS15);
break;
case XC6_IOB_OUTPUT_LVCMOS15_DRIVE_12:
cfg.drive_strength = 12;
strcpy(cfg.ostandard, IO_LVCMOS15);
break;
case XC6_IOB_OUTPUT_LVCMOS15_DRIVE_16:
cfg.drive_strength = 16;
strcpy(cfg.ostandard, IO_LVCMOS15);
break;
case XC6_IOB_OUTPUT_LVCMOS12_DRIVE_2:
cfg.drive_strength = 2;
strcpy(cfg.ostandard, IO_LVCMOS12);
break;
case XC6_IOB_OUTPUT_LVCMOS12_DRIVE_4:
cfg.drive_strength = 4;
strcpy(cfg.ostandard, IO_LVCMOS12);
break;
case XC6_IOB_OUTPUT_LVCMOS12_DRIVE_6:
cfg.drive_strength = 6;
strcpy(cfg.ostandard, IO_LVCMOS12);
break;
case XC6_IOB_OUTPUT_LVCMOS12_DRIVE_8:
cfg.drive_strength = 8;
strcpy(cfg.ostandard, IO_LVCMOS12);
break;
case XC6_IOB_OUTPUT_LVCMOS12_DRIVE_12:
cfg.drive_strength = 12;
strcpy(cfg.ostandard, IO_LVCMOS12);
break;
default: HERE(); break;
}
if (cfg.istandard[0] || cfg.ostandard[0])
u64 &= ~XC6_IOB_MASK_IO;
if (cfg.ostandard[0]) {
cfg.O_used = 1;
u64 &= ~XC6_IOB_O_PINW;
if (!strcmp(cfg.ostandard, IO_LVCMOS12)
|| !strcmp(cfg.ostandard, IO_LVCMOS15)
|| !strcmp(cfg.ostandard, IO_LVCMOS18)
|| !strcmp(cfg.ostandard, IO_LVCMOS25)
|| !strcmp(cfg.ostandard, IO_LVCMOS33)
|| !strcmp(cfg.ostandard, IO_LVTTL)) {
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_FAST:
u64 &= ~XC6_IOB_MASK_SLEW;
cfg.slew = SLEW_FAST;
break;
case XC6_IOB_SLEW_QUIETIO:
u64 &= ~XC6_IOB_MASK_SLEW;
cfg.slew = SLEW_QUIETIO;
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();
}
}
if (!u64) {
frame_set_u64(&es->bits->d[IOB_DATA_START
+ i*IOB_ENTRY_LEN], 0);
if (dev->instantiated) HERE();
dev->instantiated = 1;
dev->u.iob = cfg;
} else HERE();
}
return 0;
}
static int extract_type2(struct extract_state* es)
{
int gclk_i, bits_off;
uint16_t u16;
RC_CHECK(es->model);
extract_iobs(es);
for (gclk_i = 0; gclk_i < es->model->die->num_gclk_pins; gclk_i++) {
bits_off = IOB_DATA_START
+ es->model->die->gclk_t2_switches[gclk_i]*XC6_WORD_BYTES
+ XC6_TYPE2_GCLK_REG_SW/XC6_WORD_BITS;
u16 = frame_get_u16(&es->bits->d[bits_off]);
if (!u16)
continue;
if (u16 & (1<<(XC6_TYPE2_GCLK_REG_SW%XC6_WORD_BITS))) {
int t2_io_idx, iob_y, iob_x, iob_type_idx;
struct fpga_device *iob_dev;
struct switch_to_yx_l2 switch_to_yx_l2;
struct switch_to_rel switch_to_rel;
#ifdef DBG_EXTRACT_T2
fprintf(stderr, "#D %s:%i t2 gclk %i u16 0x%X\n",
__FILE__, __LINE__, gclk_i, u16);
#endif
//
// find and enable reg-switch for gclk_pin[i]
// the writing equivalent is in write_inner_term_sw()
//
t2_io_idx = es->model->die->gclk_t2_io_idx[gclk_i];
iob_y = es->model->die->t2_io[t2_io_idx].y;
iob_x = es->model->die->t2_io[t2_io_idx].x;
iob_type_idx = es->model->die->t2_io[t2_io_idx].type_idx;
iob_dev = fdev_p(es->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
RC_ASSERT(es->model, iob_dev);
switch_to_yx_l2.l1.yx_req = YX_X_CENTER_CMTPLL | YX_Y_CENTER;
switch_to_yx_l2.l1.flags = SWTO_YX_CLOSEST;
switch_to_yx_l2.l1.model = es->model;
switch_to_yx_l2.l1.y = iob_y;
switch_to_yx_l2.l1.x = iob_x;
switch_to_yx_l2.l1.start_switch = iob_dev->pinw[IOB_OUT_I];
switch_to_yx_l2.l1.from_to = SW_FROM;
switch_to_yx_l2.l1.exclusive_net = NO_NET;
fpga_switch_to_yx_l2(&switch_to_yx_l2);
RC_CHECK(es->model);
if (!switch_to_yx_l2.l1.set.len)
{ HERE(); continue; }
switch_to_rel.model = es->model;
switch_to_rel.start_y = switch_to_yx_l2.l1.dest_y;
switch_to_rel.start_x = switch_to_yx_l2.l1.dest_x;
switch_to_rel.start_switch = switch_to_yx_l2.l1.dest_connpt;
switch_to_rel.from_to = SW_FROM;
switch_to_rel.flags = SWTO_REL_WEAK_TARGET;
switch_to_rel.rel_y = es->model->center_y - switch_to_rel.start_y;
switch_to_rel.rel_x = es->model->center_x - switch_to_rel.start_x;
switch_to_rel.target_connpt = STRIDX_NO_ENTRY;
fpga_switch_to_rel(&switch_to_rel);
RC_CHECK(es->model);
if (!switch_to_rel.set.len)
{ HERE(); continue; }
if (switch_to_rel.set.len != 1) HERE();
RC_ASSERT(es->model, es->num_yx_pos < MAX_YX_SWITCHES);
es->yx_pos[es->num_yx_pos].y = switch_to_rel.start_y;
es->yx_pos[es->num_yx_pos].x = switch_to_rel.start_x;
es->yx_pos[es->num_yx_pos].idx = switch_to_rel.set.sw[0];
es->num_yx_pos++;
u16 &= ~(1<<(XC6_TYPE2_GCLK_REG_SW%XC6_WORD_BITS));
}
if (u16) HERE();
frame_set_u16(&es->bits->d[bits_off], u16);
}
RC_RETURN(es->model);
}
static int back_to_cout(struct fpga_model *model, int cin_y, int cin_x,
str16_t cin_str, int *cout_y, int *cout_x, str16_t *cout_str)
{
int connpt_dests_o, num_dests, i;
RC_CHECK(model);
if (fpga_connpt_find(model, cin_y, cin_x, cin_str,
&connpt_dests_o, &num_dests) == NO_CONN)
RC_FAIL(model, EINVAL);
RC_ASSERT(model, num_dests == 1 || num_dests == 2);
for (i = 0; i < num_dests; i++) {
fpga_conn_dest(model, cin_y, cin_x, connpt_dests_o+i, cout_y, cout_x, cout_str);
if (has_device(model, *cout_y, *cout_x, DEV_LOGIC))
break;
}
if (i >= num_dests)
RC_FAIL(model, EINVAL);
RC_RETURN(model);
}
static int extract_logic(struct extract_state* es)
{
int row, row_pos, x, y, i, byte_off, last_minor, rc;
int latch_ml, latch_x, l_col, lut;
struct fpgadev_logic cfg_ml, cfg_x;
uint64_t lut_X[4], lut_ML[4]; // LUT_A-LUT_D
uint64_t mi20, mi23_M, mi2526;
uint8_t* u8_p;
struct fpga_device* dev_ml;
RC_CHECK(es->model);
for (x = LEFT_SIDE_WIDTH; x < es->model->x_width-RIGHT_SIDE_WIDTH; x++) {
if (!is_atx(X_FABRIC_LOGIC_COL|X_CENTER_LOGIC_COL, es->model, x))
continue;
for (y = TOP_IO_TILES; y < es->model->y_height - BOT_IO_TILES; y++) {
if (!has_device(es->model, y, x, DEV_LOGIC))
continue;
row = which_row(y, es->model);
row_pos = pos_in_row(y, es->model);
if (row == -1 || row_pos == -1 || row_pos == 8) {
HERE();
continue;
}
if (row_pos > 8) row_pos--;
u8_p = get_first_minor(es->bits, row, es->model->x_major[x]);
byte_off = row_pos * 8;
if (row_pos >= 8) byte_off += XC6_HCLK_BYTES;
//
// Step 1:
//
// read all configuration bits for the 2 logic devices
// into local variables
//
mi20 = frame_get_u64(u8_p + 20*FRAME_SIZE + byte_off) & XC6_MI20_LOGIC_MASK;
if (has_device_type(es->model, y, x, DEV_LOGIC, LOGIC_M)) {
mi23_M = frame_get_u64(u8_p + 23*FRAME_SIZE + byte_off);
mi2526 = frame_get_u64(u8_p + 26*FRAME_SIZE + byte_off);
lut_ML[LUT_A] = frame_get_lut64(XC6_LMAP_XM_M_A,
u8_p + 24*FRAME_SIZE, row_pos*4+2);
lut_ML[LUT_B] = frame_get_lut64(XC6_LMAP_XM_M_B,
u8_p + 21*FRAME_SIZE, row_pos*4+2);
lut_ML[LUT_C] = frame_get_lut64(XC6_LMAP_XM_M_C,
u8_p + 24*FRAME_SIZE, row_pos*4);
lut_ML[LUT_D] = frame_get_lut64(XC6_LMAP_XM_M_D,
u8_p + 21*FRAME_SIZE, row_pos*4);
lut_X[LUT_A] = frame_get_lut64(XC6_LMAP_XM_X_A,
u8_p + 27*FRAME_SIZE, row_pos*4+2);
lut_X[LUT_B] = frame_get_lut64(XC6_LMAP_XM_X_B,
u8_p + 29*FRAME_SIZE, row_pos*4+2);
lut_X[LUT_C] = frame_get_lut64(XC6_LMAP_XM_X_C,
u8_p + 27*FRAME_SIZE, row_pos*4);
lut_X[LUT_D] = frame_get_lut64(XC6_LMAP_XM_X_D,
u8_p + 29*FRAME_SIZE, row_pos*4);
l_col = 0;
} else if (has_device_type(es->model, y, x, DEV_LOGIC, LOGIC_L)) {
mi23_M = 0;
mi2526 = frame_get_u64(u8_p + 25*FRAME_SIZE + byte_off);
lut_ML[LUT_A] = frame_get_lut64(XC6_LMAP_XL_L_A,
u8_p + 23*FRAME_SIZE, row_pos*4+2);
lut_ML[LUT_B] = frame_get_lut64(XC6_LMAP_XL_L_B,
u8_p + 21*FRAME_SIZE, row_pos*4+2);
lut_ML[LUT_C] = frame_get_lut64(XC6_LMAP_XL_L_C,
u8_p + 23*FRAME_SIZE, row_pos*4);
lut_ML[LUT_D] = frame_get_lut64(XC6_LMAP_XL_L_D,
u8_p + 21*FRAME_SIZE, row_pos*4);
lut_X[LUT_A] = frame_get_lut64(XC6_LMAP_XL_X_A,
u8_p + 26*FRAME_SIZE, row_pos*4+2);
lut_X[LUT_B] = frame_get_lut64(XC6_LMAP_XL_X_B,
u8_p + 28*FRAME_SIZE, row_pos*4+2);
lut_X[LUT_C] = frame_get_lut64(XC6_LMAP_XL_X_C,
u8_p + 26*FRAME_SIZE, row_pos*4);
lut_X[LUT_D] = frame_get_lut64(XC6_LMAP_XL_X_D,
u8_p + 28*FRAME_SIZE, row_pos*4);
l_col = 1;
} else {
HERE();
continue;
}
//
// Step 2:
//
// If all is zero, assume the devices are not instantiated.
// todo: we could check pin connectivity and infer 0-bit
// configured devices
//
if (!mi20 && !mi23_M && !mi2526
&& !lut_X[LUT_A] && !lut_X[LUT_B] && !lut_X[LUT_C] && !lut_X[LUT_D]
&& !lut_ML[LUT_A] && !lut_ML[LUT_B] && !lut_ML[LUT_C] && !lut_ML[LUT_D])
continue;
//
// Step 3:
//
// Parse all bits from minors 20 and 25/26 into more
// easily usable cfg_ml and cfg_x structures.
//
memset(&cfg_ml, 0, sizeof(cfg_ml));
memset(&cfg_x, 0, sizeof(cfg_x));
latch_ml = 0;
latch_x = 0;
// minor20
if (mi20 & (1ULL<<XC6_ML_D5_FFSRINIT_1)) {
cfg_ml.a2d[LUT_D].ff5_srinit = FF_SRINIT1;
mi20 &= ~(1ULL<<XC6_ML_D5_FFSRINIT_1);
}
if (mi20 & (1ULL<<XC6_X_D5_FFSRINIT_1)) {
cfg_x.a2d[LUT_D].ff5_srinit = FF_SRINIT1;
mi20 &= ~(1ULL<<XC6_X_D5_FFSRINIT_1);
}
if (mi20 & (1ULL<<XC6_ML_C5_FFSRINIT_1)) {
cfg_ml.a2d[LUT_C].ff5_srinit = FF_SRINIT1;
mi20 &= ~(1ULL<<XC6_ML_C5_FFSRINIT_1);
}
if (mi20 & (1ULL<<XC6_X_C_FFSRINIT_1)) {
cfg_x.a2d[LUT_C].ff_srinit = FF_SRINIT1;
mi20 &= ~(1ULL<<XC6_X_C_FFSRINIT_1);
}
if (mi20 & (1ULL<<XC6_X_C5_FFSRINIT_1)) {
cfg_x.a2d[LUT_C].ff5_srinit = FF_SRINIT1;
mi20 &= ~(1ULL<<XC6_X_C5_FFSRINIT_1);
}
if (mi20 & (1ULL<<XC6_ML_B5_FFSRINIT_1)) {
cfg_ml.a2d[LUT_B].ff5_srinit = FF_SRINIT1;
mi20 &= ~(1ULL<<XC6_ML_B5_FFSRINIT_1);
}
if (mi20 & (1ULL<<XC6_X_B5_FFSRINIT_1)) {
cfg_x.a2d[LUT_B].ff5_srinit = FF_SRINIT1;
mi20 &= ~(1ULL<<XC6_X_B5_FFSRINIT_1);
}
if (mi20 & (1ULL<<XC6_M_A_FFSRINIT_1)) {
if (l_col) {
HERE();
continue;
}
cfg_ml.a2d[LUT_A].ff_srinit = FF_SRINIT1;
mi20 &= ~(1ULL<<XC6_M_A_FFSRINIT_1);
}
if (mi20 & (1ULL<<XC6_X_A5_FFSRINIT_1)) {
cfg_x.a2d[LUT_A].ff5_srinit = FF_SRINIT1;
mi20 &= ~(1ULL<<XC6_X_A5_FFSRINIT_1);
}
if (mi20 & (1ULL<<XC6_ML_A5_FFSRINIT_1)) {
cfg_ml.a2d[LUT_A].ff5_srinit = FF_SRINIT1;
mi20 &= ~(1ULL<<XC6_ML_A5_FFSRINIT_1);
}
// minor 25/26
if (mi2526 & (1ULL<<XC6_ML_D_CY0_O5)) {
cfg_ml.a2d[LUT_D].cy0 = CY0_O5;
mi2526 &= ~(1ULL<<XC6_ML_D_CY0_O5);
}
if (mi2526 & (1ULL<<XC6_X_D_OUTMUX_O5)) {
cfg_x.a2d[LUT_D].out_mux = MUX_O5;
mi2526 &= ~(1ULL<<XC6_X_D_OUTMUX_O5);
}
if (mi2526 & (1ULL<<XC6_X_C_OUTMUX_O5)) {
cfg_x.a2d[LUT_C].out_mux = MUX_O5;
mi2526 &= ~(1ULL<<XC6_X_C_OUTMUX_O5);
}
if (mi2526 & (1ULL<<XC6_ML_D_FFSRINIT_1)) {
cfg_ml.a2d[LUT_D].ff_srinit = 1;
mi2526 &= ~(1ULL<<XC6_ML_D_FFSRINIT_1);
}
if (mi2526 & (1ULL<<XC6_ML_C_FFSRINIT_1)) {
cfg_ml.a2d[LUT_C].ff_srinit = 1;
mi2526 &= ~(1ULL<<XC6_ML_C_FFSRINIT_1);
}
if (mi2526 & (1ULL<<XC6_X_D_FFSRINIT_1)) {
cfg_x.a2d[LUT_D].ff_srinit = 1;
mi2526 &= ~(1ULL<<XC6_X_D_FFSRINIT_1);
}
if (mi2526 & (1ULL<<XC6_ML_C_CY0_O5)) {
cfg_ml.a2d[LUT_C].cy0 = CY0_O5;
mi2526 &= ~(1ULL<<XC6_ML_C_CY0_O5);
}
if (mi2526 & (1ULL<<XC6_X_B_OUTMUX_O5)) {
cfg_x.a2d[LUT_B].out_mux = MUX_O5;
mi2526 &= ~(1ULL<<XC6_X_B_OUTMUX_O5);
}
if (mi2526 & XC6_ML_D_OUTMUX_MASK) {
switch ((mi2526 & XC6_ML_D_OUTMUX_MASK) >> XC6_ML_D_OUTMUX_O) {
case XC6_ML_D_OUTMUX_O6:
cfg_ml.a2d[LUT_D].out_mux = MUX_O6;
break;
case XC6_ML_D_OUTMUX_XOR:
cfg_ml.a2d[LUT_D].out_mux = MUX_XOR;
break;
case XC6_ML_D_OUTMUX_O5:
cfg_ml.a2d[LUT_D].out_mux = MUX_O5;
break;
case XC6_ML_D_OUTMUX_CY:
cfg_ml.a2d[LUT_D].out_mux = MUX_CY;
break;
case XC6_ML_D_OUTMUX_5Q:
cfg_ml.a2d[LUT_D].out_mux = MUX_5Q;
break;
default: HERE(); continue;
}
mi2526 &= ~XC6_ML_D_OUTMUX_MASK;
}
if (mi2526 & XC6_ML_D_FFMUX_MASK) {
switch ((mi2526 & XC6_ML_D_FFMUX_MASK) >> XC6_ML_D_FFMUX_O) {
case XC6_ML_D_FFMUX_O5:
cfg_ml.a2d[LUT_D].ff_mux = MUX_O5;
break;
case XC6_ML_D_FFMUX_X:
cfg_ml.a2d[LUT_D].ff_mux = MUX_X;
break;
case XC6_ML_D_FFMUX_XOR:
cfg_ml.a2d[LUT_D].ff_mux = MUX_XOR;
break;
case XC6_ML_D_FFMUX_CY:
cfg_ml.a2d[LUT_D].ff_mux = MUX_CY;
break;
default: HERE(); continue;
}
mi2526 &= ~XC6_ML_D_FFMUX_MASK;
}
if (mi2526 & (1ULL<<XC6_X_CLK_B)) {
cfg_x.clk_inv = CLKINV_B;
mi2526 &= ~(1ULL<<XC6_X_CLK_B);
}
if (mi2526 & (1ULL<<XC6_ML_ALL_LATCH)) {
latch_ml = 1;
mi2526 &= ~(1ULL<<XC6_ML_ALL_LATCH);
}
if (mi2526 & (1ULL<<XC6_ML_SR_USED)) {
cfg_ml.sr_used = 1;
mi2526 &= ~(1ULL<<XC6_ML_SR_USED);
}
if (mi2526 & (1ULL<<XC6_ML_SYNC)) {
cfg_ml.sync_attr = SYNCATTR_SYNC;
mi2526 &= ~(1ULL<<XC6_ML_SYNC);
}
if (mi2526 & (1ULL<<XC6_ML_CE_USED)) {
cfg_ml.ce_used = 1;
mi2526 &= ~(1ULL<<XC6_ML_CE_USED);
}
if (mi2526 & (1ULL<<XC6_X_D_FFMUX_X)) {
cfg_x.a2d[LUT_D].ff_mux = MUX_X;
mi2526 &= ~(1ULL<<XC6_X_D_FFMUX_X);
}
if (mi2526 & (1ULL<<XC6_X_C_FFMUX_X)) {
cfg_x.a2d[LUT_C].ff_mux = MUX_X;
mi2526 &= ~(1ULL<<XC6_X_C_FFMUX_X);
}
if (mi2526 & (1ULL<<XC6_X_CE_USED)) {
cfg_x.ce_used = 1;
mi2526 &= ~(1ULL<<XC6_X_CE_USED);
}
if (mi2526 & XC6_ML_C_OUTMUX_MASK) {
switch ((mi2526 & XC6_ML_C_OUTMUX_MASK) >> XC6_ML_C_OUTMUX_O) {
case XC6_ML_C_OUTMUX_XOR:
cfg_ml.a2d[LUT_C].out_mux = MUX_XOR;
break;
case XC6_ML_C_OUTMUX_O6:
cfg_ml.a2d[LUT_C].out_mux = MUX_O6;
break;
case XC6_ML_C_OUTMUX_5Q:
cfg_ml.a2d[LUT_C].out_mux = MUX_5Q;
break;
case XC6_ML_C_OUTMUX_CY:
cfg_ml.a2d[LUT_C].out_mux = MUX_CY;
break;
case XC6_ML_C_OUTMUX_O5:
cfg_ml.a2d[LUT_C].out_mux = MUX_O5;
break;
case XC6_ML_C_OUTMUX_F7:
cfg_ml.a2d[LUT_C].out_mux = MUX_F7;
break;
default: HERE(); continue;
}
mi2526 &= ~XC6_ML_C_OUTMUX_MASK;
}
if (mi2526 & XC6_ML_C_FFMUX_MASK) {
switch ((mi2526 & XC6_ML_C_FFMUX_MASK) >> XC6_ML_C_FFMUX_O) {
case XC6_ML_C_FFMUX_O5:
cfg_ml.a2d[LUT_C].ff_mux = MUX_O5;
break;
case XC6_ML_C_FFMUX_X:
cfg_ml.a2d[LUT_C].ff_mux = MUX_X;
break;
case XC6_ML_C_FFMUX_F7:
cfg_ml.a2d[LUT_C].ff_mux = MUX_F7;
break;
case XC6_ML_C_FFMUX_XOR:
cfg_ml.a2d[LUT_C].ff_mux = MUX_XOR;
break;
case XC6_ML_C_FFMUX_CY:
cfg_ml.a2d[LUT_C].ff_mux = MUX_CY;
break;
default: HERE(); continue;
}
mi2526 &= ~XC6_ML_C_FFMUX_MASK;
}
if (mi2526 & XC6_ML_B_OUTMUX_MASK) {
switch ((mi2526 & XC6_ML_B_OUTMUX_MASK) >> XC6_ML_B_OUTMUX_O) {
case XC6_ML_B_OUTMUX_5Q:
cfg_ml.a2d[LUT_B].out_mux = MUX_5Q;
break;
case XC6_ML_B_OUTMUX_F8:
cfg_ml.a2d[LUT_B].out_mux = MUX_F8;
break;
case XC6_ML_B_OUTMUX_XOR:
cfg_ml.a2d[LUT_B].out_mux = MUX_XOR;
break;
case XC6_ML_B_OUTMUX_CY:
cfg_ml.a2d[LUT_B].out_mux = MUX_CY;
break;
case XC6_ML_B_OUTMUX_O6:
cfg_ml.a2d[LUT_B].out_mux = MUX_O6;
break;
case XC6_ML_B_OUTMUX_O5:
cfg_ml.a2d[LUT_B].out_mux = MUX_O5;
break;
default: HERE(); continue;
}
mi2526 &= ~XC6_ML_B_OUTMUX_MASK;
}
if (mi2526 & (1ULL<<XC6_X_B_FFMUX_X)) {
cfg_x.a2d[LUT_B].ff_mux = MUX_X;
mi2526 &= ~(1ULL<<XC6_X_B_FFMUX_X);
}
if (mi2526 & (1ULL<<XC6_X_A_FFMUX_X)) {
cfg_x.a2d[LUT_A].ff_mux = MUX_X;
mi2526 &= ~(1ULL<<XC6_X_A_FFMUX_X);
}
if (mi2526 & (1ULL<<XC6_X_B_FFSRINIT_1)) {
cfg_x.a2d[LUT_B].ff_srinit = FF_SRINIT1;
mi2526 &= ~(1ULL<<XC6_X_B_FFSRINIT_1);
}
if (mi2526 & (1ULL<<XC6_X_A_OUTMUX_O5)) {
cfg_x.a2d[LUT_A].out_mux = MUX_O5;
mi2526 &= ~(1ULL<<XC6_X_A_OUTMUX_O5);
}
if (mi2526 & (1ULL<<XC6_X_SR_USED)) {
cfg_x.sr_used = 1;
mi2526 &= ~(1ULL<<XC6_X_SR_USED);
}
if (mi2526 & (1ULL<<XC6_X_SYNC)) {
cfg_x.sync_attr = SYNCATTR_SYNC;
mi2526 &= ~(1ULL<<XC6_X_SYNC);
}
if (mi2526 & (1ULL<<XC6_X_ALL_LATCH)) {
latch_x = 1;
mi2526 &= ~(1ULL<<XC6_X_ALL_LATCH);
}
if (mi2526 & (1ULL<<XC6_ML_CLK_B)) {
cfg_ml.clk_inv = CLKINV_B;
mi2526 &= ~(1ULL<<XC6_ML_CLK_B);
}
if (mi2526 & XC6_ML_B_FFMUX_MASK) {
switch ((mi2526 & XC6_ML_B_FFMUX_MASK) >> XC6_ML_B_FFMUX_O) {
case XC6_ML_B_FFMUX_XOR:
cfg_ml.a2d[LUT_B].ff_mux = MUX_XOR;
break;
case XC6_ML_B_FFMUX_O5:
cfg_ml.a2d[LUT_B].ff_mux = MUX_O5;
break;
case XC6_ML_B_FFMUX_CY:
cfg_ml.a2d[LUT_B].ff_mux = MUX_CY;
break;
case XC6_ML_B_FFMUX_X:
cfg_ml.a2d[LUT_B].ff_mux = MUX_X;
break;
case XC6_ML_B_FFMUX_F8:
cfg_ml.a2d[LUT_B].ff_mux = MUX_F8;
break;
default: HERE(); continue;
}
mi2526 &= ~XC6_ML_B_FFMUX_MASK;
}
if (mi2526 & XC6_ML_A_FFMUX_MASK) {
switch ((mi2526 & XC6_ML_A_FFMUX_MASK) >> XC6_ML_A_FFMUX_O) {
case XC6_ML_A_FFMUX_XOR:
cfg_ml.a2d[LUT_A].ff_mux = MUX_XOR;
break;
case XC6_ML_A_FFMUX_X:
cfg_ml.a2d[LUT_A].ff_mux = MUX_X;
break;
case XC6_ML_A_FFMUX_O5:
cfg_ml.a2d[LUT_A].ff_mux = MUX_O5;
break;
case XC6_ML_A_FFMUX_CY:
cfg_ml.a2d[LUT_A].ff_mux = MUX_CY;
break;
case XC6_ML_A_FFMUX_F7:
cfg_ml.a2d[LUT_A].ff_mux = MUX_F7;
break;
default: HERE(); continue;
}
mi2526 &= ~XC6_ML_A_FFMUX_MASK;
}
if (mi2526 & XC6_ML_A_OUTMUX_MASK) {
switch ((mi2526 & XC6_ML_A_OUTMUX_MASK) >> XC6_ML_A_OUTMUX_O) {
case XC6_ML_A_OUTMUX_5Q:
cfg_ml.a2d[LUT_A].out_mux = MUX_5Q;
break;
case XC6_ML_A_OUTMUX_F7:
cfg_ml.a2d[LUT_A].out_mux = MUX_F7;
break;
case XC6_ML_A_OUTMUX_XOR:
cfg_ml.a2d[LUT_A].out_mux = MUX_XOR;
break;
case XC6_ML_A_OUTMUX_CY:
cfg_ml.a2d[LUT_A].out_mux = MUX_CY;
break;
case XC6_ML_A_OUTMUX_O6:
cfg_ml.a2d[LUT_A].out_mux = MUX_O6;
break;
case XC6_ML_A_OUTMUX_O5:
cfg_ml.a2d[LUT_A].out_mux = MUX_O5;
break;
default: HERE(); continue;
}
mi2526 &= ~XC6_ML_A_OUTMUX_MASK;
}
if (mi2526 & (1ULL<<XC6_ML_B_CY0_O5)) {
cfg_ml.a2d[LUT_B].cy0 = CY0_O5;
mi2526 &= ~(1ULL<<XC6_ML_B_CY0_O5);
}
if (mi2526 & (1ULL<<XC6_ML_PRECYINIT_AX)) {
cfg_ml.precyinit = PRECYINIT_AX;
mi2526 &= ~(1ULL<<XC6_ML_PRECYINIT_AX);
}
if (mi2526 & (1ULL<<XC6_X_A_FFSRINIT_1)) {
cfg_x.a2d[LUT_A].ff_srinit = FF_SRINIT1;
mi2526 &= ~(1ULL<<XC6_X_A_FFSRINIT_1);
}
if (mi2526 & (1ULL<<XC6_ML_PRECYINIT_1)) {
cfg_ml.precyinit = PRECYINIT_1;
mi2526 &= ~(1ULL<<XC6_ML_PRECYINIT_1);
}
if (mi2526 & (1ULL<<XC6_ML_B_FFSRINIT_1)) {
cfg_ml.a2d[LUT_B].ff_srinit = FF_SRINIT1;
mi2526 &= ~(1ULL<<XC6_ML_B_FFSRINIT_1);
}
if (mi2526 & (1ULL<<XC6_ML_A_CY0_O5)) {
cfg_ml.a2d[LUT_A].cy0 = CY0_O5;
mi2526 &= ~(1ULL<<XC6_ML_A_CY0_O5);
}
if (mi2526 & (1ULL<<XC6_L_A_FFSRINIT_1)) {
if (!l_col) {
HERE();
continue;
}
cfg_ml.a2d[LUT_A].ff_srinit = FF_SRINIT1;
mi2526 &= ~(1ULL<<XC6_L_A_FFSRINIT_1);
}
//
// Step 4:
//
// If any bits remain in the configuration, do not
// instantiate the logic devices.
//
if (mi20) {
fprintf(stderr, "#E %s:%i y%i x%i l%i "
"mi20 0x%016lX\n",
__FILE__, __LINE__, y, x, l_col, mi20);
continue;
}
if (mi23_M) {
fprintf(stderr, "#E %s:%i y%i x%i l%i "
"mi23_M 0x%016lX\n",
__FILE__, __LINE__, y, x, l_col, mi23_M);
continue;
}
if (mi2526) {
fprintf(stderr, "#E %s:%i y%i x%i l%i "
"mi2526 0x%016lX\n",
__FILE__, __LINE__, y, x, l_col, mi2526);
continue;
}
//
// Step 5:
//
// Do device-global sanity checking pre-LUT
//
// cfg_ml.cout_used
dev_ml = fdev_p(es->model, y, x, DEV_LOGIC, DEV_LOG_M_OR_L);
if (!dev_ml) FAIL(EINVAL);
if (find_es_switch(es, y, x, fpga_switch_first(
es->model, y, x, dev_ml->pinw[LO_COUT], SW_FROM)))
cfg_ml.cout_used = 1;
// todo: if srinit=1, the matching ff/latch must be on
// todo: handle all_latch
// todo: precyinit=0 has no bits
// todo: cy0=X has no bits, check connectivity
// todo: the x-device ffmux must not be left as MUX_X unless the ff is really in use
//
// Step 6:
//
// Determine lut5_usage and read the luts.
//
// todo: in ML, if srinit=0 cannot decide between ff_mux=O6 or
// direct-out, need to check pin connectivity, is_pin_connected()
// todo: in ML devs, ffmux=O6 has no bits set
// todo: 5Q-ff in X devices
// ML-A
if (lut_ML[LUT_A]
|| !all_zero(&cfg_ml.a2d[LUT_A], sizeof(cfg_ml.a2d[LUT_A]))) {
if (lut_ML[LUT_A]
&& cfg_ml.a2d[LUT_A].out_mux != MUX_O6
&& cfg_ml.a2d[LUT_A].out_mux != MUX_XOR
&& cfg_ml.a2d[LUT_A].out_mux != MUX_CY
&& cfg_ml.a2d[LUT_A].out_mux != MUX_F7
&& cfg_ml.a2d[LUT_A].ff_mux != MUX_O6
&& cfg_ml.a2d[LUT_A].ff_mux != MUX_XOR
&& cfg_ml.a2d[LUT_A].ff_mux != MUX_CY
&& cfg_ml.a2d[LUT_A].ff_mux != MUX_F7)
cfg_ml.a2d[LUT_A].flags |= OUT_USED;
if (cfg_ml.a2d[LUT_A].ff_mux == MUX_O5
|| cfg_ml.a2d[LUT_A].out_mux == MUX_5Q
|| cfg_ml.a2d[LUT_A].out_mux == MUX_O5
|| cfg_ml.a2d[LUT_A].cy0 == CY0_O5) {
// lut5/6 pair
cfg_ml.a2d[LUT_A].flags |= LUT6VAL_SET;
cfg_ml.a2d[LUT_A].lut6_val = ULL_HIGH32(lut_ML[LUT_A]);
cfg_ml.a2d[LUT_A].flags |= LUT5VAL_SET;
cfg_ml.a2d[LUT_A].lut5_val = ULL_LOW32(lut_ML[LUT_A]);
} else { // lut6 only
cfg_ml.a2d[LUT_A].flags |= LUT6VAL_SET;
cfg_ml.a2d[LUT_A].lut6_val = lut_ML[LUT_A];
}
}
// ML-B
if (lut_ML[LUT_B]
|| !all_zero(&cfg_ml.a2d[LUT_B], sizeof(cfg_ml.a2d[LUT_B]))) {
if (lut_ML[LUT_B]
&& cfg_ml.a2d[LUT_B].out_mux != MUX_O6
&& cfg_ml.a2d[LUT_B].out_mux != MUX_XOR
&& cfg_ml.a2d[LUT_B].out_mux != MUX_CY
&& cfg_ml.a2d[LUT_B].out_mux != MUX_F7
&& cfg_ml.a2d[LUT_B].ff_mux != MUX_O6
&& cfg_ml.a2d[LUT_B].ff_mux != MUX_XOR
&& cfg_ml.a2d[LUT_B].ff_mux != MUX_CY
&& cfg_ml.a2d[LUT_B].ff_mux != MUX_F7)
cfg_ml.a2d[LUT_B].flags |= OUT_USED;
if (cfg_ml.a2d[LUT_B].ff_mux == MUX_O5
|| cfg_ml.a2d[LUT_B].out_mux == MUX_5Q
|| cfg_ml.a2d[LUT_B].out_mux == MUX_O5
|| cfg_ml.a2d[LUT_B].cy0 == CY0_O5) {
// lut5/6 pair
cfg_ml.a2d[LUT_B].flags |= LUT6VAL_SET;
cfg_ml.a2d[LUT_B].lut6_val = ULL_HIGH32(lut_ML[LUT_B]);
cfg_ml.a2d[LUT_B].flags |= LUT5VAL_SET;
cfg_ml.a2d[LUT_B].lut5_val = ULL_LOW32(lut_ML[LUT_B]);
} else { // lut6 only
cfg_ml.a2d[LUT_B].flags |= LUT6VAL_SET;
cfg_ml.a2d[LUT_B].lut6_val = lut_ML[LUT_B];
}
}
// ML-C
if (lut_ML[LUT_C]
|| !all_zero(&cfg_ml.a2d[LUT_C], sizeof(cfg_ml.a2d[LUT_C]))) {
if (lut_ML[LUT_C]
&& cfg_ml.a2d[LUT_C].out_mux != MUX_O6
&& cfg_ml.a2d[LUT_C].out_mux != MUX_XOR
&& cfg_ml.a2d[LUT_C].out_mux != MUX_CY
&& cfg_ml.a2d[LUT_C].out_mux != MUX_F7
&& cfg_ml.a2d[LUT_C].ff_mux != MUX_O6
&& cfg_ml.a2d[LUT_C].ff_mux != MUX_XOR
&& cfg_ml.a2d[LUT_C].ff_mux != MUX_CY
&& cfg_ml.a2d[LUT_C].ff_mux != MUX_F7)
cfg_ml.a2d[LUT_C].flags |= OUT_USED;
if (cfg_ml.a2d[LUT_C].ff_mux == MUX_O5
|| cfg_ml.a2d[LUT_C].out_mux == MUX_5Q
|| cfg_ml.a2d[LUT_C].out_mux == MUX_O5
|| cfg_ml.a2d[LUT_C].cy0 == CY0_O5) {
// lut5/6 pair
cfg_ml.a2d[LUT_C].flags |= LUT6VAL_SET;
cfg_ml.a2d[LUT_C].lut6_val = ULL_HIGH32(lut_ML[LUT_C]);
cfg_ml.a2d[LUT_C].flags |= LUT5VAL_SET;
cfg_ml.a2d[LUT_C].lut5_val = ULL_LOW32(lut_ML[LUT_C]);
} else { // lut6 only
cfg_ml.a2d[LUT_C].flags |= LUT6VAL_SET;
cfg_ml.a2d[LUT_C].lut6_val = lut_ML[LUT_C];
}
}
// ML-D
if (lut_ML[LUT_D]
|| !all_zero(&cfg_ml.a2d[LUT_D], sizeof(cfg_ml.a2d[LUT_D]))) {
if (lut_ML[LUT_D]
&& cfg_ml.a2d[LUT_D].out_mux != MUX_O6
&& cfg_ml.a2d[LUT_D].out_mux != MUX_XOR
&& cfg_ml.a2d[LUT_D].out_mux != MUX_CY
&& cfg_ml.a2d[LUT_D].out_mux != MUX_F7
&& cfg_ml.a2d[LUT_D].ff_mux != MUX_O6
&& cfg_ml.a2d[LUT_D].ff_mux != MUX_XOR
&& cfg_ml.a2d[LUT_D].ff_mux != MUX_CY
&& cfg_ml.a2d[LUT_D].ff_mux != MUX_F7)
cfg_ml.a2d[LUT_D].flags |= OUT_USED;
if (cfg_ml.a2d[LUT_D].ff_mux == MUX_O5
|| cfg_ml.a2d[LUT_D].out_mux == MUX_5Q
|| cfg_ml.a2d[LUT_D].out_mux == MUX_O5
|| cfg_ml.a2d[LUT_D].cy0 == CY0_O5) {
// lut5/6 pair
cfg_ml.a2d[LUT_D].flags |= LUT6VAL_SET;
cfg_ml.a2d[LUT_D].lut6_val = ULL_HIGH32(lut_ML[LUT_D]);
cfg_ml.a2d[LUT_D].flags |= LUT5VAL_SET;
cfg_ml.a2d[LUT_D].lut5_val = ULL_LOW32(lut_ML[LUT_D]);
} else { // lut6 only
cfg_ml.a2d[LUT_D].flags |= LUT6VAL_SET;
cfg_ml.a2d[LUT_D].lut6_val = lut_ML[LUT_D];
}
}
// X-A
if (lut_X[LUT_A]
|| !all_zero(&cfg_x.a2d[LUT_A], sizeof(cfg_x.a2d[LUT_A]))) {
if (lut_X[LUT_A]
&& cfg_x.a2d[LUT_A].ff_mux != MUX_O6)
cfg_x.a2d[LUT_A].flags |= OUT_USED;
if (cfg_x.a2d[LUT_A].out_mux) {
// lut5/6 pair
cfg_x.a2d[LUT_A].flags |= LUT6VAL_SET;
cfg_x.a2d[LUT_A].lut6_val = ULL_HIGH32(lut_X[LUT_A]);
cfg_x.a2d[LUT_A].flags |= LUT5VAL_SET;
cfg_x.a2d[LUT_A].lut5_val = ULL_LOW32(lut_X[LUT_A]);
} else { // lut6 only
cfg_x.a2d[LUT_A].flags |= LUT6VAL_SET;
cfg_x.a2d[LUT_A].lut6_val = lut_X[LUT_A];
}
}
// X-B
if (lut_X[LUT_B]
|| !all_zero(&cfg_x.a2d[LUT_B], sizeof(cfg_x.a2d[LUT_B]))) {
if (lut_X[LUT_B]
&& cfg_x.a2d[LUT_B].ff_mux != MUX_O6)
cfg_x.a2d[LUT_B].flags |= OUT_USED;
if (cfg_x.a2d[LUT_B].out_mux) {
// lut5/6 pair
cfg_x.a2d[LUT_B].flags |= LUT6VAL_SET;
cfg_x.a2d[LUT_B].lut6_val = ULL_HIGH32(lut_X[LUT_B]);
cfg_x.a2d[LUT_B].flags |= LUT5VAL_SET;
cfg_x.a2d[LUT_B].lut5_val = ULL_LOW32(lut_X[LUT_B]);
} else { // lut6 only
cfg_x.a2d[LUT_B].flags |= LUT6VAL_SET;
cfg_x.a2d[LUT_B].lut6_val = lut_X[LUT_B];
}
}
// X-C
if (lut_X[LUT_C]
|| !all_zero(&cfg_x.a2d[LUT_C], sizeof(cfg_x.a2d[LUT_C]))) {
if (lut_X[LUT_C]
&& cfg_x.a2d[LUT_C].ff_mux != MUX_O6)
cfg_x.a2d[LUT_C].flags |= OUT_USED;
if (cfg_x.a2d[LUT_C].out_mux) {
// lut5/6 pair
cfg_x.a2d[LUT_C].flags |= LUT6VAL_SET;
cfg_x.a2d[LUT_C].lut6_val = ULL_HIGH32(lut_X[LUT_C]);
cfg_x.a2d[LUT_C].flags |= LUT5VAL_SET;
cfg_x.a2d[LUT_C].lut5_val = ULL_LOW32(lut_X[LUT_C]);
} else { // lut6 only
cfg_x.a2d[LUT_C].flags |= LUT6VAL_SET;
cfg_x.a2d[LUT_C].lut6_val = lut_X[LUT_C];
}
}
// X-D
if (lut_X[LUT_D]
|| !all_zero(&cfg_x.a2d[LUT_D], sizeof(cfg_x.a2d[LUT_D]))) {
if (lut_X[LUT_D]
&& cfg_x.a2d[LUT_D].ff_mux != MUX_O6)
cfg_x.a2d[LUT_D].flags |= OUT_USED;
if (cfg_x.a2d[LUT_D].out_mux) {
// lut5/6 pair
cfg_x.a2d[LUT_D].flags |= LUT6VAL_SET;
cfg_x.a2d[LUT_D].lut6_val = ULL_HIGH32(lut_X[LUT_D]);
cfg_x.a2d[LUT_D].flags |= LUT5VAL_SET;
cfg_x.a2d[LUT_D].lut5_val = ULL_LOW32(lut_X[LUT_D]);
} else { // lut6 only
cfg_x.a2d[LUT_D].flags |= LUT6VAL_SET;
cfg_x.a2d[LUT_D].lut6_val = lut_X[LUT_D];
}
}
//
// Step 7:
//
// Do more and final sanity checks before instantiation.
//
// todo: latch cannot be combined with out_mux=5Q or ff5_srinit
if (latch_ml
&& !cfg_ml.a2d[LUT_A].ff_mux
&& !cfg_ml.a2d[LUT_B].ff_mux
&& !cfg_ml.a2d[LUT_C].ff_mux
&& !cfg_ml.a2d[LUT_D].ff_mux) {
HERE();
continue;
}
if (latch_x
&& !cfg_x.a2d[LUT_A].ff_mux
&& !cfg_x.a2d[LUT_B].ff_mux
&& !cfg_x.a2d[LUT_C].ff_mux
&& !cfg_x.a2d[LUT_D].ff_mux) {
HERE();
continue;
}
// todo: latch and2l and or2l need to be determined
// from vcc connectivity, srinit etc.
for (lut = LUT_A; lut <= LUT_D; lut++) {
if (cfg_ml.a2d[lut].ff_mux) {
cfg_ml.a2d[lut].ff = latch_ml ? FF_LATCH : FF_FF;
if (!cfg_ml.a2d[lut].ff_srinit)
cfg_ml.a2d[lut].ff_srinit = FF_SRINIT0;
if (!cfg_ml.clk_inv)
cfg_ml.clk_inv = CLKINV_CLK;
if (!cfg_ml.sync_attr)
cfg_ml.sync_attr = SYNCATTR_ASYNC;
}
if (cfg_x.a2d[lut].ff_mux) {
cfg_x.a2d[lut].ff = latch_x ? FF_LATCH : FF_FF;
if (!cfg_x.a2d[lut].ff_srinit)
cfg_x.a2d[lut].ff_srinit = FF_SRINIT0;
if (!cfg_x.clk_inv)
cfg_x.clk_inv = CLKINV_CLK;
if (!cfg_x.sync_attr)
cfg_x.sync_attr = SYNCATTR_ASYNC;
}
// todo: ff5_srinit
// todo: 5Q ff also needs clock/sync check
}
// Check whether we should default to PRECYINIT_0
if (!cfg_ml.precyinit
&& (cfg_ml.a2d[LUT_A].out_mux == MUX_XOR
|| cfg_ml.a2d[LUT_A].ff_mux == MUX_XOR
|| cfg_ml.a2d[LUT_A].cy0)) {
int cout_y, cout_x;
str16_t cout_str;
rc = back_to_cout(es->model, y, x, dev_ml->pinw[LI_CIN],
&cout_y, &cout_x, &cout_str);
if (rc) FAIL(rc);
if (find_es_switch(es, cout_y, cout_x,fpga_switch_first(
es->model, cout_y, cout_x, cout_str, SW_TO)))
cfg_ml.precyinit = PRECYINIT_0;
}
//
// Step 8:
//
// Remove all bits.
//
frame_set_u64(u8_p + 20*FRAME_SIZE + byte_off,
frame_get_u64(u8_p + 20*FRAME_SIZE + byte_off)
& ~XC6_MI20_LOGIC_MASK);
last_minor = l_col ? 29 : 30;
for (i = 21; i <= last_minor; i++)
frame_set_u64(u8_p + i*FRAME_SIZE + byte_off, 0);
//
// Step 9:
//
// Instantiate configuration.
//
if (!all_zero(&cfg_ml, sizeof(cfg_ml))) {
rc = fdev_logic_setconf(es->model, y, x, DEV_LOG_M_OR_L, &cfg_ml);
if (rc) FAIL(rc);
}
if (!all_zero(&cfg_x, sizeof(cfg_x))) {
rc = fdev_logic_setconf(es->model, y, x, DEV_LOG_X, &cfg_x);
if (rc) FAIL(rc);
}
}
}
return 0;
fail:
return rc;
}
static int bitpos_is_set(struct extract_state *es, int y, int x,
struct xc6_routing_bitpos *swpos, int *is_set)
{
int row_num, row_pos, start_in_frame, two_bits_val, rc;
RC_CHECK(es->model);
*is_set = 0;
is_in_row(es->model, y, &row_num, &row_pos);
if (row_num == -1 || row_pos == -1
|| row_pos == HCLK_POS) FAIL(EINVAL);
if (row_pos > HCLK_POS)
start_in_frame = (row_pos-1)*64 + 16;
else
start_in_frame = row_pos*64;
if (swpos->minor == 20) {
two_bits_val = ((get_bit(es->bits, row_num, es->model->x_major[x],
20, start_in_frame + swpos->two_bits_o) != 0) << 1)
| ((get_bit(es->bits, row_num, es->model->x_major[x],
20, start_in_frame + swpos->two_bits_o+1) != 0) << 0);
if (two_bits_val != swpos->two_bits_val)
return 0;
if (!get_bit(es->bits, row_num, es->model->x_major[x], 20,
start_in_frame + swpos->one_bit_o))
return 0;
} else {
two_bits_val =
((get_bit(es->bits, row_num, es->model->x_major[x], swpos->minor,
start_in_frame + swpos->two_bits_o/2) != 0) << 1)
| ((get_bit(es->bits, row_num, es->model->x_major[x], swpos->minor+1,
start_in_frame + swpos->two_bits_o/2) != 0) << 0);
if (two_bits_val != swpos->two_bits_val)
return 0;
if (!get_bit(es->bits, row_num, es->model->x_major[x],
swpos->minor + (swpos->one_bit_o&1),
start_in_frame + swpos->one_bit_o/2))
return 0;
}
*is_set = 1;
return 0;
fail:
return rc;
}
static int bitpos_clear_bits(struct extract_state* es, int y, int x,
struct xc6_routing_bitpos* swpos)
{
int row_num, row_pos, start_in_frame, rc;
RC_CHECK(es->model);
is_in_row(es->model, y, &row_num, &row_pos);
if (row_num == -1 || row_pos == -1
|| row_pos == HCLK_POS) FAIL(EINVAL);
if (row_pos > HCLK_POS)
start_in_frame = (row_pos-1)*64 + 16;
else
start_in_frame = row_pos*64;
if (swpos->minor == 20) {
clear_bit(es->bits, row_num, es->model->x_major[x], swpos->minor,
start_in_frame + swpos->two_bits_o);
clear_bit(es->bits, row_num, es->model->x_major[x], swpos->minor,
start_in_frame + swpos->two_bits_o+1);
clear_bit(es->bits, row_num, es->model->x_major[x], swpos->minor,
start_in_frame + swpos->one_bit_o);
} else {
clear_bit(es->bits, row_num, es->model->x_major[x], swpos->minor,
start_in_frame + swpos->two_bits_o/2);
clear_bit(es->bits, row_num, es->model->x_major[x], swpos->minor + 1,
start_in_frame + swpos->two_bits_o/2);
clear_bit(es->bits, row_num, es->model->x_major[x], swpos->minor + (swpos->one_bit_o&1),
start_in_frame + swpos->one_bit_o/2);
}
return 0;
fail:
return rc;
}
static int bitpos_set_bits(struct fpga_bits* bits, struct fpga_model* model,
int y, int x, struct xc6_routing_bitpos* swpos)
{
int row_num, row_pos, start_in_frame, rc;
RC_CHECK(model);
is_in_row(model, y, &row_num, &row_pos);
if (row_num == -1 || row_pos == -1
|| row_pos == HCLK_POS) FAIL(EINVAL);
if (row_pos > HCLK_POS)
start_in_frame = (row_pos-1)*64 + 16;
else
start_in_frame = row_pos*64;
if (swpos->minor == 20) {
if (swpos->two_bits_val & 0x02)
set_bit(bits, row_num, model->x_major[x], swpos->minor,
start_in_frame + swpos->two_bits_o);
if (swpos->two_bits_val & 0x01)
set_bit(bits, row_num, model->x_major[x], swpos->minor,
start_in_frame + swpos->two_bits_o+1);
set_bit(bits, row_num, model->x_major[x], swpos->minor,
start_in_frame + swpos->one_bit_o);
} else {
if (swpos->two_bits_val & 0x02)
set_bit(bits, row_num, model->x_major[x], swpos->minor,
start_in_frame + swpos->two_bits_o/2);
if (swpos->two_bits_val & 0x01)
set_bit(bits, row_num, model->x_major[x], swpos->minor + 1,
start_in_frame + swpos->two_bits_o/2);
set_bit(bits, row_num, model->x_major[x], swpos->minor + (swpos->one_bit_o&1),
start_in_frame + swpos->one_bit_o/2);
}
return 0;
fail:
return rc;
}
static int extract_routing_switches(struct extract_state* es, int y, int x)
{
struct fpga_tile* tile;
swidx_t sw_idx;
str16_t from_str, to_str;
int i, is_set, rc;
RC_CHECK(es->model);
tile = YX_TILE(es->model, y, x);
for (i = 0; i < es->model->num_bitpos; i++) {
rc = bitpos_is_set(es, y, x, &es->model->sw_bitpos[i], &is_set);
if (rc) RC_FAIL(es->model, rc);
if (!is_set) continue;
from_str = fpga_wire2str_yx(es->model, es->model->sw_bitpos[i].from, y, x);
to_str = fpga_wire2str_yx(es->model, es->model->sw_bitpos[i].to, y, x);
#ifdef DBG_EXTRACT_ROUTING_SW
fprintf(stderr, "#D %s:%i y%i x%i (r%i ma%i v64_%02i mi%i) "
"from %s to %s bidir %i "
"two_bits_o %i two_bits_val %i one_bit_o %i\n",
__FILE__, __LINE__, y, x,
which_row(y, es->model),
es->model->x_major[x],
regular_row_pos(y, es->model),
es->model->sw_bitpos[i].minor,
strarray_lookup(&es->model->str, from_str),
strarray_lookup(&es->model->str, to_str),
es->model->sw_bitpos[i].bidir,
es->model->sw_bitpos[i].two_bits_o,
es->model->sw_bitpos[i].two_bits_val,
es->model->sw_bitpos[i].one_bit_o);
#endif
sw_idx = fpga_switch_lookup(es->model, y, x, from_str, to_str);
if (sw_idx == NO_SWITCH) RC_FAIL(es->model, EINVAL);
// todo: es->model->sw_bitpos[i].bidir handling
if (tile->switches[sw_idx] & SWITCH_BIDIRECTIONAL)
fprintf(stderr, "#E %s:%i BIDIR not supported yet\n",
__FILE__, __LINE__);
if (tile->switches[sw_idx] & SWITCH_USED)
fprintf(stderr, "#E %s:%i switch already in use\n",
__FILE__, __LINE__);
if (es->num_yx_pos >= MAX_YX_SWITCHES)
{ RC_FAIL(es->model, ENOTSUP); }
es->yx_pos[es->num_yx_pos].y = y;
es->yx_pos[es->num_yx_pos].x = x;
es->yx_pos[es->num_yx_pos].idx = sw_idx;
es->num_yx_pos++;
rc = bitpos_clear_bits(es, y, x, &es->model->sw_bitpos[i]);
if (rc) RC_FAIL(es->model, rc);
}
RC_RETURN(es->model);
}
static int extract_logic_switches(struct extract_state* es, int y, int x)
{
int row, row_pos, byte_off, minor, rc;
uint8_t* u8_p;
RC_CHECK(es->model);
row = which_row(y, es->model);
row_pos = pos_in_row(y, es->model);
if (row == -1 || row_pos == -1 || row_pos == 8) FAIL(EINVAL);
if (row_pos > 8) row_pos--;
u8_p = get_first_minor(es->bits, row, es->model->x_major[x]);
byte_off = row_pos * 8;
if (row_pos >= 8) byte_off += XC6_HCLK_BYTES;
if (has_device_type(es->model, y, x, DEV_LOGIC, LOGIC_M))
minor = 26;
else if (has_device_type(es->model, y, x, DEV_LOGIC, LOGIC_L))
minor = 25;
else
FAIL(EINVAL);
if (frame_get_bit(u8_p + minor*FRAME_SIZE, byte_off*8 + XC6_ML_CIN_USED)) {
struct fpga_device* dev;
int cout_y, cout_x;
str16_t cout_str;
swidx_t cout_sw;
dev = fdev_p(es->model, y, x, DEV_LOGIC, DEV_LOG_M_OR_L);
if (!dev) FAIL(EINVAL);
rc = back_to_cout(es->model, y, x, dev->pinw[LI_CIN],
&cout_y, &cout_x, &cout_str);
if (rc) FAIL(rc);
#ifdef DBG_EXTRACT_LOGIC_SW
fprintf(stderr, "#D %s:%i cin y%i x%i %s cout y%i x%i %s\n",
__FILE__, __LINE__,
y, x, strarray_lookup(&es->model->str, dev->pinw[LI_CIN]),
cout_y, cout_x, strarray_lookup(&es->model->str, cout_str));
#endif
cout_sw = fpga_switch_first(es->model, cout_y,
cout_x, cout_str, SW_TO);
if (cout_sw == NO_SWITCH)
FAIL(EINVAL);
if (es->num_yx_pos >= MAX_YX_SWITCHES)
{ FAIL(ENOTSUP); }
es->yx_pos[es->num_yx_pos].y = cout_y;
es->yx_pos[es->num_yx_pos].x = cout_x;
es->yx_pos[es->num_yx_pos].idx = cout_sw;
es->num_yx_pos++;
frame_clear_bit(u8_p + minor*FRAME_SIZE,
byte_off*8 + XC6_ML_CIN_USED);
}
return 0;
fail:
return rc;
}
#define MAX_IOLOGIC_SWBLOCK 4
#define MAX_IOLOGIC_BITS 4
struct iologic_sw_pos
{
enum iologic_wire to[MAX_IOLOGIC_SWBLOCK];
enum iologic_wire from[MAX_IOLOGIC_SWBLOCK];
int minor[MAX_IOLOGIC_BITS];
int b64[MAX_IOLOGIC_BITS];
};
struct iologic_sw_pos s_leftright_swpos[] =
{
// input
{{D_ILOGIC_IDATAIN_IODELAY_S}, {IBUF0},
{24, 24, -1},
{28, 29}},
{{D_ILOGIC_SITE}, {D_ILOGIC_IDATAIN_IODELAY},
{29, -1},
{20}},
{{D_ILOGIC_SITE_S}, {D_ILOGIC_IDATAIN_IODELAY_S},
{29, -1},
{23}},
{{DFB_ILOGIC_SITE}, {D_ILOGIC_SITE},
{28, -1},
{63}},
{{DFB_ILOGIC_SITE_S}, {D_ILOGIC_SITE_S},
{28, -1},
{0}},
{{FABRICOUT_ILOGIC_SITE}, {D_ILOGIC_SITE},
{23, -1},
{49}},
{{FABRICOUT_ILOGIC_SITE_S}, {D_ILOGIC_SITE_S},
{23, -1},
{14}},
// output
{{OQ_OLOGIC_SITE, O0}, {D1_OLOGIC_SITE, OQ_OLOGIC_SITE},
{29, 27, 28, -1},
{40, 21, 57}},
{{OQ_OLOGIC_SITE_S, O1}, {D1_OLOGIC_SITE_S, OQ_OLOGIC_SITE_S},
{29, 27, 28, -1},
{43, 56, 6}},
{{IOI_LOGICOUT0}, {IOI_INTER_LOGICOUT0}, {-1}},
{{IOI_LOGICOUT7}, {IOI_INTER_LOGICOUT7}, {-1}},
{{IOI_INTER_LOGICOUT0}, {FABRICOUT_ILOGIC_SITE}, {-1}},
{{IOI_INTER_LOGICOUT7}, {FABRICOUT_ILOGIC_SITE_S}, {-1}},
{{D_ILOGIC_IDATAIN_IODELAY}, {IBUF0}, {-1}},
{{D_ILOGIC_IDATAIN_IODELAY_S}, {IBUF1}, {-1}},
{{D1_OLOGIC_SITE}, {IOI_LOGICIN_B31}, {-1}},
{{0}}
};
struct iologic_sw_pos s_topbot_swpos[] =
{
// input
{{D_ILOGIC_IDATAIN_IODELAY_S}, {IBUF0},
{23, 23, -1},
{28, 29}},
{{D_ILOGIC_SITE}, {D_ILOGIC_IDATAIN_IODELAY},
{26, -1},
{20}},
{{D_ILOGIC_SITE_S}, {D_ILOGIC_IDATAIN_IODELAY_S},
{26, -1},
{23}},
{{DFB_ILOGIC_SITE}, {D_ILOGIC_SITE},
{28, -1},
{63}},
{{DFB_ILOGIC_SITE_S}, {D_ILOGIC_SITE_S},
{28, -1},
{0}},
{{FABRICOUT_ILOGIC_SITE}, {D_ILOGIC_SITE},
{29, -1},
{49}},
{{FABRICOUT_ILOGIC_SITE_S}, {D_ILOGIC_SITE_S},
{29, -1},
{14}},
// output
{{OQ_OLOGIC_SITE, O0}, {D1_OLOGIC_SITE, OQ_OLOGIC_SITE},
{26, 27, 28, -1},
{40, 21, 57}},
{{OQ_OLOGIC_SITE_S, O1}, {D1_OLOGIC_SITE_S, OQ_OLOGIC_SITE_S},
{26, 27, 28, -1},
{43, 56, 6}},
{{IOI_LOGICOUT0}, {IOI_INTER_LOGICOUT0}, {-1}},
{{IOI_LOGICOUT7}, {IOI_INTER_LOGICOUT7}, {-1}},
{{IOI_INTER_LOGICOUT0}, {FABRICOUT_ILOGIC_SITE}, {-1}},
{{IOI_INTER_LOGICOUT7}, {FABRICOUT_ILOGIC_SITE_S}, {-1}},
{{D_ILOGIC_IDATAIN_IODELAY}, {IBUF0}, {-1}},
{{D_ILOGIC_IDATAIN_IODELAY_S}, {IBUF1}, {-1}},
{{D1_OLOGIC_SITE}, {IOI_LOGICIN_B31}, {-1}},
{{0}}
};
static int add_yx_switch_i(struct extract_state *es,
int y, int x, str16_t from, str16_t to)
{
swidx_t sw_idx;
RC_CHECK(es->model);
sw_idx = fpga_switch_lookup(es->model, y, x,
from, to);
RC_ASSERT(es->model, sw_idx != NO_SWITCH
&& es->num_yx_pos < MAX_YX_SWITCHES);
es->yx_pos[es->num_yx_pos].y = y;
es->yx_pos[es->num_yx_pos].x = x;
es->yx_pos[es->num_yx_pos].idx = sw_idx;
es->num_yx_pos++;
RC_RETURN(es->model);
}
static int add_yx_switch(struct extract_state *es,
int y, int x, const char *from, const char *to)
{
str16_t from_str_i, to_str_i;
RC_CHECK(es->model);
from_str_i = strarray_find(&es->model->str, from);
to_str_i = strarray_find(&es->model->str, to);
return add_yx_switch_i(es, y, x, from_str_i, to_str_i);
}
static int extract_iologic_switches(struct extract_state* es, int y, int x)
{
int row_num, row_pos, bit_in_frame, i, j, rc;
uint8_t* minor0_p;
struct iologic_sw_pos* sw_pos;
RC_CHECK(es->model);
// From y/x coordinate, determine major, row, bit offset
// in frame (v64_i) and pointer to first minor.
is_in_row(es->model, y, &row_num, &row_pos);
if (row_num == -1 || row_pos == -1
|| row_pos == HCLK_POS) FAIL(EINVAL);
if (row_pos > HCLK_POS)
bit_in_frame = (row_pos-1)*64 + XC6_HCLK_BITS;
else
bit_in_frame = row_pos*64;
minor0_p = get_first_minor(es->bits, row_num, es->model->x_major[x]);
if (x < LEFT_SIDE_WIDTH) {
if (x != LEFT_IO_DEVS) FAIL(EINVAL);
sw_pos = s_leftright_swpos;
} else if (x >= es->model->x_width-RIGHT_SIDE_WIDTH) {
if (x != es->model->x_width - RIGHT_IO_DEVS_O) FAIL(EINVAL);
sw_pos = s_leftright_swpos;
} else if (y == TOP_OUTER_IO
|| y == TOP_INNER_IO
|| y == es->model->y_height-BOT_INNER_IO
|| y == es->model->y_height-BOT_OUTER_IO)
sw_pos = s_topbot_swpos;
else FAIL(EINVAL);
// Go through switches
for (i = 0; sw_pos[i].to[0]; i++) {
for (j = 0; sw_pos[i].minor[j] != -1; j++) {
if (!frame_get_bit(&minor0_p[sw_pos[i].minor[j]
*FRAME_SIZE], bit_in_frame+sw_pos[i].b64[j]))
break;
}
if (!j || sw_pos[i].minor[j] != -1)
continue;
for (j = 0; j < MAX_IOLOGIC_SWBLOCK && sw_pos[i].to[j]; j++)
add_yx_switch_i(es, y, x,
fpga_iologic_wire2str_yx(es->model, sw_pos[i].from[j], y, x),
fpga_iologic_wire2str_yx(es->model, sw_pos[i].to[j], y, x));
for (j = 0; sw_pos[i].minor[j] != -1; j++)
frame_clear_bit(&minor0_p[sw_pos[i].minor[j]
*FRAME_SIZE], bit_in_frame+sw_pos[i].b64[j]);
}
// todo: we could implement an all-or-nothing system where
// the device bits are first copied into an u64 array,
// and switches rewound by resetting num_yx_pos - unless
// all bits have been processed...
return 0;
fail:
return rc;
}
static int extract_center_switches(struct extract_state *es)
{
int center_row, center_major, word, i;
uint8_t *minor_p;
RC_CHECK(es->model);
center_row = es->model->die->num_rows/2;
center_major = xc_die_center_major(es->model->die);
minor_p = get_first_minor(es->bits, center_row,
center_major) + XC6_CENTER_GCLK_MINOR*FRAME_SIZE;
word = frame_get_pinword(minor_p + 15*8+XC6_HCLK_BYTES);
if (word) {
for (i = 0; i < 16; i++) {
if (!(word & (1<<i))) continue;
add_yx_switch(es,
es->model->center_y, es->model->center_x,
pf("CLKC_CKLR%i", i), pf("CLKC_GCLK%i", i));
}
frame_set_pinword(minor_p + 15*8+XC6_HCLK_BYTES, 0);
}
word = frame_get_pinword(minor_p + 15*8+XC6_HCLK_BYTES + XC6_WORD_BYTES);
if (word) {
for (i = 0; i < 16; i++) {
if (!(word & (1<<i))) continue;
add_yx_switch(es,
es->model->center_y, es->model->center_x,
pf("CLKC_CKTB%i", i), pf("CLKC_GCLK%i", i));
}
frame_set_pinword(minor_p + 15*8+XC6_HCLK_BYTES + XC6_WORD_BYTES, 0);
}
RC_RETURN(es->model);
}
static int write_center_sw(struct fpga_bits *bits,
struct fpga_model *model, int y, int x)
{
struct fpga_tile *tile;
const char *from_str, *to_str;
int center_row, center_major, word;
int i, j, gclk_pin_from, gclk_pin_to;
uint8_t *minor_p;
RC_CHECK(model);
center_row = model->die->num_rows/2;
center_major = xc_die_center_major(model->die);
minor_p = get_first_minor(bits, center_row,
center_major) + XC6_CENTER_GCLK_MINOR*FRAME_SIZE;
tile = YX_TILE(model, y, x);
for (i = 0; i < tile->num_switches; i++) {
if (!(tile->switches[i] & SWITCH_USED))
continue;
from_str = fpga_switch_str(model, y, x, i, SW_FROM);
to_str = fpga_switch_str(model, y, x, i, SW_TO);
RC_ASSERT(model, from_str && to_str);
j = sscanf(from_str, "CLKC_CKLR%i", &gclk_pin_from);
if (j == 1) {
j = sscanf(to_str, "CLKC_GCLK%i", &gclk_pin_to);
RC_ASSERT(model, j == 1 && gclk_pin_to == gclk_pin_from);
word = frame_get_pinword(minor_p + 15*8+XC6_HCLK_BYTES);
word |= 1 << gclk_pin_from;
frame_set_pinword(minor_p + 15*8+XC6_HCLK_BYTES, word);
continue;
}
j = sscanf(from_str, "CLKC_CKTB%i", &gclk_pin_from);
if (j == 1) {
j = sscanf(to_str, "CLKC_GCLK%i", &gclk_pin_to);
RC_ASSERT(model, j == 1 && gclk_pin_to == gclk_pin_from);
word = frame_get_pinword(minor_p + 15*8+XC6_HCLK_BYTES + XC6_WORD_BYTES);
word |= 1 << gclk_pin_from;
frame_set_pinword(minor_p + 15*8+XC6_HCLK_BYTES + XC6_WORD_BYTES, word);
continue;
}
// todo: it's possible that other switches need bits
// todo: we can manually detect used switches that do not
// need bits, such as
// I0_GCLK_SITE0:15 -> O_GCLK_SITE0:15
// O_GCLK_SITE0:15 -> CLKC_GCLK_MAIN0:15
// CLKC_GCLK%i -> I0_GCLK_SITE%i
}
RC_RETURN(model);
}
static int extract_gclk_center_vert_sw(struct extract_state *es)
{
int word, cur_row, cur_minor, cur_pin, i, hclk_y;
uint8_t *ma0_bits;
RC_CHECK(es->model);
// Switches in the vertical center column that are routing gclk
// signals to the left and right side of the chip.
for (cur_row = 0; cur_row < es->model->die->num_rows; cur_row++) {
hclk_y = row_to_hclk(cur_row, es->model);
RC_ASSERT(es->model, hclk_y != -1);
ma0_bits = get_first_minor(es->bits, cur_row, XC6_NULL_MAJOR);
for (cur_minor = 0; cur_minor <= 2; cur_minor++) {
// left
word = frame_get_pinword(ma0_bits + cur_minor*FRAME_SIZE + 8*8+XC6_HCLK_BYTES);
if (word) {
for (i = 0; i <= 16/3; i++) { // 0-5
cur_pin = cur_minor + i*3;
if (cur_pin > 15) break;
if (!(word & (1<<cur_pin))) continue;
add_yx_switch(es, hclk_y, es->model->center_x,
pf("CLKV_GCLKH_MAIN%i_FOLD", cur_pin),
pf("CLKV_GCLKH_L%i", cur_pin));
word &= ~(1<<cur_pin);
}
if (word) HERE();
frame_set_pinword(ma0_bits + cur_minor*FRAME_SIZE + 8*8+XC6_HCLK_BYTES, word);
}
// right
word = frame_get_pinword(ma0_bits + cur_minor*FRAME_SIZE + 8*8+XC6_HCLK_BYTES + 4);
if (word) {
for (i = 0; i <= 16/3; i++) { // 0-5
cur_pin = cur_minor + i*3;
if (cur_pin > 15) break;
if (!(word & (1<<cur_pin))) continue;
add_yx_switch(es, hclk_y, es->model->center_x,
pf("CLKV_GCLKH_MAIN%i_FOLD", cur_pin),
pf("CLKV_GCLKH_R%i", cur_pin));
word &= ~(1<<cur_pin);
}
if (word) HERE();
frame_set_pinword(ma0_bits + cur_minor*FRAME_SIZE + 8*8+XC6_HCLK_BYTES + 4, word);
}
}
}
RC_RETURN(es->model);
}
static int write_gclk_center_vert_sw(struct fpga_bits *bits,
struct fpga_model *model, int y, int x)
{
struct fpga_tile *tile;
const char *from_str, *to_str;
int i, j, gclk_pin_from, gclk_pin_to, cur_pin, cur_minor, minor_found, word;
uint8_t *ma0_bits;
RC_CHECK(model);
ma0_bits = get_first_minor(bits, which_row(y, model), XC6_NULL_MAJOR);
RC_ASSERT(model, ma0_bits);
tile = YX_TILE(model, y, x);
for (i = 0; i < tile->num_switches; i++) {
if (!(tile->switches[i] & SWITCH_USED))
continue;
from_str = fpga_switch_str(model, y, x, i, SW_FROM);
to_str = fpga_switch_str(model, y, x, i, SW_TO);
RC_ASSERT(model, from_str && to_str);
// left
j = sscanf(from_str, "CLKV_GCLKH_MAIN%i_FOLD", &gclk_pin_from);
if (j == 1) {
j = sscanf(to_str, "CLKV_GCLKH_L%i", &gclk_pin_to);
RC_ASSERT(model, j == 1 && gclk_pin_to == gclk_pin_from);
minor_found = -1;
for (cur_minor = 0; minor_found == -1 && cur_minor <= 2; cur_minor++) {
for (j = 0; j <= 16/3; j++) { // 0-5
cur_pin = cur_minor + j*3;
if (cur_pin > 15) break;
if (cur_pin == gclk_pin_from) {
minor_found = cur_minor;
break;
}
}
}
if (minor_found != -1) {
word = frame_get_pinword(ma0_bits + minor_found*FRAME_SIZE + 8*8+XC6_HCLK_BYTES);
word |= 1 << gclk_pin_from;
frame_set_pinword(ma0_bits + minor_found*FRAME_SIZE + 8*8+XC6_HCLK_BYTES, word);
continue;
}
HERE(); // fall-through to unsupported
}
// right
j = sscanf(from_str, "CLKV_GCLKH_MAIN%i_FOLD", &gclk_pin_from);
if (j == 1) {
j = sscanf(to_str, "CLKV_GCLKH_R%i", &gclk_pin_to);
RC_ASSERT(model, j == 1 && gclk_pin_to == gclk_pin_from);
minor_found = -1;
for (cur_minor = 0; minor_found == -1 && cur_minor <= 2; cur_minor++) {
for (j = 0; j <= 16/3; j++) { // 0-5
cur_pin = cur_minor + j*3;
if (cur_pin > 15) break;
if (cur_pin == gclk_pin_from) {
minor_found = cur_minor;
break;
}
}
}
if (minor_found != -1) {
word = frame_get_pinword(ma0_bits + minor_found*FRAME_SIZE + 8*8+XC6_HCLK_BYTES + 4);
word |= 1 << gclk_pin_from;
frame_set_pinword(ma0_bits + minor_found*FRAME_SIZE + 8*8+XC6_HCLK_BYTES + 4, word);
continue;
}
HERE(); // fall-through to unsupported
}
// todo: we can manually detect used switches that do not
// need bits, such as
// CLKV_GCLKH_L0:15 -> I_BUFH_LEFT_SITE0:15
// I_BUFH_LEFT_SITE0:15 -> O_BUFH_LEFT_SITE0:15
// O_BUFH_LEFT_SITE0:15 -> CLKV_BUFH_LEFT_L0:15
}
RC_RETURN(model);
}
static int extract_gclk_hclk_updown_sw(struct extract_state *es)
{
int word, cur_row, x, gclk_pin, hclk_y;
uint8_t *mi0_bits;
RC_CHECK(es->model);
// Switches in each horizontal hclk row that are routing
// gclk signals and and down to the clocked devices.
// todo: clk access in left and right IO devs, center devs,
// bram and macc devs as well as special devs not tested
// yet (only XM logic devs tested).
for (cur_row = 0; cur_row < es->model->die->num_rows; cur_row++) {
hclk_y = row_to_hclk(cur_row, es->model);
RC_ASSERT(es->model, hclk_y != -1);
for (x = LEFT_IO_ROUTING; x <= es->model->x_width-RIGHT_IO_ROUTING_O; x++) {
if (!is_atx(X_ROUTING_COL, es->model, x))
continue;
mi0_bits = get_first_minor(es->bits, cur_row, es->model->x_major[x]);
// each minor (0:15) stores the configuration bits for one gclk
// pin (in the hclk bytes of the minor)
for (gclk_pin = 0; gclk_pin <= 15; gclk_pin++) {
word = frame_get_pinword(mi0_bits + gclk_pin*FRAME_SIZE + XC6_HCLK_POS);
if (word & (1<<XC6_HCLK_GCLK_UP_PIN)) {
add_yx_switch(es, hclk_y, x,
pf("HCLK_GCLK%i_INT", gclk_pin),
pf("HCLK_GCLK_UP%i", gclk_pin));
word &= ~(1<<XC6_HCLK_GCLK_UP_PIN);
}
if (word & (1<<XC6_HCLK_GCLK_DOWN_PIN)) {
add_yx_switch(es, hclk_y, x,
pf("HCLK_GCLK%i_INT", gclk_pin),
pf("HCLK_GCLK%i", gclk_pin));
word &= ~(1<<XC6_HCLK_GCLK_DOWN_PIN);
}
if (word) HERE();
frame_set_pinword(mi0_bits + gclk_pin*FRAME_SIZE + XC6_HCLK_POS, word);
}
}
}
RC_RETURN(es->model);
}
static int write_hclk_sw(struct fpga_bits *bits, struct fpga_model *model,
int y, int x)
{
uint8_t *mi0_bits;
struct fpga_tile *tile;
const char *from_str, *to_str;
int i, j, gclk_pin_from, gclk_pin_to, up, word;
RC_CHECK(model);
mi0_bits = get_first_minor(bits, which_row(y, model), model->x_major[x]);
RC_ASSERT(model, mi0_bits);
tile = YX_TILE(model, y, x);
for (i = 0; i < tile->num_switches; i++) {
if (!(tile->switches[i] & SWITCH_USED))
continue;
from_str = fpga_switch_str(model, y, x, i, SW_FROM);
to_str = fpga_switch_str(model, y, x, i, SW_TO);
j = sscanf(from_str, "HCLK_GCLK%i_INT", &gclk_pin_from);
RC_ASSERT(model, j == 1);
j = sscanf(to_str, "HCLK_GCLK%i", &gclk_pin_to);
if (j == 1)
up = 0; // down
else {
j = sscanf(to_str, "HCLK_GCLK_UP%i", &gclk_pin_to);
RC_ASSERT(model, j == 1);
up = 1;
}
RC_ASSERT(model, gclk_pin_from == gclk_pin_to);
word = frame_get_pinword(mi0_bits + gclk_pin_from*FRAME_SIZE + XC6_HCLK_POS);
word |= 1 << (up ? XC6_HCLK_GCLK_UP_PIN : XC6_HCLK_GCLK_DOWN_PIN);
frame_set_pinword(mi0_bits + gclk_pin_from*FRAME_SIZE + XC6_HCLK_POS, word);
}
RC_RETURN(model);
}
static int extract_switches(struct extract_state *es)
{
int x, y;
RC_CHECK(es->model);
for (x = 0; x < es->model->x_width; x++) {
for (y = 0; y < es->model->y_height; y++) {
// routing switches
if (is_atx(X_ROUTING_COL, es->model, x)
&& y >= TOP_IO_TILES
&& y < es->model->y_height-BOT_IO_TILES
&& !is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS,
es->model, y)) {
extract_routing_switches(es, y, x);
}
// logic switches
if (has_device(es->model, y, x, DEV_LOGIC)) {
extract_logic_switches(es, y, x);
}
// iologic switches
if (has_device(es->model, y, x, DEV_ILOGIC)) {
extract_iologic_switches(es, y, x);
}
}
}
extract_center_switches(es);
extract_gclk_center_vert_sw(es);
extract_gclk_hclk_updown_sw(es);
RC_RETURN(es->model);
}
static int construct_extract_state(struct extract_state* es,
struct fpga_model* model)
{
RC_CHECK(model);
memset(es, 0, sizeof(*es));
es->model = model;
es->yx_pos = malloc(MAX_YX_SWITCHES * sizeof(*es->yx_pos));
if (!es->yx_pos) { HERE(); return ENOMEM; }
return 0;
}
static void destruct_extract_state(struct extract_state *es)
{
free(es->yx_pos);
es->yx_pos = 0;
}
static int extract_bscan(struct extract_state *es)
{
int enum_i, bscan_y, bscan_x, bscan_type_idx;
int jtag_chain, jtag_test, pinword;
uint8_t *u8_p;
struct fpga_device *dev;
RC_CHECK(es->model);
enum_i = 0;
while (!fdev_enum(es->model, DEV_BSCAN, enum_i++, &bscan_y,
&bscan_x, &bscan_type_idx) && bscan_y != -1) {
u8_p = get_first_minor(es->bits, which_row(bscan_y, es->model), es->model->x_major[bscan_x]);
RC_ASSERT(es->model, u8_p);
pinword = frame_get_pinword(u8_p + XC6_BSCAN_MINOR*FRAME_SIZE + XC6_BSCAN_WORD*XC6_WORD_BYTES);
if (!(pinword & (1 << ((bscan_y - TOP_IO_TILES)*2 + bscan_type_idx))))
continue;
pinword &= ~(1 << ((bscan_y - TOP_IO_TILES)*2 + bscan_type_idx));
jtag_chain = 1;
jtag_test = BSCAN_JTAG_TEST_N;
if (bscan_y == TOP_IO_TILES && !bscan_type_idx
&& (pinword & (1 << XC6_BSCAN_TEST_PIN))) {
pinword &= ~(1 << XC6_BSCAN_TEST_PIN);
jtag_test = BSCAN_JTAG_TEST_Y;
}
if (pinword) {
HERE();
continue;
}
dev = fdev_p(es->model, bscan_y, bscan_x, DEV_BSCAN, bscan_type_idx);
RC_ASSERT(es->model, dev);
if (dev->instantiated) {
HERE();
continue;
}
fdev_bscan(es->model, bscan_y, bscan_x, bscan_type_idx,
jtag_chain, jtag_test);
RC_CHECK(es->model);
frame_set_pinword(u8_p + XC6_BSCAN_MINOR*FRAME_SIZE + XC6_BSCAN_WORD*XC6_WORD_BYTES, 0);
}
RC_RETURN(es->model);
}
static int write_bscan(struct fpga_bits *bits, struct fpga_model *model)
{
int enum_i, bscan_y, bscan_x, bscan_type_idx, pinword;
struct fpga_device *dev;
uint8_t *u8_p;
RC_CHECK(model);
enum_i = 0;
while (!fdev_enum(model, DEV_BSCAN, enum_i++, &bscan_y,
&bscan_x, &bscan_type_idx) && bscan_y != -1) {
dev = fdev_p(model, bscan_y, bscan_x, DEV_BSCAN, bscan_type_idx);
RC_ASSERT(model, dev);
if (!dev->instantiated) continue;
u8_p = get_first_minor(bits, which_row(bscan_y, model), model->x_major[bscan_x]);
RC_ASSERT(model, u8_p);
pinword = frame_get_pinword(u8_p + XC6_BSCAN_MINOR*FRAME_SIZE + XC6_BSCAN_WORD*XC6_WORD_BYTES);
if (bscan_y == TOP_IO_TILES && !bscan_type_idx
&& dev->u.bscan.jtag_test == BSCAN_JTAG_TEST_Y)
pinword |= 1 << XC6_BSCAN_TEST_PIN;
pinword |= 1 << ((bscan_y - TOP_IO_TILES)*2 + bscan_type_idx);
frame_set_pinword(u8_p + XC6_BSCAN_MINOR*FRAME_SIZE + XC6_BSCAN_WORD*XC6_WORD_BYTES, pinword);
}
RC_RETURN(model);
}
int extract_model(struct fpga_model* model, struct fpga_bits* bits)
{
struct extract_state es;
net_idx_t net_idx;
int i, rc;
RC_CHECK(model);
rc = construct_extract_state(&es, model);
if (rc) RC_FAIL(model, rc);
es.bits = bits;
for (i = 0; i < sizeof(s_default_bits)/sizeof(s_default_bits[0]); i++) {
if (!get_bitp(bits, &s_default_bits[i])) {
RC_SET(model, EINVAL);
goto out;
}
clear_bitp(bits, &s_default_bits[i]);
}
rc = extract_switches(&es);
if (rc) { RC_SET(model, rc); goto out; }
rc = extract_type2(&es);
if (rc) { RC_SET(model, rc); goto out; }
rc = extract_logic(&es);
if (rc) { RC_SET(model, rc); goto out; }
rc = extract_bscan(&es);
if (rc) { RC_SET(model, rc); goto out; }
// turn switches into nets
if (model->nets)
HERE(); // should be empty here
for (i = 0; i < es.num_yx_pos; i++) {
rc = fnet_new(model, &net_idx);
if (rc) { RC_SET(model, rc); goto out; }
rc = fnet_add_sw(model, net_idx, es.yx_pos[i].y,
es.yx_pos[i].x, &es.yx_pos[i].idx, 1);
if (rc) { RC_SET(model, rc); goto out; }
}
out:
destruct_extract_state(&es);
RC_RETURN(model);
}
int printf_swbits(struct fpga_model* model)
{
char bit_str[129];
int i, j, width;
RC_CHECK(model);
for (i = 0; i < model->num_bitpos; i++) {
width = (model->sw_bitpos[i].minor == 20) ? 64 : 128;
for (j = 0; j < width; j++)
bit_str[j] = '0';
bit_str[j] = 0;
if (model->sw_bitpos[i].two_bits_val & 2)
bit_str[model->sw_bitpos[i].two_bits_o] = '1';
if (model->sw_bitpos[i].two_bits_val & 1)
bit_str[model->sw_bitpos[i].two_bits_o+1] = '1';
bit_str[model->sw_bitpos[i].one_bit_o] = '1';
printf("mi%02i %s %s %s %s\n", model->sw_bitpos[i].minor,
fpga_wire2str(model->sw_bitpos[i].to),
bit_str,
fpga_wire2str(model->sw_bitpos[i].from),
model->sw_bitpos[i].bidir ? "<->" : "->");
}
RC_RETURN(model);
}
static int find_bitpos(struct fpga_model* model, int y, int x, swidx_t sw)
{
enum extra_wires from_w, to_w;
const char* from_str, *to_str;
int i;
RC_CHECK(model);
from_str = fpga_switch_str(model, y, x, sw, SW_FROM);
to_str = fpga_switch_str(model, y, x, sw, SW_TO);
from_w = fpga_str2wire(from_str);
to_w = fpga_str2wire(to_str);
if (from_w == NO_WIRE || to_w == NO_WIRE) {
HERE();
return -1;
}
for (i = 0; i < model->num_bitpos; i++) {
if (model->sw_bitpos[i].from == from_w
&& model->sw_bitpos[i].to == to_w)
return i;
if (model->sw_bitpos[i].bidir
&& model->sw_bitpos[i].to == from_w
&& model->sw_bitpos[i].from == to_w) {
if (!fpga_switch_is_bidir(model, y, x, sw))
HERE();
return i;
}
}
fprintf(stderr, "#E switch %s (%i) to %s (%i) not in model\n",
from_str, from_w, to_str, to_w);
return -1;
}
static int write_routing_sw(struct fpga_bits* bits, struct fpga_model* model, int y, int x)
{
struct fpga_tile* tile;
int i, bit_pos, rc;
RC_CHECK(model);
// go through enabled switches, lookup in sw_bitpos
// and set bits
tile = YX_TILE(model, y, x);
for (i = 0; i < tile->num_switches; i++) {
if (!(tile->switches[i] & SWITCH_USED))
continue;
bit_pos = find_bitpos(model, y, x, i);
if (bit_pos == -1) {
HERE();
continue;
}
rc = bitpos_set_bits(bits, model, y, x,
&model->sw_bitpos[bit_pos]);
if (rc) FAIL(rc);
}
return 0;
fail:
return rc;
}
struct str16_sw
{
str16_t from;
str16_t to;
};
static int get_used_switches(struct fpga_model* model, int y, int x,
struct str16_sw** str_sw, int* num_sw)
{
int i, num_used, rc;
struct fpga_tile* tile;
RC_CHECK(model);
tile = YX_TILE(model, y, x);
num_used = 0;
for (i = 0; i < tile->num_switches; i++) {
if (tile->switches[i] & SWITCH_USED)
num_used++;
}
if (!num_used) {
*num_sw = 0;
*str_sw = 0;
return 0;
}
*str_sw = malloc(num_used * sizeof(**str_sw));
if (!(*str_sw)) FAIL(ENOMEM);
*num_sw = 0;
for (i = 0; i < tile->num_switches; i++) {
if (!(tile->switches[i] & SWITCH_USED))
continue;
(*str_sw)[*num_sw].from =
fpga_switch_str_i(model, y, x, i, SW_FROM);
(*str_sw)[*num_sw].to =
fpga_switch_str_i(model, y, x, i, SW_TO);
(*num_sw)++;
}
return 0;
fail:
return rc;
}
// returns the number of found to-from pairs from search_sw that
// were found in the str_sw array, but only if all of the to-from
// pairs in search_sw were found. The found array then contains
// the indices into str_sw were the matches were made.
// If not all to-from pairs were found (or none), returns 0.
static int find_switches(struct iologic_sw_pos* search_sw,
struct str16_sw* str_sw, int num_str_sw, int (*found)[MAX_IOLOGIC_SWBLOCK])
{
int i, j;
for (i = 0; i < MAX_IOLOGIC_SWBLOCK && search_sw->to[i]; i++) {
for (j = 0; j < num_str_sw; j++) {
if (!str_sw[j].to)
continue;
if (str_sw[j].to != search_sw->to[i]
|| str_sw[j].from != search_sw->from[i])
continue;
(*found)[i] = j;
break;
}
if (j >= num_str_sw)
return 0;
}
return i;
}
static int write_iologic_sw(struct fpga_bits* bits, struct fpga_model* model,
int y, int x)
{
int i, j, row_num, row_pos, start_in_frame, rc;
struct iologic_sw_pos* sw_pos;
struct str16_sw* str_sw;
int found_i[MAX_IOLOGIC_SWBLOCK];
int num_sw, num_found;
RC_CHECK(model);
if (x < LEFT_SIDE_WIDTH) {
if (x != LEFT_IO_DEVS) FAIL(EINVAL);
sw_pos = s_leftright_swpos;
} else if (x >= model->x_width-RIGHT_SIDE_WIDTH) {
if (x != model->x_width - RIGHT_IO_DEVS_O) FAIL(EINVAL);
sw_pos = s_leftright_swpos;
} else if (y == TOP_OUTER_IO
|| y == TOP_INNER_IO
|| y == model->y_height-BOT_INNER_IO
|| y == model->y_height-BOT_OUTER_IO)
sw_pos = s_topbot_swpos;
else FAIL(EINVAL);
is_in_row(model, y, &row_num, &row_pos);
if (row_num == -1 || row_pos == -1
|| row_pos == HCLK_POS) FAIL(EINVAL);
if (row_pos > HCLK_POS)
start_in_frame = (row_pos-1)*64 + 16;
else
start_in_frame = row_pos*64;
rc = get_used_switches(model, y, x, &str_sw, &num_sw);
if (rc) FAIL(rc);
for (i = 0; sw_pos[i].to[0]; i++) {
if (!(num_found = find_switches(&sw_pos[i], str_sw,
num_sw, &found_i))) continue;
for (j = 0; sw_pos[i].minor[j] != -1; j++) {
set_bit(bits, row_num, model->x_major[x],
sw_pos[i].minor[j], start_in_frame
+ sw_pos[i].b64[j]);
}
// remove switches from 'used' array
for (j = 0; j < num_found; j++)
str_sw[found_i[j]].to = STRIDX_NO_ENTRY;
}
// check whether all switches were found
for (i = 0; i < num_sw; i++) {
if (str_sw[i].to == STRIDX_NO_ENTRY)
continue;
fprintf(stderr, "#E %s:%i unsupported switch "
"y%i x%i %s -> %s\n", __FILE__, __LINE__, y, x,
strarray_lookup(&model->str, str_sw[i].from),
strarray_lookup(&model->str, str_sw[i].to));
}
free(str_sw);
return 0;
fail:
return rc;
}
static int write_inner_term_sw(struct fpga_bits *bits,
struct fpga_model *model, int y, int x)
{
struct fpga_tile *tile;
const char *from_str, *from_found, *to_str, *to_found;
int i, j, from_idx, to_idx;
RC_CHECK(model);
tile = YX_TILE(model, y, x);
for (i = 0; i < tile->num_switches; i++) {
if (!(tile->switches[i] & SWITCH_USED))
continue;
from_str = fpga_switch_str(model, y, x, i, SW_FROM);
to_str = fpga_switch_str(model, y, x, i, SW_TO);
RC_ASSERT(model, from_str && to_str);
if (strstr(from_str, "IBUF")
&& strstr(to_str, "CLKPIN"))
continue;
if ((from_found = strstr(from_str, "CLKPIN"))
&& (to_found = strstr(to_str, "CKPIN"))) {
struct switch_to_yx_l2 switch_to_yx_l2;
int t2_io_idx, iob_y, iob_x, iob_type_idx;
struct fpga_device *iob_dev;
from_idx = atoi(&from_found[6]);
to_idx = atoi(&to_found[5]);
RC_ASSERT(model, from_idx == to_idx);
// follow switches backwards to IOB
switch_to_yx_l2.l1.yx_req = YX_DEV_IOB;
switch_to_yx_l2.l1.flags = SWTO_YX_DEF;
switch_to_yx_l2.l1.model = model;
switch_to_yx_l2.l1.y = y;
switch_to_yx_l2.l1.x = x;
switch_to_yx_l2.l1.start_switch = fpga_switch_str_i(model, y, x, i, SW_TO);
switch_to_yx_l2.l1.from_to = SW_TO;
switch_to_yx_l2.l1.exclusive_net = NO_NET;
fpga_switch_to_yx_l2(&switch_to_yx_l2);
RC_ASSERT(model, switch_to_yx_l2.l1.set.len);
// find matching gclk pin
for (j = 0; j < model->die->num_gclk_pins; j++) {
t2_io_idx = model->die->gclk_t2_io_idx[j];
iob_y = model->die->t2_io[t2_io_idx].y;
iob_x = model->die->t2_io[t2_io_idx].x;
iob_type_idx = model->die->t2_io[t2_io_idx].type_idx;
if (iob_y != switch_to_yx_l2.l1.dest_y
|| iob_x != switch_to_yx_l2.l1.dest_x)
continue;
iob_dev = fdev_p(model, iob_y, iob_x, DEV_IOB, iob_type_idx);
RC_ASSERT(model, iob_dev);
if (fpga_switch_lookup(model, iob_y, iob_x,
iob_dev->pinw[IOB_OUT_I],
switch_to_yx_l2.l1.dest_connpt) != NO_SWITCH)
break;
}
// set bit
if (j < model->die->num_gclk_pins) {
uint16_t u16;
int bits_off;
bits_off = IOB_DATA_START
+ model->die->gclk_t2_switches[j]*XC6_WORD_BYTES
+ XC6_TYPE2_GCLK_REG_SW/XC6_WORD_BITS;
u16 = frame_get_u16(&bits->d[bits_off]);
u16 |= 1<<(XC6_TYPE2_GCLK_REG_SW%XC6_WORD_BITS);
frame_set_u16(&bits->d[bits_off], u16);
continue;
}
// fall-through to unsupported
}
fprintf(stderr, "#E %s:%i unsupported switch "
"y%i x%i %s -> %s\n", __FILE__, __LINE__,
y, x, from_str, to_str);
}
RC_RETURN(model);
}
static int write_logic_sw(struct fpga_bits *bits,
struct fpga_model *model, int y, int x)
{
struct fpga_tile *tile;
const char *from_str, *to_str;
int i, row, row_pos, xm_col, byte_off, frame_off;
uint64_t mi2526;
uint8_t* u8_p;
RC_CHECK(model);
tile = YX_TILE(model, y, x);
for (i = 0; i < tile->num_switches; i++) {
if (!(tile->switches[i] & SWITCH_USED))
continue;
from_str = fpga_switch_str(model, y, x, i, SW_FROM);
to_str = fpga_switch_str(model, y, x, i, SW_TO);
RC_ASSERT(model, from_str && to_str);
xm_col = has_device_type(model, y, x, DEV_LOGIC, LOGIC_M);
if ((xm_col
&& !strcmp(from_str, "M_COUT")
&& !strcmp(to_str, "M_COUT_N"))
|| (!xm_col
&& !strcmp(from_str, "XL_COUT")
&& !strcmp(to_str, "XL_COUT_N"))) {
is_in_row(model, regular_row_up(y, model), &row, &row_pos);
RC_ASSERT(model, row != -1 && row_pos != -1 && row_pos != HCLK_POS);
if (row_pos > HCLK_POS) row_pos--;
u8_p = get_first_minor(bits, row, model->x_major[x]);
byte_off = row_pos * 8;
if (row_pos >= 8) byte_off += XC6_HCLK_BYTES;
frame_off = (xm_col?26:25)*FRAME_SIZE + byte_off;
mi2526 = frame_get_u64(u8_p + frame_off);
RC_ASSERT(model, !(mi2526 & (1ULL << XC6_ML_CIN_USED)));
mi2526 |= 1ULL << XC6_ML_CIN_USED;
frame_set_u64(u8_p + frame_off, mi2526);
}
}
RC_RETURN(model);
}
static int write_switches(struct fpga_bits* bits, struct fpga_model* model)
{
struct fpga_tile* tile;
int x, y, i;
RC_CHECK(model);
// We need to identify and take out each enabled switch, whether it
// leads to enabled bits or not. That way we can print unsupported
// switches at the end and keep our model alive and maintainable
// over time.
for (x = 0; x < model->x_width; x++) {
for (y = 0; y < model->y_height; y++) {
tile = YX_TILE(model, y, x);
if (is_atx(X_ROUTING_COL, model, x)
&& y >= TOP_IO_TILES
&& y < model->y_height-BOT_IO_TILES
&& !is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS,
model, y)) {
write_routing_sw(bits, model, y, x);
continue;
}
if (is_atyx(YX_DEV_ILOGIC, model, y, x)) {
write_iologic_sw(bits, model, y, x);
continue;
}
if (is_atyx(YX_DEV_LOGIC, model, y, x)) {
write_logic_sw(bits, model, y, x);
continue;
}
if (is_atyx(YX_DEV_IOB, model, y, x))
continue;
if (is_atx(X_ROUTING_COL, model, x)
&& is_aty(Y_ROW_HORIZ_AXSYMM, model, y)) {
write_hclk_sw(bits, model, y, x);
continue;
}
if (is_atyx(YX_INNER_TERM, model, y, x)) {
write_inner_term_sw(bits, model, y, x);
continue;
}
if (is_atyx(YX_CENTER, model, y, x)) {
write_center_sw(bits, model, y, x);
continue;
}
if (is_atx(X_CENTER_REGS_COL, model, x)) {
if (is_aty(Y_ROW_HORIZ_AXSYMM, model, y)) {
write_gclk_center_vert_sw(bits, model, y, x);
continue;
}
if (tile->flags & TF_CENTER_MIDBUF
|| (y < model->center_y
&& YX_TILE(model, y+1, x)->flags & TF_CENTER_MIDBUF)
|| (y > model->center_y
&& YX_TILE(model, y-1, x)->flags & TF_CENTER_MIDBUF))
continue;
}
// print unsupported switches
for (i = 0; i < tile->num_switches; i++) {
if (!(tile->switches[i] & SWITCH_USED))
continue;
fprintf(stderr, "#E %s:%i unsupported switch "
"y%i x%i %s\n", __FILE__, __LINE__,
y, x,
fpga_switch_print(model, y, x, i));
}
}
}
RC_RETURN(model);
}
static int is_latch(struct fpga_device *dev)
{
int i;
// todo: there are a lot more checks we can do to determine whether
// the entire device is properly configured as a latch or not...
for (i = LUT_A; i <= LUT_D; i++) {
if (dev->u.logic.a2d[i].ff == FF_LATCH
|| dev->u.logic.a2d[i].ff == FF_OR2L
|| dev->u.logic.a2d[i].ff == FF_AND2L)
return 1;
}
return 0;
}
static int write_logic(struct fpga_bits* bits, struct fpga_model* model)
{
int dev_idx, row, row_pos, xm_col;
int x, y, byte_off;
uint64_t lut_X[4], lut_ML[4]; // LUT_A-LUT_D
uint64_t mi20, mi23_M, mi2526;
uint8_t* u8_p;
struct fpga_device* dev_ml, *dev_x;
RC_CHECK(model);
for (x = LEFT_SIDE_WIDTH; x < model->x_width-RIGHT_SIDE_WIDTH; x++) {
xm_col = is_atx(X_FABRIC_LOGIC_XM_COL, model, x);
if (!xm_col && !is_atx(X_FABRIC_LOGIC_XL_COL, model, x))
continue;
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (!has_device(model, y, x, DEV_LOGIC))
continue;
is_in_row(model, y, &row, &row_pos);
RC_ASSERT(model, row != -1 && row_pos != -1 && row_pos != HCLK_POS);
if (row_pos > HCLK_POS) row_pos--;
u8_p = get_first_minor(bits, row, model->x_major[x]);
byte_off = row_pos * 8;
if (row_pos >= 8) byte_off += XC6_HCLK_BYTES;
//
// 1) check current bits
//
mi20 = frame_get_u64(u8_p + 20*FRAME_SIZE + byte_off) & XC6_MI20_LOGIC_MASK;
if (xm_col) {
mi23_M = frame_get_u64(u8_p + 23*FRAME_SIZE + byte_off);
mi2526 = frame_get_u64(u8_p + 26*FRAME_SIZE + byte_off);
lut_ML[LUT_A] = frame_get_lut64(XC6_LMAP_XM_M_A,
u8_p + 24*FRAME_SIZE, row_pos*4+2);
lut_ML[LUT_B] = frame_get_lut64(XC6_LMAP_XM_M_B,
u8_p + 21*FRAME_SIZE, row_pos*4+2);
lut_ML[LUT_C] = frame_get_lut64(XC6_LMAP_XM_M_C,
u8_p + 24*FRAME_SIZE, row_pos*4);
lut_ML[LUT_D] = frame_get_lut64(XC6_LMAP_XM_M_D,
u8_p + 21*FRAME_SIZE, row_pos*4);
lut_X[LUT_A] = frame_get_lut64(XC6_LMAP_XM_X_A,
u8_p + 27*FRAME_SIZE, row_pos*4+2);
lut_X[LUT_B] = frame_get_lut64(XC6_LMAP_XM_X_B,
u8_p + 29*FRAME_SIZE, row_pos*4+2);
lut_X[LUT_C] = frame_get_lut64(XC6_LMAP_XM_X_C,
u8_p + 27*FRAME_SIZE, row_pos*4);
lut_X[LUT_D] = frame_get_lut64(XC6_LMAP_XM_X_D,
u8_p + 29*FRAME_SIZE, row_pos*4);
} else { // xl
mi23_M = 0;
mi2526 = frame_get_u64(u8_p + 25*FRAME_SIZE + byte_off);
lut_ML[LUT_A] = frame_get_lut64(XC6_LMAP_XL_L_A,
u8_p + 23*FRAME_SIZE, row_pos*4+2);
lut_ML[LUT_B] = frame_get_lut64(XC6_LMAP_XL_L_B,
u8_p + 21*FRAME_SIZE, row_pos*4+2);
lut_ML[LUT_C] = frame_get_lut64(XC6_LMAP_XL_L_C,
u8_p + 23*FRAME_SIZE, row_pos*4);
lut_ML[LUT_D] = frame_get_lut64(XC6_LMAP_XL_L_D,
u8_p + 21*FRAME_SIZE, row_pos*4);
lut_X[LUT_A] = frame_get_lut64(XC6_LMAP_XL_X_A,
u8_p + 26*FRAME_SIZE, row_pos*4+2);
lut_X[LUT_B] = frame_get_lut64(XC6_LMAP_XL_X_B,
u8_p + 28*FRAME_SIZE, row_pos*4+2);
lut_X[LUT_C] = frame_get_lut64(XC6_LMAP_XL_X_C,
u8_p + 26*FRAME_SIZE, row_pos*4);
lut_X[LUT_D] = frame_get_lut64(XC6_LMAP_XL_X_D,
u8_p + 28*FRAME_SIZE, row_pos*4);
}
// Except for XC6_ML_CIN_USED (which is set by a switch elsewhere),
// everything else should be 0.
if (mi20 || mi23_M || (mi2526 & ~(1ULL<<XC6_ML_CIN_USED))
|| lut_ML[LUT_A] || lut_ML[LUT_B] || lut_ML[LUT_C] || lut_ML[LUT_D]
|| lut_X[LUT_A] || lut_X[LUT_B] || lut_X[LUT_C] || lut_X[LUT_D]) {
HERE();
continue;
}
//
// 2) go through config to assemble bits
//
dev_idx = fpga_dev_idx(model, y, x, DEV_LOGIC, DEV_LOG_X);
dev_x = FPGA_DEV(model, y, x, dev_idx);
RC_ASSERT(model, dev_x);
dev_idx = fpga_dev_idx(model, y, x, DEV_LOGIC, DEV_LOG_M_OR_L);
dev_ml = FPGA_DEV(model, y, x, dev_idx);
RC_ASSERT(model, dev_ml);
//
// 2.1) mi20
//
// X device
if (dev_x->instantiated) {
if (dev_x->u.logic.a2d[LUT_A].ff5_srinit == FF_SRINIT1)
mi20 |= 1ULL << XC6_X_A5_FFSRINIT_1;
if (dev_x->u.logic.a2d[LUT_B].ff5_srinit == FF_SRINIT1)
mi20 |= 1ULL << XC6_X_B5_FFSRINIT_1;
if (dev_x->u.logic.a2d[LUT_C].ff5_srinit == FF_SRINIT1)
mi20 |= 1ULL << XC6_X_C5_FFSRINIT_1;
if (dev_x->u.logic.a2d[LUT_D].ff5_srinit == FF_SRINIT1)
mi20 |= 1ULL << XC6_X_D5_FFSRINIT_1;
if (dev_x->u.logic.a2d[LUT_C].ff_srinit == FF_SRINIT1)
mi20 |= 1ULL << XC6_X_C_FFSRINIT_1;
}
// M or L device
if (dev_ml->instantiated) {
if (dev_ml->u.logic.a2d[LUT_A].ff5_srinit == FF_SRINIT1)
mi20 |= 1ULL << XC6_ML_A5_FFSRINIT_1;
if (dev_ml->u.logic.a2d[LUT_B].ff5_srinit == FF_SRINIT1)
mi20 |= 1ULL << XC6_ML_B5_FFSRINIT_1;
if (dev_ml->u.logic.a2d[LUT_C].ff5_srinit == FF_SRINIT1)
mi20 |= 1ULL << XC6_ML_C5_FFSRINIT_1;
if (dev_ml->u.logic.a2d[LUT_D].ff5_srinit == FF_SRINIT1)
mi20 |= 1ULL << XC6_ML_D5_FFSRINIT_1;
if (xm_col // M-device only
&& dev_ml->u.logic.a2d[LUT_A].ff_srinit == FF_SRINIT1)
mi20 |= 1ULL << XC6_M_A_FFSRINIT_1;
}
//
// 2.2) mi2526
//
// X device
if (dev_x->instantiated) {
if (dev_x->u.logic.a2d[LUT_D].out_mux != MUX_5Q)
mi2526 |= 1ULL << XC6_X_D_OUTMUX_O5; // default-set
if (dev_x->u.logic.a2d[LUT_C].out_mux != MUX_5Q)
mi2526 |= 1ULL << XC6_X_C_OUTMUX_O5; // default-set
if (dev_x->u.logic.a2d[LUT_D].ff_srinit == FF_SRINIT1)
mi2526 |= 1ULL << XC6_X_D_FFSRINIT_1;
if (dev_x->u.logic.a2d[LUT_B].out_mux != MUX_5Q)
mi2526 |= 1ULL << XC6_X_B_OUTMUX_O5; // default-set
if (dev_x->u.logic.clk_inv == CLKINV_B)
mi2526 |= 1ULL << XC6_X_CLK_B;
if (dev_x->u.logic.a2d[LUT_D].ff_mux != MUX_O6)
mi2526 |= 1ULL << XC6_X_D_FFMUX_X; // default-set
if (dev_x->u.logic.a2d[LUT_C].ff_mux != MUX_O6)
mi2526 |= 1ULL << XC6_X_C_FFMUX_X; // default-set
if (dev_x->u.logic.ce_used)
mi2526 |= 1ULL << XC6_X_CE_USED;
if (dev_x->u.logic.a2d[LUT_B].ff_mux != MUX_O6)
mi2526 |= 1ULL << XC6_X_B_FFMUX_X; // default-set
if (dev_x->u.logic.a2d[LUT_A].ff_mux != MUX_O6)
mi2526 |= 1ULL << XC6_X_A_FFMUX_X; // default-set
if (dev_x->u.logic.a2d[LUT_B].ff_srinit == FF_SRINIT1)
mi2526 |= 1ULL << XC6_X_B_FFSRINIT_1;
if (dev_x->u.logic.a2d[LUT_A].out_mux != MUX_5Q)
mi2526 |= 1ULL << XC6_X_A_OUTMUX_O5; // default-set
if (dev_x->u.logic.sr_used)
mi2526 |= 1ULL << XC6_X_SR_USED;
if (dev_x->u.logic.sync_attr == SYNCATTR_SYNC)
mi2526 |= 1ULL << XC6_X_SYNC;
if (is_latch(dev_x))
mi2526 |= 1ULL << XC6_X_ALL_LATCH;
if (dev_x->u.logic.a2d[LUT_A].ff_srinit == FF_SRINIT1)
mi2526 |= 1ULL << XC6_X_A_FFSRINIT_1;
}
// M or L device
if (dev_ml->instantiated) {
if (dev_ml->u.logic.a2d[LUT_D].cy0 == CY0_O5)
mi2526 |= 1ULL << XC6_ML_D_CY0_O5;
if (dev_ml->u.logic.a2d[LUT_D].ff_srinit == FF_SRINIT1)
mi2526 |= 1ULL << XC6_ML_D_FFSRINIT_1;
if (dev_ml->u.logic.a2d[LUT_C].ff_srinit == FF_SRINIT1)
mi2526 |= 1ULL << XC6_ML_C_FFSRINIT_1;
if (dev_ml->u.logic.a2d[LUT_C].cy0 == CY0_O5)
mi2526 |= 1ULL << XC6_ML_C_CY0_O5;
switch (dev_ml->u.logic.a2d[LUT_D].out_mux) {
case MUX_O6: mi2526 |= XC6_ML_D_OUTMUX_O6 << XC6_ML_D_OUTMUX_O; break;
case MUX_XOR: mi2526 |= XC6_ML_D_OUTMUX_XOR << XC6_ML_D_OUTMUX_O; break;
case MUX_O5: mi2526 |= XC6_ML_D_OUTMUX_O5 << XC6_ML_D_OUTMUX_O; break;
case MUX_CY: mi2526 |= XC6_ML_D_OUTMUX_CY << XC6_ML_D_OUTMUX_O; break;
case MUX_5Q: mi2526 |= XC6_ML_D_OUTMUX_5Q << XC6_ML_D_OUTMUX_O; break;
}
switch (dev_ml->u.logic.a2d[LUT_D].ff_mux) {
// XC6_ML_D_FFMUX_O6 is 0
case MUX_O5: mi2526 |= XC6_ML_D_FFMUX_O5 << XC6_ML_D_FFMUX_O; break;
case MUX_X: mi2526 |= XC6_ML_D_FFMUX_X << XC6_ML_D_FFMUX_O; break;
case MUX_XOR: mi2526 |= XC6_ML_D_FFMUX_XOR << XC6_ML_D_FFMUX_O; break;
case MUX_CY: mi2526 |= XC6_ML_D_FFMUX_CY << XC6_ML_D_FFMUX_O; break;
}
if (is_latch(dev_ml))
mi2526 |= 1ULL << XC6_ML_ALL_LATCH;
if (dev_ml->u.logic.sr_used)
mi2526 |= 1ULL << XC6_ML_SR_USED;
if (dev_ml->u.logic.sync_attr == SYNCATTR_SYNC)
mi2526 |= 1ULL << XC6_ML_SYNC;
if (dev_ml->u.logic.ce_used)
mi2526 |= 1ULL << XC6_ML_CE_USED;
switch (dev_ml->u.logic.a2d[LUT_C].out_mux) {
case MUX_XOR: mi2526 |= XC6_ML_C_OUTMUX_XOR << XC6_ML_C_OUTMUX_O; break;
case MUX_O6: mi2526 |= XC6_ML_C_OUTMUX_O6 << XC6_ML_C_OUTMUX_O; break;
case MUX_5Q: mi2526 |= XC6_ML_C_OUTMUX_5Q << XC6_ML_C_OUTMUX_O; break;
case MUX_CY: mi2526 |= XC6_ML_C_OUTMUX_CY << XC6_ML_C_OUTMUX_O; break;
case MUX_O5: mi2526 |= XC6_ML_C_OUTMUX_O5 << XC6_ML_C_OUTMUX_O; break;
case MUX_F7: mi2526 |= XC6_ML_C_OUTMUX_F7 << XC6_ML_C_OUTMUX_O; break;
}
switch (dev_ml->u.logic.a2d[LUT_C].ff_mux) {
// XC6_ML_C_FFMUX_O6 is 0
case MUX_O5: mi2526 |= XC6_ML_C_FFMUX_O5 << XC6_ML_C_FFMUX_O; break;
case MUX_X: mi2526 |= XC6_ML_C_FFMUX_X << XC6_ML_C_FFMUX_O; break;
case MUX_F7: mi2526 |= XC6_ML_C_FFMUX_F7 << XC6_ML_C_FFMUX_O; break;
case MUX_XOR: mi2526 |= XC6_ML_C_FFMUX_XOR << XC6_ML_C_FFMUX_O; break;
case MUX_CY: mi2526 |= XC6_ML_C_FFMUX_CY << XC6_ML_C_FFMUX_O; break;
}
switch (dev_ml->u.logic.a2d[LUT_B].out_mux) {
case MUX_5Q: mi2526 |= XC6_ML_B_OUTMUX_5Q << XC6_ML_B_OUTMUX_O; break;
case MUX_F8: mi2526 |= XC6_ML_B_OUTMUX_F8 << XC6_ML_B_OUTMUX_O; break;
case MUX_XOR: mi2526 |= XC6_ML_B_OUTMUX_XOR << XC6_ML_B_OUTMUX_O; break;
case MUX_CY: mi2526 |= XC6_ML_B_OUTMUX_CY << XC6_ML_B_OUTMUX_O; break;
case MUX_O6: mi2526 |= XC6_ML_B_OUTMUX_O6 << XC6_ML_B_OUTMUX_O; break;
case MUX_O5: mi2526 |= XC6_ML_B_OUTMUX_O5 << XC6_ML_B_OUTMUX_O; break;
}
if (dev_ml->u.logic.clk_inv == CLKINV_B)
mi2526 |= 1ULL << XC6_ML_CLK_B;
switch (dev_ml->u.logic.a2d[LUT_B].ff_mux) {
// XC6_ML_B_FFMUX_O6 is 0
case MUX_XOR: mi2526 |= XC6_ML_B_FFMUX_XOR << XC6_ML_B_FFMUX_O; break;
case MUX_O5: mi2526 |= XC6_ML_B_FFMUX_O5 << XC6_ML_B_FFMUX_O; break;
case MUX_CY: mi2526 |= XC6_ML_B_FFMUX_CY << XC6_ML_B_FFMUX_O; break;
case MUX_X: mi2526 |= XC6_ML_B_FFMUX_X << XC6_ML_B_FFMUX_O; break;
case MUX_F8: mi2526 |= XC6_ML_B_FFMUX_F8 << XC6_ML_B_FFMUX_O; break;
}
switch (dev_ml->u.logic.a2d[LUT_A].ff_mux) {
// XC6_ML_A_FFMUX_O6 is 0
case MUX_XOR: mi2526 |= XC6_ML_A_FFMUX_XOR << XC6_ML_A_FFMUX_O; break;
case MUX_X: mi2526 |= XC6_ML_A_FFMUX_X << XC6_ML_A_FFMUX_O; break;
case MUX_O5: mi2526 |= XC6_ML_A_FFMUX_O5 << XC6_ML_A_FFMUX_O; break;
case MUX_CY: mi2526 |= XC6_ML_A_FFMUX_CY << XC6_ML_A_FFMUX_O; break;
case MUX_F7: mi2526 |= XC6_ML_A_FFMUX_F7 << XC6_ML_A_FFMUX_O; break;
}
switch (dev_ml->u.logic.a2d[LUT_A].out_mux) {
case MUX_5Q: mi2526 |= XC6_ML_A_OUTMUX_5Q << XC6_ML_A_OUTMUX_O; break;
case MUX_F7: mi2526 |= XC6_ML_A_OUTMUX_F7 << XC6_ML_A_OUTMUX_O; break;
case MUX_XOR: mi2526 |= XC6_ML_A_OUTMUX_XOR << XC6_ML_A_OUTMUX_O; break;
case MUX_CY: mi2526 |= XC6_ML_A_OUTMUX_CY << XC6_ML_A_OUTMUX_O; break;
case MUX_O6: mi2526 |= XC6_ML_A_OUTMUX_O6 << XC6_ML_A_OUTMUX_O; break;
case MUX_O5: mi2526 |= XC6_ML_A_OUTMUX_O5 << XC6_ML_A_OUTMUX_O; break;
}
if (dev_ml->u.logic.a2d[LUT_B].cy0 == CY0_O5)
mi2526 |= 1ULL << XC6_ML_B_CY0_O5;
if (dev_ml->u.logic.precyinit == PRECYINIT_AX)
mi2526 |= 1ULL << XC6_ML_PRECYINIT_AX;
else if (dev_ml->u.logic.precyinit == PRECYINIT_1)
mi2526 |= 1ULL << XC6_ML_PRECYINIT_1;
if (dev_ml->u.logic.a2d[LUT_B].ff_srinit == FF_SRINIT1)
mi2526 |= 1ULL << XC6_ML_B_FFSRINIT_1;
if (dev_ml->u.logic.a2d[LUT_A].cy0 == CY0_O5)
mi2526 |= 1ULL << XC6_ML_A_CY0_O5;
if (!xm_col && dev_ml->u.logic.a2d[LUT_A].ff_srinit == FF_SRINIT1)
mi2526 |= 1ULL << XC6_L_A_FFSRINIT_1;
}
//
// 2.3) luts
//
// X device
if (dev_x->instantiated) {
fdev_logic_lut_dieval(model, y, x, DEV_LOG_X, LUT_A, &lut_X[LUT_A]);
fdev_logic_lut_dieval(model, y, x, DEV_LOG_X, LUT_B, &lut_X[LUT_B]);
fdev_logic_lut_dieval(model, y, x, DEV_LOG_X, LUT_C, &lut_X[LUT_C]);
fdev_logic_lut_dieval(model, y, x, DEV_LOG_X, LUT_D, &lut_X[LUT_D]);
}
// M or L device
if (dev_ml->instantiated) {
fdev_logic_lut_dieval(model, y, x, DEV_LOG_M_OR_L, LUT_A, &lut_ML[LUT_A]);
fdev_logic_lut_dieval(model, y, x, DEV_LOG_M_OR_L, LUT_B, &lut_ML[LUT_B]);
fdev_logic_lut_dieval(model, y, x, DEV_LOG_M_OR_L, LUT_C, &lut_ML[LUT_C]);
fdev_logic_lut_dieval(model, y, x, DEV_LOG_M_OR_L, LUT_D, &lut_ML[LUT_D]);
}
//
// 3) write bits
//
// logic devs occupy only some bits in mi20, so we merge
// with the others (switches).
frame_set_u64(u8_p + 20*FRAME_SIZE + byte_off,
(frame_get_u64(u8_p + 20*FRAME_SIZE + byte_off) & ~XC6_MI20_LOGIC_MASK)
| mi20);
if (xm_col) {
frame_set_u64(u8_p + 23*FRAME_SIZE + byte_off, mi23_M);
frame_set_u64(u8_p + 26*FRAME_SIZE + byte_off, mi2526);
frame_set_lut64(u8_p + 24*FRAME_SIZE, row_pos*2+1, lut_ML[LUT_A]);
frame_set_lut64(u8_p + 21*FRAME_SIZE, row_pos*2+1, lut_ML[LUT_B]);
frame_set_lut64(u8_p + 24*FRAME_SIZE, row_pos*2, lut_ML[LUT_C]);
frame_set_lut64(u8_p + 21*FRAME_SIZE, row_pos*2, lut_ML[LUT_D]);
frame_set_lut64(u8_p + 27*FRAME_SIZE, row_pos*2+1, lut_X[LUT_A]);
frame_set_lut64(u8_p + 29*FRAME_SIZE, row_pos*2+1, lut_X[LUT_B]);
frame_set_lut64(u8_p + 27*FRAME_SIZE, row_pos*2, lut_X[LUT_C]);
frame_set_lut64(u8_p + 29*FRAME_SIZE, row_pos*2, lut_X[LUT_D]);
} else { // xl
// mi23 is unused in xl cols - no need to write it
RC_ASSERT(model, !mi23_M);
frame_set_u64(u8_p + 25*FRAME_SIZE + byte_off, mi2526);
frame_set_lut64(u8_p + 23*FRAME_SIZE, row_pos*2+1, lut_ML[LUT_A]);
frame_set_lut64(u8_p + 21*FRAME_SIZE, row_pos*2+1, lut_ML[LUT_B]);
frame_set_lut64(u8_p + 23*FRAME_SIZE, row_pos*2, lut_ML[LUT_C]);
frame_set_lut64(u8_p + 21*FRAME_SIZE, row_pos*2, lut_ML[LUT_D]);
frame_set_lut64(u8_p + 26*FRAME_SIZE, row_pos*2+1, lut_X[LUT_A]);
frame_set_lut64(u8_p + 28*FRAME_SIZE, row_pos*2+1, lut_X[LUT_B]);
frame_set_lut64(u8_p + 26*FRAME_SIZE, row_pos*2, lut_X[LUT_C]);
frame_set_lut64(u8_p + 28*FRAME_SIZE, row_pos*2, lut_X[LUT_D]);
}
}
}
RC_RETURN(model);
}
int write_model(struct fpga_bits *bits, struct fpga_model *model)
{
int i;
RC_CHECK(model);
for (i = 0; i < sizeof(s_default_bits)/sizeof(s_default_bits[0]); i++)
set_bitp(bits, &s_default_bits[i]);
write_switches(bits, model);
write_type2(bits, model);
write_logic(bits, model);
write_bscan(bits, model);
RC_RETURN(model);
}