alumacc: Fix get_lt for oversized output

Current behavior uses the output width to determine the MSb(s), however this is not correct if the output is larger than the inputs (which doesn't happen when creating an `$alu` for a compare op, but does when folding a compare op into an arithmetic `$alu`).

Co-authored-by: Lofty <dan.ravensloft@gmail.com>
This commit is contained in:
Krystine Sherwin 2026-07-24 17:41:31 +12:00
parent 66654d278d
commit 1af8ded0cb
No known key found for this signature in database
1 changed files with 29 additions and 11 deletions

View File

@ -41,18 +41,22 @@ struct AlumaccWorker
std::vector<RTLIL::Cell*> cells;
RTLIL::SigSpec a, b, c, y;
std::vector<tuple<bool, bool, bool, bool, bool, RTLIL::SigSpec>> cmp;
bool is_signed, invert_b;
bool is_signed, invert_b, oversized;
RTLIL::Cell *alu_cell;
RTLIL::SigSpec cached_lt, cached_slt, cached_gt, cached_sgt, cached_eq, cached_ne;
RTLIL::SigSpec cached_cf, cached_of, cached_sf;
RTLIL::SigSpec get_lt(bool is_signed) {
if (is_signed) {
RTLIL::SigSpec get_lt(bool this_signed) {
if (this_signed) {
if (GetSize(cached_slt) == 0) {
get_of();
get_sf();
cached_slt = alu_cell->module->Xor(NEW_ID, cached_of, cached_sf);
if (is_signed && oversized) {
cached_slt = cached_sf;
} else {
get_of();
cached_slt = alu_cell->module->Xor(NEW_ID, cached_of, cached_sf);
}
}
return cached_slt;
@ -65,10 +69,10 @@ struct AlumaccWorker
}
}
RTLIL::SigSpec get_gt(bool is_signed) {
if (is_signed) {
RTLIL::SigSpec get_gt(bool this_signed) {
if (this_signed) {
if (GetSize(cached_sgt) == 0) {
get_lt(is_signed);
get_lt(this_signed);
get_eq();
SigSpec Or = alu_cell->module->Or(NEW_ID, cached_slt, cached_eq);
cached_sgt = alu_cell->module->Not(NEW_ID, Or, false, alu_cell->get_src_attribute());
@ -77,7 +81,7 @@ struct AlumaccWorker
return cached_sgt;
} else {
if (GetSize(cached_gt) == 0) {
get_lt(is_signed);
get_lt(this_signed);
get_eq();
SigSpec Or = alu_cell->module->Or(NEW_ID, cached_lt, cached_eq);
cached_gt = alu_cell->module->Not(NEW_ID, Or, false, alu_cell->get_src_attribute());
@ -112,7 +116,14 @@ struct AlumaccWorker
if (GetSize(cached_of) == 0) {
cached_of = {alu_cell->getPort(ID::CO), alu_cell->getPort(ID::CI)};
log_assert(GetSize(cached_of) >= 2);
cached_of = alu_cell->module->Xor(NEW_ID, cached_of[GetSize(cached_of)-1], cached_of[GetSize(cached_of)-2]);
if (oversized) {
auto max_input = max(GetSize(a), GetSize(b));
log_assert(max_input >= 1);
cached_of = alu_cell->module->Xor(NEW_ID, cached_of[max_input], cached_of[max_input-1]);
} else {
log_assert(GetSize(y) >= 1);
cached_of = alu_cell->module->Xor(NEW_ID, cached_of[GetSize(y)], cached_of[GetSize(y)-1]);
}
}
return cached_of;
}
@ -120,7 +131,12 @@ struct AlumaccWorker
RTLIL::SigSpec get_sf() {
if (GetSize(cached_sf) == 0) {
cached_sf = alu_cell->getPort(ID::Y);
cached_sf = cached_sf[GetSize(cached_sf)-1];
log_assert(GetSize(cached_sf) >= 1);
if (oversized && !is_signed) {
cached_sf = cached_sf[max(GetSize(a), GetSize(b))-1];
} else {
cached_sf = cached_sf[GetSize(y)-1];
}
}
return cached_sf;
}
@ -357,6 +373,7 @@ struct AlumaccWorker
alunode->cells.push_back(n->cell);
alunode->is_signed = a_signed;
alunode->invert_b = subtract_b;
alunode->oversized = max(GetSize(A), GetSize(B)) < GetSize(n->y);
alunode->a = A;
alunode->b = B;
@ -448,6 +465,7 @@ struct AlumaccWorker
n->y = module->addWire(NEW_ID, max(GetSize(A), GetSize(B)));
n->is_signed = is_signed;
n->invert_b = true;
n->oversized = false;
sig_alu[RTLIL::SigSig(A, B)].insert(n);
log(" new $alu\n");
} else {