WebCPU-VMの内部仕様

  • すべての数字は特に断りがなければHex
  • 今のところ仕様に忠実に作っている(はず)なので、インタプリタやJITC作者の人の役には立つかも。
  • 該当オペコード・APIのすべての機能が実装されているとは限らない。
  • 値のチェックは未実装。レジスタの番号範囲さえチェックしていない。
    • なぜなら、例外やエラーのまとまった詳細仕様が見当たらないから…ないなら作ればいいのか!
  • これはRev.1のバックエンドコード仕様を元にしています。

OpCodeMap(Backend)

/+0+1+2+3+4+5+6+7+8+9+A+B+C+D+E+F
+00NOPLBLIMMPLIMMCND+5+6+7LMEMSMEM+A+B+C+DPADDPDIF
+10CP/ORXORAND+3ADDSUBMUL+7SHLSARDIVMOD+C+DPCP+F
+20CMPECMPNECMPLCMPGECMPLECMPGTSTZTSTNZPCMPEPCMPNEPCMPLPCMPGEPCMPLEPCMPG+E+F
+30+0+1MALLOC+3DATA+5+6+7+8+9+A+B+C+D+E+F
+40+0+1+2+3+4+5+6+7+8+9+A+B+C+D+E+F
+50+0+1+2+3+4+5+6+7+8+9+A+B+C+D+E+F
+60+0+1+2+3+4+5+6+7+8+9+A+B+C+D+E+F
+70+0+1+2+3+4+5+6+7+8+9+A+B+C+D+E+F
+80+0+1+2+3+4+5+6+7+8+9+A+B+C+D+E+F
+90+0+1+2+3+4+5+6+7+8+9+A+B+C+D+E+F
+A0+0+1+2+3+4+5+6+7+8+9+A+B+C+D+E+F
+B0+0+1+2+3+4+5+6+7+8+9+A+B+C+D+E+F
+C0+0+1+2+3+4+5+6+7+8+9+A+B+C+D+E+F
+D0+0+1+2+3+4+5+6+7+8+9+A+B+C+D+E+F
+E0+0+1+2+3+4+5+6+7+8+9+A+B+C+D+E+F
+F0+0+1+2+3+4+5+6+7+8+9+A+B+C+DREMARK+F
OSECPUOSECPUOSECPUOSECPUOSECPUOSECPUOSECPUOSECPUOSECPUOSECPUOSECPUOSECPUOSECPUOSECPUOSECPUOSECPU

実装済みの命令

オペコードデバッグモード表記説明
...1......2......3......4......5......6......7......8......9.....10...
00NOP();(No operation)
01optimm32LB(opt, imm32);set label#imm32 to current address.
02reg0Rimm32LIMM(reg0R, imm32);reg0R = imm32;
03reg0Rimm32PLIMM(reg0R, imm32);reg0R = Pointer of label #imm32;
04reg0RCND(reg0R);if((reg0R & 1) == 1){ execute next; } else { pass next; }
08reg0Rtyp32reg1P00LMEM(reg0R, typ32, reg1P, 0);reg0R = *((typ32 *) reg1P);
09reg0Rtyp32reg1P00SMEM(reg0R, typ32, reg1P, 0);*((typ32 *) reg1P) = reg0R;
0Ereg0Ptyp32reg1Preg2RPADD(reg0P, typ32, reg1P, reg2R);reg0P = reg1P + reg2R;
0Freg0Rtyp32reg1Preg2PPDIF(reg0R, typ32, reg1P, reg2P);reg0R = reg1P - reg2P;
10reg0Rreg1RFFCP(reg0R, reg1R);reg0R = reg1R;
10reg0Rreg1Rreg2ROR(reg0R, reg1R, reg2R);reg0R = (reg1R | reg2R);
11reg0Rreg1Rreg2RXOR(reg0R, reg1R, reg2R);reg0R = (reg1R ^ reg2R);
12reg0Rreg1Rreg2RAND(reg0R, reg1R, reg2R);reg0R = (reg1R & reg2R);
14reg0Rreg1Rreg2RADD(reg0R, reg1R, reg2R);reg0R = (reg1R + reg2R);
15reg0Rreg1Rreg2RSUB(reg0R, reg1R, reg2R);reg0R = (reg1R - reg2R);
16reg0Rreg1Rreg2RMUL(reg0R, reg1R, reg2R);reg0R = (reg1R * reg2R);
18reg0Rreg1Rreg2RSHL(reg0R, reg1R, reg2R);reg0R = (reg1R << reg2R);
19reg0Rreg1Rreg2RSAR(reg0R, reg1R, reg2R);reg0R = (reg1R >> reg2R);
1Areg0Rreg1Rreg2RDIV(reg0R, reg1R, reg2R);reg0R = (reg1R / reg2R);
1Breg0Rreg1Rreg2RMOD(reg0R, reg1R, reg2R);reg0R = (reg1R % reg2R);
1Ereg0Preg1PPCP(reg0P, reg1P);reg0P = reg1P
20reg0Rreg1Rreg2RCMPE(reg0R, reg1R, reg2R);reg0R = (reg1R == reg2R) ? -1 : 0;
21reg0Rreg1Rreg2RCMPNE(reg0R, reg1R, reg2R);reg0R = (reg1R != reg2R) ? -1 : 0;
22reg0Rreg1Rreg2RCMPL(reg0R, reg1R, reg2R);reg0R = (reg1R < reg2R) ? -1 : 0;
23reg0Rreg1Rreg2RCMPGE(reg0R, reg1R, reg2R);reg0R = (reg1R >= reg2R) ? -1 : 0;
24reg0Rreg1Rreg2RCMPLE(reg0R, reg1R, reg2R);reg0R = (reg1R <= reg2R) ? -1 : 0;
25reg0Rreg1Rreg2RCMPG(reg0R, reg1R, reg2R);reg0R = (reg1R > reg2R) ? -1 : 0;
26reg0Rreg1Rreg2RTSTZ(reg0R, reg1R, reg2R);reg0R = ((reg1R & reg2R) == 0) ? -1 : 0;
27reg0Rreg1Rreg2RTSTNZ(reg0R, reg1R, reg2R);reg0R = ((reg1R & reg2R) != 0) ? -1 : 0;
28reg0Rreg1Preg2PPCMPE(reg0R, reg1P, reg2P);reg0R = (reg1P == reg2P) ? -1 : 0;
29reg0Rreg1Preg2PPCMPNE(reg0R, reg1P, reg2P);reg0R = (reg1P != reg2P) ? -1 : 0;
2Areg0Rreg1Preg2PPCMPL(reg0R, reg1P, reg2P);reg0R = (reg1P < reg2P) ? -1 : 0;
2Breg0Rreg1Preg2PPCMPGE(reg0R, reg1P, reg2P);reg0R = (reg1P >= reg2P) ? -1 : 0;
2Creg0Rreg1Preg2PPCMPLE(reg0R, reg1P, reg2P);reg0R = (reg1P <= reg2P) ? -1 : 0;
2Dreg0Rreg1Preg2PPCMPG(reg0R, reg1P, reg2P);reg0R = (reg1P > reg2P) ? -1 : 0;
32reg0Preg1Rreg2RMALLOC(reg0P, reg1R, reg2R);reg0P = &(reg1R *)[reg2R];
34typ32len32data...DATA(type32, length32);[data]
FElen...REMARK(len);[...]

