Skip to content

Commit

Permalink
Make printf return BaseSim subclass so it can be named/annotated (chi…
Browse files Browse the repository at this point in the history
  • Loading branch information
debs-sifive authored Jul 6, 2021
1 parent 4b7499f commit 503ae52
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 27 deletions.
22 changes: 14 additions & 8 deletions core/src/main/scala/chisel3/Printf.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
package chisel3

import scala.language.experimental.macros

import chisel3.internal._
import chisel3.internal.Builder.pushCommand
import chisel3.internal.firrtl._
import chisel3.internal.sourceinfo.SourceInfo
import chisel3.experimental.BaseSim

/** Prints a message in simulation
*
Expand All @@ -34,6 +33,9 @@ object printf {
formatIn map escaped mkString ""
}

/** Named class for [[printf]]s. */
final class Printf(val pable: Printable) extends BaseSim

/** Prints a message in simulation
*
* Prints a message every cycle. If defined within the scope of a [[when]] block, the message
Expand Down Expand Up @@ -71,7 +73,7 @@ object printf {
* @param fmt printf format string
* @param data format string varargs containing data to print
*/
def apply(fmt: String, data: Bits*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit =
def apply(fmt: String, data: Bits*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Printf =
apply(Printable.pack(fmt, data:_*))
/** Prints a message in simulation
*
Expand All @@ -87,16 +89,20 @@ object printf {
* @see [[Printable]] documentation
* @param pable [[Printable]] to print
*/
def apply(pable: Printable)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit = {
def apply(pable: Printable)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Printf = {
var printfId: Printf = null
when (!Module.reset.asBool) {
printfWithoutReset(pable)
printfId = printfWithoutReset(pable)
}
printfId
}

private[chisel3] def printfWithoutReset(pable: Printable)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit = {
private[chisel3] def printfWithoutReset(pable: Printable)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Printf = {
val clock = Builder.forcedClock
pushCommand(Printf(sourceInfo, clock.ref, pable))
val printfId = new Printf(pable)
pushCommand(chisel3.internal.firrtl.Printf(printfId, sourceInfo, clock.ref, pable))
printfId
}
private[chisel3] def printfWithoutReset(fmt: String, data: Bits*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit =
private[chisel3] def printfWithoutReset(fmt: String, data: Bits*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Printf =
printfWithoutReset(Printable.pack(fmt, data:_*))
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,11 @@ import chisel3.internal.sourceinfo.SourceInfo

package object verification {

/** Named class for assertions. */
final class Assert(val predicate: Bool) extends BaseSim

/** Named class for assumes. */
final class Assume(val predicate: Bool) extends BaseSim
object assert {
/** Named class for assertions. */
final class Assert(private[chisel3] val predicate: Bool) extends BaseSim

/** Named class for covers. */
final class Cover(val predicate: Bool) extends BaseSim

object assert {
def apply(predicate: Bool, msg: String = "")(
implicit sourceInfo: SourceInfo,
compileOptions: CompileOptions): Assert = {
Expand All @@ -32,6 +27,9 @@ package object verification {
}

object assume {
/** Named class for assumes. */
final class Assume(private[chisel3] val predicate: Bool) extends BaseSim

def apply(predicate: Bool, msg: String = "")(
implicit sourceInfo: SourceInfo,
compileOptions: CompileOptions): Assume = {
Expand All @@ -45,6 +43,9 @@ package object verification {
}

object cover {
/** Named class for covers. */
final class Cover(private[chisel3] val predicate: Bool) extends BaseSim

def apply(predicate: Bool, msg: String = "")(
implicit sourceInfo: SourceInfo,
compileOptions: CompileOptions): Cover = {
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/chisel3/internal/firrtl/Converter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,10 @@ private[chisel3] object Converter {
Some(fir.DefInstance(convert(info), e.name, id.name))
case Stop(info, clock, ret) =>
Some(fir.Stop(convert(info), ret, convert(clock, ctx, info), firrtl.Utils.one))
case Printf(info, clock, pable) =>
case e @ Printf(_, info, clock, pable) =>
val (fmt, args) = unpack(pable, ctx)
Some(fir.Print(convert(info), fir.StringLit(fmt),
args.map(a => convert(a, ctx, info)), convert(clock, ctx, info), firrtl.Utils.one))
args.map(a => convert(a, ctx, info)), convert(clock, ctx, info), firrtl.Utils.one, e.name))
case e @ Verification(_, op, info, clk, pred, msg) =>
val firOp = op match {
case Formal.Assert => fir.Formal.Assert
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/chisel3/internal/firrtl/IR.scala
Original file line number Diff line number Diff line change
Expand Up @@ -773,7 +773,7 @@ case class Attach(sourceInfo: SourceInfo, locs: Seq[Node]) extends Command
case class ConnectInit(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command
case class Stop(sourceInfo: SourceInfo, clock: Arg, ret: Int) extends Command
case class Port(id: Data, dir: SpecifiedDirection)
case class Printf(sourceInfo: SourceInfo, clock: Arg, pable: Printable) extends Command
case class Printf(id: printf.Printf, sourceInfo: SourceInfo, clock: Arg, pable: Printable) extends Definition
object Formal extends Enumeration {
val Assert = Value("assert")
val Assume = Value("assume")
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/chisel3/aop/Select.scala
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ object Select {
val printfs = mutable.ArrayBuffer[Printf]()
searchWhens(module, (cmd: Command, preds: Seq[Predicate]) => {
cmd match {
case chisel3.internal.firrtl.Printf(_, clock, pable) => printfs += Printf(preds, pable, getId(clock).asInstanceOf[Clock])
case chisel3.internal.firrtl.Printf(id, _, clock, pable) => printfs += Printf(id, preds, pable, getId(clock).asInstanceOf[Clock])
case other =>
}
})
Expand Down Expand Up @@ -418,7 +418,7 @@ object Select {
* @param pable
* @param clock
*/
case class Printf(preds: Seq[Predicate], pable: Printable, clock: Clock) extends Serializeable {
case class Printf(id: printf.Printf, preds: Seq[Predicate], pable: Printable, clock: Clock) extends Serializeable {
def serialize: String = {
s"printf when(${preds.map(_.serialize).mkString(" & ")}) on ${getName(clock)}: $pable"
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/chisel3/internal/firrtl/Emitter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@ private class Emitter(circuit: Circuit) {
case e: BulkConnect => s"${e.loc1.fullName(ctx)} <- ${e.loc2.fullName(ctx)}"
case e: Attach => e.locs.map(_.fullName(ctx)).mkString("attach (", ", ", ")")
case e: Stop => s"stop(${e.clock.fullName(ctx)}, UInt<1>(1), ${e.ret})"
case e: Printf =>
case e: chisel3.internal.firrtl.Printf =>
val (fmt, args) = e.pable.unpack(ctx)
val printfArgs = Seq(e.clock.fullName(ctx), "UInt<1>(1)",
"\"" + printf.format(fmt) + "\"") ++ args
printfArgs mkString ("printf(", ", ", ")")
(printfArgs mkString ("printf(", ", ", ")")) + s": ${e.name}"
case e: Verification[_] =>
s"""${e.op}(${e.clock.fullName(ctx)}, ${e.predicate.fullName(ctx)}, UInt<1>(1), "${printf.format(e.message)}") : ${e.name}"""
case e: DefInvalid => s"${e.arg.fullName(ctx)} is invalid"
Expand Down
66 changes: 66 additions & 0 deletions src/test/scala/chiselTests/PrintableSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,33 @@
package chiselTests

import chisel3._
import chisel3.experimental.{BaseSim, ChiselAnnotation}
import chisel3.stage.ChiselStage
import chisel3.testers.BasicTester
import firrtl.annotations.{ReferenceTarget, SingleTargetAnnotation}
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

import java.io.File

/** Dummy [[printf]] annotation.
* @param target target of component to be annotated
*/
case class PrintfAnnotation(target: ReferenceTarget) extends SingleTargetAnnotation[ReferenceTarget] {
def duplicate(n: ReferenceTarget): PrintfAnnotation = this.copy(target = n)
}

object PrintfAnnotation {
/** Create annotation for a given [[printf]].
* @param c component to be annotated
*/
def annotate(c: BaseSim): Unit = {
chisel3.experimental.annotate(new ChiselAnnotation {
def toFirrtl: PrintfAnnotation = PrintfAnnotation(c.toTarget)
})
}
}

/* Printable Tests */
class PrintableSpec extends AnyFlatSpec with Matchers {
// This regex is brittle, it specifically finds the clock and enable signals followed by commas
Expand Down Expand Up @@ -194,4 +216,48 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
case e => fail()
}
}
it should "get emitted with a name and annotated" in {

/** Test circuit containing annotated and renamed [[printf]]s. */
class PrintfAnnotationTest extends Module {
val myBun = Wire(new Bundle {
val foo = UInt(32.W)
val bar = UInt(32.W)
})
myBun.foo := 0.U
myBun.bar := 0.U
val howdy = printf(p"hello ${myBun}")
PrintfAnnotation.annotate(howdy)
PrintfAnnotation.annotate(printf(p"goodbye $myBun"))
PrintfAnnotation.annotate(printf(p"adieu $myBun").suggestName("farewell"))
}

// compile circuit
val testDir = new File("test_run_dir", "PrintfAnnotationTest")
(new ChiselStage).emitSystemVerilog(
gen = new PrintfAnnotationTest,
args = Array("-td", testDir.getPath)
)

// read in annotation file
val annoFile = new File(testDir, "PrintfAnnotationTest.anno.json")
annoFile should exist
val annoLines = scala.io.Source.fromFile(annoFile).getLines.toList

// check for expected annotations
exactly(3, annoLines) should include ("chiselTests.PrintfAnnotation")
exactly(1, annoLines) should include ("~PrintfAnnotationTest|PrintfAnnotationTest>farewell")
exactly(1, annoLines) should include ("~PrintfAnnotationTest|PrintfAnnotationTest>SIM")
exactly(1, annoLines) should include ("~PrintfAnnotationTest|PrintfAnnotationTest>howdy")

// read in FIRRTL file
val firFile = new File(testDir, "PrintfAnnotationTest.fir")
firFile should exist
val firLines = scala.io.Source.fromFile(firFile).getLines.toList

// check that verification components have expected names
exactly(1, firLines) should include ("""printf(clock, UInt<1>(1), "hello AnonymousBundle(foo -> %d, bar -> %d)", myBun.foo, myBun.bar): howdy""")
exactly(1, firLines) should include ("""printf(clock, UInt<1>(1), "goodbye AnonymousBundle(foo -> %d, bar -> %d)", myBun.foo, myBun.bar): SIM""")
exactly(1, firLines) should include ("""printf(clock, UInt<1>(1), "adieu AnonymousBundle(foo -> %d, bar -> %d)", myBun.foo, myBun.bar): farewell""")
}
}
11 changes: 7 additions & 4 deletions src/test/scala/chiselTests/aop/SelectSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,16 @@ class SelectTester(results: Seq[Int]) extends BasicTester {
val nreset = reset.asBool() === false.B
val selected = values(counter)
val zero = 0.U + 0.U
var p: printf.Printf = null
when(overflow) {
counter := zero
stop()
}.otherwise {
when(nreset) {
assert(counter === values(counter))
printf("values(%d) = %d\n", counter, selected)
p = printf("values(%d) = %d\n", counter, selected)
}

}
}

Expand Down Expand Up @@ -81,17 +83,18 @@ class SelectSpec extends ChiselFlatSpec {
"Test" should "pass if selecting correct printfs" in {
execute(
() => new SelectTester(Seq(0, 1, 2)),
{ dut: SelectTester => Seq(Select.printfs(dut).last) },
{ dut: SelectTester => Seq(Select.printfs(dut).last.toString) },
{ dut: SelectTester =>
Seq(Select.Printf(
dut.p,
Seq(
When(Select.ops("eq")(dut).last.asInstanceOf[Bool]),
When(dut.nreset),
WhenNot(dut.overflow)
),
Printable.pack("values(%d) = %d\n", dut.counter, dut.selected),
dut.p.pable,
dut.clock
))
).toString)
}
)
}
Expand Down

0 comments on commit 503ae52

Please sign in to comment.