極楽プレイステーション
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