Skip to content

Commit

Permalink
Add Probes to .toString Data methods (#4478)
Browse files Browse the repository at this point in the history
* Add probe string to .toString Data methods

* Update chisel tests with new probe toString
  • Loading branch information
azidar authored Oct 18, 2024
1 parent 2d2428d commit 8c718b2
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 17 deletions.
14 changes: 12 additions & 2 deletions core/src/main/scala/chisel3/DataImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -470,21 +470,31 @@ private[chisel3] trait DataImpl extends HasId with NamedComponent { self: Data =
}
}

// Specializes the .toString method of a [[Data]] for conditions such as
// DataView, Probe modifiers, a DontCare, and whether it is bound or a pure chisel type
private[chisel3] def stringAccessor(chiselType: String): String = {
// Add probe and layer color (if they exist) to the returned String
val chiselTypeWithModifier =
probeInfo match {
case None => chiselType
case Some(ProbeInfo(writeable, layer)) =>
val layerString = layer.map(x => s"[${x.fullName}]").getOrElse("")
(if (writeable) "RWProbe" else "Probe") + s"$layerString<$chiselType>"
}
// Trace views to give better error messages
// Reifying involves checking against ViewParent which requires being in a Builder context
// Since we're just printing a String, suppress such errors and use this object
val thiz = Try(reifySingleTarget(this)).toOption.flatten.getOrElse(this)
thiz.topBindingOpt match {
case None => chiselType
case None => chiselTypeWithModifier
// Handle DontCares specially as they are "literal-like" but not actually literals
case Some(DontCareBinding()) => s"$chiselType(DontCare)"
case Some(topBinding) =>
val binding: String = thiz._bindingToString(topBinding)
val name = thiz.earlyName
val mod = thiz.parentNameOpt.map(_ + ".").getOrElse("")

s"$mod$name: $binding[$chiselType]"
s"$mod$name: $binding[$chiselTypeWithModifier]"
}
}

