ブートケーブルUSB(ブートUSB)テクニカル情報
ブートUSBには16KbyteのフラッシュROMを内蔵した高速(24MIPS)CPUを使用しています。8Kbyteをブートケーブルのファームウエアが使用して、残りの8Kbyteをユーザ領域として使用できるようにしています。
ユーザ領域にはGBAで起動できるプログラムを格納します。ここに格納したプログラムはGBAブート直後のボタンの状態によって起動されるプログラムが決定されます。
現状はジョイスティックプログラムとブートチッププログラムが格納されておりそれぞれRボタンとLボタンに割り当てられています。この2つのプログラムは両方合わせても1Kbyte程度です。これではちょっともったいないので現在はグラフィックのロゴを入れてお茶を濁しています。
将来新たな使い方が開発されれば、別のボタンを割り当て新たなプログラムをフラッシュに書きこみます。(もちろんユーザのPCを使って書き込めますので、ケーブルを送り返していただく必要などはありません。)
ブート時に何もボタンが押されないと、ブートUSBはPCからのプログラムを待ちます。
PCはブートUSBに転送したいプログラムの長さを伝え、その後プログラム本体を送ります。
全てのプログラムの転送が終わるとGBAはそのプログラムの実行を開始します。
実行を開始したプログラムは引き続きGBAの通信ポートを使用してPCと通信することが出来ます。
devmanやbtconsなどのコントロールソフトはGBAにfwlibと呼ばれるGBAのカセットをコントロールするプログラムをダウンロードして実行させます。そしてユーザがROMの吸出しボタンを押すと、通信ポートを介してfwlibにROMの読み込みコマンド(CMD_READ)が発行されます。このコマンドを受け取ったfwlibは指定されたアドレスのROMデータを通信ポートに送り出します。これがブートUSBの基本的な動作パターンです。
ブートUSBとPCの間は3本のパイプによって接続されています。USBの専門用語になるのですがパイプとはデータの流れるパイプ(管)のようなものです。この3本のパイプを使用してPCはブートUSBを制御しています。
パイプ0(cmd_h)はPCからブートUSBにコマンドを送るために使用します。
パイプ1(i_h)はブートUSBからPCにデータを送るために使用します。
パイプ2(o_h)はPCからブートUSBにデータを送るために使用します。
if(usb_open()) {
printf("Error can't found BootCable USB !!.\n");
exit(-1);
}
cmd_h = usb_pipe_open(0);
usb_pipe_reset(cmd_h);
o_h = usb_pipe_open(2);
usb_pipe_reset(o_h);
i_h = usb_pipe_open(1);
usb_pipe_reset(i_h);
ケーブルと通信を行う手順は上記のようになります。
usb_open()関数でケーブルとのコネクションを確立して、
データをやり取りするための3本のパイプをオープンします。
パイプとのデータのやり取りはWindowsのAPIのReadFile()/WriteFile()を使用します。
ケーブルとPCは下記のコマンドを使用します
(詳しい使用方法はbtcons_usbのソースコードを参照してください)
コマンド パラメータ 解説 USB_STATUS 0-16:マジックコードリード
129-144:マジックコードライト
マジックコード
0: ケーブルステータス(リードのみ)
bit0:GBA power
bit1:Ready to download
bit2:GBA sio ready
1: GBAがOFFで0クリア
2-16: ケーブルがOFFで0クリアGBAの状態取得や、マジックナンバーの読み出し書き込み
マジックナンバーは変数のようなもので特定の値をケーブルに格納してアプリケーションで使用するUSB_CMD パラメータ数
パラメータデータ0
パラメータデータ1
..GBAにダウンロードしたプログラム(fwlibなど)に対してコマンドを発行する
パイプ0(cmd_h)を使用してコマンドとパラメータをGBAに渡す
USB_READ GBAから読み込むワード(4byte)数 GBAからデータを読み込む
読み込む経路はパイプ1(i_h)を使用するUSB_WRITE GBAに書き込むワード(4byte)数 GBAにデータを書き込む
書き込む経路はパイプ2(o_h)を使用する
<例>
void bt_cmd(u32 c,u32 p0,u32 p1,u32 p2,u32 *ret,u32 n){
u8 cmd[18];
u32 size;
cmd[0]=USB_CMD;
cmd[1]=4;
*((u32 *)(cmd+2))=c;
*((u32 *)(cmd+6))=p0;
*((u32 *)(cmd+10))=p1;
*((u32 *)(cmd+14))=p2;
WriteFile(cmd_h, cmd, 18, (LPDWORD)&size, NULL);
if(n){
cmd[0]=USB_READ;
cmd[1]=n;
cmd[2]=(n>>8);
WriteFile(cmd_h, cmd, 3, (LPDWORD)&size, NULL);
ReadFile(i_h,ret,4*n,(LPDWORD)&size,NULL);
}
}
fwlibを使用する場合の流れは
・USB_CMDでコマンドを発行
・USB_READ(USB_WRITE)でデータを読み込む(書き込む)
というようになります。
GBAにプログラムをダウンロードする方法は2通りあります。
一つはGBAのブート直後に目的のプログラムを転送する方法。
もう一つはGBAのブート直後にはfwlibのようなファームウエアを転送して、ファームウエアのコマンドでプログラムをダウンロードさせる方法です。
ここではGBAのブート直後にプログラムを転送する方法を説明します。
1) GBAの電源投入のダウンロード可能状態を待ちます。
USB_STATUSコマンドを発行してGBAの状態を取得します。
2) GBAに転送するプログラムの長さを送ります。
3) プログラム本体を送ります。
<ソースコード>
{
//GBAのブート完了を待つ
for(;;){
ret=bt_getmagic(0);
Sleep(100);
if((ret & 3)==3) break; //GBA ON
}
//PGMの長さを渡す
cmd[0]=USB_WRITE;
cmd[1]=1;
cmd[2]=0;
WriteFile(cmd_h, cmd, 3, (LPDWORD)&size, NULL);
Sleep(50);
WriteFile(o_h, (LPCVOID)&len, 4, (LPDWORD)&size, NULL);
//PGM本体を渡す
cmd[0]=USB_WRITE;
cmd[1]=(len+3)/4;
cmd[2]=((len+3)/4)>>8;
WriteFile(cmd_h, cmd, 3, (LPDWORD)&size, NULL);
WriteFile(o_h, buf, (len+3)/4*4, (LPDWORD)&size, NULL);
Sleep(100); //wait GBA is up
//fwlibに対するコマンド発行
bt_cmd(CMD_ROM_PROBE,0,0,0,buf,3);
rom_type=buf[0];
rom_size=buf[1];
rom_blksize=buf[2];
}
u32 bt_getmagic(u8 n){
u32 ret,size;
cmd[0]=USB_STATUS;
cmd[1]=n;
WriteFile(cmd_h, cmd, 2, (LPDWORD)&size, NULL);
ReadFile(i_h,&ret,4,(LPDWORD)&size,NULL);
return(ret);
}
fwlibに実装されているコマンドです。devman、btconsは下記のコマンドを使用してカセットをコントロールしています。詳しくはbtcons_usbのソースコードを参照してください。
コマンド | パラメータ | 解説 |
CMD_ROM_PROBE | なし | カセットROMの種別を検出する |
CMD_BU_PROBE | なし | バックアップデバイスの種別を検出する |
CMD_WRAM_LOADEXEC | len | GBAの内蔵RAMにプログラムを転送して実行する |
CMD_BOOT_ROM | なし | カセットROMからブートする |
CMD_ROM_BERASE | add | ROM(Flash)をセクター単位で消去する |
CMD_ROM_WRITE | add len |
ROM(Flash)に書き込む |
CMD_ROM_BWRITE | add len |
ROM(Flash)に消去しながら書き込む |
CMD_READ | add len |
GBAのメモリー空間の読み出し |
CMD_WRITE | add len |
GBAのメモリー空間の書き込み |
CMD_FIND | add len strlen |
カセットROMから指定した文字列(データ)の検索 |
CMD_SRAM_READ | ofs len |
SRAM,FLASHなどのバックアップデバイスから読み込む(自動バンク切り替え) |
CMD_SRAM_WRITE | ofs len |
SRAMへの書き込み(自動バンク切り替え) |
CMD_EEP_READ | ofs len |
EEPの読み出し |
CMD_EEP_WRITE | ofs len |
EEPの書き込み |
CMD_FLASH_WRITE | ofs len |
FLASHの書き込み(自動バンク切り替え) |
CMD_BLANK | なし | カセットROM(Flash)の空き容量確認(追加書き込み用) |
CMD_IS_PRO | なし | FA-PRO以降のフラッシュカセットか調査する PROカセットは32Kbyte単位にマルチを配置出来る |
<特徴>
この機能はGBAのプログラムからPC(ホスト)に対してメッセージ(printf)を出力したり、PCのファイルをオープンしてGBAから書き込んだり・読み出したりする機能です。
この機能は主にデバッグや、開発ツール(例えばグラフィックビューア)などに使用することが出来ます。
<使用方法>
この機能を使用するにはbios_usb.zipに含まれるhio.cとhio.hが必要です。hio.cをデバッグ中のプログラムにリンクしてください。hio.hにはホストインターフェイスに必要な関数や、定数などの定義があります。
パラレルポート用のブートケーブルでも同様なホストインターフェイス(bios.zipに含まれます)は提供されていますが、パラレル版は通信割り込みを使用する設計になっているため、USB版のように単純にリンクするだけでは動きません。
詳しくはhio.hを参照してください
関数名 機能 使用例 s32 PcPrintf(s8 *fmt, ...) PCにメッセージを表示する
書式として
%d 10進表示
%x 16進表示
%s 文字列表示
%c 文字表示PcPrintf("X=%d\n",x); s32 PcOpen(s8 *filename, s32 mode) PCのファイルをオープンする
modeに指定できるのは
PC_RDONLY 読み込み専用
PC_WRONLY 書き込み専用
PC_RDWR 読み書き
PC_APPEND 追加
PC_CREAT ファイル作成
PC_TRUNC 長さを0に
s32 fh;
fh=PcOpen("bios.bin",
PC_CREAT|
PC_TRUNC|
PC_WRONLY);s32 PcClose(s32 fh) PCのファイルをクローズする PcClose(fh); s32 PcRead(s32 fh,void *buf,s32 len) PCのファイルをリードする
fh : オープンしたファイル
buf : 読み込むバッファ
len : 読み込む長さ
戻り値 : 実際に読み込んだ長さu8 buf[1024];
len=
PcRead(fh,buf,1024);s32 PcWrite(s32 fh,void *buf,s32 len) PCのファイルをライトする
fh : オープンしたファイル
buf : 読み込むバッファ
len : 読み込む長さ
戻り値 : 実際に読み込んだ長さ
u8 buf[1024];
len=PcWrite(fh,
buf,1024);s32 PcLseek(s32 fh,s32 ofs,s32 where) PCのファイルをシークする
fh : オープンしたファイル
ofs : シークするオフセット
where : シークの起点を下記から
PC_SEEK_SET ファイルの先頭から
PC_SEEK_CUR 現在のポイントから
PC_SEEK_END ファイルの最後から
戻り値 : シーク後のファイル位置s32 flen;
flen=PcLseek(fh,
0, PC_SEEK_END)