Initial support for inference 10x9 and 20x18 multipliers for k6n10f Signed-off-by: Maciej Kurc <mkurc@antmicro.com>
diff --git a/ql-qlf-plugin/qlf_k6n10f/cells_sim.v b/ql-qlf-plugin/qlf_k6n10f/cells_sim.v index fbdeedc..c69c38c 100644 --- a/ql-qlf-plugin/qlf_k6n10f/cells_sim.v +++ b/ql-qlf-plugin/qlf_k6n10f/cells_sim.v
@@ -664,22 +664,61 @@ endmodule -(* blackbox *) -module QL_DSP1 ( - input [19:0] a, - input [17:0] b, - input clk0, - (* clkbuf_sink *) - input clk1, - (* clkbuf_sink *) - input [ 1:0] feedback0, - input [ 1:0] feedback1, - input load_acc0, - input load_acc1, - input reset0, - input reset1, - output reg [37:0] z -); - parameter MODE_BITS = 27'b00000000000000000000000000; -endmodule /* QL_DSP1 */ +//(* blackbox *) +//module QL_DSP1 ( +// input [19:0] a, +// input [17:0] b, +// input clk0, +// (* clkbuf_sink *) +// input clk1, +// (* clkbuf_sink *) +// input [ 1:0] feedback0, +// input [ 1:0] feedback1, +// input load_acc0, +// input load_acc1, +// input reset0, +// input reset1, +// output reg [37:0] z +//); +// parameter MODE_BITS = 27'b00000000000000000000000000; +//endmodule /* QL_DSP1 */ +(* blackbox *) // TODO: add sim model +module dsp_t1_20x18x64 ( + input [63:0] a_i, + input [17:0] b_i, + output [63:0] z_o, + + input clock_i, + input reset_i, + input load_acc_i, + + input register_inputs_i, + input subtraction_mode_i, + input [1:0] feedback_i, + input round_i, + input [5:0] shift_right_i, + input saturate_enable_i, + input [1:0] output_select_i +); +endmodule + +(* blackbox *) // TODO: add sim model +module dsp_t1_10x9x32 ( + input [31:0] a_i, + input [ 8:0] b_i, + output [31:0] z_o, + + input clock_i, + input reset_i, + input load_acc_i, + + input register_inputs_i, + input subtraction_mode_i, + input [1:0] feedback_i, + input round_i, + input [5:0] shift_right_i, + input saturate_enable_i, + input [1:0] output_select_i +); +endmodule
diff --git a/ql-qlf-plugin/qlf_k6n10f/dsp_map.v b/ql-qlf-plugin/qlf_k6n10f/dsp_map.v index 4b8ae64..6b4cab2 100644 --- a/ql-qlf-plugin/qlf_k6n10f/dsp_map.v +++ b/ql-qlf-plugin/qlf_k6n10f/dsp_map.v
@@ -6,22 +6,77 @@ // // SPDX-License-Identifier:ISC -module \$__MUL16X16 (input [15:0] A, input [15:0] B, output [31:0] Y); - parameter A_SIGNED = 0; - parameter B_SIGNED = 0; - parameter A_WIDTH = 0; - parameter B_WIDTH = 0; - parameter Y_WIDTH = 0; +module \$__QL_MUL20X18 (input [19:0] A, input [17:0] B, output [37:0] Y); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 0; + parameter B_WIDTH = 0; + parameter Y_WIDTH = 0; - QL_DSP #( - .A_REG(1'b0), - .B_REG(1'b0), - .C_REG(1'b0), - .D_REG(1'b0), - .ENABLE_DSP(1'b1), - ) _TECHMAP_REPLACE_ ( - .A(A), - .B(B), - .O(Y), - ); + wire [19:0] a; + wire [17:0] b; + wire [63:0] z; + + assign a = (A_WIDTH == 20) ? A : + (A_SIGNED) ? {{(20 - A_WIDTH){A[A_WIDTH-1]}}, A} : + {{(20 - A_WIDTH){1'b0}}, A}; + + assign b = (B_WIDTH == 18) ? B : + (B_SIGNED) ? {{(18 - B_WIDTH){B[B_WIDTH-1]}}, B} : + {{(18 - B_WIDTH){1'b0}}, B}; + + dsp_t1_20x18x64 _TECHMAP_REPLACE_ ( + .a_i (a), + .b_i (b), + .z_o (z), + + .register_inputs_i (1'b0), + .subtraction_mode_i (1'b0), + .feedback_i (2'b00), + .round_i (1'b0), + .shift_right_i (1'b0), + .saturate_enable_i (1'b0), + .output_select_i (1'b0) + ); + + assign Y = z[37:0]; + endmodule + +module \$__QL_MUL20X18 (input [9:0] A, input [8:0] B, output [18:0] Y); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 0; + parameter B_WIDTH = 0; + parameter Y_WIDTH = 0; + + wire [ 9:0] a; + wire [ 8:0] b; + wire [31:0] z; + + assign a = (A_WIDTH == 10) ? A : + (A_SIGNED) ? {{(10 - A_WIDTH){A[A_WIDTH-1]}}, A} : + {{(10 - A_WIDTH){1'b0}}, A}; + + assign b = (B_WIDTH == 9) ? B : + (B_SIGNED) ? {{( 9 - B_WIDTH){B[B_WIDTH-1]}}, B} : + {{( 9 - B_WIDTH){1'b0}}, B}; + + dsp_t1_10x9x32 _TECHMAP_REPLACE_ ( + .a_i (a), + .b_i (b), + .z_o (z), + + .register_inputs_i (1'b0), + .subtraction_mode_i (1'b0), + .feedback_i (2'b00), + .round_i (1'b0), + .shift_right_i (1'b0), + .saturate_enable_i (1'b0), + .output_select_i (1'b0) + ); + + assign Y = z[18:0]; + +endmodule +
diff --git a/ql-qlf-plugin/synth_quicklogic.cc b/ql-qlf-plugin/synth_quicklogic.cc index d26f53a..9117470 100644 --- a/ql-qlf-plugin/synth_quicklogic.cc +++ b/ql-qlf-plugin/synth_quicklogic.cc
@@ -233,21 +233,61 @@ run("opt_clean"); run("share"); - if (help_mode || (!nodsp && family == "qlf_k6n10")) { - run("memory_dff"); - run("wreduce t:$mul"); - run("techmap -map +/mul2dsp.v -map +/quicklogic/" + family + - "/dsp_map.v -D DSP_A_MAXWIDTH=16 -D DSP_B_MAXWIDTH=16 " - "-D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 -D DSP_Y_MINWIDTH=11 " - "-D DSP_NAME=$__MUL16X16", - "(if -no_dsp)"); - run("select a:mul2dsp", " (if -no_dsp)"); - run("setattr -unset mul2dsp", " (if -no_dsp)"); - run("opt_expr -fine", " (if -no_dsp)"); - run("wreduce", " (if -no_dsp)"); - run("select -clear", " (if -no_dsp)"); - run("ql_dsp", " (if -no_dsp)"); - run("chtype -set $mul t:$__soft_mul", "(if -no_dsp)"); + if (family == "qlf_k6n10") { + if (help_mode || !nodsp) { + run("memory_dff"); + run("wreduce t:$mul"); + run("techmap -map +/mul2dsp.v -map +/quicklogic/" + family + + "/dsp_map.v -D DSP_A_MAXWIDTH=16 -D DSP_B_MAXWIDTH=16 " + "-D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 -D DSP_Y_MINWIDTH=11 " + "-D DSP_NAME=$__MUL16X16", + "(for qlf_k6n10 if not -no_dsp)"); + run("select a:mul2dsp", " (for qlf_k6n10 if not -no_dsp)"); + run("setattr -unset mul2dsp", " (for qlf_k6n10 if not -no_dsp)"); + run("opt_expr -fine", " (for qlf_k6n10 if not -no_dsp)"); + run("wreduce", " (for qlf_k6n10 if not -no_dsp)"); + run("select -clear", " (for qlf_k6n10 if not -no_dsp)"); + run("ql_dsp", " (for qlf_k6n10 if not -no_dsp)"); + run("chtype -set $mul t:$__soft_mul", "(for qlf_k6n10 if not -no_dsp)"); + } + } + else if (family == "qlf_k6n10f") { + + struct DspParams { + size_t a_maxwidth; + size_t b_maxwidth; + size_t a_minwidth; + size_t b_minwidth; + std::string type; + }; + + const std::vector<DspParams> dsp_rules = { + {20, 18, 4, 4, "$__QL_MUL20X18"}, + {10, 9, 4, 4, "$__QL_MUL10X9"}, + }; + + if (help_mode) { + run("wreduce t:$mul", " (for qlf_k6n10f if not -no_dsp)"); + run("techmap -map +/mul2dsp.v [...]", "(for qlf_k6n10f if not -no_dsp)"); + run("chtype -set $mul t:$__soft_mul", "(for qlf_k6n10f if not -no_dsp)"); + run("techmap -map +/quicklogic/" + family + "/dsp_map.v", "(for qlf_k6n10f if not -no_dsp)"); + } + else if (!nodsp) { + + run("wreduce t:$mul"); + for (const auto &rule : dsp_rules) { + run(stringf("techmap -map +/mul2dsp.v " + "-D DSP_A_MAXWIDTH=%zu -D DSP_B_MAXWIDTH=%zu " + "-D DSP_A_MINWIDTH=%zu -D DSP_B_MINWIDTH=%zu " + "-D DSP_NAME=%s", + rule.a_maxwidth, rule.b_maxwidth, + rule.a_minwidth, rule.b_minwidth, + rule.type.c_str()) + ); + run("chtype -set $mul t:$__soft_mul"); + } + run("techmap -map +/quicklogic/" + family + "/dsp_map.v"); + } } run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4");