/* * Copyright (C) 2002-2011 The DOSBox Team * * 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 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. * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // #define WEAK_EXCEPTIONS #if defined (_MSC_VER) #ifdef WEAK_EXCEPTIONS #define clx #else #define clx fclex #endif #ifdef WEAK_EXCEPTIONS #define FPUD_LOAD(op,szI,szA) \ __asm { \ __asm mov ebx, store_to \ __asm shl ebx, 4 \ __asm op szI PTR fpu.p_regs[128].m1 \ __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ } #else #define FPUD_LOAD(op,szI,szA) \ Bit16u new_sw; \ __asm { \ __asm mov eax, 8 \ __asm shl eax, 4 \ __asm mov ebx, store_to \ __asm shl ebx, 4 \ __asm fclex \ __asm op szI PTR fpu.p_regs[eax].m1 \ __asm fnstsw new_sw \ __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ } \ fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); #endif #ifdef WEAK_EXCEPTIONS #define FPUD_LOAD_EA(op,szI,szA) \ __asm { \ __asm op szI PTR fpu.p_regs[128].m1 \ } #else #define FPUD_LOAD_EA(op,szI,szA) \ Bit16u new_sw; \ __asm { \ __asm mov eax, 8 \ __asm shl eax, 4 \ __asm fclex \ __asm op szI PTR fpu.p_regs[eax].m1 \ __asm fnstsw new_sw \ } \ fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); #endif #ifdef WEAK_EXCEPTIONS #define FPUD_STORE(op,szI,szA) \ Bit16u save_cw; \ __asm { \ __asm fnstcw save_cw \ __asm mov eax, TOP \ __asm fldcw fpu.cw_mask_all \ __asm shl eax, 4 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm op szI PTR fpu.p_regs[128].m1 \ __asm fldcw save_cw \ } #else #define FPUD_STORE(op,szI,szA) \ Bit16u new_sw,save_cw; \ __asm { \ __asm fnstcw save_cw \ __asm fldcw fpu.cw_mask_all \ __asm mov eax, TOP \ __asm shl eax, 4 \ __asm mov ebx, 8 \ __asm shl ebx, 4 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm clx \ __asm op szI PTR fpu.p_regs[ebx].m1 \ __asm fnstsw new_sw \ __asm fldcw save_cw \ } \ fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); #endif // handles fsin,fcos,f2xm1,fchs,fabs #define FPUD_TRIG(op) \ Bit16u new_sw; \ __asm { \ __asm mov eax, TOP \ __asm shl eax, 4 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm clx \ __asm op \ __asm fnstsw new_sw \ __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ } \ fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); // handles fsincos #define FPUD_SINCOS() \ Bit16u new_sw; \ __asm { \ __asm mov eax, TOP \ __asm mov ebx, eax \ __asm dec ebx \ __asm and ebx, 7 \ __asm shl eax, 4 \ __asm shl ebx, 4 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm clx \ __asm fsincos \ __asm fnstsw new_sw \ __asm mov cx, new_sw \ __asm and ch, 0x04 \ __asm jnz argument_too_large1 \ __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ __asm jmp end_sincos \ __asm argument_too_large1: \ __asm fstp st(0) \ __asm end_sincos: \ } \ fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); \ if ((new_sw&0x0400)==0) FPU_PREP_PUSH(); // handles fptan #define FPUD_PTAN() \ Bit16u new_sw; \ __asm { \ __asm mov eax, TOP \ __asm mov ebx, eax \ __asm dec ebx \ __asm and ebx, 7 \ __asm shl eax, 4 \ __asm shl ebx, 4 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm clx \ __asm fptan \ __asm fnstsw new_sw \ __asm mov cx, new_sw \ __asm and ch, 0x04 \ __asm jnz argument_too_large2 \ __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ __asm jmp end_ptan \ __asm argument_too_large2: \ __asm fstp st(0) \ __asm end_ptan: \ } \ fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); \ if ((new_sw&0x0400)==0) FPU_PREP_PUSH(); // handles fxtract #ifdef WEAK_EXCEPTIONS #define FPUD_XTRACT \ __asm { \ __asm mov eax, TOP \ __asm mov ebx, eax \ __asm dec ebx \ __asm and ebx, 7 \ __asm shl eax, 4 \ __asm shl ebx, 4 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm fxtract \ __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ } \ FPU_PREP_PUSH(); #else #define FPUD_XTRACT \ Bit16u new_sw; \ __asm { \ __asm mov eax, TOP \ __asm mov ebx, eax \ __asm dec ebx \ __asm and ebx, 7 \ __asm shl eax, 4 \ __asm shl ebx, 4 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm fclex \ __asm fxtract \ __asm fnstsw new_sw \ __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ } \ fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); \ FPU_PREP_PUSH(); #endif // handles fadd,fmul,fsub,fsubr #ifdef WEAK_EXCEPTIONS #define FPUD_ARITH1(op) \ Bit16u save_cw; \ __asm { \ __asm fnstcw save_cw \ __asm mov eax, op1 \ __asm shl eax, 4 \ __asm fldcw fpu.cw_mask_all \ __asm mov ebx, op2 \ __asm shl ebx, 4 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ __asm op st(1), st(0) \ __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ __asm fldcw save_cw \ } #else #define FPUD_ARITH1(op) \ Bit16u new_sw,save_cw; \ __asm { \ __asm fnstcw save_cw \ __asm fldcw fpu.cw_mask_all \ __asm mov eax, op1 \ __asm shl eax, 4 \ __asm mov ebx, op2 \ __asm shl ebx, 4 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ __asm clx \ __asm op st(1), st(0) \ __asm fnstsw new_sw \ __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ __asm fldcw save_cw \ } \ fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); #endif // handles fadd,fmul,fsub,fsubr #ifdef WEAK_EXCEPTIONS #define FPUD_ARITH1_EA(op) \ Bit16u save_cw; \ __asm { \ __asm fnstcw save_cw \ __asm mov eax, op1 \ __asm fldcw fpu.cw_mask_all \ __asm shl eax, 4 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm fxch \ __asm op st(1), st(0) \ __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ __asm fldcw save_cw \ } #else #define FPUD_ARITH1_EA(op) \ Bit16u new_sw,save_cw; \ __asm { \ __asm fnstcw save_cw \ __asm fldcw fpu.cw_mask_all \ __asm mov eax, op1 \ __asm shl eax, 4 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm fxch \ __asm clx \ __asm op st(1), st(0) \ __asm fnstsw new_sw \ __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ __asm fldcw save_cw \ } \ fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); #endif // handles fsqrt,frndint #ifdef WEAK_EXCEPTIONS #define FPUD_ARITH2(op) \ Bit16u save_cw; \ __asm { \ __asm fnstcw save_cw \ __asm mov eax, TOP \ __asm fldcw fpu.cw_mask_all \ __asm shl eax, 4 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm op \ __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ __asm fldcw save_cw \ } #else #define FPUD_ARITH2(op) \ Bit16u new_sw,save_cw; \ __asm { \ __asm fnstcw save_cw \ __asm fldcw fpu.cw_mask_all \ __asm mov eax, TOP \ __asm shl eax, 4 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm clx \ __asm op \ __asm fnstsw new_sw \ __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ __asm fldcw save_cw \ } \ fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); #endif // handles fdiv,fdivr #ifdef WEAK_EXCEPTIONS #define FPUD_ARITH3(op) \ Bit16u save_cw; \ __asm { \ __asm fnstcw save_cw \ __asm mov eax, op1 \ __asm shl eax, 4 \ __asm fldcw fpu.cw_mask_all \ __asm mov ebx, op2 \ __asm shl ebx, 4 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ __asm op st(1), st(0) \ __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ __asm fldcw save_cw \ } #else #define FPUD_ARITH3(op) \ Bit16u new_sw,save_cw; \ __asm { \ __asm fnstcw save_cw \ __asm fldcw fpu.cw_mask_all \ __asm mov eax, op1 \ __asm shl eax, 4 \ __asm mov ebx, op2 \ __asm shl ebx, 4 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ __asm fclex \ __asm op st(1), st(0) \ __asm fnstsw new_sw \ __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ __asm fldcw save_cw \ } \ fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); #endif // handles fdiv,fdivr #ifdef WEAK_EXCEPTIONS #define FPUD_ARITH3_EA(op) \ Bit16u save_cw; \ __asm { \ __asm fnstcw save_cw \ __asm mov eax, op1 \ __asm fldcw fpu.cw_mask_all \ __asm shl eax, 4 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm fxch \ __asm op st(1), st(0) \ __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ __asm fldcw save_cw \ } #else #define FPUD_ARITH3_EA(op) \ Bit16u new_sw,save_cw; \ __asm { \ __asm fnstcw save_cw \ __asm mov eax, op1 \ __asm fldcw fpu.cw_mask_all \ __asm shl eax, 4 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm fxch \ __asm fclex \ __asm op st(1), st(0) \ __asm fnstsw new_sw \ __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ __asm fldcw save_cw \ } \ fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); #endif // handles fprem,fprem1,fscale #define FPUD_REMINDER(op) \ Bit16u new_sw; \ __asm { \ __asm mov eax, TOP \ __asm mov ebx, eax \ __asm inc ebx \ __asm and ebx, 7 \ __asm shl ebx, 4 \ __asm shl eax, 4 \ __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm fclex \ __asm op \ __asm fnstsw new_sw \ __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ __asm fstp st(0) \ } \ fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); // handles fcom,fucom #define FPUD_COMPARE(op) \ Bit16u new_sw; \ __asm { \ __asm mov ebx, op2 \ __asm mov eax, op1 \ __asm shl ebx, 4 \ __asm shl eax, 4 \ __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm clx \ __asm op \ __asm fnstsw new_sw \ } \ fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); #define FPUD_COMPARE_EA(op) \ Bit16u new_sw; \ __asm { \ __asm mov eax, op1 \ __asm shl eax, 4 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm clx \ __asm op \ __asm fnstsw new_sw \ } \ fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); // handles fxam,ftst #define FPUD_EXAMINE(op) \ Bit16u new_sw; \ __asm { \ __asm mov eax, TOP \ __asm shl eax, 4 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm clx \ __asm op \ __asm fnstsw new_sw \ __asm fstp st(0) \ } \ fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); // handles fpatan,fyl2xp1 #ifdef WEAK_EXCEPTIONS #define FPUD_WITH_POP(op) \ __asm { \ __asm mov eax, TOP \ __asm mov ebx, eax \ __asm inc ebx \ __asm and ebx, 7 \ __asm shl ebx, 4 \ __asm shl eax, 4 \ __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm op \ __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ } \ FPU_FPOP(); #else #define FPUD_WITH_POP(op) \ Bit16u new_sw; \ __asm { \ __asm mov eax, TOP \ __asm mov ebx, eax \ __asm inc ebx \ __asm and ebx, 7 \ __asm shl ebx, 4 \ __asm shl eax, 4 \ __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm fclex \ __asm op \ __asm fnstsw new_sw \ __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ } \ fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); \ FPU_FPOP(); #endif // handles fyl2x #ifdef WEAK_EXCEPTIONS #define FPUD_FYL2X(op) \ __asm { \ __asm mov eax, TOP \ __asm mov ebx, eax \ __asm inc ebx \ __asm and ebx, 7 \ __asm shl ebx, 4 \ __asm shl eax, 4 \ __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm op \ __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ } \ FPU_FPOP(); #else #define FPUD_FYL2X(op) \ Bit16u new_sw; \ __asm { \ __asm mov eax, TOP \ __asm mov ebx, eax \ __asm inc ebx \ __asm and ebx, 7 \ __asm shl ebx, 4 \ __asm shl eax, 4 \ __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ __asm fclex \ __asm op \ __asm fnstsw new_sw \ __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ } \ fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); \ FPU_FPOP(); #endif // load math constants #define FPUD_LOAD_CONST(op) \ FPU_PREP_PUSH(); \ __asm { \ __asm mov eax, TOP \ __asm shl eax, 4 \ __asm clx \ __asm op \ __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ } \ #else #ifdef WEAK_EXCEPTIONS #define clx #else #define clx "fclex" #endif #ifdef WEAK_EXCEPTIONS #define FPUD_LOAD(op,szI,szA) \ __asm__ volatile ( \ "movl $128, %%eax \n" \ "shl $4, %0 \n" \ #op #szA " (%1, %%eax) \n" \ "fstpt (%1, %0) " \ : \ : "r" (store_to), "r" (fpu.p_regs) \ : "eax", "memory" \ ); #else #define FPUD_LOAD(op,szI,szA) \ Bit16u new_sw; \ __asm__ volatile ( \ "movl $8, %%eax \n" \ "shl $4, %%eax \n" \ "shl $4, %1 \n" \ "fclex \n" \ #op #szA " (%2, %%eax) \n" \ "fnstsw %0 \n" \ "fstpt (%2, %1) " \ : "=m" (new_sw) \ : "r" (store_to), "r" (fpu.p_regs) \ : "eax", "memory" \ ); \ fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); #endif #ifdef WEAK_EXCEPTIONS #define FPUD_LOAD_EA(op,szI,szA) \ __asm__ volatile ( \ "movl $128, %%eax \n" \ #op #szA " (%0, %%eax) \n" \ : \ : "r" (fpu.p_regs) \ : "eax", "memory" \ ); #else #define FPUD_LOAD_EA(op,szI,szA) \ Bit16u new_sw; \ __asm__ volatile ( \ "movl $8, %%eax \n" \ "shl $4, %%eax \n" \ "fclex \n" \ #op #szA " (%1, %%eax) \n" \ "fnstsw %0 \n" \ : "=m" (new_sw) \ : "r" (fpu.p_regs) \ : "eax", "memory" \ ); \ fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); #endif #ifdef WEAK_EXCEPTIONS #define FPUD_STORE(op,szI,szA) \ Bit16u save_cw; \ __asm__ volatile ( \ "fnstcw %0 \n" \ "shll $4, %1 \n" \ "fldcw %3 \n" \ "movl $128, %%eax \n" \ "fldt (%2, %1) \n" \ #op #szA " (%2, %%eax) \n" \ "fldcw %0 " \ : "=m" (save_cw) \ : "r" (TOP), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ : "eax", "memory" \ ); #else #define FPUD_STORE(op,szI,szA) \ Bit16u new_sw,save_cw; \ __asm__ volatile ( \ "fnstcw %1 \n" \ "fldcw %4 \n" \ "shll $4, %2 \n" \ "movl $8, %%eax \n" \ "shl $4, %%eax \n" \ "fldt (%3, %2) \n" \ clx" \n" \ #op #szA " (%3, %%eax) \n" \ "fnstsw %0 \n" \ "fldcw %1 " \ : "=m" (new_sw), "=m" (save_cw) \ : "r" (TOP), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ : "eax", "memory" \ ); \ fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); #endif // handles fsin,fcos,f2xm1,fchs,fabs #define FPUD_TRIG(op) \ Bit16u new_sw; \ __asm__ volatile ( \ "shll $4, %1 \n" \ "fldt (%2, %1) \n" \ clx" \n" \ #op" \n" \ "fnstsw %0 \n" \ "fstpt (%2, %1) " \ : "=m" (new_sw) \ : "r" (TOP), "r" (fpu.p_regs) \ : "memory" \ ); \ fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); // handles fsincos #define FPUD_SINCOS() \ Bit16u new_sw; \ __asm__ volatile ( \ "movl %1, %%eax \n" \ "shll $4, %1 \n" \ "decl %%eax \n" \ "andl $7, %%eax \n" \ "shll $4, %%eax \n" \ "fldt (%2, %1) \n" \ clx" \n" \ "fsincos \n" \ "fnstsw %0 \n" \ "fstpt (%2, %%eax) \n" \ "movw %0, %%ax \n" \ "sahf \n" \ "jp argument_too_large1 \n" \ "fstpt (%2, %1) \n" \ "argument_too_large1: " \ : "=m" (new_sw) \ : "r" (TOP), "r" (fpu.p_regs) \ : "eax", "cc", "memory" \ ); \ fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); \ if ((new_sw&0x0400)==0) FPU_PREP_PUSH(); // handles fptan #define FPUD_PTAN() \ Bit16u new_sw; \ __asm__ volatile ( \ "movl %1, %%eax \n" \ "shll $4, %1 \n" \ "decl %%eax \n" \ "andl $7, %%eax \n" \ "shll $4, %%eax \n" \ "fldt (%2, %1) \n" \ clx" \n" \ "fptan \n" \ "fnstsw %0 \n" \ "fstpt (%2, %%eax) \n" \ "movw %0, %%ax \n" \ "sahf \n" \ "jp argument_too_large2 \n" \ "fstpt (%2, %1) \n" \ "argument_too_large2: " \ : "=m" (new_sw) \ : "r" (TOP), "r" (fpu.p_regs) \ : "eax", "cc", "memory" \ ); \ fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); \ if ((new_sw&0x0400)==0) FPU_PREP_PUSH(); // handles fxtract #ifdef WEAK_EXCEPTIONS #define FPUD_XTRACT \ __asm__ volatile ( \ "movl %0, %%eax \n" \ "shll $4, %0 \n" \ "decl %%eax \n" \ "andl $7, %%eax \n" \ "shll $4, %%eax \n" \ "fldt (%1, %0) \n" \ "fxtract \n" \ "fstpt (%1, %%eax) \n" \ "fstpt (%1, %0) " \ : \ : "r" (TOP), "r" (fpu.p_regs) \ : "eax", "memory" \ ); \ FPU_PREP_PUSH(); #else #define FPUD_XTRACT \ Bit16u new_sw; \ __asm__ volatile ( \ "movl %1, %%eax \n" \ "shll $4, %1 \n" \ "decl %%eax \n" \ "andl $7, %%eax \n" \ "shll $4, %%eax \n" \ "fldt (%2, %1) \n" \ "fclex \n" \ "fxtract \n" \ "fnstsw %0 \n" \ "fstpt (%2, %%eax) \n" \ "fstpt (%2, %1) " \ : "=m" (new_sw) \ : "r" (TOP), "r" (fpu.p_regs) \ : "eax", "memory" \ ); \ fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); \ FPU_PREP_PUSH(); #endif // handles fadd,fmul,fsub,fsubr #ifdef WEAK_EXCEPTIONS #define FPUD_ARITH1(op) \ Bit16u save_cw; \ __asm__ volatile ( \ "fnstcw %0 \n" \ "fldcw %4 \n" \ "shll $4, %2 \n" \ "shll $4, %1 \n" \ "fldt (%3, %2) \n" \ "fldt (%3, %1) \n" \ #op" \n" \ "fstpt (%3, %1) \n" \ "fldcw %0 " \ : "=m" (save_cw) \ : "r" (op1), "r" (op2), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ : "memory" \ ); #else #define FPUD_ARITH1(op) \ Bit16u new_sw,save_cw; \ __asm__ volatile ( \ "fnstcw %1 \n" \ "fldcw %5 \n" \ "shll $4, %3 \n" \ "shll $4, %2 \n" \ "fldt (%4, %3) \n" \ "fldt (%4, %2) \n" \ clx" \n" \ #op" \n" \ "fnstsw %0 \n" \ "fstpt (%4, %2) \n" \ "fldcw %1 " \ : "=m" (new_sw), "=m" (save_cw) \ : "r" (op1), "r" (op2), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ : "memory" \ ); \ fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); #endif // handles fadd,fmul,fsub,fsubr #ifdef WEAK_EXCEPTIONS #define FPUD_ARITH1_EA(op) \ Bit16u save_cw; \ __asm__ volatile ( \ "fnstcw %0 \n" \ "fldcw %3 \n" \ "shll $4, %1 \n" \ "fldt (%2, %1) \n" \ #op" \n" \ "fstpt (%2, %1) \n" \ "fldcw %0 " \ : "=m" (save_cw) \ : "r" (op1), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ : "memory" \ ); #else #define FPUD_ARITH1_EA(op) \ Bit16u new_sw,save_cw; \ __asm__ volatile ( \ "fnstcw %1 \n" \ "fldcw %4 \n" \ "shll $4, %2 \n" \ "fldt (%3, %2) \n" \ clx" \n" \ #op" \n" \ "fnstsw %0 \n" \ "fstpt (%3, %2) \n" \ "fldcw %1 " \ : "=m" (new_sw), "=m" (save_cw) \ : "r" (op1), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ : "memory" \ ); \ fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); #endif // handles fsqrt,frndint #ifdef WEAK_EXCEPTIONS #define FPUD_ARITH2(op) \ Bit16u save_cw; \ __asm__ volatile ( \ "fnstcw %0 \n" \ "fldcw %3 \n" \ "shll $4, %1 \n" \ "fldt (%2, %1) \n" \ #op" \n" \ "fstpt (%2, %1) \n" \ "fldcw %0 " \ : "=m" (save_cw) \ : "r" (TOP), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ : "memory" \ ); #else #define FPUD_ARITH2(op) \ Bit16u new_sw,save_cw; \ __asm__ volatile ( \ "fnstcw %1 \n" \ "fldcw %4 \n" \ "shll $4, %2 \n" \ "fldt (%3, %2) \n" \ clx" \n" \ #op" \n" \ "fnstsw %0 \n" \ "fstpt (%3, %2) \n" \ "fldcw %1 " \ : "=m" (new_sw), "=m" (save_cw) \ : "r" (TOP), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ : "memory" \ ); \ fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); #endif // handles fdiv,fdivr #ifdef WEAK_EXCEPTIONS #define FPUD_ARITH3(op) \ Bit16u save_cw; \ __asm__ volatile ( \ "fnstcw %0 \n" \ "fldcw %4 \n" \ "shll $4, %2 \n" \ "shll $4, %1 \n" \ "fldt (%3, %2) \n" \ "fldt (%3, %1) \n" \ #op" \n" \ "fstpt (%3, %1) \n" \ "fldcw %0 " \ : "=m" (save_cw) \ : "r" (op1), "r" (op2), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ : "memory" \ ); #else #define FPUD_ARITH3(op) \ Bit16u new_sw,save_cw; \ __asm__ volatile ( \ "fnstcw %1 \n" \ "fldcw %5 \n" \ "shll $4, %3 \n" \ "shll $4, %2 \n" \ "fldt (%4, %3) \n" \ "fldt (%4, %2) \n" \ "fclex \n" \ #op" \n" \ "fnstsw %0 \n" \ "fstpt (%4, %2) \n" \ "fldcw %1 " \ : "=m" (new_sw), "=m" (save_cw) \ : "r" (op1), "r" (op2), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ : "memory" \ ); \ fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); #endif // handles fdiv,fdivr #ifdef WEAK_EXCEPTIONS #define FPUD_ARITH3_EA(op) \ Bit16u save_cw; \ __asm__ volatile ( \ "fnstcw %0 \n" \ "fldcw %3 \n" \ "shll $4, %1 \n" \ "fldt (%2, %1) \n" \ #op" \n" \ "fstpt (%2, %1) \n" \ "fldcw %0 " \ : "=m" (save_cw) \ : "r" (op1), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ : "memory" \ ); #else #define FPUD_ARITH3_EA(op) \ Bit16u new_sw,save_cw; \ __asm__ volatile ( \ "fnstcw %1 \n" \ "fldcw %4 \n" \ "shll $4, %2 \n" \ "fldt (%3, %2) \n" \ "fclex \n" \ #op" \n" \ "fnstsw %0 \n" \ "fstpt (%3, %2) \n" \ "fldcw %1 " \ : "=m" (new_sw), "=m" (save_cw) \ : "r" (op1), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ : "memory" \ ); \ fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); #endif // handles fprem,fprem1,fscale #define FPUD_REMINDER(op) \ Bit16u new_sw; \ __asm__ volatile ( \ "movl %1, %%eax \n" \ "incl %%eax \n" \ "andl $7, %%eax \n" \ "shll $4, %%eax \n" \ "shll $4, %1 \n" \ "fldt (%2, %%eax) \n" \ "fldt (%2, %1) \n" \ "fclex \n" \ #op" \n" \ "fnstsw %0 \n" \ "fstpt (%2, %1) \n" \ "fstp %%st(0) " \ : "=m" (new_sw) \ : "r" (TOP), "r" (fpu.p_regs) \ : "eax", "memory" \ ); \ fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); // handles fcom,fucom #define FPUD_COMPARE(op) \ Bit16u new_sw; \ __asm__ volatile ( \ "shll $4, %2 \n" \ "shll $4, %1 \n" \ "fldt (%3, %2) \n" \ "fldt (%3, %1) \n" \ clx" \n" \ #op" \n" \ "fnstsw %0 " \ : "=m" (new_sw) \ : "r" (op1), "r" (op2), "r" (fpu.p_regs) \ : "memory" \ ); \ fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); // handles fcom,fucom #define FPUD_COMPARE_EA(op) \ Bit16u new_sw; \ __asm__ volatile ( \ "shll $4, %1 \n" \ "fldt (%2, %1) \n" \ clx" \n" \ #op" \n" \ "fnstsw %0 " \ : "=m" (new_sw) \ : "r" (op1), "r" (fpu.p_regs) \ : "memory" \ ); \ fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); // handles fxam,ftst #define FPUD_EXAMINE(op) \ Bit16u new_sw; \ __asm__ volatile ( \ "shll $4, %1 \n" \ "fldt (%2, %1) \n" \ clx" \n" \ #op" \n" \ "fnstsw %0 \n" \ "fstp %%st(0) " \ : "=m" (new_sw) \ : "r" (TOP), "r" (fpu.p_regs) \ : "memory" \ ); \ fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); // handles fpatan,fyl2xp1 #ifdef WEAK_EXCEPTIONS #define FPUD_WITH_POP(op) \ __asm__ volatile ( \ "movl %0, %%eax \n" \ "incl %%eax \n" \ "andl $7, %%eax \n" \ "shll $4, %%eax \n" \ "shll $4, %0 \n" \ "fldt (%1, %%eax) \n" \ "fldt (%1, %0) \n" \ #op" \n" \ "fstpt (%1, %%eax) \n" \ : \ : "r" (TOP), "r" (fpu.p_regs) \ : "eax", "memory" \ ); \ FPU_FPOP(); #else #define FPUD_WITH_POP(op) \ Bit16u new_sw; \ __asm__ volatile ( \ "movl %1, %%eax \n" \ "incl %%eax \n" \ "andl $7, %%eax \n" \ "shll $4, %%eax \n" \ "shll $4, %1 \n" \ "fldt (%2, %%eax) \n" \ "fldt (%2, %1) \n" \ "fclex \n" \ #op" \n" \ "fnstsw %0 \n" \ "fstpt (%2, %%eax) \n" \ : "=m" (new_sw) \ : "r" (TOP), "r" (fpu.p_regs) \ : "eax", "memory" \ ); \ fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); \ FPU_FPOP(); #endif // handles fyl2x #ifdef WEAK_EXCEPTIONS #define FPUD_FYL2X(op) \ __asm__ volatile ( \ "movl %0, %%eax \n" \ "incl %%eax \n" \ "andl $7, %%eax \n" \ "shll $4, %%eax \n" \ "shll $4, %0 \n" \ "fldt (%1, %%eax) \n" \ "fldt (%1, %0) \n" \ #op" \n" \ "fstpt (%1, %%eax) \n" \ : \ : "r" (TOP), "r" (fpu.p_regs) \ : "eax", "memory" \ ); \ FPU_FPOP(); #else #define FPUD_FYL2X(op) \ Bit16u new_sw; \ __asm__ volatile ( \ "movl %1, %%eax \n" \ "incl %%eax \n" \ "andl $7, %%eax \n" \ "shll $4, %%eax \n" \ "shll $4, %1 \n" \ "fldt (%2, %%eax) \n" \ "fldt (%2, %1) \n" \ "fclex \n" \ #op" \n" \ "fnstsw %0 \n" \ "fstpt (%2, %%eax) \n" \ : "=m" (new_sw) \ : "r" (TOP), "r" (fpu.p_regs) \ : "eax", "memory" \ ); \ fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); \ FPU_FPOP(); #endif // load math constants #define FPUD_LOAD_CONST(op) \ FPU_PREP_PUSH(); \ __asm__ volatile ( \ "shll $4, %0 \n" \ clx" \n" \ #op" \n" \ "fstpt (%1, %0) \n" \ : \ : "r" (TOP), "r" (fpu.p_regs) \ : "memory" \ ); #endif #ifdef WEAK_EXCEPTIONS const Bit16u exc_mask=0x7f00; #else const Bit16u exc_mask=0xffbf; #endif static void FPU_FINIT(void) { FPU_SetCW(0x37F); fpu.sw=0; TOP=FPU_GET_TOP(); fpu.tags[0]=TAG_Empty; fpu.tags[1]=TAG_Empty; fpu.tags[2]=TAG_Empty; fpu.tags[3]=TAG_Empty; fpu.tags[4]=TAG_Empty; fpu.tags[5]=TAG_Empty; fpu.tags[6]=TAG_Empty; fpu.tags[7]=TAG_Empty; fpu.tags[8]=TAG_Valid; // is only used by us } static void FPU_FCLEX(void){ fpu.sw&=0x7f00; //should clear exceptions } static void FPU_FNOP(void){ } static void FPU_PREP_PUSH(void){ TOP = (TOP - 1) &7; fpu.tags[TOP]=TAG_Valid; } static void FPU_FPOP(void){ fpu.tags[TOP]=TAG_Empty; TOP = ((TOP+1)&7); } static void FPU_FLD_F32(PhysPt addr,Bitu store_to) { fpu.p_regs[8].m1 = mem_readd(addr); FPUD_LOAD(fld,DWORD,s) } static void FPU_FLD_F32_EA(PhysPt addr) { fpu.p_regs[8].m1 = mem_readd(addr); FPUD_LOAD_EA(fld,DWORD,s) } static void FPU_FLD_F64(PhysPt addr,Bitu store_to) { fpu.p_regs[8].m1 = mem_readd(addr); fpu.p_regs[8].m2 = mem_readd(addr+4); FPUD_LOAD(fld,QWORD,l) } static void FPU_FLD_F64_EA(PhysPt addr) { fpu.p_regs[8].m1 = mem_readd(addr); fpu.p_regs[8].m2 = mem_readd(addr+4); FPUD_LOAD_EA(fld,QWORD,l) } static void FPU_FLD_F80(PhysPt addr) { fpu.p_regs[TOP].m1 = mem_readd(addr); fpu.p_regs[TOP].m2 = mem_readd(addr+4); fpu.p_regs[TOP].m3 = mem_readw(addr+8); FPU_SET_C1(0); } static void FPU_FLD_I16(PhysPt addr,Bitu store_to) { fpu.p_regs[8].m1 = (Bit32u)mem_readw(addr); FPUD_LOAD(fild,WORD,) } static void FPU_FLD_I16_EA(PhysPt addr) { fpu.p_regs[8].m1 = (Bit32u)mem_readw(addr); FPUD_LOAD_EA(fild,WORD,) } static void FPU_FLD_I32(PhysPt addr,Bitu store_to) { fpu.p_regs[8].m1 = mem_readd(addr); FPUD_LOAD(fild,DWORD,l) } static void FPU_FLD_I32_EA(PhysPt addr) { fpu.p_regs[8].m1 = mem_readd(addr); FPUD_LOAD_EA(fild,DWORD,l) } static void FPU_FLD_I64(PhysPt addr,Bitu store_to) { fpu.p_regs[8].m1 = mem_readd(addr); fpu.p_regs[8].m2 = mem_readd(addr+4); FPUD_LOAD(fild,QWORD,q) } static void FPU_FBLD(PhysPt addr,Bitu store_to) { fpu.p_regs[8].m1 = mem_readd(addr); fpu.p_regs[8].m2 = mem_readd(addr+4); fpu.p_regs[8].m3 = mem_readw(addr+8); FPUD_LOAD(fbld,TBYTE,) } static void FPU_FST_F32(PhysPt addr) { FPUD_STORE(fstp,DWORD,s) mem_writed(addr,fpu.p_regs[8].m1); } static void FPU_FST_F64(PhysPt addr) { FPUD_STORE(fstp,QWORD,l) mem_writed(addr,fpu.p_regs[8].m1); mem_writed(addr+4,fpu.p_regs[8].m2); } static void FPU_FST_F80(PhysPt addr) { mem_writed(addr,fpu.p_regs[TOP].m1); mem_writed(addr+4,fpu.p_regs[TOP].m2); mem_writew(addr+8,fpu.p_regs[TOP].m3); FPU_SET_C1(0); } static void FPU_FST_I16(PhysPt addr) { FPUD_STORE(fistp,WORD,) mem_writew(addr,(Bit16u)fpu.p_regs[8].m1); } static void FPU_FST_I32(PhysPt addr) { FPUD_STORE(fistp,DWORD,l) mem_writed(addr,fpu.p_regs[8].m1); } static void FPU_FST_I64(PhysPt addr) { FPUD_STORE(fistp,QWORD,q) mem_writed(addr,fpu.p_regs[8].m1); mem_writed(addr+4,fpu.p_regs[8].m2); } static void FPU_FBST(PhysPt addr) { FPUD_STORE(fbstp,TBYTE,) mem_writed(addr,fpu.p_regs[8].m1); mem_writed(addr+4,fpu.p_regs[8].m2); mem_writew(addr+8,fpu.p_regs[8].m3); } static void FPU_FSIN(void){ FPUD_TRIG(fsin) } static void FPU_FSINCOS(void){ FPUD_SINCOS() } static void FPU_FCOS(void){ FPUD_TRIG(fcos) } static void FPU_FSQRT(void){ FPUD_ARITH2(fsqrt) } static void FPU_FPATAN(void){ FPUD_WITH_POP(fpatan) } static void FPU_FPTAN(void){ FPUD_PTAN() } static void FPU_FADD(Bitu op1, Bitu op2){ FPUD_ARITH1(faddp) } static void FPU_FADD_EA(Bitu op1){ FPUD_ARITH1_EA(faddp) } static void FPU_FDIV(Bitu op1, Bitu op2){ FPUD_ARITH3(fdivp) } static void FPU_FDIV_EA(Bitu op1){ FPUD_ARITH3_EA(fdivp) } static void FPU_FDIVR(Bitu op1, Bitu op2){ FPUD_ARITH3(fdivrp) } static void FPU_FDIVR_EA(Bitu op1){ FPUD_ARITH3_EA(fdivrp) } static void FPU_FMUL(Bitu op1, Bitu op2){ FPUD_ARITH1(fmulp) } static void FPU_FMUL_EA(Bitu op1){ FPUD_ARITH1_EA(fmulp) } static void FPU_FSUB(Bitu op1, Bitu op2){ FPUD_ARITH1(fsubp) } static void FPU_FSUB_EA(Bitu op1){ FPUD_ARITH1_EA(fsubp) } static void FPU_FSUBR(Bitu op1, Bitu op2){ FPUD_ARITH1(fsubrp) } static void FPU_FSUBR_EA(Bitu op1){ FPUD_ARITH1_EA(fsubrp) } static void FPU_FXCH(Bitu stv, Bitu other){ FPU_Tag tag = fpu.tags[other]; fpu.tags[other] = fpu.tags[stv]; fpu.tags[stv] = tag; Bit32u m1s = fpu.p_regs[other].m1; Bit32u m2s = fpu.p_regs[other].m2; Bit16u m3s = fpu.p_regs[other].m3; fpu.p_regs[other].m1 = fpu.p_regs[stv].m1; fpu.p_regs[other].m2 = fpu.p_regs[stv].m2; fpu.p_regs[other].m3 = fpu.p_regs[stv].m3; fpu.p_regs[stv].m1 = m1s; fpu.p_regs[stv].m2 = m2s; fpu.p_regs[stv].m3 = m3s; FPU_SET_C1(0); } static void FPU_FST(Bitu stv, Bitu other){ fpu.tags[other] = fpu.tags[stv]; fpu.p_regs[other].m1 = fpu.p_regs[stv].m1; fpu.p_regs[other].m2 = fpu.p_regs[stv].m2; fpu.p_regs[other].m3 = fpu.p_regs[stv].m3; FPU_SET_C1(0); } static void FPU_FCOM(Bitu op1, Bitu op2){ FPUD_COMPARE(fcompp) } static void FPU_FCOM_EA(Bitu op1){ FPUD_COMPARE_EA(fcompp) } static void FPU_FUCOM(Bitu op1, Bitu op2){ FPUD_COMPARE(fucompp) } static void FPU_FRNDINT(void){ FPUD_ARITH2(frndint) } static void FPU_FPREM(void){ FPUD_REMINDER(fprem) } static void FPU_FPREM1(void){ FPUD_REMINDER(fprem1) } static void FPU_FXAM(void){ FPUD_EXAMINE(fxam) // handle empty registers (C1 set to sign in any way!) if(fpu.tags[TOP] == TAG_Empty) { FPU_SET_C3(1);FPU_SET_C2(0);FPU_SET_C0(1); return; } } static void FPU_F2XM1(void){ FPUD_TRIG(f2xm1) } static void FPU_FYL2X(void){ FPUD_FYL2X(fyl2x) } static void FPU_FYL2XP1(void){ FPUD_WITH_POP(fyl2xp1) } static void FPU_FSCALE(void){ FPUD_REMINDER(fscale) } static void FPU_FSTENV(PhysPt addr){ FPU_SET_TOP(TOP); if(!cpu.code.big) { mem_writew(addr+0,static_cast(fpu.cw)); mem_writew(addr+2,static_cast(fpu.sw)); mem_writew(addr+4,static_cast(FPU_GetTag())); } else { mem_writed(addr+0,static_cast(fpu.cw)); mem_writed(addr+4,static_cast(fpu.sw)); mem_writed(addr+8,static_cast(FPU_GetTag())); } } static void FPU_FLDENV(PhysPt addr){ Bit16u tag; Bit32u tagbig; Bitu cw; if(!cpu.code.big) { cw = mem_readw(addr+0); fpu.sw = mem_readw(addr+2); tag = mem_readw(addr+4); } else { cw = mem_readd(addr+0); fpu.sw = (Bit16u)mem_readd(addr+4); tagbig = mem_readd(addr+8); tag = static_cast(tagbig); } FPU_SetTag(tag); FPU_SetCW(cw); TOP=FPU_GET_TOP(); } static void FPU_FSAVE(PhysPt addr){ FPU_FSTENV(addr); Bitu start=(cpu.code.big?28:14); for(Bitu i=0;i<8;i++){ mem_writed(addr+start,fpu.p_regs[STV(i)].m1); mem_writed(addr+start+4,fpu.p_regs[STV(i)].m2); mem_writew(addr+start+8,fpu.p_regs[STV(i)].m3); start+=10; } FPU_FINIT(); } static void FPU_FRSTOR(PhysPt addr){ FPU_FLDENV(addr); Bitu start=(cpu.code.big?28:14); for(Bitu i=0;i<8;i++){ fpu.p_regs[STV(i)].m1 = mem_readd(addr+start); fpu.p_regs[STV(i)].m2 = mem_readd(addr+start+4); fpu.p_regs[STV(i)].m3 = mem_readw(addr+start+8); start+=10; } } static void FPU_FXTRACT(void) { FPUD_XTRACT } static void FPU_FCHS(void){ FPUD_TRIG(fchs) } static void FPU_FABS(void){ FPUD_TRIG(fabs) } static void FPU_FTST(void){ FPUD_EXAMINE(ftst) } static void FPU_FLD1(void){ FPUD_LOAD_CONST(fld1) } static void FPU_FLDL2T(void){ FPUD_LOAD_CONST(fldl2t) } static void FPU_FLDL2E(void){ FPUD_LOAD_CONST(fldl2e) } static void FPU_FLDPI(void){ FPUD_LOAD_CONST(fldpi) } static void FPU_FLDLG2(void){ FPUD_LOAD_CONST(fldlg2) } static void FPU_FLDLN2(void){ FPUD_LOAD_CONST(fldln2) } static void FPU_FLDZ(void){ FPUD_LOAD_CONST(fldz) fpu.tags[TOP]=TAG_Zero; }