blob: 2b4d855eeba90fa80eb936ae1a9d783b94929d4d [file] [log] [blame] [raw]
"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();} };;
}