FloatingPointAdderRound constructor

FloatingPointAdderRound(
  1. FloatingPoint a,
  2. FloatingPoint b, {
  3. Logic? subtract,
  4. Logic? clk,
  5. Logic? reset,
  6. Logic? enable,
  7. Adder adderGen(
    1. Logic,
    2. Logic
    ) = ParallelPrefixAdder.new,
  8. ParallelPrefix ppTree(
    1. List<Logic>,
    2. Logic (
      1. Logic,
      2. Logic
      )
    ) = KoggeStone.new,
  9. String name = 'floating_point_adder_round',
})

Add two floating point numbers a and b, returning result in sum. subtract is an optional Logic input to do subtraction adderGen is an adder generator to be used in the primary adder functions. ppTree is an ParallelPrefix generator for use in increment /decrement functions.

Implementation

FloatingPointAdderRound(FloatingPoint a, FloatingPoint b,
    {Logic? subtract,
    this.clk,
    this.reset,
    this.enable,
    Adder Function(Logic, Logic) adderGen = ParallelPrefixAdder.new,
    ParallelPrefix Function(List<Logic>, Logic Function(Logic, Logic))
        ppTree = KoggeStone.new,
    super.name = 'floating_point_adder_round'})
    : exponentWidth = a.exponent.width,
      mantissaWidth = a.mantissa.width {
  if (b.exponent.width != exponentWidth ||
      b.mantissa.width != mantissaWidth) {
    throw RohdHclException('FloatingPoint widths must match');
  }
  if (clk != null) {
    clk = addInput('clk', clk!);
  }
  if (reset != null) {
    reset = addInput('reset', reset!);
  }
  if (enable != null) {
    enable = addInput('enable', enable!);
  }
  a = a.clone()..gets(addInput('a', a, width: a.width));
  b = b.clone()..gets(addInput('b', b, width: b.width));
  addOutput('sum', width: _sum.width) <= _sum;

  final exponentSubtractor = OnesComplementAdder(a.exponent, b.exponent,
      subtract: true, adderGen: adderGen, name: 'exponent_sub');
  final signDelta = exponentSubtractor.sign;

  final delta = exponentSubtractor.sum;

  // Seidel: (sl, el, fl) = larger; (ss, es, fs) = smaller
  final (larger, smaller) = _swap(signDelta, (a, b));

  final fl = mux(
      larger.isNormal(),
      [larger.isNormal(), larger.mantissa].swizzle(),
      [larger.mantissa, Const(0)].swizzle());
  final fs = mux(
      smaller.isNormal(),
      [smaller.isNormal(), smaller.mantissa].swizzle(),
      [smaller.mantissa, Const(0)].swizzle());

  // Seidel: S.EFF = effectiveSubtraction
  final effectiveSubtraction = a.sign ^ b.sign ^ (subtract ?? Const(0));

  // Seidel: flp  larger preshift, normally in [2,4)
  final sigWidth = fl.width + 1;
  final largeShift = mux(effectiveSubtraction, fl.zeroExtend(sigWidth) << 1,
      fl.zeroExtend(sigWidth));
  final smallShift = mux(effectiveSubtraction, fs.zeroExtend(sigWidth) << 1,
      fs.zeroExtend(sigWidth));

  final zeroExp = Const(0, width: exponentWidth);

  final largeOperand = largeShift;
  //
  // R Datapath:  Far exponents or addition
  //
  final extendWidthRPath =
      min(mantissaWidth + 3, pow(2, exponentWidth).toInt() - 3);

  final smallerFullRPath =
      [smallShift, Const(0, width: extendWidthRPath)].swizzle();
  smallerFullRPath <= smallerFullRPath.withSet(extendWidthRPath, smallShift);

  final smallerAlignRPath = smallerFullRPath >>> exponentSubtractor.sum;
  final smallerOperandRPath = smallerAlignRPath.slice(
      smallerAlignRPath.width - 1,
      smallerAlignRPath.width - largeOperand.width);

  /// R Pipestage here:
  final aIsNormalLatched =
      condFlop(clk, a.isNormal(), en: enable, reset: reset);
  final bIsNormalLatched =
      condFlop(clk, b.isNormal(), en: enable, reset: reset);
  final effectiveSubtractionLatched =
      condFlop(clk, effectiveSubtraction, en: enable, reset: reset);
  final largeOperandLatched =
      condFlop(clk, largeOperand, en: enable, reset: reset);
  final smallerOperandRPathLatched =
      condFlop(clk, smallerOperandRPath, en: enable, reset: reset);
  final smallerAlignRPathLatched =
      condFlop(clk, smallerAlignRPath, en: enable, reset: reset);
  final largerExpLatched =
      condFlop(clk, larger.exponent, en: enable, reset: reset);
  final deltaLatched = condFlop(clk, delta, en: enable, reset: reset);

  final carryRPath = Logic();
  final significandAdderRPath = OnesComplementAdder(
      largeOperandLatched, smallerOperandRPathLatched,
      subtractIn: effectiveSubtractionLatched,
      carryOut: carryRPath,
      adderGen: adderGen,
      name: 'rpath_significand_adder');

  final lowBitsRPath =
      smallerAlignRPathLatched.slice(extendWidthRPath - 1, 0);
  final lowAdderRPath = OnesComplementAdder(
      carryRPath.zeroExtend(extendWidthRPath),
      mux(effectiveSubtractionLatched, ~lowBitsRPath, lowBitsRPath),
      adderGen: adderGen,
      name: 'rpath_lowadder');

  final preStickyRPath =
      lowAdderRPath.sum.slice(lowAdderRPath.sum.width - 4, 0).or();
  final stickyBitRPath = lowAdderRPath.sum[-3] | preStickyRPath;

  final earlyGRSRPath = [
    lowAdderRPath.sum
        .slice(lowAdderRPath.sum.width - 2, lowAdderRPath.sum.width - 3),
    preStickyRPath
  ].swizzle();

  final sumRPath = significandAdderRPath.sum.slice(mantissaWidth + 1, 0);
  final sumP1RPath =
      (significandAdderRPath.sum + 1).slice(mantissaWidth + 1, 0);

  final sumLeadZeroRPath =
      ~sumRPath[-1] & (aIsNormalLatched | bIsNormalLatched);
  final sumP1LeadZeroRPath =
      ~sumP1RPath[-1] & (aIsNormalLatched | bIsNormalLatched);

  final selectRPath = lowAdderRPath.sum[-1];
  final shiftGRSRPath = [earlyGRSRPath[2], stickyBitRPath].swizzle();
  final mergedSumRPath = mux(
      sumLeadZeroRPath,
      [sumRPath, earlyGRSRPath].swizzle().slice(sumRPath.width + 1, 0),
      [sumRPath, shiftGRSRPath].swizzle());

  final mergedSumP1RPath = mux(
      sumP1LeadZeroRPath,
      [sumP1RPath, earlyGRSRPath].swizzle().slice(sumRPath.width + 1, 0),
      [sumP1RPath, shiftGRSRPath].swizzle());

  final finalSumLGRSRPath =
      mux(selectRPath, mergedSumP1RPath, mergedSumRPath);
  // RNE: guard & (lsb | round | sticky)
  final rndRPath = finalSumLGRSRPath[2] &
      (finalSumLGRSRPath[3] | finalSumLGRSRPath[1] | finalSumLGRSRPath[0]);

  // Rounding from 1111 to 0000.
  final incExpRPath =
      rndRPath & sumLeadZeroRPath.eq(Const(1)) & sumP1LeadZeroRPath.eq(0);

  final firstZeroRPath = mux(selectRPath, ~sumP1RPath[-1], ~sumRPath[-1]);

  final expDecr = ParallelPrefixDecr(largerExpLatched,
      ppGen: ppTree, name: 'exp_decrement');
  final expIncr = ParallelPrefixIncr(largerExpLatched,
      ppGen: ppTree, name: 'exp_increment');
  final exponentRPath = Logic(width: exponentWidth);
  Combinational([
    If.block([
      // Subtract 1 from exponent
      Iff(~incExpRPath & effectiveSubtractionLatched & firstZeroRPath,
          [exponentRPath < expDecr.out]),
      // Add 1 to exponent
      ElseIf(
          ~effectiveSubtractionLatched &
              (incExpRPath & firstZeroRPath | ~incExpRPath & ~firstZeroRPath),
          [exponentRPath < expIncr.out]),
      // Add 2 to exponent
      ElseIf(incExpRPath & effectiveSubtractionLatched & ~firstZeroRPath,
          [exponentRPath < largerExpLatched << 1]),
      Else([exponentRPath < largerExpLatched])
    ])
  ]);

  final sumMantissaRPath = mux(selectRPath, sumP1RPath, sumRPath) +
      rndRPath.zeroExtend(sumRPath.width);
  final mantissaRPath = sumMantissaRPath <<
      mux(selectRPath, sumP1LeadZeroRPath, sumLeadZeroRPath);

  //
  //  N Datapath here:  close exponents, subtraction
  //
  final smallOperandNPath = smallShift >>> (a.exponent[0] ^ b.exponent[0]);

  final significandSubtractorNPath = OnesComplementAdder(
      largeOperand, smallOperandNPath,
      subtractIn: effectiveSubtraction,
      adderGen: adderGen,
      name: 'npath_significand_sub');

  final significandNPath =
      significandSubtractorNPath.sum.slice(smallOperandNPath.width - 1, 0);

  final leadOneNPath = mux(
      significandNPath.or(),
      ParallelPrefixPriorityEncoder(significandNPath.reversed,
              ppGen: ppTree, name: 'npath_leadingOne')
          .out
          .zeroExtend(exponentWidth),
      Const(15, width: exponentWidth));

  // N pipestage here:
  final significandNPathLatched =
      condFlop(clk, significandNPath, en: enable, reset: reset);
  final significandSubtractorNPathSignLatched = condFlop(
      clk, significandSubtractorNPath.sign,
      en: enable, reset: reset);
  final leadOneNPathLatched =
      condFlop(clk, leadOneNPath, en: enable, reset: reset);
  final largerSignLatched =
      condFlop(clk, larger.sign, en: enable, reset: reset);
  final smallerSignLatched =
      condFlop(clk, smaller.sign, en: enable, reset: reset);

  final expCalcNPath = OnesComplementAdder(
      largerExpLatched, leadOneNPathLatched.zeroExtend(exponentWidth),
      subtractIn: effectiveSubtractionLatched,
      adderGen: adderGen,
      name: 'npath_expcalc');

  final preExpNPath = expCalcNPath.sum.slice(exponentWidth - 1, 0);

  final posExpNPath = preExpNPath.or() & ~expCalcNPath.sign;

  final exponentNPath = mux(posExpNPath, preExpNPath, zeroExp);

  final preMinShiftNPath = ~leadOneNPathLatched.or() | ~largerExpLatched.or();

  final minShiftNPath =
      mux(posExpNPath | preMinShiftNPath, leadOneNPathLatched, expDecr.out);
  final notSubnormalNPath = aIsNormalLatched | bIsNormalLatched;

  final shiftedSignificandNPath =
      (significandNPathLatched << minShiftNPath).slice(mantissaWidth, 1);

  final finalSignificandNPath = mux(
      notSubnormalNPath,
      shiftedSignificandNPath,
      significandNPathLatched.slice(significandNPathLatched.width - 1, 2));

  final signNPath = mux(significandSubtractorNPathSignLatched,
      smallerSignLatched, largerSignLatched);

  final isR = deltaLatched.gte(Const(2, width: delta.width)) |
      ~effectiveSubtractionLatched;
  _sum <=
      mux(
          isR,
          [
            largerSignLatched,
            exponentRPath,
            mantissaRPath.slice(mantissaRPath.width - 2, 1)
          ].swizzle(),
          [signNPath, exponentNPath, finalSignificandNPath].swizzle());
}