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"なる機能で、今回の記事はそれを確認したときの副産物だったりします。 そちらについては何となくこれか?というあたりがついたので、確認してみて別途記事にします。