diff --git a/README b/README index d27eee8..b85ead3 100644 --- a/README +++ b/README @@ -5,16 +5,13 @@ Introduction block ram and multiply-accumulate devices. The long-term goals of fpgatools are: - *) reach the maximum physical performance of the chip + *) reach maximum physical chip performance *) fast development cycles *) independent toolchain that only depends on other free software - *) bootstrap on chip, i.e. program the fpga from a softcore running - on the same fpga - *) complete package including all tools to get started such as jtag, - debugging, parts data and designs for prototyping hardware - *) work towards a design flow that includes later manufacturing - in different ASIC processes, include information about ASIC - processes, libraries, GDS generation, etc. + *) reconfigure on-chip + *) include get-started tools such as jtag, debugging, parts data + and designs for prototyping hardware + *) design flow that includes asic manufacturing *) lightweight C implementation without GUI *) supported platform: Linux *) license: public domain @@ -59,13 +56,9 @@ Design Principles TODO short-term (1 month): -* add lut_encoding autotest for lut6 and lut5 in a-d position - of x(m), x(l), l and m devs -* more cases in logic_cfg test * example: blinking_led * example: counter (including clock, jtag) -* support reading iologic switches -* autotest: fix roundtrip issues in routing_sw test +* autotest: fix bugs in lut_encoding, logic_cfg, routing_sw, io_sw tests * autotest: protect stderr of diff executable in autotest log * 3 Debian packages: libfpga, libfpga-doc, fpgatools diff --git a/autotest.c b/autotest.c index a63ef34..1444ca9 100644 --- a/autotest.c +++ b/autotest.c @@ -957,6 +957,22 @@ static int test_iob_config(struct test_state* tstate) i++; }} + // enum all iobs + { + const char* name; + for (i = 0; (name = fpga_enum_iob(tstate->model, i, &iob_y, + &iob_x, &iob_type_idx)); i++) { + if (tstate->dry_run) + printf("IOB %s y%02i x%02i i%i\n", name, + iob_y, iob_x, iob_type_idx); + rc = fdev_iob_IMUX(tstate->model, iob_y, iob_x, + iob_type_idx, IMUX_I); + if (rc) FAIL(rc); + if ((rc = diff_printf(tstate))) FAIL(rc); + fdev_delete(tstate->model, iob_y, iob_x, + DEV_IOB, iob_type_idx); + } + } return 0; fail: return rc; diff --git a/blinking_led.c b/blinking_led.c index 44dba8d..b844d33 100644 --- a/blinking_led.c +++ b/blinking_led.c @@ -22,43 +22,73 @@ assign led = counter[14]; endmodule - */ int main(int argc, char** argv) { struct fpga_model model; - int iob_inA_y, iob_inA_x, iob_inA_type_idx; - int iob_inB_y, iob_inB_x, iob_inB_type_idx; - int iob_out_y, iob_out_x, iob_out_type_idx; + int iob_clk_y, iob_clk_x, iob_clk_type_idx; + int iob_led_y, iob_led_x, iob_led_type_idx; int logic_y, logic_x, logic_type_idx; + struct fpgadev_logic logic_cfg; net_idx_t inA_net, inB_net, out_net; - int rc; - if ((rc = fpga_build_model(&model, XC6SLX9_ROWS, XC6SLX9_COLUMNS, - XC6SLX9_LEFT_WIRING, XC6SLX9_RIGHT_WIRING))) FAIL(rc); + fpga_build_model(&model, XC6SLX9_ROWS, XC6SLX9_COLUMNS, + XC6SLX9_LEFT_WIRING, XC6SLX9_RIGHT_WIRING); - if ((rc = fpga_find_iob(&model, "P45", &iob_inA_y, &iob_inA_x, - &iob_inA_type_idx))) FAIL(rc); - if ((rc = fdev_iob_input(&model, iob_inA_y, iob_inA_x, - iob_inA_type_idx, IO_LVCMOS33))) FAIL(rc); + fpga_find_iob(&model, "P55", &iob_clk_y, &iob_clk_x, &iob_clk_type_idx); + fdev_iob_input(&model, iob_clk_y, iob_clk_x, iob_clk_type_idx, + IO_LVCMOS33); - if ((rc = fpga_find_iob(&model, "P46", &iob_inB_y, &iob_inB_x, - &iob_inB_type_idx))) FAIL(rc); - if ((rc = fdev_iob_input(&model, iob_inB_y, iob_inB_x, - iob_inB_type_idx, IO_LVCMOS33))) FAIL(rc); - - if ((rc = fpga_find_iob(&model, "P48", &iob_out_y, &iob_out_x, - &iob_out_type_idx))) FAIL(rc); - if ((rc = fdev_iob_output(&model, iob_out_y, iob_out_x, - iob_out_type_idx, IO_LVCMOS33))) FAIL(rc); + fpga_find_iob(&model, "P48", &iob_led_y, &iob_led_x, &iob_led_type_idx); + fdev_iob_output(&model, iob_led_y, iob_led_x, iob_led_type_idx, + IO_LVCMOS25); + fdev_iob_slew(&model, iob_led_y, iob_led_x, iob_led_type_idx, + SLEW_QUIETIO); + fdev_iob_drive(&model, iob_led_y, iob_led_x, iob_led_type_idx, + 8); +#if 0 logic_y = 68; logic_x = 13; logic_type_idx = DEV_LOG_X; if ((rc = fdev_logic_a2d_lut(&model, logic_y, logic_x, logic_type_idx, LUT_D, 6, "A3*A5", ZTERM))) FAIL(rc); + memset(&logic_cfg, 0, sizeof(logic_cfg)); + logic_cfg.a2d[LUT_A].lut6 = "(A6+~A6)*(~A5)"; + logic_cfg.a2d[LUT_A].lut5 = "1"; + logic_cfg.a2d[LUT_A].cy0 = CY0_O5; + logic_cfg.a2d[LUT_A].ff = FF_FF; + logic_cfg.a2d[LUT_A].ff_mux = MUX_XOR; + logic_cfg.a2d[LUT_A].ff_srinit = FF_SRINIT0; + logic_cfg.a2d[LUT_B].lut6 = "(A6+~A6)*(A5)"; + logic_cfg.a2d[LUT_B].lut5 = "1"; + logic_cfg.a2d[LUT_B].cy0 = CY0_O5; + logic_cfg.a2d[LUT_B].ff = FF_FF; + logic_cfg.a2d[LUT_B].ff_mux = MUX_XOR; + logic_cfg.a2d[LUT_B].ff_srinit = FF_SRINIT0; + logic_cfg.a2d[LUT_C].lut6 = "(A6+~A6)*(A5)"; + logic_cfg.a2d[LUT_C].lut5 = "1"; + logic_cfg.a2d[LUT_C].cy0 = CY0_O5; + logic_cfg.a2d[LUT_C].ff = FF_FF; + logic_cfg.a2d[LUT_C].ff_mux = MUX_XOR; + logic_cfg.a2d[LUT_C].ff_srinit = FF_SRINIT0; + logic_cfg.a2d[LUT_D].lut6 = "(A6+~A6)*(A5)"; + logic_cfg.a2d[LUT_D].lut5 = "1"; + logic_cfg.a2d[LUT_D].cy0 = CY0_O5; + logic_cfg.a2d[LUT_D].ff = FF_FF; + logic_cfg.a2d[LUT_D].ff_mux = MUX_XOR; + logic_cfg.a2d[LUT_D].ff_srinit = FF_SRINIT0; + + logic_cfg.clk_inv = CLKINV_CLK; + logic_cfg.sync_attr = SYNCATTR_ASYNC; + logic_cfg.precyinit = PRECYINIT_0; + logic_cfg.cout_used = 1; + rc = fdev_logic_setconf(tstate->model, y, x, type_idx, logic_cfg); + if (rc) FAIL(rc); + + if ((rc = fnet_new(&model, &inA_net))) FAIL(rc); if ((rc = fnet_add_port(&model, inA_net, iob_inA_y, iob_inA_x, DEV_IOB, iob_inA_type_idx, IOB_OUT_I))) FAIL(rc); @@ -79,9 +109,8 @@ int main(int argc, char** argv) if ((rc = fnet_add_port(&model, out_net, iob_out_y, iob_out_x, DEV_IOB, iob_out_type_idx, IOB_IN_O))) FAIL(rc); if ((rc = fnet_autoroute(&model, out_net))) FAIL(rc); +#endif - if ((rc = write_floorplan(stdout, &model, FP_DEFAULT))) FAIL(rc); - return EXIT_SUCCESS; -fail: - return rc; + write_floorplan(stdout, &model, FP_DEFAULT); + return fpga_free_model(&model); } diff --git a/libs/control.c b/libs/control.c index ddf2731..365b763 100644 --- a/libs/control.c +++ b/libs/control.c @@ -163,7 +163,7 @@ const char* fpga_iob_sitename(struct fpga_model* model, int y, int x, if (y == TOP_OUTER_ROW) { for (i = 0; i < sizeof(xc6slx9_iob_top)/sizeof(xc6slx9_iob_top[0]); i++) { - if (xc6slx9_iob_right[i].xy == x) { + if (xc6slx9_iob_top[i].xy == x) { if (idx < 0 || idx > 3) return 0; return xc6slx9_iob_top[i].name[idx]; } @@ -798,6 +798,60 @@ fail: return rc; } +int fdev_iob_IMUX(struct fpga_model* model, int y, int x, + int type_idx, int mux) +{ + struct fpga_device* dev; + int rc; + + dev = fdev_p(model, y, x, DEV_IOB, type_idx); + if (!dev) FAIL(EINVAL); + rc = reset_required_pins(dev); + if (rc) FAIL(rc); + + dev->u.iob.I_mux = mux; + dev->instantiated = 1; + return 0; +fail: + return rc; +} + +int fdev_iob_slew(struct fpga_model* model, int y, int x, + int type_idx, int slew) +{ + struct fpga_device* dev; + int rc; + + dev = fdev_p(model, y, x, DEV_IOB, type_idx); + if (!dev) FAIL(EINVAL); + rc = reset_required_pins(dev); + if (rc) FAIL(rc); + + dev->u.iob.slew = slew; + dev->instantiated = 1; + return 0; +fail: + return rc; +} + +int fdev_iob_drive(struct fpga_model* model, int y, int x, + int type_idx, int drive_strength) +{ + struct fpga_device* dev; + int rc; + + dev = fdev_p(model, y, x, DEV_IOB, type_idx); + if (!dev) FAIL(EINVAL); + rc = reset_required_pins(dev); + if (rc) FAIL(rc); + + dev->u.iob.drive_strength = drive_strength; + dev->instantiated = 1; + return 0; +fail: + return rc; +} + static void scan_lut_digits(const char* s, int* digits) { int i; diff --git a/libs/control.h b/libs/control.h index ce756cb..8068259 100644 --- a/libs/control.h +++ b/libs/control.h @@ -87,6 +87,12 @@ int fdev_iob_input(struct fpga_model* model, int y, int x, int type_idx, const char* io_std); int fdev_iob_output(struct fpga_model* model, int y, int x, int type_idx, const char* io_std); +int fdev_iob_IMUX(struct fpga_model* model, int y, int x, + int type_idx, int mux); +int fdev_iob_slew(struct fpga_model* model, int y, int x, + int type_idx, int slew); +int fdev_iob_drive(struct fpga_model* model, int y, int x, + int type_idx, int drive_strength); int fdev_set_required_pins(struct fpga_model* model, int y, int x, int type, int type_idx); diff --git a/libs/floorplan.c b/libs/floorplan.c index 4ce2064..d655f29 100644 --- a/libs/floorplan.c +++ b/libs/floorplan.c @@ -1051,6 +1051,10 @@ int write_floorplan(FILE* f, struct fpga_model* model, int flags) if (!(flags & FP_NO_HEADER)) printf_version(f); + if (model->rc) { + fprintf(f, "rc %i\n", model->rc); + FAIL(model->rc); + } rc = printf_devices(f, model, /*config_only*/ 1); if (rc) FAIL(rc); diff --git a/libs/model.h b/libs/model.h index 66b6722..bc66bd4 100644 --- a/libs/model.h +++ b/libs/model.h @@ -54,6 +54,8 @@ struct fpga_model { + int rc; // if rc != 0, all function calls will immediately return + int cfg_rows; char cfg_columns[512]; char cfg_left_wiring[1024], cfg_right_wiring[1024]; @@ -585,7 +587,8 @@ struct fpga_tile int fpga_build_model(struct fpga_model* model, int fpga_rows, const char* columns, const char* left_wiring, const char* right_wiring); -void fpga_free_model(struct fpga_model* model); +// returns model->rc (model itself will be memset to 0) +int fpga_free_model(struct fpga_model* model); const char* fpga_tiletype_str(enum fpga_tile_type type); diff --git a/libs/model_main.c b/libs/model_main.c index 67148f0..128b252 100644 --- a/libs/model_main.c +++ b/libs/model_main.c @@ -57,15 +57,19 @@ fail: return rc; } -void fpga_free_model(struct fpga_model* model) +int fpga_free_model(struct fpga_model* model) { - if (!model) return; + int rc; + + if (!model) return 0; + rc = model->rc; free_devices(model); free(model->tmp_str); strarray_free(&model->str); free(model->tiles); free_xc6_routing_bitpos(model->sw_bitpos); memset(model, 0, sizeof(*model)); + return rc; } static const char* fpga_ttstr[] = // tile type strings