Expand Down
18 changes: 9 additions & 9 deletions src/test/scala/chisel3/TypeEquivalenceSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ class TypeEquivalenceSpec extends AnyFlatSpec {
it should "detect differences between Probe and Not-Probe" in {
Probe(Bool()).findFirstTypeMismatch(Bool(), true, true, true) should be(
Some(
": Left (Bool with probeInfo: Some(writeable=false, color=None)) and Right (Bool with probeInfo: None) have different probeInfo."
": Left (Probe<Bool> with probeInfo: Some(writeable=false, color=None)) and Right (Bool with probeInfo: None) have different probeInfo."
)
)
}
Expand All @@ -326,37 +326,37 @@ class TypeEquivalenceSpec extends AnyFlatSpec {
it should "detect differences between Probe and Not-Probe within a Bundle" in {
new BundleWithProbe(true).findFirstTypeMismatch(new BundleWithProbe(false), true, true, true) should be(
Some(
".maybeProbe: Left (Bool with probeInfo: Some(writeable=false, color=None)) and Right (Bool with probeInfo: None) have different probeInfo."
".maybeProbe: Left (Probe<Bool> with probeInfo: Some(writeable=false, color=None)) and Right (Bool with probeInfo: None) have different probeInfo."
)
)
}

it should "detect differences between probe types" in {
RWProbe(Bool()).findFirstTypeMismatch(Probe(Bool()), true, true, true) should be(
Some(
": Left (Bool with probeInfo: Some(writeable=true, color=None)) and Right (Bool with probeInfo: Some(writeable=false, color=None)) have different probeInfo."
": Left (RWProbe<Bool> with probeInfo: Some(writeable=true, color=None)) and Right (Probe<Bool> with probeInfo: Some(writeable=false, color=None)) have different probeInfo."
)
)
}

it should "detect differences through probes" in {
Probe(Bool()).findFirstTypeMismatch(Probe(Clock()), true, true, true) should be(
Some(": Left (Bool) and Right (Clock) have different types.")
Some(": Left (Probe<Bool>) and Right (Probe<Clock>) have different types.")
)
}

it should "detect differences in presence of probe colors" in {
Probe(Bool()).findFirstTypeMismatch(Probe(Bool(), Green), true, true, true) should be(
Some(
": Left (Bool with probeInfo: Some(writeable=false, color=None)) and Right (Bool with probeInfo: Some(writeable=false, color=Some(Green))) have different probeInfo."
": Left (Probe<Bool> with probeInfo: Some(writeable=false, color=None)) and Right (Probe[Green]<Bool> with probeInfo: Some(writeable=false, color=Some(Green))) have different probeInfo."
)
)
}

it should "detect differences in probe colors" in {
Probe(Bool(), Red).findFirstTypeMismatch(Probe(Bool(), Green), true, true, true) should be(
Some(
": Left (Bool with probeInfo: Some(writeable=false, color=Some(Red))) and Right (Bool with probeInfo: Some(writeable=false, color=Some(Green))) have different probeInfo."
": Left (Probe[Red]<Bool> with probeInfo: Some(writeable=false, color=Some(Red))) and Right (Probe[Green]<Bool> with probeInfo: Some(writeable=false, color=Some(Green))) have different probeInfo."
)
)
}
Expand All @@ -375,23 +375,23 @@ class TypeEquivalenceSpec extends AnyFlatSpec {
true
) should be(
Some(
".probe: Left (Bool with probeInfo: Some(writeable=false, color=Some(Red))) and Right (Bool with probeInfo: Some(writeable=false, color=Some(Green))) have different probeInfo."
".probe: Left (Probe[Red]<Bool> with probeInfo: Some(writeable=false, color=Some(Red))) and Right (Probe[Green]<Bool> with probeInfo: Some(writeable=false, color=Some(Green))) have different probeInfo."
)
)
}

it should "detect differences in probe color presence within a Bundle" in {
new BundleWithAColor(Some(Red)).findFirstTypeMismatch(new BundleWithAColor(None), true, true, true) should be(
Some(
".probe: Left (Bool with probeInfo: Some(writeable=false, color=Some(Red))) and Right (Bool with probeInfo: Some(writeable=false, color=None)) have different probeInfo."
".probe: Left (Probe[Red]<Bool> with probeInfo: Some(writeable=false, color=Some(Red))) and Right (Probe<Bool> with probeInfo: Some(writeable=false, color=None)) have different probeInfo."
)
)
}

it should "detect differences in probe within a Vector" in {
Vec(3, Probe(Bool())).findFirstTypeMismatch(Vec(3, Bool()), true, true, true) should be(
Some(
"[_]: Left (Bool with probeInfo: Some(writeable=false, color=None)) and Right (Bool with probeInfo: None) have different probeInfo."
"[_]: Left (Probe<Bool> with probeInfo: Some(writeable=false, color=None)) and Right (Bool with probeInfo: None) have different probeInfo."
)
)
}
Expand Down
11 changes: 11 additions & 0 deletions src/test/scala/chiselTests/DataPrint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,26 @@ class DataPrintSpec extends ChiselFlatSpec with Matchers {
val f = EnumTest.Type()
}

object A extends layer.Layer(layer.LayerConfig.Extract()) {
object B extends layer.Layer(layer.LayerConfig.Extract())
}

"Data types" should "have a meaningful string representation" in {
ChiselStage.emitCHIRRTL {
new RawModule {
UInt().toString should be("UInt")
UInt(8.W).toString should be("UInt<8>")
probe.Probe(UInt(8.W)).toString should be("Probe<UInt<8>>")
probe.RWProbe(UInt(8.W)).toString should be("RWProbe<UInt<8>>")
probe.Probe(UInt(8.W), A).toString should be("Probe[A]<UInt<8>>")
probe.Probe(UInt(8.W), A.B).toString should be("Probe[A.B]<UInt<8>>")
SInt(15.W).toString should be("SInt<15>")
Bool().toString should be("Bool")
Clock().toString should be("Clock")
Vec(3, UInt(2.W)).toString should be("UInt<2>[3]")
EnumTest.Type().toString should be("EnumTest")
(new BundleTest).toString should be("BundleTest")
(probe.Probe(new BundleTest)).toString should be("Probe<BundleTest>")
new Bundle { val a = UInt(8.W) }.toString should be("AnonymousBundle")
new Bundle { val a = UInt(8.W) }.a.toString should be("UInt<8>")
}
Expand All @@ -45,6 +54,8 @@ class DataPrintSpec extends ChiselFlatSpec with Matchers {

class BoundDataModule extends Module { // not in the test to avoid anon naming suffixes
Wire(UInt()).toString should be("BoundDataModule.?: Wire[UInt]")
Wire(probe.Probe(UInt(1.W))).toString should be("BoundDataModule.?: Wire[Probe<UInt<1>>]")
Wire(probe.Probe(UInt(1.W), A)).toString should be("BoundDataModule.?: Wire[Probe[A]<UInt<1>>]")
Reg(SInt()).toString should be("BoundDataModule.?: Reg[SInt]")
val io = IO(Output(Bool())) // needs a name so elaboration doesn't fail
io.toString should be("BoundDataModule.io: IO[Bool]")
Expand Down
4 changes: 2 additions & 2 deletions src/test/scala/chiselTests/LayerSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ class LayerSpec extends ChiselFlatSpec with Utils with MatchesAndOmits {
}
intercept[ChiselException] { ChiselStage.emitCHIRRTL(new Foo, Array("--throw-on-first-error")) }
.getMessage() should include(
"Cannot define 'Foo.a: IO[Bool]' from colors {'C'} since at least one of these is NOT enabled when 'Foo.a: IO[Bool]' is enabled"
"Cannot define 'Foo.a: IO[Probe[A]<Bool>]' from colors {'C'} since at least one of these is NOT enabled when 'Foo.a: IO[Probe[A]<Bool>]' is enabled"
)
}

Expand All @@ -358,7 +358,7 @@ class LayerSpec extends ChiselFlatSpec with Utils with MatchesAndOmits {

intercept[ChiselException] { ChiselStage.convert(new Foo, Array("--throw-on-first-error")) }
.getMessage() should include(
"Cannot define 'Foo.a: IO[Bool]' from colors {'C'} since at least one of these is NOT enabled when 'Foo.a: IO[Bool]' is enabled"
"Cannot define 'Foo.a: IO[Probe[A]<Bool>]' from colors {'C'} since at least one of these is NOT enabled when 'Foo.a: IO[Probe[A]<Bool>]' is enabled"
)
}

Expand Down
8 changes: 4 additions & 4 deletions src/test/scala/chiselTests/ProbeSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ class ProbeSpec extends ChiselFlatSpec with MatchesAndOmits with Utils {
)
}
exc.getMessage should include(
"mismatched probe/non-probe types in ProbeSpec_Anon.io.out[0]: IO[Bool] and ProbeSpec_Anon.io.in[0]: IO[Bool]."
"mismatched probe/non-probe types in ProbeSpec_Anon.io.out[0]: IO[Probe<Bool>] and ProbeSpec_Anon.io.in[0]: IO[Bool]."
)
}

Expand All @@ -260,7 +260,7 @@ class ProbeSpec extends ChiselFlatSpec with MatchesAndOmits with Utils {
)
}
exc.getMessage should include(
"Connection between sink (ProbeSpec_Anon.io.out: IO[Bool]) and source (ProbeSpec_Anon.io.in: IO[Bool]) failed @: Sink io.out in ProbeSpec_Anon of Probed type cannot participate in a mono connection (:=)"
"Connection between sink (ProbeSpec_Anon.io.out: IO[Probe<Bool>]) and source (ProbeSpec_Anon.io.in: IO[Bool]) failed @: Sink io.out in ProbeSpec_Anon of Probed type cannot participate in a mono connection (:=)"
)
}

