From f1ebdb1c728274a1ab12efdaaab5e13e97510df6 Mon Sep 17 00:00:00 2001 From: Fabian Date: Mon, 1 Aug 2022 21:24:35 +0900 Subject: [PATCH] implement fbstp (close #708) --- gen/x86_table.js | 6 +++--- src/rust/cpu/fpu.rs | 29 +++++++++++++++++++++++++++++ src/rust/cpu/instructions.rs | 7 +------ src/rust/jit_instructions.rs | 17 +++++++++++++++-- tests/qemu/test-i386.c | 16 +++++++++++++--- 5 files changed, 61 insertions(+), 14 deletions(-) diff --git a/gen/x86_table.js b/gen/x86_table.js index aa84cb9834..f0fe02a0c1 100644 --- a/gen/x86_table.js +++ b/gen/x86_table.js @@ -346,9 +346,9 @@ const encodings = [ { opcode: 0xDF, e: 1, fixed_g: 2, custom: 1, is_fpu: 1, task_switch_test: 1 }, { opcode: 0xDF, e: 1, fixed_g: 3, custom: 1, is_fpu: 1, task_switch_test: 1 }, { opcode: 0xDF, e: 1, fixed_g: 4, custom: 1, is_fpu: 1, task_switch_test: 1, skip_mem: 1 }, // unimplemented: Binary Coded Decimals - { opcode: 0xDF, e: 1, fixed_g: 5, custom: 1, is_fpu: 1, task_switch_test: 1, }, - { opcode: 0xDF, e: 1, fixed_g: 6, custom: 1, is_fpu: 1, task_switch_test: 1, skip_mem: 1 }, // unimplemented: Binary Coded Decimals - { opcode: 0xDF, e: 1, fixed_g: 7, custom: 1, is_fpu: 1, task_switch_test: 1, }, + { opcode: 0xDF, e: 1, fixed_g: 5, custom: 1, is_fpu: 1, task_switch_test: 1 }, + { opcode: 0xDF, e: 1, fixed_g: 6, custom: 1, is_fpu: 1, task_switch_test: 1 }, + { opcode: 0xDF, e: 1, fixed_g: 7, custom: 1, is_fpu: 1, task_switch_test: 1 }, // loop, jcxz, etc. { opcode: 0xE0, os: 1, imm8s: 1, no_block_boundary_in_interpreted: 1, skip: 1, block_boundary: 1, jump_offset_imm: 1, custom: 1, conditional_jump: 1, }, diff --git a/src/rust/cpu/fpu.rs b/src/rust/cpu/fpu.rs index c8c6baecaa..b90fe3ccb0 100644 --- a/src/rust/cpu/fpu.rs +++ b/src/rust/cpu/fpu.rs @@ -625,6 +625,35 @@ pub unsafe fn fpu_fstp(r: i32) { fpu_pop(); } +#[no_mangle] +pub unsafe fn fpu_fbstp(addr: i32) { + match writable_or_pagefault(addr, 26) { + Ok(()) => *page_fault = false, + Err(()) => { + *page_fault = true; + return; + }, + } + let st0 = fpu_get_st0(); + let mut x = st0.to_i64().unsigned_abs(); + if x <= 99_9999_9999_9999_9999 { + for i in 0..=8 { + let low = x % 10; + x /= 10; + let high = x % 10; + x /= 10; + safe_write8(addr + i, (high as i32) << 4 | low as i32).unwrap(); + } + safe_write8(addr + 9, if st0.sign() { 0x80 } else { 0 }).unwrap(); + } + else { + fpu_invalid_arithmetic(); + safe_write64(addr + 0, 0xC000_0000_0000_0000).unwrap(); + safe_write16(addr + 8, 0xFFFF).unwrap(); + } + fpu_pop(); +} + #[no_mangle] pub unsafe fn fpu_fsub(target_index: i32, val: F80) { let st0 = fpu_get_st0(); diff --git a/src/rust/cpu/instructions.rs b/src/rust/cpu/instructions.rs index a1fea4defa..63bd6ae890 100644 --- a/src/rust/cpu/instructions.rs +++ b/src/rust/cpu/instructions.rs @@ -1989,11 +1989,7 @@ pub unsafe fn instr_DF_4_mem(_addr: i32) { fpu_unimpl(); } pub unsafe fn instr_DF_5_mem(addr: i32) { fpu_fildm64(addr); } -#[no_mangle] -pub unsafe fn instr_DF_6_mem(_addr: i32) { - dbg_log!("fbstp"); - fpu_unimpl(); -} +pub unsafe fn instr_DF_6_mem(addr: i32) { fpu_fbstp(addr); } pub unsafe fn instr_DF_7_mem(addr: i32) { fpu_fistm64p(addr); } #[no_mangle] @@ -2014,7 +2010,6 @@ pub unsafe fn instr_DF_4_reg(r: i32) { }; } pub unsafe fn instr_DF_5_reg(r: i32) { fpu_fucomip(r); } -#[no_mangle] pub unsafe fn instr_DF_6_reg(r: i32) { fpu_fcomip(r); } pub unsafe fn instr_DF_7_reg(_r: i32) { trigger_ud(); } diff --git a/src/rust/jit_instructions.rs b/src/rust/jit_instructions.rs index a728018d7f..58cd39a5f7 100644 --- a/src/rust/jit_instructions.rs +++ b/src/rust/jit_instructions.rs @@ -3776,9 +3776,22 @@ pub fn instr_DF_5_reg_jit(ctx: &mut JitContext, r: u32) { } pub fn instr_DF_6_mem_jit(ctx: &mut JitContext, modrm_byte: ModrmByte) { - dbg_log!("fbstp"); codegen::gen_modrm_resolve(ctx, modrm_byte); - codegen::gen_trigger_ud(ctx); + + codegen::gen_set_previous_eip_offset_from_eip_with_low_bits( + ctx.builder, + ctx.start_of_current_instruction as i32 & 0xFFF, + ); + + codegen::gen_move_registers_from_locals_to_memory(ctx); + ctx.builder.call_fn1("fpu_fbstp"); + codegen::gen_move_registers_from_memory_to_locals(ctx); + + codegen::gen_get_page_fault(ctx.builder); + ctx.builder.if_void(); + codegen::gen_debug_track_jit_exit(ctx.builder, ctx.start_of_current_instruction); + ctx.builder.br(ctx.exit_label); + ctx.builder.block_end(); } pub fn instr_DF_6_reg_jit(ctx: &mut JitContext, r: u32) { ctx.builder.const_i32(r as i32); diff --git a/tests/qemu/test-i386.c b/tests/qemu/test-i386.c index 4c2acd4693..db9105039f 100644 --- a/tests/qemu/test-i386.c +++ b/tests/qemu/test-i386.c @@ -1050,7 +1050,7 @@ void test_fbcd(double a) double b; asm("fbstp %0" : "=m" (bcd[0]) : "t" (a) : "st"); - asm("fbld %1" : "=t" (b) : "m" (bcd[0])); + //asm("fbld %1" : "=t" (b) : "m" (bcd[0])); printf("a=%f bcd=%04x%04x%04x%04x%04x b=%f\n", a, bcd[4], bcd[3], bcd[2], bcd[1], bcd[0], b); } @@ -1180,8 +1180,18 @@ void test_floats(void) test_fcvt(1.0/0.0); test_fcvt(q_nan.d); test_fconst(); - //test_fbcd(1234567890123456.0); - //test_fbcd(-123451234567890.0); + test_fbcd(0.0); + test_fbcd(-0.0); + test_fbcd(1.0); + test_fbcd(-1.0); + test_fbcd(1234567890123456.0); + test_fbcd(-123451234567890.0); + test_fbcd(341234567890123456.0); + test_fbcd(-345123451234567890.0); + test_fbcd(999999999999999900.0); + test_fbcd(-999999999999999900.0); + test_fbcd(1000000000000000000.0); + test_fbcd(-1000000000000000000.0); test_fenv(); if (TEST_CMOV) { test_fcmov();