Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add safer Chisel annotation API, deprecate old ones #4643

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 38 additions & 7 deletions core/src/main/scala/chisel3/Annotation.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package chisel3.experimental

import scala.language.existentials
import scala.annotation.nowarn
import chisel3.internal.Builder
import chisel3.{Data, InstanceId, RawModule}
import firrtl.annotations._
Expand All @@ -13,6 +14,10 @@ import firrtl.transforms.{DedupGroupAnnotation, NoDedupAnnotation}
*
* Defines a conversion to a corresponding FIRRTL Annotation
*/
@deprecated(
"Avoid custom annotations. If you must use annotations, new annotate.apply method that takes Data",
"Chisel 7.0"
)
trait ChiselAnnotation {

/** Conversion to FIRRTL Annotation */
Expand All @@ -23,16 +28,42 @@ trait ChiselAnnotation {
*
* Defines a conversion to corresponding FIRRTL Annotation(s)
*/
@deprecated(
"Avoid custom annotations. If you must use annotations, new annotate.apply method that takes Data",
"Chisel 7.0"
)
trait ChiselMultiAnnotation {
def toFirrtl: Seq[Annotation]
}

@nowarn("msg=Avoid custom annotations")
object annotate {
def apply(anno: ChiselAnnotation): Unit = {
Builder.annotations += anno
}
def apply(annos: ChiselMultiAnnotation): Unit = {
Builder.newAnnotations += annos
@deprecated(
"Avoid custom annotations. If you must use annotations, new annotate.apply method that takes Data",
"Chisel 7.0"
)
def apply(anno: ChiselAnnotation): Unit = apply()(Seq(anno.toFirrtl))

@deprecated(
"Avoid custom annotations. If you must use annotations, new annotate.apply method that takes Data",
"Chisel 7.0"
)
def apply(annos: ChiselMultiAnnotation): Unit = apply()(annos.toFirrtl)

/** Create annotations.
*
* Avoid this API if possible.
*
* Anything being annotated must be passed as arguments so that Chisel can do safety checks.
* The caller is still responsible for calling .toTarget on those arguments in mkAnnos.
*/
def apply(targets: InstanceId*)(mkAnnos: => Seq[Annotation]): Unit = {
targets.foreach {
case d: Data => requireIsAnnotatable(d, "Data marked with annotation")
case _ => ()
}
// TODO record views that need to be renamed
Builder.annotations += (() => mkAnnos)
}
Comment on lines +53 to 67
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to do this which directly passes the targets to the annotation construction function directly?

For this to work, an Annotation (or a subclass of) would need to have a constructor that can build it from an InstanceId (or a Data).

I'm primarily worried about there being no check of the connection between the targets and the mkAnnos function as a user could put in incorrect targets or ignore them entirely to get the old, legacy behavior.

Can you think of a way to untangle this?

}

Expand Down Expand Up @@ -76,7 +107,7 @@ object doNotDedup {
* @return Unmodified signal `module`
*/
def apply[T <: RawModule](module: T): Unit = {
annotate(new ChiselAnnotation { def toFirrtl: NoDedupAnnotation = NoDedupAnnotation(module.toNamed) })
annotate(module)(Seq(NoDedupAnnotation(module.toNamed)))
}
}

Expand All @@ -89,6 +120,6 @@ object dedupGroup {
* @return Unmodified signal `module`
*/
def apply[T <: BaseModule](module: T, group: String): Unit = {
annotate(new ChiselAnnotation { def toFirrtl: DedupGroupAnnotation = DedupGroupAnnotation(module.toTarget, group) })
annotate(module)(Seq(DedupGroupAnnotation(module.toTarget, group)))
}
}
7 changes: 7 additions & 0 deletions core/src/main/scala/chisel3/ChiselEnumImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package chisel3

import scala.language.existentials
import scala.annotation.nowarn
import scala.collection.mutable
import chisel3.experimental.{annotate, requireIsHardware, ChiselAnnotation, SourceInfo, UnlocatableSourceInfo}
import chisel3.internal.Builder.pushOp
Expand All @@ -13,6 +14,8 @@ import chisel3.internal.binding.{Binding, ChildBinding, ConstrainedBinding}

import chisel3.experimental.EnumAnnotations._

// Rather than refactoring the annotation work here, we should just remove ChiselEnum annotations
@nowarn("msg=Avoid custom annotations")
private[chisel3] abstract class EnumTypeImpl(private[chisel3] val factory: ChiselEnum, selfAnnotating: Boolean = true)
extends Element { self: EnumType =>

Expand Down Expand Up @@ -231,10 +234,14 @@ private[chisel3] abstract class EnumTypeImpl(private[chisel3] val factory: Chise
}
}

// Rather than refactoring the annotation work here, we should just remove ChiselEnum annotations
@nowarn("msg=Avoid custom annotations")
private[chisel3] object ChiselEnumImpl {
private[chisel3] case object CacheKey extends BuilderContextCache.Key[mutable.HashSet[ChiselAnnotation]]
}

// Rather than refactoring the annotation work here, we should just remove ChiselEnum annotations
@nowarn("msg=Avoid custom annotations")
private[chisel3] trait ChiselEnumImpl { self: ChiselEnum =>
class Type extends EnumType(this)
object Type {
Expand Down
5 changes: 1 addition & 4 deletions core/src/main/scala/chisel3/ModuleImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1018,10 +1018,7 @@ private object ModulePrefixAnnotation {
def annotate[T <: HasId](target: T): Unit = {
val prefix = Builder.getModulePrefix
if (prefix != "") {
val annotation: ChiselAnnotation = new ChiselAnnotation {
def toFirrtl: Annotation = ModulePrefixAnnotation(target.toTarget, prefix)
}
chisel3.experimental.annotate(annotation)
chisel3.experimental.annotate(target)(Seq(ModulePrefixAnnotation(target.toTarget, prefix)))
}
}
}
3 changes: 1 addition & 2 deletions core/src/main/scala/chisel3/dontTouch.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ object dontTouch {
case d if DataMirror.hasProbeTypeModifier(d) => ()
case _: Property[_] => ()
case agg: Aggregate => agg.getElements.foreach(dontTouch.apply)
case _: Element =>
annotate(new ChiselAnnotation { def toFirrtl: DontTouchAnnotation = DontTouchAnnotation(data.toNamed) })
case _: Element => annotate(data)(Seq(DontTouchAnnotation(data.toNamed)))
case _ => throw new ChiselException("Non-hardware dontTouch")
}
data
Expand Down
15 changes: 15 additions & 0 deletions core/src/main/scala/chisel3/experimental/EnumAnnotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

package chisel3.experimental

import scala.annotation.nowarn
import chisel3._
import firrtl.annotations._

// Rather than refactoring the annotation work here, we should just remove ChiselEnum annotations
@nowarn("msg=Avoid custom annotations")
object EnumAnnotations {

/** An annotation for strong enum instances that are ''not'' inside of Vecs
Expand All @@ -16,6 +19,10 @@ object EnumAnnotations {
def duplicate(n: Named): EnumComponentAnnotation = this.copy(target = n)
}

@deprecated(
"Avoid custom annotations. If you must use annotations, new annotate.apply method that takes Data",
"Chisel 7.0"
Comment on lines +23 to +24
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong deprecation message, just deprecate the annotation.

)
case class EnumComponentChiselAnnotation(target: InstanceId, enumTypeName: String) extends ChiselAnnotation {
def toFirrtl: EnumComponentAnnotation = EnumComponentAnnotation(target.toNamed, enumTypeName)
}
Expand Down Expand Up @@ -45,6 +52,10 @@ object EnumAnnotations {
def duplicate(n: Named): EnumVecAnnotation = this.copy(target = n)
}

@deprecated(
"Avoid custom annotations. If you must use annotations, new annotate.apply method that takes Data",
"Chisel 7.0"
)
case class EnumVecChiselAnnotation(target: InstanceId, typeName: String, fields: Seq[Seq[String]])
extends ChiselAnnotation {
override def toFirrtl: EnumVecAnnotation = EnumVecAnnotation(target.toNamed, typeName, fields)
Expand All @@ -57,6 +68,10 @@ object EnumAnnotations {
*/
case class EnumDefAnnotation(typeName: String, definition: Map[String, BigInt]) extends NoTargetAnnotation

@deprecated(
"Avoid custom annotations. If you must use annotations, new annotate.apply method that takes Data",
"Chisel 7.0"
)
case class EnumDefChiselAnnotation(typeName: String, definition: Map[String, BigInt]) extends ChiselAnnotation {
override def toFirrtl: Annotation = EnumDefAnnotation(typeName, definition)
}
Expand Down
8 changes: 2 additions & 6 deletions core/src/main/scala/chisel3/experimental/Trace.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ object Trace {

/** Trace a Instance name. */
def traceName(x: RawModule): Unit = {
annotate(new ChiselAnnotation {
def toFirrtl: Annotation = TraceAnnotation(x.toAbsoluteTarget, x.toAbsoluteTarget)
})
annotate(x)(Seq(TraceAnnotation(x.toAbsoluteTarget, x.toAbsoluteTarget)))
}

/** Trace a Data name. This does NOT add "don't touch" semantics to the traced data. If you want this behavior, use an explicit [[chisel3.dontTouch]]. */
Expand All @@ -34,9 +32,7 @@ object Trace {
case aggregate: Aggregate =>
aggregate.elementsIterator.foreach(traceName)
case element: Element =>
annotate(new ChiselAnnotation {
def toFirrtl: Annotation = TraceAnnotation(element.toAbsoluteTarget, element.toAbsoluteTarget)
})
annotate(element)(Seq(TraceAnnotation(element.toAbsoluteTarget, element.toAbsoluteTarget)))
}
}

Expand Down
13 changes: 5 additions & 8 deletions core/src/main/scala/chisel3/internal/Builder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import chisel3.internal.Builder.Prefix
import logger.{LazyLogging, LoggerOption}

import scala.collection.mutable
import scala.annotation.tailrec
import scala.annotation.{nowarn, tailrec}
import java.io.File
import scala.util.control.NonFatal
import chisel3.ChiselException
Expand Down Expand Up @@ -476,6 +476,7 @@ private[chisel3] class ChiselContext() {
var modulePrefixStack: List[(String, Boolean)] = Nil
}

@nowarn("msg=Avoid custom annotations")
private[chisel3] class DynamicContext(
val annotationSeq: AnnotationSeq,
val throwOnFirstError: Boolean,
Expand Down Expand Up @@ -541,8 +542,7 @@ private[chisel3] class DynamicContext(
}

val components = ArrayBuffer[Component]()
val annotations = ArrayBuffer[ChiselAnnotation]()
val newAnnotations = ArrayBuffer[ChiselMultiAnnotation]()
val annotations = ArrayBuffer[() => Seq[Annotation]]()
val layers = mutable.LinkedHashSet[layer.Layer]()
val options = mutable.LinkedHashSet[choice.Case]()
var currentModule: Option[BaseModule] = None
Expand Down Expand Up @@ -570,6 +570,7 @@ private[chisel3] class DynamicContext(
var inDefinition: Boolean = false
}

@nowarn("msg=Avoid custom annotations")
private[chisel3] object Builder extends LazyLogging {

// Represents the current state of the prefixes given
Expand Down Expand Up @@ -625,16 +626,13 @@ private[chisel3] object Builder extends LazyLogging {
def components: ArrayBuffer[Component] = dynamicContext.components
def definitions: ArrayBuffer[Definition[_]] = dynamicContext.definitions

def annotations: ArrayBuffer[ChiselAnnotation] = dynamicContext.annotations
def annotations: ArrayBuffer[() => Seq[Annotation]] = dynamicContext.annotations

def layers: mutable.LinkedHashSet[layer.Layer] = dynamicContext.layers
def options: mutable.LinkedHashSet[choice.Case] = dynamicContext.options

def contextCache: BuilderContextCache = dynamicContext.contextCache

// TODO : Unify this with annotations in the future - done this way for backward compatability
def newAnnotations: ArrayBuffer[ChiselMultiAnnotation] = dynamicContext.newAnnotations

def annotationSeq: AnnotationSeq = dynamicContext.annotationSeq
def namingStack: NamingStack = dynamicContext.namingStack
def importedDefinitionMap: Map[String, String] = dynamicContext.importedDefinitionMap
Expand Down Expand Up @@ -1160,7 +1158,6 @@ private[chisel3] object Builder extends LazyLogging {
components.toSeq,
annotations.toSeq,
makeViewRenameMap,
newAnnotations.toSeq,
typeAliases,
layerAdjacencyList(layer.Layer.Root).map(foldLayers).toSeq,
optionDefs
Expand Down
50 changes: 8 additions & 42 deletions core/src/main/scala/chisel3/internal/firrtl/IR.scala
Original file line number Diff line number Diff line change
Expand Up @@ -568,50 +568,16 @@ private[chisel3] object ir {
case class DefClass(id: Class, name: String, ports: Seq[Port], block: Block) extends Component

case class Circuit(
name: String,
components: Seq[Component],
annotations: Seq[ChiselAnnotation],
renames: RenameMap,
newAnnotations: Seq[ChiselMultiAnnotation],
typeAliases: Seq[DefTypeAlias],
layers: Seq[Layer],
options: Seq[DefOption]
name: String,
components: Seq[Component],
annotations: Seq[() => Seq[Annotation]],
renames: RenameMap,
typeAliases: Seq[DefTypeAlias],
layers: Seq[Layer],
options: Seq[DefOption]
) {

def this(
name: String,
components: Seq[Component],
annotations: Seq[ChiselAnnotation],
renames: RenameMap,
typeAliases: Seq[DefTypeAlias],
layers: Seq[Layer],
options: Seq[DefOption]
) =
this(name, components, annotations, renames, Seq.empty, typeAliases, layers, options)

def firrtlAnnotations: Iterable[Annotation] =
annotations.flatMap(_.toFirrtl.update(renames)) ++ newAnnotations.flatMap(
_.toFirrtl.flatMap(_.update(renames))
)
}

object Circuit
extends scala.runtime.AbstractFunction7[String, Seq[Component], Seq[ChiselAnnotation], RenameMap, Seq[
DefTypeAlias
], Seq[Layer], Seq[DefOption], Circuit] {
def unapply(c: Circuit): Option[(String, Seq[Component], Seq[ChiselAnnotation], RenameMap, Seq[DefTypeAlias])] = {
Some((c.name, c.components, c.annotations, c.renames, c.typeAliases))
}

def apply(
name: String,
components: Seq[Component],
annotations: Seq[ChiselAnnotation],
Comment on lines -598 to -609
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of this was left over from previous needs to maintain binary compatibility. These APIs are all package private now so we can just delete them.

renames: RenameMap,
typeAliases: Seq[DefTypeAlias] = Seq.empty,
layers: Seq[Layer] = Seq.empty,
options: Seq[DefOption] = Seq.empty
): Circuit =
new Circuit(name, components, annotations, renames, typeAliases, layers, options)
annotations.flatMap(_().flatMap(_.update(renames)))
}
}
5 changes: 1 addition & 4 deletions src/main/scala/chisel3/util/AttributeAnnotation.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ object addAttribute {
* @param annoString attribute string to add to target.
*/
def apply(target: Data, annoString: String): Unit = {
requireIsAnnotatable(target, "target must be annotatable")
annotate(new ChiselAnnotation {
def toFirrtl = AttributeAnnotation(target.toNamed, annoString)
})
annotate(target)(Seq(AttributeAnnotation(target.toNamed, annoString)))
}
}
15 changes: 3 additions & 12 deletions src/main/scala/chisel3/util/BlackBoxUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,7 @@ trait HasBlackBoxResource extends BlackBox {
* }}}
*/
def addResource(blackBoxResource: String): Unit = {
val anno = new ChiselAnnotation {
def toFirrtl = BlackBoxInlineAnno.fromResource(blackBoxResource, self.toNamed)
}
chisel3.experimental.annotate(anno)
chisel3.experimental.annotate(self)(Seq(BlackBoxInlineAnno.fromResource(blackBoxResource, self.toNamed)))
}
}

Expand All @@ -61,10 +58,7 @@ trait HasBlackBoxInline extends BlackBox {
* @param blackBoxInline The black box contents
*/
def setInline(blackBoxName: String, blackBoxInline: String): Unit = {
val anno = new ChiselAnnotation {
def toFirrtl = BlackBoxInlineAnno(self.toNamed, blackBoxName, blackBoxInline)
}
chisel3.experimental.annotate(anno)
chisel3.experimental.annotate(self)(Seq(BlackBoxInlineAnno(self.toNamed, blackBoxName, blackBoxInline)))
}
}

Expand All @@ -78,9 +72,6 @@ trait HasBlackBoxPath extends BlackBox {
* target directory.
*/
def addPath(blackBoxPath: String): Unit = {
val anno = new ChiselAnnotation {
def toFirrtl = BlackBoxPathAnno(self.toNamed, blackBoxPath)
}
chisel3.experimental.annotate(anno)
chisel3.experimental.annotate(self)(Seq(BlackBoxPathAnno(self.toNamed, blackBoxPath)))
}
}
Loading
Loading