diff options
Diffstat (limited to 'core/src')
| -rw-r--r-- | core/src/main/scala/chisel3/internal/BiConnect.scala | 27 |
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) |
