From a88c4f1835d865243bdb3bb6c3a20ca99a9034a2 Mon Sep 17 00:00:00 2001 From: Wolfgang Spraul Date: Thu, 23 Aug 2012 07:27:23 +0200 Subject: [PATCH] autotest, minor fixes all over --- Makefile | 6 + autotest.c | 100 ++++++---- control.c | 107 ++++++++--- control.h | 13 +- helper.h | 2 + model.h | 37 +++- model_conns.c | 8 +- model_devices.c | 16 +- model_helper.c | 116 ++++++++---- model_main.c | 29 ++- model_ports.c | 171 ++++++++--------- model_switches.c | 482 ++++++++++++++++++++++++++--------------------- 12 files changed, 651 insertions(+), 436 deletions(-) diff --git a/Makefile b/Makefile index a953bb9..5a1b770 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,12 @@ PREFIX ?= /usr/local .PHONY: all clean install uninstall .SECONDARY: + +# -fno-omit-frame-pointer and -ggdb add almost nothing to execution +# time right now, so we can leave them in all the time. +CFLAGS_DBG = -fno-omit-frame-pointer -ggdb +CFLAGS += $(CFLAGS_DBG) + CFLAGS += -Wall -Wshadow -Wmissing-prototypes -Wmissing-declarations \ -Wno-format-zero-length -Ofast CFLAGS += `pkg-config libxml-2.0 --cflags` diff --git a/autotest.c b/autotest.c index c45988e..03f765f 100644 --- a/autotest.c +++ b/autotest.c @@ -110,8 +110,10 @@ static int printf_switchtree(struct fpga_model* model, int y, int x, { int i, idx, conn_to_y, conn_to_x, num_dests, connpt_dests_o, rc; const char* to_str; + char tmp_str[128]; - printf("%.*sy%02i x%02i %s\n", indent, s_spaces, y, x, start); +// printf("%.*sy%02i x%02i %s\n", indent, s_spaces, y, x, start); +#if 0 num_dests = fpga_connpt_lookup(model, y, x, start, &connpt_dests_o); for (i = 0; i < num_dests; i++) { if (!i) @@ -132,16 +134,22 @@ static int printf_switchtree(struct fpga_model* model, int y, int x, to_str); idx = fpga_switch_next(model, y, x, idx, SW_TO); } +#endif idx = fpga_switch_first(model, y, x, start, SW_FROM); if (idx != NO_SWITCH) printf("%.*s| switches to:\n", indent, s_spaces); while (idx != NO_SWITCH) { + printf("%.*s %s\n", indent, s_spaces, + fmt_sw(model, y, x, idx, SW_FROM)); to_str = fpga_switch_str(model, y, x, idx, SW_TO); +#if 0 printf("%.*s %s %s\n", indent, s_spaces, fpga_switch_is_bidir(model, y, x, idx) ? "<->" : "->", to_str); - rc = printf_switchtree(model, y, x, to_str, indent+2); +#endif + strcpy(tmp_str, to_str); + rc = printf_switchtree(model, y, x, tmp_str, indent+2); if (rc) FAIL(rc); idx = fpga_switch_next(model, y, x, idx, SW_FROM); } @@ -150,15 +158,46 @@ fail: return rc; } +void printf_swconns(struct fpga_model* model, int y, int x, const char* sw) +{ + struct swchain_conns conns = + { .model = model, .y = y, .x = x, .start_switch = sw }; + while (fpga_switch_conns_enum(&conns) != NO_CONN) { + printf("sw %s conn y%02i x%02i %s\n", fmt_swchain(model, y, x, + conns.chain.chain, conns.chain.chain_size), + conns.dest_y, conns.dest_x, conns.dest_str); + } +} + +// return dest_y, dest_x, dest_str +int fpga_switch_to_yx(int yx_req, struct fpga_model* model, int y, int x, + const char* start_switch, swidx_t* sw_chain, int* sw_chain_size) +{ + struct swchain_conns conns = { .model = model, .y = y, .x = x, + .start_switch = start_switch }; + while (fpga_switch_conns_enum(&conns) != NO_CONN) { + if (is_atyx(yx_req, model, conns.dest_y, conns.dest_x)) { + memcpy(sw_chain, conns.chain.chain, + conns.chain.chain_size*sizeof(*sw_chain)); + *sw_chain_size = conns.chain.chain_size; + return 0; + } + } + *sw_chain_size = 0; + return 0; +} + int main(int argc, char** argv) { struct fpga_model model; struct fpga_device* P46_dev, *P48_dev, *logic_dev; int P46_y, P46_x, P46_idx, P48_y, P48_x, P48_idx, rc; struct test_state tstate; - struct sw_chain chain; - struct swchain_conns conns; +// struct sw_chain chain; +// struct swchain_conns conns; char tmp_str[128]; + swidx_t switch_chain[MAX_SW_CHAIN_SIZE]; + int switch_chain_size; printf("\n"); printf("O fpgatools automatic test suite. Be welcome and be " @@ -214,16 +253,28 @@ int main(int argc, char** argv) if (rc) FAIL(rc); rc = diff_printf(&tstate); - if (rc) goto fail; + if (rc) FAIL(rc); + rc = fpga_switch_to_yx(YX_DEV_ILOGIC, &model, P46_y, P46_x, + P46_dev->iob.pinw_out_I, switch_chain, &switch_chain_size); + if (rc) FAIL(rc); +// todo: needs to return dest_y, dest_x, dest_connpt + + printf("%s\n", fmt_swchain(&model, P46_y, P46_x, switch_chain, switch_chain_size)); + +#if 0 printf("P46 I pinw %s\n", P46_dev->iob.pinw_out_I); + + printf_swconns(&model, P46_y, P46_x, P46_dev->iob.pinw_out_I); + + conns.model = &model; conns.y = P46_y; conns.x = P46_x; conns.start_switch = P46_dev->iob.pinw_out_I; while (fpga_switch_conns_enum(&conns) != NO_CONN) { - if (is_aty(Y_TOP_INNER_IO|Y_BOT_INNER_IO, &model, conns.dest_y)) { + if (is_atyx(YX_DEV_ILOGIC, &model, conns.dest_y, conns.dest_x)) { struct swchain_conns conns2; printf("conn chain_size %i connpt_o %i num_dests %i i %i y %i x %i str %s\n", @@ -235,55 +286,36 @@ int main(int argc, char** argv) conns2.y = conns.dest_y; conns2.x = conns.dest_x; conns2.start_switch = tmp_str; + while (fpga_switch_conns_enum(&conns2) != NO_CONN) { if (is_atyx(YX_ROUTING_TILE, &model, conns2.dest_y, conns2.dest_x)) { struct swchain_conns conns3; + struct sw_chain chain3; printf("conn2 chain_size %i connpt_o %i num_dests %i i %i y %i x %i str %s\n", conns2.chain.chain_size, conns2.connpt_dest_start, conns2.num_dests, conns2.dest_i, conns2.dest_y, conns2.dest_x, conns2.dest_str); -#if 0 - rc = printf_switchtree(&model, conns2.dest_y, - conns2.dest_x, conns2.dest_str, /*indent*/ 3); - if (rc) FAIL(rc); -#endif - strcpy(tmp_str, conns2.dest_str); + printf_swconns(&model, conns2.dest_y, conns2.dest_x, tmp_str); + conns3.model = &model; conns3.y = conns2.dest_y; conns3.x = conns2.dest_x; conns3.start_switch = tmp_str; while (fpga_switch_conns_enum(&conns3) != NO_CONN) { - printf("conn3 chain_size %i connpt_o %i num_dests %i i %i y %i x %i str %s\n", - conns3.chain.chain_size, conns3.connpt_dest_start, - conns3.num_dests, conns3.dest_i, conns3.dest_y, conns3.dest_x, conns3.dest_str); + if (is_atyx(YX_ROUTING_TO_FABLOGIC, &model, conns3.dest_y, conns3.dest_x)) { + printf("route to y%02i x%02i\n", conns3.dest_y, conns3.dest_x); + break; + } } break; } } break; -#if 0 - rc = printf_switchtree(&model, conns.dest_y, - conns.dest_x, conns.dest_str, /*indent*/ 3); - if (rc) FAIL(rc); - -// go through whole tree of what is reachable from that -// switch, look for outside connections that reach to a routing tile - chain.model = &model; - chain.y = conns.dest_y; - chain.x = conns.dest_x; - chain.start_switch = conns.dest_str; - chain.from_to = SW_FROM; - while (fpga_switch_chain_enum(&chain) != NO_SWITCH) { - printf("idx %i chain_size %i from %s to %s\n", - chain.chain[chain.chain_size-1], chain.chain_size-1, - fpga_switch_str(&model, chain.y, chain.x, chain.chain[chain.chain_size-1], SW_FROM), - fpga_switch_str(&model, chain.y, chain.x, chain.chain[chain.chain_size-1], SW_TO)); - } -#endif } } +#endif printf("P48 O pinw %s\n", P48_dev->iob.pinw_in_O); diff --git a/control.c b/control.c index 23168ce..ff20c42 100644 --- a/control.c +++ b/control.c @@ -333,9 +333,7 @@ swidx_t fpga_switch_first(struct fpga_model* model, int y, int x, // Finds the first switch either from or to the name given. tile = YX_TILE(model, y, x); for (i = 0; i < tile->num_switches; i++) { - connpt_o = (from_to == SW_FROM) - ? SWITCH_FROM(tile->switches[i]) - : SWITCH_TO(tile->switches[i]); + connpt_o = SW_I(tile->switches[i], from_to); if (tile->conn_point_names[connpt_o*2+1] == name_i) break; } @@ -351,15 +349,11 @@ static swidx_t fpga_switch_search(struct fpga_model* model, int y, int x, int connpt_o, name_i, i; tile = YX_TILE(model, y, x); - connpt_o = (from_to == SW_FROM) - ? SWITCH_FROM(tile->switches[last]) - : SWITCH_TO(tile->switches[last]); + connpt_o = SW_I(tile->switches[last], from_to); name_i = tile->conn_point_names[connpt_o*2+1]; for (i = search_beg; i < tile->num_switches; i++) { - connpt_o = (from_to == SW_FROM) - ? SWITCH_FROM(tile->switches[i]) - : SWITCH_TO(tile->switches[i]); + connpt_o = SW_I(tile->switches[i], from_to); if (tile->conn_point_names[connpt_o*2+1] == name_i) break; } @@ -378,7 +372,7 @@ swidx_t fpga_switch_backtofirst(struct fpga_model* model, int y, int x, return fpga_switch_search(model, y, x, last, /*search_beg*/ 0, from_to); } -#define NUM_CONNPT_BUFS 16 +#define NUM_CONNPT_BUFS 64 #define CONNPT_BUF_SIZE 128 static const char* connpt_str(struct fpga_model* model, int y, int x, int connpt_o) @@ -406,8 +400,7 @@ const char* fpga_switch_str(struct fpga_model* model, int y, int x, swidx_t swidx, int from_to) { uint32_t sw = YX_TILE(model, y, x)->switches[swidx]; - return connpt_str(model, y, x, - (from_to == SW_FROM) ? SWITCH_FROM(sw) : SWITCH_TO(sw)); + return connpt_str(model, y, x, SW_I(sw, from_to)); } int fpga_switch_is_bidir(struct fpga_model* model, int y, int x, @@ -434,9 +427,64 @@ void fpga_switch_disable(struct fpga_model* model, int y, int x, YX_TILE(model, y, x)->switches[swidx] &= ~SWITCH_ON; } +#define SW_BUF_SIZE 256 +#define NUM_SW_BUFS 64 + +const char* fmt_sw(struct fpga_model* model, int y, int x, swidx_t sw, int from_to) +{ + static char sw_buf[NUM_SW_BUFS][SW_BUF_SIZE]; + static int last_buf = 0; + char midstr[64]; + + last_buf = (last_buf+1)%NUM_SW_BUFS; + + strcpy(midstr, fpga_switch_is_enabled(model, y, x, sw) ? "on:" : ""); + if (fpga_switch_is_bidir(model, y, x, sw)) + strcat(midstr, "<->"); + else { + // a 'to-switch' is actually still a switch that physically + // points in the other direction (unless it's a bidir switch), + // so when displaying the 'to-switch', we make the arrow point + // to the left side to match the physical direction. + strcat(midstr, (from_to == SW_TO) ? "<-" : "->"); + } + // fmt_sw() prints only the destination side of the switch (!from_to), + // because it is the significant one in a chain of switches, and if the + // caller wants the source side they can add it outside. + snprintf(sw_buf[last_buf], sizeof(sw_buf[0]), "%s%s%s", + (from_to == SW_FROM) ? "" : fpga_switch_str(model, y, x, sw, SW_FROM), + midstr, + (from_to == SW_TO) ? "" : fpga_switch_str(model, y, x, sw, SW_TO)); + + return sw_buf[last_buf]; +} + +#define FMT_SWCHAIN_BUF_SIZE 2048 +#define FMT_SWCHAIN_NUM_BUFS 8 + +const char* fmt_swchain(struct fpga_model* model, int y, int x, + swidx_t* sw, int sw_size) +{ + static char buf[FMT_SWCHAIN_NUM_BUFS][FMT_SWCHAIN_BUF_SIZE]; + static int last_buf = 0; + int i, o; + + last_buf = (last_buf+1)%FMT_SWCHAIN_NUM_BUFS; + o = 0; + for (i = 0; i < sw_size; i++) { + if (i) buf[last_buf][o++] = ' '; + strcpy(&buf[last_buf][o], fmt_sw(model, y, x, sw[i], SW_FROM)); + o += strlen(&buf[last_buf][o]); + } + buf[last_buf][o] = 0; + return buf[last_buf]; +} + int fpga_switch_chain_enum(struct sw_chain* chain) { swidx_t idx; + struct fpga_tile* tile; + int child_from_to, i; if (chain->start_switch != SW_CHAIN_NEXT) { idx = fpga_switch_first(chain->model, chain->y, chain->x, @@ -478,24 +526,39 @@ int fpga_switch_chain_enum(struct sw_chain* chain) chain->chain[chain->chain_size-1] = idx; } // look for children + tile = YX_TILE(chain->model, chain->y, chain->x); while (1) { idx = fpga_switch_first(chain->model, chain->y, chain->x, fpga_switch_str(chain->model, chain->y, chain->x, chain->chain[chain->chain_size-1], !chain->from_to), chain->from_to); - chain->chain[chain->chain_size-1] = fpga_switch_next( - chain->model, chain->y, chain->x, - chain->chain[chain->chain_size-1], chain->from_to); + child_from_to = SW_I(tile->switches[chain->chain[chain->chain_size-1]], + !chain->from_to); if (idx != NO_SWITCH) { - if (chain->chain_size >= MAX_SW_CHAIN_SIZE) { - HERE(); goto internal_error; + // If we have the same from-switch already among the + // parents, don't fall into endless recursion... + for (i = 0; i < chain->chain_size; i++) { + if (SW_I(tile->switches[chain->chain[i]], chain->from_to) + == child_from_to) + break; + } + if (i >= chain->chain_size) { + if (chain->chain_size >= MAX_SW_CHAIN_SIZE) { + HERE(); goto internal_error; + } + // back to first round at new level + chain->first_round = 1; + chain->chain[chain->chain_size] = idx; + chain->chain_size++; + return 0; } - chain->first_round = 1; // back to first round at new level - chain->chain[chain->chain_size] = idx; - chain->chain_size++; - return 0; } - while (chain->chain[chain->chain_size-1] == NO_SWITCH) { + while (1) { + chain->chain[chain->chain_size-1] = fpga_switch_next( + chain->model, chain->y, chain->x, + chain->chain[chain->chain_size-1], chain->from_to); + if (chain->chain[chain->chain_size-1] != NO_SWITCH) + break; if (chain->chain_size <= 1) { chain->chain_size = 0; return NO_SWITCH; diff --git a/control.h b/control.h index 146d132..9e797c4 100644 --- a/control.h +++ b/control.h @@ -40,11 +40,7 @@ int fpga_connpt_lookup(struct fpga_model* model, int y, int x, const char* fpga_conn_dest(struct fpga_model* model, int y, int x, int connpt_dest_idx, int* dest_y, int* dest_x); -typedef int swidx_t; - -// SW_FROM and SW_TO values are chosen such that ! inverts them. -#define SW_FROM 0 -#define SW_TO 1 +typedef int swidx_t; // swidx_t is an index into the uint32_t switches array // returns a switch index, or -1 (NO_SWITCH) if no switch was found swidx_t fpga_switch_first(struct fpga_model* model, int y, int x, @@ -65,8 +61,13 @@ void fpga_switch_enable(struct fpga_model* model, int y, int x, void fpga_switch_disable(struct fpga_model* model, int y, int x, swidx_t swidx); +const char* fmt_sw(struct fpga_model* model, int y, int x, + swidx_t sw, int from_to); +const char* fmt_swchain(struct fpga_model* model, int y, int x, + swidx_t* sw, int sw_size); + #define SW_CHAIN_NEXT 0 // use for name -#define MAX_SW_CHAIN_SIZE 32 +#define MAX_SW_CHAIN_SIZE 32 // largest seen so far was 10 struct sw_chain { diff --git a/helper.h b/helper.h index e440903..e40dfbf 100644 --- a/helper.h +++ b/helper.h @@ -115,6 +115,8 @@ struct hashed_strarray #define STRIDX_64K 0xFFFF #define STRIDX_1M 1000000 +typedef uint16_t str16_t; + int strarray_init(struct hashed_strarray* array, int highest_index); void strarray_free(struct hashed_strarray* array); diff --git a/model.h b/model.h index cb12874..d5bfe86 100644 --- a/model.h +++ b/model.h @@ -270,6 +270,10 @@ int is_atx(int check, struct fpga_model* model, int x); // True for all tiles that are in the regular 0..15 row tiles of a routing col #define YX_ROUTING_TILE 0x0001 #define YX_IO_ROUTING 0x0002 +#define YX_ROUTING_TO_FABLOGIC 0x0004 // left of a regular fabric logic device +#define YX_DEV_ILOGIC 0x0008 +#define YX_DEV_OLOGIC 0x0010 +#define YX_DEV_LOGIC 0x0020 int is_atyx(int check, struct fpga_model* model, int y, int x); @@ -387,8 +391,14 @@ struct fpga_device #define SWITCH_ON 0x80000000 #define SWITCH_BIDIRECTIONAL 0x40000000 #define SWITCH_MAX_CONNPT_O 0x7FFF // 15 bits -#define SWITCH_FROM(u32) (((u32) >> 15) & SWITCH_MAX_CONNPT_O) -#define SWITCH_TO(u32) ((u32) & SWITCH_MAX_CONNPT_O) +#define SW_FROM_I(u32) (((u32) >> 15) & SWITCH_MAX_CONNPT_O) +#define SW_TO_I(u32) ((u32) & SWITCH_MAX_CONNPT_O) + +#define SW_I(u32, from_to) ((from_to) ? SW_FROM_I(u32) : SW_TO_I(u32)) +// SW_FROM and SW_TO values are chosen such that ! inverts them, +// and swf() assumes that SW_FROM is positive. +#define SW_FROM 1 +#define SW_TO 0 #define NO_SWITCH -1 #define NO_CONN -1 @@ -435,23 +445,30 @@ void fpga_free_model(struct fpga_model* model); const char* fpga_tiletype_str(enum fpga_tile_type type); int init_tiles(struct fpga_model* model); -int init_conns(struct fpga_model* model); -int init_ports(struct fpga_model* model); int init_devices(struct fpga_model* model); void free_devices(struct fpga_model* model); -int init_switches(struct fpga_model* model); +int init_ports(struct fpga_model* model, int dup_warn); +int init_conns(struct fpga_model* model); + +int init_switches(struct fpga_model* model, int routing_sw); +// replicate_routing_switches() is a high-speed optimized way to +// initialize the routing switches, will only work before ports, +// connections or other switches. +int replicate_routing_switches(struct fpga_model* model); const char* pf(const char* fmt, ...); const char* wpref(struct fpga_model* model, int y, int x, const char* wire_name); char next_non_whitespace(const char* s); char last_major(const char* str, int cur_o); int has_connpt(struct fpga_model* model, int y, int x, const char* name); -int add_connpt_name(struct fpga_model* model, int y, int x, const char* connpt_name); +int add_connpt_name(struct fpga_model* model, int y, int x, + const char* connpt_name, int dup_warn); int has_device(struct fpga_model* model, int y, int x, int dev); int has_device_type(struct fpga_model* model, int y, int x, int dev, int subtype); int add_connpt_2(struct fpga_model* model, int y, int x, - const char* connpt_name, const char* suffix1, const char* suffix2); + const char* connpt_name, const char* suffix1, const char* suffix2, + int dup_warn); typedef int (*add_conn_f)(struct fpga_model* model, int y1, int x1, const char* name1, @@ -508,6 +525,12 @@ int add_switch(struct fpga_model* model, int y, int x, const char* from, int add_switch_set(struct fpga_model* model, int y, int x, const char* prefix, const char** pairs, int suffix_inc); +// This will replicate the entire conn_point_names and switches arrays +// from one tile to another, assuming that all of conn_point_names, +// switches and conn_point_dests in the destination tile are empty. +int replicate_switches_and_names(struct fpga_model* model, + int y_from, int x_from, int y_to, int x_to); + struct seed_data { int x_flags; diff --git a/model_conns.c b/model_conns.c index 1dc05eb..329afe2 100644 --- a/model_conns.c +++ b/model_conns.c @@ -788,11 +788,11 @@ static int run_io_wires(struct fpga_model* model) for (i = 0; s[i][0]; i++) { struct w_net net1 = { 1, - {{ pf("BIOB_%s%%i", s[i]), 0, y, x }, - { pf("IOI_BTERM_IOIUP_%s%%i", s[i]), 0, y-1, x }, - { pf("BTERM_IOIUP_%s%%i", s[i]), 0, y-1, x+1 }, + {{ pf("BIOI_INNER_%s%%i", s[i]), 0, y-3, x+1 }, { pf("BIOI_OUTER_%s%%i_EXT", s[i]), 0, y-2, x+1 }, - { pf("BIOI_INNER_%s%%i", s[i]), 0, y-3, x+1 }, + { pf("BTERM_IOIUP_%s%%i", s[i]), 0, y-1, x+1 }, + { pf("IOI_BTERM_IOIUP_%s%%i", s[i]), 0, y-1, x }, + { pf("BIOB_%s%%i", s[i]), 0, y, x }, { "" }}}; if ((rc = add_conn_net(model, NOPREF_BI_F, &net1))) goto xout; diff --git a/model_devices.c b/model_devices.c index 94dce18..085b121 100644 --- a/model_devices.c +++ b/model_devices.c @@ -57,37 +57,37 @@ static int init_iob(struct fpga_model* model, int y, int x, snprintf(tile->devs[idx].iob.pinw_in_O, sizeof(tile->devs[idx].iob.pinw_in_O), "%s_O%i_PINW", prefix, type_idx); - rc = add_connpt_name(model, y, x, tile->devs[idx].iob.pinw_in_O); + rc = add_connpt_name(model, y, x, tile->devs[idx].iob.pinw_in_O, /*dup_warn*/ 1); if (rc) FAIL(rc); snprintf(tile->devs[idx].iob.pinw_in_T, sizeof(tile->devs[idx].iob.pinw_in_T), "%s_T%i_PINW", prefix, type_idx); - rc = add_connpt_name(model, y, x, tile->devs[idx].iob.pinw_in_T); + rc = add_connpt_name(model, y, x, tile->devs[idx].iob.pinw_in_T, /*dup_warn*/ 1); if (rc) FAIL(rc); snprintf(tile->devs[idx].iob.pinw_out_I, sizeof(tile->devs[idx].iob.pinw_out_I), "%s_IBUF%i_PINW", prefix, type_idx); - rc = add_connpt_name(model, y, x, tile->devs[idx].iob.pinw_out_I); + rc = add_connpt_name(model, y, x, tile->devs[idx].iob.pinw_out_I, /*dup_warn*/ 1); if (rc) FAIL(rc); snprintf(tile->devs[idx].iob.pinw_out_PADOUT, sizeof(tile->devs[idx].iob.pinw_out_PADOUT), "%s_PADOUT%i", prefix, type_idx); - rc = add_connpt_name(model, y, x, tile->devs[idx].iob.pinw_out_PADOUT); + rc = add_connpt_name(model, y, x, tile->devs[idx].iob.pinw_out_PADOUT, /*dup_warn*/ 1); if (rc) FAIL(rc); snprintf(tile->devs[idx].iob.pinw_in_DIFFI_IN, sizeof(tile->devs[idx].iob.pinw_in_DIFFI_IN), "%s_DIFFI_IN%i", prefix, type_idx); - rc = add_connpt_name(model, y, x, tile->devs[idx].iob.pinw_in_DIFFI_IN); + rc = add_connpt_name(model, y, x, tile->devs[idx].iob.pinw_in_DIFFI_IN, /*dup_warn*/ 1); if (rc) FAIL(rc); snprintf(tile->devs[idx].iob.pinw_in_DIFFO_IN, sizeof(tile->devs[idx].iob.pinw_in_DIFFO_IN), "%s_DIFFO_IN%i", prefix, type_idx); - rc = add_connpt_name(model, y, x, tile->devs[idx].iob.pinw_in_DIFFO_IN); + rc = add_connpt_name(model, y, x, tile->devs[idx].iob.pinw_in_DIFFO_IN, /*dup_warn*/ 1); if (rc) FAIL(rc); snprintf(tile->devs[idx].iob.pinw_out_DIFFO_OUT, sizeof(tile->devs[idx].iob.pinw_out_DIFFO_OUT), "%s_DIFFO_OUT%i", prefix, type_idx); - rc = add_connpt_name(model, y, x, tile->devs[idx].iob.pinw_out_DIFFO_OUT); + rc = add_connpt_name(model, y, x, tile->devs[idx].iob.pinw_out_DIFFO_OUT, /*dup_warn*/ 1); if (rc) FAIL(rc); if (!x && y == model->center_y - CENTER_TOP_IOB_O && type_idx == 1) @@ -103,7 +103,7 @@ static int init_iob(struct fpga_model* model, int y, int x, sizeof(tile->devs[idx].iob.pinw_out_PCI_RDY), "%s_PCI_RDY%i", prefix, type_idx); } - rc = add_connpt_name(model, y, x, tile->devs[idx].iob.pinw_out_PCI_RDY); + rc = add_connpt_name(model, y, x, tile->devs[idx].iob.pinw_out_PCI_RDY, /*dup_warn*/ 1); if (rc) FAIL(rc); return 0; fail: diff --git a/model_helper.c b/model_helper.c index 3a90e0a..8e4407e 100644 --- a/model_helper.c +++ b/model_helper.c @@ -76,15 +76,29 @@ static int _add_connpt_name(struct fpga_model* model, int y, int x, int* conn_point_o); int add_connpt_name(struct fpga_model* model, int y, int x, - const char* connpt_name) + const char* connpt_name, int dup_warn) { - return _add_connpt_name(model, y, x, connpt_name, - 1 /* warn_if_duplicate */, + return _add_connpt_name(model, y, x, connpt_name, dup_warn, 0 /* name_i */, 0 /* conn_point_o */); } #define CONN_NAMES_INCREMENT 128 +// add_switch() assumes that the new element is appended +// at the end of the array. +static void connpt_names_array_append(struct fpga_tile* tile, int name_i) +{ + if (!(tile->num_conn_point_names % CONN_NAMES_INCREMENT)) { + uint16_t* new_ptr = realloc(tile->conn_point_names, + (tile->num_conn_point_names+CONN_NAMES_INCREMENT)*2*sizeof(uint16_t)); + if (!new_ptr) EXIT(ENOMEM); + tile->conn_point_names = new_ptr; + } + tile->conn_point_names[tile->num_conn_point_names*2] = tile->num_conn_point_dests; + tile->conn_point_names[tile->num_conn_point_names*2+1] = name_i; + tile->num_conn_point_names++; +} + static int _add_connpt_name(struct fpga_model* model, int y, int x, const char* connpt_name, int warn_if_duplicate, uint16_t* name_i, int* conn_point_o) @@ -117,18 +131,7 @@ static int _add_connpt_name(struct fpga_model* model, int y, int x, return 0; } // This is the first connection under name, add name. - if (!(tile->num_conn_point_names % CONN_NAMES_INCREMENT)) { - uint16_t* new_ptr = realloc(tile->conn_point_names, - (tile->num_conn_point_names+CONN_NAMES_INCREMENT)*2*sizeof(uint16_t)); - if (!new_ptr) { - fprintf(stderr, "Out of memory %s:%i\n", __FILE__, __LINE__); - return 0; - } - tile->conn_point_names = new_ptr; - } - tile->conn_point_names[tile->num_conn_point_names*2] = tile->num_conn_point_dests; - tile->conn_point_names[tile->num_conn_point_names*2+1] = _name_i; - tile->num_conn_point_names++; + connpt_names_array_append(tile, _name_i); return 0; } @@ -168,16 +171,17 @@ int has_device_type(struct fpga_model* model, int y, int x, int dev, int subtype } int add_connpt_2(struct fpga_model* model, int y, int x, - const char* connpt_name, const char* suffix1, const char* suffix2) + const char* connpt_name, const char* suffix1, const char* suffix2, + int dup_warn) { char name_buf[64]; int rc; snprintf(name_buf, sizeof(name_buf), "%s%s", connpt_name, suffix1); - rc = add_connpt_name(model, y, x, name_buf); + rc = add_connpt_name(model, y, x, name_buf, dup_warn); if (rc) goto xout; snprintf(name_buf, sizeof(name_buf), "%s%s", connpt_name, suffix2); - rc = add_connpt_name(model, y, x, name_buf); + rc = add_connpt_name(model, y, x, name_buf, dup_warn); if (rc) goto xout; return 0; xout: @@ -322,9 +326,13 @@ xout: return rc; } -#define SWITCH_ALLOC_INCREMENT 64 +#define SWITCH_ALLOC_INCREMENT 256 #define DBG_ALLOW_ADDPOINTS +// Enable CHECK_DUPLICATES when working on the switch architecture, +// but otherwise keep it disabled since it slows down building the +// model a lot. +#undef CHECK_DUPLICATES int add_switch(struct fpga_model* model, int y, int x, const char* from, const char* to, int is_bidirectional) @@ -352,42 +360,31 @@ int add_switch(struct fpga_model* model, int y, int x, const char* from, return -1; } + // It seems searching backwards is a little faster than + // searching forwards. Merging the two loops into one + // made the total slower, presumably due to cache issues. from_connpt_o = -1; - for (i = 0; i < tile->num_conn_point_names; i++) { + for (i = tile->num_conn_point_names-1; i >= 0; i--) { if (tile->conn_point_names[i*2+1] == from_idx) { from_connpt_o = i; break; } } -#ifdef DBG_ALLOW_ADDPOINTS - if (from_connpt_o == -1) { - rc = add_connpt_name(model, y, x, from); - if (rc) goto xout; - for (i = 0; i < tile->num_conn_point_names; i++) { - if (tile->conn_point_names[i*2+1] == from_idx) { - from_connpt_o = i; - break; - } - } - } -#endif to_connpt_o = -1; - for (i = 0; i < tile->num_conn_point_names; i++) { + for (i = tile->num_conn_point_names-1; i >= 0; i--) { if (tile->conn_point_names[i*2+1] == to_idx) { to_connpt_o = i; break; } } #ifdef DBG_ALLOW_ADDPOINTS + if (from_connpt_o == -1) { + from_connpt_o = tile->num_conn_point_names; + connpt_names_array_append(tile, from_idx); + } if (to_connpt_o == -1) { - rc = add_connpt_name(model, y, x, to); - if (rc) goto xout; - for (i = 0; i < tile->num_conn_point_names; i++) { - if (tile->conn_point_names[i*2+1] == to_idx) { - to_connpt_o = i; - break; - } - } + to_connpt_o = tile->num_conn_point_names; + connpt_names_array_append(tile, to_idx); } #endif if (from_connpt_o == -1 || to_connpt_o == -1) { @@ -405,6 +402,7 @@ int add_switch(struct fpga_model* model, int y, int x, const char* from, if (is_bidirectional) new_switch |= SWITCH_BIDIRECTIONAL; +#ifdef CHECK_DUPLICATES for (i = 0; i < tile->num_switches; i++) { if ((tile->switches[i] & 0x3FFFFFFF) == (new_switch & 0x3FFFFFFF)) { fprintf(stderr, "Internal error in %s:%i duplicate switch from %s to %s\n", @@ -412,6 +410,7 @@ int add_switch(struct fpga_model* model, int y, int x, const char* from, return -1; } } +#endif if (!(tile->num_switches % SWITCH_ALLOC_INCREMENT)) { uint32_t* new_ptr = realloc(tile->switches, (tile->num_switches+SWITCH_ALLOC_INCREMENT)*sizeof(*tile->switches)); @@ -457,6 +456,35 @@ xout: return rc; } +int replicate_switches_and_names(struct fpga_model* model, + int y_from, int x_from, int y_to, int x_to) +{ + struct fpga_tile* from_tile, *to_tile; + int rc; + + from_tile = YX_TILE(model, y_from, x_from); + to_tile = YX_TILE(model, y_to, x_to); + if (to_tile->num_conn_point_names + || to_tile->num_conn_point_dests + || to_tile->num_switches + || from_tile->num_conn_point_dests + || !from_tile->num_conn_point_names + || !from_tile->num_switches) FAIL(EINVAL); + + to_tile->conn_point_names = malloc(((from_tile->num_conn_point_names/CONN_NAMES_INCREMENT)+1)*CONN_NAMES_INCREMENT*2*sizeof(uint16_t)); + if (!to_tile->conn_point_names) EXIT(ENOMEM); + memcpy(to_tile->conn_point_names, from_tile->conn_point_names, from_tile->num_conn_point_names*2*sizeof(uint16_t)); + to_tile->num_conn_point_names = from_tile->num_conn_point_names; + + to_tile->switches = malloc(((from_tile->num_switches/SWITCH_ALLOC_INCREMENT)+1)*SWITCH_ALLOC_INCREMENT*sizeof(*from_tile->switches)); + if (!to_tile->switches) EXIT(ENOMEM); + memcpy(to_tile->switches, from_tile->switches, from_tile->num_switches*sizeof(*from_tile->switches)); + to_tile->num_switches = from_tile->num_switches; + return 0; +fail: + return rc; +} + void seed_strx(struct fpga_model* model, struct seed_data* data) { int x, i; @@ -584,6 +612,12 @@ int is_atyx(int check, struct fpga_model* model, int y, int x) tile = YX_TILE(model, y, x); if (check & YX_IO_ROUTING && (tile->type == IO_ROUTING || tile->type == ROUTING_IO_L)) return 1; + if (check & YX_ROUTING_TO_FABLOGIC + && model->tiles[x].flags & TF_FABRIC_ROUTING_COL + && has_device(model, y, x+1, DEV_LOGIC)) return 1; + if (check & YX_DEV_ILOGIC && has_device(model, y, x, DEV_ILOGIC)) return 1; + if (check & YX_DEV_OLOGIC && has_device(model, y, x, DEV_OLOGIC)) return 1; + if (check & YX_DEV_LOGIC && has_device(model, y, x, DEV_LOGIC)) return 1; return 0; } diff --git a/model_main.c b/model_main.c index edc9541..81bc028 100644 --- a/model_main.c +++ b/model_main.c @@ -8,8 +8,10 @@ #include #include "model.h" -int fpga_build_model(struct fpga_model* model, int fpga_rows, const char* columns, - const char* left_wiring, const char* right_wiring) +static int s_high_speed_replicate = 1; + +int fpga_build_model(struct fpga_model* model, int fpga_rows, + const char* columns, const char* left_wiring, const char* right_wiring) { int rc; @@ -27,21 +29,30 @@ int fpga_build_model(struct fpga_model* model, int fpga_rows, const char* column // that the codes can build upon each other. rc = init_tiles(model); - if (rc) return rc; + if (rc) FAIL(rc); rc = init_devices(model); - if (rc) return rc; + if (rc) FAIL(rc); - rc = init_ports(model); - if (rc) return rc; + if (s_high_speed_replicate) { + rc = replicate_routing_switches(model); + if (rc) FAIL(rc); + } + + // todo: compare.ports only works if other switches and conns + // are disabled, as long as not all connections are supported + rc = init_ports(model, /*dup_warn*/ !s_high_speed_replicate); + if (rc) FAIL(rc); rc = init_conns(model); - if (rc) return rc; + if (rc) FAIL(rc); - rc = init_switches(model); - if (rc) return rc; + rc = init_switches(model, /*routing_sw*/ !s_high_speed_replicate); + if (rc) FAIL(rc); return 0; +fail: + return rc; } void fpga_free_model(struct fpga_model* model) diff --git a/model_ports.c b/model_ports.c index d850928..d4943c9 100644 --- a/model_ports.c +++ b/model_ports.c @@ -13,7 +13,8 @@ enum which_side TOP_S, BOTTOM_S, RIGHT_S, LEFT_S }; -static int init_iologic_ports(struct fpga_model* model, int y, int x, enum which_side side) +static int init_iologic_ports(struct fpga_model* model, int y, int x, + enum which_side side, int dup_warn) { static const char* prefix, *suffix1, *suffix2; int rc, i; @@ -34,53 +35,53 @@ static int init_iologic_ports(struct fpga_model* model, int y, int x, enum which } for (i = X_A /* 0 */; i <= M_DQ /* 23 */; i++) { - rc = add_connpt_name(model, y, x, pf("IOI_INTER_LOGICOUT%i", i)); + rc = add_connpt_name(model, y, x, pf("IOI_INTER_LOGICOUT%i", i), dup_warn); if (rc) goto xout; } - rc = add_connpt_name(model, y, x, pf("%s_GND_TIEOFF", prefix)); + rc = add_connpt_name(model, y, x, pf("%s_GND_TIEOFF", prefix), dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, pf("%s_VCC_TIEOFF", prefix)); + rc = add_connpt_name(model, y, x, pf("%s_VCC_TIEOFF", prefix), dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, pf("%s_KEEP1_STUB", prefix)); + rc = add_connpt_name(model, y, x, pf("%s_KEEP1_STUB", prefix), dup_warn); if (rc) goto xout; for (i = 0; i <= 4; i++) { - rc = add_connpt_2(model, y, x, pf("AUXADDR%i_IODELAY", i), suffix1, suffix2); + rc = add_connpt_2(model, y, x, pf("AUXADDR%i_IODELAY", i), suffix1, suffix2, dup_warn); if (rc) goto xout; } - rc = add_connpt_2(model, y, x, "AUXSDOIN_IODELAY", suffix1, suffix2); + rc = add_connpt_2(model, y, x, "AUXSDOIN_IODELAY", suffix1, suffix2, dup_warn); if (rc) goto xout; - rc = add_connpt_2(model, y, x, "AUXSDO_IODELAY", suffix1, suffix2); + rc = add_connpt_2(model, y, x, "AUXSDO_IODELAY", suffix1, suffix2, dup_warn); if (rc) goto xout; - rc = add_connpt_2(model, y, x, "MEMUPDATE_IODELAY", suffix1, suffix2); + rc = add_connpt_2(model, y, x, "MEMUPDATE_IODELAY", suffix1, suffix2, dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, "OUTN_IODELAY_SITE"); + rc = add_connpt_name(model, y, x, "OUTN_IODELAY_SITE", dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, "STUB_OUTN_IODELAY_S"); + rc = add_connpt_name(model, y, x, "STUB_OUTN_IODELAY_S", dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, "OUTP_IODELAY_SITE"); + rc = add_connpt_name(model, y, x, "OUTP_IODELAY_SITE", dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, "STUB_OUTP_IODELAY_S"); + rc = add_connpt_name(model, y, x, "STUB_OUTP_IODELAY_S", dup_warn); if (rc) goto xout; for (i = 1; i <= 4; i++) { - rc = add_connpt_2(model, y, x, pf("Q%i_ILOGIC_SITE", i), "", "_S"); + rc = add_connpt_2(model, y, x, pf("Q%i_ILOGIC_SITE", i), "", "_S", dup_warn); if (rc) goto xout; - rc = add_connpt_2(model, y, x, pf("D%i_OLOGIC_SITE", i), "", "_S"); + rc = add_connpt_2(model, y, x, pf("D%i_OLOGIC_SITE", i), "", "_S", dup_warn); if (rc) goto xout; - rc = add_connpt_2(model, y, x, pf("T%i_OLOGIC_SITE", i), "", "_S"); + rc = add_connpt_2(model, y, x, pf("T%i_OLOGIC_SITE", i), "", "_S", dup_warn); if (rc) goto xout; - rc = add_connpt_2(model, y, x, pf("SHIFTIN%i_OLOGIC_SITE", i), "", "_S"); + rc = add_connpt_2(model, y, x, pf("SHIFTIN%i_OLOGIC_SITE", i), "", "_S", dup_warn); if (rc) goto xout; - rc = add_connpt_2(model, y, x, pf("SHIFTOUT%i_OLOGIC_SITE", i), "", "_S"); + rc = add_connpt_2(model, y, x, pf("SHIFTOUT%i_OLOGIC_SITE", i), "", "_S", dup_warn); if (rc) goto xout; } for (i = 0; i <= 1; i++) { - rc = add_connpt_2(model, y, x, pf("CFB%i_ILOGIC_SITE", i), "", "_S"); + rc = add_connpt_2(model, y, x, pf("CFB%i_ILOGIC_SITE", i), "", "_S", dup_warn); if (rc) goto xout; - rc = add_connpt_2(model, y, x, pf("CLK%i_ILOGIC_SITE", i), "", "_S"); + rc = add_connpt_2(model, y, x, pf("CLK%i_ILOGIC_SITE", i), "", "_S", dup_warn); if (rc) goto xout; - rc = add_connpt_2(model, y, x, pf("CLK%i_OLOGIC_SITE", i), "", "_S"); + rc = add_connpt_2(model, y, x, pf("CLK%i_OLOGIC_SITE", i), "", "_S", dup_warn); if (rc) goto xout; } { @@ -110,29 +111,29 @@ static int init_iologic_ports(struct fpga_model* model, int y, int x, enum which "VALID_ILOGIC_SITE", "" }; for (i = 0; mcb_2[i][0]; i++) { - rc = add_connpt_2(model, y, x, mcb_2[i], "", "_S"); + rc = add_connpt_2(model, y, x, mcb_2[i], "", "_S", dup_warn); } } - rc = add_connpt_name(model, y, x, "DATAOUT2_IODELAY_SITE"); + rc = add_connpt_name(model, y, x, "DATAOUT2_IODELAY_SITE", dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, "DATAOUT2_IODELAY2_SITE_S"); + rc = add_connpt_name(model, y, x, "DATAOUT2_IODELAY2_SITE_S", dup_warn); if (rc) goto xout; for (i = 0; i <= 2; i++) { rc = add_connpt_2(model, y, x, pf("IOI_CLK%iINTER", i), - "_M", "_S"); + "_M", "_S", dup_warn); if (rc) goto xout; } for (i = 0; i <= 1; i++) { rc = add_connpt_2(model, y, x, pf("IOI_CLKDIST_IOCE%i", i), - "_M", "_S"); + "_M", "_S", dup_warn); if (rc) goto xout; } - rc = add_connpt_2(model, y, x, "IOI_CLKDIST_CLK0_ILOGIC", "_M", "_S"); + rc = add_connpt_2(model, y, x, "IOI_CLKDIST_CLK0_ILOGIC", "_M", "_S", dup_warn); if (rc) goto xout; - rc = add_connpt_2(model, y, x, "IOI_CLKDIST_CLK0_OLOGIC", "_M", "_S"); + rc = add_connpt_2(model, y, x, "IOI_CLKDIST_CLK0_OLOGIC", "_M", "_S", dup_warn); if (rc) goto xout; - rc = add_connpt_2(model, y, x, "IOI_CLKDIST_CLK1", "_M", "_S"); + rc = add_connpt_2(model, y, x, "IOI_CLKDIST_CLK1", "_M", "_S", dup_warn); if (rc) goto xout; if (side == TOP_S || side == BOTTOM_S) { @@ -147,11 +148,11 @@ static int init_iologic_ports(struct fpga_model* model, int y, int x, enum which "IOI_MCB_DRPTRAIN", "" }; for (i = 0; mcb_2[i][0]; i++) { - rc = add_connpt_2(model, y, x, mcb_2[i], "_M", "_S"); + rc = add_connpt_2(model, y, x, mcb_2[i], "_M", "_S", dup_warn); if (rc) goto xout; } for (i = 0; mcb_1[i][0]; i++) { - rc = add_connpt_name(model, y, x, mcb_1[i]); + rc = add_connpt_name(model, y, x, mcb_1[i], dup_warn); if (rc) goto xout; } } @@ -160,36 +161,36 @@ xout: return rc; } -int init_ports(struct fpga_model* model) +int init_ports(struct fpga_model* model, int dup_warn) { int x, y, i, j, k, row_num, row_pos, rc; // inner and outer IO tiles (ILOGIC/ILOGIC/IODELAY) for (x = LEFT_SIDE_WIDTH; x < model->x_width - RIGHT_SIDE_WIDTH; x++) { if (has_device(model, TOP_OUTER_IO, x, DEV_ILOGIC)) { - rc = init_iologic_ports(model, TOP_OUTER_IO, x, TOP_S); + rc = init_iologic_ports(model, TOP_OUTER_IO, x, TOP_S, dup_warn); if (rc) goto xout; } if (has_device(model, TOP_INNER_IO, x, DEV_ILOGIC)) { - rc = init_iologic_ports(model, TOP_INNER_IO, x, TOP_S); + rc = init_iologic_ports(model, TOP_INNER_IO, x, TOP_S, dup_warn); if (rc) goto xout; } if (has_device(model, model->y_height - BOT_INNER_IO, x, DEV_ILOGIC)) { - rc = init_iologic_ports(model, model->y_height - BOT_INNER_IO, x, BOTTOM_S); + rc = init_iologic_ports(model, model->y_height - BOT_INNER_IO, x, BOTTOM_S, dup_warn); if (rc) goto xout; } if (has_device(model, model->y_height - BOT_OUTER_IO, x, DEV_ILOGIC)) { - rc = init_iologic_ports(model, model->y_height - BOT_OUTER_IO, x, BOTTOM_S); + rc = init_iologic_ports(model, model->y_height - BOT_OUTER_IO, x, BOTTOM_S, dup_warn); if (rc) goto xout; } } for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) { if (has_device(model, y, LEFT_IO_DEVS, DEV_ILOGIC)) { - rc = init_iologic_ports(model, y, LEFT_IO_DEVS, LEFT_S); + rc = init_iologic_ports(model, y, LEFT_IO_DEVS, LEFT_S, dup_warn); if (rc) goto xout; } if (has_device(model, y, model->x_width - RIGHT_IO_DEVS_O, DEV_ILOGIC)) { - rc = init_iologic_ports(model, y, model->x_width - RIGHT_IO_DEVS_O, RIGHT_S); + rc = init_iologic_ports(model, y, model->x_width - RIGHT_IO_DEVS_O, RIGHT_S, dup_warn); if (rc) goto xout; } } @@ -200,20 +201,20 @@ int init_ports(struct fpga_model* model) if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y)) continue; - rc = add_connpt_name(model, y, x, "VCC_WIRE"); + rc = add_connpt_name(model, y, x, "VCC_WIRE", dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, "GND_WIRE"); + rc = add_connpt_name(model, y, x, "GND_WIRE", dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, "KEEP1_WIRE"); + rc = add_connpt_name(model, y, x, "KEEP1_WIRE", dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, "FAN"); + rc = add_connpt_name(model, y, x, "FAN", dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, "FAN_B"); + rc = add_connpt_name(model, y, x, "FAN_B", dup_warn); if (rc) goto xout; if (!is_atyx(YX_IO_ROUTING, model, y, x)) { for (i = 0; i <= 1; i++) { - rc = add_connpt_name(model, y, x, pf("GFAN%i", i)); + rc = add_connpt_name(model, y, x, pf("GFAN%i", i), dup_warn); if (rc) goto xout; } } else { @@ -223,10 +224,10 @@ int init_ports(struct fpga_model* model) // to the PLL, but elsewhere? Not clear what they // connect to... rc = add_connpt_name(model, y, x, - logicin_s(X_A5, 1 /* routing_io */)); + logicin_s(X_A5, 1 /* routing_io */), dup_warn); if (rc) goto xout; rc = add_connpt_name(model, y, x, - logicin_s(X_B4, 1 /* routing_io */)); + logicin_s(X_B4, 1 /* routing_io */), dup_warn); if (rc) goto xout; } } @@ -240,30 +241,30 @@ int init_ports(struct fpga_model* model) // pass 0 is ramb16, pass 1 and 2 are for ramb8 for (i = 0; i <= 2; i++) { for (j = 'A'; j <= 'B'; j++) { - rc = add_connpt_name(model, y, x, pf("%s_CLK%c", pass_str[i], j)); + rc = add_connpt_name(model, y, x, pf("%s_CLK%c", pass_str[i], j), dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, pf("%s_EN%c", pass_str[i], j)); + rc = add_connpt_name(model, y, x, pf("%s_EN%c", pass_str[i], j), dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, pf("%s_REGCE%c", pass_str[i], j)); + rc = add_connpt_name(model, y, x, pf("%s_REGCE%c", pass_str[i], j), dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, pf("%s_RST%c", pass_str[i], j)); + rc = add_connpt_name(model, y, x, pf("%s_RST%c", pass_str[i], j), dup_warn); if (rc) goto xout; for (k = 0; k <= (!i ? 3 : 1); k++) { - rc = add_connpt_name(model, y, x, pf("%s_DIP%c%i", pass_str[i], j, k)); + rc = add_connpt_name(model, y, x, pf("%s_DIP%c%i", pass_str[i], j, k), dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, pf("%s_DOP%c%i", pass_str[i], j, k)); + rc = add_connpt_name(model, y, x, pf("%s_DOP%c%i", pass_str[i], j, k), dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, pf("%s_WE%c%i", pass_str[i], j, k)); + rc = add_connpt_name(model, y, x, pf("%s_WE%c%i", pass_str[i], j, k), dup_warn); if (rc) goto xout; } for (k = 0; k <= (!i ? 13 : 12); k++) { - rc = add_connpt_name(model, y, x, pf("%s_ADDR%c%i", pass_str[i], j, k)); + rc = add_connpt_name(model, y, x, pf("%s_ADDR%c%i", pass_str[i], j, k), dup_warn); if (rc) goto xout; } for (k = 0; k <= (!i ? 31 : 15); k++) { - rc = add_connpt_name(model, y, x, pf("%s_DI%c%i", pass_str[i], j, k)); + rc = add_connpt_name(model, y, x, pf("%s_DI%c%i", pass_str[i], j, k), dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, pf("%s_DO%c%i", pass_str[i], j, k)); + rc = add_connpt_name(model, y, x, pf("%s_DO%c%i", pass_str[i], j, k), dup_warn); if (rc) goto xout; } } @@ -279,54 +280,54 @@ int init_ports(struct fpga_model* model) is_in_row(model, y, &row_num, &row_pos); if (!row_num && row_pos == LAST_POS_IN_ROW) { - rc = add_connpt_name(model, y, x, "CARRYIN_DSP48A1_SITE"); + rc = add_connpt_name(model, y, x, "CARRYIN_DSP48A1_SITE", dup_warn); if (rc) goto xout; for (i = 0; i <= 47; i++) { - rc = add_connpt_name(model, y, x, pf("PCIN%i_DSP48A1_SITE", i)); + rc = add_connpt_name(model, y, x, pf("PCIN%i_DSP48A1_SITE", i), dup_warn); if (rc) goto xout; } } - rc = add_connpt_name(model, y, x, "CLK_DSP48A1_SITE"); + rc = add_connpt_name(model, y, x, "CLK_DSP48A1_SITE", dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, "CARRYOUT_DSP48A1_SITE"); + rc = add_connpt_name(model, y, x, "CARRYOUT_DSP48A1_SITE", dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, "CARRYOUTF_DSP48A1_SITE"); + rc = add_connpt_name(model, y, x, "CARRYOUTF_DSP48A1_SITE", dup_warn); if (rc) goto xout; for (i = 0; pref[i][0]; i++) { - rc = add_connpt_name(model, y, x, pf("%sCARRYIN_DSP48A1_SITE", pref[i])); + rc = add_connpt_name(model, y, x, pf("%sCARRYIN_DSP48A1_SITE", pref[i]), dup_warn); if (rc) goto xout; for (j = 0; seq[j][0]; j++) { - rc = add_connpt_name(model, y, x, pf("%s%s_DSP48A1_SITE", pref[i], seq[j])); + rc = add_connpt_name(model, y, x, pf("%s%s_DSP48A1_SITE", pref[i], seq[j]), dup_warn); if (rc) goto xout; } } for (i = 0; i <= 17; i++) { - rc = add_connpt_name(model, y, x, pf("A%i_DSP48A1_SITE", i)); + rc = add_connpt_name(model, y, x, pf("A%i_DSP48A1_SITE", i), dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, pf("B%i_DSP48A1_SITE", i)); + rc = add_connpt_name(model, y, x, pf("B%i_DSP48A1_SITE", i), dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, pf("D%i_DSP48A1_SITE", i)); + rc = add_connpt_name(model, y, x, pf("D%i_DSP48A1_SITE", i), dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, pf("BCOUT%i_DSP48A1_SITE", i)); + rc = add_connpt_name(model, y, x, pf("BCOUT%i_DSP48A1_SITE", i), dup_warn); if (rc) goto xout; } for (i = 0; i <= 47; i++) { - rc = add_connpt_name(model, y, x, pf("C%i_DSP48A1_SITE", i)); + rc = add_connpt_name(model, y, x, pf("C%i_DSP48A1_SITE", i), dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, pf("P%i_DSP48A1_SITE", i)); + rc = add_connpt_name(model, y, x, pf("P%i_DSP48A1_SITE", i), dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, pf("PCOUT%i_DSP48A1_SITE", i)); + rc = add_connpt_name(model, y, x, pf("PCOUT%i_DSP48A1_SITE", i), dup_warn); if (rc) goto xout; } for (i = 0; i <= 35; i++) { - rc = add_connpt_name(model, y, x, pf("M%i_DSP48A1_SITE", i)); + rc = add_connpt_name(model, y, x, pf("M%i_DSP48A1_SITE", i), dup_warn); if (rc) goto xout; } for (i = 0; i <= 7; i++) { - rc = add_connpt_name(model, y, x, pf("OPMODE%i_DSP48A1_SITE", i)); + rc = add_connpt_name(model, y, x, pf("OPMODE%i_DSP48A1_SITE", i), dup_warn); if (rc) goto xout; } } @@ -340,44 +341,44 @@ int init_ports(struct fpga_model* model) if (YX_TILE(model, y, x)->flags & TF_LOGIC_XM_DEV) { // The first SLICEM on the bottom has a given C_IN port. if (is_aty(Y_INNER_BOTTOM, model, y+3)) { - rc = add_connpt_name(model, y, x, "M_CIN"); + rc = add_connpt_name(model, y, x, "M_CIN", dup_warn); if (rc) goto xout; } - rc = add_connpt_name(model, y, x, "M_COUT"); + rc = add_connpt_name(model, y, x, "M_COUT", dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, "M_WE"); + rc = add_connpt_name(model, y, x, "M_WE", dup_warn); if (rc) goto xout; for (i = 'A'; i <= 'D'; i++) { - rc = add_connpt_name(model, y, x, pf("M_%cI", i)); + rc = add_connpt_name(model, y, x, pf("M_%cI", i), dup_warn); if (rc) goto xout; } pref[0] = "M"; pref[1] = "X"; } else { // LOGIC_XL - rc = add_connpt_name(model, y, x, "XL_COUT"); + rc = add_connpt_name(model, y, x, "XL_COUT", dup_warn); if (rc) goto xout; pref[0] = "L"; pref[1] = "XX"; } for (k = 0; k <= 1; k++) { - rc = add_connpt_name(model, y, x, pf("%s_CE", pref[k])); + rc = add_connpt_name(model, y, x, pf("%s_CE", pref[k]), dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, pf("%s_SR", pref[k])); + rc = add_connpt_name(model, y, x, pf("%s_SR", pref[k]), dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, pf("%s_CLK", pref[k])); + rc = add_connpt_name(model, y, x, pf("%s_CLK", pref[k]), dup_warn); if (rc) goto xout; for (i = 'A'; i <= 'D'; i++) { for (j = 1; j <= 6; j++) { - rc = add_connpt_name(model, y, x, pf("%s_%c%i", pref[k], i, j)); + rc = add_connpt_name(model, y, x, pf("%s_%c%i", pref[k], i, j), dup_warn); if (rc) goto xout; } - rc = add_connpt_name(model, y, x, pf("%s_%c", pref[k], i)); + rc = add_connpt_name(model, y, x, pf("%s_%c", pref[k], i), dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, pf("%s_%cMUX", pref[k], i)); + rc = add_connpt_name(model, y, x, pf("%s_%cMUX", pref[k], i), dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, pf("%s_%cQ", pref[k], i)); + rc = add_connpt_name(model, y, x, pf("%s_%cQ", pref[k], i), dup_warn); if (rc) goto xout; - rc = add_connpt_name(model, y, x, pf("%s_%cX", pref[k], i)); + rc = add_connpt_name(model, y, x, pf("%s_%cX", pref[k], i), dup_warn); if (rc) goto xout; } } diff --git a/model_switches.c b/model_switches.c index bb947e4..72c95c6 100644 --- a/model_switches.c +++ b/model_switches.c @@ -15,10 +15,15 @@ static int init_north_south_dirwire_term(struct fpga_model* model); static int init_iologic_switches(struct fpga_model* model); static int init_logic_switches(struct fpga_model* model); -int init_switches(struct fpga_model* model) +int init_switches(struct fpga_model* model, int routing_sw) { int rc; + if (routing_sw) { + rc = init_routing_switches(model); + if (rc) goto xout; + } + rc = init_logic_switches(model); if (rc) goto xout; @@ -34,10 +39,6 @@ int init_switches(struct fpga_model* model) rc = init_io_switches(model); if (rc) goto xout; -#if 0 - rc = init_routing_switches(model); - if (rc) goto xout; -#endif return 0; xout: return rc; @@ -1671,238 +1672,279 @@ xout: return rc; } -static int init_routing_switches(struct fpga_model* model) +static int init_routing_tile(struct fpga_model* model, int y, int x) { - int x, y, i, j, routing_io, rc; + int i, j, routing_io, rc; struct set_of_switches dir_EB_switches; enum wire_type wire; struct fpga_tile* tile; const char* gfan_s, *gclk_s; + tile = YX_TILE(model, y, x); + routing_io = (tile->type == IO_ROUTING || tile->type == ROUTING_IO_L); + gfan_s = routing_io ? "INT_IOI_GFAN%i" : "GFAN%i"; + + // GND + for (i = 0; i <= 1; i++) { + rc = add_switch(model, y, x, "GND_WIRE", + pf(gfan_s, i), 0 /* bidir */); + if (rc) FAIL(rc); + } + rc = add_switch(model, y, x, "GND_WIRE", "SR1", 0 /* bidir */); + if (rc) FAIL(rc); + + // VCC + { int vcc_dest[] = { + X_A3, X_A4, X_A5, X_A6, X_B3, X_B4, X_B5, X_B6, + X_C3, X_C4, X_C5, X_C6, X_D3, X_D4, X_D5, X_D6, + M_A3, M_A4, M_A5, M_A6, M_B3, M_B4, M_B5, M_B6, + M_C3, M_C4, M_C5, M_C6, M_D3, M_D4, M_D5, M_D6 }; + + for (i = 0; i < sizeof(vcc_dest)/sizeof(vcc_dest[0]); i++) { + rc = add_switch(model, y, x, "VCC_WIRE", + logicin_s(vcc_dest[i], routing_io), 0 /* bidir */); + if (rc) FAIL(rc); + }} + + // KEEP1 + for (i = X_A1; i <= M_WE; i++) { + rc = add_switch(model, y, x, "KEEP1_WIRE", + logicin_s(i, routing_io), 0 /* bidir */); + if (rc) FAIL(rc); + } + rc = add_switch(model, y, x, "KEEP1_WIRE", "FAN_B", 0 /* bidir */); + if (rc) FAIL(rc); + + // VCC and KEEP1 to CLK0:1, SR0:1, GFAN0:1 + { static const char* src[] = {"VCC_WIRE", "KEEP1_WIRE"}; + for (i = 0; i <= 1; i++) + for (j = 0; j <= 1; j++) { + rc = add_switch(model, y, x, src[i], + pf("CLK%i", j), 0 /* bidir */); + if (rc) FAIL(rc); + rc = add_switch(model, y, x, src[i], + pf("SR%i", j), 0 /* bidir */); + if (rc) FAIL(rc); + rc = add_switch(model, y, x, + src[i], pf(gfan_s, j), 0 /* bidir */); + if (rc) FAIL(rc); + } + } + + // GCLK0:15 -> CLK0:1, GFAN0:1/SR0:1 + if (tile->type == ROUTING_BRK + || tile->type == BRAM_ROUTING_BRK) + gclk_s = "GCLK%i_BRK"; + else + gclk_s = "GCLK%i"; + for (i = 0; i <= 15; i++) { + for (j = 0; j <= 1; j++) { + rc = add_switch(model, y, x, pf(gclk_s, i), + pf("CLK%i", j), 0 /* bidir */); + if (rc) FAIL(rc); + rc = add_switch(model, y, x, + pf(gclk_s, i), + (i < 8) ? pf(gfan_s, j) : pf("SR%i", j), + 0 /* bidir */); + if (rc) FAIL(rc); + } + } + + // FAN_B to SR0:1 + for (i = 0; i <= 1; i++) { + rc = add_switch(model, y, x, "FAN_B", + pf("SR%i", i), 0 /* bidir */); + if (rc) FAIL(rc); + } + + // some logicin wires are singled out + { int logic_singles[] = {X_CE, X_CX, X_DX, + M_AI, M_BI, M_CX, M_DX, M_WE}; + for (i = 0; i < sizeof(logic_singles)/sizeof(logic_singles[0]); i++) { + rc = add_switch(model, y, x, + pf("LOGICIN_B%i", logic_singles[i]), + pf("LOGICIN%i", logic_singles[i]), 0 /* bidir */); + if (rc) FAIL(rc); + }} + + // connecting directional wires endpoints to logicin + rc = add_logicin_switches(model, y, x); + if (rc) FAIL(rc); + + // connecting logicout back to directional wires + // beginning points (and some back to logicin) + rc = add_logicout_switches(model, y, x, routing_io); + if (rc) FAIL(rc); + + // there are extra wires to send signals to logicin, or + // to share/multiply logicin signals + rc = add_logicio_extra(model, y, x, routing_io); + if (rc) FAIL(rc); + + // extra wires going to SR, CLK and GFAN + { int to_sr[] = {X_BX, M_BX, M_DI}; + for (i = 0; i < sizeof(to_sr)/sizeof(to_sr[0]); i++) { + for (j = 0; j <= 1; j++) { + rc = add_switch(model, y, x, + pf("LOGICIN_B%i", to_sr[i]), + pf("SR%i", j), 0 /* bidir */); + if (rc) FAIL(rc); + } + }} + { int to_clk[] = {M_BX, M_CI}; + for (i = 0; i < sizeof(to_clk)/sizeof(to_clk[0]); i++) { + for (j = 0; j <= 1; j++) { + rc = add_switch(model, y, x, + pf("LOGICIN_B%i", to_clk[i]), + pf("CLK%i", j), 0 /* bidir */); + if (rc) FAIL(rc); + } + }} + { int to_gf[] = {M_AX, X_AX, M_CE, M_CI}; + for (i = 0; i < sizeof(to_gf)/sizeof(to_gf[0]); i++) { + for (j = 0; j <= 1; j++) { + int bidir = !routing_io + && ((!j && i < 2) || (j && i >= 2)); + rc = add_switch(model, y, x, + pf("LOGICIN_B%i", to_gf[i]), + pf(gfan_s, j), bidir); + if (rc) FAIL(rc); + } + }} + + // connecting the directional wires from one's end + // to another one's beginning + wire = W_NN2; + do { + rc = build_dirwire_switches(&dir_EB_switches, W_TO_LEN1(wire)); + if (rc) FAIL(rc); + for (i = 0; i < dir_EB_switches.num_s; i++) { + rc = add_switch(model, y, x, + dir_EB_switches.s[i].from, + dir_EB_switches.s[i].to, 0 /* bidir */); + if (rc) FAIL(rc); + } + + rc = build_dirwire_switches(&dir_EB_switches, W_TO_LEN2(wire)); + if (rc) FAIL(rc); + for (i = 0; i < dir_EB_switches.num_s; i++) { + rc = add_switch(model, y, x, + dir_EB_switches.s[i].from, + dir_EB_switches.s[i].to, 0 /* bidir */); + if (rc) FAIL(rc); + } + + rc = build_dirwire_switches(&dir_EB_switches, W_TO_LEN4(wire)); + if (rc) FAIL(rc); + for (i = 0; i < dir_EB_switches.num_s; i++) { + rc = add_switch(model, y, x, + dir_EB_switches.s[i].from, + dir_EB_switches.s[i].to, 0 /* bidir */); + if (rc) FAIL(rc); + } + + wire = W_CLOCKWISE(wire); + } while (wire != W_NN2); // one full turn + + // and finally, some end wires go to CLK, SR and GFAN + { static const char* from[] = {"NR1E2", "WR1E2"}; + for (i = 0; i < sizeof(from)/sizeof(from[0]); i++) { + for (j = 0; j <= 1; j++) { + rc = add_switch(model, y, x, from[i], + pf("CLK%i", j), 0 /* bidir */); + if (rc) FAIL(rc); + rc = add_switch(model, y, x, from[i], + pf("SR%i", j), 0 /* bidir */); + if (rc) FAIL(rc); + } + }} + { static const char* from[] = {"ER1E1", "SR1E1"}; + for (i = 0; i < sizeof(from)/sizeof(from[0]); i++) { + for (j = 0; j <= 1; j++) { + rc = add_switch(model, y, x, from[i], + pf("CLK%i", j), 0 /* bidir */); + if (rc) FAIL(rc); + rc = add_switch(model, y, x, from[i], + pf(gfan_s, j), 0 /* bidir */); + if (rc) FAIL(rc); + } + }} + { static const char* from[] = {"NR1E1", "WR1E1"}; + for (i = 0; i < sizeof(from)/sizeof(from[0]); i++) { + for (j = 0; j <= 1; j++) { + rc = add_switch(model, y, x, from[i], + pf(gfan_s, j), 0 /* bidir */); + if (rc) FAIL(rc); + } + }} + { static const char* from[] = {"ER1E2", "SR1E2"}; + for (i = 0; i < sizeof(from)/sizeof(from[0]); i++) { + for (j = 0; j <= 1; j++) { + rc = add_switch(model, y, x, from[i], + pf("SR%i", j), 0 /* bidir */); + if (rc) FAIL(rc); + } + }} + return 0; +fail: + return rc; +} + +static int init_routing_switches(struct fpga_model* model) +{ + int x, y, rc; + for (x = 0; x < model->x_width; x++) { if (!is_atx(X_ROUTING_COL, model, x)) continue; - for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) { + for (y = TOP_IO_TILES; y < model->y_height-BOT_IO_TILES; y++) { + if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, + model, y)) + continue; + rc = init_routing_tile(model, y, x); + if (rc) FAIL(rc); + } + } + return 0; +fail: + return rc; +} + +int replicate_routing_switches(struct fpga_model* model) +{ + struct fpga_tile* tile; + int x, y, first_y, first_x, rc; + + first_y = -1; + for (x = 0; x < model->x_width; x++) { + if (!is_atx(X_ROUTING_COL, model, x)) + continue; + for (y = TOP_IO_TILES; y < model->y_height-BOT_IO_TILES; y++) { if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y)) continue; tile = YX_TILE(model, y, x); - routing_io = (tile->type == IO_ROUTING || tile->type == ROUTING_IO_L); - gfan_s = routing_io ? "INT_IOI_GFAN%i" : "GFAN%i"; - - // GND - for (i = 0; i <= 1; i++) { - rc = add_switch(model, y, x, "GND_WIRE", - pf(gfan_s, i), 0 /* bidir */); - if (rc) goto xout; + // Some tiles are different so we cannot include + // them in the high-speed replication scheme. + if (tile->type == IO_ROUTING || tile->type == ROUTING_IO_L + || tile->type == ROUTING_BRK || tile->type == BRAM_ROUTING_BRK) { + rc = init_routing_tile(model, y, x); + if (rc) FAIL(rc); + continue; } - rc = add_switch(model, y, x, "GND_WIRE", "SR1", - 0 /* bidir */); - if (rc) goto xout; - - // VCC - { int vcc_dest[] = { - X_A3, X_A4, X_A5, X_A6, X_B3, X_B4, X_B5, X_B6, - X_C3, X_C4, X_C5, X_C6, X_D3, X_D4, X_D5, X_D6, - M_A3, M_A4, M_A5, M_A6, M_B3, M_B4, M_B5, M_B6, - M_C3, M_C4, M_C5, M_C6, M_D3, M_D4, M_D5, M_D6 }; - - for (i = 0; i < sizeof(vcc_dest)/sizeof(vcc_dest[0]); i++) { - rc = add_switch(model, y, x, "VCC_WIRE", - logicin_s(vcc_dest[i], routing_io), - 0 /* bidir */); - if (rc) goto xout; - }} - - // KEEP1 - for (i = X_A1; i <= M_WE; i++) { - rc = add_switch(model, y, x, "KEEP1_WIRE", - logicin_s(i, routing_io), - 0 /* bidir */); - if (rc) goto xout; + if (first_y == -1) { + first_y = y; + first_x = x; + rc = init_routing_tile(model, y, x); + if (rc) FAIL(rc); + continue; } - rc = add_switch(model, y, x, "KEEP1_WIRE", "FAN_B", - 0 /* bidir */); - if (rc) goto xout; - - // VCC and KEEP1 to CLK0:1, SR0:1, GFAN0:1 - { static const char* src[] = {"VCC_WIRE", "KEEP1_WIRE"}; - for (i = 0; i <= 1; i++) - for (j = 0; j <= 1; j++) { - rc = add_switch(model, y, x, src[i], - pf("CLK%i", j), 0 /* bidir */); - if (rc) goto xout; - rc = add_switch(model, y, x, src[i], - pf("SR%i", j), 0 /* bidir */); - if (rc) goto xout; - rc = add_switch(model, y, x, - src[i], - pf(gfan_s, j), - 0 /* bidir */); - if (rc) goto xout; - } - } - - // GCLK0:15 -> CLK0:1, GFAN0:1/SR0:1 - if (tile->type == ROUTING_BRK - || tile->type == BRAM_ROUTING_BRK) - gclk_s = "GCLK%i_BRK"; - else - gclk_s = "GCLK%i"; - for (i = 0; i <= 15; i++) { - for (j = 0; j <= 1; j++) { - rc = add_switch(model, y, x, - pf(gclk_s, i), - pf("CLK%i", j), - 0 /* bidir */); - if (rc) goto xout; - rc = add_switch(model, y, x, - pf(gclk_s, i), - (i < 8) - ? pf(gfan_s, j) - : pf("SR%i", j), - 0 /* bidir */); - if (rc) goto xout; - } - } - - // FAN_B to SR0:1 - for (i = 0; i <= 1; i++) { - rc = add_switch(model, y, x, "FAN_B", - pf("SR%i", i), 0 /* bidir */); - if (rc) goto xout; - } - - // some logicin wires are singled out - { int logic_singles[] = {X_CE, X_CX, X_DX, - M_AI, M_BI, M_CX, M_DX, M_WE}; - for (i = 0; i < sizeof(logic_singles)/sizeof(logic_singles[0]); i++) { - rc = add_switch(model, y, x, pf("LOGICIN_B%i", logic_singles[i]), - pf("LOGICIN%i", logic_singles[i]), 0 /* bidir */); - if (rc) goto xout; - }} - - // connecting directional wires endpoints to logicin - rc = add_logicin_switches(model, y, x); - if (rc) goto xout; - - // connecting logicout back to directional wires - // beginning points (and some back to logicin) - rc = add_logicout_switches(model, y, x, routing_io); - if (rc) goto xout; - - // there are extra wires to send signals to logicin, or - // to share/multiply logicin signals - rc = add_logicio_extra(model, y, x, routing_io); - if (rc) goto xout; - - // extra wires going to SR, CLK and GFAN - { int to_sr[] = {X_BX, M_BX, M_DI}; - for (i = 0; i < sizeof(to_sr)/sizeof(to_sr[0]); i++) { - for (j = 0; j <= 1; j++) { - rc = add_switch(model, y, x, - pf("LOGICIN_B%i", to_sr[i]), - pf("SR%i", j), 0 /* bidir */); - if (rc) goto xout; - } - }} - { int to_clk[] = {M_BX, M_CI}; - for (i = 0; i < sizeof(to_clk)/sizeof(to_clk[0]); i++) { - for (j = 0; j <= 1; j++) { - rc = add_switch(model, y, x, - pf("LOGICIN_B%i", to_clk[i]), - pf("CLK%i", j), 0 /* bidir */); - if (rc) goto xout; - } - }} - { int to_gf[] = {M_AX, X_AX, M_CE, M_CI}; - for (i = 0; i < sizeof(to_gf)/sizeof(to_gf[0]); i++) { - for (j = 0; j <= 1; j++) { - int bidir = !routing_io - && ((!j && i < 2) || (j && i >= 2)); - rc = add_switch(model, y, x, - pf("LOGICIN_B%i", to_gf[i]), - pf(gfan_s, j), bidir); - if (rc) goto xout; - } - }} - - // connecting the directional wires from one's end - // to another one's beginning - wire = W_NN2; - do { - rc = build_dirwire_switches(&dir_EB_switches, W_TO_LEN1(wire)); - if (rc) goto xout; - for (i = 0; i < dir_EB_switches.num_s; i++) { - rc = add_switch(model, y, x, - dir_EB_switches.s[i].from, - dir_EB_switches.s[i].to, 0 /* bidir */); - if (rc) goto xout; - } - - rc = build_dirwire_switches(&dir_EB_switches, W_TO_LEN2(wire)); - if (rc) goto xout; - for (i = 0; i < dir_EB_switches.num_s; i++) { - rc = add_switch(model, y, x, - dir_EB_switches.s[i].from, - dir_EB_switches.s[i].to, 0 /* bidir */); - if (rc) goto xout; - } - - rc = build_dirwire_switches(&dir_EB_switches, W_TO_LEN4(wire)); - if (rc) goto xout; - for (i = 0; i < dir_EB_switches.num_s; i++) { - rc = add_switch(model, y, x, - dir_EB_switches.s[i].from, - dir_EB_switches.s[i].to, 0 /* bidir */); - if (rc) goto xout; - } - - wire = W_CLOCKWISE(wire); - } while (wire != W_NN2); // one full turn - - // and finally, some end wires go to CLK, SR and GFAN - { static const char* from[] = {"NR1E2", "WR1E2"}; - for (i = 0; i < sizeof(from)/sizeof(from[0]); i++) { - for (j = 0; j <= 1; j++) { - rc = add_switch(model, y, x, from[i], - pf("CLK%i", j), 0 /* bidir */); - if (rc) goto xout; - rc = add_switch(model, y, x, from[i], - pf("SR%i", j), 0 /* bidir */); - if (rc) goto xout; - } - }} - { static const char* from[] = {"ER1E1", "SR1E1"}; - for (i = 0; i < sizeof(from)/sizeof(from[0]); i++) { - for (j = 0; j <= 1; j++) { - rc = add_switch(model, y, x, from[i], - pf("CLK%i", j), 0 /* bidir */); - if (rc) goto xout; - rc = add_switch(model, y, x, from[i], - pf(gfan_s, j), 0 /* bidir */); - if (rc) goto xout; - } - }} - { static const char* from[] = {"NR1E1", "WR1E1"}; - for (i = 0; i < sizeof(from)/sizeof(from[0]); i++) { - for (j = 0; j <= 1; j++) { - rc = add_switch(model, y, x, from[i], - pf(gfan_s, j), 0 /* bidir */); - if (rc) goto xout; - } - }} - { static const char* from[] = {"ER1E2", "SR1E2"}; - for (i = 0; i < sizeof(from)/sizeof(from[0]); i++) { - for (j = 0; j <= 1; j++) { - rc = add_switch(model, y, x, from[i], - pf("SR%i", j), 0 /* bidir */); - if (rc) goto xout; - } - }} + rc = replicate_switches_and_names(model, + first_y, first_x, y, x); + if (rc) FAIL(rc); } } return 0; -xout: +fail: return rc; }