FPGA開発日記

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

Rocket-Chipにおけるコンフィグレーション別の面積比較 (BlockRAMへのマッピングの問題)

Rocket Chipは構成によってどのようなコンポーネントが含まれているのかが変わっているのだが、それ以外にもリビジョンによっても結構構成が変わって、FPGAへのインプリメントに使用する面積が変わったりもする。

比較対象として、以下のリビジョンを使用した。

35d377d Merge pull request #1100 from freechipsproject/disable-local-amos (日記を執筆時点の最新のリビジョン)

  • DefaultConfig

FreeChipProjectのRocket Chipは、DefaultConfigとDefaultFPGAConfigというものが存在しており、それぞれの構成の違いは以下のようになっている。

  • src/main/scala/system/Config.scala
class DefaultConfig extends Config(new WithNBigCores(1) ++ new BaseConfig)
class DefaultFPGAConfig extends Config(new WithNSmallCores(1) ++ new BaseFPGAConfig)
class DefaultFPGASmallConfig extends Config(new DefaultFPGAConfig)

WithNBigCores()WithNSmallCores()の違いは、パラメータの違いとして表現されているのだが、

  • src/main/scala/coreplex/Config.scala
class WithNBigCores(n: Int) extends Config((site, here, up) => {
  case RocketTilesKey => {
    val big = RocketTileParams(
      core   = RocketCoreParams(mulDiv = Some(MulDivParams(
        mulUnroll = 8,
        mulEarlyOut = true,
        divEarlyOut = true))),
      dcache = Some(DCacheParams(
        rowBits = site(SystemBusKey).beatBits,
        nMSHRs = 0,
        blockBytes = site(CacheBlockBytes))),
      icache = Some(ICacheParams(
        rowBits = site(SystemBusKey).beatBits,
        blockBytes = site(CacheBlockBytes))))
    List.tabulate(n)(i => big.copy(hartid = i))
  }
})

class WithNSmallCores(n: Int) extends Config((site, here, up) => {
  case RocketTilesKey => {
    val small = RocketTileParams(
      core = RocketCoreParams(useVM = false, fpu = None),
      btb = None,
      dcache = Some(DCacheParams(
        rowBits = site(SystemBusKey).beatBits,
        nSets = 64,
        nWays = 1,
        nTLBEntries = 4,
        nMSHRs = 0,
        blockBytes = site(CacheBlockBytes))),
      icache = Some(ICacheParams(
        rowBits = site(SystemBusKey).beatBits,
        nSets = 64,
        nWays = 1,
        nTLBEntries = 4,
        blockBytes = site(CacheBlockBytes))))
    List.tabulate(n)(i => small.copy(hartid = i))
  }
})

これを見ると、だいたい分かってくるのは以下のような構成になっているということだ。主に命令キャッシュ、データキャッシュの構成を変更している。

WithNBigCores WithNSmallCores
コア機能 VM 指定なし(あり) なし
演算器 mulUnroll 8 指定なし(なし)
mulEarlyOut あり 指定なし(なし)
divEarlyOut あり 指定なし(なし)
FPU 指定なし(あり) なし
Dキャッシュ rowBits システムバスと同じサイズ システムバスと同じサイズ
セット数 指定なし(64) 64
ウェイ数 4 1
TLBエントリ数 32 4
MSHR数 0 0 MSHR: Miss Status Handling Register
ブロックバイト数 CacheBlockBytes CacheBlockBytes *
命令キャッシュ rowBits システムバスと同じサイズ システムバスと同じサイズ
セット数 64 64
ウェイ数 4 1
TLBエントリ数 32 4
ブロックバイト数 CacheBlockBytes CacheBlockBytes *

それぞれの構成において、Vivadoで論理合成して比較してみた。

なお、合成のためには以下のモジュールをRocket Chip以外に追加する必要がある。

  • plusarg_reader.v // Argument Reader シミュレーション用。ただしFPGA合成用はからのモジュールが定義される。
  • freechips.rocketchip.system.DefaultFPGAConfig.behav_srams.v // SRAMのビヘイビアモデル。一応FPGAで合成することは出来るが、あまり良い構成ではない。

