abc9_ops: -prep_lut and -write_lut to auto-generate LUT library
authorEddie Hung <eddie@fpgeh.com>
Tue, 11 Feb 2020 16:34:13 +0000 (08:34 -0800)
committerEddie Hung <eddie@fpgeh.com>
Thu, 27 Feb 2020 18:17:29 +0000 (10:17 -0800)
passes/techmap/abc9.cc
passes/techmap/abc9_ops.cc
techlibs/xilinx/cells_sim.v
techlibs/xilinx/synth_xilinx.cc

index 5ae2fb22a0e22b8b199b613dd9a6aadd0934734f..0e2ca80c724a9d670950a7f5102c9346a8a2f7f2 100644 (file)
@@ -145,6 +145,11 @@ struct Abc9Pass : public ScriptPass
                log("        generate netlist using luts. Use the specified costs for luts with 1,\n");
                log("        2, 3, .. inputs.\n");
                log("\n");
+               log("    -maxlut <width>\n");
+               log("        when auto-generating the lut library, discard all luts equal to or\n");
+               log("        greater than this size (applicable when neither -lut nor -luts is\n");
+               log("        specified).\n");
+               log("\n");
                log("    -dff\n");
                log("        also pass $_ABC9_FF_ cells through to ABC. modules with many clock\n");
                log("        domains are marked as such and automatically partitioned by ABC.\n");
@@ -175,6 +180,8 @@ struct Abc9Pass : public ScriptPass
 
        std::stringstream exe_cmd;
        bool dff_mode, cleanup;
+       bool lut_mode;
+       int maxlut;
        std::string box_file;
 
        void clear_flags() YS_OVERRIDE
@@ -183,6 +190,8 @@ struct Abc9Pass : public ScriptPass
                exe_cmd << "abc9_exe";
                dff_mode = false;
                cleanup = true;
+               lut_mode = false;
+               maxlut = 0;
                box_file.clear();
        }
 
@@ -204,9 +213,11 @@ struct Abc9Pass : public ScriptPass
                for (argidx = 1; argidx < args.size(); argidx++) {
                        std::string arg = args[argidx];
                        if ((arg == "-exe" || arg == "-script" || arg == "-D" ||
-                                               /* arg == "-S" || */ arg == "-lut" || arg == "-luts" ||
+                                               /*arg == "-S" ||*/ arg == "-lut" || arg == "-luts" ||
                                                /*arg == "-box" ||*/ arg == "-W") &&
                                        argidx+1 < args.size()) {
+                               if (arg == "-lut" || arg == "-luts")
+                                       lut_mode = true;
                                exe_cmd << " " << arg << " " << args[++argidx];
                                continue;
                        }
@@ -228,6 +239,10 @@ struct Abc9Pass : public ScriptPass
                                box_file = args[++argidx];
                                continue;
                        }
+                       if (arg == "-maxlut" && argidx+1 < args.size()) {
+                               maxlut = atoi(args[++argidx].c_str());
+                               continue;
+                       }
                        if (arg == "-run" && argidx+1 < args.size()) {
                                size_t pos = args[argidx+1].find(':');
                                if (pos == std::string::npos)
@@ -240,6 +255,9 @@ struct Abc9Pass : public ScriptPass
                }
                extra_args(args, argidx, design);
 