Expand Down Expand Up @@ -295,7 +295,7 @@ class ProbeSpec extends ChiselFlatSpec with MatchesAndOmits with Utils {
)
}
exc.getMessage should include(
"Connection between sink (OutProbe.p: IO[Bool]) and source (ProbeSpec_Anon.out: IO[Bool]) failed @: p in OutProbe cannot be written from module ProbeSpec_Anon."
"Connection between sink (OutProbe.p: IO[Probe<Bool>]) and source (ProbeSpec_Anon.out: IO[Probe<Bool>]) failed @: p in OutProbe cannot be written from module ProbeSpec_Anon."
)
}

Expand Down Expand Up @@ -383,7 +383,7 @@ class ProbeSpec extends ChiselFlatSpec with MatchesAndOmits with Utils {
}
exc.getMessage should include("Cannot define a probe on a non-equivalent type.")
exc.getMessage should include(
"Left (ProbeSpec_Anon.p: IO[UInt<4>]) and Right (ProbeSpec_Anon.w: OpResult[Bool]) have different types"
"Left (ProbeSpec_Anon.p: IO[Probe<UInt<4>>]) and Right (ProbeSpec_Anon.w: OpResult[Probe<Bool>]) have different types"
)

}
Expand Down

0 comments on commit 8c718b2

Please sign in to comment.