summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSchuyler Eldridge2019-01-10 12:47:18 -0500
committerSchuyler Eldridge2019-05-22 16:17:17 -0400
commita423db5fa5a9fb106c1b0048b7dcf97fc83953b6 (patch)
treeecb697238fbbf9569ca9d4a4156fac9dd81fa3f3 /src
parent820e2688f0cb966d4528ff074fdbdc623ed8f940 (diff)
Add chisel3.stage Annotations
This adds the following FIRRTL Annotations to Chisel: - NoRunFirrtlCompilerAnnotation - PrintFullStackTraceAnnotation - ChiselGeneratorAnnotation - ChiselCircuitAnnotation - ChiselOutputFileAnnotation This includes tests for ChiselGeneratorAnnotation as this Annotation is able to be constructed from a String and to elaborate itself. Co-Authored-By: Schuyler Eldridge <schuyler.eldridge@ibm.com> Co-Authored-By: chick <chick@qrhino.com> Signed-off-by: Schuyler Eldridge <schuyler.eldridge@ibm.com>
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/chisel3/stage/ChiselAnnotations.scala105
-rw-r--r--src/test/scala/chiselTests/stage/ChiselAnnotationsSpec.scala65
2 files changed, 170 insertions, 0 deletions
diff --git a/src/main/scala/chisel3/stage/ChiselAnnotations.scala b/src/main/scala/chisel3/stage/ChiselAnnotations.scala
new file mode 100644
index 00000000..fb02173b
--- /dev/null
+++ b/src/main/scala/chisel3/stage/ChiselAnnotations.scala
@@ -0,0 +1,105 @@
+// See LICENSE for license details.
+
+package chisel3.stage
+
+import firrtl.annotations.{Annotation, NoTargetAnnotation}
+import firrtl.options.{HasShellOptions, OptionsException, ShellOption, Unserializable}
+
+import chisel3.{ChiselException, Module}
+import chisel3.experimental.RawModule
+import chisel3.internal.Builder
+import chisel3.internal.firrtl.Circuit
+
+/** Mixin that indicates that this is an [[firrtl.annotations.Annotation]] used to generate a [[ChiselOptions]] view.
+ */
+sealed trait ChiselOption extends Unserializable { this: Annotation => }
+
+/** Disable the execution of the FIRRTL compiler by Chisel
+ */
+case object NoRunFirrtlCompilerAnnotation extends NoTargetAnnotation with ChiselOption with HasShellOptions {
+
+ val options = Seq(
+ new ShellOption[Unit](
+ longOption = "no-run-firrtl",
+ toAnnotationSeq = _ => Seq(NoRunFirrtlCompilerAnnotation),
+ helpText = "Do not run the FIRRTL compiler (generate FIRRTL IR from Chisel and exit)",
+ shortOption = Some("chnrf") ) )
+
+}
+
+/** On an exception, this will cause the full stack trace to be printed as opposed to a pruned stack trace.
+ */
+case object PrintFullStackTraceAnnotation extends NoTargetAnnotation with ChiselOption with HasShellOptions {
+
+ val options = Seq(
+ new ShellOption[Unit](
+ longOption = "full-stacktrace",
+ toAnnotationSeq = _ => Seq(PrintFullStackTraceAnnotation),
+ helpText = "Show full stack trace when an exception is thrown" ) )
+
+}
+
+/** An [[firrtl.annotations.Annotation]] storing a function that returns a Chisel module
+ * @param gen a generator function
+ */
+case class ChiselGeneratorAnnotation(gen: () => RawModule) extends NoTargetAnnotation with Unserializable {
+
+ /** Run elaboration on the Chisel module generator function stored by this [[firrtl.annotations.Annotation]]
+ */
+ def elaborate: ChiselCircuitAnnotation = try {
+ ChiselCircuitAnnotation(Builder.build(Module(gen())))
+ } catch {
+ case e @ (_: OptionsException | _: ChiselException) => throw e
+ case e: Throwable =>
+ throw new OptionsException(s"Exception thrown when elaborating ChiselGeneratorAnnotation", e)
+ }
+
+}
+
+object ChiselGeneratorAnnotation extends HasShellOptions {
+
+ /** Construct a [[ChiselGeneratorAnnotation]] with a generator function that will try to construct a Chisel Module
+ * from using that Module's name. The Module must both exist in the class path and not take parameters.
+ * @param name a module name
+ * @throws firrtl.options.OptionsException if the module name is not found or if no parameterless constructor for
+ * that Module is found
+ */
+ def apply(name: String): ChiselGeneratorAnnotation = {
+ val gen = () => try {
+ Class.forName(name).asInstanceOf[Class[_ <: RawModule]].newInstance()
+ } catch {
+ case e: ClassNotFoundException =>
+ throw new OptionsException(s"Unable to locate module '$name'! (Did you misspell it?)", e)
+ case e: InstantiationException =>
+ throw new OptionsException(
+ s"Unable to create instance of module '$name'! (Does this class take parameters?)", e)
+ }
+ ChiselGeneratorAnnotation(gen)
+ }
+
+ val options = Seq(
+ new ShellOption[String](
+ longOption = "module",
+ toAnnotationSeq = (a: String) => Seq(ChiselGeneratorAnnotation(a)),
+ helpText = "The name of a Chisel module to elaborate (module must be in the classpath)",
+ helpValueName = Some("<package>.<module>") ) )
+
+}
+
+/** Stores a Chisel Circuit
+ * @param circuit a Chisel Circuit
+ */
+case class ChiselCircuitAnnotation(circuit: Circuit) extends NoTargetAnnotation with ChiselOption
+
+case class ChiselOutputFileAnnotation(file: String) extends NoTargetAnnotation with ChiselOption
+
+object ChiselOutputFileAnnotation extends HasShellOptions {
+
+ val options = Seq(
+ new ShellOption[String](
+ longOption = "chisel-output-file",
+ toAnnotationSeq = (a: String) => Seq(ChiselOutputFileAnnotation(a)),
+ helpText = "Write Chisel-generated FIRRTL to this file (default: <circuit-main>.fir)",
+ helpValueName = Some("<file>") ) )
+
+}
diff --git a/src/test/scala/chiselTests/stage/ChiselAnnotationsSpec.scala b/src/test/scala/chiselTests/stage/ChiselAnnotationsSpec.scala
new file mode 100644
index 00000000..c89955f2
--- /dev/null
+++ b/src/test/scala/chiselTests/stage/ChiselAnnotationsSpec.scala
@@ -0,0 +1,65 @@
+// See LICENSE for license details.
+
+package chiselTests.stage
+
+import org.scalatest.{FlatSpec, Matchers}
+
+import chisel3._
+import chisel3.stage.{ChiselCircuitAnnotation, ChiselGeneratorAnnotation}
+import chisel3.experimental.RawModule
+
+import firrtl.options.OptionsException
+
+class ChiselAnnotationsSpecFoo extends RawModule {
+ val in = IO(Input(Bool()))
+ val out = IO(Output(Bool()))
+ out := ~in
+}
+
+class ChiselAnnotationsSpecBaz(name: String) extends ChiselAnnotationsSpecFoo {
+ override val desiredName = name
+}
+
+class ChiselAnnotationsSpecQux extends ChiselAnnotationsSpecFoo {
+ /* This printf requires an implicit clock and reset, but RawModule has none. This will thereby fail elaboration. */
+ printf("hello")
+}
+
+class ChiselAnnotation
+
+class ChiselAnnotationsSpec extends FlatSpec with Matchers {
+
+ behavior of "ChiselGeneratorAnnotation elaboration"
+
+ it should "elaborate to a ChiselCircuitAnnotation" in {
+ val annotation = ChiselGeneratorAnnotation(() => new ChiselAnnotationsSpecFoo)
+ annotation.elaborate shouldBe a [ChiselCircuitAnnotation]
+ }
+
+ it should "throw an exception if elaboration fails" in {
+ val annotation = ChiselGeneratorAnnotation(() => new ChiselAnnotationsSpecQux)
+ intercept [ChiselException] { annotation.elaborate }
+ }
+
+ behavior of "ChiselGeneratorAnnotation when stringly constructing from Module names"
+
+ it should "elaborate from a String" in {
+ val annotation = ChiselGeneratorAnnotation("chiselTests.stage.ChiselAnnotationsSpecFoo")
+ annotation.elaborate shouldBe a [ChiselCircuitAnnotation]
+ }
+
+ it should "throw an exception if elaboration from a String refers to nonexistant class" in {
+ val bar = "chiselTests.stage.ChiselAnnotationsSpecBar"
+ val annotation = ChiselGeneratorAnnotation(bar)
+ intercept [OptionsException] { annotation.elaborate }
+ .getMessage should startWith (s"Unable to locate module '$bar'")
+ }
+
+ it should "throw an exception if elaboration from a String refers to an anonymous class" in {
+ val baz = "chiselTests.stage.ChiselAnnotationsSpecBaz"
+ val annotation = ChiselGeneratorAnnotation(baz)
+ intercept [OptionsException] { annotation.elaborate }
+ .getMessage should startWith (s"Unable to create instance of module '$baz'")
+ }
+
+}