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