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;
110 int config_width
= cell
->getParam(ID::CONFIG_WIDTH
).as_int();
111 log_assert(GetSize(config_bits
) >= config_width
);
114 if (config_bits
[config_cursor
++] == State::S1
) num_bits
|= 1;
115 if (config_bits
[config_cursor
++] == State::S1
) num_bits
|= 2;
116 if (config_bits
[config_cursor
++] == State::S1
) num_bits
|= 4;
117 if (config_bits
[config_cursor
++] == State::S1
) num_bits
|= 8;
119 int port_a_cursor
= 0;
120 while (port_a_cursor
< GetSize(port_a
))
122 log_assert(config_cursor
+ 2 + 2*num_bits
<= config_width
);
125 this_port
.is_signed
= config_bits
[config_cursor
++] == State::S1
;
126 this_port
.do_subtract
= config_bits
[config_cursor
++] == State::S1
;
129 for (int i
= 0; i
< num_bits
; i
++)
130 if (config_bits
[config_cursor
++] == State::S1
)
133 this_port
.in_a
= port_a
.extract(port_a_cursor
, size_a
);
134 port_a_cursor
+= size_a
;
137 for (int i
= 0; i
< num_bits
; i
++)
138 if (config_bits
[config_cursor
++] == State::S1
)
141 this_port
.in_b
= port_a
.extract(port_a_cursor
, size_b
);
142 port_a_cursor
+= size_b
;
144 if (size_a
|| size_b
)
145 ports
.push_back(this_port
);
148 log_assert(config_cursor
== config_width
);
149 log_assert(port_a_cursor
== GetSize(port_a
));
152 void to_cell(RTLIL::Cell
*cell
) const
154 RTLIL::SigSpec port_a
;
155 std::vector
<RTLIL::State
> config_bits
;
156 int max_size
= 0, num_bits
= 0;
158 for (auto &port
: ports
) {
159 max_size
= max(max_size
, GetSize(port
.in_a
));
160 max_size
= max(max_size
, GetSize(port
.in_b
));
164 num_bits
++, max_size
/= 2;
166 log_assert(num_bits
< 16);
167 config_bits
.push_back(num_bits
& 1 ? State::S1
: State::S0
);
168 config_bits
.push_back(num_bits
& 2 ? State::S1
: State::S0
);
169 config_bits
.push_back(num_bits
& 4 ? State::S1
: State::S0
);
170 config_bits
.push_back(num_bits
& 8 ? State::S1
: State::S0
);
172 for (auto &port
: ports
)
174 if (GetSize(port
.in_a
) == 0)
177 config_bits
.push_back(port
.is_signed
? State::S1
: State::S0
);
178 config_bits
.push_back(port
.do_subtract
? State::S1
: State::S0
);
180 int size_a
= GetSize(port
.in_a
);
181 for (int i
= 0; i
< num_bits
; i
++)
182 config_bits
.push_back(size_a
& (1 << i
) ? State::S1
: State::S0
);
184 int size_b
= GetSize(port
.in_b
);
185 for (int i
= 0; i
< num_bits
; i
++)
186 config_bits
.push_back(size_b
& (1 << i
) ? State::S1
: State::S0
);
188 port_a
.append(port
.in_a
);
189 port_a
.append(port
.in_b
);
192 cell
->setPort(ID::A
, port_a
);
193 cell
->setPort(ID::B
, bit_ports
);
194 cell
->setParam(ID::CONFIG
, config_bits
);
195 cell
->setParam(ID::CONFIG_WIDTH
, GetSize(config_bits
));
196 cell
->setParam(ID::A_WIDTH
, GetSize(port_a
));
197 cell
->setParam(ID::B_WIDTH
, GetSize(bit_ports
));
200 bool eval(RTLIL::Const
&result
) const
202 for (auto &bit
: result
.bits
)
205 for (auto &port
: ports
)
207 if (!port
.in_a
.is_fully_const() || !port
.in_b
.is_fully_const())
210 RTLIL::Const summand
;
211 if (GetSize(port
.in_b
) == 0)
212 summand
= const_pos(port
.in_a
.as_const(), port
.in_b
.as_const(), port
.is_signed
, port
.is_signed
, GetSize(result
));
214 summand
= const_mul(port
.in_a
.as_const(), port
.in_b
.as_const(), port
.is_signed
, port
.is_signed
, GetSize(result
));
216 if (port
.do_subtract
)
217 result
= const_sub(result
, summand
, port
.is_signed
, port
.is_signed
, GetSize(result
));
219 result
= const_add(result
, summand
, port
.is_signed
, port
.is_signed
, GetSize(result
));
222 for (auto bit
: bit_ports
) {
225 result
= const_add(result
, bit
.data
, false, false, GetSize(result
));
231 Macc(RTLIL::Cell
*cell
= nullptr)