プチコン3号でのゲーム制作環境を考えるメモ

プチコン3号を買ってみた。Nintendo 3DSで動作するBASICインタプリタ

簡単な画面fill程度だと30fps出せるので、16bit版を移植できるのではないかとトライしてみることにした。
プチコン3号はバイトコードVMを基盤にした実数BASIC実装で、従来のASTベースと見られるインタプリタから大幅な高速化を果たしている。プチコン3号は現状New3DS3DSの両対応となっている。

プログラム/リソースの転送

(プチコン自体にもテキストエディタは装備されているが、これを駆使してゲームを作るのはちょっと現実的でない)
先代のプチコンに有ったようなQRコード認識によるプログラム/リソースの転送はできなくなっている。このため、プログラム/リソースの入力には必然的に音声入出力を使用することになる。(3)DSのDSPは基本的に32kHzで、BASICからも32kHz/16bitの入力にアクセスできるようになっている。出力はMMLを経由したシーケンサで、今のところストリーミングできない。
音声によるデータ入力は既にいくつかの実装が有る。

手元でQPSK + Hamming(7,4)を追試してみたところ、安定して転送できるのは1024バイト程度で、それ以上は再同期を挟まないと厳しい状況だった。プログラムはそれほど大きくはないが、画像データ + ステージデータで500KiBを越えてくるので、3DS側からACK/NAKを返す仕組みを用意しないと厳しそうだ。
おそらく、現状の環境で最大の効率を発揮するにはPCMコーディング(= AM)で300〜1000シンボル/secを達成する必要が有る。3DSのライン入力は良い精度の16bit入力で、録音したデータのヒストグラムを観察する限りは10bit程度の精度を実現できているように見える。PSKやFSKの低サンプリングレートのソフトウェアモデムでの実現は一般にシンボルレートを上げづらい。
ただ、PSKやFSKは単純なコンパレータを通して1bit信号でも実装できるため、(内蔵されているであろう)AGC/AECの影響を比較的うけづらいという大きなメリットが有る。PCMの場合は、これらの影響は直接波形精度の劣化という形で受けることになる。

ハードウェア抽象化レイヤとしてのプチコン3号

