OSECPUのバイトコードの詳細仕様
(0) はじめに
(1) 整数レジスタ
- OSECPUは32bitの signed int な整数レジスタを64本持っています。
- R00~R3F と表記します。
- R00やR01など番号の若いレジスタは、実際のCPUの実レジスタに割り当てるように推奨されているので、R00への代入やR00の値の参照は、R20に対する操作と比べて数倍高速になることが多いです。
- 結局どうなるかは処理系依存で、保障はされていません。
- ということで、特にこだわりがないのならR00やR01を使いましょう。
- ちなみにx86版では、R00~R02までが実レジスタに割り当てられていて、残りはメモリを使ってレジスタをエミュレーションしています。
- これらのレジスタはすべて対等で汎用的に使われるというわけではなく、ある程度の使い方が決まっています。これに逆らってはいけないということはないですが、ライブラリなどで食い違うといろいろ面倒かもしれません。
- R00~R1F (32本) : 最も汎用的な整数レジスタで、通常は関数ごとにローカルとして扱えます。つまり関数を呼び出しても破壊されたりはしません。
- R20~R27 ( 8本) : 汎用ですが、関数ごとにローカルというわけではなく、グローバル変数的に使うことを想定しています。関数呼び出しによって変更される可能性もあります。
- R28~R2F ( 8本) : これも汎用ですが、関数ごとにローカルではなく、グローバル変数的に使われます。主にOSが用途を決定しています。これに対してR20~R27はアプリが自由に用途を決定できます。
- R30~R3B (12本) : 基本的にはこれらも汎用なのですが、関数の引数を渡したり、返値を入れたりするためにも使われるレジスタで、値が破壊されやすいです。ASKAでは複雑な数式を計算しなければいけなくなると、R3BやR3Aをテンポラリとして勝手に使い、値を破壊してしまうこともあります。R39やR38まで手をつけることだってあります。しかし最悪でもR30までで、R2Fに手出しすることはありません。
- R3C~R3E ( 3本) : 将来の拡張のためにリザーブされています。
- R3F ( 1本) : 後で説明する特別な用途のための整数レジスタです。汎用には使えません。
- 全体として、OSECPUのレジスタはかなり多いほうだと思います。これはOSECPUがメモリ操作を苦手としていて、できるだけレジスタだけで主要な演算が完結できるようにという設計方針によるものです。
(2) フラグレジスタ
- x86でもARMでも、さらに6502やZ80でも、みんなフラグレジスタというものを持っていました。
- しかしOSECPUにはフラグレジスタはありません。MIPSの仕様に似ています。
- フラグレジスタがない代わりにCMPcc命令の結果に応じて任意の整数レジスタを0か-1に変更することができます。つまり普通のレジスタをフラグレジスタの代わりにしてしまったようなものです。
- これで設定された値を後述のCNDプリフィクス命令(04 Rxx)で使えば、条件分岐や条件付き代入などができます。
(3) 定数即値代入命令
02 Rxx imm32
LIMM(Rxx, imm32);
- 6バイト命令です。Rxxには0x00から0x3fのレジスタ番号を指定します。imm32は定数即値を4バイトのビックエンディアンで指定します。
(4) 単純代入命令
10 reg0 reg1 FF
CP(reg0, reg1);
- 4バイト命令です。Rxxフィールドが複数ある命令では、ここではreg0, reg1のように区別して表記することにします。
- reg1の値がreg0へコピーされます。
- reg0にR3Fを指定することはできません。reg1にもR3Fを指定してはいけません。
- この命令はバイトコード的には、OR命令でreg2をFFに指定した形式になっています。
- メモリの内容をコピーすることはこの命令ではできません。
(5) 三項演算命令
10 reg0 reg1 reg2
OR(reg0, reg1, reg2);
- 4バイト命令です。reg1とreg2がOR演算されて、結果がreg0に格納されます。演算結果に応じてフラグレジスタが変化するみたいな副作用はありません。
- 他にも以下のような命令がこの形式になっています。
- 11 XOR
- 12 AND
- 14 ADD
- 15 SUB
- 16 MUL 符号付き乗算
- 18 SHL 左シフト
- 19 SAR 右シフト(符号付き)
- 1A DIV 符号付き除算
- 1B MOD 符号付き剰余
- 符号なしの演算は一切サポートされていません。OSECPUでは整数レジスタはすべて符号付きの32ビットだと仮定しているためです。
- INCやDECのような命令は持っていません。
- 二項演算命令も持っていません。ADD(R00, R01);みたいなことがやりたいのであれば、ADD(R00, R00, R01);と書く必要があります。
- キャリーやボロー(桁あふれや桁借り)やオーバーフローを検出することはできないので、(必要なら)めんどうでも別の方法で検査する必要があります。
- OSECPUでは定数を用いた演算命令を用意していません。もしR00に1を加えたいのであれば、ADD(R00, R00,1);とは書けないので、この1をレジスタR01とかに入れておいて、ADD(R00, R00, R01);としなければいけません。これは少々不便です。
こめんと欄