前回のChisel-Bootcampの学習ではScalaのunapply
と部分関数についてを見ていった。
今回も引き続きModule3.6を見ていく。今日はChiselの型についてもう少し詳しく見ていく。
型安全な接続
Chiselの型同士を接続する場合に何がチェックされているのか、、という部分についての項目。 多くの場合についてはChiselは接続時にチェックを行ってくれていてまずい場合にはエラーを出してくれる。
とりあえずサンプルコードは以下。
class Bundle1 extends Bundle { val a = UInt(8.W) override def cloneType = (new Bundle1).asInstanceOf[this.type] } class Bundle2 extends Bundle1 { val b = UInt(16.W) override def cloneType = (new Bundle2).asInstanceOf[this.type] } class BadTypeModule extends Module { val io = IO(new Bundle { val c = Input(Clock()) val in = Input(UInt(2.W)) val out = Output(Bool()) val bundleIn = Input(new Bundle2) val bundleOut = Output(new Bundle1) }) //io.out := io.c // 型が異なるためエラーになる // 接続可能だがOutputのビット幅に合わせて下位の1bit以外は落とされる io.out := io.in // コンパイル可能;Chiselは2つのBundleから共通する要素同士を接続する(この場合だと、"a"のみが接続される) io.bundleOut := io.bundleIn }
- 上記の回路からRTLを生成した結果
[info] [0.000] Elaborating design... [info] [0.009] Done elaborating. Total FIRRTL Compile Time: 19.3 ms module cmd10HelperBadTypeModule( // @[:@3.2] input clock, // @[:@4.4] input reset, // @[:@5.4] input io_c, // @[:@6.4] input [1:0] io_in, // @[:@6.4] output io_out, // @[:@6.4] input [7:0] io_bundleIn_a, // @[:@6.4] input [15:0] io_bundleIn_b, // @[:@6.4] output [7:0] io_bundleOut_a // @[:@6.4] ); assign io_out = io_in[0]; assign io_bundleOut_a = io_bundleIn_a; endmodule
上記のコメント中にあるとおり、Clock
はChiselおいては別の型になるので、これをUInt
やBool
に接続するとエラーになる。
UInt
→Bool
やBool
→UInt
は接続可能。これはBool
がUInt
を継承して作れらた型になっているから。
sealed class Bool(lit: Option[ULit] = None) extends UInt(1.W, lit) with Reset {
3つめのBundle
を使った例では、Bundle2
がBundle1
を継承した結果Bundle2
にもa
が存在しているので、そのa
のみが接続される結果となる。
因みにこれは:=
を使って接続した場合で、<>
を使って接続しようとするとb
が存在しないためエラーになる。
chisel3.internal.ChiselException: Connection between left (ammonite.$sess.cmd6$Helper$Bundle1@27) and source (ammonite.$sess.cmd6$Helper$Bundle2@22) failed @.b: Left Record missing field (b).
一方でSInt
→UInt
やSInt
→Bool
については何もせずに接続すると以下のようなエラーが発生する。
chisel3.internal.ChiselException: Connection between sink (chisel3.core.SInt@20) and source (chisel3.core.UInt@1e) failed @: Sink (chisel3.core.SInt@20) and Source (chisel3.core.UInt@1e) have different types.
ということでざっくりまとめると以下のような感じか。
接続 | 結果 |
---|---|
Clock ⇔ Bool or UInt |
エラー |
SInt ⇔ Bool or UInt |
エラー |
Bool ⇔ UInt |
接続可能だが、接続先のビット幅に合わせて上位ビットの切り捨て又は上位ビットへのパディング |
Bundle A ⇔ Bundle B (:= を使用した場合) |
型と名前が一致するポートのみが接続される |
Bundle A ⇔ Bundle B (<> を使用した場合) |
全変数の名前と型が一致する場合のみ接続可能 |
一応補足すると、IOの接続に置いてはポートの方向はいずれの場合でもチェックされるため、接続の方向がぶつかった場合にはエラーになる。Verilogだと警告出てもエラーにならなかったりするよね、これ。
ということでUInt
とBool
で意図しない接続がされてないか、、という部分はチェックが必要だけど、それ以外についてはChiselのエラボレート時にかなり細かく見てくれるので、これに結構助けられるケースはあるはず。
あっさり目だけど、キリもいいので今日はここまで。