Skip to content

Commit

Permalink
Support checking isVisible with reflect.DataMirror (chipsalliance#3753)
Browse files Browse the repository at this point in the history
Users are now able to check whether a Data is visible from the
current context via `chisel.reflect.DataMirror.isVisible`.
  • Loading branch information
poemonsense authored and SpriteOvO committed Jan 20, 2024
1 parent fbc7a27 commit 53ad929
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 8 deletions.
23 changes: 15 additions & 8 deletions core/src/main/scala/chisel3/Data.scala
Original file line number Diff line number Diff line change
Expand Up @@ -582,18 +582,25 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc {
rec(leftType, rightType)
}

private[chisel3] def requireVisible(): Unit = {
private[chisel3] def isVisible: Boolean = isVisibleFromModule && isVisibleFromWhen
private[chisel3] def isVisibleFromModule: Boolean = {
val mod = topBindingOpt.flatMap(_.location)
topBindingOpt match {
case Some(tb: TopBinding) if (mod == Builder.currentModule) =>
case Some(tb: TopBinding) if (mod == Builder.currentModule) => true
case Some(pb: PortBinding)
if (mod.flatMap(Builder.retrieveParent(_, Builder.currentModule.get)) == Builder.currentModule) =>
case Some(pb: SecretPortBinding) => // Ignore secret to not require visibility
case Some(_: UnconstrainedBinding) =>
case _ =>
throwException(s"operand '$this' is not visible from the current module ${Builder.currentModule.get.name}")
if mod.flatMap(Builder.retrieveParent(_, Builder.currentModule.get)) == Builder.currentModule =>
true
case Some(pb: SecretPortBinding) => true // Ignore secret to not require visibility
case Some(_: UnconstrainedBinding) => true
case _ => false
}
}
private[chisel3] def isVisibleFromWhen: Boolean = MonoConnect.checkWhenVisibility(this)
private[chisel3] def requireVisible(): Unit = {
if (!isVisibleFromModule) {
throwException(s"operand '$this' is not visible from the current module ${Builder.currentModule.get.name}")
}
if (!MonoConnect.checkWhenVisibility(this)) {
if (!isVisibleFromWhen) {
throwException(s"operand has escaped the scope of the when in which it was constructed")
}
}
Expand Down
6 changes: 6 additions & 0 deletions core/src/main/scala/chisel3/reflect/DataMirror.scala
Original file line number Diff line number Diff line change
Expand Up @@ -475,4 +475,10 @@ object DataMirror {
(modulePath(left, Some(lca)) ++ Seq(lca), modulePath(right, Some(lca)) ++ Seq(lca))
}
}

/** Check if a given `Data` is visible from the current context
* @param x the `Data` to check
* @return `true` if x is visible, `false` otherwise
*/
def isVisible(target: Data): Boolean = target.isVisible
}
11 changes: 11 additions & 0 deletions src/test/scala/chiselTests/reflect/DataMirrorSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,28 @@ import chisel3.util.DecoupledIO
object DataMirrorSpec {
import org.scalatest.matchers.should.Matchers._
class GrandChild(parent: RawModule) extends Module {
val internal = WireInit(false.B)
DataMirror.getParent(this) should be(Some(parent))
DataMirror.isVisible(internal) should be(true)
}
class Child(parent: RawModule) extends Module {
val inst = Module(new GrandChild(this))
val io = IO(Input(Bool()))
val internal = WireInit(false.B)
DataMirror.getParent(inst) should be(Some(this))
DataMirror.getParent(this) should be(Some(parent))
DataMirror.isVisible(io) should be(true)
DataMirror.isVisible(internal) should be(true)
DataMirror.isVisible(inst.internal) should be(false)
}
class Parent extends Module {
val inst = Module(new Child(this))
inst.io := false.B
DataMirror.getParent(inst) should be(Some(this))
DataMirror.getParent(this) should be(None)
DataMirror.isVisible(inst.io) should be(true)
DataMirror.isVisible(inst.internal) should be(false)
DataMirror.isVisible(inst.inst.internal) should be(false)
}
}

Expand Down

0 comments on commit 53ad929

Please sign in to comment.