From d098f94dc6e938f9f43df3d7e3eb26fd60699b38 Mon Sep 17 00:00:00 2001 From: "Desmond A. Kirkpatrick" Date: Tue, 5 Nov 2024 11:25:35 -0800 Subject: [PATCH] fixed addend-compressor testing --- lib/src/arithmetic/addend_compressor.dart | 11 +- test/arithmetic/addend_compressor_test.dart | 189 ++++++++------------ 2 files changed, 83 insertions(+), 117 deletions(-) diff --git a/lib/src/arithmetic/addend_compressor.dart b/lib/src/arithmetic/addend_compressor.dart index d6700c943..fa92e7c25 100644 --- a/lib/src/arithmetic/addend_compressor.dart +++ b/lib/src/arithmetic/addend_compressor.dart @@ -170,16 +170,21 @@ class ColumnCompressor { /// The partial product array to be compressed final PartialProductArray pp; - /// The clk + /// The clk for the pipelined version of column compression. Logic? clk; - /// Optional reset + /// Optional reset for configurable pipestage Logic? reset; - /// Optional enable + /// Optional enable for configurable pipestage. Logic? enable; /// Initialize a ColumnCompressor for a set of partial products + /// + /// If [clk] is not null then a set of flops are used to latch the output + /// after compression (see [extractRow]). [reset] and [enable] are optional + /// inputs to control these flops when [clk] is provided. If [clk] is null, + /// the [ColumnCompressor] is built as a combinational tree of compressors. ColumnCompressor(this.pp, {this.clk, this.reset, this.enable}) { columns = List.generate(pp.maxWidth(), (i) => ColumnQueue()); diff --git a/test/arithmetic/addend_compressor_test.dart b/test/arithmetic/addend_compressor_test.dart index b3641d7d2..080c09b22 100644 --- a/test/arithmetic/addend_compressor_test.dart +++ b/test/arithmetic/addend_compressor_test.dart @@ -53,8 +53,6 @@ void testCompressionExhaustive(PartialProductGenerator pp) { final widthX = pp.selector.multiplicand.width; final widthY = pp.encoder.multiplier.width; - final compressor = ColumnCompressor(pp); - final limitX = pow(2, widthX); final limitY = pow(2, widthY); for (var i = 0; i < limitX; i++) { @@ -65,54 +63,80 @@ void testCompressionExhaustive(PartialProductGenerator pp) { final Y = pp.signed ? BigInt.from(j).toSigned(widthY) : BigInt.from(j).toUnsigned(widthY); - final product = X * Y; - pp.multiplicand.put(X); - pp.multiplier.put(Y); - final value = pp.evaluate(); - expect(value, equals(product), - reason: 'Fail: $i($X) * $j($Y): $value ' - 'vs expected $product' - '\n$pp'); - final evaluateValue = compressor.evaluate(); - if (evaluateValue.$1 != product) { - stdout - ..write('Fail: $i($X)[$widthX] * $j($Y)[$widthY]: $evaluateValue ' - 'vs expected $product\n') - ..write(pp); - } - compressor.compress(); - final compressedValue = compressor.evaluate().$1; - expect(compressedValue, equals(product), - reason: 'Fail: $i($X)[$widthX] * $j($Y)[$widthY]: $compressedValue ' - 'vs expected $product' - '\n$pp'); - final compressedLogicValue = compressor.evaluate(logic: true).$1; - expect(compressedLogicValue, equals(product), - reason: - 'Fail: $i($X)[$widthX] * $j($Y)[$widthY]: $compressedLogicValue ' - 'vs expected $product' - '\n$pp'); + checkCompressor(pp, X, Y); + } + } +} - final a = compressor.extractRow(0); - final b = compressor.extractRow(1); +void testCompressionRandom(PartialProductGenerator pp, int iterations) { + final widthX = pp.selector.multiplicand.width; + final widthY = pp.encoder.multiplier.width; - final adder = ParallelPrefixAdder(a, b); - final adderValue = - adder.sum.value.toBigInt().toSigned(compressor.columns.length); - expect(adderValue, equals(product), - reason: 'Fail: $i($X)[$widthX] * $j($Y)[$widthY]: ' - '$adderValue vs expected $product' - '\n$pp'); - } + final value = Random(47); + for (var i = 0; i < iterations; i++) { + final X = pp.signed + ? value.nextLogicValue(width: widthX).toBigInt().toSigned(widthX) + : value.nextLogicValue(width: widthX).toBigInt().toUnsigned(widthX); + ; + final Y = pp.signed + ? value.nextLogicValue(width: widthY).toBigInt().toSigned(widthY) + : value.nextLogicValue(width: widthY).toBigInt().toUnsigned(widthY); + + checkCompressor(pp, X, Y); } } +void checkCompressor(PartialProductGenerator pp, BigInt X, BigInt Y) { + final widthX = pp.selector.multiplicand.width; + final widthY = pp.encoder.multiplier.width; + final compressor = ColumnCompressor(pp); + + final product = X * Y; + + pp.multiplicand.put(X); + pp.multiplier.put(Y); + final value = pp.evaluate(); + expect(value, equals(product), + reason: 'Fail: $X * $Y: $value ' + 'vs expected $product' + '\n$pp'); + final evaluateValue = compressor.evaluate(); + if (evaluateValue.$1 != product) { + stdout + ..write('Fail: $X)$widthX] * $Y[$widthY]: $evaluateValue ' + 'vs expected $product\n') + ..write(pp); + } + compressor.compress(); + final compressedValue = compressor.evaluate().$1; + expect(compressedValue, equals(product), + reason: 'Fail: $X[$widthX] * $Y[$widthY]: $compressedValue ' + 'vs expected $product' + '\n$pp'); + final compressedLogicValue = compressor.evaluate(logic: true).$1; + expect(compressedLogicValue, equals(product), + reason: 'Fail: $X[$widthX] * $Y[$widthY]: $compressedLogicValue ' + 'vs expected $product' + '\n$pp'); + + final a = compressor.extractRow(0); + final b = compressor.extractRow(1); + + final adder = ParallelPrefixAdder(a, b); + final adderValue = + adder.sum.value.toBigInt().toSigned(compressor.columns.length); + expect(adderValue, equals(product), + reason: 'Fail: $X[$widthX] * $Y[$widthY]: ' + '$adderValue vs expected $product' + '\n$pp'); +} + void main() { tearDown(() async { await Simulator.reset(); }); - test('exhaustive compression evaluate: square radix-4, just CompactRect', + test('ColumnCompressor: random evaluate: square radix-4, just CompactRect', () async { stdout.write('\n'); @@ -131,13 +155,13 @@ void main() { Logic(name: 'Y', width: width), encoder, signed: signed); - testCompressionExhaustive(pp); + testCompressionRandom(pp, 30); } } } } }); - test('single compressor evaluate multiply', () async { + test('Column Compressor: single compressor evaluate', () async { const widthX = 6; const widthY = 9; final a = Logic(name: 'a', width: widthX); @@ -167,39 +191,8 @@ void main() { expect(compressor.evaluate().$1, equals(BigInt.from(av * bv))); } }); - test('single compressor evaluate', () async { - const widthX = 6; - const widthY = 6; - final a = Logic(name: 'a', width: widthX); - final b = Logic(name: 'b', width: widthY); - - const av = 3; - const bv = 6; - for (final signed in [false, true]) { - final bA = signed - ? BigInt.from(av).toSigned(widthX) - : BigInt.from(av).toUnsigned(widthX); - final bB = signed - ? BigInt.from(bv).toSigned(widthY) - : BigInt.from(bv).toUnsigned(widthY); - - // Set these so that printing inside module build will have Logic values - a.put(bA); - b.put(bB); - const radix = 2; - final encoder = RadixEncoder(radix); - - final pp = PartialProductGeneratorCompactRectSignExtension(a, b, encoder, - signed: signed); - expect(pp.evaluate(), equals(BigInt.from(av * bv))); - final compressor = ColumnCompressor(pp); - expect(compressor.evaluate().$1, equals(BigInt.from(av * bv))); - compressor.compress(); - expect(compressor.evaluate().$1, equals(BigInt.from(av * bv))); - } - }); - test('single compressor evaluate flopped', () async { + test('Column Compressor: evaluate flopped', () async { final clk = SimpleClockGenerator(10).clk; const widthX = 6; const widthY = 6; @@ -208,7 +201,13 @@ void main() { var av = 3; const bv = 6; + const radix = 2; + final encoder = RadixEncoder(radix); + unawaited(Simulator.run()); for (final signed in [false, true]) { + final compressorTestMod = + CompressorTestMod(a, b, encoder, clk, signed: signed); + await compressorTestMod.build(); var bA = signed ? BigInt.from(av).toSigned(widthX) : BigInt.from(av).toUnsigned(widthX); @@ -219,13 +218,6 @@ void main() { // Set these so that printing inside module build will have Logic values a.put(bA); b.put(bB); - const radix = 2; - final encoder = RadixEncoder(radix); - - final compressorTestMod = CompressorTestMod(a, b, encoder, clk); - await compressorTestMod.build(); - - unawaited(Simulator.run()); await clk.nextNegedge; expect(compressorTestMod.compressor.evaluate().$1, @@ -233,43 +225,12 @@ void main() { av = 4; bA = signed ? BigInt.from(av).toSigned(widthX) - : BigInt.from(bv).toUnsigned(widthX); + : BigInt.from(av).toUnsigned(widthX); a.put(bA); await clk.nextNegedge; expect(compressorTestMod.compressor.evaluate().$1, equals(BigInt.from(av * bv))); - - await Simulator.endSimulation(); - } - }); - - test('example multiplier', () async { - const widthX = 10; - const widthY = 10; - final a = Logic(name: 'a', width: widthX); - final b = Logic(name: 'b', width: widthY); - - const av = 37; - const bv = 6; - for (final signed in [false, true]) { - final bA = signed - ? BigInt.from(av).toSigned(widthX) - : BigInt.from(av).toUnsigned(widthX); - final bB = signed - ? BigInt.from(bv).toSigned(widthY) - : BigInt.from(bv).toUnsigned(widthY); - - // Set these so that printing inside module build will have Logic values - a.put(bA); - b.put(bB); - const radix = 8; - final encoder = RadixEncoder(radix); - - final pp = PartialProductGeneratorCompactRectSignExtension(a, b, encoder, - signed: signed); - expect(pp.evaluate(), equals(BigInt.from(av * bv))); - final compressor = ColumnCompressor(pp)..compress(); - expect(compressor.evaluate().$1, equals(BigInt.from(av * bv))); } + await Simulator.endSimulation(); }); }