mirror of
https://github.com/copy/v86.git
synced 2025-12-31 04:23:15 +00:00
Jit DIV/IDIV
This commit is contained in:
parent
3ef82c8c2f
commit
0edc821618
5 changed files with 173 additions and 78 deletions
|
|
@ -387,8 +387,8 @@ const encodings = [
|
|||
{ opcode: 0xF7, os: 1, e: 1, fixed_g: 3, custom: 1 },
|
||||
{ opcode: 0xF7, os: 1, e: 1, fixed_g: 4, mask_flags: zf | af, custom: 1 },
|
||||
{ opcode: 0xF7, os: 1, e: 1, fixed_g: 5, mask_flags: zf | af, custom: 1 },
|
||||
{ opcode: 0xF7, os: 1, e: 1, fixed_g: 6, block_boundary: 1, }, // div/idiv: Not a block boundary, but doesn't use control flow exceptions
|
||||
{ opcode: 0xF7, os: 1, e: 1, fixed_g: 7, block_boundary: 1, },
|
||||
{ opcode: 0xF7, os: 1, e: 1, fixed_g: 6, custom: 1 },
|
||||
{ opcode: 0xF7, os: 1, e: 1, fixed_g: 7, custom: 1 },
|
||||
|
||||
{ opcode: 0xF8, },
|
||||
{ opcode: 0xF9, },
|
||||
|
|
|
|||
|
|
@ -1585,6 +1585,17 @@ pub fn gen_fpu_load_m64(ctx: &mut JitContext, modrm_byte: u8) {
|
|||
ctx.builder.reinterpret_i64_as_f64();
|
||||
}
|
||||
|
||||
pub fn gen_trigger_de(ctx: &mut JitContext) {
|
||||
gen_move_registers_from_locals_to_memory(ctx);
|
||||
gen_set_previous_eip_offset_from_eip_with_low_bits(
|
||||
ctx.builder,
|
||||
ctx.start_of_current_instruction as i32 & 0xFFF,
|
||||
);
|
||||
gen_fn0_const(ctx.builder, "trigger_de");
|
||||
gen_debug_track_jit_exit(ctx.builder, ctx.start_of_current_instruction);
|
||||
ctx.builder.return_();
|
||||
}
|
||||
|
||||
pub fn gen_trigger_ud(ctx: &mut JitContext) {
|
||||
gen_move_registers_from_locals_to_memory(ctx);
|
||||
gen_set_previous_eip_offset_from_eip_with_low_bits(
|
||||
|
|
|
|||
|
|
@ -694,97 +694,94 @@ pub unsafe fn idiv8(source_operand: i32) {
|
|||
return;
|
||||
};
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn div16_without_fault(source_operand: u32) -> bool {
|
||||
if source_operand == 0 {
|
||||
return false;
|
||||
}
|
||||
let target_operand =
|
||||
(*reg16.offset(AX as isize) as i32 | (*reg16.offset(DX as isize) as i32) << 16) as u32;
|
||||
let result = target_operand.wrapping_div(source_operand);
|
||||
if result >= 0x10000 {
|
||||
return false;
|
||||
}
|
||||
*reg16.offset(AX as isize) = result as u16;
|
||||
*reg16.offset(DX as isize) = target_operand.wrapping_rem(source_operand) as u16;
|
||||
return true;
|
||||
}
|
||||
pub unsafe fn div16(source_operand: u32) {
|
||||
if source_operand == 0 {
|
||||
trigger_de();
|
||||
return;
|
||||
if !div16_without_fault(source_operand) {
|
||||
trigger_de()
|
||||
}
|
||||
else {
|
||||
let target_operand =
|
||||
(*reg16.offset(AX as isize) as i32 | (*reg16.offset(DX as isize) as i32) << 16) as u32;
|
||||
let result = target_operand.wrapping_div(source_operand);
|
||||
if result >= 0x10000 {
|
||||
trigger_de();
|
||||
}
|
||||
else {
|
||||
*reg16.offset(AX as isize) = result as u16;
|
||||
*reg16.offset(DX as isize) = target_operand.wrapping_rem(source_operand) as u16
|
||||
}
|
||||
return;
|
||||
};
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe fn idiv16_without_fault(source_operand: i32) -> bool {
|
||||
if source_operand == 0 {
|
||||
return false;
|
||||
}
|
||||
let target_operand =
|
||||
*reg16.offset(AX as isize) as i32 | (*reg16.offset(DX as isize) as i32) << 16;
|
||||
let result = target_operand / source_operand;
|
||||
if result >= 32768 || result <= -32769 {
|
||||
return false;
|
||||
}
|
||||
*reg16.offset(AX as isize) = result as u16;
|
||||
*reg16.offset(DX as isize) = (target_operand % source_operand) as u16;
|
||||
return true;
|
||||
}
|
||||
pub unsafe fn idiv16(source_operand: i32) {
|
||||
if source_operand == 0 {
|
||||
trigger_de();
|
||||
return;
|
||||
if !idiv16_without_fault(source_operand) {
|
||||
trigger_de()
|
||||
}
|
||||
else {
|
||||
let target_operand =
|
||||
*reg16.offset(AX as isize) as i32 | (*reg16.offset(DX as isize) as i32) << 16;
|
||||
let result = target_operand / source_operand;
|
||||
if result >= 32768 || result <= -32769 {
|
||||
trigger_de();
|
||||
}
|
||||
else {
|
||||
*reg16.offset(AX as isize) = result as u16;
|
||||
*reg16.offset(DX as isize) = (target_operand % source_operand) as u16
|
||||
}
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn div32_without_fault(source_operand: u32) -> bool {
|
||||
if source_operand == 0 {
|
||||
return false;
|
||||
}
|
||||
let target_low = *reg32.offset(EAX as isize) as u32;
|
||||
let target_high = *reg32.offset(EDX as isize) as u32;
|
||||
let target_operand = (target_high as u64) << 32 | target_low as u64;
|
||||
let result = target_operand.wrapping_div(source_operand as u64);
|
||||
if result > 0xFFFFFFFF {
|
||||
return false;
|
||||
}
|
||||
let mod_0 = target_operand.wrapping_rem(source_operand as u64) as i32;
|
||||
*reg32.offset(EAX as isize) = result as i32;
|
||||
*reg32.offset(EDX as isize) = mod_0;
|
||||
return true;
|
||||
}
|
||||
pub unsafe fn div32(source_operand: u32) {
|
||||
if source_operand == 0 {
|
||||
trigger_de();
|
||||
return;
|
||||
if !div32_without_fault(source_operand) {
|
||||
trigger_de()
|
||||
}
|
||||
else {
|
||||
let target_low = *reg32.offset(EAX as isize) as u32;
|
||||
let target_high = *reg32.offset(EDX as isize) as u32;
|
||||
let target_operand = (target_high as u64) << 32 | target_low as u64;
|
||||
let result = target_operand.wrapping_div(source_operand as u64);
|
||||
if result > 0xFFFFFFFF {
|
||||
trigger_de();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
let mod_0 = target_operand.wrapping_rem(source_operand as u64) as i32;
|
||||
*reg32.offset(EAX as isize) = result as i32;
|
||||
*reg32.offset(EDX as isize) = mod_0;
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe fn idiv32(source_operand: i32) {
|
||||
pub unsafe fn idiv32_without_fault(source_operand: i32) -> bool {
|
||||
if source_operand == 0 {
|
||||
trigger_de();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
let target_low = *reg32.offset(EAX as isize) as u32;
|
||||
let target_high = *reg32.offset(EDX as isize) as u32;
|
||||
let target_operand = ((target_high as u64) << 32 | target_low as u64) as i64;
|
||||
if source_operand == -1 && target_operand == -0x80000000_00000000 as i64 {
|
||||
return false;
|
||||
}
|
||||
let result = target_operand / source_operand as i64;
|
||||
if result < -0x80000000 || result > 0x7FFFFFFF {
|
||||
return false;
|
||||
}
|
||||
let mod_0 = (target_operand % source_operand as i64) as i32;
|
||||
*reg32.offset(EAX as isize) = result as i32;
|
||||
*reg32.offset(EDX as isize) = mod_0;
|
||||
return true;
|
||||
}
|
||||
pub unsafe fn idiv32(source_operand: i32) {
|
||||
if !idiv32_without_fault(source_operand) {
|
||||
trigger_de()
|
||||
}
|
||||
else {
|
||||
let target_low = *reg32.offset(EAX as isize) as u32;
|
||||
let target_high = *reg32.offset(EDX as isize) as u32;
|
||||
let target_operand = ((target_high as u64) << 32 | target_low as u64) as i64;
|
||||
if source_operand == -1 && target_operand == -0x80000000_00000000 as i64 {
|
||||
trigger_de();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
let result = target_operand / source_operand as i64;
|
||||
if result < -0x80000000 || result > 0x7FFFFFFF {
|
||||
trigger_de();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
let mod_0 = (target_operand % source_operand as i64) as i32;
|
||||
*reg32.offset(EAX as isize) = result as i32;
|
||||
*reg32.offset(EDX as isize) = mod_0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
|
@ -1056,6 +1053,7 @@ pub unsafe fn btr_reg(bit_base: i32, bit_offset: i32) -> i32 {
|
|||
*flags_changed &= !1;
|
||||
return bit_base & !(1 << bit_offset);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn bt_mem(virt_addr: i32, mut bit_offset: i32) {
|
||||
let bit_base = return_on_pagefault!(safe_read8(virt_addr + (bit_offset >> 3)));
|
||||
|
|
@ -1090,6 +1088,7 @@ pub unsafe fn bts_mem(virt_addr: i32, mut bit_offset: i32) {
|
|||
*flags_changed &= !1;
|
||||
write8(phys_addr, bit_base | 1 << bit_offset);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn bsf16(old: i32, bit_base: i32) -> i32 {
|
||||
*flags_changed = FLAGS_ALL & !FLAG_ZERO & !FLAG_CARRY;
|
||||
|
|
|
|||
|
|
@ -2053,6 +2053,7 @@ pub unsafe fn do_many_cycles_native() {
|
|||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn trigger_de() {
|
||||
dbg_log!("#de");
|
||||
*instruction_pointer = *previous_ip;
|
||||
|
|
|
|||
|
|
@ -3069,6 +3069,90 @@ pub fn instr32_F7_5_reg_jit(ctx: &mut JitContext, r: u32) {
|
|||
codegen::gen_move_registers_from_memory_to_locals(ctx);
|
||||
}
|
||||
|
||||
pub fn instr16_F7_6_mem_jit(ctx: &mut JitContext, modrm_byte: u8) {
|
||||
codegen::gen_modrm_resolve_safe_read16(ctx, modrm_byte);
|
||||
codegen::gen_move_registers_from_locals_to_memory(ctx);
|
||||
codegen::gen_call_fn1_ret(ctx.builder, "div16_without_fault");
|
||||
codegen::gen_move_registers_from_memory_to_locals(ctx);
|
||||
ctx.builder.eqz_i32();
|
||||
ctx.builder.if_void();
|
||||
codegen::gen_trigger_de(ctx);
|
||||
ctx.builder.block_end();
|
||||
}
|
||||
pub fn instr16_F7_6_reg_jit(ctx: &mut JitContext, r: u32) {
|
||||
codegen::gen_get_reg16(ctx, r);
|
||||
codegen::gen_move_registers_from_locals_to_memory(ctx);
|
||||
codegen::gen_call_fn1_ret(ctx.builder, "div16_without_fault");
|
||||
codegen::gen_move_registers_from_memory_to_locals(ctx);
|
||||
ctx.builder.eqz_i32();
|
||||
ctx.builder.if_void();
|
||||
codegen::gen_trigger_de(ctx);
|
||||
ctx.builder.block_end();
|
||||
}
|
||||
pub fn instr32_F7_6_mem_jit(ctx: &mut JitContext, modrm_byte: u8) {
|
||||
codegen::gen_modrm_resolve_safe_read32(ctx, modrm_byte);
|
||||
codegen::gen_move_registers_from_locals_to_memory(ctx);
|
||||
codegen::gen_call_fn1_ret(ctx.builder, "div32_without_fault");
|
||||
codegen::gen_move_registers_from_memory_to_locals(ctx);
|
||||
ctx.builder.eqz_i32();
|
||||
ctx.builder.if_void();
|
||||
codegen::gen_trigger_de(ctx);
|
||||
ctx.builder.block_end();
|
||||
}
|
||||
pub fn instr32_F7_6_reg_jit(ctx: &mut JitContext, r: u32) {
|
||||
codegen::gen_get_reg32(ctx, r);
|
||||
codegen::gen_move_registers_from_locals_to_memory(ctx);
|
||||
codegen::gen_call_fn1_ret(ctx.builder, "div32_without_fault");
|
||||
codegen::gen_move_registers_from_memory_to_locals(ctx);
|
||||
ctx.builder.eqz_i32();
|
||||
ctx.builder.if_void();
|
||||
codegen::gen_trigger_de(ctx);
|
||||
ctx.builder.block_end();
|
||||
}
|
||||
|
||||
pub fn instr16_F7_7_mem_jit(ctx: &mut JitContext, modrm_byte: u8) {
|
||||
codegen::gen_modrm_resolve_safe_read16(ctx, modrm_byte);
|
||||
codegen::sign_extend_i16(ctx.builder);
|
||||
codegen::gen_move_registers_from_locals_to_memory(ctx);
|
||||
codegen::gen_call_fn1_ret(ctx.builder, "idiv16_without_fault");
|
||||
codegen::gen_move_registers_from_memory_to_locals(ctx);
|
||||
ctx.builder.eqz_i32();
|
||||
ctx.builder.if_void();
|
||||
codegen::gen_trigger_de(ctx);
|
||||
ctx.builder.block_end();
|
||||
}
|
||||
pub fn instr16_F7_7_reg_jit(ctx: &mut JitContext, r: u32) {
|
||||
codegen::gen_get_reg16(ctx, r);
|
||||
codegen::sign_extend_i16(ctx.builder);
|
||||
codegen::gen_move_registers_from_locals_to_memory(ctx);
|
||||
codegen::gen_call_fn1_ret(ctx.builder, "idiv16_without_fault");
|
||||
codegen::gen_move_registers_from_memory_to_locals(ctx);
|
||||
ctx.builder.eqz_i32();
|
||||
ctx.builder.if_void();
|
||||
codegen::gen_trigger_de(ctx);
|
||||
ctx.builder.block_end();
|
||||
}
|
||||
pub fn instr32_F7_7_mem_jit(ctx: &mut JitContext, modrm_byte: u8) {
|
||||
codegen::gen_modrm_resolve_safe_read32(ctx, modrm_byte);
|
||||
codegen::gen_move_registers_from_locals_to_memory(ctx);
|
||||
codegen::gen_call_fn1_ret(ctx.builder, "idiv32_without_fault");
|
||||
codegen::gen_move_registers_from_memory_to_locals(ctx);
|
||||
ctx.builder.eqz_i32();
|
||||
ctx.builder.if_void();
|
||||
codegen::gen_trigger_de(ctx);
|
||||
ctx.builder.block_end();
|
||||
}
|
||||
pub fn instr32_F7_7_reg_jit(ctx: &mut JitContext, r: u32) {
|
||||
codegen::gen_get_reg32(ctx, r);
|
||||
codegen::gen_move_registers_from_locals_to_memory(ctx);
|
||||
codegen::gen_call_fn1_ret(ctx.builder, "idiv32_without_fault");
|
||||
codegen::gen_move_registers_from_memory_to_locals(ctx);
|
||||
ctx.builder.eqz_i32();
|
||||
ctx.builder.if_void();
|
||||
codegen::gen_trigger_de(ctx);
|
||||
ctx.builder.block_end();
|
||||
}
|
||||
|
||||
pub fn instr_FA_jit(ctx: &mut JitContext) {
|
||||
codegen::gen_fn0_const_ret(ctx.builder, "instr_FA_without_fault");
|
||||
ctx.builder.eqz_i32();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue