Skip to content

Commit 6da543a

Browse files
authored
Merge pull request #4818 from povik/macc_v2
Add `$macc_v2`
2 parents 65748b8 + 1d57a7c commit 6da543a

File tree

18 files changed

+375
-49
lines changed

18 files changed

+375
-49
lines changed

docs/source/cell/word_arith.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Coarse arithmetics
22
------------------
33

4-
.. todo:: Add information about `$alu`, `$fa`, and `$lcu` cells.
4+
.. todo:: Add information about `$alu`, `$fa`, `$macc_v2`, and `$lcu` cells.
55

66
The `$macc` cell type represents a generalized multiply and accumulate
77
operation. The cell is purely combinational. It outputs the result of summing up

docs/source/code_examples/fifo/fifo.ys

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ show -color maroon3 @new_cells -notitle -format dot -prefix rdata_memrdv2 o:rdat
6767
# ========================================================
6868

6969
alumacc
70-
select -set new_cells t:$alu t:$macc
70+
select -set new_cells t:$alu t:$macc_v2
7171
show -color maroon3 @new_cells -notitle -format dot -prefix rdata_alumacc o:rdata %ci*
7272

7373
# ========================================================

docs/source/getting_started/example_synth.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ That brings us to the fourth and final part for the iCE40 synthesis flow:
523523
:name: synth_coarse4
524524

525525
Where before each type of arithmetic operation had its own cell, e.g. `$add`, we
526-
now want to extract these into `$alu` and `$macc` cells which can help identify
526+
now want to extract these into `$alu` and `$macc_v2` cells which can help identify
527527
opportunities for reusing logic. We do this by running `alumacc`, which we can
528528
see produce the following changes in our example design:
529529

kernel/celledges.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL
453453
}
454454

455455
// FIXME: $mul $div $mod $divfloor $modfloor $slice $concat
456-
// FIXME: $lut $sop $alu $lcu $macc $fa
456+
// FIXME: $lut $sop $alu $lcu $macc $macc_v2 $fa
457457
// FIXME: $mul $div $mod $divfloor $modfloor $pow $slice $concat $bweqx
458458
// FIXME: $lut $sop $alu $lcu $macc $fa $logic_and $logic_or $bwmux
459459

kernel/celltypes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ struct CellTypes
144144

145145
setup_type(ID($lcu), {ID::P, ID::G, ID::CI}, {ID::CO}, true);
146146
setup_type(ID($alu), {ID::A, ID::B, ID::CI, ID::BI}, {ID::X, ID::Y, ID::CO}, true);
147+
setup_type(ID($macc_v2), {ID::A, ID::B, ID::C}, {ID::Y}, true);
147148
setup_type(ID($fa), {ID::A, ID::B, ID::C}, {ID::X, ID::Y}, true);
148149
}
149150

kernel/consteval.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ struct ConstEval
310310
}
311311
}
312312
}
313-
else if (cell->type == ID($macc))
313+
else if (cell->type.in(ID($macc), ID($macc_v2)))
314314
{
315315
Macc macc;
316316
macc.from_cell(cell);

kernel/constids.inc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,3 +276,11 @@ X(Y)
276276
X(Y_WIDTH)
277277
X(area)
278278
X(capacitance)
279+
X(NPRODUCTS)
280+
X(NADDENDS)
281+
X(PRODUCT_NEGATED)
282+
X(ADDEND_NEGATED)
283+
X(A_WIDTHS)
284+
X(B_WIDTHS)
285+
X(C_WIDTHS)
286+
X(C_SIGNED)

kernel/macc.h

Lines changed: 112 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ struct Macc
8282
new_ports.swap(ports);
8383
}
8484

85-
void from_cell(RTLIL::Cell *cell)
85+
void from_cell_v1(RTLIL::Cell *cell)
8686
{
8787
RTLIL::SigSpec port_a = cell->getPort(ID::A);
8888

@@ -136,52 +136,128 @@ struct Macc
136136
log_assert(port_a_cursor == GetSize(port_a));
137137
}
138138

