diff --git a/core/src/main/scala/chisel3/probe/package.scala b/core/src/main/scala/chisel3/probe/package.scala index 1f23c886103..dc7c2f1443b 100644 --- a/core/src/main/scala/chisel3/probe/package.scala +++ b/core/src/main/scala/chisel3/probe/package.scala @@ -9,6 +9,7 @@ import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl.ir._ import chisel3.Data.ProbeInfo import chisel3.experimental.{requireIsHardware, SourceInfo} +import chisel3.experimental.dataview.reifyIdentityView import chisel3.reflect.DataMirror.{checkTypeEquivalence, collectAllMembers, hasProbeTypeModifier} import scala.language.experimental.macros @@ -34,7 +35,12 @@ package object probe extends SourceInfoDoc { * @param probeExpr value to initialize the sink to */ def define[T <: Data](sink: T, probeExpr: T)(implicit sourceInfo: SourceInfo): Unit = { - val typeCheckResult = sink.findFirstTypeMismatch( + val (realSink, writable) = reifyIdentityView(sink).getOrElse { + Builder.error(s"Define only supports identity views for the sink, $sink has multiple targets.") + return // This error is recoverable and this function returns Unit, just continue elaboration. + } + writable.reportIfReadOnlyUnit(()) + val typeCheckResult = realSink.findFirstTypeMismatch( probeExpr, strictTypes = true, strictWidths = true, @@ -43,22 +49,22 @@ package object probe extends SourceInfoDoc { typeCheckResult.foreach { msg => Builder.error(s"Cannot define a probe on a non-equivalent type.\n$msg") } - requireHasProbeTypeModifier(sink, "Expected sink to be a probe.") - requireNotChildOfProbe(sink, "Expected sink to be the root of a probe.") + requireHasProbeTypeModifier(realSink, "Expected sink to be a probe.") + requireNotChildOfProbe(realSink, "Expected sink to be the root of a probe.") requireHasProbeTypeModifier(probeExpr, "Expected source to be a probe expression.") requireCompatibleDestinationProbeColor( - sink, - s"""Cannot define '$sink' from colors ${(Builder.enabledLayers.view ++ Builder.layerStack.headOption) + realSink, + s"""Cannot define '$realSink' from colors ${(Builder.enabledLayers.view ++ Builder.layerStack.headOption) .map(a => s"'${a.fullName}'") - .mkString("{", ", ", "}")} since at least one of these is NOT enabled when '$sink' is enabled""" + .mkString("{", ", ", "}")} since at least one of these is NOT enabled when '$realSink' is enabled""" ) - if (sink.probeInfo.get.writable) { + if (realSink.probeInfo.get.writable) { requireHasWritableProbeTypeModifier( probeExpr, "Cannot use a non-writable probe expression to define a writable probe." ) } - pushCommand(ProbeDefine(sourceInfo, sink.lref, probeExpr.ref)) + pushCommand(ProbeDefine(sourceInfo, realSink.lref, probeExpr.ref)) } /** Access the value of a probe. diff --git a/src/test/scala/chiselTests/experimental/DataView.scala b/src/test/scala/chiselTests/experimental/DataView.scala index fb95555bcd8..987514da508 100644 --- a/src/test/scala/chiselTests/experimental/DataView.scala +++ b/src/test/scala/chiselTests/experimental/DataView.scala @@ -938,7 +938,24 @@ class DataViewSpec extends ChiselFlatSpec { chirrtl should include("define a = rwprobe(w)") } - it should "error if attempting to define a viewed a Probe as a RWProbe" in { + it should "support defining identity views of Probes" in { + class InnerBundle extends Bundle { + val a = Bool() + } + class OuterBundle extends Bundle { + val a = Probe(new InnerBundle) + } + class MyModule extends Module { + val p = Wire(new OuterBundle) + val view = p.viewAs[OuterBundle] + val w = Wire(new InnerBundle) + define(view.a, ProbeValue(w)) + } + val chirrtl = ChiselStage.emitCHIRRTL(new MyModule) + chirrtl should include("define p.a = probe(w)") + } + + it should "error if attempting to define a Probe viewed as a RWProbe" in { class MyModule extends Module { val a = IO(Output(RWProbe(Bool()))) val w = WireInit(Bool(), false.B)