ハードウェアの気になるあれこれ

技術的に興味のあることを調べて書いてくブログ。主にハードウェアがネタ。

Rocket ChipのGeneratorのソースの解析メモ(2) - generateFirrtlを追ってみる

スポンサーリンク

Rocket Chip環境の仕組み解析メモの垂れ流し記事。前回見ていったGeneratorの中のgenerateFirrtlを見ていくのが良さそうだったので、今回からはそれを少しずつ見ていく。

generateFirrtl

このメソッドはGeneratorオブジェクトが継承するGeneratorAppトレイト内に定義されている。 GeneratorAppが定義されているファイルは"util/GeneratorUtils.scala" 処理は以下。

  /** Output FIRRTL, which an external compiler can turn into Verilog. */
  def generateFirrtl {
    Driver.dumpFirrtl(circuit, Some(new File(td, s"$longName.fir"))) // FIRRTL
  }

Driver.dumpFirrtlの第一引数circuitGeneratorAppトレイト内にlazy valとして宣言されている。

  lazy val names: ParsedInputNames = {
    require(args.size == 5, "Usage: sbt> " +
      "run TargetDir TopModuleProjectName TopModuleName " +
      "ConfigProjectName ConfigNameString")
    ParsedInputNames(
      targetDir = args(0),
      topModuleProject = args(1),
      topModuleClass = args(2),
      configProject = args(3),
      configs = args(4))
  }

  lazy val td: String = names.targetDir
  lazy val config: Config = getConfig(names.fullConfigClasses)
  lazy val params: Parameters = config.toInstance
  lazy val circuit: Circuit = elaborate(names.fullTopModuleClass, params)

トレイト内部でプログラム引数argsから値を生成するためlazy valにして遅延評価している。

トレイト"GeneratorApp"の挙動

順番的には

  1. generateFirrtl内でcircuitが参照される
  2. GeneratorAppトレイト内のlazy val circuitが評価される
  3. circuitの右辺のelaborateの引数でnames/paramsが参照される
  4. paramsの評価が始まる

という感じ。 なお、namesはGeneratorオブジェクト内部でlongNameの構築時に既に参照されているのでそのタイミングで値が評価される。

elaborateの処理

上述の様にcircuitという変数にelaborateされた結果のFIRRTLが格納されている。 下記のelaborateメソッドの第1引数は既出のParsedInputNamesにて引数より構築された文字列になっており、それがelaborateで生成されるFIRRTLのトップ階層のクラス名になっている。

  def elaborate(fullTopModuleClassName: String, params: Parameters): Circuit = {
    val top = () =>
      Class.forName(fullTopModuleClassName)
          .getConstructor(classOf[Parameters])
          .newInstance(params) match {
        case m: RawModule => m
        case l: LazyModule => LazyModule(l).module
      }

    Driver.elaborate(top)
  }

上記のコードでは第一引数のfullTopModuleClassNameJAVAのClass.forNameに入れることで、所望のトップ階層のモジュールを文字列から生成してそれをChiselのDriverに渡すことでFIRRTLを生成している。 なのでコードとしては以下のコードのMyModule部分をプログラム引数から生成できるようにしたイメージ。

object Elaborate extends App {
  Driver.elaborate(() => new MyModule())
}

上記elaborateメソッドの第1引数はrunMain実行時にGeneratorオブジェクトに渡すプログラム引数の2番目/3番めの要素を結合したものになっており、READMEの手順に従ってmakeした時は以下のような文字列になっている。

  • "freechips.rocketchip.system.TestHarness"

ということでemulatorディレクトリの下でmakeを実行して生成可能なRokcet Chipのトップ階層のモジュールは

  • src/main/scala/system/TestHarness.scalaの中のTestHarness()クラス

ということになる。 このクラスはただのChiselのModuleになっているためval topmatch式に於いてはcase mにマッチし、それがそのままtopに格納されている。

とりあえず今日はここまで。次回はTestHarnessの中身を少し追ってみようと思う。