メリークリスマス!最後のAdCでございます!頑張っていきますよ!
さて皆さん!ファミコンのゲームは好きですか?私は大好きです。ドット絵やピコピコサウンドの音楽など、あの古めかしい雰囲気が好きだからです。
自分でもファミコン風のゲームを作ってみたいと思ったことはありませんか?あの雰囲気を再現したくはありませんか?
でもファミコン風のゲームを再現するって中々大変。色数の制限や音色の再現、4体並んだらちらつくキャラクターやまれにバグる画面。
ファミコンを1から10まですべて再現するのは難しい!ならば!ファミコン"風"ではなくファミコン専用ゲームを作ってしまえばいい!
しかもエミュレータさえあればどんな環境でも動きます!マルチプラットフォームだ!(?)すごい!ファミコンするしかない!!
そんなわけでファミコンプログラミングやってみましょう!
- ツール
必要なツールは次の通りです。
ファミコンのcpuである6502用の開発環境です。cコンパイラもついていますがネットに資料は少ないです。今回は勉強もかねてアセンブラを使います。
ファミコン用のパターンテーブル(グラフィック)の作成、編集を行えるソフトです。このソフトはWindows用であり、Macでは動きません。Ubuntu上でWineを使って動かしている人がいましたがMac上でもできるのかな?Mac詳しくないからわかんないです。ちなみにYY-CHRはファミコンだけでなくスーパーファミコンやメガドライブ、GBAなど様々なものに使える優れものです。
Windows、Mac、Linuxで使えるファミコンエミュレータです。メモリビュアやネームテーブルビュアはもちろんのこと、プログラムのステップ実行もできるのでとても便利です。日本語化パッチもあるので英語が読めない人も安心!
makefileを使うのでMakeコマンドが必要です。WindowsにはMakeコマンドが無いのでCygwinかMake for Windowsを使いましょう。私はCygwinを使いました。
- 開発環境の構築
それでは開発環境の構築をしていきましょう。Windows向けの解説をしますので他のOSの方は適当にググってください。
まずcc65をインストールしましょう。ここのLinksにあるWindows Snapshotをダウンロードしてください。解凍したらcドライブ直下など適当なところにおいてください。
続いてYY-CHR、FCEUXをダウンロードしましょう。これも適当なところに解凍しておいてください。
最後にCygwinをダウンロードします。適当に次へを押していったら上のような画面が出ると思うので、allのdevel内にあるmake:The GNU version of the 'make' utilityをクリックしてSkipとなっているところを変えましょう。
さて、サンプルプログラムをビルドしてみましょう。NES研究室のサンプルプログラムからHELLO, WORLD!をダウンロードしてください。解凍したら適当なエディタ(メモ帳でもいいです)で、sample1.cfgを開いてください。
中身を次のように書き換えてください。
# メモリマップ
MEMORY {
HEADER: start = $0000, size = $0010, file = %O, fill = yes;
ROMST: start = $8000, size = $7ffa, type = ro, file = %O, fill = yes, define = yes;
ROMINFO: start = $fffa, size = $0006, type = ro, file = %O, fill = yes, define = yes;
ROMCHR: start = $0000, size = $2000, type = rw, define = yes;
}
# セグメントマップ
SEGMENTS {
HEADER: load = HEADER, type = ro;
STARTUP: load = ROMST, type = ro, define = yes;
VECINFO: load = ROMINFO, type = ro, define = yes;
CHARS: load = ROMCHR, type = ro;
}
次にmakefileを開いて、中身を次のように書き換えてください。…/ld65や…/cl65と書いてあるところはそこに、ld65、cl65の絶対パスを書いてください。\じゃなくて/ですよ!
CL65 = .../cl65
LD65 = .../ld65
#-------------------------------------------------------------------------------
CSOURCES =
ASMSOURCES = sample1.asm
OBJECTS = $(CSOURCES:.c=.o) $(ASMSOURCES:.asm=.o)
LIBRARIES =
#-------------------------------------------------------------------------------
all : $(OBJECTS) $(LIBRARIES)
$(LD65) -o sample1.nes --config sample1.cfg --obj $(OBJECTS)
.SUFFIXES : .asm .o
.c.o :
$(CL65) -t none -o $*.o -c -O $*.c
.asm.o :
$(CL65) -t none -o $*.o -c $*.asm
clean :
del *.smc
del *.o
さあ準備が整いました!Cygwinでmakefileのあるディレクトリまで移動したらmakeしましょう!
エラーがでなければ成功です!nesファイルが出来ているはずなので、それをエミュレータに突っ込みましょう。HELLO WORLD!と表示されます。でなければ僕の手には負えないので各自なんとかしてください。
さあHELLOWORLDもすんだところで、早速自前のプログラムを組んでいきましょう!とは言っても最初の部分はHELLOWORLDと変わらないので、sample1を改造していく形でプログラムを組みます。
でもその前にやる事があります。ファミコンのアーキテクチャの勉強と、CPUの6502の勉強です。テキトーに理解していれば大丈夫なので分からなくても読み進めていってください。僕もテキトーにしか理解していません。
- アーキテクチャについて
ファミコンはCPU、PPU、APU、RAM、VRAM、ROM、コントローラなどからできています。他にもありますがここでは割愛します。
ファミコンのCPUの種類は6502というものです。これ自体に画像を描画したり音楽を再生したりする機能は無く、メモリ上に設定されたIOポートを通してPPU、APUを操作していきます。
PPUはPictureProcessingUnitの略で、今でいうGPUみたいなものです。またAPUはAudioProcessingUnitの略で、サウンドを再生できます。
ファミコンアドレス空間はこちらが参考になります。RAMは0x0000~0x07ffまでです。先ほど言ったIOポートは0x2000~0x2007、0x4000~0x401fです。またROM(カセットの中の部分)は0x8000~0xffffまでとなっています。コントローラの状態もIOポートを通して取得します。
VRAMはCPUからは直接操作することはできず、PPUを通して操作します。
とここで締め切りが残り30分を切りました。本当は1から10まで全部書きたかったのですが、時間がないので仕方ありません。1と10だけ書かせていただきます。
- 6502について
6502のレジスタはアキュームレータレジスタ、インデックスレジスタ×2、スタックポインタ、ステータスレジスタ、プログラムカウンタとなっています。
アキュームレータは計算を行うためのレジスタ、インデックスレジスタは凄い便利。他なんか察してください。説明雑なのも察してください。
そんなこんなでいよいよプログラミングですよ!わあい楽しい!あはは!
本格的に説明が雑になってきました。最後のAdCなのに本当にごめんなさい。プログラミング講座みたいなの書きたかった。でもいいんだ。だってファミコンプログラミングしているときとっても楽しかったから。時にはアセンブリに殺意さえわいたけれども、とっても楽しかった。今までにない経験でした。
そんな思いの中できたファミコンゲームがこちらです。懐かしのアルカノイドです。ちゃんとバーの当たった位置によって跳ね返る方向が変わります。しかしながらバグだらけ。たまにブロック貫通するし変な方向に跳ね返るしバーは画面を一周して戻ってくるしスコアボードは飾りだしブロックを壊すとき画面が一瞬バグるし。でもこれ全部仕様です。ファミコンゲーにバグはつきものです。ちなみにブロックを崩したときに画面がバグるのはVBlank中に画面が更新しきれなかったからです。なに言ってるかわかんないよね。説明してないもんね。うん。
そんなこんなで僕の初めてのファミコンプログラミングは悲惨な結果に終わりました。でもゎたしゎまけなぃ...ぃつかFPGAでファミコンっくるの...。
てか今更動作確認したら動かないし!もうヤダ!!!!!!!!
ほんとにごめんなさい!!!See you!!!!!!!