FPGA開発日記

FPGAというより、コンピュータアーキテクチャかもね! カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages

AWS F1インスタンス上のFireSimでBOOMコアをシミュレーションする試行(8. カスタマイズしたアクセラレータをFireSimのプラットフォーム上に構築する)

f:id:msyksphinz:20190405012417p:plain

FireSimの環境で、どうにかRocketシングルコアを動かすことができた。ここまでできれば、今度は様々なハードウェアをf1インスタンスで動かしてみたい。RocketはChiselというハードウェア記述言語で設計されているが、ChiselでオリジナルのモジュールをRocketに追加して、オリジナルのRocketコアを作れば、f1インスタンス上で動作させることができると思う。

前回までのFireChipのシミュレーションは、いわゆるコアの単体でソフトウェアとハードウェアの動作を確認した。今度は、AWS f1インスタンス上で動作させるために、FireChipのデザインをFireSimに乗せる必要がある。

イメージとしては、FireSimがf1インスタンスを含むFPGAイメージ+SoCと考えればよい。SoCの中にFireChipが入っており、1部品としてFireSimに埋め込む。

このためには、FireSimのデザインに、FireChipのデザインを認識させなければならない。 FireSimリポジトリにはtarget-design/firechipとしてサブリポジトリが配置されている。このfirechipリポジトリはUCBのfirechipプロジェクト公式(https://github.com/firesim/firechip)のものだ。しかしこのリポジトリをforkしてオリジナルのfirechipリポジトリを作っていた。まずはこのリポジトリtarget-designディレクトリに配置しなければならない。

cd target-design
git submodule add https://github.com/msyksphinz/firechip -b memory-mapped-io firechip-msyksphinz

以下のようなディレクトリ構成になる。

$ tree -L 1 target-design
target-design
├── firechip
├── firechip-msyksphinz
└── switch

では次にFireSimリポジトリ内で新しいコンフィグレーションを作成する。コンフィグレーションというのは、ターゲットのハードウェアの構成などを示したChiselで書かれたクラスだ。あるコンフィグレーションを指定するとコアが1つ、あるいは別のコンフィグレーションを指定するとキャッシュサイズを変えることができる、など、1つのリポジトリの中に複数のコンフィグレーションを定義することができ、Verilogの生成や論理合成時にどのターゲットを使用するか指定する。

今回はFireSimのリポジトリに以下のソースファイルを追加した。

  • sim/src/main/scala/firesim/TargetConfigs.scala
diff --git a/sim/src/main/scala/firesim/TargetConfigs.scala b/sim/src/main/scala/firesim/TargetConfigs.scala
index d18574f..7bccd4f 100644
--- a/sim/src/main/scala/firesim/TargetConfigs.scala
+++ b/sim/src/main/scala/firesim/TargetConfigs.scala
@@ -9,6 +9,7 @@ import boom.system.BoomTilesKey
 import testchipip.{WithBlockDevice, BlockDeviceKey, BlockDeviceConfig}
 import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTParams}
 import icenet._
