FloatingPointSqrtSimple<FpType extends FloatingPoint> constructor

FloatingPointSqrtSimple<FpType extends FloatingPoint>(
  1. FpType a, {
  2. Logic? clk,
  3. Logic? reset,
  4. Logic? enable,
  5. FloatingPointRoundingMode roundingMode = FloatingPointRoundingMode.roundNearestEven,
  6. String name = 'floatingpoint_square_root_simple',
  7. bool reserveName = false,
  8. bool reserveDefinitionName = false,
  9. String? definitionName,
})

Square root one floating point number a, returning results sqrt and error

Implementation

FloatingPointSqrtSimple(super.a,
    {super.clk,
    super.reset,
    super.enable,
    super.roundingMode,
    super.name = 'floatingpoint_square_root_simple',
    super.reserveName,
    super.reserveDefinitionName,
    String? definitionName})
    : super(
          definitionName: definitionName ??
              'FloatingPointSquareRootSimple_'
                  'E${a.exponent.width}M${a.mantissa.width}_'
                  'R${roundingMode.name}') {
  if (a.explicitJBit) {
    throw RohdHclException(
        'FloatingPointSqrtSimple does not support explicit-J-bit inputs.');
  }

  final outputSqrt = a.clone(name: 'sqrt') as FpType;
  output('sqrt') <= outputSqrt;
  late final error = output('error');

  // check to see if we do sqrt at all or just return a
  final isInf = a.isAnInfinity.named('isInf');
  final isNaN = a.isNaN.named('isNan');
  final isZero = a.isAZero.named('isZero');
  final rawSignificand =
      [a.isNormal, a.mantissa].swizzle().named('rawSignificand');
  final leadingOne = RecursiveModulePriorityEncoder(rawSignificand.reversed,
          generateValid: true, name: 'leading_one')
      .out
      .named('leadingOne');
  final normalizationShift =
      mux(a.isNormal, Const(0, width: leadingOne.width), leadingOne)
          .named('normalizationShift');
  final normalizedSignificand =
      (rawSignificand << normalizationShift).named('normalizedSignificand');

  final exponentCalcWidth = [exponentWidth + 2, normalizationShift.width + 2]
      .reduce((a, b) => a > b ? a : b);
  final bias = a.bias.zeroExtend(exponentCalcWidth);
  final effectiveExponent = mux(
          a.isNormal,
          a.exponent.zeroExtend(exponentCalcWidth),
          Const(1, width: exponentCalcWidth))
      .named('effectiveExponent');
  final deBiasExp = (effectiveExponent -
          bias -
          normalizationShift.zeroExtend(exponentCalcWidth))
      .named('deBiasExp');
  final shiftedExp = [deBiasExp[-1], deBiasExp.slice(deBiasExp.width - 1, 1)]
      .swizzle()
      .named('shiftedExp');
  final isExpOdd = deBiasExp[0];

  final extraPrecision = a.mantissa.width.isEven ? 5 : 4;
  final aFixed = FixedPoint(
      signed: false,
      integerWidth: 3,
      fractionWidth: a.mantissa.width + extraPrecision);
  aFixed <=
      [
        Const(0, width: 2),
        normalizedSignificand,
        Const(0, width: extraPrecision)
      ].swizzle().named('aFixed');

  final aFixedAdj = aFixed.clone(name: 'aFixedAdj')
    ..gets(mux(isExpOdd, [aFixed.slice(-2, 0), Const(0)].swizzle(), aFixed)
        .named('oddMantissaMux'));

  final fixedSqrt = FixedPointSqrt(aFixedAdj).sqrt;
  final retainedSignificand = fixedSqrt
      .getRange(extraPrecision, extraPrecision + a.mantissa.width + 1)
      .named('retainedSignificand');
  final adjustedSignificand = mux(
          isExpOdd,
          normalizedSignificand.zeroExtend(normalizedSignificand.width + 1) <<
              1,
          normalizedSignificand.zeroExtend(normalizedSignificand.width + 1))
      .named('adjustedSignificand');
  final comparisonWidth = 2 * (a.mantissa.width + 2);
  final exactScaled =
      (adjustedSignificand.zeroExtend(comparisonWidth) << a.mantissa.width)
          .named('exactScaled');
  final retainedForSquare = retainedSignificand.zeroExtend(comparisonWidth);
  final retainedSquared =
      (retainedForSquare * retainedForSquare).named('retainedSquared');
  final midpoint =
      ((retainedSignificand.zeroExtend(retainedSignificand.width + 1) << 1) |
              Const(1, width: retainedSignificand.width + 1))
          .named('midpoint');
  final midpointForSquare = midpoint.zeroExtend(comparisonWidth);
  final midpointSquared =
      (midpointForSquare * midpointForSquare).named('midpointSquared');
  final midpointScaled =
      (adjustedSignificand.zeroExtend(midpointSquared.width) <<
              (a.mantissa.width + 2))
          .named('midpointScaled');
  final inexact = exactScaled
      .neq(retainedSquared.zeroExtend(exactScaled.width))
      .named('inexact');
  final aboveMidpoint =
      midpointScaled.gt(midpointSquared).named('aboveMidpoint');
  final atMidpoint = midpointScaled.eq(midpointSquared).named('atMidpoint');
  final doRound = switch (roundingMode) {
    FloatingPointRoundingMode.truncate ||
    FloatingPointRoundingMode.roundTowardsZero ||
    FloatingPointRoundingMode.roundTowardsNegativeInfinity =>
      Const(0),
    FloatingPointRoundingMode.roundTowardsInfinity => inexact,
    FloatingPointRoundingMode.roundNearestTiesAway =>
      aboveMidpoint | atMidpoint,
    FloatingPointRoundingMode.roundNearestEven =>
      aboveMidpoint | (atMidpoint & retainedSignificand[0]),
  };
  final roundedSignificand =
      (retainedSignificand.zeroExtend(retainedSignificand.width + 1) +
              doRound.zeroExtend(retainedSignificand.width + 1))
          .named('roundedSignificand');
  final roundIncExp = roundedSignificand[-1].named('roundIncExp');
  final roundedMantissa = mux(roundIncExp, roundedSignificand.slice(-2, 1),
          roundedSignificand.slice(-3, 0))
      .named('roundedMantissa');
  final roundedExponent =
      (shiftedExp + bias + roundIncExp.zeroExtend(exponentCalcWidth))
          .named('roundedExponent');

  // A negative biased exponent cannot be represented in the exponent field.
  // Shift the unrounded significand into the subnormal range and round it
  // there instead of truncating the negative exponent to its low bits.
  final isSubnormal =
      (roundedExponent[-1] | ~roundedExponent.or()).named('isSubnormal');
  final subnormalShift =
      (Const(1, width: exponentCalcWidth) - roundedExponent)
          .named('subnormalShift');
  final subnormalShiftLimit =
      Const(a.mantissa.width + 1, width: exponentCalcWidth);
  final selectedSubnormalShift = mux(subnormalShift.gt(subnormalShiftLimit),
          subnormalShiftLimit, subnormalShift)
      .named('selectedSubnormalShift');
  final subnormalCandidates =
      <({Logic mantissa, Logic carry, Logic inexact})>[];
  for (var shift = 1; shift <= a.mantissa.width + 1; shift++) {
    final subnormalInput = [Const(0, width: shift), retainedSignificand]
        .swizzle()
        .named('subnormalInput$shift');
    final subnormalRounder = FloatingPointRounder(subnormalInput, shift,
        roundingMode: roundingMode, sign: a.sign, extraSticky: inexact);
    final retained =
        subnormalInput.slice(shift + a.mantissa.width - 1, shift);
    final rounded = (retained.zeroExtend(retained.width + 1) +
            subnormalRounder.doRound.zeroExtend(retained.width + 1))
        .named('subnormalRounded$shift');
    subnormalCandidates.add((
      mantissa: rounded.slice(a.mantissa.width - 1, 0),
      carry: rounded[-1],
      inexact: subnormalRounder.inexact
    ));
  }
  var subnormalMantissa = subnormalCandidates.last.mantissa;
  var subnormalCarry = subnormalCandidates.last.carry;
  var subnormalInexact = subnormalCandidates.last.inexact;
  for (var shift = subnormalCandidates.length - 1; shift >= 1; shift--) {
    final candidate = subnormalCandidates[shift - 1];
    final selected =
        selectedSubnormalShift.eq(Const(shift, width: exponentCalcWidth));
    subnormalMantissa = mux(selected, candidate.mantissa, subnormalMantissa);
    subnormalCarry = mux(selected, candidate.carry, subnormalCarry);
    subnormalInexact = mux(selected, candidate.inexact, subnormalInexact);
  }
  final resultExponent = mux(
          isSubnormal,
          subnormalCarry.zeroExtend(exponentWidth),
          roundedExponent.getRange(0, exponentWidth))
      .named('resultExponent');
  final resultMantissa = mux(isSubnormal, subnormalMantissa,
          roundedMantissa.slice(a.mantissa.width - 1, 0))
      .named('resultMantissa');
  final invalidOperation = (a.isSignalingNaN | (a.sign & ~isZero & ~isNaN))
      .named('invalidOperation');
  internalStatus.invalid <= invalidOperation;
  internalStatus.divideByZero <= Const(0);
  internalStatus.overflow <= Const(0);
  internalStatus.underflow <=
      mux(isSubnormal, subnormalInexact, Const(0)) &
          ~isInf &
          ~isNaN &
          ~isZero &
          ~a.sign;
  internalStatus.inexact <=
      mux(isSubnormal, subnormalInexact, inexact) & ~isInf & ~isNaN & ~a.sign;

  // final calculation results
  Combinational([
    error < Const(0),
    If.block([
      Iff(isInf & ~a.sign, [
        outputSqrt < outputSqrt.inf(),
      ]),
      ElseIf(isInf & a.sign, [
        outputSqrt < outputSqrt.nan,
        error < Const(1),
      ]),
      ElseIf(isNaN, [
        outputSqrt < outputSqrt.quietNaNFrom(a),
      ]),
      ElseIf(isZero, [
        outputSqrt.sign < a.sign,
        outputSqrt.exponent < a.exponent,
        outputSqrt.mantissa < a.mantissa,
      ]),
      ElseIf(a.sign, [
        outputSqrt < outputSqrt.nan,
        error < Const(1),
      ]),
      Else([
        outputSqrt.sign < a.sign,
        outputSqrt.exponent < resultExponent,
        outputSqrt.mantissa < resultMantissa,
      ])
    ])
  ]);
}