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

New enhanced API for specifying Chisel to Firrtl Annotations #2628

Merged
merged 8 commits into from
Jul 13, 2022
Merged
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
11 changes: 11 additions & 0 deletions core/src/main/scala/chisel3/Annotation.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ trait ChiselAnnotation {
def toFirrtl: Annotation
}

/** Enhanced interface for Annotations in Chisel
*
* Defines a conversion to corresponding FIRRTL Annotation(s)
*/
trait ChiselMultiAnnotation {
def toFirrtl: Seq[Annotation]
}

/** Mixin for [[ChiselAnnotation]] that instantiates an associated FIRRTL Transform when this Annotation is present
* during a run of
* [[Driver$.execute(args:Array[String],dut:()=>chisel3\.RawModule)* Driver.execute]].
Expand All @@ -34,6 +42,9 @@ object annotate {
def apply(anno: ChiselAnnotation): Unit = {
Builder.annotations += anno
}
girishpai marked this conversation as resolved.
Show resolved Hide resolved
def apply(annos: ChiselMultiAnnotation): Unit = {
Builder.newAnnotations += annos
}
}

/** Marks that a module to be ignored in Dedup Transform in Firrtl pass
Expand Down
13 changes: 9 additions & 4 deletions core/src/main/scala/chisel3/internal/Builder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ private[chisel3] class DynamicContext(

val components = ArrayBuffer[Component]()
val annotations = ArrayBuffer[ChiselAnnotation]()
val newAnnotations = ArrayBuffer[ChiselMultiAnnotation]()
var currentModule: Option[BaseModule] = None

/** Contains a mapping from a elaborated module to their aspect
Expand Down Expand Up @@ -423,9 +424,13 @@ private[chisel3] object Builder extends LazyLogging {

def idGen: IdGen = chiselContext.get.idGen

def globalNamespace: Namespace = dynamicContext.globalNamespace
def components: ArrayBuffer[Component] = dynamicContext.components
def annotations: ArrayBuffer[ChiselAnnotation] = dynamicContext.annotations
def globalNamespace: Namespace = dynamicContext.globalNamespace
def components: ArrayBuffer[Component] = dynamicContext.components
def annotations: ArrayBuffer[ChiselAnnotation] = dynamicContext.annotations

// 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 importDefinitionMap: Map[String, String] = dynamicContext.importDefinitionMap
Expand Down Expand Up @@ -725,7 +730,7 @@ private[chisel3] object Builder extends LazyLogging {
errors.checkpoint(logger)
logger.info("Done elaborating.")

(Circuit(components.last.name, components.toSeq, annotations.toSeq, makeViewRenameMap), mod)
(Circuit(components.last.name, components.toSeq, annotations.toSeq, makeViewRenameMap, newAnnotations.toSeq), mod)
}
}
initializeSingletons()
Expand Down
37 changes: 35 additions & 2 deletions core/src/main/scala/chisel3/internal/firrtl/IR.scala
Original file line number Diff line number Diff line change
Expand Up @@ -861,7 +861,40 @@ case class DefBlackBox(
params: Map[String, Param])
extends Component

case class Circuit(name: String, components: Seq[Component], annotations: Seq[ChiselAnnotation], renames: RenameMap) {
def firrtlAnnotations: Iterable[Annotation] = annotations.flatMap(_.toFirrtl.update(renames))
case class Circuit(
girishpai marked this conversation as resolved.
Show resolved Hide resolved
name: String,
components: Seq[Component],
@deprecated("Do not use annotations val of Circuit directly - use firrtlAnnotations instead. Will be removed in a future release",
"Chisel 3.5")
annotations: Seq[ChiselAnnotation],
girishpai marked this conversation as resolved.
Show resolved Hide resolved
renames: RenameMap,
@deprecated("Do not use newAnnotations val of Circuit directly - use firrtlAnnotations instead. Will be removed in a future release",
"Chisel 3.5")

newAnnotations: Seq[ChiselMultiAnnotation]) {

def this(name: String, components: Seq[Component], annotations: Seq[ChiselAnnotation], renames: RenameMap) =
this(name, components, annotations, renames, Seq.empty)

def firrtlAnnotations: Iterable[Annotation] =
girishpai marked this conversation as resolved.
Show resolved Hide resolved
annotations.flatMap(_.toFirrtl.update(renames)) ++ newAnnotations.flatMap(
_.toFirrtl.flatMap(_.update(renames))
)

def copy(
name: String = name,
components: Seq[Component] = components,
annotations: Seq[ChiselAnnotation] = annotations,
renames: RenameMap = renames
) = Circuit(name, components, annotations, renames, newAnnotations)

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

def apply(name: String, components: Seq[Component], annotations: Seq[ChiselAnnotation], renames: RenameMap): Circuit =
new Circuit(name, components, annotations, renames)
}
72 changes: 72 additions & 0 deletions src/test/scala/chiselTests/NewAnnotationsSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package chiselTests
import chisel3._
import chisel3.experimental.{annotate, ChiselMultiAnnotation}
import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
import firrtl.stage.FirrtlCircuitAnnotation
import org.scalatest.freespec.AnyFreeSpec
import org.scalatest.matchers.should.Matchers
import firrtl.transforms.NoDedupAnnotation
import firrtl.transforms.DontTouchAnnotation

class NewAnnotationsSpec extends AnyFreeSpec with Matchers {

class MuchUsedModule extends Module {
val io = IO(new Bundle {
val in = Input(UInt(16.W))
val out = Output(UInt(16.W))
})
io.out := io.in +% 1.U
}

class UsesMuchUsedModule extends Module {
val io = IO(new Bundle {
val in = Input(UInt(16.W))
val out = Output(UInt(16.W))
})

val mod0 = Module(new MuchUsedModule)
val mod1 = Module(new MuchUsedModule)
val mod2 = Module(new MuchUsedModule)
val mod3 = Module(new MuchUsedModule)

mod0.io.in := io.in
mod1.io.in := mod0.io.out
mod2.io.in := mod1.io.out
mod3.io.in := mod2.io.out
io.out := mod3.io.out

// Give two annotations as single element of the seq - ensures previous API works by wrapping into a seq.
annotate(new ChiselMultiAnnotation { def toFirrtl = Seq(new NoDedupAnnotation(mod2.toNamed)) })
annotate(new ChiselMultiAnnotation { def toFirrtl = Seq(new NoDedupAnnotation(mod3.toNamed)) })

// Pass multiple annotations in the same seq - should get emitted out correctly.
annotate(new ChiselMultiAnnotation {
def toFirrtl =
Seq(new DontTouchAnnotation(mod1.io.in.toNamed), new DontTouchAnnotation(mod1.io.out.toNamed))
})
}

val stage = new ChiselStage
"Ensure all annotations continue to be passed / digested correctly with the new API" - {
"NoDedup and DontTouch work as expected" in {
girishpai marked this conversation as resolved.
Show resolved Hide resolved
val dutAnnos = stage
.execute(
Array("-X", "low", "--target-dir", "test_run_dir"),
Seq(ChiselGeneratorAnnotation(() => new UsesMuchUsedModule))
)

val dontTouchAnnos = dutAnnos.collect { case DontTouchAnnotation(target) => target.serialize }
val noDedupAnnos = dutAnnos.collect { case NoDedupAnnotation(target) => target.serialize }
require(dontTouchAnnos.size == 2, s"Exactly two DontTouch Annotations expected but got $dontTouchAnnos ")
require(noDedupAnnos.size == 2, s"Exactly two NoDedup Annotations expected but got $noDedupAnnos ")
val dontTouchAnnosCombined = dontTouchAnnos.mkString(",")
val noDedupAnnosCombined = noDedupAnnos.mkString(",")

noDedupAnnosCombined should include("~UsesMuchUsedModule|MuchUsedModule_2")
noDedupAnnosCombined should include("~UsesMuchUsedModule|MuchUsedModule_3")
dontTouchAnnosCombined should include("~UsesMuchUsedModule|UsesMuchUsedModule/mod1:MuchUsedModule>io_out")
dontTouchAnnosCombined should include("~UsesMuchUsedModule|UsesMuchUsedModule/mod1:MuchUsedModule>io_in")

}
}
}