FPGA開発日記

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

FIRRTLに入門する (10. 配列参照のコードはどこで除去される?)

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

ChiselからVerilogを生成すると、配列参照の記述は最終的に除去され、とんでもないVerilogが生成されることはよくある。例えば以下のようなFIRを書いたとすると、

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

このようなVerilogが生成される。これはひどい

module VecModules(
  input logic        in_0,
  input logic        in_1,
  input logic        in_2,
...  // あまりにも長いので省略
  input logic        in_13,
  input logic        in_14,
  input logic        in_15,
  input logic  [3:0] sel,
  output logic       out
);
  logic  _GEN_1;
  logic  _GEN_2;
... // あまりにも長いので省略
  logic  _GEN_13;
  logic  _GEN_14;
  assign _GEN_1 = 4'h1 == sel ? in_1 : in_0;
  assign _GEN_2 = 4'h2 == sel ? in_2 : _GEN_1;
  assign _GEN_3 = 4'h3 == sel ? in_3 : _GEN_2;
 ... // ああまりにも長いので省略
  assign _GEN_12 = 4'hc == sel ? in_12 : _GEN_11;
  assign _GEN_13 = 4'hd == sel ? in_13 : _GEN_12;
  assign _GEN_14 = 4'he == sel ? in_14 : _GEN_13;
  assign out = 4'hf == sel ? in_15 : _GEN_14;
endmodule

これがどこで生成されているかというと、Passの中で変換されるルーチンを確認しなければならないのだが、このためには、firrtlの-ll traceオプションを使用する。

./utils/bin/firrtl -td regress -i regress/VecModules.fir -X sverilog -ll trace 2>&1 | tee trace.log
======== Starting Transform ExpandConnects$ ========
----------------------------------------------------

Time: 1.6 ms
Form: UnknownForm
Annotations:
LogLevelAnnotation(Trace)
EmitCircuitAnnotation(class firrtl.SystemVerilogEmitter)
TargetDirAnnotation(regress)
InfoModeAnnotation(use)
targetDir
regress
DELETED by firrtl.stage.phases.AddCircuit
FirrtlFileAnnotation(regress/VecModules.fir)
OutputFileAnnotation(VecModules)
Circuit:
circuit VecModules :
  module VecModules :
    input in : UInt<1>[16]
    input sel : UInt<4>
    output out : UInt<1>

    out <= in[sel]

======== Finished Transform ExpandConnects$ ========
======== Starting Transform RemoveAccesses$ ========
----------------------------------------------------

Time: 10.7 ms
Form: UnknownForm
Annotations:
LogLevelAnnotation(Trace)
EmitCircuitAnnotation(class firrtl.SystemVerilogEmitter)
TargetDirAnnotation(regress)
InfoModeAnnotation(use)
targetDir
regress
DELETED by firrtl.stage.phases.AddCircuit
FirrtlFileAnnotation(regress/VecModules.fir)
OutputFileAnnotation(VecModules)
Circuit:
circuit VecModules :
  module VecModules :
    input in : UInt<1>[16]
    input sel : UInt<4>
    output out : UInt<1>

    wire _in_sel : UInt<1>
    _in_sel is invalid
    when eq(UInt<1>("h0"), sel) :
      _in_sel <= in[0]
    when eq(UInt<1>("h1"), sel) :
      _in_sel <= in[1]
    when eq(UInt<2>("h2"), sel) :
...  // あまりにも長いので省略
      _in_sel <= in[11]
    when eq(UInt<4>("hc"), sel) :
      _in_sel <= in[12]
    when eq(UInt<4>("hd"), sel) :
      _in_sel <= in[13]
    when eq(UInt<4>("he"), sel) :
      _in_sel <= in[14]
    when eq(UInt<4>("hf"), sel) :
      _in_sel <= in[15]
    out <= _in_sel

======== Finished Transform RemoveAccesses$ ========

とりあえずまずはRemoveAccessesのPassを除去してみると何が起きるかな?

diff --git a/src/main/scala/firrtl/LoweringCompilers.scala b/src/main/scala/firrtl/LoweringCompilers.scala
index 05cdbe96..d911f340 100644
--- a/src/main/scala/firrtl/LoweringCompilers.scala
+++ b/src/main/scala/firrtl/LoweringCompilers.scala
@@ -62,7 +62,6 @@ class HighFirrtlToMiddleFirrtl extends CoreTransform {
     passes.PullMuxes,
     passes.ReplaceAccesses,
     passes.ExpandConnects,
-    passes.RemoveAccesses,
     passes.Uniquify,
     passes.ExpandWhens,
     passes.CheckInitialization,

Internal Errorが発生してしまった。

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:423)
        at firrtl.Utils$.throwInternalError(Utils.scala:164)
...
        at firrtl.options.Stage.transform(Stage.scala:46)
        at firrtl.options.Stage.execute(Stage.scala:57)
        at firrtl.options.StageMain.main(Stage.scala:70)
        at firrtl.stage.FirrtlMain.main(FirrtlStage.scala)
Caused by: scala.MatchError: WSubAccess(WRef(in,VectorType(UIntType(IntWidth(1)),16),PortKind,SourceFlow),WRef(sel,UIntType(IntWidth(4)),PortKind,SourceFlow),UIntType(IntWidth(1)),Sourc
eFlow) (of class firrtl.WSubAccess)
        at firrtl.passes.LowerTypes$.lowerTypesExp(LowerTypes.scala:140)
        at firrtl.passes.LowerTypes$.$anonfun$lowerTypesStmt$22(LowerTypes.scala:254)
...
        at firrtl.passes.LowerTypes$.lowerTypesStmt(LowerTypes.scala:254)

まだInternal Errorが発生する。

Exception in thread "main" firrtl.FirrtlInternalException: Internal Error! Please file an issue at https://github.com/ucb-bar/firrtl/issues
...
        at firrtl.options.StageMain.main(Stage.scala:70)
        at firrtl.stage.FirrtlMain.main(FirrtlStage.scala)
Caused by: java.util.NoSuchElementException: key not found: in
        at scala.collection.MapLike.default(MapLike.scala:235)
        at scala.collection.MapLike.default$(MapLike.scala:234)

解析を続けよう。