Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Agnostic multiplier #125

Merged
merged 11 commits into from
Nov 6, 2024
2 changes: 1 addition & 1 deletion doc/components/floating_point.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ $$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`: 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.

Expand Down
14 changes: 8 additions & 6 deletions doc/components/multiplier.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,11 @@ digital signal processing.
The parameters of the
`CompressionTreeMultiplier` are:

- Two input terms `a` and `b`
- Two input terms `a` and `b` which can be different widths
- 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)
- Whether the operands should be treated as signed (2s complement) or unsigned
- `signed` parameter: whether the operands should be treated as signed (2s complement) or unsigned
- An optional `selectSigned` control signal which overrides the `signed` configuration allowing for runtime control of signed or unsigned operation with the same hardware.

Here is an example of use of the `CompressionTreeMultiplier`:

Expand Down Expand Up @@ -116,11 +117,12 @@ tree to allow for accumulation into this third input.
The parameters of the
`CompressionTreeMultiplyAccumulate` are:

- Two input terms a and b
- The accumulate input term c
- Two input product terms `a` and `b` which can be different widths
- The accumulate input term `c` which must have width as sum of the two operand widths + 1.
- 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)
- Whether the operands should be treated as signed (2s complement) or unsigned
- The type of `ParallelPrefix` tree used in the final `ParallelPrefixAdder` (default Kogge-Stone).
- `signed` parameter: whether the operands should be treated as signed (2s complement) or unsigned
- An optional `selectSigned` control signal which overrides the `signed` configuration allowing for runtime control of signed or unsigned operation with the same hardware.

Here is an example of using the `CompressionTreeMultiplyAccumulate`:

Expand Down
6 changes: 5 additions & 1 deletion lib/src/arithmetic/evaluate_partial_product.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ extension EvaluateLivePartialProduct on PartialProductGenerator {
}
}
final sum = LogicValue.ofBigInt(accum, maxW).toBigInt();
return signed ? sum.toSigned(maxW) : sum;
return signed
? sum.toSigned(maxW)
: (selectSigned != null && !selectSigned!.value.isZero)
? sum.toSigned(maxW)
: sum;
}

/// Print out the partial product matrix
Expand Down
22 changes: 18 additions & 4 deletions lib/src/arithmetic/multiplicand_selector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,31 @@ class MultiplicandSelector {
late LogicArray multiples;

/// Generate required multiples of multiplicand
MultiplicandSelector(this.radix, this.multiplicand, {required bool signed})
MultiplicandSelector(this.radix, this.multiplicand,
{Logic? selectSigned, bool signed = false})
: shift = log2Ceil(radix) {
if (signed && (selectSigned != null)) {
throw RohdHclException('sign reconfiguration requires signed=false');
}
if (radix > 16) {
throw RohdHclException('Radices beyond 16 are not yet supported');
}
final width = multiplicand.width + shift;
final numMultiples = radix ~/ 2;
multiples = LogicArray([numMultiples], width);
final extendedMultiplicand = signed
? multiplicand.signExtend(width)
: multiplicand.zeroExtend(width);
final Logic extendedMultiplicand;
if (selectSigned == null) {
extendedMultiplicand = signed
? multiplicand.signExtend(width)
: multiplicand.zeroExtend(width);
} else {
final len = multiplicand.width;
final sign = multiplicand[len - 1];
final extension = [
for (var i = len; i < width; i++) mux(selectSigned, sign, Const(0))
];
extendedMultiplicand = (multiplicand.elements + extension).rswizzle();
}

for (var pos = 0; pos < numMultiples; pos++) {
final ratio = pos + 1;
Expand Down
39 changes: 30 additions & 9 deletions lib/src/arithmetic/multiplier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import 'package:meta/meta.dart';
import 'package:rohd/rohd.dart';
import 'package:rohd_hcl/rohd_hcl.dart';
import 'package:rohd_hcl/src/arithmetic/partial_product_sign_extend.dart';

/// An abstract class for all multiplier implementations.
abstract class Multiplier extends Module {
Expand Down Expand Up @@ -72,10 +73,20 @@ class CompressionTreeMultiplier extends Multiplier {
@override
Logic get product => output('product');

/// Construct a compression tree integer multipler with
/// a given radix and final adder functor
/// Construct a compression tree integer multiplier with a given [radix]
/// and prefix tree functor [ppTree] for the compressor and final adder.
///
/// [a] and [b] are the product terms and they can be different widths
/// allowing for rectangular multiplication.
///
/// [signed] parameter configures the multiplier as a signed multiplier
/// (default is unsigned).
///
/// Optional [selectSigned] allows for runtime configuration of signed
/// or unsigned operation, overriding the [signed] static configuration.
CompressionTreeMultiplier(super.a, super.b, int radix,
{ParallelPrefix Function(List<Logic>, Logic Function(Logic, Logic))
{Logic? selectSigned,
ParallelPrefix Function(List<Logic>, Logic Function(Logic, Logic))
ppTree = KoggeStone.new,
super.signed = false})
: super(
Expand All @@ -86,7 +97,7 @@ class CompressionTreeMultiplier extends Multiplier {
final product = addOutput('product', width: a.width + b.width);
final pp = PartialProductGeneratorCompactRectSignExtension(
a, b, RadixEncoder(radix),
signed: signed);
selectSigned: selectSigned, signed: signed);

final compressor = ColumnCompressor(pp)..compress();
final adder = ParallelPrefixAdder(
Expand All @@ -96,16 +107,26 @@ class CompressionTreeMultiplier extends Multiplier {
}
}

/// An implementation of an integer multiply accumulate using compression trees
/// An implementation of an integer multiply-accumulate using compression trees
class CompressionTreeMultiplyAccumulate extends MultiplyAccumulate {
/// The final product of the multiplier module.
@override
Logic get accumulate => output('accumulate');

/// Construct a compression tree integer multipler with
/// a given radix and final adder functor
/// Construct a compression tree integer multiply-add with a given [radix]
/// and prefix tree functor [ppTree] for the compressor and final adder.
///
/// [a] and [b] are the product terms, [c] is the accumulate term which
/// must be the sum of the widths plus 1.
///
/// [signed] parameter configures the multiplier as a signed multiplier
/// (default is unsigned).
///
/// Optional [selectSigned] allows for runtime configuration of signed
/// or unsigned operation, overriding the [signed] static configuration.
CompressionTreeMultiplyAccumulate(super.a, super.b, super.c, int radix,
{required super.signed,
Logic? selectSigned,
ParallelPrefix Function(List<Logic>, Logic Function(Logic, Logic))
ppTree = KoggeStone.new})
: super(
Expand All @@ -114,7 +135,7 @@ class CompressionTreeMultiplyAccumulate extends MultiplyAccumulate {
final accumulate = addOutput('accumulate', width: a.width + b.width + 1);
final pp = PartialProductGeneratorCompactRectSignExtension(
a, b, RadixEncoder(radix),
signed: signed);
selectSigned: selectSigned, signed: signed);

// TODO(desmonddak): This sign extension method for the additional
// addend may only work with CompactRectSignExtension
Expand Down Expand Up @@ -151,7 +172,7 @@ class MutiplyOnly extends MultiplyAccumulate {
Logic get accumulate => output('accumulate');

/// Construct a MultiplyAccumulate that only multiplies to enable
/// using the same tester with zero addend.
/// using the same tester with zero accumulate addend [c].
MutiplyOnly(super.a, super.b, super.c,
Multiplier Function(Logic a, Logic b) multiplyGenerator,
{super.signed = false}) // Will be overrwridden by multiplyGenerator
Expand Down
27 changes: 20 additions & 7 deletions lib/src/arithmetic/multiplier_encoder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ class RadixEncoder {
].swizzle().and());
}

return RadixEncode._(
multiples.rswizzle(), multiplierSlice[multiplierSlice.width - 1]);
return RadixEncode._(multiples.rswizzle(),
multiples.rswizzle().or() & multiplierSlice[multiplierSlice.width - 1]);
}
}

Expand All @@ -97,9 +97,12 @@ class MultiplierEncoder {

/// Generate an encoding of the input multiplier
MultiplierEncoder(this.multiplier, RadixEncoder radixEncoder,
{required bool signed})
{Logic? selectSigned, bool signed = false})
: _encoder = radixEncoder,
_sliceWidth = log2Ceil(radixEncoder.radix) + 1 {
if (signed && (selectSigned != null)) {
throw RohdHclException('sign reconfiguration requires signed=false');
}
// Unsigned encoding wants to overlap past the multipler
if (signed) {
rows =
Expand All @@ -109,10 +112,20 @@ class MultiplierEncoder {
rows = (((multiplier.width + 1) % (_sliceWidth - 1) == 0) ? 0 : 1) +
((multiplier.width + 1) ~/ log2Ceil(radixEncoder.radix));
}
// slices overlap by 1 and start at -1
_extendedMultiplier = (signed
? multiplier.signExtend(rows * (_sliceWidth - 1))
: multiplier.zeroExtend(rows * (_sliceWidth - 1)));
// slices overlap by 1 and start at -1a
if (selectSigned == null) {
_extendedMultiplier = (signed
? multiplier.signExtend(rows * (_sliceWidth - 1))
: multiplier.zeroExtend(rows * (_sliceWidth - 1)));
} else {
final len = multiplier.width;
final sign = multiplier[len - 1];
final extension = [
for (var i = len - 1; i < (rows * (_sliceWidth - 1)); i++)
mux(selectSigned, sign, Const(0))
];
_extendedMultiplier = (multiplier.elements + extension).rswizzle();
}
}

/// Retrieve the Booth encoding for the row
Expand Down
Loading
Loading