Skip to content

Commit

Permalink
Allow name of blackbox resource .f file to change from static value (#…
Browse files Browse the repository at this point in the history
…1129)

* Allow name of blackbox resource .f file to change from static value

* Restore fileListName as a deprecated def per Jack's feedback

* Support both local and absolute paths for .f resource files
  • Loading branch information
albert-magyar authored Jul 25, 2019
1 parent 0512b6c commit 30bff5f
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 33 deletions.
57 changes: 32 additions & 25 deletions src/main/scala/firrtl/transforms/BlackBoxSourceHelper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ case class BlackBoxPathAnno(target: ModuleName, path: String) extends BlackBoxHe
override def serialize: String = s"path\n$path"
}

case class BlackBoxResourceFileNameAnno(resourceFileName: String) extends BlackBoxHelperAnno
with NoTargetAnnotation {
override def serialize: String = s"resourceFileName\n$resourceFileName"
}

/** Exception indicating that a blackbox wasn't found
* @param fileName the name of the BlackBox file (only used for error message generation)
* @param e an underlying exception that generated this
Expand All @@ -50,24 +55,25 @@ class BlackBoxNotFoundException(fileName: String, e: Throwable = null) extends F
* set by the execution harness, or directly in the tests
*/
class BlackBoxSourceHelper extends firrtl.Transform {
import BlackBoxSourceHelper._
private val DefaultTargetDir = new File(".")

override def inputForm: CircuitForm = LowForm
override def outputForm: CircuitForm = LowForm

/** Collect BlackBoxHelperAnnos and and find the target dir if specified
* @param annos a list of generic annotations for this transform
* @return BlackBoxHelperAnnos and target directory
*/
def collectAnnos(annos: Seq[Annotation]): (ListSet[BlackBoxHelperAnno], File) =
annos.foldLeft((ListSet.empty[BlackBoxHelperAnno], DefaultTargetDir)) {
case ((acc, tdir), anno) => anno match {
def collectAnnos(annos: Seq[Annotation]): (ListSet[BlackBoxHelperAnno], File, File) =
annos.foldLeft((ListSet.empty[BlackBoxHelperAnno], DefaultTargetDir, new File(defaultFileListName))) {
case ((acc, tdir, flistName), anno) => anno match {
case BlackBoxTargetDirAnno(dir) =>
val targetDir = new File(dir)
if (!targetDir.exists()) { FileUtils.makeDirectory(targetDir.getAbsolutePath) }
(acc, targetDir)
case a: BlackBoxHelperAnno => (acc + a, tdir)
case _ => (acc, tdir)
(acc, targetDir, flistName)
case BlackBoxResourceFileNameAnno(fileName) => (acc, tdir, new File(fileName))
case a: BlackBoxHelperAnno => (acc + a, tdir, flistName)
case _ => (acc, tdir, flistName)
}
}

Expand All @@ -79,17 +85,17 @@ class BlackBoxSourceHelper extends firrtl.Transform {
* @throws BlackBoxNotFoundException if a Verilog source cannot be found
*/
override def execute(state: CircuitState): CircuitState = {
val (annos, targetDir) = collectAnnos(state.annotations)
val (annos, targetDir, flistName) = collectAnnos(state.annotations)

val resourceFiles: ListSet[File] = annos.collect {
case BlackBoxResourceAnno(_, resourceId) =>
BlackBoxSourceHelper.writeResourceToDirectory(resourceId, targetDir)
writeResourceToDirectory(resourceId, targetDir)
case BlackBoxPathAnno(_, path) =>
val fileName = path.split("/").last
val fromFile = new File(path)
val toFile = new File(targetDir, fileName)

val inputStream = BlackBoxSourceHelper.safeFile(fromFile.toString)(new FileInputStream(fromFile).getChannel)
val inputStream = safeFile(fromFile.toString)(new FileInputStream(fromFile).getChannel)
val outputStream = new FileOutputStream(toFile).getChannel
outputStream.transferFrom(inputStream, 0, Long.MaxValue)

Expand All @@ -101,13 +107,23 @@ class BlackBoxSourceHelper extends firrtl.Transform {
val outFile = new File(targetDir, name)
(text, outFile)
}.map { case (text, file) =>
BlackBoxSourceHelper.writeTextToFile(text, file)
writeTextToFile(text, file)
file
}

// Issue #917 - We don't want to list Verilog header files ("*.vh") in our file list - they will automatically be included by reference.
val verilogSourcesOnly = (resourceFiles ++ inlineFiles).filterNot( _.getName().endsWith(".vh"))
BlackBoxSourceHelper.writeFileList(verilogSourcesOnly, targetDir)
val filelistFile = if (flistName.isAbsolute()) flistName else new File(targetDir, flistName.getName())

// We need the canonical path here, so verilator will create a path to the file that works from the targetDir,
// and, so we can compare the list of files automatically included, with an explicit list provided by the client
// and reject duplicates.
// If the path isn't canonical, when make tries to determine dependencies based on the *__ver.d file, we end up with errors like:
// make[1]: *** No rule to make target `test_run_dir/examples.AccumBlackBox_PeekPokeTest_Verilator345491158/AccumBlackBox.v', needed by `.../chisel-testers/test_run_dir/examples.AccumBlackBox_PeekPokeTest_Verilator345491158/VAccumBlackBoxWrapper.h'. Stop.
// or we end up including the same file multiple times.
if (verilogSourcesOnly.nonEmpty) {
writeTextToFile(verilogSourcesOnly.map(_.getCanonicalPath).mkString("\n"), filelistFile)
}

state
}
Expand Down Expand Up @@ -150,19 +166,10 @@ object BlackBoxSourceHelper {
out.close()
}

val fileListName = "firrtl_black_box_resource_files.f"

def writeFileList(files: ListSet[File], targetDir: File): Unit = {
if (files.nonEmpty) {
// We need the canonical path here, so verilator will create a path to the file that works from the targetDir,
// and, so we can compare the list of files automatically included, with an explicit list provided by the client
// and reject duplicates.
// If the path isn't canonical, when make tries to determine dependencies based on the *__ver.d file, we end up with errors like:
// make[1]: *** No rule to make target `test_run_dir/examples.AccumBlackBox_PeekPokeTest_Verilator345491158/AccumBlackBox.v', needed by `.../chisel-testers/test_run_dir/examples.AccumBlackBox_PeekPokeTest_Verilator345491158/VAccumBlackBoxWrapper.h'. Stop.
// or we end up including the same file multiple times.
writeTextToFile(files.map(_.getCanonicalPath).mkString("\n"), new File(targetDir, fileListName))
}
}
val defaultFileListName = "firrtl_black_box_resource_files.f"

@deprecated("Renamed to defaultFileListName, as the file list name may now be changed with an annotation", "1.3")
def fileListName = defaultFileListName

def writeTextToFile(text: String, file: File): Unit = {
val out = new PrintWriter(file)
Expand Down
12 changes: 8 additions & 4 deletions src/main/scala/firrtl/util/BackendCompilationUtilities.scala
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ trait BackendCompilationUtilities {
* all the files which are not included elsewhere. If multiple ones exist,
* the compilation will fail.
*
* If the file BlackBoxSourceHelper.fileListName exists in the output directory,
* If the file BlackBoxSourceHelper.fileListName (or an overridden .f resource filename that is
* specified with the optional resourceFileName parameter) exists in the output directory,
* it contains a list of source files to be included. Filter out any files in the vSources
* sequence that are in this file so we don't include the same file multiple times.
* This complication is an attempt to work-around the fact that clients used to have to
Expand All @@ -91,18 +92,21 @@ trait BackendCompilationUtilities {
* @param dir output directory
* @param vSources list of additional Verilog sources to compile
* @param cppHarness C++ testharness to compile/link against
* @param suppressVcd specifies if VCD tracing should be suppressed
* @param resourceFileName specifies what filename to look for to find a .f file
*/
def verilogToCpp(
dutFile: String,
dir: File,
vSources: Seq[File],
cppHarness: File,
suppressVcd: Boolean = false
suppressVcd: Boolean = false,
resourceFileName: String = firrtl.transforms.BlackBoxSourceHelper.defaultFileListName
): ProcessBuilder = {

val topModule = dutFile

val list_file = new File(dir, firrtl.transforms.BlackBoxSourceHelper.fileListName)
val list_file = new File(dir, resourceFileName)
val blackBoxVerilogList = {
if(list_file.exists()) {
Seq("-f", list_file.getAbsolutePath)
Expand All @@ -113,7 +117,7 @@ trait BackendCompilationUtilities {
}

// Don't include the same file multiple times.
// If it's in BlackBoxSourceHelper.fileListName, don't explicitly include it on the command line.
// If it's in the main .f resource file, don't explicitly include it on the command line.
// Build a set of canonical file paths to use as a filter to exclude already included additional Verilog sources.
val blackBoxHelperFiles: Set[String] = {
if(list_file.exists()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class BlacklBoxSourceHelperTransformSpec extends LowTransformSpec {
execute(input, output, annos)

val module = new java.io.File("test_run_dir/AdderExtModule.v")
val fileList = new java.io.File(s"test_run_dir/${BlackBoxSourceHelper.fileListName}")
val fileList = new java.io.File(s"test_run_dir/${BlackBoxSourceHelper.defaultFileListName}")

module.exists should be (true)
fileList.exists should be (true)
Expand All @@ -79,7 +79,7 @@ class BlacklBoxSourceHelperTransformSpec extends LowTransformSpec {
execute(input, output, annos)

val module = new java.io.File("test_run_dir/AdderExtModule.v")
val fileList = new java.io.File(s"test_run_dir/${BlackBoxSourceHelper.fileListName}")
val fileList = new java.io.File(s"test_run_dir/${BlackBoxSourceHelper.defaultFileListName}")

module.exists should be (true)
fileList.exists should be (true)
Expand All @@ -98,7 +98,7 @@ class BlacklBoxSourceHelperTransformSpec extends LowTransformSpec {
execute(input, output, annos)

new java.io.File("test_run_dir/AdderExtModule.v").exists should be (true)
new java.io.File(s"test_run_dir/${BlackBoxSourceHelper.fileListName}").exists should be (true)
new java.io.File(s"test_run_dir/${BlackBoxSourceHelper.defaultFileListName}").exists should be (true)
}

"verilog compiler" should "have BlackBoxSourceHelper transform" in {
Expand Down Expand Up @@ -130,7 +130,7 @@ class BlacklBoxSourceHelperTransformSpec extends LowTransformSpec {
new java.io.File("test_run_dir/" + n).exists should be (true)

// but our file list should not include the verilog header file.
val fileListFile = new java.io.File(s"test_run_dir/${BlackBoxSourceHelper.fileListName}")
val fileListFile = new java.io.File(s"test_run_dir/${BlackBoxSourceHelper.defaultFileListName}")
fileListFile.exists should be (true)
val fileListFileSource = io.Source.fromFile(fileListFile)
val fileList = fileListFileSource.getLines.mkString
Expand Down

0 comments on commit 30bff5f

Please sign in to comment.