diff --git a/autotest.c b/autotest.c index e5adffd..c27d916 100644 --- a/autotest.c +++ b/autotest.c @@ -125,70 +125,6 @@ fail: return rc; } -// goal: configure logic devices in all supported variations -static int test_logic_config(struct test_state* tstate) -{ - int idx_enum[] = { DEV_LOG_M_OR_L, DEV_LOG_X }; - int y, x, i, j, k, rc; - - y = 68; - x = 13; - - for (i = 0; i < sizeof(idx_enum)/sizeof(*idx_enum); i++) { - for (j = LUT_A; j <= LUT_D; j++) { - - // A1..A6 to A..D - for (k = '1'; k <= '6'; k++) { - rc = fdev_logic_a2d_lut(tstate->model, y, x, - 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_a2d_lut(tstate->model, y, x, - idx_enum[i], j, 6, "A1", ZTERM); - if (rc) FAIL(rc); - rc = fdev_logic_a2d_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_ce_used(tstate->model, y, x, idx_enum[i]); - if (rc) FAIL(rc); - rc = fdev_logic_sr_used(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; -fail: - return rc; -} - static int test_logic_net(struct test_state* tstate, int logic_y, int logic_x, int type_idx, pinw_idx_t port, const struct sw_set* logic_switch_set, int routing_y, int routing_x, swidx_t routing_sw1, swidx_t routing_sw2) @@ -1026,27 +962,26 @@ fail: return rc; } -static int test_lut(struct test_state* tstate, int y, int x, int type_idx, - int lut, const char* lut6, const char* lut5) +static int test_logic(struct test_state* tstate, int y, int x, int type_idx, + const struct fpgadev_logic* logic_cfg) { struct fpga_device* dev; net_idx_t pinw_nets[MAX_NUM_PINW]; - int i, rc; + int i, lut, rc; - if (tstate->dry_run) - printf("O lut6 '%s' lut5 '%s'\n", - lut6 ? lut6 : "-", lut5 ? lut5 : "-"); - if (lut6) { - rc = fdev_logic_a2d_lut(tstate->model, y, x, - type_idx, lut, 6, lut6, ZTERM); - if (rc) FAIL(rc); + if (tstate->dry_run) { + for (lut = LUT_A; lut <= LUT_D; lut++) { + if (!logic_cfg->a2d[lut].lut6 + && !logic_cfg->a2d[lut].lut5) + continue; + printf("O %c6_lut '%s' %c5_lut '%s'\n", + 'A'+lut, logic_cfg->a2d[lut].lut6 + ? logic_cfg->a2d[lut].lut6 : "-", + 'A'+lut, logic_cfg->a2d[lut].lut5 + ? logic_cfg->a2d[lut].lut5 : "-"); + } } - if (lut5) { - rc = fdev_logic_a2d_lut(tstate->model, y, x, - type_idx, lut, 5, lut5, ZTERM); - if (rc) FAIL(rc); - } - rc = fdev_set_required_pins(tstate->model, y, x, DEV_LOGIC, type_idx); + rc = fdev_logic_setconf(tstate->model, y, x, type_idx, logic_cfg); if (rc) FAIL(rc); if (tstate->dry_run) { fdev_print_required_pins(tstate->model, y, x, @@ -1090,6 +1025,90 @@ fail: return rc; } +static int test_logic_enum_precyinit(struct test_state* tstate, int y, int x, + int type_idx, const struct fpgadev_logic* logic_cfg) +{ + struct fpgadev_logic local_cfg = *logic_cfg; + int rc; + + rc = test_logic(tstate, y, x, type_idx, &local_cfg); + if (rc) FAIL(rc); + local_cfg.precyinit = PRECYINIT_0; + rc = test_logic(tstate, y, x, type_idx, &local_cfg); + if (rc) FAIL(rc); + local_cfg.precyinit = PRECYINIT_1; + rc = test_logic(tstate, y, x, type_idx, &local_cfg); + if (rc) FAIL(rc); + local_cfg.precyinit = PRECYINIT_AX; + rc = test_logic(tstate, y, x, type_idx, &local_cfg); + if (rc) FAIL(rc); + return 0; +fail: + return rc; +} + +static int test_logic_enum_srinit_clk_sync_ce_sr(struct test_state* tstate, int y, + int x, int type_idx, const struct fpgadev_logic* logic_cfg) +{ + struct fpgadev_logic local_cfg = *logic_cfg; + int lut, rc; + + for (lut = LUT_A; lut <= LUT_D; lut++) { + + if (!local_cfg.a2d[lut].ff_mux + && !local_cfg.a2d[lut].out_mux) + continue; + + if (local_cfg.a2d[lut].ff_mux) + local_cfg.a2d[lut].ff_srinit = FF_SRINIT0; + if (local_cfg.a2d[lut].out_mux == MUX_5Q) + local_cfg.a2d[lut].ff5_srinit = FF_SRINIT0; + local_cfg.clk_inv = CLKINV_CLK; + local_cfg.sync_attr = SYNCATTR_ASYNC; + local_cfg.ce_used = 0; + local_cfg.sr_used = 0; + + rc = test_logic(tstate, y, x, type_idx, &local_cfg); + if (rc) FAIL(rc); + + if (local_cfg.a2d[lut].ff_mux) { + local_cfg.a2d[lut].ff_srinit = FF_SRINIT1; + rc = test_logic(tstate, y, x, type_idx, &local_cfg); + if (rc) FAIL(rc); + local_cfg.a2d[lut].ff_srinit = FF_SRINIT0; + } + if (local_cfg.a2d[lut].out_mux == MUX_5Q) { + local_cfg.a2d[lut].ff5_srinit = FF_SRINIT1; + rc = test_logic(tstate, y, x, type_idx, &local_cfg); + if (rc) FAIL(rc); + local_cfg.a2d[lut].ff5_srinit = FF_SRINIT0; + } + + local_cfg.clk_inv = CLKINV_B; + rc = test_logic(tstate, y, x, type_idx, &local_cfg); + if (rc) FAIL(rc); + local_cfg.clk_inv = CLKINV_CLK; + + local_cfg.sync_attr = SYNCATTR_SYNC; + rc = test_logic(tstate, y, x, type_idx, &local_cfg); + if (rc) FAIL(rc); + local_cfg.sync_attr = SYNCATTR_ASYNC; + + local_cfg.ce_used = 1; + rc = test_logic(tstate, y, x, type_idx, &local_cfg); + if (rc) FAIL(rc); + local_cfg.ce_used = 0; + + local_cfg.sr_used = 1; + rc = test_logic(tstate, y, x, type_idx, &local_cfg); + if (rc) FAIL(rc); + local_cfg.sr_used = 0; + } + return 0; +fail: + return rc; +} + static int test_lut_encoding(struct test_state* tstate) { int idx_enum[] = { DEV_LOG_M_OR_L, DEV_LOG_X }; @@ -1097,8 +1116,9 @@ static int test_lut_encoding(struct test_state* tstate) // for the lut encoding, so it doesn't need separate testing. int x_enum[] = { /*xm*/ 13, /*xl*/ 39 }; int y, x_i, i, j, lut_str_len, rc; + struct fpgadev_logic logic_cfg; int type_i, lut; - char lut_str[128]; + char lut6_str[128], lut5_str[128]; tstate->diff_to_null = 1; @@ -1106,63 +1126,76 @@ static int test_lut_encoding(struct test_state* tstate) for (x_i = 0; x_i < sizeof(x_enum)/sizeof(*x_enum); x_i++) { for (type_i = 0; type_i < sizeof(idx_enum)/sizeof(*idx_enum); type_i++) { for (lut = LUT_A; lut <= LUT_D; lut++) { + memset(&logic_cfg, 0, sizeof(logic_cfg)); + logic_cfg.a2d[lut].lut6 = lut6_str; + logic_cfg.a2d[lut].out_used = 1; + // lut6 only - rc = test_lut(tstate, y, x_enum[x_i], idx_enum[type_i], - lut, "0", /*lut5*/ 0); + sprintf(lut6_str, "0"); + rc = test_logic(tstate, y, x_enum[x_i], idx_enum[type_i], + &logic_cfg); if (rc) FAIL(rc); - rc = test_lut(tstate, y, x_enum[x_i], idx_enum[type_i], - lut, "1", /*lut5*/ 0); + sprintf(lut6_str, "1"); + rc = test_logic(tstate, y, x_enum[x_i], idx_enum[type_i], + &logic_cfg); if (rc) FAIL(rc); for (i = '1'; i <= '6'; i++) { - snprintf(lut_str, sizeof(lut_str), "A%c", i); - rc = test_lut(tstate, y, x_enum[x_i], idx_enum[type_i], - lut, lut_str, /*lut5*/ 0); + sprintf(lut6_str, "A%c", i); + rc = test_logic(tstate, y, x_enum[x_i], idx_enum[type_i], + &logic_cfg); if (rc) FAIL(rc); } for (i = 0; i < 64; i++) { lut_str_len = 0; for (j = 0; j < 6; j++) { if (lut_str_len) - lut_str[lut_str_len++] = '*'; + lut6_str[lut_str_len++] = '*'; if (!(i & (1<diff_to_null = 1; + + y = 68; + for (x_i = 0; x_i < sizeof(x_enum)/sizeof(*x_enum); x_i++) { + for (type_i = 0; type_i < sizeof(idx_enum)/sizeof(*idx_enum); type_i++) { + for (lut = LUT_A; lut <= LUT_D; lut++) { + + // lut6, direct-out + memset(&logic_cfg, 0, sizeof(logic_cfg)); + logic_cfg.a2d[lut].lut6 = "A1"; + logic_cfg.a2d[lut].out_used = 1; + + rc = test_logic(tstate, y, x_enum[x_i], + idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + + // lut6, mux-out + memset(&logic_cfg, 0, sizeof(logic_cfg)); + logic_cfg.a2d[lut].lut6 = "A1"; + logic_cfg.a2d[lut].out_mux = MUX_O6; + + rc = test_logic(tstate, y, x_enum[x_i], + idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + + if (idx_enum[type_i] == DEV_LOG_M_OR_L) { + // . out_mux=xor + logic_cfg.a2d[lut].out_mux = MUX_XOR; + if (lut == LUT_A) { + // . precyinit=0/1/ax + rc = test_logic_enum_precyinit(tstate, + y, x_enum[x_i], idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + } else { + rc = test_logic(tstate, y, x_enum[x_i], + idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + } + + // . out_mux=cy cy0=x + logic_cfg.a2d[lut].out_mux = MUX_CY; + logic_cfg.a2d[lut].cy0 = CY0_X; + if (lut == LUT_A) { + // . precyinit=0/1/ax + // tbd: the X enum will have X drive + // both cy0 and precyinit at the same time. + rc = test_logic_enum_precyinit(tstate, + y, x_enum[x_i], idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + } else { + rc = test_logic(tstate, y, x_enum[x_i], + idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + } + } + + // lut6, ff-out + memset(&logic_cfg, 0, sizeof(logic_cfg)); + logic_cfg.a2d[lut].lut6 = "A1"; + logic_cfg.a2d[lut].ff = FF_FF; + logic_cfg.a2d[lut].ff_mux = MUX_O6; + logic_cfg.a2d[lut].ff_srinit = FF_SRINIT0; + + logic_cfg.clk_inv = CLKINV_CLK; + logic_cfg.sync_attr = SYNCATTR_ASYNC; + + rc = test_logic_enum_srinit_clk_sync_ce_sr(tstate, y, + x_enum[x_i], idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + + if (idx_enum[type_i] == DEV_LOG_M_OR_L) { + // . ff_mux=xor + logic_cfg.a2d[lut].ff_mux = MUX_XOR; + if (lut == LUT_A) { + // . precyinit=0/1/ax + rc = test_logic_enum_precyinit(tstate, + y, x_enum[x_i], idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + } else { + rc = test_logic(tstate, y, x_enum[x_i], + idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + } + + // . ff_mux=cy cy0=x + logic_cfg.a2d[lut].ff_mux = MUX_CY; + logic_cfg.a2d[lut].cy0 = CY0_X; + if (lut == LUT_A) { + // . precyinit=0/1/ax + rc = test_logic_enum_precyinit(tstate, + y, x_enum[x_i], idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + } else { + rc = test_logic(tstate, y, x_enum[x_i], + idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + } + } + + // x, ff-out + memset(&logic_cfg, 0, sizeof(logic_cfg)); + logic_cfg.a2d[lut].ff = FF_FF; + logic_cfg.a2d[lut].ff_mux = MUX_X; + logic_cfg.a2d[lut].ff_srinit = FF_SRINIT0; + + logic_cfg.clk_inv = CLKINV_CLK; + logic_cfg.sync_attr = SYNCATTR_ASYNC; + rc = test_logic(tstate, y, x_enum[x_i], + idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + + // . o6-direct + logic_cfg.a2d[lut].lut6 = "A1"; + logic_cfg.a2d[lut].out_used = 1; + rc = test_logic(tstate, y, x_enum[x_i], + idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + logic_cfg.a2d[lut].out_used = 0; + + // . o6-outmux + logic_cfg.a2d[lut].out_mux = MUX_O6; + rc = test_logic(tstate, y, x_enum[x_i], + idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + logic_cfg.a2d[lut].out_mux = 0; + + // + // lut5/6 pairs + // + + // lut6 direct-out, lut5 mux-out + memset(&logic_cfg, 0, sizeof(logic_cfg)); + logic_cfg.a2d[lut].lut6 = "(A6+~A6)*A1"; + logic_cfg.a2d[lut].out_used = 1; + logic_cfg.a2d[lut].lut5 = "A1*A2"; + logic_cfg.a2d[lut].out_mux = MUX_O5; + rc = test_logic(tstate, y, x_enum[x_i], + idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + + if (idx_enum[type_i] == DEV_LOG_M_OR_L) { + // . out_mux=cy cy0=o5 + logic_cfg.a2d[lut].out_mux = MUX_CY; + logic_cfg.a2d[lut].cy0 = CY0_O5; + if (lut == LUT_A) { + // . precyinit=0/1/ax + rc = test_logic_enum_precyinit(tstate, + y, x_enum[x_i], idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + } else { + rc = test_logic(tstate, y, x_enum[x_i], + idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + } + } + + // lut6 direct-out, lut5 a5q-out, ff5_srinit=0 + logic_cfg.a2d[lut].cy0 = 0; + logic_cfg.a2d[lut].out_mux = MUX_5Q; + logic_cfg.a2d[lut].ff5_srinit = FF_SRINIT0; + + logic_cfg.clk_inv = CLKINV_CLK; + logic_cfg.sync_attr = SYNCATTR_ASYNC; + + // We go through the global ff configs again for + // the second ff. + rc = test_logic_enum_srinit_clk_sync_ce_sr(tstate, y, + x_enum[x_i], idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + + // . change from out_mux/5q to ff_mux + logic_cfg.a2d[lut].out_mux = 0; + logic_cfg.a2d[lut].ff5_srinit = 0; + logic_cfg.a2d[lut].ff = FF_FF; + logic_cfg.a2d[lut].ff_mux = MUX_O5; + logic_cfg.a2d[lut].ff_srinit = FF_SRINIT0; + rc = test_logic(tstate, y, x_enum[x_i], + idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + + if (idx_enum[type_i] == DEV_LOG_M_OR_L) { + // . add out_mux=cy cy0=x + logic_cfg.a2d[lut].out_mux = MUX_CY; + logic_cfg.a2d[lut].cy0 = CY0_X; + rc = test_logic(tstate, y, x_enum[x_i], + idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + logic_cfg.a2d[lut].out_mux = 0; + logic_cfg.a2d[lut].cy0 = 0; + + // . ff_mux=cy cy0=o5 + logic_cfg.a2d[lut].ff_mux = MUX_CY; + logic_cfg.a2d[lut].cy0 = CY0_O5; + if (lut == LUT_A) { + // . precyinit=0/1/ax + rc = test_logic_enum_precyinit(tstate, + y, x_enum[x_i], idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + } else { + rc = test_logic(tstate, y, x_enum[x_i], + idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + } + } +//break; + } + if (idx_enum[type_i] != DEV_LOG_M_OR_L) + continue; + + // cout + 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 = test_logic(tstate, y, x_enum[x_i], + idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + + // f8 out-mux + memset(&logic_cfg, 0, sizeof(logic_cfg)); + logic_cfg.a2d[LUT_A].lut6 = "~A5"; + logic_cfg.a2d[LUT_B].lut6 = "(A5)"; + logic_cfg.a2d[LUT_C].lut6 = "A5"; + logic_cfg.a2d[LUT_D].lut6 = "((A5))"; + logic_cfg.a2d[LUT_B].out_mux = MUX_F8; + rc = test_logic(tstate, y, x_enum[x_i], + idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + + // . over ff + logic_cfg.a2d[LUT_B].out_mux = 0; + logic_cfg.a2d[LUT_B].ff_mux = MUX_F8; + logic_cfg.a2d[LUT_B].ff = FF_FF; + logic_cfg.a2d[LUT_B].ff_srinit = FF_SRINIT0; + logic_cfg.clk_inv = CLKINV_CLK; + logic_cfg.sync_attr = SYNCATTR_ASYNC; + rc = test_logic(tstate, y, x_enum[x_i], + idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + + // f7amux + memset(&logic_cfg, 0, sizeof(logic_cfg)); + logic_cfg.a2d[LUT_A].lut6 = "~A5"; + logic_cfg.a2d[LUT_B].lut6 = "(A5)"; + logic_cfg.a2d[LUT_A].out_mux = MUX_F7; + rc = test_logic(tstate, y, x_enum[x_i], + idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + + // . over ff + logic_cfg.a2d[LUT_A].out_mux = 0; + logic_cfg.a2d[LUT_A].ff_mux = MUX_F7; + logic_cfg.a2d[LUT_A].ff = FF_FF; + logic_cfg.a2d[LUT_A].ff_srinit = FF_SRINIT0; + logic_cfg.clk_inv = CLKINV_CLK; + logic_cfg.sync_attr = SYNCATTR_ASYNC; + rc = test_logic(tstate, y, x_enum[x_i], + idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + + // f7bmux + memset(&logic_cfg, 0, sizeof(logic_cfg)); + logic_cfg.a2d[LUT_C].lut6 = "~A5"; + logic_cfg.a2d[LUT_D].lut6 = "(A5)"; + logic_cfg.a2d[LUT_C].out_mux = MUX_F7; + rc = test_logic(tstate, y, x_enum[x_i], + idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + + // . over ff + logic_cfg.a2d[LUT_C].out_mux = 0; + logic_cfg.a2d[LUT_C].ff_mux = MUX_F7; + logic_cfg.a2d[LUT_C].ff = FF_FF; + logic_cfg.a2d[LUT_C].ff_srinit = FF_SRINIT0; + logic_cfg.clk_inv = CLKINV_CLK; + logic_cfg.sync_attr = SYNCATTR_ASYNC; + rc = test_logic(tstate, y, x_enum[x_i], + idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); +//goto out; + } + } +out: + return 0; +fail: + return rc; +} + #define DEFAULT_DIFF_EXEC "./autotest_diff.sh" static void printf_help(const char* argv_0, const char** available_tests) diff --git a/libs/bit_regs.c b/libs/bit_regs.c index 6e90280..0242505 100644 --- a/libs/bit_regs.c +++ b/libs/bit_regs.c @@ -744,7 +744,7 @@ static void printf_routing_2minors(const uint8_t* bits, int row, int major, static void printf_v64_mi20(const uint8_t* bits, int row, int major) { - int y, i, hclk; + int y, i, num_bits_on, hclk; uint64_t u64; char bit_str[65]; @@ -757,6 +757,19 @@ static void printf_v64_mi20(const uint8_t* bits, int row, int major) bit_str[i] = (u64 & (1ULL << i)) ? '1' : '0'; printf("r%i ma%i v64_%02i mi20 %s\n", row, major, y, bit_str); + num_bits_on = 0; + for (i = 0; i < 64; i++) { + if (u64 & (1ULL << i)) + num_bits_on++; + } + if (num_bits_on < 3) { + for (i = 0; i < 64; i++) { + if (!(u64 & (1ULL << i))) + continue; + printf("r%i ma%i v64_%02i mi20 b%i\n", + row, major, y, i); + } + } } } } @@ -766,16 +779,16 @@ static void printf_lut(const uint8_t* bits, int row, int major, { char bit_str[64]; uint64_t u64; - int i, num_on_bits; + int i, num_bits_on; u64 = frame_get_lut64(&bits[minor*FRAME_SIZE], v32_i); if (u64) { - num_on_bits = 0; + num_bits_on = 0; for (i = 0; i < 64; i++) { if (u64 & (1ULL << i)) - num_on_bits++; + num_bits_on++; } - if (num_on_bits < 5) { + if (num_bits_on < 5) { printf("r%i ma%02i v32_%02i mip%02i_lut", row, major, v32_i, minor); for (i = 0; i < 64; i++) { diff --git a/libs/control.c b/libs/control.c index 8443df0..0658b5e 100644 --- a/libs/control.c +++ b/libs/control.c @@ -434,6 +434,69 @@ static void add_req_outpin(struct fpga_device* dev, pinw_idx_t pinw_i) // logic device // +int fdev_logic_setconf(struct fpga_model* model, int y, int x, + int type_idx, const struct fpgadev_logic* logic_cfg) +{ + struct fpga_device* dev; + int lut, rc; + + dev = fdev_p(model, y, x, DEV_LOGIC, type_idx); + if (!dev) FAIL(EINVAL); + rc = reset_required_pins(dev); + if (rc) FAIL(rc); + + for (lut = LUT_A; lut <= LUT_D; lut++) { + if (logic_cfg->a2d[lut].out_used) + dev->u.logic.a2d[lut].out_used = 1; + if (logic_cfg->a2d[lut].lut6) { + rc = fdev_logic_a2d_lut(model, y, x, type_idx, + lut, 6, logic_cfg->a2d[lut].lut6, ZTERM); + if (rc) FAIL(rc); + } + if (logic_cfg->a2d[lut].lut5) { + rc = fdev_logic_a2d_lut(model, y, x, type_idx, + lut, 5, logic_cfg->a2d[lut].lut5, ZTERM); + if (rc) FAIL(rc); + } + if (logic_cfg->a2d[lut].ff == FF_FF) { + if (!logic_cfg->a2d[lut].ff_mux + || !logic_cfg->a2d[lut].ff_srinit) + FAIL(EINVAL); + dev->u.logic.a2d[lut].ff = FF_FF; + dev->u.logic.a2d[lut].ff_mux = logic_cfg->a2d[lut].ff_mux; + dev->u.logic.a2d[lut].ff_srinit = logic_cfg->a2d[lut].ff_srinit; + } else if (logic_cfg->a2d[lut].ff) + FAIL(EINVAL); + if (logic_cfg->a2d[lut].out_mux) + dev->u.logic.a2d[lut].out_mux = logic_cfg->a2d[lut].out_mux; + if (logic_cfg->a2d[lut].ff5_srinit) + dev->u.logic.a2d[lut].ff5_srinit = logic_cfg->a2d[lut].ff5_srinit; + if (logic_cfg->a2d[lut].cy0) + dev->u.logic.a2d[lut].cy0 = logic_cfg->a2d[lut].cy0; + } + if (logic_cfg->clk_inv) + dev->u.logic.clk_inv = logic_cfg->clk_inv; + if (logic_cfg->sync_attr) + dev->u.logic.sync_attr = logic_cfg->sync_attr; + if (logic_cfg->ce_used) + dev->u.logic.ce_used = logic_cfg->ce_used; + if (logic_cfg->sr_used) + dev->u.logic.sr_used = logic_cfg->sr_used; + if (logic_cfg->we_mux) + dev->u.logic.we_mux = logic_cfg->we_mux; + if (logic_cfg->cout_used) + dev->u.logic.cout_used = logic_cfg->cout_used; + if (logic_cfg->precyinit) + dev->u.logic.precyinit = logic_cfg->precyinit; + + dev->instantiated = 1; + rc = fdev_set_required_pins(model, y, x, DEV_LOGIC, type_idx); + if (rc) FAIL(rc); + return 0; +fail: + return rc; +} + int fdev_logic_a2d_out_used(struct fpga_model* model, int y, int x, int type_idx, int lut_a2d, int used) { @@ -475,21 +538,6 @@ int fdev_logic_a2d_lut(struct fpga_model* model, int y, int x, int type_idx, memcpy(*lut_ptr, lut_str, lut_len); (*lut_ptr)[lut_len] = 0; - // todo: the logic by which we auto-enable the direct - // output could have more cases, the O6 signal - // could go into the carry chain/XOR/CY, F7/F8, others? - // We need to find out over time what makes sense for - // the caller. - if (lut_5or6 == 6 - && dev->u.logic.a2d[lut_a2d].ff_mux != MUX_O6 - && dev->u.logic.a2d[lut_a2d].out_mux != MUX_O6) - dev->u.logic.a2d[lut_a2d].out_used = 1; - if (lut_5or6 == 5 - && dev->u.logic.a2d[lut_a2d].cy0 != CY0_O5 - && dev->u.logic.a2d[lut_a2d].ff_mux != MUX_O5 - && !dev->u.logic.a2d[lut_a2d].out_mux) - dev->u.logic.a2d[lut_a2d].out_mux = MUX_O5; - dev->instantiated = 1; return 0; fail: @@ -510,6 +558,25 @@ int fdev_logic_a2d_ff(struct fpga_model* model, int y, int x, int type_idx, 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; + // A flip-flop also needs a clock (and sync attribute) to operate. + dev->instantiated = 1; + return 0; +fail: + return rc; +} + +int fdev_logic_a2d_ff5_srinit(struct fpga_model* model, int y, int x, + int type_idx, int lut_a2d, 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].ff5_srinit = srinit; dev->instantiated = 1; return 0; fail: @@ -546,8 +613,6 @@ int fdev_logic_a2d_cy0(struct fpga_model* model, int y, int x, if (rc) FAIL(rc); dev->u.logic.a2d[lut_a2d].cy0 = cy0; -// todo: when cy0 is CY0_O5 and lut5 is empty, set to "0" -// (same for setting ff_mux or out_mux to MUX_O5 dev->instantiated = 1; return 0; fail: diff --git a/libs/control.h b/libs/control.h index e9dd40c..ce756cb 100644 --- a/libs/control.h +++ b/libs/control.h @@ -46,6 +46,9 @@ const char* fdev_pinw_idx2str(int devtype, pinw_idx_t idx); 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_setconf(struct fpga_model* model, int y, int x, + int type_idx, const struct fpgadev_logic* logic_cfg); + // lut_a2d is LUT_A to LUT_D int fdev_logic_a2d_out_used(struct fpga_model* model, int y, int x, int type_idx, int lut_a2d, int used); @@ -55,6 +58,8 @@ int fdev_logic_a2d_lut(struct fpga_model* model, int y, int x, int type_idx, // srinit is FF_SRINIT0 or FF_SRINIT1 int fdev_logic_a2d_ff(struct fpga_model* model, int y, int x, int type_idx, int lut_a2d, int ff_mux, int srinit); +int fdev_logic_a2d_ff5_srinit(struct fpga_model* model, int y, int x, + int type_idx, int lut_a2d, int srinit); int fdev_logic_a2d_out_mux(struct fpga_model* model, int y, int x, int type_idx, int lut_a2d, int out_mux); // cy0 is CY0_X or CY0_O5 diff --git a/libs/floorplan.c b/libs/floorplan.c index 30e10ea..4ce2064 100644 --- a/libs/floorplan.c +++ b/libs/floorplan.c @@ -369,6 +369,15 @@ static int printf_LOGIC(FILE* f, struct fpga_model* model, break; case 0: break; default: FAIL(EINVAL); } + switch (cfg->a2d[j].ff5_srinit) { + case FF_SRINIT0: + fprintf(f, "%s %c5_ffsrinit 0\n", pref, 'A'+j); + break; + case FF_SRINIT1: + fprintf(f, "%s %c5_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); @@ -551,6 +560,15 @@ static int read_LOGIC_attr(struct fpga_model* model, int y, int x, int type_idx, else return 0; goto inst_2; } + snprintf(cmp_str, sizeof(cmp_str), "%c5_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].ff5_srinit = FF_SRINIT0; + else if (!str_cmp(w2, w2_len, "1", ZTERM)) + dev->u.logic.a2d[i].ff5_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)) diff --git a/libs/model.h b/libs/model.h index e172979..6cddc4a 100644 --- a/libs/model.h +++ b/libs/model.h @@ -422,6 +422,7 @@ struct fpgadev_logic_a2d char* lut5; int ff_mux; // O6, O5, X, F7(a/c), F8(b), MC31(d), CY, XOR int ff_srinit; // SRINIT0, SRINIT1 + int ff5_srinit; // SRINIT0, SRINIT1 int out_mux; // O6, O5, 5Q, F7(a/c), F8(b), MC31(d), CY, XOR int ff; // OR2L, AND2L, LATCH, FF int cy0; // X, O5