diff --git a/lib/src/arithmetic/multiplier.dart b/lib/src/arithmetic/multiplier.dart index 9bc85c3d0..c8899b006 100644 --- a/lib/src/arithmetic/multiplier.dart +++ b/lib/src/arithmetic/multiplier.dart @@ -85,8 +85,7 @@ class CompressionTreeMultiplier extends Multiplier { ], (a, b) => Logic()).runtimeType}') { final product = addOutput('product', width: a.width + b.width); final pp = - PartialProductGenerator(a, b, RadixEncoder(radix), signed: signed) - ..signExtendCompact(); + PartialProductGenerator(a, b, RadixEncoder(radix), signed: signed); final compressor = ColumnCompressor(pp)..compress(); final adder = ParallelPrefixAdder( compressor.extractRow(0), compressor.extractRow(1), ppTree); @@ -110,8 +109,7 @@ class CompressionTreeMultiplyAccumulate extends MultiplyAccumulate { 'R${radix}_${ppTree.call([Logic()], (a, b) => Logic()).name}') { final accumulate = addOutput('accumulate', width: a.width + b.width + 1); final pp = - PartialProductGenerator(a, b, RadixEncoder(radix), signed: signed) - ..signExtendCompact(); + PartialProductGenerator(a, b, RadixEncoder(radix), signed: signed); // TODO(desmonddak): This sign extension method for the additional // addend may only work with signExtendCompact. diff --git a/lib/src/arithmetic/partial_product_generator.dart b/lib/src/arithmetic/partial_product_generator.dart index 95655a177..f71764a47 100644 --- a/lib/src/arithmetic/partial_product_generator.dart +++ b/lib/src/arithmetic/partial_product_generator.dart @@ -13,6 +13,24 @@ import 'package:rohd/rohd.dart'; import 'package:rohd_hcl/rohd_hcl.dart'; import 'package:rohd_hcl/src/arithmetic/multiplier_lib.dart'; +/// Methods for sign extending the [PartialProductGenerator] +enum SignExtension { + /// No sign extension + none, + + /// Brute force sign extend each row to the full width of the product + brute, + + /// Extend using stop bits in each row (and an extra row for final sign) + stop, + + /// Fold in last row sign bit (Mohanty, B.K., Choubey, A.) + compact, + + /// Sign folding that works for rectangular partial products + compactRect +} + /// A 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 @@ -54,7 +72,8 @@ class PartialProductGenerator { /// Construct the partial product matrix PartialProductGenerator( Logic multiplicand, Logic multiplier, RadixEncoder radixEncoder, - {this.signed = true}) { + {this.signed = true, + SignExtension signExtension = SignExtension.compactRect}) { encoder = MultiplierEncoder(multiplier, radixEncoder, signed: signed); selector = MultiplicandSelector(radixEncoder.radix, multiplicand, signed: signed); @@ -68,6 +87,18 @@ class PartialProductGenerator { '${selector.shift + (signed ? 1 : 0)}'); } _build(); + switch (signExtension) { + case SignExtension.none: + ; + case SignExtension.brute: + bruteForceSignExtend(); + case SignExtension.stop: + signExtendWithStopBitsRect(); + case SignExtension.compact: + signExtendCompact(); + case SignExtension.compactRect: + signExtendCompactRect(); + } } /// Setup the partial products array (partialProducts and rowShift) diff --git a/test/arithmetic/addend_compressor_test.dart b/test/arithmetic/addend_compressor_test.dart index f1b070505..602f06107 100644 --- a/test/arithmetic/addend_compressor_test.dart +++ b/test/arithmetic/addend_compressor_test.dart @@ -14,8 +14,6 @@ import 'package:rohd_hcl/rohd_hcl.dart'; import 'package:rohd_hcl/src/arithmetic/multiplier_lib.dart'; import 'package:test/test.dart'; -enum SignExtension { brute, stop, compact } - void testCompressionExhaustive(PartialProductGenerator pp) { final widthX = pp.selector.multiplicand.width; final widthY = pp.encoder.multiplier.width; @@ -86,17 +84,13 @@ void main() { final shift = log2Ceil(encoder.radix); for (var width = shift + 1; width < 2 * shift + 1; width++) { for (final signExtension in SignExtension.values) { + if (signExtension == SignExtension.none) { + continue; + } final pp = PartialProductGenerator(Logic(name: 'X', width: width), Logic(name: 'Y', width: width), encoder, - signed: signed); - switch (signExtension) { - case SignExtension.brute: - pp.bruteForceSignExtend(); - case SignExtension.stop: - pp.signExtendWithStopBitsRect(); - case SignExtension.compact: - pp.signExtendCompact(); - } + signed: signed, signExtension: signExtension); + testCompressionExhaustive(pp); } } @@ -124,8 +118,7 @@ void main() { b.put(bB); const radix = 4; final encoder = RadixEncoder(radix); - final pp = PartialProductGenerator(a, b, encoder, signed: signed) - ..signExtendCompactRect(); + final pp = PartialProductGenerator(a, b, encoder, signed: signed); // Turn on printing by using widthX == 6 (we are fooling the dead code // checking linter here) // print(pp); diff --git a/test/arithmetic/multiplier_encoder_test.dart b/test/arithmetic/multiplier_encoder_test.dart index d1052ce34..2bbecdffb 100644 --- a/test/arithmetic/multiplier_encoder_test.dart +++ b/test/arithmetic/multiplier_encoder_test.dart @@ -15,8 +15,6 @@ import 'package:rohd_hcl/rohd_hcl.dart'; import 'package:rohd_hcl/src/arithmetic/multiplier_lib.dart'; import 'package:test/test.dart'; -enum SignExtension { brute, stop, compact, compactRect } - void checkEvaluateExhaustive(PartialProductGenerator pp) { final widthX = pp.selector.multiplicand.width; final widthY = pp.encoder.multiplier.width; @@ -74,8 +72,7 @@ void main() { logicX.put(X); logicY.put(Y); logicZ.put(Z); - final pp = PartialProductGenerator(logicX, logicY, encoder) - ..signExtendCompact(); + final pp = PartialProductGenerator(logicX, logicY, encoder); // Add a row for addend final l = [ for (var i = 0; i < logicZ.width; i++) logicZ[i], @@ -102,19 +99,13 @@ void main() { final minWidth = shift + (signed ? 1 : 0); for (var width = minWidth; width < shift * 2 + 1; width++) { for (final signExtension in SignExtension.values) { + if (signExtension == SignExtension.none) { + continue; + } final pp = PartialProductGenerator(Logic(name: 'X', width: width), Logic(name: 'Y', width: width), encoder, - signed: signed); - switch (signExtension) { - case SignExtension.brute: - pp.bruteForceSignExtend(); - case SignExtension.stop: - pp.signExtendWithStopBitsRect(); - case SignExtension.compact: - pp.signExtendCompact(); - case SignExtension.compactRect: - pp.signExtendCompactRect(); - } + signed: signed, signExtension: signExtension); + checkEvaluateExhaustive(pp); } } @@ -132,25 +123,14 @@ void main() { // Only some sign extension routines have rectangular support // Commented out rectangular extension routines for speedup for (final signExtension in [ - // SignExtension.brute, - // SignExtension.stop, + SignExtension.brute, + SignExtension.stop, SignExtension.compactRect ]) { final pp = PartialProductGenerator(Logic(name: 'X', width: width), Logic(name: 'Y', width: width + skew), encoder, - signed: signed); - - switch (signExtension) { - case SignExtension.brute: - pp.bruteForceSignExtend(); - case SignExtension.stop: - pp.signExtendWithStopBitsRect(); - case SignExtension.compact: - pp.signExtendCompact(); - case SignExtension.compactRect: - pp.signExtendCompactRect(); - } - checkEvaluateRandom(pp, 100); + signed: signed, signExtension: signExtension); + checkEvaluateRandom(pp, 20); } } } @@ -186,7 +166,6 @@ void main() { pp.multiplicand.put(X); pp.multiplier.put(Y); - pp.signExtendCompactRect(); expect(pp.evaluate(), equals(product)); checkEvaluateRandom(pp, 100); } @@ -203,23 +182,13 @@ void main() { // Only some sign extension routines have rectangular support // Commented out rectangular extension routines for speedup for (final signExtension in SignExtension.values) { - { - final pp = PartialProductGenerator(Logic(name: 'X', width: width), - Logic(name: 'Y', width: width + skew), encoder, - signed: signed); - - switch (signExtension) { - case SignExtension.brute: - pp.bruteForceSignExtend(); - case SignExtension.stop: - pp.signExtendWithStopBitsRect(); - case SignExtension.compact: - pp.signExtendCompact(); - case SignExtension.compactRect: - pp.signExtendCompactRect(); - } - checkEvaluateRandom(pp, 100); + if (signExtension == SignExtension.none) { + continue; } + final pp = PartialProductGenerator(Logic(name: 'X', width: width), + Logic(name: 'Y', width: width + skew), encoder, + signed: signed, signExtension: signExtension); + checkEvaluateRandom(pp, 100); } } } @@ -241,18 +210,7 @@ void main() { { final pp = PartialProductGenerator(Logic(name: 'X', width: width), Logic(name: 'Y', width: width + skew), encoder, - signed: signed); - - switch (signExtension) { - case SignExtension.brute: - pp.bruteForceSignExtend(); - case SignExtension.stop: - pp.signExtendWithStopBitsRect(); - case SignExtension.compact: - pp.signExtendCompact(); - case SignExtension.compactRect: - pp.signExtendCompactRect(); - } + signed: signed, signExtension: signExtension); checkEvaluateExhaustive(pp); } } diff --git a/test/arithmetic/multiplier_test.dart b/test/arithmetic/multiplier_test.dart index 0e440b743..0562458a8 100644 --- a/test/arithmetic/multiplier_test.dart +++ b/test/arithmetic/multiplier_test.dart @@ -106,7 +106,7 @@ void main() { CompressionTreeMultiplier(a, b, 4, KoggeStone.new, signed: true); Multiplier curryUnsignedMultiplier(Logic a, Logic b) => - CompressionTreeMultiplier(a, b, 4, KoggeStone.new, signed: true); + CompressionTreeMultiplier(a, b, 4, KoggeStone.new, signed: false); // Now treat the multiplier as a MAC with a zero input addend [c] MultiplyAccumulate currySignedMultiplierAsMAC(Logic a, Logic b, Logic c) =>