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/yosys.h"
21 #include "kernel/sigtools.h"
22 #include "kernel/macc.h"
26 RTLIL::Module
*module
;
36 std::map
<RTLIL::SigBit
, int> bit_users
;
37 std::map
<RTLIL::SigSpec
, maccnode_t
*> sig_macc
;
39 AlumaccWorker(RTLIL::Module
*module
) : module(module
), sigmap(module
) { }
41 void count_bit_users()
43 for (auto port
: module
->ports
)
44 for (auto bit
: sigmap(module
->wire(port
)))
47 for (auto cell
: module
->cells())
48 for (auto &conn
: cell
->connections())
49 for (auto bit
: sigmap(conn
.second
))
55 for (auto cell
: module
->selected_cells())
57 if (!cell
->type
.in("$pos", "$neg", "$add", "$sub", "$mul"))
60 log(" creating $macc model for %s (%s).\n", log_id(cell
), log_id(cell
->type
));
62 maccnode_t
*n
= new maccnode_t
;
63 Macc::port_t new_port
;
66 n
->y
= sigmap(cell
->getPort("\\Y"));
70 n
->users
= std::max(n
->users
, bit_users
.at(bit
) - 1);
72 if (cell
->type
.in("$pos", "$neg"))
74 new_port
.in_a
= sigmap(cell
->getPort("\\A"));
75 new_port
.is_signed
= cell
->getParam("\\A_SIGNED").as_bool();
76 new_port
.do_subtract
= cell
->type
== "$neg";
77 n
->macc
.ports
.push_back(new_port
);
80 if (cell
->type
.in("$add", "$sub"))
82 new_port
.in_a
= sigmap(cell
->getPort("\\A"));
83 new_port
.is_signed
= cell
->getParam("\\A_SIGNED").as_bool();
84 new_port
.do_subtract
= false;
85 n
->macc
.ports
.push_back(new_port
);
87 new_port
.in_a
= sigmap(cell
->getPort("\\B"));
88 new_port
.is_signed
= cell
->getParam("\\B_SIGNED").as_bool();
89 new_port
.do_subtract
= cell
->type
== "$sub";
90 n
->macc
.ports
.push_back(new_port
);
93 if (cell
->type
.in("$mul"))
95 new_port
.in_a
= sigmap(cell
->getPort("\\A"));
96 new_port
.in_b
= sigmap(cell
->getPort("\\B"));
97 new_port
.is_signed
= cell
->getParam("\\A_SIGNED").as_bool();
98 new_port
.do_subtract
= false;
99 n
->macc
.ports
.push_back(new_port
);
102 log_assert(sig_macc
.count(n
->y
) == 0);
111 std::set
<maccnode_t
*> delete_nodes
;
113 for (auto &it
: sig_macc
)
117 if (delete_nodes
.count(n
))
120 for (int i
= 0; i
< SIZE(n
->macc
.ports
); i
++)
122 auto &port
= n
->macc
.ports
[i
];
124 if (SIZE(port
.in_b
) > 0 || sig_macc
.count(port
.in_a
) == 0)
127 auto other_n
= sig_macc
.at(port
.in_a
);
129 if (other_n
->users
> 1)
132 if (SIZE(other_n
->y
) != SIZE(n
->y
))
135 log(" merging $macc model for %s into %s.\n", log_id(other_n
->cell
), log_id(n
->cell
));
137 bool do_subtract
= port
.do_subtract
;
138 for (int j
= 0; j
< SIZE(other_n
->macc
.ports
); j
++) {
140 other_n
->macc
.ports
[j
].do_subtract
= !other_n
->macc
.ports
[j
].do_subtract
;
142 n
->macc
.ports
[i
--] = other_n
->macc
.ports
[j
];
144 n
->macc
.ports
.push_back(other_n
->macc
.ports
[j
]);
147 delete_nodes
.insert(other_n
);
151 if (delete_nodes
.empty())
154 for (auto n
: delete_nodes
) {
155 sig_macc
.erase(n
->y
);
163 for (auto &it
: sig_macc
)
166 auto cell
= module
->addCell(NEW_ID
, "$macc");
167 n
->macc
.to_cell(cell
);
168 cell
->setPort("\\Y", n
->y
);
169 cell
->fixup_parameters();
170 module
->remove(n
->cell
);
179 log("Extracting $alu and $macc cells in module %s:\n", log_id(module
));
188 struct AlumaccPass
: public Pass
{
189 AlumaccPass() : Pass("alumacc", "extract ALU and MACC cells") { }
192 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
194 log(" alumacc [selection]\n");
196 log("This pass translates arithmetic operations $add, $mul, $lt, etc. to $alu and\n");
197 log("$macc cells.\n");
200 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
)
202 log_header("Executing ALUMACC pass (create $alu and $macc cells).\n");
205 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
206 // if (args[argidx] == "-foobar") {
207 // foobar_mode = true;
212 extra_args(args
, argidx
, design
);
214 for (auto mod
: design
->selected_modules())
215 if (!mod
->has_processes_warn()) {
216 AlumaccWorker
worker(mod
);