summaryrefslogtreecommitdiff
path: root/core/src
diff options
context:
space:
mode:
Diffstat (limited to 'core/src')
-rw-r--r--core/src/main/scala/chisel3/internal/BiConnect.scala27
1 files changed, 19 insertions, 8 deletions
diff --git a/core/src/main/scala/chisel3/internal/BiConnect.scala b/core/src/main/scala/chisel3/internal/BiConnect.scala
index 4a9bb4f5..aa58cb95 100644
--- a/core/src/main/scala/chisel3/internal/BiConnect.scala
+++ b/core/src/main/scala/chisel3/internal/BiConnect.scala
@@ -11,6 +11,8 @@ import chisel3.internal.firrtl.{Connect, DefInvalid}
import scala.language.experimental.macros
import chisel3.internal.sourceinfo._
+import scala.annotation.tailrec
+
/**
* BiConnect.connect executes a bidirectional connection element-wise.
*
@@ -120,15 +122,24 @@ private[chisel3] object BiConnect {
val notStrict =
Seq(left_r.compileOptions, right_r.compileOptions).contains(ExplicitCompileOptions.NotStrict)
if (notStrict) {
- // chisel3 <> is commutative but FIRRTL <- is not
- val flipped = {
- import ActualDirection._
- // Everything is flipped when it's the port of a child
- val childPort = left_r._parent.get != context_mod
- val isFlipped = Seq(Bidirectional(Flipped), Input).contains(left_r.direction)
- isFlipped ^ childPort
+ // Traces flow from a child Data to its parent
+ @tailrec def traceFlow(currentlyFlipped: Boolean, data: Data): Boolean = {
+ import SpecifiedDirection.{Input => SInput, Flip => SFlip}
+ val sdir = data.specifiedDirection
+ val flipped = sdir == SInput || sdir == SFlip
+ data.binding.get match {
+ case ChildBinding(parent) => traceFlow(flipped ^ currentlyFlipped, parent)
+ case PortBinding(enclosure) =>
+ val childPort = enclosure != context_mod
+ childPort ^ flipped ^ currentlyFlipped
+ case _ => true
+ }
}
- val (newLeft, newRight) = if (flipped) pair.swap else pair
+ def canBeSink(data: Data): Boolean = traceFlow(true, data)
+ def canBeSource(data: Data): Boolean = traceFlow(false, data)
+ // chisel3 <> is commutative but FIRRTL <- is not
+ val flipConnection = !canBeSink(left_r) || !canBeSource(right_r)
+ val (newLeft, newRight) = if (flipConnection) pair.swap else pair
newLeft.bulkConnect(newRight)(sourceInfo, ExplicitCompileOptions.NotStrict)
} else {
recordConnect(sourceInfo, connectCompileOptions, left_r, right_r, context_mod)