From 24ad38ab28b888e73217a5532cac2f0d2b9a4bc2 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Wed, 1 Feb 2017 10:28:43 -0800 Subject: Move backend compilation utilities (#400) * Move copyResourceToFile() to BackendCompilationUtilities. * Move BackendCompilationUtilities into a firrtl util package. 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. * Use new createTestDirectory. Fixes #452. --- src/main/scala/chisel3/Driver.scala | 120 +--------------------- src/main/scala/chisel3/compatibility.scala | 2 +- src/main/scala/chisel3/testers/TesterDriver.scala | 17 +-- src/test/scala/chiselTests/Harness.scala | 7 +- 4 files changed, 12 insertions(+), 134 deletions(-) diff --git a/src/main/scala/chisel3/Driver.scala b/src/main/scala/chisel3/Driver.scala index e88afc1f..b2acc946 100644 --- a/src/main/scala/chisel3/Driver.scala +++ b/src/main/scala/chisel3/Driver.scala @@ -4,12 +4,12 @@ package chisel3 import chisel3.internal.firrtl.Emitter -import scala.sys.process._ import java.io._ import net.jcazevedo.moultingyaml._ import internal.firrtl._ import firrtl._ +import firrtl.util.{ BackendCompilationUtilities => FirrtlBackendCompilationUtilities } import _root_.firrtl.annotations.AnnotationYamlProtocol._ @@ -18,7 +18,7 @@ import _root_.firrtl.annotations.AnnotationYamlProtocol._ * By default firrtl is automatically run after chisel. an [[ExecutionOptionsManager]] * is needed to manage options. It can parser command line arguments or coordinate * multiple chisel toolchain tools options. - * + * * @example * {{{ * val optionsManager = new ExecutionOptionsManager("chisel3") @@ -37,29 +37,7 @@ import _root_.firrtl.annotations.AnnotationYamlProtocol._ */ import BuildInfo._ -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 - } - - 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 - } - +trait BackendCompilationUtilities extends FirrtlBackendCompilationUtilities { /** Compile Chirrtl to Verilog by invoking Firrtl inside the same JVM * * @param prefix basename of the file @@ -77,98 +55,6 @@ trait BackendCompilationUtilities { case _: FirrtlExecutionFailure => false } } - - /** Compile Chirrtl to Verilog by invoking Firrtl on the command line - * - * @param prefix basename of the file - * @param dir directory where file lives - * @return external process that can invoke Firrtl - */ - @deprecated("Use compileFirrtlToVerilog instead", "chisel3") - 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. - * - * @param dutFile name of the DUT .v without the .v extension - * @param topModule of the top-level module in the design - * @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, - topModule: String, - dir: File, - vSources: Seq[File], - cppHarness: File - ): ProcessBuilder = { - val blackBoxVerilogList = { - val list_file = new File(dir, firrtl.transforms.BlackBoxSourceHelper.FileListName) - if(list_file.exists()) { - Seq("-f", list_file.getAbsolutePath) - } - else { - Seq.empty[String] - } - } - val command = Seq( - "verilator", - "--cc", s"$dutFile.v" - ) ++ - blackBoxVerilogList ++ - 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 -DVL_USER_FINISH -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) - } } /** diff --git a/src/main/scala/chisel3/compatibility.scala b/src/main/scala/chisel3/compatibility.scala index d7ce7f24..d338d9ab 100644 --- a/src/main/scala/chisel3/compatibility.scala +++ b/src/main/scala/chisel3/compatibility.scala @@ -177,7 +177,7 @@ package object Chisel { // scalastyle:ignore package.object.name implicit class fromBooleanToLiteral(val x: Boolean) extends chisel3.core.fromBooleanToLiteral(x) implicit class fromIntToWidth(val x: Int) extends chisel3.core.fromIntToWidth(x) - type BackendCompilationUtilities = chisel3.BackendCompilationUtilities + type BackendCompilationUtilities = firrtl.util.BackendCompilationUtilities val Driver = chisel3.Driver val ImplicitConversions = chisel3.util.ImplicitConversions diff --git a/src/main/scala/chisel3/testers/TesterDriver.scala b/src/main/scala/chisel3/testers/TesterDriver.scala index bcbb9cd3..fd3ad9ba 100644 --- a/src/main/scala/chisel3/testers/TesterDriver.scala +++ b/src/main/scala/chisel3/testers/TesterDriver.scala @@ -5,18 +5,9 @@ package chisel3.testers import chisel3._ import java.io._ +import firrtl.{Driver => _, _} + object TesterDriver extends 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() - } /** For use with modules that should successfully be elaborated by the * frontend, and which can be turned into executables with assertions. */ @@ -29,7 +20,7 @@ object TesterDriver extends BackendCompilationUtilities { // plus the quirks of Verilator's naming conventions val target = circuit.name - val path = createTempDirectory(target) + val path = createTestDirectory(target) val fname = new File(path, target) // For now, dump the IR out to a file @@ -50,7 +41,7 @@ object TesterDriver extends BackendCompilationUtilities { return false } // Use sys.Process to invoke a bunch of backend stuff, then run the resulting exe - if ((verilogToCpp(target, target, path, additionalVFiles, cppHarness) #&& + if ((verilogToCpp(target, path, additionalVFiles, cppHarness) #&& cppToExe(target, path)).! == 0) { executeExpectingSuccess(target, path) } else { diff --git a/src/test/scala/chiselTests/Harness.scala b/src/test/scala/chiselTests/Harness.scala index 8a12cd7b..1da3d166 100644 --- a/src/test/scala/chiselTests/Harness.scala +++ b/src/test/scala/chiselTests/Harness.scala @@ -6,9 +6,10 @@ import chisel3.testers.BasicTester import org.scalatest._ import org.scalatest.prop._ import java.io.File +import firrtl.util.BackendCompilationUtilities class HarnessSpec extends ChiselPropSpec - with chisel3.BackendCompilationUtilities { + with BackendCompilationUtilities { def makeTrivialVerilog: (File => File) = makeHarness((prefix: String) => s""" module ${prefix}; @@ -55,13 +56,13 @@ void vl_finish(const char* filename, int linenum, const char* hier) { */ def simpleHarnessBackend(make: File => File): (File, String) = { val target = "test" - val path = createTempDirectory(target) + val path = createTestDirectory(target) val fname = new File(path, target) val cppHarness = makeCppHarness(fname) make(fname) - verilogToCpp(target, target, path, Seq(), cppHarness).! + verilogToCpp(target, path, Seq(), cppHarness).! cppToExe(target, path).! (path, target) } -- cgit v1.2.3