RISC-VのRMW(Read Modify Write)命令を自作OoOコアに実装しようとしている。
いくつか実装の方法がありそうだが、基本的なAtomic命令の形式をどのように作りこむのか考えてみる。
まず、RISC-VのAMOADD
命令は以下のように構成されている。
amoadd.w rd,rs2,(rs1) atomically load a 32-bit signed data value from the address in rs1, place the value into register rd, apply add the loaded value and the original 32-bit signed value in rs2, then store the result back to the address in rs1. x[rd] = AMO32(M[x[rs1]] + x[rs2])
なのでやらないといけないことは、
この場合、どうやって実装しようか特に悩むのは3.の部分で、 - 読み込みデータを一時的にSTQに保持し、rs2レジスタとの加算自体をSTQの中でやってしまう - シンプル。STQエントリが無駄になる。加算回路以外にもすべての演算に対してSTQの中でサポートする必要がある - ストアバッファにステートマシンを組み、L1キャッシュからデータを読み込み、演算を行い書き込む論理を追加する - 2番目にシンプル。ストアバッファのステートマシンを大幅に改造する必要がある。 - ストアバッファではなく、専用のアトミックバッファを使用して上記のステートマシンの動作を実現する - ストアバッファのステートマシンの改造が不要となる代わりに、新しいバッファが必要となる。
で、結局Atomic命令は複数同時にパイプラインを流れることはないので、3のように単一のバッファのみを持っておくだけで十分な気がする。 ただし、ストアバッファ以外に新しいL1Dのアクセスユニットを作るとArbitrationがより複雑になるので、ストアバッファのエントリ0のみをこの専用バッファにして、 ステートマシンの増加による回路の増加影響を最小限に抑えるのがよい気がしている。
もう一つは、RMW命令がSTQに格納された場合は、それよりも若い命令の投機実行を全て押さえる必要があるということだ。 特に若いロード命令はRMWがキャッシュをアップデートする前に同じアドレスを読み込んでも、ストアするデータがSTQの持っているrs2自体ではないので早すぎる。 したがって、若い命令はRMWが完了するまで投機的に動くことを控える必要がある。このために、パイプライン中(のほうがロードストア両方に対応できる)に、LDQ/STQを検索して自分よりも古いRMW命令が存在しているかチェックする機構が必要になると思う。