Create BFRs properly

This commit is contained in:
Miodrag Milanovic 2024-05-09 14:55:25 +02:00
parent 0140b2e831
commit f8680e413d
3 changed files with 99 additions and 49 deletions

View File

@ -381,12 +381,6 @@ def create_tile_types(ch: Chip, bels, bel_pins, crossbars, interconnects, muxes,
pd = tt.create_pip(f"{name}."+inp,f"{name}."+out,"MATRIX_PIP") pd = tt.create_pip(f"{name}."+inp,f"{name}."+out,"MATRIX_PIP")
pd.extra_data = PipExtraData(ch.strs.id(f"{name}."+inp),PIP_EXTRA_MUX,int(inp[1:])-1,int(out[1:])-1) pd.extra_data = PipExtraData(ch.strs.id(f"{name}."+inp),PIP_EXTRA_MUX,int(inp[1:])-1,int(out[1:])-1)
elif (tile_type.startswith("IOB") and bel=="DFR"):
by = tt.create_pip(f"{name}.I",f"{name}.O","BYPASS")
by.extra_data = PipExtraData(ch.strs.id(name),PIP_EXTRA_BYPASS,0,0)
elif (tile_type.startswith("IOB") and bel=="DDFR"):
by = tt.create_pip(f"{name}.I",f"{name}.O","BYPASS")
by.extra_data = PipExtraData(ch.strs.id(name),PIP_EXTRA_BYPASS,0,0)
elif (tile_type.startswith("CKG") and bel=="WFG"): elif (tile_type.startswith("CKG") and bel=="WFG"):
by = tt.create_pip(f"{name}.ZI",f"{name}.ZO","BYPASS") by = tt.create_pip(f"{name}.ZI",f"{name}.ZO","BYPASS")
by.extra_data = PipExtraData(ch.strs.id(name),PIP_EXTRA_BYPASS,0,0) by.extra_data = PipExtraData(ch.strs.id(name),PIP_EXTRA_BYPASS,0,0)

View File

@ -114,7 +114,7 @@ void NgUltraImpl::postRoute()
ctx->assignArchInfo(); ctx->assignArchInfo();
log_break(); log_break();
log_info("Resources spent on routing:\n"); log_info("Resources spent on routing:\n");
int dff_bypass = 0, fe_new = 0, wfg_bypass = 0, gck_bypass = 0, ddfr_bypass = 0; int dff_bypass = 0, fe_new = 0, wfg_bypass = 0, gck_bypass = 0;
for (auto &net : ctx->nets) { for (auto &net : ctx->nets) {
NetInfo *ni = net.second.get(); NetInfo *ni = net.second.get();
for (auto &w : ni->wires) { for (auto &w : ni->wires) {
@ -132,7 +132,6 @@ void NgUltraImpl::postRoute()
if (type==id_BEYOND_FE) fe_new++; if (type==id_BEYOND_FE) fe_new++;
} }
CellInfo *cell = ctx->getBoundBelCell(bel); CellInfo *cell = ctx->getBoundBelCell(bel);
std::string bel_name = ctx->getBelName(cell->bel)[1].c_str(ctx);
switch(type.index) { switch(type.index) {
case id_BEYOND_FE.index : case id_BEYOND_FE.index :
dff_bypass++; dff_bypass++;
@ -144,26 +143,6 @@ void NgUltraImpl::postRoute()
cell->setParam(ctx->id("type"), Property("WFB")); cell->setParam(ctx->id("type"), Property("WFB"));
break; break;
case id_GCK.index : gck_bypass++; break; case id_GCK.index : gck_bypass++; break;
case id_DDFR.index :
case id_DFR.index : ddfr_bypass++;
{
Loc loc = ctx->getBelLocation(bel);
cell->setParam(ctx->id("type"), Property("BFR"));
cell->setParam(ctx->id("mode"), Property(2, 2));
cell->setParam(ctx->id("data_inv"), Property(0, 1));
if (boost::ends_with(bel_name, "CD")) {
loc.z -= 3;
} else if (boost::ends_with(bel_name, "OD")) {
loc.z -= 2;
} else {
loc.z -= 1;
}
CellInfo *iob = ctx->getBoundBelCell(ctx->getBelByLocation(loc));
if (!iob || iob->params.count(ctx->id("iobname"))==0)
log_error("IOB for '%s' must have iobname defined.\n", cell->name.c_str(ctx));
cell->setParam(ctx->id("iobname"), iob->params[ctx->id("iobname")]);
}
break;
default: default:
log_error("Unmaped bel type '%s' for routing\n",type.c_str(ctx)); log_error("Unmaped bel type '%s' for routing\n",type.c_str(ctx));
} }
@ -174,7 +153,6 @@ void NgUltraImpl::postRoute()
log_info(" %6d DFFs used as BFF (%d new allocated FEs)\n", dff_bypass, fe_new); log_info(" %6d DFFs used as BFF (%d new allocated FEs)\n", dff_bypass, fe_new);
log_info(" %6d WFGs used as WFB\n", wfg_bypass); log_info(" %6d WFGs used as WFB\n", wfg_bypass);
log_info(" %6d GCK\n", gck_bypass); log_info(" %6d GCK\n", gck_bypass);
log_info(" %6d DFR/DDFR as BFR\n", ddfr_bypass);
// Handle LUT permutation // Handle LUT permutation
for (auto &cell : ctx->cells) { for (auto &cell : ctx->cells) {

View File

@ -44,6 +44,9 @@ inline bool is_dff(const BaseCtx *ctx, const CellInfo *cell) { return cell->type
// Return true if a cell is a FE // Return true if a cell is a FE
inline bool is_fe(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == id_BEYOND_FE; } inline bool is_fe(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == id_BEYOND_FE; }
// Return true if a cell is a DFR
inline bool is_dfr(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == id_NX_DFR; }
// Process the contents of packed_cells // Process the contents of packed_cells
void NgUltraPacker::flush_cells() void NgUltraPacker::flush_cells()
{ {
@ -397,31 +400,106 @@ void NgUltraPacker::pack_iobs(void)
ci.type = new_type; ci.type = new_type;
ctx->bindBel(bel, &ci, PlaceStrength::STRENGTH_LOCKED); ctx->bindBel(bel, &ci, PlaceStrength::STRENGTH_LOCKED);
to_update.push_back(&ci);
}
int dfr_as_bfr = 0, ddrf_as_bfr = 0;
for (auto cell : to_update) {
NetInfo *c_net = cell->getPort(id_C);
if (!c_net)
log_error("C input of IO primitive %s must be connected.\n", cell->name.c_str(ctx));
if (c_net->name == ctx->id("$PACKER_GND") && !cell->getPort(id_O))
log_error("O port of IO primitive %s must be connected.\n", cell->name.c_str(ctx));
if (c_net->name == ctx->id("$PACKER_VCC") && !cell->getPort(id_I))
log_error("I port of IO primitive %s must be connected.\n", cell->name.c_str(ctx));
if (!cell->getPort(id_I) && !cell->getPort(id_O))
log_error("I or O port of IO primitive %s must be connected.\n", cell->name.c_str(ctx));
NetInfo *net = ci.getPort(id_C);
if (net && net->name.in(ctx->id("$PACKER_GND"), ctx->id("$PACKER_VCC")))
{ {
to_update.push_back(&ci); 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));
if (!iod) {
if (cell->type==id_IOTP) ddrf_as_bfr++; else dfr_as_bfr++;
iod = create_cell_ptr((cell->type==id_IOTP) ? id_DDFR : id_DFR, 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"), ""));
iod->setParam(ctx->id("type"), Property("BFR"));
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 log_error("TODO handle DFR");
Loc cd_loc = cell->getLocation();
cd_loc.z += 3;
BelId bel = ctx->getBelByLocation(cd_loc);
ctx->bindBel(bel, iod, PlaceStrength::STRENGTH_LOCKED);
}
NetInfo *i_net = cell->getPort(id_I);
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));
if (!iod) {
if (cell->type==id_IOTP) ddrf_as_bfr++; else dfr_as_bfr++;
iod = create_cell_ptr((cell->type==id_IOTP) ? id_DDFR : id_DFR, 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"), ""));
iod->setParam(ctx->id("type"), Property("BFR"));
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 log_error("TODO handle DFR");
Loc cd_loc = cell->getLocation();
cd_loc.z += 2;
BelId bel = ctx->getBelByLocation(cd_loc);
ctx->bindBel(bel, iod, PlaceStrength::STRENGTH_LOCKED);
}
NetInfo *o_net = cell->getPort(id_O);
if (o_net) {
CellInfo *iod = net_only_drives(ctx, o_net, is_dfr, id_I, true);
if (!iod) {
if (cell->type==id_IOTP) ddrf_as_bfr++; else dfr_as_bfr++;
iod = create_cell_ptr((cell->type==id_IOTP) ? id_DDFR : id_DFR, 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"), ""));
iod->setParam(ctx->id("type"), Property("BFR"));
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);
} else log_error("TODO handle DFR");
Loc cd_loc = cell->getLocation();
cd_loc.z += 1;
BelId bel = ctx->getBelByLocation(cd_loc);
ctx->bindBel(bel, iod, PlaceStrength::STRENGTH_LOCKED);
} }
} }
for (auto cell : to_update) { if (dfr_as_bfr)
CellInfo *iod_cd = create_cell_ptr((cell->type==id_IOTP) ? id_DDFR : id_DFR, ctx->id(cell->name.str(ctx) + "$iod_cd")); log_info(" %6d DFRs used as BFR\n", dfr_as_bfr);
cell->disconnectPort(id_C); if (ddrf_as_bfr)
NetInfo *new_out = ctx->createNet(ctx->id(iod_cd->name.str(ctx) + "$O")); log_info(" %6d DDFRs used as BFR\n", ddrf_as_bfr);
iod_cd->connectPort(id_O, new_out);
iod_cd->setParam(ctx->id("iobname"),str_or_default(cell->params, ctx->id("iobname"), ""));
iod_cd->setParam(ctx->id("type"), Property("BFR"));
if (cell->params[ctx->id("type")].as_string()=="IP")
iod_cd->setParam(ctx->id("mode"), Property(0, 2));
else
iod_cd->setParam(ctx->id("mode"), Property(1, 2));
cell->connectPort(id_C,new_out);
Loc loc = cell->getLocation();
loc.z += 3;
BelId bel = ctx->getBelByLocation(loc);
ctx->bindBel(bel, iod_cd, PlaceStrength::STRENGTH_LOCKED);
}
} }
void NgUltraPacker::pack_ioms(void) void NgUltraPacker::pack_ioms(void)
{ {
log_info("Pack IOMs...\n"); log_info("Pack IOMs...\n");