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
;
38 std::vector
<RTLIL::Cell
*> cells
;
39 RTLIL::SigSpec a
, b
, c
, y
;
40 std::vector
<std::tuple
<bool, bool, bool, bool, RTLIL::SigSpec
>> cmp
;
41 bool is_signed
, invert_b
;
43 RTLIL::Cell
*alu_cell
;
44 RTLIL::SigSpec cached_lt
, cached_gt
, cached_eq
, cached_ne
;
45 RTLIL::SigSpec cached_cf
, cached_of
, cached_sf
;
47 RTLIL::SigSpec
get_lt() {
48 if (SIZE(cached_lt
) == 0)
49 cached_lt
= is_signed
? alu_cell
->module
->Xor(NEW_ID
, get_of(), get_sf()) : get_cf();
53 RTLIL::SigSpec
get_gt() {
54 if (SIZE(cached_gt
) == 0)
55 cached_gt
= alu_cell
->module
->Not(NEW_ID
, alu_cell
->module
->Or(NEW_ID
, get_lt(), get_eq()));
59 RTLIL::SigSpec
get_eq() {
60 if (SIZE(cached_eq
) == 0)
61 cached_eq
= alu_cell
->module
->ReduceAnd(NEW_ID
, alu_cell
->getPort("\\X"));
65 RTLIL::SigSpec
get_ne() {
66 if (SIZE(cached_ne
) == 0)
67 cached_ne
= alu_cell
->module
->Not(NEW_ID
, get_eq());
71 RTLIL::SigSpec
get_cf() {
72 if (SIZE(cached_cf
) == 0) {
73 cached_cf
= alu_cell
->getPort("\\CO");
74 log_assert(SIZE(cached_cf
) >= 1);
75 cached_cf
= alu_cell
->module
->Not(NEW_ID
, cached_cf
[SIZE(cached_cf
)-1]);
80 RTLIL::SigSpec
get_of() {
81 if (SIZE(cached_of
) == 0) {
82 cached_of
= {alu_cell
->getPort("\\CO"), alu_cell
->getPort("\\CI")};
83 log_assert(SIZE(cached_of
) >= 2);
84 cached_of
= alu_cell
->module
->Xor(NEW_ID
, cached_of
[SIZE(cached_of
)-1], cached_of
[SIZE(cached_of
)-2]);
89 RTLIL::SigSpec
get_sf() {
90 if (SIZE(cached_sf
) == 0) {
91 cached_sf
= alu_cell
->getPort("\\Y");
92 cached_sf
= cached_sf
[SIZE(cached_sf
)-1];
98 std::map
<RTLIL::SigBit
, int> bit_users
;
99 std::map
<RTLIL::SigSpec
, maccnode_t
*> sig_macc
;
100 std::map
<RTLIL::SigSig
, std::set
<alunode_t
*>> sig_alu
;
101 int macc_counter
, alu_counter
;
103 AlumaccWorker(RTLIL::Module
*module
) : module(module
), sigmap(module
)
109 void count_bit_users()
111 for (auto port
: module
->ports
)
112 for (auto bit
: sigmap(module
->wire(port
)))
115 for (auto cell
: module
->cells())
116 for (auto &conn
: cell
->connections())
117 for (auto bit
: sigmap(conn
.second
))
123 for (auto cell
: module
->selected_cells())
125 if (!cell
->type
.in("$pos", "$neg", "$add", "$sub", "$mul"))
128 log(" creating $macc model for %s (%s).\n", log_id(cell
), log_id(cell
->type
));
130 maccnode_t
*n
= new maccnode_t
;
131 Macc::port_t new_port
;
134 n
->y
= sigmap(cell
->getPort("\\Y"));
137 for (auto bit
: n
->y
)
138 n
->users
= std::max(n
->users
, bit_users
.at(bit
) - 1);
140 if (cell
->type
.in("$pos", "$neg"))
142 new_port
.in_a
= sigmap(cell
->getPort("\\A"));
143 new_port
.is_signed
= cell
->getParam("\\A_SIGNED").as_bool();
144 new_port
.do_subtract
= cell
->type
== "$neg";
145 n
->macc
.ports
.push_back(new_port
);
148 if (cell
->type
.in("$add", "$sub"))
150 new_port
.in_a
= sigmap(cell
->getPort("\\A"));
151 new_port
.is_signed
= cell
->getParam("\\A_SIGNED").as_bool();
152 new_port
.do_subtract
= false;
153 n
->macc
.ports
.push_back(new_port
);
155 new_port
.in_a
= sigmap(cell
->getPort("\\B"));
156 new_port
.is_signed
= cell
->getParam("\\B_SIGNED").as_bool();
157 new_port
.do_subtract
= cell
->type
== "$sub";
158 n
->macc
.ports
.push_back(new_port
);
161 if (cell
->type
.in("$mul"))
163 new_port
.in_a
= sigmap(cell
->getPort("\\A"));
164 new_port
.in_b
= sigmap(cell
->getPort("\\B"));
165 new_port
.is_signed
= cell
->getParam("\\A_SIGNED").as_bool();
166 new_port
.do_subtract
= false;
167 n
->macc
.ports
.push_back(new_port
);
170 log_assert(sig_macc
.count(n
->y
) == 0);
179 std::set
<maccnode_t
*> delete_nodes
;
181 for (auto &it
: sig_macc
)
185 if (delete_nodes
.count(n
))
188 for (int i
= 0; i
< SIZE(n
->macc
.ports
); i
++)
190 auto &port
= n
->macc
.ports
[i
];
192 if (SIZE(port
.in_b
) > 0 || sig_macc
.count(port
.in_a
) == 0)
195 auto other_n
= sig_macc
.at(port
.in_a
);
197 if (other_n
->users
> 1)
200 if (SIZE(other_n
->y
) != SIZE(n
->y
))
203 log(" merging $macc model for %s into %s.\n", log_id(other_n
->cell
), log_id(n
->cell
));
205 bool do_subtract
= port
.do_subtract
;
206 for (int j
= 0; j
< SIZE(other_n
->macc
.ports
); j
++) {
208 other_n
->macc
.ports
[j
].do_subtract
= !other_n
->macc
.ports
[j
].do_subtract
;
210 n
->macc
.ports
[i
--] = other_n
->macc
.ports
[j
];
212 n
->macc
.ports
.push_back(other_n
->macc
.ports
[j
]);
215 delete_nodes
.insert(other_n
);
219 if (delete_nodes
.empty())
222 for (auto n
: delete_nodes
) {
223 sig_macc
.erase(n
->y
);
231 std::set
<maccnode_t
*> delete_nodes
;
233 for (auto &it
: sig_macc
)
236 RTLIL::SigSpec A
, B
, C
= n
->macc
.bit_ports
;
237 bool a_signed
= false, b_signed
= false;
238 bool subtract_b
= false;
241 for (auto &port
: n
->macc
.ports
)
242 if (SIZE(port
.in_b
) > 0) {
244 } else if (SIZE(port
.in_a
) == 1 && !port
.is_signed
&& !port
.do_subtract
) {
246 } else if (SIZE(A
) || port
.do_subtract
) {
250 b_signed
= port
.is_signed
;
251 subtract_b
= port
.do_subtract
;
256 a_signed
= port
.is_signed
;
259 if (!a_signed
|| !b_signed
) {
260 if (SIZE(A
) == SIZE(n
->y
))
262 if (SIZE(B
) == SIZE(n
->y
))
264 if (a_signed
!= b_signed
)
268 if (SIZE(A
) == 0 && SIZE(C
) > 0) {
273 if (SIZE(B
) == 0 && SIZE(C
) > 0) {
284 if (!subtract_b
&& B
< A
&& SIZE(B
))
287 log(" creating $alu model for $macc %s.\n", log_id(n
->cell
));
289 alunode
= new alunode_t
;
290 alunode
->cells
.push_back(n
->cell
);
291 alunode
->is_signed
= a_signed
;
292 alunode
->invert_b
= subtract_b
;
299 sig_alu
[RTLIL::SigSig(A
, B
)].insert(alunode
);
300 delete_nodes
.insert(n
);
304 for (auto n
: delete_nodes
) {
305 sig_macc
.erase(n
->y
);
312 for (auto &it
: sig_macc
)
315 auto cell
= module
->addCell(NEW_ID
, "$macc");
318 log(" creating $macc cell for %s: %s\n", log_id(n
->cell
), log_id(cell
));
320 n
->macc
.to_cell(cell
);
321 cell
->setPort("\\Y", n
->y
);
322 cell
->fixup_parameters();
323 module
->remove(n
->cell
);
330 void extract_cmp_alu()
332 std::vector
<RTLIL::Cell
*> lge_cells
, eq_cells
;
334 for (auto cell
: module
->selected_cells())
336 if (cell
->type
.in("$lt", "$le", "$ge", "$gt"))
337 lge_cells
.push_back(cell
);
338 if (cell
->type
.in("$eq", "$eqx", "$ne", "$nex"))
339 eq_cells
.push_back(cell
);
342 for (auto cell
: lge_cells
)
344 log(" creating $alu model for %s (%s):", log_id(cell
), log_id(cell
->type
));
346 bool cmp_less
= cell
->type
.in("$lt", "$le");
347 bool cmp_equal
= cell
->type
.in("$le", "$ge");
348 bool is_signed
= cell
->getParam("\\A_SIGNED").as_bool();
350 RTLIL::SigSpec A
= sigmap(cell
->getPort("\\A"));
351 RTLIL::SigSpec B
= sigmap(cell
->getPort("\\B"));
352 RTLIL::SigSpec Y
= sigmap(cell
->getPort("\\Y"));
354 if (B
< A
&& SIZE(B
)) {
355 cmp_less
= !cmp_less
;
359 alunode_t
*n
= nullptr;
361 for (auto node
: sig_alu
[RTLIL::SigSig(A
, B
)])
362 if (node
->is_signed
== is_signed
&& node
->invert_b
&& node
->c
== RTLIL::S1
) {
372 n
->y
= module
->addWire(NEW_ID
, std::max(SIZE(A
), SIZE(B
)));
373 n
->is_signed
= is_signed
;
375 sig_alu
[RTLIL::SigSig(A
, B
)].insert(n
);
378 log(" merged with %s.\n", log_id(n
->cells
.front()));
381 n
->cells
.push_back(cell
);
382 n
->cmp
.push_back(std::make_tuple(cmp_less
, !cmp_less
, cmp_equal
, false, Y
));
385 for (auto cell
: eq_cells
)
387 bool cmp_equal
= cell
->type
.in("$eq", "$eqx");
388 bool is_signed
= cell
->getParam("\\A_SIGNED").as_bool();
390 RTLIL::SigSpec A
= sigmap(cell
->getPort("\\A"));
391 RTLIL::SigSpec B
= sigmap(cell
->getPort("\\B"));
392 RTLIL::SigSpec Y
= sigmap(cell
->getPort("\\Y"));
394 if (B
< A
&& SIZE(B
))
397 alunode_t
*n
= nullptr;
399 for (auto node
: sig_alu
[RTLIL::SigSig(A
, B
)])
400 if (node
->is_signed
== is_signed
&& node
->invert_b
&& node
->c
== RTLIL::S1
) {
406 log(" creating $alu model for %s (%s): merged with %s.\n", log_id(cell
), log_id(cell
->type
), log_id(n
->cells
.front()));
407 n
->cells
.push_back(cell
);
408 n
->cmp
.push_back(std::make_tuple(false, false, cmp_equal
, !cmp_equal
, Y
));
415 for (auto &it1
: sig_alu
)
416 for (auto n
: it1
.second
)
418 if (SIZE(n
->b
) == 0 && SIZE(n
->c
) == 0 && SIZE(n
->cmp
) == 0)
420 n
->alu_cell
= module
->addPos(NEW_ID
, n
->a
, n
->y
, n
->is_signed
);
422 log(" creating $pos cell for ");
423 for (int i
= 0; i
< SIZE(n
->cells
); i
++)
424 log("%s%s", i
? ", ": "", log_id(n
->cells
[i
]));
425 log(": %s\n", log_id(n
->alu_cell
));
430 n
->alu_cell
= module
->addCell(NEW_ID
, "$alu");
433 log(" creating $alu cell for ");
434 for (int i
= 0; i
< SIZE(n
->cells
); i
++)
435 log("%s%s", i
? ", ": "", log_id(n
->cells
[i
]));
436 log(": %s\n", log_id(n
->alu_cell
));
438 n
->alu_cell
->setPort("\\A", n
->a
);
439 n
->alu_cell
->setPort("\\B", n
->b
);
440 n
->alu_cell
->setPort("\\CI", SIZE(n
->c
) ? n
->c
: RTLIL::S0
);
441 n
->alu_cell
->setPort("\\BI", n
->invert_b
? RTLIL::S1
: RTLIL::S0
);
442 n
->alu_cell
->setPort("\\Y", n
->y
);
443 n
->alu_cell
->setPort("\\X", module
->addWire(NEW_ID
, SIZE(n
->y
)));
444 n
->alu_cell
->setPort("\\CO", module
->addWire(NEW_ID
, SIZE(n
->y
)));
445 n
->alu_cell
->fixup_parameters(n
->is_signed
, n
->is_signed
);
446 log_cell(n
->alu_cell
);
448 for (auto &it
: n
->cmp
)
450 bool cmp_lt
= std::get
<0>(it
);
451 bool cmp_gt
= std::get
<1>(it
);
452 bool cmp_eq
= std::get
<2>(it
);
453 bool cmp_ne
= std::get
<3>(it
);
454 RTLIL::SigSpec cmp_y
= std::get
<4>(it
);
457 if (cmp_lt
) sig
.append(n
->get_lt());
458 if (cmp_gt
) sig
.append(n
->get_gt());
459 if (cmp_eq
) sig
.append(n
->get_eq());
460 if (cmp_ne
) sig
.append(n
->get_ne());
463 sig
= module
->ReduceOr(NEW_ID
, sig
);
465 sig
.extend(SIZE(cmp_y
));
466 module
->connect(cmp_y
, sig
);
470 for (auto c
: n
->cells
)
480 log("Extracting $alu and $macc cells in module %s:\n", log_id(module
));
490 log(" created %d $alu and %d $macc cells.\n", alu_counter
, macc_counter
);
494 struct AlumaccPass
: public Pass
{
495 AlumaccPass() : Pass("alumacc", "extract ALU and MACC cells") { }
498 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
500 log(" alumacc [selection]\n");
502 log("This pass translates arithmetic operations $add, $mul, $lt, etc. to $alu and\n");
503 log("$macc cells.\n");
506 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
)
508 log_header("Executing ALUMACC pass (create $alu and $macc cells).\n");
511 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
512 // if (args[argidx] == "-foobar") {
513 // foobar_mode = true;
518 extra_args(args
, argidx
, design
);
520 for (auto mod
: design
->selected_modules())
521 if (!mod
->has_processes_warn()) {
522 AlumaccWorker
worker(mod
);