Merge pull request #3310 from robinsonb5-PRs/master
[yosys.git] / kernel / celledges.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
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 void bmux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
146 {
147 int width = GetSize(cell->getPort(ID::Y));
148 int a_width = GetSize(cell->getPort(ID::A));
149 int s_width = GetSize(cell->getPort(ID::S));
150
151 for (int i = 0; i < width; i++)
152 {
153 for (int k = i; k < a_width; k += width)
154 db->add_edge(cell, ID::A, k, ID::Y, i, -1);
155
156 for (int k = 0; k < s_width; k++)
157 db->add_edge(cell, ID::S, k, ID::Y, i, -1);
158 }
159 }
160
161 void demux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
162 {
163 int width = GetSize(cell->getPort(ID::Y));
164 int a_width = GetSize(cell->getPort(ID::A));
165 int s_width = GetSize(cell->getPort(ID::S));
166
167 for (int i = 0; i < width; i++)
168 {
169 db->add_edge(cell, ID::A, i % a_width, ID::Y, i, -1);
170 for (int k = 0; k < s_width; k++)
171 db->add_edge(cell, ID::S, k, ID::Y, i, -1);
172 }
173 }
174
175 PRIVATE_NAMESPACE_END
176
177 bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL::Cell *cell)
178 {
179 if (cell->type.in(ID($not), ID($pos))) {
180 bitwise_unary_op(this, cell);
181 return true;
182 }
183
184 if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor))) {
185 bitwise_binary_op(this, cell);
186 return true;
187 }
188
189 if (cell->type == ID($neg)) {
190 arith_neg_op(this, cell);
191 return true;
192 }
193
194 if (cell->type.in(ID($add), ID($sub))) {
195 arith_binary_op(this, cell);
196 return true;
197 }
198
199 if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($logic_not))) {
200 reduce_op(this, cell);
201 return true;
202 }
203
204 // FIXME:
205 // if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) {
206 // shift_op(this, cell);
207 // return true;
208 // }
209
210 if (cell->type.in(ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt))) {
211 compare_op(this, cell);
212 return true;
213 }
214
215 if (cell->type.in(ID($mux), ID($pmux))) {
216 mux_op(this, cell);
217 return true;
218 }
219
220 if (cell->type == ID($bmux)) {
221 bmux_op(this, cell);
222 return true;
223 }
224
225 if (cell->type == ID($demux)) {
226 demux_op(this, cell);
227 return true;
228 }
229
230 // FIXME: $mul $div $mod $divfloor $modfloor $slice $concat
231 // FIXME: $lut $sop $alu $lcu $macc $fa
232
233 return false;
234 }
235