Repository: intel/rohd (dart)

Issue:
Implement `neq`
## Motivation
Equality checks with `eq` are simple, but you have to use `~...eq` for not-equal-to.  It would be nice to be able to do not-equal-to using `neq`.

## Desired solution
Implement `neq` everywhere that `eq` exists (for values and signals).

Pull request description:
<!-- Please make sure you check out the contribution guidelines before submitting a pull request! -->

## Description & Motivation
Equality checks with eq are simple, but need to write ~...eq for not-equal-to. It would be nice to be able to do not-equal-to using neq.

<!-- Description of changes, and motivation for adding them. -->

## Testing

<!-- Please describe how you tested your changes. -->
Updated the test/comparison_test.dart  file for neq w.r.t already used values for the other supported operations.

## Documentation

> Does the change require any updates to documentation? If so, where? Are they included?

<!-- Answer here. -->
Yes. I have updated both README.md and /doc/tutorials/chapter_2/00_basic_logic.md for neq operation.

Patch:
diff --git a/README.md b/README.md
index 2f70cddb6..f4f64270b 100644
--- a/README.md
+++ b/README.md
@@ -260,6 +260,7 @@ a_times_b <=  a * b;   // multiplication
 a_div_b   <=  a / b;   // division
 a_mod_b   <=  a % b;   // modulo
 a_eq_b    <=  a.eq(b)  // equality              NOTE: == is for Object equality of Logic's
+a_neq_b   <=  a.neq(b) // inequality            NOTE: != is for Object inequality of Logic's
 a_lt_b    <=  a.lt(b)  // less than             NOTE: <  is for conditional assignment
 a_lte_b   <=  a.lte(b) // less than or equal    NOTE: <= is for assignment
 a_gt_b    <=  (a > b)  // greater than          NOTE: careful with order of operations, > needs parentheses in this case
diff --git a/doc/tutorials/chapter_2/00_basic_logic.md b/doc/tutorials/chapter_2/00_basic_logic.md
index 81eef3371..c8415f915 100644
--- a/doc/tutorials/chapter_2/00_basic_logic.md
+++ b/doc/tutorials/chapter_2/00_basic_logic.md
@@ -155,6 +155,7 @@ a_times_b <=  a * b;   // multiplication
 a_div_b   <=  a / b;   // division
 a_mod_b   <=  a % b;   // modulo
 a_eq_b    <=  a.eq(b)  // equality              NOTE: == is for Object equality of Logic's
+a_neq_b   <=  a.neq(b) // inequality            NOTE: != is for Object inequality of Logic's
 a_lt_b    <=  a.lt(b)  // less than             NOTE: <  is for conditional assignment
 a_lte_b   <=  a.lte(b) // less than or equal    NOTE: <= is for assignment
 a_gt_b    <=  (a > b)  // greater than          NOTE: careful with order of operations, > needs parentheses in this case
