Merge pull request #251 from antmicro/fix-parameter
Fix default signed value for parameters
diff --git a/ql-qlf-plugin/Makefile b/ql-qlf-plugin/Makefile
index 2819055..e9de5bd 100644
--- a/ql-qlf-plugin/Makefile
+++ b/ql-qlf-plugin/Makefile
@@ -11,14 +11,15 @@
ql-dsp.cc \
pp3_braminit.cc \
quicklogic_eqn.cc \
- ql-edif.cc
+ ql-edif.cc \
+ ql-dsp-simd.cc
include ../Makefile_plugin.common
COMMON = common
QLF_K4N8_DIR = qlf_k4n8
QLF_K6N10_DIR = qlf_k6n10
-QLF_K6N10F_DIR = qlf_k6n10f
+QLF_K6N10F_DIR = qlf_k6n10f
PP3_DIR = pp3
VERILOG_MODULES = $(COMMON)/cells_sim.v \
$(QLF_K4N8_DIR)/arith_map.v \
@@ -37,6 +38,7 @@
$(QLF_K6N10F_DIR)/cells_sim.v \
$(QLF_K6N10F_DIR)/ffs_map.v \
$(QLF_K6N10F_DIR)/dsp_map.v \
+ $(QLF_K6N10F_DIR)/dsp_final_map.v \
$(PP3_DIR)/abc9_map.v \
$(PP3_DIR)/abc9_model.v \
$(PP3_DIR)/abc9_unmap.v \
diff --git a/ql-qlf-plugin/ql-dsp-simd.cc b/ql-qlf-plugin/ql-dsp-simd.cc
new file mode 100644
index 0000000..1bd0850
--- /dev/null
+++ b/ql-qlf-plugin/ql-dsp-simd.cc
@@ -0,0 +1,275 @@
+// Copyright (C) 2020-2022 The SymbiFlow Authors.
+//
+// Use of this source code is governed by a ISC-style
+// license that can be found in the LICENSE file or at
+// https://opensource.org/licenses/ISC
+//
+// SPDX-License-Identifier:ISC
+
+#include "kernel/log.h"
+#include "kernel/register.h"
+#include "kernel/rtlil.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+// ============================================================================
+
+struct QlDspSimdPass : public Pass {
+
+ QlDspSimdPass() : Pass("ql_dsp_simd", "Infers QuickLogic k6n10f DSP pairs that can operate in SIMD mode") {}
+
+ void help() override
+ {
+ log("\n");
+ log(" ql_dsp_simd [selection]\n");
+ log("\n");
+ log(" This pass identifies k6n10f DSP cells with identical configuration\n");
+ log(" and packs pairs of them together into other DSP cells that can\n");
+ log(" perform SIMD operation.\n");
+ }
+
+ // ..........................................
+
+ /// Describes DSP config unique to a whole DSP cell
+ struct DspConfig {
+
+ // Port connections
+ dict<RTLIL::IdString, RTLIL::SigSpec> connections;
+
+ // TODO: Possibly include parameters here. For now we have just
+ // connections.
+
+ DspConfig() = default;
+
+ DspConfig(const DspConfig &ref) = default;
+ DspConfig(DspConfig &&ref) = default;
+
+ unsigned int hash() const { return connections.hash(); }
+
+ bool operator==(const DspConfig &ref) const { return connections == ref.connections; }
+ };
+
+ // ..........................................
+
+ // DSP control and config ports to consider and how to map them to ports
+ // of the target DSP cell
+ const std::vector<std::pair<std::string, std::string>> m_DspCfgPorts = {std::make_pair("clock_i", "clk"),
+ std::make_pair("reset_i", "reset"),
+
+ std::make_pair("feedback_i", "feedback"),
+ std::make_pair("load_acc_i", "load_acc"),
+ std::make_pair("unsigned_a_i", "unsigned_a"),
+ std::make_pair("unsigned_b_i", "unsigned_b"),
+
+ std::make_pair("output_select_i", "output_select"),
+ std::make_pair("saturate_enable_i", "saturate_enable"),
+ std::make_pair("shift_right_i", "shift_right"),
+ std::make_pair("round_i", "round"),
+ std::make_pair("subtract_i", "subtract"),
+ std::make_pair("register_inputs_i", "register_inputs")};
+
+ // DSP data ports and how to map them to ports of the target DSP cell
+ const std::vector<std::pair<std::string, std::string>> m_DspDataPorts = {
+ std::make_pair("a_i", "a"), std::make_pair("b_i", "b"), std::make_pair("acc_fir_i", "acc_fir"),
+ std::make_pair("z_o", "z"), std::make_pair("dly_b_o", "dly_b"),
+ };
+
+ // Source DSP cell type (SISD)
+ const RTLIL::IdString m_SisdDspType = RTLIL::escape_id("dsp_t1_10x9x32");
+ // Target DSP cell type for the SIMD mode
+ const RTLIL::IdString m_SimdDspType = RTLIL::escape_id("QL_DSP2");
+
+ /// Temporary SigBit to SigBit helper map.
+ SigMap m_SigMap;
+
+ // ..........................................
+
+ void execute(std::vector<std::string> a_Args, RTLIL::Design *a_Design) override
+ {
+ log_header(a_Design, "Executing QL_DSP_SIMD pass.\n");
+
+ // Parse args
+ extra_args(a_Args, 1, a_Design);
+
+ // Process modules
+ for (auto module : a_Design->selected_modules()) {
+
+ // Setup the SigMap
+ m_SigMap.clear();
+ m_SigMap.set(module);
+
+ // Assemble DSP cell groups
+ dict<DspConfig, std::vector<RTLIL::Cell *>> groups;
+ for (auto cell : module->selected_cells()) {
+
+ // Check if this is a DSP cell
+ if (cell->type != m_SisdDspType) {
+ continue;
+ }
+
+ // Skip if it has the (* keep *) attribute set
+ if (cell->has_keep_attr()) {
+ continue;
+ }
+
+ // Add to a group
+ const auto key = getDspConfig(cell);
+ groups[key].push_back(cell);
+ }
+
+ std::vector<const RTLIL::Cell *> 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;
+
+ // Ensure an even number
+ size_t count = group.size();
+ if (count & 1)
+ count--;
+
+ // Map SIMD pairs
+ for (size_t i = 0; i < count; i += 2) {
+ const RTLIL::Cell *dsp_a = group[i];
+ const RTLIL::Cell *dsp_b = group[i + 1];
+
+ std::string name = stringf("simd_%s_%s", RTLIL::unescape_id(dsp_a->name).c_str(), RTLIL::unescape_id(dsp_b->name).c_str());
+
+ log(" SIMD: %s (%s) + %s (%s) => %s (%s)\n", RTLIL::unescape_id(dsp_a->name).c_str(), RTLIL::unescape_id(dsp_a->type).c_str(),
+ RTLIL::unescape_id(dsp_b->name).c_str(), RTLIL::unescape_id(dsp_b->type).c_str(), RTLIL::unescape_id(name).c_str(),
+ RTLIL::unescape_id(m_SimdDspType).c_str());
+
+ // Create the new cell
+ RTLIL::Cell *simd = module->addCell(RTLIL::escape_id(name), m_SimdDspType);
+
+ // 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!", RTLIL::unescape_id(m_SimdDspType).c_str());
+ }
+
+ // Connect common ports
+ for (const auto &it : m_DspCfgPorts) {
+ auto sport = RTLIL::escape_id(it.first);
+ auto dport = RTLIL::escape_id(it.second);
+
+ simd->setPort(dport, config.connections.at(sport));
+ }
+
+ // Connect data ports
+ for (const auto &it : m_DspDataPorts) {
+ auto sport = RTLIL::escape_id(it.first);
+ auto dport = RTLIL::escape_id(it.second);
+
+ size_t width;
+ bool isOutput;
+
+ std::tie(width, isOutput) = getPortInfo(simd, dport);
+
+ auto getConnection = [&](const RTLIL::Cell *cell) {
+ RTLIL::SigSpec sigspec;
+ if (cell->hasPort(sport)) {
+ const auto &sig = cell->getPort(sport);
+ sigspec.append(sig);
+ }
+ if (sigspec.bits().size() < width / 2) {
+ if (isOutput) {
+ for (size_t i = 0; i < width / 2 - sigspec.bits().size(); ++i) {
+ sigspec.append(RTLIL::SigSpec());
+ }
+ } else {
+ sigspec.append(RTLIL::SigSpec(RTLIL::Sx, width / 2 - sigspec.bits().size()));
+ }
+ }
+ return sigspec;
+ };
+
+ RTLIL::SigSpec sigspec;
+ sigspec.append(getConnection(dsp_a));
+ sigspec.append(getConnection(dsp_b));
+ simd->setPort(dport, sigspec);
+ }
+
+ // Enable the fractured mode by connecting the control
+ // port.
+ simd->setPort(RTLIL::escape_id("f_mode"), RTLIL::S1);
+
+ // Mark DSP parts for removal
+ cellsToRemove.push_back(dsp_a);
+ cellsToRemove.push_back(dsp_b);
+ }
+ }
+
+ // Remove old cells
+ for (const auto &cell : cellsToRemove) {
+ module->remove(const_cast<RTLIL::Cell *>(cell));
+ }
+ }
+
+ // Clear
+ m_SigMap.clear();
+ }
+
+ // ..........................................
+
+ /// Looks up port width and direction in the cell definition and returns it.
+ /// Returns (0, false) if it cannot be determined.
+ std::pair<size_t, bool> getPortInfo(RTLIL::Cell *a_Cell, RTLIL::IdString a_Port)
+ {
+ if (!a_Cell->known()) {
+ return std::make_pair(0, false);
+ }
+
+ // Get the module defining the cell (the previous condition ensures
+ // that the pointers are valid)
+ RTLIL::Module *mod = a_Cell->module->design->module(a_Cell->type);
+ if (mod == nullptr) {
+ return std::make_pair(0, false);
+ }
+
+ // Get the wire representing the port
+ RTLIL::Wire *wire = mod->wire(a_Port);
+ if (wire == nullptr) {
+ return std::make_pair(0, false);
+ }
+
+ return std::make_pair(wire->width, wire->port_output);
+ }
+
+ /// Given a DSP cell populates and returns a DspConfig struct for it.
+ DspConfig getDspConfig(RTLIL::Cell *a_Cell)
+ {
+ DspConfig config;
+
+ for (const auto &it : m_DspCfgPorts) {
+ auto port = RTLIL::escape_id(it.first);
+
+ // Port unconnected
+ if (!a_Cell->hasPort(port)) {
+ config.connections[port] = RTLIL::SigSpec(RTLIL::Sx);
+ continue;
+ }
+
+ // Get the port connection and map it to unique SigBits
+ const auto &orgSigSpec = a_Cell->getPort(port);
+ const auto &orgSigBits = orgSigSpec.bits();
+
+ RTLIL::SigSpec newSigSpec;
+ for (size_t i = 0; i < orgSigBits.size(); ++i) {
+ auto newSigBit = m_SigMap(orgSigBits[i]);
+ newSigSpec.append(newSigBit);
+ }
+
+ // Store
+ config.connections[port] = newSigSpec;
+ }
+
+ return config;
+ }
+
+} QlDspSimdPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/ql-qlf-plugin/qlf_k6n10f/arith_map.v b/ql-qlf-plugin/qlf_k6n10f/arith_map.v
index c2323d6..25c6901 100644
--- a/ql-qlf-plugin/qlf_k6n10f/arith_map.v
+++ b/ql-qlf-plugin/qlf_k6n10f/arith_map.v
@@ -26,6 +26,7 @@
(* force_downto *)
output [Y_WIDTH-1:0] CO;
+
wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
(* force_downto *)
@@ -45,6 +46,8 @@
wire [Y_WIDTH:0] C;
(* force_downto *)
wire [Y_WIDTH-1:0] S = {AA ^ BB};
+
+ assign CO[Y_WIDTH-1:0] = C[Y_WIDTH:1];
generate
adder_carry intermediate_adder (
diff --git a/ql-qlf-plugin/qlf_k6n10f/cells_sim.v b/ql-qlf-plugin/qlf_k6n10f/cells_sim.v
index b8c5b38..43b3ba2 100644
--- a/ql-qlf-plugin/qlf_k6n10f/cells_sim.v
+++ b/ql-qlf-plugin/qlf_k6n10f/cells_sim.v
@@ -109,7 +109,7 @@
assign lut4_out[2] = s4[2];
assign lut4_out[3] = s4[3];
- assign lut5_out[0] = s0[0];
+ assign lut5_out[0] = s5[0];
assign lut5_out[1] = s5[1];
assign lut6_out = li[5] ? s5[0] : s5[1];
@@ -228,7 +228,7 @@
(* invertible_pin = "IS_C_INVERTED" *)
input C,
input S,
- input E,
+ input E
);
parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_C_INVERTED = 1'b0;
@@ -749,7 +749,7 @@
module dsp_t1_10x9x32 (
input [ 9:0] a_i,
input [ 8:0] b_i,
- input [ 3:0] acc_fir_i,
+ input [ 1:0] acc_fir_i,
output [18:0] z_o,
output [ 8:0] dly_b_o,
diff --git a/ql-qlf-plugin/qlf_k6n10f/dsp_final_map.v b/ql-qlf-plugin/qlf_k6n10f/dsp_final_map.v
new file mode 100644
index 0000000..5fe905c
--- /dev/null
+++ b/ql-qlf-plugin/qlf_k6n10f/dsp_final_map.v
@@ -0,0 +1,129 @@
+// Copyright (C) 2020-2021 The SymbiFlow Authors.
+//
+// Use of this source code is governed by a ISC-style
+// license that can be found in the LICENSE file or at
+// https://opensource.org/licenses/ISC
+//
+// SPDX-License-Identifier:ISC
+
+module dsp_t1_20x18x64 (
+ input [19:0] a_i,
+ input [17:0] b_i,
+ input [ 3: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,
+ input [19:0] coeff_0_i,
+ input [19:0] coeff_1_i,
+ input [19:0] coeff_2_i,
+ input [19:0] coeff_3_i
+);
+
+ QL_DSP2 _TECHMAP_REPLACE_ (
+ .a (a_i),
+ .b (b_i),
+ .acc_fir (acc_fir_i),
+ .z (z_o),
+ .dly_b (dly_b_o),
+
+ .clk (clk_i),
+ .reset (reset_i),
+
+ .feedback (feedback_i),
+ .load_acc (load_acc_i),
+ .unsigned_a (unsigned_a_i),
+ .unsigned_b (unsigned_b_i),
+
+ .f_mode (1'b0), // No fracturation
+ .output_select (output_select_i),
+ .saturate_enable (saturate_enable_i),
+ .shift_right (shift_right_i),
+ .round (round_i),
+ .subtract (subtract_i),
+ .register_inputs (register_inputs_i),
+ .coeff_0 (coeff_0_i),
+ .coeff_1 (coeff_1_i),
+ .coeff_2 (coeff_2_i),
+ .coeff_3 (coeff_3_i)
+ );
+
+endmodule
+
+module dsp_t1_10x9x32 (
+ input [ 9:0] a_i,
+ input [ 8:0] b_i,
+ input [ 1:0] acc_fir_i,
+ output [18:0] z_o,
+ output [ 8:0] dly_b_o,
+
+ (* clkbuf_sink *)
+ 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,
+ input [ 9:0] coeff_0_i,
+ input [ 9:0] coeff_1_i,
+ input [ 9:0] coeff_2_i,
+ input [ 9:0] coeff_3_i
+);
+
+ wire [37:0] z;
+ wire [17:0] dly_b;
+
+ QL_DSP2 _TECHMAP_REPLACE_ (
+ .a ({10'd0, a_i}),
+ .b ({ 9'd0, b_i}),
+ .acc_fir (acc_fir_i),
+ .z (z),
+ .dly_b (dly_b),
+
+ .clk (clk_i),
+ .reset (reset_i),
+
+ .feedback (feedback_i),
+ .load_acc (load_acc_i),
+ .unsigned_a (unsigned_a_i),
+ .unsigned_b (unsigned_b_i),
+
+ .f_mode (1'b1), // Enable fractuation, Use the lower half
+ .output_select (output_select_i),
+ .saturate_enable (saturate_enable_i),
+ .shift_right (shift_right_i),
+ .round (round_i),
+ .subtract (subtract_i),
+ .register_inputs (register_inputs_i),
+ .coeff_0 ({10'd0, coeff_0_i}),
+ .coeff_1 ({10'd0, coeff_1_i}),
+ .coeff_2 ({10'd0, coeff_2_i}),
+ .coeff_3 ({10'd0, coeff_3_i})
+ );
+
+ assign z_o = z[18:0];
+ assign dly_b_o = dly_b_o[8:0];
+
+endmodule
+
diff --git a/ql-qlf-plugin/qlf_k6n10f/dsp_map.v b/ql-qlf-plugin/qlf_k6n10f/dsp_map.v
index f0c5a8b..054d82a 100644
--- a/ql-qlf-plugin/qlf_k6n10f/dsp_map.v
+++ b/ql-qlf-plugin/qlf_k6n10f/dsp_map.v
@@ -31,7 +31,7 @@
.acc_fir_i (4'd0),
.z_o (z),
- .feedback_i (2'd0),
+ .feedback_i (3'd0),
.load_acc_i (1'b0),
.unsigned_a_i (!A_SIGNED),
.unsigned_b_i (!B_SIGNED),
@@ -74,7 +74,7 @@
dsp_t1_10x9x32 _TECHMAP_REPLACE_ (
.a_i (a),
.b_i (b),
- .acc_fir_i (4'd0),
+ .acc_fir_i (3'd0),
.z_o (z),
.feedback_i (2'd0),
diff --git a/ql-qlf-plugin/synth_quicklogic.cc b/ql-qlf-plugin/synth_quicklogic.cc
index 01ce6ef..3bb44c5 100644
--- a/ql-qlf-plugin/synth_quicklogic.cc
+++ b/ql-qlf-plugin/synth_quicklogic.cc
@@ -272,6 +272,8 @@
run("techmap -map +/mul2dsp.v [...]", "(for qlf_k6n10f if not -no_dsp)");
run("chtype -set $mul t:$__soft_mul", "(for qlf_k6n10f if not -no_dsp)");
run("techmap -map +/quicklogic/" + family + "/dsp_map.v", "(for qlf_k6n10f if not -no_dsp)");
+ run("ql_dsp_simd ", "(for qlf_k6n10f if not -no_dsp)");
+ run("techmap -map +/quicklogic/" + family + "/dsp_final_map.v", "(for qlf_k6n10f if not -no_dsp)");
} else if (!nodsp) {
run("wreduce t:$mul");
@@ -284,6 +286,8 @@
run("chtype -set $mul t:$__soft_mul");
}
run("techmap -map +/quicklogic/" + family + "/dsp_map.v");
+ run("ql_dsp_simd");
+ run("techmap -map +/quicklogic/" + family + "/dsp_final_map.v");
}
}
diff --git a/ql-qlf-plugin/tests/Makefile b/ql-qlf-plugin/tests/Makefile
index 4fc598c..e54aeaf 100644
--- a/ql-qlf-plugin/tests/Makefile
+++ b/ql-qlf-plugin/tests/Makefile
@@ -21,7 +21,8 @@
tribuf \
fsm \
pp3_bram \
- qlf_k6n10f/dsp_mult
+ qlf_k6n10f/dsp_mult \
+ qlf_k6n10f/dsp_simd
# qlf_k6n10_bram \
include $(shell pwd)/../../Makefile_test.common
@@ -40,4 +41,5 @@
fsm_verify = true
pp3_bram_verify = true
qlf_k6n10f-dsp_mult_verify = true
+qlf_k6n10f-dsp_simd_verify = true
#qlf_k6n10_bram_verify = true
diff --git a/ql-qlf-plugin/tests/full_adder/full_adder.tcl b/ql-qlf-plugin/tests/full_adder/full_adder.tcl
index 05ced41..41443f4 100644
--- a/ql-qlf-plugin/tests/full_adder/full_adder.tcl
+++ b/ql-qlf-plugin/tests/full_adder/full_adder.tcl
@@ -64,7 +64,8 @@
read_verilog -icells -DWIDTH=4 $::env(DESIGN_TOP).v
hierarchy -check -top full_adder
yosys proc
-synth_quicklogic -family qlf_k6n10f
+equiv_opt -assert -map +/quicklogic/qlf_k6n10f/cells_sim.v synth_quicklogic -family qlf_k6n10f
+design -load postopt
yosys cd full_adder
stat
select -assert-count 6 t:adder_carry
@@ -75,13 +76,26 @@
read_verilog -icells -DWIDTH=4 $::env(DESIGN_TOP).v
hierarchy -check -top subtractor
yosys proc
-synth_quicklogic -family qlf_k6n10f
+equiv_opt -assert -map +/quicklogic/qlf_k6n10f/cells_sim.v synth_quicklogic -family qlf_k6n10f
+design -load postopt
yosys cd subtractor
stat
select -assert-count 6 t:adder_carry
design -reset
+# Equivalence check for comparator synthesis for qlf-k6n10
+read_verilog -icells -DWIDTH=4 $::env(DESIGN_TOP).v
+hierarchy -check -top comparator
+yosys proc
+equiv_opt -assert -map +/quicklogic/qlf_k6n10f/cells_sim.v synth_quicklogic -family qlf_k6n10f
+design -load postopt
+yosys cd comparator
+stat
+select -assert-count 5 t:adder_carry
+
+design -reset
+
# Equivalence check for adder synthesis for pp3
read_verilog -icells -DWIDTH=4 $::env(DESIGN_TOP).v
hierarchy -check -top full_adder
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/dsp_mult/dsp_mult.tcl b/ql-qlf-plugin/tests/qlf_k6n10f/dsp_mult/dsp_mult.tcl
index 90f591d..75acb10 100644
--- a/ql-qlf-plugin/tests/qlf_k6n10f/dsp_mult/dsp_mult.tcl
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/dsp_mult/dsp_mult.tcl
@@ -10,26 +10,26 @@
hierarchy -top $TOP
synth_quicklogic -family qlf_k6n10f -top $TOP
yosys cd $TOP
-select -assert-count 1 t:dsp_t1_20x18x64
+select -assert-count 1 t:QL_DSP2
set TOP "mult_20x18"
design -load read
hierarchy -top $TOP
synth_quicklogic -family qlf_k6n10f -top $TOP
yosys cd $TOP
-select -assert-count 1 t:dsp_t1_20x18x64
+select -assert-count 1 t:QL_DSP2
set TOP "mult_8x8"
design -load read
hierarchy -top $TOP
synth_quicklogic -family qlf_k6n10f -top $TOP
yosys cd $TOP
-select -assert-count 1 t:dsp_t1_10x9x32
+select -assert-count 1 t:QL_DSP2
set TOP "mult_10x9"
design -load read
hierarchy -top $TOP
synth_quicklogic -family qlf_k6n10f -top $TOP
yosys cd $TOP
-select -assert-count 1 t:dsp_t1_10x9x32
+select -assert-count 1 t:QL_DSP2
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/dsp_simd/dsp_simd.tcl b/ql-qlf-plugin/tests/qlf_k6n10f/dsp_simd/dsp_simd.tcl
new file mode 100644
index 0000000..dd06114
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/dsp_simd/dsp_simd.tcl
@@ -0,0 +1,43 @@
+yosys -import
+if { [info procs quicklogic_eqn] == {} } { plugin -i ql-qlf}
+yosys -import ;# ingest plugin commands
+
+read_verilog dsp_simd.v
+design -save read
+
+set TOP "simd_mult"
+design -load read
+hierarchy -top $TOP
+synth_quicklogic -family qlf_k6n10f -top $TOP
+yosys cd $TOP
+select -assert-count 0 t:dsp_t1_20x18x64
+select -assert-count 0 t:dsp_t1_10x9x32
+select -assert-count 1 t:QL_DSP2
+
+set TOP "simd_mult_inferred"
+design -load read
+hierarchy -top $TOP
+synth_quicklogic -family qlf_k6n10f -top $TOP
+yosys cd $TOP
+select -assert-count 0 t:dsp_t1_20x18x64
+select -assert-count 0 t:dsp_t1_10x9x32
+select -assert-count 1 t:QL_DSP2
+
+set TOP "simd_mult_odd"
+design -load read
+hierarchy -top $TOP
+synth_quicklogic -family qlf_k6n10f -top $TOP
+yosys cd $TOP
+select -assert-count 0 t:dsp_t1_20x18x64
+select -assert-count 0 t:dsp_t1_10x9x32
+select -assert-count 2 t:QL_DSP2
+
+set TOP "simd_mult_conflict"
+design -load read
+hierarchy -top $TOP
+synth_quicklogic -family qlf_k6n10f -top $TOP
+yosys cd $TOP
+select -assert-count 0 t:dsp_t1_20x18x64
+select -assert-count 0 t:dsp_t1_10x9x32
+select -assert-count 2 t:QL_DSP2
+
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/dsp_simd/dsp_simd.v b/ql-qlf-plugin/tests/qlf_k6n10f/dsp_simd/dsp_simd.v
new file mode 100644
index 0000000..b871eb8
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/dsp_simd/dsp_simd.v
@@ -0,0 +1,215 @@
+// Copyright (C) 2020-2021 The SymbiFlow Authors.
+//
+// Use of this source code is governed by a ISC-style
+// license that can be found in the LICENSE file or at
+// https://opensource.org/licenses/ISC
+//
+// SPDX-License-Identifier:ISC
+
+module simd_mult (
+ input wire clk,
+
+ input wire [ 7:0] a0,
+ input wire [ 7:0] b0,
+ output wire [15:0] z0,
+
+ input wire [ 7:0] a1,
+ input wire [ 7:0] b1,
+ output wire [15:0] z1
+);
+
+ dsp_t1_10x9x32 dsp_0 (
+ .a_i (a0),
+ .b_i (b0),
+ .z_o (z0),
+
+ .clock_i (clk),
+
+ .feedback_i (3'd0),
+ .load_acc_i (1'b0),
+ .unsigned_a_i (1'b1),
+ .unsigned_b_i (1'b1),
+
+ .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'b1)
+ );
+
+ dsp_t1_10x9x32 dsp_1 (
+ .a_i (a1),
+ .b_i (b1),
+ .z_o (z1),
+
+ .clock_i (clk),
+
+ .feedback_i (3'd0),
+ .load_acc_i (1'b0),
+ .unsigned_a_i (1'b1),
+ .unsigned_b_i (1'b1),
+
+ .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'b1)
+ );
+
+endmodule
+
+module simd_mult_inferred (
+ input wire clk,
+
+ input wire [ 7:0] a0,
+ input wire [ 7:0] b0,
+ output reg [15:0] z0,
+
+ input wire [ 7:0] a1,
+ input wire [ 7:0] b1,
+ output reg [15:0] z1
+);
+
+ always @(posedge clk)
+ z0 <= a0 * b0;
+
+ always @(posedge clk)
+ z1 <= a1 * b1;
+
+endmodule
+
+module simd_mult_odd (
+ input wire clk,
+
+ input wire [ 7:0] a0,
+ input wire [ 7:0] b0,
+ output wire [15:0] z0,
+
+ input wire [ 7:0] a1,
+ input wire [ 7:0] b1,
+ output wire [15:0] z1,
+
+ input wire [ 7:0] a2,
+ input wire [ 7:0] b2,
+ output wire [15:0] z2
+);
+
+ dsp_t1_10x9x32 dsp_0 (
+ .a_i (a0),
+ .b_i (b0),
+ .z_o (z0),
+
+ .clock_i (clk),
+
+ .feedback_i (3'd0),
+ .load_acc_i (1'b0),
+ .unsigned_a_i (1'b1),
+ .unsigned_b_i (1'b1),
+
+ .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'b1)
+ );
+
+ dsp_t1_10x9x32 dsp_1 (
+ .a_i (a1),
+ .b_i (b1),
+ .z_o (z1),
+
+ .clock_i (clk),
+
+ .feedback_i (3'd0),
+ .load_acc_i (1'b0),
+ .unsigned_a_i (1'b1),
+ .unsigned_b_i (1'b1),
+
+ .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'b1)
+ );
+
+ dsp_t1_10x9x32 dsp_2 (
+ .a_i (a2),
+ .b_i (b2),
+ .z_o (z2),
+
+ .clock_i (clk),
+
+ .feedback_i (3'd0),
+ .load_acc_i (1'b0),
+ .unsigned_a_i (1'b1),
+ .unsigned_b_i (1'b1),
+
+ .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'b1)
+ );
+
+endmodule
+
+module simd_mult_conflict (
+ input wire clk0,
+ input wire clk1,
+
+ input wire [ 7:0] a0,
+ input wire [ 7:0] b0,
+ output wire [15:0] z0,
+
+ input wire [ 7:0] a1,
+ input wire [ 7:0] b1,
+ output wire [15:0] z1
+);
+
+ dsp_t1_10x9x32 dsp_0 (
+ .a_i (a0),
+ .b_i (b0),
+ .z_o (z0),
+
+ .clock_i (clk0),
+
+ .feedback_i (3'd0),
+ .load_acc_i (1'b0),
+ .unsigned_a_i (1'b1),
+ .unsigned_b_i (1'b1),
+
+ .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'b1)
+ );
+
+ dsp_t1_10x9x32 dsp_1 (
+ .a_i (a1),
+ .b_i (b1),
+ .z_o (z1),
+
+ .clock_i (clk1),
+
+ .feedback_i (3'd0),
+ .load_acc_i (1'b0),
+ .unsigned_a_i (1'b1),
+ .unsigned_b_i (1'b1),
+
+ .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'b1)
+ );
+
+endmodule
+