aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--passes/techmap/abc9.cc74
-rw-r--r--techlibs/xilinx/Makefile.inc2
-rw-r--r--techlibs/xilinx/cells.box13
-rw-r--r--techlibs/xilinx/cells.lut12
-rw-r--r--techlibs/xilinx/cells_map.v73
-rw-r--r--techlibs/xilinx/synth_xilinx.cc43
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"))