aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjackkoenig2016-03-03 12:23:57 -0800
committerjackkoenig2016-03-03 12:23:57 -0800
commit4d77e3ac1020b404e5a0f5d68cd36fb3a07ef333 (patch)
tree5e78244b61d87d0256efe974a7a352285f745a65 /src
parent0aa246385d1d2eabafce0e659d6438a38c3b6519 (diff)
Add some integration tests: successful compilation and execution
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/firrtl/Driver.scala2
l---------src/test/resources/integration1
-rw-r--r--src/test/scala/firrtlTests/FirrtlSpec.scala124
-rw-r--r--src/test/scala/firrtlTests/IntegrationSpec.scala26
4 files changed, 152 insertions, 1 deletions
diff --git a/src/main/scala/firrtl/Driver.scala b/src/main/scala/firrtl/Driver.scala
index f397a2ac..c93bb54e 100644
--- a/src/main/scala/firrtl/Driver.scala
+++ b/src/main/scala/firrtl/Driver.scala
@@ -47,7 +47,7 @@ Options:
"""
private val defaultOptions = Map[Symbol, Any]().withDefaultValue(false)
- private def compile(input: String, output: String, compiler: Compiler)
+ def compile(input: String, output: String, compiler: Compiler)
{
val parsedInput = Parser.parse(input, Source.fromFile(input).getLines)
val writerOutput = new PrintWriter(new File(output))
diff --git a/src/test/resources/integration b/src/test/resources/integration
new file mode 120000
index 00000000..5e63f954
--- /dev/null
+++ b/src/test/resources/integration
@@ -0,0 +1 @@
+../../../test/integration \ No newline at end of file
diff --git a/src/test/scala/firrtlTests/FirrtlSpec.scala b/src/test/scala/firrtlTests/FirrtlSpec.scala
new file mode 100644
index 00000000..438a5282
--- /dev/null
+++ b/src/test/scala/firrtlTests/FirrtlSpec.scala
@@ -0,0 +1,124 @@
+
+package firrtlTests
+
+import java.io._
+
+import scala.sys.process._
+import org.scalatest._
+import org.scalatest.prop._
+
+import firrtl._
+
+// This trait is borrowed from Chisel3, ideally this code should only exist in one location
+trait BackendCompilationUtilities {
+ /** Create a temporary directory with the prefix name. Exists here because it doesn't in Java 6.
+ */
+ def createTempDirectory(prefix: String): File = {
+ val temp = File.createTempFile(prefix, "")
+ if (!temp.delete()) {
+ throw new IOException(s"Unable to delete temp file '$temp'")
+ }
+ if (!temp.mkdir()) {
+ throw new IOException(s"Unable to create temp directory '$temp'")
+ }
+ temp
+ }
+
+ /** Copy the contents of a resource to a destination file.
+ */
+ def copyResourceToFile(name: String, file: File) {
+ val in = getClass().getResourceAsStream(name)
+ if (in == null) {
+ throw new FileNotFoundException(s"Resource '$name'")
+ }
+ val out = new FileOutputStream(file)
+ Iterator.continually(in.read).takeWhile(-1 !=).foreach(out.write)
+ out.close()
+ }
+
+
+ def makeHarness(template: String => String, post: String)(f: File): File = {
+ val prefix = f.toString.split("/").last
+ val vf = new File(f.toString + post)
+ val w = new FileWriter(vf)
+ w.write(template(prefix))
+ w.close()
+ vf
+ }
+
+ /** Generates a Verilator invocation to convert Verilog sources to C++
+ * simulation sources.
+ *
+ * The Verilator prefix will be V$dutFile, and running this will generate
+ * C++ sources and headers as well as a makefile to compile them.
+ *
+ * Verilator will automatically locate the top-level module as the one among
+ * all the files which are not included elsewhere. If multiple ones exist,
+ * the compilation will fail.
+ *
+ * @param dutFile name of the DUT .v without the .v extension
+ * @param dir output directory
+ * @param vSources list of additional Verilog sources to compile
+ * @param cppHarness C++ testharness to compile/link against
+ */
+ def verilogToCpp(
+ dutFile: String,
+ dir: File,
+ vSources: Seq[File],
+ cppHarness: File): ProcessBuilder =
+
+ Seq("verilator",
+ "--cc", s"$dutFile.v") ++
+ vSources.map(file => Seq("-v", file.toString)).flatten ++
+ Seq("--assert",
+ "--Wno-fatal",
+ "--trace",
+ "-O2",
+ "+define+TOP_TYPE=V" + dutFile,
+ "-CFLAGS", s"""-Wno-undefined-bool-conversion -O2 -DTOP_TYPE=V$dutFile -include V$dutFile.h""",
+ "-Mdir", dir.toString,
+ "--exe", cppHarness.toString)
+
+ def cppToExe(prefix: String, dir: File): ProcessBuilder =
+ Seq("make", "-C", dir.toString, "-j", "-f", s"V${prefix}.mk", s"V${prefix}")
+
+ def executeExpectingFailure(
+ prefix: String,
+ dir: File,
+ assertionMsg: String = "Assertion failed"): Boolean = {
+ var triggered = false
+ val e = Process(s"./V${prefix}", dir) !
+ ProcessLogger(line => {
+ triggered = triggered || line.contains(assertionMsg)
+ System.out.println(line)
+ })
+ triggered
+ }
+
+ def executeExpectingSuccess(prefix: String, dir: File): Boolean = {
+ !executeExpectingFailure(prefix, dir)
+ }
+}
+
+trait FirrtlRunners extends BackendCompilationUtilities {
+ lazy val cpp = new File(s"/integration/top.cpp")
+ def compileFirrtlTest(prefix: String, srcDir: String): 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)
+ testDir
+ }
+ def runFirrtlTest(prefix: String, srcDir: String) {
+ val testDir = compileFirrtlTest(prefix, srcDir)
+ val harness = new File(testDir, s"top.cpp")
+ copyResourceToFile(cpp.toString, harness)
+
+ verilogToCpp(prefix, testDir, Seq(), harness).!
+ cppToExe(prefix, testDir).!
+ executeExpectingSuccess(prefix, testDir)
+ }
+}
+
+class FirrtlPropSpec extends PropSpec with PropertyChecks with FirrtlRunners
+
diff --git a/src/test/scala/firrtlTests/IntegrationSpec.scala b/src/test/scala/firrtlTests/IntegrationSpec.scala
new file mode 100644
index 00000000..eb5a7fa1
--- /dev/null
+++ b/src/test/scala/firrtlTests/IntegrationSpec.scala
@@ -0,0 +1,26 @@
+
+package firrtlTests
+
+import org.scalatest._
+import org.scalatest.prop._
+
+class IntegrationSpec extends FirrtlPropSpec {
+
+ case class Test(name: String, dir: String)
+
+ val runTests = Seq(Test("GCDTester", "/integration"))
+
+ runTests foreach { test =>
+ property(s"${test.name} should execute correctly") {
+ runFirrtlTest(test.name, test.dir)
+ }
+ }
+
+ val compileTests = Seq(Test("rocket", "/regress"), Test("rocket-firrtl", "/regress"))
+
+ compileTests foreach { test =>
+ property(s"${test.name} should compile to Verilog") {
+ compileFirrtlTest(test.name, test.dir)
+ }
+ }
+}