FPGA開発日記

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

Rocket-ChipのTLBがメモリの属性を取得する仕組み

Rocket-ChipのTLBは、TLBミスが発生すると外部のPTWにアクセスして当該メモリ領域の属性を取得する。

その実装を探していたのだが、Chiselで書いてあって非常に分かりにくい。PTWの実装のうち、おそらくこの辺がPMAのテーブルを作っているものと思われる。

  • sims/verilator/generated-src/chipyard.TestHarness.RocketConfig/chipyard.TestHarness.RocketConfig.top.v
 module PTW(
   input         clock,
   input         reset,
   output        io_requestor_0_req_ready,
/* ... 中略 ... */
   wire [16:0] s2_entry_vec_0_tag = uncorrected[42:26]; // @[PTW.scala 261:59]
   wire  s2_hit_vec_0 = s2_valid_vec & r_tag == s2_entry_vec_0_tag; // @[PTW.scala 262:83]
   wire  s2_hit = s2_valid & s2_hit_vec_0; // @[PTW.scala 263:27]
   wire [65:0] _pmaPgLevelHomogeneous_T_6 = pte_addr ^ 66'hc000000; // @[Parameters.scala 137:31]
   wire [66:0] _pmaPgLevelHomogeneous_T_7 = {1'b0,$signed(_pmaPgLevelHomogeneous_T_6)}; // @[Parameters.scala 137:49]
   wire [66:0] _pmaPgLevelHomogeneous_T_9 = $signed(_pmaPgLevelHomogeneous_T_7) & -67'sh4000000; // @[Parameters.scala 137:52]
   wire  _pmaPgLevelHomogeneous_T_10 = $signed(_pmaPgLevelHomogeneous_T_9) == 67'sh0; // @[Parameters.scala 137:67]
   wire [65:0] _pmaPgLevelHomogeneous_T_11 = pte_addr ^ 66'h80000000; // @[Parameters.scala 137:31]
   wire [66:0] _pmaPgLevelHomogeneous_T_12 = {1'b0,$signed(_pmaPgLevelHomogeneous_T_11)}; // @[Parameters.scala 137:49]
   wire [66:0] _pmaPgLevelHomogeneous_T_14 = $signed(_pmaPgLevelHomogeneous_T_12) & -67'sh10000000; // @[Parameters.scala 137:52]
   wire  _pmaPgLevelHomogeneous_T_15 = $signed(_pmaPgLevelHomogeneous_T_14) == 67'sh0; // @[Parameters.scala 137:67]
   wire  pmaPgLevelHomogeneous_1 = _pmaPgLevelHomogeneous_T_10 | _pmaPgLevelHomogeneous_T_15; // @[TLBPermissions.scala 98:65]
   wire [66:0] _pmaPgLevelHomogeneous_T_20 = {1'b0,$signed(pte_addr)}; // @[Parameters.scala 137:49]
   wire [66:0] _pmaPgLevelHomogeneous_T_38 = $signed(_pmaPgLevelHomogeneous_T_20) & -67'sh5000; // @[Parameters.scala 137:52]
/* ... 中略 ... */

この辺の実装についてはChisel側を眺めてみると、edge.managerなどが出てくるのでおそらくDiplomacyで接続された各デバイスからメモリアクセスの属性の情報を取得して、テーブルに纏めているものと思われる。

  • rocket-chip/src/main/scala/rocket/PTW.scala
   val pageGranularityPMPs = pmpGranularity >= (1 << pgIdxBits)
   val pmaPgLevelHomogeneous = (0 until pgLevels) map { i =>
     val pgSize = BigInt(1) << (pgIdxBits + ((pgLevels - 1 - i) * pgLevelBits))
     if (pageGranularityPMPs && i == pgLevels - 1) {
       require(TLBPageLookup.homogeneous(edge.manager.managers, pgSize), s"All memory regions must be $pgSize-byte aligned")
       true.B
     } else {
       TLBPageLookup(edge.manager.managers, xLen, p(CacheBlockBytes), pgSize)(pte_addr).homogeneous
     }
   }
   val pmaHomogeneous = pmaPgLevelHomogeneous(count)
   val pmpHomogeneous = new PMPHomogeneityChecker(io.dpath.pmp).apply(pte_addr >> pgIdxBits << pgIdxBits, count)
   val homogeneous = pmaHomogeneous && pmpHomogeneous