e9f6f05e914fdc36f41a7835fc1446d55ed4a2a2
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.
23 #include "kernel/yosys.h"
30 RTLIL::SigSpec in_a
, in_b
;
31 bool is_signed
, do_subtract
;
34 std::vector
<port_t
> ports
;
35 RTLIL::SigSpec bit_ports
;
37 void optimize(int width
)
39 std::vector
<port_t
> new_ports
;
40 RTLIL::SigSpec new_bit_ports
;
41 RTLIL::Const
off(0, width
);
43 for (auto &port
: ports
)
45 if (GetSize(port
.in_a
) == 0 && GetSize(port
.in_b
) == 0)
48 if (GetSize(port
.in_a
) < GetSize(port
.in_b
))
49 std::swap(port
.in_a
, port
.in_b
);
51 if (GetSize(port
.in_a
) == 1 && GetSize(port
.in_b
) == 0 && !port
.is_signed
&& !port
.do_subtract
) {
52 bit_ports
.append(port
.in_a
);
56 if (port
.in_a
.is_fully_const() && port
.in_b
.is_fully_const()) {
57 RTLIL::Const v
= port
.in_a
.as_const();
58 if (GetSize(port
.in_b
))
59 v
= const_mul(v
, port
.in_b
.as_const(), port
.is_signed
, port
.is_signed
, width
);
61 off
= const_sub(off
, v
, port
.is_signed
, port
.is_signed
, width
);
63 off
= const_add(off
, v
, port
.is_signed
, port
.is_signed
, width
);
68 while (GetSize(port
.in_a
) > 1 && port
.in_a
[GetSize(port
.in_a
)-1] == port
.in_a
[GetSize(port
.in_a
)-2])
69 port
.in_a
.remove(GetSize(port
.in_a
)-1);
70 while (GetSize(port
.in_b
) > 1 && port
.in_b
[GetSize(port
.in_b
)-1] == port
.in_b
[GetSize(port
.in_b
)-2])
71 port
.in_b
.remove(GetSize(port
.in_b
)-1);
73 while (GetSize(port
.in_a
) > 1 && port
.in_a
[GetSize(port
.in_a
)-1] == State::S0
)
74 port
.in_a
.remove(GetSize(port
.in_a
)-1);
75 while (GetSize(port
.in_b
) > 1 && port
.in_b
[GetSize(port
.in_b
)-1] == State::S0
)
76 port
.in_b
.remove(GetSize(port
.in_b
)-1);
79 new_ports
.push_back(port
);
82 for (auto &bit
: bit_ports
)
84 off
= const_add(off
, RTLIL::Const(1, width
), false, false, width
);
85 else if (bit
!= State::S0
)
86 new_bit_ports
.append(bit
);
91 port
.is_signed
= false;
92 port
.do_subtract
= false;
93 new_ports
.push_back(port
);
96 new_ports
.swap(ports
);
97 bit_ports
= new_bit_ports
;
100 void from_cell(RTLIL::Cell
*cell
)
102 RTLIL::SigSpec port_a
= cell
->getPort(ID::A
);
105 bit_ports
= cell
->getPort(ID::B
);
107 std::vector
<RTLIL::State
> config_bits
= cell
->getParam(ID::CONFIG
).bits
;
108 int config_cursor
= 0;
111 int config_width
= cell
->getParam(ID::CONFIG_WIDTH
).as_int();
112 log_assert(GetSize(config_bits
) >= config_width
);
116 if (config_bits
[config_cursor
++] == State::S1
) num_bits
|= 1;
117 if (config_bits
[config_cursor
++] == State::S1
) num_bits
|= 2;
118 if (config_bits
[config_cursor
++] == State::S1
) num_bits
|= 4;
119 if (config_bits
[config_cursor
++] == State::S1
) num_bits
|= 8;
121 int port_a_cursor
= 0;
122 while (port_a_cursor
< GetSize(port_a
))
124 log_assert(config_cursor
+ 2 + 2*num_bits
<= config_width
);
127 this_port
.is_signed
= config_bits
[config_cursor
++] == State::S1
;
128 this_port
.do_subtract
= config_bits
[config_cursor
++] == State::S1
;
131 for (int i
= 0; i
< num_bits
; i
++)
132 if (config_bits
[config_cursor
++] == State::S1
)
135 this_port
.in_a
= port_a
.extract(port_a_cursor
, size_a
);
136 port_a_cursor
+= size_a
;
139 for (int i
= 0; i
< num_bits
; i
++)
140 if (config_bits
[config_cursor
++] == State::S1
)
143 this_port
.in_b
= port_a
.extract(port_a_cursor
, size_b
);
144 port_a_cursor
+= size_b
;
146 if (size_a
|| size_b
)
147 ports
.push_back(this_port
);
150 log_assert(config_cursor
== config_width
);
151 log_assert(port_a_cursor
== GetSize(port_a
));
154 void to_cell(RTLIL::Cell
*cell
) const
156 RTLIL::SigSpec port_a
;
157 std::vector
<RTLIL::State
> config_bits
;
158 int max_size
= 0, num_bits
= 0;
160 for (auto &port
: ports
) {
161 max_size
= max(max_size
, GetSize(port
.in_a
));
162 max_size
= max(max_size
, GetSize(port
.in_b
));
166 num_bits
++, max_size
/= 2;
168 log_assert(num_bits
< 16);
169 config_bits
.push_back(num_bits
& 1 ? State::S1
: State::S0
);
170 config_bits
.push_back(num_bits
& 2 ? State::S1
: State::S0
);
171 config_bits
.push_back(num_bits
& 4 ? State::S1
: State::S0
);
172 config_bits
.push_back(num_bits
& 8 ? State::S1
: State::S0
);
174 for (auto &port
: ports
)
176 if (GetSize(port
.in_a
) == 0)
179 config_bits
.push_back(port
.is_signed
? State::S1
: State::S0
);
180 config_bits
.push_back(port
.do_subtract
? State::S1
: State::S0
);
182 int size_a
= GetSize(port
.in_a
);
183 for (int i
= 0; i
< num_bits
; i
++)
184 config_bits
.push_back(size_a
& (1 << i
) ? State::S1
: State::S0
);
186 int size_b
= GetSize(port
.in_b
);
187 for (int i
= 0; i
< num_bits
; i
++)
188 config_bits
.push_back(size_b
& (1 << i
) ? State::S1
: State::S0
);
190 port_a
.append(port
.in_a
);
191 port_a
.append(port
.in_b
);
194 cell
->setPort(ID::A
, port_a
);
195 cell
->setPort(ID::B
, bit_ports
);
196 cell
->setParam(ID::CONFIG
, config_bits
);
197 cell
->setParam(ID::CONFIG_WIDTH
, GetSize(config_bits
));
198 cell
->setParam(ID::A_WIDTH
, GetSize(port_a
));
199 cell
->setParam(ID::B_WIDTH
, GetSize(bit_ports
));
202 bool eval(RTLIL::Const
&result
) const
204 for (auto &bit
: result
.bits
)
207 for (auto &port
: ports
)
209 if (!port
.in_a
.is_fully_const() || !port
.in_b
.is_fully_const())
212 RTLIL::Const summand
;
213 if (GetSize(port
.in_b
) == 0)
214 summand
= const_pos(port
.in_a
.as_const(), port
.in_b
.as_const(), port
.is_signed
, port
.is_signed
, GetSize(result
));
216 summand
= const_mul(port
.in_a
.as_const(), port
.in_b
.as_const(), port
.is_signed
, port
.is_signed
, GetSize(result
));
218 if (port
.do_subtract
)
219 result
= const_sub(result
, summand
, port
.is_signed
, port
.is_signed
, GetSize(result
));
221 result
= const_add(result
, summand
, port
.is_signed
, port
.is_signed
, GetSize(result
));
224 for (auto bit
: bit_ports
) {
227 result
= const_add(result
, bit
.data
, false, false, GetSize(result
));
233 Macc(RTLIL::Cell
*cell
= nullptr)