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で定義したコンフィグレーションなので、このFireSimRocketChipMatrixMulConfig
のVerilogを生成すればアクセラレータ付きのFireSimデザインを生成することができる。
まだもう少しやることがある。先ほどサブモジュールとしてチェックアウトしたfiresim-msyksphinz
を、Chiselが参照するようにディレクトリを指定しなければならない。Chiselのソースコードの管理や、プロジェクトの管理は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)
まず、rocketChipDir
とfireChipDir
をtarge-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,
...