blob: 41b61706f665d381039087e77cd513a8bddc7ea8 [file] [log] [blame] [raw]
"use strict";
/** @constructor */
function CPU()
{
/** @type {number } */
this.memory_size = 0;
this.segment_is_null = [];
this.segment_offsets = [];
this.segment_limits = [];
//this.segment_infos = [];
/**
* Translation Lookaside Buffer
* @const
*/
this.tlb_data = new Int32Array(1 << 20);
/**
* Information about which pages are cached in the tlb.
* By bit:
* 0 system, read
* 1 system, write
* 2 user, read
* 3 user, write
* @const
*/
this.tlb_info = new Uint8Array(1 << 20);
/**
* Same as tlb_info, except it only contains global pages
* @const
*/
this.tlb_info_global = new Uint8Array(1 << 20);
/**
* Wheter or not in protected mode
* @type {boolean}
*/
this.protected_mode = false;
/**
* interrupt descriptor table
* @type {number}
*/
this.idtr_size = 0;
/** @type {number} */
this.idtr_offset = 0;
/**
* global descriptor table register
* @type {number}
*/
this.gdtr_size = 0;
/** @type {number} */
this.gdtr_offset = 0;
/*
* whether or not a page fault occured
*/
this.page_fault = false;
this.cr = new Int32Array(8);
/** @type {number} */
this.cr[0] = 0;
/** @type {number} */
this.cr[2] = 0;
/** @type {number} */
this.cr[3] = 0;
/** @type {number} */
this.cr[4] = 0;
// current privilege level
/** @type {number} */
this.cpl = 0;
// if false, pages are 4 KiB, else 4 Mib
/** @type {number} */
this.page_size_extensions = 0;
// current operand/address/stack size
/** @type {boolean} */
this.is_32 = false;
/** @type {boolean} */
this.operand_size_32 = false;
/** @type {boolean} */
this.stack_size_32 = false;
/** @type {boolean} */
this.address_size_32 = false;
/**
* Was the last instruction a hlt?
* @type {boolean}
*/
this.in_hlt = false;
/** @type {!Object} */
this.devices = {
vga: {
timer: function(now) {},
destroy: function() {},
},
ps2: {
timer: function(now) {},
destroy: function() {},
},
};
/** @type {number} */
this.last_virt_eip = 0;
/** @type {number} */
this.eip_phys = 0;
/** @type {number} */
this.last_virt_esp = 0;
/** @type {number} */
this.esp_phys = 0;
/** @type {number} */
this.sysenter_cs = 0;
/** @type {number} */
this.sysenter_esp = 0;
/** @type {number} */
this.sysenter_eip = 0;
/** @type {number} */
this.repeat_string_prefix = REPEAT_STRING_PREFIX_NONE;
/** @type {number} */
this.flags = 0;
/**
* bitmap of flags which are not updated in the flags variable
* changed by arithmetic instructions, so only relevant to arithmetic flags
* @type {number}
*/
this.flags_changed = 0;
/**
* the last 2 operators and the result and size of the last arithmetic operation
* @type {number}
*/
this.last_op1 = 0;
/** @type {number} */
this.last_op2 = 0;
/** @type {number} */
this.last_op_size = 0;
/** @type {number} */
this.last_add_result = 0;
/** @type {number} */
this.last_result = 0;
this.tsc_offset = 0;
/** @type {number} */
this.modrm_byte = 0;
// cpu.reg16 or cpu.reg32s, depending on address size attribute
this.regv = this.reg16;
this.reg_vcx = 0;
this.reg_vsi = 0;
this.reg_vdi = 0;
this.table = [];
this.large_table = [];
this.large_table16 = [];
this.large_table32 = [];
this.large_table0F_16 = [];
this.large_table0F_32 = [];
// paging enabled
/** @type {boolean} */
this.paging = false;
/** @type {number} */
this.instruction_pointer = 0;
/** @type {number} */
this.previous_ip = 0;
/**
* @const
* @type {{main: ArrayBuffer, vga: ArrayBuffer}}
*/
this.bios = {
main: null,
vga: null,
};
/**
* @type {number}
*/
this.timestamp_counter = 0;
//this.modrm_resolve = function(x){ dbg_assert(false); };
// registers
this.reg32s = new Int32Array(8);
this.reg32 = new Uint32Array(this.reg32s.buffer);
this.reg16s = new Int16Array(this.reg32s.buffer);
this.reg16 = new Uint16Array(this.reg32s.buffer);
this.reg8s = new Int8Array(this.reg32s.buffer);
this.reg8 = new Uint8Array(this.reg32s.buffer);
// segment registers, tr and ldtr
this.sreg = new Uint16Array(8);
// debug registers
this.dreg = new Int32Array(8);
// sp or esp, depending on stack size attribute
this.stack_reg = this.reg16;
this.reg_vsp = 0;
this.reg_vbp = 0;
/** @type {Memory} */
this.memory = null;
// current state of prefixes
this.segment_prefix = SEG_PREFIX_NONE;
// dynamic instruction translator
this.translator = undefined;
this.io = undefined;
this.fpu = undefined;
// it looks pointless to have this here, but
// Closure Compiler is able to remove unused functions
"use strict";
(function(cpu)
{
var debug = {};
cpu.debug = debug;
/**
* wheter or not in step mode
* used for debugging
* @type {boolean}
*/
debug.step_mode = false;
debug.ops = undefined;
debug.all_ops = [];
debug.trace_all = false;
// "log" some information visually to the user.
// Also in non-DEBUG modes
debug.show = function(x)
{
if(typeof document !== "undefined")
{
var el = document.getElementById("log");
if(el)
{
el.textContent += x + "\n";
el.style.display = "block";
el.scrollTop = 1e9;
return;
}
}
console.log(x);
};
debug.init = function()
{
if(!DEBUG) return;
// used for debugging
debug.ops = new CircularQueue(200000);
if(cpu.io)
{
// write seabios debug output to console
var seabios_debug = "";
cpu.io.register_write(0x402, this, handle); // seabios
cpu.io.register_write(0x500, this, handle); // vgabios
}
function handle(out_byte)
{
if(out_byte === 10)
{
dbg_log(seabios_debug, LOG_BIOS);
seabios_debug = "";
}
else
{
seabios_debug += String.fromCharCode(out_byte);
}
}
};
debug.dump_regs = dump_regs;
debug.dump_instructions = dump_instructions;
debug.get_instructions = get_instructions;
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.get_memory_dump = get_memory_dump;
debug.memory_hex_dump = memory_hex_dump;
debug.used_memory_dump = used_memory_dump;
debug.step = step;
debug.run_until = run_until;
debug.debugger = function()
{
if(DEBUG)
{
debugger;
}
}
/**
* @param {string=} msg
*/
debug.unimpl = function(msg)
{
var s = "Unimplemented" + (msg ? ": " + msg : "");
debug.show(s);
if(DEBUG)
{
console.trace();
return s;
}
else
{
debug.show("Execution stopped");
return s;
}
//this.name = "Unimplemented";
}
function step()
{
if(!DEBUG) return;
if(!cpu.running)
{
try
{
cpu.cycle();
}
catch(e)
{
cpu.exception_cleanup(e);
}
}
dump_regs_short();
var now = Date.now();
cpu.devices.vga.timer(now);
//this.pit.timer(now);
//this.rtc.timer(now);
cpu.running = false;
dump_instructions();
}
function run_until()
{
if(!DEBUG) return;
cpu.running = false;
var a = parseInt(prompt("input hex", ""), 16);
if(a) while(cpu.instruction_pointer != a) step();
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"
];
debug.logop = function(_ip, op)
{
if(!DEBUG || !debug.step_mode)
{
return;
}
if(debug.trace_all && debug.all_ops)
{
debug.all_ops.push(_ip, op);
}
else if(debug.ops)
{
debug.ops.add(_ip);
debug.ops.add(op);
}
}
function dump_stack(start, end)
{
if(!DEBUG) return;
var esp = cpu.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(cpu.memory.read32s(esp + 4 * i) >>> 0));
}
}
function dump_regs_short()
{
if(!DEBUG) return;
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(cpu.reg32[r32[r32_names[i]]], 8) + " ";
line2 += r32_names[i+4] + "=" + h(cpu.reg32[r32[r32_names[i+4]]], 8) + " ";
}
line1 += " eip=" + h(cpu.get_real_eip() >>> 0, 8);
line2 += " flg=" + h(cpu.get_eflags(), 8);
line1 += " ds=" + h(cpu.sreg[reg_ds], 4) + " es=" + h(cpu.sreg[reg_es], 4) + " fs=" + h(cpu.sreg[reg_fs], 4);
line2 += " gs=" + h(cpu.sreg[reg_gs], 4) + " cs=" + h(cpu.sreg[reg_cs], 4) + " ss=" + h(cpu.sreg[reg_ss], 4);
dbg_log(line1, LOG_CPU);
dbg_log(line2, LOG_CPU);
}
function dump_regs()
{
if(!DEBUG) return;
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;
dbg_log("----- DUMP (ip = " + h(cpu.instruction_pointer >>> 0) + ") ----------")
dbg_log("protected mode: " + cpu.protected_mode);
for(var i in r32)
{
dbg_log(i + " = " + h(cpu.reg32[r32[i]], 8));
}
dbg_log("eip = " + h(cpu.get_real_eip() >>> 0, 8));
for(i in s)
{
dbg_log(i + " = " + h(cpu.sreg[s[i]], 4));
}
out = "";
var flg = { "cf": cpu.getcf, "pf": cpu.getpf, "zf": cpu.getzf, "sf": cpu.getsf,
"of": cpu.getof, "df": flag_direction, "if": flag_interrupt };
for(var i in flg)
{
if(+flg[i])
{
out += i + "=" + Number(!!(cpu.flags & flg[i])) + " | ";
}
else
{
out += i + "=" + Number(!!flg[i]()) + " | ";
}
}
out += "iopl=" + cpu.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 get_instructions()
{
if(!DEBUG) return;
debug.step_mode = true;
function add(ip, op)
{
out += h(ip, 8) + ": " +
v86util.pads(opcode_map[op] || "unkown", 20) + h(op, 2) + "\n";
}
var opcodes;
var out = "";
if(debug.trace_all && debug.all_ops)
{
opcodes = debug.all_ops;
}
else if(debug.ops)
{
opcodes = debug.ops.toArray();
}
if(!opcodes)
{
return "";
}
for(var i = 0; i < opcodes.length; i += 2)
{
add(opcodes[i], opcodes[i + 1]);
}
debug.ops.clear();
debug.all_ops = [];
return out;
}
function dump_instructions()
{
if(!DEBUG) return;
debug.show(get_instructions());
}
function dump_gdt_ldt()
{
if(!DEBUG) return;
dbg_log("gdt: (len = " + h(cpu.gdtr_size) + ")");
dump_table(cpu.translate_address_read(cpu.gdtr_offset), cpu.gdtr_size);
dbg_log("\nldt: (len = " + h(cpu.segment_limits[reg_ldtr]) + ")");
dump_table(cpu.translate_address_read(cpu.segment_offsets[reg_ldtr]), cpu.segment_limits[reg_ldtr]);
function dump_table(addr, size)
{
for(var i = 0; i < size; i += 8, addr += 8)
{
var base = cpu.memory.read16(addr + 2) |
cpu.memory.read8(addr + 4) << 16 |
cpu.memory.read8(addr + 7) << 24,
limit = cpu.memory.read16(addr) | (cpu.memory.read8(addr + 6) & 0xF) << 16,
access = cpu.memory.read8(addr + 5),
flags = cpu.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 = limit << 12 | 0xFFF;
}
dbg_log(h(i & ~7, 4) + " " + h(base >>> 0, 8) + " (" + h(limit >>> 0, 8) + " bytes) " +
flags_str + "; dpl = " + dpl + ", a = " + access.toString(2) +
", f = " + flags.toString(2));
}
}
}
function dump_idt()
{
if(!DEBUG) return;
for(var i = 0; i < cpu.idtr_size; i += 8)
{
var addr = cpu.translate_address_system_read(cpu.idtr_offset + i),
base = cpu.memory.read16(addr) | cpu.memory.read16(addr + 6) << 16,
selector = cpu.memory.read16(addr + 2),
type = cpu.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(!DEBUG) return;
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_disable : (dword_entry & 16) === 16,
user : (dword_entry & 4) === 4,
read_write : (dword_entry & 2) === 2,
address : address >>> 0
};
}
function dump_page_directory()
{
if(!DEBUG) return;
for(var i = 0; i < 1024; i++)
{
var dword = cpu.memory.read32s(cpu.cr[3] + 4 * i),
entry = load_page_entry(dword, true);
if(!entry)
{
continue;
}
var flags = "";
flags += entry.size ? "S " : " ";
flags += entry.accessed ? "A " : " ";
flags += entry.cache_disable ? "Cd " : " ";
flags += entry.user ? "U " : " ";
flags += entry.read_write ? "Rw " : " ";
if(entry.size)
{
dbg_log("=== " + h((i << 22) >>> 0, 8) + " -> " + h(entry.address >>> 0, 8) + " | " + flags);
continue;
}
else
{
dbg_log("=== " + h((i << 22) >>> 0, 8) + " | " + flags);
}
for(var j = 0; j < 1024; j++)
{
dword = cpu.memory.read32s(entry.address + 4 * j);
var subentry = load_page_entry(dword, false);
if(subentry)
{
flags = "";
flags += subentry.cache_disable ? "Cd " : " ";
flags += subentry.user ? "U " : " ";
flags += subentry.read_write ? "Rw " : " ";
flags += subentry.global ? "G " : " ";
flags += subentry.accessed ? "A " : " ";
flags += subentry.dirty ? "Di " : " ";
dbg_log("# " + h((i << 22 | j << 12) >>> 0, 8) + " -> " +
h(subentry.address, 8) + " | " + flags);
}
}
}
}
function get_memory_dump(start, count)
{
if(!DEBUG) return;
if(start === undefined)
{
start = 0;
count = cpu.memory_size;
}
else if(count === undefined)
{
count = start;
start = 0;
}
return cpu.memory.buffer.slice(start, start + count);
}
function memory_hex_dump(addr, length)
{
if(!DEBUG) return;
length = length || 4 * 0x10;
var line, byt;
for(var i = 0; i < length >> 4; i++)
{
line = h(addr + (i << 4), 5) + " ";
for(var j = 0; j < 0x10; j++)
{
byt = cpu.memory.read8(addr + (i << 4) + j);
line += h(byt, 2) + " ";
}
line += " ";
for(j = 0; j < 0x10; j++)
{
byt = cpu.memory.read8(addr + (i << 4) + j);
line += (byt < 33 || byt > 126) ? "." : String.fromCharCode(byt);
}
dbg_log(line);
}
}
function used_memory_dump()
{
if(!DEBUG) return;
var width = 0x80,
height = 0x10,
block_size = cpu.memory_size / width / height | 0,
row;
for(var i = 0; i < height; i++)
{
row = h(i * width * block_size, 8) + " | ";
for(var j = 0; j < width; j++)
{
var used = cpu.memory.mem32s[(i * width + j) * block_size] > 0;
row += used ? "X" : " ";
}
dbg_log(row);
}
};
})(this);
dbg_assert(this.table16 && this.table32);
dbg_assert(this.table0F_16 && this.table0F_32);
this.reg32 = new Uint32Array(this.reg32s.buffer);
this.reg16s = new Int16Array(this.reg32s.buffer);
this.reg16 = new Uint16Array(this.reg32s.buffer);
this.reg8s = new Int8Array(this.reg32s.buffer);
this.reg8 = new Uint8Array(this.reg32s.buffer);
this.update_address_size();
this.update_operand_size();
this.tsc_offset = v86.microtick();
}
CPU.prototype.get_state = function()
{
var state = [];
state[0] = this.memory_size;
state[1] = this.segment_is_null;
state[2] = this.segment_offsets;
state[3] = this.segment_limits;
state[4] = this.protected_mode;
state[5] = this.idtr_offset;
state[6] = this.idtr_size;
state[7] = this.gdtr_offset;
state[8] = this.gdtr_size;
state[9] = this.page_fault;
state[10] = this.cr;
state[11] = this.cpl;
state[12] = this.page_size_extensions;
state[13] = this.is_32;
state[14] = this.operand_size_32;
state[15] = this.address_size_32;
state[16] = this.stack_size_32;
state[17] = this.in_hlt;
state[18] = this.last_virt_eip;
state[19] = this.eip_phys;
state[20] = this.last_virt_esp;
state[21] = this.esp_phys;
state[22] = this.sysenter_cs;
state[23] = this.sysenter_eip;
state[24] = this.sysenter_esp;
state[25] = this.repeat_string_prefix;
state[26] = this.flags;
state[27] = this.flags_changed;
state[28] = this.last_op1;
state[29] = this.last_op2;
state[30] = this.last_op_size;
state[31] = this.last_add_result;
state[32] = this.modrm_byte;
state[36] = this.paging;
state[37] = this.instruction_pointer;
state[38] = this.previous_ip;
state[39] = this.reg32s;
state[40] = this.sreg;
state[41] = this.dreg;
state[42] = this.memory;
state[43] = this.fpu;
state[45] = this.devices.virtio;
state[46] = this.devices.apic;
state[47] = this.devices.rtc;
state[48] = this.devices.pci;
state[49] = this.devices.dma;
//state[50] = this.devices.acpi;
state[51] = this.devices.hpet;
state[52] = this.devices.vga;
state[53] = this.devices.ps2;
state[54] = this.devices.uart;
state[55] = this.devices.fdc;
state[56] = this.devices.cdrom;
state[57] = this.devices.hda;
state[58] = this.devices.pit;
state[59] = this.devices.net;
state[60] = this.devices.pic;
return state;
};
CPU.prototype.set_state = function(state)
{
this.memory_size = state[0];
this.segment_is_null = state[1];
this.segment_offsets = state[2];
this.segment_limits = state[3];
this.protected_mode = state[4];
this.idtr_offset = state[5];
this.idtr_size = state[6];
this.gdtr_offset = state[7];
this.gdtr_size = state[8];
this.page_fault = state[9];
this.cr = state[10];
this.cpl = state[11];
this.page_size_extensions = state[12];
this.is_32 = state[13];
this.operand_size_32 = state[14];
this.address_size_32 = state[15];
this.stack_size_32 = state[16];
this.in_hlt = state[17];
this.last_virt_eip = state[18];
this.eip_phys = state[19];
this.last_virt_esp = state[20];
this.esp_phys = state[21];
this.sysenter_cs = state[22];
this.sysenter_eip = state[23];
this.sysenter_esp = state[24];
this.repeat_string_prefix = state[25];
this.flags = state[26];
this.flags_changed = state[27];
this.last_op2 = state[27];
this.last_op3 = state[28];
this.last_op_size = state[30];
this.last_add_result = state[31];
this.modrm_byte = state[32];
this.paging = state[36];
this.instruction_pointer = state[37];
this.previous_ip = state[38];
this.reg33s = state[38];
this.sreg = state[40];
this.dreg = state[41];
this.memory = state[42];
this.fpu = state[43];
this.devices.virtio = state[45];
this.devices.apic = state[46];
this.devices.rtc = state[47];
this.devices.pci = state[48];
this.devices.dma = state[49];
this.devices.acpi = state[50];
this.devices.hpet = state[51];
this.devices.vga = state[52];
this.devices.ps5 = state[50];
this.devices.uart = state[54];
this.devices.fdc = state[55];
this.devices.cdrom = state[56];
this.devices.hda = state[57];
this.devices.pit = state[58];
this.devices.net = state[59];
this.devices.pic = state[60];
this.full_clear_tlb();
// tsc_offset?
if(this.stack_size_32)
{
this.stack_reg = this.reg32s;
this.reg_vsp = reg_esp;
this.reg_vbp = reg_ebp;
}
else
{
this.stack_reg = this.reg16;
this.reg_vsp = reg_sp;
this.reg_vbp = reg_bp;
}
this.reg32 = new Uint32Array(this.reg32s.buffer);
this.reg16s = new Int16Array(this.reg32s.buffer);
this.reg16 = new Uint16Array(this.reg32s.buffer);
this.reg8s = new Int8Array(this.reg32s.buffer);
this.reg8 = new Uint8Array(this.reg32s.buffer);
this.update_address_size();
this.update_operand_size();
};
"use strict";
/** @const */
var DYN_CODE_CACHE_LIMIT = 1000000;
/** @const */
var FN_CACHE_LIMIT = 10000;
/** @const */
var HIT_COUNT = 5;
var trans_stats = [];
var CLASSIFICATION_NONE = 0;
var CLASSIFICATION_MODRM = 1;
var CLASSIFICATION_SINGLE = 2;
var CLASSIFICATION_IMM8 = 3;
var CLASSIFICATION_IMM8S = 4;
var CLASSIFICATION_0F = 5;
var CLASSIFICATION_PREFIX = 6;
var CLASSIFICATION_NOT_OPTIMIZABLE = 7;
/** @constructor */
function DynamicTranslator(cpu)
{
this.cpu = cpu;
this.fn_cache = {};
this.fn_cache_size = 0;
this.code_translation_cache = {};
this.code_translation_cache_size = 0;
function bind(fn, thisValue, i, is_32, is_0F)
{
return function()
{
return fn.call(thisValue, i, is_32, is_0F);
};
}
console.time("create stub tables");
for(var i = 0; i < 0x10000; i++)
{
this.cpu.large_table16[i] = bind(this.stub, this, i, false, false);
this.cpu.large_table32[i] = bind(this.stub, this, i, true, false);
this.cpu.large_table0F_16[i] = bind(this.stub, this, i, false, true);
this.cpu.large_table0F_32[i] = bind(this.stub, this, i, true, true);
}
console.timeEnd("create stub tables");
this.op_body16 = [];
this.op_body32 = [];
this.op_tokens16 = [];
this.op_tokens32 = [];
this.op_body0F_16 = [];
this.op_body0F_32 = [];
this.op_tokens0F_16 = [];
this.op_tokens0F_32 = [];
this.modrm_body16 = [];
this.modrm_body32 = [];
this.page_has_code = new Uint8Array(1 << 20);
this.translatable = new Uint8Array(0x100);
this.translatable0F = new Uint8Array(0x100);
this.seen = new Uint16Array(100003);
this.modrm_table16 = Array(0xC0);
this.modrm_table32 = Array(0xC0);
this.sib_table = Array(0x100);
this.jumping_instructions = new Uint8Array(0x100);
this.table16 = [];
this.table32 = [];
this.table0F_16 = [];
this.table0F_32 = [];
this.current_cache_id = "";
this.current_eip = 0;
this.op_classification = new Uint8Array(0x100);
this.op_classification0F = new Uint8Array(0x100);
this.init_tables();
this.timing_make_fn = 0;
this.timing_make_create_op = 0;
};
/** @param {CPU} cpu */
DynamicTranslator.prototype.get_instruction_pointer = function(cpu)
{
return cpu.instruction_pointer;
};
/** @param {CPU} cpu */
DynamicTranslator.prototype.get_read_imm8 = function(cpu)
{
return cpu.read_imm8;
};
/** @param {CPU} cpu */
DynamicTranslator.prototype.get_read_imm8s = function(cpu)
{
return cpu.read_imm8s;
};
/** @param {CPU} cpu */
DynamicTranslator.prototype.get_do_op = function(cpu)
{
return cpu.do_op;
};
/** @param {CPU} cpu */
DynamicTranslator.prototype.get_safe_read8 = function(cpu)
{
return cpu.safe_read8;
};
/** @param {CPU} cpu */
DynamicTranslator.prototype.get_large_table = function(cpu)
{
return cpu.large_table;
};
/** @param {CPU} cpu */
DynamicTranslator.prototype.get_large_table0F_16 = function(cpu)
{
return cpu.large_table0F_16;
};
/** @param {CPU} cpu */
DynamicTranslator.prototype.get_large_table0F_32 = function(cpu)
{
return cpu.large_table0F_32;
};
/** @param {CPU} cpu */
DynamicTranslator.prototype.get_previous_ip = function(cpu)
{
return cpu.previous_ip;
};
/** @param {CPU} cpu */
DynamicTranslator.prototype.get_table = function(cpu)
{
return cpu.table;
};
/** @param {CPU} cpu */
DynamicTranslator.prototype.get_modrm_byte = function(cpu)
{
return cpu.modrm_byte;
};
DynamicTranslator.prototype.init_tables = function()
{
this.text = {
cpu: this.jsfunction_extract_arg(this.cpu.table16[0]),
instruction_pointer: this.jsfunction_extract_return(this.get_instruction_pointer),
read_imm8: this.jsfunction_extract_return(this.get_read_imm8),
read_imm8s: this.jsfunction_extract_return(this.get_read_imm8s),
do_op: this.jsfunction_extract_return(this.get_do_op),
safe_read8: this.jsfunction_extract_return(this.get_safe_read8),
large_table: this.jsfunction_extract_return(this.get_large_table),
large_table0F_16: this.jsfunction_extract_return(this.get_large_table0F_16),
large_table0F_32: this.jsfunction_extract_return(this.get_large_table0F_32),
previous_ip: this.jsfunction_extract_return(this.get_previous_ip),
table: this.jsfunction_extract_return(this.get_table),
modrm_byte: this.jsfunction_extract_return(this.get_modrm_byte),
}
this.text.eip_plus_1 = this.text.instruction_pointer + "+1|0";
this.text.inc_eip = this.text.instruction_pointer + "=" + this.text.eip_plus_1 + ";";
this.text.inc_eip2 = this.text.instruction_pointer + "=" + this.text.instruction_pointer + "+2|0;";
this.text.previous_eip_to_eip = this.text.previous_ip + "=" + this.text.instruction_pointer + ";";
console.log(this.text);
console.log(this.cpu.table16);
console.log(this.cpu.table32);
console.log(this.cpu.table0F_16);
console.log(this.cpu.table0F_32);
//var cpu = this.cpu;
for(var i = 0; i < 8; i++)
{
this.translatable[i << 3 | 0] = 1;
this.translatable[i << 3 | 1] = 1;
this.translatable[i << 3 | 2] = 1;
this.translatable[i << 3 | 3] = 1;
this.translatable[i << 3 | 4] = 1;
this.translatable[i << 3 | 5] = 1;
// prefixes don't work:
//this.translatable[i << 3 | 6] = 1;
this.translatable[i << 3 | 7] = 1;
this.translatable[0x40 | i] = 1;
this.translatable[0x48 | i] = 1;
this.translatable[0x50 | i] = 1;
this.translatable[0x58 | i] = 1;
this.translatable[0x70 | i] = 1;
this.translatable[0x78 | i] = 1;
this.jumping_instructions[0x70 | i] = 1;
this.jumping_instructions[0x78 | i] = 1;
//this.translatable[0x80 | i] = 1;
this.translatable[0x88 | i] = 1;
this.translatable[0x90 | i] = 1;
this.translatable[0xB0 | i] = 1;
this.translatable[0xB8 | i] = 1;
this.translatable[0xD8 | i] = 1;
this.translatable0F[0x40 | i] = 1;
this.translatable0F[0x48 | i] = 1;
this.translatable0F[0x90 | i] = 1;
this.translatable0F[0x98 | i] = 1;
this.op_classification0F[0x40 | i] = 1;
this.op_classification0F[0x48 | i] = 1;
this.op_classification0F[0x90 | i] = 1;
this.op_classification0F[0x98 | i] = 1;
};
this.op_classification0F[0xA3] = 1;
this.op_classification0F[0xA4] = 1;
this.op_classification0F[0xAB] = 1;
this.op_classification0F[0xAC] = 1;
this.op_classification0F[0xAD] = 1;
this.op_classification0F[0xAF] = 1;
this.op_classification0F[0xB0] = 1;
this.op_classification0F[0xB1] = 1;
this.op_classification0F[0xB6] = 1;
this.op_classification0F[0xB7] = 1;
this.op_classification0F[0xB8] = 1;
this.op_classification0F[0xBA] = 1;
this.op_classification0F[0xBB] = 1;
this.op_classification0F[0xBC] = 1;
this.op_classification0F[0xBD] = 1;
this.op_classification0F[0xBE] = 1;
this.op_classification0F[0xBF] = 1;
this.op_classification0F[0xC0] = 1;
this.op_classification0F[0xC1] = 1;
this.op_classification[0x00] = this.op_classification[0x01] = this.op_classification[0x02] = this.op_classification[0x03] =
this.op_classification[0x08] = this.op_classification[0x09] = this.op_classification[0x0a] = this.op_classification[0x0b] =
this.op_classification[0x10] = this.op_classification[0x11] = this.op_classification[0x12] = this.op_classification[0x13] =
this.op_classification[0x18] = this.op_classification[0x19] = this.op_classification[0x1a] = this.op_classification[0x1b] =
this.op_classification[0x20] = this.op_classification[0x21] = this.op_classification[0x22] = this.op_classification[0x23] =
this.op_classification[0x28] = this.op_classification[0x29] = this.op_classification[0x2a] = this.op_classification[0x2b] =
this.op_classification[0x30] = this.op_classification[0x31] = this.op_classification[0x32] = this.op_classification[0x33] =
this.op_classification[0x38] = this.op_classification[0x39] = this.op_classification[0x3a] = this.op_classification[0x3b] =
this.op_classification[0x69] = this.op_classification[0x6b] =
this.op_classification[0x80] = this.op_classification[0x81] = /*this.op_classification[0x82] =*/ this.op_classification[0x83] =
this.op_classification[0x84] = this.op_classification[0x85] = this.op_classification[0x86] = this.op_classification[0x87] =
this.op_classification[0x88] = this.op_classification[0x89] = this.op_classification[0x8a] = this.op_classification[0x8b] =
this.op_classification[0x8c] = this.op_classification[0x8d] = this.op_classification[0x8e] = this.op_classification[0x8f] =
this.op_classification[0xc0] = this.op_classification[0xc1] =
this.op_classification[0xc6] = this.op_classification[0xc7] =
this.op_classification[0xd0] = this.op_classification[0xd1] = this.op_classification[0xd2] = this.op_classification[0xd3] =
this.op_classification[0xd8] = this.op_classification[0xd9] = this.op_classification[0xda] = this.op_classification[0xdb] =
this.op_classification[0xdc] = this.op_classification[0xdd] = this.op_classification[0xde] = this.op_classification[0xdf] =
this.op_classification[0xf6] = this.op_classification[0xf7] = this.op_classification[0xfe] = this.op_classification[0xff] = CLASSIFICATION_MODRM;
this.op_classification[0x06] = this.op_classification[0x07] = this.op_classification[0x0E] =
this.op_classification[0x16] = this.op_classification[0x17] = this.op_classification[0x1E] = this.op_classification[0x1F] =
this.op_classification[0x27] = this.op_classification[0x2F] = this.op_classification[0x37] = this.op_classification[0x3F] =
this.op_classification[0x40] = this.op_classification[0x41] = this.op_classification[0x42] = this.op_classification[0x43] =
this.op_classification[0x44] = this.op_classification[0x45] = this.op_classification[0x46] = this.op_classification[0x47] =
this.op_classification[0x48] = this.op_classification[0x49] = this.op_classification[0x4A] = this.op_classification[0x4B] =
this.op_classification[0x4C] = this.op_classification[0x4D] = this.op_classification[0x4E] = this.op_classification[0x4F] =
this.op_classification[0x50] = this.op_classification[0x51] = this.op_classification[0x52] = this.op_classification[0x53] =
this.op_classification[0x54] = this.op_classification[0x55] = this.op_classification[0x56] = this.op_classification[0x57] =
this.op_classification[0x58] = this.op_classification[0x59] = this.op_classification[0x5A] = this.op_classification[0x5B] =
this.op_classification[0x5C] = this.op_classification[0x5D] = this.op_classification[0x5E] = this.op_classification[0x5F] =
this.op_classification[0x60] = this.op_classification[0x61] =
this.op_classification[0x90] = this.op_classification[0x91] = this.op_classification[0x92] = this.op_classification[0x93] =
this.op_classification[0x94] = this.op_classification[0x95] = this.op_classification[0x96] = this.op_classification[0x97] =
this.op_classification[0x98] = this.op_classification[0x99] = // cbw, cwd
this.op_classification[0x9C] = // pushf
//this.op_classification[0x9D] = //popf: Not supported because it calls handle_irqs -> call_interrupt_vector
this.op_classification[0x9E] = this.op_classification[0x9F] =
//this.op_classification[0xC9] = // leave, seems to break openbsd
this.op_classification[0xF5] =
this.op_classification[0xF8] = this.op_classification[0xF9] =
this.op_classification[0xFC] = this.op_classification[0xFD] = CLASSIFICATION_SINGLE;
// String operations
// Works, because rep prefixes cause the small table to be used.
// In any other case, these must be repeatable
this.op_classification[0xA4] = this.op_classification[0xA5] =
this.op_classification[0xA6] = this.op_classification[0xA7] =
this.op_classification[0xAA] = this.op_classification[0xAB] =
this.op_classification[0xAC] = this.op_classification[0xAD] =
this.op_classification[0xAE] = this.op_classification[0xAF] = CLASSIFICATION_SINGLE;
this.op_classification[0x04] = this.op_classification[0x0C] = this.op_classification[0x14] = this.op_classification[0x1C] =
this.op_classification[0x24] = this.op_classification[0x2C] = this.op_classification[0x34] = this.op_classification[0x3C] =
//this.op_classification[0xcd] =
this.op_classification[0xB0] = this.op_classification[0xB1] = this.op_classification[0xB2] = this.op_classification[0xB3] =
this.op_classification[0xB4] = this.op_classification[0xB5] = this.op_classification[0xB6] = this.op_classification[0xB7] = CLASSIFICATION_IMM8;
// nope, see popf
//this.op_classification[0xE4] = this.op_classification[0xE5] = this.op_classification[0xE6] = this.op_classification[0xE7] = CLASSIFICATION_IMM8;
this.op_classification[0x70] = this.op_classification[0x71] = this.op_classification[0x72] = this.op_classification[0x73] =
this.op_classification[0x74] = this.op_classification[0x75] = this.op_classification[0x76] = this.op_classification[0x77] =
this.op_classification[0x78] = this.op_classification[0x79] = this.op_classification[0x7A] = this.op_classification[0x7B] =
this.op_classification[0x7C] = this.op_classification[0x7D] = this.op_classification[0x7E] = this.op_classification[0x7F] =
this.op_classification[0x6A] = // push imm8s
this.op_classification[0xE0] = this.op_classification[0xE1] = // loop, loope, jcxz
this.op_classification[0xE2] = this.op_classification[0xE3] =
this.op_classification[0xEB] = // jump near
CLASSIFICATION_IMM8S;
this.op_classification[0xFB] = this.op_classification[0xFA] = // sti, cli
this.op_classification[0xCD] = // int
this.op_classification[0xF4] = CLASSIFICATION_NOT_OPTIMIZABLE; // hlt
this.op_classification[0x0F] = CLASSIFICATION_0F;
this.op_classification[0x26] = this.op_classification[0x2E] =
this.op_classification[0x36] = this.op_classification[0x3E] =
this.op_classification[0x64] = this.op_classification[0x65] =
this.op_classification[0x66] = this.op_classification[0x67] =
this.op_classification[0xF2] = this.op_classification[0xF3] =
CLASSIFICATION_PREFIX;
this.translatable[0x60] = 1;
this.translatable[0x61] = 1;
this.translatable[0x62] = 1;
this.translatable[0x63] = 1;
this.translatable[0x68] = 1;
this.translatable[0x69] = 1;
this.translatable[0x6A] = 1;
this.translatable[0x6B] = 1;
this.translatable[0x6C] = 1;
this.translatable[0x6D] = 1;
this.translatable[0x6E] = 1;
this.translatable[0x6F] = 1;
this.translatable[0x84] = 1;
this.translatable[0x85] = 1;
this.translatable[0x86] = 1;
this.translatable[0x87] = 1;
this.translatable[0x98] = 1;
this.translatable[0x99] = 1;
//this.translatable[0x9A] = 1; // problem with get_real_eip
//this.jumping_instructions[0x9A] = 1;
this.translatable[0x9B] = 1;
this.translatable[0x9C] = 1;
this.translatable[0x9D] = 1;
this.translatable[0x9E] = 1;
this.translatable[0x9F] = 1;
this.translatable[0xC0] = 1;
this.translatable[0xC1] = 1;
this.translatable[0xC6] = 1;
this.translatable[0xC7] = 1;
this.translatable[0xD0] = 1;
this.translatable[0xD1] = 1;
this.translatable[0xD2] = 1;
this.translatable[0xD3] = 1;
//this.translatable[0xF6] = 1;
//this.translatable[0xF7] = 1;
this.translatable[0xF8] = 1;
this.translatable[0xF9] = 1;
this.translatable[0xFC] = 1;
this.translatable[0xFD] = 1;
this.translatable0F[0xA3] = 1;
this.translatable0F[0xA4] = 1;
this.translatable0F[0xA5] = 1;
this.translatable0F[0xAB] = 1;
this.translatable0F[0xAC] = 1;
this.translatable0F[0xAD] = 1;
this.translatable0F[0xAF] = 1;
this.translatable0F[0xB6] = 1;
this.translatable0F[0xB7] = 1;
this.translatable0F[0xB8] = 1;
//this.translatable0F[0xBA] = 1;
this.translatable0F[0xBB] = 1;
this.translatable0F[0xBC] = 1;
this.translatable0F[0xBD] = 1;
this.translatable0F[0xBE] = 1;
this.translatable0F[0xBF] = 1;
this.translatable0F[0xC0] = 1;
this.translatable0F[0xC1] = 1;
console.time("modrm translation");
for(var low = 0; low < 8; low++)
{
for(var high = 0; high < 3; high++)
{
var x = low | high << 6;
this.modrm_table16[x] = this.rewrite_modrm(this.cpu.modrm_table16[x], "16", x);
this.modrm_table32[x] = this.rewrite_modrm(this.cpu.modrm_table32[x], "32", x);
}
};
//dbg_log(this.modrm_table16.map(String));
//dbg_log(this.modrm_table32.map(String));
for(var low = 0; low < 8; low++)
{
for(var high = 0; high < 3; high++)
{
var x = low | high << 6;
for(var i = 1; i < 8; i++)
{
var to = x | i << 3;
this.modrm_table16[to] = this.modrm_table16[x];
this.modrm_table32[to] = this.modrm_table32[x];
this.modrm_body16[to] = this.modrm_body16[x];
this.modrm_body32[to] = this.modrm_body32[x];
}
}
}
for(var i = 0; i < 0x100; i++)
{
this.sib_table[i] = this.rewrite_modrm(this.cpu.sib_table[i], "sib", i);
}
//dbg_log(this.sib_table.map(String));
console.timeEnd("modrm translation");
console.time("instruction translation");
for(var i = 0; i < 0x100; i++)
{
this.table16[i] = this.rewrite_instruction(this.cpu.table16, i, false, false);
this.table32[i] = this.rewrite_instruction(this.cpu.table32, i, true, false);
this.table0F_16[i] = this.rewrite_instruction(this.cpu.table0F_16, i, false, true);
this.table0F_32[i] = this.rewrite_instruction(this.cpu.table0F_32, i, true, true);
//if(this.table16[i]) dbg_log(h(i) + " " + this.table16[i]);
//if(this.table32[i]) dbg_log(h(i) + " " + this.table32[i]);
//if(this.table0F_16[i]) dbg_log(h(i) + " 0f " + this.table0F_16[i]);
//if(this.table0F_32[i]) dbg_log(h(i) + " 0f " + this.table0F_32[i]);
}
console.timeEnd("instruction translation");
for(var i = 0; i < 0x100; i++)
{
//if(!this.translatable[i])
// dbg_log("Not translated: " + h(i, 2));
}
for(var i = 0; i < 0x100; i++)
{
//if(!this.translatable0F[i])
// dbg_log("Not translated: 0F " + h(i, 2));
}
};
DynamicTranslator.prototype.clear_cache = function()
{
//dbg_log("cache cleared");
this.code_translation_cache = {};
this.code_translation_cache_size = 0;
};
DynamicTranslator.prototype.cache_wipe_page = function(page)
{
this.cpu.memory.mem_page_infos[page] = 0;
//console.time("wipe");
if(!this.page_has_code[page])
{
return;
}
//dbg_log("wipe page=" + h(page << 12, 8));
this.page_has_code[page] = false;
var high = page << 12;
for(var i = 0; i < 0x1000; i++)
{
if(this.code_translation_cache[high + i] !== undefined)
{
//dbg_log("removed");
this.code_translation_cache[high + i] = undefined;
//this.code_translation_cache_size--;
}
}
//console.timeEnd("wipe");
};
DynamicTranslator.prototype.cycle_translated_xxx = function()
{
var cpu = this.cpu;
cpu.previous_ip = cpu.instruction_pointer;
var phys_eip = cpu.get_phys_eip(),
eip_page = phys_eip >>> 12,
cache_entry;
if(cpu.memory.mem_page_infos[eip_page])
{
//console.time("wipe");
this.cache_wipe_page(eip_page);
//console.timeEnd("wipe");
}
else
{
cache_entry = this.code_translation_cache[phys_eip];
}
if(cache_entry === undefined)
{
var count = this.seen[phys_eip % 100003]++;
if(count > 100)
{
//console.log("translate");
//dbg_log("tran page=" + h(eip_page << 12, 5));
this.start_translation(eip_page, phys_eip);
this.seen[phys_eip % 100003] = 0;
}
else
{
this.cpu.cycle();
}
}
else
{
cache_entry(cpu);
}
};
DynamicTranslator.prototype.create_op = function(op, is_32, is_0F)
{
// possible optimizations:
// - test eax, eax; test ebx, ebx ...
// - or [mem], -1
// - and [mem, 0
// - Decoding FPU instructions
// - 66h prefix optimisations
// - Use read_imm32s and create longer lookups as useful
// - Cache result if is is the same in 16 and 32 bit mode
// - Consider generation of 16 bit operations in 32 bit address mode
if(DEBUG)
{
var start = performance.now();
}
dbg_assert(op < 0x10000 && op >= 0);
var b0 = op & 0xFF;
var b1 = op >> 8 & 0xFF;
var cpu = this.cpu;
var ignore_second_byte = false;
var other_op_table;
if(is_0F)
{
// all other cases are already optimized by double lookup including the 0F prefix
dbg_assert(this.op_classification0F[b0] === CLASSIFICATION_MODRM);
if(is_32)
{
var op_table = this.cpu.large_table0F_32;
var body = this.op_body0F_32[b0];
}
else
{
var op_table = this.cpu.large_table0F_16;
var body = this.op_body0F_16[b0];
}
// cannot reuse fn from other table because address_size_32 changes modrm operand
var tokens = is_32 ? this.op_tokens0F_32[b0] : this.op_tokens0F_16[b0];
//console.log("0x0F", h(b0, 2), h(b1, 2));
var code = this.optimize_modrm(tokens, b1, is_32);
//console.log(code);
}
else
{
if(is_32)
{
var op_table = this.cpu.large_table32;
var body = this.op_body32[b0];
}
else
{
var op_table = this.cpu.large_table16;
var body = this.op_body16[b0];
}
var classification = this.op_classification[b0];
if(
classification === CLASSIFICATION_IMM8S ||
classification === CLASSIFICATION_IMM8 ||
classification === CLASSIFICATION_NOT_OPTIMIZABLE ||
classification === CLASSIFICATION_NONE
) {
if(this.cpu.table16[b0] === this.cpu.table32[b0])
{
other_op_table = is_32 ? this.cpu.large_table16 : this.cpu.large_table32;
}
}
switch(classification)
{
case CLASSIFICATION_0F:
// create code for op from 0f table
if(this.op_classification0F[b1] === CLASSIFICATION_MODRM)
{
//var code = "cpu.instruction_pointer = cpu.instruction_pointer + 1 | 0; ";
var code = this.text.inc_eip;
if(is_32)
{
//code += "cpu.large_table0F_32[cpu.safe_read8(cpu.instruction_pointer + 1 | 0) << 8 | " + b1 + "](cpu)";
code += this.text.large_table0F_32 + "[" + this.text.safe_read8 + "(" + this.text.eip_plus_1 + ")<<8|" + b1 + "](" + this.text.cpu + ");";
}
else
{
//code += "cpu.large_table0F_16[cpu.safe_read8(cpu.instruction_pointer + 1 | 0) << 8 | " + b1 + "](cpu)";
code += this.text.large_table0F_16 + "[" + this.text.safe_read8 + "(" + this.text.eip_plus_1 + ")<<8|" + b1 + "](" + this.text.cpu + ");";
}
//console.log("0f modrm", code);
}
else
{
//var code = "cpu.instruction_pointer += 2; "
var code = this.text.inc_eip2;
if(is_32)
{
code += this.op_body0F_32[b1];
}
else
{
code += this.op_body0F_16[b1];
}
}
//console.log(code);
break;
case CLASSIFICATION_MODRM:
//if(b0 >= 0x30 && b0 < 0x34 && b1 >= 0xC0 && (b1 & 7) === (b1 >> 3 & 7))
//{
// // xor X, X
// var code = this.generate_xor_self((b0 & 1) ? is_32 ? 32 : 16 : 8, b1 & 7);
// //console.log(code);
//}
//else
{
//console.log(h(b0, 2), h(b1, 2));
var tokens = is_32 ? this.op_tokens32[b0] : this.op_tokens16[b0];
var code = this.optimize_modrm(tokens, b1, is_32);
}
//console.log(h(b0, 2), code);
break;
case CLASSIFICATION_SINGLE:
// 1 byte op codes (inc eax; ...)
//
// Probably not a huge advantage over the default case: More functions generated
//var code = "cpu.instruction_pointer = cpu.instruction_pointer + 1 | 0; " + body;
//code += "cpu.previous_ip = cpu.instruction_pointer;";
var code = this.text.inc_eip + body + ";" + this.text.previous_eip_to_eip;
if(this.op_classification[b1] === CLASSIFICATION_SINGLE)
{
//code += "cpu.instruction_pointer = cpu.instruction_pointer + 1 | 0;";
code += this.text.inc_eip;
code += is_32 ? this.op_body32[b1] : this.op_body16[b1];
//console.log(h(b0, 2), h(b1, 2), code);
}
else
{
//code += "cpu.large_table[cpu.safe_read8(cpu.instruction_pointer + 1 | 0) << 8 | " + b1 + "](cpu)";
code += this.text.large_table + "[" + this.text.safe_read8 + "(" + this.text.eip_plus_1 + ")<<8|" + b1 + "](" + this.text.cpu + ");";
}
//console.log(h(b0, 2), h(b1, 2), code);
break;
case CLASSIFICATION_IMM8:
// op with imm8 byte and no modrm (add al, 8; mov al, 8; ...)
//var code = "cpu.instruction_pointer = cpu.instruction_pointer + 2 | 0; " + body;
var code = this.text.inc_eip2 + body;
code = this.asserted_replace(code, this.text.read_imm8 + "()", b1 + "");
break;
case CLASSIFICATION_IMM8S:
// op with imm8s byte and no modrm (jz +8; ...)
//var code = "cpu.instruction_pointer = cpu.instruction_pointer + 2 | 0; " + body;
var code = this.text.inc_eip2 + body;
//code = this.asserted_replace(code, "cpu.read_imm8s()", (b1 << 24 >> 24) + "");
code = this.asserted_replace(code, this.text.read_imm8s + "()", (b1 << 24 >> 24) + "");
break
case CLASSIFICATION_PREFIX:
if(b0 !== 0x66 && b0 !== 0x67)
{
var b1_classification = this.op_classification[b1];
if(
//b1_classification === CLASSIFICATION_IMM8 ||
//b1_classification === CLASSIFICATION_IMM8S ||
b1_classification === CLASSIFICATION_MODRM ||
b1_classification === CLASSIFICATION_0F)
{
//var code = "cpu.instruction_pointer = cpu.instruction_pointer + 1 | 0; " + body;
//code = this.asserted_replace(code, "cpu.do_op()", "cpu.large_table[cpu.safe_read8(cpu.instruction_pointer + 1 | 0) << 8 | " + b1 + "](cpu);");
var code = this.text.inc_eip + body;
code = this.asserted_replace(code, this.text.do_op + "()",
this.text.large_table + "[" + this.text.safe_read8 + "(" + this.text.eip_plus_1 + ")<<8|" + b1 + "](" + this.text.cpu + ");");
//console.log(code);
}
else
{
//var code = "cpu.instruction_pointer = cpu.instruction_pointer + 2 | 0; " + body;
var code = this.text.inc_eip2 + body;
//code = this.asserted_replace(code, "cpu.do_op()", is_32 ? this.op_body32[b1] : this.op_body16[b1]);
code = this.asserted_replace(code, this.text.do_op + "()", is_32 ? this.op_body32[b1] : this.op_body16[b1]);
}
}
else
{
//var code = "cpu.instruction_pointer = cpu.instruction_pointer + 2 | 0; " + body;
//code = this.asserted_replace(code, "cpu.do_op()", "cpu.table[" + b1 + "](cpu);");
var code = this.text.inc_eip2 + body;
code = this.asserted_replace(code, this.text.do_op + "()", this.text.table + "[" + b1 + "](" + this.text.cpu + ");");
}
//console.log(h(b0, 2), h(b1, 2), code);
break;
case CLASSIFICATION_NOT_OPTIMIZABLE:
case CLASSIFICATION_NONE:
//var code = "cpu.instruction_pointer = cpu.instruction_pointer + 1 | 0; " + body;
var code = this.text.inc_eip + body;
ignore_second_byte = true;
//!window.bad_code_stats && (window.bad_code_stats = new Int32Array(0x100));
//code += "window.bad_code_stats[" + b0 + "]++;";
//code += "console.log(" + h(b0, 2) + ");";
break;
default:
dbg_assert(false, "unhandled classification: " + classification);
}
}
//console.log(h(b0, 2), h(b1, 2), code);
//code = code.replace(/\bcpu\b/g, this.cpu_identifier_name);
var fn = this.make_fn(code);
if(ignore_second_byte)
{
for(var i = 0; i < 0x100; i++)
{
op_table[b0 | i << 8] = fn;
if(other_op_table) other_op_table[b0 | i << 8] = fn;
}
}
else
{
op_table[op] = fn;
if(other_op_table) other_op_table[op] = fn;
}
if(DEBUG)
{
var end = performance.now();
this.timing_make_create_op += end - start;
}
//console.log(h(b0, 2), operand_size_32, code);
return fn;
};
DynamicTranslator.prototype.stub = function(op, is_32, is_0F)
{
var fn = this.create_op(op, is_32, is_0F);
if(DEBUG)
{
try
{
fn(this.cpu);
}
catch(e)
{
if(e !== MAGIC_CPU_EXCEPTION)
{
dbg_log("First call of op " + h(op, 2) + " failed");
dbg_log("Code: " + fn);
}
throw e;
}
}
else
{
//console.log(fn);
fn(this.cpu);
}
};
DynamicTranslator.prototype.start_translation = function(eip_page, phys_eip)
{
// 1. Read an opcode
// 2. If it crosses a page boundary, stop
// 3. If it's not translatable, insert it into the cache, execute it and quit
// 4. Otherwise:
// 5. Execute it
var cpu = this.cpu;
//var start_eip = cpu.instruction_pointer;
this.current_eip = phys_eip;
//var first_op = op;
//cpu.debug.logop(cpu.instruction_pointer - 1 >>> 0, op);
//var fn = cpu.table[op];
//fn(cpu);
//if((start_eip ^ cpu.instruction_pointer) & ~0xFFF)
//{
// // the instruction crossed a page boundary, stop right here
// // be safe and don't put this into the cache
// return;
//}
//this.current_cache_id = String.fromCharCode(cpu.operand_size_32 | cpu.address_size_32 << 1);
var op = this.tread_imm8();
var code = this.translate_instruction(op);
if(code === undefined)
{
// not translatable instruction, but we can cache the reference
//trans_stats[op]++;
//entry.fn = fn;
//entry.is_single = true;
var result = this.code_translation_cache[phys_eip] = this.not_translatable_op;
this.page_has_code[eip_page] = true;
result(cpu);
return;
}
//var code = translated;
//var instruction_start;
//var count = 1;
if(!this.jumping_instructions[op])
while(true)
{
//instruction_start = cpu.instruction_pointer;
//op = cpu.read_imm8();
//cpu.debug.logop(cpu.instruction_pointer - 1 >>> 0, op);
//var fn = cpu.table[op];
//fn(cpu);
//if((instruction_start ^ cpu.instruction_pointer) & ~0xFFF)
//{
// // the instruction crossed a page boundary, we're done
// break;
//}
//var phys = phys_eip & ~0xFFF | instruction_start & 0xFFF
var start = this.current_eip;
var op = this.tread_imm8();
var translated = this.translate_instruction(op);
if(translated === undefined)
{
//trans_stats[op]++;
//this.code_translation_cache[phys] = {
// fn: fn,
// hit_count: 0,
// is_single: true,
//};
this.page_has_code[eip_page] = true;
this.code_translation_cache[start] = this.not_translatable_op;
break;
}
code += translated;
if(this.jumping_instructions[op])
{
break;
}
//count++;
}
//if(count === 1)
//{
// var result = cpu.table[first_op],
// is_single = true;
//}
//else
{
var result = this.make_fn(code);
//is_single = false;
}
//console.log(code);
this.code_translation_cache[phys_eip] = result;
this.page_has_code[eip_page] = true;
result(cpu);
//entry.fn = result;
//entry.is_single = is_single;
};
DynamicTranslator.prototype.translate_instruction = function(opcode)
{
var cpu = this.cpu;
var is_0F = opcode === 0x0F;
//this.current_cache_id += opcode + "/";
//var start_eip = addr;
var start = this.current_eip - 1;
if(is_0F)
{
var next = this.tread_imm8();
if(!this.translatable0F[next])
{
return undefined;
}
//this.current_eip = addr + 2;
//this.current_cache_id += next + "/";
var table = cpu.operand_size_32 ? this.table0F_32 : this.table0F_16;
//console.log(table[next]);
var code = table[next](cpu);
}
else
{
if(!this.translatable[opcode])
{
return undefined;
}
// opcode has been read already
//this.current_eip = addr + 1;
var table = cpu.operand_size_32 ? this.table32 : this.table16;
//console.log(table[opcode]);
var code = table[opcode](cpu);
}
if((start ^ this.current_eip - 1) & ~0xFFF)
{
return;
}
var size = this.current_eip - start;
dbg_assert(size > 0);
//if(trans_stats[opcode])
// dbg_assert(trans_stats[opcode] === size, [opcode, size, trans_stats[op]]);
//trans_stats[opcode] = size;
//console.log(code, size, h(opcode));
code += this.cpu_identifier_name + ".instruction_pointer += " + size + ";";
//dbg_log(code);
return code;
};
DynamicTranslator.prototype.make_fn = function(code)
{
if(DEBUG)
{
var start = performance.now();
//console.log(code);
try
{
var fn = new Function(this.text.cpu, '"use strict";' + code);
}
catch(e)
{
dbg_log(code);
throw e;
}
var end = performance.now();
this.timing_make_fn += end - start;
}
else
{
var fn = new Function(this.text.cpu, '"use strict";' + code);
}
return fn;
};
DynamicTranslator.prototype.make_fn_cached = function(code, cache_id)
{
var entry = this.fn_cache[cache_id];
if(entry !== undefined)
{
return entry;
}
else
{
this.fn_cache_size++;
if(this.fn_cache_size >= FN_CACHE_LIMIT)
{
dbg_log("fn cache cleared (hit limit)");
this.fn_cache_size = 0;
this.fn_cache = {};
}
return this.fn_cache[cache_id] = new Function(this.cpu_identifier_name, '"use strict";' + code);
}
};
// extract the body of an anonymous function
var jsfunction_anon_body_regex = /^function\s*\([^)]*\)\s*{\s*([\s\S]*?)\s*}\s*$/;
// extract the name of a function
// NOTE: Only ASCII names
var jsfunction_name_regex = /^DynamicTranslator.prototype. = function\s*([$A-Z_][0-9A-Z_$]*)/;
// extract name of the first argument
var jsfunction_arg_regex = /^function\s*(?:[$A-Z_][0-9A-Z_$]*?)?\s*\(\s*([$A-Z_][0-9A-Z_$]*)/i;
// extract value of a function return a single expression
var jsfunction_return_value_regex = /^function\s*\([^)]*\)\s*{\s*return\s*([^;]*?);?\s*}\s*$/;
DynamicTranslator.prototype.jsfunction_anon_extract_body = function(fn)
{
var str = fn.toString();
var match = str.match(jsfunction_anon_body_regex);
dbg_assert(match, "jsfunction_anon_extract_body failed");
return match[1];
};
DynamicTranslator.prototype.jsfunction_extract_name = function(fn)
{
var str = fn.toString();
var match = str.match(jsfunction_name_regex);
return match[1];
};
DynamicTranslator.prototype.jsfunction_extract_arg = function(fn)
{
var str = fn.toString();
var match = str.match(jsfunction_arg_regex);
return match[1];
};
DynamicTranslator.prototype.jsfunction_extract_return = function(fn)
{
var str = fn.toString();
var match = str.match(jsfunction_return_value_regex);
dbg_assert(match, "jsfunction_extract_return failed");
return match[1];
};
// read immediate bytes at translation time (not while the instruction
// is executed)
DynamicTranslator.prototype.tread_imm8 = function()
{
var imm = this.cpu.memory.read8(this.current_eip++);
//this.current_cache_id += String.fromCharCode(imm);
return imm;
};
DynamicTranslator.prototype.tread_imm8s = function()
{
return this.tread_imm8() << 24 >> 24;
};
DynamicTranslator.prototype.tread_imm16 = function()
{
var imm = this.cpu.memory.read16(this.current_eip);
//this.current_cache_id += String.fromCharCode(imm, imm >> 8);
this.current_eip += 2;
return imm;
};
DynamicTranslator.prototype.tread_imm16s = function()
{
return this.tread_imm16() << 16 >> 16;
};
DynamicTranslator.prototype.tread_imm32s = function()
{
var imm = this.cpu.memory.read32s(this.current_eip);
//this.current_cache_id += String.fromCharCode(imm, imm >>> 8, imm >>> 16, imm >> 24);
this.current_eip += 4;
return imm;
};
DynamicTranslator.prototype.tget_seg_prefix_ds = function()
{
if(!this.cpu.protected_mode)
{
return "cpu.get_seg_prefix_ds()";
}
else
{
return this.cpu.get_seg(reg_ds);
}
};
DynamicTranslator.prototype.tget_seg_prefix_ss = function()
{
if(!this.cpu.protected_mode)
{
return "cpu.get_seg_prefix_ss()";
}
else
{
return this.cpu.get_seg(reg_ss);
}
};
DynamicTranslator.prototype.insert_modrm_resolve = function(modrm_byte)
{
if(modrm_byte < 0xC0)
{
var table = this.cpu.address_size_32 ? this.modrm_table32 : this.modrm_table16;
return table[modrm_byte](this.cpu);
}
else
{
// is (if everything works correctly) never going to be used
return "-1";
}
};
DynamicTranslator.prototype.insert_sib_addr = function(mod)
{
var sib_byte = this.tread_imm8();
return this.sib_table[sib_byte](this.cpu, mod);
};
DynamicTranslator.prototype.rewrite_modrm = function(fn, type, x)
{
var tokens = esprima.tokenize(fn);
var start = 0;
var count = tokens.length;
//dbg_assert(tokens[start++].value === "(", '"(" expected')
//dbg_assert(tokens[start++].value === "function", '"function" expected')
//dbg_assert(tokens[start++].value === "(", '"(" expected')
assert_token(start++, "function");
assert_token(start++, "(");
assert_token_type(start++, "Identifier");
if(type === "sib")
{
//dbg_assert(tokens[start++].value === ",", '"," expected')
//dbg_assert(tokens[start++].type === "Identifier", 'Identifier expected')
assert_token(start++, ",");
assert_token_type(start++, "Identifier");
}
//dbg_assert(tokens[start++].value === ")", '")" expected')
//dbg_assert(tokens[start++].value === "{", '"{" expected')
assert_token(start++, ")");
assert_token(start++, "{");
if(tokens[start].value === '"use strict"')
{
// firefox inserts this, skip the string and semicolon
start += 2;
}
assert_token(start++, "return");
//dbg_assert(tokens[count - 3].value === ";", '";" expected')
//dbg_assert(tokens[count - 2].value === "}", '"}" expected')
//dbg_assert(tokens[count - 1].value === ")", '")" expected')
assert_token(--count, "}");
assert_token(--count, ";");
//assert_token(count - 1, ")");
if(type !== "sib")
{
var body = [];
for(var i = start; i < count; i++)
{
body.push(tokens[i].value);
}
var table = type === "32" ? this.modrm_body32 : this.modrm_body16;
table[x] = "(" + body.join("") + ")";
//console.log(table[x]);
}
var replacement_table = {
"read_imm8s": this.cpu_identifier_name + ".translator.tread_imm8s()",
"read_imm16": this.cpu_identifier_name + ".translator.tread_imm16()",
"read_imm32s": this.cpu_identifier_name + ".translator.tread_imm32s()",
"get_seg_prefix_ds": this.cpu_identifier_name + ".translator.tget_seg_prefix_ds()",
"get_seg_prefix_ss": this.cpu_identifier_name + ".translator.tget_seg_prefix_ss()",
};
if(type === "32" && (x & 7) === 4)
{
// special cases:
// 0x04: sib
// 0x44: sib + imm8
// 0x84: sib + imm32
var mod = x & 0xC0;
var result = '"(" + ' + this.cpu_identifier_name + '.translator.insert_sib_addr(' + (mod > 0) + ")";
if(mod === 0)
{
result += '+"|0)"';
}
else if(mod === 0x40)
{
result += '+"+"+' + this.cpu_identifier_name + '.translator.tread_imm8s()+"|0)"';
}
else
{
dbg_assert(mod === 0x80);
result += '+"+"+' + this.cpu_identifier_name + '.translator.tread_imm32s()+"|0)"';
}
}
else if(type === "sib" && (x & 7) === 5)
{
// requires a custom base in, see #1 in
// http://www.sandpile.org/x86/opc_sib.htm
var current = [];
// cut out the first part, reg << n
for(var i = start; i < count; i++)
{
var value = tokens[i].value;
current.push(value);
if(value === ")")
{
break;
}
}
result = this.stringify_code(current.join(""));
result += ' + (mod ? "+' + this.cpu_identifier_name + '.get_seg_prefix(reg_ss)+' + this.cpu_identifier_name + '.reg32s[reg_ebp]" :' +
' "+' + this.cpu_identifier_name + '.get_seg_prefix(reg_ds)+" + ' + this.cpu_identifier_name + '.translator.tread_imm32s())';
}
else
{
var result = [];
var current = ["("];
for(var i = start; i < count; i++)
{
if(is_replaceable(i))
{
var name = tokens[i + 2].value;
result.push(this.stringify_code(current.join("")));
current = [];
result.push(replacement_table[name]);
i += 4;
//while(tokens[i].value !== ")") {
// i++;
//}
}
else
{
var value = tokens[i].value;
// required for "return"
//if(tokens[i].type === "Keyword")
//{
// value += " ";
//}
current.push(value);
}
}
current.push(")");
result.push(this.stringify_code(current.join("")));
result = result.join(" + ");
}
result = "return " + result;
//dbg_log(tokens);
//dbg_log(fn + "");
//dbg_log(result);
if(type === "sib")
{
return new Function(this.cpu_identifier_name, "mod", result);
}
else
{
return new Function(this.cpu_identifier_name, result);
}
function is_replaceable(i)
{
return i < count - 5 &&
tokens[i+0].value === "cpu" &&
tokens[i+0].type === "Identifier" &&
tokens[i+1].value === "." &&
tokens[i+1].type === "Punctuator" &&
replacement_table[tokens[i+2].value] !== undefined &&
tokens[i+2].type === "Identifier"
//&&
//tokens[i+3].value === "(" &&
//tokens[i+3].type === "Punctuator" &&
//tokens[i+4].value === ")" &&
//tokens[i+4].type === "Punctuator";
}
function assert_token(index, token)
{
var value = tokens[index].value;
dbg_assert(value === token, 'expected "' + token + '", saw "' + value + '"');
}
function assert_token_type(index, token_type)
{
var type = tokens[index].type;
dbg_assert(type === token_type, 'expected token of type "' + token_type + '", got "' + type + '"');
}
};
DynamicTranslator.prototype.rewrite_instruction = function(table, index, is_32, is_0F)
{
if(!(is_0F ? this.translatable0F : this.translatable)[index])
{
//return;
}
var fn = table[index];
if(is_32)
{
var t16 = is_0F ? table0F_16 : table16;
if(t16[index] === fn)
{
// The 16 and 32 bit versions of this instruction are the same.
// Rewrite can be skipped, requires 16 bit rewrites to be done before 32 bit rewrites
if(is_0F)
{
this.op_body0F_32[index] = this.op_body0F_16[index];
this.op_tokens0F_32[index] = this.op_tokens0F_16[index];
}
else
{
this.op_body32[index] = this.op_body16[index];
this.op_tokens32[index] = this.op_tokens16[index];
}
return;
//var result = (is_0F ? this.table0F_16 : this.table16)[index];
//dbg_assert(result);
//return result;
}
}
var tokens = esprima.tokenize(fn);
//console.log(tokens);
function assert_token(index, token)
{
var value = tokens[index].value;
dbg_assert(value === token, 'expected "' + token + '", saw "' + value + '"');
}
var start = 0;
var end = tokens.length;
assert_token(start++, "function");
assert_token(start++, "(");
assert_token(start++, "cpu");
assert_token(start++, ")");
assert_token(start++, "{");
assert_token(--end, "}");
tokens = tokens.slice(start, end);
var body_code = this.join_tokens(tokens);
if(is_0F)
{
if(is_32)
{
this.op_body0F_32[index] = body_code;
this.op_tokens0F_32[index] = tokens;
}
else
{
this.op_body0F_16[index] = body_code;
this.op_tokens0F_16[index] = tokens;
}
}
else
{
if(is_32)
{
this.op_body32[index] = body_code;
this.op_tokens32[index] = tokens;
}
else
{
this.op_body16[index] = body_code;
this.op_tokens16[index] = tokens;
}
}
//console.log(body_code);
return;
var src = this.join_tokens(tokens);
var cpu_identifier_name = this.cpu_identifier_name;
var root = esprima.parse(src, { "range": true });
// extract the body of the function
root = root.body[0]["expression"]["body"];
//console.log(root, root.body, root.body[0]);
var body_code = src.substring(root["range"][0], root["range"][1]);
var prefix = '"use strict";';
//console.log(h(index), root);
// get rid of `(function() {` and `})`
var replacements = [
{
start: 0,
end: root.range[0],
value: this.cpu_identifier_name + ".previous_ip = " + this.cpu_identifier_name + ".instruction_pointer; " + this.cpu_identifier_name + ".timestamp_counter++; ",
lifted: false,
},
{
start: root.range[1],
end: src.length,
value: "",
lifted: false,
},
];
acorn.walk.simple(root,
{
//IfStatement: function(node)
//{
// //dbg_log(node);
//},
VariableDeclaration: function(node)
{
//dbg_log(node);
var declarations = node.declarations;
if(declarations[0].id.name === "modrm_byte")
{
dbg_assert(declarations.length === 1);
//dbg_log(src.substr(node.range[0] - 1, node.range[1] - node.range[0]));
replacements.push({
start: node.range[0],
end: node.range[1],
//value: "cpu.instruction_pointer++;",
value: "",
lifted: false,
});
prefix += "var m = " + cpu_identifier_name + ".translator.tread_imm8();"
// rename so it doesn't get changed below
declarations[0].id.name = "modrm byte";
}
}
});
var call_replacements = {
"read_imm8": "" + this.cpu_identifier_name + ".translator.tread_imm8()",
"read_imm8s": "" + this.cpu_identifier_name + ".translator.tread_imm8s()",
"read_imm16": "" + this.cpu_identifier_name + ".translator.tread_imm16()",
"read_imm16s": "" + this.cpu_identifier_name + ".translator.tread_imm16s()",
"read_imm32s": "" + this.cpu_identifier_name + ".translator.tread_imm32s()",
"modrm_resolve": "" + this.cpu_identifier_name + ".translator.insert_modrm_resolve(m)",
};
acorn.walk.simple(root,
{
Identifier: function(node)
{
//dbg_log("ident", node);
if(node.name === "modrm_byte")
{
//dbg_log(src.substr(node.range[0] - 1, node.range[1] - node.range[0]));
replacements.push({
start: node.range[0],
end: node.range[1],
value: " + m + ",
lifted: true,
});
}
},
CallExpression: function(node)
{
//dbg_log(node);
var callee = node.callee;
if(callee.type === "MemberExpression")
{
var name = callee.property.name;
var r = call_replacements[name];
if(r !== undefined)
{
replacements.push({
start: node.range[0],
end: node.range[1],
value: " + " + r + " + ",
lifted: true,
});
}
}
},
});
replacements.sort(function(a, b)
{
return a.start - b.start;
});
var result = "";
var current = "";
var offset = 0;
var start = 0;
for(var i = 0; i < replacements.length; i++)
{
var r = replacements[i];
dbg_assert(r.start <= r.end);
//dbg_assert(start <= r.start);
//src.substring(start, r.start);
if(start > r.start)
continue;
current += src.substring(start, r.start);
if(r.lifted)
{
result += this.stringify_code(current);
result += r.value;
current = "";
}
else
{
current += r.value;
}
start = r.end;
}
current += src.substring(start);
result += this.stringify_code(current);
//dbg_log(current);
result = prefix + "return " + result + ";";
//dbg_log(result);
//dbg_log(src)
return new Function(this.cpu_identifier_name, result);
};
DynamicTranslator.prototype.stringify_code = function(code)
{
dbg_assert(typeof code === "string");
return JSON.stringify(code);
};
DynamicTranslator.prototype.not_translatable_op = function(cpu)
{
cpu.cycle();
};
DynamicTranslator.prototype.optimize_modrm = function(tokens, modrm_byte, is_32)
{
tokens = tokens.slice();
tokens = this.replace_switch_statement(tokens, function(expr, cases)
{
//console.log(this.join_tokens(expr), modrm_byte >> 3 & 7);
//console.log(cases);
dbg_assert(this.join_tokens(expr) === "modrm_byte>>3&7");
var index = modrm_byte >> 3 & 7;
for(var i = 0; i < cases.length; i++)
{
if(+cases[i].expr[0].value === index)
{
break;
}
}
var body = cases[i].body;
var end = body.length;
dbg_assert(+cases[i].expr[0].value === index);
dbg_assert(body[--end].value === ";", body[end].value);
dbg_assert(body[--end].value === "break");
return body.slice(0, end);
}.bind(this));
var code = this.join_tokens(tokens);
var modrm_table = is_32 ? this.modrm_body32 : this.modrm_body16;
//console.log(h(op, 2), "0f case", body);
//var code = "cpu.instruction_pointer = cpu.instruction_pointer + 2 | 0; " + code;
var code = this.text.inc_eip2 + code;
var modrm_identifier;
code = this.asserted_replace(code, this.text.modrm_byte + "=" + this.text.read_imm8 + "()", "");
//code = this.asserted_replace(code, /cpu.modrm_resolve\(modrm_byte\)/g, modrm_table[modrm_byte]);
//code = code.replace(/modrm_byte>>3&7/g, (modrm_byte >> 3 & 7) + "");
//code = code.replace(/modrm_byte&7/g, (modrm_byte & 7) + "");
//code = code.replace(/modrm_byte<<1&14/g, (modrm_byte << 1 & 14) + "");
//code = code.replace(/modrm_byte>>2&14/g, (modrm_byte >> 2 & 14) + "");
//code = code.replace(/modrm_byte<<2&0xC\|modrm_byte>>2&1/g, (modrm_byte << 2 & 0xC | modrm_byte >> 2 & 1) + "");
//code = code.replace(/modrm_byte>>1&0xC\|modrm_byte>>5&1/g, (modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1) + "");
//console.log(code);
code = code.replace(new RegExp("\\b" + this.escape_regexp(this.text.modrm_byte) + "\\b", "g"), modrm_byte + "");
//console.log(code);
return code;
};
DynamicTranslator.prototype.asserted_replace = function(str, pattern, replacement)
{
var result = str.replace(pattern, replacement);
console.assert(result !== str, "Failed to replace `" + pattern + "` with `" + replacement + "` in `" + str + "`");
return result;
}
DynamicTranslator.prototype.generate_xor_self = function(opsize, reg)
{
if(opsize === 32)
{
var data = "reg32s[" + reg + "]";
}
else if(opsize === 16)
{
var data = "reg16[" + (reg << 1) + "]";
reg <<= 1;
}
else
{
dbg_assert(opsize === 8);
var data = "reg8[" + (reg << 2 & 0xC | reg >> 2 & 1) + "]";
}
var code = "cpu.instruction_pointer = cpu.instruction_pointer + 2 | 0;" +
"cpu.flags_changed = 0; cpu.flags = cpu.flags & ~1 & ~0x10 & ~0x80 & ~0x800 | 4 | 0x40;" +
"cpu." + data + " = 0;";
return code;
}
DynamicTranslator.prototype.xor_self = function(cpu)
{
cpu.instruction_pointer = cpu.instruction_pointer + 2 | 0;
cpu.flags_changed = 0;
cpu.flags = cpu.flags & ~1 & ~flag_adjust & ~flag_sign & ~flag_overflow | flag_zero | flag_parity;
};
DynamicTranslator.prototype.join_tokens = function(tokens)
{
return tokens.map(function(t)
{
if(t.value === "var")
{
return "var ";
}
else if(t.value === "case")
{
return "case ";
}
else if(t.value === "else")
{
return "else ";
}
else if(t.value === "throw")
{
return "throw ";
}
else if(t.value === "do")
{
return "do ";
}
else if(t.value === "break")
{
return "break ";
}
else
{
return t.value;
}
}).join("");
}
DynamicTranslator.prototype.replace_switch_statement = function(tokens, cb)
{
for(var i = 0; i < tokens.length; i++)
{
var token = tokens[i];
if(token.value === "switch")
{
var switch_expression;
var cases = [];
var switch_start = i;
dbg_assert(tokens[i++].value === "switch");
dbg_assert(tokens[i].value === "(");
var expression_start = i + 1;
var expression_end = this.find_matching(tokens, i, "(", ")");
dbg_assert(expression_end !== undefined);
switch_expression = tokens.slice(expression_start, expression_end);
i = expression_end + 1;
dbg_assert(tokens[i].value === "{", tokens[i-1].value);
var switch_end = this.find_matching(tokens, i, "{", "}");
dbg_assert(switch_end !== undefined);
dbg_assert(tokens[switch_end].value === "}");
dbg_assert(tokens[i++].value === "{");
//console.log(this.join_tokens(tokens));
while(i < switch_end)
{
var value = tokens[i++].value;
dbg_assert(value === "default" || value === "case");
var start = i;
i = this.find_forward(tokens, i, ":");
dbg_assert(i !== undefined);
dbg_assert(i < switch_end);
var is_case = value === "case";
if(is_case)
{
var case_expression = tokens.slice(start, i);
//console.log(this.join_tokens(case_expression));
}
i++;
var start = i;
i = this.find_forward(tokens, i, "break");
if(i === undefined || i >= switch_end)
{
i = switch_end;
}
else
{
dbg_assert(tokens[i++].value === "break");
dbg_assert(tokens[i++].value === ";");
}
//if(i === undefined)
//{
// i = this.find_forward(tokens, i, "default");
//}
var case_body = tokens.slice(start, i);
//console.log(this.join_tokens(case_body));
cases.push({
expr: case_expression,
body: case_body,
is_case: is_case,
});
}
var replacement = cb(switch_expression, cases);
var old_length = switch_end - switch_start + 1;
//console.log("old code", this.join_tokens(tokens.slice(switch_start, switch_start + old_length)));
tokens.splice.apply(tokens, [switch_start, old_length].concat(replacement));
//console.log("replaced by", this.join_tokens(replacement));
i = switch_end - old_length + replacement.length;
}
}
return tokens;
};
DynamicTranslator.prototype.find_matching = function(tokens, i, open, close)
{
var depth = 0;
while(i < tokens.length)
{
var token = tokens[i];
var token_value = token.value;
if(token_value === open)
{
depth++;
}
else if(token_value === close)
{
depth--;
if(depth === 0)
{
return i;
}
}
i++;
}
};
DynamicTranslator.prototype.find_forward = function(tokens, i, value)
{
while(i < tokens.length)
{
if(tokens[i].value === value)
{
return i;
}
i++;
}
};
DynamicTranslator.prototype.escape_regexp = function(str)
{
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
};
/*
* This file contains functions to decode the modrm and sib bytes
*
* These functions return a virtual address
*/
"use strict";
(function()
{
CPU.prototype.modrm_table16 = Array(0xC0);
CPU.prototype.modrm_table32 = Array(0xC0);
CPU.prototype.sib_table = Array(0x100);
CPU.prototype.modrm_table16[0x00 | 0] = function(cpu)
{
return cpu.get_seg_prefix_ds() + ((cpu.reg16[reg_bx] + cpu.reg16[reg_si]) & 0xFFFF) | 0;
};
CPU.prototype.modrm_table16[0x40 | 0] = function(cpu)
{
return cpu.get_seg_prefix_ds() + ((cpu.reg16[reg_bx] + cpu.reg16[reg_si]) + cpu.read_imm8s() & 0xFFFF) | 0;
};
CPU.prototype.modrm_table16[0x80 | 0] = function(cpu)
{
return cpu.get_seg_prefix_ds() + ((cpu.reg16[reg_bx] + cpu.reg16[reg_si]) + cpu.read_imm16() & 0xFFFF) | 0;
};
CPU.prototype.modrm_table16[0x00 | 1] = function(cpu)
{
return cpu.get_seg_prefix_ds() + ((cpu.reg16[reg_bx] + cpu.reg16[reg_di]) & 0xFFFF) | 0;
};
CPU.prototype.modrm_table16[0x40 | 1] = function(cpu)
{
return cpu.get_seg_prefix_ds() + ((cpu.reg16[reg_bx] + cpu.reg16[reg_di]) + cpu.read_imm8s() & 0xFFFF) | 0;
};
CPU.prototype.modrm_table16[0x80 | 1] = function(cpu)
{
return cpu.get_seg_prefix_ds() + ((cpu.reg16[reg_bx] + cpu.reg16[reg_di]) + cpu.read_imm16() & 0xFFFF) | 0;
};
CPU.prototype.modrm_table16[0x00 | 2] = function(cpu)
{
return cpu.get_seg_prefix_ss() + ((cpu.reg16[reg_bp] + cpu.reg16[reg_si]) & 0xFFFF) | 0;
};
CPU.prototype.modrm_table16[0x40 | 2] = function(cpu)
{
return cpu.get_seg_prefix_ss() + ((cpu.reg16[reg_bp] + cpu.reg16[reg_si]) + cpu.read_imm8s() & 0xFFFF) | 0;
};
CPU.prototype.modrm_table16[0x80 | 2] = function(cpu)
{
return cpu.get_seg_prefix_ss() + ((cpu.reg16[reg_bp] + cpu.reg16[reg_si]) + cpu.read_imm16() & 0xFFFF) | 0;
};
CPU.prototype.modrm_table16[0x00 | 3] = function(cpu)
{
return cpu.get_seg_prefix_ss() + ((cpu.reg16[reg_bp] + cpu.reg16[reg_di]) & 0xFFFF) | 0;
};
CPU.prototype.modrm_table16[0x40 | 3] = function(cpu)
{
return cpu.get_seg_prefix_ss() + ((cpu.reg16[reg_bp] + cpu.reg16[reg_di]) + cpu.read_imm8s() & 0xFFFF) | 0;
};
CPU.prototype.modrm_table16[0x80 | 3] = function(cpu)
{
return cpu.get_seg_prefix_ss() + ((cpu.reg16[reg_bp] + cpu.reg16[reg_di]) + cpu.read_imm16() & 0xFFFF) | 0;
};
CPU.prototype.modrm_table16[0x00 | 4] = function(cpu)
{
return cpu.get_seg_prefix_ds() + ((cpu.reg16[reg_si]) & 0xFFFF) | 0;
};
CPU.prototype.modrm_table16[0x40 | 4] = function(cpu)
{
return cpu.get_seg_prefix_ds() + ((cpu.reg16[reg_si]) + cpu.read_imm8s() & 0xFFFF) | 0;
};
CPU.prototype.modrm_table16[0x80 | 4] = function(cpu)
{
return cpu.get_seg_prefix_ds() + ((cpu.reg16[reg_si]) + cpu.read_imm16() & 0xFFFF) | 0;
};
CPU.prototype.modrm_table16[0x00 | 5] = function(cpu)
{
return cpu.get_seg_prefix_ds() + ((cpu.reg16[reg_di]) & 0xFFFF) | 0;
};
CPU.prototype.modrm_table16[0x40 | 5] = function(cpu)
{
return cpu.get_seg_prefix_ds() + ((cpu.reg16[reg_di]) + cpu.read_imm8s() & 0xFFFF) | 0;
};
CPU.prototype.modrm_table16[0x80 | 5] = function(cpu)
{
return cpu.get_seg_prefix_ds() + ((cpu.reg16[reg_di]) + cpu.read_imm16() & 0xFFFF) | 0;
};
CPU.prototype.modrm_table16[0x00 | 6] = function(cpu)
{
return cpu.get_seg_prefix_ss() + ((cpu.reg16[reg_bp]) & 0xFFFF) | 0;
};
CPU.prototype.modrm_table16[0x40 | 6] = function(cpu)
{
return cpu.get_seg_prefix_ss() + ((cpu.reg16[reg_bp]) + cpu.read_imm8s() & 0xFFFF) | 0;
};
CPU.prototype.modrm_table16[0x80 | 6] = function(cpu)
{
return cpu.get_seg_prefix_ss() + ((cpu.reg16[reg_bp]) + cpu.read_imm16() & 0xFFFF) | 0;
};
CPU.prototype.modrm_table16[0x00 | 7] = function(cpu)
{
return cpu.get_seg_prefix_ds() + ((cpu.reg16[reg_bx]) & 0xFFFF) | 0;
};
CPU.prototype.modrm_table16[0x40 | 7] = function(cpu)
{
return cpu.get_seg_prefix_ds() + ((cpu.reg16[reg_bx]) + cpu.read_imm8s() & 0xFFFF) | 0;
};
CPU.prototype.modrm_table16[0x80 | 7] = function(cpu)
{
return cpu.get_seg_prefix_ds() + ((cpu.reg16[reg_bx]) + cpu.read_imm16() & 0xFFFF) | 0;
};
CPU.prototype.modrm_table32[0x00 | 0] = function(cpu)
{
return(cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax]) | 0;
};
CPU.prototype.modrm_table32[0x40 | 0] = function(cpu)
{
return(cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax]) + cpu.read_imm8s() | 0;
};
CPU.prototype.modrm_table32[0x80 | 0] = function(cpu)
{
return(cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax]) + cpu.read_imm32s() | 0;
};;
CPU.prototype.modrm_table32[0x00 | 1] = function(cpu)
{
return(cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx]) | 0;
};
CPU.prototype.modrm_table32[0x40 | 1] = function(cpu)
{
return(cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx]) + cpu.read_imm8s() | 0;
};
CPU.prototype.modrm_table32[0x80 | 1] = function(cpu)
{
return(cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx]) + cpu.read_imm32s() | 0;
};;
CPU.prototype.modrm_table32[0x00 | 2] = function(cpu)
{
return(cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx]) | 0;
};
CPU.prototype.modrm_table32[0x40 | 2] = function(cpu)
{
return(cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx]) + cpu.read_imm8s() | 0;
};
CPU.prototype.modrm_table32[0x80 | 2] = function(cpu)
{
return(cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx]) + cpu.read_imm32s() | 0;
};;
CPU.prototype.modrm_table32[0x00 | 3] = function(cpu)
{
return(cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx]) | 0;
};
CPU.prototype.modrm_table32[0x40 | 3] = function(cpu)
{
return(cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx]) + cpu.read_imm8s() | 0;
};
CPU.prototype.modrm_table32[0x80 | 3] = function(cpu)
{
return(cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx]) + cpu.read_imm32s() | 0;
};;
CPU.prototype.modrm_table32[0x00 | 4] = function(cpu)
{
return(cpu.sib_table[cpu.read_imm8()](cpu, false)) | 0;
};
CPU.prototype.modrm_table32[0x40 | 4] = function(cpu)
{
return(cpu.sib_table[cpu.read_imm8()](cpu, false)) + cpu.read_imm8s() | 0;
};
CPU.prototype.modrm_table32[0x80 | 4] = function(cpu)
{
return(cpu.sib_table[cpu.read_imm8()](cpu, false)) + cpu.read_imm32s() | 0;
};;
CPU.prototype.modrm_table32[0x00 | 5] = function(cpu)
{
return(cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp]) | 0;
};
CPU.prototype.modrm_table32[0x40 | 5] = function(cpu)
{
return(cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp]) + cpu.read_imm8s() | 0;
};
CPU.prototype.modrm_table32[0x80 | 5] = function(cpu)
{
return(cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp]) + cpu.read_imm32s() | 0;
};;
CPU.prototype.modrm_table32[0x00 | 6] = function(cpu)
{
return(cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi]) | 0;
};
CPU.prototype.modrm_table32[0x40 | 6] = function(cpu)
{
return(cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi]) + cpu.read_imm8s() | 0;
};
CPU.prototype.modrm_table32[0x80 | 6] = function(cpu)
{
return(cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi]) + cpu.read_imm32s() | 0;
};;
CPU.prototype.modrm_table32[0x00 | 7] = function(cpu)
{
return(cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi]) | 0;
};
CPU.prototype.modrm_table32[0x40 | 7] = function(cpu)
{
return(cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi]) + cpu.read_imm8s() | 0;
};
CPU.prototype.modrm_table32[0x80 | 7] = function(cpu)
{
return(cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi]) + cpu.read_imm32s() | 0;
};;
// special cases
CPU.prototype.modrm_table16[0x00 | 6] = function(cpu)
{
return cpu.get_seg_prefix_ds() + cpu.read_imm16() | 0;
}
CPU.prototype.modrm_table32[0x00 | 5] = function(cpu)
{
return cpu.get_seg_prefix_ds() + cpu.read_imm32s() | 0;
};
CPU.prototype.modrm_table32[0x00 | 4] = function(cpu)
{
return cpu.sib_table[cpu.read_imm8()](cpu, false) | 0;
};
CPU.prototype.modrm_table32[0x40 | 4] = function(cpu)
{
return cpu.sib_table[cpu.read_imm8()](cpu, true) + cpu.read_imm8s() | 0;
};
CPU.prototype.modrm_table32[0x80 | 4] = function(cpu)
{
return cpu.sib_table[cpu.read_imm8()](cpu, true) + cpu.read_imm32s() | 0;
};
for(var low = 0; low < 8; low++)
{
for(var high = 0; high < 3; high++)
{
var x = low | high << 6;
for(var i = 1; i < 8; i++)
{
CPU.prototype.modrm_table32[x | i << 3] = CPU.prototype.modrm_table32[x];
CPU.prototype.modrm_table16[x | i << 3] = CPU.prototype.modrm_table16[x];
}
}
}
CPU.prototype.sib_table[0x00 | 0 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x00 | 0 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x00 | 0 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x00 | 0 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x00 | 0 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax]) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x00 | 0 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax]) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x00 | 0 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x00 | 0 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0x40 | 0 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x40 | 0 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x40 | 0 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x40 | 0 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x40 | 0 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 1) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x40 | 0 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 1) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x40 | 0 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x40 | 0 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0x80 | 0 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x80 | 0 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x80 | 0 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x80 | 0 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x80 | 0 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 2) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x80 | 0 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 2) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x80 | 0 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x80 | 0 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0xC0 | 0 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0xC0 | 0 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0xC0 | 0 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0xC0 | 0 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0xC0 | 0 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 3) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0xC0 | 0 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 3) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0xC0 | 0 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0xC0 | 0 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_eax] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};;
CPU.prototype.sib_table[0x00 | 1 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x00 | 1 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x00 | 1 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x00 | 1 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x00 | 1 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx]) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x00 | 1 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx]) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x00 | 1 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x00 | 1 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0x40 | 1 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x40 | 1 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x40 | 1 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x40 | 1 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x40 | 1 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 1) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x40 | 1 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 1) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x40 | 1 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x40 | 1 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0x80 | 1 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x80 | 1 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x80 | 1 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x80 | 1 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x80 | 1 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 2) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x80 | 1 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 2) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x80 | 1 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x80 | 1 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0xC0 | 1 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0xC0 | 1 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0xC0 | 1 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0xC0 | 1 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0xC0 | 1 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 3) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0xC0 | 1 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 3) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0xC0 | 1 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0xC0 | 1 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_ecx] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};;
CPU.prototype.sib_table[0x00 | 2 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x00 | 2 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x00 | 2 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x00 | 2 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x00 | 2 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx]) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x00 | 2 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx]) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x00 | 2 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x00 | 2 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0x40 | 2 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x40 | 2 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x40 | 2 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x40 | 2 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x40 | 2 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 1) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x40 | 2 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 1) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x40 | 2 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x40 | 2 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0x80 | 2 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x80 | 2 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x80 | 2 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x80 | 2 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x80 | 2 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 2) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x80 | 2 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 2) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x80 | 2 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x80 | 2 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0xC0 | 2 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0xC0 | 2 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0xC0 | 2 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0xC0 | 2 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0xC0 | 2 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 3) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0xC0 | 2 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 3) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0xC0 | 2 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0xC0 | 2 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_edx] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};;
CPU.prototype.sib_table[0x00 | 3 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x00 | 3 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x00 | 3 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x00 | 3 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x00 | 3 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx]) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x00 | 3 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx]) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x00 | 3 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x00 | 3 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0x40 | 3 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x40 | 3 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x40 | 3 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x40 | 3 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x40 | 3 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 1) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x40 | 3 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 1) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x40 | 3 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x40 | 3 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0x80 | 3 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x80 | 3 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x80 | 3 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x80 | 3 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x80 | 3 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 2) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x80 | 3 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 2) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x80 | 3 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x80 | 3 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0xC0 | 3 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0xC0 | 3 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0xC0 | 3 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0xC0 | 3 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0xC0 | 3 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 3) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0xC0 | 3 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 3) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0xC0 | 3 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0xC0 | 3 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebx] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};;
CPU.prototype.sib_table[0x00 | 4 << 3 | 0] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x00 | 4 << 3 | 1] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x00 | 4 << 3 | 2] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x00 | 4 << 3 | 3] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x00 | 4 << 3 | 4] = function(cpu, mod)
{
return cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x00 | 4 << 3 | 5] = function(cpu, mod)
{
return (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x00 | 4 << 3 | 6] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x00 | 4 << 3 | 7] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0x40 | 4 << 3 | 0] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x40 | 4 << 3 | 1] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x40 | 4 << 3 | 2] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x40 | 4 << 3 | 3] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x40 | 4 << 3 | 4] = function(cpu, mod)
{
return cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x40 | 4 << 3 | 5] = function(cpu, mod)
{
return (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x40 | 4 << 3 | 6] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x40 | 4 << 3 | 7] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0x80 | 4 << 3 | 0] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x80 | 4 << 3 | 1] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x80 | 4 << 3 | 2] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x80 | 4 << 3 | 3] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x80 | 4 << 3 | 4] = function(cpu, mod)
{
return cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x80 | 4 << 3 | 5] = function(cpu, mod)
{
return (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x80 | 4 << 3 | 6] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x80 | 4 << 3 | 7] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0xC0 | 4 << 3 | 0] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0xC0 | 4 << 3 | 1] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0xC0 | 4 << 3 | 2] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0xC0 | 4 << 3 | 3] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0xC0 | 4 << 3 | 4] = function(cpu, mod)
{
return cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0xC0 | 4 << 3 | 5] = function(cpu, mod)
{
return (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0xC0 | 4 << 3 | 6] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0xC0 | 4 << 3 | 7] = function(cpu, mod)
{
return cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};;
CPU.prototype.sib_table[0x00 | 5 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x00 | 5 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x00 | 5 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x00 | 5 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x00 | 5 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp]) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x00 | 5 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp]) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x00 | 5 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x00 | 5 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0x40 | 5 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x40 | 5 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x40 | 5 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x40 | 5 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x40 | 5 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 1) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x40 | 5 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 1) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x40 | 5 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x40 | 5 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0x80 | 5 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x80 | 5 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x80 | 5 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x80 | 5 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x80 | 5 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 2) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x80 | 5 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 2) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x80 | 5 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x80 | 5 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0xC0 | 5 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0xC0 | 5 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0xC0 | 5 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0xC0 | 5 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0xC0 | 5 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 3) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0xC0 | 5 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 3) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0xC0 | 5 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0xC0 | 5 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_ebp] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};;
CPU.prototype.sib_table[0x00 | 6 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x00 | 6 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x00 | 6 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x00 | 6 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x00 | 6 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi]) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x00 | 6 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi]) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x00 | 6 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x00 | 6 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0x40 | 6 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x40 | 6 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x40 | 6 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x40 | 6 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x40 | 6 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 1) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x40 | 6 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 1) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x40 | 6 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x40 | 6 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0x80 | 6 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x80 | 6 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x80 | 6 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x80 | 6 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x80 | 6 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 2) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x80 | 6 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 2) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x80 | 6 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x80 | 6 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0xC0 | 6 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0xC0 | 6 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0xC0 | 6 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0xC0 | 6 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0xC0 | 6 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 3) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0xC0 | 6 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 3) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0xC0 | 6 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0xC0 | 6 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_esi] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};;
CPU.prototype.sib_table[0x00 | 7 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x00 | 7 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x00 | 7 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x00 | 7 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x00 | 7 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi]) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x00 | 7 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi]) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x00 | 7 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x00 | 7 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi]) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0x40 | 7 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x40 | 7 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x40 | 7 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x40 | 7 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x40 | 7 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 1) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x40 | 7 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 1) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x40 | 7 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x40 | 7 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 1) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0x80 | 7 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0x80 | 7 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0x80 | 7 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0x80 | 7 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0x80 | 7 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 2) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0x80 | 7 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 2) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0x80 | 7 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0x80 | 7 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 2) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.sib_table[0xC0 | 7 << 3 | 0] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_eax] | 0;
};
CPU.prototype.sib_table[0xC0 | 7 << 3 | 1] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ecx] | 0;
};
CPU.prototype.sib_table[0xC0 | 7 << 3 | 2] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edx] | 0;
};
CPU.prototype.sib_table[0xC0 | 7 << 3 | 3] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_ebx] | 0;
};
CPU.prototype.sib_table[0xC0 | 7 << 3 | 4] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 3) + cpu.get_seg_prefix_ss() + cpu.reg32s[reg_esp] | 0;
};
CPU.prototype.sib_table[0xC0 | 7 << 3 | 5] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 3) + (mod ? cpu.get_seg_prefix_ss() + cpu.reg32s[reg_ebp] : cpu.get_seg_prefix_ds() + cpu.read_imm32s()) | 0;
};
CPU.prototype.sib_table[0xC0 | 7 << 3 | 6] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_esi] | 0;
};
CPU.prototype.sib_table[0xC0 | 7 << 3 | 7] = function(cpu, mod)
{
return(cpu.reg32s[reg_edi] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};;
CPU.prototype.modrm_resolve = function(modrm_byte)
{
return(this.address_size_32 ? this.modrm_table32 : this.modrm_table16)[modrm_byte](this);
};
})();
/*
* 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
*
* popcnt
*
* Gets #included by cpu.macro.js
*
*/
"use strict";
CPU.prototype.add = function(dest_operand, source_operand, op_size)
{
//if(this.safe_read32s(this.instruction_pointer + 1) === 0) throw "0000000";
this.last_op1 = dest_operand;
this.last_op2 = source_operand;
this.last_add_result = this.last_result = dest_operand + source_operand | 0;
this.last_op_size = op_size;
this.flags_changed = flags_all;
return this.last_result;
}
CPU.prototype.adc = function(dest_operand, source_operand, op_size)
{
var cf = this.getcf();
this.last_op1 = dest_operand;
this.last_op2 = source_operand;
this.last_add_result = this.last_result = (dest_operand + source_operand | 0) + cf | 0;
this.last_op_size = op_size;
this.flags_changed = flags_all;
return this.last_result;
}
CPU.prototype.cmp = function(dest_operand, source_operand, op_size)
{
this.last_add_result = dest_operand;
this.last_op2 = source_operand;
this.last_op1 = this.last_result = dest_operand - source_operand | 0;
this.last_op_size = op_size;
this.flags_changed = flags_all;
}
CPU.prototype.sub = function(dest_operand, source_operand, op_size)
{
this.last_add_result = dest_operand;
this.last_op2 = source_operand;
this.last_op1 = this.last_result = dest_operand - source_operand | 0;
this.last_op_size = op_size;
this.flags_changed = flags_all;
return this.last_result;
}
CPU.prototype.sbb = function(dest_operand, source_operand, op_size)
{
var cf = this.getcf();
this.last_add_result = dest_operand;
this.last_op2 = source_operand;
this.last_op1 = this.last_result = dest_operand - source_operand - cf | 0;
this.last_op_size = op_size;
this.flags_changed = flags_all;
return this.last_result;
}
/*
* inc and dec
*/
CPU.prototype.inc = function(dest_operand, op_size)
{
this.flags = (this.flags & ~1) | this.getcf();
this.last_op1 = dest_operand;
this.last_op2 = 1;
this.last_add_result = this.last_result = dest_operand + 1 | 0;
this.last_op_size = op_size;
this.flags_changed = flags_all & ~1;
return this.last_result;
}
CPU.prototype.dec = function(dest_operand, op_size)
{
this.flags = (this.flags & ~1) | this.getcf();
this.last_add_result = dest_operand;
this.last_op2 = 1;
this.last_op1 = this.last_result = dest_operand - 1 | 0;
this.last_op_size = op_size;
this.flags_changed = flags_all & ~1;
return this.last_result;
}
/*
* neg
*/
CPU.prototype.neg = function(dest_operand, op_size)
{
this.last_op1 = this.last_result = -dest_operand | 0;
this.flags_changed = flags_all;
this.last_add_result = 0;
this.last_op2 = dest_operand;
this.last_op_size = op_size;
return this.last_result;
}
/*
* mul, imul, div, idiv
*
* Note: imul has some extra opcodes
* while other functions only allow
* ax * modrm
*/
CPU.prototype.mul8 = function(source_operand)
{
var result = source_operand * this.reg8[reg_al];
this.reg16[reg_ax] = result;
if(result < 0x100)
{
this.flags = this.flags & ~1 & ~flag_overflow;
}
else
{
this.flags = this.flags | 1 | flag_overflow;
}
this.flags_changed = 0;
}
CPU.prototype.imul8 = function(source_operand)
{
var result = source_operand * this.reg8s[reg_al];
this.reg16[reg_ax] = result;
if(result > 0x7F || result < -0x80)
{
this.flags = this.flags | 1 | flag_overflow;
}
else
{
this.flags = this.flags & ~1 & ~flag_overflow;
}
this.flags_changed = 0;
}
CPU.prototype.mul16 = function(source_operand)
{
var result = source_operand * this.reg16[reg_ax],
high_result = result >>> 16;
//console.log(h(a) + " * " + h(this.reg16[reg_ax]) + " = " + h(result));
this.reg16[reg_ax] = result;
this.reg16[reg_dx] = high_result;
if(high_result === 0)
{
this.flags &= ~1 & ~flag_overflow;
}
else
{
this.flags |= 1 | flag_overflow;
}
this.flags_changed = 0;
}
/*
* imul with 1 argument
* ax = ax * r/m
*/
CPU.prototype.imul16 = function(source_operand)
{
var result = source_operand * this.reg16s[reg_ax];
this.reg16[reg_ax] = result;
this.reg16[reg_dx] = result >> 16;
if(result > 0x7FFF || result < -0x8000)
{
this.flags |= 1 | flag_overflow;
}
else
{
this.flags &= ~1 & ~flag_overflow;
}
this.flags_changed = 0;
}
/*
* imul with 2 or 3 arguments
* reg = reg * r/m
* reg = imm * r/m
*/
CPU.prototype.imul_reg16 = function(operand1, operand2)
{
dbg_assert(operand1 < 0x8000 && operand1 >= -0x8000);
dbg_assert(operand2 < 0x8000 && operand2 >= -0x8000);
var result = operand1 * operand2;
if(result > 0x7FFF || result < -0x8000)
{
this.flags |= 1 | flag_overflow;
}
else
{
this.flags &= ~1 & ~flag_overflow;
}
this.flags_changed = 0;
return result;
}
CPU.prototype.mul32 = function(source_operand)
{
var dest_operand = this.reg32s[reg_eax];
var a00 = dest_operand & 0xFFFF; var a16 = dest_operand >>> 16; var b00 = source_operand & 0xFFFF; var b16 = source_operand >>> 16; var low_result = a00 * b00; var mid = (low_result >>> 16) + (a16 * b00 | 0) | 0; var high_result = mid >>> 16; mid = (mid & 0xFFFF) + (a00 * b16 | 0) | 0; low_result = (mid << 16) | low_result & 0xFFFF; high_result = ((mid >>> 16) + (a16 * b16 | 0) | 0) + high_result | 0;;
this.reg32s[reg_eax] = low_result;
this.reg32s[reg_edx] = high_result;
if(high_result === 0)
{
this.flags &= ~1 & ~flag_overflow;
}
else
{
this.flags |= 1 | flag_overflow;
}
this.flags_changed = 0;
//console.log(h(source_operand >>> 0, 8) + " * " + h(dest_operand >>> 0, 8));
//console.log("= " + h(this.reg32[reg_edx], 8) + ":" + h(this.reg32[reg_eax], 8));
}
CPU.prototype.imul32 = function(source_operand)
{
dbg_assert(source_operand < 0x80000000 && source_operand >= -0x80000000);
var dest_operand = this.reg32s[reg_eax];
var is_neg = false; if(dest_operand < 0) { is_neg = true; dest_operand = -dest_operand | 0; } if(source_operand < 0) { is_neg = !is_neg; source_operand = -source_operand | 0; } var a00 = dest_operand & 0xFFFF; var a16 = dest_operand >>> 16; var b00 = source_operand & 0xFFFF; var b16 = source_operand >>> 16; var low_result = a00 * b00; var mid = (low_result >>> 16) + (a16 * b00 | 0) | 0; var high_result = mid >>> 16; mid = (mid & 0xFFFF) + (a00 * b16 | 0) | 0; low_result = (mid << 16) | low_result & 0xFFFF; high_result = ((mid >>> 16) + (a16 * b16 | 0) | 0) + high_result | 0;; if(is_neg) { low_result = -low_result | 0; high_result = ~high_result + !low_result | 0; };
this.reg32s[reg_eax] = low_result;
this.reg32s[reg_edx] = high_result;
if(high_result === (low_result >> 31))
{
this.flags &= ~1 & ~flag_overflow;
}
else
{
this.flags |= 1 | flag_overflow;
}
this.flags_changed = 0;
//console.log(target_operand + " * " + source_operand);
//console.log("= " + h(this.reg32[reg_edx]) + " " + h(this.reg32[reg_eax]));
}
/*
* imul with 2 or 3 arguments
* reg = reg * r/m
* reg = imm * r/m
*/
CPU.prototype.imul_reg32 = function(operand1, operand2)
{
dbg_assert(operand1 < 0x80000000 && operand1 >= -0x80000000);
dbg_assert(operand2 < 0x80000000 && operand2 >= -0x80000000);
var is_neg = false; if(operand1 < 0) { is_neg = true; operand1 = -operand1 | 0; } if(operand2 < 0) { is_neg = !is_neg; operand2 = -operand2 | 0; } var a00 = operand1 & 0xFFFF; var a16 = operand1 >>> 16; var b00 = operand2 & 0xFFFF; var b16 = operand2 >>> 16; var low_result = a00 * b00; var mid = (low_result >>> 16) + (a16 * b00 | 0) | 0; var high_result = mid >>> 16; mid = (mid & 0xFFFF) + (a00 * b16 | 0) | 0; low_result = (mid << 16) | low_result & 0xFFFF; high_result = ((mid >>> 16) + (a16 * b16 | 0) | 0) + high_result | 0;; if(is_neg) { low_result = -low_result | 0; high_result = ~high_result + !low_result | 0; };
if(high_result === (low_result >> 31))
{
this.flags &= ~1 & ~flag_overflow;
}
else
{
this.flags |= 1 | flag_overflow;
}
this.flags_changed = 0;
return low_result;
//console.log(operand + " * " + source_operand);
//console.log("= " + this.reg32[reg]);
}
CPU.prototype.div8 = function(source_operand)
{
dbg_assert(source_operand >= 0 && source_operand < 0x100);
var target_operand = this.reg16[reg_ax],
result = target_operand / source_operand | 0;
if(result >= 0x100 || source_operand === 0)
{
this.trigger_de();
}
else
{
this.reg8[reg_al] = result;
this.reg8[reg_ah] = target_operand % source_operand;
}
}
CPU.prototype.idiv8 = function(source_operand)
{
dbg_assert(source_operand >= -0x80 && source_operand < 0x80);
var target_operand = this.reg16s[reg_ax],
result = target_operand / source_operand | 0;
if(result >= 0x80 || result <= -0x81 || source_operand === 0)
{
this.trigger_de();
}
else
{
this.reg8[reg_al] = result;
this.reg8[reg_ah] = target_operand % source_operand;
}
}
CPU.prototype.div16 = function(source_operand)
{
dbg_assert(source_operand >= 0 && source_operand < 0x10000);
var
target_operand = (this.reg16[reg_ax] | this.reg16[reg_dx] << 16) >>> 0,
result = target_operand / source_operand | 0;
if(result >= 0x10000 || result < 0 || source_operand === 0)
{
this.trigger_de();
}
else
{
this.reg16[reg_ax] = result;
this.reg16[reg_dx] = target_operand % source_operand;
}
}
CPU.prototype.idiv16 = function(source_operand)
{
dbg_assert(source_operand >= -0x8000 && source_operand < 0x8000);
var target_operand = this.reg16[reg_ax] | (this.reg16[reg_dx] << 16),
result = target_operand / source_operand | 0;
if(result >= 0x8000 || result <= -0x8001 || source_operand === 0)
{
this.trigger_de();
}
else
{
this.reg16[reg_ax] = result;
this.reg16[reg_dx] = target_operand % source_operand;
}
}
// If the dividend is too large, the division cannot be done precisely using
// JavaScript's double floating point numbers. Run simple long divsion until
// the dividend is small enough
CPU.prototype.div32 = function(source_operand)
{
dbg_assert(source_operand >= 0 && source_operand <= 0xffffffff);
var dest_operand_low = this.reg32[reg_eax],
dest_operand_high = this.reg32[reg_edx];
if(dest_operand_high >= source_operand || !source_operand) this.trigger_de(); var result = 0; if(dest_operand_high > 0x100000) { var m = 0; var i = 32; var q = source_operand; while(q > dest_operand_high) { q >>>= 1; i--; } while(dest_operand_high > 0x100000) { if(dest_operand_high >= q) { dest_operand_high -= q; var sub = source_operand << i >>> 0; if(sub > dest_operand_low) { dest_operand_high--; } dest_operand_low = dest_operand_low - sub >>> 0; result |= 1 << i } i--; q >>= 1; } result >>>= 0; } var div = dest_operand_low + dest_operand_high * 0x100000000; var mod = div % source_operand; result += div / source_operand | 0;;
if(result >= 0x100000000 || source_operand === 0)
{
dbg_log("div32 #DE: " + h(dest_operand_high, 8) + ":" + h(dest_operand_low, 8) + " div " + h(source_operand, 8));
this.trigger_de();
}
else
{
this.reg32s[reg_eax] = result;
this.reg32s[reg_edx] = mod;
}
//console.log(h(dest_operand_high) + ":" + h(dest_operand_low) + " / " + h(source_operand));
//console.log("= " + h(this.reg32[reg_eax]) + " rem " + h(this.reg32[reg_edx]));
}
CPU.prototype.idiv32 = function(source_operand)
{
dbg_assert(source_operand < 0x80000000 && source_operand >= -0x80000000);
var dest_operand_low = this.reg32[reg_eax],
dest_operand_high = this.reg32s[reg_edx],
div_is_neg = false,
is_neg = false;
if(source_operand < 0)
{
is_neg = true;
source_operand = -source_operand;
}
if(dest_operand_high < 0)
{
div_is_neg = true;
is_neg = !is_neg;
dest_operand_low = -dest_operand_low >>> 0;
dest_operand_high = ~dest_operand_high + !dest_operand_low;
}
if(dest_operand_high >= source_operand || !source_operand) this.trigger_de(); var result = 0; if(dest_operand_high > 0x100000) { var m = 0; var i = 32; var q = source_operand; while(q > dest_operand_high) { q >>>= 1; i--; } while(dest_operand_high > 0x100000) { if(dest_operand_high >= q) { dest_operand_high -= q; var sub = source_operand << i >>> 0; if(sub > dest_operand_low) { dest_operand_high--; } dest_operand_low = dest_operand_low - sub >>> 0; result |= 1 << i } i--; q >>= 1; } result >>>= 0; } var div = dest_operand_low + dest_operand_high * 0x100000000; var mod = div % source_operand; result += div / source_operand | 0;;
if(is_neg)
{
result = -result | 0;
}
if(div_is_neg)
{
mod = -mod | 0;
}
if(result >= 0x80000000 || result <= -0x80000001 || source_operand === 0)
{
dbg_log("div32 #DE: " + h(dest_operand_high, 8) + ":" + h(dest_operand_low, 8) + " div " + h(source_operand, 8));
this.trigger_de();
}
else
{
this.reg32s[reg_eax] = result;
this.reg32s[reg_edx] = mod;
}
//console.log(h(dest_operand_high) + ":" + h(dest_operand_low) + " / " + h(source_operand));
//console.log("= " + h(this.reg32[reg_eax]) + " rem " + h(this.reg32[reg_edx]));
}
CPU.prototype.xadd8 = function(source_operand, reg)
{
var tmp = this.reg8[reg];
this.reg8[reg] = source_operand;
return this.add(source_operand, tmp, OPSIZE_8);
}
CPU.prototype.xadd16 = function(source_operand, reg)
{
var tmp = this.reg16[reg];
this.reg16[reg] = source_operand;
return this.add(source_operand, tmp, OPSIZE_16);
}
CPU.prototype.xadd32 = function(source_operand, reg)
{
var tmp = this.reg32s[reg];
this.reg32s[reg] = source_operand;
return this.add(source_operand, tmp, OPSIZE_32);
}
CPU.prototype.bcd_daa = function()
{
//dbg_log("daa");
// decimal adjust after addition
var old_al = this.reg8[reg_al],
old_cf = this.getcf(),
old_af = this.getaf();
this.flags &= ~1 & ~flag_adjust
if((old_al & 0xF) > 9 || old_af)
{
this.reg8[reg_al] += 6;
this.flags |= flag_adjust;
}
if(old_al > 0x99 || old_cf)
{
this.reg8[reg_al] += 0x60;
this.flags |= 1;
}
this.last_result = this.reg8[reg_al];
this.last_op_size = OPSIZE_8;
this.last_op1 = this.last_op2 = 0;
this.flags_changed = flags_all & ~1 & ~flag_adjust & ~flag_overflow;
}
CPU.prototype.bcd_das = function()
{
//dbg_log("das");
// decimal adjust after subtraction
var old_al = this.reg8[reg_al],
old_cf = this.getcf();
this.flags &= ~1;
if((old_al & 0xF) > 9 || this.getaf())
{
this.reg8[reg_al] -= 6;
this.flags |= flag_adjust;
this.flags = this.flags & ~1 | old_cf | this.reg8[reg_al] >> 7;
}
else
{
this.flags &= ~flag_adjust;
}
if(old_al > 0x99 || old_cf)
{
this.reg8[reg_al] -= 0x60;
this.flags |= 1;
}
this.last_result = this.reg8[reg_al];
this.last_op_size = OPSIZE_8;
this.last_op1 = this.last_op2 = 0;
this.flags_changed = flags_all & ~1 & ~flag_adjust & ~flag_overflow;
}
CPU.prototype.bcd_aam = function(imm8)
{
//dbg_log("aam");
// ascii adjust after multiplication
if(imm8 === 0)
{
this.trigger_de();
}
else
{
var temp = this.reg8[reg_al];
this.reg8[reg_ah] = temp / imm8;
this.reg8[reg_al] = temp % imm8;
this.last_result = this.reg8[reg_al];
this.flags_changed = flags_all & ~1 & ~flag_adjust & ~flag_overflow;
this.flags &= ~1 & ~flag_adjust & ~flag_overflow;
}
}
CPU.prototype.bcd_aad = function(imm8)
{
//dbg_log("aad");
// ascii adjust before division
this.last_result = this.reg8[reg_al] + this.reg8[reg_ah] * imm8 & 0xFF;
this.reg16[reg_ax] = this.last_result;
this.last_op_size = OPSIZE_8;
this.flags_changed = flags_all & ~1 & ~flag_adjust & ~flag_overflow;
this.flags &= ~1 & ~flag_adjust & ~flag_overflow;
}
CPU.prototype.bcd_aaa = function()
{
//dbg_log("aaa");
if((this.reg8[reg_al] & 0xF) > 9 || this.getaf())
{
this.reg16[reg_ax] += 6;
this.reg8[reg_ah] += 1;
this.flags |= flag_adjust | 1;
}
else
{
this.flags &= ~flag_adjust & ~1;
}
this.reg8[reg_al] &= 0xF;
this.flags_changed &= ~flag_adjust & ~1;
};
CPU.prototype.bcd_aas = function()
{
//dbg_log("aas");
if((this.reg8[reg_al] & 0xF) > 9 || this.getaf())
{
this.reg16[reg_ax] -= 6;
this.reg8[reg_ah] -= 1;
this.flags |= flag_adjust | 1;
}
else
{
this.flags &= ~flag_adjust & ~1;
}
this.reg8[reg_al] &= 0xF;
this.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
*/
CPU.prototype.and = function(dest_operand, source_operand, op_size)
{
this.last_result = dest_operand & source_operand;
this.last_op_size = op_size;
this.flags &= ~1 & ~flag_overflow & ~flag_adjust;
this.flags_changed = flags_all & ~1 & ~flag_overflow & ~flag_adjust;
return this.last_result;
}
CPU.prototype.or = function(dest_operand, source_operand, op_size)
{
this.last_result = dest_operand | source_operand;
this.last_op_size = op_size;
this.flags &= ~1 & ~flag_overflow & ~flag_adjust;
this.flags_changed = flags_all & ~1 & ~flag_overflow & ~flag_adjust;
return this.last_result;
}
CPU.prototype.xor = function(dest_operand, source_operand, op_size)
{
this.last_result = dest_operand ^ source_operand;
this.last_op_size = op_size;
this.flags &= ~1 & ~flag_overflow & ~flag_adjust;
this.flags_changed = flags_all & ~1 & ~flag_overflow & ~flag_adjust;
return this.last_result;
}
/*
* rotates and shifts
*/
CPU.prototype.rol8 = function(dest_operand, count)
{
if(!count)
{
return dest_operand;
}
count &= 7;
var result = dest_operand << count | dest_operand >> (8 - count);
this.flags_changed &= ~1 & ~flag_overflow;
this.flags = (this.flags & ~1 & ~flag_overflow)
| (result & 1)
| (result << 11 ^ result << 4) & flag_overflow;
return result;
}
CPU.prototype.rol16 = function(dest_operand, count)
{
if(!count)
{
return dest_operand;
}
count &= 15;
var result = dest_operand << count | dest_operand >> (16 - count);
this.flags_changed &= ~1 & ~flag_overflow;
this.flags = (this.flags & ~1 & ~flag_overflow)
| (result & 1)
| (result << 11 ^ result >> 4) & flag_overflow;
return result;
}
CPU.prototype.rol32 = function(dest_operand, count)
{
if(!count)
{
return dest_operand;
}
var result = dest_operand << count | dest_operand >>> (32 - count);
this.flags_changed &= ~1 & ~flag_overflow;
this.flags = (this.flags & ~1 & ~flag_overflow)
| (result & 1)
| (result << 11 ^ result >> 20) & flag_overflow;
return result;
}
CPU.prototype.rcl8 = function(dest_operand, count)
{
count %= 9;
if(!count)
{
return dest_operand;
}
var result = dest_operand << count | this.getcf() << (count - 1) | dest_operand >> (9 - count);
this.flags_changed &= ~1 & ~flag_overflow;
this.flags = (this.flags & ~1 & ~flag_overflow)
| (result >> 8 & 1)
| (result << 3 ^ result << 4) & flag_overflow;
return result;
}
CPU.prototype.rcl16 = function(dest_operand, count)
{
count %= 17;
if(!count)
{
return dest_operand;
}
var result = dest_operand << count | this.getcf() << (count - 1) | dest_operand >> (17 - count);
this.flags_changed &= ~1 & ~flag_overflow;
this.flags = (this.flags & ~1 & ~flag_overflow)
| (result >> 16 & 1)
| (result >> 5 ^ result >> 4) & flag_overflow;
return result;
}
CPU.prototype.rcl32 = function(dest_operand, count)
{
if(!count)
{
return dest_operand;
}
var result = dest_operand << count | this.getcf() << (count - 1);
if(count > 1)
{
result |= dest_operand >>> (33 - count);
}
this.flags_changed &= ~1 & ~flag_overflow;
this.flags = (this.flags & ~1 & ~flag_overflow) | (dest_operand >>> (32 - count) & 1);
this.flags |= (this.flags << 11 ^ result >> 20) & flag_overflow;
return result;
}
CPU.prototype.ror8 = function(dest_operand, count)
{
if(!count)
{
return dest_operand;
}
count &= 7;
var result = dest_operand >> count | dest_operand << (8 - count);
this.flags_changed &= ~1 & ~flag_overflow;
this.flags = (this.flags & ~1 & ~flag_overflow)
| (result >> 7 & 1)
| (result << 4 ^ result << 5) & flag_overflow;
return result;
}
CPU.prototype.ror16 = function(dest_operand, count)
{
if(!count)
{
return dest_operand;
}
count &= 15;
var result = dest_operand >> count | dest_operand << (16 - count);
this.flags_changed &= ~1 & ~flag_overflow;
this.flags = (this.flags & ~1 & ~flag_overflow)
| (result >> 15 & 1)
| (result >> 4 ^ result >> 3) & flag_overflow;
return result;
}
CPU.prototype.ror32 = function(dest_operand, count)
{
if(!count)
{
return dest_operand;
}
var result = dest_operand >>> count | dest_operand << (32 - count);
this.flags_changed &= ~1 & ~flag_overflow;
this.flags = (this.flags & ~1 & ~flag_overflow)
| (result >> 31 & 1)
| (result >> 20 ^ result >> 19) & flag_overflow;
return result;
}
CPU.prototype.rcr8 = function(dest_operand, count)
{
count %= 9;
if(!count)
{
return dest_operand;
}
var result = dest_operand >> count | this.getcf() << (8 - count) | dest_operand << (9 - count);
this.flags_changed &= ~1 & ~flag_overflow;
this.flags = (this.flags & ~1 & ~flag_overflow)
| (result >> 8 & 1)
| (result << 4 ^ result << 5) & flag_overflow;
return result;
}
CPU.prototype.rcr16 = function(dest_operand, count)
{
count %= 17;
if(!count)
{
return dest_operand;
}
var result = dest_operand >> count | this.getcf() << (16 - count) | dest_operand << (17 - count);
this.flags_changed &= ~1 & ~flag_overflow;
this.flags = (this.flags & ~1 & ~flag_overflow)
| (result >> 16 & 1)
| (result >> 4 ^ result >> 3) & flag_overflow;
return result;
}
CPU.prototype.rcr32 = function(dest_operand, count)
{
if(!count)
{
return dest_operand;
}
var result = dest_operand >>> count | this.getcf() << (32 - count);
if(count > 1)
{
result |= dest_operand << (33 - count);
}
this.flags_changed &= ~1 & ~flag_overflow;
this.flags = (this.flags & ~1 & ~flag_overflow)
| (dest_operand >> (count - 1) & 1)
| (result >> 20 ^ result >> 19) & flag_overflow;
return result;
}
CPU.prototype.shl8 = function(dest_operand, count)
{
if(count === 0)
{
return dest_operand;
}
this.last_result = dest_operand << count;
this.last_op_size = OPSIZE_8;
this.flags_changed = flags_all & ~1 & ~flag_overflow;
this.flags = (this.flags & ~1 & ~flag_overflow)
| (this.last_result >> 8 & 1)
| (this.last_result << 3 ^ this.last_result << 4) & flag_overflow;
return this.last_result;
}
CPU.prototype.shl16 = function(dest_operand, count)
{
if(count === 0)
{
return dest_operand;
}
this.last_result = dest_operand << count;
this.last_op_size = OPSIZE_16;
this.flags_changed = flags_all & ~1 & ~flag_overflow;
this.flags = (this.flags & ~1 & ~flag_overflow)
| (this.last_result >> 16 & 1)
| (this.last_result >> 5 ^ this.last_result >> 4) & flag_overflow;
return this.last_result;
}
CPU.prototype.shl32 = function(dest_operand, count)
{
if(count === 0)
{
return dest_operand;
}
this.last_result = dest_operand << count;
this.last_op_size = OPSIZE_32;
this.flags_changed = flags_all & ~1 & ~flag_overflow;
// test this
this.flags = (this.flags & ~1 & ~flag_overflow) | (dest_operand >>> (32 - count) & 1);
this.flags |= ((this.flags & 1) ^ (this.last_result >> 31 & 1)) << 11 & flag_overflow;
return this.last_result;
}
CPU.prototype.shr8 = function(dest_operand, count)
{
if(count === 0)
{
return dest_operand;
}
this.last_result = dest_operand >> count;
this.last_op_size = OPSIZE_8;
this.flags_changed = flags_all & ~1 & ~flag_overflow;
this.flags = (this.flags & ~1 & ~flag_overflow)
| (dest_operand >> (count - 1) & 1)
| (dest_operand >> 7 & 1) << 11 & flag_overflow;
return this.last_result;
}
CPU.prototype.shr16 = function(dest_operand, count)
{
if(count === 0)
{
return dest_operand;
}
this.last_result = dest_operand >> count;
this.last_op_size = OPSIZE_16;
this.flags_changed = flags_all & ~1 & ~flag_overflow;
this.flags = (this.flags & ~1 & ~flag_overflow)
| (dest_operand >> (count - 1) & 1)
| (dest_operand >> 4) & flag_overflow;
return this.last_result;
}
CPU.prototype.shr32 = function(dest_operand, count)
{
if(count === 0)
{
return dest_operand;
}
this.last_result = dest_operand >>> count;
this.last_op_size = OPSIZE_32;
this.flags_changed = flags_all & ~1 & ~flag_overflow;
this.flags = (this.flags & ~1 & ~flag_overflow)
| (dest_operand >>> (count - 1) & 1)
| (dest_operand >> 20) & flag_overflow;
return this.last_result;
}
CPU.prototype.sar8 = function(dest_operand, count)
{
if(count === 0)
{
return dest_operand;
}
if(count < 8)
{
this.last_result = dest_operand << 24 >> count + 24;
// of is zero
this.flags = (this.flags & ~1 & ~flag_overflow) | (dest_operand >> (count - 1) & 1);
}
else
{
this.last_result = dest_operand << 24 >> 31;
this.flags = (this.flags & ~1 & ~flag_overflow) | (this.last_result & 1);
}
this.last_op_size = OPSIZE_8;
this.flags_changed = flags_all & ~1 & ~flag_overflow;
return this.last_result;
}
CPU.prototype.sar16 = function(dest_operand, count)
{
if(count === 0)
{
return dest_operand;
}
if(count < 16)
{
this.last_result = dest_operand << 16 >> count + 16;
this.flags = (this.flags & ~1 & ~flag_overflow) | (dest_operand >> (count - 1) & 1);
}
else
{
this.last_result = dest_operand << 16 >> 31;
this.flags = (this.flags & ~1 & ~flag_overflow) | (this.last_result & 1);
}
this.last_op_size = OPSIZE_16;
this.flags_changed = flags_all & ~1 & ~flag_overflow;
return this.last_result;
}
CPU.prototype.sar32 = function(dest_operand, count)
{
if(count === 0)
{
return dest_operand;
}
this.last_result = dest_operand >> count;
this.last_op_size = OPSIZE_32;
this.flags_changed = flags_all & ~1 & ~flag_overflow;
this.flags = (this.flags & ~1 & ~flag_overflow) | (dest_operand >>> (count - 1) & 1);
return this.last_result;
}
CPU.prototype.shrd16 = function(dest_operand, source_operand, count)
{
if(count === 0)
{
return dest_operand;
}
if(count <= 16)
{
this.last_result = dest_operand >> count | source_operand << (16 - count);
this.flags = (this.flags & ~1) | (dest_operand >> (count - 1) & 1);
}
else
{
this.last_result = dest_operand << (32 - count) | source_operand >> (count - 16);
this.flags = (this.flags & ~1) | (source_operand >> (count - 17) & 1);
}
this.last_op_size = OPSIZE_16;
this.flags_changed = flags_all & ~1 & ~flag_overflow;
this.flags = (this.flags & ~flag_overflow) | ((this.last_result ^ dest_operand) >> 4 & flag_overflow);
return this.last_result;
}
CPU.prototype.shrd32 = function(dest_operand, source_operand, count)
{
if(count === 0)
{
return dest_operand;
}
this.last_result = dest_operand >>> count | source_operand << (32 - count);
this.last_op_size = OPSIZE_32;
this.flags_changed = flags_all & ~1 & ~flag_overflow;
this.flags = (this.flags & ~1) | (dest_operand >>> (count - 1) & 1);
this.flags = (this.flags & ~flag_overflow) | ((this.last_result ^ dest_operand) >> 20 & flag_overflow);
return this.last_result;
}
CPU.prototype.shld16 = function(dest_operand, source_operand, count)
{
if(count === 0)
{
return dest_operand;
}
if(count <= 16)
{
this.last_result = dest_operand << count | source_operand >>> (16 - count);
this.flags = (this.flags & ~1) | (dest_operand >>> (16 - count) & 1);
}
else
{
this.last_result = dest_operand >> (32 - count) | source_operand << (count - 16);
this.flags = (this.flags & ~1) | (source_operand >>> (32 - count) & 1);
}
this.last_op_size = OPSIZE_16;
this.flags_changed = flags_all & ~1 & ~flag_overflow;
this.flags = (this.flags & ~flag_overflow) | ((this.flags & 1) ^ (this.last_result >> 15 & 1)) << 11;
return this.last_result;
}
CPU.prototype.shld32 = function(dest_operand, source_operand, count)
{
if(count === 0)
{
return dest_operand;
}
this.last_result = dest_operand << count | source_operand >>> (32 - count);
this.last_op_size = OPSIZE_32;
this.flags_changed = flags_all & ~1 & ~flag_overflow;
this.flags = (this.flags & ~1) | (dest_operand >>> (32 - count) & 1);
this.flags = (this.flags & ~flag_overflow) | ((this.flags & 1) ^ (this.last_result >> 31 & 1)) << 11;
return this.last_result;
}
CPU.prototype.bt_reg = function(bit_base, bit_offset)
{
this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1);
this.flags_changed &= ~1;
}
CPU.prototype.btc_reg = function(bit_base, bit_offset)
{
this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1);
this.flags_changed &= ~1;
return bit_base ^ 1 << bit_offset;
}
CPU.prototype.bts_reg = function(bit_base, bit_offset)
{
this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1);
this.flags_changed &= ~1;
return bit_base | 1 << bit_offset;
}
CPU.prototype.btr_reg = function(bit_base, bit_offset)
{
this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1);
this.flags_changed &= ~1;
return bit_base & ~(1 << bit_offset);
}
CPU.prototype.bt_mem = function(virt_addr, bit_offset)
{
var bit_base = this.safe_read8(virt_addr + (bit_offset >> 3) | 0);
bit_offset &= 7;
this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1);
this.flags_changed &= ~1;
}
CPU.prototype.btc_mem = function(virt_addr, bit_offset)
{
var phys_addr = this.translate_address_write(virt_addr + (bit_offset >> 3) | 0);
var bit_base = this.memory.read8(phys_addr);
bit_offset &= 7;
this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1);
this.flags_changed &= ~1;
this.memory.write8(phys_addr, bit_base ^ 1 << bit_offset);
}
CPU.prototype.btr_mem = function(virt_addr, bit_offset)
{
var phys_addr = this.translate_address_write(virt_addr + (bit_offset >> 3) | 0);
var bit_base = this.memory.read8(phys_addr);
bit_offset &= 7;
this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1);
this.flags_changed &= ~1;
this.memory.write8(phys_addr, bit_base & ~(1 << bit_offset));
}
CPU.prototype.bts_mem = function(virt_addr, bit_offset)
{
var phys_addr = this.translate_address_write(virt_addr + (bit_offset >> 3) | 0);
var bit_base = this.memory.read8(phys_addr);
bit_offset &= 7;
this.flags = (this.flags & ~1) | (bit_base >> bit_offset & 1);
this.flags_changed &= ~1;
this.memory.write8(phys_addr, bit_base | 1 << bit_offset);
}
CPU.prototype.bsf16 = function(old, bit_base)
{
this.flags_changed = 0;
if(bit_base === 0)
{
this.flags |= flag_zero;
// not defined in the docs, but value doesn't change on my intel this
return old;
}
else
{
this.flags &= ~flag_zero;
// http://jsperf.com/lowest-bit-index
return v86util.int_log2(-bit_base & bit_base);
}
}
CPU.prototype.bsf32 = function(old, bit_base)
{
this.flags_changed = 0;
if(bit_base === 0)
{
this.flags |= flag_zero;
return old;
}
else
{
this.flags &= ~flag_zero;
return v86util.int_log2((-bit_base & bit_base) >>> 0);
}
}
CPU.prototype.bsr16 = function(old, bit_base)
{
this.flags_changed = 0;
if(bit_base === 0)
{
this.flags |= flag_zero;
return old;
}
else
{
this.flags &= ~flag_zero;
return v86util.int_log2(bit_base);
}
}
CPU.prototype.bsr32 = function(old, bit_base)
{
this.flags_changed = 0;
if(bit_base === 0)
{
this.flags |= flag_zero;
return old;
}
else
{
this.flags &= ~flag_zero;
return v86util.int_log2(bit_base >>> 0);
}
}
CPU.prototype.popcnt = function(v)
{
this.flags_changed = 0;
this.flags &= ~flag_overflow & ~flag_sign & ~flag_zero
& ~flag_adjust & ~flag_parity & ~1;
if(v)
{
// http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
v = v - ((v >> 1) & 0x55555555);
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
}
else
{
this.flags |= flag_zero;
return 0;
}
};
"use strict";
/*
* string operations
*
* cmp si di
* movs 0 1 1/w A4
* cmps 1 1 1/r A6
* stos 0 0 1/w AA
* lods 0 1 0 AC
* scas 1 0 1/r AE
* ins 0 0 1/w
* outs 0 1 0
*/
/** @const */
var MAX_COUNT_PER_CYCLE = 0x1000;
function string_get_cycle_count(size, address)
{
dbg_assert(size && size <= 4 && size >= -4);
if(size < 0)
{
return (address & 0xFFF) >> (-size >> 1);
}
else
{
return (~address & 0xFFF) >> size;
}
}
function string_get_cycle_count2(size, addr1, addr2)
{
dbg_assert(arguments.length === 3);
return Math.min(
string_get_cycle_count(size, addr1),
string_get_cycle_count(size, addr2));
}
function movsb(cpu)
{
var src = cpu.get_seg_prefix(reg_ds) + cpu.regv[cpu.reg_vsi] | 0;
var dest = cpu.get_seg(reg_es) + cpu.regv[cpu.reg_vdi] | 0;
var size = cpu.flags & flag_direction ? -1 : 1;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var cycle_counter = MAX_COUNT_PER_CYCLE;
var phys_src = cpu.translate_address_read(src);
var phys_dest = cpu.translate_address_write(dest);
if(cpu.paging)
{
cycle_counter = string_get_cycle_count2(size, src, dest);
}
do
{
cpu.memory.write8(phys_dest, cpu.memory.read8(phys_src));
phys_dest += size;
phys_src += size;
cont = --count !== 0;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vsi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.timestamp_counter += start_count - count;
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
cpu.safe_write8(dest, cpu.safe_read8(src));
cpu.regv[cpu.reg_vdi] += size;
cpu.regv[cpu.reg_vsi] += size;
}
}
function movsw(cpu)
{
var src = cpu.get_seg_prefix(reg_ds) + cpu.regv[cpu.reg_vsi] | 0;
var dest = cpu.get_seg(reg_es) + cpu.regv[cpu.reg_vdi] | 0;
var size = cpu.flags & flag_direction ? -2 : 2;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var cycle_counter = MAX_COUNT_PER_CYCLE;
if(!(dest & 1) && !(src & 1))
{
var single_size = size < 0 ? -1 : 1;
var phys_src = cpu.translate_address_read(src) >> 1;
var phys_dest = cpu.translate_address_write(dest) >> 1;
if(cpu.paging)
{
cycle_counter = string_get_cycle_count2(size, src, dest);
}
do
{
cpu.memory.write_aligned16(phys_dest, cpu.memory.read_aligned16(phys_src));
phys_dest += single_size;
phys_src += single_size;
cont = --count !== 0;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vsi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.timestamp_counter += start_count - count;
}
else
{
do
{
cpu.safe_write16(dest, cpu.safe_read16(src));
dest += size;
cpu.regv[cpu.reg_vdi] += size;
src += size;
cpu.regv[cpu.reg_vsi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0;
}
while(cont && cycle_counter--);
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
cpu.safe_write16(dest, cpu.safe_read16(src));
cpu.regv[cpu.reg_vdi] += size;
cpu.regv[cpu.reg_vsi] += size;
}
}
function movsd(cpu)
{
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
{
// often used by memcpy, well worth optimizing
// using cpu.memory.mem32s.set
var ds = cpu.get_seg_prefix(reg_ds),
src = ds + cpu.regv[cpu.reg_vsi] | 0,
es = cpu.get_seg(reg_es),
dest = es + cpu.regv[cpu.reg_vdi] | 0,
count = cpu.regv[cpu.reg_vcx] >>> 0;
if(!count)
{
return;
}
// must be page-aligned if cpu.paging is enabled
// and dword-aligned in general
var align_mask = cpu.paging ? 0xFFF : 3;
if((dest & align_mask) === 0 &&
(src & align_mask) === 0 &&
// If df is set, alignment works a different
// This should be unlikely
(cpu.flags & flag_direction) === 0)
{
var cont = false;
if(cpu.paging)
{
src = cpu.translate_address_read(src);
dest = cpu.translate_address_write(dest);
if(count > 0x400)
{
count = 0x400;
cont = true;
}
}
if(!cpu.io.in_mmap_range(src, count) &&
!cpu.io.in_mmap_range(dest, count))
{
var diff = count << 2;
cpu.regv[cpu.reg_vcx] -= count;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vsi] += diff;
dest >>= 2;
src >>= 2;
cpu.memory.mem32s.set(cpu.memory.mem32s.subarray(src, src + count), dest);
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
return;
}
}
}
var src = cpu.get_seg_prefix(reg_ds) + cpu.regv[cpu.reg_vsi] | 0;
var dest = cpu.get_seg(reg_es) + cpu.regv[cpu.reg_vdi] | 0;
var size = cpu.flags & flag_direction ? -4 : 4;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var cycle_counter = MAX_COUNT_PER_CYCLE;
if(!(dest & 3) && !(src & 3))
{
var single_size = size < 0 ? -1 : 1;
var phys_src = cpu.translate_address_read(src) >>> 2;
var phys_dest = cpu.translate_address_write(dest) >>> 2;
if(cpu.paging)
{
cycle_counter = string_get_cycle_count2(size, src, dest);
}
do
{
cpu.memory.write_aligned32(phys_dest, cpu.memory.read_aligned32(phys_src));
phys_dest += single_size;
phys_src += single_size;
cont = --count !== 0;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vsi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.timestamp_counter += start_count - count;
}
else
{
do
{
cpu.safe_write32(dest, cpu.safe_read32s(src));
dest += size;
cpu.regv[cpu.reg_vdi] += size;
src += size;
cpu.regv[cpu.reg_vsi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0;
}
while(cont && cycle_counter--);
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
cpu.safe_write32(dest, cpu.safe_read32s(src));
cpu.regv[cpu.reg_vdi] += size;
cpu.regv[cpu.reg_vsi] += size;
}
}
function cmpsb(cpu)
{
var src = cpu.get_seg_prefix(reg_ds) + cpu.regv[cpu.reg_vsi] | 0;
var dest = cpu.get_seg(reg_es) + cpu.regv[cpu.reg_vdi] | 0;
var data_src, data_dest;
var size = cpu.flags & flag_direction ? -1 : 1;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = cpu.repeat_string_prefix === REPEAT_STRING_PREFIX_Z;
var cycle_counter = MAX_COUNT_PER_CYCLE;
var phys_src = cpu.translate_address_read(src);
var phys_dest = cpu.translate_address_read(dest);
if(cpu.paging)
{
cycle_counter = string_get_cycle_count2(size, src, dest);
}
do
{
data_dest = cpu.memory.read8(phys_dest);
data_src = cpu.memory.read8(phys_src);
phys_dest += size;
phys_src += size;
cont = --count !== 0 && (data_src === data_dest) === is_repz;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vsi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.timestamp_counter += start_count - count;
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
data_src = cpu.safe_read8(src);
data_dest = cpu.safe_read8(dest);
cpu.regv[cpu.reg_vdi] += size;
cpu.regv[cpu.reg_vsi] += size;
}
cpu.sub(data_src, data_dest, OPSIZE_8);
}
function cmpsw(cpu)
{
var src = cpu.get_seg_prefix(reg_ds) + cpu.regv[cpu.reg_vsi] | 0;
var dest = cpu.get_seg(reg_es) + cpu.regv[cpu.reg_vdi] | 0;
var data_src, data_dest;
var size = cpu.flags & flag_direction ? -2 : 2;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = cpu.repeat_string_prefix === REPEAT_STRING_PREFIX_Z;
var cycle_counter = MAX_COUNT_PER_CYCLE;
if(!(dest & 1) && !(src & 1))
{
var single_size = size < 0 ? -1 : 1;
var phys_src = cpu.translate_address_read(src) >> 1;
var phys_dest = cpu.translate_address_read(dest) >> 1;
if(cpu.paging)
{
cycle_counter = string_get_cycle_count2(size, src, dest);
}
do
{
data_dest = cpu.memory.read_aligned16(phys_dest);
data_src = cpu.memory.read_aligned16(phys_src);
phys_dest += single_size;
phys_src += single_size;
cont = --count !== 0 && (data_src === data_dest) === is_repz;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vsi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.timestamp_counter += start_count - count;
}
else
{
do
{
data_dest = cpu.safe_read16(dest);
data_src = cpu.safe_read16(src);
dest += size;
cpu.regv[cpu.reg_vdi] += size;
src += size;
cpu.regv[cpu.reg_vsi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0 && (data_src === data_dest) === is_repz;
}
while(cont && cycle_counter--);
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
data_dest = cpu.safe_read16(dest);
data_src = cpu.safe_read16(src);
cpu.regv[cpu.reg_vdi] += size;
cpu.regv[cpu.reg_vsi] += size;
}
cpu.sub(data_src, data_dest, OPSIZE_16);
}
function cmpsd(cpu)
{
var src = cpu.get_seg_prefix(reg_ds) + cpu.regv[cpu.reg_vsi] | 0;
var dest = cpu.get_seg(reg_es) + cpu.regv[cpu.reg_vdi] | 0;
var data_src, data_dest;
var size = cpu.flags & flag_direction ? -4 : 4;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = cpu.repeat_string_prefix === REPEAT_STRING_PREFIX_Z;
var cycle_counter = MAX_COUNT_PER_CYCLE;
if(!(dest & 3) && !(src & 3))
{
var single_size = size < 0 ? -1 : 1;
var phys_src = cpu.translate_address_read(src) >>> 2;
var phys_dest = cpu.translate_address_read(dest) >>> 2;
if(cpu.paging)
{
cycle_counter = string_get_cycle_count2(size, src, dest);
}
do
{
data_dest = cpu.memory.read_aligned32(phys_dest);
data_src = cpu.memory.read_aligned32(phys_src);
phys_dest += single_size;
phys_src += single_size;
cont = --count !== 0 && (data_src === data_dest) === is_repz;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vsi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.timestamp_counter += start_count - count;
}
else
{
do
{
data_dest = cpu.safe_read32s(dest);
data_src = cpu.safe_read32s(src);
dest += size;
cpu.regv[cpu.reg_vdi] += size;
src += size;
cpu.regv[cpu.reg_vsi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0 && (data_src === data_dest) === is_repz;
}
while(cont && cycle_counter--);
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
data_dest = cpu.safe_read32s(dest);
data_src = cpu.safe_read32s(src);
cpu.regv[cpu.reg_vdi] += size;
cpu.regv[cpu.reg_vsi] += size;
}
cpu.sub(data_src, data_dest, OPSIZE_32);
}
function stosb(cpu)
{
var data = cpu.reg8[reg_al];
var dest = cpu.get_seg(reg_es) + cpu.regv[cpu.reg_vdi] | 0;
var size = cpu.flags & flag_direction ? -1 : 1;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var cycle_counter = MAX_COUNT_PER_CYCLE;
var phys_dest = cpu.translate_address_write(dest);
if(cpu.paging)
{
cycle_counter = string_get_cycle_count(size, dest);
}
do
{
cpu.memory.write8(phys_dest, data);
phys_dest += size;
cont = --count !== 0;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.timestamp_counter += start_count - count;
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
cpu.safe_write8(dest, data);
cpu.regv[cpu.reg_vdi] += size;
}
}
function stosw(cpu)
{
var data = cpu.reg16[reg_ax];
var dest = cpu.get_seg(reg_es) + cpu.regv[cpu.reg_vdi] | 0;
var size = cpu.flags & flag_direction ? -2 : 2;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var cycle_counter = MAX_COUNT_PER_CYCLE;
if(!(dest & 1))
{
var single_size = size < 0 ? -1 : 1;
var phys_dest = cpu.translate_address_write(dest) >> 1;
if(cpu.paging)
{
cycle_counter = string_get_cycle_count(size, dest);
}
do
{
cpu.memory.write_aligned16(phys_dest, data);
phys_dest += single_size;
cont = --count !== 0;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.timestamp_counter += start_count - count;
}
else
{
do
{
cpu.safe_write16(dest, data);
dest += size;
cpu.regv[cpu.reg_vdi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0;
}
while(cont && cycle_counter--);
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
cpu.safe_write16(dest, data);
cpu.regv[cpu.reg_vdi] += size;
}
}
function stosd(cpu)
{
var data = cpu.reg32s[reg_eax];
var dest = cpu.get_seg(reg_es) + cpu.regv[cpu.reg_vdi] | 0;
var size = cpu.flags & flag_direction ? -4 : 4;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var cycle_counter = MAX_COUNT_PER_CYCLE;
if(!(dest & 3))
{
var single_size = size < 0 ? -1 : 1;
var phys_dest = cpu.translate_address_write(dest) >>> 2;
if(cpu.paging)
{
cycle_counter = string_get_cycle_count(size, dest);
}
do
{
cpu.memory.write_aligned32(phys_dest, data);
phys_dest += single_size;
cont = --count !== 0;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.timestamp_counter += start_count - count;
}
else
{
do
{
cpu.safe_write32(dest, data);
dest += size;
cpu.regv[cpu.reg_vdi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0;
}
while(cont && cycle_counter--);
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
cpu.safe_write32(dest, data);
cpu.regv[cpu.reg_vdi] += size;
}
}
function lodsb(cpu)
{
var src = cpu.get_seg_prefix(reg_ds) + cpu.regv[cpu.reg_vsi] | 0;
var size = cpu.flags & flag_direction ? -1 : 1;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var cycle_counter = MAX_COUNT_PER_CYCLE;
var phys_src = cpu.translate_address_read(src);
if(cpu.paging)
{
cycle_counter = string_get_cycle_count(size, src);
}
do
{
cpu.reg8[reg_al] = cpu.memory.read8(phys_src);
phys_src += size;
cont = --count !== 0;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vsi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.timestamp_counter += start_count - count;
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
cpu.reg8[reg_al] = cpu.safe_read8(src);
cpu.regv[cpu.reg_vsi] += size;
}
}
function lodsw(cpu)
{
var src = cpu.get_seg_prefix(reg_ds) + cpu.regv[cpu.reg_vsi] | 0;
var size = cpu.flags & flag_direction ? -2 : 2;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
if(count === 0) return;
var cont = false;
var cycle_counter = MAX_COUNT_PER_CYCLE;
do
{
cpu.reg16[reg_ax] = cpu.safe_read16(src);
src += size;
cpu.regv[cpu.reg_vsi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0;
}
while(cont && cycle_counter--);
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
cpu.reg16[reg_ax] = cpu.safe_read16(src);
cpu.regv[cpu.reg_vsi] += size;
}
}
function lodsd(cpu)
{
var src = cpu.get_seg_prefix(reg_ds) + cpu.regv[cpu.reg_vsi] | 0;
var size = cpu.flags & flag_direction ? -4 : 4;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
if(count === 0) return;
var cont = false;
var cycle_counter = MAX_COUNT_PER_CYCLE;
do
{
cpu.reg32s[reg_eax] = cpu.safe_read32s(src);
src += size;
cpu.regv[cpu.reg_vsi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0;
}
while(cont && cycle_counter--);
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
cpu.reg32s[reg_eax] = cpu.safe_read32s(src);
cpu.regv[cpu.reg_vsi] += size;
}
}
function scasb(cpu)
{
var dest = cpu.get_seg(reg_es) + cpu.regv[cpu.reg_vdi] | 0;
var size = cpu.flags & flag_direction ? -1 : 1;
var data_dest;
var data_src = cpu.reg8[reg_al];
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = cpu.repeat_string_prefix === REPEAT_STRING_PREFIX_Z;
var cycle_counter = MAX_COUNT_PER_CYCLE;
var phys_dest = cpu.translate_address_read(dest);
if(cpu.paging)
{
cycle_counter = string_get_cycle_count(size, dest);
}
do
{
data_dest = cpu.memory.read8(phys_dest);
phys_dest += size;
cont = --count !== 0 && (data_src === data_dest) === is_repz;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.timestamp_counter += start_count - count;
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
data_dest = cpu.safe_read8(dest);
cpu.regv[cpu.reg_vdi] += size;
}
cpu.sub(data_src, data_dest, OPSIZE_8);
}
function scasw(cpu)
{
var dest = cpu.get_seg(reg_es) + cpu.regv[cpu.reg_vdi] | 0;
var size = cpu.flags & flag_direction ? -2 : 2;
var data_dest;
var data_src = cpu.reg16[reg_al];
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = cpu.repeat_string_prefix === REPEAT_STRING_PREFIX_Z;
var cycle_counter = MAX_COUNT_PER_CYCLE;
if(!(dest & 1))
{
var single_size = size < 0 ? -1 : 1;
var phys_dest = cpu.translate_address_read(dest) >> 1;
if(cpu.paging)
{
cycle_counter = string_get_cycle_count(size, dest);
}
do
{
data_dest = cpu.memory.read_aligned16(phys_dest);
phys_dest += single_size;
cont = --count !== 0 && (data_src === data_dest) === is_repz;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.timestamp_counter += start_count - count;
}
else
{
do
{
data_dest = cpu.safe_read16(dest);
dest += size;
cpu.regv[cpu.reg_vdi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0 && (data_src === data_dest) === is_repz;
}
while(cont && cycle_counter--);
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
data_dest = cpu.safe_read16(dest);
cpu.regv[cpu.reg_vdi] += size;
}
cpu.sub(data_src, data_dest, OPSIZE_16);
}
function scasd(cpu)
{
var dest = cpu.get_seg(reg_es) + cpu.regv[cpu.reg_vdi] | 0;
var size = cpu.flags & flag_direction ? -4 : 4;
var data_dest;
var data_src = cpu.reg32s[reg_eax];
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = cpu.repeat_string_prefix === REPEAT_STRING_PREFIX_Z;
var cycle_counter = MAX_COUNT_PER_CYCLE;
if(!(dest & 3))
{
var single_size = size < 0 ? -1 : 1;
var phys_dest = cpu.translate_address_read(dest) >>> 2;
if(cpu.paging)
{
cycle_counter = string_get_cycle_count(size, dest);
}
do
{
data_dest = cpu.memory.read_aligned32(phys_dest);
phys_dest += single_size;
cont = --count !== 0 && (data_src === data_dest) === is_repz;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.timestamp_counter += start_count - count;
}
else
{
do
{
data_dest = cpu.safe_read32s(dest);
dest += size;
cpu.regv[cpu.reg_vdi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0 && (data_src === data_dest) === is_repz;
}
while(cont && cycle_counter--);
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
data_dest = cpu.safe_read32s(dest);
cpu.regv[cpu.reg_vdi] += size;
}
cpu.sub(data_src, data_dest, OPSIZE_32);
}
function insb(cpu)
{
var port = cpu.reg16[reg_dx];
cpu.test_privileges_for_io(port, 1);
var dest = cpu.get_seg(reg_es) + cpu.regv[cpu.reg_vdi] | 0;
var size = cpu.flags & flag_direction ? -1 : 1;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var cycle_counter = MAX_COUNT_PER_CYCLE;
var phys_dest = cpu.translate_address_write(dest);
if(cpu.paging)
{
cycle_counter = string_get_cycle_count(size, dest);
}
do
{
cpu.memory.write8(phys_dest, cpu.io.port_read8(port));
phys_dest += size;
cont = --count !== 0;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.timestamp_counter += start_count - count;
if(cont)
{
//cpu.instruction_pointer = cpu.previous_ip;
insb(cpu);
}
}
else
{
cpu.safe_write8(dest, cpu.io.port_read8(port));
cpu.regv[cpu.reg_vdi] += size;
}
}
function insw(cpu)
{
var port = cpu.reg16[reg_dx];
cpu.test_privileges_for_io(port, 2);
var dest = cpu.get_seg(reg_es) + cpu.regv[cpu.reg_vdi] | 0;
var size = cpu.flags & flag_direction ? -2 : 2;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var cycle_counter = MAX_COUNT_PER_CYCLE;
if(!(dest & 1))
{
var single_size = size < 0 ? -1 : 1;
var phys_dest = cpu.translate_address_write(dest) >> 1;
if(cpu.paging)
{
cycle_counter = string_get_cycle_count(size, dest);
}
do
{
cpu.memory.write_aligned16(phys_dest, cpu.io.port_read16(port));
phys_dest += single_size;
cont = --count !== 0;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.timestamp_counter += start_count - count;
}
else
{
do
{
cpu.safe_write16(dest, cpu.io.port_read16(port));
dest += size;
cpu.regv[cpu.reg_vdi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0;
}
while(cont && cycle_counter--);
}
if(cont)
{
//cpu.instruction_pointer = cpu.previous_ip;
insw(cpu);
}
}
else
{
cpu.safe_write16(dest, cpu.io.port_read16(port));
cpu.regv[cpu.reg_vdi] += size;
}
}
function insd(cpu)
{
var port = cpu.reg16[reg_dx];
cpu.test_privileges_for_io(port, 4);
var dest = cpu.get_seg(reg_es) + cpu.regv[cpu.reg_vdi] | 0;
var size = cpu.flags & flag_direction ? -4 : 4;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var cycle_counter = MAX_COUNT_PER_CYCLE;
if(!(dest & 3))
{
var single_size = size < 0 ? -1 : 1;
var phys_dest = cpu.translate_address_write(dest) >>> 2;
if(cpu.paging)
{
cycle_counter = string_get_cycle_count(size, dest);
}
do
{
cpu.memory.write_aligned32(phys_dest, cpu.io.port_read32(port));
phys_dest += single_size;
cont = --count !== 0;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.timestamp_counter += start_count - count;
}
else
{
do
{
cpu.safe_write32(dest, cpu.io.port_read32(port));
dest += size;
cpu.regv[cpu.reg_vdi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0;
}
while(cont && cycle_counter--);
}
if(cont)
{
//cpu.instruction_pointer = cpu.previous_ip;
insd(cpu);
}
}
else
{
cpu.safe_write32(dest, cpu.io.port_read32(port));
cpu.regv[cpu.reg_vdi] += size;
}
}
function outsb(cpu)
{
var port = cpu.reg16[reg_dx];
cpu.test_privileges_for_io(port, 1);
var src = cpu.get_seg_prefix(reg_ds) + cpu.regv[cpu.reg_vsi] | 0;
var size = cpu.flags & flag_direction ? -1 : 1;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var cycle_counter = MAX_COUNT_PER_CYCLE;
var phys_src = cpu.translate_address_read(src);
if(cpu.paging)
{
cycle_counter = string_get_cycle_count(size, src);
}
do
{
cpu.io.port_write8(port, cpu.memory.read8(phys_src));
phys_src += size;
cont = --count !== 0;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vsi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.timestamp_counter += start_count - count;
if(cont)
{
//cpu.instruction_pointer = cpu.previous_ip;
outsb(cpu);
}
}
else
{
cpu.io.port_write8(port, cpu.safe_read8(src));
cpu.regv[cpu.reg_vsi] += size;
}
}
function outsw(cpu)
{
var port = cpu.reg16[reg_dx];
cpu.test_privileges_for_io(port, 2);
var src = cpu.get_seg_prefix(reg_ds) + cpu.regv[cpu.reg_vsi] | 0;
var size = cpu.flags & flag_direction ? -2 : 2;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var cycle_counter = MAX_COUNT_PER_CYCLE;
if(!(src & 1))
{
var single_size = size < 0 ? -1 : 1;
var phys_src = cpu.translate_address_read(src) >> 1;
if(cpu.paging)
{
cycle_counter = string_get_cycle_count(size, src);
}
do
{
cpu.io.port_write16(port, cpu.memory.read_aligned16(phys_src));
phys_src += single_size;
cont = --count !== 0;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vsi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.timestamp_counter += start_count - count;
}
else
{
do
{
cpu.io.port_write16(port, cpu.safe_read16(src));
src += size;
cpu.regv[cpu.reg_vsi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0;
}
while(cont && cycle_counter--);
}
if(cont)
{
//cpu.instruction_pointer = cpu.previous_ip;
outsw(cpu);
}
}
else
{
cpu.io.port_write16(port, cpu.safe_read16(src));
cpu.regv[cpu.reg_vsi] += size;
}
}
function outsd(cpu)
{
var port = cpu.reg16[reg_dx];
cpu.test_privileges_for_io(port, 4);
var src = cpu.get_seg_prefix(reg_ds) + cpu.regv[cpu.reg_vsi] | 0;
var size = cpu.flags & flag_direction ? -4 : 4;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var cycle_counter = MAX_COUNT_PER_CYCLE;
if(!(src & 3))
{
var single_size = size < 0 ? -1 : 1;
var phys_src = cpu.translate_address_read(src) >>> 2;
if(cpu.paging)
{
cycle_counter = string_get_cycle_count(size, src);
}
do
{
cpu.io.port_write32(port, cpu.memory.read_aligned32(phys_src));
phys_src += single_size;
cont = --count !== 0;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vsi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.timestamp_counter += start_count - count;
}
else
{
do
{
cpu.io.port_write32(port, cpu.safe_read32s(src));
src += size;
cpu.regv[cpu.reg_vsi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0;
}
while(cont && cycle_counter--);
}
if(cont)
{
//cpu.instruction_pointer = cpu.previous_ip;
outsd(cpu);
}
}
else
{
cpu.io.port_write32(port, cpu.safe_read32s(src));
cpu.regv[cpu.reg_vsi] += size;
}
}
"use strict";
var
table16 = [],
table32 = [],
table0F_16 = [],
table0F_32 = [];
CPU.prototype.table16 = table16;
CPU.prototype.table32 = table32;
CPU.prototype.table0F_16 = table0F_16;
CPU.prototype.table0F_32 = table0F_32;
// opcode with modm byte
// opcode that has a 16 and a 32 bit version
// very special, should be somewhere else?
// equivalent to switch(cpu.modrm_byte >> 3 & 7)
//#define sub_op(i0, i1, i2, i3, i4, i5, i6, i7) // if(cpu.modrm_byte & 0x20) { sub_op1(i4, i5, i6, i7) }// else { sub_op1(i0, i1, i2, i3) }
//
//#define sub_op1(i0, i1, i2, i3)// if(cpu.modrm_byte & 0x10) { sub_op2(i2, i3) }// else { sub_op2(i0, i1) }
//
//#define sub_op2(i0, i1)// if(cpu.modrm_byte & 0x08) { i1 }// else { i0 }
// Evaluate the modrm byte of the instruction and run one
// of the 8 instructions depending on the middle 3 bits.
// Used by 0x80-0x83, 0xd0-0xd3, 0xc0-0xc1, 0xf6-0xf7 and 0xff
// equivalent to switch(modrm_byte >> 3 & 7)
//#define reg_g32 cpu.reg32[cpu.modrm_byte >> 3 & 7]
// use cpu.modrm_byte to write a value to cpu.memory or register
// (without reading it beforehand)
// use cpu.modrm_byte to write a value to cpu.memory or register,
// using the previous data from cpu.memory or register.
// op is a function call that needs to return the result
// instructions start here
table16[0x00] = table32[0x00] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var addr; var result; if(cpu.modrm_byte < 0xC0) { addr = cpu.translate_address_write(cpu.modrm_resolve(cpu.modrm_byte)); data = cpu.memory.read8(addr); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; } result = cpu.add(data, cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1], OPSIZE_8); if(cpu.modrm_byte < 0xC0) { cpu.memory.write8(addr, result); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = result; } } }; table16[0x00 | 1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = cpu.translate_address_write(virt_addr + 1); data = cpu.virt_boundary_read16(phys_addr, phys_addr_high); } else { data = cpu.memory.read16(phys_addr); } } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; } result = cpu.add(data, cpu.reg16[cpu.modrm_byte >> 2 & 14], OPSIZE_16); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write16(phys_addr, phys_addr_high, result); } else { cpu.memory.write16(phys_addr, result); } } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = result; } } }; table32[0x00 | 1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = cpu.translate_address_write(virt_addr + 3); data = cpu.virt_boundary_read32s(phys_addr, phys_addr_high); } else { data = cpu.memory.read32s(phys_addr); } } else { data = cpu.reg32s[cpu.modrm_byte & 7]; } result = cpu.add(data, cpu.reg32s[cpu.modrm_byte >> 3 & 7], OPSIZE_32); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write32(phys_addr, phys_addr_high, result); } else { cpu.memory.write32(phys_addr, result); } } else { cpu.reg32s[cpu.modrm_byte & 7] = result; } } }; table16[0x00 | 2] = table32[0x00 | 2] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read8(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; }; cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1] = cpu.add(cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1], data, OPSIZE_8); } }; table16[0x00 | 3] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.reg16[cpu.modrm_byte >> 2 & 14] = cpu.add(cpu.reg16[cpu.modrm_byte >> 2 & 14], data, OPSIZE_16); } }; table32[0x00 | 3] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.reg32s[cpu.modrm_byte >> 3 & 7] = cpu.add(cpu.reg32s[cpu.modrm_byte >> 3 & 7], data, OPSIZE_32); } }; table16[0x00 | 4] = table32[0x00 | 4] = function(cpu) { { cpu.reg8[reg_al] = cpu.add(cpu.reg8[reg_al], cpu.read_imm8(), OPSIZE_8); } }; table16[0x00 | 5] = function(cpu) { { cpu.reg16[reg_ax] = cpu.add(cpu.reg16[reg_ax], cpu.read_imm16(), OPSIZE_16); } }; table32[0x00 | 5] = function(cpu) { { cpu.reg32s[reg_eax] = cpu.add(cpu.reg32s[reg_eax], cpu.read_imm32s(), OPSIZE_32); } };;
table16[0x06] = function(cpu) { { cpu.push16(cpu.sreg[reg_es]); } }; table32[0x06] = function(cpu) { { cpu.push32(cpu.sreg[reg_es]); } };;
table16[0x07] = function(cpu) { { cpu.switch_seg(reg_es, cpu.safe_read16(cpu.get_stack_pointer(0))); cpu.stack_reg[cpu.reg_vsp] += 2; if(reg_es === reg_ss) { cpu.clear_prefixes(); cpu.cycle(); } } }; table32[0x07] = function(cpu) { { cpu.switch_seg(reg_es, cpu.safe_read16(cpu.get_stack_pointer(0))); cpu.stack_reg[cpu.reg_vsp] += 4; if(reg_es === reg_ss) { cpu.clear_prefixes(); cpu.cycle(); } } };;;
table16[0x08] = table32[0x08] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var addr; var result; if(cpu.modrm_byte < 0xC0) { addr = cpu.translate_address_write(cpu.modrm_resolve(cpu.modrm_byte)); data = cpu.memory.read8(addr); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; } result = cpu.or(data, cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1], OPSIZE_8); if(cpu.modrm_byte < 0xC0) { cpu.memory.write8(addr, result); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = result; } } }; table16[0x08 | 1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = cpu.translate_address_write(virt_addr + 1); data = cpu.virt_boundary_read16(phys_addr, phys_addr_high); } else { data = cpu.memory.read16(phys_addr); } } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; } result = cpu.or(data, cpu.reg16[cpu.modrm_byte >> 2 & 14], OPSIZE_16); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write16(phys_addr, phys_addr_high, result); } else { cpu.memory.write16(phys_addr, result); } } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = result; } } }; table32[0x08 | 1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = cpu.translate_address_write(virt_addr + 3); data = cpu.virt_boundary_read32s(phys_addr, phys_addr_high); } else { data = cpu.memory.read32s(phys_addr); } } else { data = cpu.reg32s[cpu.modrm_byte & 7]; } result = cpu.or(data, cpu.reg32s[cpu.modrm_byte >> 3 & 7], OPSIZE_32); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write32(phys_addr, phys_addr_high, result); } else { cpu.memory.write32(phys_addr, result); } } else { cpu.reg32s[cpu.modrm_byte & 7] = result; } } }; table16[0x08 | 2] = table32[0x08 | 2] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read8(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; }; cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1] = cpu.or(cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1], data, OPSIZE_8); } }; table16[0x08 | 3] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.reg16[cpu.modrm_byte >> 2 & 14] = cpu.or(cpu.reg16[cpu.modrm_byte >> 2 & 14], data, OPSIZE_16); } }; table32[0x08 | 3] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.reg32s[cpu.modrm_byte >> 3 & 7] = cpu.or(cpu.reg32s[cpu.modrm_byte >> 3 & 7], data, OPSIZE_32); } }; table16[0x08 | 4] = table32[0x08 | 4] = function(cpu) { { cpu.reg8[reg_al] = cpu.or(cpu.reg8[reg_al], cpu.read_imm8(), OPSIZE_8); } }; table16[0x08 | 5] = function(cpu) { { cpu.reg16[reg_ax] = cpu.or(cpu.reg16[reg_ax], cpu.read_imm16(), OPSIZE_16); } }; table32[0x08 | 5] = function(cpu) { { cpu.reg32s[reg_eax] = cpu.or(cpu.reg32s[reg_eax], cpu.read_imm32s(), OPSIZE_32); } };;
table16[0x0E] = function(cpu) { { cpu.push16(cpu.sreg[reg_cs]); } }; table32[0x0E] = function(cpu) { { cpu.push32(cpu.sreg[reg_cs]); } };;
table16[0x0F] = function(cpu) { { cpu.table0F_16[cpu.read_imm8()](cpu); } }; table32[0x0F] = function(cpu) { { cpu.table0F_32[cpu.read_imm8()](cpu); } };;
table16[0x10] = table32[0x10] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var addr; var result; if(cpu.modrm_byte < 0xC0) { addr = cpu.translate_address_write(cpu.modrm_resolve(cpu.modrm_byte)); data = cpu.memory.read8(addr); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; } result = cpu.adc(data, cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1], OPSIZE_8); if(cpu.modrm_byte < 0xC0) { cpu.memory.write8(addr, result); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = result; } } }; table16[0x10 | 1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = cpu.translate_address_write(virt_addr + 1); data = cpu.virt_boundary_read16(phys_addr, phys_addr_high); } else { data = cpu.memory.read16(phys_addr); } } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; } result = cpu.adc(data, cpu.reg16[cpu.modrm_byte >> 2 & 14], OPSIZE_16); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write16(phys_addr, phys_addr_high, result); } else { cpu.memory.write16(phys_addr, result); } } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = result; } } }; table32[0x10 | 1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = cpu.translate_address_write(virt_addr + 3); data = cpu.virt_boundary_read32s(phys_addr, phys_addr_high); } else { data = cpu.memory.read32s(phys_addr); } } else { data = cpu.reg32s[cpu.modrm_byte & 7]; } result = cpu.adc(data, cpu.reg32s[cpu.modrm_byte >> 3 & 7], OPSIZE_32); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write32(phys_addr, phys_addr_high, result); } else { cpu.memory.write32(phys_addr, result); } } else { cpu.reg32s[cpu.modrm_byte & 7] = result; } } }; table16[0x10 | 2] = table32[0x10 | 2] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read8(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; }; cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1] = cpu.adc(cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1], data, OPSIZE_8); } }; table16[0x10 | 3] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.reg16[cpu.modrm_byte >> 2 & 14] = cpu.adc(cpu.reg16[cpu.modrm_byte >> 2 & 14], data, OPSIZE_16); } }; table32[0x10 | 3] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.reg32s[cpu.modrm_byte >> 3 & 7] = cpu.adc(cpu.reg32s[cpu.modrm_byte >> 3 & 7], data, OPSIZE_32); } }; table16[0x10 | 4] = table32[0x10 | 4] = function(cpu) { { cpu.reg8[reg_al] = cpu.adc(cpu.reg8[reg_al], cpu.read_imm8(), OPSIZE_8); } }; table16[0x10 | 5] = function(cpu) { { cpu.reg16[reg_ax] = cpu.adc(cpu.reg16[reg_ax], cpu.read_imm16(), OPSIZE_16); } }; table32[0x10 | 5] = function(cpu) { { cpu.reg32s[reg_eax] = cpu.adc(cpu.reg32s[reg_eax], cpu.read_imm32s(), OPSIZE_32); } };;
table16[0x16] = function(cpu) { { cpu.push16(cpu.sreg[reg_ss]); } }; table32[0x16] = function(cpu) { { cpu.push32(cpu.sreg[reg_ss]); } };;
table16[0x17] = function(cpu) { { cpu.switch_seg(reg_ss, cpu.safe_read16(cpu.get_stack_pointer(0))); cpu.stack_reg[cpu.reg_vsp] += 2; if(reg_ss === reg_ss) { cpu.clear_prefixes(); cpu.cycle(); } } }; table32[0x17] = function(cpu) { { cpu.switch_seg(reg_ss, cpu.safe_read16(cpu.get_stack_pointer(0))); cpu.stack_reg[cpu.reg_vsp] += 4; if(reg_ss === reg_ss) { cpu.clear_prefixes(); cpu.cycle(); } } };;;
table16[0x18] = table32[0x18] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var addr; var result; if(cpu.modrm_byte < 0xC0) { addr = cpu.translate_address_write(cpu.modrm_resolve(cpu.modrm_byte)); data = cpu.memory.read8(addr); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; } result = cpu.sbb(data, cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1], OPSIZE_8); if(cpu.modrm_byte < 0xC0) { cpu.memory.write8(addr, result); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = result; } } }; table16[0x18 | 1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = cpu.translate_address_write(virt_addr + 1); data = cpu.virt_boundary_read16(phys_addr, phys_addr_high); } else { data = cpu.memory.read16(phys_addr); } } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; } result = cpu.sbb(data, cpu.reg16[cpu.modrm_byte >> 2 & 14], OPSIZE_16); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write16(phys_addr, phys_addr_high, result); } else { cpu.memory.write16(phys_addr, result); } } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = result; } } }; table32[0x18 | 1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = cpu.translate_address_write(virt_addr + 3); data = cpu.virt_boundary_read32s(phys_addr, phys_addr_high); } else { data = cpu.memory.read32s(phys_addr); } } else { data = cpu.reg32s[cpu.modrm_byte & 7]; } result = cpu.sbb(data, cpu.reg32s[cpu.modrm_byte >> 3 & 7], OPSIZE_32); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write32(phys_addr, phys_addr_high, result); } else { cpu.memory.write32(phys_addr, result); } } else { cpu.reg32s[cpu.modrm_byte & 7] = result; } } }; table16[0x18 | 2] = table32[0x18 | 2] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read8(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; }; cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1] = cpu.sbb(cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1], data, OPSIZE_8); } }; table16[0x18 | 3] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.reg16[cpu.modrm_byte >> 2 & 14] = cpu.sbb(cpu.reg16[cpu.modrm_byte >> 2 & 14], data, OPSIZE_16); } }; table32[0x18 | 3] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.reg32s[cpu.modrm_byte >> 3 & 7] = cpu.sbb(cpu.reg32s[cpu.modrm_byte >> 3 & 7], data, OPSIZE_32); } }; table16[0x18 | 4] = table32[0x18 | 4] = function(cpu) { { cpu.reg8[reg_al] = cpu.sbb(cpu.reg8[reg_al], cpu.read_imm8(), OPSIZE_8); } }; table16[0x18 | 5] = function(cpu) { { cpu.reg16[reg_ax] = cpu.sbb(cpu.reg16[reg_ax], cpu.read_imm16(), OPSIZE_16); } }; table32[0x18 | 5] = function(cpu) { { cpu.reg32s[reg_eax] = cpu.sbb(cpu.reg32s[reg_eax], cpu.read_imm32s(), OPSIZE_32); } };;
table16[0x1E] = function(cpu) { { cpu.push16(cpu.sreg[reg_ds]); } }; table32[0x1E] = function(cpu) { { cpu.push32(cpu.sreg[reg_ds]); } };;
table16[0x1F] = function(cpu) { { cpu.switch_seg(reg_ds, cpu.safe_read16(cpu.get_stack_pointer(0))); cpu.stack_reg[cpu.reg_vsp] += 2; if(reg_ds === reg_ss) { cpu.clear_prefixes(); cpu.cycle(); } } }; table32[0x1F] = function(cpu) { { cpu.switch_seg(reg_ds, cpu.safe_read16(cpu.get_stack_pointer(0))); cpu.stack_reg[cpu.reg_vsp] += 4; if(reg_ds === reg_ss) { cpu.clear_prefixes(); cpu.cycle(); } } };;;
table16[0x20] = table32[0x20] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var addr; var result; if(cpu.modrm_byte < 0xC0) { addr = cpu.translate_address_write(cpu.modrm_resolve(cpu.modrm_byte)); data = cpu.memory.read8(addr); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; } result = cpu.and(data, cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1], OPSIZE_8); if(cpu.modrm_byte < 0xC0) { cpu.memory.write8(addr, result); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = result; } } }; table16[0x20 | 1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = cpu.translate_address_write(virt_addr + 1); data = cpu.virt_boundary_read16(phys_addr, phys_addr_high); } else { data = cpu.memory.read16(phys_addr); } } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; } result = cpu.and(data, cpu.reg16[cpu.modrm_byte >> 2 & 14], OPSIZE_16); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write16(phys_addr, phys_addr_high, result); } else { cpu.memory.write16(phys_addr, result); } } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = result; } } }; table32[0x20 | 1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = cpu.translate_address_write(virt_addr + 3); data = cpu.virt_boundary_read32s(phys_addr, phys_addr_high); } else { data = cpu.memory.read32s(phys_addr); } } else { data = cpu.reg32s[cpu.modrm_byte & 7]; } result = cpu.and(data, cpu.reg32s[cpu.modrm_byte >> 3 & 7], OPSIZE_32); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write32(phys_addr, phys_addr_high, result); } else { cpu.memory.write32(phys_addr, result); } } else { cpu.reg32s[cpu.modrm_byte & 7] = result; } } }; table16[0x20 | 2] = table32[0x20 | 2] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read8(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; }; cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1] = cpu.and(cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1], data, OPSIZE_8); } }; table16[0x20 | 3] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.reg16[cpu.modrm_byte >> 2 & 14] = cpu.and(cpu.reg16[cpu.modrm_byte >> 2 & 14], data, OPSIZE_16); } }; table32[0x20 | 3] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.reg32s[cpu.modrm_byte >> 3 & 7] = cpu.and(cpu.reg32s[cpu.modrm_byte >> 3 & 7], data, OPSIZE_32); } }; table16[0x20 | 4] = table32[0x20 | 4] = function(cpu) { { cpu.reg8[reg_al] = cpu.and(cpu.reg8[reg_al], cpu.read_imm8(), OPSIZE_8); } }; table16[0x20 | 5] = function(cpu) { { cpu.reg16[reg_ax] = cpu.and(cpu.reg16[reg_ax], cpu.read_imm16(), OPSIZE_16); } }; table32[0x20 | 5] = function(cpu) { { cpu.reg32s[reg_eax] = cpu.and(cpu.reg32s[reg_eax], cpu.read_imm32s(), OPSIZE_32); } };;
table16[0x26] = table32[0x26] = function(cpu) { { cpu.segment_prefix = reg_es; cpu.do_op(); cpu.segment_prefix = SEG_PREFIX_NONE; } };;
table16[0x27] = table32[0x27] = function(cpu) { { cpu.bcd_daa(); } };;
table16[0x28] = table32[0x28] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var addr; var result; if(cpu.modrm_byte < 0xC0) { addr = cpu.translate_address_write(cpu.modrm_resolve(cpu.modrm_byte)); data = cpu.memory.read8(addr); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; } result = cpu.sub(data, cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1], OPSIZE_8); if(cpu.modrm_byte < 0xC0) { cpu.memory.write8(addr, result); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = result; } } }; table16[0x28 | 1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = cpu.translate_address_write(virt_addr + 1); data = cpu.virt_boundary_read16(phys_addr, phys_addr_high); } else { data = cpu.memory.read16(phys_addr); } } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; } result = cpu.sub(data, cpu.reg16[cpu.modrm_byte >> 2 & 14], OPSIZE_16); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write16(phys_addr, phys_addr_high, result); } else { cpu.memory.write16(phys_addr, result); } } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = result; } } }; table32[0x28 | 1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = cpu.translate_address_write(virt_addr + 3); data = cpu.virt_boundary_read32s(phys_addr, phys_addr_high); } else { data = cpu.memory.read32s(phys_addr); } } else { data = cpu.reg32s[cpu.modrm_byte & 7]; } result = cpu.sub(data, cpu.reg32s[cpu.modrm_byte >> 3 & 7], OPSIZE_32); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write32(phys_addr, phys_addr_high, result); } else { cpu.memory.write32(phys_addr, result); } } else { cpu.reg32s[cpu.modrm_byte & 7] = result; } } }; table16[0x28 | 2] = table32[0x28 | 2] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read8(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; }; cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1] = cpu.sub(cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1], data, OPSIZE_8); } }; table16[0x28 | 3] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.reg16[cpu.modrm_byte >> 2 & 14] = cpu.sub(cpu.reg16[cpu.modrm_byte >> 2 & 14], data, OPSIZE_16); } }; table32[0x28 | 3] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.reg32s[cpu.modrm_byte >> 3 & 7] = cpu.sub(cpu.reg32s[cpu.modrm_byte >> 3 & 7], data, OPSIZE_32); } }; table16[0x28 | 4] = table32[0x28 | 4] = function(cpu) { { cpu.reg8[reg_al] = cpu.sub(cpu.reg8[reg_al], cpu.read_imm8(), OPSIZE_8); } }; table16[0x28 | 5] = function(cpu) { { cpu.reg16[reg_ax] = cpu.sub(cpu.reg16[reg_ax], cpu.read_imm16(), OPSIZE_16); } }; table32[0x28 | 5] = function(cpu) { { cpu.reg32s[reg_eax] = cpu.sub(cpu.reg32s[reg_eax], cpu.read_imm32s(), OPSIZE_32); } };;
table16[0x2E] = table32[0x2E] = function(cpu) { { cpu.segment_prefix = reg_cs; cpu.do_op(); cpu.segment_prefix = SEG_PREFIX_NONE; } };;
table16[0x2F] = table32[0x2F] = function(cpu) { { cpu.bcd_das(); } };;
table16[0x30] = table32[0x30] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var addr; var result; if(cpu.modrm_byte < 0xC0) { addr = cpu.translate_address_write(cpu.modrm_resolve(cpu.modrm_byte)); data = cpu.memory.read8(addr); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; } result = cpu.xor(data, cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1], OPSIZE_8); if(cpu.modrm_byte < 0xC0) { cpu.memory.write8(addr, result); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = result; } } }; table16[0x30 | 1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = cpu.translate_address_write(virt_addr + 1); data = cpu.virt_boundary_read16(phys_addr, phys_addr_high); } else { data = cpu.memory.read16(phys_addr); } } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; } result = cpu.xor(data, cpu.reg16[cpu.modrm_byte >> 2 & 14], OPSIZE_16); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write16(phys_addr, phys_addr_high, result); } else { cpu.memory.write16(phys_addr, result); } } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = result; } } }; table32[0x30 | 1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = cpu.translate_address_write(virt_addr + 3); data = cpu.virt_boundary_read32s(phys_addr, phys_addr_high); } else { data = cpu.memory.read32s(phys_addr); } } else { data = cpu.reg32s[cpu.modrm_byte & 7]; } result = cpu.xor(data, cpu.reg32s[cpu.modrm_byte >> 3 & 7], OPSIZE_32); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write32(phys_addr, phys_addr_high, result); } else { cpu.memory.write32(phys_addr, result); } } else { cpu.reg32s[cpu.modrm_byte & 7] = result; } } }; table16[0x30 | 2] = table32[0x30 | 2] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read8(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; }; cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1] = cpu.xor(cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1], data, OPSIZE_8); } }; table16[0x30 | 3] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.reg16[cpu.modrm_byte >> 2 & 14] = cpu.xor(cpu.reg16[cpu.modrm_byte >> 2 & 14], data, OPSIZE_16); } }; table32[0x30 | 3] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.reg32s[cpu.modrm_byte >> 3 & 7] = cpu.xor(cpu.reg32s[cpu.modrm_byte >> 3 & 7], data, OPSIZE_32); } }; table16[0x30 | 4] = table32[0x30 | 4] = function(cpu) { { cpu.reg8[reg_al] = cpu.xor(cpu.reg8[reg_al], cpu.read_imm8(), OPSIZE_8); } }; table16[0x30 | 5] = function(cpu) { { cpu.reg16[reg_ax] = cpu.xor(cpu.reg16[reg_ax], cpu.read_imm16(), OPSIZE_16); } }; table32[0x30 | 5] = function(cpu) { { cpu.reg32s[reg_eax] = cpu.xor(cpu.reg32s[reg_eax], cpu.read_imm32s(), OPSIZE_32); } };;
table16[0x36] = table32[0x36] = function(cpu) { { cpu.segment_prefix = reg_ss; cpu.do_op(); cpu.segment_prefix = SEG_PREFIX_NONE; } };;
table16[0x37] = table32[0x37] = function(cpu) { { cpu.bcd_aaa(); } };;
table16[0x38] = table32[0x38] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read8(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; }; cpu.sub(data, cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1], OPSIZE_8); } };
table16[0x39] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.sub(data, cpu.reg16[cpu.modrm_byte >> 2 & 14], OPSIZE_16); } }; table32[0x39] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.sub(data, cpu.reg32s[cpu.modrm_byte >> 3 & 7], OPSIZE_32); } };
table16[0x3A] = table32[0x3A] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read8(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; }; cpu.sub(cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1], data, OPSIZE_8); } };
table16[0x3B] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.sub(cpu.reg16[cpu.modrm_byte >> 2 & 14], data, OPSIZE_16); } }; table32[0x3B] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.sub(cpu.reg32s[cpu.modrm_byte >> 3 & 7], data, OPSIZE_32); } };
table16[0x3C] = table32[0x3C] = function(cpu) { { cpu.sub(cpu.reg8[reg_al], cpu.read_imm8(), OPSIZE_8); } };
table16[0x3D] = function(cpu) { { cpu.sub(cpu.reg16[reg_ax], cpu.read_imm16(), OPSIZE_16); } }; table32[0x3D] = function(cpu) { { cpu.sub(cpu.reg32s[reg_eax], cpu.read_imm32s(), OPSIZE_32); } };
table16[0x3E] = table32[0x3E] = function(cpu) { { cpu.segment_prefix = reg_ds; cpu.do_op(); cpu.segment_prefix = SEG_PREFIX_NONE; } };;
table16[0x3F] = table32[0x3F] = function(cpu) { { cpu.bcd_aas(); } };;
table16[0x40] = function(cpu) { { cpu.reg16[reg_ax] = cpu.inc(cpu.reg16[reg_ax], OPSIZE_16); } }; table32[0x40] = function(cpu) { { cpu.reg32s[reg_eax] = cpu.inc(cpu.reg32s[reg_eax], OPSIZE_32); } };;
table16[0x41] = function(cpu) { { cpu.reg16[reg_cx] = cpu.inc(cpu.reg16[reg_cx], OPSIZE_16); } }; table32[0x41] = function(cpu) { { cpu.reg32s[reg_ecx] = cpu.inc(cpu.reg32s[reg_ecx], OPSIZE_32); } };;
table16[0x42] = function(cpu) { { cpu.reg16[reg_dx] = cpu.inc(cpu.reg16[reg_dx], OPSIZE_16); } }; table32[0x42] = function(cpu) { { cpu.reg32s[reg_edx] = cpu.inc(cpu.reg32s[reg_edx], OPSIZE_32); } };;
table16[0x43] = function(cpu) { { cpu.reg16[reg_bx] = cpu.inc(cpu.reg16[reg_bx], OPSIZE_16); } }; table32[0x43] = function(cpu) { { cpu.reg32s[reg_ebx] = cpu.inc(cpu.reg32s[reg_ebx], OPSIZE_32); } };;
table16[0x44] = function(cpu) { { cpu.reg16[reg_sp] = cpu.inc(cpu.reg16[reg_sp], OPSIZE_16); } }; table32[0x44] = function(cpu) { { cpu.reg32s[reg_esp] = cpu.inc(cpu.reg32s[reg_esp], OPSIZE_32); } };;
table16[0x45] = function(cpu) { { cpu.reg16[reg_bp] = cpu.inc(cpu.reg16[reg_bp], OPSIZE_16); } }; table32[0x45] = function(cpu) { { cpu.reg32s[reg_ebp] = cpu.inc(cpu.reg32s[reg_ebp], OPSIZE_32); } };;
table16[0x46] = function(cpu) { { cpu.reg16[reg_si] = cpu.inc(cpu.reg16[reg_si], OPSIZE_16); } }; table32[0x46] = function(cpu) { { cpu.reg32s[reg_esi] = cpu.inc(cpu.reg32s[reg_esi], OPSIZE_32); } };;
table16[0x47] = function(cpu) { { cpu.reg16[reg_di] = cpu.inc(cpu.reg16[reg_di], OPSIZE_16); } }; table32[0x47] = function(cpu) { { cpu.reg32s[reg_edi] = cpu.inc(cpu.reg32s[reg_edi], OPSIZE_32); } };;
table16[0x48] = function(cpu) { { cpu.reg16[reg_ax] = cpu.dec(cpu.reg16[reg_ax], OPSIZE_16); } }; table32[0x48] = function(cpu) { { cpu.reg32s[reg_eax] = cpu.dec(cpu.reg32s[reg_eax], OPSIZE_32); } };;
table16[0x49] = function(cpu) { { cpu.reg16[reg_cx] = cpu.dec(cpu.reg16[reg_cx], OPSIZE_16); } }; table32[0x49] = function(cpu) { { cpu.reg32s[reg_ecx] = cpu.dec(cpu.reg32s[reg_ecx], OPSIZE_32); } };;
table16[0x4A] = function(cpu) { { cpu.reg16[reg_dx] = cpu.dec(cpu.reg16[reg_dx], OPSIZE_16); } }; table32[0x4A] = function(cpu) { { cpu.reg32s[reg_edx] = cpu.dec(cpu.reg32s[reg_edx], OPSIZE_32); } };;
table16[0x4B] = function(cpu) { { cpu.reg16[reg_bx] = cpu.dec(cpu.reg16[reg_bx], OPSIZE_16); } }; table32[0x4B] = function(cpu) { { cpu.reg32s[reg_ebx] = cpu.dec(cpu.reg32s[reg_ebx], OPSIZE_32); } };;
table16[0x4C] = function(cpu) { { cpu.reg16[reg_sp] = cpu.dec(cpu.reg16[reg_sp], OPSIZE_16); } }; table32[0x4C] = function(cpu) { { cpu.reg32s[reg_esp] = cpu.dec(cpu.reg32s[reg_esp], OPSIZE_32); } };;
table16[0x4D] = function(cpu) { { cpu.reg16[reg_bp] = cpu.dec(cpu.reg16[reg_bp], OPSIZE_16); } }; table32[0x4D] = function(cpu) { { cpu.reg32s[reg_ebp] = cpu.dec(cpu.reg32s[reg_ebp], OPSIZE_32); } };;
table16[0x4E] = function(cpu) { { cpu.reg16[reg_si] = cpu.dec(cpu.reg16[reg_si], OPSIZE_16); } }; table32[0x4E] = function(cpu) { { cpu.reg32s[reg_esi] = cpu.dec(cpu.reg32s[reg_esi], OPSIZE_32); } };;
table16[0x4F] = function(cpu) { { cpu.reg16[reg_di] = cpu.dec(cpu.reg16[reg_di], OPSIZE_16); } }; table32[0x4F] = function(cpu) { { cpu.reg32s[reg_edi] = cpu.dec(cpu.reg32s[reg_edi], OPSIZE_32); } };;
table16[0x50] = function(cpu) { { cpu.push16(cpu.reg16[reg_ax]); } }; table32[0x50] = function(cpu) { { cpu.push32(cpu.reg32s[reg_eax]); } };
table16[0x51] = function(cpu) { { cpu.push16(cpu.reg16[reg_cx]); } }; table32[0x51] = function(cpu) { { cpu.push32(cpu.reg32s[reg_ecx]); } };
table16[0x52] = function(cpu) { { cpu.push16(cpu.reg16[reg_dx]); } }; table32[0x52] = function(cpu) { { cpu.push32(cpu.reg32s[reg_edx]); } };
table16[0x53] = function(cpu) { { cpu.push16(cpu.reg16[reg_bx]); } }; table32[0x53] = function(cpu) { { cpu.push32(cpu.reg32s[reg_ebx]); } };
table16[0x54] = function(cpu) { { cpu.push16(cpu.reg16[reg_sp]); } }; table32[0x54] = function(cpu) { { cpu.push32(cpu.reg32s[reg_esp]); } };
table16[0x55] = function(cpu) { { cpu.push16(cpu.reg16[reg_bp]); } }; table32[0x55] = function(cpu) { { cpu.push32(cpu.reg32s[reg_ebp]); } };
table16[0x56] = function(cpu) { { cpu.push16(cpu.reg16[reg_si]); } }; table32[0x56] = function(cpu) { { cpu.push32(cpu.reg32s[reg_esi]); } };
table16[0x57] = function(cpu) { { cpu.push16(cpu.reg16[reg_di]); } }; table32[0x57] = function(cpu) { { cpu.push32(cpu.reg32s[reg_edi]); } };
table16[0x58] = function(cpu) { { cpu.reg16[reg_ax] = cpu.pop16(); } }; table32[0x58] = function(cpu) { { cpu.reg32s[reg_eax] = cpu.pop32s(); } };
table16[0x59] = function(cpu) { { cpu.reg16[reg_cx] = cpu.pop16(); } }; table32[0x59] = function(cpu) { { cpu.reg32s[reg_ecx] = cpu.pop32s(); } };
table16[0x5A] = function(cpu) { { cpu.reg16[reg_dx] = cpu.pop16(); } }; table32[0x5A] = function(cpu) { { cpu.reg32s[reg_edx] = cpu.pop32s(); } };
table16[0x5B] = function(cpu) { { cpu.reg16[reg_bx] = cpu.pop16(); } }; table32[0x5B] = function(cpu) { { cpu.reg32s[reg_ebx] = cpu.pop32s(); } };
table16[0x5C] = function(cpu) { { cpu.reg16[reg_sp] = cpu.pop16(); } }; table32[0x5C] = function(cpu) { { cpu.reg32s[reg_esp] = cpu.pop32s(); } };
table16[0x5D] = function(cpu) { { cpu.reg16[reg_bp] = cpu.pop16(); } }; table32[0x5D] = function(cpu) { { cpu.reg32s[reg_ebp] = cpu.pop32s(); } };
table16[0x5E] = function(cpu) { { cpu.reg16[reg_si] = cpu.pop16(); } }; table32[0x5E] = function(cpu) { { cpu.reg32s[reg_esi] = cpu.pop32s(); } };
table16[0x5F] = function(cpu) { { cpu.reg16[reg_di] = cpu.pop16(); } }; table32[0x5F] = function(cpu) { { cpu.reg32s[reg_edi] = cpu.pop32s(); } };
table16[0x60] = function(cpu) { { cpu.pusha16(); } }; table32[0x60] = function(cpu) { { cpu.pusha32(); } };;
table16[0x61] = function(cpu) { { cpu.popa16(); } }; table32[0x61] = function(cpu) { { cpu.popa32(); } };;
table16[0x62] = table32[0x62] = function(cpu) { { /* bound*/ dbg_log("Unimplemented BOUND instruction", LOG_CPU); } };;
table16[0x63] = table32[0x63] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { /* arpl*/ /*dbg_log("arpl", LOG_CPU);*/ if(cpu.protected_mode && !cpu.vm86_mode()) { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = cpu.translate_address_write(virt_addr + 1); data = cpu.virt_boundary_read16(phys_addr, phys_addr_high); } else { data = cpu.memory.read16(phys_addr); } } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; } result = cpu.arpl(data, cpu.modrm_byte >> 2 & 14); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write16(phys_addr, phys_addr_high, result); } else { cpu.memory.write16(phys_addr, result); } } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = result; }; } else { cpu.trigger_ud(); } } };;
table16[0x64] = table32[0x64] = function(cpu) { { cpu.segment_prefix = reg_fs; cpu.do_op(); cpu.segment_prefix = SEG_PREFIX_NONE; } };;
table16[0x65] = table32[0x65] = function(cpu) { { cpu.segment_prefix = reg_gs; cpu.do_op(); cpu.segment_prefix = SEG_PREFIX_NONE; } };;
table16[0x66] = function(cpu) { { /* Operand-size override prefix*/ dbg_assert(cpu.operand_size_32 === cpu.is_32); cpu.operand_size_32 = true; cpu.table = cpu.table32; cpu.do_op(); cpu.operand_size_32 = cpu.is_32; cpu.update_operand_size(); } }; table32[0x66] = function(cpu) { { dbg_assert(cpu.operand_size_32 === cpu.is_32); cpu.operand_size_32 = false; cpu.table = cpu.table16; cpu.do_op(); cpu.operand_size_32 = cpu.is_32; cpu.update_operand_size(); } };;
table16[0x67] = table32[0x67] = function(cpu) { { /* Address-size override prefix*/ dbg_assert(cpu.address_size_32 === cpu.is_32); cpu.address_size_32 = !cpu.is_32; cpu.update_address_size(); cpu.do_op(); cpu.address_size_32 = cpu.is_32; cpu.update_address_size(); } };;
table16[0x68] = function(cpu) { { cpu.push16(cpu.read_imm16()); } }; table32[0x68] = function(cpu) { { cpu.push32(cpu.read_imm32s()); } };;
table16[0x69] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = (cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)) << 16 >> 16); } else { data = cpu.reg16s[cpu.modrm_byte << 1 & 14]; }; cpu.reg16[cpu.modrm_byte >> 2 & 14] = cpu.imul_reg16(cpu.read_imm16s(), data); } }; table32[0x69] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.reg32s[cpu.modrm_byte >> 3 & 7] = cpu.imul_reg32(cpu.read_imm32s(), data); } };;
table16[0x6A] = function(cpu) { { cpu.push16(cpu.read_imm8s()); } }; table32[0x6A] = function(cpu) { { cpu.push32(cpu.read_imm8s()); } };;
table16[0x6B] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = (cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)) << 16 >> 16); } else { data = cpu.reg16s[cpu.modrm_byte << 1 & 14]; }; cpu.reg16[cpu.modrm_byte >> 2 & 14] = cpu.imul_reg16(cpu.read_imm8s(), data); } }; table32[0x6B] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.reg32s[cpu.modrm_byte >> 3 & 7] = cpu.imul_reg32(cpu.read_imm8s(), data); } };;
table16[0x6C] = table32[0x6C] = function(cpu) { { insb(cpu); } };;
table16[0x6D] = function(cpu) { { insw(cpu); } }; table32[0x6D] = function(cpu) { { insd(cpu); } };;
table16[0x6E] = table32[0x6E] = function(cpu) { { outsb(cpu); } };;
table16[0x6F] = function(cpu) { { outsw(cpu); } }; table32[0x6F] = function(cpu) { { outsd(cpu); } };;
table16[0x70 | 0x0] = table32[0x70 | 0x0] = function(cpu) { { var imm8 = cpu.read_imm8s(); if(( cpu.test_o())) { cpu.instruction_pointer = cpu.instruction_pointer + imm8 | 0; } } };;; table16[0x70 | 0x1] = table32[0x70 | 0x1] = function(cpu) { { var imm8 = cpu.read_imm8s(); if((!cpu.test_o())) { cpu.instruction_pointer = cpu.instruction_pointer + imm8 | 0; } } };;; table16[0x70 | 0x2] = table32[0x70 | 0x2] = function(cpu) { { var imm8 = cpu.read_imm8s(); if(( cpu.test_b())) { cpu.instruction_pointer = cpu.instruction_pointer + imm8 | 0; } } };;; table16[0x70 | 0x3] = table32[0x70 | 0x3] = function(cpu) { { var imm8 = cpu.read_imm8s(); if((!cpu.test_b())) { cpu.instruction_pointer = cpu.instruction_pointer + imm8 | 0; } } };;; table16[0x70 | 0x4] = table32[0x70 | 0x4] = function(cpu) { { var imm8 = cpu.read_imm8s(); if(( cpu.test_z())) { cpu.instruction_pointer = cpu.instruction_pointer + imm8 | 0; } } };;; table16[0x70 | 0x5] = table32[0x70 | 0x5] = function(cpu) { { var imm8 = cpu.read_imm8s(); if((!cpu.test_z())) { cpu.instruction_pointer = cpu.instruction_pointer + imm8 | 0; } } };;; table16[0x70 | 0x6] = table32[0x70 | 0x6] = function(cpu) { { var imm8 = cpu.read_imm8s(); if(( cpu.test_be())) { cpu.instruction_pointer = cpu.instruction_pointer + imm8 | 0; } } };;; table16[0x70 | 0x7] = table32[0x70 | 0x7] = function(cpu) { { var imm8 = cpu.read_imm8s(); if((!cpu.test_be())) { cpu.instruction_pointer = cpu.instruction_pointer + imm8 | 0; } } };;; table16[0x70 | 0x8] = table32[0x70 | 0x8] = function(cpu) { { var imm8 = cpu.read_imm8s(); if(( cpu.test_s())) { cpu.instruction_pointer = cpu.instruction_pointer + imm8 | 0; } } };;; table16[0x70 | 0x9] = table32[0x70 | 0x9] = function(cpu) { { var imm8 = cpu.read_imm8s(); if((!cpu.test_s())) { cpu.instruction_pointer = cpu.instruction_pointer + imm8 | 0; } } };;; table16[0x70 | 0xA] = table32[0x70 | 0xA] = function(cpu) { { var imm8 = cpu.read_imm8s(); if(( cpu.test_p())) { cpu.instruction_pointer = cpu.instruction_pointer + imm8 | 0; } } };;; table16[0x70 | 0xB] = table32[0x70 | 0xB] = function(cpu) { { var imm8 = cpu.read_imm8s(); if((!cpu.test_p())) { cpu.instruction_pointer = cpu.instruction_pointer + imm8 | 0; } } };;; table16[0x70 | 0xC] = table32[0x70 | 0xC] = function(cpu) { { var imm8 = cpu.read_imm8s(); if(( cpu.test_l())) { cpu.instruction_pointer = cpu.instruction_pointer + imm8 | 0; } } };;; table16[0x70 | 0xD] = table32[0x70 | 0xD] = function(cpu) { { var imm8 = cpu.read_imm8s(); if((!cpu.test_l())) { cpu.instruction_pointer = cpu.instruction_pointer + imm8 | 0; } } };;; table16[0x70 | 0xE] = table32[0x70 | 0xE] = function(cpu) { { var imm8 = cpu.read_imm8s(); if(( cpu.test_le())) { cpu.instruction_pointer = cpu.instruction_pointer + imm8 | 0; } } };;; table16[0x70 | 0xF] = table32[0x70 | 0xF] = function(cpu) { { var imm8 = cpu.read_imm8s(); if((!cpu.test_le())) { cpu.instruction_pointer = cpu.instruction_pointer + imm8 | 0; } } };;;;
table16[0x80] = table32[0x80] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if((cpu.modrm_byte & 56) === 56) { /* CMP*/ if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read8(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; }; cpu.sub(data, cpu.read_imm8(), OPSIZE_8); } else { var data2; var data; var addr; var result; if(cpu.modrm_byte < 0xC0) { addr = cpu.translate_address_write(cpu.modrm_resolve(cpu.modrm_byte)); data = cpu.memory.read8(addr); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; } result = 0; data2 = cpu.read_imm8(); switch(cpu.modrm_byte >> 3 & 7) { case 0: result = cpu.add(data, data2, OPSIZE_8); break; case 1: result = cpu.or(data, data2, OPSIZE_8); break; case 2: result = cpu.adc(data, data2, OPSIZE_8); break; case 3: result = cpu.sbb(data, data2, OPSIZE_8); break; case 4: result = cpu.and(data, data2, OPSIZE_8); break; case 5: result = cpu.sub(data, data2, OPSIZE_8); break; case 6: result = cpu.xor(data, data2, OPSIZE_8); break; case 7: result = dbg_assert.bind(this, 0)(data, data2); break; }; if(cpu.modrm_byte < 0xC0) { cpu.memory.write8(addr, result); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = result; } } } };;
table16[0x81] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if((cpu.modrm_byte & 56) === 56) { /* CMP*/ if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.sub(data, cpu.read_imm16(), OPSIZE_16); } else { var data2; var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = cpu.translate_address_write(virt_addr + 1); data = cpu.virt_boundary_read16(phys_addr, phys_addr_high); } else { data = cpu.memory.read16(phys_addr); } } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; } result = 0; data2 = cpu.read_imm16(); switch(cpu.modrm_byte >> 3 & 7) { case 0: result = cpu.add(data, data2, OPSIZE_16); break; case 1: result = cpu.or(data, data2, OPSIZE_16); break; case 2: result = cpu.adc(data, data2, OPSIZE_16); break; case 3: result = cpu.sbb(data, data2, OPSIZE_16); break; case 4: result = cpu.and(data, data2, OPSIZE_16); break; case 5: result = cpu.sub(data, data2, OPSIZE_16); break; case 6: result = cpu.xor(data, data2, OPSIZE_16); break; case 7: result = dbg_assert.bind(this, 0)(data, data2); break; }; if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write16(phys_addr, phys_addr_high, result); } else { cpu.memory.write16(phys_addr, result); } } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = result; } } } }; table32[0x81] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if((cpu.modrm_byte & 56) === 56) { /* CMP*/ if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.sub(data, cpu.read_imm32s(), OPSIZE_32); } else { var data2; var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = cpu.translate_address_write(virt_addr + 3); data = cpu.virt_boundary_read32s(phys_addr, phys_addr_high); } else { data = cpu.memory.read32s(phys_addr); } } else { data = cpu.reg32s[cpu.modrm_byte & 7]; } result = 0; data2 = cpu.read_imm32s(); switch(cpu.modrm_byte >> 3 & 7) { case 0: result = cpu.add(data, data2, OPSIZE_32); break; case 1: result = cpu.or(data, data2, OPSIZE_32); break; case 2: result = cpu.adc(data, data2, OPSIZE_32); break; case 3: result = cpu.sbb(data, data2, OPSIZE_32); break; case 4: result = cpu.and(data, data2, OPSIZE_32); break; case 5: result = cpu.sub(data, data2, OPSIZE_32); break; case 6: result = cpu.xor(data, data2, OPSIZE_32); break; case 7: result = dbg_assert.bind(this, 0)(data, data2); break; }; if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write32(phys_addr, phys_addr_high, result); } else { cpu.memory.write32(phys_addr, result); } } else { cpu.reg32s[cpu.modrm_byte & 7] = result; } } } };;
table16[0x82] = table32[0x82] = function(cpu) { { cpu.table[0x80](cpu); /* alias*/ } };;
table16[0x83] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if((cpu.modrm_byte & 56) === 56) { /* CMP*/ if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.sub(data, cpu.read_imm8s(), OPSIZE_16); } else { var data2; var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = cpu.translate_address_write(virt_addr + 1); data = cpu.virt_boundary_read16(phys_addr, phys_addr_high); } else { data = cpu.memory.read16(phys_addr); } } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; } result = 0; data2 = cpu.read_imm8s(); switch(cpu.modrm_byte >> 3 & 7) { case 0: result = cpu.add(data, data2, OPSIZE_16); break; case 1: result = cpu.or(data, data2, OPSIZE_16); break; case 2: result = cpu.adc(data, data2, OPSIZE_16); break; case 3: result = cpu.sbb(data, data2, OPSIZE_16); break; case 4: result = cpu.and(data, data2, OPSIZE_16); break; case 5: result = cpu.sub(data, data2, OPSIZE_16); break; case 6: result = cpu.xor(data, data2, OPSIZE_16); break; case 7: result = dbg_assert.bind(this, 0)(data, data2); break; }; if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write16(phys_addr, phys_addr_high, result); } else { cpu.memory.write16(phys_addr, result); } } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = result; } } } }; table32[0x83] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if((cpu.modrm_byte & 56) === 56) { /* CMP*/ if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.sub(data, cpu.read_imm8s(), OPSIZE_32); } else { var data2; var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = cpu.translate_address_write(virt_addr + 3); data = cpu.virt_boundary_read32s(phys_addr, phys_addr_high); } else { data = cpu.memory.read32s(phys_addr); } } else { data = cpu.reg32s[cpu.modrm_byte & 7]; } result = 0; data2 = cpu.read_imm8s(); switch(cpu.modrm_byte >> 3 & 7) { case 0: result = cpu.add(data, data2, OPSIZE_32); break; case 1: result = cpu.or(data, data2, OPSIZE_32); break; case 2: result = cpu.adc(data, data2, OPSIZE_32); break; case 3: result = cpu.sbb(data, data2, OPSIZE_32); break; case 4: result = cpu.and(data, data2, OPSIZE_32); break; case 5: result = cpu.sub(data, data2, OPSIZE_32); break; case 6: result = cpu.xor(data, data2, OPSIZE_32); break; case 7: result = dbg_assert.bind(this, 0)(data, data2); break; }; if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write32(phys_addr, phys_addr_high, result); } else { cpu.memory.write32(phys_addr, result); } } else { cpu.reg32s[cpu.modrm_byte & 7] = result; } } } };;
table16[0x84] = table32[0x84] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read8(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; }; cpu.and(data, cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1], OPSIZE_8); } };
table16[0x85] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.and(data, cpu.reg16[cpu.modrm_byte >> 2 & 14], OPSIZE_16); } }; table32[0x85] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.and(data, cpu.reg32s[cpu.modrm_byte >> 3 & 7], OPSIZE_32); } };
table16[0x86] = table32[0x86] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var addr; var result; if(cpu.modrm_byte < 0xC0) { addr = cpu.translate_address_write(cpu.modrm_resolve(cpu.modrm_byte)); data = cpu.memory.read8(addr); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; } result = cpu.xchg8(data, cpu.modrm_byte); if(cpu.modrm_byte < 0xC0) { cpu.memory.write8(addr, result); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = result; }; } };;
table16[0x87] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = cpu.translate_address_write(virt_addr + 1); data = cpu.virt_boundary_read16(phys_addr, phys_addr_high); } else { data = cpu.memory.read16(phys_addr); } } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; } result = cpu.xchg16(data, cpu.modrm_byte); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write16(phys_addr, phys_addr_high, result); } else { cpu.memory.write16(phys_addr, result); } } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = result; }; } }; table32[0x87] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = cpu.translate_address_write(virt_addr + 3); data = cpu.virt_boundary_read32s(phys_addr, phys_addr_high); } else { data = cpu.memory.read32s(phys_addr); } } else { data = cpu.reg32s[cpu.modrm_byte & 7]; } result = cpu.xchg32(data, cpu.modrm_byte); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write32(phys_addr, phys_addr_high, result); } else { cpu.memory.write32(phys_addr, result); } } else { cpu.reg32s[cpu.modrm_byte & 7] = result; }; } };;
table16[0x88] = table32[0x88] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1]; if(cpu.modrm_byte < 0xC0) { cpu.safe_write8(addr, data); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = data; }; } };
table16[0x89] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = cpu.reg16[cpu.modrm_byte >> 2 & 14]; if(cpu.modrm_byte < 0xC0) { cpu.safe_write16(addr, data); } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = data; }; } }; table32[0x89] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = cpu.reg32s[cpu.modrm_byte >> 3 & 7]; if(cpu.modrm_byte < 0xC0) { cpu.safe_write32(addr, data); } else { cpu.reg32[cpu.modrm_byte & 7] = data; }; } };
table16[0x8A] = table32[0x8A] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read8(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; }; cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1] = data; } };;
table16[0x8B] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.reg16[cpu.modrm_byte >> 2 & 14] = data; } }; table32[0x8B] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.reg32s[cpu.modrm_byte >> 3 & 7] = data; } };;
table16[0x8C] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = cpu.sreg[cpu.modrm_byte >> 3 & 7]; if(cpu.modrm_byte < 0xC0) { cpu.safe_write16(addr, data); } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = data; }; } }; table32[0x8C] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = cpu.sreg[cpu.modrm_byte >> 3 & 7]; if(cpu.modrm_byte < 0xC0) { cpu.safe_write32(addr, data); } else { cpu.reg32[cpu.modrm_byte & 7] = data; }; } };;
table16[0x8D] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { /* lea*/ if(cpu.modrm_byte >= 0xC0) { cpu.trigger_ud(); } var mod = cpu.modrm_byte >> 3 & 7; /* override prefix, so modrm_resolve does not return the segment part*/ cpu.segment_prefix = SEG_PREFIX_ZERO; cpu.reg16[mod << 1] = cpu.modrm_resolve(cpu.modrm_byte); cpu.segment_prefix = SEG_PREFIX_NONE; } }; table32[0x8D] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte >= 0xC0) { cpu.trigger_ud(); } var mod = cpu.modrm_byte >> 3 & 7; cpu.segment_prefix = SEG_PREFIX_ZERO; cpu.reg32s[mod] = cpu.modrm_resolve(cpu.modrm_byte); cpu.segment_prefix = SEG_PREFIX_NONE; } };;
table16[0x8E] = table32[0x8E] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var mod = cpu.modrm_byte >> 3 & 7; /*cpu.paging && console.log(h(cpu.instruction_pointer >>> 0), h(cpu.modrm_byte));*/ if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; /*cpu.paging && console.log(mod, h(data));*/ cpu.switch_seg(mod, data); if(mod === reg_ss) { /* run next instruction, so no interrupts are handled*/ /*cpu.clear_prefixes();*/ /*cpu.cycle();*/ } } };;
table16[0x8F] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { /* pop*/ var sp = cpu.safe_read16(cpu.get_stack_pointer(0)); cpu.stack_reg[cpu.reg_vsp] += 2; if(cpu.modrm_byte < 0xC0) { var addr = cpu.modrm_resolve(cpu.modrm_byte); cpu.stack_reg[cpu.reg_vsp] -= 2; cpu.safe_write16(addr, sp); cpu.stack_reg[cpu.reg_vsp] += 2; } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = sp; } } }; table32[0x8F] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var sp = cpu.safe_read32s(cpu.get_stack_pointer(0)); /* change esp first, then resolve modrm address*/ cpu.stack_reg[cpu.reg_vsp] += 4; if(cpu.modrm_byte < 0xC0) { var addr = cpu.modrm_resolve(cpu.modrm_byte); /* Before attempting a write that might cause a page fault,*/ /* we must set esp to the old value. Fuck Intel.*/ cpu.stack_reg[cpu.reg_vsp] -= 4; cpu.safe_write32(addr, sp); cpu.stack_reg[cpu.reg_vsp] += 4; } else { cpu.reg32s[cpu.modrm_byte & 7] = sp; } } };;
table16[0x90] = table32[0x90] = function(cpu) { /* nop */ };;
table16[0x91] = function(cpu) { { cpu.xchg16r(reg_cx) } }; table32[0x91] = function(cpu) { { cpu.xchg32r(reg_ecx) } };;
table16[0x92] = function(cpu) { { cpu.xchg16r(reg_dx) } }; table32[0x92] = function(cpu) { { cpu.xchg32r(reg_edx) } };;
table16[0x93] = function(cpu) { { cpu.xchg16r(reg_bx) } }; table32[0x93] = function(cpu) { { cpu.xchg32r(reg_ebx) } };;
table16[0x94] = function(cpu) { { cpu.xchg16r(reg_sp) } }; table32[0x94] = function(cpu) { { cpu.xchg32r(reg_esp) } };;
table16[0x95] = function(cpu) { { cpu.xchg16r(reg_bp) } }; table32[0x95] = function(cpu) { { cpu.xchg32r(reg_ebp) } };;
table16[0x96] = function(cpu) { { cpu.xchg16r(reg_si) } }; table32[0x96] = function(cpu) { { cpu.xchg32r(reg_esi) } };;
table16[0x97] = function(cpu) { { cpu.xchg16r(reg_di) } }; table32[0x97] = function(cpu) { { cpu.xchg32r(reg_edi) } };;
table16[0x98] = function(cpu) { { /* cbw */ cpu.reg16[reg_ax] = cpu.reg8s[reg_al]; } }; table32[0x98] = function(cpu) { { /* cwde */ cpu.reg32s[reg_eax] = cpu.reg16s[reg_ax]; } };;
table16[0x99] = function(cpu) { { /* cwd */ cpu.reg16[reg_dx] = cpu.reg16s[reg_ax] >> 15; } }; table32[0x99] = function(cpu) { { /* cdq */ cpu.reg32s[reg_edx] = cpu.reg32s[reg_eax] >> 31; } };;
table16[0x9A] = function(cpu) { { /* callf*/ var new_ip = cpu.read_imm16(); var new_cs = cpu.read_imm16(); cpu.writable_or_pagefault(cpu.get_stack_pointer(-4), 4); cpu.push16(cpu.sreg[reg_cs]); cpu.push16(cpu.get_real_eip()); cpu.switch_seg(reg_cs, new_cs); cpu.instruction_pointer = cpu.get_seg(reg_cs) + new_ip | 0; } }; table32[0x9A] = function(cpu) { { var new_ip = cpu.read_imm32s(); var new_cs = cpu.read_imm16(); if(!cpu.protected_mode || cpu.vm86_mode()) { if(new_ip & 0xFFFF0000) { throw cpu.debug.unimpl("#GP handler"); } } cpu.writable_or_pagefault(cpu.get_stack_pointer(-8), 8); cpu.push32(cpu.sreg[reg_cs]); cpu.push32(cpu.get_real_eip()); cpu.switch_seg(reg_cs, new_cs); cpu.instruction_pointer = cpu.get_seg(reg_cs) + new_ip | 0; } };;
table16[0x9B] = table32[0x9B] = function(cpu) { { /* fwait: check for pending fpu exceptions*/ if((cpu.cr[0] & (CR0_MP | CR0_TS)) === (CR0_MP | CR0_TS)) { /* task switched and MP bit is set*/ cpu.trigger_nm(); } else { if(cpu.fpu) { cpu.fpu.fwait(); } else { /* EM bit isn't checked*/ /* If there's no FPU, do nothing*/ } } } };;
table16[0x9C] = function(cpu) { { /* pushf*/ if((cpu.flags & flag_vm) && cpu.getiopl() < 3) { cpu.trigger_gp(0); } else { cpu.load_eflags(); cpu.push16(cpu.flags); } } }; table32[0x9C] = function(cpu) { { /* pushf*/ if((cpu.flags & flag_vm) && cpu.getiopl() < 3) { /* trap to virtual 8086 monitor*/ cpu.trigger_gp(0); } else { cpu.load_eflags(); /* vm and rf flag are cleared in image stored on the stack*/ cpu.push32(cpu.flags & 0x00FCFFFF); } } };;
table16[0x9D] = function(cpu) { { /* popf*/ if((cpu.flags & flag_vm) && cpu.getiopl() < 3) { cpu.trigger_gp(0); } cpu.update_eflags((cpu.flags & ~0xFFFF) | cpu.pop16()); cpu.handle_irqs(); } }; table32[0x9D] = function(cpu) { { /* popf*/ if(cpu.flags & flag_vm) { /* in vm86 mode, pop causes a #GP when used with the operand-size prefix*/ cpu.trigger_gp(0); } cpu.update_eflags(cpu.pop32s()); cpu.handle_irqs(); } };;
table16[0x9E] = table32[0x9E] = function(cpu) { { /* sahf*/ cpu.flags = (cpu.flags & ~0xFF) | cpu.reg8[reg_ah]; cpu.flags = (cpu.flags & flags_mask) | flags_default; cpu.flags_changed = 0; } };;
table16[0x9F] = table32[0x9F] = function(cpu) { { /* lahf*/ cpu.load_eflags(); cpu.reg8[reg_ah] = cpu.flags; } };;
table16[0xA0] = table32[0xA0] = function(cpu) { { /* mov*/ var data = cpu.safe_read8(cpu.read_moffs()); cpu.reg8[reg_al] = data; } };;
table16[0xA1] = function(cpu) { { /* mov*/ var data = cpu.safe_read16(cpu.read_moffs()); cpu.reg16[reg_ax] = data; } }; table32[0xA1] = function(cpu) { { var data = cpu.safe_read32s(cpu.read_moffs()); cpu.reg32s[reg_eax] = data; } };;
table16[0xA2] = table32[0xA2] = function(cpu) { { /* mov*/ cpu.safe_write8(cpu.read_moffs(), cpu.reg8[reg_al]); } };;
table16[0xA3] = function(cpu) { { /* mov*/ cpu.safe_write16(cpu.read_moffs(), cpu.reg16[reg_ax]); } }; table32[0xA3] = function(cpu) { { cpu.safe_write32(cpu.read_moffs(), cpu.reg32s[reg_eax]); } };;
table16[0xA4] = table32[0xA4] = function(cpu) { { movsb(cpu); } };;
table16[0xA5] = function(cpu) { { movsw(cpu); } }; table32[0xA5] = function(cpu) { { movsd(cpu); } };;
table16[0xA6] = table32[0xA6] = function(cpu) { { cmpsb(cpu); } };;
table16[0xA7] = function(cpu) { { cmpsw(cpu); } }; table32[0xA7] = function(cpu) { { cmpsd(cpu); } };;
table16[0xA8] = table32[0xA8] = function(cpu) { { cpu.and(cpu.reg8[reg_al], cpu.read_imm8(), OPSIZE_8); } };;
table16[0xA9] = function(cpu) { { cpu.and(cpu.reg16[reg_ax], cpu.read_imm16(), OPSIZE_16); } }; table32[0xA9] = function(cpu) { { cpu.and(cpu.reg32s[reg_eax], cpu.read_imm32s(), OPSIZE_32); } };;
table16[0xAA] = table32[0xAA] = function(cpu) { { stosb(cpu); } };;
table16[0xAB] = function(cpu) { { stosw(cpu); } }; table32[0xAB] = function(cpu) { { stosd(cpu); } };;
table16[0xAC] = table32[0xAC] = function(cpu) { { lodsb(cpu); } };;
table16[0xAD] = function(cpu) { { lodsw(cpu); } }; table32[0xAD] = function(cpu) { { lodsd(cpu); } };;
table16[0xAE] = table32[0xAE] = function(cpu) { { scasb(cpu); } };;
table16[0xAF] = function(cpu) { { scasw(cpu); } }; table32[0xAF] = function(cpu) { { scasd(cpu); } };;
table16[0xB0] = table32[0xB0] = function(cpu) { { cpu.reg8[reg_al] = cpu.read_imm8(); } };
table16[0xB1] = table32[0xB1] = function(cpu) { { cpu.reg8[reg_cl] = cpu.read_imm8(); } };
table16[0xB2] = table32[0xB2] = function(cpu) { { cpu.reg8[reg_dl] = cpu.read_imm8(); } };
table16[0xB3] = table32[0xB3] = function(cpu) { { cpu.reg8[reg_bl] = cpu.read_imm8(); } };
table16[0xB4] = table32[0xB4] = function(cpu) { { cpu.reg8[reg_ah] = cpu.read_imm8(); } };
table16[0xB5] = table32[0xB5] = function(cpu) { { cpu.reg8[reg_ch] = cpu.read_imm8(); } };
table16[0xB6] = table32[0xB6] = function(cpu) { { cpu.reg8[reg_dh] = cpu.read_imm8(); } };
table16[0xB7] = table32[0xB7] = function(cpu) { { cpu.reg8[reg_bh] = cpu.read_imm8(); } };
table16[0xB8] = function(cpu) { { cpu.reg16[reg_ax] = cpu.read_imm16(); } }; table32[0xB8] = function(cpu) { { cpu.reg32s[reg_eax] = cpu.read_imm32s(); } };;
table16[0xB9] = function(cpu) { { cpu.reg16[reg_cx] = cpu.read_imm16(); } }; table32[0xB9] = function(cpu) { { cpu.reg32s[reg_ecx] = cpu.read_imm32s(); } };;
table16[0xBA] = function(cpu) { { cpu.reg16[reg_dx] = cpu.read_imm16(); } }; table32[0xBA] = function(cpu) { { cpu.reg32s[reg_edx] = cpu.read_imm32s(); } };;
table16[0xBB] = function(cpu) { { cpu.reg16[reg_bx] = cpu.read_imm16(); } }; table32[0xBB] = function(cpu) { { cpu.reg32s[reg_ebx] = cpu.read_imm32s(); } };;
table16[0xBC] = function(cpu) { { cpu.reg16[reg_sp] = cpu.read_imm16(); } }; table32[0xBC] = function(cpu) { { cpu.reg32s[reg_esp] = cpu.read_imm32s(); } };;
table16[0xBD] = function(cpu) { { cpu.reg16[reg_bp] = cpu.read_imm16(); } }; table32[0xBD] = function(cpu) { { cpu.reg32s[reg_ebp] = cpu.read_imm32s(); } };;
table16[0xBE] = function(cpu) { { cpu.reg16[reg_si] = cpu.read_imm16(); } }; table32[0xBE] = function(cpu) { { cpu.reg32s[reg_esi] = cpu.read_imm32s(); } };;
table16[0xBF] = function(cpu) { { cpu.reg16[reg_di] = cpu.read_imm16(); } }; table32[0xBF] = function(cpu) { { cpu.reg32s[reg_edi] = cpu.read_imm32s(); } };;
table16[0xC0] = table32[0xC0] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data2; var data; var addr; var result; if(cpu.modrm_byte < 0xC0) { addr = cpu.translate_address_write(cpu.modrm_resolve(cpu.modrm_byte)); data = cpu.memory.read8(addr); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; } result = 0; data2 = cpu.read_imm8() & 31; switch(cpu.modrm_byte >> 3 & 7) { case 0: result = cpu.rol8(data, data2); break; case 1: result = cpu.ror8(data, data2); break; case 2: result = cpu.rcl8(data, data2); break; case 3: result = cpu.rcr8(data, data2); break; case 4: result = cpu.shl8(data, data2); break; case 5: result = cpu.shr8(data, data2); break; case 6: result = cpu.shl8(data, data2); break; case 7: result = cpu.sar8(data, data2); break; }; if(cpu.modrm_byte < 0xC0) { cpu.memory.write8(addr, result); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = result; } } };;
table16[0xC1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data2; var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = cpu.translate_address_write(virt_addr + 1); data = cpu.virt_boundary_read16(phys_addr, phys_addr_high); } else { data = cpu.memory.read16(phys_addr); } } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; } result = 0; data2 = cpu.read_imm8() & 31; switch(cpu.modrm_byte >> 3 & 7) { case 0: result = cpu.rol16(data, data2); break; case 1: result = cpu.ror16(data, data2); break; case 2: result = cpu.rcl16(data, data2); break; case 3: result = cpu.rcr16(data, data2); break; case 4: result = cpu.shl16(data, data2); break; case 5: result = cpu.shr16(data, data2); break; case 6: result = cpu.shl16(data, data2); break; case 7: result = cpu.sar16(data, data2); break; }; if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write16(phys_addr, phys_addr_high, result); } else { cpu.memory.write16(phys_addr, result); } } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = result; } } }; table32[0xC1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data2; var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = cpu.translate_address_write(virt_addr + 3); data = cpu.virt_boundary_read32s(phys_addr, phys_addr_high); } else { data = cpu.memory.read32s(phys_addr); } } else { data = cpu.reg32s[cpu.modrm_byte & 7]; } result = 0; data2 = cpu.read_imm8() & 31; switch(cpu.modrm_byte >> 3 & 7) { case 0: result = cpu.rol32(data, data2); break; case 1: result = cpu.ror32(data, data2); break; case 2: result = cpu.rcl32(data, data2); break; case 3: result = cpu.rcr32(data, data2); break; case 4: result = cpu.shl32(data, data2); break; case 5: result = cpu.shr32(data, data2); break; case 6: result = cpu.shl32(data, data2); break; case 7: result = cpu.sar32(data, data2); break; }; if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write32(phys_addr, phys_addr_high, result); } else { cpu.memory.write32(phys_addr, result); } } else { cpu.reg32s[cpu.modrm_byte & 7] = result; } } };;
table16[0xC2] = function(cpu) { { /* retn*/ var imm16 = cpu.read_imm16(); cpu.instruction_pointer = cpu.get_seg(reg_cs) + cpu.pop16() | 0; cpu.stack_reg[cpu.reg_vsp] += imm16; } }; table32[0xC2] = function(cpu) { { /* retn*/ var imm16 = cpu.read_imm16(); cpu.instruction_pointer = cpu.get_seg(reg_cs) + cpu.pop32s() | 0; cpu.stack_reg[cpu.reg_vsp] += imm16; } };;
table16[0xC3] = function(cpu) { { /* retn*/ cpu.instruction_pointer = cpu.get_seg(reg_cs) + cpu.pop16() | 0; } }; table32[0xC3] = function(cpu) { { /* retn*/ cpu.instruction_pointer = cpu.get_seg(reg_cs) + cpu.pop32s() | 0; } };;
table16[0xC4] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte >= 0xC0) { cpu.trigger_ud(); } cpu.lss16(reg_es, cpu.modrm_resolve(cpu.modrm_byte), cpu.modrm_byte >> 2 & 14);; } }; table32[0xC4] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte >= 0xC0) { cpu.trigger_ud(); } cpu.lss32(reg_es, cpu.modrm_resolve(cpu.modrm_byte), cpu.modrm_byte >> 3 & 7);; } };;
table16[0xC5] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte >= 0xC0) { cpu.trigger_ud(); } cpu.lss16(reg_ds, cpu.modrm_resolve(cpu.modrm_byte), cpu.modrm_byte >> 2 & 14);; } }; table32[0xC5] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte >= 0xC0) { cpu.trigger_ud(); } cpu.lss32(reg_ds, cpu.modrm_resolve(cpu.modrm_byte), cpu.modrm_byte >> 3 & 7);; } };;
table16[0xC6] = table32[0xC6] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = cpu.read_imm8(); if(cpu.modrm_byte < 0xC0) { cpu.safe_write8(addr, data); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = data; }; } };
table16[0xC7] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = cpu.read_imm16(); if(cpu.modrm_byte < 0xC0) { cpu.safe_write16(addr, data); } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = data; }; } }; table32[0xC7] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = cpu.read_imm32s(); if(cpu.modrm_byte < 0xC0) { cpu.safe_write32(addr, data); } else { cpu.reg32[cpu.modrm_byte & 7] = data; }; } };
table16[0xC8] = function(cpu) { { cpu.enter16(cpu.read_imm16(), cpu.read_imm8()); } }; table32[0xC8] = function(cpu) { { cpu.enter32(cpu.read_imm16(), cpu.read_imm8()); } };;
table16[0xC9] = function(cpu) { { /* leave*/ var new_bp = cpu.safe_read16(cpu.get_seg(reg_ss) + cpu.stack_reg[cpu.reg_vbp] | 0); cpu.stack_reg[cpu.reg_vsp] = cpu.stack_reg[cpu.reg_vbp] + 2 | 0; cpu.reg16[reg_bp] = new_bp; } }; table32[0xC9] = function(cpu) { { var new_ebp = cpu.safe_read32s(cpu.get_seg(reg_ss) + cpu.stack_reg[cpu.reg_vbp] | 0); cpu.stack_reg[cpu.reg_vsp] = cpu.stack_reg[cpu.reg_vbp] + 4 | 0; cpu.reg32s[reg_ebp] = new_ebp; } };;
table16[0xCA] = function(cpu) { { /* retf*/ cpu.translate_address_read(cpu.get_seg(reg_ss) + cpu.stack_reg[cpu.reg_vsp] + 4); var imm16 = cpu.read_imm16(); var ip = cpu.pop16(); cpu.switch_seg(reg_cs, cpu.pop16()); cpu.instruction_pointer = cpu.get_seg(reg_cs) + ip | 0; cpu.stack_reg[cpu.reg_vsp] += imm16; } }; table32[0xCA] = function(cpu) { { /* retf */ cpu.translate_address_read(cpu.get_seg(reg_ss) + cpu.stack_reg[cpu.reg_vsp] + 8); var imm16 = cpu.read_imm16(); var ip = cpu.pop32s(); cpu.switch_seg(reg_cs, cpu.pop32s() & 0xFFFF); cpu.instruction_pointer = cpu.get_seg(reg_cs) + ip | 0; cpu.stack_reg[cpu.reg_vsp] += imm16; } };;
table16[0xCB] = function(cpu) { { /* retf*/ cpu.translate_address_read(cpu.get_seg(reg_ss) + cpu.stack_reg[cpu.reg_vsp] + 4); var ip = cpu.pop16(); cpu.switch_seg(reg_cs, cpu.pop16()); cpu.instruction_pointer = cpu.get_seg(reg_cs) + ip | 0; } }; table32[0xCB] = function(cpu) { { /* retf */ cpu.translate_address_read(cpu.get_seg(reg_ss) + cpu.stack_reg[cpu.reg_vsp] + 8); var ip = cpu.pop32s(); cpu.switch_seg(reg_cs, cpu.pop32s() & 0xFFFF); cpu.instruction_pointer = cpu.get_seg(reg_cs) + ip | 0; } };;
table16[0xCC] = table32[0xCC] = function(cpu) { { /* INT3*/ cpu.call_interrupt_vector(3, true, false); } };;
table16[0xCD] = table32[0xCD] = function(cpu) { { /* INT */ var imm8 = cpu.read_imm8(); cpu.call_interrupt_vector(imm8, true, false); } };;
table16[0xCE] = table32[0xCE] = function(cpu) { { /* INTO*/ if(cpu.getof()) { cpu.call_interrupt_vector(4, true, false); } } };;
table16[0xCF] = function(cpu) { { /* iret*/ cpu.iret16(); } }; table32[0xCF] = function(cpu) { { cpu.iret32(); } };;
table16[0xD0] = table32[0xD0] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data2; var data; var addr; var result; if(cpu.modrm_byte < 0xC0) { addr = cpu.translate_address_write(cpu.modrm_resolve(cpu.modrm_byte)); data = cpu.memory.read8(addr); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; } result = 0; data2 = 1; switch(cpu.modrm_byte >> 3 & 7) { case 0: result = cpu.rol8(data, data2); break; case 1: result = cpu.ror8(data, data2); break; case 2: result = cpu.rcl8(data, data2); break; case 3: result = cpu.rcr8(data, data2); break; case 4: result = cpu.shl8(data, data2); break; case 5: result = cpu.shr8(data, data2); break; case 6: result = cpu.shl8(data, data2); break; case 7: result = cpu.sar8(data, data2); break; }; if(cpu.modrm_byte < 0xC0) { cpu.memory.write8(addr, result); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = result; } } };;
table16[0xD1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data2; var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = cpu.translate_address_write(virt_addr + 1); data = cpu.virt_boundary_read16(phys_addr, phys_addr_high); } else { data = cpu.memory.read16(phys_addr); } } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; } result = 0; data2 = 1; switch(cpu.modrm_byte >> 3 & 7) { case 0: result = cpu.rol16(data, data2); break; case 1: result = cpu.ror16(data, data2); break; case 2: result = cpu.rcl16(data, data2); break; case 3: result = cpu.rcr16(data, data2); break; case 4: result = cpu.shl16(data, data2); break; case 5: result = cpu.shr16(data, data2); break; case 6: result = cpu.shl16(data, data2); break; case 7: result = cpu.sar16(data, data2); break; }; if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write16(phys_addr, phys_addr_high, result); } else { cpu.memory.write16(phys_addr, result); } } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = result; } } }; table32[0xD1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data2; var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = cpu.translate_address_write(virt_addr + 3); data = cpu.virt_boundary_read32s(phys_addr, phys_addr_high); } else { data = cpu.memory.read32s(phys_addr); } } else { data = cpu.reg32s[cpu.modrm_byte & 7]; } result = 0; data2 = 1; switch(cpu.modrm_byte >> 3 & 7) { case 0: result = cpu.rol32(data, data2); break; case 1: result = cpu.ror32(data, data2); break; case 2: result = cpu.rcl32(data, data2); break; case 3: result = cpu.rcr32(data, data2); break; case 4: result = cpu.shl32(data, data2); break; case 5: result = cpu.shr32(data, data2); break; case 6: result = cpu.shl32(data, data2); break; case 7: result = cpu.sar32(data, data2); break; }; if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write32(phys_addr, phys_addr_high, result); } else { cpu.memory.write32(phys_addr, result); } } else { cpu.reg32s[cpu.modrm_byte & 7] = result; } } };;
table16[0xD2] = table32[0xD2] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data2; var data; var addr; var result; if(cpu.modrm_byte < 0xC0) { addr = cpu.translate_address_write(cpu.modrm_resolve(cpu.modrm_byte)); data = cpu.memory.read8(addr); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; } result = 0; data2 = cpu.reg8[reg_cl] & 31; switch(cpu.modrm_byte >> 3 & 7) { case 0: result = cpu.rol8(data, data2); break; case 1: result = cpu.ror8(data, data2); break; case 2: result = cpu.rcl8(data, data2); break; case 3: result = cpu.rcr8(data, data2); break; case 4: result = cpu.shl8(data, data2); break; case 5: result = cpu.shr8(data, data2); break; case 6: result = cpu.shl8(data, data2); break; case 7: result = cpu.sar8(data, data2); break; }; if(cpu.modrm_byte < 0xC0) { cpu.memory.write8(addr, result); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = result; } } };;
table16[0xD3] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data2; var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = cpu.translate_address_write(virt_addr + 1); data = cpu.virt_boundary_read16(phys_addr, phys_addr_high); } else { data = cpu.memory.read16(phys_addr); } } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; } result = 0; data2 = cpu.reg8[reg_cl] & 31; switch(cpu.modrm_byte >> 3 & 7) { case 0: result = cpu.rol16(data, data2); break; case 1: result = cpu.ror16(data, data2); break; case 2: result = cpu.rcl16(data, data2); break; case 3: result = cpu.rcr16(data, data2); break; case 4: result = cpu.shl16(data, data2); break; case 5: result = cpu.shr16(data, data2); break; case 6: result = cpu.shl16(data, data2); break; case 7: result = cpu.sar16(data, data2); break; }; if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write16(phys_addr, phys_addr_high, result); } else { cpu.memory.write16(phys_addr, result); } } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = result; } } }; table32[0xD3] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data2; var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = cpu.translate_address_write(virt_addr + 3); data = cpu.virt_boundary_read32s(phys_addr, phys_addr_high); } else { data = cpu.memory.read32s(phys_addr); } } else { data = cpu.reg32s[cpu.modrm_byte & 7]; } result = 0; data2 = cpu.reg8[reg_cl] & 31; switch(cpu.modrm_byte >> 3 & 7) { case 0: result = cpu.rol32(data, data2); break; case 1: result = cpu.ror32(data, data2); break; case 2: result = cpu.rcl32(data, data2); break; case 3: result = cpu.rcr32(data, data2); break; case 4: result = cpu.shl32(data, data2); break; case 5: result = cpu.shr32(data, data2); break; case 6: result = cpu.shl32(data, data2); break; case 7: result = cpu.sar32(data, data2); break; }; if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write32(phys_addr, phys_addr_high, result); } else { cpu.memory.write32(phys_addr, result); } } else { cpu.reg32s[cpu.modrm_byte & 7] = result; } } };;
table16[0xD4] = table32[0xD4] = function(cpu) { { cpu.bcd_aam(cpu.read_imm8()); } };;
table16[0xD5] = table32[0xD5] = function(cpu) { { cpu.bcd_aad(cpu.read_imm8()); } };;
table16[0xD6] = table32[0xD6] = function(cpu) { { /* salc*/ cpu.reg8[reg_al] = -cpu.getcf(); } };;
table16[0xD7] = table32[0xD7] = function(cpu) { { /* xlat*/ if(cpu.address_size_32) { cpu.reg8[reg_al] = cpu.safe_read8(cpu.get_seg_prefix(reg_ds) + cpu.reg32s[reg_ebx] + cpu.reg8[reg_al]); } else { cpu.reg8[reg_al] = cpu.safe_read8(cpu.get_seg_prefix(reg_ds) + cpu.reg16[reg_bx] + cpu.reg8[reg_al]); } } };;
// fpu instructions
table16[0xD8] = table32[0xD8] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.cr[0] & (CR0_EM | CR0_TS)) cpu.trigger_nm(); if(cpu.modrm_byte < 0xC0) cpu.fpu.op_D8_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); else cpu.fpu.op_D8_reg(cpu.modrm_byte); } };;
table16[0xD9] = table32[0xD9] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.cr[0] & (CR0_EM | CR0_TS)) cpu.trigger_nm(); if(cpu.modrm_byte < 0xC0) cpu.fpu.op_D9_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); else cpu.fpu.op_D9_reg(cpu.modrm_byte); } };;
table16[0xDA] = table32[0xDA] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.cr[0] & (CR0_EM | CR0_TS)) cpu.trigger_nm(); if(cpu.modrm_byte < 0xC0) cpu.fpu.op_DA_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); else cpu.fpu.op_DA_reg(cpu.modrm_byte); } };;
table16[0xDB] = table32[0xDB] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.cr[0] & (CR0_EM | CR0_TS)) cpu.trigger_nm(); if(cpu.modrm_byte < 0xC0) cpu.fpu.op_DB_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); else cpu.fpu.op_DB_reg(cpu.modrm_byte); } };;
table16[0xDC] = table32[0xDC] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.cr[0] & (CR0_EM | CR0_TS)) cpu.trigger_nm(); if(cpu.modrm_byte < 0xC0) cpu.fpu.op_DC_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); else cpu.fpu.op_DC_reg(cpu.modrm_byte); } };;
table16[0xDD] = table32[0xDD] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.cr[0] & (CR0_EM | CR0_TS)) cpu.trigger_nm(); if(cpu.modrm_byte < 0xC0) cpu.fpu.op_DD_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); else cpu.fpu.op_DD_reg(cpu.modrm_byte); } };;
table16[0xDE] = table32[0xDE] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.cr[0] & (CR0_EM | CR0_TS)) cpu.trigger_nm(); if(cpu.modrm_byte < 0xC0) cpu.fpu.op_DE_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); else cpu.fpu.op_DE_reg(cpu.modrm_byte); } };;
table16[0xDF] = table32[0xDF] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.cr[0] & (CR0_EM | CR0_TS)) cpu.trigger_nm(); if(cpu.modrm_byte < 0xC0) cpu.fpu.op_DF_mem(cpu.modrm_byte, cpu.modrm_resolve(cpu.modrm_byte)); else cpu.fpu.op_DF_reg(cpu.modrm_byte); } };;
table16[0xE0] = table32[0xE0] = function(cpu) { { cpu.loopne(cpu.read_imm8s()); } };;
table16[0xE1] = table32[0xE1] = function(cpu) { { cpu.loope(cpu.read_imm8s()); } };;
table16[0xE2] = table32[0xE2] = function(cpu) { { cpu.loop(cpu.read_imm8s()); } };;
table16[0xE3] = table32[0xE3] = function(cpu) { { cpu.jcxz(cpu.read_imm8s()); } };;
table16[0xE4] = table32[0xE4] = function(cpu) { { var port = cpu.read_imm8(); cpu.test_privileges_for_io(port, 1); cpu.reg8[reg_al] = cpu.io.port_read8(port); } };;
table16[0xE5] = function(cpu) { { var port = cpu.read_imm8(); cpu.test_privileges_for_io(port, 2); cpu.reg16[reg_ax] = cpu.io.port_read16(port); } }; table32[0xE5] = function(cpu) { { var port = cpu.read_imm8(); cpu.test_privileges_for_io(port, 4); cpu.reg32s[reg_eax] = cpu.io.port_read32(port); } };;
table16[0xE6] = table32[0xE6] = function(cpu) { { var port = cpu.read_imm8(); cpu.test_privileges_for_io(port, 1); cpu.io.port_write8(port, cpu.reg8[reg_al]); } };;
table16[0xE7] = function(cpu) { { var port = cpu.read_imm8(); cpu.test_privileges_for_io(port, 2); cpu.io.port_write16(port, cpu.reg16[reg_ax]); } }; table32[0xE7] = function(cpu) { { var port = cpu.read_imm8(); cpu.test_privileges_for_io(port, 4); cpu.io.port_write32(port, cpu.reg32s[reg_eax]); } };;
table16[0xE8] = function(cpu) { { /* call*/ var imm16s = cpu.read_imm16s(); cpu.push16(cpu.get_real_eip()); cpu.jmp_rel16(imm16s); } }; table32[0xE8] = function(cpu) { { /* call*/ var imm32s = cpu.read_imm32s(); cpu.push32(cpu.get_real_eip()); cpu.instruction_pointer = cpu.instruction_pointer + imm32s | 0; } };;
table16[0xE9] = function(cpu) { { /* jmp*/ var imm16s = cpu.read_imm16s(); cpu.jmp_rel16(imm16s); } }; table32[0xE9] = function(cpu) { { /* jmp*/ var imm32s = cpu.read_imm32s(); cpu.instruction_pointer = cpu.instruction_pointer + imm32s | 0; } };;
table16[0xEA] = function(cpu) { { /* jmpf*/ var ip = cpu.read_imm16(); cpu.switch_seg(reg_cs, cpu.read_imm16()); cpu.instruction_pointer = ip + cpu.get_seg(reg_cs) | 0; } }; table32[0xEA] = function(cpu) { { /* jmpf*/ var ip = cpu.read_imm32s(); cpu.switch_seg(reg_cs, cpu.read_imm16()); cpu.instruction_pointer = ip + cpu.get_seg(reg_cs) | 0; } };;
table16[0xEB] = table32[0xEB] = function(cpu) { { /* jmp near*/ var imm8 = cpu.read_imm8s(); cpu.instruction_pointer = cpu.instruction_pointer + imm8 | 0; } };;
table16[0xEC] = table32[0xEC] = function(cpu) { { var port = cpu.reg16[reg_dx]; cpu.test_privileges_for_io(port, 1); cpu.reg8[reg_al] = cpu.io.port_read8(port); } };;
table16[0xED] = function(cpu) { { var port = cpu.reg16[reg_dx]; cpu.test_privileges_for_io(port, 2); cpu.reg16[reg_ax] = cpu.io.port_read16(port); } }; table32[0xED] = function(cpu) { { var port = cpu.reg16[reg_dx]; cpu.test_privileges_for_io(port, 4); cpu.reg32s[reg_eax] = cpu.io.port_read32(port); } };;
table16[0xEE] = table32[0xEE] = function(cpu) { { var port = cpu.reg16[reg_dx]; cpu.test_privileges_for_io(port, 1); cpu.io.port_write8(port, cpu.reg8[reg_al]); } };;
table16[0xEF] = function(cpu) { { var port = cpu.reg16[reg_dx]; cpu.test_privileges_for_io(port, 2); cpu.io.port_write16(port, cpu.reg16[reg_ax]); } }; table32[0xEF] = function(cpu) { { var port = cpu.reg16[reg_dx]; cpu.test_privileges_for_io(port, 4); cpu.io.port_write32(port, cpu.reg32s[reg_eax]); } };;
table16[0xF0] = table32[0xF0] = function(cpu) { { /* lock*/ /* TODO*/ /* This triggers UD when used with*/ /* some instructions that don't write to memory*/ cpu.do_op(); } };;
table16[0xF1] = table32[0xF1] = function(cpu) { { /* INT1*/ /* https://code.google.com/p/corkami/wiki/x86oddities#IceBP*/ throw cpu.debug.unimpl("int1 instruction"); } };;
table16[0xF2] = table32[0xF2] = function(cpu) { { /* repnz*/ dbg_assert(cpu.repeat_string_prefix === REPEAT_STRING_PREFIX_NONE); cpu.repeat_string_prefix = REPEAT_STRING_PREFIX_NZ; cpu.do_op(); cpu.repeat_string_prefix = REPEAT_STRING_PREFIX_NONE; } };;
table16[0xF3] = table32[0xF3] = function(cpu) { { /* repz*/ dbg_assert(cpu.repeat_string_prefix === REPEAT_STRING_PREFIX_NONE); cpu.repeat_string_prefix = REPEAT_STRING_PREFIX_Z; cpu.do_op(); cpu.repeat_string_prefix = REPEAT_STRING_PREFIX_NONE; } };;
table16[0xF4] = table32[0xF4] = function(cpu) { { cpu.hlt_op(); } };;
table16[0xF5] = table32[0xF5] = function(cpu) { { /* cmc*/ cpu.flags = (cpu.flags | 1) ^ cpu.getcf(); cpu.flags_changed &= ~1; } };;
table16[0xF6] = table32[0xF6] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { switch(cpu.modrm_byte >> 3 & 7) { case 0: { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read8(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; }; cpu.and(data, cpu.read_imm8(), OPSIZE_8); }; break; case 1: { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read8(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; }; cpu.and(data, cpu.read_imm8(), OPSIZE_8); }; break; case 2: { var data; var addr; var result; if(cpu.modrm_byte < 0xC0) { addr = cpu.translate_address_write(cpu.modrm_resolve(cpu.modrm_byte)); data = cpu.memory.read8(addr); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; } result = ~(data); if(cpu.modrm_byte < 0xC0) { cpu.memory.write8(addr, result); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = result; }; }; break; case 3: { var data; var addr; var result; if(cpu.modrm_byte < 0xC0) { addr = cpu.translate_address_write(cpu.modrm_resolve(cpu.modrm_byte)); data = cpu.memory.read8(addr); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; } result = cpu.neg(data, OPSIZE_8); if(cpu.modrm_byte < 0xC0) { cpu.memory.write8(addr, result); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = result; }; }; break; case 4: { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read8(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; }; cpu.mul8(data); }; break; case 5: { if(cpu.modrm_byte < 0xC0) { var data = (cpu.safe_read8(cpu.modrm_resolve(cpu.modrm_byte)) << 24 >> 24); } else { data = cpu.reg8s[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; }; cpu.imul8(data); }; break; case 6: { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read8(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; }; cpu.div8(data); }; break; case 7: { if(cpu.modrm_byte < 0xC0) { var data = (cpu.safe_read8(cpu.modrm_resolve(cpu.modrm_byte)) << 24 >> 24); } else { data = cpu.reg8s[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; }; cpu.idiv8(data); }; break; } } };;
table16[0xF7] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { switch(cpu.modrm_byte >> 3 & 7) { case 0: { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.and(data, cpu.read_imm16(), OPSIZE_16); }; break; case 1: { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.and(data, cpu.read_imm16(), OPSIZE_16); }; break; case 2: { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = cpu.translate_address_write(virt_addr + 1); data = cpu.virt_boundary_read16(phys_addr, phys_addr_high); } else { data = cpu.memory.read16(phys_addr); } } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; } result = ~(data); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write16(phys_addr, phys_addr_high, result); } else { cpu.memory.write16(phys_addr, result); } } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = result; }; }; break; case 3: { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = cpu.translate_address_write(virt_addr + 1); data = cpu.virt_boundary_read16(phys_addr, phys_addr_high); } else { data = cpu.memory.read16(phys_addr); } } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; } result = cpu.neg(data, OPSIZE_16); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write16(phys_addr, phys_addr_high, result); } else { cpu.memory.write16(phys_addr, result); } } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = result; }; }; break; case 4: { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.mul16(data); }; break; case 5: { if(cpu.modrm_byte < 0xC0) { var data = (cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)) << 16 >> 16); } else { data = cpu.reg16s[cpu.modrm_byte << 1 & 14]; }; cpu.imul16(data); }; break; case 6: { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.div16(data); }; break; case 7: { if(cpu.modrm_byte < 0xC0) { var data = (cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)) << 16 >> 16); } else { data = cpu.reg16s[cpu.modrm_byte << 1 & 14]; }; cpu.idiv16(data); }; break; } } }; table32[0xF7] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { switch(cpu.modrm_byte >> 3 & 7) { case 0: { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.and(data, cpu.read_imm32s(), OPSIZE_32); }; break; case 1: { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.and(data, cpu.read_imm32s(), OPSIZE_32); }; break; case 2: { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = cpu.translate_address_write(virt_addr + 3); data = cpu.virt_boundary_read32s(phys_addr, phys_addr_high); } else { data = cpu.memory.read32s(phys_addr); } } else { data = cpu.reg32s[cpu.modrm_byte & 7]; } result = ~(data); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write32(phys_addr, phys_addr_high, result); } else { cpu.memory.write32(phys_addr, result); } } else { cpu.reg32s[cpu.modrm_byte & 7] = result; }; }; break; case 3: { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = cpu.translate_address_write(virt_addr + 3); data = cpu.virt_boundary_read32s(phys_addr, phys_addr_high); } else { data = cpu.memory.read32s(phys_addr); } } else { data = cpu.reg32s[cpu.modrm_byte & 7]; } result = cpu.neg(data, OPSIZE_32); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write32(phys_addr, phys_addr_high, result); } else { cpu.memory.write32(phys_addr, result); } } else { cpu.reg32s[cpu.modrm_byte & 7] = result; }; }; break; case 4: { if(cpu.modrm_byte < 0xC0) { var data = (cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)) >>> 0); } else { data = cpu.reg32[cpu.modrm_byte & 7]; }; cpu.mul32(data); }; break; case 5: { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.imul32(data); }; break; case 6: { if(cpu.modrm_byte < 0xC0) { var data = (cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)) >>> 0); } else { data = cpu.reg32[cpu.modrm_byte & 7]; }; cpu.div32(data); }; break; case 7: { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.idiv32(data); }; break; } } };;
table16[0xF8] = table32[0xF8] = function(cpu) { { /* clc*/ cpu.flags &= ~flag_carry; cpu.flags_changed &= ~1; } };;
table16[0xF9] = table32[0xF9] = function(cpu) { { /* stc*/ cpu.flags |= flag_carry; cpu.flags_changed &= ~1; } };;
table16[0xFA] = table32[0xFA] = function(cpu) { { /* cli*/ /*dbg_log("interrupts off");*/ if(!cpu.protected_mode || ((cpu.flags & flag_vm) ? cpu.getiopl() === 3 : cpu.getiopl() >= cpu.cpl)) { cpu.flags &= ~flag_interrupt; } else { /*if(cpu.getiopl() < 3 && ((cpu.flags & flag_vm) ? */ /* (cpu.cr[4] & CR4_VME) :*/ /* (cpu.cpl === 3 && (cpu.cr[4] & CR4_PVI))))*/ /*{*/ /* cpu.flags &= ~flag_vif;*/ /*}*/ /*else*/ { cpu.trigger_gp(0); } } } };;
table16[0xFB] = table32[0xFB] = function(cpu) { { /* sti*/ /*dbg_log("interrupts on");*/ if(!cpu.protected_mode || ((cpu.flags & flag_vm) ? cpu.getiopl() === 3 : cpu.getiopl() >= cpu.cpl)) { cpu.flags |= flag_interrupt; cpu.clear_prefixes(); cpu.cycle(); cpu.handle_irqs(); } else { /*if(cpu.getiopl() < 3 && (cpu.flags & flag_vip) === 0 && ((cpu.flags & flag_vm) ? */ /* (cpu.cr[4] & CR4_VME) :*/ /* (cpu.cpl === 3 && (cpu.cr[4] & CR4_PVI))))*/ /*{*/ /* cpu.flags |= flag_vif;*/ /*}*/ /*else*/ { cpu.trigger_gp(0); } } } };;
table16[0xFC] = table32[0xFC] = function(cpu) { { /* cld*/ cpu.flags &= ~flag_direction; } };;
table16[0xFD] = table32[0xFD] = function(cpu) { { /* std*/ cpu.flags |= flag_direction; } };;
table16[0xFE] = table32[0xFE] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var mod = cpu.modrm_byte & 56; if(mod === 0) { var data; var addr; var result; if(cpu.modrm_byte < 0xC0) { addr = cpu.translate_address_write(cpu.modrm_resolve(cpu.modrm_byte)); data = cpu.memory.read8(addr); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; } result = cpu.inc(data, OPSIZE_8); if(cpu.modrm_byte < 0xC0) { cpu.memory.write8(addr, result); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = result; }; } else if(mod === 8) { var data; var addr; var result; if(cpu.modrm_byte < 0xC0) { addr = cpu.translate_address_write(cpu.modrm_resolve(cpu.modrm_byte)); data = cpu.memory.read8(addr); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; } result = cpu.dec(data, OPSIZE_8); if(cpu.modrm_byte < 0xC0) { cpu.memory.write8(addr, result); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = result; }; } else { if(DEBUG) { dbg_trace(); throw "TODO"; } cpu.trigger_ud();; } } };;
table16[0xFF] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { switch(cpu.modrm_byte >> 3 & 7) { case 0: { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = cpu.translate_address_write(virt_addr + 1); data = cpu.virt_boundary_read16(phys_addr, phys_addr_high); } else { data = cpu.memory.read16(phys_addr); } } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; } result = cpu.inc(data, OPSIZE_16); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write16(phys_addr, phys_addr_high, result); } else { cpu.memory.write16(phys_addr, result); } } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = result; }; }; break; case 1: { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = cpu.translate_address_write(virt_addr + 1); data = cpu.virt_boundary_read16(phys_addr, phys_addr_high); } else { data = cpu.memory.read16(phys_addr); } } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; } result = cpu.dec(data, OPSIZE_16); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write16(phys_addr, phys_addr_high, result); } else { cpu.memory.write16(phys_addr, result); } } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = result; }; }; break; case 2: { /* 2, call near*/ if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.push16(cpu.get_real_eip()); cpu.instruction_pointer = cpu.get_seg(reg_cs) + data | 0; }; break; case 3: { /* 3, callf*/ if(cpu.modrm_byte >= 0xC0) { cpu.trigger_ud(); dbg_assert(false, "unreachable"); } var virt_addr = cpu.modrm_resolve(cpu.modrm_byte); var new_cs = cpu.safe_read16(virt_addr + 2); var new_ip = cpu.safe_read16(virt_addr); cpu.writable_or_pagefault(cpu.get_stack_pointer(-4), 4); cpu.push16(cpu.sreg[reg_cs]); cpu.push16(cpu.get_real_eip()); cpu.switch_seg(reg_cs, new_cs); cpu.instruction_pointer = cpu.get_seg(reg_cs) + new_ip | 0; }; break; case 4: { /* 4, jmp near*/ if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.instruction_pointer = cpu.get_seg(reg_cs) + data | 0; }; break; case 5: { /* 5, jmpf*/ if(cpu.modrm_byte >= 0xC0) { cpu.trigger_ud(); dbg_assert(false, "unreachable"); } var virt_addr = cpu.modrm_resolve(cpu.modrm_byte); var new_cs = cpu.safe_read16(virt_addr + 2); var new_ip = cpu.safe_read16(virt_addr); cpu.switch_seg(reg_cs, new_cs); cpu.instruction_pointer = cpu.get_seg(reg_cs) + new_ip | 0; }; break; case 6: { /* 6, push*/ if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.push16(data); }; break; case 7: { if(DEBUG) { dbg_trace(); throw "TODO"; } cpu.trigger_ud();; }; break; } } }; table32[0xFF] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { switch(cpu.modrm_byte >> 3 & 7) { case 0: { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = cpu.translate_address_write(virt_addr + 3); data = cpu.virt_boundary_read32s(phys_addr, phys_addr_high); } else { data = cpu.memory.read32s(phys_addr); } } else { data = cpu.reg32s[cpu.modrm_byte & 7]; } result = cpu.inc(data, OPSIZE_32); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write32(phys_addr, phys_addr_high, result); } else { cpu.memory.write32(phys_addr, result); } } else { cpu.reg32s[cpu.modrm_byte & 7] = result; }; }; break; case 1: { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = cpu.translate_address_write(virt_addr + 3); data = cpu.virt_boundary_read32s(phys_addr, phys_addr_high); } else { data = cpu.memory.read32s(phys_addr); } } else { data = cpu.reg32s[cpu.modrm_byte & 7]; } result = cpu.dec(data, OPSIZE_32); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write32(phys_addr, phys_addr_high, result); } else { cpu.memory.write32(phys_addr, result); } } else { cpu.reg32s[cpu.modrm_byte & 7] = result; }; }; break; case 2: { /* 2, call near*/ if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.push32(cpu.get_real_eip()); cpu.instruction_pointer = cpu.get_seg(reg_cs) + data | 0; }; break; case 3: { /* 3, callf*/ if(cpu.modrm_byte >= 0xC0) { cpu.trigger_ud(); dbg_assert(false, "unreachable"); } var virt_addr = cpu.modrm_resolve(cpu.modrm_byte); var new_cs = cpu.safe_read16(virt_addr + 4); var new_ip = cpu.safe_read32s(virt_addr); cpu.writable_or_pagefault(cpu.get_stack_pointer(-8), 8); cpu.push32(cpu.sreg[reg_cs]); cpu.push32(cpu.get_real_eip()); cpu.switch_seg(reg_cs, new_cs); cpu.instruction_pointer = cpu.get_seg(reg_cs) + new_ip | 0; }; break; case 4: { /* 4, jmp near*/ if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.instruction_pointer = cpu.get_seg(reg_cs) + data | 0; }; break; case 5: { /* 5, jmpf*/ if(cpu.modrm_byte >= 0xC0) { cpu.trigger_ud(); dbg_assert(false, "unreachable"); } var virt_addr = cpu.modrm_resolve(cpu.modrm_byte); var new_cs = cpu.safe_read16(virt_addr + 4); var new_ip = cpu.safe_read32s(virt_addr); cpu.switch_seg(reg_cs, new_cs); cpu.instruction_pointer = cpu.get_seg(reg_cs) + new_ip | 0; }; break; case 6: { /* push*/ if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.push32(data); }; break; case 7: { if(DEBUG) { dbg_trace(); throw "TODO"; } cpu.trigger_ud();; }; break; } } };;
// 0F ops start here
table0F_16[0x00] = table0F_32[0x00] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(!cpu.protected_mode || cpu.vm86_mode()) { /* No GP, UD is correct here*/ cpu.trigger_ud(); } if(cpu.cpl) { cpu.trigger_gp(0); } switch(cpu.modrm_byte >> 3 & 7) { case 0: /* sldt*/ if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = cpu.sreg[reg_ldtr]; if(cpu.modrm_byte < 0xC0) { cpu.safe_write16(addr, data); } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = data; }; if(cpu.modrm_byte >= 0xC0) { cpu.reg32s[cpu.modrm_byte & 7] &= 0xFFFF; } break; case 1: /* str*/ if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = cpu.sreg[reg_tr]; if(cpu.modrm_byte < 0xC0) { cpu.safe_write16(addr, data); } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = data; }; if(cpu.modrm_byte >= 0xC0) { cpu.reg32s[cpu.modrm_byte & 7] &= 0xFFFF; } break; case 2: /* lldt*/ if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.load_ldt(data); break; case 3: /* ltr*/ if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.load_tr(data); break; default: dbg_log(cpu.modrm_byte >> 3 & 7, LOG_CPU); if(DEBUG) { dbg_trace(); throw "TODO"; } cpu.trigger_ud();; } } };;
table0F_16[0x01] = table0F_32[0x01] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.cpl) { cpu.trigger_gp(0); } var mod = cpu.modrm_byte >> 3 & 7; if(mod === 4) { /* smsw*/ if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = cpu.cr[0]; if(cpu.modrm_byte < 0xC0) { cpu.safe_write16(addr, data); } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = data; }; return; } else if(mod === 6) { /* lmsw*/ if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; var old_cr0 = cpu.cr[0]; cpu.cr[0] = (cpu.cr[0] & ~0xF) | (data & 0xF); if(cpu.protected_mode) { /* lmsw cannot be used to switch back*/ cpu.cr[0] |= CR0_PE; } /*dbg_log("cr0=" + h(data >>> 0), LOG_CPU);*/ cpu.cr0_changed(old_cr0); return; } if(cpu.modrm_byte >= 0xC0) { /* only memory*/ cpu.trigger_ud(); } if((mod === 2 || mod === 3) && cpu.protected_mode) { /* override prefix, so cpu.modrm_resolve does not return the segment part*/ /* only lgdt and lidt and only in protected mode*/ cpu.segment_prefix = SEG_PREFIX_ZERO; } var addr = cpu.modrm_resolve(cpu.modrm_byte); cpu.segment_prefix = SEG_PREFIX_NONE; switch(mod) { case 0: /* sgdt*/ cpu.writable_or_pagefault(addr, 6); cpu.safe_write16(addr, cpu.gdtr_size); cpu.safe_write32(addr + 2, cpu.gdtr_offset); break; case 1: /* sidt*/ cpu.writable_or_pagefault(addr, 6); cpu.safe_write16(addr, cpu.idtr_size); cpu.safe_write32(addr + 2, cpu.idtr_offset); break; case 2: /* lgdt*/ var size = cpu.safe_read16(addr); var offset = cpu.safe_read32s(addr + 2); cpu.gdtr_size = size; cpu.gdtr_offset = offset; if(!cpu.operand_size_32) { cpu.gdtr_offset &= 0xFFFFFF; } /*dbg_log("gdt at " + h(cpu.gdtr_offset) + ", " + cpu.gdtr_size + " bytes", LOG_CPU);*/ /*dump_gdt_ldt();*/ break; case 3: /* lidt*/ var size = cpu.safe_read16(addr); var offset = cpu.safe_read32s(addr + 2); cpu.idtr_size = size; cpu.idtr_offset = offset; if(!cpu.operand_size_32) { cpu.idtr_offset &= 0xFFFFFF; } /*dbg_log("[" + h(cpu.instruction_pointer) + "] idt at " + */ /* h(idtr_offset) + ", " + cpu.idtr_size + " bytes " + h(addr), LOG_CPU);*/ break; case 7: /* flush translation lookaside buffer*/ cpu.invlpg(addr); break; default: dbg_log(mod); if(DEBUG) { dbg_trace(); throw "TODO"; } cpu.trigger_ud();; } } };;
table0F_16[0x02] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { /* lar*/ dbg_log("lar", LOG_CPU); if(!cpu.protected_mode || cpu.vm86_mode()) { cpu.trigger_ud(); } if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.reg16[cpu.modrm_byte >> 2 & 14] = cpu.lar(data, cpu.reg16[cpu.modrm_byte >> 2 & 14]); } }; table0F_32[0x02] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { dbg_log("lar", LOG_CPU); if(!cpu.protected_mode || cpu.vm86_mode()) { cpu.trigger_ud(); } if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.reg32s[cpu.modrm_byte >> 3 & 7] = cpu.lar(data, cpu.reg32s[cpu.modrm_byte >> 3 & 7]); } };;
table0F_16[0x03] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { /* lsl*/ dbg_log("lsl", LOG_CPU); if(!cpu.protected_mode || cpu.vm86_mode()) { cpu.trigger_ud(); } if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.reg16[cpu.modrm_byte >> 2 & 14] = cpu.lsl(data, cpu.reg16[cpu.modrm_byte >> 2 & 14]); } }; table0F_32[0x03] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { dbg_log("lsl", LOG_CPU); if(!cpu.protected_mode || cpu.vm86_mode()) { cpu.trigger_ud(); } if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.reg32s[cpu.modrm_byte >> 3 & 7] = cpu.lsl(data, cpu.reg32s[cpu.modrm_byte >> 3 & 7]); } };;
table0F_16[0x04] = table0F_32[0x04] = function(cpu) { { if(DEBUG) throw "Possible fault: undefined instruction"; cpu.trigger_ud();} };;
table0F_16[0x05] = table0F_32[0x05] = function(cpu) { { if(DEBUG) throw "Possible fault: undefined instruction"; cpu.trigger_ud();} };;
table0F_16[0x06] = table0F_32[0x06] = function(cpu) { { /* clts*/ if(cpu.cpl) { cpu.trigger_gp(0); } else { /*dbg_log("clts", LOG_CPU);*/ cpu.cr[0] &= ~CR0_TS; } } };;
table0F_16[0x07] = table0F_32[0x07] = function(cpu) { { if(DEBUG) throw "Possible fault: undefined instruction"; cpu.trigger_ud();} };;
table0F_16[0x08] = table0F_32[0x08] = function(cpu) { { /* invd*/ if(DEBUG) { dbg_trace(); throw "TODO"; } cpu.trigger_ud();; } };
table0F_16[0x09] = table0F_32[0x09] = function(cpu) { { if(cpu.cpl) { cpu.trigger_gp(0); } /* wbinvd*/ } };;
table0F_16[0x0A] = table0F_32[0x0A] = function(cpu) { { if(DEBUG) throw "Possible fault: undefined instruction"; cpu.trigger_ud();} };;
table0F_16[0x0B] = table0F_32[0x0B] = function(cpu) { { /* UD2*/ cpu.trigger_ud(); } };;
table0F_16[0x0C] = table0F_32[0x0C] = function(cpu) { { if(DEBUG) throw "Possible fault: undefined instruction"; cpu.trigger_ud();} };;
table0F_16[0x0D] = table0F_32[0x0D] = function(cpu) { { /* nop*/ if(DEBUG) { dbg_trace(); throw "TODO"; } cpu.trigger_ud();; } };
table0F_16[0x0E] = table0F_32[0x0E] = function(cpu) { { if(DEBUG) throw "Possible fault: undefined instruction"; cpu.trigger_ud();} };;
table0F_16[0x0F] = table0F_32[0x0F] = function(cpu) { { if(DEBUG) throw "Possible fault: undefined instruction"; cpu.trigger_ud();} };;
table0F_16[0x10] = table0F_32[0x10] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x11] = table0F_32[0x11] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x12] = table0F_32[0x12] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x13] = table0F_32[0x13] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x14] = table0F_32[0x14] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x15] = table0F_32[0x15] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x16] = table0F_32[0x16] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x17] = table0F_32[0x17] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x18] = table0F_32[0x18] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { /* prefetch*/ /* nop for us */ if(cpu.modrm_byte < 0xC0) cpu.modrm_resolve(cpu.modrm_byte); } };;
table0F_16[0x19] = table0F_32[0x19] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x1A] = table0F_32[0x1A] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x1B] = table0F_32[0x1B] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x1C] = table0F_32[0x1C] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x1D] = table0F_32[0x1D] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x1E] = table0F_32[0x1E] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x1F] = table0F_32[0x1F] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x20] = table0F_32[0x20] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.cpl) { cpu.trigger_gp(0); } /*dbg_log("cr" + mod + " read", LOG_CPU);*/ /* mov addr, cr*/ /* mod = which control register*/ switch(cpu.modrm_byte >> 3 & 7) { case 0: cpu.reg32s[cpu.modrm_byte & 7] = cpu.cr[0]; break; case 2: /*dbg_log("read cr2 at " + h(cpu.instruction_pointer >>> 0, 8));*/ cpu.reg32s[cpu.modrm_byte & 7] = cpu.cr[2]; break; case 3: /*dbg_log("read cr3 (" + h(cpu.cr[3], 8) + ")", LOG_CPU);*/ cpu.reg32s[cpu.modrm_byte & 7] = cpu.cr[3]; break; case 4: cpu.reg32s[cpu.modrm_byte & 7] = cpu.cr[4]; break; default: dbg_log(cpu.modrm_byte >> 3 & 7); if(DEBUG) { dbg_trace(); throw "TODO"; } cpu.trigger_ud();; } } };;
table0F_16[0x21] = table0F_32[0x21] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.cpl) { cpu.trigger_gp(0); } /* TODO: mov from debug register*/ dbg_assert(cpu.modrm_byte >= 0xC0); cpu.reg32s[cpu.modrm_byte & 7] = cpu.dreg[cpu.modrm_byte >> 3 & 7]; /*dbg_log("read dr" + (cpu.modrm_byte >> 3 & 7) + ": " + h(cpu.reg32[cpu.modrm_byte & 7]), LOG_CPU);*/ } };;
table0F_16[0x22] = table0F_32[0x22] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.cpl) { cpu.trigger_gp(0); } var data = cpu.reg32s[cpu.modrm_byte & 7]; /*dbg_log("cr" + mod + " written: " + h(cpu.reg32[reg]), LOG_CPU);*/ /* mov cr, addr*/ /* mod = which control register*/ switch(cpu.modrm_byte >> 3 & 7) { case 0: var old_cr0 = cpu.cr[0]; cpu.cr[0] = data; if((cpu.cr[0] & (CR0_PE | CR0_PG)) === CR0_PG) { /* cannot load PG without PE*/ throw cpu.debug.unimpl("#GP handler"); } cpu.cr0_changed(old_cr0); /*dbg_log("cr0=" + h(data >>> 0), LOG_CPU);*/ break; case 2: cpu.cr[2] = data; /*dbg_log("cr2=" + h(data >>> 0), LOG_CPU);*/ break; case 3: /*dbg_log("cr3=" + h(data >>> 0), LOG_CPU);*/ cpu.cr[3] = data; dbg_assert((cpu.cr[3] & 0xFFF) === 0); cpu.clear_tlb(); /*dump_page_directory();*/ /*dbg_log("page directory loaded at " + h(cpu.cr[3] >>> 0, 8), LOG_CPU);*/ break; case 4: if(data & (1 << 11 | 1 << 12 | 1 << 15 | 1 << 16 | 1 << 19 | 0xFFC00000)) { cpu.trigger_gp(0); } if((cpu.cr[4] ^ data) & CR4_PGE) { if(data & CR4_PGE) { /* The PGE bit has been enabled. The global TLB is*/ /* still empty, so we only have to copy it over*/ cpu.clear_tlb(); } else { /* Clear the global TLB*/ cpu.full_clear_tlb(); } } cpu.cr[4] = data; cpu.page_size_extensions = (cpu.cr[4] & CR4_PSE) ? PSE_ENABLED : 0; if(cpu.cr[4] & CR4_PAE) { throw cpu.debug.unimpl("PAE"); } dbg_log("cr4=" + h(cpu.cr[4] >>> 0), LOG_CPU); break; default: dbg_log(cpu.modrm_byte >> 3 & 7); if(DEBUG) { dbg_trace(); throw "TODO"; } cpu.trigger_ud();; } } };;
table0F_16[0x23] = table0F_32[0x23] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.cpl) { cpu.trigger_gp(0); } /* TODO: mov to debug register*/ dbg_assert(cpu.modrm_byte >= 0xC0); /*dbg_log("write dr" + (cpu.modrm_byte >> 3 & 7) + ": " + h(cpu.reg32[cpu.modrm_byte & 7]), LOG_CPU);*/ cpu.dreg[cpu.modrm_byte >> 3 & 7] = cpu.reg32s[cpu.modrm_byte & 7]; } };;
table0F_16[0x24] = table0F_32[0x24] = function(cpu) { { if(DEBUG) throw "Possible fault: undefined instruction"; cpu.trigger_ud();} };;
table0F_16[0x25] = table0F_32[0x25] = function(cpu) { { if(DEBUG) throw "Possible fault: undefined instruction"; cpu.trigger_ud();} };;
table0F_16[0x26] = table0F_32[0x26] = function(cpu) { { if(DEBUG) throw "Possible fault: undefined instruction"; cpu.trigger_ud();} };;
table0F_16[0x27] = table0F_32[0x27] = function(cpu) { { if(DEBUG) throw "Possible fault: undefined instruction"; cpu.trigger_ud();} };;
table0F_16[0x28] = table0F_32[0x28] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x29] = table0F_32[0x29] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x2A] = table0F_32[0x2A] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x2B] = table0F_32[0x2B] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x2C] = table0F_32[0x2C] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x2D] = table0F_32[0x2D] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x2E] = table0F_32[0x2E] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x2F] = table0F_32[0x2F] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
// wrmsr
table0F_16[0x30] = table0F_32[0x30] = function(cpu) { { /* wrmsr - write maschine specific register*/ if(cpu.cpl) { /* cpl > 0 or vm86 mode (vm86 mode is always runs with cpl=3)*/ cpu.trigger_gp(0); } var index = cpu.reg32s[reg_ecx]; var low = cpu.reg32s[reg_eax]; var high = cpu.reg32s[reg_edx]; dbg_log("wrmsr ecx=" + h(index >>> 0, 8) + " data=" + h(high >>> 0, 8) + ":" + h(low >>> 0, 8), LOG_CPU); switch(index) { case IA32_SYSENTER_CS: cpu.sysenter_cs = low & 0xFFFF; break; case IA32_SYSENTER_EIP: cpu.sysenter_eip = low; break; case IA32_SYSENTER_ESP: cpu.sysenter_esp = low; break; } } };;
table0F_16[0x31] = table0F_32[0x31] = function(cpu) { { /* rdtsc - read timestamp counter*/ if(!cpu.cpl || !(cpu.cr[4] & CR4_TSD)) { var n = v86.microtick() - cpu.tsc_offset; dbg_assert(isFinite(n), "non-finite tsc: " + n); cpu.reg32s[reg_eax] = n * TSC_RATE; cpu.reg32s[reg_edx] = n * (TSC_RATE / 0x100000000); /*dbg_log("rdtsc edx:eax=" + h(cpu.reg32[reg_edx], 8) + ":" + h(cpu.reg32[reg_eax], 8), LOG_CPU);*/ } else { cpu.trigger_gp(0); } } };;
table0F_16[0x32] = table0F_32[0x32] = function(cpu) { { /* rdmsr - read maschine specific register*/ if(cpu.cpl) { cpu.trigger_gp(0); } var index = cpu.reg32s[reg_ecx]; dbg_log("rdmsr ecx=" + h(index >>> 0, 8), LOG_CPU); var low = 0; var high = 0; switch(index) { case IA32_SYSENTER_CS: low = cpu.sysenter_cs; break; case IA32_SYSENTER_EIP: low = cpu.sysenter_eip; break; case IA32_SYSENTER_ESP: low = cpu.sysenter_esp; break; } cpu.reg32s[reg_eax] = low; cpu.reg32s[reg_edx] = high; } };;
table0F_16[0x33] = table0F_32[0x33] = function(cpu) { { /* rdpmc*/ if(DEBUG) { dbg_trace(); throw "TODO"; } cpu.trigger_ud();; } };
table0F_16[0x34] = table0F_32[0x34] = function(cpu) { { /* sysenter*/ var seg = cpu.sysenter_cs & 0xFFFC; if(!cpu.protected_mode || seg === 0) { cpu.trigger_gp(0); } /*dbg_log("sysenter cs:eip=" + h(seg , 4) + ":" + h(cpu.sysenter_eip >>> 0, 8) + */ /* " ss:esp=" + h(seg + 8, 4) + ":" + h(cpu.sysenter_esp >>> 0, 8), LOG_CPU);*/ cpu.flags &= ~flag_vm & ~flag_interrupt; cpu.instruction_pointer = cpu.sysenter_eip; cpu.reg32s[reg_esp] = cpu.sysenter_esp; cpu.sreg[reg_cs] = seg; cpu.segment_is_null[reg_cs] = 0; cpu.segment_limits[reg_cs] = -1; cpu.segment_offsets[reg_cs] = 0; if(!cpu.is_32) cpu.update_cs_size(true); cpu.cpl = 0; cpu.cpl_changed(); cpu.sreg[reg_ss] = seg + 8; cpu.segment_is_null[reg_ss] = 0; cpu.segment_limits[reg_ss] = -1; cpu.segment_offsets[reg_ss] = 0; cpu.stack_size_32 = true; cpu.stack_reg = cpu.reg32s; cpu.reg_vsp = reg_esp; cpu.reg_vbp = reg_ebp; } };;
table0F_16[0x35] = table0F_32[0x35] = function(cpu) { { /* sysexit*/ var seg = cpu.sysenter_cs & 0xFFFC; if(!cpu.protected_mode || cpu.cpl || seg === 0) { cpu.trigger_gp(0); } /*dbg_log("sysexit cs:eip=" + h(seg + 16, 4) + ":" + h(cpu.reg32s[reg_edx] >>> 0, 8) + */ /* " ss:esp=" + h(seg + 24, 4) + ":" + h(cpu.reg32s[reg_ecx] >>> 0, 8), LOG_CPU);*/ cpu.instruction_pointer = cpu.reg32s[reg_edx]; cpu.reg32s[reg_esp] = cpu.reg32s[reg_ecx]; cpu.sreg[reg_cs] = seg + 16 | 3; cpu.segment_is_null[reg_cs] = 0; cpu.segment_limits[reg_cs] = -1; cpu.segment_offsets[reg_cs] = 0; if(!cpu.is_32) cpu.update_cs_size(true); cpu.cpl = 3; cpu.cpl_changed(); cpu.sreg[reg_ss] = seg + 24 | 3; cpu.segment_is_null[reg_ss] = 0; cpu.segment_limits[reg_ss] = -1; cpu.segment_offsets[reg_ss] = 0; cpu.stack_size_32 = true; cpu.stack_reg = cpu.reg32s; cpu.reg_vsp = reg_esp; cpu.reg_vbp = reg_ebp; } };;
table0F_16[0x36] = table0F_32[0x36] = function(cpu) { { if(DEBUG) throw "Possible fault: undefined instruction"; cpu.trigger_ud();} };;
table0F_16[0x37] = table0F_32[0x37] = function(cpu) { { /* getsec*/ if(DEBUG) { dbg_trace(); throw "TODO"; } cpu.trigger_ud();; } };
table0F_16[0x38] = table0F_32[0x38] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x39] = table0F_32[0x39] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x3A] = table0F_32[0x3A] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x3B] = table0F_32[0x3B] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x3C] = table0F_32[0x3C] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x3D] = table0F_32[0x3D] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x3E] = table0F_32[0x3E] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x3F] = table0F_32[0x3F] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
// cmov
table0F_16[0x40 | 0x0] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; if(( cpu.test_o())) { cpu.reg16[cpu.modrm_byte >> 2 & 14] = data; } } }; table0F_32[0x40 | 0x0] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; if(( cpu.test_o())) { cpu.reg32s[cpu.modrm_byte >> 3 & 7] = data; } } };;; table0F_16[0x40 | 0x1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; if((!cpu.test_o())) { cpu.reg16[cpu.modrm_byte >> 2 & 14] = data; } } }; table0F_32[0x40 | 0x1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; if((!cpu.test_o())) { cpu.reg32s[cpu.modrm_byte >> 3 & 7] = data; } } };;; table0F_16[0x40 | 0x2] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; if(( cpu.test_b())) { cpu.reg16[cpu.modrm_byte >> 2 & 14] = data; } } }; table0F_32[0x40 | 0x2] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; if(( cpu.test_b())) { cpu.reg32s[cpu.modrm_byte >> 3 & 7] = data; } } };;; table0F_16[0x40 | 0x3] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; if((!cpu.test_b())) { cpu.reg16[cpu.modrm_byte >> 2 & 14] = data; } } }; table0F_32[0x40 | 0x3] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; if((!cpu.test_b())) { cpu.reg32s[cpu.modrm_byte >> 3 & 7] = data; } } };;; table0F_16[0x40 | 0x4] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; if(( cpu.test_z())) { cpu.reg16[cpu.modrm_byte >> 2 & 14] = data; } } }; table0F_32[0x40 | 0x4] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; if(( cpu.test_z())) { cpu.reg32s[cpu.modrm_byte >> 3 & 7] = data; } } };;; table0F_16[0x40 | 0x5] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; if((!cpu.test_z())) { cpu.reg16[cpu.modrm_byte >> 2 & 14] = data; } } }; table0F_32[0x40 | 0x5] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; if((!cpu.test_z())) { cpu.reg32s[cpu.modrm_byte >> 3 & 7] = data; } } };;; table0F_16[0x40 | 0x6] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; if(( cpu.test_be())) { cpu.reg16[cpu.modrm_byte >> 2 & 14] = data; } } }; table0F_32[0x40 | 0x6] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; if(( cpu.test_be())) { cpu.reg32s[cpu.modrm_byte >> 3 & 7] = data; } } };;; table0F_16[0x40 | 0x7] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; if((!cpu.test_be())) { cpu.reg16[cpu.modrm_byte >> 2 & 14] = data; } } }; table0F_32[0x40 | 0x7] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; if((!cpu.test_be())) { cpu.reg32s[cpu.modrm_byte >> 3 & 7] = data; } } };;; table0F_16[0x40 | 0x8] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; if(( cpu.test_s())) { cpu.reg16[cpu.modrm_byte >> 2 & 14] = data; } } }; table0F_32[0x40 | 0x8] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; if(( cpu.test_s())) { cpu.reg32s[cpu.modrm_byte >> 3 & 7] = data; } } };;; table0F_16[0x40 | 0x9] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; if((!cpu.test_s())) { cpu.reg16[cpu.modrm_byte >> 2 & 14] = data; } } }; table0F_32[0x40 | 0x9] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; if((!cpu.test_s())) { cpu.reg32s[cpu.modrm_byte >> 3 & 7] = data; } } };;; table0F_16[0x40 | 0xA] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; if(( cpu.test_p())) { cpu.reg16[cpu.modrm_byte >> 2 & 14] = data; } } }; table0F_32[0x40 | 0xA] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; if(( cpu.test_p())) { cpu.reg32s[cpu.modrm_byte >> 3 & 7] = data; } } };;; table0F_16[0x40 | 0xB] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; if((!cpu.test_p())) { cpu.reg16[cpu.modrm_byte >> 2 & 14] = data; } } }; table0F_32[0x40 | 0xB] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; if((!cpu.test_p())) { cpu.reg32s[cpu.modrm_byte >> 3 & 7] = data; } } };;; table0F_16[0x40 | 0xC] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; if(( cpu.test_l())) { cpu.reg16[cpu.modrm_byte >> 2 & 14] = data; } } }; table0F_32[0x40 | 0xC] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; if(( cpu.test_l())) { cpu.reg32s[cpu.modrm_byte >> 3 & 7] = data; } } };;; table0F_16[0x40 | 0xD] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; if((!cpu.test_l())) { cpu.reg16[cpu.modrm_byte >> 2 & 14] = data; } } }; table0F_32[0x40 | 0xD] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; if((!cpu.test_l())) { cpu.reg32s[cpu.modrm_byte >> 3 & 7] = data; } } };;; table0F_16[0x40 | 0xE] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; if(( cpu.test_le())) { cpu.reg16[cpu.modrm_byte >> 2 & 14] = data; } } }; table0F_32[0x40 | 0xE] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; if(( cpu.test_le())) { cpu.reg32s[cpu.modrm_byte >> 3 & 7] = data; } } };;; table0F_16[0x40 | 0xF] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; if((!cpu.test_le())) { cpu.reg16[cpu.modrm_byte >> 2 & 14] = data; } } }; table0F_32[0x40 | 0xF] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; if((!cpu.test_le())) { cpu.reg32s[cpu.modrm_byte >> 3 & 7] = data; } } };;;;
table0F_16[0x50] = table0F_32[0x50] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x51] = table0F_32[0x51] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x52] = table0F_32[0x52] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x53] = table0F_32[0x53] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x54] = table0F_32[0x54] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x55] = table0F_32[0x55] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x56] = table0F_32[0x56] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x57] = table0F_32[0x57] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x58] = table0F_32[0x58] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x59] = table0F_32[0x59] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x5A] = table0F_32[0x5A] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x5B] = table0F_32[0x5B] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x5C] = table0F_32[0x5C] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x5D] = table0F_32[0x5D] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x5E] = table0F_32[0x5E] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x5F] = table0F_32[0x5F] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x60] = table0F_32[0x60] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x61] = table0F_32[0x61] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x62] = table0F_32[0x62] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x63] = table0F_32[0x63] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x64] = table0F_32[0x64] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x65] = table0F_32[0x65] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x66] = table0F_32[0x66] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x67] = table0F_32[0x67] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x68] = table0F_32[0x68] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x69] = table0F_32[0x69] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x6A] = table0F_32[0x6A] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x6B] = table0F_32[0x6B] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x6C] = table0F_32[0x6C] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x6D] = table0F_32[0x6D] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x6E] = table0F_32[0x6E] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x6F] = table0F_32[0x6F] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x70] = table0F_32[0x70] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x71] = table0F_32[0x71] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x72] = table0F_32[0x72] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x73] = table0F_32[0x73] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x74] = table0F_32[0x74] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x75] = table0F_32[0x75] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x76] = table0F_32[0x76] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x77] = table0F_32[0x77] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x78] = table0F_32[0x78] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x79] = table0F_32[0x79] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x7A] = table0F_32[0x7A] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x7B] = table0F_32[0x7B] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x7C] = table0F_32[0x7C] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x7D] = table0F_32[0x7D] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x7E] = table0F_32[0x7E] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x7F] = table0F_32[0x7F] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0x80 | 0x0] = function(cpu) { { cpu.jmpcc16(( cpu.test_o())); } }; table0F_32[0x80 | 0x0] = function(cpu) { { cpu.jmpcc32(( cpu.test_o())); } };; table0F_16[0x80 | 0x1] = function(cpu) { { cpu.jmpcc16((!cpu.test_o())); } }; table0F_32[0x80 | 0x1] = function(cpu) { { cpu.jmpcc32((!cpu.test_o())); } };; table0F_16[0x80 | 0x2] = function(cpu) { { cpu.jmpcc16(( cpu.test_b())); } }; table0F_32[0x80 | 0x2] = function(cpu) { { cpu.jmpcc32(( cpu.test_b())); } };; table0F_16[0x80 | 0x3] = function(cpu) { { cpu.jmpcc16((!cpu.test_b())); } }; table0F_32[0x80 | 0x3] = function(cpu) { { cpu.jmpcc32((!cpu.test_b())); } };; table0F_16[0x80 | 0x4] = function(cpu) { { cpu.jmpcc16(( cpu.test_z())); } }; table0F_32[0x80 | 0x4] = function(cpu) { { cpu.jmpcc32(( cpu.test_z())); } };; table0F_16[0x80 | 0x5] = function(cpu) { { cpu.jmpcc16((!cpu.test_z())); } }; table0F_32[0x80 | 0x5] = function(cpu) { { cpu.jmpcc32((!cpu.test_z())); } };; table0F_16[0x80 | 0x6] = function(cpu) { { cpu.jmpcc16(( cpu.test_be())); } }; table0F_32[0x80 | 0x6] = function(cpu) { { cpu.jmpcc32(( cpu.test_be())); } };; table0F_16[0x80 | 0x7] = function(cpu) { { cpu.jmpcc16((!cpu.test_be())); } }; table0F_32[0x80 | 0x7] = function(cpu) { { cpu.jmpcc32((!cpu.test_be())); } };; table0F_16[0x80 | 0x8] = function(cpu) { { cpu.jmpcc16(( cpu.test_s())); } }; table0F_32[0x80 | 0x8] = function(cpu) { { cpu.jmpcc32(( cpu.test_s())); } };; table0F_16[0x80 | 0x9] = function(cpu) { { cpu.jmpcc16((!cpu.test_s())); } }; table0F_32[0x80 | 0x9] = function(cpu) { { cpu.jmpcc32((!cpu.test_s())); } };; table0F_16[0x80 | 0xA] = function(cpu) { { cpu.jmpcc16(( cpu.test_p())); } }; table0F_32[0x80 | 0xA] = function(cpu) { { cpu.jmpcc32(( cpu.test_p())); } };; table0F_16[0x80 | 0xB] = function(cpu) { { cpu.jmpcc16((!cpu.test_p())); } }; table0F_32[0x80 | 0xB] = function(cpu) { { cpu.jmpcc32((!cpu.test_p())); } };; table0F_16[0x80 | 0xC] = function(cpu) { { cpu.jmpcc16(( cpu.test_l())); } }; table0F_32[0x80 | 0xC] = function(cpu) { { cpu.jmpcc32(( cpu.test_l())); } };; table0F_16[0x80 | 0xD] = function(cpu) { { cpu.jmpcc16((!cpu.test_l())); } }; table0F_32[0x80 | 0xD] = function(cpu) { { cpu.jmpcc32((!cpu.test_l())); } };; table0F_16[0x80 | 0xE] = function(cpu) { { cpu.jmpcc16(( cpu.test_le())); } }; table0F_32[0x80 | 0xE] = function(cpu) { { cpu.jmpcc32(( cpu.test_le())); } };; table0F_16[0x80 | 0xF] = function(cpu) { { cpu.jmpcc16((!cpu.test_le())); } }; table0F_32[0x80 | 0xF] = function(cpu) { { cpu.jmpcc32((!cpu.test_le())); } };;
table0F_16[0x90 | 0x0] = table0F_32[0x90 | 0x0] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = !( cpu.test_o()) ^ 1; if(cpu.modrm_byte < 0xC0) { cpu.safe_write8(addr, data); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = data; }; } };;; table0F_16[0x90 | 0x1] = table0F_32[0x90 | 0x1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = !(!cpu.test_o()) ^ 1; if(cpu.modrm_byte < 0xC0) { cpu.safe_write8(addr, data); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = data; }; } };;; table0F_16[0x90 | 0x2] = table0F_32[0x90 | 0x2] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = !( cpu.test_b()) ^ 1; if(cpu.modrm_byte < 0xC0) { cpu.safe_write8(addr, data); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = data; }; } };;; table0F_16[0x90 | 0x3] = table0F_32[0x90 | 0x3] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = !(!cpu.test_b()) ^ 1; if(cpu.modrm_byte < 0xC0) { cpu.safe_write8(addr, data); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = data; }; } };;; table0F_16[0x90 | 0x4] = table0F_32[0x90 | 0x4] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = !( cpu.test_z()) ^ 1; if(cpu.modrm_byte < 0xC0) { cpu.safe_write8(addr, data); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = data; }; } };;; table0F_16[0x90 | 0x5] = table0F_32[0x90 | 0x5] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = !(!cpu.test_z()) ^ 1; if(cpu.modrm_byte < 0xC0) { cpu.safe_write8(addr, data); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = data; }; } };;; table0F_16[0x90 | 0x6] = table0F_32[0x90 | 0x6] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = !( cpu.test_be()) ^ 1; if(cpu.modrm_byte < 0xC0) { cpu.safe_write8(addr, data); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = data; }; } };;; table0F_16[0x90 | 0x7] = table0F_32[0x90 | 0x7] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = !(!cpu.test_be()) ^ 1; if(cpu.modrm_byte < 0xC0) { cpu.safe_write8(addr, data); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = data; }; } };;; table0F_16[0x90 | 0x8] = table0F_32[0x90 | 0x8] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = !( cpu.test_s()) ^ 1; if(cpu.modrm_byte < 0xC0) { cpu.safe_write8(addr, data); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = data; }; } };;; table0F_16[0x90 | 0x9] = table0F_32[0x90 | 0x9] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = !(!cpu.test_s()) ^ 1; if(cpu.modrm_byte < 0xC0) { cpu.safe_write8(addr, data); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = data; }; } };;; table0F_16[0x90 | 0xA] = table0F_32[0x90 | 0xA] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = !( cpu.test_p()) ^ 1; if(cpu.modrm_byte < 0xC0) { cpu.safe_write8(addr, data); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = data; }; } };;; table0F_16[0x90 | 0xB] = table0F_32[0x90 | 0xB] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = !(!cpu.test_p()) ^ 1; if(cpu.modrm_byte < 0xC0) { cpu.safe_write8(addr, data); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = data; }; } };;; table0F_16[0x90 | 0xC] = table0F_32[0x90 | 0xC] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = !( cpu.test_l()) ^ 1; if(cpu.modrm_byte < 0xC0) { cpu.safe_write8(addr, data); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = data; }; } };;; table0F_16[0x90 | 0xD] = table0F_32[0x90 | 0xD] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = !(!cpu.test_l()) ^ 1; if(cpu.modrm_byte < 0xC0) { cpu.safe_write8(addr, data); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = data; }; } };;; table0F_16[0x90 | 0xE] = table0F_32[0x90 | 0xE] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = !( cpu.test_le()) ^ 1; if(cpu.modrm_byte < 0xC0) { cpu.safe_write8(addr, data); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = data; }; } };;; table0F_16[0x90 | 0xF] = table0F_32[0x90 | 0xF] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = !(!cpu.test_le()) ^ 1; if(cpu.modrm_byte < 0xC0) { cpu.safe_write8(addr, data); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = data; }; } };;;;
table0F_16[0xA0] = function(cpu) { { cpu.push16(cpu.sreg[reg_fs]); } }; table0F_32[0xA0] = function(cpu) { { cpu.push32(cpu.sreg[reg_fs]); } };;
table0F_16[0xA1] = function(cpu) { { cpu.switch_seg(reg_fs, cpu.safe_read16(cpu.get_stack_pointer(0))); cpu.stack_reg[cpu.reg_vsp] += 2; if(reg_fs === reg_ss) { cpu.clear_prefixes(); cpu.cycle(); } } }; table0F_32[0xA1] = function(cpu) { { cpu.switch_seg(reg_fs, cpu.safe_read16(cpu.get_stack_pointer(0))); cpu.stack_reg[cpu.reg_vsp] += 4; if(reg_fs === reg_ss) { cpu.clear_prefixes(); cpu.cycle(); } } };;;
table0F_16[0xA2] = table0F_32[0xA2] = function(cpu) { { cpu.cpuid(); } };;
table0F_16[0xA3] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { cpu.bt_mem(cpu.modrm_resolve(cpu.modrm_byte), cpu.reg16s[cpu.modrm_byte >> 2 & 14]); } else { cpu.bt_reg(cpu.reg16[cpu.modrm_byte << 1 & 14], cpu.reg16[cpu.modrm_byte >> 2 & 14] & 15); } } }; table0F_32[0xA3] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { cpu.bt_mem(cpu.modrm_resolve(cpu.modrm_byte), cpu.reg32s[cpu.modrm_byte >> 3 & 7]); } else { cpu.bt_reg(cpu.reg32s[cpu.modrm_byte & 7], cpu.reg32s[cpu.modrm_byte >> 3 & 7] & 31); } } };;
table0F_16[0xA4] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = cpu.translate_address_write(virt_addr + 1); data = cpu.virt_boundary_read16(phys_addr, phys_addr_high); } else { data = cpu.memory.read16(phys_addr); } } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; } result = cpu.shld16(data, cpu.reg16[cpu.modrm_byte >> 2 & 14], cpu.read_imm8() & 31); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write16(phys_addr, phys_addr_high, result); } else { cpu.memory.write16(phys_addr, result); } } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = result; }; } }; table0F_32[0xA4] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = cpu.translate_address_write(virt_addr + 3); data = cpu.virt_boundary_read32s(phys_addr, phys_addr_high); } else { data = cpu.memory.read32s(phys_addr); } } else { data = cpu.reg32s[cpu.modrm_byte & 7]; } result = cpu.shld32(data, cpu.reg32s[cpu.modrm_byte >> 3 & 7], cpu.read_imm8() & 31); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write32(phys_addr, phys_addr_high, result); } else { cpu.memory.write32(phys_addr, result); } } else { cpu.reg32s[cpu.modrm_byte & 7] = result; }; } };;
table0F_16[0xA5] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = cpu.translate_address_write(virt_addr + 1); data = cpu.virt_boundary_read16(phys_addr, phys_addr_high); } else { data = cpu.memory.read16(phys_addr); } } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; } result = cpu.shld16(data, cpu.reg16[cpu.modrm_byte >> 2 & 14], cpu.reg8[reg_cl] & 31); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write16(phys_addr, phys_addr_high, result); } else { cpu.memory.write16(phys_addr, result); } } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = result; }; } }; table0F_32[0xA5] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = cpu.translate_address_write(virt_addr + 3); data = cpu.virt_boundary_read32s(phys_addr, phys_addr_high); } else { data = cpu.memory.read32s(phys_addr); } } else { data = cpu.reg32s[cpu.modrm_byte & 7]; } result = cpu.shld32(data, cpu.reg32s[cpu.modrm_byte >> 3 & 7], cpu.reg8[reg_cl] & 31); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write32(phys_addr, phys_addr_high, result); } else { cpu.memory.write32(phys_addr, result); } } else { cpu.reg32s[cpu.modrm_byte & 7] = result; }; } };;
table0F_16[0xA6] = table0F_32[0xA6] = function(cpu) { { if(DEBUG) throw "Possible fault: undefined instruction"; cpu.trigger_ud();} };;
table0F_16[0xA7] = table0F_32[0xA7] = function(cpu) { { if(DEBUG) throw "Possible fault: undefined instruction"; cpu.trigger_ud();} };;
table0F_16[0xA8] = function(cpu) { { cpu.push16(cpu.sreg[reg_gs]); } }; table0F_32[0xA8] = function(cpu) { { cpu.push32(cpu.sreg[reg_gs]); } };;
table0F_16[0xA9] = function(cpu) { { cpu.switch_seg(reg_gs, cpu.safe_read16(cpu.get_stack_pointer(0))); cpu.stack_reg[cpu.reg_vsp] += 2; if(reg_gs === reg_ss) { cpu.clear_prefixes(); cpu.cycle(); } } }; table0F_32[0xA9] = function(cpu) { { cpu.switch_seg(reg_gs, cpu.safe_read16(cpu.get_stack_pointer(0))); cpu.stack_reg[cpu.reg_vsp] += 4; if(reg_gs === reg_ss) { cpu.clear_prefixes(); cpu.cycle(); } } };;;
table0F_16[0xAA] = table0F_32[0xAA] = function(cpu) { { /* rsm*/ if(DEBUG) { dbg_trace(); throw "TODO"; } cpu.trigger_ud();; } };
table0F_16[0xAB] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { cpu.bts_mem(cpu.modrm_resolve(cpu.modrm_byte), cpu.reg16s[cpu.modrm_byte >> 2 & 14]); } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = cpu.bts_reg(cpu.reg16[cpu.modrm_byte << 1 & 14], cpu.reg16s[cpu.modrm_byte >> 2 & 14] & 15); }; } }; table0F_32[0xAB] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { cpu.bts_mem(cpu.modrm_resolve(cpu.modrm_byte), cpu.reg32s[cpu.modrm_byte >> 3 & 7]); } else { cpu.reg32s[cpu.modrm_byte & 7] = cpu.bts_reg(cpu.reg32s[cpu.modrm_byte & 7], cpu.reg32s[cpu.modrm_byte >> 3 & 7] & 31); }; } };;
table0F_16[0xAC] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = cpu.translate_address_write(virt_addr + 1); data = cpu.virt_boundary_read16(phys_addr, phys_addr_high); } else { data = cpu.memory.read16(phys_addr); } } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; } result = cpu.shrd16(data, cpu.reg16[cpu.modrm_byte >> 2 & 14], cpu.read_imm8() & 31); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write16(phys_addr, phys_addr_high, result); } else { cpu.memory.write16(phys_addr, result); } } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = result; }; } }; table0F_32[0xAC] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = cpu.translate_address_write(virt_addr + 3); data = cpu.virt_boundary_read32s(phys_addr, phys_addr_high); } else { data = cpu.memory.read32s(phys_addr); } } else { data = cpu.reg32s[cpu.modrm_byte & 7]; } result = cpu.shrd32(data, cpu.reg32s[cpu.modrm_byte >> 3 & 7], cpu.read_imm8() & 31); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write32(phys_addr, phys_addr_high, result); } else { cpu.memory.write32(phys_addr, result); } } else { cpu.reg32s[cpu.modrm_byte & 7] = result; }; } };;
table0F_16[0xAD] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = cpu.translate_address_write(virt_addr + 1); data = cpu.virt_boundary_read16(phys_addr, phys_addr_high); } else { data = cpu.memory.read16(phys_addr); } } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; } result = cpu.shrd16(data, cpu.reg16[cpu.modrm_byte >> 2 & 14], cpu.reg8[reg_cl] & 31); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write16(phys_addr, phys_addr_high, result); } else { cpu.memory.write16(phys_addr, result); } } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = result; }; } }; table0F_32[0xAD] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = cpu.translate_address_write(virt_addr + 3); data = cpu.virt_boundary_read32s(phys_addr, phys_addr_high); } else { data = cpu.memory.read32s(phys_addr); } } else { data = cpu.reg32s[cpu.modrm_byte & 7]; } result = cpu.shrd32(data, cpu.reg32s[cpu.modrm_byte >> 3 & 7], cpu.reg8[reg_cl] & 31); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write32(phys_addr, phys_addr_high, result); } else { cpu.memory.write32(phys_addr, result); } } else { cpu.reg32s[cpu.modrm_byte & 7] = result; }; } };;
table0F_16[0xAE] = table0F_32[0xAE] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { /* fxsave, fxrstor, ldmxcsr ...*/ switch(cpu.modrm_byte >> 3 & 7) { case 6: /* mfence*/ dbg_assert(cpu.modrm_byte >= 0xC0, "Unexpected mfence encoding"); break; default: dbg_log("missing " + (cpu.modrm_byte >> 3 & 7), LOG_CPU); if(DEBUG) { dbg_trace(); throw "TODO"; } cpu.trigger_ud();; } } };
table0F_16[0xAF] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = (cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)) << 16 >> 16); } else { data = cpu.reg16s[cpu.modrm_byte << 1 & 14]; }; cpu.reg16[cpu.modrm_byte >> 2 & 14] = cpu.imul_reg16(cpu.reg16s[cpu.modrm_byte >> 2 & 14], data); } }; table0F_32[0xAF] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.reg32s[cpu.modrm_byte >> 3 & 7] = cpu.imul_reg32(cpu.reg32s[cpu.modrm_byte >> 3 & 7], data); } };;
table0F_16[0xB0] = table0F_32[0xB0] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { /* cmpxchg8*/ if(cpu.modrm_byte < 0xC0) { var virt_addr = cpu.modrm_resolve(cpu.modrm_byte); cpu.writable_or_pagefault(virt_addr, 1); var data = cpu.safe_read8(virt_addr); } else data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; cpu.sub(cpu.reg8[reg_al], data, OPSIZE_8); if(cpu.getzf()) { if(cpu.modrm_byte < 0xC0) cpu.safe_write8(virt_addr, cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1]); else cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = cpu.reg8[cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1]; } else { cpu.reg8[reg_al] = data; } } };;
table0F_16[0xB1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { /* cmpxchg16/32*/ if(cpu.modrm_byte < 0xC0) { var virt_addr = cpu.modrm_resolve(cpu.modrm_byte); cpu.writable_or_pagefault(virt_addr, 2); var data = cpu.safe_read16(virt_addr); } else data = cpu.reg16[cpu.modrm_byte << 1 & 14]; cpu.sub(cpu.reg16[reg_ax], data, OPSIZE_16); if(cpu.getzf()) { if(cpu.modrm_byte < 0xC0) cpu.safe_write16(virt_addr, cpu.reg16[cpu.modrm_byte >> 2 & 14]); else cpu.reg16[cpu.modrm_byte << 1 & 14] = cpu.reg16[cpu.modrm_byte >> 2 & 14]; } else { cpu.reg16[reg_ax] = data; } } }; table0F_32[0xB1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var virt_addr = cpu.modrm_resolve(cpu.modrm_byte); cpu.writable_or_pagefault(virt_addr, 4); var data = cpu.safe_read32s(virt_addr); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; } cpu.sub(cpu.reg32s[reg_eax], data, OPSIZE_32); if(cpu.getzf()) { if(cpu.modrm_byte < 0xC0) cpu.safe_write32(virt_addr, cpu.reg32s[cpu.modrm_byte >> 3 & 7]); else cpu.reg32s[cpu.modrm_byte & 7] = cpu.reg32s[cpu.modrm_byte >> 3 & 7]; } else { cpu.reg32s[reg_eax] = data; } } };;
// lss
table0F_16[0xB2] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte >= 0xC0) { cpu.trigger_ud(); } cpu.lss16(reg_ss, cpu.modrm_resolve(cpu.modrm_byte), cpu.modrm_byte >> 2 & 14);; } }; table0F_32[0xB2] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte >= 0xC0) { cpu.trigger_ud(); } cpu.lss32(reg_ss, cpu.modrm_resolve(cpu.modrm_byte), cpu.modrm_byte >> 3 & 7);; } };;
table0F_16[0xB3] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { cpu.btr_mem(cpu.modrm_resolve(cpu.modrm_byte), cpu.reg16s[cpu.modrm_byte >> 2 & 14]); } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = cpu.btr_reg(cpu.reg16[cpu.modrm_byte << 1 & 14], cpu.reg16s[cpu.modrm_byte >> 2 & 14] & 15); }; } }; table0F_32[0xB3] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { cpu.btr_mem(cpu.modrm_resolve(cpu.modrm_byte), cpu.reg32s[cpu.modrm_byte >> 3 & 7]); } else { cpu.reg32s[cpu.modrm_byte & 7] = cpu.btr_reg(cpu.reg32s[cpu.modrm_byte & 7], cpu.reg32s[cpu.modrm_byte >> 3 & 7] & 31); }; } };;
// lfs, lgs
table0F_16[0xB4] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte >= 0xC0) { cpu.trigger_ud(); } cpu.lss16(reg_fs, cpu.modrm_resolve(cpu.modrm_byte), cpu.modrm_byte >> 2 & 14);; } }; table0F_32[0xB4] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte >= 0xC0) { cpu.trigger_ud(); } cpu.lss32(reg_fs, cpu.modrm_resolve(cpu.modrm_byte), cpu.modrm_byte >> 3 & 7);; } };;
table0F_16[0xB5] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte >= 0xC0) { cpu.trigger_ud(); } cpu.lss16(reg_gs, cpu.modrm_resolve(cpu.modrm_byte), cpu.modrm_byte >> 2 & 14);; } }; table0F_32[0xB5] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte >= 0xC0) { cpu.trigger_ud(); } cpu.lss32(reg_gs, cpu.modrm_resolve(cpu.modrm_byte), cpu.modrm_byte >> 3 & 7);; } };;
table0F_16[0xB6] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { /* movzx*/ if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read8(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; }; cpu.reg16[cpu.modrm_byte >> 2 & 14] = data; } }; table0F_32[0xB6] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read8(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; }; cpu.reg32s[cpu.modrm_byte >> 3 & 7] = data; } };;
table0F_16[0xB7] = table0F_32[0xB7] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { /* movzx*/ if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.reg32s[cpu.modrm_byte >> 3 & 7] = data; } };;
table0F_16[0xB8] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { /* popcnt*/ if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.reg16[cpu.modrm_byte >> 2 & 14] = cpu.popcnt(data); } }; table0F_32[0xB8] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.reg32s[cpu.modrm_byte >> 3 & 7] = cpu.popcnt(data); } };;
table0F_16[0xB9] = table0F_32[0xB9] = function(cpu) { { /* UD*/ if(DEBUG) { dbg_trace(); throw "TODO"; } cpu.trigger_ud();; } };
table0F_16[0xBA] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { /*dbg_log("BA " + mod + " " + imm8);*/ switch(cpu.modrm_byte >> 3 & 7) { case 4: if(cpu.modrm_byte < 0xC0) { cpu.bt_mem(cpu.modrm_resolve(cpu.modrm_byte), cpu.read_imm8() & 15); } else { cpu.bt_reg(cpu.reg16[cpu.modrm_byte << 1 & 14], cpu.read_imm8() & 15); } break; case 5: if(cpu.modrm_byte < 0xC0) { cpu.bts_mem(cpu.modrm_resolve(cpu.modrm_byte), cpu.read_imm8() & 15); } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = cpu.bts_reg(cpu.reg16[cpu.modrm_byte << 1 & 14], cpu.read_imm8() & 15 & 15); }; break; case 6: if(cpu.modrm_byte < 0xC0) { cpu.btr_mem(cpu.modrm_resolve(cpu.modrm_byte), cpu.read_imm8() & 15); } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = cpu.btr_reg(cpu.reg16[cpu.modrm_byte << 1 & 14], cpu.read_imm8() & 15 & 15); }; break; case 7: if(cpu.modrm_byte < 0xC0) { cpu.btc_mem(cpu.modrm_resolve(cpu.modrm_byte), cpu.read_imm8() & 15); } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = cpu.btc_reg(cpu.reg16[cpu.modrm_byte << 1 & 14], cpu.read_imm8() & 15 & 15); }; break; default: dbg_log(cpu.modrm_byte >> 3 & 7); if(DEBUG) { dbg_trace(); throw "TODO"; } cpu.trigger_ud();; } } }; table0F_32[0xBA] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { /*dbg_log("BA " + mod + " " + imm8);*/ switch(cpu.modrm_byte >> 3 & 7) { case 4: if(cpu.modrm_byte < 0xC0) { cpu.bt_mem(cpu.modrm_resolve(cpu.modrm_byte), cpu.read_imm8() & 31); } else { cpu.bt_reg(cpu.reg32s[cpu.modrm_byte & 7], cpu.read_imm8() & 31); } break; case 5: if(cpu.modrm_byte < 0xC0) { cpu.bts_mem(cpu.modrm_resolve(cpu.modrm_byte), cpu.read_imm8() & 31); } else { cpu.reg32s[cpu.modrm_byte & 7] = cpu.bts_reg(cpu.reg32s[cpu.modrm_byte & 7], cpu.read_imm8() & 31 & 31); }; break; case 6: if(cpu.modrm_byte < 0xC0) { cpu.btr_mem(cpu.modrm_resolve(cpu.modrm_byte), cpu.read_imm8() & 31); } else { cpu.reg32s[cpu.modrm_byte & 7] = cpu.btr_reg(cpu.reg32s[cpu.modrm_byte & 7], cpu.read_imm8() & 31 & 31); }; break; case 7: if(cpu.modrm_byte < 0xC0) { cpu.btc_mem(cpu.modrm_resolve(cpu.modrm_byte), cpu.read_imm8() & 31); } else { cpu.reg32s[cpu.modrm_byte & 7] = cpu.btc_reg(cpu.reg32s[cpu.modrm_byte & 7], cpu.read_imm8() & 31 & 31); }; break; default: dbg_log(cpu.modrm_byte >> 3 & 7); if(DEBUG) { dbg_trace(); throw "TODO"; } cpu.trigger_ud();; } } };;
table0F_16[0xBB] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { cpu.btc_mem(cpu.modrm_resolve(cpu.modrm_byte), cpu.reg16s[cpu.modrm_byte >> 2 & 14]); } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = cpu.btc_reg(cpu.reg16[cpu.modrm_byte << 1 & 14], cpu.reg16s[cpu.modrm_byte >> 2 & 14] & 15); }; } }; table0F_32[0xBB] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { cpu.btc_mem(cpu.modrm_resolve(cpu.modrm_byte), cpu.reg32s[cpu.modrm_byte >> 3 & 7]); } else { cpu.reg32s[cpu.modrm_byte & 7] = cpu.btc_reg(cpu.reg32s[cpu.modrm_byte & 7], cpu.reg32s[cpu.modrm_byte >> 3 & 7] & 31); }; } };;
table0F_16[0xBC] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.reg16[cpu.modrm_byte >> 2 & 14] = cpu.bsf16(cpu.reg16[cpu.modrm_byte >> 2 & 14], data); } }; table0F_32[0xBC] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.reg32s[cpu.modrm_byte >> 3 & 7] = cpu.bsf32(cpu.reg32s[cpu.modrm_byte >> 3 & 7], data); } };;
table0F_16[0xBD] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; }; cpu.reg16[cpu.modrm_byte >> 2 & 14] = cpu.bsr16(cpu.reg16[cpu.modrm_byte >> 2 & 14], data); } }; table0F_32[0xBD] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = cpu.safe_read32s(cpu.modrm_resolve(cpu.modrm_byte)); } else { data = cpu.reg32s[cpu.modrm_byte & 7]; }; cpu.reg32s[cpu.modrm_byte >> 3 & 7] = cpu.bsr32(cpu.reg32s[cpu.modrm_byte >> 3 & 7], data); } };;
table0F_16[0xBE] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { /* movsx*/ if(cpu.modrm_byte < 0xC0) { var data = (cpu.safe_read8(cpu.modrm_resolve(cpu.modrm_byte)) << 24 >> 24); } else { data = cpu.reg8s[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; }; cpu.reg16[cpu.modrm_byte >> 2 & 14] = data; } }; table0F_32[0xBE] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { if(cpu.modrm_byte < 0xC0) { var data = (cpu.safe_read8(cpu.modrm_resolve(cpu.modrm_byte)) << 24 >> 24); } else { data = cpu.reg8s[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; }; cpu.reg32s[cpu.modrm_byte >> 3 & 7] = data; } };;
table0F_16[0xBF] = table0F_32[0xBF] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { /* movsx*/ if(cpu.modrm_byte < 0xC0) { var data = (cpu.safe_read16(cpu.modrm_resolve(cpu.modrm_byte)) << 16 >> 16); } else { data = cpu.reg16s[cpu.modrm_byte << 1 & 14]; }; cpu.reg32s[cpu.modrm_byte >> 3 & 7] = data; } };;
table0F_16[0xC0] = table0F_32[0xC0] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var addr; var result; if(cpu.modrm_byte < 0xC0) { addr = cpu.translate_address_write(cpu.modrm_resolve(cpu.modrm_byte)); data = cpu.memory.read8(addr); } else { data = cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1]; } result = cpu.xadd8(data, cpu.modrm_byte >> 1 & 0xC | cpu.modrm_byte >> 5 & 1); if(cpu.modrm_byte < 0xC0) { cpu.memory.write8(addr, result); } else { cpu.reg8[cpu.modrm_byte << 2 & 0xC | cpu.modrm_byte >> 2 & 1] = result; }; } };;
table0F_16[0xC1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) === 0xFFF) { phys_addr_high = cpu.translate_address_write(virt_addr + 1); data = cpu.virt_boundary_read16(phys_addr, phys_addr_high); } else { data = cpu.memory.read16(phys_addr); } } else { data = cpu.reg16[cpu.modrm_byte << 1 & 14]; } result = cpu.xadd16(data, cpu.modrm_byte >> 2 & 14); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write16(phys_addr, phys_addr_high, result); } else { cpu.memory.write16(phys_addr, result); } } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = result; }; } }; table0F_32[0xC1] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { var data; var virt_addr; var phys_addr; var phys_addr_high = 0; var result; if(cpu.modrm_byte < 0xC0) { virt_addr = cpu.modrm_resolve(cpu.modrm_byte); phys_addr = cpu.translate_address_write(virt_addr); if(cpu.paging && (virt_addr & 0xFFF) >= 0xFFD) { phys_addr_high = cpu.translate_address_write(virt_addr + 3); data = cpu.virt_boundary_read32s(phys_addr, phys_addr_high); } else { data = cpu.memory.read32s(phys_addr); } } else { data = cpu.reg32s[cpu.modrm_byte & 7]; } result = cpu.xadd32(data, cpu.modrm_byte >> 3 & 7); if(cpu.modrm_byte < 0xC0) { if(phys_addr_high) { cpu.virt_boundary_write32(phys_addr, phys_addr_high, result); } else { cpu.memory.write32(phys_addr, result); } } else { cpu.reg32s[cpu.modrm_byte & 7] = result; }; } };;
table0F_16[0xC2] = table0F_32[0xC2] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xC3] = table0F_32[0xC3] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xC4] = table0F_32[0xC4] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xC5] = table0F_32[0xC5] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xC6] = table0F_32[0xC6] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xC7] = table0F_32[0xC7] = function(cpu) { cpu.modrm_byte = cpu.read_imm8(); { /* cmpxchg8b*/ switch(cpu.modrm_byte >> 3 & 7) { case 1: if(cpu.modrm_byte >= 0xC0) { cpu.trigger_ud(); } var addr = cpu.modrm_resolve(cpu.modrm_byte); cpu.writable_or_pagefault(addr, 8); var m64_low = cpu.safe_read32s(addr); var m64_high = cpu.safe_read32s(addr + 4); if(cpu.reg32s[reg_eax] === m64_low && cpu.reg32s[reg_edx] === m64_high) { cpu.flags |= flag_zero; cpu.safe_write32(addr, cpu.reg32s[reg_ebx]); cpu.safe_write32(addr + 4, cpu.reg32s[reg_ecx]); } else { cpu.flags &= ~flag_zero; cpu.reg32s[reg_eax] = m64_low; cpu.reg32s[reg_edx] = m64_high; } cpu.flags_changed &= ~flag_zero; break; case 6: var has_rand = v86.has_rand_int(); if(has_rand) { var rand = v86.get_rand_int(); } else { var rand = 0; } /*dbg_log("rdrand -> " + h(rand >>> 0, 8), LOG_CPU);*/ if(cpu.operand_size_32) { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = rand; if(cpu.modrm_byte < 0xC0) { cpu.safe_write32(addr, data); } else { cpu.reg32[cpu.modrm_byte & 7] = data; }; } else { if(cpu.modrm_byte < 0xC0) var addr = cpu.modrm_resolve(cpu.modrm_byte); var data = rand; if(cpu.modrm_byte < 0xC0) { cpu.safe_write16(addr, data); } else { cpu.reg16[cpu.modrm_byte << 1 & 14] = data; }; } cpu.flags &= ~flags_all; cpu.flags |= has_rand; cpu.flags_changed = 0; break; default: dbg_log(cpu.modrm_byte >> 3 & 7, LOG_CPU); if(DEBUG) { dbg_trace(); throw "TODO"; } cpu.trigger_ud();; } } };;
table0F_16[0xC8] = table0F_32[0xC8] = function(cpu) { { cpu.bswap(reg_eax); } };;
table0F_16[0xC9] = table0F_32[0xC9] = function(cpu) { { cpu.bswap(reg_ecx); } };;
table0F_16[0xCA] = table0F_32[0xCA] = function(cpu) { { cpu.bswap(reg_edx); } };;
table0F_16[0xCB] = table0F_32[0xCB] = function(cpu) { { cpu.bswap(reg_ebx); } };;
table0F_16[0xCC] = table0F_32[0xCC] = function(cpu) { { cpu.bswap(reg_esp); } };;
table0F_16[0xCD] = table0F_32[0xCD] = function(cpu) { { cpu.bswap(reg_ebp); } };;
table0F_16[0xCE] = table0F_32[0xCE] = function(cpu) { { cpu.bswap(reg_esi); } };;
table0F_16[0xCF] = table0F_32[0xCF] = function(cpu) { { cpu.bswap(reg_edi); } };;
table0F_16[0xD0] = table0F_32[0xD0] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xD1] = table0F_32[0xD1] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xD2] = table0F_32[0xD2] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xD3] = table0F_32[0xD3] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xD4] = table0F_32[0xD4] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xD5] = table0F_32[0xD5] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xD6] = table0F_32[0xD6] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xD7] = table0F_32[0xD7] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xD8] = table0F_32[0xD8] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xD9] = table0F_32[0xD9] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xDA] = table0F_32[0xDA] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xDB] = table0F_32[0xDB] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xDC] = table0F_32[0xDC] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xDD] = table0F_32[0xDD] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xDE] = table0F_32[0xDE] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xDF] = table0F_32[0xDF] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xE0] = table0F_32[0xE0] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xE1] = table0F_32[0xE1] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xE2] = table0F_32[0xE2] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xE3] = table0F_32[0xE3] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xE4] = table0F_32[0xE4] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xE5] = table0F_32[0xE5] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xE6] = table0F_32[0xE6] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xE7] = table0F_32[0xE7] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xE8] = table0F_32[0xE8] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xE9] = table0F_32[0xE9] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xEA] = table0F_32[0xEA] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xEB] = table0F_32[0xEB] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xEC] = table0F_32[0xEC] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xED] = table0F_32[0xED] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xEE] = table0F_32[0xEE] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xEF] = table0F_32[0xEF] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xF0] = table0F_32[0xF0] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xF1] = table0F_32[0xF1] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xF2] = table0F_32[0xF2] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xF3] = table0F_32[0xF3] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xF4] = table0F_32[0xF4] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xF5] = table0F_32[0xF5] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xF6] = table0F_32[0xF6] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xF7] = table0F_32[0xF7] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xF8] = table0F_32[0xF8] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xF9] = table0F_32[0xF9] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xFA] = table0F_32[0xFA] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xFB] = table0F_32[0xFB] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xFC] = table0F_32[0xFC] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xFD] = table0F_32[0xFD] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
table0F_16[0xFE] = table0F_32[0xFE] = function(cpu) { { dbg_log("No SSE", LOG_CPU); cpu.trigger_ud();} };;
// NSA backdoor instruction
table0F_16[0xFF] = table0F_32[0xFF] = function(cpu) { { if(DEBUG) throw "Possible fault: undefined instruction"; cpu.trigger_ud();} };;
/*
* 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";
CPU.prototype.jmp_rel16 = function(rel16)
{
var current_cs = this.get_seg(reg_cs);
// limit ip to 16 bit
// ugly
this.instruction_pointer -= current_cs;
this.instruction_pointer = (this.instruction_pointer + rel16) & 0xFFFF;
this.instruction_pointer = this.instruction_pointer + current_cs | 0;
}
CPU.prototype.jmpcc16 = function(condition)
{
if(condition)
{
this.jmp_rel16(this.read_imm16());
}
else
{
this.instruction_pointer = this.instruction_pointer + 2 | 0;
}
}
CPU.prototype.jmpcc32 = function(condition)
{
if(condition)
{
// don't change to `this.instruction_pointer += this.read_imm32s()`,
// since read_imm32s modifies instruction_pointer
var imm32s = this.read_imm32s();
this.instruction_pointer = this.instruction_pointer + imm32s | 0;
}
else
{
this.instruction_pointer = this.instruction_pointer + 4 | 0;
}
}
CPU.prototype.loopne = function(imm8s)
{
if(--this.regv[this.reg_vcx] && !this.getzf())
{
this.instruction_pointer = this.instruction_pointer + imm8s | 0;
}
}
CPU.prototype.loope = function(imm8s)
{
if(--this.regv[this.reg_vcx] && this.getzf())
{
this.instruction_pointer = this.instruction_pointer + imm8s | 0;
}
}
CPU.prototype.loop = function(imm8s)
{
if(--this.regv[this.reg_vcx])
{
this.instruction_pointer = this.instruction_pointer + imm8s | 0;
}
}
CPU.prototype.jcxz = function(imm8s)
{
if(this.regv[this.reg_vcx] === 0)
{
this.instruction_pointer = this.instruction_pointer + imm8s | 0;
}
};
/**
* @return {number}
* @const
*/
CPU.prototype.getcf = function()
{
if(this.flags_changed & 1)
{
return (this.last_op1 ^ (this.last_op1 ^ this.last_op2) & (this.last_op2 ^ this.last_add_result)) >>> this.last_op_size & 1;
}
else
{
return this.flags & 1;
}
};
/** @return {number} */
CPU.prototype.getpf = function()
{
if(this.flags_changed & flag_parity)
{
// inverted lookup table
return 0x9669 << 2 >> ((this.last_result ^ this.last_result >> 4) & 0xF) & flag_parity;
}
else
{
return this.flags & flag_parity;
}
};
/** @return {number} */
CPU.prototype.getaf = function()
{
if(this.flags_changed & flag_adjust)
{
return (this.last_op1 ^ this.last_op2 ^ this.last_add_result) & flag_adjust;
}
else
{
return this.flags & flag_adjust;
}
};
/** @return {number} */
CPU.prototype.getzf = function()
{
if(this.flags_changed & flag_zero)
{
return (~this.last_result & this.last_result - 1) >>> this.last_op_size & 1;
}
else
{
return this.flags & flag_zero;
}
};
/** @return {number} */
CPU.prototype.getsf = function()
{
if(this.flags_changed & flag_sign)
{
return this.last_result >>> this.last_op_size & 1;
}
else
{
return this.flags & flag_sign;
}
};
/** @return {number} */
CPU.prototype.getof = function()
{
if(this.flags_changed & flag_overflow)
{
return ((this.last_op1 ^ this.last_add_result) & (this.last_op2 ^ this.last_add_result)) >>> this.last_op_size & 1;
}
else
{
return this.flags & flag_overflow;
}
};
CPU.prototype.test_o = CPU.prototype.getof;
CPU.prototype.test_b = CPU.prototype.getcf;
CPU.prototype.test_z = CPU.prototype.getzf;
CPU.prototype.test_s = CPU.prototype.getsf;
CPU.prototype.test_p = CPU.prototype.getpf;
CPU.prototype.test_be = function()
{
// Idea:
// return this.last_op1 <= this.last_op2;
return this.getcf() || this.getzf();
}
CPU.prototype.test_l = function()
{
// Idea:
// return this.last_add_result < this.last_op2;
return !this.getsf() !== !this.getof();
}
CPU.prototype.test_le = function()
{
// Idea:
// return this.last_add_result <= this.last_op2;
return this.getzf() || !this.getsf() !== !this.getof();
}
CPU.prototype.push16 = function(imm16)
{
var sp = this.get_stack_pointer(-2);
this.safe_write16(sp, imm16);
this.stack_reg[this.reg_vsp] -= 2;
}
CPU.prototype.push32 = function(imm32)
{
var sp = this.get_stack_pointer(-4);
this.safe_write32(sp, imm32);
this.stack_reg[this.reg_vsp] -= 4;
}
CPU.prototype.pop16 = function()
{
var sp = this.get_seg(reg_ss) + this.stack_reg[this.reg_vsp] | 0,
result = this.safe_read16(sp);
this.stack_reg[this.reg_vsp] += 2;
return result;
}
CPU.prototype.pop32s = function()
{
var sp = this.get_seg(reg_ss) + this.stack_reg[this.reg_vsp] | 0,
result = this.safe_read32s(sp);
this.stack_reg[this.reg_vsp] += 4;
return result;
}
CPU.prototype.pusha16 = function()
{
var temp = this.reg16[reg_sp];
// make sure we don't get a pagefault after having
// pushed several registers already
this.translate_address_write(this.get_seg(reg_ss) + this.stack_reg[this.reg_vsp] - 15 | 0);
this.push16(this.reg16[reg_ax]);
this.push16(this.reg16[reg_cx]);
this.push16(this.reg16[reg_dx]);
this.push16(this.reg16[reg_bx]);
this.push16(temp);
this.push16(this.reg16[reg_bp]);
this.push16(this.reg16[reg_si]);
this.push16(this.reg16[reg_di]);
}
CPU.prototype.pusha32 = function()
{
var temp = this.reg32s[reg_esp];
this.translate_address_write(this.get_seg(reg_ss) + this.stack_reg[this.reg_vsp] - 31 | 0);
this.push32(this.reg32s[reg_eax]);
this.push32(this.reg32s[reg_ecx]);
this.push32(this.reg32s[reg_edx]);
this.push32(this.reg32s[reg_ebx]);
this.push32(temp);
this.push32(this.reg32s[reg_ebp]);
this.push32(this.reg32s[reg_esi]);
this.push32(this.reg32s[reg_edi]);
}
CPU.prototype.popa16 = function()
{
this.translate_address_read(this.get_seg(reg_ss) + this.stack_reg[this.reg_vsp] + 15 | 0);
this.reg16[reg_di] = this.pop16();
this.reg16[reg_si] = this.pop16();
this.reg16[reg_bp] = this.pop16();
this.stack_reg[this.reg_vsp] += 2;
this.reg16[reg_bx] = this.pop16();
this.reg16[reg_dx] = this.pop16();
this.reg16[reg_cx] = this.pop16();
this.reg16[reg_ax] = this.pop16();
}
CPU.prototype.popa32 = function()
{
this.translate_address_read(this.get_seg(reg_ss) + this.stack_reg[this.reg_vsp] + 31 | 0);
this.reg32s[reg_edi] = this.pop32s();
this.reg32s[reg_esi] = this.pop32s();
this.reg32s[reg_ebp] = this.pop32s();
this.stack_reg[this.reg_vsp] += 4;
this.reg32s[reg_ebx] = this.pop32s();
this.reg32s[reg_edx] = this.pop32s();
this.reg32s[reg_ecx] = this.pop32s();
this.reg32s[reg_eax] = this.pop32s();
}
CPU.prototype.xchg8 = function(memory_data, modrm_byte)
{
var mod = modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1,
tmp = this.reg8[mod];
this.reg8[mod] = memory_data;
return tmp;
}
CPU.prototype.xchg16 = function(memory_data, modrm_byte)
{
var mod = modrm_byte >> 2 & 14,
tmp = this.reg16[mod];
this.reg16[mod] = memory_data;
return tmp;
}
CPU.prototype.xchg16r = function(operand)
{
var temp = this.reg16[reg_ax];
this.reg16[reg_ax] = this.reg16[operand];
this.reg16[operand] = temp;
}
CPU.prototype.xchg32 = function(memory_data, modrm_byte)
{
var mod = modrm_byte >> 3 & 7,
tmp = this.reg32s[mod];
this.reg32s[mod] = memory_data;
return tmp;
}
CPU.prototype.xchg32r = function(operand)
{
var temp = this.reg32s[reg_eax];
this.reg32s[reg_eax] = this.reg32s[operand];
this.reg32s[operand] = temp;
}
CPU.prototype.lss16 = function(seg, addr, mod)
{
var new_reg = this.safe_read16(addr),
new_seg = this.safe_read16(addr + 2 | 0);
this.switch_seg(seg, new_seg);
this.reg16[mod] = new_reg;
}
CPU.prototype.lss32 = function(seg, addr, mod)
{
var new_reg = this.safe_read32s(addr),
new_seg = this.safe_read16(addr + 4 | 0);
this.switch_seg(seg, new_seg);
this.reg32s[mod] = new_reg;
}
CPU.prototype.enter16 = function(size, nesting_level)
{
nesting_level &= 31;
var frame_temp;
var tmp_ebp;
//dbg_log("enter16 stack=" + (this.stack_size_32 ? 32 : 16) + " size=" + size + " nest=" + nesting_level, LOG_CPU);
this.push16(this.reg16[reg_bp]);
frame_temp = this.reg16[reg_sp];
if(nesting_level > 0)
{
tmp_ebp = this.reg16[reg_ebp];
for(var i = 1; i < nesting_level; i++)
{
tmp_ebp -= 2;
this.push16(this.safe_read16(this.get_seg(reg_ss) + tmp_ebp | 0));
}
this.push16(frame_temp);
}
this.reg16[reg_bp] = frame_temp;
this.reg16[reg_sp] -= size;
};
CPU.prototype.enter32 = function(size, nesting_level)
{
nesting_level &= 31;
var frame_temp;
var tmp_ebp;
//dbg_log("enter32 stack=" + (this.stack_size_32 ? 32 : 16) + " size=" + size + " nest=" + nesting_level, LOG_CPU);
this.push32(this.reg32s[reg_ebp]);
frame_temp = this.reg32s[reg_esp];
if(nesting_level > 0)
{
tmp_ebp = this.reg32s[reg_ebp];
for(var i = 1; i < nesting_level; i++)
{
tmp_ebp -= 4;
this.push32(this.safe_read32s(this.get_seg(reg_ss) + tmp_ebp | 0));
}
this.push32(frame_temp);
}
this.reg32s[reg_ebp] = frame_temp;
this.reg32s[reg_esp] -= size;
};
CPU.prototype.bswap = function(reg)
{
var temp = this.reg32s[reg];
this.reg32s[reg] = temp >>> 24 | temp << 24 | (temp >> 8 & 0xFF00) | (temp << 8 & 0xFF0000);
}
/**
* @return {number} time in ms until this method should becalled again
*/
CPU.prototype.main_run = function()
{
try
{
if(this.in_hlt)
{
var t = this.hlt_loop();
return 0;
//return t;
}
else
{
this.do_run();
}
}
catch(e)
{
this.exception_cleanup(e);
}
return 0;
};
CPU.prototype.exception_cleanup = function(e)
{
if(e === MAGIC_CPU_EXCEPTION)
{
// 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
this.page_fault = false;
// restore state from prefixes
this.clear_prefixes();
//this.main_run();
}
else
{
console.log(e);
console.log(e.stack);
//var e = new Error(e.message);
//Error.captureStackTrace && Error.captureStackTrace(e);
throw e;
}
}
CPU.prototype.reboot_internal = function()
{
this.reset();
this.load_bios();
throw MAGIC_CPU_EXCEPTION;
};
CPU.prototype.reset = function()
{
this.segment_is_null = new Uint8Array(8);
this.segment_limits = new Uint32Array(8);
//this.segment_infos = new Uint32Array(8);
this.segment_offsets = new Int32Array(8);
this.full_clear_tlb();
this.reg32s = new Int32Array(8);
this.reg32 = new Uint32Array(this.reg32s.buffer);
this.reg16s = new Int16Array(this.reg32s.buffer);
this.reg16 = new Uint16Array(this.reg32s.buffer);
this.reg8s = new Int8Array(this.reg32s.buffer);
this.reg8 = new Uint8Array(this.reg32s.buffer);
this.sreg = new Uint16Array(8);
this.dreg = new Int32Array(8);
this.protected_mode = false;
// http://www.sandpile.org/x86/initial.htm
this.idtr_size = 0;
this.idtr_offset = 0;
this.gdtr_size = 0;
this.gdtr_offset = 0;
this.page_fault = false;
this.cr[0] = 1 << 30 | 1 << 29 | 1 << 4;
this.cr[2] = 0;
this.cr[3] = 0;
this.cr[4] = 0;
this.dreg[6] = 0xFFFF0FF0|0;
this.dreg[7] = 0x400;
this.cpl = 0;
this.paging = false;
this.page_size_extensions = 0;
this.is_32 = false;
this.operand_size_32 = false;
this.stack_size_32 = false;
this.address_size_32 = false;
this.paging_changed();
this.update_operand_size();
this.update_address_size();
this.stack_reg = this.reg16;
this.reg_vsp = reg_sp;
this.reg_vbp = reg_bp;
this.timestamp_counter = 0;
this.previous_ip = 0;
this.in_hlt = false;
this.sysenter_cs = 0;
this.sysenter_esp = 0;
this.sysenter_eip = 0;
this.segment_prefix = SEG_PREFIX_NONE;
this.repeat_string_prefix = REPEAT_STRING_PREFIX_NONE;
this.flags = flags_default;
this.flags_changed = 0;
this.last_result = 0;
this.last_add_result = 0;
this.last_op1 = 0;
this.last_op2 = 0;
this.last_op_size = 0;
this.tsc_offset = v86.microtick();
this.instruction_pointer = 0xFFFF0;
this.switch_seg(reg_ss, 0x30);
this.reg16[reg_sp] = 0x100;
if(this.devices.virtio)
{
this.devices.virtio.reset();
}
};
CPU.prototype.init = function(settings, device_bus)
{
this.memory_size = settings.memory_size || 1024 * 1024 * 64;
this.memory = new Memory(this.memory_size);
this.reset();
if(OP_TRANSLATION)
{
this.translator = new DynamicTranslator(this);
}
var io = new IO(this.memory);
this.io = io;
this.bios.main = settings.bios;
this.bios.vga = settings.vga_bios;
this.load_bios();
var a20_byte = 0;
io.register_read(0x92, this, function()
{
return a20_byte;
});
io.register_write(0x92, this, function(out_byte)
{
a20_byte = out_byte;
});
if(DEBUG)
{
// Use by linux for port-IO delay
// Avoid generating tons of debug messages
io.register_write(0x80, this, function(out_byte)
{
});
}
this.devices = {};
// TODO: Make this more configurable
if(settings.load_devices)
{
this.devices.pic = new PIC(this);
if(ENABLE_ACPI)
{
this.devices.apic = new APIC(this);
this.devices.acpi = new ACPI(this);
}
this.devices.rtc = new RTC(this);
this.fill_cmos(this.devices.rtc, settings);
this.devices.pci = new PCI(this);
this.devices.dma = new DMA(this);
if(ENABLE_HPET)
{
this.devices.hpet = new HPET(this);
}
this.devices.vga = new VGAScreen(this, device_bus,
settings.vga_memory_size || 8 * 1024 * 1024);
this.fpu = new FPU(this);
this.devices.ps2 = new PS2(this, device_bus);
this.devices.uart = new UART(this, 0x3F8, device_bus);
this.devices.fdc = new FloppyController(this, settings.fda, settings.fdb);
if(settings.cdrom)
{
this.devices.cdrom = new IDEDevice(this, settings.cdrom, true, 1, device_bus);
}
if(settings.hda)
{
this.devices.hda = new IDEDevice(this, settings.hda, false, 0, device_bus);
}
else
{
//this.devices.hda = new IDEDevice(this, undefined, false, 0, device_bus);
}
//if(settings.hdb)
//{
// this.devices.hdb = hdb = new IDEDevice(this, settings.hdb, false, 1, device_bus);
//}
this.devices.pit = new PIT(this);
if(settings.enable_ne2k)
{
this.devices.net = new Ne2k(this, device_bus);
}
if(settings.fs9p)
{
this.devices.virtio = new VirtIO(this, device_bus, settings.fs9p);
}
}
if(DEBUG)
{
this.debug.init();
}
};
CPU.prototype.fill_cmos = function(rtc, settings)
{
var boot_order = settings.boot_order || 0x213;
// Used by seabios to determine the boot order
// Nibble
// 1: FloppyPrio
// 2: HDPrio
// 3: CDPrio
// 4: BEVPrio
// bootflag 1, high nibble, lowest priority
// Low nibble: Disable floppy signature check (1)
this.devices.rtc.cmos_write(CMOS_BIOS_BOOTFLAG1 , 1 | boot_order >> 4 & 0xF0);
// bootflag 2, both nibbles, high and middle priority
this.devices.rtc.cmos_write(CMOS_BIOS_BOOTFLAG2, boot_order & 0xFF);
var memory_above_16m = this.memory_size - 16 * 1024 * 1024;
this.devices.rtc.cmos_write(CMOS_MEM_EXTMEM2_LOW,
memory_above_16m >> 16 & 0xFF);
this.devices.rtc.cmos_write(CMOS_MEM_EXTMEM2_HIGH,
memory_above_16m >> 24 & 0xFF);
// memory above 4G
this.devices.rtc.cmos_write(CMOS_MEM_HIGHMEM_LOW, 0);
this.devices.rtc.cmos_write(CMOS_MEM_HIGHMEM_MID, 0);
this.devices.rtc.cmos_write(CMOS_MEM_HIGHMEM_HIGH, 0);
this.devices.rtc.cmos_write(CMOS_EQUIPMENT_INFO, 0x2D);
};
CPU.prototype.load_bios = function()
{
var bios = this.bios.main;
var vga_bios = this.bios.vga;
if(!bios)
{
dbg_log("Warning: No BIOS");
return;
}
// load bios
var data = new Uint8Array(bios),
start = 0x100000 - bios.byteLength;
this.memory.mem8.set(data, start);
if(vga_bios)
{
// load vga bios
data = new Uint8Array(vga_bios);
this.memory.mem8.set(data, 0xC0000);
}
else
{
dbg_log("Warning: No VGA BIOS");
}
// seabios expects the bios to be mapped to 0xFFF00000 also
this.io.mmap_register(0xFFF00000, 0x100000,
function(addr)
{
addr &= 0xFFFFF;
return this.memory.mem8[addr];
//return data[start + addr];
}.bind(this),
function(addr, value)
{
addr &= 0xFFFFF;
this.memory.mem8[addr] = value;
//data[start + addr] = value;
}.bind(this));
};
CPU.prototype.do_run = function()
{
var
/**
* @type {number}
*/
start = Date.now(),
now = start;
// outer loop:
// runs cycles + timers
for(; now - start < TIME_PER_FRAME;)
{
if(ENABLE_HPET)
{
this.devices.pit.timer(now, this.devices.hpet.legacy_mode);
this.devices.rtc.timer(now, this.devices.hpet.legacy_mode);
this.devices.hpet.timer(now);
}
else
{
this.devices.pit.timer(now, false);
this.devices.rtc.timer(now, false);
}
this.handle_irqs();
// inner loop:
// runs only cycles
for(var k = LOOP_COUNTER; k--;)
{
if(OP_TRANSLATION)
{
this.cycle_translated();
}
else
{
this.cycle();
}
}
now = Date.now();
}
};
// 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_inline1 = CPU.prototype.do_run;
window.__no_inline2 = CPU.prototype.exception_cleanup;
window.__no_inline3 = CPU.prototype.hlt_loop;
};
var prefixes = {};
/**
* execute a single instruction cycle on the cpu
* this includes reading all prefixes and the whole instruction
*/
CPU.prototype.cycle = function()
{
this.previous_ip = this.instruction_pointer;
//var op = this.safe_read32s(this.instruction_pointer);
//var op = this.safe_read16(this.instruction_pointer);
//var op2 = this.safe_read16(this.instruction_pointer + 4);
//prefixes[op + op2 * 0x100000000] = true;
//prefixes[op] = ~~prefixes[op] + 1 | 0;
this.timestamp_counter++;
var opcode = this.read_imm8();
if(DEBUG)
{
this.debug.logop(this.instruction_pointer - 1 >>> 0, opcode);
}
// call the instruction
this.table[opcode](this);
if(this.flags & flag_trap)
{
// TODO
dbg_log("Trap flag: Ignored", LOG_CPU);
}
};
CPU.prototype.cycle_translated = function()
{
this.previous_ip = this.instruction_pointer;
this.timestamp_counter++;
this.large_table[this.get_imm16() | 0](this);
};
CPU.prototype.do_op = function()
{
this.table[this.read_imm8()](this);
};
CPU.prototype.hlt_loop = function()
{
//dbg_log("In HLT loop", LOG_CPU);
var now = Date.now();
if(ENABLE_HPET)
{
var pit_time = this.devices.pit.timer(now, this.devices.hpet.legacy_mode);
var rtc_time = this.devices.rtc.timer(now, this.devices.hpet.legacy_mode);
this.devices.hpet.timer(now);
}
else
{
var pit_time = this.devices.pit.timer(now, false);
var rtc_time = this.devices.rtc.timer(now, false);
}
return 0;
if(!this.in_hlt)
{
return 0;
}
else
{
return Math.ceil(Math.min(100, pit_time, rtc_time));
}
};
CPU.prototype.clear_prefixes = function()
{
this.repeat_string_prefix = REPEAT_STRING_PREFIX_NONE;
this.segment_prefix = SEG_PREFIX_NONE;
if(this.address_size_32 !== this.is_32)
{
this.address_size_32 = this.is_32;
this.update_address_size();
}
if(this.operand_size_32 !== this.is_32)
{
this.operand_size_32 = this.is_32;
this.update_operand_size();
}
};
CPU.prototype.cr0_changed = function(old_cr0)
{
//dbg_log("cr0 = " + h(this.cr[0] >>> 0), LOG_CPU);
var new_paging = (this.cr[0] & CR0_PG) === CR0_PG;
if(!this.fpu)
{
// if there's no FPU, keep emulation set
this.cr[0] |= CR0_EM;
}
this.cr[0] |= CR0_ET;
dbg_assert(typeof this.paging === "boolean");
if(new_paging !== this.paging)
{
this.paging = new_paging;
this.full_clear_tlb();
}
if(OP_TRANSLATION && (this.cr[0] ^ old_cr0) & 1)
{
this.translator.clear_cache();
}
};
CPU.prototype.paging_changed = function()
{
this.last_virt_eip = -1;
this.last_virt_esp = -1;
};
CPU.prototype.cpl_changed = function()
{
this.last_virt_eip = -1;
this.last_virt_esp = -1;
};
CPU.prototype.get_phys_eip = function()
{
if((this.instruction_pointer & ~0xFFF) ^ this.last_virt_eip)
{
this.eip_phys = this.translate_address_read(this.instruction_pointer) ^ this.instruction_pointer;
this.last_virt_eip = this.instruction_pointer & ~0xFFF;
}
return this.eip_phys ^ this.instruction_pointer;
};
CPU.prototype.read_imm8 = function()
{
//return this.safe_read8(this.instruction_pointer++);
if((this.instruction_pointer & ~0xFFF) ^ this.last_virt_eip)
{
this.eip_phys = this.translate_address_read(this.instruction_pointer) ^ this.instruction_pointer;
this.last_virt_eip = this.instruction_pointer & ~0xFFF;
}
// memory.read8 inlined under the assumption that code never runs in
// memory-mapped space
//var data8 = this.memory.mem8[this.eip_phys ^ this.instruction_pointer] | 0;
var data8 = this.memory.read8(this.eip_phys ^ this.instruction_pointer);
this.instruction_pointer = this.instruction_pointer + 1 | 0;
return data8;
};
CPU.prototype.read_imm8s = function()
{
return this.read_imm8() << 24 >> 24;
};
CPU.prototype.read_imm16 = function()
{
//this.instruction_pointer += 2;
//return this.safe_read16(this.instruction_pointer - 2);
// Two checks in one comparison:
// 1. Did the high 20 bits of eip change
// or 2. Are the low 12 bits of eip 0xFFF (and this read crosses a page boundary)
if(((this.instruction_pointer ^ this.last_virt_eip) >>> 0) > 0xFFE)
{
return this.read_imm8() | this.read_imm8() << 8;
}
var data16 = this.memory.read16(this.eip_phys ^ this.instruction_pointer);
this.instruction_pointer = this.instruction_pointer + 2 | 0;
return data16;
};
CPU.prototype.read_imm16s = function()
{
return this.read_imm16() << 16 >> 16;
};
CPU.prototype.read_imm32s = function()
{
//this.instruction_pointer += 4;
//return this.safe_read32s(this.instruction_pointer - 4);
// Analogue to the above comment
if(((this.instruction_pointer ^ this.last_virt_eip) >>> 0) > 0xFFC)
{
return this.read_imm16() | this.read_imm16() << 16;
}
var data32 = this.memory.read32s(this.eip_phys ^ this.instruction_pointer);
this.instruction_pointer = this.instruction_pointer + 4 | 0;
return data32;
};
CPU.prototype.get_imm16 = function()
{
return this.safe_read16(this.instruction_pointer);
//if(((this.instruction_pointer ^ this.last_virt_eip) >>> 0) > 0xFFE)
//{
// return this.safe_read16(this.instruction_pointer);
//}
//return this.memory.read16(this.eip_phys ^ this.instruction_pointer);
};
CPU.prototype.get_imm32s = function()
{
if(((this.instruction_pointer ^ this.last_virt_eip) >>> 0) > 0xFFC)
{
return this.safe_read32s(this.instruction_pointer);
}
return this.memory.read32s(this.eip_phys ^ this.instruction_pointer);
};
// read word from a page boundary, given 2 physical addresses
CPU.prototype.virt_boundary_read16 = function(low, high)
{
dbg_assert((low & 0xFFF) === 0xFFF);
dbg_assert((high & 0xFFF) === 0);
return this.memory.read8(low) | this.memory.read8(high) << 8;
};
// read doubleword from a page boundary, given 2 addresses
CPU.prototype.virt_boundary_read32s = function(low, high)
{
dbg_assert((low & 0xFFF) >= 0xFFD);
dbg_assert((high - 3 & 0xFFF) === (low & 0xFFF));
var mid;
if(low & 1)
{
if(low & 2)
{
// 0xFFF
mid = this.memory.read_aligned16(high - 2 >> 1);
}
else
{
// 0xFFD
mid = this.memory.read_aligned16(low + 1 >> 1);
}
}
else
{
// 0xFFE
mid = this.virt_boundary_read16(low + 1 | 0, high - 1 | 0);
}
return this.memory.read8(low) | mid << 8 | this.memory.read8(high) << 24;;
};
CPU.prototype.virt_boundary_write16 = function(low, high, value)
{
dbg_assert((low & 0xFFF) === 0xFFF);
dbg_assert((high & 0xFFF) === 0);
this.memory.write8(low, value);
this.memory.write8(high, value >> 8);
};
CPU.prototype.virt_boundary_write32 = function(low, high, value)
{
dbg_assert((low & 0xFFF) >= 0xFFD);
dbg_assert((high - 3 & 0xFFF) === (low & 0xFFF));
this.memory.write8(low, value);
this.memory.write8(high, value >> 24);
if(low & 1)
{
if(low & 2)
{
// 0xFFF
this.memory.write8(high - 2, value >> 8);
this.memory.write8(high - 1, value >> 16);
}
else
{
// 0xFFD
this.memory.write8(low + 1 | 0, value >> 8);
this.memory.write8(low + 2 | 0, value >> 16);
}
}
else
{
// 0xFFE
this.memory.write8(low + 1 | 0, value >> 8);
this.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
CPU.prototype.safe_read8 = function(addr)
{
dbg_assert(addr < 0x80000000);
return this.memory.read8(this.translate_address_read(addr));
};
CPU.prototype.safe_read16 = function(addr)
{
if(this.paging && (addr & 0xFFF) === 0xFFF)
{
return this.safe_read8(addr) | this.safe_read8(addr + 1 | 0) << 8;
}
else
{
return this.memory.read16(this.translate_address_read(addr));
}
};
CPU.prototype.safe_read32s = function(addr)
{
if(this.paging && (addr & 0xFFF) >= 0xFFD)
{
return this.safe_read16(addr) | this.safe_read16(addr + 2 | 0) << 16;
}
else
{
return this.memory.read32s(this.translate_address_read(addr));
}
};
CPU.prototype.safe_write8 = function(addr, value)
{
dbg_assert(addr < 0x80000000);
this.memory.write8(this.translate_address_write(addr), value);
};
CPU.prototype.safe_write16 = function(addr, value)
{
var phys_low = this.translate_address_write(addr);
if((addr & 0xFFF) === 0xFFF)
{
this.virt_boundary_write16(phys_low, this.translate_address_write(addr + 1 | 0), value);
}
else
{
this.memory.write16(phys_low, value);
}
};
CPU.prototype.safe_write32 = function(addr, value)
{
var phys_low = this.translate_address_write(addr);
if((addr & 0xFFF) >= 0xFFD)
{
this.virt_boundary_write32(phys_low, this.translate_address_write(addr + 3 | 0), value);
}
else
{
this.memory.write32(phys_low, value);
}
};
// read 2 or 4 byte from ip, depending on address size attribute
CPU.prototype.read_moffs = function()
{
if(this.address_size_32)
{
return this.get_seg_prefix(reg_ds) + this.read_imm32s() | 0;
}
else
{
return this.get_seg_prefix(reg_ds) + this.read_imm16() | 0;
}
};
CPU.prototype.getiopl = function()
{
return this.flags >> 12 & 3;
};
CPU.prototype.vm86_mode = function()
{
return !!(this.flags & flag_vm);
};
CPU.prototype.get_eflags = function()
{
return (this.flags & ~flags_all) | !!this.getcf() | !!this.getpf() << 2 | !!this.getaf() << 4 |
!!this.getzf() << 6 | !!this.getsf() << 7 | !!this.getof() << 11;
};
CPU.prototype.load_eflags = function()
{
this.flags = this.get_eflags();
this.flags_changed = 0;
};
/**
* Update the flags register depending on iopl and cpl
*/
CPU.prototype.update_eflags = function(new_flags)
{
var dont_update = flag_rf | flag_vm | flag_vip | flag_vif,
clear = ~flag_vip & ~flag_vif & flags_mask;
if(this.flags & flag_vm)
{
// other case needs to be handled in popf or iret
dbg_assert(this.getiopl() === 3);
dont_update |= flag_iopl;
// don't clear vip or vif
clear |= flag_vip | flag_vif;
}
else
{
if(!this.protected_mode) dbg_assert(this.cpl === 0);
if(this.cpl)
{
// cpl > 0
// cannot update iopl
dont_update |= flag_iopl;
if(this.cpl > this.getiopl())
{
// cpl > iopl
// cannot update interrupt flag
dont_update |= flag_interrupt;
}
}
}
this.flags = (new_flags ^ ((this.flags ^ new_flags) & dont_update)) & clear | flags_default;
this.flags_changed = 0;
};
CPU.prototype.get_stack_pointer = function(mod)
{
if(this.stack_size_32)
{
return this.get_seg(reg_ss) + this.stack_reg[this.reg_vsp] + mod | 0;
}
else
{
return this.get_seg(reg_ss) + (this.stack_reg[this.reg_vsp] + mod & 0xFFFF) | 0;
}
};
/*
* returns the "real" instruction pointer,
* without segment offset
*/
CPU.prototype.get_real_eip = function()
{
return this.instruction_pointer - this.get_seg(reg_cs) | 0;
};
CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, error_code)
{
dbg_assert(this.instruction_pointer !== undefined);
if(DEBUG && this.debug.step_mode)
{
//this.debug.ops.add(this.instruction_pointer >>> 0);
//this.debug.ops.add("-- INT " + h(interrupt_nr));
//this.debug.ops.add(1);
}
//if(interrupt_nr == 0x10)
//{
// dbg_log("int10 ax=" + h(this.reg16[reg_ax], 4) + " '" + String.fromCharCode(this.reg8[reg_al]) + "'");
// this.debug.dump_regs_short();
// if(this.reg8[reg_ah] == 0xe) vga.tt_write(this.reg8[reg_al]);
//}
//if(interrupt_nr === 0x13)
//{
// this.debug.dump_regs_short();
//}
//if(interrupt_nr === 6)
//{
// this.instruction_pointer += 2;
// dbg_log("BUG()", LOG_CPU);
// dbg_log("line=" + this.read_imm16() + " " +
// "file=" + this.memory.read_string(this.translate_address_read(this.read_imm32s())), LOG_CPU);
// this.instruction_pointer -= 8;
// this.debug.dump_regs_short();
//}
//if(interrupt_nr === 0x80)
//{
// dbg_log("linux syscall");
// this.debug.dump_regs_short();
//}
//if(interrupt_nr === 14)
//{
// dbg_log("int14 error_code=" + error_code +
// " cr2=" + h(this.cr[2] >>> 0) +
// " prev=" + h(this.previous_ip >>> 0) +
// " cpl=" + this.cpl, LOG_CPU);
//}
//if(interrupt_nr === 0x40)
//{
// dbg_log("kolibri syscall");
// this.debug.dump_regs_short();
//}
// we have to leave hlt_loop at some point, this is a
// good place to do it
//this.in_hlt && dbg_log("Leave HLT loop", LOG_CPU);
this.in_hlt = false;
if(this.protected_mode)
{
if(this.vm86_mode() && (this.cr[4] & CR4_VME))
{
throw this.debug.unimpl("VME");
}
if(this.vm86_mode() && is_software_int && this.getiopl() < 3)
{
this.trigger_gp(0);
}
if((interrupt_nr << 3 | 7) > this.idtr_size)
{
dbg_log(interrupt_nr, LOG_CPU);
dbg_trace(LOG_CPU);
throw this.debug.unimpl("#GP handler");
}
var addr = this.idtr_offset + (interrupt_nr << 3) | 0;
dbg_assert((addr & 0xFFF) < 0xFF8);
if(this.paging)
{
addr = this.translate_address_system_read(addr);
}
var base = this.memory.read16(addr) | this.memory.read16(addr + 6 | 0) << 16,
selector = this.memory.read16(addr + 2 | 0),
type = this.memory.read8(addr + 5 | 0),
dpl = type >> 5 & 3,
is_trap,
is_16 = false;
if((type & 128) === 0)
{
// present bit not set
throw this.debug.unimpl("#NP handler");
}
if(is_software_int && dpl < this.cpl)
{
this.trigger_gp(interrupt_nr << 3 | 2);
}
type &= 31;
if(type === 14)
{
is_trap = false;
is_16 = false;
}
else if(type === 15)
{
is_trap = true;
is_16 = false;
}
else if(type === 5)
{
// task gate
dbg_trace();
dbg_log("interrupt to task gate: int=" + h(interrupt_nr, 2) + " sel=" + h(selector, 4) + " dpl=" + dpl, LOG_CPU);
this.do_task_switch(selector);
if(error_code !== false)
{
dbg_assert(typeof error_code == "number");
// TODO: push16 if in 16 bit mode?
this.push32(error_code);
}
return;
}
else if(type === 6)
{
// 16 bit interrupt gate
throw this.debug.unimpl("16 bit interrupt gate");
is_trap = false;
is_16 = true;
}
else if(type === 7)
{
// 16 bit trap gate
is_trap = true;
is_16 = true;
}
else
{
// invalid type
dbg_trace(LOG_CPU);
dbg_log("invalid type: " + h(type));
dbg_log(h(addr) + " " + h(base >>> 0) + " " + h(selector));
throw this.debug.unimpl("#GP handler");
}
var info = this.lookup_segment_selector(selector);
if(info.is_null)
{
dbg_log("is null");
throw this.debug.unimpl("#GP handler");
}
if(!info.is_executable || info.dpl > this.cpl)
{
dbg_log("not exec");
throw this.debug.unimpl("#GP handler");
}
if(!info.is_present)
{
dbg_log("not present");
throw this.debug.unimpl("#NP handler");
}
this.load_eflags();
var old_flags = this.flags;
if(!info.dc_bit && info.dpl < this.cpl)
{
// inter privilege level interrupt
// interrupt from vm86 mode
//dbg_log("Inter privilege interrupt gate=" + h(selector, 4) + ":" + h(base >>> 0, 8) + " trap=" + is_trap + " 16bit=" + is_16, LOG_CPU);
//this.debug.dump_regs_short();
var tss_stack_addr = (info.dpl << 3) + 4 | 0;
if((tss_stack_addr + 5 | 0) > this.segment_limits[reg_tr])
{
throw this.debug.unimpl("#TS handler");
}
tss_stack_addr = tss_stack_addr + this.segment_offsets[reg_tr] | 0;
if(this.paging)
{
tss_stack_addr = this.translate_address_system_read(tss_stack_addr);
}
var new_esp = this.memory.read32s(tss_stack_addr),
new_ss = this.memory.read16(tss_stack_addr + 4 | 0),
ss_info = this.lookup_segment_selector(new_ss);
if(ss_info.is_null)
{
throw this.debug.unimpl("#TS handler");
}
if(ss_info.rpl !== info.dpl)
{
throw this.debug.unimpl("#TS handler");
}
if(ss_info.dpl !== info.dpl || !ss_info.rw_bit)
{
throw this.debug.unimpl("#TS handler");
}
if(!ss_info.is_present)
{
throw this.debug.unimpl("#TS handler");
}
var old_esp = this.reg32s[reg_esp],
old_ss = this.sreg[reg_ss];
if(old_flags & flag_vm)
{
//dbg_log("return from vm86 mode");
//this.debug.dump_regs_short();
dbg_assert(info.dpl === 0, "switch to non-0 dpl from vm86 mode");
}
this.cpl = info.dpl;
//dbg_log("int" + h(interrupt_nr, 2) +" from=" + h(this.instruction_pointer >>> 0, 8)
// + " cpl=" + this.cpl + " old ss:esp=" + h(old_ss, 4) + ":" + h(old_esp >>> 0, 8), LOG_CPU);
this.cpl_changed();
dbg_assert(typeof info.size === "boolean");
if(this.is_32 !== info.size)
{
this.update_cs_size(info.size);
}
this.flags &= ~flag_vm & ~flag_rf;
this.switch_seg(reg_ss, new_ss);
this.stack_reg[this.reg_vsp] = new_esp;
if(old_flags & flag_vm)
{
if(is_16)
{
this.writable_or_pagefault(this.get_stack_pointer(-20), 20);
this.push16(this.sreg[reg_gs]);
this.push16(this.sreg[reg_fs]);
this.push16(this.sreg[reg_ds]);
this.push16(this.sreg[reg_es]);
}
else
{
this.writable_or_pagefault(this.get_stack_pointer(-40), 40);
this.push32(this.sreg[reg_gs]);
this.push32(this.sreg[reg_fs]);
this.push32(this.sreg[reg_ds]);
this.push32(this.sreg[reg_es]);
}
}
else
{
if(is_16)
{
this.writable_or_pagefault(this.get_stack_pointer(-12), 12);
}
else
{
this.writable_or_pagefault(this.get_stack_pointer(-24), 24);
}
}
if(is_16)
{
this.push16(old_ss);
this.push16(old_esp);
}
else
{
this.push32(old_ss);
this.push32(old_esp);
}
//dbg_log("esp pushed to " + h(this.get_stack_pointer(0) >>> 0));
}
else if(info.dc_bit || info.dpl === this.cpl)
{
//dbg_log("Intra privilege interrupt gate=" + h(selector, 4) + ":" + h(base >>> 0, 8) +
// " trap=" + is_trap + " 16bit=" + is_16 +
// " cpl=" + this.cpl + " dpl=" + info.dpl + " conforming=" + +info.dc_bit, LOG_CPU);
//this.debug.dump_regs_short();
if(is_16)
{
this.writable_or_pagefault(this.get_stack_pointer(-8), 8);
}
else
{
this.writable_or_pagefault(this.get_stack_pointer(-16), 16);
}
if(this.flags & flag_vm)
{
dbg_log("xxx");
this.trigger_gp(selector & ~3);
}
// intra privilege level interrupt
//dbg_log("int" + h(interrupt_nr, 2) +" from=" + h(this.instruction_pointer, 8), LOG_CPU);
}
else
{
throw this.debug.unimpl("#GP handler");
}
if(is_16)
{
this.push16(old_flags);
this.push16(this.sreg[reg_cs]);
this.push16(this.get_real_eip());
if(error_code !== false)
{
dbg_assert(typeof error_code == "number");
this.push16(error_code);
}
base &= 0xFFFF;
}
else
{
this.push32(old_flags);
this.push32(this.sreg[reg_cs]);
this.push32(this.get_real_eip());
//dbg_log("pushed eip to " + h(this.reg32s[reg_esp], 8), LOG_CPU);
if(error_code !== false)
{
dbg_assert(typeof error_code == "number");
this.push32(error_code);
}
}
if(old_flags & flag_vm)
{
this.switch_seg(reg_gs, 0);
this.switch_seg(reg_fs, 0);
this.switch_seg(reg_ds, 0);
this.switch_seg(reg_es, 0);
}
// TODO
this.sreg[reg_cs] = selector & ~3 | this.cpl;
//this.switch_seg(reg_cs);
dbg_assert(typeof info.size === "boolean");
dbg_assert(typeof this.is_32 === "boolean");
if(this.is_32 !== info.size)
{
this.update_cs_size(info.size);
}
this.segment_limits[reg_cs] = info.effective_limit;
this.segment_offsets[reg_cs] = info.base;
//dbg_log("current esp: " + h(this.reg32s[reg_esp] >>> 0, 8), LOG_CPU);
//dbg_log("call int " + h(interrupt_nr >>> 0, 8) +
// " from " + h(this.instruction_pointer >>> 0, 8) +
// " to " + h(base >>> 0) +
// " if=" + +!!(is_trap && this.flags & flag_interrupt) +
// " error_code=" + error_code, LOG_CPU);
this.instruction_pointer = this.get_seg(reg_cs) + base | 0;
//dbg_log("int" + h(interrupt_nr) + " trap=" + is_trap + " if=" + +!!(this.flags & flag_interrupt));
if(!is_trap)
{
// clear int flag for interrupt gates
this.flags &= ~flag_interrupt;
}
else
{
//this.handle_irqs();
}
}
else
{
// call 4 byte cs:ip interrupt vector from ivt at cpu.memory 0
this.writable_or_pagefault(this.get_stack_pointer(-6), 6);
var index = interrupt_nr << 2;
var new_ip = this.memory.read16(index);
var new_cs = this.memory.read16(index + 2 | 0);
//dbg_log("real mode interrupt #" + h(interrupt_nr) + " to " + h(new_cs, 4) + ":" + h(new_ip, 4), LOG_CPU);
//dbg_trace(LOG_CPU);
// push flags, cs:ip
this.load_eflags();
this.push16(this.flags);
this.push16(this.sreg[reg_cs]);
this.push16(this.get_real_eip());
this.flags = this.flags & ~flag_interrupt;
this.switch_seg(reg_cs, new_cs);
this.instruction_pointer = this.get_seg(reg_cs) + new_ip | 0;
}
};
CPU.prototype.iret16 = function()
{
if(!this.protected_mode || (this.vm86_mode() && this.getiopl() === 3))
{
if(this.vm86_mode())
{
//dbg_log("iret16 in vm86 mode iopl=3", LOG_CPU);
//this.debug.dump_regs_short();
}
var new_ip = this.pop16();
var new_cs = this.pop16();
var new_flags = this.pop16();
this.switch_seg(reg_cs, new_cs);
this.instruction_pointer = new_ip + this.get_seg(reg_cs) | 0;
this.update_eflags((this.flags & ~0xFFFF) | new_flags);
this.handle_irqs();
}
else
{
if(this.vm86_mode())
{
// vm86 mode, iopl != 3
this.trigger_gp(0);
}
throw this.debug.unimpl("16 bit iret in protected mode");
}
};
CPU.prototype.iret32 = function()
{
if(!this.protected_mode || (this.vm86_mode() && this.getiopl() === 3))
{
//if(this.vm86_mode()) dbg_log("iret in vm86 mode iopl=3", LOG_CPU);
var ip = this.pop32s();
if(ip & 0xFFFF0000)
{
throw this.debug.unimpl("#GP handler");
}
this.switch_seg(reg_cs, this.pop32s() & 0xFFFF);
var new_flags = this.pop32s();
this.instruction_pointer = ip + this.get_seg(reg_cs) | 0;
this.update_eflags(new_flags);
this.handle_irqs();
return;
}
if(this.vm86_mode())
{
// vm86 mode, iopl != 3
this.trigger_gp(0);
}
if(this.flags & flag_nt)
{
if(DEBUG) throw this.debug.unimpl("nt");
}
this.instruction_pointer = this.pop32s();
this.sreg[reg_cs] = this.pop32s();
var new_flags = this.pop32s();
if(new_flags & flag_vm)
{
if(this.cpl === 0)
{
// return to virtual 8086 mode
this.update_eflags(new_flags);
this.flags |= flag_vm;
//dbg_log("in vm86 mode now " +
// " cs:eip=" + h(this.sreg[reg_cs]) + ":" + h(this.instruction_pointer >>> 0) +
// " iopl=" + this.getiopl(), LOG_CPU);
this.switch_seg(reg_cs, this.sreg[reg_cs]);
this.instruction_pointer = (this.instruction_pointer & 0xFFFF) + this.get_seg(reg_cs) | 0;
var temp_esp = this.pop32s();
var temp_ss = this.pop32s();
this.switch_seg(reg_es, this.pop32s() & 0xFFFF);
this.switch_seg(reg_ds, this.pop32s() & 0xFFFF);
this.switch_seg(reg_fs, this.pop32s() & 0xFFFF);
this.switch_seg(reg_gs, this.pop32s() & 0xFFFF);
this.reg32s[reg_esp] = temp_esp;
this.switch_seg(reg_ss, temp_ss & 0xFFFF);
this.cpl = 3;
this.cpl_changed();
this.update_cs_size(false);
//this.debug.dump_regs_short();
return;
}
else
{
// ignored if not cpl=0
new_flags &= ~flag_vm;
}
}
// protected mode return
var info = this.lookup_segment_selector(this.sreg[reg_cs]);
if(info.is_null)
{
throw this.debug.unimpl("is null");
}
if(!info.is_present)
{
throw this.debug.unimpl("not present");
}
if(!info.is_executable)
{
throw this.debug.unimpl("not exec");
}
if(info.rpl < this.cpl)
{
throw this.debug.unimpl("rpl < cpl");
}
if(info.dc_bit && info.dpl > info.rpl)
{
throw this.debug.unimpl("conforming and dpl > rpl");
}
if(info.rpl > this.cpl)
{
// outer privilege return
var temp_esp = this.pop32s();
var temp_ss = this.pop32s();
this.reg32s[reg_esp] = temp_esp;
this.update_eflags(new_flags);
if(!this.cpl)
{
this.flags = this.flags & ~flag_vif & ~flag_vip | (new_flags & (flag_vif | flag_vip));
}
this.cpl = info.rpl;
this.cpl_changed();
this.switch_seg(reg_ss, temp_ss & 0xFFFF);
//dbg_log("iret cpu.cpl=" + this.cpl + " to " + h(this.instruction_pointer) +
// " cs:eip=" + h(this.sreg[reg_cs],4) + ":" + h(this.get_real_eip(), 8) +
// " ss:esp=" + h(temp_ss & 0xFFFF, 2) + ":" + h(temp_esp, 8), LOG_CPU);
}
else
{
// same privilege return
dbg_assert(info.rpl === this.cpl);
this.update_eflags(new_flags);
// update vip and vif, which are not changed by update_eflags
if(!this.cpl)
{
this.flags = this.flags & ~flag_vif & ~flag_vip | (new_flags & (flag_vif | flag_vip));
}
//dbg_log(h(new_flags) + " " + h(this.flags));
//dbg_log("iret to " + h(this.instruction_pointer));
}
dbg_assert(typeof info.size === "boolean");
if(info.size !== this.is_32)
{
this.update_cs_size(info.size);
}
this.segment_limits[reg_cs] = info.effective_limit;
this.segment_offsets[reg_cs] = info.base;
this.instruction_pointer = this.instruction_pointer + this.get_seg(reg_cs) | 0;
//dbg_log("iret if=" + (this.flags & flag_interrupt) +
// " cpl=" + this.cpl +
// " eip=" + h(this.instruction_pointer >>> 0, 8), LOG_CPU);
this.handle_irqs();
};
CPU.prototype.do_task_switch = function(selector)
{
var descriptor = this.lookup_segment_selector(selector);
if(!descriptor.is_valid || descriptor.is_null || !descriptor.from_gdt)
{
throw this.debug.unimpl("#GP handler");
}
if((descriptor.access & 31) === 0xB)
{
// is busy
throw this.debug.unimpl("#GP handler");
}
if(!descriptor.is_present)
{
throw this.debug.unimpl("#NP handler");
}
if(descriptor.effective_limit < 103)
{
throw this.debug.unimpl("#NP handler");
}
var tsr_size = this.segment_limits[reg_tr];
var tsr_offset = this.segment_offsets[reg_tr];
var old_eflags = this.get_eflags();
if(false /* is iret */)
{
old_eflags &= ~flag_nt;
}
this.writable_or_pagefault(tsr_offset, 0x66);
//this.safe_write32(tsr_offset + TSR_CR3, this.cr[3]);
this.safe_write32(tsr_offset + TSR_EIP, this.get_real_eip());
this.safe_write32(tsr_offset + TSR_EFLAGS, old_eflags);
this.safe_write32(tsr_offset + TSR_EAX, this.reg32s[reg_eax]);
this.safe_write32(tsr_offset + TSR_ECX, this.reg32s[reg_ecx]);
this.safe_write32(tsr_offset + TSR_EDX, this.reg32s[reg_edx]);
this.safe_write32(tsr_offset + TSR_EBX, this.reg32s[reg_ebx]);
this.safe_write32(tsr_offset + TSR_ESP, this.reg32s[reg_esp]);
this.safe_write32(tsr_offset + TSR_EBP, this.reg32s[reg_ebp]);
this.safe_write32(tsr_offset + TSR_ESI, this.reg32s[reg_esi]);
this.safe_write32(tsr_offset + TSR_EDI, this.reg32s[reg_edi]);
this.safe_write32(tsr_offset + TSR_ES, this.sreg[reg_es]);
this.safe_write32(tsr_offset + TSR_CS, this.sreg[reg_cs]);
this.safe_write32(tsr_offset + TSR_SS, this.sreg[reg_ss]);
this.safe_write32(tsr_offset + TSR_DS, this.sreg[reg_ds]);
this.safe_write32(tsr_offset + TSR_FS, this.sreg[reg_fs]);
this.safe_write32(tsr_offset + TSR_GS, this.sreg[reg_gs]);
this.safe_write32(tsr_offset + TSR_LDT, this.sreg[reg_ldtr]);
if(true /* is jump or call or int */)
{
// mark as busy
this.memory.write8(descriptor.table_offset + 5 | 0, this.memory.read8(descriptor.table_offset + 5 | 0) | 2);
}
//var new_tsr_size = descriptor.effective_limit;
var new_tsr_offset = descriptor.base;
var new_cr3 = this.safe_read32s(new_tsr_offset + TSR_CR3);
this.flags &= ~flag_vm;
this.switch_seg(reg_cs, this.safe_read16(new_tsr_offset + TSR_CS));
var new_eflags = this.safe_read32s(new_tsr_offset + TSR_EFLAGS);
if(true /* is call or int */)
{
this.safe_write32(tsr_offset + TSR_BACKLINK, selector);
new_eflags |= flag_nt;
}
if(new_eflags & flag_vm)
{
throw this.debug.unimpl("task switch to VM mode");
}
this.update_eflags(new_eflags);
this.load_ldt(this.safe_read16(new_tsr_offset + TSR_LDT));
this.reg32s[reg_eax] = this.safe_read32s(new_tsr_offset + TSR_EAX);
this.reg32s[reg_ecx] = this.safe_read32s(new_tsr_offset + TSR_ECX);
this.reg32s[reg_edx] = this.safe_read32s(new_tsr_offset + TSR_EDX);
this.reg32s[reg_ebx] = this.safe_read32s(new_tsr_offset + TSR_EBX);
this.reg32s[reg_esp] = this.safe_read32s(new_tsr_offset + TSR_ESP);
this.reg32s[reg_ebp] = this.safe_read32s(new_tsr_offset + TSR_EBP);
this.reg32s[reg_esi] = this.safe_read32s(new_tsr_offset + TSR_ESI);
this.reg32s[reg_edi] = this.safe_read32s(new_tsr_offset + TSR_EDI);
this.switch_seg(reg_es, this.safe_read16(new_tsr_offset + TSR_ES));
this.switch_seg(reg_ss, this.safe_read16(new_tsr_offset + TSR_SS));
this.switch_seg(reg_ds, this.safe_read16(new_tsr_offset + TSR_DS));
this.switch_seg(reg_fs, this.safe_read16(new_tsr_offset + TSR_FS));
this.switch_seg(reg_gs, this.safe_read16(new_tsr_offset + TSR_GS));
this.instruction_pointer = this.get_seg(reg_cs) + this.safe_read32s(new_tsr_offset + TSR_EIP) | 0;
this.segment_offsets[reg_tr] = descriptor.base;
this.segment_limits[reg_tr] = descriptor.effective_limit;
this.sreg[reg_tr] = selector;
this.cr[3] = new_cr3;
dbg_assert((this.cr[3] & 0xFFF) === 0);
this.clear_tlb();
this.cr[0] |= CR0_TS;
//debugger;
//throw "todo";
};
CPU.prototype.hlt_op = function()
{
if(this.cpl)
{
this.trigger_gp(0);
}
// hlt
if((this.flags & flag_interrupt) === 0)
{
this.debug.show("cpu halted");
if(DEBUG) this.debug.dump_regs();
throw "HALT";
}
else
{
// get out of here and into hlt_loop
this.in_hlt = true;
throw MAGIC_CPU_EXCEPTION;
}
};
// assumes ip to point to the byte before the next instruction
CPU.prototype.raise_exception = function(interrupt_nr)
{
if(DEBUG && interrupt_nr !== 7)
{
// show interesting exceptions
dbg_log("Exception " + h(interrupt_nr), LOG_CPU);
dbg_trace(LOG_CPU);
this.debug.dump_regs_short();
}
this.call_interrupt_vector(interrupt_nr, false, false);
throw MAGIC_CPU_EXCEPTION;
};
CPU.prototype.raise_exception_with_code = function(interrupt_nr, error_code)
{
if(DEBUG)
{
dbg_log("Exception " + h(interrupt_nr) + " err=" + h(error_code), LOG_CPU);
dbg_trace(LOG_CPU);
this.debug.dump_regs_short();
}
this.call_interrupt_vector(interrupt_nr, false, error_code);
throw MAGIC_CPU_EXCEPTION;
};
CPU.prototype.trigger_de = function()
{
this.instruction_pointer = this.previous_ip;
this.raise_exception(0);
};
CPU.prototype.trigger_ud = function()
{
this.instruction_pointer = this.previous_ip;
this.raise_exception(6);
};
CPU.prototype.trigger_nm = function()
{
this.instruction_pointer = this.previous_ip;
this.raise_exception(7);
};
CPU.prototype.trigger_gp = function(code)
{
this.instruction_pointer = this.previous_ip;
this.raise_exception_with_code(13, code);
};
CPU.prototype.trigger_np = function(code)
{
this.instruction_pointer = this.previous_ip;
this.raise_exception_with_code(11, code);
};
CPU.prototype.trigger_ss = function(code)
{
this.instruction_pointer = this.previous_ip;
this.raise_exception_with_code(12, code);
};
CPU.prototype.get_seg_prefix_ds = function()
{
return this.get_seg_prefix(reg_ds);
};
CPU.prototype.get_seg_prefix_ss = function()
{
return this.get_seg_prefix(reg_ss);
};
CPU.prototype.get_seg_prefix_cs = function()
{
return this.get_seg_prefix(reg_cs);
};
/**
* Get segment base by prefix or default
* @param {number} default_segment
*/
CPU.prototype.get_seg_prefix = function(default_segment /*, offset*/)
{
if(this.segment_prefix === SEG_PREFIX_NONE)
{
return this.get_seg(default_segment /*, offset*/);
}
else if(this.segment_prefix === SEG_PREFIX_ZERO)
{
return 0;
}
else
{
return this.get_seg(this.segment_prefix /*, offset*/);
}
};
/**
* Get segment base
* @param {number} segment
*/
CPU.prototype.get_seg = function(segment /*, offset*/)
{
dbg_assert(segment >= 0 && segment < 8);
if(this.protected_mode)
{
if(this.segment_is_null[segment])
{
// trying to access null segment
if(DEBUG)
{
dbg_log("Load null segment: " + segment + " sel=" + h(this.sreg[segment], 4), LOG_CPU);
throw this.debug.unimpl("#GP handler");
}
}
// TODO:
// - validate segment limits
// - validate if segment is writable
// - set accessed bit
}
return this.segment_offsets[segment];
};
CPU.prototype.handle_irqs = function()
{
dbg_assert(!this.page_fault);
if((this.flags & flag_interrupt) && !this.page_fault)
{
if(this.devices.pic)
{
this.devices.pic.check_irqs();
}
if(this.devices.apic)
{
this.devices.apic.check_irqs();
}
}
};
CPU.prototype.device_raise_irq = function(i)
{
dbg_assert(arguments.length === 1);
if(this.devices.pic)
{
this.devices.pic.raise_irq(i);
}
if(this.devices.apic)
{
this.devices.apic.raise_irq(i);
}
};
CPU.prototype.test_privileges_for_io = function(port, size)
{
if(this.protected_mode && (this.cpl > this.getiopl() || (this.flags & flag_vm)))
{
var tsr_size = this.segment_limits[reg_tr],
tsr_offset = this.segment_offsets[reg_tr];
if(tsr_size >= 0x67)
{
var iomap_base = this.memory.read16(this.translate_address_system_read(tsr_offset + 0x64 + 2 | 0)),
high_port = port + size - 1 | 0;
if(tsr_size >= (iomap_base + (high_port >> 3) | 0))
{
var mask = ((1 << size) - 1) << (port & 7),
addr = this.translate_address_system_read(tsr_offset + iomap_base + (port >> 3) | 0),
port_info = (mask & 0xFF00) ?
this.memory.read16(addr) : this.memory.read8(addr);
if(!(port_info & mask))
{
return;
}
}
}
dbg_log("#GP for port io port=" + h(port) + " size=" + size, LOG_CPU);
this.trigger_gp(0);
}
};
CPU.prototype.cpuid = function()
{
// cpuid
// TODO: Fill in with less bogus values
// http://lxr.linux.no/linux+%2a/arch/x86/include/asm/cpufeature.h
// http://www.sandpile.org/x86/cpuid.htm
var eax = 0,
ecx = 0,
edx = 0,
ebx = 0;
switch(this.reg32s[reg_eax])
{
case 0:
// maximum supported level
eax = 5;
ebx = 0x756E6547|0; // Genu
edx = 0x49656E69|0; // ineI
ecx = 0x6C65746E|0; // ntel
break;
case 1:
// pentium
eax = 3 | 6 << 4 | 15 << 8;
ebx = 1 << 16 | 8 << 8; // cpu count, clflush size
ecx = 1 << 23 | 1 << 30; // popcnt, rdrand
edx = (this.fpu ? 1 : 0) | // fpu
1 << 1 | 1 << 3 | 1 << 4 | 1 << 5 | // vme, pse, tsc, msr
1 << 8 | 1 << 11 | 1 << 13 | 1 << 15; // cx8, sep, pge, cmov
edx |= 1 << 9; // apic
break;
case 2:
// Taken from http://siyobik.info.gf/main/reference/instruction/CPUID
eax = 0x665B5001|0;
ebx = 0;
ecx = 0;
edx = 0x007A7000;
break;
case 4:
// from my local machine
switch(this.reg32s[reg_ecx])
{
case 0:
eax = 0x00000121;
ebx = 0x01c0003f;
ecx = 0x0000003f;
edx = 0x00000001;
break;
case 1:
eax = 0x00000122;
ebx = 0x01c0003f;
ecx = 0x0000003f;
edx = 0x00000001;
break
case 2:
eax = 0x00000143;
ebx = 0x05c0003f;
ecx = 0x00000fff;
edx = 0x00000001;
break;
}
break;
case 0x80000000|0:
// maximum supported extended level
eax = 5;
// other registers are reserved
break;
default:
dbg_log("cpuid: unimplemented eax: " + h(this.reg32[reg_eax]), LOG_CPU);
}
dbg_log("cpuid: eax=" + h(this.reg32[reg_eax], 8) + " cl=" + h(this.reg8[reg_cl], 2), LOG_CPU);
this.reg32s[reg_eax] = eax;
this.reg32s[reg_ecx] = ecx;
this.reg32s[reg_edx] = edx;
this.reg32s[reg_ebx] = ebx;
};
CPU.prototype.update_cs_size = function(new_size)
{
this.is_32 = this.operand_size_32 = this.address_size_32 = new_size;
this.update_operand_size();
this.update_address_size();
if(OP_TRANSLATION)
{
this.translator.clear_cache();
}
};
CPU.prototype.update_operand_size = function()
{
if(this.operand_size_32)
{
this.table = this.table32;
this.large_table = this.large_table32;
}
else
{
this.table = this.table16;
this.large_table = this.large_table16;
}
};
CPU.prototype.update_address_size = function()
{
if(this.address_size_32)
{
this.regv = this.reg32s;
this.reg_vcx = reg_ecx;
this.reg_vsi = reg_esi;
this.reg_vdi = reg_edi;
}
else
{
this.regv = this.reg16;
this.reg_vcx = reg_cx;
this.reg_vsi = reg_si;
this.reg_vdi = reg_di;
}
};
/**
* @param {number} selector
*/
CPU.prototype.lookup_segment_selector = function(selector)
{
dbg_assert(typeof selector === "number" && selector >= 0 && selector < 0x10000);
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,
base: 0,
access: 0,
flags: 0,
type: 0,
dpl: 0,
is_system: false,
is_present: false,
is_executable: false,
rw_bit: false,
dc_bit: false,
size: false,
// limit after applying granularity
effective_limit: 0,
is_writable: false,
is_readable: false,
table_offset: 0,
};
if(is_gdt)
{
table_offset = this.gdtr_offset;
table_limit = this.gdtr_size;
}
else
{
table_offset = this.segment_offsets[reg_ldtr];
table_limit = this.segment_limits[reg_ldtr];
}
if(selector_offset === 0)
{
info.is_null = true;
return info;
}
// limit is the number of entries in the table minus one
if((selector | 7) > table_limit)
{
dbg_log("Selector " + h(selector, 4) + " is outside of the "
+ (is_gdt ? "g" : "l") + "dt limits", LOG_CPU)
info.is_valid = false;
return info;
}
table_offset = table_offset + selector_offset | 0;
if(this.paging)
{
table_offset = this.translate_address_system_read(table_offset);
}
info.table_offset = table_offset;
info.base = this.memory.read16(table_offset + 2 | 0) | this.memory.read8(table_offset + 4 | 0) << 16 |
this.memory.read8(table_offset + 7 | 0) << 24;
info.access = this.memory.read8(table_offset + 5 | 0);
info.flags = this.memory.read8(table_offset + 6 | 0) >> 4;
//this.memory.write8(table_offset + 5 | 0, info.access | 1);
// 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;
var limit = this.memory.read16(table_offset) |
(this.memory.read8(table_offset + 6 | 0) & 0xF) << 16;
if(info.flags & 8)
{
// granularity set
info.effective_limit = (limit << 12 | 0xFFF) >>> 0;
}
else
{
info.effective_limit = 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
*/
CPU.prototype.switch_seg = function(reg, selector)
{
dbg_assert(reg >= 0 && reg <= 5);
dbg_assert(typeof selector === "number" && selector < 0x10000 && selector >= 0);
if(reg === reg_cs)
{
this.protected_mode = (this.cr[0] & CR0_PE) === CR0_PE;
}
if(!this.protected_mode || this.vm86_mode())
{
this.sreg[reg] = selector;
this.segment_is_null[reg] = 0;
this.segment_offsets[reg] = selector << 4;
if(reg === reg_ss && this.stack_size_32)
{
this.stack_size_32 = false;
this.stack_reg = this.reg16;
this.reg_vsp = reg_sp;
this.reg_vbp = reg_bp;
}
return;
}
var info = this.lookup_segment_selector(selector);
if(reg === reg_ss)
{
if(info.is_null)
{
dbg_log("#GP for loading 0 in SS sel=" + h(selector, 4), LOG_CPU);
dbg_trace(LOG_CPU);
this.trigger_gp(0);
}
if(!info.is_valid ||
info.is_system ||
info.rpl !== this.cpl ||
!info.is_writable ||
info.dpl !== this.cpl)
{
dbg_log("#GP for loading invalid in SS sel=" + h(selector, 4), LOG_CPU);
dbg_trace(LOG_CPU);
this.trigger_gp(selector & ~3);
}
if(!info.is_present)
{
dbg_log("#SS for loading non-present in SS sel=" + h(selector, 4), LOG_CPU);
dbg_trace(LOG_CPU);
this.trigger_ss(selector & ~3);
}
this.stack_size_32 = info.size;
if(info.size)
{
this.stack_reg = this.reg32s;
this.reg_vsp = reg_esp;
this.reg_vbp = reg_ebp;
}
else
{
this.stack_reg = this.reg16;
this.reg_vsp = reg_sp;
this.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 this.debug.unimpl("#GP handler");
}
if(info.is_system)
{
dbg_log(info + " " + h(selector & ~3), LOG_CPU);
throw this.debug.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 this.debug.unimpl("#GP handler");
//}
if(info.rpl !== this.cpl)
{
dbg_log(info + " " + h(selector & ~3), LOG_CPU);
throw this.debug.unimpl("privilege change");
}
dbg_assert(this.cpl === info.dpl);
if(!info.dc_bit && info.dpl < this.cpl)
{
throw this.debug.unimpl("inter privilege call");
}
else
{
if(info.dc_bit || info.dpl === this.cpl)
{
// ok
}
else
{
// PE = 1, interrupt or trap gate, nonconforming code segment, DPL > CPL
dbg_log(info + " " + h(selector & ~3), LOG_CPU);
throw this.debug.unimpl("#GP handler");
}
}
dbg_assert(typeof info.size === "boolean");
if(info.size !== this.is_32)
{
this.update_cs_size(info.size);
}
}
else
{
// es, ds, fs, gs
if(info.is_null)
{
//dbg_log("0 loaded in seg=" + reg + " sel=" + h(selector, 4), LOG_CPU);
//dbg_trace(LOG_CPU);
this.sreg[reg] = selector;
this.segment_is_null[reg] = 1;
return;
}
if(!info.is_valid ||
info.is_system ||
!info.is_readable ||
((!info.is_executable || !info.dc_bit) &&
info.rpl > info.dpl &&
this.cpl > info.dpl))
{
dbg_log("#GP for loading invalid in seg " + reg + " sel=" + h(selector, 4), LOG_CPU);
dbg_trace(LOG_CPU);
debugger;
this.trigger_gp(selector & ~3);
}
if(!info.is_present)
{
dbg_log("#NP for loading not-present in seg " + reg + " sel=" + h(selector, 4), LOG_CPU);
dbg_trace(LOG_CPU);
this.trigger_np(selector & ~3);
}
}
//dbg_log("seg " + reg + " " + h(info.base));
this.segment_is_null[reg] = 0;
this.segment_limits[reg] = info.effective_limit;
//this.segment_infos[reg] = 0; // TODO
//if(OP_TRANSLATION && (reg === reg_ds || reg === reg_ss) && info.base !== this.segment_offsets[reg])
//{
// this.translator.clear_cache();
//}
this.segment_offsets[reg] = info.base;
this.sreg[reg] = selector;
};
CPU.prototype.load_tr = function(selector)
{
var info = this.lookup_segment_selector(selector);
dbg_log("load tr: " + h(selector, 4), LOG_CPU);
if(!info.from_gdt)
{
throw this.debug.unimpl("TR can only be loaded from GDT");
}
if(info.is_null)
{
dbg_log("#GP(0) | tried to load null selector (ltr)");
throw this.debug.unimpl("#GP handler");
}
if(!info.is_present)
{
dbg_log("#GP | present bit not set (ltr)");
throw this.debug.unimpl("#GP handler");
}
if(!info.is_system)
{
dbg_log("#GP | ltr: not a system entry");
throw this.debug.unimpl("#GP handler");
}
if(info.type !== 9)
{
// 0xB: busy 386 TSS (GP)
// 0x3: busy 286 TSS (GP)
// 0x1: 286 TSS (]
dbg_log("#GP | ltr: invalid type (type = " + h(info.type) + ")");
throw this.debug.unimpl("#GP handler");
}
this.segment_offsets[reg_tr] = info.base;
this.segment_limits[reg_tr] = info.effective_limit;
this.sreg[reg_tr] = selector;
// Mark task as busy
this.memory.write8(info.table_offset + 5 | 0, this.memory.read8(info.table_offset + 5 | 0) | 2);
//dbg_log("tsr at " + h(info.base) + "; (" + info.effective_limit + " bytes)");
};
CPU.prototype.load_ldt = function(selector)
{
var info = this.lookup_segment_selector(selector);
if(info.is_null)
{
// invalid
this.segment_offsets[reg_ldtr] = 0;
this.segment_limits[reg_ldtr] = 0;
return;
}
if(!info.from_gdt)
{
throw this.debug.unimpl("LDTR can only be loaded from GDT");
}
if(!info.is_present)
{
dbg_log("lldt: present bit not set");
throw this.debug.unimpl("#GP handler");
}
if(!info.is_system)
{
dbg_log("lldt: not a system entry");
throw this.debug.unimpl("#GP handler");
}
if(info.type !== 2)
{
dbg_log("lldt: invalid type (" + info.type + ")");
throw this.debug.unimpl("#GP handler");
}
this.segment_offsets[reg_ldtr] = info.base;
this.segment_limits[reg_ldtr] = info.effective_limit;
this.sreg[reg_ldtr] = selector;
//dbg_log("ldt at " + h(info.base) + "; (" + info.effective_limit + " bytes)");
};
CPU.prototype.arpl = function(seg, r16)
{
this.flags_changed &= ~flag_zero;
if((seg & 3) < (this.reg16[r16] & 3))
{
this.flags |= flag_zero;
return seg & ~3 | this.reg16[r16] & 3;
}
else
{
this.flags &= ~flag_zero;
return seg;
}
};
CPU.prototype.lar = function(selector, original)
{
/** @const */
var LAR_INVALID_TYPE = 1 << 0 | 1 << 6 | 1 << 7 | 1 << 8 | 1 << 0xA |
1 << 0xD | 1 << 0xE | 1 << 0xF;
var info = this.lookup_segment_selector(selector);
this.flags_changed &= ~flag_zero;
//console.log("lar -> ", h(selector, 4), this.cpl, info, LAR_INVALID_TYPE >> info.type & 1);
if(info.is_null || !info.is_valid ||
(LAR_INVALID_TYPE >> info.type & 1)
) {
this.flags &= ~flag_zero;
return original;
}
else
{
this.flags |= flag_zero;
return info.type << 8 | info.size << 12 | info.dpl << 13 |
info.is_present << 15 |
info.flags << 20;
}
};
CPU.prototype.lsl = function(selector, original)
{
/** @const */
var LSL_INVALID_TYPE = 1 << 0 | 1 << 4 | 1 << 5 | 1 << 6 | 1 << 8 |
1 << 0xA | 1 << 0xC | 1 << 0xD | 1 << 0xE | 1 << 0xF;
var info = this.lookup_segment_selector(selector);
this.flags_changed &= ~flag_zero;
//console.log("lsl -> ", h(selector, 4), this.cpl, info, LSL_INVALID_TYPE >> info.type & 1);
//this.debug.dump_gdt_ldt();
if(info.is_null || !info.is_valid ||
(LSL_INVALID_TYPE >> info.type & 1)
) {
this.flags &= ~flag_zero;
return original;
}
else
{
this.flags |= flag_zero;
return info.effective_limit | 0;
}
};
CPU.prototype.clear_tlb = function()
{
// clear tlb excluding global pages
this.last_virt_eip = -1;
this.last_virt_esp = -1;
this.tlb_info.set(this.tlb_info_global);
//dbg_log("page table loaded", LOG_CPU);
};
CPU.prototype.full_clear_tlb = function()
{
//dbg_log("TLB full clear", LOG_CPU);
// clear tlb including global pages
var buf32 = new Int32Array(this.tlb_info_global.buffer);
for(var i = 0; i < (1 << 18); )
{
buf32[i++] = buf32[i++] = buf32[i++] = buf32[i++] = 0;
}
this.clear_tlb();
};
CPU.prototype.invlpg = function(addr)
{
var page = addr >>> 12;
//dbg_log("invlpg: addr=" + h(addr >>> 0), LOG_CPU);
this.tlb_info[page] = 0;
this.tlb_info_global[page] = 0;
this.last_virt_eip = -1;
this.last_virt_esp = -1;
};
CPU.prototype.translate_address_read = function(addr)
{
if(!this.paging)
{
return addr;
}
if(this.cpl === 3)
{
return this.translate_address_user_read(addr);
}
else
{
return this.translate_address_system_read(addr);
}
};
CPU.prototype.translate_address_write = function(addr)
{
if(!this.paging)
{
return addr;
}
if(this.cpl === 3)
{
return this.translate_address_user_write(addr);
}
else
{
return this.translate_address_system_write(addr);
}
};
CPU.prototype.translate_address_user_write = function(addr)
{
var base = addr >>> 12;
if(this.tlb_info[base] & TLB_USER_WRITE)
{
return this.tlb_data[base] ^ addr;
}
else
{
return this.do_page_translation(addr, 1, 1) | addr & 0xFFF;
}
};
CPU.prototype.translate_address_user_read = function(addr)
{
var base = addr >>> 12;
if(this.tlb_info[base] & TLB_USER_READ)
{
return this.tlb_data[base] ^ addr;
}
else
{
return this.do_page_translation(addr, 0, 1) | addr & 0xFFF;
}
};
CPU.prototype.translate_address_system_write = function(addr)
{
var base = addr >>> 12;
if(this.tlb_info[base] & TLB_SYSTEM_WRITE)
{
return this.tlb_data[base] ^ addr;
}
else
{
return this.do_page_translation(addr, 1, 0) | addr & 0xFFF;
}
};
CPU.prototype.translate_address_system_read = function(addr)
{
var base = addr >>> 12;
if(this.tlb_info[base] & TLB_SYSTEM_READ)
{
return this.tlb_data[base] ^ addr;
}
else
{
return this.do_page_translation(addr, 0, 0) | addr & 0xFFF;
}
};
/**
* @return {number}
*/
CPU.prototype.do_page_translation = function(addr, for_writing, user)
{
var page = addr >>> 12,
page_dir_addr = (this.cr[3] >>> 2) + (page >> 10) | 0,
page_dir_entry = this.memory.mem32s[page_dir_addr],
high,
can_write = true,
global,
cachable = true,
allow_user = true;
dbg_assert(addr < 0x80000000);
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);
this.cr[2] = addr;
this.trigger_pagefault(for_writing, user, 0);
// never reached as this.trigger_pagefault throws up
dbg_assert(false);
}
if((page_dir_entry & 2) === 0)
{
can_write = false;
if(for_writing && (user || (this.cr[0] & CR0_WP)))
{
this.cr[2] = addr;
this.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);
this.cr[2] = addr;
this.trigger_pagefault(for_writing, user, 1);
dbg_assert(false);
}
}
if(page_dir_entry & this.page_size_extensions)
{
// size bit is set
// set the accessed and dirty bits
this.memory.mem32s[page_dir_addr] = page_dir_entry | 0x20 | for_writing << 6;
high = (page_dir_entry & 0xFFC00000) | (addr & 0x3FF000);
global = page_dir_entry & 0x100;
}
else
{
var page_table_addr = ((page_dir_entry & 0xFFFFF000) >>> 2) + (page & 0x3FF) | 0,
page_table_entry = this.memory.mem32s[page_table_addr];
if((page_table_entry & 1) === 0)
{
//dbg_log("#PF not present table", LOG_CPU);
this.cr[2] = addr;
this.trigger_pagefault(for_writing, user, 0);
dbg_assert(false);
}
if((page_table_entry & 2) === 0)
{
can_write = false;
if(for_writing && (user || (this.cr[0] & CR0_WP)))
{
//dbg_log("#PF not writable page", LOG_CPU);
this.cr[2] = addr;
this.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);
this.cr[2] = addr;
this.trigger_pagefault(for_writing, user, 1);
dbg_assert(false);
}
}
// set the accessed and dirty bits
this.memory.mem32s[page_dir_addr] = page_dir_entry | 0x20;
this.memory.mem32s[page_table_addr] = page_table_entry | 0x20 | for_writing << 6;
high = page_table_entry & 0xFFFFF000;
global = page_table_entry & 0x100;
}
this.tlb_data[page] = high ^ page << 12;
var allowed_flag;
if(allow_user)
{
if(can_write)
{
allowed_flag = TLB_SYSTEM_READ | TLB_SYSTEM_WRITE | TLB_USER_READ | TLB_USER_WRITE;
}
else
{
// TODO: Consider if cr0.wp is not set
allowed_flag = TLB_SYSTEM_READ | TLB_USER_READ;
}
}
else
{
if(can_write)
{
allowed_flag = TLB_SYSTEM_READ | TLB_SYSTEM_WRITE;
}
else
{
allowed_flag = TLB_SYSTEM_READ;
}
}
this.tlb_info[page] = allowed_flag;
if(global && (this.cr[4] & CR4_PGE))
{
this.tlb_info_global[page] = allowed_flag;
}
return high;
};
CPU.prototype.writable_or_pagefault = function(addr, size)
{
dbg_assert(size < 0x1000, "not supported yet");
dbg_assert(size > 0);
if(!this.paging)
{
return;
}
var user = this.cpl === 3 ? 1 : 0,
mask = user ? TLB_USER_WRITE : TLB_SYSTEM_WRITE,
page = addr >>> 12;
if((this.tlb_info[page] & mask) === 0)
{
this.do_page_translation(addr, 1, user);
}
if((addr & 0xFFF) + size - 1 >= 0x1000)
{
if((this.tlb_info[page + 1 | 0] & mask) === 0)
{
this.do_page_translation(addr + size - 1 | 0, 1, user);
}
}
};
CPU.prototype.trigger_pagefault = function(write, user, present)
{
//dbg_log("page fault w=" + write + " u=" + user + " p=" + present +
// " eip=" + h(this.previous_ip >>> 0, 8) +
// " cr2=" + h(this.cr[2] >>> 0, 8), LOG_CPU);
//dbg_trace(LOG_CPU);
// likely invalid pointer reference
//if((this.cr[2] >>> 0) < 0x100)
//{
// throw "stop";
//}
if(this.page_fault)
{
dbg_trace(LOG_CPU);
throw this.debug.unimpl("Double fault");
}
// invalidate tlb entry
var page = this.cr[2] >>> 12;
this.tlb_info[page] = 0;
this.tlb_info_global[page] = 0;
this.instruction_pointer = this.previous_ip;
this.page_fault = true;
this.call_interrupt_vector(14, false, user << 2 | write << 1 | present);
throw MAGIC_CPU_EXCEPTION;
};