aboutsummaryrefslogtreecommitdiffstats
path: root/ice40
diff options
context:
space:
mode:
authorgatecat <gatecat@ds0.me>2022-04-11 18:46:44 +0100
committergatecat <gatecat@ds0.me>2022-04-11 18:46:44 +0100
commitd3ba259db2d857a075113706cec2fad9a00c3f72 (patch)
treea6082353df4665469618b74e208ec574c0223b42 /ice40
parent9067d954f4b712d858403472b4a54970a562fc8e (diff)
downloadnextpnr-d3ba259db2d857a075113706cec2fad9a00c3f72.tar.gz
nextpnr-d3ba259db2d857a075113706cec2fad9a00c3f72.tar.bz2
nextpnr-d3ba259db2d857a075113706cec2fad9a00c3f72.zip
ice40: Avoid chain finder from mixing up chains by only allowing I3 chaining at end
Signed-off-by: gatecat <gatecat@ds0.me>
Diffstat (limited to 'ice40')
-rw-r--r--ice40/chains.cc79
1 files changed, 45 insertions, 34 deletions
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<CellChain> 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<IdString> chained;
- for (auto &base_chain : carry_chains) {
- for (auto c : base_chain.cells)
- chained.insert(c->name);
+ // Find carry roots
+ std::vector<CellChain> carry_chains;
+ pool<IdString> 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<CellChain> all_chains;