diff options
| author | Chick Markley | 2019-06-03 16:22:43 -0700 |
|---|---|---|
| committer | GitHub | 2019-06-03 16:22:43 -0700 |
| commit | 821fe17b110e2a9017a335516227cb491c18cf43 (patch) | |
| tree | 22fe46c8f675ca3739f893890efc2479f367d9a1 /src/test | |
| parent | 820e2688f0cb966d4528ff074fdbdc623ed8f940 (diff) | |
| parent | 23641521174ba828feb32dc1c65c13a3d6b46970 (diff) | |
Merge pull request #1004 from freechipsproject/chisel-stage
Chisel stage
Diffstat (limited to 'src/test')
10 files changed, 486 insertions, 0 deletions
diff --git a/src/test/scala/chisel3/stage/phases/DriverCompatibilitySpec.scala b/src/test/scala/chisel3/stage/phases/DriverCompatibilitySpec.scala new file mode 100644 index 00000000..c478db27 --- /dev/null +++ b/src/test/scala/chisel3/stage/phases/DriverCompatibilitySpec.scala @@ -0,0 +1,70 @@ +// See LICENSE for license details. + +package chisel3.stage.phases + +import org.scalatest.{FlatSpec, Matchers} + +import chisel3.stage.{NoRunFirrtlCompilerAnnotation, ChiselOutputFileAnnotation} + +import firrtl.options.{OutputAnnotationFileAnnotation, StageOptions} +import firrtl.options.Viewer.view +import firrtl.stage.phases.DriverCompatibility.TopNameAnnotation + +class DriverCompatibilitySpec extends FlatSpec with Matchers { + + behavior of classOf[DriverCompatibility.AddImplicitOutputFile].toString + + it should "do nothing if a ChiselOutputFileAnnotation is present" in { + val annotations = Seq( + ChiselOutputFileAnnotation("Foo"), + TopNameAnnotation("Bar") ) + (new DriverCompatibility.AddImplicitOutputFile).transform(annotations).toSeq should be (annotations) + } + + it should "add a ChiselOutputFileAnnotation derived from a TopNameAnnotation" in { + val annotations = Seq( TopNameAnnotation("Bar") ) + val expected = ChiselOutputFileAnnotation("Bar") +: annotations + (new DriverCompatibility.AddImplicitOutputFile).transform(annotations).toSeq should be (expected) + } + + behavior of classOf[DriverCompatibility.AddImplicitOutputAnnotationFile].toString + + it should "do nothing if an OutputAnnotationFileAnnotation is present" in { + val annotations = Seq( + OutputAnnotationFileAnnotation("Foo"), + TopNameAnnotation("Bar") ) + (new DriverCompatibility.AddImplicitOutputAnnotationFile).transform(annotations).toSeq should be (annotations) + } + + it should "add an OutputAnnotationFileAnnotation derived from a TopNameAnnotation" in { + val annotations = Seq( TopNameAnnotation("Bar") ) + val expected = OutputAnnotationFileAnnotation("Bar") +: annotations + (new DriverCompatibility.AddImplicitOutputAnnotationFile).transform(annotations).toSeq should be (expected) + } + + behavior of classOf[DriverCompatibility.DisableFirrtlStage].toString + + it should "add a NoRunFirrtlCompilerAnnotation if one does not exist" in { + val annos = Seq(NoRunFirrtlCompilerAnnotation) + val expected = DriverCompatibility.RunFirrtlCompilerAnnotation +: annos + (new DriverCompatibility.DisableFirrtlStage).transform(Seq.empty).toSeq should be (expected) + } + + it should "NOT add a NoRunFirrtlCompilerAnnotation if one already exists" in { + val annos = Seq(NoRunFirrtlCompilerAnnotation) + (new DriverCompatibility.DisableFirrtlStage).transform(annos).toSeq should be (annos) + } + + behavior of classOf[DriverCompatibility.ReEnableFirrtlStage].toString + + it should "NOT strip a NoRunFirrtlCompilerAnnotation if NO RunFirrtlCompilerAnnotation is present" in { + val annos = Seq(NoRunFirrtlCompilerAnnotation, DriverCompatibility.RunFirrtlCompilerAnnotation) + (new DriverCompatibility.ReEnableFirrtlStage).transform(annos).toSeq should be (Seq.empty) + } + + it should "strip a NoRunFirrtlCompilerAnnotation if a RunFirrtlCompilerAnnotation is present" in { + val annos = Seq(NoRunFirrtlCompilerAnnotation) + (new DriverCompatibility.ReEnableFirrtlStage).transform(annos).toSeq should be (annos) + } + +} diff --git a/src/test/scala/chiselTests/DriverSpec.scala b/src/test/scala/chiselTests/DriverSpec.scala index 612bdef2..8fc58e21 100644 --- a/src/test/scala/chiselTests/DriverSpec.scala +++ b/src/test/scala/chiselTests/DriverSpec.scala @@ -28,6 +28,7 @@ class DriverSpec extends FreeSpec with Matchers { val exts = List("anno.json", "fir", "v") for (ext <- exts) { val dummyOutput = new File(targetDir, "DummyModule" + "." + ext) + info(s"${dummyOutput.toString} exists") dummyOutput.exists() should be(true) dummyOutput.delete() } @@ -44,6 +45,7 @@ class DriverSpec extends FreeSpec with Matchers { val exts = List("anno.json", "fir", "v") for (ext <- exts) { val dummyOutput = new File(targetDir, "dm" + "." + ext) + info(s"${dummyOutput.toString} exists") dummyOutput.exists() should be(true) dummyOutput.delete() } @@ -53,14 +55,21 @@ class DriverSpec extends FreeSpec with Matchers { } } + "execute returns a chisel execution result" in { val targetDir = "test_run_dir" val args = Array("--compiler", "low", "--target-dir", targetDir) + + info("Driver returned a ChiselExecutionSuccess") val result = Driver.execute(args, () => new DummyModule) result shouldBe a[ChiselExecutionSuccess] + + info("emitted circuit included 'circuit DummyModule'") val successResult = result.asInstanceOf[ChiselExecutionSuccess] successResult.emitted should include ("circuit DummyModule") + val dummyOutput = new File(targetDir, "DummyModule.lo.fir") + info(s"${dummyOutput.toString} exists") dummyOutput.exists() should be(true) dummyOutput.delete() } 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'") + } + +} diff --git a/src/test/scala/chiselTests/stage/ChiselOptionsViewSpec.scala b/src/test/scala/chiselTests/stage/ChiselOptionsViewSpec.scala new file mode 100644 index 00000000..7dbeb9fa --- /dev/null +++ b/src/test/scala/chiselTests/stage/ChiselOptionsViewSpec.scala @@ -0,0 +1,40 @@ +// See LICENSE for license details. + +package chiselTests.stage + +import org.scalatest.{FlatSpec, Matchers} + +import firrtl.options.Viewer.view + +import chisel3.stage._ +import chisel3.internal.firrtl.Circuit + +class ChiselOptionsViewSpec extends FlatSpec with Matchers { + + behavior of ChiselOptionsView.getClass.getName + + it should "construct a view from an AnnotationSeq" in { + val bar = Circuit("bar", Seq.empty, Seq.empty) + val annotations = Seq( + NoRunFirrtlCompilerAnnotation, + PrintFullStackTraceAnnotation, + ChiselOutputFileAnnotation("foo"), + ChiselCircuitAnnotation(bar) + ) + val out = view[ChiselOptions](annotations) + + info("runFirrtlCompiler was set to false") + out.runFirrtlCompiler should be (false) + + info("printFullStackTrace was set to true") + out.printFullStackTrace should be (true) + + info("outputFile was set to 'foo'") + out.outputFile should be (Some("foo")) + + info("chiselCircuit was set to circuit 'bar'") + out.chiselCircuit should be (Some(bar)) + + } + +} diff --git a/src/test/scala/chiselTests/stage/phases/AddImplicitOutputAnnotationFileSpec.scala b/src/test/scala/chiselTests/stage/phases/AddImplicitOutputAnnotationFileSpec.scala new file mode 100644 index 00000000..f5fe0440 --- /dev/null +++ b/src/test/scala/chiselTests/stage/phases/AddImplicitOutputAnnotationFileSpec.scala @@ -0,0 +1,42 @@ +// See LICENSE for license details. + +package chiselTests.stage.phases + +import org.scalatest.{FlatSpec, Matchers} + +import chisel3.experimental.RawModule +import chisel3.stage.ChiselGeneratorAnnotation +import chisel3.stage.phases.{AddImplicitOutputAnnotationFile, Elaborate} + +import firrtl.AnnotationSeq +import firrtl.options.{OutputAnnotationFileAnnotation, Phase} + +class AddImplicitOutputAnnotationFileSpec extends FlatSpec with Matchers { + + class Foo extends RawModule { override val desiredName = "Foo" } + + class Fixture { val phase: Phase = new AddImplicitOutputAnnotationFile } + + behavior of classOf[AddImplicitOutputAnnotationFile].toString + + it should "not override an existing OutputAnnotationFileAnnotation" in new Fixture { + val annotations: AnnotationSeq = Seq( + ChiselGeneratorAnnotation(() => new Foo), + OutputAnnotationFileAnnotation("Bar") ) + + Seq( new Elaborate, phase ) + .foldLeft(annotations)((a, p) => p.transform(a)) + .collect{ case a: OutputAnnotationFileAnnotation => a.file } + .toSeq should be (Seq("Bar")) + } + + it should "generate an OutputAnnotationFileAnnotation from a ChiselCircuitAnnotation" in new Fixture { + val annotations: AnnotationSeq = Seq( ChiselGeneratorAnnotation(() => new Foo) ) + + Seq( new Elaborate, phase ) + .foldLeft(annotations)((a, p) => p.transform(a)) + .collect{ case a: OutputAnnotationFileAnnotation => a.file } + .toSeq should be (Seq("Foo")) + } + +} diff --git a/src/test/scala/chiselTests/stage/phases/AddImplicitOutputFileSpec.scala b/src/test/scala/chiselTests/stage/phases/AddImplicitOutputFileSpec.scala new file mode 100644 index 00000000..411aa6ba --- /dev/null +++ b/src/test/scala/chiselTests/stage/phases/AddImplicitOutputFileSpec.scala @@ -0,0 +1,49 @@ +// See LICENSE for license details. + +package chiselTests.stage.phases + +import org.scalatest.{FlatSpec, Matchers} + +import chisel3.experimental.RawModule +import chisel3.stage.{ChiselGeneratorAnnotation, ChiselOutputFileAnnotation} +import chisel3.stage.phases.{AddImplicitOutputFile, Elaborate} + +import firrtl.AnnotationSeq +import firrtl.options.{Phase, StageOptions, TargetDirAnnotation} +import firrtl.options.Viewer.view + +class AddImplicitOutputFileSpec extends FlatSpec with Matchers { + + class Foo extends RawModule { override val desiredName = "Foo" } + + class Fixture { val phase: Phase = new AddImplicitOutputFile } + + behavior of classOf[AddImplicitOutputFile].toString + + it should "not override an existing ChiselOutputFileAnnotation" in new Fixture { + val annotations: AnnotationSeq = Seq( + ChiselGeneratorAnnotation(() => new Foo), + ChiselOutputFileAnnotation("Bar") ) + + Seq( new Elaborate, phase ) + .foldLeft(annotations)((a, p) => p.transform(a)) + .collect{ case a: ChiselOutputFileAnnotation => a.file } + .toSeq should be (Seq("Bar")) + } + + it should "generate a ChiselOutputFileAnnotation from a ChiselCircuitAnnotation" in new Fixture { + val annotations: AnnotationSeq = Seq( + ChiselGeneratorAnnotation(() => new Foo), + TargetDirAnnotation("test_run_dir") ) + + Seq( new Elaborate, phase ) + .foldLeft(annotations)((a, p) => p.transform(a)) + .collect{ case a: ChiselOutputFileAnnotation => a.file } + .toSeq should be (Seq("Foo")) + } + + it should "do nothing to an empty annotation sequence" in new Fixture { + phase.transform(AnnotationSeq(Seq.empty)).toSeq should be (empty) + } + +} diff --git a/src/test/scala/chiselTests/stage/phases/ChecksSpec.scala b/src/test/scala/chiselTests/stage/phases/ChecksSpec.scala new file mode 100644 index 00000000..6d01e38e --- /dev/null +++ b/src/test/scala/chiselTests/stage/phases/ChecksSpec.scala @@ -0,0 +1,43 @@ +// See LICENSE for license details. + +package chiselTests.stage.phases + +import org.scalatest.{FlatSpec, Matchers} + +import chisel3.stage.{ChiselOutputFileAnnotation, NoRunFirrtlCompilerAnnotation, PrintFullStackTraceAnnotation} +import chisel3.stage.phases.Checks + +import firrtl.AnnotationSeq +import firrtl.annotations.NoTargetAnnotation +import firrtl.options.{OptionsException, Phase} + +class ChecksSpec extends FlatSpec with Matchers { + + 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 "do nothing on sane annotation sequences" in new Fixture { + val a = Seq(NoRunFirrtlCompilerAnnotation, PrintFullStackTraceAnnotation) + phase.transform(a).toSeq should be (a) + } + + it should "throw an OptionsException if more than one NoRunFirrtlCompilerAnnotation is specified" in new Fixture { + val a = Seq(NoRunFirrtlCompilerAnnotation, NoRunFirrtlCompilerAnnotation) + checkExceptionMessage(phase, a, "At most one NoRunFirrtlCompilerAnnotation") + } + + it should "throw an OptionsException if more than one PrintFullStackTraceAnnotation is specified" in new Fixture { + val a = Seq(PrintFullStackTraceAnnotation, PrintFullStackTraceAnnotation) + checkExceptionMessage(phase, a, "At most one PrintFullStackTraceAnnotation") + } + + it should "throw an OptionsException if more than one ChiselOutputFileAnnotation is specified" in new Fixture { + val a = Seq(ChiselOutputFileAnnotation("foo"), ChiselOutputFileAnnotation("bar")) + checkExceptionMessage(phase, a, "At most one Chisel output file") + } + +} diff --git a/src/test/scala/chiselTests/stage/phases/ConvertSpec.scala b/src/test/scala/chiselTests/stage/phases/ConvertSpec.scala new file mode 100644 index 00000000..30fad4f5 --- /dev/null +++ b/src/test/scala/chiselTests/stage/phases/ConvertSpec.scala @@ -0,0 +1,62 @@ +// See LICENSE for license details. + +package chiselTests.stage.phases + +import org.scalatest.{FlatSpec, Matchers} + +import chisel3._ +import chisel3.experimental.{ChiselAnnotation, RawModule, RunFirrtlTransform} +import chisel3.stage.ChiselGeneratorAnnotation +import chisel3.stage.phases.{Convert, Elaborate} + +import firrtl.{AnnotationSeq, CircuitForm, CircuitState, Transform, UnknownForm} +import firrtl.annotations.{Annotation, NoTargetAnnotation} +import firrtl.options.Phase +import firrtl.stage.{FirrtlCircuitAnnotation, RunFirrtlTransformAnnotation} + +class ConvertSpecFirrtlTransform extends Transform { + def inputForm: CircuitForm = UnknownForm + def outputForm: CircuitForm = UnknownForm + def execute(state: CircuitState): CircuitState = state +} + +case class ConvertSpecFirrtlAnnotation(name: String) extends NoTargetAnnotation + +case class ConvertSpecChiselAnnotation(name: String) extends ChiselAnnotation with RunFirrtlTransform { + def toFirrtl: Annotation = ConvertSpecFirrtlAnnotation(name) + def transformClass: Class[_ <: Transform] = classOf[ConvertSpecFirrtlTransform] +} + +class ConvertSpecFoo extends RawModule { + override val desiredName: String = "foo" + + val in = IO(Input(Bool())) + val out = IO(Output(Bool())) + + experimental.annotate(ConvertSpecChiselAnnotation("bar")) +} + +class ConvertSpec extends FlatSpec with Matchers { + + class Fixture { val phase: Phase = new Convert } + + behavior of classOf[Convert].toString + + it should "convert a Chisel Circuit to a FIRRTL Circuit" in new Fixture { + val annos: AnnotationSeq = Seq(ChiselGeneratorAnnotation(() => new ConvertSpecFoo)) + + val annosx = Seq(new Elaborate, phase) + .foldLeft(annos)( (a, p) => p.transform(a) ) + + info("FIRRTL circuit generated") + annosx.collect{ case a: FirrtlCircuitAnnotation => a.circuit.main }.toSeq should be (Seq("foo")) + + info("FIRRTL annotations generated") + annosx.collect{ case a: ConvertSpecFirrtlAnnotation => a.name }.toSeq should be (Seq("bar")) + + info("FIRRTL transform annotations generated") + annosx.collect{ case a: RunFirrtlTransformAnnotation => a.transform.getClass} + .toSeq should be (Seq(classOf[ConvertSpecFirrtlTransform])) + } + +} diff --git a/src/test/scala/chiselTests/stage/phases/ElaborateSpec.scala b/src/test/scala/chiselTests/stage/phases/ElaborateSpec.scala new file mode 100644 index 00000000..4d99b24c --- /dev/null +++ b/src/test/scala/chiselTests/stage/phases/ElaborateSpec.scala @@ -0,0 +1,46 @@ +// See LICENSE for license details. + +package chiselTests.stage.phases + +import org.scalatest.{FlatSpec, Matchers} + +import chisel3._ +import chisel3.stage.{ChiselCircuitAnnotation, ChiselGeneratorAnnotation} +import chisel3.stage.phases.Elaborate + +import firrtl.options.Phase + +class ElaborateSpec extends FlatSpec with Matchers { + + class Foo extends Module { + override def desiredName: String = "Foo" + val io = IO( + new Bundle { + val in = Input(Bool()) + val out = Output(Bool()) + }) + + io.out := ~io.in + } + + class Bar extends Foo { + override def desiredName: String = "Bar" + } + + class Fixture { val phase: Phase = new Elaborate } + + behavior of classOf[Elaborate].toString + + it should "expand ChiselGeneratorAnnotations into ChiselCircuitAnnotations and delete originals" in new Fixture { + val annotations = Seq( ChiselGeneratorAnnotation(() => new Foo), + ChiselGeneratorAnnotation(() => new Bar) ) + val out = phase.transform(annotations) + + info("original annotations removed") + out.collect{ case a: ChiselGeneratorAnnotation => a } should be (empty) + + info("circuits created with the expected names") + out.collect{ case a: ChiselCircuitAnnotation => a.circuit.name } should be (Seq("Foo", "Bar")) + } + +} diff --git a/src/test/scala/chiselTests/stage/phases/EmitterSpec.scala b/src/test/scala/chiselTests/stage/phases/EmitterSpec.scala new file mode 100644 index 00000000..63498adb --- /dev/null +++ b/src/test/scala/chiselTests/stage/phases/EmitterSpec.scala @@ -0,0 +1,60 @@ +// See LICENSE for license details. + +package chiselTests.stage.phases + +import org.scalatest.{FlatSpec, Matchers} + +import chisel3.experimental.RawModule +import chisel3.stage.{ChiselCircuitAnnotation, ChiselGeneratorAnnotation, ChiselOutputFileAnnotation} +import chisel3.stage.phases.{Convert, Elaborate, Emitter} + +import firrtl.{AnnotationSeq, EmittedFirrtlCircuitAnnotation} +import firrtl.annotations.DeletedAnnotation +import firrtl.options.{Phase, TargetDirAnnotation} + +import java.io.File + +class EmitterSpec extends FlatSpec with Matchers { + + class FooModule extends RawModule { override val desiredName = "Foo" } + class BarModule extends RawModule { override val desiredName = "Bar" } + + class Fixture { val phase: Phase = new Emitter } + + behavior of classOf[Emitter].toString + + it should "do nothing if no ChiselOutputFileAnnotations are present" in new Fixture { + val dir = new File("test_run_dir/EmitterSpec") + val annotations = (new Elaborate).transform(Seq( TargetDirAnnotation(dir.toString), + ChiselGeneratorAnnotation(() => new FooModule) )) + val annotationsx = phase.transform(annotations) + + val Seq(fooFile, barFile) = Seq("Foo.fir", "Bar.fir").map(f => new File(dir + "/" + f)) + + info(s"$fooFile does not exist") + fooFile should not (exist) + + info("annotations are unmodified") + annotationsx.toSeq should be (annotations.toSeq) + } + + it should "emit a ChiselCircuitAnnotation to a specific file" in new Fixture { + val dir = new File("test_run_dir/EmitterSpec") + val circuit = (new Elaborate) + .transform(Seq(ChiselGeneratorAnnotation(() => new BarModule))) + .collectFirst{ case a: ChiselCircuitAnnotation => a} + .get + val annotations = phase.transform(Seq( TargetDirAnnotation(dir.toString), + circuit, + ChiselOutputFileAnnotation("Baz") )) + + val bazFile = new File(dir + "/Baz.fir") + + info(s"$bazFile exists") + bazFile should (exist) + + info("a deleted EmittedFirrtlCircuitAnnotation should be generated") + annotations.collect{ case a @ DeletedAnnotation(_, _: EmittedFirrtlCircuitAnnotation) => a }.size should be (1) + } + +} |
