Initial DDFR support
This commit is contained in:
parent
cefff69985
commit
d5edee414c
@ -302,6 +302,16 @@ struct BitstreamJsonBackend
|
||||
}
|
||||
}
|
||||
|
||||
void write_ddfr(CellInfo *cell) {
|
||||
open_instance(cell);
|
||||
add_config("dff_load", bool_or_default(cell->params, ctx->id("dff_load"), false));
|
||||
add_config("dff_sync", bool_or_default(cell->params, ctx->id("dff_sync"), false));
|
||||
add_config("dff_type", bool_or_default(cell->params, ctx->id("dff_type"), false));
|
||||
add_config("iobname", str_or_default(cell->params, ctx->id("iobname"), ""));
|
||||
add_config("path", int_or_default(cell->params, ctx->id("path"), 0));
|
||||
close_instance();
|
||||
}
|
||||
|
||||
void write_dfr(CellInfo *cell) {
|
||||
open_instance(cell);
|
||||
add_config("data_inv", bool_or_default(cell->params, ctx->id("data_inv"), false));
|
||||
@ -549,7 +559,7 @@ struct BitstreamJsonBackend
|
||||
case id_GCK.index: write_gck(cell.second.get()); break;
|
||||
case id_IOM.index: write_iom(cell.second.get()); break;
|
||||
case id_BFR.index: write_bfr(cell.second.get()); break;
|
||||
//case id_DDFR.index:
|
||||
case id_DDFR.index: write_ddfr(cell.second.get()); break;
|
||||
case id_DFR.index: write_dfr(cell.second.get()); break;
|
||||
case id_RAM.index: write_ram(cell.second.get()); break;
|
||||
case id_RF.index:
|
||||
|
@ -147,8 +147,7 @@ const dict<IdString,pool<IdString>> ring_clock_sinks = {
|
||||
const dict<IdString,pool<IdString>> ring_over_tile_clock_sinks = {
|
||||
// IOB
|
||||
{ id_DFR, { id_CK }},
|
||||
{ id_DDFR, { id_CK }},
|
||||
{ id_DDFR, { id_CKF }},
|
||||
{ id_DDFR, { id_CK, id_CKF }},
|
||||
};
|
||||
// IOB
|
||||
// { id_IOM, { id_ALCK1, id_ALCK2, id_ALCK3, id_CCK, id_FCK1, id_FCK2, id_FDCK,
|
||||
|
@ -48,6 +48,9 @@ inline bool is_fe(const BaseCtx *ctx, const CellInfo *cell) { return cell->type
|
||||
// Return true if a cell is a DFR
|
||||
inline bool is_dfr(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == id_NX_DFR; }
|
||||
|
||||
// Return true if a cell is a DDFR
|
||||
inline bool is_ddfr(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("NX_DDFR_U"); }
|
||||
|
||||
// Return true if a cell is a WFG/WFB
|
||||
inline bool is_wfg(const BaseCtx *ctx, const CellInfo *cell) { return cell->type.in(id_WFB, id_WFG); }
|
||||
|
||||
@ -170,6 +173,24 @@ void NgUltraPacker::dff_rewrite(CellInfo *cell)
|
||||
}
|
||||
}
|
||||
|
||||
void NgUltraPacker::ddfr_rewrite(CellInfo *cell)
|
||||
{
|
||||
// Reversed logic in comparison to DFF
|
||||
if (int_or_default(cell->params, ctx->id("dff_load"), 0)==1) {
|
||||
// Load not used
|
||||
cell->disconnectPort(id_L);
|
||||
} else {
|
||||
// Load used
|
||||
NetInfo *net = cell->getPort(id_L);
|
||||
if (net) {
|
||||
if (net->name == ctx->id("$PACKER_VCC")) {
|
||||
log_warning("Removing load enable on '%s' since it is always 1.\n", cell->name.c_str(ctx));
|
||||
cell->disconnectPort(id_L);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NgUltraPacker::update_dffs()
|
||||
{
|
||||
log_info("Update DFFs...\n");
|
||||
@ -527,6 +548,7 @@ void NgUltraPacker::pack_iobs(void)
|
||||
}
|
||||
int bfr_added = 0;
|
||||
int dfr_added = 0;
|
||||
int ddfr_added = 0;
|
||||
for (auto cell : to_update) {
|
||||
NetInfo *c_net = cell->getPort(id_C);
|
||||
if (!c_net)
|
||||
@ -550,24 +572,38 @@ void NgUltraPacker::pack_iobs(void)
|
||||
{
|
||||
CellInfo *iod = net_driven_by(ctx, c_net, is_dfr, id_O);
|
||||
if (iod && c_net->users.entries()!=1)
|
||||
log_error("NX_DFR '%s can only directly drive IOB.\n", iod->name.c_str(ctx));
|
||||
log_error("NX_DFR '%s' can only directly drive IOB.\n", iod->name.c_str(ctx));
|
||||
if (!iod) {
|
||||
bfr_added++;
|
||||
iod = create_cell_ptr(id_BFR, ctx->id(cell->name.str(ctx) + "$iod_cd"));
|
||||
NetInfo *new_out = ctx->createNet(ctx->id(iod->name.str(ctx) + "$O"));
|
||||
iod->setParam(ctx->id("iobname"),str_or_default(cell->params, ctx->id("iobname"), ""));
|
||||
cell->disconnectPort(id_C);
|
||||
if (c_net->name == ctx->id("$PACKER_GND"))
|
||||
iod->setParam(ctx->id("mode"), Property(0, 2));
|
||||
else if (c_net->name == ctx->id("$PACKER_VCC"))
|
||||
iod->setParam(ctx->id("mode"), Property(1, 2));
|
||||
else {
|
||||
iod->connectPort(id_I, c_net);
|
||||
iod->setParam(ctx->id("mode"), Property(2, 2));
|
||||
iod->setParam(ctx->id("data_inv"), Property(0, 1));
|
||||
iod = net_driven_by(ctx, c_net, is_ddfr, id_O);
|
||||
if (iod && c_net->users.entries()!=1)
|
||||
log_error("NX_DDFR '%s' can only directly drive IOB.\n", iod->name.c_str(ctx));
|
||||
if (!iod) {
|
||||
bfr_added++;
|
||||
iod = create_cell_ptr(id_BFR, ctx->id(cell->name.str(ctx) + "$iod_cd"));
|
||||
NetInfo *new_out = ctx->createNet(ctx->id(iod->name.str(ctx) + "$O"));
|
||||
iod->setParam(ctx->id("iobname"),str_or_default(cell->params, ctx->id("iobname"), ""));
|
||||
cell->disconnectPort(id_C);
|
||||
if (c_net->name == ctx->id("$PACKER_GND"))
|
||||
iod->setParam(ctx->id("mode"), Property(0, 2));
|
||||
else if (c_net->name == ctx->id("$PACKER_VCC"))
|
||||
iod->setParam(ctx->id("mode"), Property(1, 2));
|
||||
else {
|
||||
iod->connectPort(id_I, c_net);
|
||||
iod->setParam(ctx->id("mode"), Property(2, 2));
|
||||
iod->setParam(ctx->id("data_inv"), Property(0, 1));
|
||||
}
|
||||
iod->connectPort(id_O, new_out);
|
||||
cell->connectPort(id_C,new_out);
|
||||
} else {
|
||||
ddfr_added++;
|
||||
iod->type = id_DDFR;
|
||||
iod->setParam(ctx->id("iobname"),str_or_default(cell->params, ctx->id("iobname"), ""));
|
||||
iod->setParam(ctx->id("path"), Property(2, 2));
|
||||
ddfr_rewrite(iod);
|
||||
disconnect_unused(iod, id_O2);
|
||||
disconnect_if_gnd(iod, id_L);
|
||||
disconnect_if_gnd(iod, id_R);
|
||||
}
|
||||
iod->connectPort(id_O, new_out);
|
||||
cell->connectPort(id_C,new_out);
|
||||
} else {
|
||||
dfr_added++;
|
||||
iod->type = id_DFR;
|
||||
@ -583,24 +619,38 @@ void NgUltraPacker::pack_iobs(void)
|
||||
if (i_net) {
|
||||
CellInfo *iod = net_driven_by(ctx, i_net, is_dfr, id_O);
|
||||
if (iod && i_net->users.entries()!=1)
|
||||
log_error("NX_DFR '%s can only directly drive IOB.\n", iod->name.c_str(ctx));
|
||||
log_error("NX_DFR '%s' can only directly drive IOB.\n", iod->name.c_str(ctx));
|
||||
if (!iod) {
|
||||
bfr_added++;
|
||||
iod = create_cell_ptr(id_BFR, ctx->id(cell->name.str(ctx) + "$iod_od"));
|
||||
NetInfo *new_out = ctx->createNet(ctx->id(iod->name.str(ctx) + "$O"));
|
||||
iod->setParam(ctx->id("iobname"),str_or_default(cell->params, ctx->id("iobname"), ""));
|
||||
cell->disconnectPort(id_I);
|
||||
if (i_net->name == ctx->id("$PACKER_GND"))
|
||||
iod->setParam(ctx->id("mode"), Property(0, 2));
|
||||
else if (i_net->name == ctx->id("$PACKER_VCC"))
|
||||
iod->setParam(ctx->id("mode"), Property(1, 2));
|
||||
else {
|
||||
iod->connectPort(id_I, i_net);
|
||||
iod->setParam(ctx->id("mode"), Property(2, 2));
|
||||
iod->setParam(ctx->id("data_inv"), Property(0, 1));
|
||||
iod = net_driven_by(ctx, i_net, is_ddfr, id_O);
|
||||
if (iod && i_net->users.entries()!=1)
|
||||
log_error("NX_DDFR '%s' can only directly drive IOB.\n", iod->name.c_str(ctx));
|
||||
if (!iod) {
|
||||
bfr_added++;
|
||||
iod = create_cell_ptr(id_BFR, ctx->id(cell->name.str(ctx) + "$iod_od"));
|
||||
NetInfo *new_out = ctx->createNet(ctx->id(iod->name.str(ctx) + "$O"));
|
||||
iod->setParam(ctx->id("iobname"),str_or_default(cell->params, ctx->id("iobname"), ""));
|
||||
cell->disconnectPort(id_I);
|
||||
if (i_net->name == ctx->id("$PACKER_GND"))
|
||||
iod->setParam(ctx->id("mode"), Property(0, 2));
|
||||
else if (i_net->name == ctx->id("$PACKER_VCC"))
|
||||
iod->setParam(ctx->id("mode"), Property(1, 2));
|
||||
else {
|
||||
iod->connectPort(id_I, i_net);
|
||||
iod->setParam(ctx->id("mode"), Property(2, 2));
|
||||
iod->setParam(ctx->id("data_inv"), Property(0, 1));
|
||||
}
|
||||
iod->connectPort(id_O, new_out);
|
||||
cell->connectPort(id_I,new_out);
|
||||
} else {
|
||||
ddfr_added++;
|
||||
iod->type = id_DDFR;
|
||||
iod->setParam(ctx->id("iobname"),str_or_default(cell->params, ctx->id("iobname"), ""));
|
||||
iod->setParam(ctx->id("path"), Property(0, 2));
|
||||
ddfr_rewrite(iod);
|
||||
disconnect_unused(iod, id_O2);
|
||||
disconnect_if_gnd(iod, id_L);
|
||||
disconnect_if_gnd(iod, id_R);
|
||||
}
|
||||
iod->connectPort(id_O, new_out);
|
||||
cell->connectPort(id_I,new_out);
|
||||
} else {
|
||||
dfr_added++;
|
||||
iod->type = id_DFR;
|
||||
@ -618,18 +668,32 @@ void NgUltraPacker::pack_iobs(void)
|
||||
CellInfo *iod = net_only_drives(ctx, o_net, is_dfr, id_I, true);
|
||||
if (!(o_net->users.entries()==1 && (*o_net->users.begin()).cell->type == id_NX_IOM_U)) {
|
||||
bool bfr_mode = false;
|
||||
bool ddfr_mode = false;
|
||||
if (!iod) {
|
||||
bfr_added++;
|
||||
iod = create_cell_ptr(id_BFR, ctx->id(cell->name.str(ctx) + "$iod_id"));
|
||||
NetInfo *new_in = ctx->createNet(ctx->id(iod->name.str(ctx) + "$I"));
|
||||
iod->setParam(ctx->id("iobname"),str_or_default(cell->params, ctx->id("iobname"), ""));
|
||||
cell->disconnectPort(id_O);
|
||||
iod->connectPort(id_O, o_net);
|
||||
iod->setParam(ctx->id("mode"), Property(2, 2));
|
||||
iod->setParam(ctx->id("data_inv"), Property(0, 1));
|
||||
iod->connectPort(id_I, new_in);
|
||||
cell->connectPort(id_O,new_in);
|
||||
bfr_mode = true;
|
||||
iod = net_only_drives(ctx, o_net, is_ddfr, id_I, true);
|
||||
if (!iod) {
|
||||
bfr_added++;
|
||||
iod = create_cell_ptr(id_BFR, ctx->id(cell->name.str(ctx) + "$iod_id"));
|
||||
NetInfo *new_in = ctx->createNet(ctx->id(iod->name.str(ctx) + "$I"));
|
||||
iod->setParam(ctx->id("iobname"),str_or_default(cell->params, ctx->id("iobname"), ""));
|
||||
cell->disconnectPort(id_O);
|
||||
iod->connectPort(id_O, o_net);
|
||||
iod->setParam(ctx->id("mode"), Property(2, 2));
|
||||
iod->setParam(ctx->id("data_inv"), Property(0, 1));
|
||||
iod->connectPort(id_I, new_in);
|
||||
cell->connectPort(id_O,new_in);
|
||||
bfr_mode = true;
|
||||
} else {
|
||||
ddfr_mode = true;
|
||||
ddfr_added++;
|
||||
iod->type = id_DDFR;
|
||||
iod->setParam(ctx->id("iobname"),str_or_default(cell->params, ctx->id("iobname"), ""));
|
||||
iod->setParam(ctx->id("path"), Property(1, 2));
|
||||
ddfr_rewrite(iod);
|
||||
disconnect_if_gnd(iod, id_I2);
|
||||
disconnect_if_gnd(iod, id_L);
|
||||
disconnect_if_gnd(iod, id_R);
|
||||
}
|
||||
} else {
|
||||
dfr_added++;
|
||||
iod->type = id_DFR;
|
||||
@ -642,7 +706,7 @@ void NgUltraPacker::pack_iobs(void)
|
||||
ctx->bindBel(bel, iod, PlaceStrength::STRENGTH_LOCKED);
|
||||
|
||||
// Depending of DDFR mode we must use one of dedicated routes (ITCs)
|
||||
if (ctx->getBelType(bel)==id_DDFR) {
|
||||
if (!ddfr_mode && ctx->getBelType(bel)==id_DDFR) {
|
||||
WireId dwire = ctx->getBelPinWire(bel, id_O);
|
||||
for (PipId pip : ctx->getPipsDownhill(dwire)) {
|
||||
const auto &pip_data = chip_pip_info(ctx->chip_info, pip);
|
||||
@ -659,6 +723,8 @@ void NgUltraPacker::pack_iobs(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ddfr_added)
|
||||
log_info(" %6d DDFRs used as DDFR\n", ddfr_added);
|
||||
if (dfr_added)
|
||||
log_info(" %6d DFRs/DDFRs used as DFR\n", dfr_added);
|
||||
if (bfr_added)
|
||||
|
@ -78,6 +78,7 @@ TESTABLE_PRIVATE:
|
||||
void lut_to_fe(CellInfo *lut, CellInfo *fe, bool no_dff, Property lut_table);
|
||||
void dff_to_fe(CellInfo *dff, CellInfo *fe, bool pass_thru_lut);
|
||||
void dff_rewrite(CellInfo *cell);
|
||||
void ddfr_rewrite(CellInfo *cell);
|
||||
|
||||
void exchange_if_constant(CellInfo *cell, IdString input1, IdString input2);
|
||||
void pack_cy_input_and_output(CellInfo *cy, IdString cluster, IdString in_port, IdString out_port, int placer, int &lut_only, int &lut_and_ff, int &dff_only);
|
||||
|
Loading…
Reference in New Issue
Block a user