aboutsummaryrefslogtreecommitdiffstats
path: root/passes/opt/opt_lut.cc
diff options
context:
space:
mode:
Diffstat (limited to 'passes/opt/opt_lut.cc')
-rw-r--r--passes/opt/opt_lut.cc120
1 files changed, 112 insertions, 8 deletions
diff --git a/passes/opt/opt_lut.cc b/passes/opt/opt_lut.cc
index be050c713..26855fd70 100644
--- a/passes/opt/opt_lut.cc
+++ b/passes/opt/opt_lut.cc
@@ -36,7 +36,7 @@ struct OptLutWorker
dict<RTLIL::Cell*, pool<RTLIL::Cell*>> luts_dlogics;
dict<RTLIL::Cell*, pool<int>> luts_dlogic_inputs;
- int combined_count = 0;
+ int eliminated_count = 0, combined_count = 0;
bool evaluate_lut(RTLIL::Cell *lut, dict<SigBit, bool> inputs)
{
@@ -133,7 +133,7 @@ struct OptLutWorker
// Second, make sure that the connection to dedicated logic is legal. If it is not legal,
// it means one of the two things:
// * The connection is spurious. I.e. this is dedicated logic that will be packed
- // with some other LUT, and it just happens to be conected to this LUT as well.
+ // with some other LUT, and it just happens to be connected to this LUT as well.
// * The connection is illegal.
// In either of these cases, we don't need to concern ourselves with preserving the connection
// between this LUT and this dedicated logic cell.
@@ -188,7 +188,7 @@ struct OptLutWorker
show_stats_by_arity();
log("\n");
- log("Combining LUTs.\n");
+ log("Eliminating LUTs.\n");
pool<RTLIL::Cell*> worklist = luts;
while (worklist.size())
{
@@ -198,6 +198,106 @@ struct OptLutWorker
break;
}
+ auto lut = worklist.pop();
+ SigSpec lut_input = sigmap(lut->getPort("\\A"));
+ pool<int> &lut_dlogic_inputs = luts_dlogic_inputs[lut];
+
+ vector<SigBit> lut_inputs;
+ for (auto &bit : lut_input)
+ {
+ if (bit.wire)
+ lut_inputs.push_back(sigmap(bit));
+ }
+
+ bool const0_match = true;
+ bool const1_match = true;
+ vector<bool> input_matches;
+ for (size_t i = 0; i < lut_inputs.size(); i++)
+ input_matches.push_back(true);
+
+ for (int eval = 0; eval < 1 << lut_inputs.size(); eval++)
+ {
+ dict<SigBit, bool> eval_inputs;
+ for (size_t i = 0; i < lut_inputs.size(); i++)
+ eval_inputs[lut_inputs[i]] = (eval >> i) & 1;
+ bool value = evaluate_lut(lut, eval_inputs);
+ if (value != 0)
+ const0_match = false;
+ if (value != 1)
+ const1_match = false;
+ for (size_t i = 0; i < lut_inputs.size(); i++)
+ {
+ if (value != eval_inputs[lut_inputs[i]])
+ input_matches[i] = false;
+ }
+ }
+
+ int input_match = -1;
+ for (size_t i = 0; i < lut_inputs.size(); i++)
+ if (input_matches[i])
+ input_match = i;
+
+ if (const0_match || const1_match || input_match != -1)
+ {
+ log("Found redundant cell %s.%s.\n", log_id(module), log_id(lut));
+
+ SigBit value;
+ if (const0_match)
+ {
+ log(" Cell evaluates constant 0.\n");
+ value = State::S0;
+ }
+ if (const1_match)
+ {
+ log(" Cell evaluates constant 1.\n");
+ value = State::S1;
+ }
+ if (input_match != -1) {
+ log(" Cell evaluates signal %s.\n", log_signal(lut_inputs[input_match]));
+ value = lut_inputs[input_match];
+ }
+
+ if (lut_dlogic_inputs.size())
+ {
+ log(" Not eliminating cell (connected to dedicated logic).\n");
+ }
+ else
+ {
+ SigSpec lut_output = lut->getPort("\\Y");
+ for (auto &port : index.query_ports(lut_output))
+ {
+ if (port.cell != lut && luts.count(port.cell))
+ worklist.insert(port.cell);
+ }
+
+ module->connect(lut_output, value);
+ sigmap.add(lut_output, value);
+
+ module->remove(lut);
+ luts.erase(lut);
+ luts_arity.erase(lut);
+ luts_dlogics.erase(lut);
+ luts_dlogic_inputs.erase(lut);
+
+ eliminated_count++;
+ if (limit > 0)
+ limit--;
+ }
+ }
+ }
+ show_stats_by_arity();
+
+ log("\n");
+ log("Combining LUTs.\n");
+ worklist = luts;
+ while (worklist.size())
+ {
+ if (limit == 0)
+ {
+ log("Limit reached.\n");
+ break;
+ }
+
auto lutA = worklist.pop();
SigSpec lutA_input = sigmap(lutA->getPort("\\A"));
SigSpec lutA_output = sigmap(lutA->getPort("\\Y")[0]);
@@ -487,16 +587,20 @@ struct OptLutPass : public Pass {
}
extra_args(args, argidx, design);
- int total_count = 0;
+ int eliminated_count = 0, combined_count = 0;
for (auto module : design->selected_modules())
{
- OptLutWorker worker(dlogic, module, limit - total_count);
- total_count += worker.combined_count;
+ OptLutWorker worker(dlogic, module, limit - eliminated_count - combined_count);
+ eliminated_count += worker.eliminated_count;
+ combined_count += worker.combined_count;
}
- if (total_count)
+ if (eliminated_count)
+ design->scratchpad_set_bool("opt.did_something", true);
+ if (combined_count)
design->scratchpad_set_bool("opt.did_something", true);
log("\n");
- log("Combined %d LUTs.\n", total_count);
+ log("Eliminated %d LUTs.\n", eliminated_count);
+ log("Combined %d LUTs.\n", combined_count);
}
} OptLutPass;