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が実行された時点でコンパイルは失敗する。まあとりあえずここまででいいや。インタフェースを統一して、接続確認をしていこうと思う。