diff options
| author | Schuyler Eldridge | 2018-11-07 15:30:17 -0500 |
|---|---|---|
| committer | GitHub | 2018-11-07 15:30:17 -0500 |
| commit | 75284395ba7ef285daefd2da38e720590b465ad7 (patch) | |
| tree | 7ae4e04a16eb87ce306a9d891acabbd4c6b1c8b7 | |
| parent | 17b4e9835bd95dcf91c5ea5a4d7c52280031ea93 (diff) | |
| parent | b05eaea3e59c64d619a544c63311d510f335f7e5 (diff) | |
Merge pull request #919 from seldridge/f764.6
- Add, but do not use Options-mirroring Annotations
15 files changed, 415 insertions, 14 deletions
diff --git a/src/main/resources/META-INF/services/firrtl.options.RegisteredLibrary b/src/main/resources/META-INF/services/firrtl.options.RegisteredLibrary new file mode 100644 index 00000000..abfcceb0 --- /dev/null +++ b/src/main/resources/META-INF/services/firrtl.options.RegisteredLibrary @@ -0,0 +1 @@ +firrtl.passes.memlib.MemLibOptions diff --git a/src/main/resources/META-INF/services/firrtl.options.RegisteredTransform b/src/main/resources/META-INF/services/firrtl.options.RegisteredTransform new file mode 100644 index 00000000..638404be --- /dev/null +++ b/src/main/resources/META-INF/services/firrtl.options.RegisteredTransform @@ -0,0 +1,4 @@ +firrtl.transforms.DeadCodeElimination +firrtl.transforms.CheckCombLoops +firrtl.passes.InlineInstances +firrtl.passes.clocklist.ClockListTransform diff --git a/src/main/scala/firrtl/Driver.scala b/src/main/scala/firrtl/Driver.scala index d96bb903..47841cec 100644 --- a/src/main/scala/firrtl/Driver.scala +++ b/src/main/scala/firrtl/Driver.scala @@ -17,6 +17,7 @@ import firrtl.annotations.AnnotationYamlProtocol._ import firrtl.passes.{PassException, PassExceptions} import firrtl.transforms._ import firrtl.Utils.throwInternalError +import firrtl.stage.TargetDirAnnotation /** diff --git a/src/main/scala/firrtl/ExecutionOptionsManager.scala b/src/main/scala/firrtl/ExecutionOptionsManager.scala index 1754338c..2f7178bb 100644 --- a/src/main/scala/firrtl/ExecutionOptionsManager.scala +++ b/src/main/scala/firrtl/ExecutionOptionsManager.scala @@ -68,9 +68,6 @@ case class CommonOptions( } } -/** Annotation that contains the [[CommonOptions]] target directory */ -case class TargetDirAnnotation(value: String) extends NoTargetAnnotation - trait HasCommonOptions { self: ExecutionOptionsManager => var commonOptions = CommonOptions() diff --git a/src/main/scala/firrtl/annotations/JsonProtocol.scala b/src/main/scala/firrtl/annotations/JsonProtocol.scala index 36699151..acb2d957 100644 --- a/src/main/scala/firrtl/annotations/JsonProtocol.scala +++ b/src/main/scala/firrtl/annotations/JsonProtocol.scala @@ -34,6 +34,17 @@ object JsonProtocol { { case JString(s) => AnnotationUtils.toNamed(s).asInstanceOf[ComponentName] }, { case named: ComponentName => JString(named.serialize) } )) + class TransformSerializer extends CustomSerializer[Transform](format => ( + { case JString(s) => + try { + Class.forName(s).asInstanceOf[Class[_ <: Transform]].newInstance() + } catch { + case e: java.lang.InstantiationException => throw new FIRRTLException( + "NoSuchMethodException during construction of serialized Transform. Is your Transform an inner class?", e) + case t: Throwable => throw t + }}, + { case x: Transform => JString(x.getClass.getName) } + )) class TargetSerializer extends CustomSerializer[Target](format => ( @@ -67,7 +78,7 @@ object JsonProtocol { new TransformClassSerializer + new NamedSerializer + new CircuitNameSerializer + new ModuleNameSerializer + new ComponentNameSerializer + new TargetSerializer + new GenericTargetSerializer + new CircuitTargetSerializer + new ModuleTargetSerializer + - new InstanceTargetSerializer + new ReferenceTargetSerializer + new InstanceTargetSerializer + new ReferenceTargetSerializer + new TransformSerializer } /** Serialize annotations to a String for emission */ diff --git a/src/main/scala/firrtl/package.scala b/src/main/scala/firrtl/package.scala index c0b79462..9b7fce38 100644 --- a/src/main/scala/firrtl/package.scala +++ b/src/main/scala/firrtl/package.scala @@ -5,4 +5,8 @@ import firrtl.annotations.Annotation package object firrtl { implicit def seqToAnnoSeq(xs: Seq[Annotation]) = AnnotationSeq(xs) implicit def annoSeqToSeq(as: AnnotationSeq): Seq[Annotation] = as.underlying + + /* Options as annotations compatibility items */ + @deprecated("Use firrtl.stage.TargetDirAnnotation", "3.2") + val TargetDirAnnotation = firrtl.stage.TargetDirAnnotation } diff --git a/src/main/scala/firrtl/passes/Inline.scala b/src/main/scala/firrtl/passes/Inline.scala index feda80f2..dcee0ee2 100644 --- a/src/main/scala/firrtl/passes/Inline.scala +++ b/src/main/scala/firrtl/passes/Inline.scala @@ -7,6 +7,9 @@ import firrtl.ir._ import firrtl.Mappers._ import firrtl.annotations._ import firrtl.analyses.InstanceGraph +import firrtl.stage.RunFirrtlTransformAnnotation +import firrtl.options.RegisteredTransform +import scopt.OptionParser // Datastructures import scala.collection.mutable @@ -20,11 +23,30 @@ case class InlineAnnotation(target: Named) extends SingleTargetAnnotation[Named] * @note Only use on legal Firrtl. Specifically, the restriction of instance loops must have been checked, or else this * pass can infinitely recurse. */ -class InlineInstances extends Transform { +class InlineInstances extends Transform with RegisteredTransform { def inputForm = LowForm 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""") + private def collectAnns(circuit: Circuit, anns: Iterable[Annotation]): (Set[ModuleName], Set[ComponentName]) = anns.foldLeft(Set.empty[ModuleName], Set.empty[ComponentName]) { case ((modNames, instNames), ann) => ann match { diff --git a/src/main/scala/firrtl/passes/clocklist/ClockListTransform.scala b/src/main/scala/firrtl/passes/clocklist/ClockListTransform.scala index 6c7b2e18..8d70f211 100644 --- a/src/main/scala/firrtl/passes/clocklist/ClockListTransform.scala +++ b/src/main/scala/firrtl/passes/clocklist/ClockListTransform.scala @@ -14,6 +14,9 @@ import Utils._ import memlib.AnalysisUtils._ import memlib._ import Mappers._ +import firrtl.options.RegisteredTransform +import scopt.OptionParser +import firrtl.stage.RunFirrtlTransformAnnotation case class ClockListAnnotation(target: ModuleName, outputConfig: String) extends SingleTargetAnnotation[ModuleName] { @@ -54,9 +57,19 @@ Usage: } } -class ClockListTransform extends Transform { +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") + def passSeq(top: String, writer: Writer): Seq[Pass] = Seq(new ClockList(top, writer)) def execute(state: CircuitState): CircuitState = { diff --git a/src/main/scala/firrtl/passes/memlib/InferReadWrite.scala b/src/main/scala/firrtl/passes/memlib/InferReadWrite.scala index 2d1d7f6b..3494de45 100644 --- a/src/main/scala/firrtl/passes/memlib/InferReadWrite.scala +++ b/src/main/scala/firrtl/passes/memlib/InferReadWrite.scala @@ -8,10 +8,14 @@ import firrtl.ir._ import firrtl.Mappers._ import firrtl.PrimOps._ import firrtl.Utils.{one, zero, BoolType} +import firrtl.options.HasScoptOptions import MemPortUtils.memPortField import firrtl.passes.memlib.AnalysisUtils.{Connects, getConnects, getOrigin} import WrappedExpression.weq import annotations._ +import scopt.OptionParser +import firrtl.stage.RunFirrtlTransformAnnotation + case object InferReadWriteAnnotation extends NoTargetAnnotation @@ -72,10 +76,10 @@ object InferReadWritePass extends Pass { def replaceStmt(repl: Netlist)(s: Statement): Statement = s map replaceStmt(repl) map replaceExp(repl) match { - case Connect(_, EmptyExpression, _) => EmptyStmt + case Connect(_, EmptyExpression, _) => EmptyStmt case sx => sx } - + def inferReadWriteStmt(connects: Connects, repl: Netlist, stmts: Statements) @@ -143,9 +147,18 @@ 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 { +class InferReadWrite extends Transform with SeqTransformBased with HasScoptOptions { def inputForm = MidForm def outputForm = MidForm + + def addOptions(parser: OptionParser[AnnotationSeq]): Unit = parser + .opt[Unit]("infer-rw") + .abbr("firw") + .valueName ("<circuit>") + .action( (_, c) => c ++ Seq(InferReadWriteAnnotation, RunFirrtlTransformAnnotation(new InferReadWrite)) ) + .maxOccurs(1) + .text("Enable readwrite port inference for the target circuit") + def transforms = Seq( InferReadWritePass, CheckInitialization, diff --git a/src/main/scala/firrtl/passes/memlib/MemLibOptions.scala b/src/main/scala/firrtl/passes/memlib/MemLibOptions.scala new file mode 100644 index 00000000..2f26e4e5 --- /dev/null +++ b/src/main/scala/firrtl/passes/memlib/MemLibOptions.scala @@ -0,0 +1,15 @@ +// See LICENSE for license details. + +package firrtl.passes.memlib + +import firrtl._ +import firrtl.options.RegisteredLibrary +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)) +} diff --git a/src/main/scala/firrtl/passes/memlib/ReplaceMemTransform.scala b/src/main/scala/firrtl/passes/memlib/ReplaceMemTransform.scala index 311813db..f2e6cd4e 100644 --- a/src/main/scala/firrtl/passes/memlib/ReplaceMemTransform.scala +++ b/src/main/scala/firrtl/passes/memlib/ReplaceMemTransform.scala @@ -6,10 +6,13 @@ package memlib import firrtl._ import firrtl.ir._ import firrtl.annotations._ +import firrtl.options.HasScoptOptions import AnalysisUtils._ import Utils.error import java.io.{File, CharArrayWriter, PrintWriter} import wiring._ +import scopt.OptionParser +import firrtl.stage.RunFirrtlTransformAnnotation sealed trait PassOption case object InputConfigFileName extends PassOption @@ -19,11 +22,11 @@ case object PassModuleName extends PassOption object PassConfigUtil { type PassOptionMap = Map[PassOption, String] - + def getPassOptions(t: String, usage: String = "") = { // can't use space to delimit sub arguments (otherwise, Driver.scala will throw error) val passArgList = t.split(":").toList - + def nextPassOption(map: PassOptionMap, list: List[String]): PassOptionMap = { list match { case Nil => map @@ -103,9 +106,19 @@ 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 { +class ReplSeqMem extends Transform with HasScoptOptions { 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) => c ++ Seq(passes.memlib.ReplSeqMemAnnotation.parse(x), + RunFirrtlTransformAnnotation(new ReplSeqMem)) ) + .maxOccurs(1) + .text("Replace sequential memories with blackboxes + configuration file") + def transforms(inConfigFile: Option[YamlFileReader], outConfigFile: ConfWriter): Seq[Transform] = Seq(new SimpleMidTransform(Legalize), new SimpleMidTransform(ToMemIR), diff --git a/src/main/scala/firrtl/stage/FirrtlAnnotations.scala b/src/main/scala/firrtl/stage/FirrtlAnnotations.scala new file mode 100644 index 00000000..e13daf79 --- /dev/null +++ b/src/main/scala/firrtl/stage/FirrtlAnnotations.scala @@ -0,0 +1,290 @@ +// See LICENSE for license details + +package firrtl.stage + +import firrtl._ +import firrtl.ir.Circuit +import firrtl.annotations.NoTargetAnnotation +import firrtl.transforms.BlackBoxTargetDirAnno +import firrtl.options.HasScoptOptions + +import logger.LogLevel + +import scopt.OptionParser + +/** Indicates that a subclass is an [[firrtl.annotations Annotation]] that includes a command line option + * + * This must be mixed into a subclass of [[annotations.Annotation]] + */ +sealed trait FirrtlOption extends HasScoptOptions + +/** Holds the name of the top module + * - set on the command line with `-tn/--top-name` + * @param value top module name + */ +case class TopNameAnnotation(topName: String) extends NoTargetAnnotation with FirrtlOption { + def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[String]("top-name") + .abbr("tn") + .valueName("<top-level-circuit-name>") + .action( (x, c) => c :+ TopNameAnnotation(x) ) + .unbounded() // See [Note 1] + .text("This options defines the top level circuit, defaults to dut when possible") +} + +object TopNameAnnotation { + private [firrtl] def apply(): TopNameAnnotation = TopNameAnnotation(topName = "") +} + +/** Holds the name of the target directory + * - set with `-td/--target-dir` + * - if unset, a [[TargetDirAnnotation]] will be generated with the + * @param value target directory name + */ +case class TargetDirAnnotation(targetDirName: String = ".") extends NoTargetAnnotation with FirrtlOption { + def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[String]("target-dir") + .abbr("td") + .valueName("<target-directory>") + .action( (x, c) => c ++ Seq(TargetDirAnnotation(x)) ) + .unbounded() // See [Note 1] + .text(s"Work directory for intermediate files/blackboxes, default is ${CommonOptions().targetDirName}") +} + +/** Describes the verbosity of information to log + * - set with `-ll/--log-level` + * - if unset, a [[LogLevelAnnotation]] with the default log level will be emitted + * @param level the level of logging + */ +case class LogLevelAnnotation(globalLogLevel: LogLevel.Value = LogLevel.None) extends NoTargetAnnotation with FirrtlOption { + val value = globalLogLevel.toString + + def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[String]("log-level") + .abbr("ll") + .valueName("<Error|Warn|Info|Debug|Trace>") + .action( (x, c) => c :+ LogLevelAnnotation(LogLevel(x)) ) + .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() // See [Note 1] + .text(s"Sets the verbosity level of logging, default is ${CommonOptions().globalLogLevel}") +} + +/** Describes a mapping of a class to a specific log level + * - set with `-cll/--class-log-level` + * @param name the class name to log + * @param level the verbosity level + */ +case class ClassLogLevelAnnotation(className: String, level: LogLevel.Value) extends NoTargetAnnotation + with FirrtlOption { + 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) => c ++ (x.map { y => + val className :: levelName :: _ = y.split(":").toList + val level = LogLevel(levelName) + ClassLogLevelAnnotation(className, level) }) ) + .unbounded() // This can actually occur any number of times safely + .text(s"This defines per-class verbosity of logging") +} + +object ClassLogLevelAnnotation { + private [firrtl] def apply(): ClassLogLevelAnnotation = ClassLogLevelAnnotation("", LogLevel.None) +} + +/** Enables logging to a file (as opposed to STDOUT) + * - enabled with `-ltf/--log-to-file` + */ +case object LogToFileAnnotation extends NoTargetAnnotation with FirrtlOption { + def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[Unit]("log-to-file") + .abbr("ltf") + .action( (x, c) => c :+ LogToFileAnnotation ) + .unbounded() + .text(s"default logs to stdout, this flags writes to topName.log or firrtl.log if no topName") +} + +/** Enables class names in log output + * - enabled with `-lcn/--log-class-names` + */ +case object LogClassNamesAnnotation extends NoTargetAnnotation with FirrtlOption { + def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[Unit]("log-class-names") + .abbr("lcn") + .action( (x, c) => c :+ LogClassNamesAnnotation ) + .unbounded() + .text(s"shows class names and log level in logging output, useful for target --class-log-level") +} + +/** Additional arguments + * - set with any trailing option on the command line + * @param value one [[scala.String]] argument + */ +case class ProgramArgsAnnotation(value: String) extends NoTargetAnnotation with FirrtlOption { + def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.arg[String]("<arg>...") + .unbounded() + .optional() + .action( (x, c) => c :+ ProgramArgsAnnotation(x) ) + .text("optional unbounded args") +} + +object ProgramArgsAnnotation { + private [firrtl] def apply(): ProgramArgsAnnotation = ProgramArgsAnnotation("") +} + +/** An explicit input FIRRTL file to read + * - set with `-i/--input-file` + * - If unset, an [[InputFileAnnotation]] with the default input file __will not be generated__ + * @param value input filename + */ +case class InputFileAnnotation(value: String) extends NoTargetAnnotation with FirrtlOption { + def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[String]("input-file") + .abbr("i") + .valueName ("<firrtl-source>") + .action( (x, c) => c :+ InputFileAnnotation(x) ) + .unbounded() // See [Note 1] + .text("use this to override the default input file name, default is empty") +} + +object InputFileAnnotation { + private [firrtl] def apply(): InputFileAnnotation = InputFileAnnotation("") +} + +/** An explicit output file the emitter will write to + * - set with `-o/--output-file` + * @param value output filename + */ +case class OutputFileAnnotation(value: String) extends NoTargetAnnotation with FirrtlOption { + def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[String]("output-file") + .abbr("o") + .valueName("<output>") + .action( (x, c) => c :+ OutputFileAnnotation(x) ) + .unbounded() + .text("use this to override the default output file name, default is empty") +} + +object OutputFileAnnotation { + private [firrtl] def apply(): OutputFileAnnotation = OutputFileAnnotation("") +} + +/** An explicit output _annotation_ file to write to + * - set with `-foaf/--output-annotation-file` + * @param value output annotation filename + */ +case class OutputAnnotationFileAnnotation(value: String) extends NoTargetAnnotation with FirrtlOption { + def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[String]("output-annotation-file") + .abbr("foaf") + .valueName ("<output-anno-file>") + .action( (x, c) => c :+ OutputAnnotationFileAnnotation(x) ) + .unbounded() // See [Note 1] + .text("use this to set the annotation output file") +} + +object OutputAnnotationFileAnnotation { + private [firrtl] def apply(): OutputAnnotationFileAnnotation = OutputAnnotationFileAnnotation("") +} + +/** Sets the info mode style + * - set with `--info-mode` + * @param value info mode name + */ +case class InfoModeAnnotation(value: String = "append") extends NoTargetAnnotation with FirrtlOption { + def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[String]("info-mode") + .valueName ("<ignore|use|gen|append>") + .action( (x, c) => c :+ InfoModeAnnotation(x.toLowerCase) ) + .unbounded() // See [Note 1] + .text(s"specifies the source info handling, default is ${FirrtlExecutionOptions().infoModeName}") +} + +/** Holds a [[scala.String]] containing FIRRTL source to read as input + * - set with `--firrtl-source` + * @param value FIRRTL source as a [[scala.String]] + */ +case class FirrtlSourceAnnotation(value: String) extends NoTargetAnnotation with FirrtlOption { + def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[String]("firrtl-source") + .valueName ("A FIRRTL string") + .action( (x, c) => c :+ FirrtlSourceAnnotation(x) ) + .unbounded() // See [Note 1] + .text(s"A FIRRTL circuit as a string") +} + +object FirrtlSourceAnnotation { + private [firrtl] def apply(): FirrtlSourceAnnotation = FirrtlSourceAnnotation("") +} + +/** Indicates that an emitted circuit (FIRRTL, Verilog, etc.) will be one file per module + * - set with `--split-modules` + */ +case object EmitOneFilePerModuleAnnotation extends NoTargetAnnotation with FirrtlOption { + def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[Unit]("split-modules") + .abbr("fsm") + .action( (x, c) => c :+ EmitOneFilePerModuleAnnotation ) + .unbounded() + .text ("Emit each module to its own file in the target directory.") +} + +/** Holds a filename containing one or more [[annotations.Annotation]] to be read + * - this is not stored in [[FirrtlExecutionOptions]] + * - set with `-faf/--annotation-file` + * @param value input annotation filename + */ +case class InputAnnotationFileAnnotation(value: String) extends NoTargetAnnotation with FirrtlOption { + def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[String]("annotation-file") + .abbr("faf") + .unbounded() + .valueName("<input-anno-file>") + .action( (x, c) => c :+ InputAnnotationFileAnnotation(x) ) + .text("Used to specify annotation file") +} + +object InputAnnotationFileAnnotation { + private [firrtl] def apply(): InputAnnotationFileAnnotation = InputAnnotationFileAnnotation("") +} + +/** Holds the name of the compiler to run + * - set with `-X/--compiler` + * - If unset, a [[CompilerNameAnnotation]] with the default compiler ("verilog") __will be generated__ + * @param value compiler name + */ +case class CompilerNameAnnotation(value: String = "verilog") extends NoTargetAnnotation with FirrtlOption { + def addOptions(p: OptionParser[AnnotationSeq]): Unit = p.opt[String]("compiler") + .abbr("X") + .valueName ("<high|middle|low|verilog|sverilog>") + .action( (x, c) => c :+ CompilerNameAnnotation(x) ) + .unbounded() // See [Note 1] + .text(s"compiler to use, default is 'verilog'") +} + +/** Holds the unambiguous class name of a [[Transform]] to run + * - will be append to [[FirrtlExecutionOptions.customTransforms]] + * - set with `-fct/--custom-transforms` + * @param value the full class name of the transform + */ +case class RunFirrtlTransformAnnotation(transform: Transform) extends NoTargetAnnotation with FirrtlOption { + 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 FIRRTLException( + s"Unable to locate custom transform $txName (did you misspell it?)", e) + case e: InstantiationException => throw new FIRRTLException( + s"Unable to create instance of Transform $txName (is this an anonymous class?)", e) + case e: Throwable => throw new FIRRTLException( + s"Unknown error when instantiating class $txName", e) } ) + p.success } ) + .action( (x, c) => c ++ x.map(txName => + RunFirrtlTransformAnnotation(Class.forName(txName).asInstanceOf[Class[_ <: Transform]].newInstance())) ) + .unbounded() + .text("runs these custom transforms during compilation.") +} + +object RunFirrtlTransformAnnotation { + private [firrtl] def apply(): RunFirrtlTransformAnnotation = RunFirrtlTransformAnnotation(new firrtl.transforms.VerilogRename) +} + +/** Holds a FIRRTL [[Circuit]] + * @param value a circuit + */ +case class FirrtlCircuitAnnotation(value: Circuit) extends NoTargetAnnotation with FirrtlOption { + def addOptions(p: OptionParser[AnnotationSeq]): Unit = Unit +} diff --git a/src/main/scala/firrtl/transforms/CheckCombLoops.scala b/src/main/scala/firrtl/transforms/CheckCombLoops.scala index 44785c62..1a5861c5 100644 --- a/src/main/scala/firrtl/transforms/CheckCombLoops.scala +++ b/src/main/scala/firrtl/transforms/CheckCombLoops.scala @@ -15,6 +15,8 @@ import firrtl.annotations._ import firrtl.Utils.throwInternalError import firrtl.graph.{MutableDiGraph,DiGraph} import firrtl.analyses.InstanceGraph +import firrtl.options.RegisteredTransform +import scopt.OptionParser object CheckCombLoops { class CombLoopException(info: Info, mname: String, cycle: Seq[String]) extends PassException( @@ -42,12 +44,18 @@ case class CombinationalPath(sink: ComponentName, sources: Seq[ComponentName]) e * @note The pass cannot find loops that pass through ExtModules * @note The pass will throw exceptions on "false paths" */ -class CheckCombLoops extends Transform { +class CheckCombLoops extends Transform with RegisteredTransform { def inputForm = LowForm def outputForm = LowForm 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)") + /* * A case class that represents a net in the circuit. This is * necessary since combinational loop checking is an analysis on the diff --git a/src/main/scala/firrtl/transforms/DeadCodeElimination.scala b/src/main/scala/firrtl/transforms/DeadCodeElimination.scala index 523c997b..8f9fad46 100644 --- a/src/main/scala/firrtl/transforms/DeadCodeElimination.scala +++ b/src/main/scala/firrtl/transforms/DeadCodeElimination.scala @@ -11,6 +11,8 @@ import firrtl.Mappers._ import firrtl.WrappedExpression._ import firrtl.Utils.{throwInternalError, toWrappedExpression, kind} import firrtl.MemoizedHash._ +import firrtl.options.RegisteredTransform +import scopt.OptionParser import collection.mutable import java.io.{File, FileWriter} @@ -30,10 +32,16 @@ import java.io.{File, FileWriter} * circumstances of their instantiation in their parent module, they will still not be removed. To * remove such modules, use the [[NoDedupAnnotation]] to prevent deduplication. */ -class DeadCodeElimination extends Transform with ResolvedAnnotationPaths { +class DeadCodeElimination extends Transform with ResolvedAnnotationPaths with RegisteredTransform { 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") + /** Based on LogicNode ins CheckCombLoops, currently kind of faking it */ private type LogicNode = MemoizedHash[WrappedExpression] private object LogicNode { diff --git a/src/test/scala/firrtlTests/annotationTests/TargetDirAnnotationSpec.scala b/src/test/scala/firrtlTests/annotationTests/TargetDirAnnotationSpec.scala index eb061d8f..8f157131 100644 --- a/src/test/scala/firrtlTests/annotationTests/TargetDirAnnotationSpec.scala +++ b/src/test/scala/firrtlTests/annotationTests/TargetDirAnnotationSpec.scala @@ -5,6 +5,7 @@ package annotationTests import firrtlTests._ import firrtl._ +import firrtl.stage.TargetDirAnnotation /** Looks for [[TargetDirAnnotation]] */ class FindTargetDirTransform(expected: String) extends Transform { |
