mirror of
https://github.com/YosysHQ/yosys
synced 2026-06-01 14:47:53 +00:00
Clarify.
This commit is contained in:
parent
b6d656e932
commit
42c309347b
2 changed files with 23 additions and 86 deletions
|
|
@ -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/yosys.h"
|
||||||
#include "kernel/sigtools.h"
|
#include "kernel/sigtools.h"
|
||||||
#include "kernel/macc.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;
|
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)
|
bool is_chainable(Cell* cell)
|
||||||
{
|
{
|
||||||
if (!(is_add(cell) || is_subtract(cell)))
|
if (!(is_add(cell) || is_subtract(cell)))
|
||||||
|
|
@ -134,6 +138,7 @@ struct Rewriter
|
||||||
return consumer;
|
return consumer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find cells that consumes another cell's output.
|
||||||
dict<Cell*, Cell*> find_parents(const pool<Cell*>& candidates)
|
dict<Cell*, Cell*> find_parents(const pool<Cell*>& candidates)
|
||||||
{
|
{
|
||||||
dict<Cell*, Cell*> parent_of;
|
dict<Cell*, Cell*> parent_of;
|
||||||
|
|
@ -207,7 +212,7 @@ struct Rewriter
|
||||||
const pool<Cell*>& chain,
|
const pool<Cell*>& chain,
|
||||||
Cell* root,
|
Cell* root,
|
||||||
const dict<Cell*, Cell*>& parent_of,
|
const dict<Cell*, Cell*>& parent_of,
|
||||||
int& correction
|
int& neg_compensation
|
||||||
) {
|
) {
|
||||||
pool<SigBit> chain_bits = internal_bits(chain);
|
pool<SigBit> chain_bits = internal_bits(chain);
|
||||||
dict<Cell*, bool> negated;
|
dict<Cell*, bool> negated;
|
||||||
|
|
@ -229,7 +234,7 @@ struct Rewriter
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Operand> operands;
|
std::vector<Operand> operands;
|
||||||
correction = 0;
|
neg_compensation = 0;
|
||||||
|
|
||||||
for (auto cell : chain) {
|
for (auto cell : chain) {
|
||||||
bool cell_neg;
|
bool cell_neg;
|
||||||
|
|
@ -247,21 +252,21 @@ struct Rewriter
|
||||||
if (!overlaps(a, chain_bits)) {
|
if (!overlaps(a, chain_bits)) {
|
||||||
bool neg = cell_neg;
|
bool neg = cell_neg;
|
||||||
operands.push_back({a, a_signed, neg});
|
operands.push_back({a, a_signed, neg});
|
||||||
if (neg) correction++;
|
if (neg) neg_compensation++;
|
||||||
}
|
}
|
||||||
if (!overlaps(b, chain_bits)) {
|
if (!overlaps(b, chain_bits)) {
|
||||||
bool neg = cell_neg ^ b_sub;
|
bool neg = cell_neg ^ b_sub;
|
||||||
operands.push_back({b, b_signed, neg});
|
operands.push_back({b, b_signed, neg});
|
||||||
if (neg) correction++;
|
if (neg) neg_compensation++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return operands;
|
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);
|
Macc macc(cell);
|
||||||
correction = 0;
|
neg_compensation = 0;
|
||||||
|
|
||||||
for (auto& term : macc.terms) {
|
for (auto& term : macc.terms) {
|
||||||
// Bail on multiplication
|
// Bail on multiplication
|
||||||
|
|
@ -269,7 +274,7 @@ struct Rewriter
|
||||||
return false;
|
return false;
|
||||||
operands.push_back({term.in_a, term.is_signed, term.do_subtract});
|
operands.push_back({term.in_a, term.is_signed, term.do_subtract});
|
||||||
if (term.do_subtract)
|
if (term.do_subtract)
|
||||||
correction++;
|
neg_compensation++;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -307,6 +312,7 @@ struct Rewriter
|
||||||
int depth;
|
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::pair<SigSpec, SigSpec> reduce_wallace(std::vector<SigSpec>& sigs, int width, int& fa_count)
|
||||||
{
|
{
|
||||||
std::vector<DepthSig> ops;
|
std::vector<DepthSig> ops;
|
||||||
|
|
@ -356,7 +362,7 @@ struct Rewriter
|
||||||
void replace_with_csa_tree(
|
void replace_with_csa_tree(
|
||||||
std::vector<Operand>& operands,
|
std::vector<Operand>& operands,
|
||||||
SigSpec result_y,
|
SigSpec result_y,
|
||||||
int correction,
|
int neg_compensation,
|
||||||
const char* desc
|
const char* desc
|
||||||
) {
|
) {
|
||||||
int width = GetSize(result_y);
|
int width = GetSize(result_y);
|
||||||
|
|
@ -370,8 +376,8 @@ struct Rewriter
|
||||||
extended.push_back(s);
|
extended.push_back(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (correction > 0)
|
if (neg_compensation > 0)
|
||||||
extended.push_back(SigSpec(correction, width));
|
extended.push_back(SigSpec(neg_compensation, width));
|
||||||
|
|
||||||
int fa_count;
|
int fa_count;
|
||||||
auto [a, b] = reduce_wallace(extended, width, fa_count);
|
auto [a, b] = reduce_wallace(extended, width, fa_count);
|
||||||
|
|
@ -416,14 +422,12 @@ struct Rewriter
|
||||||
for (auto c : chain)
|
for (auto c : chain)
|
||||||
processed.insert(c);
|
processed.insert(c);
|
||||||
|
|
||||||
int correction;
|
int neg_compensation;
|
||||||
auto operands = extract_chain_operands(
|
auto operands = extract_chain_operands(chain, root, parent_of, neg_compensation);
|
||||||
chain, root, parent_of, correction);
|
|
||||||
if (operands.size() < 3)
|
if (operands.size() < 3)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
replace_with_csa_tree(operands, root->getPort(ID::Y),
|
replace_with_csa_tree(operands, root->getPort(ID::Y), neg_compensation, "Replaced add/sub chain");
|
||||||
correction, "Replaced add/sub chain");
|
|
||||||
for (auto cell : chain)
|
for (auto cell : chain)
|
||||||
module->remove(cell);
|
module->remove(cell);
|
||||||
}
|
}
|
||||||
|
|
@ -433,14 +437,13 @@ struct Rewriter
|
||||||
{
|
{
|
||||||
for (auto cell : cells.macc) {
|
for (auto cell : cells.macc) {
|
||||||
std::vector<Operand> operands;
|
std::vector<Operand> operands;
|
||||||
int correction;
|
int neg_compensation;
|
||||||
if (!extract_macc_operands(cell, operands, correction))
|
if (!extract_macc_operands(cell, operands, neg_compensation))
|
||||||
continue;
|
continue;
|
||||||
if (operands.size() < 3)
|
if (operands.size() < 3)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
replace_with_csa_tree(operands, cell->getPort(ID::Y),
|
replace_with_csa_tree(operands, cell->getPort(ID::Y), neg_compensation, "Replaced $macc");
|
||||||
correction, "Replaced $macc");
|
|
||||||
module->remove(cell);
|
module->remove(cell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -458,8 +461,7 @@ void run(Module* module) {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CsaTreePass : public Pass {
|
struct CsaTreePass : public Pass {
|
||||||
CsaTreePass() : Pass("csa_tree",
|
CsaTreePass() : Pass("csa_tree", "convert add/sub/macc chains to carry-save adder trees") {}
|
||||||
"convert add/sub/macc chains to carry-save adder trees") {}
|
|
||||||
|
|
||||||
void help() override
|
void help() override
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue