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