Skip to content

Commit

Permalink
Enhancements for modifying and printing partial product arrays.
Browse files Browse the repository at this point in the history
  • Loading branch information
desmonddak committed Oct 7, 2024
1 parent 87783b8 commit 437d2b4
Show file tree
Hide file tree
Showing 9 changed files with 298 additions and 71 deletions.
41 changes: 33 additions & 8 deletions doc/components/multiplier_components.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,20 +124,45 @@ Our `RadixEncoder` module is general, creating selection tables for arbitrary Bo

The `PartialProductGenerator` class also provides for sign extension with multiple options including `SignExtension.none` which is no sign extension for help in debugging, as well as `SignExtension.compactRect` which is a compact form which works for rectangular products where the multiplicand and multiplier can be of different widths.

If customization is needed beyond sign extension options, routines are provided that allow for fixed customization of bit positions, or conditional (muxed based on a Logic) form.

```dart
final ppg = PartialProductGenerator(a,b);
ppg.setAbsolute(row, col, logic);
ppg.setAbsoluteAll(row, col, List<Logic>);
ppg.muxAbsolute(row, col, condition, logic);
ppg.muxAbsoluteAll(row, col, condition, List<logic>);
```

### Partial Product Visualization

Creating new arithmetic building blocks from these components is tricky and visualizing intermediate results really helps. To that end, our `PartialProductGenerator` class has visualization extension `EvaluatePartialProduct` which help evaluate the current `Logic` values in array form during simulation to help with debug. The evaluation routine with the extension also adds the addends for you to help sanity check the partial product generation. The routine is `EvaluateLivePartialProduct.representation`.
Creating new arithmetic building blocks from these components is tricky and visualizing intermediate results really helps. To that end, our `PartialProductGenerator` class has visualization extension `EvaluatePartialProduct` which help evaluate the current `Logic` values in array form during simulation to help with debug. The evaluation routine with the extension also adds the addends for you to help sanity check the partial product generation. The routine is `EvaluateLivePartialProduct.representation`. Here 'S' or 's' represent a sign bit extension (positive polarity) with 'S' representing '1', 's' representing 0. 'I' and 'i' represent an inverted sign bit.

```text
18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
00 M= 2 S=1: 0 1 1 1 1 1 1 1 0 1 0 : 0000000001111111010 = 1018 (1018)
01 M= 1 S=0: 1 1 1 0 0 0 0 0 1 1 0 : 0000001110000011000 = 7192 (7192)
02 M= 0 S=0: 1 1 1 0 0 0 0 0 0 0 0 : 0001110000000000000 = 57344 (57344)
03 M= 0 S=0: 1 1 1 0 0 0 0 0 0 0 0 : 1110000000000000000 = 458752 (-65536)
======================================================================
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 : 0000000000000010010 = 18 (18)
18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
00 M= 2 S=1 i S S 1 1 1 1 1 1 0 0 0 = 2040 (2040)
01 M= 2 S=0 1 I 0 0 0 0 0 0 1 1 0 1 = 6170 (6170)
02 M= 0 S=0 1 I 0 0 0 0 0 0 0 0 0 0 = 24576 (24576)
03 M= 0 S=0 1 I 0 0 0 0 0 0 0 0 0 0 = 98304 (98304)
04 M= 0 S=0 1 I 0 0 0 0 0 0 0 0 0 0 = 393216 (-131072)
=====================================================================
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 = 18 (18)
```

You can also generate a Markdown form of the same matrix:
| R | M | S| 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | value|
|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--|
|00| 2| 1||||||||<span style="text-decoration:overline">0</span>|<u>1</u>|<u>1</u>|1|1|1|1|1|1|0|0|0| 2040 (2040)|

Check failure on line 155 in doc/components/multiplier_components.md

View workflow job for this annotation

GitHub Actions / Run Checks

Inline HTML

doc/components/multiplier_components.md:155:18 MD033/no-inline-html Inline HTML [Element: span] https://github.com/DavidAnson/markdownlint/blob/v0.29.0/doc/md033.md

Check failure on line 155 in doc/components/multiplier_components.md

View workflow job for this annotation

GitHub Actions / Run Checks

Inline HTML

doc/components/multiplier_components.md:155:66 MD033/no-inline-html Inline HTML [Element: u] https://github.com/DavidAnson/markdownlint/blob/v0.29.0/doc/md033.md

