signExtend method
override
Execute the sign extension, overridden to specialize.
Implementation
@override
void signExtend() {
if (isSignExtended) {
throw RohdHclException('Partial Product array already sign-extended');
}
isSignExtended = true;
final lastRow = rows - 1;
final firstAddend = partialProducts[0];
final lastAddend = partialProducts[lastRow];
final firstRowQStart = selector.width - (signedMultiplicand ? 1 : 0);
final lastRowSignPos = shift * lastRow;
final align = firstRowQStart - lastRowSignPos;
final signs = [
for (var r = 0; r < rows; r++)
encoder
.fetchEncoding(r)
.sign
.named('sign_r$r', naming: Naming.mergeable)
];
// Compute propgation info for folding sign bits into main rows
final propagate =
List.generate(rows, (i) => List.filled(0, Logic(), growable: true));
for (var row = 0; row < rows; row++) {
propagate[row].add(SignBit(signs[row]));
for (var col = 0; col < 2 * (shift - 1); col++) {
propagate[row].add(partialProducts[row][col]
.named('propagate_r${row}_c$col', naming: Naming.mergeable));
}
// Last row has extend sign propagation to Q start
if (row == lastRow) {
var col = 2 * (shift - 1);
while (propagate[lastRow].length <= align) {
propagate[lastRow].add(SignBit(partialProducts[row][col++]));
}
}
// Now compute the propagation logic
for (var col = 1; col < propagate[row].length; col++) {
propagate[row][col] = (propagate[row][col] & propagate[row][col - 1])
.named('propagate_r${row}_c$col', naming: Naming.mergeable);
}
}
// Compute 'm', the prefix of each row to carry the sign of the next row
final m =
List.generate(rows, (i) => List.filled(0, Logic(), growable: true));
for (var row = 0; row < rows; row++) {
for (var c = 0; c < shift - 1; c++) {
m[row].add((partialProducts[row][c] ^ propagate[row][c])
.named('m_r${row}_c$c', naming: Naming.mergeable));
}
m[row].addAll(List.filled(shift - 1, Logic()));
}
while (m[lastRow].length < align) {
m[lastRow].add(Logic());
}
for (var i = shift - 1; i < m[lastRow].length; i++) {
m[lastRow][i] =
(lastAddend[i] ^ (i < align ? propagate[lastRow][i] : Const(0)))
.named('m_lastrow_$i', naming: Naming.mergeable);
}
final remainders = List.filled(rows, Logic());
for (var row = 0; row < lastRow; row++) {
remainders[row] = propagate[row][shift - 1]
.named('remainder_r$row', naming: Naming.mergeable);
}
remainders[lastRow] = propagate[lastRow][align > 0 ? align : 0]
.named('remainder_lastrow', naming: Naming.mergeable);
// Merge 'm' into the LSBs of each addend
for (var row = 0; row < rows; row++) {
final addend = partialProducts[row];
if (row > 0) {
final mLimit = (row == lastRow) ? align : shift - 1;
for (var i = 0; i < mLimit; i++) {
addend[i] = m[row][i];
}
// Stop bits
addStopSignFlip(addend, SignBit(~signs[row], inverted: true));
addend
..insert(0, remainders[row - 1])
..addAll(List.filled(shift - 1, Const(1)));
rowShift[row] -= 1;
} else {
// First row
for (var i = 0; i < shift - 1; i++) {
firstAddend[i] = m[0][i];
}
}
}
// Insert the lastRow sign: Either in firstRow's Q if there is a
// collision or in another row if it lands beyond the Q sign extension
final firstSign = Logic(name: 'firstsign', naming: Naming.mergeable);
if (selectSignedMultiplicand == null) {
firstSign <=
(signedMultiplicand ? SignBit(firstAddend.last) : SignBit(signs[0]));
} else {
firstSign <=
(SignBit(mux(selectSignedMultiplicand!, firstAddend.last, signs[0])));
}
final lastSign = SignBit(remainders[lastRow]);
// Compute Sign extension MSBs for firstRow
final qLen = shift + 1;
final insertSignPos = (align > 0) ? 0 : -align;
final q = List.filled(min(qLen, insertSignPos), firstSign, growable: true);
if (insertSignPos < qLen) {
// At sign insertion position
q.add(SignBit(firstSign ^ lastSign));
if (insertSignPos == qLen - 1) {
q[insertSignPos] = SignBit(~q[insertSignPos], inverted: true);
q.add(SignBit(~(firstSign | q[insertSignPos]), inverted: true));
} else {
q
..addAll(List.filled(
qLen - insertSignPos - 2, SignBit(firstSign & ~lastSign)))
..add(SignBit(~(firstSign & ~lastSign), inverted: true));
}
}
if (-align >= q.length) {
q.last = SignBit(~firstSign, inverted: true);
}
addStopSign(firstAddend, SignBit(q[0]));
firstAddend.addAll(q.getRange(1, q.length));
if (-align >= q.length) {
final finalCarryRelPos = lastRowSignPos -
selector.width -
shift +
(signedMultiplicand ? 1 : 0);
final finalCarryRow = (finalCarryRelPos / shift).floor();
final curRowLength =
partialProducts[finalCarryRow].length + rowShift[finalCarryRow];
partialProducts[finalCarryRow]
..addAll(List.filled(lastRowSignPos - curRowLength, Const(0)))
..add(remainders[lastRow]);
}
if (shift == 1) {
lastAddend.add(Const(1));
}
}