概要

Ngaro は、スタックマシンとして振る舞うポータブルな仮想マシンです。小さく実装も簡単で、特殊な要望に沿った拡張も容易であるように設計されています。

命令セット

命令セットは小さく、31 の主命令から成ります。(実装によっては、命令セットが拡張されています)。

各コード値は最小になるように設計されています。命令 1 つがメモリ単位サイズ (訳注: 現在、32 ビット長が普通) であり、引数はもしあれば、次のメモリ単位位置から取るようになっています (訳注: たいていの Ngaro 実装では、仮想メモリ空間は int の配列として実装されており、この場合アドレスとはその配列のインデックスのことである)。

下のリストのコード値はすべて十進数です。

コード値 名前 説明
000 nop 何もしない
001 lit スタックに値を積む。値は次のメモリ単位位置から取る
002 dup TOS (訳注: スタックのトップ要素) を複製してスタックに積む
003 drop TOS を捨てる
004 swap TOS と NOS (訳注: TOS のすぐ下の要素) を入れ替える
005 push 値をデータスタックからリターンスタックへ移す
006 pop 値をリターンスタックからデータスタックへ移す
007 call サブルーチンを呼び出す。サブルーチンのアドレスは次のメモリ単位位置から取る (訳注: リターンスタックにリターンアドレスを積む)
008 jump 新しいアドレスへジャンプする。アドレスは次のメモリ単位位置から取る
009 return サブルーチンを終えて呼び出し元へ戻る (訳注: リターンスタックトップを捨てる)
010 gt_jump NOS が TOS より大きければジャンプする。アドレスは次のメモリ単位位置から取る
011 lt_jump NOS が TOS より小さければジャンプする。アドレスは次のメモリ単位位置から取る
012 ne_jump TOS と NOS が等しくなければジャンプする。アドレスは次のメモリ単位位置から取る
013 eq_jump TOS と NOS が等しければジャンプする。アドレスは次のメモリ単位位置から取る
014 fetch TOS が指すアドレスに保持されている値を取得する
015 store TOS が指すアドレスに NOS を保存する
016 add TOS に NOS を足す
017 subtract TOS から NOS を引く
018 multiply TOS に NOS を掛ける
019 divmod NOS を TOS で除算して TOS に商、NOS に余りを置く (訳注: 余りは C や Java のそれで、Scheme での remainder の方)
020 and ビット単位 AND
021 or ビット単位 OR
022 xor ビット単位 XOR
023 shift_left ビット列を左 (訳注: より大きい桁方向) へシフトする
024 shift_right ビット列を右 (訳注: より小さい桁方向) へシフトする (訳注: 符号ビットをコピーする算術右シフト。ただし C による実装では C 処理系依存)
025 zero_return TOS が 0 なら呼び出し元へ戻り TOS を捨てる (訳注: リターンスタックトップも捨てる)。TOS が 0 なら何もしない
026 inc TOS に 1 を足す
027 dec TOS から 1 を引く
028 in スタックトップの要素が示す I/O ポートから値を 1 つ読み込みスタックトップに積む
029 out スタックトップの要素が示す I/O ポートへスタックトップの下の値を 1 つ書き込む
030 wait I/O イベントを待つ

I/O デバイス

Ngaro では、I/O ポートのセットを通じてアクセスする形で最小限の I/O デバイスが利用できます。I/O ポートへのアクセスは inout、および wait 命令により行います。

ポート 説明
000 I/O イベント待機
001 キーボード入力
002 コンソール出力
003 コンソール強制更新
004 イメージファイル保存
005 環境問い合わせ
006 キャンバス出力
007 マウス入力

ポート 0: I/O イベント待機

I/O イベントの発生を Ngaro へ伝えるには、対象ポートへ適切な値を書き込んでから、ポート 00 を書き込み、それから wait 命令を呼び出します。

lit 0 # 値 (訳注: 以降、# は行コメントの意味)
lit 0 # ポート
out # ポートへ値を書き込む
wait # I/O イベントを待つ

ポート 1: キーボード入力

キーボードからの読み込みは簡単です。ポート 11 を送ってから I/O イベントを待ちます。I/O イベント発生後に、ポート 1 から打ち込まれたキーを読み込みます。non-keyboard イベントなら 0、それ以外のイベントなら打ち込まれたキーの ASCII コードが読み込まれる値です (訳注: このマニュアル現在では、イベントの種類を伝える実装はない)。

lit 1
lit 1 # キーボード入力ポート
out
# --- I/O イベントを待つ ---
lit 0
lit 0
out
wait
# --- キー入力を読み込む ---
lit 1
in

ポート 2: コンソール出力

コンソールへの文字の書き込みも同じく簡単です。出力する ASCII コードをスタックに積んでから、ポート 21 を送り I/O イベントを待ちます。

lit 98 # 'b' の ASCII コード
lit 1
lit 2 # コンソール出力ポート
out
# --- I/O イベントを待つ ---
lit 0
lit 0
out
wait

ポート 3: コンソール強制更新

Ngaro 仮想マシンは、コンソール (とキャンバス) の更新をキャッシュしてもよいことになっています。ポート 3 を使って、この画面更新を強制できます。

ポート 3 は、通常は 1 の値が設定されています。画面を更新させるには 0 を送ってください。

lit 0
lit 3 # 画面強制更新
out

なお、このポートでは I/O イベントを待つ必要はありません。

ポート 4: イメージファイル保存

ポート 4 で現在のメモリイメージをファイルに保存できます。ポート 41 を送ってから I/O イベントを待ちます。

なお、このポートが使えない実装もあります。

ポート 5: 環境問い合わせ

ポート 5 により、プラットフォームに左右されるデバイス設定や仮想マシンの処理状態に関して Ngaro に問い合わせることができます。

下の値のどれかをポート 5 へ送って I/O イベントを待ち、それからポート 5 から結果を読み込みます。

動作
-1 イメージ用メモリの可能な最大の大きさを返す
-2 キャンバスが利用可能なら -1、不可なら 0
-3 キャンバスの幅
-4 キャンバスの高さ
-5 スタックの現在の深さ
-6 リターンスタックの現在の深さ
-7 マウスが利用可能なら -1、不可なら 0

ポート 6: キャンバス出力

ポート 6 によりキャンバスに描き込むことができます。

動作
001 色の設定。スタックの値をとする
002 1 ピクセル描き込み。xy はスタックから取る
003 四角い枠組み描き込み。xy高さはスタックから取る
004 四角形塗り潰し。xy高さはスタックから取る
005 垂直線描き込み。xy高さはスタックから取る
006 水平線描き込み。xyはスタックから取る
007 丸い枠描き込み。xyはスタックから取る
008 円形塗り潰し。xyはスタックから取る

なお、キャンバスが使えない実装もあります。

ポート 7: マウス入力

ポート 7 によりマウスデバイスにアクセスできます。

マウスの位置を取得するには、ポート 71 を送ってから I/O イベントを待ちます。

lit 1
lit 7
out
# --- I/O イベントを待つ ---
lit 0
lit 0
out
wait

マウスからの座標値はスタックに置かれます。Y 座標が TOS、X 座標が NOS です。

マウスボタンの状態を取得するには、ポート 72 を送ってから I/O イベントを待ちます。

lit 2
lit 7
out
# --- I/O イベントを待つ ---
lit 0
lit 0
out
wait

マウスボタンの状態値はスタックに置かれます。ボタンが押されているなら 1、押されていないなら 0 です。