Skip to content

Commit c6e8fb2

Browse files
committed
optbarriers: add command to add/remove optimization barriers
* This can optionally ignore rewriting the outputs of cells or processes * This by default rewrites drivers of wires with public names but can also optionally rewrite drivers of wires with private names * A -remove flag allows cleaning up the design by replacing barriers with connections
1 parent c352f71 commit c6e8fb2

File tree

2 files changed

+229
-0
lines changed

2 files changed

+229
-0
lines changed

passes/cmds/Makefile.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,4 @@ OBJS += passes/cmds/future.o
5151
OBJS += passes/cmds/box_derive.o
5252
OBJS += passes/cmds/example_dt.o
5353
OBJS += passes/cmds/portarcs.o
54+
OBJS += passes/cmds/optbarriers.o

passes/cmds/optbarriers.cc

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
/*
2+
* yosys -- Yosys Open SYnthesis Suite
3+
*
4+
* Copyright (C) 2024 George Rennie <[email protected]>
5+
*
6+
* Permission to use, copy, modify, and/or distribute this software for any
7+
* purpose with or without fee is hereby granted, provided that the above
8+
* copyright notice and this permission notice appear in all copies.
9+
*
10+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11+
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12+
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13+
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14+
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15+
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16+
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17+
*
18+
*/
19+
20+
#include "kernel/yosys.h"
21+
#include "kernel/sigtools.h"
22+
23+
USING_YOSYS_NAMESPACE
24+
PRIVATE_NAMESPACE_BEGIN
25+
26+
// Standard visitor helper
27+
template<class... Ts>
28+
struct overloaded : Ts... { using Ts::operator()...; };
29+
template<class... Ts>
30+
overloaded(Ts...) -> overloaded<Ts...>;
31+
32+
struct OptBarriersPass : public Pass {
33+
OptBarriersPass() : Pass("optbarriers", "insert optimization barriers") {}
34+
35+
void help() override {
36+
log("\n");
37+
log(" optbarriers [options] [selection]\n");
38+
log("\n");
39+
log("Insert optimization barriers to drivers of selected public wires.\n");
40+
log("\n");
41+
log("\n");
42+
log(" -nocells\n");
43+
log(" don't add optimization barriers to the outputs of cells\n");
44+
log("\n");
45+
log(" -noprocs\n");
46+
log(" don't add optimization barriers to the outputs of processes\n");
47+
log("\n");
48+
log(" -private\n");
49+
log(" also add optimization barriers to private wires\n");
50+
log("\n");
51+
log(" -remove\n");
52+
log(" replace selected optimization barriers with connections\n");
53+
log("\n");
54+
}
55+
56+
void execute(std::vector<std::string> args, RTLIL::Design *design) override {
57+
log_header(design, "Executing OPTBARRIERS pass (insert optimization barriers).\n");
58+
59+
bool nocells_mode = false;
60+
bool noprocs_mode = false;
61+
bool private_mode = false;
62+
bool remove_mode = false;
63+
64+
size_t argidx;
65+
for (argidx = 1; argidx < args.size(); argidx++) {
66+
std::string arg = args[argidx];
67+
if (arg == "-nocells") {
68+
nocells_mode = true;
69+
continue;
70+
}
71+
if (arg == "-noprocs") {
72+
noprocs_mode = true;
73+
continue;
74+
}
75+
if (arg == "-private") {
76+
private_mode = true;
77+
continue;
78+
}
79+
if (arg == "-remove") {
80+
remove_mode = true;
81+
continue;
82+
}
83+
break;
84+
}
85+
extra_args(args, argidx, design);
86+
87+
if (remove_mode) {
88+
log("Replacing optimization barriers with connections.\n");
89+
remove_barriers(design);
90+
return;
91+
}
92+
93+
for (auto* module : design->selected_modules()) {
94+
// We can't just sigmap and iterate through wires for rewriting as
95+
// we want to maintain the structure in connections, and sigmap
96+
// will just return a canonical wire which does not have to be one
97+
// that is directly driving the wire. Therefore for each type of
98+
// object that could be driving the wires (cells, processes,
99+
// connections) we rewrite the sigspecs.
100+
101+
// Keep track of which wires we have allocated new wires for
102+
dict<RTLIL::Wire*, RTLIL::Wire*> new_wires;
103+
// Keep track of bit pairs we need to construct barriers for from
104+
// Y to A
105+
dict<RTLIL::SigBit, RTLIL::SigBit> new_barriers;
106+
107+
// Skip constants, unselected wires and private wires when not in
108+
// private mode. This works for SigChunk or SigBit input.
109+
const auto skip = [&](const auto& chunk) {
110+
if (!chunk.is_wire())
111+
return true;
112+
113+
if (!design->selected(module, chunk.wire))
114+
return true;
115+
116+
if (!private_mode && !chunk.wire->name.isPublic())
117+
return true;
118+
119+
return false;
120+
};
121+
122+
const auto rewrite_sigspec = [&](const SigSpec& sig) {
123+
RTLIL::SigSpec new_output;
124+
for (const auto& chunk : sig.chunks()) {
125+
if (skip(chunk)) {
126+
new_output.append(chunk);
127+
continue;
128+
}
129+
130+
// Add a wire to drive if one does not already exist
131+
auto* new_wire = new_wires.at(chunk.wire, nullptr);
132+
if (!new_wire) {
133+
new_wire = module->addWire(NEW_ID, GetSize(chunk.wire));
134+
new_wires.emplace(chunk.wire, new_wire);
135+
}
136+
137+
RTLIL::SigChunk new_chunk = chunk;
138+
new_chunk.wire = new_wire;
139+
140+
// Rewrite output to drive new wire, and schedule adding
141+
// barrier bits from new wire to original
142+
new_output.append(new_chunk);
143+
for (int i = 0; i < GetSize(chunk); i++)
144+
new_barriers.emplace(chunk[i], new_chunk[i]);
145+
}
146+
147+
return new_output;
148+
};
149+
150+
// Rewrite cell outputs
151+
if (!nocells_mode)
152+
for (auto* cell : module->cells())
153+
if (cell->type != ID($barrier))
154+
for (const auto& [name, sig] : cell->connections())
155+
if (cell->output(name))
156+
cell->setPort(name, rewrite_sigspec(sig));
157+
158+
// Rewrite connections in processes
159+
if (!noprocs_mode) {
160+
const auto proc_rewriter = overloaded{
161+
// Don't do anything for input sigspecs
162+
[&](const SigSpec&) {},
163+
// Rewrite connections to drive barrier if needed
164+
[&](SigSpec& lhs, const SigSpec&) {
165+
lhs = rewrite_sigspec(lhs);
166+
}
167+
};
168+
169+
for (auto& proc : module->processes)
170+
proc.second->rewrite_sigspecs2(proc_rewriter);
171+
}
172+
173+
// Add all the scheduled barriers. To minimize the number of cells,
174+
// first construct a sigspec of all bits, then sort and unify before
175+
// creating barriers
176+
SigSpec barrier_y;
177+
for (const auto&[y_bit, _] : new_barriers)
178+
barrier_y.append(y_bit);
179+
barrier_y.sort_and_unify();
180+
181+
for (const auto& sig_y : barrier_y.chunks()) {
182+
log_assert(sig_y.is_wire());
183+
SigSpec sig_a;
184+
for (int i = 0; i < GetSize(sig_y); i++)
185+
sig_a.append(new_barriers[sig_y[i]]);
186+
module->addBarrier(NEW_ID, sig_a, sig_y);
187+
}
188+
189+
// Rewrite connections
190+
std::vector<RTLIL::SigSig> new_connections;
191+
for (const auto& conn : module->connections()) {
192+
RTLIL::SigSig skip_conn, barrier_conn;
193+
194+
for (int i = 0; i < GetSize(conn.first); i++) {
195+
auto& sigsig = skip(conn.first[i]) ? skip_conn : barrier_conn;
196+
sigsig.first.append(conn.first[i]);
197+
sigsig.second.append(conn.second[i]);
198+
}
199+
200+
if (!skip_conn.first.empty())
201+
new_connections.emplace_back(std::move(skip_conn));
202+
203+
if (!barrier_conn.first.empty())
204+
module->addBarrier(NEW_ID, barrier_conn.second, barrier_conn.first);
205+
}
206+
module->new_connections(new_connections);
207+
}
208+
}
209+
210+
void remove_barriers(RTLIL::Design* design) {
211+
for (auto* module : design->selected_modules()) {
212+
std::vector<RTLIL::Cell*> barriers;
213+
214+
for (auto* cell : module->selected_cells())
215+
if (cell->type == ID($barrier))
216+
barriers.emplace_back(cell);
217+
218+
for (auto* cell : barriers) {
219+
const auto lhs = cell->getPort(ID::Y), rhs = cell->getPort(ID::A);
220+
module->connect(lhs, rhs);
221+
module->remove(cell);
222+
}
223+
}
224+
}
225+
226+
} OptBarriersPass;
227+
228+
PRIVATE_NAMESPACE_END

0 commit comments

Comments
 (0)