命令リファレンス

  • 命令はバイト単位で構成されており、複数バイトの即値はビッグエンディアン(0x123456(32bit) = 00 12 34 56)で指定します。

整数レジスタ

  • R00-R3F
  • 最低精度32bit
  • 64本
  • 番号の小さいレジスタは実レジスタに割り当てられる可能性が高くなります。
    ちなみにx86版では、R00~R02までが実レジスタに割り当てられていて、残りはメモリを使ってレジスタをエミュレーションしています。
  • レジスタの用途区分
    FromTo本数用途
    001F32関数ローカルな汎用レジスタです。他の関数を呼び出しても値は破壊されません。
    20278グローバルな汎用レジスタです。他の関数を呼び出すと、値が破壊されるかもしれません。アプリが自由に用途を決められます。
    282F8グローバルな汎用レジスタです。他の関数を呼び出すと、値が破壊されるかもしれません。OSが用途を決めています。
    303B12テンポラリレジスタです。汎用ではありますが、関数との引数・戻り値のやりとりや、ASKAにおける数式の計算に利用されるので値が破壊されやすいです。
    3C3E3Reserved. 将来の拡張のために予約されています。
    3F1定数即値指定などの特殊用途に利用するもので、レジスタとして値を格納するのには使えません。
  • CND命令では、整数レジスタの最下位1bitが1(真)か0(偽)かで条件判断されます。
    • C言語のように0か0以外かで判断しているのではないので、注意が必要です。

ポインタレジスタ

  • P00-P3F
  • 内部構造は実装依存
  • 番号の小さいレジスタは実レジスタに割り当てられる可能性が高くなります。
    ちなみにx86版では、P00~P02までが実レジスタに割り当てられていて、残りはメモリを使ってレジスタをエミュレーションしています。
  • レジスタの用途区分
    FromTo本数用途
    001予約済み(ベースポインタ)です。未実装なので使用できません。
    011F31関数ローカルな汎用レジスタです。他の関数を呼び出しても値は破壊されません。
    20278グローバルな汎用レジスタです。他の関数を呼び出すと、値が破壊されるかもしれません。アプリが自由に用途を決められます。
    282F8グローバルな汎用レジスタです。他の関数を呼び出すと、値が破壊されるかもしれません。OSが用途を決めています。
    303B12テンポラリレジスタです。汎用ではありますが、関数との引数・戻り値のやりとりや、ASKAにおける数式の計算に利用されるので値が破壊されやすいです。
    3C3E3Reserved. 将来の拡張のために予約されています。
    3F1無条件分岐などの特殊用途に利用するもので、レジスタとして値を格納するのには使えません。(内部的には命令ポインタといえる?)

