better support for latches
This commit is contained in:
parent
c567e6db72
commit
b310d70ee5
129
autotest.c
129
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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user