// // 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 #include "model.h" static int init_tiles(struct fpga_model* model); static int init_wires(struct fpga_model* model); static int init_ports(struct fpga_model* model); static int init_devices(struct fpga_model* model); static int init_switches(struct fpga_model* model); static int run_gclk(struct fpga_model* model); static int run_gclk_horiz_regs(struct fpga_model* model); static int run_gclk_vert_regs(struct fpga_model* model); static int run_logic_inout(struct fpga_model* model); static int run_direction_wires(struct fpga_model* model); static const char* pf(const char* fmt, ...); static const char* wpref(struct fpga_model* model, int y, int x, const char* wire_name); static char next_non_whitespace(const char* s); static char last_major(const char* str, int cur_o); static int add_connpt_name(struct fpga_model* model, int y, int x, const char* connpt_name); typedef int (*add_conn_f)(struct fpga_model* model, int y1, int x1, const char* name1, int y2, int x2, const char* name2); #define NOPREF_BI_F add_conn_bi #define PREF_BI_F add_conn_bi_pref #define NOPREF_UNI_F add_conn_uni #define PREF_UNI_F add_conn_uni_pref static int add_conn_uni(struct fpga_model* model, int y1, int x1, const char* name1, int y2, int x2, const char* name2); int add_conn_uni_pref(struct fpga_model* model, int y1, int x1, const char* name1, int y2, int x2, const char* name2); static int add_conn_bi(struct fpga_model* model, int y1, int x1, const char* name1, int y2, int x2, const char* name2); static int add_conn_bi_pref(struct fpga_model* model, int y1, int x1, const char* name1, int y2, int x2, const char* name2); static int add_conn_range(struct fpga_model* model, add_conn_f add_conn_func, int y1, int x1, const char* name1, int start1, int last1, int y2, int x2, const char* name2, int start2); struct w_point // wire point { const char* name; int start_count; // if there is a %i in the name, this is the start number int y, x; }; struct w_net { // if !last_inc, no incrementing will happen // if last_inc > 0, incrementing will happen to // the %i in the name from 0:last_inc, for a total // of last_inc+1 wires. int last_inc; struct w_point pts[40]; }; static int add_conn_net(struct fpga_model* model, add_conn_f add_conn_func, struct w_net* net); static int add_switch(struct fpga_model* model, int y, int x, const char* from, const char* to, int is_bidirectional); struct seed_data { int x_flags; const char* str; }; static void seed_strx(struct fpga_model* model, struct seed_data* data); int fpga_build_model(struct fpga_model* model, int fpga_rows, const char* columns, const char* left_wiring, const char* right_wiring) { int rc; memset(model, 0, sizeof(*model)); model->cfg_rows = fpga_rows; strncpy(model->cfg_columns, columns, sizeof(model->cfg_columns)-1); strncpy(model->cfg_left_wiring, left_wiring, sizeof(model->cfg_left_wiring)-1); strncpy(model->cfg_right_wiring, right_wiring, sizeof(model->cfg_right_wiring)-1); strarray_init(&model->str, STRIDX_64K); rc = init_tiles(model); if (rc) return rc; rc = init_wires(model); if (rc) return rc; rc = init_ports(model); if (rc) return rc; rc = init_devices(model); if (rc) return rc; rc = init_switches(model); if (rc) return rc; return 0; } void fpga_free_model(struct fpga_model* model) { if (!model) return; free(model->tmp_str); strarray_free(&model->str); free(model->tiles); memset(model, 0, sizeof(*model)); } static int init_switches(struct fpga_model* model) { int x, y, rc; for (x = 0; x < model->x_width; x++) { if (!is_atx(X_ROUTING_COL, model, x)) continue; for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) { if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y)) continue; if (y != 68 || x != 12) continue; rc = add_switch(model, y, x, "LOGICOUT0", "NN2B0", 0 /* bidir */); if (rc) goto xout; } } return 0; xout: return rc; } static int init_devices(struct fpga_model* model) { int x, y, i, j; struct fpga_tile* tile; // DCM, PLL_ADV for (i = 0; i < model->cfg_rows; i++) { y = TOP_IO_TILES + HALF_ROW + i*ROW_SIZE; if (y > model->center_y) y++; // central regs tile = YX_TILE(model, y-1, model->center_x-CMTPLL_FROM_CENTER_O); if (i%2) { tile->devices[tile->num_devices++].type = DEV_DCM; tile->devices[tile->num_devices++].type = DEV_DCM; } else tile->devices[tile->num_devices++].type = DEV_PLL_ADV; } // BSCAN tile = YX_TILE(model, TOP_IO_TILES, model->x_width-RIGHT_IO_DEVS_O); tile->devices[tile->num_devices++].type = DEV_BSCAN; tile->devices[tile->num_devices++].type = DEV_BSCAN; // BSCAN, OCT_CALIBRATE tile = YX_TILE(model, TOP_IO_TILES+1, model->x_width-RIGHT_IO_DEVS_O); tile->devices[tile->num_devices++].type = DEV_BSCAN; tile->devices[tile->num_devices++].type = DEV_BSCAN; tile->devices[tile->num_devices++].type = DEV_OCT_CALIBRATE; // ICAP, SPI_ACCESS, OCT_CALIBRATE tile = YX_TILE(model, model->y_height-BOT_IO_TILES-1, model->x_width-RIGHT_IO_DEVS_O); tile->devices[tile->num_devices++].type = DEV_ICAP; tile->devices[tile->num_devices++].type = DEV_SPI_ACCESS; tile->devices[tile->num_devices++].type = DEV_OCT_CALIBRATE; // STARTUP, POST_CRC_INTERNAL, SLAVE_SPI, SUSPEND_SYNC tile = YX_TILE(model, model->y_height-BOT_IO_TILES-2, model->x_width-RIGHT_IO_DEVS_O); tile->devices[tile->num_devices++].type = DEV_STARTUP; tile->devices[tile->num_devices++].type = DEV_POST_CRC_INTERNAL; tile->devices[tile->num_devices++].type = DEV_SLAVE_SPI; tile->devices[tile->num_devices++].type = DEV_SUSPEND_SYNC; // BUFGMUX tile = YX_TILE(model, model->center_y, model->center_x); for (i = 0; i < 16; i++) tile->devices[tile->num_devices++].type = DEV_BUFGMUX; // BUFIO, BUFIO_FB, BUFPLL, BUFPLL_MCB tile = YX_TILE(model, TOP_OUTER_ROW, model->center_x-CMTPLL_FROM_CENTER_O); tile->devices[tile->num_devices++].type = DEV_BUFPLL; tile->devices[tile->num_devices++].type = DEV_BUFPLL; tile->devices[tile->num_devices++].type = DEV_BUFPLL_MCB; for (j = 0; j < 8; j++) { tile->devices[tile->num_devices++].type = DEV_BUFIO; tile->devices[tile->num_devices++].type = DEV_BUFIO_FB; } tile = YX_TILE(model, model->center_y, LEFT_OUTER_COL); tile->devices[tile->num_devices++].type = DEV_BUFPLL; tile->devices[tile->num_devices++].type = DEV_BUFPLL; tile->devices[tile->num_devices++].type = DEV_BUFPLL_MCB; for (j = 0; j < 8; j++) { tile->devices[tile->num_devices++].type = DEV_BUFIO; tile->devices[tile->num_devices++].type = DEV_BUFIO_FB; } tile = YX_TILE(model, model->center_y, model->x_width - RIGHT_OUTER_O); tile->devices[tile->num_devices++].type = DEV_BUFPLL; tile->devices[tile->num_devices++].type = DEV_BUFPLL; tile->devices[tile->num_devices++].type = DEV_BUFPLL_MCB; for (j = 0; j < 8; j++) { tile->devices[tile->num_devices++].type = DEV_BUFIO; tile->devices[tile->num_devices++].type = DEV_BUFIO_FB; } tile = YX_TILE(model, model->y_height - BOT_OUTER_ROW, model->center_x-CMTPLL_FROM_CENTER_O); tile->devices[tile->num_devices++].type = DEV_BUFPLL; tile->devices[tile->num_devices++].type = DEV_BUFPLL; tile->devices[tile->num_devices++].type = DEV_BUFPLL_MCB; for (j = 0; j < 8; j++) { tile->devices[tile->num_devices++].type = DEV_BUFIO; tile->devices[tile->num_devices++].type = DEV_BUFIO_FB; } // BUFH for (i = 0; i < model->cfg_rows; i++) { y = TOP_IO_TILES + HALF_ROW + i*ROW_SIZE; if (y > model->center_y) y++; // central regs tile = YX_TILE(model, y, model->center_x); for (j = 0; j < 32; j++) tile->devices[tile->num_devices++].type = DEV_BUFH; } // BRAM for (x = 0; x < model->x_width; x++) { if (is_atx(X_FABRIC_BRAM_COL, model, x)) { for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) { tile = YX_TILE(model, y, x); if (tile->flags & TF_BRAM_DEV) { tile->devices[tile->num_devices++].type = DEV_BRAM16; tile->devices[tile->num_devices++].type = DEV_BRAM8; tile->devices[tile->num_devices++].type = DEV_BRAM8; } } } } // MACC for (x = 0; x < model->x_width; x++) { if (is_atx(X_FABRIC_MACC_COL, model, x)) { for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) { tile = YX_TILE(model, y, x); if (tile->flags & TF_MACC_DEV) tile->devices[tile->num_devices++].type = DEV_MACC; } } } // ILOGIC/OLOGIC/IODELAY for (x = 0; x < model->x_width; x++) { if (is_atx(X_LOGIC_COL, model, x) && !is_atx(X_ROUTING_NO_IO, model, x-1)) { for (i = 0; i <= 1; i++) { tile = YX_TILE(model, TOP_IO_TILES+i, x); for (j = 0; j <= 1; j++) { tile->devices[tile->num_devices++].type = DEV_ILOGIC; tile->devices[tile->num_devices++].type = DEV_OLOGIC; tile->devices[tile->num_devices++].type = DEV_IODELAY; } tile = YX_TILE(model, model->y_height-BOT_IO_TILES-i-1, x); for (j = 0; j <= 1; j++) { tile->devices[tile->num_devices++].type = DEV_ILOGIC; tile->devices[tile->num_devices++].type = DEV_OLOGIC; tile->devices[tile->num_devices++].type = DEV_IODELAY; } } } if (is_atx(X_LEFT_IO_DEVS_COL, model, x)) { for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) { if (is_aty(Y_LEFT_WIRED, model, y)) { tile = YX_TILE(model, y, x); for (j = 0; j <= 1; j++) { tile->devices[tile->num_devices++].type = DEV_ILOGIC; tile->devices[tile->num_devices++].type = DEV_OLOGIC; tile->devices[tile->num_devices++].type = DEV_IODELAY; } } } } if (is_atx(X_RIGHT_IO_DEVS_COL, model, x)) { for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) { if (is_aty(Y_RIGHT_WIRED, model, y)) { tile = YX_TILE(model, y, x); for (j = 0; j <= 1; j++) { tile->devices[tile->num_devices++].type = DEV_ILOGIC; tile->devices[tile->num_devices++].type = DEV_OLOGIC; tile->devices[tile->num_devices++].type = DEV_IODELAY; } } } } } // IOB for (x = 0; x < model->x_width; x++) { if (is_atx(X_OUTER_LEFT, model, x)) { for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) { if (is_aty(Y_LEFT_WIRED, model, y)) { tile = YX_TILE(model, y, x); tile->devices[tile->num_devices++].type = DEV_IOBM; tile->devices[tile->num_devices++].type = DEV_IOBS; } } } if (is_atx(X_OUTER_RIGHT, model, x)) { for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) { if (is_aty(Y_RIGHT_WIRED, model, y)) { tile = YX_TILE(model, y, x); tile->devices[tile->num_devices++].type = DEV_IOBM; tile->devices[tile->num_devices++].type = DEV_IOBS; } } } if (is_atx(X_FABRIC_LOGIC_ROUTING_COL|X_CENTER_ROUTING_COL, model, x) && !is_atx(X_ROUTING_NO_IO, model, x)) { tile = YX_TILE(model, TOP_OUTER_ROW, x); tile->devices[tile->num_devices++].type = DEV_IOBM; tile->devices[tile->num_devices++].type = DEV_IOBM; tile->devices[tile->num_devices++].type = DEV_IOBS; tile->devices[tile->num_devices++].type = DEV_IOBS; tile = YX_TILE(model, model->y_height-BOT_OUTER_ROW, x); tile->devices[tile->num_devices++].type = DEV_IOBM; tile->devices[tile->num_devices++].type = DEV_IOBM; tile->devices[tile->num_devices++].type = DEV_IOBS; tile->devices[tile->num_devices++].type = DEV_IOBS; } } // TIEOFF tile = YX_TILE(model, model->center_y, LEFT_OUTER_COL); tile->devices[tile->num_devices++].type = DEV_TIEOFF; tile = YX_TILE(model, model->center_y, model->x_width-RIGHT_OUTER_O); tile->devices[tile->num_devices++].type = DEV_TIEOFF; tile = YX_TILE(model, TOP_OUTER_ROW, model->center_x-1); tile->devices[tile->num_devices++].type = DEV_TIEOFF; tile = YX_TILE(model, model->y_height-BOT_OUTER_ROW, model->center_x-CMTPLL_FROM_CENTER_O); tile->devices[tile->num_devices++].type = DEV_TIEOFF; for (x = 0; x < model->x_width; x++) { if (is_atx(X_LEFT_IO_DEVS_COL, model, x)) { for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) { if (is_aty(Y_LEFT_WIRED, model, y)) { tile = YX_TILE(model, y, x); tile->devices[tile->num_devices++].type = DEV_TIEOFF; } } } if (is_atx(X_RIGHT_IO_DEVS_COL, model, x)) { for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) { if (is_aty(Y_RIGHT_WIRED, model, y)) { tile = YX_TILE(model, y, x); tile->devices[tile->num_devices++].type = DEV_TIEOFF; } } } if (is_atx(X_CENTER_CMTPLL_COL, model, x)) { for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) { tile = YX_TILE(model, y, x); if (tile->flags & TF_PLL_DEV) tile->devices[tile->num_devices++].type = DEV_TIEOFF; } } if (is_atx(X_ROUTING_COL, model, x)) { for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) { if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y)) continue; tile = YX_TILE(model, y, x); tile->devices[tile->num_devices++].type = DEV_TIEOFF; } } if (is_atx(X_LOGIC_COL, model, x) && !is_atx(X_ROUTING_NO_IO, model, x-1)) { for (i = 0; i <= 1; i++) { tile = YX_TILE(model, TOP_IO_TILES+i, x); tile->devices[tile->num_devices++].type = DEV_TIEOFF; tile = YX_TILE(model, model->y_height-BOT_IO_TILES-i-1, x); tile->devices[tile->num_devices++].type = DEV_TIEOFF; } } } // LOGIC for (x = 0; x < model->x_width; x++) { if (is_atx(X_LOGIC_COL, model, x)) { for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) { tile = YX_TILE(model, y, x); if (tile->flags & TF_LOGIC_XM_DEV) { tile->devices[tile->num_devices++].type = DEV_LOGIC_X; tile->devices[tile->num_devices++].type = DEV_LOGIC_M; } if (tile->flags & TF_LOGIC_XL_DEV) { tile->devices[tile->num_devices++].type = DEV_LOGIC_X; tile->devices[tile->num_devices++].type = DEV_LOGIC_L; } } } } return 0; } static int init_ports(struct fpga_model* model) { int x, y, i, j, k, row_num, row_pos, rc; for (x = 0; x < model->x_width; x++) { if (is_atx(X_ROUTING_COL, model, x)) { for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) { int keep_out = is_atx(X_ROUTING_NO_IO|X_LEFT_IO_ROUTING_COL|X_RIGHT_IO_ROUTING_COL, model, x) ? 0 : 2; if (y < TOP_IO_TILES+keep_out || y > model->y_height-BOT_IO_TILES-keep_out-1) continue; is_in_row(model, y, &row_num, &row_pos); if (row_pos < 0 || row_pos == 8) continue; if (is_atx(X_FABRIC_ROUTING_COL, model, x) || (is_atx(X_CENTER_ROUTING_COL, model, x) && (row_pos != 7 && (row_pos != 9 || row_num%2))) || (is_atx(X_LEFT_IO_ROUTING_COL, model, x) && !is_aty(Y_LEFT_WIRED, model, y)) || (is_atx(X_RIGHT_IO_ROUTING_COL, model, x) && !is_aty(Y_RIGHT_WIRED, model, y))) { for (i = 0; i <= 1; i++) { rc = add_connpt_name(model, y, x, pf("GFAN%i", i)); if (rc) goto xout; } } } } if (is_atx(X_ROUTING_COL, model, x)) { for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) { if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y)) continue; rc = add_connpt_name(model, y, x, "VCC_WIRE"); if (rc) goto xout; rc = add_connpt_name(model, y, x, "GND_WIRE"); if (rc) goto xout; rc = add_connpt_name(model, y, x, "KEEP1_WIRE"); if (rc) goto xout; rc = add_connpt_name(model, y, x, "FAN"); if (rc) goto xout; rc = add_connpt_name(model, y, x, "FAN_B"); if (rc) goto xout; } } if (is_atx(X_FABRIC_BRAM_COL, model, x)) { for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) { if (YX_TILE(model, y, x)->flags & TF_BRAM_DEV) { static const char* pass_str[3] = {"RAMB16BWER", "RAMB8BWER_0", "RAMB8BWER_1"}; // pass 0 is ramb16, pass 1 and 2 are for ramb8 for (i = 0; i <= 2; i++) { for (j = 'A'; j <= 'B'; j++) { rc = add_connpt_name(model, y, x, pf("%s_CLK%c", pass_str[i], j)); if (rc) goto xout; rc = add_connpt_name(model, y, x, pf("%s_EN%c", pass_str[i], j)); if (rc) goto xout; rc = add_connpt_name(model, y, x, pf("%s_REGCE%c", pass_str[i], j)); if (rc) goto xout; rc = add_connpt_name(model, y, x, pf("%s_RST%c", pass_str[i], j)); if (rc) goto xout; for (k = 0; k <= (!i ? 3 : 1); k++) { rc = add_connpt_name(model, y, x, pf("%s_DIP%c%i", pass_str[i], j, k)); if (rc) goto xout; rc = add_connpt_name(model, y, x, pf("%s_DOP%c%i", pass_str[i], j, k)); if (rc) goto xout; rc = add_connpt_name(model, y, x, pf("%s_WE%c%i", pass_str[i], j, k)); if (rc) goto xout; } for (k = 0; k <= (!i ? 13 : 12); k++) { rc = add_connpt_name(model, y, x, pf("%s_ADDR%c%i", pass_str[i], j, k)); if (rc) goto xout; } for (k = 0; k <= (!i ? 31 : 15); k++) { rc = add_connpt_name(model, y, x, pf("%s_DI%c%i", pass_str[i], j, k)); if (rc) goto xout; rc = add_connpt_name(model, y, x, pf("%s_DO%c%i", pass_str[i], j, k)); if (rc) goto xout; } } } } } } if (is_atx(X_FABRIC_MACC_COL, model, x)) { for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) { if (YX_TILE(model, y, x)->flags & TF_MACC_DEV) { static const char* pref[] = {"CE", "RST", ""}; static const char* seq[] = {"A", "B", "C", "D", "M", "P", "OPMODE", ""}; is_in_row(model, y, &row_num, &row_pos); if (!row_num && row_pos == LAST_POS_IN_ROW) { rc = add_connpt_name(model, y, x, "CARRYIN_DSP48A1_SITE"); if (rc) goto xout; for (i = 0; i <= 47; i++) { rc = add_connpt_name(model, y, x, pf("PCIN%i_DSP48A1_SITE", i)); if (rc) goto xout; } } rc = add_connpt_name(model, y, x, "CLK_DSP48A1_SITE"); if (rc) goto xout; rc = add_connpt_name(model, y, x, "CARRYOUT_DSP48A1_SITE"); if (rc) goto xout; rc = add_connpt_name(model, y, x, "CARRYOUTF_DSP48A1_SITE"); if (rc) goto xout; for (i = 0; pref[i][0]; i++) { rc = add_connpt_name(model, y, x, pf("%sCARRYIN_DSP48A1_SITE", pref[i])); if (rc) goto xout; for (j = 0; seq[j][0]; j++) { rc = add_connpt_name(model, y, x, pf("%s%s_DSP48A1_SITE", pref[i], seq[j])); if (rc) goto xout; } } for (i = 0; i <= 17; i++) { rc = add_connpt_name(model, y, x, pf("A%i_DSP48A1_SITE", i)); if (rc) goto xout; rc = add_connpt_name(model, y, x, pf("B%i_DSP48A1_SITE", i)); if (rc) goto xout; rc = add_connpt_name(model, y, x, pf("D%i_DSP48A1_SITE", i)); if (rc) goto xout; rc = add_connpt_name(model, y, x, pf("BCOUT%i_DSP48A1_SITE", i)); if (rc) goto xout; } for (i = 0; i <= 47; i++) { rc = add_connpt_name(model, y, x, pf("C%i_DSP48A1_SITE", i)); if (rc) goto xout; rc = add_connpt_name(model, y, x, pf("P%i_DSP48A1_SITE", i)); if (rc) goto xout; rc = add_connpt_name(model, y, x, pf("PCOUT%i_DSP48A1_SITE", i)); if (rc) goto xout; } for (i = 0; i <= 35; i++) { rc = add_connpt_name(model, y, x, pf("M%i_DSP48A1_SITE", i)); if (rc) goto xout; } for (i = 0; i <= 7; i++) { rc = add_connpt_name(model, y, x, pf("OPMODE%i_DSP48A1_SITE", i)); if (rc) goto xout; } } } } if (is_atx(X_LOGIC_COL, model, x)) { for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) { if (YX_TILE(model, y, x)->flags & (TF_LOGIC_XM_DEV|TF_LOGIC_XL_DEV)) { const char* pref[2]; if (YX_TILE(model, y, x)->flags & TF_LOGIC_XM_DEV) { pref[0] = "M"; pref[1] = "X"; rc = add_connpt_name(model, y, x, "M_COUT"); if (rc) goto xout; rc = add_connpt_name(model, y, x, "M_WE"); if (rc) goto xout; for (i = 'A'; i <= 'D'; i++) { rc = add_connpt_name(model, y, x, pf("M_%cI", i)); if (rc) goto xout; } } else { // LOGIC_XL pref[0] = "L"; pref[1] = "XX"; rc = add_connpt_name(model, y, x, "XL_COUT"); if (rc) goto xout; } for (k = 0; k <= 1; k++) { rc = add_connpt_name(model, y, x, pf("%s_CE", pref[k], i)); if (rc) goto xout; rc = add_connpt_name(model, y, x, pf("%s_SR", pref[k], i)); if (rc) goto xout; rc = add_connpt_name(model, y, x, pf("%s_CLK", pref[k], i)); if (rc) goto xout; for (i = 'A'; i <= 'D'; i++) { for (j = 1; j <= 6; j++) { rc = add_connpt_name(model, y, x, pf("%s_%c%i", pref[k], i, j)); if (rc) goto xout; } rc = add_connpt_name(model, y, x, pf("%s_%c", pref[k], i)); if (rc) goto xout; rc = add_connpt_name(model, y, x, pf("%s_%cMUX", pref[k], i)); if (rc) goto xout; rc = add_connpt_name(model, y, x, pf("%s_%cQ", pref[k], i)); if (rc) goto xout; rc = add_connpt_name(model, y, x, pf("%s_%cX", pref[k], i)); if (rc) goto xout; } } } } } } return 0; xout: return rc; } static int init_wires(struct fpga_model* model) { int rc; rc = run_logic_inout(model); if (rc) goto xout; rc = run_gclk(model); if (rc) goto xout; rc = run_direction_wires(model); if (rc) goto xout; return 0; xout: return rc; } static int run_gclk(struct fpga_model* model) { int x, i, rc, row, row_top_y, is_break, next_net_o; struct w_net gclk_net; for (row = model->cfg_rows-1; row >= 0; row--) { row_top_y = TOP_IO_TILES + (model->cfg_rows-1-row)*(8+1/* middle of row */+8); if (row < (model->cfg_rows/2)) row_top_y++; // center regs // net that connects the hclk of half the chip together horizontally gclk_net.last_inc = 15; next_net_o = 0; for (x = LEFT_IO_ROUTING;; x++) { if (next_net_o+2 > sizeof(gclk_net.pts) / sizeof(gclk_net.pts[0])) { fprintf(stderr, "Internal error in line %i\n", __LINE__); goto xout; } gclk_net.pts[next_net_o].start_count = 0; gclk_net.pts[next_net_o].x = x; gclk_net.pts[next_net_o].y = row_top_y+8; if (is_atx(X_LEFT_IO_ROUTING_COL|X_FABRIC_ROUTING_COL|X_CENTER_ROUTING_COL, model, x)) { gclk_net.pts[next_net_o++].name = "HCLK_GCLK%i_INT"; } else if (is_atx(X_LEFT_MCB, model, x)) { gclk_net.pts[next_net_o++].name = "HCLK_GCLK%i_MCB"; } else if (is_atx(X_LOGIC_COL|X_LEFT_IO_DEVS_COL, model, x)) { gclk_net.pts[next_net_o++].name = "HCLK_GCLK%i_CLB"; } else if (is_atx(X_FABRIC_BRAM_MACC_ROUTING_COL, model, x)) { gclk_net.pts[next_net_o++].name = "HCLK_GCLK%i_BRAM_INTER"; } else if (is_atx(X_FABRIC_BRAM_COL, model, x)) { gclk_net.pts[next_net_o++].name = "HCLK_GCLK%i_BRAM"; } else if (is_atx(X_FABRIC_MACC_COL, model, x)) { gclk_net.pts[next_net_o++].name = "HCLK_GCLK%i_DSP"; } else if (is_atx(X_CENTER_CMTPLL_COL, model, x)) { gclk_net.pts[next_net_o].y = row_top_y+7; gclk_net.pts[next_net_o++].name = "HCLK_CMT_GCLK%i_CLB"; } else if (is_atx(X_CENTER_REGS_COL, model, x)) { gclk_net.pts[next_net_o++].name = "CLKV_BUFH_LEFT_L%i"; // connect left half gclk_net.pts[next_net_o].name = ""; if ((rc = add_conn_net(model, NOPREF_BI_F, &gclk_net))) goto xout; // start right half gclk_net.pts[0].start_count = 0; gclk_net.pts[0].x = x; gclk_net.pts[0].y = row_top_y+8; gclk_net.pts[0].name = "CLKV_BUFH_RIGHT_R%i"; next_net_o = 1; } else if (is_atx(X_RIGHT_IO_ROUTING_COL, model, x)) { gclk_net.pts[next_net_o++].name = "HCLK_GCLK%i_INT"; // connect right half gclk_net.pts[next_net_o].name = ""; if ((rc = add_conn_net(model, NOPREF_BI_F, &gclk_net))) goto xout; break; } if (x >= model->x_width) { fprintf(stderr, "Internal error in line %i\n", __LINE__); goto xout; } } } for (x = 0; x < model->x_width; x++) { if (is_atx(X_ROUTING_COL, model, x)) { for (row = model->cfg_rows-1; row >= 0; row--) { row_top_y = 2 /* top IO */ + (model->cfg_rows-1-row)*(8+1/* middle of row */+8); if (row < (model->cfg_rows/2)) row_top_y++; // center regs is_break = 0; if (is_atx(X_LEFT_IO_ROUTING_COL|X_RIGHT_IO_ROUTING_COL, model, x)) { if (row && row != model->cfg_rows/2) is_break = 1; } else { if (row) is_break = 1; else if (is_atx(X_ROUTING_TO_BRAM_COL|X_ROUTING_TO_MACC_COL, model, x)) is_break = 1; } // vertical net inside row, pulling together 16 gclk // wires across top (8 tiles) and bottom (8 tiles) half // of the row. for (i = 0; i < 8; i++) { gclk_net.pts[i].name = "GCLK%i"; gclk_net.pts[i].start_count = 0; gclk_net.pts[i].y = row_top_y+i; gclk_net.pts[i].x = x; } gclk_net.last_inc = 15; gclk_net.pts[8].name = ""; if ((rc = add_conn_net(model, NOPREF_BI_F, &gclk_net))) goto xout; for (i = 0; i < 8; i++) gclk_net.pts[i].y += 9; if (is_break) gclk_net.pts[7].name = "GCLK%i_BRK"; if ((rc = add_conn_net(model, NOPREF_BI_F, &gclk_net))) goto xout; // vertically connects gclk of each row tile to // hclk tile at the middle of the row for (i = 0; i < 8; i++) { if ((rc = add_conn_range(model, NOPREF_BI_F, row_top_y+i, x, "GCLK%i", 0, 15, row_top_y+8, x, "HCLK_GCLK_UP%i", 0))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, row_top_y+9+i, x, (i == 7 && is_break) ? "GCLK%i_BRK" : "GCLK%i", 0, 15, row_top_y+8, x, "HCLK_GCLK%i", 0))) goto xout; } } } } rc = run_gclk_horiz_regs(model); if (rc) goto xout; rc = run_gclk_vert_regs(model); if (rc) goto xout; return 0; xout: return rc; } static int run_gclk_horiz_regs(struct fpga_model* model) { int x, i, rc, left_half; int gclk_sep_pos, start1, last1, start2; char* gclk_sep_str; // // Run a set of wire strings horizontally through the entire // chip from left to right over the center reg row. // The wires meet at the middle of each half of the chip on // the left and right side, as well as in the center. // // // 1. clk pll 0:1 // { struct seed_data clkpll_seeds[] = { { X_OUTER_LEFT, "REGL_CLKPLL%i" }, { X_INNER_LEFT, "REGL_LTERM_CLKPLL%i" }, { X_FABRIC_ROUTING_COL | X_LEFT_IO_ROUTING_COL | X_RIGHT_IO_ROUTING_COL, "INT_CLKPLL%i" }, { X_LEFT_IO_DEVS_COL | X_FABRIC_BRAM_MACC_ROUTING_COL | X_FABRIC_LOGIC_COL | X_RIGHT_IO_DEVS_COL, "CLE_CLKPLL%i" }, { X_FABRIC_MACC_COL, "DSP_CLKPLL%i" }, { X_CENTER_ROUTING_COL, "REGC_INT_CLKPLL_IO_RT%i" }, { X_CENTER_LOGIC_COL, "REGC_CLECLKPLL_IO_LT%i" }, { X_CENTER_REGS_COL, "CLKC_PLL_IO_RT%i" }, { X_INNER_RIGHT, "REGR_RTERM_CLKPLL%i" }, { X_OUTER_RIGHT, "REGR_CLKPLL%i" }, { 0 }}; left_half = 1; seed_strx(model, clkpll_seeds); for (x = 0; x < model->x_width; x++) { if (x == model->left_gclk_sep_x || x == model->right_gclk_sep_x) continue; if (is_atx(X_CENTER_CMTPLL_COL, model, x)) model->tmp_str[x] = left_half ? "REGC_CLKPLL_IO_LT%i" : "REGC_CLKPLL_IO_RT%i"; if (!model->tmp_str[x]) continue; if ((rc = add_conn_range(model, NOPREF_BI_F, model->center_y, x, model->tmp_str[x], 0, 1, model->center_y, left_half ? model->left_gclk_sep_x : model->right_gclk_sep_x, "INT_CLKPLL%i", 0))) goto xout; if (left_half && is_atx(X_CENTER_CMTPLL_COL, model, x)) { left_half = 0; x--; // wire up cmtpll col on right side as well } } } // // 2. clk pll lock 0:1 // { struct seed_data clkpll_lock_seeds[] = { { X_OUTER_LEFT, "REGL_LOCKED%i" }, { X_INNER_LEFT, "REGH_LTERM_LOCKED%i" }, { X_FABRIC_ROUTING_COL | X_LEFT_IO_ROUTING_COL | X_RIGHT_IO_ROUTING_COL, "INT_CLKPLL_LOCK%i" }, { X_LEFT_IO_DEVS_COL | X_FABRIC_BRAM_MACC_ROUTING_COL | X_FABRIC_LOGIC_COL | X_RIGHT_IO_DEVS_COL, "CLE_CLKPLL_LOCK%i" }, { X_FABRIC_MACC_COL, "DSP_CLKPLL_LOCK%i" }, { X_CENTER_ROUTING_COL, "REGC_INT_CLKPLL_LOCK_RT%i" }, { X_CENTER_LOGIC_COL, "REGC_CLECLKPLL_LOCK_LT%i" }, { X_CENTER_REGS_COL, "CLKC_PLL_LOCK_RT%i" }, { X_INNER_RIGHT, "REGH_RTERM_LOCKED%i" }, { X_OUTER_RIGHT, "REGR_LOCKED%i" }, { 0 }}; left_half = 1; seed_strx(model, clkpll_lock_seeds); for (x = 0; x < model->x_width; x++) { if (x == model->left_gclk_sep_x || x == model->right_gclk_sep_x) continue; if (is_atx(X_CENTER_CMTPLL_COL, model, x)) model->tmp_str[x] = left_half ? "CLK_PLL_LOCK_LT%i" : "CLK_PLL_LOCK_RT%i"; if (!model->tmp_str[x]) continue; if ((rc = add_conn_range(model, NOPREF_BI_F, model->center_y, x, model->tmp_str[x], 0, 1, model->center_y, left_half ? model->left_gclk_sep_x : model->right_gclk_sep_x, "INT_CLKPLL_LOCK%i", 0))) goto xout; if (left_half && is_atx(X_CENTER_CMTPLL_COL, model, x)) { left_half = 0; x--; // wire up cmtpll col on right side as well } } } // // 3. clk indirect 0:7 // 4. clk feedback 0:7 // { struct seed_data clk_indirect_seeds[] = { { X_OUTER_LEFT, "REGL_CLK_INDIRECT%i" }, { X_INNER_LEFT, "REGH_LTERM_CLKINDIRECT%i" }, { X_FABRIC_ROUTING_COL | X_LEFT_IO_ROUTING_COL | X_RIGHT_IO_ROUTING_COL, "REGH_CLKINDIRECT_LR%i_INT" }, { X_LEFT_IO_DEVS_COL | X_FABRIC_BRAM_MACC_ROUTING_COL | X_FABRIC_LOGIC_COL | X_RIGHT_IO_DEVS_COL, "REGH_CLKINDIRECT_LR%i_CLB" }, { X_FABRIC_MACC_COL, "REGH_CLKINDIRECT_LR%i_DSP" }, { X_CENTER_ROUTING_COL, "REGC_INT_CLKINDIRECT_LR%i_INT" }, { X_CENTER_LOGIC_COL, "REGC_CLECLKINDIRECT_LR%i_CLB" }, { X_CENTER_CMTPLL_COL, "REGC_CMT_CLKINDIRECT_LR%i" }, { X_CENTER_REGS_COL, "REGC_CLKINDIRECT_LR%i" }, { X_INNER_RIGHT, "REGH_RTERM_CLKINDIRECT%i" }, { X_OUTER_RIGHT, "REGR_CLK_INDIRECT%i" }, { 0 }}; struct seed_data clk_feedback_seeds[] = { { X_OUTER_LEFT, "REGL_CLK_FEEDBACK%i" }, { X_INNER_LEFT, "REGH_LTERM_CLKFEEDBACK%i" }, { X_FABRIC_ROUTING_COL | X_LEFT_IO_ROUTING_COL | X_RIGHT_IO_ROUTING_COL, "REGH_CLKFEEDBACK_LR%i_INT" }, { X_LEFT_IO_DEVS_COL | X_FABRIC_BRAM_MACC_ROUTING_COL | X_FABRIC_LOGIC_COL | X_RIGHT_IO_DEVS_COL, "REGH_CLKFEEDBACK_LR%i_CLB" }, { X_FABRIC_MACC_COL, "REGH_CLKFEEDBACK_LR%i_DSP" }, { X_CENTER_ROUTING_COL, "REGC_INT_CLKFEEDBACK_LR%i_INT" }, { X_CENTER_LOGIC_COL, "REGC_CLECLKFEEDBACK_LR%i_CLB" }, { X_CENTER_CMTPLL_COL, "REGC_CMT_CLKFEEDBACK_LR%i" }, { X_CENTER_REGS_COL, "REGC_CLKFEEDBACK_LR%i" }, { X_INNER_RIGHT, "REGH_RTERM_CLKFEEDBACK%i" }, { X_OUTER_RIGHT, "REGR_CLK_FEEDBACK%i" }, { 0 }}; struct seed_data* seeds[2] = {clk_indirect_seeds, clk_feedback_seeds}; const char* gclk_sep_str[2] = {"REGH_CLKINDIRECT_LR%i_INT", "REGH_CLKFEEDBACK_LR%i_INT"}; for (i = 0; i <= 1; i++) { // indirect and feedback left_half = 1; seed_strx(model, seeds[i]); for (x = 0; x < model->x_width; x++) { if (x == model->left_gclk_sep_x || x == model->right_gclk_sep_x) continue; if (!model->tmp_str[x]) continue; if (is_atx(X_CENTER_LOGIC_COL, model, x)) { start1 = 8; last1 = 15; start2 = 0; } else if (is_atx(X_CENTER_CMTPLL_COL, model, x)) { if (left_half) { start1 = 8; last1 = 15; start2 = 0; } else { start1 = 0; last1 = 3; start2 = 4; } } else if (is_atx(X_CENTER_REGS_COL|X_INNER_RIGHT|X_OUTER_RIGHT, model, x)) { start1 = 0; last1 = 3; start2 = 4; } else { start1 = 0; last1 = 7; start2 = 0; } if ((rc = add_conn_range(model, NOPREF_BI_F, model->center_y, x, model->tmp_str[x], start1, last1, model->center_y, left_half ? model->left_gclk_sep_x : model->right_gclk_sep_x, gclk_sep_str[i], start2))) goto xout; if (last1 == 3) { if (start1 || start2 != 4) { fprintf(stderr, "Internal error in line %i.\n", __LINE__); goto xout; } if ((rc = add_conn_range(model, NOPREF_BI_F, model->center_y, x, model->tmp_str[x], 4, 7, model->center_y, left_half ? model->left_gclk_sep_x : model->right_gclk_sep_x, gclk_sep_str[i], 0))) goto xout; } if (left_half && is_atx(X_CENTER_CMTPLL_COL, model, x)) { left_half = 0; x--; // wire up cmtpll col on right side as well } } } } // // 5. ckpin 0:7 // { struct seed_data ckpin_seeds[] = { { X_OUTER_LEFT, "REGL_CKPIN%i" }, { X_INNER_LEFT, "REGH_LTERM_CKPIN%i" }, { X_FABRIC_ROUTING_COL | X_LEFT_IO_ROUTING_COL | X_RIGHT_IO_ROUTING_COL, "REGH_CKPIN%i_INT" }, { X_LEFT_IO_DEVS_COL | X_FABRIC_BRAM_MACC_ROUTING_COL | X_FABRIC_LOGIC_COL | X_RIGHT_IO_DEVS_COL, "REGH_CKPIN%i_CLB" }, { X_FABRIC_MACC_COL, "REGH_CKPIN%i_DSP" }, { X_CENTER_ROUTING_COL, "REGC_INT_CKPIN%i_INT" }, { X_CENTER_LOGIC_COL, "REGC_CLECKPIN%i_CLB" }, { X_CENTER_CMTPLL_COL, "REGC_CMT_CKPIN%i" }, { X_CENTER_REGS_COL, "CLKC_CKLR%i" }, { X_INNER_RIGHT, "REGH_RTERM_CKPIN%i" }, { X_OUTER_RIGHT, "REGR_CKPIN%i" }, { 0 }}; left_half = 1; seed_strx(model, ckpin_seeds); for (x = 0; x < model->x_width; x++) { if (x == model->left_gclk_sep_x || x == model->right_gclk_sep_x) continue; if (!model->tmp_str[x]) continue; if (is_atx(X_CENTER_ROUTING_COL|X_CENTER_LOGIC_COL|X_CENTER_CMTPLL_COL, model, x)) start1 = 8; else if (is_atx(X_CENTER_REGS_COL, model, x)) start1 = left_half ? 8 : 0; else start1 = 0; gclk_sep_pos = left_half ? model->left_gclk_sep_x : model->right_gclk_sep_x; gclk_sep_str = ((x > gclk_sep_pos) ^ left_half) ? "REGH_DSP_IN_CKPIN%i" : "REGH_DSP_OUT_CKPIN%i"; if ((rc = add_conn_range(model, NOPREF_BI_F, model->center_y, x, model->tmp_str[x], start1, start1+7, model->center_y, gclk_sep_pos, gclk_sep_str, 0))) goto xout; // In this loop we tie around the CENTER_REGS_COL, not the // CENTER_CMTPLL_COL as before. if (left_half && is_atx(X_CENTER_REGS_COL, model, x)) { left_half = 0; x--; // wire up center regs col on right side as well } } } // some local nets around the center on the left side { struct w_net net = { 3, {{ "REGL_GCLK%i", 0, model->center_y, LEFT_OUTER_COL }, { "REGH_LTERM_GCLK%i", 0, model->center_y, LEFT_INNER_COL }, { "REGH_IOI_INT_GCLK%i", 0, model->center_y, LEFT_IO_ROUTING }, { "" }}}; if ((rc = add_conn_net(model, NOPREF_BI_F, &net))) goto xout; } { const char* str[3] = {"REGL_GCLK%i", "REGH_LTERM_GCLK%i", "REGH_IOI_INT_GCLK%i"}; if ((rc = add_conn_range(model, NOPREF_BI_F, model->center_y-2, LEFT_IO_ROUTING, "INT_BUFPLL_GCLK%i", 2, 3, model->center_y-1, LEFT_IO_ROUTING, "INT_BUFPLL_GCLK%i_EXT", 2))) goto xout; for (x = LEFT_OUTER_COL; x <= LEFT_IO_ROUTING; x++) { if ((rc = add_conn_range(model, NOPREF_BI_F, model->center_y-1, LEFT_IO_ROUTING, "INT_BUFPLL_GCLK%i", 0, 1, model->center_y, x, str[x], 0))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, model->center_y-1, LEFT_IO_ROUTING, "INT_BUFPLL_GCLK%i_EXT", 2, 3, model->center_y, x, str[x], 2))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, model->center_y-2, LEFT_IO_ROUTING, "INT_BUFPLL_GCLK%i", 2, 3, model->center_y, x, str[x], 2))) goto xout; } } // and right side { struct w_net net = { 3, {{ "REGH_RIOI_GCLK%i", 0, model->center_y, model->x_width-RIGHT_IO_DEVS_O }, { "MCB_REGH_GCLK%i", 0, model->center_y, model->x_width-RIGHT_MCB_O }, { "REGR_GCLK%i", 0, model->center_y, model->x_width-RIGHT_OUTER_O }, { "" }}}; if ((rc = add_conn_net(model, NOPREF_BI_F, &net))) goto xout; } { const char* str[5] = {"REGH_IOI_INT_GCLK%i", "REGH_RIOI_GCLK%i", "MCB_REGH_GCLK%i", "REGR_RTERM_GCLK%i", "REGR_GCLK%i"}; if ((rc = add_conn_range(model, NOPREF_BI_F, model->center_y-2, model->x_width-RIGHT_IO_ROUTING_O, "INT_BUFPLL_GCLK%i", 2, 3, model->center_y-1, model->x_width-RIGHT_IO_ROUTING_O, "INT_BUFPLL_GCLK%i_EXT", 2))) goto xout; for (x = model->x_width-RIGHT_IO_ROUTING_O; x <= model->x_width-RIGHT_OUTER_O; x++) { if ((rc = add_conn_range(model, NOPREF_BI_F, model->center_y-1, model->x_width-RIGHT_IO_ROUTING_O, "INT_BUFPLL_GCLK%i_EXT", 2, 3, model->center_y, x, str[x-(model->x_width-RIGHT_IO_ROUTING_O)], 2))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, model->center_y-2, model->x_width-RIGHT_IO_ROUTING_O, "INT_BUFPLL_GCLK%i", 2, 3, model->center_y, x, str[x-(model->x_width-RIGHT_IO_ROUTING_O)], 2))) goto xout; } } { struct w_net net = { 1, {{ "INT_BUFPLL_GCLK%i", 0, model->center_y-1, model->x_width-RIGHT_IO_ROUTING_O }, { "REGH_RIOI_INT_GCLK%i", 0, model->center_y, model->x_width-RIGHT_IO_ROUTING_O }, { "REGH_RIOI_GCLK%i", 0, model->center_y, model->x_width-RIGHT_IO_DEVS_O }, { "REGH_RTERM_GCLK%i", 0, model->center_y, model->x_width-RIGHT_INNER_O }, { "" }}}; if ((rc = add_conn_net(model, NOPREF_BI_F, &net))) goto xout; } { struct w_net net = { 1, {{ "REGH_IOI_INT_GCLK%i", 2, model->center_y, model->x_width-RIGHT_IO_ROUTING_O }, { "REGH_RIOI_GCLK%i", 2, model->center_y, model->x_width-RIGHT_IO_DEVS_O }, { "REGR_RTERM_GCLK%i", 2, model->center_y, model->x_width-RIGHT_INNER_O }, { "" }}}; if ((rc = add_conn_net(model, NOPREF_BI_F, &net))) goto xout; } // the naming is a little messed up here, and the networks are // actually simpler than represented here (with full 0:3 connections). // But until we have better representation of wire networks, this has // to suffice. if ((rc = add_conn_range(model, NOPREF_BI_F, model->center_y, model->x_width-RIGHT_OUTER_O, "REGR_GCLK%i", 0, 1, model->center_y-1, model->x_width-RIGHT_IO_ROUTING_O, "INT_BUFPLL_GCLK%i", 0))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, model->center_y, model->x_width-RIGHT_OUTER_O, "REGR_GCLK%i", 0, 1, model->center_y, model->x_width-RIGHT_IO_ROUTING_O, "REGH_RIOI_INT_GCLK%i", 0))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, model->center_y, model->x_width-RIGHT_OUTER_O, "REGR_GCLK%i", 2, 3, model->center_y, model->x_width-RIGHT_IO_ROUTING_O, "REGH_IOI_INT_GCLK%i", 2))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, model->center_y, model->x_width-RIGHT_OUTER_O, "REGR_GCLK%i", 0, 1, model->center_y, model->x_width-RIGHT_INNER_O, "REGH_RTERM_GCLK%i", 0))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, model->center_y, model->x_width-RIGHT_OUTER_O, "REGR_GCLK%i", 2, 3, model->center_y, model->x_width-RIGHT_INNER_O, "REGR_RTERM_GCLK%i", 2))) goto xout; // same from MCB_REGH_GCLK... if ((rc = add_conn_range(model, NOPREF_BI_F, model->center_y, model->x_width-RIGHT_MCB_O, "MCB_REGH_GCLK%i", 0, 1, model->center_y-1, model->x_width-RIGHT_IO_ROUTING_O, "INT_BUFPLL_GCLK%i", 0))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, model->center_y, model->x_width-RIGHT_MCB_O, "MCB_REGH_GCLK%i", 0, 1, model->center_y, model->x_width-RIGHT_IO_ROUTING_O, "REGH_RIOI_INT_GCLK%i", 0))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, model->center_y, model->x_width-RIGHT_MCB_O, "MCB_REGH_GCLK%i", 2, 3, model->center_y, model->x_width-RIGHT_IO_ROUTING_O, "REGH_IOI_INT_GCLK%i", 2))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, model->center_y, model->x_width-RIGHT_MCB_O, "MCB_REGH_GCLK%i", 0, 1, model->center_y, model->x_width-RIGHT_INNER_O, "REGH_RTERM_GCLK%i", 0))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, model->center_y, model->x_width-RIGHT_MCB_O, "MCB_REGH_GCLK%i", 2, 3, model->center_y, model->x_width-RIGHT_INNER_O, "REGR_RTERM_GCLK%i", 2))) goto xout; return 0; xout: return rc; } static int run_gclk_vert_regs(struct fpga_model* model) { struct w_net net; int rc, i; // net tying together 15 gclk lines from row 10..27 net.last_inc = 15; for (i = 0; i <= 17; i++) { if (is_aty(Y_ROW_HORIZ_AXSYMM, model, i+10)) net.pts[i].name = "CLKV_GCLKH_MAIN%i_FOLD"; else if (i == 9) // row 19 net.pts[i].name = "CLKV_GCLK_MAIN%i_BUF"; else net.pts[i].name = "CLKV_GCLK_MAIN%i_FOLD"; net.pts[i].start_count = 0; net.pts[i].y = i+10; net.pts[i].x = model->center_x; } net.pts[i].name = ""; if ((rc = add_conn_net(model, NOPREF_BI_F, &net))) goto xout; // net tying together 15 gclk lines from row 19..53 net.last_inc = 15; for (i = 0; i <= 34; i++) { // row 19..53 if (is_aty(Y_ROW_HORIZ_AXSYMM, model, i+19)) net.pts[i].name = "REGV_GCLKH_MAIN%i"; else if (is_aty(Y_CHIP_HORIZ_REGS, model, i+19)) net.pts[i].name = "CLKC_GCLK_MAIN%i"; else if (i == 16) // row 35 net.pts[i].name = "CLKV_GCLK_MAIN%i_BRK"; else net.pts[i].name = "CLKV_GCLK_MAIN%i"; net.pts[i].start_count = 0; net.pts[i].y = i+19; net.pts[i].x = model->center_x; } net.pts[i].name = ""; if ((rc = add_conn_net(model, NOPREF_BI_F, &net))) goto xout; // net tying together 15 gclk lines from row 45..62 net.last_inc = 15; for (i = 0; i <= 17; i++) { if (is_aty(Y_ROW_HORIZ_AXSYMM, model, i+45)) net.pts[i].name = "CLKV_GCLKH_MAIN%i_FOLD"; else if (i == 8) // row 53 net.pts[i].name = "CLKV_GCLK_MAIN%i_BUF"; else net.pts[i].name = "CLKV_GCLK_MAIN%i_FOLD"; net.pts[i].start_count = 0; net.pts[i].y = i+45; net.pts[i].x = model->center_x; } net.pts[i].name = ""; if ((rc = add_conn_net(model, NOPREF_BI_F, &net))) goto xout; // a few local gclk networks at the center top and bottom { struct w_net net = { 1, {{ "REGT_GCLK%i", 0, TOP_OUTER_ROW, model->center_x-1 }, { "REGT_TTERM_GCLK%i", 0, TOP_INNER_ROW, model->center_x-1 }, { "REGV_TTERM_GCLK%i", 0, TOP_INNER_ROW, model->center_x }, { "BUFPLL_TOP_GCLK%i", 0, TOP_INNER_ROW, model->center_x+1 }, { "" }}}; if ((rc = add_conn_net(model, NOPREF_BI_F, &net))) goto xout; } { struct w_net net = { 1, {{ "REGB_GCLK%i", 0, model->y_height-1, model->center_x-1 }, { "REGB_BTERM_GCLK%i", 0, model->y_height-2, model->center_x-1 }, { "REGV_BTERM_GCLK%i", 0, model->y_height-2, model->center_x }, { "BUFPLL_BOT_GCLK%i", 0, model->y_height-2, model->center_x+1 }, { "" }}}; if ((rc = add_conn_net(model, NOPREF_BI_F, &net))) goto xout; } // wire up gclk from tterm down to top 8 rows at center_x+1 for (i = TOP_IO_TILES; i <= TOP_IO_TILES+HALF_ROW; i++) { if ((rc = add_conn_range(model, NOPREF_BI_F, TOP_INNER_ROW, model->center_x+1, "IOI_TTERM_GCLK%i", 0, 15, i, model->center_x+1, (i == TOP_IO_TILES+HALF_ROW) ? "HCLK_GCLK_UP%i" : "GCLK%i", 0))) goto xout; } // same at the bottom upwards for (i = model->y_height-2-1; i >= model->y_height-2-HALF_ROW-1; i--) { if ((rc = add_conn_range(model, NOPREF_BI_F, model->y_height-2, model->center_x+1, "IOI_BTERM_GCLK%i", 0, 15, i, model->center_x+1, (i == model->y_height-2-HALF_ROW-1) ? "HCLK_GCLK%i" : "GCLK%i", 0))) goto xout; } return 0; xout: return rc; } static int run_logic_inout(struct fpga_model* model) { struct fpga_tile* tile; char buf[128]; int x, y, i, rc; // LOGICOUT for (x = 0; x < model->x_width; x++) { if (is_atx(X_FABRIC_LOGIC_ROUTING_COL|X_CENTER_ROUTING_COL, model, x)) { for (y = 0; y < model->y_height; y++) { tile = &model->tiles[y * model->x_width + x]; if (tile[1].flags & TF_LOGIC_XM_DEV) { if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICOUT%i", 0, 23, y, x+1, "CLEXM_LOGICOUT%i", 0))) goto xout; } if (tile[1].flags & TF_LOGIC_XL_DEV) { if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICOUT%i", 0, 23, y, x+1, "CLEXL_LOGICOUT%i", 0))) goto xout; } if (tile[1].flags & TF_IOLOGIC_DELAY_DEV) { if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICOUT%i", 0, 23, y, x+1, "IOI_LOGICOUT%i", 0))) goto xout; } } } if (is_atx(X_FABRIC_BRAM_ROUTING_COL|X_FABRIC_MACC_ROUTING_COL, model, x)) { for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) { if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y)) continue; if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICOUT%i", 0, 23, y, x+1, "INT_INTERFACE_LOGICOUT%i", 0))) goto xout; if (YX_TILE(model, y, x)[2].flags & TF_BRAM_DEV) { if ((rc = add_conn_range(model, NOPREF_BI_F, y-3, x+1, "INT_INTERFACE_LOGICOUT_%i", 0, 23, y, x+2, "BRAM_LOGICOUT%i_INT3", 0))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, y-2, x+1, "INT_INTERFACE_LOGICOUT_%i", 0, 23, y, x+2, "BRAM_LOGICOUT%i_INT2", 0))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, y-1, x+1, "INT_INTERFACE_LOGICOUT_%i", 0, 23, y, x+2, "BRAM_LOGICOUT%i_INT1", 0))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, y, x+1, "INT_INTERFACE_LOGICOUT_%i", 0, 23, y, x+2, "BRAM_LOGICOUT%i_INT0", 0))) goto xout; } if (YX_TILE(model, y, x)[2].flags & TF_MACC_DEV) { if ((rc = add_conn_range(model, NOPREF_BI_F, y-3, x+1, "INT_INTERFACE_LOGICOUT_%i", 0, 23, y, x+2, "MACC_LOGICOUT%i_INT3", 0))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, y-2, x+1, "INT_INTERFACE_LOGICOUT_%i", 0, 23, y, x+2, "MACC_LOGICOUT%i_INT2", 0))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, y-1, x+1, "INT_INTERFACE_LOGICOUT_%i", 0, 23, y, x+2, "MACC_LOGICOUT%i_INT1", 0))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, y, x+1, "INT_INTERFACE_LOGICOUT_%i", 0, 23, y, x+2, "MACC_LOGICOUT%i_INT0", 0))) goto xout; } } } if (is_atx(X_CENTER_ROUTING_COL, model, x)) { for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) { if (is_aty(Y_ROW_HORIZ_AXSYMM, model, y)) { if ((rc = add_conn_range(model, NOPREF_BI_F, y-1, x, "LOGICOUT%i", 0, 23, y-1, x+1, "INT_INTERFACE_LOGICOUT%i", 0))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, y+1, x, "LOGICOUT%i", 0, 23, y+1, x+1, "INT_INTERFACE_LOGICOUT%i", 0))) goto xout; if (YX_TILE(model, y-1, x+2)->flags & TF_DCM_DEV) { if ((rc = add_conn_range(model, NOPREF_BI_F, y-1, x+1, "INT_INTERFACE_LOGICOUT_%i", 0, 23, y-1, x+2, "DCM_CLB2_LOGICOUT%i", 0))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, y+1, x+1, "INT_INTERFACE_LOGICOUT_%i", 0, 23, y-1, x+2, "DCM_CLB1_LOGICOUT%i", 0))) goto xout; } else if (YX_TILE(model, y-1, x+2)->flags & TF_PLL_DEV) { if ((rc = add_conn_range(model, NOPREF_BI_F, y-1, x+1, "INT_INTERFACE_LOGICOUT_%i", 0, 23, y-1, x+2, "PLL_CLB2_LOGICOUT%i", 0))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, y+1, x+1, "INT_INTERFACE_LOGICOUT_%i", 0, 23, y-1, x+2, "PLL_CLB1_LOGICOUT%i", 0))) goto xout; } } if (is_aty(Y_CHIP_HORIZ_REGS, model, y)) { if ((rc = add_conn_range(model, NOPREF_BI_F, y-1, x, "LOGICOUT%i", 0, 23, y-1, x+1, "INT_INTERFACE_REGC_LOGICOUT%i", 0))) goto xout; } } } if (is_atx(X_LEFT_IO_ROUTING_COL|X_RIGHT_IO_ROUTING_COL, model, x)) { int wired_side, local_size; if (is_atx(X_LEFT_IO_ROUTING_COL, model, x)) { local_size = 1; wired_side = Y_LEFT_WIRED; } else { local_size = 2; wired_side = Y_RIGHT_WIRED; } for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) { if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y)) continue; if (y < TOP_IO_TILES+local_size || y > model->y_height-BOT_IO_TILES-local_size-1) { if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICOUT%i", 0, 23, y, x+1, "INT_INTERFACE_LOCAL_LOGICOUT%i", 0))) goto xout; } else if (is_aty(wired_side, model, y)) { if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICOUT%i", 0, 23, y, x+1, "IOI_LOGICOUT%i", 0))) goto xout; } else { if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICOUT%i", 0, 23, y, x+1, "INT_INTERFACE_LOGICOUT%i", 0))) goto xout; } } } } for (y = 0; y < model->y_height; y++) { for (x = 0; x < model->x_width; x++) { tile = &model->tiles[y * model->x_width + x]; // LOGICIN if (is_atyx(YX_ROUTING_TILE, model, y, x)) { static const int north_p[4] = {21, 28, 52, 60}; static const int south_p[4] = {20, 36, 44, 62}; for (i = 0; i < sizeof(north_p)/sizeof(north_p[0]); i++) { if (is_aty(Y_INNER_TOP, model, y-1)) { if ((rc = add_conn_bi_pref(model, y, x, pf("LOGICIN%i", north_p[i]), y-1, x, pf("LOGICIN%i", north_p[i])))) goto xout; } else { if ((rc = add_conn_bi_pref(model, y, x, pf("LOGICIN%i", north_p[i]), y-1, x, pf("LOGICIN_N%i", north_p[i])))) goto xout; } if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y-1)) { if ((rc = add_conn_bi_pref(model, y, x, pf("LOGICIN%i", north_p[i]), y-2, x, pf("LOGICIN_N%i", north_p[i])))) goto xout; if ((rc = add_conn_bi_pref(model, y-1, x, pf("LOGICIN_N%i", north_p[i]), y-2, x, pf("LOGICIN_N%i", north_p[i])))) goto xout; } if (is_aty(Y_INNER_BOTTOM, model, y+1) && !is_atx(X_ROUTING_TO_BRAM_COL, model, x)) { if ((rc = add_conn_bi_pref(model, y, x, pf("LOGICIN_N%i", north_p[i]), y+1, x, pf("LOGICIN_N%i", north_p[i])))) goto xout; } } for (i = 0; i < sizeof(south_p)/sizeof(south_p[0]); i++) { if (is_aty(Y_INNER_TOP, model, y-1)) { if ((rc = add_conn_bi_pref(model, y, x, pf("LOGICIN_S%i", south_p[i]), y-1, x, pf("LOGICIN_S%i", south_p[i])))) goto xout; } if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y+1)) { if ((rc = add_conn_bi_pref(model, y, x, pf("LOGICIN%i", south_p[i]), y+1, x, pf("LOGICIN%i", south_p[i])))) goto xout; if ((rc = add_conn_bi_pref(model, y, x, pf("LOGICIN%i", south_p[i]), y+2, x, pf("LOGICIN_S%i", south_p[i])))) goto xout; if ((rc = add_conn_bi_pref(model, y+1, x, pf("LOGICIN%i", south_p[i]), y+2, x, pf("LOGICIN_S%i", south_p[i])))) goto xout; } else if (is_aty(Y_INNER_BOTTOM, model, y+1)) { if (!is_atx(X_ROUTING_TO_BRAM_COL, model, x)) if ((rc = add_conn_bi_pref(model, y, x, pf("LOGICIN%i", south_p[i]), y+1, x, pf("LOGICIN%i", south_p[i])))) goto xout; } else { if ((rc = add_conn_bi_pref(model, y, x, pf("LOGICIN%i", south_p[i]), y+1, x, pf("LOGICIN_S%i", south_p[i])))) goto xout; } } if (tile[1].flags & TF_LOGIC_XM_DEV) { if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICIN_B%i", 0, 62, y, x+1, "CLEXM_LOGICIN_B%i", 0))) goto xout; } if (tile[1].flags & TF_LOGIC_XL_DEV) { if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICIN_B%i", 0, 35, y, x+1, "CLEXL_LOGICIN_B%i", 0))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICIN_B%i", 37, 43, y, x+1, "CLEXL_LOGICIN_B%i", 37))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICIN_B%i", 45, 52, y, x+1, "CLEXL_LOGICIN_B%i", 45))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICIN_B%i", 54, 60, y, x+1, "CLEXL_LOGICIN_B%i", 54))) goto xout; } if (tile[1].flags & TF_IOLOGIC_DELAY_DEV) { if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICIN_B%i", 0, 3, y, x+1, "IOI_LOGICINB%i", 0))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICIN_B%i", 5, 9, y, x+1, "IOI_LOGICINB%i", 5))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICIN_B%i", 11, 62, y, x+1, "IOI_LOGICINB%i", 11))) goto xout; } if (is_atx(X_ROUTING_TO_BRAM_COL, model, x)) { if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICIN_B%i", 0, 62, y, x+1, "INT_INTERFACE_LOGICBIN%i", 0))) goto xout; if (tile[2].flags & TF_BRAM_DEV) { for (i = 0; i < 4; i++) { sprintf(buf, "BRAM_LOGICINB%%i_INT%i", 3-i); if ((rc = add_conn_range(model, NOPREF_BI_F, y-(3-i), x, "LOGICIN_B%i", 0, 62, y, x+2, buf, 0))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, y-(3-i), x+1, "INT_INTERFACE_LOGICBIN%i", 0, 62, y, x+2, buf, 0))) goto xout; } } } if (is_atx(X_ROUTING_TO_MACC_COL, model, x)) { if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICIN_B%i", 0, 62, y, x+1, "INT_INTERFACE_LOGICBIN%i", 0))) goto xout; if (tile[2].flags & TF_MACC_DEV) { for (i = 0; i < 4; i++) { sprintf(buf, "MACC_LOGICINB%%i_INT%i", 3-i); if ((rc = add_conn_range(model, NOPREF_BI_F, y-(3-i), x, "LOGICIN_B%i", 0, 62, y, x+2, buf, 0))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, y-(3-i), x+1, "INT_INTERFACE_LOGICBIN%i", 0, 62, y, x+2, buf, 0))) goto xout; } } } if (is_atx(X_CENTER_REGS_COL, model, x+3)) { if (tile[2].flags & (TF_PLL_DEV|TF_DCM_DEV)) { const char* prefix = (tile[2].flags & TF_PLL_DEV) ? "PLL_CLB2" : "DCM_CLB2"; for (i = 0;; i = 2) { if ((rc = add_conn_range(model, NOPREF_BI_F, y+i, x, "LOGICIN_B%i", 0, 3, y+i, x+1, "INT_INTERFACE_LOGICBIN%i", 0))) goto xout; if ((rc = add_conn_bi(model, y+i, x, "INT_IOI_LOGICIN_B4", y+i, x+1, "INT_INTERFACE_IOI_LOGICBIN4"))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, y+i, x, "LOGICIN_B%i", 5, 9, y+i, x+1, "INT_INTERFACE_LOGICBIN%i", 5))) goto xout; if ((rc = add_conn_bi(model, y+i, x, "INT_IOI_LOGICIN_B10", y+i, x+1, "INT_INTERFACE_IOI_LOGICBIN10"))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, y+i, x, "LOGICIN_B%i", 11, 62, y+i, x+1, "INT_INTERFACE_LOGICBIN%i", 11))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, y+i, x, "LOGICIN_B%i", 0, 3, y, x+2, pf("%s_LOGICINB%%i", prefix), 0))) goto xout; if ((rc = add_conn_bi(model, y+i, x, "INT_IOI_LOGICIN_B4", y, x+2, pf("%s_LOGICINB4", prefix)))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, y+i, x, "LOGICIN_B%i", 5, 9, y, x+2, pf("%s_LOGICINB%%i", prefix), 5))) goto xout; if ((rc = add_conn_bi(model, y+i, x, "INT_IOI_LOGICIN_B10", y, x+2, pf("%s_LOGICINB10", prefix)))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, y+i, x, "LOGICIN_B%i", 11, 62, y, x+2, pf("%s_LOGICINB%%i", prefix), 11))) goto xout; if (tile[2].flags & TF_PLL_DEV) { if ((rc = add_conn_range(model, NOPREF_BI_F, y+2, x, "LOGICIN_B%i", 0, 62, y+2, x+1, "INT_INTERFACE_LOGICBIN%i", 0))) goto xout; if ((rc = add_conn_range(model, NOPREF_BI_F, y+2, x, "LOGICIN_B%i", 0, 62, y, x+2, "PLL_CLB1_LOGICINB%i", 0))) goto xout; break; } if (i == 2) break; prefix = "DCM_CLB1"; } } if (is_aty(Y_CHIP_HORIZ_REGS, model, y+1)) { if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICIN_B%i", 0, 62, y, x+1, "INT_INTERFACE_REGC_LOGICBIN%i", 0))) goto xout; int clk_pins[16] = { 24, 15, 7, 42, 5, 12, 62, 16, 47, 20, 38, 23, 48, 57, 44, 4 }; for (i = 0; i <= 15; i++) { if ((rc = add_conn_bi(model, y, x, pf("LOGICIN_B%i", clk_pins[i]), y+1, x+1, pf("REGC_CLE_SEL%i", i)))) goto xout; if ((rc = add_conn_bi(model, y, x, pf("LOGICIN_B%i", clk_pins[i]), y+1, x+2, pf("REGC_CMT_SEL%i", i)))) goto xout; if ((rc = add_conn_bi(model, y, x, pf("LOGICIN_B%i", clk_pins[i]), y+1, x+3, pf("CLKC_SEL%i_PLL", i)))) goto xout; } } } } } } return 0; xout: return rc; } static int run_direction_wires(struct fpga_model* model) { int x, y, rc; for (y = 0; y < model->y_height; y++) { for (x = 0; x < model->x_width; x++) { // NR1 if (is_atyx(YX_ROUTING_TILE, model, y, x)) { if (is_aty(Y_INNER_TOP, model, y-1)) { { struct w_net net = { 3, {{ "NR1B%i", 0, y, x }, { "NR1B%i", 0, y-1, x }, { "" }}}; if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; } } else if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y-1)) { { struct w_net net = { 3, {{ "NR1B%i", 0, y, x }, { "NR1E%i", 0, y-1, x }, { "NR1E%i", 0, y-2, x }, { "" }}}; if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; } } else { { struct w_net net = { 3, {{ "NR1B%i", 0, y, x }, { "NR1E%i", 0, y-1, x }, { "" }}}; if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; } if (is_aty(Y_INNER_BOTTOM, model, y+1) && !is_atx(X_ROUTING_TO_BRAM_COL, model, x)) { { struct w_net net = { 3, {{ "NR1E%i", 0, y, x }, { "NR1E%i", 0, y+1, x }, { "" }}}; if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; } } } } // NN2 if (is_atyx(YX_ROUTING_TILE, model, y, x)) { if (is_aty(Y_INNER_TOP, model, y-1)) { { struct w_net net = { 3, {{ "NN2B%i", 0, y, x }, { "NN2B%i", 0, y-1, x }, { "" }}}; if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; } { struct w_net net = { 0, {{ "NN2E_S0", 0, y, x }, { "NN2E_S0", 0, y-1, x }, { "" }}}; if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; } } else if (is_aty(Y_INNER_TOP, model, y-2)) { { struct w_net net = { 3, {{ "NN2B%i", 0, y, x }, { "NN2M%i", 0, y-1, x }, { "NN2M%i", 0, y-2, x }, { "" }}}; if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; } } else if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y-1)) { { struct w_net net = { 3, {{ "NN2B%i", 0, y, x }, { "NN2M%i", 0, y-1, x }, { "NN2M%i", 0, y-2, x }, { "NN2E%i", 0, y-3, x }, { "" }}}; if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; } if ((rc = add_conn_bi_pref(model, y-1, x, "NN2M0", y-2, x, "NN2E_S0"))) goto xout; if ((rc = add_conn_bi_pref(model, y-3, x, "NN2E0", y-2, x, "NN2E_S0"))) goto xout; if ((rc = add_conn_bi_pref(model, y, x, "NN2B0", y-2, x, "NN2E_S0"))) goto xout; } else if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y-2)) { { struct w_net net = { 3, {{ "NN2B%i", 0, y, x }, { "NN2M%i", 0, y-1, x }, { "NN2E%i", 0, y-2, x }, { "NN2E%i", 0, y-3, x }, { "" }}}; if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; } if ((rc = add_conn_bi_pref(model, y, x, "NN2B0", y-1, x, "NN2E_S0"))) goto xout; if ((rc = add_conn_bi_pref(model, y, x, "NN2B0", y-2, x, "NN2E_S0"))) goto xout; if ((rc = add_conn_bi_pref(model, y-2, x, "NN2E0", y-1, x, "NN2E_S0"))) goto xout; if ((rc = add_conn_bi_pref(model, y-2, x, "NN2E_S0", y-1, x, "NN2M0"))) goto xout; if ((rc = add_conn_bi_pref(model, y-2, x, "NN2E_S0", y-1, x, "NN2E_S0"))) goto xout; if ((rc = add_conn_bi_pref(model, y-2, x, "NN2E_S0", y-3, x, "NN2E0"))) goto xout; if ((rc = add_conn_bi_pref(model, y-3, x, "NN2E0", y-1, x, "NN2E_S0"))) goto xout; } else { { struct w_net net = { 3, {{ "NN2B%i", 0, y, x }, { "NN2M%i", 0, y-1, x }, { "NN2E%i", 0, y-2, x }, { "" }}}; if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; } if ((rc = add_conn_bi(model, y, x, "NN2B0", y-1, x, "NN2E_S0"))) goto xout; if ((rc = add_conn_bi(model, y-2, x, "NN2E0", y-1, x, "NN2E_S0"))) goto xout; if (is_aty(Y_INNER_BOTTOM, model, y+1)) { if ((rc = add_conn_bi(model, y, x, "NN2E_S0", y-1, x, "NN2E0"))) goto xout; if (!is_atx(X_ROUTING_TO_BRAM_COL, model, x)) { { struct w_net net = { 3, {{ "NN2E%i", 0, y-1, x }, { "NN2M%i", 0, y, x }, { "NN2M%i", 0, y+1, x }, { "" }}}; if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; } if ((rc = add_conn_range(model, PREF_BI_F, y, x, "NN2E%i", 0, 3, y+1, x, "NN2E%i", 0))) goto xout; if ((rc = add_conn_bi(model, y, x, "NN2E0", y+1, x, "IOI_BTERM_NN2E_S0"))) goto xout; if ((rc = add_conn_bi(model, y, x, "NN2E_S0", y+1, x, "IOI_BTERM_NN2M0"))) goto xout; } } } } // SS2 if (is_atyx(YX_ROUTING_TILE, model, y, x)) { if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y+2)) { { struct w_net net = { 3, {{ "SS2B%i", 0, y, x }, { "SS2M%i", 0, y+1, x }, { "SS2M%i", 0, y+2, x }, { "SS2E%i", 0, y+3, x }, { "" }}}; if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; } if ((rc = add_conn_bi_pref(model, y, x, "SS2B3", y+1, x, "SS2E_N3"))) goto xout; if ((rc = add_conn_bi_pref(model, y+1, x, "SS2E_N3", y+2, x, "SS2E_N3"))) goto xout; if ((rc = add_conn_bi_pref(model, y, x, "SS2B3", y+2, x, "SS2E_N3"))) goto xout; if ((rc = add_conn_bi_pref(model, y+2, x, "SS2E_N3", y+3, x, "SS2E3"))) goto xout; if ((rc = add_conn_bi_pref(model, y+1, x, "SS2E_N3", y+2, x, "SS2M3"))) goto xout; if ((rc = add_conn_bi_pref(model, y+1, x, "SS2E_N3", y+3, x, "SS2E3"))) goto xout; if ((rc = add_conn_bi_pref(model, y+1, x, "SS2M3", y+2, x, "SS2E_N3"))) goto xout; if ((rc = add_conn_bi_pref(model, y+2, x, "SS2B3", y+3, x, "SS2E_N3"))) goto xout; } else if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y+1)) { { struct w_net net = { 3, {{ "SS2B%i", 0, y, x }, { "SS2B%i", 0, y+1, x }, { "SS2M%i", 0, y+2, x }, { "SS2E%i", 0, y+3, x }, { "" }}}; if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; } if ((rc = add_conn_bi_pref(model, y, x, "SS2B3", y+2, x, "SS2E_N3"))) goto xout; if ((rc = add_conn_bi_pref(model, y+2, x, "SS2E_N3", y+3, x, "SS2E3"))) goto xout; } else if (is_aty(Y_INNER_BOTTOM, model, y+2)) { if (!is_atx(X_ROUTING_TO_BRAM_COL, model, x)) { { struct w_net net = { 3, {{ "SS2B%i", 0, y, x }, { "SS2M%i", 0, y+1, x }, { "SS2M%i", 0, y+2, x }, { "" }}}; if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; } } } else if (is_aty(Y_INNER_BOTTOM, model, y+1)) { if (!is_atx(X_ROUTING_TO_BRAM_COL, model, x)) { if ((rc = add_conn_range(model, PREF_BI_F, y, x, "SS2B%i", 0, 3, y+1, x, "SS2B%i", 0))) goto xout; if ((rc = add_conn_bi_pref(model, y, x, "SS2E_N3", y+1, x, "SS2E_N3"))) goto xout; } } else { if (is_aty(Y_INNER_TOP, model, y-1)) { { struct w_net net = { 3, {{ "SS2M%i", 0, y-1, x }, { "SS2M%i", 0, y, x }, { "SS2E%i", 0, y+1, x }, { "" }}}; if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; } if ((rc = add_conn_range(model, PREF_BI_F, y, x, "SS2E%i", 0, 3, y-1, x, "SS2E%i", 0))) goto xout; if ((rc = add_conn_bi_pref(model, y, x, "SS2E3", y-1, x, "SS2E_N3"))) goto xout; if ((rc = add_conn_bi_pref(model, y, x, "SS2E_N3", y-1, x, "SS2M3"))) goto xout; if ((rc = add_conn_bi_pref(model, y, x, "SS2E_N3", y+1, x, "SS2E3"))) goto xout; } { struct w_net net = { 3, {{ "SS2B%i", 0, y, x }, { "SS2M%i", 0, y+1, x }, { "SS2E%i", 0, y+2, x }, { "" }}}; if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; } if ((rc = add_conn_bi_pref(model, y, x, "SS2B3", y+1, x, "SS2E_N3"))) goto xout; if ((rc = add_conn_bi_pref(model, y+1, x, "SS2E_N3", y+2, x, "SS2E3"))) goto xout; } } } } return 0; xout: return rc; } static int init_tiles(struct fpga_model* model) { int tile_rows, tile_columns, i, j, k, l, row_top_y, left_side; int start, end, no_io; char cur_cfgcol, last_col; struct fpga_tile* tile_i0; tile_rows = 1 /* middle */ + (8+1+8)*model->cfg_rows + 2+2 /* two extra tiles at top and bottom */; tile_columns = 5 /* left */ + 5 /* right */; for (i = 0; model->cfg_columns[i] != 0; i++) { if (model->cfg_columns[i] == 'L' || model->cfg_columns[i] == 'M') tile_columns += 2; // 2 for logic blocks L/M else if (model->cfg_columns[i] == 'B' || model->cfg_columns[i] == 'D') tile_columns += 3; // 3 for bram or macc else if (model->cfg_columns[i] == 'R') tile_columns += 2+2; // 2+2 for middle IO+logic+PLL/DCM } model->tmp_str = malloc((tile_columns > tile_rows ? tile_columns : tile_rows) * sizeof(*model->tmp_str)); if (!model->tmp_str) { fprintf(stderr, "%i: Out of memory.\n", __LINE__); return -1; } model->x_width = tile_columns; model->y_height = tile_rows; model->center_x = -1; model->tiles = calloc(tile_columns * tile_rows, sizeof(struct fpga_tile)); if (!model->tiles) { fprintf(stderr, "%i: Out of memory.\n", __LINE__); return -1; } for (i = 0; i < tile_rows * tile_columns; i++) model->tiles[i].type = NA; if (!(tile_rows % 2)) fprintf(stderr, "Unexpected even number of tile rows (%i).\n", tile_rows); model->center_y = 2 /* top IO files */ + (model->cfg_rows/2)*(8+1/*middle of row clock*/+8); // // top, bottom, center: // go through columns from left to right, rows from top to bottom // left_side = 1; // turn off (=right side) when reaching the 'R' middle column i = 5; // skip left IO columns for (j = 0; model->cfg_columns[j]; j++) { cur_cfgcol = model->cfg_columns[j]; switch (cur_cfgcol) { case 'L': case 'l': case 'M': case 'm': no_io = (next_non_whitespace(&model->cfg_columns[j+1]) == 'n'); last_col = last_major(model->cfg_columns, j); model->tiles[i].flags |= TF_FABRIC_ROUTING_COL; if (no_io) model->tiles[i].flags |= TF_ROUTING_NO_IO; model->tiles[i+1].flags |= TF_FABRIC_LOGIC_COL; for (k = model->cfg_rows-1; k >= 0; k--) { row_top_y = 2 /* top IO tiles */ + (model->cfg_rows-1-k)*(8+1/*middle of row clock*/+8); if (k<(model->cfg_rows/2)) row_top_y++; // middle system tiles (center row) start = ((k == model->cfg_rows-1 && !no_io) ? 2 : 0); end = ((k == 0 && !no_io) ? 14 : 16); for (l = start; l < end; l++) { tile_i0 = &model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i]; if (l < 15 || (!k && no_io)) tile_i0->type = ROUTING; else tile_i0->type = ROUTING_BRK; if (cur_cfgcol == 'L') { tile_i0[1].flags |= TF_LOGIC_XL_DEV; tile_i0[1].type = LOGIC_XL; } else { tile_i0[1].flags |= TF_LOGIC_XM_DEV; tile_i0[1].type = LOGIC_XM; } } if (cur_cfgcol == 'L') { model->tiles[(row_top_y+8)*tile_columns + i].type = HCLK_ROUTING_XL; model->tiles[(row_top_y+8)*tile_columns + i + 1].type = HCLK_LOGIC_XL; } else { model->tiles[(row_top_y+8)*tile_columns + i].type = HCLK_ROUTING_XM; model->tiles[(row_top_y+8)*tile_columns + i + 1].type = HCLK_LOGIC_XM; } } if (last_col == 'R') { model->tiles[tile_columns + i].type = IO_BUFPLL_TERM_T; model->tiles[(tile_rows-2)*tile_columns + i].type = IO_BUFPLL_TERM_B; } else { model->tiles[tile_columns + i].type = IO_TERM_T; if (!no_io) model->tiles[(tile_rows-2)*tile_columns + i].type = IO_TERM_B; else model->tiles[(tile_rows-2)*tile_columns + i].type = LOGIC_ROUTING_TERM_B; } if (!no_io) { model->tiles[i].type = IO_T; model->tiles[(tile_rows-1)*tile_columns + i].type = IO_B; model->tiles[2*tile_columns + i].type = IO_ROUTING; model->tiles[3*tile_columns + i].type = IO_ROUTING; model->tiles[(tile_rows-4)*tile_columns + i].type = IO_ROUTING; model->tiles[(tile_rows-3)*tile_columns + i].type = IO_ROUTING; } if (last_col == 'R') { model->tiles[tile_columns + i + 1].type = IO_LOGIC_REG_TERM_T; model->tiles[(tile_rows-2)*tile_columns + i + 1].type = IO_LOGIC_REG_TERM_B; } else { model->tiles[tile_columns + i + 1].type = IO_LOGIC_TERM_T; if (!no_io) model->tiles[(tile_rows-2)*tile_columns + i + 1].type = IO_LOGIC_TERM_B; else model->tiles[(tile_rows-2)*tile_columns + i + 1].type = LOGIC_NOIO_TERM_B; } if (!no_io) { model->tiles[2*tile_columns + i + 1].type = IO_OUTER_T; model->tiles[2*tile_columns + i + 1].flags |= TF_IOLOGIC_DELAY_DEV; model->tiles[3*tile_columns + i + 1].type = IO_INNER_T; model->tiles[3*tile_columns + i + 1].flags |= TF_IOLOGIC_DELAY_DEV; model->tiles[(tile_rows-4)*tile_columns + i + 1].type = IO_INNER_B; model->tiles[(tile_rows-4)*tile_columns + i + 1].flags |= TF_IOLOGIC_DELAY_DEV; model->tiles[(tile_rows-3)*tile_columns + i + 1].type = IO_OUTER_B; model->tiles[(tile_rows-3)*tile_columns + i + 1].flags |= TF_IOLOGIC_DELAY_DEV; } if (cur_cfgcol == 'L') { model->tiles[model->center_y*tile_columns + i].type = REGH_ROUTING_XL; model->tiles[model->center_y*tile_columns + i + 1].type = REGH_LOGIC_XL; } else { model->tiles[model->center_y*tile_columns + i].type = REGH_ROUTING_XM; model->tiles[model->center_y*tile_columns + i + 1].type = REGH_LOGIC_XM; } i += 2; break; case 'B': if (next_non_whitespace(&model->cfg_columns[j+1]) == 'g') { if (left_side) model->left_gclk_sep_x = i+2; else model->right_gclk_sep_x = i+2; } model->tiles[i].flags |= TF_FABRIC_ROUTING_COL; model->tiles[i].flags |= TF_ROUTING_NO_IO; // no_io always on for BRAM model->tiles[i+1].flags |= TF_FABRIC_BRAM_MACC_ROUTING_COL; model->tiles[i+2].flags |= TF_FABRIC_BRAM_COL; for (k = model->cfg_rows-1; k >= 0; k--) { row_top_y = 2 /* top IO tiles */ + (model->cfg_rows-1-k)*(8+1/*middle of row clock*/+8); if (k<(model->cfg_rows/2)) row_top_y++; // middle system tiles for (l = 0; l < 16; l++) { tile_i0 = &model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i]; if (l < 15) tile_i0->type = BRAM_ROUTING; else tile_i0->type = BRAM_ROUTING_BRK; model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i + 1].type = ROUTING_VIA; if (!(l%4)) { model->tiles[(row_top_y+3+(l<8?l:l+1))*tile_columns + i + 2].type = BRAM; model->tiles[(row_top_y+3+(l<8?l:l+1))*tile_columns + i + 2].flags |= TF_BRAM_DEV; } } model->tiles[(row_top_y+8)*tile_columns + i].type = HCLK_BRAM_ROUTING; model->tiles[(row_top_y+8)*tile_columns + i + 1].type = HCLK_BRAM_ROUTING_VIA; model->tiles[(row_top_y+8)*tile_columns + i + 2].type = HCLK_BRAM; } model->tiles[tile_columns + i].type = BRAM_ROUTING_TERM_T; model->tiles[(tile_rows-2)*tile_columns + i].type = BRAM_ROUTING_TERM_B; model->tiles[tile_columns + i + 1].type = BRAM_ROUTING_VIA_TERM_T; model->tiles[(tile_rows-2)*tile_columns + i + 1].type = BRAM_ROUTING_VIA_TERM_B; model->tiles[tile_columns + i + 2].type = left_side ? BRAM_TERM_LT : BRAM_TERM_RT; model->tiles[(tile_rows-2)*tile_columns + i + 2].type = left_side ? BRAM_TERM_LB : BRAM_TERM_RB; model->tiles[model->center_y*tile_columns + i].type = REGH_BRAM_ROUTING; model->tiles[model->center_y*tile_columns + i + 1].type = REGH_BRAM_ROUTING_VIA; model->tiles[model->center_y*tile_columns + i + 2].type = left_side ? REGH_BRAM_L : REGH_BRAM_R; i += 3; break; case 'D': model->tiles[i].flags |= TF_FABRIC_ROUTING_COL; model->tiles[i].flags |= TF_ROUTING_NO_IO; // no_io always on for MACC model->tiles[i+1].flags |= TF_FABRIC_BRAM_MACC_ROUTING_COL; model->tiles[i+2].flags |= TF_FABRIC_MACC_COL; for (k = model->cfg_rows-1; k >= 0; k--) { row_top_y = 2 /* top IO tiles */ + (model->cfg_rows-1-k)*(8+1/*middle of row clock*/+8); if (k<(model->cfg_rows/2)) row_top_y++; // middle system tiles for (l = 0; l < 16; l++) { tile_i0 = &model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i]; if (l < 15) tile_i0->type = ROUTING; else tile_i0->type = ROUTING_BRK; tile_i0[1].type = ROUTING_VIA; if (!(l%4)) { model->tiles[(row_top_y+3+(l<8?l:l+1))*tile_columns + i + 2].type = MACC; model->tiles[(row_top_y+3+(l<8?l:l+1))*tile_columns + i + 2].flags |= TF_MACC_DEV; } } model->tiles[(row_top_y+8)*tile_columns + i].type = HCLK_MACC_ROUTING; model->tiles[(row_top_y+8)*tile_columns + i + 1].type = HCLK_MACC_ROUTING_VIA; model->tiles[(row_top_y+8)*tile_columns + i + 2].type = HCLK_MACC; } model->tiles[tile_columns + i].type = MACC_ROUTING_TERM_T; model->tiles[(tile_rows-2)*tile_columns + i].type = MACC_ROUTING_TERM_B; model->tiles[tile_columns + i + 1].type = MACC_VIA_TERM_T; model->tiles[(tile_rows-2)*tile_columns + i + 1].type = IO_LOGIC_TERM_B; model->tiles[tile_columns + i + 2].type = left_side ? MACC_TERM_TL : MACC_TERM_TR; model->tiles[(tile_rows-2)*tile_columns + i + 2].type = left_side ? MACC_TERM_BL : MACC_TERM_BR; model->tiles[model->center_y*tile_columns + i].type = REGH_MACC_ROUTING; model->tiles[model->center_y*tile_columns + i + 1].type = REGH_MACC_ROUTING_VIA; model->tiles[model->center_y*tile_columns + i + 2].type = REGH_MACC_L; i += 3; break; case 'R': if (next_non_whitespace(&model->cfg_columns[j+1]) != 'M') { // We expect a LOGIC_XM column to follow the center for // the top and bottom bufpll and reg routing. fprintf(stderr, "Expecting LOGIC_XM after center but found '%c'\n", model->cfg_columns[j+1]); } model->center_x = i+3; left_side = 0; for (k = model->cfg_rows-1; k >= 0; k--) { row_top_y = 2 /* top IO tiles */ + (model->cfg_rows-1-k)*(8+1/*middle of row clock*/+8); if (k<(model->cfg_rows/2)) row_top_y++; // middle system tiles for (l = 0; l < 16; l++) { tile_i0 = &model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i]; if ((k < model->cfg_rows-1 || l >= 2) && (k || l<14)) { if (l < 15) tile_i0->type = ROUTING; else tile_i0->type = ROUTING_BRK; if (l == 7) tile_i0[1].type = ROUTING_VIA_IO; else if (l == 8) tile_i0[1].type = (k%2) ? ROUTING_VIA_CARRY : ROUTING_VIA_IO_DCM; else if (l == 15 && k==model->cfg_rows/2) tile_i0[1].type = ROUTING_VIA_REGC; else { tile_i0[1].type = LOGIC_XL; tile_i0[1].flags |= TF_LOGIC_XL_DEV; } } if (l == 7 || (l == 8 && !(k%2))) { // even row, together with DCM tile_i0->type = IO_ROUTING; } if (l == 7) { if (k%2) { // odd model->tiles[(row_top_y+l)*tile_columns + i + 2].flags |= TF_PLL_DEV; model->tiles[(row_top_y+l)*tile_columns + i + 2].type = (k<(model->cfg_rows/2)) ? PLL_B : PLL_T; } else { // even model->tiles[(row_top_y+l)*tile_columns + i + 2].flags |= TF_DCM_DEV; model->tiles[(row_top_y+l)*tile_columns + i + 2].type = (k<(model->cfg_rows/2)) ? DCM_B : DCM_T; } } // four midbuf tiles, in the middle of the top and bottom halves if (l == 15) { if (k == model->cfg_rows*3/4) model->tiles[(row_top_y+l+1)*tile_columns + i + 3].type = REGV_MIDBUF_T; else if (k == model->cfg_rows/4) model->tiles[(row_top_y+l+1)*tile_columns + i + 3].type = REGV_HCLKBUF_B; else model->tiles[(row_top_y+l+1)*tile_columns + i + 3].type = REGV_BRK; } else if (l == 0 && k == model->cfg_rows*3/4-1) { model->tiles[(row_top_y+l)*tile_columns + i + 3].type = REGV_HCLKBUF_T; } else if (l == 0 && k == model->cfg_rows/4-1) { model->tiles[(row_top_y+l)*tile_columns + i + 3].type = REGV_MIDBUF_B; } else if (l == 8) { model->tiles[(row_top_y+l+1)*tile_columns + i + 3].type = (kcfg_rows/2) ? REGV_B : REGV_T; } else model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i + 3].type = REGV; } model->tiles[(row_top_y+8)*tile_columns + i].type = HCLK_ROUTING_XL; model->tiles[(row_top_y+8)*tile_columns + i + 1].type = HCLK_LOGIC_XL; model->tiles[(row_top_y+8)*tile_columns + i + 3].type = HCLK_REGV; } model->tiles[i].type = IO_T; model->tiles[(tile_rows-1)*tile_columns + i].type = IO_B; model->tiles[tile_columns + i].type = IO_TERM_T; model->tiles[(tile_rows-2)*tile_columns + i].type = IO_TERM_B; model->tiles[2*tile_columns + i].type = IO_ROUTING; model->tiles[3*tile_columns + i].type = IO_ROUTING; model->tiles[(tile_rows-4)*tile_columns + i].type = IO_ROUTING; model->tiles[(tile_rows-3)*tile_columns + i].type = IO_ROUTING; model->tiles[tile_columns + i + 1].type = IO_LOGIC_REG_TERM_T; model->tiles[(tile_rows-2)*tile_columns + i + 1].type = IO_LOGIC_REG_TERM_B; model->tiles[2*tile_columns + i + 1].type = IO_OUTER_T; model->tiles[2*tile_columns + i + 1].flags |= TF_IOLOGIC_DELAY_DEV; model->tiles[3*tile_columns + i + 1].type = IO_INNER_T; model->tiles[3*tile_columns + i + 1].flags |= TF_IOLOGIC_DELAY_DEV; model->tiles[(tile_rows-4)*tile_columns + i + 1].type = IO_INNER_B; model->tiles[(tile_rows-4)*tile_columns + i + 1].flags |= TF_IOLOGIC_DELAY_DEV; model->tiles[(tile_rows-3)*tile_columns + i + 1].type = IO_OUTER_B; model->tiles[(tile_rows-3)*tile_columns + i + 1].flags |= TF_IOLOGIC_DELAY_DEV; model->tiles[i + 2].type = REG_T; model->tiles[tile_columns + i + 2].type = REG_TERM_T; model->tiles[(tile_rows-2)*tile_columns + i + 2].type = REG_TERM_B; model->tiles[(tile_rows-1)*tile_columns + i + 2].type = REG_B; model->tiles[tile_columns + i + 3].type = REGV_TERM_T; model->tiles[(tile_rows-2)*tile_columns + i + 3].type = REGV_TERM_B; model->tiles[model->center_y*tile_columns + i].type = REGC_ROUTING; model->tiles[model->center_y*tile_columns + i + 1].type = REGC_LOGIC; model->tiles[model->center_y*tile_columns + i + 2].type = REGC_CMT; model->tiles[model->center_y*tile_columns + i + 3].type = CENTER; i += 4; break; case ' ': // space used to make string more readable only case 'g': // global clock separator case 'n': // noio for logic blocks break; default: fprintf(stderr, "Ignoring unexpected column identifier '%c'\n", cur_cfgcol); break; } } // // left IO // for (k = model->cfg_rows-1; k >= 0; k--) { row_top_y = 2 /* top IO tiles */ + (model->cfg_rows-1-k)*(8+1/*middle of row clock*/+8); if (k<(model->cfg_rows/2)) row_top_y++; // middle system tiles for (l = 0; l < 16; l++) { // // +0 // if (model->cfg_left_wiring[(model->cfg_rows-1-k)*16+l] == 'W') { model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns].flags |= TF_WIRED; model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns].type = IO_L; } // // +1 // if ((k == model->cfg_rows-1 && !l) || (!k && l==15)) model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 1].type = CORNER_TERM_L; else if (k == model->cfg_rows/2 && l == 12) model->tiles[(row_top_y+l+1)*tile_columns + 1].type = IO_TERM_L_UPPER_TOP; else if (k == model->cfg_rows/2 && l == 13) model->tiles[(row_top_y+l+1)*tile_columns + 1].type = IO_TERM_L_UPPER_BOT; else if (k == (model->cfg_rows/2)-1 && !l) model->tiles[(row_top_y+l)*tile_columns + 1].type = IO_TERM_L_LOWER_TOP; else if (k == (model->cfg_rows/2)-1 && l == 1) model->tiles[(row_top_y+l)*tile_columns + 1].type = IO_TERM_L_LOWER_BOT; else model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 1].type = IO_TERM_L; // // +2 // if (model->cfg_left_wiring[(model->cfg_rows-1-k)*16+l] == 'W') { if (l == 15 && k && k != model->cfg_rows/2) model->tiles[(row_top_y+l+1)*tile_columns + 2].type = ROUTING_IO_L_BRK; else model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 2].type = ROUTING_IO_L; } else { // unwired if (k && k != model->cfg_rows/2 && l == 15) model->tiles[(row_top_y+l+1)*tile_columns + 2].type = ROUTING_BRK; else if (k == model->cfg_rows/2 && l == 14) model->tiles[(row_top_y+l+1)*tile_columns + 2].type = ROUTING_GCLK; else model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 2].type = ROUTING; } // // +3 // if (model->cfg_left_wiring[(model->cfg_rows-1-k)*16+l] == 'W') { model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 3].type = ROUTING_IO_VIA_L; } else { // unwired if (k == model->cfg_rows-1 && !l) { model->tiles[(row_top_y+l)*tile_columns + 3].type = CORNER_TL; } else if (!k && l == 15) { model->tiles[(row_top_y+l+1)*tile_columns + 3].type = CORNER_BL; } else { if (k && k != model->cfg_rows/2 && l == 15) model->tiles[(row_top_y+l+1)*tile_columns + 3].type = ROUTING_VIA_CARRY; else model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 3].type = ROUTING_VIA; } } } model->tiles[(row_top_y+8)*tile_columns + 1].type = HCLK_TERM_L; model->tiles[(row_top_y+8)*tile_columns + 2].type = HCLK_ROUTING_IO_L; if (k >= model->cfg_rows/2) { // top half if (k > (model->cfg_rows*3)/4) model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_TOP_UP_L; else if (k == (model->cfg_rows*3)/4) model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_TOP_SPLIT_L; else model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_TOP_DN_L; } else { // bottom half if (k < model->cfg_rows/4 - 1) model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_BOT_DN_L; else if (k == model->cfg_rows/4 - 1) model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_BOT_SPLIT_L; else model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_BOT_UP_L; } model->tiles[(row_top_y+8)*tile_columns + 4].type = HCLK_MCB; } model->tiles[(model->center_y-3)*tile_columns].type = IO_PCI_L; model->tiles[(model->center_y-2)*tile_columns].type = IO_PCI_CONN_L; model->tiles[(model->center_y-1)*tile_columns].type = IO_PCI_CONN_L; model->tiles[model->center_y*tile_columns].type = REG_L; model->tiles[(model->center_y+1)*tile_columns].type = IO_RDY_L; model->tiles[model->center_y*tile_columns + 1].type = REGH_IO_TERM_L; model->tiles[tile_columns + 2].type = CORNER_TERM_T; model->tiles[(tile_rows-2)*tile_columns + 2].type = CORNER_TERM_B; model->tiles[model->center_y*tile_columns + 2].type = REGH_ROUTING_IO_L; model->tiles[tile_columns + 3].type = ROUTING_IO_PCI_CE_L; model->tiles[(tile_rows-2)*tile_columns + 3].type = ROUTING_IO_PCI_CE_L; model->tiles[model->center_y*tile_columns + 3].type = REGH_IO_L; model->tiles[model->center_y*tile_columns + 4].type = REGH_MCB; // // right IO // for (k = model->cfg_rows-1; k >= 0; k--) { row_top_y = 2 /* top IO tiles */ + (model->cfg_rows-1-k)*(8+1/*middle of row clock*/+8); if (k<(model->cfg_rows/2)) row_top_y++; // middle system tiles for (l = 0; l < 16; l++) { // // -1 // if (model->cfg_right_wiring[(model->cfg_rows-1-k)*16+l] == 'W') model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 1].flags |= TF_WIRED; if (k == model->cfg_rows/2 && l == 13) model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 1].type = IO_RDY_R; else if (k == model->cfg_rows/2 && l == 14) model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 1].type = IO_PCI_CONN_R; else if (k == model->cfg_rows/2 && l == 15) model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 1].type = IO_PCI_CONN_R; else if (k == model->cfg_rows/2-1 && !l) model->tiles[(row_top_y+l)*tile_columns + tile_columns - 1].type = IO_PCI_R; else { if (model->cfg_right_wiring[(model->cfg_rows-1-k)*16+l] == 'W') model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 1].type = IO_R; } // // -2 // if ((k == model->cfg_rows-1 && (!l || l == 1)) || (!k && (l==15 || l==14))) model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 2].type = CORNER_TERM_R; else if (k == model->cfg_rows/2 && l == 12) model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 2].type = IO_TERM_R_UPPER_TOP; else if (k == model->cfg_rows/2 && l == 13) model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 2].type = IO_TERM_R_UPPER_BOT; else if (k == (model->cfg_rows/2)-1 && !l) model->tiles[(row_top_y+l)*tile_columns + tile_columns - 2].type = IO_TERM_R_LOWER_TOP; else if (k == (model->cfg_rows/2)-1 && l == 1) model->tiles[(row_top_y+l)*tile_columns + tile_columns - 2].type = IO_TERM_R_LOWER_BOT; else model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 2].type = IO_TERM_R; // // -3 // // // -4 // if (model->cfg_right_wiring[(model->cfg_rows-1-k)*16+l] == 'W') model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 4].type = ROUTING_IO_VIA_R; else { if (k == model->cfg_rows-1 && l == 0) model->tiles[(row_top_y+l)*tile_columns + tile_columns - 4].type = CORNER_TR_UPPER; else if (k == model->cfg_rows-1 && l == 1) model->tiles[(row_top_y+l)*tile_columns + tile_columns - 4].type = CORNER_TR_LOWER; else if (k && k != model->cfg_rows/2 && l == 15) model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 4].type = ROUTING_VIA_CARRY; else if (!k && l == 14) model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 4].type = CORNER_BR_UPPER; else if (!k && l == 15) model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 4].type = CORNER_BR_LOWER; else model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 4].type = ROUTING_VIA; } // // -5 // if (model->cfg_right_wiring[(model->cfg_rows-1-k)*16+l] == 'W') model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 5].type = IO_ROUTING; else { if (k && k != model->cfg_rows/2 && l == 15) model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 5].type = ROUTING_BRK; else if (k == model->cfg_rows/2 && l == 14) model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 5].type = ROUTING_GCLK; else model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 5].type = ROUTING; } } model->tiles[(row_top_y+8)*tile_columns + tile_columns - 2].type = HCLK_TERM_R; model->tiles[(row_top_y+8)*tile_columns + tile_columns - 3].type = HCLK_MCB; model->tiles[(row_top_y+8)*tile_columns + tile_columns - 5].type = HCLK_ROUTING_IO_R; if (k >= model->cfg_rows/2) { // top half if (k > (model->cfg_rows*3)/4) model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_TOP_UP_R; else if (k == (model->cfg_rows*3)/4) model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_TOP_SPLIT_R; else model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_TOP_DN_R; } else { // bottom half if (k < model->cfg_rows/4 - 1) model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_BOT_DN_R; else if (k == model->cfg_rows/4 - 1) model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_BOT_SPLIT_R; else model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_BOT_UP_R; } } model->tiles[tile_columns + tile_columns - 5].type = CORNER_TERM_T; model->tiles[(tile_rows-2)*tile_columns + tile_columns - 5].type = CORNER_TERM_B; model->tiles[tile_columns + tile_columns - 4].type = ROUTING_IO_PCI_CE_R; model->tiles[(tile_rows-2)*tile_columns + tile_columns - 4].type = ROUTING_IO_PCI_CE_R; model->tiles[model->center_y*tile_columns + tile_columns - 1].type = REG_R; model->tiles[model->center_y*tile_columns + tile_columns - 2].type = REGH_IO_TERM_R; model->tiles[model->center_y*tile_columns + tile_columns - 3].type = REGH_MCB; model->tiles[model->center_y*tile_columns + tile_columns - 4].type = REGH_IO_R; model->tiles[model->center_y*tile_columns + tile_columns - 5].type = REGH_ROUTING_IO_R; return 0; } // // helper funcs // static const char* pf(const char* fmt, ...) { // safe to call it 8 times in 1 expression (such as function params) static char pf_buf[8][128]; static int last_buf = 0; va_list list; last_buf = (last_buf+1)%8; pf_buf[last_buf][0] = 0; va_start(list, fmt); vsnprintf(pf_buf[last_buf], sizeof(pf_buf[0]), fmt, list); va_end(list); return pf_buf[last_buf]; } static const char* wpref(struct fpga_model* model, int y, int x, const char* wire_name) { static char buf[8][128]; static int last_buf = 0; char* prefix; if (is_aty(Y_CHIP_HORIZ_REGS, model, y)) { prefix = is_atx(X_CENTER_REGS_COL, model, x+3) ? "REGC_INT_" : "REGH_"; } else if (is_aty(Y_ROW_HORIZ_AXSYMM, model, y)) prefix = "HCLK_"; else if (is_aty(Y_INNER_TOP, model, y)) prefix = "IOI_TTERM_"; else if (is_aty(Y_INNER_BOTTOM, model, y)) prefix = "IOI_BTERM_"; else prefix = ""; last_buf = (last_buf+1)%8; buf[last_buf][0] = 0; strcpy(buf[last_buf], prefix); strcat(buf[last_buf], wire_name); return buf[last_buf]; } static int _add_connpt_name(struct fpga_model* model, int y, int x, const char* connpt_name, int warn_if_duplicate, uint16_t* name_i, int* conn_point_o); static int add_connpt_name(struct fpga_model* model, int y, int x, const char* connpt_name) { return _add_connpt_name(model, y, x, connpt_name, 1 /* warn_if_duplicate */, 0 /* name_i */, 0 /* conn_point_o */); } #define CONN_NAMES_INCREMENT 128 static int _add_connpt_name(struct fpga_model* model, int y, int x, const char* connpt_name, int warn_if_duplicate, uint16_t* name_i, int* conn_point_o) { struct fpga_tile* tile; uint16_t _name_i; int rc, i; tile = &model->tiles[y * model->x_width + x]; rc = strarray_add(&model->str, connpt_name, &i); if (rc) return rc; if (i > 0xFFFF) { fprintf(stderr, "Internal error in %s:%i\n", __FILE__, __LINE__); return -1; } _name_i = i; if (name_i) *name_i = i; // Search for an existing connection point under name. for (i = 0; i < tile->num_conn_point_names; i++) { if (tile->conn_point_names[i*2+1] == _name_i) break; } if (conn_point_o) *conn_point_o = i; if (i < tile->num_conn_point_names) { if (warn_if_duplicate) fprintf(stderr, "Duplicate connection point name y%02i x%02u %s\n", y, x, connpt_name); return 0; } // This is the first connection under name, add name. if (!(tile->num_conn_point_names % CONN_NAMES_INCREMENT)) { uint16_t* new_ptr = realloc(tile->conn_point_names, (tile->num_conn_point_names+CONN_NAMES_INCREMENT)*2*sizeof(uint16_t)); if (!new_ptr) { fprintf(stderr, "Out of memory %s:%i\n", __FILE__, __LINE__); return 0; } tile->conn_point_names = new_ptr; } tile->conn_point_names[tile->num_conn_point_names*2] = tile->num_conn_point_dests; tile->conn_point_names[tile->num_conn_point_names*2+1] = _name_i; tile->num_conn_point_names++; return 0; } #define CONNS_INCREMENT 128 #undef DBG_ADD_CONN_UNI static int add_conn_uni(struct fpga_model* model, int y1, int x1, const char* name1, int y2, int x2, const char* name2) { struct fpga_tile* tile; uint16_t name1_i, name2_i; uint16_t* new_ptr; int conn_start, num_conn_point_dests_for_this_wire, rc, j, conn_point_o; rc = _add_connpt_name(model, y1, x1, name1, 0 /* warn_if_duplicate */, &name1_i, &conn_point_o); if (rc) goto xout; rc = strarray_add(&model->str, name2, &j); if (rc) return rc; if (j > 0xFFFF) { fprintf(stderr, "Internal error in %s:%i\n", __FILE__, __LINE__); return -1; } name2_i = j; tile = &model->tiles[y1 * model->x_width + x1]; conn_start = tile->conn_point_names[conn_point_o*2]; if (conn_point_o+1 >= tile->num_conn_point_names) num_conn_point_dests_for_this_wire = tile->num_conn_point_dests - conn_start; else num_conn_point_dests_for_this_wire = tile->conn_point_names[(conn_point_o+1)*2] - conn_start; // Is the connection made a second time? for (j = conn_start; j < conn_start + num_conn_point_dests_for_this_wire; j++) { if (tile->conn_point_dests[j*3] == x2 && tile->conn_point_dests[j*3+1] == y2 && tile->conn_point_dests[j*3+2] == name2_i) { fprintf(stderr, "Duplicate conn (num_conn_point_dests %i): y%02i x%02i %s - y%02i x%02i %s.\n", num_conn_point_dests_for_this_wire, y1, x1, name1, y2, x2, name2); for (j = conn_start; j < conn_start + num_conn_point_dests_for_this_wire; j++) { fprintf(stderr, "c%i: y%02i x%02i %s -> y%02i x%02i %s\n", j, y1, x1, name1, tile->conn_point_dests[j*3+1], tile->conn_point_dests[j*3], strarray_lookup(&model->str, tile->conn_point_dests[j*3+2])); } return 0; } } if (!(tile->num_conn_point_dests % CONNS_INCREMENT)) { new_ptr = realloc(tile->conn_point_dests, (tile->num_conn_point_dests+CONNS_INCREMENT)*3*sizeof(uint16_t)); if (!new_ptr) { fprintf(stderr, "Out of memory %s:%i\n", __FILE__, __LINE__); return 0; } tile->conn_point_dests = new_ptr; } if (tile->num_conn_point_dests > j) memmove(&tile->conn_point_dests[(j+1)*3], &tile->conn_point_dests[j*3], (tile->num_conn_point_dests-j)*3*sizeof(uint16_t)); tile->conn_point_dests[j*3] = x2; tile->conn_point_dests[j*3+1] = y2; tile->conn_point_dests[j*3+2] = name2_i; tile->num_conn_point_dests++; while (conn_point_o+1 < tile->num_conn_point_names) { tile->conn_point_names[(conn_point_o+1)*2]++; conn_point_o++; } #if DBG_ADD_CONN_UNI printf("conn_point_dests for y%02i x%02i %s now:\n", y1, x1, name1); for (j = conn_start; j < conn_start + num_conn_point_dests_for_this_wire+1; j++) { fprintf(stderr, "c%i: y%02i x%02i %s -> y%02i x%02i %s\n", j, y1, x1, name1, tile->conn_point_dests[j*3+1], tile->conn_point_dests[j*3], strarray_lookup(&model->str, tile->conn_point_dests[j*3+2])); } #endif return 0; xout: return rc; } int add_conn_uni_pref(struct fpga_model* model, int y1, int x1, const char* name1, int y2, int x2, const char* name2) { return add_conn_uni(model, y1, x1, wpref(model, y1, x1, name1), y2, x2, wpref(model, y2, x2, name2)); } static int add_conn_bi(struct fpga_model* model, int y1, int x1, const char* name1, int y2, int x2, const char* name2) { int rc = add_conn_uni(model, y1, x1, name1, y2, x2, name2); if (rc) return rc; return add_conn_uni(model, y2, x2, name2, y1, x1, name1); } static int add_conn_bi_pref(struct fpga_model* model, int y1, int x1, const char* name1, int y2, int x2, const char* name2) { return add_conn_bi(model, y1, x1, wpref(model, y1, x1, name1), y2, x2, wpref(model, y2, x2, name2)); } static int add_conn_range(struct fpga_model* model, add_conn_f add_conn_func, int y1, int x1, const char* name1, int start1, int last1, int y2, int x2, const char* name2, int start2) { char buf1[128], buf2[128]; int rc, i; if (last1 <= start1) return (*add_conn_func)(model, y1, x1, name1, y2, x2, name2); for (i = start1; i <= last1; i++) { snprintf(buf1, sizeof(buf1), name1, i); snprintf(buf2, sizeof(buf2), name2, start2+(i-start1)); rc = (*add_conn_func)(model, y1, x1, buf1, y2, x2, buf2); if (rc) return rc; } return 0; } static int add_conn_net(struct fpga_model* model, add_conn_f add_conn_func, struct w_net* net) { int i, j, rc; for (i = 0; net->pts[i].name[0] && i < sizeof(net->pts)/sizeof(net->pts[0]); i++) { for (j = i+1; net->pts[j].name[0] && j < sizeof(net->pts)/sizeof(net->pts[0]); j++) { rc = add_conn_range(model, add_conn_func, net->pts[i].y, net->pts[i].x, net->pts[i].name, net->pts[i].start_count, net->pts[i].start_count + net->last_inc, net->pts[j].y, net->pts[j].x, net->pts[j].name, net->pts[j].start_count); if (rc) goto xout; } } return 0; xout: return rc; } #define SWITCH_ALLOC_INCREMENT 64 static int add_switch(struct fpga_model* model, int y, int x, const char* from, const char* to, int is_bidirectional) { struct fpga_tile* tile = YX_TILE(model, y, x); int rc, i, from_idx, to_idx, from_connpt_o, to_connpt_o; uint32_t new_switch; rc = strarray_find(&model->str, from, &from_idx); if (rc) goto xout; rc = strarray_find(&model->str, to, &to_idx); if (rc) goto xout; if (from_idx == STRIDX_NO_ENTRY || to_idx == STRIDX_NO_ENTRY) { fprintf(stderr, "No string for switch from %s (%i) or %s (%i).\n", from, from_idx, to, to_idx); return -1; } from_connpt_o = -1; for (i = 0; i < tile->num_conn_point_names; i++) { if (tile->conn_point_names[i*2+1] == from_idx) { from_connpt_o = i; break; } } to_connpt_o = -1; for (i = 0; i < tile->num_conn_point_names; i++) { if (tile->conn_point_names[i*2+1] == to_idx) { to_connpt_o = i; break; } } if (from_connpt_o == -1 || to_connpt_o == -1) { fprintf(stderr, "No conn point for switch from %s (%i/%i) or %s (%i/%i).\n", from, from_idx, from_connpt_o, to, to_idx, to_connpt_o); return -1; } if (from_connpt_o > SWITCH_MAX_CONNPT_O || to_connpt_o > SWITCH_MAX_CONNPT_O) { fprintf(stderr, "Internal error in %s:%i (from_o %i to_o %i)\n", __FILE__, __LINE__, from_connpt_o, to_connpt_o); return -1; } new_switch = (from_connpt_o << 15) | to_connpt_o; if (is_bidirectional) new_switch |= SWITCH_BIDIRECTIONAL; for (i = 0; i < tile->num_switches; i++) { if ((tile->switches[i] & 0x3FFFFFFF) == (new_switch & 0x3FFFFFFF)) { fprintf(stderr, "Internal error in %s:%i duplicate switch from %s to %s\n", __FILE__, __LINE__, from, to); return -1; } } if (!(tile->num_switches % SWITCH_ALLOC_INCREMENT)) { uint32_t* new_ptr = realloc(tile->switches, (tile->num_switches+SWITCH_ALLOC_INCREMENT)*sizeof(*tile->switches)); if (!new_ptr) { fprintf(stderr, "Out of memory %s:%i\n", __FILE__, __LINE__); return -1; } tile->switches = new_ptr; } tile->switches[tile->num_switches++] = new_switch; return 0; xout: return rc; } static void seed_strx(struct fpga_model* model, struct seed_data* data) { int x, i; for (x = 0; x < model->x_width; x++) { model->tmp_str[x] = 0; for (i = 0; data[i].x_flags; i++) { if (is_atx(data[i].x_flags, model, x)) model->tmp_str[x] = data[i].str; } } } static char next_non_whitespace(const char* s) { int i; for (i = 0; s[i] == ' '; i++); return s[i]; } static char last_major(const char* str, int cur_o) { for (; cur_o; cur_o--) { if (str[cur_o-1] >= 'A' && str[cur_o-1] <= 'Z') return str[cur_o-1]; } return 0; } int is_aty(int check, struct fpga_model* model, int y) { if (y < 0) return 0; if (check & Y_INNER_TOP && y == 1) return 1; if (check & Y_INNER_BOTTOM && y == model->y_height-2) return 1; if (check & Y_CHIP_HORIZ_REGS && y == model->center_y) return 1; if (check & (Y_ROW_HORIZ_AXSYMM|Y_BOTTOM_OF_ROW)) { int row_pos; is_in_row(model, y, 0 /* row_num */, &row_pos); if (check & Y_ROW_HORIZ_AXSYMM && row_pos == 8) return 1; if (check & Y_BOTTOM_OF_ROW && row_pos == 16) return 1; } if (check & Y_LEFT_WIRED && model->tiles[y*model->x_width].flags & TF_WIRED) return 1; if (check & Y_RIGHT_WIRED && model->tiles[y*model->x_width + model->x_width-RIGHT_OUTER_O].flags & TF_WIRED) return 1; return 0; } int is_atx(int check, struct fpga_model* model, int x) { if (x < 0) return 0; if (check & X_OUTER_LEFT && !x) return 1; if (check & X_INNER_LEFT && x == 1) return 1; if (check & X_INNER_RIGHT && x == model->x_width-2) return 1; if (check & X_OUTER_RIGHT && x == model->x_width-1) return 1; if (check & X_ROUTING_COL && (model->tiles[x].flags & TF_FABRIC_ROUTING_COL || x == LEFT_IO_ROUTING || x == model->x_width-5 || x == model->center_x-3)) return 1; if (model->tiles[x].flags & TF_FABRIC_ROUTING_COL) { if (check & X_ROUTING_TO_BRAM_COL && model->tiles[x+1].flags & TF_FABRIC_BRAM_MACC_ROUTING_COL && model->tiles[x+2].flags & TF_FABRIC_BRAM_COL) return 1; if (check & X_ROUTING_TO_MACC_COL && model->tiles[x+1].flags & TF_FABRIC_BRAM_MACC_ROUTING_COL && model->tiles[x+2].flags & TF_FABRIC_MACC_COL) return 1; } if (check & X_ROUTING_NO_IO && model->tiles[x].flags & TF_ROUTING_NO_IO) return 1; if (check & X_LOGIC_COL && (model->tiles[x].flags & TF_FABRIC_LOGIC_COL || x == model->center_x-2)) return 1; if (check & X_FABRIC_ROUTING_COL && model->tiles[x].flags & TF_FABRIC_ROUTING_COL) return 1; // todo: the routing/no_io flags could be cleaned up if (check & X_FABRIC_LOGIC_ROUTING_COL && model->tiles[x].flags & TF_FABRIC_ROUTING_COL && model->tiles[x+1].flags & TF_FABRIC_LOGIC_COL) return 1; if (check & X_FABRIC_LOGIC_COL && model->tiles[x].flags & TF_FABRIC_LOGIC_COL) return 1; if (check & X_FABRIC_BRAM_ROUTING_COL && model->tiles[x].flags & TF_FABRIC_ROUTING_COL && model->tiles[x+1].flags & TF_FABRIC_BRAM_MACC_ROUTING_COL && model->tiles[x+2].flags & TF_FABRIC_BRAM_COL) return 1; if (check & X_FABRIC_MACC_ROUTING_COL && model->tiles[x].flags & TF_FABRIC_ROUTING_COL && model->tiles[x+1].flags & TF_FABRIC_BRAM_MACC_ROUTING_COL && model->tiles[x+2].flags & TF_FABRIC_MACC_COL) return 1; if (check & X_FABRIC_BRAM_MACC_ROUTING_COL && model->tiles[x].flags & TF_FABRIC_BRAM_MACC_ROUTING_COL) return 1; if (check & X_FABRIC_BRAM_COL && model->tiles[x].flags & TF_FABRIC_BRAM_COL) return 1; if (check & X_FABRIC_MACC_COL && model->tiles[x].flags & TF_FABRIC_MACC_COL) return 1; if (check & X_CENTER_ROUTING_COL && x == model->center_x-3) return 1; if (check & X_CENTER_LOGIC_COL && x == model->center_x-2) return 1; if (check & X_CENTER_CMTPLL_COL && x == model->center_x-1) return 1; if (check & X_CENTER_REGS_COL && x == model->center_x) return 1; if (check & X_LEFT_IO_ROUTING_COL && x == LEFT_IO_ROUTING) return 1; if (check & X_LEFT_IO_DEVS_COL && x == LEFT_IO_DEVS) return 1; if (check & X_RIGHT_IO_ROUTING_COL && x == model->x_width-5) return 1; if (check & X_RIGHT_IO_DEVS_COL && x == model->x_width-4) return 1; if (check & X_LEFT_SIDE && x < model->center_x) return 1; if (check & X_LEFT_MCB && x == LEFT_MCB_COL) return 1; if (check & X_RIGHT_MCB && x == model->x_width-3) return 1; return 0; } int is_atyx(int check, struct fpga_model* model, int y, int x) { if (y < 0 || x < 0) return 0; if (check & YX_ROUTING_TILE && (model->tiles[x].flags & TF_FABRIC_ROUTING_COL || x == LEFT_IO_ROUTING || x == model->x_width-5 || x == model->center_x-3)) { int row_pos; is_in_row(model, y, 0 /* row_num */, &row_pos); if (row_pos >= 0 && row_pos != 8) return 1; } return 0; } void is_in_row(const struct fpga_model* model, int y, int* row_num, int* row_pos) { int dist_to_center; if (row_num) *row_num = -1; if (row_pos) *row_pos = -1; if (y < 2) return; // normalize y to beginning of rows y -= 2; // calculate distance to center and check // that y is not pointing to the center dist_to_center = (model->cfg_rows/2)*(8+1/*middle of row*/+8); if (y == dist_to_center) return; if (y > dist_to_center) y--; // check that y is not pointing past the last row if (y >= model->cfg_rows*(8+1+8)) return; if (row_num) *row_num = model->cfg_rows-(y/(8+1+8))-1; if (row_pos) *row_pos = y%(8+1+8); } static const char* fpga_ttstr[] = // tile type strings { [NA] = "NA", [ROUTING] = "ROUTING", [ROUTING_BRK] = "ROUTING_BRK", [ROUTING_VIA] = "ROUTING_VIA", [HCLK_ROUTING_XM] = "HCLK_ROUTING_XM", [HCLK_ROUTING_XL] = "HCLK_ROUTING_XL", [HCLK_LOGIC_XM] = "HCLK_LOGIC_XM", [HCLK_LOGIC_XL] = "HCLK_LOGIC_XL", [LOGIC_XM] = "LOGIC_XM", [LOGIC_XL] = "LOGIC_XL", [REGH_ROUTING_XM] = "REGH_ROUTING_XM", [REGH_ROUTING_XL] = "REGH_ROUTING_XL", [REGH_LOGIC_XM] = "REGH_LOGIC_XM", [REGH_LOGIC_XL] = "REGH_LOGIC_XL", [BRAM_ROUTING] = "BRAM_ROUTING", [BRAM_ROUTING_BRK] = "BRAM_ROUTING_BRK", [BRAM] = "BRAM", [BRAM_ROUTING_TERM_T] = "BRAM_ROUTING_TERM_T", [BRAM_ROUTING_TERM_B] = "BRAM_ROUTING_TERM_B", [BRAM_ROUTING_VIA_TERM_T] = "BRAM_ROUTING_VIA_TERM_T", [BRAM_ROUTING_VIA_TERM_B] = "BRAM_ROUTING_VIA_TERM_B", [BRAM_TERM_LT] = "BRAM_TERM_LT", [BRAM_TERM_RT] = "BRAM_TERM_RT", [BRAM_TERM_LB] = "BRAM_TERM_LB", [BRAM_TERM_RB] = "BRAM_TERM_RB", [HCLK_BRAM_ROUTING] = "HCLK_BRAM_ROUTING", [HCLK_BRAM_ROUTING_VIA] = "HCLK_BRAM_ROUTING_VIA", [HCLK_BRAM] = "HCLK_BRAM", [REGH_BRAM_ROUTING] = "REGH_BRAM_ROUTING", [REGH_BRAM_ROUTING_VIA] = "REGH_BRAM_ROUTING_VIA", [REGH_BRAM_L] = "REGH_BRAM_L", [REGH_BRAM_R] = "REGH_BRAM_R", [MACC] = "MACC", [HCLK_MACC_ROUTING] = "HCLK_MACC_ROUTING", [HCLK_MACC_ROUTING_VIA] = "HCLK_MACC_ROUTING_VIA", [HCLK_MACC] = "HCLK_MACC", [REGH_MACC_ROUTING] = "REGH_MACC_ROUTING", [REGH_MACC_ROUTING_VIA] = "REGH_MACC_ROUTING_VIA", [REGH_MACC_L] = "REGH_MACC_L", [PLL_T] = "PLL_T", [DCM_T] = "DCM_T", [PLL_B] = "PLL_B", [DCM_B] = "DCM_B", [REG_T] = "REG_T", [REG_TERM_T] = "REG_TERM_T", [REG_TERM_B] = "REG_TERM_B", [REG_B] = "REG_B", [REGV_TERM_T] = "REGV_TERM_T", [REGV_TERM_B] = "REGV_TERM_B", [HCLK_REGV] = "HCLK_REGV", [REGV] = "REGV", [REGV_BRK] = "REGV_BRK", [REGV_T] = "REGV_T", [REGV_B] = "REGV_B", [REGV_MIDBUF_T] = "REGV_MIDBUF_T", [REGV_HCLKBUF_T] = "REGV_HCLKBUF_T", [REGV_HCLKBUF_B] = "REGV_HCLKBUF_B", [REGV_MIDBUF_B] = "REGV_MIDBUF_B", [REGC_ROUTING] = "REGC_ROUTING", [REGC_LOGIC] = "REGC_LOGIC", [REGC_CMT] = "REGC_CMT", [CENTER] = "CENTER", [IO_T] = "IO_T", [IO_B] = "IO_B", [IO_TERM_T] = "IO_TERM_T", [IO_TERM_B] = "IO_TERM_B", [IO_ROUTING] = "IO_ROUTING", [IO_LOGIC_TERM_T] = "IO_LOGIC_TERM_T", [IO_LOGIC_TERM_B] = "IO_LOGIC_TERM_B", [IO_OUTER_T] = "IO_OUTER_T", [IO_INNER_T] = "IO_INNER_T", [IO_OUTER_B] = "IO_OUTER_B", [IO_INNER_B] = "IO_INNER_B", [IO_BUFPLL_TERM_T] = "IO_BUFPLL_TERM_T", [IO_LOGIC_REG_TERM_T] = "IO_LOGIC_REG_TERM_T", [IO_BUFPLL_TERM_B] = "IO_BUFPLL_TERM_B", [IO_LOGIC_REG_TERM_B] = "IO_LOGIC_REG_TERM_B", [LOGIC_ROUTING_TERM_B] = "LOGIC_ROUTING_TERM_B", [LOGIC_NOIO_TERM_B] = "LOGIC_NOIO_TERM_B", [MACC_ROUTING_TERM_T] = "MACC_ROUTING_TERM_T", [MACC_ROUTING_TERM_B] = "MACC_ROUTING_TERM_B", [MACC_VIA_TERM_T] = "MACC_VIA_TERM_T", [MACC_TERM_TL] = "MACC_TERM_TL", [MACC_TERM_TR] = "MACC_TERM_TR", [MACC_TERM_BL] = "MACC_TERM_BL", [MACC_TERM_BR] = "MACC_TERM_BR", [ROUTING_VIA_REGC] = "ROUTING_VIA_REGC", [ROUTING_VIA_IO] = "ROUTING_VIA_IO", [ROUTING_VIA_IO_DCM] = "ROUTING_VIA_IO_DCM", [ROUTING_VIA_CARRY] = "ROUTING_VIA_CARRY", [CORNER_TERM_L] = "CORNER_TERM_L", [CORNER_TERM_R] = "CORNER_TERM_R", [IO_TERM_L_UPPER_TOP] = "IO_TERM_L_UPPER_TOP", [IO_TERM_L_UPPER_BOT] = "IO_TERM_L_UPPER_BOT", [IO_TERM_L_LOWER_TOP] = "IO_TERM_L_LOWER_TOP", [IO_TERM_L_LOWER_BOT] = "IO_TERM_L_LOWER_BOT", [IO_TERM_R_UPPER_TOP] = "IO_TERM_R_UPPER_TOP", [IO_TERM_R_UPPER_BOT] = "IO_TERM_R_UPPER_BOT", [IO_TERM_R_LOWER_TOP] = "IO_TERM_R_LOWER_TOP", [IO_TERM_R_LOWER_BOT] = "IO_TERM_R_LOWER_BOT", [IO_TERM_L] = "IO_TERM_L", [IO_TERM_R] = "IO_TERM_R", [HCLK_TERM_L] = "HCLK_TERM_L", [HCLK_TERM_R] = "HCLK_TERM_R", [REGH_IO_TERM_L] = "REGH_IO_TERM_L", [REGH_IO_TERM_R] = "REGH_IO_TERM_R", [REG_L] = "REG_L", [REG_R] = "REG_R", [IO_PCI_L] = "IO_PCI_L", [IO_PCI_R] = "IO_PCI_R", [IO_RDY_L] = "IO_RDY_L", [IO_RDY_R] = "IO_RDY_R", [IO_L] = "IO_L", [IO_R] = "IO_R", [IO_PCI_CONN_L] = "IO_PCI_CONN_L", [IO_PCI_CONN_R] = "IO_PCI_CONN_R", [CORNER_TERM_T] = "CORNER_TERM_T", [CORNER_TERM_B] = "CORNER_TERM_B", [ROUTING_IO_L] = "ROUTING_IO_L", [HCLK_ROUTING_IO_L] = "HCLK_ROUTING_IO_L", [HCLK_ROUTING_IO_R] = "HCLK_ROUTING_IO_R", [REGH_ROUTING_IO_L] = "REGH_ROUTING_IO_L", [REGH_ROUTING_IO_R] = "REGH_ROUTING_IO_R", [ROUTING_IO_L_BRK] = "ROUTING_IO_L_BRK", [ROUTING_GCLK] = "ROUTING_GCLK", [REGH_IO_L] = "REGH_IO_L", [REGH_IO_R] = "REGH_IO_R", [REGH_MCB] = "REGH_MCB", [HCLK_MCB] = "HCLK_MCB", [ROUTING_IO_VIA_L] = "ROUTING_IO_VIA_L", [ROUTING_IO_VIA_R] = "ROUTING_IO_VIA_R", [ROUTING_IO_PCI_CE_L] = "ROUTING_IO_PCI_CE_L", [ROUTING_IO_PCI_CE_R] = "ROUTING_IO_PCI_CE_R", [CORNER_TL] = "CORNER_TL", [CORNER_BL] = "CORNER_BL", [CORNER_TR_UPPER] = "CORNER_TR_UPPER", [CORNER_TR_LOWER] = "CORNER_TR_LOWER", [CORNER_BR_UPPER] = "CORNER_BR_UPPER", [CORNER_BR_LOWER] = "CORNER_BR_LOWER", [HCLK_IO_TOP_UP_L] = "HCLK_IO_TOP_UP_L", [HCLK_IO_TOP_UP_R] = "HCLK_IO_TOP_UP_R", [HCLK_IO_TOP_SPLIT_L] = "HCLK_IO_TOP_SPLIT_L", [HCLK_IO_TOP_SPLIT_R] = "HCLK_IO_TOP_SPLIT_R", [HCLK_IO_TOP_DN_L] = "HCLK_IO_TOP_DN_L", [HCLK_IO_TOP_DN_R] = "HCLK_IO_TOP_DN_R", [HCLK_IO_BOT_UP_L] = "HCLK_IO_BOT_UP_L", [HCLK_IO_BOT_UP_R] = "HCLK_IO_BOT_UP_R", [HCLK_IO_BOT_SPLIT_L] = "HCLK_IO_BOT_SPLIT_L", [HCLK_IO_BOT_SPLIT_R] = "HCLK_IO_BOT_SPLIT_R", [HCLK_IO_BOT_DN_L] = "HCLK_IO_BOT_DN_L", [HCLK_IO_BOT_DN_R] = "HCLK_IO_BOT_DN_R", }; const char* fpga_tiletype_str(enum fpga_tile_type type) { if (type >= sizeof(fpga_ttstr)/sizeof(fpga_ttstr[0]) || !fpga_ttstr[type]) return "UNK"; return fpga_ttstr[type]; }