FPGA開発日記

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

Chipyardで独自コアシミュレーション環境構築方法の調査 (2)

ArianeCoreの生成方法が分かったので、次は独自コアの構成方法について調査してみよう。ここでは、独自のRISC-Vコア MSRH を接続する方法について考えてみる。

この調査の目的は、Chipyardの環境を使えば、CPUコアを設計してインタフェースを統一すれば簡単にシミュレーション環境とFPGA環境を構築することができるのではないかという目論見だ。自作CPUは楽しいが、テスト環境やメモリサブシステムを構築するのは実に面倒くさい。そこでChipyardに外部インタフェースとメモリアクセスの部分はすべてお任せしてしまい、まずはCPUコアの設計設計のみに集中できる環境が構築できるのではないかという考えがある。

このためには、まずRocketTile, BoomTile, ArianeTileに続いて独自CPUコア用のTileを構築する。これはMSRHTileとする。まずはこれを構築していこう。

$ tree msrh
msrh
|-- build.sbt
`-- src
    `-- main
        `-- scala
            |-- ConfigMixins.scala
            |-- MSRHCoreBlackbox.scala
            `-- MSRHTile.scala

3 directories, 4 files

MRSHTileは基本的にArianeTileから持ってきている。ArianeTileから名前を変えてMSRHTileとしている。MSRHCoreBlackBoxも同様。ConfigMixins.scalaもArianeの構成を同様にMSRHに変更している。

そしてVerilog生成用のConfigはArianeConfig.scalaと並列に作成する。

  • generators/chipyard/src/main/scala/config/MSRHConfigs.scala
class MSRHConfig extends Config(
  new chipyard.iobinders.WithUARTAdapter ++                      // display UART with a SimUARTAdapter
  new chipyard.iobinders.WithTieOffInterrupts ++                 // tie off top-level interrupts
  new chipyard.iobinders.WithSimAXIMem ++                        // drive the master AXI4 memory with a SimAXIMem
...
  new freechips.rocketchip.subsystem.WithNExtTopInterrupts(0) ++ // no external interrupts
  new msrh.WithNMSRHCores(1) ++                              // single MSRH core
  new freechips.rocketchip.subsystem.WithCoherentBusTopology ++  // hierarchical buses including mbus+l2
  new freechips.rocketchip.system.BaseConfig)                    // "base" rocketchip system

msrhWithNMSRHCores()は以下のような構成となっている。

  • generators/msrh/src/main/scala/ConfigMixins.scala
class WithNMSRHCores(n: Int) extends Config(
  new WithNormalMSRHSys ++
  new Config((site, here, up) => {
    case MSRHTilesKey => {
      List.tabulate(n)(i => MSRHTileParams(hartId = i))
    }
  })
)

そして、Tileの生成の部分に、Arianeの次に独自CPUコアの構成を追加する。

  • generators/chipyard/src/main/scala/Subsystem.scala
diff --git a/generators/chipyard/src/main/scala/Subsystem.scala b/generators/chipyard/src/main/scala/Subsystem.scala
index 99c3147..b08b68f 100644
--- a/generators/chipyard/src/main/scala/Subsystem.scala
+++ b/generators/chipyard/src/main/scala/Subsystem.scala
@@ -23,6 +23,7 @@ import freechips.rocketchip.amba.axi4._

 import boom.common.{BoomTile, BoomTilesKey, BoomCrossingKey, BoomTileParams}
 import ariane.{ArianeTile, ArianeTilesKey, ArianeCrossingKey, ArianeTileParams}
+import msrh.{MSRHTile, MSRHTilesKey, MSRHCrossingKey, MSRHTileParams}

 import testchipip.{DromajoHelper}

@@ -37,13 +38,15 @@ trait HasChipyardTiles extends HasTiles
   protected val rocketTileParams = p(RocketTilesKey)
   protected val boomTileParams = p(BoomTilesKey)
   protected val arianeTileParams = p(ArianeTilesKey)
+  protected val msrhTileParams = p(MSRHTilesKey)

   // crossing can either be per tile or global (aka only 1 crossing specified)
   private val rocketCrossings = perTileOrGlobalSetting(p(RocketCrossingKey), rocketTileParams.size)
   private val boomCrossings = perTileOrGlobalSetting(p(BoomCrossingKey), boomTileParams.size)
   private val arianeCrossings = perTileOrGlobalSetting(p(ArianeCrossingKey), arianeTileParams.size)
+  private val msrhCrossings = perTileOrGlobalSetting(p(MSRHCrossingKey), msrhTileParams.size)

-  val allTilesInfo = (rocketTileParams ++ boomTileParams ++ arianeTileParams) zip (rocketCrossings ++ boomCrossings ++ arianeCrossings)
+  val allTilesInfo = (rocketTileParams ++ boomTileParams ++ arianeTileParams ++ msrhTileParams) zip (rocketCrossings ++ boomCrossings ++ arianeCrossings ++ msrhCrossings)

   // Make a tile and wire its nodes into the system,
   // according to the specified type of clock crossing.
@@ -65,6 +68,9 @@ trait HasChipyardTiles extends HasTiles
         case a: ArianeTileParams => {
           LazyModule(new ArianeTile(a, crossing, PriorityMuxHartIdFromSeq(arianeTileParams), logicalTreeNode))
         }
+        case m: MSRHTileParams => {
+          LazyModule(new MSRHTile(m, crossing, PriorityMuxHartIdFromSeq(msrhTileParams), logicalTreeNode))
+        }
       }
       connectMasterPortsToSBus(tile, crossing)
       connectSlavePortsToCBus(tile, crossing)

ここまで追加して、Arianeと全く同じ構成で名前だけ変えたChipyardのVerilog構成が完成する。一応Verilogは生成されている。ただしBlackBoxは生成していないのでVerilatorが実行された時点でコンパイルは失敗する。まあとりあえずここまででいいや。インタフェースを統一して、接続確認をしていこうと思う。