Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

parallel prefix operations #51

Closed
wants to merge 60 commits into from
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
10ba13d
schematic generation
desmonddak May 10, 2023
3eb2576
no lint on LICENSE file
desmonddak May 10, 2023
300b118
more markdown linting ignore
desmonddak May 10, 2023
c7c617f
try HTML generation in run checks flow
desmonddak May 10, 2023
1f79ee9
path fix
desmonddak May 10, 2023
e29402f
direct path for yosys
desmonddak May 10, 2023
9984f8a
forgot synthesis
desmonddak May 10, 2023
e947354
permission error or apt
desmonddak May 10, 2023
be6fb15
yosys is installed at top of source, not /
desmonddak May 10, 2023
f9b65b8
Use a binary yosys rather than building.
desmonddak May 12, 2023
0941a1a
github submodules
desmonddak May 12, 2023
50d9898
github submodules (untabify)
desmonddak May 12, 2023
51905db
more ignore lint entries
desmonddak May 12, 2023
f3dfe50
remove redundant elkjs
desmonddak May 12, 2023
bf3eb49
forgot directory add
desmonddak May 12, 2023
8bc8ee0
formatting
desmonddak May 13, 2023
1e2e42b
dart cleanup
desmonddak May 13, 2023
b4d0297
Merge pull request #1 from desmonddak/synthesis
desmonddak May 13, 2023
155ae9b
remove empty file
desmonddak May 13, 2023
6d91fae
updated workflow
desmonddak May 13, 2023
b78aba6
migrated schem generation to deploy stage
desmonddak May 13, 2023
492d6e8
Push documentation of api one directory lower
desmonddak May 13, 2023
6c51f4d
need a home dir
desmonddak May 13, 2023
d6e0700
attempt to link schematic
desmonddak May 13, 2023
bd93c4c
htmls need doc area setup
desmonddak May 13, 2023
8c18efc
partition schem support
desmonddak May 13, 2023
06e1a6f
sudo issue
desmonddak May 13, 2023
ab25690
hw schematic not schematic
desmonddak May 13, 2023
2fce1ec
npm typo
desmonddak May 13, 2023
675e028
remove quotes
desmonddak May 13, 2023
fbe11ae
each component gets a schematic
desmonddak May 13, 2023
6696b3c
format complaint
desmonddak May 13, 2023
7c7d888
fix write flushing
desmonddak May 13, 2023
90eaede
add one-hot codec documentation
desmonddak May 13, 2023
38f01a8
quieter generator, fixed onehot doc
desmonddak May 13, 2023
aabbbac
feedback fixes
desmonddak May 16, 2023
2a2993d
redirect links
desmonddak May 17, 2023
60a8878
filename not correct inside file
desmonddak May 17, 2023
55c6d61
line length issue
desmonddak May 17, 2023
6d7082d
no more puts
desmonddak May 17, 2023
de2f6e6
formatting
desmonddak May 17, 2023
2e7e435
merge from intel
desmonddak Oct 1, 2023
1423819
parallel prefix operations
desmonddak Oct 3, 2023
0c26868
doc lint fixes
desmonddak Oct 3, 2023
6eb11ff
doc lint fixes
desmonddak Oct 3, 2023
5a0b1b0
remove links to deployment area for now
desmonddak Oct 3, 2023
78e2c8f
fix bug in verilog generation for PPAdder flavors
desmonddak Oct 3, 2023
529a9d5
Merge branch 'main' of https://github.com/intel/rohd-hcl into prefix-…
desmonddak Oct 3, 2023
7e6fd8a
updated documentation, clearer naming, using Random()
desmonddak Oct 5, 2023
6601e6b
Merge branch 'prefix-tree' of https://github.com/desmonddak/rohd-hcl …
desmonddak Nov 3, 2023
4bbe8a8
doc fixes
desmonddak Feb 2, 2024
171bdbc
Merge branch 'main' of https://github.com/desmonddak/rohd-hcl
desmonddak Feb 2, 2024
659037e
merge conflict fixes
desmonddak Feb 2, 2024
b198e3c
touch file
desmonddak Feb 2, 2024
837712a
merge fixes from prefix-tree
desmonddak Feb 2, 2024
8065052
merge fixes
desmonddak Feb 5, 2024
9d335e0
Merge branch 'desmonddak-prefix-tree2' into desmonddak-prefix-tree
desmonddak Feb 5, 2024
ddce8ed
fix conflicts
desmonddak Feb 5, 2024
c71c351
removed old one_hot.dart
desmonddak Feb 5, 2024
7f73322
reverted to main CONTRIBUTING.md
desmonddak Feb 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's weird that this (and some other) files are showing up as a diff from main. If you just do a merge or rebase with main does this go away?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The merge failed so it required manual changes. The PR is quite stale, so there are more and more conflicts.
Some files were moved in main (e.g. one_hot.dart), so I removed them from this branch.
We should go through a list of changed files before final merge and make sure this branch is not changing files we do not expect.

Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ doc/api/
tmp*
*.vcd
.vscode/
*~

