Repository: intel/rohd
Pull request #438 (2023-11-16 20:52:09)

Get a Logic of a Logic List via an index 
<!-- Please make sure you check out the contribution guidelines before submitting a pull request! -->

## Description & Motivation

Logic Indexing 

2 new features
- `Logic.selectFrom(List<Logic>)`
- `List<Logic>.selectIndex(Logic index)`

## Related Issue(s)

#116 

## Testing
- done

## Backwards-compatibility

This is a new feature
- A `Logic` interface/class is now supported with ``Logic.selectFrom(List<Logic>)`
- An extension of logic array is created add 
  - `List<Logic>.selectIndex(Logic index)`


## Documentation
> TBD

<!-- Answer here. -->


RPG-coder-intc: @mkorbel1 this PR will focus on #116 

Patch:
diff --git a/lib/rohd.dart b/lib/rohd.dart
index d5a29fde..84150559 100644
--- a/lib/rohd.dart
+++ b/lib/rohd.dart
@@ -7,6 +7,7 @@ export 'src/finite_state_machine.dart';
 export 'src/interfaces/interfaces.dart';
 export 'src/module.dart';
 export 'src/modules/modules.dart';
+export 'src/selection.dart';
 export 'src/signals/signals.dart';
 export 'src/simulator.dart';
 export 'src/swizzle.dart';
diff --git a/lib/src/selection.dart b/lib/src/selection.dart
new file mode 100644
index 00000000..819b9d3d
--- /dev/null
+++ b/lib/src/selection.dart
@@ -0,0 +1,32 @@
+// Copyright (C) 2023 Intel Corporation
+// SPDX-License-Identifier: BSD-3-Clause
+//
+// selection.dart
+// Definition for selecting a Logic from List<Logic> by a given index.
+//
+// 2023 November 14
+// Author: Rahul Gautham Putcha <rahul.gautham.putcha@intel.com>
+
+import 'package:rohd/rohd.dart';
+
+/// Allows a lists of [Logic]s to have its elemets picked
+/// by a [Logic] index value.
+extension IndexedLogic on List<Logic> {
+  /// Performs a [index] based selection on an [List] of [Logic].
+  ///
+  /// Given a [List] of [Logic] say `logicList` on which we apply [selectIndex]
+  /// and an element [index] as argument , we can select any valid element
+  /// of type [Logic] within the `logicList` using the [index] of [Logic] type.
+  ///
+  /// Alternatively we can approach this with `index.selectFrom(logicList)`
+  ///
+  /// Example:
+  /// ```
+  /// // ordering matches closer to array indexing with `0` index-based.
+  /// List<Logic> logicList = [/* Add your Logic elements here */];
+  /// selected <= logicList.selectIndex(index);
+  /// ```
+  ///
+  Logic selectIndex(Logic index, {Logic? defaultValue}) =>
+      index.selectFrom(this, defaultValue: defaultValue);
+}
diff --git a/lib/src/signals/logic.dart b/lib/src/signals/logic.dart
index 737fe0c6..44837011 100644
--- a/lib/src/signals/logic.dart
+++ b/lib/src/signals/logic.dart
@@ -6,7 +6,8 @@
 // simulator, as well as basic operations on them
 //
 // 2021 August 2
-// Author: Max Korbel <max.korbel@intel.com>
+// Author: Max Korbel <max.korbel@intel.com>,
+//         Rahul Gautham Putcha <rahul.gautham.putcha@intel.com>
 
 part of 'signals.dart';
 
@@ -712,4 +713,42 @@ class Logic {
     }
     return isLogicIn;
   }
+
+  /// Performs a [Logic] `index` based selection on an [List] of [Logic]
+  /// named [busList].
+  ///
+  /// Using the [Logic] `index` on which [selectFrom] is performed on and
+  /// a [List] of [Logic] named [busList] for `index` based selection, we can
+  /// select any valid element of type [Logic] within the `logicList` using
+  /// the `index` of [Logic] type.
+  ///
+  /// Alternatively we can approach this with `busList.selectIndex(index)`
+  ///
+  /// Example:
+  /// ```
+  /// // ordering matches closer to array indexing with `0` index-based.
+  /// selected <= index.selectFrom(busList);
+  /// ```
+  ///
+  Logic selectFrom(List<Logic> busList, {Logic? defaultValue}) {
+    final selected = Logic(
+        name: 'selectFrom',
+        width: busList.first.width,
+        naming: Naming.mergeable);
+
+    Combinational(
+      [
+        Case(
+            this,
+            [
+              for (var i = 0; i < busList.length; i++)
+                CaseItem(Const(i, width: width), [selected < busList[i]])
+            ],
+            conditionalType: ConditionalType.unique,
+            defaultItem: [selected < (defaultValue ?? 0)])
+      ],
+    );
+
+    return selected;
+  }
 }
