From a3f42ee998b064a7002a13a064ee9cb06b26b5b6 Mon Sep 17 00:00:00 2001 From: Wolfgang Spraul Date: Mon, 10 Dec 2012 22:17:01 -0500 Subject: [PATCH] more clock routing --- autotest.c | 30 +++- libs/bit_frames.c | 79 ++++++++- libs/control.c | 394 ++++++++++++++++++++++++++++++++++---------- libs/control.h | 29 +++- libs/helper.c | 16 +- libs/helper.h | 2 +- libs/model.h | 4 + libs/model_helper.c | 23 +++ libs/parts.c | 11 +- libs/parts.h | 6 + 10 files changed, 492 insertions(+), 102 deletions(-) diff --git a/autotest.c b/autotest.c index a0f201e..a72612a 100644 --- a/autotest.c +++ b/autotest.c @@ -22,6 +22,7 @@ time_t g_start_time; struct test_state { int cmdline_skip; + int cmdline_count; char cmdline_diff_exec[1024]; int dry_run; int diff_to_null; @@ -78,6 +79,11 @@ static int diff_printf(struct test_state* tstate) printf("O Skipping diff %i.\n", tstate->next_diff_counter++); return 0; } + if (tstate->cmdline_count != -1 + && tstate->next_diff_counter >= tstate->cmdline_skip + tstate->cmdline_count + 1) { + printf("\nO Finished %i tests.\n", tstate->cmdline_count); + exit(0); + } snprintf(path, sizeof(path), "%s/autotest_%s_%06i", tstate->tmp_dir, tstate->base_name, tstate->next_diff_counter); @@ -561,6 +567,7 @@ static int test_routing_sw_from_logic(struct test_state* tstate, swto.start_switch = fdev_logic_pinstr_i(tstate->model, dev->pinw_req_for_cfg[0]|LD1, LOGIC_M); swto.from_to = SW_TO; + swto.flags = SWTO_REL_DEFAULT; swto.rel_y = 0; swto.rel_x = -1; swto.target_connpt = STRIDX_NO_ENTRY; @@ -1061,7 +1068,8 @@ static int test_logic(struct test_state* tstate, int y, int x, int type_idx, || (latch_logic && (dev->pinw_req_for_cfg[i] == LI_CLK || dev->pinw_req_for_cfg[i] == LI_CE))) { - rc = fnet_route_to_inpins(tstate->model, pinw_nets[i], "VCC_WIRE"); + rc = fnet_route_to_inpins_s(tstate->model, + pinw_nets[i], "VCC_WIRE"); if (rc) FAIL(rc); } } @@ -1745,6 +1753,9 @@ static int test_clock_routing(struct test_state* tstate) rc = fpga_find_iob(tstate->model, tstate->model->pkg->gclk_pin[i], &iob_clk_y, &iob_clk_x, &iob_clk_type_idx); if (rc) FAIL(rc); + printf("\nO test %i: gclk pin %s (y%02i x%02i IOB %i)\n", + tstate->next_diff_counter, tstate->model->pkg->gclk_pin[i], + iob_clk_y, iob_clk_x, iob_clk_type_idx); rc = fdev_iob_input(tstate->model, iob_clk_y, iob_clk_x, iob_clk_type_idx, IO_LVCMOS33); if (rc) FAIL(rc); @@ -1782,7 +1793,6 @@ static int test_clock_routing(struct test_state* tstate) logic_type_idx); fdev_delete(tstate->model, iob_clk_y, iob_clk_x, DEV_IOB, iob_clk_type_idx); -break; } return 0; fail: @@ -1796,8 +1806,8 @@ static void printf_help(const char* argv_0, const char** available_tests) printf( "\n" "fpgatools automatic test suite\n" "\n" - "Usage: %s [--test=] [--skip=] [--dry-run]\n" - " %*s [--diff=]\n" + "Usage: %s [--test=] [--skip=] [--count=]\n" + " %*s [--dry-run] [--diff=]\n" "Default diff executable: " DEFAULT_DIFF_EXEC "\n" "Output dir: " AUTOTEST_TMP_DIR "\n", argv_0, (int) strlen(argv_0), ""); @@ -1818,7 +1828,7 @@ int main(int argc, char** argv) struct fpga_model model; struct test_state tstate; char param[1024], cmdline_test[1024]; - int i, param_skip, rc; + int i, param_skip, param_count, rc; const char* available_tests[] = { "logic_cfg", "routing_sw", "io_sw", "iob_cfg", "lut_encoding", "bufg_cfg", "bufio_cfg", "pll_cfg", @@ -1840,6 +1850,7 @@ int main(int argc, char** argv) memset(&tstate, 0, sizeof(tstate)); tstate.cmdline_skip = -1; + tstate.cmdline_count = -1; tstate.cmdline_diff_exec[0] = 0; cmdline_test[0] = 0; tstate.dry_run = -1; @@ -1871,6 +1882,14 @@ int main(int argc, char** argv) tstate.cmdline_skip = param_skip; continue; } + if (sscanf(argv[i], "--count=%i", ¶m_count) == 1) { + if (tstate.cmdline_count != -1) { + printf_help(argv[0], available_tests); + return EINVAL; + } + tstate.cmdline_count = param_count; + continue; + } if (!strcmp(argv[i], "--dry-run")) { tstate.dry_run = 1; continue; @@ -1910,6 +1929,7 @@ int main(int argc, char** argv) printf("O Test: %s\n", cmdline_test); printf("O Diff: %s\n", tstate.cmdline_diff_exec); printf("O Skip: %i\n", tstate.cmdline_skip); + printf("O Count: %i\n", tstate.cmdline_count); printf("O Dry run: %i\n", tstate.dry_run); printf("\n"); printf("O Time measured in seconds from 0.\n"); diff --git a/libs/bit_frames.c b/libs/bit_frames.c index 1f972dc..6f26eae 100644 --- a/libs/bit_frames.c +++ b/libs/bit_frames.c @@ -106,7 +106,7 @@ static int find_es_switch(struct extract_state* es, int y, int x, swidx_t sw) return 0; } -static int write_iobs(struct fpga_bits* bits, struct fpga_model* model) +static int write_type2(struct fpga_bits* bits, struct fpga_model* model) { int i, y, x, type_idx, part_idx, dev_idx, first_iob, rc; struct fpga_device* dev; @@ -571,6 +571,79 @@ fail: return rc; } +static int extract_type2(struct extract_state* es) +{ + int i, bits_off; + uint16_t u16; + + RC_CHECK(es->model); + extract_iobs(es); + for (i = 0; i < es->model->pkg->num_gclk_pins; i++) { + if (!es->model->pkg->gclk_pin[i]) + continue; + bits_off = IOB_DATA_START + + es->model->pkg->gclk_type2_o[i]*XC6_WORD_BYTES + + XC6_TYPE2_GCLK_REG_SW/XC6_WORD_BITS; + u16 = frame_get_u16(&es->bits->d[bits_off]); + if (!u16) + continue; + if (u16 & (1<<(XC6_TYPE2_GCLK_REG_SW%XC6_WORD_BITS))) { + int iob_y, iob_x, iob_idx; + struct fpga_device *iob_dev; + struct switch_to_yx_l2 switch_to_yx_l2; + struct switch_to_rel switch_to_rel; + + // + // find and enable reg-switch for gclk_pin[i] + // + + fpga_find_iob(es->model, es->model->pkg->gclk_pin[i], + &iob_y, &iob_x, &iob_idx); + RC_CHECK(es->model); + iob_dev = fdev_p(es->model, iob_y, iob_x, DEV_IOB, iob_idx); + RC_ASSERT(es->model, iob_dev); + + switch_to_yx_l2.l1.yx_req = YX_X_CENTER_CMTPLL | YX_Y_CENTER; + switch_to_yx_l2.l1.flags = SWTO_YX_CLOSEST; + switch_to_yx_l2.l1.model = es->model; + switch_to_yx_l2.l1.y = iob_y; + switch_to_yx_l2.l1.x = iob_x; + switch_to_yx_l2.l1.start_switch = iob_dev->pinw[IOB_OUT_I]; + switch_to_yx_l2.l1.from_to = SW_FROM; + fpga_switch_to_yx_l2(&switch_to_yx_l2); + RC_CHECK(es->model); + if (!switch_to_yx_l2.l1.set.len) + { HERE(); continue; } + + switch_to_rel.model = es->model; + switch_to_rel.start_y = switch_to_yx_l2.l1.dest_y; + switch_to_rel.start_x = switch_to_yx_l2.l1.dest_x; + switch_to_rel.start_switch = switch_to_yx_l2.l1.dest_connpt; + switch_to_rel.from_to = SW_FROM; + switch_to_rel.flags = SWTO_REL_WEAK_TARGET; + switch_to_rel.rel_y = es->model->center_y - switch_to_rel.start_y; + switch_to_rel.rel_x = es->model->center_x - switch_to_rel.start_x; + switch_to_rel.target_connpt = STRIDX_NO_ENTRY; + fpga_switch_to_rel(&switch_to_rel); + RC_CHECK(es->model); + if (!switch_to_rel.set.len) + { HERE(); continue; } + if (switch_to_rel.set.len != 1) HERE(); + + RC_ASSERT(es->model, es->num_yx_pos < MAX_YX_SWITCHES); + es->yx_pos[es->num_yx_pos].y = switch_to_rel.start_y; + es->yx_pos[es->num_yx_pos].x = switch_to_rel.start_x; + es->yx_pos[es->num_yx_pos].idx = switch_to_rel.set.sw[0]; + es->num_yx_pos++; + + u16 &= ~(1<<(XC6_TYPE2_GCLK_REG_SW%XC6_WORD_BITS)); + } + if (u16) HERE(); + frame_set_u16(&es->bits->d[bits_off], u16); + } + RC_RETURN(es->model); +} + static int lut2str(uint64_t lut, int lut_pos, int lut5_used, char *lut6_buf, char** lut6_p, char *lut5_buf, char** lut5_p) { @@ -1854,7 +1927,7 @@ int extract_model(struct fpga_model* model, struct fpga_bits* bits) rc = extract_switches(&es); if (rc) RC_FAIL(model, rc); - rc = extract_iobs(&es); + rc = extract_type2(&es); if (rc) RC_FAIL(model, rc); rc = extract_logic(&es); if (rc) RC_FAIL(model, rc); @@ -2230,7 +2303,7 @@ int write_model(struct fpga_bits* bits, struct fpga_model* model) for (i = 0; i < sizeof(s_default_bits)/sizeof(s_default_bits[0]); i++) set_bitp(bits, &s_default_bits[i]); write_switches(bits, model); - write_iobs(bits, model); + write_type2(bits, model); write_logic(bits, model); RC_RETURN(model); diff --git a/libs/control.c b/libs/control.c index ef67202..46ab58d 100644 --- a/libs/control.c +++ b/libs/control.c @@ -8,6 +8,10 @@ #include "model.h" #include "control.h" +#undef DBG_ENUM_SWITCH +#undef DBG_SWITCH_TO_YX +#undef DBG_SWITCH_TO_REL + struct iob_site { int xy; @@ -1574,14 +1578,11 @@ const char* fmt_swset(struct fpga_model* model, int y, int x, return buf[last_buf]; } -#undef DBG_ENUM_SWITCH - int construct_sw_chain(struct sw_chain* chain, struct fpga_model* model, int y, int x, str16_t start_switch, int from_to, int max_depth, swidx_t* block_list, int block_list_len) { - int rc; - + RC_CHECK(model); #ifdef DBG_ENUM_SWITCH printf("construct_sw_chain() %s (%s)\n", strarray_lookup(&model->str, start_switch), @@ -1601,7 +1602,7 @@ int construct_sw_chain(struct sw_chain* chain, struct fpga_model* model, chain->internal_block_list = malloc( MAX_SWITCHBOX_SIZE * sizeof(*chain->block_list)); if (!chain->internal_block_list) - FAIL(ENOMEM); + RC_FAIL(model, ENOMEM); chain->block_list = chain->internal_block_list; chain->block_list_len = 0; } @@ -1612,9 +1613,7 @@ int construct_sw_chain(struct sw_chain* chain, struct fpga_model* model, chain->first_round = 1; chain->set.len = 1; chain->set.sw[0] = FIRST_SW | start_switch; - return 0; -fail: - return rc; + RC_RETURN(model); } void destruct_sw_chain(struct sw_chain* chain) @@ -1824,7 +1823,7 @@ int construct_sw_conns(struct sw_conns* conns, struct fpga_model* model, memset(conns, 0, sizeof(*conns)); construct_sw_chain(&conns->chain, model, y, x, start_switch, from_to, max_depth, /*block_list*/ 0, /*block_list_len*/ 0); - return 0; + RC_RETURN(model); } void destruct_sw_conns(struct sw_conns* conns) @@ -1915,41 +1914,54 @@ int fpga_switch_to_yx(struct switch_to_yx* p) struct sw_conns conns; struct sw_set best_set; int best_y, best_x, best_distance, distance; - int best_num_dests, rc; + int best_num_dests; str16_t best_connpt; RC_CHECK(p->model); - rc = construct_sw_conns(&conns, p->model, p->y, p->x, p->start_switch, +#ifdef DBG_SWITCH_TO_YX + printf("fpga_switch_to_yx() %s y%02i-x%02i-%s yx_req %Xh flags %Xh\n", + p->from_to == SW_FROM ? "SW_FROM" : "SW_TO", + p->y, p->x, strarray_lookup(&p->model->str, p->start_switch), + p->yx_req, p->flags); +#endif + construct_sw_conns(&conns, p->model, p->y, p->x, p->start_switch, p->from_to, (p->flags & SWTO_YX_MAX_SWITCH_DEPTH) ? p->max_switch_depth : SW_SET_SIZE); - if (rc) FAIL(rc); + RC_CHECK(p->model); best_y = -1; while (fpga_switch_conns(&conns) != NO_CONN) { - if (is_atyx(p->yx_req, p->model, conns.dest_y, conns.dest_x)) { - if (p->flags & SWTO_YX_TARGET_CONNPT - && conns.dest_str_i != p->target_connpt) - continue; - if (best_y != -1) { - distance = abs(conns.dest_y-p->y) - +abs(conns.dest_x-p->x); - if (distance > best_distance) - continue; - else if (conns.num_dests > best_num_dests) - continue; - else if (conns.chain.set.len > best_set.len) - continue; - } - best_set = conns.chain.set; - best_y = conns.dest_y; - best_x = conns.dest_x; - best_num_dests = conns.num_dests; - best_connpt = conns.dest_str_i; - best_distance = abs(conns.dest_y-p->y) + if (!is_atyx(p->yx_req, p->model, conns.dest_y, conns.dest_x)) + continue; +#ifdef DBG_SWITCH_TO_YX + printf(" sw %s conn y%02i x%02i %s\n", + fmt_swset(p->model, p->y, p->x, + &conns.chain.set, p->from_to), + conns.dest_y, conns.dest_x, + strarray_lookup(&p->model->str, conns.dest_str_i)); +#endif + if (p->flags & SWTO_YX_TARGET_CONNPT + && conns.dest_str_i != p->target_connpt) + continue; + if (best_y != -1) { + distance = abs(conns.dest_y-p->y) +abs(conns.dest_x-p->x); - if (!p->flags & SWTO_YX_CLOSEST) - break; + if (distance > best_distance) + continue; + else if (conns.num_dests > best_num_dests) + continue; + else if (conns.chain.set.len > best_set.len) + continue; } + best_set = conns.chain.set; + best_y = conns.dest_y; + best_x = conns.dest_x; + best_num_dests = conns.num_dests; + best_connpt = conns.dest_str_i; + best_distance = abs(conns.dest_y-p->y) + +abs(conns.dest_x-p->x); + if (!p->flags & SWTO_YX_CLOSEST) + break; } if (best_y == -1) p->set.len = 0; @@ -1960,9 +1972,7 @@ int fpga_switch_to_yx(struct switch_to_yx* p) p->dest_connpt = best_connpt; } destruct_sw_conns(&conns); - return 0; -fail: - return rc; + RC_RETURN(p->model); } void printf_switch_to_yx_result(struct switch_to_yx* p) @@ -1977,33 +1987,114 @@ void printf_switch_to_yx_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) +int fpga_switch_to_yx_l2(struct switch_to_yx_l2 *p) +{ + RC_CHECK(p->l1.model); + fpga_switch_to_yx(&p->l1); + RC_CHECK(p->l1.model); + p->l2_set.len = 0; + if (!p->l1.set.len) { + struct sw_conns conns; + struct switch_to_yx l2 = p->l1; + + construct_sw_conns(&conns, p->l1.model, p->l1.y, p->l1.x, p->l1.start_switch, + p->l1.from_to, (p->l1.flags & SWTO_YX_MAX_SWITCH_DEPTH) + ? p->l1.max_switch_depth : SW_SET_SIZE); + RC_CHECK(p->l1.model); + while (fpga_switch_conns(&conns) != NO_CONN) { + l2.y = conns.dest_y; + l2.x = conns.dest_x; + l2.start_switch = conns.dest_str_i; + fpga_switch_to_yx(&l2); + RC_CHECK(l2.model); + if (l2.set.len) { + p->l1.set = conns.chain.set; + p->l1.dest_y = l2.dest_y; + p->l1.dest_x = l2.dest_x; + p->l1.dest_connpt = l2.dest_connpt; + p->l2_set = l2.set; + p->l2_y = l2.y; + p->l2_x = l2.x; + break; + } + } + destruct_sw_conns(&conns); + } + RC_RETURN(p->l1.model); +} + +int fpga_switch_to_rel(struct switch_to_rel *p) { struct sw_conns conns; - int rc; + struct sw_set best_set; + int best_y, best_x, best_distance; + str16_t best_connpt; RC_CHECK(p->model); - rc = construct_sw_conns(&conns, p->model, p->start_y, p->start_x, +#ifdef DBG_SWITCH_TO_REL + printf("fpga_switch_to_rel() %s y%02i-x%02i-%s flags %Xh rel_y %i rel_x %i target_connpt %s\n", + p->from_to == SW_FROM ? "SW_FROM" : "SW_TO", + p->start_y, p->start_x, strarray_lookup(&p->model->str, p->start_switch), + p->flags, p->rel_y, p->rel_x, + p->target_connpt == STRIDX_NO_ENTRY ? "-" : + strarray_lookup(&p->model->str, p->target_connpt)); +#endif + 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; + RC_CHECK(p->model); + + best_y = -1; while (fpga_switch_conns(&conns) != NO_CONN) { +#ifdef DBG_SWITCH_TO_REL + printf(" sw %s conn y%02i x%02i %s\n", + fmt_swset(p->model, p->start_y, p->start_x, + &conns.chain.set, p->from_to), + conns.dest_y, conns.dest_x, + strarray_lookup(&p->model->str, conns.dest_str_i)); +#endif if (conns.dest_y != p->start_y + p->rel_y - || conns.dest_x != p->start_x + p->rel_x) + || conns.dest_x != p->start_x + p->rel_x) { + if (!(p->flags & SWTO_REL_WEAK_TARGET)) + continue; + if (best_y != -1) { + int distance = abs(conns.dest_y - (p->start_y+p->rel_y)) + + abs(conns.dest_x - (p->start_x+p->rel_x)); + if (distance > best_distance) + continue; + } + best_set = conns.chain.set; + best_y = conns.dest_y; + best_x = conns.dest_x; + best_connpt = conns.dest_str_i; + best_distance = abs(conns.dest_y - (p->start_y+p->rel_y)) + + abs(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; + best_set = conns.chain.set; + best_y = conns.dest_y; + best_x = conns.dest_x; + best_connpt = conns.dest_str_i; break; } + if (best_y == -1) + p->set.len = 0; + else { +#ifdef DBG_SWITCH_TO_REL + printf(" sw %s\n", fmt_swset(p->model, p->start_y, p->start_x, + &best_set, p->from_to)); + printf(" dest y%02i-x%02i-%s\n", best_y, best_x, + strarray_lookup(&p->model->str, best_connpt)); +#endif + p->set = best_set; + p->dest_y = best_y; + p->dest_x = best_x; + p->dest_connpt = best_connpt; + } destruct_sw_conns(&conns); - return 0; -fail: - return rc; + RC_RETURN(p->model); } void printf_switch_to_rel_result(struct switch_to_rel* p) @@ -2260,9 +2351,153 @@ void fnet_printf(FILE* f, struct fpga_model* model, net_idx_t net_i) } } +static int fnet_pinw(struct fpga_model *model, net_idx_t net_i, + int out_pinw, int idx) +{ + struct fpga_net *net_p; + struct fpga_device *dev_p; + int i, next_idx; + + if (model->rc) { HERE(); return -1; }; + net_p = fnet_get(model, net_i); + if (!net_p) { HERE(); return -1; }; + + next_idx = 0; + for (i = 0; i < net_p->len; i++) { + if (!(net_p->el[i].idx & NET_IDX_IS_PINW)) + continue; + dev_p = FPGA_DEV(model, net_p->el[i].y, + net_p->el[i].x, net_p->el[i].dev_idx); + if ((out_pinw && (net_p->el[i].idx & NET_IDX_MASK) < dev_p->num_pinw_in) + || (!out_pinw && (net_p->el[i].idx & NET_IDX_MASK) >= dev_p->num_pinw_in)) + continue; + if (next_idx == idx) + return i; + next_idx++; + } + return -1; +} + static int fnet_autoroute_clock(struct fpga_model* model, net_idx_t net_i) { - return 0; + struct fpga_net *net_p; + int out_i, in_i, hclk_y; + struct fpga_device *out_dev, *in_dev; + struct switch_to_yx_l2 switch_to_yx_l2; + struct switch_to_rel switch_to_rel; + + RC_CHECK(model); + + net_p = fnet_get(model, net_i); + if (!net_p) RC_FAIL(model, EINVAL); + + out_i = fnet_pinw(model, net_i, /*out*/ 1, 0); + in_i = fnet_pinw(model, net_i, /*out*/ 0, 0); + if (out_i == -1 || in_i == -1) + RC_FAIL(model, EINVAL); + + out_dev = FPGA_DEV(model, net_p->el[out_i].y, + net_p->el[out_i].x, net_p->el[out_i].dev_idx); + in_dev = FPGA_DEV(model, net_p->el[in_i].y, + net_p->el[in_i].x, net_p->el[in_i].dev_idx); + if (out_dev->type != DEV_IOB || in_dev->type != DEV_LOGIC) + RC_FAIL(model, ENOTSUP); + + // to regs (l2 allows one intermediate hop) + switch_to_yx_l2.l1.yx_req = YX_X_CENTER_CMTPLL | YX_Y_CENTER; + switch_to_yx_l2.l1.flags = SWTO_YX_CLOSEST; + switch_to_yx_l2.l1.model = model; + switch_to_yx_l2.l1.y = net_p->el[out_i].y; + switch_to_yx_l2.l1.x = net_p->el[out_i].x; + switch_to_yx_l2.l1.start_switch = out_dev->pinw[net_p->el[out_i].idx + & NET_IDX_MASK]; + switch_to_yx_l2.l1.from_to = SW_FROM; + fpga_switch_to_yx_l2(&switch_to_yx_l2); + RC_ASSERT(model, switch_to_yx_l2.l1.set.len); + fnet_add_sw(model, net_i, switch_to_yx_l2.l1.y, switch_to_yx_l2.l1.x, + switch_to_yx_l2.l1.set.sw, switch_to_yx_l2.l1.set.len); + if (switch_to_yx_l2.l2_set.len) + fnet_add_sw(model, net_i, switch_to_yx_l2.l2_y, switch_to_yx_l2.l2_x, + switch_to_yx_l2.l2_set.sw, switch_to_yx_l2.l2_set.len); + + // to center (possibly over intermediate) + switch_to_rel.dest_y = switch_to_yx_l2.l1.dest_y; + switch_to_rel.dest_x = switch_to_yx_l2.l1.dest_x; + switch_to_rel.dest_connpt = switch_to_yx_l2.l1.dest_connpt; + do { + switch_to_rel.model = model; + switch_to_rel.start_y = switch_to_rel.dest_y; + switch_to_rel.start_x = switch_to_rel.dest_x; + switch_to_rel.start_switch = switch_to_rel.dest_connpt; + switch_to_rel.from_to = SW_FROM; + switch_to_rel.flags = SWTO_REL_WEAK_TARGET; + switch_to_rel.rel_y = model->center_y - switch_to_rel.start_y; + switch_to_rel.rel_x = model->center_x - switch_to_rel.start_x; + switch_to_rel.target_connpt = STRIDX_NO_ENTRY; + fpga_switch_to_rel(&switch_to_rel); + RC_ASSERT(model, switch_to_rel.set.len); + fnet_add_sw(model, net_i, switch_to_rel.start_y, switch_to_rel.start_x, + switch_to_rel.set.sw, switch_to_rel.set.len); + } while (switch_to_rel.dest_y != model->center_y + || switch_to_rel.dest_x != model->center_x); + + // to hclk + RC_ASSERT(model, switch_to_rel.dest_y == model->center_y + && switch_to_rel.dest_x == model->center_x); + hclk_y = y_to_hclk(net_p->el[in_i].y, model); + RC_ASSERT(model, hclk_y != -1); + do { + switch_to_rel.model = model; + switch_to_rel.start_y = switch_to_rel.dest_y; + switch_to_rel.start_x = switch_to_rel.dest_x; + switch_to_rel.start_switch = switch_to_rel.dest_connpt; + switch_to_rel.from_to = SW_FROM; + switch_to_rel.flags = SWTO_REL_WEAK_TARGET; + switch_to_rel.rel_y = hclk_y - switch_to_rel.start_y; + switch_to_rel.rel_x = 0; + switch_to_rel.target_connpt = STRIDX_NO_ENTRY; + fpga_switch_to_rel(&switch_to_rel); + RC_ASSERT(model, switch_to_rel.set.len); + fnet_add_sw(model, net_i, switch_to_rel.start_y, switch_to_rel.start_x, + switch_to_rel.set.sw, switch_to_rel.set.len); + } while (switch_to_rel.dest_y != hclk_y); + + // to routing col + do { + switch_to_rel.model = model; + switch_to_rel.start_y = switch_to_rel.dest_y; + switch_to_rel.start_x = switch_to_rel.dest_x; + switch_to_rel.start_switch = switch_to_rel.dest_connpt; + switch_to_rel.from_to = SW_FROM; + switch_to_rel.flags = SWTO_REL_WEAK_TARGET; + switch_to_rel.rel_y = 0; + switch_to_rel.rel_x = net_p->el[in_i].x-1 - switch_to_rel.start_x; + switch_to_rel.target_connpt = STRIDX_NO_ENTRY; + fpga_switch_to_rel(&switch_to_rel); + RC_ASSERT(model, switch_to_rel.set.len); + fnet_add_sw(model, net_i, switch_to_rel.start_y, switch_to_rel.start_x, + switch_to_rel.set.sw, switch_to_rel.set.len); + } while (switch_to_rel.dest_x != net_p->el[in_i].x-1); + + // to logic device routing + switch_to_rel.model = model; + switch_to_rel.start_y = switch_to_rel.dest_y; + switch_to_rel.start_x = switch_to_rel.dest_x; + switch_to_rel.start_switch = switch_to_rel.dest_connpt; + switch_to_rel.from_to = SW_FROM; + switch_to_rel.flags = SWTO_REL_DEFAULT; + switch_to_rel.rel_y = net_p->el[in_i].y - switch_to_rel.start_y; + switch_to_rel.rel_x = net_p->el[in_i].x-1 - switch_to_rel.start_x; + switch_to_rel.target_connpt = STRIDX_NO_ENTRY; + fpga_switch_to_rel(&switch_to_rel); + RC_ASSERT(model, switch_to_rel.set.len); + fnet_add_sw(model, net_i, switch_to_rel.start_y, switch_to_rel.start_x, + switch_to_rel.set.sw, switch_to_rel.set.len); + + // connect with pinw + fnet_route_to_inpins(model, net_i, switch_to_rel.dest_connpt); + + RC_RETURN(model); } int fnet_autoroute(struct fpga_model* model, net_idx_t net_i) @@ -2294,22 +2529,9 @@ int fnet_autoroute(struct fpga_model* model, net_idx_t net_i) } // todo: gnd and vcc nets are special and have no outpin - // but lots of inpins - out_i = -1; - in_i = -1; - for (i = 0; i < net_p->len; i++) { - dev_p = FPGA_DEV(model, net_p->el[i].y, - net_p->el[i].x, net_p->el[i].dev_idx); - if ((net_p->el[i].idx & NET_IDX_MASK) < dev_p->num_pinw_in) { - // todo: right now we only support 1 inpin - if (in_i != -1) RC_FAIL(model, ENOTSUP); - in_i = i; - continue; - } - if (out_i != -1) RC_FAIL(model, EINVAL); // at most 1 outpin - out_i = i; - } - // todo: vcc and gnd have no outpin? + // but can have multiple inpins + out_i = fnet_pinw(model, net_i, /*out*/ 1, 0); + in_i = fnet_pinw(model, net_i, /*out*/ 0, 0); if (out_i == -1 || in_i == -1) RC_FAIL(model, EINVAL); @@ -2353,6 +2575,7 @@ int fnet_autoroute(struct fpga_model* model, net_idx_t net_i) switch_to_rel.start_switch = in_dev->pinw[net_p->el[in_i].idx & NET_IDX_MASK]; switch_to_rel.from_to = SW_TO; + switch_to_rel.flags = SWTO_REL_DEFAULT; switch_to_rel.rel_y = 0; switch_to_rel.rel_x = -1; switch_to_rel.target_connpt = STRIDX_NO_ENTRY; @@ -2410,6 +2633,7 @@ int fnet_autoroute(struct fpga_model* model, net_idx_t net_i) switch_to_rel.start_switch = out_dev->pinw[net_p->el[out_i].idx & NET_IDX_MASK]; switch_to_rel.from_to = SW_FROM; + switch_to_rel.flags = SWTO_REL_DEFAULT; switch_to_rel.rel_y = 0; switch_to_rel.rel_x = -1; switch_to_rel.target_connpt = STRIDX_NO_ENTRY; @@ -2435,19 +2659,16 @@ int fnet_autoroute(struct fpga_model* model, net_idx_t net_i) } int fnet_route_to_inpins(struct fpga_model* model, net_idx_t net_i, - const char* from) + str16_t from) { struct fpga_net* net_p; struct fpga_device* dev_p; - str16_t from_i; struct sw_set start_set, end_set; - int i, rc; + int i; RC_CHECK(model); net_p = fnet_get(model, net_i); - if (!net_p) FAIL(EINVAL); - from_i = strarray_find(&model->str, from); - if (from_i == STRIDX_NO_ENTRY) FAIL(EINVAL); + RC_ASSERT(model, net_p); for (i = 0; i < net_p->len; i++) { if (!(net_p->el[i].idx & NET_IDX_IS_PINW)) @@ -2459,23 +2680,30 @@ int fnet_route_to_inpins(struct fpga_model* model, net_idx_t net_i, // skip outpin continue; - rc = froute_direct(model, net_p->el[i].y, net_p->el[i].x-1, - from_i, net_p->el[i].y, net_p->el[i].x, + froute_direct(model, net_p->el[i].y, net_p->el[i].x-1, + from, net_p->el[i].y, net_p->el[i].x, dev_p->pinw[net_p->el[i].idx & NET_IDX_MASK], &start_set, &end_set); - if (rc) FAIL(rc); + RC_CHECK(model); if (!start_set.len || !end_set.len) HERE(); - rc = fnet_add_sw(model, net_i, net_p->el[i].y, + fnet_add_sw(model, net_i, net_p->el[i].y, net_p->el[i].x-1, start_set.sw, start_set.len); - if (rc) FAIL(rc); - rc = fnet_add_sw(model, net_i, net_p->el[i].y, + fnet_add_sw(model, net_i, net_p->el[i].y, net_p->el[i].x, end_set.sw, end_set.len); - if (rc) FAIL(rc); } - return 0; -fail: - return rc; + RC_RETURN(model); +} + +int fnet_route_to_inpins_s(struct fpga_model *model, net_idx_t net_i, + const char *from) +{ + str16_t from_i; + + RC_CHECK(model); + from_i = strarray_find(&model->str, from); + RC_ASSERT(model, from_i != STRIDX_NO_ENTRY); + return fnet_route_to_inpins(model, net_i, from_i); } int froute_direct(struct fpga_model* model, int start_y, int start_x, diff --git a/libs/control.h b/libs/control.h index 8e5cc94..b2f675a 100644 --- a/libs/control.h +++ b/libs/control.h @@ -268,6 +268,8 @@ void printf_swconns(struct fpga_model* model, int y, int x, str16_t sw, int from_to, int max_depth); #define SWTO_YX_DEF 0 +// SWTO_YX_CLOSEST finds the closest tile that satisfies +// the YX requirement. #define SWTO_YX_CLOSEST 0x0001 #define SWTO_YX_TARGET_CONNPT 0x0002 #define SWTO_YX_MAX_SWITCH_DEPTH 0x0004 @@ -292,8 +294,28 @@ struct switch_to_yx str16_t dest_connpt; }; -int fpga_switch_to_yx(struct switch_to_yx* p); -void printf_switch_to_yx_result(struct switch_to_yx* p); +int fpga_switch_to_yx(struct switch_to_yx *p); +void printf_switch_to_yx_result(struct switch_to_yx *p); + +struct switch_to_yx_l2 +{ + struct switch_to_yx l1; + // l2 y/x/set is inserted between l1.y/x/start_switch + // and l1.dest_y/dest_x/dest_connpt + struct sw_set l2_set; + int l2_y, l2_x; +}; + +// fpga_switch_to_yx_l2() allows for an optional intermediate tile +// to come before the yx_req. If a direct link was found, l2_set.len +// will be 0 and l2_y and l2_x are undefined. +int fpga_switch_to_yx_l2(struct switch_to_yx_l2 *p); + +#define SWTO_REL_DEFAULT 0 +// If a connection to the actal target is not found, +// WEAK_TARGET will allow to return the connection that +// reaches as close as possible to the x/y target. +#define SWTO_REL_WEAK_TARGET 0x0001 struct switch_to_rel { @@ -303,6 +325,7 @@ struct switch_to_rel int start_x; str16_t start_switch; int from_to; + int flags; // SWTO_REL-value int rel_y; int rel_x; str16_t target_connpt; // can be STRIDX_NO_ENTRY @@ -370,6 +393,8 @@ void fnet_printf(FILE* f, struct fpga_model* model, net_idx_t net_i); int fnet_autoroute(struct fpga_model* model, net_idx_t net_i); int fnet_route_to_inpins(struct fpga_model* model, net_idx_t net_i, + str16_t from); +int fnet_route_to_inpins_s(struct fpga_model* model, net_idx_t net_i, const char* from); // diff --git a/libs/helper.c b/libs/helper.c index 7a1f24d..78c7ee7 100644 --- a/libs/helper.c +++ b/libs/helper.c @@ -355,20 +355,22 @@ int parse_boolexpr(const char *expr, uint64_t *lut) return 0; } -int printf_type2(uint8_t *d, int len, int inpos, int num_entries) +void printf_type2(uint8_t *d, int len, int inpos, int num_entries) { - int i, num_printed; uint64_t u64; + uint16_t u16; + int i, j; - num_printed = 0; for (i = 0; i < num_entries; i++) { u64 = frame_get_u64(&d[inpos+i*8]); - if (u64) { - printf("type2 i%i 0x%016lX\n", i, u64); - num_printed++; + if (!u64) continue; + printf("type2 8*%i 0x%016lX\n", i, u64); + for (j = 0; j < 4; j++) { + u16 = frame_get_u16(&d[inpos+i*8+j*2]); + if (u16) + printf("type2 2*%i 8*%i+%i 0x%04X\n", i*4+j, i, j, u16); } } - return num_printed; } void printf_ramb16_data(uint8_t *bits, int inpos) diff --git a/libs/helper.h b/libs/helper.h index aa069ea..453c529 100644 --- a/libs/helper.h +++ b/libs/helper.h @@ -69,7 +69,7 @@ const char* bool_bits2str(uint64_t u64, int num_bits); int parse_boolexpr(const char* expr, uint64_t* lut); -int printf_type2(uint8_t* d, int len, int inpos, int num_entries); +void printf_type2(uint8_t* d, int len, int inpos, int num_entries); void printf_ramb16_data(uint8_t* bits, int inpos); int is_empty(const uint8_t* d, int l); diff --git a/libs/model.h b/libs/model.h index b2d1c9b..f50aeed 100644 --- a/libs/model.h +++ b/libs/model.h @@ -293,6 +293,9 @@ int is_atx(int check, struct fpga_model* model, int x); // boundary of the regular routing area. #define YX_OUTSIDE_OF_ROUTING 0x0400 #define YX_ROUTING_BOUNDARY 0x0800 +#define YX_X_CENTER_CMTPLL 0x1000 +#define YX_Y_CENTER 0x2000 +#define YX_CENTER 0x4000 int is_atyx(int check, struct fpga_model* model, int y, int x); @@ -307,6 +310,7 @@ int which_row(int y, struct fpga_model* model); int pos_in_row(int y, struct fpga_model* model); // regular_row_pos() returns the index (0..15) without hclk, or -1 if y is a hclk. int regular_row_pos(int y, struct fpga_model* model); +int y_to_hclk(int y, struct fpga_model *model); const char* logicin_s(int wire, int routing_io); diff --git a/libs/model_helper.c b/libs/model_helper.c index 8ce5b49..6efd623 100644 --- a/libs/model_helper.c +++ b/libs/model_helper.c @@ -736,6 +736,13 @@ int is_atyx(int check, struct fpga_model* model, int y, int x) && is_atyx(YX_ROUTING_TILE, model, y, x) && (x == LEFT_IO_ROUTING || x == model->x_width-RIGHT_IO_ROUTING_O || y == TOP_FIRST_REGULAR || y == model->y_height-BOT_LAST_REGULAR_O)) return 1; + if (check & YX_X_CENTER_CMTPLL + && is_atx(X_CENTER_CMTPLL_COL, model, x)) return 1; + if (check & YX_Y_CENTER + && is_aty(Y_CHIP_HORIZ_REGS, model, y)) return 1; + if (check & YX_CENTER + && is_atx(X_CENTER_REGS_COL, model, x) + && is_aty(Y_CHIP_HORIZ_REGS, model, y)) return 1; return 0; } @@ -785,6 +792,22 @@ int regular_row_pos(int y, struct fpga_model* model) return row_pos; } +int y_to_hclk(int y, struct fpga_model *model) +{ + int row_num, row_pos, hclk_pos; + + is_in_row(model, y, &row_num, &row_pos); + if (row_num == -1 + || row_pos == -1 || row_pos == HCLK_POS) + { HERE(); return -1; } + hclk_pos = model->y_height - BOT_LAST_REGULAR_O - row_num*ROW_SIZE - HCLK_POS; + if (hclk_pos < model->center_y) + hclk_pos--; // center regs + if (hclk_pos < TOP_FIRST_REGULAR) + { HERE(); return -1; } + return hclk_pos; +} + const char* logicin_s(int wire, int routing_io) { if (routing_io && ((wire & LWF_WIRE_MASK) == X_A5 || (wire & LWF_WIRE_MASK) == X_B4)) diff --git a/libs/parts.c b/libs/parts.c index 721c56c..1708360 100644 --- a/libs/parts.c +++ b/libs/parts.c @@ -389,7 +389,16 @@ const struct xc6_pkg_info *xc6_pkg_info(enum xc6_pkg pkg) /* 16 */ "P131", "P132", "P133", "P134", /* 20 */ "P14", "P15", "P16", "P17", /* 24 */ "P21", "P22", "P23", "P24", - /* 28 */ 0, 0, "P50", "P51" }}; + /* 28 */ 0, 0, "P50", "P51" }, + .gclk_type2_o = { + /* 0 */ 20*4+ 6, 20*4+ 9, -1, -1, + /* 4 */ 190*4+18, 190*4+21, 190*4+12, 190*4+15, + /* 8 */ 190*4+ 6, 190*4+ 9, 190*4+ 0, 190*4+ 3, + /* 12 */ 136*4+18, 136*4+21, 136*4+12, 136*4+15, + /* 16 */ 136*4+ 6, 136*4+ 9, 136*4+ 0, 136*4+ 3, + /* 20 */ 78*4+21, 78*4+18, 78*4+15, 78*4+12, + /* 24 */ 78*4+ 9, 78*4+ 6, 78*4+ 3, 78*4+ 0, + /* 28 */ -1, -1, 20*4+12, 20*4+15 }}; switch (pkg) { case TQG144: return &pkg_tqg144; default: ; diff --git a/libs/parts.h b/libs/parts.h index c3ba374..0148aa3 100644 --- a/libs/parts.h +++ b/libs/parts.h @@ -105,6 +105,7 @@ struct xc6_pkg_info // negative side of differential pairs: even numbers // positive side of differential pairs: odd numbers const char* gclk_pin[XC6_NUM_GCLK_PINS]; + int gclk_type2_o[XC6_NUM_GCLK_PINS]; // in words }; const struct xc6_pkg_info *xc6_pkg_info(enum xc6_pkg pkg); @@ -124,6 +125,9 @@ const struct xc6_pkg_info *xc6_pkg_info(enum xc6_pkg pkg); #define IOB_ENTRY_LEN 8 #define BITS_LEN (IOB_DATA_START+IOB_DATA_LEN) +#define XC6_WORD_BYTES 2 +#define XC6_WORD_BITS (XC6_WORD_BYTES*8) + #define XC6_HCLK_BYTES 2 #define XC6_HCLK_BITS (XC6_HCLK_BYTES*8) @@ -421,3 +425,5 @@ void xc6_lut_bitmap(int lut_pos, int (*map)[64], int num_bits); #define XC6_ML_A_CY0_O5 62 // implies lut5 on ML-A #define XC6_L_A_FFSRINIT_1 63 // L-device only + +#define XC6_TYPE2_GCLK_REG_SW 2 // bit 2 in 1st word