diff --git a/README b/README index 4a75839..a0cbc93 100644 --- a/README +++ b/README @@ -19,7 +19,7 @@ Libraries - libfpga-test autotest suite - libfpga-cores reusable cores -- libfpga-design larger design elements on top of libfpga-control +- libfpga-stdlib standard design elements on top of libfpga-control - libfpga-control programmatic access to libfpga-model - libfpga-model memory-only representation of an FPGA - libfpga-floorplan reads and writes .fp floorplan files @@ -63,7 +63,7 @@ TODO (as of 2012-08, expected time to delivery: months to years * configuration of bram and macc blocks, bram initialization data * routing switches * many more cases in model of switches and inter-tile connections -* write standard design elements for libfpga-design library +* write standard design elements for libfpga-stdlib library * support lm32 or openrisc core, either via libfpga or iverilog backend * ipv6 or vnc in hardware? * iverilog fpga backend diff --git a/autotest.c b/autotest.c index 4ffd719..42861db 100644 --- a/autotest.c +++ b/autotest.c @@ -201,8 +201,7 @@ static int test_logic_net(struct test_state* tstate, int logic_y, int logic_x, // add port rc = fpga_net_add_port(tstate->model, net_idx, logic_y, logic_x, - fpga_dev_idx(tstate->model, logic_y, logic_x, DEV_LOGIC, - type_idx), port); + DEV_LOGIC, type_idx, port); if (rc) FAIL(rc); // add (one) switch in logic tile @@ -277,7 +276,7 @@ static int test_logic_net_l2(struct test_state* tstate, int y, int x, rc = fpga_switch_to_yx(&switch_to); if (rc) FAIL(rc); if (dbg) - printf_switch_to_result(&switch_to); + printf_switch_to_yx_result(&switch_to); switch_tile = YX_TILE(tstate->model, switch_to.dest_y, switch_to.dest_x); rc = fpga_swset_fromto(tstate->model, switch_to.dest_y, @@ -379,7 +378,7 @@ static int test_logic_net_l1(struct test_state* tstate, int y, int x, rc = fpga_switch_to_yx(&switch_to); if (rc) FAIL(rc); if (tstate->dry_run) - printf_switch_to_result(&switch_to); + printf_switch_to_yx_result(&switch_to); rc = fpga_swset_fromto(tstate->model, switch_to.dest_y, switch_to.dest_x, switch_to.dest_connpt, from_to, &set_l1); @@ -414,8 +413,259 @@ fail: return rc; } +static int test_switches(struct test_state* tstate, int y, int x, + str16_t start_switch, net_idx_t net, swidx_t* done_list, int* done_list_len) +{ + struct sw_set sw_set, w4_set; + const char* switch_str; + str16_t switch_str_i; + int i, j, k, rc; + + rc = fpga_swset_fromto(tstate->model, y, x, start_switch, SW_TO, &sw_set); + if (rc) FAIL(rc); + if (tstate->dry_run) + fpga_swset_print(tstate->model, y, x, &sw_set, SW_TO); + + for (i = 0; i < sw_set.len; i++) { + switch_str_i = fpga_switch_str_i(tstate->model, y, x, + sw_set.sw[i], SW_FROM); + switch_str = strarray_lookup(&tstate->model->str, switch_str_i); + if (!switch_str) FAIL(EINVAL); + if (switch_str[2] == '4') { + // base for len-4 wire + if (tstate->dry_run) + fprintf_net(stdout, tstate->model, net); + rc = diff_printf(tstate); + if (rc) FAIL(rc); + + // add len-4 wire + rc = fpga_net_add_sw(tstate->model, net, y, x, + &sw_set.sw[i], 1); + if (rc) FAIL(rc); + + // enum dests of len-4 wire + rc = fpga_swset_fromto(tstate->model, y, x, + switch_str_i, SW_FROM, &w4_set); + if (rc) FAIL(rc); + if (tstate->dry_run) + fpga_swset_print(tstate->model, y, x, + &w4_set, SW_FROM); + + for (j = 0; j < w4_set.len; j++) { + // do not point to our base twice + if (w4_set.sw[j] == sw_set.sw[i]) + continue; + + // duplicate check and done_list + for (k = 0; k < *done_list_len; k++) { + if (done_list[k] == w4_set.sw[j]) + break; + } + if (k < *done_list_len) + continue; + done_list[(*done_list_len)++] = w4_set.sw[j]; + if (tstate->dry_run) + printf("done_list %s at %i\n", + fpga_switch_print(tstate->model, + y, x, done_list[(*done_list_len)-1]), + (*done_list_len)-1); + + // base for len-4 target + if (tstate->dry_run) + fprintf_net(stdout, tstate->model, net); + rc = diff_printf(tstate); + if (rc) FAIL(rc); + + // add len-4 target + rc = fpga_net_add_sw(tstate->model, net, y, x, + &w4_set.sw[j], 1); + if (rc) FAIL(rc); + + if (tstate->dry_run) + fprintf_net(stdout, tstate->model, net); + rc = diff_printf(tstate); + if (rc) FAIL(rc); + + rc = fpga_net_remove_sw(tstate->model, net, y, x, + &w4_set.sw[j], 1); + if (rc) FAIL(rc); + } + rc = fpga_net_remove_sw(tstate->model, net, y, x, + &sw_set.sw[i], 1); + if (rc) FAIL(rc); + } + } + return 0; +fail: + return rc; +} + +static int test_routing_sw_from_south(struct test_state* tstate, + swidx_t* done_list, int* done_list_len) +{ + struct switch_to_yx switch_to; + int iob_y, iob_x, iob_type_idx, rc; + struct fpga_device* iob_dev; + net_idx_t net; + + rc = fpga_find_iob(tstate->model, "P48", &iob_y, &iob_x, &iob_type_idx); + if (rc) FAIL(rc); + rc = fdev_iob_output(tstate->model, iob_y, iob_x, iob_type_idx); + if (rc) FAIL(rc); + iob_dev = fdev_p(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx); + if (!iob_dev) FAIL(EINVAL); + + rc = fpga_net_new(tstate->model, &net); + if (rc) FAIL(rc); + rc = fpga_net_add_port(tstate->model, net, iob_y, iob_x, + DEV_IOB, iob_type_idx, IOB_IN_O); + if (rc) FAIL(rc); + + switch_to.yx_req = YX_DEV_OLOGIC; + switch_to.flags = SWTO_YX_DEF; + switch_to.model = tstate->model; + switch_to.y = iob_y; + switch_to.x = iob_x; + switch_to.start_switch = iob_dev->pinw[IOB_IN_O]; + switch_to.from_to = SW_TO; + rc = fpga_switch_to_yx(&switch_to); + if (rc) FAIL(rc); + if (tstate->dry_run) + printf_switch_to_yx_result(&switch_to); + rc = fpga_net_add_sw(tstate->model, net, switch_to.y, + switch_to.x, switch_to.set.sw, switch_to.set.len); + if (rc) FAIL(rc); + + switch_to.yx_req = YX_ROUTING_TILE; + switch_to.flags = SWTO_YX_DEF; + switch_to.model = tstate->model; + switch_to.y = switch_to.dest_y; + switch_to.x = switch_to.dest_x; + switch_to.start_switch = switch_to.dest_connpt; + switch_to.from_to = SW_TO; + rc = fpga_switch_to_yx(&switch_to); + if (rc) FAIL(rc); + rc = fpga_net_add_sw(tstate->model, net, switch_to.y, + switch_to.x, switch_to.set.sw, switch_to.set.len); + if (rc) FAIL(rc); + if (tstate->dry_run) + printf_switch_to_yx_result(&switch_to); + + switch_to.yx_req = YX_ROUTING_TO_FABLOGIC; + switch_to.flags = SWTO_YX_CLOSEST; + switch_to.model = tstate->model; + switch_to.y = switch_to.dest_y; + switch_to.x = switch_to.dest_x; + switch_to.start_switch = switch_to.dest_connpt; + switch_to.from_to = SW_TO; + rc = fpga_switch_to_yx(&switch_to); + if (rc) FAIL(rc); + if (tstate->dry_run) + printf_switch_to_yx_result(&switch_to); + rc = fpga_net_add_sw(tstate->model, net, switch_to.y, + switch_to.x, switch_to.set.sw, switch_to.set.len); + if (rc) FAIL(rc); + + rc = test_switches(tstate, switch_to.dest_y, switch_to.dest_x, + switch_to.dest_connpt, net, done_list, done_list_len); + if (rc) FAIL(rc); + + fdev_delete(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx); + fpga_net_delete(tstate->model, net); + return 0; +fail: + return rc; +} + +static int test_routing_sw_from_north(struct test_state* tstate, + swidx_t* done_list, int* done_list_len) +{ + struct fpga_device* dev; + struct switch_to_rel swto; + struct sw_conns conns; + const char* str; + net_idx_t net; + int y, x, i, rc; + + y = 67; + x = 13; + for (i = '1'; i <= '6'; i++) { + rc = fdev_logic_set_lut(tstate->model, y, x, + DEV_LOGM, LUT_A, 6, pf("A%c", i), ZTERM); + if (rc) FAIL(rc); + rc = fdev_set_required_pins(tstate->model, y, x, + DEV_LOGIC, DEV_LOGM); + if (rc) FAIL(rc); + + if (tstate->dry_run) + fdev_print_required_pins(tstate->model, + y, x, DEV_LOGIC, DEV_LOGM); + dev = fdev_p(tstate->model, y, x, DEV_LOGIC, DEV_LOGM); + if (!dev) FAIL(EINVAL); + if (!dev->pinw_req_in) FAIL(EINVAL); + + rc = fpga_net_new(tstate->model, &net); + if (rc) FAIL(rc); + rc = fpga_net_add_port(tstate->model, net, y, x, + DEV_LOGIC, DEV_LOGM, dev->pinw_req_for_cfg[0]); + if (rc) FAIL(rc); + + swto.model = tstate->model; + swto.start_y = y; + swto.start_x = x; + swto.start_switch = fdev_logic_pinstr_i(tstate->model, + dev->pinw_req_for_cfg[0]|LD1, LOGIC_M); + swto.from_to = SW_TO; + swto.rel_y = 0; + swto.rel_x = -1; + swto.target_connpt = STRIDX_NO_ENTRY; + rc = fpga_switch_to_rel(&swto); + if (rc) FAIL(rc); + if (!swto.set.len) FAIL(EINVAL); + if (tstate->dry_run) + printf_switch_to_rel_result(&swto); + rc = fpga_net_add_sw(tstate->model, net, swto.start_y, + swto.start_x, swto.set.sw, swto.set.len); + if (rc) FAIL(rc); + + rc = construct_sw_conns(&conns, tstate->model, swto.dest_y, swto.dest_x, + swto.dest_connpt, SW_TO, /*max_depth*/ 1); + if (rc) FAIL(rc); + + while (fpga_switch_conns(&conns) != NO_CONN) { + if (conns.dest_x != swto.dest_x + || conns.dest_y != swto.dest_y+1) + continue; + str = strarray_lookup(&tstate->model->str, conns.dest_str_i); + if (!str) { HERE(); continue; } + if (strlen(str) < 5 + || str[2] != '1' || str[3] != 'B') + continue; + rc = fpga_net_add_sw(tstate->model, net, swto.dest_y, + swto.dest_x, conns.chain.set.sw, conns.chain.set.len); + if (rc) FAIL(rc); + if (tstate->dry_run) + fprintf_net(stdout, tstate->model, net); + + rc = test_switches(tstate, conns.dest_y, conns.dest_x, + conns.dest_str_i, net, done_list, done_list_len); + if (rc) FAIL(rc); + + rc = fpga_net_remove_sw(tstate->model, net, swto.dest_y, + swto.dest_x, conns.chain.set.sw, conns.chain.set.len); + if (rc) FAIL(rc); + } + destruct_sw_conns(&conns); + fdev_delete(tstate->model, y, x, DEV_LOGIC, DEV_LOGM); + fpga_net_delete(tstate->model, net); + } + return 0; +fail: + return rc; +} + // goal: use all switches in a routing switchbox -static int test_logic_switches(struct test_state* tstate) +static int test_routing_switches(struct test_state* tstate) { int idx_enum[] = { DEV_LOGM, DEV_LOGX }; int y, x, i, j, k, r, rc; @@ -426,7 +676,6 @@ static int test_logic_switches(struct test_state* tstate) y = 68; x = 13; - done_sw_len = 0; for (r = 0; r <= 1; r++) { // two rounds: @@ -494,6 +743,11 @@ static int test_logic_switches(struct test_state* tstate) } } } + done_sw_len = 0; + rc = test_routing_sw_from_south(tstate, done_sw_list, &done_sw_len); + if (rc) FAIL(rc); + rc = test_routing_sw_from_north(tstate, done_sw_list, &done_sw_len); + if (rc) FAIL(rc); return 0; fail: return rc; @@ -528,7 +782,7 @@ static int test_iologic_switches2(struct test_state* tstate, int iob_y, int iob_ rc = fpga_switch_to_yx(&switch_to); if (rc) FAIL(rc); if (tstate->dry_run) - printf_switch_to_result(&switch_to); + printf_switch_to_yx_result(&switch_to); if (construct_sw_chain(&chain, tstate->model, switch_to.dest_y, switch_to.dest_x, switch_to.dest_connpt, from_to, @@ -547,8 +801,7 @@ static int test_iologic_switches2(struct test_state* tstate, int iob_y, int iob_ // add iob port rc = fpga_net_add_port(tstate->model, net_idx, iob_y, iob_x, - fpga_dev_idx(tstate->model, iob_y, iob_x, DEV_IOB, - iob_type_idx), IOB_IN_O); + DEV_IOB, iob_type_idx, IOB_IN_O); if (rc) FAIL(rc); // add switch in iob tile @@ -643,7 +896,7 @@ int main(int argc, char** argv) char param[1024], cmdline_test[1024]; int i, param_skip, rc; const char* available_tests[] = - { "logic_cfg", "logic_sw", "io_sw", 0 }; + { "logic_cfg", "routing_sw", "io_sw", 0 }; // flush after every line is better for the autotest // output, tee, etc. @@ -755,8 +1008,8 @@ int main(int argc, char** argv) rc = test_logic_config(&tstate); if (rc) FAIL(rc); } - if (!strcmp(cmdline_test, "logic_sw")) { - rc = test_logic_switches(&tstate); + if (!strcmp(cmdline_test, "routing_sw")) { + rc = test_routing_switches(&tstate); if (rc) FAIL(rc); } if (!strcmp(cmdline_test, "io_sw")) { diff --git a/control.c b/control.c index 5b56f4e..732bbb7 100644 --- a/control.c +++ b/control.c @@ -334,6 +334,54 @@ const char* fdev_logic_pinstr(pinw_idx_t idx, int ld1_type) return buf[last_buf]; } +str16_t fdev_logic_pinstr_i(struct fpga_model* model, pinw_idx_t idx, int ld1_type) +{ + int str_i; + + str_i = strarray_find(&model->str, fdev_logic_pinstr(idx, ld1_type)); + if (OUT_OF_U16(str_i)) + { HERE(); return STRIDX_NO_ENTRY; } + return str_i; +} + +int fdev_logic_inbit(pinw_idx_t idx, int ld1_type) +{ + if (idx & LD1) { + idx &= ~LD1; + if (idx >= LI_A1 && idx <= LI_C6) + return M_A1 + (idx/6)*8+idx%6; + if (idx >= LI_D1 && idx <= LI_D6) + return M_D1 + (idx-LI_D1); + switch (idx) { + case LI_AX: return M_AX; + case LI_BX: return M_BX; + case LI_CE: return M_CE; + case LI_CX: return M_CX; + case LI_DX: return M_DX; + case LI_AI: return M_AI; + case LI_BI: return M_BI; + case LI_CI: return M_CI; + case LI_DI: return M_DI; + case LI_WE: return M_WE; + } + HERE(); + return -1; + } + if (idx >= LI_A1 && idx <= LI_C6) + return X_A1 + (idx/6)*7+idx%6; + else if (idx >= LI_D1 && idx <= LI_D6) + return X_D1 + (idx-LI_D1); + else switch (idx) { + case LI_AX: return X_AX; + case LI_BX: return X_BX; + case LI_CE: return X_CE; + case LI_CX: return X_CX; + case LI_DX: return X_DX; + } + HERE(); + return -1; +} + static int reset_required_pins(struct fpga_device* dev) { int rc; @@ -1453,7 +1501,7 @@ fail: return rc; } -void printf_switch_to_result(struct switch_to_yx* p) +void printf_switch_to_yx_result(struct switch_to_yx* p) { printf("switch_to_yx() from y%02i x%02i connpt %s (%s)\n", p->y, p->x, strarray_lookup(&p->model->str, p->start_switch), @@ -1465,6 +1513,46 @@ void printf_switch_to_result(struct switch_to_yx* p) fmt_swset(p->model, p->y, p->x, &p->set, p->from_to)); } +int fpga_switch_to_rel(struct switch_to_rel* p) +{ + struct sw_conns conns; + int rc; + + rc = construct_sw_conns(&conns, p->model, p->start_y, p->start_x, + p->start_switch, p->from_to, SW_SET_SIZE); + if (rc) FAIL(rc); + p->set.len = 0; + while (fpga_switch_conns(&conns) != NO_CONN) { + if (conns.dest_y != p->start_y + p->rel_y + || conns.dest_x != p->start_x + p->rel_x) + continue; + if (p->target_connpt != STRIDX_NO_ENTRY + && conns.dest_str_i != p->target_connpt) + continue; + p->set = conns.chain.set; + p->dest_y = conns.dest_y; + p->dest_x = conns.dest_x; + p->dest_connpt = conns.dest_str_i; + break; + } + destruct_sw_conns(&conns); + return 0; +fail: + return rc; +} + +void printf_switch_to_rel_result(struct switch_to_rel* p) +{ + printf("switch_to_rel() from y%02i x%02i connpt %s (%s)\n", + p->start_y, p->start_x, strarray_lookup(&p->model->str, p->start_switch), + p->from_to == SW_FROM ? "SW_FROM" : "SW_TO"); + printf(" %s y%02i x%02i %s via %s\n", + p->from_to == SW_FROM ? "to" : "from", + p->dest_y, p->dest_x, + strarray_lookup(&p->model->str, p->dest_connpt), + fmt_swset(p->model, p->start_y, p->start_x, &p->set, p->from_to)); +} + #define NET_ALLOC_INCREMENT 64 static int fpga_net_useidx(struct fpga_model* model, net_idx_t new_idx) @@ -1551,7 +1639,8 @@ struct fpga_net* fpga_net_get(struct fpga_model* model, net_idx_t net_i) } int fpga_net_add_port(struct fpga_model* model, net_idx_t net_i, - int y, int x, dev_idx_t dev_idx, pinw_idx_t pinw_idx) + int y, int x, enum fpgadev_type type, dev_type_idx_t type_idx, + pinw_idx_t pinw_idx) { struct fpga_net* net; int rc; @@ -1565,7 +1654,8 @@ int fpga_net_add_port(struct fpga_model* model, net_idx_t net_i, net->el[net->len].y = y; net->el[net->len].x = x; net->el[net->len].idx = pinw_idx | NET_IDX_IS_PINW; - net->el[net->len].dev_idx = dev_idx; + net->el[net->len].dev_idx = fpga_dev_idx(model, y, x, type, type_idx); + if (net->el[net->len].dev_idx == NO_DEV) FAIL(EINVAL); net->len++; return 0; fail: @@ -1599,6 +1689,45 @@ fail: return rc; } +int fpga_net_remove_sw(struct fpga_model* model, net_idx_t net_i, + int y, int x, const swidx_t* switches, int num_sw) +{ + struct fpga_net* net; + int i, j, rc; + + if (net_i > model->highest_used_net) + FAIL(EINVAL); + net = &model->nets[net_i-1]; + if (!net->len) { + HERE(); + return 0; + } + for (i = 0; i < num_sw; i++) { + for (j = 0; j < net->len; j++) { + if (net->el[j].y == y + && net->el[j].x == x + && net->el[j].idx == switches[i]) + break; + } + if (j >= net->len) { + // for now we expect the 'to-be-removed' + // switches to be in the net + HERE(); + continue; + } + if (!fpga_switch_is_used(model, y, x, switches[i])) + HERE(); + fpga_switch_disable(model, y, x, switches[i]); + if (net->len > j+1) + memmove(&net->el[j], &net->el[j+1], + (net->len-j-1)*sizeof(net->el[0])); + net->len--; + } + return 0; +fail: + return rc; +} + void fpga_net_free_all(struct fpga_model* model) { free(model->nets); diff --git a/control.h b/control.h index 30d7e7a..a58b6bf 100644 --- a/control.h +++ b/control.h @@ -38,9 +38,13 @@ dev_type_idx_t fdev_typeidx(struct fpga_model* model, int y, int x, pinw_idx_t fdev_pinw_str2idx(int devtype, const char* str, int len); // returns 0 when idx not found for the given devtype const char* fdev_pinw_idx2str(int devtype, pinw_idx_t idx); + // ld1_type can be LOGIC_M or LOGIC_L to specify whether -// we are in a XM or XL column. +// we are in a XM or XL column. You can |LD1 to idx for +// the second logic device (L or M). const char* fdev_logic_pinstr(pinw_idx_t idx, int ld1_type); +str16_t fdev_logic_pinstr_i(struct fpga_model* model, pinw_idx_t idx, int ld1_type); +int fdev_logic_inbit(pinw_idx_t idx, int ld1_type); // lut_a2d is LUT_A to LUT_D value, lut_5or6 is int 5 or int 6. int fdev_logic_set_lut(struct fpga_model* model, int y, int x, int type_idx, @@ -247,7 +251,30 @@ struct switch_to_yx }; int fpga_switch_to_yx(struct switch_to_yx* p); -void printf_switch_to_result(struct switch_to_yx* p); +void printf_switch_to_yx_result(struct switch_to_yx* p); + +struct switch_to_rel +{ + // input: + struct fpga_model* model; + int start_y; + int start_x; + str16_t start_switch; + int from_to; + int rel_y; + int rel_x; + str16_t target_connpt; // can be STRIDX_NO_ENTRY + + // output: + struct sw_set set; + int dest_y; + int dest_x; + str16_t dest_connpt; +}; + +// if no switches are found, the returned set.len will be 0. +int fpga_switch_to_rel(struct switch_to_rel* p); +void printf_switch_to_rel_result(struct switch_to_rel* p); // // nets @@ -289,9 +316,11 @@ void fpga_net_delete(struct fpga_model* model, net_idx_t net_idx); int fpga_net_enum(struct fpga_model* model, net_idx_t last, net_idx_t* next); struct fpga_net* fpga_net_get(struct fpga_model* model, net_idx_t net_i); int fpga_net_add_port(struct fpga_model* model, net_idx_t net_i, - int y, int x, dev_idx_t dev_idx, pinw_idx_t pinw_idx); + int y, int x, enum fpgadev_type type, dev_type_idx_t type_idx, pinw_idx_t pinw_idx); int fpga_net_add_sw(struct fpga_model* model, net_idx_t net_i, int y, int x, const swidx_t* switches, int num_sw); +int fpga_net_remove_sw(struct fpga_model* model, net_idx_t net_i, + int y, int x, const swidx_t* switches, int num_sw); void fpga_net_free_all(struct fpga_model* model); void fprintf_net(FILE* f, struct fpga_model* model, net_idx_t net_i); diff --git a/floorplan.c b/floorplan.c index ef6fbe3..3351c51 100644 --- a/floorplan.c +++ b/floorplan.c @@ -775,7 +775,6 @@ static void read_net_line(struct fpga_model* model, const char* line, int start) enum fpgadev_type dev_type; char buf[1024]; net_idx_t net_idx; - dev_idx_t dev_idx; pinw_idx_t pinw_idx; int sw_is_bidir; @@ -872,14 +871,12 @@ static void read_net_line(struct fpga_model* model, const char* line, int start) { HERE(); return; } dev_type = fdev_str2type(&line[dev_str_beg], dev_str_end-dev_str_beg); if (dev_type == DEV_NONE) { HERE(); return; } - dev_idx = fpga_dev_idx(model, y_coord, x_coord, dev_type, - to_i(&line[dev_type_idx_str_beg], - dev_type_idx_str_end-dev_type_idx_str_beg)); - if (dev_idx == NO_DEV) { HERE(); return; } pinw_idx = fdev_pinw_str2idx(dev_type, &line[pin_name_beg], pin_name_end-pin_name_beg); if (pinw_idx == PINW_NO_IDX) { HERE(); return; } - if (fpga_net_add_port(model, net_idx, y_coord, x_coord, dev_idx, pinw_idx)) + if (fpga_net_add_port(model, net_idx, y_coord, x_coord, dev_type, + to_i(&line[dev_type_idx_str_beg], dev_type_idx_str_end + -dev_type_idx_str_beg), pinw_idx)) HERE(); } diff --git a/model_conns.c b/model_conns.c index bce9fa4..dc9ee73 100644 --- a/model_conns.c +++ b/model_conns.c @@ -1767,153 +1767,210 @@ static int run_direction_wires(struct fpga_model* model) int x, y, i, j, _row_num, _row_pos, rc; struct w_net net; - // SS4 + // todo: EL1, ER1, WR1, WL1 + + // SR1 for (x = 0; x < model->x_width; x++) { if (!is_atx(X_ROUTING_COL, model, x)) continue; - // some wiring at the top - net.last_inc = 3; - for (i = 1; i < 5; i++) { // go through "BAMCE" - net.pts[0].start_count = 0; - net.pts[0].y = TOP_TERM(model); - net.pts[0].x = x; - net.pts[0].name = pf("SS4%c%%i", s_4wire[i]); - for (j = i; j < 5; j++) { - net.pts[j-i+1].start_count = 0; - net.pts[j-i+1].y = TOP_TERM(model)+(j-i+1); - net.pts[j-i+1].x = x; - net.pts[j-i+1].name = pf("SS4%c%%i", s_4wire[j]); - } - net.pts[j-i+1].name = ""; - if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; - if ((rc = wire_SS4E_N3(model, &net))) goto xout; - } - // rest going down to bottom termination - for (y = 0; y < model->y_height; y++) { - is_in_row(model, y, &_row_num, &_row_pos); - if (is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x) - && y > BOT_TERM(model)-5) - break; - if (_row_pos < 0 || _row_pos == 8) + for (y = TOP_OUTER_IO; y <= model->y_height-BOT_OUTER_IO; y++) { + if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y)) continue; - - net.last_inc = 3; - j = 0; - for (i = 0; i < 5; i++) { // go through "BAMCE" - net.pts[j].start_count = 0; - net.pts[j].y = y+j; - net.pts[j].x = x; - if (y+j == BOT_TERM(model)) { - EXIT(!i); - net.pts[j].name = pf("SS4%c%%i", s_4wire[i-1]); - j++; - break; + if (is_aty(Y_INNER_BOTTOM, model, y+1)) { + if (!is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) { + { struct w_net n = { + 3, + {{ "SR1B%i", 0, y, x }, + { "SR1B%i", 0, y+1, x }, + { "" }}}; + if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; } + if ((rc = add_conn_bi_pref(model, y, x, "SR1E_N3", y+1, x, "SR1E_N3"))) goto xout; } - if (IS_CENTER_Y(y+j, model) - || pos_in_row(y+j, model) == HCLK_POS) { - EXIT(!i); - net.pts[j].name = pf("SS4%c%%i", s_4wire[i-1]); - j++; - net.pts[j].start_count = 0; - net.pts[j].y = y+j; - net.pts[j].x = x; - } - net.pts[j].name = pf("SS4%c%%i", s_4wire[i]); - j++; + continue; + } + if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y+1)) { + { struct w_net n = { + 3, + {{ "SR1B%i", 0, y, x }, + { "SR1B%i", 0, y+1, x }, + { "SR1E%i", 0, y+2, x }, + { "" }}}; + if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; } + { struct w_net n = { + 0, + {{ "SR1E_N3", 0, y, x }, + { "SR1E_N3", 0, y+1, x }, + { "SR1E3", 0, y+2, x }, + { "" }}}; + if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; } + if ((rc = add_conn_bi_pref(model, y+1, x, "SR1E_N3", y, x, "SR1B3"))) goto xout; + if ((rc = add_conn_bi_pref(model, y+1, x, "SR1B3", y, x, "SR1E_N3"))) goto xout; + continue; + } + { struct w_net n = { + 3, + {{ "SR1B%i", 0, y, x }, + { "SR1E%i", 0, y+1, x }, + { "" }}}; + if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; } + if ((rc = add_conn_bi_pref(model, y+1, x, "SR1E3", y, x, "SR1E_N3"))) goto xout; + if (is_aty(Y_INNER_TOP, model, y-1)) { + { struct w_net n = { + 3, + {{ "SR1E%i", 0, y-1, x }, + { "SR1E%i", 0, y, x }, + { "" }}}; + if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; } + if ((rc = add_conn_bi_pref(model, y, x, "SR1E3", y-1, x, "SR1E_N3"))) goto xout; } - net.pts[j].name = ""; - if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; - if ((rc = wire_SS4E_N3(model, &net))) goto xout; } } - // NN4 + // NL1 for (x = 0; x < model->x_width; x++) { if (!is_atx(X_ROUTING_COL, model, x)) continue; - for (y = 0; y < model->y_height; y++) { - is_in_row(model, y, &_row_num, &_row_pos); - if (_row_pos >= 0 && _row_pos != 8) { - net.last_inc = 3; - j = 0; - for (i = 0; i < 5; i++) { // go through "BAMCE" - net.pts[j].start_count = 0; - net.pts[j].y = y-j; - net.pts[j].x = x; - if (y-j == TOP_INNER_ROW) { - EXIT(!i); - net.pts[j].name = pf("NN4%c%%i", s_4wire[i-1]); - j++; - break; - } - net.pts[j].name = pf("NN4%c%%i", s_4wire[i]); - if (IS_CENTER_Y(y-j, model) - || pos_in_row(y-j, model) == HCLK_POS) { - EXIT(!i); - i--; - } - j++; - } - net.pts[j].name = ""; - if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; + for (y = TOP_OUTER_IO; y <= model->y_height-BOT_OUTER_IO; y++) { + if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y)) + continue; + if (is_aty(Y_INNER_TOP, model, y-1)) { + { struct w_net n = { + 3, + {{ "NL1B%i", 0, y-1, x }, + { "NL1B%i", 0, y, x }, + { "" }}}; + if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; } + if ((rc = add_conn_bi_pref(model, y, x, "NL1E_S0", y-1, x, "NL1E_S0"))) goto xout; + continue; + } + if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y-1)) { + { struct w_net n = { + 3, + {{ "NL1E%i", 0, y-2, x }, + { "NL1E%i", 0, y-1, x }, + { "NL1B%i", 0, y, x }, + { "" }}}; + if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; } + { struct w_net n = { + 0, + {{ "NL1E0", 0, y-2, x }, + { "NL1E_S0", 0, y-1, x }, + { "NL1E_S0", 0, y, x }, + { "" }}}; + if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; } + if ((rc = add_conn_bi_pref(model, y-1, x, "NL1E_S0", y, x, "NL1B0"))) goto xout; + if ((rc = add_conn_bi_pref(model, y-1, x, "NL1E0", y, x, "NL1E_S0"))) goto xout; + continue; + } + { struct w_net n = { + 3, + {{ "NL1E%i", 0, y-1, x }, + { "NL1B%i", 0, y, x }, + { "" }}}; + if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; } + if ((rc = add_conn_bi_pref(model, y-1, x, "NL1E0", y, x, "NL1E_S0"))) goto xout; + if (is_aty(Y_INNER_BOTTOM, model, y+1) && !is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) { + { struct w_net n = { + 3, + {{ "NL1E%i", 0, y, x }, + { "NL1E%i", 0, y+1, x }, + { "" }}}; + if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; } + if ((rc = add_conn_bi_pref(model, y, x, "NL1E0", y+1, x, "NL1E_S0"))) goto xout; } } - if (!is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) { - net.last_inc = 3; - for (i = 1; i < 5; i++) { // go through "BAMCE" - net.pts[0].start_count = 0; - net.pts[0].y = BOT_TERM(model); - net.pts[0].x = x; - net.pts[0].name = pf("NN4%c%%i", s_4wire[i]); - for (j = i; j < 5; j++) { - net.pts[j-i+1].start_count = 0; - net.pts[j-i+1].y = BOT_TERM(model)-(j-i+1); - net.pts[j-i+1].x = x; - net.pts[j-i+1].name = pf("NN4%c%%i", s_4wire[j]); + } + + // SL1 + for (x = 0; x < model->x_width; x++) { + if (!is_atx(X_ROUTING_COL, model, x)) + continue; + for (y = TOP_OUTER_IO; y <= model->y_height-BOT_OUTER_IO; y++) { + if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y)) + continue; + if (is_aty(Y_INNER_BOTTOM, model, y+1)) { + if (!is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) { + { struct w_net n = { + 3, + {{ "SL1B%i", 0, y, x }, + { "SL1B%i", 0, y+1, x }, + { "" }}}; + if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; } } - net.pts[j-i+1].name = ""; - if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; + continue; + } + if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y+1)) { + { struct w_net n = { + 3, + {{ "SL1B%i", 0, y, x }, + { "SL1B%i", 0, y+1, x }, + { "SL1E%i", 0, y+2, x }, + { "" }}}; + if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; } + continue; + } + { struct w_net n = { + 3, + {{ "SL1B%i", 0, y, x }, + { "SL1E%i", 0, y+1, x }, + { "" }}}; + if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; } + if (is_aty(Y_INNER_TOP, model, y-1)) { + { struct w_net n = { + 3, + {{ "SL1E%i", 0, y-1, x }, + { "SL1E%i", 0, y, x }, + { "" }}}; + if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; } + } + } + } + + // NR1 + for (x = 0; x < model->x_width; x++) { + if (!is_atx(X_ROUTING_COL, model, x)) + continue; + for (y = TOP_OUTER_IO; y <= model->y_height-BOT_OUTER_IO; y++) { + if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y)) + continue; + if (is_aty(Y_INNER_TOP, model, y-1)) { + { struct w_net n = { + 3, + {{ "NR1B%i", 0, y, x }, + { "NR1B%i", 0, y-1, x }, + { "" }}}; + if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; } + continue; + } + if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y-1)) { + { struct w_net n = { + 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, &n))) goto xout; } + continue; + } + { struct w_net n = { + 3, + {{ "NR1B%i", 0, y, x }, + { "NR1E%i", 0, y-1, x }, + { "" }}}; + if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; } + if (is_aty(Y_INNER_BOTTOM, model, y+1) && !is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) { + { struct w_net n = { + 3, + {{ "NR1E%i", 0, y, x }, + { "NR1E%i", 0, y+1, x }, + { "" }}}; + if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; } } } } 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 n = { - 3, - {{ "NR1B%i", 0, y, x }, - { "NR1B%i", 0, y-1, x }, - { "" }}}; - if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; } - } else if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y-1)) { - { struct w_net n = { - 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, &n))) goto xout; } - } else { - { struct w_net n = { - 3, - {{ "NR1B%i", 0, y, x }, - { "NR1E%i", 0, y-1, x }, - { "" }}}; - if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; } - if (is_aty(Y_INNER_BOTTOM, model, y+1) && !is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) { - { struct w_net n = { - 3, - {{ "NR1E%i", 0, y, x }, - { "NR1E%i", 0, y+1, x }, - { "" }}}; - if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; } - } - } - } - // NN2 if (is_atyx(YX_ROUTING_TILE, model, y, x)) { if (is_aty(Y_INNER_TOP, model, y-1)) { @@ -2067,6 +2124,116 @@ static int run_direction_wires(struct fpga_model* model) } } } + + // SS4 + for (x = 0; x < model->x_width; x++) { + if (!is_atx(X_ROUTING_COL, model, x)) + continue; + // some wiring at the top + net.last_inc = 3; + for (i = 1; i < 5; i++) { // go through "BAMCE" + net.pts[0].start_count = 0; + net.pts[0].y = TOP_TERM(model); + net.pts[0].x = x; + net.pts[0].name = pf("SS4%c%%i", s_4wire[i]); + for (j = i; j < 5; j++) { + net.pts[j-i+1].start_count = 0; + net.pts[j-i+1].y = TOP_TERM(model)+(j-i+1); + net.pts[j-i+1].x = x; + net.pts[j-i+1].name = pf("SS4%c%%i", s_4wire[j]); + } + net.pts[j-i+1].name = ""; + if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; + if ((rc = wire_SS4E_N3(model, &net))) goto xout; + } + // rest going down to bottom termination + for (y = 0; y < model->y_height; y++) { + is_in_row(model, y, &_row_num, &_row_pos); + if (is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x) + && y > BOT_TERM(model)-5) + break; + if (_row_pos < 0 || _row_pos == 8) + continue; + + net.last_inc = 3; + j = 0; + for (i = 0; i < 5; i++) { // go through "BAMCE" + net.pts[j].start_count = 0; + net.pts[j].y = y+j; + net.pts[j].x = x; + if (y+j == BOT_TERM(model)) { + EXIT(!i); + net.pts[j].name = pf("SS4%c%%i", s_4wire[i-1]); + j++; + break; + } + if (IS_CENTER_Y(y+j, model) + || pos_in_row(y+j, model) == HCLK_POS) { + EXIT(!i); + net.pts[j].name = pf("SS4%c%%i", s_4wire[i-1]); + j++; + net.pts[j].start_count = 0; + net.pts[j].y = y+j; + net.pts[j].x = x; + } + net.pts[j].name = pf("SS4%c%%i", s_4wire[i]); + j++; + } + net.pts[j].name = ""; + if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; + if ((rc = wire_SS4E_N3(model, &net))) goto xout; + } + } + + // NN4 + for (x = 0; x < model->x_width; x++) { + if (!is_atx(X_ROUTING_COL, model, x)) + continue; + for (y = 0; y < model->y_height; y++) { + is_in_row(model, y, &_row_num, &_row_pos); + if (_row_pos >= 0 && _row_pos != 8) { + net.last_inc = 3; + j = 0; + for (i = 0; i < 5; i++) { // go through "BAMCE" + net.pts[j].start_count = 0; + net.pts[j].y = y-j; + net.pts[j].x = x; + if (y-j == TOP_INNER_ROW) { + EXIT(!i); + net.pts[j].name = pf("NN4%c%%i", s_4wire[i-1]); + j++; + break; + } + net.pts[j].name = pf("NN4%c%%i", s_4wire[i]); + if (IS_CENTER_Y(y-j, model) + || pos_in_row(y-j, model) == HCLK_POS) { + EXIT(!i); + i--; + } + j++; + } + net.pts[j].name = ""; + if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; + } + } + if (!is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) { + net.last_inc = 3; + for (i = 1; i < 5; i++) { // go through "BAMCE" + net.pts[0].start_count = 0; + net.pts[0].y = BOT_TERM(model); + net.pts[0].x = x; + net.pts[0].name = pf("NN4%c%%i", s_4wire[i]); + for (j = i; j < 5; j++) { + net.pts[j-i+1].start_count = 0; + net.pts[j-i+1].y = BOT_TERM(model)-(j-i+1); + net.pts[j-i+1].x = x; + net.pts[j-i+1].name = pf("NN4%c%%i", s_4wire[j]); + } + net.pts[j-i+1].name = ""; + if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout; + } + } + } return 0; xout: return rc;