Skip to content

Commit 136294d

Browse files
authored
Add SimulationTime (%T) format specifier (#4875)
1 parent 2bb07da commit 136294d

File tree

5 files changed

+38
-13
lines changed

5 files changed

+38
-13
lines changed

core/src/main/scala/chisel3/Printable.scala

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ sealed abstract class Printable {
7272

7373
object Printable {
7474

75-
private[chisel3] def isNoArgSpecifier(c: Char): Boolean = c == '%' || c == 'm'
75+
private[chisel3] def isNoArgSpecifier(c: Char): Boolean = c == '%' || c == 'm' || c == 'T'
7676

7777
/** Pack standard printf fmt, args* style into Printable
7878
*/
@@ -102,7 +102,7 @@ object Printable {
102102
while (iter < fmt.size) {
103103
// Encountered % which is either
104104
// 1. Describing a format specifier.
105-
// 2. %% or %m
105+
// 2. %%, %m, or %T
106106
// 3. Dangling percent - most likely due to a typo - intended literal percent or forgot the specifier.
107107
// Try to give meaningful error reports
108108
if (fmt(iter) == '%') {
@@ -193,10 +193,10 @@ object Printable {
193193
/** Resolve Printables that are resolved at Chisel-time */
194194
private[chisel3] def resolve(pable: Printable, ctx: Component)(implicit info: SourceInfo): Printable =
195195
pable.map {
196-
case Name(data) => PString(data.ref.name)
197-
case FullName(data) => PString(data.ref.fullName(ctx))
198-
case HierarchicalModuleName => PString("{{HierarchicalModuleName}}")
199-
case other => other
196+
case Name(data) => PString(data.ref.name)
197+
case FullName(data) => PString(data.ref.fullName(ctx))
198+
case s: SpecialFirrtlSubstitution => PString(s.substitutionString)
199+
case other => other
200200
}
201201
}
202202

@@ -377,11 +377,28 @@ case object Percent extends Printable {
377377
final def unpack: (String, Seq[Data]) = ("%%", List.empty)
378378
}
379379

380+
/** Printable with special representation in FIRRTL
381+
*
382+
* @note The name of the singleton object exactly matches the FIRRTL value.
383+
*/
384+
sealed trait SpecialFirrtlSubstitution { self: Singleton with Printable =>
385+
private[chisel3] final def substitutionString: String = "{{" + this.getClass.getSimpleName.dropRight(1) + "}}"
386+
}
387+
380388
/** Represents the hierarchical name in the Verilog (`%m`) */
381-
case object HierarchicalModuleName extends Printable {
389+
case object HierarchicalModuleName extends Printable with SpecialFirrtlSubstitution {
382390
@deprecated("Use unpack with no arguments instead.", "Chisel 7.0.0")
383391
final def unpack(ctx: Component)(implicit info: SourceInfo): (String, Iterable[String]) = ("%m", List.empty)
384392
@deprecated("Use unpack with no arguments instead.", "Chisel 7.0.0")
385393
final def unpackArgs: Seq[Bits] = List.empty
386394
final def unpack: (String, Seq[Data]) = ("%m", List.empty)
387395
}
396+
397+
/** Represents the simulation time in the Verilog, similar to `%t` + `$time` */
398+
case object SimulationTime extends Printable with SpecialFirrtlSubstitution {
399+
@deprecated("Use unpack with no arguments instead.", "Chisel 7.0.0")
400+
final def unpack(ctx: Component)(implicit info: SourceInfo): (String, Iterable[String]) = ("%T", List.empty)
401+
@deprecated("Use unpack with no arguments instead.", "Chisel 7.0.0")
402+
final def unpackArgs: Seq[Bits] = List.empty
403+
final def unpack: (String, Seq[Data]) = ("%T", List.empty)
404+
}

core/src/main/scala/chisel3/package.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@ package object chisel3 {
248248
Percent
249249
} else if (s(end + 1) == 'm') {
250250
HierarchicalModuleName
251+
} else if (s(end + 1) == 'T') {
252+
SimulationTime
251253
} else {
252254
throw new UnknownFormatConversionException("Un-escaped %")
253255
}

docs/src/explanations/printing.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,16 @@ printf(cf"myUInt = $myUInt%c") // myUInt = !
6262
There are special values you can include in your `cf` interpolated string:
6363

6464
* `HierarchicalModuleName` (`%m`): The hierarchical name of the current module
65+
* `SimulationTime` (`%T`): The current simulation time (unlike Verilog's `%t`, this does not take an argument)
6566
* `Percent` (`%%`): A literal `%`
6667

6768
```scala mdoc:compile-only
6869
printf(cf"hierarchical path = $HierarchicalModuleName\n") // hierarchical path = <verilog.module.path>
6970
printf(cf"hierarchical path = %m\n") // equivalent to the above
7071

72+
printf(cf"simulation time = $SimulationTime\n") // simulation time = <simulation.time>
73+
printf(cf"simulation time = %T\n") // equivalent to the above
74+
7175
printf(cf"100$Percent\n") // 100%
7276
printf(cf"100%%\n") // equivalent to the above
7377
```
@@ -167,6 +171,7 @@ Chisel provides `printf` in a similar style to its C namesake. It accepts a doub
167171
| `%c` | 8-bit ASCII character |
168172
| `%%` | literal percent |
169173
| `%m` | hierarchical name |
174+
| `%T` | simulation time |
170175

171176
`%d`, `%x`, and `%b` support the modifiers described in the [Format modifiers](#format-modifiers) section above.
172177

src/test/scala-2/chiselTests/PrintableSpec.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -318,18 +318,18 @@ class PrintableSpec extends AnyFlatSpec with Matchers with FileCheck {
318318
it should "support all legal format specifiers" in {
319319
class MyModule extends Module {
320320
val in = IO(Input(UInt(8.W)))
321-
printf(cf"$HierarchicalModuleName $in%d $in%x $in%b $in%c %%\n")
321+
printf(cf"$SimulationTime $HierarchicalModuleName $in%d $in%x $in%b $in%c %%\n")
322322
}
323323
ChiselStage
324324
.emitCHIRRTL(new MyModule)
325325
.fileCheck()(
326-
"""CHECK{LITERAL}: printf(clock, UInt<1>(0h1), "{{HierarchicalModuleName}} %d %x %b %c %%\n", in, in, in, in)"""
326+
"""CHECK{LITERAL}: printf(clock, UInt<1>(0h1), "{{SimulationTime}} {{HierarchicalModuleName}} %d %x %b %c %%\n", in, in, in, in)"""
327327
)
328328
// Also check Verilog
329329
ChiselStage
330330
.emitSystemVerilog(new MyModule)
331331
.fileCheck()(
332-
"""CHECK: $fwrite(`PRINTF_FD_, "%m %d %x %b %c %%\n", in, in, in, in);"""
332+
"""CHECK: $fwrite(`PRINTF_FD_, "%0t %m %d %x %b %c %%\n", $time, in, in, in, in);"""
333333
)
334334

335335
}
@@ -391,6 +391,7 @@ class PrintableSpec extends AnyFlatSpec with Matchers with FileCheck {
391391
(PString("foo"), ("foo", Seq())),
392392
(Percent, ("%%", Seq())),
393393
(HierarchicalModuleName, ("%m", Seq())),
394+
(SimulationTime, ("%T", Seq())),
394395
(Name(x), ("%n", Seq(x))),
395396
(FullName(x), ("%N", Seq(x)))
396397
)

src/test/scala-2/chiselTests/Printf.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,18 +76,18 @@ class PrintfSpec extends AnyFlatSpec with Matchers with FileCheck {
7676
"printf" should "support all legal format specifiers" in {
7777
class MyModule extends Module {
7878
val in = IO(Input(UInt(8.W)))
79-
printf("%m %d %x %b %c %%\n", in, in, in, in)
79+
printf("%T %m %d %x %b %c %%\n", in, in, in, in)
8080
}
8181
ChiselStage
8282
.emitCHIRRTL(new MyModule)
8383
.fileCheck()(
84-
"""CHECK{LITERAL}: printf(clock, UInt<1>(0h1), "{{HierarchicalModuleName}} %d %x %b %c %%\n", in, in, in, in)"""
84+
"""CHECK{LITERAL}: printf(clock, UInt<1>(0h1), "{{SimulationTime}} {{HierarchicalModuleName}} %d %x %b %c %%\n", in, in, in, in)"""
8585
)
8686
// Also check Verilog
8787
ChiselStage
8888
.emitSystemVerilog(new MyModule)
8989
.fileCheck()(
90-
"""CHECK: $fwrite(`PRINTF_FD_, "%m %d %x %b %c %%\n", in, in, in, in);"""
90+
"""CHECK: $fwrite(`PRINTF_FD_, "%0t %m %d %x %b %c %%\n", $time, in, in, in, in);"""
9191
)
9292
}
9393

0 commit comments

Comments
 (0)