FixedToFloat constructor

FixedToFloat(
  1. FixedPoint fixed, {
  2. required int exponentWidth,
  3. required int mantissaWidth,
  4. String name = 'FixedToFloat',
})

Constructor

Implementation

FixedToFloat(FixedPoint fixed,
    {required this.exponentWidth,
    required this.mantissaWidth,
    super.name = 'FixedToFloat'}) {
  fixed = fixed.clone()..gets(addInput('fixed', fixed, width: fixed.width));
  addOutput('float', width: _float.width) <= _float;

  final bias = FloatingPointValue.computeBias(exponentWidth);
  final eMax = pow(2, exponentWidth) - 2;
  final iWidth =
      (2 + max(fixed.n, max(log2Ceil(fixed.width), exponentWidth))).toInt();

  // Special handling needed for E4M3 as it does not support inf
  if ((exponentWidth == 4) && (mantissaWidth == 3)) {
    UnimplementedError('E4M3 is not supported.');
  }

  // Extract sign bit
  if (fixed.signed) {
    _float.sign <= fixed[-1];
  } else {
    _float.sign <= Const(0);
  }

  final absValue = Logic(name: 'absValue', width: fixed.width)
    ..gets(mux(_float.sign, ~(fixed - 1), fixed));

  final jBit =
      ParallelPrefixPriorityEncoder(absValue.reversed).out.zeroExtend(iWidth);

  // Extract mantissa
  final mantissa = Logic(name: 'mantissa', width: mantissaWidth);
  final guard = Logic(name: 'guardBit');
  final sticky = Logic(name: 'stickBit');
  final j = Logic(name: 'j', width: iWidth);
  final maxShift = fixed.width - fixed.n + bias - 2;

  // Limit to minimum exponent
  if (maxShift > 0) {
    j <= mux(jBit.gt(maxShift), Const(maxShift, width: iWidth), jBit);
  } else {
    j <= jBit;
  }

  // Align mantissa
  final absValueShifted =
      Logic(width: max(absValue.width, mantissaWidth + 2));
  if (absValue.width < mantissaWidth + 2) {
    final zeros = Const(0, width: mantissaWidth + 2 - absValue.width);
    absValueShifted <= [absValue, zeros].swizzle() << j;
  } else {
    absValueShifted <= absValue << j;
  }

  mantissa <= absValueShifted.getRange(-mantissaWidth - 1, -1);
  guard <= absValueShifted.getRange(-mantissaWidth - 2, -mantissaWidth - 1);
  sticky <= absValueShifted.getRange(0, -mantissaWidth - 2).or();

  /// Round to nearest even: mantissa | guard sticky
  final roundUp = guard & (sticky | mantissa[0]);
  final mantissaRounded = mux(roundUp, mantissa + 1, mantissa);

  // Calculate biased exponent
  final eRaw = mux(
      absValueShifted[-1],
      Const(bias + fixed.width - fixed.n - 1, width: iWidth) - j,
      Const(0, width: iWidth));
  final eRawRne = mux(roundUp & ~mantissaRounded.or(), eRaw + 1, eRaw);

  // Select output handling corner cases
  final expoLessThanOne = eRawRne[-1] | ~eRawRne.or();
  final expoMoreThanMax = ~eRawRne[-1] & (eRawRne.gt(eMax));
  Combinational([
    If.block([
      Iff(~absValue.or(), [
        // Zero
        _float.exponent < Const(0, width: exponentWidth),
        _float.mantissa < Const(0, width: mantissaWidth),
      ]),
      ElseIf(expoMoreThanMax, [
        // Infinity
        _float.exponent < LogicValue.filled(exponentWidth, LogicValue.one),
        _float.mantissa < Const(0, width: mantissaWidth),
      ]),
      ElseIf(expoLessThanOne, [
        // Subnormal
        _float.exponent < Const(0, width: exponentWidth),
        _float.mantissa < mantissaRounded
      ]),
      Else([
        // Normal
        _float.exponent < eRawRne.slice(exponentWidth - 1, 0),
        _float.mantissa < mantissaRounded
      ])
    ])
  ]);
}