*WebCPU-VMの内部仕様 -すべての数字は特に断りがなければHex -今のところ仕様に忠実に作っている(はず)なので、インタプリタやJITC作者の人の役には立つかも。 -該当オペコード・APIのすべての機能が実装されているとは限らない。 -値のチェックは未実装。レジスタの番号範囲さえチェックしていない。 --なぜなら、例外やエラーのまとまった詳細仕様が見当たらないから…ないなら作ればいいのか! -&color(#ff0000){これはRev.1のバックエンドコード仕様を元にしています。}; -- Rev.2はこちら[[page0072]] **OpCodeMap(Backend) ,/,+0,+1,+2,+3,+4,+5,+6,+7,+8,+9,+A,+B,+C,+D,+E,+F ,+00,[[NOP>#NOP]],LB,LIMM,PLIMM,CND,+5,+6,+7,LMEM,SMEM,+A,+B,+C,+D,PADD,PDIF ,+10,CP/OR,XOR,AND,+3,ADD,SUB,MUL,+7,SHL,SAR,DIV,MOD,+C,+D,PCP,+F ,+20,CMPE,CMPNE,CMPL,CMPGE,CMPLE,CMPG,TSTZ,TSTNZ,PCMPE,PCMPNE,PCMPL,PCMPGE,PCMPLE,PCMPG,+E,+F ,+30,+0,+1,MALLOC,+3,DATA,+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,+D,REMARK,+F ,,OSECPU,OSECPU,OSECPU,OSECPU,OSECPU,OSECPU,OSECPU,OSECPU,OSECPU,OSECPU,OSECPU,OSECPU,OSECPU,OSECPU,OSECPU,OSECPU **実装済みの命令 ,オペコード,==,==,==,==,==,==,==,==,==,デバッグモード表記,説明 ,...1...,...2...,...3...,...4...,...5...,...6...,...7...,...8...,...9...,..10...,, ,00,,,,,,,,,,NOP();,(No operation) ,01,opt,imm32,==,==,==,,,,,"LB(opt, imm32);",set label#imm32 to current address. ,02,reg0R,imm32,==,==,==,,,,,"LIMM(reg0R, imm32);",reg0R = imm32; ,03,reg0R,imm32,==,==,==,,,,,"PLIMM(reg0R, imm32);",reg0R = Pointer of label #imm32; ,04,reg0R,,,,,,,,,"CND(reg0R);",if((reg0R & 1) == 1){ execute next; } else { pass next; } ,08,reg0R,typ32,==,==,==,reg1P,00,,,"LMEM(reg0R, typ32, reg1P, 0);",reg0R = *((typ32 *) reg1P); ,09,reg0R,typ32,==,==,==,reg1P,00,,,"SMEM(reg0R, typ32, reg1P, 0);",*((typ32 *) reg1P) = reg0R; ,0E,reg0P,typ32,==,==,==,reg1P,reg2R,,,"PADD(reg0P, typ32, reg1P, reg2R);",reg0P = reg1P + reg2R; ,0F,reg0R,typ32,==,==,==,reg1P,reg2P,,,"PDIF(reg0R, typ32, reg1P, reg2P);",reg0R = reg1P - reg2P; ,10,reg0R,reg1R,FF,,,,,,,"CP(reg0R, reg1R);",reg0R = reg1R; ,10,reg0R,reg1R,reg2R,,,,,,,"OR(reg0R, reg1R, reg2R);",reg0R = (reg1R | reg2R); ,11,reg0R,reg1R,reg2R,,,,,,,"XOR(reg0R, reg1R, reg2R);",reg0R = (reg1R ^ reg2R); ,12,reg0R,reg1R,reg2R,,,,,,,"AND(reg0R, reg1R, reg2R);",reg0R = (reg1R & reg2R); ,14,reg0R,reg1R,reg2R,,,,,,,"ADD(reg0R, reg1R, reg2R);",reg0R = (reg1R + reg2R); ,15,reg0R,reg1R,reg2R,,,,,,,"SUB(reg0R, reg1R, reg2R);",reg0R = (reg1R - reg2R); ,16,reg0R,reg1R,reg2R,,,,,,,"MUL(reg0R, reg1R, reg2R);",reg0R = (reg1R * reg2R); ,18,reg0R,reg1R,reg2R,,,,,,,"SHL(reg0R, reg1R, reg2R);",reg0R = (reg1R << reg2R); ,19,reg0R,reg1R,reg2R,,,,,,,"SAR(reg0R, reg1R, reg2R);",reg0R = (reg1R >> reg2R); ,1A,reg0R,reg1R,reg2R,,,,,,,"DIV(reg0R, reg1R, reg2R);",reg0R = (reg1R / reg2R); ,1B,reg0R,reg1R,reg2R,,,,,,,"MOD(reg0R, reg1R, reg2R);",reg0R = (reg1R % reg2R); ,1E,reg0P,reg1P,,,,,,,,"PCP(reg0P, reg1P);",reg0P = reg1P ,20,reg0R,reg1R,reg2R,,,,,,,"CMPE(reg0R, reg1R, reg2R);",reg0R = (reg1R == reg2R) ? -1 : 0; ,21,reg0R,reg1R,reg2R,,,,,,,"CMPNE(reg0R, reg1R, reg2R);",reg0R = (reg1R != reg2R) ? -1 : 0; ,22,reg0R,reg1R,reg2R,,,,,,,"CMPL(reg0R, reg1R, reg2R);",reg0R = (reg1R < reg2R) ? -1 : 0; ,23,reg0R,reg1R,reg2R,,,,,,,"CMPGE(reg0R, reg1R, reg2R);",reg0R = (reg1R >= reg2R) ? -1 : 0; ,24,reg0R,reg1R,reg2R,,,,,,,"CMPLE(reg0R, reg1R, reg2R);",reg0R = (reg1R <= reg2R) ? -1 : 0; ,25,reg0R,reg1R,reg2R,,,,,,,"CMPG(reg0R, reg1R, reg2R);",reg0R = (reg1R > reg2R) ? -1 : 0; ,26,reg0R,reg1R,reg2R,,,,,,,"TSTZ(reg0R, reg1R, reg2R);",reg0R = ((reg1R & reg2R) == 0) ? -1 : 0; ,27,reg0R,reg1R,reg2R,,,,,,,"TSTNZ(reg0R, reg1R, reg2R);",reg0R = ((reg1R & reg2R) != 0) ? -1 : 0; ,28,reg0R,reg1P,reg2P,,,,,,,"PCMPE(reg0R, reg1P, reg2P);",reg0R = (reg1P == reg2P) ? -1 : 0; ,29,reg0R,reg1P,reg2P,,,,,,,"PCMPNE(reg0R, reg1P, reg2P);",reg0R = (reg1P != reg2P) ? -1 : 0; ,2A,reg0R,reg1P,reg2P,,,,,,,"PCMPL(reg0R, reg1P, reg2P);",reg0R = (reg1P < reg2P) ? -1 : 0; ,2B,reg0R,reg1P,reg2P,,,,,,,"PCMPGE(reg0R, reg1P, reg2P);",reg0R = (reg1P >= reg2P) ? -1 : 0; ,2C,reg0R,reg1P,reg2P,,,,,,,"PCMPLE(reg0R, reg1P, reg2P);",reg0R = (reg1P <= reg2P) ? -1 : 0; ,2D,reg0R,reg1P,reg2P,,,,,,,"PCMPG(reg0R, reg1P, reg2P);",reg0R = (reg1P > reg2P) ? -1 : 0; ,32,reg0P,reg1R,reg2R,,,,,,,"MALLOC(reg0P, reg1R, reg2R);",reg0P = &(reg1R *)[reg2R]; ,34,typ32,==,==,==,len32,==,==,==,data...,"DATA(type32, length32);[data]", ,FE,len,...,,,,,,,,"REMARK(len);[...]", *命令リファレンス -命令はバイト単位で構成されており、複数バイトの即値はビッグエンディアン(0x123456(32bit) = 00 12 34 56)で指定します。 **整数レジスタ -R00-R3F -最低精度32bit -64本 -番号の小さいレジスタは実レジスタに割り当てられる可能性が高くなります。 ちなみにx86版では、R00~R02までが実レジスタに割り当てられていて、残りはメモリを使ってレジスタをエミュレーションしています。 -レジスタの用途区分 ,From,To,本数,用途 ,00,1F,32,関数ローカルな汎用レジスタです。他の関数を呼び出しても値は破壊されません。 ,20,27,8,グローバルな汎用レジスタです。他の関数を呼び出すと、値が破壊されるかもしれません。アプリが自由に用途を決められます。 ,28,2F,8,グローバルな汎用レジスタです。他の関数を呼び出すと、値が破壊されるかもしれません。OSが用途を決めています。 ,30,3B,12,テンポラリレジスタです。汎用ではありますが、関数との引数・戻り値のやりとりや、ASKAにおける数式の計算に利用されるので値が破壊されやすいです。 ,3C,3E,3,Reserved. 将来の拡張のために予約されています。 ,3F,==,1,定数即値指定などの特殊用途に利用するもので、レジスタとして値を格納するのには使えません。 -CND命令では、整数レジスタの最下位1bitが1(真)か0(偽)かで条件判断されます。 --C言語のように0か0以外かで判断しているのではないので、注意が必要です。 **ポインタレジスタ -P00-P3F -内部構造は実装依存 -番号の小さいレジスタは実レジスタに割り当てられる可能性が高くなります。 ちなみにx86版では、P00~P02までが実レジスタに割り当てられていて、残りはメモリを使ってレジスタをエミュレーションしています。 -レジスタの用途区分 ,From,To,本数,用途 ,00,==,1,予約済み(ベースポインタ)です。未実装なので使用できません。 ,01,1F,31,関数ローカルな汎用レジスタです。他の関数を呼び出しても値は破壊されません。 ,20,27,8,グローバルな汎用レジスタです。他の関数を呼び出すと、値が破壊されるかもしれません。アプリが自由に用途を決められます。 ,28,2F,8,グローバルな汎用レジスタです。他の関数を呼び出すと、値が破壊されるかもしれません。OSが用途を決めています。 ,30,3B,12,テンポラリレジスタです。汎用ではありますが、関数との引数・戻り値のやりとりや、ASKAにおける数式の計算に利用されるので値が破壊されやすいです。 ,3C,3E,3,Reserved. 将来の拡張のために予約されています。 ,3F,==,1,無条件分岐などの特殊用途に利用するもので、レジスタとして値を格納するのには使えません。(内部的には命令ポインタといえる?) ***ポインタタイプ -ポインタにはタイプ(データ型)があります。 -データ型の一致しないポインタの読み書きはセキュリティ違反になります。 ,typ32,型名,説明 ,0x00,Undefined, ,0x01,VPtr,プログラムコード領域? ,0x02,SINT8,signed char. ,0x03,UINT8, ,0x04,SINT16,short. ,0x05,UINT16, ,0x06,SINT32, ,0x07,UINT32, ,0x08,SINT4, ,0x09,UINT4, ,0x0A,SINT2, ,0x0B,UINT2, ,0x0C,SINT1,bool.代入できるのは0か-1のみ. ,0x0D,UINT1, ,0x0E,SINT12, ,0x0F,UINT12, ,0x10,SINT20, ,0x11,UINT20, ,0x12,SINT24, ,0x13,UINT24, ,0x14,SINT28, ,0x15,UINT28, **00:NOP 何もしない命令&aname(NOP); この命令は何もしません。JITコンパイラはこの命令を翻訳せず、実CPUに対してNOP命令は発行されません。 **01:LB ラベル定義命令&aname(LB); ,,1,2,3,4,5,6 ,LB,01,opt,imm32,==,==,== ラベルを定義します。OSECPUでは、ラベルの場所に対してのみ実行を転送できます。 ラベル番号は同一アプリケーション中で重複してはなりません。 -opt --0:local分岐先(ポインタレジスタ及びメモリに格納できない) --1:public分岐先(ポインタレジスタ及びメモリに格納できる) opt=1はopt=0に比べてリソースが消費されます。基本的にはopt=0を利用してください。 ラベル番号は本来は32ビットの任意の整数(負の数もOK)なのですが、現状の実装では0~4095までしか処理できません。すみません手抜きです。 **02:LIMM 定数即値代入命令 ,,1,2,3,4,5,6 ,LIMM,02,reg0R,imm32,==,==,== -reg0Rは00-3F全ての整数レジスタ番号が指定できます。 -imm32は符号付き32bit整数をビッグエンディアンで指定します。 **03:PLIMM ラベル番号代入命令 ,,1,2,3,4,5,6 ,PLIMM,03,reg0P,imm32,==,==,== -reg0Pは00-3F全ての整数レジスタ番号が指定できます。 -imm32は、ラベル番号を符号付き32bit整数、ビッグエンディアンで指定します。 **04:CND 条件実行プリフィックス ,,1,2, ,CND,04,reg0R,... -CNDは単体の命令ではなく、後続の1命令を条件実行命令化します。 --このプリフィクスをつけられないもの: ---CNDプリフィクスそれ自体 ---R3FへのLIMM -reg0Rには、R3F以外のR00-R3Eが指定できます。 -reg0R==0の場合、後続の1命令は実行されません。 -reg0R==1の場合、後続の1命令はそのまま実行されます。 **08,09:LMEM/SMEM メモリアクセス命令 ,,1,2,3,4,5,6,7,8 ,LMEM,08,reg0R,typ32,==,==,==,reg1P,00 ,SMEM,09,reg0R,typ32,==,==,==,reg1P,00 -メモリを読み書きします。 -typ32にはポインタタイプを指定します。 -LMEMの場合 --reg0R <- reg1P -SMEMの場合 --reg1P <- reg0R ***セキュリティ違反になる場合 -reg1Pのポインタタイプが「データ」でない場合。 -reg1Pのポインタタイプがtyp32と一致しない場合。 **0E:PADD メモリ加算命令 ,,1,2,3,4,5,6,7,8 ,PADD,0E,reg0P,typ32,==,==,==,reg1P,reg2R reg1Pのポインタ位置にreg2Rの値を加えた結果、指し示す位置のポインタをreg0Pに代入します。 ***セキュリティ違反になる場合 -reg1Pのポインタタイプが「データ」でない場合。 -reg1Pのポインタタイプがtyp32と一致しない場合。 **0F:PDIF メモリ差分命令 ,,1,2,3,4,5,6,7,8 ,PDIF,0F,reg0R,typ32,==,==,==,reg1P,reg2P reg0R = reg1P - reg2Pとなるよう、二つのポインタの差分をreg0Rに代入します。 ***セキュリティ違反になる場合 -reg1Pのポインタタイプが「データ」でない場合。 -reg1Pのポインタタイプがtyp32と一致しない場合。 **10-1B:CP/OR,XOR,AND,ADD,SUB,MUL,SHL,SAR,DIV,MOD 整数三項演算命令 ,,1,2,3,4 ,CP,10,reg0R,reg1R,FF ,OR,10,reg0R,reg1R,reg2R ,(other),OpCode,reg0R,reg1R,reg2R -OpCode ,,OR,XOR,AND,ADD,SUB,MUL,SHL,SAR,DIV,MOD ,OpCode,10,11,12,14,15,16,18,19,1A,1B -CP/ORは命令番号を共有しています --CP:4バイト目がFFの場合 --OR:4バイト目が00-3Fの整数レジスタ番号の場合 それぞれの動作は、上にある実装済みの命令表の説明を参照してください。 *実装済みのAPI -APIIDはR30に入る値。 ,APIID(R30),API名,...R31...,...R32...,...R33...,...R34...,...R35...,...R36...,説明 ,FF40,openWin, xSize, ySize,,,,, ,FF41,flushWin, xSize, ySize, x0, y0,,,終了時に自動で呼ばれる。 ,FF44,drawPoint, mode, x, y, col,,, ,FF45,drawLine, mode, x0, y0, x1, y1, col, ,FF46,fillRect, mode, xSize, ySize, x0, y0, col, ,FF47,fillOval, mode, xSize, ySize, x0, y0, col, *間違い等の指摘があればお願いします… -LB命令で「0:local分岐先(ポインタレジスタ『ただしPCを除く』、及びメモリに格納できない)」だと思う。 -- [[ttwilb]] SIZE(10){2014-03-24 (月) 17:06:46} #comment();