From 0ed5eb48cdb916b644aaf9e5dbf48f6cfb6c60f4 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Wed, 7 Sep 2016 14:18:29 -0700 Subject: Add Printable (#270) Printable is a new type that changes how printing of Chisel types is represented It uses an ordered collection rather than a format string and specifiers Features: - Custom String Interpolator for Scala-like printf - String-like manipulation of "hardware strings" for custom pretty-printing - Default pretty-printing for Chisel data types--- .../src/main/scala/chisel3/core/Printf.scala | 44 +++++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) (limited to 'chiselFrontend/src/main/scala/chisel3/core/Printf.scala') diff --git a/chiselFrontend/src/main/scala/chisel3/core/Printf.scala b/chiselFrontend/src/main/scala/chisel3/core/Printf.scala index b0a3c955..55197425 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Printf.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Printf.scala @@ -10,6 +10,24 @@ import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.SourceInfo object printf { // scalastyle:ignore object.name + /** Helper for packing escape characters */ + private[chisel3] def format(formatIn: String): String = { + require(formatIn forall (c => c.toInt > 0 && c.toInt < 128), + "format strings must comprise non-null ASCII values") + def escaped(x: Char) = { + require(x.toInt >= 0) + if (x == '"' || x == '\\') { + s"\\${x}" + } else if (x == '\n') { + "\\n" + } else { + require(x.toInt >= 32) // TODO \xNN once FIRRTL issue #59 is resolved + x + } + } + formatIn map escaped mkString "" + } + /** Prints a message in simulation. * * Does not fire when in reset (defined as the encapsulating Module's @@ -23,14 +41,30 @@ object printf { // scalastyle:ignore object.name * @param fmt printf format string * @param data format string varargs containing data to print */ - def apply(fmt: String, data: Bits*)(implicit sourceInfo: SourceInfo) { - when (!(Builder.dynamicContext.currentModule.get.reset)) { - printfWithoutReset(fmt, data:_*) + def apply(fmt: String, data: Bits*)(implicit sourceInfo: SourceInfo): Unit = + apply(Printable.pack(fmt, data:_*)) + /** Prints a message in simulation. + * + * Does not fire when in reset (defined as the encapsulating Module's + * reset). If your definition of reset is not the encapsulating Module's + * reset, you will need to gate this externally. + * + * May be called outside of a Module (like defined in a function), so + * functions using printf make the standard Module assumptions (single clock + * and single reset). + * + * @param pable [[Printable]] to print + */ + def apply(pable: Printable)(implicit sourceInfo: SourceInfo): Unit = { + when (!Builder.dynamicContext.currentModule.get.reset) { + printfWithoutReset(pable) } } - private[core] def printfWithoutReset(fmt: String, data: Bits*)(implicit sourceInfo: SourceInfo) { + private[chisel3] def printfWithoutReset(pable: Printable)(implicit sourceInfo: SourceInfo): Unit = { val clock = Builder.dynamicContext.currentModule.get.clock - pushCommand(Printf(sourceInfo, Node(clock), fmt, data.map((d: Bits) => d.ref))) + pushCommand(Printf(sourceInfo, Node(clock), pable)) } + private[chisel3] def printfWithoutReset(fmt: String, data: Bits*)(implicit sourceInfo: SourceInfo): Unit = + printfWithoutReset(Printable.pack(fmt, data:_*)) } -- cgit v1.2.3