summaryrefslogtreecommitdiff
path: root/chiselFrontend/src
diff options
context:
space:
mode:
authorHasan Genc2019-03-22 09:39:53 -0700
committeredwardcwang2019-03-22 09:39:53 -0700
commit80aabc03ef2420e817bcbac34c78ec25227d9fbb (patch)
tree74164e690a2b2926006d6d874fbe27d3de4a48ac /chiselFrontend/src
parent5574131876d8bbe73cfcd3b5ae8a1317b60142c0 (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/src')
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Data.scala2
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/StrongEnum.scala104
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) {