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