FPGA開発日記

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

Chisel2とChisel3でのVerilog/C++コード生成フローの違い

f:id:msyksphinz:20181105012126p:plain

Chiselにはバージョンがあり、Chisel2とChisel3が公開されている。 微妙に文法が異なっているので要注意だ。

Chisel2ではVerilogC++を生成する方法が公開されているが、Chisel3ではどうだろう。

Chisel2でのVerilogC++の生成方法については、以下のサイトにまとめられている。 と思っていろいろ探したら自分のブログだった。

github.com

msyksphinz.hatenablog.com

  • src/main/scala/hello/Hello.scala
package Hello

import Chisel._

class Hello extends Module {
  val io = new Bundle {
    val out = UInt(OUTPUT, 8)
  }
  io.out := UInt(42)
}

class HelloTests(c: Hello) extends Tester(c) {
  step(1)
  expect(c.io.out, 42)
}

object Hello {
  def main(args: Array[String]): Unit = {
    val tutArgs = args.slice(1, args.length)
    chiselMainTest(tutArgs, () => Module(new Hello())) {
      c => new HelloTests(c) }
  }
}

Chisel3を触っているとわかる。微妙に違う。まず、import Chisel._ではなくChisel3だとimport chisel3._になる。次にBundleにカッコが入っていない。 次に、chiselMainTestなどという関数はない。これらを修正していく必要がある。

Chisel2では、chiselMainTestのargsを変更することによりC++を出力することができる。 つまり、--backend cを追加することでC++のコードが生成できる。

しかし、Chisel3ではできない。どのようにすればよいのか。

まず、上記のデザインはChisel3では以下のようになる。

package hello

import chisel3._
import chisel3.iotesters.{PeekPokeTester, Driver}

class Hello extends Module {
  val io = IO(new Bundle {
    val out = Output(UInt(8.W))
  })
  io.out := 42.U
}

class HelloTests(c: Hello) extends PeekPokeTester(c) {
  step(1)
  expect(c.io.out, 42)
}

object Hello {
  def main(args: Array[String]): Unit = {
    if (!Driver(() => new Hello())(c => new HelloTests(c))) System.exit(1)
  }
}

細かな文法の違いはあるが、大きくはchiselMainTest()が消える。その代わり、iotestersのDriverが直接呼び出される。

このAPIVerilogを生成するためのAPIである。じゃあC++を生成するためにはどうすればよいのか。

[https://chisel.eecs.berkeley.edu/api/latest/chisel3/Driver$.html#execute(args:Array[String],dut:()=%3Echisel3.experimental.RawModule):chisel3.ChiselExecutionResult:title]

同じiotestersにverilogToCppというメソッドがあるけど、これは何か違う気がする。

[https://chisel.eecs.berkeley.edu/api/latest/chisel3/Driver$.html#verilogToCpp(dutFile:String,dir:java.io.File,vSources:Seq[java.io.File],cppHarness:java.io.File,suppressVcd:Boolean):scala.sys.process.ProcessBuilder:title]

結論から言うと、Chisel3でC++を生成するのは直接的には不可能で、VerilatorでシミュレーションするためにC++を生成するという考え方に近い。

このiotestersのDriverにはどのような機能があるのか。オプションを与えるように変更していろいろと変えてみる。

object Hello {
  def main(args: Array[String]): Unit = {
    chisel3.Driver.execute(args, () => new Hello)
  }
}

sbt実行時に`sbt "run Hello.Hello --help"とか入れてみる。

common options
  -tn, --top-name <top-level-circuit-name>
                           This options defines the top level circuit, defaults to dut when possible
  -td, --target-dir <target-directory>
                           This options defines a work directory for intermediate files, default is .
  -ll, --log-level <Error|Warn|Info|Debug|Trace>
                           This options defines a work directory for intermediate files, default is .
  -cll, --class-log-level <FullClassName:[Error|Warn|Info|Debug|Trace]>[,...]
                           This options defines a work directory for intermediate files, default is .
  -ltf, --log-to-file      default logs to stdout, this flags writes to topName.log or firrtl.log if no topName
  -lcn, --log-class-names  shows class names and log level in logging output, useful for target --class-log-level
  --help                   prints this usage text
  <arg>...                 optional unbounded args
chisel3 options
  -chnrf, --no-run-firrtl  Stop after chisel emits chirrtl file
firrtl options
  -i, --input-file <firrtl-source>
                           use this to override the default input file name , default is empty
  -o, --output-file <output>
                           use this to override the default output file name, default is empty
  -faf, --annotation-file <input-anno-file>
                           Used to specify annotation files (can appear multiple times)
  -foaf, --output-annotation-file <output-anno-file>
                           use this to set the annotation output file
  -X, --compiler <high|middle|low|verilog|sverilog>
                           compiler to use, default is verilog
  --info-mode <ignore|use|gen|append>
                           specifies the source info handling, default is append
  -fct, --custom-transforms <package>.<class>
                           runs these custom transforms during compilation.
  -fil, --inline <circuit>[.<module>[.<instance>]][,..],
                           Inline one or more module (comma separated, no spaces) module looks like "MyModule" or "MyModule.myinstance
  -firw, --infer-rw <circuit>
                           Enable readwrite port inference for the target circuit
  -frsq, --repl-seq-mem -c:<circuit>:-i:<filename>:-o:<filename>
                           Replace sequential memories with blackboxes + configuration file
  -clks, --list-clocks -c:<circuit>:-m:<module>:-o:<filename>
                           List which signal drives each clock of every descendent of specified module
  -fsm, --split-modules    Emit each module to its own file in the target directory.
  --no-check-comb-loops    Do NOT check for combinational loops (not recommended)
  --no-dce                 Do NOT run dead code elimination

--compilerオプションがあるが、ここにはhigh|middle|low|verilog|sverilogとだけあり、high|middle|lowはFIRのレベル、sverilogに至っては生成されるものはVerilogと同一である。

このあたりのオプションがChisel2とChisel3ではかなり異なっている。注意して扱う必要がありそうだ。