aboutsummaryrefslogtreecommitdiffstats
path: root/nexus
diff options
context:
space:
mode:
authorMaciej Kurc <mkurc@antmicro.com>2021-11-19 12:09:55 +0100
committerMaciej Kurc <mkurc@antmicro.com>2021-11-22 10:23:24 +0100
commit5bc97c94ae91af045eb522ae770576c478275d7f (patch)
treee3d5659ae9dd2049c0b153fa203587a857b4975f /nexus
parent086bcf06153ea820b27f84b70b36fba77a975404 (diff)
downloadnextpnr-5bc97c94ae91af045eb522ae770576c478275d7f.tar.gz
nextpnr-5bc97c94ae91af045eb522ae770576c478275d7f.tar.bz2
nextpnr-5bc97c94ae91af045eb522ae770576c478275d7f.zip
Added appending FFs to other existing LUT cluster types (carry, widefn)
Signed-off-by: Maciej Kurc <mkurc@antmicro.com>
Diffstat (limited to 'nexus')
-rw-r--r--nexus/pack.cc85
1 files changed, 67 insertions, 18 deletions
diff --git a/nexus/pack.cc b/nexus/pack.cc
index a3dc7266..be298ef0 100644
--- a/nexus/pack.cc
+++ b/nexus/pack.cc
@@ -2310,6 +2310,7 @@ struct NexusPacker
size_t num_comb = 0;
size_t num_ff = 0;
size_t num_pair = 0;
+ size_t num_glue = 0;
for (auto &cell : ctx->cells) {
CellInfo *ff = cell.second.get();
@@ -2320,44 +2321,91 @@ struct NexusPacker
num_ff++;
// Get input net
- NetInfo *di = get_net_or_empty(ff, id_M); // At the packing stage all inputs go to M
+ // At the packing stage all inputs go to M
+ NetInfo *di = get_net_or_empty(ff, id_M);
if (di == nullptr || di->driver.cell == nullptr) {
continue;
}
- // Skip if there are multiple sinks
+ // Skip if there are multiple sinks on that net
if (di->users.size() != 1) {
continue;
}
// Check if the driver is a LUT and the direct connection is from F
CellInfo* lut = di->driver.cell;
- if (lut->type != id_OXIDE_COMB || di->driver.port != id_F) {
+ if (lut->type != id_OXIDE_COMB) {
+ continue;
+ }
+ if (di->driver.port != id_F &&
+ di->driver.port != id_F1 &&
+ di->driver.port != id_OFX)
+ {
+ continue;
+ }
+
+ // The FF must not use M and DI at the same time
+ if (get_net_or_empty(ff, id_DI)) {
continue;
}
- // The LUT must be in LOGIC mode
- if (str_or_default(lut->params, id_MODE, "LOGIC") != "LOGIC") {
+ // The LUT must be in LOGIC/CARRY mode
+ if (str_or_default(lut->params, id_MODE, "LOGIC") != "LOGIC" &&
+ str_or_default(lut->params, id_MODE, "LOGIC") != "CCU2") {
continue;
}
- // Skip clusters
- // FIXME: In case of carry chain make the LUTFF part of the chain
- if (lut->cluster != ClusterId() || ff->cluster != ClusterId()) {
+ // The FF cannot be in another cluster
+ if (ff->cluster != ClusterId()) {
continue;
}
- // Make a cluster
- lut->cluster = lut->name;
- lut->constr_children.push_back(ff);
+ // A free LUT, create a new cluster
+ if (lut->cluster == ClusterId()) {
+
+ lut->cluster = lut->name;
+ lut->constr_children.push_back(ff);
+
+ ff->cluster = lut->name;
+ ff->constr_x = 0;
+ ff->constr_y = 0;
+ ff->constr_z = 2;
+ ff->constr_abs_z = false;
+
+ num_pair++;
+ }
+ // Attach the FF to the existing cluster of the LUT
+ else {
+
+ // Find the cluster root
+ CellInfo* root = nullptr;
+ if (!lut->constr_children.empty()) {
+ root = lut;
+ }
+ else {
+ for (auto &it : ctx->cells) {
+ if (it.second->cluster == lut->cluster && !it.second->constr_children.empty()) {
+ root = it.second.get();
+ break;
+ }
+ }
+ }
+ NPNR_ASSERT(root != nullptr);
+
+ // Constrain the FF relative to the LUT
+ ff->cluster = root->cluster;
+ ff->constr_x = lut->constr_x;
+ ff->constr_y = lut->constr_y;
+ ff->constr_z = lut->constr_z + 2;
+ ff->constr_abs_z = false;
+ root->constr_children.push_back(ff);
- ff->cluster = lut->name;
- ff->constr_x = 0;
- ff->constr_y = 0;
- ff->constr_z = 2;
- ff->constr_abs_z = false;
+ num_glue++;
+ }
- num_pair++;
+ // Reconnect M to DI
+ rename_port(ctx, ff, id_M, id_DI);
+ ff->params[id_SEL] = std::string("DL");
}
// Count OXIDE_COMB, OXIDE_FF are already counted
@@ -2369,8 +2417,9 @@ struct NexusPacker
}
// Print statistics
- log_info(" Created %zu LUT+FF pairs from %zu FFs and %zu LUTs\n",
+ log_info(" Created %zu LUT+FF pairs and extended %zu clusters using total %zu FFs and %zu LUTs\n",
num_pair,
+ num_glue,
num_ff,
num_comb
);