Skip to content

Commit 268a034

Browse files
Merge pull request #4866 from YosysHQ/ql_ioff
add IOFF inference for qlf_k6n10f
2 parents 9106d6b + 303a386 commit 268a034

File tree

6 files changed

+352
-5
lines changed

6 files changed

+352
-5
lines changed

techlibs/quicklogic/Makefile.inc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ OBJS += techlibs/quicklogic/ql_bram_merge.o
66
OBJS += techlibs/quicklogic/ql_bram_types.o
77
OBJS += techlibs/quicklogic/ql_dsp_simd.o
88
OBJS += techlibs/quicklogic/ql_dsp_io_regs.o
9+
OBJS += techlibs/quicklogic/ql_ioff.o
910

1011
# --------------------------------------
1112

@@ -40,4 +41,4 @@ $(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf
4041
$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/dsp_final_map.v))
4142
$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/TDP18K_FIFO.v))
4243
$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/ufifo_ctl.v))
43-
$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/sram1024x18_mem.v))
44+
$(eval $(call add_share_file,share/quicklogic/qlf_k6n10f,techlibs/quicklogic/qlf_k6n10f/sram1024x18_mem.v))

techlibs/quicklogic/ql_ioff.cc

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#include "kernel/log.h"
2+
#include "kernel/modtools.h"
3+
#include "kernel/register.h"
4+
#include "kernel/rtlil.h"
5+
6+
USING_YOSYS_NAMESPACE
7+
PRIVATE_NAMESPACE_BEGIN
8+
9+
struct QlIoffPass : public Pass {
10+
QlIoffPass() : Pass("ql_ioff", "Infer I/O FFs for qlf_k6n10f architecture") {}
11+
12+
void help() override
13+
{
14+
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
15+
log("\n");
16+
log(" ql_ioff [selection]\n");
17+
log("\n");
18+
log("This pass promotes qlf_k6n10f registers directly connected to a top-level I/O\n");
19+
log("port to I/O FFs.\n");
20+
log("\n");
21+
}
22+
23+
void execute(std::vector<std::string>, RTLIL::Design *design) override
24+
{
25+
log_header(design, "Executing QL_IOFF pass.\n");
26+
27+
ModWalker modwalker(design);
28+
Module *module = design->top_module();
29+
if (!module)
30+
return;
31+
modwalker.setup(module);
32+
pool<RTLIL::Cell *> input_ffs;
33+
dict<RTLIL::Wire *, std::vector<Cell*>> output_ffs;
34+
dict<SigBit, pool<SigBit>> output_bit_aliases;
35+
36+
for (Wire* wire : module->wires())
37+
if (wire->port_output) {
38+
output_ffs[wire].resize(wire->width, nullptr);
39+
for (SigBit bit : SigSpec(wire))
40+
output_bit_aliases[modwalker.sigmap(bit)].insert(bit);
41+
}
42+
43+
for (auto cell : module->selected_cells()) {
44+
if (cell->type.in(ID(dffsre), ID(sdffsre))) {
45+
log_debug("Checking cell %s.\n", cell->name.c_str());
46+
bool e_const = cell->getPort(ID::E).is_fully_ones();
47+
bool r_const = cell->getPort(ID::R).is_fully_ones();
48+
bool s_const = cell->getPort(ID::S).is_fully_ones();
49+
50+
if (!(e_const && r_const && s_const)) {
51+
log_debug("not promoting: E, R, or S is used\n");
52+
continue;
53+
}
54+
55+
SigSpec d = cell->getPort(ID::D);
56+
log_assert(GetSize(d) == 1);
57+
if (modwalker.has_inputs(d)) {
58+
log_debug("Cell %s is potentially eligible for promotion to input IOFF.\n", cell->name.c_str());
59+
// check that d_sig has no other consumers
60+
pool<ModWalker::PortBit> portbits;
61+
modwalker.get_consumers(portbits, d);
62+
if (GetSize(portbits) > 1) {
63+
log_debug("not promoting: D has other consumers\n");
64+
continue;
65+
}
66+
input_ffs.insert(cell);
67+
continue; // prefer input FFs over output FFs
68+
}
69+
70+
SigSpec q = cell->getPort(ID::Q);
71+
log_assert(GetSize(q) == 1);
72+
if (modwalker.has_outputs(q) && !modwalker.has_consumers(q)) {
73+
log_debug("Cell %s is potentially eligible for promotion to output IOFF.\n", cell->name.c_str());
74+
for (SigBit bit : output_bit_aliases[modwalker.sigmap(q)]) {
75+
log_assert(bit.is_wire());
76+
output_ffs[bit.wire][bit.offset] = cell;
77+
}
78+
79+
}
80+
}
81+
}
82+
83+
for (auto cell : input_ffs) {
84+
log("Promoting register %s to input IOFF.\n", log_signal(cell->getPort(ID::Q)));
85+
cell->type = ID(dff);
86+
cell->unsetPort(ID::E);
87+
cell->unsetPort(ID::R);
88+
cell->unsetPort(ID::S);
89+
}
90+
for (auto & [old_port_output, ioff_cells] : output_ffs) {
91+
if (std::any_of(ioff_cells.begin(), ioff_cells.end(), [](Cell * c) { return c != nullptr; }))
92+
{
93+
// create replacement output wire
94+
RTLIL::Wire* new_port_output = module->addWire(NEW_ID, old_port_output->width);
95+
new_port_output->start_offset = old_port_output->start_offset;
96+
module->swap_names(old_port_output, new_port_output);
97+
std::swap(old_port_output->port_id, new_port_output->port_id);
98+
std::swap(old_port_output->port_input, new_port_output->port_input);
99+
std::swap(old_port_output->port_output, new_port_output->port_output);
100+
std::swap(old_port_output->upto, new_port_output->upto);
101+
std::swap(old_port_output->is_signed, new_port_output->is_signed);
102+
std::swap(old_port_output->attributes, new_port_output->attributes);
103+
104+
// create new output FFs
105+
SigSpec sig_o(old_port_output);
106+
SigSpec sig_n(new_port_output);
107+
for (int i = 0; i < new_port_output->width; i++) {
108+
if (ioff_cells[i]) {
109+
log("Promoting %s to output IOFF.\n", log_signal(sig_n[i]));
110+
111+
RTLIL::Cell *new_cell = module->addCell(NEW_ID, ID(dff));
112+
new_cell->setPort(ID::C, ioff_cells[i]->getPort(ID::C));
113+
new_cell->setPort(ID::D, ioff_cells[i]->getPort(ID::D));
114+
new_cell->setPort(ID::Q, sig_n[i]);
115+
new_cell->set_bool_attribute(ID::keep);
116+
} else {
117+
module->connect(sig_n[i], sig_o[i]);
118+
}
119+
}
120+
}
121+
}
122+
}
123+
} QlIoffPass;
124+
125+
PRIVATE_NAMESPACE_END

