目次: RISC-V
みなさまはDOOMをご存じでしょうか?特に海外で超有名なFPS(First Person Shooter、一人称視点のシューティングゲーム)の草分け的な存在です。1993年にid Softwareが開発したロングセラーシリーズです。オリジナルのid Softwareによる実装も2012年にオープンソースになりました(リポジトリへのリンク)。
日本ではそれほどでもない気がしますが、海外ではDOOMの人気は絶大で海外エンジニアの間ではゲーム機ではない電子機器(プリンタ、カメラ、ATMまで)でDOOMを動作させる改造が非常に人気のようです。
DOOM移植の良いところとしては、3D描画のゲームなので画面が派手で目を引きます。それでいて昔のゲームなので、しょぼいスペックの機器でもそこそこ動きます。操作せずに放っておいてもデモが実行される点も素晴らしいです。
今回はオリジナルのDOOMではなくて、クローン実装のprboom2(リポジトリへのリンク)を使います。prboom2はLinuxで簡単に動作確認できて楽です。いいですね。
DOOMはゲームエンジンなので実行時にはゲームデータを指定しなければなりません。ゲームデータは*.WADファイル(Where's All Dataの略らしい)に格納されていて、オリジナルDOOMのWADファイルのことをIWAD(Internal WAD)と呼ぶようです。IWADはDOOMの製品版に付属しているはずです、見たことがないから知らないですけど。本来はオリジナルDOOMを購入しDOOM.WADを持ってくるべきですが、手に入れる手段がなさそうです……。
ネット検索するとIWADを公開しているサイトがあるのでどうにかして手に入れてください。Doom Wiki(リンク)にDOOM.WADのMD5 hashが掲載されているので、入手したIWADファイルがどのバージョンか(あるいは壊れていないか)確認しましょう。
今回はIWADファイルはDOOM.WAD、バージョン1.8のもので試します。
まずは普通に動かしてみます。ビルドは簡単でbootstrapとconfigureを実行してmakeするだけです。SDLがインストールされていない環境の場合はlibsdl2-devのインストールが必要かもしれません。
$ cd prboom2 $ ./bootstrap $ ./configure $ make $ ./src/prboom -iwad DOOM.WAD
DOOM同様prboom2もゲームエンジンなので実行時にはゲームデータを指定しなければなりません。ビルド時に勝手に生成されるprboom.wadファイルと、ゲームデータが入ったIWADファイル(オリジナルのDOOM、freedoomなど)の2つが必要です。prboom.wadはカレントディレクトリに置けば勝手に見つけます。IWADファイルはオプション-iwadで指定しましょう。
音声なしで起動したければ-nosound、フルスクリーンではなくウインドウモードが良ければ-nofullscreenオプションが使えます。フルスクリーンとウインドウモードの切り替えはゲーム内のオプションから設定することもできます。
確認だけで終わってしまいました。次回から組み込み環境への移植を始めたいと思います。
目次: RISC-V
DOOMのクローン実装prboom2を組み込み環境に移植する話です。前回はLinux上で動作確認しました。今回は想定する組み込み環境と移植作戦&移植です。
想定する組み込み環境は下記のとおりです。
改造元にするコードは何でも良いですけど、私は動作するコードから出発した方がやりやすいので、前回Linux上で動作を確認した実装(src/SDL/*)をベースに改造します。移植にあたって障害となりそうなものは、
この辺の機能が移植先の組み込み環境に存在しないことです。順番に対処しましょう。
SDL(Simple DirectMedia Layer、公式サイトへのリンク、リポジトリへのリンク)はC/C++から簡単にグラフィクスや音声、各種入力機能が利用できる、素敵なライブラリです。が、しかし移植先の環境にSDLなど高等なものはないのでSDLを使用している箇所は削除します。
メイン(src/SDL/i_main.c)、サウンド(src/SDL/i_sound.c)、画面(src/SDL/i_video.c)とジョイスティック入力(src/SDL/i_joy.c)はSDL.hをインクルードか、SDLの構造体やマクロを使用していてコンパイルエラーになるので、エラーになる箇所を全て削除します。
サウンド(src/SDL/i_sound.c)、とジョイスティック入力(src/SDL/i_joy.c)は動作しなくても問題を起こさないように、常に成功もしくは無意味な値を返すように改造します。
ゲームエンジンを動作させるにはprboom2ビルド時に生成されるprboom.wadとIWADファイル(オリジナルのDOOMのWADを指してこのように呼ぶそうです)の2つのファイルが必要です。が、移植先の環境にファイルなど高尚なものはないので、下記の作戦でファイルアクセスなしでも動作するように改造します。
ファイルアクセスを行うコードはシステム(src/SDL/i_system.c)に実装されていますので、ファイルアクセスしている実装を全部静的配列へのアクセスに書き換えます。他の場所(src/d_main.c, src/w_wad.c)のファイルアクセスしている箇所も同様に置き換えます。
ファイルアクセス機能を置き換えたので、ファイル(DOOM.WADとprboom.wad)をC言語の静的配列に変換する方法も作りましょう。
変換方法は色々あると思いますが、昔作った「CmakeでバイナリをC言語の配列に変換する」やつを使います(2023年6月16日の日記参照)。こやつは適当に作った割に意外と便利です。
画面描画を削除するとDOOMが動いているかどうかわかりません。移植先の環境に画面を描画するような高尚な機能はないので、UARTとANSIエスケープシーケンスを利用して画面描画の代わりとします。
UARTの出力を受け取る端末には文字を出力する以外にもたくさんの機能があります。端末の各種機能のなかから「背景色の設定+空白の出力」をピクセル描画の代わりとして利用します。端末によって対応する機能は異なり(ECMA-48やANSI X3.64仕様が有名)ますが、今回の実装ではANSI X3.64のカーソル移動、文字色の変更機能を使用します。大抵の端末ソフトが実装しているはずです。たぶん。
端末の文字は縦長(縦:横=2:1くらい、フォント依存です)が多いため、Space 2文字でだいたい正方形になります。つまり背景色変更 + Spece 2文字 = 1ピクセルとすれば画面の描画ができる寸法です。普通の文字サイズだと1ピクセルが大きくなりすぎるので、端末側のフォントサイズ設定で調整しましょう。
背景色を変更するエスケープシーケンスはこんな感じ。
24bit色モードであれば1つのピクセルを表現するために、エスケープシーケンス16バイト+スペース2バイト = 18バイト必要になります。極めて効率が悪いですが、とりあえず動かすために先に進みましょう。
方針が決まったところで画面描画の実装(src/SDL/i_video.c)を改造します。prboom2の画面はフルカラーではなくパレット描画なので、パレット操作をする部分も合わせて改造します。
prboom2が動作している様子(ウインドウはPuTTY、画面サイズ128x120、フォントサイズ5pt)
実際描画してみるとこんな感じです。ウインドウタイトルを見るとわかりますが、SDLによる描画ではなく端末ソフトウェアPuTTYの画面です。
とりあえず動きました。やったね。画面描画が遅い問題は、次回以降対処していこうと思います。
目次: RISC-V
DOOMのクローン実装prboom2を組み込み環境に移植する話です。前回はUARTしかないショボい組み込み環境でも動作できるようにprboom2を改造しました。
Linuxの仮想端末は超速いので描画速度はあまり気になりませんが、組み込み機器に移植すると描画がめちゃくちゃ遅いことに気づくと思います。理由は簡単でUARTが遅いからです。UARTは9600bps〜115.2kbpsがよく使われる速度で、速いものでもせいぜい1.5Mbps程度です。
前回の実装では24bit色モードを使ったので、1つのピクセルを表現するために、エスケープシーケンス16バイト+スペース2バイト = 18バイト必要です。128x120の画面を1枚表示するのに276kB必要、9600bpsだと230秒(0.0043fps)、1.5Mbpsでも1.47秒(0.67fps)です。
端末の背景色設定は24bit色モードと256色モードがあります。256色モードの場合、エスケープシーケンス10バイト+スペース2バイト = 12バイトなので、24bit色より多少は軽量です。128x120の画面を1枚表示するのに184kB必要です。1.5Mbpsで0.98秒(1.01fps)ですね。
24bit色モードはエスケープシーケンスでR, G, Bの各値を指定できるのでどんな色でも指定できました。256色モードの場合はパレットの各色に番号が振られていて、エスケープシーケンスで番号を指定する仕組みです。カラーパレットは上記の配置で固定されていてパレットにない色は使えません。
DOOMの画面の各ピクセルの色を見て、256色モードパレットの色を指す番号を探す減色処理を追加します。256色モードのカラーパレット番号と色の関係は規則的です(※)から、それほど難しくないでしょう。
256色モードだとこんな感じです。24bit色版と比較するとややディティールが潰れていて黒っぽいですけど、まあまあ良さそうです。
(※)16-231番(216色)はR, G, Bそれぞれ6段階の組み合わせです。パレット番号を表す式は、16 + 36r + 6g + b (0 <= r, g, b <= 5) となっています。
もう少し軽くできないか考えてみましょう。今は毎回「背景色変更のエスケープシーケンス + スペース2つ」を出力していますが、左隣のピクセルと色が同じピクセルであれば、背景色変更をする必要はないです。
つまり左隣と同じ色のピクセルが連続する限りエスケープシーケンスの出力を省略できます。非常に単純なRLE(Run-Length Encoding)の一種とも言えましょう。
デモ開始直後のところがわかりやすいですが、256色モードで描画すると真っ黒になってしまう画面が散見されます。
DOOMの画面は比較的暗い色が多いですが、256色モードのパレットは暗い色から明るい色まで均等に割り振られているため、暗い色の表現力が低いです。単純に近似すると画面の色がほぼ真っ黒になります。
この問題を回避するために暗い色をグレースケールに置き換えます。グレースケールと暗い赤、緑、青は違う色ですが、暗い色の色味は区別しづらいのでグレースケールに置き換えてもさほど不自然にはなりません。
こんな感じです。良く見ると壁の暗い緑がグレーになっていたり若干変ですが、総じて悪くない仕上がりです。これで256色モードが活用でき、24bit色モードに比べて描画速度が1.5倍以上になりました。
今まではずっとLinuxの上で作業してきましたが、次回でようやく組み込み機器に移植します。
目次: RISC-V
目次: 独自OS
DOOMのクローン実装prboom2を組み込み環境に移植する話です。前回は画面描画を1.5倍ほど高速化しました。
今まで「組み込み環境」とひとまとめにして呼んでいましたが、OSだけでもLinux、RTOS、もっとシンプルなものも含めると無数にあります。既存のOSの上で動かすのも大変興味深いですが、今回は自作OS(2022年12月14日の日記参照)の上で動かしてみたいと思います(リポジトリへのリンク)。
今まで下記の機能を削除したり、代替機能で置き換えてきたのはこのためです。動作させるボードやSoCにHW機能がない場合もあれば、自作OSにドライバを実装しておらずHW機能があっても自作OSから使う方法がないのです。
自作OSの特徴は下記のようにLinuxと同じlibcを採用して、Linuxのアプリケーションを移植しやすい仕組みになっていることです。速度の遅い組み込み環境で何度も動作確認するのは大変ですから、なるべくLinux上で検証できるようにした構成です。
今回のprboom2の移植の際もC言語のコードを弄る必要はありませんでした。元々あったビルドシステムを無視してMakefileを別途作っていますが、なんでだったか忘れました……。
自作OSのランタイム側のビルドのための準備については、ドキュメント(リンク)を見ていただくとして。QEMU RISC-V 32bit向けに自作OSをビルドします。
$ cd baremetal_crt $ cmake ./ -G Ninja -B build \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_INSTALL_PREFIX=./test/sysroot/ \ -DARCH=riscv \ -DCROSS_COMPILE=riscv64-unknown-elf- \ -DCC=gcc \ -DDEFCONF=riscv_qemu_virt_32_xip $ ninja -C build install
次に改造prboom2をビルドします。前回まで説明してきた改造を全て適用したprboom2をGitHubに置いた(リンク)ので、このコードを使うと簡単です。実装が適当かつ書きかけのコードとかが残っていて美しくありませんが、細かいことは気にしないでください……。
$ cd prboom2 $ ./configure --disable-gl $ cd src/riscv $ make USE_NEWLIB=y USE_SYSROOT=(baremetal_crtのパス)/test/sysroot all
最初のconfigureはconfig.hを作成するために実行しています。特にconfig.hを変更する予定はないので固定で置いてしまえば良かったんじゃないか?と思いましたけど、まあいいでしょう。
$ qemu-system-riscv32 \ -machine virt \ -bios none \ -net none \ -nographic \ -chardev stdio,id=con,mux=on \ -serial chardev:con \ -mon chardev=con,mode=readline \ -smp 4 \ -s -kernel prboom2/src/riscv/prboom
こんな感じで動作確認できます。
描画速度を稼ぐため解像度を半分にしている以外、見た目が前回まで(つまりLinuxで動作させたとき)と同じなのであまり面白くないですね……。
目次: Yocto
Yocto Scarthgap(5.0.1)のメモです。前回同様、コードを読んで依存関係を調べるのは大変時間が掛かるので、簡易的な調査手法として全ファイルを消してエラーを観察し、エラーの原因となるファイルを復活させて次ステップに進める手段を用います。
引き続きBitbakeを実行してエラーを見て、足りないファイルを元に戻していくいう方法で各パーツや設定の動作を見ていきたいと思います。
$ bitbake core-image-sato ERROR: OE-core's config sanity checker detected a potential misconfiguration. Either fix the cause of this error or at your own risk disable the checker (see sanity.conf). Following is the list of potential problems / advisories: DISTRO 'poky' not found. Please set a valid DISTRO in your local.conf
新たなディストリビューション(DISTRO, distribution)なる用語が出てきました。Yoctoのドキュメント(Creating Your Own Distribution - The Yocto Project)には特に用語の説明がないのですが、一般的なLinuxディストリビューションと同じ意味、つまり「Linuxカーネルと周辺ソフトウェアを1つにまとめたもの」を意味していると思われます。
ビルドディレクトリbuild/conf/local.confに下記の記述があり、デフォルトのディストリビューションはpokyとなります。
## build/conf/local.conf
...(略)...
# Default policy config
#
# The distribution setting controls which policy settings are used as defaults.
# The default value is fine for general Yocto project use, at least initially.
# Ultimately when creating custom policy, people will likely end up subclassing
# these defaults.
#
DISTRO ?= "poky"
ちなみに環境変数による設定は上書きできます。DISTROに限らず他の変数も同様です。
$ DISTRO=something bitbake core-image-sato ERROR: OE-core's config sanity checker detected a potential misconfiguration. Either fix the cause of this error or at your own risk disable the checker (see sanity.conf). Following is the list of potential problems / advisories: DISTRO 'something' not found. Please set a valid DISTRO in your local.conf
Yoctoのドキュメントによれば、conf/distroの下にある"distro名.conf"がdistribution configuration fileなので、poky用ならばconf/distro/poky.confが該当します。探すとmeta-poky/conf/distroの下にpoky.confがありました。このファイルも元に戻します。
$ bitbake core-image-sato ERROR: Unable to parse /home/katsuhiro/share/projects/oss/poky/bitbake/lib/bb/parse/parse_py/BBHandler.py Traceback (most recent call last): File "/home/katsuhiro/share/projects/oss/poky/bitbake/lib/bb/parse/parse_py/BBHandler.py", line 71, in inherit(files=['poky-sanity'], fn='configuration INHERITs', lineno=0, d=<bb.data_smart.DataSmart object at 0x7fb98c543910>, deferred=False): if not os.path.exists(file): > raise ParseError("Could not inherit file %s" % (file), fn, lineno) bb.parse.ParseError: ParseError in configuration INHERITs: Could not inherit file classes/poky-sanity.bbclass
再びクラスが見つからないと言われています。どうもpokyディストリビューションだけで使っているクラスがあるようですので、該当するファイルも合わせて元に戻します。
今回登場したファイル、ディレクトリは、
こんなとこ。次回はレシピを見ます。
< | 2024 | > | ||||
<< | < | 06 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | - | - | - | 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | - | - | - | - | - | - |
合計:
本日: