Skip to content

Commit

Permalink
Agnostic multiplier (#125)
Browse files Browse the repository at this point in the history
* compressor with flopped output

* selectSigned is working for partial product generation

* multiplier documentation update
  • Loading branch information
desmonddak authored Nov 6, 2024
1 parent b6f7059 commit 7499025
Show file tree
Hide file tree
Showing 12 changed files with 479 additions and 265 deletions.
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

0 comments on commit 7499025

Please sign in to comment.