1 function WebCPU_Exception(errno, infoArray){
3 this.infoArray = infoArray;
5 WebCPU_Exception.prototype = {
11 getMessageString: function(){
13 s += "Error" + this.errno.toString().toUpperCase();
14 if(this.errno < 0 || this.errorMessageList.length <= this.errno){
17 s += ":" + this.errorMessageList[this.errno] + "\n";
20 s += " >" + this.infoArray.toString() + "\n";
25 // throw new WebCPU_Exception(2, [""]);
29 this.API = new WebCPU_API();
32 this.debugMessageText = null;
33 this.debugIntegerRegisterText = null;
34 this.debugPointerRegisterText = null;
36 this.debugMessageBuffer = "";
38 this.messageTimer = null;
41 //メモリはラベルごとにページとして区切られ、それらの配列が一つのメモリとなる。
42 this.mainMemory = new WebCPU_Memory();
43 this.memoryPageCounter = 0;
44 this.memoryInstructionCounter = 0;
45 this.stopFlag = false;
48 this.registers = new Object;
49 this.registers.Integer = new Array(64);
55 this.instruction = new Array(0xFF + 1);
57 for(var i = 0; i < this.instruction.length; i++){
58 this.instruction[i] = WebCPU_Instruction_Undefined;
61 this.instruction[0x00] = WebCPU_Instruction_NOP;
62 this.instruction[0x01] = WebCPU_Instruction_LB;
63 this.instruction[0x02] = WebCPU_Instruction_LIMM;
64 this.instruction[0x03] = WebCPU_Instruction_PLIMM;
65 this.instruction[0x04] = WebCPU_Instruction_CND;
66 this.instruction[0x08] = WebCPU_Instruction_LMEM;
67 this.instruction[0x09] = WebCPU_Instruction_SMEM;
68 this.instruction[0x0E] = WebCPU_Instruction_PADD;
69 this.instruction[0x0F] = WebCPU_Instruction_PDIF;
71 this.instruction[0x10] = WebCPU_Instruction_TernaryOperation;
72 this.instruction[0x11] = WebCPU_Instruction_TernaryOperation;
73 this.instruction[0x12] = WebCPU_Instruction_TernaryOperation;
74 this.instruction[0x14] = WebCPU_Instruction_TernaryOperation;
75 this.instruction[0x15] = WebCPU_Instruction_TernaryOperation;
76 this.instruction[0x16] = WebCPU_Instruction_TernaryOperation;
77 this.instruction[0x18] = WebCPU_Instruction_TernaryOperation;
78 this.instruction[0x19] = WebCPU_Instruction_TernaryOperation;
79 this.instruction[0x1A] = WebCPU_Instruction_TernaryOperation;
80 this.instruction[0x1B] = WebCPU_Instruction_TernaryOperation;
82 this.instruction[0x1E] = WebCPU_Instruction_PCP;
84 this.instruction[0x20] = WebCPU_Instruction_TernaryOperation;
85 this.instruction[0x21] = WebCPU_Instruction_TernaryOperation;
86 this.instruction[0x22] = WebCPU_Instruction_TernaryOperation;
87 this.instruction[0x23] = WebCPU_Instruction_TernaryOperation;
88 this.instruction[0x24] = WebCPU_Instruction_TernaryOperation;
89 this.instruction[0x25] = WebCPU_Instruction_TernaryOperation;
90 this.instruction[0x26] = WebCPU_Instruction_TernaryOperation;
91 this.instruction[0x27] = WebCPU_Instruction_TernaryOperation;
93 this.instruction[0x28] = WebCPU_Instruction_TernaryOperation;
94 this.instruction[0x29] = WebCPU_Instruction_TernaryOperation;
95 this.instruction[0x2A] = WebCPU_Instruction_TernaryOperation;
96 this.instruction[0x2B] = WebCPU_Instruction_TernaryOperation;
97 this.instruction[0x2C] = WebCPU_Instruction_TernaryOperation;
98 this.instruction[0x2D] = WebCPU_Instruction_TernaryOperation;
100 this.instruction[0x32] = WebCPU_Instruction_MALLOC;
101 this.instruction[0x34] = WebCPU_Instruction_DATA;
103 this.instruction[0xFE] = WebCPU_Instruction_REMARK;
105 this.message("<<< Initialized >>>\n");
108 loadBinaryText: function(binStr){
109 //引数はフロントエンドコードのHex文字列も可能。(Not implemented.)
112 binStr = replaceAll(binStr, " ", "");
113 binStr = replaceAll(binStr, "\n", "");
114 binStr = replaceAll(binStr, "\r", "");
115 binStr = replaceAll(binStr, "\t", "");
116 binStr = binStr.toUpperCase();
117 if(binStr.substr(0, 4) == "05E1"){
119 this.message("LoadBinaryText:OSECPU signature found.\n", 10);
120 if(binStr.substr(4, 2) == "00"){
122 this.message("LoadBinaryText:This is BackEndCode.\n", 10);
123 binStr = binStr.substr(6);
126 this.message("LoadBinaryText:This is FrontEndCode.\n", 10);
127 binStr = binStr.substr(4);
128 this.loadFrontEndBinaryText(binStr);
132 this.message("LoadBinaryText:OSECPU signature NOT found.\n", 1);
134 this.loadBackEndBinaryText(binStr);
136 loadBackEndBinaryText: function(binStr){
137 //引数はバックエンドコードのHex文字列表現でスペースなどの他の文字の混入は認められない。
138 this.message("****LoadBackEndBinaryText****\n", 30);
139 this.mainMemory.initMemory();
140 this.memoryPageCounter = 0;
141 this.memoryInstructionCounter = 0;
144 for(var i = 0; i < binStr.length; ){
146 var id = parseInt(binStr.substr(i, 2), 16);
148 var instr = new this.instruction[id](id);
149 instr.binOffset = (i >> 1) - 1;
150 var instrarglen = instr.loadArguments(binStr, i);
151 if(isNaN(parseInt(instrarglen))){
152 throw new WebCPU_Exception(1, ["Invalid instrarglen."]);
154 //instrarglenをバイト単位から文字列単位に変換し、さらに引数部分のみのサイズに補正する。
155 instrarglen = (instrarglen - 1) * 2;
157 if(instrarglen > binStr.length - i){
158 //オペランドの長さ分だけのバイナリがなかった、つまり不完全な状態で途切れている
159 throw new WebCPU_Exception(1, ["Invalid instrarglen."]);
164 //ラベル命令だったのでメモリページを新たにする。
165 this.mainMemory.addMemoryPage(new WebCPU_MemoryPage());
166 this.memoryPageCounter++;
167 this.memoryInstructionCounter = 0;
170 this.mainMemory.root[this.memoryPageCounter].addMemoryData(instr);
173 this.message("****LoadBackEndBinaryText Abort:\n", 1);
174 if(e instanceof WebCPU_Exception){
175 this.message(e.getMessageString(), 1);
179 this.showDisassembledCode();
180 this.mainMemory.initMemory();
181 this.memoryPageCounter = 0;
182 this.memoryInstructionCounter = 0;
184 this.showDisassembledCode();
185 this.message("****LoadBackEndBinaryText End****\n", 30);
187 this.memoryPageCounter = 0;
188 this.memoryInstructionCounter = 0;
190 loadFrontEndBinaryText: function(binStr){
191 //引数はフロントエンドコードのHex文字列表現でスペースなどの他の文字の混入は認められない。
192 this.message("****LoadFrontEndBinaryText****\n", 40);
193 this.mainMemory.initMemory();
194 this.memoryPageCounter = 0;
195 this.memoryInstructionCounter = 0;
196 //フロントエンドコードデコーダーの読み込み
197 this.loadBinaryText(decoderBinaryString);
199 var backendMaxSize = 65535;
200 var temp0MaxSize = 2 * 1024 * 1024;
201 var temp1MaxSize = 16 * 1024;
202 var temp2MaxSize = 64;
203 var temp3MaxSize = 4 * 1024 + 1;
204 var temp4MaxSize = 256;
206 //P02 = T_UINT8: &backend[2] (出力バッファ先頭)
207 m = this.mainMemory.allocateMemoryPage(WebCPU.pType.UINT8, backendMaxSize);
208 this.registers.Pointer[0x02] = new WebCPU_Pointer(m);
209 //P03 = T_UINT8: &backend[backend-maxsize] (出力バッファの限界)
210 this.registers.Pointer[0x03] = this.registers.Pointer[0x02].getCopy();
211 this.registers.Pointer[0x03].addressOffset = backendMaxSize;
212 //P04 = T_UINT8: &frontend[2] (入力データ先頭)
213 m = this.mainMemory.allocateMemoryPage(WebCPU.pType.UINT8);
214 this.registers.Pointer[0x04] = new WebCPU_Pointer(m);
215 this.registers.Pointer[0x04].addressOffset = 0;
216 this.registers.Pointer[0x04].memoryPage.data[1].data = new Array();
217 var a = this.registers.Pointer[0x04].memoryPage.data[1].data;
219 for(i = 0; i * 2 < binStr.length; i++){
220 a.push(parseInt(binStr.substr(i * 2, 2), 16));
222 //P05 = T_UINT8: &frontend[frontend-size] (入力データの終端:最終バイトの次のアドレス)
223 this.registers.Pointer[0x05] = this.registers.Pointer[0x04].getCopy();
224 this.registers.Pointer[0x05].addressOffset = i;
225 //P06 = T_UINT8: &temp0[0] (要素数が2M以上のテンポラリバッファ)
226 m = this.mainMemory.allocateMemoryPage(WebCPU.pType.UINT8, temp0MaxSize);
227 this.registers.Pointer[0x06] = new WebCPU_Pointer(m);
228 //P07 = T_UINT8: &temp0[temp-maxsize]
229 this.registers.Pointer[0x07] = this.registers.Pointer[0x06].getCopy();
230 this.registers.Pointer[0x07].addressOffset = temp0MaxSize;
231 //P0A = T_UINT32: &temp1[0] (要素数が16Kくらいあれば十分なバッファ)
232 m = this.mainMemory.allocateMemoryPage(WebCPU.pType.UINT32, temp1MaxSize);
233 this.registers.Pointer[0x0A] = new WebCPU_Pointer(m);
234 //P0B = T_SINT32: &temp2[0] (要素数が64のバッファ:Pxxレジスタの個数)
235 m = this.mainMemory.allocateMemoryPage(WebCPU.pType.SINT32, temp2MaxSize);
236 this.registers.Pointer[0x0B] = new WebCPU_Pointer(m);
237 //P0C = T_SINT32: &temp3[0] (要素数が4Kのバッファ:登録可能ラベル数)
238 m = this.mainMemory.allocateMemoryPage(WebCPU.pType.SINT32, temp3MaxSize);
239 this.registers.Pointer[0x0C] = new WebCPU_Pointer(m);
240 //P0D = T_UINT8: &temp4[0] (要素数が256のバッファ)
241 m = this.mainMemory.allocateMemoryPage(WebCPU.pType.UINT8, temp4MaxSize);
242 this.registers.Pointer[0x0D] = new WebCPU_Pointer(m);
246 P02 == バックエンドコードの終端, つまり P02 - &backend[0] = バックエンドコードのサイズ
248 if(this.registers.Integer[0x00] == 0){
250 var binData = this.registers.Pointer[0x02].memoryPage.data[1];
252 for(var i = 0; i < this.registers.Pointer[0x02].addressOffset; i++){
253 binStr += ("00" + binData.data[i].toString(16)).slice(-2);
255 this.message("[" + binStr + "]\n");
256 this.loadBackEndBinaryText(binStr);
260 this.message("loadFrontEndBinaryText: Translate failed.\n");
263 this.message("****LoadFrontEndBinaryText End****\n", 40);
265 executeStepIn: function(){
268 var retv = this.executeStepIn_Internal();
269 this.API.API_flushWin(this, this.API.mainWindowBufferCanvas.width, this.API.mainWindowBufferCanvas.height, 0, 0);
272 executeStepIn_Internal: function(){
274 //終端到達時は1を、まだ後続命令がある場合は0を返す。
277 this.message(">stepIn:Break.\n", 2);
278 this.stopFlag = false;
279 this.API.API_flushWin(this, this.API.mainWindowBufferCanvas.width, this.API.mainWindowBufferCanvas.height, 0, 0);
282 var instr = this.fetchMemoryNext();
283 if(instr === undefined){
284 this.message(">stepIn:control reached end of binary.\n", 2);
285 this.API.API_flushWin(this, this.API.mainWindowBufferCanvas.width, this.API.mainWindowBufferCanvas.height, 0, 0);
288 this.message(">stepIn:" + this.memoryPageCounter + "-" + (this.memoryInstructionCounter - 1) + ":" + instr.toString() + "\n", 20);
290 //これ以降this.memoryInstructionCounterが今実行した命令を指すとは限らない。(JMP系命令のため)
293 if(this.memoryPageCounter == 233 && this.memoryInstructionCounter == 0){
294 this.message(">stepIn:Breakpoint.\n", 2);
303 if(this.executeStepIn_Internal() != 0){
309 //実行環境をリセットする。メモリ内容は保持される。
310 for(var i = 0; i < this.registers.Integer.length; i++){
311 this.registers.Integer[i] = 0;
313 this.registers.Pointer = new Array(64);
314 for(var i = 0; i < this.registers.Pointer.length; i++){
315 this.registers.Pointer[i] = new WebCPU_Pointer(null);
317 //Set P28 for API calling.
318 this.registers.Pointer[0x28].memoryType = 0xC0FFEE;
320 this.memoryPageCounter = 0;
321 this.memoryInstructionCounter = 0;
322 this.stopFlag = false;
324 this.message("<<< Reset >>>\n");
326 fetchMemoryNext: function(){
327 if(this.mainMemory.root[this.memoryPageCounter].data.length <= this.memoryInstructionCounter){
328 this.memoryPageCounter++;
329 if(this.mainMemory.root.length <= this.memoryPageCounter){
330 this.memoryPageCounter--;
333 this.memoryInstructionCounter -= this.mainMemory.root[this.memoryPageCounter - 1].data.length;
335 var retv = this.mainMemory.root[this.memoryPageCounter].data[this.memoryInstructionCounter];
336 this.memoryInstructionCounter++;
339 setMainWindowCanvasDOMObject: function(id){
340 this.API.setMainWindowCanvasDOMObject(document.getElementById(id));
342 setDebugMessageDOMObject: function(name){
343 this.debugMessageText = document.getElementsByName(name)[0];
344 this.setDebugTimer();
346 setDebugIntegerRegisterDOMObject: function(name){
347 this.debugIntegerRegisterText = document.getElementsByName(name)[0];
348 this.setDebugTimer();
350 setDebugPointerRegisterDOMObject: function(name){
351 this.debugPointerRegisterText = document.getElementsByName(name)[0];
352 this.setDebugTimer();
354 setDebugTimer: function(){
355 if(!this.debugMessageText && !this.debugIntegerRegisterText && !this.debugPointerRegisterText){
356 //すべて無効だったらタイマーの動作自体を止める
357 window.clearTimeout(this.messageTimer);
358 this.messageTimer = null;
359 } else if(!this.messageTimer){
360 //どれかが有効でかつタイマーが止まっていたらスタートさせる
362 this.messageTimer = window.setInterval(function(){that.debugShowTick();}, 50);
365 debugShowTick: function(){
366 if(this.debugMessageText && this.debugMessageBuffer != ""){
367 var str = this.debugMessageText.innerHTML + this.debugMessageBuffer;
368 this.debugMessageBuffer = "";
369 if(str.length > WebCPU.maxDebugStringLength){
370 str = str.slice(str.length - (WebCPU.maxDebugStringLength >> 1));
372 this.debugMessageText.innerHTML = str;
373 this.debugMessageText.scrollTop = this.debugMessageText.scrollHeight;
375 this.refreshDebugIntegerRegisterText();
376 this.refreshDebugPointerRegisterText();
378 message: function(str, id){
385 //30:バックエンドバイナリ読み込みデバッグ
386 //40:フロントエンドバイナリ読み込みデバッグ
387 if(this.debugMessageText != null){
394 this.debugMessageBuffer += str;
397 //エラーのときmessageが無効であればalertで表示する。
401 showDisassembledCode: function(){
402 for(var i = 0; i < this.mainMemory.root.length; i++){
403 for(var j = 0; j < this.mainMemory.root[i].data.length; j++){
404 var instr = this.mainMemory.root[i].data[j];
405 this.message("+0x" + instr.binOffset.toString(16).toUpperCase() + ":" + i + "-" + j + ":" + instr.toString() + "\n", 30);
407 this.message(" - - - - \n", 30);
410 refreshDebugIntegerRegisterText: function(){
411 if(this.debugIntegerRegisterText != null){
412 this.debugIntegerRegisterText.innerHTML = "";
413 for(var i = 0; i < this.registers.Integer.length; i++){
414 this.debugIntegerRegisterText.innerHTML += "R" + ("00" + i.toString(16)).slice(-2).toUpperCase() + ":0x" + this.registers.Integer[i].toString(16).toUpperCase() + "\n";
418 refreshDebugPointerRegisterText: function(){
419 if(this.debugPointerRegisterText != null){
420 this.debugPointerRegisterText.innerHTML = "";
421 for(var i = 0; i < this.registers.Pointer.length; i++){
422 if(this.registers.Pointer[i]){
423 this.debugPointerRegisterText.innerHTML += "P" + ("00" + i.toString(16)).slice(-2).toUpperCase() + ":" + this.registers.Pointer[i].toString() + "\n";
425 this.debugPointerRegisterText.innerHTML += "P" + ("00" + i.toString(16)).slice(-2).toUpperCase() + ":(null)\n";
430 goToPointerRegister: function(reg0P){
433 var p = this.registers.Pointer[reg0P];
434 if(p.memoryType == 1){
436 this.memoryPageCounter = this.mainMemory.getMemoryPageCountFromMemoryPageInstance(p.memoryPage);
437 if(this.memoryPageCounter !== undefined){
438 this.memoryInstructionCounter = 0;
439 this.message("JMP:page " + this.memoryPageCounter + "\n", 20);
441 throw new WebCPU_Exception(2, ["memoryPage not found in mainMemory."]);
444 throw new WebCPU_Exception(2, ["Can't goto Memory page type is not VPtr."]);
447 createBackendBinaryString: function(){
453 instr = this.fetchMemoryNext();
454 if(instr === undefined){
457 s += instr.createBinaryString(this);
461 staticOptimize: function(){
464 //一つのメモリページにラベル命令のみがある場合は、それを次のメモリページのラベル名に置換する
466 var removePageIndexStack = new Array();
467 var labelIDStack = new Array();
470 for(var i = 0; i < this.mainMemory.root.length; i++){
471 mpage = this.mainMemory.root[i];
472 if(mpage instanceof WebCPU_MemoryPage && mpage.data[0] instanceof WebCPU_Instruction_LB){
474 if(mpage.data.length == 1){
476 labelIDStack.push(mpage.data[0].imm32);
477 removePageIndexStack.push(i);
480 if(labelIDStack.length != 0){
482 labelID = labelIDStack.pop();
483 if(labelID == undefined){
486 this.mainMemory.root.splice(removePageIndexStack[0], 1);
488 this.staticOptimize_ReplaceLabelNumber(labelID, mpage.data[0].imm32);
490 removePageIndexStack = new Array();
495 if(labelIDStack.length != 0){
496 //プログラム末尾のラベル命令は削除しないようにする
497 newLabelID = labelIDStack.pop();
499 labelID = labelIDStack.pop();
500 if(labelID == undefined){
503 this.mainMemory.root.splice(removePageIndexStack[0], 1);
505 this.staticOptimize_ReplaceLabelNumber(labelID, newLabelID);
509 staticOptimize_ReplaceLabelNumber: function(from, to){
512 for(var i = 0, iLen = this.mainMemory.root.length; i < iLen; i++){
513 mpage = this.mainMemory.root[i];
514 for(var j = 0, jLen = mpage.data.length; j < jLen; j++){
515 instr = mpage.data[j];
516 if(instr instanceof WebCPU_Instruction_PLIMM){
517 if(instr.imm32 == from){
527 function parseSignedInt32(hexStr){
528 //文字列を16進32bit符号あり整数として変換する。
529 var i = parseInt(hexStr, 16);
538 function parseSignedInt(hexStr, bits){
539 //文字列を16進符号あり整数として変換する。
541 var i = parseInt(hexStr, 16);
542 if(i >= (1 << (bits - 1))){
544 return -(((0xffffffff >>> (32 - bits)) - i) + 1);
550 function toHexString8(v){
551 return ("00" + v.toString(16).toUpperCase()).slice(-2);
554 function toHexString32(v){
558 return ("00000000" + v.toString(16).toUpperCase()).slice(-8);
561 function replaceAll(str, org, dest){
562 //文字列str中にある文字列orgを文字列destにすべて置換する。
563 //http://www.syboos.jp/webjs/doc/string-replace-and-replaceall.html
564 return str.split(org).join(dest);