Chisel/FIRRTLのBundleを使用すると、SystemVerilogのstructやインタフェースのように信号を扱うことができる。
circuit BundleTest : module BundleTest : input in: { a : UInt<32>, b : UInt<32> } output out : { a : UInt<32>, ans: UInt<32> }
これをVerilogに変換してみると、以下のようになる。つまり、すべてのBundleが分解されて、_
で接続される。つまり、このようになる。
module BundleTest( input logic [31:0] in_a, input logic [31:0] in_b, output logic [31:0] out_a, output logic [31:0] out_ans );
これを実現しているのは、LowerTypes.scala
の以下の実装だということが分かった。
firrtl/src/main/scala/firrtl/passes/LowerTypes.scala
/** Delimiter used in lowering names */ val delim = "_" ... def loweredName(e: Expression): String = e match { case e: WRef => e.name case e: WSubField => s"${loweredName(e.expr)}$delim${e.name}" ...
ここまできて分かったのだが、基本的に文字列として変数のキーを解析しているため、配列の要素、SubFieldの要素をすべて分解してしまう訳だ。そうしないと変数のキーを検出できない。
では、Bundleの配列を処理する場合にどうすればよいのか。
circuit VecBundle : module VecBundle : input in: { a : UInt<32> }[4] input sel: UInt<2> output out : { a : UInt<32> } out.a <= in[sel].a
上記のFIRコードでは、通常はin[sel].a
というコードがまんまin_sel__a
になってしまう。ところが先日の私の改造で、配列が生き残ってしまい、しかも配列の参照を最後に接続する実装に変更したため、途中のコードが
out_a <= in_a
となり、最終的に
out_a <= in_a[sel]
というコードを作ろうとしてしまう。これは問題だ...
これを回避するためには、まずはBundleの配列実装において、例えば上記のFIRであれば、下記のように変換する。
input in: { a : UInt<32>, b : UInt<32> }[4]
input in_a : UInt<32>[4] input in_b : UInt<32>[4]
こうすると、なんとか回避できそうな気がする。しかしこれがさらにNestされたらどうなるか、あまり考えたくないなあ...
input in: { a : { c : UInt<32>[8], d : UInt<32>}, b : UInt<32> }[4]
input in_a_c : UInt<32>[4][8] input in_a_d : UInt<32>[4] input in_b : UInt<32>[4]
うーん、こうやって分解しないといけないのか?