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

added flipflop enable control in synthesis #27

Open
wants to merge 4 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
2 changes: 1 addition & 1 deletion ql-qlf-plugin/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ SOURCES = synth_quicklogic.cc \
pp3_braminit.cc \
quicklogic_eqn.cc \
ql-edif.cc \
ql_ioff.cc \
ql-dsp-simd.cc \
ql-dsp-macc.cc \
ql-bram-split.cc \
Expand Down Expand Up @@ -65,7 +66,6 @@ VERILOG_MODULES = $(COMMON)/cells_sim.v \
$(QLF_K6N10F_DIR)/TDP18K_FIFO.v \
$(QLF_K6N10F_DIR)/ufifo_ctl.v \
$(QLF_K6N10F_DIR)/ffs_map.v \
$(QLF_K6N10F_DIR)/ffs_map_noaset.v \
$(QLF_K6N10F_DIR)/dsp_map.v \
$(QLF_K6N10F_DIR)/dsp_final_map.v \
$(QLF_K6N10F_DIR)/libmap_brams_map_tdp.v \
Expand Down
133 changes: 133 additions & 0 deletions ql-qlf-plugin/ql_ioff.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#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(dffre), ID(sdffre), ID(dffnre), ID(sdffnre))) {
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();

if (!(e_const && r_const)) {
log_debug("not promoting: E or R 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)));
if (cell->type.in(ID(dffre), ID(sdffre))) {
cell->type = ID(dff);
}
else if (cell->type.in(ID(dffnre), ID(sdffnre))) {
cell->type = ID(dffn);
}
cell->unsetPort(ID::E);
cell->unsetPort(ID::R);
}
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]) {
RTLIL::Cell *new_cell;
log("Promoting %s to output IOFF.\n", log_signal(sig_n[i]));
if (ioff_cells[i]->type.in(ID(dffre), ID(sdffre))) {
new_cell = module->addCell(NEW_ID, ID(dff));
}
else if (ioff_cells[i]->type.in(ID(dffnre), ID(sdffnre))) {
new_cell = module->addCell(NEW_ID, ID(dffn));
}
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
Loading