# Exceptions
!.vscode/extensions.json
!.vscode/extensions.json
19 changes: 19 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,22 @@ Here are some links to help guide you on style as recommended by Dart:
* Design: <https://dart.dev/guides/language/effective-dart/design>

We recommend following these same guidelines for any of your own packages you may create for the ecosystem, as well.

## Adding a New Component
mkorbel1 marked this conversation as resolved.
Show resolved Hide resolved

1. Create the dart code for constructing the module in lib/src

1. Create testing code in test/

1. Create a generator in gen

1. Add generator to gen/generate.dart

1. Run dart gen/generate.dart to make sure generation works.

1. Add documentation to doc/name.dart
mkorbel1 marked this conversation as resolved.
Show resolved Hide resolved

1. How to test documentation in a dart container
mkorbel1 marked this conversation as resolved.
Show resolved Hide resolved

1. gh_actions/install_oss_cad_suite.sh
1. install_d3_hwschematic.sh
16 changes: 16 additions & 0 deletions doc/components/parallel_prefix_operations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Parallel Prefix Operations

ROHD HCL implements a set of parallel prefix compute operations using different parallel prefix computation trees based on the ['ParallePrefix'] node class carrying carry/save or generate/propagate bits.

For example, we have unary operations like a word-level 'or' [`OrScan`] class, and a priority encoder [`PriorityEncoder`] class which computes the position of the first bit set to '1'. We have simple unary arithmetic operations like an increment [`PPIncr`] class, and a decrement [`PPDecr`] class. Finally, we have a binary adder [`PPAdder`] class. For background on basic parallel prefix adder structures, see <https://en.wikipedia.org/wiki/Kogge%E2%80%93Stone_adder>.
mkorbel1 marked this conversation as resolved.
Show resolved Hide resolved

Each of these operations can be implemented with different ['ParallelPrefix'] tree structures:

desmonddak marked this conversation as resolved.
Show resolved Hide resolved
- ['Ripple']
- ['Sklansky]
- ['KoggeStone']
- ['BrentKung]

[ParallelPrefixAdder (BrentKung) Schematic]

[ParallelPrefixPriorityEncoder (KoggeStone) Schematic]
2 changes: 2 additions & 0 deletions gen/generate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import 'arbiter_gen.dart';
import 'fifo_gen.dart';
import 'one_hot_gen.dart';
import 'parallel_prefix_operations_gen.dart';
import 'rf_gen.dart';
import 'rotate_gen.dart';

Expand All @@ -22,4 +23,5 @@ void main() async {
await oneHotGen();
await rfGen();
await rotateGen();
await parallelPrefixGen();
}
35 changes: 35 additions & 0 deletions gen/parallel_prefix_operations_gen.dart
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>

import 'dart:io';
import 'package:rohd/rohd.dart';
import 'package:rohd_hcl/src/parallel_prefix_operations.dart';

Future<void> 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;
}
}
2 changes: 1 addition & 1 deletion lib/src/one_hot.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// Implementation of one hot codec for Logic
//
// 2023 February 24
// Author: Desmond Kirkpatrick
// Author: Desmond Kirkpatrick <[email protected]>