diff --git a/lib/src/logic.dart b/lib/src/logic.dart
index 1f2779784..46414b242 100644
--- a/lib/src/logic.dart
+++ b/lib/src/logic.dart
@@ -574,6 +574,9 @@ class Logic {
   /// Logical equality.
   Logic eq(dynamic other) => Equals(this, other).out;
 
+  /// Logical inequality.
+  Logic neq(dynamic other) => NotEquals(this, other).out;
+
   /// Less-than.
   Logic lt(dynamic other) => LessThan(this, other).out;
 
diff --git a/lib/src/modules/gates.dart b/lib/src/modules/gates.dart
index 809c7389d..b385f7f41 100644
--- a/lib/src/modules/gates.dart
+++ b/lib/src/modules/gates.dart
@@ -478,6 +478,15 @@ class Equals extends _TwoInputComparisonGate {
       : super((a, b) => a.eq(b), '==', in0, in1, name: name);
 }
 
+/// A two-input inequality comparison module.
+class NotEquals extends _TwoInputComparisonGate {
+  /// Calculates whether [in0] and [in1] are not-equal.
+  ///
+  /// [in1] can be either a [Logic] or [int].
+  NotEquals(Logic in0, dynamic in1, {String name = 'notEquals'})
+      : super((a, b) => a.neq(b), '!=', in0, in1, name: name);
+}
+
 /// A two-input comparison module for less-than.
 class LessThan extends _TwoInputComparisonGate {
   /// Calculates whether [in0] is less than [in1].
diff --git a/lib/src/values/logic_value.dart b/lib/src/values/logic_value.dart
index c2caa0027..4fab13bb2 100644
--- a/lib/src/values/logic_value.dart
+++ b/lib/src/values/logic_value.dart
@@ -725,6 +725,14 @@ abstract class LogicValue {
   /// [eq] will return `x`.
   LogicValue eq(dynamic other) => _doCompare(other, (a, b) => a == b);
 
+  /// Not equal-to operation.
+  ///
+  /// This is different from != operator because it returns a [LogicValue]
+  /// instead of a [bool]. It does a logical comparison of the two values,
+  /// rather than exact inequality.  For example, if one of the two values is
+  /// invalid, [neq] will return `x`.
+  LogicValue neq(dynamic other) => _doCompare(other, (a, b) => a != b);
+
   /// Less-than operation.
   ///
   /// WARNING: Signed math is not fully tested.


Test patch:
diff --git a/test/comparison_test.dart b/test/comparison_test.dart
index 957bcfebf..c9a373c74 100644
--- a/test/comparison_test.dart
+++ b/test/comparison_test.dart
@@ -22,24 +22,28 @@ class ComparisonTestModule extends Module {
     b = addInput('b', b, width: b.width);
 
     final aEqB = addOutput('a_eq_b');
+    final aNeqB = addOutput('a_neq_b');
     final aLtB = addOutput('a_lt_b');
     final aLteB = addOutput('a_lte_b');
     final aGtB = addOutput('a_gt_b');
     final aGteB = addOutput('a_gte_b');
 
     final aEqC = addOutput('a_eq_c');
+    final aNeqC = addOutput('a_neq_c');
     final aLtC = addOutput('a_lt_c');
     final aLteC = addOutput('a_lte_c');
     final aGtC = addOutput('a_gt_c');
     final aGteC = addOutput('a_gte_c');
 
     aEqB <= a.eq(b);
+    aNeqB <= a.neq(b);
     aLtB <= a.lt(b);
     aLteB <= a.lte(b);
     aGtB <= (a > b);
     aGteB <= (a >= b);
 
     aEqC <= a.eq(c);
+    aNeqC <= a.neq(c);
     aLtC <= a.lt(c);
     aLteC <= a.lte(c);
     aGtC <= (a > c);
@@ -62,11 +66,13 @@ void main() {
           'b': 0
         }, {
           'a_eq_b': 1,
+          'a_neq_b': 0,
           'a_lt_b': 0,
           'a_lte_b': 1,
           'a_gt_b': 0,
           'a_gte_b': 1,
           'a_eq_c': 0,
+          'a_neq_c': 1,
           'a_lt_c': 1,
           'a_lte_c': 1,
           'a_gt_c': 0,
@@ -77,11 +83,13 @@ void main() {
           'b': 6
         }, {
           'a_eq_b': 0,
+          'a_neq_b': 1,
           'a_lt_b': 1,
           'a_lte_b': 1,
           'a_gt_b': 0,
           'a_gte_b': 0,
           'a_eq_c': 1,
+          'a_neq_c': 0,
           'a_lt_c': 0,
           'a_lte_c': 1,
           'a_gt_c': 0,
@@ -92,11 +100,13 @@ void main() {
           'b': 7
         }, {
           'a_eq_b': 0,
+          'a_neq_b': 1,
           'a_lt_b': 0,
           'a_lte_b': 0,
           'a_gt_b': 1,
           'a_gte_b': 1,
           'a_eq_c': 0,
+          'a_neq_c': 1,
           'a_lt_c': 0,
           'a_lte_c': 0,
           'a_gt_c': 1,
diff --git a/test/logic_value_test.dart b/test/logic_value_test.dart
index 4860aee4c..5052809c7 100644
--- a/test/logic_value_test.dart
+++ b/test/logic_value_test.dart
@@ -477,6 +477,29 @@ void main() {
           equals(LogicValue.x));
     });
 
+    test('inequality', () {
+      expect(
+          // != equal
+          LogicValue.ofString('1111') != LogicValue.ofString('1111'),
+          equals(false));
+      expect(
+          // != not equal
+          LogicValue.ofString('1111') != LogicValue.ofString('1110'),
+          equals(true));
+      expect(
+          // neq equal
+          LogicValue.ofString('1111').neq(LogicValue.ofString('1111')),
+          equals(LogicValue.zero));
+      expect(
+          // neq not equal, valid
+          LogicValue.ofString('1111').neq(LogicValue.ofString('1110')),
+          equals(LogicValue.one));
+      expect(
+          // eq not equal, invalid
+          LogicValue.ofString('1111').neq(LogicValue.ofString('111x')),
+          equals(LogicValue.x));
+    });
+
     test('greater', () {
       expect(
           // >