diff --git a/.gitignore b/.gitignore index 70f4645f..8118bc7f 100644 --- a/.gitignore +++ b/.gitignore @@ -9,8 +9,9 @@ closure-compiler/ images/ *.bak *.orig +*.wasm *.o *.bin *.img *.fixture -*.fuse_hidden* \ No newline at end of file +*.fuse_hidden* diff --git a/Makefile b/Makefile index 1dabe9cd..f22d696e 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,7 @@ NASM_TEST_DIR=./tests/nasm all: build/v86_all.js browser: build/v86_all.js +wasm: build/v86.wasm # Used for nodejs builds and in order to profile code. # `debug` gives identifiers a readable name, make sure it doesn't have any side effects. @@ -123,11 +124,42 @@ build/libv86.js: $(CLOSURE) src/*.js lib/*.js src/browser/*.js ls -lh build/libv86.js +build/v86.wasm: src/native/*.c src/native/*.h + mkdir -p build + -ls -lh build/v86.wasm + # --llvm-opts 3 + # -Wno-extra-semi + # EMCC_WASM_BACKEND=1 + emcc src/native/all.c \ + -Wall -Wpedantic -Wextra \ + -DDEBUG=false \ + -DNDEBUG \ + -Wno-bitwise-op-parentheses -Wno-gnu-binary-literal \ + -fcolor-diagnostics \ + -fwrapv \ + --llvm-opts 3 \ + -O3 \ + -g4 \ + -s WASM=1 -s SIDE_MODULE=1 -o build/v86.wasm + ls -lh build/v86.wasm + +build/v86-debug.wasm: src/native/*.c src/native/*.h + emcc src/native/all.c \ + -Wall -Wpedantic -Wextra \ + -Wno-bitwise-op-parentheses -Wno-gnu-binary-literal \ + -fcolor-diagnostics \ + -fwrapv \ + -Os \ + -g4 \ + -s WASM=1 -s SIDE_MODULE=1 -o build/v86-debug.wasm + ls -lh build/v86-debug.wasm + clean: -rm build/libv86.js -rm build/v86_all.js -rm build/libv86.js.map -rm build/v86_all.js.map + -rm build/v86.wasm $(MAKE) -C $(NASM_TEST_DIR) clean run: diff --git a/src/arith.js b/src/arith.js index 2bab9b6f..5334af8a 100644 --- a/src/arith.js +++ b/src/arith.js @@ -45,52 +45,52 @@ CPU.prototype.add = function(dest_operand, source_operand, op_size) { //if(this.safe_read32s(this.instruction_pointer + 1) === 0 && this.safe_read32s(this.instruction_pointer + 5) === 0) throw "0000000"; - this.last_op1 = dest_operand; - this.last_op2 = source_operand; - this.last_add_result = this.last_result = dest_operand + source_operand | 0; + this.last_op1[0] = dest_operand; + this.last_op2[0] = source_operand; + this.last_add_result[0] = this.last_result[0] = dest_operand + source_operand | 0; - this.last_op_size = op_size; - this.flags_changed = flags_all; + this.last_op_size[0] = op_size; + this.flags_changed[0] = flags_all; - return this.last_result; + return this.last_result[0]; } CPU.prototype.adc = function(dest_operand, source_operand, op_size) { var cf = this.getcf(); - this.last_op1 = dest_operand; - this.last_op2 = source_operand; - this.last_add_result = this.last_result = (dest_operand + source_operand | 0) + cf | 0; + this.last_op1[0] = dest_operand; + this.last_op2[0] = source_operand; + this.last_add_result[0] = this.last_result[0] = (dest_operand + source_operand | 0) + cf | 0; - this.last_op_size = op_size; - this.flags_changed = flags_all; + this.last_op_size[0] = op_size; + this.flags_changed[0] = flags_all; - return this.last_result; + return this.last_result[0]; } CPU.prototype.sub = function(dest_operand, source_operand, op_size) { - this.last_add_result = dest_operand; - this.last_op2 = source_operand; - this.last_op1 = this.last_result = dest_operand - source_operand | 0; + this.last_add_result[0] = dest_operand; + this.last_op2[0] = source_operand; + this.last_op1[0] = this.last_result[0] = dest_operand - source_operand | 0; - this.last_op_size = op_size; - this.flags_changed = flags_all; + this.last_op_size[0] = op_size; + this.flags_changed[0] = flags_all; - return this.last_result; + return this.last_result[0]; } CPU.prototype.sbb = function(dest_operand, source_operand, op_size) { var cf = this.getcf(); - this.last_add_result = dest_operand; - this.last_op2 = source_operand; - this.last_op1 = this.last_result = dest_operand - source_operand - cf | 0; - this.last_op_size = op_size; + this.last_add_result[0] = dest_operand; + this.last_op2[0] = source_operand; + this.last_op1[0] = this.last_result[0] = dest_operand - source_operand - cf | 0; + this.last_op_size[0] = op_size; - this.flags_changed = flags_all; + this.flags_changed[0] = flags_all; - return this.last_result; + return this.last_result[0]; } /* @@ -107,28 +107,28 @@ CPU.prototype.dec32 = function(dest) { return this.dec(dest, OPSIZE_32); } CPU.prototype.inc = function(dest_operand, op_size) { - this.flags = (this.flags & ~1) | this.getcf(); - this.last_op1 = dest_operand; - this.last_op2 = 1; - this.last_add_result = this.last_result = dest_operand + 1 | 0; - this.last_op_size = op_size; + this.flags[0] = (this.flags[0] & ~1) | this.getcf(); + this.last_op1[0] = dest_operand; + this.last_op2[0] = 1; + this.last_add_result[0] = this.last_result[0] = dest_operand + 1 | 0; + this.last_op_size[0] = op_size; - this.flags_changed = flags_all & ~1; + this.flags_changed[0] = flags_all & ~1; - return this.last_result; + return this.last_result[0]; } CPU.prototype.dec = function(dest_operand, op_size) { - this.flags = (this.flags & ~1) | this.getcf(); - this.last_add_result = dest_operand; - this.last_op2 = 1; - this.last_op1 = this.last_result = dest_operand - 1 | 0; - this.last_op_size = op_size; + this.flags[0] = (this.flags[0] & ~1) | this.getcf(); + this.last_add_result[0] = dest_operand; + this.last_op2[0] = 1; + this.last_op1[0] = this.last_result[0] = dest_operand - 1 | 0; + this.last_op_size[0] = op_size; - this.flags_changed = flags_all & ~1; + this.flags_changed[0] = flags_all & ~1; - return this.last_result; + return this.last_result[0]; } @@ -141,17 +141,16 @@ CPU.prototype.neg32 = function(dest) { return this.neg(dest, OPSIZE_32); } CPU.prototype.neg = function(dest_operand, op_size) { - this.last_op1 = this.last_result = -dest_operand | 0; + this.last_op1[0] = this.last_result[0] = -dest_operand | 0; - this.flags_changed = flags_all; - this.last_add_result = 0; - this.last_op2 = dest_operand; - this.last_op_size = op_size; + this.flags_changed[0] = flags_all; + this.last_add_result[0] = 0; + this.last_op2[0] = dest_operand; + this.last_op_size[0] = op_size; - return this.last_result; + return this.last_result[0]; } - /* * mul, imul, div, idiv * @@ -165,19 +164,19 @@ CPU.prototype.mul8 = function(source_operand) var result = source_operand * this.reg8[reg_al]; this.reg16[reg_ax] = result; - this.last_result = result & 0xFF; - this.last_op_size = OPSIZE_8; + this.last_result[0] = result & 0xFF; + this.last_op_size[0] = OPSIZE_8; if(result < 0x100) { - this.flags = this.flags & ~1 & ~flag_overflow; + this.flags[0] = this.flags[0] & ~1 & ~flag_overflow; } else { - this.flags = this.flags | 1 | flag_overflow; + this.flags[0] = this.flags[0] | 1 | flag_overflow; } - this.flags_changed = flags_all & ~1 & ~flag_overflow; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; } CPU.prototype.imul8 = function(source_operand) @@ -185,18 +184,18 @@ CPU.prototype.imul8 = function(source_operand) var result = source_operand * this.reg8s[reg_al]; this.reg16[reg_ax] = result; - this.last_result = result & 0xFF; - this.last_op_size = OPSIZE_8; + this.last_result[0] = result & 0xFF; + this.last_op_size[0] = OPSIZE_8; if(result > 0x7F || result < -0x80) { - this.flags = this.flags | 1 | flag_overflow; + this.flags[0] = this.flags[0] | 1 | flag_overflow; } else { - this.flags = this.flags & ~1 & ~flag_overflow; + this.flags[0] = this.flags[0] & ~1 & ~flag_overflow; } - this.flags_changed = flags_all & ~1 & ~flag_overflow; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; } CPU.prototype.mul16 = function(source_operand) @@ -208,18 +207,18 @@ CPU.prototype.mul16 = function(source_operand) this.reg16[reg_ax] = result; this.reg16[reg_dx] = high_result; - this.last_result = result & 0xFFFF; - this.last_op_size = OPSIZE_16; + this.last_result[0] = result & 0xFFFF; + this.last_op_size[0] = OPSIZE_16; if(high_result === 0) { - this.flags &= ~1 & ~flag_overflow; + this.flags[0] &= ~1 & ~flag_overflow; } else { - this.flags |= 1 | flag_overflow; + this.flags[0] |= 1 | flag_overflow; } - this.flags_changed = flags_all & ~1 & ~flag_overflow; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; } /* @@ -233,18 +232,18 @@ CPU.prototype.imul16 = function(source_operand) this.reg16[reg_ax] = result; this.reg16[reg_dx] = result >> 16; - this.last_result = result & 0xFFFF; - this.last_op_size = OPSIZE_16; + this.last_result[0] = result & 0xFFFF; + this.last_op_size[0] = OPSIZE_16; if(result > 0x7FFF || result < -0x8000) { - this.flags |= 1 | flag_overflow; + this.flags[0] |= 1 | flag_overflow; } else { - this.flags &= ~1 & ~flag_overflow; + this.flags[0] &= ~1 & ~flag_overflow; } - this.flags_changed = flags_all & ~1 & ~flag_overflow; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; } /* @@ -259,18 +258,18 @@ CPU.prototype.imul_reg16 = function(operand1, operand2) var result = operand1 * operand2; - this.last_result = result & 0xFFFF; - this.last_op_size = OPSIZE_16; + this.last_result[0] = result & 0xFFFF; + this.last_op_size[0] = OPSIZE_16; if(result > 0x7FFF || result < -0x8000) { - this.flags |= 1 | flag_overflow; + this.flags[0] |= 1 | flag_overflow; } else { - this.flags &= ~1 & ~flag_overflow; + this.flags[0] &= ~1 & ~flag_overflow; } - this.flags_changed = flags_all & ~1 & ~flag_overflow; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; return result; } @@ -290,6 +289,14 @@ CPU.prototype.do_mul32 = function(a, b) return this.mul32_result; }; +//XXX: do_mul32 returns a typedarray object which we can't do from a wasm +//function, so we rewrite it here differently from other ports. Would +//change this when callers of do_mul32 are rewritten in wasm. +CPU.prototype.do_mul32 = function(a, b) { + this.wm.funcs['_do_mul32'](a, b); + return this.mul32_result; +}; + CPU.prototype.do_imul32 = function(a, b) { var is_neg = false; @@ -309,6 +316,12 @@ CPU.prototype.do_imul32 = function(a, b) return result; } +//XXX: same issue as do_mul32. rewrite after callers are ported to wasm +CPU.prototype.do_imul32 = function(a, b) { + this.wm.funcs['_do_imul32'](a, b); + return this.mul32_result; +}; + CPU.prototype.mul32 = function(source_operand) { var dest_operand = this.reg32s[reg_eax]; @@ -318,18 +331,18 @@ CPU.prototype.mul32 = function(source_operand) this.reg32s[reg_eax] = result[0]; this.reg32s[reg_edx] = result[1]; - this.last_result = result[0]; - this.last_op_size = OPSIZE_32; + this.last_result[0] = result[0]; + this.last_op_size[0] = OPSIZE_32; if(result[1] === 0) { - this.flags &= ~1 & ~flag_overflow; + this.flags[0] &= ~1 & ~flag_overflow; } else { - this.flags |= 1 | flag_overflow; + this.flags[0] |= 1 | flag_overflow; } - this.flags_changed = flags_all & ~1 & ~flag_overflow; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; //console.log(h(source_operand >>> 0, 8) + " * " + h(dest_operand >>> 0, 8)); //console.log("= " + h(this.reg32[reg_edx], 8) + ":" + h(this.reg32[reg_eax], 8)); @@ -346,18 +359,18 @@ CPU.prototype.imul32 = function(source_operand) this.reg32s[reg_eax] = result[0]; this.reg32s[reg_edx] = result[1]; - this.last_result = result[0]; - this.last_op_size = OPSIZE_32; + this.last_result[0] = result[0]; + this.last_op_size[0] = OPSIZE_32; if(result[1] === (result[0] >> 31)) { - this.flags &= ~1 & ~flag_overflow; + this.flags[0] &= ~1 & ~flag_overflow; } else { - this.flags |= 1 | flag_overflow; + this.flags[0] |= 1 | flag_overflow; } - this.flags_changed = flags_all & ~1 & ~flag_overflow; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; //console.log(target_operand + " * " + source_operand); //console.log("= " + h(this.reg32[reg_edx]) + " " + h(this.reg32[reg_eax])); @@ -375,18 +388,18 @@ CPU.prototype.imul_reg32 = function(operand1, operand2) var result = this.do_imul32(operand1, operand2); - this.last_result = result[0]; - this.last_op_size = OPSIZE_32; + this.last_result[0] = result[0]; + this.last_op_size[0] = OPSIZE_32; if(result[1] === (result[0] >> 31)) { - this.flags &= ~1 & ~flag_overflow; + this.flags[0] &= ~1 & ~flag_overflow; } else { - this.flags |= 1 | flag_overflow; + this.flags[0] |= 1 | flag_overflow; } - this.flags_changed = flags_all & ~1 & ~flag_overflow; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; return result[0]; @@ -502,7 +515,7 @@ CPU.prototype.do_div32 = function(div_low, div_high, quot) this.trigger_de(); } - var result = 0; + var result = 0; if(div_high > 0x100000) { @@ -545,6 +558,7 @@ CPU.prototype.do_div32 = function(div_low, div_high, quot) CPU.prototype.div32 = function(source_operand) { + source_operand >>>= 0; dbg_assert(source_operand >= 0 && source_operand <= 0xffffffff); var dest_operand_low = this.reg32[reg_eax], @@ -666,23 +680,23 @@ CPU.prototype.bcd_daa = function() old_cf = this.getcf(), old_af = this.getaf(); - this.flags &= ~1 & ~flag_adjust + this.flags[0] &= ~1 & ~flag_adjust if((old_al & 0xF) > 9 || old_af) { this.reg8[reg_al] += 6; - this.flags |= flag_adjust; + this.flags[0] |= flag_adjust; } if(old_al > 0x99 || old_cf) { this.reg8[reg_al] += 0x60; - this.flags |= 1; + this.flags[0] |= 1; } - this.last_result = this.reg8[reg_al]; - this.last_op_size = OPSIZE_8; - this.last_op1 = this.last_op2 = 0; - this.flags_changed = flags_all & ~1 & ~flag_adjust & ~flag_overflow; + this.last_result[0] = this.reg8[reg_al]; + this.last_op_size[0] = OPSIZE_8; + this.last_op1[0] = this.last_op2[0] = 0; + this.flags_changed[0] = flags_all & ~1 & ~flag_adjust & ~flag_overflow; } CPU.prototype.bcd_das = function() @@ -692,29 +706,29 @@ CPU.prototype.bcd_das = function() var old_al = this.reg8[reg_al], old_cf = this.getcf(); - this.flags &= ~1; + this.flags[0] &= ~1; if((old_al & 0xF) > 9 || this.getaf()) { this.reg8[reg_al] -= 6; - this.flags |= flag_adjust; - this.flags = this.flags & ~1 | old_cf | (old_al < 6); + this.flags[0] |= flag_adjust; + this.flags[0] = this.flags[0] & ~1 | old_cf | (old_al < 6); } else { - this.flags &= ~flag_adjust; + this.flags[0] &= ~flag_adjust; } if(old_al > 0x99 || old_cf) { this.reg8[reg_al] -= 0x60; - this.flags |= 1; + this.flags[0] |= 1; } - this.last_result = this.reg8[reg_al]; - this.last_op_size = OPSIZE_8; - this.last_op1 = this.last_op2 = 0; - this.flags_changed = flags_all & ~1 & ~flag_adjust & ~flag_overflow; + this.last_result[0] = this.reg8[reg_al]; + this.last_op_size[0] = OPSIZE_8; + this.last_op1[0] = this.last_op2[0] = 0; + this.flags_changed[0] = flags_all & ~1 & ~flag_adjust & ~flag_overflow; } CPU.prototype.bcd_aam = function(imm8) @@ -732,10 +746,10 @@ CPU.prototype.bcd_aam = function(imm8) this.reg8[reg_ah] = temp / imm8; this.reg8[reg_al] = temp % imm8; - this.last_result = this.reg8[reg_al]; + this.last_result[0] = this.reg8[reg_al]; - this.flags_changed = flags_all & ~1 & ~flag_adjust & ~flag_overflow; - this.flags &= ~1 & ~flag_adjust & ~flag_overflow; + this.flags_changed[0] = flags_all & ~1 & ~flag_adjust & ~flag_overflow; + this.flags[0] &= ~1 & ~flag_adjust & ~flag_overflow; } } @@ -745,16 +759,16 @@ CPU.prototype.bcd_aad = function(imm8) // ascii adjust before division var result = this.reg8[reg_al] + this.reg8[reg_ah] * imm8; - this.last_result = result & 0xFF; - this.reg16[reg_ax] = this.last_result; - this.last_op_size = OPSIZE_8; + this.last_result[0] = result & 0xFF; + this.reg16[reg_ax] = this.last_result[0]; + this.last_op_size[0] = OPSIZE_8; - this.flags_changed = flags_all & ~1 & ~flag_adjust & ~flag_overflow; - this.flags &= ~1 & ~flag_adjust & ~flag_overflow; + this.flags_changed[0] = flags_all & ~1 & ~flag_adjust & ~flag_overflow; + this.flags[0] &= ~1 & ~flag_adjust & ~flag_overflow; if(result > 0xFFFF) { - this.flags |= 1; + this.flags[0] |= 1; } } @@ -765,15 +779,15 @@ CPU.prototype.bcd_aaa = function() { this.reg16[reg_ax] += 6; this.reg8[reg_ah] += 1; - this.flags |= flag_adjust | 1; + this.flags[0] |= flag_adjust | 1; } else { - this.flags &= ~flag_adjust & ~1; + this.flags[0] &= ~flag_adjust & ~1; } this.reg8[reg_al] &= 0xF; - this.flags_changed &= ~flag_adjust & ~1; + this.flags_changed[0] &= ~flag_adjust & ~1; }; @@ -784,15 +798,15 @@ CPU.prototype.bcd_aas = function() { this.reg16[reg_ax] -= 6; this.reg8[reg_ah] -= 1; - this.flags |= flag_adjust | 1; + this.flags[0] |= flag_adjust | 1; } else { - this.flags &= ~flag_adjust & ~1; + this.flags[0] &= ~flag_adjust & ~1; } this.reg8[reg_al] &= 0xF; - this.flags_changed &= ~flag_adjust & ~1; + this.flags_changed[0] &= ~flag_adjust & ~1; } @@ -826,35 +840,35 @@ CPU.prototype.xor32 = function(dest, src) { return this.xor(dest, src, OPSIZE_32 CPU.prototype.and = function(dest_operand, source_operand, op_size) { - this.last_result = dest_operand & source_operand; + this.last_result[0] = dest_operand & source_operand; - this.last_op_size = op_size; - this.flags &= ~1 & ~flag_overflow & ~flag_adjust; - this.flags_changed = flags_all & ~1 & ~flag_overflow & ~flag_adjust; + this.last_op_size[0] = op_size; + this.flags[0] &= ~1 & ~flag_overflow & ~flag_adjust; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow & ~flag_adjust; - return this.last_result; + return this.last_result[0]; } CPU.prototype.or = function(dest_operand, source_operand, op_size) { - this.last_result = dest_operand | source_operand; + this.last_result[0] = dest_operand | source_operand; - this.last_op_size = op_size; - this.flags &= ~1 & ~flag_overflow & ~flag_adjust; - this.flags_changed = flags_all & ~1 & ~flag_overflow & ~flag_adjust; + this.last_op_size[0] = op_size; + this.flags[0] &= ~1 & ~flag_overflow & ~flag_adjust; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow & ~flag_adjust; - return this.last_result; + return this.last_result[0]; } CPU.prototype.xor = function(dest_operand, source_operand, op_size) { - this.last_result = dest_operand ^ source_operand; + this.last_result[0] = dest_operand ^ source_operand; - this.last_op_size = op_size; - this.flags &= ~1 & ~flag_overflow & ~flag_adjust; - this.flags_changed = flags_all & ~1 & ~flag_overflow & ~flag_adjust; + this.last_op_size[0] = op_size; + this.flags[0] &= ~1 & ~flag_overflow & ~flag_adjust; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow & ~flag_adjust; - return this.last_result; + return this.last_result[0]; } @@ -872,8 +886,8 @@ CPU.prototype.rol8 = function(dest_operand, count) var result = dest_operand << count | dest_operand >> (8 - count); - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (result & 1) | (result << 11 ^ result << 4) & flag_overflow; @@ -890,8 +904,8 @@ CPU.prototype.rol16 = function(dest_operand, count) var result = dest_operand << count | dest_operand >> (16 - count); - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (result & 1) | (result << 11 ^ result >> 4) & flag_overflow; @@ -907,8 +921,8 @@ CPU.prototype.rol32 = function(dest_operand, count) var result = dest_operand << count | dest_operand >>> (32 - count); - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (result & 1) | (result << 11 ^ result >> 20) & flag_overflow; @@ -925,8 +939,8 @@ CPU.prototype.rcl8 = function(dest_operand, count) var result = dest_operand << count | this.getcf() << (count - 1) | dest_operand >> (9 - count); - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (result >> 8 & 1) | (result << 3 ^ result << 4) & flag_overflow; @@ -943,8 +957,8 @@ CPU.prototype.rcl16 = function(dest_operand, count) var result = dest_operand << count | this.getcf() << (count - 1) | dest_operand >> (17 - count); - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (result >> 16 & 1) | (result >> 5 ^ result >> 4) & flag_overflow; @@ -965,9 +979,9 @@ CPU.prototype.rcl32 = function(dest_operand, count) result |= dest_operand >>> (33 - count); } - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) | (dest_operand >>> (32 - count) & 1); - this.flags |= (this.flags << 11 ^ result >> 20) & flag_overflow; + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (dest_operand >>> (32 - count) & 1); + this.flags[0] |= (this.flags[0] << 11 ^ result >> 20) & flag_overflow; return result; } @@ -982,8 +996,8 @@ CPU.prototype.ror8 = function(dest_operand, count) count &= 7; var result = dest_operand >> count | dest_operand << (8 - count); - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (result >> 7 & 1) | (result << 4 ^ result << 5) & flag_overflow; @@ -1000,8 +1014,8 @@ CPU.prototype.ror16 = function(dest_operand, count) count &= 15; var result = dest_operand >> count | dest_operand << (16 - count); - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (result >> 15 & 1) | (result >> 4 ^ result >> 3) & flag_overflow; @@ -1017,8 +1031,8 @@ CPU.prototype.ror32 = function(dest_operand, count) var result = dest_operand >>> count | dest_operand << (32 - count); - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (result >> 31 & 1) | (result >> 20 ^ result >> 19) & flag_overflow; @@ -1035,8 +1049,8 @@ CPU.prototype.rcr8 = function(dest_operand, count) var result = dest_operand >> count | this.getcf() << (8 - count) | dest_operand << (9 - count); - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (result >> 8 & 1) | (result << 4 ^ result << 5) & flag_overflow; @@ -1053,8 +1067,8 @@ CPU.prototype.rcr16 = function(dest_operand, count) var result = dest_operand >> count | this.getcf() << (16 - count) | dest_operand << (17 - count); - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (result >> 16 & 1) | (result >> 4 ^ result >> 3) & flag_overflow; @@ -1075,8 +1089,8 @@ CPU.prototype.rcr32 = function(dest_operand, count) result |= dest_operand << (33 - count); } - this.flags_changed &= ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.flags_changed[0] &= ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (dest_operand >> (count - 1) & 1) | (result >> 20 ^ result >> 19) & flag_overflow; @@ -1090,15 +1104,15 @@ CPU.prototype.shl8 = function(dest_operand, count) return dest_operand; } - this.last_result = dest_operand << count; + this.last_result[0] = dest_operand << count; - this.last_op_size = OPSIZE_8; - this.flags_changed = flags_all & ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) - | (this.last_result >> 8 & 1) - | (this.last_result << 3 ^ this.last_result << 4) & flag_overflow; + this.last_op_size[0] = OPSIZE_8; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) + | (this.last_result[0] >> 8 & 1) + | (this.last_result[0] << 3 ^ this.last_result[0] << 4) & flag_overflow; - return this.last_result; + return this.last_result[0]; } CPU.prototype.shl16 = function(dest_operand, count) @@ -1108,15 +1122,15 @@ CPU.prototype.shl16 = function(dest_operand, count) return dest_operand; } - this.last_result = dest_operand << count; + this.last_result[0] = dest_operand << count; - this.last_op_size = OPSIZE_16; - this.flags_changed = flags_all & ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) - | (this.last_result >> 16 & 1) - | (this.last_result >> 5 ^ this.last_result >> 4) & flag_overflow; + this.last_op_size[0] = OPSIZE_16; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) + | (this.last_result[0] >> 16 & 1) + | (this.last_result[0] >> 5 ^ this.last_result[0] >> 4) & flag_overflow; - return this.last_result; + return this.last_result[0]; } CPU.prototype.shl32 = function(dest_operand, count) @@ -1126,15 +1140,15 @@ CPU.prototype.shl32 = function(dest_operand, count) return dest_operand; } - this.last_result = dest_operand << count; + this.last_result[0] = dest_operand << count; - this.last_op_size = OPSIZE_32; - this.flags_changed = flags_all & ~1 & ~flag_overflow; + this.last_op_size[0] = OPSIZE_32; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; // test this - this.flags = (this.flags & ~1 & ~flag_overflow) | (dest_operand >>> (32 - count) & 1); - this.flags |= ((this.flags & 1) ^ (this.last_result >> 31 & 1)) << 11 & flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (dest_operand >>> (32 - count) & 1); + this.flags[0] |= ((this.flags[0] & 1) ^ (this.last_result[0] >> 31 & 1)) << 11 & flag_overflow; - return this.last_result; + return this.last_result[0]; } CPU.prototype.shr8 = function(dest_operand, count) @@ -1144,15 +1158,15 @@ CPU.prototype.shr8 = function(dest_operand, count) return dest_operand; } - this.last_result = dest_operand >> count; + this.last_result[0] = dest_operand >> count; - this.last_op_size = OPSIZE_8; - this.flags_changed = flags_all & ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.last_op_size[0] = OPSIZE_8; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (dest_operand >> (count - 1) & 1) | (dest_operand >> 7 & 1) << 11 & flag_overflow; - return this.last_result; + return this.last_result[0]; } CPU.prototype.shr16 = function(dest_operand, count) @@ -1162,15 +1176,15 @@ CPU.prototype.shr16 = function(dest_operand, count) return dest_operand; } - this.last_result = dest_operand >> count; + this.last_result[0] = dest_operand >> count; - this.last_op_size = OPSIZE_16; - this.flags_changed = flags_all & ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.last_op_size[0] = OPSIZE_16; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (dest_operand >> (count - 1) & 1) | (dest_operand >> 4) & flag_overflow; - return this.last_result; + return this.last_result[0]; } CPU.prototype.shr32 = function(dest_operand, count) @@ -1180,15 +1194,15 @@ CPU.prototype.shr32 = function(dest_operand, count) return dest_operand; } - this.last_result = dest_operand >>> count; + this.last_result[0] = dest_operand >>> count; - this.last_op_size = OPSIZE_32; - this.flags_changed = flags_all & ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) + this.last_op_size[0] = OPSIZE_32; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (dest_operand >>> (count - 1) & 1) | (dest_operand >> 20) & flag_overflow; - return this.last_result; + return this.last_result[0]; } CPU.prototype.sar8 = function(dest_operand, count) @@ -1200,20 +1214,20 @@ CPU.prototype.sar8 = function(dest_operand, count) if(count < 8) { - this.last_result = dest_operand << 24 >> count + 24; + this.last_result[0] = dest_operand << 24 >> count + 24; // of is zero - this.flags = (this.flags & ~1 & ~flag_overflow) | (dest_operand >> (count - 1) & 1); + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (dest_operand >> (count - 1) & 1); } else { - this.last_result = dest_operand << 24 >> 31; - this.flags = (this.flags & ~1 & ~flag_overflow) | (this.last_result & 1); + this.last_result[0] = dest_operand << 24 >> 31; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (this.last_result[0] & 1); } - this.last_op_size = OPSIZE_8; - this.flags_changed = flags_all & ~1 & ~flag_overflow; + this.last_op_size[0] = OPSIZE_8; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; - return this.last_result; + return this.last_result[0]; } CPU.prototype.sar16 = function(dest_operand, count) @@ -1225,19 +1239,19 @@ CPU.prototype.sar16 = function(dest_operand, count) if(count < 16) { - this.last_result = dest_operand << 16 >> count + 16; - this.flags = (this.flags & ~1 & ~flag_overflow) | (dest_operand >> (count - 1) & 1); + this.last_result[0] = dest_operand << 16 >> count + 16; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (dest_operand >> (count - 1) & 1); } else { - this.last_result = dest_operand << 16 >> 31; - this.flags = (this.flags & ~1 & ~flag_overflow) | (this.last_result & 1); + this.last_result[0] = dest_operand << 16 >> 31; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (this.last_result[0] & 1); } - this.last_op_size = OPSIZE_16; - this.flags_changed = flags_all & ~1 & ~flag_overflow; + this.last_op_size[0] = OPSIZE_16; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; - return this.last_result; + return this.last_result[0]; } CPU.prototype.sar32 = function(dest_operand, count) @@ -1247,13 +1261,13 @@ CPU.prototype.sar32 = function(dest_operand, count) return dest_operand; } - this.last_result = dest_operand >> count; + this.last_result[0] = dest_operand >> count; - this.last_op_size = OPSIZE_32; - this.flags_changed = flags_all & ~1 & ~flag_overflow; - this.flags = (this.flags & ~1 & ~flag_overflow) | (dest_operand >>> (count - 1) & 1); + this.last_op_size[0] = OPSIZE_32; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1 & ~flag_overflow) | (dest_operand >>> (count - 1) & 1); - return this.last_result; + return this.last_result[0]; } @@ -1266,20 +1280,20 @@ CPU.prototype.shrd16 = function(dest_operand, source_operand, count) if(count <= 16) { - this.last_result = dest_operand >> count | source_operand << (16 - count); - this.flags = (this.flags & ~1) | (dest_operand >> (count - 1) & 1); + this.last_result[0] = dest_operand >> count | source_operand << (16 - count); + this.flags[0] = (this.flags[0] & ~1) | (dest_operand >> (count - 1) & 1); } else { - this.last_result = dest_operand << (32 - count) | source_operand >> (count - 16); - this.flags = (this.flags & ~1) | (source_operand >> (count - 17) & 1); + this.last_result[0] = dest_operand << (32 - count) | source_operand >> (count - 16); + this.flags[0] = (this.flags[0] & ~1) | (source_operand >> (count - 17) & 1); } - this.last_op_size = OPSIZE_16; - this.flags_changed = flags_all & ~1 & ~flag_overflow; - this.flags = (this.flags & ~flag_overflow) | ((this.last_result ^ dest_operand) >> 4 & flag_overflow); + this.last_op_size[0] = OPSIZE_16; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~flag_overflow) | ((this.last_result[0] ^ dest_operand) >> 4 & flag_overflow); - return this.last_result; + return this.last_result[0]; } CPU.prototype.shrd32 = function(dest_operand, source_operand, count) @@ -1289,14 +1303,14 @@ CPU.prototype.shrd32 = function(dest_operand, source_operand, count) return dest_operand; } - this.last_result = dest_operand >>> count | source_operand << (32 - count); + this.last_result[0] = dest_operand >>> count | source_operand << (32 - count); - this.last_op_size = OPSIZE_32; - this.flags_changed = flags_all & ~1 & ~flag_overflow; - this.flags = (this.flags & ~1) | (dest_operand >>> (count - 1) & 1); - this.flags = (this.flags & ~flag_overflow) | ((this.last_result ^ dest_operand) >> 20 & flag_overflow); + this.last_op_size[0] = OPSIZE_32; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1) | (dest_operand >>> (count - 1) & 1); + this.flags[0] = (this.flags[0] & ~flag_overflow) | ((this.last_result[0] ^ dest_operand) >> 20 & flag_overflow); - return this.last_result; + return this.last_result[0]; } CPU.prototype.shld16 = function(dest_operand, source_operand, count) @@ -1308,20 +1322,20 @@ CPU.prototype.shld16 = function(dest_operand, source_operand, count) if(count <= 16) { - this.last_result = dest_operand << count | source_operand >>> (16 - count); - this.flags = (this.flags & ~1) | (dest_operand >>> (16 - count) & 1); + this.last_result[0] = dest_operand << count | source_operand >>> (16 - count); + this.flags[0] = (this.flags[0] & ~1) | (dest_operand >>> (16 - count) & 1); } else { - this.last_result = dest_operand >> (32 - count) | source_operand << (count - 16); - this.flags = (this.flags & ~1) | (source_operand >>> (32 - count) & 1); + this.last_result[0] = dest_operand >> (32 - count) | source_operand << (count - 16); + this.flags[0] = (this.flags[0] & ~1) | (source_operand >>> (32 - count) & 1); } - this.last_op_size = OPSIZE_16; - this.flags_changed = flags_all & ~1 & ~flag_overflow; - this.flags = (this.flags & ~flag_overflow) | ((this.flags & 1) ^ (this.last_result >> 15 & 1)) << 11; + this.last_op_size[0] = OPSIZE_16; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~flag_overflow) | ((this.flags[0] & 1) ^ (this.last_result[0] >> 15 & 1)) << 11; - return this.last_result; + return this.last_result[0]; } CPU.prototype.shld32 = function(dest_operand, source_operand, count) @@ -1331,51 +1345,51 @@ CPU.prototype.shld32 = function(dest_operand, source_operand, count) return dest_operand; } - this.last_result = dest_operand << count | source_operand >>> (32 - count); + this.last_result[0] = dest_operand << count | source_operand >>> (32 - count); - this.last_op_size = OPSIZE_32; - this.flags_changed = flags_all & ~1 & ~flag_overflow; - this.flags = (this.flags & ~1) | (dest_operand >>> (32 - count) & 1); + this.last_op_size[0] = OPSIZE_32; + this.flags_changed[0] = flags_all & ~1 & ~flag_overflow; + this.flags[0] = (this.flags[0] & ~1) | (dest_operand >>> (32 - count) & 1); if(count === 1) { - this.flags = (this.flags & ~flag_overflow) | ((this.flags & 1) ^ (this.last_result >> 31 & 1)) << 11; + this.flags[0] = (this.flags[0] & ~flag_overflow) | ((this.flags[0] & 1) ^ (this.last_result[0] >> 31 & 1)) << 11; } else { - this.flags &= ~flag_overflow; + this.flags[0] &= ~flag_overflow; } - return this.last_result; + return this.last_result[0]; } CPU.prototype.bt_reg = function(bit_base, bit_offset) { - this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1); - this.flags_changed &= ~1; + this.flags[0] = (this.flags[0] & ~1) | (bit_base >> bit_offset & 1); + this.flags_changed[0] &= ~1; } CPU.prototype.btc_reg = function(bit_base, bit_offset) { - this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1); - this.flags_changed &= ~1; + this.flags[0] = (this.flags[0] & ~1) | (bit_base >> bit_offset & 1); + this.flags_changed[0] &= ~1; return bit_base ^ 1 << bit_offset; } CPU.prototype.bts_reg = function(bit_base, bit_offset) { - this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1); - this.flags_changed &= ~1; + this.flags[0] = (this.flags[0] & ~1) | (bit_base >> bit_offset & 1); + this.flags_changed[0] &= ~1; return bit_base | 1 << bit_offset; } CPU.prototype.btr_reg = function(bit_base, bit_offset) { - this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1); - this.flags_changed &= ~1; + this.flags[0] = (this.flags[0] & ~1) | (bit_base >> bit_offset & 1); + this.flags_changed[0] &= ~1; return bit_base & ~(1 << bit_offset); } @@ -1385,8 +1399,8 @@ CPU.prototype.bt_mem = function(virt_addr, bit_offset) var bit_base = this.safe_read8(virt_addr + (bit_offset >> 3) | 0); bit_offset &= 7; - this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1); - this.flags_changed &= ~1; + this.flags[0] = (this.flags[0] & ~1) | (bit_base >> bit_offset & 1); + this.flags_changed[0] &= ~1; } CPU.prototype.btc_mem = function(virt_addr, bit_offset) @@ -1396,8 +1410,8 @@ CPU.prototype.btc_mem = function(virt_addr, bit_offset) bit_offset &= 7; - this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1); - this.flags_changed &= ~1; + this.flags[0] = (this.flags[0] & ~1) | (bit_base >> bit_offset & 1); + this.flags_changed[0] &= ~1; this.write8(phys_addr, bit_base ^ 1 << bit_offset); } @@ -1409,8 +1423,8 @@ CPU.prototype.btr_mem = function(virt_addr, bit_offset) bit_offset &= 7; - this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1); - this.flags_changed &= ~1; + this.flags[0] = (this.flags[0] & ~1) | (bit_base >> bit_offset & 1); + this.flags_changed[0] &= ~1; this.write8(phys_addr, bit_base & ~(1 << bit_offset)); } @@ -1422,94 +1436,97 @@ CPU.prototype.bts_mem = function(virt_addr, bit_offset) bit_offset &= 7; - this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1); - this.flags_changed &= ~1; + this.flags[0] = (this.flags[0] & ~1) | (bit_base >> bit_offset & 1); + this.flags_changed[0] &= ~1; this.write8(phys_addr, bit_base | 1 << bit_offset); } CPU.prototype.bsf16 = function(old, bit_base) { - this.flags_changed = flags_all & ~flag_zero; - this.last_op_size = OPSIZE_16; + this.flags_changed[0] = flags_all & ~flag_zero; + this.last_op_size[0] = OPSIZE_16; if(bit_base === 0) { - this.flags |= flag_zero; - this.last_result = bit_base; + this.flags[0] |= flag_zero; + this.last_result[0] = bit_base; // not defined in the docs, but value doesn't change on my intel machine return old; } else { - this.flags &= ~flag_zero; + this.flags[0] &= ~flag_zero; // http://jsperf.com/lowest-bit-index - return this.last_result = v86util.int_log2(-bit_base & bit_base); + return this.last_result[0] = v86util.int_log2(-bit_base & bit_base); } } CPU.prototype.bsf32 = function(old, bit_base) { - this.flags_changed = flags_all & ~flag_zero; - this.last_op_size = OPSIZE_32; + this.flags_changed[0] = flags_all & ~flag_zero; + this.last_op_size[0] = OPSIZE_32; if(bit_base === 0) { - this.flags |= flag_zero; - this.last_result = bit_base; + this.flags[0] |= flag_zero; + this.last_result[0] = bit_base; + return old; } else { - this.flags &= ~flag_zero; + this.flags[0] &= ~flag_zero; - return this.last_result = v86util.int_log2((-bit_base & bit_base) >>> 0); + return this.last_result[0] = v86util.int_log2((-bit_base & bit_base) >>> 0); } } CPU.prototype.bsr16 = function(old, bit_base) { - this.flags_changed = flags_all & ~flag_zero; - this.last_op_size = OPSIZE_16; + this.flags_changed[0] = flags_all & ~flag_zero; + this.last_op_size[0] = OPSIZE_16; if(bit_base === 0) { - this.flags |= flag_zero; - this.last_result = bit_base; + this.flags[0] |= flag_zero; + this.last_result[0] = bit_base; + return old; } else { - this.flags &= ~flag_zero; + this.flags[0] &= ~flag_zero; - return this.last_result = v86util.int_log2(bit_base); + return this.last_result[0] = v86util.int_log2(bit_base); } } CPU.prototype.bsr32 = function(old, bit_base) { - this.flags_changed = flags_all & ~flag_zero; - this.last_op_size = OPSIZE_32; + this.flags_changed[0] = flags_all & ~flag_zero; + this.last_op_size[0] = OPSIZE_32; if(bit_base === 0) { - this.flags |= flag_zero; - this.last_result = bit_base; + this.flags[0] |= flag_zero; + this.last_result[0] = bit_base; + return old; } else { - this.flags &= ~flag_zero; - return this.last_result = v86util.int_log2(bit_base >>> 0); + this.flags[0] &= ~flag_zero; + return this.last_result[0] = v86util.int_log2(bit_base >>> 0); } } CPU.prototype.popcnt = function(v) { - this.flags_changed = 0; - this.flags &= ~flags_all; + this.flags_changed[0] = 0; + this.flags[0] &= ~flags_all; if(v) { @@ -1520,7 +1537,7 @@ CPU.prototype.popcnt = function(v) } else { - this.flags |= flag_zero; + this.flags[0] |= flag_zero; return 0; } }; diff --git a/src/browser/lib.js b/src/browser/lib.js index 368849fc..14c08b03 100644 --- a/src/browser/lib.js +++ b/src/browser/lib.js @@ -18,6 +18,42 @@ var ASYNC_SAFE = false; v86util.AsyncFileBuffer = AsyncFileBuffer; v86util.SyncFileBuffer = SyncFileBuffer; + v86util.load_wasm = function load_wasm(filename, imports, cb) { + if (!imports) { + imports = {}; + } + const STATIC_MEMORY_BASE = 64 * 1024 * 1024; // XXX + + v86util.load_file(filename, { done: function(buffer) + { + WebAssembly.compile(buffer) + .then(module => { + if (!imports['env']) { + imports['env'] = {}; + } + imports['env']['___assert_fail'] = (a, b, c, d) => { + console.error('Assertion Failed', a, b, c, d); + dbg_assert(false); + }; + imports['env']['memoryBase'] = STATIC_MEMORY_BASE; + imports['env']['tableBase'] = 0; + imports['env']['memory'] = new WebAssembly.Memory({ ['initial']: 4096, }); + imports['env']['table'] = new WebAssembly.Table({ ['initial']: 18, ['element']: 'anyfunc' }); + return WebAssembly.instantiate(module, imports).then(instance => ({ instance, module })); + }) + .then(({ instance, module }) => { + cb({ + mem: imports['env']['memory'], + funcs: instance['exports'], + instance, + imports, + filename, + }); + }); + } + }); + }; + /** * @param {string} filename * @param {Object} options diff --git a/src/browser/starter.js b/src/browser/starter.js index 2cd969f6..7aa17b9e 100644 --- a/src/browser/starter.js +++ b/src/browser/starter.js @@ -92,7 +92,190 @@ function V86Starter(options) var bus = Bus.create(); var adapter_bus = this.bus = bus[0]; this.emulator_bus = bus[1]; - var emulator = this.v86 = new v86(this.emulator_bus); + var emulator; + var cpu; + var mem; + var wasm_shared_funcs = { + "_throw_cpu_exception": () => { throw MAGIC_CPU_EXCEPTION; }, + "_hlt_op": function() { return cpu.hlt_op(); }, + "abort": function() { dbg_assert(false); }, + "_dbg_assert": function() { return cpu.dbg_assert.apply(cpu, arguments); }, + "_dbg_log": function() { return cpu.dbg_log.apply(cpu, arguments); }, + "_todo": function() { return cpu.todo.apply(cpu, arguments); }, + "_undefined_instruction": function() { return cpu.undefined_instruction.apply(cpu, arguments); }, + "_unimplemented_sse": function() { return cpu.unimplemented_sse_wasm(); }, + "_microtick": function() { return v86.microtick(); }, + "_get_rand_int": function() { return v86util.get_rand_int(); }, + "_has_rand_int": function() { return v86util.has_rand_int(); }, + "_printf": function(offset) { dbg_log_wasm(mem, offset, [].slice.call(arguments, 1)); }, + + "_call_interrupt_vector": function(interrupt_nr, is_software_int, has_error_code, error_code) { + cpu.call_interrupt_vector(interrupt_nr, is_software_int, !!has_error_code, error_code); + }, + "_far_jump": function(eip, selector, is_call) { return cpu.far_jump(eip, selector, !!is_call); }, + "_far_return": function(eip, selector, stack_adjust) { return cpu.far_return(eip, selector, stack_adjust); }, + "_switch_seg": function(reg, selector) { cpu.switch_seg(reg, selector); }, + "_iret16": function() { return cpu.iret16(); }, + "_iret32": function() { return cpu.iret32(); }, + + "_io_port_read8": function(addr) { return cpu.io.port_read8(addr); }, + "_io_port_read16": function(addr) { return cpu.io.port_read16(addr); }, + "_io_port_read32": function(addr) { return cpu.io.port_read32(addr); }, + "_io_port_write8": function(addr, value) { cpu.io.port_write8(addr, value); }, + "_io_port_write16": function(addr, value) { cpu.io.port_write16(addr, value); }, + "_io_port_write32": function(addr, value) { cpu.io.port_write32(addr, value); }, + + "_mmap_read8": function(addr) { return cpu.mmap_read8(addr); }, + "_mmap_read16": function(addr) { return cpu.mmap_read16(addr); }, + "_mmap_read32": function(addr) { return cpu.mmap_read32(addr); }, + "_mmap_write8": function(addr, value) { return cpu.mmap_write8(addr, value); }, + "_mmap_write16": function(addr, value) { return cpu.mmap_write16(addr, value); }, + "_mmap_write32": function(addr, value) { return cpu.mmap_write32(addr, value); }, + + "_fpu_op_D8_reg": function() { return cpu.fpu.op_D8_reg.apply(cpu.fpu, arguments); }, + "_fpu_op_D9_reg": function() { return cpu.fpu.op_D9_reg.apply(cpu.fpu, arguments); }, + "_fpu_op_DA_reg": function() { return cpu.fpu.op_DA_reg.apply(cpu.fpu, arguments); }, + "_fpu_op_DB_reg": function() { return cpu.fpu.op_DB_reg.apply(cpu.fpu, arguments); }, + "_fpu_op_DC_reg": function() { return cpu.fpu.op_DC_reg.apply(cpu.fpu, arguments); }, + "_fpu_op_DD_reg": function() { return cpu.fpu.op_DD_reg.apply(cpu.fpu, arguments); }, + "_fpu_op_DE_reg": function() { return cpu.fpu.op_DE_reg.apply(cpu.fpu, arguments); }, + "_fpu_op_DF_reg": function() { return cpu.fpu.op_DF_reg.apply(cpu.fpu, arguments); }, + + "_fpu_op_D8_mem": function() { return cpu.fpu.op_D8_mem.apply(cpu.fpu, arguments); }, + "_fpu_op_D9_mem": function() { return cpu.fpu.op_D9_mem.apply(cpu.fpu, arguments); }, + "_fpu_op_DA_mem": function() { return cpu.fpu.op_DA_mem.apply(cpu.fpu, arguments); }, + "_fpu_op_DB_mem": function() { return cpu.fpu.op_DB_mem.apply(cpu.fpu, arguments); }, + "_fpu_op_DC_mem": function() { return cpu.fpu.op_DC_mem.apply(cpu.fpu, arguments); }, + "_fpu_op_DD_mem": function() { return cpu.fpu.op_DD_mem.apply(cpu.fpu, arguments); }, + "_fpu_op_DE_mem": function() { return cpu.fpu.op_DE_mem.apply(cpu.fpu, arguments); }, + "_fpu_op_DF_mem": function() { return cpu.fpu.op_DF_mem.apply(cpu.fpu, arguments); }, + "_fwait": function() { return cpu.fpu.fwait(); }, + + "_do_page_translation": function() { return cpu.do_page_translation.apply(cpu, arguments); }, + "_read_reg_e16": function() { return cpu.read_reg_e16.apply(cpu, arguments); }, + "_read_reg_e32s": function() { return cpu.read_reg_e32s.apply(cpu, arguments); }, + "_write_reg_e16": function() { return cpu.write_reg_e16.apply(cpu, arguments); }, + "_write_reg_e32": function() { return cpu.write_reg_e32.apply(cpu, arguments); }, + "_read_moffs": function() { return cpu.read_moffs.apply(cpu, arguments); }, + "_popa16": function() { return cpu.popa16.apply(cpu, arguments); }, + "_popa32": function() { return cpu.popa32.apply(cpu, arguments); }, + "_arpl": function() { return cpu.arpl.apply(cpu, arguments); }, + "_trigger_ud": function() { return cpu.trigger_ud.apply(cpu, arguments); }, + "_trigger_nm": function() { return cpu.trigger_nm.apply(cpu, arguments); }, + "_pop16": function() { return cpu.pop16.apply(cpu, arguments); }, + "_virt_boundary_read16": function() { return cpu.virt_boundary_read16.apply(cpu, arguments); }, + "_virt_boundary_read32s": function() { return cpu.virt_boundary_read32s.apply(cpu, arguments); }, + "_virt_boundary_write16": function() { return cpu.virt_boundary_write16.apply(cpu, arguments); }, + "_virt_boundary_write32": function() { return cpu.virt_boundary_write32.apply(cpu, arguments); }, + "_set_stack_reg": function() { return cpu.set_stack_reg.apply(cpu, arguments); }, + "_getiopl": function() { return cpu.getiopl.apply(cpu, arguments); }, + "_vm86_mode": function() { return cpu.vm86_mode.apply(cpu, arguments); }, + "_shl8": function() { return cpu.shl8.apply(cpu, arguments); }, + "_shr8": function() { return cpu.shr8.apply(cpu, arguments); }, + "_sar8": function() { return cpu.sar8.apply(cpu, arguments); }, + "_shl16": function() { return cpu.shl16.apply(cpu, arguments); }, + "_shr16": function() { return cpu.shr16.apply(cpu, arguments); }, + "_sar16": function() { return cpu.sar16.apply(cpu, arguments); }, + "_shl32": function() { return cpu.shl32.apply(cpu, arguments); }, + "_shr32": function() { return cpu.shr32.apply(cpu, arguments); }, + "_sar32": function() { return cpu.sar32.apply(cpu, arguments); }, + + "_shrd16": function() { return cpu.shrd16.apply(cpu, arguments); }, + "_shrd32": function() { return cpu.shrd32.apply(cpu, arguments); }, + "_shld16": function() { return cpu.shld16.apply(cpu, arguments); }, + "_shld32": function() { return cpu.shld32.apply(cpu, arguments); }, + + "_bt_reg": function() { return cpu.bt_reg.apply(cpu, arguments); }, + "_bt_mem": function() { return cpu.bt_mem.apply(cpu, arguments); }, + "_btr_reg": function() { return cpu.btr_reg.apply(cpu, arguments); }, + "_btr_mem": function() { return cpu.btr_mem.apply(cpu, arguments); }, + "_btc_reg": function() { return cpu.btc_reg.apply(cpu, arguments); }, + "_btc_mem": function() { return cpu.btc_mem.apply(cpu, arguments); }, + "_bts_reg": function() { return cpu.bts_reg.apply(cpu, arguments); }, + "_bts_mem": function() { return cpu.bts_mem.apply(cpu, arguments); }, + + "_bsf16": function() { return cpu.bsf16.apply(cpu, arguments); }, + "_bsf32": function() { return cpu.bsf32.apply(cpu, arguments); }, + "_bsr16": function() { return cpu.bsr16.apply(cpu, arguments); }, + "_bsr32": function() { return cpu.bsr32.apply(cpu, arguments); }, + "_popcnt": function() { return cpu.popcnt.apply(cpu, arguments); }, + "_bswap": function() { return cpu.bswap.apply(cpu, arguments); }, + + "_setcc": function() { return cpu.setcc.apply(cpu, arguments); }, + "_cmovcc16": function() { return cpu.cmovcc16.apply(cpu, arguments); }, + "_cmovcc32": function() { return cpu.cmovcc32.apply(cpu, arguments); }, + + "_lar": function() { return cpu.lar.apply(cpu, arguments); }, + "_lsl": function() { return cpu.lsl.apply(cpu, arguments); }, + "_verw": function() { return cpu.verw.apply(cpu, arguments); }, + "_verr": function() { return cpu.verr.apply(cpu, arguments); }, + + "_full_clear_tlb": function() { return cpu.full_clear_tlb.apply(cpu, arguments); }, + "_invlpg": function() { return cpu.invlpg.apply(cpu, arguments); }, + "_writable_or_pagefault": function() { return cpu.writable_or_pagefault.apply(cpu, arguments); }, + + "_cpl_changed": function() { return cpu.cpl_changed.apply(cpu, arguments); }, + "_set_cr0": function() { return cpu.set_cr0.apply(cpu, arguments); }, + "_update_cs_size": function() { return cpu.update_cs_size.apply(cpu, arguments); }, + "_clear_tlb": function() { return cpu.clear_tlb.apply(cpu, arguments); }, + "_cpuid": function() { return cpu.cpuid.apply(cpu, arguments); }, + + "_load_ldt": function() { return cpu.load_ldt.apply(cpu, arguments); }, + "_load_tr": function() { return cpu.load_tr.apply(cpu, arguments); }, + + "_idiv16": function() { return cpu.idiv16.apply(cpu, arguments); }, + "_div32": function() { return cpu.div32.apply(cpu, arguments); }, + "_idiv32": function() { return cpu.idiv32.apply(cpu, arguments); }, + "_insb": function() { return cpu.insb.apply(cpu, arguments); }, + "_insw": function() { return cpu.insw.apply(cpu, arguments); }, + "_insd": function() { return cpu.insd.apply(cpu, arguments); }, + "_outsb": function() { return cpu.outsb.apply(cpu, arguments); }, + "_outsw": function() { return cpu.outsw.apply(cpu, arguments); }, + "_outsd": function() { return cpu.outsd.apply(cpu, arguments); }, + "_movsb": function() { return cpu.movsb.apply(cpu, arguments); }, + "_movsw": function() { return cpu.movsw.apply(cpu, arguments); }, + "_movsd": function() { return cpu.movsd.apply(cpu, arguments); }, + "_cmpsb": function() { return cpu.cmpsb.apply(cpu, arguments); }, + "_cmpsw": function() { return cpu.cmpsw.apply(cpu, arguments); }, + "_cmpsd": function() { return cpu.cmpsd.apply(cpu, arguments); }, + "_stosb": function() { return cpu.stosb.apply(cpu, arguments); }, + "_stosw": function() { return cpu.stosw.apply(cpu, arguments); }, + "_stosd": function() { return cpu.stosd.apply(cpu, arguments); }, + "_lodsb": function() { return cpu.lodsb.apply(cpu, arguments); }, + "_lodsw": function() { return cpu.lodsw.apply(cpu, arguments); }, + "_lodsd": function() { return cpu.lodsd.apply(cpu, arguments); }, + "_scasb": function() { return cpu.scasb.apply(cpu, arguments); }, + "_scasw": function() { return cpu.scasw.apply(cpu, arguments); }, + "_scasd": function() { return cpu.scasd.apply(cpu, arguments); }, + "_lss16": function() { return cpu.lss16.apply(cpu, arguments); }, + "_lss32": function() { return cpu.lss32.apply(cpu, arguments); }, + "_enter16": function() { return cpu.enter16.apply(cpu, arguments); }, + "_enter32": function() { return cpu.enter32.apply(cpu, arguments); }, + "_update_eflags": function() { return cpu.update_eflags.apply(cpu, arguments); }, + "_handle_irqs": function() { return cpu.handle_irqs.apply(cpu, arguments); }, + "_get_real_eip": function() { return cpu.get_real_eip.apply(cpu, arguments); }, + "_xchg8": function() { return cpu.xchg8.apply(cpu, arguments); }, + "_xchg16": function() { return cpu.xchg16.apply(cpu, arguments); }, + "_xchg16r": function() { return cpu.xchg16r.apply(cpu, arguments); }, + "_xchg32": function() { return cpu.xchg32.apply(cpu, arguments); }, + "_xchg32r": function() { return cpu.xchg32r.apply(cpu, arguments); }, + "_loop": function() { return cpu.loop.apply(cpu, arguments); }, + "_loope": function() { return cpu.loope.apply(cpu, arguments); }, + "_loopne": function() { return cpu.loopne.apply(cpu, arguments); }, + "_bcd_aam": function() { return cpu.bcd_aam.apply(cpu, arguments); }, + "_task_switch_test": function() { return cpu.task_switch_test.apply(cpu, arguments); }, + "_jcxz": function() { return cpu.jcxz.apply(cpu, arguments); }, + "_test_privileges_for_io": function() { return cpu.test_privileges_for_io.apply(cpu, arguments); }, + + "_fxsave": function() { return cpu.fxsave.apply(cpu, arguments); }, + "_fxrstor": function() { return cpu.fxrstor.apply(cpu, arguments); }, + }; + + let wasm_file = DEBUG ? "v86-debug.wasm" : "v86.wasm"; + v86util.load_wasm("build/" + wasm_file, { 'env': wasm_shared_funcs }, wm => { + emulator = this.v86 = new v86(this.emulator_bus, wm); + cpu = emulator.cpu; + mem = wm.mem.buffer; this.bus.register("emulator-stopped", function() { @@ -423,6 +606,8 @@ function V86Starter(options) }.bind(this), 0); }.bind(this), 0); } + + }); } /** @@ -627,7 +812,7 @@ V86Starter.prototype.get_instruction_counter = function() { if(this.v86) { - return this.v86.cpu.timestamp_counter; + return this.v86.cpu.timestamp_counter[0]; } else { diff --git a/src/config.js b/src/config.js index 6890fad4..4fe8dcbd 100644 --- a/src/config.js +++ b/src/config.js @@ -26,7 +26,7 @@ var LOG_PAGE_FAULTS = false; var LOG_LEVEL = LOG_ALL & ~LOG_PS2 & ~LOG_PIT & ~LOG_VIRTIO & ~LOG_9P & ~LOG_PIC & - ~LOG_DMA & ~LOG_SERIAL & ~LOG_NET & ~LOG_FLOPPY & ~LOG_DISK; + ~LOG_DMA & ~LOG_SERIAL & ~LOG_NET & ~LOG_FLOPPY & ~LOG_DISK & ~LOG_VGA; /** @const */ diff --git a/src/cpu.js b/src/cpu.js index 699f8dd4..ee350f91 100644 --- a/src/cpu.js +++ b/src/cpu.js @@ -1,7 +1,7 @@ "use strict"; /** @const */ -var CPU_LOG_VERBOSE = true; +var CPU_LOG_VERBOSE = false; // Resources: @@ -11,14 +11,17 @@ var CPU_LOG_VERBOSE = true; /** @constructor */ -function CPU(bus) +function CPU(bus, wm) { - /** @type {number} */ - this.memory_size = 0; + this.wm = wm; + this.wasm_patch(wm); + + this.memory_size = new Uint32Array(wm.mem.buffer, 812, 1); // Note: Currently unused (degrades performance and not required by any OS // that we support) - this.a20_enabled = true; + this.a20_enabled = new Int32Array(wm.mem.buffer, 552, 1); + this.a20_enabled[0] = +true; this.mem_page_infos = undefined; @@ -26,16 +29,16 @@ function CPU(bus) this.mem16 = new Uint16Array(this.mem8.buffer); this.mem32s = new Int32Array(this.mem8.buffer); - this.segment_is_null = new Uint8Array(8); - this.segment_limits = new Uint32Array(8); - //this.segment_infos = new Uint32Array(8); - this.segment_offsets = new Int32Array(8); + this.segment_is_null = new Uint8Array(wm.mem.buffer, 724, 8); + this.segment_offsets = new Int32Array(wm.mem.buffer, 736, 8); + this.segment_limits = new Uint32Array(wm.mem.buffer, 768, 8); + //this.segment_infos = []; /** * Translation Lookaside Buffer * @const */ - this.tlb_data = new Int32Array(1 << 20); + this.tlb_data = new Int32Array(wm.mem.buffer, 2048 + 0x100000*2, 0x100000); /** * Information about which pages are cached in the tlb. @@ -46,35 +49,27 @@ function CPU(bus) * 3 user, write * @const */ - this.tlb_info = new Uint8Array(1 << 20); + this.tlb_info = new Uint8Array(wm.mem.buffer, 2048, 0x100000); /** * Same as tlb_info, except it only contains global pages * @const */ - this.tlb_info_global = new Uint8Array(1 << 20); + this.tlb_info_global = new Uint8Array(wm.mem.buffer, 2048 + 0x100000, 0x100000); /** * Wheter or not in protected mode - * @type {boolean} */ - this.protected_mode = false; + this.protected_mode = new Int32Array(wm.mem.buffer, 800, 1); - /** - * interrupt descriptor table - * @type {number} - */ - this.idtr_size = 0; - /** @type {number} */ - this.idtr_offset = 0; + this.idtr_size = new Int32Array(wm.mem.buffer, 564, 1); + this.idtr_offset = new Int32Array(wm.mem.buffer, 568, 1); /** * global descriptor table register - * @type {number} */ - this.gdtr_size = 0; - /** @type {number} */ - this.gdtr_offset = 0; + this.gdtr_size = new Int32Array(wm.mem.buffer, 572, 1); + this.gdtr_offset = new Int32Array(wm.mem.buffer, 576, 1); this.tss_size_32 = false; @@ -83,7 +78,7 @@ function CPU(bus) */ this.page_fault = false; - this.cr = new Int32Array(8); + this.cr = new Int32Array(wm.mem.buffer, 580, 8); /** @type {number} */ this.cr[0] = 0; @@ -95,19 +90,15 @@ function CPU(bus) this.cr[4] = 0; // current privilege level - /** @type {number} */ - this.cpl = 0; + this.cpl = new Int32Array(wm.mem.buffer, 612, 1); // if false, pages are 4 KiB, else 4 Mib - /** @type {number} */ - this.page_size_extensions = 0; + this.page_size_extensions = new Int32Array(wm.mem.buffer, 616, 1); // current operand/address size - /** @type {boolean} */ - this.is_32 = false; + this.is_32 = new Int32Array(wm.mem.buffer, 804, 1); - /** @type {boolean} */ - this.stack_size_32 = false; + this.stack_size_32 = new Int32Array(wm.mem.buffer, 808, 1); /** * Was the last instruction a hlt? @@ -115,70 +106,52 @@ function CPU(bus) */ this.in_hlt = false; - /** @type {number} */ - this.last_virt_eip = 0; + this.last_virt_eip = new Int32Array(wm.mem.buffer, 620, 1); - /** @type {number} */ - this.eip_phys = 0; + this.eip_phys = new Int32Array(wm.mem.buffer, 624, 1); - /** @type {number} */ - this.last_virt_esp = 0; + this.last_virt_esp = new Int32Array(wm.mem.buffer, 628, 1); - /** @type {number} */ - this.esp_phys = 0; + this.esp_phys = new Int32Array(wm.mem.buffer, 632, 1); - /** @type {number} */ - this.sysenter_cs = 0; + this.sysenter_cs = new Int32Array(wm.mem.buffer, 636, 1); - /** @type {number} */ - this.sysenter_esp = 0; + this.sysenter_esp = new Int32Array(wm.mem.buffer, 640, 1); - /** @type {number} */ - this.sysenter_eip = 0; + this.sysenter_eip = new Int32Array(wm.mem.buffer, 644, 1); - /** @type {number} */ - this.prefixes = 0; + this.prefixes = new Int32Array(wm.mem.buffer, 648, 1); - /** @type {number} */ - this.flags = 0; + this.flags = new Int32Array(wm.mem.buffer, 536, 1); /** * bitmap of flags which are not updated in the flags variable * changed by arithmetic instructions, so only relevant to arithmetic flags - * @type {number} */ - this.flags_changed = 0; + this.flags_changed = new Int32Array(wm.mem.buffer, 532, 1); /** * the last 2 operators and the result and size of the last arithmetic operation - * @type {number} */ - this.last_op1 = 0; - /** @type {number} */ - this.last_op2 = 0; - /** @type {number} */ - this.last_op_size = 0; + this.last_op1 = new Int32Array(wm.mem.buffer, 512, 1); + this.last_op2 = new Int32Array(wm.mem.buffer, 516, 1); + this.last_op_size = new Int32Array(wm.mem.buffer, 520, 1); - /** @type {number} */ - this.last_add_result = 0; + this.last_add_result = new Int32Array(wm.mem.buffer, 524, 1); - /** @type {number} */ - this.last_result = 0; + this.last_result = new Int32Array(wm.mem.buffer, 528, 1); - this.mul32_result = new Int32Array(2); + this.mul32_result = new Int32Array(wm.mem.buffer, 544, 2); this.div32_result = new Float64Array(2); - this.tsc_offset = 0; + this.tsc_offset = new Int32Array(wm.mem.buffer, 652, 1); - /** @type {number} */ - this.modrm_byte = 0; + this.modrm_byte = new Int32Array(wm.mem.buffer, 540, 1); - /** @type {number} */ - this.phys_addr = 0; + this.phys_addr = new Int32Array(wm.mem.buffer, 656, 1); - /** @type {number} */ - this.phys_addr_high = 0; + this.phys_addr_high = new Int32Array(wm.mem.buffer, 660, 1); /** @type {!Object} */ this.devices = {}; @@ -186,46 +159,14 @@ function CPU(bus) this.table = []; // paging enabled - /** @type {boolean} */ - this.paging = false; + this.paging = new Uint8Array(wm.mem.buffer, 820, 1); - /** @type {number} */ - this.instruction_pointer = 0; + this.instruction_pointer = new Int32Array(wm.mem.buffer, 556, 1); - /** @type {number} */ - this.previous_ip = 0; + this.previous_ip = new Int32Array(wm.mem.buffer, 560, 1); this.apic_enabled = true; - /** - * @type {number} - */ - this.timestamp_counter = 0; - - // registers - this.reg32s = new Int32Array(8); - this.reg32 = new Uint32Array(this.reg32s.buffer); - this.reg16s = new Int16Array(this.reg32s.buffer); - this.reg16 = new Uint16Array(this.reg32s.buffer); - this.reg8s = new Int8Array(this.reg32s.buffer); - this.reg8 = new Uint8Array(this.reg32s.buffer); - - // mm0-mm7 split up into 32 bit pairs - this.reg_mmxs = new Int32Array(16); - this.reg_mmx = new Uint32Array(this.reg_mmxs.buffer); - this.reg_mmx8s = new Int8Array(this.reg_mmxs.buffer); - this.reg_mmx8 = new Uint8Array(this.reg_mmxs.buffer); - - this.reg_xmm32s = new Int32Array(8 * 4); - this.mxcsr = 0x1F80; - - // segment registers, tr and ldtr - this.sreg = new Uint16Array(8); - - // debug registers - this.dreg = new Int32Array(8); - - // managed in io.js /** @const */ this.memory_map_read8 = []; /** @const */ this.memory_map_write8 = []; @@ -241,8 +182,32 @@ function CPU(bus) vga: null, }; - /** @type {number} */ - this.fw_value = 0; + this.timestamp_counter = new Int32Array(wm.mem.buffer, 664, 1); + + // registers + this.reg32s = new Int32Array(wm.mem.buffer, 4, 8); + this.reg32 = new Uint32Array(this.reg32s.buffer, 4, 8); + this.reg16s = new Int16Array(this.reg32s.buffer, 4, 16); + this.reg16 = new Uint16Array(this.reg32s.buffer, 4, 16); + this.reg8s = new Int8Array(this.reg32s.buffer, 4, 32); + this.reg8 = new Uint8Array(this.reg32s.buffer, 4, 32); + + // mm0-mm7 split up into 32 bit pairs + this.reg_mmxs = new Int32Array(16); + this.reg_mmx = new Uint32Array(this.reg_mmxs.buffer); + this.reg_mmx8s = new Int8Array(this.reg_mmxs.buffer); + this.reg_mmx8 = new Uint8Array(this.reg_mmxs.buffer); + + this.reg_xmm32s = new Int32Array(8 * 4); + this.mxcsr = new Int32Array(wm.mem.buffer, 824, 1); + + // segment registers, tr and ldtr + this.sreg = new Uint16Array(wm.mem.buffer, 668, 8); + + // debug registers + this.dreg = new Int32Array(wm.mem.buffer, 684, 8); + + this.fw_value = new Int32Array(wm.mem.buffer, 720, 1); this.io = undefined; this.fpu = undefined; @@ -254,7 +219,7 @@ function CPU(bus) this.update_operand_size(); - this.tsc_offset = v86.microtick(); + this.tsc_offset[0] = v86.microtick(); this.debug_init(); @@ -263,44 +228,115 @@ function CPU(bus) //Object.seal(this); } +CPU.prototype.wasm_patch = function(wm) +{ + this.add = this.wm.funcs['_add']; + this.adc = this.wm.funcs['_adc']; + this.sub = this.wm.funcs['_sub']; + this.sbb = this.wm.funcs['_sbb']; + this.inc = this.wm.funcs['_inc']; + this.dec = this.wm.funcs['_dec']; + this.neg = this.wm.funcs['_neg']; + this.mul8 = this.wm.funcs['_mul8']; + this.imul8 = this.wm.funcs['_imul8']; + this.mul16 = this.wm.funcs['_mul16']; + this.imul16 = this.wm.funcs['_imul16']; + this.imul_reg16 = this.wm.funcs['_imul_reg16']; + this.mul32 = this.wm.funcs['_mul32']; + this.imul32 = this.wm.funcs['_imul32']; + this.imul_reg32 = this.wm.funcs['_imul_reg32']; + this.xadd8 = this.wm.funcs['_xadd8']; + this.xadd16 = this.wm.funcs['_xadd16']; + this.xadd32 = this.wm.funcs['_xadd32']; + this.bcd_daa = this.wm.funcs['_bcd_daa']; + this.bcd_das = this.wm.funcs['_bcd_das']; + this.bcd_aad = this.wm.funcs['_bcd_aad']; + this.bcd_aaa = this.wm.funcs['_bcd_aaa']; + this.bcd_aas = this.wm.funcs['_bcd_aas']; + this.and = this.wm.funcs['_and']; + this.or = this.wm.funcs['_or']; + this.xor = this.wm.funcs['_xor']; + this.rol8 = this.wm.funcs['_rol8']; + this.rol16 = this.wm.funcs['_rol16']; + this.rol32 = this.wm.funcs['_rol32']; + this.rcl8 = this.wm.funcs['_rcl8']; + this.rcl16 = this.wm.funcs['_rcl16']; + this.rcl32 = this.wm.funcs['_rcl32']; + this.ror8 = this.wm.funcs['_ror8']; + this.ror16 = this.wm.funcs['_ror16']; + this.ror32 = this.wm.funcs['_ror32']; + this.rcr8 = this.wm.funcs['_rcr8']; + this.rcr16 = this.wm.funcs['_rcr16']; + this.rcr32 = this.wm.funcs['_rcr32']; + this.div8 = this.wm.funcs['_div8']; + this.idiv8 = this.wm.funcs['_idiv8']; + this.div16 = this.wm.funcs['_div16']; + this.getcf = this.wm.funcs['_getcf']; + this.getaf = this.wm.funcs['_getaf']; + this.raise_exception = this.wm.funcs['_raise_exception']; + this.raise_exception_with_code = this.wm.funcs['_raise_exception_with_code']; + this.trigger_de = this.wm.funcs['_trigger_de']; + this.trigger_gp = this.wm.funcs['_trigger_gp']; + + this.do_many_cycles_unsafe = this.wm.funcs['_do_many_cycles_unsafe']; + + this.read_imm8 = this.wm.funcs['_read_imm8']; + this.read_imm8s = this.wm.funcs['_read_imm8s']; + this.read_imm16 = this.wm.funcs['_read_imm16']; + this.read_imm32s = this.wm.funcs['_read_imm32s']; + this.read_write_e8 = this.wm.funcs['_read_write_e8']; + this.write_e8 = this.wm.funcs['_write_e8']; + this.in_mapped_range = this.wm.funcs['_in_mapped_range']; + this.read16 = this.wm.funcs['_read16']; + this.read_aligned16 = this.wm.funcs['_read_aligned16']; + this.read32s = this.wm.funcs['_read32s']; + this.write8 = this.wm.funcs['_write8']; + this.write16 = this.wm.funcs['_write16']; + this.write32 = this.wm.funcs['_write32']; + this.push16 = this.wm.funcs['_push16']; + this.push32 = this.wm.funcs['_push32']; + this.pusha16 = this.wm.funcs['_pusha16']; + this.pusha32 = this.wm.funcs['_pusha32']; +}; + CPU.prototype.get_state = function() { var state = []; - state[0] = this.memory_size; + state[0] = this.memory_size[0]; state[1] = this.segment_is_null; state[2] = this.segment_offsets; state[3] = this.segment_limits; - state[4] = this.protected_mode; - state[5] = this.idtr_offset; - state[6] = this.idtr_size; - state[7] = this.gdtr_offset; - state[8] = this.gdtr_size; + state[4] = this.protected_mode[0]; + state[5] = this.idtr_offset[0]; + state[6] = this.idtr_size[0]; + state[7] = this.gdtr_offset[0]; + state[8] = this.gdtr_size[0]; state[9] = this.page_fault; state[10] = this.cr; - state[11] = this.cpl; - state[12] = this.page_size_extensions; - state[13] = this.is_32; + state[11] = this.cpl[0]; + state[12] = this.page_size_extensions[0]; + state[13] = this.is_32[0]; - state[16] = this.stack_size_32; + state[16] = this.stack_size_32[0]; state[17] = this.in_hlt; - state[18] = this.last_virt_eip; - state[19] = this.eip_phys; - state[20] = this.last_virt_esp; - state[21] = this.esp_phys; - state[22] = this.sysenter_cs; - state[23] = this.sysenter_eip; - state[24] = this.sysenter_esp; - state[25] = this.prefixes; + state[18] = this.last_virt_eip[0]; + state[19] = this.eip_phys[0]; + state[20] = this.last_virt_esp[0]; + state[21] = this.esp_phys[0]; + state[22] = this.sysenter_cs[0]; + state[23] = this.sysenter_eip[0]; + state[24] = this.sysenter_esp[0]; + state[25] = this.prefixes[0]; state[26] = this.flags; state[27] = this.flags_changed; state[28] = this.last_op1; state[29] = this.last_op2; state[30] = this.last_op_size; state[31] = this.last_add_result; - state[32] = this.modrm_byte; + state[32] = this.modrm_byte[0]; - state[36] = this.paging; + state[36] = this.paging[0]; state[37] = this.instruction_pointer; state[38] = this.previous_ip; state[39] = this.reg32s; @@ -326,8 +362,12 @@ CPU.prototype.get_state = function() state[59] = this.devices.net; state[60] = this.devices.pic; - state[61] = this.a20_enabled; - state[62] = this.fw_value; + state[61] = this.a20_enabled[0]; + state[62] = this.fw_value[0]; + + state[63] = this.devices.ioapic; + + state[64] = this.tss_size_32; state[63] = this.devices.ioapic; @@ -340,32 +380,32 @@ CPU.prototype.get_state = function() CPU.prototype.set_state = function(state) { - this.memory_size = state[0]; + this.memory_size[0] = state[0]; this.segment_is_null = state[1]; this.segment_offsets = state[2]; this.segment_limits = state[3]; - this.protected_mode = state[4]; - this.idtr_offset = state[5]; - this.idtr_size = state[6]; - this.gdtr_offset = state[7]; - this.gdtr_size = state[8]; + this.protected_mode[0] = state[4]; + this.idtr_offset[0] = state[5]; + this.idtr_size[0] = state[6]; + this.gdtr_offset[0] = state[7]; + this.gdtr_size[0] = state[8]; this.page_fault = state[9]; this.cr = state[10]; - this.cpl = state[11]; - this.page_size_extensions = state[12]; - this.is_32 = state[13]; + this.cpl[0] = state[11]; + this.page_size_extensions[0] = state[12]; + this.is_32[0] = state[13]; - this.stack_size_32 = state[16]; + this.stack_size_32[0] = state[16]; this.in_hlt = state[17]; - this.last_virt_eip = state[18]; - this.eip_phys = state[19]; - this.last_virt_esp = state[20]; - this.esp_phys = state[21]; - this.sysenter_cs = state[22]; - this.sysenter_eip = state[23]; - this.sysenter_esp = state[24]; - this.prefixes = state[25]; + this.last_virt_eip[0] = state[18]; + this.eip_phys[0] = state[19]; + this.last_virt_esp[0] = state[20]; + this.esp_phys[0] = state[21]; + this.sysenter_cs[0] = state[22]; + this.sysenter_eip[0] = state[23]; + this.sysenter_esp[0] = state[24]; + this.prefixes[0] = state[25]; this.flags = state[26]; this.flags_changed = state[27]; @@ -375,7 +415,7 @@ CPU.prototype.set_state = function(state) this.last_add_result = state[31]; this.modrm_byte = state[32]; - this.paging = state[36]; + this.paging[0] = state[36]; this.instruction_pointer = state[37]; this.previous_ip = state[38]; this.reg32s = state[39]; @@ -401,8 +441,12 @@ CPU.prototype.set_state = function(state) this.devices.net = state[59]; this.devices.pic = state[60]; - this.a20_enabled = state[61]; - this.fw_value = state[62]; + this.a20_enabled[0] = state[61]; + this.fw_value[0] = state[62]; + + this.devices.ioapic = state[63]; + + this.tss_size_32 = state[64]; this.devices.ioapic = state[63]; @@ -491,25 +535,17 @@ CPU.prototype.reboot_internal = function() CPU.prototype.reset = function() { - this.a20_enabled = true; + this.a20_enabled[0] = +true; - for(let i = 0; i < 8; i++) - { - this.segment_is_null[i] = 0; - this.segment_limits[i] = 0; - //this.segment_infos = new Uint32Array(8); - this.segment_offsets[i] = 0; - } + this.segment_is_null.fill(0); + this.segment_limits.fill(0); + //this.segment_infos = new Uint32Array(8); + this.segment_offsets.fill(0); - this.full_clear_tlb(); + this.reg32s.fill(0); - for(let i = 0; i < 8; i++) - { - this.reg32s[i] = 0; - this.sreg[i] = 0; - this.cr[i] = 0; - this.dreg[i] = 0; - } + this.sreg.fill(0); + this.dreg.fill(0); for(let i = 0; i < this.reg_mmxs.length; i++) { @@ -520,16 +556,18 @@ CPU.prototype.reset = function() { this.reg_xmm32s[i] = 0; } - this.mxcsr = 0x1F80; + this.mxcsr[0] = 0x1F80; - this.protected_mode = false; + this.full_clear_tlb(); + + this.protected_mode[0] = +false; // http://www.sandpile.org/x86/initial.htm - this.idtr_size = 0; - this.idtr_offset = 0; + this.idtr_size[0] = 0; + this.idtr_offset[0] = 0; - this.gdtr_size = 0; - this.gdtr_offset = 0; + this.gdtr_size[0] = 0; + this.gdtr_offset[0] = 0; this.page_fault = false; this.cr[0] = 1 << 30 | 1 << 29 | 1 << 4; @@ -538,38 +576,38 @@ CPU.prototype.reset = function() this.cr[4] = 0; this.dreg[6] = 0xFFFF0FF0|0; this.dreg[7] = 0x400; - this.cpl = 0; - this.paging = false; - this.page_size_extensions = 0; - this.is_32 = false; - this.stack_size_32 = false; - this.prefixes = 0; + this.cpl[0] = 0; + this.paging[0] = 0; + this.page_size_extensions[0] = 0; + this.is_32[0] = +false; + this.stack_size_32[0] = +false; + this.prefixes[0] = 0; - this.last_virt_eip = -1; - this.last_virt_esp = -1; + this.last_virt_eip[0] = -1; + this.last_virt_esp[0] = -1; this.update_operand_size(); - this.timestamp_counter = 0; - this.previous_ip = 0; + this.timestamp_counter[0] = 0; + this.previous_ip[0] = 0; this.in_hlt = false; - this.sysenter_cs = 0; - this.sysenter_esp = 0; - this.sysenter_eip = 0; + this.sysenter_cs[0] = 0; + this.sysenter_esp[0] = 0; + this.sysenter_eip[0] = 0; - this.flags = flags_default; - this.flags_changed = 0; + this.flags[0] = flags_default; + this.flags_changed.fill(0); - this.last_result = 0; - this.last_add_result = 0; - this.last_op1 = 0; - this.last_op2 = 0; - this.last_op_size = 0; + this.last_result.fill(0); + this.last_add_result.fill(0); + this.last_op1.fill(0); + this.last_op2.fill(0); + this.last_op_size.fill(0); - this.tsc_offset = v86.microtick(); + this.tsc_offset[0] = v86.microtick(); - this.instruction_pointer = 0xFFFF0; + this.instruction_pointer[0] = 0xFFFF0; this.switch_cs_real_mode(0xF000); this.switch_seg(reg_ss, 0x30); @@ -580,7 +618,7 @@ CPU.prototype.reset = function() this.devices.virtio.reset(); } - this.fw_value = 0; + this.fw_value[0] = 0; }; /** @export */ @@ -599,13 +637,13 @@ CPU.prototype.create_memory = function(size) dbg_assert((size | 0) > 0); dbg_assert((size & MMAP_BLOCK_SIZE - 1) === 0); - this.memory_size = size; + this.memory_size[0] = size; - var buffer = new ArrayBuffer(size); + var buffer = this.wm.mem.buffer; - this.mem8 = new Uint8Array(buffer); - this.mem16 = new Uint16Array(buffer); - this.mem32s = new Int32Array(buffer); + this.mem8 = new Uint8Array(buffer, 2048 + 0x100000 * 6); + this.mem16 = new Uint16Array(buffer, 2048 + 0x100000 * 6); + this.mem32s = new Int32Array(buffer, 2048 + 0x100000 * 6); }; CPU.prototype.init = function(settings, device_bus) @@ -645,8 +683,8 @@ CPU.prototype.init = function(settings, device_bus) io.register_read(0x511, this, function() { // bios config port (used by seabios and kvm-unit-test) - let result = this.fw_value & 0xFF; - this.fw_value >>>= 8; + let result = this.fw_value[0] & 0xFF; + this.fw_value[0] >>>= 8; return result; }); io.register_write(0x510, this, undefined, function(value) @@ -657,20 +695,20 @@ CPU.prototype.init = function(settings, device_bus) { // We could pretend to be QEMU here to control certain options in // seabios, but for now this isn't needed - this.fw_value = 0xfab0fab0|0; + this.fw_value[0] = 0xfab0fab0|0; } else if(value === FW_CFG_RAM_SIZE) { - this.fw_value = this.memory_size; + this.fw_value[0] = this.memory_size[0]; } else if(value === FW_CFG_NB_CPUS) { - this.fw_value = 1; + this.fw_value[0] = 1; } else { dbg_assert(false, "Unimplemented fw index: " + h(value)); - this.fw_value = 0; + this.fw_value[0] = 0; } }); @@ -811,10 +849,10 @@ CPU.prototype.load_multiboot = function(buffer) this.write32(multiboot_info_addr, 0); this.cr[0] = 1; - this.protected_mode = true; - this.flags = flags_default; + this.protected_mode[0] = +true; + this.flags[0] = flags_default; this.update_cs_size(true); - this.stack_size_32 = true; + this.stack_size_32[0] = +true; for(var i = 0; i < 6; i++) { @@ -860,7 +898,7 @@ CPU.prototype.load_multiboot = function(buffer) let blob = new Uint8Array(buffer, file_start, length); this.write_blob(blob, load_addr); - this.instruction_pointer = this.get_seg(reg_cs) + entry_addr | 0; + this.instruction_pointer[0] = this.get_seg(reg_cs) + entry_addr | 0; } else if(buf32[0] === ELF_MAGIC) { @@ -868,7 +906,7 @@ CPU.prototype.load_multiboot = function(buffer) let elf = read_elf(buffer); - this.instruction_pointer = this.get_seg(reg_cs) + elf.header.entry | 0; + this.instruction_pointer[0] = this.get_seg(reg_cs) + elf.header.entry | 0; for(let program of elf.program_headers) { @@ -964,9 +1002,9 @@ CPU.prototype.fill_cmos = function(rtc, settings) rtc.cmos_write(CMOS_MEM_BASE_HIGH, 640 >> 8); var memory_above_1m = 0; // in k - if(this.memory_size >= 1024 * 1024) + if(this.memory_size[0] >= 1024 * 1024) { - memory_above_1m = (this.memory_size - 1024 * 1024) >> 10; + memory_above_1m = (this.memory_size[0] - 1024 * 1024) >> 10; memory_above_1m = Math.min(memory_above_1m, 0xFFFF); } @@ -976,9 +1014,9 @@ CPU.prototype.fill_cmos = function(rtc, settings) rtc.cmos_write(CMOS_MEM_EXTMEM_HIGH, memory_above_1m >> 8 & 0xFF); var memory_above_16m = 0; // in 64k blocks - if(this.memory_size >= 16 * 1024 * 1024) + if(this.memory_size[0] >= 16 * 1024 * 1024) { - memory_above_16m = (this.memory_size - 16 * 1024 * 1024) >> 16; + memory_above_16m = (this.memory_size[0] - 16 * 1024 * 1024) >> 16; memory_above_16m = Math.min(memory_above_16m, 0xFFFF); } rtc.cmos_write(CMOS_MEM_EXTMEM2_LOW, memory_above_16m & 0xFF); @@ -1096,6 +1134,7 @@ CPU.prototype.do_many_cycles = function() CPU.prototype.do_many_cycles_unsafe = function() { + dbg_assert(false); // inner loop: // runs only cycles for(var k = LOOP_COUNTER; k--;) @@ -1151,9 +1190,9 @@ if(PROFILING) */ CPU.prototype.cycle_internal = function() { - this.previous_ip = this.instruction_pointer; + this.previous_ip[0] = this.instruction_pointer[0]; - this.timestamp_counter++; + this.timestamp_counter[0]++; if(PROFILING) { @@ -1165,7 +1204,7 @@ CPU.prototype.cycle_internal = function() if(DEBUG) { - this.debug.logop(this.instruction_pointer - 1 >>> 0, opcode); + this.debug.logop(this.instruction_pointer[0] - 1 >>> 0, opcode); } // call the instruction @@ -1178,7 +1217,7 @@ CPU.prototype.cycle_internal = function() instruction_count[opcode]++; } - if(this.flags & flag_trap) + if(this.flags[0] & flag_trap) { // TODO dbg_log("Trap flag: Ignored", LOG_CPU); @@ -1198,12 +1237,34 @@ CPU.prototype.cycle = function() } }; +CPU.prototype.run_instruction_0f = function() +{ + if(this.is_osize_32()) + { + this.table0F_32[this.read_op0F()](this); + } + else + { + this.table0F_16[this.read_op0F()](this); + } +}; + +CPU.prototype.dbg_log = function() +{ + dbg_log("from wasm: " + [].join.call(arguments)); +}; + +CPU.prototype.dbg_assert = function(x) +{ + dbg_assert(x); +}; + CPU.prototype.segment_prefix_op = function(sreg) { dbg_assert(sreg <= 5); - this.prefixes |= sreg + 1; + this.prefixes[0] |= sreg + 1; this.run_prefix_instruction(); - this.prefixes = 0; + this.prefixes[0] = 0; }; CPU.prototype.run_prefix_instruction = function() @@ -1220,7 +1281,7 @@ CPU.prototype.run_prefix_instruction = function() CPU.prototype.hlt_loop = function() { - dbg_assert(this.flags & flag_interrupt); + dbg_assert(this.flags[0] & flag_interrupt); //dbg_log("In HLT loop", LOG_CPU); this.run_hardware_timers(v86.microtick()); @@ -1252,7 +1313,7 @@ CPU.prototype.run_hardware_timers = function(now) CPU.prototype.clear_prefixes = function() { - this.prefixes = 0; + this.prefixes[0] = 0; }; CPU.prototype.set_cr0 = function(cr0) @@ -1276,14 +1337,13 @@ CPU.prototype.set_cr0 = function(cr0) var new_paging = (this.cr[0] & CR0_PG) === CR0_PG; - dbg_assert(typeof this.paging === "boolean"); - if(new_paging !== this.paging) + if(new_paging !== Boolean(this.paging[0])) { - this.paging = new_paging; + this.paging[0] = +new_paging; this.full_clear_tlb(); } - this.protected_mode = (this.cr[0] & CR0_PE) === CR0_PE; + this.protected_mode[0] = +((this.cr[0] & CR0_PE) === CR0_PE); }; CPU.prototype.set_cr4 = function(cr4) @@ -1309,7 +1369,7 @@ CPU.prototype.set_cr4 = function(cr4) } this.cr[4] = cr4; - this.page_size_extensions = (cr4 & CR4_PSE) ? PSE_ENABLED : 0; + this.page_size_extensions[0] = (cr4 & CR4_PSE) ? PSE_ENABLED : 0; if(cr4 & CR4_PAE) { @@ -1327,20 +1387,20 @@ CPU.prototype.set_cr4 = function(cr4) CPU.prototype.cpl_changed = function() { - this.last_virt_eip = -1; - this.last_virt_esp = -1; + this.last_virt_eip[0] = -1; + this.last_virt_esp[0] = -1; }; CPU.prototype.read_imm8 = function() { - if((this.instruction_pointer & ~0xFFF) ^ this.last_virt_eip) + if((this.instruction_pointer[0] & ~0xFFF) ^ this.last_virt_eip[0]) { - this.eip_phys = this.translate_address_read(this.instruction_pointer) ^ this.instruction_pointer; - this.last_virt_eip = this.instruction_pointer & ~0xFFF; + this.eip_phys[0] = this.translate_address_read(this.instruction_pointer[0]) ^ this.instruction_pointer[0]; + this.last_virt_eip[0] = this.instruction_pointer[0] & ~0xFFF; } - var data8 = this.read8(this.eip_phys ^ this.instruction_pointer); - this.instruction_pointer = this.instruction_pointer + 1 | 0; + var data8 = this.read8(this.eip_phys[0] ^ this.instruction_pointer[0]); + this.instruction_pointer[0] = this.instruction_pointer[0] + 1 | 0; return data8; }; @@ -1355,13 +1415,13 @@ CPU.prototype.read_imm16 = function() // Two checks in one comparison: // 1. Did the high 20 bits of eip change // or 2. Are the low 12 bits of eip 0xFFF (and this read crosses a page boundary) - if(((this.instruction_pointer ^ this.last_virt_eip) >>> 0) > 0xFFE) + if(((this.instruction_pointer[0] ^ this.last_virt_eip[0]) >>> 0) > 0xFFE) { return this.read_imm8() | this.read_imm8() << 8; } - var data16 = this.read16(this.eip_phys ^ this.instruction_pointer); - this.instruction_pointer = this.instruction_pointer + 2 | 0; + var data16 = this.read16(this.eip_phys[0] ^ this.instruction_pointer[0]); + this.instruction_pointer[0] = this.instruction_pointer[0] + 2 | 0; return data16; }; @@ -1369,13 +1429,13 @@ CPU.prototype.read_imm16 = function() CPU.prototype.read_imm32s = function() { // Analogue to the above comment - if(((this.instruction_pointer ^ this.last_virt_eip) >>> 0) > 0xFFC) + if(((this.instruction_pointer[0] ^ this.last_virt_eip[0]) >>> 0) > 0xFFC) { return this.read_imm16() | this.read_imm16() << 16; } - var data32 = this.read32s(this.eip_phys ^ this.instruction_pointer); - this.instruction_pointer = this.instruction_pointer + 4 | 0; + var data32 = this.read32s(this.eip_phys[0] ^ this.instruction_pointer[0]); + this.instruction_pointer[0] = this.instruction_pointer[0] + 4 | 0; return data32; }; @@ -1403,7 +1463,7 @@ CPU.prototype.create_atom128s = function(d0, d1, d2, d3) CPU.prototype.read_modrm_byte = function() { - this.modrm_byte = this.read_imm8(); + this.modrm_byte[0] = this.read_imm8(); }; CPU.prototype.read_op0F = CPU.prototype.read_imm8; @@ -1527,7 +1587,7 @@ CPU.prototype.safe_read8 = function(addr) CPU.prototype.safe_read16 = function(addr) { - if(this.paging && (addr & 0xFFF) === 0xFFF) + if(this.paging[0] && (addr & 0xFFF) === 0xFFF) { return this.safe_read8(addr) | this.safe_read8(addr + 1 | 0) << 8; } @@ -1539,7 +1599,7 @@ CPU.prototype.safe_read16 = function(addr) CPU.prototype.safe_read32s = function(addr) { - if(this.paging && (addr & 0xFFF) >= 0xFFD) + if(this.paging[0] && (addr & 0xFFF) >= 0xFFD) { return this.safe_read16(addr) | this.safe_read16(addr + 2 | 0) << 16; } @@ -1613,7 +1673,6 @@ CPU.prototype.safe_write32 = function(addr, value) if((addr & 0xFFF) >= 0xFFD) { - // XXX this.virt_boundary_write32(phys_low, this.translate_address_write(addr + 3 & ~3) | (addr + 3) & 3, value); } else @@ -1654,17 +1713,17 @@ CPU.prototype.read_moffs = function() CPU.prototype.getiopl = function() { - return this.flags >> 12 & 3; + return this.flags[0] >> 12 & 3; }; CPU.prototype.vm86_mode = function() { - return !!(this.flags & flag_vm); + return !!(this.flags[0] & flag_vm); }; CPU.prototype.get_eflags = function() { - return (this.flags & ~flags_all) | !!this.getcf() | !!this.getpf() << 2 | !!this.getaf() << 4 | + return (this.flags[0] & ~flags_all) | !!this.getcf() | !!this.getpf() << 2 | !!this.getaf() << 4 | !!this.getzf() << 6 | !!this.getsf() << 7 | !!this.getof() << 11; }; @@ -1676,7 +1735,7 @@ CPU.prototype.update_eflags = function(new_flags) var dont_update = flag_rf | flag_vm | flag_vip | flag_vif, clear = ~flag_vip & ~flag_vif & flags_mask; - if(this.flags & flag_vm) + if(this.flags[0] & flag_vm) { // other case needs to be handled in popf or iret dbg_assert(this.getiopl() === 3); @@ -1688,15 +1747,15 @@ CPU.prototype.update_eflags = function(new_flags) } else { - if(!this.protected_mode) dbg_assert(this.cpl === 0); + if(!this.protected_mode[0]) dbg_assert(this.cpl[0] === 0); - if(this.cpl) + if(this.cpl[0]) { // cpl > 0 // cannot update iopl dont_update |= flag_iopl; - if(this.cpl > this.getiopl()) + if(this.cpl[0] > this.getiopl()) { // cpl > iopl // cannot update interrupt flag @@ -1705,14 +1764,14 @@ CPU.prototype.update_eflags = function(new_flags) } } - this.flags = (new_flags ^ ((this.flags ^ new_flags) & dont_update)) & clear | flags_default; + this.flags[0] = (new_flags ^ ((this.flags[0] ^ new_flags) & dont_update)) & clear | flags_default; - this.flags_changed = 0; + this.flags_changed[0] = 0; }; CPU.prototype.get_stack_reg = function() { - if(this.stack_size_32) + if(this.stack_size_32[0]) { return this.reg32s[reg_esp]; } @@ -1724,7 +1783,7 @@ CPU.prototype.get_stack_reg = function() CPU.prototype.set_stack_reg = function(value) { - if(this.stack_size_32) + if(this.stack_size_32[0]) { this.reg32s[reg_esp] = value; } @@ -1736,7 +1795,7 @@ CPU.prototype.set_stack_reg = function(value) CPU.prototype.adjust_stack_reg = function(value) { - if(this.stack_size_32) + if(this.stack_size_32[0]) { this.reg32s[reg_esp] += value; } @@ -1748,7 +1807,7 @@ CPU.prototype.adjust_stack_reg = function(value) CPU.prototype.get_stack_pointer = function(mod) { - if(this.stack_size_32) + if(this.stack_size_32[0]) { return this.get_seg(reg_ss) + this.reg32s[reg_esp] + mod | 0; } @@ -1764,10 +1823,10 @@ CPU.prototype.get_stack_pointer = function(mod) */ CPU.prototype.get_real_eip = function() { - return this.instruction_pointer - this.get_seg(reg_cs) | 0; + return this.instruction_pointer[0] - this.get_seg(reg_cs) | 0; }; -CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, error_code) +CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, has_error_code, error_code) { //dbg_log("int " + h(interrupt_nr, 2) + " (" + (is_software_int ? "soft" : "hard") + "ware)", LOG_CPU); CPU_LOG_VERBOSE && this.debug.dump_state("int " + h(interrupt_nr) + " start" + @@ -1776,14 +1835,15 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er this.debug.debug_interrupt(interrupt_nr); - dbg_assert(error_code === false || typeof error_code === "number"); + dbg_assert(typeof has_error_code === "boolean"); + dbg_assert(has_error_code === false || typeof error_code === "number"); // we have to leave hlt_loop at some point, this is a // good place to do it //this.in_hlt && dbg_log("Leave HLT loop", LOG_CPU); this.in_hlt = false; - if(this.protected_mode) + if(this.protected_mode[0]) { if(this.vm86_mode() && (this.cr[4] & CR4_VME)) { @@ -1797,17 +1857,17 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er this.trigger_gp(0); } - if((interrupt_nr << 3 | 7) > this.idtr_size) + if((interrupt_nr << 3 | 7) > this.idtr_size[0]) { dbg_log(interrupt_nr, LOG_CPU); dbg_trace(LOG_CPU); throw this.debug.unimpl("#GP handler"); } - var addr = this.idtr_offset + (interrupt_nr << 3) | 0; + var addr = this.idtr_offset[0] + (interrupt_nr << 3) | 0; dbg_assert((addr & 0xFFF) < 0xFF8); - if(this.paging) + if(this.paging[0]) { addr = this.translate_address_system_read(addr); } @@ -1824,7 +1884,7 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er throw this.debug.unimpl("#NP handler"); } - if(is_software_int && dpl < this.cpl) + if(is_software_int && dpl < this.cpl[0]) { dbg_log("#gp software interrupt (" + h(interrupt_nr, 2) + ") and dpl < cpl", LOG_CPU); dbg_trace(LOG_CPU); @@ -1864,7 +1924,7 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er dbg_log("is null"); throw this.debug.unimpl("#GP handler"); } - if(!info.is_executable || info.dpl > this.cpl) + if(!info.is_executable || info.dpl > this.cpl[0]) { dbg_log("not exec"); throw this.debug.unimpl("#GP handler"); @@ -1878,9 +1938,9 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er var old_flags = this.get_eflags(); - //dbg_log("interrupt " + h(interrupt_nr, 2) + " (" + (is_software_int ? "soft" : "hard") + "ware) from cpl=" + this.cpl + " vm=" + (this.flags & flag_vm) + " cs:eip=" + h(this.sreg[reg_cs], 4) + ":" + h(this.get_real_eip(), 8) + " to cpl=" + //dbg_log("interrupt " + h(interrupt_nr, 2) + " (" + (is_software_int ? "soft" : "hard") + "ware) from cpl=" + this.cpl[0] + " vm=" + (this.flags[0] & flag_vm) + " cs:eip=" + h(this.sreg[reg_cs], 4) + ":" + h(this.get_real_eip(), 8) + " to cpl=" - if(!info.dc_bit && info.dpl < this.cpl) + if(!info.dc_bit && info.dpl < this.cpl[0]) { // inter privilege level interrupt // interrupt from vm86 mode @@ -1935,7 +1995,7 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er dbg_assert(info.dpl === 0, "switch to non-0 dpl from vm86 mode"); } - var stack_space = (is_16 ? 2 : 4) * (5 + (error_code !== false) + 4 * ((old_flags & flag_vm) === flag_vm)); + var stack_space = (is_16 ? 2 : 4) * (5 + (has_error_code === true) + 4 * ((old_flags & flag_vm) === flag_vm)); var new_stack_pointer = ss_info.base + (ss_info.size ? new_esp - stack_space : (new_esp - stack_space & 0xFFFF)); // XXX: with new cpl or with cpl 0? @@ -1944,12 +2004,12 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er // no exceptions below - this.cpl = info.dpl; + this.cpl[0] = info.dpl; this.cpl_changed(); this.update_cs_size(info.size); - this.flags &= ~flag_vm & ~flag_rf; + this.flags[0] &= ~flag_vm & ~flag_rf; this.switch_seg(reg_ss, new_ss); this.set_stack_reg(new_esp); @@ -1980,22 +2040,22 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er this.push32(old_esp); } } - else if(info.dc_bit || info.dpl === this.cpl) + else if(info.dc_bit || info.dpl === this.cpl[0]) { // intra privilege level interrupt //dbg_log("Intra privilege interrupt gate=" + h(selector, 4) + ":" + h(base >>> 0, 8) + // " trap=" + is_trap + " 16bit=" + is_16 + - // " cpl=" + this.cpl + " dpl=" + info.dpl + " conforming=" + +info.dc_bit, LOG_CPU); - //this.debug.dump_regs(); + // " cpl=" + this.cpl[0] + " dpl=" + info.dpl + " conforming=" + +info.dc_bit, LOG_CPU); + //this.debug.dump_regs_short(); - if(this.flags & flag_vm) + if(this.flags[0] & flag_vm) { dbg_assert(false, "check error code"); this.trigger_gp(selector & ~3); } - var stack_space = (is_16 ? 2 : 4) * (3 + (error_code !== false)); + var stack_space = (is_16 ? 2 : 4) * (3 + (has_error_code === true)); // XXX: with current cpl or with cpl 0? this.writable_or_pagefault(this.get_stack_pointer(-stack_space), stack_space); @@ -2013,7 +2073,7 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er this.push16(this.sreg[reg_cs]); this.push16(this.get_real_eip()); - if(error_code !== false) + if(has_error_code === true) { this.push16(error_code); } @@ -2026,7 +2086,7 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er this.push32(this.sreg[reg_cs]); this.push32(this.get_real_eip()); - if(error_code !== false) + if(has_error_code === true) { this.push32(error_code); } @@ -2040,22 +2100,22 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er this.switch_seg(reg_es, 0); } - this.sreg[reg_cs] = selector & ~3 | this.cpl; - dbg_assert((this.sreg[reg_cs] & 3) === this.cpl); + this.sreg[reg_cs] = selector & ~3 | this.cpl[0]; + dbg_assert((this.sreg[reg_cs] & 3) === this.cpl[0]); this.update_cs_size(info.size); this.segment_limits[reg_cs] = info.effective_limit; this.segment_offsets[reg_cs] = info.base; - this.instruction_pointer = this.get_seg(reg_cs) + base | 0; + this.instruction_pointer[0] = this.get_seg(reg_cs) + base | 0; - this.flags &= ~flag_nt & ~flag_vm & ~flag_rf & ~flag_trap; + this.flags[0] &= ~flag_nt & ~flag_vm & ~flag_rf & ~flag_trap; if(!is_trap) { // clear int flag for interrupt gates - this.flags &= ~flag_interrupt; + this.flags[0] &= ~flag_interrupt; } else { @@ -2078,10 +2138,10 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er this.push16(this.sreg[reg_cs]); this.push16(this.get_real_eip()); - this.flags &= ~flag_interrupt; + this.flags[0] &= ~flag_interrupt; this.switch_cs_real_mode(new_cs); - this.instruction_pointer = this.get_seg(reg_cs) + new_ip | 0; + this.instruction_pointer[0] = this.get_seg(reg_cs) + new_ip | 0; } //dbg_log("int to:", LOG_CPU); @@ -2124,7 +2184,7 @@ CPU.prototype.iret = function(is_16) var new_flags = this.safe_read32s(this.get_stack_pointer(8)); } - if(!this.protected_mode || (this.vm86_mode() && this.getiopl() === 3)) + if(!this.protected_mode[0] || (this.vm86_mode() && this.getiopl() === 3)) { if(new_eip & 0xFFFF0000) { @@ -2132,11 +2192,11 @@ CPU.prototype.iret = function(is_16) } this.switch_cs_real_mode(new_cs); - this.instruction_pointer = new_eip + this.get_seg(reg_cs) | 0; + this.instruction_pointer[0] = new_eip + this.get_seg(reg_cs) | 0; if(is_16) { - this.update_eflags(new_flags | this.flags & ~0xFFFF); + this.update_eflags(new_flags | this.flags[0] & ~0xFFFF); this.adjust_stack_reg(3 * 2); } else @@ -2154,7 +2214,7 @@ CPU.prototype.iret = function(is_16) dbg_assert(!this.vm86_mode()); - if(this.flags & flag_nt) + if(this.flags[0] & flag_nt) { if(DEBUG) throw this.debug.unimpl("nt"); this.trigger_gp(0); @@ -2162,7 +2222,7 @@ CPU.prototype.iret = function(is_16) if(new_flags & flag_vm) { - if(this.cpl === 0) + if(this.cpl[0] === 0) { // return to virtual 8086 mode @@ -2187,10 +2247,10 @@ CPU.prototype.iret = function(is_16) // no exceptions below this.update_eflags(new_flags); - this.flags |= flag_vm; + this.flags[0] |= flag_vm; this.switch_cs_real_mode(new_cs); - this.instruction_pointer = (new_eip & 0xFFFF) + this.get_seg(reg_cs) | 0; + this.instruction_pointer[0] = (new_eip & 0xFFFF) + this.get_seg(reg_cs) | 0; this.switch_seg(reg_es, new_es); this.switch_seg(reg_ds, new_ds); @@ -2202,7 +2262,7 @@ CPU.prototype.iret = function(is_16) this.reg32s[reg_esp] = temp_esp; this.switch_seg(reg_ss, temp_ss); - this.cpl = 3; + this.cpl[0] = 3; this.cpl_changed(); this.update_cs_size(false); @@ -2239,7 +2299,7 @@ CPU.prototype.iret = function(is_16) { throw this.debug.unimpl("not exec"); } - if(info.rpl < this.cpl) + if(info.rpl < this.cpl[0]) { throw this.debug.unimpl("rpl < cpl"); } @@ -2254,7 +2314,7 @@ CPU.prototype.iret = function(is_16) this.trigger_gp(new_cs & ~3); } - if(info.rpl > this.cpl) + if(info.rpl > this.cpl[0]) { // outer privilege return if(is_16) @@ -2300,42 +2360,42 @@ CPU.prototype.iret = function(is_16) if(is_16) { - this.update_eflags(new_flags | this.flags & ~0xFFFF); + this.update_eflags(new_flags | this.flags[0] & ~0xFFFF); } else { this.update_eflags(new_flags); } - this.cpl = info.rpl; + this.cpl[0] = info.rpl; this.cpl_changed(); - //dbg_log("outer privilege return: from=" + this.cpl + " to=" + info.rpl + " ss:esp=" + h(temp_ss, 4) + ":" + h(temp_esp >>> 0, 8), LOG_CPU); + //dbg_log("outer privilege return: from=" + this.cpl[0] + " to=" + info.rpl + " ss:esp=" + h(temp_ss, 4) + ":" + h(temp_esp >>> 0, 8), LOG_CPU); this.switch_seg(reg_ss, temp_ss); this.set_stack_reg(temp_esp); - if(this.cpl === 0) + if(this.cpl[0] === 0) { - this.flags = this.flags & ~flag_vif & ~flag_vip | (new_flags & (flag_vif | flag_vip)); + this.flags[0] = this.flags[0] & ~flag_vif & ~flag_vip | (new_flags & (flag_vif | flag_vip)); } // XXX: Set segment to 0 if it's not usable in the new cpl // XXX: Use cached segment information //var ds_info = this.lookup_segment_selector(this.sreg[reg_ds]); - //if(this.cpl > ds_info.dpl && (!ds_info.is_executable || !ds_info.dc_bit)) this.switch_seg(reg_ds, 0); + //if(this.cpl[0] > ds_info.dpl && (!ds_info.is_executable || !ds_info.dc_bit)) this.switch_seg(reg_ds, 0); // ... } - else if(info.rpl === this.cpl) + else if(info.rpl === this.cpl[0]) { // same privilege return // no exceptions below if(is_16) { this.adjust_stack_reg(3 * 2); - this.update_eflags(new_flags | this.flags & ~0xFFFF); + this.update_eflags(new_flags | this.flags[0] & ~0xFFFF); } else { @@ -2344,9 +2404,9 @@ CPU.prototype.iret = function(is_16) } // update vip and vif, which are not changed by update_eflags - if(this.cpl === 0) + if(this.cpl[0] === 0) { - this.flags = this.flags & ~flag_vif & ~flag_vip | (new_flags & (flag_vif | flag_vip)); + this.flags[0] = this.flags[0] & ~flag_vif & ~flag_vip | (new_flags & (flag_vif | flag_vip)); } } else @@ -2355,14 +2415,14 @@ CPU.prototype.iret = function(is_16) } this.sreg[reg_cs] = new_cs; - dbg_assert((new_cs & 3) === this.cpl); + dbg_assert((new_cs & 3) === this.cpl[0]); this.update_cs_size(info.size); this.segment_limits[reg_cs] = info.effective_limit; this.segment_offsets[reg_cs] = info.base; - this.instruction_pointer = new_eip + this.get_seg(reg_cs) | 0; + this.instruction_pointer[0] = new_eip + this.get_seg(reg_cs) | 0; CPU_LOG_VERBOSE && this.debug.dump_state("iret" + (is_16 ? "16" : "32") + " end"); @@ -2371,7 +2431,7 @@ CPU.prototype.iret = function(is_16) CPU.prototype.switch_cs_real_mode = function(selector) { - dbg_assert(!this.protected_mode || this.vm86_mode()); + dbg_assert(!this.protected_mode[0] || this.vm86_mode()); this.sreg[reg_cs] = selector; this.segment_is_null[reg_cs] = 0; @@ -2385,16 +2445,16 @@ CPU.prototype.far_return = function(eip, selector, stack_adjust) //dbg_log("far return eip=" + h(eip >>> 0, 8) + " cs=" + h(selector, 4) + " stack_adjust=" + h(stack_adjust), LOG_CPU); CPU_LOG_VERBOSE && this.debug.dump_state("far ret start"); - if(!this.protected_mode) + if(!this.protected_mode[0]) { - dbg_assert(!this.is_32); - //dbg_assert(!this.stack_size_32); + dbg_assert(!this.is_32[0]); + //dbg_assert(!this.stack_size_32[0]); } - if(!this.protected_mode || this.vm86_mode()) + if(!this.protected_mode[0] || this.vm86_mode()) { this.switch_cs_real_mode(selector); - this.instruction_pointer = this.get_seg(reg_cs) + eip | 0; + this.instruction_pointer[0] = this.get_seg(reg_cs) + eip | 0; this.adjust_stack_reg(2 * (this.is_osize_32() ? 4 : 2) + stack_adjust); return; } @@ -2425,7 +2485,7 @@ CPU.prototype.far_return = function(eip, selector, stack_adjust) this.trigger_gp(selector & ~3); } - if(info.rpl < this.cpl) + if(info.rpl < this.cpl[0]) { dbg_log("cs rpl < cpl: " + h(selector), LOG_CPU); this.trigger_gp(selector & ~3); @@ -2450,9 +2510,9 @@ CPU.prototype.far_return = function(eip, selector, stack_adjust) this.trigger_np(selector & ~3); } - if(info.rpl > this.cpl) + if(info.rpl > this.cpl[0]) { - dbg_log("far return privilege change cs: " + h(selector) + " from=" + this.cpl + " to=" + info.rpl + " is_16=" + this.is_osize_32(), LOG_CPU); + dbg_log("far return privilege change cs: " + h(selector) + " from=" + this.cpl[0] + " to=" + info.rpl + " is_16=" + this.is_osize_32(), LOG_CPU); if(this.is_osize_32()) { @@ -2469,7 +2529,7 @@ CPU.prototype.far_return = function(eip, selector, stack_adjust) var temp_ss = this.safe_read16(this.get_stack_pointer(stack_adjust + 6)); } - this.cpl = info.rpl; + this.cpl[0] = info.rpl; this.cpl_changed(); // XXX: Can raise, conditions should be checked before side effects @@ -2501,7 +2561,7 @@ CPU.prototype.far_return = function(eip, selector, stack_adjust) } } - //dbg_assert(this.cpl === info.dpl); + //dbg_assert(this.cpl[0] === info.dpl); this.update_cs_size(info.size); @@ -2511,10 +2571,9 @@ CPU.prototype.far_return = function(eip, selector, stack_adjust) this.segment_offsets[reg_cs] = info.base; this.sreg[reg_cs] = selector; + dbg_assert((selector & 3) === this.cpl[0]); - dbg_assert((selector & 3) === this.cpl); - - this.instruction_pointer = this.get_seg(reg_cs) + eip | 0; + this.instruction_pointer[0] = this.get_seg(reg_cs) + eip | 0; //dbg_log("far return to:", LOG_CPU) CPU_LOG_VERBOSE && this.debug.dump_state("far ret end"); @@ -2522,12 +2581,13 @@ CPU.prototype.far_return = function(eip, selector, stack_adjust) CPU.prototype.far_jump = function(eip, selector, is_call) { + is_call = !!is_call; dbg_assert(typeof selector === "number" && selector < 0x10000 && selector >= 0); //dbg_log("far " + ["jump", "call"][+is_call] + " eip=" + h(eip >>> 0, 8) + " cs=" + h(selector, 4), LOG_CPU); CPU_LOG_VERBOSE && this.debug.dump_state("far " + ["jump", "call"][+is_call]); - if(!this.protected_mode || this.vm86_mode()) + if(!this.protected_mode[0] || this.vm86_mode()) { if(is_call) { @@ -2545,7 +2605,7 @@ CPU.prototype.far_jump = function(eip, selector, is_call) } } this.switch_cs_real_mode(selector); - this.instruction_pointer = this.get_seg(reg_cs) + eip | 0; + this.instruction_pointer[0] = this.get_seg(reg_cs) + eip | 0; return; } @@ -2574,7 +2634,7 @@ CPU.prototype.far_jump = function(eip, selector, is_call) // call gate var is_16 = info.type === 4; - if(info.dpl < this.cpl || info.dpl < info.rpl) + if(info.dpl < this.cpl[0] || info.dpl < info.rpl) { dbg_log("#gp cs gate dpl < cpl or dpl < rpl: " + h(selector), LOG_CPU); this.trigger_gp(selector & ~3); @@ -2607,7 +2667,7 @@ CPU.prototype.far_jump = function(eip, selector, is_call) this.trigger_gp(cs_selector & ~3); } - if(cs_info.dpl > this.cpl) + if(cs_info.dpl > this.cpl[0]) { dbg_log("#gp dpl > cpl: " + h(cs_selector), LOG_CPU); this.trigger_gp(cs_selector & ~3); @@ -2619,9 +2679,9 @@ CPU.prototype.far_jump = function(eip, selector, is_call) this.trigger_np(cs_selector & ~3); } - if(!cs_info.dc_bit && cs_info.dpl < this.cpl) + if(!cs_info.dc_bit && cs_info.dpl < this.cpl[0]) { - dbg_log("more privilege call gate is_16=" + is_16 + " from=" + this.cpl + " to=" + cs_info.dpl); + dbg_log("more privilege call gate is_16=" + is_16 + " from=" + this.cpl[0] + " to=" + cs_info.dpl); var tss_stack_addr = this.get_tss_stack_addr(cs_info.dpl); if(this.tss_size_32) @@ -2685,7 +2745,7 @@ CPU.prototype.far_jump = function(eip, selector, is_call) //dbg_log("old_esp=" + h(old_esp)); - this.cpl = cs_info.dpl; + this.cpl[0] = cs_info.dpl; this.cpl_changed(); this.update_cs_size(cs_info.size); @@ -2739,7 +2799,7 @@ CPU.prototype.far_jump = function(eip, selector, is_call) } else { - dbg_log("same privilege call gate is_16=" + is_16 + " from=" + this.cpl + " to=" + cs_info.dpl + " conforming=" + cs_info.dc_bit); + dbg_log("same privilege call gate is_16=" + is_16 + " from=" + this.cpl[0] + " to=" + cs_info.dpl + " conforming=" + cs_info.dc_bit); // ok if(is_call) @@ -2775,10 +2835,10 @@ CPU.prototype.far_jump = function(eip, selector, is_call) this.segment_limits[reg_cs] = cs_info.effective_limit; //this.segment_infos[reg_cs] = 0; // TODO this.segment_offsets[reg_cs] = cs_info.base; - this.sreg[reg_cs] = cs_selector & ~3 | this.cpl; - dbg_assert((this.sreg[reg_cs] & 3) === this.cpl); + this.sreg[reg_cs] = cs_selector & ~3 | this.cpl[0]; + dbg_assert((this.sreg[reg_cs] & 3) === this.cpl[0]); - this.instruction_pointer = this.get_seg(reg_cs) + new_eip | 0; + this.instruction_pointer[0] = this.get_seg(reg_cs) + new_eip | 0; } else { @@ -2797,7 +2857,7 @@ CPU.prototype.far_jump = function(eip, selector, is_call) if(info.dc_bit) { // conforming code segment - if(info.dpl > this.cpl) + if(info.dpl > this.cpl[0]) { dbg_log("#gp cs dpl > cpl: " + h(selector), LOG_CPU); this.trigger_gp(selector & ~3); @@ -2807,7 +2867,7 @@ CPU.prototype.far_jump = function(eip, selector, is_call) { // non-conforming code segment - if(info.rpl > this.cpl || info.dpl !== this.cpl) + if(info.rpl > this.cpl[0] || info.dpl !== this.cpl[0]) { dbg_log("#gp cs rpl > cpl or dpl != cpl: " + h(selector), LOG_CPU); this.trigger_gp(selector & ~3); @@ -2846,9 +2906,9 @@ CPU.prototype.far_jump = function(eip, selector, is_call) //this.segment_infos[reg_cs] = 0; // TODO this.segment_offsets[reg_cs] = info.base; - this.sreg[reg_cs] = selector & ~3 | this.cpl; + this.sreg[reg_cs] = selector & ~3 | this.cpl[0]; - this.instruction_pointer = this.get_seg(reg_cs) + eip | 0; + this.instruction_pointer[0] = this.get_seg(reg_cs) + eip | 0; } //dbg_log("far " + ["jump", "call"][+is_call] + " to:", LOG_CPU) @@ -2883,7 +2943,7 @@ CPU.prototype.get_tss_stack_addr = function(dpl) dbg_assert((tss_stack_addr & 0xFFF) <= 0x1000 - 4); } - if(this.paging) + if(this.paging[0]) { tss_stack_addr = this.translate_address_system_read(tss_stack_addr); } @@ -2978,7 +3038,7 @@ CPU.prototype.do_task_switch = function(selector, error_code) var new_cr3 = this.safe_read32s(new_tsr_offset + TSR_CR3); - this.flags &= ~flag_vm; + this.flags[0] &= ~flag_vm; var new_eip = this.safe_read32s(new_tsr_offset + TSR_EIP); var new_cs = this.safe_read16(new_tsr_offset + TSR_CS); @@ -3054,7 +3114,7 @@ CPU.prototype.do_task_switch = function(selector, error_code) if(true /* call or int */) { - this.flags |= flag_nt; + this.flags[0] |= flag_nt; } var new_ldt = this.safe_read16(new_tsr_offset + TSR_LDT); @@ -3076,7 +3136,7 @@ CPU.prototype.do_task_switch = function(selector, error_code) this.switch_seg(reg_fs, this.safe_read16(new_tsr_offset + TSR_FS)); this.switch_seg(reg_gs, this.safe_read16(new_tsr_offset + TSR_GS)); - this.instruction_pointer = this.get_seg(reg_cs) + new_eip | 0; + this.instruction_pointer[0] = this.get_seg(reg_cs) + new_eip | 0; this.segment_offsets[reg_tr] = descriptor.base; this.segment_limits[reg_tr] = descriptor.effective_limit; @@ -3103,12 +3163,12 @@ CPU.prototype.do_task_switch = function(selector, error_code) CPU.prototype.hlt_op = function() { - if(this.cpl) + if(this.cpl[0]) { this.trigger_gp(0); } - if((this.flags & flag_interrupt) === 0) + if((this.flags[0] & flag_interrupt) === 0) { this.debug.show("cpu halted"); this.bus.send("cpu-event-halt"); @@ -3148,7 +3208,7 @@ CPU.prototype.raise_exception = function(interrupt_nr) // this.debug.dump_state(); //} - this.call_interrupt_vector(interrupt_nr, false, false); + this.call_interrupt_vector(interrupt_nr, false, false, 0); throw MAGIC_CPU_EXCEPTION; }; @@ -3163,49 +3223,49 @@ CPU.prototype.raise_exception_with_code = function(interrupt_nr, error_code) // this.debug.dump_regs(); //} - this.call_interrupt_vector(interrupt_nr, false, error_code); + this.call_interrupt_vector(interrupt_nr, false, true, error_code); throw MAGIC_CPU_EXCEPTION; }; CPU.prototype.trigger_de = function() { - this.instruction_pointer = this.previous_ip; + this.instruction_pointer[0] = this.previous_ip[0]; this.raise_exception(0); }; CPU.prototype.trigger_ud = function() { - this.instruction_pointer = this.previous_ip; + this.instruction_pointer[0] = this.previous_ip[0]; this.raise_exception(6); }; CPU.prototype.trigger_nm = function() { - this.instruction_pointer = this.previous_ip; + this.instruction_pointer[0] = this.previous_ip[0]; this.raise_exception(7); }; CPU.prototype.trigger_ts = function(code) { - this.instruction_pointer = this.previous_ip; + this.instruction_pointer[0] = this.previous_ip[0]; this.raise_exception_with_code(10, code); }; CPU.prototype.trigger_gp = function(code) { - this.instruction_pointer = this.previous_ip; + this.instruction_pointer[0] = this.previous_ip[0]; this.raise_exception_with_code(13, code); }; CPU.prototype.trigger_np = function(code) { - this.instruction_pointer = this.previous_ip; + this.instruction_pointer[0] = this.previous_ip[0]; this.raise_exception_with_code(11, code); }; CPU.prototype.trigger_ss = function(code) { - this.instruction_pointer = this.previous_ip; + this.instruction_pointer[0] = this.previous_ip[0]; this.raise_exception_with_code(12, code); }; @@ -3259,19 +3319,29 @@ CPU.prototype.unimplemented_sse = function() this.trigger_ud(); }; -CPU.prototype.get_seg_prefix_ds = function() +CPU.prototype.unimplemented_sse_wasm = function() { - return this.get_seg_prefix(reg_ds); + this.instruction_pointer[0] -= 1; + + this.table0F_32[this.read_op0F()](this); }; -CPU.prototype.get_seg_prefix_ss = function() +CPU.prototype.get_seg_prefix_ds = function(offset) { - return this.get_seg_prefix(reg_ss); + offset = offset || 0; + return this.get_seg_prefix(reg_ds) + offset | 0; }; -CPU.prototype.get_seg_prefix_cs = function() +CPU.prototype.get_seg_prefix_ss = function(offset) { - return this.get_seg_prefix(reg_cs); + offset = offset || 0; + return this.get_seg_prefix(reg_ss) + offset | 0; +}; + +CPU.prototype.get_seg_prefix_cs = function(offset) +{ + offset = offset || 0; + return this.get_seg_prefix(reg_cs) + offset | 0; }; /** @@ -3280,7 +3350,7 @@ CPU.prototype.get_seg_prefix_cs = function() */ CPU.prototype.get_seg_prefix = function(default_segment /*, offset*/) { - var prefix = this.prefixes & PREFIX_MASK_SEGMENT; + var prefix = this.prefixes[0] & PREFIX_MASK_SEGMENT; if(prefix) { @@ -3307,7 +3377,7 @@ CPU.prototype.get_seg = function(segment /*, offset*/) { dbg_assert(segment >= 0 && segment < 8); - if(this.protected_mode) + if(this.protected_mode[0]) { if(this.segment_is_null[segment]) { @@ -3328,10 +3398,11 @@ CPU.prototype.get_seg = function(segment /*, offset*/) CPU.prototype.read_e8 = function() { - if(this.modrm_byte < 0xC0) { - return this.safe_read8(this.modrm_resolve(this.modrm_byte)); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + return this.safe_read8(this.modrm_resolve(modrm_byte)); } else { - return this.reg8[this.modrm_byte << 2 & 0xC | this.modrm_byte >> 2 & 1]; + return this.wm.funcs['_read_e8_partial_branch'](); } }; @@ -3342,10 +3413,11 @@ CPU.prototype.read_e8s = function() CPU.prototype.read_e16 = function() { - if(this.modrm_byte < 0xC0) { - return this.safe_read16(this.modrm_resolve(this.modrm_byte)); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + return this.safe_read16(this.modrm_resolve(modrm_byte)); } else { - return this.reg16[this.modrm_byte << 1 & 14]; + return this.reg16[modrm_byte << 1 & 14]; } }; @@ -3356,10 +3428,11 @@ CPU.prototype.read_e16s = function() CPU.prototype.read_e32s = function() { - if(this.modrm_byte < 0xC0) { - return this.safe_read32s(this.modrm_resolve(this.modrm_byte)); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + return this.safe_read32s(this.modrm_resolve(modrm_byte)); } else { - return this.reg32s[this.modrm_byte & 7]; + return this.reg32s[modrm_byte & 7]; } }; @@ -3435,31 +3508,34 @@ CPU.prototype.read_xmm_mem128s_unaligned = function() CPU.prototype.set_e8 = function(value) { - if(this.modrm_byte < 0xC0) { - var addr = this.modrm_resolve(this.modrm_byte); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + var addr = this.modrm_resolve(modrm_byte); this.safe_write8(addr, value); } else { - this.reg8[this.modrm_byte << 2 & 0xC | this.modrm_byte >> 2 & 1] = value; + this.reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = value; } }; CPU.prototype.set_e16 = function(value) { - if(this.modrm_byte < 0xC0) { - var addr = this.modrm_resolve(this.modrm_byte); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + var addr = this.modrm_resolve(modrm_byte); this.safe_write16(addr, value); } else { - this.reg16[this.modrm_byte << 1 & 14] = value; + this.reg16[modrm_byte << 1 & 14] = value; } }; CPU.prototype.set_e32 = function(value) { - if(this.modrm_byte < 0xC0) { - var addr = this.modrm_resolve(this.modrm_byte); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + var addr = this.modrm_resolve(modrm_byte); this.safe_write32(addr, value); } else { - this.reg32s[this.modrm_byte & 7] = value; + this.reg32s[modrm_byte & 7] = value; } }; @@ -3476,141 +3552,147 @@ CPU.prototype.set_mmx_mem64s = function(low, high) CPU.prototype.read_write_e8 = function() { - if(this.modrm_byte < 0xC0) { - var virt_addr = this.modrm_resolve(this.modrm_byte); - this.phys_addr = this.translate_address_write(virt_addr); - return this.read8(this.phys_addr); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + var virt_addr = this.modrm_resolve(modrm_byte); + this.phys_addr[0] = this.translate_address_write(virt_addr); + return this.read8(this.phys_addr[0]); } else { - return this.reg8[this.modrm_byte << 2 & 0xC | this.modrm_byte >> 2 & 1]; + return this.reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; } }; CPU.prototype.write_e8 = function(value) { - if(this.modrm_byte < 0xC0) { - this.write8(this.phys_addr, value); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + this.write8(this.phys_addr[0], value); } else { - this.reg8[this.modrm_byte << 2 & 0xC | this.modrm_byte >> 2 & 1] = value; + this.reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = value; } }; CPU.prototype.read_write_e16 = function() { - if(this.modrm_byte < 0xC0) { - var virt_addr = this.modrm_resolve(this.modrm_byte); - this.phys_addr = this.translate_address_write(virt_addr); - if(this.paging && (virt_addr & 0xFFF) === 0xFFF) { - this.phys_addr_high = this.translate_address_write(virt_addr + 1 | 0); - dbg_assert(this.phys_addr_high); - return this.virt_boundary_read16(this.phys_addr, this.phys_addr_high); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + var virt_addr = this.modrm_resolve(modrm_byte); + this.phys_addr[0] = this.translate_address_write(virt_addr); + if(this.paging[0] && (virt_addr & 0xFFF) === 0xFFF) { + this.phys_addr_high[0] = this.translate_address_write(virt_addr + 1 | 0); + dbg_assert(this.phys_addr_high[0]); + return this.virt_boundary_read16(this.phys_addr[0], this.phys_addr_high[0]); } else { - this.phys_addr_high = 0; - return this.read16(this.phys_addr); + this.phys_addr_high[0] = 0; + return this.read16(this.phys_addr[0]); } } else { - return this.reg16[this.modrm_byte << 1 & 14]; + return this.reg16[modrm_byte << 1 & 14]; } }; CPU.prototype.write_e16 = function(value) { - if(this.modrm_byte < 0xC0) { - if(this.phys_addr_high) { - this.virt_boundary_write16(this.phys_addr, this.phys_addr_high, value); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + if(this.phys_addr_high[0]) { + this.virt_boundary_write16(this.phys_addr[0], this.phys_addr_high[0], value); } else { - this.write16(this.phys_addr, value); + this.write16(this.phys_addr[0], value); } } else { - this.reg16[this.modrm_byte << 1 & 14] = value; + this.reg16[modrm_byte << 1 & 14] = value; } }; CPU.prototype.read_write_e32 = function() { - if(this.modrm_byte < 0xC0) { - var virt_addr = this.modrm_resolve(this.modrm_byte); - this.phys_addr = this.translate_address_write(virt_addr); - if(this.paging && (virt_addr & 0xFFF) >= 0xFFD) { - //this.phys_addr_high = this.translate_address_write(virt_addr + 3 | 0); - this.phys_addr_high = this.translate_address_write(virt_addr + 3 & ~3) | (virt_addr + 3) & 3; - dbg_assert(this.phys_addr_high); - return this.virt_boundary_read32s(this.phys_addr, this.phys_addr_high); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + var virt_addr = this.modrm_resolve(modrm_byte); + this.phys_addr[0] = this.translate_address_write(virt_addr); + if(this.paging[0] && (virt_addr & 0xFFF) >= 0xFFD) { + //this.phys_addr_high[0] = this.translate_address_write(virt_addr + 3 | 0); + this.phys_addr_high[0] = this.translate_address_write(virt_addr + 3 & ~3) | (virt_addr + 3) & 3; + dbg_assert(this.phys_addr_high[0]); + return this.virt_boundary_read32s(this.phys_addr[0], this.phys_addr_high[0]); } else { - this.phys_addr_high = 0; - return this.read32s(this.phys_addr); + this.phys_addr_high[0] = 0; + return this.read32s(this.phys_addr[0]); } } else { - return this.reg32s[this.modrm_byte & 7]; + return this.reg32s[modrm_byte & 7]; } }; CPU.prototype.write_e32 = function(value) { - if(this.modrm_byte < 0xC0) { - if(this.phys_addr_high) { - this.virt_boundary_write32(this.phys_addr, this.phys_addr_high, value); + var modrm_byte = this.modrm_byte[0]; + if(modrm_byte < 0xC0) { + if(this.phys_addr_high[0]) { + this.virt_boundary_write32(this.phys_addr[0], this.phys_addr_high[0], value); } else { - this.write32(this.phys_addr, value); + this.write32(this.phys_addr[0], value); } } else { - this.reg32s[this.modrm_byte & 7] = value; + this.reg32s[modrm_byte & 7] = value; } }; CPU.prototype.read_reg_e16 = function() { - return this.reg16[this.modrm_byte << 1 & 14]; + return this.reg16[this.modrm_byte[0] << 1 & 14]; }; CPU.prototype.write_reg_e16 = function(value) { - this.reg16[this.modrm_byte << 1 & 14] = value; + this.reg16[this.modrm_byte[0] << 1 & 14] = value; }; CPU.prototype.read_reg_e32s = function() { - return this.reg32s[this.modrm_byte & 7]; + return this.reg32s[this.modrm_byte[0] & 7]; }; CPU.prototype.write_reg_e32 = function(value) { - this.reg32s[this.modrm_byte & 7] = value; + this.reg32s[this.modrm_byte[0] & 7] = value; }; CPU.prototype.read_g8 = function() { - return this.reg8[this.modrm_byte >> 1 & 0xC | this.modrm_byte >> 5 & 1]; + return this.reg8[this.modrm_byte[0] >> 1 & 0xC | this.modrm_byte[0] >> 5 & 1]; }; CPU.prototype.write_g8 = function(value) { - this.reg8[this.modrm_byte >> 1 & 0xC | this.modrm_byte >> 5 & 1] = value; + this.reg8[this.modrm_byte[0] >> 1 & 0xC | this.modrm_byte[0] >> 5 & 1] = value; }; CPU.prototype.read_g16 = function() { - return this.reg16[this.modrm_byte >> 2 & 14]; + return this.reg16[this.modrm_byte[0] >> 2 & 14]; }; CPU.prototype.read_g16s = function() { - return this.reg16s[this.modrm_byte >> 2 & 14]; + return this.reg16s[this.modrm_byte[0] >> 2 & 14]; }; CPU.prototype.write_g16 = function(value) { - this.reg16[this.modrm_byte >> 2 & 14] = value; + this.reg16[this.modrm_byte[0] >> 2 & 14] = value; }; CPU.prototype.read_g32s = function() { - return this.reg32s[this.modrm_byte >> 3 & 7]; + return this.reg32s[this.modrm_byte[0] >> 3 & 7]; }; CPU.prototype.write_g32 = function(value) { - this.reg32[this.modrm_byte >> 3 & 7] = value; + this.reg32[this.modrm_byte[0] >> 3 & 7] = value; }; CPU.prototype.read_xmm64s = function() @@ -3666,8 +3748,8 @@ CPU.prototype.pic_call_irq = function(int) { try { - this.previous_ip = this.instruction_pointer; - this.call_interrupt_vector(int, false, false); + this.previous_ip[0] = this.instruction_pointer[0]; + this.call_interrupt_vector(int, false, false, 0); } catch(e) { @@ -3681,7 +3763,7 @@ CPU.prototype.handle_irqs = function() this.diverged(); - if((this.flags & flag_interrupt) && !this.page_fault) + if((this.flags[0] & flag_interrupt) && !this.page_fault) { if(this.devices.pic) { @@ -3724,7 +3806,7 @@ CPU.prototype.device_lower_irq = function(i) CPU.prototype.test_privileges_for_io = function(port, size) { - if(this.protected_mode && (this.cpl > this.getiopl() || (this.flags & flag_vm))) + if(this.protected_mode[0] && (this.cpl[0] > this.getiopl() || (this.flags[0] & flag_vm))) { if(!this.tss_size_32) { @@ -3887,19 +3969,19 @@ CPU.prototype.cpuid = function() CPU.prototype.update_cs_size = function(new_size) { - dbg_assert(typeof new_size === "boolean"); + new_size = Boolean(new_size); - if(this.is_32 !== new_size) + if(Boolean(this.is_32[0]) !== new_size) { this.clear_instruction_cache(); - this.is_32 = new_size; + this.is_32[0] = +new_size; this.update_operand_size(); } }; CPU.prototype.update_operand_size = function() { - if(this.is_32) + if(this.is_32[0]) { this.table = this.table32; } @@ -3955,8 +4037,8 @@ CPU.prototype.lookup_segment_selector = function(selector) if(is_gdt) { - table_offset = this.gdtr_offset; - table_limit = this.gdtr_size; + table_offset = this.gdtr_offset[0]; + table_limit = this.gdtr_size[0]; } else { @@ -3981,7 +4063,7 @@ CPU.prototype.lookup_segment_selector = function(selector) table_offset = table_offset + selector_offset | 0; - if(this.paging) + if(this.paging[0]) { table_offset = this.translate_address_system_read(table_offset); } @@ -4041,7 +4123,7 @@ CPU.prototype.switch_seg = function(reg, selector) dbg_assert(reg >= 0 && reg <= 5); dbg_assert(typeof selector === "number" && selector < 0x10000 && selector >= 0); - if(!this.protected_mode || this.vm86_mode()) + if(!this.protected_mode[0] || this.vm86_mode()) { this.sreg[reg] = selector; this.segment_is_null[reg] = 0; @@ -4049,7 +4131,7 @@ CPU.prototype.switch_seg = function(reg, selector) if(reg === reg_ss) { - this.stack_size_32 = false; + this.stack_size_32[0] = +false; } return; } @@ -4067,9 +4149,9 @@ CPU.prototype.switch_seg = function(reg, selector) if(!info.is_valid || info.is_system || - info.rpl !== this.cpl || + info.rpl !== this.cpl[0] || !info.is_writable || - info.dpl !== this.cpl) + info.dpl !== this.cpl[0]) { dbg_log("#GP for loading invalid in SS sel=" + h(selector, 4), LOG_CPU); dbg_trace(LOG_CPU); @@ -4083,7 +4165,7 @@ CPU.prototype.switch_seg = function(reg, selector) this.trigger_ss(selector & ~3); } - this.stack_size_32 = info.size; + this.stack_size_32[0] = info.size; } else if(reg === reg_cs) { @@ -4106,7 +4188,7 @@ CPU.prototype.switch_seg = function(reg, selector) info.is_system || !info.is_readable || (!info.is_conforming_executable && - (info.rpl > info.dpl || this.cpl > info.dpl)) + (info.rpl > info.dpl || this.cpl[0] > info.dpl)) ) { dbg_log("#GP for loading invalid in seg " + reg + " sel=" + h(selector, 4), LOG_CPU); this.debug.dump_state(); @@ -4228,16 +4310,16 @@ CPU.prototype.load_ldt = function(selector) CPU.prototype.arpl = function(seg, r16) { - this.flags_changed &= ~flag_zero; + this.flags_changed[0] &= ~flag_zero; if((seg & 3) < (this.reg16[r16] & 3)) { - this.flags |= flag_zero; + this.flags[0] |= flag_zero; return seg & ~3 | this.reg16[r16] & 3; } else { - this.flags &= ~flag_zero; + this.flags[0] &= ~flag_zero; return seg; } }; @@ -4251,21 +4333,21 @@ CPU.prototype.lar = function(selector, original) 1 << 0xD | 1 << 0xE | 1 << 0xF; var info = this.lookup_segment_selector(selector); - this.flags_changed &= ~flag_zero; + this.flags_changed[0] &= ~flag_zero; - var dpl_bad = info.dpl < this.cpl || info.dpl < info.rpl; + var dpl_bad = info.dpl < this.cpl[0] || info.dpl < info.rpl; if(info.is_null || !info.is_valid || (info.is_system ? (LAR_INVALID_TYPE >> info.type & 1) || dpl_bad : !info.is_conforming_executable && dpl_bad) ) { - this.flags &= ~flag_zero; + this.flags[0] &= ~flag_zero; dbg_log("lar: invalid selector=" + h(selector, 4) + " is_null=" + info.is_null, LOG_CPU); return original; } else { - this.flags |= flag_zero; + this.flags[0] |= flag_zero; return info.raw1 & 0x00FFFF00; } }; @@ -4279,21 +4361,21 @@ CPU.prototype.lsl = function(selector, original) 1 << 0xA | 1 << 0xC | 1 << 0xD | 1 << 0xE | 1 << 0xF; var info = this.lookup_segment_selector(selector); - this.flags_changed &= ~flag_zero; + this.flags_changed[0] &= ~flag_zero; - var dpl_bad = info.dpl < this.cpl || info.dpl < info.rpl; + var dpl_bad = info.dpl < this.cpl[0] || info.dpl < info.rpl; if(info.is_null || !info.is_valid || (info.is_system ? (LSL_INVALID_TYPE >> info.type & 1) || dpl_bad : !info.is_conforming_executable && dpl_bad) ) { - this.flags &= ~flag_zero; + this.flags[0] &= ~flag_zero; dbg_log("lsl: invalid selector=" + h(selector, 4) + " is_null=" + info.is_null, LOG_CPU); return original; } else { - this.flags |= flag_zero; + this.flags[0] |= flag_zero; return info.effective_limit | 0; } @@ -4302,46 +4384,45 @@ CPU.prototype.lsl = function(selector, original) CPU.prototype.verr = function(selector) { var info = this.lookup_segment_selector(selector); - this.flags_changed &= ~flag_zero; + this.flags_changed[0] &= ~flag_zero; if(info.is_null || !info.is_valid || info.is_system || !info.is_readable || - (!info.is_conforming_executable && (info.dpl < this.cpl || info.dpl < info.rpl))) + (!info.is_conforming_executable && (info.dpl < this.cpl[0] || info.dpl < info.rpl))) { dbg_log("verr -> invalid. selector=" + h(selector, 4), LOG_CPU); - this.flags &= ~flag_zero; + this.flags[0] &= ~flag_zero; } else { dbg_log("verr -> valid. selector=" + h(selector, 4), LOG_CPU); - this.flags |= flag_zero; + this.flags[0] |= flag_zero; } }; CPU.prototype.verw = function(selector) { var info = this.lookup_segment_selector(selector); - this.flags_changed &= ~flag_zero; + this.flags_changed[0] &= ~flag_zero; if(info.is_null || !info.is_valid || info.is_system || !info.is_writable || - info.dpl < this.cpl || info.dpl < info.rpl) + info.dpl < this.cpl[0] || info.dpl < info.rpl) { dbg_log("verw invalid " + " " + h(selector) + " " + info.is_null + " " + !info.is_valid + " " + info.is_system + " " + !info.is_writable + " " + - (info.dpl < this.cpl) + " " + (info.dpl < info.rpl) + " " + LOG_CPU); - this.flags &= ~flag_zero; + (info.dpl < this.cpl[0]) + " " + (info.dpl < info.rpl) + " " + LOG_CPU); + this.flags[0] &= ~flag_zero; } else { - dbg_log("verw valid", LOG_CPU); - this.flags |= flag_zero; + this.flags[0] |= flag_zero; } }; CPU.prototype.clear_tlb = function() { // clear tlb excluding global pages - this.last_virt_eip = -1; - this.last_virt_esp = -1; + this.last_virt_eip[0] = -1; + this.last_virt_esp[0] = -1; this.tlb_info.set(this.tlb_info_global); @@ -4353,7 +4434,10 @@ CPU.prototype.full_clear_tlb = function() //dbg_log("TLB full clear", LOG_CPU); // clear tlb including global pages - var buf32 = new Int32Array(this.tlb_info_global.buffer); + var buf32 = new Int32Array( + this.tlb_info_global.buffer, + this.tlb_info_global.byteOffset, + this.tlb_info_global.length >>> 2); for(var i = 0; i < (1 << 18); ) { buf32[i++] = buf32[i++] = buf32[i++] = buf32[i++] = 0; @@ -4370,18 +4454,18 @@ CPU.prototype.invlpg = function(addr) this.tlb_info[page] = 0; this.tlb_info_global[page] = 0; - this.last_virt_eip = -1; - this.last_virt_esp = -1; + this.last_virt_eip[0] = -1; + this.last_virt_esp[0] = -1; }; CPU.prototype.translate_address_read = function(addr) { - if(!this.paging) + if(!this.paging[0]) { return addr; } - if(this.cpl === 3) + if(this.cpl[0] === 3) { return this.translate_address_user_read(addr); } @@ -4393,12 +4477,12 @@ CPU.prototype.translate_address_read = function(addr) CPU.prototype.translate_address_write = function(addr) { - if(!this.paging) + if(!this.paging[0]) { return addr; } - if(this.cpl === 3) + if(this.cpl[0] === 3) { return this.translate_address_user_write(addr); } @@ -4410,7 +4494,7 @@ CPU.prototype.translate_address_write = function(addr) CPU.prototype.translate_address_user_write = function(addr) { - if(!this.paging) + if(!this.paging[0]) { return addr; } @@ -4429,7 +4513,7 @@ CPU.prototype.translate_address_user_write = function(addr) CPU.prototype.translate_address_user_read = function(addr) { - if(!this.paging) + if(!this.paging[0]) { return addr; } @@ -4448,7 +4532,7 @@ CPU.prototype.translate_address_user_read = function(addr) CPU.prototype.translate_address_system_write = function(addr) { - if(!this.paging) + if(!this.paging[0]) { return addr; } @@ -4467,7 +4551,7 @@ CPU.prototype.translate_address_system_write = function(addr) CPU.prototype.translate_address_system_read = function(addr) { - if(!this.paging) + if(!this.paging[0]) { return addr; } @@ -4542,7 +4626,7 @@ CPU.prototype.do_page_translation = function(addr, for_writing, user) } } - if(page_dir_entry & this.page_size_extensions) + if(page_dir_entry & this.page_size_extensions[0]) { // size bit is set @@ -4642,12 +4726,12 @@ CPU.prototype.writable_or_pagefault = function(addr, size) dbg_assert(size < 0x1000, "not supported yet"); dbg_assert(size > 0); - if(!this.paging) + if(!this.paging[0]) { return; } - var user = this.cpl === 3 ? 1 : 0, + var user = this.cpl[0] === 3 ? 1 : 0, mask = user ? TLB_USER_WRITE : TLB_SYSTEM_WRITE, page = addr >>> 12; @@ -4686,21 +4770,21 @@ CPU.prototype.trigger_pagefault = function(write, user, present) this.tlb_info[page] = 0; this.tlb_info_global[page] = 0; - this.instruction_pointer = this.previous_ip; + this.instruction_pointer[0] = this.previous_ip[0]; this.page_fault = true; - this.call_interrupt_vector(14, false, user << 2 | write << 1 | present); + this.call_interrupt_vector(14, false, true, user << 2 | write << 1 | present); throw MAGIC_CPU_EXCEPTION; }; CPU.prototype.is_osize_32 = function() { - return this.is_32 !== ((this.prefixes & PREFIX_MASK_OPSIZE) === PREFIX_MASK_OPSIZE); + return Boolean(this.is_32[0]) !== ((this.prefixes[0] & PREFIX_MASK_OPSIZE) === PREFIX_MASK_OPSIZE); }; CPU.prototype.is_asize_32 = function() { - return this.is_32 !== ((this.prefixes & PREFIX_MASK_ADDRSIZE) === PREFIX_MASK_ADDRSIZE); + return Boolean(this.is_32[0]) !== ((this.prefixes[0] & PREFIX_MASK_ADDRSIZE) === PREFIX_MASK_ADDRSIZE); }; CPU.prototype.get_reg_asize = function(reg) diff --git a/src/debug.js b/src/debug.js index c7d5771f..97453d25 100644 --- a/src/debug.js +++ b/src/debug.js @@ -130,7 +130,7 @@ CPU.prototype.debug_init = function() cpu.running = false; var a = parseInt(prompt("input hex", ""), 16); - if(a) while(cpu.instruction_pointer != a) step(); + if(a) while(cpu.instruction_pointer[0] != a) step(); } // http://ref.x86asm.net/x86reference.xml @@ -215,15 +215,17 @@ CPU.prototype.debug_init = function() function get_state(where) { - var vm = (cpu.flags & flag_vm) ? 1 : 0; - var mode = cpu.protected_mode ? vm ? "vm86" : "prot" : "real"; + if(!DEBUG) return; + + var mode = cpu.protected_mode[0] ? "prot" : "real"; + var vm = (cpu.flags[0] & flag_vm) ? 1 : 0; var flags = cpu.get_eflags(); var iopl = cpu.getiopl(); - var cpl = cpu.cpl; + var cpl = cpu.cpl[0]; var cs_eip = h(cpu.sreg[reg_cs], 4) + ":" + h(cpu.get_real_eip() >>> 0, 8); var ss_esp = h(cpu.sreg[reg_ss], 4) + ":" + h(cpu.get_stack_reg() >>> 0, 8); - var op_size = cpu.is_32 ? "32" : "16"; - var if_ = (cpu.flags & flag_interrupt) ? 1 : 0; + var op_size = cpu.is_32[0] ? "32" : "16"; + var if_ = (cpu.flags[0] & flag_interrupt) ? 1 : 0; var flag_names = { [flag_carry]: "c", @@ -253,12 +255,12 @@ CPU.prototype.debug_init = function() } } - return ("mode=" + mode + "/" + op_size + " paging=" + (+cpu.paging) + + return ("mode=" + mode + "/" + op_size + " paging=" + (+cpu.paging[0]) + " iopl=" + iopl + " cpl=" + cpl + " if=" + if_ + " cs:eip=" + cs_eip + " cs_off=" + h(cpu.get_seg(reg_cs) >>> 0, 8) + " flgs=" + h(cpu.get_eflags() >>> 0, 6) + " (" + flag_string + ")" + " ss:esp=" + ss_esp + - " ssize=" + (+cpu.stack_size_32) + + " ssize=" + (+cpu.stack_size_32[0]) + (where ? " in " + where : "")); } @@ -357,8 +359,8 @@ CPU.prototype.debug_init = function() { if(!DEBUG) return; - dbg_log("gdt: (len = " + h(cpu.gdtr_size) + ")"); - dump_table(cpu.translate_address_system_read(cpu.gdtr_offset), cpu.gdtr_size); + dbg_log("gdt: (len = " + h(cpu.gdtr_size[0]) + ")"); + dump_table(cpu.translate_address_system_read(cpu.gdtr_offset[0]), cpu.gdtr_size[0]); dbg_log("\nldt: (len = " + h(cpu.segment_limits[reg_ldtr]) + ")"); dump_table(cpu.translate_address_system_read(cpu.segment_offsets[reg_ldtr]), cpu.segment_limits[reg_ldtr]); @@ -439,9 +441,9 @@ CPU.prototype.debug_init = function() { if(!DEBUG) return; - for(var i = 0; i < cpu.idtr_size; i += 8) + for(var i = 0; i < cpu.idtr_size[0]; i += 8) { - var addr = cpu.translate_address_system_read(cpu.idtr_offset + i), + var addr = cpu.translate_address_system_read(cpu.idtr_offset[0] + i), base = cpu.read16(addr) | cpu.read16(addr + 6) << 16, selector = cpu.read16(addr + 2), type = cpu.read8(addr + 5), @@ -583,7 +585,7 @@ CPU.prototype.debug_init = function() if(start === undefined) { start = 0; - count = cpu.memory_size; + count = cpu.memory_size[0]; } else if(count === undefined) { @@ -630,7 +632,7 @@ CPU.prototype.debug_init = function() var width = 0x80, height = 0x10, - block_size = cpu.memory_size / width / height | 0, + block_size = cpu.memory_size[0] / width / height | 0, row; for(var i = 0; i < height; i++) diff --git a/src/externs.js b/src/externs.js index a24e1730..cd914398 100644 --- a/src/externs.js +++ b/src/externs.js @@ -14,3 +14,4 @@ var exports = {}; var define = {}; var module = {}; +var WebAssembly = { Memory() {}, Table() {}, instantiate() {}, compile() {} }; diff --git a/src/fpu.js b/src/fpu.js index ba33a493..cb592ece 100644 --- a/src/fpu.js +++ b/src/fpu.js @@ -76,7 +76,8 @@ function FPU(cpu) // bitmap of which stack registers are empty - this.stack_empty = 0xff; + this.stack_empty = new Int32Array(cpu.wm.mem.buffer, 816, 1); + this.stack_empty[0] = 0xff; this.stack_ptr = 0; this.control_word = 0x37F; @@ -96,14 +97,20 @@ function FPU(cpu) Math.log(2) / Math.LN10, Math.LN2, 0 ]); + this.wasm_patch(); } +FPU.prototype.wasm_patch = function() +{ + this.set_tag_word = this.cpu.wm.funcs["_safe_tag_word"]; +}; + FPU.prototype.get_state = function() { var state = []; state[0] = this.st; - state[1] = this.stack_empty; + state[1] = this.stack_empty[0]; state[2] = this.stack_ptr; state[3] = this.control_word; state[4] = this.fpu_dp_selector; @@ -119,7 +126,7 @@ FPU.prototype.get_state = function() FPU.prototype.set_state = function(state) { this.st.set(state[0]); - this.stack_empty = state[1]; + this.stack_empty[0] = state[1]; this.stack_ptr = state[2]; this.control_word = state[3]; this.fpu_dp_selector = state[4]; @@ -182,23 +189,23 @@ FPU.prototype.fcomi = function(y) { var x = this.st[this.stack_ptr]; - this.cpu.flags_changed &= ~(1 | flag_parity | flag_zero); - this.cpu.flags &= ~(1 | flag_parity | flag_zero); + this.cpu.flags_changed[0] &= ~(1 | flag_parity | flag_zero); + this.cpu.flags[0] &= ~(1 | flag_parity | flag_zero); if(x > y) { } else if(y > x) { - this.cpu.flags |= 1; + this.cpu.flags[0] |= 1; } else if(x === y) { - this.cpu.flags |= flag_zero; + this.cpu.flags[0] |= flag_zero; } else { - this.cpu.flags |= 1 | flag_parity | flag_zero; + this.cpu.flags[0] |= 1 | flag_parity | flag_zero; } } @@ -233,7 +240,7 @@ FPU.prototype.fxam = function(x) this.status_word &= ~FPU_RESULT_FLAGS; this.status_word |= this.sign(0) << 9; - if(this.stack_empty >> this.stack_ptr & 1) + if(this.stack_empty[0] >> this.stack_ptr & 1) { this.status_word |= FPU_C3 | FPU_C0; } @@ -265,7 +272,7 @@ FPU.prototype.finit = function() this.fpu_dp = 0; this.fpu_opcode = 0; - this.stack_empty = 0xFF; + this.stack_empty[0] = 0xFF; this.stack_ptr = 0; } @@ -289,7 +296,7 @@ FPU.prototype.load_tag_word = function() { value = this.st[i]; - if(this.stack_empty >> i & 1) + if(this.stack_empty[0] >> i & 1) { tag_word |= 3 << (i << 1); } @@ -303,18 +310,18 @@ FPU.prototype.load_tag_word = function() } } - //dbg_log("load tw=" + h(tag_word) + " se=" + h(this.stack_empty) + " sp=" + this.stack_ptr, LOG_FPU); + //dbg_log("load tw=" + h(tag_word) + " se=" + h(this.stack_empty[0]) + " sp=" + this.stack_ptr, LOG_FPU); return tag_word; } FPU.prototype.set_tag_word = function(tag_word) { - this.stack_empty = 0; + this.stack_empty[0] = 0; for(var i = 0; i < 8; i++) { - this.stack_empty |= (tag_word >> i) & (tag_word >> i + 1) & 1 << i; + this.stack_empty[0] |= (tag_word >> i) & (tag_word >> i + 1) & 1 << i; } //dbg_log("set_tag_word tw=" + h(tag_word) + " se=" + h(this.stack_empty), LOG_FPU); @@ -447,10 +454,10 @@ FPU.prototype.push = function(x) { this.stack_ptr = this.stack_ptr - 1 & 7; - if(this.stack_empty >> this.stack_ptr & 1) + if(this.stack_empty[0] >> this.stack_ptr & 1) { this.status_word &= ~FPU_C1; - this.stack_empty &= ~(1 << this.stack_ptr); + this.stack_empty[0] &= ~(1 << this.stack_ptr); this.st[this.stack_ptr] = x; } else @@ -463,7 +470,7 @@ FPU.prototype.push = function(x) FPU.prototype.pop = function() { - this.stack_empty |= 1 << this.stack_ptr; + this.stack_empty[0] |= 1 << this.stack_ptr; this.stack_ptr = this.stack_ptr + 1 & 7; } @@ -473,7 +480,7 @@ FPU.prototype.get_sti = function(i) i = i + this.stack_ptr & 7; - if(this.stack_empty >> i & 1) + if(this.stack_empty[0] >> i & 1) { this.status_word &= ~FPU_C1; this.stack_fault(); @@ -487,7 +494,7 @@ FPU.prototype.get_sti = function(i) FPU.prototype.get_st0 = function() { - if(this.stack_empty >> this.stack_ptr & 1) + if(this.stack_empty[0] >> this.stack_ptr & 1) { this.status_word &= ~FPU_C1; this.stack_fault(); @@ -646,12 +653,12 @@ FPU.prototype.dbg_log_fpu_op = function(op, imm8) if(imm8 >= 0xC0) { dbg_log(h(op, 2) + " " + h(imm8, 2) + "/" + (imm8 >> 3 & 7) + "/" + (imm8 & 7) + - " @" + h(this.cpu.instruction_pointer >>> 0, 8) + " sp=" + this.stack_ptr + " st=" + h(this.stack_empty, 2), LOG_FPU); + " @" + h(this.cpu.instruction_pointer[0] >>> 0, 8) + " sp=" + this.stack_ptr + " st=" + h(this.stack_empty[0], 2), LOG_FPU); } else { dbg_log(h(op, 2) + " /" + (imm8 >> 3 & 7) + - " @" + h(this.cpu.instruction_pointer >>> 0, 8) + " sp=" + this.stack_ptr + " st=" + h(this.stack_empty, 2), LOG_FPU); + " @" + h(this.cpu.instruction_pointer[0] >>> 0, 8) + " sp=" + this.stack_ptr + " st=" + h(this.stack_empty[0], 2), LOG_FPU); } } @@ -987,7 +994,7 @@ FPU.prototype.op_DA_reg = function(imm8) if(this.cpu.test_b()) { this.st[this.stack_ptr] = this.get_sti(low); - this.stack_empty &= ~(1 << this.stack_ptr); + this.stack_empty[0] &= ~(1 << this.stack_ptr); } break; case 1: @@ -995,7 +1002,7 @@ FPU.prototype.op_DA_reg = function(imm8) if(this.cpu.test_z()) { this.st[this.stack_ptr] = this.get_sti(low); - this.stack_empty &= ~(1 << this.stack_ptr); + this.stack_empty[0] &= ~(1 << this.stack_ptr); } break; case 2: @@ -1003,7 +1010,7 @@ FPU.prototype.op_DA_reg = function(imm8) if(this.cpu.test_be()) { this.st[this.stack_ptr] = this.get_sti(low); - this.stack_empty &= ~(1 << this.stack_ptr); + this.stack_empty[0] &= ~(1 << this.stack_ptr); } break; case 3: @@ -1011,7 +1018,7 @@ FPU.prototype.op_DA_reg = function(imm8) if(this.cpu.test_p()) { this.st[this.stack_ptr] = this.get_sti(low); - this.stack_empty &= ~(1 << this.stack_ptr); + this.stack_empty[0] &= ~(1 << this.stack_ptr); } break; case 5: @@ -1096,7 +1103,7 @@ FPU.prototype.op_DB_reg = function(imm8) if(!this.cpu.test_b()) { this.st[this.stack_ptr] = this.get_sti(low); - this.stack_empty &= ~(1 << this.stack_ptr); + this.stack_empty[0] &= ~(1 << this.stack_ptr); } break; case 1: @@ -1104,7 +1111,7 @@ FPU.prototype.op_DB_reg = function(imm8) if(!this.cpu.test_z()) { this.st[this.stack_ptr] = this.get_sti(low); - this.stack_empty &= ~(1 << this.stack_ptr); + this.stack_empty[0] &= ~(1 << this.stack_ptr); } break; case 2: @@ -1112,7 +1119,7 @@ FPU.prototype.op_DB_reg = function(imm8) if(!this.cpu.test_be()) { this.st[this.stack_ptr] = this.get_sti(low); - this.stack_empty &= ~(1 << this.stack_ptr); + this.stack_empty[0] &= ~(1 << this.stack_ptr); } break; case 3: @@ -1120,7 +1127,7 @@ FPU.prototype.op_DB_reg = function(imm8) if(!this.cpu.test_p()) { this.st[this.stack_ptr] = this.get_sti(low); - this.stack_empty &= ~(1 << this.stack_ptr); + this.stack_empty[0] &= ~(1 << this.stack_ptr); } break; case 4: @@ -1329,7 +1336,7 @@ FPU.prototype.op_DD_reg = function(imm8) { case 0: // ffree - this.stack_empty |= 1 << (this.stack_ptr + low & 7); + this.stack_empty[0] |= 1 << (this.stack_ptr + low & 7); break; case 2: // fst diff --git a/src/instructions.js b/src/instructions.js index 59b483bb..53558a3d 100644 --- a/src/instructions.js +++ b/src/instructions.js @@ -230,9 +230,9 @@ t[0x62] = cpu => { t[0x63] = cpu => { cpu.read_modrm_byte(); // arpl //dbg_log("arpl", LOG_CPU); - if(cpu.protected_mode && !cpu.vm86_mode()) + if(cpu.protected_mode[0] && !cpu.vm86_mode()) { - cpu.write_e16(cpu.arpl(cpu.read_write_e16(), cpu.modrm_byte >> 2 & 14)); + cpu.write_e16(cpu.arpl(cpu.read_write_e16(), cpu.modrm_byte[0] >> 2 & 14)); } else { @@ -246,18 +246,18 @@ t[0x65] = cpu => { cpu.segment_prefix_op(reg_gs); }; t[0x66] = cpu => { // Operand-size override prefix - cpu.prefixes |= PREFIX_MASK_OPSIZE; + cpu.prefixes[0] |= PREFIX_MASK_OPSIZE; cpu.run_prefix_instruction(); - cpu.prefixes = 0; + cpu.prefixes[0] = 0; }; t[0x67] = cpu => { // Address-size override prefix - dbg_assert(cpu.is_asize_32() === cpu.is_32); + dbg_assert(cpu.is_asize_32() === Boolean(cpu.is_32[0])); - cpu.prefixes |= PREFIX_MASK_ADDRSIZE; + cpu.prefixes[0] |= PREFIX_MASK_ADDRSIZE; cpu.run_prefix_instruction(); - cpu.prefixes = 0; + cpu.prefixes[0] = 0; }; t16[0x68] = cpu => { cpu.push16(cpu.read_op16()); }; @@ -305,7 +305,7 @@ t[0x7E] = cpu => { cpu.jmpcc8( cpu.test_le()); }; t[0x7F] = cpu => { cpu.jmpcc8(!cpu.test_le()); }; t[0x80] = cpu => { cpu.read_modrm_byte(); - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: cpu.write_e8(cpu.add8(cpu.read_write_e8(), cpu.read_op8())); break; case 1: cpu.write_e8(cpu. or8(cpu.read_write_e8(), cpu.read_op8())); break; @@ -318,7 +318,7 @@ t[0x80] = cpu => { cpu.read_modrm_byte(); } }; t16[0x81] = cpu => { cpu.read_modrm_byte(); - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: cpu.write_e16(cpu.add16(cpu.read_write_e16(), cpu.read_op16())); break; case 1: cpu.write_e16(cpu. or16(cpu.read_write_e16(), cpu.read_op16())); break; @@ -331,7 +331,7 @@ t16[0x81] = cpu => { cpu.read_modrm_byte(); } }; t32[0x81] = cpu => { cpu.read_modrm_byte(); - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: cpu.write_e32(cpu.add32(cpu.read_write_e32(), cpu.read_op32s())); break; case 1: cpu.write_e32(cpu. or32(cpu.read_write_e32(), cpu.read_op32s())); break; @@ -345,7 +345,7 @@ t32[0x81] = cpu => { cpu.read_modrm_byte(); }; t[0x82] = t[0x80]; // alias t16[0x83] = cpu => { cpu.read_modrm_byte(); - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: cpu.write_e16(cpu.add16(cpu.read_write_e16(), cpu.read_op8s())); break; case 1: cpu.write_e16(cpu. or16(cpu.read_write_e16(), cpu.read_op8s())); break; @@ -358,7 +358,7 @@ t16[0x83] = cpu => { cpu.read_modrm_byte(); } }; t32[0x83] = cpu => { cpu.read_modrm_byte(); - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: cpu.write_e32(cpu.add32(cpu.read_write_e32(), cpu.read_op8s())); break; case 1: cpu.write_e32(cpu. or32(cpu.read_write_e32(), cpu.read_op8s())); break; @@ -376,12 +376,12 @@ t16[0x85] = cpu => { cpu.read_modrm_byte(); var data = cpu.read_e16(); cpu.test1 t32[0x85] = cpu => { cpu.read_modrm_byte(); var data = cpu.read_e32s(); cpu.test32(data, cpu.read_g32s()); } -t[0x86] = cpu => { cpu.read_modrm_byte(); var data = cpu.read_write_e8(); cpu.write_e8(cpu.xchg8(data, cpu.modrm_byte)); }; +t[0x86] = cpu => { cpu.read_modrm_byte(); var data = cpu.read_write_e8(); cpu.write_e8(cpu.xchg8(data, cpu.modrm_byte[0])); }; t16[0x87] = cpu => { cpu.read_modrm_byte(); - var data = cpu.read_write_e16(); cpu.write_e16(cpu.xchg16(data, cpu.modrm_byte)); + var data = cpu.read_write_e16(); cpu.write_e16(cpu.xchg16(data, cpu.modrm_byte[0])); }; t32[0x87] = cpu => { cpu.read_modrm_byte(); - var data = cpu.read_write_e32(); cpu.write_e32(cpu.xchg32(data, cpu.modrm_byte)); + var data = cpu.read_write_e32(); cpu.write_e32(cpu.xchg32(data, cpu.modrm_byte[0])); }; t[0x88] = cpu => { cpu.read_modrm_byte(); cpu.set_e8(cpu.read_g8()); }; @@ -402,41 +402,41 @@ t32[0x8B] = cpu => { cpu.read_modrm_byte(); }; t16[0x8C] = cpu => { cpu.read_modrm_byte(); - cpu.set_e16(cpu.sreg[cpu.modrm_byte >> 3 & 7]); + cpu.set_e16(cpu.sreg[cpu.modrm_byte[0] >> 3 & 7]); }; t32[0x8C] = cpu => { cpu.read_modrm_byte(); - cpu.set_e32(cpu.sreg[cpu.modrm_byte >> 3 & 7]); + cpu.set_e32(cpu.sreg[cpu.modrm_byte[0] >> 3 & 7]); }; t16[0x8D] = cpu => { cpu.read_modrm_byte(); // lea - if(cpu.modrm_byte >= 0xC0) + if(cpu.modrm_byte[0] >= 0xC0) { dbg_log("lea #ud", LOG_CPU); cpu.trigger_ud(); } - var mod = cpu.modrm_byte >> 3 & 7; + var mod = cpu.modrm_byte[0] >> 3 & 7; // override prefix, so modrm_resolve does not return the segment part - cpu.prefixes |= SEG_PREFIX_ZERO; - cpu.reg16[mod << 1] = cpu.modrm_resolve(cpu.modrm_byte); - cpu.prefixes = 0; + cpu.prefixes[0] |= SEG_PREFIX_ZERO; + cpu.reg16[mod << 1] = cpu.modrm_resolve(cpu.modrm_byte[0]); + cpu.prefixes[0] = 0; }; t32[0x8D] = cpu => { cpu.read_modrm_byte(); - if(cpu.modrm_byte >= 0xC0) + if(cpu.modrm_byte[0] >= 0xC0) { dbg_log("lea #ud", LOG_CPU); cpu.trigger_ud(); } - var mod = cpu.modrm_byte >> 3 & 7; + var mod = cpu.modrm_byte[0] >> 3 & 7; - cpu.prefixes |= SEG_PREFIX_ZERO; - cpu.reg32s[mod] = cpu.modrm_resolve(cpu.modrm_byte); - cpu.prefixes = 0; + cpu.prefixes[0] |= SEG_PREFIX_ZERO; + cpu.reg32s[mod] = cpu.modrm_resolve(cpu.modrm_byte[0]); + cpu.prefixes[0] = 0; }; t[0x8E] = cpu => { cpu.read_modrm_byte(); - var mod = cpu.modrm_byte >> 3 & 7; + var mod = cpu.modrm_byte[0] >> 3 & 7; var data = cpu.read_e16(); cpu.switch_seg(mod, data); @@ -454,8 +454,8 @@ t16[0x8F] = cpu => { cpu.read_modrm_byte(); cpu.adjust_stack_reg(2); - if(cpu.modrm_byte < 0xC0) { - var addr = cpu.modrm_resolve(cpu.modrm_byte); + if(cpu.modrm_byte[0] < 0xC0) { + var addr = cpu.modrm_resolve(cpu.modrm_byte[0]); cpu.adjust_stack_reg(-2); cpu.safe_write16(addr, sp); cpu.adjust_stack_reg(2); @@ -469,8 +469,8 @@ t32[0x8F] = cpu => { cpu.read_modrm_byte(); // change esp first, then resolve modrm address cpu.adjust_stack_reg(4); - if(cpu.modrm_byte < 0xC0) { - var addr = cpu.modrm_resolve(cpu.modrm_byte); + if(cpu.modrm_byte[0] < 0xC0) { + var addr = cpu.modrm_resolve(cpu.modrm_byte[0]); // Before attempting a write that might cause a page fault, // we must set esp to the old value. Fuck Intel. @@ -516,7 +516,7 @@ t32[0x9A] = cpu => { var new_ip = cpu.read_op32s(); var new_cs = cpu.read_disp16(); - if(!cpu.protected_mode || cpu.vm86_mode()) + if(!cpu.protected_mode[0] || cpu.vm86_mode()) { if(new_ip & 0xFFFF0000) { @@ -551,9 +551,9 @@ t[0x9B] = cpu => { }; t16[0x9C] = cpu => { // pushf - if((cpu.flags & flag_vm) && cpu.getiopl() < 3) + if((cpu.flags[0] & flag_vm) && cpu.getiopl() < 3) { - dbg_assert(cpu.protected_mode); + dbg_assert(cpu.protected_mode[0]); dbg_log("pushf #gp", LOG_CPU); cpu.trigger_gp(0); } @@ -564,10 +564,10 @@ t16[0x9C] = cpu => { }; t32[0x9C] = cpu => { // pushf - if((cpu.flags & flag_vm) && cpu.getiopl() < 3) + if((cpu.flags[0] & flag_vm) && cpu.getiopl() < 3) { // trap to virtual 8086 monitor - dbg_assert(cpu.protected_mode); + dbg_assert(cpu.protected_mode[0]); dbg_log("pushf #gp", LOG_CPU); cpu.trigger_gp(0); } @@ -579,20 +579,20 @@ t32[0x9C] = cpu => { }; t16[0x9D] = cpu => { // popf - if((cpu.flags & flag_vm) && cpu.getiopl() < 3) + if((cpu.flags[0] & flag_vm) && cpu.getiopl() < 3) { dbg_log("popf #gp", LOG_CPU); cpu.trigger_gp(0); } - cpu.update_eflags((cpu.flags & ~0xFFFF) | cpu.pop16()); + cpu.update_eflags((cpu.flags[0] & ~0xFFFF) | cpu.pop16()); - if(cpu.flags & flag_trap) + if(cpu.flags[0] & flag_trap) { // XXX: Problems with fdgame //cpu.clear_prefixes(); //cpu.cycle_internal(); - cpu.flags &= ~flag_trap; + cpu.flags[0] &= ~flag_trap; //cpu.instruction_pointer = cpu.previous_ip; //cpu.raise_exception(1); } @@ -603,7 +603,7 @@ t16[0x9D] = cpu => { }; t32[0x9D] = cpu => { // popf - if((cpu.flags & flag_vm) && cpu.getiopl() < 3) + if((cpu.flags[0] & flag_vm) && cpu.getiopl() < 3) { dbg_log("popf #gp", LOG_CPU); cpu.trigger_gp(0); @@ -614,9 +614,9 @@ t32[0x9D] = cpu => { }; t[0x9E] = cpu => { // sahf - cpu.flags = (cpu.flags & ~0xFF) | cpu.reg8[reg_ah]; - cpu.flags = (cpu.flags & flags_mask) | flags_default; - cpu.flags_changed = 0; + cpu.flags[0] = (cpu.flags[0] & ~0xFF) | cpu.reg8[reg_ah]; + cpu.flags[0] = (cpu.flags[0] & flags_mask) | flags_default; + cpu.flags_changed[0] = 0; }; t[0x9F] = cpu => { // lahf @@ -708,7 +708,7 @@ t[0xC0] = cpu => { cpu.read_modrm_byte(); var op1 = cpu.read_write_e8(); var op2 = cpu.read_op8() & 31; var result = 0; - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: result = cpu.rol8(op1, op2); break; case 1: result = cpu.ror8(op1, op2); break; @@ -725,7 +725,7 @@ t16[0xC1] = cpu => { cpu.read_modrm_byte(); var op1 = cpu.read_write_e16(); var op2 = cpu.read_op8() & 31; var result = 0; - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: result = cpu.rol16(op1, op2); break; case 1: result = cpu.ror16(op1, op2); break; @@ -742,7 +742,7 @@ t32[0xC1] = cpu => { cpu.read_modrm_byte(); var op1 = cpu.read_write_e32(); var op2 = cpu.read_op8() & 31; var result = 0; - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: result = cpu.rol32(op1, op2); break; case 1: result = cpu.ror32(op1, op2); break; @@ -760,7 +760,7 @@ t16[0xC2] = cpu => { // retn var imm16 = cpu.read_op16(); - cpu.instruction_pointer = cpu.get_seg(reg_cs) + cpu.pop16() | 0; + cpu.instruction_pointer[0] = cpu.get_seg(reg_cs) + cpu.pop16() | 0; dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000); cpu.adjust_stack_reg(imm16); cpu.diverged(); @@ -771,20 +771,20 @@ t32[0xC2] = cpu => { var ip = cpu.pop32s(); dbg_assert(cpu.is_asize_32() || ip < 0x10000); - cpu.instruction_pointer = cpu.get_seg(reg_cs) + ip | 0; + cpu.instruction_pointer[0] = cpu.get_seg(reg_cs) + ip | 0; cpu.adjust_stack_reg(imm16); cpu.diverged(); }; t16[0xC3] = cpu => { // retn - cpu.instruction_pointer = cpu.get_seg(reg_cs) + cpu.pop16() | 0; + cpu.instruction_pointer[0] = cpu.get_seg(reg_cs) + cpu.pop16() | 0; cpu.diverged(); }; t32[0xC3] = cpu => { // retn var ip = cpu.pop32s(); dbg_assert(cpu.is_asize_32() || ip < 0x10000); - cpu.instruction_pointer = cpu.get_seg(reg_cs) + ip | 0; + cpu.instruction_pointer[0] = cpu.get_seg(reg_cs) + ip | 0; cpu.diverged(); }; @@ -802,24 +802,24 @@ t32[0xC5] = cpu => { cpu.read_modrm_byte(); }; t[0xC6] = cpu => { cpu.read_modrm_byte(); - if(cpu.modrm_byte < 0xC0) { - cpu.safe_write8(cpu.modrm_resolve(cpu.modrm_byte), cpu.read_op8()); + if(cpu.modrm_byte[0] < 0xC0) { + cpu.safe_write8(cpu.modrm_resolve(cpu.modrm_byte[0]), cpu.read_op8()); } else { - cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = cpu.read_op8(); + cpu.reg8[cpu.modrm_byte[0] << 2 & 0xC | cpu.modrm_byte[0] >> 2 & 1] = cpu.read_op8(); } } t16[0xC7] = cpu => { cpu.read_modrm_byte(); - if(cpu.modrm_byte < 0xC0) { - cpu.safe_write16(cpu.modrm_resolve(cpu.modrm_byte), cpu.read_op16()); + if(cpu.modrm_byte[0] < 0xC0) { + cpu.safe_write16(cpu.modrm_resolve(cpu.modrm_byte[0]), cpu.read_op16()); } else { - cpu.reg16[cpu.modrm_byte << 1 & 14] = cpu.read_op16(); + cpu.reg16[cpu.modrm_byte[0] << 1 & 14] = cpu.read_op16(); } }; t32[0xC7] = cpu => { cpu.read_modrm_byte(); - if(cpu.modrm_byte < 0xC0) { - cpu.safe_write32(cpu.modrm_resolve(cpu.modrm_byte), cpu.read_op32s()); + if(cpu.modrm_byte[0] < 0xC0) { + cpu.safe_write32(cpu.modrm_resolve(cpu.modrm_byte[0]), cpu.read_op32s()); } else { - cpu.reg32s[cpu.modrm_byte & 7] = cpu.read_op32s(); + cpu.reg32s[cpu.modrm_byte[0] & 7] = cpu.read_op32s(); } } @@ -827,13 +827,13 @@ t16[0xC8] = cpu => { cpu.enter16(cpu.read_op16(), cpu.read_disp8()); }; t32[0xC8] = cpu => { cpu.enter32(cpu.read_op16(), cpu.read_disp8()); }; t16[0xC9] = cpu => { // leave - var old_vbp = cpu.stack_size_32 ? cpu.reg32s[reg_ebp] : cpu.reg16[reg_bp]; + var old_vbp = cpu.stack_size_32[0] ? cpu.reg32s[reg_ebp] : cpu.reg16[reg_bp]; var new_bp = cpu.safe_read16(cpu.get_seg(reg_ss) + old_vbp | 0); cpu.set_stack_reg(old_vbp + 2 | 0); cpu.reg16[reg_bp] = new_bp; }; t32[0xC9] = cpu => { - var old_vbp = cpu.stack_size_32 ? cpu.reg32s[reg_ebp] : cpu.reg16[reg_bp]; + var old_vbp = cpu.stack_size_32[0] ? cpu.reg32s[reg_ebp] : cpu.reg16[reg_bp]; var new_ebp = cpu.safe_read32s(cpu.get_seg(reg_ss) + old_vbp | 0); cpu.set_stack_reg(old_vbp + 4 | 0); cpu.reg32s[reg_ebp] = new_ebp; @@ -880,13 +880,13 @@ t[0xCC] = cpu => { // INT3 // TODO: inhibit iopl checks dbg_log("INT3", LOG_CPU); - cpu.call_interrupt_vector(3, true, false); + cpu.call_interrupt_vector(3, true, false, 0); cpu.diverged(); }; t[0xCD] = cpu => { // INT var imm8 = cpu.read_op8(); - cpu.call_interrupt_vector(imm8, true, false); + cpu.call_interrupt_vector(imm8, true, false, 0); cpu.diverged(); }; t[0xCE] = cpu => { @@ -895,7 +895,7 @@ t[0xCE] = cpu => { if(cpu.getof()) { // TODO: inhibit iopl checks - cpu.call_interrupt_vector(4, true, false); + cpu.call_interrupt_vector(4, true, false, 0); } cpu.diverged(); }; @@ -913,7 +913,7 @@ t32[0xCF] = cpu => { t[0xD0] = cpu => { cpu.read_modrm_byte(); var op1 = cpu.read_write_e8(); var result = 0; - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: result = cpu.rol8(op1, 1); break; case 1: result = cpu.ror8(op1, 1); break; @@ -929,7 +929,7 @@ t[0xD0] = cpu => { cpu.read_modrm_byte(); t16[0xD1] = cpu => { cpu.read_modrm_byte(); var op1 = cpu.read_write_e16(); var result = 0; - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: result = cpu.rol16(op1, 1); break; case 1: result = cpu.ror16(op1, 1); break; @@ -945,7 +945,7 @@ t16[0xD1] = cpu => { cpu.read_modrm_byte(); t32[0xD1] = cpu => { cpu.read_modrm_byte(); var op1 = cpu.read_write_e32(); var result = 0; - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: result = cpu.rol32(op1, 1); break; case 1: result = cpu.ror32(op1, 1); break; @@ -963,7 +963,7 @@ t[0xD2] = cpu => { cpu.read_modrm_byte(); var op1 = cpu.read_write_e8(); var op2 = cpu.reg8[reg_cl] & 31; var result = 0; - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: result = cpu.rol8(op1, op2); break; case 1: result = cpu.ror8(op1, op2); break; @@ -980,7 +980,7 @@ t16[0xD3] = cpu => { cpu.read_modrm_byte(); var op1 = cpu.read_write_e16(); var op2 = cpu.reg8[reg_cl] & 31; var result = 0; - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: result = cpu.rol16(op1, op2); break; case 1: result = cpu.ror16(op1, op2); break; @@ -997,7 +997,7 @@ t32[0xD3] = cpu => { cpu.read_modrm_byte(); var op1 = cpu.read_write_e32(); var op2 = cpu.reg8[reg_cl] & 31; var result = 0; - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: result = cpu.rol32(op1, op2); break; case 1: result = cpu.ror32(op1, op2); break; @@ -1036,59 +1036,59 @@ t[0xD7] = cpu => { t[0xD8] = cpu => { cpu.read_modrm_byte(); cpu.task_switch_test(); - if(cpu.modrm_byte < 0xC0) - cpu.fpu.op_D8_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); + if(cpu.modrm_byte[0] < 0xC0) + cpu.fpu.op_D8_mem(cpu.modrm_byte[0], cpu.modrm_resolve(cpu.modrm_byte[0])); else - cpu.fpu.op_D8_reg(cpu.modrm_byte); + cpu.fpu.op_D8_reg(cpu.modrm_byte[0]); }; t[0xD9] = cpu => { cpu.read_modrm_byte(); cpu.task_switch_test(); - if(cpu.modrm_byte < 0xC0) - cpu.fpu.op_D9_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); + if(cpu.modrm_byte[0] < 0xC0) + cpu.fpu.op_D9_mem(cpu.modrm_byte[0], cpu.modrm_resolve(cpu.modrm_byte[0])); else - cpu.fpu.op_D9_reg(cpu.modrm_byte); + cpu.fpu.op_D9_reg(cpu.modrm_byte[0]); }; t[0xDA] = cpu => { cpu.read_modrm_byte(); cpu.task_switch_test(); - if(cpu.modrm_byte < 0xC0) - cpu.fpu.op_DA_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); + if(cpu.modrm_byte[0] < 0xC0) + cpu.fpu.op_DA_mem(cpu.modrm_byte[0], cpu.modrm_resolve(cpu.modrm_byte[0])); else - cpu.fpu.op_DA_reg(cpu.modrm_byte); + cpu.fpu.op_DA_reg(cpu.modrm_byte[0]); }; t[0xDB] = cpu => { cpu.read_modrm_byte(); cpu.task_switch_test(); - if(cpu.modrm_byte < 0xC0) - cpu.fpu.op_DB_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); + if(cpu.modrm_byte[0] < 0xC0) + cpu.fpu.op_DB_mem(cpu.modrm_byte[0], cpu.modrm_resolve(cpu.modrm_byte[0])); else - cpu.fpu.op_DB_reg(cpu.modrm_byte); + cpu.fpu.op_DB_reg(cpu.modrm_byte[0]); }; t[0xDC] = cpu => { cpu.read_modrm_byte(); cpu.task_switch_test(); - if(cpu.modrm_byte < 0xC0) - cpu.fpu.op_DC_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); + if(cpu.modrm_byte[0] < 0xC0) + cpu.fpu.op_DC_mem(cpu.modrm_byte[0], cpu.modrm_resolve(cpu.modrm_byte[0])); else - cpu.fpu.op_DC_reg(cpu.modrm_byte); + cpu.fpu.op_DC_reg(cpu.modrm_byte[0]); }; t[0xDD] = cpu => { cpu.read_modrm_byte(); cpu.task_switch_test(); - if(cpu.modrm_byte < 0xC0) - cpu.fpu.op_DD_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); + if(cpu.modrm_byte[0] < 0xC0) + cpu.fpu.op_DD_mem(cpu.modrm_byte[0], cpu.modrm_resolve(cpu.modrm_byte[0])); else - cpu.fpu.op_DD_reg(cpu.modrm_byte); + cpu.fpu.op_DD_reg(cpu.modrm_byte[0]); }; t[0xDE] = cpu => { cpu.read_modrm_byte(); cpu.task_switch_test(); - if(cpu.modrm_byte < 0xC0) - cpu.fpu.op_DE_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); + if(cpu.modrm_byte[0] < 0xC0) + cpu.fpu.op_DE_mem(cpu.modrm_byte[0], cpu.modrm_resolve(cpu.modrm_byte[0])); else - cpu.fpu.op_DE_reg(cpu.modrm_byte); + cpu.fpu.op_DE_reg(cpu.modrm_byte[0]); }; t[0xDF] = cpu => { cpu.read_modrm_byte(); cpu.task_switch_test(); - if(cpu.modrm_byte < 0xC0) - cpu.fpu.op_DF_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); + if(cpu.modrm_byte[0] < 0xC0) + cpu.fpu.op_DF_mem(cpu.modrm_byte[0], cpu.modrm_resolve(cpu.modrm_byte[0])); else - cpu.fpu.op_DF_reg(cpu.modrm_byte); + cpu.fpu.op_DF_reg(cpu.modrm_byte[0]); }; t[0xE0] = cpu => { cpu.loopne(cpu.read_op8s()); }; @@ -1146,7 +1146,7 @@ t32[0xE8] = cpu => { var imm32s = cpu.read_op32s(); cpu.push32(cpu.get_real_eip()); - cpu.instruction_pointer = cpu.instruction_pointer + imm32s | 0; + cpu.instruction_pointer[0] = cpu.instruction_pointer[0] + imm32s | 0; dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000); cpu.diverged(); }; @@ -1159,7 +1159,7 @@ t16[0xE9] = cpu => { t32[0xE9] = cpu => { // jmp var imm32s = cpu.read_op32s(); - cpu.instruction_pointer = cpu.instruction_pointer + imm32s | 0; + cpu.instruction_pointer[0] = cpu.instruction_pointer[0] + imm32s | 0; dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000); cpu.diverged(); }; @@ -1182,7 +1182,7 @@ t32[0xEA] = cpu => { t[0xEB] = cpu => { // jmp near var imm8 = cpu.read_op8s(); - cpu.instruction_pointer = cpu.instruction_pointer + imm8 | 0; + cpu.instruction_pointer[0] = cpu.instruction_pointer[0] + imm8 | 0; dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000); cpu.diverged(); }; @@ -1241,17 +1241,17 @@ t[0xF1] = cpu => { t[0xF2] = cpu => { // repnz - dbg_assert((cpu.prefixes & PREFIX_MASK_REP) === 0); - cpu.prefixes |= PREFIX_REPNZ; + dbg_assert((cpu.prefixes[0] & PREFIX_MASK_REP) === 0); + cpu.prefixes[0] |= PREFIX_REPNZ; cpu.run_prefix_instruction(); - cpu.prefixes = 0; + cpu.prefixes[0] = 0; }; t[0xF3] = cpu => { // repz - dbg_assert((cpu.prefixes & PREFIX_MASK_REP) === 0); - cpu.prefixes |= PREFIX_REPZ; + dbg_assert((cpu.prefixes[0] & PREFIX_MASK_REP) === 0); + cpu.prefixes[0] |= PREFIX_REPZ; cpu.run_prefix_instruction(); - cpu.prefixes = 0; + cpu.prefixes[0] = 0; }; t[0xF4] = cpu => { @@ -1260,12 +1260,12 @@ t[0xF4] = cpu => { t[0xF5] = cpu => { // cmc - cpu.flags = (cpu.flags | 1) ^ cpu.getcf(); - cpu.flags_changed &= ~1; + cpu.flags[0] = (cpu.flags[0] | 1) ^ cpu.getcf(); + cpu.flags_changed[0] &= ~1; }; t[0xF6] = cpu => { cpu.read_modrm_byte(); - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: var data = cpu.read_e8(); cpu.test8(data, cpu.read_op8()); @@ -1295,7 +1295,7 @@ t[0xF6] = cpu => { cpu.read_modrm_byte(); }; t16[0xF7] = cpu => { cpu.read_modrm_byte(); - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: var data = cpu.read_e16(); cpu.test16(data, cpu.read_op16()); @@ -1324,7 +1324,7 @@ t16[0xF7] = cpu => { cpu.read_modrm_byte(); } }; t32[0xF7] = cpu => { cpu.read_modrm_byte(); - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: var data = cpu.read_e32s(); cpu.test32(data, cpu.read_op32s()); @@ -1355,31 +1355,31 @@ t32[0xF7] = cpu => { cpu.read_modrm_byte(); t[0xF8] = cpu => { // clc - cpu.flags &= ~flag_carry; - cpu.flags_changed &= ~1; + cpu.flags[0] &= ~flag_carry; + cpu.flags_changed[0] &= ~1; }; t[0xF9] = cpu => { // stc - cpu.flags |= flag_carry; - cpu.flags_changed &= ~1; + cpu.flags[0] |= flag_carry; + cpu.flags_changed[0] &= ~1; }; t[0xFA] = cpu => { // cli //dbg_log("interrupts off"); - if(!cpu.protected_mode || ((cpu.flags & flag_vm) ? - cpu.getiopl() === 3 : cpu.getiopl() >= cpu.cpl)) + if(!cpu.protected_mode[0] || ((cpu.flags[0] & flag_vm) ? + cpu.getiopl() === 3 : cpu.getiopl() >= cpu.cpl[0])) { - cpu.flags &= ~flag_interrupt; + cpu.flags[0] &= ~flag_interrupt; } else { - //if(cpu.getiopl() < 3 && ((cpu.flags & flag_vm) ? + //if(cpu.getiopl() < 3 && ((cpu.flags[0] & flag_vm) ? // (cpu.cr[4] & CR4_VME) : - // (cpu.cpl === 3 && (cpu.cr[4] & CR4_PVI)))) + // (cpu.cpl[0] === 3 && (cpu.cr[4] & CR4_PVI)))) //{ - // cpu.flags &= ~flag_vif; + // cpu.flags[0] &= ~flag_vif; //} //else { @@ -1392,10 +1392,10 @@ t[0xFB] = cpu => { // sti //dbg_log("interrupts on"); - if(!cpu.protected_mode || ((cpu.flags & flag_vm) ? - cpu.getiopl() === 3 : cpu.getiopl() >= cpu.cpl)) + if(!cpu.protected_mode[0] || ((cpu.flags[0] & flag_vm) ? + cpu.getiopl() === 3 : cpu.getiopl() >= cpu.cpl[0])) { - cpu.flags |= flag_interrupt; + cpu.flags[0] |= flag_interrupt; cpu.clear_prefixes(); cpu.cycle_internal(); @@ -1404,11 +1404,11 @@ t[0xFB] = cpu => { } else { - //if(cpu.getiopl() < 3 && (cpu.flags & flag_vip) === 0 && ((cpu.flags & flag_vm) ? + //if(cpu.getiopl() < 3 && (cpu.flags[0] & flag_vip) === 0 && ((cpu.flags[0] & flag_vm) ? // (cpu.cr[4] & CR4_VME) : - // (cpu.cpl === 3 && (cpu.cr[4] & CR4_PVI)))) + // (cpu.cpl[0] === 3 && (cpu.cr[4] & CR4_PVI)))) //{ - // cpu.flags |= flag_vif; + // cpu.flags[0] |= flag_vif; //} //else { @@ -1421,15 +1421,15 @@ t[0xFB] = cpu => { t[0xFC] = cpu => { // cld - cpu.flags &= ~flag_direction; + cpu.flags[0] &= ~flag_direction; }; t[0xFD] = cpu => { // std - cpu.flags |= flag_direction; + cpu.flags[0] |= flag_direction; }; t[0xFE] = cpu => { cpu.read_modrm_byte(); - var mod = cpu.modrm_byte & 56; + var mod = cpu.modrm_byte[0] & 56; if(mod === 0) { @@ -1445,7 +1445,7 @@ t[0xFE] = cpu => { cpu.read_modrm_byte(); } }; t16[0xFF] = cpu => { cpu.read_modrm_byte(); - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: var data = cpu.read_write_e16(); cpu.write_e16(cpu.inc16(data)); @@ -1457,20 +1457,20 @@ t16[0xFF] = cpu => { cpu.read_modrm_byte(); // 2, call near var data = cpu.read_e16(); cpu.push16(cpu.get_real_eip()); - cpu.instruction_pointer = cpu.get_seg(reg_cs) + data | 0; + cpu.instruction_pointer[0] = cpu.get_seg(reg_cs) + data | 0; dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000); cpu.diverged(); break; case 3: // 3, callf - if(cpu.modrm_byte >= 0xC0) + if(cpu.modrm_byte[0] >= 0xC0) { dbg_log("callf #ud", LOG_CPU); cpu.trigger_ud(); dbg_assert(false, "unreachable"); } - var virt_addr = cpu.modrm_resolve(cpu.modrm_byte); + var virt_addr = cpu.modrm_resolve(cpu.modrm_byte[0]); var new_ip = cpu.safe_read16(virt_addr); var new_cs = cpu.safe_read16(virt_addr + 2 | 0); @@ -1481,20 +1481,20 @@ t16[0xFF] = cpu => { cpu.read_modrm_byte(); case 4: // 4, jmp near var data = cpu.read_e16(); - cpu.instruction_pointer = cpu.get_seg(reg_cs) + data | 0; + cpu.instruction_pointer[0] = cpu.get_seg(reg_cs) + data | 0; dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000); cpu.diverged(); break; case 5: // 5, jmpf - if(cpu.modrm_byte >= 0xC0) + if(cpu.modrm_byte[0] >= 0xC0) { dbg_log("jmpf #ud", LOG_CPU); cpu.trigger_ud(); dbg_assert(false, "unreachable"); } - var virt_addr = cpu.modrm_resolve(cpu.modrm_byte); + var virt_addr = cpu.modrm_resolve(cpu.modrm_byte[0]); var new_ip = cpu.safe_read16(virt_addr); var new_cs = cpu.safe_read16(virt_addr + 2 | 0); @@ -1512,7 +1512,7 @@ t16[0xFF] = cpu => { cpu.read_modrm_byte(); } }; t32[0xFF] = cpu => { cpu.read_modrm_byte(); - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: var data = cpu.read_write_e32(); cpu.write_e32(cpu.inc32(data)); @@ -1526,23 +1526,23 @@ t32[0xFF] = cpu => { cpu.read_modrm_byte(); cpu.push32(cpu.get_real_eip()); dbg_assert(cpu.is_asize_32() || data < 0x10000); - cpu.instruction_pointer = cpu.get_seg(reg_cs) + data | 0; + cpu.instruction_pointer[0] = cpu.get_seg(reg_cs) + data | 0; cpu.diverged(); break; case 3: // 3, callf - if(cpu.modrm_byte >= 0xC0) + if(cpu.modrm_byte[0] >= 0xC0) { dbg_log("callf #ud", LOG_CPU); cpu.trigger_ud(); dbg_assert(false, "unreachable"); } - var virt_addr = cpu.modrm_resolve(cpu.modrm_byte); + var virt_addr = cpu.modrm_resolve(cpu.modrm_byte[0]); var new_ip = cpu.safe_read32s(virt_addr); var new_cs = cpu.safe_read16(virt_addr + 4 | 0); - if(!cpu.protected_mode || cpu.vm86_mode()) + if(!cpu.protected_mode[0] || cpu.vm86_mode()) { if(new_ip & 0xFFFF0000) { @@ -1558,23 +1558,23 @@ t32[0xFF] = cpu => { cpu.read_modrm_byte(); // 4, jmp near var data = cpu.read_e32s(); dbg_assert(cpu.is_asize_32() || data < 0x10000); - cpu.instruction_pointer = cpu.get_seg(reg_cs) + data | 0; + cpu.instruction_pointer[0] = cpu.get_seg(reg_cs) + data | 0; cpu.diverged(); break; case 5: // 5, jmpf - if(cpu.modrm_byte >= 0xC0) + if(cpu.modrm_byte[0] >= 0xC0) { dbg_log("jmpf #ud", LOG_CPU); cpu.trigger_ud(); dbg_assert(false, "unreachable"); } - var virt_addr = cpu.modrm_resolve(cpu.modrm_byte); + var virt_addr = cpu.modrm_resolve(cpu.modrm_byte[0]); var new_ip = cpu.safe_read32s(virt_addr); var new_cs = cpu.safe_read16(virt_addr + 4 | 0); - if(!cpu.protected_mode || cpu.vm86_mode()) + if(!cpu.protected_mode[0] || cpu.vm86_mode()) { if(new_ip & 0xFFFF0000) { @@ -1625,34 +1625,34 @@ t32 = []; // 0F ops start here t[0x00] = cpu => { cpu.read_modrm_byte(); - if(!cpu.protected_mode || cpu.vm86_mode()) + if(!cpu.protected_mode[0] || cpu.vm86_mode()) { // No GP, UD is correct here dbg_log("0f 00 #ud", LOG_CPU); cpu.trigger_ud(); } - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: // sldt cpu.set_e16(cpu.sreg[reg_ldtr]); - if(cpu.is_osize_32() && cpu.modrm_byte >= 0xC0) + if(cpu.is_osize_32() && cpu.modrm_byte[0] >= 0xC0) { - cpu.reg32s[cpu.modrm_byte & 7] &= 0xFFFF; + cpu.reg32s[cpu.modrm_byte[0] & 7] &= 0xFFFF; } break; case 1: // str cpu.set_e16(cpu.sreg[reg_tr]); - if(cpu.is_osize_32() && cpu.modrm_byte >= 0xC0) + if(cpu.is_osize_32() && cpu.modrm_byte[0] >= 0xC0) { - cpu.reg32s[cpu.modrm_byte & 7] &= 0xFFFF; + cpu.reg32s[cpu.modrm_byte[0] & 7] &= 0xFFFF; } break; case 2: // lldt - if(cpu.cpl) + if(cpu.cpl[0]) { cpu.trigger_gp(0); } @@ -1662,7 +1662,7 @@ t[0x00] = cpu => { cpu.read_modrm_byte(); break; case 3: // ltr - if(cpu.cpl) + if(cpu.cpl[0]) { cpu.trigger_gp(0); } @@ -1678,18 +1678,18 @@ t[0x00] = cpu => { cpu.read_modrm_byte(); break; default: - dbg_log(cpu.modrm_byte >> 3 & 7, LOG_CPU); + dbg_log(cpu.modrm_byte[0] >> 3 & 7, LOG_CPU); cpu.todo(); } }; t[0x01] = cpu => { cpu.read_modrm_byte(); - var mod = cpu.modrm_byte >> 3 & 7; + var mod = cpu.modrm_byte[0] >> 3 & 7; if(mod === 4) { // smsw - if(cpu.modrm_byte >= 0xC0 && cpu.is_osize_32()) + if(cpu.modrm_byte[0] >= 0xC0 && cpu.is_osize_32()) { cpu.set_e32(cpu.cr[0]); } @@ -1702,7 +1702,7 @@ t[0x01] = cpu => { cpu.read_modrm_byte(); else if(mod === 6) { // lmsw - if(cpu.cpl) + if(cpu.cpl[0]) { cpu.trigger_gp(0); } @@ -1711,7 +1711,7 @@ t[0x01] = cpu => { cpu.read_modrm_byte(); cr0 = (cpu.cr[0] & ~0xF) | (cr0 & 0xF); - if(cpu.protected_mode) + if(cpu.protected_mode[0]) { // lmsw cannot be used to switch back cr0 |= CR0_PE; @@ -1721,34 +1721,34 @@ t[0x01] = cpu => { cpu.read_modrm_byte(); return; } - if(cpu.modrm_byte >= 0xC0) + if(cpu.modrm_byte[0] >= 0xC0) { // only memory dbg_log("0f 01 #ud", LOG_CPU); cpu.trigger_ud(); } - var addr = cpu.modrm_resolve(cpu.modrm_byte); + var addr = cpu.modrm_resolve(cpu.modrm_byte[0]); switch(mod) { case 0: // sgdt cpu.writable_or_pagefault(addr, 6); - cpu.safe_write16(addr, cpu.gdtr_size); + cpu.safe_write16(addr, cpu.gdtr_size[0]); var mask = cpu.is_osize_32() ? -1 : 0x00FFFFFF; - cpu.safe_write32(addr + 2, cpu.gdtr_offset & mask); + cpu.safe_write32(addr + 2, cpu.gdtr_offset[0] & mask); break; case 1: // sidt cpu.writable_or_pagefault(addr, 6); - cpu.safe_write16(addr, cpu.idtr_size); + cpu.safe_write16(addr, cpu.idtr_size[0]); var mask = cpu.is_osize_32() ? -1 : 0x00FFFFFF; - cpu.safe_write32(addr + 2, cpu.idtr_offset & mask); + cpu.safe_write32(addr + 2, cpu.idtr_offset[0] & mask); break; case 2: // lgdt - if(cpu.cpl) + if(cpu.cpl[0]) { cpu.trigger_gp(0); } @@ -1756,22 +1756,22 @@ t[0x01] = cpu => { cpu.read_modrm_byte(); var size = cpu.safe_read16(addr); var offset = cpu.safe_read32s(addr + 2); - cpu.gdtr_size = size; - cpu.gdtr_offset = offset; + cpu.gdtr_size[0] = size; + cpu.gdtr_offset[0] = offset; if(!cpu.is_osize_32()) { - cpu.gdtr_offset &= 0xFFFFFF; + cpu.gdtr_offset[0] &= 0xFFFFFF; } - //dbg_log("gdt at " + h(cpu.gdtr_offset) + ", " + cpu.gdtr_size + " bytes", LOG_CPU); + //dbg_log("gdt at " + h(cpu.gdtr_offset[0]) + ", " + cpu.gdtr_size[0] + " bytes", LOG_CPU); //cpu.debug.dump_state(); //cpu.debug.dump_regs_short(); //cpu.debug.dump_gdt_ldt(); break; case 3: // lidt - if(cpu.cpl) + if(cpu.cpl[0]) { cpu.trigger_gp(0); } @@ -1779,20 +1779,20 @@ t[0x01] = cpu => { cpu.read_modrm_byte(); var size = cpu.safe_read16(addr); var offset = cpu.safe_read32s(addr + 2); - cpu.idtr_size = size; - cpu.idtr_offset = offset; + cpu.idtr_size[0] = size; + cpu.idtr_offset[0] = offset; if(!cpu.is_osize_32()) { - cpu.idtr_offset &= 0xFFFFFF; + cpu.idtr_offset[0] &= 0xFFFFFF; } //dbg_log("[" + h(cpu.instruction_pointer) + "] idt at " + - // h(idtr_offset) + ", " + cpu.idtr_size + " bytes " + h(addr), LOG_CPU); + // h(idtr_offset) + ", " + cpu.idtr_size[0] + " bytes " + h(addr), LOG_CPU); break; case 7: // flush translation lookaside buffer - if(cpu.cpl) + if(cpu.cpl[0]) { cpu.trigger_gp(0); } @@ -1807,7 +1807,7 @@ t[0x01] = cpu => { cpu.read_modrm_byte(); t16[0x02] = cpu => { cpu.read_modrm_byte(); // lar - if(!cpu.protected_mode || cpu.vm86_mode()) + if(!cpu.protected_mode[0] || cpu.vm86_mode()) { dbg_log("lar #ud", LOG_CPU); cpu.trigger_ud(); @@ -1816,7 +1816,7 @@ t16[0x02] = cpu => { cpu.read_modrm_byte(); cpu.write_g16(cpu.lar(data, cpu.read_g16())); }; t32[0x02] = cpu => { cpu.read_modrm_byte(); - if(!cpu.protected_mode || cpu.vm86_mode()) + if(!cpu.protected_mode[0] || cpu.vm86_mode()) { dbg_log("lar #ud", LOG_CPU); cpu.trigger_ud(); @@ -1827,7 +1827,7 @@ t32[0x02] = cpu => { cpu.read_modrm_byte(); t16[0x03] = cpu => { cpu.read_modrm_byte(); // lsl - if(!cpu.protected_mode || cpu.vm86_mode()) + if(!cpu.protected_mode[0] || cpu.vm86_mode()) { dbg_log("lsl #ud", LOG_CPU); cpu.trigger_ud(); @@ -1836,7 +1836,7 @@ t16[0x03] = cpu => { cpu.read_modrm_byte(); cpu.write_g16(cpu.lsl(data, cpu.read_g16())); }; t32[0x03] = cpu => { cpu.read_modrm_byte(); - if(!cpu.protected_mode || cpu.vm86_mode()) + if(!cpu.protected_mode[0] || cpu.vm86_mode()) { dbg_log("lsl #ud", LOG_CPU); cpu.trigger_ud(); @@ -1850,7 +1850,7 @@ t[0x05] = cpu => { cpu.undefined_instruction(); }; t[0x06] = cpu => { // clts - if(cpu.cpl) + if(cpu.cpl[0]) { dbg_log("clts #gp", LOG_CPU); cpu.trigger_gp(0); @@ -1869,7 +1869,7 @@ t[0x08] = cpu => { }; t[0x09] = cpu => { - if(cpu.cpl) + if(cpu.cpl[0]) { dbg_log("wbinvd #gp", LOG_CPU); cpu.trigger_gp(0); @@ -1913,7 +1913,21 @@ t[0x13] = cpu => { var addr = cpu.modrm_resolve(cpu.modrm_byte); cpu.safe_write64(addr, data[0], data[1]); }; -t[0x14] = cpu => { cpu.unimplemented_sse(); }; +t[0x14] = cpu => { + // unpcklpd xmm, xmm/m128 + dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) === PREFIX_66); + cpu.task_switch_test_mmx(); + cpu.read_modrm_byte(); + let source = cpu.read_xmm_mem64s(); + let destination = cpu.read_xmm64s(); + + cpu.write_xmm128s( + destination[0], + destination[1], + source[0], + source[1] + ); +}; t[0x15] = cpu => { cpu.unimplemented_sse(); }; t[0x16] = cpu => { cpu.unimplemented_sse(); }; t[0x17] = cpu => { cpu.unimplemented_sse(); }; @@ -1921,8 +1935,8 @@ t[0x17] = cpu => { cpu.unimplemented_sse(); }; t[0x18] = cpu => { cpu.read_modrm_byte(); // prefetch // nop for us - if(cpu.modrm_byte < 0xC0) - cpu.modrm_resolve(cpu.modrm_byte); + if(cpu.modrm_byte[0] < 0xC0) + cpu.modrm_resolve(cpu.modrm_byte[0]); }; t[0x19] = cpu => { cpu.unimplemented_sse(); }; @@ -1933,22 +1947,22 @@ t[0x1D] = cpu => { cpu.unimplemented_sse(); }; t[0x1E] = cpu => { cpu.unimplemented_sse(); }; t[0x1F] = cpu => { cpu.read_modrm_byte() // multi-byte nop - if(cpu.modrm_byte < 0xC0) - cpu.modrm_resolve(cpu.modrm_byte); + if(cpu.modrm_byte[0] < 0xC0) + cpu.modrm_resolve(cpu.modrm_byte[0]); }; t[0x20] = cpu => { cpu.read_modrm_byte(); - if(cpu.cpl) + if(cpu.cpl[0]) { cpu.trigger_gp(0); } - //dbg_log("cr" + (cpu.modrm_byte >> 3 & 7) + " read", LOG_CPU); + //dbg_log("cr" + (cpu.modrm_byte[0] >> 3 & 7) + " read", LOG_CPU); // mov addr, cr // mod = which control register - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: cpu.write_reg_e32(cpu.cr[0]); @@ -1972,12 +1986,12 @@ t[0x20] = cpu => { cpu.read_modrm_byte(); }; t[0x21] = cpu => { cpu.read_modrm_byte(); - if(cpu.cpl) + if(cpu.cpl[0]) { cpu.trigger_gp(0); } - var dreg = cpu.modrm_byte >> 3 & 7; + var dreg = cpu.modrm_byte[0] >> 3 & 7; if((cpu.cr[4] & CR4_DE) && (dreg === 4 || dreg === 5)) { dbg_log("#ud mov dreg 4/5 with cr4.DE set", LOG_CPU); @@ -1985,24 +1999,24 @@ t[0x21] = cpu => { cpu.read_modrm_byte(); } // high two bits of modrm are ignored - cpu.reg32s[cpu.modrm_byte & 7] = cpu.dreg[dreg]; + cpu.reg32s[cpu.modrm_byte[0] & 7] = cpu.dreg[dreg]; //dbg_log("read dr" + dreg + ": " + h(cpu.dreg[dreg] >>> 0), LOG_CPU); }; t[0x22] = cpu => { cpu.read_modrm_byte(); - if(cpu.cpl) + if(cpu.cpl[0]) { cpu.trigger_gp(0); } var data = cpu.read_reg_e32s(); - //dbg_log("cr" + (cpu.modrm_byte >> 3 & 7) + " written: " + h(data >>> 0, 8), LOG_CPU); + //dbg_log("cr" + (cpu.modrm_byte[0] >> 3 & 7) + " written: " + h(data >>> 0, 8), LOG_CPU); // mov cr, addr // mod = which control register - switch(cpu.modrm_byte >> 3 & 7) + switch(cpu.modrm_byte[0] >> 3 & 7) { case 0: cpu.set_cr0(data); @@ -2036,12 +2050,12 @@ t[0x22] = cpu => { cpu.read_modrm_byte(); } }; t[0x23] = cpu => { cpu.read_modrm_byte(); - if(cpu.cpl) + if(cpu.cpl[0]) { cpu.trigger_gp(0); } - var dreg = cpu.modrm_byte >> 3 & 7; + var dreg = cpu.modrm_byte[0] >> 3 & 7; if((cpu.cr[4] & CR4_DE) && (dreg === 4 || dreg === 5)) { dbg_log("#ud mov dreg 4/5 with cr4.DE set", LOG_CPU); @@ -2060,10 +2074,20 @@ t[0x26] = cpu => { cpu.undefined_instruction(); }; t[0x27] = cpu => { cpu.undefined_instruction(); }; t[0x28] = cpu => { - // movaps xmm, xmm/m128 - dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) === 0); cpu.task_switch_test_mmx(); cpu.read_modrm_byte(); + + if((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) === PREFIX_66) + { + // movapd xmm, xmm/m128 + // (note: same as movaps, see google.com/?q=MOVAPD+vs+MOVAPS) + } + else + { + dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) === 0); + // movaps xmm, xmm/m128 + } + let data = cpu.read_xmm_mem128s(); cpu.write_xmm128s(data[0], data[1], data[2], data[3]); }; @@ -2073,25 +2097,60 @@ t[0x29] = cpu => { if((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) === PREFIX_66) { // movapd xmm/m128, xmm - // (note: same as below, see google.com/?q=MOVAPD+vs+MOVAPS) - let data = cpu.read_xmm128s(); - dbg_assert(cpu.modrm_byte < 0xC0); - let addr = cpu.modrm_resolve(cpu.modrm_byte); - cpu.safe_write128(addr, data[0], data[1], data[2], data[3]); + // (note: same as movaps, see google.com/?q=MOVAPD+vs+MOVAPS) } else { // movaps xmm/m128, xmm dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) === 0); - let data = cpu.read_xmm128s(); - dbg_assert(cpu.modrm_byte < 0xC0); - let addr = cpu.modrm_resolve(cpu.modrm_byte); - cpu.safe_write128(addr, data[0], data[1], data[2], data[3]); } + + let data = cpu.read_xmm128s(); + dbg_assert(cpu.modrm_byte < 0xC0); + let addr = cpu.modrm_resolve(cpu.modrm_byte); + cpu.safe_write128(addr, data[0], data[1], data[2], data[3]); }; t[0x2A] = cpu => { cpu.unimplemented_sse(); }; -t[0x2B] = cpu => { cpu.unimplemented_sse(); }; -t[0x2C] = cpu => { cpu.unimplemented_sse(); }; +t[0x2B] = cpu => { + cpu.task_switch_test_mmx(); + cpu.read_modrm_byte(); + dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0 || + (cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) === PREFIX_66); + + if(cpu.modrm_byte >= 0xC0) + { + cpu.trigger_ud(); + } + + // movntps m128, xmm + // movntpd m128, xmm + + let data = cpu.read_xmm128s(); + let addr = cpu.modrm_resolve(cpu.modrm_byte); + cpu.safe_write128(addr, data[0], data[1], data[2], data[3]); +}; +t[0x2C] = cpu => { + cpu.task_switch_test_mmx(); + cpu.read_modrm_byte(); + if((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) === PREFIX_F2) + { + // cvttsd2si r32, xmm/m64 + let source = cpu.read_xmm_mem64s(); + let source_f64 = new Float64Array(source.buffer); + let f = source_f64[0]; + + if(!(f <= 0x7FFFFFFF && f >= -0x80000000)) + { + f = 0x80000000 | 0; + } + + cpu.write_g32(f); + } + else + { + dbg_assert(false); + } +}; t[0x2D] = cpu => { cpu.unimplemented_sse(); }; t[0x2E] = cpu => { cpu.unimplemented_sse(); }; t[0x2F] = cpu => { cpu.unimplemented_sse(); }; @@ -2100,7 +2159,7 @@ t[0x2F] = cpu => { cpu.unimplemented_sse(); }; t[0x30] = cpu => { // wrmsr - write maschine specific register - if(cpu.cpl) + if(cpu.cpl[0]) { // cpl > 0 or vm86 mode (vm86 mode is always runs with cpl=3) cpu.trigger_gp(0); @@ -2119,15 +2178,15 @@ t[0x30] = cpu => { switch(index) { case IA32_SYSENTER_CS: - cpu.sysenter_cs = low & 0xFFFF; + cpu.sysenter_cs[0] = low & 0xFFFF; break; case IA32_SYSENTER_EIP: - cpu.sysenter_eip = low; + cpu.sysenter_eip[0] = low; break; case IA32_SYSENTER_ESP: - cpu.sysenter_esp = low; + cpu.sysenter_esp[0] = low; break; case IA32_APIC_BASE_MSR: @@ -2140,7 +2199,7 @@ t[0x30] = cpu => { case IA32_TIME_STAMP_COUNTER: var new_tick = (low >>> 0) + 0x100000000 * (high >>> 0); - cpu.tsc_offset = v86.microtick() - new_tick / TSC_RATE; + cpu.tsc_offset[0] = v86.microtick() - new_tick / TSC_RATE; break; case IA32_BIOS_SIGN_ID: @@ -2167,9 +2226,9 @@ t[0x30] = cpu => { t[0x31] = cpu => { // rdtsc - read timestamp counter - if(!cpu.cpl || !(cpu.cr[4] & CR4_TSD)) + if(!cpu.cpl[0] || !(cpu.cr[4] & CR4_TSD)) { - var n = v86.microtick() - cpu.tsc_offset; + var n = v86.microtick() - cpu.tsc_offset[0]; dbg_assert(isFinite(n), "non-finite tsc: " + n); cpu.reg32s[reg_eax] = n * TSC_RATE; @@ -2185,7 +2244,7 @@ t[0x31] = cpu => { t[0x32] = cpu => { // rdmsr - read maschine specific register - if(cpu.cpl) + if(cpu.cpl[0]) { cpu.trigger_gp(0); } @@ -2200,19 +2259,19 @@ t[0x32] = cpu => { switch(index) { case IA32_SYSENTER_CS: - low = cpu.sysenter_cs; + low = cpu.sysenter_cs[0]; break; case IA32_SYSENTER_EIP: - low = cpu.sysenter_eip; + low = cpu.sysenter_eip[0]; break; case IA32_SYSENTER_ESP: - low = cpu.sysenter_esp; + low = cpu.sysenter_esp[0]; break; case IA32_TIME_STAMP_COUNTER: - var n = v86.microtick() - cpu.tsc_offset; + var n = v86.microtick() - cpu.tsc_offset[0]; low = n * TSC_RATE; high = n * (TSC_RATE / 0x100000000); break; @@ -2271,20 +2330,23 @@ t[0x33] = cpu => { t[0x34] = cpu => { // sysenter - var seg = cpu.sysenter_cs & 0xFFFC; + var seg = cpu.sysenter_cs[0] & 0xFFFC; - if(!cpu.protected_mode || seg === 0) + if(!cpu.protected_mode[0] || seg === 0) { cpu.trigger_gp(0); } - //dbg_log("sysenter cs:eip=" + h(seg , 4) + ":" + h(cpu.sysenter_eip >>> 0, 8) + - // " ss:esp=" + h(seg + 8, 4) + ":" + h(cpu.sysenter_esp >>> 0, 8), LOG_CPU); + if(CPU_LOG_VERBOSE) + { + dbg_log("sysenter cs:eip=" + h(seg , 4) + ":" + h(cpu.sysenter_eip[0] >>> 0, 8) + + " ss:esp=" + h(seg + 8, 4) + ":" + h(cpu.sysenter_esp[0] >>> 0, 8), LOG_CPU); + } - cpu.flags &= ~flag_vm & ~flag_interrupt; + cpu.flags[0] &= ~flag_vm & ~flag_interrupt; - cpu.instruction_pointer = cpu.sysenter_eip; - cpu.reg32s[reg_esp] = cpu.sysenter_esp; + cpu.instruction_pointer[0] = cpu.sysenter_eip[0]; + cpu.reg32s[reg_esp] = cpu.sysenter_esp[0]; cpu.sreg[reg_cs] = seg; cpu.segment_is_null[reg_cs] = 0; @@ -2293,7 +2355,7 @@ t[0x34] = cpu => { cpu.update_cs_size(true); - cpu.cpl = 0; + cpu.cpl[0] = 0; cpu.cpl_changed(); cpu.sreg[reg_ss] = seg + 8; @@ -2301,23 +2363,26 @@ t[0x34] = cpu => { cpu.segment_limits[reg_ss] = -1; cpu.segment_offsets[reg_ss] = 0; - cpu.stack_size_32 = true; + cpu.stack_size_32[0] = true; cpu.diverged(); }; t[0x35] = cpu => { // sysexit - var seg = cpu.sysenter_cs & 0xFFFC; + var seg = cpu.sysenter_cs[0] & 0xFFFC; - if(!cpu.protected_mode || cpu.cpl || seg === 0) + if(!cpu.protected_mode[0] || cpu.cpl[0] || seg === 0) { cpu.trigger_gp(0); } - //dbg_log("sysexit cs:eip=" + h(seg + 16, 4) + ":" + h(cpu.reg32s[reg_edx] >>> 0, 8) + - // " ss:esp=" + h(seg + 24, 4) + ":" + h(cpu.reg32s[reg_ecx] >>> 0, 8), LOG_CPU); + if(CPU_LOG_VERBOSE) + { + dbg_log("sysexit cs:eip=" + h(seg + 16, 4) + ":" + h(cpu.reg32s[reg_edx] >>> 0, 8) + + " ss:esp=" + h(seg + 24, 4) + ":" + h(cpu.reg32s[reg_ecx] >>> 0, 8), LOG_CPU); + } - cpu.instruction_pointer = cpu.reg32s[reg_edx]; + cpu.instruction_pointer[0] = cpu.reg32s[reg_edx]; cpu.reg32s[reg_esp] = cpu.reg32s[reg_ecx]; cpu.sreg[reg_cs] = seg + 16 | 3; @@ -2328,7 +2393,7 @@ t[0x35] = cpu => { cpu.update_cs_size(true); - cpu.cpl = 3; + cpu.cpl[0] = 3; cpu.cpl_changed(); cpu.sreg[reg_ss] = seg + 24 | 3; @@ -2336,7 +2401,7 @@ t[0x35] = cpu => { cpu.segment_limits[reg_ss] = -1; cpu.segment_offsets[reg_ss] = 0; - cpu.stack_size_32 = true; + cpu.stack_size_32[0] = true; cpu.diverged(); }; @@ -2396,7 +2461,23 @@ t[0x50] = cpu => { cpu.unimplemented_sse(); }; t[0x51] = cpu => { cpu.unimplemented_sse(); }; t[0x52] = cpu => { cpu.unimplemented_sse(); }; t[0x53] = cpu => { cpu.unimplemented_sse(); }; -t[0x54] = cpu => { cpu.unimplemented_sse(); }; +t[0x54] = cpu => { + // andps xmm, xmm/mem128 + // andpd xmm, xmm/mem128 + // Note: Same code as pand + cpu.task_switch_test_mmx(); + cpu.read_modrm_byte(); + + let source = cpu.read_xmm_mem128s(); + let destination = cpu.read_xmm128s(); + + cpu.write_xmm128s( + source[0] & destination[0], + source[1] & destination[1], + source[2] & destination[2], + source[3] & destination[3] + ); +}; t[0x55] = cpu => { cpu.unimplemented_sse(); }; t[0x56] = cpu => { cpu.unimplemented_sse(); }; t[0x57] = cpu => { @@ -3053,7 +3134,6 @@ t[0x72] = cpu => { t[0x73] = cpu => { cpu.read_modrm_byte(); - dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0); cpu.task_switch_test_mmx(); if(cpu.modrm_byte < 0xC0) @@ -3066,32 +3146,65 @@ t[0x73] = cpu => { switch(cpu.modrm_byte >> 3 & 7) { case 2: - // psrlq mm, imm8 - var source = cpu.read_op8(); - var destination = cpu.modrm_byte & 7; + if((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == PREFIX_66) + { + // psrlq xmm, imm8 + var shift = cpu.read_op8(); - var destination_low = cpu.reg_mmxs[2 * destination]; - var destination_high = cpu.reg_mmxs[2 * destination + 1]; + if(shift === 0) + { + return; + } - var shift = source; - var low = 0; - var high = 0; + let destination = cpu.read_xmm128s(); + let result = cpu.create_atom128s(0, 0, 0, 0); - if (shift <= 31) { - low = destination_low >>> shift | (destination_high << (32 - shift)); - high = destination_high >>> shift; + if (shift <= 31) + { + result[0] = destination[0] >>> shift | destination[1] << (32 - shift); + result[1] = destination[1] >>> shift; + + result[2] = destination[2] >>> shift | destination[3] << (32 - shift); + result[3] = destination[3] >>> shift; + } + else if (shift <= 63) + { + result[0] = destination[1] >>> shift; + result[2] = destination[3] >>> shift; + } + + cpu.write_xmm128s(result[0], result[1], result[2], result[3]); } - else if (shift <= 63) { - low = destination_high >>> (shift & 0x1F); - high = 0; + else + { + // psrlq mm, imm8 + dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0); + var source = cpu.read_op8(); + var destination = cpu.modrm_byte & 7; + + var destination_low = cpu.reg_mmxs[2 * destination]; + var destination_high = cpu.reg_mmxs[2 * destination + 1]; + + var shift = source; + var low = 0; + var high = 0; + + if (shift <= 31) { + low = destination_low >>> shift | (destination_high << (32 - shift)); + high = destination_high >>> shift; + } + else if (shift <= 63) { + low = destination_high >>> (shift & 0x1F); + high = 0; + } + + cpu.reg_mmxs[2 * destination] = low; + cpu.reg_mmxs[2 * destination + 1] = high; } - - cpu.reg_mmxs[2 * destination] = low; - cpu.reg_mmxs[2 * destination + 1] = high; - break; case 6: // psllq mm, imm8 + dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0); var source = cpu.read_op8(); var destination = cpu.modrm_byte & 7; @@ -3115,6 +3228,7 @@ t[0x73] = cpu => { cpu.reg_mmxs[2 * destination + 1] = high; break; + default: cpu.unimplemented_sse(); break; @@ -3171,24 +3285,47 @@ t[0x74] = cpu => { }; t[0x75] = cpu => { - // pcmpeqw mm, mm/m64 - dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0); cpu.task_switch_test_mmx(); cpu.read_modrm_byte(); - let source = cpu.read_mmx_mem64s(); - let destination_low = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7)]; - let destination_high = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7) + 1]; + if((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == PREFIX_66) + { + // pcmpeqw xmm, xmm/m128 + let source64s = cpu.read_xmm_mem128s(); + let source16 = new Uint16Array(source64s.buffer); - let word0 = (destination_low & 0xFFFF) === (source[0] & 0xFFFF) ? 0xFFFF : 0; - let word1 = (destination_low & 0xFFFF0000) === (source[0] & 0xFFFF0000) ? 0xFFFF : 0; - let word2 = (destination_high & 0xFFFF) === (source[1] & 0xFFFF) ? 0xFFFF : 0; - let word3 = (destination_high & 0xFFFF0000) === (source[1] & 0xFFFF0000) ? 0xFFFF : 0; + let destination128 = cpu.read_xmm128s(); + let destination16 = new Uint16Array(destination128.buffer); - let low = word0 | word1 << 16; - let high = word2 | word3 << 16; + let result = cpu.create_atom128s(0, 0, 0, 0); + let result16 = new Uint16Array(result.buffer); - cpu.write_mmx64s(low, high); + for(let i = 0; i < 8; i++) + { + result16[i] = source16[i] === destination16[i] ? 0xFFFF : 0; + } + + cpu.write_xmm128s(result[0], result[1], result[2], result[3]) + } + else + { + // pcmpeqw mm, mm/m64 + dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0); + + let source = cpu.read_mmx_mem64s(); + let destination_low = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7)]; + let destination_high = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7) + 1]; + + let word0 = (destination_low & 0xFFFF) === (source[0] & 0xFFFF) ? 0xFFFF : 0; + let word1 = (destination_low & 0xFFFF0000) === (source[0] & 0xFFFF0000) ? 0xFFFF : 0; + let word2 = (destination_high & 0xFFFF) === (source[1] & 0xFFFF) ? 0xFFFF : 0; + let word3 = (destination_high & 0xFFFF0000) === (source[1] & 0xFFFF0000) ? 0xFFFF : 0; + + let low = word0 | word1 << 16; + let high = word2 | word3 << 16; + + cpu.write_mmx64s(low, high); + } }; t[0x76] = cpu => { @@ -3228,7 +3365,7 @@ t[0x77] = cpu => { // emms dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0); cpu.task_switch_test_mmx(); - cpu.fpu.stack_empty = 0xFF; + cpu.fpu.stack_empty[0] = 0xFF; }; t[0x78] = cpu => { cpu.unimplemented_sse(); }; @@ -3835,7 +3972,21 @@ t[0xC3] = cpu => { cpu.set_e32(cpu.read_g32s()); }; t[0xC4] = cpu => { cpu.unimplemented_sse(); }; -t[0xC5] = cpu => { cpu.unimplemented_sse(); }; +t[0xC5] = cpu => { + dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) === PREFIX_66); + // pextrw r32/m16, xmm, imm8 + cpu.task_switch_test_mmx(); + cpu.read_modrm_byte(); + + if(cpu.modrm_byte < 0xC0) cpu.trigger_ud(); + + let data = cpu.read_xmm_mem128s(); + let data16 = new Uint16Array(data.buffer); + let index = cpu.read_imm8() & 7; + let result = data16[index]; + + cpu.write_g32(result); +}; t[0xC6] = cpu => { cpu.unimplemented_sse(); }; t[0xC7] = cpu => { @@ -3859,14 +4010,14 @@ t[0xC7] = cpu => { if(cpu.reg32s[reg_eax] === m64_low && cpu.reg32s[reg_edx] === m64_high) { - cpu.flags |= flag_zero; + cpu.flags[0] |= flag_zero; cpu.safe_write32(addr, cpu.reg32s[reg_ebx]); cpu.safe_write32(addr + 4 | 0, cpu.reg32s[reg_ecx]); } else { - cpu.flags &= ~flag_zero; + cpu.flags[0] &= ~flag_zero; cpu.reg32s[reg_eax] = m64_low; cpu.reg32s[reg_edx] = m64_high; @@ -3875,7 +4026,7 @@ t[0xC7] = cpu => { cpu.safe_write32(addr + 4 | 0, m64_high); } - cpu.flags_changed &= ~flag_zero; + cpu.flags_changed[0] &= ~flag_zero; break; case 6: @@ -3900,9 +4051,9 @@ t[0xC7] = cpu => { cpu.set_e16(rand); } - cpu.flags &= ~flags_all; - cpu.flags |= has_rand; - cpu.flags_changed = 0; + cpu.flags[0] &= ~flags_all; + cpu.flags[0] |= has_rand; + cpu.flags_changed[0] = 0; break; default: @@ -3972,35 +4123,69 @@ t[0xD2] = cpu => { }; t[0xD3] = cpu => { - // psrlq mm, mm/m64 - dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0); cpu.task_switch_test_mmx(); cpu.read_modrm_byte(); - let source = cpu.read_mmx_mem64s(); - let destination_low = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7)]; - let destination_high = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7) + 1]; - - let shift = source[0] >>> 0; - - if(shift === 0) + if((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) === PREFIX_66) { - return; - } + // psrlq xmm, mm/m64 + let source = cpu.read_xmm_mem64s(); + var shift = source[0] >>> 0; - let low = 0; - let high = 0; + if(shift === 0) + { + return; + } - if (shift <= 31) { - low = destination_low >>> shift | (destination_high << (32 - shift)); - high = destination_high >>> shift; - } - else if (shift <= 63) { - low = destination_high >>> (shift & 0x1F); - high = 0; - } + let destination = cpu.read_xmm128s(); + let result = cpu.create_atom128s(0, 0, 0, 0); - cpu.write_mmx64s(low, high); + if (shift <= 31) + { + result[0] = destination[0] >>> shift | destination[1] << (32 - shift); + result[1] = destination[1] >>> shift; + + result[2] = destination[2] >>> shift | destination[3] << (32 - shift); + result[3] = destination[3] >>> shift; + } + else if (shift <= 63) + { + result[0] = destination[1] >>> shift; + result[2] = destination[3] >>> shift; + } + + cpu.write_xmm128s(result[0], result[1], result[2], result[3]); + } + else + { + // psrlq mm, mm/m64 + dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0); + + let source = cpu.read_mmx_mem64s(); + let destination_low = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7)]; + let destination_high = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7) + 1]; + + let shift = source[0] >>> 0; + + if(shift === 0) + { + return; + } + + let low = 0; + let high = 0; + + if (shift <= 31) { + low = destination_low >>> shift | (destination_high << (32 - shift)); + high = destination_high >>> shift; + } + else if (shift <= 63) { + low = destination_high >>> (shift & 0x1F); + high = 0; + } + + cpu.write_mmx64s(low, high); + } }; t[0xD4] = cpu => { cpu.unimplemented_sse(); }; @@ -4740,19 +4925,36 @@ t[0xF9] = cpu => { }; t[0xFA] = cpu => { - // psubd mm, mm/m64 - dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0); cpu.task_switch_test_mmx(); cpu.read_modrm_byte(); - let source = cpu.read_mmx_mem64s(); - let destination_low = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7)]; - let destination_high = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7) + 1]; + if((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == PREFIX_66) + { + // psubd xmm, xmm/m128 + let source = cpu.read_xmm_mem128s(); + let destination = cpu.read_xmm128s(); - let low = destination_low - source[0]; - let high = destination_high - source[1]; + cpu.write_xmm128s( + destination[0] - source[0], + destination[1] - source[1], + destination[2] - source[2], + destination[3] - source[3] + ); + } + else + { + // psubd mm, mm/m64 + dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0); - cpu.write_mmx64s(low, high); + let source = cpu.read_mmx_mem64s(); + let destination_low = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7)]; + let destination_high = cpu.reg_mmxs[2 * (cpu.modrm_byte >> 3 & 7) + 1]; + + cpu.write_mmx64s( + destination_low - source[0], + destination_high - source[1] + ); + } }; t[0xFB] = cpu => { cpu.unimplemented_sse(); }; diff --git a/src/io.js b/src/io.js index 5d2d1ccb..b8a93451 100644 --- a/src/io.js +++ b/src/io.js @@ -20,7 +20,7 @@ function IO(cpu) this.ports[i] = this.create_empty_entry(); } - var memory_size = cpu.memory_size; + var memory_size = cpu.memory_size[0]; for(var i = 0; (i << MMAP_BLOCK_BITS) < memory_size; i++) { @@ -253,7 +253,7 @@ IO.prototype.in_mmap_range = function(start, count) var end = start + count; - if(end >= this.cpu.memory_size) + if(end >= this.cpu.memory_size[0]) { return true; } diff --git a/src/ioapic.js b/src/ioapic.js index 811cbea6..77a1fcc3 100644 --- a/src/ioapic.js +++ b/src/ioapic.js @@ -120,7 +120,7 @@ function IOAPIC(cpu) dbg_assert(false); } }); -} +}; IOAPIC.prototype.remote_eoi = function(vector) { diff --git a/src/log.js b/src/log.js index 1e740950..881b095f 100644 --- a/src/log.js +++ b/src/log.js @@ -87,6 +87,27 @@ var dbg_log = (function() return dbg_log_; })(); +function dbg_log_wasm(memory, offset, args) +{ + if(!(LOG_LEVEL & LOG_CPU)) + { + return; + } + + let s = new Uint8Array(memory, offset); + let length = s.indexOf(0); + if(length !== -1) + { + s = new Uint8Array(memory, offset, length); + } + + let format_string = "[CPU ] " + String.fromCharCode.apply(String, s); + let format_args = [format_string]; + format_args.push.apply(format_args, args); + + console.log.apply(console, format_args); +} + /** * @param {number=} level */ diff --git a/src/main.js b/src/main.js index 46e6cf3a..fd163347 100644 --- a/src/main.js +++ b/src/main.js @@ -1,7 +1,10 @@ "use strict"; -/** @constructor */ -function v86(bus) +/** + * @constructor + * @param {Object=} wm + */ +function v86(bus, wm) { /** @type {boolean} */ this.running = false; @@ -10,7 +13,7 @@ function v86(bus) this.stopped = false; /** @type {CPU} */ - this.cpu = new CPU(bus); + this.cpu = new CPU(bus, wm); this.bus = bus; bus.register("cpu-init", this.init, this); diff --git a/src/memory.js b/src/memory.js index 9db53240..3f4ca06d 100644 --- a/src/memory.js +++ b/src/memory.js @@ -81,7 +81,7 @@ CPU.prototype.mmap_write32 = function(addr, value) CPU.prototype.in_mapped_range = function(addr) { - return (addr | 0) >= 0xA0000 && (addr | 0) < 0xC0000 || (addr >>> 0) >= (this.memory_size >>> 0); + return (addr | 0) >= 0xA0000 && (addr | 0) < 0xC0000 || (addr >>> 0) >= (this.memory_size[0] >>> 0); }; /** @@ -90,7 +90,7 @@ CPU.prototype.in_mapped_range = function(addr) CPU.prototype.read8 = function(addr) { this.debug_read(addr, 1); - if(USE_A20 && !this.a20_enabled) addr &= A20_MASK; + if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK; if(this.in_mapped_range(addr)) { @@ -108,7 +108,7 @@ CPU.prototype.read8 = function(addr) CPU.prototype.read16 = function(addr) { this.debug_read(addr, 2); - if(USE_A20 && !this.a20_enabled) addr &= A20_MASK; + if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK; if(this.in_mapped_range(addr)) { @@ -127,7 +127,7 @@ CPU.prototype.read_aligned16 = function(addr) { dbg_assert(addr >= 0 && addr < 0x80000000); this.debug_read(addr << 1, 2); - if(USE_A20 && !this.a20_enabled) addr &= A20_MASK16; + if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK16; if(this.in_mapped_range(addr << 1)) { @@ -145,7 +145,7 @@ CPU.prototype.read_aligned16 = function(addr) CPU.prototype.read32s = function(addr) { this.debug_read(addr, 4); - if(USE_A20 && !this.a20_enabled) addr &= A20_MASK; + if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK; if(this.in_mapped_range(addr)) { @@ -165,7 +165,7 @@ CPU.prototype.read_aligned32 = function(addr) { dbg_assert(addr >= 0 && addr < 0x40000000); this.debug_read(addr << 2, 4); - if(USE_A20 && !this.a20_enabled) addr &= A20_MASK32; + if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK32; if(this.in_mapped_range(addr << 2)) { @@ -184,7 +184,7 @@ CPU.prototype.read_aligned32 = function(addr) CPU.prototype.write8 = function(addr, value) { this.debug_write(addr, 1, value); - if(USE_A20 && !this.a20_enabled) addr &= A20_MASK; + if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK; if(this.in_mapped_range(addr)) { @@ -203,7 +203,7 @@ CPU.prototype.write8 = function(addr, value) CPU.prototype.write16 = function(addr, value) { this.debug_write(addr, 2, value); - if(USE_A20 && !this.a20_enabled) addr &= A20_MASK; + if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK; if(this.in_mapped_range(addr)) { @@ -224,7 +224,7 @@ CPU.prototype.write_aligned16 = function(addr, value) { dbg_assert(addr >= 0 && addr < 0x80000000); this.debug_write(addr << 1, 2, value); - if(USE_A20 && !this.a20_enabled) addr &= A20_MASK16; + if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK16; if(this.in_mapped_range(addr << 1)) { @@ -243,7 +243,7 @@ CPU.prototype.write_aligned16 = function(addr, value) CPU.prototype.write32 = function(addr, value) { this.debug_write(addr, 4, value); - if(USE_A20 && !this.a20_enabled) addr &= A20_MASK; + if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK; if(this.in_mapped_range(addr)) { @@ -262,7 +262,7 @@ CPU.prototype.write_aligned32 = function(addr, value) { dbg_assert(addr >= 0 && addr < 0x40000000); this.debug_write(addr << 2, 4, value); - if(USE_A20 && !this.a20_enabled) addr &= A20_MASK32; + if(USE_A20 && !this.a20_enabled[0]) addr &= A20_MASK32; if(this.in_mapped_range(addr << 2)) { diff --git a/src/misc_instr.js b/src/misc_instr.js index 37003121..48f83226 100644 --- a/src/misc_instr.js +++ b/src/misc_instr.js @@ -20,7 +20,7 @@ CPU.prototype.jmpcc8 = function(condition) var imm8 = this.read_op8s(); if(condition) { - this.instruction_pointer = this.instruction_pointer + imm8 | 0; + this.instruction_pointer[0] = this.instruction_pointer[0] + imm8 | 0; this.branch_taken(); } else @@ -35,9 +35,9 @@ CPU.prototype.jmp_rel16 = function(rel16) // limit ip to 16 bit // ugly - this.instruction_pointer -= current_cs; - this.instruction_pointer = (this.instruction_pointer + rel16) & 0xFFFF; - this.instruction_pointer = this.instruction_pointer + current_cs | 0; + this.instruction_pointer[0] -= current_cs; + this.instruction_pointer[0] = (this.instruction_pointer[0] + rel16) & 0xFFFF; + this.instruction_pointer[0] = this.instruction_pointer[0] + current_cs | 0; }; CPU.prototype.jmpcc16 = function(condition) @@ -54,7 +54,6 @@ CPU.prototype.jmpcc16 = function(condition) } } - CPU.prototype.jmpcc32 = function(condition) { var imm32s = this.read_op32s(); @@ -63,7 +62,7 @@ CPU.prototype.jmpcc32 = function(condition) // don't change to `this.instruction_pointer += this.read_op32s()`, // since read_op32s modifies instruction_pointer - this.instruction_pointer = this.instruction_pointer + imm32s | 0; + this.instruction_pointer[0] = this.instruction_pointer[0] + imm32s | 0; this.branch_taken(); } else @@ -99,7 +98,7 @@ CPU.prototype.loopne = function(imm8s) { if(this.decr_ecx_asize() && !this.getzf()) { - this.instruction_pointer = this.instruction_pointer + imm8s | 0; + this.instruction_pointer[0] = this.instruction_pointer[0] + imm8s | 0; this.branch_taken(); } else @@ -112,7 +111,7 @@ CPU.prototype.loope = function(imm8s) { if(this.decr_ecx_asize() && this.getzf()) { - this.instruction_pointer = this.instruction_pointer + imm8s | 0; + this.instruction_pointer[0] = this.instruction_pointer[0] + imm8s | 0; this.branch_taken(); } else @@ -125,7 +124,7 @@ CPU.prototype.loop = function(imm8s) { if(this.decr_ecx_asize()) { - this.instruction_pointer = this.instruction_pointer + imm8s | 0; + this.instruction_pointer[0] = this.instruction_pointer[0] + imm8s | 0; this.branch_taken(); } else @@ -138,7 +137,7 @@ CPU.prototype.jcxz = function(imm8s) { if(this.get_reg_asize(reg_ecx) === 0) { - this.instruction_pointer = this.instruction_pointer + imm8s | 0; + this.instruction_pointer[0] = this.instruction_pointer[0] + imm8s | 0; this.branch_taken(); } else @@ -149,83 +148,82 @@ CPU.prototype.jcxz = function(imm8s) /** * @return {number} - * @const */ CPU.prototype.getcf = function() { - if(this.flags_changed & 1) + if(this.flags_changed[0] & 1) { - return (this.last_op1 ^ (this.last_op1 ^ this.last_op2) & (this.last_op2 ^ this.last_add_result)) >>> this.last_op_size & 1; + return (this.last_op1[0] ^ (this.last_op1[0] ^ this.last_op2[0]) & (this.last_op2[0] ^ this.last_add_result[0])) >>> this.last_op_size[0] & 1; } else { - return this.flags & 1; + return this.flags[0] & 1; } }; /** @return {number} */ CPU.prototype.getpf = function() { - if(this.flags_changed & flag_parity) + if(this.flags_changed[0] & flag_parity) { // inverted lookup table - return 0x9669 << 2 >> ((this.last_result ^ this.last_result >> 4) & 0xF) & flag_parity; + return 0x9669 << 2 >> ((this.last_result[0] ^ this.last_result[0] >> 4) & 0xF) & flag_parity; } else { - return this.flags & flag_parity; + return this.flags[0] & flag_parity; } }; /** @return {number} */ CPU.prototype.getaf = function() { - if(this.flags_changed & flag_adjust) + if(this.flags_changed[0] & flag_adjust) { - return (this.last_op1 ^ this.last_op2 ^ this.last_add_result) & flag_adjust; + return (this.last_op1[0] ^ this.last_op2[0] ^ this.last_add_result[0]) & flag_adjust; } else { - return this.flags & flag_adjust; + return this.flags[0] & flag_adjust; } }; /** @return {number} */ CPU.prototype.getzf = function() { - if(this.flags_changed & flag_zero) + if(this.flags_changed[0] & flag_zero) { - return (~this.last_result & this.last_result - 1) >>> this.last_op_size & 1; + return (~this.last_result[0] & this.last_result[0] - 1) >>> this.last_op_size[0] & 1; } else { - return this.flags & flag_zero; + return this.flags[0] & flag_zero; } }; /** @return {number} */ CPU.prototype.getsf = function() { - if(this.flags_changed & flag_sign) + if(this.flags_changed[0] & flag_sign) { - return this.last_result >>> this.last_op_size & 1; + return this.last_result[0] >>> this.last_op_size[0] & 1; } else { - return this.flags & flag_sign; + return this.flags[0] & flag_sign; } }; /** @return {number} */ CPU.prototype.getof = function() { - if(this.flags_changed & flag_overflow) + if(this.flags_changed[0] & flag_overflow) { - return ((this.last_op1 ^ this.last_add_result) & (this.last_op2 ^ this.last_add_result)) >>> this.last_op_size & 1; + return ((this.last_op1[0] ^ this.last_add_result[0]) & (this.last_op2[0] ^ this.last_add_result[0])) >>> this.last_op_size[0] & 1; } else { - return this.flags & flag_overflow; + return this.flags[0] & flag_overflow; } }; @@ -402,44 +400,44 @@ CPU.prototype.xchg32r = function(operand) CPU.prototype.lss16 = function(seg) { - if(this.modrm_byte >= 0xC0) + if(this.modrm_byte[0] >= 0xC0) { // 0xc4c4 #ud (EMULATOR_BOP) is used by reactos and windows to exit vm86 mode this.trigger_ud(); } - var addr = this.modrm_resolve(this.modrm_byte); + var addr = this.modrm_resolve(this.modrm_byte[0]); var new_reg = this.safe_read16(addr), new_seg = this.safe_read16(addr + 2 | 0); this.switch_seg(seg, new_seg); - this.reg16[this.modrm_byte >> 2 & 14] = new_reg; + this.reg16[this.modrm_byte[0] >> 2 & 14] = new_reg; } CPU.prototype.lss32 = function(seg) { - if(this.modrm_byte >= 0xC0) + if(this.modrm_byte[0] >= 0xC0) { this.trigger_ud(); } - var addr = this.modrm_resolve(this.modrm_byte); + var addr = this.modrm_resolve(this.modrm_byte[0]); var new_reg = this.safe_read32s(addr), new_seg = this.safe_read16(addr + 4 | 0); this.switch_seg(seg, new_seg); - this.reg32s[this.modrm_byte >> 3 & 7] = new_reg; + this.reg32s[this.modrm_byte[0] >> 3 & 7] = new_reg; } CPU.prototype.enter16 = function(size, nesting_level) { nesting_level &= 31; - if(nesting_level) dbg_log("enter16 stack=" + (this.stack_size_32 ? 32 : 16) + " size=" + size + " nest=" + nesting_level, LOG_CPU); + if(nesting_level) dbg_log("enter16 stack=" + (this.stack_size_32[0] ? 32 : 16) + " size=" + size + " nest=" + nesting_level, LOG_CPU); this.push16(this.reg16[reg_bp]); var frame_temp = this.reg16[reg_sp]; @@ -461,7 +459,7 @@ CPU.prototype.enter32 = function(size, nesting_level) { nesting_level &= 31; - if(nesting_level) dbg_log("enter32 stack=" + (this.stack_size_32 ? 32 : 16) + " size=" + size + " nest=" + nesting_level, LOG_CPU); + if(nesting_level) dbg_log("enter32 stack=" + (this.stack_size_32[0] ? 32 : 16) + " size=" + size + " nest=" + nesting_level, LOG_CPU); this.push32(this.reg32s[reg_ebp]); var frame_temp = this.reg32s[reg_esp]; @@ -492,7 +490,7 @@ CPU.prototype.fxsave = function(addr) this.safe_write16(addr + 0 | 0, this.fpu.control_word); this.safe_write16(addr + 2 | 0, this.fpu.load_status_word()); - this.safe_write8( addr + 4 | 0, ~this.fpu.stack_empty & 0xFF); + this.safe_write8( addr + 4 | 0, ~this.fpu.stack_empty[0] & 0xFF); this.safe_write16(addr + 6 | 0, this.fpu.fpu_opcode); this.safe_write32(addr + 8 | 0, this.fpu.fpu_ip); this.safe_write16(addr + 12 | 0, this.fpu.fpu_ip_selector); @@ -534,7 +532,7 @@ CPU.prototype.fxrstor = function(addr) this.fpu.control_word = this.safe_read16(addr + 0 | 0); this.fpu.set_status_word(this.safe_read16(addr + 2 | 0)); - this.fpu.stack_empty = ~this.safe_read8(addr + 4 | 0) & 0xFF; + this.fpu.stack_empty[0] = ~this.safe_read8(addr + 4 | 0) & 0xFF; this.fpu.fpu_opcode = this.safe_read16(addr + 6 | 0); this.fpu.fpu_ip = this.safe_read32s(addr + 8 | 0); this.fpu.fpu_ip = this.safe_read16(addr + 12 | 0); diff --git a/src/native/all.c b/src/native/all.c new file mode 100644 index 00000000..b208ed84 --- /dev/null +++ b/src/native/all.c @@ -0,0 +1,19 @@ +#include +#include +#include +#include + +extern void call_interrupt_vector(int32_t interrupt_nr, bool is_software_int, bool has_error_code, int32_t error_code); +extern void throw_cpu_exception(void); + +#include "const.h" +#include "global_pointers.h" +#include "log.c" +#include "cpu.c" +#include "memory.c" +#include "modrm.c" +#include "misc_instr.c" +#include "arith.c" +#include "fpu.c" +#include "instructions.c" +#include "instructions_0f.c" diff --git a/src/native/arith.c b/src/native/arith.c new file mode 100644 index 00000000..e9cc853f --- /dev/null +++ b/src/native/arith.c @@ -0,0 +1,825 @@ +#include +#include +#include +#include + +#include + +#include "const.h" +#include "global_pointers.h" + +int32_t add(int32_t dest_operand, int32_t source_operand, int32_t op_size) +{ + *last_op1 = dest_operand; + *last_op2 = source_operand; + int32_t res = dest_operand + source_operand; + *last_add_result = *last_result = res; + + *last_op_size = op_size; + *flags_changed = FLAGS_ALL; + + return res; +} + +int32_t adc(int32_t dest_operand, int32_t source_operand, int32_t op_size) +{ + int32_t cf = getcf(); + *last_op1 = dest_operand; + *last_op2 = source_operand; + + int32_t res = dest_operand + source_operand + cf; + + *last_add_result = *last_result = res; + + *last_op_size = op_size; + *flags_changed = FLAGS_ALL; + + return res; +} + +int32_t sub(int32_t dest_operand, int32_t source_operand, int32_t op_size) +{ + *last_add_result = dest_operand; + *last_op2 = source_operand; + + int32_t res = dest_operand - source_operand; + + *last_op1 = *last_result = res; + + *last_op_size = op_size; + *flags_changed = FLAGS_ALL; + + return res; +} + +int32_t sbb(int32_t dest_operand, int32_t source_operand, int32_t op_size) +{ + int32_t cf = getcf(); + *last_add_result = dest_operand; + *last_op2 = source_operand; + + int32_t res = dest_operand - source_operand - cf; + + *last_op1 = *last_result = res; + + *last_op_size = op_size; + *flags_changed = FLAGS_ALL; + + return res; +} + +int32_t add8(int32_t x, int32_t y) { return add(x, y, OPSIZE_8); } +int32_t add16(int32_t x, int32_t y) { return add(x, y, OPSIZE_16); } +int32_t add32(int32_t x, int32_t y) { return add(x, y, OPSIZE_32); } + +int32_t sub8(int32_t x, int32_t y) { return sub(x, y, OPSIZE_8); } +int32_t sub16(int32_t x, int32_t y) { return sub(x, y, OPSIZE_16); } +int32_t sub32(int32_t x, int32_t y) { return sub(x, y, OPSIZE_32); } + +int32_t adc8(int32_t x, int32_t y) { return adc(x, y, OPSIZE_8); } +int32_t adc16(int32_t x, int32_t y) { return adc(x, y, OPSIZE_16); } +int32_t adc32(int32_t x, int32_t y) { return adc(x, y, OPSIZE_32); } + +int32_t sbb8(int32_t x, int32_t y) { return sbb(x, y, OPSIZE_8); } +int32_t sbb16(int32_t x, int32_t y) { return sbb(x, y, OPSIZE_16); } +int32_t sbb32(int32_t x, int32_t y) { return sbb(x, y, OPSIZE_32); } + +void cmp8(int32_t x, int32_t y) { sub(x, y, OPSIZE_8); } +void cmp16(int32_t x, int32_t y) { sub(x, y, OPSIZE_16); } +void cmp32(int32_t x, int32_t y) { sub(x, y, OPSIZE_32); } + +int32_t inc(int32_t dest_operand, int32_t op_size) +{ + *flags = (*flags & ~1) | getcf(); + *last_op1 = dest_operand; + *last_op2 = 1; + + int32_t res = dest_operand + 1; + + *last_add_result = *last_result = res; + *last_op_size = op_size; + *flags_changed = FLAGS_ALL & ~1; + + return res; +} + +int32_t dec(int32_t dest_operand, int32_t op_size) +{ + *flags = (*flags & ~1) | getcf(); + *last_add_result = dest_operand; + *last_op2 = 1; + + int32_t res = dest_operand - 1; + + *last_op1 = *last_result = res; + *last_op_size = op_size; + *flags_changed = FLAGS_ALL & ~1; + + return res; +} + +int32_t inc8(int32_t x) { return inc(x, OPSIZE_8); } +int32_t inc16(int32_t x) { return inc(x, OPSIZE_16); } +int32_t inc32(int32_t x) { return inc(x, OPSIZE_32); } + +int32_t dec8(int32_t x) { return dec(x, OPSIZE_8); } +int32_t dec16(int32_t x) { return dec(x, OPSIZE_16); } +int32_t dec32(int32_t x) { return dec(x, OPSIZE_32); } + +int32_t neg(int32_t dest_operand, int32_t op_size) +{ + int32_t res = -dest_operand; + *last_op1 = *last_result = res; + *flags_changed = FLAGS_ALL; + *last_add_result = 0; + *last_op2 = dest_operand; + *last_op_size = op_size; + + return res; +} + +int32_t neg8(int32_t x) { return neg(x, OPSIZE_8); } +int32_t neg16(int32_t x) { return neg(x, OPSIZE_16); } +int32_t neg32(int32_t x) { return neg(x, OPSIZE_32); } + +void mul8(int32_t source_operand) +{ + int32_t result = source_operand * reg8[AL]; + + reg16[AX] = result; + *last_result = result & 0xFF; + *last_op_size = OPSIZE_8; + + if(result < 0x100) + { + *flags = *flags & ~1 & ~FLAG_OVERFLOW; + } + else + { + *flags = *flags | 1 | FLAG_OVERFLOW; + } + + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW; +} + +void imul8(int32_t source_operand) +{ + int32_t result = source_operand * reg8s[AL]; + + reg16[AX] = result; + *last_result = result & 0xFF; + *last_op_size = OPSIZE_8; + + if(result > 0x7F || result < -0x80) + { + *flags = *flags | 1 | FLAG_OVERFLOW; + } + else + { + *flags = *flags & ~1 & ~FLAG_OVERFLOW; + } + + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW; +} + +void mul16(uint32_t source_operand) +{ + uint32_t result = source_operand * reg16[AX]; + uint32_t high_result = result >> 16; + + + reg16[AX] = result; + reg16[DX] = high_result; + + *last_result = result & 0xFFFF; + *last_op_size = OPSIZE_16; + + if(high_result == 0) + { + *flags &= ~1 & ~FLAG_OVERFLOW; + } + else + { + *flags |= *flags | 1 | FLAG_OVERFLOW; + } + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW; +} + +void imul16(int32_t source_operand) +{ + int32_t result = source_operand * reg16s[AX]; + + reg16[AX] = result; + reg16[DX] = result >> 16; + + *last_result = result & 0xFFFF; + *last_op_size = OPSIZE_16; + + if(result > 0x7FFF || result < -0x8000) + { + *flags |= 1 | FLAG_OVERFLOW; + } + else + { + *flags &= ~1 & ~FLAG_OVERFLOW; + } + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW; +} + +int32_t imul_reg16(int32_t operand1, int32_t operand2) +{ + assert(operand1 < 0x8000 && operand1 >= -0x8000); + assert(operand2 < 0x8000 && operand2 >= -0x8000); + + int32_t result = operand1 * operand2; + + *last_result = result & 0xFFFF; + *last_op_size = OPSIZE_16; + + if(result > 0x7FFF || result < -0x8000) + { + *flags |= 1 | FLAG_OVERFLOW; + } + else + { + *flags &= ~1 & ~FLAG_OVERFLOW; + } + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW; + + return result; +} + +void do_mul32(uint32_t a, uint32_t b) +{ + uint32_t a00 = a & 0xFFFF; + uint32_t a16 = a >> 16; + uint32_t b00 = b & 0xFFFF; + int32_t b16 = b >> 16; + uint32_t low_result = a00 * b00; + uint32_t mid = (low_result >> 16) + (a16 * b00); + uint32_t high_result = mid >> 16; + mid = (mid & 0xFFFF) + (a00 * b16); + mul32_result[0] = (mid << 16) | low_result & 0xFFFF; + mul32_result[1] = ((mid >> 16) + (a16 * b16)) + high_result; +} + +void do_imul32(int32_t a, int32_t b) +{ + bool is_neg = false; + if(a < 0) { + is_neg = true; + a = -a; + } + if(b < 0) { + is_neg = !is_neg; + b = -b; + } + do_mul32(a, b); + if(is_neg) { + mul32_result[0] = -mul32_result[0]; + mul32_result[1] = ~mul32_result[1] + !mul32_result[0]; + } +} + +void mul32(int32_t source_operand) +{ + int32_t dest_operand = reg32s[EAX]; + + do_mul32(dest_operand, source_operand); + + reg32s[EAX] = mul32_result[0]; + reg32s[EDX] = mul32_result[1]; + + *last_result = mul32_result[0]; + *last_op_size = OPSIZE_32; + + if(mul32_result[1] == 0) + { + *flags &= ~1 & ~FLAG_OVERFLOW; + } + else + { + *flags |= 1 | FLAG_OVERFLOW; + } + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW; +} + +void imul32(int32_t source_operand) +{ + //XXX: this assert fails since the limits here are out of bounds for int32 + //but the assert is present in the original JS source :| + //assert(source_operand < 0x80000000 && source_operand >= -0x80000000); + + int32_t dest_operand = reg32s[EAX]; + + do_imul32(dest_operand, source_operand); + + reg32s[EAX] = mul32_result[0]; + reg32s[EDX] = mul32_result[1]; + + *last_result = mul32_result[0]; + *last_op_size = OPSIZE_32; + + if(mul32_result[1] == (mul32_result[0] >> 31)) + { + *flags &= ~1 & ~FLAG_OVERFLOW; + } + else + { + *flags |= 1 | FLAG_OVERFLOW; + } + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW; +} + +int32_t imul_reg32(int32_t operand1, int32_t operand2) +{ + //XXX: assert limits OOB for int32 + //dbg_assert(operand1 < 0x80000000 && operand1 >= -0x80000000); + //dbg_assert(operand2 < 0x80000000 && operand2 >= -0x80000000); + + do_imul32(operand1, operand2); + + *last_result = mul32_result[0]; + *last_op_size = OPSIZE_32; + + if(mul32_result[1] == (mul32_result[0] >> 31)) + { + *flags &= ~1 & ~FLAG_OVERFLOW; + } + else + { + *flags |= 1 | FLAG_OVERFLOW; + } + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW; + + return mul32_result[0]; +} + +int32_t xadd8(int32_t source_operand, int32_t reg) +{ + int32_t tmp = reg8[reg]; + + reg8[reg] = source_operand; + + return add(source_operand, tmp, OPSIZE_8); +} + +int32_t xadd16(int32_t source_operand, int32_t reg) +{ + int32_t tmp = reg16[reg]; + + reg16[reg] = source_operand; + + return add(source_operand, tmp, OPSIZE_16); +} + +int32_t xadd32(int32_t source_operand, int32_t reg) +{ + int32_t tmp = reg32s[reg]; + + reg32s[reg] = source_operand; + + return add(source_operand, tmp, OPSIZE_32); +} + +void bcd_daa() +{ + int32_t old_al = reg8[AL]; + int32_t old_cf = getcf(); + int32_t old_af = getaf(); + + *flags &= ~1 & ~FLAG_ADJUST; + + if((old_al & 0xF) > 9 || old_af) + { + reg8[AL] += 6; + *flags |= FLAG_ADJUST; + } + if(old_al > 0x99 || old_cf) + { + reg8[AL] += 0x60; + *flags |= 1; + } + + *last_result = reg8[AL]; + *last_op_size = OPSIZE_8; + *last_op1 = *last_op2 = 0; + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_ADJUST & ~FLAG_OVERFLOW; +} + +void bcd_das() +{ + int32_t old_al = reg8[AL]; + int32_t old_cf = getcf(); + + *flags &= ~1; + + if((old_al & 0xF) > 9 || getaf()) + { + reg8[AL] -= 6; + *flags |= FLAG_ADJUST; + *flags = *flags & ~1 | old_cf | (old_al < 6); + } + else + { + *flags &= ~FLAG_ADJUST; + } + + if(old_al > 0x99 || old_cf) + { + reg8[AL] -= 0x60; + *flags |= 1; + } + + *last_result = reg8[AL]; + *last_op_size = OPSIZE_8; + *last_op1 = *last_op2 = 0; + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_ADJUST & ~FLAG_OVERFLOW; +} + +void bcd_aad(int32_t imm8) +{ + int32_t result = reg8[AL] + reg8[AH] * imm8; + *last_result = result & 0xFF; + reg16[AX] = *last_result; + *last_op_size = OPSIZE_8; + + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_ADJUST & ~FLAG_OVERFLOW; + *flags &= ~1 & ~FLAG_ADJUST & ~FLAG_OVERFLOW; + + if(result > 0xFFFF) + { + *flags |= 1; + } +} + +void bcd_aaa() +{ + if((reg8[AL] & 0xF) > 9 || getaf()) + { + reg16[AX] += 6; + reg8[AH] += 1; + *flags |= FLAG_ADJUST | 1; + } + else + { + *flags &= ~FLAG_ADJUST & ~1; + } + reg8[AL] &= 0xF; + + *flags_changed &= ~FLAG_ADJUST & ~1; +} + +void bcd_aas() +{ + if((reg8[AL] & 0xF) > 9 || getaf()) + { + reg16[AX] -= 6; + reg8[AH] -= 1; + *flags |= FLAG_ADJUST | 1; + } + else + { + *flags &= ~FLAG_ADJUST & ~1; + } + reg8[AL] &= 0xF; + + *flags_changed &= ~FLAG_ADJUST & ~1; +} + +int32_t and(int32_t dest_operand, int32_t source_operand, int32_t op_size) +{ + *last_result = dest_operand & source_operand; + + *last_op_size = op_size; + *flags &= ~1 & ~FLAG_OVERFLOW & ~FLAG_ADJUST; + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW & ~FLAG_ADJUST; + + return *last_result; +} + +int32_t or(int32_t dest_operand, int32_t source_operand, int32_t op_size) +{ + *last_result = dest_operand | source_operand; + + *last_op_size = op_size; + *flags &= ~1 & ~FLAG_OVERFLOW & ~FLAG_ADJUST; + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW & ~FLAG_ADJUST; + + return *last_result; +} + +int32_t xor(int32_t dest_operand, int32_t source_operand, int32_t op_size) +{ + *last_result = dest_operand ^ source_operand; + + *last_op_size = op_size; + *flags &= ~1 & ~FLAG_OVERFLOW & ~FLAG_ADJUST; + *flags_changed = FLAGS_ALL & ~1 & ~FLAG_OVERFLOW & ~FLAG_ADJUST; + + return *last_result; +} + +int32_t and8(int32_t x, int32_t y) { return and(x, y, OPSIZE_8); } +int32_t and16(int32_t x, int32_t y) { return and(x, y, OPSIZE_16); } +int32_t and32(int32_t x, int32_t y) { return and(x, y, OPSIZE_32); } + +void test8(int32_t x, int32_t y) { and(x, y, OPSIZE_8); } +void test16(int32_t x, int32_t y) { and(x, y, OPSIZE_16); } +void test32(int32_t x, int32_t y) { and(x, y, OPSIZE_32); } + +int32_t or8(int32_t x, int32_t y) { return or(x, y, OPSIZE_8); } +int32_t or16(int32_t x, int32_t y) { return or(x, y, OPSIZE_16); } +int32_t or32(int32_t x, int32_t y) { return or(x, y, OPSIZE_32); } + +int32_t xor8(int32_t x, int32_t y) { return xor(x, y, OPSIZE_8); } +int32_t xor16(int32_t x, int32_t y) { return xor(x, y, OPSIZE_16); } +int32_t xor32(int32_t x, int32_t y) { return xor(x, y, OPSIZE_32); } + +int32_t rol8(int32_t dest_operand, int32_t count) +{ + if(!count) + { + return dest_operand; + } + count &= 7; + + int32_t result = dest_operand << count | dest_operand >> (8 - count); + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) + | (result & 1) + | (result << 11 ^ result << 4) & FLAG_OVERFLOW; + + return result; +} + +int32_t rol16(int32_t dest_operand, int32_t count) +{ + if(!count) + { + return dest_operand; + } + count &= 15; + + int32_t result = dest_operand << count | dest_operand >> (16 - count); + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) + | (result & 1) + | (result << 11 ^ result >> 4) & FLAG_OVERFLOW; + + return result; +} + +int32_t rol32(int32_t dest_operand, int32_t count) +{ + if(!count) + { + return dest_operand; + } + + int32_t result = dest_operand << count | ((uint32_t) dest_operand) >> (32 - count); + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) + | (result & 1) + | (result << 11 ^ result >> 20) & FLAG_OVERFLOW; + + return result; +} + +int32_t rcl8(int32_t dest_operand, int32_t count) +{ + count %= 9; + if(!count) + { + return dest_operand; + } + + int32_t result = dest_operand << count | getcf() << (count - 1) | dest_operand >> (9 - count); + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) + | (result >> 8 & 1) + | (result << 3 ^ result << 4) & FLAG_OVERFLOW; + + return result; +} + +int32_t rcl16(int32_t dest_operand, int32_t count) +{ + count %= 17; + if(!count) + { + return dest_operand; + } + + int32_t result = dest_operand << count | getcf() << (count - 1) | dest_operand >> (17 - count); + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) + | (result >> 16 & 1) + | (result >> 5 ^ result >> 4) & FLAG_OVERFLOW; + + return result; +} + +int32_t rcl32(int32_t dest_operand, int32_t count) +{ + if(!count) + { + return dest_operand; + } + + int32_t result = dest_operand << count | getcf() << (count - 1); + + if(count > 1) + { + result |= ((uint32_t) dest_operand) >> (33 - count); + } + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) | (((uint32_t) dest_operand) >> (32 - count) & 1); + *flags |= (*flags << 11 ^ result >> 20) & FLAG_OVERFLOW; + + return result; +} + +int32_t ror8(int32_t dest_operand, int32_t count) +{ + if(!count) + { + return dest_operand; + } + + count &= 7; + int32_t result = dest_operand >> count | dest_operand << (8 - count); + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) + | (result >> 7 & 1) + | (result << 4 ^ result << 5) & FLAG_OVERFLOW; + + return result; +} + +int32_t ror16(int32_t dest_operand, int32_t count) +{ + if(!count) + { + return dest_operand; + } + + count &= 15; + int32_t result = dest_operand >> count | dest_operand << (16 - count); + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) + | (result >> 15 & 1) + | (result >> 4 ^ result >> 3) & FLAG_OVERFLOW; + + return result; +} + +int32_t ror32(int32_t dest_operand, int32_t count) +{ + if(!count) + { + return dest_operand; + } + + int32_t result = ((uint32_t) dest_operand) >> count | dest_operand << (32 - count); + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) + | (result >> 31 & 1) + | (result >> 20 ^ result >> 19) & FLAG_OVERFLOW; + + return result; +} + +int32_t rcr8(int32_t dest_operand, int32_t count) +{ + count %= 9; + if(!count) + { + return dest_operand; + } + + int32_t result = dest_operand >> count | getcf() << (8 - count) | dest_operand << (9 - count); + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) + | (result >> 8 & 1) + | (result << 4 ^ result << 5) & FLAG_OVERFLOW; + + return result; +} + +int32_t rcr16(int32_t dest_operand, int32_t count) +{ + count %= 17; + if(!count) + { + return dest_operand; + } + + int32_t result = dest_operand >> count | getcf() << (16 - count) | dest_operand << (17 - count); + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) + | (result >> 16 & 1) + | (result >> 4 ^ result >> 3) & FLAG_OVERFLOW; + + return result; +} + +int32_t rcr32(int32_t dest_operand, int32_t count) +{ + if(!count) + { + return dest_operand; + } + + int32_t result = ((uint32_t) dest_operand) >> count | getcf() << (32 - count); + + if(count > 1) + { + result |= dest_operand << (33 - count); + } + + *flags_changed &= ~1 & ~FLAG_OVERFLOW; + *flags = (*flags & ~1 & ~FLAG_OVERFLOW) + | (dest_operand >> (count - 1) & 1) + | (result >> 20 ^ result >> 19) & FLAG_OVERFLOW; + + return result; +} + +void div8(uint32_t source_operand) +{ + if(source_operand == 0) + { + trigger_de(); + return; + } + + uint16_t target_operand = reg16[AX]; + uint16_t result = target_operand / source_operand; + + if(result >= 0x100) + { + trigger_de(); + } + else + { + reg8[AL] = result; + reg8[AH] = target_operand % source_operand; + } +} + +void idiv8(int32_t source_operand) +{ + if(source_operand == 0) + { + trigger_de(); + return; + } + + int32_t target_operand = reg16s[AX]; + int32_t result = target_operand / source_operand; + + if(result >= 0x80 || result <= -0x81) + { + trigger_de(); + } + else + { + reg8[AL] = result; + reg8[AH] = target_operand % source_operand; + } +} + +void div16(uint32_t source_operand) +{ + if(source_operand == 0) + { + trigger_de(); + return; + } + + uint32_t target_operand = reg16[AX] | reg16[DX] << 16; + uint32_t result = target_operand / source_operand; + + if(result >= 0x10000) + { + trigger_de(); + } + else + { + reg16[AX] = result; + reg16[DX] = target_operand % source_operand; + } +} + diff --git a/src/native/const.h b/src/native/const.h new file mode 100644 index 00000000..b5f8e10f --- /dev/null +++ b/src/native/const.h @@ -0,0 +1,159 @@ +#ifndef DEBUG +#define DEBUG true +#endif + +#define FLAG_CARRY 1 +#define FLAG_PARITY 4 +#define FLAG_ADJUST 16 +#define FLAG_ZERO 64 +#define FLAG_SIGN 128 +#define FLAG_TRAP 256 +#define FLAG_INTERRUPT 512 +#define FLAG_DIRECTION 1024 +#define FLAG_OVERFLOW 2048 +#define FLAG_IOPL (1 << 12 | 1 << 13) +#define FLAG_NT (1 << 14) +#define FLAG_RF (1 << 16) +#define FLAG_VM (1 << 17) +#define FLAG_AC (1 << 18) +#define FLAG_VIF (1 << 19) +#define FLAG_VIP (1 << 20) +#define FLAG_ID (1 << 21) +#define FLAGS_DEFAULT (1 << 1) + +#define FLAGS_MASK ( \ + FLAG_CARRY | FLAG_PARITY | FLAG_ADJUST | FLAG_ZERO | FLAG_SIGN | FLAG_TRAP | FLAG_INTERRUPT | \ + FLAG_DIRECTION | FLAG_OVERFLOW | FLAG_IOPL | FLAG_NT | FLAG_RF | FLAG_VM | FLAG_AC | \ + FLAG_VIF | FLAG_VIP | FLAG_ID) + +#define FLAGS_ALL (FLAG_CARRY | FLAG_PARITY | FLAG_ADJUST | FLAG_ZERO | FLAG_SIGN | FLAG_OVERFLOW) + +#define OPSIZE_8 7 +#define OPSIZE_16 15 +#define OPSIZE_32 31 + +#define EAX 0 +#define ECX 1 +#define EDX 2 +#define EBX 3 +#define ESP 4 +#define EBP 5 +#define ESI 6 +#define EDI 7 + +#define AX 0 +#define CX 2 +#define DX 4 +#define BX 6 +#define SP 8 +#define BP 10 +#define SI 12 +#define DI 14 + +#define AL 0 +#define CL 4 +#define DL 8 +#define BL 12 +#define AH 1 +#define CH 5 +#define DH 9 +#define BH 13 + +#define ES 0 +#define CS 1 +#define SS 2 +#define DS 3 +#define FS 4 +#define GS 5 + +#define TR 6 +#define LDTR 7 + + +#define TLB_SYSTEM_READ 1 +#define TLB_SYSTEM_WRITE 2 +#define TLB_USER_READ 4 +#define TLB_USER_WRITE 8 + + +#define PSE_ENABLED 128 + +#define MMAP_BLOCK_BITS 17 +#define MMAP_BLOCK_SIZE = (1 << MMAP_BLOCK_BITS) + +#define CR0_PE 1 +#define CR0_MP (1 << 1) +#define CR0_EM (1 << 2) +#define CR0_TS (1 << 3) +#define CR0_ET (1 << 4) +#define CR0_WP (1 << 16) +#define CR0_NW (1 << 29) +#define CR0_CD (1 << 30) +#define CR0_PG (1 << 31) + +#define CR4_VME (1) +#define CR4_PVI (1 << 1) +#define CR4_TSD (1 << 2) +#define CR4_PSE (1 << 4) +#define CR4_DE (1 << 3) +#define CR4_PAE (1 << 5) +#define CR4_PGE (1 << 7) + + +#define IA32_SYSENTER_CS 0x174 +#define IA32_SYSENTER_ESP 0x175 +#define IA32_SYSENTER_EIP 0x176 + +#define IA32_TIME_STAMP_COUNTER 0x10 +#define IA32_PLATFORM_ID 0x17 +#define IA32_APIC_BASE_MSR 0x1B +#define IA32_BIOS_SIGN_ID 0x8B +#define IA32_MISC_ENABLE 0x1A0 +#define IA32_RTIT_CTL 0x570 +#define MSR_SMI_COUNT 0x34 +#define IA32_MCG_CAP 0x179 +#define IA32_KERNEL_GS_BASE 0xC0000101 +#define MSR_PKG_C2_RESIDENCY 0x60D + +#define IA32_APIC_BASE_BSP (1 << 8) +#define IA32_APIC_BASE_EXTD (1 << 10) +#define IA32_APIC_BASE_EN (1 << 11) + + +// Note: Duplicated in apic.js +#define APIC_ADDRESS ((int32_t)0xFEE00000) + + +// Segment prefixes must not collide with reg_*s variables +// _ZERO is a special zero offset segment +#define SEG_PREFIX_NONE (-1) +#define SEG_PREFIX_ZERO 7 + +#define PREFIX_MASK_REP 0b11000 +#define PREFIX_REPZ 0b01000 +#define PREFIX_REPNZ 0b10000 + +#define PREFIX_MASK_SEGMENT 0b111 +#define PREFIX_MASK_OPSIZE 0b100000 +#define PREFIX_MASK_ADDRSIZE 0b1000000 + + + +/** + * How many cycles the CPU does at a time before running hardware timers + */ +#define LOOP_COUNTER 11001 + +#define TSC_RATE (8 * 1024) + +#define LOG_CPU 0x000002 +#define CPU_LOG_VERBOSE false +#define ENABLE_ACPI false + +#define A20_MASK (~(1 << 20)) +#define A20_MASK16 (~(1 << (20 - 1))) +#define A20_MASK32 (~(1 << (20 - 2))) + +#define USE_A20 false + +#define MXCSR_MASK (0xFFFF & ~(1 << 6)) diff --git a/src/native/cpu.c b/src/native/cpu.c new file mode 100644 index 00000000..46b45a7e --- /dev/null +++ b/src/native/cpu.c @@ -0,0 +1,572 @@ +#include +#include +#include +#include +#include + +#include "const.h" +#include "global_pointers.h" + +int32_t read_e8_partial_branch() { + return reg8[*modrm_byte << 2 & 0xC | *modrm_byte >> 2 & 1]; +} + +int32_t translate_address_read(int32_t); +int32_t translate_address_write(int32_t); +int32_t read8(uint32_t); +int32_t read16(uint32_t); +int32_t read32s(uint32_t); +int32_t virt_boundary_read16(int32_t, int32_t); +int32_t virt_boundary_read32s(int32_t, int32_t); +void write8(uint32_t, uint8_t); +void write16(uint32_t, uint16_t); +void write32(uint32_t, int32_t); +void virt_boundary_write16(int32_t, int32_t, int32_t); +void virt_boundary_write32(int32_t, int32_t, int32_t); + +void trigger_gp(int32_t); + +int32_t safe_read8(int32_t); +int32_t safe_read16(int32_t); +int32_t safe_read32s(int32_t); + +void safe_write8(int32_t, int32_t); +void safe_write16(int32_t, int32_t); +void safe_write32(int32_t, int32_t); + +void fxsave(int32_t); +void fxrstor(int32_t); + +int32_t do_page_translation(int32_t, bool, bool); + +void diverged() {} +void branch_taken() {} +void branch_not_taken() {} + +int32_t getcf(void); +int32_t getpf(void); +int32_t getaf(void); +int32_t getzf(void); +int32_t getsf(void); +int32_t getof(void); + + +int32_t get_eflags() +{ + return (*flags & ~FLAGS_ALL) | !!getcf() | !!getpf() << 2 | !!getaf() << 4 | + !!getzf() << 6 | !!getsf() << 7 | !!getof() << 11; +} + +int32_t translate_address_read(int32_t address) +{ + if(!*paging) return address; + + int32_t base = (uint32_t)address >> 12; + if(tlb_info[base] & (*cpl == 3 ? TLB_USER_READ : TLB_SYSTEM_READ)) + { + return tlb_data[base] ^ address; + } + else + { + return do_page_translation(address, 0, *cpl == 3) | address & 0xFFF; + } +} + +int32_t translate_address_write(int32_t address) +{ + if(!*paging) return address; + + int32_t base = (uint32_t)address >> 12; + if(tlb_info[base] & (*cpl == 3 ? TLB_USER_WRITE : TLB_SYSTEM_WRITE)) + { + return tlb_data[base] ^ address; + } + else + { + return do_page_translation(address, 1, *cpl == 3) | address & 0xFFF; + } +} + +int32_t read_imm8() +{ + int32_t eip = *instruction_pointer; + + if((eip & ~0xFFF) ^ *last_virt_eip) + { + *eip_phys = translate_address_read(eip) ^ eip; + *last_virt_eip = eip & ~0xFFF; + } + + int32_t data8 = read8(*eip_phys ^ eip); + *instruction_pointer = eip + 1; + + return data8; +} + +int32_t read_imm8s() +{ + return read_imm8() << 24 >> 24; +} + +int32_t read_imm16() +{ + // Two checks in one comparison: + // 1. Did the high 20 bits of eip change + // or 2. Are the low 12 bits of eip 0xFFF (and this read crosses a page boundary) + if((uint32_t)(*instruction_pointer ^ *last_virt_eip) > 0xFFE) + { + return read_imm8() | read_imm8() << 8; + } + + int32_t data16 = read16(*eip_phys ^ *instruction_pointer); + *instruction_pointer = *instruction_pointer + 2; + + return data16; +} + +int32_t read_imm32s() +{ + // Analogue to the above comment + if((uint32_t)(*instruction_pointer ^ *last_virt_eip) > 0xFFC) + { + return read_imm16() | read_imm16() << 16; + } + + int32_t data32 = read32s(*eip_phys ^ *instruction_pointer); + *instruction_pointer = *instruction_pointer + 4; + + return data32; +} + +int32_t read_op0F() { return read_imm8(); } +int32_t read_sib() { return read_imm8(); } +int32_t read_op8() { return read_imm8(); } +int32_t read_op8s() { return read_imm8s(); } +int32_t read_op16() { return read_imm16(); } +int32_t read_op32s() { return read_imm32s(); } +int32_t read_disp8() { return read_imm8(); } +int32_t read_disp8s() { return read_imm8s(); } +int32_t read_disp16() { return read_imm16(); } +int32_t read_disp32s() { return read_imm32s(); } + +bool is_osize_32() +{ + return *is_32 != ((*prefixes & PREFIX_MASK_OPSIZE) == PREFIX_MASK_OPSIZE); +} + +bool is_asize_32() +{ + return *is_32 != ((*prefixes & PREFIX_MASK_ADDRSIZE) == PREFIX_MASK_ADDRSIZE); +} + +void read_modrm_byte() +{ + *modrm_byte = read_imm8(); +} + +int32_t get_seg(int32_t segment) +{ + assert(segment >= 0 && segment < 8); + + // TODO: Remove protected_mode check + if(*protected_mode) + { + if(segment_is_null[segment]) + { + assert(segment != CS && segment != SS); + trigger_gp(0); + } + } + + return segment_offsets[segment]; +} + +int32_t get_seg_prefix(int32_t default_segment) +{ + int32_t prefix = *prefixes & PREFIX_MASK_SEGMENT; + + if(prefix) + { + if(prefix == SEG_PREFIX_ZERO) + { + return 0; // TODO: Remove this special case + } + else + { + return get_seg(prefix - 1); + } + } + else + { + return get_seg(default_segment); + } +} + +int32_t get_seg_prefix_ds(int32_t offset) { return get_seg_prefix(DS) + offset; } +int32_t get_seg_prefix_ss(int32_t offset) { return get_seg_prefix(SS) + offset; } +int32_t get_seg_prefix_cs(int32_t offset) { return get_seg_prefix(CS) + offset; } + +static void run_instruction(int32_t); +static int32_t resolve_modrm16(int32_t); +static int32_t resolve_modrm32(int32_t); + +static int32_t modrm_resolve(int32_t modrm_byte) +{ + if(is_asize_32()) + { + return resolve_modrm32(modrm_byte); + } + else + { + return resolve_modrm16(modrm_byte); + } +} + +void set_e8(int32_t value) +{ + int32_t modrm_byte_ = *modrm_byte; + if(modrm_byte_ < 0xC0) { + int32_t addr = modrm_resolve(modrm_byte_); + safe_write8(addr, value); + } else { + reg8[modrm_byte_ << 2 & 0xC | modrm_byte_ >> 2 & 1] = value; + } +} + +void set_e16(int32_t value) +{ + int32_t modrm_byte_ = *modrm_byte; + if(modrm_byte_ < 0xC0) { + int32_t addr = modrm_resolve(modrm_byte_); + safe_write16(addr, value); + } else { + reg16[modrm_byte_ << 1 & 14] = value; + } +} + +void set_e32(int32_t value) +{ + int32_t modrm_byte_ = *modrm_byte; + if(modrm_byte_ < 0xC0) { + int32_t addr = modrm_resolve(modrm_byte_); + safe_write32(addr, value); + } else { + reg32s[modrm_byte_ & 7] = value; + } +} + +int32_t read_g8() +{ + return reg8[*modrm_byte >> 1 & 0xC | *modrm_byte >> 5 & 1]; +} + +int32_t read_g16() +{ + return reg16[*modrm_byte >> 2 & 14]; +} + +int32_t read_g16s() +{ + return reg16s[*modrm_byte >> 2 & 14]; +} + +int32_t read_g32s() +{ + return reg32s[*modrm_byte >> 3 & 7]; +} + +void write_g8(int32_t value) +{ + reg8[*modrm_byte >> 1 & 0xC | *modrm_byte >> 5 & 1] = value; +} + +void write_g16(int32_t value) +{ + reg16[*modrm_byte >> 2 & 14] = value; +} + +void write_g32(int32_t value) +{ + reg32s[*modrm_byte >> 3 & 7] = value; +} + +int32_t read_e8() +{ + if(*modrm_byte < 0xC0) + { + return safe_read8(modrm_resolve(*modrm_byte)); + } + else + { + return reg8[*modrm_byte << 2 & 0xC | *modrm_byte >> 2 & 1]; + } +} + +int32_t read_e8s() +{ + return read_e8() << 24 >> 24; +} + +int32_t read_e16() +{ + if(*modrm_byte < 0xC0) + { + return safe_read16(modrm_resolve(*modrm_byte)); + } + else + { + return reg16[*modrm_byte << 1 & 14]; + } +} + +int32_t read_e16s() +{ + return read_e16() << 16 >> 16; +} + +int32_t read_e32s() +{ + if(*modrm_byte < 0xC0) + { + return safe_read32s(modrm_resolve(*modrm_byte)); + } + else + { + return reg32s[*modrm_byte & 7]; + } +} + +void cycle_internal() +{ + previous_ip[0] = instruction_pointer[0]; + + (*timestamp_counter)++; + + int32_t opcode = read_imm8(); + + run_instruction(opcode); +} + +static void run_prefix_instruction() +{ + run_instruction(read_imm8()); +} + +void clear_prefixes() +{ + *prefixes = 0; +} + +void segment_prefix_op(int32_t seg) +{ + assert(seg <= 5); + *prefixes |= seg + 1; + run_prefix_instruction(); + *prefixes = 0; +} + +void do_many_cycles_unsafe() +{ + for(int32_t k = 0; k < LOOP_COUNTER; k++) + { + cycle_internal(); + } +} + +void raise_exception(int32_t interrupt_nr) +{ + call_interrupt_vector(interrupt_nr, false, false, 0); + throw_cpu_exception(); +} + +void raise_exception_with_code(int32_t interrupt_nr, int32_t error_code) +{ + call_interrupt_vector(interrupt_nr, false, true, error_code); + throw_cpu_exception(); +} + +void trigger_de() +{ + *instruction_pointer = *previous_ip; + raise_exception(0); +} + +void trigger_gp(int32_t code) +{ + *instruction_pointer = *previous_ip; + raise_exception_with_code(13, code); +} + +int32_t safe_read8(int32_t addr) +{ + return read8(translate_address_read(addr)); +} + +int32_t safe_read16(int32_t addr) +{ + if((addr & 0xFFF) == 0xFFF) + { + return safe_read8(addr) | safe_read8(addr + 1) << 8; + } + else + { + return read16(translate_address_read(addr)); + } +} + +int32_t safe_read32s(int32_t addr) +{ + if((addr & 0xFFF) >= 0xFFD) + { + return safe_read16(addr) | safe_read16(addr + 2) << 16; + } + else + { + return read32s(translate_address_read(addr)); + } +} + +void safe_write8(int32_t addr, int32_t value) +{ + write8(translate_address_write(addr), value); +} + +void safe_write16(int32_t addr, int32_t value) +{ + int32_t phys_low = translate_address_write(addr); + + if((addr & 0xFFF) == 0xFFF) + { + virt_boundary_write16(phys_low, translate_address_write(addr + 1), value); + } + else + { + write16(phys_low, value); + } +} + +void safe_write32(int32_t addr, int32_t value) +{ + int32_t phys_low = translate_address_write(addr); + + if((addr & 0xFFF) >= 0xFFD) + { + virt_boundary_write32(phys_low, translate_address_write(addr + 3 & ~3) | (addr + 3) & 3, value); + } + else + { + write32(phys_low, value); + } +} + +int32_t read_write_e8() +{ + if(*modrm_byte < 0xC0) + { + int32_t virt_addr = modrm_resolve(*modrm_byte); + *phys_addr = translate_address_write(virt_addr); + return read8(*phys_addr); + } + else + { + return reg8[*modrm_byte << 2 & 0xC | *modrm_byte >> 2 & 1]; + } +} + +void write_e8(int32_t value) +{ + if(*modrm_byte < 0xC0) + { + write8(*phys_addr, value); + } + else + { + reg8[*modrm_byte << 2 & 0xC | *modrm_byte >> 2 & 1] = value; + } +} + +int32_t read_write_e16() +{ + if(*modrm_byte < 0xC0) + { + int32_t virt_addr = modrm_resolve(*modrm_byte); + *phys_addr = translate_address_write(virt_addr); + if((virt_addr & 0xFFF) == 0xFFF) + { + *phys_addr_high = translate_address_write(virt_addr + 1); + dbg_assert(*phys_addr_high); + return virt_boundary_read16(*phys_addr, *phys_addr_high); + } + else + { + *phys_addr_high = 0; + return read16(*phys_addr); + } + } + else + { + return reg16[*modrm_byte << 1 & 14]; + } +} + +void write_e16(int32_t value) +{ + if(*modrm_byte < 0xC0) + { + if(*phys_addr_high) + { + virt_boundary_write16(*phys_addr, *phys_addr_high, value); + } + else + { + write16(*phys_addr, value); + } + } + else + { + reg16[*modrm_byte << 1 & 14] = value; + } +} + +int32_t read_write_e32() +{ + if(*modrm_byte < 0xC0) + { + int32_t virt_addr = modrm_resolve(*modrm_byte); + *phys_addr = translate_address_write(virt_addr); + if((virt_addr & 0xFFF) >= 0xFFD) + { + *phys_addr_high = translate_address_write(virt_addr + 3 & ~3) | (virt_addr + 3) & 3; + dbg_assert(*phys_addr_high); + return virt_boundary_read32s(*phys_addr, *phys_addr_high); + } + else + { + *phys_addr_high = 0; + return read32s(*phys_addr); + } + } + else + { + return reg32s[*modrm_byte & 7]; + } +} + +void write_e32(int32_t value) +{ + if(*modrm_byte < 0xC0) + { + if(*phys_addr_high) + { + virt_boundary_write32(*phys_addr, *phys_addr_high, value); + } + else + { + write32(*phys_addr, value); + } + } + else + { + reg32s[*modrm_byte & 7] = value; + } +} diff --git a/src/native/fpu.c b/src/native/fpu.c new file mode 100644 index 00000000..aab2b889 --- /dev/null +++ b/src/native/fpu.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +#include + +#include "const.h" +#include "global_pointers.h" + +void safe_tag_word(int32_t tag_word) { + *stack_empty = 0; + + for(int i = 0; i < 8; i++) + { + *stack_empty |= (tag_word >> i) & (tag_word >> (i + 1)) & 1 << i; + } + + //dbg_log("safe tw=" + h(tag_word) + " se=" + h(this.stack_empty[0]), LOG_FPU); +} diff --git a/src/native/global_pointers.h b/src/native/global_pointers.h new file mode 100644 index 00000000..5651a416 --- /dev/null +++ b/src/native/global_pointers.h @@ -0,0 +1,69 @@ +#ifndef _GLOBAL_POINTERS_H +#define _GLOBAL_POINTERS_H + +uint8_t* const reg8 = (uint8_t* const) 4; +uint16_t* const reg16 = (uint16_t* const) 4; +int8_t* const reg8s = (int8_t* const) 4; +int16_t* const reg16s = (int16_t* const) 4; +int32_t* const reg32s = (int32_t* const) 4; + +int32_t* const last_op1 = (int32_t* const) 512; +int32_t* const last_op2 = (int32_t* const) 516; +int32_t* const last_op_size = (int32_t* const) 520; +int32_t* const last_add_result = (int32_t* const) 524; +int32_t* const last_result = (int32_t* const) 528; +int32_t* const flags_changed = (int32_t* const) 532; +int32_t* const flags = (int32_t* const) 536; +int32_t* const modrm_byte = (int32_t* const) 540; +int32_t* const mul32_result = (int32_t* const) 544; // length 2 + +bool* const a20_enabled = (bool* const) 552; +int32_t* const instruction_pointer = (int32_t* const) 556; +int32_t* const previous_ip = (int32_t* const) 560; + +int32_t* const idtr_size = (int32_t* const) 564; +int32_t* const idtr_offset = (int32_t* const) 568; +int32_t* const gdtr_size = (int32_t* const) 572; +int32_t* const gdtr_offset = (int32_t* const) 576; +int32_t* const cr = (int32_t* const) 580; // length 8 + +int32_t* const cpl = (int32_t* const) 612; +int32_t* const page_size_extensions = (int32_t* const) 616; +int32_t* const last_virt_eip = (int32_t* const) 620; +int32_t* const eip_phys = (int32_t* const) 624; +int32_t* const last_virt_esp = (int32_t* const) 628; +int32_t* const esp_phys = (int32_t* const) 632; +int32_t* const sysenter_cs = (int32_t* const) 636; +int32_t* const sysenter_esp = (int32_t* const) 640; +int32_t* const sysenter_eip = (int32_t* const) 644; +int32_t* const prefixes = (int32_t* const) 648; +int32_t* const tsc_offset = (int32_t* const) 652; +int32_t* const phys_addr = (int32_t* const) 656; +int32_t* const phys_addr_high = (int32_t* const) 660; +int32_t* const timestamp_counter = (int32_t* const) 664; + +uint16_t* const sreg = (uint16_t* const) 668; +int32_t* const dreg = (int32_t* const) 684; // length 8 +int32_t* const fw_value = (int32_t* const) 720; +uint8_t* const segment_is_null = (uint8_t* const) 724; // length 8 +int32_t* const segment_offsets = (int32_t* const) 736; // length 8 +uint32_t* const segment_limits = (uint32_t* const) 768; // length 8 + +bool* const protected_mode = (bool* const) 800; +bool* const is_32 = (bool* const) 804; +bool* const stack_size_32 = (bool* const) 808; +uint32_t* const memory_size = (uint32_t* const) 812; +int32_t* const stack_empty = (int32_t* const) 816; + +bool* const paging = (bool* const) 820; + +bool* const mxcsr = (bool* const) 824; + +uint8_t* const tlb_info = (uint8_t* const) 2048; // length 0x100000 +uint8_t* const tlb_info_global = (uint8_t* const) (2048 + 0x100000); // length 0x100000 +int32_t* const tlb_data = (int32_t* const) (2048 + 0x100000 + 0x100000); // length 0x100000*4 + +uint8_t* const mem8 = (uint8_t* const) (2048 + 0x100000 * 6); +uint16_t* const mem16 = (uint16_t* const) (2048 + 0x100000 * 6); + +#endif diff --git a/src/native/instructions.c b/src/native/instructions.c new file mode 100644 index 00000000..9280ec74 --- /dev/null +++ b/src/native/instructions.c @@ -0,0 +1,3171 @@ +#include +#include +#include +#include + +#include + +#include "const.h" +#include "global_pointers.h" + +int32_t translate_address_write(int32_t); +int32_t resolve_modrm(int32_t); + +/* +int32_t phys_read8(int32_t); +int32_t phys_write8(int32_t, int32_t); + + +#define RE8 reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] +#define E8 e8 +#define G8 reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1] + +#define IDX_E8 (modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1) +#define IDX_G8 (modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1) + +#define READ_WRITE_E8_(f)\ +{\ + int32_t modrm_byte = read_modrm_byte();\ + if(modrm_byte < 0xC0) {\ + int32_t phys_addr = translate_address_write(resolve_modrm(modrm_byte));\ + int32_t e8 = phys_read8(phys_addr);\ + phys_write8(phys_addr, f);\ + }\ + else {\ + int32_t e8 = RE8;\ + RE8 = f;\ + }\ +} + +#define READ_WRITE_E8(f)\ +{\ + int32_t modrm_byte = read_modrm_byte();\ + if(modrm_byte < 0xC0) {\ + int32_t virt_addr = resolve_modrm(modrm_byte);\ + f ## _rm(virt_addr, IDX_G8);\ + }\ + else {\ + f ## _rr(IDX_E8, IDX_G8);\ + }\ +} +*/ + + +// XXX: Remove these declarations when they are implemented in C +int32_t read_write_e8(void); +int32_t read_write_e16(void); +int32_t read_write_e32(void); +int32_t read_g8(void); +int32_t read_g16(void); +int32_t read_g32s(void); + +int32_t read_e8(void); +int32_t read_e8s(void); +int32_t read_e16(void); +int32_t read_e16s(void); +int32_t read_e32(void); +int32_t read_e32s(void); + +void write_e8(int32_t); +void write_e16(int32_t); +void write_e32(int32_t); + +void write_reg_e16(int32_t); +void write_reg_e32(int32_t); + +void set_e8(int32_t); +void set_e16(int32_t); +void set_e32(int32_t); + +void write_g8(int32_t); +void write_g16(int32_t); +void write_g32(int32_t); + +int32_t read_op8(void); +int32_t read_op8s(void); +int32_t read_op16(void); +int32_t read_op32s(void); + +int32_t read_disp8(void); +int32_t read_disp16(void); + +int32_t read_moffs(void); + +void push16(int32_t); +void push32(int32_t); + +void pusha16(void); +void pusha32(void); +void popa16(void); +void popa32(void); +int32_t arpl(int32_t, int32_t); + +void trigger_ud(void); +void trigger_nm(void); +static void run_prefix_instruction(void); + +int32_t pop16(void); +int32_t pop32s(void); + +int32_t safe_read8(int32_t); +int32_t safe_read16(int32_t); +int32_t safe_read32s(int32_t); + +void safe_write8(int32_t, int32_t); +void safe_write16(int32_t, int32_t); +void safe_write32(int32_t, int32_t); + +void push32(int32_t); +int32_t get_stack_pointer(int32_t); +void adjust_stack_reg(int32_t); +void set_stack_reg(int32_t); + +int32_t getiopl(void); +int32_t get_eflags(void); +int32_t getof(void); +int32_t getzf(void); + +void switch_seg(int32_t, int32_t); + +bool vm86_mode(void); + +int32_t shl8(int32_t, int32_t); +int32_t shr8(int32_t, int32_t); +int32_t sar8(int32_t, int32_t); +int32_t ror8(int32_t, int32_t); +int32_t rol8(int32_t, int32_t); +int32_t rcr8(int32_t, int32_t); +int32_t rcl8(int32_t, int32_t); + +int32_t shl16(int32_t, int32_t); +int32_t shr16(int32_t, int32_t); +int32_t sar16(int32_t, int32_t); +int32_t ror16(int32_t, int32_t); +int32_t rol16(int32_t, int32_t); +int32_t rcr16(int32_t, int32_t); +int32_t rcl16(int32_t, int32_t); + +int32_t shl32(int32_t, int32_t); +int32_t shr32(int32_t, int32_t); +int32_t sar32(int32_t, int32_t); +int32_t ror32(int32_t, int32_t); +int32_t rol32(int32_t, int32_t); +int32_t rcr32(int32_t, int32_t); +int32_t rcl32(int32_t, int32_t); + +int32_t idiv16(int32_t); +int32_t div32(int32_t); +int32_t idiv32(int32_t); + + +void insb(void); +void insw(void); +void insd(void); +void outsb(void); +void outsw(void); +void outsd(void); +void movsb(void); +void movsw(void); +void movsd(void); +void cmpsb(void); +void cmpsw(void); +void cmpsd(void); +void stosb(void); +void stosw(void); +void stosd(void); +void lodsb(void); +void lodsw(void); +void lodsd(void); +void scasb(void); +void scasw(void); +void scasd(void); + +void fpu_op_D8_mem(int32_t, int32_t); +void fpu_op_D8_reg(int32_t); +void fpu_op_D9_mem(int32_t, int32_t); +void fpu_op_D9_reg(int32_t); +void fpu_op_DA_mem(int32_t, int32_t); +void fpu_op_DA_reg(int32_t); +void fpu_op_DB_mem(int32_t, int32_t); +void fpu_op_DB_reg(int32_t); +void fpu_op_DC_mem(int32_t, int32_t); +void fpu_op_DC_reg(int32_t); +void fpu_op_DD_mem(int32_t, int32_t); +void fpu_op_DD_reg(int32_t); +void fpu_op_DE_mem(int32_t, int32_t); +void fpu_op_DE_reg(int32_t); +void fpu_op_DF_mem(int32_t, int32_t); +void fpu_op_DF_reg(int32_t); + +int32_t test_o(void); +int32_t test_b(void); +int32_t test_z(void); +int32_t test_s(void); +int32_t test_p(void); +int32_t test_be(void); +int32_t test_l(void); +int32_t test_le(void); + +void jmpcc8(bool); + +void far_jump(int32_t, int32_t, int32_t); +void far_return(int32_t, int32_t, int32_t); + +void iret16(); +void iret32(); + +void lss16(int32_t); +void lss32(int32_t); + +void enter16(int32_t, int32_t); +void enter32(int32_t, int32_t); + +int32_t get_seg(int32_t); +int32_t get_seg_prefix(int32_t); +void update_eflags(int32_t); +void handle_irqs(void); +int32_t get_real_eip(void); +void diverged(void); + +int32_t xchg8(int32_t, int32_t); +int32_t xchg16(int32_t, int32_t); +int32_t xchg16r(int32_t); +int32_t xchg32(int32_t, int32_t); +int32_t xchg32r(int32_t); + +int32_t loop(int32_t); +int32_t loope(int32_t); +int32_t loopne(int32_t); + +void bcd_aam(int32_t); +void task_switch_test(void); +void jcxz(int32_t); +void test_privileges_for_io(int32_t, int32_t); +int32_t io_port_read8(int32_t); +int32_t io_port_read16(int32_t); +int32_t io_port_read32(int32_t); +void jmp_rel16(int32_t); +void hlt_op(void); + +void io_port_write8(int32_t, int32_t); +void io_port_write16(int32_t, int32_t); +void io_port_write32(int32_t, int32_t); + +int32_t modrm_resolve(int32_t); + +static void run_instruction0f_16(int32_t); +static void run_instruction0f_32(int32_t); + +void clear_prefixes(void); +void cycle_internal(void); + + +void fwait(void); + + +static void instr_00() { read_modrm_byte(); write_e8(add8(read_write_e8(), read_g8())); } +static void instr16_01() { read_modrm_byte(); write_e16(add16(read_write_e16(), read_g16())); } +static void instr32_01() { read_modrm_byte(); write_e32(add32(read_write_e32(), read_g32s())); } +static void instr_02() { read_modrm_byte(); write_g8(add8(read_g8(), read_e8())); } +static void instr16_03() { read_modrm_byte(); write_g16(add16(read_g16(), read_e16())); } +static void instr32_03() { read_modrm_byte(); write_g32(add32(read_g32s(), read_e32s())); } +static void instr_04() { reg8[AL] = add8(reg8[AL], read_op8()); } +static void instr16_05() { reg16[AX] = add16(reg16[AX], read_op16()); } +static void instr32_05() { reg32s[EAX] = add32(reg32s[EAX], read_op32s()); } + +static void instr16_06() { push16(sreg[ES]); } +static void instr32_06() { push32(sreg[ES]); } +static void instr16_07() { + switch_seg(ES, safe_read16(get_stack_pointer(0))); + adjust_stack_reg(2); +} +static void instr32_07() { + switch_seg(ES, safe_read32s(get_stack_pointer(0)) & 0xFFFF); + adjust_stack_reg(4); +} + +static void instr_08() { read_modrm_byte(); write_e8(or8(read_write_e8(), read_g8())); } +static void instr16_09() { read_modrm_byte(); write_e16(or16(read_write_e16(), read_g16())); } +static void instr32_09() { read_modrm_byte(); write_e32(or32(read_write_e32(), read_g32s())); } +static void instr_0A() { read_modrm_byte(); write_g8(or8(read_g8(), read_e8())); } +static void instr16_0B() { read_modrm_byte(); write_g16(or16(read_g16(), read_e16())); } +static void instr32_0B() { read_modrm_byte(); write_g32(or32(read_g32s(), read_e32s())); } +static void instr_0C() { reg8[AL] = or8(reg8[AL], read_op8()); } +static void instr16_0D() { reg16[AX] = or16(reg16[AX], read_op16()); } +static void instr32_0D() { reg32s[EAX] = or32(reg32s[EAX], read_op32s()); } + + +static void instr16_0E() { push16(sreg[CS]); } +static void instr32_0E() { push32(sreg[CS]); } +static void instr16_0F() { + run_instruction0f_16(read_imm8()); +} +static void instr32_0F() { + run_instruction0f_32(read_imm8()); +} + +static void instr_10() { read_modrm_byte(); write_e8(adc8(read_write_e8(), read_g8())); } +static void instr16_11() { read_modrm_byte(); write_e16(adc16(read_write_e16(), read_g16())); } +static void instr32_11() { read_modrm_byte(); write_e32(adc32(read_write_e32(), read_g32s())); } +static void instr_12() { read_modrm_byte(); write_g8(adc8(read_g8(), read_e8())); } +static void instr16_13() { read_modrm_byte(); write_g16(adc16(read_g16(), read_e16())); } +static void instr32_13() { read_modrm_byte(); write_g32(adc32(read_g32s(), read_e32s())); } +static void instr_14() { reg8[AL] = adc8(reg8[AL], read_op8()); } +static void instr16_15() { reg16[AX] = adc16(reg16[AX], read_op16()); } +static void instr32_15() { reg32s[EAX] = adc32(reg32s[EAX], read_op32s()); } + +static void instr16_16() { push16(sreg[SS]); } +static void instr32_16() { push32(sreg[SS]); } +static void instr16_17() { + switch_seg(SS, safe_read16(get_stack_pointer(0))); + adjust_stack_reg(2); + clear_prefixes(); + cycle_internal(); +} +static void instr32_17() { + switch_seg(SS, safe_read32s(get_stack_pointer(0)) & 0xFFFF); + adjust_stack_reg(4); + clear_prefixes(); + cycle_internal(); +} + +static void instr_18() { read_modrm_byte(); write_e8(sbb8(read_write_e8(), read_g8())); } +static void instr16_19() { read_modrm_byte(); write_e16(sbb16(read_write_e16(), read_g16())); } +static void instr32_19() { read_modrm_byte(); write_e32(sbb32(read_write_e32(), read_g32s())); } +static void instr_1A() { read_modrm_byte(); write_g8(sbb8(read_g8(), read_e8())); } +static void instr16_1B() { read_modrm_byte(); write_g16(sbb16(read_g16(), read_e16())); } +static void instr32_1B() { read_modrm_byte(); write_g32(sbb32(read_g32s(), read_e32s())); } +static void instr_1C() { reg8[AL] = sbb8(reg8[AL], read_op8()); } +static void instr16_1D() { reg16[AX] = sbb16(reg16[AX], read_op16()); } +static void instr32_1D() { reg32s[EAX] = sbb32(reg32s[EAX], read_op32s()); } + + +static void instr16_1E() { push16(sreg[DS]); } +static void instr32_1E() { push32(sreg[DS]); } +static void instr16_1F() { + switch_seg(DS, safe_read16(get_stack_pointer(0))); + adjust_stack_reg(2); +} +static void instr32_1F() { + switch_seg(DS, safe_read32s(get_stack_pointer(0)) & 0xFFFF); + adjust_stack_reg(4); +} + +static void instr_20() { read_modrm_byte(); write_e8(and8(read_write_e8(), read_g8())); } +static void instr16_21() { read_modrm_byte(); write_e16(and16(read_write_e16(), read_g16())); } +static void instr32_21() { read_modrm_byte(); write_e32(and32(read_write_e32(), read_g32s())); } +static void instr_22() { read_modrm_byte(); write_g8(and8(read_g8(), read_e8())); } +static void instr16_23() { read_modrm_byte(); write_g16(and16(read_g16(), read_e16())); } +static void instr32_23() { read_modrm_byte(); write_g32(and32(read_g32s(), read_e32s())); } +static void instr_24() { reg8[AL] = and8(reg8[AL], read_op8()); } +static void instr16_25() { reg16[AX] = and16(reg16[AX], read_op16()); } +static void instr32_25() { reg32s[EAX] = and32(reg32s[EAX], read_op32s()); } + + +static void instr_26() { segment_prefix_op(ES); } +static void instr_27() { bcd_daa(); } + +static void instr_28() { read_modrm_byte(); write_e8(sub8(read_write_e8(), read_g8())); } +static void instr16_29() { read_modrm_byte(); write_e16(sub16(read_write_e16(), read_g16())); } +static void instr32_29() { read_modrm_byte(); write_e32(sub32(read_write_e32(), read_g32s())); } +static void instr_2A() { read_modrm_byte(); write_g8(sub8(read_g8(), read_e8())); } +static void instr16_2B() { read_modrm_byte(); write_g16(sub16(read_g16(), read_e16())); } +static void instr32_2B() { read_modrm_byte(); write_g32(sub32(read_g32s(), read_e32s())); } +static void instr_2C() { reg8[AL] = sub8(reg8[AL], read_op8()); } +static void instr16_2D() { reg16[AX] = sub16(reg16[AX], read_op16()); } +static void instr32_2D() { reg32s[EAX] = sub32(reg32s[EAX], read_op32s()); } + +static void instr_2E() { segment_prefix_op(CS); } +static void instr_2F() { bcd_das(); } + +static void instr_30() { read_modrm_byte(); write_e8(xor8(read_write_e8(), read_g8())); } +static void instr16_31() { read_modrm_byte(); write_e16(xor16(read_write_e16(), read_g16())); } +static void instr32_31() { read_modrm_byte(); write_e32(xor32(read_write_e32(), read_g32s())); } +static void instr_32() { read_modrm_byte(); write_g8(xor8(read_g8(), read_e8())); } +static void instr16_33() { read_modrm_byte(); write_g16(xor16(read_g16(), read_e16())); } +static void instr32_33() { read_modrm_byte(); write_g32(xor32(read_g32s(), read_e32s())); } +static void instr_34() { reg8[AL] = xor8(reg8[AL], read_op8()); } +static void instr16_35() { reg16[AX] = xor16(reg16[AX], read_op16()); } +static void instr32_35() { reg32s[EAX] = xor32(reg32s[EAX], read_op32s()); } + +static void instr_36() { segment_prefix_op(SS); } +static void instr_37() { bcd_aaa(); } + +static void instr_38() { read_modrm_byte(); cmp8(read_e8(), read_g8()); } +static void instr16_39() { read_modrm_byte(); cmp16(read_e16(), read_g16()); } +static void instr32_39() { read_modrm_byte(); cmp32(read_e32s(), read_g32s()); } +static void instr_3A() { read_modrm_byte(); cmp8(read_g8(), read_e8()); } +static void instr16_3B() { read_modrm_byte(); cmp16(read_g16(), read_e16()); } +static void instr32_3B() { read_modrm_byte(); cmp32(read_g32s(), read_e32s()); } +static void instr_3C() { cmp8(reg8[AL], read_op8()); } +static void instr16_3D() { cmp16(reg16[AX], read_op16()); } +static void instr32_3D() { cmp32(reg32s[EAX], read_op32s()); } + +static void instr_3E() { segment_prefix_op(DS); } +static void instr_3F() { bcd_aas(); } + + +static void instr16_40() { reg16[AX] = inc16(reg16[AX]); } +static void instr32_40() { reg32s[EAX] = inc32(reg32s[EAX]); } +static void instr16_41() { reg16[CX] = inc16(reg16[CX]); } +static void instr32_41() { reg32s[ECX] = inc32(reg32s[ECX]); } +static void instr16_42() { reg16[DX] = inc16(reg16[DX]); } +static void instr32_42() { reg32s[EDX] = inc32(reg32s[EDX]); } +static void instr16_43() { reg16[BX] = inc16(reg16[BX]); } +static void instr32_43() { reg32s[EBX] = inc32(reg32s[EBX]); } +static void instr16_44() { reg16[SP] = inc16(reg16[SP]); } +static void instr32_44() { reg32s[ESP] = inc32(reg32s[ESP]); } +static void instr16_45() { reg16[BP] = inc16(reg16[BP]); } +static void instr32_45() { reg32s[EBP] = inc32(reg32s[EBP]); } +static void instr16_46() { reg16[SI] = inc16(reg16[SI]); } +static void instr32_46() { reg32s[ESI] = inc32(reg32s[ESI]); } +static void instr16_47() { reg16[DI] = inc16(reg16[DI]); } +static void instr32_47() { reg32s[EDI] = inc32(reg32s[EDI]); } + + +static void instr16_48() { reg16[AX] = dec16(reg16[AX]); } +static void instr32_48() { reg32s[EAX] = dec32(reg32s[EAX]); } +static void instr16_49() { reg16[CX] = dec16(reg16[CX]); } +static void instr32_49() { reg32s[ECX] = dec32(reg32s[ECX]); } +static void instr16_4A() { reg16[DX] = dec16(reg16[DX]); } +static void instr32_4A() { reg32s[EDX] = dec32(reg32s[EDX]); } +static void instr16_4B() { reg16[BX] = dec16(reg16[BX]); } +static void instr32_4B() { reg32s[EBX] = dec32(reg32s[EBX]); } +static void instr16_4C() { reg16[SP] = dec16(reg16[SP]); } +static void instr32_4C() { reg32s[ESP] = dec32(reg32s[ESP]); } +static void instr16_4D() { reg16[BP] = dec16(reg16[BP]); } +static void instr32_4D() { reg32s[EBP] = dec32(reg32s[EBP]); } +static void instr16_4E() { reg16[SI] = dec16(reg16[SI]); } +static void instr32_4E() { reg32s[ESI] = dec32(reg32s[ESI]); } +static void instr16_4F() { reg16[DI] = dec16(reg16[DI]); } +static void instr32_4F() { reg32s[EDI] = dec32(reg32s[EDI]); } + + +static void instr16_50() { push16(reg16[AX]); } +static void instr32_50() { push32(reg32s[EAX]); } +static void instr16_51() { push16(reg16[CX]); } +static void instr32_51() { push32(reg32s[ECX]); } +static void instr16_52() { push16(reg16[DX]); } +static void instr32_52() { push32(reg32s[EDX]); } +static void instr16_53() { push16(reg16[BX]); } +static void instr32_53() { push32(reg32s[EBX]); } +static void instr16_54() { push16(reg16[SP]); } +static void instr32_54() { push32(reg32s[ESP]); } +static void instr16_55() { push16(reg16[BP]); } +static void instr32_55() { push32(reg32s[EBP]); } +static void instr16_56() { push16(reg16[SI]); } +static void instr32_56() { push32(reg32s[ESI]); } +static void instr16_57() { push16(reg16[DI]); } +static void instr32_57() { push32(reg32s[EDI]); } + +static void instr16_58() { reg16[AX] = pop16(); } +static void instr32_58() { reg32s[EAX] = pop32s(); } +static void instr16_59() { reg16[CX] = pop16(); } +static void instr32_59() { reg32s[ECX] = pop32s(); } +static void instr16_5A() { reg16[DX] = pop16(); } +static void instr32_5A() { reg32s[EDX] = pop32s(); } +static void instr16_5B() { reg16[BX] = pop16(); } +static void instr32_5B() { reg32s[EBX] = pop32s(); } +static void instr16_5C() { reg16[SP] = pop16(); } +static void instr32_5C() { reg32s[ESP] = pop32s(); } +static void instr16_5D() { reg16[BP] = pop16(); } +static void instr32_5D() { reg32s[EBP] = pop32s(); } +static void instr16_5E() { reg16[SI] = pop16(); } +static void instr32_5E() { reg32s[ESI] = pop32s(); } +static void instr16_5F() { reg16[DI] = pop16(); } +static void instr32_5F() { reg32s[EDI] = pop32s(); } + + +static void instr16_60() { pusha16(); } +static void instr32_60() { pusha32(); } +static void instr16_61() { popa16(); } +static void instr32_61() { popa32(); } + +static void instr_62() { + // bound + dbg_log("Unimplemented BOUND instruction"); + dbg_assert(false); +} +static void instr_63() { read_modrm_byte(); + // arpl + //dbg_log("arpl"); + if(*protected_mode && !vm86_mode()) + { + write_e16(arpl(read_write_e16(), modrm_byte[0] >> 2 & 14)); + } + else + { + dbg_log("arpl #ud"); + trigger_ud(); + } +} + +static void instr_64() { segment_prefix_op(FS); } +static void instr_65() { segment_prefix_op(GS); } + +static void instr_66() { + // Operand-size override prefix + *prefixes |= PREFIX_MASK_OPSIZE; + run_prefix_instruction(); + *prefixes = 0; +} + +static void instr_67() { + // Address-size override prefix + dbg_assert(is_asize_32() == *is_32); + + *prefixes |= PREFIX_MASK_ADDRSIZE; + run_prefix_instruction(); + *prefixes = 0; +} + +static void instr16_68() { push16(read_op16()); } +static void instr32_68() { push32(read_op32s()); } + +static void instr16_69() { read_modrm_byte(); + write_g16(imul_reg16(read_e16s(), read_op16() << 16 >> 16)); +} +static void instr32_69() { read_modrm_byte(); + write_g32(imul_reg32(read_e32s(), read_op32s())); +} + +static void instr16_6A() { push16(read_op8s()); } +static void instr32_6A() { push32(read_op8s()); } + +static void instr16_6B() { read_modrm_byte(); + write_g16(imul_reg16(read_e16s(), read_op8s())); +} +static void instr32_6B() { read_modrm_byte(); + write_g32(imul_reg32(read_e32s(), read_op8s())); +} + +static void instr_6C() { insb(); } +static void instr16_6D() { insw(); } +static void instr32_6D() { insd(); } +static void instr_6E() { outsb(); } +static void instr16_6F() { outsw(); } +static void instr32_6F() { outsd(); } + +static void instr_70() { jmpcc8( test_o()); } +static void instr_71() { jmpcc8(!test_o()); } +static void instr_72() { jmpcc8( test_b()); } +static void instr_73() { jmpcc8(!test_b()); } +static void instr_74() { jmpcc8( test_z()); } +static void instr_75() { jmpcc8(!test_z()); } +static void instr_76() { jmpcc8( test_be()); } +static void instr_77() { jmpcc8(!test_be()); } +static void instr_78() { jmpcc8( test_s()); } +static void instr_79() { jmpcc8(!test_s()); } +static void instr_7A() { jmpcc8( test_p()); } +static void instr_7B() { jmpcc8(!test_p()); } +static void instr_7C() { jmpcc8( test_l()); } +static void instr_7D() { jmpcc8(!test_l()); } +static void instr_7E() { jmpcc8( test_le()); } +static void instr_7F() { jmpcc8(!test_le()); } + +static void instr_80() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 0: write_e8(add8(read_write_e8(), read_op8())); break; + case 1: write_e8( or8(read_write_e8(), read_op8())); break; + case 2: write_e8(adc8(read_write_e8(), read_op8())); break; + case 3: write_e8(sbb8(read_write_e8(), read_op8())); break; + case 4: write_e8(and8(read_write_e8(), read_op8())); break; + case 5: write_e8(sub8(read_write_e8(), read_op8())); break; + case 6: write_e8(xor8(read_write_e8(), read_op8())); break; + case 7: cmp8(read_e8(), read_op8()); break; + } +} +static void instr16_81() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 0: write_e16(add16(read_write_e16(), read_op16())); break; + case 1: write_e16( or16(read_write_e16(), read_op16())); break; + case 2: write_e16(adc16(read_write_e16(), read_op16())); break; + case 3: write_e16(sbb16(read_write_e16(), read_op16())); break; + case 4: write_e16(and16(read_write_e16(), read_op16())); break; + case 5: write_e16(sub16(read_write_e16(), read_op16())); break; + case 6: write_e16(xor16(read_write_e16(), read_op16())); break; + case 7: cmp16(read_e16(), read_op16()); break; + } +} +static void instr32_81() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 0: write_e32(add32(read_write_e32(), read_op32s())); break; + case 1: write_e32( or32(read_write_e32(), read_op32s())); break; + case 2: write_e32(adc32(read_write_e32(), read_op32s())); break; + case 3: write_e32(sbb32(read_write_e32(), read_op32s())); break; + case 4: write_e32(and32(read_write_e32(), read_op32s())); break; + case 5: write_e32(sub32(read_write_e32(), read_op32s())); break; + case 6: write_e32(xor32(read_write_e32(), read_op32s())); break; + case 7: cmp32(read_e32s(), read_op32s()); break; + } +} +static void instr_82() { instr_80(); } // alias +static void instr16_83() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 0: write_e16(add16(read_write_e16(), read_op8s())); break; + case 1: write_e16( or16(read_write_e16(), read_op8s())); break; + case 2: write_e16(adc16(read_write_e16(), read_op8s())); break; + case 3: write_e16(sbb16(read_write_e16(), read_op8s())); break; + case 4: write_e16(and16(read_write_e16(), read_op8s())); break; + case 5: write_e16(sub16(read_write_e16(), read_op8s())); break; + case 6: write_e16(xor16(read_write_e16(), read_op8s())); break; + case 7: cmp16(read_e16(), read_op8s()); break; + } +} +static void instr32_83() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 0: write_e32(add32(read_write_e32(), read_op8s())); break; + case 1: write_e32( or32(read_write_e32(), read_op8s())); break; + case 2: write_e32(adc32(read_write_e32(), read_op8s())); break; + case 3: write_e32(sbb32(read_write_e32(), read_op8s())); break; + case 4: write_e32(and32(read_write_e32(), read_op8s())); break; + case 5: write_e32(sub32(read_write_e32(), read_op8s())); break; + case 6: write_e32(xor32(read_write_e32(), read_op8s())); break; + case 7: cmp32(read_e32s(), read_op8s()); break; + } +} + +static void instr_84() { read_modrm_byte(); int32_t data = read_e8(); test8(data, read_g8()); } +static void instr16_85() { read_modrm_byte(); int32_t data = read_e16(); test16(data, read_g16()); } +static void instr32_85() { read_modrm_byte(); int32_t data = read_e32s(); test32(data, read_g32s()); } + + +static void instr_86() { read_modrm_byte(); int32_t data = read_write_e8(); write_e8(xchg8(data, modrm_byte[0])); } +static void instr16_87() { read_modrm_byte(); + int32_t data = read_write_e16(); write_e16(xchg16(data, modrm_byte[0])); +} +static void instr32_87() { read_modrm_byte(); + int32_t data = read_write_e32(); write_e32(xchg32(data, modrm_byte[0])); +} + +static void instr_88() { read_modrm_byte(); set_e8(read_g8()); } +static void instr16_89() { read_modrm_byte(); set_e16(read_g16()); } +static void instr32_89() { read_modrm_byte(); set_e32(read_g32s()); } + +static void instr_8A() { read_modrm_byte(); + int32_t data = read_e8(); + write_g8(data); +} +static void instr16_8B() { read_modrm_byte(); + int32_t data = read_e16(); + write_g16(data); +} +static void instr32_8B() { read_modrm_byte(); + int32_t data = read_e32s(); + write_g32(data); +} + +static void instr16_8C() { read_modrm_byte(); + set_e16(sreg[modrm_byte[0] >> 3 & 7]); +} +static void instr32_8C() { read_modrm_byte(); + set_e32(sreg[modrm_byte[0] >> 3 & 7]); +} + +static void instr16_8D() { read_modrm_byte(); + // lea + if(modrm_byte[0] >= 0xC0) + { + dbg_log("lea #ud"); + trigger_ud(); + } + int32_t mod = modrm_byte[0] >> 3 & 7; + + // override prefix, so modrm_resolve does not return the segment part + *prefixes |= SEG_PREFIX_ZERO; + reg16[mod << 1] = modrm_resolve(modrm_byte[0]); + *prefixes = 0; +} +static void instr32_8D() { read_modrm_byte(); + if(modrm_byte[0] >= 0xC0) + { + dbg_log("lea #ud"); + trigger_ud(); + } + int32_t mod = modrm_byte[0] >> 3 & 7; + + *prefixes |= SEG_PREFIX_ZERO; + reg32s[mod] = modrm_resolve(modrm_byte[0]); + *prefixes = 0; +} + +static void instr_8E() { read_modrm_byte(); + int32_t mod = modrm_byte[0] >> 3 & 7; + int32_t data = read_e16(); + switch_seg(mod, data); + + if(mod == SS) + { + // run next instruction, so no interrupts are handled + clear_prefixes(); + cycle_internal(); + } +} + +static void instr16_8F() { read_modrm_byte(); + // pop + int32_t sp = safe_read16(get_stack_pointer(0)); + + adjust_stack_reg(2); + + if(modrm_byte[0] < 0xC0) { + int32_t addr = modrm_resolve(modrm_byte[0]); + adjust_stack_reg(-2); + safe_write16(addr, sp); + adjust_stack_reg(2); + } else { + write_reg_e16(sp); + } +} +static void instr32_8F() { read_modrm_byte(); + int32_t sp = safe_read32s(get_stack_pointer(0)); + + // change esp first, then resolve modrm address + adjust_stack_reg(4); + + if(modrm_byte[0] < 0xC0) { + int32_t addr = modrm_resolve(modrm_byte[0]); + + // Before attempting a write that might cause a page fault, + // we must set esp to the old value. Fuck Intel. + adjust_stack_reg(-4); + safe_write32(addr, sp); + adjust_stack_reg(4); + } else { + write_reg_e32(sp); + } +} + +static void instr_90() { } +static void instr16_91() { xchg16r(CX); } +static void instr32_91() { xchg32r(ECX); } +static void instr16_92() { xchg16r(DX); } +static void instr32_92() { xchg32r(EDX); } +static void instr16_93() { xchg16r(BX); } +static void instr32_93() { xchg32r(EBX); } +static void instr16_94() { xchg16r(SP); } +static void instr32_94() { xchg32r(ESP); } +static void instr16_95() { xchg16r(BP); } +static void instr32_95() { xchg32r(EBP); } +static void instr16_96() { xchg16r(SI); } +static void instr32_96() { xchg32r(ESI); } +static void instr16_97() { xchg16r(DI); } +static void instr32_97() { xchg32r(EDI); } + +static void instr16_98() { /* cbw */ reg16[AX] = reg8s[AL]; } +static void instr32_98() { /* cwde */ reg32s[EAX] = reg16s[AX]; } +static void instr16_99() { /* cwd */ reg16[DX] = reg16s[AX] >> 15; } +static void instr32_99() { /* cdq */ reg32s[EDX] = reg32s[EAX] >> 31; } + +static void instr16_9A() { + // callf + int32_t new_ip = read_op16(); + int32_t new_cs = read_disp16(); + + far_jump(new_ip, new_cs, true); + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); +} +static void instr32_9A() { + int32_t new_ip = read_op32s(); + int32_t new_cs = read_disp16(); + + if(!*protected_mode || vm86_mode()) + { + if(new_ip & 0xFFFF0000) + { + assert(false); + //throw debug.unimpl("#GP handler"); + } + } + + far_jump(new_ip, new_cs, true); + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); +} + +static void instr_9B() { + // fwait: check for pending fpu exceptions + if((cr[0] & (CR0_MP | CR0_TS)) == (CR0_MP | CR0_TS)) + { + // task switched and MP bit is set + trigger_nm(); + } + else + { + //if(fpu) + { + fwait(); + } + //else + //{ + // // EM bit isn't checked + // // If there's no FPU, do nothing + //} + } +} +static void instr16_9C() { + // pushf + if((flags[0] & FLAG_VM) && getiopl() < 3) + { + dbg_assert(*protected_mode); + dbg_log("pushf #gp"); + trigger_gp(0); + } + else + { + push16(get_eflags()); + } +} +static void instr32_9C() { + // pushf + if((flags[0] & FLAG_VM) && getiopl() < 3) + { + // trap to virtual 8086 monitor + dbg_assert(*protected_mode); + dbg_log("pushf #gp"); + trigger_gp(0); + } + else + { + // vm and rf flag are cleared in image stored on the stack + push32(get_eflags() & 0x00FCFFFF); + } +} +static void instr16_9D() { + // popf + if((flags[0] & FLAG_VM) && getiopl() < 3) + { + dbg_log("popf #gp"); + trigger_gp(0); + } + + update_eflags((flags[0] & ~0xFFFF) | pop16()); + + if(flags[0] & FLAG_TRAP) + { + // XXX: Problems with fdgame + //clear_prefixes(); + //cycle_internal(); + flags[0] &= ~FLAG_TRAP; + //instruction_pointer = previous_ip; + //raise_exception(1); + } + else + { + handle_irqs(); + } +} +static void instr32_9D() { + // popf + if((flags[0] & FLAG_VM) && getiopl() < 3) + { + dbg_log("popf #gp"); + trigger_gp(0); + } + + update_eflags(pop32s()); + handle_irqs(); +} +static void instr_9E() { + // sahf + flags[0] = (flags[0] & ~0xFF) | reg8[AH]; + flags[0] = (flags[0] & FLAGS_MASK) | FLAGS_DEFAULT; + flags_changed[0] = 0; +} +static void instr_9F() { + // lahf + reg8[AH] = get_eflags(); +} + +static void instr_A0() { + // mov + int32_t data = safe_read8(read_moffs()); + reg8[AL] = data; +} +static void instr16_A1() { + // mov + int32_t data = safe_read16(read_moffs()); + reg16[AX] = data; +} +static void instr32_A1() { + int32_t data = safe_read32s(read_moffs()); + reg32s[EAX] = data; +} +static void instr_A2() { + // mov + safe_write8(read_moffs(), reg8[AL]); +} +static void instr16_A3() { + // mov + safe_write16(read_moffs(), reg16[AX]); +} +static void instr32_A3() { + safe_write32(read_moffs(), reg32s[EAX]); +} + +static void instr_A4() { movsb(); } +static void instr16_A5() { movsw(); } +static void instr32_A5() { movsd(); } +static void instr_A6() { cmpsb(); } +static void instr16_A7() { cmpsw(); } +static void instr32_A7() { cmpsd(); } + +static void instr_A8() { + test8(reg8[AL], read_op8()); +} +static void instr16_A9() { + test16(reg16[AX], read_op16()); +} +static void instr32_A9() { + test32(reg32s[EAX], read_op32s()); +} + +static void instr_AA() { stosb(); } +static void instr16_AB() { stosw(); } +static void instr32_AB() { stosd(); } +static void instr_AC() { lodsb(); } +static void instr16_AD() { lodsw(); } +static void instr32_AD() { lodsd(); } +static void instr_AE() { scasb(); } +static void instr16_AF() { scasw(); } +static void instr32_AF() { scasd(); } + + +static void instr_B0() { reg8[AL] = read_op8(); } +static void instr_B1() { reg8[CL] = read_op8(); } +static void instr_B2() { reg8[DL] = read_op8(); } +static void instr_B3() { reg8[BL] = read_op8(); } +static void instr_B4() { reg8[AH] = read_op8(); } +static void instr_B5() { reg8[CH] = read_op8(); } +static void instr_B6() { reg8[DH] = read_op8(); } +static void instr_B7() { reg8[BH] = read_op8(); } + +static void instr16_B8() { reg16[AX] = read_op16(); } +static void instr32_B8() { reg32s[EAX] = read_op32s(); } +static void instr16_B9() { reg16[CX] = read_op16(); } +static void instr32_B9() { reg32s[ECX] = read_op32s(); } +static void instr16_BA() { reg16[DX] = read_op16(); } +static void instr32_BA() { reg32s[EDX] = read_op32s(); } +static void instr16_BB() { reg16[BX] = read_op16(); } +static void instr32_BB() { reg32s[EBX] = read_op32s(); } +static void instr16_BC() { reg16[SP] = read_op16(); } +static void instr32_BC() { reg32s[ESP] = read_op32s(); } +static void instr16_BD() { reg16[BP] = read_op16(); } +static void instr32_BD() { reg32s[EBP] = read_op32s(); } +static void instr16_BE() { reg16[SI] = read_op16(); } +static void instr32_BE() { reg32s[ESI] = read_op32s(); } +static void instr16_BF() { reg16[DI] = read_op16(); } +static void instr32_BF() { reg32s[EDI] = read_op32s(); } + + +static void instr_C0() { read_modrm_byte(); + int32_t op1 = read_write_e8(); + int32_t op2 = read_op8() & 31; + int32_t result = 0; + switch(modrm_byte[0] >> 3 & 7) + { + case 0: result = rol8(op1, op2); break; + case 1: result = ror8(op1, op2); break; + case 2: result = rcl8(op1, op2); break; + case 3: result = rcr8(op1, op2); break; + case 4: result = shl8(op1, op2); break; + case 5: result = shr8(op1, op2); break; + case 6: result = shl8(op1, op2); break; + case 7: result = sar8(op1, op2); break; + } + write_e8(result); +} +static void instr16_C1() { read_modrm_byte(); + int32_t op1 = read_write_e16(); + int32_t op2 = read_op8() & 31; + int32_t result = 0; + switch(modrm_byte[0] >> 3 & 7) + { + case 0: result = rol16(op1, op2); break; + case 1: result = ror16(op1, op2); break; + case 2: result = rcl16(op1, op2); break; + case 3: result = rcr16(op1, op2); break; + case 4: result = shl16(op1, op2); break; + case 5: result = shr16(op1, op2); break; + case 6: result = shl16(op1, op2); break; + case 7: result = sar16(op1, op2); break; + } + write_e16(result); +} +static void instr32_C1() { read_modrm_byte(); + int32_t op1 = read_write_e32(); + int32_t op2 = read_op8() & 31; + int32_t result = 0; + switch(modrm_byte[0] >> 3 & 7) + { + case 0: result = rol32(op1, op2); break; + case 1: result = ror32(op1, op2); break; + case 2: result = rcl32(op1, op2); break; + case 3: result = rcr32(op1, op2); break; + case 4: result = shl32(op1, op2); break; + case 5: result = shr32(op1, op2); break; + case 6: result = shl32(op1, op2); break; + case 7: result = sar32(op1, op2); break; + } + write_e32(result); +} + +static void instr16_C2() { + // retn + int32_t imm16 = read_op16(); + + instruction_pointer[0] = get_seg(CS) + pop16(); + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + adjust_stack_reg(imm16); + diverged(); +} +static void instr32_C2() { + // retn + int32_t imm16 = read_op16(); + int32_t ip = pop32s(); + + dbg_assert(is_asize_32() || ip < 0x10000); + instruction_pointer[0] = get_seg(CS) + ip; + adjust_stack_reg(imm16); + diverged(); +} +static void instr16_C3() { + // retn + instruction_pointer[0] = get_seg(CS) + pop16(); + diverged(); +} +static void instr32_C3() { + // retn + int32_t ip = pop32s(); + dbg_assert(is_asize_32() || ip < 0x10000); + instruction_pointer[0] = get_seg(CS) + ip; + diverged(); +} + +static void instr16_C4() { read_modrm_byte(); + lss16(ES); +} +static void instr32_C4() { read_modrm_byte(); + lss32(ES); +} +static void instr16_C5() { read_modrm_byte(); + lss16(DS); +} +static void instr32_C5() { read_modrm_byte(); + lss32(DS); +} + +static void instr_C6() { read_modrm_byte(); + if(modrm_byte[0] < 0xC0) { + safe_write8(modrm_resolve(modrm_byte[0]), read_op8()); + } else { + reg8[modrm_byte[0] << 2 & 0xC | modrm_byte[0] >> 2 & 1] = read_op8(); + } +} +static void instr16_C7() { read_modrm_byte(); + if(modrm_byte[0] < 0xC0) { + safe_write16(modrm_resolve(modrm_byte[0]), read_op16()); + } else { + reg16[modrm_byte[0] << 1 & 14] = read_op16(); + } +} +static void instr32_C7() { read_modrm_byte(); + if(modrm_byte[0] < 0xC0) { + safe_write32(modrm_resolve(modrm_byte[0]), read_op32s()); + } else { + reg32s[modrm_byte[0] & 7] = read_op32s(); + } +} + +static void instr16_C8() { enter16(read_op16(), read_disp8()); } +static void instr32_C8() { enter32(read_op16(), read_disp8()); } +static void instr16_C9() { + // leave + int32_t old_vbp = *stack_size_32 ? reg32s[EBP] : reg16[BP]; + int32_t new_bp = safe_read16(get_seg(SS) + old_vbp); + set_stack_reg(old_vbp + 2); + reg16[BP] = new_bp; +} +static void instr32_C9() { + int32_t old_vbp = *stack_size_32 ? reg32s[EBP] : reg16[BP]; + int32_t new_ebp = safe_read32s(get_seg(SS) + old_vbp); + set_stack_reg(old_vbp + 4); + reg32s[EBP] = new_ebp; +} +static void instr16_CA() { + // retf + int32_t imm16 = read_op16(); + int32_t ip = safe_read16(get_stack_pointer(0)); + int32_t cs = safe_read16(get_stack_pointer(2)); + + far_return(ip, cs, imm16); + diverged(); +} +static void instr32_CA() { + // retf + int32_t imm16 = read_op16(); + int32_t ip = safe_read32s(get_stack_pointer(0)); + int32_t cs = safe_read32s(get_stack_pointer(4)) & 0xFFFF; + + far_return(ip, cs, imm16); + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); +} +static void instr16_CB() { + // retf + int32_t ip = safe_read16(get_stack_pointer(0)); + int32_t cs = safe_read16(get_stack_pointer(2)); + + far_return(ip, cs, 0); + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); +} +static void instr32_CB() { + // retf + int32_t ip = safe_read32s(get_stack_pointer(0)); + int32_t cs = safe_read32s(get_stack_pointer(4)) & 0xFFFF; + + far_return(ip, cs, 0); + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); +} + +static void instr_CC() { + // INT3 + // TODO: inhibit iopl checks + dbg_log("INT3"); + call_interrupt_vector(3, true, false, 0); + diverged(); +} +static void instr_CD() { + // INT + int32_t imm8 = read_op8(); + call_interrupt_vector(imm8, true, false, 0); + diverged(); +} +static void instr_CE() { + // INTO + dbg_log("INTO"); + if(getof()) + { + // TODO: inhibit iopl checks + call_interrupt_vector(4, true, false, 0); + } + diverged(); +} + +static void instr16_CF() { + // iret + iret16(); + diverged(); +} +static void instr32_CF() { + iret32(); + diverged(); +} + +static void instr_D0() { read_modrm_byte(); + int32_t op1 = read_write_e8(); + int32_t result = 0; + switch(modrm_byte[0] >> 3 & 7) + { + case 0: result = rol8(op1, 1); break; + case 1: result = ror8(op1, 1); break; + case 2: result = rcl8(op1, 1); break; + case 3: result = rcr8(op1, 1); break; + case 4: result = shl8(op1, 1); break; + case 5: result = shr8(op1, 1); break; + case 6: result = shl8(op1, 1); break; + case 7: result = sar8(op1, 1); break; + } + write_e8(result); +} +static void instr16_D1() { read_modrm_byte(); + int32_t op1 = read_write_e16(); + int32_t result = 0; + switch(modrm_byte[0] >> 3 & 7) + { + case 0: result = rol16(op1, 1); break; + case 1: result = ror16(op1, 1); break; + case 2: result = rcl16(op1, 1); break; + case 3: result = rcr16(op1, 1); break; + case 4: result = shl16(op1, 1); break; + case 5: result = shr16(op1, 1); break; + case 6: result = shl16(op1, 1); break; + case 7: result = sar16(op1, 1); break; + } + write_e16(result); +} +static void instr32_D1() { read_modrm_byte(); + int32_t op1 = read_write_e32(); + int32_t result = 0; + switch(modrm_byte[0] >> 3 & 7) + { + case 0: result = rol32(op1, 1); break; + case 1: result = ror32(op1, 1); break; + case 2: result = rcl32(op1, 1); break; + case 3: result = rcr32(op1, 1); break; + case 4: result = shl32(op1, 1); break; + case 5: result = shr32(op1, 1); break; + case 6: result = shl32(op1, 1); break; + case 7: result = sar32(op1, 1); break; + } + write_e32(result); +} + +static void instr_D2() { read_modrm_byte(); + int32_t op1 = read_write_e8(); + int32_t op2 = reg8[CL] & 31; + int32_t result = 0; + switch(modrm_byte[0] >> 3 & 7) + { + case 0: result = rol8(op1, op2); break; + case 1: result = ror8(op1, op2); break; + case 2: result = rcl8(op1, op2); break; + case 3: result = rcr8(op1, op2); break; + case 4: result = shl8(op1, op2); break; + case 5: result = shr8(op1, op2); break; + case 6: result = shl8(op1, op2); break; + case 7: result = sar8(op1, op2); break; + } + write_e8(result); +} +static void instr16_D3() { read_modrm_byte(); + int32_t op1 = read_write_e16(); + int32_t op2 = reg8[CL] & 31; + int32_t result = 0; + switch(modrm_byte[0] >> 3 & 7) + { + case 0: result = rol16(op1, op2); break; + case 1: result = ror16(op1, op2); break; + case 2: result = rcl16(op1, op2); break; + case 3: result = rcr16(op1, op2); break; + case 4: result = shl16(op1, op2); break; + case 5: result = shr16(op1, op2); break; + case 6: result = shl16(op1, op2); break; + case 7: result = sar16(op1, op2); break; + } + write_e16(result); +} +static void instr32_D3() { read_modrm_byte(); + int32_t op1 = read_write_e32(); + int32_t op2 = reg8[CL] & 31; + int32_t result = 0; + switch(modrm_byte[0] >> 3 & 7) + { + case 0: result = rol32(op1, op2); break; + case 1: result = ror32(op1, op2); break; + case 2: result = rcl32(op1, op2); break; + case 3: result = rcr32(op1, op2); break; + case 4: result = shl32(op1, op2); break; + case 5: result = shr32(op1, op2); break; + case 6: result = shl32(op1, op2); break; + case 7: result = sar32(op1, op2); break; + } + write_e32(result); +} + +static void instr_D4() { + bcd_aam(read_op8()); +} +static void instr_D5() { + bcd_aad(read_op8()); +} + +static void instr_D6() { + // salc + reg8[AL] = -getcf(); +} +static void instr_D7() { + // xlat + if(is_asize_32()) + { + reg8[AL] = safe_read8(get_seg_prefix(DS) + reg32s[EBX] + reg8[AL]); + } + else + { + reg8[AL] = safe_read8(get_seg_prefix(DS) + (reg16[BX] + reg8[AL] & 0xFFFF)); + } +} + +static void instr_D8() { read_modrm_byte(); + task_switch_test(); + if(modrm_byte[0] < 0xC0) + fpu_op_D8_mem(modrm_byte[0], modrm_resolve(modrm_byte[0])); + else + fpu_op_D8_reg(modrm_byte[0]); +} +static void instr_D9() { read_modrm_byte(); + task_switch_test(); + if(modrm_byte[0] < 0xC0) + fpu_op_D9_mem(modrm_byte[0], modrm_resolve(modrm_byte[0])); + else + fpu_op_D9_reg(modrm_byte[0]); +} +static void instr_DA() { read_modrm_byte(); + task_switch_test(); + if(modrm_byte[0] < 0xC0) + fpu_op_DA_mem(modrm_byte[0], modrm_resolve(modrm_byte[0])); + else + fpu_op_DA_reg(modrm_byte[0]); +} +static void instr_DB() { read_modrm_byte(); + task_switch_test(); + if(modrm_byte[0] < 0xC0) + fpu_op_DB_mem(modrm_byte[0], modrm_resolve(modrm_byte[0])); + else + fpu_op_DB_reg(modrm_byte[0]); +} +static void instr_DC() { read_modrm_byte(); + task_switch_test(); + if(modrm_byte[0] < 0xC0) + fpu_op_DC_mem(modrm_byte[0], modrm_resolve(modrm_byte[0])); + else + fpu_op_DC_reg(modrm_byte[0]); +} +static void instr_DD() { read_modrm_byte(); + task_switch_test(); + if(modrm_byte[0] < 0xC0) + fpu_op_DD_mem(modrm_byte[0], modrm_resolve(modrm_byte[0])); + else + fpu_op_DD_reg(modrm_byte[0]); +} +static void instr_DE() { read_modrm_byte(); + task_switch_test(); + if(modrm_byte[0] < 0xC0) + fpu_op_DE_mem(modrm_byte[0], modrm_resolve(modrm_byte[0])); + else + fpu_op_DE_reg(modrm_byte[0]); +} +static void instr_DF() { read_modrm_byte(); + task_switch_test(); + if(modrm_byte[0] < 0xC0) + fpu_op_DF_mem(modrm_byte[0], modrm_resolve(modrm_byte[0])); + else + fpu_op_DF_reg(modrm_byte[0]); +} + +static void instr_E0() { loopne(read_op8s()); } +static void instr_E1() { loope(read_op8s()); } +static void instr_E2() { loop(read_op8s()); } +static void instr_E3() { jcxz(read_op8s()); } + +static void instr_E4() { + int32_t port = read_op8(); + test_privileges_for_io(port, 1); + reg8[AL] = io_port_read8(port); + diverged(); +} +static void instr16_E5() { + int32_t port = read_op8(); + test_privileges_for_io(port, 2); + reg16[AX] = io_port_read16(port); + diverged(); +} +static void instr32_E5() { + int32_t port = read_op8(); + test_privileges_for_io(port, 4); + reg32s[EAX] = io_port_read32(port); + diverged(); +} +static void instr_E6() { + int32_t port = read_op8(); + test_privileges_for_io(port, 1); + io_port_write8(port, reg8[AL]); + diverged(); +} +static void instr16_E7() { + int32_t port = read_op8(); + test_privileges_for_io(port, 2); + io_port_write16(port, reg16[AX]); + diverged(); +} +static void instr32_E7() { + int32_t port = read_op8(); + test_privileges_for_io(port, 4); + io_port_write32(port, reg32s[EAX]); + diverged(); +} + +static void instr16_E8() { + // call + int32_t imm16 = read_op16(); + push16(get_real_eip()); + + jmp_rel16(imm16); + diverged(); +} +static void instr32_E8() { + // call + int32_t imm32s = read_op32s(); + push32(get_real_eip()); + + instruction_pointer[0] = instruction_pointer[0] + imm32s; + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); +} +static void instr16_E9() { + // jmp + int32_t imm16 = read_op16(); + jmp_rel16(imm16); + diverged(); +} +static void instr32_E9() { + // jmp + int32_t imm32s = read_op32s(); + instruction_pointer[0] = instruction_pointer[0] + imm32s; + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); +} +static void instr16_EA() { + // jmpf + int32_t ip = read_op16(); + int32_t cs = read_disp16(); + far_jump(ip, cs, false); + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); +} +static void instr32_EA() { + // jmpf + int32_t new_ip = read_op32s(); + int32_t cs = read_disp16(); + far_jump(new_ip, cs, false); + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); +} +static void instr_EB() { + // jmp near + int32_t imm8 = read_op8s(); + instruction_pointer[0] = instruction_pointer[0] + imm8; + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); +} + +static void instr_EC() { + int32_t port = reg16[DX]; + test_privileges_for_io(port, 1); + reg8[AL] = io_port_read8(port); + diverged(); +} +static void instr16_ED() { + int32_t port = reg16[DX]; + test_privileges_for_io(port, 2); + reg16[AX] = io_port_read16(port); + diverged(); +} +static void instr32_ED() { + int32_t port = reg16[DX]; + test_privileges_for_io(port, 4); + reg32s[EAX] = io_port_read32(port); + diverged(); +} +static void instr_EE() { + int32_t port = reg16[DX]; + test_privileges_for_io(port, 1); + io_port_write8(port, reg8[AL]); + diverged(); +} +static void instr16_EF() { + int32_t port = reg16[DX]; + test_privileges_for_io(port, 2); + io_port_write16(port, reg16[AX]); + diverged(); +} +static void instr32_EF() { + int32_t port = reg16[DX]; + test_privileges_for_io(port, 4); + io_port_write32(port, reg32s[EAX]); + diverged(); +} + +static void instr_F0() { + // lock + //dbg_log("lock"); + + // TODO + // This triggers UD when used with + // some instructions that don't write to memory + run_prefix_instruction(); +} +static void instr_F1() { + // INT1 + // https://code.google.com/p/corkami/wiki/x86oddities#IceBP + //throw debug.unimpl("int1 instruction"); + assert(false); +} + +static void instr_F2() { + // repnz + dbg_assert((*prefixes & PREFIX_MASK_REP) == 0); + *prefixes |= PREFIX_REPNZ; + run_prefix_instruction(); + *prefixes = 0; +} +static void instr_F3() { + // repz + dbg_assert((*prefixes & PREFIX_MASK_REP) == 0); + *prefixes |= PREFIX_REPZ; + run_prefix_instruction(); + *prefixes = 0; +} + +static void instr_F4() { + hlt_op(); +} + +static void instr_F5() { + // cmc + flags[0] = (flags[0] | 1) ^ getcf(); + flags_changed[0] &= ~1; +} + +static void instr_F6() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 0: + test8(read_e8(), read_op8()); + break; + case 1: + test8(read_e8(), read_op8()); + break; + case 2: + write_e8(~(read_write_e8())); + break; + case 3: + write_e8(neg8(read_write_e8())); + break; + case 4: + mul8(read_e8()); + break; + case 5: + imul8(read_e8s()); + break; + case 6: + div8(read_e8()); + break; + case 7: + idiv8(read_e8s()); + break; + } +} + +static void instr16_F7() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 0: + test16(read_e16(), read_op16()); + break; + case 1: + test16(read_e16(), read_op16()); + break; + case 2: + write_e16(~(read_write_e16())); + break; + case 3: + write_e16(neg16(read_write_e16())); + break; + case 4: + mul16(read_e16()); + break; + case 5: + imul16(read_e16s()); + break; + case 6: + div16(read_e16()); + break; + case 7: + idiv16(read_e16s()); + break; + } +} +static void instr32_F7() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 0: + test32(read_e32s(), read_op32s()); + break; + case 1: + test32(read_e32s(), read_op32s()); + break; + case 2: + write_e32(~(read_write_e32())); + break; + case 3: + write_e32(neg32(read_write_e32())); + break; + case 4: + mul32(read_e32s()); + break; + case 5: + imul32(read_e32s()); + break; + case 6: + div32(read_e32s()); + break; + case 7: + idiv32(read_e32s()); + break; + } +} + +static void instr_F8() { + // clc + flags[0] &= ~FLAG_CARRY; + flags_changed[0] &= ~1; +} +static void instr_F9() { + // stc + flags[0] |= FLAG_CARRY; + flags_changed[0] &= ~1; +} + +static void instr_FA() { + // cli + //dbg_log("interrupts off"); + + if(!*protected_mode || ((flags[0] & FLAG_VM) ? + getiopl() == 3 : getiopl() >= *cpl)) + { + flags[0] &= ~FLAG_INTERRUPT; + } + else + { + //if(getiopl() < 3 && ((flags & FLAG_VM) ? + // (cr[4] & CR4_VME) : + // (*cpl == 3 && (cr[4] & CR4_PVI)))) + //{ + // flags &= ~flag_vif; + //} + //else + { + dbg_log("cli #gp"); + trigger_gp(0); + } + } +} +static void instr_FB() { + // sti + //dbg_log("interrupts on"); + + if(!*protected_mode || ((flags[0] & FLAG_VM) ? + getiopl() == 3 : getiopl() >= *cpl)) + { + flags[0] |= FLAG_INTERRUPT; + + clear_prefixes(); + cycle_internal(); + + handle_irqs(); + } + else + { + //if(getiopl() < 3 && (flags & flag_vip) == 0 && ((flags & FLAG_VM) ? + // (cr[4] & CR4_VME) : + // (cpl == 3 && (cr[4] & CR4_PVI)))) + //{ + // flags |= flag_vif; + //} + //else + { + dbg_log("sti #gp"); + trigger_gp(0); + } + } + +} + +static void instr_FC() { + // cld + flags[0] &= ~FLAG_DIRECTION; +} +static void instr_FD() { + // std + flags[0] |= FLAG_DIRECTION; +} + +static void instr_FE() { read_modrm_byte(); + int32_t mod = modrm_byte[0] & 56; + + if(mod == 0) + { + int32_t data = read_write_e8(); write_e8(inc8(data)); + } + else if(mod == 8) + { + int32_t data = read_write_e8(); write_e8(dec8(data)); + } + else + { + assert(false); + } +} +static void instr16_FF() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 0: + write_e16(inc16(read_write_e16())); + break; + case 1: + write_e16(dec16(read_write_e16())); + break; + case 2: + // 2, call near + { + int32_t data = read_e16(); + push16(get_real_eip()); + instruction_pointer[0] = get_seg(CS) + data; + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); + } + break; + case 3: + // 3, callf + { + if(modrm_byte[0] >= 0xC0) + { + dbg_log("callf #ud"); + trigger_ud(); + dbg_assert_message(false, "unreachable"); + } + + int32_t virt_addr = modrm_resolve(modrm_byte[0]); + int32_t new_ip = safe_read16(virt_addr); + int32_t new_cs = safe_read16(virt_addr + 2); + + far_jump(new_ip, new_cs, true); + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); + } + break; + case 4: + // 4, jmp near + { + int32_t data = read_e16(); + instruction_pointer[0] = get_seg(CS) + data; + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); + } + break; + case 5: + // 5, jmpf + { + if(modrm_byte[0] >= 0xC0) + { + dbg_log("jmpf #ud"); + trigger_ud(); + dbg_assert_message(false, "unreachable"); + } + + int32_t virt_addr = modrm_resolve(modrm_byte[0]); + int32_t new_ip = safe_read16(virt_addr); + int32_t new_cs = safe_read16(virt_addr + 2); + + far_jump(new_ip, new_cs, false); + dbg_assert(is_asize_32() || get_real_eip() < 0x10000); + diverged(); + } + break; + case 6: + // 6, push + push16(read_e16()); + break; + case 7: + assert(false); + } +} +static void instr32_FF() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 0: + write_e32(inc32(read_write_e32())); + break; + case 1: + write_e32(dec32(read_write_e32())); + break; + case 2: + // 2, call near + { + int32_t data = read_e32s(); + push32(get_real_eip()); + + dbg_assert(is_asize_32() || data < 0x10000); + instruction_pointer[0] = get_seg(CS) + data; + diverged(); + } + break; + case 3: + // 3, callf + { + if(modrm_byte[0] >= 0xC0) + { + dbg_log("callf #ud"); + trigger_ud(); + dbg_assert_message(false, "unreachable"); + } + + int32_t virt_addr = modrm_resolve(modrm_byte[0]); + int32_t new_ip = safe_read32s(virt_addr); + int32_t new_cs = safe_read16(virt_addr + 4); + + if(!*protected_mode || vm86_mode()) + { + if(new_ip & 0xFFFF0000) + { + //throw debug.unimpl("#GP handler"); + assert(false); + } + } + + far_jump(new_ip, new_cs, true); + dbg_assert(is_asize_32() || new_ip < 0x10000); + diverged(); + } + break; + case 4: + // 4, jmp near + { + int32_t data = read_e32s(); + dbg_assert(is_asize_32() || data < 0x10000); + instruction_pointer[0] = get_seg(CS) + data; + diverged(); + } + break; + case 5: + // 5, jmpf + { + if(modrm_byte[0] >= 0xC0) + { + dbg_log("jmpf #ud"); + trigger_ud(); + dbg_assert_message(false, "unreachable"); + } + + int32_t virt_addr = modrm_resolve(modrm_byte[0]); + int32_t new_ip = safe_read32s(virt_addr); + int32_t new_cs = safe_read16(virt_addr + 4); + + if(!*protected_mode || vm86_mode()) + { + if(new_ip & 0xFFFF0000) + { + //throw debug.unimpl("#GP handler"); + assert(false); + } + } + + far_jump(new_ip, new_cs, false); + dbg_assert(is_asize_32() || new_ip < 0x10000); + diverged(); + } + break; + case 6: + // push + push32(read_e32s()); + break; + case 7: + assert(false); + } +} + +static void run_instruction(int32_t opcode) +{ + //dbg_log(opcode); + // XXX: This table is generated. Don't modify + switch(opcode | is_osize_32() << 8) + { +case 0x00: +case 0x00|0x100: + instr_00(); + break; +case 0x01: + instr16_01(); + break; +case 0x01|0x100: + instr32_01(); + break; +case 0x02: +case 0x02|0x100: + instr_02(); + break; +case 0x03: + instr16_03(); + break; +case 0x03|0x100: + instr32_03(); + break; +case 0x04: +case 0x04|0x100: + instr_04(); + break; +case 0x05: + instr16_05(); + break; +case 0x05|0x100: + instr32_05(); + break; +case 0x06: + instr16_06(); + break; +case 0x06|0x100: + instr32_06(); + break; +case 0x07: + instr16_07(); + break; +case 0x07|0x100: + instr32_07(); + break; +case 0x08: +case 0x08|0x100: + instr_08(); + break; +case 0x09: + instr16_09(); + break; +case 0x09|0x100: + instr32_09(); + break; +case 0x0A: +case 0x0A|0x100: + instr_0A(); + break; +case 0x0B: + instr16_0B(); + break; +case 0x0B|0x100: + instr32_0B(); + break; +case 0x0C: +case 0x0C|0x100: + instr_0C(); + break; +case 0x0D: + instr16_0D(); + break; +case 0x0D|0x100: + instr32_0D(); + break; +case 0x0E: + instr16_0E(); + break; +case 0x0E|0x100: + instr32_0E(); + break; +case 0x0F: + instr16_0F(); + break; +case 0x0F|0x100: + instr32_0F(); + break; +case 0x10: +case 0x10|0x100: + instr_10(); + break; +case 0x11: + instr16_11(); + break; +case 0x11|0x100: + instr32_11(); + break; +case 0x12: +case 0x12|0x100: + instr_12(); + break; +case 0x13: + instr16_13(); + break; +case 0x13|0x100: + instr32_13(); + break; +case 0x14: +case 0x14|0x100: + instr_14(); + break; +case 0x15: + instr16_15(); + break; +case 0x15|0x100: + instr32_15(); + break; +case 0x16: + instr16_16(); + break; +case 0x16|0x100: + instr32_16(); + break; +case 0x17: + instr16_17(); + break; +case 0x17|0x100: + instr32_17(); + break; +case 0x18: +case 0x18|0x100: + instr_18(); + break; +case 0x19: + instr16_19(); + break; +case 0x19|0x100: + instr32_19(); + break; +case 0x1A: +case 0x1A|0x100: + instr_1A(); + break; +case 0x1B: + instr16_1B(); + break; +case 0x1B|0x100: + instr32_1B(); + break; +case 0x1C: +case 0x1C|0x100: + instr_1C(); + break; +case 0x1D: + instr16_1D(); + break; +case 0x1D|0x100: + instr32_1D(); + break; +case 0x1E: + instr16_1E(); + break; +case 0x1E|0x100: + instr32_1E(); + break; +case 0x1F: + instr16_1F(); + break; +case 0x1F|0x100: + instr32_1F(); + break; +case 0x20: +case 0x20|0x100: + instr_20(); + break; +case 0x21: + instr16_21(); + break; +case 0x21|0x100: + instr32_21(); + break; +case 0x22: +case 0x22|0x100: + instr_22(); + break; +case 0x23: + instr16_23(); + break; +case 0x23|0x100: + instr32_23(); + break; +case 0x24: +case 0x24|0x100: + instr_24(); + break; +case 0x25: + instr16_25(); + break; +case 0x25|0x100: + instr32_25(); + break; +case 0x26: +case 0x26|0x100: + instr_26(); + break; +case 0x27: +case 0x27|0x100: + instr_27(); + break; +case 0x28: +case 0x28|0x100: + instr_28(); + break; +case 0x29: + instr16_29(); + break; +case 0x29|0x100: + instr32_29(); + break; +case 0x2A: +case 0x2A|0x100: + instr_2A(); + break; +case 0x2B: + instr16_2B(); + break; +case 0x2B|0x100: + instr32_2B(); + break; +case 0x2C: +case 0x2C|0x100: + instr_2C(); + break; +case 0x2D: + instr16_2D(); + break; +case 0x2D|0x100: + instr32_2D(); + break; +case 0x2E: +case 0x2E|0x100: + instr_2E(); + break; +case 0x2F: +case 0x2F|0x100: + instr_2F(); + break; +case 0x30: +case 0x30|0x100: + instr_30(); + break; +case 0x31: + instr16_31(); + break; +case 0x31|0x100: + instr32_31(); + break; +case 0x32: +case 0x32|0x100: + instr_32(); + break; +case 0x33: + instr16_33(); + break; +case 0x33|0x100: + instr32_33(); + break; +case 0x34: +case 0x34|0x100: + instr_34(); + break; +case 0x35: + instr16_35(); + break; +case 0x35|0x100: + instr32_35(); + break; +case 0x36: +case 0x36|0x100: + instr_36(); + break; +case 0x37: +case 0x37|0x100: + instr_37(); + break; +case 0x38: +case 0x38|0x100: + instr_38(); + break; +case 0x39: + instr16_39(); + break; +case 0x39|0x100: + instr32_39(); + break; +case 0x3A: +case 0x3A|0x100: + instr_3A(); + break; +case 0x3B: + instr16_3B(); + break; +case 0x3B|0x100: + instr32_3B(); + break; +case 0x3C: +case 0x3C|0x100: + instr_3C(); + break; +case 0x3D: + instr16_3D(); + break; +case 0x3D|0x100: + instr32_3D(); + break; +case 0x3E: +case 0x3E|0x100: + instr_3E(); + break; +case 0x3F: +case 0x3F|0x100: + instr_3F(); + break; +case 0x40: + instr16_40(); + break; +case 0x40|0x100: + instr32_40(); + break; +case 0x41: + instr16_41(); + break; +case 0x41|0x100: + instr32_41(); + break; +case 0x42: + instr16_42(); + break; +case 0x42|0x100: + instr32_42(); + break; +case 0x43: + instr16_43(); + break; +case 0x43|0x100: + instr32_43(); + break; +case 0x44: + instr16_44(); + break; +case 0x44|0x100: + instr32_44(); + break; +case 0x45: + instr16_45(); + break; +case 0x45|0x100: + instr32_45(); + break; +case 0x46: + instr16_46(); + break; +case 0x46|0x100: + instr32_46(); + break; +case 0x47: + instr16_47(); + break; +case 0x47|0x100: + instr32_47(); + break; +case 0x48: + instr16_48(); + break; +case 0x48|0x100: + instr32_48(); + break; +case 0x49: + instr16_49(); + break; +case 0x49|0x100: + instr32_49(); + break; +case 0x4A: + instr16_4A(); + break; +case 0x4A|0x100: + instr32_4A(); + break; +case 0x4B: + instr16_4B(); + break; +case 0x4B|0x100: + instr32_4B(); + break; +case 0x4C: + instr16_4C(); + break; +case 0x4C|0x100: + instr32_4C(); + break; +case 0x4D: + instr16_4D(); + break; +case 0x4D|0x100: + instr32_4D(); + break; +case 0x4E: + instr16_4E(); + break; +case 0x4E|0x100: + instr32_4E(); + break; +case 0x4F: + instr16_4F(); + break; +case 0x4F|0x100: + instr32_4F(); + break; +case 0x50: + instr16_50(); + break; +case 0x50|0x100: + instr32_50(); + break; +case 0x51: + instr16_51(); + break; +case 0x51|0x100: + instr32_51(); + break; +case 0x52: + instr16_52(); + break; +case 0x52|0x100: + instr32_52(); + break; +case 0x53: + instr16_53(); + break; +case 0x53|0x100: + instr32_53(); + break; +case 0x54: + instr16_54(); + break; +case 0x54|0x100: + instr32_54(); + break; +case 0x55: + instr16_55(); + break; +case 0x55|0x100: + instr32_55(); + break; +case 0x56: + instr16_56(); + break; +case 0x56|0x100: + instr32_56(); + break; +case 0x57: + instr16_57(); + break; +case 0x57|0x100: + instr32_57(); + break; +case 0x58: + instr16_58(); + break; +case 0x58|0x100: + instr32_58(); + break; +case 0x59: + instr16_59(); + break; +case 0x59|0x100: + instr32_59(); + break; +case 0x5A: + instr16_5A(); + break; +case 0x5A|0x100: + instr32_5A(); + break; +case 0x5B: + instr16_5B(); + break; +case 0x5B|0x100: + instr32_5B(); + break; +case 0x5C: + instr16_5C(); + break; +case 0x5C|0x100: + instr32_5C(); + break; +case 0x5D: + instr16_5D(); + break; +case 0x5D|0x100: + instr32_5D(); + break; +case 0x5E: + instr16_5E(); + break; +case 0x5E|0x100: + instr32_5E(); + break; +case 0x5F: + instr16_5F(); + break; +case 0x5F|0x100: + instr32_5F(); + break; +case 0x60: + instr16_60(); + break; +case 0x60|0x100: + instr32_60(); + break; +case 0x61: + instr16_61(); + break; +case 0x61|0x100: + instr32_61(); + break; +case 0x62: +case 0x62|0x100: + instr_62(); + break; +case 0x63: +case 0x63|0x100: + instr_63(); + break; +case 0x64: +case 0x64|0x100: + instr_64(); + break; +case 0x65: +case 0x65|0x100: + instr_65(); + break; +case 0x66: +case 0x66|0x100: + instr_66(); + break; +case 0x67: +case 0x67|0x100: + instr_67(); + break; +case 0x68: + instr16_68(); + break; +case 0x68|0x100: + instr32_68(); + break; +case 0x69: + instr16_69(); + break; +case 0x69|0x100: + instr32_69(); + break; +case 0x6A: + instr16_6A(); + break; +case 0x6A|0x100: + instr32_6A(); + break; +case 0x6B: + instr16_6B(); + break; +case 0x6B|0x100: + instr32_6B(); + break; +case 0x6C: +case 0x6C|0x100: + instr_6C(); + break; +case 0x6D: + instr16_6D(); + break; +case 0x6D|0x100: + instr32_6D(); + break; +case 0x6E: +case 0x6E|0x100: + instr_6E(); + break; +case 0x6F: + instr16_6F(); + break; +case 0x6F|0x100: + instr32_6F(); + break; +case 0x70: +case 0x70|0x100: + instr_70(); + break; +case 0x71: +case 0x71|0x100: + instr_71(); + break; +case 0x72: +case 0x72|0x100: + instr_72(); + break; +case 0x73: +case 0x73|0x100: + instr_73(); + break; +case 0x74: +case 0x74|0x100: + instr_74(); + break; +case 0x75: +case 0x75|0x100: + instr_75(); + break; +case 0x76: +case 0x76|0x100: + instr_76(); + break; +case 0x77: +case 0x77|0x100: + instr_77(); + break; +case 0x78: +case 0x78|0x100: + instr_78(); + break; +case 0x79: +case 0x79|0x100: + instr_79(); + break; +case 0x7A: +case 0x7A|0x100: + instr_7A(); + break; +case 0x7B: +case 0x7B|0x100: + instr_7B(); + break; +case 0x7C: +case 0x7C|0x100: + instr_7C(); + break; +case 0x7D: +case 0x7D|0x100: + instr_7D(); + break; +case 0x7E: +case 0x7E|0x100: + instr_7E(); + break; +case 0x7F: +case 0x7F|0x100: + instr_7F(); + break; +case 0x80: +case 0x80|0x100: + instr_80(); + break; +case 0x81: + instr16_81(); + break; +case 0x81|0x100: + instr32_81(); + break; +case 0x82: +case 0x82|0x100: + instr_82(); + break; +case 0x83: + instr16_83(); + break; +case 0x83|0x100: + instr32_83(); + break; +case 0x84: +case 0x84|0x100: + instr_84(); + break; +case 0x85: + instr16_85(); + break; +case 0x85|0x100: + instr32_85(); + break; +case 0x86: +case 0x86|0x100: + instr_86(); + break; +case 0x87: + instr16_87(); + break; +case 0x87|0x100: + instr32_87(); + break; +case 0x88: +case 0x88|0x100: + instr_88(); + break; +case 0x89: + instr16_89(); + break; +case 0x89|0x100: + instr32_89(); + break; +case 0x8A: +case 0x8A|0x100: + instr_8A(); + break; +case 0x8B: + instr16_8B(); + break; +case 0x8B|0x100: + instr32_8B(); + break; +case 0x8C: + instr16_8C(); + break; +case 0x8C|0x100: + instr32_8C(); + break; +case 0x8D: + instr16_8D(); + break; +case 0x8D|0x100: + instr32_8D(); + break; +case 0x8E: +case 0x8E|0x100: + instr_8E(); + break; +case 0x8F: + instr16_8F(); + break; +case 0x8F|0x100: + instr32_8F(); + break; +case 0x90: +case 0x90|0x100: + instr_90(); + break; +case 0x91: + instr16_91(); + break; +case 0x91|0x100: + instr32_91(); + break; +case 0x92: + instr16_92(); + break; +case 0x92|0x100: + instr32_92(); + break; +case 0x93: + instr16_93(); + break; +case 0x93|0x100: + instr32_93(); + break; +case 0x94: + instr16_94(); + break; +case 0x94|0x100: + instr32_94(); + break; +case 0x95: + instr16_95(); + break; +case 0x95|0x100: + instr32_95(); + break; +case 0x96: + instr16_96(); + break; +case 0x96|0x100: + instr32_96(); + break; +case 0x97: + instr16_97(); + break; +case 0x97|0x100: + instr32_97(); + break; +case 0x98: + instr16_98(); + break; +case 0x98|0x100: + instr32_98(); + break; +case 0x99: + instr16_99(); + break; +case 0x99|0x100: + instr32_99(); + break; +case 0x9A: + instr16_9A(); + break; +case 0x9A|0x100: + instr32_9A(); + break; +case 0x9B: +case 0x9B|0x100: + instr_9B(); + break; +case 0x9C: + instr16_9C(); + break; +case 0x9C|0x100: + instr32_9C(); + break; +case 0x9D: + instr16_9D(); + break; +case 0x9D|0x100: + instr32_9D(); + break; +case 0x9E: +case 0x9E|0x100: + instr_9E(); + break; +case 0x9F: +case 0x9F|0x100: + instr_9F(); + break; +case 0xA0: +case 0xA0|0x100: + instr_A0(); + break; +case 0xA1: + instr16_A1(); + break; +case 0xA1|0x100: + instr32_A1(); + break; +case 0xA2: +case 0xA2|0x100: + instr_A2(); + break; +case 0xA3: + instr16_A3(); + break; +case 0xA3|0x100: + instr32_A3(); + break; +case 0xA4: +case 0xA4|0x100: + instr_A4(); + break; +case 0xA5: + instr16_A5(); + break; +case 0xA5|0x100: + instr32_A5(); + break; +case 0xA6: +case 0xA6|0x100: + instr_A6(); + break; +case 0xA7: + instr16_A7(); + break; +case 0xA7|0x100: + instr32_A7(); + break; +case 0xA8: +case 0xA8|0x100: + instr_A8(); + break; +case 0xA9: + instr16_A9(); + break; +case 0xA9|0x100: + instr32_A9(); + break; +case 0xAA: +case 0xAA|0x100: + instr_AA(); + break; +case 0xAB: + instr16_AB(); + break; +case 0xAB|0x100: + instr32_AB(); + break; +case 0xAC: +case 0xAC|0x100: + instr_AC(); + break; +case 0xAD: + instr16_AD(); + break; +case 0xAD|0x100: + instr32_AD(); + break; +case 0xAE: +case 0xAE|0x100: + instr_AE(); + break; +case 0xAF: + instr16_AF(); + break; +case 0xAF|0x100: + instr32_AF(); + break; +case 0xB0: +case 0xB0|0x100: + instr_B0(); + break; +case 0xB1: +case 0xB1|0x100: + instr_B1(); + break; +case 0xB2: +case 0xB2|0x100: + instr_B2(); + break; +case 0xB3: +case 0xB3|0x100: + instr_B3(); + break; +case 0xB4: +case 0xB4|0x100: + instr_B4(); + break; +case 0xB5: +case 0xB5|0x100: + instr_B5(); + break; +case 0xB6: +case 0xB6|0x100: + instr_B6(); + break; +case 0xB7: +case 0xB7|0x100: + instr_B7(); + break; +case 0xB8: + instr16_B8(); + break; +case 0xB8|0x100: + instr32_B8(); + break; +case 0xB9: + instr16_B9(); + break; +case 0xB9|0x100: + instr32_B9(); + break; +case 0xBA: + instr16_BA(); + break; +case 0xBA|0x100: + instr32_BA(); + break; +case 0xBB: + instr16_BB(); + break; +case 0xBB|0x100: + instr32_BB(); + break; +case 0xBC: + instr16_BC(); + break; +case 0xBC|0x100: + instr32_BC(); + break; +case 0xBD: + instr16_BD(); + break; +case 0xBD|0x100: + instr32_BD(); + break; +case 0xBE: + instr16_BE(); + break; +case 0xBE|0x100: + instr32_BE(); + break; +case 0xBF: + instr16_BF(); + break; +case 0xBF|0x100: + instr32_BF(); + break; +case 0xC0: +case 0xC0|0x100: + instr_C0(); + break; +case 0xC1: + instr16_C1(); + break; +case 0xC1|0x100: + instr32_C1(); + break; +case 0xC2: + instr16_C2(); + break; +case 0xC2|0x100: + instr32_C2(); + break; +case 0xC3: + instr16_C3(); + break; +case 0xC3|0x100: + instr32_C3(); + break; +case 0xC4: + instr16_C4(); + break; +case 0xC4|0x100: + instr32_C4(); + break; +case 0xC5: + instr16_C5(); + break; +case 0xC5|0x100: + instr32_C5(); + break; +case 0xC6: +case 0xC6|0x100: + instr_C6(); + break; +case 0xC7: + instr16_C7(); + break; +case 0xC7|0x100: + instr32_C7(); + break; +case 0xC8: + instr16_C8(); + break; +case 0xC8|0x100: + instr32_C8(); + break; +case 0xC9: + instr16_C9(); + break; +case 0xC9|0x100: + instr32_C9(); + break; +case 0xCA: + instr16_CA(); + break; +case 0xCA|0x100: + instr32_CA(); + break; +case 0xCB: + instr16_CB(); + break; +case 0xCB|0x100: + instr32_CB(); + break; +case 0xCC: +case 0xCC|0x100: + instr_CC(); + break; +case 0xCD: +case 0xCD|0x100: + instr_CD(); + break; +case 0xCE: +case 0xCE|0x100: + instr_CE(); + break; +case 0xCF: + instr16_CF(); + break; +case 0xCF|0x100: + instr32_CF(); + break; +case 0xD0: +case 0xD0|0x100: + instr_D0(); + break; +case 0xD1: + instr16_D1(); + break; +case 0xD1|0x100: + instr32_D1(); + break; +case 0xD2: +case 0xD2|0x100: + instr_D2(); + break; +case 0xD3: + instr16_D3(); + break; +case 0xD3|0x100: + instr32_D3(); + break; +case 0xD4: +case 0xD4|0x100: + instr_D4(); + break; +case 0xD5: +case 0xD5|0x100: + instr_D5(); + break; +case 0xD6: +case 0xD6|0x100: + instr_D6(); + break; +case 0xD7: +case 0xD7|0x100: + instr_D7(); + break; +case 0xD8: +case 0xD8|0x100: + instr_D8(); + break; +case 0xD9: +case 0xD9|0x100: + instr_D9(); + break; +case 0xDA: +case 0xDA|0x100: + instr_DA(); + break; +case 0xDB: +case 0xDB|0x100: + instr_DB(); + break; +case 0xDC: +case 0xDC|0x100: + instr_DC(); + break; +case 0xDD: +case 0xDD|0x100: + instr_DD(); + break; +case 0xDE: +case 0xDE|0x100: + instr_DE(); + break; +case 0xDF: +case 0xDF|0x100: + instr_DF(); + break; +case 0xE0: +case 0xE0|0x100: + instr_E0(); + break; +case 0xE1: +case 0xE1|0x100: + instr_E1(); + break; +case 0xE2: +case 0xE2|0x100: + instr_E2(); + break; +case 0xE3: +case 0xE3|0x100: + instr_E3(); + break; +case 0xE4: +case 0xE4|0x100: + instr_E4(); + break; +case 0xE5: + instr16_E5(); + break; +case 0xE5|0x100: + instr32_E5(); + break; +case 0xE6: +case 0xE6|0x100: + instr_E6(); + break; +case 0xE7: + instr16_E7(); + break; +case 0xE7|0x100: + instr32_E7(); + break; +case 0xE8: + instr16_E8(); + break; +case 0xE8|0x100: + instr32_E8(); + break; +case 0xE9: + instr16_E9(); + break; +case 0xE9|0x100: + instr32_E9(); + break; +case 0xEA: + instr16_EA(); + break; +case 0xEA|0x100: + instr32_EA(); + break; +case 0xEB: +case 0xEB|0x100: + instr_EB(); + break; +case 0xEC: +case 0xEC|0x100: + instr_EC(); + break; +case 0xED: + instr16_ED(); + break; +case 0xED|0x100: + instr32_ED(); + break; +case 0xEE: +case 0xEE|0x100: + instr_EE(); + break; +case 0xEF: + instr16_EF(); + break; +case 0xEF|0x100: + instr32_EF(); + break; +case 0xF0: +case 0xF0|0x100: + instr_F0(); + break; +case 0xF1: +case 0xF1|0x100: + instr_F1(); + break; +case 0xF2: +case 0xF2|0x100: + instr_F2(); + break; +case 0xF3: +case 0xF3|0x100: + instr_F3(); + break; +case 0xF4: +case 0xF4|0x100: + instr_F4(); + break; +case 0xF5: +case 0xF5|0x100: + instr_F5(); + break; +case 0xF6: +case 0xF6|0x100: + instr_F6(); + break; +case 0xF7: + instr16_F7(); + break; +case 0xF7|0x100: + instr32_F7(); + break; +case 0xF8: +case 0xF8|0x100: + instr_F8(); + break; +case 0xF9: +case 0xF9|0x100: + instr_F9(); + break; +case 0xFA: +case 0xFA|0x100: + instr_FA(); + break; +case 0xFB: +case 0xFB|0x100: + instr_FB(); + break; +case 0xFC: +case 0xFC|0x100: + instr_FC(); + break; +case 0xFD: +case 0xFD|0x100: + instr_FD(); + break; +case 0xFE: +case 0xFE|0x100: + instr_FE(); + break; +case 0xFF: + instr16_FF(); + break; +case 0xFF|0x100: + instr32_FF(); + break; +default: + assert(false); + } +} diff --git a/src/native/instructions_0f.c b/src/native/instructions_0f.c new file mode 100644 index 00000000..ceb70a3a --- /dev/null +++ b/src/native/instructions_0f.c @@ -0,0 +1,3155 @@ +#include +#include +#include +#include + +#include "const.h" +#include "global_pointers.h" + +// XXX: Remove these declarations when they are implemented in C +void cmovcc16(bool); +void cmovcc32(bool); +void jmpcc16(bool); +void jmpcc32(bool); +void setcc(bool); +void cpuid(); + +int32_t bt_mem(int32_t, int32_t); +int32_t bt_reg(int32_t, int32_t); +int32_t bts_mem(int32_t, int32_t); +int32_t bts_reg(int32_t, int32_t); +int32_t btc_mem(int32_t, int32_t); +int32_t btc_reg(int32_t, int32_t); +int32_t btr_mem(int32_t, int32_t); +int32_t btr_reg(int32_t, int32_t); +int32_t bsf16(int32_t, int32_t); +int32_t bsf32(int32_t, int32_t); +int32_t bsr16(int32_t, int32_t); +int32_t bsr32(int32_t, int32_t); + +int32_t popcnt(int32_t); +int32_t bswap(int32_t); + +int32_t read_g16s(void); +int32_t read_reg_e16(void); +int32_t read_reg_e32s(void); + +void cpl_changed(void); +void update_cs_size(int32_t); +void unimplemented_sse(void); + +int32_t shld16(int32_t, int32_t, int32_t); +int32_t shld32(int32_t, int32_t, int32_t); +int32_t shrd16(int32_t, int32_t, int32_t); +int32_t shrd32(int32_t, int32_t, int32_t); + +bool has_rand_int(void); +int32_t get_rand_int(void); + +void todo(); +void undefined_instruction(); + +void clear_tlb(); +void full_clear_tlb(); + +int32_t microtick(); + +int32_t lsl(int32_t, int32_t); +int32_t lar(int32_t, int32_t); +int32_t verw(int32_t); +int32_t verr(int32_t); + +void invlpg(int32_t); +void load_tr(int32_t); +void load_ldt(int32_t); + +int32_t set_cr0(int32_t); +void writable_or_pagefault(int32_t, int32_t); + +bool* const apic_enabled; + + +static void instr_0F00() { read_modrm_byte(); + if(!protected_mode[0] || vm86_mode()) + { + // No GP, UD is correct here + dbg_log("0f 00 #ud"); + trigger_ud(); + } + + switch(modrm_byte[0] >> 3 & 7) + { + case 0: + // sldt + set_e16(sreg[LDTR]); + if(is_osize_32() && modrm_byte[0] >= 0xC0) + { + reg32s[modrm_byte[0] & 7] &= 0xFFFF; + } + break; + case 1: + // str + set_e16(sreg[LDTR]); + if(is_osize_32() && modrm_byte[0] >= 0xC0) + { + reg32s[modrm_byte[0] & 7] &= 0xFFFF; + } + break; + case 2: + // lldt + if(cpl[0]) + { + trigger_gp(0); + } + + { + int32_t data = read_e16(); + load_ldt(data); + } + break; + case 3: + // ltr + if(cpl[0]) + { + trigger_gp(0); + } + + int32_t data = read_e16(); + load_tr(data); + break; + case 4: + verr(read_e16()); + break; + case 5: + verw(read_e16()); + break; + + default: + dbg_log("%d", modrm_byte[0] >> 3 & 7); + todo(); + } +} + +static void instr_0F01() { read_modrm_byte(); + int32_t mod = modrm_byte[0] >> 3 & 7; + + if(mod == 4) + { + // smsw + if(modrm_byte[0] >= 0xC0 && is_osize_32()) + { + set_e32(cr[0]); + } + else + { + set_e16(cr[0]); + } + return; + } + else if(mod == 6) + { + // lmsw + if(cpl[0]) + { + trigger_gp(0); + } + + int32_t cr0 = read_e16(); + + cr0 = (cr[0] & ~0xF) | (cr0 & 0xF); + + if(protected_mode[0]) + { + // lmsw cannot be used to switch back + cr0 |= CR0_PE; + } + + set_cr0(cr0); + return; + } + + if(modrm_byte[0] >= 0xC0) + { + // only memory + dbg_log("0f 01 #ud"); + trigger_ud(); + } + + int32_t addr = modrm_resolve(modrm_byte[0]); + + switch(mod) + { + case 0: + // sgdt + writable_or_pagefault(addr, 6); + safe_write16(addr, gdtr_size[0]); + { + int32_t mask = is_osize_32() ? -1 : 0x00FFFFFF; + safe_write32(addr + 2, gdtr_offset[0] & mask); + } + break; + case 1: + // sidt + writable_or_pagefault(addr, 6); + safe_write16(addr, idtr_size[0]); + { + int32_t mask = is_osize_32() ? -1 : 0x00FFFFFF; + safe_write32(addr + 2, idtr_offset[0] & mask); + } + break; + case 2: + // lgdt + if(cpl[0]) + { + trigger_gp(0); + } + + { + int32_t size = safe_read16(addr); + int32_t offset = safe_read32s(addr + 2); + + gdtr_size[0] = size; + gdtr_offset[0] = offset; + + if(!is_osize_32()) + { + gdtr_offset[0] &= 0xFFFFFF; + } + + //dbg_log("gdt at " + h(gdtr_offset[0]) + ", " + gdtr_size[0] + " bytes"); + //debug.dump_state(); + //debug.dump_regs_short(); + //debug.dump_gdt_ldt(); + } + break; + case 3: + // lidt + if(cpl[0]) + { + trigger_gp(0); + } + + { + int32_t size = safe_read16(addr); + int32_t offset = safe_read32s(addr + 2); + + idtr_size[0] = size; + idtr_offset[0] = offset; + + if(!is_osize_32()) + { + idtr_offset[0] &= 0xFFFFFF; + } + + //dbg_log("[" + h(instruction_pointer) + "] idt at " + + // h(idtr_offset) + ", " + idtr_size[0] + " bytes " + h(addr)); + } + break; + case 7: + // flush translation lookaside buffer + if(cpl[0]) + { + trigger_gp(0); + } + + invlpg(addr); + break; + default: + dbg_log("%d", mod); + todo(); + } +} + +static void instr16_0F02() { read_modrm_byte(); + // lar + if(!protected_mode[0] || vm86_mode()) + { + dbg_log("lar #ud"); + trigger_ud(); + } + int32_t data = read_e16(); + write_g16(lar(data, read_g16())); +} +static void instr32_0F02() { read_modrm_byte(); + if(!protected_mode[0] || vm86_mode()) + { + dbg_log("lar #ud"); + trigger_ud(); + } + int32_t data = read_e16(); + write_g32(lar(data, read_g32s())); +} + +static void instr16_0F03() { read_modrm_byte(); + // lsl + if(!protected_mode[0] || vm86_mode()) + { + dbg_log("lsl #ud"); + trigger_ud(); + } + int32_t data = read_e16(); + write_g16(lsl(data, read_g16())); +} +static void instr32_0F03() { read_modrm_byte(); + if(!protected_mode[0] || vm86_mode()) + { + dbg_log("lsl #ud"); + trigger_ud(); + } + int32_t data = read_e16(); + write_g32(lsl(data, read_g32s())); +} + +static void instr_0F04() { undefined_instruction(); } +static void instr_0F05() { undefined_instruction(); } + +static void instr_0F06() { + // clts + if(cpl[0]) + { + dbg_log("clts #gp"); + trigger_gp(0); + } + else + { + //dbg_log("clts"); + cr[0] &= ~CR0_TS; + } +} + +static void instr_0F07() { undefined_instruction(); } +static void instr_0F08() { + // invd + todo(); +} + +static void instr_0F09() { + if(cpl[0]) + { + dbg_log("wbinvd #gp"); + trigger_gp(0); + } + // wbinvd +} + + +static void instr_0F0A() { undefined_instruction(); } +static void instr_0F0B() { + // UD2 + trigger_ud(); +} +static void instr_0F0C() { undefined_instruction(); } + +static void instr_0F0D() { + // nop + todo(); +} + +static void instr_0F0E() { undefined_instruction(); } +static void instr_0F0F() { undefined_instruction(); } + +static void instr_0F10() { unimplemented_sse(); } +static void instr_0F11() { unimplemented_sse(); } +static void instr_0F12() { unimplemented_sse(); } +static void instr_0F13() { unimplemented_sse(); } +static void instr_0F14() { unimplemented_sse(); } +static void instr_0F15() { unimplemented_sse(); } +static void instr_0F16() { unimplemented_sse(); } +static void instr_0F17() { unimplemented_sse(); } + +static void instr_0F18() { read_modrm_byte(); + // prefetch + // nop for us + if(modrm_byte[0] < 0xC0) + modrm_resolve(modrm_byte[0]); +} + +static void instr_0F19() { unimplemented_sse(); } +static void instr_0F1A() { unimplemented_sse(); } +static void instr_0F1B() { unimplemented_sse(); } +static void instr_0F1C() { unimplemented_sse(); } +static void instr_0F1D() { unimplemented_sse(); } +static void instr_0F1E() { unimplemented_sse(); } +static void instr_0F1F() { read_modrm_byte(); + // multi-byte nop + if(modrm_byte[0] < 0xC0) + modrm_resolve(modrm_byte[0]); +} + + +static void instr_0F20() { read_modrm_byte(); + + if(cpl[0]) + { + trigger_gp(0); + } + //dbg_log("cr" + (modrm_byte[0] >> 3 & 7) + " read"); + + // mov addr, cr + // mod = which control register + switch(modrm_byte[0] >> 3 & 7) + { + case 0: + write_reg_e32(cr[0]); + break; + case 2: + //dbg_log("read cr2 at " + h(instruction_pointer, 8)); + write_reg_e32(cr[2]); + break; + case 3: + //dbg_log("read cr3 (" + h(cr[3], 8) + ")"); + write_reg_e32(cr[3]); + break; + case 4: + write_reg_e32(cr[4]); + break; + default: + dbg_log("%d", modrm_byte[0] >> 3 & 7); + todo(); + } +} + +static void instr_0F21() { read_modrm_byte(); + if(cpl[0]) + { + trigger_gp(0); + } + + int32_t dreg_index = modrm_byte[0] >> 3 & 7; + if((cr[4] & CR4_DE) && (dreg_index == 4 || dreg_index == 5)) + { + dbg_log("#ud mov dreg 4/5 with cr4.DE set"); + trigger_ud(); + } + + // high two bits of modrm are ignored + reg32s[modrm_byte[0] & 7] = dreg[dreg_index]; + + //dbg_log("read dr" + dreg + ": " + h(dreg[dreg_index])); +} + +static void instr_0F22() { read_modrm_byte(); + + if(cpl[0]) + { + trigger_gp(0); + } + + int32_t data = read_reg_e32s(); + //dbg_log("cr" + (modrm_byte[0] >> 3 & 7) + " written: " + h(data, 8)); + + // mov cr, addr + // mod = which control register + switch(modrm_byte[0] >> 3 & 7) + { + case 0: + set_cr0(data); + //dbg_log("cr0=" + h(data)); + break; + + case 2: + cr[2] = data; + //dbg_log("cr2=" + h(data)); + break; + + case 3: + //dbg_log("cr3=" + h(data)); + data &= ~0b111111100111; + dbg_assert_message((data & 0xFFF) == 0, "TODO"); + cr[3] = data; + clear_tlb(); + + //dump_page_directory(); + //dbg_log("page directory loaded at " + h(cr[3], 8)); + break; + + case 4: + if(data & (1 << 11 | 1 << 12 | 1 << 15 | 1 << 16 | 1 << 19 | 0xFFC00000)) + { + trigger_gp(0); + } + + if((cr[4] ^ data) & CR4_PGE) + { + if(data & CR4_PGE) + { + // The PGE bit has been enabled. The global TLB is + // still empty, so we only have to copy it over + clear_tlb(); + } + else + { + // Clear the global TLB + full_clear_tlb(); + } + } + + cr[4] = data; + page_size_extensions[0] = (cr[4] & CR4_PSE) ? PSE_ENABLED : 0; + + if(cr[4] & CR4_PAE) + { + //throw debug.unimpl("PAE"); + assert(false); + } + + //dbg_log("cr4=" + h(cr[4])); + break; + + default: + dbg_log("%d", modrm_byte[0] >> 3 & 7); + todo(); + } +} +static void instr_0F23() { read_modrm_byte(); + if(cpl[0]) + { + trigger_gp(0); + } + + int32_t dreg_index = modrm_byte[0] >> 3 & 7; + if((cr[4] & CR4_DE) && (dreg_index == 4 || dreg_index == 5)) + { + dbg_log("#ud mov dreg 4/5 with cr4.DE set"); + trigger_ud(); + } + + // high two bits of modrm are ignored + dreg[dreg_index] = read_reg_e32s(); + + //dbg_log("write dr" + dreg + ": " + h(dreg[dreg_index])); +} + +static void instr_0F24() { undefined_instruction(); } +static void instr_0F25() { undefined_instruction(); } +static void instr_0F26() { undefined_instruction(); } +static void instr_0F27() { undefined_instruction(); } + +static void instr_0F28() { unimplemented_sse(); } +static void instr_0F29() { unimplemented_sse(); } +static void instr_0F2A() { unimplemented_sse(); } +static void instr_0F2B() { unimplemented_sse(); } +static void instr_0F2C() { unimplemented_sse(); } +static void instr_0F2D() { unimplemented_sse(); } +static void instr_0F2E() { unimplemented_sse(); } +static void instr_0F2F() { unimplemented_sse(); } + +// wrmsr +static void instr_0F30() { + // wrmsr - write maschine specific register + + if(cpl[0]) + { + // cpl > 0 or vm86 mode (vm86 mode is always runs with cpl=3) + trigger_gp(0); + } + + int32_t index = reg32s[ECX]; + int32_t low = reg32s[EAX]; + int32_t high = reg32s[EDX]; + + if(index != IA32_SYSENTER_ESP) + { + //dbg_log("wrmsr ecx=" + h(index, 8) + + // " data=" + h(high, 8) + ":" + h(low, 8)); + } + + switch(index) + { + case IA32_SYSENTER_CS: + sysenter_cs[0] = low & 0xFFFF; + break; + + case IA32_SYSENTER_EIP: + sysenter_eip[0] = low; + break; + + case IA32_SYSENTER_ESP: + sysenter_esp[0] = low; + break; + + case IA32_APIC_BASE_MSR: + { + dbg_assert_message(high == 0, "Changing APIC address (high 32 bits) not supported"); + int32_t address = low & ~(IA32_APIC_BASE_BSP | IA32_APIC_BASE_EXTD | IA32_APIC_BASE_EN); + dbg_assert_message(address == APIC_ADDRESS, "Changing APIC address not supported"); + dbg_assert_message((low & IA32_APIC_BASE_EXTD) == 0, "x2apic not supported"); + *apic_enabled = (low & IA32_APIC_BASE_EN) == IA32_APIC_BASE_EN; + } + break; + + case IA32_TIME_STAMP_COUNTER: + { + int32_t new_tick = (low) + 0x100000000 * (high); + tsc_offset[0] = microtick() - new_tick / TSC_RATE; // XXX: float + } + break; + + case IA32_BIOS_SIGN_ID: + break; + + case IA32_MISC_ENABLE: // Enable Misc. Processor Features + break; + + case IA32_MCG_CAP: + // netbsd + break; + + case IA32_KERNEL_GS_BASE: + // Only used in 64 bit mode (by SWAPGS), but set by kvm-unit-test + dbg_log("GS Base written"); + break; + + default: + assert(false); + //dbg_assert(false, "Unknown msr: " + h(index, 8)); + } +} + +static void instr_0F31() { + // rdtsc - read timestamp counter + + if(!cpl[0] || !(cr[4] & CR4_TSD)) + { + int32_t n = microtick() - tsc_offset[0]; // XXX: float + //dbg_assert(isFinite(n), "non-finite tsc: " + n); + + reg32s[EAX] = n * TSC_RATE; + reg32s[EDX] = n * (TSC_RATE / 0x100000000); + + //dbg_log("rdtsc edx:eax=" + h(reg32[EDX], 8) + ":" + h(reg32[EAX], 8)); + } + else + { + trigger_gp(0); + } +} + +static void instr_0F32() { + // rdmsr - read maschine specific register + if(cpl[0]) + { + trigger_gp(0); + } + + int32_t index = reg32s[ECX]; + + //dbg_log("rdmsr ecx=" + h(index, 8)); + + int32_t low = 0; + int32_t high = 0; + + switch(index) + { + case IA32_SYSENTER_CS: + low = sysenter_cs[0]; + break; + + case IA32_SYSENTER_EIP: + low = sysenter_eip[0]; + break; + + case IA32_SYSENTER_ESP: + low = sysenter_esp[0]; + break; + + case IA32_TIME_STAMP_COUNTER: + { + int32_t n = microtick() - tsc_offset[0]; // XXX: float + low = n * TSC_RATE; + high = n * (TSC_RATE / 0x100000000); + } + break; + + case IA32_PLATFORM_ID: + break; + + case IA32_APIC_BASE_MSR: + if(ENABLE_ACPI) + { + low = APIC_ADDRESS; + + if(*apic_enabled) + { + low |= IA32_APIC_BASE_EN; + } + } + break; + + case IA32_BIOS_SIGN_ID: + break; + + case IA32_MISC_ENABLE: // Enable Misc. Processor Features + break; + + case IA32_RTIT_CTL: + // linux4 + break; + + case MSR_SMI_COUNT: + break; + + case IA32_MCG_CAP: + // netbsd + break; + + case MSR_PKG_C2_RESIDENCY: + break; + + default: + assert(false); + //dbg_assert(false, "Unknown msr: " + h(index, 8)); + } + + reg32s[EAX] = low; + reg32s[EDX] = high; +} + +static void instr_0F33() { + // rdpmc + todo(); +} + +static void instr_0F34() { + // sysenter + int32_t seg = sysenter_cs[0] & 0xFFFC; + + if(!protected_mode[0] || seg == 0) + { + trigger_gp(0); + } + + if(CPU_LOG_VERBOSE) + { + //dbg_log("sysenter cs:eip=" + h(seg , 4) + ":" + h(sysenter_eip[0], 8) + + // " ss:esp=" + h(seg + 8, 4) + ":" + h(sysenter_esp[0], 8)); + } + + flags[0] &= ~FLAG_VM & ~FLAG_INTERRUPT; + + instruction_pointer[0] = sysenter_eip[0]; + reg32s[ESP] = sysenter_esp[0]; + + sreg[CS] = seg; + segment_is_null[CS] = 0; + segment_limits[CS] = -1; + segment_offsets[CS] = 0; + + update_cs_size(true); + + cpl[0] = 0; + cpl_changed(); + + sreg[SS] = seg + 8; + segment_is_null[SS] = 0; + segment_limits[SS] = -1; + segment_offsets[SS] = 0; + + stack_size_32[0] = true; + diverged(); +} + +static void instr_0F35() { + // sysexit + int32_t seg = sysenter_cs[0] & 0xFFFC; + + if(!protected_mode[0] || cpl[0] || seg == 0) + { + trigger_gp(0); + } + + if(CPU_LOG_VERBOSE) + { + //dbg_log("sysexit cs:eip=" + h(seg + 16, 4) + ":" + h(reg32s[EDX], 8) + + // " ss:esp=" + h(seg + 24, 4) + ":" + h(reg32s[ECX], 8)); + } + + instruction_pointer[0] = reg32s[EDX]; + reg32s[ESP] = reg32s[ECX]; + + sreg[CS] = seg + 16 | 3; + + segment_is_null[CS] = 0; + segment_limits[CS] = -1; + segment_offsets[CS] = 0; + + update_cs_size(true); + + cpl[0] = 3; + cpl_changed(); + + sreg[SS] = seg + 24 | 3; + segment_is_null[SS] = 0; + segment_limits[SS] = -1; + segment_offsets[SS] = 0; + + stack_size_32[0] = true; + diverged(); +} + +static void instr_0F36() { undefined_instruction(); } + +static void instr_0F37() { + // getsec + todo(); +} + +static void instr_0F38() { unimplemented_sse(); } +static void instr_0F39() { unimplemented_sse(); } +static void instr_0F3A() { unimplemented_sse(); } +static void instr_0F3B() { unimplemented_sse(); } +static void instr_0F3C() { unimplemented_sse(); } +static void instr_0F3D() { unimplemented_sse(); } +static void instr_0F3E() { unimplemented_sse(); } +static void instr_0F3F() { unimplemented_sse(); } + + +// cmov +static void instr16_0F40() { read_modrm_byte(); cmovcc16( test_o()); } +static void instr32_0F40() { read_modrm_byte(); cmovcc32( test_o()); } +static void instr16_0F41() { read_modrm_byte(); cmovcc16(!test_o()); } +static void instr32_0F41() { read_modrm_byte(); cmovcc32(!test_o()); } +static void instr16_0F42() { read_modrm_byte(); cmovcc16( test_b()); } +static void instr32_0F42() { read_modrm_byte(); cmovcc32( test_b()); } +static void instr16_0F43() { read_modrm_byte(); cmovcc16(!test_b()); } +static void instr32_0F43() { read_modrm_byte(); cmovcc32(!test_b()); } +static void instr16_0F44() { read_modrm_byte(); cmovcc16( test_z()); } +static void instr32_0F44() { read_modrm_byte(); cmovcc32( test_z()); } +static void instr16_0F45() { read_modrm_byte(); cmovcc16(!test_z()); } +static void instr32_0F45() { read_modrm_byte(); cmovcc32(!test_z()); } +static void instr16_0F46() { read_modrm_byte(); cmovcc16( test_be()); } +static void instr32_0F46() { read_modrm_byte(); cmovcc32( test_be()); } +static void instr16_0F47() { read_modrm_byte(); cmovcc16(!test_be()); } +static void instr32_0F47() { read_modrm_byte(); cmovcc32(!test_be()); } +static void instr16_0F48() { read_modrm_byte(); cmovcc16( test_s()); } +static void instr32_0F48() { read_modrm_byte(); cmovcc32( test_s()); } +static void instr16_0F49() { read_modrm_byte(); cmovcc16(!test_s()); } +static void instr32_0F49() { read_modrm_byte(); cmovcc32(!test_s()); } +static void instr16_0F4A() { read_modrm_byte(); cmovcc16( test_p()); } +static void instr32_0F4A() { read_modrm_byte(); cmovcc32( test_p()); } +static void instr16_0F4B() { read_modrm_byte(); cmovcc16(!test_p()); } +static void instr32_0F4B() { read_modrm_byte(); cmovcc32(!test_p()); } +static void instr16_0F4C() { read_modrm_byte(); cmovcc16( test_l()); } +static void instr32_0F4C() { read_modrm_byte(); cmovcc32( test_l()); } +static void instr16_0F4D() { read_modrm_byte(); cmovcc16(!test_l()); } +static void instr32_0F4D() { read_modrm_byte(); cmovcc32(!test_l()); } +static void instr16_0F4E() { read_modrm_byte(); cmovcc16( test_le()); } +static void instr32_0F4E() { read_modrm_byte(); cmovcc32( test_le()); } +static void instr16_0F4F() { read_modrm_byte(); cmovcc16(!test_le()); } +static void instr32_0F4F() { read_modrm_byte(); cmovcc32(!test_le()); } + + +static void instr_0F50() { unimplemented_sse(); } +static void instr_0F51() { unimplemented_sse(); } +static void instr_0F52() { unimplemented_sse(); } +static void instr_0F53() { unimplemented_sse(); } +static void instr_0F54() { unimplemented_sse(); } +static void instr_0F55() { unimplemented_sse(); } +static void instr_0F56() { unimplemented_sse(); } +static void instr_0F57() { unimplemented_sse(); } + +static void instr_0F58() { unimplemented_sse(); } +static void instr_0F59() { unimplemented_sse(); } +static void instr_0F5A() { unimplemented_sse(); } +static void instr_0F5B() { unimplemented_sse(); } +static void instr_0F5C() { unimplemented_sse(); } +static void instr_0F5D() { unimplemented_sse(); } +static void instr_0F5E() { unimplemented_sse(); } +static void instr_0F5F() { unimplemented_sse(); } + +static void instr_0F60() { unimplemented_sse(); } +static void instr_0F61() { unimplemented_sse(); } +static void instr_0F62() { unimplemented_sse(); } +static void instr_0F63() { unimplemented_sse(); } +static void instr_0F64() { unimplemented_sse(); } +static void instr_0F65() { unimplemented_sse(); } +static void instr_0F66() { unimplemented_sse(); } +static void instr_0F67() { unimplemented_sse(); } + +static void instr_0F68() { unimplemented_sse(); } +static void instr_0F69() { unimplemented_sse(); } +static void instr_0F6A() { unimplemented_sse(); } +static void instr_0F6B() { unimplemented_sse(); } +static void instr_0F6C() { unimplemented_sse(); } +static void instr_0F6D() { unimplemented_sse(); } +static void instr_0F6E() { unimplemented_sse(); } +static void instr_0F6F() { unimplemented_sse(); } + +static void instr_0F70() { unimplemented_sse(); } +static void instr_0F71() { unimplemented_sse(); } +static void instr_0F72() { unimplemented_sse(); } +static void instr_0F73() { unimplemented_sse(); } +static void instr_0F74() { unimplemented_sse(); } +static void instr_0F75() { unimplemented_sse(); } +static void instr_0F76() { unimplemented_sse(); } +static void instr_0F77() { + // emms + dbg_assert((*prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) == 0); + + if(cr[0] & (CR0_EM | CR0_TS)) { + if(cr[0] & CR0_TS) { + trigger_nm(); + } + else { + trigger_ud(); + } + } + + safe_tag_word(0xFFFF); +} + +static void instr_0F78() { unimplemented_sse(); } +static void instr_0F79() { unimplemented_sse(); } +static void instr_0F7A() { unimplemented_sse(); } +static void instr_0F7B() { unimplemented_sse(); } +static void instr_0F7C() { unimplemented_sse(); } +static void instr_0F7D() { unimplemented_sse(); } +static void instr_0F7E() { unimplemented_sse(); } +static void instr_0F7F() { unimplemented_sse(); } + +// jmpcc +static void instr16_0F80() { jmpcc16( test_o()); } +static void instr32_0F80() { jmpcc32( test_o()); } +static void instr16_0F81() { jmpcc16(!test_o()); } +static void instr32_0F81() { jmpcc32(!test_o()); } +static void instr16_0F82() { jmpcc16( test_b()); } +static void instr32_0F82() { jmpcc32( test_b()); } +static void instr16_0F83() { jmpcc16(!test_b()); } +static void instr32_0F83() { jmpcc32(!test_b()); } +static void instr16_0F84() { jmpcc16( test_z()); } +static void instr32_0F84() { jmpcc32( test_z()); } +static void instr16_0F85() { jmpcc16(!test_z()); } +static void instr32_0F85() { jmpcc32(!test_z()); } +static void instr16_0F86() { jmpcc16( test_be()); } +static void instr32_0F86() { jmpcc32( test_be()); } +static void instr16_0F87() { jmpcc16(!test_be()); } +static void instr32_0F87() { jmpcc32(!test_be()); } +static void instr16_0F88() { jmpcc16( test_s()); } +static void instr32_0F88() { jmpcc32( test_s()); } +static void instr16_0F89() { jmpcc16(!test_s()); } +static void instr32_0F89() { jmpcc32(!test_s()); } +static void instr16_0F8A() { jmpcc16( test_p()); } +static void instr32_0F8A() { jmpcc32( test_p()); } +static void instr16_0F8B() { jmpcc16(!test_p()); } +static void instr32_0F8B() { jmpcc32(!test_p()); } +static void instr16_0F8C() { jmpcc16( test_l()); } +static void instr32_0F8C() { jmpcc32( test_l()); } +static void instr16_0F8D() { jmpcc16(!test_l()); } +static void instr32_0F8D() { jmpcc32(!test_l()); } +static void instr16_0F8E() { jmpcc16( test_le()); } +static void instr32_0F8E() { jmpcc32( test_le()); } +static void instr16_0F8F() { jmpcc16(!test_le()); } +static void instr32_0F8F() { jmpcc32(!test_le()); } + +// setcc +static void instr_0F90() { read_modrm_byte(); setcc( test_o()); } +static void instr_0F91() { read_modrm_byte(); setcc(!test_o()); } +static void instr_0F92() { read_modrm_byte(); setcc( test_b()); } +static void instr_0F93() { read_modrm_byte(); setcc(!test_b()); } +static void instr_0F94() { read_modrm_byte(); setcc( test_z()); } +static void instr_0F95() { read_modrm_byte(); setcc(!test_z()); } +static void instr_0F96() { read_modrm_byte(); setcc( test_be()); } +static void instr_0F97() { read_modrm_byte(); setcc(!test_be()); } +static void instr_0F98() { read_modrm_byte(); setcc( test_s()); } +static void instr_0F99() { read_modrm_byte(); setcc(!test_s()); } +static void instr_0F9A() { read_modrm_byte(); setcc( test_p()); } +static void instr_0F9B() { read_modrm_byte(); setcc(!test_p()); } +static void instr_0F9C() { read_modrm_byte(); setcc( test_l()); } +static void instr_0F9D() { read_modrm_byte(); setcc(!test_l()); } +static void instr_0F9E() { read_modrm_byte(); setcc( test_le()); } +static void instr_0F9F() { read_modrm_byte(); setcc(!test_le()); } + +static void instr16_0FA0() { push16(sreg[FS]); } +static void instr32_0FA0() { push32(sreg[FS]); } +static void instr16_0FA1() { + switch_seg(FS, safe_read16(get_stack_pointer(0))); + adjust_stack_reg(2); +} +static void instr32_0FA1() { + switch_seg(FS, safe_read32s(get_stack_pointer(0)) & 0xFFFF); + adjust_stack_reg(4); +} + +static void instr_0FA2() { cpuid(); } + +static void instr16_0FA3() { read_modrm_byte(); + if(modrm_byte[0] < 0xC0) + { + bt_mem(modrm_resolve(modrm_byte[0]), read_g16s()); + } + else + { + bt_reg(read_reg_e16(), read_g16() & 15); + } +} +static void instr32_0FA3() { read_modrm_byte(); + if(modrm_byte[0] < 0xC0) + { + bt_mem(modrm_resolve(modrm_byte[0]), read_g32s()); + } + else + { + bt_reg(read_reg_e32s(), read_g32s() & 31); + } +} + +static void instr16_0FA4() { read_modrm_byte(); + int32_t data = read_write_e16(); write_e16(shld16(data, read_g16(), read_op8() & 31)); +} +static void instr32_0FA4() { read_modrm_byte(); + int32_t data = read_write_e32(); write_e32(shld32(data, read_g32s(), read_op8() & 31)); +} +static void instr16_0FA5() { read_modrm_byte(); + int32_t data = read_write_e16(); write_e16(shld16(data, read_g16(), reg8[CL] & 31)); +} +static void instr32_0FA5() { read_modrm_byte(); + int32_t data = read_write_e32(); write_e32(shld32(data, read_g32s(), reg8[CL] & 31)); +} + +static void instr_0FA6() { + // obsolete cmpxchg (os/2) + trigger_ud(); +} +static void instr_0FA7() { undefined_instruction(); } + +static void instr16_0FA8() { push16(sreg[GS]); } +static void instr32_0FA8() { push32(sreg[GS]); } +static void instr16_0FA9() { + switch_seg(GS, safe_read16(get_stack_pointer(0))); + adjust_stack_reg(2); +} +static void instr32_0FA9() { + switch_seg(GS, safe_read32s(get_stack_pointer(0)) & 0xFFFF); + adjust_stack_reg(4); +} + + +static void instr_0FAA() { + // rsm + todo(); +} + +static void instr16_0FAB() { read_modrm_byte(); + if(modrm_byte[0] < 0xC0) { + bts_mem(modrm_resolve(modrm_byte[0]), read_g16s()); + } else { + write_reg_e16(bts_reg(read_reg_e16(), read_g16s() & 15)); + } +} +static void instr32_0FAB() { read_modrm_byte(); + if(modrm_byte[0] < 0xC0) { + bts_mem(modrm_resolve(modrm_byte[0]), read_g32s()); + } else { + write_reg_e32(bts_reg(read_reg_e32s(), read_g32s() & 31)); + } +} + + +static void instr16_0FAC() { read_modrm_byte(); + int32_t data = read_write_e16(); write_e16(shrd16(data, read_g16(), read_op8() & 31)); +} +static void instr32_0FAC() { read_modrm_byte(); + int32_t data = read_write_e32(); write_e32(shrd32(data, read_g32s(), read_op8() & 31)); +} +static void instr16_0FAD() { read_modrm_byte(); + int32_t data = read_write_e16(); write_e16(shrd16(data, read_g16(), reg8[CL] & 31)); +} +static void instr32_0FAD() { read_modrm_byte(); + int32_t data = read_write_e32(); write_e32(shrd32(data, read_g32s(), reg8[CL] & 31)); +} + +static void instr_0FAE() { read_modrm_byte(); + // fxsave, fxrstor, ldmxcsr ... + + switch(modrm_byte[0] >> 3 & 7) + { + case 0: // fxsave + if(modrm_byte[0] >= 0xC0) trigger_ud(); + { + int32_t addr = modrm_resolve(modrm_byte[0]); + fxsave(addr); + } + break; + + case 1: // fxrstor + if(modrm_byte[0] >= 0xC0) trigger_ud(); + { + int32_t addr = modrm_resolve(modrm_byte[0]); + fxrstor(addr); + } + break; + + case 2: // ldmxcsr + if(modrm_byte[0] >= 0xC0) trigger_ud(); + { + int32_t addr = modrm_resolve(modrm_byte[0]); + int32_t new_mxcsr = safe_read32s(addr); + if(new_mxcsr & ~MXCSR_MASK) + { + //dbg_log("Invalid mxcsr bits: " + h((new_mxcsr & ~MXCSR_MASK), 8)); + assert(false); + trigger_gp(0); + } + *mxcsr = new_mxcsr; + } + break; + + case 3: // stmxcsr + if(modrm_byte[0] >= 0xC0) trigger_ud(); + { + int32_t addr = modrm_resolve(modrm_byte[0]); + safe_write32(addr, *mxcsr); + } + break; + + case 5: + // lfence + dbg_assert_message(modrm_byte[0] >= 0xC0, "Unexpected mfence encoding"); + if(modrm_byte[0] < 0xC0) trigger_ud(); + break; + + case 6: + // mfence + dbg_assert_message(modrm_byte[0] >= 0xC0, "Unexpected mfence encoding"); + if(modrm_byte[0] < 0xC0) trigger_ud(); + break; + + case 7: + // sfence or clflush + dbg_assert_message(modrm_byte[0] >= 0xC0, "Unexpected sfence encoding"); + if(modrm_byte[0] < 0xC0) trigger_ud(); + break; + + default: + //dbg_log("missing " + (modrm_byte[0] >> 3 & 7)); + todo(); + } +} + +static void instr16_0FAF() { read_modrm_byte(); + int32_t data = read_e16s(); + write_g16(imul_reg16(read_g16s(), data)); +} +static void instr32_0FAF() { read_modrm_byte(); + int32_t data = read_e32s(); + write_g32(imul_reg32(read_g32s(), data)); +} + + +static void instr_0FB0() { read_modrm_byte(); + // cmpxchg8 + int32_t data = 0; + int32_t virt_addr = 0; + if(modrm_byte[0] < 0xC0) + { + virt_addr = modrm_resolve(modrm_byte[0]); + writable_or_pagefault(virt_addr, 1); + + data = safe_read8(virt_addr); + } + else + data = reg8[modrm_byte[0] << 2 & 0xC | modrm_byte[0] >> 2 & 1]; + + + cmp8(reg8[AL], data); + + if(getzf()) + { + if(modrm_byte[0] < 0xC0) + safe_write8(virt_addr, read_g8()); + else + reg8[modrm_byte[0] << 2 & 0xC | modrm_byte[0] >> 2 & 1] = read_g8(); + } + else + { + if(modrm_byte[0] < 0xC0) + safe_write8(virt_addr, data); + + reg8[AL] = data; + } +} +static void instr16_0FB1() { read_modrm_byte(); + // cmpxchg16/32 + int32_t data = 0; + int32_t virt_addr = 0; + if(modrm_byte[0] < 0xC0) + { + virt_addr = modrm_resolve(modrm_byte[0]); + writable_or_pagefault(virt_addr, 2); + + data = safe_read16(virt_addr); + } + else + data = read_reg_e16(); + + cmp16(reg16[AX], data); + + if(getzf()) + { + if(modrm_byte[0] < 0xC0) + safe_write16(virt_addr, read_g16()); + else + write_reg_e16(read_g16()); + } + else + { + if(modrm_byte[0] < 0xC0) + safe_write16(virt_addr, data); + + reg16[AX] = data; + } +} +static void instr32_0FB1() { read_modrm_byte(); + int32_t virt_addr = 0; + int32_t data = 0; + if(modrm_byte[0] < 0xC0) + { + virt_addr = modrm_resolve(modrm_byte[0]); + writable_or_pagefault(virt_addr, 4); + + data = safe_read32s(virt_addr); + } + else + { + data = read_reg_e32s(); + } + + cmp32(reg32s[EAX], data); + + if(getzf()) + { + if(modrm_byte[0] < 0xC0) + safe_write32(virt_addr, read_g32s()); + else + write_reg_e32(read_g32s()); + } + else + { + if(modrm_byte[0] < 0xC0) + safe_write32(virt_addr, data); + + reg32s[EAX] = data; + } +} + +// lss +static void instr16_0FB2() { read_modrm_byte(); + lss16(SS); +} +static void instr32_0FB2() { read_modrm_byte(); + lss32(SS); +} + +static void instr16_0FB3() { read_modrm_byte(); + if(modrm_byte[0] < 0xC0) { + btr_mem(modrm_resolve(modrm_byte[0]), read_g16s()); + } else { + write_reg_e16(btr_reg(read_reg_e16(), read_g16s() & 15)); + } +} +static void instr32_0FB3() { read_modrm_byte(); + if(modrm_byte[0] < 0xC0) { + btr_mem(modrm_resolve(modrm_byte[0]), read_g32s()); + } else { + write_reg_e32(btr_reg(read_reg_e32s(), read_g32s() & 31)); + } +} + +// lfs, lgs +static void instr16_0FB4() { read_modrm_byte(); + lss16(FS); +} +static void instr32_0FB4() { read_modrm_byte(); + lss32(FS); +} +static void instr16_0FB5() { read_modrm_byte(); + lss16(GS); +} +static void instr32_0FB5() { read_modrm_byte(); + lss32(GS); +} + +static void instr16_0FB6() { read_modrm_byte(); + // movzx + int32_t data = read_e8(); + write_g16(data); +} +static void instr32_0FB6() { read_modrm_byte(); + int32_t data = read_e8(); + write_g32(data); +} + +static void instr16_0FB7() { read_modrm_byte(); + // movzx + dbg_assert_message(false, "Possibly invalid encoding"); + int32_t data = read_e16(); + write_g16(data); +} +static void instr32_0FB7() { read_modrm_byte(); + int32_t data = read_e16(); + write_g32(data); +} + +static void instr16_0FB8() { read_modrm_byte(); + // popcnt + int32_t data = read_e16(); + write_g16(popcnt(data)); +} +static void instr32_0FB8() { read_modrm_byte(); + int32_t data = read_e32s(); + write_g32(popcnt(data)); +} + +static void instr_0FB9() { + // UD + todo(); +} + +static void instr16_0FBA() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 4: + if(modrm_byte[0] < 0xC0) + { + bt_mem(modrm_resolve(modrm_byte[0]), read_op8() & 15); + } + else + { + bt_reg(read_reg_e16(), read_op8() & 15); + } + break; + case 5: + if(modrm_byte[0] < 0xC0) { + bts_mem(modrm_resolve(modrm_byte[0]), read_op8() & 15); + } else { + write_reg_e16(bts_reg(read_reg_e16(), read_op8() & 15)); + } + break; + case 6: + if(modrm_byte[0] < 0xC0) { + btr_mem(modrm_resolve(modrm_byte[0]), read_op8() & 15); + } else { + write_reg_e16(btr_reg(read_reg_e16(), read_op8() & 15)); + } + break; + case 7: + if(modrm_byte[0] < 0xC0) { + btc_mem(modrm_resolve(modrm_byte[0]), read_op8() & 15); + } else { + write_reg_e16(btc_reg(read_reg_e16(), read_op8() & 15)); + } + break; + default: + dbg_log("%d", modrm_byte[0] >> 3 & 7); + todo(); + } +} +static void instr32_0FBA() { read_modrm_byte(); + switch(modrm_byte[0] >> 3 & 7) + { + case 4: + if(modrm_byte[0] < 0xC0) + { + bt_mem(modrm_resolve(modrm_byte[0]), read_op8() & 31); + } + else + { + bt_reg(read_reg_e32s(), read_op8() & 31); + } + break; + case 5: + if(modrm_byte[0] < 0xC0) { + bts_mem(modrm_resolve(modrm_byte[0]), read_op8() & 31); + } else { + write_reg_e32(bts_reg(read_reg_e32s(), read_op8() & 31)); + } + break; + case 6: + if(modrm_byte[0] < 0xC0) { + btr_mem(modrm_resolve(modrm_byte[0]), read_op8() & 31); + } else { + write_reg_e32(btr_reg(read_reg_e32s(), read_op8() & 31)); + } + break; + case 7: + if(modrm_byte[0] < 0xC0) { + btc_mem(modrm_resolve(modrm_byte[0]), read_op8() & 31); + } else { + write_reg_e32(btc_reg(read_reg_e32s(), read_op8() & 31)); + } + break; + default: + dbg_log("%d", modrm_byte[0] >> 3 & 7); + todo(); + } +} + +static void instr16_0FBB() { read_modrm_byte(); + if(modrm_byte[0] < 0xC0) { + btc_mem(modrm_resolve(modrm_byte[0]), read_g16s()); + } else { + write_reg_e16(btc_reg(read_reg_e16(), read_g16s() & 15)); + } +} +static void instr32_0FBB() { read_modrm_byte(); + if(modrm_byte[0] < 0xC0) { + btc_mem(modrm_resolve(modrm_byte[0]), read_g32s()); + } else { + write_reg_e32(btc_reg(read_reg_e32s(), read_g32s() & 31)); + } +} + +static void instr16_0FBC() { read_modrm_byte(); + int32_t data = read_e16(); + write_g16(bsf16(read_g16(), data)); +} +static void instr32_0FBC() { read_modrm_byte(); + int32_t data = read_e32s(); + write_g32(bsf32(read_g32s(), data)); +} + +static void instr16_0FBD() { read_modrm_byte(); + int32_t data = read_e16(); + write_g16(bsr16(read_g16(), data)); +} +static void instr32_0FBD() { read_modrm_byte(); + int32_t data = read_e32s(); + write_g32(bsr32(read_g32s(), data)); +} + +static void instr16_0FBE() { read_modrm_byte(); + // movsx + int32_t data = read_e8s(); + write_g16(data); +} +static void instr32_0FBE() { read_modrm_byte(); + int32_t data = read_e8s(); + write_g32(data); +} + +static void instr16_0FBF() { read_modrm_byte(); + // movsx + dbg_assert_message(false, "Possibly invalid encoding"); + int32_t data = read_e16(); + write_g16(data); +} + +static void instr32_0FBF() { read_modrm_byte(); + int32_t data = read_e16s(); + write_g32(data); +} + +static void instr_0FC0() { read_modrm_byte(); + int32_t data = read_write_e8(); write_e8(xadd8(data, modrm_byte[0] >> 1 & 0xC | modrm_byte[0] >> 5 & 1)); +} + +static void instr16_0FC1() { read_modrm_byte(); + int32_t data = read_write_e16(); + write_e16(xadd16(data, modrm_byte[0] >> 2 & 14)); +} +static void instr32_0FC1() { read_modrm_byte(); + int32_t data = read_write_e32(); + write_e32(xadd32(data, modrm_byte[0] >> 3 & 7)); +} + + +static void instr_0FC2() { unimplemented_sse(); } +static void instr_0FC3() { unimplemented_sse(); } +static void instr_0FC4() { unimplemented_sse(); } +static void instr_0FC5() { unimplemented_sse(); } +static void instr_0FC6() { unimplemented_sse(); } + +static void instr_0FC7() { + read_modrm_byte(); + + switch(modrm_byte[0] >> 3 & 7) + { + case 1: + // cmpxchg8b + if(modrm_byte[0] >= 0xC0) + { + trigger_ud(); + } + + int32_t addr = modrm_resolve(modrm_byte[0]); + writable_or_pagefault(addr, 8); + + int32_t m64_low = safe_read32s(addr); + int32_t m64_high = safe_read32s(addr + 4); + + if(reg32s[EAX] == m64_low && + reg32s[EDX] == m64_high) + { + flags[0] |= FLAG_ZERO; + + safe_write32(addr, reg32s[EBX]); + safe_write32(addr + 4, reg32s[ECX]); + } + else + { + flags[0] &= ~FLAG_ZERO; + + reg32s[EAX] = m64_low; + reg32s[EDX] = m64_high; + + safe_write32(addr, m64_low); + safe_write32(addr + 4, m64_high); + } + + flags_changed[0] &= ~FLAG_ZERO; + break; + + case 6: + { + int32_t has_rand = has_rand_int(); + + int32_t rand = 0; + if(has_rand) + { + rand = get_rand_int(); + } + //dbg_log("rdrand -> " + h(rand, 8)); + + if(is_osize_32()) + { + set_e32(rand); + } + else + { + set_e16(rand); + } + + flags[0] &= ~FLAGS_ALL; + flags[0] |= has_rand; + flags_changed[0] = 0; + } + break; + + default: + dbg_log("%d", modrm_byte[0] >> 3 & 7); + todo(); + } +} + +static void instr_0FC8() { bswap(EAX); } +static void instr_0FC9() { bswap(ECX); } +static void instr_0FCA() { bswap(EDX); } +static void instr_0FCB() { bswap(EBX); } +static void instr_0FCC() { bswap(ESP); } +static void instr_0FCD() { bswap(EBP); } +static void instr_0FCE() { bswap(ESI); } +static void instr_0FCF() { bswap(EDI); } + +static void instr_0FD0() { unimplemented_sse(); } +static void instr_0FD1() { unimplemented_sse(); } +static void instr_0FD2() { unimplemented_sse(); } +static void instr_0FD3() { unimplemented_sse(); } +static void instr_0FD4() { unimplemented_sse(); } +static void instr_0FD5() { unimplemented_sse(); } +static void instr_0FD6() { unimplemented_sse(); } +static void instr_0FD7() { unimplemented_sse(); } + +static void instr_0FD8() { unimplemented_sse(); } +static void instr_0FD9() { unimplemented_sse(); } +static void instr_0FDA() { unimplemented_sse(); } +static void instr_0FDB() { unimplemented_sse(); } +static void instr_0FDC() { unimplemented_sse(); } +static void instr_0FDD() { unimplemented_sse(); } +static void instr_0FDE() { unimplemented_sse(); } +static void instr_0FDF() { unimplemented_sse(); } + +static void instr_0FE0() { unimplemented_sse(); } +static void instr_0FE1() { unimplemented_sse(); } +static void instr_0FE2() { unimplemented_sse(); } +static void instr_0FE3() { unimplemented_sse(); } +static void instr_0FE4() { unimplemented_sse(); } +static void instr_0FE5() { unimplemented_sse(); } +static void instr_0FE6() { unimplemented_sse(); } +static void instr_0FE7() { unimplemented_sse(); } + +static void instr_0FE8() { unimplemented_sse(); } +static void instr_0FE9() { unimplemented_sse(); } +static void instr_0FEA() { unimplemented_sse(); } +static void instr_0FEB() { unimplemented_sse(); } +static void instr_0FEC() { unimplemented_sse(); } +static void instr_0FED() { unimplemented_sse(); } +static void instr_0FEE() { unimplemented_sse(); } +static void instr_0FEF() { unimplemented_sse(); } + +static void instr_0FF0() { unimplemented_sse(); } +static void instr_0FF1() { unimplemented_sse(); } +static void instr_0FF2() { unimplemented_sse(); } +static void instr_0FF3() { unimplemented_sse(); } +static void instr_0FF4() { unimplemented_sse(); } +static void instr_0FF5() { unimplemented_sse(); } +static void instr_0FF6() { unimplemented_sse(); } +static void instr_0FF7() { unimplemented_sse(); } + +static void instr_0FF8() { unimplemented_sse(); } +static void instr_0FF9() { unimplemented_sse(); } +static void instr_0FFA() { unimplemented_sse(); } +static void instr_0FFB() { unimplemented_sse(); } +static void instr_0FFC() { unimplemented_sse(); } +static void instr_0FFD() { unimplemented_sse(); } +static void instr_0FFE() { unimplemented_sse(); } + +static void instr_0FFF() { + // Windows 98 + dbg_log("#ud: 0F FF"); + trigger_ud(); +} + + +static void run_instruction0f_16(int32_t opcode) +{ + // XXX: This table is generated. Don't modify + switch(opcode) + { +case 0x00: + instr_0F00(); + break; +case 0x01: + instr_0F01(); + break; +case 0x02: + instr16_0F02(); + break; +case 0x03: + instr16_0F03(); + break; +case 0x04: + instr_0F04(); + break; +case 0x05: + instr_0F05(); + break; +case 0x06: + instr_0F06(); + break; +case 0x07: + instr_0F07(); + break; +case 0x08: + instr_0F08(); + break; +case 0x09: + instr_0F09(); + break; +case 0x0A: + instr_0F0A(); + break; +case 0x0B: + instr_0F0B(); + break; +case 0x0C: + instr_0F0C(); + break; +case 0x0D: + instr_0F0D(); + break; +case 0x0E: + instr_0F0E(); + break; +case 0x0F: + instr_0F0F(); + break; +case 0x10: + instr_0F10(); + break; +case 0x11: + instr_0F11(); + break; +case 0x12: + instr_0F12(); + break; +case 0x13: + instr_0F13(); + break; +case 0x14: + instr_0F14(); + break; +case 0x15: + instr_0F15(); + break; +case 0x16: + instr_0F16(); + break; +case 0x17: + instr_0F17(); + break; +case 0x18: + instr_0F18(); + break; +case 0x19: + instr_0F19(); + break; +case 0x1A: + instr_0F1A(); + break; +case 0x1B: + instr_0F1B(); + break; +case 0x1C: + instr_0F1C(); + break; +case 0x1D: + instr_0F1D(); + break; +case 0x1E: + instr_0F1E(); + break; +case 0x1F: + instr_0F1F(); + break; +case 0x20: + instr_0F20(); + break; +case 0x21: + instr_0F21(); + break; +case 0x22: + instr_0F22(); + break; +case 0x23: + instr_0F23(); + break; +case 0x24: + instr_0F24(); + break; +case 0x25: + instr_0F25(); + break; +case 0x26: + instr_0F26(); + break; +case 0x27: + instr_0F27(); + break; +case 0x28: + instr_0F28(); + break; +case 0x29: + instr_0F29(); + break; +case 0x2A: + instr_0F2A(); + break; +case 0x2B: + instr_0F2B(); + break; +case 0x2C: + instr_0F2C(); + break; +case 0x2D: + instr_0F2D(); + break; +case 0x2E: + instr_0F2E(); + break; +case 0x2F: + instr_0F2F(); + break; +case 0x30: + instr_0F30(); + break; +case 0x31: + instr_0F31(); + break; +case 0x32: + instr_0F32(); + break; +case 0x33: + instr_0F33(); + break; +case 0x34: + instr_0F34(); + break; +case 0x35: + instr_0F35(); + break; +case 0x36: + instr_0F36(); + break; +case 0x37: + instr_0F37(); + break; +case 0x38: + instr_0F38(); + break; +case 0x39: + instr_0F39(); + break; +case 0x3A: + instr_0F3A(); + break; +case 0x3B: + instr_0F3B(); + break; +case 0x3C: + instr_0F3C(); + break; +case 0x3D: + instr_0F3D(); + break; +case 0x3E: + instr_0F3E(); + break; +case 0x3F: + instr_0F3F(); + break; +case 0x40: + instr16_0F40(); + break; +case 0x41: + instr16_0F41(); + break; +case 0x42: + instr16_0F42(); + break; +case 0x43: + instr16_0F43(); + break; +case 0x44: + instr16_0F44(); + break; +case 0x45: + instr16_0F45(); + break; +case 0x46: + instr16_0F46(); + break; +case 0x47: + instr16_0F47(); + break; +case 0x48: + instr16_0F48(); + break; +case 0x49: + instr16_0F49(); + break; +case 0x4A: + instr16_0F4A(); + break; +case 0x4B: + instr16_0F4B(); + break; +case 0x4C: + instr16_0F4C(); + break; +case 0x4D: + instr16_0F4D(); + break; +case 0x4E: + instr16_0F4E(); + break; +case 0x4F: + instr16_0F4F(); + break; +case 0x50: + instr_0F50(); + break; +case 0x51: + instr_0F51(); + break; +case 0x52: + instr_0F52(); + break; +case 0x53: + instr_0F53(); + break; +case 0x54: + instr_0F54(); + break; +case 0x55: + instr_0F55(); + break; +case 0x56: + instr_0F56(); + break; +case 0x57: + instr_0F57(); + break; +case 0x58: + instr_0F58(); + break; +case 0x59: + instr_0F59(); + break; +case 0x5A: + instr_0F5A(); + break; +case 0x5B: + instr_0F5B(); + break; +case 0x5C: + instr_0F5C(); + break; +case 0x5D: + instr_0F5D(); + break; +case 0x5E: + instr_0F5E(); + break; +case 0x5F: + instr_0F5F(); + break; +case 0x60: + instr_0F60(); + break; +case 0x61: + instr_0F61(); + break; +case 0x62: + instr_0F62(); + break; +case 0x63: + instr_0F63(); + break; +case 0x64: + instr_0F64(); + break; +case 0x65: + instr_0F65(); + break; +case 0x66: + instr_0F66(); + break; +case 0x67: + instr_0F67(); + break; +case 0x68: + instr_0F68(); + break; +case 0x69: + instr_0F69(); + break; +case 0x6A: + instr_0F6A(); + break; +case 0x6B: + instr_0F6B(); + break; +case 0x6C: + instr_0F6C(); + break; +case 0x6D: + instr_0F6D(); + break; +case 0x6E: + instr_0F6E(); + break; +case 0x6F: + instr_0F6F(); + break; +case 0x70: + instr_0F70(); + break; +case 0x71: + instr_0F71(); + break; +case 0x72: + instr_0F72(); + break; +case 0x73: + instr_0F73(); + break; +case 0x74: + instr_0F74(); + break; +case 0x75: + instr_0F75(); + break; +case 0x76: + instr_0F76(); + break; +case 0x77: + instr_0F77(); + break; +case 0x78: + instr_0F78(); + break; +case 0x79: + instr_0F79(); + break; +case 0x7A: + instr_0F7A(); + break; +case 0x7B: + instr_0F7B(); + break; +case 0x7C: + instr_0F7C(); + break; +case 0x7D: + instr_0F7D(); + break; +case 0x7E: + instr_0F7E(); + break; +case 0x7F: + instr_0F7F(); + break; +case 0x80: + instr16_0F80(); + break; +case 0x81: + instr16_0F81(); + break; +case 0x82: + instr16_0F82(); + break; +case 0x83: + instr16_0F83(); + break; +case 0x84: + instr16_0F84(); + break; +case 0x85: + instr16_0F85(); + break; +case 0x86: + instr16_0F86(); + break; +case 0x87: + instr16_0F87(); + break; +case 0x88: + instr16_0F88(); + break; +case 0x89: + instr16_0F89(); + break; +case 0x8A: + instr16_0F8A(); + break; +case 0x8B: + instr16_0F8B(); + break; +case 0x8C: + instr16_0F8C(); + break; +case 0x8D: + instr16_0F8D(); + break; +case 0x8E: + instr16_0F8E(); + break; +case 0x8F: + instr16_0F8F(); + break; +case 0x90: + instr_0F90(); + break; +case 0x91: + instr_0F91(); + break; +case 0x92: + instr_0F92(); + break; +case 0x93: + instr_0F93(); + break; +case 0x94: + instr_0F94(); + break; +case 0x95: + instr_0F95(); + break; +case 0x96: + instr_0F96(); + break; +case 0x97: + instr_0F97(); + break; +case 0x98: + instr_0F98(); + break; +case 0x99: + instr_0F99(); + break; +case 0x9A: + instr_0F9A(); + break; +case 0x9B: + instr_0F9B(); + break; +case 0x9C: + instr_0F9C(); + break; +case 0x9D: + instr_0F9D(); + break; +case 0x9E: + instr_0F9E(); + break; +case 0x9F: + instr_0F9F(); + break; +case 0xA0: + instr16_0FA0(); + break; +case 0xA1: + instr16_0FA1(); + break; +case 0xA2: + instr_0FA2(); + break; +case 0xA3: + instr16_0FA3(); + break; +case 0xA4: + instr16_0FA4(); + break; +case 0xA5: + instr16_0FA5(); + break; +case 0xA6: + instr_0FA6(); + break; +case 0xA7: + instr_0FA7(); + break; +case 0xA8: + instr16_0FA8(); + break; +case 0xA9: + instr16_0FA9(); + break; +case 0xAA: + instr_0FAA(); + break; +case 0xAB: + instr16_0FAB(); + break; +case 0xAC: + instr16_0FAC(); + break; +case 0xAD: + instr16_0FAD(); + break; +case 0xAE: + instr_0FAE(); + break; +case 0xAF: + instr16_0FAF(); + break; +case 0xB0: + instr_0FB0(); + break; +case 0xB1: + instr16_0FB1(); + break; +case 0xB2: + instr16_0FB2(); + break; +case 0xB3: + instr16_0FB3(); + break; +case 0xB4: + instr16_0FB4(); + break; +case 0xB5: + instr16_0FB5(); + break; +case 0xB6: + instr16_0FB6(); + break; +case 0xB7: + instr16_0FB7(); + break; +case 0xB8: + instr16_0FB8(); + break; +case 0xB9: + instr_0FB9(); + break; +case 0xBA: + instr16_0FBA(); + break; +case 0xBB: + instr16_0FBB(); + break; +case 0xBC: + instr16_0FBC(); + break; +case 0xBD: + instr16_0FBD(); + break; +case 0xBE: + instr16_0FBE(); + break; +case 0xBF: + instr16_0FBF(); + break; +case 0xC0: + instr_0FC0(); + break; +case 0xC1: + instr16_0FC1(); + break; +case 0xC2: + instr_0FC2(); + break; +case 0xC3: + instr_0FC3(); + break; +case 0xC4: + instr_0FC4(); + break; +case 0xC5: + instr_0FC5(); + break; +case 0xC6: + instr_0FC6(); + break; +case 0xC7: + instr_0FC7(); + break; +case 0xC8: + instr_0FC8(); + break; +case 0xC9: + instr_0FC9(); + break; +case 0xCA: + instr_0FCA(); + break; +case 0xCB: + instr_0FCB(); + break; +case 0xCC: + instr_0FCC(); + break; +case 0xCD: + instr_0FCD(); + break; +case 0xCE: + instr_0FCE(); + break; +case 0xCF: + instr_0FCF(); + break; +case 0xD0: + instr_0FD0(); + break; +case 0xD1: + instr_0FD1(); + break; +case 0xD2: + instr_0FD2(); + break; +case 0xD3: + instr_0FD3(); + break; +case 0xD4: + instr_0FD4(); + break; +case 0xD5: + instr_0FD5(); + break; +case 0xD6: + instr_0FD6(); + break; +case 0xD7: + instr_0FD7(); + break; +case 0xD8: + instr_0FD8(); + break; +case 0xD9: + instr_0FD9(); + break; +case 0xDA: + instr_0FDA(); + break; +case 0xDB: + instr_0FDB(); + break; +case 0xDC: + instr_0FDC(); + break; +case 0xDD: + instr_0FDD(); + break; +case 0xDE: + instr_0FDE(); + break; +case 0xDF: + instr_0FDF(); + break; +case 0xE0: + instr_0FE0(); + break; +case 0xE1: + instr_0FE1(); + break; +case 0xE2: + instr_0FE2(); + break; +case 0xE3: + instr_0FE3(); + break; +case 0xE4: + instr_0FE4(); + break; +case 0xE5: + instr_0FE5(); + break; +case 0xE6: + instr_0FE6(); + break; +case 0xE7: + instr_0FE7(); + break; +case 0xE8: + instr_0FE8(); + break; +case 0xE9: + instr_0FE9(); + break; +case 0xEA: + instr_0FEA(); + break; +case 0xEB: + instr_0FEB(); + break; +case 0xEC: + instr_0FEC(); + break; +case 0xED: + instr_0FED(); + break; +case 0xEE: + instr_0FEE(); + break; +case 0xEF: + instr_0FEF(); + break; +case 0xF0: + instr_0FF0(); + break; +case 0xF1: + instr_0FF1(); + break; +case 0xF2: + instr_0FF2(); + break; +case 0xF3: + instr_0FF3(); + break; +case 0xF4: + instr_0FF4(); + break; +case 0xF5: + instr_0FF5(); + break; +case 0xF6: + instr_0FF6(); + break; +case 0xF7: + instr_0FF7(); + break; +case 0xF8: + instr_0FF8(); + break; +case 0xF9: + instr_0FF9(); + break; +case 0xFA: + instr_0FFA(); + break; +case 0xFB: + instr_0FFB(); + break; +case 0xFC: + instr_0FFC(); + break; +case 0xFD: + instr_0FFD(); + break; +case 0xFE: + instr_0FFE(); + break; +case 0xFF: + instr_0FFF(); + break; +default: assert(false); + } +} + +static void run_instruction0f_32(int32_t opcode) +{ + // XXX: This table is generated. Don't modify + switch(opcode) + { +case 0x00: + instr_0F00(); + break; +case 0x01: + instr_0F01(); + break; +case 0x02: + instr32_0F02(); + break; +case 0x03: + instr32_0F03(); + break; +case 0x04: + instr_0F04(); + break; +case 0x05: + instr_0F05(); + break; +case 0x06: + instr_0F06(); + break; +case 0x07: + instr_0F07(); + break; +case 0x08: + instr_0F08(); + break; +case 0x09: + instr_0F09(); + break; +case 0x0A: + instr_0F0A(); + break; +case 0x0B: + instr_0F0B(); + break; +case 0x0C: + instr_0F0C(); + break; +case 0x0D: + instr_0F0D(); + break; +case 0x0E: + instr_0F0E(); + break; +case 0x0F: + instr_0F0F(); + break; +case 0x10: + instr_0F10(); + break; +case 0x11: + instr_0F11(); + break; +case 0x12: + instr_0F12(); + break; +case 0x13: + instr_0F13(); + break; +case 0x14: + instr_0F14(); + break; +case 0x15: + instr_0F15(); + break; +case 0x16: + instr_0F16(); + break; +case 0x17: + instr_0F17(); + break; +case 0x18: + instr_0F18(); + break; +case 0x19: + instr_0F19(); + break; +case 0x1A: + instr_0F1A(); + break; +case 0x1B: + instr_0F1B(); + break; +case 0x1C: + instr_0F1C(); + break; +case 0x1D: + instr_0F1D(); + break; +case 0x1E: + instr_0F1E(); + break; +case 0x1F: + instr_0F1F(); + break; +case 0x20: + instr_0F20(); + break; +case 0x21: + instr_0F21(); + break; +case 0x22: + instr_0F22(); + break; +case 0x23: + instr_0F23(); + break; +case 0x24: + instr_0F24(); + break; +case 0x25: + instr_0F25(); + break; +case 0x26: + instr_0F26(); + break; +case 0x27: + instr_0F27(); + break; +case 0x28: + instr_0F28(); + break; +case 0x29: + instr_0F29(); + break; +case 0x2A: + instr_0F2A(); + break; +case 0x2B: + instr_0F2B(); + break; +case 0x2C: + instr_0F2C(); + break; +case 0x2D: + instr_0F2D(); + break; +case 0x2E: + instr_0F2E(); + break; +case 0x2F: + instr_0F2F(); + break; +case 0x30: + instr_0F30(); + break; +case 0x31: + instr_0F31(); + break; +case 0x32: + instr_0F32(); + break; +case 0x33: + instr_0F33(); + break; +case 0x34: + instr_0F34(); + break; +case 0x35: + instr_0F35(); + break; +case 0x36: + instr_0F36(); + break; +case 0x37: + instr_0F37(); + break; +case 0x38: + instr_0F38(); + break; +case 0x39: + instr_0F39(); + break; +case 0x3A: + instr_0F3A(); + break; +case 0x3B: + instr_0F3B(); + break; +case 0x3C: + instr_0F3C(); + break; +case 0x3D: + instr_0F3D(); + break; +case 0x3E: + instr_0F3E(); + break; +case 0x3F: + instr_0F3F(); + break; +case 0x40: + instr32_0F40(); + break; +case 0x41: + instr32_0F41(); + break; +case 0x42: + instr32_0F42(); + break; +case 0x43: + instr32_0F43(); + break; +case 0x44: + instr32_0F44(); + break; +case 0x45: + instr32_0F45(); + break; +case 0x46: + instr32_0F46(); + break; +case 0x47: + instr32_0F47(); + break; +case 0x48: + instr32_0F48(); + break; +case 0x49: + instr32_0F49(); + break; +case 0x4A: + instr32_0F4A(); + break; +case 0x4B: + instr32_0F4B(); + break; +case 0x4C: + instr32_0F4C(); + break; +case 0x4D: + instr32_0F4D(); + break; +case 0x4E: + instr32_0F4E(); + break; +case 0x4F: + instr32_0F4F(); + break; +case 0x50: + instr_0F50(); + break; +case 0x51: + instr_0F51(); + break; +case 0x52: + instr_0F52(); + break; +case 0x53: + instr_0F53(); + break; +case 0x54: + instr_0F54(); + break; +case 0x55: + instr_0F55(); + break; +case 0x56: + instr_0F56(); + break; +case 0x57: + instr_0F57(); + break; +case 0x58: + instr_0F58(); + break; +case 0x59: + instr_0F59(); + break; +case 0x5A: + instr_0F5A(); + break; +case 0x5B: + instr_0F5B(); + break; +case 0x5C: + instr_0F5C(); + break; +case 0x5D: + instr_0F5D(); + break; +case 0x5E: + instr_0F5E(); + break; +case 0x5F: + instr_0F5F(); + break; +case 0x60: + instr_0F60(); + break; +case 0x61: + instr_0F61(); + break; +case 0x62: + instr_0F62(); + break; +case 0x63: + instr_0F63(); + break; +case 0x64: + instr_0F64(); + break; +case 0x65: + instr_0F65(); + break; +case 0x66: + instr_0F66(); + break; +case 0x67: + instr_0F67(); + break; +case 0x68: + instr_0F68(); + break; +case 0x69: + instr_0F69(); + break; +case 0x6A: + instr_0F6A(); + break; +case 0x6B: + instr_0F6B(); + break; +case 0x6C: + instr_0F6C(); + break; +case 0x6D: + instr_0F6D(); + break; +case 0x6E: + instr_0F6E(); + break; +case 0x6F: + instr_0F6F(); + break; +case 0x70: + instr_0F70(); + break; +case 0x71: + instr_0F71(); + break; +case 0x72: + instr_0F72(); + break; +case 0x73: + instr_0F73(); + break; +case 0x74: + instr_0F74(); + break; +case 0x75: + instr_0F75(); + break; +case 0x76: + instr_0F76(); + break; +case 0x77: + instr_0F77(); + break; +case 0x78: + instr_0F78(); + break; +case 0x79: + instr_0F79(); + break; +case 0x7A: + instr_0F7A(); + break; +case 0x7B: + instr_0F7B(); + break; +case 0x7C: + instr_0F7C(); + break; +case 0x7D: + instr_0F7D(); + break; +case 0x7E: + instr_0F7E(); + break; +case 0x7F: + instr_0F7F(); + break; +case 0x80: + instr32_0F80(); + break; +case 0x81: + instr32_0F81(); + break; +case 0x82: + instr32_0F82(); + break; +case 0x83: + instr32_0F83(); + break; +case 0x84: + instr32_0F84(); + break; +case 0x85: + instr32_0F85(); + break; +case 0x86: + instr32_0F86(); + break; +case 0x87: + instr32_0F87(); + break; +case 0x88: + instr32_0F88(); + break; +case 0x89: + instr32_0F89(); + break; +case 0x8A: + instr32_0F8A(); + break; +case 0x8B: + instr32_0F8B(); + break; +case 0x8C: + instr32_0F8C(); + break; +case 0x8D: + instr32_0F8D(); + break; +case 0x8E: + instr32_0F8E(); + break; +case 0x8F: + instr32_0F8F(); + break; +case 0x90: + instr_0F90(); + break; +case 0x91: + instr_0F91(); + break; +case 0x92: + instr_0F92(); + break; +case 0x93: + instr_0F93(); + break; +case 0x94: + instr_0F94(); + break; +case 0x95: + instr_0F95(); + break; +case 0x96: + instr_0F96(); + break; +case 0x97: + instr_0F97(); + break; +case 0x98: + instr_0F98(); + break; +case 0x99: + instr_0F99(); + break; +case 0x9A: + instr_0F9A(); + break; +case 0x9B: + instr_0F9B(); + break; +case 0x9C: + instr_0F9C(); + break; +case 0x9D: + instr_0F9D(); + break; +case 0x9E: + instr_0F9E(); + break; +case 0x9F: + instr_0F9F(); + break; +case 0xA0: + instr32_0FA0(); + break; +case 0xA1: + instr32_0FA1(); + break; +case 0xA2: + instr_0FA2(); + break; +case 0xA3: + instr32_0FA3(); + break; +case 0xA4: + instr32_0FA4(); + break; +case 0xA5: + instr32_0FA5(); + break; +case 0xA6: + instr_0FA6(); + break; +case 0xA7: + instr_0FA7(); + break; +case 0xA8: + instr32_0FA8(); + break; +case 0xA9: + instr32_0FA9(); + break; +case 0xAA: + instr_0FAA(); + break; +case 0xAB: + instr32_0FAB(); + break; +case 0xAC: + instr32_0FAC(); + break; +case 0xAD: + instr32_0FAD(); + break; +case 0xAE: + instr_0FAE(); + break; +case 0xAF: + instr32_0FAF(); + break; +case 0xB0: + instr_0FB0(); + break; +case 0xB1: + instr32_0FB1(); + break; +case 0xB2: + instr32_0FB2(); + break; +case 0xB3: + instr32_0FB3(); + break; +case 0xB4: + instr32_0FB4(); + break; +case 0xB5: + instr32_0FB5(); + break; +case 0xB6: + instr32_0FB6(); + break; +case 0xB7: + instr32_0FB7(); + break; +case 0xB8: + instr32_0FB8(); + break; +case 0xB9: + instr_0FB9(); + break; +case 0xBA: + instr32_0FBA(); + break; +case 0xBB: + instr32_0FBB(); + break; +case 0xBC: + instr32_0FBC(); + break; +case 0xBD: + instr32_0FBD(); + break; +case 0xBE: + instr32_0FBE(); + break; +case 0xBF: + instr32_0FBF(); + break; +case 0xC0: + instr_0FC0(); + break; +case 0xC1: + instr32_0FC1(); + break; +case 0xC2: + instr_0FC2(); + break; +case 0xC3: + instr_0FC3(); + break; +case 0xC4: + instr_0FC4(); + break; +case 0xC5: + instr_0FC5(); + break; +case 0xC6: + instr_0FC6(); + break; +case 0xC7: + instr_0FC7(); + break; +case 0xC8: + instr_0FC8(); + break; +case 0xC9: + instr_0FC9(); + break; +case 0xCA: + instr_0FCA(); + break; +case 0xCB: + instr_0FCB(); + break; +case 0xCC: + instr_0FCC(); + break; +case 0xCD: + instr_0FCD(); + break; +case 0xCE: + instr_0FCE(); + break; +case 0xCF: + instr_0FCF(); + break; +case 0xD0: + instr_0FD0(); + break; +case 0xD1: + instr_0FD1(); + break; +case 0xD2: + instr_0FD2(); + break; +case 0xD3: + instr_0FD3(); + break; +case 0xD4: + instr_0FD4(); + break; +case 0xD5: + instr_0FD5(); + break; +case 0xD6: + instr_0FD6(); + break; +case 0xD7: + instr_0FD7(); + break; +case 0xD8: + instr_0FD8(); + break; +case 0xD9: + instr_0FD9(); + break; +case 0xDA: + instr_0FDA(); + break; +case 0xDB: + instr_0FDB(); + break; +case 0xDC: + instr_0FDC(); + break; +case 0xDD: + instr_0FDD(); + break; +case 0xDE: + instr_0FDE(); + break; +case 0xDF: + instr_0FDF(); + break; +case 0xE0: + instr_0FE0(); + break; +case 0xE1: + instr_0FE1(); + break; +case 0xE2: + instr_0FE2(); + break; +case 0xE3: + instr_0FE3(); + break; +case 0xE4: + instr_0FE4(); + break; +case 0xE5: + instr_0FE5(); + break; +case 0xE6: + instr_0FE6(); + break; +case 0xE7: + instr_0FE7(); + break; +case 0xE8: + instr_0FE8(); + break; +case 0xE9: + instr_0FE9(); + break; +case 0xEA: + instr_0FEA(); + break; +case 0xEB: + instr_0FEB(); + break; +case 0xEC: + instr_0FEC(); + break; +case 0xED: + instr_0FED(); + break; +case 0xEE: + instr_0FEE(); + break; +case 0xEF: + instr_0FEF(); + break; +case 0xF0: + instr_0FF0(); + break; +case 0xF1: + instr_0FF1(); + break; +case 0xF2: + instr_0FF2(); + break; +case 0xF3: + instr_0FF3(); + break; +case 0xF4: + instr_0FF4(); + break; +case 0xF5: + instr_0FF5(); + break; +case 0xF6: + instr_0FF6(); + break; +case 0xF7: + instr_0FF7(); + break; +case 0xF8: + instr_0FF8(); + break; +case 0xF9: + instr_0FF9(); + break; +case 0xFA: + instr_0FFA(); + break; +case 0xFB: + instr_0FFB(); + break; +case 0xFC: + instr_0FFC(); + break; +case 0xFD: + instr_0FFD(); + break; +case 0xFE: + instr_0FFE(); + break; +case 0xFF: + instr_0FFF(); + break; +default: assert(false); + } +} diff --git a/src/native/log.c b/src/native/log.c new file mode 100644 index 00000000..24a673bb --- /dev/null +++ b/src/native/log.c @@ -0,0 +1,13 @@ +#include +#include +#include +#include + +#include + +#include "const.h" +#include "global_pointers.h" + +#define dbg_log(...) { if(DEBUG) { printf(__VA_ARGS__); } } +#define dbg_assert(condition) { if(DEBUG) { assert(condition); } } +#define dbg_assert_message(condition, message) { if(DEBUG && !(condition)) { dbg_log(message); assert(false); } } diff --git a/src/native/memory.c b/src/native/memory.c new file mode 100644 index 00000000..1f049f08 --- /dev/null +++ b/src/native/memory.c @@ -0,0 +1,112 @@ +#include + +bool in_mapped_range(uint32_t addr) +{ + return (addr >= 0xA0000 && addr < 0xC0000) || addr >= *memory_size; +} + +int32_t mmap_read8(uint32_t); +int32_t mmap_read16(uint32_t); +int32_t mmap_read32(uint32_t); +void mmap_write8(uint32_t, uint8_t); +void mmap_write16(uint32_t, uint16_t); +void mmap_write32(uint32_t, uint32_t); + +int32_t read8(uint32_t addr) +{ + if(USE_A20 && *a20_enabled) addr &= A20_MASK; + + if(in_mapped_range(addr)) + { + return mmap_read8(addr); + } + else + { + return mem8[addr]; + } +} + +int32_t read16(uint32_t addr) +{ + if(USE_A20 && !*a20_enabled) addr &= A20_MASK; + + if(in_mapped_range(addr)) + { + return mmap_read16(addr); + } + else + { + return *(uint16_t*)(mem8 + addr); + } +} + +uint16_t read_aligned16(uint32_t addr) +{ + dbg_assert(addr >= 0 && addr < 0x80000000); + if(USE_A20 && !*a20_enabled) addr &= A20_MASK16; + + if(in_mapped_range(addr << 1)) + { + return mmap_read16(addr << 1); + } + else + { + return mem16[addr]; + } +} + +int32_t read32s(uint32_t addr) +{ + if(USE_A20 && *a20_enabled) addr &= A20_MASK; + + if(in_mapped_range(addr)) + { + return mmap_read32(addr); + } + else + { + return *(int32_t*)(mem8 + addr); + } +} + +void write8(uint32_t addr, uint8_t value) +{ + if(USE_A20 && !*a20_enabled) addr &= A20_MASK; + + if(in_mapped_range(addr)) + { + mmap_write8(addr, value); + } + else + { + mem8[addr] = value; + } +} + +void write16(uint32_t addr, uint16_t value) +{ + if(USE_A20 && !*a20_enabled) addr &= A20_MASK; + + if(in_mapped_range(addr)) + { + mmap_write16(addr, value); + } + else + { + *(uint16_t*)(mem8 + addr) = value; + } +} + +void write32(uint32_t addr, int32_t value) +{ + if(USE_A20 && !*a20_enabled) addr &= A20_MASK; + + if(in_mapped_range(addr)) + { + mmap_write32(addr, value); + } + else + { + *(int32_t*)(mem8 + addr) = value; + } +} diff --git a/src/native/misc_instr.c b/src/native/misc_instr.c new file mode 100644 index 00000000..5d4f9ee4 --- /dev/null +++ b/src/native/misc_instr.c @@ -0,0 +1,232 @@ +#include +#include +#include +#include + +#include + +#include "const.h" +#include "global_pointers.h" + +static int32_t get_stack_pointer(int32_t); +static void adjust_stack_reg(int32_t); +void branch_taken(); +void branch_not_taken(); +void writable_or_pagefault(int32_t, int32_t); + + +int32_t getcf() +{ + if(*flags_changed & 1) + { + return (*last_op1 ^ (*last_op1 ^ *last_op2) & (*last_op2 ^ *last_add_result)) >> *last_op_size & 1; + } + else + { + return *flags & 1; + } +} + +int32_t getpf() +{ + if(*flags_changed & FLAG_PARITY) + { + // inverted lookup table + return 0x9669 << 2 >> ((*last_result ^ *last_result >> 4) & 0xF) & FLAG_PARITY; + } + else + { + return *flags & FLAG_PARITY; + } +} + +int32_t getaf() +{ + if(*flags_changed & FLAG_ADJUST) + { + return (*last_op1 ^ *last_op2 ^ *last_add_result) & FLAG_ADJUST; + } + else + { + return *flags & FLAG_ADJUST; + } +} + +int32_t getzf() +{ + if(*flags_changed & FLAG_ZERO) + { + return (~*last_result & *last_result - 1) >> *last_op_size & 1; + } + else + { + return *flags & FLAG_ZERO; + } +} + +int32_t getsf() +{ + if(*flags_changed & FLAG_SIGN) + { + return *last_result >> *last_op_size & 1; + } + else + { + return *flags & FLAG_SIGN; + } +} + +int32_t getof() +{ + if(*flags_changed & FLAG_OVERFLOW) + { + return ((*last_op1 ^ *last_add_result) & (*last_op2 ^ *last_add_result)) >> *last_op_size & 1; + } + else + { + return *flags & FLAG_OVERFLOW; + } +} + +int32_t test_o() { return getof(); } +int32_t test_b() { return getcf(); } +int32_t test_z() { return getzf(); } +int32_t test_s() { return getsf(); } +int32_t test_p() { return getpf(); } +int32_t test_be() { return getcf() || getzf(); } +int32_t test_l() { return !getsf() != !getof(); } +int32_t test_le() { return getzf() || !getsf() != !getof(); } + +void jmp_rel16(int32_t rel16) +{ + int32_t cs_offset = get_seg(CS); + + // limit ip to 16 bit + *instruction_pointer = cs_offset + ((*instruction_pointer - cs_offset + rel16) & 0xFFFF); +} + +void jmpcc8(bool condition) +{ + int32_t imm8 = read_imm8s(); + if(condition) + { + *instruction_pointer += imm8; + branch_taken(); + } + else + { + branch_not_taken(); + } +} + +void jmpcc16(bool condition) +{ + int32_t imm16 = read_imm16(); + + if(condition) + { + jmp_rel16(imm16); + branch_taken(); + } + else + { + branch_not_taken(); + } +} + +void jmpcc32(bool condition) +{ + int32_t op = read_imm32s(); + + if(condition) + { + *instruction_pointer += op; + branch_taken(); + } + else + { + branch_not_taken(); + } +} + +static int32_t get_stack_pointer(int32_t offset) +{ + if(*stack_size_32) + { + return get_seg(SS) + reg32s[ESP] + offset; + } + else + { + return get_seg(SS) + (reg16[SP] + offset & 0xFFFF); + } +} + +static void adjust_stack_reg(int32_t adjustment) +{ + if(*stack_size_32) + { + reg32s[ESP] += adjustment; + } + else + { + reg16[SP] += adjustment; + } +} + +void push16(int32_t imm16) +{ + int32_t sp = get_stack_pointer(-2); + + safe_write16(sp, imm16); + adjust_stack_reg(-2); +} + +void push32(int32_t imm32) +{ + int32_t sp = get_stack_pointer(-4); + + safe_write32(sp, imm32); + adjust_stack_reg(-4); +} + +void pusha16() +{ + uint16_t temp = reg16[SP]; + + // make sure we don't get a pagefault after having + // pushed several registers already + writable_or_pagefault(get_stack_pointer(-16), 16); + + push16(reg16[AX]); + push16(reg16[CX]); + push16(reg16[DX]); + push16(reg16[BX]); + push16(temp); + push16(reg16[BP]); + push16(reg16[SI]); + push16(reg16[DI]); +} + +void pusha32() +{ + int32_t temp = reg32s[ESP]; + + writable_or_pagefault(get_stack_pointer(-32), 32); + + push32(reg32s[EAX]); + push32(reg32s[ECX]); + push32(reg32s[EDX]); + push32(reg32s[EBX]); + push32(temp); + push32(reg32s[EBP]); + push32(reg32s[ESI]); + push32(reg32s[EDI]); +} + +int32_t pop32s() +{ + int32_t sp = get_stack_pointer(0); + int32_t result = safe_read32s(sp); + adjust_stack_reg(4); + return result; +} diff --git a/src/native/modrm.c b/src/native/modrm.c new file mode 100644 index 00000000..42794ac5 --- /dev/null +++ b/src/native/modrm.c @@ -0,0 +1,230 @@ +#include +#include +#include +#include + +#include + +#include "const.h" +#include "global_pointers.h" + +// XXX: Remove these declarations when they are implemented in C +static int32_t resolve_sib(bool); + + +#define ds get_seg_prefix_ds +#define ss get_seg_prefix_ss + +#define MODRM_ENTRY(n, offset)\ + case (n) | 0 << 3:\ + case (n) | 1 << 3:\ + case (n) | 2 << 3:\ + case (n) | 3 << 3:\ + case (n) | 4 << 3:\ + case (n) | 5 << 3:\ + case (n) | 6 << 3:\ + case (n) | 7 << 3:\ + return offset; + +#define MODRM_ENTRY16(row, seg, value)\ + MODRM_ENTRY(0x00 | row, seg(((value) & 0xFFFF)))\ + MODRM_ENTRY(0x40 | row, seg(((value) + read_imm8s() & 0xFFFF)))\ + MODRM_ENTRY(0x80 | row, seg(((value) + read_imm16() & 0xFFFF)))\ + + +static int32_t resolve_modrm16(int32_t modrm_byte) +{ + switch(modrm_byte) + { + MODRM_ENTRY16(0, ds, reg16[BX] + reg16[SI]) + MODRM_ENTRY16(1, ds, reg16[BX] + reg16[DI]) + MODRM_ENTRY16(2, ss, reg16[BP] + reg16[SI]) + MODRM_ENTRY16(3, ss, reg16[BP] + reg16[DI]) + MODRM_ENTRY16(4, ds, reg16[SI]) + MODRM_ENTRY16(5, ds, reg16[DI]) + + // special case + MODRM_ENTRY(0x00 | 6, ds(read_imm16())) + MODRM_ENTRY(0x40 | 6, ss(reg16[BP] + read_imm8s() & 0xFFFF)) + MODRM_ENTRY(0x80 | 6, ss(reg16[BP] + read_imm16() & 0xFFFF)) + + MODRM_ENTRY16(7, ds, reg16[BX]) + + default: + assert(false); + } + + return 0; +} + +#undef MODRM_ENTRY16 + +#define MODRM_ENTRY32(row, seg, value)\ + MODRM_ENTRY(0x00 | row, seg((value)))\ + MODRM_ENTRY(0x40 | row, seg((value) + read_imm8s()))\ + MODRM_ENTRY(0x80 | row, seg((value) + read_imm32s()))\ + +static int32_t resolve_modrm32(int32_t modrm_byte) +{ + switch(modrm_byte) + { + MODRM_ENTRY32(0, ds, reg32s[EAX]) + MODRM_ENTRY32(1, ds, reg32s[ECX]) + MODRM_ENTRY32(2, ds, reg32s[EDX]) + MODRM_ENTRY32(3, ds, reg32s[EBX]) + + // special cases + MODRM_ENTRY(0x00 | 4, resolve_sib(false)) + MODRM_ENTRY(0x40 | 4, resolve_sib(true) + read_imm8s()) + MODRM_ENTRY(0x80 | 4, resolve_sib(true) + read_imm32s()) + MODRM_ENTRY(0x00 | 5, ds(read_imm32s())) + MODRM_ENTRY(0x40 | 5, ss(reg32s[EBP] + read_imm8s())) + MODRM_ENTRY(0x80 | 5, ss(reg32s[EBP] + read_imm32s())) + + MODRM_ENTRY32(6, ds, reg32s[ESI]) + MODRM_ENTRY32(7, ds, reg32s[EDI]) + + default: + assert(false); + } + + return 0; +} + +#undef MODRM_ENTRY32 +#undef MODRM_ENTRY + + +#define SIB_ENTRY_LEVEL3(n, offset)\ + case n: return offset; + +#define SIB_ENTRY_LEVEL2(n, offset)\ + SIB_ENTRY_LEVEL3(n | 0, ds((offset) + reg32s[EAX]))\ + SIB_ENTRY_LEVEL3(n | 1, ds((offset) + reg32s[ECX]))\ + SIB_ENTRY_LEVEL3(n | 2, ds((offset) + reg32s[EDX]))\ + SIB_ENTRY_LEVEL3(n | 3, ds((offset) + reg32s[EBX]))\ + SIB_ENTRY_LEVEL3(n | 4, ss((offset) + reg32s[ESP]))\ + SIB_ENTRY_LEVEL3(n | 5, (mod ? ss((offset) + reg32s[EBP]) : ds((offset) + read_imm32s())))\ + SIB_ENTRY_LEVEL3(n | 6, ds((offset) + reg32s[ESI]))\ + SIB_ENTRY_LEVEL3(n | 7, ds((offset) + reg32s[EDI])) + +#define SIB_ENTRY_LEVEL1(n, reg1)\ + SIB_ENTRY_LEVEL2(0x00 | (n) << 3, (reg1))\ + SIB_ENTRY_LEVEL2(0x40 | (n) << 3, (reg1) << 1)\ + SIB_ENTRY_LEVEL2(0x80 | (n) << 3, (reg1) << 2)\ + SIB_ENTRY_LEVEL2(0xC0 | (n) << 3, (reg1) << 3) + +static int32_t resolve_sib_(bool mod) +{ + switch(read_imm8()) + { + SIB_ENTRY_LEVEL1(0, reg32s[EAX]); + SIB_ENTRY_LEVEL1(1, reg32s[ECX]); + SIB_ENTRY_LEVEL1(2, reg32s[EDX]); + SIB_ENTRY_LEVEL1(3, reg32s[EBX]); + SIB_ENTRY_LEVEL1(4, 0 ); + SIB_ENTRY_LEVEL1(5, reg32s[EBP]); + SIB_ENTRY_LEVEL1(6, reg32s[ESI]); + SIB_ENTRY_LEVEL1(7, reg32s[EDI]); + + default: + assert(false); + } + + return 0; +} + +#undef SIB_ENTRY_LEVEL3 +#undef SIB_ENTRY_LEVEL2 +#undef SIB_ENTRY_LEVEL1 + +#undef ds +#undef ss + + +static int32_t resolve_sib(bool mod) +{ + uint8_t sib_byte = read_imm8(); + uint8_t r = sib_byte & 7; + uint8_t m = sib_byte >> 3 & 7; + + int32_t base; + int32_t seg; + + if(r == 4) + { + base = reg32s[ESP]; + seg = SS; + } + else if(r == 5) + { + if(mod) + { + base = reg32s[EBP]; + seg = SS; + } + else + { + base = read_imm32s(); + seg = DS; + } + } + else + { + base = reg32s[r]; + seg = DS; + } + + int32_t offset; + if(m == 4) + { + offset = 0; + } + else + { + uint8_t s = sib_byte >> 6 & 3; + offset = reg32s[m] << s; + } + + return get_seg_prefix(seg) + base + offset; +} + +static int32_t resolve_modrm32_(int32_t modrm_byte) +{ + uint8_t r = modrm_byte & 7; + assert(modrm_byte < 0xC0); + + if(r == 4) + { + if(modrm_byte < 0x40) + { + return resolve_sib(false); + } + else + { + return resolve_sib(true) + (modrm_byte < 0x80 ? read_imm8s() : read_imm32s()); + } + } + else if(r == 5) + { + if(modrm_byte < 0x40) + { + return get_seg_prefix_ds(read_imm32s()); + } + else + { + return get_seg_prefix_ss(reg32s[EBP] + (modrm_byte < 0x80 ? read_imm8s() : read_imm32s())); + } + } + else + { + if(modrm_byte < 0x40) + { + return get_seg_prefix_ds(reg32s[r]); + } + else + { + return get_seg_prefix_ds(reg32s[r] + (modrm_byte < 0x80 ? read_imm8s() : read_imm32s())); + } + } +} diff --git a/src/pci.js b/src/pci.js index c79405fa..dca6e2e2 100644 --- a/src/pci.js +++ b/src/pci.js @@ -446,6 +446,11 @@ PCI.prototype.pci_write32 = function(address, written) space[addr >> 2] = 0; } } + else if(addr === 0x04) + { + dbg_log("PCI write dev=" + h(bdf >> 3, 2) + " (" + device.name + ") addr=" + h(addr, 4) + + " value=" + h(written >>> 0, 8), LOG_PCI); + } else { dbg_log("PCI write dev=" + h(bdf >> 3, 2) + " (" + device.name + ") addr=" + h(addr, 4) + diff --git a/src/string.js b/src/string.js index cf1b934e..b38a20ce 100644 --- a/src/string.js +++ b/src/string.js @@ -46,9 +46,9 @@ CPU.prototype.movsb = function() var cpu = this; var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -1 : 1; + var size = cpu.flags[0] & flag_direction ? -1 : 1; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -57,7 +57,7 @@ CPU.prototype.movsb = function() var cycle_counter = MAX_COUNT_PER_CYCLE; var phys_src = cpu.translate_address_read(src); var phys_dest = cpu.translate_address_write(dest); - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count2(size, src, dest); } @@ -73,10 +73,10 @@ CPU.prototype.movsb = function() cpu.add_reg_asize(reg_edi, diff); cpu.add_reg_asize(reg_esi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -93,9 +93,9 @@ CPU.prototype.movsw = function() var cpu = this; var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -2 : 2; + var size = cpu.flags[0] & flag_direction ? -2 : 2; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -107,7 +107,7 @@ CPU.prototype.movsw = function() var single_size = size < 0 ? -1 : 1; var phys_src = cpu.translate_address_read(src) >>> 1; var phys_dest = cpu.translate_address_write(dest) >>> 1; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count2(size, src, dest); } @@ -123,7 +123,7 @@ CPU.prototype.movsw = function() cpu.add_reg_asize(reg_edi, diff); cpu.add_reg_asize(reg_esi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -140,7 +140,7 @@ CPU.prototype.movsw = function() } if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -156,7 +156,7 @@ CPU.prototype.movsd = function() { var cpu = this; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { // often used by memcpy, well worth optimizing // using cpu.mem32s.set @@ -173,16 +173,16 @@ CPU.prototype.movsd = function() // must be page-aligned if cpu.paging is enabled // and dword-aligned in general - var align_mask = cpu.paging ? 0xFFF : 3; + var align_mask = cpu.paging[0] ? 0xFFF : 3; if((dest & align_mask) === 0 && (src & align_mask) === 0 && // If df is set, alignment works a different // This should be unlikely - (cpu.flags & flag_direction) === 0) + (cpu.flags[0] & flag_direction) === 0) { var cont = false; - if(cpu.paging) + if(cpu.paging[0]) { src = cpu.translate_address_read(src); dest = cpu.translate_address_write(dest); @@ -208,7 +208,7 @@ CPU.prototype.movsd = function() if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } return; @@ -218,9 +218,9 @@ CPU.prototype.movsd = function() var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -4 : 4; + var size = cpu.flags[0] & flag_direction ? -4 : 4; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -232,7 +232,7 @@ CPU.prototype.movsd = function() var single_size = size < 0 ? -1 : 1; var phys_src = cpu.translate_address_read(src) >>> 2; var phys_dest = cpu.translate_address_write(dest) >>> 2; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count2(size, src, dest); } @@ -248,7 +248,7 @@ CPU.prototype.movsd = function() cpu.add_reg_asize(reg_edi, diff); cpu.add_reg_asize(reg_esi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -265,7 +265,7 @@ CPU.prototype.movsd = function() } if(cont) { - this.instruction_pointer = this.previous_ip; + this.instruction_pointer[0] = this.previous_ip[0]; } } else @@ -282,19 +282,19 @@ function cmpsb(cpu) var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; var data_src, data_dest; - var size = cpu.flags & flag_direction ? -1 : 1; + var size = cpu.flags[0] & flag_direction ? -1 : 1; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; var cont = false; var start_count = count; - var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ; + var is_repz = (cpu.prefixes[0] & PREFIX_MASK_REP) === PREFIX_REPZ; var cycle_counter = MAX_COUNT_PER_CYCLE; var phys_src = cpu.translate_address_read(src); var phys_dest = cpu.translate_address_read(dest); - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count2(size, src, dest); } @@ -311,10 +311,10 @@ function cmpsb(cpu) cpu.add_reg_asize(reg_edi, diff); cpu.add_reg_asize(reg_esi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -334,22 +334,22 @@ function cmpsw(cpu) var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; var data_src, data_dest; - var size = cpu.flags & flag_direction ? -2 : 2; + var size = cpu.flags[0] & flag_direction ? -2 : 2; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; var cont = false; var start_count = count; - var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ; + var is_repz = (cpu.prefixes[0] & PREFIX_MASK_REP) === PREFIX_REPZ; var cycle_counter = MAX_COUNT_PER_CYCLE; if(!(dest & 1) && !(src & 1)) { var single_size = size < 0 ? -1 : 1; var phys_src = cpu.translate_address_read(src) >>> 1; var phys_dest = cpu.translate_address_read(dest) >>> 1; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count2(size, src, dest); } @@ -366,7 +366,7 @@ function cmpsw(cpu) cpu.add_reg_asize(reg_edi, diff); cpu.add_reg_asize(reg_esi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -384,7 +384,7 @@ function cmpsw(cpu) } if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -404,22 +404,22 @@ function cmpsd(cpu) var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; var data_src, data_dest; - var size = cpu.flags & flag_direction ? -4 : 4; + var size = cpu.flags[0] & flag_direction ? -4 : 4; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; var cont = false; var start_count = count; - var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ; + var is_repz = (cpu.prefixes[0] & PREFIX_MASK_REP) === PREFIX_REPZ; var cycle_counter = MAX_COUNT_PER_CYCLE; if(!(dest & 3) && !(src & 3)) { var single_size = size < 0 ? -1 : 1; var phys_src = cpu.translate_address_read(src) >>> 2; var phys_dest = cpu.translate_address_read(dest) >>> 2; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count2(size, src, dest); } @@ -436,7 +436,7 @@ function cmpsd(cpu) cpu.add_reg_asize(reg_edi, diff); cpu.add_reg_asize(reg_esi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -454,7 +454,7 @@ function cmpsd(cpu) } if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -473,9 +473,9 @@ function stosb(cpu) { var data = cpu.reg8[reg_al]; var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -1 : 1; + var size = cpu.flags[0] & flag_direction ? -1 : 1; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -483,7 +483,7 @@ function stosb(cpu) var start_count = count; var cycle_counter = MAX_COUNT_PER_CYCLE; var phys_dest = cpu.translate_address_write(dest); - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, dest); } @@ -497,10 +497,10 @@ function stosb(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_edi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -515,9 +515,9 @@ function stosw(cpu) { var data = cpu.reg16[reg_ax]; var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -2 : 2; + var size = cpu.flags[0] & flag_direction ? -2 : 2; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -528,7 +528,7 @@ function stosw(cpu) { var single_size = size < 0 ? -1 : 1; var phys_dest = cpu.translate_address_write(dest) >>> 1; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, dest); } @@ -542,7 +542,7 @@ function stosw(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_edi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -557,7 +557,7 @@ function stosw(cpu) } if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -572,9 +572,9 @@ function stosd(cpu) { var data = cpu.reg32s[reg_eax]; var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -4 : 4; + var size = cpu.flags[0] & flag_direction ? -4 : 4; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -585,7 +585,7 @@ function stosd(cpu) { var single_size = size < 0 ? -1 : 1; var phys_dest = cpu.translate_address_write(dest) >>> 2; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, dest); } @@ -599,7 +599,7 @@ function stosd(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_edi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -614,7 +614,7 @@ function stosd(cpu) } if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -628,9 +628,9 @@ function stosd(cpu) function lodsb(cpu) { var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; - var size = cpu.flags & flag_direction ? -1 : 1; + var size = cpu.flags[0] & flag_direction ? -1 : 1; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -638,7 +638,7 @@ function lodsb(cpu) var start_count = count; var cycle_counter = MAX_COUNT_PER_CYCLE; var phys_src = cpu.translate_address_read(src); - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, src); } @@ -652,10 +652,10 @@ function lodsb(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_esi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -669,9 +669,9 @@ function lodsb(cpu) function lodsw(cpu) { var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; - var size = cpu.flags & flag_direction ? -2 : 2; + var size = cpu.flags[0] & flag_direction ? -2 : 2; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -687,7 +687,7 @@ function lodsw(cpu) while(cont && cycle_counter--); if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -701,9 +701,9 @@ function lodsw(cpu) function lodsd(cpu) { var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; - var size = cpu.flags & flag_direction ? -4 : 4; + var size = cpu.flags[0] & flag_direction ? -4 : 4; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -719,7 +719,7 @@ function lodsd(cpu) while(cont && cycle_counter--); if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -733,20 +733,20 @@ function lodsd(cpu) function scasb(cpu) { var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -1 : 1; + var size = cpu.flags[0] & flag_direction ? -1 : 1; var data_dest; var data_src = cpu.reg8[reg_al]; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; var cont = false; var start_count = count; - var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ; + var is_repz = (cpu.prefixes[0] & PREFIX_MASK_REP) === PREFIX_REPZ; var cycle_counter = MAX_COUNT_PER_CYCLE; var phys_dest = cpu.translate_address_read(dest); - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, dest); } @@ -760,10 +760,10 @@ function scasb(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_edi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -779,23 +779,23 @@ function scasb(cpu) function scasw(cpu) { var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -2 : 2; + var size = cpu.flags[0] & flag_direction ? -2 : 2; var data_dest; var data_src = cpu.reg16[reg_al]; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; var cont = false; var start_count = count; - var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ; + var is_repz = (cpu.prefixes[0] & PREFIX_MASK_REP) === PREFIX_REPZ; var cycle_counter = MAX_COUNT_PER_CYCLE; if(!(dest & 1)) { var single_size = size < 0 ? -1 : 1; var phys_dest = cpu.translate_address_read(dest) >>> 1; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, dest); } @@ -809,7 +809,7 @@ function scasw(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_edi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -824,7 +824,7 @@ function scasw(cpu) } if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -840,23 +840,23 @@ function scasw(cpu) function scasd(cpu) { var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -4 : 4; + var size = cpu.flags[0] & flag_direction ? -4 : 4; var data_dest; var data_src = cpu.reg32s[reg_eax]; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; var cont = false; var start_count = count; - var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ; + var is_repz = (cpu.prefixes[0] & PREFIX_MASK_REP) === PREFIX_REPZ; var cycle_counter = MAX_COUNT_PER_CYCLE; if(!(dest & 3)) { var single_size = size < 0 ? -1 : 1; var phys_dest = cpu.translate_address_read(dest) >>> 2; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, dest); } @@ -870,7 +870,7 @@ function scasd(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_edi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -885,7 +885,7 @@ function scasd(cpu) } if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -904,9 +904,9 @@ function insb(cpu) cpu.test_privileges_for_io(port, 1); var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -1 : 1; + var size = cpu.flags[0] & flag_direction ? -1 : 1; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -914,7 +914,7 @@ function insb(cpu) var start_count = count; var cycle_counter = MAX_COUNT_PER_CYCLE; var phys_dest = cpu.translate_address_write(dest); - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, dest); } @@ -928,10 +928,10 @@ function insb(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_edi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -949,9 +949,9 @@ function insw(cpu) cpu.test_privileges_for_io(port, 2); var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -2 : 2; + var size = cpu.flags[0] & flag_direction ? -2 : 2; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -962,7 +962,7 @@ function insw(cpu) { var single_size = size < 0 ? -1 : 1; var phys_dest = cpu.translate_address_write(dest) >>> 1; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, dest); } @@ -976,7 +976,7 @@ function insw(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_edi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -991,7 +991,7 @@ function insw(cpu) } if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -1009,9 +1009,9 @@ function insd(cpu) cpu.test_privileges_for_io(port, 4); var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0; - var size = cpu.flags & flag_direction ? -4 : 4; + var size = cpu.flags[0] & flag_direction ? -4 : 4; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -1022,7 +1022,7 @@ function insd(cpu) { var single_size = size < 0 ? -1 : 1; var phys_dest = cpu.translate_address_write(dest) >>> 2; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, dest); } @@ -1036,7 +1036,7 @@ function insd(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_edi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -1051,7 +1051,7 @@ function insd(cpu) } if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -1069,9 +1069,9 @@ function outsb(cpu) cpu.test_privileges_for_io(port, 1); var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; - var size = cpu.flags & flag_direction ? -1 : 1; + var size = cpu.flags[0] & flag_direction ? -1 : 1; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -1079,7 +1079,7 @@ function outsb(cpu) var start_count = count; var cycle_counter = MAX_COUNT_PER_CYCLE; var phys_src = cpu.translate_address_read(src); - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, src); } @@ -1093,10 +1093,10 @@ function outsb(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_esi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -1113,9 +1113,9 @@ function outsw(cpu) cpu.test_privileges_for_io(port, 2); var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; - var size = cpu.flags & flag_direction ? -2 : 2; + var size = cpu.flags[0] & flag_direction ? -2 : 2; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -1126,7 +1126,7 @@ function outsw(cpu) { var single_size = size < 0 ? -1 : 1; var phys_src = cpu.translate_address_read(src) >>> 1; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, src); } @@ -1140,7 +1140,7 @@ function outsw(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_esi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -1155,7 +1155,7 @@ function outsw(cpu) } if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -1172,9 +1172,9 @@ function outsd(cpu) cpu.test_privileges_for_io(port, 4); var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0; - var size = cpu.flags & flag_direction ? -4 : 4; + var size = cpu.flags[0] & flag_direction ? -4 : 4; - if(cpu.prefixes & PREFIX_MASK_REP) + if(cpu.prefixes[0] & PREFIX_MASK_REP) { var count = cpu.get_reg_asize(reg_ecx) >>> 0; if(count === 0) return; @@ -1185,7 +1185,7 @@ function outsd(cpu) { var single_size = size < 0 ? -1 : 1; var phys_src = cpu.translate_address_read(src) >>> 2; - if(cpu.paging) + if(cpu.paging[0]) { cycle_counter = string_get_cycle_count(size, src); } @@ -1199,7 +1199,7 @@ function outsd(cpu) var diff = size * (start_count - count) | 0; cpu.add_reg_asize(reg_esi, diff); cpu.set_ecx_asize(count); - cpu.timestamp_counter += start_count - count; + cpu.timestamp_counter[0] += start_count - count; } else { @@ -1214,7 +1214,7 @@ function outsd(cpu) } if(cont) { - cpu.instruction_pointer = cpu.previous_ip; + cpu.instruction_pointer[0] = cpu.previous_ip[0]; } } else @@ -1224,3 +1224,27 @@ function outsd(cpu) } cpu.diverged(); } + +CPU.prototype.stosb = function() { stosb(this); } +CPU.prototype.stosw = function() { stosw(this); } +CPU.prototype.stosd = function() { stosd(this); } + +CPU.prototype.lodsb = function() { lodsb(this); } +CPU.prototype.lodsw = function() { lodsw(this); } +CPU.prototype.lodsd = function() { lodsd(this); } + +CPU.prototype.cmpsb = function() { cmpsb(this); } +CPU.prototype.cmpsw = function() { cmpsw(this); } +CPU.prototype.cmpsd = function() { cmpsd(this); } + +CPU.prototype.scasb = function() { scasb(this); } +CPU.prototype.scasw = function() { scasw(this); } +CPU.prototype.scasd = function() { scasd(this); } + +CPU.prototype.insb = function() { insb(this); } +CPU.prototype.insw = function() { insw(this); } +CPU.prototype.insd = function() { insd(this); } + +CPU.prototype.outsb = function() { outsb(this); } +CPU.prototype.outsw = function() { outsw(this); } +CPU.prototype.outsd = function() { outsd(this); } diff --git a/src/virtio.js b/src/virtio.js index ef3cb202..cc63e9db 100644 --- a/src/virtio.js +++ b/src/virtio.js @@ -11,6 +11,8 @@ function VirtIO(cpu, bus, filesystem) { // http://ozlabs.org/~rusty/virtio-spec/virtio-0.9.5.pdf + this.irq = 10; + this.pci_space = [ 0xf4, 0x1a, 0x09, 0x10, 0x07, 0x05, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xa8, 0x00, 0x00, 0x00, 0x10, 0xbf, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, diff --git a/tests/kvm-unit-tests/run.js b/tests/kvm-unit-tests/run.js index 9ac5b93f..7f9e27b5 100755 --- a/tests/kvm-unit-tests/run.js +++ b/tests/kvm-unit-tests/run.js @@ -33,7 +33,7 @@ var emulator = new V86({ emulator.bus.register("emulator-started", function() { - emulator.v86.cpu.io.register_write_consecutive(0xF4, this, + emulator.v86.cpu.io.register_write_consecutive(0xF4, {}, function(value) { console.log("Test exited with code " + value);