FPGA開発日記

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

FIRRTLに入門する (13. Bundleの改造と配列の制約)

https://raw.githubusercontent.com/freechipsproject/firrtl/master/doc/images/firrtl_logo.svg?sanitize=true

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]

うーん、こうやって分解しないといけないのか?