ql-qlf: k6n10f: DSP: adjust custom passes
Signed-off-by: Pawel Czarnecki <pczarnecki@antmicro.com>
diff --git a/ql-qlf-plugin/ql-dsp-io-regs.cc b/ql-qlf-plugin/ql-dsp-io-regs.cc
index 7161203..4befecf 100644
--- a/ql-qlf-plugin/ql-dsp-io-regs.cc
+++ b/ql-qlf-plugin/ql-dsp-io-regs.cc
@@ -4,34 +4,56 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
+#define MODE_BITS_REGISTER_INPUTS_ID 92
+#define MODE_BITS_OUTPUT_SELECT_START_ID 81
+#define MODE_BITS_OUTPUT_SELECT_WIDTH 3
+
// ============================================================================
-const std::vector<std::string> ports2del_mult = {"feedback", "load_acc", "saturate_enable", "shift_right", "round", "subtract", "acc_fir", "dly_b"};
-const std::vector<std::string> ports2del_mult_add_acc = {"saturate_enable", "shift_right", "round", "acc_fir", "dly_b"};
+const std::vector<std::string> ports2del_mult = {"feedback", "load_acc", "subtract", "acc_fir", "dly_b"};
+const std::vector<std::string> ports2del_mult_add_acc = {"acc_fir", "dly_b"};
+const std::vector<std::string> ports2del_extension = {"saturate_enable", "shift_right", "round"};
void ql_dsp_io_regs_pass(RTLIL::Module *module)
{
for (auto cell : module->cells_) {
std::string cell_type = cell.second->type.str();
- if (cell_type == RTLIL::escape_id("QL_DSP2")) {
+ if (cell_type == RTLIL::escape_id("QL_DSP2") || cell_type == RTLIL::escape_id("QL_DSP3")) {
auto dsp = cell.second;
bool del_clk = false;
+ bool use_dsp_cfg_params = cell_type == RTLIL::escape_id("QL_DSP3");
+
+ int reg_in_i;
+ int out_sel_i;
// Get DSP configuration
- const RTLIL::SigSpec *register_inputs;
- register_inputs = &dsp->getPort(RTLIL::escape_id("register_inputs"));
- if (!register_inputs)
- log_error("register_inputs port not found!");
- auto reg_in_c = register_inputs->as_const();
- int reg_in_i = reg_in_c.as_int();
+ if (use_dsp_cfg_params) {
+ // Read MODE_BITS at correct indexes
+ auto mode_bits = &dsp->getParam(RTLIL::escape_id("MODE_BITS"));
+ RTLIL::Const register_inputs;
+ register_inputs = mode_bits->bits.at(MODE_BITS_REGISTER_INPUTS_ID);
+ reg_in_i = register_inputs.as_int();
- const RTLIL::SigSpec *output_select;
- output_select = &dsp->getPort(RTLIL::escape_id("output_select"));
- if (!output_select)
- log_error("output_select port not found!");
- auto out_sel_c = output_select->as_const();
- int out_sel_i = out_sel_c.as_int();
+ RTLIL::Const output_select;
+ output_select = mode_bits->extract(MODE_BITS_OUTPUT_SELECT_START_ID, MODE_BITS_OUTPUT_SELECT_WIDTH);
+ out_sel_i = output_select.as_int();
+ } else {
+ // Read dedicated configuration ports
+ const RTLIL::SigSpec *register_inputs;
+ register_inputs = &dsp->getPort(RTLIL::escape_id("register_inputs"));
+ if (!register_inputs)
+ log_error("register_inputs port not found!");
+ auto reg_in_c = register_inputs->as_const();
+ reg_in_i = reg_in_c.as_int();
+
+ const RTLIL::SigSpec *output_select;
+ output_select = &dsp->getPort(RTLIL::escape_id("output_select"));
+ if (!output_select)
+ log_error("output_select port not found!");
+ auto out_sel_c = output_select->as_const();
+ out_sel_i = out_sel_c.as_int();
+ }
// Build new type name
std::string new_type = cell_type;
@@ -79,6 +101,11 @@
ports2del.insert(ports2del.end(), ports2del_mult_add_acc.begin(), ports2del_mult_add_acc.end());
}
+ // Mark for deleton additional configuration ports
+ if (!use_dsp_cfg_params) {
+ ports2del.insert(ports2del.end(), ports2del_extension.begin(), ports2del_extension.end());
+ }
+
for (auto portname : ports2del) {
const RTLIL::SigSpec *port = &dsp->getPort(RTLIL::escape_id(portname));
if (!port)
diff --git a/ql-qlf-plugin/ql-dsp-macc.cc b/ql-qlf-plugin/ql-dsp-macc.cc
index 4738634..7f865b5 100644
--- a/ql-qlf-plugin/ql-dsp-macc.cc
+++ b/ql-qlf-plugin/ql-dsp-macc.cc
@@ -8,7 +8,9 @@
// ============================================================================
-void create_ql_macc_dsp(ql_dsp_macc_pm &pm)
+bool use_dsp_cfg_params;
+
+static void create_ql_macc_dsp(ql_dsp_macc_pm &pm)
{
auto &st = pm.st_ql_dsp_macc;
@@ -78,16 +80,21 @@
size_t tgt_b_width;
size_t tgt_z_width;
+ string cell_base_name = "dsp_t1";
+ string cell_size_name = "";
+ string cell_cfg_name = "";
+ string cell_full_name = "";
+
if (min_width <= 2 && max_width <= 2 && z_width <= 4) {
// Too narrow
return;
} else if (min_width <= 9 && max_width <= 10 && z_width <= 19) {
- type = RTLIL::escape_id("dsp_t1_10x9x32");
+ 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) {
- type = RTLIL::escape_id("dsp_t1_20x18x64");
+ cell_size_name = "_20x18x64";
tgt_a_width = 20;
tgt_b_width = 18;
tgt_z_width = 38;
@@ -96,6 +103,14 @@
return;
}
+ if (use_dsp_cfg_params)
+ cell_cfg_name = "_cfg_params";
+ else
+ cell_cfg_name = "_cfg_ports";
+
+ cell_full_name = cell_base_name + cell_size_name + cell_cfg_name;
+
+ type = RTLIL::escape_id(cell_full_name);
log("Inferring MACC %zux%zu->%zu as %s from:\n", a_width, b_width, z_width, RTLIL::unescape_id(type).c_str());
for (auto cell : {st.mul, st.add, st.mux, st.ff}) {
@@ -199,19 +214,26 @@
cell->setPort(RTLIL::escape_id("unsigned_a_i"), RTLIL::SigSpec(a_signed ? RTLIL::S0 : RTLIL::S1));
cell->setPort(RTLIL::escape_id("unsigned_b_i"), RTLIL::SigSpec(b_signed ? RTLIL::S0 : RTLIL::S1));
- // Connect config ports
- cell->setPort(RTLIL::escape_id("saturate_enable_i"), RTLIL::SigSpec(RTLIL::S0));
- cell->setPort(RTLIL::escape_id("shift_right_i"), RTLIL::SigSpec(RTLIL::S0, 6));
- cell->setPort(RTLIL::escape_id("round_i"), RTLIL::SigSpec(RTLIL::S0));
- cell->setPort(RTLIL::escape_id("register_inputs_i"), RTLIL::SigSpec(RTLIL::S0));
+ // Connect config bits
+ if (use_dsp_cfg_params) {
+ cell->setParam(RTLIL::escape_id("SATURATE_ENABLE"), RTLIL::Const(RTLIL::S0));
+ cell->setParam(RTLIL::escape_id("SHIFT_RIGHT"), RTLIL::Const(RTLIL::S0, 6));
+ cell->setParam(RTLIL::escape_id("ROUND"), RTLIL::Const(RTLIL::S0));
+ cell->setParam(RTLIL::escape_id("REGISTER_INPUTS"), RTLIL::Const(RTLIL::S0));
+ // 3 - output post acc; 1 - output pre acc
+ cell->setParam(RTLIL::escape_id("OUTPUT_SELECT"), out_ff ? RTLIL::Const(1, 3) : RTLIL::Const(3, 3));
+ } else {
+ cell->setPort(RTLIL::escape_id("saturate_enable_i"), RTLIL::SigSpec(RTLIL::S0));
+ cell->setPort(RTLIL::escape_id("shift_right_i"), RTLIL::SigSpec(RTLIL::S0, 6));
+ cell->setPort(RTLIL::escape_id("round_i"), RTLIL::SigSpec(RTLIL::S0));
+ cell->setPort(RTLIL::escape_id("register_inputs_i"), RTLIL::SigSpec(RTLIL::S0));
+ // 3 - output post acc; 1 - output pre acc
+ cell->setPort(RTLIL::escape_id("output_select_i"), out_ff ? RTLIL::Const(1, 3) : RTLIL::Const(3, 3));
+ }
bool subtract = (st.add->type == RTLIL::escape_id("$sub"));
cell->setPort(RTLIL::escape_id("subtract_i"), RTLIL::SigSpec(subtract ? RTLIL::S1 : RTLIL::S0));
- // 3 - output post acc
- // 1 - output pre acc
- cell->setPort(RTLIL::escape_id("output_select_i"), out_ff ? RTLIL::Const(1, 3) : RTLIL::Const(3, 3));
-
// Mark the cells for removal
pm.autoremove(st.mul);
pm.autoremove(st.add);
@@ -230,14 +252,25 @@
log("\n");
log(" ql_dsp_macc [options] [selection]\n");
log("\n");
+ log(" -use_dsp_cfg_params\n");
+ log(" By default use DSP blocks with configuration bits available at module ports.\n");
+ log(" Specifying this forces usage of DSP block with configuration bits available as module parameters\n");
+ log("\n");
}
+ void clear_flags() override { use_dsp_cfg_params = false; }
+
void execute(std::vector<std::string> a_Args, RTLIL::Design *a_Design) override
{
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] == "-use_dsp_cfg_params") {
+ use_dsp_cfg_params = true;
+ continue;
+ }
+
break;
}
extra_args(a_Args, argidx, a_Design);
@@ -246,6 +279,7 @@
ql_dsp_macc_pm(module, module->selected_cells()).run_ql_dsp_macc(create_ql_macc_dsp);
}
}
+
} QlDspMacc;
PRIVATE_NAMESPACE_END
diff --git a/ql-qlf-plugin/ql-dsp-simd.cc b/ql-qlf-plugin/ql-dsp-simd.cc
index edf432a..b2935a9 100644
--- a/ql-qlf-plugin/ql-dsp-simd.cc
+++ b/ql-qlf-plugin/ql-dsp-simd.cc
@@ -24,6 +24,9 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
+#define MODE_BITS_BASE_SIZE 80
+#define MODE_BITS_EXTENSION_SIZE 13
+
// ============================================================================
struct QlDspSimdPass : public Pass {
@@ -48,6 +51,9 @@
// Port connections
dict<RTLIL::IdString, RTLIL::SigSpec> connections;
+ // Whether DSPs pass configuration bits through ports of parameters
+ bool use_cfg_params;
+
// TODO: Possibly include parameters here. For now we have just
// connections.
@@ -58,7 +64,7 @@
unsigned int hash() const { return connections.hash(); }
- bool operator==(const DspConfig &ref) const { return connections == ref.connections; }
+ bool operator==(const DspConfig &ref) const { return connections == ref.connections && use_cfg_params == ref.use_cfg_params; }
};
// ..........................................
@@ -73,12 +79,14 @@
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")};
+ std::make_pair("subtract_i", "subtract")};
+ // For QL_DSP2 expand with configuration ports
+ const std::vector<std::pair<std::string, std::string>> m_DspCfgPorts_expand = {
+ 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("register_inputs_i", "register_inputs")};
+
+ // For QL_DSP3 use parameters instead
+ const std::vector<std::string> m_DspParams2Mode = {"OUTPUT_SELECT", "SATURATE_ENABLE", "SHIFT_RIGHT", "ROUND", "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 = {
@@ -91,8 +99,12 @@
// Source DSP cell type (SISD)
const std::string m_SisdDspType = "dsp_t1_10x9x32";
- // Target DSP cell type for the SIMD mode
- const std::string m_SimdDspType = "QL_DSP2";
+ // Suffix for DSP cell with configuration parameters
+ const std::string m_SisdDspType_cfg_params_suffix = "_cfg_params";
+
+ // Target DSP cell types for the SIMD mode
+ const std::string m_SimdDspType_cfg_ports = "QL_DSP2";
+ const std::string m_SimdDspType_cfg_params = "QL_DSP3";
/// Temporary SigBit to SigBit helper map.
SigMap m_SigMap;
@@ -117,8 +129,8 @@
dict<DspConfig, std::vector<RTLIL::Cell *>> groups;
for (auto cell : module->selected_cells()) {
- // Check if this is a DSP cell
- if (cell->type != RTLIL::escape_id(m_SisdDspType)) {
+ // Check if this is a DSP cell we are looking for (type starts with m_SisdDspType)
+ if (strncmp(cell->type.c_str(), RTLIL::escape_id(m_SisdDspType).c_str(), RTLIL::escape_id(m_SisdDspType).size()) != 0) {
continue;
}
@@ -139,6 +151,7 @@
const auto &group = it.second;
const auto &config = it.first;
+ bool use_cfg_params = config.use_cfg_params;
// Ensure an even number
size_t count = group.size();
if (count & 1)
@@ -150,22 +163,32 @@
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());
+ std::string SimdDspType;
+
+ if (use_cfg_params)
+ SimdDspType = m_SimdDspType_cfg_params;
+ else
+ SimdDspType = m_SimdDspType_cfg_ports;
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(),
- m_SimdDspType.c_str());
+ SimdDspType.c_str());
// Create the new cell
- RTLIL::Cell *simd = module->addCell(RTLIL::escape_id(name), RTLIL::escape_id(m_SimdDspType));
+ RTLIL::Cell *simd = module->addCell(RTLIL::escape_id(name), RTLIL::escape_id(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!", m_SimdDspType.c_str());
+ log_error(" The target cell type '%s' is not known!", SimdDspType.c_str());
}
+ std::vector<std::pair<std::string, std::string>> DspCfgPorts = m_DspCfgPorts;
+ if (!use_cfg_params)
+ DspCfgPorts.insert(DspCfgPorts.end(), m_DspCfgPorts_expand.begin(), m_DspCfgPorts_expand.end());
+
// Connect common ports
- for (const auto &it : m_DspCfgPorts) {
+ for (const auto &it : DspCfgPorts) {
auto sport = RTLIL::escape_id(it.first);
auto dport = RTLIL::escape_id(it.second);
@@ -216,12 +239,27 @@
mode_bits.insert(mode_bits.end(), val_a.begin(), val_a.end());
mode_bits.insert(mode_bits.end(), val_b.begin(), val_b.end());
}
+ long unsigned int mode_bits_size = MODE_BITS_BASE_SIZE;
+ if (use_cfg_params) {
+ // Add additional config parameters if necessary
+ mode_bits.push_back(RTLIL::S1); // MODE_BITS[80] == F_MODE : Enable fractured mode
+ for (const auto &it : m_DspParams2Mode) {
+ log_assert(dsp_a->getParam(RTLIL::escape_id(it)) == dsp_b->getParam(RTLIL::escape_id(it)));
+ auto param = dsp_a->getParam(RTLIL::escape_id(it));
+ if (param.size() > 1) {
+ mode_bits.insert(mode_bits.end(), param.bits.begin(), param.bits.end());
+ } else {
+ mode_bits.push_back(param.bits[0]);
+ }
+ }
+ mode_bits_size += MODE_BITS_EXTENSION_SIZE;
+ } else {
+ // Enable the fractured mode by connecting the control
+ // port.
+ simd->setPort(RTLIL::escape_id("f_mode"), RTLIL::S1);
+ }
simd->setParam(RTLIL::escape_id("MODE_BITS"), RTLIL::Const(mode_bits));
- log_assert(mode_bits.size() == 80);
-
- // Enable the fractured mode by connecting the control
- // port.
- simd->setPort(RTLIL::escape_id("f_mode"), RTLIL::S1);
+ log_assert(mode_bits.size() == mode_bits_size);
// Mark DSP parts for removal
cellsToRemove.push_back(dsp_a);
@@ -270,7 +308,18 @@
{
DspConfig config;
- for (const auto &it : m_DspCfgPorts) {
+ string cell_type = a_Cell->type.str();
+ string suffix = m_SisdDspType_cfg_params_suffix;
+
+ bool use_cfg_params = cell_type.size() >= suffix.size() && 0 == cell_type.compare(cell_type.size() - suffix.size(), suffix.size(), suffix);
+
+ std::vector<std::pair<std::string, std::string>> DspCfgPorts = m_DspCfgPorts;
+ if (!use_cfg_params)
+ DspCfgPorts.insert(DspCfgPorts.end(), m_DspCfgPorts_expand.begin(), m_DspCfgPorts_expand.end());
+
+ config.use_cfg_params = use_cfg_params;
+
+ for (const auto &it : DspCfgPorts) {
auto port = RTLIL::escape_id(it.first);
// Port unconnected
diff --git a/ql-qlf-plugin/synth_quicklogic.cc b/ql-qlf-plugin/synth_quicklogic.cc
index 303b1de..5be10ec 100644
--- a/ql-qlf-plugin/synth_quicklogic.cc
+++ b/ql-qlf-plugin/synth_quicklogic.cc
@@ -73,6 +73,10 @@
log(" By default use DSP blocks in output netlist.\n");
log(" do not use DSP blocks to implement multipliers and associated logic\n");
log("\n");
+ log(" -use_dsp_cfg_params\n");
+ log(" By default use DSP blocks with configuration bits available at module ports.\n");
+ log(" Specifying this forces usage of DSP block with configuration bits available as module parameters\n");
+ log("\n");
log(" -no_adder\n");
log(" By default use adder cells in output netlist.\n");
log(" Specifying this switch turns it off.\n");
@@ -95,7 +99,7 @@
log("\n");
}
- string top_opt, edif_file, blif_file, family, currmodule, verilog_file;
+ string top_opt, edif_file, blif_file, family, currmodule, verilog_file, use_dsp_cfg_params;
bool nodsp;
bool inferAdder;
bool inferBram;
@@ -119,6 +123,7 @@
noffmap = false;
nodsp = false;
nosdff = false;
+ use_dsp_cfg_params = "";
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
@@ -164,6 +169,10 @@
nodsp = true;
continue;
}
+ if (args[argidx] == "-use_dsp_cfg_params") {
+ use_dsp_cfg_params = " -use_dsp_cfg_params";
+ continue;
+ }
if (args[argidx] == "-no_adder") {
inferAdder = false;
continue;
@@ -223,8 +232,13 @@
void script() override
{
if (check_label("begin")) {
+ std::string family_path = " +/quicklogic/" + family;
std::string readVelArgs;
- readVelArgs = " +/quicklogic/" + family + "/cells_sim.v";
+
+ // Read simulation library
+ readVelArgs = family_path + "/cells_sim.v";
+ if (family == "qlf_k6n10f")
+ readVelArgs += family_path + "/dsp_sim.v";
// Use -nomem2reg here to prevent Yosys from complaining about
// some block ram cell models. After all the only part of the cells
@@ -295,18 +309,22 @@
};
if (help_mode) {
- run("wreduce t:$mul", " (for qlf_k6n10f if not -no_dsp)");
- run("ql_dsp_macc", " (for qlf_k6n10f if not -no_dsp)");
- 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("wreduce t:$mul", " (for qlf_k6n10f if not -no_dsp)");
+ run("ql_dsp_macc" + use_dsp_cfg_params, "(for qlf_k6n10f if not -no_dsp)");
+ 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)");
+ if (use_dsp_cfg_params == "")
+ run("techmap -map +/quicklogic/" + family + "/dsp_map.v -D USE_DSP_CFG_PARAMS=0", "(for qlf_k6n10f if not -no_dsp)");
+ else
+ run("techmap -map +/quicklogic/" + family + "/dsp_map.v -D USE_DSP_CFG_PARAMS=1", "(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)");
run("ql_dsp_io_regs");
} else if (!nodsp) {
run("wreduce t:$mul");
- run("ql_dsp_macc");
+ run("ql_dsp_macc" + use_dsp_cfg_params);
for (const auto &rule : dsp_rules) {
run(stringf("techmap -map +/mul2dsp.v "
@@ -316,7 +334,10 @@
rule.a_maxwidth, rule.b_maxwidth, rule.a_minwidth, rule.b_minwidth, rule.type.c_str()));
run("chtype -set $mul t:$__soft_mul");
}
- run("techmap -map +/quicklogic/" + family + "/dsp_map.v");
+ if (use_dsp_cfg_params == "")
+ run("techmap -map +/quicklogic/" + family + "/dsp_map.v -D USE_DSP_CFG_PARAMS=0");
+ else
+ run("techmap -map +/quicklogic/" + family + "/dsp_map.v -D USE_DSP_CFG_PARAMS=1");
run("ql_dsp_simd");
run("techmap -map +/quicklogic/" + family + "/dsp_final_map.v");
run("ql_dsp_io_regs");