From 5a79814631bdc8c71c5a7b4722cd43712f7ff445 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Thu, 29 Sep 2022 18:53:44 +0000 Subject: Add lexical scope checks to Assert, Assume and Printf (#2706) (#2753) (cherry picked from commit f462c9f9307bebf3012da52432c3729cd752321c) Co-authored-by: Aditya Naik <91489422+adkian-sifive@users.noreply.github.com>--- core/src/main/scala/chisel3/Data.scala | 2 +- core/src/main/scala/chisel3/Printable.scala | 13 ++++ core/src/main/scala/chisel3/Printf.scala | 3 + .../main/scala/chisel3/VerificationStatement.scala | 2 + src/test/scala/chiselTests/Assert.scala | 77 ++++++++++++++++++++++ src/test/scala/chiselTests/Printf.scala | 39 +++++++++++ 6 files changed, 135 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/chisel3/Data.scala b/core/src/main/scala/chisel3/Data.scala index 7c8ec1a9..f52f99de 100644 --- a/core/src/main/scala/chisel3/Data.scala +++ b/core/src/main/scala/chisel3/Data.scala @@ -662,7 +662,7 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc { */ private[chisel3] def typeEquivalent(that: Data): Boolean - private def requireVisible(): Unit = { + private[chisel3] def requireVisible(): Unit = { val mod = topBindingOpt.flatMap(_.location) topBindingOpt match { case Some(tb: TopBinding) if (mod == Builder.currentModule) => diff --git a/core/src/main/scala/chisel3/Printable.scala b/core/src/main/scala/chisel3/Printable.scala index 78655517..82054ee1 100644 --- a/core/src/main/scala/chisel3/Printable.scala +++ b/core/src/main/scala/chisel3/Printable.scala @@ -134,6 +134,19 @@ object Printable { val bufEscapeBackSlash = buf.map(_.replace("\\", "\\\\")) StringContext(bufEscapeBackSlash.toSeq: _*).cf(data: _*) } + + private[chisel3] def checkScope(message: Printable): Unit = { + def getData(x: Printable): Seq[Data] = { + x match { + case y: FirrtlFormat => Seq(y.bits) + case Name(d) => Seq(d) + case FullName(d) => Seq(d) + case Printables(p) => p.flatMap(getData(_)).toSeq + case _ => Seq() // Handles subtypes PString and Percent + } + } + getData(message).foreach(_.requireVisible()) + } } case class Printables(pables: Iterable[Printable]) extends Printable { diff --git a/core/src/main/scala/chisel3/Printf.scala b/core/src/main/scala/chisel3/Printf.scala index bdcca8e1..9410a409 100644 --- a/core/src/main/scala/chisel3/Printf.scala +++ b/core/src/main/scala/chisel3/Printf.scala @@ -108,6 +108,9 @@ object printf { ): Printf = { val clock = Builder.forcedClock val printfId = new Printf(pable) + + Printable.checkScope(pable) + pushCommand(chisel3.internal.firrtl.Printf(printfId, sourceInfo, clock.ref, pable)) printfId } diff --git a/core/src/main/scala/chisel3/VerificationStatement.scala b/core/src/main/scala/chisel3/VerificationStatement.scala index 1b13b86c..10cece60 100644 --- a/core/src/main/scala/chisel3/VerificationStatement.scala +++ b/core/src/main/scala/chisel3/VerificationStatement.scala @@ -178,6 +178,7 @@ object assert extends VerifPrintMacrosDoc { compileOptions: CompileOptions ): Assert = { val id = new Assert() + message.foreach(Printable.checkScope(_)) when(!Module.reset.asBool()) { failureMessage("Assertion", line, cond, message) Builder.pushCommand(Verification(id, Formal.Assert, sourceInfo, Module.clock.ref, cond.ref, "")) @@ -343,6 +344,7 @@ object assume extends VerifPrintMacrosDoc { compileOptions: CompileOptions ): Assume = { val id = new Assume() + message.foreach(Printable.checkScope(_)) when(!Module.reset.asBool()) { failureMessage("Assumption", line, cond, message) Builder.pushCommand(Verification(id, Formal.Assume, sourceInfo, Module.clock.ref, cond.ref, "")) diff --git a/src/test/scala/chiselTests/Assert.scala b/src/test/scala/chiselTests/Assert.scala index d7885a3b..5e7b6496 100644 --- a/src/test/scala/chiselTests/Assert.scala +++ b/src/test/scala/chiselTests/Assert.scala @@ -84,6 +84,64 @@ class PrintableAssumeTester extends Module { out := in } +class PrintableScopeTester extends Module { + val in = IO(Input(UInt(8.W))) + val out = IO(Output(UInt(8.W))) + out := in + + val w = Wire(UInt(8.W)) + w := 255.U + + val printableWire = cf"$w" + val printablePort = cf"$in" +} + +class AssertPrintableWireScope extends BasicTester { + val mod = Module(new PrintableScopeTester) + assert(1.U === 2.U, mod.printableWire) + stop() +} + +class AssertPrintablePortScope extends BasicTester { + val mod = Module(new PrintableScopeTester) + mod.in := 255.U + assert(1.U === 1.U, mod.printablePort) + stop() +} + +class AssertPrintableFailingWhenScope extends BasicTester { + val mod = Module(new PrintableWhenScopeTester) + assert(1.U === 1.U, mod.printable) + stop() +} + +class AssumePrintableWireScope extends BasicTester { + val mod = Module(new PrintableScopeTester) + assume(1.U === 1.U, mod.printableWire) + stop() +} + +class AssumePrintablePortScope extends BasicTester { + val mod = Module(new PrintableScopeTester) + mod.in := 255.U + assume(1.U === 1.U, mod.printablePort) + stop() +} + +class PrintableWhenScopeTester extends Module { + val in = IO(Input(UInt(8.W))) + val out = IO(Output(UInt(8.W))) + + out := in + + val w = Wire(UInt(8.W)) + w := 255.U + var printable = cf"" + when(true.B) { + printable = cf"$w" + } +} + class AssertSpec extends ChiselFlatSpec with Utils { "A failing assertion" should "fail the testbench" in { assert(!runTester { new FailingAssertTester }) @@ -94,6 +152,25 @@ class AssertSpec extends ChiselFlatSpec with Utils { "An assertion" should "not assert until we come out of reset" in { assertTesterPasses { new PipelinedResetTester } } + + "Assert Printables" should "respect port scoping" in { + assertTesterPasses { new AssertPrintablePortScope } + } + "Assert Printables" should "respect wire scoping" in { + a[ChiselException] should be thrownBy { ChiselStage.elaborate(new AssertPrintableWireScope) } + } + "Assume Printables" should "respect port scoping" in { + assertTesterPasses { new AssumePrintablePortScope } + } + + "Assume Printables" should "respect wire scoping" in { + a[ChiselException] should be thrownBy { ChiselStage.elaborate(new AssumePrintableWireScope) } + } + + "Assert Printables" should "respect when scope" in { + a[ChiselException] should be thrownBy { ChiselStage.elaborate(new AssertPrintableFailingWhenScope) } + } + "Assertions" should "allow the modulo operator % in the message" in { assertTesterPasses { new ModuloAssertTester } } diff --git a/src/test/scala/chiselTests/Printf.scala b/src/test/scala/chiselTests/Printf.scala index 4171f97f..6c9f05f0 100644 --- a/src/test/scala/chiselTests/Printf.scala +++ b/src/test/scala/chiselTests/Printf.scala @@ -4,6 +4,7 @@ package chiselTests import chisel3._ import chisel3.testers.BasicTester +import chisel3.stage.ChiselStage class SinglePrintfTester() extends BasicTester { val x = 254.U @@ -28,6 +29,38 @@ class ASCIIPrintableTester extends BasicTester { stop() } +class ScopeTesterModule extends Module { + val in = IO(Input(UInt(8.W))) + val out = IO(Output(UInt(8.W))) + out := in + + val w = Wire(UInt(8.W)) + w := 125.U + + val p = cf"$in" + val wp = cf"$w" +} + +class PrintablePrintfScopeTester extends BasicTester { + ChiselStage.elaborate { + new Module { + val mod = Module(new ScopeTesterModule) + printf(mod.p) + } + } + stop() +} + +class PrintablePrintfWireScopeTester extends BasicTester { + ChiselStage.elaborate { + new Module { + val mod = Module(new ScopeTesterModule) + printf(mod.wp) + } + } + stop() +} + class PrintfSpec extends ChiselFlatSpec { "A printf with a single argument" should "run" in { assertTesterPasses { new SinglePrintfTester } @@ -41,4 +74,10 @@ class PrintfSpec extends ChiselFlatSpec { "A printf with Printable ASCII characters 1-127" should "run" in { assertTesterPasses { new ASCIIPrintableTester } } + "A printf with Printable" should "respect port scopes" in { + assertTesterPasses { new PrintablePrintfScopeTester } + } + "A printf with Printable" should "respect wire scopes" in { + a[ChiselException] should be thrownBy { assertTesterPasses { new PrintablePrintfWireScopeTester } } + } } -- cgit v1.2.3