Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add $macc_v2 #4818

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/source/cell/word_arith.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Coarse arithmetics
------------------

.. todo:: Add information about `$alu`, `$fa`, and `$lcu` cells.
.. todo:: Add information about `$alu`, `$fa`, `$macc_v2`, and `$lcu` cells.

The `$macc` cell type represents a generalized multiply and accumulate
operation. The cell is purely combinational. It outputs the result of summing up
Expand Down
2 changes: 1 addition & 1 deletion docs/source/code_examples/fifo/fifo.ys
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ show -color maroon3 @new_cells -notitle -format dot -prefix rdata_memrdv2 o:rdat
# ========================================================

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

# ========================================================
Expand Down
2 changes: 1 addition & 1 deletion docs/source/getting_started/example_synth.rst
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,7 @@ That brings us to the fourth and final part for the iCE40 synthesis flow:
:name: synth_coarse4

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

Expand Down
2 changes: 1 addition & 1 deletion kernel/celledges.cc
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL
}

// FIXME: $mul $div $mod $divfloor $modfloor $slice $concat
// FIXME: $lut $sop $alu $lcu $macc $fa
// FIXME: $lut $sop $alu $lcu $macc $macc_v2 $fa
// FIXME: $mul $div $mod $divfloor $modfloor $pow $slice $concat $bweqx
// FIXME: $lut $sop $alu $lcu $macc $fa $logic_and $logic_or $bwmux

Expand Down
1 change: 1 addition & 0 deletions kernel/celltypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ struct CellTypes

setup_type(ID($lcu), {ID::P, ID::G, ID::CI}, {ID::CO}, true);
setup_type(ID($alu), {ID::A, ID::B, ID::CI, ID::BI}, {ID::X, ID::Y, ID::CO}, true);
setup_type(ID($macc_v2), {ID::A, ID::B, ID::C}, {ID::Y}, true);
setup_type(ID($fa), {ID::A, ID::B, ID::C}, {ID::X, ID::Y}, true);
}

Expand Down
2 changes: 1 addition & 1 deletion kernel/consteval.h
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ struct ConstEval
}
}
}
else if (cell->type == ID($macc))
else if (cell->type.in(ID($macc), ID($macc_v2)))
{
Macc macc;
macc.from_cell(cell);
Expand Down
8 changes: 8 additions & 0 deletions kernel/constids.inc
Original file line number Diff line number Diff line change
Expand Up @@ -276,3 +276,11 @@ X(Y)
X(Y_WIDTH)
X(area)
X(capacitance)
X(NPRODUCTS)
X(NADDENDS)
X(PRODUCT_NEGATED)
X(ADDEND_NEGATED)
X(A_WIDTHS)
X(B_WIDTHS)
X(C_WIDTHS)
X(C_SIGNED)
131 changes: 95 additions & 36 deletions kernel/macc.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ struct Macc
new_ports.swap(ports);
}

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

Expand Down Expand Up @@ -136,52 +136,111 @@ struct Macc
log_assert(port_a_cursor == GetSize(port_a));
}

