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); }