Repository: intel/rohd (dart)

Issue:
Add support to do `swizzle`-like operations on `LogicValues`
## Motivation
The `swizzle` and `rswizzle` operations on `Logic` are useful, but there's no equivalent for `LogicValues`.  It would be nice to have similar functionality available for `LogicValues`.

## Desired solution
Perhaps some sort of `Swizzleable` type or something so that `swizzle` and `rswizzle` can directly be reused as parameterized functions instead of reimplementing again?  For example:
```dart
SwizzleableType swizzle<SwizzleableType extends Swizzleable>(List<SwizzleableType> components) => ...
```

## Alternatives considered  
Available current solution is just doing things like a bitwise OR, but that's less convenient.  A specific function or constructor for `LogicValues` could work too.

Pull request description:
## Description & Motivation

Deprecated the globally visible `swizzle` and `rswizzle` functions and replaced them with extensions on `List` of certain types so that multiple different types of things can be swizzled.  Types include `Logic` (already supported) as well as `LogicValue` and `LogicValues` so that they can be swizzled directly.

## Related Issue(s)

#70 

## Testing

Added new tests for `LogicValue` and `LogicValues` swizzling.  Existing tests were updated to properly cover `Logic` swizzling.

## Backwards-compatibility

> Is this a breaking change that will not be backwards-compatible?  If yes, how so?

No, but some functions are deprecated

## Documentation

> Does the change require any updates to documentation?  If so, where?  Are they included?

- API docs via comments are updated
- Deprecated decorator is added where appropriate
- Updated README portions that mention swizzling

Patch:
diff --git a/README.md b/README.md
index 1228600a7..3e85cff16 100644
--- a/README.md
+++ b/README.md
@@ -263,11 +263,11 @@ d <= a[7];
 
 // construct e by swizzling bits from b, c, and d
 // here, the MSB is on the left, LSB is on the right
-e <= swizzle([d, c, b]);
+e <= [d, c, b].swizzle();
 
 // alternatively, do a reverse swizzle (useful for lists where 0-index is actually the 0th element)
 // here, the LSB is on the left, the MSB is on the right
