better support for latches
This commit is contained in:
parent
c567e6db72
commit
b310d70ee5
83
autotest.c
83
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;
|
struct fpga_device* dev;
|
||||||
net_idx_t pinw_nets[MAX_NUM_PINW];
|
net_idx_t pinw_nets[MAX_NUM_PINW];
|
||||||
int i, lut, rc;
|
int i, lut, latch_logic, rc;
|
||||||
|
|
||||||
if (tstate->dry_run) {
|
if (tstate->dry_run) {
|
||||||
for (lut = LUT_A; lut <= LUT_D; lut++) {
|
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,
|
fdev_print_required_pins(tstate->model, y, x,
|
||||||
DEV_LOGIC, type_idx);
|
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
|
// add stub nets for each required pin
|
||||||
dev = fdev_p(tstate->model, y, x, DEV_LOGIC, type_idx);
|
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->u.logic.a2d[LUT_C].lut5)
|
||||||
|| (dev->pinw_req_for_cfg[i] == LI_D6
|
|| (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)) {
|
&& *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");
|
rc = fnet_route_to_inpins(tstate->model, pinw_nets[i], "VCC_WIRE");
|
||||||
if (rc) FAIL(rc);
|
if (rc) FAIL(rc);
|
||||||
}
|
}
|
||||||
|
@ -1234,7 +1245,10 @@ static int test_logic_config(struct test_state* tstate)
|
||||||
idx_enum[type_i], &logic_cfg);
|
idx_enum[type_i], &logic_cfg);
|
||||||
if (rc) FAIL(rc);
|
if (rc) FAIL(rc);
|
||||||
|
|
||||||
|
if (idx_enum[type_i] == DEV_LOG_M_OR_L) {
|
||||||
// lut6, mux-out
|
// lut6, mux-out
|
||||||
|
// O6 over mux-out seems not supported
|
||||||
|
// on an X device.
|
||||||
memset(&logic_cfg, 0, sizeof(logic_cfg));
|
memset(&logic_cfg, 0, sizeof(logic_cfg));
|
||||||
logic_cfg.a2d[lut].lut6 = "A1";
|
logic_cfg.a2d[lut].lut6 = "A1";
|
||||||
logic_cfg.a2d[lut].out_mux = MUX_O6;
|
logic_cfg.a2d[lut].out_mux = MUX_O6;
|
||||||
|
@ -1243,7 +1257,6 @@ static int test_logic_config(struct test_state* tstate)
|
||||||
idx_enum[type_i], &logic_cfg);
|
idx_enum[type_i], &logic_cfg);
|
||||||
if (rc) FAIL(rc);
|
if (rc) FAIL(rc);
|
||||||
|
|
||||||
if (idx_enum[type_i] == DEV_LOG_M_OR_L) {
|
|
||||||
// . out_mux=xor
|
// . out_mux=xor
|
||||||
logic_cfg.a2d[lut].out_mux = MUX_XOR;
|
logic_cfg.a2d[lut].out_mux = MUX_XOR;
|
||||||
if (lut == LUT_A) {
|
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
|
// x, ff-out
|
||||||
memset(&logic_cfg, 0, sizeof(logic_cfg));
|
memset(&logic_cfg, 0, sizeof(logic_cfg));
|
||||||
logic_cfg.a2d[lut].ff = FF_FF;
|
logic_cfg.a2d[lut].ff = FF_FF;
|
||||||
|
@ -1337,12 +1408,14 @@ static int test_logic_config(struct test_state* tstate)
|
||||||
if (rc) FAIL(rc);
|
if (rc) FAIL(rc);
|
||||||
logic_cfg.a2d[lut].out_used = 0;
|
logic_cfg.a2d[lut].out_used = 0;
|
||||||
|
|
||||||
|
if (idx_enum[type_i] == DEV_LOG_M_OR_L) {
|
||||||
// . o6-outmux
|
// . o6-outmux
|
||||||
logic_cfg.a2d[lut].out_mux = MUX_O6;
|
logic_cfg.a2d[lut].out_mux = MUX_O6;
|
||||||
rc = test_logic(tstate, y, x_enum[x_i],
|
rc = test_logic(tstate, y, x_enum[x_i],
|
||||||
idx_enum[type_i], &logic_cfg);
|
idx_enum[type_i], &logic_cfg);
|
||||||
if (rc) FAIL(rc);
|
if (rc) FAIL(rc);
|
||||||
logic_cfg.a2d[lut].out_mux = 0;
|
logic_cfg.a2d[lut].out_mux = 0;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// lut5/6 pairs
|
// lut5/6 pairs
|
||||||
|
@ -1388,6 +1461,7 @@ static int test_logic_config(struct test_state* tstate)
|
||||||
x_enum[x_i], idx_enum[type_i], &logic_cfg);
|
x_enum[x_i], idx_enum[type_i], &logic_cfg);
|
||||||
if (rc) FAIL(rc);
|
if (rc) FAIL(rc);
|
||||||
|
|
||||||
|
if (idx_enum[type_i] == DEV_LOG_M_OR_L) {
|
||||||
// . change from out_mux/5q to ff_mux
|
// . change from out_mux/5q to ff_mux
|
||||||
logic_cfg.a2d[lut].out_mux = 0;
|
logic_cfg.a2d[lut].out_mux = 0;
|
||||||
logic_cfg.a2d[lut].ff5_srinit = 0;
|
logic_cfg.a2d[lut].ff5_srinit = 0;
|
||||||
|
@ -1398,7 +1472,6 @@ static int test_logic_config(struct test_state* tstate)
|
||||||
idx_enum[type_i], &logic_cfg);
|
idx_enum[type_i], &logic_cfg);
|
||||||
if (rc) FAIL(rc);
|
if (rc) FAIL(rc);
|
||||||
|
|
||||||
if (idx_enum[type_i] == DEV_LOG_M_OR_L) {
|
|
||||||
// . add out_mux=cy cy0=x
|
// . add out_mux=cy cy0=x
|
||||||
logic_cfg.a2d[lut].out_mux = MUX_CY;
|
logic_cfg.a2d[lut].out_mux = MUX_CY;
|
||||||
logic_cfg.a2d[lut].cy0 = CY0_X;
|
logic_cfg.a2d[lut].cy0 = CY0_X;
|
||||||
|
@ -1422,7 +1495,6 @@ static int test_logic_config(struct test_state* tstate)
|
||||||
if (rc) FAIL(rc);
|
if (rc) FAIL(rc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//break;
|
|
||||||
}
|
}
|
||||||
if (idx_enum[type_i] != DEV_LOG_M_OR_L)
|
if (idx_enum[type_i] != DEV_LOG_M_OR_L)
|
||||||
continue;
|
continue;
|
||||||
|
@ -1524,7 +1596,6 @@ static int test_logic_config(struct test_state* tstate)
|
||||||
rc = test_logic(tstate, y, x_enum[x_i],
|
rc = test_logic(tstate, y, x_enum[x_i],
|
||||||
idx_enum[type_i], &logic_cfg);
|
idx_enum[type_i], &logic_cfg);
|
||||||
if (rc) FAIL(rc);
|
if (rc) FAIL(rc);
|
||||||
//goto out;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
|
|
@ -9,6 +9,22 @@
|
||||||
#include "floorplan.h"
|
#include "floorplan.h"
|
||||||
#include "control.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)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
struct fpga_model model;
|
struct fpga_model model;
|
||||||
|
|
|
@ -9,6 +9,20 @@
|
||||||
#include "floorplan.h"
|
#include "floorplan.h"
|
||||||
#include "control.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)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
struct fpga_model model;
|
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))
|
if (u64 & (1ULL << i))
|
||||||
num_bits_on++;
|
num_bits_on++;
|
||||||
}
|
}
|
||||||
if (num_bits_on < 3) {
|
if (num_bits_on < 5) {
|
||||||
for (i = 0; i < 64; i++) {
|
for (i = 0; i < 64; i++) {
|
||||||
if (!(u64 & (1ULL << i)))
|
if (!(u64 & (1ULL << i)))
|
||||||
continue;
|
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);
|
lut, 5, logic_cfg->a2d[lut].lut5, ZTERM);
|
||||||
if (rc) FAIL(rc);
|
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
|
if (!logic_cfg->a2d[lut].ff_mux
|
||||||
|| !logic_cfg->a2d[lut].ff_srinit)
|
|| !logic_cfg->a2d[lut].ff_srinit)
|
||||||
FAIL(EINVAL);
|
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_mux = logic_cfg->a2d[lut].ff_mux;
|
||||||
dev->u.logic.a2d[lut].ff_srinit = logic_cfg->a2d[lut].ff_srinit;
|
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)
|
if (logic_cfg->a2d[lut].out_mux)
|
||||||
dev->u.logic.a2d[lut].out_mux = 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)
|
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)
|
if (dev->u.logic.precyinit == PRECYINIT_AX)
|
||||||
add_req_inpin(dev, LI_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++) {
|
for (i = LUT_A; i <= LUT_D; i++) {
|
||||||
if (dev->u.logic.a2d[i].out_used) {
|
if (dev->u.logic.a2d[i].out_used) {
|
||||||
// LO_A..LO_D are in sequence
|
// 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];
|
= 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);
|
ch->set.sw[ch->set.len-1], ch->from_to);
|
||||||
if (idx != NO_SWITCH) {
|
if (ch->set.sw[ch->set.len-1] != NO_SWITCH) {
|
||||||
if (fpga_switch_is_used(ch->model, ch->y, ch->x, idx))
|
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;
|
continue;
|
||||||
|
}
|
||||||
#ifdef DBG_ENUM_SWITCH
|
#ifdef DBG_ENUM_SWITCH
|
||||||
printf(" found %s\n", fpga_switch_print(
|
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
|
#endif
|
||||||
ch->set.sw[ch->set.len-1] = idx;
|
|
||||||
break;
|
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)
|
if ((net_p->el[i].idx & NET_IDX_MASK) >= dev_p->num_pinw_in)
|
||||||
// skip outpin
|
// skip outpin
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
rc = froute_direct(model, net_p->el[i].y, net_p->el[i].x-1,
|
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,
|
from_i, net_p->el[i].y, net_p->el[i].x,
|
||||||
dev_p->pinw[net_p->el[i].idx & NET_IDX_MASK],
|
dev_p->pinw[net_p->el[i].idx & NET_IDX_MASK],
|
||||||
&start_set, &end_set);
|
&start_set, &end_set);
|
||||||
if (rc) FAIL(rc);
|
if (rc) FAIL(rc);
|
||||||
|
if (!start_set.len || !end_set.len)
|
||||||
|
HERE();
|
||||||
rc = fnet_add_sw(model, net_i, net_p->el[i].y,
|
rc = fnet_add_sw(model, net_i, net_p->el[i].y,
|
||||||
net_p->el[i].x-1, start_set.sw, start_set.len);
|
net_p->el[i].x-1, start_set.sw, start_set.len);
|
||||||
if (rc) FAIL(rc);
|
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);
|
if (!end_switches.len) FAIL(EINVAL);
|
||||||
|
|
||||||
rc = construct_sw_conns(&conns, model, start_y, start_x, start_pt,
|
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);
|
if (rc) FAIL(rc);
|
||||||
|
|
||||||
while (fpga_switch_conns(&conns) != NO_CONN) {
|
while (fpga_switch_conns(&conns) != NO_CONN) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user