Merge pull request #2082 from YosysHQ/eddie/abc9_scc_fixes
[yosys.git] / kernel / celledges.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/celledges.h"
21
22 USING_YOSYS_NAMESPACE
23 PRIVATE_NAMESPACE_BEGIN
24
25 void bitwise_unary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
26 {
27 bool is_signed = cell->getParam(ID::A_SIGNED).as_bool();
28 int a_width = GetSize(cell->getPort(ID::A));
29 int y_width = GetSize(cell->getPort(ID::Y));
30
31 for (int i = 0; i < y_width; i++)
32 {
33 if (i < a_width)
34 db->add_edge(cell, ID::A, i, ID::Y, i, -1);
35 else if (is_signed && a_width > 0)
36 db->add_edge(cell, ID::A, a_width-1, ID::Y, i, -1);
37 }
38 }
39
40 void bitwise_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
41 {
42 bool is_signed = cell->getParam(ID::A_SIGNED).as_bool();
43 int a_width = GetSize(cell->getPort(ID::A));
44 int b_width = GetSize(cell->getPort(ID::B));
45 int y_width = GetSize(cell->getPort(ID::Y));
46
47 if (cell->type == ID($and) && !is_signed) {
48 if (a_width > b_width)
49 a_width = b_width;
50 else
51 b_width = a_width;
52 }
53
54 for (int i = 0; i < y_width; i++)
55 {
56 if (i < a_width)
57 db->add_edge(cell, ID::A, i, ID::Y, i, -1);
58 else if (is_signed && a_width > 0)
59 db->add_edge(cell, ID::A, a_width-1, ID::Y, i, -1);
60
61 if (i < b_width)
62 db->add_edge(cell, ID::B, i, ID::Y, i, -1);
63 else if (is_signed && b_width > 0)
64 db->add_edge(cell, ID::B, b_width-1, ID::Y, i, -1);
65 }
66 }
67
68 void arith_neg_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
69 {
70 bool is_signed = cell->getParam(ID::A_SIGNED).as_bool();
71 int a_width = GetSize(cell->getPort(ID::A));
72 int y_width = GetSize(cell->getPort(ID::Y));
73
74 if (is_signed && a_width == 1)
75 y_width = std::min(y_width, 1);
76
77 for (int i = 0; i < y_width; i++)
78 for (int k = 0; k <= i && k < a_width; k++)
79 db->add_edge(cell, ID::A, k, ID::Y, i, -1);
80 }
81
82 void arith_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
83 {
84 bool is_signed = cell->getParam(ID::A_SIGNED).as_bool();
85 int a_width = GetSize(cell->getPort(ID::A));
86 int b_width = GetSize(cell->getPort(ID::B));
87 int y_width = GetSize(cell->getPort(ID::Y));
88
89 if (!is_signed && cell->type != ID($sub)) {
90 int ab_width = std::max(a_width, b_width);
91 y_width = std::min(y_width, ab_width+1);
92 }
93
94 for (int i = 0; i < y_width; i++)
95 {
96 for (int k = 0; k <= i; k++)
97 {
98 if (k < a_width)
99 db->add_edge(cell, ID::A, k, ID::Y, i, -1);
100
101 if (k < b_width)
102 db->add_edge(cell, ID::B, k, ID::Y, i, -1);
103 }
104 }
105 }
106
107 void reduce_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
108 {
109 int a_width = GetSize(cell->getPort(ID::A));
110
111 for (int i = 0; i < a_width; i++)
112 db->add_edge(cell, ID::A, i, ID::Y, 0, -1);
113 }
114
115 void compare_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
116 {
117 int a_width = GetSize(cell->getPort(ID::A));
118 int b_width = GetSize(cell->getPort(ID::B));
119
120 for (int i = 0; i < a_width; i++)
121 db->add_edge(cell, ID::A, i, ID::Y, 0, -1);
122
123 for (int i = 0; i < b_width; i++)
124 db->add_edge(cell, ID::B, i, ID::Y, 0, -1);
125 }
126
127 void mux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
128 {
129 int a_width = GetSize(cell->getPort(ID::A));
130 int b_width = GetSize(cell->getPort(ID::B));
131 int s_width = GetSize(cell->getPort(ID::S));
132
133 for (int i = 0; i < a_width; i++)
134 {
135 db->add_edge(cell, ID::A, i, ID::Y, i, -1);
136
137 for (int k = i; k < b_width; k += a_width)
138 db->add_edge(cell, ID::B, k, ID::Y, i, -1);
139
140 for (int k = 0; k < s_width; k++)
141 db->add_edge(cell, ID::S, k, ID::Y, i, -1);
142 }
143 }
144
145 PRIVATE_NAMESPACE_END
146
147 bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL::Cell *cell)
148 {
149 if (cell->type.in(ID($not), ID($pos))) {
150 bitwise_unary_op(this, cell);
151 return true;
152 }
153
154 if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor))) {
155 bitwise_binary_op(this, cell);
156 return true;
157 }
158
159 if (cell->type == ID($neg)) {
160 arith_neg_op(this, cell);
161 return true;
162 }
163
164 if (cell->type.in(ID($add), ID($sub))) {
165 arith_binary_op(this, cell);
166 return true;
167 }
168
169 if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($logic_not))) {
170 reduce_op(this, cell);
171 return true;
172 }
173
174 // FIXME:
175 // if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) {
176 // shift_op(this, cell);
177 // return true;
178 // }
179
180 if (cell->type.in(ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt))) {
181 compare_op(this, cell);
182 return true;
183 }
184
185 if (cell->type.in(ID($mux), ID($pmux))) {
186 mux_op(this, cell);
187 return true;
188 }
189
190 // FIXME: $mul $div $mod $divfloor $modfloor $slice $concat
191 // FIXME: $lut $sop $alu $lcu $macc $fa
192
193 return false;
194 }
195