diff --git a/autotest.c b/autotest.c index c27d916..a9a48a1 100644 --- a/autotest.c +++ b/autotest.c @@ -967,7 +967,7 @@ static int test_logic(struct test_state* tstate, int y, int x, int type_idx, { struct fpga_device* dev; net_idx_t pinw_nets[MAX_NUM_PINW]; - int i, lut, rc; + int i, lut, latch_logic, rc; if (tstate->dry_run) { for (lut = LUT_A; lut <= LUT_D; lut++) { @@ -987,6 +987,14 @@ static int test_logic(struct test_state* tstate, int y, int x, int type_idx, fdev_print_required_pins(tstate->model, y, x, DEV_LOGIC, type_idx); } + latch_logic = 0; + for (lut = LUT_A; lut <= LUT_D; lut++) { + if (logic_cfg->a2d[lut].ff == FF_AND2L + || logic_cfg->a2d[lut].ff == FF_OR2L) { + latch_logic = 1; + break; + } + } // add stub nets for each required pin dev = fdev_p(tstate->model, y, x, DEV_LOGIC, type_idx); @@ -1009,7 +1017,10 @@ static int test_logic(struct test_state* tstate, int y, int x, int type_idx, && *dev->u.logic.a2d[LUT_C].lut5) || (dev->pinw_req_for_cfg[i] == LI_D6 && dev->u.logic.a2d[LUT_D].lut5 - && *dev->u.logic.a2d[LUT_D].lut5)) { + && *dev->u.logic.a2d[LUT_D].lut5) + || (latch_logic + && (dev->pinw_req_for_cfg[i] == LI_CLK + || dev->pinw_req_for_cfg[i] == LI_CE))) { rc = fnet_route_to_inpins(tstate->model, pinw_nets[i], "VCC_WIRE"); if (rc) FAIL(rc); } @@ -1234,16 +1245,18 @@ static int test_logic_config(struct test_state* tstate) 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) { + // lut6, mux-out + // O6 over mux-out seems not supported + // on an X device. + 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); + // . out_mux=xor logic_cfg.a2d[lut].out_mux = MUX_XOR; if (lut == LUT_A) { @@ -1317,6 +1330,64 @@ static int test_logic_config(struct test_state* tstate) } } + // lut6, latch-out + memset(&logic_cfg, 0, sizeof(logic_cfg)); + logic_cfg.a2d[lut].lut6 = "A1"; + logic_cfg.a2d[lut].ff = FF_LATCH; + 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(tstate, y, x_enum[x_i], + idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + + // + // AND and OR latches are physically a normal + // latch, but with additional configuration + // constraints: + // + // 1. ce and clk must be driven high/vcc + // 2. the clk must be inverted before the latch (clk_b) + // 3. srinit must be 0 for AND, 1 for OR + // + + // lut6, and-latch + memset(&logic_cfg, 0, sizeof(logic_cfg)); + logic_cfg.a2d[lut].lut6 = "A1"; + logic_cfg.a2d[lut].ff = FF_AND2L; + logic_cfg.a2d[lut].ff_mux = MUX_O6; + // AND2L requires SRINIT=0 + logic_cfg.a2d[lut].ff_srinit = FF_SRINIT0; + + logic_cfg.clk_inv = CLKINV_B; + logic_cfg.sync_attr = SYNCATTR_ASYNC; + logic_cfg.ce_used = 1; + logic_cfg.sr_used = 1; + + rc = test_logic(tstate, y, x_enum[x_i], + idx_enum[type_i], &logic_cfg); + if (rc) FAIL(rc); + + // lut6, or-latch + memset(&logic_cfg, 0, sizeof(logic_cfg)); + logic_cfg.a2d[lut].lut6 = "A1"; + logic_cfg.a2d[lut].ff = FF_OR2L; + logic_cfg.a2d[lut].ff_mux = MUX_O6; + // OR2L requires SRINIT=1 + logic_cfg.a2d[lut].ff_srinit = FF_SRINIT1; + + logic_cfg.clk_inv = CLKINV_B; + logic_cfg.sync_attr = SYNCATTR_ASYNC; + logic_cfg.ce_used = 1; + logic_cfg.sr_used = 1; + + 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; @@ -1337,12 +1408,14 @@ static int test_logic_config(struct test_state* tstate) 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; + if (idx_enum[type_i] == DEV_LOG_M_OR_L) { + // . 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 @@ -1388,17 +1461,17 @@ static int test_logic_config(struct test_state* tstate) 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) { + // . 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); + // . add out_mux=cy cy0=x logic_cfg.a2d[lut].out_mux = MUX_CY; logic_cfg.a2d[lut].cy0 = CY0_X; @@ -1422,7 +1495,6 @@ static int test_logic_config(struct test_state* tstate) if (rc) FAIL(rc); } } -//break; } if (idx_enum[type_i] != DEV_LOG_M_OR_L) continue; @@ -1524,7 +1596,6 @@ static int test_logic_config(struct test_state* tstate) rc = test_logic(tstate, y, x_enum[x_i], idx_enum[type_i], &logic_cfg); if (rc) FAIL(rc); -//goto out; } } out: diff --git a/blinking_led.c b/blinking_led.c index 5e0da19..44dba8d 100644 --- a/blinking_led.c +++ b/blinking_led.c @@ -9,6 +9,22 @@ #include "floorplan.h" #include "control.h" +/* + This C design corresponds to the following Verilog: + + module blinking(input clk, output led); + + // synthesis attribute LOC clk "P55 | IOSTANDARD = LVCMOS33" + // synthesis attribute LOC led "P48 | SLEW = QUIETIO | DRIVE = 8" + + reg [14:0] counter; + always @(posedge clk) counter <= counter + 1; + assign led = counter[14]; + + endmodule + +*/ + int main(int argc, char** argv) { struct fpga_model model; diff --git a/hello_world.c b/hello_world.c index 5e0da19..db0de19 100644 --- a/hello_world.c +++ b/hello_world.c @@ -9,6 +9,20 @@ #include "floorplan.h" #include "control.h" +/* + This C design corresponds to the following Verilog: + + module ver_and(input a, b, output y); + + // synthesis attribute LOC a "P45" + // synthesis attribute LOC b "P46" + // synthesis attribute LOC y "P48 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12" + + assign y = a & b; + + endmodule +*/ + int main(int argc, char** argv) { struct fpga_model model; diff --git a/libs/bit_regs.c b/libs/bit_regs.c index 0242505..e291e02 100644 --- a/libs/bit_regs.c +++ b/libs/bit_regs.c @@ -762,7 +762,7 @@ static void printf_v64_mi20(const uint8_t* bits, int row, int major) if (u64 & (1ULL << i)) num_bits_on++; } - if (num_bits_on < 3) { + if (num_bits_on < 5) { for (i = 0; i < 64; i++) { if (!(u64 & (1ULL << i))) continue; diff --git a/libs/control.c b/libs/control.c index 0658b5e..ddf2731 100644 --- a/libs/control.c +++ b/libs/control.c @@ -458,15 +458,14 @@ int fdev_logic_setconf(struct fpga_model* model, int y, int x, 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) { 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 = logic_cfg->a2d[lut].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) @@ -841,6 +840,18 @@ int fdev_set_required_pins(struct fpga_model* model, int y, int x, int type, } if (dev->u.logic.precyinit == PRECYINIT_AX) add_req_inpin(dev, LI_AX); + if (dev->u.logic.a2d[LUT_A].out_mux == MUX_F7 + || dev->u.logic.a2d[LUT_A].ff_mux == MUX_F7) + add_req_inpin(dev, LI_AX); + if (dev->u.logic.a2d[LUT_C].out_mux == MUX_F7 + || dev->u.logic.a2d[LUT_C].ff_mux == MUX_F7) + add_req_inpin(dev, LI_CX); + if (dev->u.logic.a2d[LUT_B].out_mux == MUX_F8 + || dev->u.logic.a2d[LUT_B].ff_mux == MUX_F8) { + add_req_inpin(dev, LI_AX); + add_req_inpin(dev, LI_BX); + add_req_inpin(dev, LI_CX); + } for (i = LUT_A; i <= LUT_D; i++) { if (dev->u.logic.a2d[i].out_used) { // LO_A..LO_D are in sequence @@ -1575,16 +1586,24 @@ int fpga_switch_chain(struct sw_chain* ch) = ch->set.sw[ch->set.len-1]; } - idx = fpga_switch_next(ch->model, ch->y, ch->x, + ch->set.sw[ch->set.len-1] = fpga_switch_next( + ch->model, ch->y, ch->x, ch->set.sw[ch->set.len-1], ch->from_to); - if (idx != NO_SWITCH) { - if (fpga_switch_is_used(ch->model, ch->y, ch->x, idx)) + if (ch->set.sw[ch->set.len-1] != NO_SWITCH) { + if (fpga_switch_is_used(ch->model, ch->y, + ch->x, ch->set.sw[ch->set.len-1])) { +#ifdef DBG_ENUM_SWITCH + printf(" skipping used %s\n", + fpga_switch_print(ch->model, ch->y, + ch->x, ch->set.sw[ch->set.len-1])); +#endif continue; + } #ifdef DBG_ENUM_SWITCH printf(" found %s\n", fpga_switch_print( - ch->model, ch->y, ch->x, idx)); + ch->model, ch->y, ch->x, + ch->set.sw[ch->set.len-1])); #endif - ch->set.sw[ch->set.len-1] = idx; break; } @@ -2238,11 +2257,14 @@ int fnet_route_to_inpins(struct fpga_model* model, net_idx_t net_i, if ((net_p->el[i].idx & NET_IDX_MASK) >= dev_p->num_pinw_in) // skip outpin continue; + rc = froute_direct(model, net_p->el[i].y, net_p->el[i].x-1, from_i, net_p->el[i].y, net_p->el[i].x, dev_p->pinw[net_p->el[i].idx & NET_IDX_MASK], &start_set, &end_set); if (rc) FAIL(rc); + if (!start_set.len || !end_set.len) + HERE(); rc = fnet_add_sw(model, net_i, net_p->el[i].y, net_p->el[i].x-1, start_set.sw, start_set.len); if (rc) FAIL(rc); @@ -2268,7 +2290,7 @@ int froute_direct(struct fpga_model* model, int start_y, int start_x, if (!end_switches.len) FAIL(EINVAL); rc = construct_sw_conns(&conns, model, start_y, start_x, start_pt, - SW_FROM, /*max_depth*/ 1); + SW_FROM, /*max_depth*/ 2); if (rc) FAIL(rc); while (fpga_switch_conns(&conns) != NO_CONN) {