From 531374bec19021588a201d98b50ab19972228ec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 4 Feb 2025 10:30:15 +0100 Subject: [PATCH 01/38] qlf_k6n10f: New ql_dsp pass, move to DSPV2 --- techlibs/quicklogic/Makefile.inc | 3 + techlibs/quicklogic/ql_dsp.cc | 58 + techlibs/quicklogic/ql_dsp.pmg | 266 ++ techlibs/quicklogic/qlf_k6n10f/dsp_map.v | 135 +- techlibs/quicklogic/qlf_k6n10f/dsp_sim.v | 5481 +++++----------------- techlibs/quicklogic/synth_quicklogic.cc | 19 +- 6 files changed, 1553 insertions(+), 4409 deletions(-) create mode 100644 techlibs/quicklogic/ql_dsp.cc create mode 100644 techlibs/quicklogic/ql_dsp.pmg diff --git a/techlibs/quicklogic/Makefile.inc b/techlibs/quicklogic/Makefile.inc index a54a7ec03..da324d17b 100644 --- a/techlibs/quicklogic/Makefile.inc +++ b/techlibs/quicklogic/Makefile.inc @@ -11,9 +11,12 @@ OBJS += techlibs/quicklogic/ql_ioff.o # -------------------------------------- OBJS += techlibs/quicklogic/ql_dsp_macc.o +OBJS += techlibs/quicklogic/ql_dsp.o GENFILES += techlibs/quicklogic/ql_dsp_macc_pm.h techlibs/quicklogic/qlf_k6n10f/bram_types_sim.v techlibs/quicklogic/ql_dsp_macc.o: techlibs/quicklogic/ql_dsp_macc_pm.h +techlibs/quicklogic/ql_dsp.o: techlibs/quicklogic/ql_dsp_pm.h $(eval $(call add_extra_objs,techlibs/quicklogic/ql_dsp_macc_pm.h)) +$(eval $(call add_extra_objs,techlibs/quicklogic/ql_dsp_pm.h)) # -------------------------------------- diff --git a/techlibs/quicklogic/ql_dsp.cc b/techlibs/quicklogic/ql_dsp.cc new file mode 100644 index 000000000..aa8ed6631 --- /dev/null +++ b/techlibs/quicklogic/ql_dsp.cc @@ -0,0 +1,58 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/rtlil.h" +#include "kernel/register.h" +#include "kernel/sigtools.h" + +PRIVATE_NAMESPACE_BEGIN +USING_YOSYS_NAMESPACE + +#include "ql_dsp_pm.h" + +struct QlDspPass : Pass { + QlDspPass() : Pass("ql_dsp", "pack into QuickLogic DSPs") {} + void execute(std::vector args, RTLIL::Design *d) override + { + log_header(d, "Executing QL_DSP pass. (pack into QuickLogic DSPs)\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + break; + } + extra_args(args, argidx, d); + + for (auto module : d->selected_modules()) { + { + ql_dsp_pm pm(module, module->selected_cells()); + pm.run_ql_dsp_pack_regs(); + } + + { + ql_dsp_pm pm(module, module->selected_cells()); + pm.run_ql_dsp_cascade(); + } + + { + ql_dsp_pm pm(module, module->selected_cells()); + pm.run_ql_dsp_pack_regs(); + } + } + } +} QlDspPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/quicklogic/ql_dsp.pmg b/techlibs/quicklogic/ql_dsp.pmg new file mode 100644 index 000000000..e7c253bf5 --- /dev/null +++ b/techlibs/quicklogic/ql_dsp.pmg @@ -0,0 +1,266 @@ +// derived from passes/pmgen/xilinx_dsp.pmg +pattern ql_dsp_pack_regs + +state clock reset +state clock_inferred + +// Variables used for subpatterns +state argQ argD +udata dffD dffQ +udata dffclock dffreset +udata dff + +match dsp + select dsp->type == \dspv2_32x18x64_cfg_ports +endmatch + +code clock_inferred clock reset + clock_inferred = false; + clock = port(dsp, \clock_i); + reset = port(dsp, \reset_i); +endcode + +// try packing on Z output +code argD clock_inferred clock reset + if (port(dsp, \output_select_i)[2] == RTLIL::S0 && + (!dsp->hasPort(\z_cout_o) || nusers(port(dsp, \z_cout_o)) == 1) && + nusers(port(dsp, \z_o)) == 2) { + argD = port(dsp, \z_o); + subpattern(out_dffe); + if (dff) { + clock_inferred = true; + clock = dffclock; + reset = dffreset; + log("%s: inferring Z path register from flip-flop %s\n", log_id(dsp), log_id(dff)); + dsp->connections_[\output_select_i][2] = RTLIL::S1; + dsp->setPort(\z_o, dffQ); + } + } +endcode + +// try packing on B input +code argQ clock_inferred clock reset + if ((!dsp->hasPort(\b_cout_o) || nusers(port(dsp, \b_cout_o)) == 1) && + !param(dsp, \B_REG).as_bool() && + nusers(port(dsp, \b_i)) == 2) { + argQ = port(dsp, \b_i); + subpattern(in_dffe); + if (dff) { + clock_inferred = true; + clock = dffclock; + reset = dffreset; + log("%s: inferring B path register from flip-flop %s\n", log_id(dsp), log_id(dff)); + dsp->parameters[\B_REG] = true; + dsp->setPort(\b_i, dffD); + } + } +endcode + +// try packing on A input +code argQ clock_inferred clock reset + if ((!dsp->hasPort(\a_cout_o) || nusers(port(dsp, \a_cout_o)) == 1) && + !param(dsp, \A_REG).as_bool() && + nusers(port(dsp, \a_i)) == 2) { + argQ = port(dsp, \a_i); + subpattern(in_dffe); + if (dff) { + clock_inferred = true; + clock = dffclock; + reset = dffreset; + log("%s: inferring A path register from flip-flop %s\n", log_id(dsp), log_id(dff)); + dsp->parameters[\A_REG] = true; + dsp->setPort(\a_i, dffD); + } + } +endcode + +code + if (clock_inferred) { + dsp->setPort(\clock_i, clock); + dsp->setPort(\reset_i, reset); + } +endcode + +// ####################### +// Subpattern for matching against input registers, based on knowledge of the +// 'Q' output. +subpattern in_dffe +arg argQ clock reset + +code + dff = nullptr; + if (argQ.empty()) + reject; + for (const auto &c : argQ.chunks()) { + if (!c.wire) { + // Abandon matches when constant Q bits are non-zero + // (doesn't match DSPv2 init/reset behavior) + if (!SigSpec(c).is_fully_zero()) + reject; + continue; + } + + // Abandon matches when 'Q' has the keep attribute set + if (c.wire->get_bool_attribute(\keep)) + reject; + // Abandon matches when 'Q' has a non-zero init attribute set (not supported by DSPv2) + Const init = c.wire->attributes.at(\init, Const()); + if (!init.empty()) + for (auto b : init.extract(c.offset, c.width)) + if (b != State::Sx && b != State::S0) + reject; + } +endcode + +match ff + select ff->type.in($dff, $dffe, $adff, $adffe) + // DSPv2 does not support polarity inversion + select param(ff, \CLK_POLARITY).as_bool() + + // Check that reset value, if present, is fully 0. + filter ff->type.in($dff, $dffe) || param(ff, \ARST_VALUE).is_fully_zero() + + // Check reset polarity, if present + filter ff->type.in($dff, $dffe) || param(ff, \ARST_POLARITY).as_bool() + + // Check that the LSB argQ bit is present (the rest follow by the nusers(...)=2 condition) + slice offset GetSize(port(ff, \D)) + index port(ff, \Q)[offset] === argQ[0] + + define ff_reset (ff->type.in($dff, $dffe) ? RTLIL::S0 : port(ff, \ARST)) + filter clock == RTLIL::Sx || port(ff, \CLK)[0] == clock + filter clock == RTLIL::Sx || ff_reset == reset +endmatch + +code argD + dff = ff; + dffclock = port(ff, \CLK); + dffreset = (ff->type.in($dff, $dffe) ? RTLIL::S0 : port(ff, \ARST)); + dffD = argQ; + dffD.replace(port(ff, \Q), port(ff, \D)); +endcode + + +// ####################### +// Subpattern for matching against output registers, based on knowledge of the +// 'D' input. + +subpattern out_dffe +arg argD clock reset + +code + dff = nullptr; + if (argD.empty()) + reject; + for (const auto &c : argD.chunks()) { + // Abandon matches when 'D' has the keep attribute set + if (!c.wire || c.wire->get_bool_attribute(\keep)) + reject; + } +endcode + +match ff + select ff->type.in($dff, $dffe, $adff, $adffe) + // DSPv2 does not support polarity inversion + select param(ff, \CLK_POLARITY).as_bool() + + // Check that reset value, if present, is fully 0. + filter ff->type.in($dff, $dffe) || param(ff, \ARST_VALUE).is_fully_zero() + + // Check reset polarity, if present + filter ff->type.in($dff, $dffe) || param(ff, \ARST_POLARITY).as_bool() + + slice offset GetSize(port(ff, \D)) + index port(ff, \D)[offset] === argD[0] + + define ff_reset (ff->type.in($dff, $dffe) ? RTLIL::S0 : port(ff, \ARST)) + filter clock == RTLIL::Sx || port(ff, \CLK)[0] == clock + filter clock == RTLIL::Sx || ff_reset == reset +endmatch + +code + dff = ff; + dffclock = port(ff, \CLK); + dffreset = (ff->type.in($dff, $dffe) ? RTLIL::S0 : port(ff, \ARST)); + dffQ = argD; + dffQ.replace(port(ff, \D), port(ff, \Q)); + + // Abandon matches when 'Q' has a defined init attribute set + // (not supported by DSPv2) + for (auto c : dffQ.chunks()) { + Const init = c.wire->attributes.at(\init, Const()); + if (!init.empty()) + for (auto b : init.extract(c.offset, c.width)) + if (b != State::Sx) + reject; + } + + { + // Rewire retired flip-flop slice + SigSpec D = port(ff, \D); + SigSpec Q = port(ff, \Q); + D.replace(argD, module->addWire(NEW_ID, argD.size()), &Q); + D.replace(argD, Const(RTLIL::Sx, argD.size())); + ff->setPort(\D, D); + ff->setPort(\Q, Q); + } +endcode + +pattern ql_dsp_cascade + +match dsp1 + select dsp1->type == \dspv2_32x18x64_cfg_ports + filter !dsp1->hasPort(\z_cout_o) || nusers(port(dsp1, \z_cout_o)) == 1 +endmatch + +match dsp2 + select dsp2->type == \dspv2_32x18x64_cfg_ports + filter port(dsp2, \output_select_i).is_fully_const() + define output_sel port(dsp2, \output_select_i).as_int() + filter output_sel == 3 || (output_sel == 4 && !param(dsp2, \M_REG).as_bool()) + // expect `dsp2` and `add` for exclusive users + filter nusers(port(dsp2, \z_o)) == 2 + filter !dsp2->hasPort(\z_cout_o) || nusers(port(dsp2, \z_cout_o)) == 1 +endmatch + +match add + select add->type.in($add, $sub) + define width param(add, \Y_WIDTH).as_int() + + index port(add, \A)[0] === port(dsp1, \z_o)[0] + filter port(add, \A).size() >= width && port(dsp1, \z_o).size() >= width + filter port(add, \A).extract(0, width) == port(dsp1, \z_o).extract(0, width) + + index port(add, \B)[0] === port(dsp2, \z_o)[0] + filter port(add, \B).size() >= width && port(dsp2, \z_o).size() >= width + filter port(add, \B).extract(0, width) == port(dsp2, \z_o).extract(0, width) +endmatch + +code +endcode + +code + const int z_width = 50; + + log("%s: inferring post-adder from %s (type %s)\n", log_id(dsp2), log_id(add), log_id(add->type)); + + // link up z_cout_o of dsp1 to z_cin_i of dsp2 + Wire *link = module->addWire(NEW_ID, z_width); + dsp1->setPort(\z_cout_o, link); + dsp2->setPort(\z_cin_i, link); + + // configure the path inside dsp2 + if (port(dsp2, \output_select_i).as_int() == 4) { + log("%s: inferring M register\n", log_id(dsp2)); + dsp2->setParam(\M_REG, Const(1, 1)); + } + dsp2->setParam(\SUBTRACT, Const(add->type == $sub, 1)); + dsp2->setPort(\feedback_i, Const(3, 3)); + dsp2->setPort(\output_select_i, Const(3, 3)); + dsp2->setParam(\ROUND, Const(0, 3)); + dsp2->setParam(\SHIFT_REG, Const(0, 6)); + dsp2->setParam(\SATURATE, Const(0, 1)); + + dsp2->setPort(\z_o, {port(dsp2, \z_o).extract_end(port(add, \Y).size()), port(add, \Y)}); + module->remove(add); +endcode diff --git a/techlibs/quicklogic/qlf_k6n10f/dsp_map.v b/techlibs/quicklogic/qlf_k6n10f/dsp_map.v index 127145b71..ded1f592e 100644 --- a/techlibs/quicklogic/qlf_k6n10f/dsp_map.v +++ b/techlibs/quicklogic/qlf_k6n10f/dsp_map.v @@ -1,102 +1,59 @@ -// 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 - -module \$__QL_MUL20X18 (input [19:0] A, input [17:0] B, output [37:0] Y); +module \$__MUL32X18 (input [31:0] A, input [17:0] B, output [49:0] Y); parameter A_SIGNED = 0; parameter B_SIGNED = 0; - parameter A_WIDTH = 0; - parameter B_WIDTH = 0; - parameter Y_WIDTH = 0; + parameter A_WIDTH = 32; + parameter B_WIDTH = 18; + parameter Y_WIDTH = 50; - wire [19:0] a; - wire [17:0] b; - wire [37:0] z; + dspv2_32x18x64_cfg_ports _TECHMAP_REPLACE_ ( + .a_i(A), + .b_i(B), + .c_i(18'd0), + .z_o(Y), - assign a = (A_WIDTH == 20) ? A : - (A_SIGNED) ? {{(20 - A_WIDTH){A[A_WIDTH-1]}}, A} : - {{(20 - A_WIDTH){1'b0}}, A}; - - assign b = (B_WIDTH == 18) ? B : - (B_SIGNED) ? {{(18 - B_WIDTH){B[B_WIDTH-1]}}, B} : - {{(18 - B_WIDTH){1'b0}}, B}; - - (* is_inferred=1 *) - dsp_t1_20x18x64_cfg_ports _TECHMAP_REPLACE_ ( - .a_i (a), - .b_i (b), - .acc_fir_i (6'd0), - .z_o (z), - - .feedback_i (3'd0), - .load_acc_i (1'b0), - .unsigned_a_i (!A_SIGNED), - .unsigned_b_i (!B_SIGNED), - - .output_select_i (3'd0), - .saturate_enable_i (1'b0), - .shift_right_i (6'd0), - .round_i (1'b0), - .subtract_i (1'b0), - .register_inputs_i (1'b0) + .clock_i(1'bx), + .reset_i(1'bx), + .acc_reset_i(1'b0), + .feedback_i(3'd0), + .load_acc_i(1'b0), + .output_select_i(3'd0), + .a_cin_i(32'dx), + .b_cin_i(18'dx), + .z_cin_i(50'dx), +/* TODO: connect to dummy wires? + .a_cout_o(), + .b_cout_o(), + .z_cout_o(), +*/ ); - - assign Y = z; - endmodule -module \$__QL_MUL10X9 (input [9:0] A, input [8:0] B, output [18:0] Y); +module \$__MUL16X9 (input [15:0] A, input [8:0] B, output [24:0] Y); parameter A_SIGNED = 0; parameter B_SIGNED = 0; - parameter A_WIDTH = 0; - parameter B_WIDTH = 0; - parameter Y_WIDTH = 0; + parameter A_WIDTH = 16; + parameter B_WIDTH = 9; + parameter Y_WIDTH = 25; - wire [ 9:0] a; - wire [ 8:0] b; - wire [18:0] z; + dspv2_16x9x32_cfg_ports _TECHMAP_REPLACE_ ( + .a_i(A), + .b_i(B), + .c_i(10'd0), + .z_o(Y), - assign a = (A_WIDTH == 10) ? A : - (A_SIGNED) ? {{(10 - A_WIDTH){A[A_WIDTH-1]}}, A} : - {{(10 - A_WIDTH){1'b0}}, A}; - - assign b = (B_WIDTH == 9) ? B : - (B_SIGNED) ? {{( 9 - B_WIDTH){B[B_WIDTH-1]}}, B} : - {{( 9 - B_WIDTH){1'b0}}, B}; - - (* is_inferred=1 *) - dsp_t1_10x9x32_cfg_ports _TECHMAP_REPLACE_ ( - .a_i (a), - .b_i (b), - .acc_fir_i (6'd0), - .z_o (z), - - .feedback_i (3'd0), - .load_acc_i (1'b0), - .unsigned_a_i (!A_SIGNED), - .unsigned_b_i (!B_SIGNED), - - .output_select_i (3'd0), - .saturate_enable_i (1'b0), - .shift_right_i (6'd0), - .round_i (1'b0), - .subtract_i (1'b0), - .register_inputs_i (1'b0) + .clock_i(1'bx), + .reset_i(1'bx), + .acc_reset_i(1'b0), + .feedback_i(3'd0), + .load_acc_i(1'b0), + .output_select_i(3'd0), + .a_cin_i(32'dx), + .b_cin_i(18'dx), + .z_cin_i(50'dx), +/* TODO: connect to dummy wires? + .a_cout_o(), + .b_cout_o(), + .z_cout_o(), +*/ ); - - - assign Y = z; - endmodule diff --git a/techlibs/quicklogic/qlf_k6n10f/dsp_sim.v b/techlibs/quicklogic/qlf_k6n10f/dsp_sim.v index 5f43b3229..40056bfdb 100644 --- a/techlibs/quicklogic/qlf_k6n10f/dsp_sim.v +++ b/techlibs/quicklogic/qlf_k6n10f/dsp_sim.v @@ -1,4527 +1,1382 @@ -// 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 - `timescale 1ps/1ps `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, +module QL_DSPV2 ( // TODO: Name subject to change + input wire [31:0] a, + input wire [17:0] b, + input wire [17:0] c, + input wire load_acc, + input wire [2:0] feedback, + input wire [2:0] output_select, + output wire [49: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 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 + (* clkbuf_sink *) + input wire clk, + input wire reset, + input wire acc_reset, + + input wire [31:0] a_cin, + input wire [17:0] b_cin, + input wire [49:0] z_cin, + output wire [49:0] z_cout, + output wire [31:0] a_cout, + output wire [17:0] b_cout ); - parameter [79:0] MODE_BITS = 80'd0; + parameter [67:0] MODE_BITS = 68'h00000000000000000; - 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 [31:0] COEFF_0 = MODE_BITS[31:0]; + localparam [5:0] ACC_FIR = MODE_BITS[37:32]; + localparam [2:0] ROUND = MODE_BITS[40:38]; + localparam [4:0] ZC_SHIFT = MODE_BITS[45:41]; + localparam [4:0] ZREG_SHIFT= MODE_BITS[50:46]; + localparam [5:0] SHIFT_REG = MODE_BITS[56:51]; + localparam SATURATE = MODE_BITS[57]; + localparam SUBTRACT = MODE_BITS[58]; + localparam PRE_ADD = MODE_BITS[59]; + localparam A_SEL = MODE_BITS[60]; + localparam A_REG = MODE_BITS[61]; + localparam B_SEL = MODE_BITS[62]; + localparam B_REG = MODE_BITS[63]; + localparam C_REG = MODE_BITS[64]; + localparam BC_REG = MODE_BITS[65]; + localparam M_REG = MODE_BITS[66]; + localparam FRAC_MODE = MODE_BITS[67]; + + localparam NBITS_ACC = 64; + localparam NBITS_A = 32; + localparam NBITS_BC = 18; + localparam NBITS_Z = 50; - 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_Z-1:0] dsp_full_z_cout; + wire [(NBITS_Z/2)-1:0] dsp_frac0_z_cout; + wire [(NBITS_Z/2)-1:0] dsp_frac1_z_cout; - 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_A-1:0] dsp_full_a_cout; + wire [(NBITS_A/2)-1:0] dsp_frac0_a_cout; + wire [(NBITS_A/2)-1:0] dsp_frac1_a_cout; + + wire [NBITS_BC-1:0] dsp_full_b_cout; + wire [(NBITS_BC/2)-1:0] dsp_frac0_b_cout; + wire [(NBITS_BC/2)-1:0] dsp_frac1_b_cout; - 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 = FRAC_MODE ? {dsp_frac1_z, dsp_frac0_z} : dsp_full_z; + assign z_cout = FRAC_MODE ? {dsp_frac1_z_cout, dsp_frac0_z_cout} : dsp_full_z_cout; + assign a_cout = FRAC_MODE ? {dsp_frac1_a_cout, dsp_frac0_a_cout} : dsp_full_a_cout; + assign b_cout = FRAC_MODE ? {dsp_frac1_b_cout, dsp_frac0_b_cout} : dsp_full_b_cout; - 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 ( + // Output used when fmode == 1 + dspv2_sim_cfg_ports #( + .NBITS_A(NBITS_A/2), + .NBITS_BC(NBITS_BC/2), + .NBITS_ACC(NBITS_ACC/2), + .NBITS_Z(NBITS_Z/2) + ) dsp_frac0 ( + // active/fabric ports + .clock_i(clk), + .s_reset(reset), .a_i(a[(NBITS_A/2)-1:0]), - .b_i(b[(NBITS_B/2)-1:0]), + .b_i(b[(NBITS_BC/2)-1:0]), + .c_i(c[(NBITS_BC/2)-1:0]), + .feedback_i(feedback), + .output_select_i(output_select), + .load_acc_i(load_acc), + .rst_acc_i(acc_reset), .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), + // cascade ports (connect to dedicated cascade routing) + .a_cin_i(a_cin[(NBITS_A/2)-1:0]), + .b_cin_i(b_cin[(NBITS_BC/2)-1:0]), + .z_cin_i(z_cin[(NBITS_Z/2)-1:0]), + .z_cout_o(dsp_frac0_z_cout), + .a_cout_o(dsp_frac0_a_cout), + .b_cout_o(dsp_frac0_b_cout), + // configuration ports (tie-offs) + .coeff_i(COEFF_0[(NBITS_A/2)-1:0]), + .acc_fir_i(ACC_FIR), + .round_i(ROUND), + .zc_shift_i(ZC_SHIFT), + .zreg_shift_i(ZREG_SHIFT), + .shift_right_i(SHIFT_REG), + .saturate_enable_i(SATURATE), + .subtract_i(SUBTRACT), + .pre_add_sel_i(PRE_ADD), + .a_sel_i(A_SEL), + .a_reg_i(A_REG), + .b_sel_i(B_SEL), + .b_reg_i(B_REG), + .c_reg_i(C_REG), + .bc_reg_i(BC_REG), + .m_reg_i(M_REG) + ); + // Output used when fmode == 1 + dspv2_sim_cfg_ports #( + .NBITS_A(NBITS_A/2), + .NBITS_BC(NBITS_BC/2), + .NBITS_ACC(NBITS_ACC/2), + .NBITS_Z(NBITS_Z/2) + ) dsp_frac1 ( + // active/fabric ports .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), + .b_i(b[NBITS_BC-1:NBITS_BC/2]), + .c_i(c[NBITS_BC-1:NBITS_BC/2]), .feedback_i(feedback), + .output_select_i(output_select), .load_acc_i(load_acc), + .rst_acc_i(acc_reset), + .z_o(dsp_frac1_z), + // cascade ports (connect to dedicated cascade routing) + .a_cin_i(a_cin[NBITS_A-1:NBITS_A/2]), + .b_cin_i(b_cin[NBITS_BC-1:NBITS_BC/2]), + .z_cin_i(z_cin[NBITS_Z-1:NBITS_Z/2]), + .z_cout_o(dsp_frac1_z_cout), + .a_cout_o(dsp_frac1_a_cout), + .b_cout_o(dsp_frac1_b_cout), + // configuration ports (tie-offs) + .coeff_i(COEFF_0[NBITS_A-1:NBITS_A/2]), + .acc_fir_i(ACC_FIR), + .round_i(ROUND), + .zc_shift_i(ZC_SHIFT), + .zreg_shift_i(ZREG_SHIFT), + .shift_right_i(SHIFT_REG), + .saturate_enable_i(SATURATE), + .subtract_i(SUBTRACT), + .pre_add_sel_i(PRE_ADD), + .a_sel_i(A_SEL), + .a_reg_i(A_REG), + .b_sel_i(B_SEL), + .b_reg_i(B_REG), + .c_reg_i(C_REG), + .bc_reg_i(BC_REG), + .m_reg_i(M_REG) + ); - .unsigned_a_i(unsigned_a), - .unsigned_b_i(unsigned_b), - + // Output used when fmode == 0 + dspv2_sim_cfg_ports #( + .NBITS_A(NBITS_A), + .NBITS_BC(NBITS_BC), + .NBITS_ACC(NBITS_ACC), + .NBITS_Z(NBITS_Z) + ) dsp_full ( + // active/fabric ports .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), + .c_i(c), .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, - - input wire reset, - - 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 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), - .acc_fir(6'b0), - .z(z), - .dly_b(), - - .clk(1'b0), - .reset(reset), - - .f_mode(f_mode), - - .feedback(feedback), - .load_acc(1'b0), - - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), - - .output_select(output_select), // unregistered output: a * b (0) - .saturate_enable(1'b0), - .shift_right(6'b0), - .round(1'b0), - .subtract(1'b0), - .register_inputs(register_inputs) // unregistered inputs - ); - -`ifdef SDF_SIM - specify - (a[0] => z[0]) = 0; - (a[1] => z[0]) = 0; - (a[2] => z[0]) = 0; - (a[3] => z[0]) = 0; - (a[4] => z[0]) = 0; - (a[5] => z[0]) = 0; - (a[6] => z[0]) = 0; - (a[7] => z[0]) = 0; - (a[8] => z[0]) = 0; - (a[9] => z[0]) = 0; - (a[10] => z[0]) = 0; - (a[11] => z[0]) = 0; - (a[12] => z[0]) = 0; - (a[13] => z[0]) = 0; - (a[14] => z[0]) = 0; - (a[15] => z[0]) = 0; - (a[16] => z[0]) = 0; - (a[17] => z[0]) = 0; - (a[18] => z[0]) = 0; - (a[19] => z[0]) = 0; - (b[0] => z[0]) = 0; - (b[1] => z[0]) = 0; - (b[2] => z[0]) = 0; - (b[3] => z[0]) = 0; - (b[4] => z[0]) = 0; - (b[5] => z[0]) = 0; - (b[6] => z[0]) = 0; - (b[7] => z[0]) = 0; - (b[8] => z[0]) = 0; - (b[9] => z[0]) = 0; - (b[10] => z[0]) = 0; - (b[11] => z[0]) = 0; - (b[12] => z[0]) = 0; - (b[13] => z[0]) = 0; - (b[14] => z[0]) = 0; - (b[15] => z[0]) = 0; - (b[16] => z[0]) = 0; - (b[17] => z[0]) = 0; - (a[0] => z[1]) = 0; - (a[1] => z[1]) = 0; - (a[2] => z[1]) = 0; - (a[3] => z[1]) = 0; - (a[4] => z[1]) = 0; - (a[5] => z[1]) = 0; - (a[6] => z[1]) = 0; - (a[7] => z[1]) = 0; - (a[8] => z[1]) = 0; - (a[9] => z[1]) = 0; - (a[10] => z[1]) = 0; - (a[11] => z[1]) = 0; - (a[12] => z[1]) = 0; - (a[13] => z[1]) = 0; - (a[14] => z[1]) = 0; - (a[15] => z[1]) = 0; - (a[16] => z[1]) = 0; - (a[17] => z[1]) = 0; - (a[18] => z[1]) = 0; - (a[19] => z[1]) = 0; - (b[0] => z[1]) = 0; - (b[1] => z[1]) = 0; - (b[2] => z[1]) = 0; - (b[3] => z[1]) = 0; - (b[4] => z[1]) = 0; - (b[5] => z[1]) = 0; - (b[6] => z[1]) = 0; - (b[7] => z[1]) = 0; - (b[8] => z[1]) = 0; - (b[9] => z[1]) = 0; - (b[10] => z[1]) = 0; - (b[11] => z[1]) = 0; - (b[12] => z[1]) = 0; - (b[13] => z[1]) = 0; - (b[14] => z[1]) = 0; - (b[15] => z[1]) = 0; - (b[16] => z[1]) = 0; - (b[17] => z[1]) = 0; - (a[0] => z[2]) = 0; - (a[1] => z[2]) = 0; - (a[2] => z[2]) = 0; - (a[3] => z[2]) = 0; - (a[4] => z[2]) = 0; - (a[5] => z[2]) = 0; - (a[6] => z[2]) = 0; - (a[7] => z[2]) = 0; - (a[8] => z[2]) = 0; - (a[9] => z[2]) = 0; - (a[10] => z[2]) = 0; - (a[11] => z[2]) = 0; - (a[12] => z[2]) = 0; - (a[13] => z[2]) = 0; - (a[14] => z[2]) = 0; - (a[15] => z[2]) = 0; - (a[16] => z[2]) = 0; - (a[17] => z[2]) = 0; - (a[18] => z[2]) = 0; - (a[19] => z[2]) = 0; - (b[0] => z[2]) = 0; - (b[1] => z[2]) = 0; - (b[2] => z[2]) = 0; - (b[3] => z[2]) = 0; - (b[4] => z[2]) = 0; - (b[5] => z[2]) = 0; - (b[6] => z[2]) = 0; - (b[7] => z[2]) = 0; - (b[8] => z[2]) = 0; - (b[9] => z[2]) = 0; - (b[10] => z[2]) = 0; - (b[11] => z[2]) = 0; - (b[12] => z[2]) = 0; - (b[13] => z[2]) = 0; - (b[14] => z[2]) = 0; - (b[15] => z[2]) = 0; - (b[16] => z[2]) = 0; - (b[17] => z[2]) = 0; - (a[0] => z[3]) = 0; - (a[1] => z[3]) = 0; - (a[2] => z[3]) = 0; - (a[3] => z[3]) = 0; - (a[4] => z[3]) = 0; - (a[5] => z[3]) = 0; - (a[6] => z[3]) = 0; - (a[7] => z[3]) = 0; - (a[8] => z[3]) = 0; - (a[9] => z[3]) = 0; - (a[10] => z[3]) = 0; - (a[11] => z[3]) = 0; - (a[12] => z[3]) = 0; - (a[13] => z[3]) = 0; - (a[14] => z[3]) = 0; - (a[15] => z[3]) = 0; - (a[16] => z[3]) = 0; - (a[17] => z[3]) = 0; - (a[18] => z[3]) = 0; - (a[19] => z[3]) = 0; - (b[0] => z[3]) = 0; - (b[1] => z[3]) = 0; - (b[2] => z[3]) = 0; - (b[3] => z[3]) = 0; - (b[4] => z[3]) = 0; - (b[5] => z[3]) = 0; - (b[6] => z[3]) = 0; - (b[7] => z[3]) = 0; - (b[8] => z[3]) = 0; - (b[9] => z[3]) = 0; - (b[10] => z[3]) = 0; - (b[11] => z[3]) = 0; - (b[12] => z[3]) = 0; - (b[13] => z[3]) = 0; - (b[14] => z[3]) = 0; - (b[15] => z[3]) = 0; - (b[16] => z[3]) = 0; - (b[17] => z[3]) = 0; - (a[0] => z[4]) = 0; - (a[1] => z[4]) = 0; - (a[2] => z[4]) = 0; - (a[3] => z[4]) = 0; - (a[4] => z[4]) = 0; - (a[5] => z[4]) = 0; - (a[6] => z[4]) = 0; - (a[7] => z[4]) = 0; - (a[8] => z[4]) = 0; - (a[9] => z[4]) = 0; - (a[10] => z[4]) = 0; - (a[11] => z[4]) = 0; - (a[12] => z[4]) = 0; - (a[13] => z[4]) = 0; - (a[14] => z[4]) = 0; - (a[15] => z[4]) = 0; - (a[16] => z[4]) = 0; - (a[17] => z[4]) = 0; - (a[18] => z[4]) = 0; - (a[19] => z[4]) = 0; - (b[0] => z[4]) = 0; - (b[1] => z[4]) = 0; - (b[2] => z[4]) = 0; - (b[3] => z[4]) = 0; - (b[4] => z[4]) = 0; - (b[5] => z[4]) = 0; - (b[6] => z[4]) = 0; - (b[7] => z[4]) = 0; - (b[8] => z[4]) = 0; - (b[9] => z[4]) = 0; - (b[10] => z[4]) = 0; - (b[11] => z[4]) = 0; - (b[12] => z[4]) = 0; - (b[13] => z[4]) = 0; - (b[14] => z[4]) = 0; - (b[15] => z[4]) = 0; - (b[16] => z[4]) = 0; - (b[17] => z[4]) = 0; - (a[0] => z[5]) = 0; - (a[1] => z[5]) = 0; - (a[2] => z[5]) = 0; - (a[3] => z[5]) = 0; - (a[4] => z[5]) = 0; - (a[5] => z[5]) = 0; - (a[6] => z[5]) = 0; - (a[7] => z[5]) = 0; - (a[8] => z[5]) = 0; - (a[9] => z[5]) = 0; - (a[10] => z[5]) = 0; - (a[11] => z[5]) = 0; - (a[12] => z[5]) = 0; - (a[13] => z[5]) = 0; - (a[14] => z[5]) = 0; - (a[15] => z[5]) = 0; - (a[16] => z[5]) = 0; - (a[17] => z[5]) = 0; - (a[18] => z[5]) = 0; - (a[19] => z[5]) = 0; - (b[0] => z[5]) = 0; - (b[1] => z[5]) = 0; - (b[2] => z[5]) = 0; - (b[3] => z[5]) = 0; - (b[4] => z[5]) = 0; - (b[5] => z[5]) = 0; - (b[6] => z[5]) = 0; - (b[7] => z[5]) = 0; - (b[8] => z[5]) = 0; - (b[9] => z[5]) = 0; - (b[10] => z[5]) = 0; - (b[11] => z[5]) = 0; - (b[12] => z[5]) = 0; - (b[13] => z[5]) = 0; - (b[14] => z[5]) = 0; - (b[15] => z[5]) = 0; - (b[16] => z[5]) = 0; - (b[17] => z[5]) = 0; - (a[0] => z[6]) = 0; - (a[1] => z[6]) = 0; - (a[2] => z[6]) = 0; - (a[3] => z[6]) = 0; - (a[4] => z[6]) = 0; - (a[5] => z[6]) = 0; - (a[6] => z[6]) = 0; - (a[7] => z[6]) = 0; - (a[8] => z[6]) = 0; - (a[9] => z[6]) = 0; - (a[10] => z[6]) = 0; - (a[11] => z[6]) = 0; - (a[12] => z[6]) = 0; - (a[13] => z[6]) = 0; - (a[14] => z[6]) = 0; - (a[15] => z[6]) = 0; - (a[16] => z[6]) = 0; - (a[17] => z[6]) = 0; - (a[18] => z[6]) = 0; - (a[19] => z[6]) = 0; - (b[0] => z[6]) = 0; - (b[1] => z[6]) = 0; - (b[2] => z[6]) = 0; - (b[3] => z[6]) = 0; - (b[4] => z[6]) = 0; - (b[5] => z[6]) = 0; - (b[6] => z[6]) = 0; - (b[7] => z[6]) = 0; - (b[8] => z[6]) = 0; - (b[9] => z[6]) = 0; - (b[10] => z[6]) = 0; - (b[11] => z[6]) = 0; - (b[12] => z[6]) = 0; - (b[13] => z[6]) = 0; - (b[14] => z[6]) = 0; - (b[15] => z[6]) = 0; - (b[16] => z[6]) = 0; - (b[17] => z[6]) = 0; - (a[0] => z[7]) = 0; - (a[1] => z[7]) = 0; - (a[2] => z[7]) = 0; - (a[3] => z[7]) = 0; - (a[4] => z[7]) = 0; - (a[5] => z[7]) = 0; - (a[6] => z[7]) = 0; - (a[7] => z[7]) = 0; - (a[8] => z[7]) = 0; - (a[9] => z[7]) = 0; - (a[10] => z[7]) = 0; - (a[11] => z[7]) = 0; - (a[12] => z[7]) = 0; - (a[13] => z[7]) = 0; - (a[14] => z[7]) = 0; - (a[15] => z[7]) = 0; - (a[16] => z[7]) = 0; - (a[17] => z[7]) = 0; - (a[18] => z[7]) = 0; - (a[19] => z[7]) = 0; - (b[0] => z[7]) = 0; - (b[1] => z[7]) = 0; - (b[2] => z[7]) = 0; - (b[3] => z[7]) = 0; - (b[4] => z[7]) = 0; - (b[5] => z[7]) = 0; - (b[6] => z[7]) = 0; - (b[7] => z[7]) = 0; - (b[8] => z[7]) = 0; - (b[9] => z[7]) = 0; - (b[10] => z[7]) = 0; - (b[11] => z[7]) = 0; - (b[12] => z[7]) = 0; - (b[13] => z[7]) = 0; - (b[14] => z[7]) = 0; - (b[15] => z[7]) = 0; - (b[16] => z[7]) = 0; - (b[17] => z[7]) = 0; - (a[0] => z[8]) = 0; - (a[1] => z[8]) = 0; - (a[2] => z[8]) = 0; - (a[3] => z[8]) = 0; - (a[4] => z[8]) = 0; - (a[5] => z[8]) = 0; - (a[6] => z[8]) = 0; - (a[7] => z[8]) = 0; - (a[8] => z[8]) = 0; - (a[9] => z[8]) = 0; - (a[10] => z[8]) = 0; - (a[11] => z[8]) = 0; - (a[12] => z[8]) = 0; - (a[13] => z[8]) = 0; - (a[14] => z[8]) = 0; - (a[15] => z[8]) = 0; - (a[16] => z[8]) = 0; - (a[17] => z[8]) = 0; - (a[18] => z[8]) = 0; - (a[19] => z[8]) = 0; - (b[0] => z[8]) = 0; - (b[1] => z[8]) = 0; - (b[2] => z[8]) = 0; - (b[3] => z[8]) = 0; - (b[4] => z[8]) = 0; - (b[5] => z[8]) = 0; - (b[6] => z[8]) = 0; - (b[7] => z[8]) = 0; - (b[8] => z[8]) = 0; - (b[9] => z[8]) = 0; - (b[10] => z[8]) = 0; - (b[11] => z[8]) = 0; - (b[12] => z[8]) = 0; - (b[13] => z[8]) = 0; - (b[14] => z[8]) = 0; - (b[15] => z[8]) = 0; - (b[16] => z[8]) = 0; - (b[17] => z[8]) = 0; - (a[0] => z[9]) = 0; - (a[1] => z[9]) = 0; - (a[2] => z[9]) = 0; - (a[3] => z[9]) = 0; - (a[4] => z[9]) = 0; - (a[5] => z[9]) = 0; - (a[6] => z[9]) = 0; - (a[7] => z[9]) = 0; - (a[8] => z[9]) = 0; - (a[9] => z[9]) = 0; - (a[10] => z[9]) = 0; - (a[11] => z[9]) = 0; - (a[12] => z[9]) = 0; - (a[13] => z[9]) = 0; - (a[14] => z[9]) = 0; - (a[15] => z[9]) = 0; - (a[16] => z[9]) = 0; - (a[17] => z[9]) = 0; - (a[18] => z[9]) = 0; - (a[19] => z[9]) = 0; - (b[0] => z[9]) = 0; - (b[1] => z[9]) = 0; - (b[2] => z[9]) = 0; - (b[3] => z[9]) = 0; - (b[4] => z[9]) = 0; - (b[5] => z[9]) = 0; - (b[6] => z[9]) = 0; - (b[7] => z[9]) = 0; - (b[8] => z[9]) = 0; - (b[9] => z[9]) = 0; - (b[10] => z[9]) = 0; - (b[11] => z[9]) = 0; - (b[12] => z[9]) = 0; - (b[13] => z[9]) = 0; - (b[14] => z[9]) = 0; - (b[15] => z[9]) = 0; - (b[16] => z[9]) = 0; - (b[17] => z[9]) = 0; - (a[0] => z[10]) = 0; - (a[1] => z[10]) = 0; - (a[2] => z[10]) = 0; - (a[3] => z[10]) = 0; - (a[4] => z[10]) = 0; - (a[5] => z[10]) = 0; - (a[6] => z[10]) = 0; - (a[7] => z[10]) = 0; - (a[8] => z[10]) = 0; - (a[9] => z[10]) = 0; - (a[10] => z[10]) = 0; - (a[11] => z[10]) = 0; - (a[12] => z[10]) = 0; - (a[13] => z[10]) = 0; - (a[14] => z[10]) = 0; - (a[15] => z[10]) = 0; - (a[16] => z[10]) = 0; - (a[17] => z[10]) = 0; - (a[18] => z[10]) = 0; - (a[19] => z[10]) = 0; - (b[0] => z[10]) = 0; - (b[1] => z[10]) = 0; - (b[2] => z[10]) = 0; - (b[3] => z[10]) = 0; - (b[4] => z[10]) = 0; - (b[5] => z[10]) = 0; - (b[6] => z[10]) = 0; - (b[7] => z[10]) = 0; - (b[8] => z[10]) = 0; - (b[9] => z[10]) = 0; - (b[10] => z[10]) = 0; - (b[11] => z[10]) = 0; - (b[12] => z[10]) = 0; - (b[13] => z[10]) = 0; - (b[14] => z[10]) = 0; - (b[15] => z[10]) = 0; - (b[16] => z[10]) = 0; - (b[17] => z[10]) = 0; - (a[0] => z[11]) = 0; - (a[1] => z[11]) = 0; - (a[2] => z[11]) = 0; - (a[3] => z[11]) = 0; - (a[4] => z[11]) = 0; - (a[5] => z[11]) = 0; - (a[6] => z[11]) = 0; - (a[7] => z[11]) = 0; - (a[8] => z[11]) = 0; - (a[9] => z[11]) = 0; - (a[10] => z[11]) = 0; - (a[11] => z[11]) = 0; - (a[12] => z[11]) = 0; - (a[13] => z[11]) = 0; - (a[14] => z[11]) = 0; - (a[15] => z[11]) = 0; - (a[16] => z[11]) = 0; - (a[17] => z[11]) = 0; - (a[18] => z[11]) = 0; - (a[19] => z[11]) = 0; - (b[0] => z[11]) = 0; - (b[1] => z[11]) = 0; - (b[2] => z[11]) = 0; - (b[3] => z[11]) = 0; - (b[4] => z[11]) = 0; - (b[5] => z[11]) = 0; - (b[6] => z[11]) = 0; - (b[7] => z[11]) = 0; - (b[8] => z[11]) = 0; - (b[9] => z[11]) = 0; - (b[10] => z[11]) = 0; - (b[11] => z[11]) = 0; - (b[12] => z[11]) = 0; - (b[13] => z[11]) = 0; - (b[14] => z[11]) = 0; - (b[15] => z[11]) = 0; - (b[16] => z[11]) = 0; - (b[17] => z[11]) = 0; - (a[0] => z[12]) = 0; - (a[1] => z[12]) = 0; - (a[2] => z[12]) = 0; - (a[3] => z[12]) = 0; - (a[4] => z[12]) = 0; - (a[5] => z[12]) = 0; - (a[6] => z[12]) = 0; - (a[7] => z[12]) = 0; - (a[8] => z[12]) = 0; - (a[9] => z[12]) = 0; - (a[10] => z[12]) = 0; - (a[11] => z[12]) = 0; - (a[12] => z[12]) = 0; - (a[13] => z[12]) = 0; - (a[14] => z[12]) = 0; - (a[15] => z[12]) = 0; - (a[16] => z[12]) = 0; - (a[17] => z[12]) = 0; - (a[18] => z[12]) = 0; - (a[19] => z[12]) = 0; - (b[0] => z[12]) = 0; - (b[1] => z[12]) = 0; - (b[2] => z[12]) = 0; - (b[3] => z[12]) = 0; - (b[4] => z[12]) = 0; - (b[5] => z[12]) = 0; - (b[6] => z[12]) = 0; - (b[7] => z[12]) = 0; - (b[8] => z[12]) = 0; - (b[9] => z[12]) = 0; - (b[10] => z[12]) = 0; - (b[11] => z[12]) = 0; - (b[12] => z[12]) = 0; - (b[13] => z[12]) = 0; - (b[14] => z[12]) = 0; - (b[15] => z[12]) = 0; - (b[16] => z[12]) = 0; - (b[17] => z[12]) = 0; - (a[0] => z[13]) = 0; - (a[1] => z[13]) = 0; - (a[2] => z[13]) = 0; - (a[3] => z[13]) = 0; - (a[4] => z[13]) = 0; - (a[5] => z[13]) = 0; - (a[6] => z[13]) = 0; - (a[7] => z[13]) = 0; - (a[8] => z[13]) = 0; - (a[9] => z[13]) = 0; - (a[10] => z[13]) = 0; - (a[11] => z[13]) = 0; - (a[12] => z[13]) = 0; - (a[13] => z[13]) = 0; - (a[14] => z[13]) = 0; - (a[15] => z[13]) = 0; - (a[16] => z[13]) = 0; - (a[17] => z[13]) = 0; - (a[18] => z[13]) = 0; - (a[19] => z[13]) = 0; - (b[0] => z[13]) = 0; - (b[1] => z[13]) = 0; - (b[2] => z[13]) = 0; - (b[3] => z[13]) = 0; - (b[4] => z[13]) = 0; - (b[5] => z[13]) = 0; - (b[6] => z[13]) = 0; - (b[7] => z[13]) = 0; - (b[8] => z[13]) = 0; - (b[9] => z[13]) = 0; - (b[10] => z[13]) = 0; - (b[11] => z[13]) = 0; - (b[12] => z[13]) = 0; - (b[13] => z[13]) = 0; - (b[14] => z[13]) = 0; - (b[15] => z[13]) = 0; - (b[16] => z[13]) = 0; - (b[17] => z[13]) = 0; - (a[0] => z[14]) = 0; - (a[1] => z[14]) = 0; - (a[2] => z[14]) = 0; - (a[3] => z[14]) = 0; - (a[4] => z[14]) = 0; - (a[5] => z[14]) = 0; - (a[6] => z[14]) = 0; - (a[7] => z[14]) = 0; - (a[8] => z[14]) = 0; - (a[9] => z[14]) = 0; - (a[10] => z[14]) = 0; - (a[11] => z[14]) = 0; - (a[12] => z[14]) = 0; - (a[13] => z[14]) = 0; - (a[14] => z[14]) = 0; - (a[15] => z[14]) = 0; - (a[16] => z[14]) = 0; - (a[17] => z[14]) = 0; - (a[18] => z[14]) = 0; - (a[19] => z[14]) = 0; - (b[0] => z[14]) = 0; - (b[1] => z[14]) = 0; - (b[2] => z[14]) = 0; - (b[3] => z[14]) = 0; - (b[4] => z[14]) = 0; - (b[5] => z[14]) = 0; - (b[6] => z[14]) = 0; - (b[7] => z[14]) = 0; - (b[8] => z[14]) = 0; - (b[9] => z[14]) = 0; - (b[10] => z[14]) = 0; - (b[11] => z[14]) = 0; - (b[12] => z[14]) = 0; - (b[13] => z[14]) = 0; - (b[14] => z[14]) = 0; - (b[15] => z[14]) = 0; - (b[16] => z[14]) = 0; - (b[17] => z[14]) = 0; - (a[0] => z[15]) = 0; - (a[1] => z[15]) = 0; - (a[2] => z[15]) = 0; - (a[3] => z[15]) = 0; - (a[4] => z[15]) = 0; - (a[5] => z[15]) = 0; - (a[6] => z[15]) = 0; - (a[7] => z[15]) = 0; - (a[8] => z[15]) = 0; - (a[9] => z[15]) = 0; - (a[10] => z[15]) = 0; - (a[11] => z[15]) = 0; - (a[12] => z[15]) = 0; - (a[13] => z[15]) = 0; - (a[14] => z[15]) = 0; - (a[15] => z[15]) = 0; - (a[16] => z[15]) = 0; - (a[17] => z[15]) = 0; - (a[18] => z[15]) = 0; - (a[19] => z[15]) = 0; - (b[0] => z[15]) = 0; - (b[1] => z[15]) = 0; - (b[2] => z[15]) = 0; - (b[3] => z[15]) = 0; - (b[4] => z[15]) = 0; - (b[5] => z[15]) = 0; - (b[6] => z[15]) = 0; - (b[7] => z[15]) = 0; - (b[8] => z[15]) = 0; - (b[9] => z[15]) = 0; - (b[10] => z[15]) = 0; - (b[11] => z[15]) = 0; - (b[12] => z[15]) = 0; - (b[13] => z[15]) = 0; - (b[14] => z[15]) = 0; - (b[15] => z[15]) = 0; - (b[16] => z[15]) = 0; - (b[17] => z[15]) = 0; - (a[0] => z[16]) = 0; - (a[1] => z[16]) = 0; - (a[2] => z[16]) = 0; - (a[3] => z[16]) = 0; - (a[4] => z[16]) = 0; - (a[5] => z[16]) = 0; - (a[6] => z[16]) = 0; - (a[7] => z[16]) = 0; - (a[8] => z[16]) = 0; - (a[9] => z[16]) = 0; - (a[10] => z[16]) = 0; - (a[11] => z[16]) = 0; - (a[12] => z[16]) = 0; - (a[13] => z[16]) = 0; - (a[14] => z[16]) = 0; - (a[15] => z[16]) = 0; - (a[16] => z[16]) = 0; - (a[17] => z[16]) = 0; - (a[18] => z[16]) = 0; - (a[19] => z[16]) = 0; - (b[0] => z[16]) = 0; - (b[1] => z[16]) = 0; - (b[2] => z[16]) = 0; - (b[3] => z[16]) = 0; - (b[4] => z[16]) = 0; - (b[5] => z[16]) = 0; - (b[6] => z[16]) = 0; - (b[7] => z[16]) = 0; - (b[8] => z[16]) = 0; - (b[9] => z[16]) = 0; - (b[10] => z[16]) = 0; - (b[11] => z[16]) = 0; - (b[12] => z[16]) = 0; - (b[13] => z[16]) = 0; - (b[14] => z[16]) = 0; - (b[15] => z[16]) = 0; - (b[16] => z[16]) = 0; - (b[17] => z[16]) = 0; - (a[0] => z[17]) = 0; - (a[1] => z[17]) = 0; - (a[2] => z[17]) = 0; - (a[3] => z[17]) = 0; - (a[4] => z[17]) = 0; - (a[5] => z[17]) = 0; - (a[6] => z[17]) = 0; - (a[7] => z[17]) = 0; - (a[8] => z[17]) = 0; - (a[9] => z[17]) = 0; - (a[10] => z[17]) = 0; - (a[11] => z[17]) = 0; - (a[12] => z[17]) = 0; - (a[13] => z[17]) = 0; - (a[14] => z[17]) = 0; - (a[15] => z[17]) = 0; - (a[16] => z[17]) = 0; - (a[17] => z[17]) = 0; - (a[18] => z[17]) = 0; - (a[19] => z[17]) = 0; - (b[0] => z[17]) = 0; - (b[1] => z[17]) = 0; - (b[2] => z[17]) = 0; - (b[3] => z[17]) = 0; - (b[4] => z[17]) = 0; - (b[5] => z[17]) = 0; - (b[6] => z[17]) = 0; - (b[7] => z[17]) = 0; - (b[8] => z[17]) = 0; - (b[9] => z[17]) = 0; - (b[10] => z[17]) = 0; - (b[11] => z[17]) = 0; - (b[12] => z[17]) = 0; - (b[13] => z[17]) = 0; - (b[14] => z[17]) = 0; - (b[15] => z[17]) = 0; - (b[16] => z[17]) = 0; - (b[17] => z[17]) = 0; - (a[0] => z[18]) = 0; - (a[1] => z[18]) = 0; - (a[2] => z[18]) = 0; - (a[3] => z[18]) = 0; - (a[4] => z[18]) = 0; - (a[5] => z[18]) = 0; - (a[6] => z[18]) = 0; - (a[7] => z[18]) = 0; - (a[8] => z[18]) = 0; - (a[9] => z[18]) = 0; - (a[10] => z[18]) = 0; - (a[11] => z[18]) = 0; - (a[12] => z[18]) = 0; - (a[13] => z[18]) = 0; - (a[14] => z[18]) = 0; - (a[15] => z[18]) = 0; - (a[16] => z[18]) = 0; - (a[17] => z[18]) = 0; - (a[18] => z[18]) = 0; - (a[19] => z[18]) = 0; - (b[0] => z[18]) = 0; - (b[1] => z[18]) = 0; - (b[2] => z[18]) = 0; - (b[3] => z[18]) = 0; - (b[4] => z[18]) = 0; - (b[5] => z[18]) = 0; - (b[6] => z[18]) = 0; - (b[7] => z[18]) = 0; - (b[8] => z[18]) = 0; - (b[9] => z[18]) = 0; - (b[10] => z[18]) = 0; - (b[11] => z[18]) = 0; - (b[12] => z[18]) = 0; - (b[13] => z[18]) = 0; - (b[14] => z[18]) = 0; - (b[15] => z[18]) = 0; - (b[16] => z[18]) = 0; - (b[17] => z[18]) = 0; - (a[0] => z[19]) = 0; - (a[1] => z[19]) = 0; - (a[2] => z[19]) = 0; - (a[3] => z[19]) = 0; - (a[4] => z[19]) = 0; - (a[5] => z[19]) = 0; - (a[6] => z[19]) = 0; - (a[7] => z[19]) = 0; - (a[8] => z[19]) = 0; - (a[9] => z[19]) = 0; - (a[10] => z[19]) = 0; - (a[11] => z[19]) = 0; - (a[12] => z[19]) = 0; - (a[13] => z[19]) = 0; - (a[14] => z[19]) = 0; - (a[15] => z[19]) = 0; - (a[16] => z[19]) = 0; - (a[17] => z[19]) = 0; - (a[18] => z[19]) = 0; - (a[19] => z[19]) = 0; - (b[0] => z[19]) = 0; - (b[1] => z[19]) = 0; - (b[2] => z[19]) = 0; - (b[3] => z[19]) = 0; - (b[4] => z[19]) = 0; - (b[5] => z[19]) = 0; - (b[6] => z[19]) = 0; - (b[7] => z[19]) = 0; - (b[8] => z[19]) = 0; - (b[9] => z[19]) = 0; - (b[10] => z[19]) = 0; - (b[11] => z[19]) = 0; - (b[12] => z[19]) = 0; - (b[13] => z[19]) = 0; - (b[14] => z[19]) = 0; - (b[15] => z[19]) = 0; - (b[16] => z[19]) = 0; - (b[17] => z[19]) = 0; - (a[0] => z[20]) = 0; - (a[1] => z[20]) = 0; - (a[2] => z[20]) = 0; - (a[3] => z[20]) = 0; - (a[4] => z[20]) = 0; - (a[5] => z[20]) = 0; - (a[6] => z[20]) = 0; - (a[7] => z[20]) = 0; - (a[8] => z[20]) = 0; - (a[9] => z[20]) = 0; - (a[10] => z[20]) = 0; - (a[11] => z[20]) = 0; - (a[12] => z[20]) = 0; - (a[13] => z[20]) = 0; - (a[14] => z[20]) = 0; - (a[15] => z[20]) = 0; - (a[16] => z[20]) = 0; - (a[17] => z[20]) = 0; - (a[18] => z[20]) = 0; - (a[19] => z[20]) = 0; - (b[0] => z[20]) = 0; - (b[1] => z[20]) = 0; - (b[2] => z[20]) = 0; - (b[3] => z[20]) = 0; - (b[4] => z[20]) = 0; - (b[5] => z[20]) = 0; - (b[6] => z[20]) = 0; - (b[7] => z[20]) = 0; - (b[8] => z[20]) = 0; - (b[9] => z[20]) = 0; - (b[10] => z[20]) = 0; - (b[11] => z[20]) = 0; - (b[12] => z[20]) = 0; - (b[13] => z[20]) = 0; - (b[14] => z[20]) = 0; - (b[15] => z[20]) = 0; - (b[16] => z[20]) = 0; - (b[17] => z[20]) = 0; - (a[0] => z[21]) = 0; - (a[1] => z[21]) = 0; - (a[2] => z[21]) = 0; - (a[3] => z[21]) = 0; - (a[4] => z[21]) = 0; - (a[5] => z[21]) = 0; - (a[6] => z[21]) = 0; - (a[7] => z[21]) = 0; - (a[8] => z[21]) = 0; - (a[9] => z[21]) = 0; - (a[10] => z[21]) = 0; - (a[11] => z[21]) = 0; - (a[12] => z[21]) = 0; - (a[13] => z[21]) = 0; - (a[14] => z[21]) = 0; - (a[15] => z[21]) = 0; - (a[16] => z[21]) = 0; - (a[17] => z[21]) = 0; - (a[18] => z[21]) = 0; - (a[19] => z[21]) = 0; - (b[0] => z[21]) = 0; - (b[1] => z[21]) = 0; - (b[2] => z[21]) = 0; - (b[3] => z[21]) = 0; - (b[4] => z[21]) = 0; - (b[5] => z[21]) = 0; - (b[6] => z[21]) = 0; - (b[7] => z[21]) = 0; - (b[8] => z[21]) = 0; - (b[9] => z[21]) = 0; - (b[10] => z[21]) = 0; - (b[11] => z[21]) = 0; - (b[12] => z[21]) = 0; - (b[13] => z[21]) = 0; - (b[14] => z[21]) = 0; - (b[15] => z[21]) = 0; - (b[16] => z[21]) = 0; - (b[17] => z[21]) = 0; - (a[0] => z[22]) = 0; - (a[1] => z[22]) = 0; - (a[2] => z[22]) = 0; - (a[3] => z[22]) = 0; - (a[4] => z[22]) = 0; - (a[5] => z[22]) = 0; - (a[6] => z[22]) = 0; - (a[7] => z[22]) = 0; - (a[8] => z[22]) = 0; - (a[9] => z[22]) = 0; - (a[10] => z[22]) = 0; - (a[11] => z[22]) = 0; - (a[12] => z[22]) = 0; - (a[13] => z[22]) = 0; - (a[14] => z[22]) = 0; - (a[15] => z[22]) = 0; - (a[16] => z[22]) = 0; - (a[17] => z[22]) = 0; - (a[18] => z[22]) = 0; - (a[19] => z[22]) = 0; - (b[0] => z[22]) = 0; - (b[1] => z[22]) = 0; - (b[2] => z[22]) = 0; - (b[3] => z[22]) = 0; - (b[4] => z[22]) = 0; - (b[5] => z[22]) = 0; - (b[6] => z[22]) = 0; - (b[7] => z[22]) = 0; - (b[8] => z[22]) = 0; - (b[9] => z[22]) = 0; - (b[10] => z[22]) = 0; - (b[11] => z[22]) = 0; - (b[12] => z[22]) = 0; - (b[13] => z[22]) = 0; - (b[14] => z[22]) = 0; - (b[15] => z[22]) = 0; - (b[16] => z[22]) = 0; - (b[17] => z[22]) = 0; - (a[0] => z[23]) = 0; - (a[1] => z[23]) = 0; - (a[2] => z[23]) = 0; - (a[3] => z[23]) = 0; - (a[4] => z[23]) = 0; - (a[5] => z[23]) = 0; - (a[6] => z[23]) = 0; - (a[7] => z[23]) = 0; - (a[8] => z[23]) = 0; - (a[9] => z[23]) = 0; - (a[10] => z[23]) = 0; - (a[11] => z[23]) = 0; - (a[12] => z[23]) = 0; - (a[13] => z[23]) = 0; - (a[14] => z[23]) = 0; - (a[15] => z[23]) = 0; - (a[16] => z[23]) = 0; - (a[17] => z[23]) = 0; - (a[18] => z[23]) = 0; - (a[19] => z[23]) = 0; - (b[0] => z[23]) = 0; - (b[1] => z[23]) = 0; - (b[2] => z[23]) = 0; - (b[3] => z[23]) = 0; - (b[4] => z[23]) = 0; - (b[5] => z[23]) = 0; - (b[6] => z[23]) = 0; - (b[7] => z[23]) = 0; - (b[8] => z[23]) = 0; - (b[9] => z[23]) = 0; - (b[10] => z[23]) = 0; - (b[11] => z[23]) = 0; - (b[12] => z[23]) = 0; - (b[13] => z[23]) = 0; - (b[14] => z[23]) = 0; - (b[15] => z[23]) = 0; - (b[16] => z[23]) = 0; - (b[17] => z[23]) = 0; - (a[0] => z[24]) = 0; - (a[1] => z[24]) = 0; - (a[2] => z[24]) = 0; - (a[3] => z[24]) = 0; - (a[4] => z[24]) = 0; - (a[5] => z[24]) = 0; - (a[6] => z[24]) = 0; - (a[7] => z[24]) = 0; - (a[8] => z[24]) = 0; - (a[9] => z[24]) = 0; - (a[10] => z[24]) = 0; - (a[11] => z[24]) = 0; - (a[12] => z[24]) = 0; - (a[13] => z[24]) = 0; - (a[14] => z[24]) = 0; - (a[15] => z[24]) = 0; - (a[16] => z[24]) = 0; - (a[17] => z[24]) = 0; - (a[18] => z[24]) = 0; - (a[19] => z[24]) = 0; - (b[0] => z[24]) = 0; - (b[1] => z[24]) = 0; - (b[2] => z[24]) = 0; - (b[3] => z[24]) = 0; - (b[4] => z[24]) = 0; - (b[5] => z[24]) = 0; - (b[6] => z[24]) = 0; - (b[7] => z[24]) = 0; - (b[8] => z[24]) = 0; - (b[9] => z[24]) = 0; - (b[10] => z[24]) = 0; - (b[11] => z[24]) = 0; - (b[12] => z[24]) = 0; - (b[13] => z[24]) = 0; - (b[14] => z[24]) = 0; - (b[15] => z[24]) = 0; - (b[16] => z[24]) = 0; - (b[17] => z[24]) = 0; - (a[0] => z[25]) = 0; - (a[1] => z[25]) = 0; - (a[2] => z[25]) = 0; - (a[3] => z[25]) = 0; - (a[4] => z[25]) = 0; - (a[5] => z[25]) = 0; - (a[6] => z[25]) = 0; - (a[7] => z[25]) = 0; - (a[8] => z[25]) = 0; - (a[9] => z[25]) = 0; - (a[10] => z[25]) = 0; - (a[11] => z[25]) = 0; - (a[12] => z[25]) = 0; - (a[13] => z[25]) = 0; - (a[14] => z[25]) = 0; - (a[15] => z[25]) = 0; - (a[16] => z[25]) = 0; - (a[17] => z[25]) = 0; - (a[18] => z[25]) = 0; - (a[19] => z[25]) = 0; - (b[0] => z[25]) = 0; - (b[1] => z[25]) = 0; - (b[2] => z[25]) = 0; - (b[3] => z[25]) = 0; - (b[4] => z[25]) = 0; - (b[5] => z[25]) = 0; - (b[6] => z[25]) = 0; - (b[7] => z[25]) = 0; - (b[8] => z[25]) = 0; - (b[9] => z[25]) = 0; - (b[10] => z[25]) = 0; - (b[11] => z[25]) = 0; - (b[12] => z[25]) = 0; - (b[13] => z[25]) = 0; - (b[14] => z[25]) = 0; - (b[15] => z[25]) = 0; - (b[16] => z[25]) = 0; - (b[17] => z[25]) = 0; - (a[0] => z[26]) = 0; - (a[1] => z[26]) = 0; - (a[2] => z[26]) = 0; - (a[3] => z[26]) = 0; - (a[4] => z[26]) = 0; - (a[5] => z[26]) = 0; - (a[6] => z[26]) = 0; - (a[7] => z[26]) = 0; - (a[8] => z[26]) = 0; - (a[9] => z[26]) = 0; - (a[10] => z[26]) = 0; - (a[11] => z[26]) = 0; - (a[12] => z[26]) = 0; - (a[13] => z[26]) = 0; - (a[14] => z[26]) = 0; - (a[15] => z[26]) = 0; - (a[16] => z[26]) = 0; - (a[17] => z[26]) = 0; - (a[18] => z[26]) = 0; - (a[19] => z[26]) = 0; - (b[0] => z[26]) = 0; - (b[1] => z[26]) = 0; - (b[2] => z[26]) = 0; - (b[3] => z[26]) = 0; - (b[4] => z[26]) = 0; - (b[5] => z[26]) = 0; - (b[6] => z[26]) = 0; - (b[7] => z[26]) = 0; - (b[8] => z[26]) = 0; - (b[9] => z[26]) = 0; - (b[10] => z[26]) = 0; - (b[11] => z[26]) = 0; - (b[12] => z[26]) = 0; - (b[13] => z[26]) = 0; - (b[14] => z[26]) = 0; - (b[15] => z[26]) = 0; - (b[16] => z[26]) = 0; - (b[17] => z[26]) = 0; - (a[0] => z[27]) = 0; - (a[1] => z[27]) = 0; - (a[2] => z[27]) = 0; - (a[3] => z[27]) = 0; - (a[4] => z[27]) = 0; - (a[5] => z[27]) = 0; - (a[6] => z[27]) = 0; - (a[7] => z[27]) = 0; - (a[8] => z[27]) = 0; - (a[9] => z[27]) = 0; - (a[10] => z[27]) = 0; - (a[11] => z[27]) = 0; - (a[12] => z[27]) = 0; - (a[13] => z[27]) = 0; - (a[14] => z[27]) = 0; - (a[15] => z[27]) = 0; - (a[16] => z[27]) = 0; - (a[17] => z[27]) = 0; - (a[18] => z[27]) = 0; - (a[19] => z[27]) = 0; - (b[0] => z[27]) = 0; - (b[1] => z[27]) = 0; - (b[2] => z[27]) = 0; - (b[3] => z[27]) = 0; - (b[4] => z[27]) = 0; - (b[5] => z[27]) = 0; - (b[6] => z[27]) = 0; - (b[7] => z[27]) = 0; - (b[8] => z[27]) = 0; - (b[9] => z[27]) = 0; - (b[10] => z[27]) = 0; - (b[11] => z[27]) = 0; - (b[12] => z[27]) = 0; - (b[13] => z[27]) = 0; - (b[14] => z[27]) = 0; - (b[15] => z[27]) = 0; - (b[16] => z[27]) = 0; - (b[17] => z[27]) = 0; - (a[0] => z[28]) = 0; - (a[1] => z[28]) = 0; - (a[2] => z[28]) = 0; - (a[3] => z[28]) = 0; - (a[4] => z[28]) = 0; - (a[5] => z[28]) = 0; - (a[6] => z[28]) = 0; - (a[7] => z[28]) = 0; - (a[8] => z[28]) = 0; - (a[9] => z[28]) = 0; - (a[10] => z[28]) = 0; - (a[11] => z[28]) = 0; - (a[12] => z[28]) = 0; - (a[13] => z[28]) = 0; - (a[14] => z[28]) = 0; - (a[15] => z[28]) = 0; - (a[16] => z[28]) = 0; - (a[17] => z[28]) = 0; - (a[18] => z[28]) = 0; - (a[19] => z[28]) = 0; - (b[0] => z[28]) = 0; - (b[1] => z[28]) = 0; - (b[2] => z[28]) = 0; - (b[3] => z[28]) = 0; - (b[4] => z[28]) = 0; - (b[5] => z[28]) = 0; - (b[6] => z[28]) = 0; - (b[7] => z[28]) = 0; - (b[8] => z[28]) = 0; - (b[9] => z[28]) = 0; - (b[10] => z[28]) = 0; - (b[11] => z[28]) = 0; - (b[12] => z[28]) = 0; - (b[13] => z[28]) = 0; - (b[14] => z[28]) = 0; - (b[15] => z[28]) = 0; - (b[16] => z[28]) = 0; - (b[17] => z[28]) = 0; - (a[0] => z[29]) = 0; - (a[1] => z[29]) = 0; - (a[2] => z[29]) = 0; - (a[3] => z[29]) = 0; - (a[4] => z[29]) = 0; - (a[5] => z[29]) = 0; - (a[6] => z[29]) = 0; - (a[7] => z[29]) = 0; - (a[8] => z[29]) = 0; - (a[9] => z[29]) = 0; - (a[10] => z[29]) = 0; - (a[11] => z[29]) = 0; - (a[12] => z[29]) = 0; - (a[13] => z[29]) = 0; - (a[14] => z[29]) = 0; - (a[15] => z[29]) = 0; - (a[16] => z[29]) = 0; - (a[17] => z[29]) = 0; - (a[18] => z[29]) = 0; - (a[19] => z[29]) = 0; - (b[0] => z[29]) = 0; - (b[1] => z[29]) = 0; - (b[2] => z[29]) = 0; - (b[3] => z[29]) = 0; - (b[4] => z[29]) = 0; - (b[5] => z[29]) = 0; - (b[6] => z[29]) = 0; - (b[7] => z[29]) = 0; - (b[8] => z[29]) = 0; - (b[9] => z[29]) = 0; - (b[10] => z[29]) = 0; - (b[11] => z[29]) = 0; - (b[12] => z[29]) = 0; - (b[13] => z[29]) = 0; - (b[14] => z[29]) = 0; - (b[15] => z[29]) = 0; - (b[16] => z[29]) = 0; - (b[17] => z[29]) = 0; - (a[0] => z[30]) = 0; - (a[1] => z[30]) = 0; - (a[2] => z[30]) = 0; - (a[3] => z[30]) = 0; - (a[4] => z[30]) = 0; - (a[5] => z[30]) = 0; - (a[6] => z[30]) = 0; - (a[7] => z[30]) = 0; - (a[8] => z[30]) = 0; - (a[9] => z[30]) = 0; - (a[10] => z[30]) = 0; - (a[11] => z[30]) = 0; - (a[12] => z[30]) = 0; - (a[13] => z[30]) = 0; - (a[14] => z[30]) = 0; - (a[15] => z[30]) = 0; - (a[16] => z[30]) = 0; - (a[17] => z[30]) = 0; - (a[18] => z[30]) = 0; - (a[19] => z[30]) = 0; - (b[0] => z[30]) = 0; - (b[1] => z[30]) = 0; - (b[2] => z[30]) = 0; - (b[3] => z[30]) = 0; - (b[4] => z[30]) = 0; - (b[5] => z[30]) = 0; - (b[6] => z[30]) = 0; - (b[7] => z[30]) = 0; - (b[8] => z[30]) = 0; - (b[9] => z[30]) = 0; - (b[10] => z[30]) = 0; - (b[11] => z[30]) = 0; - (b[12] => z[30]) = 0; - (b[13] => z[30]) = 0; - (b[14] => z[30]) = 0; - (b[15] => z[30]) = 0; - (b[16] => z[30]) = 0; - (b[17] => z[30]) = 0; - (a[0] => z[31]) = 0; - (a[1] => z[31]) = 0; - (a[2] => z[31]) = 0; - (a[3] => z[31]) = 0; - (a[4] => z[31]) = 0; - (a[5] => z[31]) = 0; - (a[6] => z[31]) = 0; - (a[7] => z[31]) = 0; - (a[8] => z[31]) = 0; - (a[9] => z[31]) = 0; - (a[10] => z[31]) = 0; - (a[11] => z[31]) = 0; - (a[12] => z[31]) = 0; - (a[13] => z[31]) = 0; - (a[14] => z[31]) = 0; - (a[15] => z[31]) = 0; - (a[16] => z[31]) = 0; - (a[17] => z[31]) = 0; - (a[18] => z[31]) = 0; - (a[19] => z[31]) = 0; - (b[0] => z[31]) = 0; - (b[1] => z[31]) = 0; - (b[2] => z[31]) = 0; - (b[3] => z[31]) = 0; - (b[4] => z[31]) = 0; - (b[5] => z[31]) = 0; - (b[6] => z[31]) = 0; - (b[7] => z[31]) = 0; - (b[8] => z[31]) = 0; - (b[9] => z[31]) = 0; - (b[10] => z[31]) = 0; - (b[11] => z[31]) = 0; - (b[12] => z[31]) = 0; - (b[13] => z[31]) = 0; - (b[14] => z[31]) = 0; - (b[15] => z[31]) = 0; - (b[16] => z[31]) = 0; - (b[17] => z[31]) = 0; - (a[0] => z[32]) = 0; - (a[1] => z[32]) = 0; - (a[2] => z[32]) = 0; - (a[3] => z[32]) = 0; - (a[4] => z[32]) = 0; - (a[5] => z[32]) = 0; - (a[6] => z[32]) = 0; - (a[7] => z[32]) = 0; - (a[8] => z[32]) = 0; - (a[9] => z[32]) = 0; - (a[10] => z[32]) = 0; - (a[11] => z[32]) = 0; - (a[12] => z[32]) = 0; - (a[13] => z[32]) = 0; - (a[14] => z[32]) = 0; - (a[15] => z[32]) = 0; - (a[16] => z[32]) = 0; - (a[17] => z[32]) = 0; - (a[18] => z[32]) = 0; - (a[19] => z[32]) = 0; - (b[0] => z[32]) = 0; - (b[1] => z[32]) = 0; - (b[2] => z[32]) = 0; - (b[3] => z[32]) = 0; - (b[4] => z[32]) = 0; - (b[5] => z[32]) = 0; - (b[6] => z[32]) = 0; - (b[7] => z[32]) = 0; - (b[8] => z[32]) = 0; - (b[9] => z[32]) = 0; - (b[10] => z[32]) = 0; - (b[11] => z[32]) = 0; - (b[12] => z[32]) = 0; - (b[13] => z[32]) = 0; - (b[14] => z[32]) = 0; - (b[15] => z[32]) = 0; - (b[16] => z[32]) = 0; - (b[17] => z[32]) = 0; - (a[0] => z[33]) = 0; - (a[1] => z[33]) = 0; - (a[2] => z[33]) = 0; - (a[3] => z[33]) = 0; - (a[4] => z[33]) = 0; - (a[5] => z[33]) = 0; - (a[6] => z[33]) = 0; - (a[7] => z[33]) = 0; - (a[8] => z[33]) = 0; - (a[9] => z[33]) = 0; - (a[10] => z[33]) = 0; - (a[11] => z[33]) = 0; - (a[12] => z[33]) = 0; - (a[13] => z[33]) = 0; - (a[14] => z[33]) = 0; - (a[15] => z[33]) = 0; - (a[16] => z[33]) = 0; - (a[17] => z[33]) = 0; - (a[18] => z[33]) = 0; - (a[19] => z[33]) = 0; - (b[0] => z[33]) = 0; - (b[1] => z[33]) = 0; - (b[2] => z[33]) = 0; - (b[3] => z[33]) = 0; - (b[4] => z[33]) = 0; - (b[5] => z[33]) = 0; - (b[6] => z[33]) = 0; - (b[7] => z[33]) = 0; - (b[8] => z[33]) = 0; - (b[9] => z[33]) = 0; - (b[10] => z[33]) = 0; - (b[11] => z[33]) = 0; - (b[12] => z[33]) = 0; - (b[13] => z[33]) = 0; - (b[14] => z[33]) = 0; - (b[15] => z[33]) = 0; - (b[16] => z[33]) = 0; - (b[17] => z[33]) = 0; - (a[0] => z[34]) = 0; - (a[1] => z[34]) = 0; - (a[2] => z[34]) = 0; - (a[3] => z[34]) = 0; - (a[4] => z[34]) = 0; - (a[5] => z[34]) = 0; - (a[6] => z[34]) = 0; - (a[7] => z[34]) = 0; - (a[8] => z[34]) = 0; - (a[9] => z[34]) = 0; - (a[10] => z[34]) = 0; - (a[11] => z[34]) = 0; - (a[12] => z[34]) = 0; - (a[13] => z[34]) = 0; - (a[14] => z[34]) = 0; - (a[15] => z[34]) = 0; - (a[16] => z[34]) = 0; - (a[17] => z[34]) = 0; - (a[18] => z[34]) = 0; - (a[19] => z[34]) = 0; - (b[0] => z[34]) = 0; - (b[1] => z[34]) = 0; - (b[2] => z[34]) = 0; - (b[3] => z[34]) = 0; - (b[4] => z[34]) = 0; - (b[5] => z[34]) = 0; - (b[6] => z[34]) = 0; - (b[7] => z[34]) = 0; - (b[8] => z[34]) = 0; - (b[9] => z[34]) = 0; - (b[10] => z[34]) = 0; - (b[11] => z[34]) = 0; - (b[12] => z[34]) = 0; - (b[13] => z[34]) = 0; - (b[14] => z[34]) = 0; - (b[15] => z[34]) = 0; - (b[16] => z[34]) = 0; - (b[17] => z[34]) = 0; - (a[0] => z[35]) = 0; - (a[1] => z[35]) = 0; - (a[2] => z[35]) = 0; - (a[3] => z[35]) = 0; - (a[4] => z[35]) = 0; - (a[5] => z[35]) = 0; - (a[6] => z[35]) = 0; - (a[7] => z[35]) = 0; - (a[8] => z[35]) = 0; - (a[9] => z[35]) = 0; - (a[10] => z[35]) = 0; - (a[11] => z[35]) = 0; - (a[12] => z[35]) = 0; - (a[13] => z[35]) = 0; - (a[14] => z[35]) = 0; - (a[15] => z[35]) = 0; - (a[16] => z[35]) = 0; - (a[17] => z[35]) = 0; - (a[18] => z[35]) = 0; - (a[19] => z[35]) = 0; - (b[0] => z[35]) = 0; - (b[1] => z[35]) = 0; - (b[2] => z[35]) = 0; - (b[3] => z[35]) = 0; - (b[4] => z[35]) = 0; - (b[5] => z[35]) = 0; - (b[6] => z[35]) = 0; - (b[7] => z[35]) = 0; - (b[8] => z[35]) = 0; - (b[9] => z[35]) = 0; - (b[10] => z[35]) = 0; - (b[11] => z[35]) = 0; - (b[12] => z[35]) = 0; - (b[13] => z[35]) = 0; - (b[14] => z[35]) = 0; - (b[15] => z[35]) = 0; - (b[16] => z[35]) = 0; - (b[17] => z[35]) = 0; - (a[0] => z[36]) = 0; - (a[1] => z[36]) = 0; - (a[2] => z[36]) = 0; - (a[3] => z[36]) = 0; - (a[4] => z[36]) = 0; - (a[5] => z[36]) = 0; - (a[6] => z[36]) = 0; - (a[7] => z[36]) = 0; - (a[8] => z[36]) = 0; - (a[9] => z[36]) = 0; - (a[10] => z[36]) = 0; - (a[11] => z[36]) = 0; - (a[12] => z[36]) = 0; - (a[13] => z[36]) = 0; - (a[14] => z[36]) = 0; - (a[15] => z[36]) = 0; - (a[16] => z[36]) = 0; - (a[17] => z[36]) = 0; - (a[18] => z[36]) = 0; - (a[19] => z[36]) = 0; - (b[0] => z[36]) = 0; - (b[1] => z[36]) = 0; - (b[2] => z[36]) = 0; - (b[3] => z[36]) = 0; - (b[4] => z[36]) = 0; - (b[5] => z[36]) = 0; - (b[6] => z[36]) = 0; - (b[7] => z[36]) = 0; - (b[8] => z[36]) = 0; - (b[9] => z[36]) = 0; - (b[10] => z[36]) = 0; - (b[11] => z[36]) = 0; - (b[12] => z[36]) = 0; - (b[13] => z[36]) = 0; - (b[14] => z[36]) = 0; - (b[15] => z[36]) = 0; - (b[16] => z[36]) = 0; - (b[17] => z[36]) = 0; - (a[0] => z[37]) = 0; - (a[1] => z[37]) = 0; - (a[2] => z[37]) = 0; - (a[3] => z[37]) = 0; - (a[4] => z[37]) = 0; - (a[5] => z[37]) = 0; - (a[6] => z[37]) = 0; - (a[7] => z[37]) = 0; - (a[8] => z[37]) = 0; - (a[9] => z[37]) = 0; - (a[10] => z[37]) = 0; - (a[11] => z[37]) = 0; - (a[12] => z[37]) = 0; - (a[13] => z[37]) = 0; - (a[14] => z[37]) = 0; - (a[15] => z[37]) = 0; - (a[16] => z[37]) = 0; - (a[17] => z[37]) = 0; - (a[18] => z[37]) = 0; - (a[19] => z[37]) = 0; - (b[0] => z[37]) = 0; - (b[1] => z[37]) = 0; - (b[2] => z[37]) = 0; - (b[3] => z[37]) = 0; - (b[4] => z[37]) = 0; - (b[5] => z[37]) = 0; - (b[6] => z[37]) = 0; - (b[7] => z[37]) = 0; - (b[8] => z[37]) = 0; - (b[9] => z[37]) = 0; - (b[10] => z[37]) = 0; - (b[11] => z[37]) = 0; - (b[12] => z[37]) = 0; - (b[13] => z[37]) = 0; - (b[14] => z[37]) = 0; - (b[15] => z[37]) = 0; - (b[16] => z[37]) = 0; - (b[17] => z[37]) = 0; - endspecify -`endif + .load_acc_i(load_acc), + .rst_acc_i(acc_reset), + .z_o(dsp_full_z), + // cascade ports (connect to dedicated cascade routing) + .a_cin_i(a_cin), + .b_cin_i(b_cin), + .z_cin_i(z_cin), + .z_cout_o(dsp_full_z_cout), + .a_cout_o(dsp_full_a_cout), + .b_cout_o(dsp_full_b_cout), + // configuration ports (tie-offs) + .coeff_i(COEFF_0), + .acc_fir_i(ACC_FIR), + .round_i(ROUND), + .zc_shift_i(ZC_SHIFT), + .zreg_shift_i(ZREG_SHIFT), + .shift_right_i(SHIFT_REG), + .saturate_enable_i(SATURATE), + .subtract_i(SUBTRACT), + .pre_add_sel_i(PRE_ADD), + .a_sel_i(A_SEL), + .a_reg_i(A_REG), + .b_sel_i(B_SEL), + .b_reg_i(B_REG), + .c_reg_i(C_REG), + .bc_reg_i(BC_REG), + .m_reg_i(M_REG) + ); 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, - input wire reset, +module QL_DSPV2_MULT ( + input wire [31:0] a, + input wire [17:0] b, + output wire [49:0] z, - 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 register_inputs + input wire [2:0] feedback, + input wire [2:0] output_select ); - parameter [79:0] MODE_BITS = 80'd0; + parameter [67:0] MODE_BITS = 68'h00000000000000000; - 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), - .acc_fir(6'b0), - .z(z), - .dly_b(), - - .f_mode(f_mode), + localparam [31:0] COEFF_0 = MODE_BITS[31:0]; + localparam [5:0] ACC_FIR = MODE_BITS[37:32]; + localparam [2:0] ROUND = MODE_BITS[40:38]; + localparam [4:0] ZC_SHIFT = MODE_BITS[45:41]; + localparam [4:0] ZREG_SHIFT= MODE_BITS[50:46]; + localparam [5:0] SHIFT_REG = MODE_BITS[56:51]; + localparam SATURATE = MODE_BITS[57]; + localparam SUBTRACT = MODE_BITS[58]; + localparam PRE_ADD = MODE_BITS[59]; + localparam A_SEL = MODE_BITS[60]; + localparam A_REG = MODE_BITS[61]; + localparam B_SEL = MODE_BITS[62]; + localparam B_REG = MODE_BITS[63]; + localparam C_REG = MODE_BITS[64]; + localparam BC_REG = MODE_BITS[65]; + localparam M_REG = MODE_BITS[66]; + localparam FRAC_MODE = MODE_BITS[67]; + QL_DSPV2 #( + .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .c(18'h0), + .load_acc(1'b0), .feedback(feedback), - .load_acc(1'b0), + .output_select(output_select), + .z(z), + + .clk(), + .reset(), + .acc_reset(1'b0), - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), + .a_cin(), + .b_cin(), + .z_cin(), + .z_cout(), + .a_cout(), + .b_cout() + ); + +endmodule + +module QL_DSPV2_MULT_REGIN ( + input wire [31:0] a, + input wire [17:0] b, + output wire [49:0] z, + + (* clkbuf_sink *) + input wire clk, + input wire reset, + + input wire [2:0] feedback, + input wire [2:0] output_select +); + + parameter [67:0] MODE_BITS = 68'h0A000000000000000; + + localparam [31:0] COEFF_0 = MODE_BITS[31:0]; + localparam [5:0] ACC_FIR = MODE_BITS[37:32]; + localparam [2:0] ROUND = MODE_BITS[40:38]; + localparam [4:0] ZC_SHIFT = MODE_BITS[45:41]; + localparam [4:0] ZREG_SHIFT= MODE_BITS[50:46]; + localparam [5:0] SHIFT_REG = MODE_BITS[56:51]; + localparam SATURATE = MODE_BITS[57]; + localparam SUBTRACT = MODE_BITS[58]; + localparam PRE_ADD = MODE_BITS[59]; + localparam A_SEL = MODE_BITS[60]; + localparam A_REG = MODE_BITS[61]; + localparam B_SEL = MODE_BITS[62]; + localparam B_REG = MODE_BITS[63]; + localparam C_REG = MODE_BITS[64]; + localparam BC_REG = MODE_BITS[65]; + localparam M_REG = MODE_BITS[66]; + localparam FRAC_MODE = MODE_BITS[67]; + + QL_DSPV2 #( + .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .c(18'h0), + .load_acc(1'b0), + .feedback(feedback), + .output_select(output_select), + .z(z), + .clk(clk), - .reset(reset), + .reset(reset), + .acc_reset(1'b0), - .output_select(output_select), // unregistered output: a * b (0) - .saturate_enable(1'b0), - .shift_right(6'b0), - .round(1'b0), - .subtract(1'b0), - .register_inputs(register_inputs) // registered inputs - ); - -`ifdef SDF_SIM - specify - (posedge clk => (z +: a)) = 0; - (posedge clk => (z +: b)) = 0; - $setuphold(posedge clk, a, 0, 0); - $setuphold(posedge clk, b, 0, 0); - $setuphold(posedge clk, feedback, 0, 0); - endspecify -`endif + .a_cin(), + .b_cin(), + .z_cin(), + .z_cout(), + .a_cout(), + .b_cout() + ); + 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, +module QL_DSPV2_MULT_REGOUT ( + input wire [31:0] a, + input wire [17:0] b, + output wire [49:0] z, - (* clkbuf_sink *) - input wire clk, - input wire reset, + (* clkbuf_sink *) + input wire clk, + input wire reset, - 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 register_inputs + input wire [2:0] feedback, + input wire [2:0] output_select ); - parameter [79:0] MODE_BITS = 80'd0; + parameter [67:0] MODE_BITS = 68'h00000000000000000; - 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), - .acc_fir(6'b0), - .z(z), - .dly_b(), - - .f_mode(f_mode), + localparam [31:0] COEFF_0 = MODE_BITS[31:0]; + localparam [5:0] ACC_FIR = MODE_BITS[37:32]; + localparam [2:0] ROUND = MODE_BITS[40:38]; + localparam [4:0] ZC_SHIFT = MODE_BITS[45:41]; + localparam [4:0] ZREG_SHIFT= MODE_BITS[50:46]; + localparam [5:0] SHIFT_REG = MODE_BITS[56:51]; + localparam SATURATE = MODE_BITS[57]; + localparam SUBTRACT = MODE_BITS[58]; + localparam PRE_ADD = MODE_BITS[59]; + localparam A_SEL = MODE_BITS[60]; + localparam A_REG = MODE_BITS[61]; + localparam B_SEL = MODE_BITS[62]; + localparam B_REG = MODE_BITS[63]; + localparam C_REG = MODE_BITS[64]; + localparam BC_REG = MODE_BITS[65]; + localparam M_REG = MODE_BITS[66]; + localparam FRAC_MODE = MODE_BITS[67]; + QL_DSPV2 #( + .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .c(18'h0), + .load_acc(1'b0), .feedback(feedback), - .load_acc(1'b0), - - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), - + .output_select(output_select), + .z(z), + .clk(clk), - .reset(reset), + .reset(reset), + .acc_reset(1'b0), - .output_select(output_select), // registered output: a * b (4) - .saturate_enable(1'b0), - .shift_right(6'b0), - .round(1'b0), - .subtract(1'b0), - .register_inputs(register_inputs) // unregistered inputs - ); - -`ifdef SDF_SIM - specify - (posedge clk => (z +: a)) = 0; - (posedge clk => (z +: b)) = 0; - $setuphold(posedge clk, a, 0, 0); - $setuphold(posedge clk, b, 0, 0); - $setuphold(posedge clk, feedback, 0, 0); - endspecify -`endif + .a_cin(), + .b_cin(), + .z_cin(), + .z_cout(), + .a_cout(), + .b_cout() + ); + 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, +module QL_DSPV2_MULT_REGIN_REGOUT ( // TODO: Name subject to change + input wire [31:0] a, + input wire [17:0] b, + output wire [49:0] z, - (* clkbuf_sink *) - input wire clk, - input wire reset, + (* clkbuf_sink *) + input wire clk, + input wire reset, - 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 register_inputs + input wire [2:0] feedback, + input wire [2:0] output_select ); - parameter [79:0] MODE_BITS = 80'd0; + parameter [67:0] MODE_BITS = 68'h0A000000000000000; - 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), - .acc_fir(6'b0), - .z(z), - .dly_b(), - - .f_mode(f_mode), + localparam [31:0] COEFF_0 = MODE_BITS[31:0]; + localparam [5:0] ACC_FIR = MODE_BITS[37:32]; + localparam [2:0] ROUND = MODE_BITS[40:38]; + localparam [4:0] ZC_SHIFT = MODE_BITS[45:41]; + localparam [4:0] ZREG_SHIFT= MODE_BITS[50:46]; + localparam [5:0] SHIFT_REG = MODE_BITS[56:51]; + localparam SATURATE = MODE_BITS[57]; + localparam SUBTRACT = MODE_BITS[58]; + localparam PRE_ADD = MODE_BITS[59]; + localparam A_SEL = MODE_BITS[60]; + localparam A_REG = MODE_BITS[61]; + localparam B_SEL = MODE_BITS[62]; + localparam B_REG = MODE_BITS[63]; + localparam C_REG = MODE_BITS[64]; + localparam BC_REG = MODE_BITS[65]; + localparam M_REG = MODE_BITS[66]; + localparam FRAC_MODE = MODE_BITS[67]; + QL_DSPV2 #( + .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .c(18'h0), + .load_acc(1'b0), .feedback(feedback), - .load_acc(1'b0), - - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), - + .output_select(output_select), + .z(z), + .clk(clk), - .reset(reset), + .reset(reset), + .acc_reset(1'b0), - .output_select(output_select), // registered output: a * b (4) - .saturate_enable(1'b0), - .shift_right(6'b0), - .round(1'b0), - .subtract(1'b0), - .register_inputs(register_inputs) // registered inputs - ); + .a_cin(), + .b_cin(), + .z_cin(), -`ifdef SDF_SIM - specify - (posedge clk => (z +: a)) = 0; - (posedge clk => (z +: b)) = 0; - $setuphold(posedge clk, a, 0, 0); - $setuphold(posedge clk, b, 0, 0); - $setuphold(posedge clk, feedback, 0, 0); - endspecify -`endif + .z_cout(), + .a_cout(), + .b_cout() + ); + +endmodule + +module QL_DSPV2_MULTADD ( + input wire [31:0] a, + input wire [17:0] b, + output wire [49:0] z, + + input wire [ 2:0] feedback, + input wire [ 2:0] output_select +); + + parameter [67:0] MODE_BITS = 68'h00000000000000000; + + localparam [31:0] COEFF_0 = MODE_BITS[31:0]; + localparam [5:0] ACC_FIR = MODE_BITS[37:32]; + localparam [2:0] ROUND = MODE_BITS[40:38]; + localparam [4:0] ZC_SHIFT = MODE_BITS[45:41]; + localparam [4:0] ZREG_SHIFT= MODE_BITS[50:46]; + localparam [5:0] SHIFT_REG = MODE_BITS[56:51]; + localparam SATURATE = MODE_BITS[57]; + localparam SUBTRACT = MODE_BITS[58]; + localparam PRE_ADD = MODE_BITS[59]; + localparam A_SEL = MODE_BITS[60]; + localparam A_REG = MODE_BITS[61]; + localparam B_SEL = MODE_BITS[62]; + localparam B_REG = MODE_BITS[63]; + localparam C_REG = MODE_BITS[64]; + localparam BC_REG = MODE_BITS[65]; + localparam M_REG = MODE_BITS[66]; + localparam FRAC_MODE = MODE_BITS[67]; + + QL_DSPV2 #( + .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .c(18'h0), + .load_acc(1'b0), + .feedback(feedback), + .output_select(output_select), + .z(z), + + .clk(), + .reset(), + .acc_reset(1'b0), + + .a_cin(), + .b_cin(), + .z_cin(), + + .z_cout(), + .a_cout(), + .b_cout() + ); endmodule -module QL_DSP2_MULTADD ( - input wire [19:0] a, - input wire [17:0] b, - output wire [37:0] z, +module QL_DSPV2_MULTADD_REGIN ( + input wire [31:0] a, + input wire [17:0] b, + output wire [49:0] z, - input wire reset, + (* 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 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 + input wire [ 2:0] feedback, + input wire [ 2:0] output_select ); - parameter [79:0] MODE_BITS = 80'd0; + parameter [67:0] MODE_BITS = 68'h0A000000000000000; - 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), - .dly_b(), - .z(z), - - .f_mode(f_mode), + localparam [31:0] COEFF_0 = MODE_BITS[31:0]; + localparam [5:0] ACC_FIR = MODE_BITS[37:32]; + localparam [2:0] ROUND = MODE_BITS[40:38]; + localparam [4:0] ZC_SHIFT = MODE_BITS[45:41]; + localparam [4:0] ZREG_SHIFT= MODE_BITS[50:46]; + localparam [5:0] SHIFT_REG = MODE_BITS[56:51]; + localparam SATURATE = MODE_BITS[57]; + localparam SUBTRACT = MODE_BITS[58]; + localparam PRE_ADD = MODE_BITS[59]; + localparam A_SEL = MODE_BITS[60]; + localparam A_REG = MODE_BITS[61]; + localparam B_SEL = MODE_BITS[62]; + localparam B_REG = MODE_BITS[63]; + localparam C_REG = MODE_BITS[64]; + localparam BC_REG = MODE_BITS[65]; + localparam M_REG = MODE_BITS[66]; + localparam FRAC_MODE = MODE_BITS[67]; + QL_DSPV2 #( + .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .c(18'h0), + .load_acc(1'b0), .feedback(feedback), - .acc_fir(acc_fir), - .load_acc(load_acc), - - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), - - //.clk(1'b0), - .reset(reset), - - .output_select(output_select), // unregistered output: ACCin (2, 3) - .saturate_enable(saturate_enable), - .shift_right(shift_right), - .round(round), - .subtract(subtract), - .register_inputs(register_inputs) // unregistered inputs - ); - -`ifdef SDF_SIM - specify - (a[0] => z[0]) = 0; - (a[1] => z[0]) = 0; - (a[2] => z[0]) = 0; - (a[3] => z[0]) = 0; - (a[4] => z[0]) = 0; - (a[5] => z[0]) = 0; - (a[6] => z[0]) = 0; - (a[7] => z[0]) = 0; - (a[8] => z[0]) = 0; - (a[9] => z[0]) = 0; - (a[10] => z[0]) = 0; - (a[11] => z[0]) = 0; - (a[12] => z[0]) = 0; - (a[13] => z[0]) = 0; - (a[14] => z[0]) = 0; - (a[15] => z[0]) = 0; - (a[16] => z[0]) = 0; - (a[17] => z[0]) = 0; - (a[18] => z[0]) = 0; - (a[19] => z[0]) = 0; - (b[0] => z[0]) = 0; - (b[1] => z[0]) = 0; - (b[2] => z[0]) = 0; - (b[3] => z[0]) = 0; - (b[4] => z[0]) = 0; - (b[5] => z[0]) = 0; - (b[6] => z[0]) = 0; - (b[7] => z[0]) = 0; - (b[8] => z[0]) = 0; - (b[9] => z[0]) = 0; - (b[10] => z[0]) = 0; - (b[11] => z[0]) = 0; - (b[12] => z[0]) = 0; - (b[13] => z[0]) = 0; - (b[14] => z[0]) = 0; - (b[15] => z[0]) = 0; - (b[16] => z[0]) = 0; - (b[17] => z[0]) = 0; - (a[0] => z[1]) = 0; - (a[1] => z[1]) = 0; - (a[2] => z[1]) = 0; - (a[3] => z[1]) = 0; - (a[4] => z[1]) = 0; - (a[5] => z[1]) = 0; - (a[6] => z[1]) = 0; - (a[7] => z[1]) = 0; - (a[8] => z[1]) = 0; - (a[9] => z[1]) = 0; - (a[10] => z[1]) = 0; - (a[11] => z[1]) = 0; - (a[12] => z[1]) = 0; - (a[13] => z[1]) = 0; - (a[14] => z[1]) = 0; - (a[15] => z[1]) = 0; - (a[16] => z[1]) = 0; - (a[17] => z[1]) = 0; - (a[18] => z[1]) = 0; - (a[19] => z[1]) = 0; - (b[0] => z[1]) = 0; - (b[1] => z[1]) = 0; - (b[2] => z[1]) = 0; - (b[3] => z[1]) = 0; - (b[4] => z[1]) = 0; - (b[5] => z[1]) = 0; - (b[6] => z[1]) = 0; - (b[7] => z[1]) = 0; - (b[8] => z[1]) = 0; - (b[9] => z[1]) = 0; - (b[10] => z[1]) = 0; - (b[11] => z[1]) = 0; - (b[12] => z[1]) = 0; - (b[13] => z[1]) = 0; - (b[14] => z[1]) = 0; - (b[15] => z[1]) = 0; - (b[16] => z[1]) = 0; - (b[17] => z[1]) = 0; - (a[0] => z[2]) = 0; - (a[1] => z[2]) = 0; - (a[2] => z[2]) = 0; - (a[3] => z[2]) = 0; - (a[4] => z[2]) = 0; - (a[5] => z[2]) = 0; - (a[6] => z[2]) = 0; - (a[7] => z[2]) = 0; - (a[8] => z[2]) = 0; - (a[9] => z[2]) = 0; - (a[10] => z[2]) = 0; - (a[11] => z[2]) = 0; - (a[12] => z[2]) = 0; - (a[13] => z[2]) = 0; - (a[14] => z[2]) = 0; - (a[15] => z[2]) = 0; - (a[16] => z[2]) = 0; - (a[17] => z[2]) = 0; - (a[18] => z[2]) = 0; - (a[19] => z[2]) = 0; - (b[0] => z[2]) = 0; - (b[1] => z[2]) = 0; - (b[2] => z[2]) = 0; - (b[3] => z[2]) = 0; - (b[4] => z[2]) = 0; - (b[5] => z[2]) = 0; - (b[6] => z[2]) = 0; - (b[7] => z[2]) = 0; - (b[8] => z[2]) = 0; - (b[9] => z[2]) = 0; - (b[10] => z[2]) = 0; - (b[11] => z[2]) = 0; - (b[12] => z[2]) = 0; - (b[13] => z[2]) = 0; - (b[14] => z[2]) = 0; - (b[15] => z[2]) = 0; - (b[16] => z[2]) = 0; - (b[17] => z[2]) = 0; - (a[0] => z[3]) = 0; - (a[1] => z[3]) = 0; - (a[2] => z[3]) = 0; - (a[3] => z[3]) = 0; - (a[4] => z[3]) = 0; - (a[5] => z[3]) = 0; - (a[6] => z[3]) = 0; - (a[7] => z[3]) = 0; - (a[8] => z[3]) = 0; - (a[9] => z[3]) = 0; - (a[10] => z[3]) = 0; - (a[11] => z[3]) = 0; - (a[12] => z[3]) = 0; - (a[13] => z[3]) = 0; - (a[14] => z[3]) = 0; - (a[15] => z[3]) = 0; - (a[16] => z[3]) = 0; - (a[17] => z[3]) = 0; - (a[18] => z[3]) = 0; - (a[19] => z[3]) = 0; - (b[0] => z[3]) = 0; - (b[1] => z[3]) = 0; - (b[2] => z[3]) = 0; - (b[3] => z[3]) = 0; - (b[4] => z[3]) = 0; - (b[5] => z[3]) = 0; - (b[6] => z[3]) = 0; - (b[7] => z[3]) = 0; - (b[8] => z[3]) = 0; - (b[9] => z[3]) = 0; - (b[10] => z[3]) = 0; - (b[11] => z[3]) = 0; - (b[12] => z[3]) = 0; - (b[13] => z[3]) = 0; - (b[14] => z[3]) = 0; - (b[15] => z[3]) = 0; - (b[16] => z[3]) = 0; - (b[17] => z[3]) = 0; - (a[0] => z[4]) = 0; - (a[1] => z[4]) = 0; - (a[2] => z[4]) = 0; - (a[3] => z[4]) = 0; - (a[4] => z[4]) = 0; - (a[5] => z[4]) = 0; - (a[6] => z[4]) = 0; - (a[7] => z[4]) = 0; - (a[8] => z[4]) = 0; - (a[9] => z[4]) = 0; - (a[10] => z[4]) = 0; - (a[11] => z[4]) = 0; - (a[12] => z[4]) = 0; - (a[13] => z[4]) = 0; - (a[14] => z[4]) = 0; - (a[15] => z[4]) = 0; - (a[16] => z[4]) = 0; - (a[17] => z[4]) = 0; - (a[18] => z[4]) = 0; - (a[19] => z[4]) = 0; - (b[0] => z[4]) = 0; - (b[1] => z[4]) = 0; - (b[2] => z[4]) = 0; - (b[3] => z[4]) = 0; - (b[4] => z[4]) = 0; - (b[5] => z[4]) = 0; - (b[6] => z[4]) = 0; - (b[7] => z[4]) = 0; - (b[8] => z[4]) = 0; - (b[9] => z[4]) = 0; - (b[10] => z[4]) = 0; - (b[11] => z[4]) = 0; - (b[12] => z[4]) = 0; - (b[13] => z[4]) = 0; - (b[14] => z[4]) = 0; - (b[15] => z[4]) = 0; - (b[16] => z[4]) = 0; - (b[17] => z[4]) = 0; - (a[0] => z[5]) = 0; - (a[1] => z[5]) = 0; - (a[2] => z[5]) = 0; - (a[3] => z[5]) = 0; - (a[4] => z[5]) = 0; - (a[5] => z[5]) = 0; - (a[6] => z[5]) = 0; - (a[7] => z[5]) = 0; - (a[8] => z[5]) = 0; - (a[9] => z[5]) = 0; - (a[10] => z[5]) = 0; - (a[11] => z[5]) = 0; - (a[12] => z[5]) = 0; - (a[13] => z[5]) = 0; - (a[14] => z[5]) = 0; - (a[15] => z[5]) = 0; - (a[16] => z[5]) = 0; - (a[17] => z[5]) = 0; - (a[18] => z[5]) = 0; - (a[19] => z[5]) = 0; - (b[0] => z[5]) = 0; - (b[1] => z[5]) = 0; - (b[2] => z[5]) = 0; - (b[3] => z[5]) = 0; - (b[4] => z[5]) = 0; - (b[5] => z[5]) = 0; - (b[6] => z[5]) = 0; - (b[7] => z[5]) = 0; - (b[8] => z[5]) = 0; - (b[9] => z[5]) = 0; - (b[10] => z[5]) = 0; - (b[11] => z[5]) = 0; - (b[12] => z[5]) = 0; - (b[13] => z[5]) = 0; - (b[14] => z[5]) = 0; - (b[15] => z[5]) = 0; - (b[16] => z[5]) = 0; - (b[17] => z[5]) = 0; - (a[0] => z[6]) = 0; - (a[1] => z[6]) = 0; - (a[2] => z[6]) = 0; - (a[3] => z[6]) = 0; - (a[4] => z[6]) = 0; - (a[5] => z[6]) = 0; - (a[6] => z[6]) = 0; - (a[7] => z[6]) = 0; - (a[8] => z[6]) = 0; - (a[9] => z[6]) = 0; - (a[10] => z[6]) = 0; - (a[11] => z[6]) = 0; - (a[12] => z[6]) = 0; - (a[13] => z[6]) = 0; - (a[14] => z[6]) = 0; - (a[15] => z[6]) = 0; - (a[16] => z[6]) = 0; - (a[17] => z[6]) = 0; - (a[18] => z[6]) = 0; - (a[19] => z[6]) = 0; - (b[0] => z[6]) = 0; - (b[1] => z[6]) = 0; - (b[2] => z[6]) = 0; - (b[3] => z[6]) = 0; - (b[4] => z[6]) = 0; - (b[5] => z[6]) = 0; - (b[6] => z[6]) = 0; - (b[7] => z[6]) = 0; - (b[8] => z[6]) = 0; - (b[9] => z[6]) = 0; - (b[10] => z[6]) = 0; - (b[11] => z[6]) = 0; - (b[12] => z[6]) = 0; - (b[13] => z[6]) = 0; - (b[14] => z[6]) = 0; - (b[15] => z[6]) = 0; - (b[16] => z[6]) = 0; - (b[17] => z[6]) = 0; - (a[0] => z[7]) = 0; - (a[1] => z[7]) = 0; - (a[2] => z[7]) = 0; - (a[3] => z[7]) = 0; - (a[4] => z[7]) = 0; - (a[5] => z[7]) = 0; - (a[6] => z[7]) = 0; - (a[7] => z[7]) = 0; - (a[8] => z[7]) = 0; - (a[9] => z[7]) = 0; - (a[10] => z[7]) = 0; - (a[11] => z[7]) = 0; - (a[12] => z[7]) = 0; - (a[13] => z[7]) = 0; - (a[14] => z[7]) = 0; - (a[15] => z[7]) = 0; - (a[16] => z[7]) = 0; - (a[17] => z[7]) = 0; - (a[18] => z[7]) = 0; - (a[19] => z[7]) = 0; - (b[0] => z[7]) = 0; - (b[1] => z[7]) = 0; - (b[2] => z[7]) = 0; - (b[3] => z[7]) = 0; - (b[4] => z[7]) = 0; - (b[5] => z[7]) = 0; - (b[6] => z[7]) = 0; - (b[7] => z[7]) = 0; - (b[8] => z[7]) = 0; - (b[9] => z[7]) = 0; - (b[10] => z[7]) = 0; - (b[11] => z[7]) = 0; - (b[12] => z[7]) = 0; - (b[13] => z[7]) = 0; - (b[14] => z[7]) = 0; - (b[15] => z[7]) = 0; - (b[16] => z[7]) = 0; - (b[17] => z[7]) = 0; - (a[0] => z[8]) = 0; - (a[1] => z[8]) = 0; - (a[2] => z[8]) = 0; - (a[3] => z[8]) = 0; - (a[4] => z[8]) = 0; - (a[5] => z[8]) = 0; - (a[6] => z[8]) = 0; - (a[7] => z[8]) = 0; - (a[8] => z[8]) = 0; - (a[9] => z[8]) = 0; - (a[10] => z[8]) = 0; - (a[11] => z[8]) = 0; - (a[12] => z[8]) = 0; - (a[13] => z[8]) = 0; - (a[14] => z[8]) = 0; - (a[15] => z[8]) = 0; - (a[16] => z[8]) = 0; - (a[17] => z[8]) = 0; - (a[18] => z[8]) = 0; - (a[19] => z[8]) = 0; - (b[0] => z[8]) = 0; - (b[1] => z[8]) = 0; - (b[2] => z[8]) = 0; - (b[3] => z[8]) = 0; - (b[4] => z[8]) = 0; - (b[5] => z[8]) = 0; - (b[6] => z[8]) = 0; - (b[7] => z[8]) = 0; - (b[8] => z[8]) = 0; - (b[9] => z[8]) = 0; - (b[10] => z[8]) = 0; - (b[11] => z[8]) = 0; - (b[12] => z[8]) = 0; - (b[13] => z[8]) = 0; - (b[14] => z[8]) = 0; - (b[15] => z[8]) = 0; - (b[16] => z[8]) = 0; - (b[17] => z[8]) = 0; - (a[0] => z[9]) = 0; - (a[1] => z[9]) = 0; - (a[2] => z[9]) = 0; - (a[3] => z[9]) = 0; - (a[4] => z[9]) = 0; - (a[5] => z[9]) = 0; - (a[6] => z[9]) = 0; - (a[7] => z[9]) = 0; - (a[8] => z[9]) = 0; - (a[9] => z[9]) = 0; - (a[10] => z[9]) = 0; - (a[11] => z[9]) = 0; - (a[12] => z[9]) = 0; - (a[13] => z[9]) = 0; - (a[14] => z[9]) = 0; - (a[15] => z[9]) = 0; - (a[16] => z[9]) = 0; - (a[17] => z[9]) = 0; - (a[18] => z[9]) = 0; - (a[19] => z[9]) = 0; - (b[0] => z[9]) = 0; - (b[1] => z[9]) = 0; - (b[2] => z[9]) = 0; - (b[3] => z[9]) = 0; - (b[4] => z[9]) = 0; - (b[5] => z[9]) = 0; - (b[6] => z[9]) = 0; - (b[7] => z[9]) = 0; - (b[8] => z[9]) = 0; - (b[9] => z[9]) = 0; - (b[10] => z[9]) = 0; - (b[11] => z[9]) = 0; - (b[12] => z[9]) = 0; - (b[13] => z[9]) = 0; - (b[14] => z[9]) = 0; - (b[15] => z[9]) = 0; - (b[16] => z[9]) = 0; - (b[17] => z[9]) = 0; - (a[0] => z[10]) = 0; - (a[1] => z[10]) = 0; - (a[2] => z[10]) = 0; - (a[3] => z[10]) = 0; - (a[4] => z[10]) = 0; - (a[5] => z[10]) = 0; - (a[6] => z[10]) = 0; - (a[7] => z[10]) = 0; - (a[8] => z[10]) = 0; - (a[9] => z[10]) = 0; - (a[10] => z[10]) = 0; - (a[11] => z[10]) = 0; - (a[12] => z[10]) = 0; - (a[13] => z[10]) = 0; - (a[14] => z[10]) = 0; - (a[15] => z[10]) = 0; - (a[16] => z[10]) = 0; - (a[17] => z[10]) = 0; - (a[18] => z[10]) = 0; - (a[19] => z[10]) = 0; - (b[0] => z[10]) = 0; - (b[1] => z[10]) = 0; - (b[2] => z[10]) = 0; - (b[3] => z[10]) = 0; - (b[4] => z[10]) = 0; - (b[5] => z[10]) = 0; - (b[6] => z[10]) = 0; - (b[7] => z[10]) = 0; - (b[8] => z[10]) = 0; - (b[9] => z[10]) = 0; - (b[10] => z[10]) = 0; - (b[11] => z[10]) = 0; - (b[12] => z[10]) = 0; - (b[13] => z[10]) = 0; - (b[14] => z[10]) = 0; - (b[15] => z[10]) = 0; - (b[16] => z[10]) = 0; - (b[17] => z[10]) = 0; - (a[0] => z[11]) = 0; - (a[1] => z[11]) = 0; - (a[2] => z[11]) = 0; - (a[3] => z[11]) = 0; - (a[4] => z[11]) = 0; - (a[5] => z[11]) = 0; - (a[6] => z[11]) = 0; - (a[7] => z[11]) = 0; - (a[8] => z[11]) = 0; - (a[9] => z[11]) = 0; - (a[10] => z[11]) = 0; - (a[11] => z[11]) = 0; - (a[12] => z[11]) = 0; - (a[13] => z[11]) = 0; - (a[14] => z[11]) = 0; - (a[15] => z[11]) = 0; - (a[16] => z[11]) = 0; - (a[17] => z[11]) = 0; - (a[18] => z[11]) = 0; - (a[19] => z[11]) = 0; - (b[0] => z[11]) = 0; - (b[1] => z[11]) = 0; - (b[2] => z[11]) = 0; - (b[3] => z[11]) = 0; - (b[4] => z[11]) = 0; - (b[5] => z[11]) = 0; - (b[6] => z[11]) = 0; - (b[7] => z[11]) = 0; - (b[8] => z[11]) = 0; - (b[9] => z[11]) = 0; - (b[10] => z[11]) = 0; - (b[11] => z[11]) = 0; - (b[12] => z[11]) = 0; - (b[13] => z[11]) = 0; - (b[14] => z[11]) = 0; - (b[15] => z[11]) = 0; - (b[16] => z[11]) = 0; - (b[17] => z[11]) = 0; - (a[0] => z[12]) = 0; - (a[1] => z[12]) = 0; - (a[2] => z[12]) = 0; - (a[3] => z[12]) = 0; - (a[4] => z[12]) = 0; - (a[5] => z[12]) = 0; - (a[6] => z[12]) = 0; - (a[7] => z[12]) = 0; - (a[8] => z[12]) = 0; - (a[9] => z[12]) = 0; - (a[10] => z[12]) = 0; - (a[11] => z[12]) = 0; - (a[12] => z[12]) = 0; - (a[13] => z[12]) = 0; - (a[14] => z[12]) = 0; - (a[15] => z[12]) = 0; - (a[16] => z[12]) = 0; - (a[17] => z[12]) = 0; - (a[18] => z[12]) = 0; - (a[19] => z[12]) = 0; - (b[0] => z[12]) = 0; - (b[1] => z[12]) = 0; - (b[2] => z[12]) = 0; - (b[3] => z[12]) = 0; - (b[4] => z[12]) = 0; - (b[5] => z[12]) = 0; - (b[6] => z[12]) = 0; - (b[7] => z[12]) = 0; - (b[8] => z[12]) = 0; - (b[9] => z[12]) = 0; - (b[10] => z[12]) = 0; - (b[11] => z[12]) = 0; - (b[12] => z[12]) = 0; - (b[13] => z[12]) = 0; - (b[14] => z[12]) = 0; - (b[15] => z[12]) = 0; - (b[16] => z[12]) = 0; - (b[17] => z[12]) = 0; - (a[0] => z[13]) = 0; - (a[1] => z[13]) = 0; - (a[2] => z[13]) = 0; - (a[3] => z[13]) = 0; - (a[4] => z[13]) = 0; - (a[5] => z[13]) = 0; - (a[6] => z[13]) = 0; - (a[7] => z[13]) = 0; - (a[8] => z[13]) = 0; - (a[9] => z[13]) = 0; - (a[10] => z[13]) = 0; - (a[11] => z[13]) = 0; - (a[12] => z[13]) = 0; - (a[13] => z[13]) = 0; - (a[14] => z[13]) = 0; - (a[15] => z[13]) = 0; - (a[16] => z[13]) = 0; - (a[17] => z[13]) = 0; - (a[18] => z[13]) = 0; - (a[19] => z[13]) = 0; - (b[0] => z[13]) = 0; - (b[1] => z[13]) = 0; - (b[2] => z[13]) = 0; - (b[3] => z[13]) = 0; - (b[4] => z[13]) = 0; - (b[5] => z[13]) = 0; - (b[6] => z[13]) = 0; - (b[7] => z[13]) = 0; - (b[8] => z[13]) = 0; - (b[9] => z[13]) = 0; - (b[10] => z[13]) = 0; - (b[11] => z[13]) = 0; - (b[12] => z[13]) = 0; - (b[13] => z[13]) = 0; - (b[14] => z[13]) = 0; - (b[15] => z[13]) = 0; - (b[16] => z[13]) = 0; - (b[17] => z[13]) = 0; - (a[0] => z[14]) = 0; - (a[1] => z[14]) = 0; - (a[2] => z[14]) = 0; - (a[3] => z[14]) = 0; - (a[4] => z[14]) = 0; - (a[5] => z[14]) = 0; - (a[6] => z[14]) = 0; - (a[7] => z[14]) = 0; - (a[8] => z[14]) = 0; - (a[9] => z[14]) = 0; - (a[10] => z[14]) = 0; - (a[11] => z[14]) = 0; - (a[12] => z[14]) = 0; - (a[13] => z[14]) = 0; - (a[14] => z[14]) = 0; - (a[15] => z[14]) = 0; - (a[16] => z[14]) = 0; - (a[17] => z[14]) = 0; - (a[18] => z[14]) = 0; - (a[19] => z[14]) = 0; - (b[0] => z[14]) = 0; - (b[1] => z[14]) = 0; - (b[2] => z[14]) = 0; - (b[3] => z[14]) = 0; - (b[4] => z[14]) = 0; - (b[5] => z[14]) = 0; - (b[6] => z[14]) = 0; - (b[7] => z[14]) = 0; - (b[8] => z[14]) = 0; - (b[9] => z[14]) = 0; - (b[10] => z[14]) = 0; - (b[11] => z[14]) = 0; - (b[12] => z[14]) = 0; - (b[13] => z[14]) = 0; - (b[14] => z[14]) = 0; - (b[15] => z[14]) = 0; - (b[16] => z[14]) = 0; - (b[17] => z[14]) = 0; - (a[0] => z[15]) = 0; - (a[1] => z[15]) = 0; - (a[2] => z[15]) = 0; - (a[3] => z[15]) = 0; - (a[4] => z[15]) = 0; - (a[5] => z[15]) = 0; - (a[6] => z[15]) = 0; - (a[7] => z[15]) = 0; - (a[8] => z[15]) = 0; - (a[9] => z[15]) = 0; - (a[10] => z[15]) = 0; - (a[11] => z[15]) = 0; - (a[12] => z[15]) = 0; - (a[13] => z[15]) = 0; - (a[14] => z[15]) = 0; - (a[15] => z[15]) = 0; - (a[16] => z[15]) = 0; - (a[17] => z[15]) = 0; - (a[18] => z[15]) = 0; - (a[19] => z[15]) = 0; - (b[0] => z[15]) = 0; - (b[1] => z[15]) = 0; - (b[2] => z[15]) = 0; - (b[3] => z[15]) = 0; - (b[4] => z[15]) = 0; - (b[5] => z[15]) = 0; - (b[6] => z[15]) = 0; - (b[7] => z[15]) = 0; - (b[8] => z[15]) = 0; - (b[9] => z[15]) = 0; - (b[10] => z[15]) = 0; - (b[11] => z[15]) = 0; - (b[12] => z[15]) = 0; - (b[13] => z[15]) = 0; - (b[14] => z[15]) = 0; - (b[15] => z[15]) = 0; - (b[16] => z[15]) = 0; - (b[17] => z[15]) = 0; - (a[0] => z[16]) = 0; - (a[1] => z[16]) = 0; - (a[2] => z[16]) = 0; - (a[3] => z[16]) = 0; - (a[4] => z[16]) = 0; - (a[5] => z[16]) = 0; - (a[6] => z[16]) = 0; - (a[7] => z[16]) = 0; - (a[8] => z[16]) = 0; - (a[9] => z[16]) = 0; - (a[10] => z[16]) = 0; - (a[11] => z[16]) = 0; - (a[12] => z[16]) = 0; - (a[13] => z[16]) = 0; - (a[14] => z[16]) = 0; - (a[15] => z[16]) = 0; - (a[16] => z[16]) = 0; - (a[17] => z[16]) = 0; - (a[18] => z[16]) = 0; - (a[19] => z[16]) = 0; - (b[0] => z[16]) = 0; - (b[1] => z[16]) = 0; - (b[2] => z[16]) = 0; - (b[3] => z[16]) = 0; - (b[4] => z[16]) = 0; - (b[5] => z[16]) = 0; - (b[6] => z[16]) = 0; - (b[7] => z[16]) = 0; - (b[8] => z[16]) = 0; - (b[9] => z[16]) = 0; - (b[10] => z[16]) = 0; - (b[11] => z[16]) = 0; - (b[12] => z[16]) = 0; - (b[13] => z[16]) = 0; - (b[14] => z[16]) = 0; - (b[15] => z[16]) = 0; - (b[16] => z[16]) = 0; - (b[17] => z[16]) = 0; - (a[0] => z[17]) = 0; - (a[1] => z[17]) = 0; - (a[2] => z[17]) = 0; - (a[3] => z[17]) = 0; - (a[4] => z[17]) = 0; - (a[5] => z[17]) = 0; - (a[6] => z[17]) = 0; - (a[7] => z[17]) = 0; - (a[8] => z[17]) = 0; - (a[9] => z[17]) = 0; - (a[10] => z[17]) = 0; - (a[11] => z[17]) = 0; - (a[12] => z[17]) = 0; - (a[13] => z[17]) = 0; - (a[14] => z[17]) = 0; - (a[15] => z[17]) = 0; - (a[16] => z[17]) = 0; - (a[17] => z[17]) = 0; - (a[18] => z[17]) = 0; - (a[19] => z[17]) = 0; - (b[0] => z[17]) = 0; - (b[1] => z[17]) = 0; - (b[2] => z[17]) = 0; - (b[3] => z[17]) = 0; - (b[4] => z[17]) = 0; - (b[5] => z[17]) = 0; - (b[6] => z[17]) = 0; - (b[7] => z[17]) = 0; - (b[8] => z[17]) = 0; - (b[9] => z[17]) = 0; - (b[10] => z[17]) = 0; - (b[11] => z[17]) = 0; - (b[12] => z[17]) = 0; - (b[13] => z[17]) = 0; - (b[14] => z[17]) = 0; - (b[15] => z[17]) = 0; - (b[16] => z[17]) = 0; - (b[17] => z[17]) = 0; - (a[0] => z[18]) = 0; - (a[1] => z[18]) = 0; - (a[2] => z[18]) = 0; - (a[3] => z[18]) = 0; - (a[4] => z[18]) = 0; - (a[5] => z[18]) = 0; - (a[6] => z[18]) = 0; - (a[7] => z[18]) = 0; - (a[8] => z[18]) = 0; - (a[9] => z[18]) = 0; - (a[10] => z[18]) = 0; - (a[11] => z[18]) = 0; - (a[12] => z[18]) = 0; - (a[13] => z[18]) = 0; - (a[14] => z[18]) = 0; - (a[15] => z[18]) = 0; - (a[16] => z[18]) = 0; - (a[17] => z[18]) = 0; - (a[18] => z[18]) = 0; - (a[19] => z[18]) = 0; - (b[0] => z[18]) = 0; - (b[1] => z[18]) = 0; - (b[2] => z[18]) = 0; - (b[3] => z[18]) = 0; - (b[4] => z[18]) = 0; - (b[5] => z[18]) = 0; - (b[6] => z[18]) = 0; - (b[7] => z[18]) = 0; - (b[8] => z[18]) = 0; - (b[9] => z[18]) = 0; - (b[10] => z[18]) = 0; - (b[11] => z[18]) = 0; - (b[12] => z[18]) = 0; - (b[13] => z[18]) = 0; - (b[14] => z[18]) = 0; - (b[15] => z[18]) = 0; - (b[16] => z[18]) = 0; - (b[17] => z[18]) = 0; - (a[0] => z[19]) = 0; - (a[1] => z[19]) = 0; - (a[2] => z[19]) = 0; - (a[3] => z[19]) = 0; - (a[4] => z[19]) = 0; - (a[5] => z[19]) = 0; - (a[6] => z[19]) = 0; - (a[7] => z[19]) = 0; - (a[8] => z[19]) = 0; - (a[9] => z[19]) = 0; - (a[10] => z[19]) = 0; - (a[11] => z[19]) = 0; - (a[12] => z[19]) = 0; - (a[13] => z[19]) = 0; - (a[14] => z[19]) = 0; - (a[15] => z[19]) = 0; - (a[16] => z[19]) = 0; - (a[17] => z[19]) = 0; - (a[18] => z[19]) = 0; - (a[19] => z[19]) = 0; - (b[0] => z[19]) = 0; - (b[1] => z[19]) = 0; - (b[2] => z[19]) = 0; - (b[3] => z[19]) = 0; - (b[4] => z[19]) = 0; - (b[5] => z[19]) = 0; - (b[6] => z[19]) = 0; - (b[7] => z[19]) = 0; - (b[8] => z[19]) = 0; - (b[9] => z[19]) = 0; - (b[10] => z[19]) = 0; - (b[11] => z[19]) = 0; - (b[12] => z[19]) = 0; - (b[13] => z[19]) = 0; - (b[14] => z[19]) = 0; - (b[15] => z[19]) = 0; - (b[16] => z[19]) = 0; - (b[17] => z[19]) = 0; - (a[0] => z[20]) = 0; - (a[1] => z[20]) = 0; - (a[2] => z[20]) = 0; - (a[3] => z[20]) = 0; - (a[4] => z[20]) = 0; - (a[5] => z[20]) = 0; - (a[6] => z[20]) = 0; - (a[7] => z[20]) = 0; - (a[8] => z[20]) = 0; - (a[9] => z[20]) = 0; - (a[10] => z[20]) = 0; - (a[11] => z[20]) = 0; - (a[12] => z[20]) = 0; - (a[13] => z[20]) = 0; - (a[14] => z[20]) = 0; - (a[15] => z[20]) = 0; - (a[16] => z[20]) = 0; - (a[17] => z[20]) = 0; - (a[18] => z[20]) = 0; - (a[19] => z[20]) = 0; - (b[0] => z[20]) = 0; - (b[1] => z[20]) = 0; - (b[2] => z[20]) = 0; - (b[3] => z[20]) = 0; - (b[4] => z[20]) = 0; - (b[5] => z[20]) = 0; - (b[6] => z[20]) = 0; - (b[7] => z[20]) = 0; - (b[8] => z[20]) = 0; - (b[9] => z[20]) = 0; - (b[10] => z[20]) = 0; - (b[11] => z[20]) = 0; - (b[12] => z[20]) = 0; - (b[13] => z[20]) = 0; - (b[14] => z[20]) = 0; - (b[15] => z[20]) = 0; - (b[16] => z[20]) = 0; - (b[17] => z[20]) = 0; - (a[0] => z[21]) = 0; - (a[1] => z[21]) = 0; - (a[2] => z[21]) = 0; - (a[3] => z[21]) = 0; - (a[4] => z[21]) = 0; - (a[5] => z[21]) = 0; - (a[6] => z[21]) = 0; - (a[7] => z[21]) = 0; - (a[8] => z[21]) = 0; - (a[9] => z[21]) = 0; - (a[10] => z[21]) = 0; - (a[11] => z[21]) = 0; - (a[12] => z[21]) = 0; - (a[13] => z[21]) = 0; - (a[14] => z[21]) = 0; - (a[15] => z[21]) = 0; - (a[16] => z[21]) = 0; - (a[17] => z[21]) = 0; - (a[18] => z[21]) = 0; - (a[19] => z[21]) = 0; - (b[0] => z[21]) = 0; - (b[1] => z[21]) = 0; - (b[2] => z[21]) = 0; - (b[3] => z[21]) = 0; - (b[4] => z[21]) = 0; - (b[5] => z[21]) = 0; - (b[6] => z[21]) = 0; - (b[7] => z[21]) = 0; - (b[8] => z[21]) = 0; - (b[9] => z[21]) = 0; - (b[10] => z[21]) = 0; - (b[11] => z[21]) = 0; - (b[12] => z[21]) = 0; - (b[13] => z[21]) = 0; - (b[14] => z[21]) = 0; - (b[15] => z[21]) = 0; - (b[16] => z[21]) = 0; - (b[17] => z[21]) = 0; - (a[0] => z[22]) = 0; - (a[1] => z[22]) = 0; - (a[2] => z[22]) = 0; - (a[3] => z[22]) = 0; - (a[4] => z[22]) = 0; - (a[5] => z[22]) = 0; - (a[6] => z[22]) = 0; - (a[7] => z[22]) = 0; - (a[8] => z[22]) = 0; - (a[9] => z[22]) = 0; - (a[10] => z[22]) = 0; - (a[11] => z[22]) = 0; - (a[12] => z[22]) = 0; - (a[13] => z[22]) = 0; - (a[14] => z[22]) = 0; - (a[15] => z[22]) = 0; - (a[16] => z[22]) = 0; - (a[17] => z[22]) = 0; - (a[18] => z[22]) = 0; - (a[19] => z[22]) = 0; - (b[0] => z[22]) = 0; - (b[1] => z[22]) = 0; - (b[2] => z[22]) = 0; - (b[3] => z[22]) = 0; - (b[4] => z[22]) = 0; - (b[5] => z[22]) = 0; - (b[6] => z[22]) = 0; - (b[7] => z[22]) = 0; - (b[8] => z[22]) = 0; - (b[9] => z[22]) = 0; - (b[10] => z[22]) = 0; - (b[11] => z[22]) = 0; - (b[12] => z[22]) = 0; - (b[13] => z[22]) = 0; - (b[14] => z[22]) = 0; - (b[15] => z[22]) = 0; - (b[16] => z[22]) = 0; - (b[17] => z[22]) = 0; - (a[0] => z[23]) = 0; - (a[1] => z[23]) = 0; - (a[2] => z[23]) = 0; - (a[3] => z[23]) = 0; - (a[4] => z[23]) = 0; - (a[5] => z[23]) = 0; - (a[6] => z[23]) = 0; - (a[7] => z[23]) = 0; - (a[8] => z[23]) = 0; - (a[9] => z[23]) = 0; - (a[10] => z[23]) = 0; - (a[11] => z[23]) = 0; - (a[12] => z[23]) = 0; - (a[13] => z[23]) = 0; - (a[14] => z[23]) = 0; - (a[15] => z[23]) = 0; - (a[16] => z[23]) = 0; - (a[17] => z[23]) = 0; - (a[18] => z[23]) = 0; - (a[19] => z[23]) = 0; - (b[0] => z[23]) = 0; - (b[1] => z[23]) = 0; - (b[2] => z[23]) = 0; - (b[3] => z[23]) = 0; - (b[4] => z[23]) = 0; - (b[5] => z[23]) = 0; - (b[6] => z[23]) = 0; - (b[7] => z[23]) = 0; - (b[8] => z[23]) = 0; - (b[9] => z[23]) = 0; - (b[10] => z[23]) = 0; - (b[11] => z[23]) = 0; - (b[12] => z[23]) = 0; - (b[13] => z[23]) = 0; - (b[14] => z[23]) = 0; - (b[15] => z[23]) = 0; - (b[16] => z[23]) = 0; - (b[17] => z[23]) = 0; - (a[0] => z[24]) = 0; - (a[1] => z[24]) = 0; - (a[2] => z[24]) = 0; - (a[3] => z[24]) = 0; - (a[4] => z[24]) = 0; - (a[5] => z[24]) = 0; - (a[6] => z[24]) = 0; - (a[7] => z[24]) = 0; - (a[8] => z[24]) = 0; - (a[9] => z[24]) = 0; - (a[10] => z[24]) = 0; - (a[11] => z[24]) = 0; - (a[12] => z[24]) = 0; - (a[13] => z[24]) = 0; - (a[14] => z[24]) = 0; - (a[15] => z[24]) = 0; - (a[16] => z[24]) = 0; - (a[17] => z[24]) = 0; - (a[18] => z[24]) = 0; - (a[19] => z[24]) = 0; - (b[0] => z[24]) = 0; - (b[1] => z[24]) = 0; - (b[2] => z[24]) = 0; - (b[3] => z[24]) = 0; - (b[4] => z[24]) = 0; - (b[5] => z[24]) = 0; - (b[6] => z[24]) = 0; - (b[7] => z[24]) = 0; - (b[8] => z[24]) = 0; - (b[9] => z[24]) = 0; - (b[10] => z[24]) = 0; - (b[11] => z[24]) = 0; - (b[12] => z[24]) = 0; - (b[13] => z[24]) = 0; - (b[14] => z[24]) = 0; - (b[15] => z[24]) = 0; - (b[16] => z[24]) = 0; - (b[17] => z[24]) = 0; - (a[0] => z[25]) = 0; - (a[1] => z[25]) = 0; - (a[2] => z[25]) = 0; - (a[3] => z[25]) = 0; - (a[4] => z[25]) = 0; - (a[5] => z[25]) = 0; - (a[6] => z[25]) = 0; - (a[7] => z[25]) = 0; - (a[8] => z[25]) = 0; - (a[9] => z[25]) = 0; - (a[10] => z[25]) = 0; - (a[11] => z[25]) = 0; - (a[12] => z[25]) = 0; - (a[13] => z[25]) = 0; - (a[14] => z[25]) = 0; - (a[15] => z[25]) = 0; - (a[16] => z[25]) = 0; - (a[17] => z[25]) = 0; - (a[18] => z[25]) = 0; - (a[19] => z[25]) = 0; - (b[0] => z[25]) = 0; - (b[1] => z[25]) = 0; - (b[2] => z[25]) = 0; - (b[3] => z[25]) = 0; - (b[4] => z[25]) = 0; - (b[5] => z[25]) = 0; - (b[6] => z[25]) = 0; - (b[7] => z[25]) = 0; - (b[8] => z[25]) = 0; - (b[9] => z[25]) = 0; - (b[10] => z[25]) = 0; - (b[11] => z[25]) = 0; - (b[12] => z[25]) = 0; - (b[13] => z[25]) = 0; - (b[14] => z[25]) = 0; - (b[15] => z[25]) = 0; - (b[16] => z[25]) = 0; - (b[17] => z[25]) = 0; - (a[0] => z[26]) = 0; - (a[1] => z[26]) = 0; - (a[2] => z[26]) = 0; - (a[3] => z[26]) = 0; - (a[4] => z[26]) = 0; - (a[5] => z[26]) = 0; - (a[6] => z[26]) = 0; - (a[7] => z[26]) = 0; - (a[8] => z[26]) = 0; - (a[9] => z[26]) = 0; - (a[10] => z[26]) = 0; - (a[11] => z[26]) = 0; - (a[12] => z[26]) = 0; - (a[13] => z[26]) = 0; - (a[14] => z[26]) = 0; - (a[15] => z[26]) = 0; - (a[16] => z[26]) = 0; - (a[17] => z[26]) = 0; - (a[18] => z[26]) = 0; - (a[19] => z[26]) = 0; - (b[0] => z[26]) = 0; - (b[1] => z[26]) = 0; - (b[2] => z[26]) = 0; - (b[3] => z[26]) = 0; - (b[4] => z[26]) = 0; - (b[5] => z[26]) = 0; - (b[6] => z[26]) = 0; - (b[7] => z[26]) = 0; - (b[8] => z[26]) = 0; - (b[9] => z[26]) = 0; - (b[10] => z[26]) = 0; - (b[11] => z[26]) = 0; - (b[12] => z[26]) = 0; - (b[13] => z[26]) = 0; - (b[14] => z[26]) = 0; - (b[15] => z[26]) = 0; - (b[16] => z[26]) = 0; - (b[17] => z[26]) = 0; - (a[0] => z[27]) = 0; - (a[1] => z[27]) = 0; - (a[2] => z[27]) = 0; - (a[3] => z[27]) = 0; - (a[4] => z[27]) = 0; - (a[5] => z[27]) = 0; - (a[6] => z[27]) = 0; - (a[7] => z[27]) = 0; - (a[8] => z[27]) = 0; - (a[9] => z[27]) = 0; - (a[10] => z[27]) = 0; - (a[11] => z[27]) = 0; - (a[12] => z[27]) = 0; - (a[13] => z[27]) = 0; - (a[14] => z[27]) = 0; - (a[15] => z[27]) = 0; - (a[16] => z[27]) = 0; - (a[17] => z[27]) = 0; - (a[18] => z[27]) = 0; - (a[19] => z[27]) = 0; - (b[0] => z[27]) = 0; - (b[1] => z[27]) = 0; - (b[2] => z[27]) = 0; - (b[3] => z[27]) = 0; - (b[4] => z[27]) = 0; - (b[5] => z[27]) = 0; - (b[6] => z[27]) = 0; - (b[7] => z[27]) = 0; - (b[8] => z[27]) = 0; - (b[9] => z[27]) = 0; - (b[10] => z[27]) = 0; - (b[11] => z[27]) = 0; - (b[12] => z[27]) = 0; - (b[13] => z[27]) = 0; - (b[14] => z[27]) = 0; - (b[15] => z[27]) = 0; - (b[16] => z[27]) = 0; - (b[17] => z[27]) = 0; - (a[0] => z[28]) = 0; - (a[1] => z[28]) = 0; - (a[2] => z[28]) = 0; - (a[3] => z[28]) = 0; - (a[4] => z[28]) = 0; - (a[5] => z[28]) = 0; - (a[6] => z[28]) = 0; - (a[7] => z[28]) = 0; - (a[8] => z[28]) = 0; - (a[9] => z[28]) = 0; - (a[10] => z[28]) = 0; - (a[11] => z[28]) = 0; - (a[12] => z[28]) = 0; - (a[13] => z[28]) = 0; - (a[14] => z[28]) = 0; - (a[15] => z[28]) = 0; - (a[16] => z[28]) = 0; - (a[17] => z[28]) = 0; - (a[18] => z[28]) = 0; - (a[19] => z[28]) = 0; - (b[0] => z[28]) = 0; - (b[1] => z[28]) = 0; - (b[2] => z[28]) = 0; - (b[3] => z[28]) = 0; - (b[4] => z[28]) = 0; - (b[5] => z[28]) = 0; - (b[6] => z[28]) = 0; - (b[7] => z[28]) = 0; - (b[8] => z[28]) = 0; - (b[9] => z[28]) = 0; - (b[10] => z[28]) = 0; - (b[11] => z[28]) = 0; - (b[12] => z[28]) = 0; - (b[13] => z[28]) = 0; - (b[14] => z[28]) = 0; - (b[15] => z[28]) = 0; - (b[16] => z[28]) = 0; - (b[17] => z[28]) = 0; - (a[0] => z[29]) = 0; - (a[1] => z[29]) = 0; - (a[2] => z[29]) = 0; - (a[3] => z[29]) = 0; - (a[4] => z[29]) = 0; - (a[5] => z[29]) = 0; - (a[6] => z[29]) = 0; - (a[7] => z[29]) = 0; - (a[8] => z[29]) = 0; - (a[9] => z[29]) = 0; - (a[10] => z[29]) = 0; - (a[11] => z[29]) = 0; - (a[12] => z[29]) = 0; - (a[13] => z[29]) = 0; - (a[14] => z[29]) = 0; - (a[15] => z[29]) = 0; - (a[16] => z[29]) = 0; - (a[17] => z[29]) = 0; - (a[18] => z[29]) = 0; - (a[19] => z[29]) = 0; - (b[0] => z[29]) = 0; - (b[1] => z[29]) = 0; - (b[2] => z[29]) = 0; - (b[3] => z[29]) = 0; - (b[4] => z[29]) = 0; - (b[5] => z[29]) = 0; - (b[6] => z[29]) = 0; - (b[7] => z[29]) = 0; - (b[8] => z[29]) = 0; - (b[9] => z[29]) = 0; - (b[10] => z[29]) = 0; - (b[11] => z[29]) = 0; - (b[12] => z[29]) = 0; - (b[13] => z[29]) = 0; - (b[14] => z[29]) = 0; - (b[15] => z[29]) = 0; - (b[16] => z[29]) = 0; - (b[17] => z[29]) = 0; - (a[0] => z[30]) = 0; - (a[1] => z[30]) = 0; - (a[2] => z[30]) = 0; - (a[3] => z[30]) = 0; - (a[4] => z[30]) = 0; - (a[5] => z[30]) = 0; - (a[6] => z[30]) = 0; - (a[7] => z[30]) = 0; - (a[8] => z[30]) = 0; - (a[9] => z[30]) = 0; - (a[10] => z[30]) = 0; - (a[11] => z[30]) = 0; - (a[12] => z[30]) = 0; - (a[13] => z[30]) = 0; - (a[14] => z[30]) = 0; - (a[15] => z[30]) = 0; - (a[16] => z[30]) = 0; - (a[17] => z[30]) = 0; - (a[18] => z[30]) = 0; - (a[19] => z[30]) = 0; - (b[0] => z[30]) = 0; - (b[1] => z[30]) = 0; - (b[2] => z[30]) = 0; - (b[3] => z[30]) = 0; - (b[4] => z[30]) = 0; - (b[5] => z[30]) = 0; - (b[6] => z[30]) = 0; - (b[7] => z[30]) = 0; - (b[8] => z[30]) = 0; - (b[9] => z[30]) = 0; - (b[10] => z[30]) = 0; - (b[11] => z[30]) = 0; - (b[12] => z[30]) = 0; - (b[13] => z[30]) = 0; - (b[14] => z[30]) = 0; - (b[15] => z[30]) = 0; - (b[16] => z[30]) = 0; - (b[17] => z[30]) = 0; - (a[0] => z[31]) = 0; - (a[1] => z[31]) = 0; - (a[2] => z[31]) = 0; - (a[3] => z[31]) = 0; - (a[4] => z[31]) = 0; - (a[5] => z[31]) = 0; - (a[6] => z[31]) = 0; - (a[7] => z[31]) = 0; - (a[8] => z[31]) = 0; - (a[9] => z[31]) = 0; - (a[10] => z[31]) = 0; - (a[11] => z[31]) = 0; - (a[12] => z[31]) = 0; - (a[13] => z[31]) = 0; - (a[14] => z[31]) = 0; - (a[15] => z[31]) = 0; - (a[16] => z[31]) = 0; - (a[17] => z[31]) = 0; - (a[18] => z[31]) = 0; - (a[19] => z[31]) = 0; - (b[0] => z[31]) = 0; - (b[1] => z[31]) = 0; - (b[2] => z[31]) = 0; - (b[3] => z[31]) = 0; - (b[4] => z[31]) = 0; - (b[5] => z[31]) = 0; - (b[6] => z[31]) = 0; - (b[7] => z[31]) = 0; - (b[8] => z[31]) = 0; - (b[9] => z[31]) = 0; - (b[10] => z[31]) = 0; - (b[11] => z[31]) = 0; - (b[12] => z[31]) = 0; - (b[13] => z[31]) = 0; - (b[14] => z[31]) = 0; - (b[15] => z[31]) = 0; - (b[16] => z[31]) = 0; - (b[17] => z[31]) = 0; - (a[0] => z[32]) = 0; - (a[1] => z[32]) = 0; - (a[2] => z[32]) = 0; - (a[3] => z[32]) = 0; - (a[4] => z[32]) = 0; - (a[5] => z[32]) = 0; - (a[6] => z[32]) = 0; - (a[7] => z[32]) = 0; - (a[8] => z[32]) = 0; - (a[9] => z[32]) = 0; - (a[10] => z[32]) = 0; - (a[11] => z[32]) = 0; - (a[12] => z[32]) = 0; - (a[13] => z[32]) = 0; - (a[14] => z[32]) = 0; - (a[15] => z[32]) = 0; - (a[16] => z[32]) = 0; - (a[17] => z[32]) = 0; - (a[18] => z[32]) = 0; - (a[19] => z[32]) = 0; - (b[0] => z[32]) = 0; - (b[1] => z[32]) = 0; - (b[2] => z[32]) = 0; - (b[3] => z[32]) = 0; - (b[4] => z[32]) = 0; - (b[5] => z[32]) = 0; - (b[6] => z[32]) = 0; - (b[7] => z[32]) = 0; - (b[8] => z[32]) = 0; - (b[9] => z[32]) = 0; - (b[10] => z[32]) = 0; - (b[11] => z[32]) = 0; - (b[12] => z[32]) = 0; - (b[13] => z[32]) = 0; - (b[14] => z[32]) = 0; - (b[15] => z[32]) = 0; - (b[16] => z[32]) = 0; - (b[17] => z[32]) = 0; - (a[0] => z[33]) = 0; - (a[1] => z[33]) = 0; - (a[2] => z[33]) = 0; - (a[3] => z[33]) = 0; - (a[4] => z[33]) = 0; - (a[5] => z[33]) = 0; - (a[6] => z[33]) = 0; - (a[7] => z[33]) = 0; - (a[8] => z[33]) = 0; - (a[9] => z[33]) = 0; - (a[10] => z[33]) = 0; - (a[11] => z[33]) = 0; - (a[12] => z[33]) = 0; - (a[13] => z[33]) = 0; - (a[14] => z[33]) = 0; - (a[15] => z[33]) = 0; - (a[16] => z[33]) = 0; - (a[17] => z[33]) = 0; - (a[18] => z[33]) = 0; - (a[19] => z[33]) = 0; - (b[0] => z[33]) = 0; - (b[1] => z[33]) = 0; - (b[2] => z[33]) = 0; - (b[3] => z[33]) = 0; - (b[4] => z[33]) = 0; - (b[5] => z[33]) = 0; - (b[6] => z[33]) = 0; - (b[7] => z[33]) = 0; - (b[8] => z[33]) = 0; - (b[9] => z[33]) = 0; - (b[10] => z[33]) = 0; - (b[11] => z[33]) = 0; - (b[12] => z[33]) = 0; - (b[13] => z[33]) = 0; - (b[14] => z[33]) = 0; - (b[15] => z[33]) = 0; - (b[16] => z[33]) = 0; - (b[17] => z[33]) = 0; - (a[0] => z[34]) = 0; - (a[1] => z[34]) = 0; - (a[2] => z[34]) = 0; - (a[3] => z[34]) = 0; - (a[4] => z[34]) = 0; - (a[5] => z[34]) = 0; - (a[6] => z[34]) = 0; - (a[7] => z[34]) = 0; - (a[8] => z[34]) = 0; - (a[9] => z[34]) = 0; - (a[10] => z[34]) = 0; - (a[11] => z[34]) = 0; - (a[12] => z[34]) = 0; - (a[13] => z[34]) = 0; - (a[14] => z[34]) = 0; - (a[15] => z[34]) = 0; - (a[16] => z[34]) = 0; - (a[17] => z[34]) = 0; - (a[18] => z[34]) = 0; - (a[19] => z[34]) = 0; - (b[0] => z[34]) = 0; - (b[1] => z[34]) = 0; - (b[2] => z[34]) = 0; - (b[3] => z[34]) = 0; - (b[4] => z[34]) = 0; - (b[5] => z[34]) = 0; - (b[6] => z[34]) = 0; - (b[7] => z[34]) = 0; - (b[8] => z[34]) = 0; - (b[9] => z[34]) = 0; - (b[10] => z[34]) = 0; - (b[11] => z[34]) = 0; - (b[12] => z[34]) = 0; - (b[13] => z[34]) = 0; - (b[14] => z[34]) = 0; - (b[15] => z[34]) = 0; - (b[16] => z[34]) = 0; - (b[17] => z[34]) = 0; - (a[0] => z[35]) = 0; - (a[1] => z[35]) = 0; - (a[2] => z[35]) = 0; - (a[3] => z[35]) = 0; - (a[4] => z[35]) = 0; - (a[5] => z[35]) = 0; - (a[6] => z[35]) = 0; - (a[7] => z[35]) = 0; - (a[8] => z[35]) = 0; - (a[9] => z[35]) = 0; - (a[10] => z[35]) = 0; - (a[11] => z[35]) = 0; - (a[12] => z[35]) = 0; - (a[13] => z[35]) = 0; - (a[14] => z[35]) = 0; - (a[15] => z[35]) = 0; - (a[16] => z[35]) = 0; - (a[17] => z[35]) = 0; - (a[18] => z[35]) = 0; - (a[19] => z[35]) = 0; - (b[0] => z[35]) = 0; - (b[1] => z[35]) = 0; - (b[2] => z[35]) = 0; - (b[3] => z[35]) = 0; - (b[4] => z[35]) = 0; - (b[5] => z[35]) = 0; - (b[6] => z[35]) = 0; - (b[7] => z[35]) = 0; - (b[8] => z[35]) = 0; - (b[9] => z[35]) = 0; - (b[10] => z[35]) = 0; - (b[11] => z[35]) = 0; - (b[12] => z[35]) = 0; - (b[13] => z[35]) = 0; - (b[14] => z[35]) = 0; - (b[15] => z[35]) = 0; - (b[16] => z[35]) = 0; - (b[17] => z[35]) = 0; - (a[0] => z[36]) = 0; - (a[1] => z[36]) = 0; - (a[2] => z[36]) = 0; - (a[3] => z[36]) = 0; - (a[4] => z[36]) = 0; - (a[5] => z[36]) = 0; - (a[6] => z[36]) = 0; - (a[7] => z[36]) = 0; - (a[8] => z[36]) = 0; - (a[9] => z[36]) = 0; - (a[10] => z[36]) = 0; - (a[11] => z[36]) = 0; - (a[12] => z[36]) = 0; - (a[13] => z[36]) = 0; - (a[14] => z[36]) = 0; - (a[15] => z[36]) = 0; - (a[16] => z[36]) = 0; - (a[17] => z[36]) = 0; - (a[18] => z[36]) = 0; - (a[19] => z[36]) = 0; - (b[0] => z[36]) = 0; - (b[1] => z[36]) = 0; - (b[2] => z[36]) = 0; - (b[3] => z[36]) = 0; - (b[4] => z[36]) = 0; - (b[5] => z[36]) = 0; - (b[6] => z[36]) = 0; - (b[7] => z[36]) = 0; - (b[8] => z[36]) = 0; - (b[9] => z[36]) = 0; - (b[10] => z[36]) = 0; - (b[11] => z[36]) = 0; - (b[12] => z[36]) = 0; - (b[13] => z[36]) = 0; - (b[14] => z[36]) = 0; - (b[15] => z[36]) = 0; - (b[16] => z[36]) = 0; - (b[17] => z[36]) = 0; - (a[0] => z[37]) = 0; - (a[1] => z[37]) = 0; - (a[2] => z[37]) = 0; - (a[3] => z[37]) = 0; - (a[4] => z[37]) = 0; - (a[5] => z[37]) = 0; - (a[6] => z[37]) = 0; - (a[7] => z[37]) = 0; - (a[8] => z[37]) = 0; - (a[9] => z[37]) = 0; - (a[10] => z[37]) = 0; - (a[11] => z[37]) = 0; - (a[12] => z[37]) = 0; - (a[13] => z[37]) = 0; - (a[14] => z[37]) = 0; - (a[15] => z[37]) = 0; - (a[16] => z[37]) = 0; - (a[17] => z[37]) = 0; - (a[18] => z[37]) = 0; - (a[19] => z[37]) = 0; - (b[0] => z[37]) = 0; - (b[1] => z[37]) = 0; - (b[2] => z[37]) = 0; - (b[3] => z[37]) = 0; - (b[4] => z[37]) = 0; - (b[5] => z[37]) = 0; - (b[6] => z[37]) = 0; - (b[7] => z[37]) = 0; - (b[8] => z[37]) = 0; - (b[9] => z[37]) = 0; - (b[10] => z[37]) = 0; - (b[11] => z[37]) = 0; - (b[12] => z[37]) = 0; - (b[13] => z[37]) = 0; - (b[14] => z[37]) = 0; - (b[15] => z[37]) = 0; - (b[16] => z[37]) = 0; - (b[17] => z[37]) = 0; - (subtract => z[0]) = 0; - (subtract => z[1]) = 0; - (subtract => z[2]) = 0; - (subtract => z[3]) = 0; - (subtract => z[4]) = 0; - (subtract => z[5]) = 0; - (subtract => z[6]) = 0; - (subtract => z[7]) = 0; - (subtract => z[8]) = 0; - (subtract => z[9]) = 0; - (subtract => z[10]) = 0; - (subtract => z[11]) = 0; - (subtract => z[12]) = 0; - (subtract => z[13]) = 0; - (subtract => z[14]) = 0; - (subtract => z[15]) = 0; - (subtract => z[16]) = 0; - (subtract => z[17]) = 0; - (subtract => z[18]) = 0; - (subtract => z[19]) = 0; - (subtract => z[20]) = 0; - (subtract => z[21]) = 0; - (subtract => z[22]) = 0; - (subtract => z[23]) = 0; - (subtract => z[24]) = 0; - (subtract => z[25]) = 0; - (subtract => z[26]) = 0; - (subtract => z[27]) = 0; - (subtract => z[28]) = 0; - (subtract => z[29]) = 0; - (subtract => z[30]) = 0; - (subtract => z[31]) = 0; - (subtract => z[32]) = 0; - (subtract => z[33]) = 0; - (subtract => z[34]) = 0; - (subtract => z[35]) = 0; - (subtract => z[36]) = 0; - (subtract => z[37]) = 0; - (acc_fir[0] => z[0]) = 0; - (acc_fir[1] => z[0]) = 0; - (acc_fir[2] => z[0]) = 0; - (acc_fir[3] => z[0]) = 0; - (acc_fir[4] => z[0]) = 0; - (acc_fir[5] => z[0]) = 0; - (acc_fir[0] => z[1]) = 0; - (acc_fir[1] => z[1]) = 0; - (acc_fir[2] => z[1]) = 0; - (acc_fir[3] => z[1]) = 0; - (acc_fir[4] => z[1]) = 0; - (acc_fir[5] => z[1]) = 0; - (acc_fir[0] => z[2]) = 0; - (acc_fir[1] => z[2]) = 0; - (acc_fir[2] => z[2]) = 0; - (acc_fir[3] => z[2]) = 0; - (acc_fir[4] => z[2]) = 0; - (acc_fir[5] => z[2]) = 0; - (acc_fir[0] => z[3]) = 0; - (acc_fir[1] => z[3]) = 0; - (acc_fir[2] => z[3]) = 0; - (acc_fir[3] => z[3]) = 0; - (acc_fir[4] => z[3]) = 0; - (acc_fir[5] => z[3]) = 0; - (acc_fir[0] => z[4]) = 0; - (acc_fir[1] => z[4]) = 0; - (acc_fir[2] => z[4]) = 0; - (acc_fir[3] => z[4]) = 0; - (acc_fir[4] => z[4]) = 0; - (acc_fir[5] => z[4]) = 0; - (acc_fir[0] => z[5]) = 0; - (acc_fir[1] => z[5]) = 0; - (acc_fir[2] => z[5]) = 0; - (acc_fir[3] => z[5]) = 0; - (acc_fir[4] => z[5]) = 0; - (acc_fir[5] => z[5]) = 0; - (acc_fir[0] => z[6]) = 0; - (acc_fir[1] => z[6]) = 0; - (acc_fir[2] => z[6]) = 0; - (acc_fir[3] => z[6]) = 0; - (acc_fir[4] => z[6]) = 0; - (acc_fir[5] => z[6]) = 0; - (acc_fir[0] => z[7]) = 0; - (acc_fir[1] => z[7]) = 0; - (acc_fir[2] => z[7]) = 0; - (acc_fir[3] => z[7]) = 0; - (acc_fir[4] => z[7]) = 0; - (acc_fir[5] => z[7]) = 0; - (acc_fir[0] => z[8]) = 0; - (acc_fir[1] => z[8]) = 0; - (acc_fir[2] => z[8]) = 0; - (acc_fir[3] => z[8]) = 0; - (acc_fir[4] => z[8]) = 0; - (acc_fir[5] => z[8]) = 0; - (acc_fir[0] => z[9]) = 0; - (acc_fir[1] => z[9]) = 0; - (acc_fir[2] => z[9]) = 0; - (acc_fir[3] => z[9]) = 0; - (acc_fir[4] => z[9]) = 0; - (acc_fir[5] => z[9]) = 0; - (acc_fir[0] => z[10]) = 0; - (acc_fir[1] => z[10]) = 0; - (acc_fir[2] => z[10]) = 0; - (acc_fir[3] => z[10]) = 0; - (acc_fir[4] => z[10]) = 0; - (acc_fir[5] => z[10]) = 0; - (acc_fir[0] => z[11]) = 0; - (acc_fir[1] => z[11]) = 0; - (acc_fir[2] => z[11]) = 0; - (acc_fir[3] => z[11]) = 0; - (acc_fir[4] => z[11]) = 0; - (acc_fir[5] => z[11]) = 0; - (acc_fir[0] => z[12]) = 0; - (acc_fir[1] => z[12]) = 0; - (acc_fir[2] => z[12]) = 0; - (acc_fir[3] => z[12]) = 0; - (acc_fir[4] => z[12]) = 0; - (acc_fir[5] => z[12]) = 0; - (acc_fir[0] => z[13]) = 0; - (acc_fir[1] => z[13]) = 0; - (acc_fir[2] => z[13]) = 0; - (acc_fir[3] => z[13]) = 0; - (acc_fir[4] => z[13]) = 0; - (acc_fir[5] => z[13]) = 0; - (acc_fir[0] => z[14]) = 0; - (acc_fir[1] => z[14]) = 0; - (acc_fir[2] => z[14]) = 0; - (acc_fir[3] => z[14]) = 0; - (acc_fir[4] => z[14]) = 0; - (acc_fir[5] => z[14]) = 0; - (acc_fir[0] => z[15]) = 0; - (acc_fir[1] => z[15]) = 0; - (acc_fir[2] => z[15]) = 0; - (acc_fir[3] => z[15]) = 0; - (acc_fir[4] => z[15]) = 0; - (acc_fir[5] => z[15]) = 0; - (acc_fir[0] => z[16]) = 0; - (acc_fir[1] => z[16]) = 0; - (acc_fir[2] => z[16]) = 0; - (acc_fir[3] => z[16]) = 0; - (acc_fir[4] => z[16]) = 0; - (acc_fir[5] => z[16]) = 0; - (acc_fir[0] => z[17]) = 0; - (acc_fir[1] => z[17]) = 0; - (acc_fir[2] => z[17]) = 0; - (acc_fir[3] => z[17]) = 0; - (acc_fir[4] => z[17]) = 0; - (acc_fir[5] => z[17]) = 0; - (acc_fir[0] => z[18]) = 0; - (acc_fir[1] => z[18]) = 0; - (acc_fir[2] => z[18]) = 0; - (acc_fir[3] => z[18]) = 0; - (acc_fir[4] => z[18]) = 0; - (acc_fir[5] => z[18]) = 0; - (acc_fir[0] => z[19]) = 0; - (acc_fir[1] => z[19]) = 0; - (acc_fir[2] => z[19]) = 0; - (acc_fir[3] => z[19]) = 0; - (acc_fir[4] => z[19]) = 0; - (acc_fir[5] => z[19]) = 0; - (acc_fir[0] => z[20]) = 0; - (acc_fir[1] => z[20]) = 0; - (acc_fir[2] => z[20]) = 0; - (acc_fir[3] => z[20]) = 0; - (acc_fir[4] => z[20]) = 0; - (acc_fir[5] => z[20]) = 0; - (acc_fir[0] => z[21]) = 0; - (acc_fir[1] => z[21]) = 0; - (acc_fir[2] => z[21]) = 0; - (acc_fir[3] => z[21]) = 0; - (acc_fir[4] => z[21]) = 0; - (acc_fir[5] => z[21]) = 0; - (acc_fir[0] => z[22]) = 0; - (acc_fir[1] => z[22]) = 0; - (acc_fir[2] => z[22]) = 0; - (acc_fir[3] => z[22]) = 0; - (acc_fir[4] => z[22]) = 0; - (acc_fir[5] => z[22]) = 0; - (acc_fir[0] => z[23]) = 0; - (acc_fir[1] => z[23]) = 0; - (acc_fir[2] => z[23]) = 0; - (acc_fir[3] => z[23]) = 0; - (acc_fir[4] => z[23]) = 0; - (acc_fir[5] => z[23]) = 0; - (acc_fir[0] => z[24]) = 0; - (acc_fir[1] => z[24]) = 0; - (acc_fir[2] => z[24]) = 0; - (acc_fir[3] => z[24]) = 0; - (acc_fir[4] => z[24]) = 0; - (acc_fir[5] => z[24]) = 0; - (acc_fir[0] => z[25]) = 0; - (acc_fir[1] => z[25]) = 0; - (acc_fir[2] => z[25]) = 0; - (acc_fir[3] => z[25]) = 0; - (acc_fir[4] => z[25]) = 0; - (acc_fir[5] => z[25]) = 0; - (acc_fir[0] => z[26]) = 0; - (acc_fir[1] => z[26]) = 0; - (acc_fir[2] => z[26]) = 0; - (acc_fir[3] => z[26]) = 0; - (acc_fir[4] => z[26]) = 0; - (acc_fir[5] => z[26]) = 0; - (acc_fir[0] => z[27]) = 0; - (acc_fir[1] => z[27]) = 0; - (acc_fir[2] => z[27]) = 0; - (acc_fir[3] => z[27]) = 0; - (acc_fir[4] => z[27]) = 0; - (acc_fir[5] => z[27]) = 0; - (acc_fir[0] => z[28]) = 0; - (acc_fir[1] => z[28]) = 0; - (acc_fir[2] => z[28]) = 0; - (acc_fir[3] => z[28]) = 0; - (acc_fir[4] => z[28]) = 0; - (acc_fir[5] => z[28]) = 0; - (acc_fir[0] => z[29]) = 0; - (acc_fir[1] => z[29]) = 0; - (acc_fir[2] => z[29]) = 0; - (acc_fir[3] => z[29]) = 0; - (acc_fir[4] => z[29]) = 0; - (acc_fir[5] => z[29]) = 0; - (acc_fir[0] => z[30]) = 0; - (acc_fir[1] => z[30]) = 0; - (acc_fir[2] => z[30]) = 0; - (acc_fir[3] => z[30]) = 0; - (acc_fir[4] => z[30]) = 0; - (acc_fir[5] => z[30]) = 0; - (acc_fir[0] => z[31]) = 0; - (acc_fir[1] => z[31]) = 0; - (acc_fir[2] => z[31]) = 0; - (acc_fir[3] => z[31]) = 0; - (acc_fir[4] => z[31]) = 0; - (acc_fir[5] => z[31]) = 0; - (acc_fir[0] => z[32]) = 0; - (acc_fir[1] => z[32]) = 0; - (acc_fir[2] => z[32]) = 0; - (acc_fir[3] => z[32]) = 0; - (acc_fir[4] => z[32]) = 0; - (acc_fir[5] => z[32]) = 0; - (acc_fir[0] => z[33]) = 0; - (acc_fir[1] => z[33]) = 0; - (acc_fir[2] => z[33]) = 0; - (acc_fir[3] => z[33]) = 0; - (acc_fir[4] => z[33]) = 0; - (acc_fir[5] => z[33]) = 0; - (acc_fir[0] => z[34]) = 0; - (acc_fir[1] => z[34]) = 0; - (acc_fir[2] => z[34]) = 0; - (acc_fir[3] => z[34]) = 0; - (acc_fir[4] => z[34]) = 0; - (acc_fir[5] => z[34]) = 0; - (acc_fir[0] => z[35]) = 0; - (acc_fir[1] => z[35]) = 0; - (acc_fir[2] => z[35]) = 0; - (acc_fir[3] => z[35]) = 0; - (acc_fir[4] => z[35]) = 0; - (acc_fir[5] => z[35]) = 0; - (acc_fir[0] => z[36]) = 0; - (acc_fir[1] => z[36]) = 0; - (acc_fir[2] => z[36]) = 0; - (acc_fir[3] => z[36]) = 0; - (acc_fir[4] => z[36]) = 0; - (acc_fir[5] => z[36]) = 0; - (acc_fir[0] => z[37]) = 0; - (acc_fir[1] => z[37]) = 0; - (acc_fir[2] => z[37]) = 0; - (acc_fir[3] => z[37]) = 0; - (acc_fir[4] => z[37]) = 0; - (acc_fir[5] => z[37]) = 0; - endspecify -`endif - -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, - 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 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]; - - QL_DSP2 #( - .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) - ) dsp ( - .a(a), - .b(b), - .dly_b(), - .z(z), - - .f_mode(f_mode), - - .feedback(feedback), - .acc_fir(acc_fir), - .load_acc(load_acc), - - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), - + .output_select(output_select), + .z(z), + .clk(clk), - .reset(reset), + .reset(reset), + .acc_reset(1'b0), - .output_select(output_select), // unregistered output: ACCin (2, 3) - .saturate_enable(saturate_enable), - .shift_right(shift_right), - .round(round), - .subtract(subtract), - .register_inputs(register_inputs) // registered inputs - ); + .a_cin(), + .b_cin(), + .z_cin(), -`ifdef SDF_SIM - specify - (posedge clk => (z +: a)) = 0; - (posedge clk => (z +: b)) = 0; - $setuphold(posedge clk, a, 0, 0); - $setuphold(posedge clk, b, 0, 0); - $setuphold(posedge clk, feedback, 0, 0); - $setuphold(posedge clk, load_acc, 0, 0); - $setuphold(posedge clk, subtract, 0, 0); - $setuphold(posedge clk, acc_fir, 0, 0); - endspecify -`endif + .z_cout(), + .a_cout(), + .b_cout() + ); endmodule -module QL_DSP2_MULTADD_REGOUT ( - input wire [19:0] a, - input wire [17:0] b, - output wire [37:0] z, +module QL_DSPV2_MULTADD_REGOUT ( + input wire [31:0] a, + input wire [17:0] b, + output wire [49:0] z, - (* clkbuf_sink *) - input wire clk, - input wire reset, + (* 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 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 + input wire [ 2:0] feedback, + input wire [ 2:0] output_select ); - parameter [79:0] MODE_BITS = 80'd0; + parameter [67:0] MODE_BITS = 68'h00000000000000000; - 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), - .dly_b(), - .z(z), - - .f_mode(f_mode), + localparam [31:0] COEFF_0 = MODE_BITS[31:0]; + localparam [5:0] ACC_FIR = MODE_BITS[37:32]; + localparam [2:0] ROUND = MODE_BITS[40:38]; + localparam [4:0] ZC_SHIFT = MODE_BITS[45:41]; + localparam [4:0] ZREG_SHIFT= MODE_BITS[50:46]; + localparam [5:0] SHIFT_REG = MODE_BITS[56:51]; + localparam SATURATE = MODE_BITS[57]; + localparam SUBTRACT = MODE_BITS[58]; + localparam PRE_ADD = MODE_BITS[59]; + localparam A_SEL = MODE_BITS[60]; + localparam A_REG = MODE_BITS[61]; + localparam B_SEL = MODE_BITS[62]; + localparam B_REG = MODE_BITS[63]; + localparam C_REG = MODE_BITS[64]; + localparam BC_REG = MODE_BITS[65]; + localparam M_REG = MODE_BITS[66]; + localparam FRAC_MODE = MODE_BITS[67]; + QL_DSPV2 #( + .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .c(18'h0), + .load_acc(1'b0), .feedback(feedback), - .acc_fir(acc_fir), - .load_acc(load_acc), - - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), - + .output_select(output_select), + .z(z), + .clk(clk), - .reset(reset), + .reset(reset), + .acc_reset(1'b0), - .output_select(output_select), // registered output: ACCin (6, 7) - .saturate_enable(saturate_enable), - .shift_right(shift_right), - .round(round), - .subtract(subtract), - .register_inputs(register_inputs) // unregistered inputs - ); - -`ifdef SDF_SIM - specify - (posedge clk => (z +: a)) = 0; - (posedge clk => (z +: b)) = 0; - $setuphold(posedge clk, a, 0, 0); - $setuphold(posedge clk, b, 0, 0); - $setuphold(posedge clk, feedback, 0, 0); - $setuphold(posedge clk, load_acc, 0, 0); - $setuphold(posedge clk, subtract, 0, 0); - $setuphold(posedge clk, acc_fir, 0, 0); - endspecify -`endif + .a_cin(), + .b_cin(), + .z_cin(), + .z_cout(), + .a_cout(), + .b_cout() + ); + endmodule -module QL_DSP2_MULTADD_REGIN_REGOUT ( - input wire [19:0] a, - input wire [17:0] b, - output wire [37:0] z, +module QL_DSPV2_MULTADD_REGIN_REGOUT ( + input wire [31:0] a, + input wire [17:0] b, + output wire [49:0] z, - (* clkbuf_sink *) - input wire clk, - input wire reset, + (* 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 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 + input wire [ 2:0] feedback, + input wire [ 2:0] output_select ); - parameter [79:0] MODE_BITS = 80'd0; + parameter [67:0] MODE_BITS = 68'h0A000000000000000; - 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), - .dly_b(), - .z(z), - - .f_mode(f_mode), + localparam [31:0] COEFF_0 = MODE_BITS[31:0]; + localparam [5:0] ACC_FIR = MODE_BITS[37:32]; + localparam [2:0] ROUND = MODE_BITS[40:38]; + localparam [4:0] ZC_SHIFT = MODE_BITS[45:41]; + localparam [4:0] ZREG_SHIFT= MODE_BITS[50:46]; + localparam [5:0] SHIFT_REG = MODE_BITS[56:51]; + localparam SATURATE = MODE_BITS[57]; + localparam SUBTRACT = MODE_BITS[58]; + localparam PRE_ADD = MODE_BITS[59]; + localparam A_SEL = MODE_BITS[60]; + localparam A_REG = MODE_BITS[61]; + localparam B_SEL = MODE_BITS[62]; + localparam B_REG = MODE_BITS[63]; + localparam C_REG = MODE_BITS[64]; + localparam BC_REG = MODE_BITS[65]; + localparam M_REG = MODE_BITS[66]; + localparam FRAC_MODE = MODE_BITS[67]; + QL_DSPV2 #( + .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .c(18'h0), + .load_acc(1'b0), .feedback(feedback), - .acc_fir(acc_fir), - .load_acc(load_acc), - - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), - + .output_select(output_select), + .z(z), + .clk(clk), - .reset(reset), + .reset(reset), + .acc_reset(1'b0), - .output_select(output_select), // registered output: ACCin (6, 7) - .saturate_enable(saturate_enable), - .shift_right(shift_right), - .round(round), - .subtract(subtract), - .register_inputs(register_inputs) // registered inputs - ); - -`ifdef SDF_SIM - specify - (posedge clk => (z +: a)) = 0; - (posedge clk => (z +: b)) = 0; - $setuphold(posedge clk, a, 0, 0); - $setuphold(posedge clk, b, 0, 0); - $setuphold(posedge clk, feedback, 0, 0); - $setuphold(posedge clk, load_acc, 0, 0); - $setuphold(posedge clk, subtract, 0, 0); - $setuphold(posedge clk, acc_fir, 0, 0); - endspecify -`endif + .a_cin(), + .b_cin(), + .z_cin(), + .z_cout(), + .a_cout(), + .b_cout() + ); + endmodule -module QL_DSP2_MULTACC ( - input wire [19:0] a, - input wire [17:0] b, - output wire [37:0] z, +module QL_DSPV2_MULTACC ( + input wire [31:0] a, + input wire [17:0] b, + output wire [49:0] z, - (* clkbuf_sink *) - input wire clk, - input wire reset, - - input wire load_acc, - 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 saturate_enable, - input wire [ 5:0] shift_right, - input wire round, - input wire subtract, - input wire register_inputs + (* clkbuf_sink *) + input wire clk, + input wire reset, + input wire acc_reset, + input wire load_acc, + input wire [ 2:0] feedback, + input wire [ 2:0] output_select ); - parameter [79:0] MODE_BITS = 80'd0; + parameter [67:0] MODE_BITS = 68'h00000000000000000; - 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), - .acc_fir(6'b0), - .z(z), - .dly_b(), - - .f_mode(f_mode), + localparam [31:0] COEFF_0 = MODE_BITS[31:0]; + localparam [5:0] ACC_FIR = MODE_BITS[37:32]; + localparam [2:0] ROUND = MODE_BITS[40:38]; + localparam [4:0] ZC_SHIFT = MODE_BITS[45:41]; + localparam [4:0] ZREG_SHIFT= MODE_BITS[50:46]; + localparam [5:0] SHIFT_REG = MODE_BITS[56:51]; + localparam SATURATE = MODE_BITS[57]; + localparam SUBTRACT = MODE_BITS[58]; + localparam PRE_ADD = MODE_BITS[59]; + localparam A_SEL = MODE_BITS[60]; + localparam A_REG = MODE_BITS[61]; + localparam B_SEL = MODE_BITS[62]; + localparam B_REG = MODE_BITS[63]; + localparam C_REG = MODE_BITS[64]; + localparam BC_REG = MODE_BITS[65]; + localparam M_REG = MODE_BITS[66]; + localparam FRAC_MODE = MODE_BITS[67]; + QL_DSPV2 #( + .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .c(18'h0), + .load_acc(load_acc), .feedback(feedback), - .load_acc(load_acc), - - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), - + .output_select(output_select), + .z(z), + .clk(clk), - .reset(reset), + .reset(reset), + .acc_reset(acc_reset), - .output_select(output_select), // unregistered output: ACCout (1) - .saturate_enable(saturate_enable), - .shift_right(shift_right), - .round(round), - .subtract(subtract), - .register_inputs(register_inputs) // unregistered inputs - ); - -`ifdef SDF_SIM - specify - (posedge clk => (z +: a)) = 0; - (posedge clk => (z +: b)) = 0; - $setuphold(posedge clk, a, 0, 0); - $setuphold(posedge clk, b, 0, 0); - $setuphold(posedge clk, feedback, 0, 0); - $setuphold(posedge clk, load_acc, 0, 0); - $setuphold(posedge clk, subtract, 0, 0); - endspecify -`endif + .a_cin(), + .b_cin(), + .z_cin(), + .z_cout(), + .a_cout(), + .b_cout() + ); + endmodule -module QL_DSP2_MULTACC_REGIN ( - input wire [19:0] a, - input wire [17:0] b, - output wire [37:0] z, +module QL_DSPV2_MULTACC_REGIN ( + input wire [31:0] a, + input wire [17:0] b, + output wire [49: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 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 + (* clkbuf_sink *) + input wire clk, + input wire reset, + input wire acc_reset, + input wire load_acc, + input wire [ 2:0] feedback, + input wire [ 2:0] output_select ); - parameter [79:0] MODE_BITS = 80'd0; + parameter [67:0] MODE_BITS = 68'h04000000000000000; - 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), - .acc_fir(6'b0), - .z(z), - .dly_b(), - - .f_mode(f_mode), + localparam [31:0] COEFF_0 = MODE_BITS[31:0]; + localparam [5:0] ACC_FIR = MODE_BITS[37:32]; + localparam [2:0] ROUND = MODE_BITS[40:38]; + localparam [4:0] ZC_SHIFT = MODE_BITS[45:41]; + localparam [4:0] ZREG_SHIFT= MODE_BITS[50:46]; + localparam [5:0] SHIFT_REG = MODE_BITS[56:51]; + localparam SATURATE = MODE_BITS[57]; + localparam SUBTRACT = MODE_BITS[58]; + localparam PRE_ADD = MODE_BITS[59]; + localparam A_SEL = MODE_BITS[60]; + localparam A_REG = MODE_BITS[61]; + localparam B_SEL = MODE_BITS[62]; + localparam B_REG = MODE_BITS[63]; + localparam C_REG = MODE_BITS[64]; + localparam BC_REG = MODE_BITS[65]; + localparam M_REG = MODE_BITS[66]; + localparam FRAC_MODE = MODE_BITS[67]; + QL_DSPV2 #( + .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .c(18'h0), + .load_acc(load_acc), .feedback(feedback), - .load_acc(load_acc), - - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), - + .output_select(output_select), + .z(z), + .clk(clk), - .reset(reset), + .reset(reset), + .acc_reset(acc_reset), - .output_select(output_select), // unregistered output: ACCout (1) - .saturate_enable(saturate_enable), - .shift_right(shift_right), - .round(round), - .subtract(subtract), - .register_inputs(register_inputs) // registered inputs - ); - -`ifdef SDF_SIM - specify - (posedge clk => (z +: a)) = 0; - (posedge clk => (z +: b)) = 0; - $setuphold(posedge clk, a, 0, 0); - $setuphold(posedge clk, b, 0, 0); - $setuphold(posedge clk, feedback, 0, 0); - $setuphold(posedge clk, load_acc, 0, 0); - $setuphold(posedge clk, subtract, 0, 0); - endspecify -`endif + .a_cin(), + .b_cin(), + .z_cin(), + .z_cout(), + .a_cout(), + .b_cout() + ); + endmodule -module QL_DSP2_MULTACC_REGOUT ( - input wire [19:0] a, - input wire [17:0] b, - output wire [37:0] z, +module QL_DSPV2_MULTACC_REGOUT ( + input wire [31:0] a, + input wire [17:0] b, + output wire [49: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 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 + (* clkbuf_sink *) + input wire clk, + input wire reset, + input wire acc_reset, + input wire load_acc, + input wire [ 2:0] feedback, + input wire [ 2:0] output_select ); - parameter [79:0] MODE_BITS = 80'd0; + parameter [67:0] MODE_BITS = 68'h00000000000000000; - 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), - .acc_fir(6'b0), - .z(z), - .dly_b(), - - .f_mode(f_mode), + localparam [31:0] COEFF_0 = MODE_BITS[31:0]; + localparam [5:0] ACC_FIR = MODE_BITS[37:32]; + localparam [2:0] ROUND = MODE_BITS[40:38]; + localparam [4:0] ZC_SHIFT = MODE_BITS[45:41]; + localparam [4:0] ZREG_SHIFT= MODE_BITS[50:46]; + localparam [5:0] SHIFT_REG = MODE_BITS[56:51]; + localparam SATURATE = MODE_BITS[57]; + localparam SUBTRACT = MODE_BITS[58]; + localparam PRE_ADD = MODE_BITS[59]; + localparam A_SEL = MODE_BITS[60]; + localparam A_REG = MODE_BITS[61]; + localparam B_SEL = MODE_BITS[62]; + localparam B_REG = MODE_BITS[63]; + localparam C_REG = MODE_BITS[64]; + localparam BC_REG = MODE_BITS[65]; + localparam M_REG = MODE_BITS[66]; + localparam FRAC_MODE = MODE_BITS[67]; + QL_DSPV2 #( + .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .c(18'h0), + .load_acc(load_acc), .feedback(feedback), - .load_acc(load_acc), - - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), - + .output_select(output_select), + .z(z), + .clk(clk), - .reset(reset), + .reset(reset), + .acc_reset(acc_reset), - .output_select(output_select), // registered output: ACCout (5) - .saturate_enable(saturate_enable), - .shift_right(shift_right), - .round(round), - .subtract(subtract), - .register_inputs(register_inputs) // unregistered inputs - ); - -`ifdef SDF_SIM - specify - (posedge clk => (z +: a)) = 0; - (posedge clk => (z +: b)) = 0; - $setuphold(posedge clk, a, 0, 0); - $setuphold(posedge clk, b, 0, 0); - $setuphold(posedge clk, feedback, 0, 0); - $setuphold(posedge clk, load_acc, 0, 0); - $setuphold(posedge clk, subtract, 0, 0); - endspecify -`endif + .a_cin(), + .b_cin(), + .z_cin(), + .z_cout(), + .a_cout(), + .b_cout() + ); + endmodule -module QL_DSP2_MULTACC_REGIN_REGOUT ( - input wire [19:0] a, - input wire [17:0] b, - output wire [37:0] z, +module QL_DSPV2_MULTACC_REGIN_REGOUT ( + input wire [31:0] a, + input wire [17:0] b, + output wire [49: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 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 + (* clkbuf_sink *) + input wire clk, + input wire reset, + input wire acc_reset, + input wire load_acc, + input wire [ 2:0] feedback, + input wire [ 2:0] output_select ); - parameter [79:0] MODE_BITS = 80'd0; + parameter [67:0] MODE_BITS = 68'h04000000000000000; - 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), - .acc_fir(6'b0), - .z(z), - .dly_b(), - - .f_mode(f_mode), + localparam [31:0] COEFF_0 = MODE_BITS[31:0]; + localparam [5:0] ACC_FIR = MODE_BITS[37:32]; + localparam [2:0] ROUND = MODE_BITS[40:38]; + localparam [4:0] ZC_SHIFT = MODE_BITS[45:41]; + localparam [4:0] ZREG_SHIFT= MODE_BITS[50:46]; + localparam [5:0] SHIFT_REG = MODE_BITS[56:51]; + localparam SATURATE = MODE_BITS[57]; + localparam SUBTRACT = MODE_BITS[58]; + localparam PRE_ADD = MODE_BITS[59]; + localparam A_SEL = MODE_BITS[60]; + localparam A_REG = MODE_BITS[61]; + localparam B_SEL = MODE_BITS[62]; + localparam B_REG = MODE_BITS[63]; + localparam C_REG = MODE_BITS[64]; + localparam BC_REG = MODE_BITS[65]; + localparam M_REG = MODE_BITS[66]; + localparam FRAC_MODE = MODE_BITS[67]; + QL_DSPV2 #( + .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .c(18'h0), + .load_acc(load_acc), .feedback(feedback), - .load_acc(load_acc), - - .unsigned_a(unsigned_a), - .unsigned_b(unsigned_b), - + .output_select(output_select), + .z(z), + .clk(clk), - .reset(reset), + .reset(reset), + .acc_reset(acc_reset), - .output_select(output_select), // registered output: ACCout (5) - .saturate_enable(saturate_enable), - .shift_right(shift_right), - .round(round), - .subtract(subtract), - .register_inputs(register_inputs) // registered inputs - ); - -`ifdef SDF_SIM - specify - (posedge clk => (z +: a)) = 0; - (posedge clk => (z +: b)) = 0; - $setuphold(posedge clk, a, 0, 0); - $setuphold(posedge clk, b, 0, 0); - $setuphold(posedge clk, feedback, 0, 0); - $setuphold(posedge clk, load_acc, 0, 0); - $setuphold(posedge clk, subtract, 0, 0); - endspecify -`endif + .a_cin(), + .b_cin(), + .z_cin(), + .z_cout(), + .a_cout(), + .b_cout() + ); + 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, +module dspv2_32x18x64_cfg_ports ( + input wire [31:0] a_i, + input wire [17:0] b_i, + input wire [17:0] c_i, + output wire [49:0] z_o, - (* clkbuf_sink *) - input wire clock_i, - input wire reset_i, + (* clkbuf_sink *) + input wire clock_i, + input wire reset_i, + input wire acc_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] feedback_i, + input wire load_acc_i, + input wire [ 2:0] output_select_i, + + input wire [31:0] a_cin_i, + input wire [17:0] b_cin_i, + input wire [49:0] z_cin_i, + + output wire [31:0] a_cout_o, + output wire [17:0] b_cout_o, + output wire [49:0] z_cout_o - 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; + parameter [31:0] COEFF_0 = 32'h0; + parameter [5:0] ACC_FIR = 6'h0; + parameter [2:0] ROUND = 3'h0; + parameter [4:0] ZC_SHIFT = 5'h0; + parameter [4:0] ZREG_SHIFT = 5'h0; + parameter [5:0] SHIFT_REG = 6'h0; + parameter SATURATE = 1'b0; + parameter SUBTRACT = 1'b0; + parameter PRE_ADD = 1'b0; + parameter A_SEL = 1'b0; + parameter A_REG = 1'b0; + parameter B_SEL = 1'b0; + parameter B_REG = 1'b0; + parameter C_REG = 1'b0; + parameter BC_REG = 1'b0; + parameter M_REG = 1'b0; + parameter FRAC_MODE = 1'b0; // 32x18x64 DSP - 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), + QL_DSPV2 #( + .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + ) dsp ( + .a(a_i), + .b(b_i), + .c(c_i), + .load_acc(load_acc_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) - ); + .z(z_o), + + .clk(clock_i), + .reset(reset_i), + .acc_reset(acc_reset_i), + + .a_cin(a_cin_i), + .b_cin(b_cin_i), + .z_cin(z_cin_i), + + .z_cout(a_cout_o), + .a_cout(b_cout_o), + .b_cout(z_cout_o) + ); + 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, +module dspv2_16x9x32_cfg_ports ( + input wire [15:0] a_i, + input wire [8:0] b_i, + input wire [9:0] c_i, + output wire [24:0] z_o, - (* clkbuf_sink *) - input wire clock_i, - input wire reset_i, + (* clkbuf_sink *) + input wire clock_i, + input wire reset_i, + input wire acc_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] feedback_i, + input wire load_acc_i, + input wire [ 2:0] output_select_i, + + input wire [15:0] a_cin_i, + input wire [8:0] b_cin_i, + input wire [24:0] z_cin_i, + + output wire [15:0] a_cout_o, + output wire [8:0] b_cout_o, + output wire [24:0] z_cout_o - 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; + parameter [15:0] COEFF_0 = 16'h0; + parameter [5:0] ACC_FIR = 6'h0; + parameter [2:0] ROUND = 3'h0; + parameter [4:0] ZC_SHIFT = 5'h0; + parameter [4:0] ZREG_SHIFT = 5'h0; + parameter [5:0] SHIFT_REG = 6'h0; + parameter SATURATE = 1'b0; + parameter SUBTRACT = 1'b0; + parameter PRE_ADD = 1'b0; + parameter A_SEL = 1'b0; + parameter A_REG = 1'b0; + parameter B_SEL = 1'b0; + parameter B_REG = 1'b0; + parameter C_REG = 1'b0; + parameter BC_REG = 1'b0; + parameter M_REG = 1'b0; + parameter FRAC_MODE = 1'b1; // 16x9x32 DSP - 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), + QL_DSPV2 #( + .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,16'h0,COEFF_0}) + ) dsp ( + .a(a_i), + .b(b_i), + .c(c_i), + .load_acc(load_acc_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) - ); + .z(z_o), + + .clk(clock_i), + .reset(reset_i), + .acc_reset(acc_reset_i), + + .a_cin(a_cin_i), + .b_cin(b_cin_i), + .z_cin(z_cin_i), + + .z_cout(a_cout_o), + .a_cout(b_cout_o), + .b_cout(z_cout_o) + ); + endmodule -module dsp_t1_sim_cfg_ports # ( - parameter NBITS_ACC = 64, - parameter NBITS_A = 20, - parameter NBITS_B = 18, - parameter NBITS_Z = 38 + +module dspv2_sim_cfg_ports # ( + parameter NBITS_ACC = 64, + parameter NBITS_A = 32, + parameter NBITS_BC = 18, + parameter NBITS_Z = 50 )( - 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, - + // active/fabric ports + input wire clock_i, + input wire s_reset, + input wire [NBITS_A-1:0] a_i, + input wire [NBITS_BC-1:0] b_i, + input wire [NBITS_BC-1:0] c_i, + input wire [2:0] feedback_i, + input wire [2:0] output_select_i, + input wire load_acc_i, + input wire rst_acc_i, + output wire [NBITS_Z-1:0] z_o, + + // cascade ports (connect to dedicated cascade routing) + input wire [NBITS_A-1:0] a_cin_i, + input wire [NBITS_BC-1:0] b_cin_i, + input wire [NBITS_Z-1:0] z_cin_i, + output wire [NBITS_Z-1:0] z_cout_o, + output wire [NBITS_A-1:0] a_cout_o, + output wire [NBITS_BC-1:0] b_cout_o, + + // configuration ports (tie-offs) + input wire [NBITS_A-1:0] coeff_i, + input wire [5:0] acc_fir_i, + input wire [2:0] round_i, + input wire [4:0] zc_shift_i, + input wire [4:0] zreg_shift_i, + input wire [5:0] shift_right_i, 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 + input wire pre_add_sel_i, + input wire a_sel_i, + input wire a_reg_i, + input wire b_sel_i, + input wire b_reg_i, + input wire c_reg_i, + input wire bc_reg_i, + input wire m_reg_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. + // Input registers + reg [NBITS_A-1:0] r_a; + reg [NBITS_BC-1:0] r_b; + reg [NBITS_BC-1:0] r_c; + reg [NBITS_ACC-1:0] acc; + + wire [NBITS_A-1:0] a_acin_dat; + wire [NBITS_BC-1:0] b_bcin_dat; + + wire [NBITS_A-1:0] a; + wire [NBITS_BC-1:0] b; + wire [NBITS_BC-1:0] c; + + wire [NBITS_BC:0] preadd_raw; + + reg [NBITS_BC-1:0] preadd_sat; + reg [NBITS_BC-1:0] preadd_sat_r; + wire [NBITS_BC-1:0] preadd; - // 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_c <= 0; + end + + assign a_acin_dat = (a_sel_i)? a_cin_i: a_i; + assign b_bcin_dat = (b_sel_i)? b_cin_i: b_i; - 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; + always @(posedge clock_i or posedge s_reset) begin + if (s_reset) begin + r_a <= 0; + r_b <= 0; + r_c <= 0; + end else begin + r_a <= a_acin_dat; + r_b <= b_bcin_dat; + r_c <= c_i; + end + end + // Registered / non-registered input path select + assign a = (a_reg_i) ? r_a : a_acin_dat; + assign b = (b_reg_i) ? r_b : b_bcin_dat; + assign c = (c_reg_i) ? r_c : c_i; + + assign preadd_raw = b + c; + + always @(*) begin + if (!b[(NBITS_BC-1)] && !c[(NBITS_BC-1)]) begin // pos+pos + if (preadd_raw[(NBITS_BC-1)]) begin + preadd_sat = {1'b0, {(NBITS_BC-1){1'b1}}}; // max pos # + end else begin + preadd_sat = preadd_raw[(NBITS_BC-1):0]; + end 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; - + if (b[(NBITS_BC-1)] && c[(NBITS_BC-1)]) begin // neg+neg + if (!preadd_raw[(NBITS_BC-1)]) begin + preadd_sat = {1'b1, {(NBITS_BC-1){1'b0}}}; // max neg # + end else begin + preadd_sat = preadd_raw[(NBITS_BC-1):0]; + end + end else begin // pos+neg or neg+pos + preadd_sat = preadd_raw[(NBITS_BC-1):0]; + end end end + + always @(posedge clock_i or posedge s_reset) begin + if (s_reset) begin + preadd_sat_r <= 0; + end else begin + preadd_sat_r <= preadd_sat; + end + end + + assign preadd = (bc_reg_i)? preadd_sat_r : preadd_sat; - // 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; + // Multiplier + wire [NBITS_A-1:0] mult_a; + wire [NBITS_BC-1:0] mult_b; + wire mult_sgn_a; + wire [NBITS_A-1:0] mult_mag_a; + wire mult_sgn_b; + wire [NBITS_BC-1:0] mult_mag_b; + + wire [NBITS_A+NBITS_BC-1:0] mult_mag; + wire mult_sgn; + wire [NBITS_A+NBITS_BC-1:0] mult; + wire [NBITS_ACC-1:0] mult_xtnd; + + reg [NBITS_ACC-1:0] mult_xtnd_r; + wire [NBITS_ACC-1:0] mult_xtnd_sel; + wire [NBITS_ACC-1:0] mult_xtnd_sub; + wire [NBITS_ACC-1:0] add_a; + wire [NBITS_ACC-1:0] add_b; + wire [NBITS_ACC-1:0] add_o; + wire [NBITS_ACC-1:0] acc_fir_int; + + wire [NBITS_ACC-1:0] acc_out; + + wire [NBITS_ACC-1:0] zcin_rshift; + wire [NBITS_ACC-1:0] zcin_xtnd; + wire [NBITS_ACC-1:0] zreg_rshift; + + // Output signals + wire [NBITS_Z-1:0] z0; + reg [NBITS_Z-1:0] z1; + wire [NBITS_Z-1:0] z2; + + assign mult_a = (feedback_i == 3'h0) ? a : + (feedback_i == 3'h1) ? a : + (feedback_i == 3'h2) ? a : + (feedback_i == 3'h3) ? a : + (feedback_i == 3'h4) ? a : + (feedback_i == 3'h5) ? a : + (feedback_i == 3'h6) ? acc[NBITS_A-1:0]: + coeff_i; // if feedback_i == 3'h7 - // 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; + assign mult_b = (pre_add_sel_i) ? preadd : b; - // 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 + assign mult_sgn_a = mult_a[NBITS_A-1]; + assign mult_mag_a = (mult_sgn_a) ? (~mult_a + 1) : mult_a; + assign mult_sgn_b = mult_b[NBITS_BC-1]; + assign mult_mag_b = (mult_sgn_b) ? (~mult_b + 1) : mult_b; - wire [NBITS_B-1:0] mult_b = (feedback == 2'h2) ? {NBITS_B{1'b0}} : b; + assign mult_mag = mult_mag_a * mult_mag_b; + assign mult_sgn = (mult_sgn_a ^ mult_sgn_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]}; + assign mult = (mult_sgn)? (~mult_mag + 1) : mult_mag; + // Sign extension + assign mult_xtnd = {{(NBITS_ACC-NBITS_A-NBITS_BC){mult[NBITS_A+NBITS_BC-1]}}, mult[NBITS_A+NBITS_BC-1:0]}; + + always @(posedge clock_i or posedge s_reset) begin + if (s_reset) begin + mult_xtnd_r <= 0; + end else begin + mult_xtnd_r <= mult_xtnd; + end + end + + assign mult_xtnd_sel = m_reg_i ? mult_xtnd_r : mult_xtnd; + // 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} ; + assign mult_xtnd_sub = subtract_i ? (~mult_xtnd_sel + 1) : mult_xtnd_sel; + assign add_a = (feedback_i[2:0] == 2) ? {a,b} : mult_xtnd_sub; + + assign acc_fir_int = a <<< acc_fir_i; + + assign zcin_rshift = z_cin_i >>> zc_shift_i; + assign zcin_xtnd = {{(NBITS_ACC-NBITS_Z){z_cin_i[NBITS_Z-1]}}, z_cin_i}; + + assign zreg_rshift = z1 >>> zreg_shift_i; + + assign add_b = (feedback_i == 3'h0) ? acc : + (feedback_i == 3'h1) ? zcin_rshift : + (feedback_i == 3'h2) ? zcin_xtnd : + (feedback_i == 3'h3) ? zcin_xtnd : + (feedback_i == 3'h4) ? z1 : + (feedback_i == 3'h5) ? zreg_rshift : + acc_fir_int; + + assign add_o = add_a + add_b; - 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); + // Accumulator + initial acc <= 0; - wire [NBITS_ACC-1:0] add_o = add_a + add_b; + always @(posedge clock_i or posedge s_reset) + if (s_reset) + acc <= 'h0; + else begin + if (rst_acc_i) + acc <= 'h0; + else if (load_acc_i) + acc <= add_o; + else + acc <= acc; + end - // Accumulator - initial acc <= 0; + // Adder/accumulator output selection + assign acc_out = (output_select_i[1]) ? add_o : acc; - 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 + // Round, shift, saturate + wire a_sign; + wire [NBITS_ACC-1:0] onehalf; + wire [NBITS_ACC-1:0] int_mask; + wire [NBITS_ACC-1:0] frac_mask; + wire [NBITS_ACC-1:0] a_frac; + wire [NBITS_ACC-1:0] a_int; + + reg [NBITS_ACC-1:0] acc_rnd; + wire [NBITS_ACC-1:0] acc_shr; + wire [NBITS_ACC-1:0] acc_sat_s; + wire [NBITS_ACC-1:0] acc_sat; + + assign a_sign = acc_out[(NBITS_ACC-1)]; + assign onehalf = (shift_right_i == 6'b0) ? {NBITS_ACC{1'b0}} : ({{(NBITS_ACC-1){1'b0}},1'b1} << (shift_right_i-1)); + assign int_mask = ({NBITS_ACC{1'b1}} << shift_right_i); + assign frac_mask = ~int_mask; + assign a_frac = acc_out & frac_mask; + assign a_int = acc_out >>> shift_right_i; + + always @(*) begin + case(round_i) + 3'b000 : // no rounding + acc_rnd = acc_out; - // Adder/accumulator output selection - wire [NBITS_ACC-1:0] acc_out = (output_select_i[1]) ? add_o : acc; + 3'b001 : // round half up, asymmetrical + // add 1/2 + acc_rnd = acc_out + onehalf; - // 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; + 3'b010 : // round half up, symmetrical + // if a is neg and a_frac = 1/2, do nothing, else add 1/2 + if ((a_sign == 1'b1) && (a_frac == onehalf)) + acc_rnd = acc_out; + else + acc_rnd = acc_out + onehalf; - wire [NBITS_ACC-1:0] acc_shr = (unsigned_mode) ? (acc_rnd >> shift_right_i) : - (acc_rnd >>> shift_right_i); + 3'b011 : // round half down, symmetrical + // if a is pos and a_frac = 1/2, do nothing, else add 1/2 + if ((a_sign == 1'b0) && (a_frac == onehalf)) + acc_rnd = acc_out; + else + acc_rnd = acc_out + onehalf; - 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]}}; + 3'b100 : // round half even + // if a is even and a_frac = 1/2, do nothing, else add 1/2 + if ((a_int[0] == 1'b0) && (a_frac == onehalf)) + acc_rnd = acc_out; + else + acc_rnd = acc_out + onehalf; - 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]}}}}; + 3'b100 : // round half odd + // if a is odd and a_frac = 1/2, do nothing, else add 1/2 + if ((a_int[0] == 1'b1) && (a_frac == onehalf)) + acc_rnd = acc_out; + else + acc_rnd = acc_out + onehalf; - wire [NBITS_ACC-1:0] acc_sat = (sat) ? ((unsigned_mode) ? acc_sat_u : acc_sat_s) : acc_shr; + default : // no rounding + acc_rnd = acc_out; - // Output signals - wire [NBITS_Z-1:0] z0; - reg [NBITS_Z-1:0] z1; - wire [NBITS_Z-1:0] z2; + endcase + end + + assign acc_shr = (acc_rnd >>> shift_right_i); - assign z0 = mult_xtnd[NBITS_Z-1:0]; - assign z2 = acc_sat[NBITS_Z-1:0]; + assign 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]}}}}; - initial z1 <= 0; + assign acc_sat = (saturate_enable_i)? acc_sat_s : acc_shr; - always @(posedge clock_i or posedge s_reset) - if (s_reset) - z1 <= 0; - else begin - z1 <= (output_select_i == 3'b100) ? z0 : z2; - end + assign z0 = mult_xtnd_sel[NBITS_Z-1:0]; + assign z2 = acc_sat[NBITS_Z-1:0]; - // 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 + initial z1 <= 0; - // B input delayed passthrough - initial dly_b_o <= 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 - always @(posedge clock_i or posedge s_reset) - if (s_reset) - dly_b_o <= 0; - else - dly_b_o <= b_i; + // 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 + + assign z_cout_o = z_o; + assign a_cout_o = r_a; + assign b_cout_o = r_b; endmodule diff --git a/techlibs/quicklogic/synth_quicklogic.cc b/techlibs/quicklogic/synth_quicklogic.cc index 07ec769b5..b74e02cbb 100644 --- a/techlibs/quicklogic/synth_quicklogic.cc +++ b/techlibs/quicklogic/synth_quicklogic.cc @@ -227,16 +227,21 @@ struct SynthQuickLogicPass : public ScriptPass { if (check_label("map_dsp", "(for qlf_k6n10f, skip if -nodsp)") && ((dsp && family == "qlf_k6n10f") || help_mode)) { run("wreduce t:$mul"); - run("ql_dsp_macc"); + //run("ql_dsp_macc"); - run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=20 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=11 -D DSP_B_MINWIDTH=10 -D DSP_NAME=$__QL_MUL20X18"); - run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=10 -D DSP_B_MAXWIDTH=9 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_NAME=$__QL_MUL10X9"); + + run("techmap -map +/mul2dsp.v -map " + lib_path + family + "/dsp_map.v -D USE_DSP_CFG_PARAMS=0 -D DSP_SIGNEDONLY " + "-D DSP_A_MAXWIDTH=32 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=10 -D DSP_B_MINWIDTH=10 -D DSP_NAME=$__MUL32X18"); + run("chtype -set $mul t:$__soft_mul"); + run("techmap -map +/mul2dsp.v -map " + lib_path + family + "/dsp_map.v -D USE_DSP_CFG_PARAMS=0 -D DSP_SIGNEDONLY " + "-D DSP_A_MAXWIDTH=16 -D DSP_B_MAXWIDTH=9 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_NAME=$__MUL16X9"); run("chtype -set $mul t:$__soft_mul"); - run("techmap -map " + lib_path + family + "/dsp_map.v -D USE_DSP_CFG_PARAMS=0"); - run("ql_dsp_simd"); - run("techmap -map " + lib_path + family + "/dsp_final_map.v"); - run("ql_dsp_io_regs"); + run("ql_dsp"); + + //run("ql_dsp_simd"); + //run("techmap -map " + lib_path + family + "/dsp_final_map.v"); + //run("ql_dsp_io_regs"); } if (check_label("coarse")) { From e1074e0e4e2ed5ced6d6b8dd93a8736b0307b5de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 20 Feb 2025 11:28:34 +0100 Subject: [PATCH 02/38] qlf_k6n10f: Fix DSPV2 models --- techlibs/quicklogic/qlf_k6n10f/dsp_sim.v | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/techlibs/quicklogic/qlf_k6n10f/dsp_sim.v b/techlibs/quicklogic/qlf_k6n10f/dsp_sim.v index 40056bfdb..3a4106fe7 100644 --- a/techlibs/quicklogic/qlf_k6n10f/dsp_sim.v +++ b/techlibs/quicklogic/qlf_k6n10f/dsp_sim.v @@ -976,9 +976,9 @@ module dspv2_32x18x64_cfg_ports ( .b_cin(b_cin_i), .z_cin(z_cin_i), - .z_cout(a_cout_o), - .a_cout(b_cout_o), - .b_cout(z_cout_o) + .a_cout(a_cout_o), + .b_cout(b_cout_o), + .z_cout(z_cout_o) ); endmodule From 370a033d4e14b1593a8b6724156ae5dcb34b35a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 20 Feb 2025 11:30:09 +0100 Subject: [PATCH 03/38] qlf_k6n10f: Start tests --- tests/arch/quicklogic/dspv2/complex_mult.ys | 23 +++++++++++++++++++++ tests/arch/quicklogic/dspv2/simple.ys | 17 +++++++++++++++ tests/arch/quicklogic/dspv2/simple2.ys | 12 +++++++++++ 3 files changed, 52 insertions(+) create mode 100644 tests/arch/quicklogic/dspv2/complex_mult.ys create mode 100644 tests/arch/quicklogic/dspv2/simple.ys create mode 100644 tests/arch/quicklogic/dspv2/simple2.ys diff --git a/tests/arch/quicklogic/dspv2/complex_mult.ys b/tests/arch/quicklogic/dspv2/complex_mult.ys new file mode 100644 index 000000000..8a44bbbbc --- /dev/null +++ b/tests/arch/quicklogic/dspv2/complex_mult.ys @@ -0,0 +1,23 @@ +read_verilog < Date: Tue, 25 Feb 2025 11:29:45 +0100 Subject: [PATCH 04/38] synth_quicklogic: add -dspv2 to opt into v2 DSP blocks --- techlibs/quicklogic/Makefile.inc | 8 +- .../{dsp_final_map.v => dspv1_final_map.v} | 0 techlibs/quicklogic/qlf_k6n10f/dspv1_map.v | 102 + techlibs/quicklogic/qlf_k6n10f/dspv1_sim.v | 4527 +++++++++++++++++ .../qlf_k6n10f/{dsp_map.v => dspv2_map.v} | 0 .../qlf_k6n10f/{dsp_sim.v => dspv2_sim.v} | 0 techlibs/quicklogic/synth_quicklogic.cc | 61 +- tests/arch/quicklogic/dspv2/complex_mult.ys | 2 +- tests/arch/quicklogic/dspv2/simple.ys | 2 +- tests/arch/quicklogic/dspv2/simple2.ys | 2 +- 10 files changed, 4680 insertions(+), 24 deletions(-) rename techlibs/quicklogic/qlf_k6n10f/{dsp_final_map.v => dspv1_final_map.v} (100%) create mode 100644 techlibs/quicklogic/qlf_k6n10f/dspv1_map.v create mode 100644 techlibs/quicklogic/qlf_k6n10f/dspv1_sim.v rename techlibs/quicklogic/qlf_k6n10f/{dsp_map.v => dspv2_map.v} (100%) rename techlibs/quicklogic/qlf_k6n10f/{dsp_sim.v => dspv2_sim.v} (100%) diff --git a/techlibs/quicklogic/Makefile.inc b/techlibs/quicklogic/Makefile.inc index da324d17b..32681a31f 100644 --- a/techlibs/quicklogic/Makefile.inc +++ b/techlibs/quicklogic/Makefile.inc @@ -39,9 +39,11 @@ $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf $(eval $(call add_gen_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/bram_types_sim.v)) $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/cells_sim.v)) $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/ffs_map.v)) -$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dsp_sim.v)) -$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dsp_map.v)) -$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dsp_final_map.v)) +$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dspv1_sim.v)) +$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dspv1_map.v)) +$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dspv1_final_map.v)) +$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dspv2_sim.v)) +$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dspv2_map.v)) $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/TDP18K_FIFO.v)) $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/ufifo_ctl.v)) $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/sram1024x18_mem.v)) diff --git a/techlibs/quicklogic/qlf_k6n10f/dsp_final_map.v b/techlibs/quicklogic/qlf_k6n10f/dspv1_final_map.v similarity index 100% rename from techlibs/quicklogic/qlf_k6n10f/dsp_final_map.v rename to techlibs/quicklogic/qlf_k6n10f/dspv1_final_map.v diff --git a/techlibs/quicklogic/qlf_k6n10f/dspv1_map.v b/techlibs/quicklogic/qlf_k6n10f/dspv1_map.v new file mode 100644 index 000000000..127145b71 --- /dev/null +++ b/techlibs/quicklogic/qlf_k6n10f/dspv1_map.v @@ -0,0 +1,102 @@ +// 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 + +module \$__QL_MUL20X18 (input [19:0] A, input [17:0] B, output [37:0] Y); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 0; + parameter B_WIDTH = 0; + parameter Y_WIDTH = 0; + + wire [19:0] a; + wire [17:0] b; + wire [37:0] z; + + assign a = (A_WIDTH == 20) ? A : + (A_SIGNED) ? {{(20 - A_WIDTH){A[A_WIDTH-1]}}, A} : + {{(20 - A_WIDTH){1'b0}}, A}; + + assign b = (B_WIDTH == 18) ? B : + (B_SIGNED) ? {{(18 - B_WIDTH){B[B_WIDTH-1]}}, B} : + {{(18 - B_WIDTH){1'b0}}, B}; + + (* is_inferred=1 *) + dsp_t1_20x18x64_cfg_ports _TECHMAP_REPLACE_ ( + .a_i (a), + .b_i (b), + .acc_fir_i (6'd0), + .z_o (z), + + .feedback_i (3'd0), + .load_acc_i (1'b0), + .unsigned_a_i (!A_SIGNED), + .unsigned_b_i (!B_SIGNED), + + .output_select_i (3'd0), + .saturate_enable_i (1'b0), + .shift_right_i (6'd0), + .round_i (1'b0), + .subtract_i (1'b0), + .register_inputs_i (1'b0) + ); + + assign Y = z; + +endmodule + +module \$__QL_MUL10X9 (input [9:0] A, input [8:0] B, output [18:0] Y); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 0; + parameter B_WIDTH = 0; + parameter Y_WIDTH = 0; + + wire [ 9:0] a; + wire [ 8:0] b; + wire [18:0] z; + + assign a = (A_WIDTH == 10) ? A : + (A_SIGNED) ? {{(10 - A_WIDTH){A[A_WIDTH-1]}}, A} : + {{(10 - A_WIDTH){1'b0}}, A}; + + assign b = (B_WIDTH == 9) ? B : + (B_SIGNED) ? {{( 9 - B_WIDTH){B[B_WIDTH-1]}}, B} : + {{( 9 - B_WIDTH){1'b0}}, B}; + + (* is_inferred=1 *) + dsp_t1_10x9x32_cfg_ports _TECHMAP_REPLACE_ ( + .a_i (a), + .b_i (b), + .acc_fir_i (6'd0), + .z_o (z), + + .feedback_i (3'd0), + .load_acc_i (1'b0), + .unsigned_a_i (!A_SIGNED), + .unsigned_b_i (!B_SIGNED), + + .output_select_i (3'd0), + .saturate_enable_i (1'b0), + .shift_right_i (6'd0), + .round_i (1'b0), + .subtract_i (1'b0), + .register_inputs_i (1'b0) + ); + + + assign Y = z; + +endmodule diff --git a/techlibs/quicklogic/qlf_k6n10f/dspv1_sim.v b/techlibs/quicklogic/qlf_k6n10f/dspv1_sim.v new file mode 100644 index 000000000..5f43b3229 --- /dev/null +++ b/techlibs/quicklogic/qlf_k6n10f/dspv1_sim.v @@ -0,0 +1,4527 @@ +// 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 + +`timescale 1ps/1ps + +`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, + + input wire reset, + + 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 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), + .acc_fir(6'b0), + .z(z), + .dly_b(), + + .clk(1'b0), + .reset(reset), + + .f_mode(f_mode), + + .feedback(feedback), + .load_acc(1'b0), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .output_select(output_select), // unregistered output: a * b (0) + .saturate_enable(1'b0), + .shift_right(6'b0), + .round(1'b0), + .subtract(1'b0), + .register_inputs(register_inputs) // unregistered inputs + ); + +`ifdef SDF_SIM + specify + (a[0] => z[0]) = 0; + (a[1] => z[0]) = 0; + (a[2] => z[0]) = 0; + (a[3] => z[0]) = 0; + (a[4] => z[0]) = 0; + (a[5] => z[0]) = 0; + (a[6] => z[0]) = 0; + (a[7] => z[0]) = 0; + (a[8] => z[0]) = 0; + (a[9] => z[0]) = 0; + (a[10] => z[0]) = 0; + (a[11] => z[0]) = 0; + (a[12] => z[0]) = 0; + (a[13] => z[0]) = 0; + (a[14] => z[0]) = 0; + (a[15] => z[0]) = 0; + (a[16] => z[0]) = 0; + (a[17] => z[0]) = 0; + (a[18] => z[0]) = 0; + (a[19] => z[0]) = 0; + (b[0] => z[0]) = 0; + (b[1] => z[0]) = 0; + (b[2] => z[0]) = 0; + (b[3] => z[0]) = 0; + (b[4] => z[0]) = 0; + (b[5] => z[0]) = 0; + (b[6] => z[0]) = 0; + (b[7] => z[0]) = 0; + (b[8] => z[0]) = 0; + (b[9] => z[0]) = 0; + (b[10] => z[0]) = 0; + (b[11] => z[0]) = 0; + (b[12] => z[0]) = 0; + (b[13] => z[0]) = 0; + (b[14] => z[0]) = 0; + (b[15] => z[0]) = 0; + (b[16] => z[0]) = 0; + (b[17] => z[0]) = 0; + (a[0] => z[1]) = 0; + (a[1] => z[1]) = 0; + (a[2] => z[1]) = 0; + (a[3] => z[1]) = 0; + (a[4] => z[1]) = 0; + (a[5] => z[1]) = 0; + (a[6] => z[1]) = 0; + (a[7] => z[1]) = 0; + (a[8] => z[1]) = 0; + (a[9] => z[1]) = 0; + (a[10] => z[1]) = 0; + (a[11] => z[1]) = 0; + (a[12] => z[1]) = 0; + (a[13] => z[1]) = 0; + (a[14] => z[1]) = 0; + (a[15] => z[1]) = 0; + (a[16] => z[1]) = 0; + (a[17] => z[1]) = 0; + (a[18] => z[1]) = 0; + (a[19] => z[1]) = 0; + (b[0] => z[1]) = 0; + (b[1] => z[1]) = 0; + (b[2] => z[1]) = 0; + (b[3] => z[1]) = 0; + (b[4] => z[1]) = 0; + (b[5] => z[1]) = 0; + (b[6] => z[1]) = 0; + (b[7] => z[1]) = 0; + (b[8] => z[1]) = 0; + (b[9] => z[1]) = 0; + (b[10] => z[1]) = 0; + (b[11] => z[1]) = 0; + (b[12] => z[1]) = 0; + (b[13] => z[1]) = 0; + (b[14] => z[1]) = 0; + (b[15] => z[1]) = 0; + (b[16] => z[1]) = 0; + (b[17] => z[1]) = 0; + (a[0] => z[2]) = 0; + (a[1] => z[2]) = 0; + (a[2] => z[2]) = 0; + (a[3] => z[2]) = 0; + (a[4] => z[2]) = 0; + (a[5] => z[2]) = 0; + (a[6] => z[2]) = 0; + (a[7] => z[2]) = 0; + (a[8] => z[2]) = 0; + (a[9] => z[2]) = 0; + (a[10] => z[2]) = 0; + (a[11] => z[2]) = 0; + (a[12] => z[2]) = 0; + (a[13] => z[2]) = 0; + (a[14] => z[2]) = 0; + (a[15] => z[2]) = 0; + (a[16] => z[2]) = 0; + (a[17] => z[2]) = 0; + (a[18] => z[2]) = 0; + (a[19] => z[2]) = 0; + (b[0] => z[2]) = 0; + (b[1] => z[2]) = 0; + (b[2] => z[2]) = 0; + (b[3] => z[2]) = 0; + (b[4] => z[2]) = 0; + (b[5] => z[2]) = 0; + (b[6] => z[2]) = 0; + (b[7] => z[2]) = 0; + (b[8] => z[2]) = 0; + (b[9] => z[2]) = 0; + (b[10] => z[2]) = 0; + (b[11] => z[2]) = 0; + (b[12] => z[2]) = 0; + (b[13] => z[2]) = 0; + (b[14] => z[2]) = 0; + (b[15] => z[2]) = 0; + (b[16] => z[2]) = 0; + (b[17] => z[2]) = 0; + (a[0] => z[3]) = 0; + (a[1] => z[3]) = 0; + (a[2] => z[3]) = 0; + (a[3] => z[3]) = 0; + (a[4] => z[3]) = 0; + (a[5] => z[3]) = 0; + (a[6] => z[3]) = 0; + (a[7] => z[3]) = 0; + (a[8] => z[3]) = 0; + (a[9] => z[3]) = 0; + (a[10] => z[3]) = 0; + (a[11] => z[3]) = 0; + (a[12] => z[3]) = 0; + (a[13] => z[3]) = 0; + (a[14] => z[3]) = 0; + (a[15] => z[3]) = 0; + (a[16] => z[3]) = 0; + (a[17] => z[3]) = 0; + (a[18] => z[3]) = 0; + (a[19] => z[3]) = 0; + (b[0] => z[3]) = 0; + (b[1] => z[3]) = 0; + (b[2] => z[3]) = 0; + (b[3] => z[3]) = 0; + (b[4] => z[3]) = 0; + (b[5] => z[3]) = 0; + (b[6] => z[3]) = 0; + (b[7] => z[3]) = 0; + (b[8] => z[3]) = 0; + (b[9] => z[3]) = 0; + (b[10] => z[3]) = 0; + (b[11] => z[3]) = 0; + (b[12] => z[3]) = 0; + (b[13] => z[3]) = 0; + (b[14] => z[3]) = 0; + (b[15] => z[3]) = 0; + (b[16] => z[3]) = 0; + (b[17] => z[3]) = 0; + (a[0] => z[4]) = 0; + (a[1] => z[4]) = 0; + (a[2] => z[4]) = 0; + (a[3] => z[4]) = 0; + (a[4] => z[4]) = 0; + (a[5] => z[4]) = 0; + (a[6] => z[4]) = 0; + (a[7] => z[4]) = 0; + (a[8] => z[4]) = 0; + (a[9] => z[4]) = 0; + (a[10] => z[4]) = 0; + (a[11] => z[4]) = 0; + (a[12] => z[4]) = 0; + (a[13] => z[4]) = 0; + (a[14] => z[4]) = 0; + (a[15] => z[4]) = 0; + (a[16] => z[4]) = 0; + (a[17] => z[4]) = 0; + (a[18] => z[4]) = 0; + (a[19] => z[4]) = 0; + (b[0] => z[4]) = 0; + (b[1] => z[4]) = 0; + (b[2] => z[4]) = 0; + (b[3] => z[4]) = 0; + (b[4] => z[4]) = 0; + (b[5] => z[4]) = 0; + (b[6] => z[4]) = 0; + (b[7] => z[4]) = 0; + (b[8] => z[4]) = 0; + (b[9] => z[4]) = 0; + (b[10] => z[4]) = 0; + (b[11] => z[4]) = 0; + (b[12] => z[4]) = 0; + (b[13] => z[4]) = 0; + (b[14] => z[4]) = 0; + (b[15] => z[4]) = 0; + (b[16] => z[4]) = 0; + (b[17] => z[4]) = 0; + (a[0] => z[5]) = 0; + (a[1] => z[5]) = 0; + (a[2] => z[5]) = 0; + (a[3] => z[5]) = 0; + (a[4] => z[5]) = 0; + (a[5] => z[5]) = 0; + (a[6] => z[5]) = 0; + (a[7] => z[5]) = 0; + (a[8] => z[5]) = 0; + (a[9] => z[5]) = 0; + (a[10] => z[5]) = 0; + (a[11] => z[5]) = 0; + (a[12] => z[5]) = 0; + (a[13] => z[5]) = 0; + (a[14] => z[5]) = 0; + (a[15] => z[5]) = 0; + (a[16] => z[5]) = 0; + (a[17] => z[5]) = 0; + (a[18] => z[5]) = 0; + (a[19] => z[5]) = 0; + (b[0] => z[5]) = 0; + (b[1] => z[5]) = 0; + (b[2] => z[5]) = 0; + (b[3] => z[5]) = 0; + (b[4] => z[5]) = 0; + (b[5] => z[5]) = 0; + (b[6] => z[5]) = 0; + (b[7] => z[5]) = 0; + (b[8] => z[5]) = 0; + (b[9] => z[5]) = 0; + (b[10] => z[5]) = 0; + (b[11] => z[5]) = 0; + (b[12] => z[5]) = 0; + (b[13] => z[5]) = 0; + (b[14] => z[5]) = 0; + (b[15] => z[5]) = 0; + (b[16] => z[5]) = 0; + (b[17] => z[5]) = 0; + (a[0] => z[6]) = 0; + (a[1] => z[6]) = 0; + (a[2] => z[6]) = 0; + (a[3] => z[6]) = 0; + (a[4] => z[6]) = 0; + (a[5] => z[6]) = 0; + (a[6] => z[6]) = 0; + (a[7] => z[6]) = 0; + (a[8] => z[6]) = 0; + (a[9] => z[6]) = 0; + (a[10] => z[6]) = 0; + (a[11] => z[6]) = 0; + (a[12] => z[6]) = 0; + (a[13] => z[6]) = 0; + (a[14] => z[6]) = 0; + (a[15] => z[6]) = 0; + (a[16] => z[6]) = 0; + (a[17] => z[6]) = 0; + (a[18] => z[6]) = 0; + (a[19] => z[6]) = 0; + (b[0] => z[6]) = 0; + (b[1] => z[6]) = 0; + (b[2] => z[6]) = 0; + (b[3] => z[6]) = 0; + (b[4] => z[6]) = 0; + (b[5] => z[6]) = 0; + (b[6] => z[6]) = 0; + (b[7] => z[6]) = 0; + (b[8] => z[6]) = 0; + (b[9] => z[6]) = 0; + (b[10] => z[6]) = 0; + (b[11] => z[6]) = 0; + (b[12] => z[6]) = 0; + (b[13] => z[6]) = 0; + (b[14] => z[6]) = 0; + (b[15] => z[6]) = 0; + (b[16] => z[6]) = 0; + (b[17] => z[6]) = 0; + (a[0] => z[7]) = 0; + (a[1] => z[7]) = 0; + (a[2] => z[7]) = 0; + (a[3] => z[7]) = 0; + (a[4] => z[7]) = 0; + (a[5] => z[7]) = 0; + (a[6] => z[7]) = 0; + (a[7] => z[7]) = 0; + (a[8] => z[7]) = 0; + (a[9] => z[7]) = 0; + (a[10] => z[7]) = 0; + (a[11] => z[7]) = 0; + (a[12] => z[7]) = 0; + (a[13] => z[7]) = 0; + (a[14] => z[7]) = 0; + (a[15] => z[7]) = 0; + (a[16] => z[7]) = 0; + (a[17] => z[7]) = 0; + (a[18] => z[7]) = 0; + (a[19] => z[7]) = 0; + (b[0] => z[7]) = 0; + (b[1] => z[7]) = 0; + (b[2] => z[7]) = 0; + (b[3] => z[7]) = 0; + (b[4] => z[7]) = 0; + (b[5] => z[7]) = 0; + (b[6] => z[7]) = 0; + (b[7] => z[7]) = 0; + (b[8] => z[7]) = 0; + (b[9] => z[7]) = 0; + (b[10] => z[7]) = 0; + (b[11] => z[7]) = 0; + (b[12] => z[7]) = 0; + (b[13] => z[7]) = 0; + (b[14] => z[7]) = 0; + (b[15] => z[7]) = 0; + (b[16] => z[7]) = 0; + (b[17] => z[7]) = 0; + (a[0] => z[8]) = 0; + (a[1] => z[8]) = 0; + (a[2] => z[8]) = 0; + (a[3] => z[8]) = 0; + (a[4] => z[8]) = 0; + (a[5] => z[8]) = 0; + (a[6] => z[8]) = 0; + (a[7] => z[8]) = 0; + (a[8] => z[8]) = 0; + (a[9] => z[8]) = 0; + (a[10] => z[8]) = 0; + (a[11] => z[8]) = 0; + (a[12] => z[8]) = 0; + (a[13] => z[8]) = 0; + (a[14] => z[8]) = 0; + (a[15] => z[8]) = 0; + (a[16] => z[8]) = 0; + (a[17] => z[8]) = 0; + (a[18] => z[8]) = 0; + (a[19] => z[8]) = 0; + (b[0] => z[8]) = 0; + (b[1] => z[8]) = 0; + (b[2] => z[8]) = 0; + (b[3] => z[8]) = 0; + (b[4] => z[8]) = 0; + (b[5] => z[8]) = 0; + (b[6] => z[8]) = 0; + (b[7] => z[8]) = 0; + (b[8] => z[8]) = 0; + (b[9] => z[8]) = 0; + (b[10] => z[8]) = 0; + (b[11] => z[8]) = 0; + (b[12] => z[8]) = 0; + (b[13] => z[8]) = 0; + (b[14] => z[8]) = 0; + (b[15] => z[8]) = 0; + (b[16] => z[8]) = 0; + (b[17] => z[8]) = 0; + (a[0] => z[9]) = 0; + (a[1] => z[9]) = 0; + (a[2] => z[9]) = 0; + (a[3] => z[9]) = 0; + (a[4] => z[9]) = 0; + (a[5] => z[9]) = 0; + (a[6] => z[9]) = 0; + (a[7] => z[9]) = 0; + (a[8] => z[9]) = 0; + (a[9] => z[9]) = 0; + (a[10] => z[9]) = 0; + (a[11] => z[9]) = 0; + (a[12] => z[9]) = 0; + (a[13] => z[9]) = 0; + (a[14] => z[9]) = 0; + (a[15] => z[9]) = 0; + (a[16] => z[9]) = 0; + (a[17] => z[9]) = 0; + (a[18] => z[9]) = 0; + (a[19] => z[9]) = 0; + (b[0] => z[9]) = 0; + (b[1] => z[9]) = 0; + (b[2] => z[9]) = 0; + (b[3] => z[9]) = 0; + (b[4] => z[9]) = 0; + (b[5] => z[9]) = 0; + (b[6] => z[9]) = 0; + (b[7] => z[9]) = 0; + (b[8] => z[9]) = 0; + (b[9] => z[9]) = 0; + (b[10] => z[9]) = 0; + (b[11] => z[9]) = 0; + (b[12] => z[9]) = 0; + (b[13] => z[9]) = 0; + (b[14] => z[9]) = 0; + (b[15] => z[9]) = 0; + (b[16] => z[9]) = 0; + (b[17] => z[9]) = 0; + (a[0] => z[10]) = 0; + (a[1] => z[10]) = 0; + (a[2] => z[10]) = 0; + (a[3] => z[10]) = 0; + (a[4] => z[10]) = 0; + (a[5] => z[10]) = 0; + (a[6] => z[10]) = 0; + (a[7] => z[10]) = 0; + (a[8] => z[10]) = 0; + (a[9] => z[10]) = 0; + (a[10] => z[10]) = 0; + (a[11] => z[10]) = 0; + (a[12] => z[10]) = 0; + (a[13] => z[10]) = 0; + (a[14] => z[10]) = 0; + (a[15] => z[10]) = 0; + (a[16] => z[10]) = 0; + (a[17] => z[10]) = 0; + (a[18] => z[10]) = 0; + (a[19] => z[10]) = 0; + (b[0] => z[10]) = 0; + (b[1] => z[10]) = 0; + (b[2] => z[10]) = 0; + (b[3] => z[10]) = 0; + (b[4] => z[10]) = 0; + (b[5] => z[10]) = 0; + (b[6] => z[10]) = 0; + (b[7] => z[10]) = 0; + (b[8] => z[10]) = 0; + (b[9] => z[10]) = 0; + (b[10] => z[10]) = 0; + (b[11] => z[10]) = 0; + (b[12] => z[10]) = 0; + (b[13] => z[10]) = 0; + (b[14] => z[10]) = 0; + (b[15] => z[10]) = 0; + (b[16] => z[10]) = 0; + (b[17] => z[10]) = 0; + (a[0] => z[11]) = 0; + (a[1] => z[11]) = 0; + (a[2] => z[11]) = 0; + (a[3] => z[11]) = 0; + (a[4] => z[11]) = 0; + (a[5] => z[11]) = 0; + (a[6] => z[11]) = 0; + (a[7] => z[11]) = 0; + (a[8] => z[11]) = 0; + (a[9] => z[11]) = 0; + (a[10] => z[11]) = 0; + (a[11] => z[11]) = 0; + (a[12] => z[11]) = 0; + (a[13] => z[11]) = 0; + (a[14] => z[11]) = 0; + (a[15] => z[11]) = 0; + (a[16] => z[11]) = 0; + (a[17] => z[11]) = 0; + (a[18] => z[11]) = 0; + (a[19] => z[11]) = 0; + (b[0] => z[11]) = 0; + (b[1] => z[11]) = 0; + (b[2] => z[11]) = 0; + (b[3] => z[11]) = 0; + (b[4] => z[11]) = 0; + (b[5] => z[11]) = 0; + (b[6] => z[11]) = 0; + (b[7] => z[11]) = 0; + (b[8] => z[11]) = 0; + (b[9] => z[11]) = 0; + (b[10] => z[11]) = 0; + (b[11] => z[11]) = 0; + (b[12] => z[11]) = 0; + (b[13] => z[11]) = 0; + (b[14] => z[11]) = 0; + (b[15] => z[11]) = 0; + (b[16] => z[11]) = 0; + (b[17] => z[11]) = 0; + (a[0] => z[12]) = 0; + (a[1] => z[12]) = 0; + (a[2] => z[12]) = 0; + (a[3] => z[12]) = 0; + (a[4] => z[12]) = 0; + (a[5] => z[12]) = 0; + (a[6] => z[12]) = 0; + (a[7] => z[12]) = 0; + (a[8] => z[12]) = 0; + (a[9] => z[12]) = 0; + (a[10] => z[12]) = 0; + (a[11] => z[12]) = 0; + (a[12] => z[12]) = 0; + (a[13] => z[12]) = 0; + (a[14] => z[12]) = 0; + (a[15] => z[12]) = 0; + (a[16] => z[12]) = 0; + (a[17] => z[12]) = 0; + (a[18] => z[12]) = 0; + (a[19] => z[12]) = 0; + (b[0] => z[12]) = 0; + (b[1] => z[12]) = 0; + (b[2] => z[12]) = 0; + (b[3] => z[12]) = 0; + (b[4] => z[12]) = 0; + (b[5] => z[12]) = 0; + (b[6] => z[12]) = 0; + (b[7] => z[12]) = 0; + (b[8] => z[12]) = 0; + (b[9] => z[12]) = 0; + (b[10] => z[12]) = 0; + (b[11] => z[12]) = 0; + (b[12] => z[12]) = 0; + (b[13] => z[12]) = 0; + (b[14] => z[12]) = 0; + (b[15] => z[12]) = 0; + (b[16] => z[12]) = 0; + (b[17] => z[12]) = 0; + (a[0] => z[13]) = 0; + (a[1] => z[13]) = 0; + (a[2] => z[13]) = 0; + (a[3] => z[13]) = 0; + (a[4] => z[13]) = 0; + (a[5] => z[13]) = 0; + (a[6] => z[13]) = 0; + (a[7] => z[13]) = 0; + (a[8] => z[13]) = 0; + (a[9] => z[13]) = 0; + (a[10] => z[13]) = 0; + (a[11] => z[13]) = 0; + (a[12] => z[13]) = 0; + (a[13] => z[13]) = 0; + (a[14] => z[13]) = 0; + (a[15] => z[13]) = 0; + (a[16] => z[13]) = 0; + (a[17] => z[13]) = 0; + (a[18] => z[13]) = 0; + (a[19] => z[13]) = 0; + (b[0] => z[13]) = 0; + (b[1] => z[13]) = 0; + (b[2] => z[13]) = 0; + (b[3] => z[13]) = 0; + (b[4] => z[13]) = 0; + (b[5] => z[13]) = 0; + (b[6] => z[13]) = 0; + (b[7] => z[13]) = 0; + (b[8] => z[13]) = 0; + (b[9] => z[13]) = 0; + (b[10] => z[13]) = 0; + (b[11] => z[13]) = 0; + (b[12] => z[13]) = 0; + (b[13] => z[13]) = 0; + (b[14] => z[13]) = 0; + (b[15] => z[13]) = 0; + (b[16] => z[13]) = 0; + (b[17] => z[13]) = 0; + (a[0] => z[14]) = 0; + (a[1] => z[14]) = 0; + (a[2] => z[14]) = 0; + (a[3] => z[14]) = 0; + (a[4] => z[14]) = 0; + (a[5] => z[14]) = 0; + (a[6] => z[14]) = 0; + (a[7] => z[14]) = 0; + (a[8] => z[14]) = 0; + (a[9] => z[14]) = 0; + (a[10] => z[14]) = 0; + (a[11] => z[14]) = 0; + (a[12] => z[14]) = 0; + (a[13] => z[14]) = 0; + (a[14] => z[14]) = 0; + (a[15] => z[14]) = 0; + (a[16] => z[14]) = 0; + (a[17] => z[14]) = 0; + (a[18] => z[14]) = 0; + (a[19] => z[14]) = 0; + (b[0] => z[14]) = 0; + (b[1] => z[14]) = 0; + (b[2] => z[14]) = 0; + (b[3] => z[14]) = 0; + (b[4] => z[14]) = 0; + (b[5] => z[14]) = 0; + (b[6] => z[14]) = 0; + (b[7] => z[14]) = 0; + (b[8] => z[14]) = 0; + (b[9] => z[14]) = 0; + (b[10] => z[14]) = 0; + (b[11] => z[14]) = 0; + (b[12] => z[14]) = 0; + (b[13] => z[14]) = 0; + (b[14] => z[14]) = 0; + (b[15] => z[14]) = 0; + (b[16] => z[14]) = 0; + (b[17] => z[14]) = 0; + (a[0] => z[15]) = 0; + (a[1] => z[15]) = 0; + (a[2] => z[15]) = 0; + (a[3] => z[15]) = 0; + (a[4] => z[15]) = 0; + (a[5] => z[15]) = 0; + (a[6] => z[15]) = 0; + (a[7] => z[15]) = 0; + (a[8] => z[15]) = 0; + (a[9] => z[15]) = 0; + (a[10] => z[15]) = 0; + (a[11] => z[15]) = 0; + (a[12] => z[15]) = 0; + (a[13] => z[15]) = 0; + (a[14] => z[15]) = 0; + (a[15] => z[15]) = 0; + (a[16] => z[15]) = 0; + (a[17] => z[15]) = 0; + (a[18] => z[15]) = 0; + (a[19] => z[15]) = 0; + (b[0] => z[15]) = 0; + (b[1] => z[15]) = 0; + (b[2] => z[15]) = 0; + (b[3] => z[15]) = 0; + (b[4] => z[15]) = 0; + (b[5] => z[15]) = 0; + (b[6] => z[15]) = 0; + (b[7] => z[15]) = 0; + (b[8] => z[15]) = 0; + (b[9] => z[15]) = 0; + (b[10] => z[15]) = 0; + (b[11] => z[15]) = 0; + (b[12] => z[15]) = 0; + (b[13] => z[15]) = 0; + (b[14] => z[15]) = 0; + (b[15] => z[15]) = 0; + (b[16] => z[15]) = 0; + (b[17] => z[15]) = 0; + (a[0] => z[16]) = 0; + (a[1] => z[16]) = 0; + (a[2] => z[16]) = 0; + (a[3] => z[16]) = 0; + (a[4] => z[16]) = 0; + (a[5] => z[16]) = 0; + (a[6] => z[16]) = 0; + (a[7] => z[16]) = 0; + (a[8] => z[16]) = 0; + (a[9] => z[16]) = 0; + (a[10] => z[16]) = 0; + (a[11] => z[16]) = 0; + (a[12] => z[16]) = 0; + (a[13] => z[16]) = 0; + (a[14] => z[16]) = 0; + (a[15] => z[16]) = 0; + (a[16] => z[16]) = 0; + (a[17] => z[16]) = 0; + (a[18] => z[16]) = 0; + (a[19] => z[16]) = 0; + (b[0] => z[16]) = 0; + (b[1] => z[16]) = 0; + (b[2] => z[16]) = 0; + (b[3] => z[16]) = 0; + (b[4] => z[16]) = 0; + (b[5] => z[16]) = 0; + (b[6] => z[16]) = 0; + (b[7] => z[16]) = 0; + (b[8] => z[16]) = 0; + (b[9] => z[16]) = 0; + (b[10] => z[16]) = 0; + (b[11] => z[16]) = 0; + (b[12] => z[16]) = 0; + (b[13] => z[16]) = 0; + (b[14] => z[16]) = 0; + (b[15] => z[16]) = 0; + (b[16] => z[16]) = 0; + (b[17] => z[16]) = 0; + (a[0] => z[17]) = 0; + (a[1] => z[17]) = 0; + (a[2] => z[17]) = 0; + (a[3] => z[17]) = 0; + (a[4] => z[17]) = 0; + (a[5] => z[17]) = 0; + (a[6] => z[17]) = 0; + (a[7] => z[17]) = 0; + (a[8] => z[17]) = 0; + (a[9] => z[17]) = 0; + (a[10] => z[17]) = 0; + (a[11] => z[17]) = 0; + (a[12] => z[17]) = 0; + (a[13] => z[17]) = 0; + (a[14] => z[17]) = 0; + (a[15] => z[17]) = 0; + (a[16] => z[17]) = 0; + (a[17] => z[17]) = 0; + (a[18] => z[17]) = 0; + (a[19] => z[17]) = 0; + (b[0] => z[17]) = 0; + (b[1] => z[17]) = 0; + (b[2] => z[17]) = 0; + (b[3] => z[17]) = 0; + (b[4] => z[17]) = 0; + (b[5] => z[17]) = 0; + (b[6] => z[17]) = 0; + (b[7] => z[17]) = 0; + (b[8] => z[17]) = 0; + (b[9] => z[17]) = 0; + (b[10] => z[17]) = 0; + (b[11] => z[17]) = 0; + (b[12] => z[17]) = 0; + (b[13] => z[17]) = 0; + (b[14] => z[17]) = 0; + (b[15] => z[17]) = 0; + (b[16] => z[17]) = 0; + (b[17] => z[17]) = 0; + (a[0] => z[18]) = 0; + (a[1] => z[18]) = 0; + (a[2] => z[18]) = 0; + (a[3] => z[18]) = 0; + (a[4] => z[18]) = 0; + (a[5] => z[18]) = 0; + (a[6] => z[18]) = 0; + (a[7] => z[18]) = 0; + (a[8] => z[18]) = 0; + (a[9] => z[18]) = 0; + (a[10] => z[18]) = 0; + (a[11] => z[18]) = 0; + (a[12] => z[18]) = 0; + (a[13] => z[18]) = 0; + (a[14] => z[18]) = 0; + (a[15] => z[18]) = 0; + (a[16] => z[18]) = 0; + (a[17] => z[18]) = 0; + (a[18] => z[18]) = 0; + (a[19] => z[18]) = 0; + (b[0] => z[18]) = 0; + (b[1] => z[18]) = 0; + (b[2] => z[18]) = 0; + (b[3] => z[18]) = 0; + (b[4] => z[18]) = 0; + (b[5] => z[18]) = 0; + (b[6] => z[18]) = 0; + (b[7] => z[18]) = 0; + (b[8] => z[18]) = 0; + (b[9] => z[18]) = 0; + (b[10] => z[18]) = 0; + (b[11] => z[18]) = 0; + (b[12] => z[18]) = 0; + (b[13] => z[18]) = 0; + (b[14] => z[18]) = 0; + (b[15] => z[18]) = 0; + (b[16] => z[18]) = 0; + (b[17] => z[18]) = 0; + (a[0] => z[19]) = 0; + (a[1] => z[19]) = 0; + (a[2] => z[19]) = 0; + (a[3] => z[19]) = 0; + (a[4] => z[19]) = 0; + (a[5] => z[19]) = 0; + (a[6] => z[19]) = 0; + (a[7] => z[19]) = 0; + (a[8] => z[19]) = 0; + (a[9] => z[19]) = 0; + (a[10] => z[19]) = 0; + (a[11] => z[19]) = 0; + (a[12] => z[19]) = 0; + (a[13] => z[19]) = 0; + (a[14] => z[19]) = 0; + (a[15] => z[19]) = 0; + (a[16] => z[19]) = 0; + (a[17] => z[19]) = 0; + (a[18] => z[19]) = 0; + (a[19] => z[19]) = 0; + (b[0] => z[19]) = 0; + (b[1] => z[19]) = 0; + (b[2] => z[19]) = 0; + (b[3] => z[19]) = 0; + (b[4] => z[19]) = 0; + (b[5] => z[19]) = 0; + (b[6] => z[19]) = 0; + (b[7] => z[19]) = 0; + (b[8] => z[19]) = 0; + (b[9] => z[19]) = 0; + (b[10] => z[19]) = 0; + (b[11] => z[19]) = 0; + (b[12] => z[19]) = 0; + (b[13] => z[19]) = 0; + (b[14] => z[19]) = 0; + (b[15] => z[19]) = 0; + (b[16] => z[19]) = 0; + (b[17] => z[19]) = 0; + (a[0] => z[20]) = 0; + (a[1] => z[20]) = 0; + (a[2] => z[20]) = 0; + (a[3] => z[20]) = 0; + (a[4] => z[20]) = 0; + (a[5] => z[20]) = 0; + (a[6] => z[20]) = 0; + (a[7] => z[20]) = 0; + (a[8] => z[20]) = 0; + (a[9] => z[20]) = 0; + (a[10] => z[20]) = 0; + (a[11] => z[20]) = 0; + (a[12] => z[20]) = 0; + (a[13] => z[20]) = 0; + (a[14] => z[20]) = 0; + (a[15] => z[20]) = 0; + (a[16] => z[20]) = 0; + (a[17] => z[20]) = 0; + (a[18] => z[20]) = 0; + (a[19] => z[20]) = 0; + (b[0] => z[20]) = 0; + (b[1] => z[20]) = 0; + (b[2] => z[20]) = 0; + (b[3] => z[20]) = 0; + (b[4] => z[20]) = 0; + (b[5] => z[20]) = 0; + (b[6] => z[20]) = 0; + (b[7] => z[20]) = 0; + (b[8] => z[20]) = 0; + (b[9] => z[20]) = 0; + (b[10] => z[20]) = 0; + (b[11] => z[20]) = 0; + (b[12] => z[20]) = 0; + (b[13] => z[20]) = 0; + (b[14] => z[20]) = 0; + (b[15] => z[20]) = 0; + (b[16] => z[20]) = 0; + (b[17] => z[20]) = 0; + (a[0] => z[21]) = 0; + (a[1] => z[21]) = 0; + (a[2] => z[21]) = 0; + (a[3] => z[21]) = 0; + (a[4] => z[21]) = 0; + (a[5] => z[21]) = 0; + (a[6] => z[21]) = 0; + (a[7] => z[21]) = 0; + (a[8] => z[21]) = 0; + (a[9] => z[21]) = 0; + (a[10] => z[21]) = 0; + (a[11] => z[21]) = 0; + (a[12] => z[21]) = 0; + (a[13] => z[21]) = 0; + (a[14] => z[21]) = 0; + (a[15] => z[21]) = 0; + (a[16] => z[21]) = 0; + (a[17] => z[21]) = 0; + (a[18] => z[21]) = 0; + (a[19] => z[21]) = 0; + (b[0] => z[21]) = 0; + (b[1] => z[21]) = 0; + (b[2] => z[21]) = 0; + (b[3] => z[21]) = 0; + (b[4] => z[21]) = 0; + (b[5] => z[21]) = 0; + (b[6] => z[21]) = 0; + (b[7] => z[21]) = 0; + (b[8] => z[21]) = 0; + (b[9] => z[21]) = 0; + (b[10] => z[21]) = 0; + (b[11] => z[21]) = 0; + (b[12] => z[21]) = 0; + (b[13] => z[21]) = 0; + (b[14] => z[21]) = 0; + (b[15] => z[21]) = 0; + (b[16] => z[21]) = 0; + (b[17] => z[21]) = 0; + (a[0] => z[22]) = 0; + (a[1] => z[22]) = 0; + (a[2] => z[22]) = 0; + (a[3] => z[22]) = 0; + (a[4] => z[22]) = 0; + (a[5] => z[22]) = 0; + (a[6] => z[22]) = 0; + (a[7] => z[22]) = 0; + (a[8] => z[22]) = 0; + (a[9] => z[22]) = 0; + (a[10] => z[22]) = 0; + (a[11] => z[22]) = 0; + (a[12] => z[22]) = 0; + (a[13] => z[22]) = 0; + (a[14] => z[22]) = 0; + (a[15] => z[22]) = 0; + (a[16] => z[22]) = 0; + (a[17] => z[22]) = 0; + (a[18] => z[22]) = 0; + (a[19] => z[22]) = 0; + (b[0] => z[22]) = 0; + (b[1] => z[22]) = 0; + (b[2] => z[22]) = 0; + (b[3] => z[22]) = 0; + (b[4] => z[22]) = 0; + (b[5] => z[22]) = 0; + (b[6] => z[22]) = 0; + (b[7] => z[22]) = 0; + (b[8] => z[22]) = 0; + (b[9] => z[22]) = 0; + (b[10] => z[22]) = 0; + (b[11] => z[22]) = 0; + (b[12] => z[22]) = 0; + (b[13] => z[22]) = 0; + (b[14] => z[22]) = 0; + (b[15] => z[22]) = 0; + (b[16] => z[22]) = 0; + (b[17] => z[22]) = 0; + (a[0] => z[23]) = 0; + (a[1] => z[23]) = 0; + (a[2] => z[23]) = 0; + (a[3] => z[23]) = 0; + (a[4] => z[23]) = 0; + (a[5] => z[23]) = 0; + (a[6] => z[23]) = 0; + (a[7] => z[23]) = 0; + (a[8] => z[23]) = 0; + (a[9] => z[23]) = 0; + (a[10] => z[23]) = 0; + (a[11] => z[23]) = 0; + (a[12] => z[23]) = 0; + (a[13] => z[23]) = 0; + (a[14] => z[23]) = 0; + (a[15] => z[23]) = 0; + (a[16] => z[23]) = 0; + (a[17] => z[23]) = 0; + (a[18] => z[23]) = 0; + (a[19] => z[23]) = 0; + (b[0] => z[23]) = 0; + (b[1] => z[23]) = 0; + (b[2] => z[23]) = 0; + (b[3] => z[23]) = 0; + (b[4] => z[23]) = 0; + (b[5] => z[23]) = 0; + (b[6] => z[23]) = 0; + (b[7] => z[23]) = 0; + (b[8] => z[23]) = 0; + (b[9] => z[23]) = 0; + (b[10] => z[23]) = 0; + (b[11] => z[23]) = 0; + (b[12] => z[23]) = 0; + (b[13] => z[23]) = 0; + (b[14] => z[23]) = 0; + (b[15] => z[23]) = 0; + (b[16] => z[23]) = 0; + (b[17] => z[23]) = 0; + (a[0] => z[24]) = 0; + (a[1] => z[24]) = 0; + (a[2] => z[24]) = 0; + (a[3] => z[24]) = 0; + (a[4] => z[24]) = 0; + (a[5] => z[24]) = 0; + (a[6] => z[24]) = 0; + (a[7] => z[24]) = 0; + (a[8] => z[24]) = 0; + (a[9] => z[24]) = 0; + (a[10] => z[24]) = 0; + (a[11] => z[24]) = 0; + (a[12] => z[24]) = 0; + (a[13] => z[24]) = 0; + (a[14] => z[24]) = 0; + (a[15] => z[24]) = 0; + (a[16] => z[24]) = 0; + (a[17] => z[24]) = 0; + (a[18] => z[24]) = 0; + (a[19] => z[24]) = 0; + (b[0] => z[24]) = 0; + (b[1] => z[24]) = 0; + (b[2] => z[24]) = 0; + (b[3] => z[24]) = 0; + (b[4] => z[24]) = 0; + (b[5] => z[24]) = 0; + (b[6] => z[24]) = 0; + (b[7] => z[24]) = 0; + (b[8] => z[24]) = 0; + (b[9] => z[24]) = 0; + (b[10] => z[24]) = 0; + (b[11] => z[24]) = 0; + (b[12] => z[24]) = 0; + (b[13] => z[24]) = 0; + (b[14] => z[24]) = 0; + (b[15] => z[24]) = 0; + (b[16] => z[24]) = 0; + (b[17] => z[24]) = 0; + (a[0] => z[25]) = 0; + (a[1] => z[25]) = 0; + (a[2] => z[25]) = 0; + (a[3] => z[25]) = 0; + (a[4] => z[25]) = 0; + (a[5] => z[25]) = 0; + (a[6] => z[25]) = 0; + (a[7] => z[25]) = 0; + (a[8] => z[25]) = 0; + (a[9] => z[25]) = 0; + (a[10] => z[25]) = 0; + (a[11] => z[25]) = 0; + (a[12] => z[25]) = 0; + (a[13] => z[25]) = 0; + (a[14] => z[25]) = 0; + (a[15] => z[25]) = 0; + (a[16] => z[25]) = 0; + (a[17] => z[25]) = 0; + (a[18] => z[25]) = 0; + (a[19] => z[25]) = 0; + (b[0] => z[25]) = 0; + (b[1] => z[25]) = 0; + (b[2] => z[25]) = 0; + (b[3] => z[25]) = 0; + (b[4] => z[25]) = 0; + (b[5] => z[25]) = 0; + (b[6] => z[25]) = 0; + (b[7] => z[25]) = 0; + (b[8] => z[25]) = 0; + (b[9] => z[25]) = 0; + (b[10] => z[25]) = 0; + (b[11] => z[25]) = 0; + (b[12] => z[25]) = 0; + (b[13] => z[25]) = 0; + (b[14] => z[25]) = 0; + (b[15] => z[25]) = 0; + (b[16] => z[25]) = 0; + (b[17] => z[25]) = 0; + (a[0] => z[26]) = 0; + (a[1] => z[26]) = 0; + (a[2] => z[26]) = 0; + (a[3] => z[26]) = 0; + (a[4] => z[26]) = 0; + (a[5] => z[26]) = 0; + (a[6] => z[26]) = 0; + (a[7] => z[26]) = 0; + (a[8] => z[26]) = 0; + (a[9] => z[26]) = 0; + (a[10] => z[26]) = 0; + (a[11] => z[26]) = 0; + (a[12] => z[26]) = 0; + (a[13] => z[26]) = 0; + (a[14] => z[26]) = 0; + (a[15] => z[26]) = 0; + (a[16] => z[26]) = 0; + (a[17] => z[26]) = 0; + (a[18] => z[26]) = 0; + (a[19] => z[26]) = 0; + (b[0] => z[26]) = 0; + (b[1] => z[26]) = 0; + (b[2] => z[26]) = 0; + (b[3] => z[26]) = 0; + (b[4] => z[26]) = 0; + (b[5] => z[26]) = 0; + (b[6] => z[26]) = 0; + (b[7] => z[26]) = 0; + (b[8] => z[26]) = 0; + (b[9] => z[26]) = 0; + (b[10] => z[26]) = 0; + (b[11] => z[26]) = 0; + (b[12] => z[26]) = 0; + (b[13] => z[26]) = 0; + (b[14] => z[26]) = 0; + (b[15] => z[26]) = 0; + (b[16] => z[26]) = 0; + (b[17] => z[26]) = 0; + (a[0] => z[27]) = 0; + (a[1] => z[27]) = 0; + (a[2] => z[27]) = 0; + (a[3] => z[27]) = 0; + (a[4] => z[27]) = 0; + (a[5] => z[27]) = 0; + (a[6] => z[27]) = 0; + (a[7] => z[27]) = 0; + (a[8] => z[27]) = 0; + (a[9] => z[27]) = 0; + (a[10] => z[27]) = 0; + (a[11] => z[27]) = 0; + (a[12] => z[27]) = 0; + (a[13] => z[27]) = 0; + (a[14] => z[27]) = 0; + (a[15] => z[27]) = 0; + (a[16] => z[27]) = 0; + (a[17] => z[27]) = 0; + (a[18] => z[27]) = 0; + (a[19] => z[27]) = 0; + (b[0] => z[27]) = 0; + (b[1] => z[27]) = 0; + (b[2] => z[27]) = 0; + (b[3] => z[27]) = 0; + (b[4] => z[27]) = 0; + (b[5] => z[27]) = 0; + (b[6] => z[27]) = 0; + (b[7] => z[27]) = 0; + (b[8] => z[27]) = 0; + (b[9] => z[27]) = 0; + (b[10] => z[27]) = 0; + (b[11] => z[27]) = 0; + (b[12] => z[27]) = 0; + (b[13] => z[27]) = 0; + (b[14] => z[27]) = 0; + (b[15] => z[27]) = 0; + (b[16] => z[27]) = 0; + (b[17] => z[27]) = 0; + (a[0] => z[28]) = 0; + (a[1] => z[28]) = 0; + (a[2] => z[28]) = 0; + (a[3] => z[28]) = 0; + (a[4] => z[28]) = 0; + (a[5] => z[28]) = 0; + (a[6] => z[28]) = 0; + (a[7] => z[28]) = 0; + (a[8] => z[28]) = 0; + (a[9] => z[28]) = 0; + (a[10] => z[28]) = 0; + (a[11] => z[28]) = 0; + (a[12] => z[28]) = 0; + (a[13] => z[28]) = 0; + (a[14] => z[28]) = 0; + (a[15] => z[28]) = 0; + (a[16] => z[28]) = 0; + (a[17] => z[28]) = 0; + (a[18] => z[28]) = 0; + (a[19] => z[28]) = 0; + (b[0] => z[28]) = 0; + (b[1] => z[28]) = 0; + (b[2] => z[28]) = 0; + (b[3] => z[28]) = 0; + (b[4] => z[28]) = 0; + (b[5] => z[28]) = 0; + (b[6] => z[28]) = 0; + (b[7] => z[28]) = 0; + (b[8] => z[28]) = 0; + (b[9] => z[28]) = 0; + (b[10] => z[28]) = 0; + (b[11] => z[28]) = 0; + (b[12] => z[28]) = 0; + (b[13] => z[28]) = 0; + (b[14] => z[28]) = 0; + (b[15] => z[28]) = 0; + (b[16] => z[28]) = 0; + (b[17] => z[28]) = 0; + (a[0] => z[29]) = 0; + (a[1] => z[29]) = 0; + (a[2] => z[29]) = 0; + (a[3] => z[29]) = 0; + (a[4] => z[29]) = 0; + (a[5] => z[29]) = 0; + (a[6] => z[29]) = 0; + (a[7] => z[29]) = 0; + (a[8] => z[29]) = 0; + (a[9] => z[29]) = 0; + (a[10] => z[29]) = 0; + (a[11] => z[29]) = 0; + (a[12] => z[29]) = 0; + (a[13] => z[29]) = 0; + (a[14] => z[29]) = 0; + (a[15] => z[29]) = 0; + (a[16] => z[29]) = 0; + (a[17] => z[29]) = 0; + (a[18] => z[29]) = 0; + (a[19] => z[29]) = 0; + (b[0] => z[29]) = 0; + (b[1] => z[29]) = 0; + (b[2] => z[29]) = 0; + (b[3] => z[29]) = 0; + (b[4] => z[29]) = 0; + (b[5] => z[29]) = 0; + (b[6] => z[29]) = 0; + (b[7] => z[29]) = 0; + (b[8] => z[29]) = 0; + (b[9] => z[29]) = 0; + (b[10] => z[29]) = 0; + (b[11] => z[29]) = 0; + (b[12] => z[29]) = 0; + (b[13] => z[29]) = 0; + (b[14] => z[29]) = 0; + (b[15] => z[29]) = 0; + (b[16] => z[29]) = 0; + (b[17] => z[29]) = 0; + (a[0] => z[30]) = 0; + (a[1] => z[30]) = 0; + (a[2] => z[30]) = 0; + (a[3] => z[30]) = 0; + (a[4] => z[30]) = 0; + (a[5] => z[30]) = 0; + (a[6] => z[30]) = 0; + (a[7] => z[30]) = 0; + (a[8] => z[30]) = 0; + (a[9] => z[30]) = 0; + (a[10] => z[30]) = 0; + (a[11] => z[30]) = 0; + (a[12] => z[30]) = 0; + (a[13] => z[30]) = 0; + (a[14] => z[30]) = 0; + (a[15] => z[30]) = 0; + (a[16] => z[30]) = 0; + (a[17] => z[30]) = 0; + (a[18] => z[30]) = 0; + (a[19] => z[30]) = 0; + (b[0] => z[30]) = 0; + (b[1] => z[30]) = 0; + (b[2] => z[30]) = 0; + (b[3] => z[30]) = 0; + (b[4] => z[30]) = 0; + (b[5] => z[30]) = 0; + (b[6] => z[30]) = 0; + (b[7] => z[30]) = 0; + (b[8] => z[30]) = 0; + (b[9] => z[30]) = 0; + (b[10] => z[30]) = 0; + (b[11] => z[30]) = 0; + (b[12] => z[30]) = 0; + (b[13] => z[30]) = 0; + (b[14] => z[30]) = 0; + (b[15] => z[30]) = 0; + (b[16] => z[30]) = 0; + (b[17] => z[30]) = 0; + (a[0] => z[31]) = 0; + (a[1] => z[31]) = 0; + (a[2] => z[31]) = 0; + (a[3] => z[31]) = 0; + (a[4] => z[31]) = 0; + (a[5] => z[31]) = 0; + (a[6] => z[31]) = 0; + (a[7] => z[31]) = 0; + (a[8] => z[31]) = 0; + (a[9] => z[31]) = 0; + (a[10] => z[31]) = 0; + (a[11] => z[31]) = 0; + (a[12] => z[31]) = 0; + (a[13] => z[31]) = 0; + (a[14] => z[31]) = 0; + (a[15] => z[31]) = 0; + (a[16] => z[31]) = 0; + (a[17] => z[31]) = 0; + (a[18] => z[31]) = 0; + (a[19] => z[31]) = 0; + (b[0] => z[31]) = 0; + (b[1] => z[31]) = 0; + (b[2] => z[31]) = 0; + (b[3] => z[31]) = 0; + (b[4] => z[31]) = 0; + (b[5] => z[31]) = 0; + (b[6] => z[31]) = 0; + (b[7] => z[31]) = 0; + (b[8] => z[31]) = 0; + (b[9] => z[31]) = 0; + (b[10] => z[31]) = 0; + (b[11] => z[31]) = 0; + (b[12] => z[31]) = 0; + (b[13] => z[31]) = 0; + (b[14] => z[31]) = 0; + (b[15] => z[31]) = 0; + (b[16] => z[31]) = 0; + (b[17] => z[31]) = 0; + (a[0] => z[32]) = 0; + (a[1] => z[32]) = 0; + (a[2] => z[32]) = 0; + (a[3] => z[32]) = 0; + (a[4] => z[32]) = 0; + (a[5] => z[32]) = 0; + (a[6] => z[32]) = 0; + (a[7] => z[32]) = 0; + (a[8] => z[32]) = 0; + (a[9] => z[32]) = 0; + (a[10] => z[32]) = 0; + (a[11] => z[32]) = 0; + (a[12] => z[32]) = 0; + (a[13] => z[32]) = 0; + (a[14] => z[32]) = 0; + (a[15] => z[32]) = 0; + (a[16] => z[32]) = 0; + (a[17] => z[32]) = 0; + (a[18] => z[32]) = 0; + (a[19] => z[32]) = 0; + (b[0] => z[32]) = 0; + (b[1] => z[32]) = 0; + (b[2] => z[32]) = 0; + (b[3] => z[32]) = 0; + (b[4] => z[32]) = 0; + (b[5] => z[32]) = 0; + (b[6] => z[32]) = 0; + (b[7] => z[32]) = 0; + (b[8] => z[32]) = 0; + (b[9] => z[32]) = 0; + (b[10] => z[32]) = 0; + (b[11] => z[32]) = 0; + (b[12] => z[32]) = 0; + (b[13] => z[32]) = 0; + (b[14] => z[32]) = 0; + (b[15] => z[32]) = 0; + (b[16] => z[32]) = 0; + (b[17] => z[32]) = 0; + (a[0] => z[33]) = 0; + (a[1] => z[33]) = 0; + (a[2] => z[33]) = 0; + (a[3] => z[33]) = 0; + (a[4] => z[33]) = 0; + (a[5] => z[33]) = 0; + (a[6] => z[33]) = 0; + (a[7] => z[33]) = 0; + (a[8] => z[33]) = 0; + (a[9] => z[33]) = 0; + (a[10] => z[33]) = 0; + (a[11] => z[33]) = 0; + (a[12] => z[33]) = 0; + (a[13] => z[33]) = 0; + (a[14] => z[33]) = 0; + (a[15] => z[33]) = 0; + (a[16] => z[33]) = 0; + (a[17] => z[33]) = 0; + (a[18] => z[33]) = 0; + (a[19] => z[33]) = 0; + (b[0] => z[33]) = 0; + (b[1] => z[33]) = 0; + (b[2] => z[33]) = 0; + (b[3] => z[33]) = 0; + (b[4] => z[33]) = 0; + (b[5] => z[33]) = 0; + (b[6] => z[33]) = 0; + (b[7] => z[33]) = 0; + (b[8] => z[33]) = 0; + (b[9] => z[33]) = 0; + (b[10] => z[33]) = 0; + (b[11] => z[33]) = 0; + (b[12] => z[33]) = 0; + (b[13] => z[33]) = 0; + (b[14] => z[33]) = 0; + (b[15] => z[33]) = 0; + (b[16] => z[33]) = 0; + (b[17] => z[33]) = 0; + (a[0] => z[34]) = 0; + (a[1] => z[34]) = 0; + (a[2] => z[34]) = 0; + (a[3] => z[34]) = 0; + (a[4] => z[34]) = 0; + (a[5] => z[34]) = 0; + (a[6] => z[34]) = 0; + (a[7] => z[34]) = 0; + (a[8] => z[34]) = 0; + (a[9] => z[34]) = 0; + (a[10] => z[34]) = 0; + (a[11] => z[34]) = 0; + (a[12] => z[34]) = 0; + (a[13] => z[34]) = 0; + (a[14] => z[34]) = 0; + (a[15] => z[34]) = 0; + (a[16] => z[34]) = 0; + (a[17] => z[34]) = 0; + (a[18] => z[34]) = 0; + (a[19] => z[34]) = 0; + (b[0] => z[34]) = 0; + (b[1] => z[34]) = 0; + (b[2] => z[34]) = 0; + (b[3] => z[34]) = 0; + (b[4] => z[34]) = 0; + (b[5] => z[34]) = 0; + (b[6] => z[34]) = 0; + (b[7] => z[34]) = 0; + (b[8] => z[34]) = 0; + (b[9] => z[34]) = 0; + (b[10] => z[34]) = 0; + (b[11] => z[34]) = 0; + (b[12] => z[34]) = 0; + (b[13] => z[34]) = 0; + (b[14] => z[34]) = 0; + (b[15] => z[34]) = 0; + (b[16] => z[34]) = 0; + (b[17] => z[34]) = 0; + (a[0] => z[35]) = 0; + (a[1] => z[35]) = 0; + (a[2] => z[35]) = 0; + (a[3] => z[35]) = 0; + (a[4] => z[35]) = 0; + (a[5] => z[35]) = 0; + (a[6] => z[35]) = 0; + (a[7] => z[35]) = 0; + (a[8] => z[35]) = 0; + (a[9] => z[35]) = 0; + (a[10] => z[35]) = 0; + (a[11] => z[35]) = 0; + (a[12] => z[35]) = 0; + (a[13] => z[35]) = 0; + (a[14] => z[35]) = 0; + (a[15] => z[35]) = 0; + (a[16] => z[35]) = 0; + (a[17] => z[35]) = 0; + (a[18] => z[35]) = 0; + (a[19] => z[35]) = 0; + (b[0] => z[35]) = 0; + (b[1] => z[35]) = 0; + (b[2] => z[35]) = 0; + (b[3] => z[35]) = 0; + (b[4] => z[35]) = 0; + (b[5] => z[35]) = 0; + (b[6] => z[35]) = 0; + (b[7] => z[35]) = 0; + (b[8] => z[35]) = 0; + (b[9] => z[35]) = 0; + (b[10] => z[35]) = 0; + (b[11] => z[35]) = 0; + (b[12] => z[35]) = 0; + (b[13] => z[35]) = 0; + (b[14] => z[35]) = 0; + (b[15] => z[35]) = 0; + (b[16] => z[35]) = 0; + (b[17] => z[35]) = 0; + (a[0] => z[36]) = 0; + (a[1] => z[36]) = 0; + (a[2] => z[36]) = 0; + (a[3] => z[36]) = 0; + (a[4] => z[36]) = 0; + (a[5] => z[36]) = 0; + (a[6] => z[36]) = 0; + (a[7] => z[36]) = 0; + (a[8] => z[36]) = 0; + (a[9] => z[36]) = 0; + (a[10] => z[36]) = 0; + (a[11] => z[36]) = 0; + (a[12] => z[36]) = 0; + (a[13] => z[36]) = 0; + (a[14] => z[36]) = 0; + (a[15] => z[36]) = 0; + (a[16] => z[36]) = 0; + (a[17] => z[36]) = 0; + (a[18] => z[36]) = 0; + (a[19] => z[36]) = 0; + (b[0] => z[36]) = 0; + (b[1] => z[36]) = 0; + (b[2] => z[36]) = 0; + (b[3] => z[36]) = 0; + (b[4] => z[36]) = 0; + (b[5] => z[36]) = 0; + (b[6] => z[36]) = 0; + (b[7] => z[36]) = 0; + (b[8] => z[36]) = 0; + (b[9] => z[36]) = 0; + (b[10] => z[36]) = 0; + (b[11] => z[36]) = 0; + (b[12] => z[36]) = 0; + (b[13] => z[36]) = 0; + (b[14] => z[36]) = 0; + (b[15] => z[36]) = 0; + (b[16] => z[36]) = 0; + (b[17] => z[36]) = 0; + (a[0] => z[37]) = 0; + (a[1] => z[37]) = 0; + (a[2] => z[37]) = 0; + (a[3] => z[37]) = 0; + (a[4] => z[37]) = 0; + (a[5] => z[37]) = 0; + (a[6] => z[37]) = 0; + (a[7] => z[37]) = 0; + (a[8] => z[37]) = 0; + (a[9] => z[37]) = 0; + (a[10] => z[37]) = 0; + (a[11] => z[37]) = 0; + (a[12] => z[37]) = 0; + (a[13] => z[37]) = 0; + (a[14] => z[37]) = 0; + (a[15] => z[37]) = 0; + (a[16] => z[37]) = 0; + (a[17] => z[37]) = 0; + (a[18] => z[37]) = 0; + (a[19] => z[37]) = 0; + (b[0] => z[37]) = 0; + (b[1] => z[37]) = 0; + (b[2] => z[37]) = 0; + (b[3] => z[37]) = 0; + (b[4] => z[37]) = 0; + (b[5] => z[37]) = 0; + (b[6] => z[37]) = 0; + (b[7] => z[37]) = 0; + (b[8] => z[37]) = 0; + (b[9] => z[37]) = 0; + (b[10] => z[37]) = 0; + (b[11] => z[37]) = 0; + (b[12] => z[37]) = 0; + (b[13] => z[37]) = 0; + (b[14] => z[37]) = 0; + (b[15] => z[37]) = 0; + (b[16] => z[37]) = 0; + (b[17] => z[37]) = 0; + endspecify +`endif + +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, + input wire reset, + + 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 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), + .acc_fir(6'b0), + .z(z), + .dly_b(), + + .f_mode(f_mode), + + .feedback(feedback), + .load_acc(1'b0), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset), + + .output_select(output_select), // unregistered output: a * b (0) + .saturate_enable(1'b0), + .shift_right(6'b0), + .round(1'b0), + .subtract(1'b0), + .register_inputs(register_inputs) // registered inputs + ); + +`ifdef SDF_SIM + specify + (posedge clk => (z +: a)) = 0; + (posedge clk => (z +: b)) = 0; + $setuphold(posedge clk, a, 0, 0); + $setuphold(posedge clk, b, 0, 0); + $setuphold(posedge clk, feedback, 0, 0); + endspecify +`endif + +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, + input wire reset, + + 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 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), + .acc_fir(6'b0), + .z(z), + .dly_b(), + + .f_mode(f_mode), + + .feedback(feedback), + .load_acc(1'b0), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset), + + .output_select(output_select), // registered output: a * b (4) + .saturate_enable(1'b0), + .shift_right(6'b0), + .round(1'b0), + .subtract(1'b0), + .register_inputs(register_inputs) // unregistered inputs + ); + +`ifdef SDF_SIM + specify + (posedge clk => (z +: a)) = 0; + (posedge clk => (z +: b)) = 0; + $setuphold(posedge clk, a, 0, 0); + $setuphold(posedge clk, b, 0, 0); + $setuphold(posedge clk, feedback, 0, 0); + endspecify +`endif + +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, + input wire reset, + + 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 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), + .acc_fir(6'b0), + .z(z), + .dly_b(), + + .f_mode(f_mode), + + .feedback(feedback), + .load_acc(1'b0), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + .clk(clk), + .reset(reset), + + .output_select(output_select), // registered output: a * b (4) + .saturate_enable(1'b0), + .shift_right(6'b0), + .round(1'b0), + .subtract(1'b0), + .register_inputs(register_inputs) // registered inputs + ); + +`ifdef SDF_SIM + specify + (posedge clk => (z +: a)) = 0; + (posedge clk => (z +: b)) = 0; + $setuphold(posedge clk, a, 0, 0); + $setuphold(posedge clk, b, 0, 0); + $setuphold(posedge clk, feedback, 0, 0); + endspecify +`endif + +endmodule + +module QL_DSP2_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 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]; + + QL_DSP2 #( + .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .dly_b(), + .z(z), + + .f_mode(f_mode), + + .feedback(feedback), + .acc_fir(acc_fir), + .load_acc(load_acc), + + .unsigned_a(unsigned_a), + .unsigned_b(unsigned_b), + + //.clk(1'b0), + .reset(reset), + + .output_select(output_select), // unregistered output: ACCin (2, 3) + .saturate_enable(saturate_enable), + .shift_right(shift_right), + .round(round), + .subtract(subtract), + .register_inputs(register_inputs) // unregistered inputs + ); + +`ifdef SDF_SIM + specify + (a[0] => z[0]) = 0; + (a[1] => z[0]) = 0; + (a[2] => z[0]) = 0; + (a[3] => z[0]) = 0; + (a[4] => z[0]) = 0; + (a[5] => z[0]) = 0; + (a[6] => z[0]) = 0; + (a[7] => z[0]) = 0; + (a[8] => z[0]) = 0; + (a[9] => z[0]) = 0; + (a[10] => z[0]) = 0; + (a[11] => z[0]) = 0; + (a[12] => z[0]) = 0; + (a[13] => z[0]) = 0; + (a[14] => z[0]) = 0; + (a[15] => z[0]) = 0; + (a[16] => z[0]) = 0; + (a[17] => z[0]) = 0; + (a[18] => z[0]) = 0; + (a[19] => z[0]) = 0; + (b[0] => z[0]) = 0; + (b[1] => z[0]) = 0; + (b[2] => z[0]) = 0; + (b[3] => z[0]) = 0; + (b[4] => z[0]) = 0; + (b[5] => z[0]) = 0; + (b[6] => z[0]) = 0; + (b[7] => z[0]) = 0; + (b[8] => z[0]) = 0; + (b[9] => z[0]) = 0; + (b[10] => z[0]) = 0; + (b[11] => z[0]) = 0; + (b[12] => z[0]) = 0; + (b[13] => z[0]) = 0; + (b[14] => z[0]) = 0; + (b[15] => z[0]) = 0; + (b[16] => z[0]) = 0; + (b[17] => z[0]) = 0; + (a[0] => z[1]) = 0; + (a[1] => z[1]) = 0; + (a[2] => z[1]) = 0; + (a[3] => z[1]) = 0; + (a[4] => z[1]) = 0; + (a[5] => z[1]) = 0; + (a[6] => z[1]) = 0; + (a[7] => z[1]) = 0; + (a[8] => z[1]) = 0; + (a[9] => z[1]) = 0; + (a[10] => z[1]) = 0; + (a[11] => z[1]) = 0; + (a[12] => z[1]) = 0; + (a[13] => z[1]) = 0; + (a[14] => z[1]) = 0; + (a[15] => z[1]) = 0; + (a[16] => z[1]) = 0; + (a[17] => z[1]) = 0; + (a[18] => z[1]) = 0; + (a[19] => z[1]) = 0; + (b[0] => z[1]) = 0; + (b[1] => z[1]) = 0; + (b[2] => z[1]) = 0; + (b[3] => z[1]) = 0; + (b[4] => z[1]) = 0; + (b[5] => z[1]) = 0; + (b[6] => z[1]) = 0; + (b[7] => z[1]) = 0; + (b[8] => z[1]) = 0; + (b[9] => z[1]) = 0; + (b[10] => z[1]) = 0; + (b[11] => z[1]) = 0; + (b[12] => z[1]) = 0; + (b[13] => z[1]) = 0; + (b[14] => z[1]) = 0; + (b[15] => z[1]) = 0; + (b[16] => z[1]) = 0; + (b[17] => z[1]) = 0; + (a[0] => z[2]) = 0; + (a[1] => z[2]) = 0; + (a[2] => z[2]) = 0; + (a[3] => z[2]) = 0; + (a[4] => z[2]) = 0; + (a[5] => z[2]) = 0; + (a[6] => z[2]) = 0; + (a[7] => z[2]) = 0; + (a[8] => z[2]) = 0; + (a[9] => z[2]) = 0; + (a[10] => z[2]) = 0; + (a[11] => z[2]) = 0; + (a[12] => z[2]) = 0; + (a[13] => z[2]) = 0; + (a[14] => z[2]) = 0; + (a[15] => z[2]) = 0; + (a[16] => z[2]) = 0; + (a[17] => z[2]) = 0; + (a[18] => z[2]) = 0; + (a[19] => z[2]) = 0; + (b[0] => z[2]) = 0; + (b[1] => z[2]) = 0; + (b[2] => z[2]) = 0; + (b[3] => z[2]) = 0; + (b[4] => z[2]) = 0; + (b[5] => z[2]) = 0; + (b[6] => z[2]) = 0; + (b[7] => z[2]) = 0; + (b[8] => z[2]) = 0; + (b[9] => z[2]) = 0; + (b[10] => z[2]) = 0; + (b[11] => z[2]) = 0; + (b[12] => z[2]) = 0; + (b[13] => z[2]) = 0; + (b[14] => z[2]) = 0; + (b[15] => z[2]) = 0; + (b[16] => z[2]) = 0; + (b[17] => z[2]) = 0; + (a[0] => z[3]) = 0; + (a[1] => z[3]) = 0; + (a[2] => z[3]) = 0; + (a[3] => z[3]) = 0; + (a[4] => z[3]) = 0; + (a[5] => z[3]) = 0; + (a[6] => z[3]) = 0; + (a[7] => z[3]) = 0; + (a[8] => z[3]) = 0; + (a[9] => z[3]) = 0; + (a[10] => z[3]) = 0; + (a[11] => z[3]) = 0; + (a[12] => z[3]) = 0; + (a[13] => z[3]) = 0; + (a[14] => z[3]) = 0; + (a[15] => z[3]) = 0; + (a[16] => z[3]) = 0; + (a[17] => z[3]) = 0; + (a[18] => z[3]) = 0; + (a[19] => z[3]) = 0; + (b[0] => z[3]) = 0; + (b[1] => z[3]) = 0; + (b[2] => z[3]) = 0; + (b[3] => z[3]) = 0; + (b[4] => z[3]) = 0; + (b[5] => z[3]) = 0; + (b[6] => z[3]) = 0; + (b[7] => z[3]) = 0; + (b[8] => z[3]) = 0; + (b[9] => z[3]) = 0; + (b[10] => z[3]) = 0; + (b[11] => z[3]) = 0; + (b[12] => z[3]) = 0; + (b[13] => z[3]) = 0; + (b[14] => z[3]) = 0; + (b[15] => z[3]) = 0; + (b[16] => z[3]) = 0; + (b[17] => z[3]) = 0; + (a[0] => z[4]) = 0; + (a[1] => z[4]) = 0; + (a[2] => z[4]) = 0; + (a[3] => z[4]) = 0; + (a[4] => z[4]) = 0; + (a[5] => z[4]) = 0; + (a[6] => z[4]) = 0; + (a[7] => z[4]) = 0; + (a[8] => z[4]) = 0; + (a[9] => z[4]) = 0; + (a[10] => z[4]) = 0; + (a[11] => z[4]) = 0; + (a[12] => z[4]) = 0; + (a[13] => z[4]) = 0; + (a[14] => z[4]) = 0; + (a[15] => z[4]) = 0; + (a[16] => z[4]) = 0; + (a[17] => z[4]) = 0; + (a[18] => z[4]) = 0; + (a[19] => z[4]) = 0; + (b[0] => z[4]) = 0; + (b[1] => z[4]) = 0; + (b[2] => z[4]) = 0; + (b[3] => z[4]) = 0; + (b[4] => z[4]) = 0; + (b[5] => z[4]) = 0; + (b[6] => z[4]) = 0; + (b[7] => z[4]) = 0; + (b[8] => z[4]) = 0; + (b[9] => z[4]) = 0; + (b[10] => z[4]) = 0; + (b[11] => z[4]) = 0; + (b[12] => z[4]) = 0; + (b[13] => z[4]) = 0; + (b[14] => z[4]) = 0; + (b[15] => z[4]) = 0; + (b[16] => z[4]) = 0; + (b[17] => z[4]) = 0; + (a[0] => z[5]) = 0; + (a[1] => z[5]) = 0; + (a[2] => z[5]) = 0; + (a[3] => z[5]) = 0; + (a[4] => z[5]) = 0; + (a[5] => z[5]) = 0; + (a[6] => z[5]) = 0; + (a[7] => z[5]) = 0; + (a[8] => z[5]) = 0; + (a[9] => z[5]) = 0; + (a[10] => z[5]) = 0; + (a[11] => z[5]) = 0; + (a[12] => z[5]) = 0; + (a[13] => z[5]) = 0; + (a[14] => z[5]) = 0; + (a[15] => z[5]) = 0; + (a[16] => z[5]) = 0; + (a[17] => z[5]) = 0; + (a[18] => z[5]) = 0; + (a[19] => z[5]) = 0; + (b[0] => z[5]) = 0; + (b[1] => z[5]) = 0; + (b[2] => z[5]) = 0; + (b[3] => z[5]) = 0; + (b[4] => z[5]) = 0; + (b[5] => z[5]) = 0; + (b[6] => z[5]) = 0; + (b[7] => z[5]) = 0; + (b[8] => z[5]) = 0; + (b[9] => z[5]) = 0; + (b[10] => z[5]) = 0; + (b[11] => z[5]) = 0; + (b[12] => z[5]) = 0; + (b[13] => z[5]) = 0; + (b[14] => z[5]) = 0; + (b[15] => z[5]) = 0; + (b[16] => z[5]) = 0; + (b[17] => z[5]) = 0; + (a[0] => z[6]) = 0; + (a[1] => z[6]) = 0; + (a[2] => z[6]) = 0; + (a[3] => z[6]) = 0; + (a[4] => z[6]) = 0; + (a[5] => z[6]) = 0; + (a[6] => z[6]) = 0; + (a[7] => z[6]) = 0; + (a[8] => z[6]) = 0; + (a[9] => z[6]) = 0; + (a[10] => z[6]) = 0; + (a[11] => z[6]) = 0; + (a[12] => z[6]) = 0; + (a[13] => z[6]) = 0; + (a[14] => z[6]) = 0; + (a[15] => z[6]) = 0; + (a[16] => z[6]) = 0; + (a[17] => z[6]) = 0; + (a[18] => z[6]) = 0; + (a[19] => z[6]) = 0; + (b[0] => z[6]) = 0; + (b[1] => z[6]) = 0; + (b[2] => z[6]) = 0; + (b[3] => z[6]) = 0; + (b[4] => z[6]) = 0; + (b[5] => z[6]) = 0; + (b[6] => z[6]) = 0; + (b[7] => z[6]) = 0; + (b[8] => z[6]) = 0; + (b[9] => z[6]) = 0; + (b[10] => z[6]) = 0; + (b[11] => z[6]) = 0; + (b[12] => z[6]) = 0; + (b[13] => z[6]) = 0; + (b[14] => z[6]) = 0; + (b[15] => z[6]) = 0; + (b[16] => z[6]) = 0; + (b[17] => z[6]) = 0; + (a[0] => z[7]) = 0; + (a[1] => z[7]) = 0; + (a[2] => z[7]) = 0; + (a[3] => z[7]) = 0; + (a[4] => z[7]) = 0; + (a[5] => z[7]) = 0; + (a[6] => z[7]) = 0; + (a[7] => z[7]) = 0; + (a[8] => z[7]) = 0; + (a[9] => z[7]) = 0; + (a[10] => z[7]) = 0; + (a[11] => z[7]) = 0; + (a[12] => z[7]) = 0; + (a[13] => z[7]) = 0; + (a[14] => z[7]) = 0; + (a[15] => z[7]) = 0; + (a[16] => z[7]) = 0; + (a[17] => z[7]) = 0; + (a[18] => z[7]) = 0; + (a[19] => z[7]) = 0; + (b[0] => z[7]) = 0; + (b[1] => z[7]) = 0; + (b[2] => z[7]) = 0; + (b[3] => z[7]) = 0; + (b[4] => z[7]) = 0; + (b[5] => z[7]) = 0; + (b[6] => z[7]) = 0; + (b[7] => z[7]) = 0; + (b[8] => z[7]) = 0; + (b[9] => z[7]) = 0; + (b[10] => z[7]) = 0; + (b[11] => z[7]) = 0; + (b[12] => z[7]) = 0; + (b[13] => z[7]) = 0; + (b[14] => z[7]) = 0; + (b[15] => z[7]) = 0; + (b[16] => z[7]) = 0; + (b[17] => z[7]) = 0; + (a[0] => z[8]) = 0; + (a[1] => z[8]) = 0; + (a[2] => z[8]) = 0; + (a[3] => z[8]) = 0; + (a[4] => z[8]) = 0; + (a[5] => z[8]) = 0; + (a[6] => z[8]) = 0; + (a[7] => z[8]) = 0; + (a[8] => z[8]) = 0; + (a[9] => z[8]) = 0; + (a[10] => z[8]) = 0; + (a[11] => z[8]) = 0; + (a[12] => z[8]) = 0; + (a[13] => z[8]) = 0; + (a[14] => z[8]) = 0; + (a[15] => z[8]) = 0; + (a[16] => z[8]) = 0; + (a[17] => z[8]) = 0; + (a[18] => z[8]) = 0; + (a[19] => z[8]) = 0; + (b[0] => z[8]) = 0; + (b[1] => z[8]) = 0; + (b[2] => z[8]) = 0; + (b[3] => z[8]) = 0; + (b[4] => z[8]) = 0; + (b[5] => z[8]) = 0; + (b[6] => z[8]) = 0; + (b[7] => z[8]) = 0; + (b[8] => z[8]) = 0; + (b[9] => z[8]) = 0; + (b[10] => z[8]) = 0; + (b[11] => z[8]) = 0; + (b[12] => z[8]) = 0; + (b[13] => z[8]) = 0; + (b[14] => z[8]) = 0; + (b[15] => z[8]) = 0; + (b[16] => z[8]) = 0; + (b[17] => z[8]) = 0; + (a[0] => z[9]) = 0; + (a[1] => z[9]) = 0; + (a[2] => z[9]) = 0; + (a[3] => z[9]) = 0; + (a[4] => z[9]) = 0; + (a[5] => z[9]) = 0; + (a[6] => z[9]) = 0; + (a[7] => z[9]) = 0; + (a[8] => z[9]) = 0; + (a[9] => z[9]) = 0; + (a[10] => z[9]) = 0; + (a[11] => z[9]) = 0; + (a[12] => z[9]) = 0; + (a[13] => z[9]) = 0; + (a[14] => z[9]) = 0; + (a[15] => z[9]) = 0; + (a[16] => z[9]) = 0; + (a[17] => z[9]) = 0; + (a[18] => z[9]) = 0; + (a[19] => z[9]) = 0; + (b[0] => z[9]) = 0; + (b[1] => z[9]) = 0; + (b[2] => z[9]) = 0; + (b[3] => z[9]) = 0; + (b[4] => z[9]) = 0; + (b[5] => z[9]) = 0; + (b[6] => z[9]) = 0; + (b[7] => z[9]) = 0; + (b[8] => z[9]) = 0; + (b[9] => z[9]) = 0; + (b[10] => z[9]) = 0; + (b[11] => z[9]) = 0; + (b[12] => z[9]) = 0; + (b[13] => z[9]) = 0; + (b[14] => z[9]) = 0; + (b[15] => z[9]) = 0; + (b[16] => z[9]) = 0; + (b[17] => z[9]) = 0; + (a[0] => z[10]) = 0; + (a[1] => z[10]) = 0; + (a[2] => z[10]) = 0; + (a[3] => z[10]) = 0; + (a[4] => z[10]) = 0; + (a[5] => z[10]) = 0; + (a[6] => z[10]) = 0; + (a[7] => z[10]) = 0; + (a[8] => z[10]) = 0; + (a[9] => z[10]) = 0; + (a[10] => z[10]) = 0; + (a[11] => z[10]) = 0; + (a[12] => z[10]) = 0; + (a[13] => z[10]) = 0; + (a[14] => z[10]) = 0; + (a[15] => z[10]) = 0; + (a[16] => z[10]) = 0; + (a[17] => z[10]) = 0; + (a[18] => z[10]) = 0; + (a[19] => z[10]) = 0; + (b[0] => z[10]) = 0; + (b[1] => z[10]) = 0; + (b[2] => z[10]) = 0; + (b[3] => z[10]) = 0; + (b[4] => z[10]) = 0; + (b[5] => z[10]) = 0; + (b[6] => z[10]) = 0; + (b[7] => z[10]) = 0; + (b[8] => z[10]) = 0; + (b[9] => z[10]) = 0; + (b[10] => z[10]) = 0; + (b[11] => z[10]) = 0; + (b[12] => z[10]) = 0; + (b[13] => z[10]) = 0; + (b[14] => z[10]) = 0; + (b[15] => z[10]) = 0; + (b[16] => z[10]) = 0; + (b[17] => z[10]) = 0; + (a[0] => z[11]) = 0; + (a[1] => z[11]) = 0; + (a[2] => z[11]) = 0; + (a[3] => z[11]) = 0; + (a[4] => z[11]) = 0; + (a[5] => z[11]) = 0; + (a[6] => z[11]) = 0; + (a[7] => z[11]) = 0; + (a[8] => z[11]) = 0; + (a[9] => z[11]) = 0; + (a[10] => z[11]) = 0; + (a[11] => z[11]) = 0; + (a[12] => z[11]) = 0; + (a[13] => z[11]) = 0; + (a[14] => z[11]) = 0; + (a[15] => z[11]) = 0; + (a[16] => z[11]) = 0; + (a[17] => z[11]) = 0; + (a[18] => z[11]) = 0; + (a[19] => z[11]) = 0; + (b[0] => z[11]) = 0; + (b[1] => z[11]) = 0; + (b[2] => z[11]) = 0; + (b[3] => z[11]) = 0; + (b[4] => z[11]) = 0; + (b[5] => z[11]) = 0; + (b[6] => z[11]) = 0; + (b[7] => z[11]) = 0; + (b[8] => z[11]) = 0; + (b[9] => z[11]) = 0; + (b[10] => z[11]) = 0; + (b[11] => z[11]) = 0; + (b[12] => z[11]) = 0; + (b[13] => z[11]) = 0; + (b[14] => z[11]) = 0; + (b[15] => z[11]) = 0; + (b[16] => z[11]) = 0; + (b[17] => z[11]) = 0; + (a[0] => z[12]) = 0; + (a[1] => z[12]) = 0; + (a[2] => z[12]) = 0; + (a[3] => z[12]) = 0; + (a[4] => z[12]) = 0; + (a[5] => z[12]) = 0; + (a[6] => z[12]) = 0; + (a[7] => z[12]) = 0; + (a[8] => z[12]) = 0; + (a[9] => z[12]) = 0; + (a[10] => z[12]) = 0; + (a[11] => z[12]) = 0; + (a[12] => z[12]) = 0; + (a[13] => z[12]) = 0; + (a[14] => z[12]) = 0; + (a[15] => z[12]) = 0; + (a[16] => z[12]) = 0; + (a[17] => z[12]) = 0; + (a[18] => z[12]) = 0; + (a[19] => z[12]) = 0; + (b[0] => z[12]) = 0; + (b[1] => z[12]) = 0; + (b[2] => z[12]) = 0; + (b[3] => z[12]) = 0; + (b[4] => z[12]) = 0; + (b[5] => z[12]) = 0; + (b[6] => z[12]) = 0; + (b[7] => z[12]) = 0; + (b[8] => z[12]) = 0; + (b[9] => z[12]) = 0; + (b[10] => z[12]) = 0; + (b[11] => z[12]) = 0; + (b[12] => z[12]) = 0; + (b[13] => z[12]) = 0; + (b[14] => z[12]) = 0; + (b[15] => z[12]) = 0; + (b[16] => z[12]) = 0; + (b[17] => z[12]) = 0; + (a[0] => z[13]) = 0; + (a[1] => z[13]) = 0; + (a[2] => z[13]) = 0; + (a[3] => z[13]) = 0; + (a[4] => z[13]) = 0; + (a[5] => z[13]) = 0; + (a[6] => z[13]) = 0; + (a[7] => z[13]) = 0; + (a[8] => z[13]) = 0; + (a[9] => z[13]) = 0; + (a[10] => z[13]) = 0; + (a[11] => z[13]) = 0; + (a[12] => z[13]) = 0; + (a[13] => z[13]) = 0; + (a[14] => z[13]) = 0; + (a[15] => z[13]) = 0; + (a[16] => z[13]) = 0; + (a[17] => z[13]) = 0; + (a[18] => z[13]) = 0; + (a[19] => z[13]) = 0; + (b[0] => z[13]) = 0; + (b[1] => z[13]) = 0; + (b[2] => z[13]) = 0; + (b[3] => z[13]) = 0; + (b[4] => z[13]) = 0; + (b[5] => z[13]) = 0; + (b[6] => z[13]) = 0; + (b[7] => z[13]) = 0; + (b[8] => z[13]) = 0; + (b[9] => z[13]) = 0; + (b[10] => z[13]) = 0; + (b[11] => z[13]) = 0; + (b[12] => z[13]) = 0; + (b[13] => z[13]) = 0; + (b[14] => z[13]) = 0; + (b[15] => z[13]) = 0; + (b[16] => z[13]) = 0; + (b[17] => z[13]) = 0; + (a[0] => z[14]) = 0; + (a[1] => z[14]) = 0; + (a[2] => z[14]) = 0; + (a[3] => z[14]) = 0; + (a[4] => z[14]) = 0; + (a[5] => z[14]) = 0; + (a[6] => z[14]) = 0; + (a[7] => z[14]) = 0; + (a[8] => z[14]) = 0; + (a[9] => z[14]) = 0; + (a[10] => z[14]) = 0; + (a[11] => z[14]) = 0; + (a[12] => z[14]) = 0; + (a[13] => z[14]) = 0; + (a[14] => z[14]) = 0; + (a[15] => z[14]) = 0; + (a[16] => z[14]) = 0; + (a[17] => z[14]) = 0; + (a[18] => z[14]) = 0; + (a[19] => z[14]) = 0; + (b[0] => z[14]) = 0; + (b[1] => z[14]) = 0; + (b[2] => z[14]) = 0; + (b[3] => z[14]) = 0; + (b[4] => z[14]) = 0; + (b[5] => z[14]) = 0; + (b[6] => z[14]) = 0; + (b[7] => z[14]) = 0; + (b[8] => z[14]) = 0; + (b[9] => z[14]) = 0; + (b[10] => z[14]) = 0; + (b[11] => z[14]) = 0; + (b[12] => z[14]) = 0; + (b[13] => z[14]) = 0; + (b[14] => z[14]) = 0; + (b[15] => z[14]) = 0; + (b[16] => z[14]) = 0; + (b[17] => z[14]) = 0; + (a[0] => z[15]) = 0; + (a[1] => z[15]) = 0; + (a[2] => z[15]) = 0; + (a[3] => z[15]) = 0; + (a[4] => z[15]) = 0; + (a[5] => z[15]) = 0; + (a[6] => z[15]) = 0; + (a[7] => z[15]) = 0; + (a[8] => z[15]) = 0; + (a[9] => z[15]) = 0; + (a[10] => z[15]) = 0; + (a[11] => z[15]) = 0; + (a[12] => z[15]) = 0; + (a[13] => z[15]) = 0; + (a[14] => z[15]) = 0; + (a[15] => z[15]) = 0; + (a[16] => z[15]) = 0; + (a[17] => z[15]) = 0; + (a[18] => z[15]) = 0; + (a[19] => z[15]) = 0; + (b[0] => z[15]) = 0; + (b[1] => z[15]) = 0; + (b[2] => z[15]) = 0; + (b[3] => z[15]) = 0; + (b[4] => z[15]) = 0; + (b[5] => z[15]) = 0; + (b[6] => z[15]) = 0; + (b[7] => z[15]) = 0; + (b[8] => z[15]) = 0; + (b[9] => z[15]) = 0; + (b[10] => z[15]) = 0; + (b[11] => z[15]) = 0; + (b[12] => z[15]) = 0; + (b[13] => z[15]) = 0; + (b[14] => z[15]) = 0; + (b[15] => z[15]) = 0; + (b[16] => z[15]) = 0; + (b[17] => z[15]) = 0; + (a[0] => z[16]) = 0; + (a[1] => z[16]) = 0; + (a[2] => z[16]) = 0; + (a[3] => z[16]) = 0; + (a[4] => z[16]) = 0; + (a[5] => z[16]) = 0; + (a[6] => z[16]) = 0; + (a[7] => z[16]) = 0; + (a[8] => z[16]) = 0; + (a[9] => z[16]) = 0; + (a[10] => z[16]) = 0; + (a[11] => z[16]) = 0; + (a[12] => z[16]) = 0; + (a[13] => z[16]) = 0; + (a[14] => z[16]) = 0; + (a[15] => z[16]) = 0; + (a[16] => z[16]) = 0; + (a[17] => z[16]) = 0; + (a[18] => z[16]) = 0; + (a[19] => z[16]) = 0; + (b[0] => z[16]) = 0; + (b[1] => z[16]) = 0; + (b[2] => z[16]) = 0; + (b[3] => z[16]) = 0; + (b[4] => z[16]) = 0; + (b[5] => z[16]) = 0; + (b[6] => z[16]) = 0; + (b[7] => z[16]) = 0; + (b[8] => z[16]) = 0; + (b[9] => z[16]) = 0; + (b[10] => z[16]) = 0; + (b[11] => z[16]) = 0; + (b[12] => z[16]) = 0; + (b[13] => z[16]) = 0; + (b[14] => z[16]) = 0; + (b[15] => z[16]) = 0; + (b[16] => z[16]) = 0; + (b[17] => z[16]) = 0; + (a[0] => z[17]) = 0; + (a[1] => z[17]) = 0; + (a[2] => z[17]) = 0; + (a[3] => z[17]) = 0; + (a[4] => z[17]) = 0; + (a[5] => z[17]) = 0; + (a[6] => z[17]) = 0; + (a[7] => z[17]) = 0; + (a[8] => z[17]) = 0; + (a[9] => z[17]) = 0; + (a[10] => z[17]) = 0; + (a[11] => z[17]) = 0; + (a[12] => z[17]) = 0; + (a[13] => z[17]) = 0; + (a[14] => z[17]) = 0; + (a[15] => z[17]) = 0; + (a[16] => z[17]) = 0; + (a[17] => z[17]) = 0; + (a[18] => z[17]) = 0; + (a[19] => z[17]) = 0; + (b[0] => z[17]) = 0; + (b[1] => z[17]) = 0; + (b[2] => z[17]) = 0; + (b[3] => z[17]) = 0; + (b[4] => z[17]) = 0; + (b[5] => z[17]) = 0; + (b[6] => z[17]) = 0; + (b[7] => z[17]) = 0; + (b[8] => z[17]) = 0; + (b[9] => z[17]) = 0; + (b[10] => z[17]) = 0; + (b[11] => z[17]) = 0; + (b[12] => z[17]) = 0; + (b[13] => z[17]) = 0; + (b[14] => z[17]) = 0; + (b[15] => z[17]) = 0; + (b[16] => z[17]) = 0; + (b[17] => z[17]) = 0; + (a[0] => z[18]) = 0; + (a[1] => z[18]) = 0; + (a[2] => z[18]) = 0; + (a[3] => z[18]) = 0; + (a[4] => z[18]) = 0; + (a[5] => z[18]) = 0; + (a[6] => z[18]) = 0; + (a[7] => z[18]) = 0; + (a[8] => z[18]) = 0; + (a[9] => z[18]) = 0; + (a[10] => z[18]) = 0; + (a[11] => z[18]) = 0; + (a[12] => z[18]) = 0; + (a[13] => z[18]) = 0; + (a[14] => z[18]) = 0; + (a[15] => z[18]) = 0; + (a[16] => z[18]) = 0; + (a[17] => z[18]) = 0; + (a[18] => z[18]) = 0; + (a[19] => z[18]) = 0; + (b[0] => z[18]) = 0; + (b[1] => z[18]) = 0; + (b[2] => z[18]) = 0; + (b[3] => z[18]) = 0; + (b[4] => z[18]) = 0; + (b[5] => z[18]) = 0; + (b[6] => z[18]) = 0; + (b[7] => z[18]) = 0; + (b[8] => z[18]) = 0; + (b[9] => z[18]) = 0; + (b[10] => z[18]) = 0; + (b[11] => z[18]) = 0; + (b[12] => z[18]) = 0; + (b[13] => z[18]) = 0; + (b[14] => z[18]) = 0; + (b[15] => z[18]) = 0; + (b[16] => z[18]) = 0; + (b[17] => z[18]) = 0; + (a[0] => z[19]) = 0; + (a[1] => z[19]) = 0; + (a[2] => z[19]) = 0; + (a[3] => z[19]) = 0; + (a[4] => z[19]) = 0; + (a[5] => z[19]) = 0; + (a[6] => z[19]) = 0; + (a[7] => z[19]) = 0; + (a[8] => z[19]) = 0; + (a[9] => z[19]) = 0; + (a[10] => z[19]) = 0; + (a[11] => z[19]) = 0; + (a[12] => z[19]) = 0; + (a[13] => z[19]) = 0; + (a[14] => z[19]) = 0; + (a[15] => z[19]) = 0; + (a[16] => z[19]) = 0; + (a[17] => z[19]) = 0; + (a[18] => z[19]) = 0; + (a[19] => z[19]) = 0; + (b[0] => z[19]) = 0; + (b[1] => z[19]) = 0; + (b[2] => z[19]) = 0; + (b[3] => z[19]) = 0; + (b[4] => z[19]) = 0; + (b[5] => z[19]) = 0; + (b[6] => z[19]) = 0; + (b[7] => z[19]) = 0; + (b[8] => z[19]) = 0; + (b[9] => z[19]) = 0; + (b[10] => z[19]) = 0; + (b[11] => z[19]) = 0; + (b[12] => z[19]) = 0; + (b[13] => z[19]) = 0; + (b[14] => z[19]) = 0; + (b[15] => z[19]) = 0; + (b[16] => z[19]) = 0; + (b[17] => z[19]) = 0; + (a[0] => z[20]) = 0; + (a[1] => z[20]) = 0; + (a[2] => z[20]) = 0; + (a[3] => z[20]) = 0; + (a[4] => z[20]) = 0; + (a[5] => z[20]) = 0; + (a[6] => z[20]) = 0; + (a[7] => z[20]) = 0; + (a[8] => z[20]) = 0; + (a[9] => z[20]) = 0; + (a[10] => z[20]) = 0; + (a[11] => z[20]) = 0; + (a[12] => z[20]) = 0; + (a[13] => z[20]) = 0; + (a[14] => z[20]) = 0; + (a[15] => z[20]) = 0; + (a[16] => z[20]) = 0; + (a[17] => z[20]) = 0; + (a[18] => z[20]) = 0; + (a[19] => z[20]) = 0; + (b[0] => z[20]) = 0; + (b[1] => z[20]) = 0; + (b[2] => z[20]) = 0; + (b[3] => z[20]) = 0; + (b[4] => z[20]) = 0; + (b[5] => z[20]) = 0; + (b[6] => z[20]) = 0; + (b[7] => z[20]) = 0; + (b[8] => z[20]) = 0; + (b[9] => z[20]) = 0; + (b[10] => z[20]) = 0; + (b[11] => z[20]) = 0; + (b[12] => z[20]) = 0; + (b[13] => z[20]) = 0; + (b[14] => z[20]) = 0; + (b[15] => z[20]) = 0; + (b[16] => z[20]) = 0; + (b[17] => z[20]) = 0; + (a[0] => z[21]) = 0; + (a[1] => z[21]) = 0; + (a[2] => z[21]) = 0; + (a[3] => z[21]) = 0; + (a[4] => z[21]) = 0; + (a[5] => z[21]) = 0; + (a[6] => z[21]) = 0; + (a[7] => z[21]) = 0; + (a[8] => z[21]) = 0; + (a[9] => z[21]) = 0; + (a[10] => z[21]) = 0; + (a[11] => z[21]) = 0; + (a[12] => z[21]) = 0; + (a[13] => z[21]) = 0; + (a[14] => z[21]) = 0; + (a[15] => z[21]) = 0; + (a[16] => z[21]) = 0; + (a[17] => z[21]) = 0; + (a[18] => z[21]) = 0; + (a[19] => z[21]) = 0; + (b[0] => z[21]) = 0; + (b[1] => z[21]) = 0; + (b[2] => z[21]) = 0; + (b[3] => z[21]) = 0; + (b[4] => z[21]) = 0; + (b[5] => z[21]) = 0; + (b[6] => z[21]) = 0; + (b[7] => z[21]) = 0; + (b[8] => z[21]) = 0; + (b[9] => z[21]) = 0; + (b[10] => z[21]) = 0; + (b[11] => z[21]) = 0; + (b[12] => z[21]) = 0; + (b[13] => z[21]) = 0; + (b[14] => z[21]) = 0; + (b[15] => z[21]) = 0; + (b[16] => z[21]) = 0; + (b[17] => z[21]) = 0; + (a[0] => z[22]) = 0; + (a[1] => z[22]) = 0; + (a[2] => z[22]) = 0; + (a[3] => z[22]) = 0; + (a[4] => z[22]) = 0; + (a[5] => z[22]) = 0; + (a[6] => z[22]) = 0; + (a[7] => z[22]) = 0; + (a[8] => z[22]) = 0; + (a[9] => z[22]) = 0; + (a[10] => z[22]) = 0; + (a[11] => z[22]) = 0; + (a[12] => z[22]) = 0; + (a[13] => z[22]) = 0; + (a[14] => z[22]) = 0; + (a[15] => z[22]) = 0; + (a[16] => z[22]) = 0; + (a[17] => z[22]) = 0; + (a[18] => z[22]) = 0; + (a[19] => z[22]) = 0; + (b[0] => z[22]) = 0; + (b[1] => z[22]) = 0; + (b[2] => z[22]) = 0; + (b[3] => z[22]) = 0; + (b[4] => z[22]) = 0; + (b[5] => z[22]) = 0; + (b[6] => z[22]) = 0; + (b[7] => z[22]) = 0; + (b[8] => z[22]) = 0; + (b[9] => z[22]) = 0; + (b[10] => z[22]) = 0; + (b[11] => z[22]) = 0; + (b[12] => z[22]) = 0; + (b[13] => z[22]) = 0; + (b[14] => z[22]) = 0; + (b[15] => z[22]) = 0; + (b[16] => z[22]) = 0; + (b[17] => z[22]) = 0; + (a[0] => z[23]) = 0; + (a[1] => z[23]) = 0; + (a[2] => z[23]) = 0; + (a[3] => z[23]) = 0; + (a[4] => z[23]) = 0; + (a[5] => z[23]) = 0; + (a[6] => z[23]) = 0; + (a[7] => z[23]) = 0; + (a[8] => z[23]) = 0; + (a[9] => z[23]) = 0; + (a[10] => z[23]) = 0; + (a[11] => z[23]) = 0; + (a[12] => z[23]) = 0; + (a[13] => z[23]) = 0; + (a[14] => z[23]) = 0; + (a[15] => z[23]) = 0; + (a[16] => z[23]) = 0; + (a[17] => z[23]) = 0; + (a[18] => z[23]) = 0; + (a[19] => z[23]) = 0; + (b[0] => z[23]) = 0; + (b[1] => z[23]) = 0; + (b[2] => z[23]) = 0; + (b[3] => z[23]) = 0; + (b[4] => z[23]) = 0; + (b[5] => z[23]) = 0; + (b[6] => z[23]) = 0; + (b[7] => z[23]) = 0; + (b[8] => z[23]) = 0; + (b[9] => z[23]) = 0; + (b[10] => z[23]) = 0; + (b[11] => z[23]) = 0; + (b[12] => z[23]) = 0; + (b[13] => z[23]) = 0; + (b[14] => z[23]) = 0; + (b[15] => z[23]) = 0; + (b[16] => z[23]) = 0; + (b[17] => z[23]) = 0; + (a[0] => z[24]) = 0; + (a[1] => z[24]) = 0; + (a[2] => z[24]) = 0; + (a[3] => z[24]) = 0; + (a[4] => z[24]) = 0; + (a[5] => z[24]) = 0; + (a[6] => z[24]) = 0; + (a[7] => z[24]) = 0; + (a[8] => z[24]) = 0; + (a[9] => z[24]) = 0; + (a[10] => z[24]) = 0; + (a[11] => z[24]) = 0; + (a[12] => z[24]) = 0; + (a[13] => z[24]) = 0; + (a[14] => z[24]) = 0; + (a[15] => z[24]) = 0; + (a[16] => z[24]) = 0; + (a[17] => z[24]) = 0; + (a[18] => z[24]) = 0; + (a[19] => z[24]) = 0; + (b[0] => z[24]) = 0; + (b[1] => z[24]) = 0; + (b[2] => z[24]) = 0; + (b[3] => z[24]) = 0; + (b[4] => z[24]) = 0; + (b[5] => z[24]) = 0; + (b[6] => z[24]) = 0; + (b[7] => z[24]) = 0; + (b[8] => z[24]) = 0; + (b[9] => z[24]) = 0; + (b[10] => z[24]) = 0; + (b[11] => z[24]) = 0; + (b[12] => z[24]) = 0; + (b[13] => z[24]) = 0; + (b[14] => z[24]) = 0; + (b[15] => z[24]) = 0; + (b[16] => z[24]) = 0; + (b[17] => z[24]) = 0; + (a[0] => z[25]) = 0; + (a[1] => z[25]) = 0; + (a[2] => z[25]) = 0; + (a[3] => z[25]) = 0; + (a[4] => z[25]) = 0; + (a[5] => z[25]) = 0; + (a[6] => z[25]) = 0; + (a[7] => z[25]) = 0; + (a[8] => z[25]) = 0; + (a[9] => z[25]) = 0; + (a[10] => z[25]) = 0; + (a[11] => z[25]) = 0; + (a[12] => z[25]) = 0; + (a[13] => z[25]) = 0; + (a[14] => z[25]) = 0; + (a[15] => z[25]) = 0; + (a[16] => z[25]) = 0; + (a[17] => z[25]) = 0; + (a[18] => z[25]) = 0; + (a[19] => z[25]) = 0; + (b[0] => z[25]) = 0; + (b[1] => z[25]) = 0; + (b[2] => z[25]) = 0; + (b[3] => z[25]) = 0; + (b[4] => z[25]) = 0; + (b[5] => z[25]) = 0; + (b[6] => z[25]) = 0; + (b[7] => z[25]) = 0; + (b[8] => z[25]) = 0; + (b[9] => z[25]) = 0; + (b[10] => z[25]) = 0; + (b[11] => z[25]) = 0; + (b[12] => z[25]) = 0; + (b[13] => z[25]) = 0; + (b[14] => z[25]) = 0; + (b[15] => z[25]) = 0; + (b[16] => z[25]) = 0; + (b[17] => z[25]) = 0; + (a[0] => z[26]) = 0; + (a[1] => z[26]) = 0; + (a[2] => z[26]) = 0; + (a[3] => z[26]) = 0; + (a[4] => z[26]) = 0; + (a[5] => z[26]) = 0; + (a[6] => z[26]) = 0; + (a[7] => z[26]) = 0; + (a[8] => z[26]) = 0; + (a[9] => z[26]) = 0; + (a[10] => z[26]) = 0; + (a[11] => z[26]) = 0; + (a[12] => z[26]) = 0; + (a[13] => z[26]) = 0; + (a[14] => z[26]) = 0; + (a[15] => z[26]) = 0; + (a[16] => z[26]) = 0; + (a[17] => z[26]) = 0; + (a[18] => z[26]) = 0; + (a[19] => z[26]) = 0; + (b[0] => z[26]) = 0; + (b[1] => z[26]) = 0; + (b[2] => z[26]) = 0; + (b[3] => z[26]) = 0; + (b[4] => z[26]) = 0; + (b[5] => z[26]) = 0; + (b[6] => z[26]) = 0; + (b[7] => z[26]) = 0; + (b[8] => z[26]) = 0; + (b[9] => z[26]) = 0; + (b[10] => z[26]) = 0; + (b[11] => z[26]) = 0; + (b[12] => z[26]) = 0; + (b[13] => z[26]) = 0; + (b[14] => z[26]) = 0; + (b[15] => z[26]) = 0; + (b[16] => z[26]) = 0; + (b[17] => z[26]) = 0; + (a[0] => z[27]) = 0; + (a[1] => z[27]) = 0; + (a[2] => z[27]) = 0; + (a[3] => z[27]) = 0; + (a[4] => z[27]) = 0; + (a[5] => z[27]) = 0; + (a[6] => z[27]) = 0; + (a[7] => z[27]) = 0; + (a[8] => z[27]) = 0; + (a[9] => z[27]) = 0; + (a[10] => z[27]) = 0; + (a[11] => z[27]) = 0; + (a[12] => z[27]) = 0; + (a[13] => z[27]) = 0; + (a[14] => z[27]) = 0; + (a[15] => z[27]) = 0; + (a[16] => z[27]) = 0; + (a[17] => z[27]) = 0; + (a[18] => z[27]) = 0; + (a[19] => z[27]) = 0; + (b[0] => z[27]) = 0; + (b[1] => z[27]) = 0; + (b[2] => z[27]) = 0; + (b[3] => z[27]) = 0; + (b[4] => z[27]) = 0; + (b[5] => z[27]) = 0; + (b[6] => z[27]) = 0; + (b[7] => z[27]) = 0; + (b[8] => z[27]) = 0; + (b[9] => z[27]) = 0; + (b[10] => z[27]) = 0; + (b[11] => z[27]) = 0; + (b[12] => z[27]) = 0; + (b[13] => z[27]) = 0; + (b[14] => z[27]) = 0; + (b[15] => z[27]) = 0; + (b[16] => z[27]) = 0; + (b[17] => z[27]) = 0; + (a[0] => z[28]) = 0; + (a[1] => z[28]) = 0; + (a[2] => z[28]) = 0; + (a[3] => z[28]) = 0; + (a[4] => z[28]) = 0; + (a[5] => z[28]) = 0; + (a[6] => z[28]) = 0; + (a[7] => z[28]) = 0; + (a[8] => z[28]) = 0; + (a[9] => z[28]) = 0; + (a[10] => z[28]) = 0; + (a[11] => z[28]) = 0; + (a[12] => z[28]) = 0; + (a[13] => z[28]) = 0; + (a[14] => z[28]) = 0; + (a[15] => z[28]) = 0; + (a[16] => z[28]) = 0; + (a[17] => z[28]) = 0; + (a[18] => z[28]) = 0; + (a[19] => z[28]) = 0; + (b[0] => z[28]) = 0; + (b[1] => z[28]) = 0; + (b[2] => z[28]) = 0; + (b[3] => z[28]) = 0; + (b[4] => z[28]) = 0; + (b[5] => z[28]) = 0; + (b[6] => z[28]) = 0; + (b[7] => z[28]) = 0; + (b[8] => z[28]) = 0; + (b[9] => z[28]) = 0; + (b[10] => z[28]) = 0; + (b[11] => z[28]) = 0; + (b[12] => z[28]) = 0; + (b[13] => z[28]) = 0; + (b[14] => z[28]) = 0; + (b[15] => z[28]) = 0; + (b[16] => z[28]) = 0; + (b[17] => z[28]) = 0; + (a[0] => z[29]) = 0; + (a[1] => z[29]) = 0; + (a[2] => z[29]) = 0; + (a[3] => z[29]) = 0; + (a[4] => z[29]) = 0; + (a[5] => z[29]) = 0; + (a[6] => z[29]) = 0; + (a[7] => z[29]) = 0; + (a[8] => z[29]) = 0; + (a[9] => z[29]) = 0; + (a[10] => z[29]) = 0; + (a[11] => z[29]) = 0; + (a[12] => z[29]) = 0; + (a[13] => z[29]) = 0; + (a[14] => z[29]) = 0; + (a[15] => z[29]) = 0; + (a[16] => z[29]) = 0; + (a[17] => z[29]) = 0; + (a[18] => z[29]) = 0; + (a[19] => z[29]) = 0; + (b[0] => z[29]) = 0; + (b[1] => z[29]) = 0; + (b[2] => z[29]) = 0; + (b[3] => z[29]) = 0; + (b[4] => z[29]) = 0; + (b[5] => z[29]) = 0; + (b[6] => z[29]) = 0; + (b[7] => z[29]) = 0; + (b[8] => z[29]) = 0; + (b[9] => z[29]) = 0; + (b[10] => z[29]) = 0; + (b[11] => z[29]) = 0; + (b[12] => z[29]) = 0; + (b[13] => z[29]) = 0; + (b[14] => z[29]) = 0; + (b[15] => z[29]) = 0; + (b[16] => z[29]) = 0; + (b[17] => z[29]) = 0; + (a[0] => z[30]) = 0; + (a[1] => z[30]) = 0; + (a[2] => z[30]) = 0; + (a[3] => z[30]) = 0; + (a[4] => z[30]) = 0; + (a[5] => z[30]) = 0; + (a[6] => z[30]) = 0; + (a[7] => z[30]) = 0; + (a[8] => z[30]) = 0; + (a[9] => z[30]) = 0; + (a[10] => z[30]) = 0; + (a[11] => z[30]) = 0; + (a[12] => z[30]) = 0; + (a[13] => z[30]) = 0; + (a[14] => z[30]) = 0; + (a[15] => z[30]) = 0; + (a[16] => z[30]) = 0; + (a[17] => z[30]) = 0; + (a[18] => z[30]) = 0; + (a[19] => z[30]) = 0; + (b[0] => z[30]) = 0; + (b[1] => z[30]) = 0; + (b[2] => z[30]) = 0; + (b[3] => z[30]) = 0; + (b[4] => z[30]) = 0; + (b[5] => z[30]) = 0; + (b[6] => z[30]) = 0; + (b[7] => z[30]) = 0; + (b[8] => z[30]) = 0; + (b[9] => z[30]) = 0; + (b[10] => z[30]) = 0; + (b[11] => z[30]) = 0; + (b[12] => z[30]) = 0; + (b[13] => z[30]) = 0; + (b[14] => z[30]) = 0; + (b[15] => z[30]) = 0; + (b[16] => z[30]) = 0; + (b[17] => z[30]) = 0; + (a[0] => z[31]) = 0; + (a[1] => z[31]) = 0; + (a[2] => z[31]) = 0; + (a[3] => z[31]) = 0; + (a[4] => z[31]) = 0; + (a[5] => z[31]) = 0; + (a[6] => z[31]) = 0; + (a[7] => z[31]) = 0; + (a[8] => z[31]) = 0; + (a[9] => z[31]) = 0; + (a[10] => z[31]) = 0; + (a[11] => z[31]) = 0; + (a[12] => z[31]) = 0; + (a[13] => z[31]) = 0; + (a[14] => z[31]) = 0; + (a[15] => z[31]) = 0; + (a[16] => z[31]) = 0; + (a[17] => z[31]) = 0; + (a[18] => z[31]) = 0; + (a[19] => z[31]) = 0; + (b[0] => z[31]) = 0; + (b[1] => z[31]) = 0; + (b[2] => z[31]) = 0; + (b[3] => z[31]) = 0; + (b[4] => z[31]) = 0; + (b[5] => z[31]) = 0; + (b[6] => z[31]) = 0; + (b[7] => z[31]) = 0; + (b[8] => z[31]) = 0; + (b[9] => z[31]) = 0; + (b[10] => z[31]) = 0; + (b[11] => z[31]) = 0; + (b[12] => z[31]) = 0; + (b[13] => z[31]) = 0; + (b[14] => z[31]) = 0; + (b[15] => z[31]) = 0; + (b[16] => z[31]) = 0; + (b[17] => z[31]) = 0; + (a[0] => z[32]) = 0; + (a[1] => z[32]) = 0; + (a[2] => z[32]) = 0; + (a[3] => z[32]) = 0; + (a[4] => z[32]) = 0; + (a[5] => z[32]) = 0; + (a[6] => z[32]) = 0; + (a[7] => z[32]) = 0; + (a[8] => z[32]) = 0; + (a[9] => z[32]) = 0; + (a[10] => z[32]) = 0; + (a[11] => z[32]) = 0; + (a[12] => z[32]) = 0; + (a[13] => z[32]) = 0; + (a[14] => z[32]) = 0; + (a[15] => z[32]) = 0; + (a[16] => z[32]) = 0; + (a[17] => z[32]) = 0; + (a[18] => z[32]) = 0; + (a[19] => z[32]) = 0; + (b[0] => z[32]) = 0; + (b[1] => z[32]) = 0; + (b[2] => z[32]) = 0; + (b[3] => z[32]) = 0; + (b[4] => z[32]) = 0; + (b[5] => z[32]) = 0; + (b[6] => z[32]) = 0; + (b[7] => z[32]) = 0; + (b[8] => z[32]) = 0; + (b[9] => z[32]) = 0; + (b[10] => z[32]) = 0; + (b[11] => z[32]) = 0; + (b[12] => z[32]) = 0; + (b[13] => z[32]) = 0; + (b[14] => z[32]) = 0; + (b[15] => z[32]) = 0; + (b[16] => z[32]) = 0; + (b[17] => z[32]) = 0; + (a[0] => z[33]) = 0; + (a[1] => z[33]) = 0; + (a[2] => z[33]) = 0; + (a[3] => z[33]) = 0; + (a[4] => z[33]) = 0; + (a[5] => z[33]) = 0; + (a[6] => z[33]) = 0; + (a[7] => z[33]) = 0; + (a[8] => z[33]) = 0; + (a[9] => z[33]) = 0; + (a[10] => z[33]) = 0; + (a[11] => z[33]) = 0; + (a[12] => z[33]) = 0; + (a[13] => z[33]) = 0; + (a[14] => z[33]) = 0; + (a[15] => z[33]) = 0; + (a[16] => z[33]) = 0; + (a[17] => z[33]) = 0; + (a[18] => z[33]) = 0; + (a[19] => z[33]) = 0; + (b[0] => z[33]) = 0; + (b[1] => z[33]) = 0; + (b[2] => z[33]) = 0; + (b[3] => z[33]) = 0; + (b[4] => z[33]) = 0; + (b[5] => z[33]) = 0; + (b[6] => z[33]) = 0; + (b[7] => z[33]) = 0; + (b[8] => z[33]) = 0; + (b[9] => z[33]) = 0; + (b[10] => z[33]) = 0; + (b[11] => z[33]) = 0; + (b[12] => z[33]) = 0; + (b[13] => z[33]) = 0; + (b[14] => z[33]) = 0; + (b[15] => z[33]) = 0; + (b[16] => z[33]) = 0; + (b[17] => z[33]) = 0; + (a[0] => z[34]) = 0; + (a[1] => z[34]) = 0; + (a[2] => z[34]) = 0; + (a[3] => z[34]) = 0; + (a[4] => z[34]) = 0; + (a[5] => z[34]) = 0; + (a[6] => z[34]) = 0; + (a[7] => z[34]) = 0; + (a[8] => z[34]) = 0; + (a[9] => z[34]) = 0; + (a[10] => z[34]) = 0; + (a[11] => z[34]) = 0; + (a[12] => z[34]) = 0; + (a[13] => z[34]) = 0; + (a[14] => z[34]) = 0; + (a[15] => z[34]) = 0; + (a[16] => z[34]) = 0; + (a[17] => z[34]) = 0; + (a[18] => z[34]) = 0; + (a[19] => z[34]) = 0; + (b[0] => z[34]) = 0; + (b[1] => z[34]) = 0; + (b[2] => z[34]) = 0; + (b[3] => z[34]) = 0; + (b[4] => z[34]) = 0; + (b[5] => z[34]) = 0; + (b[6] => z[34]) = 0; + (b[7] => z[34]) = 0; + (b[8] => z[34]) = 0; + (b[9] => z[34]) = 0; + (b[10] => z[34]) = 0; + (b[11] => z[34]) = 0; + (b[12] => z[34]) = 0; + (b[13] => z[34]) = 0; + (b[14] => z[34]) = 0; + (b[15] => z[34]) = 0; + (b[16] => z[34]) = 0; + (b[17] => z[34]) = 0; + (a[0] => z[35]) = 0; + (a[1] => z[35]) = 0; + (a[2] => z[35]) = 0; + (a[3] => z[35]) = 0; + (a[4] => z[35]) = 0; + (a[5] => z[35]) = 0; + (a[6] => z[35]) = 0; + (a[7] => z[35]) = 0; + (a[8] => z[35]) = 0; + (a[9] => z[35]) = 0; + (a[10] => z[35]) = 0; + (a[11] => z[35]) = 0; + (a[12] => z[35]) = 0; + (a[13] => z[35]) = 0; + (a[14] => z[35]) = 0; + (a[15] => z[35]) = 0; + (a[16] => z[35]) = 0; + (a[17] => z[35]) = 0; + (a[18] => z[35]) = 0; + (a[19] => z[35]) = 0; + (b[0] => z[35]) = 0; + (b[1] => z[35]) = 0; + (b[2] => z[35]) = 0; + (b[3] => z[35]) = 0; + (b[4] => z[35]) = 0; + (b[5] => z[35]) = 0; + (b[6] => z[35]) = 0; + (b[7] => z[35]) = 0; + (b[8] => z[35]) = 0; + (b[9] => z[35]) = 0; + (b[10] => z[35]) = 0; + (b[11] => z[35]) = 0; + (b[12] => z[35]) = 0; + (b[13] => z[35]) = 0; + (b[14] => z[35]) = 0; + (b[15] => z[35]) = 0; + (b[16] => z[35]) = 0; + (b[17] => z[35]) = 0; + (a[0] => z[36]) = 0; + (a[1] => z[36]) = 0; + (a[2] => z[36]) = 0; + (a[3] => z[36]) = 0; + (a[4] => z[36]) = 0; + (a[5] => z[36]) = 0; + (a[6] => z[36]) = 0; + (a[7] => z[36]) = 0; + (a[8] => z[36]) = 0; + (a[9] => z[36]) = 0; + (a[10] => z[36]) = 0; + (a[11] => z[36]) = 0; + (a[12] => z[36]) = 0; + (a[13] => z[36]) = 0; + (a[14] => z[36]) = 0; + (a[15] => z[36]) = 0; + (a[16] => z[36]) = 0; + (a[17] => z[36]) = 0; + (a[18] => z[36]) = 0; + (a[19] => z[36]) = 0; + (b[0] => z[36]) = 0; + (b[1] => z[36]) = 0; + (b[2] => z[36]) = 0; + (b[3] => z[36]) = 0; + (b[4] => z[36]) = 0; + (b[5] => z[36]) = 0; + (b[6] => z[36]) = 0; + (b[7] => z[36]) = 0; + (b[8] => z[36]) = 0; + (b[9] => z[36]) = 0; + (b[10] => z[36]) = 0; + (b[11] => z[36]) = 0; + (b[12] => z[36]) = 0; + (b[13] => z[36]) = 0; + (b[14] => z[36]) = 0; + (b[15] => z[36]) = 0; + (b[16] => z[36]) = 0; + (b[17] => z[36]) = 0; + (a[0] => z[37]) = 0; + (a[1] => z[37]) = 0; + (a[2] => z[37]) = 0; + (a[3] => z[37]) = 0; + (a[4] => z[37]) = 0; + (a[5] => z[37]) = 0; + (a[6] => z[37]) = 0; + (a[7] => z[37]) = 0; + (a[8] => z[37]) = 0; + (a[9] => z[37]) = 0; + (a[10] => z[37]) = 0; + (a[11] => z[37]) = 0; + (a[12] => z[37]) = 0; + (a[13] => z[37]) = 0; + (a[14] => z[37]) = 0; + (a[15] => z[37]) = 0; + (a[16] => z[37]) = 0; + (a[17] => z[37]) = 0; + (a[18] => z[37]) = 0; + (a[19] => z[37]) = 0; + (b[0] => z[37]) = 0; + (b[1] => z[37]) = 0; + (b[2] => z[37]) = 0; + (b[3] => z[37]) = 0; + (b[4] => z[37]) = 0; + (b[5] => z[37]) = 0; + (b[6] => z[37]) = 0; + (b[7] => z[37]) = 0; + (b[8] => z[37]) = 0; + (b[9] => z[37]) = 0; + (b[10] => z[37]) = 0; + (b[11] => z[37]) = 0; + (b[12] => z[37]) = 0; + (b[13] => z[37]) = 0; + (b[14] => z[37]) = 0; + (b[15] => z[37]) = 0; + (b[16] => z[37]) = 0; + (b[17] => z[37]) = 0; + (subtract => z[0]) = 0; + (subtract => z[1]) = 0; + (subtract => z[2]) = 0; + (subtract => z[3]) = 0; + (subtract => z[4]) = 0; + (subtract => z[5]) = 0; + (subtract => z[6]) = 0; + (subtract => z[7]) = 0; + (subtract => z[8]) = 0; + (subtract => z[9]) = 0; + (subtract => z[10]) = 0; + (subtract => z[11]) = 0; + (subtract => z[12]) = 0; + (subtract => z[13]) = 0; + (subtract => z[14]) = 0; + (subtract => z[15]) = 0; + (subtract => z[16]) = 0; + (subtract => z[17]) = 0; + (subtract => z[18]) = 0; + (subtract => z[19]) = 0; + (subtract => z[20]) = 0; + (subtract => z[21]) = 0; + (subtract => z[22]) = 0; + (subtract => z[23]) = 0; + (subtract => z[24]) = 0; + (subtract => z[25]) = 0; + (subtract => z[26]) = 0; + (subtract => z[27]) = 0; + (subtract => z[28]) = 0; + (subtract => z[29]) = 0; + (subtract => z[30]) = 0; + (subtract => z[31]) = 0; + (subtract => z[32]) = 0; + (subtract => z[33]) = 0; + (subtract => z[34]) = 0; + (subtract => z[35]) = 0; + (subtract => z[36]) = 0; + (subtract => z[37]) = 0; + (acc_fir[0] => z[0]) = 0; + (acc_fir[1] => z[0]) = 0; + (acc_fir[2] => z[0]) = 0; + (acc_fir[3] => z[0]) = 0; + (acc_fir[4] => z[0]) = 0; + (acc_fir[5] => z[0]) = 0; + (acc_fir[0] => z[1]) = 0; + (acc_fir[1] => z[1]) = 0; + (acc_fir[2] => z[1]) = 0; + (acc_fir[3] => z[1]) = 0; + (acc_fir[4] => z[1]) = 0; + (acc_fir[5] => z[1]) = 0; + (acc_fir[0] => z[2]) = 0; + (acc_fir[1] => z[2]) = 0; + (acc_fir[2] => z[2]) = 0; + (acc_fir[3] => z[2]) = 0; + (acc_fir[4] => z[2]) = 0; + (acc_fir[5] => z[2]) = 0; + (acc_fir[0] => z[3]) = 0; + (acc_fir[1] => z[3]) = 0; + (acc_fir[2] => z[3]) = 0; + (acc_fir[3] => z[3]) = 0; + (acc_fir[4] => z[3]) = 0; + (acc_fir[5] => z[3]) = 0; + (acc_fir[0] => z[4]) = 0; + (acc_fir[1] => z[4]) = 0; + (acc_fir[2] => z[4]) = 0; + (acc_fir[3] => z[4]) = 0; + (acc_fir[4] => z[4]) = 0; + (acc_fir[5] => z[4]) = 0; + (acc_fir[0] => z[5]) = 0; + (acc_fir[1] => z[5]) = 0; + (acc_fir[2] => z[5]) = 0; + (acc_fir[3] => z[5]) = 0; + (acc_fir[4] => z[5]) = 0; + (acc_fir[5] => z[5]) = 0; + (acc_fir[0] => z[6]) = 0; + (acc_fir[1] => z[6]) = 0; + (acc_fir[2] => z[6]) = 0; + (acc_fir[3] => z[6]) = 0; + (acc_fir[4] => z[6]) = 0; + (acc_fir[5] => z[6]) = 0; + (acc_fir[0] => z[7]) = 0; + (acc_fir[1] => z[7]) = 0; + (acc_fir[2] => z[7]) = 0; + (acc_fir[3] => z[7]) = 0; + (acc_fir[4] => z[7]) = 0; + (acc_fir[5] => z[7]) = 0; + (acc_fir[0] => z[8]) = 0; + (acc_fir[1] => z[8]) = 0; + (acc_fir[2] => z[8]) = 0; + (acc_fir[3] => z[8]) = 0; + (acc_fir[4] => z[8]) = 0; + (acc_fir[5] => z[8]) = 0; + (acc_fir[0] => z[9]) = 0; + (acc_fir[1] => z[9]) = 0; + (acc_fir[2] => z[9]) = 0; + (acc_fir[3] => z[9]) = 0; + (acc_fir[4] => z[9]) = 0; + (acc_fir[5] => z[9]) = 0; + (acc_fir[0] => z[10]) = 0; + (acc_fir[1] => z[10]) = 0; + (acc_fir[2] => z[10]) = 0; + (acc_fir[3] => z[10]) = 0; + (acc_fir[4] => z[10]) = 0; + (acc_fir[5] => z[10]) = 0; + (acc_fir[0] => z[11]) = 0; + (acc_fir[1] => z[11]) = 0; + (acc_fir[2] => z[11]) = 0; + (acc_fir[3] => z[11]) = 0; + (acc_fir[4] => z[11]) = 0; + (acc_fir[5] => z[11]) = 0; + (acc_fir[0] => z[12]) = 0; + (acc_fir[1] => z[12]) = 0; + (acc_fir[2] => z[12]) = 0; + (acc_fir[3] => z[12]) = 0; + (acc_fir[4] => z[12]) = 0; + (acc_fir[5] => z[12]) = 0; + (acc_fir[0] => z[13]) = 0; + (acc_fir[1] => z[13]) = 0; + (acc_fir[2] => z[13]) = 0; + (acc_fir[3] => z[13]) = 0; + (acc_fir[4] => z[13]) = 0; + (acc_fir[5] => z[13]) = 0; + (acc_fir[0] => z[14]) = 0; + (acc_fir[1] => z[14]) = 0; + (acc_fir[2] => z[14]) = 0; + (acc_fir[3] => z[14]) = 0; + (acc_fir[4] => z[14]) = 0; + (acc_fir[5] => z[14]) = 0; + (acc_fir[0] => z[15]) = 0; + (acc_fir[1] => z[15]) = 0; + (acc_fir[2] => z[15]) = 0; + (acc_fir[3] => z[15]) = 0; + (acc_fir[4] => z[15]) = 0; + (acc_fir[5] => z[15]) = 0; + (acc_fir[0] => z[16]) = 0; + (acc_fir[1] => z[16]) = 0; + (acc_fir[2] => z[16]) = 0; + (acc_fir[3] => z[16]) = 0; + (acc_fir[4] => z[16]) = 0; + (acc_fir[5] => z[16]) = 0; + (acc_fir[0] => z[17]) = 0; + (acc_fir[1] => z[17]) = 0; + (acc_fir[2] => z[17]) = 0; + (acc_fir[3] => z[17]) = 0; + (acc_fir[4] => z[17]) = 0; + (acc_fir[5] => z[17]) = 0; + (acc_fir[0] => z[18]) = 0; + (acc_fir[1] => z[18]) = 0; + (acc_fir[2] => z[18]) = 0; + (acc_fir[3] => z[18]) = 0; + (acc_fir[4] => z[18]) = 0; + (acc_fir[5] => z[18]) = 0; + (acc_fir[0] => z[19]) = 0; + (acc_fir[1] => z[19]) = 0; + (acc_fir[2] => z[19]) = 0; + (acc_fir[3] => z[19]) = 0; + (acc_fir[4] => z[19]) = 0; + (acc_fir[5] => z[19]) = 0; + (acc_fir[0] => z[20]) = 0; + (acc_fir[1] => z[20]) = 0; + (acc_fir[2] => z[20]) = 0; + (acc_fir[3] => z[20]) = 0; + (acc_fir[4] => z[20]) = 0; + (acc_fir[5] => z[20]) = 0; + (acc_fir[0] => z[21]) = 0; + (acc_fir[1] => z[21]) = 0; + (acc_fir[2] => z[21]) = 0; + (acc_fir[3] => z[21]) = 0; + (acc_fir[4] => z[21]) = 0; + (acc_fir[5] => z[21]) = 0; + (acc_fir[0] => z[22]) = 0; + (acc_fir[1] => z[22]) = 0; + (acc_fir[2] => z[22]) = 0; + (acc_fir[3] => z[22]) = 0; + (acc_fir[4] => z[22]) = 0; + (acc_fir[5] => z[22]) = 0; + (acc_fir[0] => z[23]) = 0; + (acc_fir[1] => z[23]) = 0; + (acc_fir[2] => z[23]) = 0; + (acc_fir[3] => z[23]) = 0; + (acc_fir[4] => z[23]) = 0; + (acc_fir[5] => z[23]) = 0; + (acc_fir[0] => z[24]) = 0; + (acc_fir[1] => z[24]) = 0; + (acc_fir[2] => z[24]) = 0; + (acc_fir[3] => z[24]) = 0; + (acc_fir[4] => z[24]) = 0; + (acc_fir[5] => z[24]) = 0; + (acc_fir[0] => z[25]) = 0; + (acc_fir[1] => z[25]) = 0; + (acc_fir[2] => z[25]) = 0; + (acc_fir[3] => z[25]) = 0; + (acc_fir[4] => z[25]) = 0; + (acc_fir[5] => z[25]) = 0; + (acc_fir[0] => z[26]) = 0; + (acc_fir[1] => z[26]) = 0; + (acc_fir[2] => z[26]) = 0; + (acc_fir[3] => z[26]) = 0; + (acc_fir[4] => z[26]) = 0; + (acc_fir[5] => z[26]) = 0; + (acc_fir[0] => z[27]) = 0; + (acc_fir[1] => z[27]) = 0; + (acc_fir[2] => z[27]) = 0; + (acc_fir[3] => z[27]) = 0; + (acc_fir[4] => z[27]) = 0; + (acc_fir[5] => z[27]) = 0; + (acc_fir[0] => z[28]) = 0; + (acc_fir[1] => z[28]) = 0; + (acc_fir[2] => z[28]) = 0; + (acc_fir[3] => z[28]) = 0; + (acc_fir[4] => z[28]) = 0; + (acc_fir[5] => z[28]) = 0; + (acc_fir[0] => z[29]) = 0; + (acc_fir[1] => z[29]) = 0; + (acc_fir[2] => z[29]) = 0; + (acc_fir[3] => z[29]) = 0; + (acc_fir[4] => z[29]) = 0; + (acc_fir[5] => z[29]) = 0; + (acc_fir[0] => z[30]) = 0; + (acc_fir[1] => z[30]) = 0; + (acc_fir[2] => z[30]) = 0; + (acc_fir[3] => z[30]) = 0; + (acc_fir[4] => z[30]) = 0; + (acc_fir[5] => z[30]) = 0; + (acc_fir[0] => z[31]) = 0; + (acc_fir[1] => z[31]) = 0; + (acc_fir[2] => z[31]) = 0; + (acc_fir[3] => z[31]) = 0; + (acc_fir[4] => z[31]) = 0; + (acc_fir[5] => z[31]) = 0; + (acc_fir[0] => z[32]) = 0; + (acc_fir[1] => z[32]) = 0; + (acc_fir[2] => z[32]) = 0; + (acc_fir[3] => z[32]) = 0; + (acc_fir[4] => z[32]) = 0; + (acc_fir[5] => z[32]) = 0; + (acc_fir[0] => z[33]) = 0; + (acc_fir[1] => z[33]) = 0; + (acc_fir[2] => z[33]) = 0; + (acc_fir[3] => z[33]) = 0; + (acc_fir[4] => z[33]) = 0; + (acc_fir[5] => z[33]) = 0; + (acc_fir[0] => z[34]) = 0; + (acc_fir[1] => z[34]) = 0; + (acc_fir[2] => z[34]) = 0; + (acc_fir[3] => z[34]) = 0; + (acc_fir[4] => z[34]) = 0; + (acc_fir[5] => z[34]) = 0; + (acc_fir[0] => z[35]) = 0; + (acc_fir[1] => z[35]) = 0; + (acc_fir[2] => z[35]) = 0; + (acc_fir[3] => z[35]) = 0; + (acc_fir[4] => z[35]) = 0; + (acc_fir[5] => z[35]) = 0; + (acc_fir[0] => z[36]) = 0; + (acc_fir[1] => z[36]) = 0; + (acc_fir[2] => z[36]) = 0; + (acc_fir[3] => z[36]) = 0; + (acc_fir[4] => z[36]) = 0; + (acc_fir[5] => z[36]) = 0; + (acc_fir[0] => z[37]) = 0; + (acc_fir[1] => z[37]) = 0; + (acc_fir[2] => z[37]) = 0; + (acc_fir[3] => z[37]) = 0; + (acc_fir[4] => z[37]) = 0; + (acc_fir[5] => z[37]) = 0; + endspecify +`endif + +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, + 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 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]; + + QL_DSP2 #( + .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .dly_b(), + .z(z), + + .f_mode(f_mode), + + .feedback(feedback), + .acc_fir(acc_fir), + .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) + .saturate_enable(saturate_enable), + .shift_right(shift_right), + .round(round), + .subtract(subtract), + .register_inputs(register_inputs) // registered inputs + ); + +`ifdef SDF_SIM + specify + (posedge clk => (z +: a)) = 0; + (posedge clk => (z +: b)) = 0; + $setuphold(posedge clk, a, 0, 0); + $setuphold(posedge clk, b, 0, 0); + $setuphold(posedge clk, feedback, 0, 0); + $setuphold(posedge clk, load_acc, 0, 0); + $setuphold(posedge clk, subtract, 0, 0); + $setuphold(posedge clk, acc_fir, 0, 0); + endspecify +`endif + +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, + 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 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]; + + QL_DSP2 #( + .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .dly_b(), + .z(z), + + .f_mode(f_mode), + + .feedback(feedback), + .acc_fir(acc_fir), + .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) + .saturate_enable(saturate_enable), + .shift_right(shift_right), + .round(round), + .subtract(subtract), + .register_inputs(register_inputs) // unregistered inputs + ); + +`ifdef SDF_SIM + specify + (posedge clk => (z +: a)) = 0; + (posedge clk => (z +: b)) = 0; + $setuphold(posedge clk, a, 0, 0); + $setuphold(posedge clk, b, 0, 0); + $setuphold(posedge clk, feedback, 0, 0); + $setuphold(posedge clk, load_acc, 0, 0); + $setuphold(posedge clk, subtract, 0, 0); + $setuphold(posedge clk, acc_fir, 0, 0); + endspecify +`endif + +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, + 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 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]; + + QL_DSP2 #( + .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .dly_b(), + .z(z), + + .f_mode(f_mode), + + .feedback(feedback), + .acc_fir(acc_fir), + .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) + .saturate_enable(saturate_enable), + .shift_right(shift_right), + .round(round), + .subtract(subtract), + .register_inputs(register_inputs) // registered inputs + ); + +`ifdef SDF_SIM + specify + (posedge clk => (z +: a)) = 0; + (posedge clk => (z +: b)) = 0; + $setuphold(posedge clk, a, 0, 0); + $setuphold(posedge clk, b, 0, 0); + $setuphold(posedge clk, feedback, 0, 0); + $setuphold(posedge clk, load_acc, 0, 0); + $setuphold(posedge clk, subtract, 0, 0); + $setuphold(posedge clk, acc_fir, 0, 0); + endspecify +`endif + +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, + input wire reset, + + input wire load_acc, + 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 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]; + + QL_DSP2 #( + .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .acc_fir(6'b0), + .z(z), + .dly_b(), + + .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: ACCout (1) + .saturate_enable(saturate_enable), + .shift_right(shift_right), + .round(round), + .subtract(subtract), + .register_inputs(register_inputs) // unregistered inputs + ); + +`ifdef SDF_SIM + specify + (posedge clk => (z +: a)) = 0; + (posedge clk => (z +: b)) = 0; + $setuphold(posedge clk, a, 0, 0); + $setuphold(posedge clk, b, 0, 0); + $setuphold(posedge clk, feedback, 0, 0); + $setuphold(posedge clk, load_acc, 0, 0); + $setuphold(posedge clk, subtract, 0, 0); + endspecify +`endif + +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, + 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]; + + QL_DSP2 #( + .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .acc_fir(6'b0), + .z(z), + .dly_b(), + + .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: ACCout (1) + .saturate_enable(saturate_enable), + .shift_right(shift_right), + .round(round), + .subtract(subtract), + .register_inputs(register_inputs) // registered inputs + ); + +`ifdef SDF_SIM + specify + (posedge clk => (z +: a)) = 0; + (posedge clk => (z +: b)) = 0; + $setuphold(posedge clk, a, 0, 0); + $setuphold(posedge clk, b, 0, 0); + $setuphold(posedge clk, feedback, 0, 0); + $setuphold(posedge clk, load_acc, 0, 0); + $setuphold(posedge clk, subtract, 0, 0); + endspecify +`endif + +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, + 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]; + + QL_DSP2 #( + .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .acc_fir(6'b0), + .z(z), + .dly_b(), + + .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: ACCout (5) + .saturate_enable(saturate_enable), + .shift_right(shift_right), + .round(round), + .subtract(subtract), + .register_inputs(register_inputs) // unregistered inputs + ); + +`ifdef SDF_SIM + specify + (posedge clk => (z +: a)) = 0; + (posedge clk => (z +: b)) = 0; + $setuphold(posedge clk, a, 0, 0); + $setuphold(posedge clk, b, 0, 0); + $setuphold(posedge clk, feedback, 0, 0); + $setuphold(posedge clk, load_acc, 0, 0); + $setuphold(posedge clk, subtract, 0, 0); + endspecify +`endif + +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, + 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]; + + QL_DSP2 #( + .MODE_BITS({COEFF_3, COEFF_2, COEFF_1, COEFF_0}) + ) dsp ( + .a(a), + .b(b), + .acc_fir(6'b0), + .z(z), + .dly_b(), + + .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: ACCout (5) + .saturate_enable(saturate_enable), + .shift_right(shift_right), + .round(round), + .subtract(subtract), + .register_inputs(register_inputs) // registered inputs + ); + +`ifdef SDF_SIM + specify + (posedge clk => (z +: a)) = 0; + (posedge clk => (z +: b)) = 0; + $setuphold(posedge clk, a, 0, 0); + $setuphold(posedge clk, b, 0, 0); + $setuphold(posedge clk, feedback, 0, 0); + $setuphold(posedge clk, load_acc, 0, 0); + $setuphold(posedge clk, subtract, 0, 0); + endspecify +`endif + +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. + + + // 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 diff --git a/techlibs/quicklogic/qlf_k6n10f/dsp_map.v b/techlibs/quicklogic/qlf_k6n10f/dspv2_map.v similarity index 100% rename from techlibs/quicklogic/qlf_k6n10f/dsp_map.v rename to techlibs/quicklogic/qlf_k6n10f/dspv2_map.v diff --git a/techlibs/quicklogic/qlf_k6n10f/dsp_sim.v b/techlibs/quicklogic/qlf_k6n10f/dspv2_sim.v similarity index 100% rename from techlibs/quicklogic/qlf_k6n10f/dsp_sim.v rename to techlibs/quicklogic/qlf_k6n10f/dspv2_sim.v diff --git a/techlibs/quicklogic/synth_quicklogic.cc b/techlibs/quicklogic/synth_quicklogic.cc index b74e02cbb..ef079edaf 100644 --- a/techlibs/quicklogic/synth_quicklogic.cc +++ b/techlibs/quicklogic/synth_quicklogic.cc @@ -27,6 +27,12 @@ PRIVATE_NAMESPACE_BEGIN struct SynthQuickLogicPass : public ScriptPass { + enum DSPKind { + None, + V1, + V2, + }; + SynthQuickLogicPass() : ScriptPass("synth_quicklogic", "Synthesis for QuickLogic FPGAs") {} void help() override @@ -50,6 +56,10 @@ struct SynthQuickLogicPass : public ScriptPass { log(" do not use dsp_t1_* to implement multipliers and associated logic\n"); log(" (qlf_k6n10f only).\n"); log("\n"); + log(" -dspv2\n"); + log(" synthesize for the v2 DSP block model instead of v1\n"); + log(" (qlf_k6n10f only).\n"); + log("\n"); log(" -nocarry\n"); log(" do not use adder_carry cells in output netlist.\n"); log("\n"); @@ -78,7 +88,8 @@ struct SynthQuickLogicPass : public ScriptPass { } string top_opt, blif_file, edif_file, family, currmodule, verilog_file, lib_path; - bool abc9, inferAdder, nobram, bramTypes, dsp, ioff; + bool abc9, inferAdder, nobram, bramTypes, ioff; + DSPKind dsp; void clear_flags() override { @@ -93,7 +104,7 @@ struct SynthQuickLogicPass : public ScriptPass { nobram = false; bramTypes = false; lib_path = "+/quicklogic/"; - dsp = true; + dsp = V1; ioff = true; } @@ -156,7 +167,11 @@ struct SynthQuickLogicPass : public ScriptPass { continue; } if (args[argidx] == "-nodsp" || args[argidx] == "-no_dsp") { - dsp = false; + dsp = None; + continue; + } + if (args[argidx] == "-dspv2") { + dsp = V2; continue; } if (args[argidx] == "-noioff") { @@ -198,8 +213,10 @@ struct SynthQuickLogicPass : public ScriptPass { read_simlibs += stringf(" %sqlf_k6n10f/brams_sim.v", lib_path.c_str()); if (bramTypes) read_simlibs += stringf(" %sqlf_k6n10f/bram_types_sim.v", lib_path.c_str()); - if (dsp) - read_simlibs += stringf(" %sqlf_k6n10f/dsp_sim.v", lib_path.c_str()); + if (dsp == V1) + read_simlibs += stringf(" %sqlf_k6n10f/dspv1_sim.v", lib_path.c_str()); + else if (dsp == V2) + read_simlibs += stringf(" %sqlf_k6n10f/dspv2_sim.v", lib_path.c_str()); } run(read_simlibs); run(stringf("hierarchy -check %s", help_mode ? "-top " : top_opt.c_str())); @@ -225,23 +242,31 @@ struct SynthQuickLogicPass : public ScriptPass { } if (check_label("map_dsp", "(for qlf_k6n10f, skip if -nodsp)") - && ((dsp && family == "qlf_k6n10f") || help_mode)) { + && (((dsp != None) && family == "qlf_k6n10f") || help_mode)) { run("wreduce t:$mul"); - //run("ql_dsp_macc"); + if (dsp == V1) { + run("ql_dsp_macc"); - run("techmap -map +/mul2dsp.v -map " + lib_path + family + "/dsp_map.v -D USE_DSP_CFG_PARAMS=0 -D DSP_SIGNEDONLY " - "-D DSP_A_MAXWIDTH=32 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=10 -D DSP_B_MINWIDTH=10 -D DSP_NAME=$__MUL32X18"); - run("chtype -set $mul t:$__soft_mul"); - run("techmap -map +/mul2dsp.v -map " + lib_path + family + "/dsp_map.v -D USE_DSP_CFG_PARAMS=0 -D DSP_SIGNEDONLY " - "-D DSP_A_MAXWIDTH=16 -D DSP_B_MAXWIDTH=9 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_NAME=$__MUL16X9"); - run("chtype -set $mul t:$__soft_mul"); + run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=20 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=11 -D DSP_B_MINWIDTH=10 -D DSP_NAME=$__QL_MUL20X18"); + run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=10 -D DSP_B_MAXWIDTH=9 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_NAME=$__QL_MUL10X9"); + run("chtype -set $mul t:$__soft_mul"); - run("ql_dsp"); - - //run("ql_dsp_simd"); - //run("techmap -map " + lib_path + family + "/dsp_final_map.v"); - //run("ql_dsp_io_regs"); + run("techmap -map " + lib_path + family + "/dspv1_map.v -D USE_DSP_CFG_PARAMS=0"); + run("ql_dsp_simd"); + run("techmap -map " + lib_path + family + "/dspv1_final_map.v"); + run("ql_dsp_io_regs"); + } else if (dsp == V2) { + run("techmap -map +/mul2dsp.v -map " + lib_path + family + "/dspv2_map.v -D USE_DSP_CFG_PARAMS=0 -D DSP_SIGNEDONLY " + "-D DSP_A_MAXWIDTH=32 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=10 -D DSP_B_MINWIDTH=10 -D DSP_NAME=$__MUL32X18"); + run("chtype -set $mul t:$__soft_mul"); + run("techmap -map +/mul2dsp.v -map " + lib_path + family + "/dspv2_map.v -D USE_DSP_CFG_PARAMS=0 -D DSP_SIGNEDONLY " + "-D DSP_A_MAXWIDTH=16 -D DSP_B_MAXWIDTH=9 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_NAME=$__MUL16X9"); + run("chtype -set $mul t:$__soft_mul"); + run("ql_dspv2"); + } else { + log_assert(false); + } } if (check_label("coarse")) { diff --git a/tests/arch/quicklogic/dspv2/complex_mult.ys b/tests/arch/quicklogic/dspv2/complex_mult.ys index 8a44bbbbc..b182f4067 100644 --- a/tests/arch/quicklogic/dspv2/complex_mult.ys +++ b/tests/arch/quicklogic/dspv2/complex_mult.ys @@ -12,7 +12,7 @@ module top(input signed [16:0] ar, input signed [16:0] ai, input signed [16:0] b endmodule EOF -synth_quicklogic -family qlf_k6n10f -run :coarse +synth_quicklogic -family qlf_k6n10f -dspv2 -run :coarse check -assert read_verilog +/quicklogic/qlf_k6n10f/dsp_sim.v prep -top top -flatten diff --git a/tests/arch/quicklogic/dspv2/simple.ys b/tests/arch/quicklogic/dspv2/simple.ys index 49f29511b..4aba5786d 100644 --- a/tests/arch/quicklogic/dspv2/simple.ys +++ b/tests/arch/quicklogic/dspv2/simple.ys @@ -11,7 +11,7 @@ module top(input [16:0] a, input [16:0] b, output reg [33:0] o, input clk, input endmodule EOF -synth_quicklogic -family qlf_k6n10f -run :coarse +synth_quicklogic -family qlf_k6n10f -dspv2 -run :coarse check opt_clean dump diff --git a/tests/arch/quicklogic/dspv2/simple2.ys b/tests/arch/quicklogic/dspv2/simple2.ys index d6179e616..d03a412a8 100644 --- a/tests/arch/quicklogic/dspv2/simple2.ys +++ b/tests/arch/quicklogic/dspv2/simple2.ys @@ -5,7 +5,7 @@ module top(input [16:0] a, input [16:0] b, input [16:0] c, input [16:0] d, outpu endmodule EOF -synth_quicklogic -family qlf_k6n10f -run :coarse +synth_quicklogic -family qlf_k6n10f -dspv2 -run :coarse read_verilog +/quicklogic/qlf_k6n10f/dsp_sim.v prep -top top -flatten opt_clean -purge From 47b270a03e95b1dbf6bbf1065fa4d00d9cad1d28 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 25 Feb 2025 11:59:41 +0100 Subject: [PATCH 05/38] synth_quicklogic: enable dspv2 tests, fix -dspv2 --- techlibs/quicklogic/synth_quicklogic.cc | 2 +- tests/arch/quicklogic/dspv2/run-test.sh | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 tests/arch/quicklogic/dspv2/run-test.sh diff --git a/techlibs/quicklogic/synth_quicklogic.cc b/techlibs/quicklogic/synth_quicklogic.cc index ef079edaf..9f5fd0919 100644 --- a/techlibs/quicklogic/synth_quicklogic.cc +++ b/techlibs/quicklogic/synth_quicklogic.cc @@ -263,7 +263,7 @@ struct SynthQuickLogicPass : public ScriptPass { run("techmap -map +/mul2dsp.v -map " + lib_path + family + "/dspv2_map.v -D USE_DSP_CFG_PARAMS=0 -D DSP_SIGNEDONLY " "-D DSP_A_MAXWIDTH=16 -D DSP_B_MAXWIDTH=9 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_NAME=$__MUL16X9"); run("chtype -set $mul t:$__soft_mul"); - run("ql_dspv2"); + run("ql_dsp"); } else { log_assert(false); } diff --git a/tests/arch/quicklogic/dspv2/run-test.sh b/tests/arch/quicklogic/dspv2/run-test.sh new file mode 100644 index 000000000..43a7874b2 --- /dev/null +++ b/tests/arch/quicklogic/dspv2/run-test.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -eu +source ../../../gen-tests-makefile.sh +generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'" From 651d5728d053145b69272aad9ba1c58792bd35cd Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 27 Feb 2025 17:36:50 +0100 Subject: [PATCH 06/38] ql_dsp_macc: dspv2 --- techlibs/quicklogic/ql_dsp_macc.cc | 65 +++++++++++++++++++------ techlibs/quicklogic/synth_quicklogic.cc | 1 + 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/techlibs/quicklogic/ql_dsp_macc.cc b/techlibs/quicklogic/ql_dsp_macc.cc index f0669da6c..39e2020ee 100644 --- a/techlibs/quicklogic/ql_dsp_macc.cc +++ b/techlibs/quicklogic/ql_dsp_macc.cc @@ -27,9 +27,11 @@ PRIVATE_NAMESPACE_BEGIN // ============================================================================ -static void create_ql_macc_dsp(ql_dsp_macc_pm &pm) +static void create_ql_macc_dsp(ql_dsp_macc_pm &pm, int dsp_version) { auto &st = pm.st_ql_dsp_macc; + log_assert(dsp_version < 3); + log_assert(dsp_version > 0); // Get port widths size_t a_width = GetSize(st.mul->getPort(ID(A))); @@ -49,26 +51,55 @@ static void create_ql_macc_dsp(ql_dsp_macc_pm &pm) size_t tgt_b_width; size_t tgt_z_width; - string cell_base_name = "dsp_t1"; + string cell_base_name; string cell_size_name = ""; string cell_cfg_name = ""; string cell_full_name = ""; + if (dsp_version == 1) + cell_base_name = "dsp_t1"; + if (dsp_version == 2) + cell_base_name = "dspv2"; if (min_width <= 2 && max_width <= 2 && z_width <= 4) { log_debug("\trejected: too narrow (%zd %zd %zd)\n", min_width, max_width, z_width); return; - } else if (min_width <= 9 && max_width <= 10 && z_width <= 19) { - cell_size_name = "_10x9x32"; - tgt_a_width = 10; - tgt_b_width = 9; - tgt_z_width = 19; - } else if (min_width <= 18 && max_width <= 20 && z_width <= 38) { - cell_size_name = "_20x18x64"; - tgt_a_width = 20; - tgt_b_width = 18; - tgt_z_width = 38; + } + + bool reject = false; + if (dsp_version == 1) { + if (min_width <= 9 && max_width <= 10 && z_width <= 19) { + cell_size_name = "_10x9x32"; + tgt_a_width = 10; + tgt_b_width = 9; + tgt_z_width = 19; + } else if (min_width <= 18 && max_width <= 20 && z_width <= 38) { + cell_size_name = "_20x18x64"; + tgt_a_width = 20; + tgt_b_width = 18; + tgt_z_width = 38; + } else { + reject = true; + } + } else if (dsp_version == 2) { + if (min_width <= 9 && max_width <= 16 && z_width <= 25) { + cell_size_name = "_16x9x32"; + tgt_a_width = 16; + tgt_b_width = 9; + tgt_z_width = 25; + } else if (min_width <= 18 && max_width <= 32 && z_width <= 50) { + cell_size_name = "_32x18x64"; + tgt_a_width = 20; + tgt_b_width = 18; + tgt_z_width = 50; + } else { + reject = true; + } } else { - log_debug("\trejected: too wide (%zd %zd %zd)\n", min_width, max_width, z_width); + log_assert(false); + } + if (reject) { + log_debug("\trejected: too wide (%zd %zd %zd) for v%d\n", + min_width, max_width, z_width, dsp_version); return; } @@ -197,16 +228,22 @@ struct QlDspMacc : public Pass { void execute(std::vector a_Args, RTLIL::Design *a_Design) override { + int dsp_version = 1; log_header(a_Design, "Executing QL_DSP_MACC pass.\n"); size_t argidx; for (argidx = 1; argidx < a_Args.size(); argidx++) { + if (a_Args[argidx] == "-dspv2") { + dsp_version = 2; + continue; + } break; } extra_args(a_Args, argidx, a_Design); + auto l = [dsp_version](ql_dsp_macc_pm& pm) { create_ql_macc_dsp(pm, dsp_version); }; for (auto module : a_Design->selected_modules()) - ql_dsp_macc_pm(module, module->selected_cells()).run_ql_dsp_macc(create_ql_macc_dsp); + ql_dsp_macc_pm(module, module->selected_cells()).run_ql_dsp_macc(l); } } QlDspMacc; diff --git a/techlibs/quicklogic/synth_quicklogic.cc b/techlibs/quicklogic/synth_quicklogic.cc index 9f5fd0919..3b924f604 100644 --- a/techlibs/quicklogic/synth_quicklogic.cc +++ b/techlibs/quicklogic/synth_quicklogic.cc @@ -257,6 +257,7 @@ struct SynthQuickLogicPass : public ScriptPass { run("techmap -map " + lib_path + family + "/dspv1_final_map.v"); run("ql_dsp_io_regs"); } else if (dsp == V2) { + run("ql_dsp_macc -dspv2"); run("techmap -map +/mul2dsp.v -map " + lib_path + family + "/dspv2_map.v -D USE_DSP_CFG_PARAMS=0 -D DSP_SIGNEDONLY " "-D DSP_A_MAXWIDTH=32 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=10 -D DSP_B_MINWIDTH=10 -D DSP_NAME=$__MUL32X18"); run("chtype -set $mul t:$__soft_mul"); From ed239b69fdf53bcf50c8edf79d932b4095260567 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 27 Feb 2025 17:37:18 +0100 Subject: [PATCH 07/38] ql_dsp_macc: whitespace. NFC --- techlibs/quicklogic/ql_dsp_macc.cc | 319 ++++++++++++++--------------- 1 file changed, 159 insertions(+), 160 deletions(-) diff --git a/techlibs/quicklogic/ql_dsp_macc.cc b/techlibs/quicklogic/ql_dsp_macc.cc index 39e2020ee..7e118d6fc 100644 --- a/techlibs/quicklogic/ql_dsp_macc.cc +++ b/techlibs/quicklogic/ql_dsp_macc.cc @@ -29,187 +29,186 @@ PRIVATE_NAMESPACE_BEGIN static void create_ql_macc_dsp(ql_dsp_macc_pm &pm, int dsp_version) { - auto &st = pm.st_ql_dsp_macc; - log_assert(dsp_version < 3); - log_assert(dsp_version > 0); + auto &st = pm.st_ql_dsp_macc; + log_assert(dsp_version < 3); + log_assert(dsp_version > 0); - // Get port widths - size_t a_width = GetSize(st.mul->getPort(ID(A))); - size_t b_width = GetSize(st.mul->getPort(ID(B))); - size_t z_width = GetSize(st.ff->getPort(ID(Q))); + // Get port widths + size_t a_width = GetSize(st.mul->getPort(ID(A))); + size_t b_width = GetSize(st.mul->getPort(ID(B))); + size_t z_width = GetSize(st.ff->getPort(ID(Q))); - size_t min_width = std::min(a_width, b_width); - size_t max_width = std::max(a_width, b_width); + size_t min_width = std::min(a_width, b_width); + size_t max_width = std::max(a_width, b_width); - // Signed / unsigned - bool ab_signed = st.mul->getParam(ID(A_SIGNED)).as_bool(); - log_assert(ab_signed == st.mul->getParam(ID(B_SIGNED)).as_bool()); + // Signed / unsigned + bool ab_signed = st.mul->getParam(ID(A_SIGNED)).as_bool(); + log_assert(ab_signed == st.mul->getParam(ID(B_SIGNED)).as_bool()); - // Determine DSP type or discard if too narrow / wide - RTLIL::IdString type; - size_t tgt_a_width; - size_t tgt_b_width; - size_t tgt_z_width; + // Determine DSP type or discard if too narrow / wide + RTLIL::IdString type; + size_t tgt_a_width; + size_t tgt_b_width; + size_t tgt_z_width; - string cell_base_name; - string cell_size_name = ""; - string cell_cfg_name = ""; - string cell_full_name = ""; - if (dsp_version == 1) - cell_base_name = "dsp_t1"; - if (dsp_version == 2) - cell_base_name = "dspv2"; + string cell_base_name; + string cell_size_name = ""; + string cell_cfg_name = ""; + string cell_full_name = ""; + if (dsp_version == 1) + cell_base_name = "dsp_t1"; + if (dsp_version == 2) + cell_base_name = "dspv2"; - if (min_width <= 2 && max_width <= 2 && z_width <= 4) { - log_debug("\trejected: too narrow (%zd %zd %zd)\n", min_width, max_width, z_width); - return; - } + if (min_width <= 2 && max_width <= 2 && z_width <= 4) { + log_debug("\trejected: too narrow (%zd %zd %zd)\n", min_width, max_width, z_width); + return; + } - bool reject = false; - if (dsp_version == 1) { - if (min_width <= 9 && max_width <= 10 && z_width <= 19) { - cell_size_name = "_10x9x32"; - tgt_a_width = 10; - tgt_b_width = 9; - tgt_z_width = 19; - } else if (min_width <= 18 && max_width <= 20 && z_width <= 38) { - cell_size_name = "_20x18x64"; - tgt_a_width = 20; - tgt_b_width = 18; - tgt_z_width = 38; - } else { - reject = true; - } - } else if (dsp_version == 2) { - if (min_width <= 9 && max_width <= 16 && z_width <= 25) { - cell_size_name = "_16x9x32"; - tgt_a_width = 16; - tgt_b_width = 9; - tgt_z_width = 25; - } else if (min_width <= 18 && max_width <= 32 && z_width <= 50) { - cell_size_name = "_32x18x64"; - tgt_a_width = 20; - tgt_b_width = 18; - tgt_z_width = 50; - } else { - reject = true; - } - } else { - log_assert(false); - } - if (reject) { - log_debug("\trejected: too wide (%zd %zd %zd) for v%d\n", - min_width, max_width, z_width, dsp_version); - return; - } + bool reject = false; + if (dsp_version == 1) { + if (min_width <= 9 && max_width <= 10 && z_width <= 19) { + cell_size_name = "_10x9x32"; + tgt_a_width = 10; + tgt_b_width = 9; + tgt_z_width = 19; + } else if (min_width <= 18 && max_width <= 20 && z_width <= 38) { + cell_size_name = "_20x18x64"; + tgt_a_width = 20; + tgt_b_width = 18; + tgt_z_width = 38; + } else { + reject = true; + } + } else if (dsp_version == 2) { + if (min_width <= 9 && max_width <= 16 && z_width <= 25) { + cell_size_name = "_16x9x32"; + tgt_a_width = 16; + tgt_b_width = 9; + tgt_z_width = 25; + } else if (min_width <= 18 && max_width <= 32 && z_width <= 50) { + cell_size_name = "_32x18x64"; + tgt_a_width = 20; + tgt_b_width = 18; + tgt_z_width = 50; + } else { + reject = true; + } + } else { + log_assert(false); + } + if (reject) { + log_debug("\trejected: too wide (%zd %zd %zd) for v%d\n", min_width, max_width, z_width, dsp_version); + return; + } - type = RTLIL::escape_id(cell_base_name + cell_size_name + "_cfg_ports"); - log("Inferring MACC %zux%zu->%zu as %s from:\n", a_width, b_width, z_width, log_id(type)); + type = RTLIL::escape_id(cell_base_name + cell_size_name + "_cfg_ports"); + log("Inferring MACC %zux%zu->%zu as %s from:\n", a_width, b_width, z_width, log_id(type)); - for (auto cell : {st.mul, st.add, st.mux, st.ff}) - if (cell) - log(" %s (%s)\n", log_id(cell), log_id(cell->type)); + for (auto cell : {st.mul, st.add, st.mux, st.ff}) + if (cell) + log(" %s (%s)\n", log_id(cell), log_id(cell->type)); - // Add the DSP cell - RTLIL::Cell *cell = pm.module->addCell(NEW_ID, type); + // Add the DSP cell + RTLIL::Cell *cell = pm.module->addCell(NEW_ID, type); - // Set attributes - cell->set_bool_attribute(ID(is_inferred), true); + // Set attributes + cell->set_bool_attribute(ID(is_inferred), true); - // Get input/output data signals - RTLIL::SigSpec sig_a, sig_b, sig_z; - sig_a = st.mul->getPort(ID(A)); - sig_b = st.mul->getPort(ID(B)); - sig_z = st.output_registered ? st.ff->getPort(ID(Q)) : st.ff->getPort(ID(D)); + // Get input/output data signals + RTLIL::SigSpec sig_a, sig_b, sig_z; + sig_a = st.mul->getPort(ID(A)); + sig_b = st.mul->getPort(ID(B)); + sig_z = st.output_registered ? st.ff->getPort(ID(Q)) : st.ff->getPort(ID(D)); - if (a_width < b_width) - std::swap(sig_a, sig_b); + if (a_width < b_width) + std::swap(sig_a, sig_b); - // Connect input data ports, sign extend / pad with zeros - sig_a.extend_u0(tgt_a_width, ab_signed); - sig_b.extend_u0(tgt_b_width, ab_signed); - cell->setPort(ID(a_i), sig_a); - cell->setPort(ID(b_i), sig_b); + // Connect input data ports, sign extend / pad with zeros + sig_a.extend_u0(tgt_a_width, ab_signed); + sig_b.extend_u0(tgt_b_width, ab_signed); + cell->setPort(ID(a_i), sig_a); + cell->setPort(ID(b_i), sig_b); - // Connect output data port, pad if needed - if ((size_t) GetSize(sig_z) < tgt_z_width) { - auto *wire = pm.module->addWire(NEW_ID, tgt_z_width - GetSize(sig_z)); - sig_z.append(wire); - } - cell->setPort(ID(z_o), sig_z); + // Connect output data port, pad if needed + if ((size_t)GetSize(sig_z) < tgt_z_width) { + auto *wire = pm.module->addWire(NEW_ID, tgt_z_width - GetSize(sig_z)); + sig_z.append(wire); + } + cell->setPort(ID(z_o), sig_z); - // Connect clock, reset and enable - cell->setPort(ID(clock_i), st.ff->getPort(ID(CLK))); + // Connect clock, reset and enable + cell->setPort(ID(clock_i), st.ff->getPort(ID(CLK))); - RTLIL::SigSpec rst; - RTLIL::SigSpec ena; + RTLIL::SigSpec rst; + RTLIL::SigSpec ena; - if (st.ff->hasPort(ID(ARST))) { - if (st.ff->getParam(ID(ARST_POLARITY)).as_int() != 1) { - rst = pm.module->Not(NEW_ID, st.ff->getPort(ID(ARST))); - } else { - rst = st.ff->getPort(ID(ARST)); - } - } else { - rst = RTLIL::SigSpec(RTLIL::S0); - } + if (st.ff->hasPort(ID(ARST))) { + if (st.ff->getParam(ID(ARST_POLARITY)).as_int() != 1) { + rst = pm.module->Not(NEW_ID, st.ff->getPort(ID(ARST))); + } else { + rst = st.ff->getPort(ID(ARST)); + } + } else { + rst = RTLIL::SigSpec(RTLIL::S0); + } - if (st.ff->hasPort(ID(EN))) { - if (st.ff->getParam(ID(EN_POLARITY)).as_int() != 1) { - ena = pm.module->Not(NEW_ID, st.ff->getPort(ID(EN))); - } else { - ena = st.ff->getPort(ID(EN)); - } - } else { - ena = RTLIL::SigSpec(RTLIL::S1); - } + if (st.ff->hasPort(ID(EN))) { + if (st.ff->getParam(ID(EN_POLARITY)).as_int() != 1) { + ena = pm.module->Not(NEW_ID, st.ff->getPort(ID(EN))); + } else { + ena = st.ff->getPort(ID(EN)); + } + } else { + ena = RTLIL::SigSpec(RTLIL::S1); + } - cell->setPort(ID(reset_i), rst); - cell->setPort(ID(load_acc_i), ena); + cell->setPort(ID(reset_i), rst); + cell->setPort(ID(load_acc_i), ena); - // Insert feedback_i control logic used for clearing / loading the accumulator - if (st.mux_in_pattern) { - RTLIL::SigSpec sig_s = st.mux->getPort(ID(S)); + // Insert feedback_i control logic used for clearing / loading the accumulator + if (st.mux_in_pattern) { + RTLIL::SigSpec sig_s = st.mux->getPort(ID(S)); - // Depending on the mux port ordering insert inverter if needed - log_assert(st.mux_ab.in(ID(A), ID(B))); - if (st.mux_ab == ID(A)) - sig_s = pm.module->Not(NEW_ID, sig_s); + // Depending on the mux port ordering insert inverter if needed + log_assert(st.mux_ab.in(ID(A), ID(B))); + if (st.mux_ab == ID(A)) + sig_s = pm.module->Not(NEW_ID, sig_s); - // Assemble the full control signal for the feedback_i port - RTLIL::SigSpec sig_f; - sig_f.append(sig_s); - sig_f.append(RTLIL::S0); - sig_f.append(RTLIL::S0); - cell->setPort(ID(feedback_i), sig_f); - } - // No acc clear/load - else { - cell->setPort(ID(feedback_i), RTLIL::SigSpec(RTLIL::S0, 3)); - } + // Assemble the full control signal for the feedback_i port + RTLIL::SigSpec sig_f; + sig_f.append(sig_s); + sig_f.append(RTLIL::S0); + sig_f.append(RTLIL::S0); + cell->setPort(ID(feedback_i), sig_f); + } + // No acc clear/load + else { + cell->setPort(ID(feedback_i), RTLIL::SigSpec(RTLIL::S0, 3)); + } - // Connect control ports - cell->setPort(ID(unsigned_a_i), RTLIL::SigSpec(ab_signed ? RTLIL::S0 : RTLIL::S1)); - cell->setPort(ID(unsigned_b_i), RTLIL::SigSpec(ab_signed ? RTLIL::S0 : RTLIL::S1)); + // Connect control ports + cell->setPort(ID(unsigned_a_i), RTLIL::SigSpec(ab_signed ? RTLIL::S0 : RTLIL::S1)); + cell->setPort(ID(unsigned_b_i), RTLIL::SigSpec(ab_signed ? RTLIL::S0 : RTLIL::S1)); - // Connect config bits - cell->setPort(ID(saturate_enable_i), RTLIL::SigSpec(RTLIL::S0)); - cell->setPort(ID(shift_right_i), RTLIL::SigSpec(RTLIL::S0, 6)); - cell->setPort(ID(round_i), RTLIL::SigSpec(RTLIL::S0)); - cell->setPort(ID(register_inputs_i), RTLIL::SigSpec(RTLIL::S0)); - // 3 - output post acc; 1 - output pre acc - cell->setPort(ID(output_select_i), RTLIL::Const(st.output_registered ? 1 : 3, 3)); + // Connect config bits + cell->setPort(ID(saturate_enable_i), RTLIL::SigSpec(RTLIL::S0)); + cell->setPort(ID(shift_right_i), RTLIL::SigSpec(RTLIL::S0, 6)); + cell->setPort(ID(round_i), RTLIL::SigSpec(RTLIL::S0)); + cell->setPort(ID(register_inputs_i), RTLIL::SigSpec(RTLIL::S0)); + // 3 - output post acc; 1 - output pre acc + cell->setPort(ID(output_select_i), RTLIL::Const(st.output_registered ? 1 : 3, 3)); - bool subtract = (st.add->type == ID($sub)); - cell->setPort(ID(subtract_i), RTLIL::SigSpec(subtract ? RTLIL::S1 : RTLIL::S0)); + bool subtract = (st.add->type == ID($sub)); + cell->setPort(ID(subtract_i), RTLIL::SigSpec(subtract ? RTLIL::S1 : RTLIL::S0)); - // Mark the cells for removal - pm.autoremove(st.mul); - pm.autoremove(st.add); - if (st.mux != nullptr) { - pm.autoremove(st.mux); - } - pm.autoremove(st.ff); + // Mark the cells for removal + pm.autoremove(st.mul); + pm.autoremove(st.add); + if (st.mux != nullptr) { + pm.autoremove(st.mux); + } + pm.autoremove(st.ff); } struct QlDspMacc : public Pass { @@ -217,18 +216,18 @@ struct QlDspMacc : public Pass { void help() override { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" ql_dsp_macc [selection]\n"); - log("\n"); - log("This pass looks for a multiply-accumulate pattern based on which it infers a\n"); - log("QuickLogic DSP cell.\n"); + log("\n"); + log("This pass looks for a multiply-accumulate pattern based on which it infers a\n"); + log("QuickLogic DSP cell.\n"); log("\n"); } void execute(std::vector a_Args, RTLIL::Design *a_Design) override { - int dsp_version = 1; + int dsp_version = 1; log_header(a_Design, "Executing QL_DSP_MACC pass.\n"); size_t argidx; @@ -241,7 +240,7 @@ struct QlDspMacc : public Pass { } extra_args(a_Args, argidx, a_Design); - auto l = [dsp_version](ql_dsp_macc_pm& pm) { create_ql_macc_dsp(pm, dsp_version); }; + auto l = [dsp_version](ql_dsp_macc_pm &pm) { create_ql_macc_dsp(pm, dsp_version); }; for (auto module : a_Design->selected_modules()) ql_dsp_macc_pm(module, module->selected_cells()).run_ql_dsp_macc(l); } From 9b52ba8738ad350ddb6e8f57c3f9d386b32bd929 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 5 Mar 2025 21:39:18 +0100 Subject: [PATCH 08/38] quicklogic: ql_dsp_simd add dspv2 support, fix dspv1 --- techlibs/quicklogic/ql_dsp_simd.cc | 262 +++++++++++++----- .../arch/quicklogic/qlf_k6n10f/dspv2_simd.ys | 61 ++++ 2 files changed, 251 insertions(+), 72 deletions(-) create mode 100644 tests/arch/quicklogic/qlf_k6n10f/dspv2_simd.ys diff --git a/techlibs/quicklogic/ql_dsp_simd.cc b/techlibs/quicklogic/ql_dsp_simd.cc index fdd2de406..8e914f57f 100644 --- a/techlibs/quicklogic/ql_dsp_simd.cc +++ b/techlibs/quicklogic/ql_dsp_simd.cc @@ -29,7 +29,7 @@ PRIVATE_NAMESPACE_BEGIN struct QlDspSimdPass : public Pass { - QlDspSimdPass() : Pass("ql_dsp_simd", "merge QuickLogic K6N10f DSP pairs to operate in SIMD mode") {} + QlDspSimdPass() : Pass("ql_dsp_simd", "merge QuickLogic K6N10f DSP pairs to operate in fractured mode") {} void help() override { @@ -37,16 +37,17 @@ struct QlDspSimdPass : public Pass { log("\n"); log(" ql_dsp_simd [selection]\n"); log("\n"); - log("This pass identifies K6N10f DSP cells with identical configuration and pack pairs\n"); - log("of them together into other DSP cells that can perform SIMD operation.\n"); + log("This pass identifies K6N10f DSP cells with identical configuration and merges\n"); + log("pairs of them, enabling fractured mode.\n"); } // .......................................... - /// Describes DSP config unique to a whole DSP cell + /// Describes DSP config unique to a DSP cell struct DspConfig { // Port connections dict connections; + dict parameters; DspConfig() = default; @@ -55,60 +56,149 @@ struct QlDspSimdPass : public Pass { [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(connections); return h; } - bool operator==(const DspConfig &ref) const { return connections == ref.connections; } + bool operator==(const DspConfig &ref) const { return connections == ref.connections && parameters == ref.parameters; } }; // .......................................... - const int m_ModeBitsSize = 80; - - // DSP parameters - const std::vector m_DspParams = {"COEFF_3", "COEFF_2", "COEFF_1", "COEFF_0"}; + const int m_Dspv1ModeBitsSize = 80; + const int m_Dspv2ModeBitsSize = 68; /// Temporary SigBit to SigBit helper map. SigMap sigmap; + static bool is_cascade(const Cell* cell) + { + std::array cascade_ports { + ID(a_cout_o), + ID(b_cout_o), + ID(z_cout_o), + ID(a_cin_i), + ID(b_cin_i), + ID(z_cin_i) + }; + for (auto p : cascade_ports) { + if (cell->hasPort(p) && !cell->getPort(p).is_fully_undef()) + return true; + } + return false; + } // .......................................... void execute(std::vector a_Args, RTLIL::Design *a_Design) override { log_header(a_Design, "Executing QL_DSP_SIMD pass.\n"); - // DSP control and config ports to consider and how to map them to ports - // of the target DSP cell - static const std::vector> m_DspCfgPorts = { - std::make_pair(ID(clock_i), ID(clk)), - std::make_pair(ID(reset_i), ID(reset)), - std::make_pair(ID(feedback_i), ID(feedback)), - std::make_pair(ID(load_acc_i), ID(load_acc)), - std::make_pair(ID(unsigned_a_i), ID(unsigned_a)), - std::make_pair(ID(unsigned_b_i), ID(unsigned_b)), - std::make_pair(ID(subtract_i), ID(subtract)), - std::make_pair(ID(output_select_i), ID(output_select)), - std::make_pair(ID(saturate_enable_i), ID(saturate_enable)), - std::make_pair(ID(shift_right_i), ID(shift_right)), - std::make_pair(ID(round_i), ID(round)), - std::make_pair(ID(register_inputs_i), ID(register_inputs)) + // The following lists have to match simulation model interfaces. + + // DSP control and config ports that must be equal between + // merged half-blocks + // In addition to functional differences, + // v1 and v2 have different balance between shared functionality + // in ports vs params. + static const std::vector m_Dspv1CfgPorts = { + ID(acc_fir_i), + ID(feedback_i), + ID(load_acc_i), + ID(unsigned_a_i), + ID(unsigned_b_i), + ID(clock_i), + ID(s_reset), + ID(saturate_enable_i), + ID(output_select_i), + ID(round_i), + ID(shift_right_i), + ID(subtract_i), + ID(register_inputs_i), + ID(coeff_0_i), + ID(coeff_1_i), + ID(coeff_2_i), + ID(coeff_3_i), + }; + static const std::vector m_Dspv1CfgParams = {}; + static const std::vector m_Dspv2CfgPorts = { + ID(clock_i), + ID(reset_i), + ID(acc_reset_i), + ID(feedback_i), + ID(load_acc_i), + ID(output_select_i), + }; + static const std::vector m_Dspv2CfgParams = { + ID(COEFF_0), + ID(ACC_FIR), + ID(ROUND), + ID(ZC_SHIFT), + ID(ZREG_SHIFT), + ID(SHIFT_REG), + ID(SATURATE), + ID(SUBTRACT), + ID(PRE_ADD), + ID(A_SEL), + ID(A_REG), + ID(B_SEL), + ID(B_REG), + ID(C_REG), + ID(BC_REG), + ID(M_REG), + ID(FRAC_MODE), }; - // DSP data ports and how to map them to ports of the target DSP cell - static const std::vector> m_DspDataPorts = { - std::make_pair(ID(a_i), ID(a)), - std::make_pair(ID(b_i), ID(b)), - std::make_pair(ID(acc_fir_i), ID(acc_fir)), - std::make_pair(ID(z_o), ID(z)), - std::make_pair(ID(dly_b_o), ID(dly_b)) + + // Data ports to be concatenated into merged cell + static const std::vector m_Dspv1DataPorts = { + ID(a_i), + ID(b_i), + ID(z_o), + ID(dly_b_o), }; + static const std::vector m_Dspv2DataPorts = { + ID(a_i), + ID(b_i), + ID(c_i), + ID(z_o), + }; + + // Params to serialize into MODE_BITS param + static const std::vector m_Dspv1ModeBitParams = { + ID(COEFF_3), + ID(COEFF_2), + ID(COEFF_1), + ID(COEFF_0), + }; + static const std::vector m_Dspv2ModeBitParams = {}; - // Source DSP cell type (SISD) - static const IdString m_SisdDspType = ID(dsp_t1_10x9x32); + // Source DSP cell type (half-block) + static const IdString m_Dspv1SisdType = ID(dsp_t1_10x9x32_cfg_ports); + static const IdString m_Dspv2SisdType = ID(dspv2_16x9x32_cfg_ports); - // Target DSP cell types for the SIMD mode - static const IdString m_SimdDspType = ID(QL_DSP2); + // Target DSP cell types (full-block) + static const IdString m_Dspv1SimdType = ID(dsp_t1_20x18x64_cfg_ports); + static const IdString m_Dspv2SimdType = ID(dspv2_32x18x64_cfg_ports); // Parse args - extra_args(a_Args, 1, a_Design); + int dsp_version = 1; + size_t argidx; + for (argidx = 1; argidx < a_Args.size(); argidx++) { + if (a_Args[argidx] == "-dspv2") { + dsp_version = 2; + continue; + } + break; + } + extra_args(a_Args, argidx, a_Design); + log_assert(dsp_version < 3); + log_assert(dsp_version > 0); + const auto& cfg_ports = (dsp_version == 1) ? m_Dspv1CfgPorts : m_Dspv2CfgPorts; + const auto& cfg_params = (dsp_version == 1) ? m_Dspv1CfgParams : m_Dspv2CfgParams; + const auto& data_ports = (dsp_version == 1) ? m_Dspv1DataPorts : m_Dspv2DataPorts; + auto half_dsp = (dsp_version == 1) ? m_Dspv1SisdType : m_Dspv2SisdType; + auto full_dsp = (dsp_version == 1) ? m_Dspv1SimdType : m_Dspv2SimdType; + auto mode_bit_params = (dsp_version == 1) ? m_Dspv1ModeBitParams : m_Dspv2ModeBitParams; + auto mode_bits_size = (dsp_version == 1) ? m_Dspv1ModeBitsSize : m_Dspv2ModeBitsSize; + + int cellsMerged = 0; // Process modules for (auto module : a_Design->selected_modules()) { // Setup the SigMap @@ -118,25 +208,33 @@ struct QlDspSimdPass : public Pass { dict> groups; for (auto cell : module->selected_cells()) { // Check if this is a DSP cell we are looking for (type starts with m_SisdDspType) - if (cell->type != m_SisdDspType) + if (cell->type != half_dsp) continue; // Skip if it has the (* keep *) attribute set - if (cell->has_keep_attr()) + if (cell->has_keep_attr()) { + log_debug("skip %s because it's marked keep\n", log_id(cell)); continue; + } + + // Skip if it has cascading + if (is_cascade(cell)) { + log_debug("skip %s because it's cascading\n", log_id(cell)); + continue; + } // Add to a group - const auto key = getDspConfig(cell, m_DspCfgPorts); + const auto key = getDspConfig(cell, cfg_ports, cfg_params); groups[key].push_back(cell); } + log_debug("Checking %zu detected mode-equivalent DSP cell classes\n", groups.size()); std::vector cellsToRemove; - // Map cell pairs to the target DSP SIMD cell for (const auto &it : groups) { const auto &group = it.second; const auto &config = it.first; - + log_debug("Checking %zu half-blocks\n", group.size()); // Ensure an even number size_t count = group.size(); if (count & 1) @@ -148,7 +246,7 @@ struct QlDspSimdPass : public Pass { Cell *dsp_b = group[i + 1]; // Create the new cell - Cell *simd = module->addCell(NEW_ID, m_SimdDspType); + Cell *simd = module->addCell(NEW_ID, full_dsp); log(" SIMD: %s (%s) + %s (%s) => %s (%s)\n", log_id(dsp_a), log_id(dsp_a->type), log_id(dsp_b), log_id(dsp_b->type), log_id(simd), log_id(simd->type)); @@ -157,26 +255,35 @@ struct QlDspSimdPass : public Pass { // its port widths) if (!simd->known()) log_error(" The target cell type '%s' is not known!", log_id(simd)); - // Connect common ports - for (const auto &it : m_DspCfgPorts) - simd->setPort(it.first, config.connections.at(it.second)); + + for (auto port : cfg_ports) { + if (config.connections.count(port)) + simd->setPort(port, config.connections.at(port)); + } + for (auto param : cfg_params) { + if (config.parameters.count(param)) + simd->setParam(param, config.parameters.at(param)); + } // Connect data ports - for (const auto &it : m_DspDataPorts) { + for (auto port : data_ports) { size_t width; bool isOutput; - std::tie(width, isOutput) = getPortInfo(simd, it.second); + std::tie(width, isOutput) = getPortInfo(simd, port); + if (!width) + log_error("Can't determine portinfo for %s\n", log_id(port)); auto getConnection = [&](const RTLIL::Cell *cell) { RTLIL::SigSpec sigspec; - if (cell->hasPort(it.first)) { - const auto &sig = cell->getPort(it.first); + if (cell->hasPort(port)) { + const auto &sig = cell->getPort(port); sigspec.append(sig); } int padding = width / 2 - sigspec.size(); + log_assert(padding >= 0); if (padding) { if (!isOutput) @@ -190,27 +297,32 @@ struct QlDspSimdPass : public Pass { RTLIL::SigSpec sigspec; sigspec.append(getConnection(dsp_a)); sigspec.append(getConnection(dsp_b)); - simd->setPort(it.second, sigspec); + simd->setPort(port, sigspec); } - // Concatenate FIR coefficient parameters into the single - // MODE_BITS parameter - Const mode_bits; - for (const auto &it : m_DspParams) { - auto val_a = dsp_a->getParam(it); - auto val_b = dsp_b->getParam(it); - - mode_bits.bits().insert(mode_bits.bits().end(), - val_a.begin(), val_a.end()); - mode_bits.bits().insert(mode_bits.bits().end(), - val_b.begin(), val_b.end()); + if (mode_bit_params.size()) { + // Concatenate FIR coefficient parameters into the single + // MODE_BITS parameter + Const mode_bits; + for (const auto &it : mode_bit_params) { + auto val_a = dsp_a->getParam(it); + auto val_b = dsp_b->getParam(it); + + mode_bits.bits().insert(mode_bits.bits().end(), + val_a.begin(), val_a.end()); + mode_bits.bits().insert(mode_bits.bits().end(), + val_b.begin(), val_b.end()); + } + + simd->setParam(ID(MODE_BITS), mode_bits); + log_assert(mode_bits.size() == mode_bits_size); + } - - // Enable the fractured mode by connecting the control - // port. - simd->setPort(ID(f_mode), State::S1); - simd->setParam(ID(MODE_BITS), mode_bits); - log_assert(mode_bits.size() == m_ModeBitsSize); + // Enable the fractured mode + if (dsp_version == 1) + simd->setPort(ID(f_mode), State::S1); + else + simd->setParam(ID(FRAC_MODE), State::S1); // Handle the "is_inferred" attribute. If one of the fragments // is not inferred mark the whole DSP as not inferred @@ -223,11 +335,12 @@ struct QlDspSimdPass : public Pass { cellsToRemove.push_back(dsp_b); } } - + cellsMerged += cellsToRemove.size(); // Remove old cells for (auto cell : cellsToRemove) module->remove(cell); } + log("Merged %d half-block cells\n", cellsMerged); } // .......................................... @@ -257,19 +370,24 @@ struct QlDspSimdPass : public Pass { } /// Given a DSP cell populates and returns a DspConfig struct for it. - DspConfig getDspConfig(RTLIL::Cell *a_Cell, const std::vector> &dspCfgPorts) + DspConfig getDspConfig(RTLIL::Cell *a_Cell, const std::vector &dspCfgPorts, const std::vector &dspCfgParams) { DspConfig config; - for (const auto &it : dspCfgPorts) { - auto port = it.first; - + for (auto port : dspCfgPorts) { // Port unconnected if (!a_Cell->hasPort(port)) continue; config.connections[port] = sigmap(a_Cell->getPort(port)); } + for (auto param : dspCfgParams) { + // Param unset? + if (!a_Cell->hasParam(param)) + continue; + + config.parameters[param] = a_Cell->getParam(param); + } return config; } diff --git a/tests/arch/quicklogic/qlf_k6n10f/dspv2_simd.ys b/tests/arch/quicklogic/qlf_k6n10f/dspv2_simd.ys new file mode 100644 index 000000000..d1440c921 --- /dev/null +++ b/tests/arch/quicklogic/qlf_k6n10f/dspv2_simd.ys @@ -0,0 +1,61 @@ +read_verilog < Date: Wed, 5 Mar 2025 22:00:29 +0100 Subject: [PATCH 09/38] quicklogic: update dspv2_sim.v to v1.1 Feb21 --- techlibs/quicklogic/qlf_k6n10f/dspv2_map.v | 2 +- techlibs/quicklogic/qlf_k6n10f/dspv2_sim.v | 213 ++++++++++++--------- 2 files changed, 127 insertions(+), 88 deletions(-) diff --git a/techlibs/quicklogic/qlf_k6n10f/dspv2_map.v b/techlibs/quicklogic/qlf_k6n10f/dspv2_map.v index ded1f592e..8640edb12 100644 --- a/techlibs/quicklogic/qlf_k6n10f/dspv2_map.v +++ b/techlibs/quicklogic/qlf_k6n10f/dspv2_map.v @@ -38,7 +38,7 @@ module \$__MUL16X9 (input [15:0] A, input [8:0] B, output [24:0] Y); dspv2_16x9x32_cfg_ports _TECHMAP_REPLACE_ ( .a_i(A), .b_i(B), - .c_i(10'd0), + .c_i(9'd0), .z_o(Y), .clock_i(1'bx), diff --git a/techlibs/quicklogic/qlf_k6n10f/dspv2_sim.v b/techlibs/quicklogic/qlf_k6n10f/dspv2_sim.v index 3a4106fe7..c879e5c32 100644 --- a/techlibs/quicklogic/qlf_k6n10f/dspv2_sim.v +++ b/techlibs/quicklogic/qlf_k6n10f/dspv2_sim.v @@ -2,12 +2,7 @@ `default_nettype none -// ---------------------------------------- // -// ----- DSP cells simulation modules ----- // -// --------- Control bits in ports -------- // -// ---------------------------------------- // - -module QL_DSPV2 ( // TODO: Name subject to change +module QL_DSPV2 ( input wire [31:0] a, input wire [17:0] b, input wire [17:0] c, @@ -29,7 +24,7 @@ module QL_DSPV2 ( // TODO: Name subject to change output wire [17:0] b_cout ); - parameter [67:0] MODE_BITS = 68'h00000000000000000; + parameter [71:0] MODE_BITS = 72'h000000000000000000; localparam [31:0] COEFF_0 = MODE_BITS[31:0]; localparam [5:0] ACC_FIR = MODE_BITS[37:32]; @@ -47,7 +42,8 @@ module QL_DSPV2 ( // TODO: Name subject to change localparam C_REG = MODE_BITS[64]; localparam BC_REG = MODE_BITS[65]; localparam M_REG = MODE_BITS[66]; - localparam FRAC_MODE = MODE_BITS[67]; + localparam ZCIN_REG = MODE_BITS[67]; + localparam FRAC_MODE = MODE_BITS[71]; localparam NBITS_ACC = 64; localparam NBITS_A = 32; @@ -116,7 +112,8 @@ module QL_DSPV2 ( // TODO: Name subject to change .b_reg_i(B_REG), .c_reg_i(C_REG), .bc_reg_i(BC_REG), - .m_reg_i(M_REG) + .m_reg_i(M_REG), + .zcin_sel_i(ZCIN_REG) ); // Output used when fmode == 1 @@ -160,7 +157,8 @@ module QL_DSPV2 ( // TODO: Name subject to change .b_reg_i(B_REG), .c_reg_i(C_REG), .bc_reg_i(BC_REG), - .m_reg_i(M_REG) + .m_reg_i(M_REG), + .zcin_sel_i(ZCIN_REG) ); // Output used when fmode == 0 @@ -204,12 +202,12 @@ module QL_DSPV2 ( // TODO: Name subject to change .b_reg_i(B_REG), .c_reg_i(C_REG), .bc_reg_i(BC_REG), - .m_reg_i(M_REG) + .m_reg_i(M_REG), + .zcin_sel_i(ZCIN_REG) ); endmodule - module QL_DSPV2_MULT ( input wire [31:0] a, input wire [17:0] b, @@ -219,7 +217,7 @@ module QL_DSPV2_MULT ( input wire [2:0] output_select ); - parameter [67:0] MODE_BITS = 68'h00000000000000000; + parameter [71:0] MODE_BITS = 72'h000000000000000000; localparam [31:0] COEFF_0 = MODE_BITS[31:0]; localparam [5:0] ACC_FIR = MODE_BITS[37:32]; @@ -237,10 +235,11 @@ module QL_DSPV2_MULT ( localparam C_REG = MODE_BITS[64]; localparam BC_REG = MODE_BITS[65]; localparam M_REG = MODE_BITS[66]; - localparam FRAC_MODE = MODE_BITS[67]; + localparam ZCIN_REG = MODE_BITS[67]; + localparam FRAC_MODE = MODE_BITS[71]; QL_DSPV2 #( - .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + .MODE_BITS({FRAC_MODE,3'b000,ZCIN_REG,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) ) dsp ( .a(a), .b(b), @@ -278,7 +277,7 @@ module QL_DSPV2_MULT_REGIN ( input wire [2:0] output_select ); - parameter [67:0] MODE_BITS = 68'h0A000000000000000; + parameter [71:0] MODE_BITS = 72'h00A000000000000000; localparam [31:0] COEFF_0 = MODE_BITS[31:0]; localparam [5:0] ACC_FIR = MODE_BITS[37:32]; @@ -296,10 +295,11 @@ module QL_DSPV2_MULT_REGIN ( localparam C_REG = MODE_BITS[64]; localparam BC_REG = MODE_BITS[65]; localparam M_REG = MODE_BITS[66]; - localparam FRAC_MODE = MODE_BITS[67]; + localparam ZCIN_REG = MODE_BITS[67]; + localparam FRAC_MODE = MODE_BITS[71]; QL_DSPV2 #( - .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + .MODE_BITS({FRAC_MODE,3'b000,ZCIN_REG,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) ) dsp ( .a(a), .b(b), @@ -337,7 +337,7 @@ module QL_DSPV2_MULT_REGOUT ( input wire [2:0] output_select ); - parameter [67:0] MODE_BITS = 68'h00000000000000000; + parameter [71:0] MODE_BITS = 72'h000000000000000000; localparam [31:0] COEFF_0 = MODE_BITS[31:0]; localparam [5:0] ACC_FIR = MODE_BITS[37:32]; @@ -355,10 +355,11 @@ module QL_DSPV2_MULT_REGOUT ( localparam C_REG = MODE_BITS[64]; localparam BC_REG = MODE_BITS[65]; localparam M_REG = MODE_BITS[66]; - localparam FRAC_MODE = MODE_BITS[67]; + localparam ZCIN_REG = MODE_BITS[67]; + localparam FRAC_MODE = MODE_BITS[71]; QL_DSPV2 #( - .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + .MODE_BITS({FRAC_MODE,3'b000,ZCIN_REG,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) ) dsp ( .a(a), .b(b), @@ -383,7 +384,7 @@ module QL_DSPV2_MULT_REGOUT ( endmodule -module QL_DSPV2_MULT_REGIN_REGOUT ( // TODO: Name subject to change +module QL_DSPV2_MULT_REGIN_REGOUT ( input wire [31:0] a, input wire [17:0] b, output wire [49:0] z, @@ -396,7 +397,7 @@ module QL_DSPV2_MULT_REGIN_REGOUT ( // TODO: Name subject to change input wire [2:0] output_select ); - parameter [67:0] MODE_BITS = 68'h0A000000000000000; + parameter [71:0] MODE_BITS = 72'h00A000000000000000; localparam [31:0] COEFF_0 = MODE_BITS[31:0]; localparam [5:0] ACC_FIR = MODE_BITS[37:32]; @@ -414,10 +415,11 @@ module QL_DSPV2_MULT_REGIN_REGOUT ( // TODO: Name subject to change localparam C_REG = MODE_BITS[64]; localparam BC_REG = MODE_BITS[65]; localparam M_REG = MODE_BITS[66]; - localparam FRAC_MODE = MODE_BITS[67]; + localparam ZCIN_REG = MODE_BITS[67]; + localparam FRAC_MODE = MODE_BITS[71]; QL_DSPV2 #( - .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + .MODE_BITS({FRAC_MODE,3'b000,ZCIN_REG,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) ) dsp ( .a(a), .b(b), @@ -446,12 +448,21 @@ module QL_DSPV2_MULTADD ( input wire [31:0] a, input wire [17:0] b, output wire [49:0] z, + + (* clkbuf_sink *) + input wire clk, + input wire reset, + input wire acc_reset, + input wire load_acc, + + input wire [49:0] z_cin, + output wire [49:0] z_cout, input wire [ 2:0] feedback, input wire [ 2:0] output_select ); - parameter [67:0] MODE_BITS = 68'h00000000000000000; + parameter [71:0] MODE_BITS = 72'h000000000000000000; localparam [31:0] COEFF_0 = MODE_BITS[31:0]; localparam [5:0] ACC_FIR = MODE_BITS[37:32]; @@ -469,28 +480,29 @@ module QL_DSPV2_MULTADD ( localparam C_REG = MODE_BITS[64]; localparam BC_REG = MODE_BITS[65]; localparam M_REG = MODE_BITS[66]; - localparam FRAC_MODE = MODE_BITS[67]; + localparam ZCIN_REG = MODE_BITS[67]; + localparam FRAC_MODE = MODE_BITS[71]; QL_DSPV2 #( - .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + .MODE_BITS({FRAC_MODE,3'b000,ZCIN_REG,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) ) dsp ( .a(a), .b(b), .c(18'h0), - .load_acc(1'b0), + .load_acc(load_acc), .feedback(feedback), .output_select(output_select), .z(z), - .clk(), - .reset(), - .acc_reset(1'b0), + .clk(clk), + .reset(reset), + .acc_reset(acc_reset), .a_cin(), .b_cin(), - .z_cin(), + .z_cin(z_cin), - .z_cout(), + .z_cout(z_cout), .a_cout(), .b_cout() ); @@ -501,16 +513,21 @@ module QL_DSPV2_MULTADD_REGIN ( input wire [31:0] a, input wire [17:0] b, output wire [49:0] z, - - (* clkbuf_sink *) + + (* clkbuf_sink *) input wire clk, input wire reset, + input wire acc_reset, + input wire load_acc, + + input wire [49:0] z_cin, + output wire [49:0] z_cout, input wire [ 2:0] feedback, input wire [ 2:0] output_select ); - parameter [67:0] MODE_BITS = 68'h0A000000000000000; + parameter [71:0] MODE_BITS = 72'h00A000000000000000; localparam [31:0] COEFF_0 = MODE_BITS[31:0]; localparam [5:0] ACC_FIR = MODE_BITS[37:32]; @@ -528,28 +545,29 @@ module QL_DSPV2_MULTADD_REGIN ( localparam C_REG = MODE_BITS[64]; localparam BC_REG = MODE_BITS[65]; localparam M_REG = MODE_BITS[66]; - localparam FRAC_MODE = MODE_BITS[67]; + localparam ZCIN_REG = MODE_BITS[67]; + localparam FRAC_MODE = MODE_BITS[71]; QL_DSPV2 #( - .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + .MODE_BITS({FRAC_MODE,3'b000,ZCIN_REG,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) ) dsp ( .a(a), .b(b), .c(18'h0), - .load_acc(1'b0), + .load_acc(load_acc), .feedback(feedback), .output_select(output_select), .z(z), .clk(clk), .reset(reset), - .acc_reset(1'b0), + .acc_reset(acc_reset), .a_cin(), .b_cin(), - .z_cin(), + .z_cin(z_cin), - .z_cout(), + .z_cout(z_cout), .a_cout(), .b_cout() ); @@ -560,16 +578,21 @@ module QL_DSPV2_MULTADD_REGOUT ( input wire [31:0] a, input wire [17:0] b, output wire [49:0] z, - - (* clkbuf_sink *) + + (* clkbuf_sink *) input wire clk, input wire reset, + input wire acc_reset, + input wire load_acc, + + input wire [49:0] z_cin, + output wire [49:0] z_cout, input wire [ 2:0] feedback, input wire [ 2:0] output_select ); - parameter [67:0] MODE_BITS = 68'h00000000000000000; + parameter [71:0] MODE_BITS = 72'h000000000000000000; localparam [31:0] COEFF_0 = MODE_BITS[31:0]; localparam [5:0] ACC_FIR = MODE_BITS[37:32]; @@ -587,28 +610,29 @@ module QL_DSPV2_MULTADD_REGOUT ( localparam C_REG = MODE_BITS[64]; localparam BC_REG = MODE_BITS[65]; localparam M_REG = MODE_BITS[66]; - localparam FRAC_MODE = MODE_BITS[67]; + localparam ZCIN_REG = MODE_BITS[67]; + localparam FRAC_MODE = MODE_BITS[71]; QL_DSPV2 #( - .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + .MODE_BITS({FRAC_MODE,3'b000,ZCIN_REG,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) ) dsp ( .a(a), .b(b), .c(18'h0), - .load_acc(1'b0), + .load_acc(load_acc), .feedback(feedback), .output_select(output_select), .z(z), .clk(clk), .reset(reset), - .acc_reset(1'b0), + .acc_reset(acc_reset), .a_cin(), .b_cin(), - .z_cin(), + .z_cin(z_cin), - .z_cout(), + .z_cout(z_cout), .a_cout(), .b_cout() ); @@ -619,16 +643,21 @@ module QL_DSPV2_MULTADD_REGIN_REGOUT ( input wire [31:0] a, input wire [17:0] b, output wire [49:0] z, - - (* clkbuf_sink *) + + (* clkbuf_sink *) input wire clk, input wire reset, + input wire acc_reset, + input wire load_acc, + + input wire [49:0] z_cin, + output wire [49:0] z_cout, input wire [ 2:0] feedback, input wire [ 2:0] output_select ); - parameter [67:0] MODE_BITS = 68'h0A000000000000000; + parameter [71:0] MODE_BITS = 72'h00A000000000000000; localparam [31:0] COEFF_0 = MODE_BITS[31:0]; localparam [5:0] ACC_FIR = MODE_BITS[37:32]; @@ -646,28 +675,29 @@ module QL_DSPV2_MULTADD_REGIN_REGOUT ( localparam C_REG = MODE_BITS[64]; localparam BC_REG = MODE_BITS[65]; localparam M_REG = MODE_BITS[66]; - localparam FRAC_MODE = MODE_BITS[67]; + localparam ZCIN_REG = MODE_BITS[67]; + localparam FRAC_MODE = MODE_BITS[71]; QL_DSPV2 #( - .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + .MODE_BITS({FRAC_MODE,3'b000,ZCIN_REG,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) ) dsp ( .a(a), .b(b), .c(18'h0), - .load_acc(1'b0), + .load_acc(load_acc), .feedback(feedback), .output_select(output_select), .z(z), .clk(clk), .reset(reset), - .acc_reset(1'b0), + .acc_reset(acc_reset), .a_cin(), .b_cin(), - .z_cin(), + .z_cin(z_cin), - .z_cout(), + .z_cout(z_cout), .a_cout(), .b_cout() ); @@ -688,7 +718,7 @@ module QL_DSPV2_MULTACC ( input wire [ 2:0] output_select ); - parameter [67:0] MODE_BITS = 68'h00000000000000000; + parameter [71:0] MODE_BITS = 72'h000000000000000000; localparam [31:0] COEFF_0 = MODE_BITS[31:0]; localparam [5:0] ACC_FIR = MODE_BITS[37:32]; @@ -706,10 +736,11 @@ module QL_DSPV2_MULTACC ( localparam C_REG = MODE_BITS[64]; localparam BC_REG = MODE_BITS[65]; localparam M_REG = MODE_BITS[66]; - localparam FRAC_MODE = MODE_BITS[67]; + localparam ZCIN_REG = MODE_BITS[67]; + localparam FRAC_MODE = MODE_BITS[71]; QL_DSPV2 #( - .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + .MODE_BITS({FRAC_MODE,3'b000,ZCIN_REG,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) ) dsp ( .a(a), .b(b), @@ -748,7 +779,7 @@ module QL_DSPV2_MULTACC_REGIN ( input wire [ 2:0] output_select ); - parameter [67:0] MODE_BITS = 68'h04000000000000000; + parameter [71:0] MODE_BITS = 72'h004000000000000000; localparam [31:0] COEFF_0 = MODE_BITS[31:0]; localparam [5:0] ACC_FIR = MODE_BITS[37:32]; @@ -766,10 +797,11 @@ module QL_DSPV2_MULTACC_REGIN ( localparam C_REG = MODE_BITS[64]; localparam BC_REG = MODE_BITS[65]; localparam M_REG = MODE_BITS[66]; - localparam FRAC_MODE = MODE_BITS[67]; + localparam ZCIN_REG = MODE_BITS[67]; + localparam FRAC_MODE = MODE_BITS[71]; QL_DSPV2 #( - .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + .MODE_BITS({FRAC_MODE,3'b000,ZCIN_REG,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) ) dsp ( .a(a), .b(b), @@ -808,7 +840,7 @@ module QL_DSPV2_MULTACC_REGOUT ( input wire [ 2:0] output_select ); - parameter [67:0] MODE_BITS = 68'h00000000000000000; + parameter [71:0] MODE_BITS = 72'h000000000000000000; localparam [31:0] COEFF_0 = MODE_BITS[31:0]; localparam [5:0] ACC_FIR = MODE_BITS[37:32]; @@ -826,10 +858,11 @@ module QL_DSPV2_MULTACC_REGOUT ( localparam C_REG = MODE_BITS[64]; localparam BC_REG = MODE_BITS[65]; localparam M_REG = MODE_BITS[66]; - localparam FRAC_MODE = MODE_BITS[67]; + localparam ZCIN_REG = MODE_BITS[67]; + localparam FRAC_MODE = MODE_BITS[71]; QL_DSPV2 #( - .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + .MODE_BITS({FRAC_MODE,3'b000,ZCIN_REG,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) ) dsp ( .a(a), .b(b), @@ -868,7 +901,7 @@ module QL_DSPV2_MULTACC_REGIN_REGOUT ( input wire [ 2:0] output_select ); - parameter [67:0] MODE_BITS = 68'h04000000000000000; + parameter [71:0] MODE_BITS = 72'h004000000000000000; localparam [31:0] COEFF_0 = MODE_BITS[31:0]; localparam [5:0] ACC_FIR = MODE_BITS[37:32]; @@ -886,10 +919,11 @@ module QL_DSPV2_MULTACC_REGIN_REGOUT ( localparam C_REG = MODE_BITS[64]; localparam BC_REG = MODE_BITS[65]; localparam M_REG = MODE_BITS[66]; - localparam FRAC_MODE = MODE_BITS[67]; + localparam ZCIN_REG = MODE_BITS[67]; + localparam FRAC_MODE = MODE_BITS[71]; QL_DSPV2 #( - .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + .MODE_BITS({FRAC_MODE,3'b000,ZCIN_REG,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) ) dsp ( .a(a), .b(b), @@ -955,10 +989,11 @@ module dspv2_32x18x64_cfg_ports ( parameter C_REG = 1'b0; parameter BC_REG = 1'b0; parameter M_REG = 1'b0; + parameter ZCIN_REG = 1'b0; parameter FRAC_MODE = 1'b0; // 32x18x64 DSP QL_DSPV2 #( - .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + .MODE_BITS({FRAC_MODE,3'b000,ZCIN_REG,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) ) dsp ( .a(a_i), .b(b_i), @@ -976,9 +1011,9 @@ module dspv2_32x18x64_cfg_ports ( .b_cin(b_cin_i), .z_cin(z_cin_i), + .z_cout(z_cout_o), .a_cout(a_cout_o), - .b_cout(b_cout_o), - .z_cout(z_cout_o) + .b_cout(b_cout_o) ); endmodule @@ -986,7 +1021,7 @@ endmodule module dspv2_16x9x32_cfg_ports ( input wire [15:0] a_i, input wire [8:0] b_i, - input wire [9:0] c_i, + input wire [8:0] c_i, output wire [24:0] z_o, (* clkbuf_sink *) @@ -1024,10 +1059,11 @@ module dspv2_16x9x32_cfg_ports ( parameter C_REG = 1'b0; parameter BC_REG = 1'b0; parameter M_REG = 1'b0; + parameter ZCIN_REG = 1'b0; parameter FRAC_MODE = 1'b1; // 16x9x32 DSP QL_DSPV2 #( - .MODE_BITS({FRAC_MODE,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,16'h0,COEFF_0}) + .MODE_BITS({FRAC_MODE,3'b000,ZCIN_REG,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,16'h0,COEFF_0}) ) dsp ( .a(a_i), .b(b_i), @@ -1045,14 +1081,13 @@ module dspv2_16x9x32_cfg_ports ( .b_cin(b_cin_i), .z_cin(z_cin_i), - .z_cout(a_cout_o), - .a_cout(b_cout_o), - .b_cout(z_cout_o) + .z_cout(z_cout_o), + .a_cout(a_cout_o), + .b_cout(b_cout_o) ); endmodule - module dspv2_sim_cfg_ports # ( parameter NBITS_ACC = 64, parameter NBITS_A = 32, @@ -1095,7 +1130,8 @@ module dspv2_sim_cfg_ports # ( input wire b_reg_i, input wire c_reg_i, input wire bc_reg_i, - input wire m_reg_i + input wire m_reg_i, + input wire zcin_sel_i ); // Input registers @@ -1207,7 +1243,8 @@ module dspv2_sim_cfg_ports # ( // Output signals wire [NBITS_Z-1:0] z0; reg [NBITS_Z-1:0] z1; - wire [NBITS_Z-1:0] z2; + wire [NBITS_Z-1:0] z2; + wire [NBITS_Z-1:0] z_cin; assign mult_a = (feedback_i == 3'h0) ? a : (feedback_i == 3'h1) ? a : @@ -1249,8 +1286,10 @@ module dspv2_sim_cfg_ports # ( assign acc_fir_int = a <<< acc_fir_i; - assign zcin_rshift = z_cin_i >>> zc_shift_i; - assign zcin_xtnd = {{(NBITS_ACC-NBITS_Z){z_cin_i[NBITS_Z-1]}}, z_cin_i}; + + assign z_cin = (zcin_sel_i)? z_cin_i : 50'h0; + assign zcin_rshift = z_cin >>> zc_shift_i; + assign zcin_xtnd = {{(NBITS_ACC-NBITS_Z){z_cin[NBITS_Z-1]}}, z_cin}; assign zreg_rshift = z1 >>> zreg_shift_i; @@ -1379,4 +1418,4 @@ module dspv2_sim_cfg_ports # ( assign a_cout_o = r_a; assign b_cout_o = r_b; -endmodule +endmodule \ No newline at end of file From 62885f1de306e7b3202604e6ffa88c302fb82960 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 6 Mar 2025 12:54:36 +0100 Subject: [PATCH 10/38] quicklogic: ql_dsp_simd remove unused MODE_BITS packing --- techlibs/quicklogic/ql_dsp_simd.cc | 45 +++++------------------------- 1 file changed, 7 insertions(+), 38 deletions(-) diff --git a/techlibs/quicklogic/ql_dsp_simd.cc b/techlibs/quicklogic/ql_dsp_simd.cc index 8e914f57f..b77464cb3 100644 --- a/techlibs/quicklogic/ql_dsp_simd.cc +++ b/techlibs/quicklogic/ql_dsp_simd.cc @@ -61,9 +61,6 @@ struct QlDspSimdPass : public Pass { // .......................................... - const int m_Dspv1ModeBitsSize = 80; - const int m_Dspv2ModeBitsSize = 68; - /// Temporary SigBit to SigBit helper map. SigMap sigmap; @@ -110,12 +107,13 @@ struct QlDspSimdPass : public Pass { ID(shift_right_i), ID(subtract_i), ID(register_inputs_i), - ID(coeff_0_i), - ID(coeff_1_i), - ID(coeff_2_i), - ID(coeff_3_i), }; - static const std::vector m_Dspv1CfgParams = {}; + static const std::vector m_Dspv1CfgParams = { + ID(COEFF_0), + ID(COEFF_1), + ID(COEFF_2), + ID(COEFF_3), + }; static const std::vector m_Dspv2CfgPorts = { ID(clock_i), ID(reset_i), @@ -159,15 +157,6 @@ struct QlDspSimdPass : public Pass { ID(z_o), }; - // Params to serialize into MODE_BITS param - static const std::vector m_Dspv1ModeBitParams = { - ID(COEFF_3), - ID(COEFF_2), - ID(COEFF_1), - ID(COEFF_0), - }; - static const std::vector m_Dspv2ModeBitParams = {}; - // Source DSP cell type (half-block) static const IdString m_Dspv1SisdType = ID(dsp_t1_10x9x32_cfg_ports); static const IdString m_Dspv2SisdType = ID(dspv2_16x9x32_cfg_ports); @@ -195,8 +184,6 @@ struct QlDspSimdPass : public Pass { const auto& data_ports = (dsp_version == 1) ? m_Dspv1DataPorts : m_Dspv2DataPorts; auto half_dsp = (dsp_version == 1) ? m_Dspv1SisdType : m_Dspv2SisdType; auto full_dsp = (dsp_version == 1) ? m_Dspv1SimdType : m_Dspv2SimdType; - auto mode_bit_params = (dsp_version == 1) ? m_Dspv1ModeBitParams : m_Dspv2ModeBitParams; - auto mode_bits_size = (dsp_version == 1) ? m_Dspv1ModeBitsSize : m_Dspv2ModeBitsSize; int cellsMerged = 0; // Process modules @@ -300,27 +287,9 @@ struct QlDspSimdPass : public Pass { simd->setPort(port, sigspec); } - if (mode_bit_params.size()) { - // Concatenate FIR coefficient parameters into the single - // MODE_BITS parameter - Const mode_bits; - for (const auto &it : mode_bit_params) { - auto val_a = dsp_a->getParam(it); - auto val_b = dsp_b->getParam(it); - - mode_bits.bits().insert(mode_bits.bits().end(), - val_a.begin(), val_a.end()); - mode_bits.bits().insert(mode_bits.bits().end(), - val_b.begin(), val_b.end()); - } - - simd->setParam(ID(MODE_BITS), mode_bits); - log_assert(mode_bits.size() == mode_bits_size); - - } // Enable the fractured mode if (dsp_version == 1) - simd->setPort(ID(f_mode), State::S1); + simd->setPort(ID(f_mode_i), State::S1); else simd->setParam(ID(FRAC_MODE), State::S1); From fcdd013c57330c215c59c89fbc07dbf6501f30bb Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 6 Mar 2025 12:55:26 +0100 Subject: [PATCH 11/38] quicklogic: allow fractured mode on canonical dspv1 modules --- techlibs/quicklogic/qlf_k6n10f/dspv1_final_map.v | 5 +++-- techlibs/quicklogic/qlf_k6n10f/dspv1_sim.v | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/techlibs/quicklogic/qlf_k6n10f/dspv1_final_map.v b/techlibs/quicklogic/qlf_k6n10f/dspv1_final_map.v index 9eae617b9..118fe1b5a 100644 --- a/techlibs/quicklogic/qlf_k6n10f/dspv1_final_map.v +++ b/techlibs/quicklogic/qlf_k6n10f/dspv1_final_map.v @@ -34,7 +34,8 @@ module dsp_t1_20x18x64_cfg_ports ( input [5:0] shift_right_i, input round_i, input subtract_i, - input register_inputs_i + input register_inputs_i, + input f_mode_i ); parameter [19:0] COEFF_0 = 20'd0; @@ -59,7 +60,7 @@ module dsp_t1_20x18x64_cfg_ports ( .unsigned_a (unsigned_a_i), .unsigned_b (unsigned_b_i), - .f_mode (1'b0), // No fracturation + .f_mode (f_mode_i), // No fracturation .output_select (output_select_i), .saturate_enable (saturate_enable_i), .shift_right (shift_right_i), diff --git a/techlibs/quicklogic/qlf_k6n10f/dspv1_sim.v b/techlibs/quicklogic/qlf_k6n10f/dspv1_sim.v index 5f43b3229..474e3d647 100644 --- a/techlibs/quicklogic/qlf_k6n10f/dspv1_sim.v +++ b/techlibs/quicklogic/qlf_k6n10f/dspv1_sim.v @@ -4195,7 +4195,8 @@ module dsp_t1_20x18x64_cfg_ports ( input wire [ 5:0] shift_right_i, input wire round_i, input wire subtract_i, - input wire register_inputs_i + input wire register_inputs_i, + input wire f_mode_i ); parameter [19:0] COEFF_0 = 20'd0; @@ -4211,7 +4212,7 @@ module dsp_t1_20x18x64_cfg_ports ( .z(z_o), .dly_b(dly_b_o), - .f_mode(1'b0), // 20x18x64 DSP + .f_mode(f_mode_i), // 20x18x64 DSP .acc_fir(acc_fir_i), .feedback(feedback_i), From 642c313947c928f1170b910bc9acf9fb8076c1fa Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 6 Mar 2025 12:55:56 +0100 Subject: [PATCH 12/38] quicklogic: remove irrelevant comments in dspv2 test --- tests/arch/quicklogic/qlf_k6n10f/dspv2_simd.ys | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/arch/quicklogic/qlf_k6n10f/dspv2_simd.ys b/tests/arch/quicklogic/qlf_k6n10f/dspv2_simd.ys index d1440c921..aa79ddcb7 100644 --- a/tests/arch/quicklogic/qlf_k6n10f/dspv2_simd.ys +++ b/tests/arch/quicklogic/qlf_k6n10f/dspv2_simd.ys @@ -19,7 +19,6 @@ ql_dsp_macc -dspv2 techmap -map +/mul2dsp.v -map +/quicklogic/qlf_k6n10f/dspv2_map.v -D USE_DSP_CFG_PARAMS=0 -D DSP_SIGNEDONLY -D DSP_A_MAXWIDTH=32 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=10 -D DSP_B_MINWIDTH=10 -D DSP_NAME=$__MUL32X18 chtype -set $mul t:$__soft_mul techmap -map +/mul2dsp.v -map +/quicklogic/qlf_k6n10f/dspv2_map.v -D USE_DSP_CFG_PARAMS=0 -D DSP_SIGNEDONLY -D DSP_A_MAXWIDTH=16 -D DSP_B_MAXWIDTH=9 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_NAME=$__MUL16X9 -# TODO is this missing from synth_quicklogic? read_verilog -lib +/quicklogic/qlf_k6n10f/dspv2_sim.v select -assert-count 2 t:dspv2_16x9x32_cfg_ports select -assert-count 0 t:dspv2_32x18x64_cfg_ports @@ -51,7 +50,6 @@ ql_dsp_macc -dspv2 techmap -map +/mul2dsp.v -map +/quicklogic/qlf_k6n10f/dspv2_map.v -D USE_DSP_CFG_PARAMS=0 -D DSP_SIGNEDONLY -D DSP_A_MAXWIDTH=32 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=10 -D DSP_B_MINWIDTH=10 -D DSP_NAME=$__MUL32X18 chtype -set $mul t:$__soft_mul techmap -map +/mul2dsp.v -map +/quicklogic/qlf_k6n10f/dspv2_map.v -D USE_DSP_CFG_PARAMS=0 -D DSP_SIGNEDONLY -D DSP_A_MAXWIDTH=16 -D DSP_B_MAXWIDTH=9 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_NAME=$__MUL16X9 -# TODO is this missing from synth_quicklogic? read_verilog -lib +/quicklogic/qlf_k6n10f/dspv2_sim.v select -assert-count 2 t:dspv2_16x9x32_cfg_ports select -assert-count 0 t:dspv2_32x18x64_cfg_ports From 7380cf6217c77d6bdf01f947dc7320147f48dcee Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 6 Mar 2025 12:56:11 +0100 Subject: [PATCH 13/38] quicklogic: ql_dsp_simd add dspv1 test --- .../arch/quicklogic/qlf_k6n10f/dspv1_simd.ys | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 tests/arch/quicklogic/qlf_k6n10f/dspv1_simd.ys diff --git a/tests/arch/quicklogic/qlf_k6n10f/dspv1_simd.ys b/tests/arch/quicklogic/qlf_k6n10f/dspv1_simd.ys new file mode 100644 index 000000000..d6088bf26 --- /dev/null +++ b/tests/arch/quicklogic/qlf_k6n10f/dspv1_simd.ys @@ -0,0 +1,63 @@ +read_verilog < Date: Thu, 6 Mar 2025 17:59:46 +0100 Subject: [PATCH 14/38] quicklogic: rename dspv1 full synth_quicklogic test for clarity --- tests/arch/quicklogic/qlf_k6n10f/{dsp.ys => dspv1_full.ys} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename tests/arch/quicklogic/qlf_k6n10f/{dsp.ys => dspv1_full.ys} (93%) diff --git a/tests/arch/quicklogic/qlf_k6n10f/dsp.ys b/tests/arch/quicklogic/qlf_k6n10f/dspv1_full.ys similarity index 93% rename from tests/arch/quicklogic/qlf_k6n10f/dsp.ys rename to tests/arch/quicklogic/qlf_k6n10f/dspv1_full.ys index 1e652855b..6f61b434b 100644 --- a/tests/arch/quicklogic/qlf_k6n10f/dsp.ys +++ b/tests/arch/quicklogic/qlf_k6n10f/dspv1_full.ys @@ -21,7 +21,7 @@ EOF design -save ast proc wreduce -#equiv_opt -async2sync -map +/quicklogic/qlf_k6n10f/dsp_sim.v synth_quicklogic -family qlf_k6n10f +#equiv_opt -async2sync -map +/quicklogic/qlf_k6n10f/dspv1_sim.v synth_quicklogic -family qlf_k6n10f #design -load postopt synth_quicklogic -family qlf_k6n10f cd top @@ -114,8 +114,8 @@ always @(posedge clk) begin end endmodule EOF -read_verilog +/quicklogic/qlf_k6n10f/dsp_sim.v +read_verilog +/quicklogic/qlf_k6n10f/dspv1_sim.v hierarchy -top testbench proc async2sync -sim -assert -q -clock clk -n 20 +sim -q -clock clk -n 20 -assert From 15b3ed47472968edc0ed0f10e7a8d2f3f07ae955 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 6 Mar 2025 18:00:23 +0100 Subject: [PATCH 15/38] quicklogic: ql_dsp_macc set fractured mode --- techlibs/quicklogic/ql_dsp_macc.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/techlibs/quicklogic/ql_dsp_macc.cc b/techlibs/quicklogic/ql_dsp_macc.cc index 7e118d6fc..69ed93c4a 100644 --- a/techlibs/quicklogic/ql_dsp_macc.cc +++ b/techlibs/quicklogic/ql_dsp_macc.cc @@ -60,6 +60,10 @@ static void create_ql_macc_dsp(ql_dsp_macc_pm &pm, int dsp_version) if (dsp_version == 2) cell_base_name = "dspv2"; + std::function set_fractured = nullptr; + auto set_fractured_dspv1 = [](Cell* cell) -> void {cell->setPort(ID(f_mode_i), State::S0);}; + auto set_fractured_dspv2 = [](Cell* cell) -> void {cell->setParam(ID(FRAC_MODE), State::S0);}; + if (min_width <= 2 && max_width <= 2 && z_width <= 4) { log_debug("\trejected: too narrow (%zd %zd %zd)\n", min_width, max_width, z_width); return; @@ -77,6 +81,7 @@ static void create_ql_macc_dsp(ql_dsp_macc_pm &pm, int dsp_version) tgt_a_width = 20; tgt_b_width = 18; tgt_z_width = 38; + set_fractured = set_fractured_dspv1; } else { reject = true; } @@ -91,6 +96,7 @@ static void create_ql_macc_dsp(ql_dsp_macc_pm &pm, int dsp_version) tgt_a_width = 20; tgt_b_width = 18; tgt_z_width = 50; + set_fractured = set_fractured_dspv2; } else { reject = true; } @@ -202,6 +208,10 @@ static void create_ql_macc_dsp(ql_dsp_macc_pm &pm, int dsp_version) bool subtract = (st.add->type == ID($sub)); cell->setPort(ID(subtract_i), RTLIL::SigSpec(subtract ? RTLIL::S1 : RTLIL::S0)); + // Disable fractured mode + if (set_fractured) + set_fractured(cell); + // Mark the cells for removal pm.autoremove(st.mul); pm.autoremove(st.add); From 35efe92949e49795dd566e67fe86821b96ab700f Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 6 Mar 2025 18:00:53 +0100 Subject: [PATCH 16/38] quicklogic: fix dspv2 tests --- tests/arch/quicklogic/dspv2/complex_mult.ys | 2 +- tests/arch/quicklogic/dspv2/simple2.ys | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/arch/quicklogic/dspv2/complex_mult.ys b/tests/arch/quicklogic/dspv2/complex_mult.ys index b182f4067..350ee8d6b 100644 --- a/tests/arch/quicklogic/dspv2/complex_mult.ys +++ b/tests/arch/quicklogic/dspv2/complex_mult.ys @@ -14,7 +14,7 @@ EOF synth_quicklogic -family qlf_k6n10f -dspv2 -run :coarse check -assert -read_verilog +/quicklogic/qlf_k6n10f/dsp_sim.v +read_verilog +/quicklogic/qlf_k6n10f/dspv2_sim.v prep -top top -flatten opt_clean -purge opt -full diff --git a/tests/arch/quicklogic/dspv2/simple2.ys b/tests/arch/quicklogic/dspv2/simple2.ys index d03a412a8..a9a1794b8 100644 --- a/tests/arch/quicklogic/dspv2/simple2.ys +++ b/tests/arch/quicklogic/dspv2/simple2.ys @@ -6,7 +6,7 @@ endmodule EOF synth_quicklogic -family qlf_k6n10f -dspv2 -run :coarse -read_verilog +/quicklogic/qlf_k6n10f/dsp_sim.v +read_verilog +/quicklogic/qlf_k6n10f/dspv2_sim.v prep -top top -flatten opt_clean -purge dump From fb3ad314ba75aee09703209154bc67c3c9f75e6a Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 6 Mar 2025 18:01:28 +0100 Subject: [PATCH 17/38] quicklogic: ql_dsp_io_regs debug print --- techlibs/quicklogic/ql_dsp_io_regs.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/techlibs/quicklogic/ql_dsp_io_regs.cc b/techlibs/quicklogic/ql_dsp_io_regs.cc index ecf163dbf..d99623dcc 100644 --- a/techlibs/quicklogic/ql_dsp_io_regs.cc +++ b/techlibs/quicklogic/ql_dsp_io_regs.cc @@ -127,6 +127,7 @@ struct QlDspIORegs : public Pass { } // Set new type name + log_debug("Converted %s to %s\n", log_id(cell->type), new_type.c_str()); cell->type = RTLIL::IdString(new_type); std::vector ports2del; From 4cbc92f50f98ba6da09208a2bb0715da5d1f4155 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 10 Mar 2025 17:12:31 +0100 Subject: [PATCH 18/38] quicklogic: add fracturable full-block dspv1 to keep vendor simulation model unchanged --- techlibs/quicklogic/Makefile.inc | 1 + techlibs/quicklogic/ql_dsp_macc.cc | 2 - techlibs/quicklogic/ql_dsp_simd.cc | 8 +- .../quicklogic/qlf_k6n10f/dspv1_final_map.v | 62 +++++++++++++- techlibs/quicklogic/qlf_k6n10f/dspv1_sim.v | 5 +- .../quicklogic/qlf_k6n10f/dspv1_sim_extra.v | 80 +++++++++++++++++++ techlibs/quicklogic/synth_quicklogic.cc | 5 +- .../arch/quicklogic/qlf_k6n10f/dspv1_simd.ys | 14 ++-- 8 files changed, 157 insertions(+), 20 deletions(-) create mode 100644 techlibs/quicklogic/qlf_k6n10f/dspv1_sim_extra.v diff --git a/techlibs/quicklogic/Makefile.inc b/techlibs/quicklogic/Makefile.inc index 32681a31f..684eb28a3 100644 --- a/techlibs/quicklogic/Makefile.inc +++ b/techlibs/quicklogic/Makefile.inc @@ -40,6 +40,7 @@ $(eval $(call add_gen_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/cells_sim.v)) $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/ffs_map.v)) $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dspv1_sim.v)) +$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dspv1_sim_extra.v)) $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dspv1_map.v)) $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dspv1_final_map.v)) $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dspv2_sim.v)) diff --git a/techlibs/quicklogic/ql_dsp_macc.cc b/techlibs/quicklogic/ql_dsp_macc.cc index 69ed93c4a..de52156ef 100644 --- a/techlibs/quicklogic/ql_dsp_macc.cc +++ b/techlibs/quicklogic/ql_dsp_macc.cc @@ -61,7 +61,6 @@ static void create_ql_macc_dsp(ql_dsp_macc_pm &pm, int dsp_version) cell_base_name = "dspv2"; std::function set_fractured = nullptr; - auto set_fractured_dspv1 = [](Cell* cell) -> void {cell->setPort(ID(f_mode_i), State::S0);}; auto set_fractured_dspv2 = [](Cell* cell) -> void {cell->setParam(ID(FRAC_MODE), State::S0);}; if (min_width <= 2 && max_width <= 2 && z_width <= 4) { @@ -81,7 +80,6 @@ static void create_ql_macc_dsp(ql_dsp_macc_pm &pm, int dsp_version) tgt_a_width = 20; tgt_b_width = 18; tgt_z_width = 38; - set_fractured = set_fractured_dspv1; } else { reject = true; } diff --git a/techlibs/quicklogic/ql_dsp_simd.cc b/techlibs/quicklogic/ql_dsp_simd.cc index b77464cb3..9c2e340db 100644 --- a/techlibs/quicklogic/ql_dsp_simd.cc +++ b/techlibs/quicklogic/ql_dsp_simd.cc @@ -87,7 +87,7 @@ struct QlDspSimdPass : public Pass { log_header(a_Design, "Executing QL_DSP_SIMD pass.\n"); // The following lists have to match simulation model interfaces. - + // DSP control and config ports that must be equal between // merged half-blocks // In addition to functional differences, @@ -156,13 +156,13 @@ struct QlDspSimdPass : public Pass { ID(c_i), ID(z_o), }; - + // Source DSP cell type (half-block) static const IdString m_Dspv1SisdType = ID(dsp_t1_10x9x32_cfg_ports); static const IdString m_Dspv2SisdType = ID(dspv2_16x9x32_cfg_ports); // Target DSP cell types (full-block) - static const IdString m_Dspv1SimdType = ID(dsp_t1_20x18x64_cfg_ports); + static const IdString m_Dspv1SimdType = ID(dsp_t1_20x18x64_cfg_ports_fracturable); static const IdString m_Dspv2SimdType = ID(dspv2_32x18x64_cfg_ports); // Parse args @@ -241,7 +241,7 @@ struct QlDspSimdPass : public Pass { // Check if the target cell is known (important to know // its port widths) if (!simd->known()) - log_error(" The target cell type '%s' is not known!", log_id(simd)); + log_error(" The target cell type '%s' is not known!", log_id(simd->type)); // Connect common ports for (auto port : cfg_ports) { diff --git a/techlibs/quicklogic/qlf_k6n10f/dspv1_final_map.v b/techlibs/quicklogic/qlf_k6n10f/dspv1_final_map.v index 118fe1b5a..cdbc8056b 100644 --- a/techlibs/quicklogic/qlf_k6n10f/dspv1_final_map.v +++ b/techlibs/quicklogic/qlf_k6n10f/dspv1_final_map.v @@ -14,7 +14,7 @@ // // SPDX-License-Identifier: Apache-2.0 -module dsp_t1_20x18x64_cfg_ports ( +module dsp_t1_20x18x64_cfg_ports_fracturable ( input [19:0] a_i, input [17:0] b_i, input [ 5:0] acc_fir_i, @@ -60,7 +60,7 @@ module dsp_t1_20x18x64_cfg_ports ( .unsigned_a (unsigned_a_i), .unsigned_b (unsigned_b_i), - .f_mode (f_mode_i), // No fracturation + .f_mode (f_mode_i), .output_select (output_select_i), .saturate_enable (saturate_enable_i), .shift_right (shift_right_i), @@ -71,6 +71,62 @@ module dsp_t1_20x18x64_cfg_ports ( endmodule +module dsp_t1_20x18x64_cfg_ports ( + input [19:0] a_i, + input [17:0] b_i, + input [ 5:0] acc_fir_i, + output [37:0] z_o, + output [17:0] dly_b_o, + + input clock_i, + input reset_i, + + input [2:0] feedback_i, + input load_acc_i, + input unsigned_a_i, + input unsigned_b_i, + + input [2:0] output_select_i, + input saturate_enable_i, + input [5:0] shift_right_i, + input round_i, + input subtract_i, + input 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; + + dsp_t1_20x18x64_cfg_ports_fracturable # ( + .COEFF_0 (COEFF_0), + .COEFF_1 (COEFF_1), + .COEFF_2 (COEFF_2), + .COEFF_3 (COEFF_3) + ) _TECHMAP_REPLACE_ ( + .a_i (a_i), + .b_i (b_i), + .acc_fir_i (acc_fir_i), + .z_o (z_o), + .dly_b_o (dly_b_o), + .clock_i (clock_i), + .reset_i (reset_i), + .feedback_i (feedback_i), + .load_acc_i (load_acc_i), + .unsigned_a_i (unsigned_a_i), + .unsigned_b_i (unsigned_b_i), + .output_select_i (output_select_i), + .saturate_enable_i (saturate_enable_i), + .shift_right_i (shift_right_i), + .round_i (round_i), + .subtract_i (subtract_i), + .register_inputs_i (register_inputs_i), + .f_mode_i (1'b0) + ); + +endmodule + module dsp_t1_10x9x32_cfg_ports ( input [ 9:0] a_i, input [ 8:0] b_i, @@ -123,7 +179,7 @@ module dsp_t1_10x9x32_cfg_ports ( .unsigned_a (unsigned_a_i), .unsigned_b (unsigned_b_i), - .f_mode (1'b1), // Enable fractuation, Use the lower half + .f_mode (1'b0), .output_select (output_select_i), .saturate_enable (saturate_enable_i), .shift_right (shift_right_i), diff --git a/techlibs/quicklogic/qlf_k6n10f/dspv1_sim.v b/techlibs/quicklogic/qlf_k6n10f/dspv1_sim.v index 474e3d647..5f43b3229 100644 --- a/techlibs/quicklogic/qlf_k6n10f/dspv1_sim.v +++ b/techlibs/quicklogic/qlf_k6n10f/dspv1_sim.v @@ -4195,8 +4195,7 @@ module dsp_t1_20x18x64_cfg_ports ( input wire [ 5:0] shift_right_i, input wire round_i, input wire subtract_i, - input wire register_inputs_i, - input wire f_mode_i + input wire register_inputs_i ); parameter [19:0] COEFF_0 = 20'd0; @@ -4212,7 +4211,7 @@ module dsp_t1_20x18x64_cfg_ports ( .z(z_o), .dly_b(dly_b_o), - .f_mode(f_mode_i), // 20x18x64 DSP + .f_mode(1'b0), // 20x18x64 DSP .acc_fir(acc_fir_i), .feedback(feedback_i), diff --git a/techlibs/quicklogic/qlf_k6n10f/dspv1_sim_extra.v b/techlibs/quicklogic/qlf_k6n10f/dspv1_sim_extra.v new file mode 100644 index 000000000..d888ac08a --- /dev/null +++ b/techlibs/quicklogic/qlf_k6n10f/dspv1_sim_extra.v @@ -0,0 +1,80 @@ +// 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 + +`timescale 1ps/1ps + +`default_nettype none + +// dsp_t1_20x18x64_cfg_ports but with input wire f_mode_i +// This is a yosys-specific extension beyond the vendor-provided model +module dsp_t1_20x18x64_cfg_ports_fracturable ( + 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, + input wire f_mode_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(f_mode_i), // 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 diff --git a/techlibs/quicklogic/synth_quicklogic.cc b/techlibs/quicklogic/synth_quicklogic.cc index 3b924f604..2daafa451 100644 --- a/techlibs/quicklogic/synth_quicklogic.cc +++ b/techlibs/quicklogic/synth_quicklogic.cc @@ -213,9 +213,10 @@ struct SynthQuickLogicPass : public ScriptPass { read_simlibs += stringf(" %sqlf_k6n10f/brams_sim.v", lib_path.c_str()); if (bramTypes) read_simlibs += stringf(" %sqlf_k6n10f/bram_types_sim.v", lib_path.c_str()); - if (dsp == V1) + if (dsp == V1) { read_simlibs += stringf(" %sqlf_k6n10f/dspv1_sim.v", lib_path.c_str()); - else if (dsp == V2) + read_simlibs += stringf(" %sqlf_k6n10f/dspv1_sim_extra.v", lib_path.c_str()); + } else if (dsp == V2) read_simlibs += stringf(" %sqlf_k6n10f/dspv2_sim.v", lib_path.c_str()); } run(read_simlibs); diff --git a/tests/arch/quicklogic/qlf_k6n10f/dspv1_simd.ys b/tests/arch/quicklogic/qlf_k6n10f/dspv1_simd.ys index d6088bf26..26f0ca16b 100644 --- a/tests/arch/quicklogic/qlf_k6n10f/dspv1_simd.ys +++ b/tests/arch/quicklogic/qlf_k6n10f/dspv1_simd.ys @@ -21,13 +21,14 @@ chtype -set $mul t:$__soft_mul techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=10 -D DSP_B_MAXWIDTH=9 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_NAME=$__QL_MUL10X9 techmap -map +/quicklogic/qlf_k6n10f/dspv1_map.v -D USE_DSP_CFG_PARAMS=0 read_verilog -lib +/quicklogic/qlf_k6n10f/dspv1_sim.v +read_verilog -lib +/quicklogic/qlf_k6n10f/dspv1_sim_extra.v select -assert-count 2 t:dsp_t1_10x9x32_cfg_ports -select -assert-count 0 t:dsp_t1_20x18x64_cfg_ports -equiv_opt -assert -async2sync -map +/quicklogic/qlf_k6n10f/dspv1_sim.v ql_dsp_simd +select -assert-count 0 t:dsp_t1_20x18x64_cfg_ports_fracturable +equiv_opt -assert -async2sync -map +/quicklogic/qlf_k6n10f/dspv1_sim.v -map +/quicklogic/qlf_k6n10f/dspv1_sim_extra.v ql_dsp_simd design -load postopt select -assert-count 0 t:dsp_t1_10x9x32_cfg_ports -select -assert-count 1 t:dsp_t1_20x18x64_cfg_ports +select -assert-count 1 t:dsp_t1_20x18x64_cfg_ports_fracturable design -reset @@ -54,10 +55,11 @@ chtype -set $mul t:$__soft_mul techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=10 -D DSP_B_MAXWIDTH=9 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_NAME=$__QL_MUL10X9 techmap -map +/quicklogic/qlf_k6n10f/dspv1_map.v -D USE_DSP_CFG_PARAMS=0 read_verilog -lib +/quicklogic/qlf_k6n10f/dspv1_sim.v +read_verilog -lib +/quicklogic/qlf_k6n10f/dspv1_sim_extra.v select -assert-count 2 t:dsp_t1_10x9x32_cfg_ports -select -assert-count 0 t:dsp_t1_20x18x64_cfg_ports -equiv_opt -assert -async2sync -map +/quicklogic/qlf_k6n10f/dspv1_sim.v ql_dsp_simd +select -assert-count 0 t:dsp_t1_20x18x64_cfg_ports_fracturable +equiv_opt -assert -async2sync -map +/quicklogic/qlf_k6n10f/dspv1_sim.v -map +/quicklogic/qlf_k6n10f/dspv1_sim_extra.v ql_dsp_simd design -load postopt select -assert-count 0 t:dsp_t1_10x9x32_cfg_ports -select -assert-count 1 t:dsp_t1_20x18x64_cfg_ports +select -assert-count 1 t:dsp_t1_20x18x64_cfg_ports_fracturable From 0b8243b742487e755c15f72a301630839e8dc86d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 10 Mar 2025 15:56:10 +0100 Subject: [PATCH 19/38] quicklogic: Revert changes to converge development --- techlibs/quicklogic/ql_dsp_macc.cc | 81 ++++++++---------------------- 1 file changed, 20 insertions(+), 61 deletions(-) diff --git a/techlibs/quicklogic/ql_dsp_macc.cc b/techlibs/quicklogic/ql_dsp_macc.cc index de52156ef..be72f3817 100644 --- a/techlibs/quicklogic/ql_dsp_macc.cc +++ b/techlibs/quicklogic/ql_dsp_macc.cc @@ -27,11 +27,9 @@ PRIVATE_NAMESPACE_BEGIN // ============================================================================ -static void create_ql_macc_dsp(ql_dsp_macc_pm &pm, int dsp_version) +static void create_ql_macc_dsp(ql_dsp_macc_pm &pm) { auto &st = pm.st_ql_dsp_macc; - log_assert(dsp_version < 3); - log_assert(dsp_version > 0); // Get port widths size_t a_width = GetSize(st.mul->getPort(ID(A))); @@ -51,58 +49,26 @@ static void create_ql_macc_dsp(ql_dsp_macc_pm &pm, int dsp_version) size_t tgt_b_width; size_t tgt_z_width; - string cell_base_name; + string cell_base_name = "dsp_t1"; string cell_size_name = ""; string cell_cfg_name = ""; string cell_full_name = ""; - if (dsp_version == 1) - cell_base_name = "dsp_t1"; - if (dsp_version == 2) - cell_base_name = "dspv2"; - - std::function set_fractured = nullptr; - auto set_fractured_dspv2 = [](Cell* cell) -> void {cell->setParam(ID(FRAC_MODE), State::S0);}; if (min_width <= 2 && max_width <= 2 && z_width <= 4) { log_debug("\trejected: too narrow (%zd %zd %zd)\n", min_width, max_width, z_width); return; - } - - bool reject = false; - if (dsp_version == 1) { - if (min_width <= 9 && max_width <= 10 && z_width <= 19) { - cell_size_name = "_10x9x32"; - tgt_a_width = 10; - tgt_b_width = 9; - tgt_z_width = 19; - } else if (min_width <= 18 && max_width <= 20 && z_width <= 38) { - cell_size_name = "_20x18x64"; - tgt_a_width = 20; - tgt_b_width = 18; - tgt_z_width = 38; - } else { - reject = true; - } - } else if (dsp_version == 2) { - if (min_width <= 9 && max_width <= 16 && z_width <= 25) { - cell_size_name = "_16x9x32"; - tgt_a_width = 16; - tgt_b_width = 9; - tgt_z_width = 25; - } else if (min_width <= 18 && max_width <= 32 && z_width <= 50) { - cell_size_name = "_32x18x64"; - tgt_a_width = 20; - tgt_b_width = 18; - tgt_z_width = 50; - set_fractured = set_fractured_dspv2; - } else { - reject = true; - } + } else if (min_width <= 9 && max_width <= 10 && z_width <= 19) { + cell_size_name = "_10x9x32"; + tgt_a_width = 10; + tgt_b_width = 9; + tgt_z_width = 19; + } else if (min_width <= 18 && max_width <= 20 && z_width <= 38) { + cell_size_name = "_20x18x64"; + tgt_a_width = 20; + tgt_b_width = 18; + tgt_z_width = 38; } else { - log_assert(false); - } - if (reject) { - log_debug("\trejected: too wide (%zd %zd %zd) for v%d\n", min_width, max_width, z_width, dsp_version); + log_debug("\trejected: too wide (%zd %zd %zd)\n", min_width, max_width, z_width); return; } @@ -110,12 +76,15 @@ static void create_ql_macc_dsp(ql_dsp_macc_pm &pm, int dsp_version) log("Inferring MACC %zux%zu->%zu as %s from:\n", a_width, b_width, z_width, log_id(type)); for (auto cell : {st.mul, st.add, st.mux, st.ff}) - if (cell) - log(" %s (%s)\n", log_id(cell), log_id(cell->type)); + if (cell) + log(" %s (%s)\n", log_id(cell), log_id(cell->type)); // Add the DSP cell RTLIL::Cell *cell = pm.module->addCell(NEW_ID, type); + if (cell->type == ID(dsp_t1_20x18x64_cfg_ports)) + cell->setPort(ID(f_mode_i), State::S0); + // Set attributes cell->set_bool_attribute(ID(is_inferred), true); @@ -135,7 +104,7 @@ static void create_ql_macc_dsp(ql_dsp_macc_pm &pm, int dsp_version) cell->setPort(ID(b_i), sig_b); // Connect output data port, pad if needed - if ((size_t)GetSize(sig_z) < tgt_z_width) { + if ((size_t) GetSize(sig_z) < tgt_z_width) { auto *wire = pm.module->addWire(NEW_ID, tgt_z_width - GetSize(sig_z)); sig_z.append(wire); } @@ -206,10 +175,6 @@ static void create_ql_macc_dsp(ql_dsp_macc_pm &pm, int dsp_version) bool subtract = (st.add->type == ID($sub)); cell->setPort(ID(subtract_i), RTLIL::SigSpec(subtract ? RTLIL::S1 : RTLIL::S0)); - // Disable fractured mode - if (set_fractured) - set_fractured(cell); - // Mark the cells for removal pm.autoremove(st.mul); pm.autoremove(st.add); @@ -235,22 +200,16 @@ struct QlDspMacc : public Pass { void execute(std::vector a_Args, RTLIL::Design *a_Design) override { - int dsp_version = 1; log_header(a_Design, "Executing QL_DSP_MACC pass.\n"); size_t argidx; for (argidx = 1; argidx < a_Args.size(); argidx++) { - if (a_Args[argidx] == "-dspv2") { - dsp_version = 2; - continue; - } break; } extra_args(a_Args, argidx, a_Design); - auto l = [dsp_version](ql_dsp_macc_pm &pm) { create_ql_macc_dsp(pm, dsp_version); }; for (auto module : a_Design->selected_modules()) - ql_dsp_macc_pm(module, module->selected_cells()).run_ql_dsp_macc(l); + ql_dsp_macc_pm(module, module->selected_cells()).run_ql_dsp_macc(create_ql_macc_dsp); } } QlDspMacc; From 6a3d1cc97608258e2c28c4cae6f3a8dbc7d9678b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 5 Mar 2025 14:22:29 +0100 Subject: [PATCH 20/38] ql_dsp_macc: Avoid ID() macro for common IDs --- techlibs/quicklogic/ql_dsp_macc.cc | 40 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/techlibs/quicklogic/ql_dsp_macc.cc b/techlibs/quicklogic/ql_dsp_macc.cc index be72f3817..e134f1c19 100644 --- a/techlibs/quicklogic/ql_dsp_macc.cc +++ b/techlibs/quicklogic/ql_dsp_macc.cc @@ -32,16 +32,16 @@ static void create_ql_macc_dsp(ql_dsp_macc_pm &pm) auto &st = pm.st_ql_dsp_macc; // Get port widths - size_t a_width = GetSize(st.mul->getPort(ID(A))); - size_t b_width = GetSize(st.mul->getPort(ID(B))); - size_t z_width = GetSize(st.ff->getPort(ID(Q))); + size_t a_width = GetSize(st.mul->getPort(ID::A)); + size_t b_width = GetSize(st.mul->getPort(ID::B)); + size_t z_width = GetSize(st.ff->getPort(ID::Q)); size_t min_width = std::min(a_width, b_width); size_t max_width = std::max(a_width, b_width); // Signed / unsigned - bool ab_signed = st.mul->getParam(ID(A_SIGNED)).as_bool(); - log_assert(ab_signed == st.mul->getParam(ID(B_SIGNED)).as_bool()); + bool ab_signed = st.mul->getParam(ID::A_SIGNED).as_bool(); + log_assert(ab_signed == st.mul->getParam(ID::B_SIGNED).as_bool()); // Determine DSP type or discard if too narrow / wide RTLIL::IdString type; @@ -90,9 +90,9 @@ static void create_ql_macc_dsp(ql_dsp_macc_pm &pm) // Get input/output data signals RTLIL::SigSpec sig_a, sig_b, sig_z; - sig_a = st.mul->getPort(ID(A)); - sig_b = st.mul->getPort(ID(B)); - sig_z = st.output_registered ? st.ff->getPort(ID(Q)) : st.ff->getPort(ID(D)); + sig_a = st.mul->getPort(ID::A); + sig_b = st.mul->getPort(ID::B); + sig_z = st.output_registered ? st.ff->getPort(ID::Q) : st.ff->getPort(ID::D); if (a_width < b_width) std::swap(sig_a, sig_b); @@ -111,26 +111,26 @@ static void create_ql_macc_dsp(ql_dsp_macc_pm &pm) cell->setPort(ID(z_o), sig_z); // Connect clock, reset and enable - cell->setPort(ID(clock_i), st.ff->getPort(ID(CLK))); + cell->setPort(ID(clock_i), st.ff->getPort(ID::CLK)); RTLIL::SigSpec rst; RTLIL::SigSpec ena; - if (st.ff->hasPort(ID(ARST))) { - if (st.ff->getParam(ID(ARST_POLARITY)).as_int() != 1) { - rst = pm.module->Not(NEW_ID, st.ff->getPort(ID(ARST))); + if (st.ff->hasPort(ID::ARST)) { + if (st.ff->getParam(ID::ARST_POLARITY).as_int() != 1) { + rst = pm.module->Not(NEW_ID, st.ff->getPort(ID::ARST)); } else { - rst = st.ff->getPort(ID(ARST)); + rst = st.ff->getPort(ID::ARST); } } else { rst = RTLIL::SigSpec(RTLIL::S0); } - if (st.ff->hasPort(ID(EN))) { - if (st.ff->getParam(ID(EN_POLARITY)).as_int() != 1) { - ena = pm.module->Not(NEW_ID, st.ff->getPort(ID(EN))); + if (st.ff->hasPort(ID::EN)) { + if (st.ff->getParam(ID::EN_POLARITY).as_int() != 1) { + ena = pm.module->Not(NEW_ID, st.ff->getPort(ID::EN)); } else { - ena = st.ff->getPort(ID(EN)); + ena = st.ff->getPort(ID::EN); } } else { ena = RTLIL::SigSpec(RTLIL::S1); @@ -141,11 +141,11 @@ static void create_ql_macc_dsp(ql_dsp_macc_pm &pm) // Insert feedback_i control logic used for clearing / loading the accumulator if (st.mux_in_pattern) { - RTLIL::SigSpec sig_s = st.mux->getPort(ID(S)); + RTLIL::SigSpec sig_s = st.mux->getPort(ID::S); // Depending on the mux port ordering insert inverter if needed - log_assert(st.mux_ab.in(ID(A), ID(B))); - if (st.mux_ab == ID(A)) + log_assert(st.mux_ab.in(ID::A, ID::B)); + if (st.mux_ab == ID::A) sig_s = pm.module->Not(NEW_ID, sig_s); // Assemble the full control signal for the feedback_i port From c439f8c7701bf904ad694d8b8a851cf810e275ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 10 Mar 2025 16:25:02 +0100 Subject: [PATCH 21/38] quicklogic: Fix cascading --- techlibs/quicklogic/ql_dsp.pmg | 1 + 1 file changed, 1 insertion(+) diff --git a/techlibs/quicklogic/ql_dsp.pmg b/techlibs/quicklogic/ql_dsp.pmg index e7c253bf5..a7e772f62 100644 --- a/techlibs/quicklogic/ql_dsp.pmg +++ b/techlibs/quicklogic/ql_dsp.pmg @@ -260,6 +260,7 @@ code dsp2->setParam(\ROUND, Const(0, 3)); dsp2->setParam(\SHIFT_REG, Const(0, 6)); dsp2->setParam(\SATURATE, Const(0, 1)); + dsp2->setParam(\ZCIN_REG, Const(1, 1)); dsp2->setPort(\z_o, {port(dsp2, \z_o).extract_end(port(add, \Y).size()), port(add, \Y)}); module->remove(add); From 947ca842f96a163446852cb64a270c7c72070deb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 10 Mar 2025 16:28:16 +0100 Subject: [PATCH 22/38] ql_dsp: Add promotion on cascading --- techlibs/quicklogic/ql_dsp.cc | 44 ++++++++++++++++++++++++++++++++++ techlibs/quicklogic/ql_dsp.pmg | 10 +++++--- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/techlibs/quicklogic/ql_dsp.cc b/techlibs/quicklogic/ql_dsp.cc index aa8ed6631..e84bd8905 100644 --- a/techlibs/quicklogic/ql_dsp.cc +++ b/techlibs/quicklogic/ql_dsp.cc @@ -22,6 +22,50 @@ PRIVATE_NAMESPACE_BEGIN USING_YOSYS_NAMESPACE +// promote dspv2_16x9x32_cfg_ports to dspv2_32x18x64_cfg_ports if need be +bool promote(Module *m, Cell *cell) { + if (cell->type == ID(dspv2_32x18x64_cfg_ports)) { + return false; + } else { + log_assert(cell->type == ID(dspv2_16x9x32_cfg_ports)); + } + + auto widen_output = [&](IdString port_name, int new_width) { + if (!cell->hasPort(port_name)) + return; + SigSpec port = cell->getPort(port_name); + if (port.size() < new_width) { + port = {m->addWire(NEW_ID, new_width - port.size()), port}; + cell->setPort(port_name, port); + } + }; + + auto widen_input = [&](IdString port_name, int new_width) { + if (!cell->hasPort(port_name)) + return; + SigSpec port = cell->getPort(port_name); + if (port.size() < new_width) { + port.extend_u0(new_width, /* is_signed= */ true); + cell->setPort(port_name, port); + } + }; + + widen_output(ID(z_o), 50); + widen_output(ID(a_cout_o), 32); + widen_output(ID(b_cout_o), 18); + widen_output(ID(z_cout_o), 50); + + if (cell->hasPort(ID(a_cin_i)) || cell->hasPort(ID(b_cin_i)) || cell->hasPort(ID(z_cin_i))) { + log_error("Cannot promote %s (type %s) with cascading paths\n", log_id(cell), log_id(cell->type)); + } + + widen_input(ID(a_i), 32); + widen_input(ID(b_i), 18); + widen_input(ID(c_i), 18); + cell->type = ID(dspv2_32x18x64_cfg_ports); + return true; +} + #include "ql_dsp_pm.h" struct QlDspPass : Pass { diff --git a/techlibs/quicklogic/ql_dsp.pmg b/techlibs/quicklogic/ql_dsp.pmg index a7e772f62..44c2377d0 100644 --- a/techlibs/quicklogic/ql_dsp.pmg +++ b/techlibs/quicklogic/ql_dsp.pmg @@ -11,7 +11,7 @@ udata dffclock dffreset udata dff match dsp - select dsp->type == \dspv2_32x18x64_cfg_ports + select dsp->type.in(\dspv2_32x18x64_cfg_ports, \dspv2_16x9x32_cfg_ports) endmatch code clock_inferred clock reset @@ -209,12 +209,12 @@ endcode pattern ql_dsp_cascade match dsp1 - select dsp1->type == \dspv2_32x18x64_cfg_ports + select dsp1->type.in(\dspv2_32x18x64_cfg_ports, \dspv2_16x9x32_cfg_ports) filter !dsp1->hasPort(\z_cout_o) || nusers(port(dsp1, \z_cout_o)) == 1 endmatch match dsp2 - select dsp2->type == \dspv2_32x18x64_cfg_ports + select dsp2->type.in(\dspv2_32x18x64_cfg_ports, \dspv2_16x9x32_cfg_ports) filter port(dsp2, \output_select_i).is_fully_const() define output_sel port(dsp2, \output_select_i).as_int() filter output_sel == 3 || (output_sel == 4 && !param(dsp2, \M_REG).as_bool()) @@ -243,6 +243,10 @@ code const int z_width = 50; log("%s: inferring post-adder from %s (type %s)\n", log_id(dsp2), log_id(add), log_id(add->type)); + if (promote(module, dsp1)) + log(" - promoting %s to non-fractured DSP block\n", log_id(dsp1)); + if (promote(module, dsp2)) + log(" - promoting %s to non-fractured DSP block\n", log_id(dsp2)); // link up z_cout_o of dsp1 to z_cin_i of dsp2 Wire *link = module->addWire(NEW_ID, z_width); From 0615209562cccc0c31312afcff9f966e1699a7e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 10 Mar 2025 16:28:33 +0100 Subject: [PATCH 23/38] ql_dsp_macc: Support v2 DSP --- techlibs/quicklogic/ql_dsp_macc.cc | 176 +++++++++++++++++++++++++++-- 1 file changed, 166 insertions(+), 10 deletions(-) diff --git a/techlibs/quicklogic/ql_dsp_macc.cc b/techlibs/quicklogic/ql_dsp_macc.cc index e134f1c19..b4e17f04b 100644 --- a/techlibs/quicklogic/ql_dsp_macc.cc +++ b/techlibs/quicklogic/ql_dsp_macc.cc @@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN // ============================================================================ -static void create_ql_macc_dsp(ql_dsp_macc_pm &pm) +static void create_ql_macc_dsp_v1(ql_dsp_macc_pm &pm) { auto &st = pm.st_ql_dsp_macc; @@ -82,9 +82,6 @@ static void create_ql_macc_dsp(ql_dsp_macc_pm &pm) // Add the DSP cell RTLIL::Cell *cell = pm.module->addCell(NEW_ID, type); - if (cell->type == ID(dsp_t1_20x18x64_cfg_ports)) - cell->setPort(ID(f_mode_i), State::S0); - // Set attributes cell->set_bool_attribute(ID(is_inferred), true); @@ -184,6 +181,151 @@ static void create_ql_macc_dsp(ql_dsp_macc_pm &pm) pm.autoremove(st.ff); } +void create_ql_macc_dsp_v2(ql_dsp_macc_pm &pm) +{ + auto &st = pm.st_ql_dsp_macc; + + SigSpec sig_a = st.mul->getPort(ID::A); + SigSpec sig_b = st.mul->getPort(ID::B); + + if (sig_a.size() < sig_b.size()) + std::swap(sig_a, sig_b); + + // Signed / unsigned + bool ab_signed = st.mul->getParam(ID::A_SIGNED).as_bool(); + log_assert(ab_signed == st.mul->getParam(ID::B_SIGNED).as_bool()); + + int z_width = GetSize(st.ff->getPort(ID::Q)); + if (!ab_signed) { + if (sig_a.msb() != RTLIL::S0 && sig_a.size() < z_width) + sig_a.append(RTLIL::S0); + if (sig_b.msb() != RTLIL::S0 && sig_b.size() < z_width) + sig_b.append(RTLIL::S0); + } + int a_width = GetSize(sig_a); + int b_width = GetSize(sig_b); + + // Determine DSP type or discard if too narrow / wide + RTLIL::IdString type; + size_t tgt_a_width; + size_t tgt_b_width; + size_t tgt_z_width; + + string cell_base_name = "dspv2"; + string cell_size_name = ""; + string cell_cfg_name = ""; + string cell_full_name = ""; + + if (a_width <= 2 && b_width <= 2 && z_width <= 4) { + log_debug("\trejected: too narrow (%d %d %d)\n", a_width, b_width, z_width); + return; + } else if (a_width <= 16 && b_width <= 9 && z_width <= 25) { + cell_size_name = "_16x9x32"; + tgt_a_width = 16; + tgt_b_width = 9; + tgt_z_width = 25; // TODO + } else if (a_width <= 32 && b_width <= 18 && z_width <= 50) { + cell_size_name = "_32x18x64"; + tgt_a_width = 32; + tgt_b_width = 18; + tgt_z_width = 50; + } else { + log_debug("\trejected: too wide (%d %d %d)\n", a_width, b_width, z_width); + return; + } + + type = RTLIL::escape_id(cell_base_name + cell_size_name + "_cfg_ports"); + log("Inferring MACC %dx%d->%d as %s from:\n", a_width, b_width, z_width, log_id(type)); + + for (auto cell : {st.mul, st.add, st.mux, st.ff}) + if (cell) + log(" %s (%s)\n", log_id(cell), log_id(cell->type)); + + // Add the DSP cell + RTLIL::Cell *cell = pm.module->addCell(NEW_ID, type); + + // Set attributes + cell->set_bool_attribute(ID(is_inferred), true); + + // Get input/output data signals + SigSpec sig_z; + sig_z = st.output_registered ? st.ff->getPort(ID::Q) : st.ff->getPort(ID::D); + + // Connect input data ports, sign extend / pad with zeros + sig_a.extend_u0(tgt_a_width, true); + sig_b.extend_u0(tgt_b_width, true); + cell->setPort(ID(a_i), sig_a); + cell->setPort(ID(b_i), sig_b); + cell->setPort(ID(c_i), SigSpec(RTLIL::S0, tgt_b_width)); + + // Connect output data port, pad if needed + if ((size_t) GetSize(sig_z) < tgt_z_width) { + auto *wire = pm.module->addWire(NEW_ID, tgt_z_width - GetSize(sig_z)); + sig_z.append(wire); + } + cell->setPort(ID(z_o), sig_z); + + // Connect clock, reset and enable + cell->setPort(ID(clock_i), st.ff->getPort(ID::CLK)); + + RTLIL::SigSpec rst; + RTLIL::SigSpec ena; + + if (st.ff->hasPort(ID::ARST)) { + if (st.ff->getParam(ID::ARST_POLARITY).as_int() != 1) { + rst = pm.module->Not(NEW_ID, st.ff->getPort(ID::ARST)); + } else { + rst = st.ff->getPort(ID::ARST); + } + } else { + rst = RTLIL::SigSpec(RTLIL::S0); + } + + if (st.ff->hasPort(ID::EN)) { + if (st.ff->getParam(ID::EN_POLARITY).as_int() != 1) { + ena = pm.module->Not(NEW_ID, st.ff->getPort(ID::EN)); + } else { + ena = st.ff->getPort(ID::EN); + } + } else { + ena = RTLIL::SigSpec(RTLIL::S1); + } + + cell->setPort(ID(reset_i), rst); + cell->setPort(ID(load_acc_i), ena); + + // Insert feedback_i control logic used for clearing / loading the accumulator + if (st.mux_in_pattern) { + RTLIL::SigSpec sig_s = st.mux->getPort(ID::S); + + // Depending on the mux port ordering insert inverter if needed + log_assert(st.mux_ab.in(ID::A, ID::B)); + if (st.mux_ab == ID::A) + sig_s = pm.module->Not(NEW_ID, sig_s); + + cell->setPort(ID(feedback_i), {RTLIL::S0, RTLIL::S0, sig_s}); + } + // No acc clear/load + else { + cell->setPort(ID(feedback_i), RTLIL::SigSpec(RTLIL::S0, 3)); + } + + cell->setPort(ID(acc_reset_i), RTLIL::SigSpec(RTLIL::S0)); + // 3 - output post acc; 1 - output pre acc + cell->setPort(ID(output_select_i), RTLIL::Const(st.output_registered ? 1 : 3, 3)); + + bool subtract = (st.add->type == ID($sub)); + cell->setParam(ID(SUBTRACT), RTLIL::Const(subtract ? RTLIL::S1 : RTLIL::S0)); + + // Mark the cells for removal + pm.autoremove(st.mul); + pm.autoremove(st.add); + if (st.mux != nullptr) { + pm.autoremove(st.mux); + } + pm.autoremove(st.ff); +} + struct QlDspMacc : public Pass { QlDspMacc() : Pass("ql_dsp_macc", "infer QuickLogic multiplier-accumulator DSP cells") {} @@ -196,20 +338,34 @@ struct QlDspMacc : public Pass { log("This pass looks for a multiply-accumulate pattern based on which it infers a\n"); log("QuickLogic DSP cell.\n"); log("\n"); + log(" -dspv2\n"); + log(" target DSPv2.\n"); + log("\n"); } - void execute(std::vector a_Args, RTLIL::Design *a_Design) override + void execute(std::vector args, RTLIL::Design *design) override { - log_header(a_Design, "Executing QL_DSP_MACC pass.\n"); + log_header(design, "Executing QL_DSP_MACC pass.\n"); + bool target_dspv2 = false; size_t argidx; - for (argidx = 1; argidx < a_Args.size(); argidx++) { + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-dspv2") { + target_dspv2 = true; + continue; + } break; } - extra_args(a_Args, argidx, a_Design); + extra_args(args, argidx, design); - for (auto module : a_Design->selected_modules()) - ql_dsp_macc_pm(module, module->selected_cells()).run_ql_dsp_macc(create_ql_macc_dsp); + for (auto module : design->selected_modules()) { + ql_dsp_macc_pm pm(module, module->selected_cells()); + + if (target_dspv2) + pm.run_ql_dsp_macc(create_ql_macc_dsp_v2); + else + pm.run_ql_dsp_macc(create_ql_macc_dsp_v1); + } } } QlDspMacc; From fde681623c6582bc56860af16212d1b14dd9c021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 11 Mar 2025 10:33:00 +0100 Subject: [PATCH 24/38] ql_dsp: Improve cascading detection --- techlibs/quicklogic/ql_dsp.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/techlibs/quicklogic/ql_dsp.cc b/techlibs/quicklogic/ql_dsp.cc index e84bd8905..8b53dffcb 100644 --- a/techlibs/quicklogic/ql_dsp.cc +++ b/techlibs/quicklogic/ql_dsp.cc @@ -55,7 +55,11 @@ bool promote(Module *m, Cell *cell) { widen_output(ID(b_cout_o), 18); widen_output(ID(z_cout_o), 50); - if (cell->hasPort(ID(a_cin_i)) || cell->hasPort(ID(b_cin_i)) || cell->hasPort(ID(z_cin_i))) { + auto uses_port = [&](IdString port_name) { + return cell->hasPort(port_name) && !cell->getPort(port_name).is_fully_undef(); + }; + + if (uses_port(ID(a_cin_i)) || uses_port(ID(b_cin_i)) || uses_port(ID(z_cin_i))) { log_error("Cannot promote %s (type %s) with cascading paths\n", log_id(cell), log_id(cell->type)); } From f157a868a329789dc0a017670309912ff48c2360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 11 Mar 2025 10:34:09 +0100 Subject: [PATCH 25/38] ql_dsp: Add outer loop --- techlibs/quicklogic/ql_dsp.cc | 29 ++++++++++++++++++----------- techlibs/quicklogic/ql_dsp.pmg | 12 +++++++----- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/techlibs/quicklogic/ql_dsp.cc b/techlibs/quicklogic/ql_dsp.cc index 8b53dffcb..760e76cf8 100644 --- a/techlibs/quicklogic/ql_dsp.cc +++ b/techlibs/quicklogic/ql_dsp.cc @@ -70,6 +70,8 @@ bool promote(Module *m, Cell *cell) { return true; } +bool did_something; + #include "ql_dsp_pm.h" struct QlDspPass : Pass { @@ -85,19 +87,24 @@ struct QlDspPass : Pass { extra_args(args, argidx, d); for (auto module : d->selected_modules()) { - { - ql_dsp_pm pm(module, module->selected_cells()); - pm.run_ql_dsp_pack_regs(); - } + did_something = true; + while (did_something) { - ql_dsp_pm pm(module, module->selected_cells()); - pm.run_ql_dsp_cascade(); - } - - { - ql_dsp_pm pm(module, module->selected_cells()); - pm.run_ql_dsp_pack_regs(); + // TODO: could be optimized by more reuse of the pmgen object + did_something = false; + { + ql_dsp_pm pm(module, module->selected_cells()); + pm.run_ql_dsp_pack_regs(); + } + { + ql_dsp_pm pm(module, module->selected_cells()); + pm.run_ql_dsp_cascade(); + } + { + ql_dsp_pm pm(module, module->selected_cells()); + pm.run_ql_dsp_pack_regs(); + } } } } diff --git a/techlibs/quicklogic/ql_dsp.pmg b/techlibs/quicklogic/ql_dsp.pmg index 44c2377d0..1dc1907b7 100644 --- a/techlibs/quicklogic/ql_dsp.pmg +++ b/techlibs/quicklogic/ql_dsp.pmg @@ -34,6 +34,7 @@ code argD clock_inferred clock reset log("%s: inferring Z path register from flip-flop %s\n", log_id(dsp), log_id(dff)); dsp->connections_[\output_select_i][2] = RTLIL::S1; dsp->setPort(\z_o, dffQ); + did_something = true; } } endcode @@ -52,6 +53,7 @@ code argQ clock_inferred clock reset log("%s: inferring B path register from flip-flop %s\n", log_id(dsp), log_id(dff)); dsp->parameters[\B_REG] = true; dsp->setPort(\b_i, dffD); + did_something = true; } } endcode @@ -70,6 +72,7 @@ code argQ clock_inferred clock reset log("%s: inferring A path register from flip-flop %s\n", log_id(dsp), log_id(dff)); dsp->parameters[\A_REG] = true; dsp->setPort(\a_i, dffD); + did_something = true; } } endcode @@ -236,9 +239,6 @@ match add filter port(add, \B).extract(0, width) == port(dsp2, \z_o).extract(0, width) endmatch -code -endcode - code const int z_width = 50; @@ -265,7 +265,9 @@ code dsp2->setParam(\SHIFT_REG, Const(0, 6)); dsp2->setParam(\SATURATE, Const(0, 1)); dsp2->setParam(\ZCIN_REG, Const(1, 1)); - dsp2->setPort(\z_o, {port(dsp2, \z_o).extract_end(port(add, \Y).size()), port(add, \Y)}); - module->remove(add); + + did_something = true; + autoremove(add); + accept; endcode From b230c00551ee77c82cf35658b1a6c1fb242347ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 11 Mar 2025 10:34:28 +0100 Subject: [PATCH 26/38] ql_dsp: Fix precondition for cascading --- techlibs/quicklogic/ql_dsp.pmg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/quicklogic/ql_dsp.pmg b/techlibs/quicklogic/ql_dsp.pmg index 1dc1907b7..5014f24e2 100644 --- a/techlibs/quicklogic/ql_dsp.pmg +++ b/techlibs/quicklogic/ql_dsp.pmg @@ -220,7 +220,7 @@ match dsp2 select dsp2->type.in(\dspv2_32x18x64_cfg_ports, \dspv2_16x9x32_cfg_ports) filter port(dsp2, \output_select_i).is_fully_const() define output_sel port(dsp2, \output_select_i).as_int() - filter output_sel == 3 || (output_sel == 4 && !param(dsp2, \M_REG).as_bool()) + filter output_sel == 0 || (output_sel == 4 && !param(dsp2, \M_REG).as_bool()) // expect `dsp2` and `add` for exclusive users filter nusers(port(dsp2, \z_o)) == 2 filter !dsp2->hasPort(\z_cout_o) || nusers(port(dsp2, \z_cout_o)) == 1 From 7f833f4c3736b074f4cfd1639f7e3a6e4dd89ad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 11 Mar 2025 16:26:54 +0100 Subject: [PATCH 27/38] ql_dsp: Add help --- techlibs/quicklogic/ql_dsp.cc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/techlibs/quicklogic/ql_dsp.cc b/techlibs/quicklogic/ql_dsp.cc index 760e76cf8..3e19b6c9d 100644 --- a/techlibs/quicklogic/ql_dsp.cc +++ b/techlibs/quicklogic/ql_dsp.cc @@ -76,6 +76,19 @@ bool did_something; struct QlDspPass : Pass { QlDspPass() : Pass("ql_dsp", "pack into QuickLogic DSPs") {} + + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" ql_dsp [selection]\n"); + log("\n"); + log("This pass packs input and output path registers into QuickLogic DSP blocks,\n"); + log("additionally it supports Z path cascading and post-adder packing.\n"); + log("\n"); + + } + void execute(std::vector args, RTLIL::Design *d) override { log_header(d, "Executing QL_DSP pass. (pack into QuickLogic DSPs)\n"); From 26dc68086fca4097f0d0a68ea0be72be8bd0ffe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 11 Mar 2025 16:27:57 +0100 Subject: [PATCH 28/38] ql_dsp: Relax packing condition --- techlibs/quicklogic/ql_dsp.pmg | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/techlibs/quicklogic/ql_dsp.pmg b/techlibs/quicklogic/ql_dsp.pmg index 5014f24e2..f331f9038 100644 --- a/techlibs/quicklogic/ql_dsp.pmg +++ b/techlibs/quicklogic/ql_dsp.pmg @@ -42,8 +42,7 @@ endcode // try packing on B input code argQ clock_inferred clock reset if ((!dsp->hasPort(\b_cout_o) || nusers(port(dsp, \b_cout_o)) == 1) && - !param(dsp, \B_REG).as_bool() && - nusers(port(dsp, \b_i)) == 2) { + !param(dsp, \B_REG).as_bool()) { argQ = port(dsp, \b_i); subpattern(in_dffe); if (dff) { @@ -61,8 +60,7 @@ endcode // try packing on A input code argQ clock_inferred clock reset if ((!dsp->hasPort(\a_cout_o) || nusers(port(dsp, \a_cout_o)) == 1) && - !param(dsp, \A_REG).as_bool() && - nusers(port(dsp, \a_i)) == 2) { + !param(dsp, \A_REG).as_bool()) { argQ = port(dsp, \a_i); subpattern(in_dffe); if (dff) { From 0180e8f30f4ec3dc7f40de598f7b00a792757667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 11 Mar 2025 16:29:01 +0100 Subject: [PATCH 29/38] ql_dsp: Fix parameter widths, forbid self-cascading --- techlibs/quicklogic/ql_dsp.pmg | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/techlibs/quicklogic/ql_dsp.pmg b/techlibs/quicklogic/ql_dsp.pmg index f331f9038..e5c712957 100644 --- a/techlibs/quicklogic/ql_dsp.pmg +++ b/techlibs/quicklogic/ql_dsp.pmg @@ -50,7 +50,7 @@ code argQ clock_inferred clock reset clock = dffclock; reset = dffreset; log("%s: inferring B path register from flip-flop %s\n", log_id(dsp), log_id(dff)); - dsp->parameters[\B_REG] = true; + dsp->parameters[\B_REG] = Const(1, 1); dsp->setPort(\b_i, dffD); did_something = true; } @@ -68,7 +68,7 @@ code argQ clock_inferred clock reset clock = dffclock; reset = dffreset; log("%s: inferring A path register from flip-flop %s\n", log_id(dsp), log_id(dff)); - dsp->parameters[\A_REG] = true; + dsp->parameters[\A_REG] = Const(1, 1); dsp->setPort(\a_i, dffD); did_something = true; } @@ -222,6 +222,7 @@ match dsp2 // expect `dsp2` and `add` for exclusive users filter nusers(port(dsp2, \z_o)) == 2 filter !dsp2->hasPort(\z_cout_o) || nusers(port(dsp2, \z_cout_o)) == 1 + filter dsp1 != dsp2 endmatch match add From 0d484818a7ef3dad0621a97bfbfad19c4fe6becc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 11 Mar 2025 16:35:38 +0100 Subject: [PATCH 30/38] ql_dsp_io_regs: Add DSPv2 support, adjust sim model Add support for cell type dispatching of the new DSP block; adjust the definition of MULT and MULTACC variants to support those instances starting a cascading chain. --- techlibs/quicklogic/ql_dsp_io_regs.cc | 154 ++++++++++++++++++++- techlibs/quicklogic/qlf_k6n10f/dspv2_sim.v | 48 ++++--- 2 files changed, 185 insertions(+), 17 deletions(-) diff --git a/techlibs/quicklogic/ql_dsp_io_regs.cc b/techlibs/quicklogic/ql_dsp_io_regs.cc index d99623dcc..922feadd0 100644 --- a/techlibs/quicklogic/ql_dsp_io_regs.cc +++ b/techlibs/quicklogic/ql_dsp_io_regs.cc @@ -44,20 +44,32 @@ struct QlDspIORegs : public Pass { log("\n"); log("This pass looks for QL_DSP2 cells and changes their cell type depending on their\n"); log("configuration.\n"); + log("\n"); + log(" -dspv2\n"); + log(" target DSPv2.\n"); + log("\n"); } void execute(std::vector a_Args, RTLIL::Design *a_Design) override { log_header(a_Design, "Executing QL_DSP_IO_REGS pass.\n"); + bool target_dspv2 = false; size_t argidx; for (argidx = 1; argidx < a_Args.size(); argidx++) { + if (a_Args[argidx] == "-dspv2") { + target_dspv2 = true; + continue; + } break; } extra_args(a_Args, argidx, a_Design); for (auto module : a_Design->selected_modules()) { - ql_dsp_io_regs_pass(module); + if (target_dspv2) + ql_dsp_io_regs_pass_v2(module); + else + ql_dsp_io_regs_pass(module); } } @@ -153,6 +165,146 @@ struct QlDspIORegs : public Pass { } } } + + + void ql_dsp_io_regs_pass_v2(Module *module) + { + sigmap.set(module); + + for (auto cell : module->cells()) { + if (cell->type != ID(QL_DSPV2)) + continue; + + // If the cell does not have the "is_inferred" attribute set + // then don't touch it. + if (!cell->get_bool_attribute(ID(is_inferred))) + continue; + + if (!cell->hasPort(ID(output_select)) || + !sigmap(cell->getPort(ID(output_select))).is_fully_def() || + !cell->hasParam(ID(MODE_BITS)) || + cell->getParam(ID(MODE_BITS)).size() != 72) { + log_error("Missing configuration tie-offs or parameters on DSP cell %s\n", + log_id(cell)); + } + int out_sel_i = sigmap(cell->getPort(ID(output_select))).as_int(); + Const mode = cell->getParam(ID(MODE_BITS)); + + // Get the feedback port + if (!cell->hasPort(ID(feedback))) + log_error("Missing 'feedback' port on %s", log_id(cell)); + SigSpec feedback = sigmap(cell->getPort(ID(feedback))); + + bool a_reg = mode[61] != RTLIL::S0; + bool b_reg = mode[63] != RTLIL::S0; + + // Build new type name + std::string new_type = "\\QL_DSPV2_MULT"; + + // Decide if we should be deleting the clock port + bool del_clk = true; + + if (a_reg != b_reg) { + // no specialized type for mixed scenario + continue; + } + + enum { + MULT, + MULTADD, + MULTACC, + Unrecognized + } base_function = Unrecognized; + + switch (out_sel_i) { + case 0: + case 4: + base_function = MULT; + break; + case 1: + case 5: + case 2: + case 3: + case 6: + case 7: + if (feedback.is_fully_def() && (feedback.as_int() == 2 || feedback.as_int() == 3)) { + del_clk = false; + new_type += "ADD"; + base_function = MULTADD; + break; + } else if (feedback.extract(1, 2).is_fully_zero()) { + del_clk = false; + new_type += "ACC"; + base_function = MULTACC; + break; + } else { + base_function = Unrecognized; + } + break; + default: + break; + } + + if (base_function == Unrecognized) { + continue; + } + + if (a_reg && b_reg) { + del_clk = false; + new_type += "_REGIN"; + } + + if (out_sel_i > 3) { + del_clk = false; + new_type += "_REGOUT"; + } + + // Set new type name + log_debug("Converted %s to %s\n", log_id(cell->type), new_type.c_str()); + cell->type = RTLIL::IdString(new_type); + + std::vector ports2del; + + if (del_clk) { + cell->unsetPort(ID(clk)); + cell->unsetPort(ID(reset)); + } + + switch (base_function) { + case MULTACC: { + static const std::vector to_del = { + ID(c), ID(a_cin), ID(b_cin), ID(z_cin), + ID(a_cout), ID(b_cout) + }; + + for (auto port : to_del) + cell->unsetPort(port); + break; + } + case MULTADD: { + static const std::vector to_del = { + ID(c), ID(a_cin), ID(b_cin), ID(a_cout), ID(b_cout) + }; + + for (auto port : to_del) + cell->unsetPort(port); + break; + } + case MULT: { + static const std::vector to_del = { + ID(c), ID(load_acc), ID(acc_reset), + ID(a_cin), ID(b_cin), ID(z_cin), ID(a_cout), ID(b_cout) + }; + + for (auto port : to_del) + cell->unsetPort(port); + break; + } + default: + ; + } + } + } } QlDspIORegs; PRIVATE_NAMESPACE_END diff --git a/techlibs/quicklogic/qlf_k6n10f/dspv2_sim.v b/techlibs/quicklogic/qlf_k6n10f/dspv2_sim.v index c879e5c32..fd85c70ff 100644 --- a/techlibs/quicklogic/qlf_k6n10f/dspv2_sim.v +++ b/techlibs/quicklogic/qlf_k6n10f/dspv2_sim.v @@ -214,7 +214,9 @@ module QL_DSPV2_MULT ( output wire [49:0] z, input wire [2:0] feedback, - input wire [2:0] output_select + input wire [2:0] output_select, + + output wire [49:0] z_cout ); parameter [71:0] MODE_BITS = 72'h000000000000000000; @@ -257,7 +259,7 @@ module QL_DSPV2_MULT ( .b_cin(), .z_cin(), - .z_cout(), + .z_cout(z_cout), .a_cout(), .b_cout() ); @@ -274,7 +276,9 @@ module QL_DSPV2_MULT_REGIN ( input wire reset, input wire [2:0] feedback, - input wire [2:0] output_select + input wire [2:0] output_select, + + output wire [49:0] z_cout ); parameter [71:0] MODE_BITS = 72'h00A000000000000000; @@ -317,7 +321,7 @@ module QL_DSPV2_MULT_REGIN ( .b_cin(), .z_cin(), - .z_cout(), + .z_cout(z_cout), .a_cout(), .b_cout() ); @@ -334,7 +338,9 @@ module QL_DSPV2_MULT_REGOUT ( input wire reset, input wire [2:0] feedback, - input wire [2:0] output_select + input wire [2:0] output_select, + + output wire [49:0] z_cout ); parameter [71:0] MODE_BITS = 72'h000000000000000000; @@ -377,7 +383,7 @@ module QL_DSPV2_MULT_REGOUT ( .b_cin(), .z_cin(), - .z_cout(), + .z_cout(z_cout), .a_cout(), .b_cout() ); @@ -394,7 +400,9 @@ module QL_DSPV2_MULT_REGIN_REGOUT ( input wire reset, input wire [2:0] feedback, - input wire [2:0] output_select + input wire [2:0] output_select, + + output wire [49:0] z_cout ); parameter [71:0] MODE_BITS = 72'h00A000000000000000; @@ -437,7 +445,7 @@ module QL_DSPV2_MULT_REGIN_REGOUT ( .b_cin(), .z_cin(), - .z_cout(), + .z_cout(z_cout), .a_cout(), .b_cout() ); @@ -715,7 +723,9 @@ module QL_DSPV2_MULTACC ( input wire acc_reset, input wire load_acc, input wire [ 2:0] feedback, - input wire [ 2:0] output_select + input wire [ 2:0] output_select, + + output wire [49:0] z_cout ); parameter [71:0] MODE_BITS = 72'h000000000000000000; @@ -758,7 +768,7 @@ module QL_DSPV2_MULTACC ( .b_cin(), .z_cin(), - .z_cout(), + .z_cout(z_cout), .a_cout(), .b_cout() ); @@ -776,7 +786,9 @@ module QL_DSPV2_MULTACC_REGIN ( input wire acc_reset, input wire load_acc, input wire [ 2:0] feedback, - input wire [ 2:0] output_select + input wire [ 2:0] output_select, + + output wire [49:0] z_cout ); parameter [71:0] MODE_BITS = 72'h004000000000000000; @@ -819,7 +831,7 @@ module QL_DSPV2_MULTACC_REGIN ( .b_cin(), .z_cin(), - .z_cout(), + .z_cout(z_cout), .a_cout(), .b_cout() ); @@ -837,7 +849,9 @@ module QL_DSPV2_MULTACC_REGOUT ( input wire acc_reset, input wire load_acc, input wire [ 2:0] feedback, - input wire [ 2:0] output_select + input wire [ 2:0] output_select, + + output wire [49:0] z_cout ); parameter [71:0] MODE_BITS = 72'h000000000000000000; @@ -880,7 +894,7 @@ module QL_DSPV2_MULTACC_REGOUT ( .b_cin(), .z_cin(), - .z_cout(), + .z_cout(z_cout), .a_cout(), .b_cout() ); @@ -898,7 +912,9 @@ module QL_DSPV2_MULTACC_REGIN_REGOUT ( input wire acc_reset, input wire load_acc, input wire [ 2:0] feedback, - input wire [ 2:0] output_select + input wire [ 2:0] output_select, + + output wire [49:0] z_cout ); parameter [71:0] MODE_BITS = 72'h004000000000000000; @@ -941,7 +957,7 @@ module QL_DSPV2_MULTACC_REGIN_REGOUT ( .b_cin(), .z_cin(), - .z_cout(), + .z_cout(z_cout), .a_cout(), .b_cout() ); From 4f2a06f55a84f37d158b72868a43136fbdd4c0b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 11 Mar 2025 16:37:43 +0100 Subject: [PATCH 31/38] quicklogic: Complete DSPv2 flow --- .../quicklogic/qlf_k6n10f/dspv2_final_map.v | 142 ++++++++++++++++++ techlibs/quicklogic/synth_quicklogic.cc | 3 + 2 files changed, 145 insertions(+) create mode 100644 techlibs/quicklogic/qlf_k6n10f/dspv2_final_map.v diff --git a/techlibs/quicklogic/qlf_k6n10f/dspv2_final_map.v b/techlibs/quicklogic/qlf_k6n10f/dspv2_final_map.v new file mode 100644 index 000000000..d951c6f87 --- /dev/null +++ b/techlibs/quicklogic/qlf_k6n10f/dspv2_final_map.v @@ -0,0 +1,142 @@ +// Derived from dspv2_sim.v + +module dspv2_32x18x64_cfg_ports ( + input wire [31:0] a_i, + input wire [17:0] b_i, + input wire [17:0] c_i, + output wire [49:0] z_o, + + input wire clock_i, + input wire reset_i, + input wire acc_reset_i, + + input wire [ 2:0] feedback_i, + input wire load_acc_i, + input wire [ 2:0] output_select_i, + + input wire [31:0] a_cin_i, + input wire [17:0] b_cin_i, + input wire [49:0] z_cin_i, + + output wire [31:0] a_cout_o, + output wire [17:0] b_cout_o, + output wire [49:0] z_cout_o + +); + + parameter [31:0] COEFF_0 = 32'h0; + parameter [5:0] ACC_FIR = 6'h0; + parameter [2:0] ROUND = 3'h0; + parameter [4:0] ZC_SHIFT = 5'h0; + parameter [4:0] ZREG_SHIFT = 5'h0; + parameter [5:0] SHIFT_REG = 6'h0; + parameter SATURATE = 1'b0; + parameter SUBTRACT = 1'b0; + parameter PRE_ADD = 1'b0; + parameter A_SEL = 1'b0; + parameter A_REG = 1'b0; + parameter B_SEL = 1'b0; + parameter B_REG = 1'b0; + parameter C_REG = 1'b0; + parameter BC_REG = 1'b0; + parameter M_REG = 1'b0; + parameter ZCIN_REG = 1'b0; + parameter FRAC_MODE = 1'b0; // 32x18x64 DSP + + (* is_inferred *) + QL_DSPV2 #( + .MODE_BITS({FRAC_MODE,3'b000,ZCIN_REG,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,COEFF_0}) + ) _TECHMAP_REPLACE_ ( + .a(a_i), + .b(b_i), + .c(c_i), + .load_acc(load_acc_i), + .feedback(feedback_i), + .output_select(output_select_i), + .z(z_o), + + .clk(clock_i), + .reset(reset_i), + .acc_reset(acc_reset_i), + + .a_cin(a_cin_i), + .b_cin(b_cin_i), + .z_cin(z_cin_i), + + .z_cout(z_cout_o), + .a_cout(a_cout_o), + .b_cout(b_cout_o) + ); + +endmodule + +module dspv2_16x9x32_cfg_ports ( + input wire [15:0] a_i, + input wire [8:0] b_i, + input wire [8:0] c_i, + output wire [24:0] z_o, + + input wire clock_i, + input wire reset_i, + input wire acc_reset_i, + + input wire [ 2:0] feedback_i, + input wire load_acc_i, + input wire [ 2:0] output_select_i, + + input wire [15:0] a_cin_i, + input wire [8:0] b_cin_i, + input wire [24:0] z_cin_i, + + output wire [15:0] a_cout_o, + output wire [8:0] b_cout_o, + output wire [24:0] z_cout_o + +); + + parameter [15:0] COEFF_0 = 16'h0; + parameter [5:0] ACC_FIR = 6'h0; + parameter [2:0] ROUND = 3'h0; + parameter [4:0] ZC_SHIFT = 5'h0; + parameter [4:0] ZREG_SHIFT = 5'h0; + parameter [5:0] SHIFT_REG = 6'h0; + parameter SATURATE = 1'b0; + parameter SUBTRACT = 1'b0; + parameter PRE_ADD = 1'b0; + parameter A_SEL = 1'b0; + parameter A_REG = 1'b0; + parameter B_SEL = 1'b0; + parameter B_REG = 1'b0; + parameter C_REG = 1'b0; + parameter BC_REG = 1'b0; + parameter M_REG = 1'b0; + parameter ZCIN_REG = 1'b0; + parameter FRAC_MODE = 1'b1; // 16x9x32 DSP + + (* is_inferred *) + QL_DSPV2 #( + .MODE_BITS({FRAC_MODE,3'b000,ZCIN_REG,M_REG,BC_REG,C_REG,B_REG,B_SEL,A_REG,A_SEL,PRE_ADD,SUBTRACT,SATURATE,SHIFT_REG,ZREG_SHIFT,ZC_SHIFT,ROUND,ACC_FIR,16'h0,COEFF_0}) + ) _TECHMAP_REPLACE_ ( + .a(a_i), + .b(b_i), + .c(c_i), + .load_acc(load_acc_i), + .feedback(feedback_i), + .output_select(output_select_i), + .z(z_o), + + .clk(clock_i), + .reset(reset_i), + .acc_reset(acc_reset_i), + + .a_cin(a_cin_i), + .b_cin(b_cin_i), + .z_cin(z_cin_i), + + .z_cout(z_cout_o), + .a_cout(a_cout_o), + .b_cout(b_cout_o) + ); + +endmodule + diff --git a/techlibs/quicklogic/synth_quicklogic.cc b/techlibs/quicklogic/synth_quicklogic.cc index 2daafa451..8ac5eacb9 100644 --- a/techlibs/quicklogic/synth_quicklogic.cc +++ b/techlibs/quicklogic/synth_quicklogic.cc @@ -266,6 +266,9 @@ struct SynthQuickLogicPass : public ScriptPass { "-D DSP_A_MAXWIDTH=16 -D DSP_B_MAXWIDTH=9 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_NAME=$__MUL16X9"); run("chtype -set $mul t:$__soft_mul"); run("ql_dsp"); + run("ql_dsp_simd -dspv2"); + run("techmap -map " + lib_path + family + "/dspv2_final_map.v"); + run("ql_dsp_io_regs -dspv2"); } else { log_assert(false); } From 1e9e7ad6aad1374fe73d8f4458c6e2dd033b7a06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 11 Mar 2025 16:50:22 +0100 Subject: [PATCH 32/38] quicklogic: Redo DSPv2 tests --- tests/arch/quicklogic/dspv2/complex_mult.ys | 23 --- tests/arch/quicklogic/dspv2/run-test.sh | 4 - tests/arch/quicklogic/dspv2/simple.ys | 17 -- tests/arch/quicklogic/dspv2/simple2.ys | 12 -- .../qlf_k6n10f/dspv2_full_dsp_flow.ys | 174 ++++++++++++++++++ .../arch/quicklogic/qlf_k6n10f/dspv2_macc.tcl | 45 +++++ tests/arch/quicklogic/qlf_k6n10f/dspv2_macc.v | 145 +++++++++++++++ 7 files changed, 364 insertions(+), 56 deletions(-) delete mode 100644 tests/arch/quicklogic/dspv2/complex_mult.ys delete mode 100644 tests/arch/quicklogic/dspv2/run-test.sh delete mode 100644 tests/arch/quicklogic/dspv2/simple.ys delete mode 100644 tests/arch/quicklogic/dspv2/simple2.ys create mode 100644 tests/arch/quicklogic/qlf_k6n10f/dspv2_full_dsp_flow.ys create mode 100644 tests/arch/quicklogic/qlf_k6n10f/dspv2_macc.tcl create mode 100644 tests/arch/quicklogic/qlf_k6n10f/dspv2_macc.v diff --git a/tests/arch/quicklogic/dspv2/complex_mult.ys b/tests/arch/quicklogic/dspv2/complex_mult.ys deleted file mode 100644 index 350ee8d6b..000000000 --- a/tests/arch/quicklogic/dspv2/complex_mult.ys +++ /dev/null @@ -1,23 +0,0 @@ -read_verilog < Date: Tue, 11 Mar 2025 17:02:36 +0100 Subject: [PATCH 33/38] ql_dsp: Add `-nocascade` --- techlibs/quicklogic/ql_dsp.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/techlibs/quicklogic/ql_dsp.cc b/techlibs/quicklogic/ql_dsp.cc index 3e19b6c9d..02f7b3d4e 100644 --- a/techlibs/quicklogic/ql_dsp.cc +++ b/techlibs/quicklogic/ql_dsp.cc @@ -86,6 +86,9 @@ struct QlDspPass : Pass { log("This pass packs input and output path registers into QuickLogic DSP blocks,\n"); log("additionally it supports Z path cascading and post-adder packing.\n"); log("\n"); + log(" -nocascade\n"); + log(" forbid cascading\n"); + log("\n"); } @@ -93,8 +96,13 @@ struct QlDspPass : Pass { { log_header(d, "Executing QL_DSP pass. (pack into QuickLogic DSPs)\n"); + bool nocascade = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-nocascade") { + nocascade = true; + continue; + } break; } extra_args(args, argidx, d); @@ -110,7 +118,7 @@ struct QlDspPass : Pass { ql_dsp_pm pm(module, module->selected_cells()); pm.run_ql_dsp_pack_regs(); } - { + if (!nocascade) { ql_dsp_pm pm(module, module->selected_cells()); pm.run_ql_dsp_cascade(); } From 397f748dd22cd0c3fa73d6ea1f8825538d8afdb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 11 Mar 2025 17:11:11 +0100 Subject: [PATCH 34/38] tests: Update path to sim model --- tests/verific/blackbox_ql.ys | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/verific/blackbox_ql.ys b/tests/verific/blackbox_ql.ys index 1c6d43587..360bc2a32 100644 --- a/tests/verific/blackbox_ql.ys +++ b/tests/verific/blackbox_ql.ys @@ -1,4 +1,4 @@ -verific -sv -lib +/quicklogic/qlf_k6n10f/dsp_sim.v +verific -sv -lib +/quicklogic/qlf_k6n10f/dspv1_sim.v verific -sv < Date: Tue, 11 Mar 2025 19:39:50 +0100 Subject: [PATCH 35/38] quicklogic: Fix missing install rule --- techlibs/quicklogic/Makefile.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/techlibs/quicklogic/Makefile.inc b/techlibs/quicklogic/Makefile.inc index 684eb28a3..da23ab89d 100644 --- a/techlibs/quicklogic/Makefile.inc +++ b/techlibs/quicklogic/Makefile.inc @@ -45,6 +45,7 @@ $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dspv1_final_map.v)) $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dspv2_sim.v)) $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dspv2_map.v)) +$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dspv2_final_map.v)) $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/TDP18K_FIFO.v)) $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/ufifo_ctl.v)) $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/sram1024x18_mem.v)) From 535dab1e192a5791e6be184ef378bda574b21a4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 11 Mar 2025 20:21:39 +0100 Subject: [PATCH 36/38] quicklogic: Fix one more rule --- techlibs/quicklogic/Makefile.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/quicklogic/Makefile.inc b/techlibs/quicklogic/Makefile.inc index da23ab89d..40f6af3d3 100644 --- a/techlibs/quicklogic/Makefile.inc +++ b/techlibs/quicklogic/Makefile.inc @@ -12,7 +12,7 @@ OBJS += techlibs/quicklogic/ql_ioff.o OBJS += techlibs/quicklogic/ql_dsp_macc.o OBJS += techlibs/quicklogic/ql_dsp.o -GENFILES += techlibs/quicklogic/ql_dsp_macc_pm.h techlibs/quicklogic/qlf_k6n10f/bram_types_sim.v +GENFILES += techlibs/quicklogic/ql_dsp_macc_pm.h techlibs/quicklogic/ql_dsp_pm.h techlibs/quicklogic/qlf_k6n10f/bram_types_sim.v techlibs/quicklogic/ql_dsp_macc.o: techlibs/quicklogic/ql_dsp_macc_pm.h techlibs/quicklogic/ql_dsp.o: techlibs/quicklogic/ql_dsp_pm.h $(eval $(call add_extra_objs,techlibs/quicklogic/ql_dsp_macc_pm.h)) From de61ff848cfb3dc512c55eab39836fe402c6d40e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 11 Mar 2025 21:07:03 +0100 Subject: [PATCH 37/38] quicklogic: Tune include path to fix OOT builds --- techlibs/quicklogic/ql_dsp.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/quicklogic/ql_dsp.cc b/techlibs/quicklogic/ql_dsp.cc index 02f7b3d4e..b446a6bc6 100644 --- a/techlibs/quicklogic/ql_dsp.cc +++ b/techlibs/quicklogic/ql_dsp.cc @@ -72,7 +72,7 @@ bool promote(Module *m, Cell *cell) { bool did_something; -#include "ql_dsp_pm.h" +#include "techlibs/quicklogic/ql_dsp_pm.h" struct QlDspPass : Pass { QlDspPass() : Pass("ql_dsp", "pack into QuickLogic DSPs") {} From c68fd85b9ccceb773a4aaac2a35f7d90fbb15fc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 11 Mar 2025 21:57:40 +0100 Subject: [PATCH 38/38] ql_dsp_simd: Remove array usage failing VS build --- techlibs/quicklogic/ql_dsp_simd.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/quicklogic/ql_dsp_simd.cc b/techlibs/quicklogic/ql_dsp_simd.cc index 9c2e340db..86722c66b 100644 --- a/techlibs/quicklogic/ql_dsp_simd.cc +++ b/techlibs/quicklogic/ql_dsp_simd.cc @@ -66,7 +66,7 @@ struct QlDspSimdPass : public Pass { static bool is_cascade(const Cell* cell) { - std::array cascade_ports { + static const std::vector cascade_ports = { ID(a_cout_o), ID(b_cout_o), ID(z_cout_o),