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

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

Chisel3.4.0のリリースノートを確認した(3) - Module.io / BlackBox.io がdeprecatedになった

スポンサーリンク

Chisel3.4.0の変更点確認の3回目。今回は#1550のioがdeprecated指定に変更された件の影響を確認する。

(#1550) Deprecate Module.io and BlackBox.io

PRの内容自体は、タイトルそのままでModule.io/BlackBox.iodeprecatedに指定された、というもの。 ただModule/BlackBoxクラスはChiselでモジュールを作る際のベースになるもので、雛形の様に次のようなモジュールの形を作ってきたので、影響が大きいのでは??となったので、ちょっとしっかり確認してみる。

  • Chiselのモジュールの雛形
import chisel3._
import chisel3.util._

class <モジュール名> extends Module {
  val io = IO(new Bundle { // <-- このioがdeprecatedになっている。
    <ポート宣言>
  })
}

実際にPRで修正されたソースコードは次のようなもので、確かにdeprecated扱いになっている。

    // IO for this Module. At the Scala level (pre-FIRRTL transformations),
    // connections in and out of a Module may only go through `io` elements.
    @deprecated("Removed for causing issues in Scala 2.12+. You remain free to define io Bundles " +
      "in your Modules, but you cannot rely on an io field in every Module. " +
      "For more information, see: https://github.com/freechipsproject/chisel3/pull/1550.",
      "Chisel 3.4"
    )
    def io: Record

これコメントにもあるとおりで、実際に次のバージョンとかで削除されると、モジュールにioという変数が無くてもOKになる(RawModule使うのと変わらん状態)。

変更された理由

なぜ今回の修正が入ったかについては、PRのコメントを読むと書いてあった。

I was experimenting with some stuff in Scala 2.13 and realized that -Xsource:2.11 is no longer supported in 2.13. In fact, it was never recommended as an option to Scalac for anything but debugging, let alone our recommended way of supporting Scala 2.12.

現在のChiselはScala 2.12上で動かす場合には、-Xsource:2.11の指定を入れて、動作しているのだが、この指定がScala 2.13からは使えなくなってしまう。 そのため、残された方法として-Xsoucrce:2.11の指定を市内状態でScala 2.12をサポートする必要が出たということらしい。

ここで気になるのが、どのような記述がScala 2.12では動作しなかったのか、ということなのだが、それについてのコメントが次のもの。

For a long time, we thought the issue only had to do with structural typing. This was incorrect, there were actually 2 different problems: 1. Structural Typing - formerly unsupported in Scala 3, now supported, it always worked in Scala 2.12/13 1. Type Inference for overridden definitions defaults to overridden type (as opposed to overriding type) - Strict in Scala 3, weaker in Scala 2.12/13

構造的型付けと、継承元のデフォルト型をオーバーライドしたときの挙動が問題だった、らしい。 具体的には、モジュール宣言の際に行っているioの宣言部分が該当している。

  • 現在は-Xsourceを使って次のように書けている

    scala class MyModule extends Module { val io = IO(new Bundle { ... }) }

  • -Xsource無しのScala 2.12だと、次のようにIO用の型の定義が必要になる。(無いとエラー)

    scala class MyModule extends Module { class MyModuleIntf extends Bundle { ... } val io = IO(new MyModuleIntf) }

  • さらにScala 3からは型の明示が必要になる(らしい)

    ```scala class MyModule extends Module { class MyModuleIntf extends Bundle { ... } val io: MyModuleIntf = IO(new MyModuleIntf) }

で、これが起きる原因というのがModuleで宣言されているval io: Recordという宣言にあるため、この指定を廃止しようというこになったようだ。

影響範囲

単純に冒頭に記載したval iodeprecated指定の変更だけだと、いろんなシチュエーションでdeprecatedの警告が発生しそうだが、実際にはあんまり発生はしなかった。

というのも、次のように対策のための実装がなされており、ある程度、というかかなりのケースで警告が発生しないようになっている。

  // Private accessor to reduce number of deprecation warnings
  private[chisel3] def _io: Record = io

  // Allow access to bindings from the compatibility package
  protected def _compatIoPortBound() = portsContains(_io)

この対策のおかげで、次のような基本的な使い方では警告は発生しない。

class MyModule extends Module {
  val io = IO(new Bundle {
    val in = Input(Bool())
    val out = Output(Bool())
  })

  io.out := io.in
}

今回の修正でioにまつわるdeprecatedの警告が発生するのは、次のコードのように、Module.ioを直接参照するケース。 このコードではDeprecatedIOGetsWarningというモジュール内で、Moduleクラスを引数に取るconnectというメソッドが定義されている。 この場合、connectメソッドにModuleを継承した自前のクラスを渡しても、connectメソッドでは継承元のModuleクラスが見えるため、deprecatedに関する警告が発生する。

import chisel3._
import chisel3.util._

class DeprecatedIO extends Module {
  val io = IO(new Bundle {
    val in = Input(Bool())
    val out = Output(Bool())
  })

  io.out := !io.in
}

class DeprecatedIOGetsWarning extends Module {
  val io = IO(new Bundle {
    val in = Input(Bool())
    val out = Output(Bool())
  })

  val m = Module(new DeprecatedIO)

  def connect(src: Module, dst: Module): Unit = {
    dst.io <> src.io // 警告が発生
    // 次のようにasInstanceOfを使うと警告は消える
    //dst.asInstanceOf[DeprecatedIO].io <> src.asInstanceOf[DeprecatedIOGetsWarning].io
  }

  connect(this, m)
}

object ElaborateDeprecatedIO extends App {
  println(chisel3.stage.ChiselStage.emitVerilog(new DeprecatedIO))
  println(chisel3.stage.ChiselStage.emitVerilog(new DeprecatedIOGetsWarning))
}
  • 発生する警告
[warn] /home/diningyo/workspace/study/2000_chisel/500_learning-chisel3/
subprj/chisel-3.4.x/src/main/scala/DeprecatedIO.scala:23:9: method io in
class LegacyModule is deprecated (since Chisel 3.4): Removed for causing
issues in Scala 2.12+. You remain free to define io Bundles in your
Modules, but you cannot rely on an io field in every Module. For more
information, see: https://github.com/freechipsproject/chisel3/pull/1550.
[warn]     dst.io <> src.io // 警告が発生

Module.ioを直接触らなければOKなので、上記のconnectメソッドにおいても、asInstanceOfを使って元のクラスに戻せば警告は消すことができる。

まとめ

PRのタイトル見たときは、「影響範囲デカくない??」と思ったけど、既存のモジュールについては、さほど気にしなくても良さそう。 今後という点で考えると、実際にval ioが削除されるとModuleを継承したクラスにioが存在する保証は無くなる。 そのため、自分以外の人が作ったモジュールを見る時にはIOポートの宣言が何になっているかに少しだけ注意が必要かも(とはいえ、IO()で囲われていることは変わらないので、これもそんなに気にならない)。