From a8ab7228240fb227f4178ca02037cdcf897ee19e Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 7 Dec 2018 16:31:15 +0000 Subject: [PATCH 1/3] opt_lut: add -limit option, for debugging misoptimizations. --- passes/opt/opt_lut.cc | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/passes/opt/opt_lut.cc b/passes/opt/opt_lut.cc index befe346a3..ee3943f9c 100644 --- a/passes/opt/opt_lut.cc +++ b/passes/opt/opt_lut.cc @@ -93,7 +93,7 @@ struct OptLutWorker } } - OptLutWorker(dict> &dlogic, RTLIL::Module *module) : + OptLutWorker(dict> &dlogic, RTLIL::Module *module, int limit) : dlogic(dlogic), module(module), index(module), sigmap(module) { log("Discovering LUTs.\n"); @@ -192,6 +192,12 @@ struct OptLutWorker pool 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]); @@ -398,6 +404,8 @@ struct OptLutWorker worklist.erase(lutR); combined_count++; + if (limit > 0) + limit--; } } } @@ -431,17 +439,22 @@ struct OptLutPass : public Pass { log(" the case where both LUT and dedicated logic input are connected to\n"); log(" the same constant.\n"); log("\n"); + log(" -limit N\n"); + log(" only perform the first N combines, then stop. useful for debugging.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing OPT_LUT pass (optimize LUTs).\n"); dict> dlogic; + int limit = -1; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - if (args[argidx] == "-dlogic" && argidx+1 < args.size()) { + if (args[argidx] == "-dlogic" && argidx+1 < args.size()) + { std::vector tokens; split(tokens, args[++argidx], ':'); if (tokens.size() < 2) @@ -458,6 +471,11 @@ struct OptLutPass : public Pass { } continue; } + if (args[argidx] == "-limit" && argidx + 1 < args.size()) + { + limit = atoi(args[++argidx].c_str()); + continue; + } break; } extra_args(args, argidx, design); @@ -465,7 +483,7 @@ struct OptLutPass : public Pass { int total_count = 0; for (auto module : design->selected_modules()) { - OptLutWorker worker(dlogic, module); + OptLutWorker worker(dlogic, module, limit - total_count); total_count += worker.combined_count; } if (total_count) From 9eb03d458dcb2a3ba91a84739e764558b26e335c Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 7 Dec 2018 17:04:41 +0000 Subject: [PATCH 2/3] opt_lut: show original truth table for both cells. --- passes/opt/opt_lut.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/passes/opt/opt_lut.cc b/passes/opt/opt_lut.cc index ee3943f9c..4207fbdb9 100644 --- a/passes/opt/opt_lut.cc +++ b/passes/opt/opt_lut.cc @@ -388,8 +388,9 @@ struct OptLutWorker lutM_new_table[eval] = (RTLIL::State) evaluate_lut(lutB, eval_inputs); } - log(" Old truth table: %s.\n", lutM->getParam("\\LUT").as_string().c_str()); - log(" New truth table: %s.\n", lutM_new_table.as_string().c_str()); + log(" Cell A truth table: %s.\n", lutA->getParam("\\LUT").as_string().c_str()); + log(" Cell B truth table: %s.\n", lutB->getParam("\\LUT").as_string().c_str()); + log(" Merged truth table: %s.\n", lutM_new_table.as_string().c_str()); lutM->setParam("\\LUT", lutM_new_table); lutM->setPort("\\A", lutM_new_inputs); From 7ec740b7ad4ee4bc02e2564671e0153cdd08152f Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 7 Dec 2018 17:13:52 +0000 Subject: [PATCH 3/3] opt_lut: leave intact LUTs with cascade feeding module outputs. --- passes/opt/opt_lut.cc | 6 ++++++ tests/opt/opt_lut_port.il | 18 ++++++++++++++++++ tests/opt/opt_lut_port.ys | 2 ++ 3 files changed, 26 insertions(+) create mode 100644 tests/opt/opt_lut_port.il create mode 100644 tests/opt/opt_lut_port.ys diff --git a/passes/opt/opt_lut.cc b/passes/opt/opt_lut.cc index 4207fbdb9..ba2cc6ee7 100644 --- a/passes/opt/opt_lut.cc +++ b/passes/opt/opt_lut.cc @@ -225,6 +225,12 @@ struct OptLutWorker log("Found %s.%s (cell A) feeding %s.%s (cell B).\n", log_id(module), log_id(lutA), log_id(module), log_id(lutB)); + if (index.query_is_output(lutA->getPort("\\Y"))) + { + log(" Not combining LUTs (cascade connection feeds module output).\n"); + continue; + } + pool lutA_inputs; pool lutB_inputs; for (auto &bit : lutA_input) diff --git a/tests/opt/opt_lut_port.il b/tests/opt/opt_lut_port.il new file mode 100644 index 000000000..7eb71890f --- /dev/null +++ b/tests/opt/opt_lut_port.il @@ -0,0 +1,18 @@ +module $1 + wire width 4 input 2 \_0_ + wire output 4 \_1_ + wire input 3 \_2_ + wire output 1 \o + cell $lut \_3_ + parameter \LUT 16'0011000000000011 + parameter \WIDTH 4 + connect \A { \_0_ [3] \o 2'00 } + connect \Y \_1_ + end + cell $lut \_4_ + parameter \LUT 4'0001 + parameter \WIDTH 4 + connect \A { 3'000 \_2_ } + connect \Y \o + end +end diff --git a/tests/opt/opt_lut_port.ys b/tests/opt/opt_lut_port.ys new file mode 100644 index 000000000..51dfd988b --- /dev/null +++ b/tests/opt/opt_lut_port.ys @@ -0,0 +1,2 @@ +read_ilang opt_lut_port.il +select -assert-count 2 t:$lut