<ジョイキャリーカートリッジとは?>
コナミから発売されているゲームキューブ(GC)用ゲームタイトル「ヒカルの碁3」にバンドルされているものです。中身は8Mbitのカスタムフラッシュチップ(DACS)が使用されています。GCとGBAをケーブルで接続してミニゲームをジョイキャリーカートリッジにダウンロードします。ダウンロードしたジョイキャリーカートリッジはGBAとともに持ち歩くことが出来ます。


ヒカルの碁3専用と書かれているジョイキャリーカートリッジ。
見た目は普通のゲームカセットと同じ。


8M FLASH DACSと書かれている。
このSHARP製チップだけの構成。

<8M DACSの解析>
8M DACSに関する情報はGB/GBAの解析で有名なReinerZiegler氏のページで多少触れられています。このページによればDACSとはDebugging And Communication Systemの頭文字をとったものであり、ROMパッチ機能を持ち、ROM空間の上位エリアにマッピングされるとあります。
このチップはSHARP製ですので、SHARPのフラッシュチップであるLH28F320BJHEのデーターシートも参考になります。
実際に解析するに当たってはこのHPで公開している「カメレオンUSB+ロジアナ」を使用します。100MHz、32チャンネルの解析が可能です。


ゲームテック社のエックスターミネータを改造してGBA専用のプローブを作成。
これでカートリッジ内で発生する全ての現象を解析可能です。


ロジアナコントロールソフトの画面。ここからコマンドを解析していく。

<8M DACS仕様>
解析の結果8M DACSのメモリーマッピングは以下のようになることがわかります。データの消去は通常のフラッシュメモリーと同様にセクター単位に行われます。
通常のゲームカセットがアドレス0x08000000から連続でマッピングされるのと違い、ROM空間の上位(0x09f00000)にマッピングされているのがわかります。
このため通常の市販ゲームや、フラッシュカセットを対象に開発された自作ゲームなどはそのままコピーしても動作しません。(市販ゲームの場合は容量的にもコピーすることは出来ません。)
GBAはカセットからブートする場合0x08000000のアドレスにNINTENDOのヘッダーテーブルが無いといけません。この問題はDACSのROMパッチ機能を使用することで解決しているようです。つまりDACSの0x09ffc000からの8Kbyteを0x08000000にパッチすることでブートを可能にしています。
このROMパッチ機能がプログラムから自由に設定できると非常に面白いのですが、ジョイキャリーカートリッジの場合は固定になっているようでパッチ先のアドレスを変更することは出来ません。
識別セクターは消去・書き込みともに不可能なエリアで、予めヒカルの碁3用のIDが書き込まれています。恐らくGCのダウンロードプログラムはこのエリアをチックしてヒカルの碁3以外のジョイキャリーカセットには書き込まないようにしていると思われます。(折角のフラッシュなのになんで専用になってしまうのでしょうかね。)

アドレス セクター
0x08000000-0x08001fff ブートセクターのイメージ(8K)
0x09f00000-0x09f0ffff データーセクター0(64K)
0x09f10000-0x09f1ffff データーセクター1(64K)
0x09f20000-0x09f2ffff データーセクター2(64K)
0x09f30000-0x09f3ffff データーセクター3(64K)
0x09f40000-0x09f4ffff データーセクター4(64K)
0x09f50000-0x09f5ffff データーセクター5(64K)
0x09f60000-0x09f6ffff データーセクター6(64K)
0x09f70000-0x09f7ffff データーセクター7(64K)
0x09f80000-0x09f8ffff データーセクター8(64K)
0x09f90000-0x09f9ffff データーセクター9(64K)
0x09fa0000-0x09faffff データーセクター10(64K)
0x09fb0000-0x09fbffff データーセクター11(64K)
0x09fc0000-0x09fcffff データーセクター12(64K)
0x09fd0000-0x09fdffff データーセクター13(64K)
0x09fe0000-0x09feffff データーセクター14(64K)
0x09ff0000-0x09f1ffff データーセクター15(8K)
0x09ff2000-0x09ff3fff データーセクター16(8K)
0x09ff4000-0x09ff5fff データーセクター17(8K)
0x09ff6000-0x09ff7fff データーセクター18(8K)
0x09ff8000-0x09ff9fff データーセクター19(8K)
0x09ffa000-0x09ffbfff データーセクター20(8K)
0x09ffc000-0x09ffdfff ブートセクター(8K)
0x09ffe000-0x09ffffff 識別セクター(消去・書不可)
DACS 8M メモリーマッピング

