2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
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.
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.
20 #include "kernel/register.h"
21 #include "kernel/bitpattern.h"
22 #include "kernel/log.h"
28 PRIVATE_NAMESPACE_BEGIN
32 idict
<SigSpec
> sigidx
;
33 dict
<SigBit
, int> bit2snippet
;
36 void insert(SigSpec sig
)
41 int key
= sigidx(sig
);
42 if (snippets
.count(key
))
47 for (int i
= 0; i
< GetSize(sig
); i
++)
49 int other_key
= bit2snippet
.at(sig
[i
], -1);
52 new_sig
.append(sig
[i
]);
56 if (!new_sig
.empty()) {
57 int new_key
= sigidx(new_sig
);
58 snippets
.insert(new_key
);
59 for (auto bit
: new_sig
)
60 bit2snippet
[bit
] = new_key
;
64 SigSpec other_sig
= sigidx
[other_key
];
67 while (other_sig
[k
] != sig
[i
]) {
69 log_assert(k
< GetSize(other_sig
));
72 while (i
+n
< GetSize(sig
) && k
+n
< GetSize(other_sig
) && sig
[i
+n
] == other_sig
[k
+n
])
75 SigSpec sig1
= other_sig
.extract(0, k
);
76 SigSpec sig2
= other_sig
.extract(k
, n
);
77 SigSpec sig3
= other_sig
.extract(k
+n
, GetSize(other_sig
)-k
-n
);
79 for (auto bit
: other_sig
)
80 bit2snippet
.erase(bit
);
81 snippets
.erase(other_key
);
90 if (!new_sig
.empty()) {
91 int new_key
= sigidx(new_sig
);
92 snippets
.insert(new_key
);
93 for (auto bit
: new_sig
)
94 bit2snippet
[bit
] = new_key
;
98 void insert(const RTLIL::CaseRule
*cs
)
100 for (auto &action
: cs
->actions
)
101 insert(action
.first
);
103 for (auto sw
: cs
->switches
)
104 for (auto cs2
: sw
->cases
)
109 struct SnippetSwCache
111 dict
<RTLIL::SwitchRule
*, pool
<RTLIL::SigBit
>, hash_ptr_ops
> full_case_bits_cache
;
112 dict
<RTLIL::SwitchRule
*, pool
<int>, hash_ptr_ops
> cache
;
113 const SigSnippets
*snippets
;
116 bool check(RTLIL::SwitchRule
*sw
)
118 return cache
[sw
].count(current_snippet
) != 0;
121 void insert(const RTLIL::CaseRule
*cs
, vector
<RTLIL::SwitchRule
*> &sw_stack
)
123 for (auto &action
: cs
->actions
)
124 for (auto bit
: action
.first
) {
125 int sn
= snippets
->bit2snippet
.at(bit
, -1);
128 for (auto sw
: sw_stack
)
129 cache
[sw
].insert(sn
);
132 for (auto sw
: cs
->switches
) {
133 sw_stack
.push_back(sw
);
134 for (auto cs2
: sw
->cases
)
135 insert(cs2
, sw_stack
);
140 void insert(const RTLIL::CaseRule
*cs
)
142 vector
<RTLIL::SwitchRule
*> sw_stack
;
143 insert(cs
, sw_stack
);
147 void apply_attrs(RTLIL::Cell
*cell
, const RTLIL::SwitchRule
*sw
, const RTLIL::CaseRule
*cs
)
149 cell
->attributes
= sw
->attributes
;
150 cell
->add_strpool_attribute(ID::src
, cs
->get_strpool_attribute(ID::src
));
153 RTLIL::SigSpec
gen_cmp(RTLIL::Module
*mod
, const RTLIL::SigSpec
&signal
, const std::vector
<RTLIL::SigSpec
> &compare
, RTLIL::SwitchRule
*sw
, RTLIL::CaseRule
*cs
, bool ifxmode
)
155 std::stringstream sstr
;
156 sstr
<< "$procmux$" << (autoidx
++);
158 RTLIL::Wire
*cmp_wire
= mod
->addWire(sstr
.str() + "_CMP", 0);
160 for (auto comp
: compare
)
162 RTLIL::SigSpec sig
= signal
;
164 // get rid of don't-care bits
165 log_assert(sig
.size() == comp
.size());
166 for (int i
= 0; i
< comp
.size(); i
++)
167 if (comp
[i
] == RTLIL::State::Sa
) {
171 if (comp
.size() == 0)
172 return RTLIL::SigSpec();
174 if (sig
.size() == 1 && comp
== RTLIL::SigSpec(1,1) && !ifxmode
)
176 mod
->connect(RTLIL::SigSig(RTLIL::SigSpec(cmp_wire
, cmp_wire
->width
++), sig
));
180 // create compare cell
181 RTLIL::Cell
*eq_cell
= mod
->addCell(stringf("%s_CMP%d", sstr
.str().c_str(), cmp_wire
->width
), ifxmode
? ID($eqx
) : ID($eq
));
182 apply_attrs(eq_cell
, sw
, cs
);
184 eq_cell
->parameters
[ID::A_SIGNED
] = RTLIL::Const(0);
185 eq_cell
->parameters
[ID::B_SIGNED
] = RTLIL::Const(0);
187 eq_cell
->parameters
[ID::A_WIDTH
] = RTLIL::Const(sig
.size());
188 eq_cell
->parameters
[ID::B_WIDTH
] = RTLIL::Const(comp
.size());
189 eq_cell
->parameters
[ID::Y_WIDTH
] = RTLIL::Const(1);
191 eq_cell
->setPort(ID::A
, sig
);
192 eq_cell
->setPort(ID::B
, comp
);
193 eq_cell
->setPort(ID::Y
, RTLIL::SigSpec(cmp_wire
, cmp_wire
->width
++));
197 RTLIL::Wire
*ctrl_wire
;
198 if (cmp_wire
->width
== 1)
200 ctrl_wire
= cmp_wire
;
204 ctrl_wire
= mod
->addWire(sstr
.str() + "_CTRL");
206 // reduce cmp vector to one logic signal
207 RTLIL::Cell
*any_cell
= mod
->addCell(sstr
.str() + "_ANY", ID($reduce_or
));
208 apply_attrs(any_cell
, sw
, cs
);
210 any_cell
->parameters
[ID::A_SIGNED
] = RTLIL::Const(0);
211 any_cell
->parameters
[ID::A_WIDTH
] = RTLIL::Const(cmp_wire
->width
);
212 any_cell
->parameters
[ID::Y_WIDTH
] = RTLIL::Const(1);
214 any_cell
->setPort(ID::A
, cmp_wire
);
215 any_cell
->setPort(ID::Y
, RTLIL::SigSpec(ctrl_wire
));
218 return RTLIL::SigSpec(ctrl_wire
);
221 RTLIL::SigSpec
gen_mux(RTLIL::Module
*mod
, const RTLIL::SigSpec
&signal
, const std::vector
<RTLIL::SigSpec
> &compare
, RTLIL::SigSpec when_signal
, RTLIL::SigSpec else_signal
, RTLIL::Cell
*&last_mux_cell
, RTLIL::SwitchRule
*sw
, RTLIL::CaseRule
*cs
, bool ifxmode
)
223 log_assert(when_signal
.size() == else_signal
.size());
225 std::stringstream sstr
;
226 sstr
<< "$procmux$" << (autoidx
++);
229 if (compare
.size() == 0 || when_signal
== else_signal
)
233 RTLIL::SigSpec ctrl_sig
= gen_cmp(mod
, signal
, compare
, sw
, cs
, ifxmode
);
234 if (ctrl_sig
.size() == 0)
236 log_assert(ctrl_sig
.size() == 1);
238 // prepare multiplexer output signal
239 RTLIL::Wire
*result_wire
= mod
->addWire(sstr
.str() + "_Y", when_signal
.size());
241 // create the multiplexer itself
242 RTLIL::Cell
*mux_cell
= mod
->addCell(sstr
.str(), ID($mux
));
243 apply_attrs(mux_cell
, sw
, cs
);
245 mux_cell
->parameters
[ID::WIDTH
] = RTLIL::Const(when_signal
.size());
246 mux_cell
->setPort(ID::A
, else_signal
);
247 mux_cell
->setPort(ID::B
, when_signal
);
248 mux_cell
->setPort(ID::S
, ctrl_sig
);
249 mux_cell
->setPort(ID::Y
, RTLIL::SigSpec(result_wire
));
251 last_mux_cell
= mux_cell
;
252 return RTLIL::SigSpec(result_wire
);
255 void append_pmux(RTLIL::Module
*mod
, const RTLIL::SigSpec
&signal
, const std::vector
<RTLIL::SigSpec
> &compare
, RTLIL::SigSpec when_signal
, RTLIL::Cell
*last_mux_cell
, RTLIL::SwitchRule
*sw
, RTLIL::CaseRule
*cs
, bool ifxmode
)
257 log_assert(last_mux_cell
!= NULL
);
258 log_assert(when_signal
.size() == last_mux_cell
->getPort(ID::A
).size());
260 if (when_signal
== last_mux_cell
->getPort(ID::A
))
263 RTLIL::SigSpec ctrl_sig
= gen_cmp(mod
, signal
, compare
, sw
, cs
, ifxmode
);
264 log_assert(ctrl_sig
.size() == 1);
265 last_mux_cell
->type
= ID($pmux
);
267 RTLIL::SigSpec new_s
= last_mux_cell
->getPort(ID::S
);
268 new_s
.append(ctrl_sig
);
269 last_mux_cell
->setPort(ID::S
, new_s
);
271 RTLIL::SigSpec new_b
= last_mux_cell
->getPort(ID::B
);
272 new_b
.append(when_signal
);
273 last_mux_cell
->setPort(ID::B
, new_b
);
275 last_mux_cell
->parameters
[ID::S_WIDTH
] = last_mux_cell
->getPort(ID::S
).size();
278 const pool
<SigBit
> &get_full_case_bits(SnippetSwCache
&swcache
, RTLIL::SwitchRule
*sw
)
280 if (!swcache
.full_case_bits_cache
.count(sw
))
284 if (sw
->get_bool_attribute(ID::full_case
))
286 bool first_case
= true;
288 for (auto cs
: sw
->cases
)
290 pool
<SigBit
> case_bits
;
292 for (auto it
: cs
->actions
) {
293 for (auto bit
: it
.first
)
294 case_bits
.insert(bit
);
297 for (auto it
: cs
->switches
) {
298 for (auto bit
: get_full_case_bits(swcache
, it
))
299 case_bits
.insert(bit
);
306 pool
<SigBit
> new_bits
;
307 for (auto bit
: bits
)
308 if (case_bits
.count(bit
))
309 new_bits
.insert(bit
);
315 bits
.swap(swcache
.full_case_bits_cache
[sw
]);
318 return swcache
.full_case_bits_cache
.at(sw
);
321 RTLIL::SigSpec
signal_to_mux_tree(RTLIL::Module
*mod
, SnippetSwCache
&swcache
, dict
<RTLIL::SwitchRule
*, bool, hash_ptr_ops
> &swpara
,
322 RTLIL::CaseRule
*cs
, const RTLIL::SigSpec
&sig
, const RTLIL::SigSpec
&defval
, bool ifxmode
)
324 RTLIL::SigSpec result
= defval
;
326 for (auto &action
: cs
->actions
) {
327 sig
.replace(action
.first
, action
.second
, &result
);
328 action
.first
.remove2(sig
, &action
.second
);
331 for (auto sw
: cs
->switches
)
333 if (!swcache
.check(sw
))
336 // detect groups of parallel cases
337 std::vector
<int> pgroups(sw
->cases
.size());
338 bool is_simple_parallel_case
= true;
340 if (!sw
->get_bool_attribute(ID::parallel_case
)) {
341 if (!swpara
.count(sw
)) {
342 pool
<Const
> case_values
;
343 for (size_t i
= 0; i
< sw
->cases
.size(); i
++) {
344 RTLIL::CaseRule
*cs2
= sw
->cases
[i
];
345 for (auto pat
: cs2
->compare
) {
346 if (!pat
.is_fully_def())
347 goto not_simple_parallel_case
;
348 Const cpat
= pat
.as_const();
349 if (case_values
.count(cpat
))
350 goto not_simple_parallel_case
;
351 case_values
.insert(cpat
);
355 not_simple_parallel_case
:
356 is_simple_parallel_case
= false;
357 swpara
[sw
] = is_simple_parallel_case
;
359 is_simple_parallel_case
= swpara
.at(sw
);
363 if (!is_simple_parallel_case
) {
364 BitPatternPool
pool(sw
->signal
.size());
365 bool extra_group_for_next_case
= false;
366 for (size_t i
= 0; i
< sw
->cases
.size(); i
++) {
367 RTLIL::CaseRule
*cs2
= sw
->cases
[i
];
369 pgroups
[i
] = pgroups
[i
-1];
370 if (extra_group_for_next_case
) {
371 pgroups
[i
] = pgroups
[i
-1]+1;
372 extra_group_for_next_case
= false;
374 for (auto pat
: cs2
->compare
)
375 if (!pat
.is_fully_const() || !pool
.has_all(pat
))
376 pgroups
[i
] = pgroups
[i
-1]+1;
377 if (cs2
->compare
.empty())
378 pgroups
[i
] = pgroups
[i
-1]+1;
379 if (pgroups
[i
] != pgroups
[i
-1])
380 pool
= BitPatternPool(sw
->signal
.size());
382 for (auto pat
: cs2
->compare
)
383 if (!pat
.is_fully_const())
384 extra_group_for_next_case
= true;
390 // mask default bits that are irrelevant because the output is driven by a full case
391 const pool
<SigBit
> &full_case_bits
= get_full_case_bits(swcache
, sw
);
392 for (int i
= 0; i
< GetSize(sig
); i
++)
393 if (full_case_bits
.count(sig
[i
]))
394 result
[i
] = State::Sx
;
396 // evaluate in reverse order to give the first entry the top priority
397 RTLIL::SigSpec initial_val
= result
;
398 RTLIL::Cell
*last_mux_cell
= NULL
;
399 for (size_t i
= 0; i
< sw
->cases
.size(); i
++) {
400 int case_idx
= sw
->cases
.size() - i
- 1;
401 RTLIL::CaseRule
*cs2
= sw
->cases
[case_idx
];
402 RTLIL::SigSpec value
= signal_to_mux_tree(mod
, swcache
, swpara
, cs2
, sig
, initial_val
, ifxmode
);
403 if (last_mux_cell
&& pgroups
[case_idx
] == pgroups
[case_idx
+1])
404 append_pmux(mod
, sw
->signal
, cs2
->compare
, value
, last_mux_cell
, sw
, cs2
, ifxmode
);
406 result
= gen_mux(mod
, sw
->signal
, cs2
->compare
, value
, result
, last_mux_cell
, sw
, cs2
, ifxmode
);
413 void proc_mux(RTLIL::Module
*mod
, RTLIL::Process
*proc
, bool ifxmode
)
415 log("Creating decoders for process `%s.%s'.\n", mod
->name
.c_str(), proc
->name
.c_str());
418 sigsnip
.insert(&proc
->root_case
);
420 SnippetSwCache swcache
;
421 swcache
.snippets
= &sigsnip
;
422 swcache
.insert(&proc
->root_case
);
424 dict
<RTLIL::SwitchRule
*, bool, hash_ptr_ops
> swpara
;
427 for (int idx
: sigsnip
.snippets
)
429 swcache
.current_snippet
= idx
;
430 RTLIL::SigSpec sig
= sigsnip
.sigidx
[idx
];
432 log("%6d/%d: %s\n", ++cnt
, GetSize(sigsnip
.snippets
), log_signal(sig
));
434 RTLIL::SigSpec value
= signal_to_mux_tree(mod
, swcache
, swpara
, &proc
->root_case
, sig
, RTLIL::SigSpec(RTLIL::State::Sx
, sig
.size()), ifxmode
);
435 mod
->connect(RTLIL::SigSig(sig
, value
));
439 struct ProcMuxPass
: public Pass
{
440 ProcMuxPass() : Pass("proc_mux", "convert decision trees to multiplexers") { }
443 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
445 log(" proc_mux [options] [selection]\n");
447 log("This pass converts the decision trees in processes (originating from if-else\n");
448 log("and case statements) to trees of multiplexer cells.\n");
451 log(" Use Verilog simulation behavior with respect to undef values in\n");
452 log(" 'case' expressions and 'if' conditions.\n");
455 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
457 bool ifxmode
= false;
458 log_header(design
, "Executing PROC_MUX pass (convert decision trees to multiplexers).\n");
461 for (argidx
= 1; argidx
< args
.size(); argidx
++)
463 if (args
[argidx
] == "-ifx") {
469 extra_args(args
, argidx
, design
);
471 for (auto mod
: design
->modules())
472 if (design
->selected(mod
))
473 for (auto &proc_it
: mod
->processes
)
474 if (design
->selected(mod
, proc_it
.second
))
475 proc_mux(mod
, proc_it
.second
, ifxmode
);
479 PRIVATE_NAMESPACE_END