ice40: Avoid chain finder from mixing up chains by only allowing I3 chaining at end
Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
parent
9067d954f4
commit
d3ba259db2
@ -183,43 +183,54 @@ class ChainConstrainer
|
|||||||
|
|
||||||
void process_carries()
|
void process_carries()
|
||||||
{
|
{
|
||||||
std::vector<CellChain> carry_chains = find_chains(
|
// Find carry roots
|
||||||
ctx, [](const Context *ctx, const CellInfo *cell) { return is_lc(ctx, cell); },
|
std::vector<CellChain> carry_chains;
|
||||||
[](const Context *ctx, const
|
pool<IdString> processed;
|
||||||
|
|
||||||
CellInfo *cell) {
|
|
||||||
CellInfo *carry_prev = net_driven_by(ctx, cell->ports.at(id_CIN).net, is_lc, id_COUT);
|
|
||||||
if (carry_prev != nullptr)
|
|
||||||
return carry_prev;
|
|
||||||
CellInfo *i3_prev = net_driven_by(ctx, cell->ports.at(id_I3).net, is_lc, id_COUT);
|
|
||||||
if (i3_prev != nullptr)
|
|
||||||
return i3_prev;
|
|
||||||
return (CellInfo *)nullptr;
|
|
||||||
},
|
|
||||||
[](const Context *ctx, const CellInfo *cell) {
|
|
||||||
CellInfo *carry_next = net_only_drives(ctx, cell->ports.at(id_COUT).net, is_lc, id_CIN, false);
|
|
||||||
if (carry_next != nullptr)
|
|
||||||
return carry_next;
|
|
||||||
CellInfo *i3_next = net_only_drives(ctx, cell->ports.at(id_COUT).net, is_lc, id_I3, false);
|
|
||||||
if (i3_next != nullptr)
|
|
||||||
return i3_next;
|
|
||||||
return (CellInfo *)nullptr;
|
|
||||||
});
|
|
||||||
pool<IdString> chained;
|
|
||||||
for (auto &base_chain : carry_chains) {
|
|
||||||
for (auto c : base_chain.cells)
|
|
||||||
chained.insert(c->name);
|
|
||||||
}
|
|
||||||
// Any cells not in chains, but with carry enabled, must also be put in a single-carry chain
|
|
||||||
// for correct processing
|
|
||||||
for (auto &cell : ctx->cells) {
|
for (auto &cell : ctx->cells) {
|
||||||
CellInfo *ci = cell.second.get();
|
CellInfo *ci = cell.second.get();
|
||||||
if (chained.find(cell.first) == chained.end() && is_lc(ctx, ci) &&
|
if (is_lc(ctx, ci) && bool_or_default(ci->params, id_CARRY_ENABLE)) {
|
||||||
bool_or_default(ci->params, id_CARRY_ENABLE)) {
|
// possibly a non-root if CIN or I3 driven by another cout
|
||||||
CellChain sChain;
|
NetInfo *cin = ci->getPort(id_CIN);
|
||||||
sChain.cells.push_back(ci);
|
if (cin && cin->driver.cell && is_lc(ctx, cin->driver.cell) && cin->driver.port == id_COUT) {
|
||||||
chained.insert(cell.first);
|
continue;
|
||||||
carry_chains.push_back(sChain);
|
}
|
||||||
|
carry_chains.emplace_back();
|
||||||
|
auto &cc = carry_chains.back();
|
||||||
|
CellInfo *cursor = ci;
|
||||||
|
while (cursor) {
|
||||||
|
cc.cells.push_back(cursor);
|
||||||
|
processed.insert(cursor->name);
|
||||||
|
NetInfo *cout = cursor->getPort(id_COUT);
|
||||||
|
if (!cout)
|
||||||
|
break;
|
||||||
|
cursor = nullptr;
|
||||||
|
// look for CIN connectivity
|
||||||
|
for (auto &usr : cout->users) {
|
||||||
|
if (is_lc(ctx, usr.cell) && usr.port == id_CIN && !processed.count(usr.cell->name)) {
|
||||||
|
cursor = usr.cell;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// look for I3 connectivity - only to a top cell with no further chaining
|
||||||
|
if (cursor)
|
||||||
|
continue;
|
||||||
|
for (auto &usr : cout->users) {
|
||||||
|
if (is_lc(ctx, usr.cell) && usr.port == id_I3 && !processed.count(usr.cell->name) &&
|
||||||
|
!usr.cell->getPort(id_COUT)) {
|
||||||
|
cursor = usr.cell;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// anything left behind....
|
||||||
|
for (auto &cell : ctx->cells) {
|
||||||
|
CellInfo *ci = cell.second.get();
|
||||||
|
if (is_lc(ctx, ci) && bool_or_default(ci->params, id_CARRY_ENABLE) && !processed.count(ci->name)) {
|
||||||
|
carry_chains.emplace_back();
|
||||||
|
carry_chains.back().cells.push_back(ci);
|
||||||
|
processed.insert(ci->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::vector<CellChain> all_chains;
|
std::vector<CellChain> all_chains;
|
||||||
|
Loading…
Reference in New Issue
Block a user