ファミコンにはCPUにリコーの6502の互換チップが積まれています。
なので、CPUを操作しつつ、I/Oレジスタを弄る事で昔でいうマリオやロックマンがPPUとしてグラフィックが動いたり、音楽はAPUが動いて矩形波、三角波、ノイズ波が再生されます。
0.
I/Oレジスタ(うろ覚えの覚え書き)
$2002
ロードすると、NMI(VBLANK期間が発生している場合)最上位ビットに1
が発生する。これは、8ビットの最上位ビットが1なのでマイナスとなるので
waitV:
lda $2002
bpl waitV
と一緒に使われる。
また、$2002をロードすると、VRAMのセットされたアドレス
もリセットされる
$2006
二度書きレジスタ
一回目の書き込みでVRAMの上位バイトがセットされて、二回目の書き込みで下位バイトがセットされる。セットされたVRAMを読みたい場合、
ロード系命令で $2007
書き込みたい場合
ストア系命令で $2007
一番左上に1番のBGを置きたいならば
lda $2002 ;vram reset
lda #$20
sta $2006 ;high byte
lda #$00
sta $2006 ;low byte
lda #1 ;write bg pattern
sta $2007 ;write vram
lda #0
sta $2005 ;scroll register
sta $2005 ;scroll register
$2005はスクロールレジスタ
一回目の書き込みはX方向、二回目の書き込みはY方向ですが、
スクロール値と画面表示フラグを上手く組み合わせないと
うまくスクロールできません。また、bgを書き込む際に
$2007を使いますがその直後にスクロール値が乱れます。
なので、現在のスクロール値に戻す必要があるのですが。
(画面が壊れるとも言う)これを上手く利用すると
0番スプライトで0爆弾というラスタースクロールが
行う事が出来るため、多くの名作ゲームでは使われています。
1.LDA,LDX,LDY(読み込み命令)
ロードA
ロードX
ロードY
2.STA,STX,STY(書き込み命令)
ストアA
ストアX
ストアY
即値の読み込み方
lda #%2進数表記
lda #$16進数表記
lda #10進数表記
ldxも同様
ldyも同様
3.CMP,CPX,CPY(比較命令)
コンペア CMP
コンペアX CPX
コンペアY CPY
一体この比較命令は何に使うのかと言うと、下の分岐命令と
一緒に使います。比較しなくとも計算結果でフラグが発生するようですが
自分は少ししか気にしていません。
4.分岐命令
BNE:違うなら
BEQ:等しいなら
BPL:プラスなら
BMI:マイナスなら
BCC:未満なら
BCS:以上なら
jmp:事実上どんなアドレスでもジャンプできる無条件分岐。
jmpより上の分岐は、(jmpアドレスより上のアドレスに飛べないという意味ではなくて、BNE,BEQ,BPL,BMI,BCC,BCSは)マシン語に直す場合、符号付き8ビットの範囲しか飛べない。
例:
lda #5
cmp #3 ;Aが3か?
bne .no3 ;Aが3と違うなら.no3ラベルに分岐する
;Aが3ならばここに分岐する
lda #5
.no3
5.スタック操作命令
PHA:pushA
PLA:pullA
TXA:X->A
TYA:Y->A
TAX:A->X
TYA:Y->A
例:
PHA ;すぐ下のcomplexへサブルーチンが飛ぶ為、恐らくAレジスタの内容は
;破壊されるため、スタックにプッシュする
jsr complex
PLA ;破壊されたAレジスタを破壊前にスタックに保存した内容をプルする
6.シフト・ローテート命令
ASL:左シフト
LSR:右シフト
ROL:左ローテート
ROR:右ローテート
例:
シフトと加算と組み合わせると上手く計算すると、N倍がいくらでも
求まる
;5を10倍にする処理
lda #5
asl a ;10
asl a ;20
asl a ;40
sta <$00
lda #5
asl a ;10
clc
adc <$00 ;40+10
;50になる(はずである)
7.サブルーチン命令
jsr ラベル名
で飛びます
(が、分岐命令でサブルーチンへ飛ぶとスタックを積まずにrtsするとプログラムカウンタと関係のあるスタックが破壊されて困ります)
rts
リターンサブルーチン
8.加算命令、減算命令
基本的に計算命令はアキュームレータの
Aレジスタしか計算できないのと、
adcは、clcしないとcフラグだけ1つ多く加算する場合もあるので
clc(クリアc)
adc #値
か
clc
adc $メモリの内容か即値の値
で計算する
また、sbcは例えば32減算する場合、31減算する場合があるので
sec
sbc #メモリの内容か即値の値
か
sec
sbc $メモリの内容
とするとよい。
具体的には、
lda Sprite1_Y
clc
adc #-1
sta Sprite1_Y
とか何とか
9.何もしないけどクロックだけは消費する命令
NOP:ノーオペレーション
10.では、応用編として、これらを組み合わせたプログラムを
書きます。
;←';'がコメントそれ以降のその行はコメントになりアセンブルされません
;50を3.25倍する処理
LDA #50
ASL A
CLC
ADC #50
STA <$00 ;50X3の150が入る
LDA #50
LSR A ;50/2=25
LSR A ;50/4=12.5が入る(つまり、50*0.25=12.5)
CLC
ADC <$00 ;50*0.25+50*3で50*3.25=162.5
;だが実際には小数点以下は無視されるので162となる
; 追記2024/07/14 誤解を招く書き込みが多数あったので
; 訂正しました