diff --git a/Makefile b/Makefile index bf780dd..a953bb9 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ all: new_fp fp2bit bit2fp draw_svg_tiles \ autotest: autotest.o $(MODEL_OBJ) floorplan.o control.o helper.o model.h -autotest.c: model.h floorplan.h control.h +autotest.o: model.h floorplan.h control.h new_fp: new_fp.o $(MODEL_OBJ) floorplan.o helper.o control.o diff --git a/README b/README index 61eb888..942714b 100644 --- a/README +++ b/README @@ -4,15 +4,22 @@ Design Principles - plain C, no C++ - simple Makefiles - text-based file formats -- no documentation - please read the sources - automatic test suite +- public domain software + +Introduction + todo + +FAQ + todo Libraries -- libfpga-test test harness for model, control and design -- libfpga-model memory-only representation of an FPGA -- libfpga-control programmatic access to libfpga-model +- libfpga-test autotest suite +- libfpga-cores reusable cores - libfpga-design larger 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 - libfpga-bit reads and writes .bit bitstream files @@ -40,13 +47,14 @@ TODO (as of 2012-08, expected time to delivery: months to years * smarter autotester that can remember and verify groups of tests, automatically oversee test execution, etc. * 3 Debian packages: libfpga, libfpga-doc, fpgatools -* correct auto-crc calculation in .bit file +* auto-crc calculation in .bit file * many more cases in logic block configuration * 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 * support lm32 or openrisc core, either via libfpga or iverilog backend +* ipv6 or vnc in hardware? * iverilog fpga backend ChangeLog diff --git a/autotest.c b/autotest.c index 0c85995..c45988e 100644 --- a/autotest.c +++ b/autotest.c @@ -108,18 +108,16 @@ static const char* s_spaces = " "; static int printf_switchtree(struct fpga_model* model, int y, int x, const char* start, int indent) { - int i, idx, conn_to_y, conn_to_x, rc; + int i, idx, conn_to_y, conn_to_x, num_dests, connpt_dests_o, rc; const char* to_str; printf("%.*sy%02i x%02i %s\n", indent, s_spaces, y, x, start); - for (i = 0;; i++) { - idx = fpga_conn_dest(model, y, x, start, i); - if (idx == NO_CONN) - break; + num_dests = fpga_connpt_lookup(model, y, x, start, &connpt_dests_o); + for (i = 0; i < num_dests; i++) { if (!i) printf("%.*s| connects to:\n", indent, s_spaces); - to_str = fpga_conn_to(model, y, x, - idx, &conn_to_y, &conn_to_x); + to_str = fpga_conn_dest(model, y, x, + connpt_dests_o + i, &conn_to_y, &conn_to_x); printf("%.*s y%02i x%02i %s\n", indent, s_spaces, conn_to_y, conn_to_x, to_str); } @@ -151,16 +149,16 @@ static int printf_switchtree(struct fpga_model* model, int y, int x, fail: return rc; } + 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, i, sw_idx, rc; - const char* str; - char tmp_str[128]; + int P46_y, P46_x, P46_idx, P48_y, P48_x, P48_idx, rc; struct test_state tstate; - const char* conn_to_str; - int conn_idx, conn_to_y, conn_to_x; + struct sw_chain chain; + struct swchain_conns conns; + char tmp_str[128]; printf("\n"); printf("O fpgatools automatic test suite. Be welcome and be " @@ -219,46 +217,74 @@ int main(int argc, char** argv) if (rc) goto fail; printf("P46 I pinw %s\n", P46_dev->iob.pinw_out_I); - sw_idx = fpga_switch_first(&model, P46_y, P46_x, - P46_dev->iob.pinw_out_I, SW_FROM); - while (sw_idx != NO_SWITCH) { - str = fpga_switch_str(&model, P46_y, P46_x, sw_idx, SW_TO); - if (!str) FAIL(EINVAL); - strcpy(tmp_str, str); // ringbuffer too small for long use - printf(" from %s to %s\n", P46_dev->iob.pinw_out_I, tmp_str); - for (i = 0;; i++) { - conn_idx = fpga_conn_dest(&model, P46_y, P46_x, tmp_str, i); - if (conn_idx == NO_CONN) - break; - conn_to_str = fpga_conn_to(&model, P46_y, P46_x, - conn_idx, &conn_to_y, &conn_to_x); - printf(" %s goes to y%02i x%02i %s\n", - tmp_str, conn_to_y, conn_to_x, conn_to_str); - if (is_aty(Y_TOP_INNER_IO|Y_BOT_INNER_IO, &model, conn_to_y)) { - rc = printf_switchtree(&model, conn_to_y, - conn_to_x, conn_to_str, /*indent*/ 3); - if (rc) FAIL(rc); + 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)) { + struct swchain_conns conns2; + + printf("conn chain_size %i connpt_o %i num_dests %i i %i y %i x %i str %s\n", + conns.chain.chain_size, conns.connpt_dest_start, + conns.num_dests, conns.dest_i, conns.dest_y, conns.dest_x, conns.dest_str); + + strcpy(tmp_str, conns.dest_str); + conns2.model = &model; + 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; + + 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); + 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); + } + 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 - { swidx_t idx; - swidx_t* parents; int num_parents; - - idx = fpga_switch_tree(&model, conn_to_y, conn_to_x, - conn_to_str, SW_FROM, &parents, &num_parents); - while (idx != NO_SWITCH) { - printf("idx %i num_parents %i from %s to %s\n", - idx, num_parents, - fpga_switch_str(&model, conn_to_y, conn_to_x, idx, SW_FROM), - fpga_switch_str(&model, conn_to_y, conn_to_x, idx, SW_TO)); - idx = fpga_switch_tree(&model, conn_to_y, conn_to_x, - SW_TREE_NEXT, SW_FROM, &parents, &num_parents); - } - } + 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 } - sw_idx = fpga_switch_next(&model, P46_y, P46_x, sw_idx, SW_FROM); } + printf("P48 O pinw %s\n", P48_dev->iob.pinw_in_O); printf("\n"); diff --git a/control.c b/control.c index 9c5ce53..23168ce 100644 --- a/control.c +++ b/control.c @@ -262,11 +262,11 @@ int fpga_set_lut(struct fpga_model* model, struct fpga_device* dev, return 0; } -int fpga_conn_dest(struct fpga_model* model, int y, int x, - const char* name, int dest_idx) +int fpga_connpt_lookup(struct fpga_model* model, int y, int x, + const char* name, int* connpt_dests_o) { struct fpga_tile* tile; - int i, rc, connpt_i, num_dests, conn_point_dests_o; + int i, rc, connpt_i, num_dests; rc = strarray_find(&model->str, name, &connpt_i); if (rc) FAIL(rc); @@ -278,22 +278,20 @@ int fpga_conn_dest(struct fpga_model* model, int y, int x, if (i >= tile->num_conn_point_names) FAIL(EINVAL); - conn_point_dests_o = tile->conn_point_names[i*2]; + *connpt_dests_o = tile->conn_point_names[i*2]; if (i < tile->num_conn_point_names-1) - num_dests = tile->conn_point_names[(i+1)*2] - conn_point_dests_o; + num_dests = tile->conn_point_names[(i+1)*2] - *connpt_dests_o; else - num_dests = tile->num_conn_point_dests - conn_point_dests_o; - if (dest_idx >= num_dests) - return NO_CONN; - return conn_point_dests_o + dest_idx; + num_dests = tile->num_conn_point_dests - *connpt_dests_o; + return num_dests; fail: - return NO_CONN; + return 0; } #define NUM_CONN_DEST_BUFS 16 #define CONN_DEST_BUF_SIZE 128 -const char* fpga_conn_to(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) { static char conn_dest_buf[NUM_CONN_DEST_BUFS][CONN_DEST_BUF_SIZE]; @@ -346,7 +344,8 @@ fail: return NO_SWITCH; } -swidx_t fpga_switch_next(struct fpga_model* model, int y, int x, swidx_t last, int from_to) +static swidx_t fpga_switch_search(struct fpga_model* model, int y, int x, + swidx_t last, swidx_t search_beg, int from_to) { struct fpga_tile* tile; int connpt_o, name_i, i; @@ -357,7 +356,7 @@ swidx_t fpga_switch_next(struct fpga_model* model, int y, int x, swidx_t last, i : SWITCH_TO(tile->switches[last]); name_i = tile->conn_point_names[connpt_o*2+1]; - for (i = last+1; i < tile->num_switches; i++) { + 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]); @@ -367,58 +366,16 @@ swidx_t fpga_switch_next(struct fpga_model* model, int y, int x, swidx_t last, i return (i >= tile->num_switches) ? NO_SWITCH : i; } -#define MAX_SW_PARENTS 32 - -swidx_t fpga_switch_tree(struct fpga_model* model, int y, int x, - const char* name, int from_to, swidx_t** parents, int* num_parents) +swidx_t fpga_switch_next(struct fpga_model* model, int y, int x, + swidx_t last, int from_to) { - // the static 'parents' always contain the current - // (last) member as their last element, which is - // not reported back as a parent. - static swidx_t s_parents[MAX_SW_PARENTS]; - static int s_num_parents = 0; + return fpga_switch_search(model, y, x, last, last+1, from_to); +} - swidx_t idx; - - *parents = s_parents; - if (name != SW_TREE_NEXT) { - idx = fpga_switch_first(model, y, x, name, from_to); - if (idx == NO_SWITCH) return NO_SWITCH; - s_parents[0] = idx; - s_num_parents = 1; - *num_parents = 0; - return idx; - } - if (!s_num_parents) { - HERE(); - return NO_SWITCH; - } - // first check whether there are children - idx = fpga_switch_first(model, y, x, - fpga_switch_str(model, y, x, s_parents[s_num_parents-1], !from_to), - from_to); - if (idx != NO_SWITCH) { - if (s_num_parents >= MAX_SW_PARENTS) { - HERE(); - return NO_SWITCH; - } - s_parents[s_num_parents] = idx; - s_num_parents++; - *num_parents = s_num_parents - 1; - return idx; - } - do { - // then check whether there are more members at the same level - idx = fpga_switch_next(model, y, x, s_parents[s_num_parents-1], - from_to); - if (idx != NO_SWITCH) { - s_parents[s_num_parents-1] = idx; - *num_parents = s_num_parents - 1; - return idx; - } - // and finally go one level up - } while (s_num_parents--); // post-decrement - return NO_SWITCH; +swidx_t fpga_switch_backtofirst(struct fpga_model* model, int y, int x, + swidx_t last, int from_to) +{ + return fpga_switch_search(model, y, x, last, /*search_beg*/ 0, from_to); } #define NUM_CONNPT_BUFS 16 @@ -476,3 +433,122 @@ void fpga_switch_disable(struct fpga_model* model, int y, int x, { YX_TILE(model, y, x)->switches[swidx] &= ~SWITCH_ON; } + +int fpga_switch_chain_enum(struct sw_chain* chain) +{ + swidx_t idx; + + if (chain->start_switch != SW_CHAIN_NEXT) { + idx = fpga_switch_first(chain->model, chain->y, chain->x, + chain->start_switch, chain->from_to); + chain->start_switch = SW_CHAIN_NEXT; + if (idx == NO_SWITCH) { + chain->chain_size = 0; + return NO_SWITCH; + } + chain->chain[0] = idx; + chain->chain_size = 1; + + // at every level, the first round returns all members + // at that level, then the second round tries to go + // one level down for each member. This sorts the + // returned switches in a nice way. + chain->first_round = 1; + return 0; + } + if (!chain->chain_size) { + HERE(); goto internal_error; + } + if (chain->first_round) { + // first go through all members are present level + idx = fpga_switch_next(chain->model, chain->y, chain->x, + chain->chain[chain->chain_size-1], chain->from_to); + if (idx != NO_SWITCH) { + chain->chain[chain->chain_size-1] = idx; + return 0; + } + // if there are no more, initiate the second round + // looking for children + chain->first_round = 0; + idx = fpga_switch_backtofirst(chain->model, chain->y, chain->x, + chain->chain[chain->chain_size-1], chain->from_to); + if (idx == NO_SWITCH) { + HERE(); goto internal_error; + } + chain->chain[chain->chain_size-1] = idx; + } + // look for children + 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); + if (idx != NO_SWITCH) { + if (chain->chain_size >= MAX_SW_CHAIN_SIZE) { + HERE(); goto internal_error; + } + 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) { + if (chain->chain_size <= 1) { + chain->chain_size = 0; + return NO_SWITCH; + } + chain->chain_size--; + } + } +internal_error: + chain->chain_size = 0; + return NO_SWITCH; +} + +int fpga_switch_conns_enum(struct swchain_conns* conns) +{ + const char* end_of_chain_str; + + if (conns->start_switch != SW_CHAIN_NEXT) { + conns->chain.model = conns->model; + conns->chain.y = conns->y; + conns->chain.x = conns->x; + conns->chain.start_switch = conns->start_switch; + conns->chain.from_to = SW_FROM; + + conns->start_switch = SW_CHAIN_NEXT; + conns->num_dests = 0; + conns->dest_i = 0; + } + else if (!conns->chain.chain_size) { HERE(); goto internal_error; } + + while (conns->dest_i >= conns->num_dests) { + fpga_switch_chain_enum(&conns->chain); + if (conns->chain.chain_size == 0) + return NO_CONN; + end_of_chain_str = fpga_switch_str(conns->model, + conns->y, conns->x, + conns->chain.chain[conns->chain.chain_size-1], + SW_TO); + if (!end_of_chain_str) { HERE(); goto internal_error; } + conns->dest_i = 0; + conns->num_dests = fpga_connpt_lookup(conns->model, + conns->y, conns->x, end_of_chain_str, + &conns->connpt_dest_start); + if (conns->num_dests) + break; + } + conns->dest_str = fpga_conn_dest(conns->model, conns->y, conns->x, + conns->connpt_dest_start + conns->dest_i, + &conns->dest_y, &conns->dest_x); + if (!conns->dest_str) { HERE(); goto internal_error; } + conns->dest_i++; + return 0; + +internal_error: + conns->chain.chain_size = 0; + return NO_CONN; +} diff --git a/control.h b/control.h index e1cf85d..146d132 100644 --- a/control.h +++ b/control.h @@ -31,10 +31,13 @@ enum { A6_LUT, B6_LUT, C6_LUT, D6_LUT }; int fpga_set_lut(struct fpga_model* model, struct fpga_device* dev, int which_lut, const char* lut_str, int lut_len); -// returns a connpt dest index, or -1 (NO_CONN) if no connection was found -int fpga_conn_dest(struct fpga_model* model, int y, int x, - const char* name, int dest_idx); -const char* fpga_conn_to(struct fpga_model* model, int y, int x, +// returns the number of outgoing connections for the +// connection point given with 'name', and the connection +// point's first dest offset in connpt_dests_o. +int fpga_connpt_lookup(struct fpga_model* model, int y, int x, + const char* name, int* connpt_dests_o); + +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; @@ -48,11 +51,8 @@ swidx_t fpga_switch_first(struct fpga_model* model, int y, int x, const char* name, int from_to); swidx_t fpga_switch_next(struct fpga_model* model, int y, int x, swidx_t last, int from_to); - -#define SW_TREE_NEXT 0 // use for name -// returns -1 (NO_SWITCH) when there are no more switches in the tree -swidx_t fpga_switch_tree(struct fpga_model* model, int y, int x, - const char* name, int from_to, swidx_t** parents, int* num_parents); +swidx_t fpga_switch_backtofirst(struct fpga_model* model, int y, int x, + swidx_t last, int from_to); const char* fpga_switch_str(struct fpga_model* model, int y, int x, swidx_t swidx, int from_to); @@ -64,3 +64,52 @@ void fpga_switch_enable(struct fpga_model* model, int y, int x, swidx_t swidx); void fpga_switch_disable(struct fpga_model* model, int y, int x, swidx_t swidx); + +#define SW_CHAIN_NEXT 0 // use for name +#define MAX_SW_CHAIN_SIZE 32 + +struct sw_chain +{ + // start and recurring values: + struct fpga_model* model; + int y; + int x; + // start_switch will be set to SW_CHAIN_NEXT (0) after the first call + const char* start_switch; + int from_to; + + // return values: + swidx_t chain[MAX_SW_CHAIN_SIZE]; + int chain_size; + + // internal: + int first_round; +}; + +// Returns 0 if another switch is returned in chain, or +// NO_SWITCH (-1) if there is no other switch. +// chain_size set to 0 when there are no more switches in the tree +int fpga_switch_chain_enum(struct sw_chain* chain); + +struct swchain_conns +{ + // start and recurring values: + struct fpga_model* model; + int y; + int x; + // start_switch will be set to SW_CHAIN_NEXT (0) after first call + const char* start_switch; + + // return values: + struct sw_chain chain; + int connpt_dest_start; + int num_dests; + int dest_i; + int dest_y; + int dest_x; + const char* dest_str; +}; + +// Returns 0 if another connection is returned in conns, or +// NO_CONN (-1) if there is no other connection. +int fpga_switch_conns_enum(struct swchain_conns* conns);