FPGA開発日記

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

RISC-Vのメモリ仮想化の方式について (v1.9.1編)

自作ISSのテストパタンが通らなくなってきた!

特に仮想メモリを使っているパタンが通らなくなった。大昔に自作ISSに仮想アドレスから物理アドレスの変換を実装していたのだが、どうやら仕様がv.1.9.1で変わっているらしい。 もう一度チェックしてみよう。

ちなみに、前回の解説はこちら。

msyksphinz.hatenablog.com

ここから、いろんな仕様が変更されている。

sptbr(Supervisor Page-Table Base Register)の仕様について

f:id:msyksphinz:20170210005726p:plain

v1.9.1には、sptbrの仕様変更が行われている。これまでは上位ビットにアドレス変換のベースアドレスが格納されていたが、sptbrのベースアドレスは下位(PPN)に移動されている。 Sv32の仕様ならば、PAGESIZE=2^12を乗算してベースアドレスとしている。

ページテーブルエントリの仕様について

ページテーブルの変換では、メモリ上(あるいはTLB)上に存在するアドレス情報を探索していくが、ページテーブルのエントリの仕様も変更されている。

f:id:msyksphinz:20170210010955p:plain

属性ビットがv.1.9.1では増強されている。

  • V=Valid Bit. ページテーブルエントリが有効であることを示す。
  • R=Read Bit. ページが読み込み可能であることを示す。
  • W=Write Bit. ページが書き込み可能であることを示す。
  • X=Executable Bit. ページがフェッチ可能であることを示す。 ちなみに、RWXがどれも1がセットされていない場合は、次のページテーブルへのポインタページとなっている。
  • U=UserMode Bit. ユーザモードのソフトウェアはU=1のページテーブルでないとアクセスできない。
  • G=Global Mapping Bit. グローバルマッピング。すべてのアドレス空間に存在していることを示す。
  • A=Access Bit. アクセス済みビット
  • D=Dirty Bit. 書き込み済みビット

アドレス変換処理の仕様変更について

v.1.7の場合

  1. i=LEVELS-1 (LEVEL=2)からスタートする。つまり、上位の変換ブロックから変換を始める。
  2. va.vpn[i]×PTSIZE(=4)+sptbr のアドレスを計算し(これが変換テーブルのアドレスとなる。つまり、va.vpn[i]をインデックスとして変換テーブルを参照している)、ページテーブルエントリ(=pte)を参照する。
  3. pte.Vビットを確認し、0であれば無効テーブルエントリなのでアドレスエラーを出力する。
  4. pte.type が2以上であれば、テーブルの参照の終端まで行ったことになるので、ステップ5に進む。ここでpte.typeの意味は以下のように定義されているようだ (Privileged Reference Manual参照)。

f:id:msyksphinz:20160115022437p:plain

つまり、Type=0 or 1であれば次のテーブルへの参照となるが、それ以外は最終的なページテーブルとなる。 ここでテーブルのアクセスエラーを確認する。 Type=0,1のときは次のアドレスを計算する。a=pte.ppn×PAGESIZEとし(つまりベースアドレスを更新する)、再度ステップ2に進む。また、i<0となるとこれもテーブル不良のためアドレスエラーとなる。

  1. ステップ5まで来たということは、i>=0の間にページテーブルの終端に到達したことを意味する。ここでpte.typeのアクセス権限を確認し、アクセス権限が足りなければエラーとなる。 そうでなければ、以下の方針でアドレス変換を実行する。

  2. オフセットはそのまま利用する。 pa.pgoff = va.pgoff

  3. i>0(=つまり、インデックスの参照を0まで使い切らない)場合はi-1から0まで(つまり到達しなかったレベル)は、仮想アドレスをそのまま物理アドレスとして利用する。 pa.ppn[i-1:0]=va.vpn[i-1:0]。
  4. それ以外のインデックスはページテーブルを参照して変換する。pa.ppn[LEVELS-1:i] = pte.ppn[LEVELS-1:i]

v.1.9.1の場合

  1. i=LEVELS-1 (LEVEL=2)からスタートする。つまり、上位の変換ブロックから変換を始める。
  2. va.vpn[i]×PTSIZE(=4)+sptbr.PPN×PAGESIZE(=212) のアドレスを計算し(これが変換テーブルのアドレスとなる。つまり、va.vpn[i]をインデックスとして変換テーブルを参照している)、ページテーブルエントリ(=pte)を参照する。
  3. pte.Vビット、pte.Rビット、pte.Wビットを確認し、pte.V=0、もしくはpte.R=0&pte.W=1であれば無効テーブルエントリなのでアドレスエラーを出力する。
  4. pte.R=1, pte.X=1であれば、テーブルの参照の終端まで行ったことになるので、ステップ5に進む。そうでなければ、a=pte.ppn×PAGESIZEとして2.に戻る。

  5. ステップ5まで来たということは、i>=0の間にページテーブルの終端に到達したことを意味する。以下の方針でアドレス変換を実行する。

  6. オフセットはそのまま利用する。 pa.pgoff = va.pgoff

  7. i>0(=つまり、インデックスの参照を0まで使い切らない)場合はi-1から0まで(つまり到達しなかったレベル)は、仮想アドレスをそのまま物理アドレスとして利用する。 pa.ppn[i-1:0]=va.vpn[i-1:0]。
  8. それ以外のインデックスはページテーブルを参照して変換する。pa.ppn[LEVELS-1:i] = pte.ppn[LEVELS-1:i]