mirror of https://github.com/YosysHQ/yosys.git
qlf_k6n10f: New ql_dsp pass, move to DSPV2
This commit is contained in:
parent
92afe26d6b
commit
d600245ccf
|
@ -10,9 +10,12 @@ OBJS += techlibs/quicklogic/ql_dsp_io_regs.o
|
||||||
# --------------------------------------
|
# --------------------------------------
|
||||||
|
|
||||||
OBJS += techlibs/quicklogic/ql_dsp_macc.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/qlf_k6n10f/bram_types_sim.v
|
||||||
techlibs/quicklogic/ql_dsp_macc.o: techlibs/quicklogic/ql_dsp_macc_pm.h
|
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_macc_pm.h))
|
||||||
|
$(eval $(call add_extra_objs,techlibs/quicklogic/ql_dsp_pm.h))
|
||||||
|
|
||||||
# --------------------------------------
|
# --------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -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<std::string> 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
|
|
@ -0,0 +1,266 @@
|
||||||
|
// derived from passes/pmgen/xilinx_dsp.pmg
|
||||||
|
pattern ql_dsp_pack_regs
|
||||||
|
|
||||||
|
state <SigBit> clock reset
|
||||||
|
state <bool> clock_inferred
|
||||||
|
|
||||||
|
// Variables used for subpatterns
|
||||||
|
state <SigSpec> argQ argD
|
||||||
|
udata <SigSpec> dffD dffQ
|
||||||
|
udata <SigBit> dffclock dffreset
|
||||||
|
udata <Cell*> 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 <SigBit> port(ff, \Q)[offset] === argQ[0]
|
||||||
|
|
||||||
|
define <SigBit> 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 <SigBit> port(ff, \D)[offset] === argD[0]
|
||||||
|
|
||||||
|
define <SigBit> 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 <int> 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 <int> width param(add, \Y_WIDTH).as_int()
|
||||||
|
|
||||||
|
index <SigBit> 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 <SigBit> 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
|
|
@ -1,102 +1,59 @@
|
||||||
// Copyright 2020-2022 F4PGA Authors
|
module \$__MUL32X18 (input [31:0] A, input [17:0] B, output [49:0] Y);
|
||||||
//
|
|
||||||
// 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 A_SIGNED = 0;
|
||||||
parameter B_SIGNED = 0;
|
parameter B_SIGNED = 0;
|
||||||
parameter A_WIDTH = 0;
|
parameter A_WIDTH = 32;
|
||||||
parameter B_WIDTH = 0;
|
parameter B_WIDTH = 18;
|
||||||
parameter Y_WIDTH = 0;
|
parameter Y_WIDTH = 50;
|
||||||
|
|
||||||
wire [19:0] a;
|
dspv2_32x18x64_cfg_ports _TECHMAP_REPLACE_ (
|
||||||
wire [17:0] b;
|
.a_i(A),
|
||||||
wire [37:0] z;
|
.b_i(B),
|
||||||
|
.c_i(18'd0),
|
||||||
|
.z_o(Y),
|
||||||
|
|
||||||
assign a = (A_WIDTH == 20) ? A :
|
.clock_i(1'bx),
|
||||||
(A_SIGNED) ? {{(20 - A_WIDTH){A[A_WIDTH-1]}}, A} :
|
.reset_i(1'bx),
|
||||||
{{(20 - A_WIDTH){1'b0}}, A};
|
.acc_reset_i(1'b0),
|
||||||
|
.feedback_i(3'd0),
|
||||||
assign b = (B_WIDTH == 18) ? B :
|
.load_acc_i(1'b0),
|
||||||
(B_SIGNED) ? {{(18 - B_WIDTH){B[B_WIDTH-1]}}, B} :
|
.output_select_i(3'd0),
|
||||||
{{(18 - B_WIDTH){1'b0}}, B};
|
.a_cin_i(32'dx),
|
||||||
|
.b_cin_i(18'dx),
|
||||||
(* is_inferred=1 *)
|
.z_cin_i(50'dx),
|
||||||
dsp_t1_20x18x64_cfg_ports _TECHMAP_REPLACE_ (
|
/* TODO: connect to dummy wires?
|
||||||
.a_i (a),
|
.a_cout_o(),
|
||||||
.b_i (b),
|
.b_cout_o(),
|
||||||
.acc_fir_i (6'd0),
|
.z_cout_o(),
|
||||||
.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
|
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 A_SIGNED = 0;
|
||||||
parameter B_SIGNED = 0;
|
parameter B_SIGNED = 0;
|
||||||
parameter A_WIDTH = 0;
|
parameter A_WIDTH = 16;
|
||||||
parameter B_WIDTH = 0;
|
parameter B_WIDTH = 9;
|
||||||
parameter Y_WIDTH = 0;
|
parameter Y_WIDTH = 25;
|
||||||
|
|
||||||
wire [ 9:0] a;
|
dspv2_16x9x32_cfg_ports _TECHMAP_REPLACE_ (
|
||||||
wire [ 8:0] b;
|
.a_i(A),
|
||||||
wire [18:0] z;
|
.b_i(B),
|
||||||
|
.c_i(10'd0),
|
||||||
|
.z_o(Y),
|
||||||
|
|
||||||
assign a = (A_WIDTH == 10) ? A :
|
.clock_i(1'bx),
|
||||||
(A_SIGNED) ? {{(10 - A_WIDTH){A[A_WIDTH-1]}}, A} :
|
.reset_i(1'bx),
|
||||||
{{(10 - A_WIDTH){1'b0}}, A};
|
.acc_reset_i(1'b0),
|
||||||
|
.feedback_i(3'd0),
|
||||||
assign b = (B_WIDTH == 9) ? B :
|
.load_acc_i(1'b0),
|
||||||
(B_SIGNED) ? {{( 9 - B_WIDTH){B[B_WIDTH-1]}}, B} :
|
.output_select_i(3'd0),
|
||||||
{{( 9 - B_WIDTH){1'b0}}, B};
|
.a_cin_i(32'dx),
|
||||||
|
.b_cin_i(18'dx),
|
||||||
(* is_inferred=1 *)
|
.z_cin_i(50'dx),
|
||||||
dsp_t1_10x9x32_cfg_ports _TECHMAP_REPLACE_ (
|
/* TODO: connect to dummy wires?
|
||||||
.a_i (a),
|
.a_cout_o(),
|
||||||
.b_i (b),
|
.b_cout_o(),
|
||||||
.acc_fir_i (6'd0),
|
.z_cout_o(),
|
||||||
.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
|
endmodule
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -222,16 +222,21 @@ struct SynthQuickLogicPass : public ScriptPass {
|
||||||
if (check_label("map_dsp", "(for qlf_k6n10f, skip if -nodsp)")
|
if (check_label("map_dsp", "(for qlf_k6n10f, skip if -nodsp)")
|
||||||
&& ((dsp && family == "qlf_k6n10f") || help_mode)) {
|
&& ((dsp && family == "qlf_k6n10f") || help_mode)) {
|
||||||
run("wreduce t:$mul");
|
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("chtype -set $mul t:$__soft_mul");
|
||||||
|
|
||||||
run("techmap -map " + lib_path + family + "/dsp_map.v -D USE_DSP_CFG_PARAMS=0");
|
run("ql_dsp");
|
||||||
run("ql_dsp_simd");
|
|
||||||
run("techmap -map " + lib_path + family + "/dsp_final_map.v");
|
//run("ql_dsp_simd");
|
||||||
run("ql_dsp_io_regs");
|
//run("techmap -map " + lib_path + family + "/dsp_final_map.v");
|
||||||
|
//run("ql_dsp_io_regs");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_label("coarse")) {
|
if (check_label("coarse")) {
|
||||||
|
|
Loading…
Reference in New Issue