OSDN Git Service

AIのDB連携機能を実装中。
[chnosproject/AI004.git] / webcpu / webcpu.js
1 //WebCPUは、このディレクトリにあるファイルで完結している。
2
3 function WebCPU_Exception(errno, infoArray){
4         this.errno = errno;
5         this.infoArray = infoArray;
6 }
7 WebCPU_Exception.prototype = {
8         errorMessageList: [
9                 "Trap.",
10                 "Pre-compile error.",
11                 "Execution error.",
12         ],
13         getMessageString: function(){
14                 var s = "";
15                 s += "Error" + this.errno.toString().toUpperCase();
16                 if(this.errno < 0 || this.errorMessageList.length <= this.errno){
17                         s += ":Unknown\n";
18                 } else{
19                         s += ":" + this.errorMessageList[this.errno] + "\n";
20                 }
21                 if(this.infoArray){
22                         s += "  >" + this.infoArray.toString() + "\n";
23                 }
24                 return s;
25         },
26 }
27 // throw new WebCPU_Exception(2, [""]);
28
29 function WebCPU(){
30         //APIクラスインスタンス取得
31         this.API = new WebCPU_API();
32
33         //DOMオブジェクト連携
34         this.debugMessageText = null;
35         this.debugIntegerRegisterText = null;
36         this.debugPointerRegisterText = null;
37         //デバッグコンソール設定
38         this.debugMessageBuffer = "";
39         var that = this;
40         this.messageTimer = null;
41         
42         //メモリ
43         //メモリはラベルごとにページとして区切られ、それらの配列が一つのメモリとなる。
44         this.mainMemory = new WebCPU_Memory();
45         this.memoryPageCounter = 0;
46         this.memoryInstructionCounter = 0;
47         this.stopFlag = false;
48         
49         //レジスタ配列
50         this.registers = new Object;
51         this.registers.Integer = new Array(64);
52         
53         //初期化
54         this.reset();
55         
56         //命令リスト
57         this.instruction = new Array(0xFF + 1);
58         //命令テーブル初期化
59         for(var i = 0; i < this.instruction.length; i++){
60                 this.instruction[i] = WebCPU_Instruction_Undefined;
61         }
62         //
63         this.instruction[0x00] = WebCPU_Instruction_NOP;
64         this.instruction[0x01] = WebCPU_Instruction_LB;
65         this.instruction[0x02] = WebCPU_Instruction_LIMM;
66         this.instruction[0x03] = WebCPU_Instruction_PLIMM;
67         this.instruction[0x04] = WebCPU_Instruction_CND;
68         this.instruction[0x08] = WebCPU_Instruction_LMEM;
69         this.instruction[0x09] = WebCPU_Instruction_SMEM;
70         this.instruction[0x0E] = WebCPU_Instruction_PADD;
71         this.instruction[0x0F] = WebCPU_Instruction_PDIF;
72         //
73         this.instruction[0x10] = WebCPU_Instruction_TernaryOperation;
74         this.instruction[0x11] = WebCPU_Instruction_TernaryOperation;
75         this.instruction[0x12] = WebCPU_Instruction_TernaryOperation;
76         this.instruction[0x14] = WebCPU_Instruction_TernaryOperation;
77         this.instruction[0x15] = WebCPU_Instruction_TernaryOperation;
78         this.instruction[0x16] = WebCPU_Instruction_TernaryOperation;
79         this.instruction[0x18] = WebCPU_Instruction_TernaryOperation;
80         this.instruction[0x19] = WebCPU_Instruction_TernaryOperation;
81         this.instruction[0x1A] = WebCPU_Instruction_TernaryOperation;
82         this.instruction[0x1B] = WebCPU_Instruction_TernaryOperation;
83         //
84         this.instruction[0x1E] = WebCPU_Instruction_PCP;
85         //
86         this.instruction[0x20] = WebCPU_Instruction_TernaryOperation;
87         this.instruction[0x21] = WebCPU_Instruction_TernaryOperation;
88         this.instruction[0x22] = WebCPU_Instruction_TernaryOperation;
89         this.instruction[0x23] = WebCPU_Instruction_TernaryOperation;
90         this.instruction[0x24] = WebCPU_Instruction_TernaryOperation;
91         this.instruction[0x25] = WebCPU_Instruction_TernaryOperation;
92         this.instruction[0x26] = WebCPU_Instruction_TernaryOperation;
93         this.instruction[0x27] = WebCPU_Instruction_TernaryOperation;
94         //
95         this.instruction[0x28] = WebCPU_Instruction_TernaryOperation;
96         this.instruction[0x29] = WebCPU_Instruction_TernaryOperation;
97         this.instruction[0x2A] = WebCPU_Instruction_TernaryOperation;
98         this.instruction[0x2B] = WebCPU_Instruction_TernaryOperation;
99         this.instruction[0x2C] = WebCPU_Instruction_TernaryOperation;
100         this.instruction[0x2D] = WebCPU_Instruction_TernaryOperation;
101         //
102         this.instruction[0x32] = WebCPU_Instruction_MALLOC;
103         this.instruction[0x34] = WebCPU_Instruction_DATA;
104         //
105         this.instruction[0xFE] = WebCPU_Instruction_REMARK;
106         
107         this.message("<<< Initialized >>>\n");
108 }
109 WebCPU.prototype = {
110         loadBinaryText: function(binStr){
111                 //引数はフロントエンドコードのHex文字列も可能。(Not implemented.)
112                 //改行やスペースも含まれていてよい。
113                 //シグネチャも含まれていてよい
114                 binStr = replaceAll(binStr, " ", "");
115                 binStr = replaceAll(binStr, "\n", "");
116                 binStr = replaceAll(binStr, "\r", "");
117                 binStr = replaceAll(binStr, "\t", "");
118                 binStr = binStr.toUpperCase();
119                 if(binStr.substr(0, 4) == "05E1"){
120                         //シグネチャあり
121                         this.message("LoadBinaryText:OSECPU signature found.\n", 10);
122                         if(binStr.substr(4, 2) == "00"){
123                                 //BackEndCode
124                                 this.message("LoadBinaryText:This is BackEndCode.\n", 10);
125                                 binStr = binStr.substr(6);
126                         } else{
127                                 //FrontEndCode
128                                 this.message("LoadBinaryText:This is FrontEndCode.\n", 10);
129                                 binStr = binStr.substr(4);
130                                 this.loadFrontEndBinaryText(binStr);
131                                 return;
132                         }
133                 } else{
134                         this.message("LoadBinaryText:OSECPU signature NOT found.\n", 1);
135                 }
136                 this.loadBackEndBinaryText(binStr);
137         },
138         loadBackEndBinaryText: function(binStr){
139                 //引数はバックエンドコードのHex文字列表現でスペースなどの他の文字の混入は認められない。
140                 this.message("****LoadBackEndBinaryText****\n", 30);
141                 this.mainMemory.initMemory();
142                 this.memoryPageCounter = 0;
143                 this.memoryInstructionCounter = 0;
144                 
145                 try{
146                         for(var i = 0; i < binStr.length; ){
147                                 //命令解釈
148                                 var id = parseInt(binStr.substr(i, 2), 16);
149                                 i += 2;
150                                 var instr = new this.instruction[id](id);
151                                 instr.binOffset = (i >> 1) - 1;
152                                 var instrarglen = instr.loadArguments(binStr, i);
153                                 if(isNaN(parseInt(instrarglen))){
154                                         throw new WebCPU_Exception(1, ["Invalid instrarglen."]);
155                                 }
156                                 //instrarglenをバイト単位から文字列単位に変換し、さらに引数部分のみのサイズに補正する。
157                                 instrarglen = (instrarglen - 1) * 2;
158                                 //命令オペランド長チェック
159                                 if(instrarglen > binStr.length - i){
160                                         //オペランドの長さ分だけのバイナリがなかった、つまり不完全な状態で途切れている
161                                         throw new WebCPU_Exception(1, ["Invalid instrarglen."]);
162                                 }
163                                 i+= instrarglen;
164                                 
165                                 if(id == 0x01){
166                                         //ラベル命令だったのでメモリページを新たにする。
167                                         this.mainMemory.addMemoryPage(new WebCPU_MemoryPage());
168                                         this.memoryPageCounter++;
169                                         this.memoryInstructionCounter = 0;
170                                 }
171                                 
172                                 this.mainMemory.root[this.memoryPageCounter].addMemoryData(instr);
173                         }
174                 } catch(e){
175                         this.message("****LoadBackEndBinaryText Abort:\n", 1);
176                         if(e instanceof WebCPU_Exception){
177                                 this.message(e.getMessageString(), 1);
178                         } else{
179                                 throw e;
180                         }
181                         this.showDisassembledCode();
182                         this.mainMemory.initMemory();
183                         this.memoryPageCounter = 0;
184                         this.memoryInstructionCounter = 0;
185                 }
186                 this.showDisassembledCode();
187                 this.message("****LoadBackEndBinaryText End****\n", 30);
188                 
189                 this.memoryPageCounter = 0;
190                 this.memoryInstructionCounter = 0;
191                 this.reset();
192         },
193         loadFrontEndBinaryText: function(binStr){
194                 //引数はフロントエンドコードのHex文字列表現でスペースなどの他の文字の混入は認められない。
195                 this.message("****LoadFrontEndBinaryText****\n", 40);
196                 this.mainMemory.initMemory();
197                 this.memoryPageCounter = 0;
198                 this.memoryInstructionCounter = 0;
199                 //フロントエンドコードデコーダーの読み込み
200                 this.loadBinaryText(decoderBinaryString);
201                 //変換準備
202                 var backendMaxSize = 65535;
203                 var temp0MaxSize = 2 * 1024 * 1024;
204                 var temp1MaxSize = 16 * 1024;
205                 var temp2MaxSize = 64;
206                 var temp3MaxSize = 4 * 1024 + 1;
207                 var temp4MaxSize = 256;
208                 var m;
209                 //P02 = T_UINT8:  &backend[2] (出力バッファ先頭)
210                 m = this.mainMemory.allocateMemoryPage(WebCPU.pType.UINT8, backendMaxSize);
211                 this.registers.Pointer[0x02] = new WebCPU_Pointer(m);
212                 //P03 = T_UINT8:  &backend[backend-maxsize] (出力バッファの限界)
213                 this.registers.Pointer[0x03] = this.registers.Pointer[0x02].getCopy();
214                 this.registers.Pointer[0x03].addressOffset = backendMaxSize;
215                 //P04 = T_UINT8:  &frontend[2] (入力データ先頭)
216                 m = this.mainMemory.allocateMemoryPage(WebCPU.pType.UINT8);
217                 this.registers.Pointer[0x04] = new WebCPU_Pointer(m);
218                 this.registers.Pointer[0x04].addressOffset = 0;
219                 this.registers.Pointer[0x04].memoryPage.data[1].data = new Array();
220                 var a = this.registers.Pointer[0x04].memoryPage.data[1].data;
221                 var i;
222                 for(i = 0; i * 2 < binStr.length; i++){
223                         a.push(parseInt(binStr.substr(i * 2, 2), 16));
224                 }
225                 //P05 = T_UINT8:  &frontend[frontend-size] (入力データの終端:最終バイトの次のアドレス)
226                 this.registers.Pointer[0x05] = this.registers.Pointer[0x04].getCopy();
227                 this.registers.Pointer[0x05].addressOffset = i;
228                 //P06 = T_UINT8:  &temp0[0] (要素数が2M以上のテンポラリバッファ)
229                 m = this.mainMemory.allocateMemoryPage(WebCPU.pType.UINT8, temp0MaxSize);
230                 this.registers.Pointer[0x06] = new WebCPU_Pointer(m);
231                 //P07 = T_UINT8:  &temp0[temp-maxsize]
232                 this.registers.Pointer[0x07] = this.registers.Pointer[0x06].getCopy();
233                 this.registers.Pointer[0x07].addressOffset = temp0MaxSize;
234                 //P0A = T_UINT32: &temp1[0] (要素数が16Kくらいあれば十分なバッファ)
235                 m = this.mainMemory.allocateMemoryPage(WebCPU.pType.UINT32, temp1MaxSize);
236                 this.registers.Pointer[0x0A] = new WebCPU_Pointer(m);
237                 //P0B = T_SINT32: &temp2[0] (要素数が64のバッファ:Pxxレジスタの個数)
238                 m = this.mainMemory.allocateMemoryPage(WebCPU.pType.SINT32, temp2MaxSize);
239                 this.registers.Pointer[0x0B] = new WebCPU_Pointer(m);
240                 //P0C = T_SINT32: &temp3[0] (要素数が4Kのバッファ:登録可能ラベル数)
241                 m = this.mainMemory.allocateMemoryPage(WebCPU.pType.SINT32, temp3MaxSize);
242                 this.registers.Pointer[0x0C] = new WebCPU_Pointer(m);
243                 //P0D = T_UINT8:  &temp4[0] (要素数が256のバッファ)
244                 m = this.mainMemory.allocateMemoryPage(WebCPU.pType.UINT8, temp4MaxSize);
245                 this.registers.Pointer[0x0D] = new WebCPU_Pointer(m);
246                 //変換
247                 this.execute();
248                 /*
249                 P02 == バックエンドコードの終端, つまり P02 - &backend[0] = バックエンドコードのサイズ
250                 */
251                 if(this.registers.Integer[0x00] == 0){
252                         //R00 == 0 正常終了
253                         var binData = this.registers.Pointer[0x02].memoryPage.data[1];
254                         var binStr = "";
255                         for(var i = 0; i < this.registers.Pointer[0x02].addressOffset; i++){
256                                 binStr += ("00" + binData.data[i].toString(16)).slice(-2);
257                         }
258                         this.message("[" + binStr + "](" + (binStr.length >> 1) + "Bytes)\n");
259                         this.loadBackEndBinaryText(binStr);
260                         this.reset();
261                 } else{
262                         //R00 != 0 変換失敗
263                         this.message("loadFrontEndBinaryText: Translate failed.\n");
264                 }
265                 
266                 this.message("****LoadFrontEndBinaryText End****\n", 40);
267         },
268         executeStepIn: function(){
269                 //ステップ実行する。
270                 //一回実行するたびに再描画する。
271                 var retv = this.executeStepIn_Internal(true);
272                 this.API.API_flushWin(this, this.API.mainWindowCanvas.width, this.API.mainWindowCanvas.height, 0, 0);
273                 return retv;
274         },
275         executeStepIn_Internal: function(isManualStepIn){
276                 //ステップ実行の内部部分。
277                 //終端到達時は1を、まだ後続命令がある場合は0を返す。
278                 //終了時にのみ再描画を行う
279                 if(this.stopFlag){
280                         this.message(">stepIn:Break.\n", 2);
281                         this.stopFlag = false;
282                         this.API.API_flushWin(this, this.API.mainWindowCanvas.width, this.API.mainWindowCanvas.height, 0, 0);
283                         return 2;
284                 }
285                 var instr = this.fetchMemoryNext();
286                 if(instr === undefined){
287                         this.message(">stepIn:control reached end of binary.\n", 2);
288                         this.API.API_flushWin(this, this.API.mainWindowCanvas.width, this.API.mainWindowCanvas.height, 0, 0);
289                         return 1;
290                 }
291                 if(isManualStepIn){
292                         this.message(">stepIn:" + this.memoryPageCounter + "-" + (this.memoryInstructionCounter - 1) + ":" + instr.toString() + "\n", 20);
293                 }
294                 instr.execute(this);
295                 //これ以降this.memoryInstructionCounterが今実行した命令を指すとは限らない。(JMP系命令のため)
296                 /*
297                 //ブレークポイント
298                 if(this.memoryPageCounter == 233 && this.memoryInstructionCounter == 0){
299                         this.message(">stepIn:Breakpoint.\n", 2);
300                         return 3;
301                 }
302                 */
303                 return 0;
304         },
305         execute: function(){
306                 //最速で実行する
307                 for(;;){
308                         if(this.executeStepIn_Internal(false) != 0){
309                                 return;
310                         }
311                 }
312         },
313         reset: function(){
314                 //実行環境をリセットする。メモリ内容は保持される。
315                 for(var i = 0; i < this.registers.Integer.length; i++){
316                         this.registers.Integer[i] = 0;
317                 }
318                 this.registers.Pointer = new Array(64);
319                 for(var i = 0; i < this.registers.Pointer.length; i++){
320                         this.registers.Pointer[i] = new WebCPU_Pointer(null);
321                 }
322                 //Set P28 for API  calling.
323                 this.registers.Pointer[0x28].memoryType = 0xC0FFEE;
324                 //
325                 this.memoryPageCounter = 0;
326                 this.memoryInstructionCounter = 0;
327                 this.stopFlag = false;
328                 //reset window
329                 if(this.API.mainWindowCanvas){
330                         this.API.setMainWindowCanvasDOMObject(this.API.mainWindowCanvas);
331                 }
332                 this.message("<<< Reset >>>\n");
333         },
334         fetchMemoryNext: function(){
335                 if(this.mainMemory.root[this.memoryPageCounter].data.length <= this.memoryInstructionCounter){
336                         this.memoryPageCounter++;
337                         if(this.mainMemory.root.length <= this.memoryPageCounter){
338                                 this.memoryPageCounter--;
339                                 return undefined;
340                         }
341                         this.memoryInstructionCounter -= this.mainMemory.root[this.memoryPageCounter - 1].data.length;
342                 }
343                 var retv = this.mainMemory.root[this.memoryPageCounter].data[this.memoryInstructionCounter];
344                 this.memoryInstructionCounter++;
345                 return retv;
346         },
347         setMainWindowCanvasDOMObject: function(id){
348                 this.API.setMainWindowCanvasDOMObject(document.getElementById(id));
349         },
350         setDebugMessageDOMObject: function(name){
351                 if(name){
352                         this.debugMessageText = document.getElementsByName(name)[0];
353                         if(!this.debugMessageText){
354                                 this.debugMessageText = document.getElementById(name);
355                         }
356                 } else{
357                         this.debugMessageText = null;
358                 }
359                 this.setDebugTimer();
360         },
361         setDebugIntegerRegisterDOMObject: function(name){
362                 if(name){
363                         this.debugIntegerRegisterText = document.getElementsByName(name)[0];
364                         if(!this.debugIntegerRegisterText){
365                                 this.debugIntegerRegisterText = document.getElementById(name);
366                         }
367                 } else{
368                         this.debugIntegerRegisterText = null;
369                 }
370                 this.setDebugTimer();
371         },
372         setDebugPointerRegisterDOMObject: function(name){
373                 this.debugPointerRegisterText = document.getElementsByName(name)[0];
374                 if(name){
375                         this.debugPointerRegisterText = document.getElementsByName(name)[0];
376                         if(!this.debugPointerRegisterText){
377                                 this.debugPointerRegisterText = document.getElementById(name);
378                         }
379                 } else{
380                         this.debugPointerRegisterText = null;
381                 }
382                 this.setDebugTimer();
383         },
384         setDebugTimer: function(){
385                 if(!this.debugMessageText && !this.debugIntegerRegisterText && !this.debugPointerRegisterText){
386                         //すべて無効だったらタイマーの動作自体を止める
387                         window.clearTimeout(this.messageTimer);
388                         this.messageTimer = null;
389                         WebCPU_Instruction.prototype.isEnabledPrintSourceRegister = false;
390                         WebCPU_Instruction.prototype.isEnabledPrintDestinationRegister = false;
391                 } else if(!this.messageTimer){
392                         //どれかが有効でかつタイマーが止まっていたらスタートさせる
393                         var that = this;
394                         this.messageTimer = window.setInterval(function(){that.debugShowTick();}, 50);
395                         WebCPU_Instruction.prototype.isEnabledPrintSourceRegister = true;
396                         WebCPU_Instruction.prototype.isEnabledPrintDestinationRegister = true;
397                 }
398         },
399         debugShowTick: function(){
400                 if(this.debugMessageText && this.debugMessageBuffer != ""){
401                         var str = this.debugMessageText.value + this.debugMessageBuffer;
402                         this.debugMessageBuffer = "";
403                         if(str.length > WebCPU.maxDebugStringLength){
404                                 str = str.slice(str.length - (WebCPU.maxDebugStringLength >> 1));
405                         }
406                         this.debugMessageText.value = str;
407                         this.debugMessageText.scrollTop = this.debugMessageText.scrollHeight;
408                 }
409                 this.refreshDebugIntegerRegisterText();
410                 this.refreshDebugPointerRegisterText();
411         },
412         message: function(str, id){
413                 //id:メッセージの種類
414                 //省略:常に表示する
415                 //1:Error
416                 //2:Warning
417                 //10:バイナリ読み込みデバッグ
418                 //20:実行時詳細情報
419                 //30:バックエンドバイナリ読み込みデバッグ
420                 //40:フロントエンドバイナリ読み込みデバッグ
421                 if(this.debugMessageText != null){
422                         if(
423                                 true ||
424                                 id == 1 || 
425                                 id == 2 || 
426                                 id == 30
427                         ){
428                                 this.debugMessageBuffer += str;
429                         }
430                 } else if(id == 1){
431                         //エラーのときmessageが無効であればalertで表示する。
432                         window.alert(str);
433                 }
434         },
435         showDisassembledCode: function(){
436                 for(var i = 0; i < this.mainMemory.root.length; i++){
437                         for(var j = 0; j < this.mainMemory.root[i].data.length; j++){
438                                 var instr = this.mainMemory.root[i].data[j];
439                                 this.message("+0x" + instr.binOffset.toString(16).toUpperCase() + ":" + i + "-" + j + ":" + instr.toString() + "\n", 30);
440                         }
441                         this.message(" - - - - \n", 30);
442                 }
443         },
444         showIntegerRegister: function(){
445                 for(var i = 0; i < this.registers.Integer.length; i++){
446                         this.message("R" +  ("00" + i.toString(16)).slice(-2).toUpperCase() + ":0x" + this.registers.Integer[i].toString(16).toUpperCase() + "\n");
447                 }
448         },
449         showPointerRegister: function(){
450                 for(var i = 0; i < this.registers.Pointer.length; i++){
451                         if(this.registers.Pointer[i]){
452                                 this.message("P" +  ("00" + i.toString(16)).slice(-2).toUpperCase() + ":" + this.registers.Pointer[i].toString() + "\n");
453                         } else{
454                                 this.message("P" +  ("00" + i.toString(16)).slice(-2).toUpperCase() + ":(null)\n");
455                         }
456                 }
457         },
458         refreshDebugIntegerRegisterText: function(){
459                 if(this.debugIntegerRegisterText != null){
460                         this.debugIntegerRegisterText.value = "";
461                         for(var i = 0; i < this.registers.Integer.length; i++){
462                                 this.debugIntegerRegisterText.value += "R" +  ("00" + i.toString(16)).slice(-2).toUpperCase() + ":0x" + this.registers.Integer[i].toString(16).toUpperCase() + "\n";
463                         }
464                 }
465         },
466         refreshDebugPointerRegisterText: function(){
467                 if(this.debugPointerRegisterText != null){
468                         this.debugPointerRegisterText.value = "";
469                         for(var i = 0; i < this.registers.Pointer.length; i++){
470                                 if(this.registers.Pointer[i]){
471                                         this.debugPointerRegisterText.value += "P" +  ("00" + i.toString(16)).slice(-2).toUpperCase() + ":" + this.registers.Pointer[i].toString() + "\n";
472                                 } else{
473                                         this.debugPointerRegisterText.value += "P" +  ("00" + i.toString(16)).slice(-2).toUpperCase() + ":(null)\n";
474                                 }
475                         }
476                 }
477         },
478         goToPointerRegister: function(reg0P){
479                 //レジスタはいじらない
480                 //goto
481                 var p = this.registers.Pointer[reg0P];
482                 if(p.memoryType == 1){
483                         //VPtr
484                         this.memoryPageCounter = this.mainMemory.getMemoryPageCountFromMemoryPageInstance(p.memoryPage);
485                         if(this.memoryPageCounter !== undefined){
486                                 this.memoryInstructionCounter = 0;
487                                 this.message("JMP:page " + this.memoryPageCounter + "\n", 20);
488                         } else{
489                                 throw new WebCPU_Exception(2, ["memoryPage not found in mainMemory."]);
490                         }
491                 } else{
492                         throw new WebCPU_Exception(2, ["Can't goto Memory page type is not VPtr."]);
493                 }
494         },
495         createBackendBinaryString: function(){
496                 var s = "05E100";
497                 var instr;
498                 
499                 this.reset();
500                 for(;;){
501                         instr = this.fetchMemoryNext();
502                         if(instr === undefined){
503                                 break;
504                         }
505                         s += instr.createBinaryString(this);
506                 }
507                 return s;
508         },
509         staticOptimize: function(){
510                 //静的最適化
511                 this.staticOptimize_RemoveDuplicatedLabelNumber();
512                 this.staticOptimize_CMPxx_CND_PLIMM_PLIMM_LB();
513                 this.staticOptimize_RemoveUnusedLabelNumber();
514         },
515         staticOptimize_RemoveDuplicatedLabelNumber: function(){
516                 //連続するラベル命令の削除
517                 //一つのメモリページにラベル命令のみがある場合は、それを次のメモリページのラベル名に置換する
518                 var mpage;
519                 var removePageIndexStack = new Array();
520                 var labelIDStack = new Array();
521                 var labelID;
522                 var newLabelID;
523                 for(var i = 0; i < this.mainMemory.root.length; i++){
524                         mpage = this.mainMemory.root[i];
525                         if(mpage instanceof WebCPU_MemoryPage && mpage.data[0] instanceof WebCPU_Instruction_LB){
526                                 //メモリページ
527                                 if(mpage.data.length == 1){
528                                         //ラベルしかないので削除候補に追加
529                                         labelIDStack.push(mpage.data[0].imm32);
530                                         removePageIndexStack.push(i);
531                                 } else{
532                                         //これは必要なラベル命令
533                                         if(labelIDStack.length != 0){
534                                                 for(;;){
535                                                         labelID = labelIDStack.pop();
536                                                         if(labelID == undefined){
537                                                                 break;
538                                                         }
539                                                         this.mainMemory.root.splice(removePageIndexStack[0], 1);
540                                                         i--;
541                                                         this.staticOptimize_ReplaceLabelNumber(labelID, mpage.data[0].imm32);
542                                                 }
543                                                 removePageIndexStack = new Array();
544                                         }
545                                 }
546                         }
547                 }
548                 if(labelIDStack.length != 0){
549                         //プログラム末尾のラベル命令は削除しない。
550                         newLabelID = labelIDStack.pop();
551                         for(;;){
552                                 labelID = labelIDStack.pop();
553                                 if(labelID == undefined){
554                                         break;
555                                 }
556                                 this.mainMemory.root.splice(removePageIndexStack[0], 1);
557                                 i--;
558                                 this.staticOptimize_ReplaceLabelNumber(labelID, newLabelID);
559                         }
560                 }
561         },
562         staticOptimize_ReplaceLabelNumber: function(from, to){
563                 //PLIMM命令のラベル番号がfromのものをtoに変更する。
564                 var mpage;
565                 var instr;
566                 for(var i = 0, iLen = this.mainMemory.root.length; i < iLen; i++){
567                         mpage = this.mainMemory.root[i];
568                         for(var j = 0, jLen = mpage.data.length; j < jLen; j++){
569                                 instr = mpage.data[j];
570                                 if(instr instanceof WebCPU_Instruction_PLIMM){
571                                         if(instr.imm32 == from){
572                                                 instr.imm32 = to;
573                                         }
574                                 }
575                         }
576                 }
577         },
578         staticOptimize_RemoveUnusedLabelNumber: function(){
579                 var usedLabelNumberList = new Array();
580                 var mpage;
581                 var instr;
582                 //使われているラベル番号のリスト生成
583                 for(var i = 0, iLen = this.mainMemory.root.length; i < iLen; i++){
584                         mpage = this.mainMemory.root[i];
585                         for(var j = 0, jLen = mpage.data.length; j < jLen; j++){
586                                 instr = mpage.data[j];
587                                 if(instr instanceof WebCPU_Instruction_PLIMM){
588                                         usedLabelNumberList.pushUnique(instr.imm32);
589                                 }
590                         }
591                 }
592                 //ラベルを走査し、不要なラベル番号を削除
593                 for(var i = 0; i < this.mainMemory.root.length; i++){
594                         mpage = this.mainMemory.root[i];
595                         if(mpage instanceof WebCPU_MemoryPage && mpage.data[0] instanceof WebCPU_Instruction_LB){
596                                 if(mpage.data[0].opt == 1 || usedLabelNumberList.isIncluded(mpage.data[0].imm32)){
597                                         //使われている、もしくはグローバルなラベル番号
598                                 } else{
599                                         //未参照のローカルラベル番号
600                                         //ひとまずラベル命令削除
601                                         mpage.data.splice(0, 1);
602                                         if(i != 0){
603                                                 //一つ前のページに統合
604                                                 this.mainMemory.root[i - 1].data = this.mainMemory.root[i - 1].data.concat(mpage.data);
605                                                 //このページを削除
606                                                 this.mainMemory.root.splice(i, 1);
607                                                 i--;
608                                         }
609                                 }
610                         }
611                 }
612         },
613         staticOptimize_CMPxx_CND_PLIMM_PLIMM_LB: function(){
614                 //From:
615                 //>CMPxx(Ra, --, --);
616                 //CND(Ra);
617                 //>PLIMM(P3F, b);
618                 //PLIMM(P3F, --);
619                 //----
620                 //LB(opt:--, b);
621                 //
622                 //To:
623                 //>CMP!(xx)(Ra, --, --);
624                 //CND(Ra);
625                 //PLIMM(P3F, --);
626                 //----
627                 //LB(opt:--, b);
628                 
629                 //これより後にstaticOptimize_RemoveUnusedLabelNumberを実行することを推奨する。
630                 //CMP系命令は、InstrIDが偶数の場合+1, 奇数の場合-1することで逆の条件になる。
631                 //CMP系:20-2D
632                 var mode = 0;
633                 var rega;
634                 var immb;
635                 //0:次は CMPxx(Ra, --, --);
636                 //1:次は CND(Ra);
637                 //2:次は PLIMM(P3F, b);
638                 //3:次は PLIMM(P3F, --);
639                 //4:次は LB(opt:--, b);
640                 for(var i = 0, iLen = this.mainMemory.root.length; i < iLen; i++){
641                         mpage = this.mainMemory.root[i];
642                         for(var j = 0, jLen = mpage.data.length; j < jLen; j++){
643                                 instr = mpage.data[j];
644                                 switch(mode){
645                                         case 0:
646                                                 if(instr instanceof WebCPU_Instruction_TernaryOperation && 0x20 <= instr.instrID && instr.instrID <= 0x2D){
647                                                         //CMPxx(Ra, --, --);
648                                                         rega = instr.reg0;
649                                                         mode++;
650                                                 }
651                                                 break;
652                                         case 1:
653                                                 if(instr instanceof WebCPU_Instruction_CND && instr.reg0R == rega){
654                                                         //CND(Ra);
655                                                         mode++;
656                                                 } else{
657                                                         mode = 0;
658                                                 }
659                                                 break;
660                                         case 2:
661                                                 if(instr instanceof WebCPU_Instruction_PLIMM && instr.reg0 == 0x3f){
662                                                         //PLIMM(P3F, b);
663                                                         immb = instr.imm32;
664                                                         mode++;
665                                                 } else{
666                                                         mode = 0;
667                                                 }
668                                                 break;
669                                         case 3:
670                                                 if(instr instanceof WebCPU_Instruction_PLIMM && instr.reg0 == 0x3f){
671                                                         //PLIMM(P3F, --);
672                                                         mode++;
673                                                 } else{
674                                                         mode = 0;
675                                                 }
676                                                 break;
677                                         case 4:
678                                                 if(instr instanceof WebCPU_Instruction_LB && instr.imm32 == immb){
679                                                         //LB(opt:--, b);
680                                                         //置換対象確定
681                                                         mpage = this.mainMemory.root[i - 1];
682                                                         //CMPxx(Ra, --, --); -> CMP!(xx)(Ra, --, --);
683                                                         instr = mpage.data[mpage.data.length - 4];
684                                                         if((instr.instrID & 0x01) == 0){
685                                                                 instr.instrID++;
686                                                         } else{
687                                                                 instr.instrID--;
688                                                         }
689                                                         instr.setParameter(instr.reg0, instr.reg1, instr.reg2);
690                                                         //Remove PLIMM(P3F, b);
691                                                         mpage.data.splice(mpage.data.length - 2, 1);
692                                                 }
693                                                 mode = 0;
694                                                 break;
695                                 }
696                         }
697                 }
698         },
699 }
700
701 //数値計算
702 function parseSignedInt32(hexStr){
703         //文字列を16進32bit符号あり整数として変換する。
704         var i = parseInt(hexStr, 16);
705         if(i > 0x7fffffff){
706                 //-
707                 return -(~i + 1);
708         }
709         //+
710         return i;
711 }
712
713 function parseSignedInt(hexStr, bits){
714         //文字列を16進符号あり整数として変換する。
715         //32bitまで対応
716         var i = parseInt(hexStr, 16);
717         if(i >= (1 << (bits - 1))){
718                 //-
719                 return -(((0xffffffff >>> (32 - bits)) - i) + 1);
720         }
721         //+
722         return i;
723 }
724
725 function toHexString8(v){
726         return ("00" + v.toString(16).toUpperCase()).slice(-2);
727 }
728
729 function toHexString32(v){
730         if(v < 0){
731                 v = 0x100000000 + v;
732         }
733         return ("00000000" + v.toString(16).toUpperCase()).slice(-8);
734 }
735
736 function replaceAll(str, org, dest){
737         //文字列str中にある文字列orgを文字列destにすべて置換する。
738         //http://www.syboos.jp/webjs/doc/string-replace-and-replaceall.html
739         return str.split(org).join(dest);
740 }