diff options
| -rw-r--r-- | chiselFrontend/src/main/scala/chisel3/core/Assert.scala | 11 | ||||
| -rw-r--r-- | src/test/scala/chiselTests/Assert.scala | 21 |
2 files changed, 27 insertions, 5 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Assert.scala b/chiselFrontend/src/main/scala/chisel3/core/Assert.scala index 7f67f244..43a74192 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Assert.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Assert.scala @@ -23,9 +23,10 @@ object assert { // scalastyle:ignore object.name * and single reset). * * @param cond condition, assertion fires (simulation fails) when false - * @param message optional message to print when the assertion fires + * @param message optional format string to print when the assertion fires * @param data optional bits to print in the message formatting * + * @note See [[printf.apply(fmt:String* printf]] for format string documentation * @note currently cannot be used in core Chisel / libraries because macro * defs need to be compiled first and the SBT project is not set up to do * that @@ -51,12 +52,14 @@ object assert { // scalastyle:ignore object.name } def apply_impl_do(cond: Bool, line: String, message: Option[String], data: Bits*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) { + val escLine = line.replaceAll("%", "%%") when (!(cond || Module.reset.toBool)) { val fmt = message match { - case Some(str) => s"Assertion failed: $str\n at $line\n" - case None => s"Assertion failed\n at $line\n" + case Some(msg) => + s"Assertion failed: $msg\n at $escLine\n" + case None => s"Assertion failed\n at $escLine\n" } - printf.printfWithoutReset(fmt.replaceAll("%", "%%"), data:_*) + printf.printfWithoutReset(fmt, data:_*) pushCommand(Stop(sourceInfo, Node(Builder.forcedClock), 1)) } } diff --git a/src/test/scala/chiselTests/Assert.scala b/src/test/scala/chiselTests/Assert.scala index 994a16fd..075cc4e2 100644 --- a/src/test/scala/chiselTests/Assert.scala +++ b/src/test/scala/chiselTests/Assert.scala @@ -46,7 +46,18 @@ class PipelinedResetTester extends BasicTester { class ModuloAssertTester extends BasicTester { assert((4.U % 2.U) === 0.U) - assert(1.U === 1.U, "I'm 110% sure this will succeed") + stop() +} + +class FormattedAssertTester extends BasicTester { + val foobar = Wire(UInt(32.W)) + foobar := 123.U + assert(foobar === 123.U, "Error! Wire foobar =/= %x! This is 100%% wrong.\n", foobar) + stop() +} + +class BadUnescapedPercentAssertTester extends BasicTester { + assert(1.U === 1.U, "I'm 110% sure this is an invalid message") stop() } @@ -63,4 +74,12 @@ class AssertSpec extends ChiselFlatSpec { "Assertions" should "allow the modulo operator % in the message" in { assertTesterPasses{ new ModuloAssertTester } } + they should "allow printf-style format strings with arguments" in { + assertTesterPasses{ new FormattedAssertTester } + } + they should "not allow unescaped % in the message" in { + a [java.util.UnknownFormatConversionException] should be thrownBy { + elaborate { new BadUnescapedPercentAssertTester } + } + } } |
