From 700745da99ae62bf245049ad48c7265c3b05e56c Mon Sep 17 00:00:00 2001 From: Galileo Newton Date: Sat, 11 Jan 2025 07:28:20 -0800 Subject: [PATCH 01/14] begin refactoring of sign extension classes: compactrect refactored and passing --- .../arithmetic/partial_product_generator.dart | 8 +- .../partial_product_sign_extend.dart | 280 +++++++++++++++++- test/arithmetic/multiplier_encoder_test.dart | 51 ++++ 3 files changed, 331 insertions(+), 8 deletions(-) diff --git a/lib/src/arithmetic/partial_product_generator.dart b/lib/src/arithmetic/partial_product_generator.dart index 048d3b92f..35b5a17ac 100644 --- a/lib/src/arithmetic/partial_product_generator.dart +++ b/lib/src/arithmetic/partial_product_generator.dart @@ -227,13 +227,17 @@ abstract class PartialProductGenerator extends PartialProductArray { PartialProductGenerator( Logic multiplicand, Logic multiplier, RadixEncoder radixEncoder, {this.signedMultiplicand = false, - this.selectSignedMultiplicand, this.signedMultiplier = false, + this.selectSignedMultiplicand, this.selectSignedMultiplier, super.name = 'ppg'}) { if (signedMultiplier && (selectSignedMultiplier != null)) { throw RohdHclException('sign reconfiguration requires signed=false'); } + if (signedMultiplicand && (selectSignedMultiplicand != null)) { + throw RohdHclException('multiplicand sign reconfiguration requires ' + 'signedMultiplicand=false'); + } encoder = MultiplierEncoder(multiplier, radixEncoder, signedMultiplier: signedMultiplier, selectSignedMultiplier: selectSignedMultiplier); @@ -250,7 +254,7 @@ abstract class PartialProductGenerator extends PartialProductArray { 'or equal to ${selector.shift + (signedMultiplier ? 1 : 0)}'); } _build(); - signExtend(); + // signExtend(); } /// Perform sign extension (defined in child classes) diff --git a/lib/src/arithmetic/partial_product_sign_extend.dart b/lib/src/arithmetic/partial_product_sign_extend.dart index 33aa48ae7..a6c2aa4ae 100644 --- a/lib/src/arithmetic/partial_product_sign_extend.dart +++ b/lib/src/arithmetic/partial_product_sign_extend.dart @@ -64,7 +64,9 @@ class PartialProductGeneratorBruteSignExtension super.signedMultiplier, super.selectSignedMultiplicand, super.selectSignedMultiplier, - super.name = 'brute'}); + super.name = 'brute'}) { + signExtend(); + } /// Fully sign extend the PP array: useful for reference only @override @@ -111,7 +113,9 @@ class PartialProductGeneratorCompactSignExtension super.selectSignedMultiplicand, super.signedMultiplier, super.selectSignedMultiplier, - super.name = 'compact'}); + super.name = 'compact'}) { + signExtend(); + } /// Sign extend the PP array using stop bits without adding a row. @override @@ -236,7 +240,9 @@ class PartialProductGeneratorStopBitsSignExtension super.selectSignedMultiplicand, super.signedMultiplier, super.selectSignedMultiplier, - super.name = 'stop_bits'}); + super.name = 'stop_bits'}) { + signExtend(); + } /// Sign extend the PP array using stop bits. /// If possible, fold the final carry into another row (only when rectangular @@ -315,16 +321,18 @@ class PartialProductGeneratorStopBitsSignExtension } /// A Partial Product Generator using Compact Rectangular Extension -class PartialProductGeneratorCompactRectSignExtension +class OldPartialProductGeneratorCompactRectSignExtension extends PartialProductGenerator { /// Construct a compact rect sign extending Partial Product Generator - PartialProductGeneratorCompactRectSignExtension( + OldPartialProductGeneratorCompactRectSignExtension( super.multiplicand, super.multiplier, super.radixEncoder, {super.signedMultiplicand, super.signedMultiplier, super.selectSignedMultiplicand, super.selectSignedMultiplier, - super.name = 'compact_rect'}); + super.name = 'compact_rect'}) { + signExtend(); + } /// Sign extend the PP array using stop bits without adding a row /// This routine works with different widths of multiplicand/multiplier, @@ -332,10 +340,270 @@ class PartialProductGeneratorCompactRectSignExtension /// Desmond A. Kirkpatrick @override void signExtend() { + if (isSignExtended) { + throw RohdHclException('Partial Product array already sign-extended'); + } + isSignExtended = true; + + final lastRow = rows - 1; + final firstAddend = partialProducts[0]; + final lastAddend = partialProducts[lastRow]; + + final firstRowQStart = selector.width - (signedMultiplicand ? 1 : 0); + final lastRowSignPos = shift * lastRow; + + final align = firstRowQStart - lastRowSignPos; + + final signs = [for (var r = 0; r < rows; r++) encoder.getEncoding(r).sign]; + + // Compute propgation info for folding sign bits into main rows + final propagate = + List.generate(rows, (i) => List.filled(0, Logic(), growable: true)); + + for (var row = 0; row < rows; row++) { + propagate[row].add(SignBit(signs[row])); + for (var col = 0; col < 2 * (shift - 1); col++) { + propagate[row].add(partialProducts[row][col]); + } + // Last row has extend sign propagation to Q start + if (row == lastRow) { + var col = 2 * (shift - 1); + while (propagate[lastRow].length <= align) { + propagate[lastRow].add(SignBit(partialProducts[row][col++])); + } + } + // Now compute the propagation logic + for (var col = 1; col < propagate[row].length; col++) { + propagate[row][col] = propagate[row][col] & propagate[row][col - 1]; + } + } + + // Compute 'm', the prefix of each row to carry the sign of the next row + final m = + List.generate(rows, (i) => List.filled(0, Logic(), growable: true)); + for (var row = 0; row < rows; row++) { + for (var c = 0; c < shift - 1; c++) { + m[row].add(partialProducts[row][c] ^ propagate[row][c]); + } + m[row].addAll(List.filled(shift - 1, Logic())); + } + + while (m[lastRow].length < align) { + m[lastRow].add(Logic()); + } + for (var i = shift - 1; i < m[lastRow].length; i++) { + m[lastRow][i] = + lastAddend[i] ^ (i < align ? propagate[lastRow][i] : Const(0)); + } + + final remainders = List.filled(rows, Logic()); + for (var row = 0; row < lastRow; row++) { + remainders[row] = propagate[row][shift - 1]; + } + remainders[lastRow] = propagate[lastRow][align > 0 ? align : 0]; + + // Merge 'm' into the LSBs of each addend + for (var row = 0; row < rows; row++) { + final addend = partialProducts[row]; + if (row > 0) { + final mLimit = (row == lastRow) ? align : shift - 1; + for (var i = 0; i < mLimit; i++) { + addend[i] = m[row][i]; + } + // Stop bits + addStopSignFlip(addend, SignBit(~signs[row], inverted: true)); + addend + ..insert(0, remainders[row - 1]) + ..addAll(List.filled(shift - 1, Const(1))); + rowShift[row] -= 1; + } else { + // First row + for (var i = 0; i < shift - 1; i++) { + firstAddend[i] = m[0][i]; + } + } + } + + // Insert the lastRow sign: Either in firstRow's Q if there is a + // collision or in another row if it lands beyond the Q sign extension + final Logic firstSign; + if (selectSignedMultiplicand == null) { + firstSign = + signedMultiplicand ? SignBit(firstAddend.last) : SignBit(signs[0]); + } else { + firstSign = + SignBit(mux(selectSignedMultiplicand!, firstAddend.last, signs[0])); + } + final lastSign = SignBit(remainders[lastRow]); + // Compute Sign extension MSBs for firstRow + final qLen = shift + 1; + final insertSignPos = (align > 0) ? 0 : -align; + final q = List.filled(min(qLen, insertSignPos), firstSign, growable: true); + if (insertSignPos < qLen) { + // At sign insertion position + q.add(SignBit(firstSign ^ lastSign)); + if (insertSignPos == qLen - 1) { + q[insertSignPos] = SignBit(~q[insertSignPos], inverted: true); + q.add(SignBit(~(firstSign | q[insertSignPos]), inverted: true)); + } else { + q + ..addAll(List.filled( + qLen - insertSignPos - 2, SignBit(firstSign & ~lastSign))) + ..add(SignBit(~(firstSign & ~lastSign), inverted: true)); + } + } + + if (-align >= q.length) { + q.last = SignBit(~firstSign, inverted: true); + } + addStopSign(firstAddend, SignBit(q[0])); + firstAddend.addAll(q.getRange(1, q.length)); + + if (-align >= q.length) { + final finalCarryRelPos = lastRowSignPos - + selector.width - + shift + + (signedMultiplicand ? 1 : 0); + final finalCarryRow = (finalCarryRelPos / shift).floor(); + final curRowLength = + partialProducts[finalCarryRow].length + rowShift[finalCarryRow]; + + partialProducts[finalCarryRow] + ..addAll(List.filled(lastRowSignPos - curRowLength, Const(0))) + ..add(remainders[lastRow]); + } + if (shift == 1) { + lastAddend.add(Const(1)); + } + } +} + +/// A wrapper class for CompactRectSignExtension we used +/// during refactoring to be compatible with old calls. +class PartialProductGeneratorCompactRectSignExtension + extends PartialProductGenerator { + /// The extension routine we will be using. + late final PartialProductSignExtension extender; + + /// Construct a compact rect sign extending Partial Product Generator + PartialProductGeneratorCompactRectSignExtension( + super.multiplicand, super.multiplier, super.radixEncoder, + {super.signedMultiplicand, + super.signedMultiplier, + super.selectSignedMultiplicand, + super.selectSignedMultiplier, + super.name = 'compact_rect'}) { + extender = CompactRectSignExtension(this, + signedMultiplicand: signedMultiplicand, + signedMultiplier: signedMultiplier, + selectSignedMultiplicand: selectSignedMultiplicand, + selectSignedMultiplier: selectSignedMultiplier); + signExtend(); + } + + @override + void signExtend() { + extender.signExtend(); + } +} + +/// API for sign extension classes +abstract class PartialProductSignExtension { + /// The partial product generator we are sign extending. + late final PartialProductGenerator ppg; + + /// multiplicand operand is always signed. + final bool signedMultiplicand; + + /// multiplier operand is always signed. + final bool signedMultiplier; + + /// If not null, use this signal to select between signed and unsigned + /// multiplicand. + final Logic? selectSignedMultiplicand; + + /// If not null, use this signal to select between signed and unsigned + /// multiplier. + final Logic? selectSignedMultiplier; + + /// Sign Extension class that operates on a [PartialProductGenerator] + /// and sign-extends the entries. + PartialProductSignExtension( + this.ppg, { + this.signedMultiplicand = false, + this.signedMultiplier = false, + this.selectSignedMultiplicand, + this.selectSignedMultiplier, + }) { + // + if (signedMultiplier && (selectSignedMultiplier != null)) { + throw RohdHclException('sign reconfiguration requires signed=false'); + } if (signedMultiplicand && (selectSignedMultiplicand != null)) { throw RohdHclException('multiplicand sign reconfiguration requires ' 'signedMultiplicand=false'); } + } + + /// Execute the sign extension, overridden to specialize. + void signExtend(); + + /// Helper function for sign extension routines: + /// For signed operands, set the MSB to [sign], otherwise add this [sign] bit. + void addStopSign(List addend, SignBit sign) { + if (!signedMultiplicand) { + addend.add(sign); + } else { + addend.last = sign; + } + } + + /// Helper function for sign extension routines: + /// For signed operands, flip the MSB, otherwise add this [sign] bit. + void addStopSignFlip(List addend, SignBit sign) { + if (!signedMultiplicand) { + if (selectSignedMultiplicand == null) { + addend.add(sign); + } else { + addend.add(SignBit(mux(selectSignedMultiplicand!, ~addend.last, sign), + inverted: selectSignedMultiplicand != null)); + } + } else { + addend.last = SignBit(~addend.last, inverted: true); + } + } +} + +/// A Partial Product Generator using Compact Rectangular Extension +class CompactRectSignExtension extends PartialProductSignExtension { + /// Sign extend the PP array using stop bits without adding a row + /// This routine works with different widths of multiplicand/multiplier, + /// an extension of Mohanty, B.K., Choubey designed by + /// Desmond A. Kirkpatrick. + CompactRectSignExtension( + super.ppg, { + super.signedMultiplicand = false, + super.signedMultiplier = false, + super.selectSignedMultiplicand, + super.selectSignedMultiplier, + }); + + @override + void signExtend() { + // These are in ppa + final rows = ppg.rows; + final rowShift = ppg.rowShift; + final partialProducts = ppg.partialProducts; + // should be in ppa + var isSignExtended = ppg.isSignExtended; + // Could override in ppa + final shift = ppg.shift; + final encoder = ppg.encoder; // signs getter + + // is multiplicand.width == entry.length? + // width=> multiplicand.width + shift - 1; + final selector = ppg.selector; // selector.width accessed + if (isSignExtended) { throw RohdHclException('Partial Product array already sign-extended'); } diff --git a/test/arithmetic/multiplier_encoder_test.dart b/test/arithmetic/multiplier_encoder_test.dart index 13570b83f..13b7ed828 100644 --- a/test/arithmetic/multiplier_encoder_test.dart +++ b/test/arithmetic/multiplier_encoder_test.dart @@ -472,6 +472,57 @@ void main() { expect(pp.evaluate(), equals(product)); }); + test('single MAC partial product sign extension test', () async { + final encoder = RadixEncoder(16); + const widthX = 8; + const widthY = 18; + + const i = 1478; + const j = 9; + const k = 0; + + final X = BigInt.from(i).toSigned(widthX); + final Y = BigInt.from(j).toSigned(widthY); + final Z = BigInt.from(k).toSigned(widthX + widthY); + // print('X=$X Y=$Y, Z=$Z'); + final product = X * Y + Z; + + final logicX = Logic(name: 'X', width: widthX); + final logicY = Logic(name: 'Y', width: widthY); + final logicZ = Logic(name: 'Z', width: widthX + widthY); + logicX.put(X); + logicY.put(Y); + logicZ.put(Z); + + final pp = PartialProductGeneratorCompactRectSignExtension( + logicX, logicY, encoder, + signedMultiplicand: true, signedMultiplier: true); + + final lastLength = + pp.partialProducts[pp.rows - 1].length + pp.rowShift[pp.rows - 1]; + + final sign = logicZ[logicZ.width - 1]; + // for unsigned versus signed testing + // final sign = signed ? logicZ[logicZ.width - 1] : Const(0); + final l = [for (var i = 0; i < logicZ.width; i++) logicZ[i]]; + while (l.length < lastLength) { + l.add(sign); + } + l + ..add(~sign) + ..add(Const(1)); + // print(pp.representation()); + + pp.partialProducts.insert(0, l); + pp.rowShift.insert(0, 0); + // print(pp.representation()); + + if (pp.evaluate() != product) { + stdout.write('Fail: $X * $Y: ${pp.evaluate()} vs expected $product\n'); + } + expect(pp.evaluate(), equals(product)); + }); + test('majority function', () async { expect(LogicValue.ofBigInt(BigInt.from(7), 5).majority(), true); expect(LogicValue.ofBigInt(BigInt.from(7) << 1, 5).majority(), true); From 86c49472caf40157662bc2eb945df1782d8cf14c Mon Sep 17 00:00:00 2001 From: Galileo Newton Date: Sat, 11 Jan 2025 10:37:16 -0800 Subject: [PATCH 02/14] wrapped sign extension works for all cases --- lib/src/arithmetic/multiplier.dart | 4 +- .../arithmetic/partial_product_generator.dart | 6 +- .../partial_product_sign_extend.dart | 623 +++++++++++++++--- test/arithmetic/addend_compressor_test.dart | 4 +- test/arithmetic/multiplier_encoder_test.dart | 12 +- test/arithmetic/multiplier_test.dart | 9 +- 6 files changed, 547 insertions(+), 111 deletions(-) diff --git a/lib/src/arithmetic/multiplier.dart b/lib/src/arithmetic/multiplier.dart index 88d903f16..b49eab26f 100644 --- a/lib/src/arithmetic/multiplier.dart +++ b/lib/src/arithmetic/multiplier.dart @@ -245,7 +245,7 @@ class CompressionTreeMultiplier extends Multiplier { required bool signedMultiplicand, Logic? selectSignedMultiplier, Logic? selectSignedMultiplicand}) - ppGen = PartialProductGeneratorCompactRectSignExtension.new, + ppGen = NewPartialProductGeneratorCompactRectSignExtension.new, super.name = 'compression_tree_multiplier'}) { clk = (clk != null) ? addInput('clk', clk!) : null; reset = (reset != null) ? addInput('reset', reset!) : null; @@ -341,7 +341,7 @@ class CompressionTreeMultiplyAccumulate extends MultiplyAccumulate { required bool signedMultiplicand, Logic? selectSignedMultiplier, Logic? selectSignedMultiplicand}) - ppGen = PartialProductGeneratorCompactRectSignExtension.new, + ppGen = NewPartialProductGeneratorCompactRectSignExtension.new, super.name = 'compression_tree_mac'}) { clk = (clk != null) ? addInput('clk', clk) : null; reset = (reset != null) ? addInput('reset', reset) : null; diff --git a/lib/src/arithmetic/partial_product_generator.dart b/lib/src/arithmetic/partial_product_generator.dart index 35b5a17ac..1c6556d7a 100644 --- a/lib/src/arithmetic/partial_product_generator.dart +++ b/lib/src/arithmetic/partial_product_generator.dart @@ -254,7 +254,6 @@ abstract class PartialProductGenerator extends PartialProductArray { 'or equal to ${selector.shift + (signedMultiplier ? 1 : 0)}'); } _build(); - // signExtend(); } /// Perform sign extension (defined in child classes) @@ -300,9 +299,10 @@ abstract class PartialProductGenerator extends PartialProductArray { } /// A Partial Product Generator with no sign extension -class PartialProductGeneratorNoneSignExtension extends PartialProductGenerator { +class OldPartialProductGeneratorNoneSignExtension + extends PartialProductGenerator { /// Construct a basic Partial Product Generator - PartialProductGeneratorNoneSignExtension( + OldPartialProductGeneratorNoneSignExtension( super.multiplicand, super.multiplier, super.radixEncoder, {super.signedMultiplicand, super.signedMultiplier, diff --git a/lib/src/arithmetic/partial_product_sign_extend.dart b/lib/src/arithmetic/partial_product_sign_extend.dart index a6c2aa4ae..30f68368b 100644 --- a/lib/src/arithmetic/partial_product_sign_extend.dart +++ b/lib/src/arithmetic/partial_product_sign_extend.dart @@ -41,24 +41,195 @@ typedef PPGFunction = PartialProductGenerator Function( /// Used to test different sign extension methods PPGFunction curryPartialProductGenerator(SignExtension signExtension) => switch (signExtension) { - SignExtension.none => PartialProductGeneratorNoneSignExtension.new, - SignExtension.brute => PartialProductGeneratorBruteSignExtension.new, + // SignExtension.none => + // NewPartialProductGeneratorNoneSignExtension.new, + // SignExtension.brute => + // NewPartialProductGeneratorBruteSignExtension.new, + // SignExtension.stopBits => + // NewPartialProductGeneratorStopBitsSignExtension.new, + // SignExtension.compact => + // NewPartialProductGeneratorCompactSignExtension.new, + // SignExtension.compactRect => + // NewPartialProductGeneratorCompactRectSignExtension.new, + SignExtension.none => NewPartialProductGeneratorNoneSignExtension.new, + SignExtension.brute => NewPartialProductGeneratorBruteSignExtension.new, SignExtension.stopBits => - PartialProductGeneratorStopBitsSignExtension.new, - SignExtension.compact => PartialProductGeneratorCompactSignExtension.new, + NewPartialProductGeneratorStopBitsSignExtension.new, + SignExtension.compact => + NewPartialProductGeneratorCompactSignExtension.new, SignExtension.compactRect => - PartialProductGeneratorCompactRectSignExtension.new, + NewPartialProductGeneratorCompactRectSignExtension.new, }; +/// API for sign extension classes +abstract class PartialProductSignExtension { + /// The partial product generator we are sign extending. + final PartialProductGenerator ppg; + + /// multiplicand operand is always signed. + final bool signedMultiplicand; + + /// multiplier operand is always signed. + final bool signedMultiplier; + + /// If not null, use this signal to select between signed and unsigned + /// multiplicand. + final Logic? selectSignedMultiplicand; + + /// If not null, use this signal to select between signed and unsigned + /// multiplier. + final Logic? selectSignedMultiplier; + + /// in PPA + int get rows => ppg.rows; + + /// in PPA + List get rowShift => ppg.rowShift; + + /// in PPA + List> get partialProducts => ppg.partialProducts; + + /// should be in ppa + bool get isSignExtended => ppg.isSignExtended; + set isSignExtended(bool set) { + ppg.isSignExtended = set; + } + + /// Could override in ppa + int get shift => ppg.shift; + + /// Need signs[] API instead + MultiplierEncoder get encoder => ppg.encoder; // signs getter + + // is multiplicand.width == entry.length? + // width=> multiplicand.width + shift - 1; + /// Only used to get width as above + MultiplicandSelector get selector => ppg.selector; // selector.width accessed + + /// Sign Extension class that operates on a [PartialProductGenerator] + /// and sign-extends the entries. + PartialProductSignExtension( + this.ppg, { + this.signedMultiplicand = false, + this.signedMultiplier = false, + this.selectSignedMultiplicand, + this.selectSignedMultiplier, + }) { + // + if (signedMultiplier && (selectSignedMultiplier != null)) { + throw RohdHclException('sign reconfiguration requires signed=false'); + } + if (signedMultiplicand && (selectSignedMultiplicand != null)) { + throw RohdHclException('multiplicand sign reconfiguration requires ' + 'signedMultiplicand=false'); + } + } + + /// Execute the sign extension, overridden to specialize. + void signExtend(); + + /// Helper function for sign extension routines: + /// For signed operands, set the MSB to [sign], otherwise add this [sign] bit. + void addStopSign(List addend, SignBit sign) { + if (!signedMultiplicand) { + addend.add(sign); + } else { + addend.last = sign; + } + } + + /// Helper function for sign extension routines: + /// For signed operands, flip the MSB, otherwise add this [sign] bit. + void addStopSignFlip(List addend, SignBit sign) { + if (!signedMultiplicand) { + if (selectSignedMultiplicand == null) { + addend.add(sign); + } else { + addend.add(SignBit(mux(selectSignedMultiplicand!, ~addend.last, sign), + inverted: selectSignedMultiplicand != null)); + } + } else { + addend.last = SignBit(~addend.last, inverted: true); + } + } +} + +/// Used to test different sign extension methods +typedef SignExtensionFunction = PartialProductSignExtension Function( + PartialProductGenerator ppg, + {bool signedMultiplicand, + bool signedMultiplier, + Logic? selectSignedMultiplicand, + Logic? selectSignedMultiplier}); + +/// Used to test different sign extension methods +SignExtensionFunction currysignExtensionFunction(SignExtension signExtension) => + switch (signExtension) { + SignExtension.none => NoneSignExtension.new, + SignExtension.brute => BruteSignExtension.new, + SignExtension.stopBits => StopBitsSignExtension.new, + SignExtension.compact => CompactSignExtension.new, + SignExtension.compactRect => CompactRectSignExtension.new, + }; + +/// These other sign extensions are for assisting with testing and debugging. +/// More robust and simpler sign extensions in case +/// complex sign extension routines obscure other bugs. +/// +/// /// A Partial Product Generator using None Sign Extension +class NoneSignExtension extends PartialProductSignExtension { + /// Construct a no sign-extension class. + NoneSignExtension( + super.ppg, { + super.signedMultiplicand = false, + super.signedMultiplier = false, + super.selectSignedMultiplicand, + super.selectSignedMultiplier, + }); + + /// Fully sign extend the PP array: useful for reference only + @override + void signExtend() {} +} + +/// A wrapper class for [NoneSignExtension] we used +/// during refactoring to be compatible with old calls. +class NewPartialProductGeneratorNoneSignExtension + extends PartialProductGenerator { + /// The extension routine we will be using. + late final PartialProductSignExtension extender; + + /// Construct a none sign extending Partial Product Generator + NewPartialProductGeneratorNoneSignExtension( + super.multiplicand, super.multiplier, super.radixEncoder, + {super.signedMultiplicand, + super.signedMultiplier, + super.selectSignedMultiplicand, + super.selectSignedMultiplier, + super.name = 'none'}) { + extender = BruteSignExtension(this, + signedMultiplicand: signedMultiplicand, + signedMultiplier: signedMultiplier, + selectSignedMultiplicand: selectSignedMultiplicand, + selectSignedMultiplier: selectSignedMultiplier); + signExtend(); + } + + @override + void signExtend() { + extender.signExtend(); + } +} + /// These other sign extensions are for assisting with testing and debugging. /// More robust and simpler sign extensions in case /// complex sign extension routines obscure other bugs. /// A Partial Product Generator using Brute Sign Extension -class PartialProductGeneratorBruteSignExtension +class OldPartialProductGeneratorBruteSignExtension extends PartialProductGenerator { /// Construct a brute-force sign extending Partial Product Generator - PartialProductGeneratorBruteSignExtension( + OldPartialProductGeneratorBruteSignExtension( super.multiplicand, super.multiplier, super.radixEncoder, {super.signedMultiplicand, super.signedMultiplier, @@ -103,11 +274,86 @@ class PartialProductGeneratorBruteSignExtension } } +/// A Brute Sign Extension class. +class BruteSignExtension extends PartialProductSignExtension { + /// Construct a brute-force sign extending Partial Product Generator + BruteSignExtension( + super.ppg, { + super.signedMultiplicand = false, + super.signedMultiplier = false, + super.selectSignedMultiplicand, + super.selectSignedMultiplier, + }); + + /// Fully sign extend the PP array: useful for reference only + @override + void signExtend() { + if (signedMultiplicand && (selectSignedMultiplicand != null)) { + throw RohdHclException('multiplicand sign reconfiguration requires ' + 'signedMultiplicand=false'); + } + if (isSignExtended) { + throw RohdHclException('Partial Product array already sign-extended'); + } + isSignExtended = true; + final signs = [for (var r = 0; r < rows; r++) encoder.getEncoding(r).sign]; + for (var row = 0; row < rows; row++) { + final addend = partialProducts[row]; + final Logic sign; + if (selectSignedMultiplicand != null) { + sign = mux(selectSignedMultiplicand!, addend.last, signs[row]); + } else { + sign = signedMultiplicand ? addend.last : signs[row]; + } + addend.addAll(List.filled((rows - row) * shift, SignBit(sign))); + if (row > 0) { + addend + ..insertAll(0, List.filled(shift - 1, Const(0))) + ..insert(0, SignBit(signs[row - 1])); + rowShift[row] -= shift; + } + } + // Insert carry bit in extra row + partialProducts.add(List.generate(selector.width, (i) => Const(0))); + partialProducts.last.insert(0, SignBit(signs[rows - 2])); + rowShift.add((rows - 2) * shift); + } +} + +/// A wrapper class for [BruteSignExtension] we used +/// during refactoring to be compatible with old calls. +class NewPartialProductGeneratorBruteSignExtension + extends PartialProductGenerator { + /// The extension routine we will be using. + late final PartialProductSignExtension extender; + + /// Construct a compact rect sign extending Partial Product Generator + NewPartialProductGeneratorBruteSignExtension( + super.multiplicand, super.multiplier, super.radixEncoder, + {super.signedMultiplicand, + super.signedMultiplier, + super.selectSignedMultiplicand, + super.selectSignedMultiplier, + super.name = 'brute'}) { + extender = BruteSignExtension(this, + signedMultiplicand: signedMultiplicand, + signedMultiplier: signedMultiplier, + selectSignedMultiplicand: selectSignedMultiplicand, + selectSignedMultiplier: selectSignedMultiplier); + signExtend(); + } + + @override + void signExtend() { + extender.signExtend(); + } +} + /// A Partial Product Generator using Brute Sign Extension -class PartialProductGeneratorCompactSignExtension +class OldPartialProductGeneratorCompactSignExtension extends PartialProductGenerator { /// Construct a compact sign extending Partial Product Generator - PartialProductGeneratorCompactSignExtension( + OldPartialProductGeneratorCompactSignExtension( super.multiplicand, super.multiplier, super.radixEncoder, {super.signedMultiplicand, super.selectSignedMultiplicand, @@ -230,11 +476,163 @@ class PartialProductGeneratorCompactSignExtension } } +/// A Compact Sign Extension class. +class CompactSignExtension extends PartialProductSignExtension { + /// Construct a compact sign extendsion class. + CompactSignExtension( + super.ppg, { + super.signedMultiplicand = false, + super.signedMultiplier = false, + super.selectSignedMultiplicand, + super.selectSignedMultiplier, + }); + + @override + void signExtend() { + // An implementation of + // Mohanty, B.K., Choubey, A. Efficient Design for Radix-8 Booth Multiplier + // and Its Application in Lifting 2-D DWT. Circuits Syst Signal Process 36, + // 1129–1149 (2017). https://doi.org/10.1007/s00034-016-0349-9 + if (signedMultiplicand && (selectSignedMultiplicand != null)) { + throw RohdHclException('multiplicand sign reconfiguration requires ' + 'signedMultiplicand=false'); + } + if (isSignExtended) { + throw RohdHclException('Partial Product array already sign-extended'); + } + isSignExtended = true; + + final lastRow = rows - 1; + final firstAddend = partialProducts[0]; + final lastAddend = partialProducts[lastRow]; + + final firstRowQStart = selector.width - (signedMultiplicand ? 1 : 0); + final lastRowSignPos = shift * lastRow; + final alignRow0Sign = firstRowQStart - lastRowSignPos; + + final signs = [for (var r = 0; r < rows; r++) encoder.getEncoding(r).sign]; + + final propagate = + List.generate(rows, (i) => List.filled(0, Logic(), growable: true)); + + for (var row = 0; row < rows; row++) { + propagate[row].add(signs[row]); + for (var col = 0; col < 2 * (shift - 1); col++) { + propagate[row].add(partialProducts[row][col]); + } + // Last row has extend sign propagation to Q start + if (row == lastRow) { + var col = 2 * (shift - 1); + while (propagate[lastRow].length <= alignRow0Sign) { + propagate[lastRow].add(SignBit(partialProducts[row][col++])); + } + } + for (var col = 1; col < propagate[row].length; col++) { + propagate[row][col] = propagate[row][col] & propagate[row][col - 1]; + } + } + final m = + List.generate(rows, (i) => List.filled(0, Logic(), growable: true)); + for (var row = 0; row < rows; row++) { + for (var c = 0; c < shift - 1; c++) { + m[row].add(partialProducts[row][c] ^ propagate[row][c]); + } + m[row].addAll(List.filled(shift - 1, Logic())); + } + while (m[lastRow].length < alignRow0Sign) { + m[lastRow].add(Logic()); + } + + for (var i = shift - 1; i < m[lastRow].length; i++) { + m[lastRow][i] = lastAddend[i] ^ + (i < alignRow0Sign ? propagate[lastRow][i] : Const(0)); + } + + final remainders = List.filled(rows, Logic()); + for (var row = 0; row < lastRow; row++) { + remainders[row] = propagate[row][shift - 1]; + } + remainders[lastRow] <= propagate[lastRow][max(alignRow0Sign, 0)]; + + // Compute Sign extension for row==0 + final Logic firstSign; + if (selectSignedMultiplicand == null) { + firstSign = + signedMultiplicand ? SignBit(firstAddend.last) : SignBit(signs[0]); + } else { + firstSign = + SignBit(mux(selectSignedMultiplicand!, firstAddend.last, signs[0])); + } + final q = [ + firstSign ^ remainders[lastRow], + ~(firstSign & ~remainders[lastRow]), + ]; + q.insertAll(1, List.filled(shift - 1, ~q[1])); + + for (var row = 0; row < rows; row++) { + final addend = partialProducts[row]; + if (row > 0) { + final mLimit = (row == lastRow) ? alignRow0Sign : shift - 1; + for (var i = 0; i < mLimit; i++) { + addend[i] = m[row][i]; + } + addStopSignFlip(addend, SignBit(~signs[row], inverted: true)); + addend + ..insert(0, remainders[row - 1]) + ..addAll(List.filled(shift - 1, Const(1))); + rowShift[row] -= 1; + } else { + for (var i = 0; i < shift - 1; i++) { + firstAddend[i] = m[0][i]; + } + if (!signedMultiplicand) { + firstAddend.add(q[0]); + } else { + firstAddend.last = q[0]; + } + firstAddend.addAll(q.getRange(1, q.length)); + } + } + if (shift == 1) { + lastAddend.add(Const(1)); + } + } +} + +/// A wrapper class for [CompactSignExtension] we used +/// during refactoring to be compatible with old calls. +class NewPartialProductGeneratorCompactSignExtension + extends PartialProductGenerator { + /// The extension routine we will be using. + late final PartialProductSignExtension extender; + + /// Construct a compact sign extending Partial Product Generator + NewPartialProductGeneratorCompactSignExtension( + super.multiplicand, super.multiplier, super.radixEncoder, + {super.signedMultiplicand, + super.signedMultiplier, + super.selectSignedMultiplicand, + super.selectSignedMultiplier, + super.name = 'compact'}) { + extender = CompactSignExtension(this, + signedMultiplicand: signedMultiplicand, + signedMultiplier: signedMultiplier, + selectSignedMultiplicand: selectSignedMultiplicand, + selectSignedMultiplier: selectSignedMultiplier); + signExtend(); + } + + @override + void signExtend() { + extender.signExtend(); + } +} + /// A Partial Product Generator using Brute Sign Extension -class PartialProductGeneratorStopBitsSignExtension +class OldPartialProductGeneratorStopBitsSignExtension extends PartialProductGenerator { /// Construct a stop bits sign extending Partial Product Generator - PartialProductGeneratorStopBitsSignExtension( + OldPartialProductGeneratorStopBitsSignExtension( super.multiplicand, super.multiplier, super.radixEncoder, {super.signedMultiplicand, super.selectSignedMultiplicand, @@ -320,6 +718,124 @@ class PartialProductGeneratorStopBitsSignExtension } } +/// A StopBits Sign Extension. +class StopBitsSignExtension extends PartialProductSignExtension { + /// Construct a stop bits sign extendsion class. + StopBitsSignExtension( + super.ppg, { + super.signedMultiplicand = false, + super.signedMultiplier = false, + super.selectSignedMultiplicand, + super.selectSignedMultiplier, + }); + + /// Sign extend the PP array using stop bits. + /// If possible, fold the final carry into another row (only when rectangular + /// enough that carry bit lands outside another row). + /// This technique can then be combined with a first-row extension technique + /// for folding in the final carry. + /// + @override + void signExtend() { + if (signedMultiplicand && (selectSignedMultiplicand != null)) { + throw RohdHclException('multiplicand sign reconfiguration requires ' + 'signedMultiplicand=false'); + } + if (isSignExtended) { + throw RohdHclException('Partial Product array already sign-extended'); + } + isSignExtended = true; + + final finalCarryPos = shift * (rows - 1); + final finalCarryRelPos = finalCarryPos - selector.width - shift; + final finalCarryRow = + ((encoder.multiplier.width > selector.multiplicand.width) && + (finalCarryRelPos > 0)) + ? (finalCarryRelPos / shift).floor() + : 0; + + final signs = [for (var r = 0; r < rows; r++) encoder.getEncoding(r).sign]; + + for (var row = 0; row < rows; row++) { + final addend = partialProducts[row]; + final Logic sign; + if (selectSignedMultiplicand != null) { + sign = mux(selectSignedMultiplicand!, addend.last, signs[row]); + } else { + sign = signedMultiplicand ? addend.last : signs[row]; + } + if (row == 0) { + if (!signedMultiplicand) { + addend.addAll(List.filled(shift, SignBit(sign))); + } else { + // either is signed? + addend.addAll(List.filled(shift - 1, SignBit(sign))); // signed only? + } + addend.add(SignBit(~sign, inverted: true)); + } else { + addStopSign(addend, SignBit(~sign, inverted: true)); + addend + ..addAll(List.filled(shift - 1, Const(1))) + ..insertAll(0, List.filled(shift - 1, Const(0))) + ..insert(0, SignBit(signs[row - 1])); + rowShift[row] -= shift; + } + } + + if (finalCarryRow > 0) { + final extensionRow = partialProducts[finalCarryRow]; + extensionRow + ..addAll(List.filled( + finalCarryPos - (extensionRow.length + rowShift[finalCarryRow]), + Const(0))) + ..add(SignBit(signs[rows - 1])); + } else if (signedMultiplier | (selectSignedMultiplier != null)) { + // Create an extra row to hold the final carry bit + partialProducts + .add(List.filled(selector.width, Const(0), growable: true)); + partialProducts.last.insert(0, SignBit(signs[rows - 2])); + rowShift.add((rows - 2) * shift); + + // Hack for radix-2 + if (shift == 1) { + addStopSignFlip( + partialProducts.last, SignBit(Const(1), inverted: true)); + } + } + } +} + +// + +/// A wrapper class for [StopBitsSignExtension] we used +/// during refactoring to be compatible with old calls. +class NewPartialProductGeneratorStopBitsSignExtension + extends PartialProductGenerator { + /// The extension routine we will be using. + late final PartialProductSignExtension extender; + + /// Construct a stop bits sign extending Partial Product Generator + NewPartialProductGeneratorStopBitsSignExtension( + super.multiplicand, super.multiplier, super.radixEncoder, + {super.signedMultiplicand, + super.signedMultiplier, + super.selectSignedMultiplicand, + super.selectSignedMultiplier, + super.name = 'stop_bits'}) { + extender = StopBitsSignExtension(this, + signedMultiplicand: signedMultiplicand, + signedMultiplier: signedMultiplier, + selectSignedMultiplicand: selectSignedMultiplicand, + selectSignedMultiplier: selectSignedMultiplier); + signExtend(); + } + + @override + void signExtend() { + extender.signExtend(); + } +} + /// A Partial Product Generator using Compact Rectangular Extension class OldPartialProductGeneratorCompactRectSignExtension extends PartialProductGenerator { @@ -480,13 +996,13 @@ class OldPartialProductGeneratorCompactRectSignExtension /// A wrapper class for CompactRectSignExtension we used /// during refactoring to be compatible with old calls. -class PartialProductGeneratorCompactRectSignExtension +class NewPartialProductGeneratorCompactRectSignExtension extends PartialProductGenerator { /// The extension routine we will be using. late final PartialProductSignExtension extender; /// Construct a compact rect sign extending Partial Product Generator - PartialProductGeneratorCompactRectSignExtension( + NewPartialProductGeneratorCompactRectSignExtension( super.multiplicand, super.multiplier, super.radixEncoder, {super.signedMultiplicand, super.signedMultiplier, @@ -507,73 +1023,6 @@ class PartialProductGeneratorCompactRectSignExtension } } -/// API for sign extension classes -abstract class PartialProductSignExtension { - /// The partial product generator we are sign extending. - late final PartialProductGenerator ppg; - - /// multiplicand operand is always signed. - final bool signedMultiplicand; - - /// multiplier operand is always signed. - final bool signedMultiplier; - - /// If not null, use this signal to select between signed and unsigned - /// multiplicand. - final Logic? selectSignedMultiplicand; - - /// If not null, use this signal to select between signed and unsigned - /// multiplier. - final Logic? selectSignedMultiplier; - - /// Sign Extension class that operates on a [PartialProductGenerator] - /// and sign-extends the entries. - PartialProductSignExtension( - this.ppg, { - this.signedMultiplicand = false, - this.signedMultiplier = false, - this.selectSignedMultiplicand, - this.selectSignedMultiplier, - }) { - // - if (signedMultiplier && (selectSignedMultiplier != null)) { - throw RohdHclException('sign reconfiguration requires signed=false'); - } - if (signedMultiplicand && (selectSignedMultiplicand != null)) { - throw RohdHclException('multiplicand sign reconfiguration requires ' - 'signedMultiplicand=false'); - } - } - - /// Execute the sign extension, overridden to specialize. - void signExtend(); - - /// Helper function for sign extension routines: - /// For signed operands, set the MSB to [sign], otherwise add this [sign] bit. - void addStopSign(List addend, SignBit sign) { - if (!signedMultiplicand) { - addend.add(sign); - } else { - addend.last = sign; - } - } - - /// Helper function for sign extension routines: - /// For signed operands, flip the MSB, otherwise add this [sign] bit. - void addStopSignFlip(List addend, SignBit sign) { - if (!signedMultiplicand) { - if (selectSignedMultiplicand == null) { - addend.add(sign); - } else { - addend.add(SignBit(mux(selectSignedMultiplicand!, ~addend.last, sign), - inverted: selectSignedMultiplicand != null)); - } - } else { - addend.last = SignBit(~addend.last, inverted: true); - } - } -} - /// A Partial Product Generator using Compact Rectangular Extension class CompactRectSignExtension extends PartialProductSignExtension { /// Sign extend the PP array using stop bits without adding a row @@ -590,20 +1039,6 @@ class CompactRectSignExtension extends PartialProductSignExtension { @override void signExtend() { - // These are in ppa - final rows = ppg.rows; - final rowShift = ppg.rowShift; - final partialProducts = ppg.partialProducts; - // should be in ppa - var isSignExtended = ppg.isSignExtended; - // Could override in ppa - final shift = ppg.shift; - final encoder = ppg.encoder; // signs getter - - // is multiplicand.width == entry.length? - // width=> multiplicand.width + shift - 1; - final selector = ppg.selector; // selector.width accessed - if (isSignExtended) { throw RohdHclException('Partial Product array already sign-extended'); } diff --git a/test/arithmetic/addend_compressor_test.dart b/test/arithmetic/addend_compressor_test.dart index d479e940f..becf72b6c 100644 --- a/test/arithmetic/addend_compressor_test.dart +++ b/test/arithmetic/addend_compressor_test.dart @@ -36,7 +36,7 @@ class CompressorTestMod extends Module { clk = addInput('clk', iclk); } - pp = PartialProductGeneratorCompactRectSignExtension(a, b, encoder, + pp = NewPartialProductGeneratorCompactRectSignExtension(a, b, encoder, signedMultiplicand: signed, signedMultiplier: signed); compressor = ColumnCompressor(pp, clk: clk); compressor.compress(); @@ -111,7 +111,7 @@ void main() { selectSignedMultiplicand!.put(signed ? 1 : 0); selectSignedMultiplier!.put(signed ? 1 : 0); } - final pp = PartialProductGeneratorCompactRectSignExtension( + final pp = NewPartialProductGeneratorCompactRectSignExtension( a, b, encoder, signedMultiplicand: !useSelect & signed, signedMultiplier: !useSelect & signed, diff --git a/test/arithmetic/multiplier_encoder_test.dart b/test/arithmetic/multiplier_encoder_test.dart index 13b7ed828..637e6a6b6 100644 --- a/test/arithmetic/multiplier_encoder_test.dart +++ b/test/arithmetic/multiplier_encoder_test.dart @@ -197,7 +197,7 @@ void main() { a.put(X); b.put(Y); final PartialProductGenerator pp; - pp = PartialProductGeneratorStopBitsSignExtension(a, b, encoder, + pp = OldPartialProductGeneratorStopBitsSignExtension(a, b, encoder, signedMultiplicand: signedMultiplicand, signedMultiplier: signedMultiplier); testPartialProductSingle(pp, X, Y); @@ -256,7 +256,7 @@ void main() { selectSignMultiplicand.put(selectMultiplicand ? 1 : 0); selectSignMultiplier.put(selectMultiplier ? 1 : 0); final PartialProductGenerator pp; - pp = PartialProductGeneratorStopBitsSignExtension( + pp = OldPartialProductGeneratorStopBitsSignExtension( Logic(name: 'X', width: width), Logic(name: 'Y', width: width), encoder, @@ -385,7 +385,7 @@ void main() { final skew = align.$3; - final pp = PartialProductGeneratorCompactRectSignExtension( + final pp = NewPartialProductGeneratorCompactRectSignExtension( Logic(name: 'X', width: width), Logic(name: 'Y', width: width + skew), encoder); @@ -405,7 +405,7 @@ void main() { final multiplicand = Logic(width: widthX); final multiplier = Logic(width: widthY); for (final signed in [false, true]) { - final pp = PartialProductGeneratorCompactSignExtension( + final pp = OldPartialProductGeneratorCompactSignExtension( multiplicand, multiplier, radixEncoder, signedMultiplicand: signed, signedMultiplier: signed); for (var i = BigInt.zero; i < BigInt.from(limitX); i += BigInt.one) { @@ -443,7 +443,7 @@ void main() { logicX.put(X); logicY.put(Y); logicZ.put(Z); - final pp = PartialProductGeneratorCompactRectSignExtension( + final pp = NewPartialProductGeneratorCompactRectSignExtension( logicX, logicY, encoder, signedMultiplicand: true, signedMultiplier: true); @@ -494,7 +494,7 @@ void main() { logicY.put(Y); logicZ.put(Z); - final pp = PartialProductGeneratorCompactRectSignExtension( + final pp = NewPartialProductGeneratorCompactRectSignExtension( logicX, logicY, encoder, signedMultiplicand: true, signedMultiplier: true); diff --git a/test/arithmetic/multiplier_test.dart b/test/arithmetic/multiplier_test.dart index 629804bfe..a36e286ed 100644 --- a/test/arithmetic/multiplier_test.dart +++ b/test/arithmetic/multiplier_test.dart @@ -188,7 +188,8 @@ void main() { MultiplierCallback curryCompressionTreeMultiplier(int radix, ParallelPrefix Function(List, Logic Function(Logic, Logic)) ppTree, - {PPGFunction ppGen = PartialProductGeneratorCompactRectSignExtension.new, + {PPGFunction ppGen = + NewPartialProductGeneratorCompactRectSignExtension.new, bool signedMultiplicand = false, bool signedMultiplier = false, Logic? selectSignedMultiplicand, @@ -225,7 +226,7 @@ void main() { {ParallelPrefix Function(List, Logic Function(Logic, Logic)) ppTree = KoggeStone.new, PPGFunction ppGen = - PartialProductGeneratorCompactRectSignExtension.new, + NewPartialProductGeneratorCompactRectSignExtension.new, bool signedMultiplicand = false, bool signedMultiplier = false, Logic? selectSignedMultiplicand, @@ -252,7 +253,7 @@ void main() { int radix, { ParallelPrefix Function(List, Logic Function(Logic, Logic)) ppTree = KoggeStone.new, - PPGFunction ppGen = PartialProductGeneratorCompactRectSignExtension.new, + PPGFunction ppGen = NewPartialProductGeneratorCompactRectSignExtension.new, bool signedMultiplicand = false, bool signedMultiplier = false, bool signedAddend = false, @@ -617,7 +618,7 @@ void main() { a.put(6); b.put(3); - final ppG0 = PartialProductGeneratorCompactRectSignExtension( + final ppG0 = NewPartialProductGeneratorCompactRectSignExtension( a, b, RadixEncoder(4), signedMultiplicand: true, signedMultiplier: true); From 39c4f95a584ee070249177c71ae98124a8427867 Mon Sep 17 00:00:00 2001 From: Galileo Newton Date: Sat, 11 Jan 2025 10:55:38 -0800 Subject: [PATCH 03/14] old sign extenders work --- .../arithmetic/partial_product_sign_extend.dart | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/src/arithmetic/partial_product_sign_extend.dart b/lib/src/arithmetic/partial_product_sign_extend.dart index 30f68368b..8fea773d1 100644 --- a/lib/src/arithmetic/partial_product_sign_extend.dart +++ b/lib/src/arithmetic/partial_product_sign_extend.dart @@ -41,6 +41,14 @@ typedef PPGFunction = PartialProductGenerator Function( /// Used to test different sign extension methods PPGFunction curryPartialProductGenerator(SignExtension signExtension) => switch (signExtension) { + SignExtension.none => OldPartialProductGeneratorNoneSignExtension.new, + SignExtension.brute => OldPartialProductGeneratorBruteSignExtension.new, + SignExtension.stopBits => + OldPartialProductGeneratorStopBitsSignExtension.new, + SignExtension.compact => + OldPartialProductGeneratorCompactSignExtension.new, + SignExtension.compactRect => + OldPartialProductGeneratorCompactRectSignExtension.new, // SignExtension.none => // NewPartialProductGeneratorNoneSignExtension.new, // SignExtension.brute => @@ -51,14 +59,6 @@ PPGFunction curryPartialProductGenerator(SignExtension signExtension) => // NewPartialProductGeneratorCompactSignExtension.new, // SignExtension.compactRect => // NewPartialProductGeneratorCompactRectSignExtension.new, - SignExtension.none => NewPartialProductGeneratorNoneSignExtension.new, - SignExtension.brute => NewPartialProductGeneratorBruteSignExtension.new, - SignExtension.stopBits => - NewPartialProductGeneratorStopBitsSignExtension.new, - SignExtension.compact => - NewPartialProductGeneratorCompactSignExtension.new, - SignExtension.compactRect => - NewPartialProductGeneratorCompactRectSignExtension.new, }; /// API for sign extension classes From 54a12d576f597507fc980f789bd42c1aa8e17551 Mon Sep 17 00:00:00 2001 From: Galileo Newton Date: Sat, 11 Jan 2025 11:02:13 -0800 Subject: [PATCH 04/14] converted all to new wrappers for sign extension --- .../arithmetic/partial_product_generator.dart | 15 - .../partial_product_sign_extend.dart | 444 +----------------- test/arithmetic/multiplier_encoder_test.dart | 6 +- 3 files changed, 8 insertions(+), 457 deletions(-) diff --git a/lib/src/arithmetic/partial_product_generator.dart b/lib/src/arithmetic/partial_product_generator.dart index 1c6556d7a..36da41fa2 100644 --- a/lib/src/arithmetic/partial_product_generator.dart +++ b/lib/src/arithmetic/partial_product_generator.dart @@ -297,18 +297,3 @@ abstract class PartialProductGenerator extends PartialProductArray { } } } - -/// A Partial Product Generator with no sign extension -class OldPartialProductGeneratorNoneSignExtension - extends PartialProductGenerator { - /// Construct a basic Partial Product Generator - OldPartialProductGeneratorNoneSignExtension( - super.multiplicand, super.multiplier, super.radixEncoder, - {super.signedMultiplicand, - super.signedMultiplier, - super.selectSignedMultiplicand, - super.selectSignedMultiplier}); - - @override - void signExtend() {} -} diff --git a/lib/src/arithmetic/partial_product_sign_extend.dart b/lib/src/arithmetic/partial_product_sign_extend.dart index 8fea773d1..986d90fdf 100644 --- a/lib/src/arithmetic/partial_product_sign_extend.dart +++ b/lib/src/arithmetic/partial_product_sign_extend.dart @@ -41,24 +41,14 @@ typedef PPGFunction = PartialProductGenerator Function( /// Used to test different sign extension methods PPGFunction curryPartialProductGenerator(SignExtension signExtension) => switch (signExtension) { - SignExtension.none => OldPartialProductGeneratorNoneSignExtension.new, - SignExtension.brute => OldPartialProductGeneratorBruteSignExtension.new, + SignExtension.none => NewPartialProductGeneratorNoneSignExtension.new, + SignExtension.brute => NewPartialProductGeneratorBruteSignExtension.new, SignExtension.stopBits => - OldPartialProductGeneratorStopBitsSignExtension.new, + NewPartialProductGeneratorStopBitsSignExtension.new, SignExtension.compact => - OldPartialProductGeneratorCompactSignExtension.new, + NewPartialProductGeneratorCompactSignExtension.new, SignExtension.compactRect => - OldPartialProductGeneratorCompactRectSignExtension.new, - // SignExtension.none => - // NewPartialProductGeneratorNoneSignExtension.new, - // SignExtension.brute => - // NewPartialProductGeneratorBruteSignExtension.new, - // SignExtension.stopBits => - // NewPartialProductGeneratorStopBitsSignExtension.new, - // SignExtension.compact => - // NewPartialProductGeneratorCompactSignExtension.new, - // SignExtension.compactRect => - // NewPartialProductGeneratorCompactRectSignExtension.new, + NewPartialProductGeneratorCompactRectSignExtension.new, }; /// API for sign extension classes @@ -225,55 +215,6 @@ class NewPartialProductGeneratorNoneSignExtension /// More robust and simpler sign extensions in case /// complex sign extension routines obscure other bugs. -/// A Partial Product Generator using Brute Sign Extension -class OldPartialProductGeneratorBruteSignExtension - extends PartialProductGenerator { - /// Construct a brute-force sign extending Partial Product Generator - OldPartialProductGeneratorBruteSignExtension( - super.multiplicand, super.multiplier, super.radixEncoder, - {super.signedMultiplicand, - super.signedMultiplier, - super.selectSignedMultiplicand, - super.selectSignedMultiplier, - super.name = 'brute'}) { - signExtend(); - } - - /// Fully sign extend the PP array: useful for reference only - @override - void signExtend() { - if (signedMultiplicand && (selectSignedMultiplicand != null)) { - throw RohdHclException('multiplicand sign reconfiguration requires ' - 'signedMultiplicand=false'); - } - if (isSignExtended) { - throw RohdHclException('Partial Product array already sign-extended'); - } - isSignExtended = true; - final signs = [for (var r = 0; r < rows; r++) encoder.getEncoding(r).sign]; - for (var row = 0; row < rows; row++) { - final addend = partialProducts[row]; - final Logic sign; - if (selectSignedMultiplicand != null) { - sign = mux(selectSignedMultiplicand!, addend.last, signs[row]); - } else { - sign = signedMultiplicand ? addend.last : signs[row]; - } - addend.addAll(List.filled((rows - row) * shift, SignBit(sign))); - if (row > 0) { - addend - ..insertAll(0, List.filled(shift - 1, Const(0))) - ..insert(0, SignBit(signs[row - 1])); - rowShift[row] -= shift; - } - } - // Insert carry bit in extra row - partialProducts.add(List.generate(selector.width, (i) => Const(0))); - partialProducts.last.insert(0, SignBit(signs[rows - 2])); - rowShift.add((rows - 2) * shift); - } -} - /// A Brute Sign Extension class. class BruteSignExtension extends PartialProductSignExtension { /// Construct a brute-force sign extending Partial Product Generator @@ -349,133 +290,6 @@ class NewPartialProductGeneratorBruteSignExtension } } -/// A Partial Product Generator using Brute Sign Extension -class OldPartialProductGeneratorCompactSignExtension - extends PartialProductGenerator { - /// Construct a compact sign extending Partial Product Generator - OldPartialProductGeneratorCompactSignExtension( - super.multiplicand, super.multiplier, super.radixEncoder, - {super.signedMultiplicand, - super.selectSignedMultiplicand, - super.signedMultiplier, - super.selectSignedMultiplier, - super.name = 'compact'}) { - signExtend(); - } - - /// Sign extend the PP array using stop bits without adding a row. - @override - void signExtend() { - // An implementation of - // Mohanty, B.K., Choubey, A. Efficient Design for Radix-8 Booth Multiplier - // and Its Application in Lifting 2-D DWT. Circuits Syst Signal Process 36, - // 1129–1149 (2017). https://doi.org/10.1007/s00034-016-0349-9 - if (signedMultiplicand && (selectSignedMultiplicand != null)) { - throw RohdHclException('multiplicand sign reconfiguration requires ' - 'signedMultiplicand=false'); - } - if (isSignExtended) { - throw RohdHclException('Partial Product array already sign-extended'); - } - isSignExtended = true; - - final lastRow = rows - 1; - final firstAddend = partialProducts[0]; - final lastAddend = partialProducts[lastRow]; - - final firstRowQStart = selector.width - (signedMultiplicand ? 1 : 0); - final lastRowSignPos = shift * lastRow; - final alignRow0Sign = firstRowQStart - lastRowSignPos; - - final signs = [for (var r = 0; r < rows; r++) encoder.getEncoding(r).sign]; - - final propagate = - List.generate(rows, (i) => List.filled(0, Logic(), growable: true)); - - for (var row = 0; row < rows; row++) { - propagate[row].add(signs[row]); - for (var col = 0; col < 2 * (shift - 1); col++) { - propagate[row].add(partialProducts[row][col]); - } - // Last row has extend sign propagation to Q start - if (row == lastRow) { - var col = 2 * (shift - 1); - while (propagate[lastRow].length <= alignRow0Sign) { - propagate[lastRow].add(SignBit(partialProducts[row][col++])); - } - } - for (var col = 1; col < propagate[row].length; col++) { - propagate[row][col] = propagate[row][col] & propagate[row][col - 1]; - } - } - final m = - List.generate(rows, (i) => List.filled(0, Logic(), growable: true)); - for (var row = 0; row < rows; row++) { - for (var c = 0; c < shift - 1; c++) { - m[row].add(partialProducts[row][c] ^ propagate[row][c]); - } - m[row].addAll(List.filled(shift - 1, Logic())); - } - while (m[lastRow].length < alignRow0Sign) { - m[lastRow].add(Logic()); - } - - for (var i = shift - 1; i < m[lastRow].length; i++) { - m[lastRow][i] = lastAddend[i] ^ - (i < alignRow0Sign ? propagate[lastRow][i] : Const(0)); - } - - final remainders = List.filled(rows, Logic()); - for (var row = 0; row < lastRow; row++) { - remainders[row] = propagate[row][shift - 1]; - } - remainders[lastRow] <= propagate[lastRow][max(alignRow0Sign, 0)]; - - // Compute Sign extension for row==0 - final Logic firstSign; - if (selectSignedMultiplicand == null) { - firstSign = - signedMultiplicand ? SignBit(firstAddend.last) : SignBit(signs[0]); - } else { - firstSign = - SignBit(mux(selectSignedMultiplicand!, firstAddend.last, signs[0])); - } - final q = [ - firstSign ^ remainders[lastRow], - ~(firstSign & ~remainders[lastRow]), - ]; - q.insertAll(1, List.filled(shift - 1, ~q[1])); - - for (var row = 0; row < rows; row++) { - final addend = partialProducts[row]; - if (row > 0) { - final mLimit = (row == lastRow) ? alignRow0Sign : shift - 1; - for (var i = 0; i < mLimit; i++) { - addend[i] = m[row][i]; - } - addStopSignFlip(addend, SignBit(~signs[row], inverted: true)); - addend - ..insert(0, remainders[row - 1]) - ..addAll(List.filled(shift - 1, Const(1))); - rowShift[row] -= 1; - } else { - for (var i = 0; i < shift - 1; i++) { - firstAddend[i] = m[0][i]; - } - if (!signedMultiplicand) { - firstAddend.add(q[0]); - } else { - firstAddend.last = q[0]; - } - firstAddend.addAll(q.getRange(1, q.length)); - } - } - if (shift == 1) { - lastAddend.add(Const(1)); - } - } -} - /// A Compact Sign Extension class. class CompactSignExtension extends PartialProductSignExtension { /// Construct a compact sign extendsion class. @@ -628,96 +442,6 @@ class NewPartialProductGeneratorCompactSignExtension } } -/// A Partial Product Generator using Brute Sign Extension -class OldPartialProductGeneratorStopBitsSignExtension - extends PartialProductGenerator { - /// Construct a stop bits sign extending Partial Product Generator - OldPartialProductGeneratorStopBitsSignExtension( - super.multiplicand, super.multiplier, super.radixEncoder, - {super.signedMultiplicand, - super.selectSignedMultiplicand, - super.signedMultiplier, - super.selectSignedMultiplier, - super.name = 'stop_bits'}) { - signExtend(); - } - - /// Sign extend the PP array using stop bits. - /// If possible, fold the final carry into another row (only when rectangular - /// enough that carry bit lands outside another row). - /// This technique can then be combined with a first-row extension technique - /// for folding in the final carry. - /// - @override - void signExtend() { - if (signedMultiplicand && (selectSignedMultiplicand != null)) { - throw RohdHclException('multiplicand sign reconfiguration requires ' - 'signedMultiplicand=false'); - } - if (isSignExtended) { - throw RohdHclException('Partial Product array already sign-extended'); - } - isSignExtended = true; - - final finalCarryPos = shift * (rows - 1); - final finalCarryRelPos = finalCarryPos - selector.width - shift; - final finalCarryRow = - ((encoder.multiplier.width > selector.multiplicand.width) && - (finalCarryRelPos > 0)) - ? (finalCarryRelPos / shift).floor() - : 0; - - final signs = [for (var r = 0; r < rows; r++) encoder.getEncoding(r).sign]; - - for (var row = 0; row < rows; row++) { - final addend = partialProducts[row]; - final Logic sign; - if (selectSignedMultiplicand != null) { - sign = mux(selectSignedMultiplicand!, addend.last, signs[row]); - } else { - sign = signedMultiplicand ? addend.last : signs[row]; - } - if (row == 0) { - if (!signedMultiplicand) { - addend.addAll(List.filled(shift, SignBit(sign))); - } else { - // either is signed? - addend.addAll(List.filled(shift - 1, SignBit(sign))); // signed only? - } - addend.add(SignBit(~sign, inverted: true)); - } else { - addStopSign(addend, SignBit(~sign, inverted: true)); - addend - ..addAll(List.filled(shift - 1, Const(1))) - ..insertAll(0, List.filled(shift - 1, Const(0))) - ..insert(0, SignBit(signs[row - 1])); - rowShift[row] -= shift; - } - } - - if (finalCarryRow > 0) { - final extensionRow = partialProducts[finalCarryRow]; - extensionRow - ..addAll(List.filled( - finalCarryPos - (extensionRow.length + rowShift[finalCarryRow]), - Const(0))) - ..add(SignBit(signs[rows - 1])); - } else if (signedMultiplier | (selectSignedMultiplier != null)) { - // Create an extra row to hold the final carry bit - partialProducts - .add(List.filled(selector.width, Const(0), growable: true)); - partialProducts.last.insert(0, SignBit(signs[rows - 2])); - rowShift.add((rows - 2) * shift); - - // Hack for radix-2 - if (shift == 1) { - addStopSignFlip( - partialProducts.last, SignBit(Const(1), inverted: true)); - } - } - } -} - /// A StopBits Sign Extension. class StopBitsSignExtension extends PartialProductSignExtension { /// Construct a stop bits sign extendsion class. @@ -836,164 +560,6 @@ class NewPartialProductGeneratorStopBitsSignExtension } } -/// A Partial Product Generator using Compact Rectangular Extension -class OldPartialProductGeneratorCompactRectSignExtension - extends PartialProductGenerator { - /// Construct a compact rect sign extending Partial Product Generator - OldPartialProductGeneratorCompactRectSignExtension( - super.multiplicand, super.multiplier, super.radixEncoder, - {super.signedMultiplicand, - super.signedMultiplier, - super.selectSignedMultiplicand, - super.selectSignedMultiplier, - super.name = 'compact_rect'}) { - signExtend(); - } - - /// Sign extend the PP array using stop bits without adding a row - /// This routine works with different widths of multiplicand/multiplier, - /// an extension of Mohanty, B.K., Choubey designed by - /// Desmond A. Kirkpatrick - @override - void signExtend() { - if (isSignExtended) { - throw RohdHclException('Partial Product array already sign-extended'); - } - isSignExtended = true; - - final lastRow = rows - 1; - final firstAddend = partialProducts[0]; - final lastAddend = partialProducts[lastRow]; - - final firstRowQStart = selector.width - (signedMultiplicand ? 1 : 0); - final lastRowSignPos = shift * lastRow; - - final align = firstRowQStart - lastRowSignPos; - - final signs = [for (var r = 0; r < rows; r++) encoder.getEncoding(r).sign]; - - // Compute propgation info for folding sign bits into main rows - final propagate = - List.generate(rows, (i) => List.filled(0, Logic(), growable: true)); - - for (var row = 0; row < rows; row++) { - propagate[row].add(SignBit(signs[row])); - for (var col = 0; col < 2 * (shift - 1); col++) { - propagate[row].add(partialProducts[row][col]); - } - // Last row has extend sign propagation to Q start - if (row == lastRow) { - var col = 2 * (shift - 1); - while (propagate[lastRow].length <= align) { - propagate[lastRow].add(SignBit(partialProducts[row][col++])); - } - } - // Now compute the propagation logic - for (var col = 1; col < propagate[row].length; col++) { - propagate[row][col] = propagate[row][col] & propagate[row][col - 1]; - } - } - - // Compute 'm', the prefix of each row to carry the sign of the next row - final m = - List.generate(rows, (i) => List.filled(0, Logic(), growable: true)); - for (var row = 0; row < rows; row++) { - for (var c = 0; c < shift - 1; c++) { - m[row].add(partialProducts[row][c] ^ propagate[row][c]); - } - m[row].addAll(List.filled(shift - 1, Logic())); - } - - while (m[lastRow].length < align) { - m[lastRow].add(Logic()); - } - for (var i = shift - 1; i < m[lastRow].length; i++) { - m[lastRow][i] = - lastAddend[i] ^ (i < align ? propagate[lastRow][i] : Const(0)); - } - - final remainders = List.filled(rows, Logic()); - for (var row = 0; row < lastRow; row++) { - remainders[row] = propagate[row][shift - 1]; - } - remainders[lastRow] = propagate[lastRow][align > 0 ? align : 0]; - - // Merge 'm' into the LSBs of each addend - for (var row = 0; row < rows; row++) { - final addend = partialProducts[row]; - if (row > 0) { - final mLimit = (row == lastRow) ? align : shift - 1; - for (var i = 0; i < mLimit; i++) { - addend[i] = m[row][i]; - } - // Stop bits - addStopSignFlip(addend, SignBit(~signs[row], inverted: true)); - addend - ..insert(0, remainders[row - 1]) - ..addAll(List.filled(shift - 1, Const(1))); - rowShift[row] -= 1; - } else { - // First row - for (var i = 0; i < shift - 1; i++) { - firstAddend[i] = m[0][i]; - } - } - } - - // Insert the lastRow sign: Either in firstRow's Q if there is a - // collision or in another row if it lands beyond the Q sign extension - final Logic firstSign; - if (selectSignedMultiplicand == null) { - firstSign = - signedMultiplicand ? SignBit(firstAddend.last) : SignBit(signs[0]); - } else { - firstSign = - SignBit(mux(selectSignedMultiplicand!, firstAddend.last, signs[0])); - } - final lastSign = SignBit(remainders[lastRow]); - // Compute Sign extension MSBs for firstRow - final qLen = shift + 1; - final insertSignPos = (align > 0) ? 0 : -align; - final q = List.filled(min(qLen, insertSignPos), firstSign, growable: true); - if (insertSignPos < qLen) { - // At sign insertion position - q.add(SignBit(firstSign ^ lastSign)); - if (insertSignPos == qLen - 1) { - q[insertSignPos] = SignBit(~q[insertSignPos], inverted: true); - q.add(SignBit(~(firstSign | q[insertSignPos]), inverted: true)); - } else { - q - ..addAll(List.filled( - qLen - insertSignPos - 2, SignBit(firstSign & ~lastSign))) - ..add(SignBit(~(firstSign & ~lastSign), inverted: true)); - } - } - - if (-align >= q.length) { - q.last = SignBit(~firstSign, inverted: true); - } - addStopSign(firstAddend, SignBit(q[0])); - firstAddend.addAll(q.getRange(1, q.length)); - - if (-align >= q.length) { - final finalCarryRelPos = lastRowSignPos - - selector.width - - shift + - (signedMultiplicand ? 1 : 0); - final finalCarryRow = (finalCarryRelPos / shift).floor(); - final curRowLength = - partialProducts[finalCarryRow].length + rowShift[finalCarryRow]; - - partialProducts[finalCarryRow] - ..addAll(List.filled(lastRowSignPos - curRowLength, Const(0))) - ..add(remainders[lastRow]); - } - if (shift == 1) { - lastAddend.add(Const(1)); - } - } -} - /// A wrapper class for CompactRectSignExtension we used /// during refactoring to be compatible with old calls. class NewPartialProductGeneratorCompactRectSignExtension diff --git a/test/arithmetic/multiplier_encoder_test.dart b/test/arithmetic/multiplier_encoder_test.dart index 637e6a6b6..0bed01146 100644 --- a/test/arithmetic/multiplier_encoder_test.dart +++ b/test/arithmetic/multiplier_encoder_test.dart @@ -197,7 +197,7 @@ void main() { a.put(X); b.put(Y); final PartialProductGenerator pp; - pp = OldPartialProductGeneratorStopBitsSignExtension(a, b, encoder, + pp = NewPartialProductGeneratorStopBitsSignExtension(a, b, encoder, signedMultiplicand: signedMultiplicand, signedMultiplier: signedMultiplier); testPartialProductSingle(pp, X, Y); @@ -256,7 +256,7 @@ void main() { selectSignMultiplicand.put(selectMultiplicand ? 1 : 0); selectSignMultiplier.put(selectMultiplier ? 1 : 0); final PartialProductGenerator pp; - pp = OldPartialProductGeneratorStopBitsSignExtension( + pp = NewPartialProductGeneratorStopBitsSignExtension( Logic(name: 'X', width: width), Logic(name: 'Y', width: width), encoder, @@ -405,7 +405,7 @@ void main() { final multiplicand = Logic(width: widthX); final multiplier = Logic(width: widthY); for (final signed in [false, true]) { - final pp = OldPartialProductGeneratorCompactSignExtension( + final pp = NewPartialProductGeneratorCompactSignExtension( multiplicand, multiplier, radixEncoder, signedMultiplicand: signed, signedMultiplier: signed); for (var i = BigInt.zero; i < BigInt.from(limitX); i += BigInt.one) { From 6b790e28759aaddac0d9972027dba21d10a77ad3 Mon Sep 17 00:00:00 2001 From: Galileo Newton Date: Sat, 11 Jan 2025 17:29:27 -0800 Subject: [PATCH 05/14] doc updates and code doc fixes --- doc/components/multiplier.md | 2 +- doc/components/multiplier_components.md | 35 ++-- lib/src/arithmetic/addend_compressor.dart | 2 +- lib/src/arithmetic/multiplier.dart | 25 +-- .../parallel_prefix_operations.dart | 28 +-- .../arithmetic/partial_product_generator.dart | 2 +- .../partial_product_sign_extend.dart | 163 ++++++------------ lib/src/arithmetic/sign_magnitude_adder.dart | 2 +- test/arithmetic/addend_compressor_test.dart | 11 +- test/arithmetic/multiplier_encoder_test.dart | 77 +++++---- test/arithmetic/multiplier_test.dart | 46 ++--- 11 files changed, 177 insertions(+), 216 deletions(-) diff --git a/doc/components/multiplier.md b/doc/components/multiplier.md index f2439c983..b6eeab299 100644 --- a/doc/components/multiplier.md +++ b/doc/components/multiplier.md @@ -137,7 +137,7 @@ The parameters of the - 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` (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`). +- `esGen` parameter: the type of `PartialProductSignExtension` 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 `CompactRectSignExtension`). - `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 (twos' complement) or unsigned - `signedAddend` parameter: whether the addend (third arg) should be treated as signed (twos' complement) or unsigned diff --git a/doc/components/multiplier_components.md b/doc/components/multiplier_components.md index 00c49a81c..0b2875191 100644 --- a/doc/components/multiplier_components.md +++ b/doc/components/multiplier_components.md @@ -90,7 +90,19 @@ Note that radix-4 shifts by 2 positions each row, but with only two rows and wit ## Partial Product Generator -This building block creates a set of rows of partial products from a multiplicand and a multiplier. It maintains the partial products as a list of rows, which are themselves lists of Logic as well as a row shift value for each row to represent the starting column of the row's least-significant bit. Its primary inputs are the multiplicand, multiplier, `RadixEncoder`, whether the operands are signed, and the type of `SignExtension` to use in generating the partial product rows. +The base class of `PartialProductGenerator` is `PartialProductArray` which is simply a `List>` to represent addends and a `rowShift[row]` to represent the shifts in the partial product matrix. If customization is needed beyond sign extension options, routines are provided that allow for fixed customization of bit positions or conditional (mux based on a Logic) form in the `PartialProductArray`. + +```dart +final ppa = PartialProductArray(a,b); +ppa.setAbsolute(row, col, logic); +ppa.setAbsoluteAll(row, col, List); +ppa.muxAbsolute(row, col, condition, logic); +ppa.muxAbsoluteAll(row, col, condition, List); +``` + + The `PartialProductGenerator` adds to this the `RadixEncoder` to encode the rows along with a matching `MultiplicandSelector` to create the actual mantissas used in each row. + +As a building block which creates a set of rows of partial products from a multiplicand and a multiplier, it maintains the partial products as a list of rows om the `PartialProductArray` base. Its primary inputs are the multiplicand, multiplier, `RadixEncoder`, and whether the operands are signed. The partial product generator produces a set of addends in shifted position to be added. The main output of the component is @@ -122,17 +134,13 @@ Our `RadixEncoder` module is general, creating selection tables for arbitrary Bo ### Sign Extension Option -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. - -The `PartialProductGenerator` creates a set of addends in its base class `PartialProductArray` which is simply a `List>` to represent addends and a `rowShift[row]` to represent the shifts in the partial product matrix. If customization is needed beyond sign extension options, routines are provided that allow for fixed customization of bit positions or conditional (mux based on a Logic) form in the `PartialProductArray`. +The `PartialProductSignExtension` defines the API for doing different kinds of sign extension on the `PartialProductArray`, from very simplistic for helping design new arithmetics to fairly standard to even compact, rectangular forms. -```dart -final ppg = PartialProductGenerator(a,b); -ppg.setAbsolute(row, col, logic); -ppg.setAbsoluteAll(row, col, List); -ppg.muxAbsolute(row, col, condition, logic); -ppg.muxAbsoluteAll(row, col, condition, List); -``` +- None: no sign extension. +- Brute: full width extension which is robust but costly. +- StopBit: A standard form which has the inverse-sign and a '1' stop bit in each row +- Compact: A form that eliminates a final sign in an otherwise empty final row. +- CompactRect: An enhanced form of compact that can handle rectangular multiplications. ### Partial Product Visualization @@ -213,7 +221,7 @@ Any adder can be used as the final adder of the final two addends produced from Here is a code snippet that shows how these components can be used to create a multiplier. -First the partial product generator is used, which has compact sign extension for rectangular products (`PartialProductGeneratorCompactRectSignExtension`) which we pass in the `RadixEncoder`, whether the operands are signed, and the kind of sign extension to use on the partial products. Note that sign extension is needed regardless of whether operands are signed or not due to Booth encoding. +First the partial product generator is used (`PartialProductGenerator`), which we pass in the `RadixEncoder`, whether the operands are signed. We operate on this generator with a compact sign extension class for rectangular products (`CompactRectSignExtension`). Note that sign extension is needed regardless of whether operands are signed or not due to Booth encoding. Next, we use the `ColumnCompressor` to compress the partial products into two final addends. @@ -222,7 +230,8 @@ Finally, we produce the product. ```dart final pp = - PartialProductGeneratorCompactRectSignExtension(a, b, RadixEncoder(radix), signedMultiplicand: true, signedMultiplier: true); + PartialProductGenerator(a, b, RadixEncoder(radix), signedMultiplicand: true, signedMultiplier: true); + CompactRectSignExtension(pp).signExtend(); final compressor = ColumnCompressor(pp)..compress(); final adder = ParallelPrefixAdder( compressor.exractRow(0), compressor.extractRow(1), BrentKung.new); diff --git a/lib/src/arithmetic/addend_compressor.dart b/lib/src/arithmetic/addend_compressor.dart index fa92e7c25..8c4d30c42 100644 --- a/lib/src/arithmetic/addend_compressor.dart +++ b/lib/src/arithmetic/addend_compressor.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2024 Intel Corporation +// Copyright (C) 2024-2025 Intel Corporation // SPDX-License-Identifier: BSD-3-Clause // // addend_compressor.dart diff --git a/lib/src/arithmetic/multiplier.dart b/lib/src/arithmetic/multiplier.dart index b49eab26f..4906fe632 100644 --- a/lib/src/arithmetic/multiplier.dart +++ b/lib/src/arithmetic/multiplier.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2023-2024 Intel Corporation +// Copyright (C) 2023-2025 Intel Corporation // SPDX-License-Identifier: BSD-3-Clause // // multiplier.dart @@ -207,7 +207,7 @@ class CompressionTreeMultiplier extends Multiplier { /// and prefix tree functor [ppTree] for the compressor and final adder. /// /// Sign extension methodology is defined by the partial product generator - /// supplied via [ppGen]. + /// supplied via [seGen]. /// /// [a] multiplicand and [b] multiplier are the product terms and they can /// be different widths allowing for rectangular multiplication. @@ -238,21 +238,19 @@ class CompressionTreeMultiplier extends Multiplier { super.signedMultiplier = false, super.selectSignedMultiplicand, super.selectSignedMultiplier, - ParallelPrefix Function(List, Logic Function(Logic, Logic)) + ParallelPrefix Function( + List inp, Logic Function(Logic term1, Logic term2)) ppTree = KoggeStone.new, - PartialProductGenerator Function(Logic, Logic, RadixEncoder, - {required bool signedMultiplier, - required bool signedMultiplicand, - Logic? selectSignedMultiplier, - Logic? selectSignedMultiplicand}) - ppGen = NewPartialProductGeneratorCompactRectSignExtension.new, + PartialProductSignExtension Function(PartialProductGenerator pp, + {String name}) + seGen = CompactRectSignExtension.new, super.name = 'compression_tree_multiplier'}) { clk = (clk != null) ? addInput('clk', clk!) : null; reset = (reset != null) ? addInput('reset', reset!) : null; enable = (enable != null) ? addInput('enable', enable!) : null; final product = addOutput('product', width: a.width + b.width); - final pp = ppGen( + final pp = PartialProductGeneratorBasic( a, b, RadixEncoder(radix), @@ -262,6 +260,8 @@ class CompressionTreeMultiplier extends Multiplier { signedMultiplier: signedMultiplier, ); + seGen(pp).signExtend(); + final compressor = ColumnCompressor(clk: clk, reset: reset, enable: enable, pp) ..compress(); @@ -334,14 +334,15 @@ class CompressionTreeMultiplyAccumulate extends MultiplyAccumulate { super.selectSignedMultiplicand, super.selectSignedMultiplier, super.selectSignedAddend, - ParallelPrefix Function(List, Logic Function(Logic, Logic)) + ParallelPrefix Function( + List inps, Logic Function(Logic term1, Logic term2)) ppTree = KoggeStone.new, PartialProductGenerator Function(Logic, Logic, RadixEncoder, {required bool signedMultiplier, required bool signedMultiplicand, Logic? selectSignedMultiplier, Logic? selectSignedMultiplicand}) - ppGen = NewPartialProductGeneratorCompactRectSignExtension.new, + ppGen = PartialProductGeneratorCompactRectSignExtension.new, super.name = 'compression_tree_mac'}) { clk = (clk != null) ? addInput('clk', clk) : null; reset = (reset != null) ? addInput('reset', reset) : null; diff --git a/lib/src/arithmetic/parallel_prefix_operations.dart b/lib/src/arithmetic/parallel_prefix_operations.dart index bbbcdf0ee..a3939dc1c 100644 --- a/lib/src/arithmetic/parallel_prefix_operations.dart +++ b/lib/src/arithmetic/parallel_prefix_operations.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2023-2024 Intel Corporation +// Copyright (C) 2023-2025 Intel Corporation // SPDX-License-Identifier: BSD-3-Clause // // parallel_prefix_operations.dart @@ -61,7 +61,7 @@ class Ripple extends ParallelPrefix { /// Sklansky shaped ParallelPrefix tree class Sklansky extends ParallelPrefix { /// Sklansky constructor - Sklansky(List inps, Logic Function(Logic, Logic) op) + Sklansky(List inps, Logic Function(Logic term1, Logic term2) op) : super(inps, 'sklansky') { final iseq = []; @@ -90,7 +90,7 @@ class Sklansky extends ParallelPrefix { /// KoggeStone shaped ParallelPrefix tree class KoggeStone extends ParallelPrefix { /// KoggeStone constructor - KoggeStone(List inps, Logic Function(Logic, Logic) op) + KoggeStone(List inps, Logic Function(Logic term1, Logic term2) op) : super(inps, 'kogge_stone') { final iseq = []; @@ -117,7 +117,7 @@ class KoggeStone extends ParallelPrefix { /// BrentKung shaped ParallelPrefix tree class BrentKung extends ParallelPrefix { /// BrentKung constructor - BrentKung(List inps, Logic Function(Logic, Logic) op) + BrentKung(List inps, Logic Function(Logic term1, Logic term2) op) : super(inps, 'brent_kung') { final iseq = []; @@ -162,7 +162,8 @@ class ParallelPrefixOrScan extends Module { /// OrScan constructor ParallelPrefixOrScan(Logic inp, - {ParallelPrefix Function(List, Logic Function(Logic, Logic)) + {ParallelPrefix Function( + List inps, Logic Function(Logic term1, Logic term2) op) ppGen = KoggeStone.new, super.name = 'parallel_prefix_orscan'}) { inp = addInput('inp', inp, width: inp.width); @@ -179,7 +180,8 @@ class ParallelPrefixPriorityFinder extends Module { /// Priority Finder constructor ParallelPrefixPriorityFinder(Logic inp, - {ParallelPrefix Function(List, Logic Function(Logic, Logic)) + {ParallelPrefix Function( + List inps, Logic Function(Logic term1, Logic term2) op) ppGen = KoggeStone.new, super.name = 'parallel_prefix_finder'}) { inp = addInput('inp', inp, width: inp.width); @@ -196,7 +198,8 @@ class ParallelPrefixPriorityEncoder extends Module { /// PriorityEncoder constructor ParallelPrefixPriorityEncoder(Logic inp, - {ParallelPrefix Function(List, Logic Function(Logic, Logic)) + {ParallelPrefix Function( + List inps, Logic Function(Logic term1, Logic term2) op) ppGen = KoggeStone.new, super.name = 'parallel_prefix_encoder'}) { inp = addInput('inp', inp, width: inp.width); @@ -211,8 +214,9 @@ class ParallelPrefixAdder extends Adder { /// Adder constructor ParallelPrefixAdder(super.a, super.b, {super.carryIn, - ParallelPrefix Function(List, Logic Function(Logic, Logic)) ppGen = - KoggeStone.new, + ParallelPrefix Function( + List inps, Logic Function(Logic term1, Logic term2) op) + 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()); @@ -243,7 +247,8 @@ class ParallelPrefixIncr extends Module { /// Increment constructor ParallelPrefixIncr(Logic inp, - {ParallelPrefix Function(List, Logic Function(Logic, Logic)) + {ParallelPrefix Function( + List inps, Logic Function(Logic term1, Logic term2) op) ppGen = KoggeStone.new, super.name = 'parallel_prefix_incr'}) { inp = addInput('inp', inp, width: inp.width); @@ -262,7 +267,8 @@ class ParallelPrefixDecr extends Module { /// Decrement constructor ParallelPrefixDecr(Logic inp, - {ParallelPrefix Function(List, Logic Function(Logic, Logic)) + {ParallelPrefix Function( + List inps, Logic Function(Logic term1, Logic term2) op) ppGen = KoggeStone.new, super.name = 'parallel_prefix_decr'}) { inp = addInput('inp', inp, width: inp.width); diff --git a/lib/src/arithmetic/partial_product_generator.dart b/lib/src/arithmetic/partial_product_generator.dart index 36da41fa2..918e111a3 100644 --- a/lib/src/arithmetic/partial_product_generator.dart +++ b/lib/src/arithmetic/partial_product_generator.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2024 Intel Corporation +// Copyright (C) 2024-2025 Intel Corporation // SPDX-License-Identifier: BSD-3-Clause // // partial_product_generator.dart diff --git a/lib/src/arithmetic/partial_product_sign_extend.dart b/lib/src/arithmetic/partial_product_sign_extend.dart index 986d90fdf..f0148b172 100644 --- a/lib/src/arithmetic/partial_product_sign_extend.dart +++ b/lib/src/arithmetic/partial_product_sign_extend.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2024 Intel Corporation +// Copyright (C) 2024-2025 Intel Corporation // SPDX-License-Identifier: BSD-3-Clause // // partial_product_test_sign_extend.dart @@ -38,37 +38,27 @@ typedef PPGFunction = PartialProductGenerator Function( bool signedMultiplier, Logic? selectSignedMultiplier}); -/// Used to test different sign extension methods -PPGFunction curryPartialProductGenerator(SignExtension signExtension) => - switch (signExtension) { - SignExtension.none => NewPartialProductGeneratorNoneSignExtension.new, - SignExtension.brute => NewPartialProductGeneratorBruteSignExtension.new, - SignExtension.stopBits => - NewPartialProductGeneratorStopBitsSignExtension.new, - SignExtension.compact => - NewPartialProductGeneratorCompactSignExtension.new, - SignExtension.compactRect => - NewPartialProductGeneratorCompactRectSignExtension.new, - }; - /// API for sign extension classes abstract class PartialProductSignExtension { + /// name used for PartialProductSignExtension + final String name; + /// The partial product generator we are sign extending. final PartialProductGenerator ppg; /// multiplicand operand is always signed. - final bool signedMultiplicand; + bool get signedMultiplicand => ppg.signedMultiplicand; /// multiplier operand is always signed. - final bool signedMultiplier; + bool get signedMultiplier => ppg.signedMultiplier; /// If not null, use this signal to select between signed and unsigned /// multiplicand. - final Logic? selectSignedMultiplicand; + Logic? get selectSignedMultiplicand => ppg.selectSignedMultiplicand; /// If not null, use this signal to select between signed and unsigned /// multiplier. - final Logic? selectSignedMultiplier; + Logic? get selectSignedMultiplier => ppg.selectSignedMultiplier; /// in PPA int get rows => ppg.rows; @@ -98,13 +88,7 @@ abstract class PartialProductSignExtension { /// Sign Extension class that operates on a [PartialProductGenerator] /// and sign-extends the entries. - PartialProductSignExtension( - this.ppg, { - this.signedMultiplicand = false, - this.signedMultiplier = false, - this.selectSignedMultiplicand, - this.selectSignedMultiplier, - }) { + PartialProductSignExtension(this.ppg, {this.name = 'no_sign_extension'}) { // if (signedMultiplier && (selectSignedMultiplier != null)) { throw RohdHclException('sign reconfiguration requires signed=false'); @@ -145,15 +129,11 @@ abstract class PartialProductSignExtension { } /// Used to test different sign extension methods -typedef SignExtensionFunction = PartialProductSignExtension Function( - PartialProductGenerator ppg, - {bool signedMultiplicand, - bool signedMultiplier, - Logic? selectSignedMultiplicand, - Logic? selectSignedMultiplier}); +typedef SignExtensionFunction = PartialProductSignExtension + Function(PartialProductGenerator ppg, {String name}); /// Used to test different sign extension methods -SignExtensionFunction currysignExtensionFunction(SignExtension signExtension) => +SignExtensionFunction currySignExtensionFunction(SignExtension signExtension) => switch (signExtension) { SignExtension.none => NoneSignExtension.new, SignExtension.brute => BruteSignExtension.new, @@ -169,39 +149,51 @@ SignExtensionFunction currysignExtensionFunction(SignExtension signExtension) => /// /// A Partial Product Generator using None Sign Extension class NoneSignExtension extends PartialProductSignExtension { /// Construct a no sign-extension class. - NoneSignExtension( - super.ppg, { - super.signedMultiplicand = false, - super.signedMultiplier = false, - super.selectSignedMultiplicand, - super.selectSignedMultiplier, - }); + NoneSignExtension(super.ppg, {super.name = 'none_sign_extension'}); /// Fully sign extend the PP array: useful for reference only @override void signExtend() {} } +/// A concrete base class for partial product generation +class PartialProductGeneratorBasic extends PartialProductGenerator { + /// The extension routine we will be using. + late final PartialProductSignExtension extender; + + /// Construct a none sign extending Partial Product Generator + PartialProductGeneratorBasic( + super.multiplicand, super.multiplier, super.radixEncoder, + {super.signedMultiplicand, + super.signedMultiplier, + super.selectSignedMultiplicand, + super.selectSignedMultiplier, + super.name = 'none'}) { + extender = NoneSignExtension(this); + signExtend(); + } + + @override + void signExtend() { + extender.signExtend(); + } +} + /// A wrapper class for [NoneSignExtension] we used /// during refactoring to be compatible with old calls. -class NewPartialProductGeneratorNoneSignExtension - extends PartialProductGenerator { +class PartialProductGeneratorNoneSignExtension extends PartialProductGenerator { /// The extension routine we will be using. late final PartialProductSignExtension extender; /// Construct a none sign extending Partial Product Generator - NewPartialProductGeneratorNoneSignExtension( + PartialProductGeneratorNoneSignExtension( super.multiplicand, super.multiplier, super.radixEncoder, {super.signedMultiplicand, super.signedMultiplier, super.selectSignedMultiplicand, super.selectSignedMultiplier, super.name = 'none'}) { - extender = BruteSignExtension(this, - signedMultiplicand: signedMultiplicand, - signedMultiplier: signedMultiplier, - selectSignedMultiplicand: selectSignedMultiplicand, - selectSignedMultiplier: selectSignedMultiplier); + extender = NoneSignExtension(this); signExtend(); } @@ -211,20 +203,10 @@ class NewPartialProductGeneratorNoneSignExtension } } -/// These other sign extensions are for assisting with testing and debugging. -/// More robust and simpler sign extensions in case -/// complex sign extension routines obscure other bugs. - /// A Brute Sign Extension class. class BruteSignExtension extends PartialProductSignExtension { /// Construct a brute-force sign extending Partial Product Generator - BruteSignExtension( - super.ppg, { - super.signedMultiplicand = false, - super.signedMultiplier = false, - super.selectSignedMultiplicand, - super.selectSignedMultiplier, - }); + BruteSignExtension(super.ppg, {super.name = 'brute_sign_extension'}); /// Fully sign extend the PP array: useful for reference only @override @@ -263,24 +245,20 @@ class BruteSignExtension extends PartialProductSignExtension { /// A wrapper class for [BruteSignExtension] we used /// during refactoring to be compatible with old calls. -class NewPartialProductGeneratorBruteSignExtension +class PartialProductGeneratorBruteSignExtension extends PartialProductGenerator { /// The extension routine we will be using. late final PartialProductSignExtension extender; /// Construct a compact rect sign extending Partial Product Generator - NewPartialProductGeneratorBruteSignExtension( + PartialProductGeneratorBruteSignExtension( super.multiplicand, super.multiplier, super.radixEncoder, {super.signedMultiplicand, super.signedMultiplier, super.selectSignedMultiplicand, super.selectSignedMultiplier, super.name = 'brute'}) { - extender = BruteSignExtension(this, - signedMultiplicand: signedMultiplicand, - signedMultiplier: signedMultiplier, - selectSignedMultiplicand: selectSignedMultiplicand, - selectSignedMultiplier: selectSignedMultiplier); + extender = BruteSignExtension(this); signExtend(); } @@ -293,13 +271,7 @@ class NewPartialProductGeneratorBruteSignExtension /// A Compact Sign Extension class. class CompactSignExtension extends PartialProductSignExtension { /// Construct a compact sign extendsion class. - CompactSignExtension( - super.ppg, { - super.signedMultiplicand = false, - super.signedMultiplier = false, - super.selectSignedMultiplicand, - super.selectSignedMultiplier, - }); + CompactSignExtension(super.ppg, {super.name = 'compact_sign_extension'}); @override void signExtend() { @@ -415,24 +387,20 @@ class CompactSignExtension extends PartialProductSignExtension { /// A wrapper class for [CompactSignExtension] we used /// during refactoring to be compatible with old calls. -class NewPartialProductGeneratorCompactSignExtension +class PartialProductGeneratorCompactSignExtension extends PartialProductGenerator { /// The extension routine we will be using. late final PartialProductSignExtension extender; /// Construct a compact sign extending Partial Product Generator - NewPartialProductGeneratorCompactSignExtension( + PartialProductGeneratorCompactSignExtension( super.multiplicand, super.multiplier, super.radixEncoder, {super.signedMultiplicand, super.signedMultiplier, super.selectSignedMultiplicand, super.selectSignedMultiplier, super.name = 'compact'}) { - extender = CompactSignExtension(this, - signedMultiplicand: signedMultiplicand, - signedMultiplier: signedMultiplier, - selectSignedMultiplicand: selectSignedMultiplicand, - selectSignedMultiplier: selectSignedMultiplier); + extender = CompactSignExtension(this); signExtend(); } @@ -445,13 +413,7 @@ class NewPartialProductGeneratorCompactSignExtension /// A StopBits Sign Extension. class StopBitsSignExtension extends PartialProductSignExtension { /// Construct a stop bits sign extendsion class. - StopBitsSignExtension( - super.ppg, { - super.signedMultiplicand = false, - super.signedMultiplier = false, - super.selectSignedMultiplicand, - super.selectSignedMultiplier, - }); + StopBitsSignExtension(super.ppg, {super.name = 'stopbits_sign_extension'}); /// Sign extend the PP array using stop bits. /// If possible, fold the final carry into another row (only when rectangular @@ -533,24 +495,20 @@ class StopBitsSignExtension extends PartialProductSignExtension { /// A wrapper class for [StopBitsSignExtension] we used /// during refactoring to be compatible with old calls. -class NewPartialProductGeneratorStopBitsSignExtension +class PartialProductGeneratorStopBitsSignExtension extends PartialProductGenerator { /// The extension routine we will be using. late final PartialProductSignExtension extender; /// Construct a stop bits sign extending Partial Product Generator - NewPartialProductGeneratorStopBitsSignExtension( + PartialProductGeneratorStopBitsSignExtension( super.multiplicand, super.multiplier, super.radixEncoder, {super.signedMultiplicand, super.signedMultiplier, super.selectSignedMultiplicand, super.selectSignedMultiplier, super.name = 'stop_bits'}) { - extender = StopBitsSignExtension(this, - signedMultiplicand: signedMultiplicand, - signedMultiplier: signedMultiplier, - selectSignedMultiplicand: selectSignedMultiplicand, - selectSignedMultiplier: selectSignedMultiplier); + extender = StopBitsSignExtension(this); signExtend(); } @@ -562,24 +520,20 @@ class NewPartialProductGeneratorStopBitsSignExtension /// A wrapper class for CompactRectSignExtension we used /// during refactoring to be compatible with old calls. -class NewPartialProductGeneratorCompactRectSignExtension +class PartialProductGeneratorCompactRectSignExtension extends PartialProductGenerator { /// The extension routine we will be using. late final PartialProductSignExtension extender; /// Construct a compact rect sign extending Partial Product Generator - NewPartialProductGeneratorCompactRectSignExtension( + PartialProductGeneratorCompactRectSignExtension( super.multiplicand, super.multiplier, super.radixEncoder, {super.signedMultiplicand, super.signedMultiplier, super.selectSignedMultiplicand, super.selectSignedMultiplier, super.name = 'compact_rect'}) { - extender = CompactRectSignExtension(this, - signedMultiplicand: signedMultiplicand, - signedMultiplier: signedMultiplier, - selectSignedMultiplicand: selectSignedMultiplicand, - selectSignedMultiplier: selectSignedMultiplier); + extender = CompactRectSignExtension(this); signExtend(); } @@ -595,13 +549,8 @@ class CompactRectSignExtension extends PartialProductSignExtension { /// This routine works with different widths of multiplicand/multiplier, /// an extension of Mohanty, B.K., Choubey designed by /// Desmond A. Kirkpatrick. - CompactRectSignExtension( - super.ppg, { - super.signedMultiplicand = false, - super.signedMultiplier = false, - super.selectSignedMultiplicand, - super.selectSignedMultiplier, - }); + CompactRectSignExtension(super.ppg, + {super.name = 'compactrect_sign_extension'}); @override void signExtend() { diff --git a/lib/src/arithmetic/sign_magnitude_adder.dart b/lib/src/arithmetic/sign_magnitude_adder.dart index ea7ef9132..a21966c32 100644 --- a/lib/src/arithmetic/sign_magnitude_adder.dart +++ b/lib/src/arithmetic/sign_magnitude_adder.dart @@ -37,7 +37,7 @@ class SignMagnitudeAdder extends Adder { /// 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, {Logic? carryIn}) adderGen, + Adder Function(Logic a, Logic b, {Logic? carryIn}) adderGen, {this.largestMagnitudeFirst = false, super.name = 'sign_magnitude_adder'}) { aSign = addInput('aSign', aSign); diff --git a/test/arithmetic/addend_compressor_test.dart b/test/arithmetic/addend_compressor_test.dart index becf72b6c..6e53c4978 100644 --- a/test/arithmetic/addend_compressor_test.dart +++ b/test/arithmetic/addend_compressor_test.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2023-2024 Intel Corporation +// Copyright (C) 2023-2025 Intel Corporation // SPDX-License-Identifier: BSD-3-Clause // // addend_compressor_test.dart @@ -36,8 +36,10 @@ class CompressorTestMod extends Module { clk = addInput('clk', iclk); } - pp = NewPartialProductGeneratorCompactRectSignExtension(a, b, encoder, + final pp = PartialProductGeneratorBasic(a, b, encoder, signedMultiplicand: signed, signedMultiplier: signed); + CompactRectSignExtension(pp).signExtend(); + compressor = ColumnCompressor(pp, clk: clk); compressor.compress(); final r0 = addOutput('r0', width: compressor.columns.length); @@ -111,12 +113,13 @@ void main() { selectSignedMultiplicand!.put(signed ? 1 : 0); selectSignedMultiplier!.put(signed ? 1 : 0); } - final pp = NewPartialProductGeneratorCompactRectSignExtension( - a, b, encoder, + final pp = PartialProductGeneratorBasic(a, b, encoder, signedMultiplicand: !useSelect & signed, signedMultiplier: !useSelect & signed, selectSignedMultiplicand: selectSignedMultiplicand, selectSignedMultiplier: selectSignedMultiplier); + CompactRectSignExtension(pp).signExtend(); + expect(pp.evaluate(), equals(bA * bB)); final compressor = ColumnCompressor(pp); expect(compressor.evaluate().$1, equals(bA * bB)); diff --git a/test/arithmetic/multiplier_encoder_test.dart b/test/arithmetic/multiplier_encoder_test.dart index 0bed01146..0e56558ff 100644 --- a/test/arithmetic/multiplier_encoder_test.dart +++ b/test/arithmetic/multiplier_encoder_test.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2023-2024 Intel Corporation +// Copyright (C) 2023-2025 Intel Corporation // SPDX-License-Identifier: BSD-3-Clause // // multiplier_encoder_test.dart @@ -167,11 +167,13 @@ void main() { final width = log2Ceil(radix) + (signedMultiplier ? 1 : 0); for (final signExtension in SignExtension.values.where((e) => e != SignExtension.none)) { - final ppg = curryPartialProductGenerator(signExtension); - final pp = ppg(Logic(name: 'X', width: width), - Logic(name: 'Y', width: width), RadixEncoder(radix), + final pp = PartialProductGeneratorBasic( + Logic(name: 'X', width: width), + Logic(name: 'Y', width: width), + RadixEncoder(radix), signedMultiplicand: signedMultiplicand, signedMultiplier: signedMultiplier); + currySignExtensionFunction(signExtension)(pp).signExtend(); testPartialProductExhaustive(pp); } } @@ -197,9 +199,10 @@ void main() { a.put(X); b.put(Y); final PartialProductGenerator pp; - pp = NewPartialProductGeneratorStopBitsSignExtension(a, b, encoder, + pp = PartialProductGeneratorBasic(a, b, encoder, signedMultiplicand: signedMultiplicand, signedMultiplier: signedMultiplier); + StopBitsSignExtension(pp).signExtend(); testPartialProductSingle(pp, X, Y); } } @@ -221,9 +224,8 @@ void main() { for (final signExtension in SignExtension.values .where((e) => e != SignExtension.none)) { final width = log2Ceil(radix) + (signMultiplier ? 1 : 0); - final ppg = curryPartialProductGenerator(signExtension); final PartialProductGenerator pp; - pp = ppg( + pp = PartialProductGeneratorBasic( Logic(name: 'X', width: width), Logic(name: 'Y', width: width), encoder, @@ -233,6 +235,7 @@ void main() { selectMultiplicand ? selectSignMultiplicand : null, selectSignedMultiplier: selectMultiplier ? selectSignMultiplier : null); + currySignExtensionFunction(signExtension)(pp).signExtend(); testPartialProductExhaustive(pp); } @@ -256,7 +259,7 @@ void main() { selectSignMultiplicand.put(selectMultiplicand ? 1 : 0); selectSignMultiplier.put(selectMultiplier ? 1 : 0); final PartialProductGenerator pp; - pp = NewPartialProductGeneratorStopBitsSignExtension( + pp = PartialProductGeneratorStopBitsSignExtension( Logic(name: 'X', width: width), Logic(name: 'Y', width: width), encoder, @@ -286,9 +289,13 @@ void main() { for (var width = shift; width < min(5, 2 * shift); width++) { for (final signExtension in SignExtension.values.where((e) => e != SignExtension.none)) { - final ppg = curryPartialProductGenerator(signExtension); - final pp = ppg(Logic(name: 'X', width: width), - Logic(name: 'Y', width: width), encoder); + // final ppg = curryPartialProductGenerator(signExtension); + final pp = PartialProductGeneratorBasic( + Logic(name: 'X', width: width), + Logic(name: 'Y', width: width), + encoder); + currySignExtensionFunction(signExtension)(pp).signExtend(); + testPartialProductExhaustive(pp); } } @@ -308,11 +315,14 @@ void main() { SignExtension.stopBits, SignExtension.compactRect ]) { - final ppg = curryPartialProductGenerator(signExtension); - final pp = ppg(Logic(name: 'X', width: widthX), - Logic(name: 'Y', width: widthY), encoder, + final pp = PartialProductGeneratorBasic( + Logic(name: 'X', width: widthX), + Logic(name: 'Y', width: widthY), + encoder, signedMultiplicand: signedMultiplicand, signedMultiplier: signedMultiplier); + currySignExtensionFunction(signExtension)(pp).signExtend(); + testPartialProductExhaustive(pp); } } @@ -328,9 +338,12 @@ void main() { for (var width = shift; width < min(5, 2 * shift); width++) { for (final signExtension in SignExtension.values.where((e) => e != SignExtension.none)) { - final ppg = curryPartialProductGenerator(signExtension); - final pp = ppg(Logic(name: 'X', width: width), - Logic(name: 'Y', width: width), encoder); + final pp = PartialProductGeneratorBasic( + Logic(name: 'X', width: width), + Logic(name: 'Y', width: width), + encoder); + currySignExtensionFunction(signExtension)(pp).signExtend(); + testPartialProductExhaustive(pp); } } @@ -352,11 +365,14 @@ void main() { SignExtension.stopBits, SignExtension.compactRect ]) { - final ppg = curryPartialProductGenerator(signExtension); - final pp = ppg(Logic(name: 'X', width: widthX), - Logic(name: 'Y', width: widthY), encoder, + final pp = PartialProductGeneratorBasic( + Logic(name: 'X', width: widthX), + Logic(name: 'Y', width: widthY), + encoder, signedMultiplicand: signedMultiplicand, signedMultiplier: signedMultiplier); + currySignExtensionFunction(signExtension)(pp).signExtend(); + testPartialProductExhaustive(pp); } } @@ -385,10 +401,9 @@ void main() { final skew = align.$3; - final pp = NewPartialProductGeneratorCompactRectSignExtension( - Logic(name: 'X', width: width), - Logic(name: 'Y', width: width + skew), - encoder); + final pp = PartialProductGeneratorBasic(Logic(name: 'X', width: width), + Logic(name: 'Y', width: width + skew), encoder); + CompactRectSignExtension(pp).signExtend(); testPartialProductRandom(pp, 10); } @@ -405,16 +420,17 @@ void main() { final multiplicand = Logic(width: widthX); final multiplier = Logic(width: widthY); for (final signed in [false, true]) { - final pp = NewPartialProductGeneratorCompactSignExtension( + final ppg = PartialProductGeneratorBasic( multiplicand, multiplier, radixEncoder, signedMultiplicand: signed, signedMultiplier: signed); + CompactSignExtension(ppg).signExtend(); for (var i = BigInt.zero; i < BigInt.from(limitX); i += BigInt.one) { for (var j = BigInt.zero; j < BigInt.from(limitY); j += BigInt.one) { final X = signed ? i.toSigned(widthX) : i.toUnsigned(widthX); final Y = signed ? j.toSigned(widthY) : j.toUnsigned(widthY); multiplicand.put(X); multiplier.put(Y); - final value = pp.evaluate(); + final value = ppg.evaluate(); expect(value, equals(X * Y), reason: '$X * $Y = $value should be ${X * Y}'); } @@ -443,9 +459,9 @@ void main() { logicX.put(X); logicY.put(Y); logicZ.put(Z); - final pp = NewPartialProductGeneratorCompactRectSignExtension( - logicX, logicY, encoder, + final pp = PartialProductGeneratorBasic(logicX, logicY, encoder, signedMultiplicand: true, signedMultiplier: true); + CompactRectSignExtension(pp).signExtend(); final lastLength = pp.partialProducts[pp.rows - 1].length + pp.rowShift[pp.rows - 1]; @@ -493,10 +509,9 @@ void main() { logicX.put(X); logicY.put(Y); logicZ.put(Z); - - final pp = NewPartialProductGeneratorCompactRectSignExtension( - logicX, logicY, encoder, + final pp = PartialProductGeneratorBasic(logicX, logicY, encoder, signedMultiplicand: true, signedMultiplier: true); + CompactRectSignExtension(pp).signExtend(); final lastLength = pp.partialProducts[pp.rows - 1].length + pp.rowShift[pp.rows - 1]; diff --git a/test/arithmetic/multiplier_test.dart b/test/arithmetic/multiplier_test.dart index a36e286ed..25bc550f5 100644 --- a/test/arithmetic/multiplier_test.dart +++ b/test/arithmetic/multiplier_test.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2024 Intel Corporation +// Copyright (C) 2024-2025 Intel Corporation // SPDX-License-Identifier: BSD-3-Clause // // multiplier_test.dart @@ -188,23 +188,13 @@ void main() { MultiplierCallback curryCompressionTreeMultiplier(int radix, ParallelPrefix Function(List, Logic Function(Logic, Logic)) ppTree, - {PPGFunction ppGen = - NewPartialProductGeneratorCompactRectSignExtension.new, + {SignExtensionFunction seGen = CompactRectSignExtension.new, bool signedMultiplicand = false, bool signedMultiplier = false, Logic? selectSignedMultiplicand, Logic? selectSignedMultiplier}) { - String genName(Logic a, Logic b) => ppGen( - a, - b, - RadixEncoder(radix), - signedMultiplicand: signedMultiplicand, - signedMultiplier: signedMultiplier, - selectSignedMultiplicand: - selectSignedMultiplicand != null ? Logic() : null, - selectSignedMultiplier: - selectSignedMultiplier != null ? Logic() : null, - ).name; + String genName(Logic a, Logic b) => + seGen(PartialProductGeneratorBasic(a, b, RadixEncoder(radix))).name; final signage = ' SD=${signedMultiplicand ? 1 : 0}' ' SM=${signedMultiplier ? 1 : 0}' ' SelD=${(selectSignedMultiplicand != null) ? 1 : 0}' @@ -212,7 +202,6 @@ void main() { return (a, b, {selectSignedMultiplicand, selectSignedMultiplier}) => CompressionTreeMultiplier(a, b, radix, ppTree: ppTree, - ppGen: ppGen, signedMultiplicand: signedMultiplicand, signedMultiplier: signedMultiplier, selectSignedMultiplicand: selectSignedMultiplicand, @@ -225,8 +214,7 @@ void main() { MultiplyAccumulateCallback curryMultiplierAsMultiplyAccumulate(int radix, {ParallelPrefix Function(List, Logic Function(Logic, Logic)) ppTree = KoggeStone.new, - PPGFunction ppGen = - NewPartialProductGeneratorCompactRectSignExtension.new, + SignExtensionFunction seGen = CompactRectSignExtension.new, bool signedMultiplicand = false, bool signedMultiplier = false, Logic? selectSignedMultiplicand, @@ -242,7 +230,7 @@ void main() { curryCompressionTreeMultiplier( radix, ppTree, - ppGen: ppGen, + seGen: seGen, signedMultiplicand: signedMultiplicand, signedMultiplier: signedMultiplier, selectSignedMultiplicand: selectSignedMultiplicand, @@ -253,7 +241,7 @@ void main() { int radix, { ParallelPrefix Function(List, Logic Function(Logic, Logic)) ppTree = KoggeStone.new, - PPGFunction ppGen = NewPartialProductGeneratorCompactRectSignExtension.new, + SignExtensionFunction seGen = CompactRectSignExtension.new, bool signedMultiplicand = false, bool signedMultiplier = false, bool signedAddend = false, @@ -261,17 +249,8 @@ void main() { Logic? selectSignedMultiplier, Logic? selectSignedAddend, }) { - String genName(Logic a, Logic b) => ppGen( - a, - b, - RadixEncoder(radix), - signedMultiplicand: signedMultiplicand, - signedMultiplier: signedMultiplier, - selectSignedMultiplicand: - selectSignedMultiplicand != null ? Logic() : null, - selectSignedMultiplier: - selectSignedMultiplier != null ? Logic() : null, - ).name; + String genName(Logic a, Logic b) => + seGen(PartialProductGeneratorBasic(a, b, RadixEncoder(radix))).name; final signage = ' SD=${signedMultiplicand ? 1 : 0}' ' SM=${signedMultiplier ? 1 : 0}' ' SelD=${(selectSignedMultiplicand != null) ? 1 : 0}' @@ -279,7 +258,6 @@ void main() { return (a, b, c) => CompressionTreeMultiplyAccumulate(a, b, c, radix, ppTree: ppTree, - ppGen: ppGen, signedMultiplicand: signedMultiplicand, signedMultiplier: signedMultiplier, signedAddend: signedAddend, @@ -308,9 +286,9 @@ void main() { for (final width in [3, 4]) { for (final signExtension in SignExtension.values.where((e) => e != SignExtension.none)) { - final ppg = curryPartialProductGenerator(signExtension); + final seg = currySignExtensionFunction(signExtension); testMultiplyAccumulateRandom(width, 10, - curryMultiplierAsMultiplyAccumulate(radix, ppGen: ppg)); + curryMultiplierAsMultiplyAccumulate(radix, seGen: seg)); } } } @@ -618,7 +596,7 @@ void main() { a.put(6); b.put(3); - final ppG0 = NewPartialProductGeneratorCompactRectSignExtension( + final ppG0 = PartialProductGeneratorCompactRectSignExtension( a, b, RadixEncoder(4), signedMultiplicand: true, signedMultiplier: true); From c1f44d98336039733a67d14ca6bba7fd3d5485fb Mon Sep 17 00:00:00 2001 From: Galileo Newton Date: Sat, 11 Jan 2025 17:46:26 -0800 Subject: [PATCH 06/14] changed dead pubdev links --- doc/components/floating_point.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/components/floating_point.md b/doc/components/floating_point.md index fe5b6f322..a6e0a8915 100644 --- a/doc/components/floating_point.md +++ b/doc/components/floating_point.md @@ -34,7 +34,7 @@ Finally, we have a [random value constructor](https://intel.github.io/rohd-hcl/r ## FloatingPoint -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. +The [FloatingPoint](https://intel.github.io/rohd-hcl/rohd_hcl/FloatingPoint-class.html) type is a [LogicStructure](https://intel.github.io/rohd/rohd/LogicStructure-class.html) which comprises the [Logic](https://intel.github.io/rohd/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](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. From 9357f80dbd6366359a6999b82d11ac64b61dd54e Mon Sep 17 00:00:00 2001 From: Galileo Newton Date: Sat, 11 Jan 2025 18:00:12 -0800 Subject: [PATCH 07/14] link fix again --- doc/components/floating_point.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/components/floating_point.md b/doc/components/floating_point.md index a6e0a8915..6f630c3e0 100644 --- a/doc/components/floating_point.md +++ b/doc/components/floating_point.md @@ -1,6 +1,6 @@ # 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](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. +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://intel.github.io/rohd/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 @@ -40,7 +40,7 @@ Again, like [FloatingPointValue](https://intel.github.io/rohd-hcl/rohd_hcl/Floa ## FloatingPointAdder -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. +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://intel.github.io/rohd/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](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. From b001cf7493533a4f6e693498e832c6eaada0c5cd Mon Sep 17 00:00:00 2001 From: Galileo Newton Date: Sat, 11 Jan 2025 20:11:03 -0800 Subject: [PATCH 08/14] doc improvements --- .../arithmetic/evaluate_partial_product.dart | 4 +- lib/src/arithmetic/multiplier.dart | 4 +- .../arithmetic/partial_product_generator.dart | 58 +++++-------------- .../partial_product_sign_extend.dart | 38 ++++++------ test/arithmetic/addend_compressor_test.dart | 2 +- test/arithmetic/multiplier_encoder_test.dart | 15 ++--- 6 files changed, 50 insertions(+), 71 deletions(-) diff --git a/lib/src/arithmetic/evaluate_partial_product.dart b/lib/src/arithmetic/evaluate_partial_product.dart index 97339bea9..bbf82bab4 100644 --- a/lib/src/arithmetic/evaluate_partial_product.dart +++ b/lib/src/arithmetic/evaluate_partial_product.dart @@ -11,7 +11,7 @@ import 'package:rohd/rohd.dart'; import 'package:rohd_hcl/rohd_hcl.dart'; /// The following routines are useful only during testing -extension TestPartialProductSignage on PartialProductGenerator { +extension TestPartialProductSignage on PartialProductGeneratorBase { /// Return true if multiplicand is truly signed (fixed or runtime) bool isSignedMultiplicand() => (selectSignedMultiplicand == null) ? signedMultiplicand @@ -28,7 +28,7 @@ extension TestPartialProductSignage on PartialProductGenerator { /// Debug routines for printing out partial product matrix during /// simulation with live logic values -extension EvaluateLivePartialProduct on PartialProductGenerator { +extension EvaluateLivePartialProduct on PartialProductGeneratorBase { /// Accumulate the partial products and return as BigInt BigInt evaluate() { final maxW = maxWidth(); diff --git a/lib/src/arithmetic/multiplier.dart b/lib/src/arithmetic/multiplier.dart index 4906fe632..9fd232300 100644 --- a/lib/src/arithmetic/multiplier.dart +++ b/lib/src/arithmetic/multiplier.dart @@ -241,7 +241,7 @@ class CompressionTreeMultiplier extends Multiplier { ParallelPrefix Function( List inp, Logic Function(Logic term1, Logic term2)) ppTree = KoggeStone.new, - PartialProductSignExtension Function(PartialProductGenerator pp, + PartialProductSignExtension Function(PartialProductGeneratorBase pp, {String name}) seGen = CompactRectSignExtension.new, super.name = 'compression_tree_multiplier'}) { @@ -337,7 +337,7 @@ class CompressionTreeMultiplyAccumulate extends MultiplyAccumulate { ParallelPrefix Function( List inps, Logic Function(Logic term1, Logic term2)) ppTree = KoggeStone.new, - PartialProductGenerator Function(Logic, Logic, RadixEncoder, + PartialProductGeneratorBase Function(Logic, Logic, RadixEncoder, {required bool signedMultiplier, required bool signedMultiplicand, Logic? selectSignedMultiplier, diff --git a/lib/src/arithmetic/partial_product_generator.dart b/lib/src/arithmetic/partial_product_generator.dart index 918e111a3..c8ceeb962 100644 --- a/lib/src/arithmetic/partial_product_generator.dart +++ b/lib/src/arithmetic/partial_product_generator.dart @@ -25,7 +25,7 @@ class SignBit extends Logic { } /// A [PartialProductArray] is a class that holds a set of partial products -/// for manipulation by [PartialProductGenerator] and [ColumnCompressor]. +/// for manipulation by [PartialProductGeneratorBase] and [ColumnCompressor]. abstract class PartialProductArray { /// name used for PartialProductGenerators final String name; @@ -43,7 +43,7 @@ abstract class PartialProductArray { /// extension routines late final List> partialProducts; - /// rows of partial products + /// Number of rows of partial products. int get rows => partialProducts.length; /// Return the actual largest width of all rows @@ -181,34 +181,33 @@ abstract class PartialProductArray { partialProducts[row].insertAll(col - rowShift[row], list); } -/// A [PartialProductGenerator] class that generates a set of partial products. -/// Essentially a set of -/// shifted rows of [Logic] addends generated by Booth recoding and -/// manipulated by sign extension, before being compressed -abstract class PartialProductGenerator extends PartialProductArray { - /// Get the shift increment between neighboring product rows +/// A [PartialProductGeneratorBase] class that generates a set of partial +/// products. Essentially a set of shifted rows of [Logic] addends generated by +/// Booth recoding and manipulated by sign extension, before being compressed. +abstract class PartialProductGeneratorBase extends PartialProductArray { + /// Get the shift increment between neighboring product rows. int get shift => selector.shift; - /// The multiplicand term + /// The multiplicand term. Logic get multiplicand => selector.multiplicand; - /// The multiplier term + /// The multiplier term. Logic get multiplier => encoder.multiplier; - /// Encoder for the full multiply operand + /// Encoder for the full multiply operand. late final MultiplierEncoder encoder; /// Selector for the multiplicand which uses the encoder to index into - /// multiples of the multiplicand and generate partial products + /// multiples of the multiplicand and generate partial products. late final MultiplicandSelector selector; - /// [multiplicand] operand is always signed + /// [multiplicand] operand is always signed. final bool signedMultiplicand; - /// [multiplier] operand is always signed + /// [multiplier] operand is always signed. final bool signedMultiplier; - /// Used to avoid sign extending more than once + /// Used to avoid sign extending more than once. bool isSignExtended = false; /// If not null, use this signal to select between signed and unsigned @@ -219,12 +218,12 @@ abstract class PartialProductGenerator extends PartialProductArray { /// [multiplier]. final Logic? selectSignedMultiplier; - /// Construct a [PartialProductGenerator] -- the partial product matrix. + /// Construct a [PartialProductGeneratorBase] -- the partial product matrix. /// /// [signedMultiplier] generates a fixed signed encoder versus using /// [selectSignedMultiplier] which is a runtime sign selection [Logic] /// in which case [signedMultiplier] must be false. - PartialProductGenerator( + PartialProductGeneratorBase( Logic multiplicand, Logic multiplier, RadixEncoder radixEncoder, {this.signedMultiplicand = false, this.signedMultiplier = false, @@ -271,29 +270,4 @@ abstract class PartialProductGenerator extends PartialProductArray { rowShift.add(row * shift); } } - - /// Helper function for sign extension routines: - /// For signed operands, set the MSB to [sign], otherwise add this [sign] bit. - void addStopSign(List addend, SignBit sign) { - if (!signedMultiplicand) { - addend.add(sign); - } else { - addend.last = sign; - } - } - - /// Helper function for sign extension routines: - /// For signed operands, flip the MSB, otherwise add this [sign] bit. - void addStopSignFlip(List addend, SignBit sign) { - if (!signedMultiplicand) { - if (selectSignedMultiplicand == null) { - addend.add(sign); - } else { - addend.add(SignBit(mux(selectSignedMultiplicand!, ~addend.last, sign), - inverted: selectSignedMultiplicand != null)); - } - } else { - addend.last = SignBit(~addend.last, inverted: true); - } - } } diff --git a/lib/src/arithmetic/partial_product_sign_extend.dart b/lib/src/arithmetic/partial_product_sign_extend.dart index f0148b172..8cef373fa 100644 --- a/lib/src/arithmetic/partial_product_sign_extend.dart +++ b/lib/src/arithmetic/partial_product_sign_extend.dart @@ -12,7 +12,7 @@ import 'dart:math'; import 'package:rohd/rohd.dart'; import 'package:rohd_hcl/rohd_hcl.dart'; -/// Methods for sign extending the [PartialProductGenerator] +/// Methods for sign extending the [PartialProductGeneratorBase] enum SignExtension { /// No sign extension none, @@ -31,7 +31,7 @@ enum SignExtension { } /// Used to test different sign extension methods -typedef PPGFunction = PartialProductGenerator Function( +typedef PPGFunction = PartialProductGeneratorBase Function( Logic a, Logic b, RadixEncoder radixEncoder, {bool signedMultiplicand, Logic? selectSignedMultiplicand, @@ -44,7 +44,7 @@ abstract class PartialProductSignExtension { final String name; /// The partial product generator we are sign extending. - final PartialProductGenerator ppg; + final PartialProductGeneratorBase ppg; /// multiplicand operand is always signed. bool get signedMultiplicand => ppg.signedMultiplicand; @@ -60,25 +60,28 @@ abstract class PartialProductSignExtension { /// multiplier. Logic? get selectSignedMultiplier => ppg.selectSignedMultiplier; - /// in PPA + /// Number of rows of partial products. int get rows => ppg.rows; - /// in PPA + /// The actual shift in each row. This value will be modified by the + /// sign extension routine used when folding in a sign bit from another + /// row. List get rowShift => ppg.rowShift; - /// in PPA + /// Partial Products output. Generated by selector and extended by sign + /// extension routines. List> get partialProducts => ppg.partialProducts; - /// should be in ppa + /// Used to avoid sign extending more than once. bool get isSignExtended => ppg.isSignExtended; set isSignExtended(bool set) { ppg.isSignExtended = set; } - /// Could override in ppa + /// Get the shift increment between neighboring product rows. int get shift => ppg.shift; - /// Need signs[] API instead + /// Encoder for the full multiply operand. Used here just to get signs[]. MultiplierEncoder get encoder => ppg.encoder; // signs getter // is multiplicand.width == entry.length? @@ -86,7 +89,7 @@ abstract class PartialProductSignExtension { /// Only used to get width as above MultiplicandSelector get selector => ppg.selector; // selector.width accessed - /// Sign Extension class that operates on a [PartialProductGenerator] + /// Sign Extension class that operates on a [PartialProductGeneratorBase] /// and sign-extends the entries. PartialProductSignExtension(this.ppg, {this.name = 'no_sign_extension'}) { // @@ -130,7 +133,7 @@ abstract class PartialProductSignExtension { /// Used to test different sign extension methods typedef SignExtensionFunction = PartialProductSignExtension - Function(PartialProductGenerator ppg, {String name}); + Function(PartialProductGeneratorBase ppg, {String name}); /// Used to test different sign extension methods SignExtensionFunction currySignExtensionFunction(SignExtension signExtension) => @@ -157,7 +160,7 @@ class NoneSignExtension extends PartialProductSignExtension { } /// A concrete base class for partial product generation -class PartialProductGeneratorBasic extends PartialProductGenerator { +class PartialProductGeneratorBasic extends PartialProductGeneratorBase { /// The extension routine we will be using. late final PartialProductSignExtension extender; @@ -181,7 +184,8 @@ class PartialProductGeneratorBasic extends PartialProductGenerator { /// A wrapper class for [NoneSignExtension] we used /// during refactoring to be compatible with old calls. -class PartialProductGeneratorNoneSignExtension extends PartialProductGenerator { +class PartialProductGeneratorNoneSignExtension + extends PartialProductGeneratorBase { /// The extension routine we will be using. late final PartialProductSignExtension extender; @@ -246,7 +250,7 @@ class BruteSignExtension extends PartialProductSignExtension { /// A wrapper class for [BruteSignExtension] we used /// during refactoring to be compatible with old calls. class PartialProductGeneratorBruteSignExtension - extends PartialProductGenerator { + extends PartialProductGeneratorBase { /// The extension routine we will be using. late final PartialProductSignExtension extender; @@ -388,7 +392,7 @@ class CompactSignExtension extends PartialProductSignExtension { /// A wrapper class for [CompactSignExtension] we used /// during refactoring to be compatible with old calls. class PartialProductGeneratorCompactSignExtension - extends PartialProductGenerator { + extends PartialProductGeneratorBase { /// The extension routine we will be using. late final PartialProductSignExtension extender; @@ -496,7 +500,7 @@ class StopBitsSignExtension extends PartialProductSignExtension { /// A wrapper class for [StopBitsSignExtension] we used /// during refactoring to be compatible with old calls. class PartialProductGeneratorStopBitsSignExtension - extends PartialProductGenerator { + extends PartialProductGeneratorBase { /// The extension routine we will be using. late final PartialProductSignExtension extender; @@ -521,7 +525,7 @@ class PartialProductGeneratorStopBitsSignExtension /// A wrapper class for CompactRectSignExtension we used /// during refactoring to be compatible with old calls. class PartialProductGeneratorCompactRectSignExtension - extends PartialProductGenerator { + extends PartialProductGeneratorBase { /// The extension routine we will be using. late final PartialProductSignExtension extender; diff --git a/test/arithmetic/addend_compressor_test.dart b/test/arithmetic/addend_compressor_test.dart index 6e53c4978..56214dcb7 100644 --- a/test/arithmetic/addend_compressor_test.dart +++ b/test/arithmetic/addend_compressor_test.dart @@ -18,7 +18,7 @@ import 'package:test/test.dart'; /// This [CompressorTestMod] module is used to test instantiation, where we can /// catch trace errors (IO not added) not found in a simple test instantiation. class CompressorTestMod extends Module { - late final PartialProductGenerator pp; + late final PartialProductGeneratorBase pp; late final ColumnCompressor compressor; diff --git a/test/arithmetic/multiplier_encoder_test.dart b/test/arithmetic/multiplier_encoder_test.dart index 0e56558ff..6ed65be82 100644 --- a/test/arithmetic/multiplier_encoder_test.dart +++ b/test/arithmetic/multiplier_encoder_test.dart @@ -26,7 +26,7 @@ import 'package:test/test.dart'; // - Rectangular: again, need to cross a shift interval // - Sign Extension: [brute, stop, compact, compactRect] -void testPartialProductExhaustive(PartialProductGenerator pp) { +void testPartialProductExhaustive(PartialProductGeneratorBase pp) { final widthX = pp.selector.multiplicand.width; final widthY = pp.encoder.multiplier.width; @@ -72,7 +72,7 @@ void testPartialProductExhaustive(PartialProductGenerator pp) { }); } -void testPartialProductRandom(PartialProductGenerator pp, int iterations) { +void testPartialProductRandom(PartialProductGeneratorBase pp, int iterations) { final widthX = pp.selector.multiplicand.width; final widthY = pp.encoder.multiplier.width; @@ -119,7 +119,8 @@ void testPartialProductRandom(PartialProductGenerator pp, int iterations) { }); } -void testPartialProductSingle(PartialProductGenerator pp, BigInt X, BigInt Y) { +void testPartialProductSingle( + PartialProductGeneratorBase pp, BigInt X, BigInt Y) { test( 'single: ${pp.name} R${pp.selector.radix} ' 'WD=${pp.multiplicand.width} WM=${pp.multiplier.width} ' @@ -137,7 +138,7 @@ void testPartialProductSingle(PartialProductGenerator pp, BigInt X, BigInt Y) { }); } -void checkPartialProduct(PartialProductGenerator pp, BigInt iX, BigInt iY) { +void checkPartialProduct(PartialProductGeneratorBase pp, BigInt iX, BigInt iY) { final widthX = pp.selector.multiplicand.width; final widthY = pp.encoder.multiplier.width; @@ -198,7 +199,7 @@ void main() { SignedBigInt.fromSignedInt(j, width, signed: signedMultiplier); a.put(X); b.put(Y); - final PartialProductGenerator pp; + final PartialProductGeneratorBase pp; pp = PartialProductGeneratorBasic(a, b, encoder, signedMultiplicand: signedMultiplicand, signedMultiplier: signedMultiplier); @@ -224,7 +225,7 @@ void main() { for (final signExtension in SignExtension.values .where((e) => e != SignExtension.none)) { final width = log2Ceil(radix) + (signMultiplier ? 1 : 0); - final PartialProductGenerator pp; + final PartialProductGeneratorBase pp; pp = PartialProductGeneratorBasic( Logic(name: 'X', width: width), Logic(name: 'Y', width: width), @@ -258,7 +259,7 @@ void main() { for (final selectMultiplier in [false, true]) { selectSignMultiplicand.put(selectMultiplicand ? 1 : 0); selectSignMultiplier.put(selectMultiplier ? 1 : 0); - final PartialProductGenerator pp; + final PartialProductGeneratorBase pp; pp = PartialProductGeneratorStopBitsSignExtension( Logic(name: 'X', width: width), Logic(name: 'Y', width: width), From c093d4d45b365e95d568cb2576ff3966d152592e Mon Sep 17 00:00:00 2001 From: Galileo Newton Date: Sun, 12 Jan 2025 09:20:04 -0800 Subject: [PATCH 09/14] documentation updates --- doc/components/adder.md | 32 +++++++++------- doc/components/multiplier.md | 51 ++++++++++++------------- doc/components/multiplier_components.md | 8 ++-- lib/src/arithmetic/multiplier.dart | 2 +- 4 files changed, 47 insertions(+), 46 deletions(-) diff --git a/doc/components/adder.md b/doc/components/adder.md index 0c162052f..93547fdb4 100644 --- a/doc/components/adder.md +++ b/doc/components/adder.md @@ -12,7 +12,7 @@ ROHD-HCL provides a set of adder modules to get the sum from a pair of Logic. So 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](https://intel.github.io/rohd-hcl/rohd_hcl/RohdHclException-class.html) will be thrown. +The [adder](https://intel.github.io/rohd-hcl/rohd_hcl/adder-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. @@ -23,8 +23,8 @@ final b = Logic(name: 'b', width: 8); a.put(5); b.put(5); -final rippleCarryAdder = RippleCarryAdder(a, b); -final sum = rippleCarryAdder.sum; +final adder = adder(a, b); +final sum = adder.sum; ``` ## Parallel Prefix Adder @@ -68,7 +68,7 @@ Here is an example of instantiating a [OnesComplementAdder](https://intel.githu b.put(bv); final carry = Logic(); final adder = OnesComplementAdder( - a, b, carryOut: carry, adderGen: RippleCarryAdder.new, + a, b, carryOut: carry, adderGen: adder.new, subtract: true); final mag = adder.sum.value.toInt() + (carry.value.isZero ? 0 : 1)); final out = (adder.sign.value.toInt() == 1 ? -mag : mag); @@ -96,7 +96,7 @@ Here is an example of instantiating a [SignMagnitudeAdder](https://intel.github. b.put(18); bSign.put(0); - final adder = SignMagnitudeAdder(aSign, a, bSign, b, adderGen: RippleCarryAdder.new, + final adder = SignMagnitudeAdder(aSign, a, bSign, b, adderGen: adder.new, largestMagnitudeFirst: true); final sum = adder.sum; @@ -112,14 +112,18 @@ The [`CarrySelectCompoundAdder`](https://intel.github.io/rohd-hcl/rohd_hcl/Carry The delay of the adder is defined by the combination of the sub-adders and the accumulated carry-select chain delay. 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. +The compound adder forms a select chain around a set of adders specified by: -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](). +- `addergen`: an adder generator functor option to build the block adders with the default being `ParallelPrefixAdder`. -The `adderGen` input selects the type of sub-adder used, with the default being `ParallelPrefixAdder`. +The compound adder generator provides two algorithms for splitting the adder into adder sub-blocks: + +- `splitSelectAdderAlgorithmSingleBlock: + - 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. + +- `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](). An example is shown below to add two inputs of signals that have 8-bits of width. @@ -130,10 +134,10 @@ final b = Logic(name: 'b', width: 8); a.put(5); b.put(5); -final rippleCarryAdder = CarrySelectCompoundAdder(a, b); -final sum = rippleCarryAdder.sum; -final sum1 = rippleCarryAdder.sum1; +final adder = CarrySelectCompoundAdder(a, b); +final sum = adder.sum; +final sum1 = adder.sum1; -final rippleCarryAdder4BitBlock = CarrySelectCompoundAdder(a, b, +final adder4BitBlock = CarrySelectCompoundAdder(a, b, widthGen: CarrySelectCompoundAdder.splitSelectAdderAlgorithm4Bit); ``` diff --git a/doc/components/multiplier.md b/doc/components/multiplier.md index b6eeab299..75a71c6f5 100644 --- a/doc/components/multiplier.md +++ b/doc/components/multiplier.md @@ -1,6 +1,6 @@ -# Multiplier +# Integer Multiplier -ROHD-HCL provides an abstract `Multiplier` module which multiplies two +ROHD-HCL provides an abstract [Multiplier](https://intel.github.io/rohd-hcl/rohd_hcl/Multiplier-class.html) module which multiplies two numbers represented as two `Logic`s, potentially of different widths, treating them as either signed (twos' complement) or unsigned. It produces the product as a `Logic` with width equal to the sum of the @@ -16,7 +16,7 @@ of this abstract `Module`: - [Compression Tree Multiplier](#compression-tree-multiplier) An additional kind of abstract module provided is a -`MultiplyAccumulate` module which multiplies two numbers represented +[MultiplierAccumulate](https://intel.github.io/rohd-hcl/rohd_hcl/MultiplyAccumulate-class.html) 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. Similar to the `Multiplier`, the signs of the operands are either fixed by a parameter, @@ -86,23 +86,24 @@ Simulator.endSimulation(); A compression tree multiplier is a digital circuit used for performing multiplication operations, using Booth encoding to produce addends, a -compression tree for reducing addends to a final pair, and a final -adder generated from a parallel prefix tree option. It is particularly -useful in applications that require high speed multiplication, such as -digital signal processing. +compression tree for reducing addends to a final pair, and a final adder +generated from a parallel prefix tree functor parameter. It is particularly +useful in applications that require high speed and varying width multiplication, +such as digital signal processing. The parameters of the -`CompressionTreeMultiplier` are: +[CompressionTreeMultiplier](https://intel.github.io/rohd-hcl/rohd_hcl/CompressionTreeMultiplier-class.html) are: - 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). -- `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 (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. +- `seGen` parameter: the type of `PartialProductSignExtension` functor 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 `CompactRectSignExtension` does not). See [Sign Extension Options](./multiplier_components.md#sign-extension-option). +- Signed or unsigned operands: + - `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. +- Alternatively, it supports runtime control of signage: + - An optional `selectSignedMultiplicand` control signal which allows 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 allows 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, making the multiplier operate in 2 cycles. Here is an example of use of the `CompressionTreeMultiplier` with one signed input: @@ -130,22 +131,18 @@ A compression tree multiply-accumulate is similar to a compress tree multiplier, but it inserts an additional addend into the compression tree to allow for accumulation into this third input. -The parameters of the -`CompressionTreeMultiplyAccumulate` are: +The additional parameters of the +[CompressionTreeMultiplyAccumulate](https://intel.github.io/rohd-hcl/rohd_hcl/CompressionTreeMultiplyAccumulate-class.html) over the [CompressionTreeMltiplier](#compression-tree-multiplier) are: -- 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` (default Kogge-Stone). -- `esGen` parameter: the type of `PartialProductSignExtension` 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 `CompactRectSignExtension`). -- `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 (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. +- Addend signage: + - `signedAddend` parameter: whether the addend (third arg) should be treated as signed (twos' complement) or unsigned +OR + - An optional `selectSignedAddend` control signal allows for runtime control of signed or unsigned operation with the same hardware. `signedAddend` 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. +The output width of the `CompressionTreeMultiplier` is the sum of the product term widths plus one to accomodate the additional acccumulate term. + Here is an example of using the `CompressionTreeMultiplyAccumulate` with all inputs as signed: ```dart diff --git a/doc/components/multiplier_components.md b/doc/components/multiplier_components.md index 0b2875191..ed5f2c606 100644 --- a/doc/components/multiplier_components.md +++ b/doc/components/multiplier_components.md @@ -51,7 +51,7 @@ row slice mult 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 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). + Here is the matrix with a crude sign extension `brute` (the table formatting is available from our [PartialProductGenerator](https://intel.github.io/rohd-hcl/rohd_hcl/PartialProductGenerator-class.html) 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 @@ -90,7 +90,7 @@ Note that radix-4 shifts by 2 positions each row, but with only two rows and wit ## Partial Product Generator -The base class of `PartialProductGenerator` is `PartialProductArray` which is simply a `List>` to represent addends and a `rowShift[row]` to represent the shifts in the partial product matrix. If customization is needed beyond sign extension options, routines are provided that allow for fixed customization of bit positions or conditional (mux based on a Logic) form in the `PartialProductArray`. +The base class of `PartialProductGenerator` is [PartialProductArray](https://intel.github.io/rohd-hcl/rohd_hcl/PartialProductArray-class.html) which is simply a `List>` to represent addends and a `rowShift[row]` to represent the shifts in the partial product matrix. If customization is needed beyond sign extension options, routines are provided that allow for fixed customization of bit positions or conditional (mux based on a Logic) form in the `PartialProductArray`. ```dart final ppa = PartialProductArray(a,b); @@ -100,7 +100,7 @@ ppa.muxAbsolute(row, col, condition, logic); ppa.muxAbsoluteAll(row, col, condition, List); ``` - The `PartialProductGenerator` adds to this the `RadixEncoder` to encode the rows along with a matching `MultiplicandSelector` to create the actual mantissas used in each row. + The `PartialProductGenerator` adds to this the [RadixEncoder](https://intel.github.io/rohd-hcl/rohd_hcl/RadixEncoder-class.html) to encode the rows along with a matching `MultiplicandSelector` to create the actual mantissas used in each row. As a building block which creates a set of rows of partial products from a multiplicand and a multiplier, it maintains the partial products as a list of rows om the `PartialProductArray` base. Its primary inputs are the multiplicand, multiplier, `RadixEncoder`, and whether the operands are signed. @@ -175,7 +175,7 @@ You can also generate a Markdown form of the same matrix: 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. -Our `ColumnCompressor` class uses a delay-driven approach to efficiently compress the rows of the partial product matrix. Its only argument is a `PartialProductArray` (base class of `PartialProductGenerator`), and it creates a list of `ColumnQueue`s containing the final two addends stored by column after compression. An `extractRow`routine can be used to extract the columns. `ColumnCompressor` currently has an extension `EvaluateColumnCompressor` which can be used to print out the compression progress. Here is the legend for these printouts. +Our [ColumnCompressor](https://intel.github.io/rohd-hcl/rohd_hcl/ColumnCompressor-class.html) class uses a delay-driven approach to efficiently compress the rows of the partial product matrix. Its only argument is a `PartialProductArray` (base class of `PartialProductGenerator`), and it creates a list of `ColumnQueue`s containing the final two addends stored by column after compression. An `extractRow`routine can be used to extract the columns. `ColumnCompressor` currently has an extension `EvaluateColumnCompressor` which can be used to print out the compression progress. Here is the legend for these printouts. - `ppR,C` = partial product entry at row R, column C - `sR,C` = sum term coming last from row R, column C diff --git a/lib/src/arithmetic/multiplier.dart b/lib/src/arithmetic/multiplier.dart index 9fd232300..bf660ed69 100644 --- a/lib/src/arithmetic/multiplier.dart +++ b/lib/src/arithmetic/multiplier.dart @@ -188,7 +188,7 @@ abstract class MultiplyAccumulate extends Module { } } -/// An implementation of an integer multiplier using compression trees +/// An implementation of an integer multiplier using compression trees. class CompressionTreeMultiplier extends Multiplier { /// The clk for the pipelined version of column compression. Logic? clk; From d318e541f0df6ae63f703993a94f42b893c60d4e Mon Sep 17 00:00:00 2001 From: Galileo Newton Date: Sun, 12 Jan 2025 12:15:26 -0800 Subject: [PATCH 10/14] typo in link --- doc/components/adder.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/components/adder.md b/doc/components/adder.md index 93547fdb4..bbb1f6890 100644 --- a/doc/components/adder.md +++ b/doc/components/adder.md @@ -12,7 +12,7 @@ ROHD-HCL provides a set of adder modules to get the sum from a pair of Logic. So 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 [adder](https://intel.github.io/rohd-hcl/rohd_hcl/adder-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. +The [adder](https://intel.github.io/rohd-hcl/rohd_hcl/Adder-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. From fed8c607c10811b46ca017bf1847869badc50ba6 Mon Sep 17 00:00:00 2001 From: Galileo Newton Date: Tue, 14 Jan 2025 23:35:22 -0800 Subject: [PATCH 11/14] remove last of the old sign extension routines --- .../partial_product_sign_extend.dart | 36 +++---------------- 1 file changed, 5 insertions(+), 31 deletions(-) diff --git a/lib/src/arithmetic/partial_product_sign_extend.dart b/lib/src/arithmetic/partial_product_sign_extend.dart index 8cef373fa..caffc6eb5 100644 --- a/lib/src/arithmetic/partial_product_sign_extend.dart +++ b/lib/src/arithmetic/partial_product_sign_extend.dart @@ -92,7 +92,6 @@ abstract class PartialProductSignExtension { /// Sign Extension class that operates on a [PartialProductGeneratorBase] /// and sign-extends the entries. PartialProductSignExtension(this.ppg, {this.name = 'no_sign_extension'}) { - // if (signedMultiplier && (selectSignedMultiplier != null)) { throw RohdHclException('sign reconfiguration requires signed=false'); } @@ -145,11 +144,11 @@ SignExtensionFunction currySignExtensionFunction(SignExtension signExtension) => SignExtension.compactRect => CompactRectSignExtension.new, }; -/// These other sign extensions are for assisting with testing and debugging. -/// More robust and simpler sign extensions in case -/// complex sign extension routines obscure other bugs. -/// -/// /// A Partial Product Generator using None Sign Extension +/// A range of SignExtension classes to be used in building new arithmetic +/// building blocks. Start with [BruteSignExtension] when composing new +/// partial product array shapes as it should work in all situations. + +/// A Partial Product Generator using None Sign Extension class NoneSignExtension extends PartialProductSignExtension { /// Construct a no sign-extension class. NoneSignExtension(super.ppg, {super.name = 'none_sign_extension'}); @@ -182,31 +181,6 @@ class PartialProductGeneratorBasic extends PartialProductGeneratorBase { } } -/// A wrapper class for [NoneSignExtension] we used -/// during refactoring to be compatible with old calls. -class PartialProductGeneratorNoneSignExtension - extends PartialProductGeneratorBase { - /// The extension routine we will be using. - late final PartialProductSignExtension extender; - - /// Construct a none sign extending Partial Product Generator - PartialProductGeneratorNoneSignExtension( - super.multiplicand, super.multiplier, super.radixEncoder, - {super.signedMultiplicand, - super.signedMultiplier, - super.selectSignedMultiplicand, - super.selectSignedMultiplier, - super.name = 'none'}) { - extender = NoneSignExtension(this); - signExtend(); - } - - @override - void signExtend() { - extender.signExtend(); - } -} - /// A Brute Sign Extension class. class BruteSignExtension extends PartialProductSignExtension { /// Construct a brute-force sign extending Partial Product Generator From daf4dd794efd61d9109628f17bf76a5f25c2b0fd Mon Sep 17 00:00:00 2001 From: Galileo Newton Date: Wed, 15 Jan 2025 16:04:13 -0800 Subject: [PATCH 12/14] attempt to fix conflicts with main --- lib/src/arithmetic/multiplier.dart | 22 +++++--------- .../config_compression_tree_multiplier.dart | 29 ++++++++++--------- test/arithmetic/multiplier_test.dart | 2 -- 3 files changed, 23 insertions(+), 30 deletions(-) diff --git a/lib/src/arithmetic/multiplier.dart b/lib/src/arithmetic/multiplier.dart index bf660ed69..db734aa87 100644 --- a/lib/src/arithmetic/multiplier.dart +++ b/lib/src/arithmetic/multiplier.dart @@ -204,7 +204,7 @@ class CompressionTreeMultiplier extends Multiplier { Logic get product => output('product'); /// Construct a compression tree integer multiplier with a given [radix] - /// and prefix tree functor [ppTree] for the compressor and final adder. + /// and an [Adder] generator functor [adderGen] for the final adder. /// /// Sign extension methodology is defined by the partial product generator /// supplied via [seGen]. @@ -238,9 +238,8 @@ class CompressionTreeMultiplier extends Multiplier { super.signedMultiplier = false, super.selectSignedMultiplicand, super.selectSignedMultiplier, - ParallelPrefix Function( - List inp, Logic Function(Logic term1, Logic term2)) - ppTree = KoggeStone.new, + Adder Function(Logic a, Logic b, {Logic? carryIn}) adderGen = + ParallelPrefixAdder.new, PartialProductSignExtension Function(PartialProductGeneratorBase pp, {String name}) seGen = CompactRectSignExtension.new, @@ -265,9 +264,7 @@ class CompressionTreeMultiplier extends Multiplier { final compressor = ColumnCompressor(clk: clk, reset: reset, enable: enable, pp) ..compress(); - final adder = ParallelPrefixAdder( - compressor.extractRow(0), compressor.extractRow(1), - ppGen: ppTree); + final adder = adderGen(compressor.extractRow(0), compressor.extractRow(1)); product <= adder.sum.slice(a.width + b.width - 1, 0); } } @@ -291,7 +288,7 @@ class CompressionTreeMultiplyAccumulate extends MultiplyAccumulate { Logic get accumulate => output('accumulate'); /// Construct a compression tree integer multiply-add with a given [radix] - /// and prefix tree functor [ppTree] for the compressor and final adder. + /// and an [Adder] generator functor [adderGen] for the final adder. /// /// [a] and [b] are the product terms, [c] is the accumulate term which /// must be the sum of the widths plus 1. @@ -334,9 +331,8 @@ class CompressionTreeMultiplyAccumulate extends MultiplyAccumulate { super.selectSignedMultiplicand, super.selectSignedMultiplier, super.selectSignedAddend, - ParallelPrefix Function( - List inps, Logic Function(Logic term1, Logic term2)) - ppTree = KoggeStone.new, + Adder Function(Logic a, Logic b, {Logic? carryIn}) adderGen = + ParallelPrefixAdder.new, PartialProductGeneratorBase Function(Logic, Logic, RadixEncoder, {required bool signedMultiplier, required bool signedMultiplicand, @@ -384,9 +380,7 @@ class CompressionTreeMultiplyAccumulate extends MultiplyAccumulate { final compressor = ColumnCompressor(clk: clk, reset: reset, enable: enable, pp) ..compress(); - final adder = ParallelPrefixAdder( - compressor.extractRow(0), compressor.extractRow(1), - ppGen: ppTree); + final adder = adderGen(compressor.extractRow(0), compressor.extractRow(1)); accumulate <= adder.sum.slice(a.width + b.width - 1 + 1, 0); } } diff --git a/lib/src/component_config/components/config_compression_tree_multiplier.dart b/lib/src/component_config/components/config_compression_tree_multiplier.dart index 5b9e77649..c80f19c28 100644 --- a/lib/src/component_config/components/config_compression_tree_multiplier.dart +++ b/lib/src/component_config/components/config_compression_tree_multiplier.dart @@ -14,26 +14,27 @@ import 'package:rohd_hcl/rohd_hcl.dart'; /// A [Configurator] for [CompressionTreeMultiplier]s. class CompressionTreeMultiplierConfigurator extends Configurator { - /// Map from Type to Function for Parallel Prefix generator - static Map, Logic Function(Logic, Logic))> - generatorMap = { - Ripple: Ripple.new, - Sklansky: Sklansky.new, - KoggeStone: KoggeStone.new, - BrentKung: BrentKung.new + /// Map from Type to Function for Adder generator + 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, {carryIn}) => + ParallelPrefixAdder(a, b, ppGen: BrentKung.new), }; - /// Controls the type of [ParallelPrefix] tree used in the adder. - final prefixTreeKnob = - ChoiceConfigKnob(generatorMap.keys.toList(), value: KoggeStone); - /// Controls the Booth encoding radix of the multiplier.! final radixKnob = ChoiceConfigKnob( [2, 4, 8, 16], value: 4, ); + /// Controls the type of [Adder] used for internal adders. + final adderTypeKnob = + ChoiceConfigKnob(adderGeneratorMap.keys.toList(), value: KoggeStone); + /// Controls the width of the multiplicand.! final IntConfigKnob multiplicandWidthKnob = IntConfigKnob(value: 5); @@ -63,11 +64,11 @@ class CompressionTreeMultiplierConfigurator extends Configurator { signMultiplicandValueKnob.value == 'selected' ? Logic() : null, selectSignedMultiplier: signMultiplierValueKnob.value == 'selected' ? Logic() : null, - ppTree: generatorMap[prefixTreeKnob.value]!); + adderGen: adderGeneratorMap[adderTypeKnob.value]!); @override late final Map> knobs = UnmodifiableMapView({ - 'Tree type': prefixTreeKnob, + 'Adder type': adderTypeKnob, 'Radix': radixKnob, 'Multiplicand width': multiplicandWidthKnob, 'Multiplicand sign': signMultiplicandValueKnob, diff --git a/test/arithmetic/multiplier_test.dart b/test/arithmetic/multiplier_test.dart index 25bc550f5..ad7ad75e5 100644 --- a/test/arithmetic/multiplier_test.dart +++ b/test/arithmetic/multiplier_test.dart @@ -201,7 +201,6 @@ void main() { ' SelM=${(selectSignedMultiplier != null) ? 1 : 0}'; return (a, b, {selectSignedMultiplicand, selectSignedMultiplier}) => CompressionTreeMultiplier(a, b, radix, - ppTree: ppTree, signedMultiplicand: signedMultiplicand, signedMultiplier: signedMultiplier, selectSignedMultiplicand: selectSignedMultiplicand, @@ -257,7 +256,6 @@ void main() { ' SelM=${(selectSignedMultiplier != null) ? 1 : 0}'; return (a, b, c) => CompressionTreeMultiplyAccumulate(a, b, c, radix, - ppTree: ppTree, signedMultiplicand: signedMultiplicand, signedMultiplier: signedMultiplier, signedAddend: signedAddend, From d0ee832519d8670d2a4cf9ea887cede29b43591a Mon Sep 17 00:00:00 2001 From: Galileo Newton Date: Wed, 15 Jan 2025 16:11:58 -0800 Subject: [PATCH 13/14] closer to main --- lib/src/arithmetic/multiplier.dart | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/src/arithmetic/multiplier.dart b/lib/src/arithmetic/multiplier.dart index db734aa87..4f056490f 100644 --- a/lib/src/arithmetic/multiplier.dart +++ b/lib/src/arithmetic/multiplier.dart @@ -333,19 +333,16 @@ class CompressionTreeMultiplyAccumulate extends MultiplyAccumulate { super.selectSignedAddend, Adder Function(Logic a, Logic b, {Logic? carryIn}) adderGen = ParallelPrefixAdder.new, - PartialProductGeneratorBase Function(Logic, Logic, RadixEncoder, - {required bool signedMultiplier, - required bool signedMultiplicand, - Logic? selectSignedMultiplier, - Logic? selectSignedMultiplicand}) - ppGen = PartialProductGeneratorCompactRectSignExtension.new, + PartialProductSignExtension Function(PartialProductGeneratorBase pp, + {String name}) + seGen = CompactRectSignExtension.new, super.name = 'compression_tree_mac'}) { clk = (clk != null) ? addInput('clk', clk) : null; reset = (reset != null) ? addInput('reset', reset) : null; enable = (enable != null) ? addInput('enable', enable) : null; final accumulate = addOutput('accumulate', width: a.width + b.width + 1); - final pp = ppGen( + final pp = PartialProductGeneratorBasic( a, b, RadixEncoder(radix), @@ -355,6 +352,8 @@ class CompressionTreeMultiplyAccumulate extends MultiplyAccumulate { signedMultiplier: signedMultiplier, ); + seGen(pp).signExtend(); + final lastLength = pp.partialProducts[pp.rows - 1].length + pp.rowShift[pp.rows - 1]; From a793992e7ae9431cb19b43b4cc076f07ad2eb30c Mon Sep 17 00:00:00 2001 From: Galileo Newton Date: Wed, 15 Jan 2025 16:24:44 -0800 Subject: [PATCH 14/14] formatting --- lib/src/arithmetic/multiplier.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/src/arithmetic/multiplier.dart b/lib/src/arithmetic/multiplier.dart index 021606737..5714d70f8 100644 --- a/lib/src/arithmetic/multiplier.dart +++ b/lib/src/arithmetic/multiplier.dart @@ -303,7 +303,7 @@ class CompressionTreeMultiplyAccumulate extends MultiplyAccumulate { /// always signed (default is unsigned). /// /// Sign extension methodology is defined by the partial product generator - /// supplied via [ppGen]. + /// supplied via [seGen]. /// /// Optional [selectSignedMultiplicand] allows for runtime configuration of /// signed or unsigned operation, overriding the [signedMultiplicand] static @@ -336,7 +336,6 @@ class CompressionTreeMultiplyAccumulate extends MultiplyAccumulate { PartialProductSignExtension Function(PartialProductGeneratorBase pp, {String name}) seGen = CompactRectSignExtension.new, - super.name = 'compression_tree_mac'}) { clk = (clk != null) ? addInput('clk', clk) : null; reset = (reset != null) ? addInput('reset', reset) : null;