-e <= rswizzle([b, c, d]);
+e <= [b, c, d].rswizzle();
 ```
 
 ROHD does not (currently) support assignment to a subset of a bus.  That is, you *cannot* do something like `e[3] <= d`.  If you need to build a bus from a collection of other signals, use swizzling.
@@ -421,7 +421,7 @@ Sequential(clk, [
 ROHD supports [`Case`](https://intel.github.io/rohd/rohd/Case-class.html) and [`CaseZ`](https://intel.github.io/rohd/rohd/CaseZ-class.html) statements, including priority and unique flavors, which are implemented in the same way as SystemVerilog.  For example:
 ```dart
 Combinational([
-  Case(swizzle([b,a]), [
+  Case([b,a].swizzle(), [
       CaseItem(Const(LogicValues.fromString('01')), [
         c < 1,
         d < 0
@@ -436,7 +436,7 @@ Combinational([
     ],
     conditionalType: ConditionalType.Unique
   ),
-  CaseZ(swizzle([b,a]),[
+  CaseZ([b,a].swizzle(),[
       CaseItem(Const(LogicValues.fromString('z1')), [
         e < 1,
       ])
diff --git a/lib/rohd.dart b/lib/rohd.dart
index c88b69ba5..8145d997b 100644
--- a/lib/rohd.dart
+++ b/lib/rohd.dart
@@ -10,3 +10,4 @@ export 'src/interface.dart';
 export 'src/external.dart';
 export 'src/values/values.dart';
 export 'src/synthesizers/synthesizers.dart';
+export 'src/swizzle.dart';
diff --git a/lib/src/modules/bus.dart b/lib/src/modules/bus.dart
index 930efc66b..e1093c48e 100644
--- a/lib/src/modules/bus.dart
+++ b/lib/src/modules/bus.dart
@@ -81,26 +81,6 @@ class BusSubset extends Module with InlineSystemVerilog {
   }
 }
 
-/// Performs a concatenation operation on the list of signals, where index 0 of [signals] is
-/// the *most* significant bit(s).
-///
-/// This is the one you should use if you're writing something like SystemVerilog's `{}` notation.
-/// If you write `swizzle([a, b, c])` you would get a single output [Logic] where the bits in `a`
-/// are the most significant (highest) bits.
-///
-/// If you want the opposite, check out [rswizzle()].
-Logic swizzle(List<Logic> signals) => Swizzle(signals).out;
-
-/// Performs a concatenation operation on the list of signals, where index 0 of [signals] is
-/// the *least* significant bit(s).
-///
-/// This is the one you should probably use if you're trying to concatenate a generated [List] of signals.
-/// If you write `rswizzle([a, b, c])` you would get a single output [Logic] where the bits in `a`
-/// are the least significant (lowest) bits.
-///
-/// If you want the opposite, check out [swizzle()].
-Logic rswizzle(List<Logic> signals) => Swizzle(signals.reversed.toList()).out;
-
 /// A [Module] that performs concatenation of signals into one bigger [Logic].
 ///
 /// The concatenation occurs such that index 0 of [signals] is the *most* significant bit(s).
diff --git a/lib/src/swizzle.dart b/lib/src/swizzle.dart
new file mode 100644
index 000000000..a72b37c1c
--- /dev/null
+++ b/lib/src/swizzle.dart
@@ -0,0 +1,104 @@
+/// Copyright (C) 2022 Intel Corporation
+/// SPDX-License-Identifier: BSD-3-Clause
+///
+/// swizzle_test.dart
+/// Tests for swizzling values
+///
+/// 2022 January 6
+/// Author: Max Korbel <max.korbel@intel.com>
+///
+
+import 'package:rohd/rohd.dart';
+
+/// Allows lists of [Logic]s to be swizzled.
+extension LogicSwizzle on List<Logic> {
+  /// Performs a concatenation operation on the list of signals, where index 0 of this list is
+  /// the *most* significant bit(s).
+  ///
+  /// This is the one you should use if you're writing something like SystemVerilog's `{}` notation.
+  /// If you call [swizzle] on `[a, b, c]` you would get a single output [Logic] where the bits in `a`
+  /// are the most significant (highest) bits.
+  ///
+  /// If you want the opposite, check out [rswizzle].
+  Logic swizzle() => Swizzle(this).out;
+
+  /// Performs a concatenation operation on the list of signals, where index 0 of this list is
+  /// the *least* significant bit(s).
+  ///
+  /// This is the one you should probably use if you're trying to concatenate a generated [List] of signals.
+  /// If you call [rswizzle] on `[a, b, c]` you would get a single output [Logic] where the bits in `a`
+  /// are the least significant (lowest) bits.
+  ///
+  /// If you want the opposite, check out [swizzle].
+  Logic rswizzle() => Swizzle(reversed.toList()).out;
+}
+
+/// Allows lists of [LogicValue]s to be swizzled.
+extension LogicValueSwizzle on List<LogicValue> {
+  /// Performs a concatenation operation on the list of signals, where index 0 of this list is
+  /// the *most* significant bit.
+  ///
+  /// This is the one you should use if you're writing something like SystemVerilog's `{}` notation.
+  /// If you call [swizzle] on `[a, b, c]` you would get a single output [LogicValues] where the bits in `a`
+  /// are the most significant (highest) bits.
+  ///
+  /// If you want the opposite, check out [rswizzle].
+  LogicValues swizzle() => LogicValues.from(reversed);
+
+  /// Performs a concatenation operation on the list of signals, where index 0 of this list is
+  /// the *least* significant bit.
+  ///
+  /// This is the one you should probably use if you're trying to concatenate a generated [List] of signals.
+  /// If you call [rswizzle] on `[a, b, c]` you would get a single output [LogicValues] where the bits in `a`
+  /// are the least significant (lowest) bits.
+  ///
+  /// If you want the opposite, check out [swizzle].
+  LogicValues rswizzle() => LogicValues.from(this);
+}
+
+/// Allows lists of [LogicValues]s to be swizzled.
+extension LogicValuesSwizzle on List<LogicValues> {
+  /// Performs a concatenation operation on the list of signals, where index 0 of this list is
+  /// the *most* significant bit(s).
+  ///
+  /// This is the one you should use if you're writing something like SystemVerilog's `{}` notation.
+  /// If you call [swizzle] on `[a, b, c]` you would get a single output [LogicValues] where the bits in `a`
+  /// are the most significant (highest) bits.
+  ///
+  /// If you want the opposite, check out [rswizzle].
+  LogicValues swizzle() =>
+      LogicValues.from(reversed.map((e) => e.toList()).expand((e) => e));
+
+  /// Performs a concatenation operation on the list of signals, where index 0 of this list is
+  /// the *least* significant bit(s).
+  ///
+  /// This is the one you should probably use if you're trying to concatenate a generated [List] of signals.
+  /// If you call [rswizzle] on `[a, b, c]` you would get a single output [LogicValues] where the bits in `a`
+  /// are the least significant (lowest) bits.
+  ///
+  /// If you want the opposite, check out [swizzle].
+  LogicValues rswizzle() =>
+      LogicValues.from(map((e) => e.toList()).expand((e) => e));
+}
+
+/// Performs a concatenation operation on the list of signals, where index 0 of [signals] is
+/// the *most* significant bit(s).
+///
+/// This is the one you should use if you're writing something like SystemVerilog's `{}` notation.
+/// If you write `swizzle([a, b, c])` you would get a single output [Logic] where the bits in `a`
+/// are the most significant (highest) bits.
+///
+/// If you want the opposite, check out [rswizzle()].
+@Deprecated('Use `List<Logic>.swizzle()` instead')
+Logic swizzle(List<Logic> signals) => signals.swizzle();
+
+/// Performs a concatenation operation on the list of signals, where index 0 of [signals] is
+/// the *least* significant bit(s).
+///
+/// This is the one you should probably use if you're trying to concatenate a generated [List] of signals.
+/// If you write `rswizzle([a, b, c])` you would get a single output [Logic] where the bits in `a`
+/// are the least significant (lowest) bits.
+///
+/// If you want the opposite, check out [swizzle()].
+@Deprecated('Use `List<Logic>.rswizzle()` instead')
+Logic rswizzle(List<Logic> signals) => signals.rswizzle();


Test patch:
diff --git a/test/conditionals_test.dart b/test/conditionals_test.dart
index 101b683b8..da54595b7 100644
--- a/test/conditionals_test.dart
+++ b/test/conditionals_test.dart
@@ -38,7 +38,7 @@ class CaseModule extends Module {
 
     Combinational([
       Case(
-          swizzle([b, a]),
+          [b, a].swizzle(),
           [
             CaseItem(Const(LogicValues.fromString('01')), [c < 1, d < 0]),
             CaseItem(Const(LogicValues.fromString('10')), [
@@ -52,9 +52,9 @@ class CaseModule extends Module {
           ],
           conditionalType: ConditionalType.unique),
       CaseZ(
-          swizzle([b, a]),
+          [b, a].rswizzle(),
           [
-            CaseItem(Const(LogicValues.fromString('z1')), [
+            CaseItem(Const(LogicValues.fromString('1z')), [
               e < 1,
             ])
           ],
diff --git a/test/swizzle_test.dart b/test/swizzle_test.dart
new file mode 100644
index 000000000..2759cb643
--- /dev/null
+++ b/test/swizzle_test.dart
@@ -0,0 +1,44 @@
+/// Copyright (C) 2022 Intel Corporation
+/// SPDX-License-Identifier: BSD-3-Clause
+///
+/// swizzle_test.dart
+/// Tests for swizzling values
+///
+/// 2022 January 6
+/// Author: Max Korbel <max.korbel@intel.com>
+///
+
+import 'package:rohd/rohd.dart';
+import 'package:test/test.dart';
+
+void main() {
+  group('LogicValue', () {
+    test('simple swizzle', () {
+      expect(
+          [LogicValue.one, LogicValue.zero, LogicValue.x, LogicValue.z]
+              .swizzle(),
+          equals(LogicValues.fromString('10xz')));
+    });
+    test('simple rswizzle', () {
+      expect(
+          [LogicValue.one, LogicValue.zero, LogicValue.x, LogicValue.z]
+              .rswizzle(),
+          equals(LogicValues.fromString('zx01')));
+    });
+  });
+  group('LogicValues', () {
+    test('simple swizzle', () {
+      expect(
+          [LogicValues.fromString('10'), LogicValues.fromString('xz')]
+              .swizzle(),
+          equals(LogicValues.fromString('10xz')));
+    });
+
+    test('simple rswizzle', () {
+      expect(
+          [LogicValues.fromString('10'), LogicValues.fromString('xz')]
+              .rswizzle(),
+          equals(LogicValues.fromString('xz10')));
+    });
+  });
+}