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

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

Chisel3.2.0で追加された非同期リセットについて(勝手に)勘違いしてた話

スポンサーリンク

Chiselの3.3.0-RC1が公開されて調べたら、自分の把握できていない非同期リセットの振る舞いがあったので それをとめておこうと思う。

非同期リセットはモジュール間も伝搬する

Chisel3.2.0からは非同期リセットを使いたい場合にはasAsyncResetを使ってAsyncReset型に変換したリセット信号を withReset式に指定してやると使用することができる(posedge限定)。

自分が最初に試した際にはレジスタに対して非同期リセットが使用可能ということしか調べていなくて、モジュールをまたぐと どうなるのかを確かめていなかった。

どういうことかを示したのが次のコードだ。このコードではuseAsyncResetを切り替えることでモジュールを withResetでラップするかどうかを選択できるようになっていて、これを実行することでSubModuleのリセットがどう変わるかを 確認することができる。

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

  io.out := RegNext(io.in, false.B)
}

class BetterAsyncReset(useAsyncReset: Boolean = false) extends Module {
  val io = IO(new Bundle {
    val in = Input(Bool())
    val out = Output(Bool())
  })

  val w_async_reset = reset.asAsyncReset()

  val m_sub = if (useAsyncReset) {
                withReset(w_async_reset) { Module(new SubModule) } }
              else {
                   Module(new SubModule())
              }

  withReset(w_async_reset) {
    m_sub.io.in := RegNext(io.in, false.B)
  }

  io.out := m_sub.io.out
}

Chisel3.2.0を使ってuseAsyncReset=trueの状態でRTLを生成すると次のようになる。 なお非同期リセットがどうなるかに着目しているので各モジュールのFFの記述のみを記載した。

useAsyncReset=true

module SubModule(
  input   clock,
  input   reset,
  input   io_in,
  output  io_out
);
  // withReset内でインスタンスしたモジュール内の
  // レジスタも非同期リセットになった
  always @(posedge clock or posedge reset) begin
    if (reset) begin
      _T <= 1'h0;
    end else begin
      _T <= io_in;
    end
  end
endmodule
module BetterAsyncReset(
  input   clock,
  input   reset,
  input   io_in,
  output  io_out
);
  // こっちは当然非同期リセット
  always @(posedge clock or posedge reset) begin
    if (reset) begin
      _T <= 1'h0;
    end else begin
      _T <= io_in;
    end
  end
endmodule

なおwithResetを使わない、すなわち通常のリセットを使用する場合には次のように通常のリセットが使用される。

useAsyncReset=true

module SubModule(
  input   clock,
  input   reset,
  input   io_in,
  output  io_out
);
  // withResetで非同期リセットの外にすると
  // 通常のresetが使用される
  always @(posedge clock) begin
    if (reset) begin
      _T <= 1'h0;
    end else begin
      _T <= io_in;
    end
  end
endmodule
module BetterAsyncReset(
  input   clock,
  input   reset,
  input   io_in,
  output  io_out
);
  always @(posedge clock or posedge reset) begin
    if (reset) begin
      _T <= 1'h0;
    end else begin
      _T <= io_in;
    end
  end
endmodule

ということでChisel3.2.0の時点でもモジュールを非同期リセットを使用するブロック内で宣言すれば非同期リセットが接続されるよーというお話でした。 考えてみればこうなるのが自然なんだけど、自分は確かめもせずにモジュールについては勝手に通常の同期リセットに戻るもんだと思ってました。 思い込み良くない(戒め)。

じつは本題はChisel3.3.0-RC1で追加された"Better Async Reset"なる機能で、今回の記事はそれを確認したときの副産物だったりします。 そちらについては何となくこれか?というあたりがついたので、確認してみて別途記事にします。