3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-05-25 19:36:21 +00:00

Collapse signed*signed or combined nodes via BW.

This commit is contained in:
nella 2026-05-18 17:21:26 +02:00
parent 73fe179a26
commit 749d6cd8f7
4 changed files with 210 additions and 35 deletions

View file

@ -113,10 +113,6 @@ inline SigSpec normalize_to_width(SigSpec sig, bool is_signed, int width)
return sig;
}
inline bool supports_signedness(bool a_signed, bool b_signed) {
return !(a_signed || b_signed);
}
/**
* generate_partial_products() - Generate partial products for FMA concat
* @module:The Yosys module to which the compressors will be added
@ -126,15 +122,13 @@ inline bool supports_signedness(bool a_signed, bool b_signed) {
* @b_signed: Whether signal B is signed
* @width: Target width
*
* Return: Radix-2 partial product matrix as a set of depth-0 vectors
* Return: Partial-product matrix as a set of depth-0 vectors
*/
inline std::vector<DepthSig> generate_partial_products(Module *module, SigSpec a, SigSpec b, bool a_signed, bool b_signed, int width) {
// TODO: Baugh-Wooley sign extension for mixed sign and sign*sign cases, don't bail out to non-FMA
log_assert(supports_signedness(a_signed, b_signed) && "CompressorTree::generate_partial_products: signed inputs unsupported");
int width_a = GetSize(a);
int width_b = GetSize(b);
std::vector<DepthSig> products;
products.reserve(width_a);
products.reserve(width_a + 3);
for (int i = 0; i < width_a; i++) {
SigBit ai = a[i];
@ -144,14 +138,62 @@ inline std::vector<DepthSig> generate_partial_products(Module *module, SigSpec a
b_shifted.append(b);
b_shifted = normalize_to_width(b_shifted, false, width);
// product = b_shifted & replicate(a[i], width)
// row = b_shifted & replicate(a[i], width)
SigSpec ai_rep = SigSpec(ai, width);
SigSpec product = module->addWire(NEW_ID, width);
module->addAnd(NEW_ID, b_shifted, ai_rep, product);
SigSpec row = module->addWire(NEW_ID, width);
module->addAnd(NEW_ID, b_shifted, ai_rep, row);
products.push_back({product, 0});
// Apply Modified Baugh-Wooley inversions for this row
bool row_is_bottom = (i == width_a - 1);
bool any_inversion = (row_is_bottom && b_signed) || a_signed;
if (any_inversion) {
std::vector<RTLIL::State> mask(width, RTLIL::State::S0);
for (int j = 0; j < width_b; j++) {
int col = i + j;
if (col < 0 || col >= width)
continue;
bool col_is_right = (j == width_b - 1);
// Flip masks
bool invert = (row_is_bottom && b_signed) ^ (col_is_right && a_signed);
if (invert)
mask[col] = RTLIL::State::S1;
}
// Skip the xor entirely if the mask is all zeroes
bool nonzero = false;
for (auto s : mask)
if (s == RTLIL::State::S1) {
nonzero = true;
break;
}
if (nonzero) {
SigSpec inverted = module->addWire(NEW_ID, width);
module->addXor(NEW_ID, row, SigSpec(RTLIL::Const(mask)), inverted);
row = inverted;
}
}
products.push_back({row, 0});
}
// Correction constants
auto push_one_at = [&](int col) {
if (col < 0 || col >= width)
return;
std::vector<RTLIL::State> v(width, RTLIL::State::S0);
v[col] = RTLIL::State::S1;
products.push_back({SigSpec(RTLIL::Const(v)), 0});
};
if (b_signed)
push_one_at(width_a - 1);
if (a_signed)
push_one_at(width_b - 1);
if (a_signed || b_signed)
push_one_at(width_a + width_b - 1);
return products;
}