ポインタタイプ

  • ポインタにはタイプ(データ型)があります。
  • データ型の一致しないポインタの読み書きはセキュリティ違反になります。
    typ32型名説明
    0x00Undefined
    0x01VPtrプログラムコード領域?
    0x02SINT8signed char.
    0x03UINT8
    0x04SINT16short.
    0x05UINT16
    0x06SINT32
    0x07UINT32
    0x08SINT4
    0x09UINT4
    0x0ASINT2
    0x0BUINT2
    0x0CSINT1bool.代入できるのは0か-1のみ.
    0x0DUINT1
    0x0ESINT12
    0x0FUINT12
    0x10SINT20
    0x11UINT20
    0x12SINT24
    0x13UINT24
    0x14SINT28
    0x15UINT28

00:NOP 何もしない命令

この命令は何もしません。JITコンパイラはこの命令を翻訳せず、実CPUに対してNOP命令は発行されません。

01:LB ラベル定義命令

123456
LB01optimm32

ラベルを定義します。OSECPUでは、ラベルの場所に対してのみ実行を転送できます。 ラベル番号は同一アプリケーション中で重複してはなりません。

  • opt
    • 0:local分岐先(ポインタレジスタ及びメモリに格納できない)
    • 1:public分岐先(ポインタレジスタ及びメモリに格納できる) opt=1はopt=0に比べてリソースが消費されます。基本的にはopt=0を利用してください。
      ラベル番号は本来は32ビットの任意の整数(負の数もOK)なのですが、現状の実装では0~4095までしか処理できません。すみません手抜きです。

02:LIMM 定数即値代入命令

123456
LIMM02reg0Rimm32
  • reg0Rは00-3F全ての整数レジスタ番号が指定できます。
  • imm32は符号付き32bit整数をビッグエンディアンで指定します。

03:PLIMM ラベル番号代入命令

123456
PLIMM03reg0Pimm32
  • reg0Pは00-3F全ての整数レジスタ番号が指定できます。
  • imm32は、ラベル番号を符号付き32bit整数、ビッグエンディアンで指定します。

04:CND 条件実行プリフィックス

12
CND04reg0R...
  • CNDは単体の命令ではなく、後続の1命令を条件実行命令化します。
    • このプリフィクスをつけられないもの:
      • CNDプリフィクスそれ自体
      • R3FへのLIMM
  • reg0Rには、R3F以外のR00-R3Eが指定できます。
  • reg0R==0の場合、後続の1命令は実行されません。
  • reg0R==1の場合、後続の1命令はそのまま実行されます。

08,09:LMEM/SMEM メモリアクセス命令

12345678
LMEM08reg0Rtyp32reg1P00
SMEM09reg0Rtyp32reg1P00
  • メモリを読み書きします。
  • typ32にはポインタタイプを指定します。
  • LMEMの場合
    • reg0R <- reg1P
  • SMEMの場合
    • reg1P <- reg0R

セキュリティ違反になる場合

  • reg1Pのポインタタイプが「データ」でない場合。
  • reg1Pのポインタタイプがtyp32と一致しない場合。

0E:PADD メモリ加算命令

12345678
PADD0Ereg0Ptyp32reg1Preg2R

reg1Pのポインタ位置にreg2Rの値を加えた結果、指し示す位置のポインタをreg0Pに代入します。

セキュリティ違反になる場合

  • reg1Pのポインタタイプが「データ」でない場合。
  • reg1Pのポインタタイプがtyp32と一致しない場合。

0F:PDIF メモリ差分命令

12345678
PDIF0Freg0Rtyp32reg1Preg2P

reg0R = reg1P - reg2Pとなるよう、二つのポインタの差分をreg0Rに代入します。

セキュリティ違反になる場合

  • reg1Pのポインタタイプが「データ」でない場合。
  • reg1Pのポインタタイプがtyp32と一致しない場合。

10-1B:CP/OR,XOR,AND,ADD,SUB,MUL,SHL,SAR,DIV,MOD 整数三項演算命令

1234
CP10reg0Rreg1RFF
OR10reg0Rreg1Rreg2R
(other)OpCodereg0Rreg1Rreg2R
  • OpCode
    ORXORANDADDSUBMULSHLSARDIVMOD
    OpCode10111214151618191A1B
  • CP/ORは命令番号を共有しています
    • CP:4バイト目がFFの場合
    • OR:4バイト目が00-3Fの整数レジスタ番号の場合 それぞれの動作は、上にある実装済みの命令表の説明を参照してください。

実装済みのAPI

  • APIIDはR30に入る値。
    APIID(R30)API名...R31......R32......R33......R34......R35......R36...説明
    FF40openWinxSizeySize
    FF41flushWinxSizeySizex0y0終了時に自動で呼ばれる。
    FF44drawPointmodexycol
    FF45drawLinemodex0y0x1y1col
    FF46fillRectmodexSizeySizex0y0col
    FF47fillOvalmodexSizeySizex0y0col

間違い等の指摘があればお願いします…

  • LB命令で「0:local分岐先(ポインタレジスタ『ただしPCを除く』、及びメモリに格納できない)」だと思う。 -- ttwilb 2014-03-24 (月) 17:06:46

コメントお名前NameLink

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2014-03-24 (月) 17:06:46 (2984d)