diff options
| author | Hasan Genc | 2019-06-24 15:04:10 -0700 |
|---|---|---|
| committer | Adam Izraelevitz | 2019-06-24 15:04:09 -0700 |
| commit | c282515b1bcf49f2566390fd059601734ffba196 (patch) | |
| tree | be31f7af7b1c71045a5fd506b6d22238e22ae797 | |
| parent | c6376e7b4669b313bbdaa936f8f9273f684bfa1a (diff) | |
Changed Value macro in ChiselEnum so that it doesn't use deprecated (#1104)
function. This also fixes prior issue where ChiselEnums would not
compile when @chiselName was applied to a module containing a ChiselEnum
| -rw-r--r-- | chiselFrontend/src/main/scala/chisel3/StrongEnum.scala | 40 | ||||
| -rw-r--r-- | src/test/scala/chiselTests/StrongEnum.scala | 95 |
2 files changed, 105 insertions, 30 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/StrongEnum.scala b/chiselFrontend/src/main/scala/chisel3/StrongEnum.scala index b37ba703..8edce4d8 100644 --- a/chiselFrontend/src/main/scala/chisel3/StrongEnum.scala +++ b/chiselFrontend/src/main/scala/chisel3/StrongEnum.scala @@ -249,14 +249,13 @@ abstract class EnumFactory { protected def Value: Type = macro EnumMacros.ValImpl // scalastyle:off method.name protected def Value(id: UInt): Type = macro EnumMacros.ValCustomImpl // scalastyle:off method.name - protected def do_Value(names: Seq[String]): Type = { + protected def do_Value(name: String): Type = { val result = new Type // We have to use UnknownWidth here, because we don't actually know what the final width will be result.bindToLiteral(id, UnknownWidth()) - val result_name = names.find(!enumNames.contains(_)).get - enum_records.append(EnumRecord(result, result_name)) + enum_records.append(EnumRecord(result, name)) width = (1 max id.bitLength).W id += 1 @@ -264,7 +263,7 @@ abstract class EnumFactory { result } - protected def do_Value(names: Seq[String], id: UInt): Type = { + protected def do_Value(name: String, id: UInt): Type = { // TODO: These throw ExceptionInInitializerError which can be confusing to the user. Get rid of the error, and just // throw an exception if (id.litOption.isEmpty) { @@ -275,7 +274,7 @@ abstract class EnumFactory { } this.id = id.litValue() - do_Value(names) + do_Value(name) } def apply(): Type = new Type @@ -308,31 +307,30 @@ abstract class EnumFactory { private[chisel3] object EnumMacros { def ValImpl(c: Context) : c.Tree = { // scalastyle:off method.name import c.universe._ - val names = getNames(c) - q"""this.do_Value(Seq(..$names))""" - } - def ValCustomImpl(c: Context)(id: c.Expr[UInt]): c.universe.Tree = { // scalastyle:off method.name - import c.universe._ - val names = getNames(c) - q"""this.do_Value(Seq(..$names), $id)""" + // Much thanks to michael_s for this solution: + // stackoverflow.com/questions/18450203/retrieve-the-name-of-the-value-a-scala-macro-invocation-will-be-assigned-to + val term = c.internal.enclosingOwner + val name = term.name.decodedName.toString.trim + + if (name.contains(" ")) { + c.abort(c.enclosingPosition, "Value cannot be called without assigning to an enum") + } + + q"""this.do_Value($name)""" } - // Much thanks to Travis Brown for this solution: - // stackoverflow.com/questions/18450203/retrieve-the-name-of-the-value-a-scala-macro-invocation-will-be-assigned-to - def getNames(c: Context): Seq[String] = { + def ValCustomImpl(c: Context)(id: c.Expr[UInt]): c.universe.Tree = { // scalastyle:off method.name import c.universe._ - val names = c.enclosingClass.collect { - case ValDef(_, name, _, rhs) - if rhs.pos == c.macroApplication.pos => name.decodedName.toString - } + val term = c.internal.enclosingOwner + val name = term.name.decodedName.toString.trim - if (names.isEmpty) { + if (name.contains(" ")) { c.abort(c.enclosingPosition, "Value cannot be called without assigning to an enum") } - names + q"""this.do_Value($name, $id)""" } } diff --git a/src/test/scala/chiselTests/StrongEnum.scala b/src/test/scala/chiselTests/StrongEnum.scala index 5e7ca2e1..40fcfbed 100644 --- a/src/test/scala/chiselTests/StrongEnum.scala +++ b/src/test/scala/chiselTests/StrongEnum.scala @@ -5,6 +5,7 @@ package chiselTests import chisel3._ import chisel3.experimental.ChiselEnum import chisel3.internal.firrtl.UnknownWidth +import chisel3.internal.naming.chiselName import chisel3.util._ import chisel3.testers.BasicTester import org.scalatest.{Assertion, FreeSpec, Matchers} @@ -378,15 +379,83 @@ class StrongEnumSpec extends ChiselFlatSpec { class StrongEnumAnnotator extends Module { import EnumExample._ + object LocalEnum extends ChiselEnum { + val le0, le1 = Value + val le2 = Value + val le100 = Value(100.U) + } + + val io = IO(new Bundle{ + val in = Input(EnumExample()) + val out = Output(EnumExample()) + val other = Output(OtherEnum()) + val local = Output(LocalEnum()) + }) + + class Bund extends Bundle { + val field = EnumExample() + val other = OtherEnum() + val local = LocalEnum() + 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 + io.local := LocalEnum.le0 + 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) +} + +@chiselName +class StrongEnumAnnotatorWithChiselName extends Module { + import EnumExample._ + + object LocalEnum extends ChiselEnum { + val le0, le1 = Value + val le2 = Value + val le100 = Value(100.U) + } + val io = IO(new Bundle{ val in = Input(EnumExample()) val out = Output(EnumExample()) val other = Output(OtherEnum()) + val local = Output(LocalEnum()) }) class Bund extends Bundle { val field = EnumExample() val other = OtherEnum() + val local = LocalEnum() val vec = Vec(5, EnumExample()) val inner_bundle1 = new Bundle { val x = UInt(4.W) @@ -412,6 +481,7 @@ class StrongEnumAnnotator extends Module { io.out := e101 io.other := OtherEnum.otherEnum + io.local := LocalEnum.le0 simple := e100 bund := DontCare vec_of_bundles := DontCare @@ -431,6 +501,7 @@ class StrongEnumAnnotationSpec extends FreeSpec with Matchers { val enumExampleName = "EnumExample" val otherEnumName = "OtherEnum" + val localEnumName = "LocalEnum" case class CorrectDefAnno(typeName: String, definition: Map[String, BigInt]) case class CorrectCompAnno(targetName: String, typeName: String) @@ -438,16 +509,19 @@ class StrongEnumAnnotationSpec extends FreeSpec with Matchers { val correctDefAnnos = Seq( CorrectDefAnno(otherEnumName, Map("otherEnum" -> 0)), - CorrectDefAnno(enumExampleName, Map("e0" -> 0, "e1" -> 1, "e2" -> 2, "e100" -> 100, "e101" -> 101)) + CorrectDefAnno(enumExampleName, Map("e0" -> 0, "e1" -> 1, "e2" -> 2, "e100" -> 100, "e101" -> 101)), + CorrectDefAnno(localEnumName, Map("le0" -> 0, "le1" -> 1, "le2" -> 2, "le100" -> 100)) ) val correctCompAnnos = Seq( CorrectCompAnno("io.other", otherEnumName), + CorrectCompAnno("io.local", localEnumName), CorrectCompAnno("io.out", enumExampleName), CorrectCompAnno("io.in", enumExampleName), CorrectCompAnno("simple", enumExampleName), CorrectCompAnno("bund.field", enumExampleName), CorrectCompAnno("bund.other", otherEnumName), + CorrectCompAnno("bund.local", localEnumName), CorrectCompAnno("bund.inner_bundle1.e", enumExampleName) ) @@ -456,6 +530,7 @@ class StrongEnumAnnotationSpec extends FreeSpec with Matchers { 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("vec_of_bundles", localEnumName, Set(Seq("local"))), CorrectVecAnno("bund.vec", enumExampleName, Set()), CorrectVecAnno("bund.inner_bundle1.v", enumExampleName, Set()) ) @@ -482,7 +557,8 @@ class StrongEnumAnnotationSpec extends FreeSpec with Matchers { def isCorrect(anno: EnumDefAnnotation, correct: CorrectDefAnno): Boolean = { (anno.typeName == correct.typeName || - anno.typeName.endsWith("." + correct.typeName)) && + anno.typeName.endsWith("." + correct.typeName) || + anno.typeName.endsWith("$" + correct.typeName)) && anno.definition == correct.definition } @@ -491,7 +567,8 @@ class StrongEnumAnnotationSpec extends FreeSpec with Matchers { case ComponentName(name, _) => name == correct.targetName case _ => throw new Exception("Unknown target type in EnumComponentAnnotation") }) && - (anno.enumTypeName == correct.typeName || anno.enumTypeName.endsWith("." + correct.typeName)) + (anno.enumTypeName == correct.typeName || anno.enumTypeName.endsWith("." + correct.typeName) || + anno.enumTypeName.endsWith("$" + correct.typeName)) } def isCorrect(anno: EnumVecAnnotation, correct: CorrectVecAnno): Boolean = { @@ -499,7 +576,8 @@ class StrongEnumAnnotationSpec extends FreeSpec with Matchers { 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.typeName == correct.typeName || anno.typeName.endsWith("." + correct.typeName) || + anno.typeName.endsWith("$" + correct.typeName)) && anno.fields.map(_.toSeq).toSet == correct.fields } @@ -516,8 +594,8 @@ class StrongEnumAnnotationSpec extends FreeSpec with Matchers { 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 { + def test(strongEnumAnnotatorGen: () => Module) { + Driver.execute(Array("--target-dir", "test_run_dir"), strongEnumAnnotatorGen) match { case ChiselExecutionSuccess(Some(circuit), emitted, _) => val annos = circuit.annotations.map(_.toFirrtl) @@ -537,8 +615,7 @@ class StrongEnumAnnotationSpec extends FreeSpec with Matchers { } "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() + test(() => new StrongEnumAnnotator) + test(() => new StrongEnumAnnotatorWithChiselName) } } |
