summaryrefslogtreecommitdiff
path: root/src/test/scala/chiselTests/PrintableSpec.scala
diff options
context:
space:
mode:
authorJack2022-07-30 22:41:15 +0000
committerJack2022-07-30 22:41:15 +0000
commit4cd44fa4dab370fcc5c20bcacc1fa0ee02327252 (patch)
tree05730be260feca0d2a870c4bb88325d36631a8fc /src/test/scala/chiselTests/PrintableSpec.scala
parentfe9635ef21bad233945617a24ab16cfa4055f2d1 (diff)
parentbced77045c8fc5db37e40b159c49220929e15d46 (diff)
Merge branch '3.5.x' into 3.5-release
Diffstat (limited to 'src/test/scala/chiselTests/PrintableSpec.scala')
-rw-r--r--src/test/scala/chiselTests/PrintableSpec.scala207
1 files changed, 168 insertions, 39 deletions
diff --git a/src/test/scala/chiselTests/PrintableSpec.scala b/src/test/scala/chiselTests/PrintableSpec.scala
index 7d584cea..8039918d 100644
--- a/src/test/scala/chiselTests/PrintableSpec.scala
+++ b/src/test/scala/chiselTests/PrintableSpec.scala
@@ -9,7 +9,8 @@ import chisel3.testers.BasicTester
import firrtl.annotations.{ReferenceTarget, SingleTargetAnnotation}
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
-
+import chisel3.util._
+import org.scalactic.source.Position
import java.io.File
/** Dummy [[printf]] annotation.
@@ -32,7 +33,7 @@ object PrintfAnnotation {
}
/* Printable Tests */
-class PrintableSpec extends AnyFlatSpec with Matchers {
+class PrintableSpec extends AnyFlatSpec with Matchers with Utils {
// This regex is brittle, it specifically finds the clock and enable signals followed by commas
private val PrintfRegex = """\s*printf\(\w+, [^,]+,(.*)\).*""".r
private val StringRegex = """([^"]*)"(.*?)"(.*)""".r
@@ -47,7 +48,6 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
case _ => fail(s"Regex to process Printf should work on $str!")
}
}
-
firrtl.split("\n").collect {
case PrintfRegex(matched) =>
val (str, args) = processBody(matched)
@@ -55,26 +55,34 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
}
}
+ // Generates firrtl, gets Printfs
+ // Calls fail() if failed match; else calls the partial function which could have its own check
+ private def generateAndCheck(gen: => RawModule)(check: PartialFunction[Seq[Printf], Unit])(implicit pos: Position) = {
+ val firrtl = ChiselStage.emitChirrtl(gen)
+ val printfs = getPrintfs(firrtl)
+ if (!check.isDefinedAt(printfs)) {
+ fail()
+ } else {
+ check(printfs)
+ }
+ }
+
behavior.of("Printable & Custom Interpolator")
it should "pass exact strings through" in {
class MyModule extends BasicTester {
printf(p"An exact string")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("An exact string", Seq())) =>
- case e => fail()
}
}
it should "handle Printable and String concatination" in {
class MyModule extends BasicTester {
printf(p"First " + PString("Second ") + "Third")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("First Second Third", Seq())) =>
- case e => fail()
}
}
it should "call toString on non-Printable objects" in {
@@ -82,10 +90,8 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
val myInt = 1234
printf(p"myInt = $myInt")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("myInt = 1234", Seq())) =>
- case e => fail()
}
}
it should "generate proper printf for simple Decimal printing" in {
@@ -93,41 +99,33 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
val myWire = WireDefault(1234.U)
printf(p"myWire = ${Decimal(myWire)}")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("myWire = %d", Seq("myWire"))) =>
- case e => fail()
}
}
it should "handle printing literals" in {
class MyModule extends BasicTester {
printf(Decimal(10.U(32.W)))
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("%d", Seq(lit))) =>
assert(lit contains "UInt<32>")
- case e => fail()
}
}
it should "correctly escape percent" in {
class MyModule extends BasicTester {
printf(p"%")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("%%", Seq())) =>
- case e => fail()
}
}
it should "correctly emit tab" in {
class MyModule extends BasicTester {
printf(p"\t")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("\\t", Seq())) =>
- case e => fail()
}
}
it should "support names of circuit elements including submodule IO" in {
@@ -149,10 +147,8 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
printf(p"${FullName(myWire.foo)}")
printf(p"${FullName(myInst.io.fizz)}")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("foo", Seq()), Printf("myWire.foo", Seq()), Printf("myInst.io.fizz", Seq())) =>
- case e => fail()
}
}
it should "handle printing ports of submodules" in {
@@ -165,10 +161,8 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
val myInst = Module(new MySubModule)
printf(p"${myInst.io.fizz}")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("%d", Seq("myInst.io.fizz"))) =>
- case e => fail()
}
}
it should "print UInts and SInts as Decimal by default" in {
@@ -177,10 +171,8 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
val mySInt = WireDefault(-1.S)
printf(p"$myUInt & $mySInt")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("%d & %d", Seq("myUInt", "mySInt"))) =>
- case e => fail()
}
}
it should "print Vecs like Scala Seqs by default" in {
@@ -189,10 +181,8 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
myVec.foreach(_ := 0.U)
printf(p"$myVec")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("Vec(%d, %d, %d, %d)", Seq("myVec[0]", "myVec[1]", "myVec[2]", "myVec[3]"))) =>
- case e => fail()
}
}
it should "print Bundles like Scala Maps by default" in {
@@ -205,10 +195,8 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
myBun.bar := 0.U
printf(p"$myBun")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("AnonymousBundle(foo -> %d, bar -> %d)", Seq("myBun.foo", "myBun.bar"))) =>
- case e => fail()
}
}
it should "get emitted with a name and annotated" in {
@@ -261,4 +249,145 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
"""printf(clock, UInt<1>("h1"), "adieu AnonymousBundle(foo -> %d, bar -> %d)", myBun.foo, myBun.bar) : farewell"""
)
}
+
+ // Unit tests for cf
+ it should "print regular scala variables with cf format specifier" in {
+
+ class MyModule extends BasicTester {
+ val f1 = 20.4517
+ val i1 = 10
+ val str1 = "String!"
+ printf(
+ cf"F1 = $f1 D1 = $i1 F1 formatted = $f1%2.2f str1 = $str1%s i1_str = $i1%s i1_hex=$i1%x"
+ )
+
+ }
+
+ generateAndCheck(new MyModule) {
+ case Seq(Printf("F1 = 20.4517 D1 = 10 F1 formatted = 20.45 str1 = String! i1_str = 10 i1_hex=a", Seq())) =>
+ }
+ }
+
+ it should "print chisel bits with cf format specifier" in {
+
+ class MyBundle extends Bundle {
+ val foo = UInt(32.W)
+ val bar = UInt(32.W)
+ override def toPrintable: Printable = {
+ cf"Bundle : " +
+ cf"Foo : $foo%x Bar : $bar%x"
+ }
+ }
+ class MyModule extends BasicTester {
+ val b1 = 10.U
+ val w1 = Wire(new MyBundle)
+ w1.foo := 5.U
+ w1.bar := 10.U
+ printf(cf"w1 = $w1")
+ }
+ generateAndCheck(new MyModule) {
+ case Seq(Printf("w1 = Bundle : Foo : %x Bar : %x", Seq("w1.foo", "w1.bar"))) =>
+ }
+ }
+
+ it should "support names of circuit elements using format specifier including submodule IO with cf format specifier" in {
+ // Submodule IO is a subtle issue because the Chisel element has a different
+ // parent module
+ class MySubModule extends Module {
+ val io = IO(new Bundle {
+ val fizz = UInt(32.W)
+ })
+ }
+ class MyBundle extends Bundle {
+ val foo = UInt(32.W)
+ }
+ class MyModule extends BasicTester {
+ override def desiredName: String = "MyModule"
+ val myWire = Wire(new MyBundle)
+ val myInst = Module(new MySubModule)
+ printf(cf"${myWire.foo}%n")
+ printf(cf"${myWire.foo}%N")
+ printf(cf"${myInst.io.fizz}%N")
+ }
+ generateAndCheck(new MyModule) {
+ case Seq(Printf("foo", Seq()), Printf("myWire.foo", Seq()), Printf("myInst.io.fizz", Seq())) =>
+ }
+ }
+
+ it should "correctly print strings after modifier" in {
+ class MyModule extends BasicTester {
+ val b1 = 10.U
+ printf(cf"This is here $b1%x!!!! And should print everything else")
+ }
+ generateAndCheck(new MyModule) {
+ case Seq(Printf("This is here %x!!!! And should print everything else", Seq("UInt<4>(\"ha\")"))) =>
+ }
+ }
+
+ it should "correctly print strings with a lot of literal %% and different format specifiers for Wires" in {
+ class MyModule extends BasicTester {
+ val b1 = 10.U
+ val b2 = 20.U
+ printf(cf"%% $b1%x%%$b2%b = ${b1 % b2}%d %%%% Tail String")
+ }
+
+ generateAndCheck(new MyModule) {
+ case Seq(Printf("%% %x%%%b = %d %%%% Tail String", Seq(lita, litb, _))) =>
+ assert(lita.contains("UInt<4>") && litb.contains("UInt<5>"))
+ }
+ }
+
+ it should "not allow unescaped % in the message" in {
+ class MyModule extends BasicTester {
+ printf(cf"This should error out for sure because of % - it should be %%")
+ }
+ a[java.util.UnknownFormatConversionException] should be thrownBy {
+ extractCause[java.util.UnknownFormatConversionException] {
+ ChiselStage.elaborate { new MyModule }
+ }
+ }
+ }
+
+ it should "allow Printables to be expanded and used" in {
+ class MyModule extends BasicTester {
+ val w1 = 20.U
+ val f1 = 30.2
+ val i1 = 14
+ val pable = cf"w1 = $w1%b f1 = $f1%2.2f"
+ printf(cf"Trying to expand printable $pable and mix with i1 = $i1%d")
+ }
+ generateAndCheck(new MyModule) {
+ case Seq(Printf("Trying to expand printable w1 = %b f1 = 30.20 and mix with i1 = 14", Seq(lit))) =>
+ assert(lit.contains("UInt<5>"))
+ }
+ }
+
+ it should "fail with a single % in the message" in {
+ class MyModule extends BasicTester {
+ printf(cf"%")
+ }
+ a[java.util.UnknownFormatConversionException] should be thrownBy {
+ extractCause[java.util.UnknownFormatConversionException] {
+ ChiselStage.elaborate { new MyModule }
+ }
+ }
+ }
+
+ it should "fail when passing directly to StirngContext.cf a string with literal \\ correctly escaped " in {
+ a[StringContext.InvalidEscapeException] should be thrownBy {
+ extractCause[StringContext.InvalidEscapeException] {
+ val s_seq = Seq("Test with literal \\ correctly escaped")
+ StringContext(s_seq: _*).cf(Seq(): _*)
+ }
+ }
+ }
+
+ it should "pass correctly escaped \\ when using Printable.pack" in {
+ class MyModule extends BasicTester {
+ printf(Printable.pack("\\ \\]"))
+ }
+ generateAndCheck(new MyModule) {
+ case Seq(Printf("\\\\ \\\\]", Seq())) =>
+ }
+ }
}