3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-04-02 18:08:58 +00:00
This commit is contained in:
nella 2026-04-01 08:55:20 +02:00
parent d0e381506c
commit 5f2407f449
2 changed files with 23 additions and 86 deletions

View file

@ -1,3 +1,6 @@
// Replaces chains of $add/$sub and $macc cells with carry-save adder trees, reducing multi-operand
// addition to logarithmic depth. ref. paper: Zimmermann, "Architectures for Adders"
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/macc.h"
@ -88,6 +91,7 @@ struct AluInfo {
return GetSize(bi) == 1 && bi[0] == State::S0 && GetSize(ci) == 1 && ci[0] == State::S0;
}
// A cell is chainable if it's a plain add/sub with unused carries.
bool is_chainable(Cell* cell)
{
if (!(is_add(cell) || is_subtract(cell)))
@ -134,6 +138,7 @@ struct Rewriter
return consumer;
}
// Find cells that consumes another cell's output.
dict<Cell*, Cell*> find_parents(const pool<Cell*>& candidates)
{
dict<Cell*, Cell*> parent_of;
@ -207,7 +212,7 @@ struct Rewriter
const pool<Cell*>& chain,
Cell* root,
const dict<Cell*, Cell*>& parent_of,
int& correction
int& neg_compensation
) {
pool<SigBit> chain_bits = internal_bits(chain);
dict<Cell*, bool> negated;
@ -229,7 +234,7 @@ struct Rewriter
}
std::vector<Operand> operands;
correction = 0;
neg_compensation = 0;
for (auto cell : chain) {
bool cell_neg;
@ -247,21 +252,21 @@ struct Rewriter
if (!overlaps(a, chain_bits)) {
bool neg = cell_neg;
operands.push_back({a, a_signed, neg});
if (neg) correction++;
if (neg) neg_compensation++;
}
if (!overlaps(b, chain_bits)) {
bool neg = cell_neg ^ b_sub;
operands.push_back({b, b_signed, neg});
if (neg) correction++;
if (neg) neg_compensation++;
}
}
return operands;
}
bool extract_macc_operands(Cell* cell, std::vector<Operand>& operands, int& correction)
bool extract_macc_operands(Cell* cell, std::vector<Operand>& operands, int& neg_compensation)
{
Macc macc(cell);
correction = 0;
neg_compensation = 0;
for (auto& term : macc.terms) {
// Bail on multiplication
@ -269,7 +274,7 @@ struct Rewriter
return false;
operands.push_back({term.in_a, term.is_signed, term.do_subtract});
if (term.do_subtract)
correction++;
neg_compensation++;
}
return true;
}
@ -307,6 +312,7 @@ struct Rewriter
int depth;
};
// Group ready operands into triplets and compress via full adders until two operands remain.
std::pair<SigSpec, SigSpec> reduce_wallace(std::vector<SigSpec>& sigs, int width, int& fa_count)
{
std::vector<DepthSig> ops;
@ -356,7 +362,7 @@ struct Rewriter
void replace_with_csa_tree(
std::vector<Operand>& operands,
SigSpec result_y,
int correction,
int neg_compensation,
const char* desc
) {
int width = GetSize(result_y);
@ -370,8 +376,8 @@ struct Rewriter
extended.push_back(s);
}
if (correction > 0)
extended.push_back(SigSpec(correction, width));
if (neg_compensation > 0)
extended.push_back(SigSpec(neg_compensation, width));
int fa_count;
auto [a, b] = reduce_wallace(extended, width, fa_count);
@ -416,14 +422,12 @@ struct Rewriter
for (auto c : chain)
processed.insert(c);
int correction;
auto operands = extract_chain_operands(
chain, root, parent_of, correction);
int neg_compensation;
auto operands = extract_chain_operands(chain, root, parent_of, neg_compensation);
if (operands.size() < 3)
continue;
replace_with_csa_tree(operands, root->getPort(ID::Y),
correction, "Replaced add/sub chain");
replace_with_csa_tree(operands, root->getPort(ID::Y), neg_compensation, "Replaced add/sub chain");
for (auto cell : chain)
module->remove(cell);
}
@ -433,14 +437,13 @@ struct Rewriter
{
for (auto cell : cells.macc) {
std::vector<Operand> operands;
int correction;
if (!extract_macc_operands(cell, operands, correction))
int neg_compensation;
if (!extract_macc_operands(cell, operands, neg_compensation))
continue;
if (operands.size() < 3)
continue;
replace_with_csa_tree(operands, cell->getPort(ID::Y),
correction, "Replaced $macc");
replace_with_csa_tree(operands, cell->getPort(ID::Y), neg_compensation, "Replaced $macc");
module->remove(cell);
}
}
@ -458,8 +461,7 @@ void run(Module* module) {
}
struct CsaTreePass : public Pass {
CsaTreePass() : Pass("csa_tree",
"convert add/sub/macc chains to carry-save adder trees") {}
CsaTreePass() : Pass("csa_tree", "convert add/sub/macc chains to carry-save adder trees") {}
void help() override
{

View file

@ -1,65 +0,0 @@
read_verilog <<EOT
module bench(
input [7:0] a, b, c, d, e, f, g, h,
output [7:0] y
);
assign y = a + b + c + d + e + f + g + h;
endmodule
EOT
hierarchy -auto-top
proc
opt
techmap
abc -g AND,OR,XOR
select -assert-min 236 t:$_AND_ t:$_OR_ t:$_XOR_ %u
design -reset
read_verilog <<EOT
module bench(
input [7:0] a, b, c, d, e, f, g, h,
output [7:0] y
);
assign y = a + b + c + d + e + f + g + h;
endmodule
EOT
hierarchy -auto-top
proc
opt
csa_tree
techmap
abc -g AND,OR,XOR
select -assert-max 235 t:$_AND_ t:$_OR_ t:$_XOR_ %u
design -reset
read_verilog <<EOT
module bench(
input [7:0] a, b, c, d, e, f, g, h,
output [7:0] y
);
assign y = a + b + c + d + e + f + g + h;
endmodule
EOT
hierarchy -auto-top
proc
opt
techmap
abc -D 1
select -assert-min 240 t:$_AND_ t:$_NAND_ t:$_OR_ t:$_NOR_ t:$_XOR_ t:$_XNOR_ t:$_NOT_ %u
design -reset
read_verilog <<EOT
module bench(
input [7:0] a, b, c, d, e, f, g, h,
output [7:0] y
);
assign y = a + b + c + d + e + f + g + h;
endmodule
EOT
hierarchy -auto-top
proc
opt
csa_tree
techmap
abc -D 1
select -assert-max 236 t:$_AND_ t:$_NAND_ t:$_OR_ t:$_NOR_ t:$_XOR_ t:$_XNOR_ t:$_NOT_ %u
design -reset