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]
いいね、想定通りだ。