ql-qlf: k6n10f: DSP: move dsp simulation models to separate file Signed-off-by: Paweł Czarnecki <pczarnecki@antmicro.com>
diff --git a/ql-qlf-plugin/Makefile b/ql-qlf-plugin/Makefile index 7deee70..3e08cd3 100644 --- a/ql-qlf-plugin/Makefile +++ b/ql-qlf-plugin/Makefile
@@ -51,6 +51,7 @@ $(QLF_K6N10F_DIR)/brams_final_map.v \ $(QLF_K6N10F_DIR)/brams.txt \ $(QLF_K6N10F_DIR)/cells_sim.v \ + $(QLF_K6N10F_DIR)/dsp_sim.v \ $(QLF_K6N10F_DIR)/sram1024x18.v \ $(QLF_K6N10F_DIR)/TDP18K_FIFO.v \ $(QLF_K6N10F_DIR)/ufifo_ctl.v \
diff --git a/ql-qlf-plugin/qlf_k6n10f/cells_sim.v b/ql-qlf-plugin/qlf_k6n10f/cells_sim.v index ae54ec3..d3b78ca 100644 --- a/ql-qlf-plugin/qlf_k6n10f/cells_sim.v +++ b/ql-qlf-plugin/qlf_k6n10f/cells_sim.v
@@ -1506,1129 +1506,3 @@ .FLUSH2_i(FLUSH2) ); endmodule - -(* blackbox *) -module QL_DSP1 ( - input wire [19:0] a, - input wire [17:0] b, - (* clkbuf_sink *) - input wire clk0, - (* clkbuf_sink *) - input wire clk1, - input wire [ 1:0] feedback0, - input wire [ 1:0] feedback1, - input wire load_acc0, - input wire load_acc1, - input wire reset0, - input wire reset1, - output reg [37:0] z -); - parameter MODE_BITS = 27'b00000000000000000000000000; -endmodule /* QL_DSP1 */ - -module QL_DSP2 ( // TODO: Name subject to change - input wire [19:0] a, - input wire [17:0] b, - input wire [ 5:0] acc_fir, - output wire [37:0] z, - output wire [17:0] dly_b, - - (* clkbuf_sink *) - input wire clk, - input wire reset, - - input wire [2:0] feedback, - input wire load_acc, - input wire unsigned_a, - input wire unsigned_b, - - input wire f_mode, - input wire [2:0] output_select, - input wire saturate_enable, - input wire [5:0] shift_right, - input wire round, - input wire subtract, - input wire register_inputs -); - - parameter [79:0] MODE_BITS = 80'd0; - - localparam [19:0] COEFF_0 = MODE_BITS[19:0]; - localparam [19:0] COEFF_1 = MODE_BITS[39:20]; - localparam [19:0] COEFF_2 = MODE_BITS[59:40]; - localparam [19:0] COEFF_3 = MODE_BITS[79:60]; - - localparam NBITS_ACC = 64; - localparam NBITS_A = 20; - localparam NBITS_B = 18; - localparam NBITS_Z = 38; - - wire [NBITS_Z-1:0] dsp_full_z; - wire [(NBITS_Z/2)-1:0] dsp_frac0_z; - wire [(NBITS_Z/2)-1:0] dsp_frac1_z; - - wire [NBITS_B-1:0] dsp_full_dly_b; - wire [(NBITS_B/2)-1:0] dsp_frac0_dly_b; - wire [(NBITS_B/2)-1:0] dsp_frac1_dly_b; - - assign z = f_mode ? {dsp_frac1_z, dsp_frac0_z} : dsp_full_z; - assign dly_b = f_mode ? {dsp_frac1_dly_b, dsp_frac0_dly_b} : dsp_full_dly_b; - - // Output used when fmode == 1 - dsp_t1_sim #( - .NBITS_A(NBITS_A/2), - .NBITS_B(NBITS_B/2), - .NBITS_ACC(NBITS_ACC/2), - .NBITS_Z(NBITS_Z/2) - ) dsp_frac0 ( - .a_i(a[(NBITS_A/2)-1:0]), - .b_i(b[(NBITS_B/2)-1:0]), - .z_o(dsp_frac0_z), - .dly_b_o(dsp_frac0_dly_b), - - .acc_fir_i(acc_fir), - .feedback_i(feedback), - .load_acc_i(load_acc), - - .unsigned_a_i(unsigned_a), - .unsigned_b_i(unsigned_b), - - .clock_i(clk), - .s_reset(reset), - - .saturate_enable_i(saturate_enable), - .output_select_i(output_select), - .round_i(round), - .shift_right_i(shift_right), - .subtract_i(subtract), - .register_inputs_i(register_inputs), - .coef_0_i(COEFF_0[(NBITS_A/2)-1:0]), - .coef_1_i(COEFF_1[(NBITS_A/2)-1:0]), - .coef_2_i(COEFF_2[(NBITS_A/2)-1:0]), - .coef_3_i(COEFF_3[(NBITS_A/2)-1:0]) - ); - - // Output used when fmode == 1 - dsp_t1_sim #( - .NBITS_A(NBITS_A/2), - .NBITS_B(NBITS_B/2), - .NBITS_ACC(NBITS_ACC/2), - .NBITS_Z(NBITS_Z/2) - ) dsp_frac1 ( - .a_i(a[NBITS_A-1:NBITS_A/2]), - .b_i(b[NBITS_B-1:NBITS_B/2]), - .z_o(dsp_frac1_z), - .dly_b_o(dsp_frac1_dly_b), - - .acc_fir_i(acc_fir), - .feedback_i(feedback), - .load_acc_i(load_acc), - - .unsigned_a_i(unsigned_a), - .unsigned_b_i(unsigned_b), - - .clock_i(clk), - .s_reset(reset), - - .saturate_enable_i(saturate_enable), - .output_select_i(output_select), - .round_i(round), - .shift_right_i(shift_right), - .subtract_i(subtract), - .register_inputs_i(register_inputs), - .coef_0_i(COEFF_0[NBITS_A-1:NBITS_A/2]), - .coef_1_i(COEFF_1[NBITS_A-1:NBITS_A/2]), - .coef_2_i(COEFF_2[NBITS_A-1:NBITS_A/2]), - .coef_3_i(COEFF_3[NBITS_A-1:NBITS_A/2]) - ); - - // Output used when fmode == 0 - dsp_t1_sim #( - .NBITS_A(NBITS_A), - .NBITS_B(NBITS_B), - .NBITS_ACC(NBITS_ACC), - .NBITS_Z(NBITS_Z) - ) dsp_full ( - .a_i(a), - .b_i(b), - .z_o(dsp_full_z), - .dly_b_o(dsp_full_dly_b), - - .acc_fir_i(acc_fir), - .feedback_i(feedback), - .load_acc_i(load_acc), - - .unsigned_a_i(unsigned_a), - .unsigned_b_i(unsigned_b), - - .clock_i(clk), - .s_reset(reset), - - .saturate_enable_i(saturate_enable), - .output_select_i(output_select), - .round_i(round), - .shift_right_i(shift_right), - .subtract_i(subtract), - .register_inputs_i(register_inputs), - .coef_0_i(COEFF_0), - .coef_1_i(COEFF_1), - .coef_2_i(COEFF_2), - .coef_3_i(COEFF_3) - ); -endmodule - -module QL_DSP2_MULT ( // TODO: Name subject to change - input wire [19:0] a, - input wire [17:0] b, - output wire [37:0] z, - - // Port not available in architecture file - input wire reset, - - input wire unsigned_a, - input wire unsigned_b, - - input wire f_mode, - input wire [2:0] output_select, - input wire register_inputs -); - - parameter [79:0] MODE_BITS = 80'd0; - - localparam [19:0] COEFF_0 = MODE_BITS[19:0]; - localparam [19:0] COEFF_1 = MODE_BITS[39:20]; - localparam [19:0] COEFF_2 = MODE_BITS[59:40]; - localparam [19:0] COEFF_3 = MODE_BITS[79:60]; - - QL_DSP2 #( - .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) - ) dsp ( - .a(a), - .b(b), - .z(z), - - .reset(reset), - - .f_mode(f_mode), - - .feedback(3'b0), - - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), - - .output_select(3'b0), // unregistered output: a * b (0) - .register_inputs(1'b0) // unregistered inputs - ); -endmodule - -module QL_DSP2_MULT_REGIN ( // TODO: Name subject to change - input wire [19:0] a, - input wire [17:0] b, - output wire [37:0] z, - - (* clkbuf_sink *) - input wire clk, - // Port not available in architecture file - input wire reset, - - input wire unsigned_a, - input wire unsigned_b, - - input wire f_mode, - input wire [2:0] output_select, - input wire register_inputs -); - - parameter [79:0] MODE_BITS = 80'd0; - - localparam [19:0] COEFF_0 = MODE_BITS[19:0]; - localparam [19:0] COEFF_1 = MODE_BITS[39:20]; - localparam [19:0] COEFF_2 = MODE_BITS[59:40]; - localparam [19:0] COEFF_3 = MODE_BITS[79:60]; - - QL_DSP2 #( - .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) - ) dsp ( - .a(a), - .b(b), - .z(z), - - .f_mode(f_mode), - - .feedback(3'b0), - - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), - - .clk(clk), - .reset(reset), - - .output_select(3'b0), // unregistered output: a * b (0) - .register_inputs(1'b1) // registered inputs - ); -endmodule - -module QL_DSP2_MULT_REGOUT ( // TODO: Name subject to change - input wire [19:0] a, - input wire [17:0] b, - output wire [37:0] z, - - (* clkbuf_sink *) - input wire clk, - // Port not available in architecture file - input wire reset, - - input wire unsigned_a, - input wire unsigned_b, - input wire f_mode, - input wire [2:0] output_select, - input wire register_inputs -); - - parameter [79:0] MODE_BITS = 80'd0; - - localparam [19:0] COEFF_0 = MODE_BITS[19:0]; - localparam [19:0] COEFF_1 = MODE_BITS[39:20]; - localparam [19:0] COEFF_2 = MODE_BITS[59:40]; - localparam [19:0] COEFF_3 = MODE_BITS[79:60]; - - QL_DSP2 #( - .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) - ) dsp ( - .a(a), - .b(b), - .z(z), - - .f_mode(f_mode), - - .feedback(3'b0), - - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), - - .clk(clk), - .reset(reset), - - .output_select(3'b100), // registered output: a * b (4) - .register_inputs(1'b0) // unregistered inputs - ); -endmodule - -module QL_DSP2_MULT_REGIN_REGOUT ( // TODO: Name subject to change - input wire [19:0] a, - input wire [17:0] b, - output wire [37:0] z, - - (* clkbuf_sink *) - input wire clk, - // Port not available in architecture file - input wire reset, - - input wire unsigned_a, - input wire unsigned_b, - input wire f_mode, - input wire [2:0] output_select, - input wire register_inputs -); - - parameter [79:0] MODE_BITS = 80'd0; - - localparam [19:0] COEFF_0 = MODE_BITS[19:0]; - localparam [19:0] COEFF_1 = MODE_BITS[39:20]; - localparam [19:0] COEFF_2 = MODE_BITS[59:40]; - localparam [19:0] COEFF_3 = MODE_BITS[79:60]; - - QL_DSP2 #( - .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) - ) dsp ( - .a(a), - .b(b), - .z(z), - - .f_mode(f_mode), - - .feedback(3'b0), - - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), - - .clk(clk), - .reset(reset), - - .output_select(3'b100), // registered output: a * b (4) - .register_inputs(1'b1) // registered inputs - ); -endmodule - -module QL_DSP2_MULTADD ( - input wire [19:0] a, - input wire [17:0] b, - output wire [37:0] z, - - // begin: Ports not available in architecture file - (* clkbuf_sink *) - input wire clk, - input wire reset, - - input wire [ 2:0] feedback, - input wire load_acc, - // end: Ports not available in architecture file - input wire unsigned_a, - input wire unsigned_b, - - input wire f_mode, - input wire [ 2:0] output_select, - input wire subtract, - input wire register_inputs -); - - parameter [79:0] MODE_BITS = 80'd0; - - localparam [19:0] COEFF_0 = MODE_BITS[19:0]; - localparam [19:0] COEFF_1 = MODE_BITS[39:20]; - localparam [19:0] COEFF_2 = MODE_BITS[59:40]; - localparam [19:0] COEFF_3 = MODE_BITS[79:60]; - - QL_DSP2 #( - .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) - ) dsp ( - .a(a), - .b(b), - .z(z), - - .f_mode(f_mode), - - .feedback(feedback), - .load_acc(load_acc), - - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), - - .clk(clk), - .reset(reset), - - .output_select(output_select), // unregistered output: ACCin (2, 3) - .subtract(subtract), - .register_inputs(1'b0) // unregistered inputs - ); -endmodule - -module QL_DSP2_MULTADD_REGIN ( - input wire [19:0] a, - input wire [17:0] b, - output wire [37:0] z, - - (* clkbuf_sink *) - input wire clk, - // Port not available in architecture file - input wire reset, - - input wire [ 2:0] feedback, - input wire load_acc, - input wire unsigned_a, - input wire unsigned_b, - - input wire f_mode, - input wire [ 2:0] output_select, - input wire subtract, - input wire register_inputs -); - - parameter [79:0] MODE_BITS = 80'd0; - - localparam [19:0] COEFF_0 = MODE_BITS[19:0]; - localparam [19:0] COEFF_1 = MODE_BITS[39:20]; - localparam [19:0] COEFF_2 = MODE_BITS[59:40]; - localparam [19:0] COEFF_3 = MODE_BITS[79:60]; - - QL_DSP2 #( - .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) - ) dsp ( - .a(a), - .b(b), - .z(z), - - .f_mode(f_mode), - - .feedback(feedback), - .load_acc(load_acc), - - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), - - .clk(clk), - .reset(reset), - - .output_select(output_select), // unregistered output: ACCin (2, 3) - .subtract(subtract), - .register_inputs(1'b1) // registered inputs - ); -endmodule - -module QL_DSP2_MULTADD_REGOUT ( - input wire [19:0] a, - input wire [17:0] b, - output wire [37:0] z, - - (* clkbuf_sink *) - input wire clk, - // Port not available in architecture file - input wire reset, - - input wire [ 2:0] feedback, - input wire load_acc, - input wire unsigned_a, - input wire unsigned_b, - - input wire f_mode, - input wire [ 2:0] output_select, - input wire subtract, - input wire register_inputs -); - - parameter [79:0] MODE_BITS = 80'd0; - - localparam [19:0] COEFF_0 = MODE_BITS[19:0]; - localparam [19:0] COEFF_1 = MODE_BITS[39:20]; - localparam [19:0] COEFF_2 = MODE_BITS[59:40]; - localparam [19:0] COEFF_3 = MODE_BITS[79:60]; - - QL_DSP2 #( - .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) - ) dsp ( - .a(a), - .b(b), - .z(z), - - .f_mode(f_mode), - - .feedback(feedback), - .load_acc(load_acc), - - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), - - .clk(clk), - .reset(reset), - - .output_select(output_select), // registered output: ACCin (6, 7) - .subtract(subtract), - .register_inputs(1'b0) // unregistered inputs - ); -endmodule - -module QL_DSP2_MULTADD_REGIN_REGOUT ( - input wire [19:0] a, - input wire [17:0] b, - output wire [37:0] z, - - (* clkbuf_sink *) - input wire clk, - // Port not available in architecture file - input wire reset, - - input wire [ 2:0] feedback, - input wire load_acc, - input wire unsigned_a, - input wire unsigned_b, - - input wire f_mode, - input wire [ 2:0] output_select, - input wire subtract, - input wire register_inputs -); - - parameter [79:0] MODE_BITS = 80'd0; - - localparam [19:0] COEFF_0 = MODE_BITS[19:0]; - localparam [19:0] COEFF_1 = MODE_BITS[39:20]; - localparam [19:0] COEFF_2 = MODE_BITS[59:40]; - localparam [19:0] COEFF_3 = MODE_BITS[79:60]; - - QL_DSP2 #( - .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) - ) dsp ( - .a(a), - .b(b), - .z(z), - - .f_mode(f_mode), - - .feedback(feedback), - .load_acc(load_acc), - - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), - - .clk(clk), - .reset(reset), - - .output_select(output_select), // registered output: ACCin (6, 7) - .subtract(subtract), - .register_inputs(1'b1) // registered inputs - ); -endmodule - -module QL_DSP2_MULTACC ( - input wire [19:0] a, - input wire [17:0] b, - output wire [37:0] z, - - (* clkbuf_sink *) - input wire clk, - // begin: Ports not available in architecture file - input wire reset, - - input wire load_acc, - // end: Ports not available in architecture file - input wire [ 2:0] feedback, - input wire unsigned_a, - input wire unsigned_b, - - input wire f_mode, - input wire [ 2:0] output_select, - input wire subtract, - input wire register_inputs -); - - parameter [79:0] MODE_BITS = 80'd0; - - localparam [19:0] COEFF_0 = MODE_BITS[19:0]; - localparam [19:0] COEFF_1 = MODE_BITS[39:20]; - localparam [19:0] COEFF_2 = MODE_BITS[59:40]; - localparam [19:0] COEFF_3 = MODE_BITS[79:60]; - - QL_DSP2 #( - .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) - ) dsp ( - .a(a), - .b(b), - .z(z), - - .f_mode(f_mode), - - .feedback(feedback), - .load_acc(load_acc), - - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), - - .clk(clk), - .reset(reset), - - .output_select(1'b1), // unregistered output: ACCout (1) - .subtract(subtract), - .register_inputs(1'b0) // unregistered inputs - ); -endmodule - -module QL_DSP2_MULTACC_REGIN ( - input wire [19:0] a, - input wire [17:0] b, - output wire [37:0] z, - - (* clkbuf_sink *) - input wire clk, - // Port not available in architecture file - input wire reset, - - input wire [ 2:0] feedback, - input wire load_acc, - input wire unsigned_a, - input wire unsigned_b, - - input wire f_mode, - input wire [ 2:0] output_select, - input wire subtract, - input wire register_inputs -); - - parameter [79:0] MODE_BITS = 80'd0; - - localparam [19:0] COEFF_0 = MODE_BITS[19:0]; - localparam [19:0] COEFF_1 = MODE_BITS[39:20]; - localparam [19:0] COEFF_2 = MODE_BITS[59:40]; - localparam [19:0] COEFF_3 = MODE_BITS[79:60]; - - QL_DSP2 #( - .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) - ) dsp ( - .a(a), - .b(b), - .z(z), - - .f_mode(f_mode), - - .feedback(feedback), - .load_acc(load_acc), - - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), - - .clk(clk), - .reset(reset), - - .output_select(1'b1), // unregistered output: ACCout (1) - .subtract(subtract), - .register_inputs(1'b1) // registered inputs - ); -endmodule - -module QL_DSP2_MULTACC_REGOUT ( - input wire [19:0] a, - input wire [17:0] b, - output wire [37:0] z, - - (* clkbuf_sink *) - input wire clk, - // Port not available in architecture file - input wire reset, - - input wire [ 2:0] feedback, - input wire load_acc, - input wire unsigned_a, - input wire unsigned_b, - - input wire f_mode, - input wire [ 2:0] output_select, - input wire subtract, - input wire register_inputs -); - - parameter [79:0] MODE_BITS = 80'd0; - - localparam [19:0] COEFF_0 = MODE_BITS[19:0]; - localparam [19:0] COEFF_1 = MODE_BITS[39:20]; - localparam [19:0] COEFF_2 = MODE_BITS[59:40]; - localparam [19:0] COEFF_3 = MODE_BITS[79:60]; - - QL_DSP2 #( - .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) - ) dsp ( - .a(a), - .b(b), - .z(z), - - .f_mode(f_mode), - - .feedback(feedback), - .load_acc(load_acc), - - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), - - .clk(clk), - .reset(reset), - - .output_select(3'b101), // registered output: ACCout (5) - .subtract(subtract), - .register_inputs(1'b0) // unregistered inputs - ); -endmodule - -module QL_DSP2_MULTACC_REGIN_REGOUT ( - input wire [19:0] a, - input wire [17:0] b, - output wire [37:0] z, - - (* clkbuf_sink *) - input wire clk, - // Port not available in architecture file - input wire reset, - - input wire [ 2:0] feedback, - input wire load_acc, - input wire unsigned_a, - input wire unsigned_b, - - input wire f_mode, - input wire [ 2:0] output_select, - input wire subtract, - input wire register_inputs -); - - parameter [79:0] MODE_BITS = 80'd0; - - localparam [19:0] COEFF_0 = MODE_BITS[19:0]; - localparam [19:0] COEFF_1 = MODE_BITS[39:20]; - localparam [19:0] COEFF_2 = MODE_BITS[59:40]; - localparam [19:0] COEFF_3 = MODE_BITS[79:60]; - - QL_DSP2 #( - .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) - ) dsp ( - .a(a), - .b(b), - .z(z), - - .f_mode(f_mode), - - .feedback(feedback), - .load_acc(load_acc), - - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), - - .clk(clk), - .reset(reset), - - .output_select(3'b101), // registered output: ACCout (5) - .subtract(subtract), - .register_inputs(1'b1) // registered inputs - ); -endmodule - -module dsp_t1_sim # ( - parameter NBITS_ACC = 64, - parameter NBITS_A = 20, - parameter NBITS_B = 18, - parameter NBITS_Z = 38 -)( - input wire [NBITS_A-1:0] a_i, - input wire [NBITS_B-1:0] b_i, - output wire [NBITS_Z-1:0] z_o, - output reg [NBITS_B-1:0] dly_b_o, - - input wire [5:0] acc_fir_i, - input wire [2:0] feedback_i, - input wire load_acc_i, - - input wire unsigned_a_i, - input wire unsigned_b_i, - - input wire clock_i, - input wire s_reset, - - input wire saturate_enable_i, - input wire [2:0] output_select_i, - input wire round_i, - input wire [5:0] shift_right_i, - input wire subtract_i, - input wire register_inputs_i, - input wire [NBITS_A-1:0] coef_0_i, - input wire [NBITS_A-1:0] coef_1_i, - input wire [NBITS_A-1:0] coef_2_i, - input wire [NBITS_A-1:0] coef_3_i -); - -// FIXME: The version of Icarus Verilog from Conda seems not to recognize the -// $error macro. Disable this sanity check for now because of that. -`ifndef __ICARUS__ - if (NBITS_ACC < NBITS_A + NBITS_B) - $error("NBITS_ACC must be > NBITS_A + NBITS_B"); -`endif - - // Input registers - reg [NBITS_A-1:0] r_a; - reg [NBITS_B-1:0] r_b; - reg [5:0] r_acc_fir; - reg r_unsigned_a; - reg r_unsigned_b; - reg r_load_acc; - reg [2:0] r_feedback; - reg [5:0] r_shift_d1; - reg [5:0] r_shift_d2; - reg r_subtract; - reg r_sat; - reg r_rnd; - reg [NBITS_ACC-1:0] acc; - - initial begin - r_a <= 0; - r_b <= 0; - - r_acc_fir <= 0; - r_unsigned_a <= 0; - r_unsigned_b <= 0; - r_feedback <= 0; - r_shift_d1 <= 0; - r_shift_d2 <= 0; - r_subtract <= 0; - r_load_acc <= 0; - r_sat <= 0; - r_rnd <= 0; - end - - always @(posedge clock_i or posedge s_reset) begin - if (s_reset) begin - - r_a <= 'h0; - r_b <= 'h0; - - r_acc_fir <= 0; - r_unsigned_a <= 0; - r_unsigned_b <= 0; - r_feedback <= 0; - r_shift_d1 <= 0; - r_shift_d2 <= 0; - r_subtract <= 0; - r_load_acc <= 0; - r_sat <= 0; - r_rnd <= 0; - - end else begin - - r_a <= a_i; - r_b <= b_i; - - r_acc_fir <= acc_fir_i; - r_unsigned_a <= unsigned_a_i; - r_unsigned_b <= unsigned_b_i; - r_feedback <= feedback_i; - r_shift_d1 <= shift_right_i; - r_shift_d2 <= r_shift_d1; - r_subtract <= subtract_i; - r_load_acc <= load_acc_i; - r_sat <= r_sat; - r_rnd <= r_rnd; - - end - end - - // Registered / non-registered input path select - wire [NBITS_A-1:0] a = register_inputs_i ? r_a : a_i; - wire [NBITS_B-1:0] b = register_inputs_i ? r_b : b_i; - - wire [5:0] acc_fir = register_inputs_i ? r_acc_fir : acc_fir_i; - wire unsigned_a = register_inputs_i ? r_unsigned_a : unsigned_a_i; - wire unsigned_b = register_inputs_i ? r_unsigned_b : unsigned_b_i; - wire [2:0] feedback = register_inputs_i ? r_feedback : feedback_i; - wire load_acc = register_inputs_i ? r_load_acc : load_acc_i; - wire subtract = register_inputs_i ? r_subtract : subtract_i; - wire sat = register_inputs_i ? r_sat : saturate_enable_i; - wire rnd = register_inputs_i ? r_rnd : round_i; - - // Shift right control - wire [5:0] shift_d1 = register_inputs_i ? r_shift_d1 : shift_right_i; - wire [5:0] shift_d2 = output_select_i[1] ? shift_d1 : r_shift_d2; - - // Multiplier - wire unsigned_mode = unsigned_a & unsigned_b; - wire [NBITS_A-1:0] mult_a; - assign mult_a = (feedback == 3'h0) ? a : - (feedback == 3'h1) ? a : - (feedback == 3'h2) ? a : - (feedback == 3'h3) ? acc[NBITS_A-1:0] : - (feedback == 3'h4) ? coef_0_i : - (feedback == 3'h5) ? coef_1_i : - (feedback == 3'h6) ? coef_2_i : - coef_3_i; // if feedback == 3'h7 - - wire [NBITS_B-1:0] mult_b = (feedback == 2'h2) ? {NBITS_B{1'b0}} : b; - - wire [NBITS_A-1:0] mult_sgn_a = mult_a[NBITS_A-1]; - wire [NBITS_A-1:0] mult_mag_a = (mult_sgn_a && !unsigned_a) ? (~mult_a + 1) : mult_a; - wire [NBITS_B-1:0] mult_sgn_b = mult_b[NBITS_B-1]; - wire [NBITS_B-1:0] mult_mag_b = (mult_sgn_b && !unsigned_b) ? (~mult_b + 1) : mult_b; - - wire [NBITS_A+NBITS_B-1:0] mult_mag = mult_mag_a * mult_mag_b; - wire mult_sgn = (mult_sgn_a && !unsigned_a) ^ (mult_sgn_b && !unsigned_b); - - wire [NBITS_A+NBITS_B-1:0] mult = (unsigned_a && unsigned_b) ? - (mult_a * mult_b) : (mult_sgn ? (~mult_mag + 1) : mult_mag); - - // Sign extension - wire [NBITS_ACC-1:0] mult_xtnd = unsigned_mode ? - {{(NBITS_ACC-NBITS_A-NBITS_B){1'b0}}, mult[NBITS_A+NBITS_B-1:0]} : - {{(NBITS_ACC-NBITS_A-NBITS_B){mult[NBITS_A+NBITS_B-1]}}, mult[NBITS_A+NBITS_B-1:0]}; - - // Adder - wire [NBITS_ACC-1:0] acc_fir_int = unsigned_a ? {{(NBITS_ACC-NBITS_A){1'b0}}, a} : - {{(NBITS_ACC-NBITS_A){a[NBITS_A-1]}}, a} ; - - wire [NBITS_ACC-1:0] add_a = (subtract) ? (~mult_xtnd + 1) : mult_xtnd; - wire [NBITS_ACC-1:0] add_b = (feedback_i == 3'h0) ? acc : - (feedback_i == 3'h1) ? {{NBITS_ACC}{1'b0}} : (acc_fir_int << acc_fir); - - wire [NBITS_ACC-1:0] add_o = add_a + add_b; - - // Accumulator - initial acc <= 0; - - always @(posedge clock_i or posedge s_reset) - if (s_reset) acc <= 'h0; - else begin - if (load_acc) - acc <= add_o; - else - acc <= acc; - end - - // Adder/accumulator output selection - wire [NBITS_ACC-1:0] acc_out = (output_select_i[1]) ? add_o : acc; - - // Round, shift, saturate - wire [NBITS_ACC-1:0] acc_rnd = (rnd && (shift_right_i != 0)) ? (acc_out + ({{(NBITS_ACC-1){1'b0}}, 1'b1} << (shift_right_i - 1))) : - acc_out; - - wire [NBITS_ACC-1:0] acc_shr = (unsigned_mode) ? (acc_rnd >> shift_right_i) : - (acc_rnd >>> shift_right_i); - - wire [NBITS_ACC-1:0] acc_sat_u = (acc_shr[NBITS_ACC-1:NBITS_Z] != 0) ? {{(NBITS_ACC-NBITS_Z){1'b0}},{NBITS_Z{1'b1}}} : - {{(NBITS_ACC-NBITS_Z){1'b0}},{acc_shr[NBITS_Z-1:0]}}; - - wire [NBITS_ACC-1:0] acc_sat_s = ((|acc_shr[NBITS_ACC-1:NBITS_Z-1] == 1'b0) || - (&acc_shr[NBITS_ACC-1:NBITS_Z-1] == 1'b1)) ? {{(NBITS_ACC-NBITS_Z){1'b0}},{acc_shr[NBITS_Z-1:0]}} : - {{(NBITS_ACC-NBITS_Z){1'b0}},{acc_shr[NBITS_ACC-1],{NBITS_Z-1{~acc_shr[NBITS_ACC-1]}}}}; - - wire [NBITS_ACC-1:0] acc_sat = (sat) ? ((unsigned_mode) ? acc_sat_u : acc_sat_s) : acc_shr; - - // Output signals - wire [NBITS_Z-1:0] z0; - reg [NBITS_Z-1:0] z1; - wire [NBITS_Z-1:0] z2; - - assign z0 = mult_xtnd[NBITS_Z-1:0]; - assign z2 = acc_sat[NBITS_Z-1:0]; - - initial z1 <= 0; - - always @(posedge clock_i or posedge s_reset) - if (s_reset) - z1 <= 0; - else begin - z1 <= (output_select_i == 3'b100) ? z0 : z2; - end - - // Output mux - assign z_o = (output_select_i == 3'h0) ? z0 : - (output_select_i == 3'h1) ? z2 : - (output_select_i == 3'h2) ? z2 : - (output_select_i == 3'h3) ? z2 : - (output_select_i == 3'h4) ? z1 : - (output_select_i == 3'h5) ? z1 : - (output_select_i == 3'h6) ? z1 : - z1; // if output_select_i == 3'h7 - - // B input delayed passthrough - initial dly_b_o <= 0; - - always @(posedge clock_i or posedge s_reset) - if (s_reset) - dly_b_o <= 0; - else - dly_b_o <= b_i; - -endmodule - -module dsp_t1_20x18x64 ( - input wire [19:0] a_i, - input wire [17:0] b_i, - input wire [ 5:0] acc_fir_i, - output wire [37:0] z_o, - output wire [17:0] dly_b_o, - - (* clkbuf_sink *) - input wire clock_i, - input wire reset_i, - - input wire [ 2:0] feedback_i, - input wire load_acc_i, - input wire unsigned_a_i, - input wire unsigned_b_i, - - input wire [ 2:0] output_select_i, - input wire saturate_enable_i, - input wire [ 5:0] shift_right_i, - input wire round_i, - input wire subtract_i, - input wire register_inputs_i -); - - parameter [19:0] COEFF_0 = 20'd0; - parameter [19:0] COEFF_1 = 20'd0; - parameter [19:0] COEFF_2 = 20'd0; - parameter [19:0] COEFF_3 = 20'd0; - - QL_DSP2 #( - .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) - ) dsp ( - .a(a_i), - .b(b_i), - .z(z_o), - .dly_b(dly_b_o), - - .f_mode(1'b0), // 20x18x64 DSP - - .acc_fir(acc_fir_i), - .feedback(feedback_i), - .load_acc(load_acc_i), - - .unsigned_a(unsigned_a_i), - .unsigned_b(unsigned_b_i), - - .clk(clock_i), - .reset(reset_i), - - .saturate_enable(saturate_enable_i), - .output_select(output_select_i), - .round(round_i), - .shift_right(shift_right_i), - .subtract(subtract_i), - .register_inputs(register_inputs_i) - ); -endmodule - -module dsp_t1_10x9x32 ( - input wire [ 9:0] a_i, - input wire [ 8:0] b_i, - input wire [ 5:0] acc_fir_i, - output wire [18:0] z_o, - output wire [ 8:0] dly_b_o, - - (* clkbuf_sink *) - input wire clock_i, - input wire reset_i, - - input wire [ 2:0] feedback_i, - input wire load_acc_i, - input wire unsigned_a_i, - input wire unsigned_b_i, - - input wire [ 2:0] output_select_i, - input wire saturate_enable_i, - input wire [ 5:0] shift_right_i, - input wire round_i, - input wire subtract_i, - input wire register_inputs_i -); - - parameter [9:0] COEFF_0 = 10'd0; - parameter [9:0] COEFF_1 = 10'd0; - parameter [9:0] COEFF_2 = 10'd0; - parameter [9:0] COEFF_3 = 10'd0; - - wire [18:0] z_rem; - wire [8:0] dly_b_rem; - - QL_DSP2 #( - .MODE_BITS({10'd0, COEFF_3, - 10'd0, COEFF_2, - 10'd0, COEFF_1, - 10'd0, COEFF_0}) - ) dsp ( - .a({10'd0, a_i}), - .b({9'd0, b_i}), - .z({z_rem, z_o}), - .dly_b({dly_b_rem, dly_b_o}), - - .f_mode(1'b1), // 10x9x32 DSP - - .acc_fir(acc_fir_i), - .feedback(feedback_i), - .load_acc(load_acc_i), - - .unsigned_a(unsigned_a_i), - .unsigned_b(unsigned_b_i), - - .clk(clock_i), - .reset(reset_i), - - .saturate_enable(saturate_enable_i), - .output_select(output_select_i), - .round(round_i), - .shift_right(shift_right_i), - .subtract(subtract_i), - .register_inputs(register_inputs_i) - ); -endmodule
diff --git a/ql-qlf-plugin/qlf_k6n10f/dsp_sim.v b/ql-qlf-plugin/qlf_k6n10f/dsp_sim.v new file mode 100644 index 0000000..9164d8c --- /dev/null +++ b/ql-qlf-plugin/qlf_k6n10f/dsp_sim.v
@@ -0,0 +1,2380 @@ +// Copyright 2020-2022 F4PGA Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +`default_nettype none + +(* blackbox *) +module QL_DSP1 ( + input wire [19:0] a, + input wire [17:0] b, + (* clkbuf_sink *) + input wire clk0, + (* clkbuf_sink *) + input wire clk1, + input wire [ 1:0] feedback0, + input wire [ 1:0] feedback1, + input wire load_acc0, + input wire load_acc1, + input wire reset0, + input wire reset1, + output reg [37:0] z +); + parameter MODE_BITS = 27'b00000000000000000000000000; +endmodule /* QL_DSP1 */ + + + +// ---------------------------------------- // +// ----- DSP cells simulation modules ----- // +// --------- Control bits in ports -------- // +// ---------------------------------------- // + +module QL_DSP2 ( // TODO: Name subject to change + input wire [19:0] a, + input wire [17:0] b, + input wire [ 5:0] acc_fir, + output wire [37:0] z, + output wire [17:0] dly_b, + + (* clkbuf_sink *) + input wire clk, + input wire reset, + + input wire [2:0] feedback, + input wire load_acc, + input wire unsigned_a, + input wire unsigned_b, + + input wire f_mode, + input wire [2:0] output_select, + input wire saturate_enable, + input wire [5:0] shift_right, + input wire round, + input wire subtract, + input wire register_inputs +); + + parameter [79:0] MODE_BITS = 80'd0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + localparam NBITS_ACC = 64; + localparam NBITS_A = 20; + localparam NBITS_B = 18; + localparam NBITS_Z = 38; + + wire [NBITS_Z-1:0] dsp_full_z; + wire [(NBITS_Z/2)-1:0] dsp_frac0_z; + wire [(NBITS_Z/2)-1:0] dsp_frac1_z; + + wire [NBITS_B-1:0] dsp_full_dly_b; + wire [(NBITS_B/2)-1:0] dsp_frac0_dly_b; + wire [(NBITS_B/2)-1:0] dsp_frac1_dly_b; + + assign z = f_mode ? {dsp_frac1_z, dsp_frac0_z} : dsp_full_z; + assign dly_b = f_mode ? {dsp_frac1_dly_b, dsp_frac0_dly_b} : dsp_full_dly_b; + + // Output used when fmode == 1 + dsp_t1_sim_cfg_ports #( + .NBITS_A(NBITS_A/2), + .NBITS_B(NBITS_B/2), + .NBITS_ACC(NBITS_ACC/2), + .NBITS_Z(NBITS_Z/2) + ) dsp_frac0 ( + .a_i(a[(NBITS_A/2)-1:0]), + .b_i(b[(NBITS_B/2)-1:0]), + .z_o(dsp_frac0_z), + .dly_b_o(dsp_frac0_dly_b), + + .acc_fir_i(acc_fir), + .feedback_i(feedback), + .load_acc_i(load_acc), + + .unsigned_a_i(unsigned_a), + .unsigned_b_i(unsigned_b), + + .clock_i(clk), + .s_reset(reset), + + .saturate_enable_i(saturate_enable), + .output_select_i(output_select), + .round_i(round), + .shift_right_i(shift_right), + .subtract_i(subtract), + .register_inputs_i(register_inputs), + .coef_0_i(COEFF_0[(NBITS_A/2)-1:0]), + .coef_1_i(COEFF_1[(NBITS_A/2)-1:0]), + .coef_2_i(COEFF_2[(NBITS_A/2)-1:0]), + .coef_3_i(COEFF_3[(NBITS_A/2)-1:0]) + ); + + // Output used when fmode == 1 + dsp_t1_sim_cfg_ports #( + .NBITS_A(NBITS_A/2), + .NBITS_B(NBITS_B/2), + .NBITS_ACC(NBITS_ACC/2), + .NBITS_Z(NBITS_Z/2) + ) dsp_frac1 ( + .a_i(a[NBITS_A-1:NBITS_A/2]), + .b_i(b[NBITS_B-1:NBITS_B/2]), + .z_o(dsp_frac1_z), + .dly_b_o(dsp_frac1_dly_b), + + .acc_fir_i(acc_fir), + .feedback_i(feedback), + .load_acc_i(load_acc), + + .unsigned_a_i(unsigned_a), + .unsigned_b_i(unsigned_b), + + .clock_i(clk), + .s_reset(reset), + + .saturate_enable_i(saturate_enable), + .output_select_i(output_select), + .round_i(round), + .shift_right_i(shift_right), + .subtract_i(subtract), + .register_inputs_i(register_inputs), + .coef_0_i(COEFF_0[NBITS_A-1:NBITS_A/2]), + .coef_1_i(COEFF_1[NBITS_A-1:NBITS_A/2]), + .coef_2_i(COEFF_2[NBITS_A-1:NBITS_A/2]), + .coef_3_i(COEFF_3[NBITS_A-1:NBITS_A/2]) + ); + + // Output used when fmode == 0 + dsp_t1_sim_cfg_ports #( + .NBITS_A(NBITS_A), + .NBITS_B(NBITS_B), + .NBITS_ACC(NBITS_ACC), + .NBITS_Z(NBITS_Z) + ) dsp_full ( + .a_i(a), + .b_i(b), + .z_o(dsp_full_z), + .dly_b_o(dsp_full_dly_b), + + .acc_fir_i(acc_fir), + .feedback_i(feedback), + .load_acc_i(load_acc), + + .unsigned_a_i(unsigned_a), + .unsigned_b_i(unsigned_b), + + .clock_i(clk), + .s_reset(reset), + + .saturate_enable_i(saturate_enable), + .output_select_i(output_select), + .round_i(round), + .shift_right_i(shift_right), + .subtract_i(subtract), + .register_inputs_i(register_inputs), + .coef_0_i(COEFF_0), + .coef_1_i(COEFF_1), + .coef_2_i(COEFF_2), + .coef_3_i(COEFF_3) + ); +endmodule + +module QL_DSP2_MULT ( // TODO: Name subject to change + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + // Port not available in architecture file + input wire reset, + + input wire unsigned_a, + input wire unsigned_b, + + input wire f_mode, + input wire [2:0] output_select, + input wire register_inputs +); + + parameter [79:0] MODE_BITS = 80'd0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + QL_DSP2 #( + .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .reset(reset), + + .f_mode(f_mode), + + .feedback(3'b0), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .output_select(3'b0), // unregistered output: a * b (0) + .register_inputs(1'b0) // unregistered inputs + ); +endmodule + +module QL_DSP2_MULT_REGIN ( // TODO: Name subject to change + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + (* clkbuf_sink *) + input wire clk, + // Port not available in architecture file + input wire reset, + + input wire unsigned_a, + input wire unsigned_b, + + input wire f_mode, + input wire [2:0] output_select, + input wire register_inputs +); + + parameter [79:0] MODE_BITS = 80'd0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + QL_DSP2 #( + .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .f_mode(f_mode), + + .feedback(3'b0), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset), + + .output_select(3'b0), // unregistered output: a * b (0) + .register_inputs(1'b1) // registered inputs + ); +endmodule + +module QL_DSP2_MULT_REGOUT ( // TODO: Name subject to change + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + (* clkbuf_sink *) + input wire clk, + // Port not available in architecture file + input wire reset, + + input wire unsigned_a, + input wire unsigned_b, + input wire f_mode, + input wire [2:0] output_select, + input wire register_inputs +); + + parameter [79:0] MODE_BITS = 80'd0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + QL_DSP2 #( + .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .f_mode(f_mode), + + .feedback(3'b0), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset), + + .output_select(3'b100), // registered output: a * b (4) + .register_inputs(1'b0) // unregistered inputs + ); +endmodule + +module QL_DSP2_MULT_REGIN_REGOUT ( // TODO: Name subject to change + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + (* clkbuf_sink *) + input wire clk, + // Port not available in architecture file + input wire reset, + + input wire unsigned_a, + input wire unsigned_b, + input wire f_mode, + input wire [2:0] output_select, + input wire register_inputs +); + + parameter [79:0] MODE_BITS = 80'd0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + QL_DSP2 #( + .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .f_mode(f_mode), + + .feedback(3'b0), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset), + + .output_select(3'b100), // registered output: a * b (4) + .register_inputs(1'b1) // registered inputs + ); +endmodule + +module QL_DSP2_MULTADD ( + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + // begin: Ports not available in architecture file + (* clkbuf_sink *) + input wire clk, + input wire reset, + + input wire [ 2:0] feedback, + input wire load_acc, + // end: Ports not available in architecture file + input wire unsigned_a, + input wire unsigned_b, + + input wire f_mode, + input wire [ 2:0] output_select, + input wire subtract, + input wire register_inputs +); + + parameter [79:0] MODE_BITS = 80'd0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + QL_DSP2 #( + .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .f_mode(f_mode), + + .feedback(feedback), + .load_acc(load_acc), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset), + + .output_select(output_select), // unregistered output: ACCin (2, 3) + .subtract(subtract), + .register_inputs(1'b0) // unregistered inputs + ); +endmodule + +module QL_DSP2_MULTADD_REGIN ( + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + (* clkbuf_sink *) + input wire clk, + // Port not available in architecture file + input wire reset, + + input wire [ 2:0] feedback, + input wire load_acc, + input wire unsigned_a, + input wire unsigned_b, + + input wire f_mode, + input wire [ 2:0] output_select, + input wire subtract, + input wire register_inputs +); + + parameter [79:0] MODE_BITS = 80'd0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + QL_DSP2 #( + .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .f_mode(f_mode), + + .feedback(feedback), + .load_acc(load_acc), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset), + + .output_select(output_select), // unregistered output: ACCin (2, 3) + .subtract(subtract), + .register_inputs(1'b1) // registered inputs + ); +endmodule + +module QL_DSP2_MULTADD_REGOUT ( + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + (* clkbuf_sink *) + input wire clk, + // Port not available in architecture file + input wire reset, + + input wire [ 2:0] feedback, + input wire load_acc, + input wire unsigned_a, + input wire unsigned_b, + + input wire f_mode, + input wire [ 2:0] output_select, + input wire subtract, + input wire register_inputs +); + + parameter [79:0] MODE_BITS = 80'd0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + QL_DSP2 #( + .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .f_mode(f_mode), + + .feedback(feedback), + .load_acc(load_acc), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset), + + .output_select(output_select), // registered output: ACCin (6, 7) + .subtract(subtract), + .register_inputs(1'b0) // unregistered inputs + ); +endmodule + +module QL_DSP2_MULTADD_REGIN_REGOUT ( + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + (* clkbuf_sink *) + input wire clk, + // Port not available in architecture file + input wire reset, + + input wire [ 2:0] feedback, + input wire load_acc, + input wire unsigned_a, + input wire unsigned_b, + + input wire f_mode, + input wire [ 2:0] output_select, + input wire subtract, + input wire register_inputs +); + + parameter [79:0] MODE_BITS = 80'd0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + QL_DSP2 #( + .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .f_mode(f_mode), + + .feedback(feedback), + .load_acc(load_acc), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset), + + .output_select(output_select), // registered output: ACCin (6, 7) + .subtract(subtract), + .register_inputs(1'b1) // registered inputs + ); +endmodule + +module QL_DSP2_MULTACC ( + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + (* clkbuf_sink *) + input wire clk, + // begin: Ports not available in architecture file + input wire reset, + + input wire load_acc, + // end: Ports not available in architecture file + input wire [ 2:0] feedback, + input wire unsigned_a, + input wire unsigned_b, + + input wire f_mode, + input wire [ 2:0] output_select, + input wire subtract, + input wire register_inputs +); + + parameter [79:0] MODE_BITS = 80'd0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + QL_DSP2 #( + .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .f_mode(f_mode), + + .feedback(feedback), + .load_acc(load_acc), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset), + + .output_select(1'b1), // unregistered output: ACCout (1) + .subtract(subtract), + .register_inputs(1'b0) // unregistered inputs + ); +endmodule + +module QL_DSP2_MULTACC_REGIN ( + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + (* clkbuf_sink *) + input wire clk, + // Port not available in architecture file + input wire reset, + + input wire [ 2:0] feedback, + input wire load_acc, + input wire unsigned_a, + input wire unsigned_b, + + input wire f_mode, + input wire [ 2:0] output_select, + input wire subtract, + input wire register_inputs +); + + parameter [79:0] MODE_BITS = 80'd0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + QL_DSP2 #( + .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .f_mode(f_mode), + + .feedback(feedback), + .load_acc(load_acc), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset), + + .output_select(1'b1), // unregistered output: ACCout (1) + .subtract(subtract), + .register_inputs(1'b1) // registered inputs + ); +endmodule + +module QL_DSP2_MULTACC_REGOUT ( + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + (* clkbuf_sink *) + input wire clk, + // Port not available in architecture file + input wire reset, + + input wire [ 2:0] feedback, + input wire load_acc, + input wire unsigned_a, + input wire unsigned_b, + + input wire f_mode, + input wire [ 2:0] output_select, + input wire subtract, + input wire register_inputs +); + + parameter [79:0] MODE_BITS = 80'd0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + QL_DSP2 #( + .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .f_mode(f_mode), + + .feedback(feedback), + .load_acc(load_acc), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset), + + .output_select(3'b101), // registered output: ACCout (5) + .subtract(subtract), + .register_inputs(1'b0) // unregistered inputs + ); +endmodule + +module QL_DSP2_MULTACC_REGIN_REGOUT ( + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + (* clkbuf_sink *) + input wire clk, + // Port not available in architecture file + input wire reset, + + input wire [ 2:0] feedback, + input wire load_acc, + input wire unsigned_a, + input wire unsigned_b, + + input wire f_mode, + input wire [ 2:0] output_select, + input wire subtract, + input wire register_inputs +); + + parameter [79:0] MODE_BITS = 80'd0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + QL_DSP2 #( + .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .f_mode(f_mode), + + .feedback(feedback), + .load_acc(load_acc), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset), + + .output_select(3'b101), // registered output: ACCout (5) + .subtract(subtract), + .register_inputs(1'b1) // registered inputs + ); +endmodule + +module dsp_t1_20x18x64_cfg_ports ( + input wire [19:0] a_i, + input wire [17:0] b_i, + input wire [ 5:0] acc_fir_i, + output wire [37:0] z_o, + output wire [17:0] dly_b_o, + + (* clkbuf_sink *) + input wire clock_i, + input wire reset_i, + + input wire [ 2:0] feedback_i, + input wire load_acc_i, + input wire unsigned_a_i, + input wire unsigned_b_i, + + input wire [ 2:0] output_select_i, + input wire saturate_enable_i, + input wire [ 5:0] shift_right_i, + input wire round_i, + input wire subtract_i, + input wire register_inputs_i +); + + parameter [19:0] COEFF_0 = 20'd0; + parameter [19:0] COEFF_1 = 20'd0; + parameter [19:0] COEFF_2 = 20'd0; + parameter [19:0] COEFF_3 = 20'd0; + + QL_DSP2 #( + .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) + ) dsp ( + .a(a_i), + .b(b_i), + .z(z_o), + .dly_b(dly_b_o), + + .f_mode(1'b0), // 20x18x64 DSP + + .acc_fir(acc_fir_i), + .feedback(feedback_i), + .load_acc(load_acc_i), + + .unsigned_a(unsigned_a_i), + .unsigned_b(unsigned_b_i), + + .clk(clock_i), + .reset(reset_i), + + .saturate_enable(saturate_enable_i), + .output_select(output_select_i), + .round(round_i), + .shift_right(shift_right_i), + .subtract(subtract_i), + .register_inputs(register_inputs_i) + ); +endmodule + +module dsp_t1_10x9x32_cfg_ports ( + input wire [ 9:0] a_i, + input wire [ 8:0] b_i, + input wire [ 5:0] acc_fir_i, + output wire [18:0] z_o, + output wire [ 8:0] dly_b_o, + + (* clkbuf_sink *) + input wire clock_i, + input wire reset_i, + + input wire [ 2:0] feedback_i, + input wire load_acc_i, + input wire unsigned_a_i, + input wire unsigned_b_i, + + input wire [ 2:0] output_select_i, + input wire saturate_enable_i, + input wire [ 5:0] shift_right_i, + input wire round_i, + input wire subtract_i, + input wire register_inputs_i +); + + parameter [9:0] COEFF_0 = 10'd0; + parameter [9:0] COEFF_1 = 10'd0; + parameter [9:0] COEFF_2 = 10'd0; + parameter [9:0] COEFF_3 = 10'd0; + + wire [18:0] z_rem; + wire [8:0] dly_b_rem; + + QL_DSP2 #( + .MODE_BITS({10'd0, COEFF_3, + 10'd0, COEFF_2, + 10'd0, COEFF_1, + 10'd0, COEFF_0}) + ) dsp ( + .a({10'd0, a_i}), + .b({9'd0, b_i}), + .z({z_rem, z_o}), + .dly_b({dly_b_rem, dly_b_o}), + + .f_mode(1'b1), // 10x9x32 DSP + + .acc_fir(acc_fir_i), + .feedback(feedback_i), + .load_acc(load_acc_i), + + .unsigned_a(unsigned_a_i), + .unsigned_b(unsigned_b_i), + + .clk(clock_i), + .reset(reset_i), + + .saturate_enable(saturate_enable_i), + .output_select(output_select_i), + .round(round_i), + .shift_right(shift_right_i), + .subtract(subtract_i), + .register_inputs(register_inputs_i) + ); +endmodule + +module dsp_t1_sim_cfg_ports # ( + parameter NBITS_ACC = 64, + parameter NBITS_A = 20, + parameter NBITS_B = 18, + parameter NBITS_Z = 38 +)( + input wire [NBITS_A-1:0] a_i, + input wire [NBITS_B-1:0] b_i, + output wire [NBITS_Z-1:0] z_o, + output reg [NBITS_B-1:0] dly_b_o, + + input wire [5:0] acc_fir_i, + input wire [2:0] feedback_i, + input wire load_acc_i, + + input wire unsigned_a_i, + input wire unsigned_b_i, + + input wire clock_i, + input wire s_reset, + + input wire saturate_enable_i, + input wire [2:0] output_select_i, + input wire round_i, + input wire [5:0] shift_right_i, + input wire subtract_i, + input wire register_inputs_i, + input wire [NBITS_A-1:0] coef_0_i, + input wire [NBITS_A-1:0] coef_1_i, + input wire [NBITS_A-1:0] coef_2_i, + input wire [NBITS_A-1:0] coef_3_i +); + +// FIXME: The version of Icarus Verilog from Conda seems not to recognize the +// $error macro. Disable this sanity check for now because of that. +`ifndef __ICARUS__ + if (NBITS_ACC < NBITS_A + NBITS_B) + $error("NBITS_ACC must be > NBITS_A + NBITS_B"); +`endif + + // Input registers + reg [NBITS_A-1:0] r_a; + reg [NBITS_B-1:0] r_b; + reg [5:0] r_acc_fir; + reg r_unsigned_a; + reg r_unsigned_b; + reg r_load_acc; + reg [2:0] r_feedback; + reg [5:0] r_shift_d1; + reg [5:0] r_shift_d2; + reg r_subtract; + reg r_sat; + reg r_rnd; + reg [NBITS_ACC-1:0] acc; + + initial begin + r_a <= 0; + r_b <= 0; + + r_acc_fir <= 0; + r_unsigned_a <= 0; + r_unsigned_b <= 0; + r_feedback <= 0; + r_shift_d1 <= 0; + r_shift_d2 <= 0; + r_subtract <= 0; + r_load_acc <= 0; + r_sat <= 0; + r_rnd <= 0; + end + + always @(posedge clock_i or posedge s_reset) begin + if (s_reset) begin + + r_a <= 'h0; + r_b <= 'h0; + + r_acc_fir <= 0; + r_unsigned_a <= 0; + r_unsigned_b <= 0; + r_feedback <= 0; + r_shift_d1 <= 0; + r_shift_d2 <= 0; + r_subtract <= 0; + r_load_acc <= 0; + r_sat <= 0; + r_rnd <= 0; + + end else begin + + r_a <= a_i; + r_b <= b_i; + + r_acc_fir <= acc_fir_i; + r_unsigned_a <= unsigned_a_i; + r_unsigned_b <= unsigned_b_i; + r_feedback <= feedback_i; + r_shift_d1 <= shift_right_i; + r_shift_d2 <= r_shift_d1; + r_subtract <= subtract_i; + r_load_acc <= load_acc_i; + r_sat <= r_sat; + r_rnd <= r_rnd; + + end + end + + // Registered / non-registered input path select + wire [NBITS_A-1:0] a = register_inputs_i ? r_a : a_i; + wire [NBITS_B-1:0] b = register_inputs_i ? r_b : b_i; + + wire [5:0] acc_fir = register_inputs_i ? r_acc_fir : acc_fir_i; + wire unsigned_a = register_inputs_i ? r_unsigned_a : unsigned_a_i; + wire unsigned_b = register_inputs_i ? r_unsigned_b : unsigned_b_i; + wire [2:0] feedback = register_inputs_i ? r_feedback : feedback_i; + wire load_acc = register_inputs_i ? r_load_acc : load_acc_i; + wire subtract = register_inputs_i ? r_subtract : subtract_i; + wire sat = register_inputs_i ? r_sat : saturate_enable_i; + wire rnd = register_inputs_i ? r_rnd : round_i; + + // Shift right control + wire [5:0] shift_d1 = register_inputs_i ? r_shift_d1 : shift_right_i; + wire [5:0] shift_d2 = output_select_i[1] ? shift_d1 : r_shift_d2; + + // Multiplier + wire unsigned_mode = unsigned_a & unsigned_b; + wire [NBITS_A-1:0] mult_a; + assign mult_a = (feedback == 3'h0) ? a : + (feedback == 3'h1) ? a : + (feedback == 3'h2) ? a : + (feedback == 3'h3) ? acc[NBITS_A-1:0] : + (feedback == 3'h4) ? coef_0_i : + (feedback == 3'h5) ? coef_1_i : + (feedback == 3'h6) ? coef_2_i : + coef_3_i; // if feedback == 3'h7 + + wire [NBITS_B-1:0] mult_b = (feedback == 2'h2) ? {NBITS_B{1'b0}} : b; + + wire [NBITS_A-1:0] mult_sgn_a = mult_a[NBITS_A-1]; + wire [NBITS_A-1:0] mult_mag_a = (mult_sgn_a && !unsigned_a) ? (~mult_a + 1) : mult_a; + wire [NBITS_B-1:0] mult_sgn_b = mult_b[NBITS_B-1]; + wire [NBITS_B-1:0] mult_mag_b = (mult_sgn_b && !unsigned_b) ? (~mult_b + 1) : mult_b; + + wire [NBITS_A+NBITS_B-1:0] mult_mag = mult_mag_a * mult_mag_b; + wire mult_sgn = (mult_sgn_a && !unsigned_a) ^ (mult_sgn_b && !unsigned_b); + + wire [NBITS_A+NBITS_B-1:0] mult = (unsigned_a && unsigned_b) ? + (mult_a * mult_b) : (mult_sgn ? (~mult_mag + 1) : mult_mag); + + // Sign extension + wire [NBITS_ACC-1:0] mult_xtnd = unsigned_mode ? + {{(NBITS_ACC-NBITS_A-NBITS_B){1'b0}}, mult[NBITS_A+NBITS_B-1:0]} : + {{(NBITS_ACC-NBITS_A-NBITS_B){mult[NBITS_A+NBITS_B-1]}}, mult[NBITS_A+NBITS_B-1:0]}; + + // Adder + wire [NBITS_ACC-1:0] acc_fir_int = unsigned_a ? {{(NBITS_ACC-NBITS_A){1'b0}}, a} : + {{(NBITS_ACC-NBITS_A){a[NBITS_A-1]}}, a} ; + + wire [NBITS_ACC-1:0] add_a = (subtract) ? (~mult_xtnd + 1) : mult_xtnd; + wire [NBITS_ACC-1:0] add_b = (feedback_i == 3'h0) ? acc : + (feedback_i == 3'h1) ? {{NBITS_ACC}{1'b0}} : (acc_fir_int << acc_fir); + + wire [NBITS_ACC-1:0] add_o = add_a + add_b; + + // Accumulator + initial acc <= 0; + + always @(posedge clock_i or posedge s_reset) + if (s_reset) acc <= 'h0; + else begin + if (load_acc) + acc <= add_o; + else + acc <= acc; + end + + // Adder/accumulator output selection + wire [NBITS_ACC-1:0] acc_out = (output_select_i[1]) ? add_o : acc; + + // Round, shift, saturate + wire [NBITS_ACC-1:0] acc_rnd = (rnd && (shift_right_i != 0)) ? (acc_out + ({{(NBITS_ACC-1){1'b0}}, 1'b1} << (shift_right_i - 1))) : + acc_out; + + wire [NBITS_ACC-1:0] acc_shr = (unsigned_mode) ? (acc_rnd >> shift_right_i) : + (acc_rnd >>> shift_right_i); + + wire [NBITS_ACC-1:0] acc_sat_u = (acc_shr[NBITS_ACC-1:NBITS_Z] != 0) ? {{(NBITS_ACC-NBITS_Z){1'b0}},{NBITS_Z{1'b1}}} : + {{(NBITS_ACC-NBITS_Z){1'b0}},{acc_shr[NBITS_Z-1:0]}}; + + wire [NBITS_ACC-1:0] acc_sat_s = ((|acc_shr[NBITS_ACC-1:NBITS_Z-1] == 1'b0) || + (&acc_shr[NBITS_ACC-1:NBITS_Z-1] == 1'b1)) ? {{(NBITS_ACC-NBITS_Z){1'b0}},{acc_shr[NBITS_Z-1:0]}} : + {{(NBITS_ACC-NBITS_Z){1'b0}},{acc_shr[NBITS_ACC-1],{NBITS_Z-1{~acc_shr[NBITS_ACC-1]}}}}; + + wire [NBITS_ACC-1:0] acc_sat = (sat) ? ((unsigned_mode) ? acc_sat_u : acc_sat_s) : acc_shr; + + // Output signals + wire [NBITS_Z-1:0] z0; + reg [NBITS_Z-1:0] z1; + wire [NBITS_Z-1:0] z2; + + assign z0 = mult_xtnd[NBITS_Z-1:0]; + assign z2 = acc_sat[NBITS_Z-1:0]; + + initial z1 <= 0; + + always @(posedge clock_i or posedge s_reset) + if (s_reset) + z1 <= 0; + else begin + z1 <= (output_select_i == 3'b100) ? z0 : z2; + end + + // Output mux + assign z_o = (output_select_i == 3'h0) ? z0 : + (output_select_i == 3'h1) ? z2 : + (output_select_i == 3'h2) ? z2 : + (output_select_i == 3'h3) ? z2 : + (output_select_i == 3'h4) ? z1 : + (output_select_i == 3'h5) ? z1 : + (output_select_i == 3'h6) ? z1 : + z1; // if output_select_i == 3'h7 + + // B input delayed passthrough + initial dly_b_o <= 0; + + always @(posedge clock_i or posedge s_reset) + if (s_reset) + dly_b_o <= 0; + else + dly_b_o <= b_i; + +endmodule + + + +// ---------------------------------------- // +// ----- DSP cells simulation modules ----- // +// ------ Control bits in parameters ------ // +// ---------------------------------------- // + +module QL_DSP3 ( // TODO: Name subject to change + input wire [19:0] a, + input wire [17:0] b, + input wire [ 5:0] acc_fir, + output wire [37:0] z, + output wire [17:0] dly_b, + + (* clkbuf_sink *) + input wire clk, + input wire reset, + + input wire [2:0] feedback, + input wire load_acc, + input wire unsigned_a, + input wire unsigned_b, + input wire subtract +); + + parameter [92:0] MODE_BITS = 93'b0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + localparam [0:0] F_MODE = MODE_BITS[80]; + localparam [2:0] OUTPUT_SELECT = MODE_BITS[83:81]; + localparam [0:0] SATURATE_ENABLE = MODE_BITS[84]; + localparam [5:0] SHIFT_RIGHT = MODE_BITS[90:85]; + localparam [0:0] ROUND = MODE_BITS[91]; + localparam [0:0] REGISTER_INPUTS = MODE_BITS[92]; + + localparam NBITS_ACC = 64; + localparam NBITS_A = 20; + localparam NBITS_B = 18; + localparam NBITS_Z = 38; + + // Fractured + generate if(F_MODE == 1'b1) begin + + wire [(NBITS_Z/2)-1:0] dsp_frac0_z; + wire [(NBITS_Z/2)-1:0] dsp_frac1_z; + + wire [(NBITS_B/2)-1:0] dsp_frac0_dly_b; + wire [(NBITS_B/2)-1:0] dsp_frac1_dly_b; + + dsp_t1_sim_cfg_params #( + .NBITS_A (NBITS_A/2), + .NBITS_B (NBITS_B/2), + .NBITS_ACC (NBITS_ACC/2), + .NBITS_Z (NBITS_Z/2), + .OUTPUT_SELECT (OUTPUT_SELECT), + .SATURATE_ENABLE (SATURATE_ENABLE), + .SHIFT_RIGHT (SHIFT_RIGHT), + .ROUND (ROUND), + .REGISTER_INPUTS (REGISTER_INPUTS) + ) dsp_frac0 ( + .a_i(a[(NBITS_A/2)-1:0]), + .b_i(b[(NBITS_B/2)-1:0]), + .z_o(dsp_frac0_z), + .dly_b_o(dsp_frac0_dly_b), + + .acc_fir_i(acc_fir), + .feedback_i(feedback), + .load_acc_i(load_acc), + + .unsigned_a_i(unsigned_a), + .unsigned_b_i(unsigned_b), + + .clock_i(clk), + .s_reset(reset), + + .subtract_i(subtract), + .coef_0_i(COEFF_0[(NBITS_A/2)-1:0]), + .coef_1_i(COEFF_1[(NBITS_A/2)-1:0]), + .coef_2_i(COEFF_2[(NBITS_A/2)-1:0]), + .coef_3_i(COEFF_3[(NBITS_A/2)-1:0]) + ); + + dsp_t1_sim_cfg_params #( + .NBITS_A (NBITS_A/2), + .NBITS_B (NBITS_B/2), + .NBITS_ACC (NBITS_ACC/2), + .NBITS_Z (NBITS_Z/2), + .OUTPUT_SELECT (OUTPUT_SELECT), + .SATURATE_ENABLE (SATURATE_ENABLE), + .SHIFT_RIGHT (SHIFT_RIGHT), + .ROUND (ROUND), + .REGISTER_INPUTS (REGISTER_INPUTS) + ) dsp_frac1 ( + .a_i(a[NBITS_A-1:NBITS_A/2]), + .b_i(b[NBITS_B-1:NBITS_B/2]), + .z_o(dsp_frac1_z), + .dly_b_o(dsp_frac1_dly_b), + .acc_fir_i(acc_fir), + .feedback_i(feedback), + .load_acc_i(load_acc), + + .unsigned_a_i(unsigned_a), + .unsigned_b_i(unsigned_b), + + .clock_i(clk), + .s_reset(reset), + + .subtract_i(subtract), + .coef_0_i(COEFF_0[NBITS_A-1:NBITS_A/2]), + .coef_1_i(COEFF_1[NBITS_A-1:NBITS_A/2]), + .coef_2_i(COEFF_2[NBITS_A-1:NBITS_A/2]), + .coef_3_i(COEFF_3[NBITS_A-1:NBITS_A/2]) + ); + + assign z = {dsp_frac1_z, dsp_frac0_z}; + assign dly_b = {dsp_frac1_dly_b, dsp_frac0_dly_b}; + + // Whole + end else begin + + dsp_t1_sim_cfg_params #( + .NBITS_A (NBITS_A), + .NBITS_B (NBITS_B), + .NBITS_ACC (NBITS_ACC), + .NBITS_Z (NBITS_Z), + .OUTPUT_SELECT (OUTPUT_SELECT), + .SATURATE_ENABLE (SATURATE_ENABLE), + .SHIFT_RIGHT (SHIFT_RIGHT), + .ROUND (ROUND), + .REGISTER_INPUTS (REGISTER_INPUTS) + ) dsp_full ( + .a_i(a), + .b_i(b), + .z_o(z), + .dly_b_o(dly_b), + + .acc_fir_i(acc_fir), + .feedback_i(feedback), + .load_acc_i(load_acc), + + .unsigned_a_i(unsigned_a), + .unsigned_b_i(unsigned_b), + + .clock_i(clk), + .s_reset(reset), + + .subtract_i(subtract), + .coef_0_i(COEFF_0), + .coef_1_i(COEFF_1), + .coef_2_i(COEFF_2), + .coef_3_i(COEFF_3) + ); + + end endgenerate + +endmodule + +module QL_DSP3_MULT ( // TODO: Name subject to change + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + input wire reset, + + input wire [2:0] feedback, + input wire unsigned_a, + input wire unsigned_b +); + + parameter [92:0] MODE_BITS = 93'b0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + localparam [0:0] F_MODE = MODE_BITS[80]; + localparam [2:0] OUTPUT_SELECT = 3'b0; // unregistered output: a * b (0) + localparam [0:0] SATURATE_ENABLE = MODE_BITS[84]; + localparam [5:0] SHIFT_RIGHT = MODE_BITS[90:85]; + localparam [0:0] ROUND = MODE_BITS[91]; + localparam [0:0] REGISTER_INPUTS = 1'b0; // unregistered inputs + + QL_DSP3 #( + .MODE_BITS({ + REGISTER_INPUTS, + ROUND, + SHIFT_RIGHT, + SATURATE_ENABLE, + OUTPUT_SELECT, + F_MODE, + COEFF_3, + COEFF_2, + COEFF_1, + COEFF_0 + }) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .reset(reset), + + .feedback(feedback), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b) + ); +endmodule + +module QL_DSP3_MULT_REGIN ( // TODO: Name subject to change + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + (* clkbuf_sink *) + input wire clk, + input wire reset, + + input wire [2:0] feedback, + + input wire unsigned_a, + input wire unsigned_b +); + + wire [37:0] dly_b_o; + parameter [92:0] MODE_BITS = 93'b0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + localparam [0:0] F_MODE = MODE_BITS[80]; + localparam [2:0] OUTPUT_SELECT = 3'b0; // unregistered output: a * b (0) + localparam [0:0] SATURATE_ENABLE = MODE_BITS[84]; + localparam [5:0] SHIFT_RIGHT = MODE_BITS[90:85]; + localparam [0:0] ROUND = MODE_BITS[91]; + localparam [0:0] REGISTER_INPUTS = 1'b1; // registered inputs + + QL_DSP3 #( + .MODE_BITS({ + REGISTER_INPUTS, + ROUND, + SHIFT_RIGHT, + SATURATE_ENABLE, + OUTPUT_SELECT, + F_MODE, + COEFF_3, + COEFF_2, + COEFF_1, + COEFF_0 + }) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .feedback(feedback), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset) + ); +endmodule + +module QL_DSP3_MULT_REGOUT ( // TODO: Name subject to change + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + (* clkbuf_sink *) + input wire clk, + input wire reset, + + input wire [2:0] feedback, + + input wire unsigned_a, + input wire unsigned_b +); + + parameter [92:0] MODE_BITS = 93'b0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + localparam [0:0] F_MODE = MODE_BITS[80]; + localparam [2:0] OUTPUT_SELECT = 3'b100; // registered output: a * b (4) + localparam [0:0] SATURATE_ENABLE = MODE_BITS[84]; + localparam [5:0] SHIFT_RIGHT = MODE_BITS[90:85]; + localparam [0:0] ROUND = MODE_BITS[91]; + localparam [0:0] REGISTER_INPUTS = 1'b0; // unregistered inputs + + QL_DSP3 #( + .MODE_BITS({ + REGISTER_INPUTS, + ROUND, + SHIFT_RIGHT, + SATURATE_ENABLE, + OUTPUT_SELECT, + F_MODE, + COEFF_3, + COEFF_2, + COEFF_1, + COEFF_0 + }) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .feedback(feedback), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset) + ); +endmodule + +module QL_DSP3_MULT_REGIN_REGOUT ( // TODO: Name subject to change + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + (* clkbuf_sink *) + input wire clk, + input wire reset, + + input wire [2:0] feedback, + + input wire unsigned_a, + input wire unsigned_b +); + + parameter [92:0] MODE_BITS = 93'b0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + localparam [0:0] F_MODE = MODE_BITS[80]; + localparam [2:0] OUTPUT_SELECT = 3'b100; // registered output: a * b (4) + localparam [0:0] SATURATE_ENABLE = MODE_BITS[84]; + localparam [5:0] SHIFT_RIGHT = MODE_BITS[90:85]; + localparam [0:0] ROUND = MODE_BITS[91]; + localparam [0:0] REGISTER_INPUTS = 1'b1; // unregistered inputs + + QL_DSP3 #( + .MODE_BITS({ + REGISTER_INPUTS, + ROUND, + SHIFT_RIGHT, + SATURATE_ENABLE, + OUTPUT_SELECT, + F_MODE, + COEFF_3, + COEFF_2, + COEFF_1, + COEFF_0 + }) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .feedback(feedback), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset) + ); +endmodule + +module QL_DSP3_MULTADD ( + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + input wire reset, + + input wire [ 2:0] feedback, + input wire [ 5:0] acc_fir, + input wire load_acc, + input wire unsigned_a, + input wire unsigned_b, + input wire subtract +); + + parameter [92:0] MODE_BITS = 93'b0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + localparam [0:0] F_MODE = MODE_BITS[80]; + localparam [2:0] OUTPUT_SELECT = MODE_BITS[83:81]; + localparam [0:0] SATURATE_ENABLE = MODE_BITS[84]; + localparam [5:0] SHIFT_RIGHT = MODE_BITS[90:85]; + localparam [0:0] ROUND = MODE_BITS[91]; + localparam [0:0] REGISTER_INPUTS = MODE_BITS[92]; + + QL_DSP3 #( + .MODE_BITS({ + REGISTER_INPUTS, + ROUND, + SHIFT_RIGHT, + SATURATE_ENABLE, + OUTPUT_SELECT, + F_MODE, + COEFF_3, + COEFF_2, + COEFF_1, + COEFF_0 + }) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .feedback(feedback), + .acc_fir(acc_fir), + .load_acc(load_acc), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .reset(reset), + .subtract(subtract) + ); +endmodule + +module QL_DSP3_MULTADD_REGIN ( + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + (* clkbuf_sink *) + input wire clk, + input wire reset, + + input wire [ 2:0] feedback, + input wire [ 5:0] acc_fir, + input wire load_acc, + input wire unsigned_a, + input wire unsigned_b, + input wire subtract +); + + parameter [92:0] MODE_BITS = 93'b0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + localparam [0:0] F_MODE = MODE_BITS[80]; + localparam [2:0] OUTPUT_SELECT = MODE_BITS[83:81]; + localparam [0:0] SATURATE_ENABLE = MODE_BITS[84]; + localparam [5:0] SHIFT_RIGHT = MODE_BITS[90:85]; + localparam [0:0] ROUND = MODE_BITS[91]; + localparam [0:0] REGISTER_INPUTS = MODE_BITS[92]; + + QL_DSP3 #( + .MODE_BITS({ + REGISTER_INPUTS, + ROUND, + SHIFT_RIGHT, + SATURATE_ENABLE, + OUTPUT_SELECT, + F_MODE, + COEFF_3, + COEFF_2, + COEFF_1, + COEFF_0 + }) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .feedback(feedback), + .acc_fir(acc_fir), + .load_acc(load_acc), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset), + .subtract(subtract) + ); +endmodule + +module QL_DSP3_MULTADD_REGOUT ( + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + (* clkbuf_sink *) + input wire clk, + input wire reset, + + input wire [ 2:0] feedback, + input wire [ 5:0] acc_fir, + input wire load_acc, + input wire unsigned_a, + input wire unsigned_b, + input wire subtract +); + + parameter [92:0] MODE_BITS = 93'b0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + localparam [0:0] F_MODE = MODE_BITS[80]; + localparam [2:0] OUTPUT_SELECT = MODE_BITS[83:81]; + localparam [0:0] SATURATE_ENABLE = MODE_BITS[84]; + localparam [5:0] SHIFT_RIGHT = MODE_BITS[90:85]; + localparam [0:0] ROUND = MODE_BITS[91]; + localparam [0:0] REGISTER_INPUTS = MODE_BITS[92]; + + QL_DSP3 #( + .MODE_BITS({ + REGISTER_INPUTS, + ROUND, + SHIFT_RIGHT, + SATURATE_ENABLE, + OUTPUT_SELECT, + F_MODE, + COEFF_3, + COEFF_2, + COEFF_1, + COEFF_0 + }) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .feedback(feedback), + .acc_fir(acc_fir), + .load_acc(load_acc), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset), + .subtract(subtract) + ); +endmodule + +module QL_DSP3_MULTADD_REGIN_REGOUT ( + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + (* clkbuf_sink *) + input wire clk, + input wire reset, + + input wire [ 2:0] feedback, + input wire [ 5:0] acc_fir, + input wire load_acc, + input wire unsigned_a, + input wire unsigned_b, + input wire subtract +); + + parameter [92:0] MODE_BITS = 93'b0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + localparam [0:0] F_MODE = MODE_BITS[80]; + localparam [2:0] OUTPUT_SELECT = MODE_BITS[83:81]; + localparam [0:0] SATURATE_ENABLE = MODE_BITS[84]; + localparam [5:0] SHIFT_RIGHT = MODE_BITS[90:85]; + localparam [0:0] ROUND = MODE_BITS[91]; + localparam [0:0] REGISTER_INPUTS = MODE_BITS[92]; + + QL_DSP3 #( + .MODE_BITS({ + REGISTER_INPUTS, + ROUND, + SHIFT_RIGHT, + SATURATE_ENABLE, + OUTPUT_SELECT, + F_MODE, + COEFF_3, + COEFF_2, + COEFF_1, + COEFF_0 + }) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .feedback(feedback), + .acc_fir(acc_fir), + .load_acc(load_acc), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset), + .subtract(subtract) + ); +endmodule + +module QL_DSP3_MULTACC ( + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + (* clkbuf_sink *) + input wire clk, + input wire reset, + + input wire [ 2:0] feedback, + input wire load_acc, + input wire unsigned_a, + input wire unsigned_b, + input wire subtract +); + + parameter [92:0] MODE_BITS = 93'b0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + localparam [0:0] F_MODE = MODE_BITS[80]; + localparam [2:0] OUTPUT_SELECT = MODE_BITS[83:81]; + localparam [0:0] SATURATE_ENABLE = MODE_BITS[84]; + localparam [5:0] SHIFT_RIGHT = MODE_BITS[90:85]; + localparam [0:0] ROUND = MODE_BITS[91]; + localparam [0:0] REGISTER_INPUTS = MODE_BITS[92]; + + QL_DSP3 #( + .MODE_BITS({ + REGISTER_INPUTS, + ROUND, + SHIFT_RIGHT, + SATURATE_ENABLE, + OUTPUT_SELECT, + F_MODE, + COEFF_3, + COEFF_2, + COEFF_1, + COEFF_0 + }) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .feedback(feedback), + .load_acc(load_acc), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset), + .subtract(subtract) + ); +endmodule + +module QL_DSP3_MULTACC_REGIN ( + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + (* clkbuf_sink *) + input wire clk, + input wire reset, + + input wire [ 2:0] feedback, + input wire load_acc, + input wire unsigned_a, + input wire unsigned_b, + input wire subtract +); + + parameter [92:0] MODE_BITS = 93'b0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + localparam [0:0] F_MODE = MODE_BITS[80]; + localparam [2:0] OUTPUT_SELECT = MODE_BITS[83:81]; + localparam [0:0] SATURATE_ENABLE = MODE_BITS[84]; + localparam [5:0] SHIFT_RIGHT = MODE_BITS[90:85]; + localparam [0:0] ROUND = MODE_BITS[91]; + localparam [0:0] REGISTER_INPUTS = MODE_BITS[92]; + + QL_DSP3 #( + .MODE_BITS({ + REGISTER_INPUTS, + ROUND, + SHIFT_RIGHT, + SATURATE_ENABLE, + OUTPUT_SELECT, + F_MODE, + COEFF_3, + COEFF_2, + COEFF_1, + COEFF_0 + }) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .feedback(feedback), + .load_acc(load_acc), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset), + .subtract(subtract) + ); +endmodule + +module QL_DSP3_MULTACC_REGOUT ( + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + (* clkbuf_sink *) + input wire clk, + input wire reset, + + input wire [ 2:0] feedback, + input wire load_acc, + input wire unsigned_a, + input wire unsigned_b, + input wire subtract +); + + parameter [92:0] MODE_BITS = 93'b0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + localparam [0:0] F_MODE = MODE_BITS[80]; + localparam [2:0] OUTPUT_SELECT = MODE_BITS[83:81]; + localparam [0:0] SATURATE_ENABLE = MODE_BITS[84]; + localparam [5:0] SHIFT_RIGHT = MODE_BITS[90:85]; + localparam [0:0] ROUND = MODE_BITS[91]; + localparam [0:0] REGISTER_INPUTS = MODE_BITS[92]; + + QL_DSP3 #( + .MODE_BITS({ + REGISTER_INPUTS, + ROUND, + SHIFT_RIGHT, + SATURATE_ENABLE, + OUTPUT_SELECT, + F_MODE, + COEFF_3, + COEFF_2, + COEFF_1, + COEFF_0 + }) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .feedback(feedback), + .load_acc(load_acc), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset), + .subtract(subtract) + ); +endmodule + +module QL_DSP3_MULTACC_REGIN_REGOUT ( + input wire [19:0] a, + input wire [17:0] b, + output wire [37:0] z, + + (* clkbuf_sink *) + input wire clk, + input wire reset, + + input wire [ 2:0] feedback, + input wire load_acc, + input wire unsigned_a, + input wire unsigned_b, + input wire subtract +); + + parameter [92:0] MODE_BITS = 93'b0; + + localparam [19:0] COEFF_0 = MODE_BITS[19:0]; + localparam [19:0] COEFF_1 = MODE_BITS[39:20]; + localparam [19:0] COEFF_2 = MODE_BITS[59:40]; + localparam [19:0] COEFF_3 = MODE_BITS[79:60]; + + localparam [0:0] F_MODE = MODE_BITS[80]; + localparam [2:0] OUTPUT_SELECT = MODE_BITS[83:81]; + localparam [0:0] SATURATE_ENABLE = MODE_BITS[84]; + localparam [5:0] SHIFT_RIGHT = MODE_BITS[90:85]; + localparam [0:0] ROUND = MODE_BITS[91]; + localparam [0:0] REGISTER_INPUTS = MODE_BITS[92]; + + QL_DSP3 #( + .MODE_BITS({ + REGISTER_INPUTS, + ROUND, + SHIFT_RIGHT, + SATURATE_ENABLE, + OUTPUT_SELECT, + F_MODE, + COEFF_3, + COEFF_2, + COEFF_1, + COEFF_0 + }) + ) dsp ( + .a(a), + .b(b), + .z(z), + + .feedback(feedback), + .load_acc(load_acc), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset), + .subtract(subtract) + ); +endmodule + +module dsp_t1_20x18x64_cfg_params ( + input wire [19:0] a_i, + input wire [17:0] b_i, + input wire [ 5:0] acc_fir_i, + output wire [37:0] z_o, + output wire [17:0] dly_b_o, + + (* clkbuf_sink *) + input wire clock_i, + input wire reset_i, + + input wire [ 2:0] feedback_i, + input wire load_acc_i, + input wire unsigned_a_i, + input wire unsigned_b_i, + input wire subtract_i +); + + parameter [19:0] COEFF_0 = 20'b0; + parameter [19:0] COEFF_1 = 20'b0; + parameter [19:0] COEFF_2 = 20'b0; + parameter [19:0] COEFF_3 = 20'b0; + + parameter [2:0] OUTPUT_SELECT = 3'b0; + parameter [0:0] SATURATE_ENABLE = 1'b0; + parameter [5:0] SHIFT_RIGHT = 6'b0; + parameter [0:0] ROUND = 1'b0; + parameter [0:0] REGISTER_INPUTS = 1'b0; + + QL_DSP3 #( + .MODE_BITS ({ + REGISTER_INPUTS, + ROUND, + SHIFT_RIGHT, + SATURATE_ENABLE, + OUTPUT_SELECT, + 1'b0, // Not fractured + COEFF_3, + COEFF_2, + COEFF_1, + COEFF_0 + }) + ) dsp ( + .a(a_i), + .b(b_i), + .z(z_o), + .dly_b(dly_b_o), + + .acc_fir(acc_fir_i), + .feedback(feedback_i), + .load_acc(load_acc_i), + + .unsigned_a(unsigned_a_i), + .unsigned_b(unsigned_b_i), + + .clk(clock_i), + .reset(reset_i), + .subtract(subtract_i) + ); +endmodule + +module dsp_t1_10x9x32_cfg_params ( + input wire [ 9:0] a_i, + input wire [ 8:0] b_i, + input wire [ 5:0] acc_fir_i, + output wire [18:0] z_o, + output wire [ 8:0] dly_b_o, + + (* clkbuf_sink *) + input wire clock_i, + input wire reset_i, + + input wire [ 2:0] feedback_i, + input wire load_acc_i, + input wire unsigned_a_i, + input wire unsigned_b_i, + input wire subtract_i +); + + parameter [9:0] COEFF_0 = 10'b0; + parameter [9:0] COEFF_1 = 10'b0; + parameter [9:0] COEFF_2 = 10'b0; + parameter [9:0] COEFF_3 = 10'b0; + + parameter [2:0] OUTPUT_SELECT = 3'b0; + parameter [0:0] SATURATE_ENABLE = 1'b0; + parameter [5:0] SHIFT_RIGHT = 6'b0; + parameter [0:0] ROUND = 1'b0; + parameter [0:0] REGISTER_INPUTS = 1'b0; + + wire [18:0] z_rem; + wire [8:0] dly_b_rem; + + QL_DSP3 #( + .MODE_BITS ({ + REGISTER_INPUTS, + ROUND, + SHIFT_RIGHT, + SATURATE_ENABLE, + OUTPUT_SELECT, + 1'b1, // Fractured + 10'd0, COEFF_3, + 10'd0, COEFF_2, + 10'd0, COEFF_1, + 10'd0, COEFF_0 + }) + ) dsp ( + .a({10'b0, a_i}), + .b({9'b0, b_i}), + .z({z_rem, z_o}), + .dly_b({dly_b_rem, dly_b_o}), + + .acc_fir(acc_fir_i), + .feedback(feedback_i), + .load_acc(load_acc_i), + + .unsigned_a(unsigned_a_i), + .unsigned_b(unsigned_b_i), + + .clk(clock_i), + .reset(reset_i), + .subtract(subtract_i) + ); +endmodule + +module dsp_t1_sim_cfg_params # ( + parameter NBITS_ACC = 64, + parameter NBITS_A = 20, + parameter NBITS_B = 18, + parameter NBITS_Z = 38, + + parameter [2:0] OUTPUT_SELECT = 3'b0, + parameter [0:0] SATURATE_ENABLE = 1'b0, + parameter [5:0] SHIFT_RIGHT = 6'b0, + parameter [0:0] ROUND = 1'b0, + parameter [0:0] REGISTER_INPUTS = 1'b0 +)( + input wire [NBITS_A-1:0] a_i, + input wire [NBITS_B-1:0] b_i, + output wire [NBITS_Z-1:0] z_o, + output reg [NBITS_B-1:0] dly_b_o, + + input wire [5:0] acc_fir_i, + input wire [2:0] feedback_i, + input wire load_acc_i, + + input wire unsigned_a_i, + input wire unsigned_b_i, + + input wire clock_i, + input wire s_reset, + + input wire subtract_i, + input wire [NBITS_A-1:0] coef_0_i, + input wire [NBITS_A-1:0] coef_1_i, + input wire [NBITS_A-1:0] coef_2_i, + input wire [NBITS_A-1:0] coef_3_i +); + +// FIXME: The version of Icarus Verilog from Conda seems not to recognize the +// $error macro. Disable this sanity check for now because of that. +`ifndef __ICARUS__ + if (NBITS_ACC < NBITS_A + NBITS_B) + $error("NBITS_ACC must be > NBITS_A + NBITS_B"); +`endif + + // Input registers + reg [NBITS_A-1:0] r_a; + reg [NBITS_B-1:0] r_b; + reg [5:0] r_acc_fir; + reg r_unsigned_a; + reg r_unsigned_b; + reg r_load_acc; + reg [2:0] r_feedback; + reg [5:0] r_shift_d1; + reg [5:0] r_shift_d2; + reg r_subtract; + reg r_sat; + reg r_rnd; + reg [NBITS_ACC-1:0] acc; + + initial begin + r_a <= 0; + r_b <= 0; + + r_acc_fir <= 0; + r_unsigned_a <= 0; + r_unsigned_b <= 0; + r_feedback <= 0; + r_shift_d1 <= 0; + r_shift_d2 <= 0; + r_subtract <= 0; + r_load_acc <= 0; + r_sat <= 0; + r_rnd <= 0; + end + + always @(posedge clock_i or posedge s_reset) begin + if (s_reset) begin + + r_a <= 'h0; + r_b <= 'h0; + + r_acc_fir <= 0; + r_unsigned_a <= 0; + r_unsigned_b <= 0; + r_feedback <= 0; + r_shift_d1 <= 0; + r_shift_d2 <= 0; + r_subtract <= 0; + r_load_acc <= 0; + r_sat <= 0; + r_rnd <= 0; + + end else begin + + r_a <= a_i; + r_b <= b_i; + + r_acc_fir <= acc_fir_i; + r_unsigned_a <= unsigned_a_i; + r_unsigned_b <= unsigned_b_i; + r_feedback <= feedback_i; + r_shift_d1 <= SHIFT_RIGHT; + r_shift_d2 <= r_shift_d1; + r_subtract <= subtract_i; + r_load_acc <= load_acc_i; + r_sat <= r_sat; + r_rnd <= r_rnd; + + end + end + + // Registered / non-registered input path select + wire [NBITS_A-1:0] a = REGISTER_INPUTS ? r_a : a_i; + wire [NBITS_B-1:0] b = REGISTER_INPUTS ? r_b : b_i; + + wire [5:0] acc_fir = REGISTER_INPUTS ? r_acc_fir : acc_fir_i; + wire unsigned_a = REGISTER_INPUTS ? r_unsigned_a : unsigned_a_i; + wire unsigned_b = REGISTER_INPUTS ? r_unsigned_b : unsigned_b_i; + wire [2:0] feedback = REGISTER_INPUTS ? r_feedback : feedback_i; + wire load_acc = REGISTER_INPUTS ? r_load_acc : load_acc_i; + wire subtract = REGISTER_INPUTS ? r_subtract : subtract_i; + wire sat = REGISTER_INPUTS ? r_sat : SATURATE_ENABLE; + wire rnd = REGISTER_INPUTS ? r_rnd : ROUND; + + // Shift right control + wire [5:0] shift_d1 = REGISTER_INPUTS ? r_shift_d1 : SHIFT_RIGHT; + wire [5:0] shift_d2 = OUTPUT_SELECT[1] ? shift_d1 : r_shift_d2; + + // Multiplier + wire unsigned_mode = unsigned_a & unsigned_b; + wire [NBITS_A-1:0] mult_a; + assign mult_a = (feedback == 3'h0) ? a : + (feedback == 3'h1) ? a : + (feedback == 3'h2) ? a : + (feedback == 3'h3) ? acc[NBITS_A-1:0] : + (feedback == 3'h4) ? coef_0_i : + (feedback == 3'h5) ? coef_1_i : + (feedback == 3'h6) ? coef_2_i : + coef_3_i; // if feedback == 3'h7 + + wire [NBITS_B-1:0] mult_b = (feedback == 2'h2) ? {NBITS_B{1'b0}} : b; + + wire [NBITS_A-1:0] mult_sgn_a = mult_a[NBITS_A-1]; + wire [NBITS_A-1:0] mult_mag_a = (mult_sgn_a && !unsigned_a) ? (~mult_a + 1) : mult_a; + wire [NBITS_B-1:0] mult_sgn_b = mult_b[NBITS_B-1]; + wire [NBITS_B-1:0] mult_mag_b = (mult_sgn_b && !unsigned_b) ? (~mult_b + 1) : mult_b; + + wire [NBITS_A+NBITS_B-1:0] mult_mag = mult_mag_a * mult_mag_b; + wire mult_sgn = (mult_sgn_a && !unsigned_a) ^ (mult_sgn_b && !unsigned_b); + + wire [NBITS_A+NBITS_B-1:0] mult = (unsigned_a && unsigned_b) ? + (mult_a * mult_b) : (mult_sgn ? (~mult_mag + 1) : mult_mag); + + // Sign extension + wire [NBITS_ACC-1:0] mult_xtnd = unsigned_mode ? + {{(NBITS_ACC-NBITS_A-NBITS_B){1'b0}}, mult[NBITS_A+NBITS_B-1:0]} : + {{(NBITS_ACC-NBITS_A-NBITS_B){mult[NBITS_A+NBITS_B-1]}}, mult[NBITS_A+NBITS_B-1:0]}; + + // Adder + wire [NBITS_ACC-1:0] acc_fir_int = unsigned_a ? {{(NBITS_ACC-NBITS_A){1'b0}}, a} : + {{(NBITS_ACC-NBITS_A){a[NBITS_A-1]}}, a} ; + + wire [NBITS_ACC-1:0] add_a = (subtract) ? (~mult_xtnd + 1) : mult_xtnd; + wire [NBITS_ACC-1:0] add_b = (feedback_i == 3'h0) ? acc : + (feedback_i == 3'h1) ? {{NBITS_ACC}{1'b0}} : (acc_fir_int << acc_fir); + + wire [NBITS_ACC-1:0] add_o = add_a + add_b; + + // Accumulator + initial acc <= 0; + + always @(posedge clock_i or posedge s_reset) + if (s_reset) acc <= 'h0; + else begin + if (load_acc) + acc <= add_o; + else + acc <= acc; + end + + // Adder/accumulator output selection + wire [NBITS_ACC-1:0] acc_out = (OUTPUT_SELECT[1]) ? add_o : acc; + + // Round, shift, saturate + wire [NBITS_ACC-1:0] acc_rnd = (rnd && (SHIFT_RIGHT != 0)) ? (acc_out + ({{(NBITS_ACC-1){1'b0}}, 1'b1} << (SHIFT_RIGHT - 1))) : + acc_out; + + wire [NBITS_ACC-1:0] acc_shr = (unsigned_mode) ? (acc_rnd >> SHIFT_RIGHT) : + (acc_rnd >>> SHIFT_RIGHT); + + wire [NBITS_ACC-1:0] acc_sat_u = (acc_shr[NBITS_ACC-1:NBITS_Z] != 0) ? {{(NBITS_ACC-NBITS_Z){1'b0}},{NBITS_Z{1'b1}}} : + {{(NBITS_ACC-NBITS_Z){1'b0}},{acc_shr[NBITS_Z-1:0]}}; + + wire [NBITS_ACC-1:0] acc_sat_s = ((|acc_shr[NBITS_ACC-1:NBITS_Z-1] == 1'b0) || + (&acc_shr[NBITS_ACC-1:NBITS_Z-1] == 1'b1)) ? {{(NBITS_ACC-NBITS_Z){1'b0}},{acc_shr[NBITS_Z-1:0]}} : + {{(NBITS_ACC-NBITS_Z){1'b0}},{acc_shr[NBITS_ACC-1],{NBITS_Z-1{~acc_shr[NBITS_ACC-1]}}}}; + + wire [NBITS_ACC-1:0] acc_sat = (sat) ? ((unsigned_mode) ? acc_sat_u : acc_sat_s) : acc_shr; + + // Output signals + wire [NBITS_Z-1:0] z0; + reg [NBITS_Z-1:0] z1; + wire [NBITS_Z-1:0] z2; + + assign z0 = mult_xtnd[NBITS_Z-1:0]; + assign z2 = acc_sat[NBITS_Z-1:0]; + + initial z1 <= 0; + + always @(posedge clock_i or posedge s_reset) + if (s_reset) + z1 <= 0; + else begin + z1 <= (OUTPUT_SELECT == 3'b100) ? z0 : z2; + end + + // Output mux + assign z_o = (OUTPUT_SELECT == 3'h0) ? z0 : + (OUTPUT_SELECT == 3'h1) ? z2 : + (OUTPUT_SELECT == 3'h2) ? z2 : + (OUTPUT_SELECT == 3'h3) ? z2 : + (OUTPUT_SELECT == 3'h4) ? z1 : + (OUTPUT_SELECT == 3'h5) ? z1 : + (OUTPUT_SELECT == 3'h6) ? z1 : + z1; // if OUTPUT_SELECT == 3'h7 + + // B input delayed passthrough + initial dly_b_o <= 0; + + always @(posedge clock_i or posedge s_reset) + if (s_reset) + dly_b_o <= 0; + else + dly_b_o <= b_i; + +endmodule