From: Eddie Hung Date: Tue, 11 Feb 2020 16:34:13 +0000 (-0800) Subject: abc9_ops: -prep_lut and -write_lut to auto-generate LUT library X-Git-Tag: working-ls180~780^2~45 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=5643c1b8c5fbe1a31fcb4027ddbe096e74439cbf;p=yosys.git abc9_ops: -prep_lut and -write_lut to auto-generate LUT library --- diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 5ae2fb22a..0e2ca80c7 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -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 \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 ", "(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 /input.lut", "(skip if '-lut' or '-luts')"); run(" abc9_ops -write_box [|(null)] /input.box"); run(" write_xaiger -map /input.sym /input.xaig"); - run(" abc9_exe [options] -cwd -box /input.box"); + run(" abc9_exe [options] -cwd [-lut /input.lut] -box /input.box"); run(" read_aiger -xaiger -wideports -module_name $abc9 -map /input.sym /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"); } diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 54605f90e..cf6d5eabb 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -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> table; + for (auto module : design->modules()) { + auto it = module->attributes.find(ID(abc9_lut)); + if (it == module->attributes.end()) + continue; + SigBit o; + std::vector 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 \n"); + log(" pre-compute the lut library.\n"); + log("\n"); + log(" -write_lut \n"); + log(" TODO.\n"); + log("\n"); log(" -write_box (|(null)) \n"); log(" copy the existing box file from (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); diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index 4692eba33..a1fe56fa1 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -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 diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index a6b422b83..4614a2bf9 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -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);