mirror of
https://github.com/YosysHQ/yosys
synced 2026-06-05 00:20:52 +00:00
Depth-schedule finar adder.
This commit is contained in:
parent
ba7173a469
commit
afabf72e23
4 changed files with 45 additions and 30 deletions
|
|
@ -133,7 +133,7 @@ std::vector<DepthSig> generate_partial_products(Module *module, SigSpec a, SigSp
|
||||||
return products;
|
return products;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<SigSpec, SigSpec> reduce_scheduled(Module *module, std::vector<DepthSig> operands, int width, Strategy strategy, int *compressor_count) {
|
std::pair<SigSpec, SigSpec> reduce_scheduled(Module *module, std::vector<DepthSig> operands, int width, Strategy strategy, int *out_compressor_count, int *out_final_depth) {
|
||||||
int levels = 0;
|
int levels = 0;
|
||||||
int fa_count = 0;
|
int fa_count = 0;
|
||||||
int c42_count = 0;
|
int c42_count = 0;
|
||||||
|
|
@ -217,15 +217,22 @@ std::pair<SigSpec, SigSpec> reduce_scheduled(Module *module, std::vector<DepthSi
|
||||||
levels++;
|
levels++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(compressor_count)
|
if(out_compressor_count)
|
||||||
*compressor_count = fa_count;
|
*out_compressor_count = fa_count;
|
||||||
|
if (operands.size() == 0) {
|
||||||
if (operands.size() == 0)
|
if (out_final_depth)
|
||||||
|
*out_final_depth = 0;
|
||||||
return {SigSpec(State::S0, width), SigSpec(State::S0, width)};
|
return {SigSpec(State::S0, width), SigSpec(State::S0, width)};
|
||||||
if (operands.size() == 1)
|
}
|
||||||
|
if (operands.size() == 1) {
|
||||||
|
if (out_final_depth)
|
||||||
|
*out_final_depth = operands[0].depth;
|
||||||
return {operands[0].sig, SigSpec(State::S0, width)};
|
return {operands[0].sig, SigSpec(State::S0, width)};
|
||||||
|
}
|
||||||
|
|
||||||
final_depth = std::max(operands[0].depth, operands[1].depth);
|
final_depth = std::max(operands[0].depth, operands[1].depth);
|
||||||
|
if (out_final_depth)
|
||||||
|
*out_final_depth = final_depth;
|
||||||
log_assert(operands.size() == 2);
|
log_assert(operands.size() == 2);
|
||||||
log(" CompressorTree::reduce_scheduled: %d levels, %d $fa (%d as 4:2), final depth %d\n", levels, fa_count, c42_count, final_depth);
|
log(" CompressorTree::reduce_scheduled: %d levels, %d $fa (%d as 4:2), final depth %d\n", levels, fa_count, c42_count, final_depth);
|
||||||
return {operands[0].sig, operands[1].sig};
|
return {operands[0].sig, operands[1].sig};
|
||||||
|
|
@ -320,12 +327,16 @@ Cell *emit_final_adder(Module *module, SigSpec a, SigSpec b, SigSpec y, FinalAdd
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
FinalAdder pick_final_adder(int width, FinalMode mode) {
|
FinalAdder pick_final_adder(int width, int final_depth, FinalMode mode) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case FinalMode::RIPPLE: return FinalAdder::RIPPLE;
|
case FinalMode::RIPPLE: return FinalAdder::RIPPLE;
|
||||||
case FinalMode::PREFIX: return FinalAdder::PARALLEL_PREFIX;
|
case FinalMode::PREFIX: return FinalAdder::PARALLEL_PREFIX;
|
||||||
case FinalMode::AUTO:
|
case FinalMode::AUTO:
|
||||||
default: return (width < RIPPLE_PREFIX_THRESHOLD) ? FinalAdder::DEFAULT : FinalAdder::PARALLEL_PREFIX;
|
default: {
|
||||||
|
bool wide = width >= RIPPLE_PREFIX_THRESHOLD;
|
||||||
|
bool deep = final_depth >= PREFIX_DEPTH_THRESHOLD;
|
||||||
|
return (wide && deep) ? FinalAdder::PARALLEL_PREFIX : FinalAdder::DEFAULT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,9 @@ YOSYS_NAMESPACE_BEGIN
|
||||||
namespace CompressorTree
|
namespace CompressorTree
|
||||||
{
|
{
|
||||||
|
|
||||||
// Width threshold below which a ripple is preferred over parallel-prefix
|
// Width and depth thresholds below which a ripple is preferred over parallel-prefix
|
||||||
constexpr int RIPPLE_PREFIX_THRESHOLD = 16;
|
constexpr int RIPPLE_PREFIX_THRESHOLD = 16;
|
||||||
|
constexpr int PREFIX_DEPTH_THRESHOLD = 5;
|
||||||
|
|
||||||
enum class Strategy {
|
enum class Strategy {
|
||||||
FA_ONLY, // 3:2 compressors
|
FA_ONLY, // 3:2 compressors
|
||||||
|
|
@ -80,11 +81,12 @@ std::vector<DepthSig> generate_partial_products(Module *module, SigSpec a, SigSp
|
||||||
* @sigs: Vector of input signals (operands) to be reduced
|
* @sigs: Vector of input signals (operands) to be reduced
|
||||||
* @width: Target bit-width to which all operands will be zero-extended
|
* @width: Target bit-width to which all operands will be zero-extended
|
||||||
* @strategy: Compression strategy to use
|
* @strategy: Compression strategy to use
|
||||||
* @compressor_count: Optional pointer to return the number of $fa cells emitted
|
* @out_compressor_count: Optional pointer to return the number of $fa cells emitted
|
||||||
|
* @out_final_depth: Optional pointer to return the final depth of the scheduled tree
|
||||||
*
|
*
|
||||||
* Return: The final two reduced operands, that are to be fed into an adder
|
* Return: The final two reduced operands, that are to be fed into an adder
|
||||||
*/
|
*/
|
||||||
std::pair<SigSpec, SigSpec> reduce_scheduled(Module *module, std::vector<DepthSig> operands, int width, Strategy strategy, int *compressor_count = nullptr);
|
std::pair<SigSpec, SigSpec> reduce_scheduled(Module *module, std::vector<DepthSig> operands, int width, Strategy strategy, int *out_compressor_count = nullptr, int *out_final_depth = nullptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* emit_kogge_stone() - Emit a Kogge-Stone parallel-prefix adder
|
* emit_kogge_stone() - Emit a Kogge-Stone parallel-prefix adder
|
||||||
|
|
@ -107,7 +109,7 @@ void emit_kogge_stone(Module *module, SigSpec a, SigSpec b, SigSpec y);
|
||||||
*/
|
*/
|
||||||
Cell *emit_final_adder(Module *module, SigSpec a, SigSpec b, SigSpec y, FinalAdder choice);
|
Cell *emit_final_adder(Module *module, SigSpec a, SigSpec b, SigSpec y, FinalAdder choice);
|
||||||
|
|
||||||
FinalAdder pick_final_adder(int width, FinalMode mode);
|
FinalAdder pick_final_adder(int width, int final_depth, FinalMode mode);
|
||||||
|
|
||||||
} // namespace CompressorTree
|
} // namespace CompressorTree
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -309,21 +309,22 @@ struct ArithTreeWorker {
|
||||||
s = module->Not(NEW_ID, s);
|
s = module->Not(NEW_ID, s);
|
||||||
pool.push_back({s, 0});
|
pool.push_back({s, 0});
|
||||||
} else {
|
} else {
|
||||||
// Multiplicative operand
|
// Multiplicative operand
|
||||||
auto pps = CompressorTree::generate_partial_products(module, op.sig, op.factor_b, op.is_signed, op.factor_b_signed, width);
|
auto pps = CompressorTree::generate_partial_products(module, op.sig, op.factor_b, op.is_signed, op.factor_b_signed, width);
|
||||||
|
|
||||||
if (!op.negate) {
|
if (!op.negate) {
|
||||||
for (auto &pp : pps)
|
for (auto &pp : pps)
|
||||||
pool.push_back(pp);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
SigSpec neg_a = module->Not(NEW_ID, op.sig);
|
|
||||||
auto neg_pps = CompressorTree::generate_partial_products(module, neg_a, op.factor_b, op.is_signed, op.factor_b_signed, width);
|
|
||||||
for (auto &pp : neg_pps)
|
|
||||||
pool.push_back(pp);
|
pool.push_back(pp);
|
||||||
SigSpec b_ext = CompressorTree::normalize_to_width(op.factor_b, op.factor_b_signed, width);
|
continue;
|
||||||
pool.push_back({b_ext, 0});
|
}
|
||||||
|
|
||||||
|
auto [pa, pb] = CompressorTree::reduce_scheduled(module, pps, width, opt.strategy);
|
||||||
|
SigSpec p = module->addWire(NEW_ID, width);
|
||||||
|
module->addAdd(NEW_ID, pa, pb, p, false);
|
||||||
|
SigSpec np = module->addWire(NEW_ID, width);
|
||||||
|
module->addNot(NEW_ID, p, np);
|
||||||
|
pool.push_back({np, 0});
|
||||||
|
neg_compensation++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -337,8 +338,9 @@ struct ArithTreeWorker {
|
||||||
{
|
{
|
||||||
int width = GetSize(result_y);
|
int width = GetSize(result_y);
|
||||||
auto pool = build_operand_pool(operands, width, neg_compensation);
|
auto pool = build_operand_pool(operands, width, neg_compensation);
|
||||||
auto [a, b] = CompressorTree::reduce_scheduled(module, std::move(pool), width, opt.strategy);
|
int final_depth = 0;
|
||||||
auto final_choice = CompressorTree::pick_final_adder(width, opt.final_mode);
|
auto [a, b] = CompressorTree::reduce_scheduled(module, std::move(pool), width, opt.strategy, nullptr, &final_depth);
|
||||||
|
auto final_choice = CompressorTree::pick_final_adder(width, final_depth, opt.final_mode);
|
||||||
CompressorTree::emit_final_adder(module, a, b, result_y, final_choice);
|
CompressorTree::emit_final_adder(module, a, b, result_y, final_choice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,10 @@ hierarchy -auto-top
|
||||||
proc
|
proc
|
||||||
equiv_opt arith_tree -final auto
|
equiv_opt arith_tree -final auto
|
||||||
design -load postopt
|
design -load postopt
|
||||||
select -assert-none t:$add
|
select -assert-count 1 t:$add
|
||||||
select -assert-count 2 t:$fa
|
select -assert-count 2 t:$fa
|
||||||
select -assert-min 1 t:$_AND_
|
select -assert-none t:$_AND_
|
||||||
select -assert-min 1 t:$_XOR_
|
select -assert-none 1 t:$_XOR_
|
||||||
design -reset
|
design -reset
|
||||||
|
|
||||||
read_verilog <<EOT
|
read_verilog <<EOT
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue