FPGA開発日記

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

FIRRTLに入門する (11. 配列参照のコードを残したままVerilogを出したい)

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

ChiselからVerilogを生成すると、配列参照の記述は最終的に除去され、とんでもないVerilogが生成されることはよくある。 これをVerilogでそのまま配列で出力する方法を探しているのだが、試行錯誤でなかなかうまく進まない。

まず、passes.RemoveAccessesパスを除去すると、配列アクセスが除去出るが、それだけで話は終わらない。 例えば、入力ポートに対してVecを使っているとVerilog生成時にVecがすべて分解されてしまう。 すると、配列参照のために残していたin_a[in]というコードに対して、in_ain_a_0, in_a_1, in_a_2, in_a_3などに分解されてしまい名前参照に失敗する。 これはどうすればいいのだろう?

まず、InferTypesのパスにprintfを大量に挿入していくと、このあたりで配列参照を個々の信号に分解していることが分かる。

  • firrtl/src/main/scala/firrtl/passes/InferTypes.scala
    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)
      }
    }

このFIRの回路が、

circuit VecModules :
  module VecModules :
    input in : UInt<1>[4]
    input sel : UInt<2>
    output out : UInt<1>

    skip
    out <= in[sel]

このように分解されてしまう。

 circuit VecModules :
  module VecModules :
    input in_0 : UInt<1>
    input in_1 : UInt<1>
    input in_2 : UInt<1>
    input in_3 : UInt<1>
    input sel : UInt<2>
    output out : UInt<1>

    skip
    out <= in[sel]

これを防ぐためには、どうにかしてVecの分解を防ぐ方法を見つけなければならない。とりあえず、上記のexpsがどのようになっているかダンプしてみると、

Vector(WSubIndex(WRef(in,VectorType(UIntType(IntWidth(1)),4),PortKind,SourceFlow),0,UIntType(IntWidth(1)),SourceFlow), 
       WSubIndex(WRef(in,VectorType(UIntType(IntWidth(1)),4),PortKind,SourceFlow),1,UIntType(IntWidth(1)),SourceFlow), 
       WSubIndex(WRef(in,VectorType(UIntType(IntWidth(1)),4),PortKind,SourceFlow),2,UIntType(IntWidth(1)),SourceFlow),
       WSubIndex(WRef(in,VectorType(UIntType(IntWidth(1)),4),PortKind,SourceFlow),3,UIntType(IntWidth(1)),SourceFlow)
)

うーん、4つに分解されたけど個々の要素が複雑すぎんかね? とりあえず、分解するコードを削ってみる。

  • firrtl/src/main/scala/firrtl/Utils.scala
diff --git a/src/main/scala/firrtl/Utils.scala b/src/main/scala/firrtl/Utils.scala
index 4bf2d14d..957fb200 100644
--- a/src/main/scala/firrtl/Utils.scala
+++ b/src/main/scala/firrtl/Utils.scala
@@ -241,7 +241,8 @@ object Utils extends LazyLogging {
       case (_: GroundType) => Seq(ex)
       case t: BundleType =>
         t.fields.flatMap(f => create_exps(WSubField(ex, f.name, f.tpe,times(flow(ex), f.flip))))
-      case t: VectorType => (0 until t.size).flatMap(i => create_exps(WSubIndex(ex, i, t.tpe,flow(ex))))
+      // case t: VectorType => (0 until t.size).flatMap(i => create_exps(WSubIndex(ex, i, t.tpe,flow(ex))))
+      case t: VectorType => Seq(ex)
     }
   }

とりあえずこの状態のままキープする。

circuit VecModules :
  module VecModules :
    input in : UInt<1>[4]
    input sel : UInt<2>
    output out : UInt<1>

    out <= in[sel]

今度はこのエラーだ。これはなんだろう?

======== Starting Transform DeadCodeElimination ========
Exception in thread "main" firrtl.FirrtlInternalException: Internal Error! Please file an issue at https://github.com/ucb-bar/firrtl/issues
        at firrtl.Utils$.error(Utils.scala:424)
        at firrtl.Utils$.throwInternalError(Utils.scala:164)
        at firrtl.transforms.DeadCodeElimination.$anonfun$setupDepGraph$20(DeadCodeElimination.scala:143)
        at scala.collection.mutable.ResizableArray.foreach(ResizableArray.scala:62)
        at scala.collection.mutable.ResizableArray.foreach$(ResizableArray.scala:55)
        at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:49)
        at firrtl.transforms.DeadCodeElimination.setupDepGraph(DeadCodeElimination.scala:141)
...