ポケコンエミュレータ Pokecom Go と SC61860

Android 用ポケコンエミュレータで LC-3 コンパイラが動いたとの連絡を頂いたので紹介させていただきます。

Pokecom GO

LC-3 について幾つか質問もいただいたのですがだいぶ忘れていました。資料が残っていると思うので発掘できたら紹介させていただきます。

また LC-3 の配布に関しては自由に行っていただいて構いません。ダンプリスト、バイナリ等、任意に掲載していただいて結構です。

SHARP のポケットコンピュータに使われた CPU SC61860 は、小型でポケットに入る電卓サイズの機種に搭載されています。小型&安価な機種ながら、8bit でマシン語が使えることから人気が出ました。それ以前のポケットコンピュータ PC-1211/10 は 4bit CPU が使われており BASIC しか使えませんでした。また最上位機種 PC-1500/1501 はより強力な CPU を搭載しており性能が高かったものの、サイズも大きく高価でした。

PC-1250/51/45/55 当時のポケコン向け BASIC は非常に低速で、アクションゲームのようなリアルタイムな処理はほぼ不可能でした。数値演算はすべて10進数の BCD で行われており、内部表現は単精度で 8byte も消費します。整数型はありませんし CPU Clock も 576KHz です。

画面に任意の dot pattern を表示することができず、表示できるのは ASCII の A~Z 大文字のみ。しかも BASIC 演算実行中は画面の表示が強制的に off になり、画面に文字列を表示できるのは表示命令で実行が止まっているときだけです。

サウンドも予め内蔵されている BEEP 音を一定期間鳴らすことしかできず、音程等はありませんでした。

しかしながら隠し機能だったマシン語を使うことで、これらのこれらの制限がほぼなくなることが判明します。PC-1250/51 向けのマシン語解析記事が当時の雑誌に掲載され、さまざまなゲームも作られるようになります。

マシン語を活用すると動作も高速でリアルタイムなキー入力も可能。常時画面表示を ON にしたまま任意のドットパターンを表示することができました。サイクル計算次第では任意の音程のサウンド再生も可能です。

ただ上記の通り RAM が圧倒的に足りません。RAM は不揮発性でストレージを兼ねていましたが、外部記憶装置はカセットテープなので外部から容易に読み込むこともできません。

そのため当時のマシン語プログラミングは動作効率よりもいかにサイズを減らすかが重要でした。1byte 減らすためには何でもしました。

例えば相対ジャンプは前後 8bit 範囲 (= 9bit 512byte 範囲) にしか飛べないので、リロケータブル前提で大きなプログラムを作る場合は途中に中継地点が必要です。無駄な命令が増えるので、条件付きジャンプだったとしても同じ番地に戻る命令があればそこを再利用します。もちろん飛ぶ前にフラグが誤動作する組み合わせにならないように、前後の命令を入れ替えるなどして調整します。

A:
           ; 目的位置

B:
  102Dnn   ; DP を破壊しても良い前提で中継地点を埋め込む。2Dnn が A: に飛ぶ命令


  41       ; I--
  29nn     ; JRNZ ; 中継地点の B: +1 に飛ぶ。

A:
           ; 目的位置

C:
  2Bnn     ; JRNC ; たまたま同じ A: に飛ぶ別の命令 (条件付き)


  41       ; I--
  29nn     ; JRNZ ; C: に飛ぶ。41 により C=0 が保証されている

これで中継地点が不要となり 3byte 減ります。CMP/INC/DEC 系はフラグを破壊するので、代わりに BIT TEST や 5A/D2 (SHIFT) を使うのもありです。リロケータブル化が不要な場合でも絶対ジャンプと比べると 1byte 削減になります。

CPU の未定義な挙動も使いました。そのため CPU エミュレータを作るには、ドキュメント化されていない CPU の内部挙動まである程度再現する必要があるかもしれません。

有名なところだと特定の命令で Q レジスタに定数(レジスタ番号)が格納されることでしょう。

1302    Q=02

もし A を破壊しても構わなければ INC A を代わりに使うことができます。これで 1byte 減ります。

42      A++   (副作用で Q=02)

35 命令は PC を使ってメモリ内容を読み出すことができます。PC が破壊されると困るので、内部で一時的にスタックに PC を保存しているようです。そのため 35 命令を使うとスタックに PC の痕跡が残ります。

ただし PC の読み出しなら 35 命令を使わなくても、内RAM 内ROM 内の任意の 37 (RTN) を一度呼び出せば良いので、あまり使わなかったように思います。

SC61860 は RAM にアクセスするには必ず特定のレジスタを経由しなければなりませんでした。DP もしくは PC です。

メモリアクセス可能なレジスタ

Register 内ROM 外ROM 外RAM VRAM
DP Y Y Y
PC Y Y Y

内ROM (CPU 内蔵 ROM) はプロテクトがかかっており通常のデータアクセス用 DP では読み出すことができませんでした。ですがプログラムの実行はできるので、PC は当然読み出すことが可能です。35 命令は PC を使うことで、本来読み出せないはずの内 ROM の内容を読み込むことができます。

マシン語モニタを作る場合は DP ではなく常に PC (35命令) を使えばよいかというとそうではなく、今度は VRAM を読むことができません。すべてのメモリにアクセスするには、DP, PC 両方を併用する必要があります。ちなみに PC は VRAM にアクセス出来ないので、VRAM にマシン語コードを書き込んでも実行できませんでした。

byte 削減のために一番活用したのはやはり 内ROM で、少しでも都合が良い命令並びがあれば積極的に 内ROM CALL を多用していました。たった 3byte の命令並びでも、内ROM CALL だと 2byte で済むからです。

関連エントリ
24年ぶりに「おくやくん」が移植されました。ポケコン PC-1245
BASICコンパイラと手書き原稿の時代
28年前のモバイル PC-1211 他
20年前のモバイル PC-1417G