a few more short north and south wires, autotester

This commit is contained in:
Wolfgang Spraul 2012-09-12 03:41:32 +02:00
parent 988180051c
commit 0fa0e7f3c3
6 changed files with 727 additions and 152 deletions

4
README
View File

@ -19,7 +19,7 @@ Libraries
- libfpga-test autotest suite
- libfpga-cores reusable cores
- libfpga-design larger design elements on top of libfpga-control
- libfpga-stdlib standard design elements on top of libfpga-control
- libfpga-control programmatic access to libfpga-model
- libfpga-model memory-only representation of an FPGA
- libfpga-floorplan reads and writes .fp floorplan files
@ -63,7 +63,7 @@ TODO (as of 2012-08, expected time to delivery: months to years
* configuration of bram and macc blocks, bram initialization data
* routing switches
* many more cases in model of switches and inter-tile connections
* write standard design elements for libfpga-design library
* write standard design elements for libfpga-stdlib library
* support lm32 or openrisc core, either via libfpga or iverilog backend
* ipv6 or vnc in hardware?
* iverilog fpga backend

View File

@ -201,8 +201,7 @@ static int test_logic_net(struct test_state* tstate, int logic_y, int logic_x,
// add port
rc = fpga_net_add_port(tstate->model, net_idx, logic_y, logic_x,
fpga_dev_idx(tstate->model, logic_y, logic_x, DEV_LOGIC,
type_idx), port);
DEV_LOGIC, type_idx, port);
if (rc) FAIL(rc);
// add (one) switch in logic tile
@ -277,7 +276,7 @@ static int test_logic_net_l2(struct test_state* tstate, int y, int x,
rc = fpga_switch_to_yx(&switch_to);
if (rc) FAIL(rc);
if (dbg)
printf_switch_to_result(&switch_to);
printf_switch_to_yx_result(&switch_to);
switch_tile = YX_TILE(tstate->model, switch_to.dest_y, switch_to.dest_x);
rc = fpga_swset_fromto(tstate->model, switch_to.dest_y,
@ -379,7 +378,7 @@ static int test_logic_net_l1(struct test_state* tstate, int y, int x,
rc = fpga_switch_to_yx(&switch_to);
if (rc) FAIL(rc);
if (tstate->dry_run)
printf_switch_to_result(&switch_to);
printf_switch_to_yx_result(&switch_to);
rc = fpga_swset_fromto(tstate->model, switch_to.dest_y,
switch_to.dest_x, switch_to.dest_connpt, from_to, &set_l1);
@ -414,8 +413,259 @@ fail:
return rc;
}
static int test_switches(struct test_state* tstate, int y, int x,
str16_t start_switch, net_idx_t net, swidx_t* done_list, int* done_list_len)
{
struct sw_set sw_set, w4_set;
const char* switch_str;
str16_t switch_str_i;
int i, j, k, rc;
rc = fpga_swset_fromto(tstate->model, y, x, start_switch, SW_TO, &sw_set);
if (rc) FAIL(rc);
if (tstate->dry_run)
fpga_swset_print(tstate->model, y, x, &sw_set, SW_TO);
for (i = 0; i < sw_set.len; i++) {
switch_str_i = fpga_switch_str_i(tstate->model, y, x,
sw_set.sw[i], SW_FROM);
switch_str = strarray_lookup(&tstate->model->str, switch_str_i);
if (!switch_str) FAIL(EINVAL);
if (switch_str[2] == '4') {
// base for len-4 wire
if (tstate->dry_run)
fprintf_net(stdout, tstate->model, net);
rc = diff_printf(tstate);
if (rc) FAIL(rc);
// add len-4 wire
rc = fpga_net_add_sw(tstate->model, net, y, x,
&sw_set.sw[i], 1);
if (rc) FAIL(rc);
// enum dests of len-4 wire
rc = fpga_swset_fromto(tstate->model, y, x,
switch_str_i, SW_FROM, &w4_set);
if (rc) FAIL(rc);
if (tstate->dry_run)
fpga_swset_print(tstate->model, y, x,
&w4_set, SW_FROM);
for (j = 0; j < w4_set.len; j++) {
// do not point to our base twice
if (w4_set.sw[j] == sw_set.sw[i])
continue;
// duplicate check and done_list
for (k = 0; k < *done_list_len; k++) {
if (done_list[k] == w4_set.sw[j])
break;
}
if (k < *done_list_len)
continue;
done_list[(*done_list_len)++] = w4_set.sw[j];
if (tstate->dry_run)
printf("done_list %s at %i\n",
fpga_switch_print(tstate->model,
y, x, done_list[(*done_list_len)-1]),
(*done_list_len)-1);
// base for len-4 target
if (tstate->dry_run)
fprintf_net(stdout, tstate->model, net);
rc = diff_printf(tstate);
if (rc) FAIL(rc);
// add len-4 target
rc = fpga_net_add_sw(tstate->model, net, y, x,
&w4_set.sw[j], 1);
if (rc) FAIL(rc);
if (tstate->dry_run)
fprintf_net(stdout, tstate->model, net);
rc = diff_printf(tstate);
if (rc) FAIL(rc);
rc = fpga_net_remove_sw(tstate->model, net, y, x,
&w4_set.sw[j], 1);
if (rc) FAIL(rc);
}
rc = fpga_net_remove_sw(tstate->model, net, y, x,
&sw_set.sw[i], 1);
if (rc) FAIL(rc);
}
}
return 0;
fail:
return rc;
}
static int test_routing_sw_from_south(struct test_state* tstate,
swidx_t* done_list, int* done_list_len)
{
struct switch_to_yx switch_to;
int iob_y, iob_x, iob_type_idx, rc;
struct fpga_device* iob_dev;
net_idx_t net;
rc = fpga_find_iob(tstate->model, "P48", &iob_y, &iob_x, &iob_type_idx);
if (rc) FAIL(rc);
rc = fdev_iob_output(tstate->model, iob_y, iob_x, iob_type_idx);
if (rc) FAIL(rc);
iob_dev = fdev_p(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
if (!iob_dev) FAIL(EINVAL);
rc = fpga_net_new(tstate->model, &net);
if (rc) FAIL(rc);
rc = fpga_net_add_port(tstate->model, net, iob_y, iob_x,
DEV_IOB, iob_type_idx, IOB_IN_O);
if (rc) FAIL(rc);
switch_to.yx_req = YX_DEV_OLOGIC;
switch_to.flags = SWTO_YX_DEF;
switch_to.model = tstate->model;
switch_to.y = iob_y;
switch_to.x = iob_x;
switch_to.start_switch = iob_dev->pinw[IOB_IN_O];
switch_to.from_to = SW_TO;
rc = fpga_switch_to_yx(&switch_to);
if (rc) FAIL(rc);
if (tstate->dry_run)
printf_switch_to_yx_result(&switch_to);
rc = fpga_net_add_sw(tstate->model, net, switch_to.y,
switch_to.x, switch_to.set.sw, switch_to.set.len);
if (rc) FAIL(rc);
switch_to.yx_req = YX_ROUTING_TILE;
switch_to.flags = SWTO_YX_DEF;
switch_to.model = tstate->model;
switch_to.y = switch_to.dest_y;
switch_to.x = switch_to.dest_x;
switch_to.start_switch = switch_to.dest_connpt;
switch_to.from_to = SW_TO;
rc = fpga_switch_to_yx(&switch_to);
if (rc) FAIL(rc);
rc = fpga_net_add_sw(tstate->model, net, switch_to.y,
switch_to.x, switch_to.set.sw, switch_to.set.len);
if (rc) FAIL(rc);
if (tstate->dry_run)
printf_switch_to_yx_result(&switch_to);
switch_to.yx_req = YX_ROUTING_TO_FABLOGIC;
switch_to.flags = SWTO_YX_CLOSEST;
switch_to.model = tstate->model;
switch_to.y = switch_to.dest_y;
switch_to.x = switch_to.dest_x;
switch_to.start_switch = switch_to.dest_connpt;
switch_to.from_to = SW_TO;
rc = fpga_switch_to_yx(&switch_to);
if (rc) FAIL(rc);
if (tstate->dry_run)
printf_switch_to_yx_result(&switch_to);
rc = fpga_net_add_sw(tstate->model, net, switch_to.y,
switch_to.x, switch_to.set.sw, switch_to.set.len);
if (rc) FAIL(rc);
rc = test_switches(tstate, switch_to.dest_y, switch_to.dest_x,
switch_to.dest_connpt, net, done_list, done_list_len);
if (rc) FAIL(rc);
fdev_delete(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
fpga_net_delete(tstate->model, net);
return 0;
fail:
return rc;
}
static int test_routing_sw_from_north(struct test_state* tstate,
swidx_t* done_list, int* done_list_len)
{
struct fpga_device* dev;
struct switch_to_rel swto;
struct sw_conns conns;
const char* str;
net_idx_t net;
int y, x, i, rc;
y = 67;
x = 13;
for (i = '1'; i <= '6'; i++) {
rc = fdev_logic_set_lut(tstate->model, y, x,
DEV_LOGM, LUT_A, 6, pf("A%c", i), ZTERM);
if (rc) FAIL(rc);
rc = fdev_set_required_pins(tstate->model, y, x,
DEV_LOGIC, DEV_LOGM);
if (rc) FAIL(rc);
if (tstate->dry_run)
fdev_print_required_pins(tstate->model,
y, x, DEV_LOGIC, DEV_LOGM);
dev = fdev_p(tstate->model, y, x, DEV_LOGIC, DEV_LOGM);
if (!dev) FAIL(EINVAL);
if (!dev->pinw_req_in) FAIL(EINVAL);
rc = fpga_net_new(tstate->model, &net);
if (rc) FAIL(rc);
rc = fpga_net_add_port(tstate->model, net, y, x,
DEV_LOGIC, DEV_LOGM, dev->pinw_req_for_cfg[0]);
if (rc) FAIL(rc);
swto.model = tstate->model;
swto.start_y = y;
swto.start_x = x;
swto.start_switch = fdev_logic_pinstr_i(tstate->model,
dev->pinw_req_for_cfg[0]|LD1, LOGIC_M);
swto.from_to = SW_TO;
swto.rel_y = 0;
swto.rel_x = -1;
swto.target_connpt = STRIDX_NO_ENTRY;
rc = fpga_switch_to_rel(&swto);
if (rc) FAIL(rc);
if (!swto.set.len) FAIL(EINVAL);
if (tstate->dry_run)
printf_switch_to_rel_result(&swto);
rc = fpga_net_add_sw(tstate->model, net, swto.start_y,
swto.start_x, swto.set.sw, swto.set.len);
if (rc) FAIL(rc);
rc = construct_sw_conns(&conns, tstate->model, swto.dest_y, swto.dest_x,
swto.dest_connpt, SW_TO, /*max_depth*/ 1);
if (rc) FAIL(rc);
while (fpga_switch_conns(&conns) != NO_CONN) {
if (conns.dest_x != swto.dest_x
|| conns.dest_y != swto.dest_y+1)
continue;
str = strarray_lookup(&tstate->model->str, conns.dest_str_i);
if (!str) { HERE(); continue; }
if (strlen(str) < 5
|| str[2] != '1' || str[3] != 'B')
continue;
rc = fpga_net_add_sw(tstate->model, net, swto.dest_y,
swto.dest_x, conns.chain.set.sw, conns.chain.set.len);
if (rc) FAIL(rc);
if (tstate->dry_run)
fprintf_net(stdout, tstate->model, net);
rc = test_switches(tstate, conns.dest_y, conns.dest_x,
conns.dest_str_i, net, done_list, done_list_len);
if (rc) FAIL(rc);
rc = fpga_net_remove_sw(tstate->model, net, swto.dest_y,
swto.dest_x, conns.chain.set.sw, conns.chain.set.len);
if (rc) FAIL(rc);
}
destruct_sw_conns(&conns);
fdev_delete(tstate->model, y, x, DEV_LOGIC, DEV_LOGM);
fpga_net_delete(tstate->model, net);
}
return 0;
fail:
return rc;
}
// goal: use all switches in a routing switchbox
static int test_logic_switches(struct test_state* tstate)
static int test_routing_switches(struct test_state* tstate)
{
int idx_enum[] = { DEV_LOGM, DEV_LOGX };
int y, x, i, j, k, r, rc;
@ -426,7 +676,6 @@ static int test_logic_switches(struct test_state* tstate)
y = 68;
x = 13;
done_sw_len = 0;
for (r = 0; r <= 1; r++) {
// two rounds:
@ -494,6 +743,11 @@ static int test_logic_switches(struct test_state* tstate)
}
}
}
done_sw_len = 0;
rc = test_routing_sw_from_south(tstate, done_sw_list, &done_sw_len);
if (rc) FAIL(rc);
rc = test_routing_sw_from_north(tstate, done_sw_list, &done_sw_len);
if (rc) FAIL(rc);
return 0;
fail:
return rc;
@ -528,7 +782,7 @@ static int test_iologic_switches2(struct test_state* tstate, int iob_y, int iob_
rc = fpga_switch_to_yx(&switch_to);
if (rc) FAIL(rc);
if (tstate->dry_run)
printf_switch_to_result(&switch_to);
printf_switch_to_yx_result(&switch_to);
if (construct_sw_chain(&chain, tstate->model, switch_to.dest_y,
switch_to.dest_x, switch_to.dest_connpt, from_to,
@ -547,8 +801,7 @@ static int test_iologic_switches2(struct test_state* tstate, int iob_y, int iob_
// add iob port
rc = fpga_net_add_port(tstate->model, net_idx, iob_y, iob_x,
fpga_dev_idx(tstate->model, iob_y, iob_x, DEV_IOB,
iob_type_idx), IOB_IN_O);
DEV_IOB, iob_type_idx, IOB_IN_O);
if (rc) FAIL(rc);
// add switch in iob tile
@ -643,7 +896,7 @@ int main(int argc, char** argv)
char param[1024], cmdline_test[1024];
int i, param_skip, rc;
const char* available_tests[] =
{ "logic_cfg", "logic_sw", "io_sw", 0 };
{ "logic_cfg", "routing_sw", "io_sw", 0 };
// flush after every line is better for the autotest
// output, tee, etc.
@ -755,8 +1008,8 @@ int main(int argc, char** argv)
rc = test_logic_config(&tstate);
if (rc) FAIL(rc);
}
if (!strcmp(cmdline_test, "logic_sw")) {
rc = test_logic_switches(&tstate);
if (!strcmp(cmdline_test, "routing_sw")) {
rc = test_routing_switches(&tstate);
if (rc) FAIL(rc);
}
if (!strcmp(cmdline_test, "io_sw")) {

135
control.c
View File

@ -334,6 +334,54 @@ const char* fdev_logic_pinstr(pinw_idx_t idx, int ld1_type)
return buf[last_buf];
}
str16_t fdev_logic_pinstr_i(struct fpga_model* model, pinw_idx_t idx, int ld1_type)
{
int str_i;
str_i = strarray_find(&model->str, fdev_logic_pinstr(idx, ld1_type));
if (OUT_OF_U16(str_i))
{ HERE(); return STRIDX_NO_ENTRY; }
return str_i;
}
int fdev_logic_inbit(pinw_idx_t idx, int ld1_type)
{
if (idx & LD1) {
idx &= ~LD1;
if (idx >= LI_A1 && idx <= LI_C6)
return M_A1 + (idx/6)*8+idx%6;
if (idx >= LI_D1 && idx <= LI_D6)
return M_D1 + (idx-LI_D1);
switch (idx) {
case LI_AX: return M_AX;
case LI_BX: return M_BX;
case LI_CE: return M_CE;
case LI_CX: return M_CX;
case LI_DX: return M_DX;
case LI_AI: return M_AI;
case LI_BI: return M_BI;
case LI_CI: return M_CI;
case LI_DI: return M_DI;
case LI_WE: return M_WE;
}
HERE();
return -1;
}
if (idx >= LI_A1 && idx <= LI_C6)
return X_A1 + (idx/6)*7+idx%6;
else if (idx >= LI_D1 && idx <= LI_D6)
return X_D1 + (idx-LI_D1);
else switch (idx) {
case LI_AX: return X_AX;
case LI_BX: return X_BX;
case LI_CE: return X_CE;
case LI_CX: return X_CX;
case LI_DX: return X_DX;
}
HERE();
return -1;
}
static int reset_required_pins(struct fpga_device* dev)
{
int rc;
@ -1453,7 +1501,7 @@ fail:
return rc;
}
void printf_switch_to_result(struct switch_to_yx* p)
void printf_switch_to_yx_result(struct switch_to_yx* p)
{
printf("switch_to_yx() from y%02i x%02i connpt %s (%s)\n",
p->y, p->x, strarray_lookup(&p->model->str, p->start_switch),
@ -1465,6 +1513,46 @@ void printf_switch_to_result(struct switch_to_yx* p)
fmt_swset(p->model, p->y, p->x, &p->set, p->from_to));
}
int fpga_switch_to_rel(struct switch_to_rel* p)
{
struct sw_conns conns;
int rc;
rc = construct_sw_conns(&conns, p->model, p->start_y, p->start_x,
p->start_switch, p->from_to, SW_SET_SIZE);
if (rc) FAIL(rc);
p->set.len = 0;
while (fpga_switch_conns(&conns) != NO_CONN) {
if (conns.dest_y != p->start_y + p->rel_y
|| conns.dest_x != p->start_x + p->rel_x)
continue;
if (p->target_connpt != STRIDX_NO_ENTRY
&& conns.dest_str_i != p->target_connpt)
continue;
p->set = conns.chain.set;
p->dest_y = conns.dest_y;
p->dest_x = conns.dest_x;
p->dest_connpt = conns.dest_str_i;
break;
}
destruct_sw_conns(&conns);
return 0;
fail:
return rc;
}
void printf_switch_to_rel_result(struct switch_to_rel* p)
{
printf("switch_to_rel() from y%02i x%02i connpt %s (%s)\n",
p->start_y, p->start_x, strarray_lookup(&p->model->str, p->start_switch),
p->from_to == SW_FROM ? "SW_FROM" : "SW_TO");
printf(" %s y%02i x%02i %s via %s\n",
p->from_to == SW_FROM ? "to" : "from",
p->dest_y, p->dest_x,
strarray_lookup(&p->model->str, p->dest_connpt),
fmt_swset(p->model, p->start_y, p->start_x, &p->set, p->from_to));
}
#define NET_ALLOC_INCREMENT 64
static int fpga_net_useidx(struct fpga_model* model, net_idx_t new_idx)
@ -1551,7 +1639,8 @@ struct fpga_net* fpga_net_get(struct fpga_model* model, net_idx_t net_i)
}
int fpga_net_add_port(struct fpga_model* model, net_idx_t net_i,
int y, int x, dev_idx_t dev_idx, pinw_idx_t pinw_idx)
int y, int x, enum fpgadev_type type, dev_type_idx_t type_idx,
pinw_idx_t pinw_idx)
{
struct fpga_net* net;
int rc;
@ -1565,7 +1654,8 @@ int fpga_net_add_port(struct fpga_model* model, net_idx_t net_i,
net->el[net->len].y = y;
net->el[net->len].x = x;
net->el[net->len].idx = pinw_idx | NET_IDX_IS_PINW;
net->el[net->len].dev_idx = dev_idx;
net->el[net->len].dev_idx = fpga_dev_idx(model, y, x, type, type_idx);
if (net->el[net->len].dev_idx == NO_DEV) FAIL(EINVAL);
net->len++;
return 0;
fail:
@ -1599,6 +1689,45 @@ fail:
return rc;
}
int fpga_net_remove_sw(struct fpga_model* model, net_idx_t net_i,
int y, int x, const swidx_t* switches, int num_sw)
{
struct fpga_net* net;
int i, j, rc;
if (net_i > model->highest_used_net)
FAIL(EINVAL);
net = &model->nets[net_i-1];
if (!net->len) {
HERE();
return 0;
}
for (i = 0; i < num_sw; i++) {
for (j = 0; j < net->len; j++) {
if (net->el[j].y == y
&& net->el[j].x == x
&& net->el[j].idx == switches[i])
break;
}
if (j >= net->len) {
// for now we expect the 'to-be-removed'
// switches to be in the net
HERE();
continue;
}
if (!fpga_switch_is_used(model, y, x, switches[i]))
HERE();
fpga_switch_disable(model, y, x, switches[i]);
if (net->len > j+1)
memmove(&net->el[j], &net->el[j+1],
(net->len-j-1)*sizeof(net->el[0]));
net->len--;
}
return 0;
fail:
return rc;
}
void fpga_net_free_all(struct fpga_model* model)
{
free(model->nets);

View File

@ -38,9 +38,13 @@ dev_type_idx_t fdev_typeidx(struct fpga_model* model, int y, int x,
pinw_idx_t fdev_pinw_str2idx(int devtype, const char* str, int len);
// returns 0 when idx not found for the given devtype
const char* fdev_pinw_idx2str(int devtype, pinw_idx_t idx);
// ld1_type can be LOGIC_M or LOGIC_L to specify whether
// we are in a XM or XL column.
// we are in a XM or XL column. You can |LD1 to idx for
// the second logic device (L or M).
const char* fdev_logic_pinstr(pinw_idx_t idx, int ld1_type);
str16_t fdev_logic_pinstr_i(struct fpga_model* model, pinw_idx_t idx, int ld1_type);
int fdev_logic_inbit(pinw_idx_t idx, int ld1_type);
// lut_a2d is LUT_A to LUT_D value, lut_5or6 is int 5 or int 6.
int fdev_logic_set_lut(struct fpga_model* model, int y, int x, int type_idx,
@ -247,7 +251,30 @@ struct switch_to_yx
};
int fpga_switch_to_yx(struct switch_to_yx* p);
void printf_switch_to_result(struct switch_to_yx* p);
void printf_switch_to_yx_result(struct switch_to_yx* p);
struct switch_to_rel
{
// input:
struct fpga_model* model;
int start_y;
int start_x;
str16_t start_switch;
int from_to;
int rel_y;
int rel_x;
str16_t target_connpt; // can be STRIDX_NO_ENTRY
// output:
struct sw_set set;
int dest_y;
int dest_x;
str16_t dest_connpt;
};
// if no switches are found, the returned set.len will be 0.
int fpga_switch_to_rel(struct switch_to_rel* p);
void printf_switch_to_rel_result(struct switch_to_rel* p);
//
// nets
@ -289,9 +316,11 @@ void fpga_net_delete(struct fpga_model* model, net_idx_t net_idx);
int fpga_net_enum(struct fpga_model* model, net_idx_t last, net_idx_t* next);
struct fpga_net* fpga_net_get(struct fpga_model* model, net_idx_t net_i);
int fpga_net_add_port(struct fpga_model* model, net_idx_t net_i,
int y, int x, dev_idx_t dev_idx, pinw_idx_t pinw_idx);
int y, int x, enum fpgadev_type type, dev_type_idx_t type_idx, pinw_idx_t pinw_idx);
int fpga_net_add_sw(struct fpga_model* model, net_idx_t net_i,
int y, int x, const swidx_t* switches, int num_sw);
int fpga_net_remove_sw(struct fpga_model* model, net_idx_t net_i,
int y, int x, const swidx_t* switches, int num_sw);
void fpga_net_free_all(struct fpga_model* model);
void fprintf_net(FILE* f, struct fpga_model* model, net_idx_t net_i);

View File

@ -775,7 +775,6 @@ static void read_net_line(struct fpga_model* model, const char* line, int start)
enum fpgadev_type dev_type;
char buf[1024];
net_idx_t net_idx;
dev_idx_t dev_idx;
pinw_idx_t pinw_idx;
int sw_is_bidir;
@ -872,14 +871,12 @@ static void read_net_line(struct fpga_model* model, const char* line, int start)
{ HERE(); return; }
dev_type = fdev_str2type(&line[dev_str_beg], dev_str_end-dev_str_beg);
if (dev_type == DEV_NONE) { HERE(); return; }
dev_idx = fpga_dev_idx(model, y_coord, x_coord, dev_type,
to_i(&line[dev_type_idx_str_beg],
dev_type_idx_str_end-dev_type_idx_str_beg));
if (dev_idx == NO_DEV) { HERE(); return; }
pinw_idx = fdev_pinw_str2idx(dev_type, &line[pin_name_beg],
pin_name_end-pin_name_beg);
if (pinw_idx == PINW_NO_IDX) { HERE(); return; }
if (fpga_net_add_port(model, net_idx, y_coord, x_coord, dev_idx, pinw_idx))
if (fpga_net_add_port(model, net_idx, y_coord, x_coord, dev_type,
to_i(&line[dev_type_idx_str_beg], dev_type_idx_str_end
-dev_type_idx_str_beg), pinw_idx))
HERE();
}

View File

@ -1767,153 +1767,210 @@ static int run_direction_wires(struct fpga_model* model)
int x, y, i, j, _row_num, _row_pos, rc;
struct w_net net;
// SS4
// todo: EL1, ER1, WR1, WL1
// SR1
for (x = 0; x < model->x_width; x++) {
if (!is_atx(X_ROUTING_COL, model, x))
continue;
// some wiring at the top
net.last_inc = 3;
for (i = 1; i < 5; i++) { // go through "BAMCE"
net.pts[0].start_count = 0;
net.pts[0].y = TOP_TERM(model);
net.pts[0].x = x;
net.pts[0].name = pf("SS4%c%%i", s_4wire[i]);
for (j = i; j < 5; j++) {
net.pts[j-i+1].start_count = 0;
net.pts[j-i+1].y = TOP_TERM(model)+(j-i+1);
net.pts[j-i+1].x = x;
net.pts[j-i+1].name = pf("SS4%c%%i", s_4wire[j]);
}
net.pts[j-i+1].name = "";
if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout;
if ((rc = wire_SS4E_N3(model, &net))) goto xout;
}
// rest going down to bottom termination
for (y = 0; y < model->y_height; y++) {
is_in_row(model, y, &_row_num, &_row_pos);
if (is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)
&& y > BOT_TERM(model)-5)
break;
if (_row_pos < 0 || _row_pos == 8)
for (y = TOP_OUTER_IO; y <= model->y_height-BOT_OUTER_IO; y++) {
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y))
continue;
net.last_inc = 3;
j = 0;
for (i = 0; i < 5; i++) { // go through "BAMCE"
net.pts[j].start_count = 0;
net.pts[j].y = y+j;
net.pts[j].x = x;
if (y+j == BOT_TERM(model)) {
EXIT(!i);
net.pts[j].name = pf("SS4%c%%i", s_4wire[i-1]);
j++;
break;
if (is_aty(Y_INNER_BOTTOM, model, y+1)) {
if (!is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) {
{ struct w_net n = {
3,
{{ "SR1B%i", 0, y, x },
{ "SR1B%i", 0, y+1, x },
{ "" }}};
if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; }
if ((rc = add_conn_bi_pref(model, y, x, "SR1E_N3", y+1, x, "SR1E_N3"))) goto xout;
}
if (IS_CENTER_Y(y+j, model)
|| pos_in_row(y+j, model) == HCLK_POS) {
EXIT(!i);
net.pts[j].name = pf("SS4%c%%i", s_4wire[i-1]);
j++;
net.pts[j].start_count = 0;
net.pts[j].y = y+j;
net.pts[j].x = x;
}
net.pts[j].name = pf("SS4%c%%i", s_4wire[i]);
j++;
continue;
}
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y+1)) {
{ struct w_net n = {
3,
{{ "SR1B%i", 0, y, x },
{ "SR1B%i", 0, y+1, x },
{ "SR1E%i", 0, y+2, x },
{ "" }}};
if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; }
{ struct w_net n = {
0,
{{ "SR1E_N3", 0, y, x },
{ "SR1E_N3", 0, y+1, x },
{ "SR1E3", 0, y+2, x },
{ "" }}};
if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; }
if ((rc = add_conn_bi_pref(model, y+1, x, "SR1E_N3", y, x, "SR1B3"))) goto xout;
if ((rc = add_conn_bi_pref(model, y+1, x, "SR1B3", y, x, "SR1E_N3"))) goto xout;
continue;
}
{ struct w_net n = {
3,
{{ "SR1B%i", 0, y, x },
{ "SR1E%i", 0, y+1, x },
{ "" }}};
if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; }
if ((rc = add_conn_bi_pref(model, y+1, x, "SR1E3", y, x, "SR1E_N3"))) goto xout;
if (is_aty(Y_INNER_TOP, model, y-1)) {
{ struct w_net n = {
3,
{{ "SR1E%i", 0, y-1, x },
{ "SR1E%i", 0, y, x },
{ "" }}};
if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; }
if ((rc = add_conn_bi_pref(model, y, x, "SR1E3", y-1, x, "SR1E_N3"))) goto xout;
}
net.pts[j].name = "";
if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout;
if ((rc = wire_SS4E_N3(model, &net))) goto xout;
}
}
// NN4
// NL1
for (x = 0; x < model->x_width; x++) {
if (!is_atx(X_ROUTING_COL, model, x))
continue;
for (y = 0; y < model->y_height; y++) {
is_in_row(model, y, &_row_num, &_row_pos);
if (_row_pos >= 0 && _row_pos != 8) {
net.last_inc = 3;
j = 0;
for (i = 0; i < 5; i++) { // go through "BAMCE"
net.pts[j].start_count = 0;
net.pts[j].y = y-j;
net.pts[j].x = x;
if (y-j == TOP_INNER_ROW) {
EXIT(!i);
net.pts[j].name = pf("NN4%c%%i", s_4wire[i-1]);
j++;
break;
}
net.pts[j].name = pf("NN4%c%%i", s_4wire[i]);
if (IS_CENTER_Y(y-j, model)
|| pos_in_row(y-j, model) == HCLK_POS) {
EXIT(!i);
i--;
}
j++;
}
net.pts[j].name = "";
if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout;
for (y = TOP_OUTER_IO; y <= model->y_height-BOT_OUTER_IO; y++) {
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y))
continue;
if (is_aty(Y_INNER_TOP, model, y-1)) {
{ struct w_net n = {
3,
{{ "NL1B%i", 0, y-1, x },
{ "NL1B%i", 0, y, x },
{ "" }}};
if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; }
if ((rc = add_conn_bi_pref(model, y, x, "NL1E_S0", y-1, x, "NL1E_S0"))) goto xout;
continue;
}
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y-1)) {
{ struct w_net n = {
3,
{{ "NL1E%i", 0, y-2, x },
{ "NL1E%i", 0, y-1, x },
{ "NL1B%i", 0, y, x },
{ "" }}};
if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; }
{ struct w_net n = {
0,
{{ "NL1E0", 0, y-2, x },
{ "NL1E_S0", 0, y-1, x },
{ "NL1E_S0", 0, y, x },
{ "" }}};
if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; }
if ((rc = add_conn_bi_pref(model, y-1, x, "NL1E_S0", y, x, "NL1B0"))) goto xout;
if ((rc = add_conn_bi_pref(model, y-1, x, "NL1E0", y, x, "NL1E_S0"))) goto xout;
continue;
}
{ struct w_net n = {
3,
{{ "NL1E%i", 0, y-1, x },
{ "NL1B%i", 0, y, x },
{ "" }}};
if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; }
if ((rc = add_conn_bi_pref(model, y-1, x, "NL1E0", y, x, "NL1E_S0"))) goto xout;
if (is_aty(Y_INNER_BOTTOM, model, y+1) && !is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) {
{ struct w_net n = {
3,
{{ "NL1E%i", 0, y, x },
{ "NL1E%i", 0, y+1, x },
{ "" }}};
if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; }
if ((rc = add_conn_bi_pref(model, y, x, "NL1E0", y+1, x, "NL1E_S0"))) goto xout;
}
}
if (!is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) {
net.last_inc = 3;
for (i = 1; i < 5; i++) { // go through "BAMCE"
net.pts[0].start_count = 0;
net.pts[0].y = BOT_TERM(model);
net.pts[0].x = x;
net.pts[0].name = pf("NN4%c%%i", s_4wire[i]);
for (j = i; j < 5; j++) {
net.pts[j-i+1].start_count = 0;
net.pts[j-i+1].y = BOT_TERM(model)-(j-i+1);
net.pts[j-i+1].x = x;
net.pts[j-i+1].name = pf("NN4%c%%i", s_4wire[j]);
}
// SL1
for (x = 0; x < model->x_width; x++) {
if (!is_atx(X_ROUTING_COL, model, x))
continue;
for (y = TOP_OUTER_IO; y <= model->y_height-BOT_OUTER_IO; y++) {
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y))
continue;
if (is_aty(Y_INNER_BOTTOM, model, y+1)) {
if (!is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) {
{ struct w_net n = {
3,
{{ "SL1B%i", 0, y, x },
{ "SL1B%i", 0, y+1, x },
{ "" }}};
if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; }
}
net.pts[j-i+1].name = "";
if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout;
continue;
}
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y+1)) {
{ struct w_net n = {
3,
{{ "SL1B%i", 0, y, x },
{ "SL1B%i", 0, y+1, x },
{ "SL1E%i", 0, y+2, x },
{ "" }}};
if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; }
continue;
}
{ struct w_net n = {
3,
{{ "SL1B%i", 0, y, x },
{ "SL1E%i", 0, y+1, x },
{ "" }}};
if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; }
if (is_aty(Y_INNER_TOP, model, y-1)) {
{ struct w_net n = {
3,
{{ "SL1E%i", 0, y-1, x },
{ "SL1E%i", 0, y, x },
{ "" }}};
if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; }
}
}
}
// NR1
for (x = 0; x < model->x_width; x++) {
if (!is_atx(X_ROUTING_COL, model, x))
continue;
for (y = TOP_OUTER_IO; y <= model->y_height-BOT_OUTER_IO; y++) {
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y))
continue;
if (is_aty(Y_INNER_TOP, model, y-1)) {
{ struct w_net n = {
3,
{{ "NR1B%i", 0, y, x },
{ "NR1B%i", 0, y-1, x },
{ "" }}};
if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; }
continue;
}
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y-1)) {
{ struct w_net n = {
3,
{{ "NR1B%i", 0, y, x },
{ "NR1E%i", 0, y-1, x },
{ "NR1E%i", 0, y-2, x },
{ "" }}};
if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; }
continue;
}
{ struct w_net n = {
3,
{{ "NR1B%i", 0, y, x },
{ "NR1E%i", 0, y-1, x },
{ "" }}};
if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; }
if (is_aty(Y_INNER_BOTTOM, model, y+1) && !is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) {
{ struct w_net n = {
3,
{{ "NR1E%i", 0, y, x },
{ "NR1E%i", 0, y+1, x },
{ "" }}};
if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; }
}
}
}
for (y = 0; y < model->y_height; y++) {
for (x = 0; x < model->x_width; x++) {
// NR1
if (is_atyx(YX_ROUTING_TILE, model, y, x)) {
if (is_aty(Y_INNER_TOP, model, y-1)) {
{ struct w_net n = {
3,
{{ "NR1B%i", 0, y, x },
{ "NR1B%i", 0, y-1, x },
{ "" }}};
if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; }
} else if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y-1)) {
{ struct w_net n = {
3,
{{ "NR1B%i", 0, y, x },
{ "NR1E%i", 0, y-1, x },
{ "NR1E%i", 0, y-2, x },
{ "" }}};
if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; }
} else {
{ struct w_net n = {
3,
{{ "NR1B%i", 0, y, x },
{ "NR1E%i", 0, y-1, x },
{ "" }}};
if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; }
if (is_aty(Y_INNER_BOTTOM, model, y+1) && !is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) {
{ struct w_net n = {
3,
{{ "NR1E%i", 0, y, x },
{ "NR1E%i", 0, y+1, x },
{ "" }}};
if ((rc = add_conn_net(model, PREF_BI_F, &n))) goto xout; }
}
}
}
// NN2
if (is_atyx(YX_ROUTING_TILE, model, y, x)) {
if (is_aty(Y_INNER_TOP, model, y-1)) {
@ -2067,6 +2124,116 @@ static int run_direction_wires(struct fpga_model* model)
}
}
}
// SS4
for (x = 0; x < model->x_width; x++) {
if (!is_atx(X_ROUTING_COL, model, x))
continue;
// some wiring at the top
net.last_inc = 3;
for (i = 1; i < 5; i++) { // go through "BAMCE"
net.pts[0].start_count = 0;
net.pts[0].y = TOP_TERM(model);
net.pts[0].x = x;
net.pts[0].name = pf("SS4%c%%i", s_4wire[i]);
for (j = i; j < 5; j++) {
net.pts[j-i+1].start_count = 0;
net.pts[j-i+1].y = TOP_TERM(model)+(j-i+1);
net.pts[j-i+1].x = x;
net.pts[j-i+1].name = pf("SS4%c%%i", s_4wire[j]);
}
net.pts[j-i+1].name = "";
if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout;
if ((rc = wire_SS4E_N3(model, &net))) goto xout;
}
// rest going down to bottom termination
for (y = 0; y < model->y_height; y++) {
is_in_row(model, y, &_row_num, &_row_pos);
if (is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)
&& y > BOT_TERM(model)-5)
break;
if (_row_pos < 0 || _row_pos == 8)
continue;
net.last_inc = 3;
j = 0;
for (i = 0; i < 5; i++) { // go through "BAMCE"
net.pts[j].start_count = 0;
net.pts[j].y = y+j;
net.pts[j].x = x;
if (y+j == BOT_TERM(model)) {
EXIT(!i);
net.pts[j].name = pf("SS4%c%%i", s_4wire[i-1]);
j++;
break;
}
if (IS_CENTER_Y(y+j, model)
|| pos_in_row(y+j, model) == HCLK_POS) {
EXIT(!i);
net.pts[j].name = pf("SS4%c%%i", s_4wire[i-1]);
j++;
net.pts[j].start_count = 0;
net.pts[j].y = y+j;
net.pts[j].x = x;
}
net.pts[j].name = pf("SS4%c%%i", s_4wire[i]);
j++;
}
net.pts[j].name = "";
if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout;
if ((rc = wire_SS4E_N3(model, &net))) goto xout;
}
}
// NN4
for (x = 0; x < model->x_width; x++) {
if (!is_atx(X_ROUTING_COL, model, x))
continue;
for (y = 0; y < model->y_height; y++) {
is_in_row(model, y, &_row_num, &_row_pos);
if (_row_pos >= 0 && _row_pos != 8) {
net.last_inc = 3;
j = 0;
for (i = 0; i < 5; i++) { // go through "BAMCE"
net.pts[j].start_count = 0;
net.pts[j].y = y-j;
net.pts[j].x = x;
if (y-j == TOP_INNER_ROW) {
EXIT(!i);
net.pts[j].name = pf("NN4%c%%i", s_4wire[i-1]);
j++;
break;
}
net.pts[j].name = pf("NN4%c%%i", s_4wire[i]);
if (IS_CENTER_Y(y-j, model)
|| pos_in_row(y-j, model) == HCLK_POS) {
EXIT(!i);
i--;
}
j++;
}
net.pts[j].name = "";
if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout;
}
}
if (!is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) {
net.last_inc = 3;
for (i = 1; i < 5; i++) { // go through "BAMCE"
net.pts[0].start_count = 0;
net.pts[0].y = BOT_TERM(model);
net.pts[0].x = x;
net.pts[0].name = pf("NN4%c%%i", s_4wire[i]);
for (j = i; j < 5; j++) {
net.pts[j-i+1].start_count = 0;
net.pts[j-i+1].y = BOT_TERM(model)-(j-i+1);
net.pts[j-i+1].x = x;
net.pts[j-i+1].name = pf("NN4%c%%i", s_4wire[j]);
}
net.pts[j-i+1].name = "";
if ((rc = add_conn_net(model, PREF_BI_F, &net))) goto xout;
}
}
}
return 0;
xout:
return rc;