X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/1b6b029e40c4297ce9c27e0f8b8ae177085c990a..313aa567104a63fbe84d6ec2eeff5b5c81cb3524:/op-i386.c diff --git a/op-i386.c b/op-i386.c index 835a1ed51b..60ae5e55f2 100644 --- a/op-i386.c +++ b/op-i386.c @@ -3,113 +3,22 @@ * * Copyright (c) 2003 Fabrice Bellard * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "exec-i386.h" -/* NOTE: data are not static to force relocation generation by GCC */ - -uint8_t parity_table[256] = { - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, -}; - -/* modulo 17 table */ -const uint8_t rclw_table[32] = { - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9,10,11,12,13,14,15, - 16, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 9,10,11,12,13,14, -}; - -/* modulo 9 table */ -const uint8_t rclb_table[32] = { - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 0, 1, 2, 3, 4, 5, - 6, 7, 8, 0, 1, 2, 3, 4, -}; - -#ifdef USE_X86LDOUBLE -/* an array of Intel 80-bit FP constants, to be loaded via integer ops */ -typedef unsigned short f15ld[5]; -const f15ld f15rk[] = -{ -/*0*/ {0x0000,0x0000,0x0000,0x0000,0x0000}, -/*1*/ {0x0000,0x0000,0x0000,0x8000,0x3fff}, -/*pi*/ {0xc235,0x2168,0xdaa2,0xc90f,0x4000}, -/*lg2*/ {0xf799,0xfbcf,0x9a84,0x9a20,0x3ffd}, -/*ln2*/ {0x79ac,0xd1cf,0x17f7,0xb172,0x3ffe}, -/*l2e*/ {0xf0bc,0x5c17,0x3b29,0xb8aa,0x3fff}, -/*l2t*/ {0x8afe,0xcd1b,0x784b,0xd49a,0x4000} -}; -#else -/* the same, 64-bit version */ -typedef unsigned short f15ld[4]; -const f15ld f15rk[] = -{ -#ifndef WORDS_BIGENDIAN -/*0*/ {0x0000,0x0000,0x0000,0x0000}, -/*1*/ {0x0000,0x0000,0x0000,0x3ff0}, -/*pi*/ {0x2d18,0x5444,0x21fb,0x4009}, -/*lg2*/ {0x79ff,0x509f,0x4413,0x3fd3}, -/*ln2*/ {0x39ef,0xfefa,0x2e42,0x3fe6}, -/*l2e*/ {0x82fe,0x652b,0x1547,0x3ff7}, -/*l2t*/ {0xa371,0x0979,0x934f,0x400a} -#else -/*0*/ {0x0000,0x0000,0x0000,0x0000}, -/*1*/ {0x3ff0,0x0000,0x0000,0x0000}, -/*pi*/ {0x4009,0x21fb,0x5444,0x2d18}, -/*lg2*/ {0x3fd3,0x4413,0x509f,0x79ff}, -/*ln2*/ {0x3fe6,0x2e42,0xfefa,0x39ef}, -/*l2e*/ {0x3ff7,0x1547,0x652b,0x82fe}, -/*l2t*/ {0x400a,0x934f,0x0979,0xa371} -#endif -}; -#endif - /* n must be a constant to be efficient */ static inline int lshift(int x, int n) { @@ -119,40 +28,6 @@ static inline int lshift(int x, int n) return x >> (-n); } -/* exception support */ -/* NOTE: not static to force relocation generation by GCC */ -void raise_exception(int exception_index) -{ - /* NOTE: the register at this point must be saved by hand because - longjmp restore them */ -#ifdef reg_EAX - env->regs[R_EAX] = EAX; -#endif -#ifdef reg_ECX - env->regs[R_ECX] = ECX; -#endif -#ifdef reg_EDX - env->regs[R_EDX] = EDX; -#endif -#ifdef reg_EBX - env->regs[R_EBX] = EBX; -#endif -#ifdef reg_ESP - env->regs[R_ESP] = ESP; -#endif -#ifdef reg_EBP - env->regs[R_EBP] = EBP; -#endif -#ifdef reg_ESI - env->regs[R_ESI] = ESI; -#endif -#ifdef reg_EDI - env->regs[R_EDI] = EDI; -#endif - env->exception_index = exception_index; - longjmp(env->jmp_env, 1); -} - /* we define the various pieces of code used by the JIT */ #define REG EAX @@ -205,62 +80,34 @@ void raise_exception(int exception_index) /* operations with flags */ -void OPPROTO op_addl_T0_T1_cc(void) +/* update flags with T0 and T1 (add/sub case) */ +void OPPROTO op_update2_cc(void) { - CC_SRC = T0; - T0 += T1; + CC_SRC = T1; CC_DST = T0; } -void OPPROTO op_orl_T0_T1_cc(void) +/* update flags with T0 (logic operation case) */ +void OPPROTO op_update1_cc(void) { - T0 |= T1; CC_DST = T0; } -void OPPROTO op_andl_T0_T1_cc(void) +void OPPROTO op_update_neg_cc(void) { - T0 &= T1; - CC_DST = T0; -} - -void OPPROTO op_subl_T0_T1_cc(void) -{ - CC_SRC = T0; - T0 -= T1; - CC_DST = T0; -} - -void OPPROTO op_xorl_T0_T1_cc(void) -{ - T0 ^= T1; + CC_SRC = -T0; CC_DST = T0; } void OPPROTO op_cmpl_T0_T1_cc(void) { - CC_SRC = T0; + CC_SRC = T1; CC_DST = T0 - T1; } -void OPPROTO op_negl_T0_cc(void) -{ - CC_SRC = 0; - T0 = -T0; - CC_DST = T0; -} - -void OPPROTO op_incl_T0_cc(void) +void OPPROTO op_update_inc_cc(void) { CC_SRC = cc_table[CC_OP].compute_c(); - T0++; - CC_DST = T0; -} - -void OPPROTO op_decl_T0_cc(void) -{ - CC_SRC = cc_table[CC_OP].compute_c(); - T0--; CC_DST = T0; } @@ -391,13 +238,18 @@ void OPPROTO op_imull_T0_T1(void) } /* division, flags are undefined */ -/* XXX: add exceptions for overflow & div by zero */ +/* XXX: add exceptions for overflow */ + void OPPROTO op_divb_AL_T0(void) { unsigned int num, den, q, r; num = (EAX & 0xffff); den = (T0 & 0xff); + if (den == 0) { + EIP = PARAM1; + raise_exception(EXCP00_DIVZ); + } q = (num / den) & 0xff; r = (num % den) & 0xff; EAX = (EAX & 0xffff0000) | (r << 8) | q; @@ -409,6 +261,10 @@ void OPPROTO op_idivb_AL_T0(void) num = (int16_t)EAX; den = (int8_t)T0; + if (den == 0) { + EIP = PARAM1; + raise_exception(EXCP00_DIVZ); + } q = (num / den) & 0xff; r = (num % den) & 0xff; EAX = (EAX & 0xffff0000) | (r << 8) | q; @@ -420,6 +276,10 @@ void OPPROTO op_divw_AX_T0(void) num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); den = (T0 & 0xffff); + if (den == 0) { + EIP = PARAM1; + raise_exception(EXCP00_DIVZ); + } q = (num / den) & 0xffff; r = (num % den) & 0xffff; EAX = (EAX & 0xffff0000) | q; @@ -432,6 +292,10 @@ void OPPROTO op_idivw_AX_T0(void) num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); den = (int16_t)T0; + if (den == 0) { + EIP = PARAM1; + raise_exception(EXCP00_DIVZ); + } q = (num / den) & 0xffff; r = (num % den) & 0xffff; EAX = (EAX & 0xffff0000) | q; @@ -440,28 +304,12 @@ void OPPROTO op_idivw_AX_T0(void) void OPPROTO op_divl_EAX_T0(void) { - unsigned int den, q, r; - uint64_t num; - - num = EAX | ((uint64_t)EDX << 32); - den = T0; - q = (num / den); - r = (num % den); - EAX = q; - EDX = r; + helper_divl_EAX_T0(PARAM1); } void OPPROTO op_idivl_EAX_T0(void) { - int den, q, r; - int64_t num; - - num = EAX | ((uint64_t)EDX << 32); - den = T0; - q = (num / den); - r = (num % den); - EAX = q; - EDX = r; + helper_idivl_EAX_T0(PARAM1); } /* constant load & misc op */ @@ -481,6 +329,11 @@ void OPPROTO op_andl_T0_ffff(void) T0 = T0 & 0xffff; } +void OPPROTO op_andl_T0_im(void) +{ + T0 = T0 & PARAM1; +} + void OPPROTO op_movl_T0_T1(void) { T0 = T1; @@ -511,6 +364,11 @@ void OPPROTO op_addl_A0_im(void) A0 += PARAM1; } +void OPPROTO op_addl_A0_AL(void) +{ + A0 += (EAX & 0xff); +} + void OPPROTO op_andl_A0_ffff(void) { A0 = A0 & 0xffff; @@ -518,120 +376,152 @@ void OPPROTO op_andl_A0_ffff(void) /* memory access */ -void OPPROTO op_ldub_T0_A0(void) -{ - T0 = ldub((uint8_t *)A0); -} +#define MEMSUFFIX +#include "ops_mem.h" + +#define MEMSUFFIX _user +#include "ops_mem.h" + +#define MEMSUFFIX _kernel +#include "ops_mem.h" -void OPPROTO op_ldsb_T0_A0(void) +/* used for bit operations */ + +void OPPROTO op_add_bitw_A0_T1(void) { - T0 = ldsb((int8_t *)A0); + A0 += ((int32_t)T1 >> 4) << 1; } -void OPPROTO op_lduw_T0_A0(void) +void OPPROTO op_add_bitl_A0_T1(void) { - T0 = lduw((uint8_t *)A0); + A0 += ((int32_t)T1 >> 5) << 2; } -void OPPROTO op_ldsw_T0_A0(void) +/* indirect jump */ + +void OPPROTO op_jmp_T0(void) { - T0 = ldsw((int8_t *)A0); + EIP = T0; } -void OPPROTO op_ldl_T0_A0(void) +void OPPROTO op_jmp_im(void) { - T0 = ldl((uint8_t *)A0); + EIP = PARAM1; } -void OPPROTO op_ldub_T1_A0(void) +void OPPROTO op_hlt(void) { - T1 = ldub((uint8_t *)A0); + env->exception_index = EXCP_HLT; + cpu_loop_exit(); } -void OPPROTO op_ldsb_T1_A0(void) +void OPPROTO op_debug(void) { - T1 = ldsb((int8_t *)A0); + env->exception_index = EXCP_DEBUG; + cpu_loop_exit(); } -void OPPROTO op_lduw_T1_A0(void) +void OPPROTO op_raise_interrupt(void) { - T1 = lduw((uint8_t *)A0); + int intno; + unsigned int next_eip; + intno = PARAM1; + next_eip = PARAM2; + raise_interrupt(intno, 1, 0, next_eip); } -void OPPROTO op_ldsw_T1_A0(void) +void OPPROTO op_raise_exception(void) { - T1 = ldsw((int8_t *)A0); + int exception_index; + exception_index = PARAM1; + raise_exception(exception_index); } -void OPPROTO op_ldl_T1_A0(void) +void OPPROTO op_into(void) { - T1 = ldl((uint8_t *)A0); + int eflags; + eflags = cc_table[CC_OP].compute_all(); + if (eflags & CC_O) { + raise_interrupt(EXCP04_INTO, 1, 0, PARAM1); + } + FORCE_RET(); } -void OPPROTO op_stb_T0_A0(void) +void OPPROTO op_cli(void) { - stb((uint8_t *)A0, T0); + env->eflags &= ~IF_MASK; } -void OPPROTO op_stw_T0_A0(void) +void OPPROTO op_sti(void) { - stw((uint8_t *)A0, T0); + env->eflags |= IF_MASK; } -void OPPROTO op_stl_T0_A0(void) +#if 0 +/* vm86plus instructions */ +void OPPROTO op_cli_vm(void) { - stl((uint8_t *)A0, T0); + env->eflags &= ~VIF_MASK; } -/* used for bit operations */ - -void OPPROTO op_add_bitw_A0_T1(void) +void OPPROTO op_sti_vm(void) { - A0 += ((int32_t)T1 >> 4) << 1; + env->eflags |= VIF_MASK; + if (env->eflags & VIP_MASK) { + EIP = PARAM1; + raise_exception(EXCP0D_GPF); + } + FORCE_RET(); } +#endif -void OPPROTO op_add_bitl_A0_T1(void) +void OPPROTO op_boundw(void) { - A0 += ((int32_t)T1 >> 5) << 2; + int low, high, v; + low = ldsw((uint8_t *)A0); + high = ldsw((uint8_t *)A0 + 2); + v = (int16_t)T0; + if (v < low || v > high) { + EIP = PARAM1; + raise_exception(EXCP05_BOUND); + } + FORCE_RET(); } -/* indirect jump */ - -void OPPROTO op_jmp_T0(void) +void OPPROTO op_boundl(void) { - EIP = T0; + int low, high, v; + low = ldl((uint8_t *)A0); + high = ldl((uint8_t *)A0 + 4); + v = T0; + if (v < low || v > high) { + EIP = PARAM1; + raise_exception(EXCP05_BOUND); + } + FORCE_RET(); } -void OPPROTO op_jmp_im(void) +void OPPROTO op_cmpxchg8b(void) { - EIP = PARAM1; + helper_cmpxchg8b(); } -void OPPROTO op_int_im(void) +void OPPROTO op_jmp_tb_next(void) { - EIP = PARAM1; - raise_exception(EXCP0D_GPF); + JUMP_TB(PARAM1, 0, PARAM2); } -void OPPROTO op_int3(void) +void OPPROTO op_movl_T0_0(void) { - EIP = PARAM1; - raise_exception(EXCP03_INT3); + T0 = 0; } -void OPPROTO op_into(void) +void OPPROTO op_exit_tb(void) { - int eflags; - eflags = cc_table[CC_OP].compute_all(); - if (eflags & CC_O) { - EIP = PARAM1; - raise_exception(EXCP04_INTO); - } else { - EIP = PARAM2; - } + EXIT_TB(); } -/* string ops */ +/* multiple size ops */ #define ldul ldl @@ -689,6 +579,38 @@ void OPPROTO op_movswl_DX_AX(void) EDX = (EDX & 0xffff0000) | (((int16_t)EAX >> 15) & 0xffff); } +/* string ops helpers */ + +void OPPROTO op_addl_ESI_T0(void) +{ + ESI += T0; +} + +void OPPROTO op_addw_ESI_T0(void) +{ + ESI = (ESI & ~0xffff) | ((ESI + T0) & 0xffff); +} + +void OPPROTO op_addl_EDI_T0(void) +{ + EDI += T0; +} + +void OPPROTO op_addw_EDI_T0(void) +{ + EDI = (EDI & ~0xffff) | ((EDI + T0) & 0xffff); +} + +void OPPROTO op_decl_ECX(void) +{ + ECX--; +} + +void OPPROTO op_decw_ECX(void) +{ + ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff); +} + /* push/pop */ void op_pushl_T0(void) @@ -713,7 +635,7 @@ void op_pushl_ss32_T0(void) { uint32_t offset; offset = ESP - 4; - stl(env->seg_cache[R_SS].base + offset, T0); + stl(env->segs[R_SS].base + offset, T0); /* modify ESP after to handle exceptions correctly */ ESP = offset; } @@ -722,7 +644,7 @@ void op_pushw_ss32_T0(void) { uint32_t offset; offset = ESP - 2; - stw(env->seg_cache[R_SS].base + offset, T0); + stw(env->segs[R_SS].base + offset, T0); /* modify ESP after to handle exceptions correctly */ ESP = offset; } @@ -731,7 +653,7 @@ void op_pushl_ss16_T0(void) { uint32_t offset; offset = (ESP - 4) & 0xffff; - stl(env->seg_cache[R_SS].base + offset, T0); + stl(env->segs[R_SS].base + offset, T0); /* modify ESP after to handle exceptions correctly */ ESP = (ESP & ~0xffff) | offset; } @@ -740,7 +662,7 @@ void op_pushw_ss16_T0(void) { uint32_t offset; offset = (ESP - 2) & 0xffff; - stw(env->seg_cache[R_SS].base + offset, T0); + stw(env->segs[R_SS].base + offset, T0); /* modify ESP after to handle exceptions correctly */ ESP = (ESP & ~0xffff) | offset; } @@ -758,22 +680,22 @@ void op_popw_T0(void) void op_popl_ss32_T0(void) { - T0 = ldl(env->seg_cache[R_SS].base + ESP); + T0 = ldl(env->segs[R_SS].base + ESP); } void op_popw_ss32_T0(void) { - T0 = lduw(env->seg_cache[R_SS].base + ESP); + T0 = lduw(env->segs[R_SS].base + ESP); } void op_popl_ss16_T0(void) { - T0 = ldl(env->seg_cache[R_SS].base + (ESP & 0xffff)); + T0 = ldl(env->segs[R_SS].base + (ESP & 0xffff)); } void op_popw_ss16_T0(void) { - T0 = lduw(env->seg_cache[R_SS].base + (ESP & 0xffff)); + T0 = lduw(env->segs[R_SS].base + (ESP & 0xffff)); } void op_addl_ESP_4(void) @@ -806,21 +728,24 @@ void op_addw_ESP_im(void) ESP = (ESP & ~0xffff) | ((ESP + PARAM1) & 0xffff); } -/* rdtsc */ -#ifndef __i386__ -uint64_t emu_time; -#endif -void op_rdtsc(void) +void OPPROTO op_rdtsc(void) { - uint64_t val; -#ifdef __i386__ - asm("rdtsc" : "=A" (val)); -#else - /* better than nothing: the time increases */ - val = emu_time++; -#endif - EAX = val; - EDX = val >> 32; + helper_rdtsc(); +} + +void OPPROTO op_cpuid(void) +{ + helper_cpuid(); +} + +void OPPROTO op_rdmsr(void) +{ + helper_rdmsr(); +} + +void OPPROTO op_wrmsr(void) +{ + helper_wrmsr(); } /* bcd */ @@ -955,51 +880,32 @@ void OPPROTO op_das(void) /* segment handling */ -void load_seg(int seg_reg, int selector) +void OPPROTO op_movl_seg_T0(void) { - SegmentCache *sc; - SegmentDescriptorTable *dt; - int index; - uint32_t e1, e2; - uint8_t *ptr; - - env->segs[seg_reg] = selector; - sc = &env->seg_cache[seg_reg]; - if (env->vm86) { - sc->base = (void *)(selector << 4); - sc->limit = 0xffff; - sc->seg_32bit = 0; - } else { - if (selector & 0x4) - dt = &env->ldt; - else - dt = &env->gdt; - index = selector & ~7; - if ((index + 7) > dt->limit) - raise_exception(EXCP0D_GPF); - ptr = dt->base + index; - e1 = ldl(ptr); - e2 = ldl(ptr + 4); - sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); - sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000); - if (e2 & (1 << 23)) - sc->limit = (sc->limit << 12) | 0xfff; - sc->seg_32bit = (e2 >> 22) & 1; -#if 0 - fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx seg_32bit=%d\n", - selector, (unsigned long)sc->base, sc->limit, sc->seg_32bit); -#endif - } + load_seg(PARAM1, T0 & 0xffff, PARAM2); } -void OPPROTO op_movl_seg_T0(void) +/* faster VM86 version */ +void OPPROTO op_movl_seg_T0_vm(void) { - load_seg(PARAM1, T0 & 0xffff); + int selector; + SegmentCache *sc; + + selector = T0 & 0xffff; + /* env->segs[] access */ + sc = (SegmentCache *)((char *)env + PARAM1); + sc->selector = selector; + sc->base = (void *)(selector << 4); } void OPPROTO op_movl_T0_seg(void) { - T0 = env->segs[PARAM1]; + T0 = env->segs[PARAM1].selector; +} + +void OPPROTO op_movl_A0_seg(void) +{ + A0 = *(unsigned long *)((char *)env + PARAM1); } void OPPROTO op_addl_A0_seg(void) @@ -1007,92 +913,112 @@ void OPPROTO op_addl_A0_seg(void) A0 += *(unsigned long *)((char *)env + PARAM1); } -/* flags handling */ +void OPPROTO op_lsl(void) +{ + helper_lsl(); +} -/* slow jumps cases (compute x86 flags) */ -void OPPROTO op_jo_cc(void) +void OPPROTO op_lar(void) { - int eflags; - eflags = cc_table[CC_OP].compute_all(); - if (eflags & CC_O) - EIP = PARAM1; - else - EIP = PARAM2; - FORCE_RET(); + helper_lar(); } -void OPPROTO op_jb_cc(void) +/* T0: segment, T1:eip */ +void OPPROTO op_ljmp_protected_T0_T1(void) { - if (cc_table[CC_OP].compute_c()) - EIP = PARAM1; - else - EIP = PARAM2; - FORCE_RET(); + helper_ljmp_protected_T0_T1(); } -void OPPROTO op_jz_cc(void) +void OPPROTO op_lcall_real_T0_T1(void) { - int eflags; - eflags = cc_table[CC_OP].compute_all(); - if (eflags & CC_Z) - EIP = PARAM1; - else - EIP = PARAM2; - FORCE_RET(); + helper_lcall_real_T0_T1(PARAM1, PARAM2); } -void OPPROTO op_jbe_cc(void) +void OPPROTO op_lcall_protected_T0_T1(void) { - int eflags; - eflags = cc_table[CC_OP].compute_all(); - if (eflags & (CC_Z | CC_C)) - EIP = PARAM1; - else - EIP = PARAM2; - FORCE_RET(); + helper_lcall_protected_T0_T1(PARAM1, PARAM2); } -void OPPROTO op_js_cc(void) +void OPPROTO op_iret_real(void) { - int eflags; - eflags = cc_table[CC_OP].compute_all(); - if (eflags & CC_S) - EIP = PARAM1; - else - EIP = PARAM2; - FORCE_RET(); + helper_iret_real(PARAM1); } -void OPPROTO op_jp_cc(void) +void OPPROTO op_iret_protected(void) { - int eflags; - eflags = cc_table[CC_OP].compute_all(); - if (eflags & CC_P) - EIP = PARAM1; - else - EIP = PARAM2; - FORCE_RET(); + helper_iret_protected(PARAM1); } -void OPPROTO op_jl_cc(void) +void OPPROTO op_lret_protected(void) { - int eflags; - eflags = cc_table[CC_OP].compute_all(); - if ((eflags ^ (eflags >> 4)) & 0x80) - EIP = PARAM1; - else - EIP = PARAM2; - FORCE_RET(); + helper_lret_protected(PARAM1, PARAM2); } -void OPPROTO op_jle_cc(void) +void OPPROTO op_lldt_T0(void) { - int eflags; - eflags = cc_table[CC_OP].compute_all(); - if (((eflags ^ (eflags >> 4)) & 0x80) || (eflags & CC_Z)) - EIP = PARAM1; + helper_lldt_T0(); +} + +void OPPROTO op_ltr_T0(void) +{ + helper_ltr_T0(); +} + +/* CR registers access */ +void OPPROTO op_movl_crN_T0(void) +{ + helper_movl_crN_T0(PARAM1); +} + +/* DR registers access */ +void OPPROTO op_movl_drN_T0(void) +{ + helper_movl_drN_T0(PARAM1); +} + +void OPPROTO op_lmsw_T0(void) +{ + /* only 4 lower bits of CR0 are modified */ + T0 = (env->cr[0] & ~0xf) | (T0 & 0xf); + helper_movl_crN_T0(0); +} + +void OPPROTO op_invlpg_A0(void) +{ + helper_invlpg(A0); +} + +void OPPROTO op_movl_T0_env(void) +{ + T0 = *(uint32_t *)((char *)env + PARAM1); +} + +void OPPROTO op_movl_env_T0(void) +{ + *(uint32_t *)((char *)env + PARAM1) = T0; +} + +void OPPROTO op_movl_env_T1(void) +{ + *(uint32_t *)((char *)env + PARAM1) = T1; +} + +void OPPROTO op_clts(void) +{ + env->cr[0] &= ~CR0_TS_MASK; +} + +/* flags handling */ + +/* slow jumps cases : in order to avoid calling a function with a + pointer (which can generate a stack frame on PowerPC), we use + op_setcc to set T0 and then call op_jcc. */ +void OPPROTO op_jcc(void) +{ + if (T0) + JUMP_TB(PARAM1, 0, PARAM2); else - EIP = PARAM2; + JUMP_TB(PARAM1, 1, PARAM3); FORCE_RET(); } @@ -1161,25 +1087,111 @@ void OPPROTO op_set_cc_op(void) CC_OP = PARAM1; } +#define FL_UPDATE_MASK16 (FL_UPDATE_MASK32 & 0xffff) + void OPPROTO op_movl_eflags_T0(void) { - CC_SRC = T0; - DF = 1 - (2 * ((T0 >> 10) & 1)); + int eflags; + eflags = T0; + CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + DF = 1 - (2 * ((eflags >> 10) & 1)); + /* we also update some system flags as in user mode */ + env->eflags = (env->eflags & ~FL_UPDATE_MASK32) | + (eflags & FL_UPDATE_MASK32); } +void OPPROTO op_movw_eflags_T0(void) +{ + int eflags; + eflags = T0; + CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + DF = 1 - (2 * ((eflags >> 10) & 1)); + /* we also update some system flags as in user mode */ + env->eflags = (env->eflags & ~FL_UPDATE_MASK16) | + (eflags & FL_UPDATE_MASK16); +} + +void OPPROTO op_movl_eflags_T0_cpl0(void) +{ + load_eflags(T0, FL_UPDATE_CPL0_MASK); +} + +void OPPROTO op_movw_eflags_T0_cpl0(void) +{ + load_eflags(T0, FL_UPDATE_CPL0_MASK & 0xffff); +} + +#if 0 +/* vm86plus version */ +void OPPROTO op_movw_eflags_T0_vm(void) +{ + int eflags; + eflags = T0; + CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + DF = 1 - (2 * ((eflags >> 10) & 1)); + /* we also update some system flags as in user mode */ + env->eflags = (env->eflags & ~(FL_UPDATE_MASK16 | VIF_MASK)) | + (eflags & FL_UPDATE_MASK16); + if (eflags & IF_MASK) { + env->eflags |= VIF_MASK; + if (env->eflags & VIP_MASK) { + EIP = PARAM1; + raise_exception(EXCP0D_GPF); + } + } + FORCE_RET(); +} + +void OPPROTO op_movl_eflags_T0_vm(void) +{ + int eflags; + eflags = T0; + CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + DF = 1 - (2 * ((eflags >> 10) & 1)); + /* we also update some system flags as in user mode */ + env->eflags = (env->eflags & ~(FL_UPDATE_MASK32 | VIF_MASK)) | + (eflags & FL_UPDATE_MASK32); + if (eflags & IF_MASK) { + env->eflags |= VIF_MASK; + if (env->eflags & VIP_MASK) { + EIP = PARAM1; + raise_exception(EXCP0D_GPF); + } + } + FORCE_RET(); +} +#endif + /* XXX: compute only O flag */ void OPPROTO op_movb_eflags_T0(void) { int of; of = cc_table[CC_OP].compute_all() & CC_O; - CC_SRC = T0 | of; + CC_SRC = (T0 & (CC_S | CC_Z | CC_A | CC_P | CC_C)) | of; } void OPPROTO op_movl_T0_eflags(void) { - T0 = cc_table[CC_OP].compute_all(); - T0 |= (DF & DIRECTION_FLAG); + int eflags; + eflags = cc_table[CC_OP].compute_all(); + eflags |= (DF & DF_MASK); + eflags |= env->eflags & ~(VM_MASK | RF_MASK); + T0 = eflags; +} + +/* vm86plus version */ +#if 0 +void OPPROTO op_movl_T0_eflags_vm(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + eflags |= (DF & DF_MASK); + eflags |= env->eflags & ~(VM_MASK | RF_MASK | IF_MASK); + if (env->eflags & VIF_MASK) + eflags |= IF_MASK; + T0 = eflags; } +#endif void OPPROTO op_cld(void) { @@ -1286,112 +1298,59 @@ CCTable cc_table[CC_OP_NB] = { [CC_OP_DECW] = { compute_all_decw, compute_c_incl }, [CC_OP_DECL] = { compute_all_decl, compute_c_incl }, - [CC_OP_SHLB] = { compute_all_shlb, compute_c_shll }, - [CC_OP_SHLW] = { compute_all_shlw, compute_c_shll }, + [CC_OP_SHLB] = { compute_all_shlb, compute_c_shlb }, + [CC_OP_SHLW] = { compute_all_shlw, compute_c_shlw }, [CC_OP_SHLL] = { compute_all_shll, compute_c_shll }, - [CC_OP_SARB] = { compute_all_sarb, compute_c_shll }, - [CC_OP_SARW] = { compute_all_sarw, compute_c_shll }, - [CC_OP_SARL] = { compute_all_sarl, compute_c_shll }, + [CC_OP_SARB] = { compute_all_sarb, compute_c_sarl }, + [CC_OP_SARW] = { compute_all_sarw, compute_c_sarl }, + [CC_OP_SARL] = { compute_all_sarl, compute_c_sarl }, }; -/* floating point support */ - -#ifdef USE_X86LDOUBLE -/* use long double functions */ -#define lrint lrintl -#define llrint llrintl -#define fabs fabsl -#define sin sinl -#define cos cosl -#define sqrt sqrtl -#define pow powl -#define log logl -#define tan tanl -#define atan2 atan2l -#define floor floorl -#define ceil ceill -#define rint rintl -#endif +/* floating point support. Some of the code for complicated x87 + functions comes from the LGPL'ed x86 emulator found in the Willows + TWIN windows emulator. */ -extern int lrint(CPU86_LDouble x); -extern int64_t llrint(CPU86_LDouble x); -extern CPU86_LDouble fabs(CPU86_LDouble x); -extern CPU86_LDouble sin(CPU86_LDouble x); -extern CPU86_LDouble cos(CPU86_LDouble x); -extern CPU86_LDouble sqrt(CPU86_LDouble x); -extern CPU86_LDouble pow(CPU86_LDouble, CPU86_LDouble); -extern CPU86_LDouble log(CPU86_LDouble x); -extern CPU86_LDouble tan(CPU86_LDouble x); -extern CPU86_LDouble atan2(CPU86_LDouble, CPU86_LDouble); -extern CPU86_LDouble floor(CPU86_LDouble x); -extern CPU86_LDouble ceil(CPU86_LDouble x); -extern CPU86_LDouble rint(CPU86_LDouble x); - -#define RC_MASK 0xc00 -#define RC_NEAR 0x000 -#define RC_DOWN 0x400 -#define RC_UP 0x800 -#define RC_CHOP 0xc00 - -#define MAXTAN 9223372036854775808.0 - -#ifdef USE_X86LDOUBLE +#if defined(__powerpc__) +extern CPU86_LDouble copysign(CPU86_LDouble, CPU86_LDouble); -/* only for x86 */ -typedef union { - long double d; - struct { - unsigned long long lower; - unsigned short upper; - } l; -} CPU86_LDoubleU; - -/* the following deal with x86 long double-precision numbers */ -#define MAXEXPD 0x7fff -#define EXPBIAS 16383 -#define EXPD(fp) (fp.l.upper & 0x7fff) -#define SIGND(fp) ((fp.l.upper) & 0x8000) -#define MANTD(fp) (fp.l.lower) -#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS - -#else +/* correct (but slow) PowerPC rint() (glibc version is incorrect) */ +double qemu_rint(double x) +{ + double y = 4503599627370496.0; + if (fabs(x) >= y) + return x; + if (x < 0) + y = -y; + y = (x + y) - y; + if (y == 0.0) + y = copysign(y, x); + return y; +} -typedef union { - double d; -#ifndef WORDS_BIGENDIAN - struct { - unsigned long lower; - long upper; - } l; -#else - struct { - long upper; - unsigned long lower; - } l; -#endif - long long ll; -} CPU86_LDoubleU; - -/* the following deal with IEEE double-precision numbers */ -#define MAXEXPD 0x7ff -#define EXPBIAS 1023 -#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) -#define SIGND(fp) ((fp.l.upper) & 0x80000000) -#define MANTD(fp) (fp.ll & ((1LL << 52) - 1)) -#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7ff << 20)) | (EXPBIAS << 20) +#define rint qemu_rint #endif /* fp load FT0 */ void OPPROTO op_flds_FT0_A0(void) { +#ifdef USE_FP_CONVERT + FP_CONVERT.i32 = ldl((void *)A0); + FT0 = FP_CONVERT.f; +#else FT0 = ldfl((void *)A0); +#endif } void OPPROTO op_fldl_FT0_A0(void) { +#ifdef USE_FP_CONVERT + FP_CONVERT.i64 = ldq((void *)A0); + FT0 = FP_CONVERT.d; +#else FT0 = ldfq((void *)A0); +#endif } /* helpers are needed to avoid static constant reference. XXX: find a better way */ @@ -1431,17 +1390,32 @@ void OPPROTO op_fildll_FT0_A0(void) void OPPROTO op_fild_FT0_A0(void) { +#ifdef USE_FP_CONVERT + FP_CONVERT.i32 = ldsw((void *)A0); + FT0 = (CPU86_LDouble)FP_CONVERT.i32; +#else FT0 = (CPU86_LDouble)ldsw((void *)A0); +#endif } void OPPROTO op_fildl_FT0_A0(void) { +#ifdef USE_FP_CONVERT + FP_CONVERT.i32 = (int32_t) ldl((void *)A0); + FT0 = (CPU86_LDouble)FP_CONVERT.i32; +#else FT0 = (CPU86_LDouble)((int32_t)ldl((void *)A0)); +#endif } void OPPROTO op_fildll_FT0_A0(void) { +#ifdef USE_FP_CONVERT + FP_CONVERT.i64 = (int64_t) ldq((void *)A0); + FT0 = (CPU86_LDouble)FP_CONVERT.i64; +#else FT0 = (CPU86_LDouble)((int64_t)ldq((void *)A0)); +#endif } #endif @@ -1449,33 +1423,42 @@ void OPPROTO op_fildll_FT0_A0(void) void OPPROTO op_flds_ST0_A0(void) { - ST0 = ldfl((void *)A0); + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; +#ifdef USE_FP_CONVERT + FP_CONVERT.i32 = ldl((void *)A0); + env->fpregs[new_fpstt] = FP_CONVERT.f; +#else + env->fpregs[new_fpstt] = ldfl((void *)A0); +#endif + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ } void OPPROTO op_fldl_ST0_A0(void) { - ST0 = ldfq((void *)A0); + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; +#ifdef USE_FP_CONVERT + FP_CONVERT.i64 = ldq((void *)A0); + env->fpregs[new_fpstt] = FP_CONVERT.d; +#else + env->fpregs[new_fpstt] = ldfq((void *)A0); +#endif + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ } #ifdef USE_X86LDOUBLE void OPPROTO op_fldt_ST0_A0(void) { - ST0 = *(long double *)A0; + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; + env->fpregs[new_fpstt] = *(long double *)A0; + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ } #else -void helper_fldt_ST0_A0(void) -{ - CPU86_LDoubleU temp; - int upper, e; - /* mantissa */ - upper = lduw((uint8_t *)A0 + 8); - /* XXX: handle overflow ? */ - e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */ - e |= (upper >> 4) & 0x800; /* sign */ - temp.ll = ((ldq((void *)A0) >> 11) & ((1LL << 52) - 1)) | ((uint64_t)e << 52); - ST0 = temp.d; -} - void OPPROTO op_fldt_ST0_A0(void) { helper_fldt_ST0_A0(); @@ -1487,17 +1470,29 @@ void OPPROTO op_fldt_ST0_A0(void) void helper_fild_ST0_A0(void) { - ST0 = (CPU86_LDouble)ldsw((void *)A0); + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; + env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw((void *)A0); + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ } void helper_fildl_ST0_A0(void) { - ST0 = (CPU86_LDouble)((int32_t)ldl((void *)A0)); + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; + env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl((void *)A0)); + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ } void helper_fildll_ST0_A0(void) { - ST0 = (CPU86_LDouble)((int64_t)ldq((void *)A0)); + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; + env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq((void *)A0)); + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ } void OPPROTO op_fild_ST0_A0(void) @@ -1519,17 +1514,44 @@ void OPPROTO op_fildll_ST0_A0(void) void OPPROTO op_fild_ST0_A0(void) { - ST0 = (CPU86_LDouble)ldsw((void *)A0); + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; +#ifdef USE_FP_CONVERT + FP_CONVERT.i32 = ldsw((void *)A0); + env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32; +#else + env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw((void *)A0); +#endif + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ } void OPPROTO op_fildl_ST0_A0(void) { - ST0 = (CPU86_LDouble)((int32_t)ldl((void *)A0)); + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; +#ifdef USE_FP_CONVERT + FP_CONVERT.i32 = (int32_t) ldl((void *)A0); + env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32; +#else + env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl((void *)A0)); +#endif + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ } void OPPROTO op_fildll_ST0_A0(void) { - ST0 = (CPU86_LDouble)((int64_t)ldq((void *)A0)); + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; +#ifdef USE_FP_CONVERT + FP_CONVERT.i64 = (int64_t) ldq((void *)A0); + env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i64; +#else + env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq((void *)A0)); +#endif + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ } #endif @@ -1538,7 +1560,12 @@ void OPPROTO op_fildll_ST0_A0(void) void OPPROTO op_fsts_ST0_A0(void) { +#ifdef USE_FP_CONVERT + FP_CONVERT.f = (float)ST0; + stfl((void *)A0, FP_CONVERT.f); +#else stfl((void *)A0, (float)ST0); +#endif } void OPPROTO op_fstl_ST0_A0(void) @@ -1552,19 +1579,6 @@ void OPPROTO op_fstt_ST0_A0(void) *(long double *)A0 = ST0; } #else -void helper_fstt_ST0_A0(void) -{ - CPU86_LDoubleU temp; - int e; - temp.d = ST0; - /* mantissa */ - stq((void *)A0, (MANTD(temp) << 11) | (1LL << 63)); - /* exponent + sign */ - e = EXPD(temp) - EXPBIAS + 16383; - e |= SIGND(temp) >> 16; - stw((uint8_t *)A0 + 8, e); -} - void OPPROTO op_fstt_ST0_A0(void) { helper_fstt_ST0_A0(); @@ -1573,74 +1587,46 @@ void OPPROTO op_fstt_ST0_A0(void) void OPPROTO op_fist_ST0_A0(void) { +#if defined(__sparc__) && !defined(__sparc_v9__) + register CPU86_LDouble d asm("o0"); +#else + CPU86_LDouble d; +#endif int val; - val = lrint(ST0); + + d = ST0; + val = lrint(d); + if (val != (int16_t)val) + val = -32768; stw((void *)A0, val); } void OPPROTO op_fistl_ST0_A0(void) { +#if defined(__sparc__) && !defined(__sparc_v9__) + register CPU86_LDouble d asm("o0"); +#else + CPU86_LDouble d; +#endif int val; - val = lrint(ST0); + + d = ST0; + val = lrint(d); stl((void *)A0, val); } void OPPROTO op_fistll_ST0_A0(void) { +#if defined(__sparc__) && !defined(__sparc_v9__) + register CPU86_LDouble d asm("o0"); +#else + CPU86_LDouble d; +#endif int64_t val; - val = llrint(ST0); - stq((void *)A0, val); -} -/* BCD ops */ - -#define MUL10(iv) ( iv + iv + (iv << 3) ) - -void helper_fbld_ST0_A0(void) -{ - uint8_t *seg; - CPU86_LDouble fpsrcop; - int m32i; - unsigned int v; - - /* in this code, seg/m32i will be used as temporary ptr/int */ - seg = (uint8_t *)A0 + 8; - v = ldub(seg--); - /* XXX: raise exception */ - if (v != 0) - return; - v = ldub(seg--); - /* XXX: raise exception */ - if ((v & 0xf0) != 0) - return; - m32i = v; /* <-- d14 */ - v = ldub(seg--); - m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d13 */ - m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d12 */ - v = ldub(seg--); - m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d11 */ - m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d10 */ - v = ldub(seg--); - m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d9 */ - m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d8 */ - fpsrcop = ((CPU86_LDouble)m32i) * 100000000.0; - - v = ldub(seg--); - m32i = (v >> 4); /* <-- d7 */ - m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d6 */ - v = ldub(seg--); - m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d5 */ - m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d4 */ - v = ldub(seg--); - m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d3 */ - m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d2 */ - v = ldub(seg); - m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d1 */ - m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d0 */ - fpsrcop += ((CPU86_LDouble)m32i); - if ( ldub(seg+9) & 0x80 ) - fpsrcop = -fpsrcop; - ST0 = fpsrcop; + d = ST0; + val = llrint(d); + stq((void *)A0, val); } void OPPROTO op_fbld_ST0_A0(void) @@ -1648,42 +1634,6 @@ void OPPROTO op_fbld_ST0_A0(void) helper_fbld_ST0_A0(); } -void helper_fbst_ST0_A0(void) -{ - CPU86_LDouble fptemp; - CPU86_LDouble fpsrcop; - int v; - uint8_t *mem_ref, *mem_end; - - fpsrcop = rint(ST0); - mem_ref = (uint8_t *)A0; - mem_end = mem_ref + 8; - if ( fpsrcop < 0.0 ) { - stw(mem_end, 0x8000); - fpsrcop = -fpsrcop; - } else { - stw(mem_end, 0x0000); - } - while (mem_ref < mem_end) { - if (fpsrcop == 0.0) - break; - fptemp = floor(fpsrcop/10.0); - v = ((int)(fpsrcop - fptemp*10.0)); - if (fptemp == 0.0) { - stb(mem_ref++, v); - break; - } - fpsrcop = fptemp; - fptemp = floor(fpsrcop/10.0); - v |= (((int)(fpsrcop - fptemp*10.0)) << 4); - stb(mem_ref++, v); - fpsrcop = fptemp; - } - while (mem_ref < mem_end) { - stb(mem_ref++, 0); - } -} - void OPPROTO op_fbst_ST0_A0(void) { helper_fbst_ST0_A0(); @@ -1691,18 +1641,6 @@ void OPPROTO op_fbst_ST0_A0(void) /* FPU move */ -static inline void fpush(void) -{ - env->fpstt = (env->fpstt - 1) & 7; - env->fptags[env->fpstt] = 0; /* validate stack entry */ -} - -static inline void fpop(void) -{ - env->fptags[env->fpstt] = 1; /* invvalidate stack entry */ - env->fpstt = (env->fpstt + 1) & 7; -} - void OPPROTO op_fpush(void) { fpush(); @@ -1777,6 +1715,34 @@ void OPPROTO op_fucom_ST0_FT0(void) FORCE_RET(); } +/* XXX: handle nans */ +void OPPROTO op_fcomi_ST0_FT0(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + eflags &= ~(CC_Z | CC_P | CC_C); + if (ST0 < FT0) + eflags |= CC_C; + else if (ST0 == FT0) + eflags |= CC_Z; + CC_SRC = eflags; + FORCE_RET(); +} + +/* XXX: handle nans */ +void OPPROTO op_fucomi_ST0_FT0(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + eflags &= ~(CC_Z | CC_P | CC_C); + if (ST0 < FT0) + eflags |= CC_C; + else if (ST0 == FT0) + eflags |= CC_Z; + CC_SRC = eflags; + FORCE_RET(); +} + void OPPROTO op_fadd_ST0_FT0(void) { ST0 += FT0; @@ -1854,33 +1820,6 @@ void OPPROTO op_fabs_ST0(void) ST0 = fabs(ST0); } -void helper_fxam_ST0(void) -{ - CPU86_LDoubleU temp; - int expdif; - - temp.d = ST0; - - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - if (SIGND(temp)) - env->fpus |= 0x200; /* C1 <-- 1 */ - - expdif = EXPD(temp); - if (expdif == MAXEXPD) { - if (MANTD(temp) == 0) - env->fpus |= 0x500 /*Infinity*/; - else - env->fpus |= 0x100 /*NaN*/; - } else if (expdif == 0) { - if (MANTD(temp) == 0) - env->fpus |= 0x4000 /*Zero*/; - else - env->fpus |= 0x4400 /*Denormal*/; - } else { - env->fpus |= 0x400; - } -} - void OPPROTO op_fxam_ST0(void) { helper_fxam_ST0(); @@ -1888,253 +1827,42 @@ void OPPROTO op_fxam_ST0(void) void OPPROTO op_fld1_ST0(void) { - ST0 = *(CPU86_LDouble *)&f15rk[1]; + ST0 = f15rk[1]; } void OPPROTO op_fldl2t_ST0(void) { - ST0 = *(CPU86_LDouble *)&f15rk[6]; + ST0 = f15rk[6]; } void OPPROTO op_fldl2e_ST0(void) { - ST0 = *(CPU86_LDouble *)&f15rk[5]; + ST0 = f15rk[5]; } void OPPROTO op_fldpi_ST0(void) { - ST0 = *(CPU86_LDouble *)&f15rk[2]; + ST0 = f15rk[2]; } void OPPROTO op_fldlg2_ST0(void) { - ST0 = *(CPU86_LDouble *)&f15rk[3]; + ST0 = f15rk[3]; } void OPPROTO op_fldln2_ST0(void) { - ST0 = *(CPU86_LDouble *)&f15rk[4]; + ST0 = f15rk[4]; } void OPPROTO op_fldz_ST0(void) { - ST0 = *(CPU86_LDouble *)&f15rk[0]; + ST0 = f15rk[0]; } void OPPROTO op_fldz_FT0(void) { - ST0 = *(CPU86_LDouble *)&f15rk[0]; -} - -void helper_f2xm1(void) -{ - ST0 = pow(2.0,ST0) - 1.0; -} - -void helper_fyl2x(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if (fptemp>0.0){ - fptemp = log(fptemp)/log(2.0); /* log2(ST) */ - ST1 *= fptemp; - fpop(); - } else { - env->fpus &= (~0x4700); - env->fpus |= 0x400; - } -} - -void helper_fptan(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { - env->fpus |= 0x400; - } else { - ST0 = tan(fptemp); - fpush(); - ST0 = 1.0; - env->fpus &= (~0x400); /* C2 <-- 0 */ - /* the above code is for |arg| < 2**52 only */ - } -} - -void helper_fpatan(void) -{ - CPU86_LDouble fptemp, fpsrcop; - - fpsrcop = ST1; - fptemp = ST0; - ST1 = atan2(fpsrcop,fptemp); - fpop(); -} - -void helper_fxtract(void) -{ - CPU86_LDoubleU temp; - unsigned int expdif; - - temp.d = ST0; - expdif = EXPD(temp) - EXPBIAS; - /*DP exponent bias*/ - ST0 = expdif; - fpush(); - BIASEXPONENT(temp); - ST0 = temp.d; -} - -void helper_fprem1(void) -{ - CPU86_LDouble dblq, fpsrcop, fptemp; - CPU86_LDoubleU fpsrcop1, fptemp1; - int expdif; - int q; - - fpsrcop = ST0; - fptemp = ST1; - fpsrcop1.d = fpsrcop; - fptemp1.d = fptemp; - expdif = EXPD(fpsrcop1) - EXPD(fptemp1); - if (expdif < 53) { - dblq = fpsrcop / fptemp; - dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); - ST0 = fpsrcop - fptemp*dblq; - q = (int)dblq; /* cutting off top bits is assumed here */ - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - /* (C0,C1,C3) <-- (q2,q1,q0) */ - env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ - env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ - env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ - } else { - env->fpus |= 0x400; /* C2 <-- 1 */ - fptemp = pow(2.0, expdif-50); - fpsrcop = (ST0 / ST1) / fptemp; - /* fpsrcop = integer obtained by rounding to the nearest */ - fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)? - floor(fpsrcop): ceil(fpsrcop); - ST0 -= (ST1 * fpsrcop * fptemp); - } -} - -void helper_fprem(void) -{ - CPU86_LDouble dblq, fpsrcop, fptemp; - CPU86_LDoubleU fpsrcop1, fptemp1; - int expdif; - int q; - - fpsrcop = ST0; - fptemp = ST1; - fpsrcop1.d = fpsrcop; - fptemp1.d = fptemp; - expdif = EXPD(fpsrcop1) - EXPD(fptemp1); - if ( expdif < 53 ) { - dblq = fpsrcop / fptemp; - dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); - ST0 = fpsrcop - fptemp*dblq; - q = (int)dblq; /* cutting off top bits is assumed here */ - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - /* (C0,C1,C3) <-- (q2,q1,q0) */ - env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ - env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ - env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ - } else { - env->fpus |= 0x400; /* C2 <-- 1 */ - fptemp = pow(2.0, expdif-50); - fpsrcop = (ST0 / ST1) / fptemp; - /* fpsrcop = integer obtained by chopping */ - fpsrcop = (fpsrcop < 0.0)? - -(floor(fabs(fpsrcop))): floor(fpsrcop); - ST0 -= (ST1 * fpsrcop * fptemp); - } -} - -void helper_fyl2xp1(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if ((fptemp+1.0)>0.0) { - fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */ - ST1 *= fptemp; - fpop(); - } else { - env->fpus &= (~0x4700); - env->fpus |= 0x400; - } -} - -void helper_fsqrt(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if (fptemp<0.0) { - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - env->fpus |= 0x400; - } - ST0 = sqrt(fptemp); -} - -void helper_fsincos(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { - env->fpus |= 0x400; - } else { - ST0 = sin(fptemp); - fpush(); - ST0 = cos(fptemp); - env->fpus &= (~0x400); /* C2 <-- 0 */ - /* the above code is for |arg| < 2**63 only */ - } -} - -void helper_frndint(void) -{ - ST0 = rint(ST0); -} - -void helper_fscale(void) -{ - CPU86_LDouble fpsrcop, fptemp; - - fpsrcop = 2.0; - fptemp = pow(fpsrcop,ST1); - ST0 *= fptemp; -} - -void helper_fsin(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { - env->fpus |= 0x400; - } else { - ST0 = sin(fptemp); - env->fpus &= (~0x400); /* C2 <-- 0 */ - /* the above code is for |arg| < 2**53 only */ - } -} - -void helper_fcos(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { - env->fpus |= 0x400; - } else { - ST0 = cos(fptemp); - env->fpus &= (~0x400); /* C2 <-- 0 */ - /* the above code is for |arg5 < 2**63 only */ - } + ST0 = f15rk[0]; } /* associated heplers to reduce generated code length and to simplify @@ -2273,6 +2001,26 @@ void OPPROTO op_fninit(void) env->fptags[7] = 1; } +void OPPROTO op_fnstenv_A0(void) +{ + helper_fstenv((uint8_t *)A0, PARAM1); +} + +void OPPROTO op_fldenv_A0(void) +{ + helper_fldenv((uint8_t *)A0, PARAM1); +} + +void OPPROTO op_fnsave_A0(void) +{ + helper_fsave((uint8_t *)A0, PARAM1); +} + +void OPPROTO op_frstor_A0(void) +{ + helper_frstor((uint8_t *)A0, PARAM1); +} + /* threading support */ void OPPROTO op_lock(void) { @@ -2283,3 +2031,4 @@ void OPPROTO op_unlock(void) { cpu_unlock(); } +