diff --git a/.gitignore b/.gitignore index ddce787..becab0e 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,7 @@ floorplan.o control.o autotest autotest.o +bits.o +fp2bit +fp2bit.o +autotest.tmp/ diff --git a/Makefile b/Makefile index c736106..2a1fc3b 100644 --- a/Makefile +++ b/Makefile @@ -17,17 +17,21 @@ LDLIBS += `pkg-config libxml-2.0 --libs` MODEL_OBJ = model_main.o model_tiles.o model_devices.o model_ports.o model_conns.o model_switches.o model_helper.o -all: autotest bit2txt draw_svg_tiles new_fp hstrrep sort_seq merge_seq +all: autotest bit2txt draw_svg_tiles new_fp fp2bit hstrrep sort_seq merge_seq -autotest: autotest.o $(MODEL_OBJ) floorplan.o control.o helper.o +autotest: autotest.o $(MODEL_OBJ) floorplan.o control.o helper.o model.h new_fp: new_fp.o $(MODEL_OBJ) floorplan.o helper.o new_fp.o: new_fp.c floorplan.h model.h helper.h -floorplan.o: floorplan.c floorplan.h +fp2bit: fp2bit.c $(MODEL_OBJ) bits.o helper.o -control.o: control.c control.h +floorplan.o: floorplan.c floorplan.h model.h + +bits.o: bits.c bits.h model.h + +control.o: control.c control.h model.h draw_svg_tiles: draw_svg_tiles.o $(MODEL_OBJ) helper.o diff --git a/autotest.c b/autotest.c index e8bbeb5..869b1a9 100644 --- a/autotest.c +++ b/autotest.c @@ -17,9 +17,32 @@ time_t g_start_time; #define MEMUSAGE() printf("O memusage %i\n", get_vm_mb()); #define TIME_AND_MEM() TIMESTAMP(); MEMUSAGE() +#define AUTOTEST_TMP_DIR "autotest.tmp" + +static int dump_file(const char* path) +{ + char line[1024]; + FILE* f; + + printf("O begin dump %s\n", path); + f = fopen(path, "r"); + EXIT(!f); + while (fgets(line, sizeof(line), f)) { + if (!strncmp(line, "--- ", 4) + || !strncmp(line, "+++ ", 4) + || !strncmp(line, "@@ ", 3)) + continue; + printf(line); + } + fclose(f); + printf("O end dump %s\n", path); + return 0; +} + int main(int argc, char** argv) { struct fpga_model model; + FILE* dest_f; int rc; printf("\n"); @@ -39,12 +62,25 @@ int main(int argc, char** argv) printf("O Done\n"); TIME_AND_MEM(); - // pick 2 input IOBs, one output IOB and configure them - // pick 1 logic block and configure - // printf floorplan - // start routing, step by step - // after each step, printf floorplan diff (test_diff.sh) - // popen/fork/pipe + // todo: pick 2 input IOBs, one output IOB and configure them + // todo: pick 1 logic block and configure + + mkdir(AUTOTEST_TMP_DIR, S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH); + dest_f = fopen(AUTOTEST_TMP_DIR "/test_0001.fp", "w"); + EXIT(!dest_f); + rc = printf_devices(dest_f, &model, /*config_only*/ 1); + EXIT(rc); + rc = printf_switches(dest_f, &model, /*enabled_only*/ 1); + EXIT(rc); + fclose(dest_f); + rc = system("./autotest_diff.sh autotest.tmp/test_0001.fp"); + EXIT(rc); + rc = dump_file(AUTOTEST_TMP_DIR "/test_0001.diff"); + EXIT(rc); + + // todo: start routing, step by step + // todo: after each step, printf floorplan diff (test_diff.sh) + // todo: popen/fork/pipe printf("\n"); printf("O Test suite completed.\n"); diff --git a/autotest_diff.sh b/autotest_diff.sh new file mode 100755 index 0000000..b90056f --- /dev/null +++ b/autotest_diff.sh @@ -0,0 +1,2 @@ +#!/bin/bash +diff -u /dev/null $1 > autotest.tmp/test_0001.diff || true diff --git a/bits.c b/bits.c new file mode 100644 index 0000000..42d8d6b --- /dev/null +++ b/bits.c @@ -0,0 +1,9 @@ +// +// Author: Wolfgang Spraul +// +// This is free and unencumbered software released into the public domain. +// For details see the UNLICENSE file at the root of the source tree. +// + +#include "model.h" +#include "bits.h" diff --git a/bits.h b/bits.h new file mode 100644 index 0000000..0d6562e --- /dev/null +++ b/bits.h @@ -0,0 +1,6 @@ +// +// Author: Wolfgang Spraul +// +// This is free and unencumbered software released into the public domain. +// For details see the UNLICENSE file at the root of the source tree. +// diff --git a/floorplan.c b/floorplan.c index e5940ab..b421437 100644 --- a/floorplan.c +++ b/floorplan.c @@ -8,55 +8,56 @@ #include "model.h" #include "floorplan.h" -void printf_version(void) +void printf_version(FILE* f) { - printf("fpga_floorplan_format 1\n"); + fprintf(f, "fpga_floorplan_format 1\n"); } -#define PRINT_FLAG(f) if (tf & f) { printf (" %s", #f); tf &= ~f; } +#define PRINT_FLAG(fp, flag) if ((tf) & (flag)) \ + { fprintf (fp, " %s", #flag); tf &= ~(flag); } -int printf_tiles(struct fpga_model* model) +int printf_tiles(FILE* f, struct fpga_model* model) { struct fpga_tile* tile; int x, y; for (x = 0; x < model->x_width; x++) { - printf("\n"); + fprintf(f, "\n"); for (y = 0; y < model->y_height; y++) { tile = &model->tiles[y*model->x_width + x]; if (tile->type != NA) - printf("tile y%02i x%02i name %s\n", y, x, + fprintf(f, "tile y%02i x%02i name %s\n", y, x, fpga_tiletype_str(tile->type)); if (tile->flags) { int tf = tile->flags; - printf("tile y%02i x%02i flags", y, x); + fprintf(f, "tile y%02i x%02i flags", y, x); - PRINT_FLAG(TF_FABRIC_ROUTING_COL); - PRINT_FLAG(TF_FABRIC_LOGIC_COL); - PRINT_FLAG(TF_FABRIC_BRAM_VIA_COL); - PRINT_FLAG(TF_FABRIC_MACC_VIA_COL); - PRINT_FLAG(TF_FABRIC_BRAM_COL); - PRINT_FLAG(TF_FABRIC_MACC_COL); - PRINT_FLAG(TF_ROUTING_NO_IO); - PRINT_FLAG(TF_BRAM_DEV); - PRINT_FLAG(TF_MACC_DEV); - PRINT_FLAG(TF_LOGIC_XL_DEV); - PRINT_FLAG(TF_LOGIC_XM_DEV); - PRINT_FLAG(TF_IOLOGIC_DELAY_DEV); - PRINT_FLAG(TF_DCM_DEV); - PRINT_FLAG(TF_PLL_DEV); - PRINT_FLAG(TF_WIRED); + PRINT_FLAG(f, TF_FABRIC_ROUTING_COL); + PRINT_FLAG(f, TF_FABRIC_LOGIC_COL); + PRINT_FLAG(f, TF_FABRIC_BRAM_VIA_COL); + PRINT_FLAG(f, TF_FABRIC_MACC_VIA_COL); + PRINT_FLAG(f, TF_FABRIC_BRAM_COL); + PRINT_FLAG(f, TF_FABRIC_MACC_COL); + PRINT_FLAG(f, TF_ROUTING_NO_IO); + PRINT_FLAG(f, TF_BRAM_DEV); + PRINT_FLAG(f, TF_MACC_DEV); + PRINT_FLAG(f, TF_LOGIC_XL_DEV); + PRINT_FLAG(f, TF_LOGIC_XM_DEV); + PRINT_FLAG(f, TF_IOLOGIC_DELAY_DEV); + PRINT_FLAG(f, TF_DCM_DEV); + PRINT_FLAG(f, TF_PLL_DEV); + PRINT_FLAG(f, TF_WIRED); - if (tf) printf(" 0x%x", tf); - printf("\n"); + if (tf) fprintf(f, " 0x%x", tf); + fprintf(f, "\n"); } } } return 0; } -int printf_devices(struct fpga_model* model) +int printf_devices(FILE* f, struct fpga_model* model, int config_only) { int x, y, i; struct fpga_tile* tile; @@ -65,90 +66,92 @@ int printf_devices(struct fpga_model* model) for (y = 0; y < model->y_height; y++) { tile = YX_TILE(model, y, x); for (i = 0; i < tile->num_devices; i++) { + if (config_only && !(tile->devices[i].instantiated)) + continue; switch (tile->devices[i].type) { case DEV_LOGIC_M: - printf("device y%02i x%02i SLICEM\n", y, x); + fprintf(f, "device y%02i x%02i SLICEM\n", y, x); break; case DEV_LOGIC_L: - printf("device y%02i x%02i SLICEL\n", y, x); + fprintf(f, "device y%02i x%02i SLICEL\n", y, x); break; case DEV_LOGIC_X: - printf("device y%02i x%02i SLICEX\n", y, x); + fprintf(f, "device y%02i x%02i SLICEX\n", y, x); break; case DEV_MACC: - printf("device y%02i x%02i DSP48A1\n", y, x); + fprintf(f, "device y%02i x%02i DSP48A1\n", y, x); break; case DEV_TIEOFF: - printf("device y%02i x%02i TIEOFF\n", y, x); + fprintf(f, "device y%02i x%02i TIEOFF\n", y, x); break; case DEV_IOBM: - printf("device y%02i x%02i IOBM\n", y, x); + fprintf(f, "device y%02i x%02i IOBM\n", y, x); break; case DEV_IOBS: - printf("device y%02i x%02i IOBS\n", y, x); + fprintf(f, "device y%02i x%02i IOBS\n", y, x); break; case DEV_ILOGIC: - printf("device y%02i x%02i ILOGIC2\n", y, x); + fprintf(f, "device y%02i x%02i ILOGIC2\n", y, x); break; case DEV_OLOGIC: - printf("device y%02i x%02i OLOGIC2\n", y, x); + fprintf(f, "device y%02i x%02i OLOGIC2\n", y, x); break; case DEV_IODELAY: - printf("device y%02i x%02i IODELAY2\n", y, x); + fprintf(f, "device y%02i x%02i IODELAY2\n", y, x); break; case DEV_BRAM16: - printf("device y%02i x%02i RAMB16BWER\n", y, x); + fprintf(f, "device y%02i x%02i RAMB16BWER\n", y, x); break; case DEV_BRAM8: - printf("device y%02i x%02i RAMB8BWER\n", y, x); + fprintf(f, "device y%02i x%02i RAMB8BWER\n", y, x); break; case DEV_BUFH: - printf("device y%02i x%02i BUFH\n", y, x); + fprintf(f, "device y%02i x%02i BUFH\n", y, x); break; case DEV_BUFIO: - printf("device y%02i x%02i BUFIO2\n", y, x); + fprintf(f, "device y%02i x%02i BUFIO2\n", y, x); break; case DEV_BUFIO_FB: - printf("device y%02i x%02i BUFIO2FB\n", y, x); + fprintf(f, "device y%02i x%02i BUFIO2FB\n", y, x); break; case DEV_BUFPLL: - printf("device y%02i x%02i BUFPLL\n", y, x); + fprintf(f, "device y%02i x%02i BUFPLL\n", y, x); break; case DEV_BUFPLL_MCB: - printf("device y%02i x%02i BUFPLL_MCB\n", y, x); + fprintf(f, "device y%02i x%02i BUFPLL_MCB\n", y, x); break; case DEV_BUFGMUX: - printf("device y%02i x%02i BUFGMUX\n", y, x); + fprintf(f, "device y%02i x%02i BUFGMUX\n", y, x); break; case DEV_BSCAN: - printf("device y%02i x%02i BSCAN\n", y, x); + fprintf(f, "device y%02i x%02i BSCAN\n", y, x); break; case DEV_DCM: - printf("device y%02i x%02i DCM\n", y, x); + fprintf(f, "device y%02i x%02i DCM\n", y, x); break; case DEV_PLL: - printf("device y%02i x%02i PLL\n", y, x); + fprintf(f, "device y%02i x%02i PLL\n", y, x); break; case DEV_ICAP: - printf("device y%02i x%02i ICAP\n", y, x); + fprintf(f, "device y%02i x%02i ICAP\n", y, x); break; case DEV_POST_CRC_INTERNAL: - printf("device y%02i x%02i POST_CRC_INTERNAL\n", y, x); + fprintf(f, "device y%02i x%02i POST_CRC_INTERNAL\n", y, x); break; case DEV_STARTUP: - printf("device y%02i x%02i STARTUP\n", y, x); + fprintf(f, "device y%02i x%02i STARTUP\n", y, x); break; case DEV_SLAVE_SPI: - printf("device y%02i x%02i SLAVE_SPI\n", y, x); + fprintf(f, "device y%02i x%02i SLAVE_SPI\n", y, x); break; case DEV_SUSPEND_SYNC: - printf("device y%02i x%02i SUSPEND_SYNC\n", y, x); + fprintf(f, "device y%02i x%02i SUSPEND_SYNC\n", y, x); break; case DEV_OCT_CALIBRATE: - printf("device y%02i x%02i OCT_CALIBRATE\n", y, x); + fprintf(f, "device y%02i x%02i OCT_CALIBRATE\n", y, x); break; case DEV_SPI_ACCESS: - printf("device y%02i x%02i SPI_ACCESS\n", y, x); + fprintf(f, "device y%02i x%02i SPI_ACCESS\n", y, x); break; } } @@ -157,7 +160,7 @@ int printf_devices(struct fpga_model* model) return 0; } -int printf_ports(struct fpga_model* model) +int printf_ports(FILE* f, struct fpga_model* model) { struct fpga_tile* tile; const char* conn_point_name_src; @@ -186,16 +189,17 @@ int printf_ports(struct fpga_model* model) } if (!first_port_printed) { first_port_printed = 1; - printf("\n"); + fprintf(f, "\n"); } - printf("port y%02i x%02i %s\n", y, x, conn_point_name_src); + fprintf(f, "port y%02i x%02i %s\n", + y, x, conn_point_name_src); } } } return 0; } -int printf_conns(struct fpga_model* model) +int printf_conns(FILE* f, struct fpga_model* model) { struct fpga_tile* tile; char tmp_line[512]; @@ -237,7 +241,7 @@ int printf_conns(struct fpga_model* model) if (!first_conn_printed) { first_conn_printed = 1; - printf("\n"); + fprintf(f, "\n"); } sprintf(tmp_line, "static_conn y%02i x%02i %s ", y, x, conn_point_name_src); @@ -246,7 +250,7 @@ int printf_conns(struct fpga_model* model) tmp_line[k++] = ' '; sprintf(&tmp_line[k], "y%02i x%02i %s\n", other_tile_y, other_tile_x, other_tile_connpt_str); - printf(tmp_line); + fprintf(f, tmp_line); } } } @@ -254,11 +258,11 @@ int printf_conns(struct fpga_model* model) return 0; } -int printf_switches(struct fpga_model* model) +int printf_switches(FILE* f, struct fpga_model* model, int enabled_only) { struct fpga_tile* tile; int x, y, i, from_connpt_o, to_connpt_o, from_str_i, to_str_i; - int first_switch_printed, is_bidirectional; + int first_switch_printed, is_bidirectional, is_on; const char* from_str, *to_str; for (x = 0; x < model->x_width; x++) { @@ -270,6 +274,7 @@ int printf_switches(struct fpga_model* model) from_connpt_o = (tile->switches[i] & 0x3FFF8000) >> 15; to_connpt_o = tile->switches[i] & 0x00007FFF; is_bidirectional = (tile->switches[i] & SWITCH_BIDIRECTIONAL) != 0; + is_on = (tile->switches[i] & SWITCH_ON) != 0; from_str_i = tile->conn_point_names[from_connpt_o*2+1]; to_str_i = tile->conn_point_names[to_connpt_o*2+1]; @@ -281,12 +286,15 @@ int printf_switches(struct fpga_model* model) __FILE__, __LINE__, from_str_i, to_str_i); continue; } + if (enabled_only && !is_on) + continue; if (!first_switch_printed) { first_switch_printed = 1; - printf("\n"); + fprintf(f, "\n"); } - printf("switch y%02i x%02i %s %s %s\n", y, x, from_str, - is_bidirectional ? "<->" : "->", to_str); + fprintf(f, "switch y%02i x%02i %s %s %s\n", + y, x, from_str, is_bidirectional + ? "<->" : "->", to_str); } } } diff --git a/floorplan.h b/floorplan.h index 546bfb1..439be5b 100644 --- a/floorplan.h +++ b/floorplan.h @@ -24,9 +24,9 @@ // - lines should typically not exceed 80 characters // -void printf_version(void); -int printf_tiles(struct fpga_model* model); -int printf_devices(struct fpga_model* model); -int printf_ports(struct fpga_model* model); -int printf_conns(struct fpga_model* model); -int printf_switches(struct fpga_model* model); +void printf_version(FILE* f); +int printf_tiles(FILE* f, struct fpga_model* model); +int printf_devices(FILE* f, struct fpga_model* model, int config_only); +int printf_ports(FILE* f, struct fpga_model* model); +int printf_conns(FILE* f, struct fpga_model* model); +int printf_switches(FILE* f, struct fpga_model* model, int enabled_only); diff --git a/fp2bit.c b/fp2bit.c new file mode 100644 index 0000000..0002ebe --- /dev/null +++ b/fp2bit.c @@ -0,0 +1,23 @@ +// +// Author: Wolfgang Spraul +// +// This is free and unencumbered software released into the public domain. +// For details see the UNLICENSE file at the root of the source tree. +// + +#include "model.h" +#include "bits.h" + +int main(int argc, char** argv) +{ + struct fpga_model model; + int rc; + + if ((rc = fpga_build_model(&model, XC6SLX9_ROWS, XC6SLX9_COLUMNS, + XC6SLX9_LEFT_WIRING, XC6SLX9_RIGHT_WIRING))) + goto fail; + + return EXIT_SUCCESS; +fail: + return rc; +} diff --git a/model.h b/model.h index b35603a..e9b6fb0 100644 --- a/model.h +++ b/model.h @@ -301,6 +301,10 @@ enum fpgadev_type DEV_SPI_ACCESS }; +// All device configuration is structured so that the value +// 0 is never a valid configured setting. That way all config +// data can safely be initialized to 0 meaning unconfigured. + struct fpgadev_logic_x { int a; @@ -316,13 +320,41 @@ struct fpgadev_logic_m int c; }; +typedef char IOSTANDARD[32]; +#define IO_LVCMOS33 "LVCMOS33" +enum { BYPASS_MUX_I = 1, BYPASS_MUX_O, BYPASS_MUX_T }; +enum { IMUX_I_B = 1, IMUX_I }; +enum { SLEW_SLOW = 1, SLEW_FAST, SLEW_QUIETIO }; +enum { SUSP_LAST_VAL = 1, SUSP_3STATE, SUSP_3STATE_PULLUP, + SUSP_3STATE_PULLDOWN, SUSP_3STATE_KEEPER, SUSP_3STATE_OCT_ON }; +enum { ITERM_NONE = 1, ITERM_UNTUNED_25, ITERM_UNTUNED_50, + ITERM_UNTUNED_75 }; +enum { OTERM_NONE = 1, OTERM_UNTUNED_25, OTERM_UNTUNED_50, + OTERM_UNTUNED_75 }; + +struct fpgadev_iob +{ + IOSTANDARD istandard; + IOSTANDARD ostandard; + int bypass_mux; + int imux; + int drive_strength; // supports 2,4,6,8,12,16 and 24 + int slew; + int o_used; + int suspend; + int in_term; + int out_term; +}; + struct fpga_device { enum fpgadev_type type; + int instantiated; union { struct fpgadev_logic_m log_m; struct fpgadev_logic_l log_l; struct fpgadev_logic_x log_x; + struct fpgadev_iob iob; }; }; @@ -335,7 +367,7 @@ struct fpga_tile enum fpga_tile_type type; int flags; - // expect up to 64 devices per tile + // we currently support a maximum of 32 devices per tile int num_devices; struct fpga_device devices[32]; @@ -387,17 +419,29 @@ int has_device(struct fpga_model* model, int y, int x, int dev); int add_connpt_2(struct fpga_model* model, int y, int x, const char* connpt_name, const char* suffix1, const char* suffix2); -typedef int (*add_conn_f)(struct fpga_model* model, int y1, int x1, const char* name1, int y2, int x2, const char* name2); +typedef int (*add_conn_f)(struct fpga_model* model, + int y1, int x1, const char* name1, + int y2, int x2, const char* name2); #define NOPREF_BI_F add_conn_bi #define PREF_BI_F add_conn_bi_pref #define NOPREF_UNI_F add_conn_uni #define PREF_UNI_F add_conn_uni_pref -int add_conn_uni(struct fpga_model* model, int y1, int x1, const char* name1, int y2, int x2, const char* name2); -int add_conn_uni_pref(struct fpga_model* model, int y1, int x1, const char* name1, int y2, int x2, const char* name2); -int add_conn_bi(struct fpga_model* model, int y1, int x1, const char* name1, int y2, int x2, const char* name2); -int add_conn_bi_pref(struct fpga_model* model, int y1, int x1, const char* name1, int y2, int x2, const char* name2); -int add_conn_range(struct fpga_model* model, add_conn_f add_conn_func, int y1, int x1, const char* name1, int start1, int last1, int y2, int x2, const char* name2, int start2); +int add_conn_uni(struct fpga_model* model, + int y1, int x1, const char* name1, + int y2, int x2, const char* name2); +int add_conn_uni_pref(struct fpga_model* model, + int y1, int x1, const char* name1, + int y2, int x2, const char* name2); +int add_conn_bi(struct fpga_model* model, + int y1, int x1, const char* name1, + int y2, int x2, const char* name2); +int add_conn_bi_pref(struct fpga_model* model, + int y1, int x1, const char* name1, + int y2, int x2, const char* name2); +int add_conn_range(struct fpga_model* model, add_conn_f add_conn_func, + int y1, int x1, const char* name1, int start1, int last1, + int y2, int x2, const char* name2, int start2); // COUNT_DOWN can be OR'ed to start_count to make // the enumerated wires count from start_count down. diff --git a/model_main.c b/model_main.c index 9a1aa54..48c8a9d 100644 --- a/model_main.c +++ b/model_main.c @@ -38,8 +38,10 @@ int fpga_build_model(struct fpga_model* model, int fpga_rows, const char* column rc = init_conns(model); if (rc) return rc; +#if 0 rc = init_switches(model); if (rc) return rc; +#endif return 0; } diff --git a/new_fp.c b/new_fp.c index f306395..2d29899 100644 --- a/new_fp.c +++ b/new_fp.c @@ -21,23 +21,23 @@ int main(int argc, char** argv) if (argc > 1 && !strcmp(argv[1], "--no-conns")) no_conns = 1; - printf_version(); + printf_version(stdout); - rc = printf_tiles(&model); + rc = printf_tiles(stdout, &model); if (rc) goto fail; - rc = printf_devices(&model); + rc = printf_devices(stdout, &model, /*config_only*/ 0); if (rc) goto fail; - rc = printf_ports(&model); + rc = printf_ports(stdout, &model); if (rc) goto fail; if (!no_conns) { - rc = printf_conns(&model); + rc = printf_conns(stdout, &model); if (rc) goto fail; } - rc = printf_switches(&model); + rc = printf_switches(stdout, &model, /*enabled_only*/ 0); if (rc) goto fail; return EXIT_SUCCESS;