From 9c48f72ecd6d767263e72e5536e8fdc896fd4ed3 Mon Sep 17 00:00:00 2001 From: Galileo Newton Date: Mon, 23 Dec 2024 17:08:09 -0800 Subject: [PATCH 1/3] adder api and documentation cleanup --- doc/README.md | 26 +-- doc/components/adder.md | 45 +++--- doc/components/fixed_point.md | 8 +- doc/components/floating_point.md | 34 ++-- lib/src/arithmetic/adder.dart | 55 +++---- lib/src/arithmetic/carry_save_mutiplier.dart | 8 +- lib/src/arithmetic/compound_adder.dart | 16 +- .../floating_point_adder_round.dart | 3 +- .../floating_point_adder_simple.dart | 3 +- lib/src/arithmetic/ones_complement_adder.dart | 3 +- .../parallel_prefix_operations.dart | 25 ++- lib/src/arithmetic/ripple_carry_adder.dart | 12 +- lib/src/arithmetic/sign_magnitude_adder.dart | 2 +- .../config_floating_point_adder_round.dart | 11 +- .../config_parallel_prefix_adder.dart | 1 + pubspec.yaml | 12 +- test/arithmetic/adder_test.dart | 149 +++++++++++------- .../carry_save_multiplier_test.dart | 2 +- test/arithmetic/compound_adder_test.dart | 1 + 19 files changed, 245 insertions(+), 171 deletions(-) diff --git a/doc/README.md b/doc/README.md index fd6876234..a653b4180 100644 --- a/doc/README.md +++ b/doc/README.md @@ -11,6 +11,7 @@ Some in-development items will have opened issues, as well. Feel free to create - [Binary to Gray](./components/binary_gray.md#binary-to-gray) - [Gray to Binary](./components/binary_gray.md#gray-to-binary) - Priority + - [Prefix-tree based Priority Encoder](./components/parallel_prefix_operations.md) - PLAs - Arbiters - [Priority Arbiter](./components/arbiter.md#priority-arbiter) @@ -19,7 +20,7 @@ Some in-development items will have opened issues, as well. Feel free to create - [Synchronous FIFO](./components/fifo.md) - Asynchronous / clock-crossing FIFO - [Shift register](./components/shift_register.md) -- Find +- [Find](./components/find.md) - [Find N'th bit (0 or 1) from the start/end](./components/find.md#find-nth) - [Extrema](./components/extrema.md) - Find N'th pattern from the start/end @@ -37,10 +38,12 @@ Some in-development items will have opened issues, as well. Feel free to create - [Incrementer](./components/parallel_prefix_operations.md) - [Decrementer](./components/parallel_prefix_operations.md) - [Adders](./components/adder.md) - - [Sign Magnitude Adder](./components/adder.md#ripple-carry-adder) + - [Ripple Carry Adder](./components/adder.md#ripple-carry-adder) - [Parallel Prefix Adder](./components/parallel_prefix_operations.md) + - [Sign Magnitude Adder](./components/adder.md#sign-magnitude-adder) + - [compound Adder](./components/adder.md#compound-adder) - Subtractors - - [One's Complement Adder Subtractor](./components/adder.md#ones-complement-adder-subtractor) + - [Ones Complement Adder Subtractor](./components/adder.md#ones-complement-adder-subtractor) - Multipliers - [Pipelined Integer Multiplier](./components/multiplier.md#carry-save-multiplier) - [Compression Tree Multiplier](./components/multiplier.md#compression-tree-multiplier) @@ -52,14 +55,17 @@ Some in-development items will have opened issues, as well. Feel free to create - Square root - Inverse square root - Floating point - - [Floating-Point Value Types](./components/floating_point.md) - - Double (64-bit) - - Float (32-bit) - - BFloat16 (16-bit) - - BFloat8 (8-bit) - - BFloat4 (4-bit) + - [Floating-Point Value Types](./components/floating_point.md#floatingpointvalue) + - Double (64-bit) + - Float (32-bit) + - BFloat16 (16-bit) + - TensorFloat32 (32-bit) + - 8-bit E4/M3 and E5/M2 - [Simple Floating-Point Adder](./components/floating_point.md#floatingpointadder) - - Fixed point + - [Rounding Floating-Point Adder](./components/floating_point.md#floatingpointadder) + - [Fixed point](./components/fixed_point.md) + - [FloatToFixed](./components/fixed_point.md#floattofixed) + - [FixedToFloat](./components/fixed_point.md#fixedtofloat) - Binary-Coded Decimal (BCD) - [Rotate](./components/rotate.md) - Counters diff --git a/doc/components/adder.md b/doc/components/adder.md index 7c1e9af17..5d45df212 100644 --- a/doc/components/adder.md +++ b/doc/components/adder.md @@ -1,6 +1,6 @@ -# Adder +# Adders -ROHD-HCL provides a set of adder modules to get the sum from a pair of Logic. As of now, we have +ROHD-HCL provides a set of adder modules to get the sum from a pair of Logic. Adders which provide a carry input have a base class of [AdderCi](https://intel.github.io/rohd-hcl/rohd_hcl/Adder-class.html), those that don't use a base class of [Adder](https://intel.github.io/rohd-hcl/rohd_hcl/Adder-class.html). As of now, ROHD-HCL supplies: - [Ripple Carry Adder](#ripple-carry-adder) - [Parallel Prefix Adder](#parallel-prefix-adder) @@ -10,9 +10,9 @@ ROHD-HCL provides a set of adder modules to get the sum from a pair of Logic. As ## Ripple Carry Adder -A ripple carry adder is a digital circuit used for binary addition. It consists of a series of full adders connected in a chain, with the carry output of each adder linked to the carry input of the next one. Starting from the least significant bit (LSB) to most significant bit (MSB), the adder sequentially adds corresponding bits of two binary numbers. +A ripple carry adder is a digital circuit used for binary addition. It consists of a series of [FullAdder](https://intel.github.io/rohd-hcl/rohd_hcl/FullAdder-class.html)s connected in a chain, with the carry output of each adder linked to the carry input of the next one. Starting from the least significant bit (LSB) to most significant bit (MSB), the adder sequentially adds corresponding bits of two binary numbers. -The [`RippleCarryAdder`](https://intel.github.io/rohd-hcl/rohd_hcl/RippleCarryAdder-class.html) module in ROHD-HCL accept input `Logic`s a and b as the input pin and the name of the module `name`. Note that the width of the inputs must be the same or a `RohdHclException` will be thrown. +The [RippleCarryAdder](https://intel.github.io/rohd-hcl/rohd_hcl/RippleCarryAdder-class.html) module in ROHD-HCL accept input `Logic`s a and b as the input pin and the name of the module `name`. Note that the width of the inputs must be the same or a [RohdHclException](https://intel.github.io/rohd-hcl/rohd_hcl/RohdHclException-class.html) will be thrown. An example is shown below to add two inputs of signals that have 8-bits of width. @@ -29,9 +29,9 @@ final sum = rippleCarryAdder.sum; ## Parallel Prefix Adder -A parallel prefix adder is an adder that uses different varieties of a parallel prefix tree (see `Parallel Prefix Operations`) to efficiently connect a set of `Full Adder` circuits to form a complete adder. +A parallel prefix adder is an adder that uses different varieties of a parallel prefix tree (see [Parallel Prefix Operations](../components/parallel_prefix_operations.md)) to efficiently connect a set of `Full Adder` circuits to form a complete adder. -Here is an example of instantiating a `ParallelPrefixAdder`: +Here is an example of instantiating a [ParallelPrefixAdder](https://intel.github.io/rohd-hcl/rohd_hcl/ParallelPrefixAdder-class.html) : ```dart const width = 6; @@ -48,16 +48,16 @@ Here is an example of instantiating a `ParallelPrefixAdder`: print('${sum.value.toBigInt()}'); ``` -## One's Complement Adder Subtractor +## Ones Complement Adder Subtractor A ones-complement adder (and subtractor) is useful in efficient arithmetic operations as the end-around carry can be bypassed and used later. -The `OnesComplementAdder` can take a subtraction command as either a Logic `subtractIn` or a boolean `subtract` (the Logic overrides the boolean). If Logic `carry` is provided, the end-around carry is output on `carry` and the value will be one less than expected when `carry` is high. An `adderGen` adder function can be provided that generates your favorite internal adder (such as a parallel prefix adder). +The [OnesComplementAdder](https://intel.github.io/rohd-hcl/rohd_hcl/OnesComplementAdder-class.html) can take a subtraction command as either a `Logic` `subtractIn` or a boolean `subtract` (the Logic overrides the boolean). If Logic `carry` is provided, the end-around carry is output on `carry` and the value will be one less than expected when `carry` is high. An `adderGen` adder function can be provided that generates your favorite internal adder (such as a parallel prefix adder). -The output of `OnesComplementAdder` is a `sum` which is the magnitude and a `sign`. +The output of [OnesComplementAdder](https://intel.github.io/rohd-hcl/rohd_hcl/OnesComplementAdder-class.html) is a `sum` which is the magnitude and a `sign`. -Here is an example of instantiating a `OnesComplementAdder` as a subtractor, but saving the `carry`: +Here is an example of instantiating a [OnesComplementAdder](https://intel.github.io/rohd-hcl/rohd_hcl/OnesComplementAdder-class.html) as a subtractor, but saving the `carry`: ```dart const width = 4; @@ -76,13 +76,13 @@ Here is an example of instantiating a `OnesComplementAdder` as a subtractor, but ## Sign Magnitude Adder -A sign magnitude adder is useful in situations where the sign of the addends is separated from their magnitude (e.g., not 2s complement), such as in floating point multipliers. The `SignMagnitudeAdder` inherits from `Adder` but adds the `Logic` inputs for the two operands. +A sign magnitude adder is useful in situations where the sign of the addends is separated from their magnitude (e.g., not 2s complement), such as in floating point multipliers. The [SignMagnitudeAdder](https://intel.github.io/rohd-hcl/rohd_hcl/SignMagnitudeAdder-class.html) inherits from `Adder` but adds the `Logic` inputs for the two operands. If you can supply the largest magnitude number first, then you can disable a comparator generation inside by declaring the `largestMagnitudeFirst` option as true. -The `SignMagnitudeAdder` uses a `OnesComplementAdder` internally. +The [SignMagnitudeAdder](https://intel.github.io/rohd-hcl/rohd_hcl/SignMagnitudeAdder-class.html) uses a [OnesComplementAdder](https://intel.github.io/rohd-hcl/rohd_hcl/OnesComplementAdder-class.html) internally. -Here is an example of instantiating a `SignMagnitudeAdder`: +Here is an example of instantiating a [SignMagnitudeAdder](https://intel.github.io/rohd-hcl/rohd_hcl/SignMagnitudeAdder-class.html): ```dart const width = 6; @@ -106,13 +106,20 @@ Here is an example of instantiating a `SignMagnitudeAdder`: ## Compound Adder -A compound carry adder is a digital circuit used for binary addition. It produces sum and sum+1 outputs. -A trivial compound adder component `TrivialCompoundAdder` doesnt use any RTL code optimization. -Carry-select adder-based compound adder `CarrySelectCompoundAdder` uses carry-select adder as a basis. Like a carry-select adder it consists of a multiple blocks of two ripple-carry adders . But the first block has two ripple-carry adders and two separate carry-propagate chains are used to select sum and sum+1 output bits. Sum selecting chain starts from carry input 0 driven block and sum+1 selecting chain starts from carry input 1 driven block. -The delay of the adder is defined by combination ripple-carry adder and accumulated carry-select chain delay. +A compound carry adder is a digital circuit used for binary addition. It efficiently produces both sum and sum+1 outputs. +A trivial compound adder component [TrivialCompoundAdder](https://intel.github.io/rohd-hcl/rohd_hcl/TrivialCompoundAdder-class.html) doesn't use any RTL code optimization, and uses the native '+' operation. +The [`CarrySelectCompoundAdder`](https://intel.github.io/rohd-hcl/rohd_hcl/CarrySelectCompoundAdder-class.html) uses a carry-select adder as a basis. Like a carry-select adder it consists of a multiple blocks of two parallel adders . The first block has two adders and two separate carry-propagate chains are used to select sum and sum+1 output bits. The sum selecting chain starts from the carry input 0 driven block and sum+1 selecting chain starts from the carry input 1 driven block. +The delay of the adder is defined by the combination of the sub-adders and the accumulated carry-select chain delay. -The `CarrySelectCompoundAdder` module in ROHD-HCL accept input `Logic`s a and b as the input pin and the name of the module `name`. Note that the width of the inputs must be the same or a `RohdHclException` will be thrown. -Compound adder generator provides two alogithms for splitting adder into ripple-carry blocks. `CarrySelectCompoundAdder.splitSelectAdderAlgorithm4Bit` algoritm splits adder into blocks of 4-bit ripple-carry adders with the first one width adjusted down. `CarrySelectCompoundAdder.splitSelectAdderAlgorithmSingleBlock` algorithm generates only one block of full bitwidth of the adder. Input List\ Function(int adderFullWidth) `widthGen` should be used to specify custom adder splitting algorithm that returns a list of sub-adders width. The default one is `CarrySelectCompoundAdder.splitSelectAdderAlgorithmSingleBlock`. +The [CarrySelectCompoundAdder](https://intel.github.io/rohd-hcl/rohd_hcl/CarrySelectCompoundAdder-class.html) module in ROHD-HCL accepts input `Logic`s a and b as the input pin and the name of the module `name`. Note that the width of the inputs must be the same or a [RohdHclException](https://intel.github.io/rohd-hcl/rohd_hcl/RohdHclException-class.html) will be thrown. +The compound adder generator provides two alogithms for splitting the adder into adder sub-blocks: + +- The [CarrySelectCompoundAdder.splitSelectAdderAlgorithm4Bit](https://intel.github.io/rohd-hcl/rohd_hcl/CarrySelectCompoundAdder/splitSelectAdderAlgorithm4Bit.html) algoritm splits the adder into blocks of 4-bit ripple-carry adders with the first one width adjusted down. +- The [CarrySelectCompoundAdder.splitSelectAdderAlgorithmSingleBlock](https://intel.github.io/rohd-hcl/rohd_hcl/CarrySelectCompoundAdder/splitSelectAdderAlgorithmSingleBlock.html) algorithm generates only one sub=block with the full bitwidth of the adder. + +Input `List Function(int adderFullWidth) widthGen` should be used to specify the custom adder splitting algorithm that returns a list of sub-adders width. The default one is [CarrySelectCompoundAdder.splitSelectAdderAlgorithmSingleBlock](). + +The `adderGen` input selects the type of sub-adder used, with the default being `ParallelPrefixAdder`. An example is shown below to add two inputs of signals that have 8-bits of width. diff --git a/doc/components/fixed_point.md b/doc/components/fixed_point.md index 090e861ae..fb21f491c 100644 --- a/doc/components/fixed_point.md +++ b/doc/components/fixed_point.md @@ -1,14 +1,14 @@ # Fixed-Point Arithmetic -Fixed-point binary representation of numbers is useful several applications including digital signal processing and embedded systems. As a first step towards enabling fixed-point components, we created a new value system `FixedPointValue` similar to `LogicValue`. +Fixed-point binary representation of numbers is useful several applications including digital signal processing and embedded systems. As a first step towards enabling fixed-point components, we created a new value system [FixedPointValue](https://intel.github.io/rohd-hcl/rohd_hcl/FixedPointValue-class.html) similar to [LogicValue](https://intel.github.io/rohd/rohd/LogicValue-class.html). ## FixedPointValue -A `FixedPointValue` 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`s can be constructed from individual fields or from a Dart `double`, converted to Dart `double`, 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 (+, -, *, /). ## FixedPoint -The `FixedPoint` type is an extension of `Logic` 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 [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. ## FixedToFloat @@ -20,4 +20,4 @@ This component converts a floating-point signal to a signed fixed-point signal. ## Float8ToFixed -This component converts an 8-bit floating-point (FP8) representation (E5M2 or E4M3) to a signed fixed-point representation. This component offers using the same hardware for both FP8 formats. Therefore, both input and output are of type `Logic` and can be cast from/to floating point/fixed point by the producer/consumer based on the selected `mode`. Infinities and NaN's are not supported. The output width is 33 to accomodate E5M2 without loss. +This component converts an 8-bit floating-point (FP8) representation ([FloatingPoint8E4M3Value](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPoint8E4M3Value-class.html) or [FloatingPoint8E5M2Value](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPoint8E5M2Value-class.html)) to a signed fixed-point representation. This component offers using the same hardware for both FP8 formats. Therefore, both input and output are of type [Logic](https://intel.github.io/rohd/rohd/Logic-class.html) and can be cast from/to floating point/fixed point by the producer/consumer based on the selected `mode`. Infinities and NaN's are not supported. The output width is 33bits to accomodate [FloatingPoint8E5M2Value](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPoint8E5M2Value-class.html) without loss. diff --git a/doc/components/floating_point.md b/doc/components/floating_point.md index 313dd0b2e..fe5b6f322 100644 --- a/doc/components/floating_point.md +++ b/doc/components/floating_point.md @@ -1,39 +1,47 @@ # Floating-Point Components -Floating-point operations require meticulous precision, and have standards like [IEEE-754]() which govern them. To support floating-point components, we have created a parallel to `Logic`/`LogicValue` which are part of [ROHD](). Here, `FloatingPoint` is the `Logic` wire in a component that carries `FloatingPointValue` literal values. An important distinction is that these classes are parameterized to create arbitrary size floating-point values. +Floating-point operations require meticulous precision, and have standards like [IEEE-754]() which govern them. To support floating-point components, we have created a parallel to [Logic](https://intel.github.io/rohd/rohd/Logic-class.html)/[LogicValue](https://intel.github.io/rohd/rohd/LogicValue-class.html) which are part of [ROHD](). Here, [FloatingPoint](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPoint-class.html) is the [Logic](https://pub.dev/documentation/rohd/latest/rohd/Logic-class.html) wire in a component that carries [FloatingPointValue](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPointValue-class.html) literal values, a subclass of [LogicValue](https://intel.github.io/rohd/rohd/LogicValue-class.html). An important distinction is that these classes are parameterized to create arbitrary size floating-point values. ## FloatingPointValue -The `FloatingPointValue` class comprises the sign, exponent, and mantissa `LogicValue`s that represent a floating-point number. `FloatingPointValue`s can be converted to and from Dart native `Double`s, as well as constructed from integer and string representations of their fields. They can be operated on (+, -, *, /) and compared. +The [FloatingPointValue](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPointValue-class.html) class comprises the sign, exponent, and mantissa [LogicValue](https://intel.github.io/rohd/rohd/LogicValue-class.html)s that represent a floating-point number. [FloatingPointValue](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPointValue-class.html)s can be converted to and from Dart native [Double](https://api.dart.dev/stable/3.6.0/dart-core/double-class.html)s, as well as constructed from integer and string representations of their fields. They can be operated on (+, -, *, /) and compared. This is useful for helping validate [FloatingPoint](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPoint-class.html) logic components. -A `FloatingPointValue` has a mantissa in $[0,2)$ with +A [FloatingPointValue](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPointValue-class.html) has a mantissa in $[0,2)$ with $$0 <= exponent <= maxExponent$$ -A normal `isNormal` `FloatingPointValue` has: +A normal `isNormal` [FloatingPointValue](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPointValue-class.html) has: $$minExponent <= exponent <= maxExponent$$ And a mantissa in the range of $[1,2)$. Subnormal numbers are represented with a zero exponent and leading zeros in the mantissa capture the negative exponent value. -The various IEEE constants representing corner cases of the field of floating-point values for a given size of `FloatingPointValue`: infinities, zeros, limits for normal (e.g. mantissa in the range of $[1,2)$ and sub-normal numbers (zero exponent, and mantissa <1). +The various IEEE constants representing corner cases of the field of floating-point values for a given size of [FloatingPointValue](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPointValue-class.html): infinities, zeros, limits for normal (e.g. mantissa in the range of $[1,2)$ and sub-normal numbers (zero exponent, and mantissa <1). -Appropriate string representations, comparison operations, and operators are available. The usefulness of `FloatingPointValue` is in the testing of `FloatingPoint` components, where we can leverage the abstraction of a floating-point value type to drive and compare floating-point values operated upon by floating-point components. +Appropriate string representations, comparison operations, and operators are available. The usefulness of [FloatingPointValue](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPointValue-class.html) is in the testing of [FloatingPoint](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPoint-class.html) components, where we can leverage the abstraction of a floating-point value type to drive and compare floating-point values operated upon by floating-point components. -As 32-bit single precision and 64-bit double-precision floating-point types are most common, we have `FloatingPoint32Value` and `FloatingPoint64Value` subclasses with direct converters from Dart native Double. +As 64-bit double-precision and 32-bit single-precision floating-point types are most common, we have [FloatingPoint32Value](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPoint32Value-class.html) and [FloatingPoint64Value](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPoint64Value-class.html) subclasses with direct converters from Dart native [Double](https://api.dart.dev/stable/3.6.0/dart-core/double-class.html). -Finally, we have a `FloatingPointValue` random generator for testing purposes, generating valid floating-point types, optionally constrained to normal range (mantissa in $[1, 2)$). +Other special widths of floating-point values supported are: + +- [FloatingPoint16Value](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPoint16Value-class.html) +- [FloatingPoint8E4M3Value](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPoint8E4M3Value-class.html) +- [FloatingPoint8E5M2Value](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPoint8E5M2Value-class.html) +- [FloatingPointBF16Value](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPointBF16Value-class.html) +- [FloatingPointTF32Value](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPointTF32Value-class.html) + +Finally, we have a [random value constructor](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPointValue/FloatingPointValue.random.html) generator for testing purposes, generating valid [FloatingPointValue](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPointValue-class.html) types, optionally constrained to normal range (mantissa in $[1, 2)$). ## FloatingPoint -The `FloatingPoint` type is a `LogicStructure` which comprises the `Logic` bits for the sign, exponent, and mantissa used in hardware floating-point. These types are provided to simplify and abstract the declaration and manipulation of floating-point types in hardware. This type is parameterized like `FloatingPointValue`, for exponent and mantissa width. +The [FloatingPoint](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPoint-class.html) type is a [LogicStructure](https://pub.dev/documentation/rohd/latest/rohd/LogicStructure-class.html) which comprises the [Logic](https://pub.dev/documentation/rohd/latest/rohd/Logic-class.html) bits for the sign, exponent, and mantissa used in hardware floating-point. This type is provided to simplify and abstract the declaration and manipulation of floating-point bits in hardware. This type is parameterized like [FloatingPointValue](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPointValue-class.html), for exponent and mantissa width. -Again, like `FloatingPointValue`, `FloatingPoint64` and `FloatingPoint32` subclasses are provided as these are the most common floating-point number types. +Again, like [FloatingPointValue](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPointValue-class.html), [FloatingPoint64](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPoint64-class.html) and [FloatingPoint32](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPoint32-class.html) subclasses are provided as these are the most common floating-point number types. ## FloatingPointAdder -A very basic `FloatingPointAdderSimple` component is available which does not perform any rounding. It takes two `FloatingPoint` `LogicStructure`s and adds them, returning a normalized `FloatingPoint` on the output. An option on input is the type of `ParallelPrefixTree` used in the internal addition of the mantissas. +A very basic [FloatingPointAdderSimple](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPointAdderSimple-class.html) component is available which does not perform any rounding. It takes two [FloatingPoint](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPoint-class.html) [LogicStructure](https://pub.dev/documentation/rohd/latest/rohd/LogicStructure-class.html)s and adds them, returning a normalized [FloatingPoint](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPoint-class.html) on the output. An option on input is the type of ['ParallelPrefix'](https://intel.github.io/rohd-hcl/rohd_hcl/ParallelPrefix-class.html) used in the critical internal addition of the mantissas. -Currently, the `FloatingPointAdderSimple` is close in accuracy (as it has no rounding) and is not optimized for circuit performance, but only provides the key functionalities of alignment, addition, and normalization. Still, this component is a starting point for more realistic floating-point components that leverage the logical `FloatingPoint` and literal `FloatingPointValue` type abstractions. +Currently, the [FloatingPointAdderSimple](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPointAdderSimple-class.html) is close in accuracy (as it has no rounding) and is not optimized for circuit performance, but only provides the key functionalities of alignment, addition, and normalization. Still, this component is a starting point for more realistic floating-point components that leverage the logical [FloatingPoint](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPoint-class.html) and literal [FloatingPointValue](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPointValue-class.html) type abstractions. -A second `FloatingPointAdderRound` component is available which does perform rounding. It is based on "Delay-Optimized Implementation of IEEE Floating-Point Addition", by Peter-Michael Seidel and Guy Even, using an R-path and an N-path to process far-apart exponents and use rounding and an N-path for exponents within 2 and subtraction, which is exact. If you pass in an optional clock, a pipestage will be added to help optimize frequency; an optional reset and enable are can control the pipestage. +A second [FloatingPointAdderRound](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPointAdderRound-class.html) component is available which does perform rounding. It is based on "Delay-Optimized Implementation of IEEE Floating-Point Addition", by Peter-Michael Seidel and Guy Even, using an R-path and an N-path to process far-apart exponents and use rounding and an N-path for exponents within 2 and subtraction, which is exact. If you pass in an optional clock, a pipestage will be added to help optimize frequency; an optional reset and enable are can control the pipestage. diff --git a/lib/src/arithmetic/adder.dart b/lib/src/arithmetic/adder.dart index d1967be18..01d94c08a 100644 --- a/lib/src/arithmetic/adder.dart +++ b/lib/src/arithmetic/adder.dart @@ -5,13 +5,14 @@ // Implementation of Adder Module. // // 2023 June 1 -// Author: Yao Jing Quek +// Author: Yao Jing Quek , +// Desmond Kirkpatrick import 'package:meta/meta.dart'; import 'package:rohd/rohd.dart'; import 'package:rohd_hcl/rohd_hcl.dart'; -/// An abstract class for all adder module. +/// An abstract class for adders.. abstract class Adder extends Module { /// The input to the adder pin [a]. @protected @@ -24,45 +25,45 @@ abstract class Adder extends Module { /// The addition results in 2s complement form as [sum] Logic get sum => output('sum'); + /// The input to the carry in pin [carryIn] + @protected + Logic? get carryIn => tryInput('carryIn'); + + /// Check if this adder has a carryIn input + bool get hasCarryIn => carryIn != null; + /// Takes in input [a] and input [b] and return the [sum] of the addition /// result. The width of input [a] and [b] must be the same. - Adder(Logic a, Logic b, {super.name}) { + Adder(Logic a, Logic b, {Logic? carryIn, super.name}) : super() { if (a.width != b.width) { throw RohdHclException('inputs of a and b should have same width.'); } addInput('a', a, width: a.width); addInput('b', b, width: b.width); addOutput('sum', width: a.width + 1); + if (carryIn != null) { + addInput('carryIn', carryIn); + } } } -/// A simple full-adder with inputs `a` and `b` to be added with a `carryIn`. -class FullAdder extends Module { - /// The addition's result [sum]. - Logic get sum => output('sum'); - - /// The carry bit's result [carryOut]. - Logic get carryOut => output('carry_out'); - +/// A simple full-adder with single-bit inputs `a` and `b` to be added +/// with a `carryIn`. +class FullAdder extends Adder { /// Constructs a [FullAdder] with value [a], [b] and [carryIn] based on /// full adder truth table. - FullAdder({ - required Logic a, - required Logic b, - required Logic carryIn, + FullAdder( + super.a, + super.b, { + required super.carryIn, super.name = 'full_adder', }) { - a = addInput('a', a, width: a.width); - b = addInput('b', b, width: b.width); - carryIn = addInput('carry_in', carryIn, width: carryIn.width); - - final carryOut = addOutput('carry_out'); - final sum = addOutput('sum'); - - final and1 = carryIn & (a ^ b); - final and2 = b & a; - - sum <= (a ^ b) ^ carryIn; - carryOut <= and1 | and2; + if ((a.width != 1) | (b.width != 1) | ((carryIn ?? Const(0)).width != 1)) { + throw RohdHclException('widths must all be one'); + } + if (carryIn == null) { + throw RohdHclException('FullAdder must have a carryIn input'); + } + sum <= [carryIn! & (a ^ b) | a & b, (a ^ b) ^ carryIn!].swizzle(); } } diff --git a/lib/src/arithmetic/carry_save_mutiplier.dart b/lib/src/arithmetic/carry_save_mutiplier.dart index 3ec4f410b..739368296 100644 --- a/lib/src/arithmetic/carry_save_mutiplier.dart +++ b/lib/src/arithmetic/carry_save_mutiplier.dart @@ -69,15 +69,15 @@ class CarrySaveMultiplier extends Multiplier { for (var column = maxIndexA; column >= row; column--) { final fullAdder = FullAdder( - a: column == maxIndexA || row == 0 + column == maxIndexA || row == 0 ? Const(0) : p.get(_sum[column]), - b: p.get(a)[column - row] & p.get(b)[row], + p.get(a)[column - row] & p.get(b)[row], carryIn: row == 0 ? Const(0) : p.get(_carry[column - 1])); columnAdder - ..add(p.get(_carry[column]) < fullAdder.carryOut) - ..add(p.get(_sum[column]) < fullAdder.sum); + ..add(p.get(_carry[column]) < fullAdder.sum[1]) + ..add(p.get(_sum[column]) < fullAdder.sum[0]); } return columnAdder; diff --git a/lib/src/arithmetic/compound_adder.dart b/lib/src/arithmetic/compound_adder.dart index 027ef6af5..0776cf73e 100644 --- a/lib/src/arithmetic/compound_adder.dart +++ b/lib/src/arithmetic/compound_adder.dart @@ -66,7 +66,9 @@ class CarrySelectCompoundAdder extends CompoundAdder { /// Constructs a [CarrySelectCompoundAdder]. CarrySelectCompoundAdder(super.a, super.b, - {super.name = 'cs_compound_adder', + {Adder Function(Logic a, Logic b, {Logic? carryIn, String name}) + adderGen = ParallelPrefixAdder.new, + super.name = 'cs_compound_adder', List Function(int) widthGen = splitSelectAdderAlgorithmSingleBlock}) { // output bits lists @@ -84,20 +86,20 @@ class CarrySelectCompoundAdder extends CompoundAdder { // input width of current ripple-carry adder block final blockWidth = adderSplit[i]; if (blockWidth <= 0) { - throw RohdHclException('non-positive ripple-carry adder block size.'); + throw RohdHclException('non-positive adder block size.'); } if (blockWidth + blockStartIdx > a.width) { - throw RohdHclException('oversized ripple-carry adders sequence.'); + throw RohdHclException('oversized adders sequence.'); } final blockA = Logic(name: 'block_${i}_a', width: blockWidth); final blockB = Logic(name: 'block_${i}_b', width: blockWidth); blockA <= a.getRange(blockStartIdx, blockStartIdx + blockWidth); blockB <= b.getRange(blockStartIdx, blockStartIdx + blockWidth); // Build ripple-carry adders for 0 and 1 carryin values - final fullAdder0 = RippleCarryAdder(blockA, blockB, - carryIn: Const(0), name: 'block0_$i'); - final fullAdder1 = RippleCarryAdder(blockA, blockB, - carryIn: Const(1), name: 'block1_$i'); + final fullAdder0 = + adderGen(blockA, blockB, carryIn: Const(0), name: 'block0_$i'); + final fullAdder1 = + adderGen(blockA, blockB, carryIn: Const(1), name: 'block1_$i'); for (var bitIdx = 0; bitIdx < blockWidth; ++bitIdx) { if (i == 0) { // connect directly to respective sum output bit diff --git a/lib/src/arithmetic/floating_point/floating_point_adder_round.dart b/lib/src/arithmetic/floating_point/floating_point_adder_round.dart index ec9878146..2d4c090a6 100644 --- a/lib/src/arithmetic/floating_point/floating_point_adder_round.dart +++ b/lib/src/arithmetic/floating_point/floating_point_adder_round.dart @@ -92,7 +92,8 @@ class FloatingPointAdderRound extends Module { this.clk, this.reset, this.enable, - Adder Function(Logic, Logic) adderGen = ParallelPrefixAdder.new, + Adder Function(Logic, Logic, {Logic? carryIn}) adderGen = + ParallelPrefixAdder.new, ParallelPrefix Function(List, Logic Function(Logic, Logic)) ppTree = KoggeStone.new, super.name = 'floating_point_adder_round'}) diff --git a/lib/src/arithmetic/floating_point/floating_point_adder_simple.dart b/lib/src/arithmetic/floating_point/floating_point_adder_simple.dart index eaab7bb73..4051e219c 100644 --- a/lib/src/arithmetic/floating_point/floating_point_adder_simple.dart +++ b/lib/src/arithmetic/floating_point/floating_point_adder_simple.dart @@ -71,7 +71,8 @@ class FloatingPointAdderSimple extends Module { [a.isNormal(), a.mantissa].swizzle(), b.sign, [b.isNormal(), b.mantissa].swizzle() >>> expDiff, - (a, b) => ParallelPrefixAdder(a, b, ppGen: ppGen)); + (a, b, {carryIn}) => + ParallelPrefixAdder(a, b, carryIn: carryIn, ppGen: ppGen)); final sum = adder.sum.slice(adder.sum.width - 2, 0); final leadOneE = diff --git a/lib/src/arithmetic/ones_complement_adder.dart b/lib/src/arithmetic/ones_complement_adder.dart index 813aa6e03..deec89ff6 100644 --- a/lib/src/arithmetic/ones_complement_adder.dart +++ b/lib/src/arithmetic/ones_complement_adder.dart @@ -31,7 +31,8 @@ class OnesComplementAdder extends Adder { /// is provided as not null, then the end-around carry is not performed and is /// left to the caller via the output [carryOut]. OnesComplementAdder(super.a, super.b, - {Adder Function(Logic, Logic) adderGen = ParallelPrefixAdder.new, + {Adder Function(Logic, Logic, {Logic? carryIn}) adderGen = + ParallelPrefixAdder.new, Logic? subtractIn, Logic? carryOut, bool subtract = false, diff --git a/lib/src/arithmetic/parallel_prefix_operations.dart b/lib/src/arithmetic/parallel_prefix_operations.dart index 0be9c7509..bbbcdf0ee 100644 --- a/lib/src/arithmetic/parallel_prefix_operations.dart +++ b/lib/src/arithmetic/parallel_prefix_operations.dart @@ -210,19 +210,28 @@ class ParallelPrefixPriorityEncoder extends Module { class ParallelPrefixAdder extends Adder { /// Adder constructor ParallelPrefixAdder(super.a, super.b, - {ParallelPrefix Function(List, Logic Function(Logic, Logic)) - ppGen = KoggeStone.new, + {super.carryIn, + ParallelPrefix Function(List, Logic Function(Logic, Logic)) ppGen = + KoggeStone.new, super.name = 'parallel_prefix_adder'}) { + final l = List.generate(a.width - 1, + (i) => [a[i + 1] & b[i + 1], a[i + 1] | b[i + 1]].swizzle()); + final cin = carryIn ?? Const(0); + // ignore: cascade_invocations + l.insert( + 0, + [(a[0] & b[0]) | (a[0] & cin) | (b[0] & cin), a[0] | b[0] | cin] + .swizzle()); final u = ppGen( - List.generate( - a.width, (i) => [a[i] & b[i], a[i] | b[i]].swizzle()), - (lhs, rhs) => [rhs[1] | rhs[0] & lhs[1], rhs[0] & lhs[0]].swizzle()); + l, (lhs, rhs) => [rhs[1] | rhs[0] & lhs[1], rhs[0] & lhs[0]].swizzle()); sum <= [ u.val[a.width - 1][1], - List.generate(a.width, - (i) => (i == 0) ? a[i] ^ b[i] : a[i] ^ b[i] ^ u.val[i - 1][1]) - .rswizzle() + List.generate( + a.width, + (i) => (i == 0) + ? a[i] ^ b[i] ^ cin + : a[i] ^ b[i] ^ u.val[i - 1][1]).rswizzle() ].swizzle(); } } diff --git a/lib/src/arithmetic/ripple_carry_adder.dart b/lib/src/arithmetic/ripple_carry_adder.dart index bb95b5177..b4178a1a0 100644 --- a/lib/src/arithmetic/ripple_carry_adder.dart +++ b/lib/src/arithmetic/ripple_carry_adder.dart @@ -19,22 +19,18 @@ import 'package:rohd_hcl/rohd_hcl.dart'; class RippleCarryAdder extends Adder { /// Constructs an n-bit adder based on inputs List of inputs. RippleCarryAdder(super.a, super.b, - {Logic? carryIn, super.name = 'ripple_carry_adder_carry_in'}) { - if (carryIn != null) { - carryIn = addInput('carry_in', carryIn, width: carryIn.width); - } + {super.carryIn, super.name = 'ripple_carry_adder_carry_in'}) { Logic? carry; final sumList = []; for (var i = 0; i < a.width; i++) { final fullAdder = - FullAdder(a: a[i], b: b[i], carryIn: carry ?? (carryIn ?? Const(0))); + FullAdder(a[i], b[i], carryIn: carry ?? (carryIn ?? Const(0))); - carry = fullAdder.carryOut; - sumList.add(fullAdder.sum); + carry = fullAdder.sum[1]; + sumList.add(fullAdder.sum[0]); } sumList.add(carry!); - sum <= sumList.rswizzle(); } } diff --git a/lib/src/arithmetic/sign_magnitude_adder.dart b/lib/src/arithmetic/sign_magnitude_adder.dart index 360f780e3..fc3945325 100644 --- a/lib/src/arithmetic/sign_magnitude_adder.dart +++ b/lib/src/arithmetic/sign_magnitude_adder.dart @@ -36,7 +36,7 @@ class SignMagnitudeAdder extends Adder { /// too 'true' to avoid a comparator. // TODO(desmonddak): this adder may need a carry-in for rounding SignMagnitudeAdder(this.aSign, super.a, this.bSign, super.b, - Adder Function(Logic, Logic) adderGen, + Adder Function(Logic, Logic, {Logic? carryIn}) adderGen, {this.largestMagnitudeFirst = false, super.name = 'sign_magnitude_adder'}) { aSign = addInput('aSign', aSign); diff --git a/lib/src/component_config/components/config_floating_point_adder_round.dart b/lib/src/component_config/components/config_floating_point_adder_round.dart index ea629f70d..2ca5a5283 100644 --- a/lib/src/component_config/components/config_floating_point_adder_round.dart +++ b/lib/src/component_config/components/config_floating_point_adder_round.dart @@ -15,11 +15,14 @@ import 'package:rohd_hcl/rohd_hcl.dart'; /// A [Configurator] for [FloatingPointAdderRound]s. class FloatingPointAdderRoundConfigurator extends Configurator { /// Map from Type to Function for Adder generator - static Map adderGeneratorMap = { - Ripple: (a, b) => ParallelPrefixAdder(a, b, ppGen: Ripple.new), - Sklansky: (a, b) => ParallelPrefixAdder(a, b, ppGen: Sklansky.new), + static Map + adderGeneratorMap = { + Ripple: (a, b, {carryIn}) => ParallelPrefixAdder(a, b, ppGen: Ripple.new), + Sklansky: (a, b, {carryIn}) => + ParallelPrefixAdder(a, b, ppGen: Sklansky.new), KoggeStone: ParallelPrefixAdder.new, - BrentKung: (a, b) => ParallelPrefixAdder(a, b, ppGen: BrentKung.new) + BrentKung: (a, b, {carryIn}) => + ParallelPrefixAdder(a, b, ppGen: BrentKung.new) }; /// Map from Type to Function for Parallel Prefix generator diff --git a/lib/src/component_config/components/config_parallel_prefix_adder.dart b/lib/src/component_config/components/config_parallel_prefix_adder.dart index 0cda4da18..5a8998e22 100644 --- a/lib/src/component_config/components/config_parallel_prefix_adder.dart +++ b/lib/src/component_config/components/config_parallel_prefix_adder.dart @@ -35,6 +35,7 @@ class ParallelPrefixAdderConfigurator extends Configurator { Module createModule() => ParallelPrefixAdder( Logic(name: 'a', width: dataWidthKnob.value), Logic(name: 'b', width: dataWidthKnob.value), + carryIn: Logic(name: 'carryIn'), ppGen: generatorMap[prefixTreeKnob.value]!); @override diff --git a/pubspec.yaml b/pubspec.yaml index c7241e144..ca515507b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,9 +12,19 @@ environment: dependencies: collection: ^1.18.0 meta: ^1.9.1 - rohd: ^0.5.2 + rohd: ^0.5.3 rohd_vf: ^0.5.0 dev_dependencies: logging: ^1.0.1 test: ^1.25.0 + +dependency_overrides: + rohd: + git: + url: https://github.com/intel/rohd.git + ref: main + rohd_vf: + git: + url: https://github.com/intel/rohd-vf.git + ref: main \ No newline at end of file diff --git a/test/arithmetic/adder_test.dart b/test/arithmetic/adder_test.dart index 1e0af79e0..3aad74554 100644 --- a/test/arithmetic/adder_test.dart +++ b/test/arithmetic/adder_test.dart @@ -7,73 +7,82 @@ // 2024 April 4 // Author: Desmond Kirkpatrick +// ignore_for_file: invalid_use_of_protected_member + import 'dart:math'; import 'package:rohd/rohd.dart'; import 'package:rohd_hcl/rohd_hcl.dart'; import 'package:test/test.dart'; -void checkAdder(Adder adder, LogicValue av, LogicValue bv) { +void checkAdder(Adder adder, LogicValue av, LogicValue bv, LogicValue cv) { final aB = av.toBigInt(); final bB = bv.toBigInt(); - // ignore: invalid_use_of_protected_member + final cB = cv.toBigInt(); adder.a.put(av); - // ignore: invalid_use_of_protected_member adder.b.put(bv); - - expect( - adder.sum.value.toBigInt(), - // ignore: invalid_use_of_protected_member - // equals((aB + bB) & ((BigInt.one << adder.a.width) - BigInt.one))); - equals(aB + bB)); - expect(adder.sum.value.toBigInt(), equals(aB + bB)); + final BigInt golden; + if (adder.hasCarryIn) { + adder.carryIn!.put(cv); + golden = aB + bB + cB; + } else { + golden = aB + bB; + } + expect(adder.sum.value.toBigInt(), equals(golden)); } -void testExhaustive(int n, Adder Function(Logic a, Logic b) fn) { - final a = Logic(name: 'a', width: n); - final b = Logic(name: 'b', width: n); +void testAdderRandomIter(int n, int nSamples, Adder adder) { + test('random ci: ${adder.name}_W${n}_I$nSamples', () async { + for (var i = 0; i < nSamples; i++) { + final aa = Random().nextLogicValue(width: n); + final bb = Random().nextLogicValue(width: n); + final cc = Random().nextLogicValue(width: 1); + checkAdder(adder, aa, bb, cc); + } + }); +} - final mod = fn(a, b); +void testAdderExhaustiveIter(int n, Adder mod) { test( - 'exhaustive: ${mod.name}_W$n' - '_G${fn.call(a, b).name}', () async { - await mod.build(); - - for (var aa = 0; aa < (1 << n); ++aa) { - for (var bb = 0; bb < (1 << n); ++bb) { - final av = LogicValue.of(BigInt.from(aa), width: n); - final bv = LogicValue.of(BigInt.from(bb), width: n); - checkAdder(mod, av, bv); + 'exhaustive cin: ${mod.name}_W$n' + '_G${mod.name}', () async { + for (var aa = 0; aa < (1 << n); aa++) { + for (var bb = 0; bb < (1 << n); bb++) { + for (var cc = 0; cc < 2; cc++) { + final av = LogicValue.of(BigInt.from(aa), width: n); + final bv = LogicValue.of(BigInt.from(bb), width: n); + final cv = Random().nextLogicValue(width: 1); + + checkAdder(mod, av, bv, cv); + } } } }); } -void testAdderRandom(int n, int nSamples, Adder Function(Logic a, Logic b) fn) { - final a = Logic(name: 'a', width: n); - final b = Logic(name: 'b', width: n); - - final adder = fn(a, b); - test('random: ${adder.name}_W${a.width}_I$nSamples', () async { - await adder.build(); +void testAdderRandom( + int n, int nSamples, Adder Function(Logic a, Logic b, {Logic? carryIn}) fn, + {bool testCarryIn = true}) { + testAdderRandomIter( + n, + nSamples, + fn(Logic(name: 'a', width: n), Logic(name: 'b', width: n), + carryIn: testCarryIn ? Logic(name: 'c') : null)); +} - for (var i = 0; i < nSamples; ++i) { - final aa = Random().nextLogicValue(width: n); - final bb = Random().nextLogicValue(width: n); - checkAdder(adder, aa, bb); - } - }); +void testAdderExhaustive( + int n, Adder Function(Logic a, Logic b, {Logic? carryIn}) fn, + {bool testCarryIn = true}) { + testAdderExhaustiveIter( + n, + fn(Logic(name: 'a', width: n), Logic(name: 'b', width: n), + carryIn: testCarryIn ? Logic(name: 'c') : null)); } void checkSignMagnitudeAdder(SignMagnitudeAdder adder, LogicValue aSign, LogicValue aMagnitude, LogicValue bSign, LogicValue bMagnitude) { - // ignore: invalid_use_of_protected_member adder.aSign.put(aSign); - // ignore: invalid_use_of_protected_member adder.bSign.put(bSign); - - // ignore: invalid_use_of_protected_member adder.a.put(aMagnitude); - // ignore: invalid_use_of_protected_member adder.b.put(bMagnitude); final computedVal = (adder.sign.value == LogicValue.one) @@ -93,7 +102,8 @@ void checkSignMagnitudeAdder(SignMagnitudeAdder adder, LogicValue aSign, expect(computedVal, equals(expectVal)); } -void testExhaustiveSignMagnitude(int n, Adder Function(Logic a, Logic b) fn, +void testExhaustiveSignMagnitude( + int n, Adder Function(Logic a, Logic b, {Logic? carryIn}) fn, {bool operandsArePresorted = true}) { final aSign = Logic(name: 'aSign'); final a = Logic(name: 'a', width: n); @@ -105,8 +115,8 @@ void testExhaustiveSignMagnitude(int n, Adder Function(Logic a, Logic b) fn, test( 'exhaustive Sign Magnitude: ' '${adder.name}_W${a.width}_N$operandsArePresorted', () { - for (var i = 0; i < pow(2, n); i += 1) { - for (var j = 0; j < pow(2, n); j += 1) { + for (var i = 0; i < pow(2, n); i++) { + for (var j = 0; j < pow(2, n); j++) { final bI = BigInt.from(i).toSigned(n); final bJ = BigInt.from(j).toSigned(n); @@ -134,8 +144,8 @@ void testExhaustiveSignMagnitude(int n, Adder Function(Logic a, Logic b) fn, }); } -void testRandomSignMagnitude( - int width, int nSamples, Adder Function(Logic a, Logic b) fn, +void testRandomSignMagnitude(int width, int nSamples, + Adder Function(Logic a, Logic b, {Logic? carryIn}) fn, {bool sortOperands = true}) { final aSign = Logic(name: 'aSign'); final a = Logic(name: 'a', width: width); @@ -148,7 +158,7 @@ void testRandomSignMagnitude( () async { await adder.build(); - for (var i = 0; i < nSamples; ++i) { + for (var i = 0; i < nSamples; i++) { final aa = Random().nextLogicValue(width: width); final av = aa.toBigInt().toSigned(width); final bb = Random().nextLogicValue(width: width); @@ -184,29 +194,45 @@ void main() { final generators = [Ripple.new, Sklansky.new, KoggeStone.new, BrentKung.new]; - group('adderRandom', () { - for (final n in [64, 64, 65]) { - testAdderRandom(n, 30, RippleCarryAdder.new); - for (final ppGen in generators) { - testAdderRandom( - n, 30, (a, b) => ParallelPrefixAdder(a, b, ppGen: ppGen)); + group('adder random', () { + for (final n in [63, 64, 65]) { + for (final testCin in [false, true]) { + testAdderRandom(n, 30, RippleCarryAdder.new, testCarryIn: testCin); + for (final ppGen in generators) { + testAdderRandom( + n, + 30, + (a, b, {carryIn}) => + ParallelPrefixAdder(a, b, ppGen: ppGen, carryIn: carryIn), + testCarryIn: testCin); + } } + testAdderRandom( + n, 30, (a, b, {carryIn}) => CarrySelectCompoundAdder(a, b)); } }); - group('exhaustive', () { - testExhaustive(4, RippleCarryAdder.new); - for (final ppGen in generators) { - testExhaustive(4, (a, b) => ParallelPrefixAdder(a, b, ppGen: ppGen)); + group('adder exhaustive', () { + for (final testCin in [false, true]) { + testAdderExhaustive(4, RippleCarryAdder.new, testCarryIn: testCin); + for (final ppGen in generators) { + testAdderExhaustive( + 4, + (a, b, {carryIn}) => + ParallelPrefixAdder(a, b, ppGen: ppGen, carryIn: carryIn), + testCarryIn: testCin); + } } + testAdderExhaustive(4, (a, b, {carryIn}) => CarrySelectCompoundAdder(a, b)); }); + group('SignMagnitude random', () { for (final ppGen in generators) { testRandomSignMagnitude(4, 30, RippleCarryAdder.new); testRandomSignMagnitude(4, 30, RippleCarryAdder.new, sortOperands: false); testRandomSignMagnitude( - 4, 30, (a, b) => ParallelPrefixAdder(a, b, ppGen: ppGen)); + 4, 30, (a, b, {carryIn}) => ParallelPrefixAdder(a, b, ppGen: ppGen)); testRandomSignMagnitude( - 4, 30, (a, b) => ParallelPrefixAdder(a, b, ppGen: ppGen), + 4, 30, (a, b, {carryIn}) => ParallelPrefixAdder(a, b, ppGen: ppGen), sortOperands: false); } }); @@ -216,12 +242,13 @@ void main() { testExhaustiveSignMagnitude(4, RippleCarryAdder.new, operandsArePresorted: false); testExhaustiveSignMagnitude( - 4, (a, b) => ParallelPrefixAdder(a, b, ppGen: ppGen)); + 4, (a, b, {carryIn}) => ParallelPrefixAdder(a, b, ppGen: ppGen)); testExhaustiveSignMagnitude( - 4, (a, b) => ParallelPrefixAdder(a, b, ppGen: ppGen), + 4, (a, b, {carryIn}) => ParallelPrefixAdder(a, b, ppGen: ppGen), operandsArePresorted: false); } }); + test('trivial parallel prefix adder test', () async { const width = 6; final a = Logic(name: 'a', width: width); diff --git a/test/arithmetic/carry_save_multiplier_test.dart b/test/arithmetic/carry_save_multiplier_test.dart index 35778a806..716a2f19d 100644 --- a/test/arithmetic/carry_save_multiplier_test.dart +++ b/test/arithmetic/carry_save_multiplier_test.dart @@ -19,7 +19,7 @@ void main() { await Simulator.reset(); }); - test('should throw exception if inputs Logics have diferent width.', () { + test('should throw exception if inputs Logics have different width.', () { final a = Logic(name: 'a', width: 8); final b = Logic(name: 'b', width: 16); final clk = SimpleClockGenerator(10).clk; diff --git a/test/arithmetic/compound_adder_test.dart b/test/arithmetic/compound_adder_test.dart index 461d69b6a..bcf71aebb 100644 --- a/test/arithmetic/compound_adder_test.dart +++ b/test/arithmetic/compound_adder_test.dart @@ -74,6 +74,7 @@ void main() { final b = Logic(name: 'b', width: 10); final adder = CarrySelectCompoundAdder(a, b, + adderGen: RippleCarryAdder.new, widthGen: CarrySelectCompoundAdder.splitSelectAdderAlgorithm4Bit); await adder.build(); From 3da4a4a90ef08b23322c19537154217964cf9a94 Mon Sep 17 00:00:00 2001 From: Galileo Newton Date: Mon, 23 Dec 2024 20:51:16 -0800 Subject: [PATCH 2/3] remove dependency overrides --- .../components/config_ripple_carry_adder.dart | 5 ++--- pubspec.yaml | 10 ---------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/lib/src/component_config/components/config_ripple_carry_adder.dart b/lib/src/component_config/components/config_ripple_carry_adder.dart index 8256ad3f1..d0f308b3f 100644 --- a/lib/src/component_config/components/config_ripple_carry_adder.dart +++ b/lib/src/component_config/components/config_ripple_carry_adder.dart @@ -26,7 +26,6 @@ class RippleCarryAdderConfigurator extends Configurator { @override Module createModule() => RippleCarryAdder( - Logic(width: logicWidthKnob.value), - Logic(width: logicWidthKnob.value), - ); + Logic(width: logicWidthKnob.value), Logic(width: logicWidthKnob.value), + carryIn: Logic()); } diff --git a/pubspec.yaml b/pubspec.yaml index ca515507b..2eaed7d66 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,13 +18,3 @@ dependencies: dev_dependencies: logging: ^1.0.1 test: ^1.25.0 - -dependency_overrides: - rohd: - git: - url: https://github.com/intel/rohd.git - ref: main - rohd_vf: - git: - url: https://github.com/intel/rohd-vf.git - ref: main \ No newline at end of file From cf85b3d98b81bb35e8e3103700e27e98710752db Mon Sep 17 00:00:00 2001 From: Galileo Newton Date: Thu, 26 Dec 2024 14:50:46 -0800 Subject: [PATCH 3/3] doc cleanup --- doc/README.md | 6 +++--- doc/components/adder.md | 4 ++-- doc/components/multiplier.md | 10 +++++----- doc/components/multiplier_components.md | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/doc/README.md b/doc/README.md index a653b4180..d1bd835e2 100644 --- a/doc/README.md +++ b/doc/README.md @@ -41,9 +41,9 @@ Some in-development items will have opened issues, as well. Feel free to create - [Ripple Carry Adder](./components/adder.md#ripple-carry-adder) - [Parallel Prefix Adder](./components/parallel_prefix_operations.md) - [Sign Magnitude Adder](./components/adder.md#sign-magnitude-adder) - - [compound Adder](./components/adder.md#compound-adder) + - [Compound Adder](./components/adder.md#compound-adder) - Subtractors - - [Ones Complement Adder Subtractor](./components/adder.md#ones-complement-adder-subtractor) + - [Ones' Complement Adder Subtractor](./components/adder.md#ones-complement-adder-subtractor) - Multipliers - [Pipelined Integer Multiplier](./components/multiplier.md#carry-save-multiplier) - [Compression Tree Multiplier](./components/multiplier.md#compression-tree-multiplier) @@ -59,7 +59,7 @@ Some in-development items will have opened issues, as well. Feel free to create - Double (64-bit) - Float (32-bit) - BFloat16 (16-bit) - - TensorFloat32 (32-bit) + - TensorFloat32 (19-bit) - 8-bit E4/M3 and E5/M2 - [Simple Floating-Point Adder](./components/floating_point.md#floatingpointadder) - [Rounding Floating-Point Adder](./components/floating_point.md#floatingpointadder) diff --git a/doc/components/adder.md b/doc/components/adder.md index 5d45df212..0c162052f 100644 --- a/doc/components/adder.md +++ b/doc/components/adder.md @@ -1,6 +1,6 @@ # Adders -ROHD-HCL provides a set of adder modules to get the sum from a pair of Logic. Adders which provide a carry input have a base class of [AdderCi](https://intel.github.io/rohd-hcl/rohd_hcl/Adder-class.html), those that don't use a base class of [Adder](https://intel.github.io/rohd-hcl/rohd_hcl/Adder-class.html). As of now, ROHD-HCL supplies: +ROHD-HCL provides a set of adder modules to get the sum from a pair of Logic. Some adders provide an optional carry input provided in the base class of [Adder](https://intel.github.io/rohd-hcl/rohd_hcl/Adder-class.html). As of now, ROHD-HCL supplies: - [Ripple Carry Adder](#ripple-carry-adder) - [Parallel Prefix Adder](#parallel-prefix-adder) @@ -48,7 +48,7 @@ Here is an example of instantiating a [ParallelPrefixAdder](https://intel.github print('${sum.value.toBigInt()}'); ``` -## Ones Complement Adder Subtractor +## Ones' Complement Adder Subtractor A ones-complement adder (and subtractor) is useful in efficient arithmetic operations as the end-around carry can be bypassed and used later. diff --git a/doc/components/multiplier.md b/doc/components/multiplier.md index e34736329..f2439c983 100644 --- a/doc/components/multiplier.md +++ b/doc/components/multiplier.md @@ -2,7 +2,7 @@ ROHD-HCL provides an abstract `Multiplier` module which multiplies two numbers represented as two `Logic`s, potentially of different widths, -treating them as either signed (2s complement) or unsigned. It +treating them as either signed (twos' complement) or unsigned. It produces the product as a `Logic` with width equal to the sum of the widths of the inputs. The signs of the operands are either fixed by a parameter, or runtime selectable, e.g.: `signedMultiplicand` or `selectSignedMultiplicand`. @@ -98,8 +98,8 @@ The parameters of the - The radix used for Booth encoding (2, 4, 8, and 16 are currently supported). - The type of `ParallelPrefix` tree used in the final `ParallelPrefixAdder` (optional). - `ppGen` parameter: the type of `PartialProductGenerator` to use which has derived classes for different styles of sign extension. In some cases this adds an extra row to hold a sign bit. -- `signedMultiplicand` parameter: whether the multiplicand (first arg) should be treated as signed (2s complement) or unsigned. -- `signedMultiplier` parameter: whether the multiplier (second arg) should be treated as signed (2s complement) or unsigned. +- `signedMultiplicand` parameter: whether the multiplicand (first arg) should be treated as signed (twos' complement) or unsigned. +- `signedMultiplier` parameter: whether the multiplier (second arg) should be treated as signed (twos' complement) or unsigned. - An optional `selectSignedMultiplicand` control signal which overrides the `signedMultiplicand` parameter allowing for runtime control of signed or unsigned operation with the same hardware. `signedMultiplicand` must be false if using this control signal. - An optional `selectSignedMultiplier` control signal which overrides the `signedMultiplier` parameter allowing for runtime control of signed or unsigned operation with the same hardware. `signedMultiplier` must be false if using this control signal. - An optional `clk`, as well as `enable` and `reset` that are used to add a pipestage in the `ColumnCompressor` to allow for pipelined operation. @@ -139,8 +139,8 @@ The parameters of the - The type of `ParallelPrefix` tree used in the final `ParallelPrefixAdder` (default Kogge-Stone). - `ppGen` parameter: the type of `PartialProductGenerator` to use which has derived classes for different styles of sign extension. In some cases this adds an extra row to hold a sign bit (default `PartialProductGeneratorCompactRectSignExtension`). - `signedMultiplicand` parameter: whether the multiplicand (first arg) should be treated as signed (2s complement) or unsigned -- `signedMultiplier` parameter: whether the multiplier (second arg) should be treated as signed (2s complement) or unsigned -- `signedAddend` parameter: whether the addend (third arg) should be treated as signed (2s complement) or unsigned +- `signedMultiplier` parameter: whether the multiplier (second arg) should be treated as signed (twos' complement) or unsigned +- `signedAddend` parameter: whether the addend (third arg) should be treated as signed (twos' complement) or unsigned - An optional `selectSignedMultiplicand` control signal which overrides the `signedMultiplicand` parameter allowing for runtime control of signed or unsigned operation with the same hardware. `signedMultiplicand` must be false if using this control signal. - An optional `selectSignedMultiplier` control signal which overrides the `signedMultiplier` parameter allowing for runtime control of signed or unsigned operation with the same hardware. `signedMultiplier` must be false if using this control signal. - An optional `selectSignedAddend` control signal which overrides the `signedAddend` parameter allowing for runtime control of signed or unsigned operation with the same hardware. `signedAddend` must be false if using this control signal. diff --git a/doc/components/multiplier_components.md b/doc/components/multiplier_components.md index d0a9515e0..00c49a81c 100644 --- a/doc/components/multiplier_components.md +++ b/doc/components/multiplier_components.md @@ -49,9 +49,9 @@ row slice mult 03 [0 1] = +1 0 0 1 1 ``` -A few things to note: first, that we are negating by 1s complement (so we need a -0) and second, these rows do not add up to (18: 10010). For Booth encoded rows to add up properly, they need to be in 2s complement form, and they need to be sign-extended. +A few things to note: first, that we are negating by ones' complement (so we need a -0) and second, these rows do not add up to (18: 10010). For Booth encoded rows to add up properly, they need to be in twos' complement form, and they need to be sign-extended. - Here is the matrix with a crude sign extension `brute` (the table formatting is available from our `PartialProductGenerator` component). With 2s complementation, and sign bits folded in (note the LSB of each row has a sign term from the previous row), these addends are correctly formed and add to (18: 10010). + Here is the matrix with a crude sign extension `brute` (the table formatting is available from our `PartialProductGenerator` component). With twos' complementation, and sign bits folded in (note the LSB of each row has a sign term from the previous row), these addends are correctly formed and add to (18: 10010). ```text 7 6 5 4 3 2 1 0