From d3ba259db2d857a075113706cec2fad9a00c3f72 Mon Sep 17 00:00:00 2001 From: gatecat Date: Mon, 11 Apr 2022 18:46:44 +0100 Subject: ice40: Avoid chain finder from mixing up chains by only allowing I3 chaining at end Signed-off-by: gatecat --- ice40/chains.cc | 79 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 34 deletions(-) (limited to 'ice40') diff --git a/ice40/chains.cc b/ice40/chains.cc index 6ea261de..20edafaa 100644 --- a/ice40/chains.cc +++ b/ice40/chains.cc @@ -183,43 +183,54 @@ class ChainConstrainer void process_carries() { - std::vector carry_chains = find_chains( - ctx, [](const Context *ctx, const CellInfo *cell) { return is_lc(ctx, cell); }, - [](const Context *ctx, const - - 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 chained; - for (auto &base_chain : carry_chains) { - for (auto c : base_chain.cells) - chained.insert(c->name); + // Find carry roots + std::vector carry_chains; + pool processed; + for (auto &cell : ctx->cells) { + CellInfo *ci = cell.second.get(); + if (is_lc(ctx, ci) && bool_or_default(ci->params, id_CARRY_ENABLE)) { + // possibly a non-root if CIN or I3 driven by another cout + NetInfo *cin = ci->getPort(id_CIN); + if (cin && cin->driver.cell && is_lc(ctx, cin->driver.cell) && cin->driver.port == id_COUT) { + continue; + } + 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; + } + } + } + } } - // Any cells not in chains, but with carry enabled, must also be put in a single-carry chain - // for correct processing + // anything left behind.... for (auto &cell : ctx->cells) { CellInfo *ci = cell.second.get(); - if (chained.find(cell.first) == chained.end() && is_lc(ctx, ci) && - bool_or_default(ci->params, id_CARRY_ENABLE)) { - CellChain sChain; - sChain.cells.push_back(ci); - chained.insert(cell.first); - carry_chains.push_back(sChain); + 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 all_chains; -- cgit v1.2.3