| "use strict"; |
| var debug = {}; |
| /** @constructor */ |
| function v86() |
| { |
| var cpu = this; |
| this.run = function() |
| { |
| if(!running) |
| { |
| cpu_run(); |
| } |
| } |
| this.stop = cpu_stop; |
| this.init = cpu_init; |
| this.restart = cpu_restart; |
| this.dev = {}; |
| this.instr_counter = 0; |
| var |
| segment_is_null, |
| segment_offsets, |
| segment_limits, |
| segment_infos, |
| /* |
| * Translation Lookaside Buffer |
| */ |
| tlb_user_read, |
| tlb_user_write, |
| tlb_system_read, |
| tlb_system_write, |
| /* |
| * Information about which pages are cached in the tlb. |
| * By bit: |
| * 0 system, read |
| * 1 system, write |
| * 2 user, read |
| * 3 user, write |
| */ |
| tlb_info, |
| /* |
| * Same as tlb_info, except it only contains global pages |
| */ |
| tlb_info_global, |
| /** |
| * Wheter or not in protected mode |
| * @type {boolean} |
| */ |
| protected_mode, |
| /** |
| * interrupt descriptor table |
| * @type {number} |
| */ |
| idtr_size, |
| /** @type {number} */ |
| idtr_offset, |
| /** |
| * global descriptor table register |
| * @type {number} |
| */ |
| gdtr_size, |
| /** @type {number} */ |
| gdtr_offset, |
| /** |
| * local desciptor table |
| * @type {number} |
| */ |
| ldtr_size, |
| /** @type {number} */ |
| ldtr_offset, |
| /** |
| * task register |
| * @type {number} |
| */ |
| tsr_size, |
| /** @type {number} */ |
| tsr_offset, |
| /* |
| * whether or not a page fault occured |
| */ |
| page_fault, |
| /** @type {number} */ |
| cr0, |
| /** @type {number} */ |
| cr2, |
| /** @type {number} */ |
| cr3, |
| /** @type {number} */ |
| cr4, |
| // current privilege level |
| /** @type {number} */ |
| cpl, |
| // paging enabled |
| /** @type {boolean} */ |
| paging, |
| // if false, pages are 4 KiB, else 4 Mib |
| /** @type {number} */ |
| page_size_extensions, |
| // current operand/address/stack size |
| /** @type {boolean} */ |
| is_32, |
| /** @type {boolean} */ |
| operand_size_32, |
| /** @type {boolean} */ |
| stack_size_32, |
| /** |
| * Cycles since last cpu reset, used by rdtsc instruction |
| * @type {number} |
| */ |
| cpu_timestamp_counter, |
| /** @type {number} */ |
| previous_ip, |
| /** |
| * wheter or not in step mode |
| * used for debugging |
| * @type {boolean} |
| */ |
| step_mode, |
| /** |
| * was the last instruction a hlt |
| * @type {boolean} |
| */ |
| in_hlt, |
| /** @type {VGAScreen} */ |
| vga, |
| /** @type {PS2} */ |
| ps2, |
| /** |
| * Programmable interval timer |
| * @type {PIT} |
| */ |
| timer, |
| /** |
| * Real Time Clock |
| * @type {RTC} |
| */ |
| rtc, |
| /** |
| * Floppy Disk controller |
| * @type {FloppyController} |
| */ |
| fdc, |
| /** |
| * Serial controller |
| * @type {UART} |
| */ |
| uart, |
| /** @type {boolean} */ |
| running, |
| /** @type {boolean} */ |
| stopped, |
| /** @type {number} */ |
| loop_counter, |
| /** @type {Memory} */ |
| memory, |
| /** @type {(FPU|NoFPU)} */ |
| fpu, |
| /** |
| * Programmable interrupt controller |
| * @type {PIC} |
| */ |
| pic, |
| /** |
| * @type {IO} |
| */ |
| io, |
| /** |
| * @type {PCI} |
| */ |
| pci, |
| /** |
| * @type {CDRom} |
| */ |
| cdrom, |
| /** |
| * @type {HDD} |
| */ |
| hda, |
| /** |
| * @type {HDD} |
| */ |
| hdb, |
| /** |
| * Direct Memory Access Controller |
| * @type {DMA} |
| */ |
| dma, |
| translate_address_read, |
| translate_address_write, |
| ops, |
| /** @type {boolean} */ |
| address_size_32, |
| /** @type {number} */ |
| instruction_pointer, |
| /** @type {number} */ |
| last_virt_eip, |
| /** @type {number} */ |
| eip_phys, |
| /** @type {number} */ |
| last_virt_esp, |
| /** @type {number} */ |
| esp_phys, |
| // current state of prefixes |
| segment_prefix, |
| /** @type {boolean} */ |
| repeat_string_prefix, |
| /** @type {boolean} */ |
| repeat_string_type, |
| /** @type {number} */ |
| last_result, |
| /** @type {number} */ |
| flags, |
| /** |
| * bitmap of flags which are not updated in the flags variable |
| * changed by arithmetic instructions, so only relevant to arithmetic flags |
| * @type {number} |
| */ |
| flags_changed, |
| /** |
| * the last 2 operators and the result and size of the last arithmetic operation |
| * @type {number} |
| */ |
| last_op1, |
| /** @type {number} */ |
| last_op2, |
| /** @type {number} */ |
| last_op_size, |
| // registers |
| reg32, |
| reg32s, |
| reg16, |
| reg16s, |
| reg8, |
| reg8s, |
| sreg, |
| // sp or esp, depending on stack size attribute |
| stack_reg, |
| reg_vsp, |
| reg_vbp, |
| // reg16 or reg32, depending on address size attribute |
| regv, |
| reg_vcx, |
| reg_vsi, |
| reg_vdi, |
| // functions that are set depending on whether paging is enabled or not |
| read_imm8, |
| read_imm8s, |
| read_imm16, |
| read_imm32s, |
| safe_read8, |
| safe_read8s, |
| safe_read16, |
| safe_read32s, |
| get_esp_read, |
| get_esp_write, |
| table, |
| table0F, |
| modrm_resolve, |
| current_settings |
| ; |
| function cpu_run() |
| { |
| if(stopped) |
| { |
| stopped = running = false; |
| return; |
| } |
| running = true; |
| try { |
| do_run(); |
| } |
| catch(e) |
| { |
| if(e === 0xDEADBEE) |
| { |
| // A legit CPU exception (for instance, a page fault happened) |
| // call_interrupt_vector has already been called at this point, |
| // so we just need to reset some state |
| page_fault = false; |
| repeat_string_prefix = false; |
| segment_prefix = -1; |
| address_size_32 = is_32; |
| update_address_size(); |
| operand_size_32 = is_32; |
| update_operand_size(); |
| cpu_run(); |
| } |
| else |
| { |
| throw e; |
| } |
| } |
| }; |
| function cpu_stop() |
| { |
| if(running) |
| { |
| stopped = true; |
| } |
| } |
| function cpu_restart() |
| { |
| var was_running = running; |
| stopped = true; |
| running = false; |
| setTimeout(function() |
| { |
| ps2.destroy(); |
| vga.destroy(); |
| cpu_init(current_settings); |
| if(was_running) |
| { |
| cpu_run(); |
| } |
| }, 10); |
| } |
| function cpu_reboot_internal() |
| { |
| dbg_assert(running); |
| ps2.destroy(); |
| vga.destroy(); |
| cpu_init(current_settings); |
| throw 0xDEADBEE; |
| } |
| function cpu_init(settings) |
| { |
| // see browser/main.js or node/main.js |
| if(typeof set_tick !== "undefined") |
| { |
| set_tick(cpu_run); |
| } |
| current_settings = settings; |
| cpu.memory = memory = new Memory(new ArrayBuffer(memory_size), memory_size); |
| segment_is_null = new Uint8Array(8); |
| segment_limits = new Uint32Array(8); |
| segment_infos = new Uint32Array(8); |
| segment_offsets = new Int32Array(8); |
| // 16 MB in total |
| tlb_user_read = new Int32Array(1 << 20); |
| tlb_user_write = new Int32Array(1 << 20); |
| tlb_system_read = new Int32Array(1 << 20); |
| tlb_system_write = new Int32Array(1 << 20); |
| tlb_info = new Uint8Array(1 << 20); |
| tlb_info_global = new Uint8Array(1 << 20); |
| reg32 = new Uint32Array(8); |
| reg32s = new Int32Array(reg32.buffer); |
| reg16 = new Uint16Array(reg32.buffer); |
| reg16s = new Int16Array(reg32.buffer); |
| reg8 = new Uint8Array(reg32.buffer); |
| reg8s = new Int8Array(reg32.buffer); |
| sreg = new Uint16Array(8); |
| protected_mode = false; |
| idtr_size = 0; |
| idtr_offset = 0; |
| gdtr_size = 0; |
| gdtr_offset = 0; |
| ldtr_size = 0; |
| ldtr_offset = 0; |
| tsr_size = 0; |
| tsr_offset = 0; |
| page_fault = false; |
| cr0 = 0; |
| cr2 = 0; |
| cr3 = 0; |
| cr4 = 0; |
| cpl = 0; |
| paging = false; |
| page_size_extensions = 0; |
| is_32 = false; |
| operand_size_32 = false; |
| stack_size_32 = false; |
| address_size_32 = false; |
| paging_changed(); |
| update_operand_size(); |
| update_address_size(); |
| stack_reg = reg16; |
| reg_vsp = reg_sp; |
| reg_vbp = reg_bp; |
| cpu_timestamp_counter = 0; |
| previous_ip = 0; |
| step_mode = false; |
| in_hlt = false; |
| running = false; |
| stopped = false; |
| loop_counter = 20; |
| translate_address_read = translate_address_disabled; |
| translate_address_write = translate_address_disabled; |
| segment_prefix = -1; |
| repeat_string_prefix = false; |
| last_result = 0; |
| flags = flags_default; |
| flags_changed = 0; |
| last_op1 = 0; |
| last_op2 = 0; |
| last_op_size = 0; |
| if(settings.bios) |
| { |
| // load bios |
| var data = new Uint8Array(settings.bios), |
| start = 0x100000 - settings.bios.byteLength; |
| for(var i = 0; i < settings.bios.byteLength; i++) |
| { |
| memory.mem8[start + i] = data[i]; |
| } |
| if(settings.vga_bios) |
| { |
| // load vga bios |
| data = new Uint8Array(settings.vga_bios); |
| for(var i = 0; i < settings.vga_bios.byteLength; i++) |
| { |
| memory.mem8[0xC0000 + i] = data[i]; |
| } |
| } |
| // ip initial value |
| instruction_pointer = 0xFFFF0; |
| // ss and sp inital value |
| switch_seg(reg_ss, 0x30); |
| reg16[reg_sp] = 0x100; |
| } |
| else if(settings.linux) |
| { |
| instruction_pointer = 0x10000; |
| memory.write_blob(new Uint8Array(settings.linux.vmlinux), 0x100000); |
| memory.write_blob(new Uint8Array(settings.linux.linuxstart), instruction_pointer); |
| if(settings.linux.root) |
| { |
| memory.write_blob(new Uint8Array(settings.linux.root), 0x00400000); |
| reg32[reg_ebx] = settings.linux.root.byteLength; |
| } |
| memory.write_string(settings.linux.cmdline, 0xF800); |
| reg32[reg_eax] = memory_size; |
| reg32[reg_ecx] = 0xF800; |
| switch_seg(reg_cs, 0); |
| switch_seg(reg_ss, 0); |
| switch_seg(reg_ds, 0); |
| switch_seg(reg_es, 0); |
| switch_seg(reg_gs, 0); |
| switch_seg(reg_fs, 0); |
| is_32 = true; |
| address_size_32 = true; |
| operand_size_32 = true; |
| stack_size_32 = true; |
| protected_mode = true; |
| update_operand_size(); |
| update_address_size(); |
| regv = reg32; |
| reg_vsp = reg_esp; |
| reg_vbp = reg_ebp; |
| cr0 = 1; |
| } |
| else |
| { |
| switch_seg(reg_ss, 0x30); |
| reg16[reg_sp] = 0x100; |
| instruction_pointer = 0; |
| } |
| cpu.dev = {}; |
| if(settings.load_devices) |
| { |
| var devapi = { |
| memory: memory, |
| reboot: cpu_reboot_internal, |
| }; |
| devapi.io = cpu.dev.io = io = new IO(); |
| devapi.pic = pic = new PIC(devapi, call_interrupt_vector, handle_irqs); |
| devapi.pci = pci = new PCI(devapi); |
| devapi.dma = dma = new DMA(devapi); |
| cpu.dev.vga = vga = new VGAScreen(devapi, settings.screen_adapter) |
| cpu.dev.ps2 = ps2 = new PS2(devapi, settings.keyboard_adapter, settings.mouse_adapter); |
| //fpu = new NoFPU(); |
| fpu = new FPU(devapi); |
| uart = new UART(devapi); |
| cpu.dev.fdc = fdc = new FloppyController(devapi, settings.floppy_disk); |
| if(settings.cdrom_disk) |
| { |
| cpu.dev.cdrom = cdrom = new CDRom(devapi, settings.cdrom_disk); |
| } |
| if(settings.hda_disk) |
| { |
| cpu.dev.hda = hda = new HDD(devapi, settings.hda_disk, 0); |
| } |
| if(settings.hdb_disk) |
| { |
| cpu.dev.hdb = hdb = new HDD(devapi, settings.hdb_disk, 1); |
| } |
| timer = new PIT(devapi); |
| rtc = new RTC(devapi, fdc.type); |
| } |
| if(DEBUG) |
| { |
| // used for debugging |
| ops = new CircularQueue(30000); |
| if(typeof window !== "undefined") |
| { |
| window.memory = memory; |
| window.vga = vga; |
| } |
| if(io) |
| { |
| // write seabios debug output to console |
| var seabios_debug = ""; |
| io.register_write(0x402, function(out_byte) |
| { |
| // seabios debug |
| // |
| if(out_byte === 10) |
| { |
| dbg_log(seabios_debug, LOG_BIOS); |
| seabios_debug = ""; |
| } |
| else |
| { |
| seabios_debug += String.fromCharCode(out_byte); |
| } |
| }); |
| } |
| } |
| } |
| function do_run() |
| { |
| var |
| /** |
| * @type {number} |
| */ |
| now, |
| start = Date.now(); |
| vga.timer(start); |
| // outer loop: |
| // runs cycles + timers |
| for(var j = loop_counter; j--;) |
| { |
| // inner loop: |
| // runs only cycles |
| for(var k = LOOP_COUNTER; k--;) |
| { |
| previous_ip = instruction_pointer; |
| cycle(); |
| cpu_timestamp_counter++; |
| } |
| now = Date.now(); |
| timer.timer(now); |
| rtc.timer(now); |
| } |
| cpu.instr_counter += loop_counter * LOOP_COUNTER; |
| if(now - start > TIME_PER_FRAME) |
| { |
| loop_counter--; |
| } |
| else |
| { |
| loop_counter++; |
| } |
| next_tick(); |
| } |
| // do_run must not be inlined into cpu_run, because then more code |
| // is in the deoptimized try-catch. |
| // This trick is a bit ugly, but it works without further complication. |
| if(typeof window !== "undefined") |
| { |
| window.__no_inline = do_run; |
| } |
| /** |
| * execute a single instruction cycle on the cpu |
| * this includes reading all prefixes and the whole instruction |
| */ |
| function cycle() |
| { |
| var opcode = read_imm8(); |
| logop(instruction_pointer - 1, opcode); |
| // call the instruction |
| table[opcode](); |
| // TODO |
| //if(flags & flag_trap) |
| //{ |
| // |
| //} |
| } |
| cpu.cycle = function() |
| { |
| table[read_imm8()](); |
| } |
| function cr0_changed() |
| { |
| //protected_mode = (cr0 & 1) === 1; |
| //dbg_log("cr0 = " + h(cr0)); |
| var new_paging = (cr0 & 0x80000000) !== 0; |
| if(fpu.is_fpu) |
| { |
| cr0 &= ~4; |
| } |
| else |
| { |
| cr0 |= 4; |
| } |
| if(new_paging !== paging) |
| { |
| paging = new_paging; |
| paging_changed(); |
| } |
| } |
| function paging_changed() |
| { |
| var table = paging ? pe_functions : npe_functions; |
| read_imm8 = table.read_imm8; |
| read_imm8s = table.read_imm8s; |
| read_imm16 = table.read_imm16; |
| read_imm32s = table.read_imm32s; |
| safe_read8 = table.safe_read8; |
| safe_read8s = table.safe_read8s; |
| safe_read16 = table.safe_read16; |
| safe_read32s = table.safe_read32s; |
| get_esp_read = table.get_esp_read; |
| get_esp_write = table.get_esp_write; |
| // set translate_address_* depending on cpl and paging |
| cpl_changed(); |
| } |
| function cpl_changed() |
| { |
| last_virt_eip = -1; |
| last_virt_esp = -1; |
| if(!paging) |
| { |
| translate_address_write = translate_address_disabled; |
| translate_address_read = translate_address_disabled; |
| } |
| else if(cpl) |
| { |
| translate_address_write = translate_address_user_write; |
| translate_address_read = translate_address_user_read; |
| } |
| else |
| { |
| translate_address_write = translate_address_system_write; |
| translate_address_read = translate_address_system_read; |
| } |
| } |
| // functions that are used when paging is disabled |
| var npe_functions = { |
| get_esp_read: get_esp_npe, |
| get_esp_write: get_esp_npe, |
| read_imm8: function() |
| { |
| return memory.mem8[instruction_pointer++]; |
| }, |
| read_imm8s: function() |
| { |
| return memory.mem8s[instruction_pointer++]; |
| }, |
| read_imm16 : function() |
| { |
| var data16 = memory.read16(instruction_pointer); |
| instruction_pointer = instruction_pointer + 2 | 0; |
| return data16; |
| }, |
| read_imm32s : function() |
| { |
| var data32 = memory.read32s(instruction_pointer); |
| instruction_pointer = instruction_pointer + 4 | 0; |
| return data32; |
| }, |
| safe_read8 : function(addr) { return memory.read8(addr) }, |
| safe_read8s : function(addr) { return memory.read8s(addr); }, |
| safe_read16 : function(addr) { return memory.read16(addr); }, |
| safe_read32s : function(addr) { return memory.read32s(addr); }, |
| }; |
| // functions that are used when paging is enabled |
| var pe_functions = |
| { |
| get_esp_read: get_esp_pe_read, |
| get_esp_write: get_esp_pe_write, |
| read_imm8 : function() |
| { |
| if((instruction_pointer & ~0xFFF) ^ last_virt_eip) |
| { |
| eip_phys = translate_address_read(instruction_pointer) ^ instruction_pointer; |
| last_virt_eip = instruction_pointer & ~0xFFF; |
| } |
| // memory.read8 inlined under the assumption that code never runs in |
| // memory-mapped io |
| return memory.mem8[eip_phys ^ instruction_pointer++]; |
| }, |
| read_imm8s : function() |
| { |
| if((instruction_pointer & ~0xFFF) ^ last_virt_eip) |
| { |
| eip_phys = translate_address_read(instruction_pointer) ^ instruction_pointer; |
| last_virt_eip = instruction_pointer & ~0xFFF; |
| } |
| return memory.mem8s[eip_phys ^ instruction_pointer++]; |
| }, |
| 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((instruction_pointer ^ last_virt_eip) > 0xFFE) |
| { |
| return read_imm8() | read_imm8() << 8; |
| } |
| var data16 = memory.read16(eip_phys ^ instruction_pointer); |
| instruction_pointer = instruction_pointer + 2 | 0; |
| return data16; |
| }, |
| read_imm32s : function() |
| { |
| // Analogue to the above comment |
| if((instruction_pointer ^ last_virt_eip) > 0xFFC) |
| { |
| return read_imm16() | read_imm16() << 16; |
| } |
| var data32 = memory.read32s(eip_phys ^ instruction_pointer); |
| instruction_pointer = instruction_pointer + 4 | 0; |
| return data32; |
| }, |
| safe_read8 : do_safe_read8, |
| safe_read8s : do_safe_read8s, |
| safe_read16 : do_safe_read16, |
| safe_read32s : do_safe_read32s, |
| }; |
| // read word from a page boundary, given 2 physical addresses |
| function virt_boundary_read16(low, high) |
| { |
| dbg_assert((low & 0xFFF) === 0xFFF); |
| dbg_assert((high & 0xFFF) === 0); |
| return memory.read8(low) | memory.read8(high) << 8; |
| } |
| // read doubleword from a page boundary, given 2 addresses |
| function virt_boundary_read32s(low, high) |
| { |
| dbg_assert((low & 0xFFF) >= 0xFFD); |
| dbg_assert((high - 3 & 0xFFF) === (low & 0xFFF)); |
| var result = memory.read8(low) | memory.read8(high) << 24; |
| if(low & 1) |
| { |
| if(low & 2) |
| { |
| // 0xFFF |
| result |= memory.read8(high - 2) << 8 | |
| memory.read8(high - 1) << 16; |
| } |
| else |
| { |
| // 0xFFD |
| result |= memory.read8(low + 1) << 8 | |
| memory.read8(low + 2) << 16; |
| } |
| } |
| else |
| { |
| // 0xFFE |
| result |= memory.read8(low + 1) << 8 | |
| memory.read8(high - 1) << 16; |
| } |
| return result; |
| } |
| function virt_boundary_write16(low, high, value) |
| { |
| dbg_assert((low & 0xFFF) === 0xFFF); |
| dbg_assert((high & 0xFFF) === 0); |
| memory.write8(low, value); |
| memory.write8(high, value >> 8); |
| } |
| function virt_boundary_write32(low, high, value) |
| { |
| dbg_assert((low & 0xFFF) >= 0xFFD); |
| dbg_assert((high - 3 & 0xFFF) === (low & 0xFFF)); |
| memory.write8(low, value); |
| memory.write8(high, value >> 24); |
| if(low & 1) |
| { |
| if(low & 2) |
| { |
| // 0xFFF |
| memory.write8(high - 2, value >> 8); |
| memory.write8(high - 1, value >> 16); |
| } |
| else |
| { |
| // 0xFFD |
| memory.write8(low + 1, value >> 8); |
| memory.write8(low + 2, value >> 16); |
| } |
| } |
| else |
| { |
| // 0xFFE |
| memory.write8(low + 1, value >> 8); |
| memory.write8(high - 1, value >> 16); |
| } |
| } |
| // safe_read, safe_write |
| // read or write byte, word or dword to the given *virtual* address, |
| // and be safe on page boundaries |
| function do_safe_read8(addr) |
| { |
| return memory.read8(translate_address_read(addr)); |
| } |
| function do_safe_read8s(addr) |
| { |
| return memory.read8s(translate_address_read(addr)); |
| } |
| function do_safe_read16(addr) |
| { |
| if((addr & 0xFFF) === 0xFFF) |
| { |
| return safe_read8(addr) | safe_read8(addr + 1) << 8; |
| } |
| else |
| { |
| return memory.read16(translate_address_read(addr)); |
| } |
| } |
| function do_safe_read32s(addr) |
| { |
| if((addr & 0xFFF) >= 0xFFD) |
| { |
| return safe_read16(addr) | safe_read16(addr + 2) << 16; |
| } |
| else |
| { |
| return memory.read32s(translate_address_read(addr)); |
| } |
| } |
| function safe_write8(addr, value) |
| { |
| memory.write8(translate_address_write(addr), value); |
| } |
| function safe_write16(addr, value) |
| { |
| var phys_low = translate_address_write(addr); |
| if((addr & 0xFFF) === 0xFFF) |
| { |
| virt_boundary_write16(phys_low, translate_address_write(addr + 1), value); |
| } |
| else |
| { |
| memory.write16(phys_low, value); |
| } |
| } |
| function safe_write32(addr, value) |
| { |
| var phys_low = translate_address_write(addr); |
| if((addr & 0xFFF) >= 0xFFD) |
| { |
| virt_boundary_write32(phys_low, translate_address_write(addr + 3), value); |
| } |
| else |
| { |
| memory.write32(phys_low, value); |
| } |
| } |
| // read 2 or 4 byte from ip, depending on address size attribute |
| function read_moffs() |
| { |
| if(address_size_32) |
| { |
| return get_seg_prefix(reg_ds) + read_imm32s(); |
| } |
| else |
| { |
| return get_seg_prefix(reg_ds) + read_imm16(); |
| } |
| } |
| function get_flags() |
| { |
| return (flags & ~flags_all) | getcf() | getpf() | getaf() | getzf() | getsf() | getof(); |
| } |
| function load_flags() |
| { |
| flags = get_flags(); |
| flags_changed = 0; |
| } |
| // get esp with paging disabled |
| function get_esp_npe(mod) |
| { |
| if(stack_size_32) |
| { |
| return get_seg(reg_ss) + stack_reg[reg_vsp] + mod; |
| } |
| else |
| { |
| return get_seg(reg_ss) + (stack_reg[reg_vsp] + mod & 0xFFFF); |
| } |
| } |
| function get_esp_pe_read(mod) |
| { |
| // UNSAFE: stack_reg[reg_vsp]+mod needs to be masked in 16 bit mode |
| // (only if paging is enabled and in 16 bit mode) |
| return translate_address_read(get_seg(reg_ss) + stack_reg[reg_vsp] + mod); |
| } |
| function get_esp_pe_write(mod) |
| { |
| return translate_address_write(get_seg(reg_ss) + stack_reg[reg_vsp] + mod); |
| } |
| /* |
| * returns the "real" instruction pointer, |
| * without segment offset |
| */ |
| function get_real_ip() |
| { |
| return instruction_pointer - get_seg(reg_cs); |
| } |
| function call_interrupt_vector(interrupt_nr, is_software_int, error_code) |
| { |
| if(DEBUG) |
| { |
| ops.add(instruction_pointer); |
| ops.add("-- INT " + h(interrupt_nr)); |
| ops.add(1); |
| } |
| //if(interrupt_nr == 0x13) |
| //{ |
| // dbg_log("INT 13"); |
| // dbg_log(memory.read8(ch) + "/" + memory.read8(dh) + "/" + memory.read8(cl) + " |" + memory.read8(al)); |
| // dbg_log("=> ", h(memory.read16(es) * 16 + memory.read16(bx))); |
| //} |
| //if(interrupt_nr == 0x10) |
| //{ |
| // dbg_log("int10 ax=" + h(reg16[reg_ax], 4) + " '" + String.fromCharCode(reg8[reg_al]) + "'"); |
| // dump_regs_short(); |
| // if(reg8[reg_ah] == 0xe) vga.tt_write(reg8[reg_al]); |
| //} |
| //dbg_log("int " + h(interrupt_nr)); |
| //if(interrupt_nr === 0x13) |
| //{ |
| // dump_regs_short(); |
| //} |
| //if(interrupt_nr === 0x80) |
| //{ |
| // dbg_log("linux syscall"); |
| // dump_regs_short(); |
| //} |
| if(interrupt_nr === 14) |
| { |
| dbg_log("int14 error_code=" + error_code + " cr2=" + h(cr2) + " prev=" + h(previous_ip) + " cpl=" + cpl, LOG_CPU); |
| } |
| if(in_hlt) |
| { |
| // return to the instruction following the hlt |
| instruction_pointer++; |
| in_hlt = false; |
| } |
| if(protected_mode) |
| { |
| if((interrupt_nr << 3 | 7) > idtr_size) |
| { |
| dbg_log(interrupt_nr, LOG_CPU); |
| dbg_trace(); |
| throw unimpl("#GP handler"); |
| } |
| var addr = idtr_offset + (interrupt_nr << 3) | 0; |
| dbg_assert((addr & 0xFFF) < 0xFF8); |
| if(paging) |
| { |
| addr = translate_address_system_read(addr); |
| } |
| var base = memory.read16(addr) | memory.read16(addr + 6) << 16, |
| selector = memory.read16(addr + 2), |
| type = memory.read8(addr + 5), |
| dpl = type >> 5 & 3, |
| is_trap; |
| if((type & 128) === 0) |
| { |
| // present bit not set |
| throw unimpl("#NP handler"); |
| } |
| if(is_software_int && dpl < cpl) |
| { |
| trigger_gp(interrupt_nr << 3 | 2); |
| } |
| type &= 31; |
| if(type === 14) |
| { |
| is_trap = false; |
| } |
| else if(type === 15) |
| { |
| is_trap = true; |
| } |
| else if(type === 5) |
| { |
| throw unimpl("call int to task gate"); |
| } |
| else if(type === 6) |
| { |
| throw unimpl("16 bit interrupt gate"); |
| } |
| else if(type === 7) |
| { |
| throw unimpl("16 bit trap gate"); |
| } |
| else |
| { |
| // invalid type |
| dbg_trace(); |
| dbg_log("invalid type: " + h(type)); |
| dbg_log(h(addr) + " " + h(base) + " " + h(selector)); |
| throw unimpl("#GP handler"); |
| } |
| var info = lookup_segment_selector(selector); |
| if(info.is_null) |
| { |
| dbg_log("is null"); |
| throw unimpl("#GP handler"); |
| } |
| if(info === -1) |
| { |
| dbg_log("is -1"); |
| throw unimpl("#GP handler"); |
| } |
| if(!info.is_executable || info.dpl > cpl) |
| { |
| dbg_log("not exec"); |
| throw unimpl("#GP handler"); |
| } |
| if(!info.is_present) |
| { |
| dbg_log("not present"); |
| throw unimpl("#NP handler"); |
| } |
| if(flags & flag_vm) |
| { |
| throw unimpl("VM flag"); |
| } |
| if(!info.dc_bit && info.dpl < cpl) |
| { |
| // inter privilege level interrupt |
| var tss_stack_addr = (info.dpl << 3) + 4; |
| if(tss_stack_addr + 5 > tsr_size) |
| { |
| throw unimpl("#TS handler"); |
| } |
| tss_stack_addr += tsr_offset; |
| if(paging) |
| { |
| tss_stack_addr = translate_address_system_read(tss_stack_addr); |
| } |
| var new_esp = memory.read32s(tss_stack_addr), |
| new_ss = memory.read16(tss_stack_addr + 4), |
| ss_info = lookup_segment_selector(new_ss); |
| if(ss_info.is_null) |
| { |
| throw unimpl("#TS handler"); |
| } |
| if(ss_info.rpl !== info.dpl) |
| { |
| throw unimpl("#TS handler"); |
| } |
| if(ss_info.dpl !== info.dpl || !ss_info.rw_bit) |
| { |
| throw unimpl("#TS handler"); |
| } |
| if(!ss_info.is_present) |
| { |
| throw unimpl("#TS handler"); |
| } |
| var old_esp = reg32s[reg_esp], |
| old_ss = sreg[reg_ss]; |
| reg32[reg_esp] = new_esp; |
| sreg[reg_ss] = new_ss; |
| cpl = info.dpl; |
| //dbg_log("int" + h(interrupt_nr, 2) +" from=" + h(instruction_pointer, 8) |
| // + " cpl=" + cpl + " old ss:esp=" + h(old_ss,4) + ":" + h(old_esp,8), LOG_CPU); |
| cpl_changed(); |
| push32(old_ss); |
| push32(old_esp); |
| } |
| else if(info.dc_bit || info.dpl === cpl) |
| { |
| // intra privilege level interrupt |
| //dbg_log("int" + h(interrupt_nr, 2) +" from=" + h(instruction_pointer, 8), LOG_CPU); |
| } |
| load_flags(); |
| push32(flags); |
| push32(sreg[reg_cs]); |
| push32(get_real_ip()); |
| //dbg_log("pushed eip to " + h(reg32[reg_esp], 8), LOG_CPU); |
| if(error_code !== false) |
| { |
| dbg_assert(typeof error_code == "number"); |
| push32(error_code); |
| } |
| // TODO |
| sreg[reg_cs] = selector; |
| //switch_seg(reg_cs); |
| //dbg_log("current esp: " + h(reg32[reg_esp]), LOG_CPU); |
| //dbg_log("call int " + h(interrupt_nr) + " from " + h(instruction_pointer) + " to " + h(base) + " with error_code=" + error_code, LOG_CPU); |
| instruction_pointer = get_seg(reg_cs) + base | 0; |
| //dbg_log("int" + h(interrupt_nr) + " trap=" + is_trap + " if=" + +!!(flags & flag_interrupt)); |
| if(!is_trap) |
| { |
| // clear int flag for interrupt gates |
| flags &= ~flag_interrupt; |
| } |
| else |
| { |
| handle_irqs(); |
| } |
| } |
| else |
| { |
| // call 4 byte cs:ip interrupt vector from ivt at memory 0 |
| //logop(instruction_pointer, "callu " + h(interrupt_nr) + "." + h(memory.read8(ah))); |
| //dbg_log("callu " + h(interrupt_nr) + "." + h(memory.read8(ah)) + " at " + h(instruction_pointer, 8), LOG_CPU, LOG_CPU); |
| // push flags, cs:ip |
| load_flags(); |
| push16(flags); |
| push16(sreg[reg_cs]); |
| push16(get_real_ip()); |
| flags = flags & ~flag_interrupt; |
| switch_seg(reg_cs, memory.read16((interrupt_nr << 2) + 2)); |
| instruction_pointer = get_seg(reg_cs) + memory.read16(interrupt_nr << 2) | 0; |
| } |
| } |
| // assumes ip to point to the byte before the next instruction |
| function raise_exception(interrupt_nr) |
| { |
| if(DEBUG) |
| { |
| // warn about error |
| dbg_log("Exception " + h(interrupt_nr), LOG_CPU); |
| dbg_trace(); |
| //throw "exception: " + interrupt_nr; |
| } |
| // TODO |
| call_interrupt_vector(interrupt_nr, false, false); |
| throw 0xDEADBEE; |
| } |
| function raise_exception_with_code(interrupt_nr, error_code) |
| { |
| if(DEBUG) |
| { |
| dbg_log("Exception " + h(interrupt_nr) + " err=" + h(error_code), LOG_CPU); |
| dbg_trace(); |
| //throw "exception: " + interrupt_nr; |
| } |
| call_interrupt_vector(interrupt_nr, false, error_code); |
| throw 0xDEADBEE; |
| } |
| function trigger_de() |
| { |
| instruction_pointer = previous_ip; |
| raise_exception(0); |
| } |
| function trigger_ud() |
| { |
| instruction_pointer = previous_ip; |
| raise_exception(6); |
| } |
| function trigger_gp(code) |
| { |
| instruction_pointer = previous_ip; |
| raise_exception_with_code(13, code); |
| } |
| function trigger_np(code) |
| { |
| instruction_pointer = previous_ip; |
| raise_exception_with_code(11, code); |
| } |
| function trigger_ss(code) |
| { |
| instruction_pointer = previous_ip; |
| raise_exception_with_code(12, code); |
| } |
| /** |
| * @param {number} seg |
| */ |
| function seg_prefix(seg) |
| { |
| dbg_assert(segment_prefix === -1); |
| dbg_assert(seg >= 0 && seg <= 5); |
| segment_prefix = seg; |
| table[read_imm8()](); |
| segment_prefix = -1; |
| } |
| /** |
| * Get segment base by prefix or default |
| * @param {number} default_segment |
| */ |
| function get_seg_prefix(default_segment /*, offset*/) |
| { |
| if(segment_prefix === -1) |
| { |
| return get_seg(default_segment /*, offset*/); |
| } |
| else |
| { |
| return get_seg(segment_prefix /*, offset*/); |
| } |
| } |
| /** |
| * Get segment base |
| * @param {number} segment |
| */ |
| function get_seg(segment /*, offset*/) |
| { |
| dbg_assert(segment >= 0 && segment < 8); |
| dbg_assert(protected_mode || (sreg[segment] << 4) == segment_offsets[segment]); |
| if(protected_mode) |
| { |
| if(segment_is_null[segment]) |
| { |
| // trying to access null segment |
| if(DEBUG) |
| { |
| dbg_log("Load null segment: " + h(segment), LOG_CPU); |
| throw unimpl("#GP handler"); |
| } |
| } |
| // TODO: |
| // - validate segment limits |
| // - validate if segment is writable |
| // - set accessed bit |
| } |
| return segment_offsets[segment]; |
| } |
| function arpl(seg, r16) |
| { |
| flags_changed &= ~flag_zero; |
| if((seg & 3) < (reg16[r16] & 3)) |
| { |
| flags |= flag_zero; |
| return seg & ~3 | reg16[r16] & 3; |
| } |
| else |
| { |
| flags &= ~flag_zero; |
| return seg; |
| } |
| } |
| function handle_irqs() |
| { |
| if(pic) |
| { |
| if((flags & flag_interrupt) && !page_fault) |
| { |
| pic.handle_irqs(); |
| } |
| } |
| } |
| // any two consecutive 8-bit ports can be treated as a 16-bit port; |
| // and four consecutive 8-bit ports can be treated as a 32-bit port |
| // |
| // http://css.csail.mit.edu/6.858/2012/readings/i386/s08_01.htm |
| function out8(port_addr, out_byte) |
| { |
| if(privileges_for_io()) |
| { |
| io.port_write(port_addr, out_byte); |
| } |
| else |
| { |
| trigger_gp(0); |
| } |
| } |
| function out16(port_addr, out_word) |
| { |
| if(privileges_for_io()) |
| { |
| io.port_write(port_addr, out_word & 0xFF); |
| io.port_write(port_addr + 1, out_word >> 8 & 0xFF); |
| } |
| else |
| { |
| trigger_gp(0); |
| } |
| } |
| function out32(port_addr, out_dword) |
| { |
| if(privileges_for_io()) |
| { |
| io.port_write(port_addr, out_dword & 0xFF); |
| io.port_write(port_addr + 1, out_dword >> 8 & 0xFF); |
| io.port_write(port_addr + 2, out_dword >> 16 & 0xFF); |
| io.port_write(port_addr + 3, out_dword >> 24 & 0xFF); |
| } |
| else |
| { |
| trigger_gp(0); |
| } |
| } |
| function in8(port_addr) |
| { |
| if(privileges_for_io()) |
| { |
| return io.port_read(port_addr); |
| } |
| else |
| { |
| trigger_gp(0); |
| } |
| } |
| function in16(port_addr) |
| { |
| if(privileges_for_io()) |
| { |
| return io.port_read(port_addr) | |
| io.port_read(port_addr + 1) << 8; |
| } |
| else |
| { |
| trigger_gp(0); |
| } |
| } |
| function in32(port_addr) |
| { |
| if(privileges_for_io()) |
| { |
| return io.port_read(port_addr) | |
| io.port_read(port_addr + 1) << 8 | |
| io.port_read(port_addr + 2) << 16 | |
| io.port_read(port_addr + 3) << 24; |
| } |
| else |
| { |
| trigger_gp(0); |
| } |
| } |
| /** |
| * returns the current iopl from the eflags register |
| */ |
| function getiopl() |
| { |
| return flags >> 12 & 3; |
| } |
| function privileges_for_io() |
| { |
| return !protected_mode || cpl <= getiopl(); |
| } |
| function cpuid() |
| { |
| // cpuid |
| // TODO: Fill in with less bogus values |
| // http://lxr.linux.no/linux+%2a/arch/x86/include/asm/cpufeature.h |
| var id = reg32s[reg_eax]; |
| if((id & 0x7FFFFFFF) === 0) |
| { |
| reg32[reg_eax] = 2; |
| if(id === 0) |
| { |
| reg32[reg_ebx] = 0x756E6547; // Genu |
| reg32[reg_edx] = 0x49656E69; // ineI |
| reg32[reg_ecx] = 0x6C65746E; // ntel |
| } |
| } |
| else if(id === 1) |
| { |
| // pentium |
| reg32[reg_eax] = 0x513; |
| reg32[reg_ebx] = 0; |
| reg32[reg_ecx] = 0; |
| reg32[reg_edx] = fpu.is_fpu | 1 << 3 | 1 << 4 | 1 << 8| 1 << 13 | 1 << 15; |
| } |
| else if(id === 2) |
| { |
| // Taken from http://siyobik.info.gf/main/reference/instruction/CPUID |
| reg32[reg_eax] = 0x665B5001; |
| reg32[reg_ebx] = 0; |
| reg32[reg_ecx] = 0; |
| reg32[reg_edx] = 0x007A7000; |
| } |
| else if(id === (0x80860000 | 0)) |
| { |
| reg32[reg_eax] = 0; |
| reg32[reg_ebx] = 0; |
| reg32[reg_ecx] = 0; |
| reg32[reg_edx] = 0; |
| } |
| else if((id & 0xF0000000) === ~~0x40000000) |
| { |
| // Invalid |
| } |
| else |
| { |
| if(DEBUG) throw "cpuid: unimplemented eax: " + h(id); |
| } |
| } |
| /** |
| * Update the flags register depending on iopl and cpl |
| */ |
| function update_flags(new_flags) |
| { |
| if(cpl === 0 || !protected_mode) |
| { |
| // can update all flags |
| flags = new_flags; |
| } |
| else if(cpl <= getiopl()) |
| { |
| // cpl != 0 and iopl <= cpl |
| // can update interrupt flag but not iopl |
| flags = (new_flags & ~flag_iopl) | (flags & flag_iopl); |
| } |
| else |
| { |
| // cannot update interrupt flag or iopl |
| flags = (new_flags & ~flag_iopl & ~flag_interrupt) | (flags & (flag_iopl | flag_interrupt)); |
| } |
| flags_changed = 0; |
| //flags = (flags & flags_mask) | flags_default; |
| } |
| function update_operand_size() |
| { |
| if(operand_size_32) |
| { |
| table = table32; |
| table0F = table0F_32; |
| } |
| else |
| { |
| table = table16; |
| table0F = table0F_16; |
| } |
| } |
| function update_address_size() |
| { |
| if(address_size_32) |
| { |
| modrm_resolve = modrm_resolve32; |
| regv = reg32; |
| reg_vcx = reg_ecx; |
| reg_vsi = reg_esi; |
| reg_vdi = reg_edi; |
| } |
| else |
| { |
| modrm_resolve = modrm_resolve16; |
| regv = reg16; |
| reg_vcx = reg_cx; |
| reg_vsi = reg_si; |
| reg_vdi = reg_di; |
| } |
| } |
| /** |
| * @param {number} selector |
| */ |
| function lookup_segment_selector(selector) |
| { |
| var is_gdt = (selector & 4) === 0, |
| selector_offset = selector & ~7, |
| info, |
| table_offset, |
| table_limit; |
| info = { |
| rpl: selector & 3, |
| from_gdt: is_gdt, |
| is_null: false, |
| is_valid: true, |
| }; |
| if(is_gdt) |
| { |
| table_offset = gdtr_offset; |
| table_limit = gdtr_size; |
| } |
| else |
| { |
| table_offset = ldtr_offset |
| table_limit = ldtr_size; |
| } |
| if(selector_offset === 0) |
| { |
| info.is_null = true; |
| return info; |
| } |
| // limit is the number of entries in the table minus one |
| if((selector_offset >> 3) > table_limit) |
| { |
| info.is_valid = false; |
| return info; |
| } |
| table_offset += selector_offset; |
| if(paging) |
| { |
| table_offset = translate_address_system_read(table_offset); |
| } |
| info.base = memory.read16(table_offset + 2) | memory.read8(table_offset + 4) << 16 | |
| memory.read8(table_offset + 7) << 24, |
| info.access = memory.read8(table_offset + 5), |
| info.flags = memory.read8(table_offset + 6) >> 4, |
| info.limit = memory.read16(table_offset) | (memory.read8(table_offset + 6) & 0xF) << 16, |
| // used if system |
| info.type = info.access & 0xF; |
| info.dpl = info.access >> 5 & 3; |
| info.is_system = (info.access & 0x10) === 0; |
| info.is_present = (info.access & 0x80) === 0x80; |
| info.is_executable = (info.access & 8) === 8; |
| info.rw_bit = (info.access & 2) === 2; |
| info.dc_bit = (info.access & 4) === 4; |
| info.size = (info.flags & 4) === 4; |
| info.granularity = (info.flags & 8) === 8; |
| if(info.gr_bit) |
| { |
| info.real_limit = (info.limit << 12 | 0xFFF) >>> 0; |
| } |
| else |
| { |
| info.real_limit = info.limit; |
| } |
| info.is_writable = info.rw_bit && !info.is_executable; |
| info.is_readable = info.rw_bit || !info.is_executable; |
| return info; |
| } |
| /** |
| * @param {number} reg |
| * @param {number} selector |
| */ |
| function switch_seg(reg, selector) |
| { |
| dbg_assert(reg >= 0 && reg <= 5); |
| dbg_assert(typeof selector === "number" && selector < 0x10000 && selector >= 0); |
| if(reg === reg_cs) |
| { |
| protected_mode = (cr0 & 1) === 1; |
| } |
| if(!protected_mode) |
| { |
| sreg[reg] = selector; |
| segment_is_null[reg] = 0; |
| segment_limits[reg] = 0xFFFFF; |
| segment_offsets[reg] = selector << 4; |
| return; |
| } |
| var info = lookup_segment_selector(selector); |
| if(reg === reg_ss) |
| { |
| if(info.is_null) |
| { |
| trigger_gp(0); |
| return false; |
| } |
| if(!info.is_valid || |
| info.is_system || |
| info.rpl !== cpl || |
| !info.is_writable || |
| info.dpl !== cpl) |
| { |
| trigger_gp(selector & ~3); |
| return false; |
| } |
| if(!info.is_present) |
| { |
| trigger_ss(selector & ~3); |
| return false; |
| } |
| stack_size_32 = info.size; |
| if(info.size) |
| { |
| stack_reg = reg32s; |
| reg_vsp = reg_esp; |
| reg_vbp = reg_ebp; |
| } |
| else |
| { |
| stack_reg = reg16; |
| reg_vsp = reg_sp; |
| reg_vbp = reg_bp; |
| } |
| } |
| else if(reg === reg_cs) |
| { |
| if(!info.is_executable) |
| { |
| // cs not executable |
| dbg_log(info + " " + h(selector & ~3), LOG_CPU); |
| throw unimpl("#GP handler"); |
| } |
| if(info.is_system) |
| { |
| dbg_log(info + " " + h(selector & ~3), LOG_CPU); |
| throw unimpl("load system segment descriptor, type = " + (info.access & 15)); |
| } |
| if(info.dc_bit && (info.dpl !== info.rpl)) |
| { |
| dbg_log(info + " " + h(selector & ~3), LOG_CPU); |
| throw unimpl("#GP handler"); |
| } |
| if(info.rpl !== cpl) |
| { |
| dbg_log(info + " " + h(selector & ~3), LOG_CPU); |
| throw unimpl("privilege change"); |
| } |
| dbg_assert(cpl === info.dpl); |
| if(!info.dc_bit && info.dpl < cpl) |
| { |
| throw unimpl("inter privilege interrupt"); |
| } |
| else |
| { |
| if(info.dc_bit || info.dpl === cpl) |
| { |
| // ok |
| } |
| else |
| { |
| // PE = 1, interrupt or trap gate, nonconforming code segment, DPL > CPL |
| dbg_log(info + " " + h(selector & ~3), LOG_CPU); |
| throw unimpl("#GP handler"); |
| } |
| } |
| operand_size_32 = address_size_32 = is_32 = info.size; |
| update_operand_size(); |
| update_address_size(); |
| } |
| else |
| { |
| // es, ds, fs, gs |
| if(info.is_null) |
| { |
| sreg[reg] = selector; |
| segment_is_null[reg] = 1; |
| return true; |
| } |
| if(!info.is_valid || |
| info.is_system || |
| !info.is_readable || |
| ((!info.is_executable || !info.dc_bit) && |
| info.rpl > info.dpl && |
| cpl > info.dpl)) |
| { |
| trigger_gp(selector & ~3); |
| return false; |
| } |
| if(!info.is_present) |
| { |
| trigger_np(selector & ~3); |
| return false; |
| } |
| } |
| //dbg_log("seg " + reg + " " + h(info.base)); |
| segment_is_null[reg] = 0; |
| segment_limits[reg] = info.real_limit; |
| segment_infos[reg] = 0; // TODO |
| segment_offsets[reg] = info.base; |
| sreg[reg] = selector; |
| return true; |
| } |
| function load_tr(selector) |
| { |
| var info = lookup_segment_selector(selector); |
| //dbg_log("load tr"); |
| if(!info.from_gdt) |
| { |
| throw unimpl("TR can only be loaded from GDT"); |
| } |
| if(info.is_null) |
| { |
| dbg_log("#GP(0) | tried to load null selector (ltr)"); |
| throw unimpl("#GP handler"); |
| } |
| if(!info.is_present) |
| { |
| dbg_log("#GP | present bit not set (ltr)"); |
| throw unimpl("#GP handler"); |
| } |
| if(!info.is_system) |
| { |
| dbg_log("#GP | ltr: not a system entry"); |
| throw unimpl("#GP handler"); |
| } |
| if(info.type !== 9) |
| { |
| dbg_log("#GP | ltr: invalid type (type = " + info.type + ")"); |
| throw unimpl("#GP handler"); |
| } |
| tsr_size = info.limit; |
| tsr_offset = info.base; |
| //dbg_log("tsr at " + h(tsr_offset) + "; (" + tsr_size + " bytes)"); |
| } |
| function load_ldt(selector) |
| { |
| var info = lookup_segment_selector(selector); |
| if(info.is_null) |
| { |
| // invalid |
| ldtr_size = 0; |
| ldtr_offset = 0; |
| return; |
| } |
| if(!info.from_gdt) |
| { |
| throw unimpl("LDTR can only be loaded from GDT"); |
| } |
| if(!info.is_present) |
| { |
| dbg_log("lldt: present bit not set"); |
| throw unimpl("#GP handler"); |
| } |
| if(!info.is_system) |
| { |
| dbg_log("lldt: not a system entry"); |
| throw unimpl("#GP handler"); |
| } |
| if(info.type !== 2) |
| { |
| dbg_log("lldt: invalid type (" + info.type + ")"); |
| throw unimpl("#GP handler"); |
| } |
| ldtr_size = info.limit; |
| ldtr_offset = info.base; |
| //dbg_log("ldt at " + h(ldtr_offset) + "; (" + ldtr_size + " bytes)"); |
| } |
| function clear_tlb() |
| { |
| // clear tlb excluding global pages |
| last_virt_eip = -1; |
| last_virt_esp = -1; |
| tlb_info.set(tlb_info_global); |
| //dbg_log("page table loaded", LOG_CPU); |
| } |
| function full_clear_tlb() |
| { |
| // clear tlb including global pages |
| tlb_info_global = new Uint8Array(1 << 20); |
| clear_tlb(); |
| } |
| function invlpg(addr) |
| { |
| var page = addr >>> 12; |
| dbg_log("invlpg: " + h(page), LOG_CPU); |
| tlb_info[page] = 0; |
| tlb_info_global[page] = 0; |
| last_virt_eip = -1; |
| last_virt_esp = -1; |
| } |
| /** |
| * @param {number} addr |
| */ |
| function translate_address_disabled(addr) |
| { |
| return addr; |
| } |
| function translate_address_user_write(addr) |
| { |
| var base = addr >>> 12; |
| if(tlb_info[base] & TLB_USER_WRITE) |
| { |
| return tlb_user_write[base] ^ addr; |
| } |
| else |
| { |
| return do_page_translation(addr, 1, 1) | addr & 0xFFF; |
| } |
| } |
| function translate_address_user_read(addr) |
| { |
| var base = addr >>> 12; |
| if(tlb_info[base] & TLB_USER_READ) |
| { |
| return tlb_user_read[base] ^ addr; |
| } |
| else |
| { |
| return do_page_translation(addr, 0, 1) | addr & 0xFFF; |
| } |
| } |
| function translate_address_system_write(addr) |
| { |
| var base = addr >>> 12; |
| if(tlb_info[base] & TLB_SYSTEM_WRITE) |
| { |
| return tlb_system_write[base] ^ addr; |
| } |
| else |
| { |
| return do_page_translation(addr, 1, 0) | addr & 0xFFF; |
| } |
| } |
| function translate_address_system_read(addr) |
| { |
| var base = addr >>> 12; |
| if(tlb_info[base] & TLB_SYSTEM_READ) |
| { |
| return tlb_system_read[base] ^ addr; |
| } |
| else |
| { |
| return do_page_translation(addr, 0, 0) | addr & 0xFFF; |
| } |
| } |
| /** |
| * @return {number} |
| */ |
| function do_page_translation(addr, for_writing, user) |
| { |
| var page = addr >>> 12, |
| page_dir_addr = (cr3 >>> 2) + (page >> 10), |
| page_dir_entry = memory.mem32s[page_dir_addr], |
| high, |
| can_write = true, |
| global, |
| cachable = true, |
| allow_user = true; |
| if(!(page_dir_entry & 1)) |
| { |
| // to do at this place: |
| // |
| // - set cr2 = addr (which caused the page fault) |
| // - call_interrupt_vector with id 14, error code 0-7 (requires information if read or write) |
| // - prevent execution of the function that triggered this call |
| dbg_log("#PF not present", LOG_CPU); |
| cr2 = addr; |
| trigger_pagefault(for_writing, user, 0); |
| // never reached as trigger_pagefault throws up |
| dbg_assert(false); |
| } |
| if((page_dir_entry & 2) === 0) |
| { |
| can_write = false; |
| if(for_writing) |
| { |
| cr2 = addr; |
| trigger_pagefault(for_writing, user, 1); |
| dbg_assert(false); |
| } |
| } |
| if((page_dir_entry & 4) === 0) |
| { |
| allow_user = false; |
| if(user) |
| { |
| // "Page Fault: page table accessed by non-supervisor"; |
| dbg_log("#PF supervisor", LOG_CPU); |
| cr2 = addr; |
| trigger_pagefault(for_writing, user, 1); |
| dbg_assert(false); |
| } |
| } |
| if((page_dir_entry & 0x10) === 0) |
| { |
| cachable = false; |
| } |
| if(page_dir_entry & page_size_extensions) |
| { |
| // size bit is set |
| // set the accessed and dirty bits |
| memory.mem32s[page_dir_addr] = page_dir_entry | 0x20 | for_writing << 6; |
| high = (page_dir_entry & 0xFFC00000) | (page << 12 & 0x3FF000); |
| global = page_dir_entry & 0x100; |
| } |
| else |
| { |
| var page_table_addr = ((page_dir_entry & 0xFFFFF000) >>> 2) + (page & 0x3FF), |
| page_table_entry = memory.mem32s[page_table_addr]; |
| if(!(page_table_entry & 1)) |
| { |
| dbg_log("#PF not present table", LOG_CPU); |
| cr2 = addr; |
| trigger_pagefault(for_writing, user, 0); |
| dbg_assert(false); |
| } |
| if((page_table_entry & 2) === 0) |
| { |
| can_write = false; |
| if(for_writing) |
| { |
| dbg_log("#PF not writable page", LOG_CPU); |
| cr2 = addr; |
| trigger_pagefault(for_writing, user, 1); |
| dbg_assert(false); |
| } |
| } |
| if((page_table_entry & 4) === 0) |
| { |
| allow_user = false; |
| if(user) |
| { |
| dbg_log("#PF not supervisor page", LOG_CPU); |
| cr2 = addr; |
| trigger_pagefault(for_writing, user, 1); |
| dbg_assert(false); |
| } |
| } |
| if((page_table_entry & 0x10) === 0) |
| { |
| cachable = false; |
| } |
| // set the accessed and dirty bits |
| memory.mem32s[page_dir_addr] = page_dir_entry | 0x20; |
| memory.mem32s[page_table_addr] = page_table_entry | 0x20 | for_writing << 6; |
| high = page_table_entry & 0xFFFFF000; |
| global = page_table_entry & 0x100; |
| } |
| if(cachable) |
| { |
| var cache_entry = high ^ page << 12, |
| info = 0; |
| if(allow_user) |
| { |
| tlb_user_read[page] = cache_entry; |
| info |= TLB_USER_READ; |
| if(can_write) |
| { |
| tlb_user_write[page] = cache_entry; |
| info |= TLB_USER_WRITE; |
| } |
| } |
| tlb_system_read[page] = cache_entry; |
| info |= TLB_SYSTEM_READ; |
| if(can_write) |
| { |
| tlb_system_write[page] = cache_entry; |
| info |= TLB_SYSTEM_WRITE; |
| } |
| tlb_info[page] |= info; |
| if(global) |
| { |
| tlb_info_global[page] = info; |
| } |
| } |
| return high ; |
| } |
| function trigger_pagefault(write, user, present) |
| { |
| if(LOG_LEVEL & LOG_CPU) |
| { |
| dbg_trace(); |
| } |
| if(page_fault) |
| { |
| dbg_trace(); |
| throw unimpl("Double fault"); |
| } |
| instruction_pointer = previous_ip; |
| page_fault = true; |
| call_interrupt_vector(14, false, user << 2 | write << 1 | present); |
| throw 0xDEADBEE; |
| } |
| // it looks pointless to have these two here, but |
| // Closure Compiler is able to remove unused functions |
| //#include "test_helpers.js" |
| "use strict"; |
| debug.dump_regs = dump_regs; |
| debug.dump_regs_short = dump_regs_short; |
| debug.dump_stack = dump_stack; |
| debug.dump_page_directory = dump_page_directory; |
| debug.dump_gdt_ldt = dump_gdt_ldt; |
| debug.dump_idt = dump_idt; |
| debug.step = step; |
| debug.run_until = run_until; |
| debug.debugger = function() |
| { |
| debugger; |
| } |
| function step() |
| { |
| step_mode = true; |
| if(!running) |
| { |
| cycle(); |
| } |
| dump_regs(); |
| var now = Date.now(); |
| vga.timer(now); |
| timer.timer(now); |
| rtc.timer(now); |
| running = false; |
| } |
| function run_until() |
| { |
| running = false; |
| var a = parseInt(prompt("input hex", ""), 16); |
| if(a) while(instruction_pointer != a) cycle() |
| dump_regs(); |
| } |
| // http://ref.x86asm.net/x86reference.xml |
| // for debuggin' purposes |
| var opcode_map = [ |
| "ADD", "ADD", "ADD", "ADD", "ADD", "ADD", "PUSH", "POP", |
| "OR", "OR", "OR", "OR", "OR", "OR", "PUSH", "0F:", |
| "ADC", "ADC", "ADC", "ADC", "ADC", "ADC", "PUSH", "POP", |
| "SBB", "SBB", "SBB", "SBB", "SBB", "SBB", "PUSH", "POP", |
| "AND", "AND", "AND", "AND", "AND", "AND", "ES", "DAA", |
| "SUB", "SUB", "SUB", "SUB", "SUB", "SUB", "CS", "DAS", |
| "XOR", "XOR", "XOR", "XOR", "XOR", "XOR", "SS", "AAA", |
| "CMP", "CMP", "CMP", "CMP", "CMP", "CMP", "DS", "AAS", |
| "INC", "INC", "INC", "INC", "INC", "INC", "INC", "INC", |
| "DEC", "DEC", "DEC", "DEC", "DEC", "DEC", "DEC", "DEC", |
| "PUSH", "PUSH", "PUSH", "PUSH", "PUSH", "PUSH", "PUSH", "PUSH", |
| "POP", "POP", "POP", "POP", "POP", "POP", "POP", "POP", |
| "PUSHA", "POPA", "BOUND", "ARPL", "FS", "GS", "none", "none", |
| "PUSH", "IMUL", "PUSH", "IMUL", "INS", "INS", "OUTS", "OUTS", |
| "JO", "JNO", "JB", "JNB", "JZ", "JNZ", "JBE", "JNBE", |
| "JS", "JNS", "JP", "JNP", "JL", "JNL", "JLE", "JNLE", |
| "ADD", "ADD", "ADD", "ADD", "TEST", "TEST", "XCHG", "XCHG", |
| "MOV", "MOV", "MOV", "MOV", "MOV", "LEA", "MOV", "POP", |
| "NOP", "XCHG", "XCHG", "XCHG", "XCHG", "XCHG", "XCHG", "XCHG", |
| "CBW", "CWD", "CALLF", "FWAIT", "PUSHF", "POPF", "SAHF", "LAHF", |
| "MOV", "MOV", "MOV", "MOV", "MOVS", "MOVS", "CMPS", "CMPS", |
| "TEST", "TEST", "STOS", "STOS", "LODS", "LODS", "SCAS", "SCAS", |
| "MOV", "MOV", "MOV", "MOV", "MOV", "MOV", "MOV", "MOV", |
| "MOV", "MOV", "MOV", "MOV", "MOV", "MOV", "MOV", "MOV", |
| "ROL", "ROL", "RETN", "RETN", "LES", "LDS", "MOV", "MOV", |
| "ENTER", "LEAVE", "RETF", "RETF", "INT", "INT", "INTO", "IRET", |
| "ROL", "ROL", "ROL", "ROL", "AAM", "AAD", "none", "XLAT", |
| "FADD", "FLD", "FIADD", "FILD", "FADD", "FLD", "FIADD", "FILD", |
| "LOOPNZ", "LOOPZ", "LOOP", "JCXZ", "IN", "IN", "OUT", "OUT", |
| "CALL", "JMP", "JMPF", "JMP", "IN", "IN", "OUT", "OUT", |
| "LOCK", "none", "REPNZ", "REPZ", "HLT", "CMC", "TEST", "TEST", |
| "CLC", "STC", "CLI", "STI", "CLD", "STD", "INC", "INC" |
| ]; |
| function logop(_ip, op) |
| { |
| if(!DEBUG || !ops) |
| { |
| return; |
| } |
| if(!step_mode) |
| { |
| //return; |
| } |
| ops.add(_ip); |
| ops.add(opcode_map[op] || "unkown"); |
| ops.add(op); |
| } |
| function dump_stack(start, end) |
| { |
| var esp = reg32[reg_esp]; |
| dbg_log("========= STACK =========="); |
| if(end >= start || end === undefined) |
| { |
| start = 5; |
| end = -5; |
| } |
| for(var i = start; i > end; i--) |
| { |
| var line = " "; |
| if(!i) line = "=> "; |
| line += h(i, 2) + " | "; |
| dbg_log(line + h(esp + 4 * i, 8) + " | " + h(memory.read32s(esp + 4 * i) >>> 0)); |
| } |
| } |
| function dump_regs_short() |
| { |
| var |
| r32 = { "eax": reg_eax, "ecx": reg_ecx, "edx": reg_edx, "ebx": reg_ebx, |
| "esp": reg_esp, "ebp": reg_ebp, "esi": reg_esi, "edi": reg_edi }, |
| r32_names = ["eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"], |
| s = { "cs": reg_cs, "ds": reg_ds, "es": reg_es, "fs": reg_fs, "gs": reg_gs, "ss": reg_ss }, |
| line1 = "", |
| line2 = ""; |
| for(var i = 0; i < 4; i++) |
| { |
| line1 += r32_names[i] + "=" + h(reg32[r32[r32_names[i]]], 8) + " "; |
| line2 += r32_names[i+4] + "=" + h(reg32[r32[r32_names[i+4]]], 8) + " "; |
| } |
| line1 += " eip=" + h(get_real_ip(), 8); |
| line2 += " flg=" + h(get_flags()); |
| line1 += " ds=" + h(sreg[reg_ds], 4) + " es=" + h(sreg[reg_es], 4) + " fs=" + h(sreg[reg_fs], 4); |
| line2 += " gs=" + h(sreg[reg_gs], 4) + " cs=" + h(sreg[reg_cs], 4) + " ss=" + h(sreg[reg_ss], 4); |
| dbg_log(line1); |
| dbg_log(line2); |
| } |
| function dump_regs() |
| { |
| var |
| r32 = { "eax": reg_eax, "ecx": reg_ecx, "edx": reg_edx, "ebx": reg_ebx, |
| "esp": reg_esp, "ebp": reg_ebp, "esi": reg_esi, "edi": reg_edi }, |
| s = { "cs": reg_cs, "ds": reg_ds, "es": reg_es, |
| "fs": reg_fs, "gs": reg_gs, "ss": reg_ss }, |
| out = ""; |
| var opcodes = ops.toArray(); |
| for(var i = 0; i < opcodes.length; i += 3) |
| { |
| if(opcodes[i]) |
| { |
| out += h(opcodes[i], 6) + ": " + |
| String.pads(opcodes[i + 1], 20) + h(opcodes[i + 2], 2) + "\n"; |
| } |
| } |
| //dbg_log(out.substr(0, out.length - 1)); |
| log(out.substr(0, out.length - 1)); |
| ops.clear(); |
| dbg_log("----- DUMP (ip = 0x" + h(instruction_pointer >>> 0) + ") ----------") |
| dbg_log("protected mode: " + protected_mode); |
| for(i in r32) |
| { |
| dbg_log(i + " = 0x" + h(reg32[r32[i]], 8)); |
| } |
| dbg_log("eip = 0x" + h(get_real_ip(), 8)); |
| for(i in s) |
| { |
| dbg_log(i + " = 0x" + h(sreg[s[i]], 4)); |
| //var infos = segment_cache[ s[i] - registers_start >> 1 ]; |
| /*if(infos) |
| { |
| dbg_log(infos); |
| }*/ |
| } |
| out = ""; |
| var flg = { "cf": getcf, "pf": getpf, "zf": getzf, "sf": getsf, |
| "of": getof, "df": flag_direction, "if": flag_interrupt }; |
| for(var i in flg) |
| { |
| if(+flg[i]) |
| { |
| out += i + "=" + Number(!!(flags & flg[i])) + " | "; |
| } |
| else |
| { |
| out += i + "=" + Number(!!flg[i]()) + " | "; |
| } |
| } |
| out += "iopl=" + getiopl(); |
| dbg_log(out); |
| //dbg_log("last operation: " + h(last_op1 | 0) + ", " + h(last_op2 | 0) + " = " + |
| //h(last_result | 0) + " (" + last_op_size + " bit)") |
| } |
| function dump_gdt_ldt() |
| { |
| dbg_log("gdt: (len = " + h(gdtr_size) + ")"); |
| dump_table(translate_address_read(gdtr_offset), gdtr_size); |
| dbg_log("\nldt: (len = " + h(ldtr_size) + ")"); |
| dump_table(translate_address_read(ldtr_offset), ldtr_size); |
| function dump_table(addr, size) |
| { |
| for(var i = 0; i < size; i += 8, addr += 8) |
| { |
| var base = memory.read16(addr + 2) | |
| memory.read8(addr + 4) << 16 | |
| memory.read8(addr + 7) << 24, |
| limit = (memory.read16(addr) | memory.read8(addr + 6) & 0xF) + 1, |
| access = memory.read8(addr + 5), |
| flags = memory.read8(addr + 6) >> 4, |
| flags_str = '', |
| dpl = access >> 5 & 3; |
| if(!(access & 128)) |
| { |
| // present bit not set |
| //continue; |
| flags_str += 'NP '; |
| } |
| else |
| { |
| flags_str += ' P '; |
| } |
| if(access & 16) |
| { |
| if(flags & 4) |
| { |
| flags_str += '32b '; |
| } |
| else |
| { |
| flags_str += '16b '; |
| } |
| if(access & 8) |
| { |
| // executable |
| flags_str += 'X '; |
| if(access & 4) |
| { |
| flags_str += 'C '; |
| } |
| } |
| else |
| { |
| // data |
| flags_str += 'R '; |
| } |
| } |
| else |
| { |
| // system |
| flags_str += 'sys: ' + h(access & 15); |
| } |
| if(flags & 8) |
| { |
| limit <<= 12; |
| } |
| dbg_log(h(i & ~7, 4) + " " + h(base >>> 0, 8) + " (" + h(limit, 8) + " bytes) " + |
| flags_str + "; dpl = " + dpl + ", a = " + access.toString(2) + |
| ", f = " + flags.toString(2)); |
| } |
| } |
| } |
| function dump_idt() |
| { |
| for(var i = 0; i < idtr_size; i += 8) |
| { |
| var addr = do_page_translation(idtr_offset + i, 0, 0), |
| base = memory.read16(addr) | memory.read16(addr + 6) << 16, |
| selector = memory.read16(addr + 2), |
| type = memory.read8(addr + 5), |
| line, |
| dpl = type >> 5 & 3; |
| if((type & 31) === 5) |
| { |
| line = 'task gate '; |
| } |
| else if((type & 31) === 14) |
| { |
| line = 'intr gate '; |
| } |
| else if((type & 31) === 15) |
| { |
| line = 'trap gate '; |
| } |
| else |
| { |
| line = 'invalid '; |
| } |
| if(type & 128) |
| { |
| line += ' P'; |
| } |
| else |
| { |
| // present bit not set |
| //continue; |
| line += 'NP'; |
| } |
| dbg_log(h(i >> 3, 4) + " " + h(base >>> 0, 8) + ", " + |
| h(selector, 4) + "; " + line + "; dpl = " + dpl + ", t = " + type.toString(2)); |
| } |
| } |
| function load_page_entry(dword_entry, is_directory) |
| { |
| if(!(dword_entry & 1)) |
| { |
| // present bit not set |
| return false; |
| } |
| var size = (dword_entry & 128) === 128, |
| address; |
| if(size && !is_directory) |
| { |
| address = dword_entry & 0xFFC00000; |
| } |
| else |
| { |
| address = dword_entry & 0xFFFFF000; |
| } |
| return { |
| size: size, |
| global: (dword_entry & 256) === 256, |
| accessed: (dword_entry & 0x20) === 0x20, |
| dirty: (dword_entry & 0x40) === 0x40, |
| cache : (dword_entry & 16) === 16, |
| user : (dword_entry & 4) === 4, |
| read_write : (dword_entry & 2) === 2, |
| address : address >>> 0 |
| }; |
| } |
| function dump_page_directory() |
| { |
| for(var i = 0; i < 1024; i++) |
| { |
| var dword = memory.read32s(cr3 + 4 * i), |
| entry = load_page_entry(dword, true); |
| if(!entry) |
| { |
| continue; |
| } |
| var flags = ''; |
| if(entry.size) |
| flags += 'S '; |
| if(entry.cache) |
| flags += 'D '; |
| if(entry.user) |
| flags += 'U '; |
| if(entry.read_write) |
| flags += 'R '; |
| if(entry.accessed) |
| flags += 'A '; |
| dbg_log("=== " + h(entry.address >>> 0, 8) + " | " + flags); |
| //dbg_log("=========================") |
| if(entry.size) |
| { |
| continue; |
| } |
| for(var j = 0; j < 1024; j++) |
| { |
| dword = memory.read32s(entry.address + 4 * j); |
| var subentry = load_page_entry(dword, false); |
| if(subentry) |
| { |
| flags = ''; |
| if(subentry.size) |
| flags += 'S '; |
| if(subentry.cache) |
| flags += 'D '; |
| if(subentry.user) |
| flags += 'U '; |
| if(subentry.read_write) |
| flags += 'R '; |
| if(subentry.global) |
| flags += 'G '; |
| if(subentry.accessed) |
| flags += 'A '; |
| if(subentry.dirty) |
| flags += 'Di '; |
| dbg_log("# " + h((i << 22 | j << 12) >>> 0, 8) + " -> " + |
| h(subentry.address, 8) + " | " + flags); |
| } |
| } |
| } |
| } |
| /* |
| * This file contains functions to decode the modrm and sib bytes |
| * |
| * These functions return a virtual address |
| * |
| * Gets #included by cpu.macro.js |
| */ |
| "use strict"; |
| var modrm_resolve16, |
| modrm_resolve32; |
| (function() { |
| var modrm_table16 = Array(0xC0), |
| modrm_table32 = Array(0xC0), |
| sib_table = Array(0x100); |
| modrm_table16[0x00 | 0] = function() { return get_seg_prefix(reg_ds) + ((reg16[reg_bx] + reg16[reg_si]) & 0xFFFF) | 0; }; modrm_table16[0x40 | 0] = function() { return get_seg_prefix(reg_ds) + ((reg16[reg_bx] + reg16[reg_si]) + read_imm8s() & 0xFFFF) | 0; }; modrm_table16[0x80 | 0] = function() { return get_seg_prefix(reg_ds) + ((reg16[reg_bx] + reg16[reg_si]) + read_imm16() & 0xFFFF) | 0; }; |
| modrm_table16[0x00 | 1] = function() { return get_seg_prefix(reg_ds) + ((reg16[reg_bx] + reg16[reg_di]) & 0xFFFF) | 0; }; modrm_table16[0x40 | 1] = function() { return get_seg_prefix(reg_ds) + ((reg16[reg_bx] + reg16[reg_di]) + read_imm8s() & 0xFFFF) | 0; }; modrm_table16[0x80 | 1] = function() { return get_seg_prefix(reg_ds) + ((reg16[reg_bx] + reg16[reg_di]) + read_imm16() & 0xFFFF) | 0; }; |
| modrm_table16[0x00 | 2] = function() { return get_seg_prefix(reg_ss) + ((reg16[reg_bp] + reg16[reg_si]) & 0xFFFF) | 0; }; modrm_table16[0x40 | 2] = function() { return get_seg_prefix(reg_ss) + ((reg16[reg_bp] + reg16[reg_si]) + read_imm8s() & 0xFFFF) | 0; }; modrm_table16[0x80 | 2] = function() { return get_seg_prefix(reg_ss) + ((reg16[reg_bp] + reg16[reg_si]) + read_imm16() & 0xFFFF) | 0; }; |
| modrm_table16[0x00 | 3] = function() { return get_seg_prefix(reg_ss) + ((reg16[reg_bp] + reg16[reg_di]) & 0xFFFF) | 0; }; modrm_table16[0x40 | 3] = function() { return get_seg_prefix(reg_ss) + ((reg16[reg_bp] + reg16[reg_di]) + read_imm8s() & 0xFFFF) | 0; }; modrm_table16[0x80 | 3] = function() { return get_seg_prefix(reg_ss) + ((reg16[reg_bp] + reg16[reg_di]) + read_imm16() & 0xFFFF) | 0; }; |
| modrm_table16[0x00 | 4] = function() { return get_seg_prefix(reg_ds) + ((reg16[reg_si]) & 0xFFFF) | 0; }; modrm_table16[0x40 | 4] = function() { return get_seg_prefix(reg_ds) + ((reg16[reg_si]) + read_imm8s() & 0xFFFF) | 0; }; modrm_table16[0x80 | 4] = function() { return get_seg_prefix(reg_ds) + ((reg16[reg_si]) + read_imm16() & 0xFFFF) | 0; }; |
| modrm_table16[0x00 | 5] = function() { return get_seg_prefix(reg_ds) + ((reg16[reg_di]) & 0xFFFF) | 0; }; modrm_table16[0x40 | 5] = function() { return get_seg_prefix(reg_ds) + ((reg16[reg_di]) + read_imm8s() & 0xFFFF) | 0; }; modrm_table16[0x80 | 5] = function() { return get_seg_prefix(reg_ds) + ((reg16[reg_di]) + read_imm16() & 0xFFFF) | 0; }; |
| modrm_table16[0x00 | 6] = function() { return get_seg_prefix(reg_ss) + ((reg16[reg_bp]) & 0xFFFF) | 0; }; modrm_table16[0x40 | 6] = function() { return get_seg_prefix(reg_ss) + ((reg16[reg_bp]) + read_imm8s() & 0xFFFF) | 0; }; modrm_table16[0x80 | 6] = function() { return get_seg_prefix(reg_ss) + ((reg16[reg_bp]) + read_imm16() & 0xFFFF) | 0; }; |
| modrm_table16[0x00 | 7] = function() { return get_seg_prefix(reg_ds) + ((reg16[reg_bx]) & 0xFFFF) | 0; }; modrm_table16[0x40 | 7] = function() { return get_seg_prefix(reg_ds) + ((reg16[reg_bx]) + read_imm8s() & 0xFFFF) | 0; }; modrm_table16[0x80 | 7] = function() { return get_seg_prefix(reg_ds) + ((reg16[reg_bx]) + read_imm16() & 0xFFFF) | 0; }; |
| modrm_table32[0x00 | 0] = function() { return (get_seg_prefix(reg_ds) + reg32s[reg_eax]) | 0; }; modrm_table32[0x40 | 0] = function() { return (get_seg_prefix(reg_ds) + reg32s[reg_eax]) + read_imm8s() | 0; }; modrm_table32[0x80 | 0] = function() { return (get_seg_prefix(reg_ds) + reg32s[reg_eax]) + read_imm32s() | 0; };; |
| modrm_table32[0x00 | 1] = function() { return (get_seg_prefix(reg_ds) + reg32s[reg_ecx]) | 0; }; modrm_table32[0x40 | 1] = function() { return (get_seg_prefix(reg_ds) + reg32s[reg_ecx]) + read_imm8s() | 0; }; modrm_table32[0x80 | 1] = function() { return (get_seg_prefix(reg_ds) + reg32s[reg_ecx]) + read_imm32s() | 0; };; |
| modrm_table32[0x00 | 2] = function() { return (get_seg_prefix(reg_ds) + reg32s[reg_edx]) | 0; }; modrm_table32[0x40 | 2] = function() { return (get_seg_prefix(reg_ds) + reg32s[reg_edx]) + read_imm8s() | 0; }; modrm_table32[0x80 | 2] = function() { return (get_seg_prefix(reg_ds) + reg32s[reg_edx]) + read_imm32s() | 0; };; |
| modrm_table32[0x00 | 3] = function() { return (get_seg_prefix(reg_ds) + reg32s[reg_ebx]) | 0; }; modrm_table32[0x40 | 3] = function() { return (get_seg_prefix(reg_ds) + reg32s[reg_ebx]) + read_imm8s() | 0; }; modrm_table32[0x80 | 3] = function() { return (get_seg_prefix(reg_ds) + reg32s[reg_ebx]) + read_imm32s() | 0; };; |
| modrm_table32[0x00 | 4] = function() { return (getsib(false)) | 0; }; modrm_table32[0x40 | 4] = function() { return (getsib(false)) + read_imm8s() | 0; }; modrm_table32[0x80 | 4] = function() { return (getsib(false)) + read_imm32s() | 0; };; |
| modrm_table32[0x00 | 5] = function() { return (get_seg_prefix(reg_ss) + reg32s[reg_ebp]) | 0; }; modrm_table32[0x40 | 5] = function() { return (get_seg_prefix(reg_ss) + reg32s[reg_ebp]) + read_imm8s() | 0; }; modrm_table32[0x80 | 5] = function() { return (get_seg_prefix(reg_ss) + reg32s[reg_ebp]) + read_imm32s() | 0; };; |
| modrm_table32[0x00 | 6] = function() { return (get_seg_prefix(reg_ds) + reg32s[reg_esi]) | 0; }; modrm_table32[0x40 | 6] = function() { return (get_seg_prefix(reg_ds) + reg32s[reg_esi]) + read_imm8s() | 0; }; modrm_table32[0x80 | 6] = function() { return (get_seg_prefix(reg_ds) + reg32s[reg_esi]) + read_imm32s() | 0; };; |
| modrm_table32[0x00 | 7] = function() { return (get_seg_prefix(reg_ds) + reg32s[reg_edi]) | 0; }; modrm_table32[0x40 | 7] = function() { return (get_seg_prefix(reg_ds) + reg32s[reg_edi]) + read_imm8s() | 0; }; modrm_table32[0x80 | 7] = function() { return (get_seg_prefix(reg_ds) + reg32s[reg_edi]) + read_imm32s() | 0; };; |
| // special cases |
| modrm_table16[0x00 | 6] = function() { return get_seg_prefix(reg_ds) + read_imm16() | 0; } |
| modrm_table32[0x00 | 5] = function() { return get_seg_prefix(reg_ds) + read_imm32s() | 0; }; |
| modrm_table32[0x00 | 4] = function() { return getsib(false) | 0; }; |
| modrm_table32[0x40 | 4] = function() { return getsib(true) + read_imm8s() | 0; }; |
| modrm_table32[0x80 | 4] = function() { return getsib(true) + read_imm32s() | 0; }; |
| for(var low = 0; low < 8; low++) |
| { |
| for(var high = 0; high < 3; high++) |
| { |
| for(var i = 1; i < 8; i++) |
| { |
| var x = low | high << 6; |
| modrm_table32[x | i << 3] = modrm_table32[x]; |
| modrm_table16[x | i << 3] = modrm_table16[x]; |
| } |
| } |
| } |
| sib_table[0x00 | 0 << 3 | 0] = function(mod) { return (reg32s[reg_eax]) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x00 | 0 << 3 | 1] = function(mod) { return (reg32s[reg_eax]) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x00 | 0 << 3 | 2] = function(mod) { return (reg32s[reg_eax]) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x00 | 0 << 3 | 3] = function(mod) { return (reg32s[reg_eax]) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x00 | 0 << 3 | 4] = function(mod) { return (reg32s[reg_eax]) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x00 | 0 << 3 | 5] = function(mod) { return (reg32s[reg_eax]) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x00 | 0 << 3 | 6] = function(mod) { return (reg32s[reg_eax]) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x00 | 0 << 3 | 7] = function(mod) { return (reg32s[reg_eax]) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0x40 | 0 << 3 | 0] = function(mod) { return (reg32s[reg_eax] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x40 | 0 << 3 | 1] = function(mod) { return (reg32s[reg_eax] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x40 | 0 << 3 | 2] = function(mod) { return (reg32s[reg_eax] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x40 | 0 << 3 | 3] = function(mod) { return (reg32s[reg_eax] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x40 | 0 << 3 | 4] = function(mod) { return (reg32s[reg_eax] << 1) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x40 | 0 << 3 | 5] = function(mod) { return (reg32s[reg_eax] << 1) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x40 | 0 << 3 | 6] = function(mod) { return (reg32s[reg_eax] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x40 | 0 << 3 | 7] = function(mod) { return (reg32s[reg_eax] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0x80 | 0 << 3 | 0] = function(mod) { return (reg32s[reg_eax] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x80 | 0 << 3 | 1] = function(mod) { return (reg32s[reg_eax] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x80 | 0 << 3 | 2] = function(mod) { return (reg32s[reg_eax] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x80 | 0 << 3 | 3] = function(mod) { return (reg32s[reg_eax] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x80 | 0 << 3 | 4] = function(mod) { return (reg32s[reg_eax] << 2) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x80 | 0 << 3 | 5] = function(mod) { return (reg32s[reg_eax] << 2) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x80 | 0 << 3 | 6] = function(mod) { return (reg32s[reg_eax] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x80 | 0 << 3 | 7] = function(mod) { return (reg32s[reg_eax] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0xC0 | 0 << 3 | 0] = function(mod) { return (reg32s[reg_eax] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0xC0 | 0 << 3 | 1] = function(mod) { return (reg32s[reg_eax] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0xC0 | 0 << 3 | 2] = function(mod) { return (reg32s[reg_eax] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0xC0 | 0 << 3 | 3] = function(mod) { return (reg32s[reg_eax] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0xC0 | 0 << 3 | 4] = function(mod) { return (reg32s[reg_eax] << 3) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0xC0 | 0 << 3 | 5] = function(mod) { return (reg32s[reg_eax] << 3) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0xC0 | 0 << 3 | 6] = function(mod) { return (reg32s[reg_eax] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0xC0 | 0 << 3 | 7] = function(mod) { return (reg32s[reg_eax] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; };; |
| sib_table[0x00 | 1 << 3 | 0] = function(mod) { return (reg32s[reg_ecx]) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x00 | 1 << 3 | 1] = function(mod) { return (reg32s[reg_ecx]) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x00 | 1 << 3 | 2] = function(mod) { return (reg32s[reg_ecx]) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x00 | 1 << 3 | 3] = function(mod) { return (reg32s[reg_ecx]) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x00 | 1 << 3 | 4] = function(mod) { return (reg32s[reg_ecx]) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x00 | 1 << 3 | 5] = function(mod) { return (reg32s[reg_ecx]) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x00 | 1 << 3 | 6] = function(mod) { return (reg32s[reg_ecx]) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x00 | 1 << 3 | 7] = function(mod) { return (reg32s[reg_ecx]) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0x40 | 1 << 3 | 0] = function(mod) { return (reg32s[reg_ecx] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x40 | 1 << 3 | 1] = function(mod) { return (reg32s[reg_ecx] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x40 | 1 << 3 | 2] = function(mod) { return (reg32s[reg_ecx] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x40 | 1 << 3 | 3] = function(mod) { return (reg32s[reg_ecx] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x40 | 1 << 3 | 4] = function(mod) { return (reg32s[reg_ecx] << 1) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x40 | 1 << 3 | 5] = function(mod) { return (reg32s[reg_ecx] << 1) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x40 | 1 << 3 | 6] = function(mod) { return (reg32s[reg_ecx] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x40 | 1 << 3 | 7] = function(mod) { return (reg32s[reg_ecx] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0x80 | 1 << 3 | 0] = function(mod) { return (reg32s[reg_ecx] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x80 | 1 << 3 | 1] = function(mod) { return (reg32s[reg_ecx] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x80 | 1 << 3 | 2] = function(mod) { return (reg32s[reg_ecx] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x80 | 1 << 3 | 3] = function(mod) { return (reg32s[reg_ecx] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x80 | 1 << 3 | 4] = function(mod) { return (reg32s[reg_ecx] << 2) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x80 | 1 << 3 | 5] = function(mod) { return (reg32s[reg_ecx] << 2) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x80 | 1 << 3 | 6] = function(mod) { return (reg32s[reg_ecx] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x80 | 1 << 3 | 7] = function(mod) { return (reg32s[reg_ecx] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0xC0 | 1 << 3 | 0] = function(mod) { return (reg32s[reg_ecx] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0xC0 | 1 << 3 | 1] = function(mod) { return (reg32s[reg_ecx] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0xC0 | 1 << 3 | 2] = function(mod) { return (reg32s[reg_ecx] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0xC0 | 1 << 3 | 3] = function(mod) { return (reg32s[reg_ecx] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0xC0 | 1 << 3 | 4] = function(mod) { return (reg32s[reg_ecx] << 3) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0xC0 | 1 << 3 | 5] = function(mod) { return (reg32s[reg_ecx] << 3) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0xC0 | 1 << 3 | 6] = function(mod) { return (reg32s[reg_ecx] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0xC0 | 1 << 3 | 7] = function(mod) { return (reg32s[reg_ecx] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; };; |
| sib_table[0x00 | 2 << 3 | 0] = function(mod) { return (reg32s[reg_edx]) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x00 | 2 << 3 | 1] = function(mod) { return (reg32s[reg_edx]) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x00 | 2 << 3 | 2] = function(mod) { return (reg32s[reg_edx]) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x00 | 2 << 3 | 3] = function(mod) { return (reg32s[reg_edx]) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x00 | 2 << 3 | 4] = function(mod) { return (reg32s[reg_edx]) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x00 | 2 << 3 | 5] = function(mod) { return (reg32s[reg_edx]) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x00 | 2 << 3 | 6] = function(mod) { return (reg32s[reg_edx]) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x00 | 2 << 3 | 7] = function(mod) { return (reg32s[reg_edx]) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0x40 | 2 << 3 | 0] = function(mod) { return (reg32s[reg_edx] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x40 | 2 << 3 | 1] = function(mod) { return (reg32s[reg_edx] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x40 | 2 << 3 | 2] = function(mod) { return (reg32s[reg_edx] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x40 | 2 << 3 | 3] = function(mod) { return (reg32s[reg_edx] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x40 | 2 << 3 | 4] = function(mod) { return (reg32s[reg_edx] << 1) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x40 | 2 << 3 | 5] = function(mod) { return (reg32s[reg_edx] << 1) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x40 | 2 << 3 | 6] = function(mod) { return (reg32s[reg_edx] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x40 | 2 << 3 | 7] = function(mod) { return (reg32s[reg_edx] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0x80 | 2 << 3 | 0] = function(mod) { return (reg32s[reg_edx] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x80 | 2 << 3 | 1] = function(mod) { return (reg32s[reg_edx] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x80 | 2 << 3 | 2] = function(mod) { return (reg32s[reg_edx] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x80 | 2 << 3 | 3] = function(mod) { return (reg32s[reg_edx] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x80 | 2 << 3 | 4] = function(mod) { return (reg32s[reg_edx] << 2) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x80 | 2 << 3 | 5] = function(mod) { return (reg32s[reg_edx] << 2) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x80 | 2 << 3 | 6] = function(mod) { return (reg32s[reg_edx] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x80 | 2 << 3 | 7] = function(mod) { return (reg32s[reg_edx] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0xC0 | 2 << 3 | 0] = function(mod) { return (reg32s[reg_edx] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0xC0 | 2 << 3 | 1] = function(mod) { return (reg32s[reg_edx] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0xC0 | 2 << 3 | 2] = function(mod) { return (reg32s[reg_edx] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0xC0 | 2 << 3 | 3] = function(mod) { return (reg32s[reg_edx] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0xC0 | 2 << 3 | 4] = function(mod) { return (reg32s[reg_edx] << 3) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0xC0 | 2 << 3 | 5] = function(mod) { return (reg32s[reg_edx] << 3) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0xC0 | 2 << 3 | 6] = function(mod) { return (reg32s[reg_edx] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0xC0 | 2 << 3 | 7] = function(mod) { return (reg32s[reg_edx] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; };; |
| sib_table[0x00 | 3 << 3 | 0] = function(mod) { return (reg32s[reg_ebx]) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x00 | 3 << 3 | 1] = function(mod) { return (reg32s[reg_ebx]) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x00 | 3 << 3 | 2] = function(mod) { return (reg32s[reg_ebx]) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x00 | 3 << 3 | 3] = function(mod) { return (reg32s[reg_ebx]) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x00 | 3 << 3 | 4] = function(mod) { return (reg32s[reg_ebx]) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x00 | 3 << 3 | 5] = function(mod) { return (reg32s[reg_ebx]) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x00 | 3 << 3 | 6] = function(mod) { return (reg32s[reg_ebx]) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x00 | 3 << 3 | 7] = function(mod) { return (reg32s[reg_ebx]) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0x40 | 3 << 3 | 0] = function(mod) { return (reg32s[reg_ebx] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x40 | 3 << 3 | 1] = function(mod) { return (reg32s[reg_ebx] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x40 | 3 << 3 | 2] = function(mod) { return (reg32s[reg_ebx] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x40 | 3 << 3 | 3] = function(mod) { return (reg32s[reg_ebx] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x40 | 3 << 3 | 4] = function(mod) { return (reg32s[reg_ebx] << 1) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x40 | 3 << 3 | 5] = function(mod) { return (reg32s[reg_ebx] << 1) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x40 | 3 << 3 | 6] = function(mod) { return (reg32s[reg_ebx] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x40 | 3 << 3 | 7] = function(mod) { return (reg32s[reg_ebx] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0x80 | 3 << 3 | 0] = function(mod) { return (reg32s[reg_ebx] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x80 | 3 << 3 | 1] = function(mod) { return (reg32s[reg_ebx] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x80 | 3 << 3 | 2] = function(mod) { return (reg32s[reg_ebx] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x80 | 3 << 3 | 3] = function(mod) { return (reg32s[reg_ebx] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x80 | 3 << 3 | 4] = function(mod) { return (reg32s[reg_ebx] << 2) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x80 | 3 << 3 | 5] = function(mod) { return (reg32s[reg_ebx] << 2) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x80 | 3 << 3 | 6] = function(mod) { return (reg32s[reg_ebx] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x80 | 3 << 3 | 7] = function(mod) { return (reg32s[reg_ebx] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0xC0 | 3 << 3 | 0] = function(mod) { return (reg32s[reg_ebx] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0xC0 | 3 << 3 | 1] = function(mod) { return (reg32s[reg_ebx] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0xC0 | 3 << 3 | 2] = function(mod) { return (reg32s[reg_ebx] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0xC0 | 3 << 3 | 3] = function(mod) { return (reg32s[reg_ebx] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0xC0 | 3 << 3 | 4] = function(mod) { return (reg32s[reg_ebx] << 3) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0xC0 | 3 << 3 | 5] = function(mod) { return (reg32s[reg_ebx] << 3) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0xC0 | 3 << 3 | 6] = function(mod) { return (reg32s[reg_ebx] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0xC0 | 3 << 3 | 7] = function(mod) { return (reg32s[reg_ebx] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; };; |
| sib_table[0x00 | 4 << 3 | 0] = function(mod) { return (0) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x00 | 4 << 3 | 1] = function(mod) { return (0) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x00 | 4 << 3 | 2] = function(mod) { return (0) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x00 | 4 << 3 | 3] = function(mod) { return (0) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x00 | 4 << 3 | 4] = function(mod) { return (0) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x00 | 4 << 3 | 5] = function(mod) { return (0) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x00 | 4 << 3 | 6] = function(mod) { return (0) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x00 | 4 << 3 | 7] = function(mod) { return (0) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0x40 | 4 << 3 | 0] = function(mod) { return (0 << 1) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x40 | 4 << 3 | 1] = function(mod) { return (0 << 1) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x40 | 4 << 3 | 2] = function(mod) { return (0 << 1) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x40 | 4 << 3 | 3] = function(mod) { return (0 << 1) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x40 | 4 << 3 | 4] = function(mod) { return (0 << 1) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x40 | 4 << 3 | 5] = function(mod) { return (0 << 1) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x40 | 4 << 3 | 6] = function(mod) { return (0 << 1) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x40 | 4 << 3 | 7] = function(mod) { return (0 << 1) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0x80 | 4 << 3 | 0] = function(mod) { return (0 << 2) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x80 | 4 << 3 | 1] = function(mod) { return (0 << 2) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x80 | 4 << 3 | 2] = function(mod) { return (0 << 2) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x80 | 4 << 3 | 3] = function(mod) { return (0 << 2) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x80 | 4 << 3 | 4] = function(mod) { return (0 << 2) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x80 | 4 << 3 | 5] = function(mod) { return (0 << 2) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x80 | 4 << 3 | 6] = function(mod) { return (0 << 2) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x80 | 4 << 3 | 7] = function(mod) { return (0 << 2) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0xC0 | 4 << 3 | 0] = function(mod) { return (0 << 3) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0xC0 | 4 << 3 | 1] = function(mod) { return (0 << 3) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0xC0 | 4 << 3 | 2] = function(mod) { return (0 << 3) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0xC0 | 4 << 3 | 3] = function(mod) { return (0 << 3) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0xC0 | 4 << 3 | 4] = function(mod) { return (0 << 3) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0xC0 | 4 << 3 | 5] = function(mod) { return (0 << 3) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0xC0 | 4 << 3 | 6] = function(mod) { return (0 << 3) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0xC0 | 4 << 3 | 7] = function(mod) { return (0 << 3) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; };; |
| sib_table[0x00 | 5 << 3 | 0] = function(mod) { return (reg32s[reg_ebp]) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x00 | 5 << 3 | 1] = function(mod) { return (reg32s[reg_ebp]) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x00 | 5 << 3 | 2] = function(mod) { return (reg32s[reg_ebp]) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x00 | 5 << 3 | 3] = function(mod) { return (reg32s[reg_ebp]) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x00 | 5 << 3 | 4] = function(mod) { return (reg32s[reg_ebp]) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x00 | 5 << 3 | 5] = function(mod) { return (reg32s[reg_ebp]) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x00 | 5 << 3 | 6] = function(mod) { return (reg32s[reg_ebp]) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x00 | 5 << 3 | 7] = function(mod) { return (reg32s[reg_ebp]) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0x40 | 5 << 3 | 0] = function(mod) { return (reg32s[reg_ebp] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x40 | 5 << 3 | 1] = function(mod) { return (reg32s[reg_ebp] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x40 | 5 << 3 | 2] = function(mod) { return (reg32s[reg_ebp] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x40 | 5 << 3 | 3] = function(mod) { return (reg32s[reg_ebp] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x40 | 5 << 3 | 4] = function(mod) { return (reg32s[reg_ebp] << 1) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x40 | 5 << 3 | 5] = function(mod) { return (reg32s[reg_ebp] << 1) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x40 | 5 << 3 | 6] = function(mod) { return (reg32s[reg_ebp] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x40 | 5 << 3 | 7] = function(mod) { return (reg32s[reg_ebp] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0x80 | 5 << 3 | 0] = function(mod) { return (reg32s[reg_ebp] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x80 | 5 << 3 | 1] = function(mod) { return (reg32s[reg_ebp] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x80 | 5 << 3 | 2] = function(mod) { return (reg32s[reg_ebp] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x80 | 5 << 3 | 3] = function(mod) { return (reg32s[reg_ebp] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x80 | 5 << 3 | 4] = function(mod) { return (reg32s[reg_ebp] << 2) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x80 | 5 << 3 | 5] = function(mod) { return (reg32s[reg_ebp] << 2) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x80 | 5 << 3 | 6] = function(mod) { return (reg32s[reg_ebp] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x80 | 5 << 3 | 7] = function(mod) { return (reg32s[reg_ebp] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0xC0 | 5 << 3 | 0] = function(mod) { return (reg32s[reg_ebp] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0xC0 | 5 << 3 | 1] = function(mod) { return (reg32s[reg_ebp] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0xC0 | 5 << 3 | 2] = function(mod) { return (reg32s[reg_ebp] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0xC0 | 5 << 3 | 3] = function(mod) { return (reg32s[reg_ebp] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0xC0 | 5 << 3 | 4] = function(mod) { return (reg32s[reg_ebp] << 3) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0xC0 | 5 << 3 | 5] = function(mod) { return (reg32s[reg_ebp] << 3) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0xC0 | 5 << 3 | 6] = function(mod) { return (reg32s[reg_ebp] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0xC0 | 5 << 3 | 7] = function(mod) { return (reg32s[reg_ebp] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; };; |
| sib_table[0x00 | 6 << 3 | 0] = function(mod) { return (reg32s[reg_esi]) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x00 | 6 << 3 | 1] = function(mod) { return (reg32s[reg_esi]) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x00 | 6 << 3 | 2] = function(mod) { return (reg32s[reg_esi]) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x00 | 6 << 3 | 3] = function(mod) { return (reg32s[reg_esi]) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x00 | 6 << 3 | 4] = function(mod) { return (reg32s[reg_esi]) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x00 | 6 << 3 | 5] = function(mod) { return (reg32s[reg_esi]) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x00 | 6 << 3 | 6] = function(mod) { return (reg32s[reg_esi]) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x00 | 6 << 3 | 7] = function(mod) { return (reg32s[reg_esi]) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0x40 | 6 << 3 | 0] = function(mod) { return (reg32s[reg_esi] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x40 | 6 << 3 | 1] = function(mod) { return (reg32s[reg_esi] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x40 | 6 << 3 | 2] = function(mod) { return (reg32s[reg_esi] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x40 | 6 << 3 | 3] = function(mod) { return (reg32s[reg_esi] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x40 | 6 << 3 | 4] = function(mod) { return (reg32s[reg_esi] << 1) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x40 | 6 << 3 | 5] = function(mod) { return (reg32s[reg_esi] << 1) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x40 | 6 << 3 | 6] = function(mod) { return (reg32s[reg_esi] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x40 | 6 << 3 | 7] = function(mod) { return (reg32s[reg_esi] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0x80 | 6 << 3 | 0] = function(mod) { return (reg32s[reg_esi] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x80 | 6 << 3 | 1] = function(mod) { return (reg32s[reg_esi] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x80 | 6 << 3 | 2] = function(mod) { return (reg32s[reg_esi] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x80 | 6 << 3 | 3] = function(mod) { return (reg32s[reg_esi] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x80 | 6 << 3 | 4] = function(mod) { return (reg32s[reg_esi] << 2) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x80 | 6 << 3 | 5] = function(mod) { return (reg32s[reg_esi] << 2) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x80 | 6 << 3 | 6] = function(mod) { return (reg32s[reg_esi] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x80 | 6 << 3 | 7] = function(mod) { return (reg32s[reg_esi] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0xC0 | 6 << 3 | 0] = function(mod) { return (reg32s[reg_esi] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0xC0 | 6 << 3 | 1] = function(mod) { return (reg32s[reg_esi] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0xC0 | 6 << 3 | 2] = function(mod) { return (reg32s[reg_esi] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0xC0 | 6 << 3 | 3] = function(mod) { return (reg32s[reg_esi] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0xC0 | 6 << 3 | 4] = function(mod) { return (reg32s[reg_esi] << 3) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0xC0 | 6 << 3 | 5] = function(mod) { return (reg32s[reg_esi] << 3) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0xC0 | 6 << 3 | 6] = function(mod) { return (reg32s[reg_esi] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0xC0 | 6 << 3 | 7] = function(mod) { return (reg32s[reg_esi] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; };; |
| sib_table[0x00 | 7 << 3 | 0] = function(mod) { return (reg32s[reg_edi]) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x00 | 7 << 3 | 1] = function(mod) { return (reg32s[reg_edi]) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x00 | 7 << 3 | 2] = function(mod) { return (reg32s[reg_edi]) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x00 | 7 << 3 | 3] = function(mod) { return (reg32s[reg_edi]) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x00 | 7 << 3 | 4] = function(mod) { return (reg32s[reg_edi]) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x00 | 7 << 3 | 5] = function(mod) { return (reg32s[reg_edi]) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x00 | 7 << 3 | 6] = function(mod) { return (reg32s[reg_edi]) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x00 | 7 << 3 | 7] = function(mod) { return (reg32s[reg_edi]) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0x40 | 7 << 3 | 0] = function(mod) { return (reg32s[reg_edi] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x40 | 7 << 3 | 1] = function(mod) { return (reg32s[reg_edi] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x40 | 7 << 3 | 2] = function(mod) { return (reg32s[reg_edi] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x40 | 7 << 3 | 3] = function(mod) { return (reg32s[reg_edi] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x40 | 7 << 3 | 4] = function(mod) { return (reg32s[reg_edi] << 1) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x40 | 7 << 3 | 5] = function(mod) { return (reg32s[reg_edi] << 1) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x40 | 7 << 3 | 6] = function(mod) { return (reg32s[reg_edi] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x40 | 7 << 3 | 7] = function(mod) { return (reg32s[reg_edi] << 1) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0x80 | 7 << 3 | 0] = function(mod) { return (reg32s[reg_edi] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0x80 | 7 << 3 | 1] = function(mod) { return (reg32s[reg_edi] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0x80 | 7 << 3 | 2] = function(mod) { return (reg32s[reg_edi] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0x80 | 7 << 3 | 3] = function(mod) { return (reg32s[reg_edi] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0x80 | 7 << 3 | 4] = function(mod) { return (reg32s[reg_edi] << 2) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0x80 | 7 << 3 | 5] = function(mod) { return (reg32s[reg_edi] << 2) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0x80 | 7 << 3 | 6] = function(mod) { return (reg32s[reg_edi] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0x80 | 7 << 3 | 7] = function(mod) { return (reg32s[reg_edi] << 2) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; }; sib_table[0xC0 | 7 << 3 | 0] = function(mod) { return (reg32s[reg_edi] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_eax] | 0; }; sib_table[0xC0 | 7 << 3 | 1] = function(mod) { return (reg32s[reg_edi] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_ecx] | 0; }; sib_table[0xC0 | 7 << 3 | 2] = function(mod) { return (reg32s[reg_edi] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_edx] | 0; }; sib_table[0xC0 | 7 << 3 | 3] = function(mod) { return (reg32s[reg_edi] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_ebx] | 0; }; sib_table[0xC0 | 7 << 3 | 4] = function(mod) { return (reg32s[reg_edi] << 3) + get_seg_prefix(reg_ss) + reg32s[reg_esp] | 0; }; sib_table[0xC0 | 7 << 3 | 5] = function(mod) { return (reg32s[reg_edi] << 3) + (mod ? get_seg_prefix(reg_ss) + reg32s[reg_ebp] : get_seg_prefix(reg_ds) + read_imm32s()) | 0; }; sib_table[0xC0 | 7 << 3 | 6] = function(mod) { return (reg32s[reg_edi] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_esi] | 0; }; sib_table[0xC0 | 7 << 3 | 7] = function(mod) { return (reg32s[reg_edi] << 3) + get_seg_prefix(reg_ds) + reg32s[reg_edi] | 0; };; |
| /** |
| * @param {number} modrm_byte |
| * @return {number} |
| */ |
| modrm_resolve16 = function(modrm_byte) |
| { |
| return modrm_table16[modrm_byte](); |
| } |
| /** |
| * @param {number} modrm_byte |
| * @return {number} |
| */ |
| modrm_resolve32 = function(modrm_byte) |
| { |
| return modrm_table32[modrm_byte](); |
| } |
| /** |
| * @param {boolean} mod |
| * @return {number} |
| */ |
| function getsib(mod) |
| { |
| return sib_table[read_imm8()](mod); |
| } |
| })(); |
| /* |
| * Arithmatic functions |
| * This file contains: |
| * |
| * add, adc, sub, sbc, cmp |
| * inc, dec |
| * neg, not |
| * imul, mul, idiv, div |
| * xadd |
| * |
| * das, daa, aad, aam |
| * |
| * and, or, xor, test |
| * shl, shr, sar, ror, rol, rcr, rcl |
| * shld, shrd |
| * |
| * bts, btr, btc, bt |
| * bsf, bsr |
| * |
| * Gets #included by cpu.macro.js |
| * |
| */ |
| "use strict"; |
| /** |
| * Helper function for multiplying 2 32 bit numbers |
| * Returns the low 32 bit (which would normally get cut off) |
| * |
| * @param {number} n1 |
| * @param {number} n2 |
| */ |
| function multiply_low(n1, n2) |
| { |
| var low1 = n1 & 0xFFFF, |
| low2 = n2 & 0xFFFF, |
| high1 = n1 & ~0xFFFF, |
| high2 = n2 & ~0xFFFF; |
| return low1 * low2 + low1 * high2 + high1 * low2; |
| } |
| function add8(dest_operand, source_operand) |
| { |
| // very likely to be a crash |
| if(DEBUG && memory.read32s(translate_address_read(instruction_pointer)) === 0) |
| { |
| dump_regs(); |
| throw "detected jump to 00000000"; |
| } |
| last_op1 = dest_operand; |
| last_op2 = source_operand; |
| last_result = last_op1 + source_operand | 0; |
| last_op_size = OPSIZE_8; |
| flags_changed = flags_all; |
| return last_result; |
| } |
| function add16(dest_operand, source_operand) |
| { |
| last_op1 = dest_operand; |
| last_op2 = source_operand; |
| last_result = last_op1 + source_operand | 0; |
| last_op_size = OPSIZE_16; |
| flags_changed = flags_all; |
| return last_result; |
| } |
| function add32(dest_operand, source_operand) |
| { |
| last_op1 = dest_operand; |
| last_op2 = source_operand; |
| last_result = last_op1 + source_operand; |
| last_op_size = OPSIZE_32; |
| flags_changed = flags_all; |
| return last_result; |
| } |
| function adc8(dest_operand, source_operand) |
| { |
| last_op1 = dest_operand; |
| last_op2 = source_operand; |
| last_result = last_op1 + last_op2 + getcf() | 0; |
| last_op_size = OPSIZE_8; |
| flags_changed = flags_all; |
| return last_result; |
| } |
| function adc16(dest_operand, source_operand) |
| { |
| last_op1 = dest_operand; |
| last_op2 = source_operand; |
| last_result = last_op1 + last_op2 + getcf() | 0; |
| last_op_size = OPSIZE_16; |
| flags_changed = flags_all; |
| return last_result; |
| } |
| function adc32(dest_operand, source_operand) |
| { |
| last_op1 = dest_operand; |
| last_op2 = source_operand; |
| last_result = last_op1 + last_op2 + getcf(); |
| last_op_size = OPSIZE_32; |
| flags_changed = flags_all; |
| return last_result; |
| } |
| function cmp8(dest_operand, source_operand) |
| { |
| dbg_assert(source_operand >= 0 && source_operand < 0x100); |
| dbg_assert(dest_operand >= 0 && dest_operand < 0x100); |
| last_op1 = dest_operand; |
| last_op2 = ~source_operand; |
| last_result = last_op1 - source_operand; |
| last_op_size = OPSIZE_8; |
| flags_changed = flags_all; |
| } |
| function cmp16(dest_operand, source_operand) |
| { |
| dbg_assert(source_operand >= 0 && source_operand < 0x10000); |
| dbg_assert(dest_operand >= 0 && dest_operand < 0x10000); |
| last_op1 = dest_operand; |
| last_op2 = ~source_operand; |
| last_result = last_op1 - source_operand; |
| last_op_size = OPSIZE_16; |
| flags_changed = flags_all; |
| } |
| function cmp32(dest_operand, source_operand) |
| { |
| dbg_assert(source_operand >= 0 && source_operand < 0x100000000); |
| dbg_assert(dest_operand >= 0 && dest_operand < 0x100000000); |
| last_op1 = dest_operand; |
| last_op2 = -source_operand - 1; |
| last_result = last_op1 - source_operand; |
| last_op_size = OPSIZE_32; |
| flags_changed = flags_all; |
| } |
| function sub8(dest_operand, source_operand) |
| { |
| last_op1 = dest_operand; |
| last_op2 = ~source_operand; |
| last_result = last_op1 - source_operand | 0; |
| last_op_size = OPSIZE_8; |
| flags_changed = flags_all; |
| return last_result; |
| } |
| function sub16(dest_operand, source_operand) |
| { |
| last_op1 = dest_operand; |
| last_op2 = ~source_operand; |
| last_result = last_op1 - source_operand | 0; |
| last_op_size = OPSIZE_16; |
| flags_changed = flags_all; |
| return last_result; |
| } |
| function sub32(dest_operand, source_operand) |
| { |
| last_op1 = dest_operand; |
| last_op2 = -source_operand - 1; |
| last_result = last_op1 - source_operand; |
| last_op_size = OPSIZE_32; |
| flags_changed = flags_all; |
| return last_result; |
| } |
| function sbb8(dest_operand, source_operand) |
| { |
| last_op1 = dest_operand; |
| last_op2 = ~source_operand; |
| last_result = last_op1 - source_operand - getcf() | 0; |
| last_op_size = OPSIZE_8; |
| flags_changed = flags_all; |
| return last_result; |
| } |
| function sbb16(dest_operand, source_operand) |
| { |
| last_op1 = dest_operand; |
| last_op2 = ~source_operand; |
| last_result = last_op1 - source_operand - getcf() | 0; |
| last_op_size = OPSIZE_16; |
| flags_changed = flags_all; |
| return last_result; |
| } |
| function sbb32(dest_operand, source_operand) |
| { |
| last_op1 = dest_operand; |
| last_op2 = -source_operand - 1; |
| last_result = last_op1 - source_operand - getcf(); |
| last_op_size = OPSIZE_32; |
| flags_changed = flags_all; |
| return last_result; |
| } |
| /* |
| * inc and dec |
| */ |
| function inc8(dest_operand) |
| { |
| flags = (flags & ~1) | getcf(); |
| last_op1 = dest_operand; |
| last_op2 = 1; |
| last_result = last_op1 + 1 | 0; |
| last_op_size = OPSIZE_8; |
| flags_changed = flags_all & ~flag_carry; |
| return last_result; |
| } |
| function inc16(dest_operand) |
| { |
| flags = (flags & ~1) | getcf(); |
| last_op1 = dest_operand; |
| last_op2 = 1; |
| last_result = last_op1 + 1 | 0; |
| last_op_size = OPSIZE_16; |
| flags_changed = flags_all & ~flag_carry; |
| return last_result; |
| } |
| function inc32(dest_operand) |
| { |
| flags = (flags & ~1) | getcf(); |
| last_op1 = dest_operand; |
| last_op2 = 1; |
| last_result = last_op1 + 1; |
| last_op_size = OPSIZE_32; |
| flags_changed = flags_all & ~flag_carry; |
| return last_result; |
| } |
| function dec8(dest_operand) |
| { |
| flags = (flags & ~1) | getcf(); |
| last_op1 = dest_operand; |
| last_op2 = -1; |
| last_result = last_op1 - 1 | 0; |
| last_op_size = OPSIZE_8; |
| flags_changed = flags_all & ~flag_carry; |
| return last_result; |
| } |
| function dec16(dest_operand) |
| { |
| flags = (flags & ~1) | getcf(); |
| last_op1 = dest_operand; |
| last_op2 = -1; |
| last_result = last_op1 - 1 | 0; |
| last_op_size = OPSIZE_16; |
| flags_changed = flags_all & ~flag_carry; |
| return last_result; |
| } |
| function dec32(dest_operand) |
| { |
| flags = (flags & ~1) | getcf(); |
| last_op1 = dest_operand; |
| last_op2 = -1; |
| last_result = last_op1 - 1; |
| last_op_size = OPSIZE_32; |
| flags_changed = flags_all & ~flag_carry; |
| return last_result; |
| } |
| /* |
| * neg and not |
| */ |
| function not8(dest_operand) |
| { |
| return ~dest_operand; |
| } |
| function not16(dest_operand) |
| { |
| return ~dest_operand; |
| } |
| function not32(dest_operand) |
| { |
| return ~dest_operand; |
| } |
| function neg8(dest_operand) |
| { |
| last_result = -dest_operand; |
| flags_changed = flags_all; |
| last_op_size = OPSIZE_8; |
| last_op1 = 0; |
| last_op2 = last_result - 1; |
| return last_result; |
| } |
| function neg16(dest_operand) |
| { |
| last_result = -dest_operand; |
| flags_changed = flags_all; |
| last_op_size = OPSIZE_16; |
| last_op1 = 0; |
| last_op2 = last_result - 1; |
| return last_result; |
| } |
| function neg32(dest_operand) |
| { |
| last_result = -dest_operand; |
| flags_changed = flags_all; |
| last_op_size = OPSIZE_32; |
| last_op1 = 0; |
| last_op2 = last_result - 1; |
| return last_result; |
| } |
| /* |
| * mul, imul, div, idiv |
| * |
| * Note: imul has some extra opcodes |
| * while other functions only allow |
| * ax * modrm |
| */ |
| function mul8(source_operand) |
| { |
| var result = source_operand * reg8[reg_al]; |
| reg16[reg_ax] = result; |
| if(result < 0x100) |
| { |
| flags = flags & ~1 & ~flag_overflow; |
| } |
| else |
| { |
| flags = flags | 1 | flag_overflow; |
| } |
| flags_changed = 0; |
| } |
| function imul8(source_operand) |
| { |
| var result = source_operand * reg8s[reg_al]; |
| reg16[reg_ax] = result; |
| if(result > 0x7F || result < -0x80) |
| { |
| flags = flags | 1 | flag_overflow; |
| } |
| else |
| { |
| flags = flags & ~1 & ~flag_overflow; |
| } |
| flags_changed = 0; |
| } |
| function mul16(source_operand) |
| { |
| var result = source_operand * reg16[reg_ax], |
| high_result = result >>> 16; |
| //console.log(h(a) + " * " + h(reg16[reg_ax]) + " = " + h(result)); |
| reg16[reg_ax] = result; |
| reg16[reg_dx] = high_result; |
| if(high_result === 0) |
| { |
| flags &= ~1 & ~flag_overflow; |
| } |
| else |
| { |
| flags |= 1 | flag_overflow; |
| } |
| flags_changed = 0; |
| } |
| /* |
| * imul with 1 argument |
| * ax = ax * r/m |
| */ |
| function imul16(source_operand) |
| { |
| var result = source_operand * reg16s[reg_ax]; |
| reg16[reg_ax] = result; |
| reg16[reg_dx] = result >> 16; |
| if(result > 0x7FFF || result < -0x8000) |
| { |
| flags |= 1 | flag_overflow; |
| } |
| else |
| { |
| flags &= ~1 & ~flag_overflow; |
| } |
| flags_changed = 0; |
| } |
| /* |
| * imul with 2 or 3 arguments |
| * reg = reg * r/m |
| * reg = imm * r/m |
| */ |
| function imul_reg16(operand1, operand2) |
| { |
| dbg_assert(operand1 < 0x8000 && operand1 >= -0x8000); |
| dbg_assert(operand2 < 0x8000 && operand2 >= -0x8000); |
| var result = operand1 * operand2; |
| if(result > 0x7FFF || result < -0x8000) |
| { |
| flags |= 1 | flag_overflow; |
| } |
| else |
| { |
| flags &= ~1 & ~flag_overflow; |
| } |
| flags_changed = 0; |
| return result; |
| } |
| function mul32(source_operand) |
| { |
| var dest_operand = reg32[reg_eax], |
| high_result = source_operand * dest_operand / 0x100000000 | 0; |
| reg32[reg_eax] = multiply_low(source_operand, dest_operand); |
| reg32[reg_edx] = high_result; |
| if(high_result === 0) |
| { |
| flags &= ~1 & ~flag_overflow; |
| } |
| else |
| { |
| flags |= 1 | flag_overflow; |
| } |
| flags_changed = 0; |
| //console.log(memory.read32s(address) + " * " + old); |
| //console.log("= " + reg32[reg_edx] + " " + reg32[reg_eax]); |
| } |
| function imul32(source_operand) |
| { |
| dbg_assert(source_operand < 0x80000000 && source_operand >= -0x80000000); |
| var dest_operand = reg32s[reg_eax], |
| high_result = source_operand * dest_operand / 0x100000000 | 0, |
| low_result = multiply_low(source_operand, dest_operand); |
| if(high_result === 0 && low_result < 0) |
| { |
| high_result = -1; |
| } |
| reg32[reg_eax] = low_result; |
| reg32[reg_edx] = high_result; |
| if(high_result === (reg32[reg_eax] < 0x80000000 ? 0 : -1)) |
| { |
| flags &= ~1 & ~flag_overflow; |
| } |
| else |
| { |
| flags |= 1 | flag_overflow; |
| } |
| flags_changed = 0; |
| //console.log(target_operand + " * " + source_operand); |
| //console.log("= " + h(reg32[reg_edx]) + " " + h(reg32[reg_eax])); |
| } |
| /* |
| * imul with 2 or 3 arguments |
| * reg = reg * r/m |
| * reg = imm * r/m |
| */ |
| function imul_reg32(operand1, operand2) |
| { |
| dbg_assert(operand1 < 0x80000000 && operand1 >= -0x80000000); |
| dbg_assert(operand2 < 0x80000000 && operand2 >= -0x80000000); |
| var result = multiply_low(operand1, operand2), |
| high_result = operand1 * operand2 / 0x100000000 | 0; |
| if(high_result === 0) |
| { |
| flags &= ~1 & ~flag_overflow; |
| } |
| else |
| { |
| flags |= 1 | flag_overflow; |
| } |
| flags_changed = 0; |
| return result; |
| //console.log(operand + " * " + source_operand); |
| //console.log("= " + reg32[reg]); |
| } |
| function div8(source_operand) |
| { |
| dbg_assert(source_operand >= 0 && source_operand < 0x100); |
| var target_operand = reg16[reg_ax], |
| result = target_operand / source_operand | 0; |
| if(result > 0xFF || source_operand === 0) |
| { |
| trigger_de(); |
| } |
| else |
| { |
| reg8[reg_al] = result; |
| reg8[reg_ah] = target_operand % source_operand; |
| } |
| } |
| function idiv8(source_operand) |
| { |
| dbg_assert(source_operand >= -0x80 && source_operand < 0x80); |
| var target_operand = reg16s[reg_ax], |
| result = target_operand / source_operand | 0; |
| if(result > 0x7F || result < -0x80 || source_operand === 0) |
| { |
| trigger_de(); |
| } |
| else |
| { |
| reg8[reg_al] = result; |
| reg8[reg_ah] = target_operand % source_operand; |
| } |
| } |
| function div16(source_operand) |
| { |
| dbg_assert(source_operand >= 0 && source_operand < 0x10000); |
| var |
| target_operand = (reg16[reg_ax] | reg16[reg_dx] << 16) >>> 0, |
| result = target_operand / source_operand | 0; |
| if(result > 0xFFFF || source_operand === 0) |
| { |
| trigger_de(); |
| } |
| else |
| { |
| reg16[reg_ax] = result; |
| reg16[reg_dx] = target_operand % source_operand; |
| } |
| } |
| function idiv16(source_operand) |
| { |
| dbg_assert(source_operand >= -0x8000 && source_operand < 0x8000); |
| var target_operand = reg16[reg_ax] | (reg16[reg_dx] << 16), |
| result = target_operand / source_operand | 0; |
| if(result > 0x7FFF || result < -0x8000 || source_operand === 0) |
| { |
| trigger_de(); |
| } |
| else |
| { |
| reg16[reg_ax] = result; |
| reg16[reg_dx] = target_operand % source_operand; |
| } |
| } |
| function div32(source_operand) |
| { |
| dbg_assert(source_operand >= 0 && source_operand <= 0xffffffff); |
| var |
| dest_operand_low = reg32[reg_eax], |
| dest_operand_high = reg32[reg_edx], |
| // Wat? Not sure if seriös ... |
| mod = (0x100000000 * dest_operand_high % source_operand + dest_operand_low % source_operand) % source_operand, |
| result = dest_operand_low / source_operand + dest_operand_high * 0x100000000 / source_operand; |
| if(result > 0xFFFFFFFF || source_operand === 0) |
| { |
| trigger_de(); |
| } |
| else |
| { |
| reg32[reg_eax] = result; |
| reg32[reg_edx] = mod; |
| } |
| //console.log(h(dest_operand_high) + ":" + h(dest_operand_low) + " / " + h(source_operand)); |
| //console.log("= " + h(reg32[reg_eax]) + " rem " + h(reg32[reg_edx])); |
| } |
| function idiv32(source_operand) |
| { |
| dbg_assert(source_operand < 0x80000000 && source_operand >= -0x80000000); |
| var |
| dest_operand_low = reg32[reg_eax], |
| dest_operand_high = reg32s[reg_edx], |
| mod = (0x100000000 * dest_operand_high % source_operand + dest_operand_low % source_operand) % source_operand, |
| result = dest_operand_low / source_operand + dest_operand_high * 0x100000000 / source_operand; |
| if(result > 0x7FFFFFFF || result < -0x80000000 || source_operand === 0) |
| { |
| trigger_de(); |
| } |
| else |
| { |
| reg32[reg_eax] = result; |
| reg32[reg_edx] = mod; |
| } |
| //console.log(h(dest_operand_high) + ":" + h(dest_operand_low) + " / " + h(source_operand)); |
| //console.log("= " + h(reg32[reg_eax]) + " rem " + h(reg32[reg_edx])); |
| } |
| function xadd8(source_operand, reg) |
| { |
| var tmp = reg8[reg]; |
| reg8[reg] = source_operand; |
| return add8(source_operand, tmp); |
| } |
| function xadd16(source_operand, reg) |
| { |
| var tmp = reg16[reg]; |
| reg16[reg] = source_operand; |
| return add16(source_operand, tmp); |
| } |
| function xadd32(source_operand, reg) |
| { |
| var tmp = reg32[reg]; |
| reg32[reg] = source_operand; |
| return add32(source_operand, tmp); |
| } |
| function bcd_daa() |
| { |
| //dbg_log("daa"); |
| // decimal adjust after addition |
| var old_al = reg8[reg_al], |
| old_cf = getcf(), |
| old_af = getaf(); |
| flags &= ~1 & ~flag_adjust |
| if((old_al & 0xF) > 9 || old_af) |
| { |
| reg8[reg_al] += 6; |
| flags |= flag_adjust; |
| } |
| if(old_al > 0x99 || old_cf) |
| { |
| reg8[reg_al] += 0x60; |
| flags |= 1; |
| } |
| last_result = reg8[reg_al]; |
| last_op_size = OPSIZE_8; |
| last_op1 = last_op2 = 0; |
| flags_changed = flags_all & ~1 & ~flag_adjust & ~flag_overflow; |
| } |
| function bcd_das() |
| { |
| //dbg_log("das"); |
| // decimal adjust after subtraction |
| var old_al = reg8[reg_al], |
| old_cf = getcf(); |
| flags &= ~1; |
| if((old_al & 0xF) > 9 || getaf()) |
| { |
| reg8[reg_al] -= 6; |
| flags |= flag_adjust; |
| flags = flags & ~1 | old_cf | reg8[reg_al] >> 7; |
| } |
| else |
| { |
| flags &= ~flag_adjust; |
| } |
| if(old_al > 0x99 || old_cf) |
| { |
| reg8[reg_al] -= 0x60; |
| flags |= 1; |
| } |
| last_result = reg8[reg_al]; |
| last_op_size = OPSIZE_8; |
| last_op1 = last_op2 = 0; |
| flags_changed = flags_all & ~1 & ~flag_adjust & ~flag_overflow; |
| } |
| function bcd_aam() |
| { |
| // ascii adjust after multiplication |
| var imm8 = read_imm8(); |
| if(imm8 === 0) |
| { |
| trigger_de(); |
| } |
| else |
| { |
| var temp = reg8[reg_al]; |
| reg8[reg_ah] = temp / imm8; |
| reg8[reg_al] = temp % imm8; |
| last_result = reg8[reg_al]; |
| flags_changed = flags_all; |
| } |
| } |
| function bcd_aad() |
| { |
| // ascii adjust after division |
| var imm8 = read_imm8(); |
| last_result = reg8[reg_al] + reg8[reg_ah] * imm8; |
| reg16[reg_ax] = last_result & 0xFF; |
| last_op_size = OPSIZE_8; |
| flags_changed = flags_all; |
| } |
| function bcd_aaa() |
| { |
| if((reg8[reg_al] & 0xF) > 9 || getaf()) |
| { |
| reg16[reg_ax] += 6; |
| reg8[reg_ah] += 1; |
| flags |= flag_adjust | 1; |
| } |
| else |
| { |
| flags &= ~flag_adjust & ~1; |
| } |
| reg8[reg_al] &= 0xF; |
| flags_changed &= ~flag_adjust & ~1; |
| } |
| function bcd_aas() |
| { |
| if((reg8[reg_al] & 0xF) > 9 || getaf()) |
| { |
| reg16[reg_ax] -= 6; |
| reg8[reg_ah] -= 1; |
| flags |= flag_adjust | 1; |
| } |
| else |
| { |
| flags &= ~flag_adjust & ~1; |
| } |
| reg8[reg_al] &= 0xF; |
| flags_changed &= ~flag_adjust & ~1; |
| } |
| /* \O |
| * bitwise functions | * / * |
| |
| * |
| * and, or, xor, test |
| * shl, shr, sar, rol, ror, rcl, ror |
| * shrd, shld |
| * |
| * bt, bts, btr, btc |
| * bsf, bsr |
| */ |
| function and8(dest_operand, source_operand) |
| { |
| last_result = dest_operand & source_operand; |
| last_op_size = OPSIZE_8; |
| flags &= ~1 & ~flag_overflow & ~flag_adjust; |
| flags_changed = flags_all & ~flag_carry & ~flag_overflow & ~flag_adjust; |
| return last_result; |
| } |
| function and16(dest_operand, source_operand) |
| { |
| last_result = dest_operand & source_operand; |
| last_op_size = OPSIZE_16; |
| flags &= ~1 & ~flag_overflow & ~flag_adjust; |
| flags_changed = flags_all & ~flag_carry & ~flag_overflow & ~flag_adjust; |
| return last_result; |
| } |
| function and32(dest_operand, source_operand) |
| { |
| last_result = dest_operand & source_operand; |
| last_op_size = OPSIZE_32; |
| flags &= ~1 & ~flag_overflow & ~flag_adjust; |
| flags_changed = flags_all & ~flag_carry & ~flag_overflow & ~flag_adjust; |
| return last_result; |
| } |
| function test8(dest_operand, source_operand) |
| { |
| last_result = dest_operand & source_operand; |
| last_op_size = OPSIZE_8; |
| flags &= ~1 & ~flag_overflow & ~flag_adjust; |
| flags_changed = flags_all & ~flag_carry & ~flag_overflow & ~flag_adjust; |
| } |
| function test16(dest_operand, source_operand) |
| { |
| last_result = dest_operand & source_operand; |
| last_op_size = OPSIZE_16; |
| flags &= ~1 & ~flag_overflow; |
| flags_changed = flags_all & ~flag_carry & ~flag_overflow & ~flag_adjust; |
| } |
| function test32(dest_operand, source_operand) |
| { |
| last_result = dest_operand & source_operand; |
| last_op_size = OPSIZE_32; |
| flags &= ~1 & ~flag_overflow & ~flag_adjust; |
| flags_changed = flags_all & ~flag_carry & ~flag_overflow & ~flag_adjust; |
| } |
| function or8(dest_operand, source_operand) |
| { |
| last_result = dest_operand | source_operand; |
| last_op_size = OPSIZE_8; |
| flags &= ~1 & ~flag_overflow & ~flag_adjust; |
| flags_changed = flags_all & ~flag_carry & ~flag_overflow & ~flag_adjust; |
| return last_result; |
| } |
| function or16(dest_operand, source_operand) |
| { |
| last_result = dest_operand | source_operand; |
| last_op_size = OPSIZE_16; |
| flags &= ~1 & ~flag_overflow & ~flag_adjust; |
| flags_changed = flags_all & ~flag_carry & ~flag_overflow & ~flag_adjust; |
| return last_result; |
| } |
| function or32(dest_operand, source_operand) |
| { |
| last_result = dest_operand | source_operand; |
| last_op_size = OPSIZE_32; |
| flags &= ~1 & ~flag_overflow & ~flag_adjust; |
| flags_changed = flags_all & ~flag_carry & ~flag_overflow & ~flag_adjust; |
| return last_result; |
| } |
| function xor8(dest_operand, source_operand) |
| { |
| last_result = dest_operand ^ source_operand; |
| last_op_size = OPSIZE_8; |
| flags &= ~1 & ~flag_overflow & ~flag_adjust; |
| flags_changed = flags_all & ~flag_carry & ~flag_overflow & ~flag_adjust; |
| return last_result; |
| } |
| function xor16(dest_operand, source_operand) |
| { |
| last_result = dest_operand ^ source_operand; |
| last_op_size = OPSIZE_16; |
| flags &= ~1 & ~flag_overflow & ~flag_adjust; |
| flags_changed = flags_all & ~flag_carry & ~flag_overflow & ~flag_adjust; |
| return last_result; |
| } |
| function xor32(dest_operand, source_operand) |
| { |
| last_result = dest_operand ^ source_operand; |
| last_op_size = OPSIZE_32; |
| flags &= ~1 & ~flag_overflow & ~flag_adjust; |
| flags_changed = flags_all & ~flag_carry & ~flag_overflow & ~flag_adjust; |
| return last_result; |
| } |
| /* |
| * rotates and shifts |
| */ |
| function rol8(dest_operand, count) |
| { |
| if(!count) |
| { |
| return dest_operand; |
| } |
| count &= 7; |
| var result = dest_operand << count | dest_operand >> (8 - count); |
| flags_changed &= ~flag_carry & ~flag_overflow; |
| flags = (flags & ~1 & ~flag_overflow) |
| | (result & 1) |
| | (result << 11 ^ result << 4) & flag_overflow; |
| return result; |
| } |
| function rol16(dest_operand, count) |
| { |
| if(!count) |
| { |
| return dest_operand; |
| } |
| count &= 15; |
| var result = dest_operand << count | dest_operand >> (16 - count); |
| flags_changed &= ~flag_carry & ~flag_overflow; |
| flags = (flags & ~1 & ~flag_overflow) |
| | (result & 1) |
| | (result << 11 ^ result >> 4) & flag_overflow; |
| return result; |
| } |
| function rol32(dest_operand, count) |
| { |
| if(!count) |
| { |
| return dest_operand; |
| } |
| var result = dest_operand << count | dest_operand >>> (32 - count); |
| flags_changed &= ~flag_carry & ~flag_overflow; |
| flags = (flags & ~1 & ~flag_overflow) |
| | (result & 1) |
| | (result << 11 ^ result >> 20) & flag_overflow; |
| return result; |
| } |
| function rcl8(dest_operand, count) |
| { |
| count %= 9; |
| if(!count) |
| { |
| return dest_operand; |
| } |
| var result = dest_operand << count | getcf() << (count - 1) | dest_operand >> (9 - count); |
| flags_changed &= ~flag_carry & ~flag_overflow; |
| flags = (flags & ~1 & ~flag_overflow) |
| | (result >> 8 & 1) |
| | (result << 3 ^ result << 4) & flag_overflow; |
| return result; |
| } |
| function rcl16(dest_operand, count) |
| { |
| count %= 17; |
| if(!count) |
| { |
| return dest_operand; |
| } |
| var result = dest_operand << count | getcf() << (count - 1) | dest_operand >> (17 - count); |
| flags_changed &= ~flag_carry & ~flag_overflow; |
| flags = (flags & ~1 & ~flag_overflow) |
| | (result >> 16 & 1) |
| | (result >> 5 ^ result >> 4) & flag_overflow; |
| return result; |
| } |
| function rcl32(dest_operand, count) |
| { |
| if(!count) |
| { |
| return dest_operand; |
| } |
| var result = dest_operand << count | getcf() << (count - 1); |
| if(count > 1) |
| { |
| result |= dest_operand >>> (33 - count); |
| } |
| flags_changed &= ~flag_carry & ~flag_overflow; |
| flags = (flags & ~1 & ~flag_overflow) | (dest_operand >>> (32 - count) & 1); |
| flags |= (flags << 11 ^ result >> 20) & flag_overflow; |
| return result; |
| } |
| function ror8(dest_operand, count) |
| { |
| count &= 7; |
| if(!count) |
| { |
| return dest_operand; |
| } |
| var result = dest_operand >> count | dest_operand << (8 - count); |
| flags_changed &= ~flag_carry & ~flag_overflow; |
| flags = (flags & ~1 & ~flag_overflow) |
| | (result >> 7 & 1) |
| | (result << 4 ^ result << 5) & flag_overflow; |
| return result; |
| } |
| function ror16(dest_operand, count) |
| { |
| count &= 15; |
| if(!count) |
| { |
| return dest_operand; |
| } |
| var result = dest_operand >> count | dest_operand << (16 - count); |
| flags_changed &= ~flag_carry & ~flag_overflow; |
| flags = (flags & ~1 & ~flag_overflow) |
| | (result >> 15 & 1) |
| | (result >> 4 ^ result >> 3) & flag_overflow; |
| return result; |
| } |
| function ror32(dest_operand, count) |
| { |
| if(!count) |
| { |
| return dest_operand; |
| } |
| var result = dest_operand >>> count | dest_operand << (32 - count); |
| flags_changed &= ~flag_carry & ~flag_overflow; |
| flags = (flags & ~1 & ~flag_overflow) |
| | (result >> 31 & 1) |
| | (result >> 20 ^ result >> 19) & flag_overflow; |
| return result; |
| } |
| function rcr8(dest_operand, count) |
| { |
| count %= 9; |
| if(!count) |
| { |
| return dest_operand; |
| } |
| var result = dest_operand >> count | getcf() << (8 - count) | dest_operand << (9 - count); |
| flags_changed &= ~flag_carry & ~flag_overflow; |
| flags = (flags & ~1 & ~flag_overflow) |
| | (result >> 8 & 1) |
| | (result << 4 ^ result << 5) & flag_overflow; |
| return result; |
| } |
| function rcr16(dest_operand, count) |
| { |
| count %= 17; |
| if(!count) |
| { |
| return dest_operand; |
| } |
| var result = dest_operand >> count | getcf() << (16 - count) | dest_operand << (17 - count); |
| flags_changed &= ~flag_carry & ~flag_overflow; |
| flags = (flags & ~1 & ~flag_overflow) |
| | (result >> 16 & 1) |
| | (result >> 4 ^ result >> 3) & flag_overflow; |
| return result; |
| } |
| function rcr32(dest_operand, count) |
| { |
| if(!count) |
| { |
| return dest_operand; |
| } |
| var result = dest_operand >>> count | getcf() << (32 - count); |
| if(count > 1) |
| { |
| result |= dest_operand << (33 - count); |
| } |
| flags_changed &= ~flag_carry & ~flag_overflow; |
| flags = (flags & ~1 & ~flag_overflow) |
| | (dest_operand >> (count - 1) & 1) |
| | (result >> 20 ^ result >> 19) & flag_overflow; |
| return result; |
| } |
| function shl8(dest_operand, count) |
| { |
| if(count === 0) |
| { |
| return dest_operand; |
| } |
| last_result = dest_operand << count; |
| last_op_size = OPSIZE_8; |
| flags_changed = flags_all & ~flag_carry & ~flag_overflow; |
| flags = (flags & ~1 & ~flag_overflow) |
| | (last_result >> 8 & 1) |
| | (last_result << 3 ^ last_result << 4) & flag_overflow; |
| return last_result; |
| } |
| function shl16(dest_operand, count) |
| { |
| if(count === 0) |
| { |
| return dest_operand; |
| } |
| last_result = dest_operand << count; |
| last_op_size = OPSIZE_16; |
| flags_changed = flags_all & ~flag_carry & ~flag_overflow; |
| flags = (flags & ~1 & ~flag_overflow) |
| | (last_result >> 16 & 1) |
| | (last_result >> 5 ^ last_result >> 4) & flag_overflow; |
| return last_result; |
| } |
| function shl32(dest_operand, count) |
| { |
| if(count === 0) |
| { |
| return dest_operand; |
| } |
| last_result = dest_operand << count; |
| last_op_size = OPSIZE_32; |
| flags_changed = flags_all & ~flag_carry & ~flag_overflow; |
| // test this |
| flags = (flags & ~1 & ~flag_overflow) | (dest_operand >>> (32 - count) & 1); |
| flags |= ((flags & 1) ^ (last_result >> 31 & 1)) << 11 & flag_overflow; |
| return last_result; |
| } |
| function shr8(dest_operand, count) |
| { |
| if(count === 0) |
| { |
| return dest_operand; |
| } |
| last_result = dest_operand >> count; |
| last_op_size = OPSIZE_8; |
| flags_changed = flags_all & ~flag_carry & ~flag_overflow; |
| flags = (flags & ~1 & ~flag_overflow) |
| | (dest_operand >> (count - 1) & 1) |
| | (dest_operand >> 7 & 1) << 11 & flag_overflow; |
| return last_result; |
| } |
| function shr16(dest_operand, count) |
| { |
| if(count === 0) |
| { |
| return dest_operand; |
| } |
| last_result = dest_operand >> count; |
| last_op_size = OPSIZE_16; |
| flags_changed = flags_all & ~flag_carry & ~flag_overflow; |
| flags = (flags & ~1 & ~flag_overflow) |
| | (dest_operand >> (count - 1) & 1) |
| | (dest_operand >> 4) & flag_overflow; |
| return last_result; |
| } |
| function shr32(dest_operand, count) |
| { |
| if(count === 0) |
| { |
| return dest_operand; |
| } |
| last_result = dest_operand >>> count; |
| last_op_size = OPSIZE_32; |
| flags_changed = flags_all & ~flag_carry & ~flag_overflow; |
| flags = (flags & ~1 & ~flag_overflow) |
| | (dest_operand >>> (count - 1) & 1) |
| | (dest_operand >> 20) & flag_overflow; |
| return last_result; |
| } |
| function sar8(dest_operand, count) |
| { |
| if(count === 0) |
| { |
| return dest_operand; |
| } |
| last_result = dest_operand >> count; |
| last_op_size = OPSIZE_8; |
| flags_changed = flags_all & ~flag_carry & ~flag_overflow; |
| flags = (flags & ~1 & ~flag_overflow) | (dest_operand >> (count - 1) & 1); |
| // of is zero |
| return last_result; |
| } |
| function sar16(dest_operand, count) |
| { |
| if(count === 0) |
| { |
| return dest_operand; |
| } |
| last_result = dest_operand >> count; |
| last_op_size = OPSIZE_16; |
| flags_changed = flags_all & ~flag_carry & ~flag_overflow; |
| flags = (flags & ~1 & ~flag_overflow) | (dest_operand >> (count - 1) & 1); |
| return last_result; |
| } |
| function sar32(dest_operand, count) |
| { |
| if(count === 0) |
| { |
| return dest_operand; |
| } |
| last_result = dest_operand >> count; |
| last_op_size = OPSIZE_32; |
| flags_changed = flags_all & ~flag_carry & ~flag_overflow; |
| flags = (flags & ~1 & ~flag_overflow) | (dest_operand >>> (count - 1) & 1); |
| return last_result; |
| } |
| function shrd16(dest_operand, source_operand, count) |
| { |
| if(count === 0) |
| { |
| return dest_operand; |
| } |
| if(count <= 16) |
| { |
| last_result = dest_operand >> count | source_operand << (16 - count); |
| flags = (flags & ~1) | (dest_operand >> (count - 1) & 1); |
| } |
| else |
| { |
| last_result = dest_operand << (32 - count) | source_operand >> (count - 16); |
| flags = (flags & ~1) | (source_operand >> (count - 17) & 1); |
| } |
| last_op_size = OPSIZE_16; |
| flags_changed = flags_all & ~1 & ~flag_overflow; |
| flags = (flags & ~flag_overflow) | ((last_result ^ dest_operand) >> 4 & flag_overflow); |
| return last_result; |
| } |
| function shrd32(dest_operand, source_operand, count) |
| { |
| if(count === 0) |
| { |
| return dest_operand; |
| } |
| last_result = dest_operand >>> count | source_operand << (32 - count); |
| last_op_size = OPSIZE_32; |
| flags_changed = flags_all & ~1 & ~flag_overflow; |
| flags = (flags & ~1) | (dest_operand >>> (count - 1) & 1); |
| flags = (flags & ~flag_overflow) | ((last_result ^ dest_operand) >> 20 & flag_overflow); |
| return last_result; |
| } |
| function shld16(dest_operand, source_operand, count) |
| { |
| if(count === 0) |
| { |
| return dest_operand; |
| } |
| if(count <= 16) |
| { |
| last_result = dest_operand << count | source_operand >>> (16 - count); |
| flags = (flags & ~1) | (dest_operand >>> (16 - count) & 1); |
| } |
| else |
| { |
| last_result = dest_operand >> (32 - count) | source_operand << (count - 16); |
| flags = (flags & ~1) | (source_operand >>> (32 - count) & 1); |
| } |
| last_op_size = OPSIZE_16; |
| flags_changed = flags_all & ~1 & ~flag_overflow; |
| flags = (flags & ~flag_overflow) | ((flags & 1) ^ (last_result >> 15 & 1)) << 11; |
| return last_result; |
| } |
| function shld32(dest_operand, source_operand, count) |
| { |
| if(count === 0) |
| { |
| return dest_operand; |
| } |
| last_result = dest_operand << count | source_operand >>> (32 - count); |
| last_op_size = OPSIZE_32; |
| flags_changed = flags_all & ~1 & ~flag_overflow; |
| // test this |
| flags = (flags & ~1) | (dest_operand >>> (32 - count) & 1); |
| flags = (flags & ~flag_overflow) | ((flags & 1) ^ (last_result >> 31 & 1)) << 11; |
| return last_result; |
| } |
| function bt_reg(bit_base, bit_offset) |
| { |
| flags = (flags & ~1) | (bit_base >> bit_offset & 1); |
| flags_changed = 0; |
| } |
| function btc_reg(bit_base, bit_offset) |
| { |
| flags = (flags & ~1) | (bit_base >> bit_offset & 1); |
| flags_changed = 0; |
| return bit_base ^ 1 << bit_offset; |
| } |
| function bts_reg(bit_base, bit_offset) |
| { |
| flags = (flags & ~1) | (bit_base >> bit_offset & 1); |
| flags_changed = 0; |
| return bit_base | 1 << bit_offset; |
| } |
| function btr_reg(bit_base, bit_offset) |
| { |
| flags = (flags & ~1) | (bit_base >> bit_offset & 1); |
| flags_changed = 0; |
| return bit_base & ~(1 << bit_offset); |
| } |
| function bt_mem(virt_addr, bit_offset) |
| { |
| var bit_base = safe_read8(virt_addr + (bit_offset >> 3)); |
| bit_offset &= 7; |
| flags = (flags & ~1) | (bit_base >> bit_offset & 1); |
| flags_changed = 0; |
| } |
| function btc_mem(virt_addr, bit_offset) |
| { |
| var phys_addr = translate_address_write(virt_addr + (bit_offset >> 3)); |
| var bit_base = memory.read8(phys_addr); |
| bit_offset &= 7; |
| flags = (flags & ~1) | (bit_base >> bit_offset & 1); |
| flags_changed = 0; |
| memory.write8(phys_addr, bit_base ^ 1 << bit_offset); |
| } |
| function btr_mem(virt_addr, bit_offset) |
| { |
| var phys_addr = translate_address_write(virt_addr + (bit_offset >> 3)); |
| var bit_base = memory.read8(phys_addr); |
| bit_offset &= 7; |
| flags = (flags & ~1) | (bit_base >> bit_offset & 1); |
| flags_changed = 0; |
| memory.write8(phys_addr, bit_base & ~(1 << bit_offset)); |
| } |
| function bts_mem(virt_addr, bit_offset) |
| { |
| var phys_addr = translate_address_write(virt_addr + (bit_offset >> 3)); |
| var bit_base = memory.read8(phys_addr); |
| bit_offset &= 7; |
| flags = (flags & ~1) | (bit_base >> bit_offset & 1); |
| flags_changed = 0; |
| memory.write8(phys_addr, bit_base | 1 << bit_offset); |
| } |
| var mod37_bit_position = new Uint8Array([ |
| 32, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, 4, |
| 7, 17, 0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9, 5, |
| 20, 8, 19, 18 |
| ]); |
| function bsf16(old, bit_base) |
| { |
| flags_changed = 0; |
| if(bit_base === 0) |
| { |
| flags |= flag_zero; |
| // not defined in the docs, but value doesn't change on my intel cpu |
| return old; |
| } |
| else |
| { |
| flags &= ~flag_zero; |
| return mod37_bit_position[((-bit_base & bit_base) >>> 0) % 37]; |
| } |
| } |
| function bsf32(old, bit_base) |
| { |
| flags_changed = 0; |
| if(bit_base === 0) |
| { |
| flags |= flag_zero; |
| return old; |
| } |
| else |
| { |
| flags &= ~flag_zero; |
| return mod37_bit_position[((-bit_base & bit_base) >>> 0) % 37]; |
| } |
| } |
| function bsr16(old, bit_base) |
| { |
| flags_changed = 0; |
| if(bit_base === 0) |
| { |
| flags |= flag_zero; |
| return old; |
| } |
| else |
| { |
| flags &= ~flag_zero; |
| var t = bit_base >>> 8; |
| if(t) |
| { |
| return 8 + log2_table[t]; |
| } |
| else |
| { |
| return log2_table[bit_base]; |
| } |
| } |
| } |
| function bsr32(old, bit_base) |
| { |
| flags_changed = 0; |
| if(bit_base === 0) |
| { |
| flags |= flag_zero; |
| return old; |
| } |
| else |
| { |
| flags &= ~flag_zero; |
| var tt = bit_base >>> 16, |
| t; |
| if(tt) |
| { |
| t = tt >>> 8; |
| if(t) |
| { |
| return 24 + log2_table[t]; |
| } |
| else |
| { |
| return 16 + log2_table[tt]; |
| } |
| } |
| else |
| { |
| t = bit_base >>> 8; |
| if(t) |
| { |
| return 8 + log2_table[t]; |
| } |
| else |
| { |
| return log2_table[bit_base]; |
| } |
| } |
| } |
| } |
| /* |
| * Some miscellaneous instructions: |
| * |
| * jmpcc16, jmpcc32, jmp16 |
| * loop, loope, loopne, jcxz |
| * test_cc |
| * |
| * mov, push, pop |
| * pusha, popa |
| * xchg, lss |
| * lea |
| * enter |
| * bswap |
| * |
| * Gets #included by cpu.macro.js |
| */ |
| "use strict"; |
| function jmp_rel16(rel16) |
| { |
| var current_cs = get_seg(reg_cs); |
| // limit ip to 16 bit |
| // ugly |
| instruction_pointer -= current_cs; |
| instruction_pointer = (instruction_pointer + rel16) & 0xFFFF; |
| instruction_pointer = instruction_pointer + current_cs | 0; |
| } |
| function jmpcc16(condition) |
| { |
| if(condition) |
| { |
| jmp_rel16(read_imm16()); |
| } |
| else |
| { |
| instruction_pointer += 2; |
| } |
| } |
| function jmpcc32(condition) |
| { |
| if(condition) |
| { |
| // don't write `instruction_pointer += read_imm32s()` |
| var imm32s = read_imm32s(); |
| instruction_pointer = instruction_pointer + imm32s | 0; |
| } |
| else |
| { |
| instruction_pointer = instruction_pointer + 4 | 0; |
| } |
| } |
| function loopne() |
| { |
| if(--regv[reg_vcx] && !getzf()) |
| { |
| var imm8s = read_imm8s(); |
| instruction_pointer = instruction_pointer + imm8s | 0; |
| } |
| else |
| { |
| instruction_pointer++; |
| } |
| } |
| function loope() |
| { |
| if(--regv[reg_vcx] && getzf()) |
| { |
| var imm8s = read_imm8s(); |
| instruction_pointer = instruction_pointer + imm8s | 0; |
| } |
| else |
| { |
| instruction_pointer++; |
| } |
| } |
| function loop() |
| { |
| if(--regv[reg_vcx]) |
| { |
| var imm8s = read_imm8s(); |
| instruction_pointer = instruction_pointer + imm8s | 0; |
| } |
| else |
| { |
| instruction_pointer++; |
| } |
| } |
| function jcxz() |
| { |
| var imm8s = read_imm8s(); |
| if(regv[reg_vcx] === 0) |
| { |
| instruction_pointer = instruction_pointer + imm8s | 0; |
| } |
| } |
| var test_o = getof, |
| test_b = getcf, |
| test_z = getzf, |
| test_s = getsf, |
| test_p = getpf; |
| function test_be() |
| { |
| return getcf() || getzf(); |
| } |
| function test_l() |
| { |
| return !getsf() !== !getof(); |
| } |
| function test_le() |
| { |
| return getzf() || !getsf() !== !getof(); |
| } |
| /** |
| * @return {number} |
| * @const |
| */ |
| function getcf() |
| { |
| if(flags_changed & 1) |
| { |
| if(last_op_size === OPSIZE_32) |
| { |
| // cannot bit test above 2^32-1 |
| return last_result > 0xffffffff | last_result < 0; |
| //return ((last_op1 ^ last_result) & (last_op2 ^ last_result)) >>> 31; |
| } |
| else |
| { |
| return last_result >> last_op_size & 1; |
| } |
| //return last_result >= (1 << last_op_size) | last_result < 0; |
| } |
| else |
| { |
| return flags & 1; |
| } |
| } |
| /** @return {number} */ |
| function 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; |
| } |
| } |
| /** @return {number} */ |
| function getaf() |
| { |
| if(flags_changed & flag_adjust) |
| { |
| return (last_op1 ^ last_op2 ^ last_result ^ (last_op2 < 0) << 4) & flag_adjust; |
| } |
| else |
| { |
| return flags & flag_adjust; |
| } |
| } |
| /** @return {number} */ |
| function getzf() |
| { |
| if(flags_changed & flag_zero) |
| { |
| return (~last_result & last_result - 1) >> last_op_size - 7 & flag_zero; |
| } |
| else |
| { |
| return flags & flag_zero; |
| } |
| } |
| /** @return {number} */ |
| function getsf() |
| { |
| if(flags_changed & flag_sign) |
| { |
| return last_result >> last_op_size - 8 & flag_sign; |
| } |
| else |
| { |
| return flags & flag_sign; |
| } |
| } |
| /** @return {number} */ |
| function getof() |
| { |
| if(flags_changed & flag_overflow) |
| { |
| return (((last_op1 ^ last_result) & (last_op2 ^ last_result)) >> last_op_size - 1) << 11 & flag_overflow; |
| } |
| else |
| { |
| return flags & flag_overflow; |
| } |
| } |
| function push16(imm16) |
| { |
| var sp = get_esp_write(-2); |
| stack_reg[reg_vsp] -= 2; |
| memory.write16(sp, imm16); |
| } |
| function push32(imm32) |
| { |
| var sp = get_esp_write(-4); |
| stack_reg[reg_vsp] -= 4; |
| memory.write32(sp, imm32); |
| } |
| function pop16() |
| { |
| var sp = get_esp_read(0); |
| stack_reg[reg_vsp] += 2; |
| return memory.read16(sp); |
| } |
| function pop32s() |
| { |
| var sp = get_esp_read(0); |
| stack_reg[reg_vsp] += 4; |
| return memory.read32s(sp); |
| } |
| function pusha16() |
| { |
| var temp = reg16[reg_sp]; |
| // make sure we don't get a pagefault after having |
| // pushed several registers already |
| translate_address_write(temp - 15); |
| push16(reg16[reg_ax]); |
| push16(reg16[reg_cx]); |
| push16(reg16[reg_dx]); |
| push16(reg16[reg_bx]); |
| push16(temp); |
| push16(reg16[reg_bp]); |
| push16(reg16[reg_si]); |
| push16(reg16[reg_di]); |
| } |
| function pusha32() |
| { |
| var temp = reg32s[reg_esp]; |
| translate_address_write(temp - 31); |
| push32(reg32s[reg_eax]); |
| push32(reg32s[reg_ecx]); |
| push32(reg32s[reg_edx]); |
| push32(reg32s[reg_ebx]); |
| push32(temp); |
| push32(reg32s[reg_ebp]); |
| push32(reg32s[reg_esi]); |
| push32(reg32s[reg_edi]); |
| } |
| function popa16() |
| { |
| translate_address_read(stack_reg[reg_vsp] + 15); |
| reg16[reg_di] = pop16(); |
| reg16[reg_si] = pop16(); |
| reg16[reg_bp] = pop16(); |
| stack_reg[reg_vsp] += 2; |
| reg16[reg_bx] = pop16(); |
| reg16[reg_dx] = pop16(); |
| reg16[reg_cx] = pop16(); |
| reg16[reg_ax] = pop16(); |
| } |
| function popa32() |
| { |
| translate_address_read(stack_reg[reg_vsp] + 31); |
| reg32[reg_edi] = pop32s(); |
| reg32[reg_esi] = pop32s(); |
| reg32[reg_ebp] = pop32s(); |
| stack_reg[reg_vsp] += 4; |
| reg32[reg_ebx] = pop32s(); |
| reg32[reg_edx] = pop32s(); |
| reg32[reg_ecx] = pop32s(); |
| reg32[reg_eax] = pop32s(); |
| } |
| function xchg8(memory_data, modrm_byte) |
| { |
| var mod = modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1, |
| tmp = reg8[mod]; |
| reg8[mod] = memory_data; |
| return tmp; |
| } |
| function xchg16(memory_data, modrm_byte) |
| { |
| var mod = modrm_byte >> 2 & 14, |
| tmp = reg16[mod]; |
| reg16[mod] = memory_data; |
| return tmp; |
| } |
| function xchg16r(operand) |
| { |
| var temp = reg16[reg_ax]; |
| reg16[reg_ax] = reg16[operand]; |
| reg16[operand] = temp; |
| } |
| function xchg32(memory_data, modrm_byte) |
| { |
| var mod = modrm_byte >> 3 & 7, |
| tmp = reg32s[mod]; |
| reg32[mod] = memory_data; |
| return tmp; |
| } |
| function xchg32r(operand) |
| { |
| var temp = reg32s[reg_eax]; |
| reg32[reg_eax] = reg32s[operand]; |
| reg32[operand] = temp; |
| } |
| function lss16(seg, addr, mod) |
| { |
| var new_reg = safe_read16(addr), |
| new_seg = safe_read16(addr + 2); |
| switch_seg(seg, new_seg); |
| reg16[mod] = new_reg; |
| } |
| function lss32(seg, addr, mod) |
| { |
| var new_reg = safe_read32s(addr), |
| new_seg = safe_read16(addr + 4); |
| switch_seg(seg, new_seg); |
| reg32[mod] = new_reg; |
| } |
| function lea16() |
| { |
| var modrm_byte = read_imm8(), |
| mod = modrm_byte >> 3 & 7; |
| // override prefix, so modrm16 does not return the segment part |
| segment_prefix = reg_noseg; |
| reg16[mod << 1] = modrm_resolve(modrm_byte); |
| segment_prefix = -1; |
| } |
| function lea32() |
| { |
| var modrm_byte = read_imm8(), |
| mod = modrm_byte >> 3 & 7; |
| segment_prefix = reg_noseg; |
| reg32[mod] = modrm_resolve(modrm_byte); |
| segment_prefix = -1; |
| } |
| function enter16() |
| { |
| var size = read_imm16(), |
| nesting_level = read_imm8(), |
| frame_temp; |
| push16(reg16[reg_bp]); |
| frame_temp = reg16[reg_sp]; |
| if(nesting_level > 0) |
| { |
| for(var i = 1; i < nesting_level; i++) |
| { |
| reg16[reg_bp] -= 2; |
| push16(reg16[reg_bp]); |
| } |
| push16(frame_temp); |
| } |
| reg16[reg_bp] = frame_temp; |
| reg16[reg_sp] = frame_temp - size; |
| dbg_assert(!page_fault); |
| } |
| function enter32() |
| { |
| var size = read_imm16(), |
| nesting_level = read_imm8() & 31, |
| frame_temp; |
| push32(reg32s[reg_ebp]); |
| frame_temp = reg32s[reg_esp]; |
| if(nesting_level > 0) |
| { |
| for(var i = 1; i < nesting_level; i++) |
| { |
| reg32[reg_ebp] -= 4; |
| push32(reg32s[reg_ebp]); |
| } |
| push32(frame_temp); |
| } |
| reg32[reg_ebp] = frame_temp; |
| reg32[reg_esp] -= size; |
| dbg_assert(!page_fault); |
| } |
| function bswap(reg) |
| { |
| var temp = reg32s[reg]; |
| reg32[reg] = temp >>> 24 | temp << 24 | (temp >> 8 & 0xFF00) | (temp << 8 & 0xFF0000); |
| } |
| "use strict"; |
| /* |
| * string operations |
| * |
| * cmp si di |
| * movs 0 1 1 A4 |
| * cmps 1 1 1 A6 |
| * stos 0 0 1 AA |
| * lods 0 1 0 AC |
| * scas 1 0 1 AE |
| * ins 0 0 1 |
| * outs 0 1 0 |
| */ |
| function movsb() |
| { |
| var src, dest, data_src, data_dest; var size = flags & flag_direction ? -(8 >> 3) : 8 >> 3; var ds, es; if(false && !true) data_src = reg8[reg_eax]; if(true) es = get_seg(reg_es), dest = es + regv[reg_vdi]; if(true) ds = get_seg_prefix(reg_ds), src = ds + regv[reg_vsi]; if(repeat_string_prefix) { if(regv[reg_vcx] === 0) return; var aligned = 8 > 8 && (!true || (dest & (8 >> 3) - 1) === 0) && (!true || (src & (8 >> 3) - 1) === 0); do { if(aligned) { {}; } else { { safe_write8(dest, safe_read8(src)); }; } if(true) dest += size, regv[reg_vdi] += size; if(true) src += size, regv[reg_vsi] += size; } while(--regv[reg_vcx] && (!false || (data_src === data_dest) === repeat_string_type)); } else { { safe_write8(dest, safe_read8(src)); }; if(true) regv[reg_vdi] += size; if(true) regv[reg_vsi] += size; } if(false) cmp8(data_src, data_dest);; |
| } |
| function movsw() |
| { |
| var src, dest, data_src, data_dest; var size = flags & flag_direction ? -(16 >> 3) : 16 >> 3; var ds, es; if(false && !true) data_src = reg16[reg_eax]; if(true) es = get_seg(reg_es), dest = es + regv[reg_vdi]; if(true) ds = get_seg_prefix(reg_ds), src = ds + regv[reg_vsi]; if(repeat_string_prefix) { if(regv[reg_vcx] === 0) return; var aligned = 16 > 8 && (!true || (dest & (16 >> 3) - 1) === 0) && (!true || (src & (16 >> 3) - 1) === 0); do { if(aligned) { { var phys_src = translate_address_read(src); var phys_dest = translate_address_write(dest); memory.write_aligned16(phys_dest, memory.read_aligned16(phys_src)); }; } else { { safe_write16(dest, safe_read16(src)); }; } if(true) dest += size, regv[reg_vdi] += size; if(true) src += size, regv[reg_vsi] += size; } while(--regv[reg_vcx] && (!false || (data_src === data_dest) === repeat_string_type)); } else { { safe_write16(dest, safe_read16(src)); }; if(true) regv[reg_vdi] += size; if(true) regv[reg_vsi] += size; } if(false) cmp16(data_src, data_dest);; |
| } |
| function movsd() |
| { |
| var src, dest, data_src, data_dest; var size = flags & flag_direction ? -(32 >> 3) : 32 >> 3; var ds, es; if(false && !true) data_src = reg32[reg_eax]; if(true) es = get_seg(reg_es), dest = es + regv[reg_vdi]; if(true) ds = get_seg_prefix(reg_ds), src = ds + regv[reg_vsi]; if(repeat_string_prefix) { if(regv[reg_vcx] === 0) return; var aligned = 32 > 8 && (!true || (dest & (32 >> 3) - 1) === 0) && (!true || (src & (32 >> 3) - 1) === 0); do { if(aligned) { { var phys_src = translate_address_read(src); var phys_dest = translate_address_write(dest); memory.write_aligned32(phys_dest, memory.read_aligned32(phys_src)); }; } else { { safe_write32(dest, safe_read32s(src)); }; } if(true) dest += size, regv[reg_vdi] += size; if(true) src += size, regv[reg_vsi] += size; } while(--regv[reg_vcx] && (!false || (data_src === data_dest) === repeat_string_type)); } else { { safe_write32(dest, safe_read32s(src)); }; if(true) regv[reg_vdi] += size; if(true) regv[reg_vsi] += size; } if(false) cmp32(data_src, data_dest);; |
| } |
| function cmpsb() |
| { |
| var src, dest, data_src, data_dest; var size = flags & flag_direction ? -(8 >> 3) : 8 >> 3; var ds, es; if(true && !true) data_src = reg8[reg_eax]; if(true) es = get_seg(reg_es), dest = es + regv[reg_vdi]; if(true) ds = get_seg_prefix(reg_ds), src = ds + regv[reg_vsi]; if(repeat_string_prefix) { if(regv[reg_vcx] === 0) return; var aligned = 8 > 8 && (!true || (dest & (8 >> 3) - 1) === 0) && (!true || (src & (8 >> 3) - 1) === 0); do { if(aligned) { {}; } else { { data_dest = safe_read8(dest); data_src = safe_read8(src); }; } if(true) dest += size, regv[reg_vdi] += size; if(true) src += size, regv[reg_vsi] += size; } while(--regv[reg_vcx] && (!true || (data_src === data_dest) === repeat_string_type)); } else { { data_dest = safe_read8(dest); data_src = safe_read8(src); }; if(true) regv[reg_vdi] += size; if(true) regv[reg_vsi] += size; } if(true) cmp8(data_src, data_dest);; |
| } |
| function cmpsw() |
| { |
| var src, dest, data_src, data_dest; var size = flags & flag_direction ? -(16 >> 3) : 16 >> 3; var ds, es; if(true && !true) data_src = reg16[reg_eax]; if(true) es = get_seg(reg_es), dest = es + regv[reg_vdi]; if(true) ds = get_seg_prefix(reg_ds), src = ds + regv[reg_vsi]; if(repeat_string_prefix) { if(regv[reg_vcx] === 0) return; var aligned = 16 > 8 && (!true || (dest & (16 >> 3) - 1) === 0) && (!true || (src & (16 >> 3) - 1) === 0); do { if(aligned) { { data_dest = memory.read_aligned16(translate_address_read(dest)); data_src = memory.read_aligned16(translate_address_read(src)); }; } else { { data_dest = safe_read16(dest); data_src = safe_read16(src); }; } if(true) dest += size, regv[reg_vdi] += size; if(true) src += size, regv[reg_vsi] += size; } while(--regv[reg_vcx] && (!true || (data_src === data_dest) === repeat_string_type)); } else { { data_dest = safe_read16(dest); data_src = safe_read16(src); }; if(true) regv[reg_vdi] += size; if(true) regv[reg_vsi] += size; } if(true) cmp16(data_src, data_dest);; |
| } |
| function cmpsd() |
| { |
| var src, dest, data_src, data_dest; var size = flags & flag_direction ? -(32 >> 3) : 32 >> 3; var ds, es; if(true && !true) data_src = reg32[reg_eax]; if(true) es = get_seg(reg_es), dest = es + regv[reg_vdi]; if(true) ds = get_seg_prefix(reg_ds), src = ds + regv[reg_vsi]; if(repeat_string_prefix) { if(regv[reg_vcx] === 0) return; var aligned = 32 > 8 && (!true || (dest & (32 >> 3) - 1) === 0) && (!true || (src & (32 >> 3) - 1) === 0); do { if(aligned) { { data_dest = memory.read_aligned32(translate_address_read(dest)) >>> 0; data_src = memory.read_aligned32(translate_address_read(src)) >>> 0; }; } else { { data_dest = (safe_read32s(dest) >>> 0); data_src = (safe_read32s(src) >>> 0); }; } if(true) dest += size, regv[reg_vdi] += size; if(true) src += size, regv[reg_vsi] += size; } while(--regv[reg_vcx] && (!true || (data_src === data_dest) === repeat_string_type)); } else { { data_dest = (safe_read32s(dest) >>> 0); data_src = (safe_read32s(src) >>> 0); }; if(true) regv[reg_vdi] += size; if(true) regv[reg_vsi] += size; } if(true) cmp32(data_src, data_dest);; |
| } |
| function stosb() |
| { |
| var data = reg8[reg_al]; |
| var src, dest, data_src, data_dest; var size = flags & flag_direction ? -(8 >> 3) : 8 >> 3; var ds, es; if(false && !false) data_src = reg8[reg_eax]; if(true) es = get_seg(reg_es), dest = es + regv[reg_vdi]; if(false) ds = get_seg_prefix(reg_ds), src = ds + regv[reg_vsi]; if(repeat_string_prefix) { if(regv[reg_vcx] === 0) return; var aligned = 8 > 8 && (!true || (dest & (8 >> 3) - 1) === 0) && (!false || (src & (8 >> 3) - 1) === 0); do { if(aligned) { {}; } else { { safe_write8(dest, data); }; } if(true) dest += size, regv[reg_vdi] += size; if(false) src += size, regv[reg_vsi] += size; } while(--regv[reg_vcx] && (!false || (data_src === data_dest) === repeat_string_type)); } else { { safe_write8(dest, data); }; if(true) regv[reg_vdi] += size; if(false) regv[reg_vsi] += size; } if(false) cmp8(data_src, data_dest);; |
| } |
| function stosw() |
| { |
| var data = reg16[reg_ax]; |
| var src, dest, data_src, data_dest; var size = flags & flag_direction ? -(16 >> 3) : 16 >> 3; var ds, es; if(false && !false) data_src = reg16[reg_eax]; if(true) es = get_seg(reg_es), dest = es + regv[reg_vdi]; if(false) ds = get_seg_prefix(reg_ds), src = ds + regv[reg_vsi]; if(repeat_string_prefix) { if(regv[reg_vcx] === 0) return; var aligned = 16 > 8 && (!true || (dest & (16 >> 3) - 1) === 0) && (!false || (src & (16 >> 3) - 1) === 0); do { if(aligned) { { memory.write_aligned16(translate_address_write(dest), data); }; } else { { safe_write16(dest, data); }; } if(true) dest += size, regv[reg_vdi] += size; if(false) src += size, regv[reg_vsi] += size; } while(--regv[reg_vcx] && (!false || (data_src === data_dest) === repeat_string_type)); } else { { safe_write16(dest, data); }; if(true) regv[reg_vdi] += size; if(false) regv[reg_vsi] += size; } if(false) cmp16(data_src, data_dest);; |
| } |
| function stosd() |
| { |
| //dbg_log("stosd " + ((reg32[reg_edi] & 3) ? "mis" : "") + "aligned", LOG_CPU); |
| var data = reg32[reg_eax]; |
| var src, dest, data_src, data_dest; var size = flags & flag_direction ? -(32 >> 3) : 32 >> 3; var ds, es; if(false && !false) data_src = reg32[reg_eax]; if(true) es = get_seg(reg_es), dest = es + regv[reg_vdi]; if(false) ds = get_seg_prefix(reg_ds), src = ds + regv[reg_vsi]; if(repeat_string_prefix) { if(regv[reg_vcx] === 0) return; var aligned = 32 > 8 && (!true || (dest & (32 >> 3) - 1) === 0) && (!false || (src & (32 >> 3) - 1) === 0); do { if(aligned) { { memory.write_aligned32(translate_address_write(dest), data); }; } else { { safe_write32(dest, data); }; } if(true) dest += size, regv[reg_vdi] += size; if(false) src += size, regv[reg_vsi] += size; } while(--regv[reg_vcx] && (!false || (data_src === data_dest) === repeat_string_type)); } else { { safe_write32(dest, data); }; if(true) regv[reg_vdi] += size; if(false) regv[reg_vsi] += size; } if(false) cmp32(data_src, data_dest);; |
| } |
| function lodsb() |
| { |
| var src, dest, data_src, data_dest; var size = flags & flag_direction ? -(8 >> 3) : 8 >> 3; var ds, es; if(false && !true) data_src = reg8[reg_eax]; if(false) es = get_seg(reg_es), dest = es + regv[reg_vdi]; if(true) ds = get_seg_prefix(reg_ds), src = ds + regv[reg_vsi]; if(repeat_string_prefix) { if(regv[reg_vcx] === 0) return; var aligned = 8 > 8 && (!false || (dest & (8 >> 3) - 1) === 0) && (!true || (src & (8 >> 3) - 1) === 0); do { if(aligned) { {}; } else { { reg8[reg_al] = safe_read8(src); }; } if(false) dest += size, regv[reg_vdi] += size; if(true) src += size, regv[reg_vsi] += size; } while(--regv[reg_vcx] && (!false || (data_src === data_dest) === repeat_string_type)); } else { { reg8[reg_al] = safe_read8(src); }; if(false) regv[reg_vdi] += size; if(true) regv[reg_vsi] += size; } if(false) cmp8(data_src, data_dest);; |
| } |
| function lodsw() |
| { |
| var src, dest, data_src, data_dest; var size = flags & flag_direction ? -(16 >> 3) : 16 >> 3; var ds, es; if(false && !true) data_src = reg16[reg_eax]; if(false) es = get_seg(reg_es), dest = es + regv[reg_vdi]; if(true) ds = get_seg_prefix(reg_ds), src = ds + regv[reg_vsi]; if(repeat_string_prefix) { if(regv[reg_vcx] === 0) return; var aligned = 16 > 8 && (!false || (dest & (16 >> 3) - 1) === 0) && (!true || (src & (16 >> 3) - 1) === 0); do { if(aligned) { { reg16[reg_ax] = safe_read16(src); }; } else { { reg16[reg_ax] = safe_read16(src); }; } if(false) dest += size, regv[reg_vdi] += size; if(true) src += size, regv[reg_vsi] += size; } while(--regv[reg_vcx] && (!false || (data_src === data_dest) === repeat_string_type)); } else { { reg16[reg_ax] = safe_read16(src); }; if(false) regv[reg_vdi] += size; if(true) regv[reg_vsi] += size; } if(false) cmp16(data_src, data_dest);; |
| } |
| function lodsd() |
| { |
| var src, dest, data_src, data_dest; var size = flags & flag_direction ? -(32 >> 3) : 32 >> 3; var ds, es; if(false && !true) data_src = reg32[reg_eax]; if(false) es = get_seg(reg_es), dest = es + regv[reg_vdi]; if(true) ds = get_seg_prefix(reg_ds), src = ds + regv[reg_vsi]; if(repeat_string_prefix) { if(regv[reg_vcx] === 0) return; var aligned = 32 > 8 && (!false || (dest & (32 >> 3) - 1) === 0) && (!true || (src & (32 >> 3) - 1) === 0); do { if(aligned) { { reg32[reg_eax] = safe_read32s(src); }; } else { { reg32[reg_eax] = safe_read32s(src); }; } if(false) dest += size, regv[reg_vdi] += size; if(true) src += size, regv[reg_vsi] += size; } while(--regv[reg_vcx] && (!false || (data_src === data_dest) === repeat_string_type)); } else { { reg32[reg_eax] = safe_read32s(src); }; if(false) regv[reg_vdi] += size; if(true) regv[reg_vsi] += size; } if(false) cmp32(data_src, data_dest);; |
| } |
| function scasb() |
| { |
| var src, dest, data_src, data_dest; var size = flags & flag_direction ? -(8 >> 3) : 8 >> 3; var ds, es; if(true && !false) data_src = reg8[reg_eax]; if(true) es = get_seg(reg_es), dest = es + regv[reg_vdi]; if(false) ds = get_seg_prefix(reg_ds), src = ds + regv[reg_vsi]; if(repeat_string_prefix) { if(regv[reg_vcx] === 0) return; var aligned = 8 > 8 && (!true || (dest & (8 >> 3) - 1) === 0) && (!false || (src & (8 >> 3) - 1) === 0); do { if(aligned) { {}; } else { { data_dest = safe_read8(dest); }; } if(true) dest += size, regv[reg_vdi] += size; if(false) src += size, regv[reg_vsi] += size; } while(--regv[reg_vcx] && (!true || (data_src === data_dest) === repeat_string_type)); } else { { data_dest = safe_read8(dest); }; if(true) regv[reg_vdi] += size; if(false) regv[reg_vsi] += size; } if(true) cmp8(data_src, data_dest);; |
| } |
| function scasw() |
| { |
| var src, dest, data_src, data_dest; var size = flags & flag_direction ? -(16 >> 3) : 16 >> 3; var ds, es; if(true && !false) data_src = reg16[reg_eax]; if(true) es = get_seg(reg_es), dest = es + regv[reg_vdi]; if(false) ds = get_seg_prefix(reg_ds), src = ds + regv[reg_vsi]; if(repeat_string_prefix) { if(regv[reg_vcx] === 0) return; var aligned = 16 > 8 && (!true || (dest & (16 >> 3) - 1) === 0) && (!false || (src & (16 >> 3) - 1) === 0); do { if(aligned) { { data_dest = memory.read_aligned16(translate_address_read(dest)); }; } else { { data_dest = safe_read16(dest); }; } if(true) dest += size, regv[reg_vdi] += size; if(false) src += size, regv[reg_vsi] += size; } while(--regv[reg_vcx] && (!true || (data_src === data_dest) === repeat_string_type)); } else { { data_dest = safe_read16(dest); }; if(true) regv[reg_vdi] += size; if(false) regv[reg_vsi] += size; } if(true) cmp16(data_src, data_dest);; |
| } |
| function scasd() |
| { |
| var src, dest, data_src, data_dest; var size = flags & flag_direction ? -(32 >> 3) : 32 >> 3; var ds, es; if(true && !false) data_src = reg32[reg_eax]; if(true) es = get_seg(reg_es), dest = es + regv[reg_vdi]; if(false) ds = get_seg_prefix(reg_ds), src = ds + regv[reg_vsi]; if(repeat_string_prefix) { if(regv[reg_vcx] === 0) return; var aligned = 32 > 8 && (!true || (dest & (32 >> 3) - 1) === 0) && (!false || (src & (32 >> 3) - 1) === 0); do { if(aligned) { { data_dest = memory.read_aligned32(translate_address_read(dest)) >>> 0; }; } else { { data_dest = (safe_read32s(dest) >>> 0); }; } if(true) dest += size, regv[reg_vdi] += size; if(false) src += size, regv[reg_vsi] += size; } while(--regv[reg_vcx] && (!true || (data_src === data_dest) === repeat_string_type)); } else { { data_dest = (safe_read32s(dest) >>> 0); }; if(true) regv[reg_vdi] += size; if(false) regv[reg_vsi] += size; } if(true) cmp32(data_src, data_dest);; |
| } |
| function insb() |
| { |
| var port = reg16[reg_dx]; |
| var src, dest, data_src, data_dest; var size = flags & flag_direction ? -(8 >> 3) : 8 >> 3; var ds, es; if(false && !false) data_src = reg8[reg_eax]; if(true) es = get_seg(reg_es), dest = es + regv[reg_vdi]; if(false) ds = get_seg_prefix(reg_ds), src = ds + regv[reg_vsi]; if(repeat_string_prefix) { if(regv[reg_vcx] === 0) return; var aligned = 8 > 8 && (!true || (dest & (8 >> 3) - 1) === 0) && (!false || (src & (8 >> 3) - 1) === 0); do { if(aligned) { { }; } else { { safe_write8(dest, in8(port)); }; } if(true) dest += size, regv[reg_vdi] += size; if(false) src += size, regv[reg_vsi] += size; } while(--regv[reg_vcx] && (!false || (data_src === data_dest) === repeat_string_type)); } else { { safe_write8(dest, in8(port)); }; if(true) regv[reg_vdi] += size; if(false) regv[reg_vsi] += size; } if(false) cmp8(data_src, data_dest);; |
| } |
| function insw() |
| { |
| var port = reg16[reg_dx]; |
| var src, dest, data_src, data_dest; var size = flags & flag_direction ? -(8 >> 3) : 8 >> 3; var ds, es; if(false && !false) data_src = reg8[reg_eax]; if(true) es = get_seg(reg_es), dest = es + regv[reg_vdi]; if(false) ds = get_seg_prefix(reg_ds), src = ds + regv[reg_vsi]; if(repeat_string_prefix) { if(regv[reg_vcx] === 0) return; var aligned = 8 > 8 && (!true || (dest & (8 >> 3) - 1) === 0) && (!false || (src & (8 >> 3) - 1) === 0); do { if(aligned) { { var phys_dest = translate_address_write(dest); memory.write_aligned16(phys_dest, in16(port)); }; } else { { safe_write16(dest, in16(port)); }; } if(true) dest += size, regv[reg_vdi] += size; if(false) src += size, regv[reg_vsi] += size; } while(--regv[reg_vcx] && (!false || (data_src === data_dest) === repeat_string_type)); } else { { safe_write16(dest, in16(port)); }; if(true) regv[reg_vdi] += size; if(false) regv[reg_vsi] += size; } if(false) cmp8(data_src, data_dest);; |
| } |
| function insd() |
| { |
| var port = reg16[reg_dx]; |
| var src, dest, data_src, data_dest; var size = flags & flag_direction ? -(32 >> 3) : 32 >> 3; var ds, es; if(false && !false) data_src = reg32[reg_eax]; if(true) es = get_seg(reg_es), dest = es + regv[reg_vdi]; if(false) ds = get_seg_prefix(reg_ds), src = ds + regv[reg_vsi]; if(repeat_string_prefix) { if(regv[reg_vcx] === 0) return; var aligned = 32 > 8 && (!true || (dest & (32 >> 3) - 1) === 0) && (!false || (src & (32 >> 3) - 1) === 0); do { if(aligned) { { var phys_dest = translate_address_write(dest); memory.write_aligned32(phys_dest, in32(port)); }; } else { { safe_write32(dest, in32(port)); }; } if(true) dest += size, regv[reg_vdi] += size; if(false) src += size, regv[reg_vsi] += size; } while(--regv[reg_vcx] && (!false || (data_src === data_dest) === repeat_string_type)); } else { { safe_write32(dest, in32(port)); }; if(true) regv[reg_vdi] += size; if(false) regv[reg_vsi] += size; } if(false) cmp32(data_src, data_dest);; |
| } |
| function outsb() |
| { |
| var port = reg16[reg_dx]; |
| var src, dest, data_src, data_dest; var size = flags & flag_direction ? -(8 >> 3) : 8 >> 3; var ds, es; if(false && !true) data_src = reg8[reg_eax]; if(false) es = get_seg(reg_es), dest = es + regv[reg_vdi]; if(true) ds = get_seg_prefix(reg_ds), src = ds + regv[reg_vsi]; if(repeat_string_prefix) { if(regv[reg_vcx] === 0) return; var aligned = 8 > 8 && (!false || (dest & (8 >> 3) - 1) === 0) && (!true || (src & (8 >> 3) - 1) === 0); do { if(aligned) { { out8(port, safe_read8(src)); }; } else { { out8(port, safe_read8(src)); }; } if(false) dest += size, regv[reg_vdi] += size; if(true) src += size, regv[reg_vsi] += size; } while(--regv[reg_vcx] && (!false || (data_src === data_dest) === repeat_string_type)); } else { { out8(port, safe_read8(src)); }; if(false) regv[reg_vdi] += size; if(true) regv[reg_vsi] += size; } if(false) cmp8(data_src, data_dest);; |
| } |
| function outsw() |
| { |
| var port = reg16[reg_dx]; |
| var src, dest, data_src, data_dest; var size = flags & flag_direction ? -(16 >> 3) : 16 >> 3; var ds, es; if(false && !true) data_src = reg16[reg_eax]; if(false) es = get_seg(reg_es), dest = es + regv[reg_vdi]; if(true) ds = get_seg_prefix(reg_ds), src = ds + regv[reg_vsi]; if(repeat_string_prefix) { if(regv[reg_vcx] === 0) return; var aligned = 16 > 8 && (!false || (dest & (16 >> 3) - 1) === 0) && (!true || (src & (16 >> 3) - 1) === 0); do { if(aligned) { { out16(port, safe_read16(src)); }; } else { { out16(port, safe_read16(src)); }; } if(false) dest += size, regv[reg_vdi] += size; if(true) src += size, regv[reg_vsi] += size; } while(--regv[reg_vcx] && (!false || (data_src === data_dest) === repeat_string_type)); } else { { out16(port, safe_read16(src)); }; if(false) regv[reg_vdi] += size; if(true) regv[reg_vsi] += size; } if(false) cmp16(data_src, data_dest);; |
| } |
| function outsd() |
| { |
| var port = reg16[reg_dx]; |
| var src, dest, data_src, data_dest; var size = flags & flag_direction ? -(32 >> 3) : 32 >> 3; var ds, es; if(false && !true) data_src = reg32[reg_eax]; if(false) es = get_seg(reg_es), dest = es + regv[reg_vdi]; if(true) ds = get_seg_prefix(reg_ds), src = ds + regv[reg_vsi]; if(repeat_string_prefix) { if(regv[reg_vcx] === 0) return; var aligned = 32 > 8 && (!false || (dest & (32 >> 3) - 1) === 0) && (!true || (src & (32 >> 3) - 1) === 0); do { if(aligned) { { out32(port, safe_read32s(src)); }; } else { { out32(port, safe_read32s(src)); }; } if(false) dest += size, regv[reg_vdi] += size; if(true) src += size, regv[reg_vsi] += size; } while(--regv[reg_vcx] && (!false || (data_src === data_dest) === repeat_string_type)); } else { { out32(port, safe_read32s(src)); }; if(false) regv[reg_vdi] += size; if(true) regv[reg_vsi] += size; } if(false) cmp32(data_src, data_dest);; |
| } |
| "use strict"; |
| /** @const */ |
| var FPU_LOG_OP = true; |
| /** |
| * this behaves as if no x87 fpu existed |
| * @constructor |
| */ |
| function NoFPU(io) |
| { |
| this.is_fpu = 0; |
| //cr0 |= 4; |
| this.fwait = function() |
| { |
| }; |
| this.op_D8_reg = function(imm8) |
| { |
| trigger_ud(); |
| }; |
| this.op_D8_mem = function(imm8, addr) |
| { |
| trigger_ud(); |
| }; |
| this.op_D9_reg = function(imm8) |
| { |
| trigger_ud(); |
| }; |
| this.op_D9_mem = function(imm8, addr) |
| { |
| var mod = imm8 >> 3 & 7; |
| if(mod === 7) |
| { |
| // FNSTCW |
| dbg_log("Unimplemented D9", LOG_FPU); |
| safe_write16(addr, 0); |
| } |
| else |
| { |
| trigger_ud(); |
| } |
| }; |
| this.op_DA = function(imm8) |
| { |
| trigger_ud(); |
| }; |
| this.op_DA_mem = function(imm8, addr) |
| { |
| trigger_ud(); |
| }; |
| this.op_DB_reg = function(imm8) |
| { |
| if(imm8 === 0xE3) |
| { |
| // fninit |
| // don't error, even if no fpu is present |
| dbg_log("Unimplemented DB", LOG_FPU); |
| } |
| else |
| { |
| trigger_ud(); |
| } |
| }; |
| this.op_DB_mem = function(imm8, addr) |
| { |
| trigger_ud(); |
| }; |
| this.op_DC_reg = function(imm8) |
| { |
| trigger_ud(); |
| }; |
| this.op_DC_mem = function(imm8, addr) |
| { |
| trigger_ud(); |
| }; |
| this.op_DD_reg = function(imm8) |
| { |
| trigger_ud(); |
| }; |
| this.op_DD_mem = function(imm8, addr) |
| { |
| var mod = imm8 >> 3 & 7; |
| switch(mod) |
| { |
| case 7: |
| // fnstsw / store status word |
| // no fpu -> write nonzero |
| dbg_log("Unimplemented DD", LOG_FPU); |
| safe_write16(addr, 1); |
| break; |
| default: |
| trigger_ud(); |
| } |
| }; |
| this.op_DE_reg = function(imm8) |
| { |
| trigger_ud(); |
| }; |
| this.op_DE_mem = function(imm8, addr) |
| { |
| trigger_ud(); |
| }; |
| this.op_DF_reg = function(imm8) |
| { |
| if(imm8 === 0xE0) |
| { |
| // fnstsw |
| // no fpu -> write nonzero |
| dbg_log("Unimplemented DF", LOG_FPU); |
| reg16[reg_ax] = 1; |
| } |
| else |
| { |
| trigger_ud(); |
| } |
| }; |
| this.op_DF_mem = function(imm8, addr) |
| { |
| trigger_ud(); |
| }; |
| } |
| /** |
| * @constructor |
| */ |
| function FPU(io) |
| { |
| this.is_fpu = 1; |
| // TODO: |
| // - Precision Control |
| // - QNaN, unordered comparison |
| // - Exceptions |
| var |
| /** @const */ |
| C0 = 0x100, |
| /** @const */ |
| C1 = 0x200, |
| /** @const */ |
| C2 = 0x400, |
| /** @const */ |
| C3 = 0x4000, |
| /** @const */ |
| RESULT_FLAGS = C0 | C1 | C2 | C3, |
| /** @const */ |
| STACK_TOP = 0x3800; |
| var |
| // precision, round & infinity control |
| /** @const */ |
| PC = 3 << 8, |
| /** @const */ |
| RC = 3 << 10, |
| /** @const */ |
| IF = 1 << 12; |
| // exception bits in the status word |
| var EX_SF = 1 << 6, |
| EX_P = 1 << 5, |
| EX_U = 1 << 4, |
| EX_O = 1 << 3, |
| EX_Z = 1 << 2, |
| EX_D = 1 << 1, |
| EX_I = 1 << 0; |
| var |
| // Why no Float80Array :-( |
| st = new Float64Array(8), |
| st8 = new Uint8Array(st.buffer), |
| st32 = new Uint32Array(st.buffer), |
| // bitmap of which stack registers are empty |
| stack_empty = 0xff, |
| stack_ptr = 0, |
| // used for conversion |
| float32 = new Float32Array(1), |
| float32_byte = new Uint8Array(float32.buffer), |
| float32_int = new Uint32Array(float32.buffer), |
| float64 = new Float64Array(1), |
| float64_byte = new Uint8Array(float64.buffer), |
| float64_int = new Uint32Array(float64.buffer), |
| float80_int = new Uint8Array(10), |
| control_word = 0x37F, |
| status_word = 0, |
| fpu_ip = 0, |
| fpu_ip_selector = 0, |
| fpu_opcode = 0, |
| fpu_dp = 0, |
| fpu_dp_selector = 0, |
| /** @const */ |
| indefinite_nan = NaN; |
| var constants = new Float64Array([ |
| 1, Math.log(10) / Math.LN2, Math.LOG2E, Math.PI, |
| Math.log(2) / Math.LN10, Math.LN2, 0 |
| ]); |
| function fpu_unimpl() |
| { |
| dbg_trace(); |
| if(DEBUG) throw "fpu: unimplemented"; |
| else trigger_ud(); |
| } |
| function stack_fault() |
| { |
| // TODO: Interrupt |
| status_word |= EX_SF | EX_I; |
| } |
| function invalid_arithmatic() |
| { |
| status_word |= EX_I; |
| } |
| function fcom(y) |
| { |
| var x = get_st0(); |
| status_word &= ~RESULT_FLAGS; |
| if(x > y) |
| { |
| } |
| else if(y > x) |
| { |
| status_word |= C0; |
| } |
| else if(x === y) |
| { |
| status_word |= C3; |
| } |
| else |
| { |
| status_word |= C0 | C2 | C3; |
| } |
| } |
| function fucom(y) |
| { |
| // TODO |
| fcom(y); |
| } |
| function fcomi(y) |
| { |
| var x = st[stack_ptr]; |
| flags_changed &= ~(1 | flag_parity | flag_zero); |
| flags &= ~(1 | flag_parity | flag_zero); |
| if(x > y) |
| { |
| } |
| else if(y > x) |
| { |
| flags |= 1; |
| } |
| else if(x === y) |
| { |
| flags |= flag_zero; |
| } |
| else |
| { |
| flags |= 1 | flag_parity | flag_zero; |
| } |
| } |
| function fucomi(y) |
| { |
| // TODO |
| fcomi(y); |
| } |
| function ftst() |
| { |
| var st0 = get_st0(); |
| status_word &= ~RESULT_FLAGS; |
| if(isNaN(st0)) |
| { |
| status_word |= C3 | C2 | C0; |
| } |
| else if(st0 === 0) |
| { |
| status_word |= C3; |
| } |
| else if(st0 < 0) |
| { |
| status_word |= C0; |
| } |
| // TODO: unordered (st0 is nan, etc) |
| } |
| function fxam() |
| { |
| var x = get_st0(); |
| status_word &= ~RESULT_FLAGS; |
| status_word |= sign(0) << 9; |
| if(stack_empty >> stack_ptr & 1) |
| { |
| status_word |= C3 | C0; |
| } |
| else if(isNaN(x)) |
| { |
| status_word |= C0; |
| } |
| else if(x === 0) |
| { |
| status_word |= C3; |
| } |
| else if(x === Infinity || x === -Infinity) |
| { |
| status_word |= C2 | C0; |
| } |
| else |
| { |
| status_word |= C2; |
| } |
| // TODO: |
| // Unsupported, Denormal |
| } |
| function finit() |
| { |
| control_word = 0x37F; |
| status_word = 0; |
| fpu_ip = 0; |
| fpu_dp = 0; |
| fpu_opcode = 0; |
| stack_empty = 0xFF; |
| stack_ptr = 0; |
| } |
| function load_status_word() |
| { |
| return status_word & ~(7 << 11) | stack_ptr << 11; |
| } |
| function safe_status_word(sw) |
| { |
| status_word = sw & ~(7 << 11); |
| stack_ptr = sw >> 11 & 7; |
| } |
| function load_tag_word() |
| { |
| var tag_word = 0, |
| value; |
| for(var i = 0; i < 8; i++) |
| { |
| value = st[i]; |
| if(stack_empty >> i & 1) |
| { |
| tag_word |= 3 << (i << 1); |
| } |
| else if(value === 0) |
| { |
| tag_word |= 1 << (i << 1); |
| } |
| else if(isNaN(value) || value === Infinity || value === -Infinity) |
| { |
| tag_word |= 2 << (i << 1); |
| } |
| } |
| //dbg_log("load tw=" + h(tag_word) + " se=" + h(stack_empty) + " sp=" + stack_ptr, LOG_FPU); |
| return tag_word; |
| } |
| function safe_tag_word(tag_word) |
| { |
| stack_empty = 0; |
| for(var 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(stack_empty), LOG_FPU); |
| } |
| function fstenv(addr) |
| { |
| if(operand_size_32) |
| { |
| safe_write16(addr, control_word); |
| safe_write16(addr + 4, load_status_word()); |
| safe_write16(addr + 8, load_tag_word()); |
| safe_write32(addr + 12, fpu_ip); |
| safe_write16(addr + 16, fpu_ip_selector); |
| safe_write16(addr + 18, fpu_opcode); |
| safe_write32(addr + 20, fpu_dp); |
| safe_write16(addr + 24, fpu_dp_selector); |
| } |
| else |
| { |
| fpu_unimpl(); |
| } |
| } |
| function fldenv(addr) |
| { |
| if(operand_size_32) |
| { |
| control_word = safe_read16(addr); |
| safe_status_word(safe_read16(addr + 4)); |
| safe_tag_word(safe_read16(addr + 8)); |
| fpu_ip = (safe_read32s(addr + 12) >>> 0); |
| fpu_ip_selector = safe_read16(addr + 16); |
| fpu_opcode = safe_read16(addr + 18); |
| fpu_dp = (safe_read32s(addr + 20) >>> 0); |
| fpu_dp_selector = safe_read16(addr + 24); |
| } |
| else |
| { |
| fpu_unimpl(); |
| } |
| } |
| function fsave(addr) |
| { |
| fstenv(addr); |
| addr += 28; |
| for(var i = 0; i < 8; i++) |
| { |
| store_m80(addr, i - stack_ptr & 7); |
| addr += 10; |
| } |
| //dbg_log("save " + [].slice.call(st), LOG_FPU); |
| finit(); |
| } |
| function frstor(addr) |
| { |
| fldenv(addr); |
| addr += 28; |
| for(var i = 0; i < 8; i++) |
| { |
| st[i] = load_m80(addr); |
| addr += 10; |
| } |
| //dbg_log("rstor " + [].slice.call(st), LOG_FPU); |
| } |
| function integer_round(f) |
| { |
| var rc = control_word >> 10 & 3; |
| if(rc === 0) |
| { |
| // Round to nearest, or even if equidistant |
| var rounded = Math.round(f); |
| if(rounded - f === 0.5 && (rounded & 1)) |
| { |
| // Special case: Math.round rounds to positive infinity |
| // if equidistant |
| rounded--; |
| } |
| return rounded; |
| } |
| // rc=3 is truncate -> floor for positive numbers |
| else if(rc === 1 || (rc === 3 && f > 0)) |
| { |
| return Math.floor(f); |
| } |
| else |
| { |
| return Math.ceil(f); |
| } |
| } |
| function truncate(x) |
| { |
| return x > 0 ? Math.floor(x) : Math.ceil(x); |
| } |
| function push(x) |
| { |
| stack_ptr = stack_ptr - 1 & 7; |
| if(stack_empty >> stack_ptr & 1) |
| { |
| status_word &= ~C1; |
| stack_empty &= ~(1 << stack_ptr); |
| st[stack_ptr] = x; |
| } |
| else |
| { |
| status_word |= C1; |
| stack_fault(); |
| st[stack_ptr] = indefinite_nan; |
| } |
| } |
| function pop() |
| { |
| stack_empty |= 1 << stack_ptr; |
| stack_ptr = stack_ptr + 1 & 7; |
| } |
| function get_sti(i) |
| { |
| dbg_assert(typeof i === "number" && i >= 0 && i < 8); |
| i = i + stack_ptr & 7; |
| if(stack_empty >> i & 1) |
| { |
| status_word &= ~C1; |
| stack_fault(); |
| return indefinite_nan; |
| } |
| else |
| { |
| return st[i]; |
| } |
| } |
| function get_st0() |
| { |
| if(stack_empty >> stack_ptr & 1) |
| { |
| status_word &= ~C1; |
| stack_fault(); |
| return indefinite_nan; |
| } |
| else |
| { |
| return st[stack_ptr]; |
| } |
| } |
| function assert_not_empty(i) |
| { |
| if(stack_empty >> (i + stack_ptr & 7) & 1) |
| { |
| status_word &= ~C1; |
| } |
| else |
| { |
| } |
| } |
| function load_m80(addr) |
| { |
| var exponent = safe_read16(addr + 8), |
| sign, |
| low = (safe_read32s(addr) >>> 0), |
| high = (safe_read32s(addr + 4) >>> 0); |
| sign = exponent >> 15; |
| exponent &= ~0x8000; |
| if(exponent === 0) |
| { |
| // TODO: denormal numbers |
| return 0; |
| } |
| if(exponent < 0x7FFF) |
| { |
| exponent -= 0x3FFF; |
| } |
| else |
| { |
| // TODO: NaN, Infinity |
| //dbg_log("Load m80 TODO", LOG_FPU); |
| float64_byte[7] = 0x7F | sign << 7; |
| float64_byte[6] = 0xF0 | high >> 30 << 3 & 0x08; |
| float64_byte[5] = 0; |
| float64_byte[4] = 0; |
| float64_int[0] = 0; |
| return float64[0]; |
| } |
| // Note: some bits might be lost at this point |
| var mantissa = low + 0x100000000 * high; |
| if(sign) |
| { |
| mantissa = -mantissa; |
| } |
| //console.log("m: " + mantissa); |
| //console.log("e: " + exponent); |
| //console.log("s: " + sign); |
| //console.log("f: " + mantissa * Math.pow(2, exponent - 63)); |
| // Simply compute the 64 bit floating point number. |
| // An alternative write the mantissa, sign and exponent in the |
| // float64_byte and return float64[0] |
| return mantissa * Math.pow(2, exponent - 63); |
| } |
| function store_m80(addr, i) |
| { |
| float64[0] = st[stack_ptr + i & 7]; |
| var sign = float64_byte[7] & 0x80, |
| exponent = (float64_byte[7] & 0x7f) << 4 | float64_byte[6] >> 4, |
| low, |
| high; |
| if(exponent === 0x7FF) |
| { |
| // all bits set (NaN and infinity) |
| exponent = 0x7FFF; |
| low = 0; |
| high = 0x80000000 | (float64_int[1] & 0x80000) << 11; |
| } |
| else if(exponent === 0) |
| { |
| // zero and denormal numbers |
| // Just assume zero for now |
| low = 0; |
| high = 0; |
| } |
| else |
| { |
| exponent += 0x3FFF - 0x3FF; |
| // does the mantissa need to be adjusted? |
| low = float64_int[0] << 11; |
| high = 0x80000000 | (float64_int[1] & 0xFFFFF) << 11 | (float64_int[0] >>> 21); |
| } |
| dbg_assert(exponent >= 0 && exponent < 0x8000); |
| safe_write32(addr, low); |
| safe_write32(addr + 4, high); |
| safe_write16(addr + 8, sign << 8 | exponent); |
| } |
| function load_m64(addr) |
| { |
| float64_int[0] = safe_read32s(addr); |
| float64_int[1] = safe_read32s(addr + 4); |
| return float64[0]; |
| }; |
| function store_m64(addr, i) |
| { |
| // protect against writing only a single dword |
| // and then page-faulting |
| translate_address_write(addr + 7); |
| float64[0] = get_sti(i); |
| safe_write32(addr, float64_int[0]); |
| safe_write32(addr + 4, float64_int[1]); |
| }; |
| function load_m32(addr) |
| { |
| float32_int[0] = safe_read32s(addr); |
| return float32[0]; |
| }; |
| function store_m32(addr, i) |
| { |
| float32[0] = get_sti(i); |
| safe_write32(addr, float32_int[0]); |
| }; |
| // sign of a number on the stack |
| function sign(i) |
| { |
| return st8[(stack_ptr + i & 7) << 3 | 7] >> 7; |
| }; |
| function dbg_log_fpu_op(op, imm8) |
| { |
| if(!FPU_LOG_OP) |
| { |
| return; |
| } |
| if(imm8 >= 0xC0) |
| { |
| dbg_log(h(op, 2) + " " + h(imm8, 2) + "/" + (imm8 >> 3 & 7) + "/" + (imm8 & 7) + |
| " @" + h(instruction_pointer, 8) + " sp=" + stack_ptr + " st=" + h(stack_empty, 2), LOG_FPU); |
| } |
| else |
| { |
| dbg_log(h(op, 2) + " /" + (imm8 >> 3 & 7) + |
| " @" + h(instruction_pointer, 8) + " sp=" + stack_ptr + " st=" + h(stack_empty, 2), LOG_FPU); |
| } |
| } |
| this.fwait = function() |
| { |
| // TODO: |
| // Exceptions |
| }; |
| this.op_D8_reg = function(imm8) |
| { |
| dbg_log_fpu_op(0xD8, imm8); |
| var mod = imm8 >> 3 & 7, |
| low = imm8 & 7, |
| sti = get_sti(low), |
| st0 = get_st0(); |
| switch(mod) |
| { |
| case 0: |
| // fadd |
| st[stack_ptr] = st0 + sti; |
| break; |
| case 1: |
| // fmul |
| st[stack_ptr] = st0 * sti; |
| break; |
| case 2: |
| // fcom |
| fcom(sti); |
| break; |
| case 3: |
| // fcomp |
| fcom(sti); |
| pop(); |
| break; |
| case 4: |
| // fsub |
| st[stack_ptr] = st0 - sti; |
| break; |
| case 5: |
| // fsubr |
| st[stack_ptr] = sti - st0; |
| break; |
| case 6: |
| // fdiv |
| st[stack_ptr] = st0 / sti; |
| break; |
| case 7: |
| // fdivr |
| st[stack_ptr] = sti / st0; |
| break; |
| default: |
| dbg_log(mod); |
| fpu_unimpl(); |
| } |
| }; |
| this.op_D8_mem = function(imm8, addr) |
| { |
| dbg_log_fpu_op(0xD8, imm8); |
| var mod = imm8 >> 3 & 7, |
| m32 = load_m32(addr); |
| var st0 = get_st0(); |
| switch(mod) |
| { |
| case 0: |
| // fadd |
| st[stack_ptr] = st0 + m32; |
| break; |
| case 1: |
| // fmul |
| st[stack_ptr] = st0 * m32; |
| break; |
| case 2: |
| // fcom |
| fcom(m32); |
| break; |
| case 3: |
| // fcomp |
| fcom(m32); |
| pop(); |
| break; |
| case 4: |
| // fsub |
| st[stack_ptr] = st0 - m32; |
| break; |
| case 5: |
| // fsubr |
| st[stack_ptr] = m32 - st0; |
| break; |
| case 6: |
| // fdiv |
| st[stack_ptr] = st0 / m32; |
| break; |
| case 7: |
| // fdivr |
| st[stack_ptr] = m32 / st0; |
| break; |
| default: |
| dbg_log(mod); |
| fpu_unimpl(); |
| } |
| }; |
| this.op_D9_reg = function(imm8) |
| { |
| dbg_log_fpu_op(0xD9, imm8); |
| var mod = imm8 >> 3 & 7, |
| low = imm8 & 7; |
| switch(mod) |
| { |
| case 0: |
| // fld |
| var sti = get_sti(low); |
| push(sti); |
| break; |
| case 1: |
| // fxch |
| var sti = get_sti(low); |
| st[stack_ptr + low & 7] = get_st0(); |
| st[stack_ptr] = sti; |
| break; |
| case 4: |
| switch(low) |
| { |
| case 0: |
| // fchs |
| st[stack_ptr] = -get_st0(); |
| break; |
| case 1: |
| // fabs |
| st[stack_ptr] = Math.abs(get_st0()); |
| break; |
| case 4: |
| ftst(); |
| break; |
| case 5: |
| fxam(); |
| break; |
| default: |
| dbg_log(low); fpu_unimpl(); |
| } |
| break; |
| case 5: |
| push(constants[low]); |
| break; |
| case 6: |
| switch(low) |
| { |
| case 0: |
| // f2xm1 |
| st[stack_ptr] = Math.pow(2, get_st0()) - 1; |
| break; |
| case 1: |
| // fyl2x |
| st[stack_ptr + 1 & 7] = get_sti(1) * Math.log(get_st0()) / Math.LN2; |
| pop(); |
| break; |
| case 2: |
| // fptan |
| st[stack_ptr] = Math.tan(get_st0()); |
| push(1); // no bug: push constant 1 |
| break; |
| case 3: |
| // fpatan |
| //st[stack_ptr + 1 & 7] = Math.atan(get_sti(1) / get_st0()); |
| st[stack_ptr + 1 & 7] = Math.atan2(get_sti(1), get_st0()); |
| pop(); |
| break; |
| case 5: |
| // fprem1 |
| st[stack_ptr] = get_st0() % get_sti(1); |
| break; |
| default: |
| dbg_log(low); fpu_unimpl(); |
| } |
| break; |
| case 7: |
| switch(low) |
| { |
| case 0: |
| // fprem |
| st[stack_ptr] = get_st0() % get_sti(1); |
| break; |
| case 2: |
| st[stack_ptr] = Math.sqrt(get_st0()); |
| break; |
| case 3: |
| var st0 = get_st0(); |
| st[stack_ptr] = Math.sin(st0); |
| push(Math.cos(st0)); |
| break; |
| case 4: |
| // frndint |
| st[stack_ptr] = integer_round(get_st0()); |
| break; |
| case 5: |
| // fscale |
| st[stack_ptr] = get_st0() * Math.pow(2, truncate(get_sti(1))); |
| break; |
| case 6: |
| st[stack_ptr] = Math.sin(get_st0()); |
| break; |
| case 7: |
| st[stack_ptr] = Math.cos(get_st0()); |
| break; |
| default: |
| dbg_log(low); fpu_unimpl(); |
| } |
| break; |
| default: |
| dbg_log(mod); |
| fpu_unimpl(); |
| } |
| }; |
| this.op_D9_mem = function(imm8, addr) |
| { |
| dbg_log_fpu_op(0xD9, imm8); |
| var mod = imm8 >> 3 & 7; |
| switch(mod) |
| { |
| case 0: |
| var data = load_m32(addr); |
| push(data); |
| break; |
| case 2: |
| store_m32(addr, 0); |
| break; |
| case 3: |
| store_m32(addr, 0); |
| pop(); |
| break; |
| case 4: |
| fldenv(addr); |
| break; |
| case 5: |
| var word = safe_read16(addr); |
| control_word = word; |
| break; |
| case 6: |
| fstenv(addr); |
| break; |
| case 7: |
| safe_write16(addr, control_word); |
| break; |
| default: |
| dbg_log(mod); |
| fpu_unimpl(); |
| } |
| }; |
| this.op_DA_reg = function(imm8) |
| { |
| dbg_log_fpu_op(0xDA, imm8); |
| var mod = imm8 >> 3 & 7, |
| low = imm8 & 7; |
| switch(mod) |
| { |
| case 0: |
| // fcmovb |
| if(test_b()) |
| { |
| st[stack_ptr] = get_sti(low); |
| stack_empty &= ~(1 << stack_ptr); |
| } |
| break; |
| case 1: |
| // fcmove |
| if(test_z()) |
| { |
| st[stack_ptr] = get_sti(low); |
| stack_empty &= ~(1 << stack_ptr); |
| } |
| break; |
| case 2: |
| // fcmovbe |
| if(test_be()) |
| { |
| st[stack_ptr] = get_sti(low); |
| stack_empty &= ~(1 << stack_ptr); |
| } |
| break; |
| case 3: |
| // fcmovu |
| if(test_p()) |
| { |
| st[stack_ptr] = get_sti(low); |
| stack_empty &= ~(1 << stack_ptr); |
| } |
| break; |
| case 5: |
| if(low === 1) |
| { |
| // fucompp |
| fucom(get_sti(1)); |
| pop(); |
| pop(); |
| } |
| else |
| { |
| dbg_log(mod); fpu_unimpl(); |
| } |
| break; |
| default: |
| dbg_log(mod); |
| fpu_unimpl(); |
| } |
| }; |
| this.op_DA_mem = function(imm8, addr) |
| { |
| dbg_log_fpu_op(0xDA, imm8); |
| var mod = imm8 >> 3 & 7, |
| m32 = safe_read32s(addr); |
| var st0 = get_st0(); |
| switch(mod) |
| { |
| case 0: |
| // fadd |
| st[stack_ptr] = st0 + m32; |
| break; |
| case 1: |
| // fmul |
| st[stack_ptr] = st0 * m32; |
| break; |
| case 2: |
| // fcom |
| fcom(m32); |
| break; |
| case 3: |
| // fcomp |
| fcom(m32); |
| pop(); |
| break; |
| case 4: |
| // fsub |
| st[stack_ptr] = st0 - m32; |
| break; |
| case 5: |
| // fsubr |
| st[stack_ptr] = m32 - st0; |
| break; |
| case 6: |
| // fdiv |
| st[stack_ptr] = st0 / m32; |
| break; |
| case 7: |
| // fdivr |
| st[stack_ptr] = m32 / st0; |
| break; |
| default: |
| dbg_log(mod); |
| fpu_unimpl(); |
| } |
| }; |
| this.op_DB_reg = function(imm8) |
| { |
| dbg_log_fpu_op(0xDB, imm8); |
| var mod = imm8 >> 3 & 7, |
| low = imm8 & 7; |
| switch(mod) |
| { |
| case 0: |
| // fcmovnb |
| if(!test_b()) |
| { |
| st[stack_ptr] = get_sti(low); |
| stack_empty &= ~(1 << stack_ptr); |
| } |
| break; |
| case 1: |
| // fcmovne |
| if(!test_z()) |
| { |
| st[stack_ptr] = get_sti(low); |
| stack_empty &= ~(1 << stack_ptr); |
| } |
| break; |
| case 2: |
| // fcmovnbe |
| if(!test_be()) |
| { |
| st[stack_ptr] = get_sti(low); |
| stack_empty &= ~(1 << stack_ptr); |
| } |
| break; |
| case 3: |
| // fcmovnu |
| if(!test_p()) |
| { |
| st[stack_ptr] = get_sti(low); |
| stack_empty &= ~(1 << stack_ptr); |
| } |
| break; |
| case 4: |
| if(imm8 === 0xE3) |
| { |
| finit(); |
| } |
| else if(imm8 === 0xE4) |
| { |
| // fsetpm |
| // treat as nop |
| } |
| else |
| { |
| fpu_unimpl(); |
| } |
| break; |
| case 5: |
| fucomi(get_sti(low)); |
| break; |
| case 6: |
| fcomi(get_sti(low)); |
| break; |
| default: |
| dbg_log(mod); |
| fpu_unimpl(); |
| } |
| }; |
| this.op_DB_mem = function(imm8, addr) |
| { |
| dbg_log_fpu_op(0xDB, imm8); |
| var mod = imm8 >> 3 & 7; |
| switch(mod) |
| { |
| case 0: |
| // fild |
| var int32 = safe_read32s(addr); |
| push(int32); |
| break; |
| case 2: |
| // fist |
| var st0 = get_st0(); |
| if(isNaN(st0) || st0 > 0x7FFFFFFF || st0 < -0x80000000) |
| { |
| invalid_arithmatic(); |
| safe_write32(addr, 0x80000000); |
| } |
| else |
| { |
| // TODO: Invalid operation |
| safe_write32(addr, integer_round(st0)); |
| } |
| break; |
| case 3: |
| // fistp |
| var st0 = get_st0(); |
| if(isNaN(st0) || st0 > 0x7FFFFFFF || st0 < -0x80000000) |
| { |
| invalid_arithmatic(); |
| safe_write32(addr, 0x80000000); |
| } |
| else |
| { |
| safe_write32(addr, integer_round(st0)); |
| } |
| pop(); |
| break; |
| case 5: |
| // fld |
| push(load_m80(addr)); |
| break; |
| case 7: |
| // fstp |
| store_m80(addr, 0); |
| pop(); |
| break; |
| default: |
| dbg_log(mod); |
| fpu_unimpl(); |
| } |
| }; |
| this.op_DC_reg = function(imm8) |
| { |
| dbg_log_fpu_op(0xDC, imm8); |
| var mod = imm8 >> 3 & 7, |
| low = imm8 & 7, |
| low_ptr = stack_ptr + low & 7, |
| sti = get_sti(low), |
| st0 = get_st0(); |
| switch(mod) |
| { |
| case 0: |
| // fadd |
| st[low_ptr] = sti + st0; |
| break; |
| case 1: |
| // fmul |
| st[low_ptr] = sti * st0; |
| break; |
| case 2: |
| // fcom |
| fcom(sti); |
| break; |
| case 3: |
| // fcomp |
| fcom(sti); |
| pop(); |
| break; |
| case 4: |
| // fsubr |
| st[low_ptr] = st0 - sti; |
| break; |
| case 5: |
| // fsub |
| st[low_ptr] = sti - st0; |
| break; |
| case 6: |
| // fdivr |
| st[low_ptr] = st0 / sti; |
| break; |
| case 7: |
| // fdiv |
| st[low_ptr] = sti / st0; |
| break; |
| default: |
| dbg_log(mod); |
| fpu_unimpl(); |
| } |
| }; |
| this.op_DC_mem = function(imm8, addr) |
| { |
| dbg_log_fpu_op(0xDC, imm8); |
| var |
| mod = imm8 >> 3 & 7, |
| m64 = load_m64(addr); |
| var st0 = get_st0(); |
| switch(mod) |
| { |
| case 0: |
| // fadd |
| st[stack_ptr] = st0 + m64; |
| break; |
| case 1: |
| // fmul |
| st[stack_ptr] = st0 * m64; |
| break; |
| case 2: |
| // fcom |
| fcom(m64); |
| break; |
| case 3: |
| // fcomp |
| fcom(m64); |
| pop(); |
| break; |
| case 4: |
| // fsub |
| st[stack_ptr] = st0 - m64; |
| break; |
| case 5: |
| // fsubr |
| st[stack_ptr] = m64 - st0; |
| break; |
| case 6: |
| // fdiv |
| st[stack_ptr] = st0 / m64; |
| break; |
| case 7: |
| // fdivr |
| st[stack_ptr] = m64 / st0; |
| break; |
| default: |
| dbg_log(mod); |
| fpu_unimpl(); |
| } |
| }; |
| this.op_DD_reg = function(imm8) |
| { |
| dbg_log_fpu_op(0xDD, imm8); |
| var mod = imm8 >> 3 & 7, |
| low = imm8 & 7; |
| switch(mod) |
| { |
| case 0: |
| // ffree |
| stack_empty |= 1 << (stack_ptr + low & 7); |
| break; |
| case 2: |
| // fst |
| st[stack_ptr + low & 7] = get_st0(); |
| break; |
| case 3: |
| // fstp |
| if(low === 0) |
| { |
| pop(); |
| } |
| else |
| { |
| st[stack_ptr + low & 7] = get_st0(); |
| pop(); |
| } |
| break; |
| case 4: |
| fucom(get_sti(low)); |
| break; |
| case 5: |
| // fucomp |
| fucom(get_sti(low)); |
| pop(); |
| break; |
| default: |
| dbg_log(mod); |
| fpu_unimpl(); |
| } |
| }; |
| this.op_DD_mem = function(imm8, addr) |
| { |
| dbg_log_fpu_op(0xDD, imm8); |
| var mod = imm8 >> 3 & 7; |
| switch(mod) |
| { |
| case 0: |
| // fld |
| var data = load_m64(addr); |
| push(data); |
| break; |
| case 2: |
| // fst |
| store_m64(addr, 0); |
| break; |
| case 3: |
| // fstp |
| store_m64(addr, 0); |
| pop(); |
| break; |
| case 4: |
| frstor(addr); |
| break; |
| case 6: |
| // fsave |
| fsave(addr); |
| break; |
| case 7: |
| // fnstsw / store status word |
| safe_write16(addr, load_status_word()); |
| break; |
| default: |
| dbg_log(mod); |
| fpu_unimpl(); |
| } |
| }; |
| this.op_DE_reg = function(imm8) |
| { |
| dbg_log_fpu_op(0xDE, imm8); |
| var mod = imm8 >> 3 & 7, |
| low = imm8 & 7, |
| low_ptr = stack_ptr + low & 7, |
| sti = get_sti(low), |
| st0 = get_st0(); |
| switch(mod) |
| { |
| case 0: |
| // faddp |
| st[low_ptr] = sti + st0; |
| break; |
| case 1: |
| // fmulp |
| st[low_ptr] = sti * st0; |
| break; |
| case 2: |
| // fcomp |
| fcom(sti); |
| break; |
| case 3: |
| // fcompp |
| if(low === 1) |
| { |
| fcom(st[low_ptr]); |
| pop(); |
| } |
| else |
| { |
| // not a valid encoding |
| dbg_log(mod); |
| fpu_unimpl(); |
| } |
| break; |
| case 4: |
| // fsubrp |
| st[low_ptr] = st0 - sti; |
| break; |
| case 5: |
| // fsubp |
| st[low_ptr] = sti - st0; |
| break; |
| case 6: |
| // fdivrp |
| st[low_ptr] = st0 / sti; |
| break; |
| case 7: |
| // fdivp |
| st[low_ptr] = sti / st0; |
| break; |
| default: |
| dbg_log(mod); |
| fpu_unimpl(); |
| } |
| pop(); |
| }; |
| this.op_DE_mem = function(imm8, addr) |
| { |
| dbg_log_fpu_op(0xDE, imm8); |
| var mod = imm8 >> 3 & 7, |
| m16 = (safe_read16(addr) << 16 >> 16); |
| var st0 = get_st0(); |
| switch(mod) |
| { |
| case 0: |
| // fadd |
| st[stack_ptr] = st0 + m16; |
| break; |
| case 1: |
| // fmul |
| st[stack_ptr] = st0 * m16; |
| break; |
| case 2: |
| // fcom |
| fcom(m16); |
| break; |
| case 3: |
| // fcomp |
| fcom(m16); |
| pop(); |
| break; |
| case 4: |
| // fsub |
| st[stack_ptr] = st0 - m16; |
| break; |
| case 5: |
| // fsubr |
| st[stack_ptr] = m16 - st0; |
| break; |
| case 6: |
| // fdiv |
| st[stack_ptr] = st0 / m16; |
| break; |
| case 7: |
| // fdivr |
| st[stack_ptr] = m16 / st0; |
| break; |
| default: |
| dbg_log(mod); |
| fpu_unimpl(); |
| } |
| }; |
| this.op_DF_reg = function(imm8) |
| { |
| dbg_log_fpu_op(0xDF, imm8); |
| var mod = imm8 >> 3 & 7, |
| low = imm8 & 7; |
| switch(mod) |
| { |
| case 4: |
| if(imm8 === 0xE0) |
| { |
| // fnstsw |
| reg16[reg_ax] = load_status_word(); |
| } |
| else |
| { |
| dbg_log(imm8); |
| fpu_unimpl(); |
| } |
| break; |
| case 5: |
| // fucomip |
| fucomi(get_sti(low)); |
| pop(); |
| break; |
| default: |
| dbg_log(mod); |
| fpu_unimpl(); |
| } |
| }; |
| this.op_DF_mem = function(imm8, addr) |
| { |
| dbg_log_fpu_op(0xDF, imm8); |
| var mod = imm8 >> 3 & 7; |
| switch(mod) |
| { |
| case 0: |
| var m16 = (safe_read16(addr) << 16 >> 16); |
| push(m16); |
| break; |
| case 2: |
| // fist |
| var st0 = get_st0(); |
| if(isNaN(st0) || st0 > 0x7FFF || st0 < -0x8000) |
| { |
| invalid_arithmatic(); |
| safe_write16(addr, 0x8000); |
| } |
| else |
| { |
| safe_write16(addr, integer_round(st0)); |
| } |
| break; |
| case 3: |
| // fistp |
| var st0 = get_st0(); |
| if(isNaN(st0) || st0 > 0x7FFF || st0 < -0x8000) |
| { |
| invalid_arithmatic(); |
| safe_write16(addr, 0x8000); |
| } |
| else |
| { |
| safe_write16(addr, integer_round(st0)); |
| } |
| pop(); |
| break; |
| case 5: |
| // fild |
| var low = (safe_read32s(addr) >>> 0); |
| var high = (safe_read32s(addr + 4) >>> 0); |
| var m64 = low + 0x100000000 * high; |
| if(high >> 31) |
| { |
| m64 -= 0x10000000000000000; |
| } |
| push(m64); |
| break; |
| case 7: |
| // fistp |
| var st0 = integer_round(get_st0()); |
| if(isNaN(st0) || st0 > 0x7FFFFFFFFFFFFFFF || st0 < -0x8000000000000000) |
| { |
| st0 = 0x8000000000000000; |
| invalid_arithmatic(); |
| } |
| pop(); |
| safe_write32(addr, st0); |
| st0 /= 0x100000000; |
| if(st0 < 0 && st0 > -1) |
| st0 = -1; |
| safe_write32(addr + 4, st0); |
| break; |
| default: |
| dbg_log(mod); |
| fpu_unimpl(); |
| } |
| }; |
| } |
| "use strict"; |
| var table16 = [], |
| table32 = [], |
| table0F_16 = [], |
| table0F_32 = []; |
| // no cmp, because it uses different arguments |
| // very special, should be somewhere else? |
| // equivalent to switch(modrm_byte >> 3 & 7) |
| //#define sub_op(i0, i1, i2, i3, i4, i5, i6, i7) // if(modrm_byte & 0x20) { sub_op1(i4, i5, i6, i7) }// else { sub_op1(i0, i1, i2, i3) } |
| // |
| //#define sub_op1(i0, i1, i2, i3)// if(modrm_byte & 0x10) { sub_op2(i2, i3) }// else { sub_op2(i0, i1) } |
| // |
| //#define sub_op2(i0, i1)// if(modrm_byte & 0x08) { i1 }// else { i0 } |
| // use modrm_byte to write a value to memory or register |
| // (without reading it beforehand) |
| // use modrm_byte to write a value to memory or register, |
| // using the previous data from memory or register. |
| // op is a function call that needs to return the result |
| // opcode with modrm byte |
| // opcode that has a 16 and a 32 bit version |
| // instructions start here |
| table16[0x00] = table32[0x00] = function() { var modrm_byte = read_imm8(); { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, add8(data, reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1])); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = add8(data, reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1]); } } }; table16[0x00 | 1] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, add16(data, reg16[modrm_byte >> 2 & 14])); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, add16(data, reg16[modrm_byte >> 2 & 14])); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = add16(data, reg16[modrm_byte >> 2 & 14]); } } }; table32[0x00 | 1] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, add32(data, reg32[modrm_byte >> 3 & 7])); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, add32(data, reg32[modrm_byte >> 3 & 7])); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = add32(data, reg32[modrm_byte >> 3 & 7]); } } }; table16[0x00 | 2] = table32[0x00 | 2] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read8(modrm_resolve(modrm_byte)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; }; reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1] = add8(reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1], data); } }; table16[0x00 | 3] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = add16(reg16[modrm_byte >> 2 & 14], data); } }; table32[0x00 | 3] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = (safe_read32s(modrm_resolve(modrm_byte)) >>> 0); } else { data = reg32[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = add32(reg32[modrm_byte >> 3 & 7], data); } }; table16[0x00 | 4] = table32[0x00 | 4] = function() { { reg8[reg_al] = add8(reg8[reg_al], read_imm8()); } }; table16[0x00 | 5] = function() { { reg16[reg_ax] = add16(reg16[reg_ax], read_imm16()); } }; table32[0x00 | 5] = function() { { reg32[reg_eax] = add32(reg32[reg_eax], (read_imm32s() >>> 0)); } };; |
| table16[0x06] = function() { { push16(sreg[reg_es]); } }; table32[0x06] = function() { { push32(sreg[reg_es]); } };; |
| table16[0x07] = function() { { switch_seg(reg_es, memory.read16(get_esp_read(0))); stack_reg[reg_vsp] += 2; } }; table32[0x07] = function() { { switch_seg(reg_es, memory.read16(get_esp_read(0))); stack_reg[reg_vsp] += 4; } };;; |
| //op2(0x07, |
| // { safe_pop16(sreg[reg_es]); switch_seg(reg_es, memory.read16(get_esp_read(0))); }, |
| // { safe_pop32s(sreg[reg_es]); switch_seg(reg_es); }); |
| table16[0x08] = table32[0x08] = function() { var modrm_byte = read_imm8(); { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, or8(data, reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1])); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = or8(data, reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1]); } } }; table16[0x08 | 1] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, or16(data, reg16[modrm_byte >> 2 & 14])); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, or16(data, reg16[modrm_byte >> 2 & 14])); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = or16(data, reg16[modrm_byte >> 2 & 14]); } } }; table32[0x08 | 1] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high); virt_boundary_write32(phys_addr, phys_addr_high, or32(data, reg32s[modrm_byte >> 3 & 7])); } else { data = memory.read32s(phys_addr); memory.write32(phys_addr, or32(data, reg32s[modrm_byte >> 3 & 7])); } } else { data = reg32s[modrm_byte & 7]; reg32s[modrm_byte & 7] = or32(data, reg32s[modrm_byte >> 3 & 7]); } } }; table16[0x08 | 2] = table32[0x08 | 2] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read8(modrm_resolve(modrm_byte)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; }; reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1] = or8(reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1], data); } }; table16[0x08 | 3] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = or16(reg16[modrm_byte >> 2 & 14], data); } }; table32[0x08 | 3] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = or32(reg32s[modrm_byte >> 3 & 7], data); } }; table16[0x08 | 4] = table32[0x08 | 4] = function() { { reg8[reg_al] = or8(reg8[reg_al], read_imm8()); } }; table16[0x08 | 5] = function() { { reg16[reg_ax] = or16(reg16[reg_ax], read_imm16()); } }; table32[0x08 | 5] = function() { { reg32[reg_eax] = or32(reg32s[reg_eax], read_imm32s()); } };; |
| table16[0x0E] = function() { { push16(sreg[reg_cs]); } }; table32[0x0E] = function() { { push32(sreg[reg_cs]); } };; |
| table16[0x0F] = table32[0x0F] = function() { { table0F[read_imm8()](); } };; |
| table16[0x10] = table32[0x10] = function() { var modrm_byte = read_imm8(); { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, adc8(data, reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1])); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = adc8(data, reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1]); } } }; table16[0x10 | 1] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, adc16(data, reg16[modrm_byte >> 2 & 14])); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, adc16(data, reg16[modrm_byte >> 2 & 14])); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = adc16(data, reg16[modrm_byte >> 2 & 14]); } } }; table32[0x10 | 1] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, adc32(data, reg32[modrm_byte >> 3 & 7])); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, adc32(data, reg32[modrm_byte >> 3 & 7])); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = adc32(data, reg32[modrm_byte >> 3 & 7]); } } }; table16[0x10 | 2] = table32[0x10 | 2] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read8(modrm_resolve(modrm_byte)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; }; reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1] = adc8(reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1], data); } }; table16[0x10 | 3] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = adc16(reg16[modrm_byte >> 2 & 14], data); } }; table32[0x10 | 3] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = (safe_read32s(modrm_resolve(modrm_byte)) >>> 0); } else { data = reg32[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = adc32(reg32[modrm_byte >> 3 & 7], data); } }; table16[0x10 | 4] = table32[0x10 | 4] = function() { { reg8[reg_al] = adc8(reg8[reg_al], read_imm8()); } }; table16[0x10 | 5] = function() { { reg16[reg_ax] = adc16(reg16[reg_ax], read_imm16()); } }; table32[0x10 | 5] = function() { { reg32[reg_eax] = adc32(reg32[reg_eax], (read_imm32s() >>> 0)); } };; |
| table16[0x16] = function() { { push16(sreg[reg_ss]); } }; table32[0x16] = function() { { push32(sreg[reg_ss]); } };; |
| table16[0x17] = function() { { switch_seg(reg_ss, memory.read16(get_esp_read(0))); stack_reg[reg_vsp] += 2; } }; table32[0x17] = function() { { switch_seg(reg_ss, memory.read16(get_esp_read(0))); stack_reg[reg_vsp] += 4; } };;; |
| //op2(0x17, |
| // { safe_pop16(sreg[reg_ss]); switch_seg(reg_ss); }, |
| // { safe_pop32s(sreg[reg_ss]); switch_seg(reg_ss); }); |
| table16[0x18] = table32[0x18] = function() { var modrm_byte = read_imm8(); { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, sbb8(data, reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1])); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = sbb8(data, reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1]); } } }; table16[0x18 | 1] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, sbb16(data, reg16[modrm_byte >> 2 & 14])); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, sbb16(data, reg16[modrm_byte >> 2 & 14])); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = sbb16(data, reg16[modrm_byte >> 2 & 14]); } } }; table32[0x18 | 1] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, sbb32(data, reg32[modrm_byte >> 3 & 7])); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, sbb32(data, reg32[modrm_byte >> 3 & 7])); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = sbb32(data, reg32[modrm_byte >> 3 & 7]); } } }; table16[0x18 | 2] = table32[0x18 | 2] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read8(modrm_resolve(modrm_byte)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; }; reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1] = sbb8(reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1], data); } }; table16[0x18 | 3] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = sbb16(reg16[modrm_byte >> 2 & 14], data); } }; table32[0x18 | 3] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = (safe_read32s(modrm_resolve(modrm_byte)) >>> 0); } else { data = reg32[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = sbb32(reg32[modrm_byte >> 3 & 7], data); } }; table16[0x18 | 4] = table32[0x18 | 4] = function() { { reg8[reg_al] = sbb8(reg8[reg_al], read_imm8()); } }; table16[0x18 | 5] = function() { { reg16[reg_ax] = sbb16(reg16[reg_ax], read_imm16()); } }; table32[0x18 | 5] = function() { { reg32[reg_eax] = sbb32(reg32[reg_eax], (read_imm32s() >>> 0)); } };; |
| table16[0x1E] = function() { { push16(sreg[reg_ds]); } }; table32[0x1E] = function() { { push32(sreg[reg_ds]); } };; |
| table16[0x1F] = function() { { switch_seg(reg_ds, memory.read16(get_esp_read(0))); stack_reg[reg_vsp] += 2; } }; table32[0x1F] = function() { { switch_seg(reg_ds, memory.read16(get_esp_read(0))); stack_reg[reg_vsp] += 4; } };;; |
| //op2(0x1F, |
| // { safe_pop16(sreg[reg_ds]); switch_seg(reg_ds); }, |
| // { safe_pop32s(sreg[reg_ds]); switch_seg(reg_ds); }); |
| table16[0x20] = table32[0x20] = function() { var modrm_byte = read_imm8(); { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, and8(data, reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1])); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = and8(data, reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1]); } } }; table16[0x20 | 1] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, and16(data, reg16[modrm_byte >> 2 & 14])); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, and16(data, reg16[modrm_byte >> 2 & 14])); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = and16(data, reg16[modrm_byte >> 2 & 14]); } } }; table32[0x20 | 1] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high); virt_boundary_write32(phys_addr, phys_addr_high, and32(data, reg32s[modrm_byte >> 3 & 7])); } else { data = memory.read32s(phys_addr); memory.write32(phys_addr, and32(data, reg32s[modrm_byte >> 3 & 7])); } } else { data = reg32s[modrm_byte & 7]; reg32s[modrm_byte & 7] = and32(data, reg32s[modrm_byte >> 3 & 7]); } } }; table16[0x20 | 2] = table32[0x20 | 2] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read8(modrm_resolve(modrm_byte)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; }; reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1] = and8(reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1], data); } }; table16[0x20 | 3] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = and16(reg16[modrm_byte >> 2 & 14], data); } }; table32[0x20 | 3] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = and32(reg32s[modrm_byte >> 3 & 7], data); } }; table16[0x20 | 4] = table32[0x20 | 4] = function() { { reg8[reg_al] = and8(reg8[reg_al], read_imm8()); } }; table16[0x20 | 5] = function() { { reg16[reg_ax] = and16(reg16[reg_ax], read_imm16()); } }; table32[0x20 | 5] = function() { { reg32[reg_eax] = and32(reg32s[reg_eax], read_imm32s()); } };; |
| table16[0x26] = table32[0x26] = function() { { seg_prefix(reg_es); } };; |
| table16[0x27] = table32[0x27] = function() { { bcd_daa(); } };; |
| table16[0x28] = table32[0x28] = function() { var modrm_byte = read_imm8(); { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, sub8(data, reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1])); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = sub8(data, reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1]); } } }; table16[0x28 | 1] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, sub16(data, reg16[modrm_byte >> 2 & 14])); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, sub16(data, reg16[modrm_byte >> 2 & 14])); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = sub16(data, reg16[modrm_byte >> 2 & 14]); } } }; table32[0x28 | 1] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, sub32(data, reg32[modrm_byte >> 3 & 7])); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, sub32(data, reg32[modrm_byte >> 3 & 7])); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = sub32(data, reg32[modrm_byte >> 3 & 7]); } } }; table16[0x28 | 2] = table32[0x28 | 2] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read8(modrm_resolve(modrm_byte)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; }; reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1] = sub8(reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1], data); } }; table16[0x28 | 3] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = sub16(reg16[modrm_byte >> 2 & 14], data); } }; table32[0x28 | 3] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = (safe_read32s(modrm_resolve(modrm_byte)) >>> 0); } else { data = reg32[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = sub32(reg32[modrm_byte >> 3 & 7], data); } }; table16[0x28 | 4] = table32[0x28 | 4] = function() { { reg8[reg_al] = sub8(reg8[reg_al], read_imm8()); } }; table16[0x28 | 5] = function() { { reg16[reg_ax] = sub16(reg16[reg_ax], read_imm16()); } }; table32[0x28 | 5] = function() { { reg32[reg_eax] = sub32(reg32[reg_eax], (read_imm32s() >>> 0)); } };; |
| table16[0x2E] = table32[0x2E] = function() { { seg_prefix(reg_cs); } };; |
| table16[0x2F] = table32[0x2F] = function() { { bcd_das(); } };; |
| table16[0x30] = table32[0x30] = function() { var modrm_byte = read_imm8(); { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, xor8(data, reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1])); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = xor8(data, reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1]); } } }; table16[0x30 | 1] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, xor16(data, reg16[modrm_byte >> 2 & 14])); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, xor16(data, reg16[modrm_byte >> 2 & 14])); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = xor16(data, reg16[modrm_byte >> 2 & 14]); } } }; table32[0x30 | 1] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high); virt_boundary_write32(phys_addr, phys_addr_high, xor32(data, reg32s[modrm_byte >> 3 & 7])); } else { data = memory.read32s(phys_addr); memory.write32(phys_addr, xor32(data, reg32s[modrm_byte >> 3 & 7])); } } else { data = reg32s[modrm_byte & 7]; reg32s[modrm_byte & 7] = xor32(data, reg32s[modrm_byte >> 3 & 7]); } } }; table16[0x30 | 2] = table32[0x30 | 2] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read8(modrm_resolve(modrm_byte)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; }; reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1] = xor8(reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1], data); } }; table16[0x30 | 3] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = xor16(reg16[modrm_byte >> 2 & 14], data); } }; table32[0x30 | 3] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = xor32(reg32s[modrm_byte >> 3 & 7], data); } }; table16[0x30 | 4] = table32[0x30 | 4] = function() { { reg8[reg_al] = xor8(reg8[reg_al], read_imm8()); } }; table16[0x30 | 5] = function() { { reg16[reg_ax] = xor16(reg16[reg_ax], read_imm16()); } }; table32[0x30 | 5] = function() { { reg32[reg_eax] = xor32(reg32s[reg_eax], read_imm32s()); } };; |
| table16[0x36] = table32[0x36] = function() { { seg_prefix(reg_ss); } };; |
| table16[0x37] = table32[0x37] = function() { { bcd_aaa(); } };; |
| table16[0x38] = table32[0x38] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read8(modrm_resolve(modrm_byte)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; }; cmp8(data, reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1]); } }; |
| table16[0x39] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; cmp16(data, reg16[modrm_byte >> 2 & 14]); } }; table32[0x39] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = (safe_read32s(modrm_resolve(modrm_byte)) >>> 0); } else { data = reg32[modrm_byte & 7]; }; cmp32(data, reg32[modrm_byte >> 3 & 7]); } }; |
| table16[0x3A] = table32[0x3A] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read8(modrm_resolve(modrm_byte)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; }; cmp8(reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1], data); } }; |
| table16[0x3B] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; cmp16(reg16[modrm_byte >> 2 & 14], data); } }; table32[0x3B] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = (safe_read32s(modrm_resolve(modrm_byte)) >>> 0); } else { data = reg32[modrm_byte & 7]; }; cmp32(reg32[modrm_byte >> 3 & 7], data); } }; |
| table16[0x3C] = table32[0x3C] = function() { { cmp8(reg8[reg_al], read_imm8()); } }; |
| table16[0x3D] = function() { { cmp16(reg16[reg_ax], read_imm16()); } }; table32[0x3D] = function() { { cmp32(reg32[reg_eax], (read_imm32s() >>> 0)); } }; |
| table16[0x3E] = table32[0x3E] = function() { { seg_prefix(reg_ds); } };; |
| table16[0x3F] = table32[0x3F] = function() { { bcd_aas(); } };; |
| table16[0x40 | 0] = function() { { reg16[reg_ax] = inc16(reg16[reg_ax]); } }; table32[0x40 | 0] = function() { { reg32[reg_eax] = inc32(reg32[reg_eax]); } };; table16[0x40 | 1] = function() { { reg16[reg_cx] = inc16(reg16[reg_cx]); } }; table32[0x40 | 1] = function() { { reg32[reg_ecx] = inc32(reg32[reg_ecx]); } };; table16[0x40 | 2] = function() { { reg16[reg_dx] = inc16(reg16[reg_dx]); } }; table32[0x40 | 2] = function() { { reg32[reg_edx] = inc32(reg32[reg_edx]); } };; table16[0x40 | 3] = function() { { reg16[reg_bx] = inc16(reg16[reg_bx]); } }; table32[0x40 | 3] = function() { { reg32[reg_ebx] = inc32(reg32[reg_ebx]); } };; table16[0x40 | 4] = function() { { reg16[reg_sp] = inc16(reg16[reg_sp]); } }; table32[0x40 | 4] = function() { { reg32[reg_esp] = inc32(reg32[reg_esp]); } };; table16[0x40 | 5] = function() { { reg16[reg_bp] = inc16(reg16[reg_bp]); } }; table32[0x40 | 5] = function() { { reg32[reg_ebp] = inc32(reg32[reg_ebp]); } };; table16[0x40 | 6] = function() { { reg16[reg_si] = inc16(reg16[reg_si]); } }; table32[0x40 | 6] = function() { { reg32[reg_esi] = inc32(reg32[reg_esi]); } };; table16[0x40 | 7] = function() { { reg16[reg_di] = inc16(reg16[reg_di]); } }; table32[0x40 | 7] = function() { { reg32[reg_edi] = inc32(reg32[reg_edi]); } };;; |
| table16[0x48 | 0] = function() { { reg16[reg_ax] = dec16(reg16[reg_ax]); } }; table32[0x48 | 0] = function() { { reg32[reg_eax] = dec32(reg32[reg_eax]); } };; table16[0x48 | 1] = function() { { reg16[reg_cx] = dec16(reg16[reg_cx]); } }; table32[0x48 | 1] = function() { { reg32[reg_ecx] = dec32(reg32[reg_ecx]); } };; table16[0x48 | 2] = function() { { reg16[reg_dx] = dec16(reg16[reg_dx]); } }; table32[0x48 | 2] = function() { { reg32[reg_edx] = dec32(reg32[reg_edx]); } };; table16[0x48 | 3] = function() { { reg16[reg_bx] = dec16(reg16[reg_bx]); } }; table32[0x48 | 3] = function() { { reg32[reg_ebx] = dec32(reg32[reg_ebx]); } };; table16[0x48 | 4] = function() { { reg16[reg_sp] = dec16(reg16[reg_sp]); } }; table32[0x48 | 4] = function() { { reg32[reg_esp] = dec32(reg32[reg_esp]); } };; table16[0x48 | 5] = function() { { reg16[reg_bp] = dec16(reg16[reg_bp]); } }; table32[0x48 | 5] = function() { { reg32[reg_ebp] = dec32(reg32[reg_ebp]); } };; table16[0x48 | 6] = function() { { reg16[reg_si] = dec16(reg16[reg_si]); } }; table32[0x48 | 6] = function() { { reg32[reg_esi] = dec32(reg32[reg_esi]); } };; table16[0x48 | 7] = function() { { reg16[reg_di] = dec16(reg16[reg_di]); } }; table32[0x48 | 7] = function() { { reg32[reg_edi] = dec32(reg32[reg_edi]); } };;; |
| table16[0x50 | 0] = function() { { push16(reg16[reg_ax]); } }; table32[0x50 | 0] = function() { { push32(reg32s[reg_eax]); } }; table16[0x50 | 1] = function() { { push16(reg16[reg_cx]); } }; table32[0x50 | 1] = function() { { push32(reg32s[reg_ecx]); } }; table16[0x50 | 2] = function() { { push16(reg16[reg_dx]); } }; table32[0x50 | 2] = function() { { push32(reg32s[reg_edx]); } }; table16[0x50 | 3] = function() { { push16(reg16[reg_bx]); } }; table32[0x50 | 3] = function() { { push32(reg32s[reg_ebx]); } }; table16[0x50 | 4] = function() { { push16(reg16[reg_sp]); } }; table32[0x50 | 4] = function() { { push32(reg32s[reg_esp]); } }; table16[0x50 | 5] = function() { { push16(reg16[reg_bp]); } }; table32[0x50 | 5] = function() { { push32(reg32s[reg_ebp]); } }; table16[0x50 | 6] = function() { { push16(reg16[reg_si]); } }; table32[0x50 | 6] = function() { { push32(reg32s[reg_esi]); } }; table16[0x50 | 7] = function() { { push16(reg16[reg_di]); } }; table32[0x50 | 7] = function() { { push32(reg32s[reg_edi]); } };; |
| table16[0x58 | 0] = function() { { reg16[reg_ax] = pop16();; } }; table32[0x58 | 0] = function() { { reg32[reg_eax] = pop32s();; } }; table16[0x58 | 1] = function() { { reg16[reg_cx] = pop16();; } }; table32[0x58 | 1] = function() { { reg32[reg_ecx] = pop32s();; } }; table16[0x58 | 2] = function() { { reg16[reg_dx] = pop16();; } }; table32[0x58 | 2] = function() { { reg32[reg_edx] = pop32s();; } }; table16[0x58 | 3] = function() { { reg16[reg_bx] = pop16();; } }; table32[0x58 | 3] = function() { { reg32[reg_ebx] = pop32s();; } }; table16[0x58 | 4] = function() { { reg16[reg_sp] = pop16();; } }; table32[0x58 | 4] = function() { { reg32[reg_esp] = pop32s();; } }; table16[0x58 | 5] = function() { { reg16[reg_bp] = pop16();; } }; table32[0x58 | 5] = function() { { reg32[reg_ebp] = pop32s();; } }; table16[0x58 | 6] = function() { { reg16[reg_si] = pop16();; } }; table32[0x58 | 6] = function() { { reg32[reg_esi] = pop32s();; } }; table16[0x58 | 7] = function() { { reg16[reg_di] = pop16();; } }; table32[0x58 | 7] = function() { { reg32[reg_edi] = pop32s();; } };; |
| table16[0x60] = function() { { pusha16(); } }; table32[0x60] = function() { { pusha32(); } };; |
| table16[0x61] = function() { { popa16(); } }; table32[0x61] = function() { { popa32(); } };; |
| table16[0x62] = table32[0x62] = function() { { throw unimpl("bound instruction"); } };; |
| table16[0x63] = table32[0x63] = function() { var modrm_byte = read_imm8(); { /* arpl*/ var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, arpl(data, modrm_byte >> 2 & 14)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, arpl(data, modrm_byte >> 2 & 14)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = arpl(data, modrm_byte >> 2 & 14); }; } };; |
| table16[0x64] = table32[0x64] = function() { { seg_prefix(reg_fs); } };; |
| table16[0x65] = table32[0x65] = function() { { seg_prefix(reg_gs); } };; |
| table16[0x66] = table32[0x66] = function() { { /* Operand-size override prefix*/ dbg_assert(operand_size_32 === is_32); operand_size_32 = !is_32; update_operand_size(); table[read_imm8()](); operand_size_32 = is_32; update_operand_size(); } };; |
| table16[0x67] = table32[0x67] = function() { { /* Address-size override prefix*/ dbg_assert(address_size_32 === is_32); address_size_32 = !is_32; update_address_size(); table[read_imm8()](); address_size_32 = is_32; update_address_size(); } };; |
| table16[0x68] = function() { { push16(read_imm16()); } }; table32[0x68] = function() { { push32(read_imm32s()); } };; |
| table16[0x69] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = (safe_read16(modrm_resolve(modrm_byte)) << 16 >> 16); } else { data = reg16s[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = imul_reg16((read_imm16() << 16 >> 16), data); } }; table32[0x69] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32[modrm_byte >> 3 & 7] = imul_reg32(read_imm32s(), data); } };; |
| table16[0x6A] = function() { { push16(read_imm8s()); } }; table32[0x6A] = function() { { push32(read_imm8s()); } };; |
| table16[0x6B] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = (safe_read16(modrm_resolve(modrm_byte)) << 16 >> 16); } else { data = reg16s[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = imul_reg16(read_imm8s(), data); } }; table32[0x6B] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32[modrm_byte >> 3 & 7] = imul_reg32(read_imm8s(), data); } };; |
| table16[0x6C] = table32[0x6C] = function() { { insb(); } };; |
| table16[0x6D] = function() { { insw(); } }; table32[0x6D] = function() { { insd(); } };; |
| table16[0x6E] = table32[0x6E] = function() { { outsb(); } };; |
| table16[0x6F] = function() { { outsw(); } }; table32[0x6F] = function() { { outsd(); } };; |
| table16[0x70 | 0x0] = table32[0x70 | 0x0] = function() { { if((test_o())) { instruction_pointer = instruction_pointer + read_imm8s() | 0; } instruction_pointer++; } };;; table16[0x70 | 0x1] = table32[0x70 | 0x1] = function() { { if((!test_o())) { instruction_pointer = instruction_pointer + read_imm8s() | 0; } instruction_pointer++; } };;; table16[0x70 | 0x2] = table32[0x70 | 0x2] = function() { { if((test_b())) { instruction_pointer = instruction_pointer + read_imm8s() | 0; } instruction_pointer++; } };;; table16[0x70 | 0x3] = table32[0x70 | 0x3] = function() { { if((!test_b())) { instruction_pointer = instruction_pointer + read_imm8s() | 0; } instruction_pointer++; } };;; table16[0x70 | 0x4] = table32[0x70 | 0x4] = function() { { if((test_z())) { instruction_pointer = instruction_pointer + read_imm8s() | 0; } instruction_pointer++; } };;; table16[0x70 | 0x5] = table32[0x70 | 0x5] = function() { { if((!test_z())) { instruction_pointer = instruction_pointer + read_imm8s() | 0; } instruction_pointer++; } };;; table16[0x70 | 0x6] = table32[0x70 | 0x6] = function() { { if((test_be())) { instruction_pointer = instruction_pointer + read_imm8s() | 0; } instruction_pointer++; } };;; table16[0x70 | 0x7] = table32[0x70 | 0x7] = function() { { if((!test_be())) { instruction_pointer = instruction_pointer + read_imm8s() | 0; } instruction_pointer++; } };;; table16[0x70 | 0x8] = table32[0x70 | 0x8] = function() { { if((test_s())) { instruction_pointer = instruction_pointer + read_imm8s() | 0; } instruction_pointer++; } };;; table16[0x70 | 0x9] = table32[0x70 | 0x9] = function() { { if((!test_s())) { instruction_pointer = instruction_pointer + read_imm8s() | 0; } instruction_pointer++; } };;; table16[0x70 | 0xA] = table32[0x70 | 0xA] = function() { { if((test_p())) { instruction_pointer = instruction_pointer + read_imm8s() | 0; } instruction_pointer++; } };;; table16[0x70 | 0xB] = table32[0x70 | 0xB] = function() { { if((!test_p())) { instruction_pointer = instruction_pointer + read_imm8s() | 0; } instruction_pointer++; } };;; table16[0x70 | 0xC] = table32[0x70 | 0xC] = function() { { if((test_l())) { instruction_pointer = instruction_pointer + read_imm8s() | 0; } instruction_pointer++; } };;; table16[0x70 | 0xD] = table32[0x70 | 0xD] = function() { { if((!test_l())) { instruction_pointer = instruction_pointer + read_imm8s() | 0; } instruction_pointer++; } };;; table16[0x70 | 0xE] = table32[0x70 | 0xE] = function() { { if((test_le())) { instruction_pointer = instruction_pointer + read_imm8s() | 0; } instruction_pointer++; } };;; table16[0x70 | 0xF] = table32[0x70 | 0xF] = function() { { if((!test_le())) { instruction_pointer = instruction_pointer + read_imm8s() | 0; } instruction_pointer++; } };;;; |
| table16[0x80] = table32[0x80] = function() { var modrm_byte = read_imm8(); { switch(modrm_byte >> 3 & 7) { case 0: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, add8(data, read_imm8())); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = add8(data, read_imm8()); }; }; break; case 1: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, or8(data, read_imm8())); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = or8(data, read_imm8()); }; }; break; case 2: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, adc8(data, read_imm8())); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = adc8(data, read_imm8()); }; }; break; case 3: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, sbb8(data, read_imm8())); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = sbb8(data, read_imm8()); }; }; break; case 4: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, and8(data, read_imm8())); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = and8(data, read_imm8()); }; }; break; case 5: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, sub8(data, read_imm8())); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = sub8(data, read_imm8()); }; }; break; case 6: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, xor8(data, read_imm8())); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = xor8(data, read_imm8()); }; }; break; case 7: { if(modrm_byte < 0xC0) { var data = safe_read8(modrm_resolve(modrm_byte)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; }; cmp8(data, read_imm8()); }; break; } } };; |
| table16[0x81] = function() { var modrm_byte = read_imm8(); { switch(modrm_byte >> 3 & 7) { case 0: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, add16(data, read_imm16())); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, add16(data, read_imm16())); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = add16(data, read_imm16()); }; }; break; case 1: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, or16(data, read_imm16())); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, or16(data, read_imm16())); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = or16(data, read_imm16()); }; }; break; case 2: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, adc16(data, read_imm16())); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, adc16(data, read_imm16())); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = adc16(data, read_imm16()); }; }; break; case 3: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, sbb16(data, read_imm16())); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, sbb16(data, read_imm16())); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = sbb16(data, read_imm16()); }; }; break; case 4: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, and16(data, read_imm16())); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, and16(data, read_imm16())); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = and16(data, read_imm16()); }; }; break; case 5: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, sub16(data, read_imm16())); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, sub16(data, read_imm16())); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = sub16(data, read_imm16()); }; }; break; case 6: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, xor16(data, read_imm16())); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, xor16(data, read_imm16())); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = xor16(data, read_imm16()); }; }; break; case 7: { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; cmp16(data, read_imm16()); }; break; } } }; table32[0x81] = function() { var modrm_byte = read_imm8(); { switch(modrm_byte >> 3 & 7) { case 0: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, add32(data, (read_imm32s() >>> 0))); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, add32(data, (read_imm32s() >>> 0))); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = add32(data, (read_imm32s() >>> 0)); }; }; break; case 1: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high); virt_boundary_write32(phys_addr, phys_addr_high, or32(data, read_imm32s())); } else { data = memory.read32s(phys_addr); memory.write32(phys_addr, or32(data, read_imm32s())); } } else { data = reg32s[modrm_byte & 7]; reg32s[modrm_byte & 7] = or32(data, read_imm32s()); }; }; break; case 2: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, adc32(data, (read_imm32s() >>> 0))); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, adc32(data, (read_imm32s() >>> 0))); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = adc32(data, (read_imm32s() >>> 0)); }; }; break; case 3: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, sbb32(data, (read_imm32s() >>> 0))); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, sbb32(data, (read_imm32s() >>> 0))); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = sbb32(data, (read_imm32s() >>> 0)); }; }; break; case 4: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high); virt_boundary_write32(phys_addr, phys_addr_high, and32(data, read_imm32s())); } else { data = memory.read32s(phys_addr); memory.write32(phys_addr, and32(data, read_imm32s())); } } else { data = reg32s[modrm_byte & 7]; reg32s[modrm_byte & 7] = and32(data, read_imm32s()); }; }; break; case 5: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, sub32(data, (read_imm32s() >>> 0))); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, sub32(data, (read_imm32s() >>> 0))); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = sub32(data, (read_imm32s() >>> 0)); }; }; break; case 6: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high); virt_boundary_write32(phys_addr, phys_addr_high, xor32(data, read_imm32s())); } else { data = memory.read32s(phys_addr); memory.write32(phys_addr, xor32(data, read_imm32s())); } } else { data = reg32s[modrm_byte & 7]; reg32s[modrm_byte & 7] = xor32(data, read_imm32s()); }; }; break; case 7: { if(modrm_byte < 0xC0) { var data = (safe_read32s(modrm_resolve(modrm_byte)) >>> 0); } else { data = reg32[modrm_byte & 7]; }; cmp32(data, (read_imm32s() >>> 0)); }; break; } } };; |
| table16[0x82] = table32[0x82] = function() { { table[0x80](); /* alias*/ } };; |
| table16[0x83] = function() { var modrm_byte = read_imm8(); { switch(modrm_byte >> 3 & 7) { case 0: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, add16(data, read_imm8s() & 0xFFFF)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, add16(data, read_imm8s() & 0xFFFF)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = add16(data, read_imm8s() & 0xFFFF); }; }; break; case 1: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, or16(data, read_imm8s())); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, or16(data, read_imm8s())); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = or16(data, read_imm8s()); }; }; break; case 2: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, adc16(data, read_imm8s() & 0xFFFF)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, adc16(data, read_imm8s() & 0xFFFF)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = adc16(data, read_imm8s() & 0xFFFF); }; }; break; case 3: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, sbb16(data, read_imm8s() & 0xFFFF)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, sbb16(data, read_imm8s() & 0xFFFF)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = sbb16(data, read_imm8s() & 0xFFFF); }; }; break; case 4: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, and16(data, read_imm8s())); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, and16(data, read_imm8s())); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = and16(data, read_imm8s()); }; }; break; case 5: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, sub16(data, read_imm8s() & 0xFFFF)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, sub16(data, read_imm8s() & 0xFFFF)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = sub16(data, read_imm8s() & 0xFFFF); }; }; break; case 6: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, xor16(data, read_imm8s())); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, xor16(data, read_imm8s())); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = xor16(data, read_imm8s()); }; }; break; case 7: { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; cmp16(data, read_imm8s() & 0xFFFF); }; break; } } }; table32[0x83] = function() { var modrm_byte = read_imm8(); { switch(modrm_byte >> 3 & 7) { case 0: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, add32(data, read_imm8s() >>> 0)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, add32(data, read_imm8s() >>> 0)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = add32(data, read_imm8s() >>> 0); }; }; break; case 1: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high); virt_boundary_write32(phys_addr, phys_addr_high, or32(data, read_imm8s())); } else { data = memory.read32s(phys_addr); memory.write32(phys_addr, or32(data, read_imm8s())); } } else { data = reg32s[modrm_byte & 7]; reg32s[modrm_byte & 7] = or32(data, read_imm8s()); }; }; break; case 2: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, adc32(data, read_imm8s() >>> 0)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, adc32(data, read_imm8s() >>> 0)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = adc32(data, read_imm8s() >>> 0); }; }; break; case 3: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, sbb32(data, read_imm8s() >>> 0)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, sbb32(data, read_imm8s() >>> 0)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = sbb32(data, read_imm8s() >>> 0); }; }; break; case 4: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high); virt_boundary_write32(phys_addr, phys_addr_high, and32(data, read_imm8s())); } else { data = memory.read32s(phys_addr); memory.write32(phys_addr, and32(data, read_imm8s())); } } else { data = reg32s[modrm_byte & 7]; reg32s[modrm_byte & 7] = and32(data, read_imm8s()); }; }; break; case 5: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, sub32(data, read_imm8s() >>> 0)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, sub32(data, read_imm8s() >>> 0)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = sub32(data, read_imm8s() >>> 0); }; }; break; case 6: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high); virt_boundary_write32(phys_addr, phys_addr_high, xor32(data, read_imm8s())); } else { data = memory.read32s(phys_addr); memory.write32(phys_addr, xor32(data, read_imm8s())); } } else { data = reg32s[modrm_byte & 7]; reg32s[modrm_byte & 7] = xor32(data, read_imm8s()); }; }; break; case 7: { if(modrm_byte < 0xC0) { var data = (safe_read32s(modrm_resolve(modrm_byte)) >>> 0); } else { data = reg32[modrm_byte & 7]; }; cmp32(data, read_imm8s() >>> 0); }; break; } } };; |
| table16[0x84] = table32[0x84] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read8(modrm_resolve(modrm_byte)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; }; test8(data, reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1]); } }; |
| table16[0x85] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; test16(data, reg16[modrm_byte >> 2 & 14]); } }; table32[0x85] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; test32(data, reg32s[modrm_byte >> 3 & 7]); } }; |
| table16[0x86] = table32[0x86] = function() { var modrm_byte = read_imm8(); { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, xchg8(data, modrm_byte)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = xchg8(data, modrm_byte); }; } };; |
| table16[0x87] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, xchg16(data, modrm_byte)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, xchg16(data, modrm_byte)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = xchg16(data, modrm_byte); }; } }; table32[0x87] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, xchg32(data, modrm_byte)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, xchg32(data, modrm_byte)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = xchg32(data, modrm_byte); }; } };; |
| table16[0x88] = table32[0x88] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write8(modrm_resolve(modrm_byte), reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1]); } else { reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1]; }; } }; |
| table16[0x89] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write16(modrm_resolve(modrm_byte), reg16[modrm_byte >> 2 & 14]); } else { reg16[modrm_byte << 1 & 14] = reg16[modrm_byte >> 2 & 14]; }; } }; table32[0x89] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write32(modrm_resolve(modrm_byte), reg32s[modrm_byte >> 3 & 7]); } else { reg32[modrm_byte & 7] = reg32s[modrm_byte >> 3 & 7]; }; } }; |
| table16[0x8A] = table32[0x8A] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read8(modrm_resolve(modrm_byte)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; }; reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1] = data; } };; |
| table16[0x8B] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = data; } }; table32[0x8B] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = data; } };; |
| table16[0x8C] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write16(modrm_resolve(modrm_byte), sreg[modrm_byte >> 3 & 7]); } else { reg16[modrm_byte << 1 & 14] = sreg[modrm_byte >> 3 & 7]; }; } }; table32[0x8C] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write32(modrm_resolve(modrm_byte), sreg[modrm_byte >> 3 & 7]); } else { reg32[modrm_byte & 7] = sreg[modrm_byte >> 3 & 7]; }; } }; |
| table16[0x8D] = function() { { lea16(); } }; table32[0x8D] = function() { { lea32(); } };; |
| table16[0x8E] = table32[0x8E] = function() { var modrm_byte = read_imm8(); { var mod = modrm_byte >> 3 & 7; if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; switch_seg(mod, data); if(mod === reg_ss) { /* TODO*/ /* run next instruction, so no irqs are handled*/ } } };; |
| table16[0x8F] = table32[0x8F] = function() { var modrm_byte = read_imm8(); { /* pop*/ if(operand_size_32) { /* change esp first, then resolve modrm address*/ var sp = get_esp_read(0); /* TODO unsafe*/ stack_reg[reg_vsp] += 4; if(modrm_byte < 0xC0) { safe_write32(modrm_resolve(modrm_byte), memory.read32s(sp)); } else { reg32[modrm_byte & 7] = memory.read32s(sp); }; } else { var sp = get_esp_read(0); stack_reg[reg_vsp] += 2; if(modrm_byte < 0xC0) { safe_write16(modrm_resolve(modrm_byte), memory.read16(sp)); } else { reg16[modrm_byte << 1 & 14] = memory.read16(sp); }; } } };; |
| table16[0x90 | 0] = function() { { xchg16r(reg_ax) } }; table32[0x90 | 0] = function() { { xchg32r(reg_eax) } }; table16[0x90 | 1] = function() { { xchg16r(reg_cx) } }; table32[0x90 | 1] = function() { { xchg32r(reg_ecx) } }; table16[0x90 | 2] = function() { { xchg16r(reg_dx) } }; table32[0x90 | 2] = function() { { xchg32r(reg_edx) } }; table16[0x90 | 3] = function() { { xchg16r(reg_bx) } }; table32[0x90 | 3] = function() { { xchg32r(reg_ebx) } }; table16[0x90 | 4] = function() { { xchg16r(reg_sp) } }; table32[0x90 | 4] = function() { { xchg32r(reg_esp) } }; table16[0x90 | 5] = function() { { xchg16r(reg_bp) } }; table32[0x90 | 5] = function() { { xchg32r(reg_ebp) } }; table16[0x90 | 6] = function() { { xchg16r(reg_si) } }; table32[0x90 | 6] = function() { { xchg32r(reg_esi) } }; table16[0x90 | 7] = function() { { xchg16r(reg_di) } }; table32[0x90 | 7] = function() { { xchg32r(reg_edi) } }; |
| table16[0x90] = table32[0x90] = function() { /* nop */ };; |
| table16[0x98] = function() { { /* cbw */ reg16[reg_ax] = reg8s[reg_al]; } }; table32[0x98] = function() { { /* cwde */ reg32[reg_eax] = reg16s[reg_ax]; } };; |
| table16[0x99] = function() { { /* cwd */ reg16[reg_dx] = reg16s[reg_ax] >> 15; } }; table32[0x99] = function() { { /* cdq */ reg32[reg_edx] = reg32s[reg_eax] >> 31; } };; |
| table16[0x9A] = function() { { /* callf*/ if(protected_mode) { throw unimpl("16 bit callf in protected mode"); } else { var new_ip = read_imm16(); var new_cs = read_imm16(); push16(sreg[reg_cs]); push16(get_real_ip()); switch_seg(reg_cs, new_cs); instruction_pointer = get_seg(reg_cs) + new_ip | 0; } } }; table32[0x9A] = function() { { if(protected_mode) { throw unimpl("callf"); } else { var new_ip = read_imm32s(); var new_cs = read_imm16(); push32(sreg[reg_cs]); push32(get_real_ip()); switch_seg(reg_cs, new_cs); instruction_pointer = get_seg(reg_cs) + new_ip | 0; } } };; |
| table16[0x9B] = table32[0x9B] = function() { { /* fwait: check for pending fpu exceptions*/ fpu.fwait(); } };; |
| table16[0x9C] = function() { { /* pushf*/ load_flags(); push16(flags); } }; table32[0x9C] = function() { { /* pushf*/ load_flags(); push32(flags); } };; |
| table16[0x9D] = function() { { /* popf*/ var tmp; tmp = pop16();; update_flags(tmp); handle_irqs(); } }; table32[0x9D] = function() { { /* popf*/ update_flags(pop32s()); handle_irqs(); } };; |
| table16[0x9E] = table32[0x9E] = function() { { /* sahf*/ flags = (flags & ~0xFF) | reg8[reg_ah]; flags = (flags & flags_mask) | flags_default; flags_changed = 0; } };; |
| table16[0x9F] = table32[0x9F] = function() { { /* lahf*/ load_flags(); reg8[reg_ah] = flags; } };; |
| table16[0xA0] = table32[0xA0] = function() { { /* mov*/ var data = safe_read8(read_moffs()); reg8[reg_al] = data; } };; |
| table16[0xA1] = function() { { /* mov*/ var data = safe_read16(read_moffs()); reg16[reg_ax] = data; } }; table32[0xA1] = function() { { var data = safe_read32s(read_moffs()); reg32[reg_eax] = data; } };; |
| table16[0xA2] = table32[0xA2] = function() { { /* mov*/ safe_write8(read_moffs(), reg8[reg_al]); } };; |
| table16[0xA3] = function() { { /* mov*/ safe_write16(read_moffs(), reg16[reg_ax]); } }; table32[0xA3] = function() { { safe_write32(read_moffs(), reg32s[reg_eax]); } };; |
| table16[0xA4] = table32[0xA4] = function() { { movsb(); } };; |
| table16[0xA5] = function() { { movsw(); } }; table32[0xA5] = function() { { movsd(); } };; |
| table16[0xA6] = table32[0xA6] = function() { { cmpsb(); } };; |
| table16[0xA7] = function() { { cmpsw(); } }; table32[0xA7] = function() { { cmpsd(); } };; |
| table16[0xA8] = table32[0xA8] = function() { { test8(reg8[reg_al], read_imm8()); } };; |
| table16[0xA9] = function() { { test16(reg16[reg_ax], read_imm16()); } }; table32[0xA9] = function() { { test32(reg32s[reg_eax], read_imm32s()); } };; |
| table16[0xAA] = table32[0xAA] = function() { { stosb(); } };; |
| table16[0xAB] = function() { { stosw(); } }; table32[0xAB] = function() { { stosd(); } };; |
| table16[0xAC] = table32[0xAC] = function() { { lodsb(); } };; |
| table16[0xAD] = function() { { lodsw(); } }; table32[0xAD] = function() { { lodsd(); } };; |
| table16[0xAE] = table32[0xAE] = function() { { scasb(); } };; |
| table16[0xAF] = function() { { scasw(); } }; table32[0xAF] = function() { { scasd(); } };; |
| table16[0xB0 | 0] = table32[0xB0 | 0] = function() { { reg8[reg_al] = read_imm8(); } };; table16[0xB0 | 1] = table32[0xB0 | 1] = function() { { reg8[reg_cl] = read_imm8(); } };; table16[0xB0 | 2] = table32[0xB0 | 2] = function() { { reg8[reg_dl] = read_imm8(); } };; table16[0xB0 | 3] = table32[0xB0 | 3] = function() { { reg8[reg_bl] = read_imm8(); } };; table16[0xB0 | 4] = table32[0xB0 | 4] = function() { { reg8[reg_ah] = read_imm8(); } };; table16[0xB0 | 5] = table32[0xB0 | 5] = function() { { reg8[reg_ch] = read_imm8(); } };; table16[0xB0 | 6] = table32[0xB0 | 6] = function() { { reg8[reg_dh] = read_imm8(); } };; table16[0xB0 | 7] = table32[0xB0 | 7] = function() { { reg8[reg_bh] = read_imm8(); } };;; |
| table16[0xB8 | 0] = function() { { reg16[reg_ax] = read_imm16(); } }; table32[0xB8 | 0] = function() { { reg32s[reg_eax] = read_imm32s(); } };; table16[0xB8 | 1] = function() { { reg16[reg_cx] = read_imm16(); } }; table32[0xB8 | 1] = function() { { reg32s[reg_ecx] = read_imm32s(); } };; table16[0xB8 | 2] = function() { { reg16[reg_dx] = read_imm16(); } }; table32[0xB8 | 2] = function() { { reg32s[reg_edx] = read_imm32s(); } };; table16[0xB8 | 3] = function() { { reg16[reg_bx] = read_imm16(); } }; table32[0xB8 | 3] = function() { { reg32s[reg_ebx] = read_imm32s(); } };; table16[0xB8 | 4] = function() { { reg16[reg_sp] = read_imm16(); } }; table32[0xB8 | 4] = function() { { reg32s[reg_esp] = read_imm32s(); } };; table16[0xB8 | 5] = function() { { reg16[reg_bp] = read_imm16(); } }; table32[0xB8 | 5] = function() { { reg32s[reg_ebp] = read_imm32s(); } };; table16[0xB8 | 6] = function() { { reg16[reg_si] = read_imm16(); } }; table32[0xB8 | 6] = function() { { reg32s[reg_esi] = read_imm32s(); } };; table16[0xB8 | 7] = function() { { reg16[reg_di] = read_imm16(); } }; table32[0xB8 | 7] = function() { { reg32s[reg_edi] = read_imm32s(); } };;; |
| table16[0xC0] = table32[0xC0] = function() { var modrm_byte = read_imm8(); { switch(modrm_byte >> 3 & 7) { case 0: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, rol8(data, read_imm8() & 31)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = rol8(data, read_imm8() & 31); }; }; break; case 1: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, ror8(data, read_imm8() & 31)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = ror8(data, read_imm8() & 31); }; }; break; case 2: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, rcl8(data, read_imm8() & 31)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = rcl8(data, read_imm8() & 31); }; }; break; case 3: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, rcr8(data, read_imm8() & 31)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = rcr8(data, read_imm8() & 31); }; }; break; case 4: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, shl8(data, read_imm8() & 31)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = shl8(data, read_imm8() & 31); }; }; break; case 5: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, shr8(data, read_imm8() & 31)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = shr8(data, read_imm8() & 31); }; }; break; case 6: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, shl8(data, read_imm8() & 31)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = shl8(data, read_imm8() & 31); }; }; break; case 7: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, sar8(data, read_imm8() & 31)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = sar8(data, read_imm8() & 31); }; }; break; } } };; |
| table16[0xC1] = function() { var modrm_byte = read_imm8(); { switch(modrm_byte >> 3 & 7) { case 0: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, rol16(data, read_imm8() & 31)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, rol16(data, read_imm8() & 31)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = rol16(data, read_imm8() & 31); }; }; break; case 1: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, ror16(data, read_imm8() & 31)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, ror16(data, read_imm8() & 31)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = ror16(data, read_imm8() & 31); }; }; break; case 2: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, rcl16(data, read_imm8() & 31)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, rcl16(data, read_imm8() & 31)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = rcl16(data, read_imm8() & 31); }; }; break; case 3: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, rcr16(data, read_imm8() & 31)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, rcr16(data, read_imm8() & 31)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = rcr16(data, read_imm8() & 31); }; }; break; case 4: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, shl16(data, read_imm8() & 31)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, shl16(data, read_imm8() & 31)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = shl16(data, read_imm8() & 31); }; }; break; case 5: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, shr16(data, read_imm8() & 31)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, shr16(data, read_imm8() & 31)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = shr16(data, read_imm8() & 31); }; }; break; case 6: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, shl16(data, read_imm8() & 31)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, shl16(data, read_imm8() & 31)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = shl16(data, read_imm8() & 31); }; }; break; case 7: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, sar16(data, read_imm8() & 31)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, sar16(data, read_imm8() & 31)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = sar16(data, read_imm8() & 31); }; }; break; } } }; table32[0xC1] = function() { var modrm_byte = read_imm8(); { switch(modrm_byte >> 3 & 7) { case 0: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, rol32(data, read_imm8() & 31)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, rol32(data, read_imm8() & 31)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = rol32(data, read_imm8() & 31); }; }; break; case 1: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, ror32(data, read_imm8() & 31)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, ror32(data, read_imm8() & 31)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = ror32(data, read_imm8() & 31); }; }; break; case 2: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, rcl32(data, read_imm8() & 31)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, rcl32(data, read_imm8() & 31)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = rcl32(data, read_imm8() & 31); }; }; break; case 3: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, rcr32(data, read_imm8() & 31)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, rcr32(data, read_imm8() & 31)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = rcr32(data, read_imm8() & 31); }; }; break; case 4: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, shl32(data, read_imm8() & 31)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, shl32(data, read_imm8() & 31)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = shl32(data, read_imm8() & 31); }; }; break; case 5: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, shr32(data, read_imm8() & 31)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, shr32(data, read_imm8() & 31)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = shr32(data, read_imm8() & 31); }; }; break; case 6: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, shl32(data, read_imm8() & 31)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, shl32(data, read_imm8() & 31)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = shl32(data, read_imm8() & 31); }; }; break; case 7: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, sar32(data, read_imm8() & 31)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, sar32(data, read_imm8() & 31)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = sar32(data, read_imm8() & 31); }; }; break; } } };; |
| table16[0xC2] = function() { { /* retn*/ var imm16 = read_imm16(); instruction_pointer = get_seg(reg_cs) + pop16() | 0; /* TODO regv*/ reg32[reg_esp] += imm16; } }; table32[0xC2] = function() { { /* retn*/ var imm16 = read_imm16(); instruction_pointer = get_seg(reg_cs) + pop32s() | 0; reg32[reg_esp] += imm16; } };; |
| table16[0xC3] = function() { { /* retn*/ instruction_pointer = get_seg(reg_cs) + pop16() | 0;; } }; table32[0xC3] = function() { { /* retn*/ instruction_pointer = get_seg(reg_cs) + pop32s() | 0;; } };; |
| table16[0xC4] = table32[0xC4] = function() { var modrm_byte = read_imm8(); { if(modrm_byte >= 0xC0) { raise_exception(6); return; } if(operand_size_32) { lss32(reg_es, modrm_resolve(modrm_byte), modrm_byte >> 3 & 7); } else { lss16(reg_es, modrm_resolve(modrm_byte), modrm_byte >> 2 & 14); }; } };; |
| table16[0xC5] = table32[0xC5] = function() { var modrm_byte = read_imm8(); { if(modrm_byte >= 0xC0) { raise_exception(6); return; } if(operand_size_32) { lss32(reg_ds, modrm_resolve(modrm_byte), modrm_byte >> 3 & 7); } else { lss16(reg_ds, modrm_resolve(modrm_byte), modrm_byte >> 2 & 14); }; } };; |
| table16[0xC6] = table32[0xC6] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write8(modrm_resolve(modrm_byte), read_imm8()); } else { reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = read_imm8(); }; } }; |
| table16[0xC7] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write16(modrm_resolve(modrm_byte), read_imm16()); } else { reg16[modrm_byte << 1 & 14] = read_imm16(); }; } }; table32[0xC7] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write32(modrm_resolve(modrm_byte), read_imm32s()); } else { reg32[modrm_byte & 7] = read_imm32s(); }; } }; |
| table16[0xC8] = function() { { enter16(); } }; table32[0xC8] = function() { { enter32(); } };; |
| table16[0xC9] = function() { { /* leave*/ stack_reg[reg_vsp] = stack_reg[reg_vbp]; reg16[reg_bp] = pop16(); } }; table32[0xC9] = function() { { stack_reg[reg_vsp] = stack_reg[reg_vbp]; reg32[reg_ebp] = pop32s(); } };; |
| table16[0xCA] = function() { { /* retf*/ if(protected_mode) { throw unimpl("16 bit retf in protected mode"); } var imm16 = read_imm16(); var ip = pop16(); switch_seg(reg_cs, pop16()); instruction_pointer = get_seg(reg_cs) + ip | 0; reg16[reg_sp] += imm16; } }; table32[0xCA] = function() { { /* retf */ var imm16 = read_imm16(); if(protected_mode) { /*dbg_log("retf");*/ var ip = pop32s(); switch_seg(reg_cs, pop32s() & 0xFFFF); instruction_pointer = get_seg(reg_cs) + ip | 0; stack_reg[reg_vsp] += imm16; } else { throw unimpl("32 bit retf in real mode"); } } };; |
| table16[0xCB] = function() { { /* retf*/ if(protected_mode) { throw unimpl("16 bit retf in protected mode"); } else { var ip = pop16(); switch_seg(reg_cs, pop16()); instruction_pointer = get_seg(reg_cs) + ip | 0; } } }; table32[0xCB] = function() { { /* retf */ if(protected_mode) { var ip = pop32s(); switch_seg(reg_cs, pop32s() & 0xFFFF); instruction_pointer = get_seg(reg_cs) + ip | 0; } else { var ip = pop32s(); switch_seg(reg_cs, pop32s() & 0xFFFF); instruction_pointer = get_seg(reg_cs) + ip | 0; } } };; |
| table16[0xCC] = table32[0xCC] = function() { { /* INT3*/ call_interrupt_vector(3, true, false); } };; |
| table16[0xCD] = table32[0xCD] = function() { { /* INT */ var imm8 = read_imm8(); call_interrupt_vector(imm8, true, false); } };; |
| table16[0xCE] = table32[0xCE] = function() { { /* INTO*/ if(getof()) { call_interrupt_vector(4, true, false); } } };; |
| table16[0xCF] = function() { { /* iret*/ if(protected_mode) { throw unimpl("16 bit iret in protected mode"); } var ip = pop16(); switch_seg(reg_cs, pop16()); var new_flags = pop16(); instruction_pointer = ip + get_seg(reg_cs) | 0; flags = new_flags; flags_changed = 0; handle_irqs(); } }; table32[0xCF] = function() { { /* iret*/ if(!protected_mode) { throw unimpl("32 bit iret in real mode"); } else { if(flags & flag_nt) { if(DEBUG) throw "unimplemented nt"; } if(flags & flag_vm) { if(DEBUG) throw "unimplemented vm"; } } /*dbg_log("pop eip from " + h(reg32[reg_esp], 8));*/ instruction_pointer = pop32s(); /*dbg_log("IRET | from " + h(previous_ip) + " to " + h(instruction_pointer));*/ sreg[reg_cs] = pop32s(); /*instruction_pointer += get_seg(reg_cs);*/ var new_flags = pop32s(); if(new_flags & flag_vm) { if(DEBUG) throw "unimplemented"; } /* protected mode return*/ var info = lookup_segment_selector(sreg[reg_cs]); if(info.is_null) { throw unimpl("is null"); } if(!info.is_present) { throw unimpl("not present"); } if(!info.is_executable) { throw unimpl("not exec"); } if(info.rpl < cpl) { throw unimpl("rpl < cpl"); } if(info.dc_bit && info.dpl > info.rpl) { throw unimpl("conforming and dpl > rpl"); } if(info.rpl > cpl) { /* outer privilege return*/ var temp_esp = pop32s(); var temp_ss = pop32s(); reg32[reg_esp] = temp_esp; update_flags(new_flags); cpl = info.rpl; switch_seg(reg_ss, temp_ss & 0xFFFF); /*dbg_log("iret cpl=" + cpl + " to " + h(instruction_pointer) + */ /* " cs:eip=" + h(sreg[reg_cs],4) + ":" + h(get_real_ip(), 8) +*/ /* " ss:esp=" + h(temp_ss & 0xFFFF, 2) + ":" + h(temp_esp, 8), LOG_CPU);*/ cpl_changed(); } else { update_flags(new_flags); /* same privilege return*/ /*dbg_log(h(new_flags) + " " + h(flags));*/ /*dbg_log("iret to " + h(instruction_pointer));*/ } /*dbg_log("iret if=" + (flags & flag_interrupt) + " cpl=" + cpl);*/ dbg_assert(!page_fault); handle_irqs(); } };; |
| table16[0xD0] = table32[0xD0] = function() { var modrm_byte = read_imm8(); { switch(modrm_byte >> 3 & 7) { case 0: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, rol8(data, 1)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = rol8(data, 1); }; }; break; case 1: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, ror8(data, 1)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = ror8(data, 1); }; }; break; case 2: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, rcl8(data, 1)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = rcl8(data, 1); }; }; break; case 3: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, rcr8(data, 1)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = rcr8(data, 1); }; }; break; case 4: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, shl8(data, 1)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = shl8(data, 1); }; }; break; case 5: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, shr8(data, 1)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = shr8(data, 1); }; }; break; case 6: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, shl8(data, 1)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = shl8(data, 1); }; }; break; case 7: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, sar8(data, 1)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = sar8(data, 1); }; }; break; } } };; |
| table16[0xD1] = function() { var modrm_byte = read_imm8(); { switch(modrm_byte >> 3 & 7) { case 0: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, rol16(data, 1)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, rol16(data, 1)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = rol16(data, 1); }; }; break; case 1: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, ror16(data, 1)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, ror16(data, 1)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = ror16(data, 1); }; }; break; case 2: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, rcl16(data, 1)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, rcl16(data, 1)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = rcl16(data, 1); }; }; break; case 3: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, rcr16(data, 1)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, rcr16(data, 1)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = rcr16(data, 1); }; }; break; case 4: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, shl16(data, 1)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, shl16(data, 1)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = shl16(data, 1); }; }; break; case 5: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, shr16(data, 1)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, shr16(data, 1)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = shr16(data, 1); }; }; break; case 6: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, shl16(data, 1)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, shl16(data, 1)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = shl16(data, 1); }; }; break; case 7: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, sar16(data, 1)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, sar16(data, 1)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = sar16(data, 1); }; }; break; } } }; table32[0xD1] = function() { var modrm_byte = read_imm8(); { switch(modrm_byte >> 3 & 7) { case 0: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, rol32(data, 1)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, rol32(data, 1)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = rol32(data, 1); }; }; break; case 1: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, ror32(data, 1)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, ror32(data, 1)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = ror32(data, 1); }; }; break; case 2: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, rcl32(data, 1)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, rcl32(data, 1)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = rcl32(data, 1); }; }; break; case 3: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, rcr32(data, 1)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, rcr32(data, 1)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = rcr32(data, 1); }; }; break; case 4: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, shl32(data, 1)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, shl32(data, 1)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = shl32(data, 1); }; }; break; case 5: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, shr32(data, 1)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, shr32(data, 1)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = shr32(data, 1); }; }; break; case 6: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, shl32(data, 1)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, shl32(data, 1)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = shl32(data, 1); }; }; break; case 7: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, sar32(data, 1)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, sar32(data, 1)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = sar32(data, 1); }; }; break; } } };; |
| table16[0xD2] = table32[0xD2] = function() { var modrm_byte = read_imm8(); { var shift = reg8[reg_cl] & 31; switch(modrm_byte >> 3 & 7) { case 0: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, rol8(data, shift)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = rol8(data, shift); }; }; break; case 1: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, ror8(data, shift)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = ror8(data, shift); }; }; break; case 2: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, rcl8(data, shift)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = rcl8(data, shift); }; }; break; case 3: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, rcr8(data, shift)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = rcr8(data, shift); }; }; break; case 4: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, shl8(data, shift)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = shl8(data, shift); }; }; break; case 5: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, shr8(data, shift)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = shr8(data, shift); }; }; break; case 6: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, shl8(data, shift)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = shl8(data, shift); }; }; break; case 7: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, sar8(data, shift)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = sar8(data, shift); }; }; break; } } };; |
| table16[0xD3] = function() { var modrm_byte = read_imm8(); { var shift = reg8[reg_cl] & 31; switch(modrm_byte >> 3 & 7) { case 0: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, rol16(data, shift)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, rol16(data, shift)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = rol16(data, shift); }; }; break; case 1: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, ror16(data, shift)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, ror16(data, shift)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = ror16(data, shift); }; }; break; case 2: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, rcl16(data, shift)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, rcl16(data, shift)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = rcl16(data, shift); }; }; break; case 3: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, rcr16(data, shift)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, rcr16(data, shift)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = rcr16(data, shift); }; }; break; case 4: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, shl16(data, shift)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, shl16(data, shift)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = shl16(data, shift); }; }; break; case 5: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, shr16(data, shift)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, shr16(data, shift)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = shr16(data, shift); }; }; break; case 6: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, shl16(data, shift)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, shl16(data, shift)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = shl16(data, shift); }; }; break; case 7: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, sar16(data, shift)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, sar16(data, shift)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = sar16(data, shift); }; }; break; } } }; table32[0xD3] = function() { var modrm_byte = read_imm8(); { var shift = reg8[reg_cl] & 31; switch(modrm_byte >> 3 & 7) { case 0: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, rol32(data, shift)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, rol32(data, shift)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = rol32(data, shift); }; }; break; case 1: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, ror32(data, shift)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, ror32(data, shift)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = ror32(data, shift); }; }; break; case 2: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, rcl32(data, shift)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, rcl32(data, shift)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = rcl32(data, shift); }; }; break; case 3: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, rcr32(data, shift)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, rcr32(data, shift)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = rcr32(data, shift); }; }; break; case 4: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, shl32(data, shift)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, shl32(data, shift)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = shl32(data, shift); }; }; break; case 5: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, shr32(data, shift)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, shr32(data, shift)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = shr32(data, shift); }; }; break; case 6: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, shl32(data, shift)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, shl32(data, shift)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = shl32(data, shift); }; }; break; case 7: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, sar32(data, shift)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, sar32(data, shift)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = sar32(data, shift); }; }; break; } } };; |
| table16[0xD4] = table32[0xD4] = function() { { bcd_aam(); } };; |
| table16[0xD5] = table32[0xD5] = function() { { bcd_aad(); } };; |
| table16[0xD6] = table32[0xD6] = function() { { /* salc*/ throw unimpl("salc instruction"); } };; |
| table16[0xD7] = table32[0xD7] = function() { { /* xlat*/ if(address_size_32) { reg8[reg_al] = safe_read8(get_seg_prefix(reg_ds) + reg32s[reg_ebx] + reg8[reg_al]); } else { reg8[reg_al] = safe_read8(get_seg_prefix(reg_ds) + reg16[reg_bx] + reg8[reg_al]); } } };; |
| // fpu instructions |
| table16[0xD8] = table32[0xD8] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) fpu.op_D8_mem(modrm_byte, modrm_resolve(modrm_byte)); else fpu.op_D8_reg(modrm_byte); } };; |
| table16[0xD9] = table32[0xD9] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) fpu.op_D9_mem(modrm_byte, modrm_resolve(modrm_byte)); else fpu.op_D9_reg(modrm_byte); } };; |
| table16[0xDA] = table32[0xDA] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) fpu.op_DA_mem(modrm_byte, modrm_resolve(modrm_byte)); else fpu.op_DA_reg(modrm_byte); } };; |
| table16[0xDB] = table32[0xDB] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) fpu.op_DB_mem(modrm_byte, modrm_resolve(modrm_byte)); else fpu.op_DB_reg(modrm_byte); } };; |
| table16[0xDC] = table32[0xDC] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) fpu.op_DC_mem(modrm_byte, modrm_resolve(modrm_byte)); else fpu.op_DC_reg(modrm_byte); } };; |
| table16[0xDD] = table32[0xDD] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) fpu.op_DD_mem(modrm_byte, modrm_resolve(modrm_byte)); else fpu.op_DD_reg(modrm_byte); } };; |
| table16[0xDE] = table32[0xDE] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) fpu.op_DE_mem(modrm_byte, modrm_resolve(modrm_byte)); else fpu.op_DE_reg(modrm_byte); } };; |
| table16[0xDF] = table32[0xDF] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) fpu.op_DF_mem(modrm_byte, modrm_resolve(modrm_byte)); else fpu.op_DF_reg(modrm_byte); } };; |
| table16[0xE0] = table32[0xE0] = function() { { loopne(); } };; |
| table16[0xE1] = table32[0xE1] = function() { { loope(); } };; |
| table16[0xE2] = table32[0xE2] = function() { { loop(); } };; |
| table16[0xE3] = table32[0xE3] = function() { { jcxz(); } };; |
| table16[0xE4] = table32[0xE4] = function() { { reg8[reg_al] = in8(read_imm8()); } };; |
| table16[0xE5] = function() { { reg16[reg_ax] = in16(read_imm8()); } }; table32[0xE5] = function() { { reg32[reg_eax] = in32(read_imm8()); } };; |
| table16[0xE6] = table32[0xE6] = function() { { out8(read_imm8(), reg8[reg_al]); } };; |
| table16[0xE7] = function() { { out16(read_imm8(), reg16[reg_ax]); } }; table32[0xE7] = function() { { out32(read_imm8(), reg32s[reg_eax]); } };; |
| table16[0xE8] = function() { { /* call*/ var imm16s = (read_imm16() << 16 >> 16); push16(get_real_ip()); jmp_rel16(imm16s); } }; table32[0xE8] = function() { { /* call*/ var imm32s = read_imm32s(); push32(get_real_ip()); instruction_pointer = instruction_pointer + imm32s | 0; } };; |
| table16[0xE9] = function() { { /* jmp*/ var imm16s = (read_imm16() << 16 >> 16); jmp_rel16(imm16s); } }; table32[0xE9] = function() { { /* jmp*/ var imm32s = read_imm32s(); instruction_pointer = instruction_pointer + imm32s | 0; } };; |
| table16[0xEA] = function() { { /* jmpf*/ var ip = read_imm16(); switch_seg(reg_cs, read_imm16()); instruction_pointer = ip + get_seg(reg_cs) | 0; } }; table32[0xEA] = function() { { /* jmpf*/ var ip = read_imm32s(); switch_seg(reg_cs, read_imm16()); instruction_pointer = ip + get_seg(reg_cs) | 0; } };; |
| table16[0xEB] = table32[0xEB] = function() { { /* jmp near*/ var imm8 = read_imm8s(); instruction_pointer = instruction_pointer + imm8 | 0; } };; |
| table16[0xEC] = table32[0xEC] = function() { { reg8[reg_al] = in8(reg16[reg_dx]); } };; |
| table16[0xED] = function() { { reg16[reg_ax] = in16(reg16[reg_dx]); } }; table32[0xED] = function() { { reg32[reg_eax] = in32(reg16[reg_dx]); } };; |
| table16[0xEE] = table32[0xEE] = function() { { out8(reg16[reg_dx], reg8[reg_al]); } };; |
| table16[0xEF] = function() { { out16(reg16[reg_dx], reg16[reg_ax]); } }; table32[0xEF] = function() { { out32(reg16[reg_dx], reg32s[reg_eax]); } };; |
| table16[0xF0] = table32[0xF0] = function() { { /* lock*/ /* TODO*/ /* This triggers UD when used with*/ /* some instructions that don't write to memory*/ } };; |
| table16[0xF1] = table32[0xF1] = function() { { /* INT1*/ /* https://code.google.com/p/corkami/wiki/x86oddities#IceBP*/ throw unimpl("int1 instruction"); } };; |
| table16[0xF2] = table32[0xF2] = function() { { /* repnz*/ dbg_assert(!repeat_string_prefix); repeat_string_prefix = true; repeat_string_type = false; table[read_imm8()](); repeat_string_prefix = false; } };; |
| table16[0xF3] = table32[0xF3] = function() { { /* repz*/ dbg_assert(!repeat_string_prefix); repeat_string_prefix = true; repeat_string_type = true; table[read_imm8()](); repeat_string_prefix = false; } };; |
| table16[0xF4] = table32[0xF4] = function() { { if(cpl) { trigger_gp(0); } /* hlt*/ if((flags & flag_interrupt) === 0) { log("cpu halted"); stopped = true; if(DEBUG) dump_regs(); throw "HALT"; } else { /* infinite loop until an irq happens*/ /* this is handled in call_interrupt_vector*/ instruction_pointer--; in_hlt = true; } } };; |
| table16[0xF5] = table32[0xF5] = function() { { /* cmc*/ flags = (flags | 1) ^ getcf(); flags_changed &= ~1; } };; |
| table16[0xF6] = table32[0xF6] = function() { var modrm_byte = read_imm8(); { switch(modrm_byte >> 3 & 7) { case 0: { if(modrm_byte < 0xC0) { var data = safe_read8(modrm_resolve(modrm_byte)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; }; test8(data, read_imm8()); }; break; case 1: { if(modrm_byte < 0xC0) { var data = safe_read8(modrm_resolve(modrm_byte)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; }; test8(data, read_imm8()); }; break; case 2: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, not8(data)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = not8(data); }; }; break; case 3: { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, neg8(data)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = neg8(data); }; }; break; case 4: { if(modrm_byte < 0xC0) { var data = safe_read8(modrm_resolve(modrm_byte)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; }; mul8(data); }; break; case 5: { if(modrm_byte < 0xC0) { var data = safe_read8s(modrm_resolve(modrm_byte)); } else { data = reg8s[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; }; imul8(data); }; break; case 6: { if(modrm_byte < 0xC0) { var data = safe_read8(modrm_resolve(modrm_byte)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; }; div8(data); }; break; case 7: { if(modrm_byte < 0xC0) { var data = safe_read8s(modrm_resolve(modrm_byte)); } else { data = reg8s[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; }; idiv8(data); }; break; } } };; |
| table16[0xF7] = function() { var modrm_byte = read_imm8(); { switch(modrm_byte >> 3 & 7) { case 0: { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; test16(data, read_imm16()); }; break; case 1: { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; test16(data, read_imm16()); }; break; case 2: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, not16(data)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, not16(data)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = not16(data); }; }; break; case 3: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, neg16(data)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, neg16(data)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = neg16(data); }; }; break; case 4: { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; mul16(data); }; break; case 5: { if(modrm_byte < 0xC0) { var data = (safe_read16(modrm_resolve(modrm_byte)) << 16 >> 16); } else { data = reg16s[modrm_byte << 1 & 14]; }; imul16(data); }; break; case 6: { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; div16(data); }; break; case 7: { if(modrm_byte < 0xC0) { var data = (safe_read16(modrm_resolve(modrm_byte)) << 16 >> 16); } else { data = reg16s[modrm_byte << 1 & 14]; }; idiv16(data); }; break; } } }; table32[0xF7] = function() { var modrm_byte = read_imm8(); { switch(modrm_byte >> 3 & 7) { case 0: { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; test32(data, read_imm32s()); }; break; case 1: { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; test32(data, read_imm32s()); }; break; case 2: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, not32(data)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, not32(data)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = not32(data); }; }; break; case 3: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, neg32(data)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, neg32(data)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = neg32(data); }; }; break; case 4: { if(modrm_byte < 0xC0) { var data = (safe_read32s(modrm_resolve(modrm_byte)) >>> 0); } else { data = reg32[modrm_byte & 7]; }; mul32(data); }; break; case 5: { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; imul32(data); }; break; case 6: { if(modrm_byte < 0xC0) { var data = (safe_read32s(modrm_resolve(modrm_byte)) >>> 0); } else { data = reg32[modrm_byte & 7]; }; div32(data); }; break; case 7: { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; idiv32(data); }; break; } } };; |
| table16[0xF8] = table32[0xF8] = function() { { /* clc*/ flags &= ~flag_carry; flags_changed &= ~1; } };; |
| table16[0xF9] = table32[0xF9] = function() { { /* stc*/ flags |= flag_carry; flags_changed &= ~1; } };; |
| table16[0xFA] = table32[0xFA] = function() { { /* cli*/ /*dbg_log("interrupts off");*/ if(!privileges_for_io()) { trigger_gp(0); } else { flags &= ~flag_interrupt; } } };; |
| table16[0xFB] = table32[0xFB] = function() { { /* sti*/ /*dbg_log("interrupts on");*/ if(!privileges_for_io()) { trigger_gp(0); } else { flags |= flag_interrupt; handle_irqs(); } } };; |
| table16[0xFC] = table32[0xFC] = function() { { /* cld*/ flags &= ~flag_direction; } };; |
| table16[0xFD] = table32[0xFD] = function() { { /* std*/ flags |= flag_direction; } };; |
| table16[0xFE] = table32[0xFE] = function() { var modrm_byte = read_imm8(); { var mod = modrm_byte & 56; if(mod === 0) { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, inc8(data)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = inc8(data); }; } else if(mod === 8) { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, dec8(data)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = dec8(data); }; } else { if(DEBUG) { dbg_trace(); throw "TODO"; } trigger_ud();; } } };; |
| table16[0xFF] = function() { var modrm_byte = read_imm8(); { switch(modrm_byte >> 3 & 7) { case 0: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, inc16(data)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, inc16(data)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = inc16(data); }; }; break; case 1: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, dec16(data)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, dec16(data)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = dec16(data); }; }; break; case 2: { /* 2, call near*/ if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; push16(get_real_ip()); instruction_pointer = get_seg(reg_cs) + data | 0; }; break; case 3: { /* 3, callf*/ if(modrm_byte >= 0xC0) { raise_exception(6); dbg_assert(false); } var virt_addr = modrm_resolve(modrm_byte); push16(sreg[reg_cs]); push16(get_real_ip()); switch_seg(reg_cs, safe_read16(virt_addr + 2)); instruction_pointer = get_seg(reg_cs) + safe_read16(virt_addr) | 0; dbg_assert(!page_fault); }; break; case 4: { /* 4, jmp near*/ if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; instruction_pointer = get_seg(reg_cs) + data | 0; }; break; case 5: { /* 5, jmpf*/ if(modrm_byte >= 0xC0) { raise_exception(6); dbg_assert(false); } var virt_addr = modrm_resolve(modrm_byte); switch_seg(reg_cs, safe_read16(virt_addr + 2)); instruction_pointer = get_seg(reg_cs) + safe_read16(virt_addr) | 0; /* TODO safe read*/ }; break; case 6: { /* 6, push*/ if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; push16(data); }; break; case 7: { if(DEBUG) { dbg_trace(); throw "TODO"; } trigger_ud();; }; break; } } }; table32[0xFF] = function() { var modrm_byte = read_imm8(); { switch(modrm_byte >> 3 & 7) { case 0: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, inc32(data)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, inc32(data)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = inc32(data); }; }; break; case 1: { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, dec32(data)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, dec32(data)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = dec32(data); }; }; break; case 2: { /* 2, call near*/ if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; push32(get_real_ip()); instruction_pointer = get_seg(reg_cs) + data | 0; }; break; case 3: { /* 3, callf*/ if(modrm_byte >= 0xC0) { raise_exception(6); dbg_assert(false); } var virt_addr = modrm_resolve(modrm_byte); var new_cs = safe_read16(virt_addr + 4); var new_ip = safe_read32s(virt_addr); push32(sreg[reg_cs]); push32(get_real_ip()); switch_seg(reg_cs, new_cs); instruction_pointer = get_seg(reg_cs) + new_ip | 0; }; break; case 4: { /* 4, jmp near*/ if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; instruction_pointer = get_seg(reg_cs) + data | 0; }; break; case 5: { /* 5, jmpf*/ if(modrm_byte >= 0xC0) { raise_exception(6); dbg_assert(false); } var virt_addr = modrm_resolve(modrm_byte); var new_cs = safe_read16(virt_addr + 4); var new_ip = safe_read32s(virt_addr); switch_seg(reg_cs, new_cs); instruction_pointer = get_seg(reg_cs) + new_ip | 0; }; break; case 6: { /* push*/ if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; push32(data); }; break; case 7: { if(DEBUG) { dbg_trace(); throw "TODO"; } trigger_ud();; }; break; } } };; |
| // 0F ops start here |
| table0F_16[0x00] = table0F_32[0x00] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; if(!protected_mode) { /* No GP, UD is correct*/ trigger_ud(); } if(cpl) { trigger_gp(0); } switch(modrm_byte >> 3 & 7) { case 2: load_ldt(data); break; case 3: load_tr(data); break; default: dbg_log(modrm_byte >> 3 & 7, LOG_CPU); if(DEBUG) { dbg_trace(); throw "TODO"; } trigger_ud();; } } };; |
| table0F_16[0x01] = table0F_32[0x01] = function() { var modrm_byte = read_imm8(); { if(cpl) { trigger_gp(0); } var mod = modrm_byte >> 3 & 7; if(mod === 4) { /* smsw*/ if(modrm_byte < 0xC0) { safe_write16(modrm_resolve(modrm_byte), cr0); } else { reg16[modrm_byte << 1 & 14] = cr0; }; return; } else if(mod === 6) { /* lmsw*/ if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; cr0 = (cr0 & ~0xF) | (data & 0xF); cr0_changed(); return; } if(modrm_byte >= 0xC0) { /* only memory*/ raise_exception(6); dbg_assert(false); } if((mod === 2 || mod === 3) && protected_mode) { /* override prefix, so modrm_resolve does not return the segment part*/ /* only lgdt and lidt and only in protected mode*/ segment_prefix = reg_noseg; } var addr = modrm_resolve(modrm_byte); segment_prefix = -1; switch(mod) { case 0: /* sgdt*/ safe_write16(addr, gdtr_size); safe_write32(addr + 2, gdtr_offset); break; case 1: /* sidt*/ safe_write16(addr, idtr_size); safe_write32(addr + 2, idtr_offset); break; case 2: /* lgdt*/ var size = safe_read16(addr); var offset = safe_read32s(addr + 2); gdtr_size = size; gdtr_offset = offset; if(!operand_size_32) { gdtr_offset &= 0xFFFFFF; } dbg_log("eax " + h(reg32[reg_eax]), LOG_CPU); dbg_log("gdt loaded from " + h(addr), LOG_CPU); dbg_log("gdt at " + h(gdtr_offset) + ", " + gdtr_size + " bytes", LOG_CPU); /*dump_gdt_ldt();*/ break; case 3: /* lidt*/ var size = safe_read16(addr); var offset = safe_read32s(addr + 2); idtr_size = size; idtr_offset = offset; if(!operand_size_32) { idtr_offset &= 0xFFFFFF; } /*dbg_log("[" + h(instruction_pointer) + "] idt at " + */ /* h(idtr_offset) + ", " + idtr_size + " bytes " + h(addr), LOG_CPU);*/ break; case 7: /* flush translation lookaside buffer*/ invlpg(addr); break; default: dbg_log(mod); if(DEBUG) { dbg_trace(); throw "TODO"; } trigger_ud();; } } };; |
| table0F_16[0x02] = table0F_32[0x02] = function() { var modrm_byte = read_imm8(); { if(DEBUG) { dbg_trace(); throw "TODO"; } trigger_ud();; /* lar*/ } };; |
| table0F_16[0x03] = table0F_32[0x03] = function() { var modrm_byte = read_imm8(); { if(DEBUG) { dbg_trace(); throw "TODO"; } trigger_ud();; /* lsl*/ } };; |
| table0F_16[0x04] = table0F_32[0x04] = function() { { if(DEBUG) throw "Possible fault: undefined instruction"; trigger_ud();} };; |
| table0F_16[0x05] = table0F_32[0x05] = function() { { if(DEBUG) throw "Possible fault: undefined instruction"; trigger_ud();} };; |
| table0F_16[0x06] = table0F_32[0x06] = function() { { /* clts*/ if(cpl) { trigger_gp(0); } else { /*dbg_log("clts", LOG_CPU);*/ cr0 &= ~8; /* do something here ?*/ } } };; |
| table0F_16[0x07] = table0F_32[0x07] = function() { { if(DEBUG) throw "Possible fault: undefined instruction"; trigger_ud();} };; |
| // invd |
| table0F_16[0x08] = table0F_32[0x08] = function() { { if(DEBUG) { dbg_trace(); throw "TODO"; } trigger_ud();;} };; |
| table0F_16[0x09] = table0F_32[0x09] = function() { { if(cpl) { trigger_gp(0); } /* wbinvd*/ } };; |
| table0F_16[0x0A] = table0F_32[0x0A] = function() { { if(DEBUG) throw "Possible fault: undefined instruction"; trigger_ud();} };; |
| table0F_16[0x0B] = table0F_32[0x0B] = function() { { trigger_ud(); } };; |
| table0F_16[0x0C] = table0F_32[0x0C] = function() { { if(DEBUG) throw "Possible fault: undefined instruction"; trigger_ud();} };; |
| table0F_16[0x0D] = table0F_32[0x0D] = function() { { if(DEBUG) { dbg_trace(); throw "TODO"; } trigger_ud();;} };; |
| table0F_16[0x0E] = table0F_32[0x0E] = function() { { if(DEBUG) throw "Possible fault: undefined instruction"; trigger_ud();} };; |
| table0F_16[0x0F] = table0F_32[0x0F] = function() { { if(DEBUG) throw "Possible fault: undefined instruction"; trigger_ud();} };; |
| table0F_16[0x10] = table0F_32[0x10] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x11] = table0F_32[0x11] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x12] = table0F_32[0x12] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x13] = table0F_32[0x13] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x14] = table0F_32[0x14] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x15] = table0F_32[0x15] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x16] = table0F_32[0x16] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x17] = table0F_32[0x17] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x18] = table0F_32[0x18] = function() { var modrm_byte = read_imm8(); { /* prefetch*/ /* nop for us */ if(operand_size_32) { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; } else { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; } } };; |
| table0F_16[0x19] = table0F_32[0x19] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x1A] = table0F_32[0x1A] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x1B] = table0F_32[0x1B] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x1C] = table0F_32[0x1C] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x1D] = table0F_32[0x1D] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x1E] = table0F_32[0x1E] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x1F] = table0F_32[0x1F] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x20] = table0F_32[0x20] = function() { var modrm_byte = read_imm8(); { if(cpl) { trigger_gp(0); } /*dbg_log("cr" + mod + " read", LOG_CPU);*/ /* mov addr, cr*/ /* mod = which control register*/ switch(modrm_byte >> 3 & 7) { case 0: reg32[modrm_byte & 7] = cr0; break; case 2: reg32[modrm_byte & 7] = cr2; break; case 3: /*dbg_log("read cr3 (" + h(cr3, 8) + ")", LOG_CPU);*/ reg32[modrm_byte & 7] = cr3; break; case 4: reg32[modrm_byte & 7] = cr4; break; default: dbg_log(modrm_byte >> 3 & 7); if(DEBUG) { dbg_trace(); throw "TODO"; } trigger_ud();; } } };; |
| table0F_16[0x21] = table0F_32[0x21] = function() { var modrm_byte = read_imm8(); { if(cpl) { trigger_gp(0); } /* TODO: mov from debug register*/ dbg_assert(modrm_byte >= 0xC0); } };; |
| table0F_16[0x22] = table0F_32[0x22] = function() { var modrm_byte = read_imm8(); { if(cpl) { trigger_gp(0); } var data = reg32[modrm_byte & 7]; /*dbg_log("cr" + mod + " written: " + h(reg32[reg]), LOG_CPU);*/ /* mov cr, addr*/ /* mod = which control register*/ switch(modrm_byte >> 3 & 7) { case 0: if((data & 0x80000001) === (0x80000000 | 0)) { /* cannot load PG without PE*/ throw unimpl("#GP handler"); } if((cr0 & 0x80000000) && !(data & 0x80000000)) { full_clear_tlb(); } cr0 = data; cr0_changed(); /*dbg_log("cr1 = " + bits(memory.read32s(addr)), LOG_CPU);*/ break; case 3: cr3 = data; dbg_assert((cr3 & 0xFFF) === 0); clear_tlb(); /*dump_page_directory();*/ /*dbg_log("page directory loaded at " + h(cr3, 8), LOG_CPU);*/ break; case 4: if((cr4 ^ data) & 128) { full_clear_tlb(); } cr4 = data; page_size_extensions = (cr4 & 16) ? PSE_ENABLED : 0; dbg_log("cr4 set to " + h(cr4), LOG_CPU); break; default: dbg_log(modrm_byte >> 3 & 7); if(DEBUG) { dbg_trace(); throw "TODO"; } trigger_ud();; } } };; |
| table0F_16[0x23] = table0F_32[0x23] = function() { var modrm_byte = read_imm8(); { if(cpl) { trigger_gp(0); } /* TODO: mov to debug register*/ dbg_assert(modrm_byte >= 0xC0); } };; |
| table0F_16[0x24] = table0F_32[0x24] = function() { { if(DEBUG) throw "Possible fault: undefined instruction"; trigger_ud();} };; |
| table0F_16[0x25] = table0F_32[0x25] = function() { { if(DEBUG) throw "Possible fault: undefined instruction"; trigger_ud();} };; |
| table0F_16[0x26] = table0F_32[0x26] = function() { { if(DEBUG) throw "Possible fault: undefined instruction"; trigger_ud();} };; |
| table0F_16[0x27] = table0F_32[0x27] = function() { { if(DEBUG) throw "Possible fault: undefined instruction"; trigger_ud();} };; |
| table0F_16[0x28] = table0F_32[0x28] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x29] = table0F_32[0x29] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x2A] = table0F_32[0x2A] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x2B] = table0F_32[0x2B] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x2C] = table0F_32[0x2C] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x2D] = table0F_32[0x2D] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x2E] = table0F_32[0x2E] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x2F] = table0F_32[0x2F] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| // wrmsr |
| table0F_16[0x30] = table0F_32[0x30] = function() { { if(DEBUG) { dbg_trace(); throw "TODO"; } trigger_ud();;} };; |
| table0F_16[0x31] = table0F_32[0x31] = function() { { /* rdtsc - read timestamp counter*/ /*var cycles = (Date.now() - emulation_start) / 1000 * 3000000;*/ /*reg32[reg_eax] = cycles;*/ /*reg32[reg_edx] = cycles / 0x100000000;*/ reg32[reg_eax] = cpu_timestamp_counter; reg32[reg_edx] = cpu_timestamp_counter / 0x100000000; } };; |
| // rdmsr |
| table0F_16[0x32] = table0F_32[0x32] = function() { { if(DEBUG) { dbg_trace(); throw "TODO"; } trigger_ud();;} };; |
| // rdpmc |
| table0F_16[0x33] = table0F_32[0x33] = function() { { if(DEBUG) { dbg_trace(); throw "TODO"; } trigger_ud();;} };; |
| // sysenter |
| table0F_16[0x34] = table0F_32[0x34] = function() { { if(DEBUG) { dbg_trace(); throw "TODO"; } trigger_ud();;} };; |
| // sysexit |
| table0F_16[0x35] = table0F_32[0x35] = function() { { if(DEBUG) { dbg_trace(); throw "TODO"; } trigger_ud();;} };; |
| table0F_16[0x36] = table0F_32[0x36] = function() { { if(DEBUG) throw "Possible fault: undefined instruction"; trigger_ud();} };; |
| // getsec |
| table0F_16[0x37] = table0F_32[0x37] = function() { { if(DEBUG) { dbg_trace(); throw "TODO"; } trigger_ud();;} };; |
| table0F_16[0x38] = table0F_32[0x38] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x39] = table0F_32[0x39] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x3A] = table0F_32[0x3A] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x3B] = table0F_32[0x3B] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x3C] = table0F_32[0x3C] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x3D] = table0F_32[0x3D] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x3E] = table0F_32[0x3E] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x3F] = table0F_32[0x3F] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x40 | 0x0] = function() { var modrm_byte = read_imm8(); { if((test_o())) { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } }; table0F_32[0x40 | 0x0] = function() { var modrm_byte = read_imm8(); { if((test_o())) { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } };;; table0F_16[0x40 | 0x1] = function() { var modrm_byte = read_imm8(); { if((!test_o())) { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } }; table0F_32[0x40 | 0x1] = function() { var modrm_byte = read_imm8(); { if((!test_o())) { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } };;; table0F_16[0x40 | 0x2] = function() { var modrm_byte = read_imm8(); { if((test_b())) { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } }; table0F_32[0x40 | 0x2] = function() { var modrm_byte = read_imm8(); { if((test_b())) { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } };;; table0F_16[0x40 | 0x3] = function() { var modrm_byte = read_imm8(); { if((!test_b())) { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } }; table0F_32[0x40 | 0x3] = function() { var modrm_byte = read_imm8(); { if((!test_b())) { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } };;; table0F_16[0x40 | 0x4] = function() { var modrm_byte = read_imm8(); { if((test_z())) { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } }; table0F_32[0x40 | 0x4] = function() { var modrm_byte = read_imm8(); { if((test_z())) { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } };;; table0F_16[0x40 | 0x5] = function() { var modrm_byte = read_imm8(); { if((!test_z())) { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } }; table0F_32[0x40 | 0x5] = function() { var modrm_byte = read_imm8(); { if((!test_z())) { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } };;; table0F_16[0x40 | 0x6] = function() { var modrm_byte = read_imm8(); { if((test_be())) { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } }; table0F_32[0x40 | 0x6] = function() { var modrm_byte = read_imm8(); { if((test_be())) { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } };;; table0F_16[0x40 | 0x7] = function() { var modrm_byte = read_imm8(); { if((!test_be())) { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } }; table0F_32[0x40 | 0x7] = function() { var modrm_byte = read_imm8(); { if((!test_be())) { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } };;; table0F_16[0x40 | 0x8] = function() { var modrm_byte = read_imm8(); { if((test_s())) { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } }; table0F_32[0x40 | 0x8] = function() { var modrm_byte = read_imm8(); { if((test_s())) { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } };;; table0F_16[0x40 | 0x9] = function() { var modrm_byte = read_imm8(); { if((!test_s())) { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } }; table0F_32[0x40 | 0x9] = function() { var modrm_byte = read_imm8(); { if((!test_s())) { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } };;; table0F_16[0x40 | 0xA] = function() { var modrm_byte = read_imm8(); { if((test_p())) { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } }; table0F_32[0x40 | 0xA] = function() { var modrm_byte = read_imm8(); { if((test_p())) { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } };;; table0F_16[0x40 | 0xB] = function() { var modrm_byte = read_imm8(); { if((!test_p())) { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } }; table0F_32[0x40 | 0xB] = function() { var modrm_byte = read_imm8(); { if((!test_p())) { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } };;; table0F_16[0x40 | 0xC] = function() { var modrm_byte = read_imm8(); { if((test_l())) { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } }; table0F_32[0x40 | 0xC] = function() { var modrm_byte = read_imm8(); { if((test_l())) { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } };;; table0F_16[0x40 | 0xD] = function() { var modrm_byte = read_imm8(); { if((!test_l())) { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } }; table0F_32[0x40 | 0xD] = function() { var modrm_byte = read_imm8(); { if((!test_l())) { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } };;; table0F_16[0x40 | 0xE] = function() { var modrm_byte = read_imm8(); { if((test_le())) { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } }; table0F_32[0x40 | 0xE] = function() { var modrm_byte = read_imm8(); { if((test_le())) { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } };;; table0F_16[0x40 | 0xF] = function() { var modrm_byte = read_imm8(); { if((!test_le())) { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } }; table0F_32[0x40 | 0xF] = function() { var modrm_byte = read_imm8(); { if((!test_le())) { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32s[modrm_byte >> 3 & 7] = data; } else if(modrm_byte < 0xC0) modrm_resolve(modrm_byte) } };;;; |
| table0F_16[0x50] = table0F_32[0x50] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x51] = table0F_32[0x51] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x52] = table0F_32[0x52] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x53] = table0F_32[0x53] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x54] = table0F_32[0x54] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x55] = table0F_32[0x55] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x56] = table0F_32[0x56] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x57] = table0F_32[0x57] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x58] = table0F_32[0x58] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x59] = table0F_32[0x59] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x5A] = table0F_32[0x5A] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x5B] = table0F_32[0x5B] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x5C] = table0F_32[0x5C] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x5D] = table0F_32[0x5D] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x5E] = table0F_32[0x5E] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x5F] = table0F_32[0x5F] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x60] = table0F_32[0x60] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x61] = table0F_32[0x61] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x62] = table0F_32[0x62] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x63] = table0F_32[0x63] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x64] = table0F_32[0x64] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x65] = table0F_32[0x65] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x66] = table0F_32[0x66] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x67] = table0F_32[0x67] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x68] = table0F_32[0x68] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x69] = table0F_32[0x69] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x6A] = table0F_32[0x6A] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x6B] = table0F_32[0x6B] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x6C] = table0F_32[0x6C] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x6D] = table0F_32[0x6D] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x6E] = table0F_32[0x6E] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x6F] = table0F_32[0x6F] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x70] = table0F_32[0x70] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x71] = table0F_32[0x71] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x72] = table0F_32[0x72] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x73] = table0F_32[0x73] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x74] = table0F_32[0x74] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x75] = table0F_32[0x75] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x76] = table0F_32[0x76] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x77] = table0F_32[0x77] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x78] = table0F_32[0x78] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x79] = table0F_32[0x79] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x7A] = table0F_32[0x7A] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x7B] = table0F_32[0x7B] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x7C] = table0F_32[0x7C] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x7D] = table0F_32[0x7D] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x7E] = table0F_32[0x7E] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x7F] = table0F_32[0x7F] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0x80 | 0x0] = function() { { jmpcc16((test_o())); } }; table0F_32[0x80 | 0x0] = function() { { jmpcc32((test_o())); } };; table0F_16[0x80 | 0x1] = function() { { jmpcc16((!test_o())); } }; table0F_32[0x80 | 0x1] = function() { { jmpcc32((!test_o())); } };; table0F_16[0x80 | 0x2] = function() { { jmpcc16((test_b())); } }; table0F_32[0x80 | 0x2] = function() { { jmpcc32((test_b())); } };; table0F_16[0x80 | 0x3] = function() { { jmpcc16((!test_b())); } }; table0F_32[0x80 | 0x3] = function() { { jmpcc32((!test_b())); } };; table0F_16[0x80 | 0x4] = function() { { jmpcc16((test_z())); } }; table0F_32[0x80 | 0x4] = function() { { jmpcc32((test_z())); } };; table0F_16[0x80 | 0x5] = function() { { jmpcc16((!test_z())); } }; table0F_32[0x80 | 0x5] = function() { { jmpcc32((!test_z())); } };; table0F_16[0x80 | 0x6] = function() { { jmpcc16((test_be())); } }; table0F_32[0x80 | 0x6] = function() { { jmpcc32((test_be())); } };; table0F_16[0x80 | 0x7] = function() { { jmpcc16((!test_be())); } }; table0F_32[0x80 | 0x7] = function() { { jmpcc32((!test_be())); } };; table0F_16[0x80 | 0x8] = function() { { jmpcc16((test_s())); } }; table0F_32[0x80 | 0x8] = function() { { jmpcc32((test_s())); } };; table0F_16[0x80 | 0x9] = function() { { jmpcc16((!test_s())); } }; table0F_32[0x80 | 0x9] = function() { { jmpcc32((!test_s())); } };; table0F_16[0x80 | 0xA] = function() { { jmpcc16((test_p())); } }; table0F_32[0x80 | 0xA] = function() { { jmpcc32((test_p())); } };; table0F_16[0x80 | 0xB] = function() { { jmpcc16((!test_p())); } }; table0F_32[0x80 | 0xB] = function() { { jmpcc32((!test_p())); } };; table0F_16[0x80 | 0xC] = function() { { jmpcc16((test_l())); } }; table0F_32[0x80 | 0xC] = function() { { jmpcc32((test_l())); } };; table0F_16[0x80 | 0xD] = function() { { jmpcc16((!test_l())); } }; table0F_32[0x80 | 0xD] = function() { { jmpcc32((!test_l())); } };; table0F_16[0x80 | 0xE] = function() { { jmpcc16((test_le())); } }; table0F_32[0x80 | 0xE] = function() { { jmpcc32((test_le())); } };; table0F_16[0x80 | 0xF] = function() { { jmpcc16((!test_le())); } }; table0F_32[0x80 | 0xF] = function() { { jmpcc32((!test_le())); } };; |
| table0F_16[0x90 | 0x0] = table0F_32[0x90 | 0x0] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write8(modrm_resolve(modrm_byte), !(test_o()) ^ 1); } else { reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = !(test_o()) ^ 1; }; } };;; table0F_16[0x90 | 0x1] = table0F_32[0x90 | 0x1] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write8(modrm_resolve(modrm_byte), !(!test_o()) ^ 1); } else { reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = !(!test_o()) ^ 1; }; } };;; table0F_16[0x90 | 0x2] = table0F_32[0x90 | 0x2] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write8(modrm_resolve(modrm_byte), !(test_b()) ^ 1); } else { reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = !(test_b()) ^ 1; }; } };;; table0F_16[0x90 | 0x3] = table0F_32[0x90 | 0x3] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write8(modrm_resolve(modrm_byte), !(!test_b()) ^ 1); } else { reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = !(!test_b()) ^ 1; }; } };;; table0F_16[0x90 | 0x4] = table0F_32[0x90 | 0x4] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write8(modrm_resolve(modrm_byte), !(test_z()) ^ 1); } else { reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = !(test_z()) ^ 1; }; } };;; table0F_16[0x90 | 0x5] = table0F_32[0x90 | 0x5] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write8(modrm_resolve(modrm_byte), !(!test_z()) ^ 1); } else { reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = !(!test_z()) ^ 1; }; } };;; table0F_16[0x90 | 0x6] = table0F_32[0x90 | 0x6] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write8(modrm_resolve(modrm_byte), !(test_be()) ^ 1); } else { reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = !(test_be()) ^ 1; }; } };;; table0F_16[0x90 | 0x7] = table0F_32[0x90 | 0x7] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write8(modrm_resolve(modrm_byte), !(!test_be()) ^ 1); } else { reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = !(!test_be()) ^ 1; }; } };;; table0F_16[0x90 | 0x8] = table0F_32[0x90 | 0x8] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write8(modrm_resolve(modrm_byte), !(test_s()) ^ 1); } else { reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = !(test_s()) ^ 1; }; } };;; table0F_16[0x90 | 0x9] = table0F_32[0x90 | 0x9] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write8(modrm_resolve(modrm_byte), !(!test_s()) ^ 1); } else { reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = !(!test_s()) ^ 1; }; } };;; table0F_16[0x90 | 0xA] = table0F_32[0x90 | 0xA] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write8(modrm_resolve(modrm_byte), !(test_p()) ^ 1); } else { reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = !(test_p()) ^ 1; }; } };;; table0F_16[0x90 | 0xB] = table0F_32[0x90 | 0xB] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write8(modrm_resolve(modrm_byte), !(!test_p()) ^ 1); } else { reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = !(!test_p()) ^ 1; }; } };;; table0F_16[0x90 | 0xC] = table0F_32[0x90 | 0xC] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write8(modrm_resolve(modrm_byte), !(test_l()) ^ 1); } else { reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = !(test_l()) ^ 1; }; } };;; table0F_16[0x90 | 0xD] = table0F_32[0x90 | 0xD] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write8(modrm_resolve(modrm_byte), !(!test_l()) ^ 1); } else { reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = !(!test_l()) ^ 1; }; } };;; table0F_16[0x90 | 0xE] = table0F_32[0x90 | 0xE] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write8(modrm_resolve(modrm_byte), !(test_le()) ^ 1); } else { reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = !(test_le()) ^ 1; }; } };;; table0F_16[0x90 | 0xF] = table0F_32[0x90 | 0xF] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { safe_write8(modrm_resolve(modrm_byte), !(!test_le()) ^ 1); } else { reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = !(!test_le()) ^ 1; }; } };;;; |
| table0F_16[0xA0] = function() { { push16(sreg[reg_fs]); } }; table0F_32[0xA0] = function() { { push32(sreg[reg_fs]); } };; |
| table0F_16[0xA1] = function() { { switch_seg(reg_fs, memory.read16(get_esp_read(0))); stack_reg[reg_vsp] += 2; } }; table0F_32[0xA1] = function() { { switch_seg(reg_fs, memory.read16(get_esp_read(0))); stack_reg[reg_vsp] += 4; } };;; |
| //op2(0xA1, |
| // { safe_pop16(sreg[reg_fs]); switch_seg(reg_fs); }, |
| // { safe_pop32s(sreg[reg_fs]); switch_seg(reg_fs); }); |
| table0F_16[0xA2] = table0F_32[0xA2] = function() { { cpuid(); } };; |
| table0F_16[0xA3] = table0F_32[0xA3] = function() { var modrm_byte = read_imm8(); { if(operand_size_32) { if(modrm_byte < 0xC0) { bt_mem(modrm_resolve(modrm_byte), reg32s[modrm_byte >> 3 & 7]); } else { bt_reg(reg32[modrm_byte & 7], reg32[modrm_byte >> 3 & 7] & 31); } } else { if(modrm_byte < 0xC0) { bt_mem(modrm_resolve(modrm_byte), reg16s[modrm_byte >> 2 & 14]); } else { bt_reg(reg16[modrm_byte << 1 & 14], reg16[modrm_byte >> 2 & 14] & 15); } } } };; |
| table0F_16[0xA4] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, shld16(data, reg16[modrm_byte >> 2 & 14], read_imm8() & 31)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, shld16(data, reg16[modrm_byte >> 2 & 14], read_imm8() & 31)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = shld16(data, reg16[modrm_byte >> 2 & 14], read_imm8() & 31); }; } }; table0F_32[0xA4] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, shld32(data, reg32[modrm_byte >> 3 & 7], read_imm8() & 31)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, shld32(data, reg32[modrm_byte >> 3 & 7], read_imm8() & 31)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = shld32(data, reg32[modrm_byte >> 3 & 7], read_imm8() & 31); }; } };; |
| table0F_16[0xA5] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, shld16(data, reg16[modrm_byte >> 2 & 14], reg8[reg_cl] & 31)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, shld16(data, reg16[modrm_byte >> 2 & 14], reg8[reg_cl] & 31)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = shld16(data, reg16[modrm_byte >> 2 & 14], reg8[reg_cl] & 31); }; } }; table0F_32[0xA5] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, shld32(data, reg32[modrm_byte >> 3 & 7], reg8[reg_cl] & 31)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, shld32(data, reg32[modrm_byte >> 3 & 7], reg8[reg_cl] & 31)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = shld32(data, reg32[modrm_byte >> 3 & 7], reg8[reg_cl] & 31); }; } };; |
| table0F_16[0xA6] = table0F_32[0xA6] = function() { { if(DEBUG) throw "Possible fault: undefined instruction"; trigger_ud();} };; |
| table0F_16[0xA7] = table0F_32[0xA7] = function() { { if(DEBUG) throw "Possible fault: undefined instruction"; trigger_ud();} };; |
| table0F_16[0xA8] = function() { { push16(sreg[reg_gs]); } }; table0F_32[0xA8] = function() { { push32(sreg[reg_gs]); } };; |
| table0F_16[0xA9] = function() { { switch_seg(reg_gs, memory.read16(get_esp_read(0))); stack_reg[reg_vsp] += 2; } }; table0F_32[0xA9] = function() { { switch_seg(reg_gs, memory.read16(get_esp_read(0))); stack_reg[reg_vsp] += 4; } };;; |
| //op2(0xA9, |
| // { safe_pop16(sreg[reg_gs]); switch_seg(reg_gs); }, |
| // { safe_pop32s(sreg[reg_gs]); switch_seg(reg_gs); }); |
| // rsm |
| table0F_16[0xAA] = table0F_32[0xAA] = function() { { if(DEBUG) { dbg_trace(); throw "TODO"; } trigger_ud();;} };; |
| table0F_16[0xAB] = table0F_32[0xAB] = function() { var modrm_byte = read_imm8(); { if(operand_size_32) { if(modrm_byte < 0xC0) { bts_mem(modrm_resolve(modrm_byte), reg32s[modrm_byte >> 3 & 7]); } else { reg32[modrm_byte & 7] = bts_reg(reg32s[modrm_byte & 7], reg32s[modrm_byte >> 3 & 7] & 31); } } else { if(modrm_byte < 0xC0) { bts_mem(modrm_resolve(modrm_byte), reg16s[modrm_byte >> 2 & 14]); } else { reg16[modrm_byte << 1 & 14] = bts_reg(reg16[modrm_byte << 1 & 14], reg16s[modrm_byte >> 2 & 14] & 15); } }; } };; |
| table0F_16[0xAC] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, shrd16(data, reg16[modrm_byte >> 2 & 14], read_imm8() & 31)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, shrd16(data, reg16[modrm_byte >> 2 & 14], read_imm8() & 31)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = shrd16(data, reg16[modrm_byte >> 2 & 14], read_imm8() & 31); }; } }; table0F_32[0xAC] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, shrd32(data, reg32[modrm_byte >> 3 & 7], read_imm8() & 31)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, shrd32(data, reg32[modrm_byte >> 3 & 7], read_imm8() & 31)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = shrd32(data, reg32[modrm_byte >> 3 & 7], read_imm8() & 31); }; } };; |
| table0F_16[0xAD] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, shrd16(data, reg16[modrm_byte >> 2 & 14], reg8[reg_cl] & 31)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, shrd16(data, reg16[modrm_byte >> 2 & 14], reg8[reg_cl] & 31)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = shrd16(data, reg16[modrm_byte >> 2 & 14], reg8[reg_cl] & 31); }; } }; table0F_32[0xAD] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, shrd32(data, reg32[modrm_byte >> 3 & 7], reg8[reg_cl] & 31)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, shrd32(data, reg32[modrm_byte >> 3 & 7], reg8[reg_cl] & 31)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = shrd32(data, reg32[modrm_byte >> 3 & 7], reg8[reg_cl] & 31); }; } };; |
| table0F_16[0xAE] = table0F_32[0xAE] = function() { { if(DEBUG) { dbg_trace(); throw "TODO"; } trigger_ud();;} };; |
| table0F_16[0xAF] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = (safe_read16(modrm_resolve(modrm_byte)) << 16 >> 16); } else { data = reg16s[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = imul_reg16(reg16s[modrm_byte >> 2 & 14], data); } }; table0F_32[0xAF] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32[modrm_byte >> 3 & 7] = imul_reg32(reg32s[modrm_byte >> 3 & 7], data); } };; |
| table0F_16[0xB0] = table0F_32[0xB0] = function() { var modrm_byte = read_imm8(); { /* cmpxchg8*/ if(modrm_byte < 0xC0) { var virt_addr = modrm_resolve(modrm_byte); var data = safe_read8(virt_addr); } else data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; cmp8(data, reg8[reg_al]); if(getzf()) { if(modrm_byte < 0xC0) safe_write8(virt_addr, reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1]); else reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = reg8[modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1]; } else { reg8[reg_al] = data; } } };; |
| table0F_16[0xB1] = table0F_32[0xB1] = function() { var modrm_byte = read_imm8(); { /* cmpxchg16/32*/ if(operand_size_32) { if(modrm_byte < 0xC0) { var virt_addr = modrm_resolve(modrm_byte); var data = (safe_read32s(virt_addr) >>> 0); } else data = reg32[modrm_byte & 7]; cmp32(data, reg32[reg_eax]); if(getzf()) { if(modrm_byte < 0xC0) safe_write32(virt_addr, reg32[modrm_byte >> 3 & 7]); else reg32[modrm_byte & 7] = reg32[modrm_byte >> 3 & 7]; } else { reg32[reg_eax] = data; } } else { if(modrm_byte < 0xC0) { var virt_addr = modrm_resolve(modrm_byte); var data = safe_read16(virt_addr); } else data = reg16[modrm_byte << 1 & 14]; cmp16(data, reg16[reg_ax]); if(getzf()) { if(modrm_byte < 0xC0) safe_write16(virt_addr, reg16[modrm_byte >> 2 & 14]); else reg16[modrm_byte << 1 & 14] = reg16[modrm_byte >> 2 & 14]; } else { reg16[reg_ax] = data; } } } };; |
| // lss |
| table0F_16[0xB2] = table0F_32[0xB2] = function() { var modrm_byte = read_imm8(); { if(modrm_byte >= 0xC0) { raise_exception(6); return; } if(operand_size_32) { lss32(reg_ss, modrm_resolve(modrm_byte), modrm_byte >> 3 & 7); } else { lss16(reg_ss, modrm_resolve(modrm_byte), modrm_byte >> 2 & 14); }; } };; |
| table0F_16[0xB3] = table0F_32[0xB3] = function() { var modrm_byte = read_imm8(); { if(operand_size_32) { if(modrm_byte < 0xC0) { btr_mem(modrm_resolve(modrm_byte), reg32s[modrm_byte >> 3 & 7]); } else { reg32[modrm_byte & 7] = btr_reg(reg32s[modrm_byte & 7], reg32s[modrm_byte >> 3 & 7] & 31); } } else { if(modrm_byte < 0xC0) { btr_mem(modrm_resolve(modrm_byte), reg16s[modrm_byte >> 2 & 14]); } else { reg16[modrm_byte << 1 & 14] = btr_reg(reg16[modrm_byte << 1 & 14], reg16s[modrm_byte >> 2 & 14] & 15); } }; } };; |
| // lfs, lgs |
| table0F_16[0xB4] = table0F_32[0xB4] = function() { var modrm_byte = read_imm8(); { if(modrm_byte >= 0xC0) { raise_exception(6); return; } if(operand_size_32) { lss32(reg_fs, modrm_resolve(modrm_byte), modrm_byte >> 3 & 7); } else { lss16(reg_fs, modrm_resolve(modrm_byte), modrm_byte >> 2 & 14); }; } };; |
| table0F_16[0xB5] = table0F_32[0xB5] = function() { var modrm_byte = read_imm8(); { if(modrm_byte >= 0xC0) { raise_exception(6); return; } if(operand_size_32) { lss32(reg_gs, modrm_resolve(modrm_byte), modrm_byte >> 3 & 7); } else { lss16(reg_gs, modrm_resolve(modrm_byte), modrm_byte >> 2 & 14); }; } };; |
| table0F_16[0xB6] = function() { var modrm_byte = read_imm8(); { /* movzx*/ if(modrm_byte < 0xC0) { var data = safe_read8(modrm_resolve(modrm_byte)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; }; reg16[modrm_byte >> 2 & 14] = data; } }; table0F_32[0xB6] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read8(modrm_resolve(modrm_byte)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; }; reg32[modrm_byte >> 3 & 7] = data; } };; |
| table0F_16[0xB7] = table0F_32[0xB7] = function() { var modrm_byte = read_imm8(); { /* movzx*/ if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg32[modrm_byte >> 3 & 7] = data; } };; |
| // popcnt |
| table0F_16[0xB8] = table0F_32[0xB8] = function() { { if(DEBUG) { dbg_trace(); throw "TODO"; } trigger_ud();;} };; |
| // UD |
| table0F_16[0xB9] = table0F_32[0xB9] = function() { { if(DEBUG) { dbg_trace(); throw "TODO"; } trigger_ud();;} };; |
| table0F_16[0xBA] = table0F_32[0xBA] = function() { var modrm_byte = read_imm8(); { /*dbg_log("BA " + mod + " " + imm8);*/ switch(modrm_byte >> 3 & 7) { case 4: if(operand_size_32) { if(modrm_byte < 0xC0) { bt_mem(modrm_resolve(modrm_byte), read_imm8() & 31); } else { bt_reg(reg32[modrm_byte & 7], read_imm8() & 31); } } else { if(modrm_byte < 0xC0) { bt_mem(modrm_resolve(modrm_byte), read_imm8() & 31); } else { bt_reg(reg16[modrm_byte << 1 & 14], read_imm8() & 15); } } break; case 5: if(operand_size_32) { if(modrm_byte < 0xC0) { bts_mem(modrm_resolve(modrm_byte), read_imm8() & 31); } else { reg32[modrm_byte & 7] = bts_reg(reg32s[modrm_byte & 7], read_imm8() & 31 & 31); } } else { if(modrm_byte < 0xC0) { bts_mem(modrm_resolve(modrm_byte), read_imm8() & 31); } else { reg16[modrm_byte << 1 & 14] = bts_reg(reg16[modrm_byte << 1 & 14], read_imm8() & 31 & 15); } }; break; case 6: if(operand_size_32) { if(modrm_byte < 0xC0) { btr_mem(modrm_resolve(modrm_byte), read_imm8() & 31); } else { reg32[modrm_byte & 7] = btr_reg(reg32s[modrm_byte & 7], read_imm8() & 31 & 31); } } else { if(modrm_byte < 0xC0) { btr_mem(modrm_resolve(modrm_byte), read_imm8() & 31); } else { reg16[modrm_byte << 1 & 14] = btr_reg(reg16[modrm_byte << 1 & 14], read_imm8() & 31 & 15); } }; break; case 7: if(operand_size_32) { if(modrm_byte < 0xC0) { btc_mem(modrm_resolve(modrm_byte), read_imm8() & 31); } else { reg32[modrm_byte & 7] = btc_reg(reg32s[modrm_byte & 7], read_imm8() & 31 & 31); } } else { if(modrm_byte < 0xC0) { btc_mem(modrm_resolve(modrm_byte), read_imm8() & 31); } else { reg16[modrm_byte << 1 & 14] = btc_reg(reg16[modrm_byte << 1 & 14], read_imm8() & 31 & 15); } }; break; default: dbg_log(modrm_byte >> 3 & 7); if(DEBUG) { dbg_trace(); throw "TODO"; } trigger_ud();; } } };; |
| table0F_16[0xBB] = table0F_32[0xBB] = function() { var modrm_byte = read_imm8(); { if(operand_size_32) { if(modrm_byte < 0xC0) { btc_mem(modrm_resolve(modrm_byte), reg32s[modrm_byte >> 3 & 7]); } else { reg32[modrm_byte & 7] = btc_reg(reg32s[modrm_byte & 7], reg32s[modrm_byte >> 3 & 7] & 31); } } else { if(modrm_byte < 0xC0) { btc_mem(modrm_resolve(modrm_byte), reg16s[modrm_byte >> 2 & 14]); } else { reg16[modrm_byte << 1 & 14] = btc_reg(reg16[modrm_byte << 1 & 14], reg16s[modrm_byte >> 2 & 14] & 15); } }; } };; |
| table0F_16[0xBC] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = bsf16(reg16[modrm_byte >> 2 & 14], data); } }; table0F_32[0xBC] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32[modrm_byte >> 3 & 7] = bsf32(reg32[modrm_byte >> 3 & 7], data); } };; |
| table0F_16[0xBD] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read16(modrm_resolve(modrm_byte)); } else { data = reg16[modrm_byte << 1 & 14]; }; reg16[modrm_byte >> 2 & 14] = bsr16(reg16[modrm_byte >> 2 & 14], data); } }; table0F_32[0xBD] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read32s(modrm_resolve(modrm_byte)); } else { data = reg32s[modrm_byte & 7]; }; reg32[modrm_byte >> 3 & 7] = bsr32(reg32[modrm_byte >> 3 & 7], data); } };; |
| table0F_16[0xBE] = function() { var modrm_byte = read_imm8(); { /* movsx*/ if(modrm_byte < 0xC0) { var data = safe_read8s(modrm_resolve(modrm_byte)); } else { data = reg8s[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; }; reg16[modrm_byte >> 2 & 14] = data; } }; table0F_32[0xBE] = function() { var modrm_byte = read_imm8(); { if(modrm_byte < 0xC0) { var data = safe_read8s(modrm_resolve(modrm_byte)); } else { data = reg8s[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; }; reg32s[modrm_byte >> 3 & 7] = data; } };; |
| table0F_16[0xBF] = table0F_32[0xBF] = function() { var modrm_byte = read_imm8(); { /* movsx*/ if(modrm_byte < 0xC0) { var data = (safe_read16(modrm_resolve(modrm_byte)) << 16 >> 16); } else { data = reg16s[modrm_byte << 1 & 14]; }; reg32s[modrm_byte >> 3 & 7] = data; } };; |
| table0F_16[0xC0] = table0F_32[0xC0] = function() { var modrm_byte = read_imm8(); { var data; var addr; if(modrm_byte < 0xC0) { addr = translate_address_write(modrm_resolve(modrm_byte)); data = memory.read8(addr); memory.write8(addr, xadd8(data, modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1)); } else { data = reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1]; reg8[modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1] = xadd8(data, modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1); }; } };; |
| table0F_16[0xC1] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = translate_address_write(virt_addr + 1); data = virt_boundary_read16(phys_addr, phys_addr_high); virt_boundary_write16(phys_addr, phys_addr_high, xadd16(data, modrm_byte >> 2 & 14)); } else { data = memory.read16(phys_addr); memory.write16(phys_addr, xadd16(data, modrm_byte >> 2 & 14)); } } else { data = reg16[modrm_byte << 1 & 14]; reg16[modrm_byte << 1 & 14] = xadd16(data, modrm_byte >> 2 & 14); }; } }; table0F_32[0xC1] = function() { var modrm_byte = read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high; if(modrm_byte < 0xC0) { virt_addr = modrm_resolve(modrm_byte); phys_addr = translate_address_write(virt_addr); if(paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = translate_address_write(virt_addr + 3); data = virt_boundary_read32s(phys_addr, phys_addr_high) >>> 0; virt_boundary_write32(phys_addr, phys_addr_high, xadd32(data, modrm_byte >> 3 & 7)); } else { data = memory.read32s(phys_addr) >>> 0; memory.write32(phys_addr, xadd32(data, modrm_byte >> 3 & 7)); } } else { data = reg32[modrm_byte & 7]; reg32s[modrm_byte & 7] = xadd32(data, modrm_byte >> 3 & 7); }; } };; |
| table0F_16[0xC2] = table0F_32[0xC2] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xC3] = table0F_32[0xC3] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xC4] = table0F_32[0xC4] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xC5] = table0F_32[0xC5] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xC6] = table0F_32[0xC6] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xC7] = table0F_32[0xC7] = function() { var modrm_byte = read_imm8(); { /* cmpxchg8b*/ var addr = modrm_resolve(modrm_byte); var m64_low = (safe_read32s(addr) >>> 0); var m64_high = (safe_read32s(addr + 4) >>> 0); if(reg32[reg_eax] === m64_low && reg32[reg_edx] === m64_high) { flags |= flag_zero; safe_write32(addr, reg32[reg_ebx]); safe_write32(addr + 4, reg32[reg_ecx]); } else { flags &= ~flag_zero; reg32[reg_eax] = m64_low; reg32[reg_edx] = m64_high; } flags_changed &= ~flag_zero; } };; |
| table0F_16[0xC8 | 0] = table0F_32[0xC8 | 0] = function() { { bswap(reg_eax); } };; table0F_16[0xC8 | 1] = table0F_32[0xC8 | 1] = function() { { bswap(reg_ecx); } };; table0F_16[0xC8 | 2] = table0F_32[0xC8 | 2] = function() { { bswap(reg_edx); } };; table0F_16[0xC8 | 3] = table0F_32[0xC8 | 3] = function() { { bswap(reg_ebx); } };; table0F_16[0xC8 | 4] = table0F_32[0xC8 | 4] = function() { { bswap(reg_esp); } };; table0F_16[0xC8 | 5] = table0F_32[0xC8 | 5] = function() { { bswap(reg_ebp); } };; table0F_16[0xC8 | 6] = table0F_32[0xC8 | 6] = function() { { bswap(reg_esi); } };; table0F_16[0xC8 | 7] = table0F_32[0xC8 | 7] = function() { { bswap(reg_edi); } };; |
| table0F_16[0xD0] = table0F_32[0xD0] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xD1] = table0F_32[0xD1] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xD2] = table0F_32[0xD2] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xD3] = table0F_32[0xD3] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xD4] = table0F_32[0xD4] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xD5] = table0F_32[0xD5] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xD6] = table0F_32[0xD6] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xD7] = table0F_32[0xD7] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xD8] = table0F_32[0xD8] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xD9] = table0F_32[0xD9] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xDA] = table0F_32[0xDA] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xDB] = table0F_32[0xDB] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xDC] = table0F_32[0xDC] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xDD] = table0F_32[0xDD] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xDE] = table0F_32[0xDE] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xDF] = table0F_32[0xDF] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xE0] = table0F_32[0xE0] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xE1] = table0F_32[0xE1] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xE2] = table0F_32[0xE2] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xE3] = table0F_32[0xE3] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xE4] = table0F_32[0xE4] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xE5] = table0F_32[0xE5] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xE6] = table0F_32[0xE6] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xE7] = table0F_32[0xE7] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xE8] = table0F_32[0xE8] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xE9] = table0F_32[0xE9] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xEA] = table0F_32[0xEA] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xEB] = table0F_32[0xEB] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xEC] = table0F_32[0xEC] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xED] = table0F_32[0xED] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xEE] = table0F_32[0xEE] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xEF] = table0F_32[0xEF] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xF0] = table0F_32[0xF0] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xF1] = table0F_32[0xF1] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xF2] = table0F_32[0xF2] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xF3] = table0F_32[0xF3] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xF4] = table0F_32[0xF4] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xF5] = table0F_32[0xF5] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xF6] = table0F_32[0xF6] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xF7] = table0F_32[0xF7] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xF8] = table0F_32[0xF8] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xF9] = table0F_32[0xF9] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xFA] = table0F_32[0xFA] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xFB] = table0F_32[0xFB] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xFC] = table0F_32[0xFC] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xFD] = table0F_32[0xFD] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| table0F_16[0xFE] = table0F_32[0xFE] = function() { { dbg_log("No SSE", LOG_CPU); trigger_ud();} };; |
| // NSA backdoor instruction |
| table0F_16[0xFF] = table0F_32[0xFF] = function() { { if(DEBUG) throw "Possible fault: undefined instruction"; trigger_ud();} };; |
| } |