Chiselのutil以下に存在するモジュールに自分のモジュールのIOを接続しようとした時に遭遇したエラーとその解決法であるchiselTypeOf
について簡単にまとめておく。
QueueにモジュールのIOをつなぐときにエラー
ざっくりと以下のようなコードを作成してエラボレートしたところエラーが発生した。
import chisel3._ import chisel3.util._ class MyIO extends Bundle { val strb = UInt(4.W) val data = UInt(32.W) } class MyModule extends Module { val io = IO(new Bundle { val in = Flipped(Decoupled(new MyIO)) val out = Decoupled(new MyIO) }) val q = Module(new Queue(io.in.bits, 4)) // L.53:ここがエラー発生行 q.io.deq <> io.out }
発生するエラーの内容は以下のようなもの
[info] [0.002] Elaborating design... [error] (run-main-0) chisel3.core.Binding$ExpectedChiselTypeException: 'MyIO@37' must be a Chisel type, not hardware [error] chisel3.core.Binding$ExpectedChiselTypeException: 'MyIO@37' must be a Chisel type, not hardware [error] at chisel3.core.requireIsChiselType$.apply(Binding.scala:42) [error] at chisel3.util.Queue.<init>(Decoupled.scala:203) [error] at MyModule$$anonfun$2.apply(QueueError.scala:53) [error] at MyModule$$anonfun$2.apply(QueueError.scala:53) [error] at chisel3.core.Module$.do_apply(Module.scala:49) [error] at MyModule.<init>(QueueError.scala:53) [error] at ElaborateTypeError$$anonfun$3.apply(QueueError.scala:63) [error] at ElaborateTypeError$$anonfun$3.apply(QueueError.scala:63)
エラーの内容としては「new Queue
の第一引数に指定するのはChiselのハードウェアではなく型でなければならない」というもの。
確かにio.in.bits
はChiselのIO
でくるまれているため、Chiselのハードウェアになっている。
対処法1:MyIOのインスタンスを渡す
ということはここの宣言をChiselのハードウェアではなく型にしてあげればいいので、以下のような修正が考えれられる。
class MyModule extends Module { val io = IO(new Bundle { val in = Flipped(Decoupled(new MyIO)) val out = Decoupled(new MyIO) }) val q = Module(new Queue(new MyIO, 4)) // MyIOのインスタンスを渡す。 q.io.enq <> io.in // インスタンスを渡しただけなので別途接続が必要 io.out <> q.io.deq }
上記の様に修正してやると、エラボレートは下記のように正常にPASSするようになる。
[info] Running ElaborateTypeError [info] [0.001] Elaborating design... [info] [0.899] Done elaborating. Total FIRRTL Compile Time: 510.0 ms
対処法2:chiselTypeOfを使う
でもなんかわざわざ元の型を指定してやるのが野暮ったい。
そう思って再度ChiselのQueueのソースコードを眺めていたところ、Queueのclass
ではなくobject
の方に答えが載っていた。。。
その答えというのがchiselTypeOf
というChiselのハードウェアを型のインスタンスに変換する処理だ。
- chisel3/core/Data.scala : L.149 @ Chisel 3.1.7
/** Returns the chisel type of a hardware object, allowing other hardware to be constructed from it. */ object chiselTypeOf { def apply[T <: Data](target: T): T = { requireIsHardware(target) target.cloneTypeFull.asInstanceOf[T] } }
やってる内容自体は割と単純で
- 引数の
target
がChiselのハードウェアであるかをチェック cloneTypeFull.asInstanceOf
で変換
となっている。
早速先ほどのコードに適用してみよう。
class MyModule extends Module { val io = IO(new Bundle { val in = Flipped(Decoupled(new MyIO)) val out = Decoupled(new MyIO) }) val q = Module(new Queue(chiselTypeOf(io.in.bits), 4)) q.io.enq <> io.in io.out <> q.io.deq }
- エラボレート結果
[info] Done packaging. [info] Running ElaborateTypeError [info] [0.001] Elaborating design... [info] [0.889] Done elaborating. Total FIRRTL Compile Time: 516.2 ms
正常にエラボレートが通った。
ということで何かChsielのハードウェアから別のインスタンスを作りたいなーという時にはchiselTypeOf
を使ってやるのが簡単でいい、という話でした。
通常はオブジェクトのapply
を使って作ることが多いのでそれに倣ってればハマらなかったってことなんだけど、これの存在に気づけたのでよしとしよう。。