Repository: intel/rohd (dart)

Issue:
Unique `Case` with multiple match behavior
## Motivation
When multiple cases match on a unique case statement, it currently causes an exception to be thrown.  Perhaps this should be a configurable option allowing X's to be driven instead.

## Desired solution
Always drive X when there's a violation of unique rules, and raise exception on it as well in a configurable way (default enabled) on a per-`Case` basis.

## Alternatives considered  
A global switch for this type of check could also be an option.

## Additional details
SystemVerilog by default just prints a warning message (http://www.verilogpro.com/systemverilog-unique-priority/) which seems not great.

Pull request description:
<!-- Please make sure you check out the contribution guidelines before submitting a pull request! -->

## Description & Motivation

When multiple cases match on a unique case statement, it currently causes an exception to be thrown. Perhaps this should be a configurable option allowing X's to be driven instead. 

## Related Issue(s)

Fix #107

## Testing

<!-- Please describe how you tested your changes. -->

## Backwards-compatibility

> Is this a breaking change that will not be backwards-compatible? If yes, how so?

<!-- Answer here. -->

## Documentation

> Does the change require any updates to documentation? If so, where? Are they included?

<!-- Answer here. -->

Patch:
diff --git a/lib/src/modules/conditional.dart b/lib/src/modules/conditional.dart
index 8c46498f6..535e35729 100644
--- a/lib/src/modules/conditional.dart
+++ b/lib/src/modules/conditional.dart
@@ -740,6 +740,16 @@ abstract class Conditional {
   /// This is used for [Combinational.ssa].
   Map<Logic, Logic> _processSsa(Map<Logic, Logic> currentMappings,
       {required int context});
+
+  /// Drives X to all receivers.
+  void _driveX(Set<Logic> drivenSignals) {
+    for (final receiver in receivers) {
+      receiverOutput(receiver).put(LogicValue.x);
+      if (!drivenSignals.contains(receiver) || receiver.value.isValid) {
+        drivenSignals.add(receiver);
+      }
+    }
+  }
 }
 
 /// Represents a group of [Conditional]s to be executed.
@@ -957,12 +967,7 @@ class Case extends Conditional {
 
     if (!expression.value.isValid) {
       // if expression has X or Z, then propogate X's!
-      for (final receiver in receivers) {
-        receiverOutput(receiver).put(LogicValue.x);
-        if (!drivenSignals.contains(receiver) || receiver.value.isValid) {
-          drivenSignals.add(receiver);
-        }
-      }
+      _driveX(drivenSignals);
       return;
     }
 
@@ -975,9 +980,8 @@ class Case extends Conditional {
           conditional.execute(drivenSignals, guard);
         }
         if (foundMatch != null && conditionalType == ConditionalType.unique) {
-          throw Exception('Unique case statement had multiple matching cases.'
-              ' Original: "$foundMatch".'
-              ' Duplicate: "$item".');
+          _driveX(drivenSignals);
+          return;
         }
 
         foundMatch = item;
@@ -996,8 +1000,8 @@ class Case extends Conditional {
     } else if (foundMatch == null &&
         (conditionalType == ConditionalType.unique ||
             conditionalType == ConditionalType.priority)) {
-      throw Exception('$conditionalType case statement had no matching case,'
-          ' and type was $conditionalType.');
+      _driveX(drivenSignals);
+      return;
     }
   }
 


Test patch:
diff --git a/test/conditionals_test.dart b/test/conditionals_test.dart
index 829c8ee0f..4c87cb3a3 100644
--- a/test/conditionals_test.dart
+++ b/test/conditionals_test.dart
@@ -141,6 +141,28 @@ class CaseModule extends Module {
   }
 }
 
+class UniqueCase extends Module {
+  UniqueCase(Logic a, Logic b) : super(name: 'UniqueCase') {
+    a = addInput('a', a);
+    b = addInput('b', b);
+    final c = addOutput('c');
+    final d = addOutput('d');
+    Combinational([
+      Case(
+          Const(1),
+          [
+            CaseItem(a, [c < 1, d < 0]),
+            CaseItem(b, [c < 1, d < 0]),
+          ],
+          defaultItem: [
+            c < 0,
+            d < 1,
+          ],
+          conditionalType: ConditionalType.unique),
+    ]);
+  }
+}
+
 enum SeqCondModuleType { caseNormal, caseZ, ifNormal }
 
 class SeqCondModule extends Module {
@@ -568,6 +590,18 @@ void main() {
       expect(simResult, equals(true));
     });
 
+    test('Unique case', () async {
+      final mod = UniqueCase(Logic(), Logic());
+      await mod.build();
+      final vectors = [
+        Vector({'a': 0, 'b': 0}, {'c': 0, 'd': 1}),
+        Vector({'a': 0, 'b': 1}, {'c': 1, 'd': 0}),
+        Vector({'a': 1, 'b': 0}, {'c': 1, 'd': 0}),
+        Vector({'a': 1, 'b': 1}, {'c': LogicValue.x, 'd': LogicValue.x}),
+      ];
+      await SimCompare.checkFunctionalVector(mod, vectors);
+    });
+
     test('conditional ff', () async {
       final mod = SequentialModule(Logic(), Logic(), Logic(width: 8));
       await mod.build();