blob: f5fc46ff4b7174577624a36cc8332f5e1bd25f52 [file] [log] [blame] [raw]
"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));
}
CPU.prototype.movsb = function()
{
var cpu = this;
var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -1 : 1;
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 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.write8(phys_dest, cpu.read8(phys_src));
phys_dest += size;
phys_src += size;
cont = --count !== 0;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
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;
}
}
else
{
cpu.safe_write8(dest, cpu.safe_read8(src));
cpu.add_reg_asize(reg_edi, size);
cpu.add_reg_asize(reg_esi, size);
}
cpu.diverged();
}
CPU.prototype.movsw = function()
{
var cpu = this;
var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -2 : 2;
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 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.write_aligned16(phys_dest, cpu.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.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
{
do
{
cpu.safe_write16(dest, cpu.safe_read16(src));
dest += size;
cpu.add_reg_asize(reg_edi, size);
src += size;
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;
}
}
else
{
cpu.safe_write16(dest, cpu.safe_read16(src));
cpu.add_reg_asize(reg_edi, size);
cpu.add_reg_asize(reg_esi, size);
}
cpu.diverged();
}
CPU.prototype.movsd = function()
{
var cpu = this;
if(cpu.prefixes & PREFIX_MASK_REP)
{
// often used by memcpy, well worth optimizing
// using cpu.mem32s.set
var ds = cpu.get_seg_prefix(reg_ds),
src = ds + cpu.get_reg_asize(reg_esi) | 0,
es = cpu.get_seg(reg_es),
dest = es + cpu.get_reg_asize(reg_edi) | 0,
count = cpu.get_reg_asize(reg_ecx) >>> 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.add_reg_asize(reg_ecx, -count);
cpu.add_reg_asize(reg_edi, diff);
cpu.add_reg_asize(reg_esi, diff);
dest >>= 2;
src >>= 2;
cpu.write_blob32(cpu.mem32s.subarray(src, src + count), dest);
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
return;
}
}
}
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.prefixes & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 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.write_aligned32(phys_dest, cpu.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.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
{
do
{
cpu.safe_write32(dest, cpu.safe_read32s(src));
dest += size;
cpu.add_reg_asize(reg_edi, size);
src += size;
cpu.add_reg_asize(reg_esi, size);
cont = cpu.decr_ecx_asize() !== 0;
}
while(cont && cycle_counter--);
}
if(cont)
{
this.instruction_pointer = this.previous_ip;
}
}
else
{
cpu.safe_write32(dest, cpu.safe_read32s(src));
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.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.prefixes & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ;
var 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.read8(phys_dest);
data_src = cpu.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.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;
}
}
else
{
data_src = cpu.safe_read8(src);
data_dest = cpu.safe_read8(dest);
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.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.prefixes & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ;
var 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.read_aligned16(phys_dest);
data_src = cpu.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.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
{
do
{
data_dest = cpu.safe_read16(dest);
data_src = cpu.safe_read16(src);
dest += size;
cpu.add_reg_asize(reg_edi, size);
src += size;
cpu.add_reg_asize(reg_esi, size);
cont = cpu.decr_ecx_asize() !== 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.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.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.prefixes & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ;
var 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.read_aligned32(phys_dest);
data_src = cpu.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.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
{
do
{
data_dest = cpu.safe_read32s(dest);
data_src = cpu.safe_read32s(src);
dest += size;
cpu.add_reg_asize(reg_edi, size);
src += size;
cpu.add_reg_asize(reg_esi, size);
cont = cpu.decr_ecx_asize() !== 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.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.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -1 : 1;
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 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.write8(phys_dest, data);
phys_dest += size;
cont = --count !== 0;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
cpu.safe_write8(dest, data);
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.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -2 : 2;
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 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.write_aligned16(phys_dest, data);
phys_dest += single_size;
cont = --count !== 0;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
}
else
{
do
{
cpu.safe_write16(dest, data);
dest += size;
cpu.add_reg_asize(reg_edi, size);
cont = cpu.decr_ecx_asize() !== 0;
}
while(cont && cycle_counter--);
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
cpu.safe_write16(dest, data);
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.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -4 : 4;
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 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.write_aligned32(phys_dest, data);
phys_dest += single_size;
cont = --count !== 0;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
}
else
{
do
{
cpu.safe_write32(dest, data);
dest += size;
cpu.add_reg_asize(reg_edi, size);
cont = cpu.decr_ecx_asize() !== 0;
}
while(cont && cycle_counter--);
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
cpu.safe_write32(dest, data);
cpu.add_reg_asize(reg_edi, size);
}
cpu.diverged();
}
function lodsb(cpu)
{
var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var size = cpu.flags & flag_direction ? -1 : 1;
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 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.read8(phys_src);
phys_src += size;
cont = --count !== 0;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
cpu.reg8[reg_al] = cpu.safe_read8(src);
cpu.add_reg_asize(reg_esi, size);
}
cpu.diverged();
}
function lodsw(cpu)
{
var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var size = cpu.flags & flag_direction ? -2 : 2;
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 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.add_reg_asize(reg_esi, size);
cont = cpu.decr_ecx_asize() !== 0;
}
while(cont && cycle_counter--);
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
cpu.reg16[reg_ax] = cpu.safe_read16(src);
cpu.add_reg_asize(reg_esi, size);
}
cpu.diverged();
}
function lodsd(cpu)
{
var src = cpu.get_seg_prefix(reg_ds) + cpu.get_reg_asize(reg_esi) | 0;
var size = cpu.flags & flag_direction ? -4 : 4;
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 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.add_reg_asize(reg_esi, size);
cont = cpu.decr_ecx_asize() !== 0;
}
while(cont && cycle_counter--);
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
cpu.reg32s[reg_eax] = cpu.safe_read32s(src);
cpu.add_reg_asize(reg_esi, size);
}
cpu.diverged();
}
function scasb(cpu)
{
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -1 : 1;
var data_dest;
var data_src = cpu.reg8[reg_al];
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ;
var 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.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.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
data_dest = cpu.safe_read8(dest);
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.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.prefixes & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ;
var 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.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.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
}
else
{
do
{
data_dest = cpu.safe_read16(dest);
dest += size;
cpu.add_reg_asize(reg_edi, size);
cont = cpu.decr_ecx_asize() !== 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.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.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.prefixes & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 0;
if(count === 0) return;
var cont = false;
var start_count = count;
var is_repz = (cpu.prefixes & PREFIX_MASK_REP) === PREFIX_REPZ;
var 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.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.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
}
else
{
do
{
data_dest = cpu.safe_read32s(dest);
dest += size;
cpu.add_reg_asize(reg_edi, size);
cont = cpu.decr_ecx_asize() !== 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.add_reg_asize(reg_edi, size);
}
cpu.cmp32(data_src, data_dest);
cpu.diverged();
}
function insb(cpu)
{
var port = cpu.reg16[reg_dx];
cpu.test_privileges_for_io(port, 1);
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -1 : 1;
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 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.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.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
cpu.safe_write8(dest, cpu.io.port_read8(port));
cpu.add_reg_asize(reg_edi, size);
}
cpu.diverged();
}
function insw(cpu)
{
var port = cpu.reg16[reg_dx];
cpu.test_privileges_for_io(port, 2);
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -2 : 2;
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 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.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.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
}
else
{
do
{
cpu.safe_write16(dest, cpu.io.port_read16(port));
dest += size;
cpu.add_reg_asize(reg_edi, size);
cont = cpu.decr_ecx_asize() !== 0;
}
while(cont && cycle_counter--);
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
cpu.safe_write16(dest, cpu.io.port_read16(port));
cpu.add_reg_asize(reg_edi, size);
}
cpu.diverged();
}
function insd(cpu)
{
var port = cpu.reg16[reg_dx];
cpu.test_privileges_for_io(port, 4);
var dest = cpu.get_seg(reg_es) + cpu.get_reg_asize(reg_edi) | 0;
var size = cpu.flags & flag_direction ? -4 : 4;
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 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.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.add_reg_asize(reg_edi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
}
else
{
do
{
cpu.safe_write32(dest, cpu.io.port_read32(port));
dest += size;
cpu.add_reg_asize(reg_edi, size);
cont = cpu.decr_ecx_asize() !== 0;
}
while(cont && cycle_counter--);
}
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
cpu.safe_write32(dest, cpu.io.port_read32(port));
cpu.add_reg_asize(reg_edi, size);
}
cpu.diverged();
}
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.get_reg_asize(reg_esi) | 0;
var size = cpu.flags & flag_direction ? -1 : 1;
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 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.read8(phys_src));
phys_src += size;
cont = --count !== 0;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
if(cont)
{
cpu.instruction_pointer = cpu.previous_ip;
}
}
else
{
cpu.io.port_write8(port, cpu.safe_read8(src));
cpu.add_reg_asize(reg_esi, size);
}
cpu.diverged();
}
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.get_reg_asize(reg_esi) | 0;
var size = cpu.flags & flag_direction ? -2 : 2;
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 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.read_aligned16(phys_src));
phys_src += single_size;
cont = --count !== 0;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
}
else
{
do
{
cpu.io.port_write16(port, cpu.safe_read16(src));
src += size;
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;
}
}
else
{
cpu.io.port_write16(port, cpu.safe_read16(src));
cpu.add_reg_asize(reg_esi, size);
}
cpu.diverged();
}
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.get_reg_asize(reg_esi) | 0;
var size = cpu.flags & flag_direction ? -4 : 4;
if(cpu.prefixes & PREFIX_MASK_REP)
{
var count = cpu.get_reg_asize(reg_ecx) >>> 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.read_aligned32(phys_src));
phys_src += single_size;
cont = --count !== 0;
}
while(cont && cycle_counter--);
var diff = size * (start_count - count) | 0;
cpu.add_reg_asize(reg_esi, diff);
cpu.set_ecx_asize(count);
cpu.timestamp_counter += start_count - count;
}
else
{
do
{
cpu.io.port_write32(port, cpu.safe_read32s(src));
src += size;
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;
}
}
else
{
cpu.io.port_write32(port, cpu.safe_read32s(src));
cpu.add_reg_asize(reg_esi, size);
}
cpu.diverged();
}