From 4b28789f78efe50ed8fdea06b1267dcd273f5167 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Mon, 22 Apr 2024 18:16:49 -0700 Subject: [PATCH] Add chisel6 stage --- .../src/main/scala/ChipyardAnnotations.scala | 66 +++++++++++++++++ tools/stage/src/main/scala/ChipyardCli.scala | 17 +++++ .../src/main/scala/ChipyardOptions.scala | 40 +++++++++++ .../stage/src/main/scala/ChipyardStage.scala | 71 +++++++++++++++++++ tools/stage/src/main/scala/StageUtils.scala | 32 +++++++++ tools/stage/src/main/scala/package.scala | 24 +++++++ .../main/scala/phases/AddDefaultTests.scala | 53 ++++++++++++++ .../stage/src/main/scala/phases/Checks.scala | 47 ++++++++++++ .../main/scala/phases/GenerateArtefacts.scala | 26 +++++++ .../scala/phases/GenerateFirrtlAnnos.scala | 34 +++++++++ .../phases/GenerateTestSuiteMakefrags.scala | 49 +++++++++++++ .../main/scala/phases/PreElaboration.scala | 43 +++++++++++ .../src/main/scala/phases/PreservesAll.scala | 8 +++ .../scala/phases/TransformAnnotations.scala | 21 ++++++ 14 files changed, 531 insertions(+) create mode 100644 tools/stage/src/main/scala/ChipyardAnnotations.scala create mode 100644 tools/stage/src/main/scala/ChipyardCli.scala create mode 100644 tools/stage/src/main/scala/ChipyardOptions.scala create mode 100644 tools/stage/src/main/scala/ChipyardStage.scala create mode 100644 tools/stage/src/main/scala/StageUtils.scala create mode 100644 tools/stage/src/main/scala/package.scala create mode 100644 tools/stage/src/main/scala/phases/AddDefaultTests.scala create mode 100644 tools/stage/src/main/scala/phases/Checks.scala create mode 100644 tools/stage/src/main/scala/phases/GenerateArtefacts.scala create mode 100644 tools/stage/src/main/scala/phases/GenerateFirrtlAnnos.scala create mode 100644 tools/stage/src/main/scala/phases/GenerateTestSuiteMakefrags.scala create mode 100644 tools/stage/src/main/scala/phases/PreElaboration.scala create mode 100644 tools/stage/src/main/scala/phases/PreservesAll.scala create mode 100644 tools/stage/src/main/scala/phases/TransformAnnotations.scala diff --git a/tools/stage/src/main/scala/ChipyardAnnotations.scala b/tools/stage/src/main/scala/ChipyardAnnotations.scala new file mode 100644 index 00000000..b9c04eb8 --- /dev/null +++ b/tools/stage/src/main/scala/ChipyardAnnotations.scala @@ -0,0 +1,66 @@ +// See LICENSE for license details. +// Based on Rocket Chip's stage implementation + +package chipyard.stage + +import chisel3.experimental.BaseModule +import firrtl.annotations.{Annotation, NoTargetAnnotation} +import firrtl.options.{HasShellOptions, ShellOption, Unserializable} + +trait ChipyardOption extends Unserializable { this: Annotation => } + +/** This hijacks the existing ConfigAnnotation to accept the legacy _-delimited format */ +private[stage] object UnderscoreDelimitedConfigsAnnotation extends HasShellOptions { + override val options = Seq( + new ShellOption[String]( + longOption = "legacy-configs", + toAnnotationSeq = a => { + val split = a.split(':') + assert(split.length == 2, s"'${a}' split by ':' doesn't yield two things") + val packageName = split.head + val configs = split.last.split("_") + Seq(new ConfigsAnnotation(configs map { config => if (config contains ".") s"${config}" else s"${packageName}.${config}" } )) + }, + helpText = "A string of underscore-delimited configs (configs have decreasing precendence from left to right).", + shortOption = Some("LC") + ) + ) +} + +/** Paths to config classes */ +case class ConfigsAnnotation(configNames: Seq[String]) extends NoTargetAnnotation with ChipyardOption +private[stage] object ConfigsAnnotation extends HasShellOptions { + override val options = Seq( + new ShellOption[Seq[String]]( + longOption = "configs", + toAnnotationSeq = a => Seq(ConfigsAnnotation(a)), + helpText = "", + shortOption = Some("C") + ) + ) +} + +case class TopModuleAnnotation(clazz: Class[_ <: Any]) extends NoTargetAnnotation with ChipyardOption +private[stage] object TopModuleAnnotation extends HasShellOptions { + override val options = Seq( + new ShellOption[String]( + longOption = "top-module", + toAnnotationSeq = a => Seq(TopModuleAnnotation(Class.forName(a).asInstanceOf[Class[_ <: BaseModule]])), + helpText = "", + shortOption = Some("T") + ) + ) +} + +/** Optional base name for generated files' filenames */ +case class OutputBaseNameAnnotation(outputBaseName: String) extends NoTargetAnnotation with ChipyardOption +private[stage] object OutputBaseNameAnnotation extends HasShellOptions { + override val options = Seq( + new ShellOption[String]( + longOption = "name", + toAnnotationSeq = a => Seq(OutputBaseNameAnnotation(a)), + helpText = "", + shortOption = Some("n") + ) + ) +} diff --git a/tools/stage/src/main/scala/ChipyardCli.scala b/tools/stage/src/main/scala/ChipyardCli.scala new file mode 100644 index 00000000..d6071ff3 --- /dev/null +++ b/tools/stage/src/main/scala/ChipyardCli.scala @@ -0,0 +1,17 @@ +// See LICENSE for license details. +// Based on Rocket Chip's stage implementation + +package chipyard.stage + +import firrtl.options.Shell + +trait ChipyardCli { this: Shell => + + parser.note("Chipyard Generator Options") + Seq( + TopModuleAnnotation, + ConfigsAnnotation, + OutputBaseNameAnnotation, + UnderscoreDelimitedConfigsAnnotation + ).foreach(_.addOptions(parser)) +} diff --git a/tools/stage/src/main/scala/ChipyardOptions.scala b/tools/stage/src/main/scala/ChipyardOptions.scala new file mode 100644 index 00000000..8d8eb6e3 --- /dev/null +++ b/tools/stage/src/main/scala/ChipyardOptions.scala @@ -0,0 +1,40 @@ +// See LICENSE + +package chipyard.stage + +class ChipyardOptions private[stage] ( + val topModule: Option[Class[_ <: Any]] = None, + val configNames: Option[Seq[String]] = None, + val outputBaseName: Option[String] = None) { + + private[stage] def copy( + topModule: Option[Class[_ <: Any]] = topModule, + configNames: Option[Seq[String]] = configNames, + outputBaseName: Option[String] = outputBaseName, + ): ChipyardOptions = { + + new ChipyardOptions( + topModule=topModule, + configNames=configNames, + outputBaseName=outputBaseName, + ) + } + + lazy val topPackage: Option[String] = topModule match { + case Some(a) => Some(a.getPackage.getName) + case _ => None + } + + lazy val configClass: Option[String] = configNames match { + case Some(names) => + val classNames = names.map{ n => n.split('.').last } + Some(classNames.mkString("_")) + case _ => None + } + + lazy val longName: Option[String] = outputBaseName match { + case Some(name) => Some(name) + case _ => + if (!topPackage.isEmpty && !configClass.isEmpty) Some(s"${topPackage.get}.${configClass.get}") else None + } +} diff --git a/tools/stage/src/main/scala/ChipyardStage.scala b/tools/stage/src/main/scala/ChipyardStage.scala new file mode 100644 index 00000000..371116c3 --- /dev/null +++ b/tools/stage/src/main/scala/ChipyardStage.scala @@ -0,0 +1,71 @@ +// See LICENSE for license details. +// Based on Rocket Chip's stage implementation + +package chipyard.stage + +import circt.stage.{ChiselStage} +import firrtl.options.PhaseManager.PhaseDependency +import firrtl.options.{Shell} +import firrtl.{AnnotationSeq} +import firrtl.options.{Phase, PhaseManager, Shell, Stage, StageError, StageMain, Dependency} + +final class ChipyardChiselStage extends ChiselStage { + override def run(annotations: AnnotationSeq): AnnotationSeq = { + + val pm = new PhaseManager( + targets = Seq( + Dependency[chisel3.stage.phases.Checks], + Dependency[chisel3.stage.phases.AddImplicitOutputFile], + Dependency[chisel3.stage.phases.AddImplicitOutputAnnotationFile], + Dependency[chisel3.stage.phases.MaybeAspectPhase], + Dependency[chisel3.stage.phases.AddSerializationAnnotations], + Dependency[chisel3.stage.phases.Convert], + Dependency[chisel3.stage.phases.AddDedupGroupAnnotations], + Dependency[chisel3.stage.phases.MaybeInjectingPhase], + Dependency[circt.stage.phases.AddImplicitOutputFile], + Dependency[circt.stage.phases.Checks], + Dependency[circt.stage.phases.CIRCT] + ), + currentState = Seq( + Dependency[firrtl.stage.phases.AddDefaults], + Dependency[firrtl.stage.phases.Checks] + ) + ) + pm.transform(annotations) + } +} + +class ChipyardStage extends ChiselStage { + override val shell = new Shell("chipyard") with ChipyardCli with circt.stage.CLI + override def run(annotations: AnnotationSeq): AnnotationSeq = { + + val pm = new PhaseManager( + targets = Seq( + Dependency[chipyard.stage.phases.Checks], + Dependency[chipyard.stage.phases.TransformAnnotations], + Dependency[chipyard.stage.phases.PreElaboration], + Dependency[ChipyardChiselStage], + Dependency[chipyard.stage.phases.GenerateFirrtlAnnos], + Dependency[chipyard.stage.phases.AddDefaultTests], + Dependency[chipyard.stage.phases.GenerateTestSuiteMakefrags], + Dependency[chipyard.stage.phases.GenerateArtefacts], + ), + currentState = Seq( + Dependency[firrtl.stage.phases.AddDefaults], + Dependency[firrtl.stage.phases.Checks] + ) + ) + pm.transform(annotations) + } + // override val targets: Seq[PhaseDependency] = Seq( + // Dependency[chipyard.stage.phases.Checks], + // Dependency[chipyard.stage.phases.TransformAnnotations], + // Dependency[chipyard.stage.phases.PreElaboration], + // Dependency[ChipyardChiselStage], + // Dependency[chipyard.stage.phases.GenerateFirrtlAnnos], + // Dependency[chipyard.stage.phases.AddDefaultTests], + // Dependency[chipyard.stage.phases.GenerateTestSuiteMakefrags], + // Dependency[chipyard.stage.phases.GenerateArtefacts], + // ) + override final def invalidates(a: Phase): Boolean = false +} diff --git a/tools/stage/src/main/scala/StageUtils.scala b/tools/stage/src/main/scala/StageUtils.scala new file mode 100644 index 00000000..5654c20a --- /dev/null +++ b/tools/stage/src/main/scala/StageUtils.scala @@ -0,0 +1,32 @@ +// See LICENSE + +package chipyard.stage + +import java.io.{File, FileWriter} + +import org.chipsalliance.cde.config.{Config, Parameters} +import freechips.rocketchip.util.{BlackBoxedROM, ROMGenerator} + +trait HasChipyardStageUtils { + + def getConfig(fullConfigClassNames: Seq[String]): Config = { + new Config(fullConfigClassNames.foldRight(Parameters.empty) { case (currentName, config) => + val currentConfig = try { + Class.forName(currentName).newInstance.asInstanceOf[Config] + } catch { + case e: java.lang.ClassNotFoundException => + throw new Exception(s"""Unable to find part "$currentName" from "$fullConfigClassNames", did you misspell it or specify the wrong package path?""", e) + } + currentConfig ++ config + }) + } + + def writeOutputFile(targetDir: String, fname: String, contents: String): File = { + val f = new File(targetDir, fname) + val fw = new FileWriter(f) + fw.write(contents) + fw.close + f + } + +} diff --git a/tools/stage/src/main/scala/package.scala b/tools/stage/src/main/scala/package.scala new file mode 100644 index 00000000..5dc89f9c --- /dev/null +++ b/tools/stage/src/main/scala/package.scala @@ -0,0 +1,24 @@ +// See LICENSE + +package chipyard + +import firrtl.AnnotationSeq +import firrtl.options.OptionsView + +package object stage { + + implicit object ChipyardOptionsView extends OptionsView[ChipyardOptions] { + + def view(annotations: AnnotationSeq): ChipyardOptions = annotations + .collect { case a: ChipyardOption => a } + .foldLeft(new ChipyardOptions()){ (c, x) => + x match { + case TopModuleAnnotation(a) => c.copy(topModule = Some(a)) + case ConfigsAnnotation(a) => c.copy(configNames = Some(a)) + case OutputBaseNameAnnotation(a) => c.copy(outputBaseName = Some(a)) + } + } + + } + +} diff --git a/tools/stage/src/main/scala/phases/AddDefaultTests.scala b/tools/stage/src/main/scala/phases/AddDefaultTests.scala new file mode 100644 index 00000000..e0addc40 --- /dev/null +++ b/tools/stage/src/main/scala/phases/AddDefaultTests.scala @@ -0,0 +1,53 @@ +// See LICENSE for license details. +// Based on Rocket Chip's stage implementation + +package chipyard.stage.phases + +import scala.util.Try +import scala.collection.mutable + +import org.chipsalliance.cde.config.Parameters +import chisel3.stage.phases.Elaborate +import firrtl.AnnotationSeq +import firrtl.annotations.{Annotation, NoTargetAnnotation} +import firrtl.options._ +import firrtl.options.Viewer._ +import freechips.rocketchip.system.{RocketTestSuite, TestGeneration} +import freechips.rocketchip.subsystem.{TilesLocated, InSubsystem} +import freechips.rocketchip.tile.XLen + +import chipyard.TestSuiteHelper +import chipyard.TestSuitesKey +import chipyard.stage._ + +/** Annotation that contains a list of [[RocketTestSuite]]s to run */ +case class ChipyardTestSuiteAnnotation(tests: Seq[RocketTestSuite]) extends NoTargetAnnotation with Unserializable + + +class AddDefaultTests extends Phase with PreservesAll with HasChipyardStageUtils { + override val prerequisites = Seq(Dependency[ChipyardChiselStage]) + override val optionalPrerequisiteOf = Seq(Dependency[GenerateTestSuiteMakefrags]) + + private def addTestSuiteAnnotations(implicit p: Parameters): Seq[Annotation] = { + val annotations = mutable.ArrayBuffer[Annotation]() + val suiteHelper = new TestSuiteHelper + // Use Xlen as a proxy for detecting if we are a processor-like target + // The underlying test suites expect this field to be defined + val tileParams = p(TilesLocated(InSubsystem)) map (tp => tp.tileParams) + if (p.lift(XLen).nonEmpty) + // If a custom test suite is set up, use the custom test suite + annotations += CustomMakefragSnippet(p(TestSuitesKey).apply(tileParams, suiteHelper, p)) + + ChipyardTestSuiteAnnotation(suiteHelper.suites.values.toSeq) +: annotations.toSeq + } + + + override def transform(annotations: AnnotationSeq): AnnotationSeq = { + val (testSuiteAnnos, oAnnos) = annotations.partition { + case ChipyardTestSuiteAnnotation(_) => true + case o => false + } + implicit val p = getConfig(view[ChipyardOptions](annotations).configNames.get).toInstance + addTestSuiteAnnotations(p) ++ oAnnos + } +} diff --git a/tools/stage/src/main/scala/phases/Checks.scala b/tools/stage/src/main/scala/phases/Checks.scala new file mode 100644 index 00000000..b7eaae6e --- /dev/null +++ b/tools/stage/src/main/scala/phases/Checks.scala @@ -0,0 +1,47 @@ +// See LICENSE + +package chipyard.stage.phases + +import firrtl.AnnotationSeq +import firrtl.annotations.Annotation +import firrtl.options.{OptionsException, Phase, TargetDirAnnotation} +import chipyard.stage._ + +import scala.collection.mutable + +/** Checks for the correct type and number of command line arguments */ +class Checks extends Phase with PreservesAll { + + override def transform(annotations: AnnotationSeq): AnnotationSeq = { + val targetDir, topModule, configNames, outputBaseName = mutable.ListBuffer[Annotation]() + + annotations.foreach { + case a: TargetDirAnnotation => a +=: targetDir + case a: TopModuleAnnotation => a +=: topModule + case a: ConfigsAnnotation => a +=: configNames + case a: OutputBaseNameAnnotation => a +=: outputBaseName + case _ => + } + + def required(annoList: mutable.ListBuffer[Annotation], option: String): Unit = { + if (annoList.size != 1) { + throw new OptionsException(s"Exactly one $option required") + } + } + + def optional(annoList: mutable.ListBuffer[Annotation], option: String): Unit = { + if (annoList.size > 1) { + throw new OptionsException(s"Too many $option options have been specified") + } + } + + required(targetDir, "target directory") + required(topModule, "top module") + required(configNames, "configs string (','-delimited)") + + optional(outputBaseName, "output base name") + + annotations + } + +} diff --git a/tools/stage/src/main/scala/phases/GenerateArtefacts.scala b/tools/stage/src/main/scala/phases/GenerateArtefacts.scala new file mode 100644 index 00000000..0982ae36 --- /dev/null +++ b/tools/stage/src/main/scala/phases/GenerateArtefacts.scala @@ -0,0 +1,26 @@ +// See LICENSE + +package chipyard.stage.phases + +import firrtl.AnnotationSeq +import firrtl.options.{Dependency, Phase, StageOptions} +import firrtl.options.Viewer.view +import chipyard.stage._ +import freechips.rocketchip.util.{ElaborationArtefacts} + +/** Writes [[ElaborationArtefacts]] into files */ +class GenerateArtefacts extends Phase with PreservesAll with HasChipyardStageUtils { + + override val prerequisites = Seq(Dependency[chipyard.stage.ChipyardChiselStage]) + + override def transform(annotations: AnnotationSeq): AnnotationSeq = { + val targetDir = view[StageOptions](annotations).targetDir + + ElaborationArtefacts.files.foreach { case (extension, contents) => + writeOutputFile(targetDir, s"${view[ChipyardOptions](annotations).longName.get}.${extension}", contents ()) + } + + annotations + } + +} diff --git a/tools/stage/src/main/scala/phases/GenerateFirrtlAnnos.scala b/tools/stage/src/main/scala/phases/GenerateFirrtlAnnos.scala new file mode 100644 index 00000000..ec69aef2 --- /dev/null +++ b/tools/stage/src/main/scala/phases/GenerateFirrtlAnnos.scala @@ -0,0 +1,34 @@ +// See LICENSE + +package chipyard.stage.phases + +import firrtl.AnnotationSeq +import firrtl.annotations.{JsonProtocol} +import firrtl.options.Viewer.view +import firrtl.options._ +import chipyard.stage._ + +/** Writes FIRRTL annotations into a file */ +class GenerateFirrtlAnnos extends Phase with PreservesAll with HasChipyardStageUtils { + + override val prerequisites = Seq(Dependency[chipyard.stage.ChipyardChiselStage]) + + override def transform(annotations: AnnotationSeq): AnnotationSeq = { + val targetDir = view[StageOptions](annotations).targetDir + val fileName = s"${view[ChipyardOptions](annotations).longName.get}.anno.json" + + val annos = annotations.view.flatMap { + // Remove TargetDirAnnotation so that we can pass as argument to FIRRTL + // Remove CustomFileEmission, those are serialized automatically by Stages + case (_: Unserializable | _: TargetDirAnnotation | _: CustomFileEmission) => + None + case a => + Some(a) + } + + writeOutputFile(targetDir, fileName, JsonProtocol.serialize(annos.toSeq)) + + annotations + } + +} diff --git a/tools/stage/src/main/scala/phases/GenerateTestSuiteMakefrags.scala b/tools/stage/src/main/scala/phases/GenerateTestSuiteMakefrags.scala new file mode 100644 index 00000000..18e73121 --- /dev/null +++ b/tools/stage/src/main/scala/phases/GenerateTestSuiteMakefrags.scala @@ -0,0 +1,49 @@ +// See LICENSE for license details. +// Based on Rocket Chip's stage implementation + +package chipyard.stage.phases + +import scala.collection.mutable + +import firrtl.AnnotationSeq +import firrtl.annotations.{Annotation, NoTargetAnnotation} +import firrtl.options.{Phase, StageOptions, Unserializable, Dependency} +import firrtl.options.Viewer.view +import chipyard.stage._ +import freechips.rocketchip.system.TestGeneration + +trait MakefragSnippet { self: Annotation => + def toMakefrag: String +} + +case class CustomMakefragSnippet(val toMakefrag: String) extends NoTargetAnnotation with MakefragSnippet with Unserializable + +/** Generates a make script to run tests in [[RocketTestSuiteAnnotation]]. */ +class GenerateTestSuiteMakefrags extends Phase with HasChipyardStageUtils { + + // Our annotations tend not to be serializable, but are not marked as such. + override val prerequisites = Seq(Dependency[chipyard.stage.phases.GenerateFirrtlAnnos], + Dependency[chipyard.stage.phases.AddDefaultTests]) + + override def transform(annotations: AnnotationSeq): AnnotationSeq = { + val targetDir = view[StageOptions](annotations).targetDir + val fileName = s"${view[ChipyardOptions](annotations).longName.get}.d" + + val makefragBuilder = new mutable.StringBuilder() + val outputAnnotations = annotations.flatMap { + case ChipyardTestSuiteAnnotation(tests) => + // Unfortunately the gen method of TestGeneration is rocketchip package + // private, so we either have to copy code in or use the stateful form + TestGeneration.addSuites(tests) + None + case a: MakefragSnippet => + makefragBuilder :+ ("\n" + a.toMakefrag) + None + case a => Some(a) + } + writeOutputFile(targetDir, fileName, TestGeneration.generateMakeFrag ++ makefragBuilder.toString) + outputAnnotations + } + + override final def invalidates(a: Phase): Boolean = false +} diff --git a/tools/stage/src/main/scala/phases/PreElaboration.scala b/tools/stage/src/main/scala/phases/PreElaboration.scala new file mode 100644 index 00000000..646d54c3 --- /dev/null +++ b/tools/stage/src/main/scala/phases/PreElaboration.scala @@ -0,0 +1,43 @@ +// See LICENSE + +package chipyard.stage.phases + +import chisel3.RawModule +import chisel3.stage.ChiselGeneratorAnnotation +import firrtl.AnnotationSeq +import firrtl.options.Viewer.view +import firrtl.options.{Dependency, Phase, StageOptions} +import org.chipsalliance.cde.config.{Field, Parameters} +import freechips.rocketchip.diplomacy._ +import chipyard.stage._ + +case object TargetDirKey extends Field[String](".") + +/** Constructs a generator function that returns a top module with given config parameters */ +class PreElaboration extends Phase with PreservesAll with HasChipyardStageUtils { + + override val prerequisites = Seq(Dependency[Checks]) + override val optionalPrerequisiteOf = Seq(Dependency[chisel3.stage.phases.Elaborate]) + + override def transform(annotations: AnnotationSeq): AnnotationSeq = { + + val stageOpts = view[StageOptions](annotations) + val rOpts = view[ChipyardOptions](annotations) + val topMod = rOpts.topModule.get + + val config = getConfig(rOpts.configNames.get).alterPartial { + case TargetDirKey => stageOpts.targetDir + } + + val gen = () => + topMod + .getConstructor(classOf[Parameters]) + .newInstance(config) match { + case a: RawModule => a + case a: LazyModule => LazyModule(a).module + } + + ChiselGeneratorAnnotation(gen) +: annotations + } + +} diff --git a/tools/stage/src/main/scala/phases/PreservesAll.scala b/tools/stage/src/main/scala/phases/PreservesAll.scala new file mode 100644 index 00000000..30884be4 --- /dev/null +++ b/tools/stage/src/main/scala/phases/PreservesAll.scala @@ -0,0 +1,8 @@ +package chipyard.stage.phases + +import firrtl.AnnotationSeq +import firrtl.options.{Dependency, DependencyManagerException, Phase, PhaseManager} + +trait PreservesAll { this: Phase => + override def invalidates(phase: Phase) = false +} diff --git a/tools/stage/src/main/scala/phases/TransformAnnotations.scala b/tools/stage/src/main/scala/phases/TransformAnnotations.scala new file mode 100644 index 00000000..71640841 --- /dev/null +++ b/tools/stage/src/main/scala/phases/TransformAnnotations.scala @@ -0,0 +1,21 @@ +// See LICENSE + +package chipyard.stage.phases + +import chisel3.stage.ChiselOutputFileAnnotation +import firrtl.AnnotationSeq +import firrtl.options.Viewer.view +import firrtl.options.{Dependency, Phase} +import chipyard.stage._ + +/** Transforms RocketChipAnnotations into those used by other stages */ +class TransformAnnotations extends Phase with PreservesAll with HasChipyardStageUtils { + + override val prerequisites = Seq(Dependency[Checks]) + override val optionalPrerequisiteOf = Seq(Dependency[chisel3.stage.phases.AddImplicitOutputFile]) + + override def transform(annotations: AnnotationSeq): AnnotationSeq = { + /** Construct output file annotation for emission */ + new ChiselOutputFileAnnotation(view[ChipyardOptions](annotations).longName.get) +: annotations + } +}