diff --git a/.github/workflows/general.yml b/.github/workflows/general.yml index 63478fa8..825a28d3 100644 --- a/.github/workflows/general.yml +++ b/.github/workflows/general.yml @@ -17,6 +17,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v3 + with: + submodules: recursive - name: Lint Markdown files uses: DavidAnson/markdownlint-cli2-action@v11 diff --git a/.gitignore b/.gitignore index 5c5e8ba8..04504631 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +# NOTE: Be sure to update .pubignore as well! + # Files and directories created by pub .dart_tool/ .packages @@ -7,12 +9,17 @@ pubspec.lock build/ # Directory created by dartdoc -doc/api/ +doc/api # Other stuff tmp* *.vcd -.vscode/ +.vscode/* +confapp/.vscode/* +*tracker.json +*tracker.log # Exceptions -!.vscode/extensions.json \ No newline at end of file +!.vscode/extensions.json +!confapp/.vscode/extensions.json +!confapp/.vscode/launch.json \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fb5ec428..ccb0d9f1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -134,6 +134,21 @@ Here is an example of a recommended file header template: // Author: Max Korbel ``` +#### Adding a New Component + +To add a new component to the library, you can follow the steps below, referencing other components as examples. + +1. Create the dart code for constructing the module in `lib/src`. +1. Create unit tests in `test/`. +1. Create a `Configurator` for the component (enabling things like schematic generation, web-app generation, etc.). + 1. Create a new config in `lib/src/component_config/commponents`. + 1. Update the component registry in `lib/src/component_config/components/component_registry.dart`. +1. Add documentation to `doc/components/name.md`. + +If you would like to generate and view schematics locally, you'll need to have access to some tools. You can either use the dev container (via Codespaces or VS Code) or install the software from `tool/gh_actions/install_opencadsuite.sh` and `tool/gh_actions/install_d3_hwschematic.sh`. Then you can just run `tool/gh_actions/create_htmls.sh`, which will generate component schematic HTML documents in the `build/` directory. + +The `confapp/` directory contains the source code for the Flutter configuration app, if you would like to run that locally. + ### Creating a New Package Not every new contribution has to go directly into the ROHD or ROHD-HCL frameworks! If you have an idea for a reusable piece of hardware, tooling, verification collateral, or anything else that helps the ROHD ecosystem but is somewhat standalone, you can make your own package that depends on ROHD. Building an ecosystem of reusable components is important to the success of ROHD. Reach out if you want some help or guidance deciding if or how you should create a new package. diff --git a/README.md b/README.md index 9e0e53dd..c0a7859b 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,5 @@ Some examples of component categories include: - Models ---------------- - Copyright (C) 2023 Intel Corporation SPDX-License-Identifier: BSD-3-Clause diff --git a/build/README.md b/build/README.md deleted file mode 100644 index 567fed47..00000000 --- a/build/README.md +++ /dev/null @@ -1 +0,0 @@ -This directory is for Verilog output and HTML conversion of components. diff --git a/doc/components/parallel_prefix_operations.md b/doc/components/parallel_prefix_operations.md new file mode 100644 index 00000000..b8c0f1a7 --- /dev/null +++ b/doc/components/parallel_prefix_operations.md @@ -0,0 +1,14 @@ +# Parallel Prefix Operations + +ROHD HCL implements a set of parallel prefix compute operations using different parallel prefix computation trees based on the ['ParallelPrefix'] node class carrying carry/save or generate/propagate bits. + +For example, we have unary operations like a word-level 'or' [`ParallelPrefixOrScan`] class, and a priority encoder [`ParallelPrefixPriorityEncoder`] class which computes the position of the first bit set to '1'. We have simple unary arithmetic operations like an increment [`ParallelPrefixIncr`] class, and a decrement [`ParallelPrefixDecr`] class. Finally, we have a binary adder [`ParallelPrefixAdder`] class. For background on basic parallel prefix adder structures, see . + +Each of these operations can be implemented with different ['ParallelPrefix'] types: + +- ['Ripple'](https://intel.github.io/rohd-hcl/rohd_hcl/Ripple-class.html) +- ['Sklansky](https://intel.github.io/rohd-hcl/rohd_hcl/Sklansky-class.html) +- ['KoggeStone'](https://intel.github.io/rohd-hcl/rohd_hcl/KoggeStone-class.html) +- ['BrentKung](https://intel.github.io/rohd-hcl/rohd_hcl/BrentKung-class.html) + +[PPAdder_BrentKung Schematic](https://intel.github.io/rohd-hcl/PPAdder_BrentKung.html) diff --git a/gen/generate.dart b/gen/generate.dart index 066dfc4d..8adda02b 100644 --- a/gen/generate.dart +++ b/gen/generate.dart @@ -10,16 +10,15 @@ // 2023 May 09 // Author: Desmond Kirkpatrick -import 'arbiter_gen.dart'; -import 'fifo_gen.dart'; -import 'one_hot_gen.dart'; -import 'rf_gen.dart'; -import 'rotate_gen.dart'; +import 'dart:io'; + +import 'package:rohd_hcl/src/component_config/components/component_registry.dart'; void main() async { - await arbiterGen(); - await fifoGen(); - await oneHotGen(); - await rfGen(); - await rotateGen(); + Directory('build').createSync(recursive: true); + for (final configurator in componentRegistry) { + final sv = await configurator.generateSV(); + final name = configurator.createModule().definitionName; + File('build/$name.v').writeAsStringSync(sv); + } } diff --git a/gen/parallel_prefix_operations_gen.dart b/gen/parallel_prefix_operations_gen.dart new file mode 100644 index 00000000..654550c1 --- /dev/null +++ b/gen/parallel_prefix_operations_gen.dart @@ -0,0 +1,35 @@ +// Copyright (C) 2023 Intel Corporation +// SPDX-License-Identifier: BSD-3-Clause +// +// one_hot_gen.dart +// Generate one_hot codecs. +// +// 2023 Oct 02 +// Author: Desmond Kirkpatrick + +import 'dart:io'; +import 'package:rohd/rohd.dart'; +import 'package:rohd_hcl/src/parallel_prefix_operations.dart'; + +Future parallelPrefixGen() async { + const n = 8; + final a = Logic(name: 'a', width: n); + final b = Logic(name: 'b', width: n); + + final generators = [Ripple.new, Sklansky.new, KoggeStone.new, BrentKung.new]; + final names = ['Ripple', 'Sklansky', 'KoggeStone', 'BrentKung']; + var i = 0; + for (final ppGen in generators) { + final m1 = ParallelPrefixAdder(a, b, ppGen); + await m1.build(); + File('build/${m1.definitionName}_${names[i]}.v').writeAsStringSync(m1 + .generateSynth() + .replaceAll(m1.definitionName, '${m1.definitionName}_${names[i]}')); + final m2 = ParallelPrefixPriorityEncoder(a, ppGen); + await m2.build(); + File('build/${m2.definitionName}_${names[i]}.v').writeAsStringSync(m2 + .generateSynth() + .replaceAll(m2.definitionName, '${m2.definitionName}_${names[i]}')); + i = i + 1; + } +} diff --git a/lib/src/one_hot.dart b/lib/src/one_hot.dart deleted file mode 100644 index ed89bdc5..00000000 --- a/lib/src/one_hot.dart +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (C) 2023 Intel Corporation -// SPDX-License-Identifier: BSD-3-Clause -// -// one_hot.dart -// Implementation of one hot codec for Logic -// -// 2023 February 24 -// Author: Desmond Kirkpatrick - -import 'dart:math'; -import 'package:rohd/rohd.dart'; -import 'package:rohd_hcl/src/utils.dart'; - -/// Encodes a binary number into one-hot -class BinaryToOneHot extends Module { - /// The [encoded] one-hot result. - Logic get encoded => output('encoded'); - - /// Constructs a [Module] which encodes a 2's complement number [binary] - /// into a one-hot, or thermometer code - BinaryToOneHot(Logic binary) { - binary = addInput('binary', binary, width: binary.width); - addOutput('encoded', width: pow(2, binary.width).toInt()); - encoded <= Const(1, width: encoded.width) << binary; - } -} - -/// Decodes a one-hot number into binary using a for-loop -class OneHotToBinary extends Module { - /// The [binary] decoded result. - Logic get binary => output('binary'); - - /// Constructs a [Module] which decodes a one-hot or thermometer-encoded - /// number [onehot] into a 2s complement number [binary] by encoding - /// the position of the '1' - OneHotToBinary(Logic onehot) { - onehot = addInput('onehot', onehot, width: onehot.width); - addOutput('binary', width: log2Ceil(onehot.width + 1)); - Combinational([ - Case(onehot, conditionalType: ConditionalType.unique, [ - for (var i = 0; i < onehot.width; i++) - CaseItem( - Const(BigInt.from(1) << i, width: onehot.width), - [binary < Const(i, width: binary.width)], - ) - ], defaultItem: [ - binary < Const(binary.width, width: binary.width) - ]) - ]); - } -} - -/// Internal class for binary-tree recursion for decoding one-hot -class _NodeOneHotToBinary extends Module { - /// The [binary] decoded result. - Logic get binary => output('binary'); - - /// Build a shorter-input module for recursion - /// (borrowed from Chisel OHToUInt) - _NodeOneHotToBinary(Logic onehot) { - final wid = onehot.width; - onehot = addInput('onehot', onehot, width: wid); - - if (wid <= 2) { - addOutput('binary'); - //Log2 of 2-bit quantity - if (wid == 2) { - binary <= onehot[1]; - } else { - binary <= Const(0, width: 1); - } - } else { - final mid = 1 << (log2Ceil(wid) - 1); - addOutput('binary', width: log2Ceil(mid + 1)); - final hi = onehot.getRange(mid).zeroExtend(mid); - final lo = onehot.getRange(0, mid).zeroExtend(mid); - final recurse = lo | hi; - final response = _NodeOneHotToBinary(recurse).binary; - binary <= [hi.or(), response].swizzle(); - } - } -} - -/// Module for binary-tree recursion for decoding one-hot -class TreeOneHotToBinary extends Module { - /// The [binary] decoded result. - Logic get binary => output('binary'); - - /// Top level module for computing binary to one-hot using recursion - TreeOneHotToBinary(Logic one) { - final ret = _NodeOneHotToBinary(one).binary; - addOutput('binary', width: ret.width); - binary <= ret; - } -} diff --git a/lib/src/parallel_prefix_operations.dart b/lib/src/parallel_prefix_operations.dart new file mode 100644 index 00000000..4660fbb1 --- /dev/null +++ b/lib/src/parallel_prefix_operations.dart @@ -0,0 +1,255 @@ +// Copyright (C) 2023 Intel Corporation +// SPDX-License-Identifier: BSD-3-Clause +// +// parallel_prefix_operations.dart +// Implementation of operators using various parallel-prefix trees. +// +// 2023 Sep 29 +// Author: Desmond Kirkpatrick +// Borrowed from https://github.com/stevenmburns/rohd_sklansky.git + +import 'dart:math'; + +import 'package:collection/collection.dart'; +import 'package:rohd/rohd.dart'; +import 'package:rohd_hcl/rohd_hcl.dart'; + +/// This computes the power of 2 less than x +int largestPow2LessThan(int x) => pow(2, log2Ceil(x) - 1).toInt(); + +/// [ParallelPrefix] is the core parallel prefix tree structure node +/// The output is a List of multi-bit Logic vectors (typically 2-bit) that +/// represent things like carry-save or generate-propagate signaling in adder +/// networks. Each node in a parallel prefix tree transforms a row of inputs +/// to an equal length row of outputs of these multi-bit Logic values. +class ParallelPrefix extends Module { + final List _oseq = []; + + /// Output sequence value + List get val => UnmodifiableListView(_oseq); + + /// ParallePrefix recursion + ParallelPrefix(List inps, String name) : super(name: name) { + if (inps.isEmpty) { + throw Exception("Don't use {name} with an empty sequence"); + } + } +} + +/// Ripple shaped ParallelPrefix tree +class Ripple extends ParallelPrefix { + /// Ripple constructor + Ripple(List inps, Logic Function(Logic, Logic) op) + : super(inps, 'ripple') { + final iseq = []; + + inps.forEachIndexed((i, el) { + iseq.add(addInput('i$i', el, width: el.width)); + _oseq.add(addOutput('o$i', width: el.width)); + }); + + for (var i = 0; i < iseq.length; ++i) { + if (i == 0) { + _oseq[i] <= iseq[i]; + } else { + _oseq[i] <= op(_oseq[i - 1], iseq[i]); + } + } + } +} + +/// Sklansky shaped ParallelPrefix tree +class Sklansky extends ParallelPrefix { + /// Sklansky constructor + Sklansky(List inps, Logic Function(Logic, Logic) op) + : super(inps, 'sklansky') { + final iseq = []; + + inps.forEachIndexed((i, el) { + iseq.add(addInput('i$i', el, width: el.width)); + _oseq.add(addOutput('o$i', width: el.width)); + }); + + if (iseq.length == 1) { + _oseq[0] <= iseq[0]; + } else { + final n = iseq.length; + final m = largestPow2LessThan(n); + final u = Sklansky(iseq.getRange(0, m).toList(), op).val; + final v = Sklansky(iseq.getRange(m, n).toList(), op).val; + u.forEachIndexed((i, el) { + _oseq[i] <= el; + }); + v.forEachIndexed((i, el) { + _oseq[m + i] <= op(u[m - 1], el); + }); + } + } +} + +/// KoggeStone shaped ParallelPrefix tree +class KoggeStone extends ParallelPrefix { + /// KoggeStone constructor + KoggeStone(List inps, Logic Function(Logic, Logic) op) + : super(inps, 'kogge_stone') { + final iseq = []; + + inps.forEachIndexed((i, el) { + iseq.add(addInput('i$i', el, width: el.width)); + _oseq.add(addOutput('o$i', width: el.width)); + }); + + var skip = 1; + + while (skip < inps.length) { + for (var i = inps.length - 1; i >= skip; --i) { + iseq[i] = op(iseq[i - skip], iseq[i]); + } + skip *= 2; + } + + iseq.forEachIndexed((i, el) { + _oseq[i] <= el; + }); + } +} + +/// BrentKung shaped ParallelPrefix tree +class BrentKung extends ParallelPrefix { + /// BrentKung constructor + BrentKung(List inps, Logic Function(Logic, Logic) op) + : super(inps, 'brent_kung') { + final iseq = []; + + inps.forEachIndexed((i, el) { + iseq.add(addInput('i$i', el, width: el.width)); + _oseq.add(addOutput('o$i', width: el.width)); + }); + + // Reduce phase + var skip = 2; + while (skip <= inps.length) { + for (var i = skip - 1; i < inps.length; i += skip) { + iseq[i] = op(iseq[i - skip ~/ 2], iseq[i]); + } + skip *= 2; + } + + // Prefix Phase + skip = largestPow2LessThan(inps.length); + while (skip > 2) { + for (var i = 3 * (skip ~/ 2) - 1; i < inps.length; i += skip) { + iseq[i] = op(iseq[i - skip ~/ 2], iseq[i]); + } + skip ~/= 2; + } + + // Final row + for (var i = 2; i < inps.length; i += 2) { + iseq[i] = op(iseq[i - 1], iseq[i]); + } + + iseq.forEachIndexed((i, el) { + _oseq[i] <= el; + }); + } +} + +/// Or scan based on ParallelPrefix tree +class ParallelPrefixOrScan extends Module { + /// Output [out] is the or of bits of the input + Logic get out => output('out'); + + /// OrScan constructor + ParallelPrefixOrScan( + Logic inp, + ParallelPrefix Function(List, Logic Function(Logic, Logic)) + ppGen) { + inp = addInput('inp', inp, width: inp.width); + final u = + ppGen(List.generate(inp.width, (i) => inp[i]), (a, b) => a | b); + addOutput('out', width: inp.width) <= u.val.rswizzle(); + } +} + +/// Priority Encoder based on ParallelPrefix tree +class ParallelPrefixPriorityEncoder extends Module { + /// Output [out] is the bit position of the first '1' in the Logic input + /// Search is counted from the LSB + Logic get out => output('out'); + + /// PriorityEncoder constructor + ParallelPrefixPriorityEncoder( + Logic inp, + ParallelPrefix Function(List, Logic Function(Logic, Logic)) + ppGen) { + inp = addInput('inp', inp, width: inp.width); + final u = ParallelPrefixOrScan(inp, ppGen); + addOutput('out', width: inp.width) <= (u.out & ~(u.out << Const(1))); + } +} + +/// Adder based on ParallelPrefix tree +class ParallelPrefixAdder extends Module { + /// Output [out] the arithmetic sum of the two Logic inputs + Logic get out => output('out'); + + /// Adder constructor + ParallelPrefixAdder( + Logic a, + Logic b, + ParallelPrefix Function(List, Logic Function(Logic, Logic)) + ppGen) { + a = addInput('a', a, width: a.width); + b = addInput('b', b, width: b.width); + final u = ppGen( + // generate, propagate or generate + List.generate( + a.width, (i) => [a[i] & b[i], a[i] | b[i]].swizzle()), + (lhs, rhs) => [rhs[1] | rhs[0] & lhs[1], rhs[0] & lhs[0]].swizzle()); + addOutput('out', width: a.width) <= + List.generate(a.width, + (i) => (i == 0) ? a[i] ^ b[i] : a[i] ^ b[i] ^ u.val[i - 1][1]) + .rswizzle(); + } +} + +/// Incrementer based on ParallelPrefix tree +class ParallelPrefixIncr extends Module { + /// Output is '1' added to the Logic input + Logic get out => output('out'); + + /// Increment constructor + ParallelPrefixIncr( + Logic inp, + ParallelPrefix Function(List, Logic Function(Logic, Logic)) + ppGen) { + inp = addInput('inp', inp, width: inp.width); + final u = ppGen(List.generate(inp.width, (i) => inp[i]), + (lhs, rhs) => rhs & lhs); + addOutput('out', width: inp.width) <= + (List.generate( + inp.width, (i) => ((i == 0) ? ~inp[i] : inp[i] ^ u.val[i - 1])) + .rswizzle()); + } +} + +/// Decrementer based on ParallelPrefix tree +class ParallelPrefixDecr extends Module { + /// Output is '1' subtracted from the Logic input + Logic get out => output('out'); + + /// Decrement constructor + ParallelPrefixDecr( + Logic inp, + ParallelPrefix Function(List, Logic Function(Logic, Logic)) + ppGen) { + inp = addInput('inp', inp, width: inp.width); + final u = ppGen(List.generate(inp.width, (i) => ~inp[i]), + (lhs, rhs) => rhs & lhs); + addOutput('out', width: inp.width) <= + (List.generate( + inp.width, (i) => ((i == 0) ? ~inp[i] : inp[i] ^ u.val[i - 1])) + .rswizzle()); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index d643b049..8496ccb9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,6 +10,7 @@ environment: sdk: '>=2.18.0 <3.0.0' dependencies: + collection: ^1.18.0 meta: ^1.9.1 rohd: ^0.5.0 rohd_vf: ^0.5.0 diff --git a/test/one_hot_test.dart b/test/one_hot_test.dart index 3a14edf4..4ce1e4c6 100644 --- a/test/one_hot_test.dart +++ b/test/one_hot_test.dart @@ -5,7 +5,7 @@ // Test of one_hot codec. // // 2023 February 24 -// Author: Desmond Kirkpatrick +// Author: Desmond Kirkpatrick import 'dart:math'; diff --git a/test/parallel_prefix_operations_test.dart b/test/parallel_prefix_operations_test.dart new file mode 100644 index 00000000..09da5835 --- /dev/null +++ b/test/parallel_prefix_operations_test.dart @@ -0,0 +1,226 @@ +// Copyright (C) 2023 Intel Corporation +// SPDX-License-Identifier: BSD-3-Clause +// +// parallel-prefix_operations.dart +// Implementation of operations using various parallel-prefix trees. +// +// 2023 Sep 29 +// Author: Desmond Kirkpatrick + +import 'dart:math'; +import 'package:rohd/rohd.dart'; +import 'package:rohd_hcl/src/parallel_prefix_operations.dart'; +import 'package:test/test.dart'; + +void testOrScan(int n, ParallelPrefixOrScan Function(Logic a) fn) { + test('or_scan_$n', () async { + final inp = Logic(name: 'inp', width: n); + final mod = fn(inp); + await mod.build(); + + int computeOrScan(int j) { + var result = 0; + var found = false; + for (var i = 0; i < n; ++i) { + if (found || ((1 << i) & j) != 0) { + result |= 1 << i; + found = true; + } + } + return result; + } + + // put/expect testing + + for (var j = 0; j < (1 << n); ++j) { + final golden = computeOrScan(j); + inp.put(j); + final result = mod.out.value.toInt(); + //print("$j ${result} ${golden}"); + expect(result, equals(golden)); + } + }); +} + +void testPriorityEncoder( + int n, ParallelPrefixPriorityEncoder Function(Logic a) fn) { + test('priority_encoder_$n', () async { + final inp = Logic(name: 'inp', width: n); + final mod = fn(inp); + await mod.build(); + + int computePriorityEncoding(int j) { + for (var i = 0; i < n; ++i) { + if (((1 << i) & j) != 0) { + return 1 << i; + } + } + return 0; + } + + // put/expect testing + + for (var j = 0; j < (1 << n); ++j) { + final golden = computePriorityEncoding(j); + inp.put(j); + final result = mod.out.value.toInt(); + // print("priority_encoder: $j ${result} ${golden}"); + expect(result, equals(golden)); + } + }); +} + +void testAdder(int n, ParallelPrefixAdder Function(Logic a, Logic b) fn) { + test('adder_$n', () async { + final a = Logic(name: 'a', width: n); + final b = Logic(name: 'b', width: n); + + final mod = fn(a, b); + await mod.build(); + + int computeAdder(int aa, int bb) => (aa + bb) & ((1 << n) - 1); + + // put/expect testing + + for (var aa = 0; aa < (1 << n); ++aa) { + for (var bb = 0; bb < (1 << n); ++bb) { + final golden = computeAdder(aa, bb); + a.put(aa); + b.put(bb); + final result = mod.out.value.toInt(); + //print("adder: $aa $bb $result $golden"); + expect(result, equals(golden)); + } + } + }); +} + +void testAdderRandom( + int n, int nSamples, ParallelPrefixAdder Function(Logic a, Logic b) fn) { + test('adder_$n', () async { + final a = Logic(name: 'a', width: n); + final b = Logic(name: 'b', width: n); + + final mod = fn(a, b); + await mod.build(); + + LogicValue computeAdder(LogicValue aa, LogicValue bb) => + (aa + bb) & LogicValue.ofBigInt(BigInt.from((1 << n) - 1), n); + // put/expect testing + + for (var i = 0; i < nSamples; ++i) { + final aa = Random().nextLogicValue(width: n); + final bb = Random().nextLogicValue(width: n); + final golden = computeAdder(aa, bb); + a.put(aa); + b.put(bb); + final result = mod.out.value; + expect(result, equals(golden)); + } + }); +} + +void testIncr(int n, ParallelPrefixIncr Function(Logic a) fn) { + test('incr_$n', () async { + final inp = Logic(name: 'inp', width: n); + final mod = fn(inp); + await mod.build(); + + int computeIncr(int aa) => (aa + 1) & ((1 << n) - 1); + + // put/expect testing + + for (var aa = 0; aa < (1 << n); ++aa) { + final golden = computeIncr(aa); + inp.put(aa); + final result = mod.out.value.toInt(); + //print("incr: $aa $result $golden"); + expect(result, equals(golden)); + } + }); +} + +void testDecr(int n, ParallelPrefixDecr Function(Logic a) fn) { + test('decr_$n', () async { + final inp = Logic(name: 'inp', width: n); + final mod = fn(inp); + await mod.build(); + + int computeDecr(int aa) => (aa - 1) % (1 << n); + + // put/expect testing + + for (var aa = 0; aa < (1 << n); ++aa) { + final golden = computeDecr(aa); + inp.put(aa); + final result = mod.out.value.toInt(); + //print("decr: $aa $result $golden"); + expect(result, equals(golden)); + } + }); +} + +void main() { + tearDown(() async { + await Simulator.reset(); + }); + + group('largest_pow2_less_than', () { + test('largest_pow2_less_than', () async { + expect(largestPow2LessThan(5), equals(4)); + expect(largestPow2LessThan(4), equals(2)); + expect(largestPow2LessThan(3), equals(2)); + }); + }); + + final generators = [Ripple.new, Sklansky.new, KoggeStone.new, BrentKung.new]; + + group('or_scan', () { + for (final n in [7, 8, 9]) { + for (final ppGen in generators) { + testOrScan(n, (inp) => ParallelPrefixOrScan(inp, ppGen)); + } + } + }); + + group('priority_encoder', () { + for (final n in [7, 8, 9]) { + for (final ppGen in generators) { + testPriorityEncoder( + n, (inp) => ParallelPrefixPriorityEncoder(inp, ppGen)); + } + } + }); + + group('adder', () { + for (final n in [3, 4, 5]) { + for (final ppGen in generators) { + testAdder(n, (a, b) => ParallelPrefixAdder(a, b, ppGen)); + } + } + }); + + group('adderRandom', () { + for (final n in [127, 128, 129]) { + for (final ppGen in generators) { + testAdderRandom(n, 10, (a, b) => ParallelPrefixAdder(a, b, ppGen)); + } + } + }); + + group('incr', () { + for (final n in [7, 8, 9]) { + for (final ppGen in generators) { + testIncr(n, (inp) => ParallelPrefixIncr(inp, ppGen)); + } + } + }); + + group('decr', () { + for (final n in [7, 8, 9]) { + for (final ppGen in generators) { + testDecr(n, (inp) => ParallelPrefixDecr(inp, ppGen)); + } + } + }); +} diff --git a/tool/gh_codespaces/run_setup.sh b/tool/gh_codespaces/run_setup.sh index 866bae80..252a5aed 100755 --- a/tool/gh_codespaces/run_setup.sh +++ b/tool/gh_codespaces/run_setup.sh @@ -21,4 +21,4 @@ tool/gh_actions/install_dependencies.sh tool/gh_actions/install_opencadsuite.sh # Install D3 Schematic viewer -tool/gh_actions/install_d3_hwschematic.sh \ No newline at end of file +tool/gh_actions/install_d3_hwschematic.sh