はじめに
ファミコンといえばオジサン(おじいさん)たちが子供のころに任天堂が発売したゲーム機で一世を風靡し社会現象にまで発展しました。
小さい頃は、ファミコンのゲームをやりながら、こんなゲームを作れるようになったらなぁと思っていました。
その後、紆余曲折ありウェブプログラマーになっているのですが、いつかはファミコンのゲームを作ってみたいと思っていました。
大人になった今、すこし時間ができたのでファミコンのプログラムを作ってみようと思います。
開発環境
プログラムを作るには、まずは開発環境を構築しなければなりません。
今回はみんなが使っている一般的な環境で開発できる様、Windowsで動作する環境を作ります。
コンパイラ
ファミコンのプログラムというのはアセンブラでガリガリ書くようなイメージですが、今はC言語で書けるようなコンパイラーも用意されているようです。
今回は cc65 というコンパイラーを使用します。
このページの一番下の方にある「Windows Snapshot」をクリックすると、Zip ファイルがダウンロードされます。
Zipファイルを展開するとコンパイラーの実行ファイル等が展開されるので、自分のホームディレクトリ配下に移動してパスを通しておきます。
パスを通す?と思った人は
スタートメニュー⇒設定⇒システム⇒「環境変数」で検索⇒環境変数の編集
変数名:Path を選択して編集ボタンを押し、一番最後の行に追加します。
例「C:\Users\ishida\cc65-snapshot-win32\bin」
実行環境
次に実際にプログラムを動作させるエミュレーターをダウンロードします。
今回は Mesen を使用する為、下記のサイトからダウンロードします。
https://www.mesen.ca/
Zipをダウンロードして展開すると Mesen.exe が生成されるため、自分のホームディレクトリ等にコピーしてパスを通しておきます。
試しに実行してみると .Net Core の最新ランタイムば必要という事でダウンロードページに飛ばされます。
今回は下記のバージョンをダウンロードしています。
.NET 6.0 Desktop Runtime (v6.0.16)
もう一度実行してみると下記の様な、コントローラーの設定画面が表示されました。
多分これで問題ないと思います。
コーディング
環境もそろったので実際にソースを書いてみたいと思います。
メインのソースコードとして下記のプログラムを作成します。
今回は https://w.atwiki.jp/cc65/pages/14.html から使用させて頂きました。
#include <conio.h>
#include <string.h>
const char message[] = "Hello cc65!";
int main(void)
{
unsigned int frame = 0;
// 画面の消去
clrscr();
// 表示位置の変更
gotoxy((32-strlen(message))/2, 30/2);
// メッセージの表示
cprintf(message);
// 処理を終わらせないための無限ループ
while(1) {
gotoxy(0, 0);
cprintf("%8d", frame++);
}
return 0;
}
もうひとつ、コンパイル用のバッチファイルを作成します。
本当は Makefile を作って管理したいのですが、そこまで分からず。。。
set VM_PATH=C:\Users\ishida\Mesen.exe
set CA65_INC=C:\Users\ishida\cc65-snapshot-win32\include
set CC65_INC=C:\Users\ishida\cc65-snapshot-win32\include
set LD65_CFG=C:\Users\ishida\cc65-snapshot-win32\cfg
set LD65_LIB=C:\Users\ishida\cc65-snapshot-win32\lib
set LD65_OBJ=C:\Users\ishida\cc65-snapshot-win32\obj
set CC65_HOME=C:\Users\ishida\cc65-snapshot-win32
cc65 -t nes main.c
ca65 -t nes main.s
ld65 -t nes main.o nes.lib atmos.lib -o main.nes
build.bat を実行すると下記の様にコンパイルが実行されました。
PS Z:\techtune\nesapp\hello> .\build.bat
Z:\techtune\nesapp\hello>set VM_PATH=C:\Users\ishida\Mesen.exe
Z:\techtune\nesapp\hello>set CA65_INC=C:\Users\ishida\cc65-snapshot-win32\include
Z:\techtune\nesapp\hello>set CC65_INC=C:\Users\ishida\cc65-snapshot-win32\include
Z:\techtune\nesapp\hello>set LD65_CFG=C:\Users\ishida\cc65-snapshot-win32\cfg
Z:\techtune\nesapp\hello>set LD65_LIB=C:\Users\ishida\cc65-snapshot-win32\lib
Z:\techtune\nesapp\hello>set LD65_OBJ=C:\Users\ishida\cc65-snapshot-win32\obj
Z:\techtune\nesapp\hello>set CC65_HOME=C:\Users\ishida\cc65-snapshot-win32
Z:\techtune\nesapp\hello>cc65 -t nes main.c
Z:\techtune\nesapp\hello>ca65 -t nes main.s
Z:\techtune\nesapp\hello>ld65 -t nes main.o nes.lib atmos.lib -o main.nes
PS Z:\techtune\nesapp\hello> dir
ディレクトリ: Z:\techtune\nesapp\hello
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2023/05/04 12:05 bin
d----- 2023/05/04 12:05 obj
-a---- 2023/05/04 12:24 463 build.bat
-a---- 2023/05/04 11:56 468 main.c
-a---- 2023/05/04 12:24 40976 main.nes
-a---- 2023/05/04 12:24 1494 main.o
-a---- 2023/05/04 12:24 1604 main.s
-a---- 2023/05/04 12:21 1348 makefile
PS Z:\techtune\nesapp\hello>
では、おもむろに Mesen.exe で実行してみたいと思います。
Mesen.exe を起動して、File ⇒ Open で main.nes を選択します。
おおー!動いた。想定通り文字が表示されています。
これで、どんどんいろんなものができそうな気になってきました。
中間ファイル
さてプログラマーとしてひとつ気になることがあります。
それは、コンパイル時に生成された、main.s というファイルです。
これは、コンパイラが吐き出した6502アセンブラのソースです。
.segment "CODE"
ldx #$00
lda #$00
jsr pushax
jsr _clrscr
ldx #$00
lda #$20
jsr pushax
lda #<(_message)
ldx #>(_message)
jsr _strlen
jsr tossubax
jsr shrax1
ldx #$00
jsr pusha
ldx #$00
lda #$0F
jsr _gotoxy
lda #<(_message)
ldx #>(_message)
これを見るとアセンブラの勉強もできそうです。
最近コンパイラを自分で書いている人の話を聞くことが多かったのでとても興味深い点です。
おわりに
ファミコンはゲーム機として一般的ですが、コンピューターの基本形として一番身近な存在ともいえます。
最終的にはゲームだけではなく、OSやコンパイラ、エディタ等のアプリケーションを作成してファミコンの限界に迫ってみたいと思います。
いろいろプログラムを作成してみて、ファミコンを使ってコンピューターの仕組みプログラムの考え方を発掘していきたいと思います。
ファミコンプログラミングを通してコンピューターサイエンスに触れて行きたいと思います。
参考文献
https://w.atwiki.jp/cc65/
http://muto.world.coocan.jp/nesapp/nesapp-build.html