diff options
| author | Jack Koenig | 2018-02-27 18:07:11 -0800 |
|---|---|---|
| committer | GitHub | 2018-02-27 18:07:11 -0800 |
| commit | c7eb1570dfb1c7701ea32d1209982a053f3cec1d (patch) | |
| tree | 3f509b202d82841c5dad5588d1f953a25d389b44 /src/test/scala/firrtlTests/AnnotationTests.scala | |
| parent | b90fc784a1819c1d7905910130a7da022214bc22 (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.scala | 224 |
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) + } +} |
