Repository: intel/rohd (dart)

Issue:
Gates should output `X` (never `Z`) when inputs are invalid
### Describe the bug

Some gates (e.g. the `Mux`) will potentially output a `Z` if the input (e.g. the control) is a `Z` instead of outputting an `X`.  We should fix the `Mux` and also search for any other gates or built-in modules that may be outputting a `Z` instead of an `X` when inputs are invalid.

### To Reproduce

Set the control on `Mux` to `Z`, and observe output value.

### Expected behavior

Output is `X`

### Actual behavior

Output is `Z`

### Additional: Dart SDK info

_No response_

### Additional: pubspec.yaml

_No response_

### Additional: Context

_No response_

Pull request description:
<!-- Please make sure you check out the contribution guidelines before submitting a pull request! -->

## Description & Motivation

Some gates (e.g. the Mux) will potentially output a Z if the input (e.g. the control) is a Z instead of outputting an X. We should fix the Mux and also search for any other gates or built-in modules that may be outputting a Z instead of an X when inputs are invalid.
## Related Issue(s)

fix #235 

## 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/benchmark/comb_guard_fanout_benchmark.dart b/benchmark/comb_guard_fanout_benchmark.dart
index 446ddd528..bac930106 100644
--- a/benchmark/comb_guard_fanout_benchmark.dart
+++ b/benchmark/comb_guard_fanout_benchmark.dart
@@ -48,11 +48,6 @@ class CombGuardFanoutBenchmark extends AsyncBenchmarkBase {
   CombGuardFanoutBenchmark({this.numPuts = 100})
       : super('CombGuardFanoutBenchmark');
 
-  @override
-  Future<void> teardown() async {
-    await Simulator.reset();
-  }
-
   CombGuardFanout? mod;
   final Logic a = Logic(width: 8);
 
diff --git a/lib/src/modules/conditional.dart b/lib/src/modules/conditional.dart
index b11b3487a..7852fe296 100644
--- a/lib/src/modules/conditional.dart
+++ b/lib/src/modules/conditional.dart
@@ -855,7 +855,12 @@ class ConditionalAssign extends Conditional {
       guard(driver);
     }
 
-    _receiverOutput.put(driverValue(driver));
+    final currentValue = driverValue(driver);
+    if (!currentValue.isValid) {
+      _receiverOutput.put(LogicValue.x);
+    } else {
+      _receiverOutput.put(currentValue);
+    }
 
     if (!drivenSignals.contains(receiver) || receiver.value.isValid) {
       drivenSignals.add(receiver);
@@ -1406,12 +1411,7 @@ class If extends Conditional {
         break;
       } else if (driverValue(iff.condition) != LogicValue.zero) {
         // x and z propagation
-        for (final receiver in receivers) {
-          receiverOutput(receiver).put(driverValue(iff.condition)[0]);
-          if (!drivenSignals.contains(receiver) || receiver.value.isValid) {
-            drivenSignals.add(receiver);
-          }
-        }
+        _driveX(drivenSignals);
         break;
       }
       // if it's 0, then continue searching down the path
diff --git a/lib/src/modules/gates.dart b/lib/src/modules/gates.dart
index 7415e58ff..f7194efe5 100644
--- a/lib/src/modules/gates.dart
+++ b/lib/src/modules/gates.dart
@@ -661,11 +661,11 @@ class Mux extends Module with InlineSystemVerilog {
   /// Executes the functional behavior of the mux.
   void _execute() {
     if (!_control.value.isValid) {
-      out.put(_control.value);
+      out.put(LogicValue.x);
     } else if (_control.value == LogicValue.zero) {
-      out.put(_d0.value);
+      out.put(_d0.value.isValid ? _d0.value : LogicValue.x);
     } else if (_control.value == LogicValue.one) {
-      out.put(_d1.value);
+      out.put(_d1.value.isValid ? _d1.value : LogicValue.x);
     }
   }
 
diff --git a/lib/src/utilities/simcompare.dart b/lib/src/utilities/simcompare.dart
index 4a6b073ad..95ac4b342 100644
--- a/lib/src/utilities/simcompare.dart
+++ b/lib/src/utilities/simcompare.dart
@@ -86,11 +86,9 @@ class Vector {
         }
         return arrAssigns.toString();
       } else {
-        var assignmentValue = inputValues[signalName];
-        if (assignmentValue is BigInt) {
-          assignmentValue = LogicValue.of(assignmentValue, width: signal.width);
-        }
-        return '$signalName = $assignmentValue;';
+        final signalVal =
+            LogicValue.of(inputValues[signalName], width: signal.width);
+        return '$signalName = $signalVal;';
       }
     }).join('\n');
 


