FAQ

コマンドプロンプトでGBFSのワイルドカードが使えません

could not open *.img: Invalid argumentdone!

2015/10/07 時点で起きている現象です。昔のバージョンでは起こりません。
公式サイトからgbfs.exeを入手して差し替えてください。

古いサンプルプログラムをコンパイルするとエラーになる

開発環境が変わった為、少々の手直しが必要になります。
試しにNO.96 adrvをコンパイルさせてみましょう。

  • 昔 2009/01/15 devkitARM r24
  • 今 2014/10/28 devkitARM r42

何も考えず、make_bin.batをしてみると

# converting bg_ascii.bmp
# converting bg_keyboard.bmp
# converting spr_cur.bmp
make[1]: `all' is up to date.
# assembling res/bg_ascii.s
sh: arm-eabi-as: command not found
make[1]: *** [obj/bg_ascii.o] Error 127
make: *** [all] Error 2
続行するには何かキーを押してください . . .

arm-eabi-asがないぞと言われます。Makefileの

PREFIX	= arm-eabi-


PREFIX	= arm-none-eabi-

に書き換えて再度実行してみます。が・・・

(省略・・・)

# Linking test.elf
obj/crt0.o: In function `CIDExit':
(.init+0x1b4): undefined reference to `__bss_end'
obj/crt0.o: In function `CIDExit':
(.init+0x1b8): undefined reference to `__sbss_start'
obj/crt0.o: In function `CIDExit':
(.init+0x1bc): undefined reference to `__sbss_end'
obj/crt0.o: In function `CIDExit':
(.init+0x1c4): undefined reference to `__data_start'
obj/crt0.o: In function `CIDExit':
(.init+0x1c8): undefined reference to `__data_end'
obj/crt0.o: In function `CIDExit':
(.init+0x1d4): undefined reference to `__iwram_end'
collect2.exe: error: ld returned 1 exit status
make[1]: *** [test.elf] Error 1
make: *** [all] Error 2
続行するには何かキーを押してください . . .

今度はcrt0.s内の名前が定義されてないぞと怒られます。
以下のように書き換えてください。

  • src\libgba\crt0.s
    行数書き換え前書き換え後
    107__bss_start__bss_start__
    108__bss_end__bss_end__
    115__sbss_start__sbss_start__
    116__sbss_end__sbss_end__
    124__data_start__data_start__
    125__data_end__data_end__
    132__iwram_start__iwram_start__
    133__iwram_end__iwram_end__

今のバージョンはアンダーバーを増やしたみたいですね。
これで無事コンパイルできました。

あと、古いサンプルコードでは意味もなくs16, u16を多用しています。
完全な間違いです。CPUに余計な処理を入れてしまう為、遅くなる要因になります。

特にループ変数などはs32, u32を使用してください。

サンプルプログラムのライセンスはなんですか

libgba(LGPL)を静的リンクしている関係でGPLになります。
本人としてはNYSL 0.9982(通称:煮るなり焼くなり好きにしろライセンス)が
希望なんですけれど、大人の事情でびみょーなところで落ち着いています。

僕が作成したコンバータやツール類はNYSLでいいです。
また、libgbaが絡んでいないコードもNYSLとします。

他の作者様の作成されたものは(zipファイルで同封されていても)個別に従ってください。

GBA開発で活気がある掲示板はどこですか

2014年現在どこも活気はありません。過去ログとしては

を見てみることをオススメします。

libgbaを元にゲームを作りたいのですが仕組みがわかりません

libgbaにはマニュアルがないので直接ソースコードを読まなくてはなりません。
ソースコードは別途ダウンロードしてください。

sourceforgeのdevkitProプロジェクト libgbaにあります。

xxx.mb(xxx.mb.gba)と、xxx.gbaの違いはなんですか

ブートケーブル(MultiBoot)か、カードリッジからの起動の違いです。
もちろんブートケーブルからはカードリッジを使用していないことを前提にしています。

それぞれの電源を入れたときの開始番地は0x2000000(ブートケーブル)、
0x8000000(カードリッジ)になります。

GBA(ARM7TDMI)には割り算や除算命令がないって本当ですか

本当です。devkitARMでは暗黙の了解としてlibgcc.aで計算をしています。
ただし計算は非常に遅いので、BIOS(SWI 6, 7)を使うか、
IWRAM領域に自作の関数を作るのがいいようです。

実機でテストしたいのですが機材はどこで入手できますか

マジコン(カードリッジの内容を書き換えるハードウェア)は、
homebrewを目的としたものではなく、あくまで市販ゲームを遊ぶものとして販売されています。

このwikiではhackしていく楽しみを目的としていきたいと思っていますので、
申し訳ないのですが別のサイトを利用してください。

rand関数を使っていると、いつも同じ結果、同じ順番が得られてしまいます

電源投入時のGBAには、乱数に使えるようなメモリ領域がありません。
NDSならRTC(日付や時間)をsrand関数に使うことが可能ですが、
GBAにはRTCの対応したカードリッジを使用しなくてはなりません。
以下、回避策です。

  • SRAM領域にsrand関数用の変数を用意する。
  • キー入力のタイミングでsrand関数用の変数を用意する。

なおgccに入っているのではなく、メルセンヌ・ツイスタ法を使われることをオススメします。

実機でテストしたいのですが起動中のタイトルロゴでフリーズしてしまいます

GBAは起動時、ROMの内容が正しいかどうかCRCチェックを行っています。
失敗した場合、ロゴが表示されたところでフリーズしてしまいます。

対策としてはgbafixというツールでROMのCRC値を修正してください。
実行ファイルはdevkitProに標準でついています。

gbafix.exe test.gba -tTest -cTest -m00 -r01

割り込みがうまくいかない

doc.15を参照してください。

日本語の文字列を書くとワーニングになるのだけれど

ConsoleDebug("表示\n");

例でいうところの「表」(ShiftJIS)コードは、0x95 0x5cです。
問題なのは2バイト目で、この0x5cというのは1バイト単体だけだと
「\」(エンマーク)という特殊文字で解釈されます。

この為、「\\n」となるので書き方がおかしくないか警告を出していると思われます。
以下のように修正してください。

ConsoleDebug("表\示\n");

GBA開発に関する書籍があれば教えてください

製作途中ですが別ページ(推薦図書)に作りました。

開発で使っているツール類があれば教えてください

  • GraphicsGale FreeEdition ドット絵エディタ。グリッド、パレット操作がお手軽。
  • OPTPIX web Designer 画像減色ソフト。タイル画像の並び替え等にも使える。操作感がいい。
  • Bz バイナリエディタ。

スタック領域はどこにありますか

devkitARM をインストールしたディレクトリから arm-eabi/lib/gba_cart.ld を開いて下さい。
以下のような記述が見つかると思います。

__iwram_start	=	ORIGIN(iwram);
__iwram_top	=	ORIGIN(iwram) + LENGTH(iwram);;
__sp_irq	=	__iwram_top - 0x100;
__sp_usr	=	__sp_irq - 0x100;
__irq_flags	=	0x03007ff8;

このうち __sp_usr と __sp_irq に、各モードにおけるスタックポインタの指すべきアドレスが割り当てられ、
crt0.S 内でのスタックポインタ初期化によりスタック領域が確定します。

.iwram __iwram_start (0x03000000)
 | 
.bss (不定)
 | 初期値なしグローバル変数領域
.data (不定)
 | 初期値ありグローバル変数領域
__iheap_start (不定)
 | IWRAMヒープ領域
 | ユーザースタック領域
__sp_usr (0x03007e00)
 | IRQスタック領域
__sp_irq (0x03007f00)
 | 
__irq_flags (0x03007ff8)
 | 割り込みフラグ
 | 割り込みベクタ
__iwram_top (0x03007800)

通常は EWRAM にあるヒープ領域 (__eheap_start) を使用するため問題となることはありませんが、
ユーザースタック領域とヒープ領域が重なっている点に注意して下さい。

定義したい構造体のサイズにならない

typedef struct {
	u16 a;
	u8  b;
	u16 c;
} ST_TEST;

この構造体をsizeofで見てみると、6バイトになります。

コンパイラとしてはソースを機械語に落としたときに、そちらの方が効率的にアクセスできるからという理由です。
この状態でmemcmp関数を使用して、初期化されていないスタック変数で比較すると、
1バイト不定の為バグったりしますので注意してください。

どうしても意図したサイズにしたい場合、以下のマクロを使用するといいと思います。

#define __PACKED	__attribute__ ((__packed__))

typedef struct {
	u16 a;
	u8  b;
	u16 c;
} __PACKED ST_TEST;

この場合は5バイトになります。

コードは合っているのに、コンパイラがそのとおりに解釈してくれない

コンパイラのオプションにコードの最適化(-0x)を指定しているときに起こる現象です。
たとえば次のような処理があったとします。

u16 flag=0;
void wait()
{
	while(flag == 0)
	{
		//割り込みにより、処理を抜けます。
	}
}

while文の処理の内容は、コンパイラ側から見れば余計な処理と解釈されてしまい、
機械語に落とす過程で処理自体を省かれてしまいます。

こういう時は変数flagにvolatile修飾子をつけることで、
この変数は最適化しないでくださいという指示をコンパイラに教えることができます。

volatile u16 flag=0;

先の例はものすごく簡単なものでしたけれど、実際にはもっと複雑です。
妙にハマることもしばしばあって、こんなことまでも最適化されてしまうのかと
関心してしまうこともあります。

なので、コードに問題がなくて、処理が思うように行かない場合は、
コンパイラの最適化オプションを弄るか修飾子を付けてみてください。

履歴

  • 2015/10/08
  • 2014/12/19
  • 2007/09/28

Last-modified: 2015-10-08 (木) 00:39:28 (2206d)