Ubuntuでファミコンプログラム その3(背景描画とパレット)
Ubuntuでファミコンエミュレーターで動くプログラムを作ってみてます。Ubuntuでファミコンプログラム その2(YY-CHR)
こちらのサンプルソースとにらめっこしている状態です。
http://hp.vector.co.jp/authors/VA042397/nes/sample.html
前回までのソースは、
https://bitbucket.org/symfo/nes_sample/src
こちらのsample2においてます。
背景(ネームテーブル)
背景は、アドレス0x2000(エミュレーターによっては0x2020からが有効)からデータを書きこめば良いのでした。
この0x2000からの領域を「ネームテーブル」と言うようです。
YY-CHRを使用して、背景データ「character.chr」を編集してみます。
0x01の箇所に、四色の色を使った図形を定義しました。

パレットテーブルの出力をこのように修正しました。
- ; パレットテーブル
- palettes:
- .byte $0f, $17, $28, $39
- .byte $0f, $0f, $0f, $0f
- .byte $0f, $0f, $0f, $0f
- .byte $0f, $0f, $0f, $0f
左上に4つ上下に並べて0x01の図形を描画するようプログラムを修正し実行してみます。

パレット
ここからが本題なのですが、パレットでは4色の組み合わせを4つ、16色定義しています。
図形により使用する色を変更できるはずなのですがやり方がわからない。
例によって
ギコ猫でもわかるファミコンプログラミング - 第11章 BGスクロール
NES研究室 - グラフィック
ここを穴が開くほど眺めてわかったこと。
1.パレットは4色1セット。16色定義しているので、4色4セットある。

2.使用する色セットの指定は、0x23c0から書き始める。
この領域のことを「属性テーブル」と言うようです。
3.8x8の背景1つにつき、1つの色指定ができるというわけではなく、
8x8の背景を4ブロックまとめた塊に対して色の指定を行なっていく。
上手い説明が思いつかないのですが、背景を4x4の塊に分けて、左上を0x23c0とし、右下に向けて0x23ffまでのブロックに分けます。
各々のアドレスに対して、使用する色情報を指定していきます。

4.色の指定は8bitを4つに分けて、それぞれに0から3の色番号を指定する。
指定はビットの左側から「右下」「左下」「右上」「左上」になります。
これ、「左上」「右上」「左下」「右下」の順だと思ってて相当ハマりました。
冷静に考えると、ビットの下の方から見るとこの順になってますね。

この図のように色番号を指定したい場合は、
0x23c0のアドレスに11100100(二進数)を書きこめば良いことになります。
これらを踏まえて、属性テーブルのアドレス「0x23c8」の領域に
4x4の背景を描画します。

このパターンの色を変化させてやります。
パレットテーブルは、適当にこんな感じで定義します。
- ; パレットテーブル
- palettes:
- .byte $0f, $17, $28, $39
- .byte $01, $02, $03, $04
- .byte $05, $06, $07, $08
- .byte $09, $0a, $0b, $0c
属性テーブルへの書き込みはこんな感じ。
- ;属性テーブルへ転送
- lda #$23 ;$23c8への書きこみ開始を通知
- sta $2006
- lda #$c8
- sta $2006
- ldx #$00
- lda #%11100100 ;左下3,右下2,左上1,右下0の色番号を適応
- sta $2007 ;go!
ちなみに、数値に%をつけると二進数表記になるそうです。$だと16進数。
#は即値で有ることを示しています。
これを付けないと、メモリのアドレスとして解釈されるようです。
このへんも勉強しなきゃいけません。
実行すると、狙い通りの動作になってくれました。長かった。

色は4つセットで指定しますが、最初の指定は無視される仕様だそうです。
実質使えるのは3色です。
サブルーチン(関数)の書き方
アセンブラのことがよくわかってないので、背景の描画はこんなソースを書いてます。
- ; ネームテーブルへ転送(画面の左上)
- lda #$20
- sta $2006
- lda #$80
- sta $2006
- ldx #$00
- ldy #$04 ; 4文字表示
- copymap:
- ;lda string, x
- lda #$01
- sta $2007
- inx
- dey
- bne copymap
- ;ネームテーブルへ転送(画面の左上2行目)
- lda #$20
- sta $2006
- lda #$a0
- sta $2006
- ldx #$00
- ldy #$04 ; 4文字表示
- copymap2:
- lda #$01
- sta $2007
- inx
- dey
- bne copymap2
- ;ネームテーブルへ転送(画面の左上3行目)
- lda #$20
- sta $2006
- lda #$c0
- sta $2006
- ldx #$00
- ldy #$04 ; 4文字表示
- copymap3:
- lda #$01
- sta $2007
- inx
- dey
- bne copymap3
- ;ネームテーブルへ転送(画面の左上4行目)
- lda #$20
- sta $2006
- lda #$e0
- sta $2006
- ldx #$00
- ldy #$04 ; 4文字表示
- copymap4:
- lda #$01
- sta $2007
- inx
- dey
- bne copymap4
あんまりなので修正しようと思います。
しかし、普通の言語なら関数にしてしまえば良いのですが、アセンブラでどう書くかわからず。
取っ掛かりがなくて困っていたのですが、ヒントになったのはこのサイト
65816命令表
関数の呼び出しと終了
JSR、JSL、RTS、RTL
なるほど、普通にプログラム書いてた時のノウハウは捨てて、
困ったときはCPUの命令表を見れば良いわけです。
「6502 命令表」で検索するといくつか候補が出てくると思います。
Mnemonic6502 for NES
NES研究室 - 6502
サブルーチンに行きたい時は、
jsr [ラベル名]
サブルーチンから呼び出し元に戻るには
rts
これを踏まえて、こんな感じにしてみました。
- ; ネームテーブルへ転送(画面の左上)
- lda #$20
- sta $2006
- lda #$80
- sta $2006
- ldx #$00
- ldy #$04 ; 4文字表示
- jsr copymap
- ;ネームテーブルへ転送(画面の左上2行目)
- lda #$20
- sta $2006
- lda #$a0
- sta $2006
- ldx #$00
- ldy #$04 ; 4文字表示
- jsr copymap
- ;ネームテーブルへ転送(画面の左上3行目)
- lda #$20
- sta $2006
- lda #$c0
- sta $2006
- ldx #$00
- ldy #$04 ; 4文字表示
- jsr copymap
- ;ネームテーブルへ転送(画面の左上4行目)
- lda #$20
- sta $2006
- lda #$e0
- sta $2006
- ldx #$00
- ldy #$04 ; 4文字表示
- jsr copymap
サブルーチン部分はこんな感じ。
- copymap:
- lda #$01
- sta $2007
- inx
- dey
- bne copymap
- rts
たかがこれだけのことでも知らないとわかんないもんです。
ソースは、
https://bitbucket.org/symfo/nes_sample/src
こちらのsample3においてます。
続きはこちら。
Ubuntuでファミコンプログラム その4(スプライト)
【参考URL】
ギコ猫でもわかるファミコンプログラミング - 第11章 BGスクロール
NES研究室 - グラフィック
NES研究室 - 6502
Mnemonic6502 for NES
- 関連記事
-
- Ubuntuでファミコンプログラム その5(スプライトを動かす)
- Ubuntuでファミコンプログラム その4(スプライト)
- Ubuntuでファミコンプログラム その3(背景描画とパレット)
- Ubuntuでファミコンプログラム その2(YY-CHR)
- Ubuntu で ファミコン(NES)プログラム その1.1(リローデット)
コメント