diff options
23 files changed, 379 insertions, 284 deletions
diff --git a/src/main/scala/firrtl/Driver.scala b/src/main/scala/firrtl/Driver.scala index c8713e09..66e09e86 100644 --- a/src/main/scala/firrtl/Driver.scala +++ b/src/main/scala/firrtl/Driver.scala @@ -18,8 +18,8 @@ import firrtl.transforms._ import firrtl.Utils.throwInternalError import firrtl.stage.{FirrtlExecutionResultView, FirrtlStage} import firrtl.stage.phases.DriverCompatibility -import firrtl.options.{StageUtils, Phase} -import firrtl.options.Viewer +import firrtl.options.{StageUtils, Phase, Viewer} +import firrtl.options.phases.DeletedWrapper /** @@ -216,15 +216,16 @@ object Driver { val annos = optionsManager.firrtlOptions.toAnnotations ++ optionsManager.commonOptions.toAnnotations - val phases: Seq[Phase] = Seq( - new DriverCompatibility.AddImplicitAnnotationFile, - new DriverCompatibility.AddImplicitFirrtlFile, - new DriverCompatibility.AddImplicitOutputFile, - new DriverCompatibility.AddImplicitEmitter, - new FirrtlStage ) + val phases: Seq[Phase] = + Seq( new DriverCompatibility.AddImplicitAnnotationFile, + new DriverCompatibility.AddImplicitFirrtlFile, + new DriverCompatibility.AddImplicitOutputFile, + new DriverCompatibility.AddImplicitEmitter, + new FirrtlStage ) + .map(DeletedWrapper(_)) val annosx = try { - phases.foldLeft(annos)( (a, p) => p.runTransform(a) ) + phases.foldLeft(annos)( (a, p) => p.transform(a) ) } catch { case e: firrtl.options.OptionsException => return FirrtlExecutionFailure(e.message) } diff --git a/src/main/scala/firrtl/Emitter.scala b/src/main/scala/firrtl/Emitter.scala index 44190b39..3bbba289 100644 --- a/src/main/scala/firrtl/Emitter.scala +++ b/src/main/scala/firrtl/Emitter.scala @@ -19,7 +19,7 @@ import firrtl.PrimOps._ import firrtl.WrappedExpression._ import Utils._ import MemPortUtils.{memPortField, memType} -import firrtl.options.{HasScoptOptions, StageUtils, PhaseException} +import firrtl.options.{HasShellOptions, ShellOption, StageUtils, PhaseException} import firrtl.stage.RunFirrtlTransformAnnotation import scopt.OptionParser // Datastructures @@ -34,14 +34,12 @@ sealed trait EmitAnnotation extends NoTargetAnnotation { case class EmitCircuitAnnotation(emitter: Class[_ <: Emitter]) extends EmitAnnotation case class EmitAllModulesAnnotation(emitter: Class[_ <: Emitter]) extends EmitAnnotation -object EmitCircuitAnnotation extends HasScoptOptions { - def addOptions(p: OptionParser[AnnotationSeq]): Unit = p - .opt[String]("emit-circuit") - .abbr("E") - .valueName("<chirrtl|high|middle|low|verilog|mverilog|sverilog>") - .unbounded() - .action{ (x, c) => - val xx = x match { +object EmitCircuitAnnotation extends HasShellOptions { + + val options = Seq( + new ShellOption[String]( + longOption = "emit-circuit", + toAnnotationSeq = (a: String) => a match { case "chirrtl" => Seq(RunFirrtlTransformAnnotation(new ChirrtlEmitter), EmitCircuitAnnotation(classOf[ChirrtlEmitter])) case "high" => Seq(RunFirrtlTransformAnnotation(new HighFirrtlEmitter), @@ -54,20 +52,19 @@ object EmitCircuitAnnotation extends HasScoptOptions { EmitCircuitAnnotation(classOf[VerilogEmitter])) case "sverilog" => Seq(RunFirrtlTransformAnnotation(new SystemVerilogEmitter), EmitCircuitAnnotation(classOf[SystemVerilogEmitter])) - case _ => throw new PhaseException(s"Unknown emitter '$x'! (Did you misspell it?)") - } - xx ++ c } - .text("Run the specified circuit emitter (all modules in one file)") + case _ => throw new PhaseException(s"Unknown emitter '$a'! (Did you misspell it?)") }, + helpText = "Run the specified circuit emitter (all modules in one file)", + shortOption = Some("E"), + helpValueName = Some("<chirrtl|high|middle|low|verilog|mverilog|sverilog>") ) ) + } -object EmitAllModulesAnnotation extends HasScoptOptions { - def addOptions(p: OptionParser[AnnotationSeq]): Unit = p - .opt[String]("emit-modules") - .abbr("e") - .valueName("<none|high|middle|low|verilog|mverilog|sverilog>") - .unbounded() - .action{ (x, c) => - val xx = x match { +object EmitAllModulesAnnotation extends HasShellOptions { + + val options = Seq( + new ShellOption[String]( + longOption = "emit-modules", + toAnnotationSeq = (a: String) => a match { case "chirrtl" => Seq(RunFirrtlTransformAnnotation(new ChirrtlEmitter), EmitAllModulesAnnotation(classOf[ChirrtlEmitter])) case "high" => Seq(RunFirrtlTransformAnnotation(new HighFirrtlEmitter), @@ -80,10 +77,11 @@ object EmitAllModulesAnnotation extends HasScoptOptions { EmitAllModulesAnnotation(classOf[VerilogEmitter])) case "sverilog" => Seq(RunFirrtlTransformAnnotation(new SystemVerilogEmitter), EmitAllModulesAnnotation(classOf[SystemVerilogEmitter])) - case _ => throw new PhaseException(s"Unknown emitter '$x'! (Did you misspell it?)") - } - xx ++ c } - .text("Run the specified module emitter (one file per module)") + case _ => throw new PhaseException(s"Unknown emitter '$a'! (Did you misspell it?)") }, + helpText = "Run the specified module emitter (one file per module)", + shortOption = Some("e"), + helpValueName = Some("<chirrtl|high|middle|low|verilog|mverilog|sverilog>") ) ) + } // ***** Annotations for results of emission ***** diff --git a/src/main/scala/firrtl/options/Phase.scala b/src/main/scala/firrtl/options/Phase.scala index a660d08a..34739053 100644 --- a/src/main/scala/firrtl/options/Phase.scala +++ b/src/main/scala/firrtl/options/Phase.scala @@ -39,22 +39,6 @@ abstract class Phase extends TransformLike[AnnotationSeq] { */ lazy val name: String = this.getClass.getName - /** Perform the transform of [[transform]] on an [[firrtl.AnnotationSeq AnnotationSeq]] and add - * [[firrtl.annotations.DeletedAnnotation DeletedAnnotation]]s for any deleted [[firrtl.annotations.Annotation - * Annotation]]s. - * @param a - */ - final def runTransform(annotations: AnnotationSeq): AnnotationSeq = { - val ax = transform(annotations) - - val (in, out) = (mutable.LinkedHashSet() ++ annotations, mutable.LinkedHashSet() ++ ax) - - (in -- out).map { - case DeletedAnnotation(n, a) => DeletedAnnotation(s"$n+$name", a) - case a => DeletedAnnotation(name, a) - }.toSeq ++ ax - } - } /** A [[TransformLike]] that internally ''translates'' the input type to some other type, transforms the internal type, diff --git a/src/main/scala/firrtl/options/Registration.scala b/src/main/scala/firrtl/options/Registration.scala index a826ec50..c832ec7c 100644 --- a/src/main/scala/firrtl/options/Registration.scala +++ b/src/main/scala/firrtl/options/Registration.scala @@ -4,40 +4,70 @@ package firrtl.options import firrtl.{AnnotationSeq, Transform} -import scopt.OptionParser +import scopt.{OptionDef, OptionParser, Read} + +/** Contains information about a [[Shell]] command line option + * @tparam the type of the command line argument + * @param longOption a long, double-dash option + * @param toAnnotationSeq a function to convert the type into an [[firrtl.AnnotationSeq AnnotationSeq]] + * @param helpText help text + * @param shortOption an optional single-dash option + * @param helpValueName a string to show as a placeholder argument in help text + */ +final class ShellOption[A: Read] ( + val longOption: String, + val toAnnotationSeq: A => AnnotationSeq, + val helpText: String, + val shortOption: Option[String] = None, + val helpValueName: Option[String] = None +) { + + /** Add this specific shell (command line) option to an option parser + * @param p an option parser + */ + final def addOption(p: OptionParser[AnnotationSeq]): Unit = { + val f = Seq( + (p: OptionDef[A, AnnotationSeq]) => p.action( (x, c) => toAnnotationSeq(x).reverse ++ c ), + (p: OptionDef[A, AnnotationSeq]) => p.text(helpText), + (p: OptionDef[A, AnnotationSeq]) => p.unbounded()) ++ + shortOption.map( a => (p: OptionDef[A, AnnotationSeq]) => p.abbr(a) ) ++ + helpValueName.map( a => (p: OptionDef[A, AnnotationSeq]) => p.valueName(a) ) + + f.foldLeft(p.opt[A](longOption))( (a, b) => b(a) ) + } +} /** Indicates that this class/object includes options (but does not add these as a registered class) */ -trait HasScoptOptions { +trait HasShellOptions { - /** This method will be called to add options to an OptionParser ('''OPTIONS SHOULD BE PREPENDED''') - * - * - * '''The ordering of [[firrtl.annotations.Annotation Annotation]] is important and has meaning for parallel - * compilations. For deterministic behavior, you should always prepend any annotations to the [[firrtl.AnnotationSeq - * AnnotationSeq]]. The [[firrtl.AnnotationSeq AnnotationSeq]] will be automatically reversed after a [[Stage]] - * parses it.''' - * + /** A sequence of options provided + */ + def options: Seq[ShellOption[_]] + + /** Add all shell (command line) options to an option parser * @param p an option parser */ - def addOptions(p: OptionParser[AnnotationSeq]): Unit + final def addOptions(p: OptionParser[AnnotationSeq]): Unit = options.foreach(_.addOption(p)) + } -/** A [[Transform]] that includes options that should be exposed at the top level. +/** A [[Transform]] that includes an option that should be exposed at the top level. * * @note To complete registration, include an entry in * src/main/resources/META-INF/services/firrtl.options.RegisteredTransform */ -trait RegisteredTransform extends HasScoptOptions { this: Transform => } +trait RegisteredTransform extends HasShellOptions { this: Transform => } /** A class that includes options that should be exposed as a group at the top level. * * @note To complete registration, include an entry in * src/main/resources/META-INF/services/firrtl.options.RegisteredLibrary */ -trait RegisteredLibrary extends HasScoptOptions { +trait RegisteredLibrary extends HasShellOptions { /** The name of this library. * * This will be used when generating help text. */ def name: String + } diff --git a/src/main/scala/firrtl/options/Shell.scala b/src/main/scala/firrtl/options/Shell.scala index dbc403a5..28c0554a 100644 --- a/src/main/scala/firrtl/options/Shell.scala +++ b/src/main/scala/firrtl/options/Shell.scala @@ -16,10 +16,10 @@ import java.util.ServiceLoader class Shell(val applicationName: String) { /** Command line argument parser (OptionParser) with modifications */ - final val parser = new OptionParser[AnnotationSeq](applicationName) with DuplicateHandling with ExceptOnError + protected val parser = new OptionParser[AnnotationSeq](applicationName) with DuplicateHandling with ExceptOnError /** Contains all discovered [[RegisteredLibrary]] */ - lazy val registeredLibraries: Seq[RegisteredLibrary] = { + final lazy val registeredLibraries: Seq[RegisteredLibrary] = { val libraries = scala.collection.mutable.ArrayBuffer[RegisteredLibrary]() val iter = ServiceLoader.load(classOf[RegisteredLibrary]).iterator() while (iter.hasNext) { @@ -33,7 +33,7 @@ class Shell(val applicationName: String) { } /** Contains all discovered [[RegisteredTransform]] */ - lazy val registeredTransforms: Seq[RegisteredTransform] = { + final lazy val registeredTransforms: Seq[RegisteredTransform] = { val transforms = scala.collection.mutable.ArrayBuffer[RegisteredTransform]() val iter = ServiceLoader.load(classOf[RegisteredTransform]).iterator() if (iter.hasNext) { parser.note("FIRRTL Transform Options") } @@ -61,11 +61,11 @@ class Shell(val applicationName: String) { } parser.note("Shell Options") + ProgramArgsAnnotation.addOptions(parser) Seq( TargetDirAnnotation, - ProgramArgsAnnotation, InputAnnotationFileAnnotation, OutputAnnotationFileAnnotation ) - .map(_.addOptions(parser)) + .foreach(_.addOptions(parser)) parser.opt[Unit]("show-registrations") .action{ (_, c) => @@ -85,5 +85,5 @@ class Shell(val applicationName: String) { ClassLogLevelAnnotation, LogFileAnnotation, LogClassNamesAnnotation ) - .map(_.addOptions(parser)) + .foreach(_.addOptions(parser)) } diff --git a/src/main/scala/firrtl/options/Stage.scala b/src/main/scala/firrtl/options/Stage.scala index 38cc9d42..f2780761 100644 --- a/src/main/scala/firrtl/options/Stage.scala +++ b/src/main/scala/firrtl/options/Stage.scala @@ -31,16 +31,19 @@ abstract class Stage extends Phase { * @throws OptionsException if command line or annotation validation fails */ final def transform(annotations: AnnotationSeq): AnnotationSeq = { - val annotationsx = Seq( new phases.GetIncludes, - new phases.ConvertLegacyAnnotations ) - .foldLeft(annotations)((a, p) => p.runTransform(a)) + val annotationsx = + Seq( new phases.GetIncludes, + new phases.ConvertLegacyAnnotations ) + .map(phases.DeletedWrapper(_)) + .foldLeft(annotations)((a, p) => p.transform(a)) Logger.makeScope(annotationsx) { Seq( new phases.AddDefaults, new phases.Checks, new Phase { def transform(a: AnnotationSeq) = run(a) }, new phases.WriteOutputAnnotations ) - .foldLeft(annotationsx)((a, p) => p.runTransform(a)) + .map(phases.DeletedWrapper(_)) + .foldLeft(annotationsx)((a, p) => p.transform(a)) } } diff --git a/src/main/scala/firrtl/options/StageAnnotations.scala b/src/main/scala/firrtl/options/StageAnnotations.scala index e8a1a288..e35a6afa 100644 --- a/src/main/scala/firrtl/options/StageAnnotations.scala +++ b/src/main/scala/firrtl/options/StageAnnotations.scala @@ -21,13 +21,16 @@ trait Unserializable { this: Annotation => } */ case class TargetDirAnnotation(directory: String = ".") extends NoTargetAnnotation with StageOption -object TargetDirAnnotation extends HasScoptOptions { - def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[String]("target-dir") - .abbr("td") - .valueName("<target-directory>") - .action( (x, c) => TargetDirAnnotation(x) +: c ) - .unbounded() // See [Note 1] - .text(s"Work directory for intermediate files/blackboxes, default is '.' (current directory)") +object TargetDirAnnotation extends HasShellOptions { + + val options = Seq( + new ShellOption[String]( + longOption = "target-dir", + toAnnotationSeq = (a: String) => Seq(TargetDirAnnotation(a)), + helpText = "Work directory (default: '.')", + shortOption = Some("td"), + helpValueName = Some("<directory>") ) ) + } /** Additional arguments @@ -36,7 +39,8 @@ object TargetDirAnnotation extends HasScoptOptions { */ case class ProgramArgsAnnotation(arg: String) extends NoTargetAnnotation with StageOption -object ProgramArgsAnnotation extends HasScoptOptions { +object ProgramArgsAnnotation { + def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.arg[String]("<arg>...") .unbounded() .optional() @@ -51,13 +55,16 @@ object ProgramArgsAnnotation extends HasScoptOptions { */ case class InputAnnotationFileAnnotation(file: String) extends NoTargetAnnotation with StageOption -object InputAnnotationFileAnnotation extends HasScoptOptions { - def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[String]("annotation-file") - .abbr("faf") - .unbounded() - .valueName("<input-anno-file>") - .action( (x, c) => InputAnnotationFileAnnotation(x) +: c ) - .text("Used to specify annotation file") +object InputAnnotationFileAnnotation extends HasShellOptions { + + val options = Seq( + new ShellOption[String]( + longOption = "annotation-file", + toAnnotationSeq = (a: String) => Seq(InputAnnotationFileAnnotation(a)), + helpText = "An input annotation file", + shortOption = Some("faf"), + helpValueName = Some("<file>") ) ) + } /** An explicit output _annotation_ file to write to @@ -66,13 +73,16 @@ object InputAnnotationFileAnnotation extends HasScoptOptions { */ case class OutputAnnotationFileAnnotation(file: String) extends NoTargetAnnotation with StageOption -object OutputAnnotationFileAnnotation extends HasScoptOptions { - def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[String]("output-annotation-file") - .abbr("foaf") - .valueName ("<output-anno-file>") - .action( (x, c) => OutputAnnotationFileAnnotation(x) +: c ) - .unbounded() - .text("use this to set the annotation output file") +object OutputAnnotationFileAnnotation extends HasShellOptions { + + val options = Seq( + new ShellOption[String]( + longOption = "output-annotation-file", + toAnnotationSeq = (a: String) => Seq(OutputAnnotationFileAnnotation(a)), + helpText = "An output annotation file", + shortOption = Some("foaf"), + helpValueName = Some("<file>") ) ) + } /** If this [[firrtl.annotations.Annotation Annotation]] exists in an [[firrtl.AnnotationSeq AnnotationSeq]], then a @@ -80,12 +90,12 @@ object OutputAnnotationFileAnnotation extends HasScoptOptions { * [[firrtl.annotations.DeletedAnnotation DeletedAnnotation]]s when it writes to a file. * - set with '--write-deleted' */ -case object WriteDeletedAnnotation extends NoTargetAnnotation with StageOption with HasScoptOptions { +case object WriteDeletedAnnotation extends NoTargetAnnotation with StageOption with HasShellOptions { - def addOptions(p: OptionParser[AnnotationSeq]): Unit = p - .opt[Unit]("write-deleted") - .unbounded() - .action( (_, c) => WriteDeletedAnnotation +: c ) - .text("Include deleted annotations in the output annotation file") + val options = Seq( + new ShellOption[Unit]( + longOption = "write-deleted", + toAnnotationSeq = (_: Unit) => Seq(WriteDeletedAnnotation), + helpText = "Include deleted annotations in the output annotation file" ) ) } diff --git a/src/main/scala/firrtl/options/phases/DeletedWrapper.scala b/src/main/scala/firrtl/options/phases/DeletedWrapper.scala new file mode 100644 index 00000000..0a959f32 --- /dev/null +++ b/src/main/scala/firrtl/options/phases/DeletedWrapper.scala @@ -0,0 +1,43 @@ +// See LICENSE for license details. + +package firrtl.options.phases + +import firrtl.AnnotationSeq +import firrtl.annotations.DeletedAnnotation +import firrtl.options.{Phase, Translator} + +import scala.collection.mutable + +/** Wrap a [[firrtl.options.Phase Phase]] such that any [[firrtl.annotations.Annotation Annotation]] removed by the + * wrapped [[firrtl.options.Phase Phase]] will be added as [[firrtl.annotations.DeletedAnnotation DeletedAnnotation]]s. + * @param p a [[firrtl.options.Phase Phase]] to wrap + */ +class DeletedWrapper(p: Phase) extends Phase with Translator[AnnotationSeq, (AnnotationSeq, AnnotationSeq)] { + + override lazy val name: String = p.name + + def aToB(a: AnnotationSeq): (AnnotationSeq, AnnotationSeq) = (a, a) + + def bToA(b: (AnnotationSeq, AnnotationSeq)): AnnotationSeq = { + + val (in, out) = (mutable.LinkedHashSet() ++ b._1, mutable.LinkedHashSet() ++ b._2) + + (in -- out).map { + case DeletedAnnotation(n, a) => DeletedAnnotation(s"$n+$name", a) + case a => DeletedAnnotation(name, a) + }.toSeq ++ b._2 + + } + + def internalTransform(b: (AnnotationSeq, AnnotationSeq)): (AnnotationSeq, AnnotationSeq) = (b._1, p.transform(b._2)) + +} + +object DeletedWrapper { + + /** Wrap a [[firrtl.options.Phase Phase]] in a [[DeletedWrapper]] + * @param p a [[firrtl.options.Phase Phase]] to wrap + */ + def apply(p: Phase): DeletedWrapper = new DeletedWrapper(p) + +} diff --git a/src/main/scala/firrtl/passes/Inline.scala b/src/main/scala/firrtl/passes/Inline.scala index dcee0ee2..0806563c 100644 --- a/src/main/scala/firrtl/passes/Inline.scala +++ b/src/main/scala/firrtl/passes/Inline.scala @@ -8,7 +8,7 @@ import firrtl.Mappers._ import firrtl.annotations._ import firrtl.analyses.InstanceGraph import firrtl.stage.RunFirrtlTransformAnnotation -import firrtl.options.RegisteredTransform +import firrtl.options.{RegisteredTransform, ShellOption} import scopt.OptionParser // Datastructures @@ -28,24 +28,22 @@ class InlineInstances extends Transform with RegisteredTransform { def outputForm = LowForm private [firrtl] val inlineDelim: String = "_" - def addOptions(parser: OptionParser[AnnotationSeq]): Unit = parser - .opt[Seq[String]]("inline") - .abbr("fil") - .valueName ("<circuit>[.<module>[.<instance>]][,..],") - .action( (x, c) => { - val newAnnotations = x.map { value => - value.split('.') match { - case Array(circuit) => - InlineAnnotation(CircuitName(circuit)) - case Array(circuit, module) => - InlineAnnotation(ModuleName(module, CircuitName(circuit))) - case Array(circuit, module, inst) => - InlineAnnotation(ComponentName(inst, ModuleName(module, CircuitName(circuit)))) - } - } - c ++ newAnnotations :+ RunFirrtlTransformAnnotation(new InlineInstances) } ) - .text( - """Inline one or more module (comma separated, no spaces) module looks like "MyModule" or "MyModule.myinstance""") + val options = Seq( + new ShellOption[Seq[String]]( + longOption = "inline", + toAnnotationSeq = (a: Seq[String]) => a.map { value => + value.split('.') match { + case Array(circuit) => + InlineAnnotation(CircuitName(circuit)) + case Array(circuit, module) => + InlineAnnotation(ModuleName(module, CircuitName(circuit))) + case Array(circuit, module, inst) => + InlineAnnotation(ComponentName(inst, ModuleName(module, CircuitName(circuit)))) + } + } :+ RunFirrtlTransformAnnotation(new InlineInstances), + helpText = "Inline selected modules", + shortOption = Some("fil"), + helpValueName = Some("<circuit>[.<module>[.<instance>]][,...]") ) ) private def collectAnns(circuit: Circuit, anns: Iterable[Annotation]): (Set[ModuleName], Set[ComponentName]) = anns.foldLeft(Set.empty[ModuleName], Set.empty[ComponentName]) { diff --git a/src/main/scala/firrtl/passes/clocklist/ClockListTransform.scala b/src/main/scala/firrtl/passes/clocklist/ClockListTransform.scala index de9f6c52..f95787bd 100644 --- a/src/main/scala/firrtl/passes/clocklist/ClockListTransform.scala +++ b/src/main/scala/firrtl/passes/clocklist/ClockListTransform.scala @@ -13,7 +13,7 @@ import ClockListUtils._ import Utils._ import memlib.AnalysisUtils._ import memlib._ -import firrtl.options.RegisteredTransform +import firrtl.options.{RegisteredTransform, ShellOption} import scopt.OptionParser import firrtl.stage.RunFirrtlTransformAnnotation @@ -60,14 +60,14 @@ class ClockListTransform extends Transform with RegisteredTransform { def inputForm = LowForm def outputForm = LowForm - def addOptions(parser: OptionParser[AnnotationSeq]): Unit = parser - .opt[String]("list-clocks") - .abbr("clks") - .valueName ("-c:<circuit>:-m:<module>:-o:<filename>") - .action( (x, c) => c ++ Seq(passes.clocklist.ClockListAnnotation.parse(x), - RunFirrtlTransformAnnotation(new ClockListTransform)) ) - .maxOccurs(1) - .text("List which signal drives each clock of every descendent of specified module") + val options = Seq( + new ShellOption[String]( + longOption = "list-clocks", + toAnnotationSeq = (a: String) => Seq( passes.clocklist.ClockListAnnotation.parse(a), + RunFirrtlTransformAnnotation(new ClockListTransform) ), + helpText = "List which signal drives each clock of every descendent of specified modules", + shortOption = Some("clks"), + helpValueName = Some("-c:<circuit>:-m:<module>:-o:<filename>") ) ) def passSeq(top: String, writer: Writer): Seq[Pass] = Seq(new ClockList(top, writer)) diff --git a/src/main/scala/firrtl/passes/memlib/InferReadWrite.scala b/src/main/scala/firrtl/passes/memlib/InferReadWrite.scala index f524d60b..0602e4f1 100644 --- a/src/main/scala/firrtl/passes/memlib/InferReadWrite.scala +++ b/src/main/scala/firrtl/passes/memlib/InferReadWrite.scala @@ -8,7 +8,7 @@ import firrtl.ir._ import firrtl.Mappers._ import firrtl.PrimOps._ import firrtl.Utils.{one, zero, BoolType} -import firrtl.options.HasScoptOptions +import firrtl.options.{HasShellOptions, ShellOption} import MemPortUtils.memPortField import firrtl.passes.memlib.AnalysisUtils.{Connects, getConnects, getOrigin} import WrappedExpression.weq @@ -147,17 +147,16 @@ object InferReadWritePass extends Pass { // Transform input: Middle Firrtl. Called after "HighFirrtlToMidleFirrtl" // To use this transform, circuit name should be annotated with its TransId. -class InferReadWrite extends Transform with SeqTransformBased with HasScoptOptions { +class InferReadWrite extends Transform with SeqTransformBased with HasShellOptions { def inputForm = MidForm def outputForm = MidForm - def addOptions(parser: OptionParser[AnnotationSeq]): Unit = parser - .opt[Unit]("infer-rw") - .abbr("firw") - .valueName ("<circuit>") - .action( (_, c) => Seq(InferReadWriteAnnotation, RunFirrtlTransformAnnotation(new InferReadWrite)) ++ c ) - .maxOccurs(1) - .text("Enable readwrite port inference for the target circuit") + val options = Seq( + new ShellOption[Unit]( + longOption = "infer-rw", + toAnnotationSeq = (_: Unit) => Seq(InferReadWriteAnnotation, RunFirrtlTransformAnnotation(new InferReadWrite)), + helpText = "Enable read/write port inference for memories", + shortOption = Some("firw") ) ) def transforms = Seq( InferReadWritePass, diff --git a/src/main/scala/firrtl/passes/memlib/MemLibOptions.scala b/src/main/scala/firrtl/passes/memlib/MemLibOptions.scala index 2f26e4e5..4076d5d6 100644 --- a/src/main/scala/firrtl/passes/memlib/MemLibOptions.scala +++ b/src/main/scala/firrtl/passes/memlib/MemLibOptions.scala @@ -3,13 +3,14 @@ package firrtl.passes.memlib import firrtl._ -import firrtl.options.RegisteredLibrary +import firrtl.options.{RegisteredLibrary, ShellOption} import scopt.OptionParser class MemLibOptions extends RegisteredLibrary { val name: String = "MemLib Options" - def addOptions(p: OptionParser[AnnotationSeq]): Unit = - Seq( new InferReadWrite, - new ReplSeqMem ) - .map(_.addOptions(p)) + + val options: Seq[ShellOption[_]] = Seq( new InferReadWrite, + new ReplSeqMem ) + .flatMap(_.options) + } diff --git a/src/main/scala/firrtl/passes/memlib/ReplaceMemTransform.scala b/src/main/scala/firrtl/passes/memlib/ReplaceMemTransform.scala index 32d83181..a9d0cc7c 100644 --- a/src/main/scala/firrtl/passes/memlib/ReplaceMemTransform.scala +++ b/src/main/scala/firrtl/passes/memlib/ReplaceMemTransform.scala @@ -6,7 +6,7 @@ package memlib import firrtl._ import firrtl.ir._ import firrtl.annotations._ -import firrtl.options.HasScoptOptions +import firrtl.options.{HasShellOptions, ShellOption} import AnalysisUtils._ import Utils.error import java.io.{File, CharArrayWriter, PrintWriter} @@ -102,18 +102,18 @@ class SimpleTransform(p: Pass, form: CircuitForm) extends Transform { class SimpleMidTransform(p: Pass) extends SimpleTransform(p, MidForm) // SimpleRun instead of PassBased because of the arguments to passSeq -class ReplSeqMem extends Transform with HasScoptOptions { +class ReplSeqMem extends Transform with HasShellOptions { def inputForm = MidForm def outputForm = MidForm - def addOptions(parser: OptionParser[AnnotationSeq]): Unit = parser - .opt[String]("repl-seq-mem") - .abbr("frsq") - .valueName ("-c:<circuit>:-i:<filename>:-o:<filename>") - .action( (x, c) => Seq(passes.memlib.ReplSeqMemAnnotation.parse(x), - RunFirrtlTransformAnnotation(new ReplSeqMem)) ++ c ) - .maxOccurs(1) - .text("Replace sequential memories with blackboxes + configuration file") + val options = Seq( + new ShellOption[String]( + longOption = "repl-seq-mem", + toAnnotationSeq = (a: String) => Seq( passes.memlib.ReplSeqMemAnnotation.parse(a), + RunFirrtlTransformAnnotation(new ReplSeqMem) ), + helpText = "Blackbox and emit a configuration file for each sequential memory", + shortOption = Some("frsq"), + helpValueName = Some("-c:<circuit>:-i:<file>:-o:<file>") ) ) def transforms(inConfigFile: Option[YamlFileReader], outConfigFile: ConfWriter): Seq[Transform] = Seq(new SimpleMidTransform(Legalize), diff --git a/src/main/scala/firrtl/stage/FirrtlAnnotations.scala b/src/main/scala/firrtl/stage/FirrtlAnnotations.scala index 600e825b..ed5415f6 100644 --- a/src/main/scala/firrtl/stage/FirrtlAnnotations.scala +++ b/src/main/scala/firrtl/stage/FirrtlAnnotations.scala @@ -5,7 +5,7 @@ package firrtl.stage import firrtl._ import firrtl.ir.Circuit import firrtl.annotations.{Annotation, NoTargetAnnotation} -import firrtl.options.{HasScoptOptions, OptionsException} +import firrtl.options.{HasShellOptions, OptionsException, ShellOption} import scopt.OptionParser @@ -49,13 +49,16 @@ case class FirrtlFileAnnotation(file: String) extends NoTargetAnnotation with Ci } -object FirrtlFileAnnotation extends HasScoptOptions { - def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[String]("input-file") - .abbr("i") - .valueName ("<firrtl-source>") - .action( (x, c) => FirrtlFileAnnotation(x) +: c ) - .unbounded() - .text("use this to override the default input file name, default is empty") +object FirrtlFileAnnotation extends HasShellOptions { + + val options = Seq( + new ShellOption[String]( + longOption = "input-file", + toAnnotationSeq = a => Seq(FirrtlFileAnnotation(a)), + helpText = "An input FIRRTL file", + shortOption = Some("i"), + helpValueName = Some("<file>") ) ) + } /** An explicit output file the emitter will write to @@ -64,13 +67,16 @@ object FirrtlFileAnnotation extends HasScoptOptions { */ case class OutputFileAnnotation(file: String) extends NoTargetAnnotation with FirrtlOption -object OutputFileAnnotation extends HasScoptOptions { - def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[String]("output-file") - .abbr("o") - .valueName("<output>") - .action( (x, c) => OutputFileAnnotation(x) +: c ) - .unbounded() - .text("use this to override the default output file name, default is empty") +object OutputFileAnnotation extends HasShellOptions { + + val options = Seq( + new ShellOption[String]( + longOption = "output-file", + toAnnotationSeq = a => Seq(OutputFileAnnotation(a)), + helpText = "The output FIRRTL file", + shortOption = Some("o"), + helpValueName = Some("<file>") ) ) + } /** Sets the info mode style @@ -97,12 +103,15 @@ case class InfoModeAnnotation(modeName: String = "use") extends NoTargetAnnotati } } -object InfoModeAnnotation extends HasScoptOptions { - def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[String]("info-mode") - .valueName ("<ignore|use|gen|append>") - .action( (x, c) => InfoModeAnnotation(x) +: c ) - .unbounded() - .text(s"specifies the source info handling, default is ${apply().modeName}") +object InfoModeAnnotation extends HasShellOptions { + + val options = Seq( + new ShellOption[String]( + longOption = "info-mode", + toAnnotationSeq = a => Seq(InfoModeAnnotation(a)), + helpText = s"Source file info handling mode (default: ${apply().modeName})", + shortOption = Some("<ignore|use|gen|append>") ) ) + } /** Holds a [[scala.Predef.String String]] containing FIRRTL source to read as input @@ -116,22 +125,25 @@ case class FirrtlSourceAnnotation(source: String) extends NoTargetAnnotation wit } -object FirrtlSourceAnnotation extends HasScoptOptions { - def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[String]("firrtl-source") - .valueName ("A FIRRTL string") - .action( (x, c) => FirrtlSourceAnnotation(x) +: c ) - .unbounded() - .text(s"A FIRRTL circuit as a string") +object FirrtlSourceAnnotation extends HasShellOptions { + + val options = Seq( + new ShellOption[String]( + longOption = "firrtl-source", + toAnnotationSeq = a => Seq(FirrtlSourceAnnotation(a)), + helpText = "An input FIRRTL circuit string", + shortOption = Some("<string>") ) ) + } -/** Holds a [[Compiler]] that should be run +/** helpValueName a [[Compiler]] that should be run * - set stringly with `-X/--compiler` * - If unset, a [[CompilerAnnotation]] with the default [[VerilogCompiler]] * @param compiler compiler name */ case class CompilerAnnotation(compiler: Compiler = new VerilogCompiler()) extends NoTargetAnnotation with FirrtlOption -object CompilerAnnotation extends HasScoptOptions { +object CompilerAnnotation extends HasShellOptions { private [firrtl] def apply(compilerName: String): CompilerAnnotation = { val c = compilerName match { @@ -147,12 +159,14 @@ object CompilerAnnotation extends HasScoptOptions { CompilerAnnotation(c) } - def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[String]("compiler") - .abbr("X") - .valueName ("<none|high|middle|low|verilog|mverilog|sverilog>") - .action{ (x, c) => CompilerAnnotation(x) +: c } - .unbounded() - .text(s"compiler to use, default is 'verilog'") + val options = Seq( + new ShellOption[String]( + longOption = "compiler", + toAnnotationSeq = a => Seq(CompilerAnnotation(a)), + helpText = "The FIRRTL compiler to use (default: verilog)", + shortOption = Some("X"), + helpValueName = Some("<none|high|middle|low|verilog|mverilog|sverilog>") ) ) + } /** Holds the unambiguous class name of a [[Transform]] to run @@ -162,27 +176,26 @@ object CompilerAnnotation extends HasScoptOptions { */ case class RunFirrtlTransformAnnotation(transform: Transform) extends NoTargetAnnotation -object RunFirrtlTransformAnnotation extends HasScoptOptions { - def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[Seq[String]]("custom-transforms") - .abbr("fct") - .valueName ("<package>.<class>") - .validate( x => { - x.map(txName => - try { Class.forName(txName).asInstanceOf[Class[_ <: Transform]].newInstance() } - catch { - case e: ClassNotFoundException => throw new OptionsException( - s"Unable to locate custom transform $txName (did you misspell it?)", e) - case e: InstantiationException => throw new OptionsException( - s"Unable to create instance of Transform $txName (is this an anonymous class?)", e) - case e: Throwable => throw new OptionsException( - s"Unknown error when instantiating class $txName", e) } ) - p.success } ) - .action( (x, c) => - x.map(txName => - RunFirrtlTransformAnnotation(Class.forName(txName).asInstanceOf[Class[_ <: Transform]].newInstance())) - .reverse ++ c ) - .unbounded() - .text("runs these custom transforms during compilation.") +object RunFirrtlTransformAnnotation extends HasShellOptions { + + val options = Seq( + new ShellOption[Seq[String]]( + longOption = "custom-transforms", + toAnnotationSeq = _.map(txName => + try { + val tx = Class.forName(txName).asInstanceOf[Class[_ <: Transform]].newInstance() + RunFirrtlTransformAnnotation(tx) + } catch { + case e: ClassNotFoundException => throw new OptionsException( + s"Unable to locate custom transform $txName (did you misspell it?)", e) + case e: InstantiationException => throw new OptionsException( + s"Unable to create instance of Transform $txName (is this an anonymous class?)", e) + case e: Throwable => throw new OptionsException( + s"Unknown error when instantiating class $txName", e) }), + helpText = "Run these transforms during compilation", + shortOption = Some("fct"), + helpValueName = Some("<package>.<class>") ) ) + } /** Holds a FIRRTL [[firrtl.ir.Circuit Circuit]] diff --git a/src/main/scala/firrtl/stage/FirrtlStage.scala b/src/main/scala/firrtl/stage/FirrtlStage.scala index e4620913..5d121322 100644 --- a/src/main/scala/firrtl/stage/FirrtlStage.scala +++ b/src/main/scala/firrtl/stage/FirrtlStage.scala @@ -3,7 +3,8 @@ package firrtl.stage import firrtl.{AnnotationSeq, CustomTransformException, FIRRTLException, Utils} -import firrtl.options.{Phase, PhaseException, Shell, Stage, StageMain, OptionsException} +import firrtl.options.{Stage, Phase, PhaseException, Shell, OptionsException, StageMain} +import firrtl.options.phases.DeletedWrapper import firrtl.passes.{PassException, PassExceptions} import scala.util.control.ControlThrowable @@ -13,18 +14,18 @@ import java.io.PrintWriter class FirrtlStage extends Stage { val shell: Shell = new Shell("firrtl") with FirrtlCli - private val phases: Seq[Phase] = Seq( - new firrtl.stage.phases.AddDefaults, - new firrtl.stage.phases.AddImplicitEmitter, - new firrtl.stage.phases.Checks, - new firrtl.stage.phases.AddCircuit, - new firrtl.stage.phases.AddImplicitOutputFile, - new firrtl.stage.phases.Compiler, - new firrtl.stage.phases.WriteEmitted - ) + private val phases: Seq[Phase] = + Seq( new firrtl.stage.phases.AddDefaults, + new firrtl.stage.phases.AddImplicitEmitter, + new firrtl.stage.phases.Checks, + new firrtl.stage.phases.AddCircuit, + new firrtl.stage.phases.AddImplicitOutputFile, + new firrtl.stage.phases.Compiler, + new firrtl.stage.phases.WriteEmitted ) + .map(DeletedWrapper(_)) def run(annotations: AnnotationSeq): AnnotationSeq = try { - phases.foldLeft(annotations)((a, f) => f.runTransform(a)) + phases.foldLeft(annotations)((a, f) => f.transform(a)) } catch { /* Rethrow the exceptions which are expected or due to the runtime environment (out of memory, stack overflow, etc.). * Any UNEXPECTED exceptions should be treated as internal errors. */ diff --git a/src/main/scala/firrtl/stage/phases/DriverCompatibility.scala b/src/main/scala/firrtl/stage/phases/DriverCompatibility.scala index 310e0bd4..cb6a135d 100644 --- a/src/main/scala/firrtl/stage/phases/DriverCompatibility.scala +++ b/src/main/scala/firrtl/stage/phases/DriverCompatibility.scala @@ -7,8 +7,8 @@ import firrtl.stage._ import firrtl.{AnnotationSeq, EmitAllModulesAnnotation, EmitCircuitAnnotation, FirrtlExecutionResult, Parser} import firrtl.annotations.NoTargetAnnotation import firrtl.proto.FromProto -import firrtl.options.{HasScoptOptions, InputAnnotationFileAnnotation, OptionsException, Phase, StageOptions, - StageUtils} +import firrtl.options.{HasShellOptions, InputAnnotationFileAnnotation, OptionsException, Phase, ShellOption, + StageOptions, StageUtils} import firrtl.options.Viewer import scopt.OptionParser @@ -49,7 +49,8 @@ object DriverCompatibility { @deprecated(""""top-name" is deprecated as part of the Stage/Phase refactor. Use explicit input/output files.""", "1.2") case class TopNameAnnotation(topName: String) extends NoTargetAnnotation - object TopNameAnnotation extends HasScoptOptions { + object TopNameAnnotation { + def addOptions(p: OptionParser[AnnotationSeq]): Unit = p .opt[Unit]("top-name") .abbr("tn") diff --git a/src/main/scala/firrtl/transforms/CheckCombLoops.scala b/src/main/scala/firrtl/transforms/CheckCombLoops.scala index 0a9ec0e3..17e1569b 100644 --- a/src/main/scala/firrtl/transforms/CheckCombLoops.scala +++ b/src/main/scala/firrtl/transforms/CheckCombLoops.scala @@ -17,7 +17,7 @@ import firrtl.annotations._ import firrtl.Utils.throwInternalError import firrtl.graph.{MutableDiGraph,DiGraph} import firrtl.analyses.InstanceGraph -import firrtl.options.RegisteredTransform +import firrtl.options.{RegisteredTransform, ShellOption} import scopt.OptionParser object CheckCombLoops { @@ -69,11 +69,11 @@ class CheckCombLoops extends Transform with RegisteredTransform { import CheckCombLoops._ - def addOptions(parser: OptionParser[AnnotationSeq]): Unit = parser - .opt[Unit]("no-check-comb-loops") - .action( (x, c) => c :+ DontCheckCombLoopsAnnotation ) - .maxOccurs(1) - .text("Do NOT check for combinational loops (not recommended)") + val options = Seq( + new ShellOption[Unit]( + longOption = "no-check-comb-loops", + toAnnotationSeq = (_: Unit) => Seq(DontCheckCombLoopsAnnotation), + helpText = "Disable combinational loop checking" ) ) /* * A case class that represents a net in the circuit. This is diff --git a/src/main/scala/firrtl/transforms/DeadCodeElimination.scala b/src/main/scala/firrtl/transforms/DeadCodeElimination.scala index deb7299d..0c357267 100644 --- a/src/main/scala/firrtl/transforms/DeadCodeElimination.scala +++ b/src/main/scala/firrtl/transforms/DeadCodeElimination.scala @@ -11,7 +11,7 @@ import firrtl.Mappers._ import firrtl.WrappedExpression._ import firrtl.Utils.{throwInternalError, toWrappedExpression, kind} import firrtl.MemoizedHash._ -import firrtl.options.RegisteredTransform +import firrtl.options.{RegisteredTransform, ShellOption} import scopt.OptionParser import collection.mutable @@ -36,11 +36,11 @@ class DeadCodeElimination extends Transform with ResolvedAnnotationPaths with Re def inputForm = LowForm def outputForm = LowForm - def addOptions(parser: OptionParser[AnnotationSeq]): Unit = parser - .opt[Unit]("no-dce") - .action( (x, c) => c :+ NoDCEAnnotation ) - .maxOccurs(1) - .text("Do NOT run dead code elimination") + val options = Seq( + new ShellOption[Unit]( + longOption = "no-dce", + toAnnotationSeq = (_: Unit) => Seq(NoDCEAnnotation), + helpText = "Disable dead code elimination" ) ) /** Based on LogicNode ins CheckCombLoops, currently kind of faking it */ private type LogicNode = MemoizedHash[WrappedExpression] diff --git a/src/main/scala/logger/Logger.scala b/src/main/scala/logger/Logger.scala index 1cf7d7ee..00c29b1a 100644 --- a/src/main/scala/logger/Logger.scala +++ b/src/main/scala/logger/Logger.scala @@ -363,9 +363,9 @@ object Logger { * @param inputAnnotations annotation sequence containing logger options */ def setOptions(inputAnnotations: AnnotationSeq): Unit = { - val annotations = Seq( AddDefaults, - Checks ) - .foldLeft(inputAnnotations)((a, p) => p.runTransform(a)) + val annotations = + Seq( AddDefaults, Checks ) + .foldLeft(inputAnnotations)((a, p) => p.transform(a)) val lopts = view[LoggerOptions](annotations) state.globalLevel = (state.globalLevel, lopts.globalLogLevel) match { diff --git a/src/main/scala/logger/LoggerAnnotations.scala b/src/main/scala/logger/LoggerAnnotations.scala index 2811cc6c..204fc4ab 100644 --- a/src/main/scala/logger/LoggerAnnotations.scala +++ b/src/main/scala/logger/LoggerAnnotations.scala @@ -4,7 +4,7 @@ package logger import firrtl.AnnotationSeq import firrtl.annotations.{Annotation, NoTargetAnnotation} -import firrtl.options.{HasScoptOptions, StageUtils} +import firrtl.options.{HasShellOptions, ShellOption, StageUtils} import scopt.OptionParser @@ -18,17 +18,16 @@ sealed trait LoggerOption { this: Annotation => } */ case class LogLevelAnnotation(globalLogLevel: LogLevel.Value = LogLevel.None) extends NoTargetAnnotation with LoggerOption -object LogLevelAnnotation extends HasScoptOptions { - def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[String]("log-level") - .abbr("ll") - .valueName("<Error|Warn|Info|Debug|Trace>") - .action( (x, c) => LogLevelAnnotation(LogLevel(x)) +: c ) - .validate{ x => - lazy val msg = s"$x bad value must be one of error|warn|info|debug|trace" - if (Array("error", "warn", "info", "debug", "trace").contains(x.toLowerCase)) { p.success } - else { p.failure(msg) }} - .unbounded() - .text(s"Sets the verbosity level of logging, default is ${new LoggerOptions().globalLogLevel}") +object LogLevelAnnotation extends HasShellOptions { + + val options = Seq( + new ShellOption[String]( + longOption = "log-level", + toAnnotationSeq = (a: String) => Seq(LogLevelAnnotation(LogLevel(a))), + helpText = s"Set global logging verbosity (default: ${new LoggerOptions().globalLogLevel}", + shortOption = Some("ll"), + helpValueName = Some("{error|warn|info|debug|trace}") ) ) + } /** Describes a mapping of a class to a specific log level @@ -38,16 +37,19 @@ object LogLevelAnnotation extends HasScoptOptions { */ case class ClassLogLevelAnnotation(className: String, level: LogLevel.Value) extends NoTargetAnnotation with LoggerOption -object ClassLogLevelAnnotation extends HasScoptOptions { - def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[Seq[String]]("class-log-level") - .abbr("cll") - .valueName("<FullClassName:[Error|Warn|Info|Debug|Trace]>[,...]") - .action( (x, c) => (x.map { y => - val className :: levelName :: _ = y.split(":").toList - val level = LogLevel(levelName) - ClassLogLevelAnnotation(className, level) }) ++ c ) - .unbounded() - .text(s"This defines per-class verbosity of logging") +object ClassLogLevelAnnotation extends HasShellOptions { + + val options = Seq( + new ShellOption[Seq[String]]( + longOption = "class-log-level", + toAnnotationSeq = (a: Seq[String]) => a.map { aa => + val className :: levelName :: _ = aa.split(":").toList + val level = LogLevel(levelName) + ClassLogLevelAnnotation(className, level) }, + helpText = "Set per-class logging verbosity", + shortOption = Some("cll"), + helpValueName = Some("<FullClassName:{error|warn|info|debug|trace}>...") ) ) + } /** Enables logging to a file (as opposed to STDOUT) @@ -56,22 +58,27 @@ object ClassLogLevelAnnotation extends HasScoptOptions { */ case class LogFileAnnotation(file: Option[String]) extends NoTargetAnnotation with LoggerOption -object LogFileAnnotation extends HasScoptOptions { - def addOptions(p: OptionParser[AnnotationSeq]): Unit = { - p.opt[String]("log-file") - .action( (x, c) => LogFileAnnotation(Some(x)) +: c ) - .unbounded() - .text(s"log to the specified file") - } +object LogFileAnnotation extends HasShellOptions { + + val options = Seq( + new ShellOption[String]( + longOption = "log-file", + toAnnotationSeq = (a: String) => Seq(LogFileAnnotation(Some(a))), + helpText = "Log to a file instead of STDOUT", + helpValueName = Some("<file>") ) ) + } /** Enables class names in log output * - enabled with `-lcn/--log-class-names` */ -case object LogClassNamesAnnotation extends NoTargetAnnotation with LoggerOption with HasScoptOptions { - def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[Unit]("log-class-names") - .abbr("lcn") - .action( (x, c) => LogClassNamesAnnotation +: c ) - .unbounded() - .text(s"shows class names and log level in logging output, useful for target --class-log-level") +case object LogClassNamesAnnotation extends NoTargetAnnotation with LoggerOption with HasShellOptions { + + val options = Seq( + new ShellOption[Unit]( + longOption = "log-class-names", + toAnnotationSeq = (a: Unit) => Seq(LogClassNamesAnnotation), + helpText = "Show class names and log level in logging output", + shortOption = Some("lcn") ) ) + } diff --git a/src/test/scala/firrtlTests/options/RegistrationSpec.scala b/src/test/scala/firrtlTests/options/RegistrationSpec.scala index c060341d..43d71b6d 100644 --- a/src/test/scala/firrtlTests/options/RegistrationSpec.scala +++ b/src/test/scala/firrtlTests/options/RegistrationSpec.scala @@ -6,7 +6,7 @@ import org.scalatest.{FlatSpec, Matchers} import scopt.OptionParser import java.util.ServiceLoader -import firrtl.options.{RegisteredTransform, RegisteredLibrary} +import firrtl.options.{RegisteredTransform, RegisteredLibrary, ShellOption} import firrtl.passes.Pass import firrtl.ir.Circuit import firrtl.annotations.NoTargetAnnotation @@ -16,16 +16,23 @@ case object HelloAnnotation extends NoTargetAnnotation class FooTransform extends Pass with RegisteredTransform { def run(c: Circuit): Circuit = c - def addOptions(p: OptionParser[AnnotationSeq]): Unit = - p.opt[Unit]("hello") - .action( (_, c) => HelloAnnotation +: c ) + + val options = Seq( + new ShellOption[Unit]( + longOption = "hello", + toAnnotationSeq = _ => Seq(HelloAnnotation), + helpText = "Hello option") ) + } class BarLibrary extends RegisteredLibrary { def name: String = "Bar" - def addOptions(p: OptionParser[AnnotationSeq]): Unit = - p.opt[Unit]("world") - .action( (_, c) => HelloAnnotation +: c ) + + val options = Seq( + new ShellOption[Unit]( + longOption = "world", + toAnnotationSeq = _ => Seq(HelloAnnotation), + helpText = "World option") ) } class RegistrationSpec extends FlatSpec with Matchers { diff --git a/src/test/scala/firrtlTests/options/phases/ChecksSpec.scala b/src/test/scala/firrtlTests/options/phases/ChecksSpec.scala index e04ba554..b988f838 100644 --- a/src/test/scala/firrtlTests/options/phases/ChecksSpec.scala +++ b/src/test/scala/firrtlTests/options/phases/ChecksSpec.scala @@ -13,14 +13,14 @@ class ChecksSpec extends FlatSpec with Matchers { val targetDir = TargetDirAnnotation("foo") val annoOut = OutputAnnotationFileAnnotation("bar") + class Fixture { val phase: Phase = new Checks } + /* A minimum annotation Seq that will pass [[Checks]] */ val min = Seq(targetDir) def checkExceptionMessage(phase: Phase, annotations: AnnotationSeq, messageStart: String): Unit = intercept[OptionsException]{ phase.transform(annotations) }.getMessage should startWith(messageStart) - class Fixture { val phase: Phase = new Checks } - behavior of classOf[Checks].toString it should "enforce exactly one TargetDirAnnotation" in new Fixture { diff --git a/src/test/scala/firrtlTests/options/phases/GetIncludesSpec.scala b/src/test/scala/firrtlTests/options/phases/GetIncludesSpec.scala index 5b07d0e0..1007ca8c 100644 --- a/src/test/scala/firrtlTests/options/phases/GetIncludesSpec.scala +++ b/src/test/scala/firrtlTests/options/phases/GetIncludesSpec.scala @@ -21,7 +21,6 @@ case object E extends NoTargetAnnotation class GetIncludesSpec extends FlatSpec with Matchers with BackendCompilationUtilities with firrtlTests.Utils { - val dir = new File("test_run_dir/GetIncludesSpec") dir.mkdirs() |