というわけで、Rocket-ChipのVerilogのモジュールのうち、RocketTile_rocket から下の1階層のモジュールの面積比較を行ってみた。

f:id:msyksphinz:20171111141629p:plain

DCacheが大きすぎる。ちゃんとブロックRAMに変換できていないんじゃないか?BigCoresとSmallCoresでキャッシュの構成が違いすぎている気がする。

基本的にDCacheの大きさがダイレクトに聞いているような気がしていて、data_arrays_0_extを正しく作らなければこのようになってしまう。 これは外部のVerilogで定義されているのだが、この実装がそのまんまなのでBlockRAMに手起業させることが出来ない。 っていうかRAMBを全く使ってくれない。

  • WithNBigCoresの場合
+---------------------------------------+----------------------------+------------+------------+---------+------+--------+--------+--------+--------------+
|                Instance               |           Module           | Total LUTs | Logic LUTs | LUTRAMs | SRLs |   FFs  | RAMB36 | RAMB18 | DSP48 Blocks |
+---------------------------------------+----------------------------+------------+------------+---------+------+--------+--------+--------+--------------+
|     dcache                            |              DCache_dcache |      56796 |      56795 |       0 |    1 | 133722 |      0 |      4 |            0 |
|       (dcache)                        |              DCache_dcache |        788 |        787 |       0 |    1 |    536 |      0 |      0 |            0 |
|       data                            |            DCacheDataArray |      54494 |      54494 |       0 |    0 | 131145 |      0 |      0 |            0 |
|         data_arrays_0                 |              data_arrays_0 |      54494 |      54494 |       0 |    0 | 131145 |      0 |      0 |            0 |
|           data_arrays_0_ext           |          data_arrays_0_ext |      54494 |      54494 |       0 |    0 | 131145 |      0 |      0 |            0 |
|       tag_array                       |                  tag_array |        147 |        147 |       0 |    0 |      0 |      0 |      4 |            0 |
|         tag_array_ext                 |              tag_array_ext |        147 |        147 |       0 |    0 |      0 |      0 |      4 |            0 |
|       tlb                             |                        TLB |       1367 |       1367 |       0 |    0 |   2041 |      0 |      0 |            0 |
  • WithNSmallCoresの場合
+--------------------------------+----------------------------+------------+------------+---------+------+------+--------+--------+--------------+
|            Instance            |           Module           | Total LUTs | Logic LUTs | LUTRAMs | SRLs |  FFs | RAMB36 | RAMB18 | DSP48 Blocks |
+--------------------------------+----------------------------+------------+------------+---------+------+------+--------+--------+--------------+
|     dcache                     |              DCache_dcache |       1119 |       1119 |       0 |    0 |  482 |      1 |      1 |            0 |
|       (dcache)                 |              DCache_dcache |        880 |        880 |       0 |    0 |  482 |      0 |      0 |            0 |
|       data                     |            DCacheDataArray |        139 |        139 |       0 |    0 |    0 |      1 |      0 |            0 |
|         data_arrays_0          |              data_arrays_0 |        139 |        139 |       0 |    0 |    0 |      1 |      0 |            0 |
|           data_arrays_0_ext    |          data_arrays_0_ext |        139 |        139 |       0 |    0 |    0 |      1 |      0 |            0 |
|       tag_array                |                  tag_array |         91 |         91 |       0 |    0 |    0 |      0 |      1 |            0 |
|         tag_array_ext          |              tag_array_ext |         91 |         91 |       0 |    0 |    0 |      0 |      1 |            0 |
|       tlb                      |                        TLB |          9 |          9 |       0 |    0 |    0 |      0 |      0 |            0 |
|         pmp                    |                 PMPChecker |          9 |          9 |       0 |    0 |    0 |      0 |      0 |            0 |

以下がそのVerilogの実装だ。ちょっとひどい。ちゃんとBlockRAMに置き換えないと。

  • WithNBigCores の場合、 freechips.rocketchip.system.DefaultConfig.behav_srams.v の構成
  reg [255:0] ram [511:0];