<ツールの対応>
DACS(8M FLASH)はdevman.exeとbtcons.exeの両方のツールで対応しています。
ジョイキャリーカートリッジの場合DACSはプログラム領域として使用されますが、本来はセーブデータのバックアップ用に使用されるようです。したがってツール上ではDACSはセーブデバイスとして扱うようにしています。

上記の説明のようにDACSは特殊なアドレスマッピングを行っていますので、ブートセクターに対しての書き込みなどが行えると便利です。そこでdevman.exeでは以下のように対象エリアを選択できるようにしています。


このようにプルダウンでFLASH 8M(全体)、ブートセクターなどを選択できます。
2M(1)-(4)はこの8MのDACSを2Mずつ書き込むためのものです。

<自作ゲームをジョイキャリーカートリッジに書き込む>
ジョイキャリーカートリッジ用の自作ゲームを作成するにはコード領域の先頭を0x09f00000番地にして再リンクすればOKです。
このHPで公開しているサンプルゲームpuzzleを例に説明します。puzzleではGBAの本体RAMで動くようにリリンクされています。本体RAMのアドレスは0x02000000ですのでこの部分を0x09f00000に変更します。具体的はMakefileの"-Ttext 0x02000000"となっている部分を"-Ttext 0x09f00000"に変更してmakeすればOKです。

実はこれだけでは動きません。なぜかといえばブートセクターに正しい処理を書き込んでいないためです。今回の場合はブートセクターにはNINTENDOのヘッダー情報と自作ゲーム本体の0x09f00000番地にジャンプする処理が必要です。
このような処理を行うブートプログラム(joyboot.bin)を用意しましたのでご自由にご使用ください。(ソースコードも公開しておきます。)
joyboot.binをdevmanを使用して"BOOT BLOCK 64K"に書き込みます。後は自作プログラムを"FLASH 8M"に書き込めばOKです。joyboot.binは一度書き込めば毎回書き込む必要はありません。

<PocketNESをジョイキャリーカートリッジに書き込む>
PocketNESはソースが公開されていますので上記の自作ゲームと同じ方法で再リンクすればジョイキャリーカートリッジに書き込んで遊ぶことは可能です。
私も再リンクしてみようと思ったのですが、PocketNESはARMSDTというツール(コンパイラ)を使用しているため、このツールを使用したことの無い私にはちょっと厳しそうです。それにPocketNESがジョイキャリーに対応するのであれば、ステートのセーブ機能などもDACSで実現して欲しいところです。したがってこのあたりのことはPocketNESの作者であるLoopy氏にお任せすることにします。

PocketNESはGBAの内臓RAMで動かすことが出来ます。(つまりブートケーブルとGBA本体だけで遊べます。)
この機能を使用してジョイキャリーでPocketNESを動かすことが出来ます。つまりローダーを用意しておき、ローダーで選択されたゲームをGBAの内臓RAMに転送して起動するわけです。
この方法で起動できるPocketNESの大きさはGBAの内臓RAMの256Kbyte以下にする必要があります。
このローダーはPocketNESだけではなくGBAの内臓RAMで動くプログラムであれば何でも動かすことが出来ます。(このHPで紹介しているpuzzleやTeamKNOxが開発している"BONSAI WARE"など。)
このローダーは小さいのでDACSのブートセクターに入りきります。ジョイキャリーに書き込めるゲームの本数は4本までで、"2M (1)"〜"2M (4)"に書き込みます。最後の"2M (4)"に書き込むゲームは256Kbyte(2Mbit)-16Kbyte以下である必要があります。
使い方は遊びたいゲームを"2M (1)"〜"2M (4)"のどれかに書き込み、joyloader.binを"BOOT BLOCK 64K"に書き込みます。GBAを起動するとメニューが表示されますので遊びたいゲームを選択してAボタンで実行です。(joyloaderソース