極楽プレイステーション
R3000命令表
最終編集日 1998-03-05
PSのCPUであるR3000の命令表です。
プログラミングで必要となる命令だけを解説しています。
ネイティブ命令が中心で、
マクロ命令はあまり解説していません。
・命令表を作ろう
ADD...レジスタ同士の加算
ADDU...レジスタ同士の加算(オーバフロー無視)
二つのレジスタの値を加算し、結果をレジスタへ入れる。
ADDは符号を考慮し、オーバフローがあると例外処理となる。
ADDUは符号を考慮せず、オーバフローを無視する。
add a0,a0,a1 #a0 ← a0 + a1
addu a0,a0,a1 #a0 ← a0 + a1
------
ADDI...即値の加算
ADDIU...即値の加算(符号なし)
レジスタの値に16bitの即値を符号拡張して加算し、
結果をレジスタに入れる。
R3000には即値の減算命令が存在しないので、
符号拡張されることを利用して減算命令としても使用する。
addiは符号を考慮し、オーバフローがあると例外処理となる。
addiuは符号を考慮せず、オーバフローを無視する。
addi a0,a0,1 #a0 ← a0 + 1
addi t0,zero,123 #t0 ← 123
addiu a0,a0,4 #a0 ← a0 + 4
------
AND...レジスタ同士の論理積
ANDI...即値との論理積
andはレジスタ同士、andiはレジスタと即値との論理積をとり、
結果をレジスタに入れる。
二つのレジスタの値を2進数で表したとき、両方の桁が1であれば、
答えのその桁が1になるような演算を論理積という。
任意のビットを0にしたい時に便利。
and t0,t1,t2 #t0 ← t1 & t2
andi t0,t0,$00ff #t0 ← t0 & $00ff
andi t0,t0,$ffff #t0 ← t0 & $ffffffff
------
BEQ...二つのレジスタが等しいなら分岐
BNE...二つのレジスタが等しくないなら分岐
それぞれBranch EQual、Branch Not Equalの略らしい。
レジスタの比較と分岐を1命令で実行できるので便利だ。
beq a0,a1,_exit #a0=a1なら_exitへ分岐
beq t0,zero,_skip #t0=0なら_skipへ分岐
bne a0,a1,_loop #a0≠a1なら_loopへ分岐
bne t0,zero,_loop #t0≠0なら_loopへ分岐
------
BGEZ...レジスタが0以上なら分岐
BGTZ...レジスタが0より大きいなら分岐
BLEZ...レジスタが0以下なら分岐
BLTZ...レジスタが0より小さいなら分岐
bgezはBranch ≧ Zeroの略らしい。
記号「≧」はGreater than or Equalで「GE」となる。
記号「≦」はLess than or Equalで「LE」となる。
bgez t0,_loop #t0≧0なら_loopへ分岐
bgtz t0,_loop #t0>0なら_loopへ分岐
bgez t0,_loop #t0≦0なら_loopへ分岐
bltz t0,_loop #t0<0なら_loopへ分岐
------
BGEZAL...レジスタが0以上ならサブルーチンへ分岐
BLTZAL...レジスタが0より小さいならサブルーチンへ分岐
bgezalとbltzalは、それぞれレジスタが0以上、0未満のとき、
raに戻り番地を入れて分岐する。
ようするに条件付きのサブルーチンコールである。
なお、戻り番地は遅延スロットの次の命令である。
bgezal t0,turn #t0≧0なら、サブルーチンturnへ分岐
bltzal t0,tuen #t0<0なら、サブルーチンturnへ分岐
------
BREAK...強制的な例外処理
デバガではブレークポイントを設定するのに使われるが、
通常のプログラムにおいては必要ない。
break #プログラムの実行を止める
------
DIV...わり算
DIVU...わり算
divは二つのレジスタを符号付きの値とみなして割り算を行ない、
商を特殊レジスタLO、剰余を特殊レジスタHIに返す。
divuは二つの値を符号なしの値として割り算を行なう。
div t0,t1 #LO←t0÷t1, HI←t0÷t1の余り
divu t0,t1 #LO←t0÷t1, HI←t0÷t1の余り
------
J...ジャンプ
指定アドレスへ分岐する。
分岐可能なアドレスは相対アドレスで26+2bitで、
bで始まる分岐命令より広範囲のアドレス空間に分岐できる。
j boot #bootへ分岐
------
JAL...サブルーチンへ分岐
Jump And Linkの略である。
戻り番地をリングレジスタraに入れて指定アドレスへ分岐する。
戻り番地は遅延スロットの次の番地となる。
分岐可能なアドレスは相対アドレスで26+2bitである。
jal game #戻り番地をraに入れ、gameへ分岐
------
JALR....リンク付きジャンプ
戻り番地をリンクレジスタに入れて指定アドレスへ分岐する。
分岐先アドレスはレジスタで指定し、すべてのアドレス空間に分岐できる。
jalr ra,a0 #戻り番地をraに入れ、a0番地へジャンプ
jalr a0 # 〃 (省略するとraと解釈される)
jalr a1,a0 #戻り番地をa1に入れ、a0番地へジャンプ
------
JR...レジスタへのジャンプ
レジスタで指定されたアドレスへジャンプする。
サブルーチンからの復帰や、
ジャンプテーブルを使った分岐に使えそうだ。
jr ra #ra番地へ分岐
#s0番目のテーブルに分岐するつもり
la a0,_table #テーブルの先頭アドレス
sll t0,s0,2 #r0 ← s0 × 4
add a0,a0,t0 #アドレスを計算
lw a0,$0000(a0) #計算したアドレスの内容をロード
nop #ロード完了を待つ
jr a0 #そのアドレスへ分岐
nop #遅延スロットを殺す
_table:
dw pochi,tama,jiro #ジャンプテーブルのつもり
------
LA...ワードの即値をAレジスタにロード
LI...ワードの即値をレジスタにロード
ワードの即値をレジスタへロードする。
liとlaはまったく同じ命令だが、
laはaレジスタ専用のロード命令である。
これによりアドレスを扱うことを明示できる。
この命令はアセンブラのマクロであり、
複数の命令に展開される可能性がある。
li t0,$123 #t0 = $00000123
la a0,map_data #map_dataをロード
------
LB...バイトのロード(符号拡張あり)
LBU...バイトのロード(符号拡張なし)
指定された番地から1バイトの値をロードする。
lbは値を符号拡張するので、たとえば$ff=-1をロードすると、
レジスタの値は$ffffffffになる。
lbuは値をゼロ拡張してロードするので、$ffをロードすると、
レジスタの値は$000000ffになる。
lb t0,$0010(a0) #t0←a0+$0010番地の値
lbu t0,$0010(a0) #t0←a0+$0010番地の値
------
LH...ハーフワードのロード(符号拡張あり)
LHU...ハーフワードのロード(符号拡張なし)
指定された番地からハーフワードの値をロードする。
lhは値を符号拡張するので、たとえば$ffff(=-1)をロードすると、
レジスタの値は$ffffffffになる。
lhuは値をゼロ拡張してロードするので、$ffffをロードすると、
レジスタの値は$0000ffffになる。
値は偶数アドレスに配置されていなければならない。
lh t0,$0010(a0) #t0←a0+$0010番地のハーフワード値
lhu t0,$0010(a0) #t0←a0+$0010番地のハーフワード値
------
LUI...ワードの即値をレジスタの上位へロード
ハーフワードの即値をレジスタの上位ハーフワードへロードし、
下位ハーフワードを$0000にする。
ハーフワードは世間でいうところのワード(2バイト)である。
下位ハーフワードへのロード命令はoriで代用できるので存在しない。
たとえば、以下のコードは$12345678をa0にロードする。
lui a0,$1234 #上位ハーフワードに$1234をロード
ori a0,a0,$5678 #下位ハーフワードに$5678をロード
------
LW...メモリからワードの値をロード
ワード境界に合わせて配置されたワード(=4バイト)値をロードする。
lw t0,$1234(a0) #t0←a0+$1234番地のワード値
------
LWL...ワード値の左ロード
LWR...ワード値の右ロード
ワード境界(4の倍数)に配置されていないワード値をロードする。
ロードには二つの命令を使い、二度に分けてロードする必要がある。
二つの命令はlwlとlwrで、
lwlは境界より左の部分を1〜4バイトロードする。
境界よりも右の部分はlwrでロードする。
lwl t0,$0000(a0) #t0 ← a0+$0000番地の左半分の値
lwr t0,$0000(a0) #t0 ← a0+$0000番地の右半分の値
------
MFHI...特殊レジスタHIの値をロード
MFLO...特殊レジスタLOの値をロード
かけ算や割り算の結果は、特殊レジスタHI/LOに格納される。
mfhiとmfloは、それぞれ特殊レジスタHIとLOの値をロードする。
mfhi t0
mflo t1
------
MTHI...特殊レジスタHIへの転送
MTLO...特殊レジスタLOへの転送
かけ算や割り算の結果は、特殊レジスタHI/LOに格納される。
その特殊レジスタHIへ値を転送するのはわかるが、
この命令の存在価値はよくわからない。
mthi t0
mtlo t1
------
MULT...かけ算
MULTU...かけ算
multは二つのレジスタを符号付きの値とみなしてかけ算を行ない、
結果を特殊レジスタHIとLOに返す。
multuは二つのレジスタを符号なしの値とみなしてかけ算を行なう。
計算はCPUから独立して処理され、CPUは他の命令を実行できるが、
特殊レジスタの値を読み出そうとすると待ち時間が発生する。
mult t0,t1 #HI:LO = t0×t1
multu t0,t1 #HI:LO = t0×t1
------
NOR...否定論理和
二つのレジスタの論理和をとり反転して結果レジスタに入れる。
論理和についての説明は、ORを参照のこと。
nor t0,t0,t1 #t0 ← !(t0|t1)
------
OR...論理和
ORI...即値との論理和
二つのレジスタの値を2進数で表したとき、
どちらかの桁が1、あるいは両方が1であれば、
答えのその桁が1になるような演算を論理和という。
指定ビットを1にするのに便利。
orはレジスタ同士で論理和をとり、
oriはレジスタと即値との論理和をとり、
結果をレジスタに入れる。
or t0,t0,t1 #t0 ← t0 | t1
ori t0,t0,$00ff #t0 ← t0 | $00ff
------
SB...バイトのストア
レジスタの1バイト値をメモリに入れる。
sb t0,$0000(a0) #t0の1バイトをa0+$0000番地にストア
------
SH...ハーフワードのストア
レジスタのハーフワード値(=2バイト)をメモリに入れる。
ストアする番地は偶数番地でなければならない。
sh t0,$0000(a0) #t0のハーフワードをa0+$0000番地にストア
------
SW...ワードのストア
レジスタのワード値(=4バイト)をメモリに入れる。
ストアするアドレスは、ワード境界(4の倍数)でなければならない。
ワード境界でないアドレスにストアするためには、
swlとswrの2命令を使わなければならない。
sw t0,$0000(a0) #t0をa0+$0000番地にストア
------
SLL...論理左シフト
SLLV...論理左シフト
レジスタの値を任意の桁数だけ左シフトし、
結果を別のレジスタに入れる。
シフトにより空いたビットには0が入る。
符号なしの値を2,4,8,16...倍するのに便利。
sllはシフト回数を即値で指定し、
sllvはシフト回数をレジスタで指定する。
sll t0,t0,1 #t0を2倍する
sllv t0,t0,t1 #t0をt1回左シフト
------
SLT...未満なら1(符号あり)
SLTU...未満なら1(符号なし)
二つのレジスタを比較し、その関係が「Rs<Rd」であれば、
結果レジスタが真(=1)、そうでなければ偽(=0)になる。
sltは符号を考慮し、sltuは符号を考慮しない。
slt at,v0,v1 #if (v0<v1) t0=1 else t1=0
bne at,zero,_loop #at≠0なら_loop、つまりv0<v1なら_loop
------
SLTI...即値未満なら1(符号あり)
SLTIU...即値未満なら1(符号なし)
レジスタと即値を比較し、その関係が「Rs<値」であれば、
結果レジスタが真(=1)、そうでなければ偽(=0)となる。
sltiは符号を考慮し、sltiuは符号を考慮しない。
slti at,t0,100 #if t0<100 rr=1 else rr=0
bne at,zero,_loop #at≠0なら_loop、つまりt0<100なら_loop
------
SRA...算術右シフト
SRAV...算術右シフト
レジスタの値を任意の桁数だけ右シフトし、
結果を別のレジスタに入れる。
空いたビットには、符号ビット(最上位ビット)が入る。
符号付きの値を1/2,1/4,1/8,1/16...倍するのに便利。
sraはシフト回数を即値で指定、
sravはシフト回数をレジスタで指定する。
sra t0,t0,4 #t0を右シフト4回(1/16倍)
srav t0,t0,t1 #t0をt1回右シフト
------
SRL...論理右シフト
SRLV...論理右シフト
レジスタの値を任意の桁数だけ右シフトし、
結果を別のレジスタに入れる。
空いたビットには、0が入るので、
符号なしの値を1/2,1/4,1/8,1/16...倍するのに便利。
srlはシフト回数を即値で指定、
srlvはシフト回数をレジスタで指定する。
srl t0,t0,4 #t0を4回右シフト(16倍)
srlv t0,t0,t1 #t0をt1回右シフト
------
SUB...減算
SUBU...減算(オーバフロー無視)
二つのレジスタの値をひき算する。
subは符号を考慮し、オーバフローがあれば例外処理となる。
subuは符号を無視し、オーバフローを無視する。
sub t0,t1,t2 #t0 ← t1 - t2
subu t0,t1,t2 #t0 ← t1 + t2
------
SWL...任意のアドレスへワード値を左ストア
SWR...任意のアドレスへワード値を右ストア
lwl/lwrのストア版。
詳細はlwl/lwrを参照のこと。
swl t0,$0000(a0) #左(上位)ストア
swr t0,$0000(a0) #右(下位)ストア
------
XOR...レジスタ同士の排他的論理和
XORI...即値との排他的論理和
二つのレジスタの値を2進数で表したとき、
どちらか一方だけの桁が1なら、
答えのその桁が1になるような演算を排他的論理和という。
指定ビットを反転するのに便利。
xor t0,t0,t1 #t0 ← t0 (+) t1
xor t0,t0,t0 #t0 ← $00000000(笑)
xori t0,t0,$ffff #t0の下位ハーフワードを反転
------
・参考文献
共立出版「mips RISCアーキテクチャ R2000/R3000」
Gerry Kane著 前川守監訳 4,000円(税別)
ISBN4-320-02598-9 C3041
その他4冊(笑)
間違いは教えてください...
koh@inetmie.or.jp