Firtool creates empty .sv files when it is passed "-o=."

Any ideas on why this might be happening?

I’m getting empty .sv files when firtool is passed “-o=.”, whereas it works fine if I pass in “-o=test/”

$ firtool --version
LLVM (http://llvm.org/):
LLVM version 18.0.0git
Optimized build.
CIRCT firtool-1.53.0

Empty .sv files:

        circt.stage.FirtoolOption("-o=.")

Non-empty .sv files:

        circt.stage.FirtoolOption("-o=foobar/")

Because of the way that circt.stage.ChiselStage works it needs to take control of the output file options in order for things to not break. I haven’t found a good way of checking this other than throwing errors after parsing FirtoolOptions which seems pretty bad.

What I’d suggest is to use the ChiselStage object’s emitSystemVerilogFile method instead with the --target-dir and, optionally, --split-verilog option.

A full example is the following:

//> using scala "2.13.11"
//> using lib "org.chipsalliance::chisel::6.0.0-M3"
//> using plugin "org.chipsalliance:::chisel-plugin::6.0.0-M3"
//> using options "-unchecked", "-deprecation", "-language:reflectiveCalls", "-feature", "-Xcheckinit", "-Xfatal-warnings", "-Ywarn-dead-code", "-Ywarn-unused", "-Ymacro-annotations"

import chisel3._
import circt.stage.ChiselStage

class Bar extends RawModule {
  val a = IO(Input(Bool()))
  val b = IO(Output(Bool()))

  b :<>= a
}

class Foo extends Module {
  val a = IO(Input(Bool()))
  val b = IO(Output(Bool()))

  val bar = Module(new Bar)
  bar.a :<>= a
  b :<>= bar.b
}

object Main extends App {
  ChiselStage.emitSystemVerilogFile(new Foo, Array("--target-dir", "unified/"))
  ChiselStage.emitSystemVerilogFile(
    new Foo,
    Array("--target-dir", "split/", "--split-verilog")
  )
}

This produces the following output:

# tree .
.
├── Foo.scala
├── split
│   ├── Bar.sv
│   ├── Foo.sv
│   └── filelist.f
└── unified
    └── Foo.sv

3 directories, 5 files

I have been trying to rewrite this code to use --target-dir, but I can’t get Chisel 5 to recognize --target-dir:

  new circt.stage.ChiselStage()
    .execute(
      chiselArgs.drop(1),
      Seq(
        circt.stage.CIRCTTargetAnnotation(
          circt.stage.CIRCTTarget.SystemVerilog
        ),
        ChiselGeneratorAnnotation(() => new MockRegisterFile()(c)),
        circt.stage.FirtoolOption(
          "--lowering-options=disallowPackedArrays,disallowLocalVariables,noAlwaysComb,omitVersionComment"
        ),
        circt.stage.FirtoolOption("--split-verilog"),
        circt.stage.FirtoolOption("--dedup"),
        circt.stage.FirtoolOption("--strip-debug-info"),
        circt.stage.FirtoolOption("--extract-test-code"),
        circt.stage.FirtoolOption("--disable-annotation-unknown"),
        circt.stage.FirtoolOption("--disable-all-randomization"),
        circt.stage.FirtoolOption("--emit-chisel-asserts-as-sva"),
        circt.stage.FirtoolOption("-o=" + chiselArgs(0))
      )
    )

Aha!

This works:

 new circt.stage.ChiselStage()
    .execute(Array("--target-dir", "split/", "--split-verilog"),
            circt.stage.FirtoolOption("--split-verilog"),
 ...

This fails:

 new circt.stage.ChiselStage()
    .execute(Array("--target-dir", "split/"),
            circt.stage.FirtoolOption("--split-verilog"),
 ...

with an error message that threw me off:

[error] missing output directory: specify with -o=<dir>

I thought the “–target-dir” option was not recognized, but the --split-verilog must come together with the --target-dir in the first set of options…