TL;DR
おれの!!短歌!!オン・ゲームボーイアドバンス!!!!!! pic.twitter.com/bzBNAM0gfa
— hiroki asano (@ashnoa) 2022年6月19日
- 西田亙『Linuxから目覚めるぼくらのゲームボーイ!』(ソフトバンククリエイティブ、2003年)がめっちゃいい。
- 手っ取り早く書籍のコード用に環境構築したいなら、パッケージマネージャーなどで
gcc-arm-none-eabi
をインストールしよう。 - Windows 10(64bit)環境で書籍同梱のブートケーブルUSBを利用して実機にプログラムを転送するなら、移植版の転送ソフトを利用すること。
- GBA用の画像変換はOpenCVとPythonで行うのが(個人的には)やりやすい気がする。
visualboyadvance-m
だと一部書籍内のプログラムが動作しないみたい。
はじめに
NINTENDO64やゲームボーイといった、幼少期にかぶりついて遊んでいたハードやソフトがどんな仕組みで動いていたのかを知りたくて、先人たちがつくってくれた動画や記事をいろいろ漁っていた。
そんななか、Rustから目覚めるぼくらのゲームボーイ!で西田亙『Linuxから目覚めるぼくらのゲームボーイ!』(ソフトバンククリエイティブ、2003年)の存在を知る。
GBAというハードを題材にしつつ、GNU開発ツールを用いたクロスコンパイラ開発について理解を深められるらしい。 各所での評価が高いものの、既に絶版扱いで復刊ドットコムでも投票が開始されている。 良品だとAmazonで2万円ほどするということに悩みつつも、「でもまさにあなたのやりたいことが書かれてる本なんだから買ったら?」と妻に後押ししてもらい、えいやっと購入。
絶版で2万円する本を買う しかも技術書
— hiroki asano (@ashnoa) 2022年5月23日
2万円出して買った技術書が来た うれしい https://t.co/XBcmGrNT85 pic.twitter.com/vVjzbxKlTq
— hiroki asano (@ashnoa) 2022年5月26日
届いてさっそく意気揚々と読み始めたのだが、書籍に記載されている内容も付録のブートケーブルUSBも2003年のものであるということで、2022年現在に実際に手を動かしてやってみようとするとハマリどころが多かった。
まずは第1章から第2章途中までを読んだので、本記事ではそこまでの範囲で実際に手を動かしてみて得た気づきや、ハマった箇所と解決策について記載する。
なお、今回は以下の環境で作業を実施した。
- Windows 10(64bit)
binutilsとgccを用意する
GBAはCPUとしてゲームボーイ用のカスタムZ80のほか、GBA用の32bitARM7TDMI(現在でいうところのARMv4系らしい)が搭載されている。 そのためGBA向けの環境をGNUの開発ツールでそろえようとするなら、ARM7(ARMv4)向けに以下の2つを用意することになる。
学習のためもあり、書籍内ではソースコードをダウンロードして自前でbinutils-2.14
とgcc-core-3.3.2
をビルドしている。
2022年時点ではより新しいバージョンのbinutils-2.38
とgcc-12.1.0
が利用可能だが、その際には書籍内のtargetがarm-gba-elf
と表記されていることには注意が必要。
arm-*-elf
を指定しているものがWeb上でも多く見られるのだが、2022年現在Host/Target specific installation notes for GCCをみるとarm-*-elf
は記載がなくarm-*-eabi
のみの表記となっている。
"Note that this list of install notes is not a list of supported hosts or targets..."とあるので、arm-*-elf
ももしかしたら利用できるのでは? とも思ったが、gcc-12.1.0
ではさらにgcc/config.gcc
内に"Unsupported targets list"という記載があり、arm*-*-*eabi*
は"Avoid special cases that are not obsolete"としてぎりぎり許容されているものの、arm*-*-elf
はがっつりUnsupportedという扱いになっている。
上記から、2022年時点で新しめのバージョンのbinutils/gccを利用するなら、arm-none-eabi
をtargetにすること。もしくは素直に書籍と同じバージョンのものを利用する方が良い。
ただし、(特にGCCについて)自前でのmake install時に失敗することも多数。そのためパッケージマネージャなどで管理されているARM用のbinutils
とgcc
をそれぞれインストールするのが手っ取り早いようだった。私はしばらく自前ビルドに挑んでいたものの、上記のtarget問題にもその時は気が付いておらず、どうしてもビルド時のエラーが解消しなかったため、すごすごと以下を利用させてもらうことに……。
# for linux(debian) # binutils-arm-none-eabiなども一緒にインストールされる sudo apt install gcc-arm-none-eabi # for macOS brew install --cask gcc-arm-embedded
これは以下のようなツールを/usr/bin
にインストールしてくれる。
ls /usr/bin | grep arm arm-none-eabi-addr2line arm-none-eabi-ar arm-none-eabi-as arm-none-eabi-c++ arm-none-eabi-c++filt arm-none-eabi-cpp arm-none-eabi-elfedit arm-none-eabi-g++ arm-none-eabi-gcc arm-none-eabi-gcc-9.2.1 arm-none-eabi-gcc-ar arm-none-eabi-gcc-nm arm-none-eabi-gcc-ranlib arm-none-eabi-gcov arm-none-eabi-gcov-dump arm-none-eabi-gcov-tool arm-none-eabi-gprof arm-none-eabi-ld arm-none-eabi-ld.bfd arm-none-eabi-nm arm-none-eabi-objcopy arm-none-eabi-objdump arm-none-eabi-ranlib arm-none-eabi-readelf arm-none-eabi-size arm-none-eabi-strings arm-none-eabi-strip
こちらで書籍内の操作を実施してみると、ちゃんと書籍に掲載されているのと同じバイナリが得られる。
自前ビルドがうまくいかなかったのが悔しい……未検証だが、いま再度試してみるなら以下のようなconfigure
の設定で行けるような気もする。書籍のほか、gccをソースからビルド/インストールするを一部参考にしている。
# build binutils-2.38 mkdir build_arm cd build_arm ../configure --prefix=/usr/local/gnu \ --program-suffix=-arm \ --target=arm-none-eabi # build gcc-12.1.0 ./contrib/download_prerequisites # ビルドに必要なモジュールのダウンロード mkdir build_arm cd build_arm ../configure --target=arm-none-eabi \ --enable-languages=c \ # C向けのコンパイラのみ --prefix=/usr/local/gnu \ --program-suffix=-arm --disable-shared \ --disable-threads \ --disable-nls \ --disable-bootstrap \ # ビルド時間短縮のためビルド回数を1回にする --disable-multilib # 64bit環境下でのビルド時のエラー回避
付録のケーブルをWindows 10(64bit)環境下で利用できるようにする
付録として同梱されているオプティマイズのブートケーブルUSBを利用することで、GBA実機で動作を確認することができる。 WSL2上からUSBデバイスを認識させる方法もあるようだが、それはそれで手間がかかりそうに見えたので、まずは転送作業はWindows側ですることに。
これで難なく接続できる……はずなのだが、Windows 10(64bit)の環境であるせいか、どうしてもデバイスドライバが正常にインストールされない。 どうやらWindows 7(32bit)くらいまでは古いWindows向けのドライバも利用できることが多かったようだが、Windows 10以降は署名制限などの厳格化によって一筋縄ではいかない様子……(古いUSBドライバーをWindows 10 で使いたい)
もうGBA実機への転送は諦めてエミュレータでの検証までにしようかと思った矢先、主専攻実験を手元でやるためにGBA開発環境を構築するという記事を発見。 この記事で紹介されているGitHubのリポジトリに、WinUSB汎用ドライバーによってブートケーブルUSBを動作させる場合に利用可能な移植版の転送ソフト(optusbx)と転送のための手順が記載されている。 READMEに記載の手順の通りに実施することで、無事にGBA実機に作成したプログラムを転送できた。
WinUSBとlibusbでUSBデバイスを動作させるというのは、また別の機会に学習してみたいと思う。こういう移植がさっとできるというのは憧れる。
画像を用意する
第1章ではGBAのディスプレイ上にドット単位で色を指定して画像を表示させるのだが、もちろん通常の画像ファイルをそのまま送れるわけではなくて、画像をGBAで描画可能なバイナリに変換して、それをプログラムとリンクしたうえで転送しなくてはならない。
GBAでの色指定は、最上位ビットを未使用で0
と固定し、そのあと上位ビットから順に青(B
)、緑(G
)、赤(R
)をそれぞれ5ビットずつ、計16ビット(2バイト)の0BBBBBGGGGGRRRRR
という形式で表すものとなっている。またGBAはリトルエディアンでのデータ格納を行うため、この2バイトの色指定の連なりによる画像のバイナリも当然リトルエディアンにする必要がある。
書籍ではRGB汎用フォーマット(24ビットRGB)をGBAで表示可能な形式に変換するためのC言語によるサンプルコードも掲載されているのだが、もう少し楽に変換できないものかと思い、今回はOpenCVを利用してBMP形式の画像をGBAで表示可能な形式に変換するPythonのスクリプトを書いて対応した。
OpenCVは読み込んだ画像をRGBではなくBGRの形式で扱うため、今回の用途にはちょうどよかった。横240px・縦160pxのサイズのBMP形式の画像データを用意したうえで、以下のようなスクリプトで目的のバイナリを保存するようにした。なお画像のリサイズにはImageMagickが便利だった。
gist4412d65056eb82115eb8db2efb59ea6d
ちなみに今回は以下の画像を用意した。
おわりに
上記を経て作成されたのが、以下の動画のプログラムだった。
おれの!!短歌!!オン・ゲームボーイアドバンス!!!!!! pic.twitter.com/bzBNAM0gfa
— hiroki asano (@ashnoa) 2022年6月19日
ちなみにだが、エミュレータのvisualboyadvance-m
ではなぜかこの画像表示のプログラムがうまく処理できなかった。もう少し余裕があるときに、こちらも調査したりGitHubで報告したりしてみたい。
普段なかなか利用してこなかったツールや知識を理解しつつの作業なので骨の折れる部分も多いが、その分非常に学びも多いなあと思う。 まだ書籍はまだまだ続きがあるので、時間を見つつこの先も手を動かしていきたい。