Jit DIV/IDIV

This commit is contained in:
Fabian 2020-12-31 19:14:30 -06:00
parent 3ef82c8c2f
commit 0edc821618
5 changed files with 173 additions and 78 deletions

View file

@ -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, },

View file

@ -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(

View file

@ -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;

View file

@ -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;

View file

@ -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();