signExtend method

  1. @override
void signExtend()
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));
  }
}