aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorAdam Izraelevitz2016-05-02 14:59:51 -0700
committerjackkoenig2016-05-12 22:42:06 -0700
commitf07baed2bc46e107250c317f290af48747a98322 (patch)
treea63c5d2477eabccab85dc6780f289fc24cbcad5c /src/test
parent0ee659e85c7fe46c2678a49866ef1eca8f4a2c65 (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.fir4
-rw-r--r--src/test/scala/firrtlTests/AnnotationTests.scala57
-rw-r--r--src/test/scala/firrtlTests/ChirrtlSpec.scala2
-rw-r--r--src/test/scala/firrtlTests/CompilerTests.scala120
-rw-r--r--src/test/scala/firrtlTests/FirrtlSpec.scala23
-rw-r--r--src/test/scala/firrtlTests/InlineInstancesTests.scala272
-rw-r--r--src/test/scala/firrtlTests/PassTests.scala82
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)
+ )
+}