25 using namespace RTLIL;
35 supported_cell_types = std::set<IdString>({
36 "$not",
"$pos",
"$neg",
37 "$and",
"$or",
"$xor",
"$xnor",
38 "$shl",
"$shr",
"$sshl",
"$sshr",
"$shift",
"$shiftx",
39 "$lt",
"$le",
"$eq",
"$ne",
"$eqx",
"$nex",
"$ge",
"$gt",
56 config(config), module(module), mi(module) { }
66 std::vector<SigBit> bits_removed;
68 for (
int i =
GetSize(sig_y)-1; i >= 0; i--)
70 auto info = mi.query(sig_y[i]);
71 if (!info->is_output &&
GetSize(info->ports) <= 1) {
72 bits_removed.push_back(
Sx);
77 for (
int k = 0; k <
GetSize(sig_s); k++) {
78 if (ref !=
Sx && sig_b[k*
GetSize(sig_a) + i] !=
Sx && ref != sig_b[k*
GetSize(sig_a) + i])
81 ref = sig_b[k*
GetSize(sig_a) + i];
86 bits_removed.push_back(ref);
89 if (bits_removed.empty())
93 for (
int i =
GetSize(bits_removed)-1; i >= 0; i--)
103 log(
"Removed top %d bits (of %d) from mux cell %s.%s (%s).\n",
106 int n_removed =
GetSize(sig_removed);
110 new_work_queue_bits.
append(sig_a.
extract(n_kept, n_removed));
111 new_work_queue_bits.
append(sig_y.
extract(n_kept, n_removed));
117 for (
int k = 0; k <
GetSize(sig_s); k++) {
119 new_work_queue_bits.
append(sig_b.
extract(k*GetSize(sig_a) + n_kept, n_removed));
122 for (
auto bit : new_work_queue_bits)
123 work_queue_bits.insert(bit);
125 cell->
setPort(
"\\A", new_sig_a);
126 cell->
setPort(
"\\B", new_sig_b);
127 cell->
setPort(
"\\Y", new_sig_y);
138 if (port ==
'B' && cell->
type.
in(
"$shl",
"$shr",
"$sshl",
"$sshr"))
141 int bits_removed = 0;
142 if (
GetSize(sig) > max_port_size) {
143 bits_removed =
GetSize(sig) - max_port_size;
144 for (
auto bit : sig.
extract(max_port_size, bits_removed))
145 work_queue_bits.insert(bit);
146 sig = sig.
extract(0, max_port_size);
158 log(
"Removed top %d bits (of %d) from port %c of cell %s.%s (%s).\n",
161 did_something =
true;
169 if (!cell->
type.
in(config->supported_cell_types))
172 if (cell->
type.
in(
"$mux",
"$pmux"))
173 return run_cell_mux(cell);
181 if (cell->
type.
in(
"$not",
"$pos",
"$neg",
"$and",
"$or",
"$xor",
"$add",
"$sub")) {
182 max_port_a_size = std::min(max_port_a_size,
GetSize(cell->
getPort(
"\\Y")));
183 max_port_b_size = std::min(max_port_b_size,
GetSize(cell->
getPort(
"\\Y")));
186 bool port_a_signed =
false;
187 bool port_b_signed =
false;
189 if (max_port_a_size >= 0 && cell->
type !=
"$shiftx")
190 run_reduce_inport(cell,
'A', max_port_a_size, port_a_signed, did_something);
192 if (max_port_b_size >= 0)
193 run_reduce_inport(cell,
'B', max_port_b_size, port_b_signed, did_something);
200 int bits_removed = 0;
201 if (port_a_signed && cell->
type ==
"$shr") {
206 auto info = mi.query(sig[
GetSize(sig)-1]);
208 if (info->is_output ||
GetSize(info->ports) > 1)
216 if (cell->
type.
in(
"$pos",
"$add",
"$mul",
"$and",
"$or",
"$xor"))
220 int a_size = 0, b_size = 0;
224 int max_y_size = std::max(a_size, b_size);
226 if (cell->
type ==
"$add")
229 if (cell->
type ==
"$mul")
230 max_y_size = a_size + b_size;
246 log(
"Removed top %d bits (of %d) from port Y of cell %s.%s (%s).\n",
249 did_something =
true;
260 int count = w->attributes.size();
261 count -= w->attributes.count(
"\\src");
262 count -= w->attributes.count(
"\\unused_bits");
269 work_queue_cells.insert(c);
271 while (!work_queue_cells.empty())
273 work_queue_bits.clear();
274 for (
auto c : work_queue_cells)
277 work_queue_cells.clear();
278 for (
auto bit : work_queue_bits)
279 for (
auto port : mi.query_ports(bit))
281 work_queue_cells.insert(port.cell);
286 int unused_top_bits = 0;
291 for (
int i =
GetSize(w)-1; i >= 0; i--) {
293 auto info = mi.query(bit);
294 if (info && (info->is_input || info->is_output ||
GetSize(info->ports) > 0))
299 if (0 < unused_top_bits && unused_top_bits <
GetSize(w)) {
316 log(
" wreduce [options] [selection]\n");
318 log(
"This command reduces the word size of operations. For example it will replace\n");
319 log(
"the 32 bit adders in the following code with adders of more appropriate widths:\n");
321 log(
" module test(input [3:0] a, b, c, output [7:0] y);\n");
322 log(
" assign y = a + b + c + 1;\n");
330 log_header(
"Executing WREDUCE pass (reducing word size of cells).\n");
333 for (argidx = 1; argidx < args.size(); argidx++) {
336 extra_args(args, argidx, design);
void fixup_parameters(bool set_a_signed=false, bool set_b_signed=false)
std::set< Cell *, IdString::compare_ptr_by_name< Cell > > work_queue_cells
std::string stringf(const char *fmt,...)
int count_nontrivial_wire_attrs(RTLIL::Wire *w)
void log_header(const char *format,...)
void setPort(RTLIL::IdString portname, RTLIL::SigSpec signal)
void swap_names(RTLIL::Wire *w1, RTLIL::Wire *w2)
void remove(const RTLIL::SigSpec &pattern)
bool in(T first, Args...rest)
bool has_processes_warn() const
USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN bool did_something
std::set< IdString > supported_cell_types
void connect(const RTLIL::SigSig &conn)
void append_bit(const RTLIL::SigBit &bit)
bool selected(T *member) const
#define PRIVATE_NAMESPACE_BEGIN
RTLIL_ATTRIBUTE_MEMBERS bool hasPort(RTLIL::IdString portname) const
void run_cell(Cell *cell)
const RTLIL::SigSpec & getPort(RTLIL::IdString portname) const
int GetSize(RTLIL::Wire *wire)
std::vector< RTLIL::Wire * > selected_wires() const
virtual void execute(std::vector< std::string > args, Design *design)
RTLIL::Wire * addWire(RTLIL::IdString name, int width=1)
std::vector< RTLIL::Cell * > selected_cells() const
#define PRIVATE_NAMESPACE_END
void run_cell_mux(Cell *cell)
#define USING_YOSYS_NAMESPACE
void run_reduce_inport(Cell *cell, char port, int max_port_size, bool &port_signed, bool &did_something)
void remove(const std::set< RTLIL::Wire * > &wires)
WreduceWorker(WreduceConfig *config, Module *module)
void log(const char *format,...)
const RTLIL::Const & getParam(RTLIL::IdString paramname) const
RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other=NULL) const
static int count_nontrivial_wire_attrs(RTLIL::Wire *w)
void append(const RTLIL::SigSpec &signal)
std::vector< RTLIL::Module * > selected_modules() const
std::set< SigBit > work_queue_bits
const char * log_id(RTLIL::IdString str)