+import example._

 class WithBootROM extends Config((site, here, up) => {
   case BootROMParams => BootROMParams(
@@ -90,6 +91,20 @@ class FireSimRocketChipConfig extends Config(
   new WithPerfCounters ++
   new freechips.rocketchip.system.DefaultConfig)

+
+class FireSimMatrixMulConfig extends Config(
+  new WithBootROM ++
+  new WithPeripheryBusFrequency(BigInt(3200000000L)) ++
+  new WithExtMemSize(0x400000000L) ++ // 16GB
+  new WithoutTLMonitors ++
+  new WithUARTKey ++
+  new WithNICKey ++
+  new WithBlockDevice ++
+  new WithRocketL2TLBs(1024) ++
+  new WithPerfCounters ++
+  new example.RoccMatrixMulConfig)
+
+
 class WithNDuplicatedRocketCores(n: Int) extends Config((site, here, up) => {
   case RocketTilesKey => List.tabulate(n)(i => up(RocketTilesKey).head.copy(hartId = i))
 })
@@ -100,6 +115,9 @@ class FireSimRocketChipTracedConfig extends Config(
 // single core config
 class FireSimRocketChipSingleCoreConfig extends Config(new FireSimRocketChipConfig)

+// single core config
+class FireSimRocketChipMatrixMulConfig extends Config(new FireSimMatrixMulConfig)
+

一番大元になるコンフィグレーション名はFireSimRocketChipMatrixMulConfigだ。このクラスはFireSimMatrixMulConfigを呼び出しており、これはexample.RoccMatrixMulConfigと各種デバイスやバスを定義している。RoccMatrixMulConfigはFireChipで定義したコンフィグレーションなので、このFireSimRocketChipMatrixMulConfigVerilogを生成すればアクセラレータ付きのFireSimデザインを生成することができる。

まだもう少しやることがある。先ほどサブモジュールとしてチェックアウトしたfiresim-msyksphinzを、Chiselが参照するようにディレクトリを指定しなければならない。Chiselのソースコードの管理や、プロジェクトの管理はsim/build.sbtで管理する。

  • sim.build.sbt
diff --git a/sim/build.sbt b/sim/build.sbt
index daae7dc..fda246f 100644
--- a/sim/build.sbt
+++ b/sim/build.sbt
@@ -21,8 +21,8 @@ def isolateAllTests(tests: Seq[TestDefinition]) = tests map { test =>

 testGrouping in Test := isolateAllTests( (definedTests in Test).value )

-val rocketChipDir = file("target-rtl/firechip/rocket-chip")
-val fireChipDir  = file("target-rtl/firechip")
+val rocketChipDir = file("target-rtl/firechip-msyksphinz/rocket-chip")
+val fireChipDir  = file("target-rtl/firechip-msyksphinz")

 // Subproject definitions begin
 // NB: FIRRTL dependency is unmanaged (and dropped in sim/lib)
@@ -67,6 +67,10 @@ lazy val icenet     = (project in fireChipDir / "icenet")
   .settings(commonSettings)
   .dependsOn(rocketchip, testchipip)

+lazy val example    = (project in fireChipDir / "src/main/scala/example")
+  .settings(commonSettings)
+  .dependsOn(rocketchip, testchipip, icenet)
+
 // MIDAS-specific dependencies
 lazy val mdf        = RootProject(file("barstools/mdf/scalalib"))
 lazy val barstools  = (project in file("barstools/macros"))
@@ -79,4 +83,4 @@ lazy val midas      = (project in file("midas"))
 // Finally the root project
 lazy val firesim    = (project in file("."))
   .settings(commonSettings)
-  .dependsOn(rocketchip, midas, boom, icenet, sifiveip)
+  .dependsOn(rocketchip, midas, boom, icenet, sifiveip, example)

まず、rocketChipDirfireChipDirtarge-rtl/firechip/からtarget-rtl/firechip-msyksphinzに書き換えている。また、FireChipディレクトリの中でsrc/main/scala/example内のコンフィグレーションを参照してほしいので、example変数を定義し、さらにfiresim変数の依存関係にexampleを追加している。

これで、simディレクトリに移動してmakeを実行してみる。

make TARGET_CONFIG=FireSimRocketChipMatrixMulConfig

しばらく待つと、RTLが生成されているのが分かる。生成されたRTLを見てみると、開発したMatrixMulモジュールがしっかり組み込まれていた。

find . -name "*.v" | grep Matrix
...
./generated-src/f1/FireSim-FireSimRocketChipMatrixMulConfig-FireSimConfig/FPGATop.v
  • generated-src/f1/FireSim-FireSimRocketChipMatrixMulConfig-FireSimConfig/FPGATop.v
module MatrixMul(
  input         clock,
  input         reset,
  output        io_cmd_ready,
  input         io_cmd_valid,
  input  [6:0]  io_cmd_bits_inst_funct,
  input  [4:0]  io_cmd_bits_inst_rd,
  input  [63:0] io_cmd_bits_rs1,
  input  [63:0] io_cmd_bits_rs2,
...