FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

FIRRTLに入門する (6. FIRRTLのコンパイルオプションについて違いを確認)

https://raw.githubusercontent.com/freechipsproject/firrtl/master/doc/images/firrtl_logo.svg?sanitize=true

FIRRTLのコンパイルオプション・というか生成ファイルオプションには以下が存在する。

  • none : NoneCompiler() を呼び出す。特に何もしない。
  • hi : HighFirrtlCompiler()を呼び出す。
  • low : LowFirrtlCompiler()を呼び出す。
  • middle : MiddleFirrtlCompiler()を呼び出す。High, Low, Middleの違いは良く分からない。一応生成されるコードが違う?
  • verilog : VerilogCompiler()を呼び出す。Verilogコードを生成する。
  • mverilog : MinimumVerilogCompiler()を呼び出す。最適化されていないVerilogコードを生成する。DeadCodeEliminationが適用されない。
  • sverilog : SystemVerilogCompiler()を呼び出す。実体はVerilogCompilerとどういうである。

それぞれ以下のように実装が分かれている。

  • src/main/scala/firrtl/stage/FirrtlAnnotations.scala
  private [firrtl] def apply(compilerName: String): CompilerAnnotation = {
    val c = compilerName match {
      case "none"      => new NoneCompiler()
      case "high"      => new HighFirrtlCompiler()
      case "low"       => new LowFirrtlCompiler()
      case "middle"    => new MiddleFirrtlCompiler()
      case "verilog"   => new VerilogCompiler()
      case "mverilog"  => new MinimumVerilogCompiler()
      case "sverilog"  => new SystemVerilogCompiler()
      case _           => throw new OptionsException(s"Unknown compiler name '$compilerName'! (Did you misspell it?)")
    }
    CompilerAnnotation(c)
  }

つまり、HighFirrtlCompiler(), LowFirrtlCompiler(), MiddleFirrtlCompiler()のように、FIRRTLからFIRRTLへの変換のコンパイラも用意されているということだ。

実体はFirrtlEmitterであり、この引数にあたるformが変わる。

  • firrtl/Emitter.scala
sealed abstract class FirrtlEmitter(form: CircuitForm) extends Transform with Emitter {
  def inputForm = form
  def outputForm = form

  val outputSuffix: String = form.outputSuffix
...
  • firrtl/Compiler.scala
sealed abstract class CircuitForm(private val value: Int) extends Ordered[CircuitForm] {
  // Note that value is used only to allow comparisons
  def compare(that: CircuitForm): Int = this.value - that.value

  /** Defines a suffix to use if this form is written to a file */
  def outputSuffix: String
}
...

試しに、以下のようなFIRのコードを使ってコンパイル後のコードをチェックしてみる。これはtag_array_ext

のコードである。

  • tag_array.fir
circuit tag_array_ext :
  module tag_array_ext :
    input RW0_clk : Clock
    input RW0_addr : UInt<6>
    input RW0_wdata : UInt<80>
    output RW0_rdata : UInt<80>
    input RW0_en : UInt<1>
    input RW0_wmode : UInt<1>
    input RW0_wmask : UInt<4>

    inst mem_0_0 of rawr
    inst mem_0_1 of rawr
    inst mem_0_2 of rawr
    inst mem_0_3 of rawr
    mem_0_0.clk <= RW0_clk
    mem_0_0.addr <= RW0_addr
    node RW0_rdata_0_0 = bits(mem_0_0.dout, 19, 0)
    mem_0_0.din <= bits(RW0_wdata, 19, 0)
    mem_0_0.write_en <= and(and(RW0_wmode, bits(RW0_wmask, 0, 0)), UInt<1>("h1"))
    mem_0_1.clk <= RW0_clk
    mem_0_1.addr <= RW0_addr
    node RW0_rdata_0_1 = bits(mem_0_1.dout, 19, 0)
    mem_0_1.din <= bits(RW0_wdata, 39, 20)
    mem_0_1.write_en <= and(and(RW0_wmode, bits(RW0_wmask, 1, 1)), UInt<1>("h1"))
    mem_0_2.clk <= RW0_clk
    mem_0_2.addr <= RW0_addr
    node RW0_rdata_0_2 = bits(mem_0_2.dout, 19, 0)
    mem_0_2.din <= bits(RW0_wdata, 59, 40)
    mem_0_2.write_en <= and(and(RW0_wmode, bits(RW0_wmask, 2, 2)), UInt<1>("h1"))
    mem_0_3.clk <= RW0_clk
    mem_0_3.addr <= RW0_addr
    node RW0_rdata_0_3 = bits(mem_0_3.dout, 19, 0)
    mem_0_3.din <= bits(RW0_wdata, 79, 60)
    mem_0_3.write_en <= and(and(RW0_wmode, bits(RW0_wmask, 3, 3)), UInt<1>("h1"))
    node RW0_rdata_0 = cat(RW0_rdata_0_3, cat(RW0_rdata_0_2, cat(RW0_rdata_0_1, RW0_rdata_0_0)))
    RW0_rdata <= mux(UInt<1>("h1"), RW0_rdata_0, UInt<1>("h0"))

  extmodule rawr :
    input clk : Clock
    input addr : UInt<6>
    input din : UInt<32>
    output dout : UInt<32>
    input write_en : UInt<1>

    defname = rawr
 ./utils/bin/firrtl -td regress -i regress/tag_array.fir -X none
 ./utils/bin/firrtl -td regress -i regress/tag_array.fir -X high
 ./utils/bin/firrtl -td regress -i regress/tag_array.fir -X low
 ./utils/bin/firrtl -td regress -i regress/tag_array.fir -X middle
 ./utils/bin/firrtl -td regress -i regress/tag_array.fir -X mverilog
 ./utils/bin/firrtl -td regress -i regress/tag_array.fir -X sverilog

一応比較してみたが、あまり大きな違いは無かった。生成される行の位置が少し違うくらいかなあ。