// // 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 lut2str(uint64_t lut, int lut_pos, int lut5_used, char *lut6_buf, char** lut6_p, char *lut5_buf, char** lut5_p) { int lut_map[64], rc; uint64_t lut_mapped; const char* str; if (lut5_used) { xc6_lut_bitmap(lut_pos, &lut_map, 32); lut_mapped = map_bits(lut, 64, lut_map); // lut6 str = bool_bits2str(ULL_HIGH32(lut_mapped), 32); if (!str) FAIL(EINVAL); snprintf(lut6_buf, MAX_LUT_LEN, "(A6+~A6)*(%s)", str); *lut6_p = lut6_buf; // lut5 str = bool_bits2str(ULL_LOW32(lut_mapped), 32); if (!str) FAIL(EINVAL); strcpy(lut5_buf, str); *lut5_p = lut5_buf; } else { xc6_lut_bitmap(lut_pos, &lut_map, 64); lut_mapped = map_bits(lut, 64, lut_map); str = bool_bits2str(lut_mapped, 64); if (!str) FAIL(EINVAL); strcpy(lut6_buf, str); *lut6_p = lut6_buf; } return 0; fail: return rc; } 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, lut5_used, 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; char lut6_ml[NUM_LUTS][MAX_LUT_LEN]; char lut5_ml[NUM_LUTS][MAX_LUT_LEN]; char lut6_x[NUM_LUTS][MAX_LUT_LEN]; char lut5_x[NUM_LUTS][MAX_LUT_LEN]; 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(u8_p + 24*FRAME_SIZE, row_pos*2+1); lut_ML[LUT_B] = frame_get_lut64(u8_p + 21*FRAME_SIZE, row_pos*2+1); lut_ML[LUT_C] = frame_get_lut64(u8_p + 24*FRAME_SIZE, row_pos*2); lut_ML[LUT_D] = frame_get_lut64(u8_p + 21*FRAME_SIZE, row_pos*2); lut_X[LUT_A] = frame_get_lut64(u8_p + 27*FRAME_SIZE, row_pos*2+1); lut_X[LUT_B] = frame_get_lut64(u8_p + 29*FRAME_SIZE, row_pos*2+1); lut_X[LUT_C] = frame_get_lut64(u8_p + 27*FRAME_SIZE, row_pos*2); lut_X[LUT_D] = frame_get_lut64(u8_p + 29*FRAME_SIZE, row_pos*2); 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(u8_p + 23*FRAME_SIZE, row_pos*2+1); lut_ML[LUT_B] = frame_get_lut64(u8_p + 21*FRAME_SIZE, row_pos*2+1); lut_ML[LUT_C] = frame_get_lut64(u8_p + 23*FRAME_SIZE, row_pos*2); lut_ML[LUT_D] = frame_get_lut64(u8_p + 21*FRAME_SIZE, row_pos*2); lut_X[LUT_A] = frame_get_lut64(u8_p + 26*FRAME_SIZE, row_pos*2+1); lut_X[LUT_B] = frame_get_lut64(u8_p + 28*FRAME_SIZE, row_pos*2+1); lut_X[LUT_C] = frame_get_lut64(u8_p + 26*FRAME_SIZE, row_pos*2); lut_X[LUT_D] = frame_get_lut64(u8_p + 28*FRAME_SIZE, row_pos*2); 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[0] && !lut_X[1] && !lut_X[2] && !lut_X[3] && !lut_ML[0] && !lut_ML[1] && !lut_ML[2] && !lut_ML[3]) 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_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_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_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<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; lut5_used = (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); rc = lut2str(lut_ML[LUT_A], l_col ? XC6_LMAP_XL_L_A : XC6_LMAP_XM_M_A, lut5_used, lut6_ml[LUT_A], &cfg_ml.a2d[LUT_A].lut6_str, lut5_ml[LUT_A], &cfg_ml.a2d[LUT_A].lut5_str); if (rc) FAIL(rc); } // 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; lut5_used = (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); rc = lut2str(lut_ML[LUT_B], l_col ? XC6_LMAP_XL_L_B : XC6_LMAP_XM_M_B, lut5_used, lut6_ml[LUT_B], &cfg_ml.a2d[LUT_B].lut6_str, lut5_ml[LUT_B], &cfg_ml.a2d[LUT_B].lut5_str); if (rc) FAIL(rc); } // 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; lut5_used = (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); rc = lut2str(lut_ML[LUT_C], l_col ? XC6_LMAP_XL_L_C : XC6_LMAP_XM_M_C, lut5_used, lut6_ml[LUT_C], &cfg_ml.a2d[LUT_C].lut6_str, lut5_ml[LUT_C], &cfg_ml.a2d[LUT_C].lut5_str); if (rc) FAIL(rc); } // 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; lut5_used = (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); rc = lut2str(lut_ML[LUT_D], l_col ? XC6_LMAP_XL_L_D : XC6_LMAP_XM_M_D, lut5_used, lut6_ml[LUT_D], &cfg_ml.a2d[LUT_D].lut6_str, lut5_ml[LUT_D], &cfg_ml.a2d[LUT_D].lut5_str); if (rc) FAIL(rc); } // 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; lut5_used = cfg_x.a2d[LUT_A].out_mux != 0; rc = lut2str(lut_X[LUT_A], l_col ? XC6_LMAP_XL_X_A : XC6_LMAP_XM_X_A, lut5_used, lut6_x[LUT_A], &cfg_x.a2d[LUT_A].lut6_str, lut5_x[LUT_A], &cfg_x.a2d[LUT_A].lut5_str); if (rc) FAIL(rc); } // 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; lut5_used = cfg_x.a2d[LUT_B].out_mux != 0; rc = lut2str(lut_X[LUT_B], l_col ? XC6_LMAP_XL_X_B : XC6_LMAP_XM_X_B, lut5_used, lut6_x[LUT_B], &cfg_x.a2d[LUT_B].lut6_str, lut5_x[LUT_B], &cfg_x.a2d[LUT_B].lut5_str); if (rc) FAIL(rc); } // 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; lut5_used = cfg_x.a2d[LUT_C].out_mux != 0; rc = lut2str(lut_X[LUT_C], l_col ? XC6_LMAP_XL_X_C : XC6_LMAP_XM_X_C, lut5_used, lut6_x[LUT_C], &cfg_x.a2d[LUT_C].lut6_str, lut5_x[LUT_C], &cfg_x.a2d[LUT_C].lut5_str); if (rc) FAIL(rc); } // 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; lut5_used = cfg_x.a2d[LUT_D].out_mux != 0; rc = lut2str(lut_X[LUT_D], l_col ? XC6_LMAP_XL_X_D : XC6_LMAP_XM_X_D, lut5_used, lut6_x[LUT_D], &cfg_x.a2d[LUT_D].lut6_str, lut5_x[LUT_D], &cfg_x.a2d[LUT_D].lut5_str); if (rc) FAIL(rc); } // // 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<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<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<model->center_x, pf("CLKV_GCLKH_MAIN%i_FOLD", cur_pin), pf("CLKV_GCLKH_L%i", cur_pin)); word &= ~(1< 15) break; if (!(word & (1<model->center_x, pf("CLKV_GCLKH_MAIN%i_FOLD", cur_pin), pf("CLKV_GCLKH_R%i", cur_pin)); word &= ~(1<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<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 str2lut(uint64_t *lut, int lut_pos, const struct fpgadev_logic_a2d *a2d) { int lut6_used, lut5_used, lut_map[64], rc; uint64_t u64; lut6_used = a2d->lut6_str && a2d->lut6_str[0]; lut5_used = a2d->lut5_str && a2d->lut5_str[0]; if (!lut6_used && !lut5_used) return 0; if (lut5_used) { if (!lut6_used) u64 = 0; else { rc = bool_str2bits(a2d->lut6_str, &u64, 32); if (rc) FAIL(rc); u64 <<= 32; } rc = bool_str2bits(a2d->lut5_str, &u64, 32); if (rc) FAIL(rc); xc6_lut_bitmap(lut_pos, &lut_map, 32); } else { // lut6_used only rc = bool_str2bits(a2d->lut6_str, &u64, 64); if (rc) FAIL(rc); xc6_lut_bitmap(lut_pos, &lut_map, 64); } *lut = map_bits(u64, 64, lut_map); return 0; fail: return rc; } 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, rc; 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(u8_p + 24*FRAME_SIZE, row_pos*2+1); lut_ML[LUT_B] = frame_get_lut64(u8_p + 21*FRAME_SIZE, row_pos*2+1); lut_ML[LUT_C] = frame_get_lut64(u8_p + 24*FRAME_SIZE, row_pos*2); lut_ML[LUT_D] = frame_get_lut64(u8_p + 21*FRAME_SIZE, row_pos*2); lut_X[LUT_A] = frame_get_lut64(u8_p + 27*FRAME_SIZE, row_pos*2+1); lut_X[LUT_B] = frame_get_lut64(u8_p + 29*FRAME_SIZE, row_pos*2+1); lut_X[LUT_C] = frame_get_lut64(u8_p + 27*FRAME_SIZE, row_pos*2); lut_X[LUT_D] = frame_get_lut64(u8_p + 29*FRAME_SIZE, row_pos*2); } else { // xl mi23_M = 0; mi2526 = frame_get_u64(u8_p + 25*FRAME_SIZE + byte_off); lut_ML[LUT_A] = frame_get_lut64(u8_p + 23*FRAME_SIZE, row_pos*2+1); lut_ML[LUT_B] = frame_get_lut64(u8_p + 21*FRAME_SIZE, row_pos*2+1); lut_ML[LUT_C] = frame_get_lut64(u8_p + 23*FRAME_SIZE, row_pos*2); lut_ML[LUT_D] = frame_get_lut64(u8_p + 21*FRAME_SIZE, row_pos*2); lut_X[LUT_A] = frame_get_lut64(u8_p + 26*FRAME_SIZE, row_pos*2+1); lut_X[LUT_B] = frame_get_lut64(u8_p + 28*FRAME_SIZE, row_pos*2+1); lut_X[LUT_C] = frame_get_lut64(u8_p + 26*FRAME_SIZE, row_pos*2); lut_X[LUT_D] = frame_get_lut64(u8_p + 28*FRAME_SIZE, row_pos*2); } // Except for XC6_ML_CIN_USED (which is set by a switch elsewhere), // everything else should be 0. if (mi20 || mi23_M || (mi2526 & ~(1ULL<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) { rc = str2lut(&lut_X[LUT_A], xm_col ? XC6_LMAP_XM_X_A : XC6_LMAP_XL_X_A, &dev_x->u.logic.a2d[LUT_A]); RC_ASSERT(model, !rc); rc = str2lut(&lut_X[LUT_B], xm_col ? XC6_LMAP_XM_X_B : XC6_LMAP_XL_X_B, &dev_x->u.logic.a2d[LUT_B]); RC_ASSERT(model, !rc); rc = str2lut(&lut_X[LUT_C], xm_col ? XC6_LMAP_XM_X_C : XC6_LMAP_XL_X_C, &dev_x->u.logic.a2d[LUT_C]); RC_ASSERT(model, !rc); rc = str2lut(&lut_X[LUT_D], xm_col ? XC6_LMAP_XM_X_D : XC6_LMAP_XL_X_D, &dev_x->u.logic.a2d[LUT_D]); RC_ASSERT(model, !rc); } // M or L device if (dev_ml->instantiated) { rc = str2lut(&lut_ML[LUT_A], xm_col ? XC6_LMAP_XM_M_A : XC6_LMAP_XL_L_A, &dev_ml->u.logic.a2d[LUT_A]); RC_ASSERT(model, !rc); rc = str2lut(&lut_ML[LUT_B], xm_col ? XC6_LMAP_XM_M_B : XC6_LMAP_XL_L_B, &dev_ml->u.logic.a2d[LUT_B]); RC_ASSERT(model, !rc); rc = str2lut(&lut_ML[LUT_C], xm_col ? XC6_LMAP_XM_M_C : XC6_LMAP_XL_L_C, &dev_ml->u.logic.a2d[LUT_C]); RC_ASSERT(model, !rc); rc = str2lut(&lut_ML[LUT_D], xm_col ? XC6_LMAP_XM_M_D : XC6_LMAP_XL_L_D, &dev_ml->u.logic.a2d[LUT_D]); RC_ASSERT(model, !rc); } // // 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); }