LowerTypeの調査を続けている、前回の記事からずいぶんと時間が経ってしまったが、Bundleを分解する方法について調査している。つまり、FIRRTLで以下のように記述されているコードを、Vectorを分解せずに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
上記のFIRのコードを分解する。下記のようになれば良い。
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_a[sel]
out_b <= in_b[sel]
このために、LowerTypesを見直している。つまり、現時点で何が問題なのかというとLowerTypesの段階でin[sel].Aをin_A[sel]に変換で来ているのは良いのだが、この時に間違えて実はin_A[sel]という1つの変数として変換してしまっており、結果的に次のResolveKindsのパスでin_A[sel]という変数は無いよと怒られてしまっている。したがって、in_Aとselは別々になるように管理しておかなければならないのだ。
で、なぜin_A[sel]が1つの変数として登録されてしまったかというと、LowerTypesの中で改造をさぼって、
case (_:SubField, _: WSubIndex) => kind(e) match { case InstanceKind => val (root, tail) = splitRef(e) val name = loweredTypeName(tail) WSubField(root, name, e.tpe, flow(e)) case MemKind => val exps = lowerTypesMemExp(memDataTypeMap, info, mname)(e) exps.size match { case 1 => exps.head case _ => error("Error! lowerTypesExp called on MemKind " + "SubField that needs to be expanded!")(info, mname) } case _ => WRef(loweredTypeName(e), e.tpe, kind(e), flow(e)) }
となっており、インスタンスでもメモリでもない場合は単純なWRefによってそれ以降の変数階層をすべて潰してしまい、1つの変数にしてしまっているからである。したがって、in[sel].Aのように、
SubField(構造体のメンバへのアクセス)が発生すると、とりあえず構造体のメンバ変数の解析と、構造体の名前の解析に進む。- 構造体の名前を解析した結果それが配列であれば(
in[sel]のような形)、その配列名を書き直してin_Aという名前に変換してしまう。
という処理が必要になる。このために、上記の処理を下記のように書き直した。
case e: WSubField => { kind(e) match { case InstanceKind => val (root, tail) = splitRef(e) val name = loweredTypeName(tail) WSubField(root, name, e.tpe, flow(e)) case MemKind => val exps = lowerTypesMemExp(memDataTypeMap, info, mname)(e) exps.size match { case 1 => exps.head case _ => error("Error! lowerTypesExp called on MemKind " + "SubField that needs to be expanded!")(info, mname) } case _ => { val exps = lowerTypesExp(memDataTypeMap, info, mname)(e.expr) exps match { case ex: WSubAccess => WSubAccess(WRef(loweredName(ex.expr) + delim + e.name, e.tpe, kind(e), flow(e)), ex.index, ex.tpe, flow(ex)) case _ => WRef(loweredTypeName(e), e.tpe, kind(e), flow(e)) } } } }
これはWSubFieldとWSubIndexを分解して、WSubFieldの型にのみ適用している。InstanceKindでもMemKindでもない場合、
lowerTypesExpで構造体な名前の部分(つまりin[sel]の部分)を解析する。- 構造体の名前を解析した結果それが配列であれば(つまり
WSubAccessであれば)、WSubAccess型を再度作り直す。このときに名前をloweredName(ex.expr) + delim + e.nameとする。つまり構造体の名前とメンバ変数をdelimでくっつけてそれを新しい配列の名前としてしまう。
このようにすることで、上記のテストケースは最終的に以下のように変換されるようになった。
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>
out_a <= in_a[sel]
out_b <= in_b[sel]
いいね、想定通りだ。