diff --git a/lib/src/signals/logic_structure.dart b/lib/src/signals/logic_structure.dart
index 44790b42..0a5a2510 100644
--- a/lib/src/signals/logic_structure.dart
+++ b/lib/src/signals/logic_structure.dart
@@ -515,4 +515,8 @@ class LogicStructure implements Logic {
   void _updateWire(_Wire newWire) {
     throw UnsupportedError('Delegated to elements');
   }
+
+  @override
+  Logic selectFrom(List<Logic> busList, {Logic? defaultValue}) =>
+      packed.selectFrom(busList, defaultValue: defaultValue);
 }


Test patch:
diff --git a/test/bus_test.dart b/test/bus_test.dart
index 5b7cd00d..989be34b 100644
--- a/test/bus_test.dart
+++ b/test/bus_test.dart
@@ -7,10 +7,61 @@
 // 2021 May 7
 // Author: Max Korbel <max.korbel@intel.com>
 
+import 'dart:math';
+
 import 'package:rohd/rohd.dart';
 import 'package:rohd/src/utilities/simcompare.dart';
 import 'package:test/test.dart';
 
+class SelectTestModule extends Module {
+  Logic get selectIndexValue => output('selectIndexValue');
+  Logic get selectFromValue => output('selectFromValue');
+
+  SelectTestModule(Logic a1, Logic a2, Logic a3, Logic b, {Logic? defaultValue})
+      : super(name: 'selecttestmodule') {
+    a1 = addInput('a1', a1, width: a1.width);
+    a2 = addInput('a2', a2, width: a2.width);
+    a3 = addInput('a3', a3, width: a3.width);
+    b = addInput('b', b, width: b.width);
+
+    if (defaultValue != null) {
+      defaultValue =
+          addInput('defaultValue', defaultValue, width: defaultValue.width);
+      selectWithDefaultValue(a1, a2, a3, b, defaultValue);
+    } else {
+      selectWithoutDefaultValue(a1, a2, a3, b);
+    }
+  }
+
+  void selectWithoutDefaultValue(Logic a1, Logic a2, Logic a3, Logic b) {
+    final selectIndexValue = addOutput('selectIndexValue', width: a1.width);
+    final selectFromValue = addOutput('selectFromValue', width: a1.width);
+
+    if (a1.width != a2.width || a1.width != a3.width) {
+      throw Exception('a1, a2 and a3 must be same width.');
+    }
+
+    final logicList = <Logic>[a1, a2, a3];
+
+    selectIndexValue <= logicList.selectIndex(b);
+    selectFromValue <= b.selectFrom(logicList);
+  }
+
+  void selectWithDefaultValue(
+      Logic a1, Logic a2, Logic a3, Logic b, Logic defaultValue) {
+    final selectFromValue = addOutput('selectFromValue', width: a1.width);
+    final selectIndexValue = addOutput('selectIndexValue', width: a1.width);
+
+    if (a1.width != a2.width || a1.width != a3.width) {
+      throw Exception('a1, a2 and a3 must be same width.');
+    }
+
+    final logicList = <Logic>[a1, a2, a3];
+    selectFromValue <= b.selectFrom(logicList, defaultValue: defaultValue);
+    selectIndexValue <= logicList.selectIndex(b, defaultValue: defaultValue);
+  }
+}
+
 class BusTestModule extends Module {
   // --- Getters ---
   Logic get aBar => output('a_bar');
@@ -561,5 +612,36 @@ void main() {
       await SimCompare.checkFunctionalVector(gtm, vectors);
       SimCompare.checkIverilogVector(gtm, vectors);
     });
+
+    test('selectFrom and selectIndex', () async {
+      final gtm = SelectTestModule(Logic(width: 8), Logic(width: 8),
+          Logic(width: 8), Logic(width: (log(8) / log(2)).ceil()));
+      await gtm.build();
+      final vectors = [
+        Vector({'a1': 1, 'a2': 2, 'a3': 3, 'b': 1},
+            {'selectIndexValue': 2, 'selectFromValue': 2}),
+        Vector({'a1': 1, 'a2': 2, 'a3': 3, 'b': 0},
+            {'selectIndexValue': 1, 'selectFromValue': 1}),
+        Vector({'a1': 1, 'a2': 2, 'a3': 3, 'b': 2},
+            {'selectIndexValue': 3, 'selectFromValue': 3})
+      ];
+      await SimCompare.checkFunctionalVector(gtm, vectors);
+      final simResult = SimCompare.iverilogVector(gtm, vectors);
+      expect(simResult, equals(true));
+    });
+
+    test('selectFrom with default Value', () async {
+      final gtm = SelectTestModule(Logic(width: 8), Logic(width: 8),
+          Logic(width: 8), Logic(width: (log(8) / log(2)).ceil()),
+          defaultValue: Logic(width: 8));
+      await gtm.build();
+      final vectors = [
+        Vector({'a1': 1, 'a2': 2, 'a3': 3, 'b': 4, 'defaultValue': 5},
+            {'selectFromValue': 5, 'selectIndexValue': 5}),
+      ];
+      await SimCompare.checkFunctionalVector(gtm, vectors);
+      final simResult = SimCompare.iverilogVector(gtm, vectors);
+      expect(simResult, equals(true));
+    });
   });
 }