2013年5月7日火曜日

ファミコン用の自作ソフトを作って遊ぼう

昨年、初めてニューファミコンというゲーム機を入手したのですが、MSXで育ったせいか遊び方を知りません。本体やコントローラの改造ばかりして遊んでいたのですが、どうもこの遊び方は普通とは違うようです。

というわけで今回は、本体やコントローラじゃなくてカートリッジで遊んでみることにします。
通常は固定データであるカートリッジ内のEPROMを、何度も書き換えが可能なFlashROMで置き換えて自作ソフトを動かすことができる、いわゆるFlashROMカートリッジを作ってみました。

(FlashROMの書き込みについてあまりネットに情報がなさげなので、仕様のメモ代わりにもなっています。適当に読み飛ばしてください)。

FlashROMの入手

秋月にて安価に購入可能な、256kBのPLCC FlashROM(EN29F002T)を選びました。256kBもあれば大抵のものは動かせるでしょう。

PLCC→DIP変換基板はaitendoのものを入手しました。
このaitendoのPLCC→DIP変換基板なのですが、届いてみたら曲者で、ピンの並びが全然違いました。最近傍のピンに繋げているようで、PLCCの1番ピンがDIPの32番ピンに繋がっていたりします…。混乱するので、変換表を作りました(誰得データなので省略)。

FlashROMの制御信号の種類

下記の一連の信号ピンで構成されています。
  • VCC/GND → 電源
  • A0〜A17 → アドレス情報
  • D0〜D7 → データ情報
  • /RESET(Chip Reset) → LOWのとき、FlashROMの状態をリセットします。基本的に常にHIGHにします。
  • /CE(Chip Enable) → LOWのとき、FlashROMの機能が有効になります。基本的に常にLOWにします。
  • /OE(Output Enable) → LOWのとき、データがD0〜D7に出力されます。
  • /WE(Write Enable) → LOWのとき、FlashROM内のコントローラに情報が書き込みされます。
データを読み取りしたいときは、以下のようになります。
  1. /OEと/WEをHIGHにします。
  2. A0〜A17にアドレスを指定します。
  3. /OEをLOWに指定します。
  4. D0〜D7にデータが出力されています。
  5. /OEをHIGHに指定します。

FlashROMの書き込み手順

全消去→書き込み→読み込んでCRC32チェック、という流れです。消去すると全領域が「0xFF」になるので、データが0xFFなアドレスには書き込まなくても良いです。
消去と書き込みには独特のシーケンスが必要です。このシーケンスはJEDECという方式のようです。

コマンド1コ分のシーケンスは以下の通りです。/CEと/OEは基本的にHIGHのままです。
  1. /WEをHIGHに設定します。
  2. アドレスピンの値を設定します。
  3. /WEをLOWに設定します。このタイミングでアドレス情報が設定されます。
  4. データピンの値を設定します。
  5. /WEをHIGHに設定します。このタイミングでデータ情報が設定されます。
全消去の場合、以下のような流れでコマンドを発行していきます。
  1. アドレス: 0x5555 データ: 0xAA
  2. アドレス: 0x2AAA データ: 0x55
  3. アドレス: 0x5555 データ: 0x80
  4. アドレス: 0x5555 データ: 0xAA
  5. アドレス: 0x2AAA データ: 0x55
  6. アドレス: 0x5555 データ: 0x10
  7. この状態でデータを読み取り続けて(前述のデータ読み取り手順の3〜5)、データが「0xFF(もしくは、最上位ビットが1)」になれば完了です。
データ書き込みの場合、以下のような流れでコマンドを発行していきます。
  1. アドレス: 0x5555 データ: 0xAA
  2. アドレス: 0x2AAA データ: 0x55
  3. アドレス: 0x5555 データ: 0xA0
  4. アドレス: 目的のアドレス データ: 目的のデータ
  5. この状態でデータを読み取り続けて(前述のデータ読み取り手順の3〜5)、目的のデータになれば完了です。
具体的な実装については、ソースコードをgithubに公開しているので、参照してみてください。

書き込み用ハード・ソフトの作成

当初 mbed + ブレッドボードで作っていたのですが、大層ハマってしまい、ハードのバグなのかソフトのバグなのかも分からなくなったので、一旦保留しました…。
多数のGPIOを持つ必要があるならArduino MEGAでも良いじゃないか、というわけで、気分転換でArduino MEGAに挿せる変換基板を作って、ソフトも実装してみました。githubにて公開していますので、ご自由にお使いください。

ライター動作中の様子

mbedへの移植は、近日中に行う予定です。
今回の書き込み用ソフト作成にあたって、unagiフラッシュメモリ EN29F002T ライタのソースコードが参考になりました。

ベースとなるカートリッジの選定と購入

今回は「バッテリーバックアップ付きのMMC1」をターゲットにしています。ハードオフのジャンクコーナーで、裏に「バッテリーバックアップについての注意書き」があるカートリッジをいくつかピックアップしてきました。有名なタイトルでなければ、一個あたり数百円で手に入ります。

てきとーに選んで「ベースボールスター(SKROM)」にしました。

ファミコン・カートリッジの仕様

EPROMとしては、プログラムROM(PRG-ROM)とキャラクタROM(CHR-ROM)の二つが搭載されています。この他にメモリコントローラとバックアップ用SRAMがあります。
今回はPRG-ROMとCHR-ROMをFlashROMに載せ替えます。

FlashROMの配線とテスト

  • カートリッジを殻割りして、基板を取り出します。殻割りの方法はニコ動の「ファミコンカセットを簡単に殻割りする裏技」という動画が参考になります…が、古いカートリッジはプラスチックが脆くなっているので、ある程度の確率で爪が折れるでしょう。
  • 基板に付いている32ピン・28ピンのEPROMを、はんだ吸い取り線などを用いて取り外します。フラックスで汚れるので、アルコールなどで洗っておきましょう。
  • ROMの居たところに、32ピンのICソケットを取り付けます。
  • 32ピンの基板接続ピンヘッダと、PLCC→DIP変換基板をユニバーサル基板に取り付けます。サンハヤトのICB-504を半分にしたものが、丁度よい大きさでした。
  • ピンヘッダと変換基板の対応するピンを接続していきます。ファミコンカートリッジ側のEPROMのピンアサインは、nesdevのドキュメントに記載があります。
  • 今回、ROMは外して書き込みできるので、特別な配線はしません。A0〜A17、D0〜D7、VCC/GND をそれぞれ接続します。/CEと/OEはGNDに接続、/RESETと/WEはVCCに接続します。
  • インターネット上で合法に公開されている、HomeBrewなROMデータ(NTRQとか、激おこプンプン丸とか)をFlashROMに書き込み、動作テストをします。
PRGROM側だけ配線が終わって、実機で動かしている様子

ソフトの開発

ソフトの開発にはCC65というコンパイラを使います。Cコンパイラですが、基本的にアセンブラが推奨されています。ファミコンで使えるCの機能は限定的なので、「Cで書ける」以外の利点はあまりないかもしれません。

コンパイルしてはFlashROMに書いてデバッグ…とするのはすごく時間が掛かるので、主な開発・動作テストはエミュレーター上で行います。都合のいいことに、ファミコンのエミュレータはいっぱいあります。

とりあえず、「Hello World」と表示するだけのプログラムを書いて動かしてみました。と言っても「NES Game Programming Part 1」というドキュメントにあるコード、ほぼそのままですが。
キー操作やキャラクタ描画、音の再生などなど、まだ全然分かっていないのでこれから勉強していきます。