Merge remote-tracking branch 'origin/master' into xaig
[yosys.git] / kernel / cellaigs.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
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/cellaigs.h"
21
22 YOSYS_NAMESPACE_BEGIN
23
24 AigNode::AigNode()
25 {
26 portbit = -1;
27 inverter = false;
28 left_parent = -1;
29 right_parent = -1;
30 }
31
32 bool AigNode::operator==(const AigNode &other) const
33 {
34 if (portname != other.portname) return false;
35 if (portbit != other.portbit) return false;
36 if (inverter != other.inverter) return false;
37 if (left_parent != other.left_parent) return false;
38 if (right_parent != other.right_parent) return false;
39 return true;
40 }
41
42 unsigned int AigNode::hash() const
43 {
44 unsigned int h = mkhash_init;
45 h = mkhash(portname.hash(), portbit);
46 h = mkhash(h, inverter);
47 h = mkhash(h, left_parent);
48 h = mkhash(h, right_parent);
49 return h;
50 }
51
52 bool Aig::operator==(const Aig &other) const
53 {
54 return name == other.name;
55 }
56
57 unsigned int Aig::hash() const
58 {
59 return hash_ops<std::string>::hash(name);
60 }
61
62 struct AigMaker
63 {
64 Aig *aig;
65 Cell *cell;
66 idict<AigNode> aig_indices;
67
68 int the_true_node;
69 int the_false_node;
70
71 AigMaker(Aig *aig, Cell *cell) : aig(aig), cell(cell)
72 {
73 the_true_node = -1;
74 the_false_node = -1;
75 }
76
77 int node2index(const AigNode &node)
78 {
79 if (node.left_parent > node.right_parent) {
80 AigNode n(node);
81 std::swap(n.left_parent, n.right_parent);
82 return node2index(n);
83 }
84
85 if (!aig_indices.count(node)) {
86 aig_indices.expect(node, GetSize(aig->nodes));
87 aig->nodes.push_back(node);
88 }
89
90 return aig_indices.at(node);
91 }
92
93 int bool_node(bool value)
94 {
95 AigNode node;
96 node.inverter = value;
97 return node2index(node);
98 }
99
100 int inport(IdString portname, int portbit = 0, bool inverter = false)
101 {
102 if (portbit >= GetSize(cell->getPort(portname))) {
103 if (cell->parameters.count(portname.str() + "_SIGNED") && cell->getParam(portname.str() + "_SIGNED").as_bool())
104 return inport(portname, GetSize(cell->getPort(portname))-1, inverter);
105 return bool_node(inverter);
106 }
107
108 AigNode node;
109 node.portname = portname;
110 node.portbit = portbit;
111 node.inverter = inverter;
112 return node2index(node);
113 }
114
115 vector<int> inport_vec(IdString portname, int width)
116 {
117 vector<int> vec;
118 for (int i = 0; i < width; i++)
119 vec.push_back(inport(portname, i));
120 return vec;
121 }
122
123 int not_inport(IdString portname, int portbit = 0)
124 {
125 return inport(portname, portbit, true);
126 }
127
128 int not_gate(int A)
129 {
130 AigNode node(aig_indices[A]);
131 node.outports.clear();
132 node.inverter = !node.inverter;
133 return node2index(node);
134 }
135
136 int and_gate(int A, int B, bool inverter = false)
137 {
138 if (A == B)
139 return inverter ? not_gate(A) : A;
140
141 const AigNode &nA = aig_indices[A];
142 const AigNode &nB = aig_indices[B];
143
144 AigNode nB_inv(nB);
145 nB_inv.inverter = !nB_inv.inverter;
146
147 if (nA == nB_inv)
148 return bool_node(inverter);
149
150 bool nA_bool = nA.portbit < 0 && nA.left_parent < 0 && nA.right_parent < 0;
151 bool nB_bool = nB.portbit < 0 && nB.left_parent < 0 && nB.right_parent < 0;
152
153 if (nA_bool && nB_bool) {
154 bool bA = nA.inverter;
155 bool bB = nB.inverter;
156 return bool_node(inverter != (bA && bB));
157 }
158
159 if (nA_bool) {
160 bool bA = nA.inverter;
161 if (inverter)
162 return bA ? not_gate(B) : bool_node(true);
163 return bA ? B : bool_node(false);
164 }
165
166 if (nB_bool) {
167 bool bB = nB.inverter;
168 if (inverter)
169 return bB ? not_gate(A) : bool_node(true);
170 return bB ? A : bool_node(false);
171 }
172
173 AigNode node;
174 node.inverter = inverter;
175 node.left_parent = A;
176 node.right_parent = B;
177 return node2index(node);
178 }
179
180 int nand_gate(int A, int B)
181 {
182 return and_gate(A, B, true);
183 }
184
185 int or_gate(int A, int B)
186 {
187 return nand_gate(not_gate(A), not_gate(B));
188 }
189
190 int nor_gate(int A, int B)
191 {
192 return and_gate(not_gate(A), not_gate(B));
193 }
194
195 int xor_gate(int A, int B)
196 {
197 return nor_gate(and_gate(A, B), nor_gate(A, B));
198 }
199
200 int xnor_gate(int A, int B)
201 {
202 return or_gate(and_gate(A, B), nor_gate(A, B));
203 }
204
205 int andnot_gate(int A, int B)
206 {
207 return and_gate(A, not_gate(B));
208 }
209
210 int ornot_gate(int A, int B)
211 {
212 return or_gate(A, not_gate(B));
213 }
214
215 int mux_gate(int A, int B, int S)
216 {
217 return or_gate(and_gate(A, not_gate(S)), and_gate(B, S));
218 }
219
220 vector<int> adder(const vector<int> &A, const vector<int> &B, int carry, vector<int> *X = nullptr, vector<int> *CO = nullptr)
221 {
222 vector<int> Y(GetSize(A));
223 log_assert(GetSize(A) == GetSize(B));
224 for (int i = 0; i < GetSize(A); i++) {
225 Y[i] = xor_gate(xor_gate(A[i], B[i]), carry);
226 carry = or_gate(and_gate(A[i], B[i]), and_gate(or_gate(A[i], B[i]), carry));
227 if (X != nullptr)
228 X->at(i) = xor_gate(A[i], B[i]);
229 if (CO != nullptr)
230 CO->at(i) = carry;
231 }
232 return Y;
233 }
234
235 void outport(int node, IdString portname, int portbit = 0)
236 {
237 if (portbit < GetSize(cell->getPort(portname)))
238 aig->nodes.at(node).outports.push_back(pair<IdString, int>(portname, portbit));
239 }
240
241 void outport_bool(int node, IdString portname)
242 {
243 outport(node, portname);
244 for (int i = 1; i < GetSize(cell->getPort(portname)); i++)
245 outport(bool_node(false), portname, i);
246 }
247
248 void outport_vec(const vector<int> &vec, IdString portname)
249 {
250 for (int i = 0; i < GetSize(vec); i++)
251 outport(vec.at(i), portname, i);
252 }
253 };
254
255 Aig::Aig(Cell *cell)
256 {
257 if (cell->type[0] != '$')
258 return;
259
260 AigMaker mk(this, cell);
261 name = cell->type.str();
262
263 string mkname_last;
264 bool mkname_a_signed = false;
265 bool mkname_b_signed = false;
266 bool mkname_is_signed = false;
267
268 cell->parameters.sort();
269 for (auto p : cell->parameters)
270 {
271 if (p.first == "\\A_WIDTH" && mkname_a_signed) {
272 name = mkname_last + stringf(":%d%c", p.second.as_int(), mkname_is_signed ? 'S' : 'U');
273 } else if (p.first == "\\B_WIDTH" && mkname_b_signed) {
274 name = mkname_last + stringf(":%d%c", p.second.as_int(), mkname_is_signed ? 'S' : 'U');
275 } else {
276 mkname_last = name;
277 name += stringf(":%d", p.second.as_int());
278 }
279
280 mkname_a_signed = false;
281 mkname_b_signed = false;
282 mkname_is_signed = false;
283 if (p.first == "\\A_SIGNED") {
284 mkname_a_signed = true;
285 mkname_is_signed = p.second.as_bool();
286 }
287 if (p.first == "\\B_SIGNED") {
288 mkname_b_signed = true;
289 mkname_is_signed = p.second.as_bool();
290 }
291 }
292
293 if (cell->type.in("$not", "$_NOT_", "$pos", "$_BUF_"))
294 {
295 for (int i = 0; i < GetSize(cell->getPort("\\Y")); i++) {
296 int A = mk.inport("\\A", i);
297 int Y = cell->type.in("$not", "$_NOT_") ? mk.not_gate(A) : A;
298 mk.outport(Y, "\\Y", i);
299 }
300 goto optimize;
301 }
302
303 if (cell->type.in("$and", "$_AND_", "$_NAND_", "$or", "$_OR_", "$_NOR_", "$xor", "$xnor", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_"))
304 {
305 for (int i = 0; i < GetSize(cell->getPort("\\Y")); i++) {
306 int A = mk.inport("\\A", i);
307 int B = mk.inport("\\B", i);
308 int Y = cell->type.in("$and", "$_AND_") ? mk.and_gate(A, B) :
309 cell->type.in("$_NAND_") ? mk.nand_gate(A, B) :
310 cell->type.in("$or", "$_OR_") ? mk.or_gate(A, B) :
311 cell->type.in("$_NOR_") ? mk.nor_gate(A, B) :
312 cell->type.in("$xor", "$_XOR_") ? mk.xor_gate(A, B) :
313 cell->type.in("$xnor", "$_XNOR_") ? mk.xnor_gate(A, B) :
314 cell->type.in("$_ANDNOT_") ? mk.andnot_gate(A, B) :
315 cell->type.in("$_ORNOT_") ? mk.ornot_gate(A, B) : -1;
316 mk.outport(Y, "\\Y", i);
317 }
318 goto optimize;
319 }
320
321 if (cell->type.in("$mux", "$_MUX_"))
322 {
323 int S = mk.inport("\\S");
324 for (int i = 0; i < GetSize(cell->getPort("\\Y")); i++) {
325 int A = mk.inport("\\A", i);
326 int B = mk.inport("\\B", i);
327 int Y = mk.mux_gate(A, B, S);
328 mk.outport(Y, "\\Y", i);
329 }
330 goto optimize;
331 }
332
333 if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool"))
334 {
335 int Y = mk.inport("\\A", 0);
336 for (int i = 1; i < GetSize(cell->getPort("\\A")); i++) {
337 int A = mk.inport("\\A", i);
338 if (cell->type == "$reduce_and") Y = mk.and_gate(A, Y);
339 if (cell->type == "$reduce_or") Y = mk.or_gate(A, Y);
340 if (cell->type == "$reduce_bool") Y = mk.or_gate(A, Y);
341 if (cell->type == "$reduce_xor") Y = mk.xor_gate(A, Y);
342 if (cell->type == "$reduce_xnor") Y = mk.xor_gate(A, Y);
343 }
344 if (cell->type == "$reduce_xnor")
345 Y = mk.not_gate(Y);
346 mk.outport(Y, "\\Y", 0);
347 for (int i = 1; i < GetSize(cell->getPort("\\Y")); i++)
348 mk.outport(mk.bool_node(false), "\\Y", i);
349 goto optimize;
350 }
351
352 if (cell->type.in("$logic_not", "$logic_and", "$logic_or"))
353 {
354 int A = mk.inport("\\A", 0), Y = -1;
355 for (int i = 1; i < GetSize(cell->getPort("\\A")); i++)
356 A = mk.or_gate(mk.inport("\\A", i), A);
357 if (cell->type.in("$logic_and", "$logic_or")) {
358 int B = mk.inport("\\B", 0);
359 for (int i = 1; i < GetSize(cell->getPort("\\B")); i++)
360 B = mk.or_gate(mk.inport("\\B", i), B);
361 if (cell->type == "$logic_and") Y = mk.and_gate(A, B);
362 if (cell->type == "$logic_or") Y = mk.or_gate(A, B);
363 } else {
364 if (cell->type == "$logic_not") Y = mk.not_gate(A);
365 }
366 mk.outport_bool(Y, "\\Y");
367 goto optimize;
368 }
369
370 if (cell->type.in("$add", "$sub"))
371 {
372 int width = GetSize(cell->getPort("\\Y"));
373 vector<int> A = mk.inport_vec("\\A", width);
374 vector<int> B = mk.inport_vec("\\B", width);
375 int carry = mk.bool_node(false);
376 if (cell->type == "$sub") {
377 for (auto &n : B)
378 n = mk.not_gate(n);
379 carry = mk.not_gate(carry);
380 }
381 vector<int> Y = mk.adder(A, B, carry);
382 mk.outport_vec(Y, "\\Y");
383 goto optimize;
384 }
385
386 if (cell->type == "$alu")
387 {
388 int width = GetSize(cell->getPort("\\Y"));
389 vector<int> A = mk.inport_vec("\\A", width);
390 vector<int> B = mk.inport_vec("\\B", width);
391 int carry = mk.inport("\\CI");
392 int binv = mk.inport("\\BI");
393 for (auto &n : B)
394 n = mk.xor_gate(n, binv);
395 vector<int> X(width), CO(width);
396 vector<int> Y = mk.adder(A, B, carry, &X, &CO);
397 for (int i = 0; i < width; i++)
398 X[i] = mk.xor_gate(A[i], B[i]);
399 mk.outport_vec(Y, "\\Y");
400 mk.outport_vec(X, "\\X");
401 mk.outport_vec(CO, "\\CO");
402 goto optimize;
403 }
404
405 if (cell->type.in("$eq", "$ne"))
406 {
407 int width = max(GetSize(cell->getPort("\\A")), GetSize(cell->getPort("\\B")));
408 vector<int> A = mk.inport_vec("\\A", width);
409 vector<int> B = mk.inport_vec("\\B", width);
410 int Y = mk.bool_node(false);
411 for (int i = 0; i < width; i++)
412 Y = mk.or_gate(Y, mk.xor_gate(A[i], B[i]));
413 if (cell->type == "$eq")
414 Y = mk.not_gate(Y);
415 mk.outport_bool(Y, "\\Y");
416 goto optimize;
417 }
418
419 if (cell->type == "$_AOI3_")
420 {
421 int A = mk.inport("\\A");
422 int B = mk.inport("\\B");
423 int C = mk.inport("\\C");
424 int Y = mk.nor_gate(mk.and_gate(A, B), C);
425 mk.outport(Y, "\\Y");
426 goto optimize;
427 }
428
429 if (cell->type == "$_OAI3_")
430 {
431 int A = mk.inport("\\A");
432 int B = mk.inport("\\B");
433 int C = mk.inport("\\C");
434 int Y = mk.nand_gate(mk.or_gate(A, B), C);
435 mk.outport(Y, "\\Y");
436 goto optimize;
437 }
438
439 if (cell->type == "$_AOI4_")
440 {
441 int A = mk.inport("\\A");
442 int B = mk.inport("\\B");
443 int C = mk.inport("\\C");
444 int D = mk.inport("\\D");
445 int Y = mk.nor_gate(mk.and_gate(A, B), mk.and_gate(C, D));
446 mk.outport(Y, "\\Y");
447 goto optimize;
448 }
449
450 if (cell->type == "$_OAI4_")
451 {
452 int A = mk.inport("\\A");
453 int B = mk.inport("\\B");
454 int C = mk.inport("\\C");
455 int D = mk.inport("\\D");
456 int Y = mk.nand_gate(mk.or_gate(A, B), mk.or_gate(C, D));
457 mk.outport(Y, "\\Y");
458 goto optimize;
459 }
460
461 name.clear();
462 return;
463
464 optimize:;
465 pool<int> used_old_ids;
466 vector<AigNode> new_nodes;
467 dict<int, int> old_to_new_ids;
468 old_to_new_ids[-1] = -1;
469
470 for (int i = GetSize(nodes)-1; i >= 0; i--) {
471 if (!nodes[i].outports.empty())
472 used_old_ids.insert(i);
473 if (!used_old_ids.count(i))
474 continue;
475 if (nodes[i].left_parent >= 0)
476 used_old_ids.insert(nodes[i].left_parent);
477 if (nodes[i].right_parent >= 0)
478 used_old_ids.insert(nodes[i].right_parent);
479 }
480
481 for (int i = 0; i < GetSize(nodes); i++) {
482 if (!used_old_ids.count(i))
483 continue;
484 nodes[i].left_parent = old_to_new_ids.at(nodes[i].left_parent);
485 nodes[i].right_parent = old_to_new_ids.at(nodes[i].right_parent);
486 old_to_new_ids[i] = GetSize(new_nodes);
487 new_nodes.push_back(nodes[i]);
488 }
489
490 new_nodes.swap(nodes);
491 }
492
493 YOSYS_NAMESPACE_END