前回までの多次元構造体の処理を見直して、もう少し簡単になるんじゃないかということで作り直した。基本的な考え方は以下の通りだ。
SubField(構造体のメンバへのアクセス)が発生すると、WSubFieldの構造を取り除き、WRefと足し込む名前(ex.name)を記憶して次に進む。WSubIndexおよびWSubAccessが発生すると、そのままの形を保持する。WRefの場合、これまでにため込んだ構造体のWSubFieldの値を足し込む。
以下のようなソースコードになった。
src/main/scala/firrtl/passes/LowerTypes.scala
def lowerTypesExp(memDataTypeMap: MemDataTypeMap, info: Info, mname: String, subfield_name: String = "")(e: Expression): Expression = { e match { case e: WRef => { val new_subfield_name = subfield_name match { case "" => e.name case x => e.name + "_" + x } e.copy(name = new_subfield_name) }
case e: WSubAccess => { val exps = lowerTypesExp(memDataTypeMap, info, mname, subfield_name)(e.expr) WSubAccess(exps, e.index, e.tpe, flow(e)) }
case e: WSubField => { ... case _ => { val new_subfield_name = subfield_name match { case "" => e.name case x => e.name + "_" + x } lowerTypesExp(memDataTypeMap, info, mname, new_subfield_name)(e.expr) }
case e: WSubIndex => { ... case _ => { val exps = lowerTypesExp(memDataTypeMap, info, mname, subfield_name)(e.expr) WSubIndex(exps, e.value, e.tpe, flow(e)) }
以下の2つのテストをコンパイルする。WSubIndexとWSubAccessを使うケースだ。どちらもWSubFieldを3階層使用している。
VecBundle.fir
module VecBundle8 :
input in: { a : { b : { c : UInt<8>[4] } [8] } [16] }[32]
output out : { b : UInt<8>[4] }
out.b <= in[0].a[1].b[2].c
module VecBundle9 :
input in: { a : { b : { c : UInt<8>[4] } [8] } [16] }[32]
input sel1: UInt<5>
input sel2: UInt<4>
input sel3: UInt<3>
output out : { b : UInt<8>[4] }
out.b <= in[sel1].a[sel2].b[sel3].c
module VecBundle8 :
input in_a_b_c : UInt<8>[4][8][16][32]
output out_b : UInt<8>[4]
out_b <= in_a_b_c[0][1][2]
module VecBundle9 :
input in_a_b_c : UInt<8>[4][8][16][32]
input sel1 : UInt<5>
input sel2 : UInt<4>
input sel3 : UInt<3>
output out_b : UInt<8>[4]
out_b <= in_a_b_c[sel1][sel2][sel3]
上手くできた。この配列分解の検討は、とりあえずここまでかな。