Test patch:
diff --git a/test/conditionals_test.dart b/test/conditionals_test.dart
index 981f73607..01905c1c5 100644
--- a/test/conditionals_test.dart
+++ b/test/conditionals_test.dart
@@ -163,6 +163,16 @@ class UniqueCase extends Module {
 
 enum SeqCondModuleType { caseNormal, caseZ, ifNormal }
 
+class ConditionalAssignModule extends Module {
+  ConditionalAssignModule(
+    Logic a,
+  ) : super(name: 'ConditionalAssignModule') {
+    a = addInput('a', a);
+    final c = addOutput('c');
+    Combinational([c < a]);
+  }
+}
+
 class SeqCondModule extends Module {
   Logic get equal => output('equal');
   SeqCondModule(Logic clk, Logic a, {required SeqCondModuleType combType}) {
@@ -214,6 +224,18 @@ class IfBlockModule extends Module {
   }
 }
 
+class IffModule extends Module {
+  IffModule(Logic a, Logic b) : super(name: 'Iffmodule') {
+    a = addInput('a', a);
+    b = addInput('b', b);
+    final c = addOutput('c');
+
+    Combinational([
+      If(a, then: [c < b])
+    ]);
+  }
+}
+
 class SingleIfBlockModule extends Module {
   SingleIfBlockModule(Logic a) : super(name: 'singleifblockmodule') {
     a = addInput('a', a);
@@ -537,6 +559,17 @@ void main() {
       expect(simResult, equals(true));
     });
 
+    test('if invalid ', () async {
+      final mod = IffModule(Logic(), Logic());
+      await mod.build();
+      final vectors = [
+        Vector({'a': 1, 'b': 0}, {'c': 0}),
+        Vector({'a': LogicValue.z, 'b': 1}, {'c': LogicValue.x}),
+        Vector({'a': LogicValue.x, 'b': 0}, {'c': LogicValue.x}),
+      ];
+      await SimCompare.checkFunctionalVector(mod, vectors);
+    });
+
     test('single iffblock comb', () async {
       final mod = SingleIfBlockModule(Logic());
       await mod.build();
@@ -562,6 +595,18 @@ void main() {
       expect(simResult, equals(true));
     });
 
+    test('Conditional assign module with invalid inputs', () async {
+      final mod = ConditionalAssignModule(Logic());
+      await mod.build();
+      final vectors = [
+        Vector({'a': 1}, {'c': 1}),
+        Vector({'a': 0}, {'c': 0}),
+        Vector({'a': LogicValue.z}, {'c': LogicValue.x}),
+        Vector({'a': LogicValue.x}, {'c': LogicValue.x}),
+      ];
+      await SimCompare.checkFunctionalVector(mod, vectors);
+    });
+
     test('single elseifblock comb', () async {
       final mod = SingleElseIfBlockModule(Logic());
       await mod.build();
diff --git a/test/gate_test.dart b/test/gate_test.dart
index 032ecbb62..cde781e8e 100644
--- a/test/gate_test.dart
+++ b/test/gate_test.dart
@@ -414,13 +414,25 @@ void main() {
     test('Mux bus', () async {
       final mod = MuxWrapper(Logic(), Logic(width: 8), Logic(width: 8));
       await mod.build();
-      final vectors = [
+      final vector1 = [
         Vector({'control': 1, 'd0': 12, 'd1': 15}, {'y': 15}),
         Vector({'control': 0, 'd0': 18, 'd1': 7}, {'y': 18}),
         Vector({'control': 0, 'd0': 3, 'd1': 6}, {'y': 3}),
+        Vector({'control': 0, 'd0': 10, 'd1': LogicValue.z}, {'y': 10}),
+        Vector({'control': 1, 'd0': LogicValue.z, 'd1': 6}, {'y': 6}),
       ];
-      await SimCompare.checkFunctionalVector(mod, vectors);
-      final simResult = SimCompare.iverilogVector(mod, vectors);
+
+      final vector2 = [
+        Vector(
+            {'control': 1, 'd0': 6, 'd1': LogicValue.z}, {'y': LogicValue.x}),
+        Vector(
+            {'control': LogicValue.z, 'd0': 10, 'd1': 6}, {'y': LogicValue.x}),
+        Vector(
+            {'control': 0, 'd0': LogicValue.z, 'd1': 10}, {'y': LogicValue.x}),
+      ];
+
+      await SimCompare.checkFunctionalVector(mod, vector1 + vector2);
+      final simResult = SimCompare.iverilogVector(mod, vector1);
       expect(simResult, equals(true));
     });