aboutsummaryrefslogtreecommitdiff
path: root/src/test/scala/firrtlTests/AnnotationTests.scala
diff options
context:
space:
mode:
authorJack Koenig2018-02-27 18:07:11 -0800
committerGitHub2018-02-27 18:07:11 -0800
commitc7eb1570dfb1c7701ea32d1209982a053f3cec1d (patch)
tree3f509b202d82841c5dad5588d1f953a25d389b44 /src/test/scala/firrtlTests/AnnotationTests.scala
parentb90fc784a1819c1d7905910130a7da022214bc22 (diff)
Refactor Annotations (#721)
- Old Annotation renamed to deprecated LegacyAnnotation - Annotation is now a trait that can be extended - New JsonProtocol for Annotation [de]serialization - Replace AnnotationMap with AnnotationSeq - Deprecate Transform.getMyAnnotations - Update Transforms - Turn on deprecation warnings - Remove deprecated Driver.compile - Make AnnotationTests abstract with Legacy and Json subclasses - Add functionality to convert LegacyAnnotations of built-in annos This will give a noisy warning and is more of a best effort than a robust solution. Fixes #475 Closes #609
Diffstat (limited to 'src/test/scala/firrtlTests/AnnotationTests.scala')
-rw-r--r--src/test/scala/firrtlTests/AnnotationTests.scala224
1 files changed, 116 insertions, 108 deletions
diff --git a/src/test/scala/firrtlTests/AnnotationTests.scala b/src/test/scala/firrtlTests/AnnotationTests.scala
index 7b7e7839..85814713 100644
--- a/src/test/scala/firrtlTests/AnnotationTests.scala
+++ b/src/test/scala/firrtlTests/AnnotationTests.scala
@@ -25,32 +25,22 @@ trait AnnotationSpec extends LowTransformSpec {
// Check if Annotation Exception is thrown
override def failingexecute(input: String, annotations: Seq[Annotation]): Exception = {
intercept[AnnotationException] {
- compile(CircuitState(parse(input), ChirrtlForm, Some(AnnotationMap(annotations))), Seq.empty)
+ compile(CircuitState(parse(input), ChirrtlForm, annotations), Seq.empty)
}
}
def execute(input: String, check: Annotation, annotations: Seq[Annotation]): Unit = {
- val cr = compile(CircuitState(parse(input), ChirrtlForm, Some(AnnotationMap(annotations))), Seq.empty)
- cr.annotations.get.annotations should contain (check)
+ val cr = compile(CircuitState(parse(input), ChirrtlForm, annotations), Seq.empty)
+ cr.annotations.toSeq should contain (check)
}
}
+// Abstract but with lots of tests defined so that we can use the same tests
+// for Legacy and newer Annotations
+abstract class AnnotationTests extends AnnotationSpec with Matchers {
+ def anno(s: String, value: String ="this is a value", mod: String = "Top"): Annotation
+ def manno(mod: String): Annotation
-/**
- * Tests for Annotation Permissibility and Tenacity
- *
- * WARNING(izraelevitz): Not a complete suite of tests, requires the LowerTypes
- * pass and ConstProp pass to correctly populate its RenameMap before Strict, Rigid, Firm,
- * Unstable, Fickle, and Insistent can be tested.
- */
-class AnnotationTests extends AnnotationSpec with Matchers {
- def getAMap(a: Annotation): Option[AnnotationMap] = Some(AnnotationMap(Seq(a)))
- def getAMap(as: Seq[Annotation]): Option[AnnotationMap] = Some(AnnotationMap(as))
- def anno(s: String, value: String ="this is a value", mod: String = "Top"): Annotation =
- Annotation(ComponentName(s, ModuleName(mod, CircuitName("Top"))), classOf[Transform], value)
- def manno(mod: String): Annotation =
- Annotation(ModuleName(mod, CircuitName("Top")), classOf[Transform], "some value")
-
- "Loose and Sticky annotation on a node" should "pass through" in {
+ "Annotation on a node" should "pass through" in {
val input: String =
"""circuit Top :
| module Top :
@@ -61,71 +51,6 @@ class AnnotationTests extends AnnotationSpec with Matchers {
execute(input, ta, Seq(ta))
}
- "Annotations" should "be readable from file" in {
- val annotationStream = getClass.getResourceAsStream("/annotations/SampleAnnotations.anno")
- val annotationsYaml = scala.io.Source.fromInputStream(annotationStream).getLines().mkString("\n").parseYaml
- val annotationArray = annotationsYaml.convertTo[Array[Annotation]]
- annotationArray.length should be (9)
- annotationArray(0).targetString should be ("ModC")
- annotationArray(7).transformClass should be ("firrtl.passes.InlineInstances")
- val expectedValue = "TopOfDiamond\nWith\nSome new lines"
- annotationArray(7).value should be (expectedValue)
- }
-
- "Badly formatted serializations" should "return reasonable error messages" in {
- var badYaml =
- """
- |- transformClass: firrtl.passes.InlineInstances
- | targetString: circuit.module..
- | value: ModC.this params 16 32
- """.stripMargin.parseYaml
-
- var thrown = intercept[Exception] {
- badYaml.convertTo[Array[Annotation]]
- }
- thrown.getMessage should include ("Illegal component name")
-
- badYaml =
- """
- |- transformClass: firrtl.passes.InlineInstances
- | targetString: .circuit.module.component
- | value: ModC.this params 16 32
- """.stripMargin.parseYaml
-
- thrown = intercept[Exception] {
- badYaml.convertTo[Array[Annotation]]
- }
- thrown.getMessage should include ("Illegal circuit name")
- }
-
- "Round tripping annotations through text file" should "preserve annotations" in {
- val annos: Array[Annotation] = Seq(
- InlineAnnotation(CircuitName("fox")),
- InlineAnnotation(ModuleName("dog", CircuitName("bear"))),
- InlineAnnotation(ComponentName("chocolate", ModuleName("like", CircuitName("i")))),
- PinAnnotation(CircuitName("Pinniped"), Seq("sea-lion", "monk-seal"))
- ).toArray
-
- val annoFile = new File("temp-anno")
- val writer = new FileWriter(annoFile)
- writer.write(annos.toYaml.prettyPrint)
- writer.close()
-
- val yaml = io.Source.fromFile(annoFile).getLines().mkString("\n").parseYaml
- annoFile.delete()
-
- val readAnnos = yaml.convertTo[Array[Annotation]]
-
- annos.zip(readAnnos).foreach { case (beforeAnno, afterAnno) =>
- beforeAnno.targetString should be (afterAnno.targetString)
- beforeAnno.target should be (afterAnno.target)
- beforeAnno.transformClass should be (afterAnno.transformClass)
- beforeAnno.transform should be (afterAnno.transform)
-
- beforeAnno should be (afterAnno)
- }
- }
-
"Deleting annotations" should "create a DeletedAnnotation" in {
val compiler = new VerilogCompiler
val input =
@@ -136,12 +61,15 @@ class AnnotationTests extends AnnotationSpec with Matchers {
class DeletingTransform extends Transform {
val inputForm = LowForm
val outputForm = LowForm
- def execute(state: CircuitState) = state.copy(annotations = None)
+ def execute(state: CircuitState) = state.copy(annotations = Seq())
}
+ val transform = new DeletingTransform
+ val tname = transform.name
val inlineAnn = InlineAnnotation(CircuitName("Top"))
- val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, getAMap(inlineAnn)), Seq(new DeletingTransform))
- result.annotations.get.annotations.head should matchPattern {
- case DeletedAnnotation(x, inlineAnn) =>
+ val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, Seq(inlineAnn)), Seq(transform))
+ println(result.annotations.head)
+ result.annotations.head should matchPattern {
+ case DeletedAnnotation(`tname`, `inlineAnn`) =>
}
val exception = (intercept[FIRRTLException] {
result.getEmittedCircuit
@@ -149,6 +77,7 @@ class AnnotationTests extends AnnotationSpec with Matchers {
val deleted = result.deletedAnnotations
exception.str should be (s"No EmittedCircuit found! Did you delete any annotations?\n$deleted")
}
+
"Renaming" should "propagate in Lowering of memories" in {
val compiler = new VerilogCompiler
// Uncomment to help debugging failing tests
@@ -170,8 +99,8 @@ class AnnotationTests extends AnnotationSpec with Matchers {
|""".stripMargin
val annos = Seq(anno("m.r.data.b", "sub"), anno("m.r.data", "all"), anno("m", "mem"),
dontTouch("Top.m"))
- val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, getAMap(annos)), Nil)
- val resultAnno = result.annotations.get.annotations
+ val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, annos), Nil)
+ val resultAnno = result.annotations.toSeq
resultAnno should contain (anno("m_a", "mem"))
resultAnno should contain (anno("m_b_0", "mem"))
resultAnno should contain (anno("m_b_1", "mem"))
@@ -185,7 +114,6 @@ class AnnotationTests extends AnnotationSpec with Matchers {
}
"Renaming" should "propagate in RemoveChirrtl and Lowering of memories" in {
val compiler = new VerilogCompiler
- Logger.setClassLogLevels(Map(compiler.getClass.getName -> LogLevel.Debug))
val input =
"""circuit Top :
| module Top :
@@ -195,8 +123,8 @@ class AnnotationTests extends AnnotationSpec with Matchers {
| read mport r = m[in], clk
|""".stripMargin
val annos = Seq(anno("r.b", "sub"), anno("r", "all"), anno("m", "mem"), dontTouch("Top.m"))
- val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, getAMap(annos)), Nil)
- val resultAnno = result.annotations.get.annotations
+ val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, annos), Nil)
+ val resultAnno = result.annotations.toSeq
resultAnno should contain (anno("m_a", "mem"))
resultAnno should contain (anno("m_b_0", "mem"))
resultAnno should contain (anno("m_b_1", "mem"))
@@ -225,8 +153,8 @@ class AnnotationTests extends AnnotationSpec with Matchers {
|""".stripMargin
val annos = Seq(anno("zero"), anno("x.a"), anno("x.b"), anno("y[0]"), anno("y[1]"),
anno("y[2]"), dontTouch("Top.x"))
- val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, getAMap(annos)), Nil)
- val resultAnno = result.annotations.get.annotations
+ val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, annos), Nil)
+ val resultAnno = result.annotations.toSeq
resultAnno should contain (anno("x_a"))
resultAnno should not contain (anno("zero"))
resultAnno should not contain (anno("x.a"))
@@ -267,8 +195,8 @@ class AnnotationTests extends AnnotationSpec with Matchers {
anno("write.a"), anno("write.b[0]"), anno("write.b[1]"),
dontTouch("Top.r"), dontTouch("Top.w")
)
- val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, getAMap(annos)), Nil)
- val resultAnno = result.annotations.get.annotations
+ val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, annos), Nil)
+ val resultAnno = result.annotations.toSeq
resultAnno should not contain (anno("in.a"))
resultAnno should not contain (anno("in.b[0]"))
resultAnno should not contain (anno("in.b[1]"))
@@ -321,8 +249,8 @@ class AnnotationTests extends AnnotationSpec with Matchers {
|""".stripMargin
val annos = Seq(anno("in"), anno("out"), anno("w"), anno("n"), anno("r"), dontTouch("Top.r"),
dontTouch("Top.w"))
- val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, getAMap(annos)), Nil)
- val resultAnno = result.annotations.get.annotations
+ val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, annos), Nil)
+ val resultAnno = result.annotations.toSeq
resultAnno should contain (anno("in_a"))
resultAnno should contain (anno("in_b_0"))
resultAnno should contain (anno("in_b_1"))
@@ -357,8 +285,8 @@ class AnnotationTests extends AnnotationSpec with Matchers {
|""".stripMargin
val annos = Seq(anno("in.b"), anno("out.b"), anno("w.b"), anno("n.b"), anno("r.b"),
dontTouch("Top.r"), dontTouch("Top.w"))
- val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, getAMap(annos)), Nil)
- val resultAnno = result.annotations.get.annotations
+ val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, annos), Nil)
+ val resultAnno = result.annotations.toSeq
resultAnno should contain (anno("in_b_0"))
resultAnno should contain (anno("in_b_1"))
resultAnno should contain (anno("out_b_0"))
@@ -388,8 +316,8 @@ class AnnotationTests extends AnnotationSpec with Matchers {
anno("out.a"), anno("out.b[0]"), anno("out.b[1]"),
anno("n.a"), anno("n.b[0]"), anno("n.b[1]")
)
- val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, getAMap(annos)), Nil)
- val resultAnno = result.annotations.get.annotations
+ val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, annos), Nil)
+ val resultAnno = result.annotations.toSeq
resultAnno should not contain (anno("in.a"))
resultAnno should not contain (anno("in.b[0]"))
resultAnno should not contain (anno("in.b[1]"))
@@ -438,17 +366,17 @@ class AnnotationTests extends AnnotationSpec with Matchers {
anno("foo", mod = "Dead"), anno("bar", mod = "Dead"),
anno("foo", mod = "DeadExt"), anno("bar", mod = "DeadExt")
)
- val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, getAMap(annos)), Nil)
+ val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, annos), Nil)
/* Uncomment to help debug
println(result.circuit.serialize)
- result.annotations.get.annotations.foreach{ a =>
+ result.annotations.foreach{ a =>
a match {
case DeletedAnnotation(xform, anno) => println(s"$xform deleted: ${a.target}")
case Annotation(target, _, _) => println(s"not deleted: $target")
}
}
*/
- val resultAnno = result.annotations.get.annotations
+ val resultAnno = result.annotations.toSeq
resultAnno should contain (manno("Top"))
resultAnno should contain (anno("foo", mod = "Top"))
@@ -488,8 +416,8 @@ class AnnotationTests extends AnnotationSpec with Matchers {
val annos = Seq(
anno("x", mod = "Child"), anno("y", mod = "Child_1"), manno("Child"), manno("Child_1")
)
- val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, getAMap(annos)), Nil)
- val resultAnno = result.annotations.get.annotations
+ val result = compiler.compile(CircuitState(parse(input), ChirrtlForm, annos), Nil)
+ val resultAnno = result.annotations.toSeq
resultAnno should contain (anno("x", mod = "Child"))
resultAnno should contain (anno("y", mod = "Child"))
resultAnno should contain (manno("Child"))
@@ -503,3 +431,83 @@ class AnnotationTests extends AnnotationSpec with Matchers {
require(x == y)
}
}
+
+class LegacyAnnotationTests extends AnnotationTests {
+ def anno(s: String, value: String ="this is a value", mod: String = "Top"): Annotation =
+ Annotation(ComponentName(s, ModuleName(mod, CircuitName("Top"))), classOf[Transform], value)
+ def manno(mod: String): Annotation =
+ Annotation(ModuleName(mod, CircuitName("Top")), classOf[Transform], "some value")
+
+ "LegacyAnnotations" should "be readable from file" in {
+ val annotationStream = getClass.getResourceAsStream("/annotations/SampleAnnotations.anno")
+ val annotationsYaml = scala.io.Source.fromInputStream(annotationStream).getLines().mkString("\n").parseYaml
+ val annotationArray = annotationsYaml.convertTo[Array[LegacyAnnotation]]
+ annotationArray.length should be (9)
+ annotationArray(0).targetString should be ("ModC")
+ annotationArray(7).transformClass should be ("firrtl.passes.InlineInstances")
+ val expectedValue = "TopOfDiamond\nWith\nSome new lines"
+ annotationArray(7).value should be (expectedValue)
+ }
+
+ "Badly formatted LegacyAnnotation serializations" should "return reasonable error messages" in {
+ var badYaml =
+ """
+ |- transformClass: firrtl.passes.InlineInstances
+ | targetString: circuit.module..
+ | value: ModC.this params 16 32
+ """.stripMargin.parseYaml
+
+ var thrown = intercept[Exception] {
+ badYaml.convertTo[Array[LegacyAnnotation]]
+ }
+ thrown.getMessage should include ("Illegal component name")
+
+ badYaml =
+ """
+ |- transformClass: firrtl.passes.InlineInstances
+ | targetString: .circuit.module.component
+ | value: ModC.this params 16 32
+ """.stripMargin.parseYaml
+
+ thrown = intercept[Exception] {
+ badYaml.convertTo[Array[LegacyAnnotation]]
+ }
+ thrown.getMessage should include ("Illegal circuit name")
+ }
+}
+
+class JsonAnnotationTests extends AnnotationTests {
+ // Helper annotations
+ case class SimpleAnno(target: ComponentName, value: String) extends
+ SingleTargetAnnotation[ComponentName] {
+ def duplicate(n: ComponentName) = this.copy(target = n)
+ }
+ case class ModuleAnno(target: ModuleName) extends SingleTargetAnnotation[ModuleName] {
+ def duplicate(n: ModuleName) = this.copy(target = n)
+ }
+
+ def anno(s: String, value: String ="this is a value", mod: String = "Top"): SimpleAnno =
+ SimpleAnno(ComponentName(s, ModuleName(mod, CircuitName("Top"))), value)
+ def manno(mod: String): Annotation = ModuleAnno(ModuleName(mod, CircuitName("Top")))
+
+ "Round tripping annotations through text file" should "preserve annotations" in {
+ val annos: Array[Annotation] = Seq(
+ InlineAnnotation(CircuitName("fox")),
+ InlineAnnotation(ModuleName("dog", CircuitName("bear"))),
+ InlineAnnotation(ComponentName("chocolate", ModuleName("like", CircuitName("i")))),
+ PinAnnotation(Seq("sea-lion", "monk-seal"))
+ ).toArray
+
+ val annoFile = new File("temp-anno")
+ val writer = new FileWriter(annoFile)
+ writer.write(JsonProtocol.serialize(annos))
+ writer.close()
+
+ val text = io.Source.fromFile(annoFile).getLines().mkString("\n")
+ annoFile.delete()
+
+ val readAnnos = JsonProtocol.deserializeTry(text).get
+
+ annos should be (readAnnos)
+ }
+}