(あとでちゃんと書く: エミュレータを作るためにはもうちょっと真面目に考察が必要)
プチコンシリーズは基本的にMS BASICや80年代のホビーパソコンの影響を受けたシステムとなっており、Sega SaturnPS2で実装されたようなgame BASIC系のものと比べると機能的には見劣りするものとなる。例えばハードウェアはポリゴンをサポートするがポリゴンのための命令は一切備えていないし、漢字の表示をサポートしていない。
グラフィックスやオーディオは議論の有るところだと思うが、地味にタイマが無いため、チューニング時に不可欠な時間計測が行えない。今のところ、オーディオサンプル位置をMICPOS変数により取得することは可能なので、それで代替することができる。
オーディオ出力はMMLを書いて出力する楽曲出力が使用できるが、楽曲の演奏位置を取得する方法が無い。MMLには8bit変数を8つまで持たせることができ、この変数は相互に読み書き可能であるため、これを監視することで強制的な同期が可能となっている。まだ同期の精度については考察していない。
N64以降の任天堂ハードウェアのOSは一般にスレッドをサポートするが、プチコンにはスレッドのサポートは存在しない。プチコンに存在する唯一の時間同期手段はVSYNCで、ゲームループ先頭でVSYNCとMICPOSを同期し、MICPOSを使用して各パートの時間計測を行うことになる。
グラフィックスは512x512のテクスチャであるグラフィックスページ(GRP0〜GRP5の6枚+コンソール用隠しページGRPF)とそれに対する数値配列のblitやLINEやPAINT等のBASICでよくある描画命令で描画することができる。また、BG/スプライトといったグラフィックスページをソースとするゲーム向け描画機能や、伝統的なBASICのLOCATE文を使用するコンソールも備えている。
3DSは3D表示が特徴的なハードウェアだが左右で別々のデータを表示する方法は無く、BG/スプライト/コンソールで視差を付けられるだけとなっている。特に、BGはBG面単体の指定となるため、1枚のBG中で異なるZ値を持たせることはできない。
スプライトは大きさに制限が無く、最大512個を表示することができる。上下画面ではスプライト番号を適当に区切り、上画面に412個下画面に100個のように設定する必要がある。スプライトも視差のためのZ値を持つことができ、視差によって自動に拡大縮小されることは無い。全てのスプライトは1つのグラフィックページに含める必要がある。このため、グラフィックページの面積である512x512ドットが事実上のスプライトの最大サイズとなる。
BGは4枚定義/表示することができ、16k個分の16x16ドットチップを指定したグラフィックページから指定して表示することができる。
視差のためのZ値はグラフィックスの重ね合わせ順としても使用される。Z値としては-256〜1024まで指定できるが、視差は最大でも10ドット程度となるため変化は段階的となる( https://twitter.com/shisyamo_wizwiz/status/540146109838917632 )。また、何故か3D表示を無効にする方法は提供されない(手動で3Dボリュームを調整する必要がある)。(see comment) 一般には画面から飛び出す方向の使用は推奨されないが、プチコンはどうも積極的に使用しているように見える。画面から飛び出す方向のZ値は、HUDの表示の際に障害となるため、半透明パーティクルなど用途を絞るのが望ましい。

プログラミング環境としてのプチコン3号

プチコン3号はバイトコードVMを基盤としており、BASIC言語としてはかなり拡張されたものとなっている。
実行環境はPRG0〜PRG3の4つの"スロット"をもち、それぞれで独立した大域環境を持つ。また、関数/手続きに関しては、"COMMON DEF"命令によってスロットを越えてエクスポートすることができる。
evalに相当するものとしてはUSE命令が有る。PRGEDIT命令等のプログラム編集命令群( http://smileboom.com/special/ptcm3/reference/#code )を使用してスロットを構築し、USE命令を使用することでバイトコードコンパイルを行わせることができる。(特に、プチコンシリーズは伝統的にLOADによってプログラムのロードを行うとダイアログ確認と演出が入るため、高速なロードのためにはこのテクニックが必要になる。)
↑のようなリソース入力事情と合わせると、プログラムを小さく分割(モジュール化)し、3DS側でLOADとPRGEDITを駆使して繋ぎ合わせて実行するのが標準的なスタイルになると考えられる。

プログラミング言語としてのプチコン3号

公式サイトの"スペック"に載っている : http://smileboom.com/special/ptcm3/spec/
(この"スペック"の内容は3DS側の説明書における30ページ目 "BASIC基本仕様" に相当する)
プチコン3号で実装されているプログラミング言語はBASICの方言の一つといえる。いわゆる構造化BASICの筋を引き、かつ、いくつかのモダンな変更を加えている。

  • 行番号の廃止
  • 関数定義とエクスポート
  • 4次元まで扱える配列
    • 配列の添字はC言語記法を使用、0 origin
    • 1次元配列はPUSHとPOP/SHIFTによってサイズの増減が可能
  • バイトコードコンパイルを意識する必要のある仕様
    • カレントでないプログラムスロットにLOADした場合はUSEまたはEXECによってバイトコードコンパイルする必要が有る
    • CONT命令は編集後使用不可
  • "OPTION STRICT"による変数宣言の強制機能
    • STRICT時はVAR構文によって変数の宣言が可能で、VARはDIMの機能も併せ持つ
    • STRICT時は一部命令の配列自動伸長が何故か無効になる
  • グローバル変数はRUN時に自動的にクリアされる
  • 3種類のデータ型

BASICの常として、変数の参照型が存在しない。必要な場合は、DEFで手続きを定義し、OUTを取るようにする。配列は入力として与え、関数内で書き込むことができる。
言語の重要な欠陥として、ELSEIFが存在しない点がある。このため、単純なIF - THEN - ELSEタイプでない分岐は、その分だけENDIFを書き連ねることになる。いわゆるSWITCH - CASEも存在しない。BASICによくあるON ... GOTO等は存在する。
浮動小数点数を扱うことはできるが、NaNやInfをサポートしていない。これらの表示形は存在せず、値が出現すると演算はエラーになる(はず) 何か間違っている(see comment)。

次の一手

プチコン上での動作確認を必要最低限にする必要がある。このため、使用する命令に絞ってエミュレータを作るのが好ましいように思える。
... もっとも、使用する命令を選ぶためにはバジェッティングが必要で、このためにはやっぱりPC→3DSを最初に確立する必要がある。というわけで、最初は音声CODECとプロトコルのデザインをする。3DS→PCの必要性は難しいところ。単純なACK/NAKであれば、ビープ音の高低で十分実現できるが。。