+               if (maxlut && lut_mode)
+                       log_cmd_error("abc9 '-maxlut' option only applicable without '-lut' nor '-luts'.\n");
+
                log_assert(design);
                if (design->selected_modules().empty()) {
                        log_warning("No modules selected for ABC9 techmapping.\n");
@@ -263,6 +281,10 @@ struct Abc9Pass : public ScriptPass
                                run("abc9_ops -mark_scc -prep_delays -prep_xaiger [-dff]", "(option for -dff)");
                        else
                                run("abc9_ops -mark_scc -prep_delays -prep_xaiger" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)");
+                       if (help_mode)
+                               run("abc9_ops -prep_lut <maxlut>", "(skip if -lut or -luts)");
+                       else if (!lut_mode)
+                               run(stringf("abc9_ops -prep_lut %d", maxlut));
                        run("select -set abc9_holes A:abc9_holes");
                        run("flatten -wb @abc9_holes");
                        run("techmap @abc9_holes");
@@ -276,9 +298,10 @@ struct Abc9Pass : public ScriptPass
                if (check_label("map")) {
                        if (help_mode) {
                                run("foreach module in selection");
+                               run("    abc9_ops -write_lut <abc-temp-dir>/input.lut", "(skip if '-lut' or '-luts')");
                                run("    abc9_ops -write_box [<value from -box>|(null)] <abc-temp-dir>/input.box");
                                run("    write_xaiger -map <abc-temp-dir>/input.sym <abc-temp-dir>/input.xaig");
-                               run("    abc9_exe [options] -cwd <abc-temp-dir> -box <abc-temp-dir>/input.box");
+                               run("    abc9_exe [options] -cwd <abc-temp-dir> [-lut <abc-temp-dir>/input.lut] -box <abc-temp-dir>/input.box");
                                run("    read_aiger -xaiger -wideports -module_name <module-name>$abc9 -map <abc-temp-dir>/input.sym <abc-temp-dir>/output.aig");
                                run("    abc9_ops -reintegrate");
                        }
@@ -304,6 +327,8 @@ struct Abc9Pass : public ScriptPass
                                                tempdir_name[0] = tempdir_name[4] = '_';
                                        tempdir_name = make_temp_dir(tempdir_name);
 
+                                       if (!lut_mode)
+                                               run(stringf("abc9_ops -write_lut %s/input.lut", tempdir_name.c_str()));
                                        if (box_file.empty())
                                                run(stringf("abc9_ops -write_box (null) %s/input.box", tempdir_name.c_str()));
                                        else
@@ -319,7 +344,12 @@ struct Abc9Pass : public ScriptPass
                                                        active_design->scratchpad_get_int("write_xaiger.num_inputs"),
                                                        num_outputs);
                                        if (num_outputs) {
-                                               run(stringf("%s -cwd %s -box %s/input.box", exe_cmd.str().c_str(), tempdir_name.c_str(), tempdir_name.c_str()));
+                                               std::string abc9_exe_cmd;
+                                               abc9_exe_cmd += stringf("%s -cwd %s", exe_cmd.str().c_str(), tempdir_name.c_str());
+                                               if (!lut_mode)
+                                                       abc9_exe_cmd += stringf(" -lut %s/input.lut", tempdir_name.c_str());
+                                               abc9_exe_cmd += stringf(" -box %s/input.box", tempdir_name.c_str());
+                                               run(abc9_exe_cmd);
                                                run(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod), tempdir_name.c_str(), tempdir_name.c_str()));
                                                run("abc9_ops -reintegrate");
                                        }
index 54605f90e33d06e3a262257d13d218bff6045268..cf6d5eabb5efd4e838850a4ec4c530d38076bca6 100644 (file)
@@ -562,6 +562,56 @@ void prep_delays(RTLIL::Design *design)
        design->scratchpad_set_string("abc9_ops.box.flops", ss.str());
 }
 
