diff --git a/autotest.c b/autotest.c index 95f259a..0919e1d 100644 --- a/autotest.c +++ b/autotest.c @@ -434,7 +434,7 @@ static int test_switches(struct test_state* tstate, int y, int x, if (switch_str[2] == '4') { // base for len-4 wire if (tstate->dry_run) - fprintf_net(stdout, tstate->model, net); + fnet_printf(stdout, tstate->model, net); rc = diff_printf(tstate); if (rc) FAIL(rc); @@ -472,7 +472,7 @@ static int test_switches(struct test_state* tstate, int y, int x, // base for len-4 target if (tstate->dry_run) - fprintf_net(stdout, tstate->model, net); + fnet_printf(stdout, tstate->model, net); rc = diff_printf(tstate); if (rc) FAIL(rc); @@ -482,7 +482,7 @@ static int test_switches(struct test_state* tstate, int y, int x, if (rc) FAIL(rc); if (tstate->dry_run) - fprintf_net(stdout, tstate->model, net); + fnet_printf(stdout, tstate->model, net); rc = diff_printf(tstate); if (rc) FAIL(rc); @@ -652,7 +652,7 @@ static int test_routing_sw_from_logic(struct test_state* tstate, 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); + fnet_printf(stdout, tstate->model, net); rc = test_switches(tstate, conns.dest_y, conns.dest_x, conns.dest_str_i, net, done_list, done_list_len); diff --git a/bit_frames.c b/bit_frames.c index 271616f..a1db0f4 100644 --- a/bit_frames.c +++ b/bit_frames.c @@ -378,6 +378,43 @@ fail: return rc; } +static int bitpos_set_bits(struct fpga_bits* bits, struct fpga_model* model, + int y, int x, struct xc6_routing_bitpos* swpos) +{ + int row_num, row_pos, start_in_frame, rc; + + is_in_row(model, y, &row_num, &row_pos); + if (row_num == -1 || row_pos == -1 + || row_pos == HCLK_POS) FAIL(EINVAL); + if (row_pos > HCLK_POS) + start_in_frame = (row_pos-1)*64 + 16; + else + start_in_frame = row_pos*64; + + if (swpos->minor == 20) { + if (swpos->two_bits_val & 0x02) + set_bit(bits, row_num, model->x_major[x], swpos->minor, + start_in_frame + swpos->two_bits_o); + if (swpos->two_bits_val & 0x01) + set_bit(bits, row_num, model->x_major[x], swpos->minor, + start_in_frame + swpos->two_bits_o+1); + set_bit(bits, row_num, model->x_major[x], swpos->minor, + start_in_frame + swpos->one_bit_o); + } else { + if (swpos->two_bits_val & 0x02) + set_bit(bits, row_num, model->x_major[x], swpos->minor, + start_in_frame + swpos->two_bits_o/2); + if (swpos->two_bits_val & 0x01) + set_bit(bits, row_num, model->x_major[x], swpos->minor + 1, + start_in_frame + swpos->two_bits_o/2); + set_bit(bits, row_num, model->x_major[x], swpos->minor + (swpos->one_bit_o&1), + start_in_frame + swpos->one_bit_o/2); + } + return 0; +fail: + return rc; +} + static int extract_routing_switches(struct extract_state* es, int y, int x) { struct fpga_tile* tile; @@ -392,8 +429,8 @@ static int extract_routing_switches(struct extract_state* es, int y, int x) if (!is_set) continue; sw_idx = fpga_switch_lookup(es->model, y, x, - fpga_wirestr_i(es->model, es->model->sw_bitpos[i].from), - fpga_wirestr_i(es->model, es->model->sw_bitpos[i].to)); + fpga_wire2str_i(es->model, es->model->sw_bitpos[i].from), + fpga_wire2str_i(es->model, es->model->sw_bitpos[i].to)); if (sw_idx == NO_SWITCH) FAIL(EINVAL); // todo: es->model->sw_bitpos[i].bidir handling @@ -499,18 +536,50 @@ int printf_swbits(struct fpga_model* model) bit_str[model->sw_bitpos[i].two_bits_o+1] = '1'; bit_str[model->sw_bitpos[i].one_bit_o] = '1'; printf("mi%02i %s %s %s %s\n", model->sw_bitpos[i].minor, - fpga_wirestr(model, model->sw_bitpos[i].to), + fpga_wire2str(model->sw_bitpos[i].to), bit_str, - fpga_wirestr(model, model->sw_bitpos[i].from), + fpga_wire2str(model->sw_bitpos[i].from), model->sw_bitpos[i].bidir ? "<->" : "->"); } return 0; } +static int find_bitpos(struct fpga_model* model, int y, int x, swidx_t sw) +{ + enum extra_wires from_w, to_w; + const char* from_str, *to_str; + int i; + + from_str = fpga_switch_str(model, y, x, sw, SW_FROM); + to_str = fpga_switch_str(model, y, x, sw, SW_TO); + from_w = fpga_str2wire(from_str); + to_w = fpga_str2wire(to_str); + + if (from_w == NO_WIRE || to_w == NO_WIRE) { + HERE(); + return -1; + } + for (i = 0; i < model->num_bitpos; i++) { + if (model->sw_bitpos[i].from == from_w + && model->sw_bitpos[i].to == to_w) + return i; + if (model->sw_bitpos[i].bidir + && model->sw_bitpos[i].to == from_w + && model->sw_bitpos[i].from == to_w) { + if (!fpga_switch_is_bidir(model, y, x, sw)) + HERE(); + return i; + } + } + fprintf(stderr, "#E switch %s (%i) to %s (%i) not in model\n", + from_str, from_w, to_str, to_w); + return -1; +} + static int write_switches(struct fpga_bits* bits, struct fpga_model* model) { - int x, y, i; struct fpga_tile* tile; + int x, y, i, bit_pos, rc; for (x = 0; x < model->x_width; x++) { for (y = 0; y < model->y_height; y++) { @@ -524,10 +593,20 @@ static int write_switches(struct fpga_bits* bits, struct fpga_model* model) // go through enabled switches, lookup in sw_bitpos // and set bits for (i = 0; i < tile->num_switches; i++) { + if (!(tile->switches[i] & SWITCH_USED)) + continue; + bit_pos = find_bitpos(model, y, x, i); + if (bit_pos == -1) + continue; + rc = bitpos_set_bits(bits, model, y, x, + &model->sw_bitpos[bit_pos]); + if (rc) FAIL(rc); } } } return 0; +fail: + return rc; } int write_model(struct fpga_bits* bits, struct fpga_model* model) diff --git a/control.c b/control.c index e779f74..47ece33 100644 --- a/control.c +++ b/control.c @@ -728,6 +728,31 @@ void fpga_conn_dest(struct fpga_model* model, int y, int x, *str_i = tile->conn_point_dests[connpt_dest_idx*3+2]; } +int fpga_find_conn(struct fpga_model* model, int search_y, int search_x, + str16_t* pt, int target_y, int target_x, str16_t target_pt) +{ + struct fpga_tile* tile; + int i, j, dests_end; + + tile = YX_TILE(model, search_y, search_x); + for (i = 0; i < tile->num_conn_point_names; i++) { + dests_end = (i < tile->num_conn_point_names-1) + ? tile->conn_point_names[(i+1)*2] + : tile->num_conn_point_dests; + for (j = tile->conn_point_names[i*2]; j < dests_end; j++) { + if (tile->conn_point_dests[j*3] == target_x + && tile->conn_point_dests[j*3+1] == target_y + && tile->conn_point_dests[j*3+2] == target_pt) { + *pt = tile->conn_point_names[i*2+1]; + return 0; + } + } + } + *pt = STRIDX_NO_ENTRY; + return 0; + +} + swidx_t fpga_switch_first(struct fpga_model* model, int y, int x, str16_t name_i, int from_to) { @@ -894,6 +919,17 @@ void fpga_swset_print(struct fpga_model* model, int y, int x, } } +int fpga_swset_is_used(struct fpga_model* model, int y, int x, + swidx_t* sw, int len) +{ + int i; + for (i = 0; i < len; i++) { + if (fpga_switch_is_used(model, y, x, sw[i])) + return 1; + } + return 0; +} + int fpga_switch_same_fromto(struct fpga_model* model, int y, int x, swidx_t sw, int from_to, swidx_t* same_sw, int *same_len) { @@ -1181,7 +1217,7 @@ int fpga_switch_chain(struct sw_chain* ch) { swidx_t idx; struct fpga_tile* tile; - int child_from_to, loop_detect, block_detect, i; + int child_from_to, level_down, i; if (!ch->set.len) { HERE(); goto internal_error; } @@ -1193,7 +1229,8 @@ int fpga_switch_chain(struct sw_chain* ch) if (idx == NO_SWITCH) break; ch->set.sw[ch->set.len-1] = idx; - if (switch_list_contains(ch->model, ch->y, ch->x, + if (!fpga_switch_is_used(ch->model, ch->y, ch->x, idx) + && switch_list_contains(ch->model, ch->y, ch->x, ch->block_list, ch->block_list_len, idx) == NO_SWITCH) return 0; @@ -1229,8 +1266,14 @@ int fpga_switch_chain(struct sw_chain* ch) ch->model, ch->y, ch->x, idx)); #endif if (idx != NO_SWITCH) { - // If we have the same from-switch already among the - // parents, don't enter into a loop. + // There are four reasons why we don't want to + // go down one level: + // 1) switch is used + // 2) switch loop back to parent of chain + // 3) switch is blocked + // 4) max depth reached + level_down = 1; + child_from_to = SW_I(tile->switches[ch->set.sw[ ch->set.len-1]], !ch->from_to); #ifdef DBG_ENUM_SWITCH @@ -1238,25 +1281,34 @@ int fpga_switch_chain(struct sw_chain* ch) ch->model, ch->y, ch->x, child_from_to)); #endif - loop_detect = 0; - for (i = 0; i < ch->set.len; i++) { - int parent_connpt = SW_I(tile->switches[ - ch->set.sw[i]], ch->from_to); + if (fpga_switch_is_used(ch->model, ch->y, ch->x, idx)) + level_down = 0; + + if (level_down) { + // If we have the same from-switch already + // among the parents, don't enter into a loop. + for (i = 0; i < ch->set.len; i++) { + int parent_connpt = SW_I(tile->switches[ + ch->set.sw[i]], ch->from_to); #ifdef DBG_ENUM_SWITCH - printf(" parent connpt %s%s\n", connpt_str( - ch->model, ch->y, ch->x, - parent_connpt), parent_connpt - == child_from_to ? " (match)" : ""); + printf(" parent connpt %s%s\n", connpt_str( + ch->model, ch->y, ch->x, + parent_connpt), parent_connpt + == child_from_to ? " (match)" : ""); #endif - if (parent_connpt == child_from_to) { - loop_detect = 1; - break; + if (parent_connpt == child_from_to) { + level_down = 0; + break; + } } } - block_detect = switch_list_contains(ch->model, - ch->y, ch->x, ch->block_list, - ch->block_list_len, idx) != NO_SWITCH; - if (!loop_detect && !block_detect) { + if (level_down) { + // only go down if not blocked + level_down = switch_list_contains(ch->model, + ch->y, ch->x, ch->block_list, + ch->block_list_len, idx) == NO_SWITCH; + } + if (level_down) { if (ch->set.len >= SW_SET_SIZE) { HERE(); goto internal_error; } if (ch->max_depth < 1 @@ -1294,6 +1346,8 @@ int fpga_switch_chain(struct sw_chain* ch) idx = fpga_switch_next(ch->model, ch->y, ch->x, ch->set.sw[ch->set.len-1], ch->from_to); if (idx != NO_SWITCH) { + if (fpga_switch_is_used(ch->model, ch->y, ch->x, idx)) + continue; #ifdef DBG_ENUM_SWITCH printf(" found %s\n", fpga_switch_print( ch->model, ch->y, ch->x, idx)); @@ -1731,7 +1785,7 @@ static void fprintf_inout_pin(FILE* f, struct fpga_model* model, fprintf(f, buf); } -void fprintf_net(FILE* f, struct fpga_model* model, net_idx_t net_i) +void fnet_printf(FILE* f, struct fpga_model* model, net_idx_t net_i) { struct fpga_net* net; int i; @@ -1750,3 +1804,218 @@ void fprintf_net(FILE* f, struct fpga_model* model, net_idx_t net_i) net->el[i].x, net->el[i].idx)); } } + +int fnet_autoroute(struct fpga_model* model, net_idx_t net_i) +{ + struct fpga_net* net_p; + struct fpga_device* dev_p, *out_dev, *in_dev; + struct switch_to_yx switch_to; + struct sw_set logic_route_set, iologic_route_set; + struct switch_to_rel switch_to_rel; + int i, out_i, in_i, rc; + + // todo: gnd and vcc nets are special and have no outpin + // but lots of inpins + + net_p = fnet_get(model, net_i); + if (!net_p) FAIL(EINVAL); + out_i = -1; + in_i = -1; + for (i = 0; i < net_p->len; i++) { + if (!(net_p->el[i].idx & NET_IDX_IS_PINW)) { + // net already routed? + FAIL(EINVAL); + } + 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) FAIL(ENOTSUP); + in_i = i; + continue; + } + if (out_i != -1) FAIL(EINVAL); // at most 1 outpin + out_i = i; + } + // todo: vcc and gnd have no outpin? + if (out_i == -1 || in_i == -1) + FAIL(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) { + if (in_dev->type != DEV_LOGIC) + FAIL(ENOTSUP); + + // switch to ilogic + switch_to.yx_req = YX_DEV_ILOGIC; + switch_to.flags = SWTO_YX_DEF; + switch_to.model = model; + switch_to.y = net_p->el[out_i].y; + switch_to.x = net_p->el[out_i].x; + switch_to.start_switch = out_dev->pinw[net_p->el[out_i].idx + & NET_IDX_MASK]; + switch_to.from_to = SW_FROM; + rc = fpga_switch_to_yx(&switch_to); + if (rc) FAIL(rc); + rc = fnet_add_sw(model, net_i, switch_to.y, switch_to.x, + switch_to.set.sw, switch_to.set.len); + if (rc) FAIL(rc); + + // switch to ilogic routing + switch_to.yx_req = YX_ROUTING_TILE; + switch_to.flags = SWTO_YX_DEF; + switch_to.model = 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_FROM; + rc = fpga_switch_to_yx(&switch_to); + if (rc) FAIL(rc); + rc = fnet_add_sw(model, net_i, switch_to.y, switch_to.x, + switch_to.set.sw, switch_to.set.len); + if (rc) FAIL(rc); + + // switch from logic tile to logic routing tile + switch_to_rel.model = model; + switch_to_rel.start_y = net_p->el[in_i].y; + switch_to_rel.start_x = net_p->el[in_i].x; + 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.rel_y = 0; + switch_to_rel.rel_x = -1; + switch_to_rel.target_connpt = STRIDX_NO_ENTRY; + rc = fpga_switch_to_rel(&switch_to_rel); + if (rc) FAIL(rc); + rc = 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); + if (rc) FAIL(rc); + + // route from ilogic routing to logic routing + rc = froute_direct(model, switch_to.dest_y, switch_to.dest_x, + switch_to.dest_connpt, + switch_to_rel.dest_y, switch_to_rel.dest_x, + switch_to_rel.dest_connpt, + &iologic_route_set, &logic_route_set); + if (rc) FAIL(rc); + if (!iologic_route_set.len || !logic_route_set.len) FAIL(EINVAL); + rc = fnet_add_sw(model, net_i, switch_to.dest_y, switch_to.dest_x, + iologic_route_set.sw, iologic_route_set.len); + if (rc) FAIL(rc); + rc = fnet_add_sw(model, net_i, net_p->el[in_i].y, net_p->el[in_i].x-1, + logic_route_set.sw, logic_route_set.len); + if (rc) FAIL(rc); + + return 0; + } + if (out_dev->type == DEV_LOGIC) { + if (in_dev->type != DEV_IOB) + FAIL(ENOTSUP); + + // switch from ologic to iob + switch_to.yx_req = YX_DEV_OLOGIC; + switch_to.flags = SWTO_YX_DEF; + switch_to.model = model; + switch_to.y = net_p->el[in_i].y; + switch_to.x = net_p->el[in_i].x; + switch_to.start_switch = in_dev->pinw[net_p->el[in_i].idx + & NET_IDX_MASK]; + switch_to.from_to = SW_TO; + rc = fpga_switch_to_yx(&switch_to); + if (rc) FAIL(rc); + rc = fnet_add_sw(model, net_i, switch_to.y, switch_to.x, + switch_to.set.sw, switch_to.set.len); + if (rc) FAIL(rc); + + // switches inside ologic to ologic routing + switch_to.yx_req = YX_ROUTING_TILE; + switch_to.flags = SWTO_YX_DEF; + switch_to.model = 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 = fnet_add_sw(model, net_i, switch_to.y, switch_to.x, + switch_to.set.sw, switch_to.set.len); + if (rc) FAIL(rc); + + // switch inside logic tile + switch_to_rel.model = model; + switch_to_rel.start_y = net_p->el[out_i].y; + switch_to_rel.start_x = net_p->el[out_i].x; + 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.rel_y = 0; + switch_to_rel.rel_x = -1; + switch_to_rel.target_connpt = STRIDX_NO_ENTRY; + rc = fpga_switch_to_rel(&switch_to_rel); + if (rc) FAIL(rc); + rc = 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); + if (rc) FAIL(rc); + + // route from logic routing to ilogic routing + rc = froute_direct(model, switch_to_rel.dest_y, + switch_to_rel.dest_x, switch_to_rel.dest_connpt, + switch_to.dest_y, switch_to.dest_x, switch_to.dest_connpt, + &logic_route_set, &iologic_route_set); + if (rc) FAIL(rc); + if (!iologic_route_set.len || !logic_route_set.len) FAIL(EINVAL); + rc = fnet_add_sw(model, net_i, switch_to.dest_y, switch_to.dest_x, + iologic_route_set.sw, iologic_route_set.len); + if (rc) FAIL(rc); + rc = fnet_add_sw(model, net_i, switch_to_rel.dest_y, + switch_to_rel.dest_x, logic_route_set.sw, + logic_route_set.len); + if (rc) FAIL(rc); + + return 0; + } + FAIL(ENOTSUP); +fail: + return rc; +} + +int froute_direct(struct fpga_model* model, int start_y, int start_x, + str16_t start_pt, int end_y, int end_x, str16_t end_pt, + struct sw_set* start_set, struct sw_set* end_set) +{ + struct sw_conns conns; + struct sw_set end_switches; + int i, rc; + + rc = fpga_swset_fromto(model, end_y, end_x, end_pt, SW_TO, &end_switches); + if (rc) FAIL(rc); + if (!end_switches.len) FAIL(EINVAL); + + rc = construct_sw_conns(&conns, model, start_y, start_x, start_pt, + SW_FROM, /*max_depth*/ 1); + if (rc) FAIL(rc); + + while (fpga_switch_conns(&conns) != NO_CONN) { + if (conns.dest_y != end_y + || conns.dest_x != end_x) continue; + for (i = 0; i < end_switches.len; i++) { + if (conns.dest_str_i == fpga_switch_str_i(model, end_y, + end_x, end_switches.sw[i], SW_FROM)) { + *start_set = conns.chain.set; + end_set->len = 1; + end_set->sw[0] = end_switches.sw[i]; + return 0; + } + } + } + destruct_sw_conns(&conns); + start_set->len = 0; + end_set->len = 0; + return 0; +fail: + return rc; +} diff --git a/control.h b/control.h index 42c6bbc..3afc182 100644 --- a/control.h +++ b/control.h @@ -131,6 +131,8 @@ int fpga_swset_level_down(struct fpga_model* model, int y, int x, struct sw_set* set, int from_to); void fpga_swset_print(struct fpga_model* model, int y, int x, struct sw_set* set, int from_to); +int fpga_swset_is_used(struct fpga_model* model, int y, int x, + swidx_t* sw, int len); // When calling, same_len must contain the size of the // same_sw array. Upon return same_len returns how many @@ -328,5 +330,14 @@ int fnet_add_sw(struct fpga_model* model, net_idx_t net_i, int fnet_remove_sw(struct fpga_model* model, net_idx_t net_i, int y, int x, const swidx_t* switches, int num_sw); void fnet_free_all(struct fpga_model* model); +void fnet_printf(FILE* f, struct fpga_model* model, net_idx_t net_i); -void fprintf_net(FILE* f, struct fpga_model* model, net_idx_t net_i); +int fnet_autoroute(struct fpga_model* model, net_idx_t net_i); + +// +// routing +// + +int froute_direct(struct fpga_model* model, int start_y, int start_x, + str16_t start_pt, int end_y, int end_x, str16_t end_pt, + struct sw_set* start_set, struct sw_set* end_set); diff --git a/floorplan.c b/floorplan.c index 3e199b4..ba3b8e8 100644 --- a/floorplan.c +++ b/floorplan.c @@ -729,7 +729,7 @@ int printf_nets(FILE* f, struct fpga_model* model) net_i = NO_NET; while (!(rc = fnet_enum(model, net_i, &net_i)) && net_i != NO_NET) - fprintf_net(f, model, net_i); + fnet_printf(f, model, net_i); if (rc) FAIL(rc); return 0; fail: diff --git a/hello_world.c b/hello_world.c index bd0eb87..1d38d66 100644 --- a/hello_world.c +++ b/hello_world.c @@ -9,246 +9,6 @@ #include "floorplan.h" #include "control.h" -int fpga_find_conn(struct fpga_model* model, int search_y, int search_x, - str16_t* pt, int target_y, int target_x, str16_t target_pt) -{ - struct fpga_tile* tile; - int i, j, dests_end; - - tile = YX_TILE(model, search_y, search_x); - for (i = 0; i < tile->num_conn_point_names; i++) { - dests_end = (i < tile->num_conn_point_names-1) - ? tile->conn_point_names[(i+1)*2] - : tile->num_conn_point_dests; - for (j = tile->conn_point_names[i*2]; j < dests_end; j++) { - if (tile->conn_point_dests[j*3] == target_x - && tile->conn_point_dests[j*3+1] == target_y - && tile->conn_point_dests[j*3+2] == target_pt) { - *pt = tile->conn_point_names[i*2+1]; - return 0; - } - } - } - *pt = STRIDX_NO_ENTRY; - return 0; - -} - -static int froute_direct(struct fpga_model* model, int start_y, int start_x, - str16_t start_pt, int end_y, int end_x, str16_t end_pt, - struct sw_set* start_set, struct sw_set* end_set) -{ - struct sw_conns conns; - struct sw_set end_switches; - int i, rc; - - rc = fpga_swset_fromto(model, end_y, end_x, end_pt, SW_TO, &end_switches); - if (rc) FAIL(rc); - if (!end_switches.len) FAIL(EINVAL); - - rc = construct_sw_conns(&conns, model, start_y, start_x, start_pt, - SW_FROM, /*max_depth*/ 1); - if (rc) FAIL(rc); - - while (fpga_switch_conns(&conns) != NO_CONN) { - if (conns.dest_y != end_y - || conns.dest_x != end_x) continue; - for (i = 0; i < end_switches.len; i++) { - if (conns.dest_str_i == fpga_switch_str_i(model, end_y, - end_x, end_switches.sw[i], SW_FROM)) { - *start_set = conns.chain.set; - end_set->len = 1; - end_set->sw[0] = end_switches.sw[i]; - return 0; - } - } - } - destruct_sw_conns(&conns); - start_set->len = 0; - end_set->len = 0; - return 0; -fail: - return rc; -} - -static int fnet_autoroute(struct fpga_model* model, net_idx_t net_i) -{ - struct fpga_net* net_p; - struct fpga_device* dev_p, *out_dev, *in_dev; - struct switch_to_yx switch_to; - struct sw_set logic_route_set, iologic_route_set; - struct switch_to_rel switch_to_rel; - int i, out_i, in_i, rc; - - // todo: gnd and vcc nets are special and have no outpin - // but lots of inpins - - net_p = fnet_get(model, net_i); - if (!net_p) FAIL(EINVAL); - out_i = -1; - in_i = -1; - for (i = 0; i < net_p->len; i++) { - if (!(net_p->el[i].idx & NET_IDX_IS_PINW)) { - // net already routed? - FAIL(EINVAL); - } - 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) FAIL(ENOTSUP); - in_i = i; - continue; - } - if (out_i != -1) FAIL(EINVAL); // at most 1 outpin - out_i = i; - } - // todo: vcc and gnd have no outpin? - if (out_i == -1 || in_i == -1) - FAIL(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) { - if (in_dev->type != DEV_LOGIC) - FAIL(ENOTSUP); - - // switch to ilogic - switch_to.yx_req = YX_DEV_ILOGIC; - switch_to.flags = SWTO_YX_DEF; - switch_to.model = model; - switch_to.y = net_p->el[out_i].y; - switch_to.x = net_p->el[out_i].x; - switch_to.start_switch = out_dev->pinw[net_p->el[out_i].idx - & NET_IDX_MASK]; - switch_to.from_to = SW_FROM; - rc = fpga_switch_to_yx(&switch_to); - if (rc) FAIL(rc); - rc = fnet_add_sw(model, net_i, switch_to.y, switch_to.x, - switch_to.set.sw, switch_to.set.len); - if (rc) FAIL(rc); - - // switch to ilogic routing - switch_to.yx_req = YX_ROUTING_TILE; - switch_to.flags = SWTO_YX_DEF; - switch_to.model = 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_FROM; - rc = fpga_switch_to_yx(&switch_to); - if (rc) FAIL(rc); - rc = fnet_add_sw(model, net_i, switch_to.y, switch_to.x, - switch_to.set.sw, switch_to.set.len); - if (rc) FAIL(rc); - - // switch from logic tile to logic routing tile - switch_to_rel.model = model; - switch_to_rel.start_y = net_p->el[in_i].y; - switch_to_rel.start_x = net_p->el[in_i].x; - 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.rel_y = 0; - switch_to_rel.rel_x = -1; - switch_to_rel.target_connpt = STRIDX_NO_ENTRY; - rc = fpga_switch_to_rel(&switch_to_rel); - if (rc) FAIL(rc); - rc = 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); - if (rc) FAIL(rc); - - // route from ilogic routing to logic routing - rc = froute_direct(model, switch_to.dest_y, switch_to.dest_x, - switch_to.dest_connpt, - switch_to_rel.dest_y, switch_to_rel.dest_x, - switch_to_rel.dest_connpt, - &iologic_route_set, &logic_route_set); - if (rc) FAIL(rc); - if (!iologic_route_set.len || !logic_route_set.len) FAIL(EINVAL); - rc = fnet_add_sw(model, net_i, switch_to.dest_y, switch_to.dest_x, - iologic_route_set.sw, iologic_route_set.len); - if (rc) FAIL(rc); - rc = fnet_add_sw(model, net_i, net_p->el[in_i].y, net_p->el[in_i].x-1, - logic_route_set.sw, logic_route_set.len); - if (rc) FAIL(rc); - - return 0; - } - if (out_dev->type == DEV_LOGIC) { - if (in_dev->type != DEV_IOB) - FAIL(ENOTSUP); - - // switch from ologic to iob - switch_to.yx_req = YX_DEV_OLOGIC; - switch_to.flags = SWTO_YX_DEF; - switch_to.model = model; - switch_to.y = net_p->el[in_i].y; - switch_to.x = net_p->el[in_i].x; - switch_to.start_switch = in_dev->pinw[net_p->el[in_i].idx - & NET_IDX_MASK]; - switch_to.from_to = SW_TO; - rc = fpga_switch_to_yx(&switch_to); - if (rc) FAIL(rc); - rc = fnet_add_sw(model, net_i, switch_to.y, switch_to.x, - switch_to.set.sw, switch_to.set.len); - if (rc) FAIL(rc); - - // switches inside ologic to ologic routing - switch_to.yx_req = YX_ROUTING_TILE; - switch_to.flags = SWTO_YX_DEF; - switch_to.model = 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 = fnet_add_sw(model, net_i, switch_to.y, switch_to.x, - switch_to.set.sw, switch_to.set.len); - if (rc) FAIL(rc); - - // switch inside logic tile - switch_to_rel.model = model; - switch_to_rel.start_y = net_p->el[out_i].y; - switch_to_rel.start_x = net_p->el[out_i].x; - 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.rel_y = 0; - switch_to_rel.rel_x = -1; - switch_to_rel.target_connpt = STRIDX_NO_ENTRY; - rc = fpga_switch_to_rel(&switch_to_rel); - if (rc) FAIL(rc); - rc = 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); - if (rc) FAIL(rc); - - // route from logic routing to ilogic routing - rc = froute_direct(model, switch_to_rel.dest_y, - switch_to_rel.dest_x, switch_to_rel.dest_connpt, - switch_to.dest_y, switch_to.dest_x, switch_to.dest_connpt, - &logic_route_set, &iologic_route_set); - if (rc) FAIL(rc); - if (!iologic_route_set.len || !logic_route_set.len) FAIL(EINVAL); - rc = fnet_add_sw(model, net_i, switch_to.dest_y, switch_to.dest_x, - iologic_route_set.sw, iologic_route_set.len); - if (rc) FAIL(rc); - rc = fnet_add_sw(model, net_i, switch_to_rel.dest_y, - switch_to_rel.dest_x, logic_route_set.sw, - logic_route_set.len); - if (rc) FAIL(rc); - - return 0; - } - FAIL(ENOTSUP); -fail: - return rc; -} - int main(int argc, char** argv) { struct fpga_model model; @@ -282,6 +42,8 @@ int main(int argc, char** argv) logic_type_idx = DEV_LOGX; if ((rc = fdev_logic_set_lut(&model, logic_y, logic_x, logic_type_idx, LUT_D, 6, "A3*A5", ZTERM))) FAIL(rc); + if ((rc = fdev_logic_out_used(&model, logic_y, logic_x, logic_type_idx, + LUT_D))) FAIL(rc); if ((rc = fnet_new(&model, &inA_net))) FAIL(rc); if ((rc = fnet_add_port(&model, inA_net, iob_inA_y, iob_inA_x, diff --git a/model.h b/model.h index ba95d67..396ed62 100644 --- a/model.h +++ b/model.h @@ -764,6 +764,7 @@ enum wire_type #define W_TO_LEN4(w) wire_to_len(w, FIRST_LEN4) const char* wire_base(enum wire_type w); +enum wire_type base2wire(const char* str); enum wire_type rotate_wire(enum wire_type cur, int off); enum wire_type wire_to_len(enum wire_type w, int first_len); @@ -824,7 +825,8 @@ enum extra_wires { LW_LAST = 1999 }; -const char* fpga_wirestr(struct fpga_model* model, enum extra_wires wire); -str16_t fpga_wirestr_i(struct fpga_model* model, enum extra_wires wire); +const char* fpga_wire2str(enum extra_wires wire); +str16_t fpga_wire2str_i(struct fpga_model* model, enum extra_wires wire); +enum extra_wires fpga_str2wire(const char* str); int fdev_logic_inbit(pinw_idx_t idx); int fdev_logic_outbit(pinw_idx_t idx); diff --git a/model_helper.c b/model_helper.c index 40161a9..8adf425 100644 --- a/model_helper.c +++ b/model_helper.c @@ -743,7 +743,7 @@ const char* logicout_str(enum logicout_wire w) return 0; } -const char* fpga_wirestr(struct fpga_model* model, enum extra_wires wire) +const char* fpga_wire2str(enum extra_wires wire) { enum { NUM_BUFS = 8, BUF_SIZE = 64 }; static char buf[NUM_BUFS][BUF_SIZE]; @@ -807,9 +807,184 @@ const char* fpga_wirestr(struct fpga_model* model, enum extra_wires wire) return buf[last_buf]; } -str16_t fpga_wirestr_i(struct fpga_model* model, enum extra_wires wire) +str16_t fpga_wire2str_i(struct fpga_model* model, enum extra_wires wire) { - return strarray_find(&model->str, fpga_wirestr(model, wire)); + return strarray_find(&model->str, fpga_wire2str(wire)); +} + +enum extra_wires fpga_str2wire(const char* str) +{ + const char* _str; + enum wire_type wtype; + int len, num, flags; + + _str = str; + if (!strncmp(_str, "INT_IOI_", 8)) + _str = &_str[8]; + + if (!strncmp(_str, "GCLK", 4)) { + len = strlen(_str); + if (!strcmp(&_str[len-4], "_BRK")) + len -= 4; + if (len > 4) { + num = to_i(&_str[4], len-4); + if (num >= 0 && num <= 15) + return GCLK0 + num; + } + } + if (!strncmp(_str, "LOGICIN_B", 9)) { + len = strlen(&_str[9]); + if (len) { + switch (to_i(&_str[9], len)) { + case X_A1: return LW + LI_A1; + case X_A2: return LW + LI_A2; + case X_A3: return LW + LI_A3; + case X_A4: return LW + LI_A4; + case X_A5: return LW + LI_A5; + case X_A6: return LW + LI_A6; + case X_AX: return LW + LI_AX; + case X_B1: return LW + LI_B1; + case X_B2: return LW + LI_B2; + case X_B3: return LW + LI_B3; + case X_B4: return LW + LI_B4; + case X_B5: return LW + LI_B5; + case X_B6: return LW + LI_B6; + case X_BX: return LW + LI_BX; + case X_C1: return LW + LI_C1; + case X_C2: return LW + LI_C2; + case X_C3: return LW + LI_C3; + case X_C4: return LW + LI_C4; + case X_C5: return LW + LI_C5; + case X_C6: return LW + LI_C6; + case X_CE: return LW + LI_CE; + case X_CX: return LW + LI_CX; + case X_D1: return LW + LI_D1; + case X_D2: return LW + LI_D2; + case X_D3: return LW + LI_D3; + case X_D4: return LW + LI_D4; + case X_D5: return LW + LI_D5; + case X_D6: return LW + LI_D6; + case X_DX: return LW + LI_DX; + case M_A1: return LW + (LI_A1|LD1); + case M_A2: return LW + (LI_A2|LD1); + case M_A3: return LW + (LI_A3|LD1); + case M_A4: return LW + (LI_A4|LD1); + case M_A5: return LW + (LI_A5|LD1); + case M_A6: return LW + (LI_A6|LD1); + case M_AX: return LW + (LI_AX|LD1); + case M_AI: return LW + (LI_AI|LD1); + case M_B1: return LW + (LI_B1|LD1); + case M_B2: return LW + (LI_B2|LD1); + case M_B3: return LW + (LI_B3|LD1); + case M_B4: return LW + (LI_B4|LD1); + case M_B5: return LW + (LI_B5|LD1); + case M_B6: return LW + (LI_B6|LD1); + case M_BX: return LW + (LI_BX|LD1); + case M_BI: return LW + (LI_BI|LD1); + case M_C1: return LW + (LI_C1|LD1); + case M_C2: return LW + (LI_C2|LD1); + case M_C3: return LW + (LI_C3|LD1); + case M_C4: return LW + (LI_C4|LD1); + case M_C5: return LW + (LI_C5|LD1); + case M_C6: return LW + (LI_C6|LD1); + case M_CE: return LW + (LI_CE|LD1); + case M_CX: return LW + (LI_CX|LD1); + case M_CI: return LW + (LI_CI|LD1); + case M_D1: return LW + (LI_D1|LD1); + case M_D2: return LW + (LI_D2|LD1); + case M_D3: return LW + (LI_D3|LD1); + case M_D4: return LW + (LI_D4|LD1); + case M_D5: return LW + (LI_D5|LD1); + case M_D6: return LW + (LI_D6|LD1); + case M_DX: return LW + (LI_DX|LD1); + case M_DI: return LW + (LI_DI|LD1); + case M_WE: return LW + (LI_WE|LD1); + } + } + } + if (!strncmp(_str, "LOGICOUT", 8)) { + len = strlen(&_str[8]); + if (len) { + switch (to_i(&_str[8], len)) { + case M_A: return LW + (LO_A|LD1); + case M_AMUX: return LW + (LO_AMUX|LD1); + case M_AQ: return LW + (LO_AQ|LD1); + case M_B: return LW + (LO_B|LD1); + case M_BMUX: return LW + (LO_BMUX|LD1); + case M_BQ: return LW + (LO_BQ|LD1); + case M_C: return LW + (LO_C|LD1); + case M_CMUX: return LW + (LO_CMUX|LD1); + case M_CQ: return LW + (LO_CQ|LD1); + case M_D: return LW + (LO_D|LD1); + case M_DMUX: return LW + (LO_DMUX|LD1); + case M_DQ: return LW + (LO_DQ|LD1); + case X_A: return LW + LO_A; + case X_AMUX: return LW + LO_AMUX; + case X_AQ: return LW + LO_AQ; + case X_B: return LW + LO_B; + case X_BMUX: return LW + LO_BMUX; + case X_BQ: return LW + LO_BQ; + case X_C: return LW + LO_C; + case X_CMUX: return LW + LO_CMUX; + case X_CQ: return LW + LO_CQ; + case X_D: return LW + LO_D; + case X_DMUX: return LW + LO_DMUX; + case X_DQ: return LW + LO_DQ; + } + } + } + if ((wtype = base2wire(_str))) { + flags = 0; + if (_str[3] == 'B') + flags |= DIR_BEG; + if (_str[3] != 'B' && _str[3] != 'E') + HERE(); + else { + if (!strcmp(&_str[4], "_S0")) { + num = 0; + flags |= DIR_S0; + } else if (!strcmp(&_str[4], "_N3")) { + num = 3; + flags |= DIR_N3; + } else switch (_str[4]) { + case '0': num = 0; break; + case '1': num = 1; break; + case '2': num = 2; break; + case '3': num = 3; break; + default: + HERE(); + num = -1; + break; + } + if (num != -1) + return DW + ((wtype*4 + num)|flags); + } + } + if (!strcmp(_str, "GFAN0")) return GFAN0; + if (!strcmp(_str, "GFAN1")) return GFAN1; + if (!strcmp(_str, "CLK0")) return CLK0; + if (!strcmp(_str, "CLK1")) return CLK1; + if (!strcmp(_str, "SR0")) return SR0; + if (!strcmp(_str, "SR1")) return SR1; + if (!strcmp(_str, "GND_WIRE")) return GND_WIRE; + if (!strcmp(_str, "VCC_WIRE")) return VCC_WIRE; + if (!strcmp(_str, "FAN_B")) return FAN_B; + if (!strncmp(_str, "LOGICIN", 7)) { + if (!strcmp(&_str[7], "20")) return LOGICIN20; + if (!strcmp(&_str[7], "21")) return LOGICIN21; + if (!strcmp(&_str[7], "44")) return LOGICIN44; + if (!strcmp(&_str[7], "52")) return LOGICIN52; + if (!strcmp(&_str[7], "_N21")) return LOGICIN_N21; + if (!strcmp(&_str[7], "_N28")) return LOGICIN_N28; + if (!strcmp(&_str[7], "_N52")) return LOGICIN_N52; + if (!strcmp(&_str[7], "_N60")) return LOGICIN_N60; + if (!strcmp(&_str[7], "_S20")) return LOGICIN_S20; + if (!strcmp(&_str[7], "_S36")) return LOGICIN_S36; + if (!strcmp(&_str[7], "_S44")) return LOGICIN_S44; + if (!strcmp(&_str[7], "_S62")) return LOGICIN_S62; + } + HERE(); + return NO_WIRE; } int fdev_logic_inbit(pinw_idx_t idx) diff --git a/model_switches.c b/model_switches.c index d34f5c4..0df5826 100644 --- a/model_switches.c +++ b/model_switches.c @@ -908,6 +908,38 @@ const char* wire_base(enum wire_type w) EXIT(1); } +enum wire_type base2wire(const char* str) +{ + if (!strncmp(str, "NL1", 3)) return W_NL1; + if (!strncmp(str, "NR1", 3)) return W_NR1; + if (!strncmp(str, "EL1", 3)) return W_EL1; + if (!strncmp(str, "ER1", 3)) return W_ER1; + if (!strncmp(str, "SL1", 3)) return W_SL1; + if (!strncmp(str, "SR1", 3)) return W_SR1; + if (!strncmp(str, "WL1", 3)) return W_WL1; + if (!strncmp(str, "WR1", 3)) return W_WR1; + + if (!strncmp(str, "NN2", 3)) return W_NN2; + if (!strncmp(str, "NE2", 3)) return W_NE2; + if (!strncmp(str, "EE2", 3)) return W_EE2; + if (!strncmp(str, "SE2", 3)) return W_SE2; + if (!strncmp(str, "SS2", 3)) return W_SS2; + if (!strncmp(str, "SW2", 3)) return W_SW2; + if (!strncmp(str, "WW2", 3)) return W_WW2; + if (!strncmp(str, "NW2", 3)) return W_NW2; + + if (!strncmp(str, "NN4", 3)) return W_NN4; + if (!strncmp(str, "NE4", 3)) return W_NE4; + if (!strncmp(str, "EE4", 3)) return W_EE4; + if (!strncmp(str, "SE4", 3)) return W_SE4; + if (!strncmp(str, "SS4", 3)) return W_SS4; + if (!strncmp(str, "SW4", 3)) return W_SW4; + if (!strncmp(str, "WW4", 3)) return W_WW4; + if (!strncmp(str, "NW4", 3)) return W_NW4; + + return 0; +} + static int rotate_num(int cur, int off, int first, int last) { if (cur+off > last) @@ -939,8 +971,8 @@ enum wire_type wire_to_len(enum wire_type w, int first_len) EXIT(1); } -static const char* routing_wirestr(struct fpga_model* model, - enum extra_wires wire, int routing_io, int gclk_brk) +static const char* routing_wirestr(enum extra_wires wire, + int routing_io, int gclk_brk) { if (routing_io) { if (wire == GFAN0) return "INT_IOI_GFAN0"; @@ -969,7 +1001,7 @@ static const char* routing_wirestr(struct fpga_model* model, default: ; } } - return fpga_wirestr(model, wire); + return fpga_wire2str(wire); } static int init_routing_tile(struct fpga_model* model, int y, int x) @@ -997,7 +1029,7 @@ static int init_routing_tile(struct fpga_model* model, int y, int x) pf("SR%i", i), 0 /* bidir */); if (rc) FAIL(rc); rc = add_switch(model, y, x, - "KEEP1_WIRE", routing_wirestr(model, GFAN0+i, routing_io, gclk_brk), 0 /* bidir */); + "KEEP1_WIRE", routing_wirestr(GFAN0+i, routing_io, gclk_brk), 0 /* bidir */); if (rc) FAIL(rc); } @@ -1013,14 +1045,14 @@ static int init_routing_tile(struct fpga_model* model, int y, int x) is_bidir = 0; } rc = add_switch(model, y, x, - routing_wirestr(model, from_wire, routing_io, gclk_brk), - routing_wirestr(model, to_wire, routing_io, gclk_brk), + routing_wirestr(from_wire, routing_io, gclk_brk), + routing_wirestr(to_wire, routing_io, gclk_brk), is_bidir); if (rc) FAIL(rc); if (is_bidir) { rc = add_switch(model, y, x, - routing_wirestr(model, to_wire, routing_io, gclk_brk), - routing_wirestr(model, from_wire, routing_io, gclk_brk), + routing_wirestr(to_wire, routing_io, gclk_brk), + routing_wirestr(from_wire, routing_io, gclk_brk), /* bidir */ 1); if (rc) FAIL(rc); } diff --git a/parts.c b/parts.c index 29d3045..4359123 100644 --- a/parts.c +++ b/parts.c @@ -220,6 +220,21 @@ static int wire_decrement(int wire) return wire; } +static enum extra_wires clean_S0N3(enum extra_wires wire) +{ + int flags; + + if (wire < DW || wire > DW_LAST) return wire; + wire -= DW; + flags = wire & DIR_FLAGS; + wire &= ~DIR_FLAGS; + if (flags & DIR_S0 && wire%4 != 0) + flags &= ~DIR_S0; + if (flags & DIR_N3 && wire%4 != 3) + flags &= ~DIR_N3; + return DW + (wire | flags); +} + static int src_to_bitpos(struct xc6_routing_bitpos* bitpos, int* cur_el, int max_el, const struct sw_mip_src* src, int src_len) { @@ -232,8 +247,8 @@ static int src_to_bitpos(struct xc6_routing_bitpos* bitpos, int* cur_el, int max bidir = bidir_check(src[i].m0_sw_to, src[i].from_w[j]); if (bidir != -1) { if (*cur_el >= max_el) FAIL(EINVAL); - bitpos[*cur_el].from = src[i].from_w[j]; - bitpos[*cur_el].to = src[i].m0_sw_to; + bitpos[*cur_el].from = clean_S0N3(src[i].from_w[j]); + bitpos[*cur_el].to = clean_S0N3(src[i].m0_sw_to); bitpos[*cur_el].bidir = bidir; bitpos[*cur_el].minor = src[i].minor; bitpos[*cur_el].two_bits_o = src[i].m0_two_bits_o; @@ -245,8 +260,8 @@ static int src_to_bitpos(struct xc6_routing_bitpos* bitpos, int* cur_el, int max bidir = bidir_check(src[i].m1_sw_to, src[i].from_w[j]); if (bidir != -1) { if (*cur_el >= max_el) FAIL(EINVAL); - bitpos[*cur_el].from = src[i].from_w[j]; - bitpos[*cur_el].to = src[i].m1_sw_to; + bitpos[*cur_el].from = clean_S0N3(src[i].from_w[j]); + bitpos[*cur_el].to = clean_S0N3(src[i].m1_sw_to); bitpos[*cur_el].bidir = bidir; bitpos[*cur_el].minor = src[i].minor; bitpos[*cur_el].two_bits_o = src[i].m1_two_bits_o;