diff options
-rw-r--r-- | passes/techmap/abc9.cc | 74 | ||||
-rw-r--r-- | techlibs/xilinx/Makefile.inc | 2 | ||||
-rw-r--r-- | techlibs/xilinx/cells.box | 13 | ||||
-rw-r--r-- | techlibs/xilinx/cells.lut | 12 | ||||
-rw-r--r-- | techlibs/xilinx/cells_map.v | 73 | ||||
-rw-r--r-- | techlibs/xilinx/synth_xilinx.cc | 43 |
6 files changed, 185 insertions, 32 deletions
diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index da3d36354..e26920f20 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -272,7 +272,7 @@ failed: void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, std::string liberty_file, std::string constr_file, bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str, bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode, - const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode) + const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode, std::string box_file, std::string lut_file) { module = current_module; map_autoidx = autoidx++; @@ -329,8 +329,17 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri if (!constr_file.empty()) abc_script += stringf("read_constr -v %s; ", constr_file.c_str()); } else - if (!lut_costs.empty()) + if (!lut_costs.empty()) { abc_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str()); + if (!box_file.empty()) + abc_script += stringf("read_box -v %s; ", box_file.c_str()); + } + else + if (!lut_file.empty()) { + abc_script += stringf("read_lut %s; ", lut_file.c_str()); + if (!box_file.empty()) + abc_script += stringf("read_box -v %s; ", box_file.c_str()); + } else abc_script += stringf("read_library %s/stdcells.genlib; ", tempdir_name.c_str()); @@ -345,11 +354,11 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri abc_script += script_file[i]; } else abc_script += stringf("source %s", script_file.c_str()); - } else if (!lut_costs.empty()) { - bool all_luts_cost_same = true; - for (int this_cost : lut_costs) - if (this_cost != lut_costs.front()) - all_luts_cost_same = false; + } else if (!lut_costs.empty() || !lut_file.empty()) { + //bool all_luts_cost_same = true; + //for (int this_cost : lut_costs) + // if (this_cost != lut_costs.front()) + // all_luts_cost_same = false; abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT; //if (all_luts_cost_same && !fast_mode) // abc_script += "; lutpack {S}"; @@ -403,6 +412,10 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri RTLIL::Selection& sel = design->selection_stack.back(); sel.select(module); + // Adopt same behaviour as abc + // TODO: How to specify don't-care to abc9? + Pass::call(design, "setundef -zero"); + Pass::call(design, "aigmap"); handle_loops(design); @@ -572,7 +585,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri RTLIL::Cell *cell; RTLIL::SigBit a_bit = c->getPort("\\A").as_bit(); RTLIL::SigBit y_bit = c->getPort("\\Y").as_bit(); - if (!lut_costs.empty()) { + if (!lut_costs.empty() || !lut_file.empty()) { // ABC can return NOT gates that drive POs if (a_bit.wire->port_input) { // If it's a NOT gate that comes from a primary input directly @@ -1000,7 +1013,7 @@ struct Abc9Pass : public Pass { log(" file format).\n"); log("\n"); log(" -constr <file>\n"); - log(" pass this file with timing constraints to ABC. use with -liberty.\n"); + log(" pass this file with timing constraints to ABC. Use with -liberty.\n"); log("\n"); log(" a constr file contains two lines:\n"); log(" set_driving_cell <cell_name>\n"); @@ -1037,6 +1050,9 @@ struct Abc9Pass : public Pass { log(" the area cost doubles with each additional input bit. the delay cost\n"); log(" is still constant for all lut widths.\n"); log("\n"); + log(" -lut <file>\n"); + log(" pass this file with lut library to ABC.\n"); + log("\n"); log(" -luts <cost1>,<cost2>,<cost3>,<sizeN>:<cost4-N>,..\n"); log(" generate netlist using luts. Use the specified costs for luts with 1,\n"); log(" 2, 3, .. inputs.\n"); @@ -1090,6 +1106,9 @@ struct Abc9Pass : public Pass { log(" this attribute is a unique integer for each ABC process started. This\n"); log(" is useful for debugging the partitioning of clock domains.\n"); log("\n"); + log(" -box <file>\n"); + log(" pass this file with box library to ABC. Use with -lut.\n"); + log("\n"); log("When neither -liberty nor -lut is used, the Yosys standard cell library is\n"); log("loaded into ABC before the ABC script is executed.\n"); log("\n"); @@ -1119,7 +1138,7 @@ struct Abc9Pass : public Pass { #else std::string exe_file = proc_self_dirname() + "yosys-abc"; #endif - std::string script_file, liberty_file, constr_file, clk_str; + std::string script_file, liberty_file, constr_file, clk_str, box_file, lut_file; std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1"; bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true; bool show_tempdir = false, sop_mode = false; @@ -1165,8 +1184,8 @@ struct Abc9Pass : public Pass { continue; } if (arg == "-constr" && argidx+1 < args.size()) { - rewrite_filename(constr_file); constr_file = args[++argidx]; + rewrite_filename(constr_file); if (!constr_file.empty() && !is_absolute_path(constr_file)) constr_file = std::string(pwd) + "/" + constr_file; continue; @@ -1195,8 +1214,17 @@ struct Abc9Pass : public Pass { lut_mode = atoi(arg.substr(0, pos).c_str()); lut_mode2 = atoi(arg.substr(pos+1).c_str()); } else { - lut_mode = atoi(arg.c_str()); - lut_mode2 = lut_mode; + pos = arg.find_first_of('.'); + if (pos != string::npos) { + lut_file = arg; + rewrite_filename(lut_file); + if (!lut_file.empty() && !is_absolute_path(lut_file)) + lut_file = std::string(pwd) + "/" + lut_file; + } + else { + lut_mode = atoi(arg.c_str()); + lut_mode2 = lut_mode; + } } lut_costs.clear(); for (int i = 0; i < lut_mode; i++) @@ -1237,6 +1265,11 @@ struct Abc9Pass : public Pass { map_mux16 = true; continue; } + if (arg == "-dress") { + // TODO + //abc_dress = true; + continue; + } if (arg == "-g" && argidx+1 < args.size()) { for (auto g : split_tokens(args[++argidx], ",")) { vector<string> gate_list; @@ -1348,11 +1381,18 @@ struct Abc9Pass : public Pass { markgroups = true; continue; } + if (arg == "-box" && argidx+1 < args.size()) { + box_file = args[++argidx]; + rewrite_filename(box_file); + if (!box_file.empty() && !is_absolute_path(box_file)) + box_file = std::string(pwd) + "/" + box_file; + continue; + } break; } extra_args(args, argidx, design); - if (!lut_costs.empty() && !liberty_file.empty()) + if ((!lut_costs.empty() || !lut_file.empty()) && !liberty_file.empty()) log_cmd_error("Got -lut and -liberty! This two options are exclusive.\n"); if (!constr_file.empty() && liberty_file.empty()) log_cmd_error("Got -constr but no -liberty!\n"); @@ -1386,7 +1426,8 @@ struct Abc9Pass : public Pass { if (!dff_mode || !clk_str.empty()) { abc9_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff, - delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode); + delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, + box_file, lut_file); continue; } @@ -1531,7 +1572,8 @@ struct Abc9Pass : public Pass { en_polarity = std::get<2>(it.first); en_sig = assign_map(std::get<3>(it.first)); abc9_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$", - keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode); + keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, + box_file, lut_file); assign_map.set(mod); } } diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc index d68f03bb4..432bb0770 100644 --- a/techlibs/xilinx/Makefile.inc +++ b/techlibs/xilinx/Makefile.inc @@ -30,6 +30,8 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/ff_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells.box)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells.lut)) $(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh)) $(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_32.vh)) diff --git a/techlibs/xilinx/cells.box b/techlibs/xilinx/cells.box new file mode 100644 index 000000000..c8092db6e --- /dev/null +++ b/techlibs/xilinx/cells.box @@ -0,0 +1,13 @@ +# Max delays from https://pastebin.com/v2hrcksd +# from https://github.com/SymbiFlow/prjxray/pull/706#issuecomment-479380321 + +# F7BMUX slower than F7AMUX +# Inputs: 0 1 S0 +# Outputs: OUT +F7BMUX 1 0 3 1 +217 223 296 + +# Inputs: 0 1 S0 +# Outputs: OUT +MUXF8 2 0 3 1 +104 94 273 diff --git a/techlibs/xilinx/cells.lut b/techlibs/xilinx/cells.lut new file mode 100644 index 000000000..a1d9b9c42 --- /dev/null +++ b/techlibs/xilinx/cells.lut @@ -0,0 +1,12 @@ +# Max delays from https://pastebin.com/v2hrcksd +# from https://github.com/SymbiFlow/prjxray/pull/706#issuecomment-479380321 + +# K area delay +1 11 624 +2 12 624 +3 13 624 +4 14 624 +5 15 624 +6 20 724 +7 40 1020 +8 80 1293 diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index d5801c0fc..93d60f60b 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -17,4 +17,75 @@ * */ -// Empty for now +module \$shiftx (A, B, Y); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 1; + parameter B_WIDTH = 1; + parameter Y_WIDTH = 1; + + input [A_WIDTH-1:0] A; + input [B_WIDTH-1:0] B; + output [Y_WIDTH-1:0] Y; + + parameter [B_WIDTH-1:0] _TECHMAP_CONSTMSK_B_ = 0; + parameter [B_WIDTH-1:0] _TECHMAP_CONSTVAL_B_ = 0; + + localparam NUM = A_WIDTH/Y_WIDTH; + generate + genvar i, j; + if (B_SIGNED) begin + if (_TECHMAP_CONSTMSK_B_[B_WIDTH-1] && _TECHMAP_CONSTVAL_B_[B_WIDTH-1] == 1'b0) + // Optimisation to remove B_SIGNED if sign bit of B is constant-0 + \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(0), .A_WIDTH(A_WIDTH), .B_WIDTH(B_WIDTH-1), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A), .B(B[B_WIDTH-2:0]), .Y(Y)); + else + wire _TECHMAP_FAIL_ = 1; + end + else if (NUM <= 4) begin + wire _TECHMAP_FAIL_ = 1; + end + else if (NUM <= 8) begin + localparam a_width0 = Y_WIDTH * 4; + localparam a_widthN = A_WIDTH - a_width0; + wire [Y_WIDTH-1:0] T0, T1; + \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_width0), .B_WIDTH(B_WIDTH-1), .Y_WIDTH(Y_WIDTH)) fpga_shiftx (.A(A[a_width0-1:0]), .B(B[B_WIDTH-2:0]), .Y(T0)); + \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_widthN), .B_WIDTH($clog2(a_widthN)), .Y_WIDTH(Y_WIDTH)) fpga_shiftx_last (.A(A[A_WIDTH-1:a_width0]), .B(B[$clog2(a_widthN)-1:0]), .Y(T1)); + for (i = 0; i < Y_WIDTH; i++) + MUXF7 fpga_mux (.I0(T0[i]), .I1(T1[i]), .S(B[B_WIDTH-1]), .O(Y[i])); + end + else if (NUM <= 16) begin + localparam a_width0 = Y_WIDTH * 4; + localparam num_mux8 = A_WIDTH / a_width0; + localparam a_widthN = A_WIDTH - num_mux8*a_width0; + wire [Y_WIDTH*4-1:0] T; + wire [Y_WIDTH-1:0] T0, T1; + for (i = 0; i < 4; i++) + if (i < num_mux8) + \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_width0), .B_WIDTH(B_WIDTH-2), .Y_WIDTH(Y_WIDTH)) fpga_shiftx (.A(A[(i+1)*a_width0-1:i*a_width0]), .B(B[B_WIDTH-3:0]), .Y(T[(i+1)*Y_WIDTH-1:i*Y_WIDTH])); + else if (i == num_mux8 && a_widthN > 0) + \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_widthN), .B_WIDTH(B_WIDTH-2), .Y_WIDTH(Y_WIDTH)) fpga_shiftx_last (.A(A[A_WIDTH-1:i*a_width0]), .B(B[B_WIDTH-3:0]), .Y(T[(i+1)*Y_WIDTH-1:i*Y_WIDTH])); + else + assign T[(i+1)*Y_WIDTH-1:i*Y_WIDTH] = {Y_WIDTH{1'bx}}; + for (i = 0; i < Y_WIDTH; i++) begin + MUXF7 fpga_mux_0 (.I0(T[0*Y_WIDTH+i]), .I1(T[1*Y_WIDTH+i]), .S(B[B_WIDTH-2]), .O(T0[i])); + MUXF7 fpga_mux_1 (.I0(T[2*Y_WIDTH+i]), .I1(T[3*Y_WIDTH+i]), .S(B[B_WIDTH-2]), .O(T1[i])); + MUXF8 fpga_mux_2 (.I0(T0[i]), .I1(T1[i]), .S(B[B_WIDTH-1]), .O(Y[i])); + end + end + else begin + localparam a_width0 = Y_WIDTH * 16; + localparam num_mux16 = A_WIDTH / a_width0; + localparam a_widthN = A_WIDTH - num_mux16*a_width0; + wire [Y_WIDTH * (2 ** ($clog2(NUM)-4))-1:0] T; + for (i = 0; i < 2 ** ($clog2(NUM)-4); i++) + if (i < num_mux16) + \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_width0), .B_WIDTH($clog2(a_width0)), .Y_WIDTH(Y_WIDTH)) fpga_shiftx (.A(A[(i+1)*a_width0-1:i*a_width0]), .B(B[$clog2(a_width0)-1:0]), .Y(T[(i+1)*Y_WIDTH-1:i*Y_WIDTH])); + else if (i == num_mux16 && a_widthN > 0) begin + \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_widthN), .B_WIDTH($clog2(a_width0)), .Y_WIDTH(Y_WIDTH)) fpga_shiftx_last (.A(A[A_WIDTH-1:i*a_width0]), .B(B[$clog2(a_width0)-1:0]), .Y(T[(i+1)*Y_WIDTH-1:i*Y_WIDTH])); + end + else + assign T[(i+1)*Y_WIDTH-1:i*Y_WIDTH] = {Y_WIDTH{1'bx}}; + \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(Y_WIDTH * (2 ** ($clog2(NUM)-4))), .B_WIDTH(B_WIDTH-$clog2(a_width0)), .Y_WIDTH(Y_WIDTH)) fpga_shiftx (.A(T), .B(B[B_WIDTH-1:$clog2(a_width0)]), .Y(Y)); + end + endgenerate +endmodule diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 805ae8e6e..10902a560 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -80,6 +80,9 @@ struct SynthXilinxPass : public Pass log(" -retime\n"); log(" run 'abc' with -dff option\n"); log("\n"); + log(" -abc9\n"); + log(" use abc9 instead of abc\n"); + log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); log("\n"); @@ -110,19 +113,20 @@ struct SynthXilinxPass : public Pass log(" dffsr2dff\n"); log(" dff2dffe\n"); log(" opt -full\n"); - log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v\n"); + log(" techmap -map +/xilinx/arith_map.v\n"); log(" opt -fast\n"); log("\n"); - log(" map_luts:\n"); - log(" abc -luts 2:2,3,6:5,10,20 [-dff] (without '-vpr' only!)\n"); - log(" abc -lut 5 [-dff] (with '-vpr' only!)\n"); - log(" clean\n"); - log("\n"); log(" map_cells:\n"); log(" techmap -map +/xilinx/cells_map.v\n"); + log(" clean\n"); + log("\n"); + log(" map_luts:\n"); + log(" techmap -map +/techmap.v\n"); + log(" abc -luts 2:2,3,6:5,10,20 [-dff]\n"); + log(" clean\n"); + log(" techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v\n"); log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT \\\n"); log(" -ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT\n"); - log(" clean\n"); log("\n"); log(" check:\n"); log(" hierarchy -check\n"); @@ -142,6 +146,7 @@ struct SynthXilinxPass : public Pass std::string edif_file; std::string blif_file; std::string run_from, run_to; + std::string abc = "abc"; bool flatten = false; bool retime = false; bool vpr = false; @@ -191,6 +196,10 @@ struct SynthXilinxPass : public Pass nodram = true; continue; } + if (args[argidx] == "-abc9") { + abc = "abc9"; + continue; + } break; } extra_args(args, argidx, design); @@ -256,28 +265,32 @@ struct SynthXilinxPass : public Pass Pass::call(design, "opt -full"); if (vpr) { - Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v -D _EXPLICIT_CARRY"); + Pass::call(design, "techmap -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY"); } else { - Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v"); + Pass::call(design, "techmap -map +/xilinx/arith_map.v"); } Pass::call(design, "hierarchy -check"); Pass::call(design, "opt -fast"); } - if (check_label(active, run_from, run_to, "map_luts")) + if (check_label(active, run_from, run_to, "map_cells")) { - Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); + Pass::call(design, "techmap -map +/xilinx/cells_map.v"); Pass::call(design, "clean"); - Pass::call(design, "techmap -map +/xilinx/lut_map.v"); } - if (check_label(active, run_from, run_to, "map_cells")) + if (check_label(active, run_from, run_to, "map_luts")) { - Pass::call(design, "techmap -map +/xilinx/cells_map.v"); + Pass::call(design, "techmap -map +/techmap.v"); + if (abc == "abc9") + Pass::call(design, abc + " -lut +/xilinx/cells.lut -box +/xilinx/cells.box" + string(retime ? " -dff" : "")); + else + Pass::call(design, abc + " -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); + Pass::call(design, "clean"); + Pass::call(design, "techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v"); Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT " "-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT"); - Pass::call(design, "clean"); } if (check_label(active, run_from, run_to, "check")) |