ハードウェアの気になるあれこれ

技術的に興味のあることを調べて書いてくブログ。主にハードウェアがネタ。

Chisel3.3.0のリリースノートを確認した(2) - ChiselStageを使ったエラボレート

スポンサーリンク

今日は前回の続きでChisel3.3.0で変更/追加になった機能について確認していく。 今回は一番気になったRTLの生成処理の変更について。

#1213 Driverのいくつかのメソッドが非推奨になった

Chisel3.2.xまでのバージョンではRTLの生成時に次のようにDriver.executeメソッドを実行すればよかった。

object OldElaborate extends App {
  val name = "SampleModule"

  Driver.execute(Array(
    "-td=rtl",
    s"-tn=$name"
  ),
    () => new SampleModule
  )
}

上記のコードをChisel3.3.0以降のコードで実行してみると次のように警告が表示されるようになっている。

[warn] chisel-3.3.x/src/main/scala/Elaborate.scala:23:10:
method execute in object Driver is deprecated: Use chisel3.stage.ChiselStage.execute. This will be removed in 3.4.
[warn] chisel-3.3.x/src/main/scala/Elaborate.scala:23:3:
object Driver in package chisel3 is deprecated: Please switch to chisel3.stage.ChiselStage. Driver will be removed in 3.4.

警告の中身は

  • chisel3.Driver.executeが非推奨になりChisel3.4で削除予定なのでchisel3.stage.ChiselStage.executeを使うように
  • chisel3.Driverが非推奨になりChisel3.4で削除予定なのでchisel3.stage.ChiselStageを使うように

というものだ。 ソースコードの方をみるとDriverオブジェクトの全メソッドに@deprecatedが付与されているので、本当にまるごと削除されるみたい。

Chisel3.stage.ChiselStage

ということでChisel3.3.0以降の水晶となったChiselStageを使ったRTLの生成について確認しておく。 代わりに、、と書いてあったのでDriver.executeをそのままstage.ChiselStage.executeに置き換えてみた所エラーが発生した。。。

// このコードはエラーが発生する
object NewElaborate extends App {
  val name = "SampleModule"

  stage.ChiselStage.execute(Array(
    "-td=rtl",
    s"-tn=$name"
  ),
    () => new SampleModule
  )
}

出てくるエラーはこんなメソッドは存在しない、、というもの。 仕方ないので、ソースコードを確認する。

class ChiselStage extends Stage with PreservesAll[Phase] {

  val shell: Shell = new Shell("chisel") with ChiselCli with FirrtlCli

~~~ 中略 ~~~

object ChiselStage {

  /** Return a Chisel circuit for a Chisel module
    * @param gen a call-by-name Chisel module
    */
  def elaborate(gen: => RawModule): cir.Circuit = {

上記の様にChiselStageというクラスとそのコンパニオン・オブジェクトが定義されているのだが、どちらのChiselStageにもexecuteという メソッドは存在していなかった。 エラボレートを行うだけなら、オブジェクトの方のChiselStageにモジュールを渡せば良さそう。 ちゃんとモジュール内にエラーが存在する場合は次のように、例外が発生する。

[error] chisel3.internal.ChiselException:
Connection between sink (Bool(IO in unelaborated SampleModule)) and source (Bool(IO in unelaborated SampleModule)) failed @:
Sink is unwriteable by current module.
[error]     ...
[error]     at SampleModule.<init>(Elaborate.scala:14)
[error]     at NewElaborate$$anonfun$2.apply(Elaborate.scala:33)
[error]     at NewElaborate$$anonfun$2.apply(Elaborate.scala:33)

とはいえ、上記のelaborateメソッドはCircuitになっていて、このメソッドの中ではRTLへの変換やRTLファイルの生成は行われない。

もう少し探してみた所executeメソッドはChiselStageスーパークラスであるStageに定義されていた。

abstract class Stage extends Phase {
~~~ 中略 ~~~
  final def execute(args: Array[String], annotations: AnnotationSeq): AnnotationSeq =
    transform(shell.parse(args, annotations))

ということで、クラスの方のChiselStageを使って再度エラボレート処理を実行してみる。 ここで気をつけないと行けないのは、上記executeメソッドの第2引数がAnnotationSeqを要求していること。 なので生成したいモジュールを次のようにして渡してやる。

object NewElaborate extends App {
  val name = "SampleModule"

  (new stage.ChiselStage).execute(Array(
    "-td=rtl",
    s"-tn=$name"
  ),
    Seq(chisel3.stage.ChiselGeneratorAnnotation(
        () => new SampleModule))
  )
}

これでもまだ次のようなエラーが出た。。。。オプションも変わっているのか??

[error] (run-main-4) firrtl.options.OptionsException:
Option --top-name failed when given ''. Option '--top-name/-tn' was removed
as part of the FIRRTL Stage refactor. Use an explicit input/output options instead.
[error] This error will be removed in 1.3.

ChiselStage.executeを使ったRTLの生成

最終的にChisel3.2.xまでのDriver.executeと同様にRTLを生成できたコードは次のようになった。

object NewElaborate extends App {
  val name = "SampleModule"

  (new stage.ChiselStage).execute(
    Array("-td=rtl", s"-o=$name"),
    Seq(chisel3.stage.ChiselGeneratorAnnotation(
      () => new SampleModule)))
}

-tnに関するエラーメッセージで指定されていたinput/outputオプションは実際にはそれぞれ次のオプション名が正しい物になる。

  • input -> -i / --input-file
  • output -> -o / --output-file

長い方のオプションだと-fileが必要な点に注意が必要。

ChiselStage.emitVerilogを使ったRTLの生成

ChiselStageにはemitVerilogというメソッドが追加されているので、こちらを使ってもOK。というかexecute使うよりも こっちのほうが使いやすい。戻り値はStringとなっていて、生成されたRTLがそのまま入っている。

object NewElaborate extends App {
  val rtl = (new stage.ChiselStage).emitVerilog(
    new SampleModule,
    Array("-td=rtl", s"-o=$name"))

  print(rtl)
}

上記のコードを実行するとエラボレートのprintlnが実行されて、生成されたRTLが表示される。

[IJ]sbt:chisel33x> runMain NewElaborate
[warn] Multiple main classes detected.  Run 'show discoveredMainClasses' to see the list
[info] running NewElaborate
[info] [0.002] Elaborating design...
[info] [0.065] Done elaborating.
Computed transform order in: 171.3 ms
Total FIRRTL Compile Time: 528.6 ms
module SampleModule(
  input   clock,
  input   reset,
  input   io_in,
  output  io_out
);
  assign io_out = io_in; // @[Elaborate.scala 15:10]
endmodule
[success] Total time: 2 s, completed 2020/05/17 16:29:30
[IJ]sbt:chisel33x>

単純にRTLの生成の面からすると、少し面倒になったなぁという印象ではある。 ただなんとなくコードを見ているとChiselStageを使うことで、生成の過程をカスタマイズできそうな気配もあるので この辺はもう少し掘り下げてみたい所。

ということでChisel3.3.0からの推奨となった新しいRTLの生成フローについての紹介でした。