diff --git a/techlibs/quicklogic/Makefile.inc b/techlibs/quicklogic/Makefile.inc index ade1443713c..a54a7ec0324 100644 --- a/techlibs/quicklogic/Makefile.inc +++ b/techlibs/quicklogic/Makefile.inc @@ -6,6 +6,7 @@ OBJS += techlibs/quicklogic/ql_bram_merge.o OBJS += techlibs/quicklogic/ql_bram_types.o OBJS += techlibs/quicklogic/ql_dsp_simd.o OBJS += techlibs/quicklogic/ql_dsp_io_regs.o +OBJS += techlibs/quicklogic/ql_ioff.o # -------------------------------------- @@ -40,4 +41,4 @@ $(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/dsp_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)) \ No newline at end of file +$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/sram1024x18_mem.v)) diff --git a/techlibs/quicklogic/ql_ioff.cc b/techlibs/quicklogic/ql_ioff.cc new file mode 100644 index 00000000000..96d0f7c431c --- /dev/null +++ b/techlibs/quicklogic/ql_ioff.cc @@ -0,0 +1,71 @@ +#include "kernel/log.h" +#include "kernel/modtools.h" +#include "kernel/register.h" +#include "kernel/rtlil.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct QlIoffPass : public Pass { + QlIoffPass() : Pass("ql_ioff", "Infer I/O FFs for qlf_k6n10f architecture") {} + + void execute(std::vector, RTLIL::Design *design) override + { + log_header(design, "Executing QL_IOFF pass.\n"); + + ModWalker modwalker(design); + Module *module = design->top_module(); + if (!module) + return; + modwalker.setup(module); + pool cells_to_replace; + for (auto cell : module->selected_cells()) { + if (cell->type.in(ID(dffsre), ID(sdffsre))) { + bool e_const = cell->getPort(ID::E).is_fully_const(); + bool r_const = cell->getPort(ID::R).is_fully_const(); + bool s_const = cell->getPort(ID::S).is_fully_const(); + + if (!(e_const && r_const && s_const)) + continue; + + auto d_sig = modwalker.sigmap(cell->getPort(ID::D)); + if (d_sig.is_wire() && d_sig.as_wire()->port_input) { + log_debug("Cell %s is potentially eligible for promotion to input IOFF.\n", cell->name.c_str()); + // check that d_sig has no other consumers + if (GetSize(d_sig) != 1) continue; + pool portbits; + modwalker.get_consumers(portbits, d_sig[0]); + if (GetSize(portbits) > 1) { + log_debug("not promoting: d_sig has other consumers\n"); + continue; + } + cells_to_replace.insert(cell); + continue; // no need to check Q if we already put it on the list + } + auto q_sig = modwalker.sigmap(cell->getPort(ID::Q)); + if (q_sig.is_wire() && q_sig.as_wire()->port_output) { + log_debug("Cell %s is potentially eligible for promotion to output IOFF.\n", cell->name.c_str()); + // check that q_sig has no other consumers + if (GetSize(q_sig) != 1) continue; + pool portbits; + modwalker.get_consumers(portbits, q_sig[0]); + if (GetSize(portbits) > 0) { + log_debug("not promoting: q_sig has other consumers\n"); + continue; + } + cells_to_replace.insert(cell); + } + } + } + + for (auto cell : cells_to_replace) { + log("Promoting register %s to IOFF.\n", log_signal(cell->getPort(ID::Q))); + cell->type = ID(dff); + cell->unsetPort(ID::E); + cell->unsetPort(ID::R); + cell->unsetPort(ID::S); + } + } +} QlIoffPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/quicklogic/synth_quicklogic.cc b/techlibs/quicklogic/synth_quicklogic.cc index 76ef4457069..40cd75eb921 100644 --- a/techlibs/quicklogic/synth_quicklogic.cc +++ b/techlibs/quicklogic/synth_quicklogic.cc @@ -78,7 +78,7 @@ struct SynthQuickLogicPass : public ScriptPass { } string top_opt, blif_file, edif_file, family, currmodule, verilog_file, lib_path; - bool abc9, inferAdder, nobram, bramTypes, dsp; + bool abc9, inferAdder, nobram, bramTypes, dsp, ioff; void clear_flags() override { @@ -94,6 +94,7 @@ struct SynthQuickLogicPass : public ScriptPass { bramTypes = false; lib_path = "+/quicklogic/"; dsp = true; + ioff = true; } void set_scratchpad_defaults(RTLIL::Design *design) { @@ -158,6 +159,10 @@ struct SynthQuickLogicPass : public ScriptPass { dsp = false; continue; } + if (args[argidx] == "-noioff") { + ioff = false; + continue; + } break; } extra_args(args, argidx, design); @@ -298,6 +303,9 @@ struct SynthQuickLogicPass : public ScriptPass { run("techmap -map " + lib_path + family + "/ffs_map.v"); } run("opt"); + if (ioff || help_mode) { + run("ql_ioff", "(unless -noioff)"); + } } if (check_label("map_luts", "(for pp3)") && (help_mode || family == "pp3")) { diff --git a/tests/arch/quicklogic/qlf_k6n10f/ioff.ys b/tests/arch/quicklogic/qlf_k6n10f/ioff.ys new file mode 100644 index 00000000000..bd69a28d400 --- /dev/null +++ b/tests/arch/quicklogic/qlf_k6n10f/ioff.ys @@ -0,0 +1,91 @@ +# test: acceptable for output IOFF promotion +read_verilog <