=参考にしたホームページ= ギコ猫のファミコンプログラミング NESASMのコードの書き方などはギコ猫で学ぼう! NES研究室 サイクル数を意識して作るならNES研究室。I/Oの説明やサンプルプログラムも〇 ●ファミコンのプログラムを作ろう フリーのNESASMをダウンロードして、asm(アセンブラー)形式からnes形式へ…ファミコンのエミュレータを使って、 nes形式のファイルがファミコンのソフトとして再現されます。 nesファイルで配布するってとかの人は、そのままだと文字化けするので、zipファイルで圧縮した形でサーバーに置きましょう。 自分のホームページ自体も、もっと見やすいように、整理して作り直ししたいと思ってます。こんな感じです!… ニーモニックの説明もこんな感じ… アドレッシングについてはこちら 基数の変換はこちらです。後でまとめたいと思います。 以下にリンクは貼らせていただきました!。 ダウンロード先はNESASM ※64ビット版のNESASMについては多分こちらです。→NESASM 7Zファイルなので、解凍ソフトをダウンロードする必要があります。(フリーソフト) ファミコンのエミュレータはエミュレーター総合サイト スプライト・BGパターンを作るならYY-CHR ファミベーのよっしんさんの作品はこちら→ザックナー キャラクターエディターを作成してみました。→キャラクターエディター ドット絵を描ける人が必要ですね!(><) 8×8ドットは非常に狭いです。簡単なようで難しいです。キャラクター作成は、難しいと言わざるを得ません。 星のスクロールのサンプルです。とりあえず星を点滅させてみました。スクロールサンプル これだけでも3日くらいかかりましたでしょうか。やっぱりvblank期間中は、なるだけバッファにパレットバッファ用とBGバッファ用を作っておいて、 すぐにVRAMに書き込める状態にしておく方が望ましいです。そうしていないので、vblank中に処理が終わっていない気がします。 そして自機の移動を加え、スコア加算のテストをやってみました。シュート途中まで 良い物はなかなか出来ないよね~難しい世界です。 符号なし数値の時、オーバーフローしたときはキャリーフラグが立ち、ダウンフローしたときはキャリーフラグが立ちません。 アセンブラに慣れるのに、しばらくかかります。レジスタの少なさと、命令を最小ステップで書いていく辛さはありますが、6502は意外と速いです。 1/60秒でも結構色々な事が出来ます。 ここからは、 敵機のテーブルを作り、時間に応じて種類別のスプライトを表示させ、種類に応じた動きを作成→当たり判定→敵弾処理とか進んでいくわけです。 現在の進捗状況(シューティング)-download- 進捗状況に応じて、プログラムを載せていきます。 敵機の弾を吐き出させてみました。割り算ルーチンが大変でした。 あとはサイン関数と等加速度運動処理でひとつずつ敵の動きが完成…、シュート3 こんな感じでやっていくんだと思います。 ファミコンのゲームひとつ作るにしても大変なんだと感じます! mckcでファミコン音楽を作成してみました。グラディウス各ステージの曲作成です。 出来は70%くらいだと思います。 エンベロープを見つけるのが難しいと感じます。根気よくやれる人が最高の曲を奏でられると思います。 ---NESASMの使い方--- ●適当な名前 sample.asmをメモ帳で作成 ●メモ帳で作成したsample.asmをNESASM.EXEへドラッグ ●成功するとsample.nesファイルが作成されます。 ●nesファイルをエミュレーターへ通します。( ここでのエミュレーターはVirtuaNESです。) ●ここから先は長々とプログラムを書いていきます。 作成してはasmで保存し、再度NESASM.EXEへドラッグしてnesファイルを作ります。 nesファイルが作成されない場合は、文法などがあっていない場合なので、もういちどasmファイルを見直しします。 ●これがnesasmにおける一連の流れになります。(私はC言語をあまり良く知らないので、他の方法もあるかと思います。) 2進数-10進数-16進数の変換から 2進数の計算と小数点の計算 ●1ビットが8個集まって1byte(バイト) ●210byte=1024byte=1K(kilo) byte 1ページは$xx00-$xxffの256byte空間なので、1K byteは4ページ分に相当します。 ●220byte=1048576byte=1M(mega) byte .inesprg→16kのプログラムサイズなので$8000~$BFFFの16k空間? .ineschr→8kのキャラクタデータなのでVRAMの$0000~$1FFFの空間と解釈出来ます。 .inesmap→マッパー(拡張出来るそうなので、スプライトやBGを多く取り扱いたい時に使用します。) .inesmir→VRAMのミラーリング(BG面1,2を横へ配置するか縦へ配置するか) 0-垂直に配置(水平にミラーリング) 1-水平に配置(垂直にミラーリング) dw(デファインワード)-が連続した2バイトを指定します。ラベルでも16進数でも良いです。 db(デファインバイト)-が1バイト。データとして置きたい時は、カンマで数値を区切って記述します。 ※バイト数が多いと出力されません。 org(オリジン)-開始アドレスを指定。 .bank 0-プログラム本体部分と変数の確保 ※注意-.bank 0命令の後に、引き続きプログラムを書かないと実行されません。 ファミコンの仕様は何度やっても良く分からなくなるので、最初のBG( バックグランド )を表示させるまでに、窓口であるPPU制御レジスタ2000Hと2001Hに、 垂直ブランク割り込みOFFと、背景とスプライトの表示を消しておきます。 それから背景の初期化、メモリの初期化などを行ってBG、スプライト共にON→垂直ブランク割り込みをONにして、無限ループ( ウェイト )を作ってNMI割り込みを待ちます。 ○変数-$0000~$07FFのファミコン本体内ワークRAM 0ページ目と1ページ目は、ゼロページアドレスとスタックなので、変数として使用したい時はゼロページの方を使います。 ワークRAM初期化は多分こんな感じです。メモリ$00を下位アドレス、メモリ$01を上位アドレスとして インダイレクト・インデックスド命令でメモリクリアしていきます。 ゼロページ記号<を使って間接アドレッシングの時は[]を使います。 <記号を付けないと、ゼロページアドレスとして認識してくれません。(2バイトアドレスとして認識される。) 間接アドレッシングの、sta [$00],yの$00は、<記号を付けてはいけません。 ↓ファミコン内RAMのクリア。 ↑のプログラムは0以外は書き込めないプログラムです。試しに0以外のデータで書き込もうとすると、$0000と$0001にデータを上書きしてしまうため、 指定しているアドレスを壊すことになってしまいます。また0で書き込んでも、最終的にメモリ$0001は0xffになります。 ○プログラム本体部分-$8000~$BFFF ☆データとして使用したい時、$8000~$BFFF内にデータを置いて、先頭アドレスをラベルとして書く事が出来ます、 ファミコン本体内のワークRAMにラベルとして設定する場合、変数名(ラベル名):(タブを入れる).db(タブを入れる)0として、RAMのアドレス自体をラベルとして使う事も出来ます。 .bank 1-割り込みによる、ベクターアドレスを記述する。 ○$FFFA NMI割り込み-(1/60秒割り込み)-NMI割り込みを使わないで、$2002の最上位ビットを読み込んで同期を取る方法もあります。 ○$FFFC RESET割り込み-電源ON時やRESETした時 ○$FFFE IRQ、BRK割り込み .bank 2-BG、スプライトデータをセット( プレーン2枚分(4色)で1キャラクタ8×8dot=16バイト必要 ) ○RESET割り込みからスタート→SEIでIRQ割り込みを禁止→分岐命令を使うためのスタック退避命令…LDX #$FF→TXSとして、スタックポインタを$01FFにセットします。(設定なしでも自動で初期化) 1ページ分のスタックエリア($0100~$01FFが作られます。) ○プロセッサステータスレジスタの初期状態を知りたいためPHPした後、スタックをアキュムレータに入れた所、 30(16)が返って来ました。(フラグの説明はCPU_INST.TXTより)
Pレジスタ | N | V | T | B | D | I | Z | C |
設定値 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 |
Pレジスタ | N | V | T | B | D | I | Z | C |
設定値 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 |
得点 | メモリ上のデータ構造 |
0 | 0 |
1 | 1 |
2 | 2 |
3 | 3 |
4 | 4 |
5 | 5 |
6 | 6 |
7 | 7 |
8 | 8 |
9 | 9 |
アドレス | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 |
2000(16) | 垂直ブランキング期間中にNMIを 0:実行しない 1:実行する | スプライトサイズ指定 0:8×8dot 1:8×16dot | BGパターン先頭アドレス 0:0000(16) 1:1000(16) | スプライトパターン先頭アドレス 0:0000(16) 1:1000(16) | PPUアドレス自動インクリメント 0:+1(1キャラクタ) 1:+32(1ライン) | 0:VRAM表示領域(2000(16)-23FF(16)) 1:VRAM表示領域(2400(16)-27FF(16)) 2:VRAM表示領域(2800(16)-2BFF(16)) 3:VRAM表示領域(2C00(16)-2FFF(16)) | ||
2001(16) | フィルターをかけた時のフィルター色 青(bit7):緑(bit6):赤(bit5) | スプライトの表示 0:オフ 1:オン | BGの表示 0:オフ 1:オン | スプライト左端のマスク 0:隠す 1:表示 | BG左端のマスク 0:隠す 1:表示 | フィルターをかける 0:カラーモード 1:フィルターをかける |
アドレス | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 |
4016(16) | ||||||||
4017(16) | ||||||||
コントローラー読み出しは4016(16)の最下位bitを1にし0にしてから4016(16)を8回読む。(4017(16)は2コン) A(X)→B(Z)→select→start(Enter)→上→下→左→右の順番に入って来る。 |