summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Waterman2015-12-10 22:40:46 -0800
committerAndrew Waterman2015-12-10 22:40:46 -0800
commitf094430e20d7db5fed60e0a306ab22169d705d71 (patch)
tree06815b9314650e40816d41eaff3989fdd2000a21 /src
parent035a30d25cdd955af6385c1334826781b17d894c (diff)
parent2785c3337a323e343141fd6a7fe4d2468e7feb34 (diff)
Merge pull request #61 from ucb-bar/multivtest
Refactor test code generation, add support for additional .v files
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/Chisel/Driver.scala75
-rw-r--r--src/main/scala/Chisel/testers/TesterDriver.scala23
-rw-r--r--src/test/scala/chiselTests/Harness.scala36
3 files changed, 71 insertions, 63 deletions
diff --git a/src/main/scala/Chisel/Driver.scala b/src/main/scala/Chisel/Driver.scala
index a31786d9..7f950025 100644
--- a/src/main/scala/Chisel/Driver.scala
+++ b/src/main/scala/Chisel/Driver.scala
@@ -8,26 +8,20 @@ import java.io._
import internal._
import firrtl._
-trait FileSystemUtilities {
- def writeTempFile(pre: String, post: String, contents: String): File = {
- val t = File.createTempFile(pre, post)
- val w = new FileWriter(t)
- w.write(contents)
- w.close()
- t
- }
-
- // This "fire-and-forgets" the method, which can be lazily read through
- // a Stream[String], and accumulates all errors on a StringBuffer
- def sourceFilesAt(baseDir: String): (Stream[String], StringBuffer) = {
- val buffer = new StringBuffer()
- val cmd = Seq("find", baseDir, "-name", "*.scala", "-type", "f")
- val lines = cmd lines_! ProcessLogger(buffer append _)
- (lines, buffer)
+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
}
-}
-trait BackendCompilationUtilities {
def makeHarness(template: String => String, post: String)(f: File): File = {
val prefix = f.toString.split("/").last
val vf = new File(f.toString + post)
@@ -46,22 +40,38 @@ trait BackendCompilationUtilities {
dir)
}
+ /** 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(
- prefix: String,
+ dutFile: String,
dir: File,
- vDut: File,
- cppHarness: File,
- vH: File): ProcessBuilder =
+ vSources: Seq[File],
+ cppHarness: File): ProcessBuilder =
+
Seq("verilator",
- "--cc", vDut.toString,
- "--assert",
- "--Wno-fatal",
- "--trace",
- "-O2",
- "+define+TOP_TYPE=V" + prefix,
- "-CFLAGS", s"""-Wno-undefined-bool-conversion -O2 -DTOP_TYPE=V$prefix -include ${vH.toString}""",
- "-Mdir", dir.toString,
- "--exe", cppHarness.toString)
+ "--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}")
@@ -79,10 +89,9 @@ trait BackendCompilationUtilities {
def executeExpectingSuccess(prefix: String, dir: File): Boolean = {
!executeExpectingFailure(prefix, dir)
}
-
}
-object Driver extends FileSystemUtilities with BackendCompilationUtilities {
+object Driver extends BackendCompilationUtilities {
/** Elaborates the Module specified in the gen function into a Circuit
*
diff --git a/src/main/scala/Chisel/testers/TesterDriver.scala b/src/main/scala/Chisel/testers/TesterDriver.scala
index d104782a..364480a7 100644
--- a/src/main/scala/Chisel/testers/TesterDriver.scala
+++ b/src/main/scala/Chisel/testers/TesterDriver.scala
@@ -5,33 +5,30 @@ import Chisel._
import scala.sys.process._
import java.io.File
-object TesterDriver extends BackendCompilationUtilities with FileSystemUtilities {
+object TesterDriver extends BackendCompilationUtilities {
/** For use with modules that should successfully be elaborated by the
* frontend, and which can be turned into executeables with assertions. */
- def execute(t: () => BasicTester): Boolean = {
+ def execute(t: () => BasicTester, additionalVSources: Seq[File] = Seq()): Boolean = {
// Invoke the chisel compiler to get the circuit's IR
val circuit = Driver.elaborate(t)
// Set up a bunch of file handlers based on a random temp filename,
// plus the quirks of Verilator's naming conventions
val target = circuit.name
- val fname = File.createTempFile(target, "")
- val path = fname.getParentFile.toString
+
+ val path = createTempDirectory(target)
+ val fname = File.createTempFile(target, "", path)
val prefix = fname.toString.split("/").last
- val dir = new File(System.getProperty("java.io.tmpdir"))
- val vDut = new File(fname.toString + ".v")
- val vH = new File(path + "/V" + prefix + ".h")
- val cppHarness = new File(fname.toString + ".cpp")
+ val cppHarness = new File(System.getProperty("user.dir") + "/src/main/resources/top.cpp")
// For now, dump the IR out to a file
Driver.dumpFirrtl(circuit, Some(new File(fname.toString + ".fir")))
// Use sys.Process to invoke a bunch of backend stuff, then run the resulting exe
- if (((new File(System.getProperty("user.dir") + "/src/main/resources/top.cpp") #> cppHarness) #&&
- firrtlToVerilog(prefix, dir) #&&
- verilogToCpp(prefix, dir, vDut, cppHarness, vH) #&&
- cppToExe(prefix, dir)).! == 0) {
- executeExpectingSuccess(prefix, dir)
+ if ((firrtlToVerilog(prefix, path) #&&
+ verilogToCpp(prefix, path, additionalVSources, cppHarness) #&&
+ cppToExe(prefix, path)).! == 0) {
+ executeExpectingSuccess(prefix, path)
} else {
false
}
diff --git a/src/test/scala/chiselTests/Harness.scala b/src/test/scala/chiselTests/Harness.scala
index 31a219e4..1a628e6c 100644
--- a/src/test/scala/chiselTests/Harness.scala
+++ b/src/test/scala/chiselTests/Harness.scala
@@ -44,34 +44,36 @@ int main(int argc, char **argv, char **env) {
}
""", ".cpp") _
- val dir = new File(System.getProperty("java.io.tmpdir"))
-
- def simpleHarnessBackend(make: File => File): String = {
+ /** Compiles a C++ emulator from Verilog and returns the path to the
+ * executable and the executable filename as a tuple.
+ */
+ def simpleHarnessBackend(make: File => File): (File, String) = {
val target = "test"
- val fname = File.createTempFile(target, "")
- val path = fname.getParentFile.toString
+ val path = createTempDirectory(target)
+ val fname = File.createTempFile(target, "", path)
val prefix = fname.toString.split("/").last
- val vDut = make(fname)
- val vH = new File(path + "/V" + prefix + ".h")
+
val cppHarness = makeCppHarness(fname)
- verilogToCpp(target, dir, vDut, cppHarness, vH).!
- cppToExe(prefix, dir).!
- prefix
+
+ make(fname)
+ verilogToCpp(prefix, path, Seq(), cppHarness).!
+ cppToExe(prefix, path).!
+ (path, prefix)
}
property("Test making trivial verilog harness and executing") {
- val prefix = simpleHarnessBackend(makeTrivialVerilog)
+ val (path, prefix) = simpleHarnessBackend(makeTrivialVerilog)
- assert(executeExpectingSuccess(prefix, dir))
+ assert(executeExpectingSuccess(prefix, path))
}
property("Test that assertion failues in Verilog are caught") {
- val prefix = simpleHarnessBackend(makeFailingVerilog)
+ val (path, prefix) = simpleHarnessBackend(makeFailingVerilog)
- assert(!executeExpectingSuccess(prefix, dir))
- assert(executeExpectingFailure(prefix, dir))
- assert(executeExpectingFailure(prefix, dir, "My specific, expected error message!"))
- assert(!executeExpectingFailure(prefix, dir, "A string that doesn't match any test output"))
+ assert(!executeExpectingSuccess(prefix, path))
+ assert(executeExpectingFailure(prefix, path))
+ assert(executeExpectingFailure(prefix, path, "My specific, expected error message!"))
+ assert(!executeExpectingFailure(prefix, path, "A string that doesn't match any test output"))
}
}