diff --git a/autotest.c b/autotest.c index abbc449..12b1b02 100644 --- a/autotest.c +++ b/autotest.c @@ -23,6 +23,7 @@ struct test_state { int cmdline_skip; char cmdline_diff_exec[1024]; + int dry_run; struct fpga_model* model; // test filenames are: tmp_dir/autotest__.??? @@ -38,16 +39,18 @@ static int dump_file(const char* path) printf("\n"); 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); + if (!(f = fopen(path, "r"))) + printf("#E error opening %s\n", path); + else { + while (fgets(line, sizeof(line), f)) { + if (!strncmp(line, "--- ", 4) + || !strncmp(line, "+++ ", 4) + || !strncmp(line, "@@ ", 3)) + continue; + printf(line); + } + fclose(f); } - fclose(f); printf("O end dump %s\n", path); return 0; } @@ -66,9 +69,12 @@ static int diff_printf(struct test_state* tstate) FILE* dest_f = 0; int rc; + if (tstate->dry_run) { + printf("O Dry run, skipping diff %i.\n", tstate->next_diff_counter++); + return 0; + } if (tstate->cmdline_skip >= tstate->next_diff_counter) { - printf("O Skipping diff %i.\n", tstate->next_diff_counter); - tstate->next_diff_counter++; + printf("O Skipping diff %i.\n", tstate->next_diff_counter++); return 0; } @@ -101,6 +107,8 @@ static int diff_printf(struct test_state* tstate) if (rc) { printf("#E %s:%i system call '%s' failed with code %i, " "check %s.log\n", __FILE__, __LINE__, tmp, rc, path); + // ENOENT comes back when pressing ctrl-c + if (rc == ENOENT) EXIT(rc); // todo: report the error up so we can avoid adding a switch to the block list etc. } @@ -118,7 +126,6 @@ fail: // goal: configure logic devices in all supported variations static int test_logic_config(struct test_state* tstate) { - int a_to_d[] = { A6_LUT, B6_LUT, C6_LUT, D6_LUT }; int idx_enum[] = { DEV_LOGM, DEV_LOGX }; int y, x, i, j, k, rc; @@ -126,17 +133,53 @@ static int test_logic_config(struct test_state* tstate) x = 13; for (i = 0; i < sizeof(idx_enum)/sizeof(*idx_enum); i++) { - for (j = 0; j < sizeof(a_to_d)/sizeof(*a_to_d); j++) { + for (j = LUT_A; j <= LUT_D; j++) { + + // A1..A6 to A..D for (k = '1'; k <= '6'; k++) { rc = fdev_logic_set_lut(tstate->model, y, x, - idx_enum[i], a_to_d[j], pf("A%c", k), ZTERM); + idx_enum[i], j, 6, pf("A%c", k), ZTERM); + if (rc) FAIL(rc); + rc = fdev_set_required_pins(tstate->model, y, x, + DEV_LOGIC, idx_enum[i]); if (rc) FAIL(rc); + if (tstate->dry_run) + fdev_print_required_pins(tstate->model, + y, x, DEV_LOGIC, idx_enum[i]); rc = diff_printf(tstate); if (rc) FAIL(rc); - fdev_delete(tstate->model, y, x, DEV_LOGIC, idx_enum[i]); } + + // A1 to O6 to FF to AQ + rc = fdev_logic_set_lut(tstate->model, y, x, + idx_enum[i], j, 6, "A1", ZTERM); + if (rc) FAIL(rc); + rc = fdev_logic_FF(tstate->model, y, x, idx_enum[i], + j, MUX_O6, FF_SRINIT0); + if (rc) FAIL(rc); + rc = fdev_logic_sync(tstate->model, y, x, idx_enum[i], + SYNCATTR_ASYNC); + if (rc) FAIL(rc); + rc = fdev_logic_clk(tstate->model, y, x, idx_enum[i], + CLKINV_B); + if (rc) FAIL(rc); + rc = fdev_logic_ceused(tstate->model, y, x, idx_enum[i]); + if (rc) FAIL(rc); + rc = fdev_logic_srused(tstate->model, y, x, idx_enum[i]); + if (rc) FAIL(rc); + + rc = fdev_set_required_pins(tstate->model, y, x, + DEV_LOGIC, idx_enum[i]); + if (rc) FAIL(rc); + + if (tstate->dry_run) + fdev_print_required_pins(tstate->model, + y, x, DEV_LOGIC, idx_enum[i]); + rc = diff_printf(tstate); + if (rc) FAIL(rc); + fdev_delete(tstate->model, y, x, DEV_LOGIC, idx_enum[i]); } } return 0; @@ -269,6 +312,10 @@ static int test_logic_net_l2(struct test_state* tstate, int y, int x, if (m < *l2_done_len) continue; l2_done_list[(*l2_done_len)++] = set_l2.sw[l]; + if (tstate->dry_run) + printf("l2_done_list %s at %i\n", fpga_switch_print(tstate->model, + switch_to.dest_y, switch_to.dest_x, l2_done_list[(*l2_done_len)-1]), + (*l2_done_len)-1); // we did the l1 switches in an earlier round, but have to // redo them before every l2 switch to make a clean diff @@ -305,7 +352,7 @@ static int test_logic_net_l1(struct test_state* tstate, int y, int x, rc = fdev_set_required_pins(tstate->model, y, x, type, type_idx); if (rc) FAIL(rc); - if (dbg) + if (tstate->dry_run) fdev_print_required_pins(tstate->model, y, x, type, type_idx); dev = fdev_p(tstate->model, y, x, type, type_idx); @@ -320,7 +367,7 @@ static int test_logic_net_l1(struct test_state* tstate, int y, int x, if (j < *done_pinw_len) continue; done_pinw_list[(*done_pinw_len)++] = dev->pinw[dev->pinw_req_for_cfg[i]]; - + from_to = (i < dev->pinw_req_in) ? SW_TO : SW_FROM; switch_to.yx_req = YX_ROUTING_TILE; switch_to.flags = SWTO_YX_DEF; @@ -331,7 +378,7 @@ static int test_logic_net_l1(struct test_state* tstate, int y, int x, switch_to.from_to = from_to; rc = fpga_switch_to_yx(&switch_to); if (rc) FAIL(rc); - if (dbg) + if (tstate->dry_run) printf_switch_to_result(&switch_to); rc = fpga_swset_fromto(tstate->model, switch_to.dest_y, @@ -356,7 +403,7 @@ static int test_logic_net_l1(struct test_state* tstate, int y, int x, set_l1.sw[j], NO_SWITCH); if (rc) FAIL(rc); done_sw_list[(*done_sw_len)++] = set_l1.sw[j]; - if (dbg) + if (tstate->dry_run) printf("done_list %s at %i\n", fpga_switch_print(tstate->model, switch_to.dest_y, switch_to.dest_x, set_l1.sw[j]), (*done_sw_len)-1); @@ -368,11 +415,10 @@ fail: } // goal: use all switches in a routing switchbox -static int test_logic_routing_switches(struct test_state* tstate) +static int test_logic_switches(struct test_state* tstate) { - int a_to_d[] = { A6_LUT, B6_LUT, C6_LUT, D6_LUT }; int idx_enum[] = { DEV_LOGM, DEV_LOGX }; - int y, x, i, j, k, rc; + int y, x, i, j, k, r, rc; swidx_t done_sw_list[MAX_SWITCHBOX_SIZE]; int done_sw_len; str16_t done_pinw_list[2000]; @@ -381,38 +427,68 @@ static int test_logic_routing_switches(struct test_state* tstate) y = 68; x = 13; - // first make one round over all configs with single-level nets only. - done_pinw_len = 0; done_sw_len = 0; - for (i = 0; i < sizeof(idx_enum)/sizeof(*idx_enum); i++) { - for (j = 0; j < sizeof(a_to_d)/sizeof(*a_to_d); j++) { - for (k = '1'; k <= '6'; k++) { + for (r = 0; r <= 1; r++) { + // two rounds: + // r == 0: round over all configs with single-level nets only + // r == 1: second round with two-level nets + + done_pinw_len = 0; // reset done pinwires for each round + + for (i = 0; i < sizeof(idx_enum)/sizeof(*idx_enum); i++) { + for (j = LUT_A; j <= LUT_D; j++) { + + // A1-A6 to A (same for lut B-D) + for (k = '1'; k <= '6'; k++) { + rc = fdev_logic_set_lut(tstate->model, y, x, + idx_enum[i], j, 6, pf("A%c", k), ZTERM); + if (rc) FAIL(rc); + rc = fdev_logic_out_used(tstate->model, y, x, + idx_enum[i], j); + if (rc) FAIL(rc); + + if (!r) + rc = test_logic_net_l1(tstate, y, x, DEV_LOGIC, + idx_enum[i], done_pinw_list, &done_pinw_len, + done_sw_list, &done_sw_len); + else + rc = test_logic_net_l2(tstate, y, x, DEV_LOGIC, + idx_enum[i], done_pinw_list, &done_pinw_len, + done_sw_list, &done_sw_len); + if (rc) FAIL(rc); + fdev_delete(tstate->model, y, x, DEV_LOGIC, idx_enum[i]); + } + + // A1->O6->FF->AQ (same for lut B-D) rc = fdev_logic_set_lut(tstate->model, y, x, - idx_enum[i], a_to_d[j], pf("A%c", k), ZTERM); + idx_enum[i], j, 6, "A1", ZTERM); if (rc) FAIL(rc); - - rc = test_logic_net_l1(tstate, y, x, DEV_LOGIC, - idx_enum[i], done_pinw_list, &done_pinw_len, - done_sw_list, &done_sw_len); + rc = fdev_logic_FF(tstate->model, y, x, idx_enum[i], + j, MUX_O6, FF_SRINIT0); if (rc) FAIL(rc); - fdev_delete(tstate->model, y, x, DEV_LOGIC, idx_enum[i]); - } - } - - } - - // second round with two-level nets - done_pinw_len = 0; // reset done pinwires - for (i = 0; i < sizeof(idx_enum)/sizeof(*idx_enum); i++) { - for (j = 0; j < sizeof(a_to_d)/sizeof(*a_to_d); j++) { - for (k = '1'; k <= '6'; k++) { - rc = fdev_logic_set_lut(tstate->model, y, x, - idx_enum[i], a_to_d[j], pf("A%c", k), ZTERM); + rc = fdev_logic_sync(tstate->model, y, x, idx_enum[i], + SYNCATTR_ASYNC); if (rc) FAIL(rc); - - rc = test_logic_net_l2(tstate, y, x, DEV_LOGIC, - idx_enum[i], done_pinw_list, &done_pinw_len, - done_sw_list, &done_sw_len); + rc = fdev_logic_clk(tstate->model, y, x, idx_enum[i], + CLKINV_B); + if (rc) FAIL(rc); + rc = fdev_logic_ceused(tstate->model, y, x, idx_enum[i]); + if (rc) FAIL(rc); + rc = fdev_logic_srused(tstate->model, y, x, idx_enum[i]); + if (rc) FAIL(rc); + + rc = fdev_set_required_pins(tstate->model, y, x, + DEV_LOGIC, idx_enum[i]); + if (rc) FAIL(rc); + + if (!r) + rc = test_logic_net_l1(tstate, y, x, DEV_LOGIC, + idx_enum[i], done_pinw_list, &done_pinw_len, + done_sw_list, &done_sw_len); + else + rc = test_logic_net_l2(tstate, y, x, DEV_LOGIC, + idx_enum[i], done_pinw_list, &done_pinw_len, + done_sw_list, &done_sw_len); if (rc) FAIL(rc); fdev_delete(tstate->model, y, x, DEV_LOGIC, idx_enum[i]); } @@ -431,7 +507,8 @@ static void printf_help(const char* argv_0, const char** available_tests) "fpgatools automatic test suite\n" "\n" "Usage: %s [--test=] [--diff=] [--skip=]\n" - "Default diff executable: " DEFAULT_DIFF_EXEC "\n", argv_0); + " %*s [--dry-run]\n" + "Default diff executable: " DEFAULT_DIFF_EXEC "\n", argv_0, (int) strlen(argv_0), ""); if (available_tests) { int i = 0; @@ -452,7 +529,7 @@ int main(int argc, char** argv) char param[1024], cmdline_test[1024]; int i, param_skip, rc; const char* available_tests[] = - { "logic_cfg", "routing_sw", 0 }; + { "logic_cfg", "logic_sw", 0 }; // flush after every line is better for the autotest // output, tee, etc. @@ -472,6 +549,7 @@ int main(int argc, char** argv) tstate.cmdline_skip = -1; tstate.cmdline_diff_exec[0] = 0; cmdline_test[0] = 0; + tstate.dry_run = -1; for (i = 1; i < argc; i++) { memset(param, 0, sizeof(param)); if (sscanf(argv[i], "--test=%1023c", param) == 1) { @@ -499,6 +577,10 @@ int main(int argc, char** argv) tstate.cmdline_skip = param_skip; continue; } + if (!strcmp(argv[i], "--dry-run")) { + tstate.dry_run = 1; + continue; + } printf_help(argv[0], available_tests); return EINVAL; } @@ -520,6 +602,8 @@ int main(int argc, char** argv) strcpy(tstate.cmdline_diff_exec, DEFAULT_DIFF_EXEC); if (tstate.cmdline_skip == -1) tstate.cmdline_skip = 0; + if (tstate.dry_run == -1) + tstate.dry_run = 0; // // test @@ -532,6 +616,7 @@ int main(int argc, char** argv) printf("O Test: %s\n", cmdline_test); printf("O Diff: %s\n", tstate.cmdline_diff_exec); printf("O Skip: %i\n", tstate.cmdline_skip); + printf("O Dry run: %i\n", tstate.dry_run); printf("\n"); printf("O Time measured in seconds from 0.\n"); g_start_time = time(0); @@ -556,13 +641,13 @@ int main(int argc, char** argv) rc = test_logic_config(&tstate); if (rc) FAIL(rc); } - if (!strcmp(cmdline_test, "routing_sw")) { - rc = test_logic_routing_switches(&tstate); + if (!strcmp(cmdline_test, "logic_sw")) { + rc = test_logic_switches(&tstate); if (rc) FAIL(rc); } - // test_iob_config - // test_iologic_routing_switches + // iob_sw: test_iob_switches + // test_iologic_switches #if 0 // test_swchain: diff --git a/bit_frames.c b/bit_frames.c index 087c4d9..907ac24 100644 --- a/bit_frames.c +++ b/bit_frames.c @@ -193,7 +193,7 @@ static int extract_logic(struct fpga_model* model, struct fpga_bits* bits) lut_str = lut2bool(u64, 64, &logic_base, /*flip_b0*/ 1); } if (*lut_str) { rc = fdev_logic_set_lut(model, y, x, DEV_LOGM, - A6_LUT, lut_str, ZTERM); + LUT_A, 6, lut_str, ZTERM); if (rc) FAIL(rc); *(uint32_t*)(u8_p+24*FRAME_SIZE+byte_off+4) = 0; *(uint32_t*)(u8_p+25*FRAME_SIZE+byte_off+4) = 0; @@ -207,7 +207,7 @@ static int extract_logic(struct fpga_model* model, struct fpga_bits* bits) lut_str = lut2bool(u64, 64, &logic_base, /*flip_b0*/ 1); } if (*lut_str) { rc = fdev_logic_set_lut(model, y, x, DEV_LOGM, - B6_LUT, lut_str, ZTERM); + LUT_B, 6, lut_str, ZTERM); if (rc) FAIL(rc); *(uint32_t*)(u8_p+21*FRAME_SIZE+byte_off+4) = 0; *(uint32_t*)(u8_p+22*FRAME_SIZE+byte_off+4) = 0; @@ -221,7 +221,7 @@ static int extract_logic(struct fpga_model* model, struct fpga_bits* bits) lut_str = lut2bool(u64, 64, &logic_base, /*flip_b0*/ 1); } if (*lut_str) { rc = fdev_logic_set_lut(model, y, x, DEV_LOGM, - C6_LUT, lut_str, ZTERM); + LUT_C, 6, lut_str, ZTERM); if (rc) FAIL(rc); *(uint32_t*)(u8_p+24*FRAME_SIZE+byte_off) = 0; *(uint32_t*)(u8_p+25*FRAME_SIZE+byte_off) = 0; @@ -235,7 +235,7 @@ static int extract_logic(struct fpga_model* model, struct fpga_bits* bits) lut_str = lut2bool(u64, 64, &logic_base, /*flip_b0*/ 1); } if (*lut_str) { rc = fdev_logic_set_lut(model, y, x, DEV_LOGM, - D6_LUT, lut_str, ZTERM); + LUT_D, 6, lut_str, ZTERM); if (rc) FAIL(rc); *(uint32_t*)(u8_p+21*FRAME_SIZE+byte_off) = 0; *(uint32_t*)(u8_p+22*FRAME_SIZE+byte_off) = 0; @@ -271,7 +271,7 @@ static int extract_logic(struct fpga_model* model, struct fpga_bits* bits) lut_str = lut2bool(u64, 64, &logic_base, /*flip_b0*/ 0); } if (*lut_str) { rc = fdev_logic_set_lut(model, y, x, DEV_LOGX, - A6_LUT, lut_str, ZTERM); + LUT_A, 6, lut_str, ZTERM); if (rc) FAIL(rc); *(uint32_t*)(u8_p+27*FRAME_SIZE+byte_off+4) = 0; *(uint32_t*)(u8_p+28*FRAME_SIZE+byte_off+4) = 0; @@ -282,7 +282,7 @@ static int extract_logic(struct fpga_model* model, struct fpga_bits* bits) lut_str = lut2bool(u64, 64, &logic_base, /*flip_b0*/ 0); } if (*lut_str) { rc = fdev_logic_set_lut(model, y, x, DEV_LOGX, - B6_LUT, lut_str, ZTERM); + LUT_B, 6, lut_str, ZTERM); *(uint32_t*)(u8_p+29*FRAME_SIZE+byte_off+4) = 0; *(uint32_t*)(u8_p+30*FRAME_SIZE+byte_off+4) = 0; } @@ -292,7 +292,7 @@ static int extract_logic(struct fpga_model* model, struct fpga_bits* bits) lut_str = lut2bool(u64, 64, &logic_base, /*flip_b0*/ 0); } if (*lut_str) { rc = fdev_logic_set_lut(model, y, x, DEV_LOGX, - C6_LUT, lut_str, ZTERM); + LUT_C, 6, lut_str, ZTERM); *(uint32_t*)(u8_p+27*FRAME_SIZE+byte_off) = 0; *(uint32_t*)(u8_p+28*FRAME_SIZE+byte_off) = 0; } @@ -302,7 +302,7 @@ static int extract_logic(struct fpga_model* model, struct fpga_bits* bits) lut_str = lut2bool(u64, 64, &logic_base, /*flip_b0*/ 0); } if (*lut_str) { rc = fdev_logic_set_lut(model, y, x, DEV_LOGX, - D6_LUT, lut_str, ZTERM); + LUT_D, 6, lut_str, ZTERM); *(uint32_t*)(u8_p+29*FRAME_SIZE+byte_off) = 0; *(uint32_t*)(u8_p+30*FRAME_SIZE+byte_off) = 0; } diff --git a/control.c b/control.c index fbdff6a..8cdeb37 100644 --- a/control.c +++ b/control.c @@ -359,6 +359,11 @@ void fdev_print_required_pins(struct fpga_model* model, int y, int x, dev = fdev_p(model, y, x, type, type_idx); if (!dev) { HERE(); return; } + // We don't want to reset or write the required pins in this + // function because it is mainly used for debugging purposes + // and the caller should not suddenly be working with old + // required pins when the print() function is not called. + printf("y%02i x%02i %s %i inpin", y, x, fdev_type2str(type), type_idx); if (!dev->pinw_req_in) printf(" -\n"); @@ -397,13 +402,11 @@ static void add_req_outpin(struct fpga_device* dev, pinw_idx_t pinw_i) dev->pinw_req_total++; } -#define MAX_LUT_LEN 512 - int fdev_logic_set_lut(struct fpga_model* model, int y, int x, int type_idx, - int which_lut, const char* lut_str, int lut_len) + int lut_a2d, int lut_5or6, const char* lut_str, int lut_len) { struct fpga_device* dev; - char** luts; + char** lut_ptr; int rc; dev = fdev_p(model, y, x, DEV_LOGIC, type_idx); @@ -411,38 +414,125 @@ int fdev_logic_set_lut(struct fpga_model* model, int y, int x, int type_idx, rc = reset_required_pins(dev); if (rc) FAIL(rc); - luts = dev->u.logic.luts; - if (!luts[which_lut]) { - luts[which_lut] = malloc(MAX_LUT_LEN); - if (!luts[which_lut]) { - OUT_OF_MEM(); - return -1; - } + lut_ptr = (lut_5or6 == 5) + ? &dev->u.logic.a2d[lut_a2d].lut5 + : &dev->u.logic.a2d[lut_a2d].lut6; + if (*lut_ptr == 0) { + *lut_ptr = malloc(MAX_LUT_LEN); + if (!(*lut_ptr)) FAIL(ENOMEM); } if (lut_len == ZTERM) lut_len = strlen(lut_str); - memcpy(luts[which_lut], lut_str, lut_len); - luts[which_lut][lut_len] = 0; + memcpy(*lut_ptr, lut_str, lut_len); + (*lut_ptr)[lut_len] = 0; - switch (which_lut) { - case A5_LUT: - case A6_LUT: - dev->u.logic.A_used = 1; - break; - case B5_LUT: - case B6_LUT: - dev->u.logic.B_used = 1; - break; - case C5_LUT: - case C6_LUT: - dev->u.logic.C_used = 1; - break; - case D5_LUT: - case D6_LUT: - dev->u.logic.D_used = 1; - break; - default: FAIL(EINVAL); - } + dev->instantiated = 1; + return 0; +fail: + return rc; +} +int fdev_logic_out_used(struct fpga_model* model, int y, int x, int type_idx, + int lut_a2d) +{ + struct fpga_device* dev; + int rc; + + dev = fdev_p(model, y, x, DEV_LOGIC, type_idx); + if (!dev) FAIL(EINVAL); + rc = reset_required_pins(dev); + if (rc) FAIL(rc); + + dev->u.logic.a2d[lut_a2d].used = 1; + dev->instantiated = 1; + return 0; +fail: + return rc; +} + +int fdev_logic_FF(struct fpga_model* model, int y, int x, int type_idx, + int lut_a2d, int ff_mux, int srinit) +{ + struct fpga_device* dev; + int rc; + + dev = fdev_p(model, y, x, DEV_LOGIC, type_idx); + if (!dev) FAIL(EINVAL); + rc = reset_required_pins(dev); + if (rc) FAIL(rc); + + dev->u.logic.a2d[lut_a2d].ff = FF_FF; + dev->u.logic.a2d[lut_a2d].ff_mux = ff_mux; + dev->u.logic.a2d[lut_a2d].ff_srinit = srinit; + dev->instantiated = 1; + return 0; +fail: + return rc; +} + +int fdev_logic_clk(struct fpga_model* model, int y, int x, int type_idx, + int clk) +{ + struct fpga_device* dev; + int rc; + + dev = fdev_p(model, y, x, DEV_LOGIC, type_idx); + if (!dev) FAIL(EINVAL); + rc = reset_required_pins(dev); + if (rc) FAIL(rc); + + dev->u.logic.clk_inv = clk; + dev->instantiated = 1; + return 0; +fail: + return rc; +} + +int fdev_logic_sync(struct fpga_model* model, int y, int x, int type_idx, + int sync_attr) +{ + struct fpga_device* dev; + int rc; + + dev = fdev_p(model, y, x, DEV_LOGIC, type_idx); + if (!dev) FAIL(EINVAL); + rc = reset_required_pins(dev); + if (rc) FAIL(rc); + + dev->u.logic.sync_attr = sync_attr; + dev->instantiated = 1; + return 0; +fail: + return rc; +} + +int fdev_logic_ceused(struct fpga_model* model, int y, int x, int type_idx) +{ + struct fpga_device* dev; + int rc; + + dev = fdev_p(model, y, x, DEV_LOGIC, type_idx); + if (!dev) FAIL(EINVAL); + rc = reset_required_pins(dev); + if (rc) FAIL(rc); + + dev->u.logic.ce_used = 1; + dev->instantiated = 1; + return 0; +fail: + return rc; +} + +int fdev_logic_srused(struct fpga_model* model, int y, int x, int type_idx) +{ + struct fpga_device* dev; + int rc; + + dev = fdev_p(model, y, x, DEV_LOGIC, type_idx); + if (!dev) FAIL(EINVAL); + rc = reset_required_pins(dev); + if (rc) FAIL(rc); + + dev->u.logic.sr_used = 1; dev->instantiated = 1; return 0; fail: @@ -474,23 +564,38 @@ int fdev_set_required_pins(struct fpga_model* model, int y, int x, int type, rc = reset_required_pins(dev); if (rc) FAIL(rc); if (type == DEV_LOGIC) { - if (dev->u.logic.A_used) - add_req_outpin(dev, LO_A); - if (dev->u.logic.B_used) - add_req_outpin(dev, LO_B); - if (dev->u.logic.C_used) - add_req_outpin(dev, LO_C); - if (dev->u.logic.D_used) - add_req_outpin(dev, LO_D); - for (i = 0; i < sizeof(dev->u.logic.luts) - /sizeof(dev->u.logic.luts[0]); i++) { - if (!dev->u.logic.luts[i]) continue; - scan_lut_digits(dev->u.logic.luts[i], digits); - for (j = 0; j < 6; j++) { - // i/2 because luts order is A5-A6 B5-B6, etc. - if (digits[j]) - add_req_inpin(dev, - LI_A1+(i/2)*6+j); + if (dev->u.logic.clk_inv) + add_req_inpin(dev, LI_CLK); + if (dev->u.logic.ce_used) + add_req_inpin(dev, LI_CE); + if (dev->u.logic.sr_used) + add_req_inpin(dev, LI_SR); + for (i = LUT_A; i <= LUT_D; i++) { + if (dev->u.logic.a2d[i].used) { + // LO_A..LO_D are in sequence + add_req_outpin(dev, LO_A+i); + } + if (dev->u.logic.a2d[i].ff) { + // LO_AQ..LO_DQ are in sequence + add_req_outpin(dev, LO_AQ+i); + } + if (dev->u.logic.a2d[i].ff_mux == MUX_X) { + // LI_AX..LI_DX are in sequence + add_req_inpin(dev, LI_AX+i); + } + if (dev->u.logic.a2d[i].lut6) { + scan_lut_digits(dev->u.logic.a2d[i].lut6, digits); + for (j = 0; j < 6; j++) { + if (!digits[j]) continue; + add_req_inpin(dev, LI_A1+i*6+j); + } + } + if (dev->u.logic.a2d[i].lut5) { + scan_lut_digits(dev->u.logic.a2d[i].lut5, digits); + for (j = 0; j < 6; j++) { + if (!digits[j]) continue; + add_req_inpin(dev, LI_A1+i*6+j); + } } } } @@ -512,10 +617,11 @@ void fdev_delete(struct fpga_model* model, int y, int x, int type, int type_idx) dev->pinw_req_total = 0; dev->pinw_req_in = 0; if (dev->type == DEV_LOGIC) { - for (i = 0; i < sizeof(dev->u.logic.luts) - /sizeof(dev->u.logic.luts[0]); i++) { - free(dev->u.logic.luts[i]); - dev->u.logic.luts[i] = 0; + for (i = LUT_A; i <= LUT_D; i++) { + free(dev->u.logic.a2d[i].lut6); + dev->u.logic.a2d[i].lut6 = 0; + free(dev->u.logic.a2d[i].lut5); + dev->u.logic.a2d[i].lut5 = 0; } } dev->instantiated = 0; diff --git a/control.h b/control.h index 61fadeb..52567c3 100644 --- a/control.h +++ b/control.h @@ -42,8 +42,24 @@ const char* fdev_pinw_idx2str(int devtype, pinw_idx_t idx); // we are in a XM or XL column. const char* fdev_logic_pinstr(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, - int which_lut, const char* lut_str, int lut_len); + int lut_a2d, int lut_5or6, const char* lut_str, int lut_len); +int fdev_logic_out_used(struct fpga_model* model, int y, int x, int type_idx, + int lut_a2d); +// ff_mux is MUX_O6 or MUX_X +// srinit is FF_SRINIT0 or FF_SRINIT1 +int fdev_logic_FF(struct fpga_model* model, int y, int x, int type_idx, + int lut_a2d, int ff_mux, int srinit); +// clk is CLKINV_B or CLKINV_CLK +int fdev_logic_clk(struct fpga_model* model, int y, int x, int type_idx, + int clk); +// sync is SYNCATTR_SYNC or SYNCATTR_ASYNC +int fdev_logic_sync(struct fpga_model* model, int y, int x, int type_idx, + int sync_attr); +int fdev_logic_ceused(struct fpga_model* model, int y, int x, int type_idx); +int fdev_logic_srused(struct fpga_model* model, int y, int x, int type_idx); + int fdev_set_required_pins(struct fpga_model* model, int y, int x, int type, int type_idx); void fdev_print_required_pins(struct fpga_model* model, int y, int x, diff --git a/floorplan.c b/floorplan.c index 097e9ea..06f6f7f 100644 --- a/floorplan.c +++ b/floorplan.c @@ -287,14 +287,13 @@ inst_2: return 2; } -static const char* s_fplut_str[] = FP_LUT_STR; - static int printf_LOGIC(FILE* f, struct fpga_model* model, int y, int x, int config_only) { struct fpga_tile* tile; + struct fpgadev_logic* cfg; char pref[256]; - int type_count, i, j; + int type_count, i, j, rc; tile = YX_TILE(model, y, x); type_count = 0; @@ -323,71 +322,253 @@ static int printf_LOGIC(FILE* f, struct fpga_model* model, default: EXIT(1); } } - if (tile->devs[i].u.logic.A_used) - fprintf(f, "%s A_used\n", pref); - if (tile->devs[i].u.logic.B_used) - fprintf(f, "%s B_used\n", pref); - if (tile->devs[i].u.logic.C_used) - fprintf(f, "%s C_used\n", pref); - if (tile->devs[i].u.logic.D_used) - fprintf(f, "%s D_used\n", pref); - { - for (j = 0; j < sizeof(tile->devs[i].u.logic.luts) - / sizeof(tile->devs[i].u.logic.luts[0]); j++) { - if (tile->devs[i].u.logic.luts[j] - && tile->devs[i].u.logic.luts[j][0]) - fprintf(f, "%s %s %s\n", pref, - s_fplut_str[j], - tile->devs[i].u.logic.luts[j]); + cfg = &tile->devs[i].u.logic; + for (j = LUT_A; j <= LUT_D; j++) { + if (cfg->a2d[j].used) + fprintf(f, "%s %c_used\n", pref, 'A'+j); + if (cfg->a2d[j].lut6 && cfg->a2d[j].lut6[0]) + fprintf(f, "%s %c6_lut %s\n", pref, 'A'+j, + cfg->a2d[j].lut6); + if (cfg->a2d[j].lut5 && cfg->a2d[j].lut5[0]) + fprintf(f, "%s %c5_lut %s\n", pref, 'A'+j, + cfg->a2d[j].lut5); + + switch (cfg->a2d[j].ff_mux) { + case MUX_O6: + fprintf(f, "%s %c_ffmux O6\n", pref, 'A'+j); + break; + case MUX_O5: + fprintf(f, "%s %c_ffmux O5\n", pref, 'A'+j); + break; + case MUX_X: + fprintf(f, "%s %c_ffmux X\n", pref, 'A'+j); + break; + case MUX_F7: + fprintf(f, "%s %c_ffmux F7\n", pref, 'A'+j); + break; + case MUX_CY: + fprintf(f, "%s %c_ffmux CY\n", pref, 'A'+j); + break; + case MUX_XOR: + fprintf(f, "%s %c_ffmux XOR\n", pref, 'A'+j); + break; + case 0: break; default: FAIL(EINVAL); } + switch (cfg->a2d[j].ff_srinit) { + case FF_SRINIT0: + fprintf(f, "%s %c_ffsrinit 0\n", pref, 'A'+j); + break; + case FF_SRINIT1: + fprintf(f, "%s %c_ffsrinit 1\n", pref, 'A'+j); + break; + case 0: break; default: FAIL(EINVAL); + } + switch (cfg->a2d[j].out_mux) { + case MUX_O6: + fprintf(f, "%s %c_outmux O6\n", pref, 'A'+j); + break; + case MUX_O5: + fprintf(f, "%s %c_outmux O5\n", pref, 'A'+j); + break; + case MUX_5Q: + fprintf(f, "%s %c_outmux 5Q\n", pref, 'A'+j); + break; + case MUX_F7: + fprintf(f, "%s %c_outmux F7\n", pref, 'A'+j); + break; + case MUX_CY: + fprintf(f, "%s %c_outmux CY\n", pref, 'A'+j); + break; + case MUX_XOR: + fprintf(f, "%s %c_outmux XOR\n", pref, 'A'+j); + break; + case 0: break; default: FAIL(EINVAL); + } + switch (cfg->a2d[j].ff) { + case FF_OR2L: + fprintf(f, "%s %c_ff OR2L\n", pref, 'A'+j); + break; + case FF_AND2L: + fprintf(f, "%s %c_ff AND2L\n", pref, 'A'+j); + break; + case FF_LATCH: + fprintf(f, "%s %c_ff LATCH\n", pref, 'A'+j); + break; + case FF_FF: + fprintf(f, "%s %c_ff FF\n", pref, 'A'+j); + break; + case 0: break; default: FAIL(EINVAL); + } + } + switch (cfg->clk_inv) { + case CLKINV_B: + fprintf(f, "%s clk CLK_B\n", pref); + break; + case CLKINV_CLK: + fprintf(f, "%s clk CLK\n", pref); + break; + case 0: break; default: FAIL(EINVAL); + } + switch (cfg->sync_attr) { + case SYNCATTR_SYNC: + fprintf(f, "%s sync SYNC\n", pref); + break; + case SYNCATTR_ASYNC: + fprintf(f, "%s sync ASYNC\n", pref); + break; + case 0: break; default: FAIL(EINVAL); + } + if (cfg->ce_used) + fprintf(f, "%s ce_used\n", pref); + if (cfg->sr_used) + fprintf(f, "%s sr_used\n", pref); + switch (cfg->we_mux) { + case WEMUX_WE: + fprintf(f, "%s wemux WE\n", pref); + break; + case WEMUX_CE: + fprintf(f, "%s wemux CE\n", pref); + break; + case 0: break; default: FAIL(EINVAL); } } return 0; +fail: + return rc; } static int read_LOGIC_attr(struct fpga_model* model, int y, int x, int type_idx, const char* w1, int w1_len, const char* w2, int w2_len) { struct fpga_device* dev; + char cmp_str[128]; int i, rc; dev = fdev_p(model, y, x, DEV_LOGIC, type_idx); if (!dev) { HERE(); return 0; } // First the one-word attributes. - if (!str_cmp(w1, w1_len, "A_used", ZTERM)) { - dev->u.logic.A_used = 1; + for (i = LUT_A; i <= LUT_D; i++) { + snprintf(cmp_str, sizeof(cmp_str), "%c_used", 'A'+i); + if (!str_cmp(w1, w1_len, cmp_str, ZTERM)) { + dev->u.logic.a2d[i].used = 1; + goto inst_1; + } + } + if (!str_cmp(w1, w1_len, "ce_used", ZTERM)) { + dev->u.logic.ce_used = 1; goto inst_1; } - if (!str_cmp(w1, w1_len, "B_used", ZTERM)) { - dev->u.logic.B_used = 1; - goto inst_1; - } - if (!str_cmp(w1, w1_len, "C_used", ZTERM)) { - dev->u.logic.C_used = 1; - goto inst_1; - } - if (!str_cmp(w1, w1_len, "D_used", ZTERM)) { - dev->u.logic.D_used = 1; + if (!str_cmp(w1, w1_len, "sr_used", ZTERM)) { + dev->u.logic.sr_used = 1; goto inst_1; } + // The remaining attributes all require 2 words. if (w2_len < 1) return 0; if (!str_cmp(w1, w1_len, "type", ZTERM)) return 2; // no reason for instantiation - for (i = 0; i < sizeof(dev->u.logic.luts)/sizeof(dev->u.logic.luts[0]); i++) { - if (!str_cmp(w1, w1_len, s_fplut_str[i], ZTERM)) { - rc = fdev_logic_set_lut(model, y, x, type_idx, i, w2, w2_len); + + for (i = LUT_A; i <= LUT_D; i++) { + snprintf(cmp_str, sizeof(cmp_str), "%c6_lut", 'A'+i); + if (!str_cmp(w1, w1_len, cmp_str, ZTERM)) { + rc = fdev_logic_set_lut(model, y, x, type_idx, i, 6, w2, w2_len); if (rc) return 0; goto inst_2; } + snprintf(cmp_str, sizeof(cmp_str), "%c5_lut", 'A'+i); + if (!str_cmp(w1, w1_len, cmp_str, ZTERM)) { + rc = fdev_logic_set_lut(model, y, x, type_idx, i, 5, w2, w2_len); + if (rc) return 0; + goto inst_2; + } + snprintf(cmp_str, sizeof(cmp_str), "%c_ffmux", 'A'+i); + if (!str_cmp(w1, w1_len, cmp_str, ZTERM)) { + if (!str_cmp(w2, w2_len, "O6", ZTERM)) + dev->u.logic.a2d[i].ff_mux = MUX_O6; + else if (!str_cmp(w2, w2_len, "O5", ZTERM)) + dev->u.logic.a2d[i].ff_mux = MUX_O5; + else if (!str_cmp(w2, w2_len, "X", ZTERM)) + dev->u.logic.a2d[i].ff_mux = MUX_X; + else if (!str_cmp(w2, w2_len, "F7", ZTERM)) + dev->u.logic.a2d[i].ff_mux = MUX_F7; + else if (!str_cmp(w2, w2_len, "CY", ZTERM)) + dev->u.logic.a2d[i].ff_mux = MUX_CY; + else if (!str_cmp(w2, w2_len, "XOR", ZTERM)) + dev->u.logic.a2d[i].ff_mux = MUX_XOR; + else return 0; + goto inst_2; + } + snprintf(cmp_str, sizeof(cmp_str), "%c_ffsrinit", 'A'+i); + if (!str_cmp(w1, w1_len, cmp_str, ZTERM)) { + if (!str_cmp(w2, w2_len, "0", ZTERM)) + dev->u.logic.a2d[i].ff_srinit = FF_SRINIT0; + else if (!str_cmp(w2, w2_len, "1", ZTERM)) + dev->u.logic.a2d[i].ff_srinit = FF_SRINIT1; + else return 0; + goto inst_2; + } + snprintf(cmp_str, sizeof(cmp_str), "%c_outmux", 'A'+i); + if (!str_cmp(w1, w1_len, cmp_str, ZTERM)) { + if (!str_cmp(w2, w2_len, "O6", ZTERM)) + dev->u.logic.a2d[i].out_mux = MUX_O6; + if (!str_cmp(w2, w2_len, "O5", ZTERM)) + dev->u.logic.a2d[i].out_mux = MUX_O5; + if (!str_cmp(w2, w2_len, "5Q", ZTERM)) + dev->u.logic.a2d[i].out_mux = MUX_5Q; + if (!str_cmp(w2, w2_len, "F7", ZTERM)) + dev->u.logic.a2d[i].out_mux = MUX_F7; + if (!str_cmp(w2, w2_len, "CY", ZTERM)) + dev->u.logic.a2d[i].out_mux = MUX_CY; + if (!str_cmp(w2, w2_len, "XOR", ZTERM)) + dev->u.logic.a2d[i].out_mux = MUX_XOR; + else return 0; + goto inst_2; + } + snprintf(cmp_str, sizeof(cmp_str), "%c_ff", 'A'+i); + if (!str_cmp(w1, w1_len, cmp_str, ZTERM)) { + if (!str_cmp(w2, w2_len, "OR2L", ZTERM)) + dev->u.logic.a2d[i].ff = FF_OR2L; + if (!str_cmp(w2, w2_len, "AND2L", ZTERM)) + dev->u.logic.a2d[i].ff = FF_AND2L; + if (!str_cmp(w2, w2_len, "LATCH", ZTERM)) + dev->u.logic.a2d[i].ff = FF_LATCH; + if (!str_cmp(w2, w2_len, "FF", ZTERM)) + dev->u.logic.a2d[i].ff = FF_FF; + else return 0; + goto inst_2; + } + } + if (!str_cmp(w1, w1_len, "clk", ZTERM)) { + if (!str_cmp(w2, w2_len, "CLK_B", ZTERM)) + dev->u.logic.clk_inv = CLKINV_B; + else if (!str_cmp(w2, w2_len, "CLK", ZTERM)) + dev->u.logic.clk_inv = CLKINV_CLK; + else return 0; + goto inst_2; + } + if (!str_cmp(w1, w1_len, "sync", ZTERM)) { + if (!str_cmp(w2, w2_len, "SYNC", ZTERM)) + dev->u.logic.sync_attr = SYNCATTR_SYNC; + else if (!str_cmp(w2, w2_len, "ASYNC", ZTERM)) + dev->u.logic.sync_attr = SYNCATTR_ASYNC; + else return 0; + goto inst_2; + } + if (!str_cmp(w1, w1_len, "wemux", ZTERM)) { + if (!str_cmp(w2, w2_len, "WE", ZTERM)) + dev->u.logic.we_mux = WEMUX_WE; + else if (!str_cmp(w2, w2_len, "CE", ZTERM)) + dev->u.logic.we_mux = WEMUX_CE; + else return 0; + goto inst_2; } return 0; inst_1: dev->instantiated = 1; return 1; inst_2: - dev->instantiated = 2; + dev->instantiated = 1; return 2; } diff --git a/model.h b/model.h index aaecb78..f7d41fc 100644 --- a/model.h +++ b/model.h @@ -338,6 +338,10 @@ typedef int dev_type_idx_t; #define NO_DEV -1 #define FPGA_DEV(model, y, x, dev_idx) (&YX_TILE(model, y, x)->devs[dev_idx]) +// +// logic device +// + // M and L device is always at type index 0, X device // is always at type index 1. #define DEV_LOGM 0 @@ -394,21 +398,41 @@ enum { // input: "AQ", "BQ", "CQ", "DQ", \ "COUT" } -// offsets into fpgadev_logic:luts[], also hardcoded in -// control.c:fdev_set_required_pins(), where we assume -// that div2 will lead to A-D -enum { A5_LUT = 0, A6_LUT, B5_LUT, B6_LUT, - C5_LUT, C6_LUT, D5_LUT, D6_LUT, NUM_LUTS }; -#define FP_LUT_STR \ - { "A5_lut", "A6_lut", "B5_lut", "B6_lut", \ - "C5_lut", "C6_lut", "D5_lut", "D6_lut" } +enum { LUT_A = 0, LUT_B, LUT_C, LUT_D }; // offset into a2d[] +enum { FF_SRINIT0 = 1, FF_SRINIT1 }; +enum { MUX_O6 = 1, MUX_O5, MUX_5Q, MUX_X, MUX_F7, MUX_CY, MUX_XOR }; +enum { FF_OR2L = 1, FF_AND2L, FF_LATCH, FF_FF }; +enum { CLKINV_B = 1, CLKINV_CLK }; +enum { SYNCATTR_SYNC = 1, SYNCATTR_ASYNC }; +enum { WEMUX_WE = 1, WEMUX_CE }; + +#define MAX_LUT_LEN 2048 + +struct fpgadev_logic_a2d +{ + int used; + char* lut6; + char* lut5; + int ff_mux; // O6, O5, X, F7, CY, XOR + int ff_srinit; // SRINIT0, SRINIT1 + int out_mux; // O6, O5, 5Q, F7, CY, XOR + int ff; // OR2L, AND2L, LATCH, FF +}; struct fpgadev_logic { - int A_used, B_used, C_used, D_used; - char* luts[NUM_LUTS]; + struct fpgadev_logic_a2d a2d[4]; + int clk_inv; // CLKINV_B, CLKINV_CLK + int sync_attr; // SYNCATTR_SYNC, SYNCATTR_ASYNC + int ce_used; + int sr_used; + int we_mux; // WEMUX_WE, WEMUX_CE }; +// +// iob device +// + enum { IOBM = 1, IOBS }; typedef char IOSTANDARD[32]; #define IO_LVCMOS33 "LVCMOS33" @@ -446,6 +470,10 @@ struct fpgadev_iob int out_term; }; +// +// fpga_device +// + typedef int pinw_idx_t; // index into pinw array struct fpga_device