From 80aabc03ef2420e817bcbac34c78ec25227d9fbb Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Fri, 22 Mar 2019 09:39:53 -0700 Subject: Fix enum annotations (#936) * Turned off strong enum annotations because they weren't working with Vec indexes * Add new EnumVecAnnotation for vecs of enums and vecs of bundles with enum fields * Changed Clock's width parameter back to a fixed constant value of 1 * Fixed enum annotations for Vecs of Bundles which contain enum elements * Fixed usage of "when/otherwise" to use consistent style--- src/test/scala/chiselTests/StrongEnum.scala | 213 +++++++++++++++++++++------- 1 file changed, 163 insertions(+), 50 deletions(-) (limited to 'src/test') diff --git a/src/test/scala/chiselTests/StrongEnum.scala b/src/test/scala/chiselTests/StrongEnum.scala index f5c3bc2f..6c87aee3 100644 --- a/src/test/scala/chiselTests/StrongEnum.scala +++ b/src/test/scala/chiselTests/StrongEnum.scala @@ -367,64 +367,177 @@ class StrongEnumSpec extends ChiselFlatSpec { "foo(OtherEnum.otherEnum)" shouldNot compile } + it should "prevent enums from being declared without names" in { + "object UnnamedEnum extends ChiselEnum { Value }" shouldNot compile + } + "StrongEnum FSM" should "work" in { assertTesterPasses(new StrongEnumFSMTester) } } -class StrongEnumAnnotationSpec extends ChiselFlatSpec { +class StrongEnumAnnotator extends Module { + import EnumExample._ + + val io = IO(new Bundle{ + val in = Input(EnumExample()) + val out = Output(EnumExample()) + val other = Output(OtherEnum()) + }) + + class Bund extends Bundle { + val field = EnumExample() + val other = OtherEnum() + val vec = Vec(5, EnumExample()) + val inner_bundle1 = new Bundle { + val x = UInt(4.W) + val y = Vec(3, UInt(4.W)) + val e = EnumExample() + val v = Vec(3, EnumExample()) + } + val inner_bundle2 = new Bundle {} + val inner_bundle3 = new Bundle { + val x = Bool() + } + val inner_bundle4 = new Bundle { + val inner_inner_bundle = new Bundle {} + } + } + + val simple = Wire(EnumExample()) + val vec = VecInit(e0, e1, e2) + val vec_of_vecs = VecInit(VecInit(e0, e1), VecInit(e100, e101)) + + val bund = Wire(new Bund()) + val vec_of_bundles = Wire(Vec(5, new Bund())) + + io.out := e101 + io.other := OtherEnum.otherEnum + simple := e100 + bund := DontCare + vec_of_bundles := DontCare + + // Make sure that dynamically indexing into a Vec of enums will not cause an elaboration error. + // The components created here will not be annotated. + val cycle = RegInit(0.U) + cycle := cycle + 1.U + + val indexed1 = vec_of_vecs(cycle)(cycle) + val indexed2 = vec_of_bundles(cycle) +} + +class StrongEnumAnnotationSpec extends FreeSpec with Matchers { import chisel3.experimental.EnumAnnotations._ - import firrtl.annotations.ComponentName - - ignore should "Test that strong enums annotate themselves appropriately" in { - - // scalastyle:off regex - def test(): Assertion = {// scalastyle:ignore cyclomatic.complexity - Driver.execute(Array("--target-dir", "test_run_dir"), () => new StrongEnumFSM) match { - case ChiselExecutionSuccess(Some(circuit), emitted, _) => - val annos = circuit.annotations.map(_.toFirrtl) - - val enumDefAnnos = annos.collect { case a: EnumDefAnnotation => a } - val enumCompAnnos = annos.collect { case a: EnumComponentAnnotation => a } - - // Print the annotations out onto the screen - println("Enum definitions:") - enumDefAnnos.foreach { - case EnumDefAnnotation(enumTypeName, definition) => println(s"\t$enumTypeName: $definition") - } - println("Enum components:") - enumCompAnnos.foreach{ - case EnumComponentAnnotation(target, enumTypeName) => println(s"\t$target => $enumTypeName") - } - - // Check that the global annotation is correct - enumDefAnnos.exists { - case EnumDefAnnotation(name, map) => - name.endsWith("State") && - map.size == StrongEnumFSM.State.correct_annotation_map.size && - map.forall { - case (k, v) => - val correctValue = StrongEnumFSM.State.correct_annotation_map(k) - correctValue == v - } - case _ => false - } should be(true) - - // Check that the component annotations are correct - enumCompAnnos.count { - case EnumComponentAnnotation(target, enumName) => - val ComponentName(targetName, _) = target - (targetName == "state" && enumName.endsWith("State")) || - (targetName == "io.state" && enumName.endsWith("State")) - case _ => false - } should be(2) - - case _ => - assert(false) - } - // scalastyle:on regex + import firrtl.annotations.{ComponentName, Annotation} + + val enumExampleName = "EnumExample" + val otherEnumName = "OtherEnum" + + case class CorrectDefAnno(typeName: String, definition: Map[String, BigInt]) + case class CorrectCompAnno(targetName: String, typeName: String) + case class CorrectVecAnno(targetName: String, typeName: String, fields: Set[Seq[String]]) + + val correctDefAnnos = Seq( + CorrectDefAnno(otherEnumName, Map("otherEnum" -> 0)), + CorrectDefAnno(enumExampleName, Map("e0" -> 0, "e1" -> 1, "e2" -> 2, "e100" -> 100, "e101" -> 101)) + ) + + val correctCompAnnos = Seq( + CorrectCompAnno("io.other", otherEnumName), + CorrectCompAnno("io.out", enumExampleName), + CorrectCompAnno("io.in", enumExampleName), + CorrectCompAnno("simple", enumExampleName), + CorrectCompAnno("bund.field", enumExampleName), + CorrectCompAnno("bund.other", otherEnumName), + CorrectCompAnno("bund.inner_bundle1.e", enumExampleName) + ) + + val correctVecAnnos = Seq( + CorrectVecAnno("vec", enumExampleName, Set()), + CorrectVecAnno("vec_of_vecs", enumExampleName, Set()), + CorrectVecAnno("vec_of_bundles", enumExampleName, Set(Seq("field"), Seq("vec"), Seq("inner_bundle1", "e"), Seq("inner_bundle1", "v"))), + CorrectVecAnno("vec_of_bundles", otherEnumName, Set(Seq("other"))), + CorrectVecAnno("bund.vec", enumExampleName, Set()), + CorrectVecAnno("bund.inner_bundle1.v", enumExampleName, Set()) + ) + + // scalastyle:off regex + def printAnnos(annos: Seq[Annotation]) { + println("Enum definitions:") + annos.foreach { + case EnumDefAnnotation(enumTypeName, definition) => println(s"\t$enumTypeName: $definition") + case _ => + } + println("Enum components:") + annos.foreach{ + case EnumComponentAnnotation(target, enumTypeName) => println(s"\t$target => $enumTypeName") + case _ => } + println("Enum vecs:") + annos.foreach{ + case EnumVecAnnotation(target, enumTypeName, fields) => println(s"\t$target[$fields] => $enumTypeName") + case _ => + } + } + // scalastyle:on regex + + def isCorrect(anno: EnumDefAnnotation, correct: CorrectDefAnno): Boolean = { + (anno.typeName == correct.typeName || + anno.typeName.endsWith("." + correct.typeName)) && + anno.definition == correct.definition + } + + def isCorrect(anno: EnumComponentAnnotation, correct: CorrectCompAnno): Boolean = { + (anno.target match { + case ComponentName(name, _) => name == correct.targetName + case _ => throw new Exception("Unknown target type in EnumComponentAnnotation") + }) && + (anno.enumTypeName == correct.typeName || anno.enumTypeName.endsWith("." + correct.typeName)) + } + + def isCorrect(anno: EnumVecAnnotation, correct: CorrectVecAnno): Boolean = { + (anno.target match { + case ComponentName(name, _) => name == correct.targetName + case _ => throw new Exception("Unknown target type in EnumVecAnnotation") + }) && + (anno.typeName == correct.typeName || anno.typeName.endsWith("." + correct.typeName)) && + anno.fields.map(_.toSeq).toSet == correct.fields + } + + def allCorrectDefs(annos: Seq[EnumDefAnnotation], corrects: Seq[CorrectDefAnno]): Boolean = { + corrects.forall(c => annos.exists(isCorrect(_, c))) && + correctDefAnnos.length == annos.length + } + + // Because temporary variables might be formed and annotated, we do not check that every component or vector + // annotation is accounted for in the correct results listed above + def allCorrectComps(annos: Seq[EnumComponentAnnotation], corrects: Seq[CorrectCompAnno]): Boolean = + corrects.forall(c => annos.exists(isCorrect(_, c))) + + def allCorrectVecs(annos: Seq[EnumVecAnnotation], corrects: Seq[CorrectVecAnno]): Boolean = + corrects.forall(c => annos.exists(isCorrect(_, c))) + + def test() { + Driver.execute(Array("--target-dir", "test_run_dir"), () => new StrongEnumAnnotator) match { + case ChiselExecutionSuccess(Some(circuit), emitted, _) => + val annos = circuit.annotations.map(_.toFirrtl) + + printAnnos(annos) + + val enumDefAnnos = annos.collect { case a: EnumDefAnnotation => a } + val enumCompAnnos = annos.collect { case a: EnumComponentAnnotation => a } + val enumVecAnnos = annos.collect { case a: EnumVecAnnotation => a } + + allCorrectDefs(enumDefAnnos, correctDefAnnos) should be(true) + allCorrectComps(enumCompAnnos, correctCompAnnos) should be(true) + allCorrectVecs(enumVecAnnos, correctVecAnnos) should be(true) + + case _ => + assert(false) + } + } + "Test that strong enums annotate themselves appropriately" in { // We run this test twice, to test for an older bug where only the first circuit would be annotated test() test() -- cgit v1.2.3