// // Author: Wolfgang Spraul // // This is free and unencumbered software released into the public domain. // For details see the UNLICENSE file at the root of the source tree. // #include "model.h" #include "control.h" struct iob_site { int xy; const char* name[4]; // left and right only use 2, top and bottom 4 }; static const struct iob_site xc6slx9_iob_top[] = { { 5, {"P144", "P143", "P142", "P141"}}, { 7, {"P140", "P139", "P138", "P137"}}, {12, {"UNB9", "UNB10", "UNB11", "UNB12"}}, {14, {"UNB13", "UNB14", "UNB15", "UNB16"}}, {19, {"UNB17", "UNB18", "UNB19", "UNB20"}}, {21, {"P134", "P133", "P132", "P131"}}, {25, {"P127", "P126", "P124", "P123"}}, {29, {"UNB29", "UNB30", "UNB31", "UNB32"}}, {31, {"UNB33", "UNB34", "P121", "P120"}}, {36, {"P119", "P118", "P117", "P116"}}, {38, {"P115", "P114", "P112", "P111"}}, }; static const struct iob_site xc6slx9_iob_bottom[] = { { 5, {"P38", "P39", "P40", "P41"}}, { 7, {"UNB140", "UNB139", "P43", "P44"}}, {12, {"P45", "P46", "P47", "P48"}}, {14, {"UNB132", "UNB131", "UNB130", "UNB129"}}, {19, {"UNB128", "UNB127", "UNB126", "UNB125"}}, {21, {"UNB124", "UNB123", "P50", "P51"}}, {25, {"P55", "P56", "UNB118", "UNB117"}}, {29, {"UNB116", "UNB115", "UNB114", "UNB113"}}, {31, {"P57", "P58", "P59", "P60"}}, {36, {"P61", "P62", "P64", "P65"}}, {38, {"P66", "P67", "P69", "P70"}}, }; static const struct iob_site xc6slx9_iob_left[] = { { 3, {"P1", "P2"}}, { 5, {"UNB198", "UNB197"}}, { 7, {"UNB196", "UNB195"}}, { 9, {"UNB194", "UNB193"}}, { 11, {"P5", "P6"}}, { 12, {"P7", "P8"}}, { 13, {"P9", "P10"}}, { 14, {"P11", "P12"}}, { 28, {"UNB184", "UNB183"}}, { 29, {"UNB182", "UNB181"}}, { 30, {"UNB180", "UNB179"}}, { 31, {"UNB178", "UNB177"}}, { 32, {"P14", "P15"}}, { 33, {"P16", "P17"}}, { 37, {"P21", "P22"}}, { 38, {"P23", "P24"}}, { 39, {"UNB168", "UNB167"}}, { 42, {"UNB166", "UNB165"}}, { 46, {"UNB164", "UNB163"}}, { 49, {"P26", "P27"}}, { 52, {"P29", "P30"}}, { 55, {"UNB158", "UNB157"}}, { 58, {"UNB156", "UNB155"}}, { 61, {"UNB154", "UNB153"}}, { 65, {"UNB152", "UNB151"}}, { 66, {"UNB150", "UNB149"}}, { 67, {"P32", "P33"}}, { 68, {"P34", "P35"}}, }; static const struct iob_site xc6slx9_iob_right[] = { { 4, {"P105", "P104"}}, { 5, {"UNB47", "UNB48"}}, { 7, {"UNB49", "UNB50"}}, { 9, {"UNB51", "UNB52"}}, { 11, {"P102", "P101"}}, { 12, {"P100", "P99"}}, { 13, {"P98", "P97"}}, { 14, {"UNB59", "UNB60"}}, { 28, {"UNB61", "UNB62"}}, { 29, {"UNB63", "UNB64"}}, { 30, {"UNB65", "UNB66"}}, { 31, {"UNB67", "UNB68"}}, { 32, {"P95", "P94"}}, { 33, {"P93", "P92"}}, { 37, {"P88", "P87"}}, { 38, {"P85", "P84"}}, { 39, {"UNB77", "UNB78"}}, { 42, {"P83", "P82"}}, { 46, {"P81", "P80"}}, { 49, {"P79", "P78"}}, { 52, {"UNB85", "UNB86"}}, { 55, {"UNB87", "UNB88"}}, { 58, {"UNB89", "UNB90"}}, { 61, {"UNB91", "UNB92"}}, { 65, {"UNB93", "UNB94"}}, { 66, {"UNB95", "UNB96"}}, { 67, {"UNB97", "UNB98"}}, { 68, {"P75", "P74"}}, }; int fpga_find_iob(struct fpga_model* model, const char* sitename, int* y, int* x, int* idx) { int i, j; for (i = 0; i < sizeof(xc6slx9_iob_top)/sizeof(xc6slx9_iob_top[0]); i++) { for (j = 0; j < 4; j++) { if (!strcmp(xc6slx9_iob_top[i].name[j], sitename)) { *y = TOP_OUTER_ROW; *x = xc6slx9_iob_top[i].xy; *idx = j; return 0; } } } for (i = 0; i < sizeof(xc6slx9_iob_bottom)/sizeof(xc6slx9_iob_bottom[0]); i++) { for (j = 0; j < 4; j++) { if (!strcmp(xc6slx9_iob_bottom[i].name[j], sitename)) { *y = model->y_height-BOT_OUTER_ROW; *x = xc6slx9_iob_bottom[i].xy; *idx = j; return 0; } } } for (i = 0; i < sizeof(xc6slx9_iob_left)/sizeof(xc6slx9_iob_left[0]); i++) { for (j = 0; j < 2; j++) { if (!strcmp(xc6slx9_iob_left[i].name[j], sitename)) { *y = xc6slx9_iob_left[i].xy; *x = LEFT_OUTER_COL; *idx = j; return 0; } } } for (i = 0; i < sizeof(xc6slx9_iob_right)/sizeof(xc6slx9_iob_right[0]); i++) { for (j = 0; j < 2; j++) { if (!strcmp(xc6slx9_iob_right[i].name[j], sitename)) { *y = xc6slx9_iob_right[i].xy; *x = model->x_width-RIGHT_OUTER_O; *idx = j; return 0; } } } return -1; } const char* fpga_iob_sitename(struct fpga_model* model, int y, int x, int idx) { int i; if (y == TOP_OUTER_ROW) { for (i = 0; i < sizeof(xc6slx9_iob_top)/sizeof(xc6slx9_iob_top[0]); i++) { if (xc6slx9_iob_right[i].xy == x) { if (idx < 0 || idx > 3) return 0; return xc6slx9_iob_top[i].name[idx]; } } return 0; } if (y == model->y_height-BOT_OUTER_ROW) { for (i = 0; i < sizeof(xc6slx9_iob_bottom)/sizeof(xc6slx9_iob_bottom[0]); i++) { if (xc6slx9_iob_bottom[i].xy == x) { if (idx < 0 || idx > 3) return 0; return xc6slx9_iob_bottom[i].name[idx]; } } return 0; } if (x == LEFT_OUTER_COL) { for (i = 0; i < sizeof(xc6slx9_iob_left)/sizeof(xc6slx9_iob_left[0]); i++) { if (xc6slx9_iob_left[i].xy == y) { if (idx < 0 || idx > 1) return 0; return xc6slx9_iob_left[i].name[idx]; } } return 0; } if (x == model->x_width-RIGHT_OUTER_O) { for (i = 0; i < sizeof(xc6slx9_iob_right)/sizeof(xc6slx9_iob_right[0]); i++) { if (xc6slx9_iob_right[i].xy == y) { if (idx < 0 || idx > 1) return 0; return xc6slx9_iob_right[i].name[idx]; } } return 0; } return 0; } struct fpga_device* fpga_dev(struct fpga_model* model, int y, int x, enum fpgadev_type type, int type_idx) { struct fpga_tile* tile; int type_count, i; tile = YX_TILE(model, y, x); type_count = 0; for (i = 0; i < tile->num_devs; i++) { if (tile->devs[i].type == type) { if (type_count == type_idx) return &tile->devs[i]; type_count++; } } return 0; } int fpga_dev_typecount(struct fpga_model* model, int y, int x, enum fpgadev_type type, int dev_idx) { struct fpga_tile* tile; int type_count, i; tile = YX_TILE(model, y, x); type_count = 0; for (i = 0; i < dev_idx; i++) { if (tile->devs[i].type == type) type_count++; } return type_count; } #define MAX_LUT_LEN 512 int fpga_set_lut(struct fpga_model* model, struct fpga_device* dev, int which_lut, const char* lut_str, int lut_len) { char** ptr; if (dev->type != DEV_LOGIC) return -1; switch (which_lut) { case A6_LUT: ptr = &dev->logic.A6_lut; break; case B6_LUT: ptr = &dev->logic.B6_lut; break; case C6_LUT: ptr = &dev->logic.C6_lut; break; case D6_LUT: ptr = &dev->logic.D6_lut; break; default: return -1; } if (!(*ptr)) { *ptr = malloc(MAX_LUT_LEN); if (!(*ptr)) { OUT_OF_MEM(); return -1; } } if (lut_len == ZTERM) lut_len = strlen(lut_str); memcpy(*ptr, lut_str, lut_len); (*ptr)[lut_len] = 0; return 0; } int fpga_conn_dest(struct fpga_model* model, int y, int x, const char* name, int dest_idx) { struct fpga_tile* tile; int i, rc, connpt_i, num_dests, conn_point_dests_o; rc = strarray_find(&model->str, name, &connpt_i); if (rc) FAIL(rc); tile = YX_TILE(model, y, x); for (i = 0; i < tile->num_conn_point_names; i++) { if (tile->conn_point_names[i*2+1] == connpt_i) break; } if (i >= tile->num_conn_point_names) FAIL(EINVAL); conn_point_dests_o = tile->conn_point_names[i*2]; if (i < tile->num_conn_point_names-1) num_dests = tile->conn_point_names[(i+1)*2] - conn_point_dests_o; else num_dests = tile->num_conn_point_dests - conn_point_dests_o; if (dest_idx >= num_dests) return NO_CONN; return conn_point_dests_o + dest_idx; fail: return NO_CONN; } #define NUM_CONN_DEST_BUFS 16 #define CONN_DEST_BUF_SIZE 128 const char* fpga_conn_to(struct fpga_model* model, int y, int x, int connpt_dest_idx, int* dest_y, int* dest_x) { static char conn_dest_buf[NUM_CONN_DEST_BUFS][CONN_DEST_BUF_SIZE]; static int last_buf = 0; struct fpga_tile* tile; const char* hash_str; tile = YX_TILE(model, y, x); if (connpt_dest_idx < 0 || connpt_dest_idx >= tile->num_conn_point_dests) { HERE(); return 0; } *dest_x = tile->conn_point_dests[connpt_dest_idx*3]; *dest_y = tile->conn_point_dests[connpt_dest_idx*3+1]; hash_str = strarray_lookup(&model->str, tile->conn_point_dests[connpt_dest_idx*3+2]); if (!hash_str || (strlen(hash_str) >= CONN_DEST_BUF_SIZE)) { HERE(); return 0; } last_buf = (last_buf+1)%NUM_CONN_DEST_BUFS; strcpy(conn_dest_buf[last_buf], hash_str); return conn_dest_buf[last_buf]; } int fpga_switch_dest(struct fpga_model* model, int y, int x, const char* name, int dest_idx) { struct fpga_tile* tile; int rc, i, connpt_o, from_name_i, dest_idx_counter; rc = strarray_find(&model->str, name, &from_name_i); if (rc) FAIL(rc); // counts how many switches from the same source (name) // we have already encountered - to find the dest_idx'th // entry in that series dest_idx_counter = 0; tile = YX_TILE(model, y, x); for (i = 0; i < tile->num_switches; i++) { connpt_o = SWITCH_FROM(tile->switches[i]); if (tile->conn_point_names[connpt_o*2+1] == from_name_i) { if (dest_idx_counter >= dest_idx) break; dest_idx_counter++; } } if (i >= tile->num_switches) return NO_SWITCH; if (dest_idx_counter > dest_idx) FAIL(EINVAL); return i; fail: return NO_SWITCH; } #define NUM_SWITCH_TO_BUFS 16 #define SWITCH_TO_BUF_SIZE 128 const char* fpga_switch_to(struct fpga_model* model, int y, int x, int swidx, int* is_bidir) { // We have a little local ringbuffer to make passing // around pointers with unknown lifetime and possible // overlap with writing functions more stable. static char switch_to_buf[NUM_SWITCH_TO_BUFS][SWITCH_TO_BUF_SIZE]; static int last_buf = 0; struct fpga_tile* tile; const char* hash_str; int connpt_o, str_i; tile = YX_TILE(model, y, x); if (is_bidir) *is_bidir = (tile->switches[swidx] & SWITCH_BIDIRECTIONAL) != 0; connpt_o = SWITCH_TO(tile->switches[swidx]); str_i = tile->conn_point_names[connpt_o*2+1]; hash_str = strarray_lookup(&model->str, str_i); if (!hash_str || (strlen(hash_str) >= SWITCH_TO_BUF_SIZE)) { HERE(); return 0; } last_buf = (last_buf+1)%NUM_SWITCH_TO_BUFS; strcpy(switch_to_buf[last_buf], hash_str); return switch_to_buf[last_buf]; }