void to_cell(RTLIL::Cell *cell) const
void from_cell(RTLIL::Cell *cell)
{
RTLIL::SigSpec port_a;
std::vector<RTLIL::State> config_bits;
int max_size = 0, num_bits = 0;

for (auto &port : ports) {
max_size = max(max_size, GetSize(port.in_a));
max_size = max(max_size, GetSize(port.in_b));
if (cell->type == ID($macc)) {
from_cell_v1(cell);
return;
}
log_assert(cell->type == ID($macc_v2));

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

log_assert(num_bits < 16);
config_bits.push_back(num_bits & 1 ? State::S1 : State::S0);
config_bits.push_back(num_bits & 2 ? State::S1 : State::S0);
config_bits.push_back(num_bits & 4 ? State::S1 : State::S0);
config_bits.push_back(num_bits & 8 ? State::S1 : State::S0);
ports.clear();

for (auto &port : ports)
{
if (GetSize(port.in_a) == 0)
continue;
int nproducts = cell->getParam(ID::NPRODUCTS).as_int();
const Const &product_neg = cell->getParam(ID::PRODUCT_NEGATED);
const Const &a_widths = cell->getParam(ID::A_WIDTHS);
const Const &b_widths = cell->getParam(ID::B_WIDTHS);
const Const &a_signed = cell->getParam(ID::A_SIGNED);
const Const &b_signed = cell->getParam(ID::B_SIGNED);
int ai = 0, bi = 0;
for (int i = 0; i < nproducts; i++) {
port_t term;

log_assert(a_signed[i] == b_signed[i]);
term.is_signed = (a_signed[i] == State::S1);
int a_width = a_widths.extract(16 * i, 16).as_int(false);
int b_width = b_widths.extract(16 * i, 16).as_int(false);

term.in_a = port_a.extract(ai, a_width);
ai += a_width;
term.in_b = port_b.extract(bi, b_width);
bi += b_width;
term.do_subtract = (product_neg[i] == State::S1);

ports.push_back(term);
}
log_assert(port_a.size() == ai);
log_assert(port_b.size() == bi);

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

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

int size_b = GetSize(port.in_b);
for (int i = 0; i < num_bits; i++)
config_bits.push_back(size_b & (1 << i) ? State::S1 : State::S0);
term.in_a = port_c.extract(ci, c_width);
ci += c_width;
term.do_subtract = (addend_neg[i] == State::S1);

ports.push_back(term);
}
log_assert(port_c.size() == ci);
}

port_a.append(port.in_a);
port_a.append(port.in_b);
void to_cell(RTLIL::Cell *cell)
{
cell->type = ID($macc_v2);

int nproducts = 0, naddends = 0;
Const a_signed, b_signed, a_widths, b_widths, product_negated;
Const c_signed, c_widths, addend_negated;
SigSpec a, b, c;

for (int i = 0; i < (int) ports.size(); i++) {
SigSpec term_a = ports[i].in_a, term_b = ports[i].in_b;

if (term_b.empty()) {
// addend
c_widths.append(Const(term_a.size(), 16));
c_signed.append(ports[i].is_signed ? RTLIL::S1 : RTLIL::S0);
addend_negated.append(ports[i].do_subtract ? RTLIL::S1 : RTLIL::S0);
c.append(term_a);
naddends++;
} else {
// product
a_widths.append(Const(term_a.size(), 16));
b_widths.append(Const(term_b.size(), 16));
a_signed.append(ports[i].is_signed ? RTLIL::S1 : RTLIL::S0);
b_signed.append(ports[i].is_signed ? RTLIL::S1 : RTLIL::S0);
product_negated.append(ports[i].do_subtract ? RTLIL::S1 : RTLIL::S0);
a.append(term_a);
b.append(term_b);
nproducts++;
}
}

cell->setPort(ID::A, port_a);
cell->setPort(ID::B, {});
cell->setParam(ID::CONFIG, config_bits);
cell->setParam(ID::CONFIG_WIDTH, GetSize(config_bits));
cell->setParam(ID::A_WIDTH, GetSize(port_a));
cell->setParam(ID::B_WIDTH, 0);
cell->setParam(ID::NPRODUCTS, nproducts);
cell->setParam(ID::PRODUCT_NEGATED, product_negated);
cell->setParam(ID::NADDENDS, naddends);
cell->setParam(ID::ADDEND_NEGATED, addend_negated);
cell->setParam(ID::A_SIGNED, a_signed);
cell->setParam(ID::B_SIGNED, b_signed);
cell->setParam(ID::C_SIGNED, c_signed);
cell->setParam(ID::A_WIDTHS, a_widths);
cell->setParam(ID::B_WIDTHS, b_widths);
cell->setParam(ID::C_WIDTHS, c_widths);
cell->setPort(ID::A, a);
cell->setPort(ID::B, b);
cell->setPort(ID::C, c);
}

bool eval(RTLIL::Const &result) const
Expand Down
45 changes: 45 additions & 0 deletions kernel/rtlil.cc
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,12 @@ void RTLIL::Const::bitvectorize() const {
}
}

void RTLIL::Const::append(const RTLIL::Const &other) {
bitvectorize();
bitvectype& bv = get_bits();
bv.insert(bv.end(), other.begin(), other.end());
}

