FPGA開発日記

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

マルチポートRAMを使用するためのXOR Multiport RAMの実装

前のブログの記事では、LVTを用いたSingle Port RAMをMulti Portに複製するための方法について調査した。

msyksphinz.hatenablog.com

LVT(Live Value Table)を用いた手法では、各RAMインデックスについて、どのバンクRAMに最新の値が書き込まれているかを示すLVTエントリを用意する。 この手法は強力で便利なのだが、ポートの数が増えれば増えるほど、LVTの必要なビット幅は増加していく。

例えば、かなり高性能寄りCPUでは読み込みポートが12、書き込みポートが10とかいうとんでもない量のポートが必要になる。 また、物理レジスタの数を考慮すると256エントリなどのRAMを管理する必要があり、これを純粋にLVTで管理するとなると、必要となるLVTのFFの数は以下のように計算できる。

256 * $clog2(10) = 1024 FF

それでもって、このLVTをアップデートするための論理も結構きついものになってくる。単純に実装すると、10ポートのFFとなり、周辺の論理回路もかなり大きなものになるだろう。

always_ff @ (posedge i_clk, negedge i_reset_n) begin
  if (!i_reset_n) begin
    for (int i = 0; i < WORDS; i++)
      r_lvt[i] <= 'h0;
  end else begin
    for (int i = 0; i < WR_PORTS; i++) begin
      if (i_wr[i]) begin
        r_lvt[i_wr_addr[i]] <= i;
      end
    end
  end
end // always_ff @ (posedge i_clk, negedge i_reset_n)                                                                                                                                                                                                                                                                                                                                     

そこで、LVTすら排除してしまう手法であるXOR Multi Port RAMについて調査する。この手法はLVTを除去することができるが、さらに余分にRAMが必要なる。

tomverbeure.github.io

基本的な考え方としては、例えば書き込みポートが2であるとして、それぞれRAM1とRAM2を使用しているとする。あるインデックスAにそれぞれVALUE1, VALUE2が書き込まれているとする。 ライトポート0に対してNEWが書き込まれたとする。この時、RAM1に対して以下のようにRAM2との値を使用して変更した値を書き込む。

RAM1 New Value = NEW ^ VALUE2

そして、読み出すときはRAM1の値(NEW ^ VALUE2)とRAM1の値(VALUE2)をXORして読み出す。すると、NEW ^ VALUE2 ^ VALUE2 = NEWとなり、NEWの値を読み出すことができる。

ただし、これでは問題がある。読み込みと書き込みが同時に発生したとき、書き込みにも既存の値を読み出すために読み込みポートが必要になる。単純に考えればこのためにポートを1つ増やす必要があるが、これを回避する方法がある。それ専用のRAMを新たに追加すればよいのだ。 これは自分以外の書き込んだデータを記憶しておくためのRAMなので、各書き込みポートあたり、書き込みポート数-1個が必要となる。

結果的に、全体的に必要なRAMの数は、

書き込みに必要なRAMの数 = 書き込みポート数 * (書き込みポート数-1)
読み出しに必要なRAMの数 = 書き込みポート数 * 読み出しポート数
全体で必要なRAMの数 = 書き込みに必要なRAMの数 + 読み出しに必要なRAMの数 = 書き込みポート数 * (書き込みポート数-1+読み出しポート数)

となる。上記の読み出しポート=12,書き込みポート数=10の場合でLVTと必要なRAMの数を比較すると、

  • LVTの場合 = 10 * 12= 120
  • XORの場合 = 10 * (10-1+12) =10 * 21 = 210

と、大幅に増加してしまう。しかしまあ、LVTというクリティカルパスを完全に削除することができるため、使いどころによっては有用であろう。