import 'dart:math';
import 'package:rohd/rohd.dart';
Expand Down
255 changes: 255 additions & 0 deletions lib/src/parallel_prefix_operations.dart
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you need to add this file to lib/rohd_hcl.dart to expose it as a public API

Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
// Copyright (C) 2023 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// parallel-prefix_operations.dart
mkorbel1 marked this conversation as resolved.
Show resolved Hide resolved
// Implementation of operators using various parallel-prefix trees.
//
// 2023 Sep 29
// Author: Desmond Kirkpatrick <[email protected]>
// 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();
desmonddak marked this conversation as resolved.
Show resolved Hide resolved

/// ParallePrefix is the core parallel prefix tree structure node
mkorbel1 marked this conversation as resolved.
Show resolved Hide resolved
/// The output is a List of multi-bit Logic vectors (typicall 2-bit) that
mkorbel1 marked this conversation as resolved.
Show resolved Hide resolved
/// 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<Logic> _oseq = [];

/// Output sequence value
List<Logic> get val => _oseq;
mkorbel1 marked this conversation as resolved.
Show resolved Hide resolved

/// ParallePrefix recursion
ParallelPrefix(List<Logic> inps, String name) : super(name: name) {
desmonddak marked this conversation as resolved.
Show resolved Hide resolved
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<Logic> inps, Logic Function(Logic, Logic) op)
: super(inps, 'ripple') {
final iseq = <Logic>[];

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<Logic> inps, Logic Function(Logic, Logic) op)
: super(inps, 'sklansky') {
final iseq = <Logic>[];

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<Logic> inps, Logic Function(Logic, Logic) op)
: super(inps, 'kogge_stone') {
final iseq = <Logic>[];

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<Logic> inps, Logic Function(Logic, Logic) op)
: super(inps, 'brent_kung') {
final iseq = <Logic>[];

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>, Logic Function(Logic, Logic))
ppGen) {
inp = addInput('inp', inp, width: inp.width);
final u =
ppGen(List<Logic>.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>, 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>, 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<Logic>.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<Logic>.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>, Logic Function(Logic, Logic))
ppGen) {
inp = addInput('inp', inp, width: inp.width);
final u = ppGen(List<Logic>.generate(inp.width, (i) => inp[i]),
(lhs, rhs) => rhs & lhs);
addOutput('out', width: inp.width) <=
(List<Logic>.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>, Logic Function(Logic, Logic))
ppGen) {
inp = addInput('inp', inp, width: inp.width);
final u = ppGen(List<Logic>.generate(inp.width, (i) => ~inp[i]),
(lhs, rhs) => rhs & lhs);
addOutput('out', width: inp.width) <=
(List<Logic>.generate(
inp.width, (i) => ((i == 0) ? ~inp[i] : inp[i] ^ u.val[i - 1]))
.rswizzle());
}
}
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ environment:
sdk: '>=2.18.0 <3.0.0'

dependencies:
collection: ^1.18.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NOTE: need to update open-source dependencies prior to merge (I'll take care of it, just marking it here so I don't forget)

meta: ^1.9.1
rohd: ^0.5.0
rohd_vf: ^0.5.0
Expand Down
2 changes: 1 addition & 1 deletion test/one_hot_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// Test of one_hot codec.
//
// 2023 February 24
// Author: Desmond Kirkpatrick
// Author: Desmond Kirkpatrick <[email protected]>

import 'dart:math';

Expand Down
Loading