FIRRTLで配列を扱えるように改造を行っている。単純に、配列をキープしながらFIRRTLの処理を進めていくことは可能なのだが、例えば以下のような状態が発生ると問題だ。下記の状況では、Bundleによる構造体が配列で複数定義されているような状態になる。
circuit VecBundle : module VecBundle : input in: { a : UInt<32>, b : UInt<32> }[4] input sel: UInt<2> output out : { a : UInt<32>, b : UInt<32> } out.a <= in[sel].a out.b <= in[sel].b
この場合、Bundleを分解しつつ、配列をキープしなければならない。このための手法について、まずはポートや変数宣言の分解方法を調査した。
FIRRTLにおいて配列は、LowerType
というPassによって分解される。したがって、このLowerType
を改造することになる。まずはLowerType
の処理全体を見てみると、
src/main/scala/firrtl/passes/LowerTypes.scala
def lowerTypes(renames: RenameMap)(m: DefModule): DefModule = { val memDataTypeMap = new MemDataTypeMap renames.setModule(m.name) // Lower Ports val portsx = m.ports flatMap { p => val exps = create_exps(WRef(p.name, p.tpe, PortKind, to_flow(p.direction))) val names = exps map loweredName renameExps(renames, p.name, p.tpe) (exps zip names) map { case (e, n) => Port(p.info, n, to_dir(flow(e)), e.tpe) } } ...
create_exps
によりまずはすべての構造を分解する。そしてこれをloweredNameにより文字列に分解する。したがって、create_exps()
に改造すればよい。このcreate_exps()
はsrc/main/scala/firrtl/Utils.scala
に定義があるのだが、これをそのまま変更すると影響が大きすぎるのでLowerTypes()
にコピーしてから編集する。
src/main/scala/firrtl/passes/LowerTypes.scala
def create_exps(n: String, t: Type): Seq[Expression] = create_exps(WRef(n, t, ExpKind, UnknownFlow)) def create_exps(e: Expression): Seq[Expression] = e match { case ex: Mux => val e1s = create_exps(ex.tval) ... case ex: WRef => { ex.tpe match { case (_: GroundType) => Seq(ex) case t: BundleType => { val ret = t.fields.flatMap(f => create_exps(WSubField(ex, f.name, f.tpe, times(flow(ex), f.flip)))) ret } case t: VectorType => { val elem_exp = create_exps(WRef(ex.name, t.tpe, ExpKind, flow(ex))) elem_exp.map(e => WRef(loweredName(e) , VectorType(e.tpe, t.size), ExpKind, flow(e))) } } }
WRef
の形式をしているときの実装が問題だ。BundleType
の時は変えなくてよい。問題はVectorType
の時に、通常はベクトルのサイズ分だけ展開していたのだがそうはいかない。VectorTypeをキープしつつその中のTypeに処理を加えていく。このため、まずはcreate_exps(WRef(ex.name, t.tpe, ExpKind, flow(ex)))
でVectorTypeの内部の信号(t.tpe
)に対してcreate_exps
を適用し、内部信号を分解する。
その後、その結果をもとに内部のすべての信号に対してWRef
で再度VectorTypeのラッパーを追加することで、VectorTypeの型を維持しつつ内部のBundleを分解する。試行錯誤の結果、このような実装になった。
上記のテストコードで試してみると、以下のようになった。
circuit VecBundle : module VecBundle : input in_a : UInt<32>[4] input in_b : UInt<32>[4] input sel : UInt<2> output out_a : UInt<32> output out_b : UInt<32> skip out_a <= in[sel]_a out_b <= in[sel]_b
展開自体はできたようだ。ただし、まだin[sel]_a
が処理できていない。これは更なる調査が必要となる。