Check failure on line 155 in doc/components/multiplier_components.md

View workflow job for this annotation

GitHub Actions / Run Checks

Inline HTML

doc/components/multiplier_components.md:155:75 MD033/no-inline-html Inline HTML [Element: u] https://github.com/DavidAnson/markdownlint/blob/v0.29.0/doc/md033.md
|01| 2| 0|||||||1|<span style="text-decoration:overline">1</span>|0|0|0|0|0|0|1|1|0|1|| 6170 (6170)|

Check failure on line 156 in doc/components/multiplier_components.md

View workflow job for this annotation

GitHub Actions / Run Checks

Inline HTML

doc/components/multiplier_components.md:156:19 MD033/no-inline-html Inline HTML [Element: span] https://github.com/DavidAnson/markdownlint/blob/v0.29.0/doc/md033.md
|02| 0| 0|||||1|<span style="text-decoration:overline">1</span>|0|0|0|0|0|0|0|0|0|0|||| 24576 (24576)|

Check failure on line 157 in doc/components/multiplier_components.md

View workflow job for this annotation

GitHub Actions / Run Checks

Inline HTML

doc/components/multiplier_components.md:157:17 MD033/no-inline-html Inline HTML [Element: span] https://github.com/DavidAnson/markdownlint/blob/v0.29.0/doc/md033.md
|03| 0| 0|||1|<span style="text-decoration:overline">1</span>|0|0|0|0|0|0|0|0|0|0|||||| 98304 (98304)|

Check failure on line 158 in doc/components/multiplier_components.md

View workflow job for this annotation

GitHub Actions / Run Checks

Inline HTML

doc/components/multiplier_components.md:158:15 MD033/no-inline-html Inline HTML [Element: span] https://github.com/DavidAnson/markdownlint/blob/v0.29.0/doc/md033.md
|04| 0| 0|1|<span style="text-decoration:overline">1</span>|0|0|0|0|0|0|0|0|0|0|||||||| 393216 (-131072)|

Check failure on line 159 in doc/components/multiplier_components.md

View workflow job for this annotation

GitHub Actions / Run Checks

Inline HTML

doc/components/multiplier_components.md:159:13 MD033/no-inline-html Inline HTML [Element: span] https://github.com/DavidAnson/markdownlint/blob/v0.29.0/doc/md033.md
||
||||0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |1 |0 |0 |1 |0 |18 (18)|

Here <u>1</u> or <u>0</u> represent a sign bit extension (positive polarity),

Check failure on line 163 in doc/components/multiplier_components.md

View workflow job for this annotation

GitHub Actions / Run Checks

Inline HTML

doc/components/multiplier_components.md:163:7 MD033/no-inline-html Inline HTML [Element: u] https://github.com/DavidAnson/markdownlint/blob/v0.29.0/doc/md033.md

Check failure on line 163 in doc/components/multiplier_components.md

View workflow job for this annotation

GitHub Actions / Run Checks

Inline HTML

doc/components/multiplier_components.md:163:19 MD033/no-inline-html Inline HTML [Element: u] https://github.com/DavidAnson/markdownlint/blob/v0.29.0/doc/md033.md
whereas <span style="text-decoration:overline">1</span> or <span style="text-decoration:overline">0</span> represents a negative polarity sign bit.

Check failure on line 164 in doc/components/multiplier_components.md

View workflow job for this annotation

GitHub Actions / Run Checks

Inline HTML

doc/components/multiplier_components.md:164:10 MD033/no-inline-html Inline HTML [Element: span] https://github.com/DavidAnson/markdownlint/blob/v0.29.0/doc/md033.md

## Compression Tree

Once you have a partial product matrix, you would like to add up the addends. Traditionally this is done using compression trees which instantiate 2:1 and 3:2 column compressors (or carry-save adders) to reduce the matrix to two addends. The final two addends are often added with an efficient final adder.
Expand Down
5 changes: 4 additions & 1 deletion lib/src/arithmetic/addend_compressor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,10 @@ class ColumnCompressor {
}
}
rowBits.addAll(List.filled(pp.rowShift[row], Const(0)));
return rowBits.swizzle().zeroExtend(width);
if (width > rowBits.length) {
return rowBits.swizzle().zeroExtend(width);
}
return rowBits.swizzle().getRange(0, width);
}

