Repository: intel/rohd (dart)

Issue:
Make `endIndex` in `getRange` an optional positional argument, default to width
### Motivation

It's relatively common to want to grab a bus or value from a certain bit all the way to the end, but right now that requires explicitly specifying the width as the `end` argument of `getRange`.  It would be nice if supplying only the `start` would default to grabbing all the way to the end.

### Desired solution

Modify `getRange` in both `Logic` and `LogicValue` so that `endIndex` is an optional positional argument:
```dart
... getRange(int startIndex, [int? endIndex]) {
```
If `endIndex` is null, then default the value of it to `width`.

### Alternatives considered

_No response_

### Additional details

_No response_

Pull request description:
<!-- Please make sure you check out the contribution guidelines before submitting a pull request! -->

## Description & Motivation

It's relatively common to want to grab a bus or value from a certain bit all the way to the end, but right now that requires explicitly specifying the width as the end argument of getRange. It would be nice if supplying only the start would default to grabbing all the way to the end.

## Related Issue(s)

Fix #228 

## Testing


## Backwards-compatibility

No

## Documentation

> Does the change require any updates to documentation?  If so, where?  Are they included?

Patch:
diff --git a/lib/src/logic.dart b/lib/src/logic.dart
index 0d1471b0e..ac7b8033a 100644
--- a/lib/src/logic.dart
+++ b/lib/src/logic.dart
@@ -668,6 +668,9 @@ class Logic {
   /// [endIndex] are equal, then a zero-width signal is returned.
   /// Negative/Positive index values are allowed. (The negative indexing starts from where the array ends)
   ///
+  /// If [endIndex] is not provided, [width] of the [Logic] will
+  /// be used as the default values which assign it to the last index.
+  ///
   /// ```dart
   /// Logic nextVal = addOutput('nextVal', width: width);
   /// // Example: val = 0xce, val.width = 8, bin(0xce) = "0b11001110"
@@ -676,9 +679,13 @@ class Logic {
   ///
   /// // Positive getRange
   /// nextVal <= val.getRange(0, 6); // = val.slice(0, -2) & output: 0b001110, where the output.width=6
+  ///
+  /// // Get range from startIndex
+  /// nextVal <= val.getRange(-3); // the endIndex will be auto assign to val.width
   /// ```
   ///
-  Logic getRange(int startIndex, int endIndex) {
+  Logic getRange(int startIndex, [int? endIndex]) {
+    endIndex ??= width;
     if (endIndex == startIndex) {
       return Const(0, width: 0);
     }
diff --git a/lib/src/values/logic_value.dart b/lib/src/values/logic_value.dart
index a8c24ead4..eabc0c34f 100644
--- a/lib/src/values/logic_value.dart
+++ b/lib/src/values/logic_value.dart
@@ -467,16 +467,22 @@ abstract class LogicValue {
   /// and [endIndex] are equal, then a zero-width value is returned.
   /// Negative/Positive index values are allowed. (The negative indexing starts from the end=[width]-1)
   ///
+  /// If [endIndex] is not provided, [width] of the [LogicValue] will
+  /// be used as the default values which assign it to the last index.
+  ///
   /// ```dart [TODO]
   /// LogicValue.ofString('0101').getRange(0, 2);   // == LogicValue.ofString('01')
   /// LogicValue.ofString('0101').getRange(1, -2);  // == LogicValue.zero
   /// LogicValue.ofString('0101').getRange(-3, 4);  // == LogicValue.ofString('010')
+  /// LogicValue.ofString('0101').getRange(1);      // == LogicValue.ofString('010')
+  ///
   /// LogicValue.ofString('0101').getRange(-1, -2); // Error - negative end index and start > end - error! start must be less than end
   /// LogicValue.ofString('0101').getRange(2, 1);   // Error - bad inputs start > end
   /// LogicValue.ofString('0101').getRange(0, 7);   // Error - bad inputs end > length-1
   /// ```
   ///
-  LogicValue getRange(int startIndex, int endIndex) {
+  LogicValue getRange(int startIndex, [int? endIndex]) {
+    endIndex ??= width;
     final modifiedStartIndex =
         (startIndex < 0) ? width + startIndex : startIndex;
     final modifiedEndIndex = (endIndex < 0) ? width + endIndex : endIndex;


Test patch:
diff --git a/test/bus_test.dart b/test/bus_test.dart
index 9ab65bfc0..9af8a4c47 100644
--- a/test/bus_test.dart
+++ b/test/bus_test.dart
@@ -39,9 +39,11 @@ class BusTestModule extends Module {
   Logic get aRange1 => output('a_range1');
   Logic get aRange2 => output('a_range2');
   Logic get aRange3 => output('a_range3');
+  Logic get aRange4 => output('a_range4');
   Logic get aNegativeRange1 => output('a_neg_range1');
   Logic get aNegativeRange2 => output('a_neg_range2');
   Logic get aNegativeRange3 => output('a_neg_range3');
+  Logic get aNegativeRange4 => output('a_neg_range4');
   // --- Getters for operator[]
   Logic get aOperatorIndexing1 => output('a_operator_indexing1');
   Logic get aOperatorIndexing2 => output('a_operator_indexing2');
@@ -91,9 +93,11 @@ class BusTestModule extends Module {
     final aRange1 = addOutput('a_range1', width: 3);
     final aRange2 = addOutput('a_range2', width: 2);
     final aRange3 = addOutput('a_range3');
+    final aRange4 = addOutput('a_range4', width: 3);
     final aNegativeRange1 = addOutput('a_neg_range1', width: 3);
     final aNegativeRange2 = addOutput('a_neg_range2', width: 2);
     final aNegativeRange3 = addOutput('a_neg_range3');
+    final aNegativeRange4 = addOutput('a_neg_range4', width: 3);
     // Operator Indexing with positive index value
     final aOperatorIndexing1 = addOutput('a_operator_indexing1');
     final aOperatorIndexing2 = addOutput('a_operator_indexing2');
@@ -128,9 +132,11 @@ class BusTestModule extends Module {
     aRange1 <= a.getRange(5, 8);
     aRange2 <= a.getRange(6, 8);
     aRange3 <= a.getRange(7, 8);
+    aRange4 <= a.getRange(5);
     aNegativeRange1 <= a.getRange(-3, 8); // NOTE: endIndex value is exclusive
     aNegativeRange2 <= a.getRange(-2, 8);
     aNegativeRange3 <= a.getRange(-1, 8);
+    aNegativeRange4 <= a.getRange(-3);
 
     aOperatorIndexing1 <= a[0];
     aOperatorIndexing2 <= a[a.width - 1];
@@ -279,9 +285,11 @@ void main() {
       'a_range1': 3,
       'a_range2': 2,
       'a_range3': 1,
+      'a_range4': 3,
       'a_neg_range1': 3,
       'a_neg_range2': 2,
       'a_neg_range3': 1,
+      'a_neg_range4': 3,
 
       // operator[]
       'a_operator_indexing1': 1,
@@ -458,6 +466,10 @@ void main() {
         Vector({'a': 0}, {'a_range3': 0}),
         Vector({'a': 0x80}, {'a_range3': 1}),
         Vector({'a': bin('10000000')}, {'a_range3': bin('1')}),
+        // Test set 4
+        Vector({'a': 0}, {'a_range4': 0}),
+        Vector({'a': 0xaf}, {'a_range4': 5}),
+        Vector({'a': bin('11000101')}, {'a_range4': bin('110')}),
 
         // Negative Indexing
         // Test set 1
@@ -472,6 +484,10 @@ void main() {
         Vector({'a': 0}, {'a_neg_range3': 0}),
         Vector({'a': 0x80}, {'a_neg_range3': 1}),
         Vector({'a': bin('10000000')}, {'a_neg_range3': bin('1')}),
+        // Test set 4
+        Vector({'a': 0}, {'a_neg_range4': 0}),
+        Vector({'a': 0xaf}, {'a_neg_range4': 5}),
+        Vector({'a': bin('11000101')}, {'a_neg_range4': bin('110')}),
       ];
       await SimCompare.checkFunctionalVector(gtm, vectors);
       final simResult = SimCompare.iverilogVector(
diff --git a/test/logic_value_test.dart b/test/logic_value_test.dart
index 593177b0d..f587bdb7f 100644
--- a/test/logic_value_test.dart
+++ b/test/logic_value_test.dart
@@ -347,6 +347,14 @@ void main() {
           // getRange - good inputs
           LogicValue.ofString('0101').getRange(0, 2),
           equals(LogicValue.ofString('01')));
+      expect(
+          // getRange - slice from range 1
+          LogicValue.ofString('0101').getRange(1),
+          equals(LogicValue.ofString('010')));
+      expect(
+          // getRange - slice from negative range
+          LogicValue.ofString('0101').getRange(-2),
+          equals(LogicValue.ofString('01')));
       expect(
           // getRange - negative end index and start < end
           LogicValue.ofString('0101').getRange(1, -2),