...
  always @(posedge RW0_clk)
    if (RW0_en && RW0_wmode) begin
      if (RW0_wmask[0]) ram[RW0_addr][7:0] <= RW0_wdata[7:0];
      if (RW0_wmask[1]) ram[RW0_addr][15:8] <= RW0_wdata[15:8];
      if (RW0_wmask[2]) ram[RW0_addr][23:16] <= RW0_wdata[23:16];
      if (RW0_wmask[3]) ram[RW0_addr][31:24] <= RW0_wdata[31:24];
      if (RW0_wmask[4]) ram[RW0_addr][39:32] <= RW0_wdata[39:32];
      if (RW0_wmask[5]) ram[RW0_addr][47:40] <= RW0_wdata[47:40];
      if (RW0_wmask[6]) ram[RW0_addr][55:48] <= RW0_wdata[55:48];
      if (RW0_wmask[7]) ram[RW0_addr][63:56] <= RW0_wdata[63:56];
      if (RW0_wmask[8]) ram[RW0_addr][71:64] <= RW0_wdata[71:64];
      if (RW0_wmask[9]) ram[RW0_addr][79:72] <= RW0_wdata[79:72];
      if (RW0_wmask[10]) ram[RW0_addr][87:80] <= RW0_wdata[87:80];
      if (RW0_wmask[11]) ram[RW0_addr][95:88] <= RW0_wdata[95:88];
      if (RW0_wmask[12]) ram[RW0_addr][103:96] <= RW0_wdata[103:96];
      if (RW0_wmask[13]) ram[RW0_addr][111:104] <= RW0_wdata[111:104];
      if (RW0_wmask[14]) ram[RW0_addr][119:112] <= RW0_wdata[119:112];
      if (RW0_wmask[15]) ram[RW0_addr][127:120] <= RW0_wdata[127:120];
      if (RW0_wmask[16]) ram[RW0_addr][135:128] <= RW0_wdata[135:128];
      if (RW0_wmask[17]) ram[RW0_addr][143:136] <= RW0_wdata[143:136];
  • WithNSmallCores の場合、 freechips.rocketchip.system.DefaultFPGAConfig.behav_srams.v の構成
  reg [63:0] ram [511:0];
  always @(posedge RW0_clk)
    if (RW0_en && RW0_wmode) begin
      if (RW0_wmask[0]) ram[RW0_addr][7:0] <= RW0_wdata[7:0];
      if (RW0_wmask[1]) ram[RW0_addr][15:8] <= RW0_wdata[15:8];
      if (RW0_wmask[2]) ram[RW0_addr][23:16] <= RW0_wdata[23:16];
      if (RW0_wmask[3]) ram[RW0_addr][31:24] <= RW0_wdata[31:24];
      if (RW0_wmask[4]) ram[RW0_addr][39:32] <= RW0_wdata[39:32];
      if (RW0_wmask[5]) ram[RW0_addr][47:40] <= RW0_wdata[47:40];
      if (RW0_wmask[6]) ram[RW0_addr][55:48] <= RW0_wdata[55:48];
      if (RW0_wmask[7]) ram[RW0_addr][63:56] <= RW0_wdata[63:56];
    end

追記: fpga-zynqの構成で実行すると、BlockRAMが正しく推論されているようだ。

+-----------------------------------------+------------------------------------------+------------+------------+---------+------+-------+--------+--------+--------------+
|                 Instance                |                  Module                  | Total LUTs | Logic LUTs | LUTRAMs | SRLs |  FFs  | RAMB36 | RAMB18 | DSP48 Blocks |
+-----------------------------------------+------------------------------------------+------------+------------+---------+------+-------+--------+--------+--------------+
|     DCache                              |                                   DCache |       1659 |       1658 |       0 |    1 |   986 |      0 |     36 |            0 |
|       (DCache)                          |                                   DCache |        504 |        503 |       0 |    1 |   502 |      0 |      0 |            0 |
|       MetadataArray                     |                            MetadataArray |        283 |        283 |       0 |    0 |     7 |      0 |      4 |            0 |
|       data                              |                          DCacheDataArray |        535 |        535 |       0 |    0 |     0 |      0 |     32 |            0 |
|       fq                                |                              FinishQueue |          8 |          8 |       0 |    0 |     5 |      0 |      0 |            0 |
|       tlb                               |                                    TLB_2 |        329 |        329 |       0 |    0 |   472 |      0 |      0 |            0 |