RTLIL::State RTLIL::Const::const_iterator::operator*() const {
if (auto bv = parent.get_if_bits())
return (*bv)[idx];
Expand Down Expand Up @@ -1461,6 +1467,40 @@ namespace {
return;
}

if (cell->type == ID($macc_v2)) {
if (param(ID::NPRODUCTS) <= 0)
error(__LINE__);
if (param(ID::NADDENDS) <= 0)
error(__LINE__);
param_bits(ID::PRODUCT_NEGATED, min(param(ID::NPRODUCTS), 1));
param_bits(ID::ADDEND_NEGATED, min(param(ID::NADDENDS), 1));
param_bits(ID::A_SIGNED, min(param(ID::NPRODUCTS), 1));
param_bits(ID::B_SIGNED, min(param(ID::NPRODUCTS), 1));
param_bits(ID::C_SIGNED, min(param(ID::NADDENDS), 1));
if (cell->getParam(ID::A_SIGNED) != cell->getParam(ID::B_SIGNED))
error(__LINE__);
param_bits(ID::A_WIDTHS, min(param(ID::NPRODUCTS) * 16, 1));
param_bits(ID::B_WIDTHS, min(param(ID::NPRODUCTS) * 16, 1));
param_bits(ID::C_WIDTHS, min(param(ID::NADDENDS) * 16, 1));
const Const &a_width = cell->getParam(ID::A_WIDTHS);
const Const &b_width = cell->getParam(ID::B_WIDTHS);
const Const &c_width = cell->getParam(ID::C_WIDTHS);
int a_width_sum = 0, b_width_sum = 0, c_width_sum = 0;
for (int i = 0; i < param(ID::NPRODUCTS); i++) {
a_width_sum += a_width.extract(16 * i, 16).as_int(false);
b_width_sum += b_width.extract(16 * i, 16).as_int(false);
}
for (int i = 0; i < param(ID::NADDENDS); i++) {
c_width_sum += c_width.extract(16 * i, 16).as_int(false);
}
port(ID::A, a_width_sum);
port(ID::B, b_width_sum);
port(ID::C, c_width_sum);
port(ID::Y, param(ID::Y_WIDTH));
check_expected();
return;
}

if (cell->type == ID($logic_not)) {
param_bool(ID::A_SIGNED);
port(ID::A, param(ID::A_WIDTH));
Expand Down Expand Up @@ -4093,6 +4133,11 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
return;
}

if (type == ID($macc_v2)) {
parameters[ID::Y_WIDTH] = GetSize(connections_[ID::Y]);
return;
}

bool signedness_ab = !type.in(ID($slice), ID($concat), ID($macc));

if (connections_.count(ID::A)) {
Expand Down
2 changes: 2 additions & 0 deletions kernel/rtlil.h
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,8 @@ struct RTLIL::Const
bool empty() const;
void bitvectorize() const;

void append(const RTLIL::Const &other);

class const_iterator {
private:
const Const& parent;
Expand Down
2 changes: 1 addition & 1 deletion kernel/satgen.cc
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
return true;
}

if (cell->type == ID($macc))
if (cell->type.in(ID($macc), ID($macc_v2)))
{
std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
Expand Down
2 changes: 1 addition & 1 deletion passes/techmap/booth.cc
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ struct BoothPassWorker {

log_assert(cell->getParam(ID::A_SIGNED).as_bool() == cell->getParam(ID::B_SIGNED).as_bool());
is_signed = cell->getParam(ID::A_SIGNED).as_bool();
} else if (cell->type == ID($macc)) {
} else if (cell->type.in(ID($macc), ID($macc_v2))) {
Macc macc;
macc.from_cell(cell);

Expand Down
2 changes: 1 addition & 1 deletion passes/techmap/maccmap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ struct MaccmapPass : public Pass {

for (auto mod : design->selected_modules())
for (auto cell : mod->selected_cells())
if (cell->type == ID($macc)) {
if (cell->type.in(ID($macc), ID($macc_v2))) {
log("Mapping %s.%s (%s).\n", log_id(mod), log_id(cell), log_id(cell->type));
maccmap(mod, cell, unmap_mode);
mod->remove(cell);
Expand Down
Loading
Loading