極楽プレイステーション
R3000のお約束


更新日付 1998-03-03

開発用のプレイステーションを買って、ゲームを作っています。
もともとX68000を使っていたこともあり、
あっという間にゲームが作れるようになりました。
で、私も何か講座を開こうと思ったのですが、
すでに多くのホームページが公開されていました。
というわけで、誰もやっていないアセンブラ講座です。
内容は独自の解析結果に基づいていますので、
間違いなどがありましたら、メールで教えてください。

[戻る]


・R3000の基礎知識

R3000の構造とアセンブラについてまとめておきます。
命令はひじょうに直交性が高く、
68000系と同じようにひじょうに美しいものです。
86系などと違って頭が腐ることはありません。


・レジスタ

R3000のレジスタは32個、それらは$0〜$31と記述できますが、
すべてにあだ名がついていて、
あだ名でプログラミングすることもできます。
レジスタ 呼び名 用途
$0 zero 常に0。あんたそれでもレジスタか?
$1 at アセンブラで使用。
命令を最適化する際に使われる。
$2〜$3 v0〜v1 汎用、好きにして〜。
$4〜$7 a0〜a3 汎用、アドレスを入れると○
$8〜$15 t0〜t7 汎用、好きにして〜。
$16〜$23 s0〜s7 汎用、カーネルを呼び出しても保存される。
もちろんプレステでも同じ。
$24〜$25 t8〜t9 汎用、好きにして〜。
$26〜$27 k0〜k1 カーネルで使用。
プレステだとk1は使われていない。
$28 gp グローバルポインタかな。
Cコンパイラがワーク参照のために使用。
$29 sp スタックポインタです。
$30 s8、fp フレームポインタかな。
サブルーチンごとのローカルなワークを参照。
$31 ra サブルーチンからの戻り番地を記憶。


・命令長

1命令は4バイト固定です。
32bitのレジスタ幅いっぱいの値を扱う場合や、
遠いアドレスに分岐するときは、
その値を二度にわけてレジスタにロードし、
値や分岐先をレジスタで指定するという方法をとります。
ちなみに、32bitの値をワード、
16bitの値をハーフワードといいます。
68000系のCPUとは違うので注意してください。
Z80
68000
65816
R3000
 バイト 
 バイト 
 バイト 
 バイト 
2バイト
ワード
ワード
ハーフワード
4バイト
ロングワード
4バイト
ワード


・符号拡張

即値の多くはアセンブラ上では16bitの値として記述しますが、
その多くは内部的に32bitの値として扱われます。
それが符号を意識する命令であれば、
符号拡張という処理が行なわれます。

たとえば、「lb t0,$ffff(a0)」は、
a0+$ffff番地からの1バイトロード命令です。
$ffffは符号拡張され、a0+$0000ffff番地ではなく、
a0+$ffffffff番地からのロードとなります。
よって、a0+65535番地ではなく、
a0-1番地からのロードになります。


・サブルーチン(リンク)

R3000には普通のCPUに見られるような、
サブルーチンコールとリターン命令がありません。
RISC-CPUでは多くの命令を1クロックで実行します。
スタックを用いたサブルーチンコールは、
速度的に不利と考えたのかもしれません。
代わりとなる命令がいくつか用意されています。
戻り番地をレジスタに入れて分岐する命令と、
レジスタに入っている番地に分岐する命令です。
戻り番地をレジスタに入れてサブルーチンに分岐し、
サブルーチンでの処理を終えたら、
レジスタに入っている戻り番地に分岐するのです。
このレジスタのことをリンクレジスタといいます。


・遅延スロット

R3000はほとんどの命令を1クロックで処理します。
実はこれを正確にいうと、1クロックで一つの命令を実行します。
同じように聞こえるかもしれませんが違います。
CPUの内部処理を何段階かに分けます。
たとえば、読み込み、解析、実行、書き込みとしましょう。
そしてこの各々の処理を別々の回路で同時にできるとすれば、
ある命令を実行中に、次の命令の解析や、
そのまた次の命令の取り込みができます。
このようにCPU次のアドレスにある命令を、次々に先読み、解析し、
並列処理することで、平均的な速度を上げています。
つまり平均1クロックというわけです。
分岐命令やメモリに関する処理は、1クロック余分にかかります。
ところで、分岐が起こると面白いことが起こります。
CPUが先読みしていた命令は勢い余って実行されてしまうのです。
よって、分岐命令の次にはnopを記述しなければなりません。
この命令が入る場所を遅延スロットといいます。
この性質を利用して、分岐処理の間に1命令処理できます。


・マクロ

R3000はあって当然という命令がたくさん省略されています。
たとえば、レジスタから123を引き算する命令はありません。
しかし、これは-123を加算すれば実現できます。
このように省略可能な命令は、片っ端から削除されています。
それを補うために常識的な命令は、
アセンブラ上でマクロとして用意されています。
たとえば、nopという命令は何もしないという命令です。
これは「add a0,a0,zero」でもかまいませんよね。

「li a0,pochi」という命令について考えます。
これはpochiという即値をレジスタa0入れる命令ですが、
pochiが小さい値なら「add a0,zero,pochi」に置換されます。
pochiが16bitを超える大きな値なら、
複数の命令を使ったロード命令に置換されます。
これらの処理はアセンブラが勝手に行ないます。

[戻る]


間違いがあったら教えてください... koh@inetmie.or.jp