aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authorJim Lawson2017-01-27 12:19:38 -0800
committerGitHub2017-01-27 12:19:38 -0800
commit91570ec8d7ab6bede24eb8da4a7e005f00ac076f (patch)
tree1abe0499ff53baa702610f8aaaf5d2ee7b7cbe0d /src/main
parent6c00f2c880a536b61196e7ec63fc861d69c8b764 (diff)
Move BackendCompilationUtilities into a util package for use by chisel3. (#400)
* Move BackendCompilationUtilities into a util package for use by chisel3. Some of this could be moved into a more general tools package, but since chisel3 already has a dependency on firrtl ... * Push util down into firrtl so as not to conflict with scala.util.
Diffstat (limited to 'src/main')
-rw-r--r--src/main/scala/firrtl/util/BackendCompilationUtilities.scala130
1 files changed, 130 insertions, 0 deletions
diff --git a/src/main/scala/firrtl/util/BackendCompilationUtilities.scala b/src/main/scala/firrtl/util/BackendCompilationUtilities.scala
new file mode 100644
index 00000000..c1ead8b9
--- /dev/null
+++ b/src/main/scala/firrtl/util/BackendCompilationUtilities.scala
@@ -0,0 +1,130 @@
+// See LICENSE for license details.
+
+package firrtl.util
+
+import scala.sys.process._
+import java.io._
+
+import firrtl._
+import firrtl.{Driver, ExecutionOptionsManager}
+
+import scala.sys.process.{ProcessBuilder, ProcessLogger}
+
+
+trait BackendCompilationUtilities {
+ /** 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()
+ }
+
+ /** 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
+ }
+
+ 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
+ }
+
+ /**
+ * compule chirrtl to verilog by using a separate process
+ *
+ * @param prefix basename of the file
+ * @param dir directory where file lives
+ * @return true if compiler completed successfully
+ */
+ def firrtlToVerilog(prefix: String, dir: File): ProcessBuilder = {
+ Process(
+ Seq("firrtl",
+ "-i", s"$prefix.fir",
+ "-o", s"$prefix.v",
+ "-X", "verilog"),
+ 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(
+ dutFile: String,
+ dir: File,
+ vSources: Seq[File],
+ cppHarness: File
+ ): ProcessBuilder = {
+ val topModule = dutFile
+ val command = Seq("verilator",
+ "--cc", s"$dutFile.v") ++
+ vSources.map(file => Seq("-v", file.toString)).flatten ++
+ Seq("--assert",
+ "-Wno-fatal",
+ "-Wno-WIDTH",
+ "-Wno-STMTDLY",
+ "--trace",
+ "-O1",
+ "--top-module", topModule,
+ "+define+TOP_TYPE=V" + dutFile,
+ s"+define+PRINTF_COND=!$topModule.reset",
+ s"+define+STOP_COND=!$topModule.reset",
+ "-CFLAGS",
+ s"""-Wno-undefined-bool-conversion -O1 -DTOP_TYPE=V$dutFile -include V$dutFile.h""",
+ "-Mdir", dir.toString,
+ "--exe", cppHarness.toString)
+ System.out.println(s"${command.mkString(" ")}") // scalastyle:ignore regex
+ command
+ }
+
+ 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 = ""): Boolean = {
+ var triggered = false
+ val assertionMessageSupplied = assertionMsg != ""
+ val e = Process(s"./V${prefix}", dir) !
+ ProcessLogger(line => {
+ triggered = triggered || (assertionMessageSupplied && line.contains(assertionMsg))
+ System.out.println(line) // scalastyle:ignore regex
+ })
+ // Fail if a line contained an assertion or if we get a non-zero exit code
+ // or, we get a SIGABRT (assertion failure) and we didn't provide a specific assertion message
+ triggered || (e != 0 && (e != 134 || !assertionMessageSupplied))
+ }
+
+ def executeExpectingSuccess(prefix: String, dir: File): Boolean = {
+ !executeExpectingFailure(prefix, dir)
+ }
+}