techlibs/quicklogic/synth_quicklogic.cc

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ struct SynthQuickLogicPass : public ScriptPass {
7878
}
7979

8080
string top_opt, blif_file, edif_file, family, currmodule, verilog_file, lib_path;
81-
bool abc9, inferAdder, nobram, bramTypes, dsp;
81+
bool abc9, inferAdder, nobram, bramTypes, dsp, ioff;
8282

8383
void clear_flags() override
8484
{
@@ -94,6 +94,7 @@ struct SynthQuickLogicPass : public ScriptPass {
9494
bramTypes = false;
9595
lib_path = "+/quicklogic/";
9696
dsp = true;
97+
ioff = true;
9798
}
9899

99100
void set_scratchpad_defaults(RTLIL::Design *design) {
@@ -158,6 +159,10 @@ struct SynthQuickLogicPass : public ScriptPass {
158159
dsp = false;
159160
continue;
160161
}
162+
if (args[argidx] == "-noioff") {
163+
ioff = false;
164+
continue;
165+
}
161166
break;
162167
}
163168
extra_args(args, argidx, design);
@@ -328,6 +333,13 @@ struct SynthQuickLogicPass : public ScriptPass {
328333
run("clean");
329334
run("opt_lut");
330335
}
336+
337+
if (check_label("iomap", "(for qlf_k6n10f, skip if -noioff)") && (family == "qlf_k6n10f" || help_mode)) {
338+
if (ioff || help_mode) {
339+
run("ql_ioff");
340+
run("opt_clean");
341+
}
342+
}
331343

332344
if (check_label("check")) {
333345
run("autoname");

tests/arch/quicklogic/qlf_k6n10f/counter.ys

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ read_verilog ../../common/counter.v
22
hierarchy -top top
33
proc
44
flatten
5-
equiv_opt -assert -multiclock -map +/quicklogic/qlf_k6n10f/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic -family qlf_k6n10f # equivalency check
5+
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
66
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
77
cd top # Constrain all select calls below inside the top module
88
select -assert-count 4 t:$lut

tests/arch/quicklogic/qlf_k6n10f/dffs.ys

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ design -save read
55

66
hierarchy -top my_dff
77
proc
8-
equiv_opt -async2sync -assert -map +/quicklogic/qlf_k6n10f/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic -family qlf_k6n10f # equivalency check
8+
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
99
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
1010
cd my_dff # Constrain all select calls below inside the top module
1111
select -assert-count 1 t:sdffsre
@@ -14,7 +14,7 @@ select -assert-none t:sdffsre %% t:* %D
1414
design -load read
1515
hierarchy -top my_dffe
1616
proc
17-
equiv_opt -async2sync -assert -map +/quicklogic/qlf_k6n10f/cells_sim.v -map +/quicklogic/common/cells_sim.v synth_quicklogic -family qlf_k6n10f # equivalency check
17+
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
1818
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
1919
cd my_dffe # Constrain all select calls below inside the top module
2020
select -assert-count 1 t:sdffsre

0 commit comments

Comments
 (0)