mirror of https://github.com/YosysHQ/nextpnr.git
add support for FF_OBF merge when Q has multiple sinks or EN is used
This commit is contained in:
parent
2b560ad0cc
commit
ec321c5b6a
|
|
@ -142,6 +142,11 @@ CellInfo *GateMatePacker::create_cell_ptr(IdString type, IdString name)
|
||||||
add_port(id_USR_PLL_LOCKED, PORT_OUT);
|
add_port(id_USR_PLL_LOCKED, PORT_OUT);
|
||||||
add_port(id_USR_PLL_LOCKED_STDY, PORT_OUT);
|
add_port(id_USR_PLL_LOCKED_STDY, PORT_OUT);
|
||||||
add_port(id_USR_LOCKED_STDY_RST, PORT_IN);
|
add_port(id_USR_LOCKED_STDY_RST, PORT_IN);
|
||||||
|
} else if (type.in(id_CC_MX2)) {
|
||||||
|
add_port(id_D0, PORT_IN);
|
||||||
|
add_port(id_D1, PORT_IN);
|
||||||
|
add_port(id_S0, PORT_IN);
|
||||||
|
add_port(id_Y, PORT_OUT);
|
||||||
} else {
|
} else {
|
||||||
log_error("Trying to create unknown cell type %s.\n", type.c_str(ctx));
|
log_error("Trying to create unknown cell type %s.\n", type.c_str(ctx));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,8 @@ struct GateMatePacker
|
||||||
std::pair<CellInfo *, CellInfo *> move_ram_io_fixed(CellInfo *cell, IdString iPort, IdString oPort, Loc fixed);
|
std::pair<CellInfo *, CellInfo *> move_ram_io_fixed(CellInfo *cell, IdString iPort, IdString oPort, Loc fixed);
|
||||||
uint8_t ram_ctrl_signal(CellInfo *cell, IdString port, bool alt);
|
uint8_t ram_ctrl_signal(CellInfo *cell, IdString port, bool alt);
|
||||||
uint8_t ram_clk_signal(CellInfo *cell, IdString port);
|
uint8_t ram_clk_signal(CellInfo *cell, IdString port);
|
||||||
bool is_gpio_valid_dff(CellInfo *dff);
|
bool is_gpio_out_valid_dff(CellInfo *dff);
|
||||||
|
bool is_gpio_in_valid_dff(CellInfo *dff);
|
||||||
bool are_ffs_compatible(CellInfo *dff, CellInfo *other);
|
bool are_ffs_compatible(CellInfo *dff, CellInfo *other);
|
||||||
|
|
||||||
// Cell creating
|
// Cell creating
|
||||||
|
|
|
||||||
|
|
@ -390,7 +390,7 @@ void GateMatePacker::pack_io_sel()
|
||||||
cell->disconnectPort(id_CLK);
|
cell->disconnectPort(id_CLK);
|
||||||
} else {
|
} else {
|
||||||
if (!uarch->global_signals.count(clk_net)) {
|
if (!uarch->global_signals.count(clk_net)) {
|
||||||
cell->movePortTo(id_CLK, target, id_OUT4);
|
cell->copyPortTo(id_CLK, target, id_OUT4);
|
||||||
target->params[id_SEL_OUT_CLOCK] = Property(Property::State::S1);
|
target->params[id_SEL_OUT_CLOCK] = Property(Property::State::S1);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -401,7 +401,7 @@ void GateMatePacker::pack_io_sel()
|
||||||
log_error("Not able to connected different CLK signal to cell '%s'.\n",
|
log_error("Not able to connected different CLK signal to cell '%s'.\n",
|
||||||
cell->name.c_str(ctx));
|
cell->name.c_str(ctx));
|
||||||
} else {
|
} else {
|
||||||
cell->movePortTo(id_CLK, target, ctx->idf("CLOCK%d", index + 1));
|
cell->copyPortTo(id_CLK, target, ctx->idf("CLOCK%d", index + 1));
|
||||||
}
|
}
|
||||||
target->params[id_OUT_CLOCK] = Property(index, 2);
|
target->params[id_OUT_CLOCK] = Property(index, 2);
|
||||||
}
|
}
|
||||||
|
|
@ -438,7 +438,7 @@ void GateMatePacker::pack_io_sel()
|
||||||
|
|
||||||
auto merge_ibf = [&](NetInfo *di_net, CellInfo &ci, bool use_custom_clock) -> bool {
|
auto merge_ibf = [&](NetInfo *di_net, CellInfo &ci, bool use_custom_clock) -> bool {
|
||||||
CellInfo *dff = (*di_net->users.begin()).cell;
|
CellInfo *dff = (*di_net->users.begin()).cell;
|
||||||
if (is_gpio_valid_dff(dff)) {
|
if (is_gpio_in_valid_dff(dff)) {
|
||||||
if (!uarch->global_signals.count(ci.getPort(id_CLK)) && use_custom_clock) {
|
if (!uarch->global_signals.count(ci.getPort(id_CLK)) && use_custom_clock) {
|
||||||
log_warning("Found DFF %s cell, but not enough CLK signals.\n", dff->name.c_str(ctx));
|
log_warning("Found DFF %s cell, but not enough CLK signals.\n", dff->name.c_str(ctx));
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -516,25 +516,51 @@ void GateMatePacker::pack_io_sel()
|
||||||
} else {
|
} else {
|
||||||
ci.params[id_OUT_SIGNAL] = Property(Property::State::S1);
|
ci.params[id_OUT_SIGNAL] = Property(Property::State::S1);
|
||||||
bool ff_obf_merged = false;
|
bool ff_obf_merged = false;
|
||||||
if (ff_obf && do_net->driver.cell && do_net->driver.cell->type == id_CC_DFF &&
|
if (ff_obf && do_net->driver.cell && do_net->driver.cell->type == id_CC_DFF) {
|
||||||
do_net->users.entries() == 1) {
|
|
||||||
CellInfo *dff = do_net->driver.cell;
|
CellInfo *dff = do_net->driver.cell;
|
||||||
if (is_gpio_valid_dff(dff)) {
|
if (is_gpio_out_valid_dff(dff)) {
|
||||||
ci.params[id_OUT1_FF] = Property(Property::State::S1);
|
ci.params[id_OUT1_FF] = Property(Property::State::S1);
|
||||||
packed_cells.emplace(dff->name);
|
|
||||||
ci.disconnectPort(id_A);
|
ci.disconnectPort(id_A);
|
||||||
dff->movePortTo(id_D, &ci, id_OUT1);
|
dff->copyPortTo(id_D, &ci, id_OUT1);
|
||||||
use_custom_clock = set_out_clk(dff, &ci);
|
use_custom_clock = set_out_clk(dff, &ci);
|
||||||
bool invert = bool_or_default(dff->params, id_CLK_INV, 0);
|
bool invert = bool_or_default(dff->params, id_CLK_INV, 0);
|
||||||
if (invert) {
|
if (invert) {
|
||||||
ci.params[id_INV_OUT1_CLOCK] = Property(Property::State::S1);
|
ci.params[id_INV_OUT1_CLOCK] = Property(Property::State::S1);
|
||||||
ci.params[id_INV_OUT2_CLOCK] = Property(Property::State::S1);
|
ci.params[id_INV_OUT2_CLOCK] = Property(Property::State::S1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetInfo *en_net = dff->getPort(id_EN);
|
||||||
|
bool en_invert = bool_or_default(dff->params, id_EN_INV, 0);
|
||||||
|
if ((en_net == net_PACKER_GND && en_invert) || (en_net == net_PACKER_VCC && !en_invert)) {
|
||||||
|
dff->disconnectPort(id_EN);
|
||||||
|
dff->unsetParam(id_EN_INV);
|
||||||
|
en_net = nullptr;
|
||||||
|
}
|
||||||
|
if (en_net) {
|
||||||
|
// enable not supprted -> build external enable logic
|
||||||
|
CellInfo *enmux = create_cell_ptr(id_CC_MX2, ctx->idf("%s$enmux", ci.name.c_str(ctx)));
|
||||||
|
if (!en_invert) {
|
||||||
|
enmux->connectPort(id_D0, do_net);
|
||||||
|
dff->copyPortTo(id_D, enmux, id_D1);
|
||||||
|
} else {
|
||||||
|
dff->copyPortTo(id_D, enmux, id_D0);
|
||||||
|
enmux->connectPort(id_D1, do_net);
|
||||||
|
}
|
||||||
|
enmux->connectPort(id_S0, en_net);
|
||||||
|
ci.disconnectPort(id_OUT1);
|
||||||
|
enmux->connectPorts(id_Y, &ci, id_OUT1);
|
||||||
|
}
|
||||||
|
|
||||||
ff_obf_merged = true;
|
ff_obf_merged = true;
|
||||||
|
if (do_net->users.empty()) {
|
||||||
|
packed_cells.emplace(dff->name);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log_warning("DFF '%s' cell for IO '%s', but unable to merge.\n", dff->name.c_str(ctx),
|
log_warning("DFF '%s' cell for IO '%s', but unable to merge.\n", dff->name.c_str(ctx),
|
||||||
ci.name.c_str(ctx));
|
ci.name.c_str(ctx));
|
||||||
}
|
}
|
||||||
|
} else if (ff_obf && do_net->driver.cell && do_net->driver.cell->type != id_CC_ODDR) {
|
||||||
|
log_warning("FF_OBF set for IO '%s', but not driven by DFF.\n", ci.name.c_str(ctx));
|
||||||
}
|
}
|
||||||
bool oddr_merged = false;
|
bool oddr_merged = false;
|
||||||
if (do_net->driver.cell && do_net->driver.cell->type == id_CC_LUT1 && do_net->users.entries() == 1) {
|
if (do_net->driver.cell && do_net->driver.cell->type == id_CC_LUT1 && do_net->users.entries() == 1) {
|
||||||
|
|
@ -612,27 +638,10 @@ void GateMatePacker::pack_io_sel()
|
||||||
flush_cells();
|
flush_cells();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GateMatePacker::is_gpio_valid_dff(CellInfo *dff)
|
bool GateMatePacker::is_gpio_out_valid_dff(CellInfo *dff)
|
||||||
{
|
{
|
||||||
NetInfo *en_net = dff->getPort(id_EN);
|
|
||||||
bool invert = bool_or_default(dff->params, id_EN_INV, 0);
|
|
||||||
if (en_net) {
|
|
||||||
if (en_net == net_PACKER_GND) {
|
|
||||||
if (!invert)
|
|
||||||
return false;
|
|
||||||
dff->disconnectPort(id_EN);
|
|
||||||
} else if (en_net == net_PACKER_VCC) {
|
|
||||||
if (invert)
|
|
||||||
return false;
|
|
||||||
dff->disconnectPort(id_EN);
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dff->unsetParam(id_EN_INV);
|
|
||||||
|
|
||||||
NetInfo *sr_net = dff->getPort(id_SR);
|
NetInfo *sr_net = dff->getPort(id_SR);
|
||||||
invert = bool_or_default(dff->params, id_SR_INV, 0);
|
bool invert = bool_or_default(dff->params, id_SR_INV, 0);
|
||||||
if (sr_net) {
|
if (sr_net) {
|
||||||
if ((sr_net == net_PACKER_GND) || (sr_net == net_PACKER_VCC)) {
|
if ((sr_net == net_PACKER_GND) || (sr_net == net_PACKER_VCC)) {
|
||||||
bool sr_signal = sr_net == net_PACKER_VCC;
|
bool sr_signal = sr_net == net_PACKER_VCC;
|
||||||
|
|
@ -661,4 +670,26 @@ bool GateMatePacker::is_gpio_valid_dff(CellInfo *dff)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GateMatePacker::is_gpio_in_valid_dff(CellInfo *dff)
|
||||||
|
{
|
||||||
|
NetInfo *en_net = dff->getPort(id_EN);
|
||||||
|
bool invert = bool_or_default(dff->params, id_EN_INV, 0);
|
||||||
|
if (en_net) {
|
||||||
|
if (en_net == net_PACKER_GND) {
|
||||||
|
if (!invert)
|
||||||
|
return false;
|
||||||
|
dff->disconnectPort(id_EN);
|
||||||
|
} else if (en_net == net_PACKER_VCC) {
|
||||||
|
if (invert)
|
||||||
|
return false;
|
||||||
|
dff->disconnectPort(id_EN);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dff->unsetParam(id_EN_INV);
|
||||||
|
|
||||||
|
return is_gpio_out_valid_dff(dff);
|
||||||
|
}
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue