Improved prefix handling, preparation for faster emulation

This commit is contained in:
copy 2017-03-06 19:03:06 -05:00
parent b6056f8589
commit b23b070a8d
8 changed files with 611 additions and 480 deletions

View file

@ -269,7 +269,7 @@ var
SEG_PREFIX_NONE = -1,
/** @const */
SEG_PREFIX_ZERO = 9;
SEG_PREFIX_ZERO = 7;
var
@ -340,3 +340,18 @@ var TSC_RATE = 8 * 1024;
/** @const */ var TSR_LDT = 0x60;
/** @const */
var PREFIX_MASK_REP = 0b11000;
/** @const */
var PREFIX_REPZ = 0b01000;
/** @const */
var PREFIX_REPNZ = 0b10000;
/** @const */
var PREFIX_MASK_SEGMENT = 0b111;
/** @const */
var PREFIX_MASK_OPSIZE = 0b100000;
/** @const */
var PREFIX_MASK_ADDRSIZE = 0b1000000;

View file

@ -98,13 +98,8 @@ function CPU()
/** @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}
@ -145,9 +140,8 @@ function CPU()
/** @type {number} */
this.sysenter_eip = 0;
/** @type {number} */
this.repeat_string_prefix = REPEAT_STRING_PREFIX_NONE;
this.prefixes = 0;
/** @type {number} */
this.flags = 0;
@ -189,13 +183,6 @@ function CPU()
/** @type {number} */
this.phys_addr_high = 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 = [];
// paging enabled
@ -243,9 +230,6 @@ function CPU()
// debug registers
this.dreg = new Int32Array(8);
// current state of prefixes
this.segment_prefix = SEG_PREFIX_NONE;
// dynamic instruction translator
this.translator = undefined;
@ -255,13 +239,14 @@ function CPU()
dbg_assert(this.table16 && this.table32);
dbg_assert(this.table0F_16 && this.table0F_32);
this.update_address_size();
this.update_operand_size();
this.tsc_offset = v86.microtick();
this.debug_init();
this.init2();
//Object.seal(this);
}
@ -283,8 +268,7 @@ CPU.prototype.get_state = function()
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;
@ -294,7 +278,7 @@ CPU.prototype.get_state = function()
state[22] = this.sysenter_cs;
state[23] = this.sysenter_eip;
state[24] = this.sysenter_esp;
state[25] = this.repeat_string_prefix;
state[25] = this.prefixes;
state[26] = this.flags;
state[27] = this.flags_changed;
state[28] = this.last_op1;
@ -350,9 +334,9 @@ CPU.prototype.set_state = function(state)
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];
@ -361,7 +345,8 @@ CPU.prototype.set_state = function(state)
this.sysenter_cs = state[22];
this.sysenter_eip = state[23];
this.sysenter_esp = state[24];
this.repeat_string_prefix = state[25];
this.prefixes = state[25];
this.flags = state[26];
this.flags_changed = state[27];
this.last_op1 = state[28];
@ -411,7 +396,6 @@ CPU.prototype.set_state = function(state)
this.reg8s = new Int8Array(this.reg32s.buffer);
this.reg8 = new Uint8Array(this.reg32s.buffer);
this.update_address_size();
this.update_operand_size();
};
@ -440,6 +424,7 @@ CPU.prototype.main_run = function()
}
this.do_run();
return 0;
};
@ -464,7 +449,7 @@ CPU.prototype.exception_cleanup = function(e)
//Error.captureStackTrace && Error.captureStackTrace(e);
throw e;
}
}
};
CPU.prototype.reboot_internal = function()
{
@ -513,14 +498,11 @@ CPU.prototype.reset = function()
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.timestamp_counter = 0;
this.previous_ip = 0;
@ -530,8 +512,6 @@ CPU.prototype.reset = function()
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;
@ -573,9 +553,6 @@ CPU.prototype.create_memory = function(size)
this.memory_size = size;
// use by dynamic translator
//if(OP_TRANSLATION) this.mem_page_infos = new Uint8Array(1 << 20);
var buffer = new ArrayBuffer(size);
this.mem8 = new Uint8Array(buffer);
@ -585,15 +562,11 @@ CPU.prototype.create_memory = function(size)
CPU.prototype.init = function(settings, device_bus)
{
this.create_memory(settings.memory_size || 1024 * 1024 * 64);
this.create_memory(typeof settings.memory_size === "number" ?
settings.memory_size : 1024 * 1024 * 64);
this.reset();
if(OP_TRANSLATION)
{
this.translator = new DynamicTranslator(this);
}
var io = new IO(this);
this.io = io;
@ -830,7 +803,6 @@ CPU.prototype.do_run = function()
if(this.in_hlt)
{
this.hlt_loop();
return;
}
@ -857,7 +829,7 @@ CPU.prototype.do_many_cycles_unsafe = function()
{
this.cycle_internal();
}
}
};
// Some functions must not be inlined, because then more code is in the
// deoptimized try-catch block.
@ -869,7 +841,7 @@ if(typeof window !== "undefined")
CPU.prototype.do_many_cycles_unsafe,
CPU.prototype.do_many_cycles,
];
};
}
/** @const */
var PROFILING = false;
@ -887,7 +859,7 @@ if(PROFILING)
total: instruction_total[i],
count: instruction_count[i],
per: (instruction_total[i] / instruction_count[i]) || 0,
}
};
console.log("count:");
console.table(prof_instructions.sort((p0, p1) => p1.count - p0.count));
@ -897,7 +869,7 @@ if(PROFILING)
console.log("time/count:");
console.table(prof_instructions.sort((p0, p1) => p1.per - p0.per));
}
};
}
/**
@ -953,9 +925,24 @@ CPU.prototype.cycle = function()
}
};
CPU.prototype.segment_prefix_op = function(sreg)
{
dbg_assert(sreg <= 5);
this.prefixes |= sreg + 1;
this.run_prefix_instruction();
this.prefixes = 0;
};
CPU.prototype.run_prefix_instruction = function()
{
this.table[this.read_imm8()](this);
if(this.is_osize_32())
{
this.table32[this.read_imm8()](this);
}
else
{
this.table16[this.read_imm8()](this);
}
};
CPU.prototype.hlt_loop = function()
@ -987,20 +974,7 @@ CPU.prototype.hlt_loop = function()
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();
}
this.prefixes = 0;
};
CPU.prototype.cr0_changed = function(old_cr0)
@ -1024,11 +998,6 @@ CPU.prototype.cr0_changed = function(old_cr0)
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()
@ -1097,17 +1066,36 @@ CPU.prototype.read_modrm_byte = function()
this.modrm_byte = this.read_imm8();
};
CPU.prototype.read_op0F = CPU.prototype.read_imm8;
CPU.prototype.read_sib = CPU.prototype.read_imm8;
CPU.prototype.read_op8 = CPU.prototype.read_imm8;
CPU.prototype.read_op8s = CPU.prototype.read_imm8s;
CPU.prototype.read_op16 = CPU.prototype.read_imm16;
CPU.prototype.read_op32s = CPU.prototype.read_imm32s;
CPU.prototype.read_second_op8 = CPU.prototype.read_imm8;
CPU.prototype.read_second_op16 = CPU.prototype.read_imm16;
CPU.prototype.read_disp8 = CPU.prototype.read_imm8;
CPU.prototype.read_disp8s = CPU.prototype.read_imm8s;
CPU.prototype.read_disp16 = CPU.prototype.read_imm16;
CPU.prototype.read_disp32s = CPU.prototype.read_imm32s;
CPU.prototype.init2 = function () {};
CPU.prototype.branch_taken = function () {};
CPU.prototype.branch_not_taken = function () {};
CPU.prototype.diverged = function () {};
CPU.prototype.modrm_resolve = function(modrm_byte)
{
dbg_assert(modrm_byte < 0xC0);
return (this.is_asize_32() ? this.modrm_table32 : this.modrm_table16)[modrm_byte](this);
};
CPU.prototype.sib_resolve = function(mod)
{
return this.sib_table[this.read_sib()](this, mod);
};
CPU.prototype.clear_instruction_cache = function() {};
// read word from a page boundary, given 2 physical addresses
CPU.prototype.virt_boundary_read16 = function(low, high)
{
@ -1144,7 +1132,7 @@ CPU.prototype.virt_boundary_read32s = function(low, high)
mid = this.virt_boundary_read16(low + 1 | 0, high - 1 | 0);
}
return this.read8(low) | mid << 8 | this.read8(high) << 24;;
return this.read8(low) | mid << 8 | this.read8(high) << 24;
};
CPU.prototype.virt_boundary_write16 = function(low, high, value)
@ -1247,7 +1235,8 @@ CPU.prototype.safe_write32 = function(addr, value)
if((addr & 0xFFF) >= 0xFFD)
{
this.virt_boundary_write32(phys_low, this.translate_address_write(addr + 3 | 0), value);
// XXX
this.virt_boundary_write32(phys_low, this.translate_address_write(addr + 3 & ~3) | (addr + 3) & 3, value);
}
else
{
@ -1258,7 +1247,7 @@ CPU.prototype.safe_write32 = function(addr, value)
// read 2 or 4 byte from ip, depending on address size attribute
CPU.prototype.read_moffs = function()
{
if(this.address_size_32)
if(this.is_asize_32())
{
return this.get_seg_prefix(reg_ds) + this.read_op32s() | 0;
}
@ -1392,7 +1381,7 @@ CPU.prototype.get_real_eip = function()
CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, error_code)
{
//dbg_log("int " + h(interrupt_nr, 2) + " (" + (is_software_int ? "soft" : "hard") + "ware)", LOG_CPU);
CPU_LOG_VERBOSE && this.debug.dump_state("int start");
CPU_LOG_VERBOSE && this.debug.dump_state("int " + h(interrupt_nr) + " start");
//this.debug.dump_regs_short();
this.debug.debug_interrupt(interrupt_nr);
@ -1730,9 +1719,16 @@ CPU.prototype.iret32 = function()
CPU.prototype.iret = function(is_16)
{
//dbg_log("iret is_16=" + is_16, LOG_CPU);
CPU_LOG_VERBOSE && this.debug.dump_state("iret start");
CPU_LOG_VERBOSE && this.debug.dump_state("iret" + (is_16 ? "16" : "32") + " start");
//this.debug.dump_regs_short();
if(this.vm86_mode() && this.getiopl() < 3)
{
// vm86 mode, iopl != 3
dbg_log("#gp iret vm86 mode, iopl != 3", LOG_CPU);
this.trigger_gp(0);
}
if(is_16)
{
var new_eip = this.safe_read16(this.get_stack_pointer(0));
@ -1774,12 +1770,7 @@ CPU.prototype.iret = function(is_16)
return;
}
if(this.vm86_mode())
{
// vm86 mode, iopl != 3
dbg_log("#gp iret vm86 mode, iopl != 3", LOG_CPU)
this.trigger_gp(0);
}
dbg_assert(!this.vm86_mode());
if(this.flags & flag_nt)
{
@ -1912,7 +1903,6 @@ CPU.prototype.iret = function(is_16)
ss_info.dpl !== new_cpl)
{
dbg_log("#GP for loading invalid in SS sel=" + h(temp_ss, 4), LOG_CPU);
debugger;
dbg_trace(LOG_CPU);
this.trigger_gp(temp_ss & ~3);
}
@ -1996,8 +1986,7 @@ CPU.prototype.iret = function(is_16)
this.instruction_pointer = new_eip + this.get_seg(reg_cs) | 0;
//dbg_log("iret is_16=" + is_16 + " to:", LOG_CPU);
CPU_LOG_VERBOSE && this.debug.dump_state("iret end");
CPU_LOG_VERBOSE && this.debug.dump_state("iret" + (is_16 ? "16" : "32") + " end");
this.handle_irqs();
};
@ -2030,7 +2019,7 @@ CPU.prototype.far_return = function(eip, selector, stack_adjust)
{
this.switch_cs_real_mode(selector);
this.instruction_pointer = this.get_seg(reg_cs) + eip | 0;
this.adjust_stack_reg(2 * (this.operand_size_32 ? 4 : 2) + stack_adjust);
this.adjust_stack_reg(2 * (this.is_osize_32() ? 4 : 2) + stack_adjust);
return;
}
@ -2087,20 +2076,20 @@ CPU.prototype.far_return = function(eip, selector, stack_adjust)
if(info.rpl > this.cpl)
{
dbg_log("far return privilege change cs: " + h(selector) + " from=" + this.cpl + " to=" + info.rpl + " is_16=" + this.operand_size_32, LOG_CPU);
dbg_log("far return privilege change cs: " + h(selector) + " from=" + this.cpl + " to=" + info.rpl + " is_16=" + this.is_osize_32(), LOG_CPU);
if(this.operand_size_32)
if(this.is_osize_32())
{
dbg_log("esp read from " + h(this.translate_address_system_read(this.get_stack_pointer(stack_adjust + 8))))
//dbg_log("esp read from " + h(this.translate_address_system_read(this.get_stack_pointer(stack_adjust + 8))))
var temp_esp = this.safe_read32s(this.get_stack_pointer(stack_adjust + 8));
dbg_log("esp=" + h(temp_esp));
//dbg_log("esp=" + h(temp_esp));
var temp_ss = this.safe_read16(this.get_stack_pointer(stack_adjust + 12));
}
else
{
dbg_log("esp read from " + h(this.translate_address_system_read(this.get_stack_pointer(stack_adjust + 4))));
//dbg_log("esp read from " + h(this.translate_address_system_read(this.get_stack_pointer(stack_adjust + 4))));
var temp_esp = this.safe_read16(this.get_stack_pointer(stack_adjust + 4));
dbg_log("esp=" + h(temp_esp));
//dbg_log("esp=" + h(temp_esp));
var temp_ss = this.safe_read16(this.get_stack_pointer(stack_adjust + 6));
}
@ -2111,7 +2100,7 @@ CPU.prototype.far_return = function(eip, selector, stack_adjust)
this.switch_seg(reg_ss, temp_ss);
this.set_stack_reg(temp_esp + stack_adjust);
//if(this.operand_size_32)
//if(this.is_osize_32())
//{
// this.adjust_stack_reg(2 * 4);
//}
@ -2126,7 +2115,7 @@ CPU.prototype.far_return = function(eip, selector, stack_adjust)
}
else
{
if(this.operand_size_32)
if(this.is_osize_32())
{
this.adjust_stack_reg(2 * 4 + stack_adjust);
}
@ -2171,7 +2160,7 @@ CPU.prototype.far_jump = function(eip, selector, is_call)
{
if(is_call)
{
if(this.operand_size_32)
if(this.is_osize_32())
{
this.writable_or_pagefault(this.get_stack_pointer(-8), 8);
this.push32(this.sreg[reg_cs]);
@ -2461,7 +2450,7 @@ CPU.prototype.far_jump = function(eip, selector, is_call)
if(is_call)
{
if(this.operand_size_32)
if(this.is_osize_32())
{
this.writable_or_pagefault(this.get_stack_pointer(-8), 8);
this.push32(this.sreg[reg_cs]);
@ -2648,7 +2637,6 @@ CPU.prototype.hlt_op = function()
this.trigger_gp(0);
}
// hlt
if((this.flags & flag_interrupt) === 0)
{
this.debug.show("cpu halted");
@ -2659,7 +2647,21 @@ CPU.prototype.hlt_op = function()
{
// get out of here and into hlt_loop
this.in_hlt = true;
throw MAGIC_CPU_EXCEPTION;
if(false) // possibly unsafe, test in safari
{
this.hlt_loop();
this.diverged();
if(this.in_hlt)
{
throw MAGIC_CPU_EXCEPTION;
}
}
else
{
throw MAGIC_CPU_EXCEPTION;
}
}
};
@ -2681,6 +2683,8 @@ CPU.prototype.raise_exception = function(interrupt_nr)
CPU.prototype.raise_exception_with_code = function(interrupt_nr, error_code)
{
dbg_assert(typeof error_code === "number");
//if(DEBUG)
//{
// dbg_log("Exception " + h(interrupt_nr) + " err=" + h(error_code) + " at " + h(this.previous_ip >>> 0, 8) + " (cs=" + h(this.sreg[reg_cs], 4) + ")", LOG_CPU);
@ -2791,17 +2795,22 @@ CPU.prototype.get_seg_prefix_cs = function()
*/
CPU.prototype.get_seg_prefix = function(default_segment /*, offset*/)
{
if(this.segment_prefix === SEG_PREFIX_NONE)
var prefix = this.prefixes & PREFIX_MASK_SEGMENT;
if(prefix)
{
return this.get_seg(default_segment /*, offset*/);
}
else if(this.segment_prefix === SEG_PREFIX_ZERO)
{
return 0;
if(prefix === SEG_PREFIX_ZERO)
{
return 0;
}
else
{
return this.get_seg(prefix - 1 /*, offset*/);
}
}
else
{
return this.get_seg(this.segment_prefix /*, offset*/);
return this.get_seg(default_segment /*, offset*/);
}
};
@ -2962,7 +2971,8 @@ CPU.prototype.read_write_e32 = function()
var virt_addr = this.modrm_resolve(this.modrm_byte);
this.phys_addr = this.translate_address_write(virt_addr);
if(this.paging && (virt_addr & 0xFFF) >= 0xFFD) {
this.phys_addr_high = this.translate_address_write(virt_addr + 3 | 0);
//this.phys_addr_high = this.translate_address_write(virt_addr + 3 | 0);
this.phys_addr_high = this.translate_address_write(virt_addr + 3 & ~3) | (virt_addr + 3) & 3;
dbg_assert(this.phys_addr_high);
return this.virt_boundary_read32s(this.phys_addr, this.phys_addr_high);
} else {
@ -3059,6 +3069,8 @@ CPU.prototype.handle_irqs = function()
{
dbg_assert(!this.page_fault);
this.diverged();
if((this.flags & flag_interrupt) && !this.page_fault)
{
if(this.devices.pic)
@ -3238,20 +3250,16 @@ CPU.prototype.cpuid = function()
CPU.prototype.update_cs_size = function(new_size)
{
this.is_32 = this.operand_size_32 = this.address_size_32 = new_size;
this.clear_instruction_cache();
this.is_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)
if(this.is_32)
{
this.table = this.table32;
}
@ -3261,24 +3269,6 @@ CPU.prototype.update_operand_size = function()
}
};
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
*/
@ -4061,6 +4051,60 @@ CPU.prototype.trigger_pagefault = function(write, user, present)
throw MAGIC_CPU_EXCEPTION;
};
CPU.prototype.is_osize_32 = function()
{
return this.is_32 !== ((this.prefixes & PREFIX_MASK_OPSIZE) === PREFIX_MASK_OPSIZE);
};
CPU.prototype.is_asize_32 = function()
{
return this.is_32 !== ((this.prefixes & PREFIX_MASK_ADDRSIZE) === PREFIX_MASK_ADDRSIZE);
};
CPU.prototype.get_reg_asize = function(reg)
{
dbg_assert(reg === reg_ecx || reg === reg_esi || reg === reg_edi);
var r = this.reg32s[reg];
if(this.is_asize_32())
{
return r;
}
else
{
return r & 0xFFFF;
}
};
CPU.prototype.set_ecx_asize = function(value)
{
if(this.is_asize_32())
{
this.reg32s[reg_ecx] = value;
}
else
{
this.reg16[reg_cx] = value;
}
};
CPU.prototype.add_reg_asize = function(reg, value)
{
dbg_assert(reg === reg_ecx || reg === reg_esi || reg === reg_edi);
if(this.is_asize_32())
{
this.reg32s[reg] += value;
}
else
{
this.reg16[reg << 1] += value;
}
};
CPU.prototype.decr_ecx_asize = function()
{
return this.is_asize_32() ? --this.reg32s[reg_ecx] : --this.reg16[reg_cx];
}
// Closure Compiler's way of exporting
if(typeof window !== "undefined")

View file

@ -322,7 +322,7 @@ FPU.prototype.safe_tag_word = function(tag_word)
FPU.prototype.fstenv = function(addr)
{
if(this.cpu.operand_size_32)
if(this.cpu.is_osize_32())
{
this.cpu.writable_or_pagefault(addr, 26);
@ -345,7 +345,7 @@ FPU.prototype.fstenv = function(addr)
FPU.prototype.fldenv = function(addr)
{
if(this.cpu.operand_size_32)
if(this.cpu.is_osize_32())
{
this.control_word = this.cpu.safe_read16(addr);

View file

@ -6,13 +6,13 @@ var t32 = [];
t[0x00] = cpu => { cpu.read_modrm_byte(); cpu.write_e8(cpu.add8(cpu.read_write_e8(), cpu.read_g8())); };
t16[0x01] = cpu => { cpu.read_modrm_byte(); cpu.write_e16(cpu.add16(cpu.read_write_e16(), cpu.read_g16())); };
t32[0x01] = cpu => { cpu.read_modrm_byte(); cpu.write_e32(cpu.add32(cpu.read_write_e32(), cpu.read_g32s())); }
t32[0x01] = cpu => { cpu.read_modrm_byte(); cpu.write_e32(cpu.add32(cpu.read_write_e32(), cpu.read_g32s())); };
t[0x02] = cpu => { cpu.read_modrm_byte(); cpu.write_g8(cpu.add8(cpu.read_g8(), cpu.read_e8())); };
t16[0x03] = cpu => { cpu.read_modrm_byte(); cpu.write_g16(cpu.add16(cpu.read_g16(), cpu.read_e16())); };
t32[0x03] = cpu => { cpu.read_modrm_byte(); cpu.write_g32(cpu.add32(cpu.read_g32s(), cpu.read_e32s())); }
t32[0x03] = cpu => { cpu.read_modrm_byte(); cpu.write_g32(cpu.add32(cpu.read_g32s(), cpu.read_e32s())); };
t[0x04] = cpu => { cpu.reg8[reg_al] = cpu.add8(cpu.reg8[reg_al], cpu.read_op8()); };
t16[0x05] = cpu => { cpu.reg16[reg_ax] = cpu.add16(cpu.reg16[reg_ax], cpu.read_op16()); };
t32[0x05] = cpu => { cpu.reg32s[reg_eax] = cpu.add32(cpu.reg32s[reg_eax], cpu.read_op32s()); }
t32[0x05] = cpu => { cpu.reg32s[reg_eax] = cpu.add32(cpu.reg32s[reg_eax], cpu.read_op32s()); };
t16[0x06] = cpu => { cpu.push16(cpu.sreg[reg_es]); };
t32[0x06] = cpu => { cpu.push32(cpu.sreg[reg_es]); };
@ -27,7 +27,7 @@ t32[0x07] = cpu => {
t[0x08] = cpu => { cpu.read_modrm_byte(); cpu.write_e8(cpu.or8(cpu.read_write_e8(), cpu.read_g8())); };
t16[0x09] = cpu => { cpu.read_modrm_byte(); cpu.write_e16(cpu.or16(cpu.read_write_e16(), cpu.read_g16())); };
t32[0x09] = cpu => { cpu.read_modrm_byte(); cpu.write_e32(cpu.or32(cpu.read_write_e32(), cpu.read_g32s())); }
t32[0x09] = cpu => { cpu.read_modrm_byte(); cpu.write_e32(cpu.or32(cpu.read_write_e32(), cpu.read_g32s())); };
t[0x0a] = cpu => { cpu.read_modrm_byte(); cpu.write_g8(cpu.or8(cpu.read_g8(), cpu.read_e8())); };
t16[0x0b] = cpu => { cpu.read_modrm_byte(); cpu.write_g16(cpu.or16(cpu.read_g16(), cpu.read_e16())); };
t32[0x0b] = cpu => { cpu.read_modrm_byte(); cpu.write_g32(cpu.or32(cpu.read_g32s(), cpu.read_e32s())); }
@ -39,10 +39,10 @@ t32[0x0d] = cpu => { cpu.reg32s[reg_eax] = cpu.or32(cpu.reg32s[reg_eax], cpu.rea
t16[0x0E] = cpu => { cpu.push16(cpu.sreg[reg_cs]); };
t32[0x0E] = cpu => { cpu.push32(cpu.sreg[reg_cs]); };
t16[0x0F] = cpu => {
cpu.table0F_16[cpu.read_op8()](cpu);
cpu.table0F_16[cpu.read_op0F()](cpu);
};
t32[0x0F] = cpu => {
cpu.table0F_32[cpu.read_op8()](cpu);
cpu.table0F_32[cpu.read_op0F()](cpu);
};
t[0x10] = cpu => { cpu.read_modrm_byte(); cpu.write_e8(cpu.adc8(cpu.read_write_e8(), cpu.read_g8())); };
@ -103,7 +103,7 @@ t16[0x25] = cpu => { cpu.reg16[reg_ax] = cpu.and16(cpu.reg16[reg_ax], cpu.read_o
t32[0x25] = cpu => { cpu.reg32s[reg_eax] = cpu.and32(cpu.reg32s[reg_eax], cpu.read_op32s()); }
t[0x26] = cpu => { cpu.segment_prefix = reg_es; cpu.run_prefix_instruction(); cpu.segment_prefix = SEG_PREFIX_NONE; };
t[0x26] = cpu => { cpu.segment_prefix_op(reg_es); };
t[0x27] = cpu => { cpu.bcd_daa(); };
t[0x28] = cpu => { cpu.read_modrm_byte(); cpu.write_e8(cpu.sub8(cpu.read_write_e8(), cpu.read_g8())); };
@ -116,7 +116,7 @@ t[0x2c] = cpu => { cpu.reg8[reg_al] = cpu.sub8(cpu.reg8[reg_al], cpu.read_op8())
t16[0x2d] = cpu => { cpu.reg16[reg_ax] = cpu.sub16(cpu.reg16[reg_ax], cpu.read_op16()); };
t32[0x2d] = cpu => { cpu.reg32s[reg_eax] = cpu.sub32(cpu.reg32s[reg_eax], cpu.read_op32s()); }
t[0x2E] = cpu => { cpu.segment_prefix = reg_cs; cpu.run_prefix_instruction(); cpu.segment_prefix = SEG_PREFIX_NONE; };
t[0x2E] = cpu => { cpu.segment_prefix_op(reg_cs); };
t[0x2F] = cpu => { cpu.bcd_das(); };
t[0x30] = cpu => { cpu.read_modrm_byte(); cpu.write_e8(cpu.xor8(cpu.read_write_e8(), cpu.read_g8())); };
@ -129,7 +129,7 @@ t[0x34] = cpu => { cpu.reg8[reg_al] = cpu.xor8(cpu.reg8[reg_al], cpu.read_op8())
t16[0x35] = cpu => { cpu.reg16[reg_ax] = cpu.xor16(cpu.reg16[reg_ax], cpu.read_op16()); };
t32[0x35] = cpu => { cpu.reg32s[reg_eax] = cpu.xor32(cpu.reg32s[reg_eax], cpu.read_op32s()); }
t[0x36] = cpu => { cpu.segment_prefix = reg_ss; cpu.run_prefix_instruction(); cpu.segment_prefix = SEG_PREFIX_NONE; };
t[0x36] = cpu => { cpu.segment_prefix_op(reg_ss); };
t[0x37] = cpu => { cpu.bcd_aaa(); };
t[0x38] = cpu => { cpu.read_modrm_byte(); cpu.cmp8(cpu.read_e8(), cpu.read_g8()); };
@ -142,7 +142,7 @@ t[0x3C] = cpu => { cpu.cmp8(cpu.reg8[reg_al], cpu.read_op8()); };
t16[0x3D] = cpu => { cpu.cmp16(cpu.reg16[reg_ax], cpu.read_op16()); };
t32[0x3D] = cpu => { cpu.cmp32(cpu.reg32s[reg_eax], cpu.read_op32s()); }
t[0x3E] = cpu => { cpu.segment_prefix = reg_ds; cpu.run_prefix_instruction(); cpu.segment_prefix = SEG_PREFIX_NONE; };
t[0x3E] = cpu => { cpu.segment_prefix_op(reg_ds); };
t[0x3F] = cpu => { cpu.bcd_aas(); };
@ -241,31 +241,23 @@ t[0x63] = cpu => { cpu.read_modrm_byte();
}
};
t[0x64] = cpu => { cpu.segment_prefix = reg_fs; cpu.run_prefix_instruction(); cpu.segment_prefix = SEG_PREFIX_NONE; };
t[0x65] = cpu => { cpu.segment_prefix = reg_gs; cpu.run_prefix_instruction(); cpu.segment_prefix = SEG_PREFIX_NONE; };
t[0x64] = cpu => { cpu.segment_prefix_op(reg_fs); };
t[0x65] = cpu => { cpu.segment_prefix_op(reg_gs); };
t[0x66] = cpu => {
// Operand-size override prefix
cpu.operand_size_32 = !cpu.is_32;
cpu.update_operand_size();
cpu.prefixes |= PREFIX_MASK_OPSIZE;
cpu.run_prefix_instruction();
cpu.operand_size_32 = cpu.is_32;
cpu.update_operand_size();
cpu.prefixes = 0;
};
t[0x67] = 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();
dbg_assert(cpu.is_asize_32() === cpu.is_32);
cpu.prefixes |= PREFIX_MASK_ADDRSIZE;
cpu.run_prefix_instruction();
cpu.address_size_32 = cpu.is_32;
cpu.update_address_size();
cpu.prefixes = 0;
};
t16[0x68] = cpu => { cpu.push16(cpu.read_op16()); };
@ -351,9 +343,7 @@ t32[0x81] = cpu => { cpu.read_modrm_byte();
case 7: cpu.cmp32(cpu.read_e32s(), cpu.read_op32s()); break;
}
};
t[0x82] = cpu => {
cpu.table[0x80](cpu); // alias
};
t[0x82] = t[0x80]; // alias
t16[0x83] = cpu => { cpu.read_modrm_byte();
switch(cpu.modrm_byte >> 3 & 7)
{
@ -428,9 +418,9 @@ t16[0x8D] = cpu => { cpu.read_modrm_byte();
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.prefixes |= SEG_PREFIX_ZERO;
cpu.reg16[mod << 1] = cpu.modrm_resolve(cpu.modrm_byte);
cpu.segment_prefix = SEG_PREFIX_NONE;
cpu.prefixes = 0;
};
t32[0x8D] = cpu => { cpu.read_modrm_byte();
if(cpu.modrm_byte >= 0xC0)
@ -440,9 +430,9 @@ t32[0x8D] = cpu => { cpu.read_modrm_byte();
}
var mod = cpu.modrm_byte >> 3 & 7;
cpu.segment_prefix = SEG_PREFIX_ZERO;
cpu.prefixes |= SEG_PREFIX_ZERO;
cpu.reg32s[mod] = cpu.modrm_resolve(cpu.modrm_byte);
cpu.segment_prefix = SEG_PREFIX_NONE;
cpu.prefixes = 0;
};
t[0x8E] = cpu => { cpu.read_modrm_byte();
@ -516,14 +506,15 @@ t32[0x99] = cpu => { /* cdq */ cpu.reg32s[reg_edx] = cpu.reg32s[reg_eax] >> 31;
t16[0x9A] = cpu => {
// callf
var new_ip = cpu.read_op16();
var new_cs = cpu.read_second_op16();
var new_cs = cpu.read_disp16();
cpu.far_jump(new_ip, new_cs, true);
dbg_assert(cpu.address_size_32 || cpu.get_real_eip() < 0x10000);
dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000);
cpu.diverged();
};
t32[0x9A] = cpu => {
var new_ip = cpu.read_op32s();
var new_cs = cpu.read_second_op16();
var new_cs = cpu.read_disp16();
if(!cpu.protected_mode || cpu.vm86_mode())
{
@ -534,7 +525,8 @@ t32[0x9A] = cpu => {
}
cpu.far_jump(new_ip, new_cs, true);
dbg_assert(cpu.address_size_32 || cpu.get_real_eip() < 0x10000);
dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000);
cpu.diverged();
};
t[0x9B] = cpu => {
@ -606,7 +598,7 @@ t16[0x9D] = cpu => {
//cpu.instruction_pointer = cpu.previous_ip;
//cpu.raise_exception(1);
}
else // XXX
else
{
cpu.handle_irqs();
}
@ -660,9 +652,9 @@ t32[0xA3] = cpu => {
cpu.safe_write32(cpu.read_moffs(), cpu.reg32s[reg_eax]);
};
t[0xA4] = cpu => { movsb(cpu); };
t16[0xA5] = cpu => { movsw(cpu); };
t32[0xA5] = cpu => { movsd(cpu); };
t[0xA4] = cpu => { cpu.movsb(); };
t16[0xA5] = cpu => { cpu.movsw(); };
t32[0xA5] = cpu => { cpu.movsd(); };
t[0xA6] = cpu => { cmpsb(cpu); };
t16[0xA7] = cpu => { cmpsw(cpu); };
t32[0xA7] = cpu => { cmpsd(cpu); };
@ -772,27 +764,31 @@ t16[0xC2] = cpu => {
var imm16 = cpu.read_op16();
cpu.instruction_pointer = cpu.get_seg(reg_cs) + cpu.pop16() | 0;
dbg_assert(cpu.address_size_32 || cpu.get_real_eip() < 0x10000);
dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000);
cpu.adjust_stack_reg(imm16);
cpu.diverged();
};
t32[0xC2] = cpu => {
// retn
var imm16 = cpu.read_op16();
var ip = cpu.pop32s();
dbg_assert(cpu.address_size_32 || ip < 0x10000);
dbg_assert(cpu.is_asize_32() || ip < 0x10000);
cpu.instruction_pointer = cpu.get_seg(reg_cs) + ip | 0;
cpu.adjust_stack_reg(imm16);
cpu.diverged();
};
t16[0xC3] = cpu => {
// retn
cpu.instruction_pointer = cpu.get_seg(reg_cs) + cpu.pop16() | 0;
cpu.diverged();
};
t32[0xC3] = cpu => {
// retn
var ip = cpu.pop32s();
dbg_assert(cpu.address_size_32 || ip < 0x10000);
dbg_assert(cpu.is_asize_32() || ip < 0x10000);
cpu.instruction_pointer = cpu.get_seg(reg_cs) + ip | 0;
cpu.diverged();
};
t16[0xC4] = cpu => { cpu.read_modrm_byte();
@ -830,8 +826,8 @@ t32[0xC7] = cpu => { cpu.read_modrm_byte();
}
}
t16[0xC8] = cpu => { cpu.enter16(cpu.read_op16(), cpu.read_second_op8()); };
t32[0xC8] = cpu => { cpu.enter32(cpu.read_op16(), cpu.read_second_op8()); };
t16[0xC8] = cpu => { cpu.enter16(cpu.read_op16(), cpu.read_disp8()); };
t32[0xC8] = cpu => { cpu.enter32(cpu.read_op16(), cpu.read_disp8()); };
t16[0xC9] = cpu => {
// leave
var old_vbp = cpu.stack_size_32 ? cpu.reg32s[reg_ebp] : cpu.reg16[reg_bp];
@ -852,6 +848,7 @@ t16[0xCA] = cpu => {
var cs = cpu.safe_read16(cpu.get_stack_pointer(2));
cpu.far_return(ip, cs, imm16);
cpu.diverged();
};
t32[0xCA] = cpu => {
// retf
@ -860,7 +857,8 @@ t32[0xCA] = cpu => {
var cs = cpu.safe_read32s(cpu.get_stack_pointer(4)) & 0xFFFF;
cpu.far_return(ip, cs, imm16);
dbg_assert(cpu.address_size_32 || cpu.get_real_eip() < 0x10000);
dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000);
cpu.diverged();
};
t16[0xCB] = cpu => {
// retf
@ -868,7 +866,8 @@ t16[0xCB] = cpu => {
var cs = cpu.safe_read16(cpu.get_stack_pointer(2));
cpu.far_return(ip, cs, 0);
dbg_assert(cpu.address_size_32 || cpu.get_real_eip() < 0x10000);
dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000);
cpu.diverged();
};
t32[0xCB] = cpu => {
// retf
@ -876,7 +875,8 @@ t32[0xCB] = cpu => {
var cs = cpu.safe_read32s(cpu.get_stack_pointer(4)) & 0xFFFF;
cpu.far_return(ip, cs, 0);
dbg_assert(cpu.address_size_32 || cpu.get_real_eip() < 0x10000);
dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000);
cpu.diverged();
};
t[0xCC] = cpu => {
@ -884,11 +884,13 @@ t[0xCC] = cpu => {
// TODO: inhibit iopl checks
dbg_log("INT3", LOG_CPU);
cpu.call_interrupt_vector(3, true, false);
cpu.diverged();
};
t[0xCD] = cpu => {
// INT
var imm8 = cpu.read_op8();
cpu.call_interrupt_vector(imm8, true, false);
cpu.diverged();
};
t[0xCE] = cpu => {
// INTO
@ -898,14 +900,17 @@ t[0xCE] = cpu => {
// TODO: inhibit iopl checks
cpu.call_interrupt_vector(4, true, false);
}
cpu.diverged();
};
t16[0xCF] = cpu => {
// iret
cpu.iret16();
cpu.diverged();
};
t32[0xCF] = cpu => {
cpu.iret32();
cpu.diverged();
};
t[0xD0] = cpu => { cpu.read_modrm_byte();
@ -1022,13 +1027,13 @@ t[0xD6] = cpu => {
};
t[0xD7] = cpu => {
// xlat
if(cpu.address_size_32)
if(cpu.is_asize_32())
{
cpu.reg8[reg_al] = cpu.safe_read8(cpu.get_seg_prefix(reg_ds) + cpu.reg32s[reg_ebx] + cpu.reg8[reg_al]);
cpu.reg8[reg_al] = cpu.safe_read8(cpu.get_seg_prefix(reg_ds) + cpu.reg32s[reg_ebx] + cpu.reg8[reg_al] | 0);
}
else
{
cpu.reg8[reg_al] = cpu.safe_read8(cpu.get_seg_prefix(reg_ds) + cpu.reg16[reg_bx] + cpu.reg8[reg_al]);
cpu.reg8[reg_al] = cpu.safe_read8(cpu.get_seg_prefix(reg_ds) + (cpu.reg16[reg_bx] + cpu.reg8[reg_al] & 0xFFFF) | 0);
}
};
@ -1098,31 +1103,37 @@ t[0xE4] = cpu => {
var port = cpu.read_op8();
cpu.test_privileges_for_io(port, 1);
cpu.reg8[reg_al] = cpu.io.port_read8(port);
cpu.diverged();
};
t16[0xE5] = cpu => {
var port = cpu.read_op8();
cpu.test_privileges_for_io(port, 2);
cpu.reg16[reg_ax] = cpu.io.port_read16(port);
cpu.diverged();
};
t32[0xE5] = cpu => {
var port = cpu.read_op8();
cpu.test_privileges_for_io(port, 4);
cpu.reg32s[reg_eax] = cpu.io.port_read32(port);
cpu.diverged();
};
t[0xE6] = cpu => {
var port = cpu.read_op8();
cpu.test_privileges_for_io(port, 1);
cpu.io.port_write8(port, cpu.reg8[reg_al]);
cpu.diverged();
};
t16[0xE7] = cpu => {
var port = cpu.read_op8();
cpu.test_privileges_for_io(port, 2);
cpu.io.port_write16(port, cpu.reg16[reg_ax]);
cpu.diverged();
};
t32[0xE7] = cpu => {
var port = cpu.read_op8();
cpu.test_privileges_for_io(port, 4);
cpu.io.port_write32(port, cpu.reg32s[reg_eax]);
cpu.diverged();
};
t16[0xE8] = cpu => {
@ -1131,6 +1142,7 @@ t16[0xE8] = cpu => {
cpu.push16(cpu.get_real_eip());
cpu.jmp_rel16(imm16);
cpu.diverged();
};
t32[0xE8] = cpu => {
// call
@ -1138,71 +1150,83 @@ t32[0xE8] = cpu => {
cpu.push32(cpu.get_real_eip());
cpu.instruction_pointer = cpu.instruction_pointer + imm32s | 0;
dbg_assert(cpu.address_size_32 || cpu.get_real_eip() < 0x10000);
dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000);
cpu.diverged();
};
t16[0xE9] = cpu => {
// jmp
var imm16 = cpu.read_op16();
cpu.jmp_rel16(imm16);
cpu.diverged();
};
t32[0xE9] = cpu => {
// jmp
var imm32s = cpu.read_op32s();
cpu.instruction_pointer = cpu.instruction_pointer + imm32s | 0;
dbg_assert(cpu.address_size_32 || cpu.get_real_eip() < 0x10000);
dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000);
cpu.diverged();
};
t16[0xEA] = cpu => {
// jmpf
var ip = cpu.read_op16();
var cs = cpu.read_second_op16();
var cs = cpu.read_disp16();
cpu.far_jump(ip, cs, false);
dbg_assert(cpu.address_size_32 || cpu.get_real_eip() < 0x10000);
dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000);
cpu.diverged();
};
t32[0xEA] = cpu => {
// jmpf
var new_ip = cpu.read_op32s();
var cs = cpu.read_second_op16();
var cs = cpu.read_disp16();
cpu.far_jump(new_ip, cs, false);
dbg_assert(cpu.address_size_32 || cpu.get_real_eip() < 0x10000);
dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000);
cpu.diverged();
};
t[0xEB] = cpu => {
// jmp near
var imm8 = cpu.read_op8s();
cpu.instruction_pointer = cpu.instruction_pointer + imm8 | 0;
dbg_assert(cpu.address_size_32 || cpu.get_real_eip() < 0x10000);
dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000);
cpu.protected_mode = (cpu.cr[0] & CR0_PE) === CR0_PE;
cpu.diverged();
};
t[0xEC] = cpu => {
var port = cpu.reg16[reg_dx];
cpu.test_privileges_for_io(port, 1);
cpu.reg8[reg_al] = cpu.io.port_read8(port);
cpu.diverged();
};
t16[0xED] = cpu => {
var port = cpu.reg16[reg_dx];
cpu.test_privileges_for_io(port, 2);
cpu.reg16[reg_ax] = cpu.io.port_read16(port);
cpu.diverged();
};
t32[0xED] = cpu => {
var port = cpu.reg16[reg_dx];
cpu.test_privileges_for_io(port, 4);
cpu.reg32s[reg_eax] = cpu.io.port_read32(port);
cpu.diverged();
};
t[0xEE] = cpu => {
var port = cpu.reg16[reg_dx];
cpu.test_privileges_for_io(port, 1);
cpu.io.port_write8(port, cpu.reg8[reg_al]);
cpu.diverged();
};
t16[0xEF] = cpu => {
var port = cpu.reg16[reg_dx];
cpu.test_privileges_for_io(port, 2);
cpu.io.port_write16(port, cpu.reg16[reg_ax]);
cpu.diverged();
};
t32[0xEF] = cpu => {
var port = cpu.reg16[reg_dx];
cpu.test_privileges_for_io(port, 4);
cpu.io.port_write32(port, cpu.reg32s[reg_eax]);
cpu.diverged();
};
t[0xF0] = cpu => {
@ -1222,17 +1246,17 @@ t[0xF1] = cpu => {
t[0xF2] = cpu => {
// repnz
dbg_assert(cpu.repeat_string_prefix === REPEAT_STRING_PREFIX_NONE);
cpu.repeat_string_prefix = REPEAT_STRING_PREFIX_NZ;
dbg_assert((cpu.prefixes & PREFIX_MASK_REP) === 0);
cpu.prefixes |= PREFIX_REPNZ;
cpu.run_prefix_instruction();
cpu.repeat_string_prefix = REPEAT_STRING_PREFIX_NONE;
cpu.prefixes = 0;
};
t[0xF3] = cpu => {
// repz
dbg_assert(cpu.repeat_string_prefix === REPEAT_STRING_PREFIX_NONE);
cpu.repeat_string_prefix = REPEAT_STRING_PREFIX_Z;
dbg_assert((cpu.prefixes & PREFIX_MASK_REP) === 0);
cpu.prefixes |= PREFIX_REPZ;
cpu.run_prefix_instruction();
cpu.repeat_string_prefix = REPEAT_STRING_PREFIX_NONE;
cpu.prefixes = 0;
};
t[0xF4] = cpu => {
@ -1439,7 +1463,8 @@ t16[0xFF] = cpu => { cpu.read_modrm_byte();
var data = cpu.read_e16();
cpu.push16(cpu.get_real_eip());
cpu.instruction_pointer = cpu.get_seg(reg_cs) + data | 0;
dbg_assert(cpu.address_size_32 || cpu.get_real_eip() < 0x10000);
dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000);
cpu.diverged();
break;
case 3:
// 3, callf
@ -1455,13 +1480,15 @@ t16[0xFF] = cpu => { cpu.read_modrm_byte();
var new_cs = cpu.safe_read16(virt_addr + 2 | 0);
cpu.far_jump(new_ip, new_cs, true);
dbg_assert(cpu.address_size_32 || cpu.get_real_eip() < 0x10000);
dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000);
cpu.diverged();
break;
case 4:
// 4, jmp near
var data = cpu.read_e16();
cpu.instruction_pointer = cpu.get_seg(reg_cs) + data | 0;
dbg_assert(cpu.address_size_32 || cpu.get_real_eip() < 0x10000);
dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000);
cpu.diverged();
break;
case 5:
// 5, jmpf
@ -1477,7 +1504,8 @@ t16[0xFF] = cpu => { cpu.read_modrm_byte();
var new_cs = cpu.safe_read16(virt_addr + 2 | 0);
cpu.far_jump(new_ip, new_cs, false);
dbg_assert(cpu.address_size_32 || cpu.get_real_eip() < 0x10000);
dbg_assert(cpu.is_asize_32() || cpu.get_real_eip() < 0x10000);
cpu.diverged();
break;
case 6:
// 6, push
@ -1502,8 +1530,9 @@ t32[0xFF] = cpu => { cpu.read_modrm_byte();
var data = cpu.read_e32s();
cpu.push32(cpu.get_real_eip());
dbg_assert(cpu.address_size_32 || data < 0x10000);
dbg_assert(cpu.is_asize_32() || data < 0x10000);
cpu.instruction_pointer = cpu.get_seg(reg_cs) + data | 0;
cpu.diverged();
break;
case 3:
// 3, callf
@ -1527,13 +1556,15 @@ t32[0xFF] = cpu => { cpu.read_modrm_byte();
}
cpu.far_jump(new_ip, new_cs, true);
dbg_assert(cpu.address_size_32 || new_ip < 0x10000);
dbg_assert(cpu.is_asize_32() || new_ip < 0x10000);
cpu.diverged();
break;
case 4:
// 4, jmp near
var data = cpu.read_e32s();
dbg_assert(cpu.address_size_32 || data < 0x10000);
dbg_assert(cpu.is_asize_32() || data < 0x10000);
cpu.instruction_pointer = cpu.get_seg(reg_cs) + data | 0;
cpu.diverged();
break;
case 5:
// 5, jmpf
@ -1557,7 +1588,8 @@ t32[0xFF] = cpu => { cpu.read_modrm_byte();
}
cpu.far_jump(new_ip, new_cs, false);
dbg_assert(cpu.address_size_32 || new_ip < 0x10000);
dbg_assert(cpu.is_asize_32() || new_ip < 0x10000);
cpu.diverged();
break;
case 6:
// push
@ -1610,7 +1642,7 @@ t[0x00] = cpu => { cpu.read_modrm_byte();
case 0:
// sldt
cpu.set_e16(cpu.sreg[reg_ldtr]);
if(cpu.modrm_byte >= 0xC0)
if(cpu.is_osize_32() && cpu.modrm_byte >= 0xC0)
{
cpu.reg32s[cpu.modrm_byte & 7] &= 0xFFFF;
}
@ -1618,7 +1650,7 @@ t[0x00] = cpu => { cpu.read_modrm_byte();
case 1:
// str
cpu.set_e16(cpu.sreg[reg_tr]);
if(cpu.modrm_byte >= 0xC0)
if(cpu.is_osize_32() && cpu.modrm_byte >= 0xC0)
{
cpu.reg32s[cpu.modrm_byte & 7] &= 0xFFFF;
}
@ -1662,7 +1694,14 @@ t[0x01] = cpu => { cpu.read_modrm_byte();
if(mod === 4)
{
// smsw
cpu.set_e16(cpu.cr[0]);
if(cpu.modrm_byte >= 0xC0 && cpu.is_osize_32())
{
cpu.set_e32(cpu.cr[0]);
}
else
{
cpu.set_e16(cpu.cr[0]);
}
return;
}
else if(mod === 6)
@ -1704,14 +1743,14 @@ t[0x01] = cpu => { cpu.read_modrm_byte();
// sgdt
cpu.writable_or_pagefault(addr, 6);
cpu.safe_write16(addr, cpu.gdtr_size);
var mask = cpu.operand_size_32 ? -1 : 0x00FFFFFF;
var mask = cpu.is_osize_32() ? -1 : 0x00FFFFFF;
cpu.safe_write32(addr + 2, cpu.gdtr_offset & mask);
break;
case 1:
// sidt
cpu.writable_or_pagefault(addr, 6);
cpu.safe_write16(addr, cpu.idtr_size);
var mask = cpu.operand_size_32 ? -1 : 0x00FFFFFF;
var mask = cpu.is_osize_32() ? -1 : 0x00FFFFFF;
cpu.safe_write32(addr + 2, cpu.idtr_offset & mask);
break;
case 2:
@ -1727,7 +1766,7 @@ t[0x01] = cpu => { cpu.read_modrm_byte();
cpu.gdtr_size = size;
cpu.gdtr_offset = offset;
if(!cpu.operand_size_32)
if(!cpu.is_osize_32())
{
cpu.gdtr_offset &= 0xFFFFFF;
}
@ -1750,7 +1789,7 @@ t[0x01] = cpu => { cpu.read_modrm_byte();
cpu.idtr_size = size;
cpu.idtr_offset = offset;
if(!cpu.operand_size_32)
if(!cpu.is_osize_32())
{
cpu.idtr_offset &= 0xFFFFFF;
}
@ -1968,7 +2007,7 @@ t[0x22] = cpu => { cpu.read_modrm_byte();
case 3:
//dbg_log("cr3=" + h(data >>> 0), LOG_CPU);
cpu.cr[3] = data;
dbg_assert((cpu.cr[3] & 0xFFF) === 0);
dbg_assert((cpu.cr[3] & 0xFFF) === 0); // os2 v4
cpu.clear_tlb();
//dump_page_directory();
@ -2053,8 +2092,11 @@ t[0x30] = cpu => {
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);
if(index !== IA32_SYSENTER_ESP)
{
dbg_log("wrmsr ecx=" + h(index >>> 0, 8) +
" data=" + h(high >>> 0, 8) + ":" + h(low >>> 0, 8), LOG_CPU);
}
switch(index)
{
@ -2199,8 +2241,8 @@ t[0x34] = cpu => {
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);
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;
@ -2224,6 +2266,7 @@ t[0x34] = cpu => {
cpu.segment_offsets[reg_ss] = 0;
cpu.stack_size_32 = true;
cpu.diverged();
};
t[0x35] = cpu => {
@ -2235,8 +2278,8 @@ t[0x35] = cpu => {
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);
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];
@ -2259,6 +2302,7 @@ t[0x35] = cpu => {
cpu.segment_offsets[reg_ss] = 0;
cpu.stack_size_32 = true;
cpu.diverged();
};
t[0x36] = cpu => { cpu.undefined_instruction(); };
@ -2571,6 +2615,9 @@ t[0xB0] = cpu => { cpu.read_modrm_byte();
}
else
{
if(cpu.modrm_byte < 0xC0)
cpu.safe_write8(virt_addr, data);
cpu.reg8[reg_al] = data;
}
};
@ -2597,6 +2644,9 @@ t16[0xB1] = cpu => { cpu.read_modrm_byte();
}
else
{
if(cpu.modrm_byte < 0xC0)
cpu.safe_write16(virt_addr, data);
cpu.reg16[reg_ax] = data;
}
};
@ -2624,6 +2674,9 @@ t32[0xB1] = cpu => { cpu.read_modrm_byte();
}
else
{
if(cpu.modrm_byte < 0xC0)
cpu.safe_write32(virt_addr, data);
cpu.reg32s[reg_eax] = data;
}
};
@ -2847,10 +2900,10 @@ t[0xC6] = cpu => { cpu.unimplemented_sse(); };
t[0xC7] = cpu => {
cpu.read_modrm_byte();
// cmpxchg8b
switch(cpu.modrm_byte >> 3 & 7)
{
case 1:
// cmpxchg8b
if(cpu.modrm_byte >= 0xC0)
{
cpu.trigger_ud();
@ -2876,6 +2929,9 @@ t[0xC7] = cpu => {
cpu.reg32s[reg_eax] = m64_low;
cpu.reg32s[reg_edx] = m64_high;
cpu.safe_write32(addr, m64_low);
cpu.safe_write32(addr + 4 | 0, m64_high);
}
cpu.flags_changed &= ~flag_zero;
@ -2894,7 +2950,7 @@ t[0xC7] = cpu => {
}
//dbg_log("rdrand -> " + h(rand >>> 0, 8), LOG_CPU);
if(cpu.operand_size_32)
if(cpu.is_osize_32())
{
cpu.set_e32(rand);
}

View file

@ -10,7 +10,8 @@ var A20_MASK32 = ~(1 << 20 - 2);
/** @const */
var USE_A20 = false;
// called by all memory reads and writes
// called by all memory writes
CPU.prototype.debug_write = function(addr, size, value)
{
if(!DEBUG)
@ -80,7 +81,7 @@ CPU.prototype.mmap_write32 = function(addr, value)
CPU.prototype.in_mapped_range = function(addr)
{
return addr < 0 || addr >= 0xA0000 && addr < 0xC0000 || addr >= this.memory_size;
return (addr | 0) >= 0xA0000 && (addr | 0) < 0xC0000 || (addr >>> 0) >= (this.memory_size >>> 0);
};
/**
@ -185,10 +186,6 @@ CPU.prototype.write8 = function(addr, value)
this.debug_write(addr, 1, value);
if(USE_A20 && !this.a20_enabled) addr &= A20_MASK;
var page = addr >>> MMAP_BLOCK_BITS;
//if(OP_TRANSLATION) this.mem_page_infos[page] |= MEM_PAGE_WRITTEN;
if(this.in_mapped_range(addr))
{
this.mmap_write8(addr, value);
@ -206,16 +203,9 @@ CPU.prototype.write8 = function(addr, value)
CPU.prototype.write16 = function(addr, value)
{
this.debug_write(addr, 2, value);
this.check_write2(addr, 2);
if(USE_A20 && !this.a20_enabled) addr &= A20_MASK;
var page = addr >>> MMAP_BLOCK_BITS;
//if(OP_TRANSLATION)
//{
// this.mem_page_infos[page] |= MEM_PAGE_WRITTEN;
// this.mem_page_infos[addr + 1 >>> MMAP_BLOCK_BITS] |= MEM_PAGE_WRITTEN;
//}
if(this.in_mapped_range(addr))
{
this.mmap_write16(addr, value);
@ -237,10 +227,6 @@ CPU.prototype.write_aligned16 = function(addr, value)
this.debug_write(addr << 1, 2, value);
if(USE_A20 && !this.a20_enabled) addr &= A20_MASK16;
var page = addr >>> MMAP_BLOCK_BITS - 1;
//if(OP_TRANSLATION) this.mem_page_infos[page] |= MEM_PAGE_WRITTEN;
if(this.in_mapped_range(addr << 1))
{
this.mmap_write16(addr << 1, value);
@ -258,16 +244,9 @@ CPU.prototype.write_aligned16 = function(addr, value)
CPU.prototype.write32 = function(addr, value)
{
this.debug_write(addr, 4, value);
this.check_write2(addr, 4);
if(USE_A20 && !this.a20_enabled) addr &= A20_MASK;
var page = addr >>> MMAP_BLOCK_BITS;
//if(OP_TRANSLATION)
//{
// this.mem_page_infos[page] |= MEM_PAGE_WRITTEN;
// this.mem_page_infos[addr + 3 >>> MMAP_BLOCK_BITS] |= MEM_PAGE_WRITTEN;
//}
if(this.in_mapped_range(addr))
{
this.mmap_write32(addr, value);
@ -287,10 +266,6 @@ CPU.prototype.write_aligned32 = function(addr, value)
this.debug_write(addr << 2, 4, value);
if(USE_A20 && !this.a20_enabled) addr &= A20_MASK32;
var page = addr >>> MMAP_BLOCK_BITS - 2;
//if(OP_TRANSLATION) this.mem_page_infos[page] |= MEM_PAGE_WRITTEN;
if(this.in_mapped_range(addr << 2))
{
this.mmap_write32(addr << 2, value);
@ -307,20 +282,10 @@ CPU.prototype.write_aligned32 = function(addr, value)
*/
CPU.prototype.write_blob = function(blob, offset)
{
dbg_assert(blob && blob.length);
this.debug_write(offset, blob.length, 0)
dbg_assert(blob && blob.length >= 0);
this.mem8.set(blob, offset);
//var page = offset >>> 12;
//var end = (offset + blob) >>> 12;
//if(OP_TRANSLATION)
//{
// for(; page <= end; page++)
// {
// this.mem_page_infos[page] |= MEM_PAGE_WRITTEN;
// }
//}
};
/**
@ -330,5 +295,6 @@ CPU.prototype.write_blob = function(blob, offset)
CPU.prototype.write_blob32 = function(blob, offset)
{
dbg_assert(blob && blob.length);
this.debug_write(offset, blob.length << 2, 0);
this.mem32s.set(blob, offset);
};

View file

@ -20,6 +20,11 @@ CPU.prototype.jmpcc8 = function(condition)
if(condition)
{
this.instruction_pointer = this.instruction_pointer + imm8 | 0;
this.branch_taken();
}
else
{
this.branch_not_taken();
}
};
@ -40,6 +45,11 @@ CPU.prototype.jmpcc16 = function(condition)
if(condition)
{
this.jmp_rel16(imm16);
this.branch_taken();
}
else
{
this.branch_not_taken();
}
}
@ -53,6 +63,11 @@ CPU.prototype.jmpcc32 = function(condition)
// since read_op32s modifies instruction_pointer
this.instruction_pointer = this.instruction_pointer + imm32s | 0;
this.branch_taken();
}
else
{
this.branch_not_taken();
}
};
@ -81,37 +96,53 @@ CPU.prototype.setcc = function(condition)
CPU.prototype.loopne = function(imm8s)
{
if(--this.regv[this.reg_vcx] && !this.getzf())
if(this.decr_ecx_asize() && !this.getzf())
{
this.instruction_pointer = this.instruction_pointer + imm8s | 0;
if(!this.operand_size_32) dbg_assert(this.get_real_eip() <= 0xffff);
this.branch_taken();
}
else
{
this.branch_not_taken();
}
}
CPU.prototype.loope = function(imm8s)
{
if(--this.regv[this.reg_vcx] && this.getzf())
if(this.decr_ecx_asize() && this.getzf())
{
this.instruction_pointer = this.instruction_pointer + imm8s | 0;
if(!this.operand_size_32) dbg_assert(this.get_real_eip() <= 0xffff);
this.branch_taken();
}
else
{
this.branch_not_taken();
}
}
CPU.prototype.loop = function(imm8s)
{
if(--this.regv[this.reg_vcx])
if(this.decr_ecx_asize())
{
this.instruction_pointer = this.instruction_pointer + imm8s | 0;
if(!this.operand_size_32) dbg_assert(this.get_real_eip() <= 0xffff);
this.branch_taken();
}
else
{
this.branch_not_taken();
}
}
CPU.prototype.jcxz = function(imm8s)
{
if(this.regv[this.reg_vcx] === 0)
if(this.get_reg_asize(reg_ecx) === 0)
{
this.instruction_pointer = this.instruction_pointer + imm8s | 0;
if(!this.operand_size_32) dbg_assert(this.get_real_eip() <= 0xffff);
this.branch_taken();
}
else
{
this.branch_not_taken();
}
};
@ -266,7 +297,7 @@ CPU.prototype.pusha16 = function()
// make sure we don't get a pagefault after having
// pushed several registers already
this.translate_address_write(this.get_stack_pointer(-15));
this.writable_or_pagefault(this.get_stack_pointer(-16), 16);
this.push16(this.reg16[reg_ax]);
this.push16(this.reg16[reg_cx]);
@ -282,7 +313,7 @@ CPU.prototype.pusha32 = function()
{
var temp = this.reg32s[reg_esp];
this.translate_address_write(this.get_stack_pointer(-31));
this.writable_or_pagefault(this.get_stack_pointer(-32), 32);
this.push32(this.reg32s[reg_eax]);
this.push32(this.reg32s[reg_ecx]);
@ -296,6 +327,7 @@ CPU.prototype.pusha32 = function()
CPU.prototype.popa16 = function()
{
this.translate_address_read(this.get_stack_pointer(0));
this.translate_address_read(this.get_stack_pointer(15));
this.reg16[reg_di] = this.pop16();
@ -310,6 +342,7 @@ CPU.prototype.popa16 = function()
CPU.prototype.popa32 = function()
{
this.translate_address_read(this.get_stack_pointer(0));
this.translate_address_read(this.get_stack_pointer(31));
this.reg32s[reg_edi] = this.pop32s();
@ -419,7 +452,7 @@ CPU.prototype.enter16 = function(size, nesting_level)
this.push16(frame_temp);
}
this.reg16[reg_bp] = frame_temp;
this.reg16[reg_sp] -= size;
this.adjust_stack_reg(-size);
};
CPU.prototype.enter32 = function(size, nesting_level)
@ -441,7 +474,7 @@ CPU.prototype.enter32 = function(size, nesting_level)
this.push32(frame_temp);
}
this.reg32s[reg_ebp] = frame_temp;
this.reg32s[reg_esp] -= size;
this.adjust_stack_reg(-size);
};
CPU.prototype.bswap = function(reg)

View file

@ -203,15 +203,15 @@
};
CPU.prototype.modrm_table32[0x00 | 4] = function(cpu)
{
return cpu.sib_table[cpu.read_sib()](cpu, false) | 0;
return cpu.sib_resolve(false) | 0;
};
CPU.prototype.modrm_table32[0x40 | 4] = function(cpu)
{
return cpu.sib_table[cpu.read_sib()](cpu, true) + cpu.read_disp8s() | 0;
return cpu.sib_resolve(true) + cpu.read_disp8s() | 0;
};
CPU.prototype.modrm_table32[0x80 | 4] = function(cpu)
{
return cpu.sib_table[cpu.read_sib()](cpu, true) + cpu.read_disp32s() | 0;
return cpu.sib_resolve(true) + cpu.read_disp32s() | 0;
};
for(var low = 0; low < 8; low++)
{
@ -1250,16 +1250,4 @@
{
return(cpu.reg32s[reg_edi] << 3) + cpu.get_seg_prefix_ds() + cpu.reg32s[reg_edi] | 0;
};
CPU.prototype.modrm_resolve = function(modrm_byte)
{
if(modrm_byte < 0xC0)
{
return(this.address_size_32 ? this.modrm_table32 : this.modrm_table16)[modrm_byte](this);
}
else
{
return -1;
}
};
})();

View file

@ -41,15 +41,16 @@ function string_get_cycle_count2(size, addr1, addr2)
}
function movsb(cpu)
CPU.prototype.movsb = function()
{
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 cpu = this;
var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -1 : 1;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
@ -69,32 +70,35 @@ function movsb(cpu)
}
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.add_reg_asize(reg_edi, diff);
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
//cpu.instruction_pointer = cpu.previous_ip;
this.movsb();
}
}
else
{
cpu.safe_write8(dest, cpu.safe_read8(src));
cpu.regv[cpu.reg_vdi] += size;
cpu.regv[cpu.reg_vsi] += size;
cpu.add_reg_asize(reg_edi, size);
cpu.add_reg_asize(reg_esi, size);
}
cpu.diverged();
}
function movsw(cpu)
CPU.prototype.movsw = function()
{
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 cpu = this;
var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -2 : 2;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
@ -117,9 +121,9 @@ function movsw(cpu)
}
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.add_reg_asize(reg_edi, diff);
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
}
else
@ -128,37 +132,41 @@ function movsw(cpu)
{
cpu.safe_write16(dest, cpu.safe_read16(src));
dest += size;
cpu.regv[cpu.reg_vdi] += size;
cpu.add_reg_asize(reg_edi, size);
src += size;
cpu.regv[cpu.reg_vsi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0;
cpu.add_reg_asize(reg_esi, size);
cont = cpu.decr_ecx_asize() !== 0;
}
while(cont && cycle_counter--);
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
//cpu.instruction_pointer = cpu.previous_ip;
this.movsw();
}
}
else
{
cpu.safe_write16(dest, cpu.safe_read16(src));
cpu.regv[cpu.reg_vdi] += size;
cpu.regv[cpu.reg_vsi] += size;
cpu.add_reg_asize(reg_edi, size);
cpu.add_reg_asize(reg_esi, size);
}
cpu.diverged();
}
function movsd(cpu)
CPU.prototype.movsd = function()
{
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
var cpu = this;
//if(cpu.prefixes & PREFIX_MASK_REP)
if(false)
{
// often used by memcpy, well worth optimizing
// using cpu.mem32s.set
var ds = cpu.get_seg_prefix(reg_ds),
src = ds + cpu.regv[cpu.reg_vsi] | 0,
src = ds + cpu.get_reg_asize(reg_esi) | 0,
es = cpu.get_seg(reg_es),
dest = es + cpu.regv[cpu.reg_vdi] | 0,
count = cpu.regv[cpu.reg_vcx] >>> 0;
dest = es + cpu.get_reg_asize(reg_edi) | 0,
count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(!count)
{
@ -192,9 +200,9 @@ function movsd(cpu)
!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;
cpu.add_reg_asize(reg_ecx, -count);
cpu.add_reg_asize(reg_edi, diff);
cpu.add_reg_asize(reg_esi, diff);
dest >>= 2;
src >>= 2;
@ -202,7 +210,8 @@ function movsd(cpu)
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
//cpu.instruction_pointer = cpu.previous_ip;
this.movsd();
}
return;
@ -210,13 +219,13 @@ function movsd(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 src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -4 : 4;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
@ -239,9 +248,9 @@ function movsd(cpu)
}
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.add_reg_asize(reg_edi, diff);
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
}
else
@ -250,40 +259,42 @@ function movsd(cpu)
{
cpu.safe_write32(dest, cpu.safe_read32s(src));
dest += size;
cpu.regv[cpu.reg_vdi] += size;
cpu.add_reg_asize(reg_edi, size);
src += size;
cpu.regv[cpu.reg_vsi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0;
cpu.add_reg_asize(reg_esi, size);
cont = cpu.decr_ecx_asize() !== 0;
}
while(cont && cycle_counter--);
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
this.instruction_pointer = this.previous_ip;
//this.movsd();
}
}
else
{
cpu.safe_write32(dest, cpu.safe_read32s(src));
cpu.regv[cpu.reg_vdi] += size;
cpu.regv[cpu.reg_vsi] += size;
cpu.add_reg_asize(reg_edi, size);
cpu.add_reg_asize(reg_esi, size);
}
cpu.diverged();
}
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 src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var data_src, data_dest;
var size = cpu.flags & flag_direction ? -1 : 1;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = cpu.repeat_string_prefix === REPEAT_STRING_PREFIX_Z;
var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ;
var cycle_counter = MAX_COUNT_PER_CYCLE;
var phys_src = cpu.translate_address_read(src);
var phys_dest = cpu.translate_address_read(dest);
@ -301,9 +312,9 @@ function cmpsb(cpu)
}
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.add_reg_asize(reg_edi, diff);
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
if(cont)
{
@ -314,27 +325,28 @@ function cmpsb(cpu)
{
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.add_reg_asize(reg_edi, size);
cpu.add_reg_asize(reg_esi, size);
}
cpu.cmp8(data_src, data_dest);
cpu.diverged();
}
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 src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var data_src, data_dest;
var size = cpu.flags & flag_direction ? -2 : 2;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = cpu.repeat_string_prefix === REPEAT_STRING_PREFIX_Z;
var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ;
var cycle_counter = MAX_COUNT_PER_CYCLE;
if(!(dest & 1) && !(src & 1))
{
@ -355,9 +367,9 @@ function cmpsw(cpu)
}
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.add_reg_asize(reg_edi, diff);
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
}
else
@ -367,10 +379,10 @@ function cmpsw(cpu)
data_dest = cpu.safe_read16(dest);
data_src = cpu.safe_read16(src);
dest += size;
cpu.regv[cpu.reg_vdi] += size;
cpu.add_reg_asize(reg_edi, size);
src += size;
cpu.regv[cpu.reg_vsi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0 && (data_src === data_dest) === is_repz;
cpu.add_reg_asize(reg_esi, size);
cont = cpu.decr_ecx_asize() !== 0 && (data_src === data_dest) === is_repz;
}
while(cont && cycle_counter--);
}
@ -383,27 +395,28 @@ function cmpsw(cpu)
{
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.add_reg_asize(reg_edi, size);
cpu.add_reg_asize(reg_esi, size);
}
cpu.cmp16(data_src, data_dest);
cpu.diverged();
}
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 src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var data_src, data_dest;
var size = cpu.flags & flag_direction ? -4 : 4;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = cpu.repeat_string_prefix === REPEAT_STRING_PREFIX_Z;
var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ;
var cycle_counter = MAX_COUNT_PER_CYCLE;
if(!(dest & 3) && !(src & 3))
{
@ -424,9 +437,9 @@ function cmpsd(cpu)
}
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.add_reg_asize(reg_edi, diff);
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
}
else
@ -436,10 +449,10 @@ function cmpsd(cpu)
data_dest = cpu.safe_read32s(dest);
data_src = cpu.safe_read32s(src);
dest += size;
cpu.regv[cpu.reg_vdi] += size;
cpu.add_reg_asize(reg_edi, size);
src += size;
cpu.regv[cpu.reg_vsi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0 && (data_src === data_dest) === is_repz;
cpu.add_reg_asize(reg_esi, size);
cont = cpu.decr_ecx_asize() !== 0 && (data_src === data_dest) === is_repz;
}
while(cont && cycle_counter--);
}
@ -452,22 +465,23 @@ function cmpsd(cpu)
{
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.add_reg_asize(reg_edi, size);
cpu.add_reg_asize(reg_esi, size);
}
cpu.cmp32(data_src, data_dest);
cpu.diverged();
}
function stosb(cpu)
{
var data = cpu.reg8[reg_al];
var dest = cpu.get_seg(reg_es) + cpu.regv[cpu.reg_vdi] | 0;
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -1 : 1;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
@ -485,8 +499,8 @@ function stosb(cpu)
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
if(cont)
{
@ -496,19 +510,20 @@ function stosb(cpu)
else
{
cpu.safe_write8(dest, data);
cpu.regv[cpu.reg_vdi] += size;
cpu.add_reg_asize(reg_edi, size);
}
cpu.diverged();
}
function stosw(cpu)
{
var data = cpu.reg16[reg_ax];
var dest = cpu.get_seg(reg_es) + cpu.regv[cpu.reg_vdi] | 0;
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -2 : 2;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
@ -529,8 +544,8 @@ function stosw(cpu)
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
}
else
@ -539,8 +554,8 @@ function stosw(cpu)
{
cpu.safe_write16(dest, data);
dest += size;
cpu.regv[cpu.reg_vdi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0;
cpu.add_reg_asize(reg_edi, size);
cont = cpu.decr_ecx_asize() !== 0;
}
while(cont && cycle_counter--);
}
@ -552,19 +567,20 @@ function stosw(cpu)
else
{
cpu.safe_write16(dest, data);
cpu.regv[cpu.reg_vdi] += size;
cpu.add_reg_asize(reg_edi, size);
}
cpu.diverged();
}
function stosd(cpu)
{
var data = cpu.reg32s[reg_eax];
var dest = cpu.get_seg(reg_es) + cpu.regv[cpu.reg_vdi] | 0;
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -4 : 4;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
@ -585,8 +601,8 @@ function stosd(cpu)
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
}
else
@ -595,8 +611,8 @@ function stosd(cpu)
{
cpu.safe_write32(dest, data);
dest += size;
cpu.regv[cpu.reg_vdi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0;
cpu.add_reg_asize(reg_edi, size);
cont = cpu.decr_ecx_asize() !== 0;
}
while(cont && cycle_counter--);
}
@ -608,18 +624,19 @@ function stosd(cpu)
else
{
cpu.safe_write32(dest, data);
cpu.regv[cpu.reg_vdi] += size;
cpu.add_reg_asize(reg_edi, size);
}
cpu.diverged();
}
function lodsb(cpu)
{
var src = cpu.get_seg_prefix(reg_ds) + cpu.regv[cpu.reg_vsi] | 0;
var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var size = cpu.flags & flag_direction ? -1 : 1;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
@ -637,8 +654,8 @@ function lodsb(cpu)
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vsi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
if(cont)
{
@ -648,18 +665,19 @@ function lodsb(cpu)
else
{
cpu.reg8[reg_al] = cpu.safe_read8(src);
cpu.regv[cpu.reg_vsi] += size;
cpu.add_reg_asize(reg_esi, size);
}
cpu.diverged();
}
function lodsw(cpu)
{
var src = cpu.get_seg_prefix(reg_ds) + cpu.regv[cpu.reg_vsi] | 0;
var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var size = cpu.flags & flag_direction ? -2 : 2;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var cycle_counter = MAX_COUNT_PER_CYCLE;
@ -667,8 +685,8 @@ function lodsw(cpu)
{
cpu.reg16[reg_ax] = cpu.safe_read16(src);
src += size;
cpu.regv[cpu.reg_vsi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0;
cpu.add_reg_asize(reg_esi, size);
cont = cpu.decr_ecx_asize() !== 0;
}
while(cont && cycle_counter--);
if(cont)
@ -679,18 +697,19 @@ function lodsw(cpu)
else
{
cpu.reg16[reg_ax] = cpu.safe_read16(src);
cpu.regv[cpu.reg_vsi] += size;
cpu.add_reg_asize(reg_esi, size);
}
cpu.diverged();
}
function lodsd(cpu)
{
var src = cpu.get_seg_prefix(reg_ds) + cpu.regv[cpu.reg_vsi] | 0;
var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var size = cpu.flags & flag_direction ? -4 : 4;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var cycle_counter = MAX_COUNT_PER_CYCLE;
@ -698,8 +717,8 @@ function lodsd(cpu)
{
cpu.reg32s[reg_eax] = cpu.safe_read32s(src);
src += size;
cpu.regv[cpu.reg_vsi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0;
cpu.add_reg_asize(reg_esi, size);
cont = cpu.decr_ecx_asize() !== 0;
}
while(cont && cycle_counter--);
if(cont)
@ -710,24 +729,25 @@ function lodsd(cpu)
else
{
cpu.reg32s[reg_eax] = cpu.safe_read32s(src);
cpu.regv[cpu.reg_vsi] += size;
cpu.add_reg_asize(reg_esi, size);
}
cpu.diverged();
}
function scasb(cpu)
{
var dest = cpu.get_seg(reg_es) + cpu.regv[cpu.reg_vdi] | 0;
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 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)
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = cpu.repeat_string_prefix === REPEAT_STRING_PREFIX_Z;
var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ;
var cycle_counter = MAX_COUNT_PER_CYCLE;
var phys_dest = cpu.translate_address_read(dest);
if(cpu.paging)
@ -742,8 +762,8 @@ function scasb(cpu)
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
if(cont)
{
@ -753,26 +773,27 @@ function scasb(cpu)
else
{
data_dest = cpu.safe_read8(dest);
cpu.regv[cpu.reg_vdi] += size;
cpu.add_reg_asize(reg_edi, size);
}
cpu.cmp8(data_src, data_dest);
cpu.diverged();
}
function scasw(cpu)
{
var dest = cpu.get_seg(reg_es) + cpu.regv[cpu.reg_vdi] | 0;
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 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)
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = cpu.repeat_string_prefix === REPEAT_STRING_PREFIX_Z;
var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ;
var cycle_counter = MAX_COUNT_PER_CYCLE;
if(!(dest & 1))
{
@ -790,8 +811,8 @@ function scasw(cpu)
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
}
else
@ -800,8 +821,8 @@ function scasw(cpu)
{
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;
cpu.add_reg_asize(reg_edi, size);
cont = cpu.decr_ecx_asize() !== 0 && (data_src === data_dest) === is_repz;
}
while(cont && cycle_counter--);
}
@ -813,26 +834,27 @@ function scasw(cpu)
else
{
data_dest = cpu.safe_read16(dest);
cpu.regv[cpu.reg_vdi] += size;
cpu.add_reg_asize(reg_edi, size);
}
cpu.cmp16(data_src, data_dest);
cpu.diverged();
}
function scasd(cpu)
{
var dest = cpu.get_seg(reg_es) + cpu.regv[cpu.reg_vdi] | 0;
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 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)
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = cpu.repeat_string_prefix === REPEAT_STRING_PREFIX_Z;
var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ;
var cycle_counter = MAX_COUNT_PER_CYCLE;
if(!(dest & 3))
{
@ -850,8 +872,8 @@ function scasd(cpu)
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
}
else
@ -860,8 +882,8 @@ function scasd(cpu)
{
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;
cpu.add_reg_asize(reg_edi, size);
cont = cpu.decr_ecx_asize() !== 0 && (data_src === data_dest) === is_repz;
}
while(cont && cycle_counter--);
}
@ -873,10 +895,11 @@ function scasd(cpu)
else
{
data_dest = cpu.safe_read32s(dest);
cpu.regv[cpu.reg_vdi] += size;
cpu.add_reg_asize(reg_edi, size);
}
cpu.cmp32(data_src, data_dest);
cpu.diverged();
}
function insb(cpu)
@ -884,12 +907,12 @@ 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 dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -1 : 1;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
@ -907,8 +930,8 @@ function insb(cpu)
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
if(cont)
{
@ -919,8 +942,9 @@ function insb(cpu)
else
{
cpu.safe_write8(dest, cpu.io.port_read8(port));
cpu.regv[cpu.reg_vdi] += size;
cpu.add_reg_asize(reg_edi, size);
}
cpu.diverged();
}
function insw(cpu)
@ -928,12 +952,12 @@ 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 dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -2 : 2;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
@ -954,8 +978,8 @@ function insw(cpu)
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
}
else
@ -964,8 +988,8 @@ function insw(cpu)
{
cpu.safe_write16(dest, cpu.io.port_read16(port));
dest += size;
cpu.regv[cpu.reg_vdi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0;
cpu.add_reg_asize(reg_edi, size);
cont = cpu.decr_ecx_asize() !== 0;
}
while(cont && cycle_counter--);
}
@ -978,8 +1002,9 @@ function insw(cpu)
else
{
cpu.safe_write16(dest, cpu.io.port_read16(port));
cpu.regv[cpu.reg_vdi] += size;
cpu.add_reg_asize(reg_edi, size);
}
cpu.diverged();
}
function insd(cpu)
@ -987,12 +1012,12 @@ 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 dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -4 : 4;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
@ -1013,8 +1038,8 @@ function insd(cpu)
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vdi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
}
else
@ -1023,8 +1048,8 @@ function insd(cpu)
{
cpu.safe_write32(dest, cpu.io.port_read32(port));
dest += size;
cpu.regv[cpu.reg_vdi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0;
cpu.add_reg_asize(reg_edi, size);
cont = cpu.decr_ecx_asize() !== 0;
}
while(cont && cycle_counter--);
}
@ -1037,8 +1062,9 @@ function insd(cpu)
else
{
cpu.safe_write32(dest, cpu.io.port_read32(port));
cpu.regv[cpu.reg_vdi] += size;
cpu.add_reg_asize(reg_edi, size);
}
cpu.diverged();
}
function outsb(cpu)
@ -1046,12 +1072,12 @@ 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 src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var size = cpu.flags & flag_direction ? -1 : 1;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
@ -1069,8 +1095,8 @@ function outsb(cpu)
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vsi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
if(cont)
{
@ -1081,8 +1107,9 @@ function outsb(cpu)
else
{
cpu.io.port_write8(port, cpu.safe_read8(src));
cpu.regv[cpu.reg_vsi] += size;
cpu.add_reg_asize(reg_esi, size);
}
cpu.diverged();
}
function outsw(cpu)
@ -1090,12 +1117,12 @@ 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 src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var size = cpu.flags & flag_direction ? -2 : 2;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
@ -1116,8 +1143,8 @@ function outsw(cpu)
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vsi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
}
else
@ -1126,8 +1153,8 @@ function outsw(cpu)
{
cpu.io.port_write16(port, cpu.safe_read16(src));
src += size;
cpu.regv[cpu.reg_vsi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0;
cpu.add_reg_asize(reg_esi, size);
cont = cpu.decr_ecx_asize() !== 0;
}
while(cont && cycle_counter--);
}
@ -1140,8 +1167,9 @@ function outsw(cpu)
else
{
cpu.io.port_write16(port, cpu.safe_read16(src));
cpu.regv[cpu.reg_vsi] += size;
cpu.add_reg_asize(reg_esi, size);
}
cpu.diverged();
}
function outsd(cpu)
@ -1149,12 +1177,12 @@ 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 src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var size = cpu.flags & flag_direction ? -4 : 4;
if(cpu.repeat_string_prefix !== REPEAT_STRING_PREFIX_NONE)
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.regv[cpu.reg_vcx] >>> 0;
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
@ -1175,8 +1203,8 @@ function outsd(cpu)
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.regv[cpu.reg_vsi] += diff;
cpu.regv[cpu.reg_vcx] = count;
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
}
else
@ -1185,8 +1213,8 @@ function outsd(cpu)
{
cpu.io.port_write32(port, cpu.safe_read32s(src));
src += size;
cpu.regv[cpu.reg_vsi] += size;
cont = --cpu.regv[cpu.reg_vcx] !== 0;
cpu.add_reg_asize(reg_esi, size);
cont = cpu.decr_ecx_asize() !== 0;
}
while(cont && cycle_counter--);
}
@ -1199,6 +1227,7 @@ function outsd(cpu)
else
{
cpu.io.port_write32(port, cpu.safe_read32s(src));
cpu.regv[cpu.reg_vsi] += size;
cpu.add_reg_asize(reg_esi, size);
}
cpu.diverged();
}