diff options
| author | Schuyler Eldridge | 2019-01-10 12:47:18 -0500 |
|---|---|---|
| committer | Schuyler Eldridge | 2019-05-22 16:17:17 -0400 |
| commit | a423db5fa5a9fb106c1b0048b7dcf97fc83953b6 (patch) | |
| tree | ecb697238fbbf9569ca9d4a4156fac9dd81fa3f3 /src | |
| parent | 820e2688f0cb966d4528ff074fdbdc623ed8f940 (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.scala | 105 | ||||
| -rw-r--r-- | src/test/scala/chiselTests/stage/ChiselAnnotationsSpec.scala | 65 |
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'") + } + +} |
