Skip to content

Commit

Permalink
split/reorganize integer multiplication files
Browse files Browse the repository at this point in the history
  • Loading branch information
desmonddak committed Aug 9, 2024
1 parent ac60259 commit ae9055f
Show file tree
Hide file tree
Showing 12 changed files with 659 additions and 99 deletions.
20 changes: 10 additions & 10 deletions doc/components/multiplier.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
# Multiplier

ROHD HCL provides an abstract [Multiplier] module which multiplies two
numbers represented as two [Logic]s, potentially of different widths,
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
produces the product as a [Logic] with width equal to the sum of the
produces the product as a `Logic` with width equal to the sum of the
widths of the inputs. As of now, we have the following implementations
of this abstract [Module]:
of this abstract `Module`:

- [Carry Save Multiplier](#carry-save-multiplier)
- [Compression Tree Multiplier](#compression-tree-multiplier)

An additional kind of abstract module provided is a
[MultiplyAccumulate] module which multiplies two numbers represented
as two [Logic]s and adds the result to a third [Logic] with width
`MultiplyAccumulate` module which multiplies two numbers represented
as two `Logic`s and adds the result to a third `Logic` with width
equal to the sum of the widths of the main inputs. We have a
high-performance implementation:

Expand Down Expand Up @@ -78,11 +78,11 @@ useful in applications that require high speed multiplication, such as
digital signal processing.

The parameters of the
[CompressionTreeMultiplier] are:
`CompressionTreeMultiplier` are:

- Two input terms a and b
- The radix used for Booth encoding (2, 4, 8, and 16 are currently supported)
- The type of [ParallelPrefix] tree used in the final [ParallelPrefixAdder]
- The type of `ParallelPrefix` tree used in the final `ParallelPrefixAdder`
- Whether the operands should be treated as signed (2s complement) or unsigned

## Compression Tree Multiply Accumulate
Expand All @@ -92,10 +92,10 @@ multiplier, but it inserts an additional addend into the compression
tree to allow for accumulation into this third input.

The parameters of the
[CompressionTreeMultiplier] are:
`CompressionTreeMultiplier` are:

- Two input terms a and b
- The accumulate input term c
- The radix used for Booth encoding (2, 4, 8, and 16 are currently supported)
- The type of [ParallelPrefix] tree used in the final [ParallelPrefixAdder]
- The type of `ParallelPrefix` tree used in the final `ParallelPrefixAdder`
- Whether the operands should be treated as signed (2s complement) or unsigned
2 changes: 2 additions & 0 deletions lib/rohd_hcl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
export 'src/arbiters/arbiters.dart';
export 'src/arithmetic/adder.dart';
export 'src/arithmetic/carry_save_mutiplier.dart';
export 'src/arithmetic/compressor.dart';
export 'src/arithmetic/multiplier.dart';
export 'src/arithmetic/multiplier_encoder.dart';
export 'src/arithmetic/parallel_prefix_operations.dart';
export 'src/arithmetic/ripple_carry_adder.dart';
export 'src/arithmetic/sign_magnitude_adder.dart';
Expand Down
20 changes: 13 additions & 7 deletions lib/src/arithmetic/compressor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,11 @@ import 'package:collection/collection.dart';
import 'package:meta/meta.dart';
import 'package:rohd/rohd.dart';
import 'package:rohd_hcl/rohd_hcl.dart';
import 'package:rohd_hcl/src/arithmetic/booth.dart';

// TODO(desmonddak): Logic and LogicValue majority() functions

/// Base class for column compressor function
class Compressor extends Module {
abstract class Compressor extends Module {
/// Input bits to compress
@protected
late final Logic compressBits;
Expand Down Expand Up @@ -60,8 +59,17 @@ class Compressor3 extends Compressor {
}
}

// ignore: public_member_api_docs
enum CompressTermType { carry, sum, pp }
/// Compress terms
enum CompressTermType {
/// A carry term
carry,

/// A sum term
sum,

/// A partial product term (from the original matrix)
pp
}

/// A compression term
class CompressTerm implements Comparable<CompressTerm> {
Expand Down Expand Up @@ -90,9 +98,7 @@ class CompressTerm implements Comparable<CompressTerm> {
static const carryDelay = 0.75;

/// CompressTerm constructor
CompressTerm(this.type, this.row, this.col) {
delay = 0.0;
}
CompressTerm(this.type, this.row, this.col) : delay = 0.0;

/// Create a sum Term
factory CompressTerm.sumTerm(List<CompressTerm> args, int row, int col) {
Expand Down
73 changes: 73 additions & 0 deletions lib/src/arithmetic/multiplicand_selector.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// multiplicand_selector.dart
// Selection of muliples of the multiplicand for booth recoding
//
// 2024 May 15
// Author: Desmond Kirkpatrick <[email protected]>

import 'package:rohd/rohd.dart';
import 'package:rohd_hcl/rohd_hcl.dart';
import 'package:rohd_hcl/src/arithmetic/multiplier_encoder.dart';

/// A class accessing the multiples of the multiplicand at a position
class MultiplicandSelector {
/// radix of the selector
int radix;

/// The bit shift of the selector (typically overlaps 1)
int shift;

/// New width of partial products generated from the multiplicand
int get width => multiplicand.width + shift - 1;

/// Access the multiplicand
Logic multiplicand = Logic();

/// Place to store multiples of the multiplicand
late LogicArray multiples;

/// Generate required multiples of multiplicand
MultiplicandSelector(this.radix, this.multiplicand, {bool signed = true})
: shift = log2Ceil(radix) {
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);

for (var pos = 0; pos < numMultiples; pos++) {
final ratio = pos + 1;
multiples.elements[pos] <=
switch (ratio) {
1 => extendedMultiplicand,
2 => extendedMultiplicand << 1,
3 => (extendedMultiplicand << 2) - extendedMultiplicand,
4 => extendedMultiplicand << 2,
5 => (extendedMultiplicand << 2) + extendedMultiplicand,
6 => (extendedMultiplicand << 3) - (extendedMultiplicand << 1),
7 => (extendedMultiplicand << 3) - extendedMultiplicand,
8 => extendedMultiplicand << 3,
_ => throw RohdHclException('Radix is beyond 16')
};
}
}

/// Retrieve the multiples of the multiplicand at current bit position
Logic getMultiples(int col) => [
for (var i = 0; i < multiples.elements.length; i++)
multiples.elements[i][col]
].swizzle().reversed;

Logic _select(Logic multiples, RadixEncode encode) =>
(encode.multiples & multiples).or() ^ encode.sign;

/// Select the partial product term from the multiples using a RadixEncode
Logic select(int col, RadixEncode encode) =>
_select(getMultiples(col), encode);
}
42 changes: 13 additions & 29 deletions lib/src/arithmetic/multiplier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
import 'package:meta/meta.dart';
import 'package:rohd/rohd.dart';
import 'package:rohd_hcl/rohd_hcl.dart';
import 'package:rohd_hcl/src/arithmetic/booth.dart';
import 'package:rohd_hcl/src/arithmetic/compressor.dart';

/// An abstract class for all multiplier implementations.
abstract class Multiplier extends Module {
Expand All @@ -25,18 +23,14 @@ abstract class Multiplier extends Module {
late final Logic b;

/// The multiplier treats operands and output as signed
bool get signed => _signed;

@protected
bool _signed = false;
bool signed;

/// The multiplication results of the multiplier.
Logic get product;

/// Take input [a] and input [b] and return the
/// [product] of the multiplication result.
Multiplier(Logic a, Logic b, {bool signed = false, super.name}) {
_signed = signed;
Multiplier(Logic a, Logic b, {this.signed = false, super.name}) {
this.a = addInput('a', a, width: a.width);
this.b = addInput('b', b, width: b.width);
}
Expand All @@ -57,19 +51,15 @@ abstract class MultiplyAccumulate extends Module {
late final Logic c;

/// The multiplier treats operands and output as signed
bool get signed => _signed;

@protected
bool _signed = false;
bool signed;

/// The multiplication results of the multiply-accumulate.
Logic get accumulate;

/// Take input [a] and input [b], compute their
/// product, add input [c] to produce the [accumulate] result.
MultiplyAccumulate(Logic a, Logic b, Logic c,
{bool signed = false, super.name}) {
_signed = signed;
{this.signed = false, super.name}) {
this.a = addInput('a', a, width: a.width);
this.b = addInput('b', b, width: b.width);
this.c = addInput('c', c, width: c.width);
Expand Down Expand Up @@ -117,22 +107,14 @@ class CompressionTreeMultiplyAccumulate extends MultiplyAccumulate {
/// a given radix and final adder functor
CompressionTreeMultiplyAccumulate(super.a, super.b, super.c, int radix,
ParallelPrefix Function(List<Logic>, Logic Function(Logic, Logic)) ppTree,
{bool signed = false})
{super.signed = false})
: super(
name: 'Compression Tree Multiplier: '
'R${radix}_${ppTree.call([Logic()], (a, b) => Logic()).name}') {
final accumulate = addOutput('accumulate', width: a.width + b.width + 1);
_signed = signed;

final pp =
PartialProductGenerator(a, b, RadixEncoder(radix), signed: signed);
// ignore: cascade_invocations
pp.signExtendCompact();

// Evaluate works only because the compressed rows have the same shape
// So the rowshift is valid.
// But this requires that we prefix the PP with the addend (not add) to
// keep the evaluate routine working.
PartialProductGenerator(a, b, RadixEncoder(radix), signed: signed)
..signExtendCompact();

// TODO(desmonddak): This sign extension method for the additional
// addend may only work with signExtendCompact.
Expand All @@ -149,16 +131,18 @@ class CompressionTreeMultiplyAccumulate extends MultiplyAccumulate {
..add(~sign)
..add(Const(1));

// Evaluate works only because the compressed rows have the same shape
// So the rowshift is valid.
// But this requires that we prefix the PP with the addend (not add) to
// keep the evaluate routine working.
pp.partialProducts.insert(0, l);
pp.rowShift.insert(0, 0);

// TODO(desmonddak): probably cleaner to add row at end, but
// compressor fails to properly handle, so we need to debug
// pp.partialProducts.add(l);
// pp.rowShift.add(0);
final compressor = ColumnCompressor(pp);
// ignore: cascade_invocations
compressor.compress();
final compressor = ColumnCompressor(pp)..compress();

final adder = ParallelPrefixAdder(
compressor.extractRow(0), compressor.extractRow(1), ppTree);
Expand All @@ -180,7 +164,7 @@ class MultiplyOnly extends MultiplyAccumulate {
final accumulate = addOutput('accumulate', width: a.width + b.width + 1);

final multiply = multiplyGenerator(a, b);
_signed = multiply.signed;
signed = multiply.signed;

accumulate <=
(signed
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// booth.dart
// muliplier_encoder.dart
// Generation of Booth Encoded partial products for multiplication
//
// 2024 May 15
// Author: Desmond Kirkpatrick <[email protected]>

import 'dart:io';
import 'dart:math';

import 'package:rohd/rohd.dart';
import 'package:rohd_hcl/rohd_hcl.dart';

/// Simplest version of bit string representation
// String bitString(LogicValue value) => value.toString(includeWidth: false);

/// A bundle for the leaf radix compute nodes
/// This holds the multiples of the multiplicand that are needed for encoding
/// A bundle for the leaf radix compute nodes. This holds the multiples
/// of the multiplicand that are needed for encoding
class RadixEncode extends LogicStructure {
/// Which multiples need to be selected
final Logic multiples;
Expand Down Expand Up @@ -84,11 +80,13 @@ class RadixEncoder {
/// A class that generates the Booth encoding of the multipler
class MultiplierEncoder {
/// Access the multiplier
Logic multiplier = Logic();
final Logic multiplier;

/// Number of row radixEncoders
late final int rows;

/// The multiplier value, sign extended as appropriate to be divisible
/// by the RadixEncoder overlapping bitslices.
Logic _extendedMultiplier = Logic();
late final RadixEncoder _encoder;
late final int _sliceWidth;
Expand Down
4 changes: 2 additions & 2 deletions lib/src/arithmetic/parallel_prefix_operations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,8 @@ class ParallelPrefixPriorityEncoder extends Module {

/// Adder based on ParallelPrefix tree
class ParallelPrefixAdder extends Adder {
late final Logic _out;
late final Logic _carry = Logic();
final Logic _out;
final Logic _carry = Logic();

/// Adder constructor
ParallelPrefixAdder(super.a, super.b,
Expand Down
Loading

0 comments on commit ae9055f

Please sign in to comment.