/// Core iterator for column compressor routine
Expand Down
3 changes: 2 additions & 1 deletion lib/src/arithmetic/arithmetic_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ extension NumericVector on LogicValue {
int extraSpace = 0,
bool markDown = false}) {
final str = StringBuffer();
final maxHigh = max(alignHigh ?? width, width);
final minHigh = min(alignHigh ?? width, width);
final length = BigInt.from(minHigh).toString().length + extraSpace;
final length = BigInt.from(maxHigh).toString().length + extraSpace;
// ignore: cascade_invocations
const hdrSep = '| ';
const hdrSepStart = '| ';
Expand Down
137 changes: 99 additions & 38 deletions lib/src/arithmetic/evaluate_partial_product.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,15 @@ extension EvaluateLivePartialProduct on PartialProductGenerator {
return signed ? sum.toSigned(maxW) : sum;
}

/// Print out the partial product matrix
String representation() {
/// Print out the partial product matrix.
/// S = Sign bit positive polarity = 1 final value)
/// s = Sign bit positive polarity = 0 final value)
/// I = Sign bit negative polarity = 1 final value)
/// i = Sign bit negative polarity = 0 (final value)
/// [bitvector] = true will print out a compact final bitvector array
/// [value] = true will print out the numerical value of the bitvector as
/// 'unsigned (signed)
String representation({bool bitvector = false, bool value = true}) {
final str = StringBuffer();

final maxW = maxWidth();
Expand All @@ -39,7 +46,7 @@ extension EvaluateLivePartialProduct on PartialProductGenerator {
? shift - 1
: 1;
// We will print encoding(1-hot multiples and sign) before each row
final shortPrefix = '99 ${'M='}99 S= : '.length + 3 * nonSignExtendedPad;
final shortPrefix = '99 ${'M='}99 S= '.length + 3 * nonSignExtendedPad;

// print bit position header
str.write(' ' * shortPrefix);
Expand All @@ -61,28 +68,43 @@ extension EvaluateLivePartialProduct on PartialProductGenerator {
final multiple = first + 1;
str.write('$rowStr M='
'${multiple.toString().padLeft(2)} '
'S=${encoding.sign.value.toInt()}: ');
'S=${encoding.sign.value.toInt()} ');
} else {
str.write(' ' * shortPrefix);
}
} else {
str.write('$rowStr ${'M='} S= : ');
str.write('$rowStr ${'M='} S= ');
}
final entry = partialProducts[row].reversed.toList();
final prefixCnt =
maxW - (entry.length + rowShift[row]) + nonSignExtendedPad;
str.write(' ' * prefixCnt);
for (var col = 0; col < entry.length; col++) {
str.write('${entry[col].value.bitString} ');
final bit = entry[col];
if (bit is SignBit) {
final val = bit.value.toInt();
if (bit.inverted) {
str.write(val == 0 ? 'i' : 'I');
} else {
str.write(val == 0 ? 's' : 'S');
}
str.write(' ');
} else {
str.write('${entry[col].value.bitString} ');
}
}
final suffixCnt = rowShift[row];
final value = entry.swizzle().value.zeroExtend(maxW) << suffixCnt;
final intValue = value.isValid ? value.toBigInt() : BigInt.from(-1);
str
..write(' ' * suffixCnt)
..write(': ${value.bitString}')
..write(' = ${value.isValid ? intValue : "<invalid>"}'
' (${value.isValid ? intValue.toSigned(maxW) : "<invalid>"})\n');
final bitVal = entry.swizzle().value.zeroExtend(maxW) << suffixCnt;
final intValue = bitVal.isValid ? bitVal.toBigInt() : BigInt.from(-1);
str.write(' ' * suffixCnt);
if (bitvector) {
str.write(': ${bitVal.bitString}');
}
if (value) {
str.write(' = ${bitVal.isValid ? intValue : "<invalid>"}'
' (${bitVal.isValid ? intValue.toSigned(maxW) : "<invalid>"})');
}
str.write('\n');
}
// Compute and print binary representation from accumulated value
// Later: we will compare with a compression tree result
Expand All @@ -97,16 +119,24 @@ extension EvaluateLivePartialProduct on PartialProductGenerator {
str.write('${elem.toInt()} ');
}
final val = evaluate();
str.write(': ${sum.bitString} = '
'${val.toUnsigned(maxW)}');
if (isSignExtended) {
str.write(' ($val)\n\n');
if (bitvector) {
str.write(': ${sum.bitString}');
}
if (value) {
str.write(' = '
'${val.toUnsigned(maxW)}');
if (isSignExtended) {
str.write(' ($val)');
}
}
str.write('\n');
return str.toString();
}

/// Print out the partial product matrix
String markdown() {
/// [bitvector] = true will print out a compact bitvector to the right
/// [value] = true will print out the value of each row as 'unsigned (signed)'
String markdown({bool bitvector = false, bool value = true}) {
final str = StringBuffer();

final maxW = maxWidth();
Expand All @@ -115,13 +145,25 @@ extension EvaluateLivePartialProduct on PartialProductGenerator {
for (var i = maxW - 1; i >= 0; i--) {
str.write('| $i ');
}
str
..write('| bitvector | value|\n')
..write('|:--:' * 3);
if (bitvector) {
str.write('| bitvector ');
}
if (value) {
str.write('| value');
}
str.write('|\n');
str.write('|:--:' * 3);
for (var i = maxW - 1; i >= 0; i--) {
str.write('|:--:');
}
str.write('|:--: |:--:|\n');
str.write('|');
if (bitvector) {
str.write(':--|');
}
if (value) {
str.write(':--|');
}
str.write('\n');
// Partial product matrix: rows of multiplicand multiples shift by
// rowshift[row]
for (var row = 0; row < rows; row++) {
Expand All @@ -135,24 +177,39 @@ extension EvaluateLivePartialProduct on PartialProductGenerator {
'$multiple| '
'${encoding.sign.value.toInt()}');
} else {
str.write('| | |');
str.write('|||');
}
} else {
str.write('|$rowStr | |');
str.write('|$rowStr ||');
}
final entry = partialProducts[row].reversed.toList();
str.write('| ' * (maxW - (entry.length + rowShift[row])));
str.write('|' * (maxW - (entry.length + rowShift[row])));
for (var col = 0; col < entry.length; col++) {
str.write('|${entry[col].value.bitString}');
final bit = entry[col];
if (bit is SignBit) {
if (bit.inverted) {
str.write('|<span style="text-decoration:overline">'
'${entry[col].value.bitString}'
'</span>');
} else {
str.write('|<u>${entry[col].value.bitString}</u>');
}
} else {
str.write('|${entry[col].value.bitString}');
}
}
final suffixCnt = rowShift[row];
final value = entry.swizzle().value.zeroExtend(maxW) << suffixCnt;
final intValue = value.isValid ? value.toBigInt() : BigInt.from(-1);
str
..write('| ' * suffixCnt)
..write('| ${value.bitString}')
..write('| ${value.isValid ? intValue : "<invalid>"}'
' (${value.isValid ? intValue.toSigned(maxW) : "<invalid>"})|\n');
final val = entry.swizzle().value.zeroExtend(maxW) << suffixCnt;
final intValue = val.isValid ? val.toBigInt() : BigInt.from(-1);
str.write('|' * suffixCnt);
if (bitvector) {
str.write('| ${val.bitString}');
}
if (value) {
str.write('| ${val.isValid ? intValue : "<invalid>"}'
' (${val.isValid ? intValue.toSigned(maxW) : "<invalid>"})');
}
str.write('|\n');
}
// Compute and print binary representation from accumulated value
// Later: we will compare with a compression tree result
Expand All @@ -164,11 +221,15 @@ extension EvaluateLivePartialProduct on PartialProductGenerator {
for (final elem in [for (var i = 0; i < maxW; i++) sum[i]].reversed) {
str.write('|${elem.toInt()} ');
}
final val = evaluate();
str.write('| ${sum.bitString}| '
'${val.toUnsigned(maxW)}');
if (isSignExtended) {
str.write(' ($val)');
if (bitvector) {
str.write('| ${sum.bitString}');
}
if (value) {
final val = evaluate();
str.write('|${val.toUnsigned(maxW)}');
if (isSignExtended) {
str.write(' ($val)');
}
}
str.write('|\n');
return str.toString();
Expand Down
Loading

0 comments on commit 437d2b4

Please sign in to comment.