+void prep_lut(RTLIL::Design *design, int maxlut)
+{
+       std::stringstream ss;
+       std::vector<std::pair<int, std::string>> table;
+       for (auto module : design->modules()) {
+               auto it = module->attributes.find(ID(abc9_lut));
+               if (it == module->attributes.end())
+                       continue;
+               SigBit o;
+               std::vector<int> specify;
+               for (auto cell : module->cells()) {
+                       if (cell->type != ID($specify2))
+                               continue;
+                       log_assert(cell->getParam(ID(SRC_WIDTH)) == 1);
+                       log_assert(cell->getParam(ID(DST_WIDTH)) == 1);
+                       SigBit d = cell->getPort(ID(DST));
+                       if (o == SigBit())
+                               o = d;
+                       else
+                               log_assert(o == d);
+                       int rise_max = cell->getParam(ID(T_RISE_MAX)).as_int();
+                       int fall_max = cell->getParam(ID(T_FALL_MAX)).as_int();
+                       specify.push_back(std::max(rise_max,fall_max));
+               }
+               if (maxlut && GetSize(specify) > maxlut)
+                       continue;
+               std::sort(specify.begin(), specify.end());
+               ss.str("");
+               ss << "# " << module->name.str() << std::endl;
+               ss << GetSize(specify) << " " << it->second.as_int();
+               for (auto i : specify)
+                       ss << " " << i;
+               ss << std::endl;
+               table.emplace_back(GetSize(specify), ss.str());
+       }
+       // ABC expects ascending size
+       std::sort(table.begin(), table.end());
+       ss.str("");
+       for (auto &i : table)
+               ss << i.second;
+       design->scratchpad_set_string("abc9_ops.lut_library", ss.str());
+}
+
+void write_lut(RTLIL::Module *module, const std::string &dst) {
+       std::ofstream ofs(dst);
+       log_assert(ofs.is_open());
+       ofs << module->design->scratchpad_get_string("abc9_ops.lut_library");
+       ofs.close();
+}
+
 void write_box(RTLIL::Module *module, const std::string &src, const std::string &dst) {
        std::ofstream ofs(dst);
        log_assert(ofs.is_open());
@@ -1002,6 +1052,12 @@ struct Abc9OpsPass : public Pass {
                log("        compute the clock domain and initial value of each flop in the design.\n");
                log("        process the '$holes' module to support clock-enable functionality.\n");
                log("\n");
+               log("    -prep_lut <maxlut>\n");
+               log("        pre-compute the lut library.\n");
+               log("\n");
+               log("    -write_lut <dst>\n");
+               log("        TODO.\n");
+               log("\n");
                log("    -write_box (<src>|(null)) <dst>\n");
                log("        copy the existing box file from <src> (skip if '(null)') and append any\n");
                log("        new box definitions.\n");
@@ -1021,8 +1077,11 @@ struct Abc9OpsPass : public Pass {
                bool mark_scc_mode = false;
                bool prep_dff_mode = false;
                bool prep_xaiger_mode = false;
+               bool prep_lut_mode = false;
                bool reintegrate_mode = false;
                bool dff_mode = false;
+               std::string write_lut_dst;
+               int maxlut = 0;
                std::string write_box_src, write_box_dst;
 
                size_t argidx;
@@ -1048,6 +1107,19 @@ struct Abc9OpsPass : public Pass {
                                prep_delays_mode = true;
                                continue;
                        }
+                       if (arg == "-prep_lut" && argidx+1 < args.size()) {
+                               prep_lut_mode = true;
+                               maxlut = atoi(args[++argidx].c_str());
+                               continue;
+                       }
+                       if (arg == "-write_lut" && argidx+1 < args.size()) {
+                               write_lut_dst = args[++argidx];
+                               rewrite_filename(write_lut_dst);
+                               continue;
+                       }
+                       if (arg == "-maxlut" && argidx+1 < args.size()) {
+                               continue;
+                       }
                        if (arg == "-write_box" && argidx+2 < args.size()) {
                                write_box_src = args[++argidx];
                                write_box_dst = args[++argidx];
@@ -1067,16 +1139,21 @@ struct Abc9OpsPass : public Pass {
                }
                extra_args(args, argidx, design);
 
-               if (!(check_mode || mark_scc_mode || prep_delays_mode || prep_xaiger_mode || prep_dff_mode || !write_box_src.empty() || reintegrate_mode))
-                       log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff}, -write_box, -reintegrate must be specified.\n");
+               if (!(check_mode || mark_scc_mode || prep_delays_mode || prep_xaiger_mode || prep_dff_mode || prep_lut_mode || !write_lut_dst.empty() || !write_box_dst.empty() || reintegrate_mode))
+                       log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff,lut}, -write_{lut,box}, -reintegrate must be specified.\n");
 
                if (dff_mode && !prep_xaiger_mode)
                        log_cmd_error("'-dff' option is only relevant for -prep_xaiger.\n");
 
+               if (maxlut && !write_lut_dst.empty())
+                       log_cmd_error("'-maxlut' option is only relevant for -prep_lut.\n");
+
                if (check_mode)
                        check(design);
                if (prep_delays_mode)
                        prep_delays(design);
+               if (prep_lut_mode)
+                       prep_lut(design, maxlut);
 
                for (auto mod : design->selected_modules()) {
                        if (mod->get_bool_attribute("\\abc9_holes"))
@@ -1090,7 +1167,9 @@ struct Abc9OpsPass : public Pass {
                        if (!design->selected_whole_module(mod))
                                log_error("Can't handle partially selected module %s!\n", log_id(mod));
 
-                       if (!write_box_src.empty())
+                       if (!write_lut_dst.empty())
+                               write_lut(mod, write_lut_dst);
+                       if (!write_box_dst.empty())
                                write_box(mod, write_box_src, write_box_dst);
                        if (mark_scc_mode)
                                mark_scc(mod);
index 4692eba331666342194096f341a8bd1264f2908b..a1fe56fa17252c10145404ed3044ff7ea43a2a7b 100644 (file)
@@ -162,32 +162,55 @@ module INV(
   assign O = !I;
 endmodule
 
+(* abc9_lut=1 *)
 module LUT1(output O, input I0);
   parameter [1:0] INIT = 0;
   assign O = I0 ? INIT[1] : INIT[0];
+  specify
+    (I0 => O) = 127;
+  endspecify
 endmodule
 
+(* abc9_lut=2 *)
 module LUT2(output O, input I0, I1);
   parameter [3:0] INIT = 0;
   wire [ 1: 0] s1 = I1 ? INIT[ 3: 2] : INIT[ 1: 0];
   assign O = I0 ? s1[1] : s1[0];
+  specify
+    (I0 => O) = 238;
+    (I1 => O) = 127;
+  endspecify
 endmodule
 
+(* abc9_lut=3 *)
 module LUT3(output O, input I0, I1, I2);
   parameter [7:0] INIT = 0;
   wire [ 3: 0] s2 = I2 ? INIT[ 7: 4] : INIT[ 3: 0];
   wire [ 1: 0] s1 = I1 ?   s2[ 3: 2] :   s2[ 1: 0];
   assign O = I0 ? s1[1] : s1[0];
+  specify
+    (I0 => O) = 407;
+    (I1 => O) = 238;
+    (I2 => O) = 127;
+  endspecify
 endmodule
 
+(* abc9_lut=3 *)
 module LUT4(output O, input I0, I1, I2, I3);
   parameter [15:0] INIT = 0;
   wire [ 7: 0] s3 = I3 ? INIT[15: 8] : INIT[ 7: 0];
   wire [ 3: 0] s2 = I2 ?   s3[ 7: 4] :   s3[ 3: 0];
   wire [ 1: 0] s1 = I1 ?   s2[ 3: 2] :   s2[ 1: 0];
   assign O = I0 ? s1[1] : s1[0];
+  specify
+    (I0 => O) = 472;
+    (I1 => O) = 407;
+    (I2 => O) = 238;
+    (I3 => O) = 127;
+  endspecify
 endmodule
 
+(* abc9_lut=3 *)
 module LUT5(output O, input I0, I1, I2, I3, I4);
   parameter [31:0] INIT = 0;
   wire [15: 0] s4 = I4 ? INIT[31:16] : INIT[15: 0];
@@ -195,8 +218,16 @@ module LUT5(output O, input I0, I1, I2, I3, I4);
   wire [ 3: 0] s2 = I2 ?   s3[ 7: 4] :   s3[ 3: 0];
   wire [ 1: 0] s1 = I1 ?   s2[ 3: 2] :   s2[ 1: 0];
   assign O = I0 ? s1[1] : s1[0];
+  specify
+    (I0 => O) = 631;
+    (I1 => O) = 472;
+    (I2 => O) = 407;
+    (I3 => O) = 238;
+    (I4 => O) = 127;
+  endspecify
 endmodule
 
+(* abc9_lut=5 *)
 module LUT6(output O, input I0, I1, I2, I3, I4, I5);
   parameter [63:0] INIT = 0;
   wire [31: 0] s5 = I5 ? INIT[63:32] : INIT[31: 0];
@@ -205,6 +236,14 @@ module LUT6(output O, input I0, I1, I2, I3, I4, I5);
   wire [ 3: 0] s2 = I2 ?   s3[ 7: 4] :   s3[ 3: 0];
   wire [ 1: 0] s1 = I1 ?   s2[ 3: 2] :   s2[ 1: 0];
   assign O = I0 ? s1[1] : s1[0];
+  specify
+    (I0 => O) = 642;
+    (I1 => O) = 631;
+    (I2 => O) = 472;
+    (I3 => O) = 407;
+    (I4 => O) = 238;
+    (I5 => O) = 127;
+  endspecify
 endmodule
 
 module LUT6_2(output O6, output O5, input I0, I1, I2, I3, I4, I5);
@@ -223,6 +262,50 @@ module LUT6_2(output O6, output O5, input I0, I1, I2, I3, I4, I5);
   assign O5 = I0 ? s5_1[1] : s5_1[0];
 endmodule
 
+(* abc9_lut=10 *)
+module $__ABC9_LUT7(output O, input I0, I1, I2, I3, I4, I5, I6);
+  parameter [127:0] INIT = 0;
+  wire [63: 0] s6 = I6 ? INIT[127:64] : INIT[63: 0];
+  wire [31: 0] s5 = I5 ?    s6[63:32] :   s6[31: 0];
+  wire [15: 0] s4 = I4 ?    s5[31:16] :   s5[15: 0];
+  wire [ 7: 0] s3 = I3 ?    s4[15: 8] :   s4[ 7: 0];
+  wire [ 3: 0] s2 = I2 ?    s3[ 7: 4] :   s3[ 3: 0];
+  wire [ 1: 0] s1 = I1 ?    s2[ 3: 2] :   s2[ 1: 0];
+  assign O = I0 ? s1[1] : s1[0];
+  specify
+    (I0 => O) = 1028;
+    (I1 => O) = 1017;
+    (I2 => O) =  858;
+    (I3 => O) =  793;
+    (I4 => O) =  624;
+    (I5 => O) =  513;
+    (I6 => O) =  464;
+  endspecify
+endmodule
+
+(* abc9_lut=20 *)
+module $__ABC9_LUT8(output O, input I0, I1, I2, I3, I4, I5, I6, I7);
+  parameter [255:0] INIT = 0;
+  wire [127: 0] s7 = I7 ? INIT[255:128] : INIT[127: 0];
+  wire [ 63: 0] s6 = I6 ?   s7[127:63]  :   s7[ 64: 0];
+  wire [ 31: 0] s5 = I5 ?   s6[ 63:32]  :   s6[ 31: 0];
+  wire [ 15: 0] s4 = I4 ?   s5[ 31:16]  :   s5[ 15: 0];
+  wire [  7: 0] s3 = I3 ?   s4[ 15: 8]  :   s4[  7: 0];
+  wire [  3: 0] s2 = I2 ?   s3[  7: 4]  :   s3[  3: 0];
+  wire [  1: 0] s1 = I1 ?   s2[  3: 2]  :   s2[  1: 0];
+  assign O = I0 ? s1[1] : s1[0];
+  specify
+    (I0 => O) = 1149;
+    (I1 => O) = 1138;
+    (I2 => O) =  979;
+    (I3 => O) =  914;
+    (I4 => O) =  745;
+    (I5 => O) =  634;
+    (I6 => O) =  585;
+    (I7 => O) =  468;
+  endspecify
+endmodule
+
 module MUXCY(output O, input CI, DI, S);
   assign O = S ? CI : DI;
 endmodule
index a6b422b835b40f4697793662b59f7ef3fda3130f..4614a2bf9740a128cab5e1468b0ba5d485580408 100644 (file)
@@ -354,7 +354,7 @@ struct SynthXilinxPass : public ScriptPass
                        std::string read_args;
                        if (vpr)
                                read_args += " -D_EXPLICIT_CARRY";
-                       read_args += " -lib +/xilinx/cells_sim.v";
+                       read_args += " -lib -specify +/xilinx/cells_sim.v";
                        run("read_verilog" + read_args);
 
                        run("read_verilog -lib +/xilinx/cells_xtra.v");
@@ -627,9 +627,7 @@ struct SynthXilinxPass : public ScriptPass
                                else
                                        abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k, RTLIL::constpad.at("synth_xilinx.abc9.xc7.W")).c_str());
                                if (nowidelut)
-                                       abc9_opts += " -lut +/xilinx/abc9_xc7_nowide.lut";
-                               else
-                                       abc9_opts += " -lut +/xilinx/abc9_xc7.lut";
+                                       abc9_opts += stringf(" -maxlut %d", lut_size_s);
                                if (dff_mode)
                                        abc9_opts += " -dff";
                                run("abc9" + abc9_opts);