Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add IOFF inference for qlf_k6n10f #4866

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion techlibs/quicklogic/Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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

# --------------------------------------

Expand Down Expand Up @@ -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))
$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/sram1024x18_mem.v))
125 changes: 125 additions & 0 deletions techlibs/quicklogic/ql_ioff.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#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 help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" ql_ioff [selection]\n");
log("\n");
log("This pass promotes qlf_k6n10f registers directly connected to a top-level I/O\n");
log("port to I/O FFs.\n");
log("\n");
}

void execute(std::vector<std::string>, 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<RTLIL::Cell *> input_ffs;
dict<RTLIL::Wire *, std::vector<Cell*>> output_ffs;
dict<SigBit, pool<SigBit>> output_bit_aliases;

for (Wire* wire : module->wires())
if (wire->port_output) {
output_ffs[wire].resize(wire->width, nullptr);
for (SigBit bit : SigSpec(wire))
output_bit_aliases[modwalker.sigmap(bit)].insert(bit);
}

for (auto cell : module->selected_cells()) {
if (cell->type.in(ID(dffsre), ID(sdffsre))) {
log_debug("Checking cell %s.\n", cell->name.c_str());
bool e_const = cell->getPort(ID::E).is_fully_ones();
bool r_const = cell->getPort(ID::R).is_fully_ones();
bool s_const = cell->getPort(ID::S).is_fully_ones();

if (!(e_const && r_const && s_const)) {
log_debug("not promoting: E, R, or S is used\n");
continue;
}

SigSpec d = cell->getPort(ID::D);
log_assert(GetSize(d) == 1);
if (modwalker.has_inputs(d)) {
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
pool<ModWalker::PortBit> portbits;
modwalker.get_consumers(portbits, d);
if (GetSize(portbits) > 1) {
log_debug("not promoting: D has other consumers\n");
continue;
}
input_ffs.insert(cell);
continue; // prefer input FFs over output FFs
}

SigSpec q = cell->getPort(ID::Q);
log_assert(GetSize(q) == 1);
if (modwalker.has_outputs(q) && !modwalker.has_consumers(q)) {
log_debug("Cell %s is potentially eligible for promotion to output IOFF.\n", cell->name.c_str());
for (SigBit bit : output_bit_aliases[modwalker.sigmap(q)]) {
log_assert(bit.is_wire());
output_ffs[bit.wire][bit.offset] = cell;
}

}
}
}

for (auto cell : input_ffs) {
log("Promoting register %s to input IOFF.\n", log_signal(cell->getPort(ID::Q)));
cell->type = ID(dff);
cell->unsetPort(ID::E);
cell->unsetPort(ID::R);
cell->unsetPort(ID::S);
}
for (auto & [old_port_output, ioff_cells] : output_ffs) {
if (std::any_of(ioff_cells.begin(), ioff_cells.end(), [](Cell * c) { return c != nullptr; }))
{
// create replacement output wire
RTLIL::Wire* new_port_output = module->addWire(NEW_ID, old_port_output->width);
new_port_output->start_offset = old_port_output->start_offset;
module->swap_names(old_port_output, new_port_output);
std::swap(old_port_output->port_id, new_port_output->port_id);
std::swap(old_port_output->port_input, new_port_output->port_input);
std::swap(old_port_output->port_output, new_port_output->port_output);
std::swap(old_port_output->upto, new_port_output->upto);
std::swap(old_port_output->is_signed, new_port_output->is_signed);
std::swap(old_port_output->attributes, new_port_output->attributes);

// create new output FFs
SigSpec sig_o(old_port_output);
SigSpec sig_n(new_port_output);
for (int i = 0; i < new_port_output->width; i++) {
if (ioff_cells[i]) {
log("Promoting %s to output IOFF.\n", log_signal(sig_n[i]));

RTLIL::Cell *new_cell = module->addCell(NEW_ID, ID(dff));
new_cell->setPort(ID::C, ioff_cells[i]->getPort(ID::C));
new_cell->setPort(ID::D, ioff_cells[i]->getPort(ID::D));
new_cell->setPort(ID::Q, sig_n[i]);
new_cell->set_bool_attribute(ID::keep);
} else {
module->connect(sig_n[i], sig_o[i]);
}
}
}
}
}
} QlIoffPass;

PRIVATE_NAMESPACE_END
14 changes: 13 additions & 1 deletion techlibs/quicklogic/synth_quicklogic.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -94,6 +94,7 @@ struct SynthQuickLogicPass : public ScriptPass {
bramTypes = false;
lib_path = "+/quicklogic/";
dsp = true;
ioff = true;
}

void set_scratchpad_defaults(RTLIL::Design *design) {
Expand Down Expand Up @@ -158,6 +159,10 @@ struct SynthQuickLogicPass : public ScriptPass {
dsp = false;
continue;
}
if (args[argidx] == "-noioff") {
ioff = false;
continue;
}
break;
}
extra_args(args, argidx, design);
Expand Down Expand Up @@ -328,6 +333,13 @@ struct SynthQuickLogicPass : public ScriptPass {
run("clean");
run("opt_lut");
}

if (check_label("iomap", "(for qlf_k6n10f, skip if -noioff)") && (family == "qlf_k6n10f" || help_mode)) {
if (ioff || help_mode) {
run("ql_ioff");
run("opt_clean");
}
}

if (check_label("check")) {
run("autoname");
Expand Down
2 changes: 1 addition & 1 deletion tests/arch/quicklogic/qlf_k6n10f/counter.ys
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ read_verilog ../../common/counter.v
hierarchy -top top
proc
flatten
equiv_opt -assert -multiclock -map +/quicklogic/qlf_k6n10f/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic -family qlf_k6n10f # equivalency check
equiv_opt -assert -multiclock -map +/quicklogic/qlf_k6n10f/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic -family qlf_k6n10f -noioff # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module
select -assert-count 4 t:$lut
Expand Down
4 changes: 2 additions & 2 deletions tests/arch/quicklogic/qlf_k6n10f/dffs.ys
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ design -save read

hierarchy -top my_dff
proc
equiv_opt -async2sync -assert -map +/quicklogic/qlf_k6n10f/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic -family qlf_k6n10f # equivalency check
equiv_opt -async2sync -assert -map +/quicklogic/qlf_k6n10f/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic -family qlf_k6n10f -noioff # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd my_dff # Constrain all select calls below inside the top module
select -assert-count 1 t:sdffsre
Expand All @@ -14,7 +14,7 @@ select -assert-none t:sdffsre %% t:* %D
design -load read
hierarchy -top my_dffe
proc
equiv_opt -async2sync -assert -map +/quicklogic/qlf_k6n10f/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic -family qlf_k6n10f # equivalency check
equiv_opt -async2sync -assert -map +/quicklogic/qlf_k6n10f/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic -family qlf_k6n10f -noioff # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd my_dffe # Constrain all select calls below inside the top module
select -assert-count 1 t:sdffsre
Expand Down
Loading
Loading