ゲーム内でコードを組む際にはゲームボーイの仕様をある程度把握しておく必要がある。
そこで、ゲームボーイの仕様にまつわる要素と各種命令コード及びポケモンにおける文字列との対応の解説を行う。
基礎の基礎として、1bitは0か1が入る2進数の単位で、1Byteは8bitで構成される。
0x○○や○○hで表現されることがある16進数は4bitをまとめて0~Fで表現したものであり、2桁で0~255までの数値を表現できる。
(hはhexの頭文字から。10進数はdecimalの頭文字でd、2進数はbinaryの頭文字からbで表現されることもある)
コンピューターでは多くの番号を0から数えるということを頭に入れておきたい。
8bitで1Byte | ||||||||
16進表現 | 0~F | 0~F | ||||||
16進の桁 | 80h | 40h | 20h | 10h | 08h | 04h | 02h | 01h |
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
ぽけもんばぐ・りっちーず(リンク切れ)
メモリマップ - GB Spec - atwiki(アットウィキ)
数値は16進数で表記する。
始点 | 終点 | 内容 | 解説 |
---|---|---|---|
0000 | 3FFF | ROMバンク00 | 常時使う基本的なプログラムを格納してある。 |
4000 | 7FFF | ROMバンク01~1F | 場面ごとに必要に応じたデータを呼び出して格納してある。 2000~3FFFに数値を入れることでバンクを切り替えられる。 ポケモンではバンク切り替え時、FFB8にも切り替え先のバンクNo.を書き込んでいる。 |
8000 | 9FFF | VRAM | 画面情報にかかわる領域。 ここを弄ることで画面に好きなものを書き込んだりすることもできるがかなり難しい。 |
A000 | BFFF | SRAMバンク00~03 | セーブデータの領域であり、一部(バンク00)はグラフィックデータの展開先としても用いられている。 初代でバグポケモンの姿を見ると殿堂入りデータが壊れるのは、グラフィックデータを展開する場所の先に殿堂入りデータがあるから。 |
C000 | DFFF | WRAM | ここからはゲーム中で使用するメインメモリとなり、数値を書き換えることでゲームを進行する。 ゲームボーイカラーではD000~DFFFのバンクを変更可能だが、任意コード実行で使うことはまずない。 |
E000 | FDFF | EchoRAM | C000~DDFFのミラー領域となっており、二つのアドレスは連動して書き換わる。 環境によっては全く別の数値が入っていることもある。(ポケスタ等) |
FE00 | FFFF | システム領域 | ここから先はシステムを管理する数値が入っている。 FF80~FFFEがHRAM(上位RAM)と呼ばれ、常時実行し続けるような命令が入っている。 FFFFは割り込みの有無を切り替える領域。 |
計算や代入を行う数値を格納するうえで使用するのがレジスタであり、ゲームボーイには10個のレジスタが存在する。
汎用レジスタと呼ばれるもので、各種8bit(0~255/00h~FFh)の値を格納できる。
bcのペアとdeのペアで16bitの演算に使用することもある。(例:ld bc,DCE0)
High/Lowの略らしい。
こちらも汎用レジスタではあるのだが、hlの組み合わせでアドレスの位置を指定することが多い。(例:ldd (hl),a)
アキュムレータと呼ばれるもので、計算結果を格納するのに用いられる。
特定アドレスの読み書きに多用するため、プログラム構築で使う機会も多い。
フラグレジスタと呼ばれるもので、上位4bitで演算にまつわる要素をつかさどる。
bit | 内容 | 解説 |
---|---|---|
7 | Z | ゼロフラグ。演算結果が00hになった場合に1となる。 |
6 | N | サブストラクト。直前の演算が引き算なら1、足し算なら0となる。 要は引き算が行われたかを見ている。 |
5 | H | ハーフキャリー。計算処理で下位4bitから上位4bitへの繰り上がりや繰り下がりが行われると1となる。 例:0Bhに0Bhを足して16hになったらHが1になる。 |
4 | C | キャリー。直前の演算結果で繰り上がり(FFh→00h)や繰り下がり(00h→FFh)があった時に1となる。 |
プログラムで主に使うのはZとC。条件分岐に使える。
push,pop命令ではaレジスタとセット(af)で扱われる。文字入力ではどちらもできないのであまり使われないが。
キャリーフラグはscf命令で1にすることはできるが、0にする命令が(元となるZ80に)無く、後述の論理演算をした場合に0になることを利用して代用することがある。
スタックポインタと呼ばれるもので、現在のスタック位置を記録している。
スタックにはサブルーチン実行時の戻り先を記録したり、他のレジスタの値を一時的に退避したりするのに用いられる。
プログラムカウンタと呼ばれるもので、次に実行するコードのアドレスを記録している。
通常は実行中のアドレスの次のアドレスが指定されるが、ジャンプ、コール、リターン命令を使うことで行き先を書き換えられる。
ノープログラム。何もしない。
00hで表現できるが、文字や道具欄では扱いにくいため、他の無意味になる命令で代用することが通例。
(例:ld a,aやcp a等)
ロード命令。基本的にはld (対象1),(対象2)で記述し、対象1の値を対象2で書き換えるという意味になる。
数値の読み込みや書き込みに使用するため、非常に多く使われる命令である。
まずは8bitのロード命令から。(hl)というのはhlレジスタで示したアドレスの中身を参照するものである。
対象2→ ↓対象1 |
任意 | b | c | d | e | h | l | (hl) | a |
---|---|---|---|---|---|---|---|---|---|
b | 06h xx ガX |
40h パ |
41h ピ |
42h プ |
43h ポ |
44h ぱ |
45h ぴ |
46h ぷ |
47h ぺ |
c | 0Eh xx ゾX |
48h ぽ |
49h | 4Ah | 4Bh | 4Ch | 4Dh | 4Eh 改行 |
4Fh |
d | 16h xx | 50h 終端 |
51h | 52h | 53h | 54h | 55h | 56h | 57h |
e | 1Eh xx | 58h | 59h | 5Ah | 5Bh | 5Ch | 5Dh | 5Eh | 5Fh |
h | 26h xx がX |
60h | 61h | 62h | 63h | 64h | 65h | 66h | 67h |
l | 2Eh xx ぜX |
68h | 69h | 6Ah | 6Bh | 6Ch | 6Dh | 6Eh | 6Fh |
(hl) | 36h xx | 70h | 71h | 72h | 73h | 74h | 75h | - | 77h |
a | 3Eh xx ぼX |
78h | 79h | 7Ah | 7Bh | 7Ch | 7Dh | 7Eh | 7Fh 空白 |
赤字で示したものは入力不能文字に当たるコード。4Ehは第二世代のメールに必ず入る改行となる。そのため、メールコードでのcレジスタの扱いには注意が必要。
このことからわかるように、レジスタ間の直接の代入は(bレジスタ以外)ほぼ行えない。
(例:ョぺぽ[xor a→ld b,a→ld c,b]「AF 47 48」でbcレジスタを0000hにする。xor aについては後述)
無意味な命令として、「パ」(ld b,b)や「空白」(ld a,a)がスペーサーとして使われることがある。
終端というのは、文字列の最後を表すもので、ニックネームを付ける際も末尾に挿入される。(そのため、名前には5文字+終端分の6バイトが使われている)
dレジスタを扱う場合はこれが結構厄介。(終端文字が入るたびにbレジスタの値で上書きされてしまうため)
続いては16bitのロード命令。(ld ○○,yyxx)
ここで記述に注意が必要なのは、下位bit(bcの場合はc)に入れる値から書き始めること。(例:ld de,D2A2なら「11 A2 D2」と記述する)
対象2→ ↓対象1 |
任意 (yyxx) |
---|---|
bc | 01h xx yy |
de | 11h xx yy ヅXY |
hl | 21h xx yy |
sp | 31h xx yy ぢXY |
赤字で示したものは入力不能文字に当たるコード。
ここで重要なのは、
ニックネームコーディングの場合は「ヅ」を4文字目に入れることで(dレジスタの値を50hにしつつも)ld e,xxの代わりに使用するというテクニックがある。
ld sp,yyxxを使うことはほぼ無い。(初代ポケモンではld sp,DFFFでスタックポインタをDFFFhから始めるようにしている)
一応、ld hl,sp+xx 「F8 xx」でスタックの途中にあるアドレスを参照して書き換えることで、戻り先を変更するという小技がある。
ld
sp,hl「F9」というのも一応あるが、push(後述)と違ってret先を直接書き換えてしまうため、元の処理に戻ってくる必要がある任意コード実行とは相性が悪い。
次は特定アドレスからの読み込み及び代入について。
(hl)への読み書きは8bitのロード命令でも触れたが、その他のアドレス指定ロードはaレジスタを使うことになる。
(FF00+xx)は任意の値をFF00hに足した数値を指定するという意味になる。
(FF00+c)はcレジスタの値をFF00hに足した数値を指定するという意味になる。
指定アドレス | 書き込み | 読み込み |
---|---|---|
(bc) | 02h | 0Ah ザ |
(de) | 12h デ |
1Ah ビ |
(hl) | 77h | 7Eh |
(FF00+xx) | E0h xx ゃX |
F0h xx |
(FF00+c) | E2h ょ |
F2h |
(yyxx) | EAh xx yy ゥXY |
FAh xx yy 4XY |
赤字で示したものは入力不能文字に当たるコード。(「ゥ」は第二世代で、「4」はメール本文で入力可能)
(yyxx)への読み書きは「EA xx yy」といったように3バイトを使って記述する命令となる。
これだと一見(hl)からの読み書きができないように見えるが、これらの読み書きには別の命令が存在するのでそちらを使用する。
なお、ld (yyxx),sp「08 xx
yy」は、アドレスyyxxにスタックポインタの下位8bit、その一つ後ろ(yyxx+01h)のアドレスに上位8bitの数値を格納することになる。
(例:スタックポインタがDFF5hの場合、ld (D010),sp「08 10 D0」は、D010hにF5h、D011hにDFhを入れる)
hlレジスタ(で示すアドレスの中身)とaレジスタの間で読み書きを行った後、hlレジスタの数値を操作する命令。
ldiがインクリメント(hlレジスタの値を+01h)、lddがデクリメント(hlレジスタの値を-01h)となる。動くのは基本lレジスタとなるが、繰り上がり/繰り下がりが起こるとhレジスタの値も動く。
本来は連続したデータの読み書きに使用するものだが、ld (hl),a、ld
a,(hl)共に入力不能文字のため、1バイトのみの読み書きにもこれを利用せざるをえなかったりする。
(一応、「ョぷア」[xor a→ld b,(hl)→add b]のようにbレジスタ経由で読み込むことはできなくもないが…)
(hl),a (書き込み) |
a,(hl) (読み込み) |
|
---|---|---|
ldi | 22h | 2Ah ご |
ldd | 32h づ |
3Ah ば |
赤字で示したものは入力不能文字に当たるコード。
上記の通り、読み込みはldi,ldd共に行えるが、書き込みはlddの方しか入力可能文字で行えない。
そのため、連続したアドレスへの書き込みは下から行うのが通例となっている。(例:ョべづづづづ)
ちなみに道具欄で行う場合、ldd (hl),aが偽ポイントアップになって紛らわしいので、ldi (hl),aになるみずのいしを使う方が無難かもしれない。
プッシュ、ポップ。これらはスタックポインタ(sp)の値を操作する命令となる。対象となるのはbc、de、hl、afの4種。
レジスタを他の用途に使う際に値を一時的に退避するのが基本的な使い方だが、ret命令(後述)の戻り先を変えるのにも使える。
(ゲーム中のプログラムでは現在のROMバンクとアドレスの値を退避する用途にも使われている)
pushでは(sp-1)と(sp-2)に2つのレジスタの値を挿入し、sp=sp-2とすることで、スタックの上にレジスタの値を積む。
(例:sp=DFF5hの時のpush afは、(DFF4h)=a、(DFF3h)=f、sp=DFF3hとなる)
popでは(sp+1)とspの値を2つのレジスタに代入し、sp=sp+2とすることで、スタックの上からレジスタに値を崩す。
(例:sp=DFF3hの時のpop afは、a=(DFF4h)、f=(DFF3h)、sp=DFF5hとなる)
bc | de | hl | af | |
---|---|---|---|---|
push | C5h な |
D5h ゆ |
E5h | F5h |
pop | C1h ち |
D1h む |
E1h ゅ |
F1h × |
赤字で示したものは入力不能文字に当たるコード。一応「×」はポケスタ金銀でボックスの名前やメール本文に入力できるようである。
afがpush、popどちらもできないため、aレジスタの値を退避するにはbレジスタを経由する必要が出てくる。
(例:ld b,a→push bc「ぺな」で退避、pop bc→xor a→add a「ちョア」で復帰)
絶対ジャンプ、コール。指定したアドレスにプログラムを飛ばす命令。3バイトで記述する。(例:jp DE64「C3 64 DE」」
jp命令は文字通り指定したアドレスにプログラムを移動する。
call命令の場合は現在のプログラムカウンタをスタックに積むことで、ret命令で元のプログラムに戻ってくることができるようになる。
具体的には、現在のpc上位8bitを(sp-1)、下位8bitを(sp-2)に代入し、spをsp-2に設定した後、pcに指定した数値を入れる。
同じことを複数個所で行うようなケースで効果を発揮する。
キャリーやゼロフラグを条件にジャンプすることも可能で、特定条件下でプログラムを飛ばすだけでなく、繰り返し処理に利用してコード長の短縮を行える場合がある。
特にポケモンの文字入力では短距離の相対ジャンプ(後述)ができないことが多いため、絶対ジャンプで記述することで短距離の戻りジャンプを実現しているケースが多数ある。
ゼロフラグが1(直前の演算結果が00h)の場合はz、0の場合はnz。キャリーフラグが1(00hとFFhをまたぐような計算が行われた)の場合はc、0の場合はncとなる。
条件→ ↓命令 |
条件なし | nz | z | nc | c |
---|---|---|---|---|---|
jp yyxx | C3h xx yy てXY |
C2h xx yy つXY |
CAh xx yy はXY |
D2h xx yy めXY |
DAh xx yy れXY |
call yyxx | CDh xx yy へXY |
C4h xx yy とXY |
CCh xx yy ふXY |
D4h xx yy やXY |
DCh xx yy わXY |
jpやcallはすべて入力可能文字となっているので、ニックネームコーディングでも扱いやすい。ただし、ジャンプ先のアドレスが入力不能文字の場合は一工夫がいる。
これとは別に、hlレジスタで記したアドレスにジャンプできるjp
hlという1バイト命令もあるのだが、文字入力では初代で入力できない「ァ」(E9h)になるのがネック。
道具欄ではわざマシン33(初代)、わざマシン41(二世代)であるため、かみなりのいし(21h)でhlレジスタの値を指定してニックネーム部に飛ばすといった使い方をされる場合がある。
相対ジャンプ命令。プログラムカウンタ(pc)に指定した数値を足すことで、+-7Fh(127)バイトの間のジャンプを行う。2バイトで記述する。(例:jr
64「メノクラゲ→プリン」)
変更するのがpc(基本的に実行した箇所の次のアドレスを指す)であることから、数値の指定はjr命令を書いた場所の後ろから数える点に注意。
戻りジャンプを用いる場合はFFhから減らしていく。(00hを起点にする)
(例:ldi (hl),a→dec b→jr z,FC「22 0520 FC」で、冒頭のldi
(hl),aに飛ばせる。)
相対ジャンプを使うメリットは2バイトで記述できることによるコード長の短縮と、コード自体の移植のしやすさにある。
絶対ジャンプ同様に条件付きのジャンプも可能。
ゼロフラグが1(直前の演算結果が00h)の場合はz、0の場合はnz。キャリーフラグが1(00hとFFhをまたぐような計算が行われた)の場合はc、0の場合はncとなる。
条件なし | nz | z | nc | c |
---|---|---|---|---|
18h xx | 20h xx | 28h xx ぐX |
30h xx だX |
38h xx |
赤字で示したものは入力不能文字に当たるコード。
条件なしジャンプはまだしもループ処理に便利なnzの条件付きジャンプも入力ができず、戻りジャンプには初代で入力できる最大の数値が「ー」のE3h(-1dh、つまり29バイト)であることが問題となる。
第二世代ではメールでF6h~FFhに当たる数字が入力できるため、短距離の戻りジャンプもいくらか使いやすくなってはいる。
条件なしのjrはメノクラゲやにどげりを使う方が多いかもしれない。第二世代ではアーボックに該当することも覚えておきたい。
リターン。本来はサブルーチンから戻るための命令だが、任意コード実行を行う際も道具使用などのサブルーチンに入ってはいるため、retで終了して元の画面に戻る必要がある。(ジャンプ先でretするケースもある)
戻り先がスタックから取られることを利用し、jp hl「E9」の代わりにする運用方法もある。(例:ld bc,DE46→swap c→push
bc→ret「01 46 DE CB 31 D5 C9」でjp DE64の代わりにする)
ジャンプ、コール命令同様、リターンにも条件を付けることが可能。
ゼロフラグが1(直前の演算結果が00h)の場合はz、0の場合はnz。キャリーフラグが1(00hとFFhをまたぐような計算が行われた)の場合はc、0の場合はncとなる。
条件なし | nz | z | nc | c |
---|---|---|---|---|
C9h の |
C0h た |
C8h ね |
D0h み |
D8h リ |
道具ではわざマシン01(初代)、わざマシン10(二世代)がretに該当する。個数201で書かれていることも。
割り込みを有効にしつつリターンするreti「D9」も存在するが、任意コード実行で使うことはまずないと思われる。
リスタート…という意味だが、実際のところ頻繁に使うサブルーチンを1バイトで呼び出す命令となる。(call 00xxと同じ意味になる)
初代ではこれらの領域にすべてFFhが入っており、コードとして使うことができない。第二世代ではこの領域にバンク跨ぎコールなどの命令が入っており、うまく使うとコード長の短縮にもなる。
00 | 08 | 10 | 18 | 20 | 28 | 30 | 38 |
---|---|---|---|---|---|---|---|
C7h ぬ |
CFh ま |
D7h ら |
DFh っ |
E7h ? |
EFh ♂ |
F7h 1 |
FFh 9 |
赤字で示したものは入力不能文字に当たるコード。第二世代ではメールの本文で「?」「1」「9」が入力でき、ポケスタ金銀では「♂」も入力可能になる。
インクリメントが増加、デクリメントが減少。数値を1ずつ上限させる命令。
各レジスタ及びhlレジスタで示したアドレスの数値に対して使用できるが、00hとFFhをまたいだ時にキャリーフラグが立たないという特徴がある。
8bitレジスタに使用する場合は数値が00hになった時にゼロフラグが立つため、繰り返し処理のカウンターとして使用することができる。
16bitレジスタで使用する場合、00FFhをincすると0100hになったりするが、この時フラグは一切変化しない。これは256回以上のループを行う際に注意が必要。
レジスタ→ ↓命令 |
bc | b | c | de | d | e | hl | h | l | sp | (hl) | a |
---|---|---|---|---|---|---|---|---|---|---|---|---|
inc | 03h | 04h | 0Ch ズ |
13h ド |
14h | 1Ch ボ |
23h | 24h | 2Ch じ |
33h で |
34h ど |
3Ch ぶ |
dec | 0Bh ジ |
05h ガ |
0Dh ゼ |
1Bh ブ |
15h | 1Dh | 2Bh ざ |
25h | 2Dh ず |
3Bh び |
35h | 3Dh べ |
赤字で示したものは入力不能文字に当たるコード。
結構不自由が多く、特にhがincもdecもできないせいで困るケースがたびたびある。
inc (hl)は道具などの所持数を増やす際に便利だが、decできないのが惜しい。
足し算を行う命令。aレジスタの値に他の値を足す。結果はaレジスタ(とフラグレジスタ)に格納される。
計算結果がFFhを超えた場合は繰り上がって00hから増え、キャリーフラグが立つ。
addの場合はキャリーフラグが立つだけだが、adcの場合はキャリーフラグが計算結果に足される。(繰り上がると1増える)
例:a=FBhの時に08hを足す場合、add a,08だとaが03hに、adc a,08だとaが04hになる。(どちらの場合もキャリーフラグは立つ)
足すもの→ ↓命令 |
任意 (a,xx) |
b | c | d | e | h | l | (hl) | a |
---|---|---|---|---|---|---|---|---|---|
add | C6h xx にX |
80h ア |
81h イ |
82h ウ |
83h エ |
84h オ |
85h カ |
86h キ |
87h ク |
adc | CEh xx ほX |
88h ケ |
89h コ |
8Ah サ |
8Bh シ |
8Ch ス |
8Dh セ |
8Eh ソ |
8Fh タ |
aレジスタを00hにしてから各レジスタの値をaddすることで、入力ができないld a,(各レジスタ)の代わりにすることができる。
他には入力不能文字を数値として扱いたい場合にadd a,xxで直前の値から加算する使い方もある。
これとは別にadd (対象1),(対象2)の形で表記する16bit加算命令もある。
これはhlレジスタに対して行うもので、参照するアドレスを一定数動かす用途で使える。
rr(レジスタ)→ | bc | de | hl | sp |
---|---|---|---|---|
add hl,rr | 09h ゴ |
19h バ |
29h げ |
39h |
赤字で示したものは入力不能文字に当たるコード。
ちなみにadd sp,xx「E8 xx」でspの位置を8bit値で動かすこともできる模様?
引き算を行う命令。aレジスタの値から他の値を引く。結果はaレジスタ(とフラグレジスタ)に格納される。
計算結果が00hを下回った場合は繰り下がってFFhから減り、キャリーフラグが立つ。
subの場合はキャリーフラグが立つだけだが、sbcの場合はキャリーフラグが計算結果から引かれる。
a=00hの時にABhを引く場合、sub a,ABだとaが55hに、sbc a,ABだとaが54hになる。(どちらの場合もキャリーフラグは立つ)
足すもの→ ↓命令 |
任意 (a,xx) |
b | c | d | e | h | l | (hl) | a |
---|---|---|---|---|---|---|---|---|---|
sub | D6h xx よX |
90h チ |
91h ツ |
92h テ |
93h ト |
94h ナ |
95h ニ |
96h ヌ |
97h ネ |
sbc | DEh xx んX |
98h ノ |
99h ハ |
9Ah ヒ |
9Bh フ |
9Ch ホ |
9Dh マ |
9Eh ミ |
9Fh ム |
add同様、入力不能文字を数値として扱いたい場合にsub a,xxで直前の値から減算する使い方もある。
sub aやsbc aだとaレジスタが00hになるが、aレジスタのリセットには後述のxor aの方がよく使われている。
それぞれセットキャリーフラグ(scf)、コンプリメントキャリーフラグ(ccf)。
scfはキャリーフラグを1にする命令で、ccfはキャリーフラグを反転(0なら1、1なら0)する命令となる。
その名の通り、キャリーフラグを立てたり折ったりする命令だが、任意コード実行でわざわざ行う必要はない上、scf「37」、ccf「3F」共に入力不能文字なため、使う機会は無いと思われる。
金銀のわざマシン17(分類違い)や図鑑モード06h等、目的のコードにたどり着くまでに他のコードが混じってしまう場面で不意に立ってしまうと困ることがある程度。
(例:scfが混じってしまったためにjr nc,DFが失敗してフリーズ)
キャリーフラグを0にする命令が無いため、後述の論理演算を使ってキャリーフラグを折るという運用方法が(Z80系では)たびたび見られるという。
論理演算と呼ばれるもので、aレジスタと指定した数値またはレジスタをbit比較し、その結果をaレジスタに格納する。
andが論理積(両方が1なら1、どちらか片方でも0なら0)、xorが排他的論理和(両方が異なれば1、同じなら0)、orが論理和(どちらかが1なら1、両方とも0なら0)となる。
例として、72hと21h比較するとそれぞれ以下のようになる。
[72h]
0111 0010
0010 0001
[21h]
↓
0010 0000
[20h]
[72h]
0111 0010
0010 0001
[21h]
↓
0101 0011
[53h]
[72h]
0111 0010
0010 0001
[21h]
↓
0111 0011
[73h]
ちなみに、aレジスタ同士の比較の場合、and aやor
aだとaレジスタの値は変化しないが、a=00hの時にゼロフラグが立つので、条件分岐に利用できる。
(Z80には)論理演算を行うとキャリーフラグが0になるという仕様があるため、キャリーフラグを0にする目的でand aやor
aが使われることもあるようだ。
dec bc→ld a,c→or bと組み合わせることで、bcレジスタが0000hになった時にゼロフラグが立つといった運用方法も見られる。
他にはand a,0Fで下位4bitを、and a,F0で上位4bitのみを取り出して使用したり、xor
a,02で02hとそれ以外を切り替えるといった使い方もある。
xor aだとaレジスタが00hになるので、aレジスタをクリアする目的でよく使用される。
比較対象→ ↓命令 |
任意 (a,xx) |
b | c | d | e | h | l | (hl) | a |
---|---|---|---|---|---|---|---|---|---|
and | E6h xx ?X |
A0h メ |
A1h モ |
A2h ヤ |
A3h ユ |
A4h ヨ |
A5h ラ |
A6h ル |
A7h レ |
xor | EEh xx | A8h ロ |
A9h ワ |
AAh ヲ |
ABh ン |
ACh ッ |
ADh ャ |
AEh ュ |
AFh ョ |
or | F6h xx 0X |
B0h ィ |
B1h あ |
B2h い |
B3h う |
B4h え |
B5h お |
B6h か |
B7h き |
赤字で示したものは入力不能文字に当たるコード。しかし、EEh以外は第二世代で入力できる。(「?」と「0」はメール本文限定)
コンプリメント。aレジスタのbitをすべて反転(0は1に、1は0に)する命令。
FFhから引くようにすると計算しやすい。
[72h]
0111 0010
↓
1000 1101
[8Dh]
文字入力では「ぞ」(2Fh)で使用できる。
デシマルアジャストアキュムレーター。aレジスタの値を16進数から10進数の形に変換する命令。
実行時にはハーフキャリーフラグやサブストラクトフラグも参照するため、直前に計算が絡む場合はちょっとややこしくなる。
文字入力では「ぎ」(27h)で使用できるが、任意コード実行でわざわざ使う場面は少なそう。
ポケモンではお金やコインの計算にこれを使用しており、初代では10進化した状態で所持金やコインをメモリに格納している。なぜか第二世代では16進数の形で入っているが。
コンペア。aレジスタの値と指定した数値やレジスタの値を比較する命令で、数値を引く点はsub命令に似ているが、aレジスタそのものは変化させず、結果によって立つフラグだけが変わる。
主な使い方は条件分岐となるが、cp aを事実上のnopとして使用したり、jr z,xxと組み合わせてjr
xxの代わりに使用しているコードもある。(この場合、ゼロフラグが立ち、キャリーフラグが折られる)
任意 (a,xx) |
b | c | d | e | h | l | (hl) | a |
---|---|---|---|---|---|---|---|---|
FEh xx 8X |
B8h く |
B9h け |
BAh こ |
BBh さ |
BCh し |
BDh す |
BEh せ |
BFh そ |
赤字で示したものは入力不能文字に当たるコード。しかし、FEhは第二世代のメール本文で入力できる。
それぞれホールト、ストップ。ともに動作を停止する命令だが、復帰のタイミングが異なる。
halt[76h]は割り込みが起こるまでCPUを停止させる命令。停止中は消費電力を抑えられる。
主に画面描画を待ちたい時に使用するが、文字としては入力不能なので、バイナリエディタを使用して作るような大型のプログラムで使用する程度。
stop「ヂ」[10h]はCPUと画面を休止してスリープモードにする命令で、実行するとかなり長い時間ゲームが止まってしまう(キー入力を受け付けなくなる)らしい?(特に5かい使用時は)このコードが混じらないように気を付けたい。(ニドクインが10hになる)
eはEnable、dはDisable、iはInterruptsの略で、割り込みの有無を切り替える命令。任意コード実行で使うことはまずない。
ei[FBh]が割り込み有効。基本的にはこの状態にしておく。
di[F3h]が割り込み無効。使うとしてもreti[D9h]と組み合わせるのだろうか。
CBh「ひ」と組み合わせた2バイトコードでは、ビット操作を行うことができる。
入力不能文字が絡む数値(主にアドレス)を指定したいときに役立つ。
ちなみにbitの位置は0から数えて8桁(上桁からbit7~bit0)と表記する。
ローテート。各bitを左右に1つずらす命令。一番前の数値が後ろに回る環のイメージで、cの有無はキャリーフラグを環の中に含むかの違い。
[8Ah]
1000 1010
←
0001 0101
[15h]
[E3h]
1110 0011
→
1111 0001
[F1h]
[8Ah]
(C0)1000 1010
←
(C1)0001 0100
[14h]
※Cはキャリーフラグ
[E3h]
(C0)1110 0011
→
(C1)0111 0001
[71h]
※Cはキャリーフラグ
※以上の例では桁があふれているため、キャリーフラグは1になる。
rlcおよびrlは左方向のローテート。
rlcだとbit7(左端)の数値がキャリーフラグ及びbit0(右端)に入るが、rlだとbit7(左端)の数値はキャリーフラグのみに入り、元からキャリーフラグが立っていた場合のみbit0(右端)が1になる。
rrcおよびrlは右方向のローテート。
rrcだとbit0(右端)の数値がキャリーフラグ及びbit7(左端)に入るが、rrだとbit0(右端)の数値はキャリーフラグのみに入り、元からキャリーフラグが立っていた場合のみbit7(左端)が1になる。
aレジスタに対しては、rlca、rrca、rla、rraと1バイトで実行できるようになっている。
レジスタ→ ↓命令 |
b | c | d | e | h | l | (hl) | a |
---|---|---|---|---|---|---|---|---|
rlc | CBh 00h | CBh 01h | CBh 02h | CBh 03h | CBh 04h | CBh 05h ひガ |
CBh 06h ひギ |
07h グ |
rrc | CBh 08h ひゲ |
CBh 09h ひゴ |
CBh 0Ah ひザ |
CBh 0Bh ひジ |
CBh 0Ch ひズ |
CBh 0Dh ひゼ |
CBh 0Eh ひゾ |
0Fh ダ |
rl | CBh 10h ひヂ |
CBh 11h ひヅ |
CBh 12h ひデ |
CBh 13h ひド |
CBh 14h | CBh 15h | CBh 16h | 17h |
rr | CBh 18h | CBh 19h ひバ |
CBh 1Ah ひビ |
CBh 1Bh ひブ |
CBh 1Ch ひボ |
CBh 1Dh | CBh 1Eh | 1Fh |
赤字で示したものは入力不能文字に当たるコード。
rl及びrrはキャリーフラグの状態を正しく把握していないと使うのが難しいだけでなく、rla、rra共に入力不能文字なのもあって任意コード実行ではあまり使われない。
せいぜい後述のslaができないb、c、d、e、hレジスタの値を2倍にしたいときに使う程度。
端のbitがキャリーフラグに入ることを利用し、bit命令の代わりにrlcaやrrcaを使うことでコード長を短縮するテクニックもある。
シフト。各bitを左右に一つずらす命令。ローテートとの違いは溢れた桁が反対側に行かない点。
[8Ah]
1000 1010
←
0001 0100
[14h]
[E3h]
1110 0011
→
0110 0001
[71h]
[E3h]
1110 0011
→
1011 0001
[B1h]
※以上の例では桁があふれているため、キャリーフラグは1になる。
slaは左方向へのシフト。bit7(左端)はキャリーフラグに入り、、bit0(右端)は必ず0になる。
数値を倍にしたい場合に用いられる。
srlは右方向へのシフト。bit0(右端)はキャリーフラグに入り、bit7(左端)は必ず0になる。
数値を半分にしたい場合に用いられる。(端数は切り捨てになるが)
sraも右方向のシフトだが、こちらはbit7(左端)を変化させない。
本来はbit7を符号ビット(正か負かを表すもの)として扱う場合に使う右シフトとなる。
レジスタ | b | c | d | e | h | l | (hl) | a |
---|---|---|---|---|---|---|---|---|
sla | CBh 20h | CBh 21h | CBh 22h | CBh 23h | CBh 24h | CBh 25h | CBh 26h ひが |
CBh 27h ひぎ |
srl | CBh 38h | CBh 39h | CBh 3Ah ひば |
CBh 3Bh ひび |
CBh 3Ch ひぶ |
CBh 3Dh ひべ |
CBh 3Eh ひぼ |
CBh 3Fh |
sra | CBh 28h ひぐ |
CBh 29h ひげ |
CBh 2Ah ひご |
CBh 2Bh ひざ |
CBh 2Ch ひじ |
CBh 2Dh ひず |
CBh 2Eh ひぜ |
CBh 2Fh ひぞ |
赤字で示したものは入力不能文字に当たるコード。
数値を作る上ではrlcやrrcで十分なことが多いためあまり使われないが、ミニゲームを作ったりする場合は結構便利かも?
スワップ。1バイトの内、上位4bitと下位4bitを反転させる命令。
[81h]
1000 0001
↔
0001 1000
[18h]
ポケモンのゲーム中では個体値の一部を取り出す過程で使われているとか。
数値の変化が直感的にわかりやすいためか、swap dで数値を作っているコードがたびたび見られる。
b | c | d | e | h | l | (hl) | a |
---|---|---|---|---|---|---|---|
CBh 30h ひだ |
CBh 31h ひぢ |
CBh 32h ひづ |
CBh 33h ひで |
CBh 34h ひど |
CBh 35h | CBh 36h | CBh 37h |
赤字で示したものは入力不能文字に当たるコード。
aレジスタに対して使えないのが結構痛い。
ビット。各レジスタ(またはアドレス内の値)の特定bitを見て、0だった場合にゼロフラグを立てる命令。条件分岐に使用する。
bit→ ↓レジスタ |
7 (80h) |
6 (40h) |
5 (20h) |
4 (10h) |
3 (08h) |
2 (04h) |
1 (02h) |
0 (01h) |
---|---|---|---|---|---|---|---|---|
b | CBh 78h | CBh 70h | CBh 68h | CBh 60h | CBh 58h | CBh 50h ひ(終端) |
CBh 48h ひぽ |
CBh 40h ひパ |
c | CBh 79h | CBh 71h | CBh 69h | CBh 61h | CBh 59h | CBh 51h | CBh 49h | CBh 41h ひピ |
d | CBh 7Ah | CBh 72h | CBh 6Ah | CBh 62h | CBh 5Ah | CBh 52h | CBh 4Ah | CBh 42h ひプ |
e | CBh 7Bh | CBh 73h | CBh 6Bh | CBh 63h | CBh 5Bh | CBh 53h | CBh 4Bh | CBh 43h ひポ |
h | CBh 7Ch | CBh 74h | CBh 6Ch | CBh 64h | CBh 5Ch | CBh 54h | CBh 4Ch | CBh 44h ひぱ |
l | CBh 7Dh | CBh 75h | CBh 6Dh | CBh 65h | CBh 5Dh | CBh 55h | CBh 4Dh | CBh 45h ひぴ |
(hl) | CBh 7Eh | CBh 76h | CBh 6Eh | CBh 66h | CBh 5Eh | CBh 56h | CBh 4Eh ひ(改行) |
CBh 46h ひぷ |
a | CBh 7Fh ひ(空白) |
CBh 77h | CBh 6Fh | CBh 67h | CBh 5Fh | CBh 57h | CBh 4Fh | CBh 47h ひぺ |
赤字で示したものは入力不能文字に当たるコード。4Ehは第二世代のメール本文に入る改行が該当する。
入力不能文字が多すぎて条件分岐の目的で使うのは困難。むしろ終端除けや改行避けとして使われている印象。
そもそもbitごとに条件分岐をしたいのはキー入力やイベントフラグぐらいなのだが、(数値は使い捨てになるが)rlcaを使った方がコード長を短くできる。
それぞれセット、リセット。各レジスタ(またはアドレス内の値)の特定bitをsetでは立て、resでは折る。
入力不能文字が絡む数値の作成にも使えるが、すでに立っているbitにsetをしても無意味だったりするなど、純粋な加減算目的で使用することはできない。
ビット | (80h) 7 |
(40h) 6 |
(20h) 5 |
(10h) 4 |
(08h) 3 |
(04h) 2 |
(02h) 1 |
(01h) 0 |
|
---|---|---|---|---|---|---|---|---|---|
b | set | CBh F8h ひ2 |
CBh F0h | CBh E8h ひ。 |
CBh E0h ひゃ |
CBh D8h ひリ |
CBh D0h ひみ |
CBh C8h ひね |
CBh C0h ひた |
res | CBh B8h ひく |
CBh B0h ひィ |
CBh A8h ひロ |
CBh A0h ひメ |
CBh 98h ひノ |
CBh 90h ひチ |
CBh 88h ひケ |
CBh 80h ひア |
|
c | set | CBh F9h ひ3 |
CBh F1h ひ× |
CBh E9h ひァ |
CBh E1h ひゅ |
CBh D9h ひる |
CBh D1h ひむ |
CBh C9h ひの |
CBh C1h ひち |
res | CBh B9h ひけ |
CBh B1h ひあ |
CBh A9h ひワ |
CBh A1h ひモ |
CBh 99h ひハ |
CBh 91h ひツ |
CBh 89h ひコ |
CBh 81h ひイ |
|
d | set | CBh FAh ひ4 |
CBh F2h ひ. |
CBh EAh ひゥ |
CBh E2h ひょ |
CBh DAh ひれ |
CBh D2h ひめ |
CBh CAh ひは |
CBh C2h ひつ |
res | CBh BAh ひこ |
CBh B2h ひい |
CBh AAh ひヲ |
CBh A2h ひヤ |
CBh 9Ah ひヒ |
CBh 92h ひテ |
CBh 8Ah ひサ |
CBh 82h ひウ |
|
e | set | CBh FBh ひ5 |
CBh F3h ひ/ |
CBh EBh ひェ |
CBh E3h ひー |
CBh DBh ひろ |
CBh D3h ひも |
CBh CBh ひひ |
CBh C3h ひて |
res | CBh BBh ひさ |
CBh B3h ひう |
CBh ABh ひン |
CBh A3h ひユ |
CBh 9Bh ひフ |
CBh 93h ひト |
CBh 8Bh ひシ |
CBh 83h ひエ |
|
h | set | CBh FCh ひ6 |
CBh F4h ひォ |
CBh ECh | CBh E4h | CBh DCh ひわ |
CBh D4h ひや |
CBh CCh ひふ |
CBh C4h ひと |
res | CBh BCh ひし |
CBh B4h ひえ |
CBh ACh ひッ |
CBh A4h ひヨ |
CBh 9Ch ひホ |
CBh 94h ひナ |
CBh 8Ch ひス |
CBh 84h ひオ |
|
l | set | CBh FDh ひ7 |
CBh F5h ひ♀ |
CBh EDh | CBh E5h | CBh DDh ひを |
CBh D5h ひゆ |
CBh CDh ひへ |
CBh C5h ひな |
res | CBh BDh ひす |
CBh B5h ひお |
CBh ADh ひャ |
CBh A5h ひラ |
CBh 9Dh ひマ |
CBh 95h ひニ |
CBh 8Dh ひセ |
CBh 85h ひカ |
|
(hl) | set | CBh FEh ひ8 |
CBh F6h ひ0 |
CBh EEh | CBh E6h ひ? |
CBh DEh ひん |
CBh D6h ひよ |
CBh CEh ひほ |
CBh C6h ひに |
res | CBh BEh ひせ |
CBh B6h ひか |
CBh AEh ひュ |
CBh A6h ひル |
CBh 9Eh ひミ |
CBh 96h ひヌ |
CBh 8Eh ひソ |
CBh 86h ひキ |
|
a | set | CBh FFh ひ9 |
CBh F7h ひ1 |
CBh EFh ひ♂ |
CBh E7h ひ! |
CBh DFh ひっ |
CBh D7h ひら |
CBh CFh ひま |
CBh C7h ひぬ |
res | CBh BFh ひそ |
CBh B7h ひき |
CBh AFh ひョ |
CBh A7h ひレ |
CBh 9Fh ひム |
CBh 97h ひネ |
CBh 8Fh ひタ |
CBh 87h ひク |
赤字で示したものは入力不能文字に当たるコード。
しかし、「ヲ」「を」「ァ」「ィ」「ゥ」「ェ」「ォ」は第二世代で、数字および「?」「!」「/」はメールで、「♂」「♀」「×」「。」「.」はポケスタ金銀で入力可能。
resはほぼすべてのレジスタで行えるが、setは上位bitでの使用に制限が付く。
res 8,a、res 8,h、res 8,lあたりは使い勝手がいい。