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");
std::stringstream exe_cmd;
bool dff_mode, cleanup;
+ bool lut_mode;
+ int maxlut;
std::string box_file;
void clear_flags() YS_OVERRIDE
exe_cmd << "abc9_exe";
dff_mode = false;
cleanup = true;
+ lut_mode = false;
+ maxlut = 0;
box_file.clear();
}
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;
}
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)
}
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");
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");
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");
}
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
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");
}
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());
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");
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;
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];
}
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"))
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);
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];
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];
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);
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
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");
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);