signExtend method

  1. @override
void signExtend()
override

Execute the sign extension, overridden to specialize.

Implementation

@override
void signExtend() {
  // An implementation of
  // Mohanty, B.K., Choubey, A. Efficient Design for Radix-8 Booth Multiplier
  // and Its Application in Lifting 2-D DWT. Circuits Syst Signal Process 36,
  // 1129–1149 (2017). https://doi.org/10.1007/s00034-016-0349-9
  if (signedMultiplicand && (selectSignedMultiplicand != null)) {
    throw RohdHclException('multiplicand sign reconfiguration requires '
        'signedMultiplicand=false');
  }
  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 alignRow0Sign = firstRowQStart - lastRowSignPos;

  final signs = [
    for (var r = 0; r < rows; r++)
      encoder
          .fetchEncoding(r)
          .sign
          .named('sign_r$r', naming: Naming.mergeable)
  ];

  final propagate =
      List.generate(rows, (i) => List.filled(0, Logic(), growable: true));

  for (var row = 0; row < rows; row++) {
    propagate[row].add(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 <= alignRow0Sign) {
        propagate[lastRow].add(SignBit(partialProducts[row][col++]));
      }
    }
    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);
    }
  }
  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 < alignRow0Sign) {
    m[lastRow].add(Logic());
  }
  // TODO(desmonddak): this seems unused when looking at Verilog output
  for (var i = shift - 1; i < m[lastRow].length; i++) {
    m[lastRow][i] = (lastAddend[i] ^
            (i < alignRow0Sign ? propagate[lastRow][i] : Const(0)))
        .named('m_lastr_c$i', naming: Naming.mergeable);
  }

  final remainders = List.filled(rows, Logic());
  for (var row = 0; row < lastRow; row++) {
    remainders[row] = propagate[row][shift - 1]
        .named('remainders_r$row', naming: Naming.mergeable);
  }
  remainders[lastRow] <=
      propagate[lastRow][max(alignRow0Sign, 0)]
          .named('remainders_lastrow', naming: Naming.mergeable);

  // Compute Sign extension for row==0
  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 q = [
    (firstSign ^ remainders[lastRow])
        .named('qfirst', naming: Naming.mergeable),
    (~(firstSign & ~remainders[lastRow]))
        .named('q_last', naming: Naming.mergeable),
  ];
  q.insertAll(1, List.filled(shift - 1, ~q[1]));

  for (var row = 0; row < rows; row++) {
    final addend = partialProducts[row];
    if (row > 0) {
      final mLimit = (row == lastRow) ? alignRow0Sign : shift - 1;
      for (var i = 0; i < mLimit; i++) {
        addend[i] = m[row][i];
      }
      addStopSignFlip(addend, SignBit(~signs[row], inverted: true));
      addend
        ..insert(0, remainders[row - 1])
        ..addAll(List.filled(shift - 1, Const(1)));
      rowShift[row] -= 1;
    } else {
      for (var i = 0; i < shift - 1; i++) {
        firstAddend[i] = m[0][i];
      }
      if (!signedMultiplicand) {
        firstAddend.add(q[0]);
      } else {
        firstAddend.last = q[0];
      }
      firstAddend.addAll(q.getRange(1, q.length));
    }
  }
  if (shift == 1) {
    lastAddend.add(Const(1));
  }
}