FPGA開発日記

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

Chiselでクロックゲーティングを扱うための方法いろいろ

Chiselを書いていると、Chiselには基本的にクロックとリセットという概念が存在しない。

クロック信号とリセット信号は隠されており、普段は見える事は無いのだが、一応扱うことは可能だ。 例えば、特定のモジュールに対してクロックゲーティングを挿入するためにはどうすればよいのか、調べてみた。

方法その1. クロックゲーティングのためのVerilog Wrapperを使う

これはおそらく一般的に行われている手法。VerilogBlackBoxとして挿入することができるので、その機能を使う。

f:id:msyksphinz:20191128224453p:plain

方法その2. クロックゲーティングの論理を生成する

Chiselには、隠された信号としてclockとresetというものが存在している。これは、Moduleクラスに定義されている者であり、これを継承するモジュールではすべて扱うことができる。

class clock_gating extends Module
{
  val io = IO(new Bundle {
    val en_clock = Input(Bool())

    val reg_in  = Input(UInt(32.W))
    val reg_out = Output(UInt(32.W))
  })
  val gated_clock = (io.en_clock & clock.asUInt()(0)).asClock
  val inst = Module(new gated_clock_module())
  inst.clock := gated_clock
  inst.io.reg_in := io.reg_in
  io.reg_out := inst.io.reg_out
}

上記がその例だ。gated_clockio.en_clockにより制御されるGated Clockで、Implicitに定義されたclock信号に対して&演算を挿入することで実現している。

  val gated_clock = (io.en_clock & clock.asUInt()(0)).asClock
                                   ~~~~~~~~~~~~~~             <-- クロック信号はデフォルトでClock型であり、これをUInt型に変換
                                   ~~~~~~~~~~~~~~~~~          <-- UInt信号は32ビットなので、最下位の1ビットを抽出する
                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~          <-- クロック信号とio.en_clockのAND演算
                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ <-- AND演算したUInt型の信号を、再びClock型に戻す。

このカラクリは上記のように分解すると分かりやすいと思う。このように生成したクロック信号は、あとは別のモジュールに接続すれば自由に使用できる。

  val inst = Module(new gated_clock_module())
  inst.clock := gated_clock
  inst.io.reg_in := io.reg_in
  io.reg_out := inst.io.reg_out

これで、gated_clock_moduleモジュール内で使用されるFFはすべてio.en_clockに基づいてクロックゲーティングされている。

f:id:msyksphinz:20191128224305p:plain
Chiselを使ったクロックゲーティングの生成