diff options
| -rw-r--r-- | core/src/main/scala/chisel3/Annotation.scala | 11 | ||||
| -rw-r--r-- | core/src/main/scala/chisel3/internal/Builder.scala | 13 | ||||
| -rw-r--r-- | core/src/main/scala/chisel3/internal/firrtl/IR.scala | 37 | ||||
| -rw-r--r-- | src/test/scala/chiselTests/NewAnnotationsSpec.scala | 72 |
4 files changed, 127 insertions, 6 deletions
diff --git a/core/src/main/scala/chisel3/Annotation.scala b/core/src/main/scala/chisel3/Annotation.scala index e08557eb..c350fb30 100644 --- a/core/src/main/scala/chisel3/Annotation.scala +++ b/core/src/main/scala/chisel3/Annotation.scala @@ -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]]. @@ -34,6 +42,9 @@ object annotate { def apply(anno: ChiselAnnotation): Unit = { Builder.annotations += anno } + def apply(annos: ChiselMultiAnnotation): Unit = { + Builder.newAnnotations += annos + } } /** Marks that a module to be ignored in Dedup Transform in Firrtl pass diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala index 35dd01ab..61f94f8f 100644 --- a/core/src/main/scala/chisel3/internal/Builder.scala +++ b/core/src/main/scala/chisel3/internal/Builder.scala @@ -404,6 +404,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 @@ -466,9 +467,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 @@ -770,7 +775,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() diff --git a/core/src/main/scala/chisel3/internal/firrtl/IR.scala b/core/src/main/scala/chisel3/internal/firrtl/IR.scala index 9327c29e..dc9ab027 100644 --- a/core/src/main/scala/chisel3/internal/firrtl/IR.scala +++ b/core/src/main/scala/chisel3/internal/firrtl/IR.scala @@ -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( + 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], + 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] = + 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) } diff --git a/src/test/scala/chiselTests/NewAnnotationsSpec.scala b/src/test/scala/chiselTests/NewAnnotationsSpec.scala new file mode 100644 index 00000000..38e1c1d9 --- /dev/null +++ b/src/test/scala/chiselTests/NewAnnotationsSpec.scala @@ -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 { + 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") + + } + } +} |
