C89規格ではasmが予約語として使われているので__asm__を用いる。せっかくアセンブラで書いてもコンパイラが要らない最適化をすることがあるのでvolatileを書いておく。
この辺から軽くコードを書いて、それを説明しようと思う。
__asm__ volatile (
"vmzero.q M000\n"
);
こんな風にするとVFPUの0~15番レジスタを0にできる。
vmzeroというのはVFPU Matrix Zero Clearの略だと思われる。qはquad即ち4なので、4x4Matrix(行列)をゼロクリアする命令となる。qのほかにs(Single)、p(pair)、t(triple)がある。
その後のM000というのは000番レジスタを基点とするMatrixという意味。
M以外にS(Scalar)C(Column)R(Row)E(単語不明)等があります。それぞれ、1つのレジスタ、行としてのレジスタ群、列としてのレジスタ群、転置行列としてのレジスタ群という意味。
レジスタの番号は左からブロック番号、行番号、列番号となっている。
レジスタの番号については以下のURLを参照。
http://wiki.fx-world.org/doku.php?id=general:vfpu_registers
アセンブラとC言語の変数の間で値をやりとりする場合を以下に示す。
float scalar = 5.0f;
scePspFVector4 vector;
__asm__ volatile(
"mtv %1,S000\n"
"vmov.q C000,C000[x,x,x,x]\n"
"usv.q C000,%0\n"
:"=m"(vector)
:"r"(scalar)
);
mtv命令はMove To VFPUの略と思われる。CPUのレジスタの値をVFPUのレジスタにコピーする命令。%1については後述する。
vmov.qは4つのデータを扱うVFPU Move命令で、役割としては値のコピー。[x,x,x,x]というものはプレフィックスといわれる。レジスタの直後に指定することで簡単なベクトルの変形が行える。x,y,z,wを指定するとそれぞれ0~3番目のレジスタを入力として使うことになる。今回はxだけが指定されているので、コピー前にC000の0番目のレジスタの内容が0~3番にコピーされた一時的なベクトルが(直接見えないけれど)あると考えてよい。
プレフィックスに指定できるのは他に-x,-y,-z,-wつまり符号を反転させたもの。|x|,|y|,|z|,|w|という絶対値のついたもの。0,1,2,3,1/2,1/3,1/6のどれかの数値である。
usv.qはUnaligned Store Vector命令で、アラインメントされていないメモリ上のベクトル型変数に対してレジスタの内容を書き込む命令。一般にプロセッサがメモリを読むときはロード、書き込むときはストアと言うのは覚えておこう。%0については以下に書く。
もう気が付いた方もいると思うが、%0は下のほうで記述されている0番目の変数、%1は1番目の変数である。つまりC言語でvectorとscalarという名前をつけられた変数である。
"=m"というのはアセンブラが値を変更するかもしれないメモリ上のオブジェクトという意味だ。"r"はアセンブラからは読み出しのみ行うレジスタ上のオブジェクトという意味になる。
=があれば代入可能、無ければ読み出し専用となっている。読み書きを両方する場合は+を書く必要がある。
mとrは書くまでもないかも知れないが、memoryとregisterの頭文字である。
一つ目の:の後にアセンブラが値を変更するものを、二つ目の:の後にアセンブラからは値を読み出すだけのものを記述する。三つ目は省略されていて、本来アセンブラが使う(つまり元々そこにあったデータが破棄される)レジスタを記述するものである。ただし、VFPUを使うだけなら省略しても別に問題はでない。なお、複数のものが:と:の間にある場合は,で区切る必要がある。
あとは数学のベクトルや行列をまともに勉強していれば別に困ることは無いと思う。
命令一覧は以下を参照。
http://wiki.fx-world.org/doku.php?id=general:cycles
"vzero.q C00\n"
0 件のコメント:
コメントを投稿