Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Probes to .toString Data methods #4478

Merged
merged 5 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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