139-
void to_cell(RTLIL::Cell *cell) const
139+
void from_cell(RTLIL::Cell *cell)
140140
{
141-
RTLIL::SigSpec port_a;
142-
std::vector<RTLIL::State> config_bits;
143-
int max_size = 0, num_bits = 0;
144-
145-
for (auto &port : ports) {
146-
max_size = max(max_size, GetSize(port.in_a));
147-
max_size = max(max_size, GetSize(port.in_b));
141+
if (cell->type == ID($macc)) {
142+
from_cell_v1(cell);
143+
return;
148144
}
145+
log_assert(cell->type == ID($macc_v2));
149146

150-
while (max_size)
151-
num_bits++, max_size /= 2;
147+
RTLIL::SigSpec port_a = cell->getPort(ID::A);
148+
RTLIL::SigSpec port_b = cell->getPort(ID::B);
149+
RTLIL::SigSpec port_c = cell->getPort(ID::C);
152150

153-
log_assert(num_bits < 16);
154-
config_bits.push_back(num_bits & 1 ? State::S1 : State::S0);
155-
config_bits.push_back(num_bits & 2 ? State::S1 : State::S0);
156-
config_bits.push_back(num_bits & 4 ? State::S1 : State::S0);
157-
config_bits.push_back(num_bits & 8 ? State::S1 : State::S0);
151+
ports.clear();
158152

159-
for (auto &port : ports)
160-
{
161-
if (GetSize(port.in_a) == 0)
162-
continue;
153+
int nproducts = cell->getParam(ID::NPRODUCTS).as_int();
154+
const Const &product_neg = cell->getParam(ID::PRODUCT_NEGATED);
155+
const Const &a_widths = cell->getParam(ID::A_WIDTHS);
156+
const Const &b_widths = cell->getParam(ID::B_WIDTHS);
157+
const Const &a_signed = cell->getParam(ID::A_SIGNED);
158+
const Const &b_signed = cell->getParam(ID::B_SIGNED);
159+
int ai = 0, bi = 0;
160+
for (int i = 0; i < nproducts; i++) {
161+
port_t term;
162+
163+
log_assert(a_signed[i] == b_signed[i]);
164+
term.is_signed = (a_signed[i] == State::S1);
165+
int a_width = a_widths.extract(16 * i, 16).as_int(false);
166+
int b_width = b_widths.extract(16 * i, 16).as_int(false);
167+
168+
term.in_a = port_a.extract(ai, a_width);
169+
ai += a_width;
170+
term.in_b = port_b.extract(bi, b_width);
171+
bi += b_width;
172+
term.do_subtract = (product_neg[i] == State::S1);
173+
174+
ports.push_back(term);
175+
}
176+
log_assert(port_a.size() == ai);
177+
log_assert(port_b.size() == bi);
163178

164-
config_bits.push_back(port.is_signed ? State::S1 : State::S0);
165-
config_bits.push_back(port.do_subtract ? State::S1 : State::S0);
179+
int naddends = cell->getParam(ID::NADDENDS).as_int();
180+
const Const &addend_neg = cell->getParam(ID::ADDEND_NEGATED);
181+
const Const &c_widths = cell->getParam(ID::C_WIDTHS);
182+
const Const &c_signed = cell->getParam(ID::C_SIGNED);
183+
int ci = 0;
184+
for (int i = 0; i < naddends; i++) {
185+
port_t term;
166186

167-
int size_a = GetSize(port.in_a);
168-
for (int i = 0; i < num_bits; i++)
169-
config_bits.push_back(size_a & (1 << i) ? State::S1 : State::S0);
187+
term.is_signed = (c_signed[i] == State::S1);
188+
int c_width = c_widths.extract(16 * i, 16).as_int(false);
170189

171-
int size_b = GetSize(port.in_b);
172-
for (int i = 0; i < num_bits; i++)
173-
config_bits.push_back(size_b & (1 << i) ? State::S1 : State::S0);
190+
term.in_a = port_c.extract(ci, c_width);
191+
ci += c_width;
192+
term.do_subtract = (addend_neg[i] == State::S1);
193+
194+
ports.push_back(term);
195+
}
196+
log_assert(port_c.size() == ci);
197+
}
174198

175-
port_a.append(port.in_a);
176-
port_a.append(port.in_b);
199+
void to_cell(RTLIL::Cell *cell)
200+
{
201+
cell->type = ID($macc_v2);
202+
203+
int nproducts = 0, naddends = 0;
204+
Const a_signed, b_signed, a_widths, b_widths, product_negated;
205+
Const c_signed, c_widths, addend_negated;
206+
SigSpec a, b, c;
207+
208+
for (int i = 0; i < (int) ports.size(); i++) {
209+
SigSpec term_a = ports[i].in_a, term_b = ports[i].in_b;
210+
211+
if (term_b.empty()) {
212+
// addend
213+
c_widths.append(Const(term_a.size(), 16));
214+
c_signed.append(ports[i].is_signed ? RTLIL::S1 : RTLIL::S0);
215+
addend_negated.append(ports[i].do_subtract ? RTLIL::S1 : RTLIL::S0);
216+
c.append(term_a);
217+
naddends++;
218+
} else {
219+
// product
220+
a_widths.append(Const(term_a.size(), 16));
221+
b_widths.append(Const(term_b.size(), 16));
222+
a_signed.append(ports[i].is_signed ? RTLIL::S1 : RTLIL::S0);
223+
b_signed.append(ports[i].is_signed ? RTLIL::S1 : RTLIL::S0);
224+
product_negated.append(ports[i].do_subtract ? RTLIL::S1 : RTLIL::S0);
225+
a.append(term_a);
226+
b.append(term_b);
227+
nproducts++;
228+
}
177229
}
178230

179-
cell->setPort(ID::A, port_a);
180-
cell->setPort(ID::B, {});
181-
cell->setParam(ID::CONFIG, config_bits);
182-
cell->setParam(ID::CONFIG_WIDTH, GetSize(config_bits));
183-
cell->setParam(ID::A_WIDTH, GetSize(port_a));
184-
cell->setParam(ID::B_WIDTH, 0);
231+
if (a_signed.empty())
232+
a_signed = {RTLIL::Sx};
233+
if (b_signed.empty())
234+
b_signed = {RTLIL::Sx};
235+
if (c_signed.empty())
236+
c_signed = {RTLIL::Sx};
237+
if (a_widths.empty())
238+
a_widths = {RTLIL::Sx};
239+
if (b_widths.empty())
240+
b_widths = {RTLIL::Sx};
241+
if (c_widths.empty())
242+
c_widths = {RTLIL::Sx};
243+
if (product_negated.empty())
244+
product_negated = {RTLIL::Sx};
245+
if (addend_negated.empty())
246+
addend_negated = {RTLIL::Sx};
247+
248+
cell->setParam(ID::NPRODUCTS, nproducts);
249+
cell->setParam(ID::PRODUCT_NEGATED, product_negated);
250+
cell->setParam(ID::NADDENDS, naddends);
251+
cell->setParam(ID::ADDEND_NEGATED, addend_negated);
252+
cell->setParam(ID::A_SIGNED, a_signed);
253+
cell->setParam(ID::B_SIGNED, b_signed);
254+
cell->setParam(ID::C_SIGNED, c_signed);
255+
cell->setParam(ID::A_WIDTHS, a_widths);
256+
cell->setParam(ID::B_WIDTHS, b_widths);
257+
cell->setParam(ID::C_WIDTHS, c_widths);
258+
cell->setPort(ID::A, a);
259+
cell->setPort(ID::B, b);
260+
cell->setPort(ID::C, c);
185261
}
186262

187263
bool eval(RTLIL::Const &result) const

kernel/rtlil.cc

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,12 @@ void RTLIL::Const::bitvectorize() const {
540540
}
541541
}
542542

543+
void RTLIL::Const::append(const RTLIL::Const &other) {
544+
bitvectorize();
545+
bitvectype& bv = get_bits();
546+
bv.insert(bv.end(), other.begin(), other.end());
547+
}
548+
543549
RTLIL::State RTLIL::Const::const_iterator::operator*() const {
544550
if (auto bv = parent.get_if_bits())
545551
return (*bv)[idx];
@@ -1461,6 +1467,40 @@ namespace {
14611467
return;
14621468
}
14631469

1470+
if (cell->type == ID($macc_v2)) {
1471+
if (param(ID::NPRODUCTS) < 0)
1472+
error(__LINE__);
1473+
if (param(ID::NADDENDS) < 0)
1474+
error(__LINE__);
1475+
param_bits(ID::PRODUCT_NEGATED, max(param(ID::NPRODUCTS), 1));
1476+
param_bits(ID::ADDEND_NEGATED, max(param(ID::NADDENDS), 1));
1477+
param_bits(ID::A_SIGNED, max(param(ID::NPRODUCTS), 1));
1478+
param_bits(ID::B_SIGNED, max(param(ID::NPRODUCTS), 1));
1479+
param_bits(ID::C_SIGNED, max(param(ID::NADDENDS), 1));
1480+
if (cell->getParam(ID::A_SIGNED) != cell->getParam(ID::B_SIGNED))
1481+
error(__LINE__);
1482+
param_bits(ID::A_WIDTHS, max(param(ID::NPRODUCTS) * 16, 1));
1483+
param_bits(ID::B_WIDTHS, max(param(ID::NPRODUCTS) * 16, 1));
1484+
param_bits(ID::C_WIDTHS, max(param(ID::NADDENDS) * 16, 1));
1485+
const Const &a_width = cell->getParam(ID::A_WIDTHS);
1486+
const Const &b_width = cell->getParam(ID::B_WIDTHS);
1487+
const Const &c_width = cell->getParam(ID::C_WIDTHS);
1488+
int a_width_sum = 0, b_width_sum = 0, c_width_sum = 0;
1489+
for (int i = 0; i < param(ID::NPRODUCTS); i++) {
1490+
a_width_sum += a_width.extract(16 * i, 16).as_int(false);
1491+
b_width_sum += b_width.extract(16 * i, 16).as_int(false);
1492+
}
1493+
for (int i = 0; i < param(ID::NADDENDS); i++) {
1494+
c_width_sum += c_width.extract(16 * i, 16).as_int(false);
1495+
}
1496+
port(ID::A, a_width_sum);
1497+
port(ID::B, b_width_sum);
1498+
port(ID::C, c_width_sum);
1499+
port(ID::Y, param(ID::Y_WIDTH));
1500+
check_expected();
1501+
return;
1502+
}
1503+
14641504
if (cell->type == ID($logic_not)) {
14651505
param_bool(ID::A_SIGNED);
14661506
port(ID::A, param(ID::A_WIDTH));
@@ -4093,6 +4133,11 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
40934133
return;
40944134
}
40954135

4136+
if (type == ID($macc_v2)) {
4137+
parameters[ID::Y_WIDTH] = GetSize(connections_[ID::Y]);
4138+
return;
4139+
}
4140+
40964141
bool signedness_ab = !type.in(ID($slice), ID($concat), ID($macc));
40974142

40984143
if (connections_.count(ID::A)) {

kernel/rtlil.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,8 @@ struct RTLIL::Const
738738
bool empty() const;
739739
void bitvectorize() const;
740740

741+
void append(const RTLIL::Const &other);
742+
741743
class const_iterator {
742744
private:
743745
const Const& parent;

0 commit comments

Comments
 (0)