diff --git a/.github/workflows/general.yml b/.github/workflows/general.yml index ec063bcba..86d1f7013 100644 --- a/.github/workflows/general.yml +++ b/.github/workflows/general.yml @@ -90,7 +90,7 @@ jobs: uses: flutter-actions/setup-flutter@v2 with: channel: stable - version: 3.24.2 + version: 3.27.0 - name: Analyze flutter source run: tool/gh_actions/analyze_flutter_source.sh @@ -157,7 +157,7 @@ jobs: uses: flutter-actions/setup-flutter@v2 with: channel: stable - version: 3.24.2 + version: 3.27.0 - name: Build static site run: tool/gh_actions/hcl_site_generation_build.sh diff --git a/confapp/lib/hcl/view/screen/sidebar_widget.dart b/confapp/lib/hcl/view/screen/sidebar_widget.dart index f4969a472..31dfd27ad 100644 --- a/confapp/lib/hcl/view/screen/sidebar_widget.dart +++ b/confapp/lib/hcl/view/screen/sidebar_widget.dart @@ -17,8 +17,8 @@ const canvasColor = Color(0xFF2E2E48); const scaffoldBackgroundColor = Color(0xFF464667); const accentCanvasColor = Color(0xFF3E3E61); const white = Colors.white; -final actionColor = const Color(0xFF5F5FA7).withOpacity(0.6); -final divider = Divider(color: white.withOpacity(0.3), height: 1); +final actionColor = const Color(0xFF5F5FA7).withValues(alpha: 0.6); +final divider = Divider(color: white.withValues(alpha: 0.3), height: 1); class ComponentsSidebar extends StatefulWidget { final Function(void) updateForm; @@ -67,7 +67,7 @@ class _ComponentsSidebarState extends State { borderRadius: BorderRadius.circular(20), ), hoverColor: scaffoldBackgroundColor, - textStyle: TextStyle(color: Colors.white.withOpacity(0.7)), + textStyle: TextStyle(color: Colors.white.withValues(alpha: 0.7)), selectedTextStyle: const TextStyle(color: Colors.white), itemTextPadding: const EdgeInsets.only(left: 5), selectedItemTextPadding: const EdgeInsets.only(left: 5), @@ -78,20 +78,20 @@ class _ComponentsSidebarState extends State { selectedItemDecoration: BoxDecoration( borderRadius: BorderRadius.circular(10), border: Border.all( - color: actionColor.withOpacity(0.37), + color: actionColor.withValues(alpha: 0.37), ), gradient: const LinearGradient( colors: [accentCanvasColor, canvasColor], ), boxShadow: [ BoxShadow( - color: Colors.black.withOpacity(0.28), + color: Colors.black.withValues(alpha: 0.28), blurRadius: 30, ) ], ), iconTheme: IconThemeData( - color: Colors.white.withOpacity(0.7), + color: Colors.white.withValues(alpha: 0.7), size: 20, ), selectedIconTheme: const IconThemeData( diff --git a/doc/components/fixed_point.md b/doc/components/fixed_point.md index 89e3daf6e..8f5b510e2 100644 --- a/doc/components/fixed_point.md +++ b/doc/components/fixed_point.md @@ -4,11 +4,11 @@ Fixed-point binary representation of numbers is useful several applications incl ## FixedPointValue -A [FixedPointValue](https://intel.github.io/rohd-hcl/rohd_hcl/FixedPointValue-class.html) represents a signed or unsigned fixed-point value following the Q notation (Qm.n format) as introduced by [Texas Instruments](https://www.ti.com/lit/ug/spru565b/spru565b.pdf). It comprises an optional sign, integer part and/or a fractional part. [FixedPointValue](https://intel.github.io/rohd-hcl/rohd_hcl/FixedPointValue-class.html)s can be constructed from individual fields or from a Dart [double](https://api.dart.dev/stable/3.6.0/dart-core/double-class.html), converted to Dart [double](https://api.dart.dev/stable/3.6.0/dart-core/double-class.html), can be compared and can be operated on (+, -, *, /). +A [FixedPointValue](https://intel.github.io/rohd-hcl/rohd_hcl/FixedPointValue-class.html) represents a signed or unsigned fixed-point value following the Q notation (Qm.n format) as introduced by [Texas Instruments](https://www.ti.com/lit/ug/spru565b/spru565b.pdf). It comprises an optional sign, integer part and/or a fractional part. [FixedPointValue](https://intel.github.io/rohd-hcl/rohd_hcl/FixedPointValue-class.html)s can be constructed from individual fields or from a Dart [double](https://api.dart.dev/stable/3.6.0/dart-core/double-class.html), converted to Dart [double](https://api.dart.dev/stable/3.6.0/dart-core/double-class.html), can be compared and can be operated on (+, -, *, /). A `FixedPointValuePopulator` can be used to construct `FixedPointValue` using different kinds of converters. ## FixedPoint -The [FixedPoint](https://intel.github.io/rohd-hcl/rohd_hcl/FixedPoint-class.html) type is an extension of [Logic](https://intel.github.io/rohd/rohd/Logic-class.html) with additional attributes (signed or unsigned, integer width and fraction width). This type is provided to simplify the design of fixed-point arithmetic blocks. +The [FixedPoint](https://intel.github.io/rohd-hcl/rohd_hcl/FixedPoint-class.html) type is an extension of [LogicStructure](https://intel.github.io/rohd/rohd/LogicStructure-class.html) with additional attributes (signed or unsigned, integer width and fraction width). This type is provided to simplify the design of fixed-point arithmetic blocks. ## FixedToFloat @@ -18,7 +18,7 @@ The [FixedToFloat](https://intel.github.io/rohd-hcl/rohd_hcl/FixedToFloat-class. This component converts a floating-point signal to a signed fixed-point signal. Infinities and NaN's are not supported. The integer and fraction widths are auto-calculated to achieve lossless conversion. -If the `m` and `n` integer and fraction widths are supplied, then lossy conversion is performed to fit the floating-point value into the fixed-point value. For testing, [FixedPointValue](https://intel.github.io/rohd-hcl/rohd_hcl/FixedPointValue-class.html) has a `canStore` method to predetermine if a given double can fit. For execution, [FloatToFixed](https://intel.github.io/rohd-hcl/rohd_hcl/FloatToFixed-class.html) can perform overflow detection by setting a `checkOverflow` option, which is a property of the class and set in the constructor (default is false as it must add significant logic to do the check). +If the `integerWidth` and `fractionWidth` integer and fraction widths are supplied, then lossy conversion is performed to fit the floating-point value into the fixed-point value. For testing, [FixedPointValue](https://intel.github.io/rohd-hcl/rohd_hcl/FixedPointValue-class.html) has a `canStore` method to predetermine if a given double can fit. For execution, [FloatToFixed](https://intel.github.io/rohd-hcl/rohd_hcl/FloatToFixed-class.html) can perform overflow detection by setting a `checkOverflow` option, which is a property of the class and set in the constructor (default is false as it must add significant logic to do the check). Currently, the FloatToFixed converter, when in lossy mode, is not performing any real rounding (just truncating). diff --git a/lib/src/arithmetic/fixed_sqrt.dart b/lib/src/arithmetic/fixed_sqrt.dart index ee123f350..738bb8242 100644 --- a/lib/src/arithmetic/fixed_sqrt.dart +++ b/lib/src/arithmetic/fixed_sqrt.dart @@ -48,14 +48,26 @@ class FixedPointSqrt extends FixedPointSqrtBase { throw RohdHclException('Signed values not supported'); } - Logic solution = - FixedPoint(signed: a.signed, name: 'solution', m: a.m + 1, n: a.n + 1); - Logic remainder = - FixedPoint(signed: a.signed, name: 'remainder', m: a.m + 1, n: a.n + 1); - Logic subtractionValue = - FixedPoint(signed: a.signed, name: 'subValue', m: a.m + 1, n: a.n + 1); - Logic aLoc = - FixedPoint(signed: a.signed, name: 'aLoc', m: a.m + 1, n: a.n + 1); + Logic solution = FixedPoint( + signed: a.signed, + name: 'solution', + integerWidth: a.integerWidth + 1, + fractionWidth: a.fractionWidth + 1); + Logic remainder = FixedPoint( + signed: a.signed, + name: 'remainder', + integerWidth: a.integerWidth + 1, + fractionWidth: a.fractionWidth + 1); + Logic subtractionValue = FixedPoint( + signed: a.signed, + name: 'subValue', + integerWidth: a.integerWidth + 1, + fractionWidth: a.fractionWidth + 1); + Logic aLoc = FixedPoint( + signed: a.signed, + name: 'aLoc', + integerWidth: a.integerWidth + 1, + fractionWidth: a.fractionWidth + 1); solution = Const(0, width: aLoc.width).named('solution'); remainder = Const(0, width: aLoc.width).named('remainder'); diff --git a/lib/src/arithmetic/fixed_to_float.dart b/lib/src/arithmetic/fixed_to_float.dart index 434ed9d9d..bed93fff3 100644 --- a/lib/src/arithmetic/fixed_to_float.dart +++ b/lib/src/arithmetic/fixed_to_float.dart @@ -60,7 +60,7 @@ class FixedToFloat extends Module { final bias = float.floatingPointValue.bias; final eMax = pow(2, float.exponent.width) - 2; final iWidth = (1 + - max(log2Ceil(fixed.n), + max(log2Ceil(fixed.fractionWidth), max(log2Ceil(fixed.width), float.exponent.width))) .toInt(); @@ -82,7 +82,7 @@ class FixedToFloat extends Module { ..gets(mux(_convertedFloat.sign, fixed, fixed)); } - final maxShift = fixed.width - fixed.n + bias - 2; + final maxShift = fixed.width - fixed.fractionWidth + bias - 2; final jBit = Logic(name: 'jBit', width: iWidth); Logic estimatedJBit; @@ -166,7 +166,9 @@ class FixedToFloat extends Module { // Calculate biased exponent final eRaw = mux( absValueShifted[-1], - (Const(bias + fixed.width - fixed.n - 1, width: iWidth) - jBit) + (Const(bias + fixed.width - fixed.fractionWidth - 1, + width: iWidth) - + jBit) .named('eShift'), Const(0, width: iWidth)) .named('eRaw'); diff --git a/lib/src/arithmetic/float_to_fixed.dart b/lib/src/arithmetic/float_to_fixed.dart index 1d2ca893c..0ea403d99 100644 --- a/lib/src/arithmetic/float_to_fixed.dart +++ b/lib/src/arithmetic/float_to_fixed.dart @@ -23,10 +23,10 @@ import 'package:rohd_hcl/rohd_hcl.dart'; /// ``` class FloatToFixed extends Module { /// Width of output integer part. - late final int m; + late final int integerWidth; /// Width of output fractional part. - late final int n; + late final int fractionWidth; /// Add overflow checking logic final bool checkOverflow; @@ -35,20 +35,25 @@ class FloatToFixed extends Module { Logic? get overflow => tryOutput('overflow'); /// Internal representation of the output port - late final FixedPoint _fixed = FixedPoint(signed: true, m: m, n: n); + late final FixedPoint _fixed = + FixedPoint(integerWidth: integerWidth, fractionWidth: fractionWidth); /// Output fixed point port late final FixedPoint fixed = _fixed.clone()..gets(output('fixed')); /// Build a [FloatingPoint] to [FixedPoint] converter. - /// - if [m] and [n] are supplied, an m.n fixed-point output will be produced. - /// Otherwise, the converter will compute a lossless size for [m] and [n] for - /// outputing the floating-point value into a fixed-point value. + /// - if [integerWidth] and [fractionWidth] are supplied, an m.n fixed-point + /// output will be produced. Otherwise, the converter will compute a + /// lossless size for [integerWidth] and [fractionWidth] for outputing the + /// floating-point value into a fixed-point value. /// - [checkOverflow] set to true will cause overflow detection to happen in - /// case that loss can occur and an optional output [overflow] will be - /// produced that returns true when overflow occurs. + /// case that loss can occur and an optional output [overflow] will be + /// produced that returns true when overflow occurs. FloatToFixed(FloatingPoint float, - {super.name = 'FloatToFixed', int? m, int? n, this.checkOverflow = false}) + {super.name = 'FloatToFixed', + int? integerWidth, + int? fractionWidth, + this.checkOverflow = false}) : super( definitionName: 'FloatE${float.exponent.width}' 'M${float.mantissa.width}ToFixed') { @@ -61,27 +66,33 @@ class FloatToFixed extends Module { : bias + 1; // accomodate the jbit final noLossN = bias + float.mantissa.width - 1; - this.m = m ?? noLossM; - this.n = n ?? noLossN; - final outputWidth = this.m + this.n + 1; + // TODO(desmonddak): Check what happens with an explicitJBit FP + + this.integerWidth = integerWidth ?? noLossM; + this.fractionWidth = fractionWidth ?? noLossN; + final outputWidth = this.integerWidth + this.fractionWidth + 1; final jBit = Logic(name: 'jBit')..gets(float.isNormal); final fullMantissa = [jBit, float.mantissa].swizzle().named('fullMantissa'); - final eWidth = max(log2Ceil(this.n + this.m), float.exponent.width) + 2; + final eWidth = max(log2Ceil(this.fractionWidth + this.integerWidth), + float.exponent.width) + + 2; final shift = Logic(name: 'shift', width: eWidth); final exp = (float.exponent - 1).zeroExtend(eWidth).named('expMinus1'); - if (this.n > noLossN) { + if (this.fractionWidth > noLossN) { shift <= mux(jBit, exp, Const(0, width: eWidth)) + - Const(this.n - noLossN, width: eWidth).named('deltaN'); - } else if (this.n == noLossN) { + Const(this.fractionWidth - noLossN, width: eWidth) + .named('deltaN'); + } else if (this.fractionWidth == noLossN) { shift <= mux(jBit, exp, Const(0, width: eWidth)); } else { shift <= mux(jBit, exp, Const(0, width: eWidth)) - - Const(noLossN - this.n, width: eWidth).named('deltaN'); + Const(noLossN - this.fractionWidth, width: eWidth) + .named('deltaN'); } // TODO(desmonddak): Could use signed shifter if we unified shift math final shiftRight = ((fullMantissa.width > outputWidth) @@ -89,7 +100,8 @@ class FloatToFixed extends Module { : (~shift + 1)) .named('shiftRight'); - if (checkOverflow & ((this.m < noLossM) | (this.n < noLossN))) { + if (checkOverflow & + ((this.integerWidth < noLossM) | (this.fractionWidth < noLossN))) { final overflow = Logic(name: 'overflow'); final leadDetect = RecursiveModulePriorityEncoder(fullMantissa.reversed, name: 'leadone_detector'); @@ -151,10 +163,12 @@ class Float8ToFixed extends Module { Logic get fixed => output('fixed'); /// Getter for Q23.9 - FixedPoint get q23p9 => FixedPoint.of(fixed, signed: true, m: 23, n: 9); + FixedPoint get q23p9 => + FixedPoint.of(fixed, integerWidth: 23, fractionWidth: 9); /// Getter for Q16.16 - FixedPoint get q16p16 => FixedPoint.of(fixed, signed: true, m: 16, n: 16); + FixedPoint get q16p16 => + FixedPoint.of(fixed, integerWidth: 16, fractionWidth: 16); /// Constructor Float8ToFixed(Logic float, Logic mode, {super.name = 'Float8ToFixed'}) { diff --git a/lib/src/arithmetic/floating_point/floating_point_sqrt_simple.dart b/lib/src/arithmetic/floating_point/floating_point_sqrt_simple.dart index 9696ff793..e34d03c5e 100644 --- a/lib/src/arithmetic/floating_point/floating_point_sqrt_simple.dart +++ b/lib/src/arithmetic/floating_point/floating_point_sqrt_simple.dart @@ -55,7 +55,8 @@ class FloatingPointSqrtSimple final isExpOdd = deBiasExp[0]; // use fixed sqrt unit - final aFixed = FixedPoint(signed: false, m: 3, n: a.mantissa.width); + final aFixed = FixedPoint( + signed: false, integerWidth: 3, fractionWidth: a.mantissa.width); aFixed <= [Const(1, width: 3), a.mantissa.getRange(0)].swizzle().named('aFixed'); diff --git a/lib/src/arithmetic/signals/fixed_point_logic.dart b/lib/src/arithmetic/signals/fixed_point_logic.dart index f5ba2cd04..3249b4eb5 100644 --- a/lib/src/arithmetic/signals/fixed_point_logic.dart +++ b/lib/src/arithmetic/signals/fixed_point_logic.dart @@ -7,61 +7,89 @@ // 2024 October 24 // Author: Soner Yaldiz -import 'dart:math'; +import 'package:meta/meta.dart'; import 'package:rohd/rohd.dart'; import 'package:rohd_hcl/rohd_hcl.dart'; /// A representation of (un)signed fixed-point logic following /// Q notation (Qm.n format) as introduced by /// (Texas Instruments)[https://www.ti.com/lit/ug/spru565b/spru565b.pdf]. -class FixedPoint extends Logic { - /// [signed] indicates whether the representation is signed. - final bool signed; +class FixedPoint extends LogicStructure { + /// The integer part of the fixed-point number. + Logic integer; + + /// The fractional part of the fixed-point number. + Logic fraction; - /// [m] is the number of bits reserved for the integer part. - final int m; + /// Return true if signed + final bool signed; - /// [n] is the number of bits reserved for the fractional part. - final int n; + /// [integerWidth] is the number of bits reserved for the integer part. + int get integerWidth => integer.width - (signed ? 1 : 0); - static int _fixedPointWidth(bool s, int a, int b) => s ? 1 + a + b : a + b; + /// [fractionWidth] is the number of bits reserved for the fractional part. + int get fractionWidth => fraction.width; /// Constructs a [FixedPoint] signal. FixedPoint( - {required this.signed, - required this.m, - required this.n, - super.name, - super.naming}) - : super(width: _fixedPointWidth(signed, m, n)) { - if ((m < 0) | (n < 0)) { - throw RohdHclException('m and n must be non-negative'); - } - if (max(m, n) == 0) { - throw RohdHclException('either m or n must be greater than zero'); - } - } + {required int integerWidth, + required int fractionWidth, + bool signed = true, + String? name}) + : this._( + Logic( + width: integerWidth + (signed ? 1 : 0), + name: 'integer', + naming: Naming.mergeable), + Logic( + width: fractionWidth, + name: 'fraction', + naming: Naming.mergeable), + signed, + name: name); + + /// [FixedPoint] internal constructor. + FixedPoint._(this.integer, this.fraction, this.signed, {super.name}) + : super([fraction, integer]); /// Retrieve the [FixedPointValue] of this [FixedPoint] logical signal. - FixedPointValue get fixedPointValue => - FixedPointValue(value: value, signed: signed, m: m, n: n); + FixedPointValue get fixedPointValue => valuePopulator().ofFixedPoint(this); + + /// A [FixedPointValuePopulator] for values associated with this + /// [FloatingPoint] type. + @mustBeOverridden + FixedPointValuePopulator valuePopulator() => FixedPointValue.populator( + integerWidth: integerWidth, fractionWidth: fractionWidth, signed: signed); /// Clone for I/O ports. @override - FixedPoint clone({String? name}) => FixedPoint(signed: signed, m: m, n: n); + FixedPoint clone({String? name}) => FixedPoint( + signed: signed, integerWidth: integerWidth, fractionWidth: fractionWidth); /// Cast logic to fixed point FixedPoint.of(Logic signal, - {required this.signed, required this.m, required this.n}) - : super(width: _fixedPointWidth(signed, m, n)) { - this <= signal; - } + {required int integerWidth, + required int fractionWidth, + bool signed = true}) + : this._( + signal.slice( + fractionWidth + (signed ? integerWidth : integerWidth - 1), + fractionWidth), + signal.slice(fractionWidth - 1, 0), + signed, + name: signal.name); @override void put(dynamic val, {bool fill = false}) { if (val is FixedPointValue) { - if ((signed != val.signed) | (m != val.m) | (n != val.n)) { - throw RohdHclException('Value is not compatible with signal.'); + if ((signed != val.signed) | + (integerWidth != val.integerWidth) | + (fractionWidth != val.fractionWidth)) { + throw RohdHclException('Value is not compatible with signal. ' + 'Expected: signed=$signed, integerWidth=$integerWidth, ' + 'nWidth=$fractionWidth. ' + 'Got: signed=${val.signed}, fractionWidth=${val.integerWidth}, ' + 'nWidth=${val.fractionWidth}.'); } super.put(val.value); } else { @@ -74,7 +102,9 @@ class FixedPoint extends Logic { if (other is! FixedPoint) { throw RohdHclException('Input must be fixed point signal.'); } - if ((signed != other.signed) | (m != other.m) | (n != other.n)) { + if ((signed != other.signed) | + (integerWidth != other.integerWidth) | + (fractionWidth != other.fractionWidth)) { throw RohdHclException('Inputs are not comparable.'); } } @@ -127,7 +157,10 @@ class FixedPoint extends Logic { Logic _multiply(dynamic other) { _verifyCompatible(other); final product = Multiply(this, other).out; - return FixedPoint.of(product, signed: false, m: 2 * m, n: 2 * n); + return FixedPoint.of(product, + signed: false, + integerWidth: 2 * integerWidth, + fractionWidth: 2 * fractionWidth); } /// Greater-than. @@ -138,7 +171,7 @@ class FixedPoint extends Logic { @override Logic operator >=(dynamic other) => gte(other); - /// multiply + /// multiply: TODO(desmonddak): this needs tests @override Logic operator *(dynamic other) => _multiply(other); diff --git a/lib/src/arithmetic/signals/floating_point_logics/floating_point_logic.dart b/lib/src/arithmetic/signals/floating_point_logics/floating_point_logic.dart index a8dd6899a..5b7da5966 100644 --- a/lib/src/arithmetic/signals/floating_point_logics/floating_point_logic.dart +++ b/lib/src/arithmetic/signals/floating_point_logics/floating_point_logic.dart @@ -41,14 +41,14 @@ class FloatingPoint extends LogicStructure { bool explicitJBit = false, String? name}) : this._( - Logic(name: _nameJoin(name, 'sign'), naming: Naming.mergeable), + Logic(name: 'sign', naming: Naming.mergeable), Logic( width: exponentWidth, - name: _nameJoin(name, 'exponent'), + name: 'exponent', naming: Naming.mergeable), Logic( width: mantissaWidth, - name: _nameJoin(name, 'mantissa'), + name: 'mantissa', naming: Naming.mergeable), explicitJBit, name: name); diff --git a/lib/src/arithmetic/values/fixed_point_populator.dart b/lib/src/arithmetic/values/fixed_point_populator.dart new file mode 100644 index 000000000..4305cd880 --- /dev/null +++ b/lib/src/arithmetic/values/fixed_point_populator.dart @@ -0,0 +1,141 @@ +// Copyright (C) 2025 Intel Corporation +// SPDX-License-Identifier: BSD-3-Clause +// +// fixed_point_value_populator.dart +// Populator for Fixed Point Values +// +// 2025 June 8, 2025 +// Author: Desmond A Kirkpatrick + +import 'dart:math'; + +import 'package:meta/meta.dart'; +import 'package:rohd/rohd.dart'; +import 'package:rohd_hcl/rohd_hcl.dart'; + +/// A populator for [FixedPointValue]s, a utility that can populate various +/// forms of [FixedPointValue]s. +class FixedPointValuePopulator { + /// An unpopulated [FixedPointValue] that this populator will populate. + /// + /// The `late final` variables will not yet be initialized until after this + /// populator is used to [populate] it. + final FxvType _unpopulated; + + /// The width of the exponent field. + int get integerWidth => _unpopulated.integerWidth; + + /// The width of the mantissa field. + int get fractionWidth => _unpopulated.fractionWidth; + + /// Return whether the [FixedPointValue] is signed. + bool get signed => _unpopulated.signed; + + /// Whether or not this populator has already populated values. + bool _hasPopulated = false; + + /// Creates a [FixedPointValuePopulator] for the given [_unpopulated] + /// [FixedPointValue]. + FixedPointValuePopulator(this._unpopulated); + + /// Extracts a [FixedPointValue] from a [FixedPoint]'s current `value`. + FxvType ofFixedPoint(FixedPoint fp) => populate( + integer: fp.integer.value, + fraction: fp.fraction.value, + ); + + @override + String toString() => 'FixedPointValuePopulator<${_unpopulated.runtimeType}>'; + + /// Populates the [FixedPointValue] with the given [integer] and + /// [fraction], then performs additional validation. + FxvType populate( + {required LogicValue integer, required LogicValue fraction}) { + if (_hasPopulated) { + throw RohdHclException('FixedPointPopulator: already populated'); + } + _hasPopulated = true; + + return _unpopulated + ..integer = integer + ..fraction = fraction; + } + + /// Construct a [FixedPointValue] from a [LogicValue] + FxvType ofLogicValue(LogicValue val) => populate( + integer: val.getRange( + fractionWidth, integerWidth + fractionWidth + (signed ? 1 : 0)), + fraction: val.getRange(0, fractionWidth), + ); + + /// Return true if double [val] to be stored in [FixedPointValue] + /// with [m] and [n] lengths without overflowing. + static bool canStore(double val, + {required bool signed, required int m, required int n}) { + final w = signed ? 1 + m + n : m + n; + if (val.isFinite) { + final bigIntegerValue = BigInt.from(val * pow(2, n)); + final negBigIntegerValue = BigInt.from(-val * pow(2, n)); + final l = (val < 0.0) + ? max(bigIntegerValue.bitLength, negBigIntegerValue.bitLength) + : bigIntegerValue.bitLength; + return l <= w; + } + return false; + } + + /// Constructs [FixedPointValue] from a Dart [double] rounding away from zero. + FxvType ofDouble(double val) { + final m = integerWidth; + final n = fractionWidth; + final signed = _unpopulated.signed; + if (!signed & (val < 0)) { + throw RohdHclException('Negative input not allowed with unsigned'); + } + if (!canStore(val, signed: signed, m: m, n: n)) { + throw RohdHclException('Double is too long to store in ' + 'FixedPointValue: $m, $n'); + } + final integerValue = BigInt.from(val * pow(2, n)); + final w = signed ? 1 + m + n : m + n; + final v = LogicValue.ofBigInt(integerValue, w); + return ofLogicValue(v); + } + + /// Constructs [FixedPointValue] from a Dart [double] without rounding. + @internal + FxvType ofDoubleUnrounded(double val) { + final m = integerWidth; + final n = fractionWidth; + final signed = _unpopulated.signed; + if (!signed & (val < 0)) { + throw RohdHclException('Negative input not allowed with unsigned'); + } + final integerValue = BigInt.from(val * pow(2, n + 1)); + final w = signed ? 1 + m + n : m + n; + final v = LogicValue.ofBigInt(integerValue >> 1, w); + return ofLogicValue(v); + } + + /// Constructs a [FixedPointValue] from another [FixedPointValue] with + /// by widening the integer and/or fraction widths. + FxvType widen(FxvType fxv) { + if ((fxv.integerWidth > integerWidth) || + (fxv.fractionWidth > fractionWidth)) { + throw RohdHclException('Cannot expand from $fxv to $_unpopulated'); + } + + var newInteger = fxv.signed + ? fxv.integer + .signExtend(fxv.integer.width + integerWidth - fxv.integerWidth) + : fxv.integer + .zeroExtend(fxv.integer.width + integerWidth - fxv.integerWidth); + if (signed & !fxv.signed) { + newInteger = newInteger.zeroExtend(newInteger.width + 1); + } + + final newFraction = + fxv.fraction.reversed.zeroExtend(fractionWidth).reversed; + return populate(integer: newInteger, fraction: newFraction); + } +} diff --git a/lib/src/arithmetic/values/fixed_point_value.dart b/lib/src/arithmetic/values/fixed_point_value.dart index 5760cdaa7..f5dc654df 100644 --- a/lib/src/arithmetic/values/fixed_point_value.dart +++ b/lib/src/arithmetic/values/fixed_point_value.dart @@ -12,6 +12,7 @@ import 'dart:math'; import 'package:meta/meta.dart'; import 'package:rohd/rohd.dart'; import 'package:rohd_hcl/rohd_hcl.dart'; +export 'fixed_point_populator.dart'; /// An immutable representation of (un)signed fixed-point values following /// Q notation (Qm.n format) as introduced by @@ -19,63 +20,63 @@ import 'package:rohd_hcl/rohd_hcl.dart'; @immutable class FixedPointValue implements Comparable { /// The fixed point value bit storage in two's complement. - late final LogicValue value; + late final LogicValue value = [integer, fraction].swizzle(); - /// [signed] indicates whether the representation is signed. - final bool signed; + /// The integer valuue portion. + late final LogicValue integer; + + /// The fractional value portion. + late final LogicValue fraction; - /// [m] is the number of bits reserved for the integer part. - final int m; + /// [integerWidth] is the number of bits reserved for the integer part. + late final int integerWidth; - /// [n] is the number of bits reserved for the fractional part. - final int n; + /// [fractionWidth] is the number of bits reserved for the fractional part. + late final int fractionWidth; + + /// [signed] indicates whether the representation is signed. + late final bool signed; /// Returns true if the number is negative. bool isNegative() => signed & (value[-1] == LogicValue.one); /// Constructs [FixedPointValue] from sign, integer and fraction values. - FixedPointValue( - {required this.value, - required this.signed, - required this.m, - required this.n}) { - if (value == LogicValue.empty) { - throw RohdHclException('Zero width is not allowed.'); - } - final w = signed ? m + n + 1 : m + n; - if (w != value.width) { - throw RohdHclException('Width must be (sign) + m + n.'); - } - } + factory FixedPointValue( + {required LogicValue integer, + required LogicValue fraction, + bool signed = false}) => + populator( + integerWidth: integer.width - (signed ? 1 : 0), + fractionWidth: fraction.width) + .populate(integer: integer, fraction: fraction); - /// Expands the bit width of integer and fractional parts. - LogicValue expandWidth({required bool sign, int m = 0, int n = 0}) { - if ((m < 0) | (n < 0)) { - throw RohdHclException('Input width must be non-negative.'); - } - if ((m > 0) & (m < this.m)) { - throw RohdHclException('Integer width is larger than input.'); - } - if ((n > 0) & (n < this.n)) { - throw RohdHclException('Fraction width is larger than input.'); - } - var newValue = value; - if (m >= this.m) { - if (signed) { - newValue = newValue.signExtend(newValue.width + m - this.m); - } else { - newValue = newValue.zeroExtend(newValue.width + m - this.m); - if (sign) { - newValue = newValue.zeroExtend(newValue.width + 1); - } - } - } - if (n > this.n) { - newValue = - newValue.reversed.zeroExtend(newValue.width + n - this.n).reversed; - } - return newValue; - } + /// Creates an unpopulated version of a [FixedPointValue], intended to be + /// called with the [populator]. + @protected + FixedPointValue.uninitialized({this.signed = false}); + + /// Creates a [FixedPointValuePopulator] with the provided [integerWidth] + /// and [fractionWidth], which can then be used to complete construction of + /// a [FixedPointValue] using population functions. + static FixedPointValuePopulator populator( + {required int integerWidth, + required int fractionWidth, + bool signed = false}) => + FixedPointValuePopulator(FixedPointValue.uninitialized(signed: signed) + ..integerWidth = integerWidth + ..fractionWidth = fractionWidth); + + /// Creates a [FixedPointValuePopulator] for the same type as `this` and + /// with the same widths. + /// + /// This must be overridden in subclasses so that the correct type of + /// [FixedPointValuePopulator] is returned for generating equivalent types + /// of [FixedPointValue]s. + @mustBeOverridden + FixedPointValuePopulator clonePopulator() => + FixedPointValuePopulator(FixedPointValue.uninitialized(signed: signed) + ..integerWidth = integerWidth + ..fractionWidth = fractionWidth); /// Returns a negative integer if `this` less than [other], /// a positive integer if `this` greater than [other], @@ -89,10 +90,16 @@ class FixedPointValue implements Comparable { throw RohdHclException('Inputs must be valid.'); } final s = signed | other.signed; - final m = max(this.m, other.m); - final n = max(this.n, other.n); - final val1 = expandWidth(sign: s, m: m, n: n); - final val2 = other.expandWidth(sign: s, m: m, n: n); + final m = max(integerWidth, other.integerWidth); + final n = max(fractionWidth, other.fractionWidth); + final val1 = + FixedPointValue.populator(integerWidth: m, fractionWidth: n, signed: s) + .widen(this) + .value; + final val2 = + FixedPointValue.populator(integerWidth: m, fractionWidth: n, signed: s) + .widen(other) + .value; final comp = val1.compareTo(val2); if (comp == 0) { return comp; @@ -133,7 +140,10 @@ class FixedPointValue implements Comparable { @override int get hashCode => - value.hashCode ^ signed.hashCode ^ m.hashCode ^ n.hashCode; + value.hashCode ^ + signed.hashCode ^ + integerWidth.hashCode ^ + fractionWidth.hashCode; @override bool operator ==(Object other) { @@ -143,60 +153,16 @@ class FixedPointValue implements Comparable { return compareTo(other) == 0; } - /// Return a string representation of FloatingPointValue. - /// return sign, exponent, mantissa as binary strings. + /// Return a string representation of [FixedPointValue]. + /// return sign, integer, fraction as binary strings. @override String toString() => "(${signed ? '${value[-1].bitString} ' : ''}" - "${(m > 0) ? '${value.slice(m + n - 1, n).bitString} ' : ''}" - '${value.slice(n - 1, 0).bitString})'; - - /// Return true if double [val] to be stored in [FixedPointValue] - /// with [m] and [n] lengths without overflowing. - static bool canStore(double val, - {required bool signed, required int m, required int n}) { - final w = signed ? 1 + m + n : m + n; - if (val.isFinite) { - final bigIntegerValue = BigInt.from(val * pow(2, n)); - final negBigIntegerValue = BigInt.from(-val * pow(2, n)); - final l = (val < 0.0) - ? max(bigIntegerValue.bitLength, negBigIntegerValue.bitLength) - : bigIntegerValue.bitLength; - return l <= w; - } - return false; - } - - /// Constructs [FixedPointValue] from a Dart [double] rounding away from zero. - factory FixedPointValue.ofDouble(double val, - {required bool signed, required int m, required int n}) { - if (!signed & (val < 0)) { - throw RohdHclException('Negative input not allowed with unsigned'); - } - if (!canStore(val, signed: signed, m: m, n: n)) { - throw RohdHclException('Double is too long to store in ' - 'FixedPointValue: $m, $n'); - } - final integerValue = BigInt.from(val * pow(2, n)); - final w = signed ? 1 + m + n : m + n; - final v = LogicValue.ofBigInt(integerValue, w); - return FixedPointValue(value: v, signed: signed, m: m, n: n); - } - - /// Constructs [FixedPointValue] from a Dart [double] without rounding. - factory FixedPointValue.ofDoubleUnrounded(double val, - {required bool signed, required int m, required int n}) { - if (!signed & (val < 0)) { - throw RohdHclException('Negative input not allowed with unsigned'); - } - final integerValue = BigInt.from(val * pow(2, n + 1)); - final w = signed ? 1 + m + n : m + n; - final v = LogicValue.ofBigInt(integerValue >> 1, w); - return FixedPointValue(value: v, signed: signed, m: m, n: n); - } + "${integerWidth > 0 ? '${value.getRange(fractionWidth).bitString} ' : ''}" + '${value.slice(fractionWidth - 1, 0).bitString})'; /// Converts a fixed-point value to a Dart [double]. double toDouble() { - if (m + n > 52) { + if (integerWidth + fractionWidth > 52) { throw RohdHclException('Fixed-point value is too wide to convert.'); } if (!this.value.isValid) { @@ -208,7 +174,7 @@ class FixedPointValue implements Comparable { } else { number = this.value.toBigInt(); } - final value = number.toDouble() / pow(2, n).toDouble(); + final value = number.toDouble() / pow(2, fractionWidth).toDouble(); return isNegative() ? -value : value; } @@ -221,11 +187,19 @@ class FixedPointValue implements Comparable { throw RohdHclException('Inputs must be valid.'); } final s = signed | other.signed; - final nr = max(n, other.n); - final mr = max(m, other.m) + 1; - final val1 = expandWidth(sign: s, m: mr, n: nr); - final val2 = other.expandWidth(sign: s, m: mr, n: nr); - return FixedPointValue(value: val1 + val2, signed: s, m: mr, n: nr); + final nr = max(fractionWidth, other.fractionWidth); + final mr = max(integerWidth, other.integerWidth) + 1; + final val1 = FixedPointValue.populator( + integerWidth: mr, fractionWidth: nr, signed: s) + .widen(this) + .value; + final val2 = FixedPointValue.populator( + integerWidth: mr, fractionWidth: nr, signed: s) + .widen(other) + .value; + return FixedPointValue.populator( + integerWidth: mr, fractionWidth: nr, signed: s) + .ofLogicValue(val1 + val2); } /// Subtraction operation that returns a FixedPointValue. @@ -237,11 +211,19 @@ class FixedPointValue implements Comparable { throw RohdHclException('Inputs must be valid.'); } const s = true; - final nr = max(n, other.n); - final mr = max(m, other.m) + 1; - final val1 = expandWidth(sign: s, m: mr, n: nr); - final val2 = other.expandWidth(sign: s, m: mr, n: nr); - return FixedPointValue(value: val1 - val2, signed: s, m: mr, n: nr); + final nr = max(fractionWidth, other.fractionWidth); + final mr = max(integerWidth, other.integerWidth) + 1; + final val1 = FixedPointValue.populator( + integerWidth: mr, fractionWidth: nr, signed: s) + .widen(this) + .value; + final val2 = FixedPointValue.populator( + integerWidth: mr, fractionWidth: nr, signed: s) + .widen(other) + .value; + return FixedPointValue.populator( + integerWidth: mr, fractionWidth: nr, signed: s) + .ofLogicValue(val1 - val2); } /// Multiplication operation that returns a FixedPointValue. @@ -252,12 +234,26 @@ class FixedPointValue implements Comparable { throw RohdHclException('Inputs must be valid.'); } final s = signed | other.signed; - final mr = s ? m + other.m + 1 : m + other.m; - final nr = n + other.n; + final mr = s + ? integerWidth + other.integerWidth + 1 + : integerWidth + other.integerWidth; + final nr = fractionWidth + other.fractionWidth; final tr = mr + nr; - final val1 = expandWidth(sign: s, m: tr - n); - final val2 = other.expandWidth(sign: s, m: tr - other.n); - return FixedPointValue(value: val1 * val2, signed: s, m: mr, n: nr); + final val1 = FixedPointValue.populator( + integerWidth: tr - fractionWidth, + fractionWidth: fractionWidth, + signed: s) + .widen(this) + .value; + final val2 = FixedPointValue.populator( + integerWidth: tr - other.fractionWidth, + fractionWidth: other.fractionWidth, + signed: s) + .widen(other) + .value; + return FixedPointValue.populator( + integerWidth: mr, fractionWidth: nr, signed: s) + .ofLogicValue(val1 * val2); } /// Division operation that returns a FixedPointValue. @@ -271,13 +267,21 @@ class FixedPointValue implements Comparable { } final s = signed | other.signed; // extend integer width for max negative number - final m1 = s ? m + 1 : m; - final m2 = s ? other.m + 1 : other.m; - final mr = m1 + other.n; - final nr = n + m2; + final m1 = s ? integerWidth + 1 : integerWidth; + final m2 = s ? other.integerWidth + 1 : other.integerWidth; + final mr = m1 + other.fractionWidth; + final nr = fractionWidth + m2; final tr = mr + nr; - var val1 = expandWidth(sign: s, m: m1, n: tr - m1); - var val2 = other.expandWidth(sign: s, m: tr - other.n); + var val1 = FixedPointValue.populator( + integerWidth: m1, fractionWidth: tr - m1, signed: s) + .widen(this) + .value; + var val2 = FixedPointValue.populator( + integerWidth: tr - other.fractionWidth, + fractionWidth: other.fractionWidth, + signed: s) + .widen(other) + .value; // Convert to positive as needed if (s) { if (val1[-1] == LogicValue.one) { @@ -292,6 +296,8 @@ class FixedPointValue implements Comparable { if (isNegative() != other.isNegative()) { val = (~val) + 1; } - return FixedPointValue(value: val, signed: s, m: mr, n: nr); + return FixedPointValue.populator( + integerWidth: mr, fractionWidth: nr, signed: s) + .ofLogicValue(val); } } diff --git a/lib/src/component_config/components/config_fixed_sqrt.dart b/lib/src/component_config/components/config_fixed_sqrt.dart index f8ecc8c0d..b92ba550d 100644 --- a/lib/src/component_config/components/config_fixed_sqrt.dart +++ b/lib/src/component_config/components/config_fixed_sqrt.dart @@ -13,22 +13,24 @@ import 'package:rohd_hcl/rohd_hcl.dart'; /// A [Configurator] for [FixedPointSqrt]. class FixedPointSqrtConfigurator extends Configurator { /// Controls the size of the integer 'm'. - final IntConfigKnob mWidthKnob = IntConfigKnob(value: 8); + final IntConfigKnob integerWidthKnob = IntConfigKnob(value: 8); /// Controls the size of the fraction 'n'. - final IntConfigKnob nWidthKnob = IntConfigKnob(value: 4); + final IntConfigKnob fractionWidthKnob = IntConfigKnob(value: 4); @override Module createModule() { - final inp = - FixedPoint(signed: false, m: mWidthKnob.value, n: nWidthKnob.value); + final inp = FixedPoint( + signed: false, + integerWidth: integerWidthKnob.value, + fractionWidth: fractionWidthKnob.value); return FixedPointSqrt(inp); } @override Map> get knobs => { - 'm width': mWidthKnob, - 'n width': nWidthKnob, + 'Integer Width': integerWidthKnob, + 'Fraction Width': fractionWidthKnob, }; @override diff --git a/lib/src/component_config/components/config_fixed_to_float.dart b/lib/src/component_config/components/config_fixed_to_float.dart index 6bb382d4e..da4f79641 100644 --- a/lib/src/component_config/components/config_fixed_to_float.dart +++ b/lib/src/component_config/components/config_fixed_to_float.dart @@ -22,10 +22,10 @@ class FixedToFloatConfigurator extends Configurator { ToggleConfigKnob(value: false); /// Width of integer part. - final IntConfigKnob mKnob = IntConfigKnob(value: 8); + final IntConfigKnob integerWidthKnob = IntConfigKnob(value: 8); /// Width of fractional part. - final IntConfigKnob nKnob = IntConfigKnob(value: 23); + final IntConfigKnob fractionWidthKnob = IntConfigKnob(value: 23); /// Width of exponent, must be greater than 0. final IntConfigKnob exponentWidthKnob = IntConfigKnob(value: 8); @@ -40,19 +40,22 @@ class FixedToFloatConfigurator extends Configurator { late final Map> knobs = UnmodifiableMapView({ 'Signed Input': signKnob, 'Leading Digit Prediction Input': leadingDigitPredictionKnob, - 'Input integer width': mKnob, - 'Input fraction width': nKnob, + 'Input integer width': integerWidthKnob, + 'Input fraction width': fractionWidthKnob, 'Output exponent width': exponentWidthKnob, 'Output mantissa width': mantissaWidthKnob, }); @override Module createModule() => FixedToFloat( - FixedPoint(signed: signKnob.value, m: mKnob.value, n: nKnob.value), + FixedPoint( + signed: signKnob.value, + integerWidth: integerWidthKnob.value, + fractionWidth: fractionWidthKnob.value), FloatingPoint( exponentWidth: exponentWidthKnob.value, mantissaWidth: mantissaWidthKnob.value), leadingDigitPredict: leadingDigitPredictionKnob.value - ? Logic(width: log2Ceil(mKnob.value)) + ? Logic(width: log2Ceil(integerWidthKnob.value)) : null); } diff --git a/test/arithmetic/fixed_sqrt_test.dart b/test/arithmetic/fixed_sqrt_test.dart index fe0736785..82563fa32 100644 --- a/test/arithmetic/fixed_sqrt_test.dart +++ b/test/arithmetic/fixed_sqrt_test.dart @@ -19,14 +19,15 @@ void main() { await Simulator.reset(); }); test('sqrt(negative number)', () async { - final fixed = FixedPoint(signed: true, m: 3, n: 23); + final fixed = FixedPoint(integerWidth: 3, fractionWidth: 23); expect(() => FixedPointSqrt(fixed), throwsException); }); test('Fixed Point: expected correct sqrt', () { const mantissaWidth = 23; - final fixed = FixedPoint(signed: false, m: 3, n: mantissaWidth); + final fixed = FixedPoint( + signed: false, integerWidth: 3, fractionWidth: mantissaWidth); for (final dut in [ FixedPointSqrt(fixed), @@ -42,13 +43,19 @@ void main() { ]; for (final test in testCases) { - fixed.put(FixedPointValue.ofDouble(test, - signed: fixed.signed, m: fixed.m, n: fixed.n)); + fixed.put(FixedPointValue.populator( + integerWidth: fixed.integerWidth, + fractionWidth: fixed.fractionWidth, + signed: fixed.signed) + .ofDouble(test)); final fpvResult = dut.sqrt.fixedPointValue; - final fpvExpected = FixedPointValue.ofDouble(sqrt(test), - signed: fixed.signed, m: fixed.m, n: fixed.n); + final fpvExpected = FixedPointValue.populator( + integerWidth: fixed.integerWidth, + fractionWidth: fixed.fractionWidth, + signed: fixed.signed) + .ofDouble(sqrt(test)); expect(fpvResult, fpvExpected); } } diff --git a/test/arithmetic/fixed_to_float_test.dart b/test/arithmetic/fixed_to_float_test.dart index 2193b01c7..b0f09c815 100644 --- a/test/arithmetic/fixed_to_float_test.dart +++ b/test/arithmetic/fixed_to_float_test.dart @@ -14,10 +14,13 @@ import 'package:test/test.dart'; void main() async { test('FixedToFloat: singleton', () async { - final fixed = FixedPoint(signed: true, m: 34, n: 33); + final fixed = FixedPoint(integerWidth: 34, fractionWidth: 33); const inDouble = -2.0; - fixed.put(FixedPointValue.ofDouble(inDouble, - signed: fixed.signed, m: fixed.m, n: fixed.n)); + fixed.put(FixedPointValue.populator( + integerWidth: fixed.integerWidth, + fractionWidth: fixed.fractionWidth, + signed: fixed.signed) + .ofDouble(inDouble)); final fp = FloatingPoint(exponentWidth: 8, mantissaWidth: 23); final dut = FixedToFloat(fixed, fp); final fpv = dut.float.floatingPointValue; @@ -33,26 +36,30 @@ void main() async { test('FixedToFloat: exhaustive', () async { for (final signed in [false, true]) { - final fixed = FixedPoint(signed: signed, m: 8, n: 8); + final fixed = + FixedPoint(signed: signed, integerWidth: 8, fractionWidth: 8); final dut = FixedToFloat( fixed, signed: signed, FloatingPoint(exponentWidth: 8, mantissaWidth: 16)); await dut.build(); for (var val = 0; val < pow(2, fixed.width); val++) { - final fixedValue = FixedPointValue( - value: LogicValue.ofInt(val, fixed.width), - signed: signed, - m: fixed.m, - n: fixed.n); + final fixedValue = FixedPointValue.populator( + integerWidth: fixed.integerWidth, + fractionWidth: fixed.fractionWidth, + signed: signed) + .ofLogicValue(LogicValue.ofInt(val, fixed.width)); fixed.put(fixedValue); final fpv = dut.float.floatingPointValue; final fpvExpected = FloatingPointValue.populator( exponentWidth: dut.float.exponent.width, mantissaWidth: dut.float.mantissa.width) .ofDouble(fixedValue.toDouble()); - final newFixed = FixedPointValue.ofDouble(fpv.toDouble(), - signed: true, m: fixed.m, n: fixed.n); + final newFixed = FixedPointValue.populator( + integerWidth: fixed.integerWidth, + fractionWidth: fixed.fractionWidth, + signed: fixed.signed) + .ofDouble(fpv.toDouble()); expect(newFixed, equals(fixedValue), reason: ''' fpvdbl=${fpv.toDouble()} $fpv ${newFixed.toDouble()} $newFixed @@ -76,10 +83,14 @@ void main() async { a.put(val1); b.put(val2); - final fixed = FixedPoint(signed: true, m: width ~/ 2 - 1, n: width ~/ 2); + final fixed = + FixedPoint(integerWidth: width ~/ 2 - 1, fractionWidth: width ~/ 2); final val = NativeAdder(a, b).sum.slice(width - 1, 0).value; - final fixedValue = - FixedPointValue(signed: true, value: val, m: fixed.m, n: fixed.n); + final fixedValue = FixedPointValue.populator( + integerWidth: fixed.integerWidth, + fractionWidth: fixed.fractionWidth, + signed: true) + .ofLogicValue(val); fixed.put(fixedValue); final anticipator = LeadingDigitAnticipate(a, b); final dut = FixedToFloat( @@ -88,8 +99,11 @@ void main() async { leadingDigitPredict: anticipator.leadingDigit, ); final fpv = dut.float.floatingPointValue; - final roundTripFixed = FixedPointValue.ofDouble(fpv.toDouble(), - signed: true, m: fixed.m, n: fixed.n); + final roundTripFixed = FixedPointValue.populator( + integerWidth: fixed.integerWidth, + fractionWidth: fixed.fractionWidth, + signed: fixed.signed) + .ofDouble(fpv.toDouble()); expect(roundTripFixed, equals(fixedValue), reason: ''' val1=$val1\t ${a.value.bitString} val2=$val2\t ${b.value.bitString} @@ -109,12 +123,14 @@ void main() async { final val = NativeAdder(a, b).sum.slice(width - 1, 0).value; for (final signed in [false, true]) { final fixed = FixedPoint( - signed: signed, m: width ~/ 2 - (signed ? 1 : 0), n: width ~/ 2); - final fixedValue = FixedPointValue( - value: LogicValue.zero.zeroExtend(fixed.width), signed: signed, - m: fixed.m, - n: fixed.n); + integerWidth: width ~/ 2 - (signed ? 1 : 0), + fractionWidth: width ~/ 2); + final fixedValue = FixedPointValue.populator( + integerWidth: fixed.integerWidth, + fractionWidth: fixed.fractionWidth, + signed: signed) + .ofLogicValue(LogicValue.zero.zeroExtend(fixed.width)); fixed.put(fixedValue); final dut = FixedToFloat( @@ -129,13 +145,18 @@ void main() async { final lVal2 = LogicValue.ofInt(val2, width); a.put(lVal1); b.put(lVal2); - - final fixedValue = FixedPointValue( - value: val, signed: signed, m: fixed.m, n: fixed.n); + final fixedValue = FixedPointValue.populator( + integerWidth: fixed.integerWidth, + fractionWidth: fixed.fractionWidth, + signed: signed) + .ofLogicValue(val); fixed.put(fixedValue); final fpv = dut.float.floatingPointValue; - final roundTripFixed = FixedPointValue.ofDouble(fpv.toDouble(), - signed: signed, m: fixed.m, n: fixed.n); + final roundTripFixed = FixedPointValue.populator( + integerWidth: fixed.integerWidth, + fractionWidth: fixed.fractionWidth, + signed: fixed.signed) + .ofDouble(fpv.toDouble()); expect(roundTripFixed, equals(fixedValue), reason: ''' signed = $signed val1 = $val1 @@ -162,9 +183,12 @@ void main() async { b.put(bv); final tsum = a + b; - final fixed = FixedPoint(signed: true, m: 34, n: 33); - final fixedValue = FixedPointValue( - value: tsum.value, signed: true, m: fixed.m, n: fixed.n); + final fixed = FixedPoint(integerWidth: 34, fractionWidth: 33); + final fixedValue = FixedPointValue.populator( + integerWidth: fixed.integerWidth, + fractionWidth: fixed.fractionWidth, + signed: true) + .ofLogicValue(tsum.value); fixed.put(fixedValue); final leadingDigit = Const(32, width: log2Ceil(68) + 2); final dut = FixedToFloat( @@ -196,12 +220,13 @@ void main() async { generateValid: true); for (final signed in [true]) { - final fixed = FixedPoint(signed: signed, m: 8, n: 8); - final fixedValue = FixedPointValue( - value: LogicValue.zero.zeroExtend(width + 1), - signed: signed, - m: fixed.m, - n: fixed.n); + final fixed = + FixedPoint(signed: signed, integerWidth: 8, fractionWidth: 8); + final fixedValue = FixedPointValue.populator( + integerWidth: fixed.integerWidth, + fractionWidth: fixed.fractionWidth, + signed: signed) + .ofLogicValue(LogicValue.zero.zeroExtend(width + 1)); fixed.put(fixedValue); final golden = FixedToFloat( fixed, @@ -221,9 +246,11 @@ void main() async { final lVal = LogicValue.ofInt(val, fixed.width); // Use a leading one detector on both positive and negative numbers leadPredictIn.put(signed & !lVal[-1].isZero ? ~val : val); - - final fixedValue = FixedPointValue( - value: lVal, signed: signed, m: fixed.m, n: fixed.n); + final fixedValue = FixedPointValue.populator( + integerWidth: fixed.integerWidth, + fractionWidth: fixed.fractionWidth, + signed: signed) + .ofLogicValue(lVal); fixed.put(fixedValue); final fpvGolden = golden.float.floatingPointValue; @@ -252,16 +279,16 @@ void main() async { }); test('Q16.16 to E5M2 < pow(2,14)', () async { - final fixed = FixedPoint(signed: true, m: 16, n: 16); + final fixed = FixedPoint(integerWidth: 16, fractionWidth: 16); final dut = FixedToFloat(fixed, FloatingPoint(exponentWidth: 5, mantissaWidth: 2)); await dut.build(); for (var val = 0; val < pow(2, 14); val++) { - final fixedValue = FixedPointValue( - value: LogicValue.ofInt(val, fixed.width), - signed: true, - m: fixed.m, - n: fixed.n); + final fixedValue = FixedPointValue.populator( + integerWidth: fixed.integerWidth, + fractionWidth: fixed.fractionWidth, + signed: true) + .ofLogicValue(LogicValue.ofInt(val, fixed.width)); fixed.put(fixedValue); final fpv = dut.float.floatingPointValue; final fpvExpected = FloatingPointValue.populator( @@ -277,16 +304,16 @@ void main() async { }); test('Signed Q4.4 to E3M2', () async { - final fixed = FixedPoint(signed: true, m: 4, n: 4); + final fixed = FixedPoint(integerWidth: 4, fractionWidth: 4); final dut = FixedToFloat(fixed, FloatingPoint(exponentWidth: 3, mantissaWidth: 2)); await dut.build(); for (var val = 0; val < pow(2, fixed.width); val++) { - final fixedValue = FixedPointValue( - value: LogicValue.ofInt(val, fixed.width), - signed: fixed.signed, - m: fixed.m, - n: fixed.n); + final fixedValue = FixedPointValue.populator( + integerWidth: fixed.integerWidth, + fractionWidth: fixed.fractionWidth, + signed: true) + .ofLogicValue(LogicValue.ofInt(val, fixed.width)); fixed.put(fixedValue); final fpv = dut.float.floatingPointValue; final fpvExpected = FloatingPointValue.populator( @@ -302,16 +329,15 @@ void main() async { }); test('Unsigned Q4.4 to E3M2', () async { - final fixed = FixedPoint(signed: false, m: 4, n: 4); + final fixed = FixedPoint(signed: false, integerWidth: 4, fractionWidth: 4); final dut = FixedToFloat(fixed, FloatingPoint(exponentWidth: 3, mantissaWidth: 2)); await dut.build(); for (var val = 0; val < pow(2, fixed.width); val++) { - final fixedValue = FixedPointValue( - value: LogicValue.ofInt(val, fixed.width), - signed: fixed.signed, - m: fixed.m, - n: fixed.n); + final fixedValue = FixedPointValue.populator( + integerWidth: fixed.integerWidth, + fractionWidth: fixed.fractionWidth) + .ofLogicValue(LogicValue.ofInt(val, fixed.width)); fixed.put(fixedValue); final fpv = dut.float.floatingPointValue; final fpvExpected = FloatingPointValue.populator( @@ -327,16 +353,16 @@ void main() async { }); test('Signed Q0.8 to E3M2 shrink', () async { - final fixed = FixedPoint(signed: true, m: 0, n: 7); + final fixed = FixedPoint(integerWidth: 0, fractionWidth: 7); final dut = FixedToFloat(fixed, FloatingPoint(exponentWidth: 3, mantissaWidth: 2)); await dut.build(); for (var val = 0; val < pow(2, fixed.width); val++) { - final fixedValue = FixedPointValue( - value: LogicValue.ofInt(val, fixed.width), - signed: fixed.signed, - m: fixed.m, - n: fixed.n); + final fixedValue = FixedPointValue.populator( + integerWidth: fixed.integerWidth, + fractionWidth: fixed.fractionWidth, + signed: true) + .ofLogicValue(LogicValue.ofInt(val, fixed.width)); fixed.put(fixedValue); final fpv = dut.float.floatingPointValue; final fpvExpected = FloatingPointValue.populator( @@ -352,16 +378,16 @@ void main() async { }); test('Signed Q0.3 to E5M6 expand', () async { - final fixed = FixedPoint(signed: true, m: 0, n: 3); + final fixed = FixedPoint(integerWidth: 0, fractionWidth: 3); final dut = FixedToFloat(fixed, FloatingPoint(exponentWidth: 5, mantissaWidth: 6)); await dut.build(); for (var val = 0; val < pow(2, fixed.width); val++) { - final fixedValue = FixedPointValue( - value: LogicValue.ofInt(val, fixed.width), - signed: fixed.signed, - m: fixed.m, - n: fixed.n); + final fixedValue = FixedPointValue.populator( + integerWidth: fixed.integerWidth, + fractionWidth: fixed.fractionWidth, + signed: true) + .ofLogicValue(LogicValue.ofInt(val, fixed.width)); fixed.put(fixedValue); final fpv = dut.float.floatingPointValue; final fpvExpected = FloatingPointValue.populator( @@ -377,16 +403,17 @@ void main() async { }); test('Signed Q7.0 to E3M2', () async { - final fixed = FixedPoint(signed: true, m: 7, n: 0); + final fixed = FixedPoint(integerWidth: 7, fractionWidth: 0); final dut = FixedToFloat(fixed, FloatingPoint(exponentWidth: 3, mantissaWidth: 2)); await dut.build(); for (var val = 0; val < pow(2, fixed.width); val++) { - final fixedValue = FixedPointValue( - value: LogicValue.ofInt(val, fixed.width), - signed: fixed.signed, - m: fixed.m, - n: fixed.n); + final fixedValue = FixedPointValue.populator( + integerWidth: fixed.integerWidth, + fractionWidth: fixed.fractionWidth, + signed: true) + .ofLogicValue(LogicValue.ofInt(val, fixed.width)); + fixed.put(fixedValue); final fpv = dut.float.floatingPointValue; final fpvExpected = FloatingPointValue.populator( diff --git a/test/arithmetic/float_to_fixed_test.dart b/test/arithmetic/float_to_fixed_test.dart index 07a54b271..7dcd42e4f 100644 --- a/test/arithmetic/float_to_fixed_test.dart +++ b/test/arithmetic/float_to_fixed_test.dart @@ -24,8 +24,11 @@ void main() async { if (!fpv.isAnInfinity & !fpv.isNaN) { float.put(fpv); final fxp = dut.fixed; - final fxpExp = FixedPointValue.ofDouble(fpv.toDouble(), - signed: true, m: dut.m, n: dut.n); + final fxpExp = FixedPointValue.populator( + integerWidth: dut.integerWidth, + fractionWidth: dut.fractionWidth, + signed: true) + .ofDouble(fpv.toDouble()); expect(fxp.value.bitString, fxpExp.value.bitString); } } @@ -62,11 +65,12 @@ void main() async { final fp1 = FloatingPoint(exponentWidth: sEW, mantissaWidth: sMW) ..put(0); final nominal = FloatToFixed(fp1); - for (var i = 0; i < nominal.n - 2; i++) { - final tN = nominal.n - i; - for (var j = 0; j < nominal.m - 2; j++) { - final tM = nominal.m - j; - final convert = FloatToFixed(fp1, m: tM, n: tN); + for (var i = 0; i < nominal.fractionWidth - 2; i++) { + final tN = nominal.fractionWidth - i; + for (var j = 0; j < nominal.integerWidth - 2; j++) { + final tM = nominal.integerWidth - j; + final convert = + FloatToFixed(fp1, integerWidth: tM, fractionWidth: tN); final fxc = convert.fixed; for (final negate in [false, true]) { for (var e1 = 0; e1 < pow(2, sEW) - 1; e1++) { @@ -76,10 +80,11 @@ void main() async { .ofInts(e1, m1, sign: negate); fp1.put(fv1.value); final val = fv1.toDouble(); - if (FixedPointValue.canStore(val, + if (FixedPointValuePopulator.canStore(val, signed: true, m: tM, n: tN)) { - final fx = FixedPointValue.ofDouble(fv1.toDouble(), - signed: true, m: tM, n: tN); + final fx = FixedPointValue.populator( + integerWidth: tM, fractionWidth: tN, signed: true) + .ofDouble(fv1.toDouble()); expect(fxc.fixedPointValue, equals(fx), reason: ''' $fx (${fx.toDouble()}) @@ -113,10 +118,11 @@ void main() async { final fp1 = FloatingPoint(exponentWidth: sEW, mantissaWidth: sMW) ..put(0); final nominal = FloatToFixed(fp1); - for (var i = 0; i < nominal.n - 2; i++) { - final tN = nominal.n - i; - final tM = nominal.m; - final convert = FloatToFixed(fp1, m: tM, n: tN); + for (var i = 0; i < nominal.fractionWidth - 2; i++) { + final tN = nominal.fractionWidth - i; + final tM = nominal.integerWidth; + final convert = + FloatToFixed(fp1, integerWidth: tM, fractionWidth: tN); for (final negate in [false, true]) { for (var e1 = 0; e1 < pow(2, sEW) - 1; e1++) { for (var m1 = 0; m1 < pow(2, sMW); m1++) { @@ -125,9 +131,9 @@ void main() async { .ofInts(e1, m1, sign: negate); fp1.put(fv1.value); final fxc = convert.fixed; - - final fx = FixedPointValue.ofDouble(fv1.toDouble(), - signed: true, m: tM, n: tN); + final fx = FixedPointValue.populator( + integerWidth: tM, fractionWidth: tN, signed: true) + .ofDouble(fv1.toDouble()); expect(fxc.fixedPointValue, equals(fx), reason: ''' $fx (${fx.toDouble()}) @@ -155,10 +161,12 @@ void main() async { final fp1 = FloatingPoint(exponentWidth: sEW, mantissaWidth: sMW) ..put(0); final nominal = FloatToFixed(fp1); - for (var i = 0; i < nominal.m - 2; i++) { - final tM = nominal.m - i; - final convert = - FloatToFixed(fp1, m: tM, n: nominal.n, checkOverflow: true); + for (var i = 0; i < nominal.integerWidth - 2; i++) { + final tM = nominal.integerWidth - i; + final convert = FloatToFixed(fp1, + integerWidth: tM, + fractionWidth: nominal.fractionWidth, + checkOverflow: true); for (final negate in [false, true]) { for (var e1 = 0; e1 < pow(2, sEW) - 1; e1++) { for (var m1 = 0; m1 < pow(2, sMW); m1++) { @@ -187,7 +195,9 @@ void main() async { final fp1 = FloatingPoint(exponentWidth: sEW, mantissaWidth: sMW) ..put(0); final nominal = FloatToFixed(fp1); - final convert = FloatToFixed(fp1, m: nominal.m + 4, n: nominal.n + 2); + final convert = FloatToFixed(fp1, + integerWidth: nominal.integerWidth + 4, + fractionWidth: nominal.fractionWidth + 2); for (final negate in [false, true]) { for (var e1 = 0; e1 < pow(2, sEW) - 1; e1++) { for (var m1 = 0; m1 < pow(2, sMW); m1++) { @@ -220,8 +230,9 @@ void main() async { .ofLogicValue(LogicValue.ofInt(val, float.width)); if (!fp8.isNaN & !fp8.isAnInfinity) { float.put(fp8.value); - final fx8 = - FixedPointValue.ofDouble(fp8.toDouble(), signed: true, m: 23, n: 9); + final fx8 = FixedPointValue.populator( + integerWidth: 23, fractionWidth: 9, signed: true) + .ofDouble(fp8.toDouble()); expect(dut.fixed.value.bitString, fx8.value.bitString); expect(dut.q23p9.value, fx8.value); } @@ -235,8 +246,9 @@ void main() async { .ofLogicValue(LogicValue.ofInt(val, float.width)); if (!fp8.isNaN & !fp8.isAnInfinity) { float.put(fp8.value); - final fx8 = FixedPointValue.ofDouble(fp8.toDouble(), - signed: true, m: 16, n: 16); + final fx8 = FixedPointValue.populator( + integerWidth: 16, fractionWidth: 16, signed: true) + .ofDouble(fp8.toDouble()); expect(dut.fixed.value.bitString, fx8.value.bitString); expect(dut.q16p16.value, fx8.value); } @@ -249,17 +261,19 @@ void main() async { bf16.put(bf16Val); const m = 18; const n = 16; - final convert = FloatToFixed(bf16, m: m, n: n); + final convert = FloatToFixed(bf16, integerWidth: m, fractionWidth: n); final expectedDbl = bf16Val.toDouble(); - if (FixedPointValue.canStore(expectedDbl, - signed: true, m: convert.m, n: convert.n)) { - final expected = - FixedPointValue.ofDouble(expectedDbl, signed: true, m: m, n: n); + if (FixedPointValuePopulator.canStore(expectedDbl, + signed: true, m: convert.integerWidth, n: convert.fractionWidth)) { + final expected = FixedPointValue.populator( + integerWidth: m, fractionWidth: n, signed: true) + .ofDouble(expectedDbl); final fixedVal = convert.fixed; final computedDbl = fixedVal.fixedPointValue.toDouble(); - final computed = - FixedPointValue.ofDouble(computedDbl, signed: true, m: m, n: n); + final computed = FixedPointValue.populator( + integerWidth: m, fractionWidth: n, signed: true) + .ofDouble(computedDbl); expect(expected, equals(computed), reason: ''' expected=$expected ($expectedDbl) computed=$computed ($computedDbl) @@ -270,21 +284,23 @@ void main() async { final bf16 = FloatingPointBF16()..put(0); const m = 18; const n = 16; - final convert = FloatToFixed(bf16, m: m, n: n); + final convert = FloatToFixed(bf16, integerWidth: m, fractionWidth: n); for (var i = 0; i < pow(2, 16); i++) { final val = LogicValue.ofInt(i, 16); final bf16Val = FloatingPointBF16Value.populator().ofLogicValue(val); bf16.put(bf16Val); final expectedDbl = bf16Val.toDouble(); - if (FixedPointValue.canStore(expectedDbl, - signed: true, m: convert.m, n: convert.n)) { - final expected = - FixedPointValue.ofDouble(expectedDbl, signed: true, m: m, n: n); + if (FixedPointValuePopulator.canStore(expectedDbl, + signed: true, m: convert.integerWidth, n: convert.fractionWidth)) { + final expected = FixedPointValue.populator( + integerWidth: m, fractionWidth: n, signed: true) + .ofDouble(expectedDbl); final fixedVal = convert.fixed; final computedDbl = fixedVal.fixedPointValue.toDouble(); - final computed = - FixedPointValue.ofDouble(computedDbl, signed: true, m: m, n: n); + final computed = FixedPointValue.populator( + integerWidth: m, fractionWidth: n, signed: true) + .ofDouble(computedDbl); expect(expected, equals(computed), reason: ''' expected=$expected ($expectedDbl) computed=$computed ($computedDbl) diff --git a/test/arithmetic/values/fixed_point_value_test.dart b/test/arithmetic/values/fixed_point_value_test.dart index 206c19751..8ed657f79 100644 --- a/test/arithmetic/values/fixed_point_value_test.dart +++ b/test/arithmetic/values/fixed_point_value_test.dart @@ -23,14 +23,14 @@ void main() { (LogicValue.filled(128, LogicValue.one), false, 128, 0, 128), ]; for (var c = 0; c < corners.length; c++) { - final fxp = FixedPointValue( - value: corners[c].$1, - signed: corners[c].$2, - m: corners[c].$3, - n: corners[c].$4); + final pop = FixedPointValue.populator( + integerWidth: corners[c].$3, + fractionWidth: corners[c].$4, + signed: corners[c].$2); + final fxp = pop.ofLogicValue(corners[c].$1); + expect(fxp.value.width, corners[c].$5); expect(corners[c].$1, fxp.value); expect(fxp.signed, corners[c].$2); - expect(fxp.value.width, corners[c].$5); } }); @@ -51,13 +51,19 @@ void main() { ('1100', true, 3, 0, true, 4, 2, '1110000'), ]; for (var c = 0; c < corners.length; c++) { - final fxp = FixedPointValue( - value: LogicValue.ofString(corners[c].$1), - signed: corners[c].$2, - m: corners[c].$3, - n: corners[c].$4); - final value = fxp.expandWidth( - sign: corners[c].$5, m: corners[c].$6, n: corners[c].$7); + final fxp = FixedPointValue.populator( + integerWidth: corners[c].$3, + fractionWidth: corners[c].$4, + signed: corners[c].$2) + .ofLogicValue(LogicValue.ofString(corners[c].$1)); + + final value = FixedPointValue.populator( + integerWidth: corners[c].$6, + fractionWidth: corners[c].$7, + signed: corners[c].$5) + .widen(fxp) + .value; + expect(value, LogicValue.ofString(corners[c].$8), reason: value.bitString); } @@ -79,16 +85,16 @@ void main() { ('10000', true, 2, 2, '0111000', true, 3, 3, lessThan(0)), ]; for (var c = 0; c < corners.length; c++) { - final fxp1 = FixedPointValue( - value: LogicValue.ofString(corners[c].$1), - signed: corners[c].$2, - m: corners[c].$3, - n: corners[c].$4); - final fxp2 = FixedPointValue( - value: LogicValue.ofString(corners[c].$5), - signed: corners[c].$6, - m: corners[c].$7, - n: corners[c].$8); + final fxp1 = FixedPointValue.populator( + integerWidth: corners[c].$3, + fractionWidth: corners[c].$4, + signed: corners[c].$2) + .ofLogicValue(LogicValue.ofString(corners[c].$1)); + final fxp2 = FixedPointValue.populator( + integerWidth: corners[c].$7, + fractionWidth: corners[c].$8, + signed: corners[c].$6) + .ofLogicValue(LogicValue.ofString(corners[c].$5)); expect(fxp1.compareTo(fxp2), corners[c].$9); } }); @@ -106,8 +112,12 @@ void main() { ]; for (var c = 0; c < corners.length; c++) { final number = corners[c].$4; - final fxp = FixedPointValue.ofDouble(number, - signed: true, m: corners[c].$2, n: corners[c].$3); + final fxp = FixedPointValue.populator( + integerWidth: corners[c].$2, + fractionWidth: corners[c].$3, + signed: true) + .ofDouble(number); + expect(fxp.value.bitString, corners[c].$1); expect(fxp.toDouble(), number); } @@ -122,8 +132,9 @@ void main() { ]); for (var c = 0; c < corners.length; c++) { final number = corners[c].$4; - final fxp = FixedPointValue.ofDouble(number, - signed: false, m: corners[c].$2, n: corners[c].$3); + final fxp = FixedPointValue.populator( + integerWidth: corners[c].$2, fractionWidth: corners[c].$3) + .ofDouble(number); expect(fxp.value.bitString, corners[c].$1); expect(fxp.toDouble(), number); } @@ -131,8 +142,8 @@ void main() { for (var i = 0; i < pow(2, 4); i++) { for (var m = 0; m < 5; m++) { final n = 4 - m; - final fxp = FixedPointValue( - value: LogicValue.ofInt(i, 4), signed: false, m: m, n: n); + final fxp = FixedPointValue.populator(integerWidth: m, fractionWidth: n) + .ofLogicValue(LogicValue.ofInt(i, 4)); expect(fxp.value.width, 4); expect(fxp.toDouble(), i / pow(2, n)); } @@ -141,36 +152,53 @@ void main() { test('Comparison operators', () { expect( - FixedPointValue.ofDouble(14.432, signed: false, m: 4, n: 2) - .eq(FixedPointValue.ofDouble(14.432, signed: false, m: 4, n: 2)), + FixedPointValue.populator( + integerWidth: 4, fractionWidth: 2, signed: true) + .ofDouble(14.432) + .eq(FixedPointValue.populator(integerWidth: 4, fractionWidth: 2) + .ofDouble(14.432)), LogicValue.one); expect( - FixedPointValue.ofDouble(14.432, signed: false, m: 4, n: 2) - .neq(FixedPointValue.ofDouble(14.432, signed: false, m: 4, n: 2)), + FixedPointValue.populator(integerWidth: 4, fractionWidth: 2) + .ofDouble(14.432) + .neq(FixedPointValue.populator(integerWidth: 4, fractionWidth: 2) + .ofDouble(14.432)), LogicValue.zero); expect( - FixedPointValue.ofDouble(13.454, signed: false, m: 4, n: 2) > - (FixedPointValue.ofDouble(14, signed: false, m: 4, n: 2)), + FixedPointValue.populator(integerWidth: 4, fractionWidth: 2) + .ofDouble(13.454) > + FixedPointValue.populator(integerWidth: 4, fractionWidth: 2) + .ofDouble(14), LogicValue.zero); expect( - FixedPointValue.ofDouble(13.454, signed: false, m: 4, n: 2) >= - (FixedPointValue.ofDouble(14, signed: false, m: 4, n: 2)), + FixedPointValue.populator(integerWidth: 4, fractionWidth: 2) + .ofDouble(13.454) >= + FixedPointValue.populator(integerWidth: 4, fractionWidth: 2) + .ofDouble(14), LogicValue.zero); expect( - FixedPointValue.ofDouble(13.454, signed: false, m: 4, n: 2) < - (FixedPointValue.ofDouble(14, signed: false, m: 4, n: 2)), + FixedPointValue.populator(integerWidth: 4, fractionWidth: 2) + .ofDouble(13.454) < + FixedPointValue.populator(integerWidth: 4, fractionWidth: 2) + .ofDouble(14), LogicValue.one); expect( - FixedPointValue.ofDouble(13.454, signed: false, m: 4, n: 2) <= - (FixedPointValue.ofDouble(14, signed: false, m: 4, n: 2)), + FixedPointValue.populator(integerWidth: 4, fractionWidth: 2) + .ofDouble(13.454) <= + FixedPointValue.populator(integerWidth: 4, fractionWidth: 2) + .ofDouble(14), LogicValue.one); expect( - FixedPointValue.ofDouble(14, signed: false, m: 4, n: 2) <= - (FixedPointValue.ofDouble(14, signed: false, m: 4, n: 2)), + FixedPointValue.populator(integerWidth: 4, fractionWidth: 2) + .ofDouble(14) <= + FixedPointValue.populator(integerWidth: 4, fractionWidth: 2) + .ofDouble(14), LogicValue.one); expect( - FixedPointValue.ofDouble(14, signed: false, m: 4, n: 2) >= - (FixedPointValue.ofDouble(14, signed: false, m: 4, n: 2)), + FixedPointValue.populator(integerWidth: 4, fractionWidth: 2) + .ofDouble(14) >= + FixedPointValue.populator(integerWidth: 4, fractionWidth: 2) + .ofDouble(14), LogicValue.one); }); @@ -179,14 +207,17 @@ void main() { const m = 3; const n = 4; for (var i = 0; i < pow(2, width); i++) { - final fxv = FixedPointValue( - value: LogicValue.ofInt(i, width), signed: true, m: m, n: n); + final fxv = FixedPointValue.populator(integerWidth: m, fractionWidth: n) + .ofLogicValue(LogicValue.ofInt(i, width)); final dbl = fxv.toDouble(); - if (!FixedPointValue.canStore(dbl, - signed: fxv.signed, m: fxv.m, n: fxv.n)) { + if (!FixedPointValuePopulator.canStore(dbl, + signed: fxv.signed, m: fxv.integerWidth, n: fxv.fractionWidth)) { throw RohdHclException('generated a value that we cannot store'); } - final fxv2 = FixedPointValue.ofDouble(dbl, signed: true, m: m, n: n); + final fxv2 = FixedPointValue.populator( + integerWidth: m, fractionWidth: n, signed: true) + .ofDouble(dbl); + expect(fxv, equals(fxv2)); } }); @@ -204,37 +235,34 @@ void main() { for (var s2 = 0; s2 < 2; s2++) { final n1 = s1 == 0 ? w - m1 - 1 : w - m1; final n2 = s2 == 0 ? w - m2 - 1 : w - m2; - fxp1 = FixedPointValue( - value: LogicValue.ofInt(i1, w), - signed: s1 == 0, - m: m1, - n: n1); - fxp2 = FixedPointValue( - value: LogicValue.ofInt(i2, w), - signed: s2 == 0, - m: m2, - n: n2); + fxp1 = FixedPointValue.populator( + integerWidth: m1, fractionWidth: n1, signed: s1 == 0) + .ofLogicValue(LogicValue.ofInt(i1, w)); + + fxp2 = FixedPointValue.populator( + integerWidth: m2, fractionWidth: n2, signed: s2 == 0) + .ofLogicValue(LogicValue.ofInt(i2, w)); // add fxp = fxp1 + fxp2; expect(fxp.toDouble(), fxp1.toDouble() + fxp2.toDouble(), reason: '+'); - expect(fxp.n, max(n1, n2)); - expect(fxp.m, max(m1, m2) + 1); + expect(fxp.fractionWidth, max(n1, n2)); + expect(fxp.integerWidth, max(m1, m2) + 1); // subtract fxp = fxp1 - fxp2; expect(fxp.toDouble(), fxp1.toDouble() - fxp2.toDouble(), reason: '-'); - expect(fxp.n, max(n1, n2)); - expect(fxp.m, max(m1, m2) + 1); + expect(fxp.fractionWidth, max(n1, n2)); + expect(fxp.integerWidth, max(m1, m2) + 1); // multiply fxp = fxp1 * fxp2; expect(fxp.toDouble(), fxp1.toDouble() * fxp2.toDouble(), reason: '${fxp1.toDouble()}*${fxp2.toDouble()}'); - expect(fxp.n, n1 + n2); - expect(fxp.m, s1 + s2 == 2 ? m1 + m2 : m1 + m2 + 1); + expect(fxp.fractionWidth, n1 + n2); + expect(fxp.integerWidth, s1 + s2 == 2 ? m1 + m2 : m1 + m2 + 1); // divide fxp = fxp1 / fxp2;