diff options
| author | Adam Izraelevitz | 2016-05-02 14:59:51 -0700 |
|---|---|---|
| committer | jackkoenig | 2016-05-12 22:42:06 -0700 |
| commit | f07baed2bc46e107250c317f290af48747a98322 (patch) | |
| tree | a63c5d2477eabccab85dc6780f289fc24cbcad5c /src/test | |
| parent | 0ee659e85c7fe46c2678a49866ef1eca8f4a2c65 (diff) | |
Restructured Compiler to use Transforms. Added an InlineInstance pass.
Transforms are new unit of modularity within the compiler.
Diffstat (limited to 'src/test')
| -rw-r--r-- | src/test/resources/features/ChirrtlMems.fir (renamed from src/test/resources/features/CHIRRTLMems.fir) | 0 | ||||
| -rw-r--r-- | src/test/resources/features/Printf.fir | 4 | ||||
| -rw-r--r-- | src/test/scala/firrtlTests/AnnotationTests.scala | 57 | ||||
| -rw-r--r-- | src/test/scala/firrtlTests/ChirrtlSpec.scala | 2 | ||||
| -rw-r--r-- | src/test/scala/firrtlTests/CompilerTests.scala | 120 | ||||
| -rw-r--r-- | src/test/scala/firrtlTests/FirrtlSpec.scala | 23 | ||||
| -rw-r--r-- | src/test/scala/firrtlTests/InlineInstancesTests.scala | 272 | ||||
| -rw-r--r-- | src/test/scala/firrtlTests/PassTests.scala | 82 |
8 files changed, 552 insertions, 8 deletions
diff --git a/src/test/resources/features/CHIRRTLMems.fir b/src/test/resources/features/ChirrtlMems.fir index bd92c872..bd92c872 100644 --- a/src/test/resources/features/CHIRRTLMems.fir +++ b/src/test/resources/features/ChirrtlMems.fir diff --git a/src/test/resources/features/Printf.fir b/src/test/resources/features/Printf.fir index d0c1c775..6e11c64e 100644 --- a/src/test/resources/features/Printf.fir +++ b/src/test/resources/features/Printf.fir @@ -1,5 +1,5 @@ -circuit Top : - module Top : +circuit Printf : + module Printf : input clk : Clock input reset : UInt<1> diff --git a/src/test/scala/firrtlTests/AnnotationTests.scala b/src/test/scala/firrtlTests/AnnotationTests.scala new file mode 100644 index 00000000..81a74b54 --- /dev/null +++ b/src/test/scala/firrtlTests/AnnotationTests.scala @@ -0,0 +1,57 @@ +package firrtlTests + +import java.io.StringWriter + +import org.scalatest.FlatSpec +import org.scalatest.Matchers +import org.scalatest.junit.JUnitRunner + +import firrtl.{Parser,Circuit} +import firrtl.{ + Named, + ModuleName, + ComponentName, + CircuitAnnotation, + StringAnnotation, + BrittleCircuitAnnotation, + UnknownCAKind, + Compiler, + CompilerResult, + Annotation, + RenameMap, + VerilogCompiler +} + +/** + * An example methodology for testing Firrtl annotations. + */ +abstract class AnnotationSpec extends FlatSpec { + def parse (s: String): Circuit = Parser.parse(s.split("\n").toIterator) + def compiler: Compiler + def input: String + def getResult (annotation: CircuitAnnotation): CompilerResult = { + val writer = new StringWriter() + compiler.compile(parse(input), Seq(annotation), writer) + } +} + + +/** + * An example test for testing module annotations + */ +class BrittleModuleAnnotationSpec extends AnnotationSpec with Matchers { + val compiler = new VerilogCompiler() + val input = +""" +circuit Top : + module Top : + input a : UInt<1>[2] + node x = a +""" + val message = "This is Top" + val map: Map[Named, Annotation] = Map(ModuleName("Top") -> StringAnnotation(message)) + val annotation = BrittleCircuitAnnotation(UnknownCAKind, map) + "The annotation" should "get passed through the compiler" in { + (getResult(annotation).annotations.head == annotation) should be (true) + } +} diff --git a/src/test/scala/firrtlTests/ChirrtlSpec.scala b/src/test/scala/firrtlTests/ChirrtlSpec.scala index 0059d7ed..858d43b6 100644 --- a/src/test/scala/firrtlTests/ChirrtlSpec.scala +++ b/src/test/scala/firrtlTests/ChirrtlSpec.scala @@ -73,6 +73,6 @@ class ChirrtlSpec extends FirrtlFlatSpec { } it should "compile and run" in { - runFirrtlTest("CHIRRTLMems", "/features") + runFirrtlTest("ChirrtlMems", "/features") } } diff --git a/src/test/scala/firrtlTests/CompilerTests.scala b/src/test/scala/firrtlTests/CompilerTests.scala new file mode 100644 index 00000000..f66b39e6 --- /dev/null +++ b/src/test/scala/firrtlTests/CompilerTests.scala @@ -0,0 +1,120 @@ +package firrtlTests + +import java.io.StringWriter + +import org.scalatest.FlatSpec +import org.scalatest.Matchers +import org.scalatest.junit.JUnitRunner + +import firrtl.{Parser,Circuit} +import firrtl.{ + HighFirrtlCompiler, + LowFirrtlCompiler, + VerilogCompiler, + Compiler +} + +/** + * An example methodology for testing Firrtl compilers. + * + * Given an input Firrtl circuit (expressed as a string), + * the compiler is executed. The output of the compiler + * should be compared against the check string. + */ +abstract class CompilerSpec extends FlatSpec { + def parse (s: String): Circuit = Parser.parse(s.split("\n").toIterator) + val writer = new StringWriter() + def compiler: Compiler + def input: String + def check: String + def getOutput: String = { + compiler.compile(parse(input), Seq.empty, writer) + writer.toString() + } +} + +/** + * An example test for testing the HighFirrtlCompiler. + * + * Given an input Firrtl circuit (expressed as a string), + * the compiler is executed. The output of the compiler + * is parsed again and compared (in-memory) to the parsed + * input. + */ +class HighFirrtlCompilerSpec extends CompilerSpec with Matchers { + val compiler = new HighFirrtlCompiler() + val input = +"""circuit Top : + module Top : + input a : UInt<1>[2] + node x = a +""" + val check = input + "Any circuit" should "match exactly to its input" in { + (parse(getOutput)) should be (parse(check)) + } +} + +/** + * An example test for testing the LoweringCompiler. + * + * Given an input Firrtl circuit (expressed as a string), + * the compiler is executed. The output of the compiler is + * a lowered version of the input circuit. The output is + * string compared to the correct lowered circuit. + */ +class LowFirrtlCompilerSpec extends CompilerSpec with Matchers { + val compiler = new LowFirrtlCompiler() + val input = +""" +circuit Top : + module Top : + input a : UInt<1>[2] + node x = a +""" + val check = Seq( + "circuit Top :", + " module Top :", + " input a_0 : UInt<1>", + " input a_1 : UInt<1>", + " node x_0 = a_0", + " node x_1 = a_1\n\n" + ).reduce(_ + "\n" + _) + "A circuit" should "match exactly to its lowered state" in { + (parse(getOutput)) should be (parse(check)) + } +} + +/** + * An example test for testing the VerilogCompiler. + * + * Given an input Firrtl circuit (expressed as a string), + * the compiler is executed. The output of the compiler is + * the corresponding Verilog. The output is string compared + * to the correct Verilog. + */ +class VerilogCompilerSpec extends CompilerSpec with Matchers { + val compiler = new VerilogCompiler() + val input = +""" +circuit Top : + module Top : + input a : UInt<1>[2] + output b : UInt<1>[2] + b <= a +""" + val check = Seq( + "module Top(", + " input a_0,", + " input a_1,", + " output b_0,", + " output b_1", + ");", + " assign b_0 = a_0;", + " assign b_1 = a_1;", + "endmodule\n" + ).reduce(_ + "\n" + _) + "A circuit's verilog output" should "match the given string" in { + (getOutput) should be (check) + } +} diff --git a/src/test/scala/firrtlTests/FirrtlSpec.scala b/src/test/scala/firrtlTests/FirrtlSpec.scala index 8e1dd8cb..c148b488 100644 --- a/src/test/scala/firrtlTests/FirrtlSpec.scala +++ b/src/test/scala/firrtlTests/FirrtlSpec.scala @@ -33,6 +33,7 @@ import com.typesafe.scalalogging.LazyLogging import scala.sys.process._ import org.scalatest._ import org.scalatest.prop._ +import scala.io.Source import firrtl._ @@ -101,6 +102,7 @@ trait BackendCompilationUtilities { "--Wno-fatal", "--trace", "-O2", + "--top-module", dutFile, "+define+TOP_TYPE=V" + dutFile, "-CFLAGS", s"""-Wno-undefined-bool-conversion -O2 -DTOP_TYPE=V$dutFile -include V$dutFile.h""", "-Mdir", dir.toString, @@ -129,15 +131,26 @@ trait BackendCompilationUtilities { trait FirrtlRunners extends BackendCompilationUtilities { lazy val cppHarness = new File(s"/top.cpp") - def compileFirrtlTest(prefix: String, srcDir: String): File = { + def compileFirrtlTest( + prefix: String, + srcDir: String, + annotations: Seq[CircuitAnnotation] = Seq.empty): File = { val testDir = createTempDirectory(prefix) copyResourceToFile(s"${srcDir}/${prefix}.fir", new File(testDir, s"${prefix}.fir")) - - Driver.compile(s"${testDir}/${prefix}.fir", s"${testDir}/${prefix}.v", VerilogCompiler) + + Driver.compile( + s"$testDir/$prefix.fir", + s"$testDir/$prefix.v", + new VerilogCompiler(), + Parser.IgnoreInfo, + annotations) testDir } - def runFirrtlTest(prefix: String, srcDir: String) { - val testDir = compileFirrtlTest(prefix, srcDir) + def runFirrtlTest( + prefix: String, + srcDir: String, + annotations: Seq[CircuitAnnotation] = Seq.empty) = { + val testDir = compileFirrtlTest(prefix, srcDir, annotations) val harness = new File(testDir, s"top.cpp") copyResourceToFile(cppHarness.toString, harness) diff --git a/src/test/scala/firrtlTests/InlineInstancesTests.scala b/src/test/scala/firrtlTests/InlineInstancesTests.scala new file mode 100644 index 00000000..52c01dc4 --- /dev/null +++ b/src/test/scala/firrtlTests/InlineInstancesTests.scala @@ -0,0 +1,272 @@ +package firrtlTests + +import java.io.StringWriter + +import org.scalatest.FlatSpec +import org.scalatest.Matchers +import org.scalatest.junit.JUnitRunner + +import firrtl.{Parser,Circuit} +import firrtl.passes.{PassExceptions,InlineCAKind} +import firrtl.{ + Named, + ModuleName, + ComponentName, + Annotation, + CircuitAnnotation, + TagAnnotation, + StickyCircuitAnnotation +} +import firrtl.passes.{InlineInstances, InlineCAKind} + + +/** + * Tests inline instances transformation + */ +class InlineInstancesTests extends HighTransformSpec { + val transform = InlineInstances + "The module Inline" should "be inlined" in { + val input = + """circuit Top : + | module Top : + | input a : UInt<32> + | output b : UInt<32> + | inst i of Inline + | i.a <= a + | b <= i.b + | module Inline : + | input a : UInt<32> + | output b : UInt<32> + | b <= a""".stripMargin + val check = + """circuit Top : + | module Top : + | input a : UInt<32> + | output b : UInt<32> + | wire i$a : UInt<32> + | wire i$b : UInt<32> + | i$b <= i$a + | i$a <= a + | b <= i$b + | module Inline : + | input a : UInt<32> + | output b : UInt<32> + | b <= a""".stripMargin + val writer = new StringWriter() + val map: Map[Named, Annotation] = Map(ModuleName("Inline") -> TagAnnotation) + val annotation = StickyCircuitAnnotation(InlineCAKind, map) + execute(writer, Seq(annotation), input, check) + } + + "The all instances of Simple" should "be inlined" in { + val input = + """circuit Top : + | module Top : + | input a : UInt<32> + | output b : UInt<32> + | inst i0 of Simple + | inst i1 of Simple + | i0.a <= a + | i1.a <= i0.b + | b <= i1.b + | module Simple : + | input a : UInt<32> + | output b : UInt<32> + | b <= a""".stripMargin + val check = + """circuit Top : + | module Top : + | input a : UInt<32> + | output b : UInt<32> + | wire i0$a : UInt<32> + | wire i0$b : UInt<32> + | i0$b <= i0$a + | wire i1$a : UInt<32> + | wire i1$b : UInt<32> + | i1$b <= i1$a + | i0$a <= a + | i1$a <= i0$b + | b <= i1$b + | module Simple : + | input a : UInt<32> + | output b : UInt<32> + | b <= a""".stripMargin + val writer = new StringWriter() + val map: Map[Named, Annotation] = Map(ModuleName("Simple") -> TagAnnotation) + val annotation = StickyCircuitAnnotation(InlineCAKind, map) + execute(writer, Seq(annotation), input, check) + } + + "Only one instance of Simple" should "be inlined" in { + val input = + """circuit Top : + | module Top : + | input a : UInt<32> + | output b : UInt<32> + | inst i0 of Simple + | inst i1 of Simple + | i0.a <= a + | i1.a <= i0.b + | b <= i1.b + | module Simple : + | input a : UInt<32> + | output b : UInt<32> + | b <= a""".stripMargin + val check = + """circuit Top : + | module Top : + | input a : UInt<32> + | output b : UInt<32> + | wire i0$a : UInt<32> + | wire i0$b : UInt<32> + | i0$b <= i0$a + | inst i1 of Simple + | i0$a <= a + | i1.a <= i0$b + | b <= i1.b + | module Simple : + | input a : UInt<32> + | output b : UInt<32> + | b <= a""".stripMargin + val writer = new StringWriter() + val map: Map[Named, Annotation] = Map(ComponentName("i0",ModuleName("Top")) -> TagAnnotation) + val annotation = StickyCircuitAnnotation(InlineCAKind, map) + execute(writer, Seq(annotation), input, check) + } + + "All instances of A" should "be inlined" in { + val input = + """circuit Top : + | module Top : + | input a : UInt<32> + | output b : UInt<32> + | inst i0 of A + | inst i1 of B + | i0.a <= a + | i1.a <= i0.b + | b <= i1.b + | module A : + | input a : UInt<32> + | output b : UInt<32> + | b <= a + | module B : + | input a : UInt<32> + | output b : UInt<32> + | inst i of A + | i.a <= a + | b <= i.b""".stripMargin + val check = + """circuit Top : + | module Top : + | input a : UInt<32> + | output b : UInt<32> + | wire i0$a : UInt<32> + | wire i0$b : UInt<32> + | i0$b <= i0$a + | inst i1 of B + | i0$a <= a + | i1.a <= i0$b + | b <= i1.b + | module A : + | input a : UInt<32> + | output b : UInt<32> + | b <= a + | module B : + | input a : UInt<32> + | output b : UInt<32> + | wire i$a : UInt<32> + | wire i$b : UInt<32> + | i$b <= i$a + | i$a <= a + | b <= i$b""".stripMargin + val writer = new StringWriter() + val map: Map[Named, Annotation] = Map(ModuleName("A") -> TagAnnotation) + val annotation = StickyCircuitAnnotation(InlineCAKind, map) + execute(writer, Seq(annotation), input, check) + } + + + // ---- Errors ---- + // 1) ext module + "External module" should "not be inlined" in { + val input = + """circuit Top : + | module Top : + | input a : UInt<32> + | output b : UInt<32> + | inst i of A + | i.a <= a + | b <= i.b + | extmodule A : + | input a : UInt<32> + | output b : UInt<32>""".stripMargin + val writer = new StringWriter() + val map: Map[Named, Annotation] = Map(ModuleName("A") -> TagAnnotation) + val annotation = StickyCircuitAnnotation(InlineCAKind,map) + failingexecute(writer, Seq(annotation), input) + } + // 2) ext instance + "External instance" should "not be inlined" in { + val input = + """circuit Top : + | module Top : + | input a : UInt<32> + | output b : UInt<32> + | inst i of A + | i.a <= a + | b <= i.b + | extmodule A : + | input a : UInt<32> + | output b : UInt<32>""".stripMargin + val writer = new StringWriter() + val map: Map[Named, Annotation] = Map(ModuleName("A") -> TagAnnotation) + val annotation = StickyCircuitAnnotation(InlineCAKind,map) + failingexecute(writer, Seq(annotation), input) + } + // 3) no module + "Inlined module" should "exist" in { + val input = + """circuit Top : + | module Top : + | input a : UInt<32> + | output b : UInt<32> + | b <= a""".stripMargin + val writer = new StringWriter() + val map: Map[Named, Annotation] = Map(ModuleName("A") -> TagAnnotation) + val annotation = StickyCircuitAnnotation(InlineCAKind,map) + failingexecute(writer, Seq(annotation), input) + } + // 4) no inst + "Inlined instance" should "exist" in { + val input = + """circuit Top : + | module Top : + | input a : UInt<32> + | output b : UInt<32> + | b <= a""".stripMargin + val writer = new StringWriter() + val map: Map[Named, Annotation] = Map(ModuleName("A") -> TagAnnotation) + val annotation = StickyCircuitAnnotation(InlineCAKind,map) + failingexecute(writer, Seq(annotation), input) + } +} + +// Execution driven tests for inlining modules +class InlineInstancesIntegrationSpec extends FirrtlPropSpec { + // Shorthand for creating annotations to inline modules + def inlineModules(names: Seq[String]): Seq[CircuitAnnotation] = + Seq(StickyCircuitAnnotation(InlineCAKind, names.map(n => ModuleName(n) -> TagAnnotation).toMap)) + + case class Test(name: String, dir: String, ann: Seq[CircuitAnnotation]) + + val runTests = Seq( + Test("GCDTester", "/integration", inlineModules(Seq("DecoupledGCD"))) + ) + + runTests foreach { test => + property(s"${test.name} should execute correctly with inlining") { + println(s"Got annotations ${test.ann}") + runFirrtlTest(test.name, test.dir, test.ann) + } + } +} diff --git a/src/test/scala/firrtlTests/PassTests.scala b/src/test/scala/firrtlTests/PassTests.scala new file mode 100644 index 00000000..38ecc7c3 --- /dev/null +++ b/src/test/scala/firrtlTests/PassTests.scala @@ -0,0 +1,82 @@ +package firrtlTests + +import com.typesafe.scalalogging.LazyLogging +import java.io.{StringWriter,Writer} +import org.scalatest.{FlatSpec, Matchers} +import org.scalatest.junit.JUnitRunner +import firrtl.{Parser,Circuit,FIRRTLEmitter} +import firrtl.Parser.IgnoreInfo +import firrtl.passes.{Pass, PassExceptions} +import firrtl.{ + Transform, + CircuitAnnotation, + TransformResult, + SimpleRun, + Chisel3ToHighFirrtl, + IRToWorkingIR, + ResolveAndCheck, + HighFirrtlToMiddleFirrtl, + MiddleFirrtlToLowFirrtl, + EmitFirrtl, + Compiler +} + + +// An example methodology for testing Firrtl Passes +// Spec class should extend this class +abstract class SimpleTransformSpec extends FlatSpec with Matchers with Compiler with LazyLogging { + // Utility function + def parse(s: String): Circuit = Parser.parse(s.split("\n").toIterator, infoMode = IgnoreInfo) + + // Executes the test. Call in tests. + def execute(writer: Writer, annotations: Seq[CircuitAnnotation], input: String, check: String) = { + compile(parse(input), annotations, writer) + logger.debug(writer.toString) + logger.debug(check) + (parse(writer.toString)) should be (parse(check)) + } + // Executes the test, should throw an error + def failingexecute(writer: Writer, annotations: Seq[CircuitAnnotation], input: String) = { + intercept[PassExceptions] { + compile(parse(input), annotations, writer) + } + } +} + +trait LowTransformSpec extends SimpleTransformSpec { + def transform: Transform + def transforms (writer: Writer) = Seq( + new Chisel3ToHighFirrtl(), + new IRToWorkingIR(), + new ResolveAndCheck(), + new HighFirrtlToMiddleFirrtl(), + new MiddleFirrtlToLowFirrtl(), + new ResolveAndCheck(), + transform, + new EmitFirrtl(writer) + ) +} + +trait MiddleTransformSpec extends SimpleTransformSpec { + def transform: Transform + def transforms (writer: Writer) = Seq( + new Chisel3ToHighFirrtl(), + new IRToWorkingIR(), + new ResolveAndCheck(), + new HighFirrtlToMiddleFirrtl(), + new ResolveAndCheck(), + transform, + new EmitFirrtl(writer) + ) +} + +trait HighTransformSpec extends SimpleTransformSpec { + def transform: Transform + def transforms (writer: Writer) = Seq( + new Chisel3ToHighFirrtl(), + new IRToWorkingIR(), + new ResolveAndCheck(), + transform, + new EmitFirrtl(writer) + ) +} |
