better support for latches

This commit is contained in:
Wolfgang Spraul 2012-10-09 04:11:32 +02:00
parent c567e6db72
commit b310d70ee5
5 changed files with 163 additions and 40 deletions

View File

@ -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:

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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) {