diff options
| author | Hasan Genc | 2019-03-22 09:39:53 -0700 |
|---|---|---|
| committer | edwardcwang | 2019-03-22 09:39:53 -0700 |
| commit | 80aabc03ef2420e817bcbac34c78ec25227d9fbb (patch) | |
| tree | 74164e690a2b2926006d6d874fbe27d3de4a48ac /chiselFrontend | |
| parent | 5574131876d8bbe73cfcd3b5ae8a1317b60142c0 (diff) | |
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
Diffstat (limited to 'chiselFrontend')
| -rw-r--r-- | chiselFrontend/src/main/scala/chisel3/core/Data.scala | 2 | ||||
| -rw-r--r-- | chiselFrontend/src/main/scala/chisel3/core/StrongEnum.scala | 104 |
2 files changed, 88 insertions, 18 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala index 64c84c05..7cf005c0 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala @@ -266,7 +266,7 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc { // sc // perform checks in Chisel, where more informative error messages are possible. private var _binding: Option[Binding] = None // Only valid after node is bound (synthesizable), crashes otherwise - protected def binding: Option[Binding] = _binding + protected[core] def binding: Option[Binding] = _binding protected def binding_=(target: Binding) { if (_binding.isDefined) { throw Binding.RebindingException(s"Attempted reassignment of binding to $this") diff --git a/chiselFrontend/src/main/scala/chisel3/core/StrongEnum.scala b/chiselFrontend/src/main/scala/chisel3/core/StrongEnum.scala index f9414901..3439cf16 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/StrongEnum.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/StrongEnum.scala @@ -5,7 +5,6 @@ package chisel3.core import scala.language.experimental.macros import scala.reflect.macros.blackbox.Context import scala.collection.mutable - import chisel3.internal.Builder.pushOp import chisel3.internal.firrtl.PrimOp._ import chisel3.internal.firrtl._ @@ -15,6 +14,11 @@ import firrtl.annotations._ object EnumAnnotations { + /** An annotation for strong enum instances that are ''not'' inside of Vecs + * + * @param target the enum instance being annotated + * @param typeName the name of the enum's type (e.g. ''"mypackage.MyEnum"'') + */ case class EnumComponentAnnotation(target: Named, enumTypeName: String) extends SingleTargetAnnotation[Named] { def duplicate(n: Named): EnumComponentAnnotation = this.copy(target = n) } @@ -23,16 +27,50 @@ object EnumAnnotations { def toFirrtl: EnumComponentAnnotation = EnumComponentAnnotation(target.toNamed, enumTypeName) } - case class EnumDefAnnotation(enumTypeName: String, definition: Map[String, BigInt]) extends NoTargetAnnotation + /** An annotation for Vecs of strong enums. + * + * The ''fields'' parameter deserves special attention, since it may be difficult to understand. Suppose you create a the following Vec: + + * {{{ + * VecInit(new Bundle { + * val e = MyEnum() + * val b = new Bundle { + * val inner_e = MyEnum() + * } + * val v = Vec(3, MyEnum()) + * } + * }}} + * + * Then, the ''fields'' parameter will be: ''Seq(Seq("e"), Seq("b", "inner_e"), Seq("v"))''. Note that for any Vec that doesn't contain Bundles, this field will simply be an empty Seq. + * + * @param target the Vec being annotated + * @param typeName the name of the enum's type (e.g. ''"mypackage.MyEnum"'') + * @param fields a list of all chains of elements leading from the Vec instance to its inner enum fields. + * + */ + case class EnumVecAnnotation(target: Named, typeName: String, fields: Seq[Seq[String]]) extends SingleTargetAnnotation[Named] { + def duplicate(n: Named) = this.copy(target = n) + } + + case class EnumVecChiselAnnotation(target: InstanceId, typeName: String, fields: Seq[Seq[String]]) extends ChiselAnnotation { + override def toFirrtl = EnumVecAnnotation(target.toNamed, typeName, fields) + } + + /** An annotation for enum types (rather than enum ''instances''). + * + * @param typeName the name of the enum's type (e.g. ''"mypackage.MyEnum"'') + * @param definition a map describing which integer values correspond to which enum names + */ + case class EnumDefAnnotation(typeName: String, definition: Map[String, BigInt]) extends NoTargetAnnotation - case class EnumDefChiselAnnotation(enumTypeName: String, definition: Map[String, BigInt]) extends ChiselAnnotation { - override def toFirrtl: Annotation = EnumDefAnnotation(enumTypeName, definition) + case class EnumDefChiselAnnotation(typeName: String, definition: Map[String, BigInt]) extends ChiselAnnotation { + override def toFirrtl: Annotation = EnumDefAnnotation(typeName, definition) } } import EnumAnnotations._ -abstract class EnumType(private val factory: EnumFactory, selfAnnotating: Boolean = false) extends Element { +abstract class EnumType(private val factory: EnumFactory, selfAnnotating: Boolean = true) extends Element { override def toString: String = { val bindingString = litOption match { case Some(value) => factory.nameOfValue(value) match { @@ -119,18 +157,53 @@ abstract class EnumType(private val factory: EnumFactory, selfAnnotating: Boolea lit.bindLitArg(this) } - override def bind(target: Binding, parentDirection: SpecifiedDirection): Unit = { + override private[chisel3] def bind(target: Binding, parentDirection: SpecifiedDirection = SpecifiedDirection.Unspecified): Unit = { super.bind(target, parentDirection) - // If we try to annotate something that is bound to a literal, we get a FIRRTL annotation exception. - // To workaround that, we only annotate enums that are not bound to literals. + // Make sure we only annotate hardware and not literals if (selfAnnotating && litOption.isEmpty) { annotateEnum() } } + // This function conducts a depth-wise search to find all enum-type fields within a vector or bundle (or vector of bundles) + private def enumFields(d: Aggregate): Seq[Seq[String]] = d match { + case v: Vec[_] => v.sample_element match { + case b: Bundle => enumFields (b) + case _ => Seq () + } + case b: Bundle => + b.elements.collect { + case (name, e: EnumType) if this.typeEquivalent(e) => Seq(Seq(name)) + case (name, v: Vec[_]) if this.typeEquivalent(v.sample_element) => Seq(Seq(name)) + case (name, b2: Bundle) => enumFields(b2).map(name +: _) + }.flatten.toSeq + } + + private def outerMostVec(d: Data = this): Option[Vec[_]] = { + val currentVecOpt = d match { + case v: Vec[_] => Some(v) + case _ => None + } + + d.binding match { + case Some(ChildBinding(parent)) => outerMostVec(parent) match { + case outer @ Some(_) => outer + case None => currentVecOpt + } + case _ => currentVecOpt + } + } + private def annotateEnum(): Unit = { - annotate(EnumComponentChiselAnnotation(this, enumTypeName)) + val anno = outerMostVec() match { + case Some(v) => EnumVecChiselAnnotation(v, enumTypeName, enumFields(v)) + case None => EnumComponentChiselAnnotation(this, enumTypeName) + } + + if (!Builder.annotations.contains(anno)) { + annotate(anno) + } if (!Builder.annotations.contains(factory.globalAnnotation)) { annotate(factory.globalAnnotation) @@ -209,19 +282,16 @@ abstract class EnumFactory { def apply(n: UInt)(implicit sourceInfo: SourceInfo, connectionCompileOptions: CompileOptions): Type = { // scalastyle:off line.size.limit if (n.litOption.isDefined) { - val result = enumInstances.find(_.litValue == n.litValue) - - if (result.isEmpty) { - throwException(s"${n.litValue}.U is not a valid value for $enumTypeName") - } else { - result.get + enumInstances.find(_.litValue == n.litValue) match { + case Some(result) => result + case None => throwException(s"${n.litValue} is not a valid value for $enumTypeName") } } else if (!n.isWidthKnown) { throwException(s"Non-literal UInts being cast to $enumTypeName must have a defined width") } else if (n.getWidth > this.getWidth) { throwException(s"The UInt being cast to $enumTypeName is wider than $enumTypeName's width ($getWidth)") } else { - Builder.warning(s"A non-literal UInt is being cast to $enumTypeName. You can check that its value is legal by calling isValid") + Builder.warning(s"Casting non-literal UInt to $enumTypeName. You can check that its value is legal by calling isValid") val glue = Wire(new UnsafeEnum(width)) glue := n @@ -254,7 +324,7 @@ private[core] object EnumMacros { val names = c.enclosingClass.collect { case ValDef(_, name, _, rhs) - if rhs.pos == c.macroApplication.pos => name.decoded + if rhs.pos == c.macroApplication.pos => name.decodedName.toString } if (names.isEmpty) { |
