459 lines
8.1 KiB
JavaScript
459 lines
8.1 KiB
JavaScript
/*
|
|
* Some miscellaneous instructions:
|
|
*
|
|
* jmpcc16, jmpcc32, jmp16
|
|
* loop, loope, loopne, jcxz
|
|
* test_cc
|
|
*
|
|
* mov, push, pop
|
|
* pusha, popa
|
|
* xchg, lss
|
|
* lea
|
|
* enter
|
|
* bswap
|
|
*
|
|
* Gets #included by cpu.macro.js
|
|
*/
|
|
"use strict";
|
|
|
|
function jmp_rel16(rel16)
|
|
{
|
|
var current_cs = get_seg(reg_cs);
|
|
|
|
// limit ip to 16 bit
|
|
// ugly
|
|
instruction_pointer -= current_cs;
|
|
instruction_pointer = (instruction_pointer + rel16) & 0xFFFF;
|
|
instruction_pointer = instruction_pointer + current_cs | 0;
|
|
}
|
|
|
|
function jmpcc16(condition)
|
|
{
|
|
if(condition)
|
|
{
|
|
jmp_rel16(read_imm16());
|
|
}
|
|
else
|
|
{
|
|
instruction_pointer += 2;
|
|
}
|
|
}
|
|
|
|
|
|
function jmpcc32(condition)
|
|
{
|
|
if(condition)
|
|
{
|
|
// don't write `instruction_pointer += read_imm32s()`
|
|
var imm32s = read_imm32s();
|
|
instruction_pointer = instruction_pointer + imm32s | 0;
|
|
}
|
|
else
|
|
{
|
|
instruction_pointer = instruction_pointer + 4 | 0;
|
|
}
|
|
}
|
|
|
|
function loopne()
|
|
{
|
|
if(--regv[reg_vcx] && !getzf())
|
|
{
|
|
var imm8s = read_imm8s();
|
|
instruction_pointer = instruction_pointer + imm8s | 0;
|
|
}
|
|
else
|
|
{
|
|
instruction_pointer++;
|
|
}
|
|
}
|
|
|
|
function loope()
|
|
{
|
|
if(--regv[reg_vcx] && getzf())
|
|
{
|
|
var imm8s = read_imm8s();
|
|
instruction_pointer = instruction_pointer + imm8s | 0;
|
|
}
|
|
else
|
|
{
|
|
instruction_pointer++;
|
|
}
|
|
}
|
|
|
|
function loop()
|
|
{
|
|
if(--regv[reg_vcx])
|
|
{
|
|
var imm8s = read_imm8s();
|
|
instruction_pointer = instruction_pointer + imm8s | 0;
|
|
}
|
|
else
|
|
{
|
|
instruction_pointer++;
|
|
}
|
|
}
|
|
|
|
function jcxz()
|
|
{
|
|
var imm8s = read_imm8s();
|
|
|
|
if(regv[reg_vcx] === 0)
|
|
{
|
|
instruction_pointer = instruction_pointer + imm8s | 0;
|
|
}
|
|
}
|
|
|
|
var test_o = getof,
|
|
test_b = getcf,
|
|
test_z = getzf,
|
|
test_s = getsf,
|
|
test_p = getpf;
|
|
|
|
function test_be()
|
|
{
|
|
return getcf() || getzf();
|
|
}
|
|
|
|
function test_l()
|
|
{
|
|
return !getsf() !== !getof();
|
|
}
|
|
|
|
function test_le()
|
|
{
|
|
return getzf() || !getsf() !== !getof();
|
|
}
|
|
|
|
/**
|
|
* @return {number}
|
|
* @const
|
|
*/
|
|
function getcf()
|
|
{
|
|
if(flags_changed & 1)
|
|
{
|
|
if(last_op_size === OPSIZE_32)
|
|
{
|
|
// cannot bit test above 2^32-1
|
|
return last_result > 0xffffffff | last_result < 0;
|
|
//return ((last_op1 ^ last_result) & (last_op2 ^ last_result)) >>> 31;
|
|
}
|
|
else
|
|
{
|
|
return last_result >> last_op_size & 1;
|
|
}
|
|
|
|
//return last_result >= (1 << last_op_size) | last_result < 0;
|
|
}
|
|
else
|
|
{
|
|
return flags & 1;
|
|
}
|
|
}
|
|
|
|
/** @return {number} */
|
|
function getpf()
|
|
{
|
|
if(flags_changed & flag_parity)
|
|
{
|
|
// inverted lookup table
|
|
return 0x9669 << 2 >> ((last_result ^ last_result >> 4) & 0xF) & flag_parity;
|
|
}
|
|
else
|
|
{
|
|
return flags & flag_parity;
|
|
}
|
|
}
|
|
|
|
/** @return {number} */
|
|
function getaf()
|
|
{
|
|
if(flags_changed & flag_adjust)
|
|
{
|
|
return (last_op1 ^ last_op2 ^ last_result ^ (last_op2 < 0) << 4) & flag_adjust;
|
|
}
|
|
else
|
|
{
|
|
return flags & flag_adjust;
|
|
}
|
|
}
|
|
|
|
/** @return {number} */
|
|
function getzf()
|
|
{
|
|
if(flags_changed & flag_zero)
|
|
{
|
|
return (~last_result & last_result - 1) >> last_op_size - 7 & flag_zero;
|
|
}
|
|
else
|
|
{
|
|
return flags & flag_zero;
|
|
}
|
|
}
|
|
|
|
/** @return {number} */
|
|
function getsf()
|
|
{
|
|
if(flags_changed & flag_sign)
|
|
{
|
|
return last_result >> last_op_size - 8 & flag_sign;
|
|
}
|
|
else
|
|
{
|
|
return flags & flag_sign;
|
|
}
|
|
}
|
|
|
|
/** @return {number} */
|
|
function getof()
|
|
{
|
|
if(flags_changed & flag_overflow)
|
|
{
|
|
return (((last_op1 ^ last_result) & (last_op2 ^ last_result)) >> last_op_size - 1) << 11 & flag_overflow;
|
|
}
|
|
else
|
|
{
|
|
return flags & flag_overflow;
|
|
}
|
|
}
|
|
|
|
|
|
function push16(imm16)
|
|
{
|
|
var sp = get_esp_write(-2);
|
|
|
|
stack_reg[reg_vsp] -= 2;
|
|
memory.write16(sp, imm16);
|
|
}
|
|
|
|
function push32(imm32)
|
|
{
|
|
var sp = get_esp_write(-4);
|
|
|
|
stack_reg[reg_vsp] -= 4;
|
|
memory.write32(sp, imm32);
|
|
}
|
|
|
|
function pop16()
|
|
{
|
|
var sp = get_esp_read(0);
|
|
|
|
stack_reg[reg_vsp] += 2;
|
|
return memory.read16(sp);
|
|
}
|
|
|
|
function pop32s()
|
|
{
|
|
var sp = get_esp_read(0);
|
|
|
|
stack_reg[reg_vsp] += 4;
|
|
return memory.read32s(sp);
|
|
}
|
|
|
|
function pusha16()
|
|
{
|
|
var temp = reg16[reg_sp];
|
|
|
|
// make sure we don't get a pagefault after having
|
|
// pushed several registers already
|
|
translate_address_write(temp - 15);
|
|
|
|
push16(reg16[reg_ax]);
|
|
push16(reg16[reg_cx]);
|
|
push16(reg16[reg_dx]);
|
|
push16(reg16[reg_bx]);
|
|
push16(temp);
|
|
push16(reg16[reg_bp]);
|
|
push16(reg16[reg_si]);
|
|
push16(reg16[reg_di]);
|
|
}
|
|
|
|
function pusha32()
|
|
{
|
|
var temp = reg32s[reg_esp];
|
|
|
|
translate_address_write(temp - 31);
|
|
|
|
push32(reg32s[reg_eax]);
|
|
push32(reg32s[reg_ecx]);
|
|
push32(reg32s[reg_edx]);
|
|
push32(reg32s[reg_ebx]);
|
|
push32(temp);
|
|
push32(reg32s[reg_ebp]);
|
|
push32(reg32s[reg_esi]);
|
|
push32(reg32s[reg_edi]);
|
|
}
|
|
|
|
function popa16()
|
|
{
|
|
translate_address_read(stack_reg[reg_vsp] + 15);
|
|
|
|
reg16[reg_di] = pop16();
|
|
reg16[reg_si] = pop16();
|
|
reg16[reg_bp] = pop16();
|
|
stack_reg[reg_vsp] += 2;
|
|
reg16[reg_bx] = pop16();
|
|
reg16[reg_dx] = pop16();
|
|
reg16[reg_cx] = pop16();
|
|
reg16[reg_ax] = pop16();
|
|
}
|
|
|
|
function popa32()
|
|
{
|
|
translate_address_read(stack_reg[reg_vsp] + 31);
|
|
|
|
reg32[reg_edi] = pop32s();
|
|
reg32[reg_esi] = pop32s();
|
|
reg32[reg_ebp] = pop32s();
|
|
stack_reg[reg_vsp] += 4;
|
|
reg32[reg_ebx] = pop32s();
|
|
reg32[reg_edx] = pop32s();
|
|
reg32[reg_ecx] = pop32s();
|
|
reg32[reg_eax] = pop32s();
|
|
}
|
|
|
|
function xchg8(memory_data, modrm_byte)
|
|
{
|
|
var mod = modrm_byte >> 1 & 0xC | modrm_byte >> 5 & 1,
|
|
tmp = reg8[mod];
|
|
|
|
reg8[mod] = memory_data;
|
|
|
|
return tmp;
|
|
}
|
|
|
|
function xchg16(memory_data, modrm_byte)
|
|
{
|
|
var mod = modrm_byte >> 2 & 14,
|
|
tmp = reg16[mod];
|
|
|
|
reg16[mod] = memory_data;
|
|
|
|
return tmp;
|
|
}
|
|
|
|
function xchg16r(operand)
|
|
{
|
|
var temp = reg16[reg_ax];
|
|
reg16[reg_ax] = reg16[operand];
|
|
reg16[operand] = temp;
|
|
}
|
|
|
|
function xchg32(memory_data, modrm_byte)
|
|
{
|
|
var mod = modrm_byte >> 3 & 7,
|
|
tmp = reg32s[mod];
|
|
|
|
reg32[mod] = memory_data;
|
|
|
|
return tmp;
|
|
}
|
|
|
|
function xchg32r(operand)
|
|
{
|
|
var temp = reg32s[reg_eax];
|
|
reg32[reg_eax] = reg32s[operand];
|
|
reg32[operand] = temp;
|
|
}
|
|
|
|
function lss16(seg, addr, mod)
|
|
{
|
|
var new_reg = safe_read16(addr),
|
|
new_seg = safe_read16(addr + 2);
|
|
|
|
switch_seg(seg, new_seg);
|
|
|
|
reg16[mod] = new_reg;
|
|
}
|
|
|
|
function lss32(seg, addr, mod)
|
|
{
|
|
var new_reg = safe_read32s(addr),
|
|
new_seg = safe_read16(addr + 4);
|
|
|
|
switch_seg(seg, new_seg);
|
|
|
|
reg32[mod] = new_reg;
|
|
}
|
|
|
|
function lea16()
|
|
{
|
|
var modrm_byte = read_imm8(),
|
|
mod = modrm_byte >> 3 & 7;
|
|
|
|
// override prefix, so modrm16 does not return the segment part
|
|
segment_prefix = reg_noseg;
|
|
|
|
reg16[mod << 1] = modrm_resolve(modrm_byte);
|
|
|
|
segment_prefix = -1;
|
|
}
|
|
|
|
function lea32()
|
|
{
|
|
var modrm_byte = read_imm8(),
|
|
mod = modrm_byte >> 3 & 7;
|
|
|
|
segment_prefix = reg_noseg;
|
|
|
|
reg32[mod] = modrm_resolve(modrm_byte);
|
|
|
|
segment_prefix = -1;
|
|
}
|
|
|
|
function enter16()
|
|
{
|
|
var size = read_imm16(),
|
|
nesting_level = read_imm8(),
|
|
frame_temp;
|
|
|
|
push16(reg16[reg_bp]);
|
|
frame_temp = reg16[reg_sp];
|
|
|
|
if(nesting_level > 0)
|
|
{
|
|
for(var i = 1; i < nesting_level; i++)
|
|
{
|
|
reg16[reg_bp] -= 2;
|
|
push16(reg16[reg_bp]);
|
|
}
|
|
push16(frame_temp);
|
|
}
|
|
reg16[reg_bp] = frame_temp;
|
|
reg16[reg_sp] = frame_temp - size;
|
|
|
|
dbg_assert(!page_fault);
|
|
}
|
|
|
|
function enter32()
|
|
{
|
|
var size = read_imm16(),
|
|
nesting_level = read_imm8() & 31,
|
|
frame_temp;
|
|
|
|
push32(reg32s[reg_ebp]);
|
|
frame_temp = reg32s[reg_esp];
|
|
|
|
if(nesting_level > 0)
|
|
{
|
|
for(var i = 1; i < nesting_level; i++)
|
|
{
|
|
reg32[reg_ebp] -= 4;
|
|
push32(reg32s[reg_ebp]);
|
|
}
|
|
push32(frame_temp);
|
|
}
|
|
reg32[reg_ebp] = frame_temp;
|
|
reg32[reg_esp] -= size;
|
|
|
|
dbg_assert(!page_fault);
|
|
}
|
|
|
|
function bswap(reg)
|
|
{
|
|
var temp = reg32s[reg];
|
|
|
|
reg32[reg] = temp >>> 24 | temp << 24 | (temp >> 8 & 0xFF00) | (temp << 8 & 0xFF0000);
|
|
}
|
|
|