FPGA開発日記

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

FIRRTLに入門する (3. FIRRTLのざっくりとしたフローを追いかける)

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

まずはfirrtlに取り込まれる引数を確認した。以下のようにprintlnを挿入した。

  • firrtl/options/Stage.scala
  final def execute(args: Array[String], annotations: AnnotationSeq): AnnotationSeq = {
    println("execute : args")
    for (i <- 0 until args.size) {
      println(args(i))
    }
    transform(shell.parse(args, annotations))
  }

実行すると以下のようになる。まあこれは想定通り。

execute : args
-td
regress
-i
regress/simple_test.fir
-o
regress/simple_test.v
-X
sverilog

つぎに、以下のようにしてすべての処理にprintlnを挟んでみる。

diff --git a/src/main/scala/firrtl/options/Stage.scala b/src/main/scala/firrtl/options/Stage.scala
index 3752b846..ee3bf80b 100644
--- a/src/main/scala/firrtl/options/Stage.scala
+++ b/src/main/scala/firrtl/options/Stage.scala
@@ -35,7 +35,7 @@ abstract class Stage extends Phase {
       Seq( new phases.GetIncludes,
            new phases.ConvertLegacyAnnotations )
         .map(phases.DeletedWrapper(_))
-        .foldLeft(annotations)((a, p) => p.transform(a))
+        .foldLeft(annotations)((a, p) => { println(s"Annotation = ${p}"); p.transform(a)})

     Logger.makeScope(annotationsx) {
       Seq( new phases.AddDefaults,
@@ -43,7 +43,7 @@ abstract class Stage extends Phase {
            new Phase { def transform(a: AnnotationSeq) = run(a) },
            new phases.WriteOutputAnnotations )
         .map(phases.DeletedWrapper(_))
-        .foldLeft(annotationsx)((a, p) => p.transform(a))
+        .foldLeft(annotationsx)((a, p) => { println(s"Annotation2 = ${p}"); p.transform(a)})
     }
   }

以下のようになった。とりあえずPassが進んでいるようだ。

execute = DeletedAnnotation(firrtl.options.Stage$$anon$1,FirrtlFileAnnotation(regress/simple_test.fir))
execute = DeletedAnnotation(firrtl.options.Stage$$anon$1,CompilerAnnotation(firrtl.SystemVerilogCompiler@78aab498))
execute = DeletedAnnotation(firrtl.stage.phases.WriteEmitted,EmittedVerilogCircuitAnnotation(EmittedVerilogCircuit(SimpleCircuit,module SimpleCircuit(
  input  [31:0] io_in,
  output [31:0] io_out
);
  assign io_out = io_in;
endmodule
,.sv)))
execute = DeletedAnnotation(firrtl.stage.phases.Compiler,FirrtlCircuitAnnotation(Circuit(,ArrayBuffer(Module(,SimpleCircuit,ArrayBuffer(Port(,io,Output,BundleType(ArrayBuffer(Field(in,Flip,UIntType(IntWidth(32))), Field(out,Default,UIntType(IntWidth(32))))))),Block(ArrayBuffer(Connect(,SubField(Reference(io,UnknownType),out,UnknownType),SubField(Reference(io,UnknownType),in,UnknownType)))))),SimpleCircuit)))
execute = DeletedAnnotation(firrtl.stage.phases.Compiler,CompilerAnnotation(firrtl.SystemVerilogCompiler@78aab498))
execute = DeletedAnnotation(firrtl.stage.phases.Compiler,RunFirrtlTransformAnnotation(firrtl.SystemVerilogEmitter@7e0b85f9))
execute = FirrtlCircuitAnnotation(Circuit(,ArrayBuffer(Module(,SimpleCircuit,ArrayBuffer(Port(,io_in,Input,UIntType(IntWidth(32))), Port(,io_out,Output,UIntType(IntWidth(32)))),Block(ArrayBuffer(Block(ArrayBuffer(Connect(,WRef(io_out,UIntType(IntWidth(32)),PortKind,SinkFlow),WRef(io_in,UIntType(IntWidth(32)),PortKind,SourceFlow)))))))),SimpleCircuit))
execute = CombinationalPath(ReferenceTarget(SimpleCircuit,SimpleCircuit,List(),io_out,List()),ArrayBuffer(ReferenceTarget(SimpleCircuit,SimpleCircuit,List(),io_in,List())))
execute = EmitCircuitAnnotation(class firrtl.SystemVerilogEmitter)
execute = OutputFileAnnotation(regress/simple_test.v)
execute = TargetDirAnnotation(regress)
execute = InfoModeAnnotation(use)
execute = BlackBoxTargetDirAnno(regress)
execute = DeletedAnnotation(firrtl.stage.phases.AddCircuit,FirrtlFileAnnotation(regress/simple_test.fir))

例えば、EmitCircuitAnnotationを見てみる。ここでは、firrtl.SystemVerilogEmitterを引数として渡しているようだが、実体はVerilogEmitterと同一である。

  • firrtl/Emitter.scala
object EmitCircuitAnnotation extends HasShellOptions {

  val options = Seq(
    new ShellOption[String](
      longOption = "emit-circuit",
      toAnnotationSeq = (a: String) => a match {
        case "chirrtl"              => Seq(RunFirrtlTransformAnnotation(new ChirrtlEmitter),
                                           EmitCircuitAnnotation(classOf[ChirrtlEmitter]))
        case "high"                 => Seq(RunFirrtlTransformAnnotation(new HighFirrtlEmitter),
                                           EmitCircuitAnnotation(classOf[HighFirrtlEmitter]))
        case "middle"               => Seq(RunFirrtlTransformAnnotation(new MiddleFirrtlEmitter),
                                           EmitCircuitAnnotation(classOf[MiddleFirrtlEmitter]))
        case "low"                  => Seq(RunFirrtlTransformAnnotation(new LowFirrtlEmitter),
                                           EmitCircuitAnnotation(classOf[LowFirrtlEmitter]))
        case "verilog" | "mverilog" => Seq(RunFirrtlTransformAnnotation(new VerilogEmitter),
                                           EmitCircuitAnnotation(classOf[VerilogEmitter]))
        case "sverilog"             => Seq(RunFirrtlTransformAnnotation(new SystemVerilogEmitter),
                                           EmitCircuitAnnotation(classOf[SystemVerilogEmitter]))
        case _                      => throw new PhaseException(s"Unknown emitter '$a'! (Did you misspell it?)") },
...
  • firrtl/Emitter.scala
class SystemVerilogEmitter extends VerilogEmitter {
  StageUtils.dramaticWarning("SystemVerilog Emitter is the same as the Verilog Emitter!")
...

やはりEmitterのあたりがみそな気がするなあ。ここですべての構文に対するVerilogの対応が行われてる様子。

そもそも、Verilogに一対一対応で変換する前に、ファイルとして取り込んだFIRファイルをどこかで構文木に経関していると思うのだけれど、それはどこで行われているのだろう?