x86: lindent arch/i386/math-emu
lindent these files: errors lines of code errors/KLOC arch/x86/math-emu/ 2236 9424 237.2 arch/x86/math-emu/ 128 8706 14.7 no other changes. No code changed: text data bss dec hex filename5589802
612739 3833856 10036397 9924ad vmlinux.before5589802
612739 3833856 10036397 9924ad vmlinux.after the intent of this patch is to ease the automated tracking of kernel code quality - it's just much easier for us to maintain it if every file in arch/x86 is supposed to be clean. NOTE: it is a known problem of lindent that it causes some style damage of its own, but it's a safe tool (well, except for the gcc array range initializers extension), so we did the bulk of the changes via lindent, and did the manual fixups in a followup patch. the resulting math-emu code has been tested by Thomas Gleixner on a real 386 DX CPU as well, and it works fine. Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,6 @@
|
|||||||
#ifndef _EXCEPTION_H_
|
#ifndef _EXCEPTION_H_
|
||||||
#define _EXCEPTION_H_
|
#define _EXCEPTION_H_
|
||||||
|
|
||||||
|
|
||||||
#ifdef __ASSEMBLY__
|
#ifdef __ASSEMBLY__
|
||||||
#define Const_(x) $##x
|
#define Const_(x) $##x
|
||||||
#else
|
#else
|
||||||
@@ -20,8 +19,8 @@
|
|||||||
#include "fpu_emu.h"
|
#include "fpu_emu.h"
|
||||||
#endif /* SW_C1 */
|
#endif /* SW_C1 */
|
||||||
|
|
||||||
#define FPU_BUSY Const_(0x8000) /* FPU busy bit (8087 compatibility) */
|
#define FPU_BUSY Const_(0x8000) /* FPU busy bit (8087 compatibility) */
|
||||||
#define EX_ErrorSummary Const_(0x0080) /* Error summary status */
|
#define EX_ErrorSummary Const_(0x0080) /* Error summary status */
|
||||||
/* Special exceptions: */
|
/* Special exceptions: */
|
||||||
#define EX_INTERNAL Const_(0x8000) /* Internal error in wm-FPU-emu */
|
#define EX_INTERNAL Const_(0x8000) /* Internal error in wm-FPU-emu */
|
||||||
#define EX_StackOver Const_(0x0041|SW_C1) /* stack overflow */
|
#define EX_StackOver Const_(0x0041|SW_C1) /* stack overflow */
|
||||||
@@ -34,11 +33,9 @@
|
|||||||
#define EX_Denormal Const_(0x0002) /* denormalized operand */
|
#define EX_Denormal Const_(0x0002) /* denormalized operand */
|
||||||
#define EX_Invalid Const_(0x0001) /* invalid operation */
|
#define EX_Invalid Const_(0x0001) /* invalid operation */
|
||||||
|
|
||||||
|
|
||||||
#define PRECISION_LOST_UP Const_((EX_Precision | SW_C1))
|
#define PRECISION_LOST_UP Const_((EX_Precision | SW_C1))
|
||||||
#define PRECISION_LOST_DOWN Const_(EX_Precision)
|
#define PRECISION_LOST_DOWN Const_(EX_Precision)
|
||||||
|
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
@@ -48,6 +45,6 @@
|
|||||||
#define EXCEPTION(x) FPU_exception(x)
|
#define EXCEPTION(x) FPU_exception(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __ASSEMBLY__ */
|
#endif /* __ASSEMBLY__ */
|
||||||
|
|
||||||
#endif /* _EXCEPTION_H_ */
|
#endif /* _EXCEPTION_H_ */
|
||||||
|
@@ -15,160 +15,138 @@
|
|||||||
#include "control_w.h"
|
#include "control_w.h"
|
||||||
#include "status_w.h"
|
#include "status_w.h"
|
||||||
|
|
||||||
|
|
||||||
void fadd__(void)
|
void fadd__(void)
|
||||||
{
|
{
|
||||||
/* fadd st,st(i) */
|
/* fadd st,st(i) */
|
||||||
int i = FPU_rm;
|
int i = FPU_rm;
|
||||||
clear_C1();
|
clear_C1();
|
||||||
FPU_add(&st(i), FPU_gettagi(i), 0, control_word);
|
FPU_add(&st(i), FPU_gettagi(i), 0, control_word);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fmul__(void)
|
void fmul__(void)
|
||||||
{
|
{
|
||||||
/* fmul st,st(i) */
|
/* fmul st,st(i) */
|
||||||
int i = FPU_rm;
|
int i = FPU_rm;
|
||||||
clear_C1();
|
clear_C1();
|
||||||
FPU_mul(&st(i), FPU_gettagi(i), 0, control_word);
|
FPU_mul(&st(i), FPU_gettagi(i), 0, control_word);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void fsub__(void)
|
void fsub__(void)
|
||||||
{
|
{
|
||||||
/* fsub st,st(i) */
|
/* fsub st,st(i) */
|
||||||
clear_C1();
|
clear_C1();
|
||||||
FPU_sub(0, FPU_rm, control_word);
|
FPU_sub(0, FPU_rm, control_word);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fsubr_(void)
|
void fsubr_(void)
|
||||||
{
|
{
|
||||||
/* fsubr st,st(i) */
|
/* fsubr st,st(i) */
|
||||||
clear_C1();
|
clear_C1();
|
||||||
FPU_sub(REV, FPU_rm, control_word);
|
FPU_sub(REV, FPU_rm, control_word);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fdiv__(void)
|
void fdiv__(void)
|
||||||
{
|
{
|
||||||
/* fdiv st,st(i) */
|
/* fdiv st,st(i) */
|
||||||
clear_C1();
|
clear_C1();
|
||||||
FPU_div(0, FPU_rm, control_word);
|
FPU_div(0, FPU_rm, control_word);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fdivr_(void)
|
void fdivr_(void)
|
||||||
{
|
{
|
||||||
/* fdivr st,st(i) */
|
/* fdivr st,st(i) */
|
||||||
clear_C1();
|
clear_C1();
|
||||||
FPU_div(REV, FPU_rm, control_word);
|
FPU_div(REV, FPU_rm, control_word);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void fadd_i(void)
|
void fadd_i(void)
|
||||||
{
|
{
|
||||||
/* fadd st(i),st */
|
/* fadd st(i),st */
|
||||||
int i = FPU_rm;
|
int i = FPU_rm;
|
||||||
clear_C1();
|
clear_C1();
|
||||||
FPU_add(&st(i), FPU_gettagi(i), i, control_word);
|
FPU_add(&st(i), FPU_gettagi(i), i, control_word);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fmul_i(void)
|
void fmul_i(void)
|
||||||
{
|
{
|
||||||
/* fmul st(i),st */
|
/* fmul st(i),st */
|
||||||
clear_C1();
|
clear_C1();
|
||||||
FPU_mul(&st(0), FPU_gettag0(), FPU_rm, control_word);
|
FPU_mul(&st(0), FPU_gettag0(), FPU_rm, control_word);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fsubri(void)
|
void fsubri(void)
|
||||||
{
|
{
|
||||||
/* fsubr st(i),st */
|
/* fsubr st(i),st */
|
||||||
clear_C1();
|
clear_C1();
|
||||||
FPU_sub(DEST_RM, FPU_rm, control_word);
|
FPU_sub(DEST_RM, FPU_rm, control_word);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fsub_i(void)
|
void fsub_i(void)
|
||||||
{
|
{
|
||||||
/* fsub st(i),st */
|
/* fsub st(i),st */
|
||||||
clear_C1();
|
clear_C1();
|
||||||
FPU_sub(REV|DEST_RM, FPU_rm, control_word);
|
FPU_sub(REV | DEST_RM, FPU_rm, control_word);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fdivri(void)
|
void fdivri(void)
|
||||||
{
|
{
|
||||||
/* fdivr st(i),st */
|
/* fdivr st(i),st */
|
||||||
clear_C1();
|
clear_C1();
|
||||||
FPU_div(DEST_RM, FPU_rm, control_word);
|
FPU_div(DEST_RM, FPU_rm, control_word);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fdiv_i(void)
|
void fdiv_i(void)
|
||||||
{
|
{
|
||||||
/* fdiv st(i),st */
|
/* fdiv st(i),st */
|
||||||
clear_C1();
|
clear_C1();
|
||||||
FPU_div(REV|DEST_RM, FPU_rm, control_word);
|
FPU_div(REV | DEST_RM, FPU_rm, control_word);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void faddp_(void)
|
void faddp_(void)
|
||||||
{
|
{
|
||||||
/* faddp st(i),st */
|
/* faddp st(i),st */
|
||||||
int i = FPU_rm;
|
int i = FPU_rm;
|
||||||
clear_C1();
|
clear_C1();
|
||||||
if ( FPU_add(&st(i), FPU_gettagi(i), i, control_word) >= 0 )
|
if (FPU_add(&st(i), FPU_gettagi(i), i, control_word) >= 0)
|
||||||
FPU_pop();
|
FPU_pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fmulp_(void)
|
void fmulp_(void)
|
||||||
{
|
{
|
||||||
/* fmulp st(i),st */
|
/* fmulp st(i),st */
|
||||||
clear_C1();
|
clear_C1();
|
||||||
if ( FPU_mul(&st(0), FPU_gettag0(), FPU_rm, control_word) >= 0 )
|
if (FPU_mul(&st(0), FPU_gettag0(), FPU_rm, control_word) >= 0)
|
||||||
FPU_pop();
|
FPU_pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void fsubrp(void)
|
void fsubrp(void)
|
||||||
{
|
{
|
||||||
/* fsubrp st(i),st */
|
/* fsubrp st(i),st */
|
||||||
clear_C1();
|
clear_C1();
|
||||||
if ( FPU_sub(DEST_RM, FPU_rm, control_word) >= 0 )
|
if (FPU_sub(DEST_RM, FPU_rm, control_word) >= 0)
|
||||||
FPU_pop();
|
FPU_pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fsubp_(void)
|
void fsubp_(void)
|
||||||
{
|
{
|
||||||
/* fsubp st(i),st */
|
/* fsubp st(i),st */
|
||||||
clear_C1();
|
clear_C1();
|
||||||
if ( FPU_sub(REV|DEST_RM, FPU_rm, control_word) >= 0 )
|
if (FPU_sub(REV | DEST_RM, FPU_rm, control_word) >= 0)
|
||||||
FPU_pop();
|
FPU_pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fdivrp(void)
|
void fdivrp(void)
|
||||||
{
|
{
|
||||||
/* fdivrp st(i),st */
|
/* fdivrp st(i),st */
|
||||||
clear_C1();
|
clear_C1();
|
||||||
if ( FPU_div(DEST_RM, FPU_rm, control_word) >= 0 )
|
if (FPU_div(DEST_RM, FPU_rm, control_word) >= 0)
|
||||||
FPU_pop();
|
FPU_pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fdivp_(void)
|
void fdivp_(void)
|
||||||
{
|
{
|
||||||
/* fdivp st(i),st */
|
/* fdivp st(i),st */
|
||||||
clear_C1();
|
clear_C1();
|
||||||
if ( FPU_div(REV|DEST_RM, FPU_rm, control_word) >= 0 )
|
if (FPU_div(REV | DEST_RM, FPU_rm, control_word) >= 0)
|
||||||
FPU_pop();
|
FPU_pop();
|
||||||
}
|
}
|
||||||
|
@@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
#define EXCEPTION FPU_exception
|
#define EXCEPTION FPU_exception
|
||||||
|
|
||||||
|
|
||||||
#define PARAM1 8(%ebp)
|
#define PARAM1 8(%ebp)
|
||||||
#define PARAM2 12(%ebp)
|
#define PARAM2 12(%ebp)
|
||||||
#define PARAM3 16(%ebp)
|
#define PARAM3 16(%ebp)
|
||||||
|
@@ -16,34 +16,34 @@
|
|||||||
#include "status_w.h"
|
#include "status_w.h"
|
||||||
#include "control_w.h"
|
#include "control_w.h"
|
||||||
|
|
||||||
|
|
||||||
static void fnop(void)
|
static void fnop(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fclex(void)
|
static void fclex(void)
|
||||||
{
|
{
|
||||||
partial_status &= ~(SW_Backward|SW_Summary|SW_Stack_Fault|SW_Precision|
|
partial_status &=
|
||||||
SW_Underflow|SW_Overflow|SW_Zero_Div|SW_Denorm_Op|
|
~(SW_Backward | SW_Summary | SW_Stack_Fault | SW_Precision |
|
||||||
SW_Invalid);
|
SW_Underflow | SW_Overflow | SW_Zero_Div | SW_Denorm_Op |
|
||||||
no_ip_update = 1;
|
SW_Invalid);
|
||||||
|
no_ip_update = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Needs to be externally visible */
|
/* Needs to be externally visible */
|
||||||
void finit(void)
|
void finit(void)
|
||||||
{
|
{
|
||||||
control_word = 0x037f;
|
control_word = 0x037f;
|
||||||
partial_status = 0;
|
partial_status = 0;
|
||||||
top = 0; /* We don't keep top in the status word internally. */
|
top = 0; /* We don't keep top in the status word internally. */
|
||||||
fpu_tag_word = 0xffff;
|
fpu_tag_word = 0xffff;
|
||||||
/* The behaviour is different from that detailed in
|
/* The behaviour is different from that detailed in
|
||||||
Section 15.1.6 of the Intel manual */
|
Section 15.1.6 of the Intel manual */
|
||||||
operand_address.offset = 0;
|
operand_address.offset = 0;
|
||||||
operand_address.selector = 0;
|
operand_address.selector = 0;
|
||||||
instruction_address.offset = 0;
|
instruction_address.offset = 0;
|
||||||
instruction_address.selector = 0;
|
instruction_address.selector = 0;
|
||||||
instruction_address.opcode = 0;
|
instruction_address.opcode = 0;
|
||||||
no_ip_update = 1;
|
no_ip_update = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -54,151 +54,134 @@ void finit(void)
|
|||||||
#define fsetpm fnop
|
#define fsetpm fnop
|
||||||
|
|
||||||
static FUNC const finit_table[] = {
|
static FUNC const finit_table[] = {
|
||||||
feni, fdisi, fclex, finit,
|
feni, fdisi, fclex, finit,
|
||||||
fsetpm, FPU_illegal, FPU_illegal, FPU_illegal
|
fsetpm, FPU_illegal, FPU_illegal, FPU_illegal
|
||||||
};
|
};
|
||||||
|
|
||||||
void finit_(void)
|
void finit_(void)
|
||||||
{
|
{
|
||||||
(finit_table[FPU_rm])();
|
(finit_table[FPU_rm]) ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void fstsw_ax(void)
|
static void fstsw_ax(void)
|
||||||
{
|
{
|
||||||
*(short *) &FPU_EAX = status_word();
|
*(short *)&FPU_EAX = status_word();
|
||||||
no_ip_update = 1;
|
no_ip_update = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static FUNC const fstsw_table[] = {
|
static FUNC const fstsw_table[] = {
|
||||||
fstsw_ax, FPU_illegal, FPU_illegal, FPU_illegal,
|
fstsw_ax, FPU_illegal, FPU_illegal, FPU_illegal,
|
||||||
FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
|
FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
|
||||||
};
|
};
|
||||||
|
|
||||||
void fstsw_(void)
|
void fstsw_(void)
|
||||||
{
|
{
|
||||||
(fstsw_table[FPU_rm])();
|
(fstsw_table[FPU_rm]) ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static FUNC const fp_nop_table[] = {
|
static FUNC const fp_nop_table[] = {
|
||||||
fnop, FPU_illegal, FPU_illegal, FPU_illegal,
|
fnop, FPU_illegal, FPU_illegal, FPU_illegal,
|
||||||
FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
|
FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
|
||||||
};
|
};
|
||||||
|
|
||||||
void fp_nop(void)
|
void fp_nop(void)
|
||||||
{
|
{
|
||||||
(fp_nop_table[FPU_rm])();
|
(fp_nop_table[FPU_rm]) ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fld_i_(void)
|
void fld_i_(void)
|
||||||
{
|
{
|
||||||
FPU_REG *st_new_ptr;
|
FPU_REG *st_new_ptr;
|
||||||
int i;
|
int i;
|
||||||
u_char tag;
|
u_char tag;
|
||||||
|
|
||||||
if ( STACK_OVERFLOW )
|
if (STACK_OVERFLOW) {
|
||||||
{ FPU_stack_overflow(); return; }
|
FPU_stack_overflow();
|
||||||
|
return;
|
||||||
/* fld st(i) */
|
}
|
||||||
i = FPU_rm;
|
|
||||||
if ( NOT_EMPTY(i) )
|
/* fld st(i) */
|
||||||
{
|
i = FPU_rm;
|
||||||
reg_copy(&st(i), st_new_ptr);
|
if (NOT_EMPTY(i)) {
|
||||||
tag = FPU_gettagi(i);
|
reg_copy(&st(i), st_new_ptr);
|
||||||
push();
|
tag = FPU_gettagi(i);
|
||||||
FPU_settag0(tag);
|
push();
|
||||||
}
|
FPU_settag0(tag);
|
||||||
else
|
} else {
|
||||||
{
|
if (control_word & CW_Invalid) {
|
||||||
if ( control_word & CW_Invalid )
|
/* The masked response */
|
||||||
{
|
FPU_stack_underflow();
|
||||||
/* The masked response */
|
} else
|
||||||
FPU_stack_underflow();
|
EXCEPTION(EX_StackUnder);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
EXCEPTION(EX_StackUnder);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fxch_i(void)
|
void fxch_i(void)
|
||||||
{
|
{
|
||||||
/* fxch st(i) */
|
/* fxch st(i) */
|
||||||
FPU_REG t;
|
FPU_REG t;
|
||||||
int i = FPU_rm;
|
int i = FPU_rm;
|
||||||
FPU_REG *st0_ptr = &st(0), *sti_ptr = &st(i);
|
FPU_REG *st0_ptr = &st(0), *sti_ptr = &st(i);
|
||||||
long tag_word = fpu_tag_word;
|
long tag_word = fpu_tag_word;
|
||||||
int regnr = top & 7, regnri = ((regnr + i) & 7);
|
int regnr = top & 7, regnri = ((regnr + i) & 7);
|
||||||
u_char st0_tag = (tag_word >> (regnr*2)) & 3;
|
u_char st0_tag = (tag_word >> (regnr * 2)) & 3;
|
||||||
u_char sti_tag = (tag_word >> (regnri*2)) & 3;
|
u_char sti_tag = (tag_word >> (regnri * 2)) & 3;
|
||||||
|
|
||||||
if ( st0_tag == TAG_Empty )
|
if (st0_tag == TAG_Empty) {
|
||||||
{
|
if (sti_tag == TAG_Empty) {
|
||||||
if ( sti_tag == TAG_Empty )
|
FPU_stack_underflow();
|
||||||
{
|
FPU_stack_underflow_i(i);
|
||||||
FPU_stack_underflow();
|
return;
|
||||||
FPU_stack_underflow_i(i);
|
}
|
||||||
return;
|
if (control_word & CW_Invalid) {
|
||||||
|
/* Masked response */
|
||||||
|
FPU_copy_to_reg0(sti_ptr, sti_tag);
|
||||||
|
}
|
||||||
|
FPU_stack_underflow_i(i);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if ( control_word & CW_Invalid )
|
if (sti_tag == TAG_Empty) {
|
||||||
{
|
if (control_word & CW_Invalid) {
|
||||||
/* Masked response */
|
/* Masked response */
|
||||||
FPU_copy_to_reg0(sti_ptr, sti_tag);
|
FPU_copy_to_regi(st0_ptr, st0_tag, i);
|
||||||
|
}
|
||||||
|
FPU_stack_underflow();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
FPU_stack_underflow_i(i);
|
clear_C1();
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ( sti_tag == TAG_Empty )
|
|
||||||
{
|
|
||||||
if ( control_word & CW_Invalid )
|
|
||||||
{
|
|
||||||
/* Masked response */
|
|
||||||
FPU_copy_to_regi(st0_ptr, st0_tag, i);
|
|
||||||
}
|
|
||||||
FPU_stack_underflow();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
clear_C1();
|
|
||||||
|
|
||||||
reg_copy(st0_ptr, &t);
|
reg_copy(st0_ptr, &t);
|
||||||
reg_copy(sti_ptr, st0_ptr);
|
reg_copy(sti_ptr, st0_ptr);
|
||||||
reg_copy(&t, sti_ptr);
|
reg_copy(&t, sti_ptr);
|
||||||
|
|
||||||
tag_word &= ~(3 << (regnr*2)) & ~(3 << (regnri*2));
|
tag_word &= ~(3 << (regnr * 2)) & ~(3 << (regnri * 2));
|
||||||
tag_word |= (sti_tag << (regnr*2)) | (st0_tag << (regnri*2));
|
tag_word |= (sti_tag << (regnr * 2)) | (st0_tag << (regnri * 2));
|
||||||
fpu_tag_word = tag_word;
|
fpu_tag_word = tag_word;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ffree_(void)
|
void ffree_(void)
|
||||||
{
|
{
|
||||||
/* ffree st(i) */
|
/* ffree st(i) */
|
||||||
FPU_settagi(FPU_rm, TAG_Empty);
|
FPU_settagi(FPU_rm, TAG_Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ffreep(void)
|
void ffreep(void)
|
||||||
{
|
{
|
||||||
/* ffree st(i) + pop - unofficial code */
|
/* ffree st(i) + pop - unofficial code */
|
||||||
FPU_settagi(FPU_rm, TAG_Empty);
|
FPU_settagi(FPU_rm, TAG_Empty);
|
||||||
FPU_pop();
|
FPU_pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fst_i_(void)
|
void fst_i_(void)
|
||||||
{
|
{
|
||||||
/* fst st(i) */
|
/* fst st(i) */
|
||||||
FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
|
FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fstp_i(void)
|
void fstp_i(void)
|
||||||
{
|
{
|
||||||
/* fstp st(i) */
|
/* fstp st(i) */
|
||||||
FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
|
FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
|
||||||
FPU_pop();
|
FPU_pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -7,7 +7,6 @@
|
|||||||
| |
|
| |
|
||||||
+---------------------------------------------------------------------------*/
|
+---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef _FPU_EMU_H_
|
#ifndef _FPU_EMU_H_
|
||||||
#define _FPU_EMU_H_
|
#define _FPU_EMU_H_
|
||||||
|
|
||||||
@@ -28,15 +27,15 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define EXP_BIAS Const(0)
|
#define EXP_BIAS Const(0)
|
||||||
#define EXP_OVER Const(0x4000) /* smallest invalid large exponent */
|
#define EXP_OVER Const(0x4000) /* smallest invalid large exponent */
|
||||||
#define EXP_UNDER Const(-0x3fff) /* largest invalid small exponent */
|
#define EXP_UNDER Const(-0x3fff) /* largest invalid small exponent */
|
||||||
#define EXP_WAY_UNDER Const(-0x6000) /* Below the smallest denormal, but
|
#define EXP_WAY_UNDER Const(-0x6000) /* Below the smallest denormal, but
|
||||||
still a 16 bit nr. */
|
still a 16 bit nr. */
|
||||||
#define EXP_Infinity EXP_OVER
|
#define EXP_Infinity EXP_OVER
|
||||||
#define EXP_NaN EXP_OVER
|
#define EXP_NaN EXP_OVER
|
||||||
|
|
||||||
#define EXTENDED_Ebias Const(0x3fff)
|
#define EXTENDED_Ebias Const(0x3fff)
|
||||||
#define EXTENDED_Emin (-0x3ffe) /* smallest valid exponent */
|
#define EXTENDED_Emin (-0x3ffe) /* smallest valid exponent */
|
||||||
|
|
||||||
#define SIGN_POS Const(0)
|
#define SIGN_POS Const(0)
|
||||||
#define SIGN_NEG Const(0x80)
|
#define SIGN_NEG Const(0x80)
|
||||||
@@ -44,10 +43,9 @@
|
|||||||
#define SIGN_Positive Const(0)
|
#define SIGN_Positive Const(0)
|
||||||
#define SIGN_Negative Const(0x8000)
|
#define SIGN_Negative Const(0x8000)
|
||||||
|
|
||||||
|
|
||||||
/* Keep the order TAG_Valid, TAG_Zero, TW_Denormal */
|
/* Keep the order TAG_Valid, TAG_Zero, TW_Denormal */
|
||||||
/* The following fold to 2 (Special) in the Tag Word */
|
/* The following fold to 2 (Special) in the Tag Word */
|
||||||
#define TW_Denormal Const(4) /* De-normal */
|
#define TW_Denormal Const(4) /* De-normal */
|
||||||
#define TW_Infinity Const(5) /* + or - infinity */
|
#define TW_Infinity Const(5) /* + or - infinity */
|
||||||
#define TW_NaN Const(6) /* Not a Number */
|
#define TW_NaN Const(6) /* Not a Number */
|
||||||
#define TW_Unsupported Const(7) /* Not supported by an 80486 */
|
#define TW_Unsupported Const(7) /* Not supported by an 80486 */
|
||||||
@@ -67,14 +65,13 @@
|
|||||||
#define DEST_RM 0x20
|
#define DEST_RM 0x20
|
||||||
#define LOADED 0x40
|
#define LOADED 0x40
|
||||||
|
|
||||||
#define FPU_Exception Const(0x80000000) /* Added to tag returns. */
|
#define FPU_Exception Const(0x80000000) /* Added to tag returns. */
|
||||||
|
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
#include "fpu_system.h"
|
#include "fpu_system.h"
|
||||||
|
|
||||||
#include <asm/sigcontext.h> /* for struct _fpstate */
|
#include <asm/sigcontext.h> /* for struct _fpstate */
|
||||||
#include <asm/math_emu.h>
|
#include <asm/math_emu.h>
|
||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
|
|
||||||
@@ -112,30 +109,33 @@ extern u_char emulating;
|
|||||||
#define PREFIX_DEFAULT 7
|
#define PREFIX_DEFAULT 7
|
||||||
|
|
||||||
struct address {
|
struct address {
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
unsigned int selector:16;
|
unsigned int selector:16;
|
||||||
unsigned int opcode:11;
|
unsigned int opcode:11;
|
||||||
unsigned int empty:5;
|
unsigned int empty:5;
|
||||||
};
|
};
|
||||||
struct fpu__reg {
|
struct fpu__reg {
|
||||||
unsigned sigl;
|
unsigned sigl;
|
||||||
unsigned sigh;
|
unsigned sigh;
|
||||||
short exp;
|
short exp;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*FUNC)(void);
|
typedef void (*FUNC) (void);
|
||||||
typedef struct fpu__reg FPU_REG;
|
typedef struct fpu__reg FPU_REG;
|
||||||
typedef void (*FUNC_ST0)(FPU_REG *st0_ptr, u_char st0_tag);
|
typedef void (*FUNC_ST0) (FPU_REG * st0_ptr, u_char st0_tag);
|
||||||
typedef struct { u_char address_size, operand_size, segment; }
|
typedef struct {
|
||||||
overrides;
|
u_char address_size, operand_size, segment;
|
||||||
|
} overrides;
|
||||||
/* This structure is 32 bits: */
|
/* This structure is 32 bits: */
|
||||||
typedef struct { overrides override;
|
typedef struct {
|
||||||
u_char default_mode; } fpu_addr_modes;
|
overrides override;
|
||||||
|
u_char default_mode;
|
||||||
|
} fpu_addr_modes;
|
||||||
/* PROTECTED has a restricted meaning in the emulator; it is used
|
/* PROTECTED has a restricted meaning in the emulator; it is used
|
||||||
to signal that the emulator needs to do special things to ensure
|
to signal that the emulator needs to do special things to ensure
|
||||||
that protection is respected in a segmented model. */
|
that protection is respected in a segmented model. */
|
||||||
#define PROTECTED 4
|
#define PROTECTED 4
|
||||||
#define SIXTEEN 1 /* We rely upon this being 1 (true) */
|
#define SIXTEEN 1 /* We rely upon this being 1 (true) */
|
||||||
#define VM86 SIXTEEN
|
#define VM86 SIXTEEN
|
||||||
#define PM16 (SIXTEEN | PROTECTED)
|
#define PM16 (SIXTEEN | PROTECTED)
|
||||||
#define SEG32 PROTECTED
|
#define SEG32 PROTECTED
|
||||||
@@ -166,10 +166,10 @@ extern u_char const data_sizes_16[32];
|
|||||||
#define signpositive(a) ( (signbyte(a) & 0x80) == 0 )
|
#define signpositive(a) ( (signbyte(a) & 0x80) == 0 )
|
||||||
#define signnegative(a) (signbyte(a) & 0x80)
|
#define signnegative(a) (signbyte(a) & 0x80)
|
||||||
|
|
||||||
static inline void reg_copy(FPU_REG const *x, FPU_REG *y)
|
static inline void reg_copy(FPU_REG const *x, FPU_REG * y)
|
||||||
{
|
{
|
||||||
*(short *)&(y->exp) = *(const short *)&(x->exp);
|
*(short *)&(y->exp) = *(const short *)&(x->exp);
|
||||||
*(long long *)&(y->sigl) = *(const long long *)&(x->sigl);
|
*(long long *)&(y->sigl) = *(const long long *)&(x->sigl);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define exponent(x) (((*(short *)&((x)->exp)) & 0x7fff) - EXTENDED_Ebias)
|
#define exponent(x) (((*(short *)&((x)->exp)) & 0x7fff) - EXTENDED_Ebias)
|
||||||
@@ -184,29 +184,28 @@ static inline void reg_copy(FPU_REG const *x, FPU_REG *y)
|
|||||||
|
|
||||||
#define significand(x) ( ((unsigned long long *)&((x)->sigl))[0] )
|
#define significand(x) ( ((unsigned long long *)&((x)->sigl))[0] )
|
||||||
|
|
||||||
|
|
||||||
/*----- Prototypes for functions written in assembler -----*/
|
/*----- Prototypes for functions written in assembler -----*/
|
||||||
/* extern void reg_move(FPU_REG *a, FPU_REG *b); */
|
/* extern void reg_move(FPU_REG *a, FPU_REG *b); */
|
||||||
|
|
||||||
asmlinkage int FPU_normalize(FPU_REG *x);
|
asmlinkage int FPU_normalize(FPU_REG * x);
|
||||||
asmlinkage int FPU_normalize_nuo(FPU_REG *x);
|
asmlinkage int FPU_normalize_nuo(FPU_REG * x);
|
||||||
asmlinkage int FPU_u_sub(FPU_REG const *arg1, FPU_REG const *arg2,
|
asmlinkage int FPU_u_sub(FPU_REG const *arg1, FPU_REG const *arg2,
|
||||||
FPU_REG *answ, unsigned int control_w, u_char sign,
|
FPU_REG * answ, unsigned int control_w, u_char sign,
|
||||||
int expa, int expb);
|
int expa, int expb);
|
||||||
asmlinkage int FPU_u_mul(FPU_REG const *arg1, FPU_REG const *arg2,
|
asmlinkage int FPU_u_mul(FPU_REG const *arg1, FPU_REG const *arg2,
|
||||||
FPU_REG *answ, unsigned int control_w, u_char sign,
|
FPU_REG * answ, unsigned int control_w, u_char sign,
|
||||||
int expon);
|
int expon);
|
||||||
asmlinkage int FPU_u_div(FPU_REG const *arg1, FPU_REG const *arg2,
|
asmlinkage int FPU_u_div(FPU_REG const *arg1, FPU_REG const *arg2,
|
||||||
FPU_REG *answ, unsigned int control_w, u_char sign);
|
FPU_REG * answ, unsigned int control_w, u_char sign);
|
||||||
asmlinkage int FPU_u_add(FPU_REG const *arg1, FPU_REG const *arg2,
|
asmlinkage int FPU_u_add(FPU_REG const *arg1, FPU_REG const *arg2,
|
||||||
FPU_REG *answ, unsigned int control_w, u_char sign,
|
FPU_REG * answ, unsigned int control_w, u_char sign,
|
||||||
int expa, int expb);
|
int expa, int expb);
|
||||||
asmlinkage int wm_sqrt(FPU_REG *n, int dummy1, int dummy2,
|
asmlinkage int wm_sqrt(FPU_REG * n, int dummy1, int dummy2,
|
||||||
unsigned int control_w, u_char sign);
|
unsigned int control_w, u_char sign);
|
||||||
asmlinkage unsigned FPU_shrx(void *l, unsigned x);
|
asmlinkage unsigned FPU_shrx(void *l, unsigned x);
|
||||||
asmlinkage unsigned FPU_shrxs(void *v, unsigned x);
|
asmlinkage unsigned FPU_shrxs(void *v, unsigned x);
|
||||||
asmlinkage unsigned long FPU_div_small(unsigned long long *x, unsigned long y);
|
asmlinkage unsigned long FPU_div_small(unsigned long long *x, unsigned long y);
|
||||||
asmlinkage int FPU_round(FPU_REG *arg, unsigned int extent, int dummy,
|
asmlinkage int FPU_round(FPU_REG * arg, unsigned int extent, int dummy,
|
||||||
unsigned int control_w, u_char sign);
|
unsigned int control_w, u_char sign);
|
||||||
|
|
||||||
#ifndef MAKING_PROTO
|
#ifndef MAKING_PROTO
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -16,128 +16,115 @@
|
|||||||
#include "status_w.h"
|
#include "status_w.h"
|
||||||
#include "reg_constant.h"
|
#include "reg_constant.h"
|
||||||
|
|
||||||
|
static void fchs(FPU_REG * st0_ptr, u_char st0tag)
|
||||||
static void fchs(FPU_REG *st0_ptr, u_char st0tag)
|
|
||||||
{
|
{
|
||||||
if ( st0tag ^ TAG_Empty )
|
if (st0tag ^ TAG_Empty) {
|
||||||
{
|
signbyte(st0_ptr) ^= SIGN_NEG;
|
||||||
signbyte(st0_ptr) ^= SIGN_NEG;
|
clear_C1();
|
||||||
clear_C1();
|
} else
|
||||||
}
|
FPU_stack_underflow();
|
||||||
else
|
|
||||||
FPU_stack_underflow();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fabs(FPU_REG * st0_ptr, u_char st0tag)
|
||||||
static void fabs(FPU_REG *st0_ptr, u_char st0tag)
|
|
||||||
{
|
{
|
||||||
if ( st0tag ^ TAG_Empty )
|
if (st0tag ^ TAG_Empty) {
|
||||||
{
|
setpositive(st0_ptr);
|
||||||
setpositive(st0_ptr);
|
clear_C1();
|
||||||
clear_C1();
|
} else
|
||||||
}
|
FPU_stack_underflow();
|
||||||
else
|
|
||||||
FPU_stack_underflow();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ftst_(FPU_REG * st0_ptr, u_char st0tag)
|
||||||
static void ftst_(FPU_REG *st0_ptr, u_char st0tag)
|
|
||||||
{
|
{
|
||||||
switch (st0tag)
|
switch (st0tag) {
|
||||||
{
|
case TAG_Zero:
|
||||||
case TAG_Zero:
|
|
||||||
setcc(SW_C3);
|
|
||||||
break;
|
|
||||||
case TAG_Valid:
|
|
||||||
if (getsign(st0_ptr) == SIGN_POS)
|
|
||||||
setcc(0);
|
|
||||||
else
|
|
||||||
setcc(SW_C0);
|
|
||||||
break;
|
|
||||||
case TAG_Special:
|
|
||||||
switch ( FPU_Special(st0_ptr) )
|
|
||||||
{
|
|
||||||
case TW_Denormal:
|
|
||||||
if (getsign(st0_ptr) == SIGN_POS)
|
|
||||||
setcc(0);
|
|
||||||
else
|
|
||||||
setcc(SW_C0);
|
|
||||||
if ( denormal_operand() < 0 )
|
|
||||||
{
|
|
||||||
#ifdef PECULIAR_486
|
|
||||||
/* This is weird! */
|
|
||||||
if (getsign(st0_ptr) == SIGN_POS)
|
|
||||||
setcc(SW_C3);
|
setcc(SW_C3);
|
||||||
|
break;
|
||||||
|
case TAG_Valid:
|
||||||
|
if (getsign(st0_ptr) == SIGN_POS)
|
||||||
|
setcc(0);
|
||||||
|
else
|
||||||
|
setcc(SW_C0);
|
||||||
|
break;
|
||||||
|
case TAG_Special:
|
||||||
|
switch (FPU_Special(st0_ptr)) {
|
||||||
|
case TW_Denormal:
|
||||||
|
if (getsign(st0_ptr) == SIGN_POS)
|
||||||
|
setcc(0);
|
||||||
|
else
|
||||||
|
setcc(SW_C0);
|
||||||
|
if (denormal_operand() < 0) {
|
||||||
|
#ifdef PECULIAR_486
|
||||||
|
/* This is weird! */
|
||||||
|
if (getsign(st0_ptr) == SIGN_POS)
|
||||||
|
setcc(SW_C3);
|
||||||
#endif /* PECULIAR_486 */
|
#endif /* PECULIAR_486 */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TW_NaN:
|
case TW_NaN:
|
||||||
setcc(SW_C0|SW_C2|SW_C3); /* Operand is not comparable */
|
setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */
|
||||||
EXCEPTION(EX_Invalid);
|
EXCEPTION(EX_Invalid);
|
||||||
break;
|
break;
|
||||||
case TW_Infinity:
|
case TW_Infinity:
|
||||||
if (getsign(st0_ptr) == SIGN_POS)
|
if (getsign(st0_ptr) == SIGN_POS)
|
||||||
setcc(0);
|
setcc(0);
|
||||||
else
|
else
|
||||||
setcc(SW_C0);
|
setcc(SW_C0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
setcc(SW_C0|SW_C2|SW_C3); /* Operand is not comparable */
|
setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */
|
||||||
EXCEPTION(EX_INTERNAL|0x14);
|
EXCEPTION(EX_INTERNAL | 0x14);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TAG_Empty:
|
||||||
|
setcc(SW_C0 | SW_C2 | SW_C3);
|
||||||
|
EXCEPTION(EX_StackUnder);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case TAG_Empty:
|
|
||||||
setcc(SW_C0|SW_C2|SW_C3);
|
|
||||||
EXCEPTION(EX_StackUnder);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fxam(FPU_REG * st0_ptr, u_char st0tag)
|
||||||
static void fxam(FPU_REG *st0_ptr, u_char st0tag)
|
|
||||||
{
|
{
|
||||||
int c = 0;
|
int c = 0;
|
||||||
switch (st0tag)
|
switch (st0tag) {
|
||||||
{
|
case TAG_Empty:
|
||||||
case TAG_Empty:
|
c = SW_C3 | SW_C0;
|
||||||
c = SW_C3|SW_C0;
|
break;
|
||||||
break;
|
case TAG_Zero:
|
||||||
case TAG_Zero:
|
c = SW_C3;
|
||||||
c = SW_C3;
|
break;
|
||||||
break;
|
case TAG_Valid:
|
||||||
case TAG_Valid:
|
c = SW_C2;
|
||||||
c = SW_C2;
|
break;
|
||||||
break;
|
case TAG_Special:
|
||||||
case TAG_Special:
|
switch (FPU_Special(st0_ptr)) {
|
||||||
switch ( FPU_Special(st0_ptr) )
|
case TW_Denormal:
|
||||||
{
|
c = SW_C2 | SW_C3; /* Denormal */
|
||||||
case TW_Denormal:
|
break;
|
||||||
c = SW_C2|SW_C3; /* Denormal */
|
case TW_NaN:
|
||||||
break;
|
/* We also use NaN for unsupported types. */
|
||||||
case TW_NaN:
|
if ((st0_ptr->sigh & 0x80000000)
|
||||||
/* We also use NaN for unsupported types. */
|
&& (exponent(st0_ptr) == EXP_OVER))
|
||||||
if ( (st0_ptr->sigh & 0x80000000) && (exponent(st0_ptr) == EXP_OVER) )
|
c = SW_C0;
|
||||||
c = SW_C0;
|
break;
|
||||||
break;
|
case TW_Infinity:
|
||||||
case TW_Infinity:
|
c = SW_C2 | SW_C0;
|
||||||
c = SW_C2|SW_C0;
|
break;
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
}
|
if (getsign(st0_ptr) == SIGN_NEG)
|
||||||
if ( getsign(st0_ptr) == SIGN_NEG )
|
c |= SW_C1;
|
||||||
c |= SW_C1;
|
setcc(c);
|
||||||
setcc(c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static FUNC_ST0 const fp_etc_table[] = {
|
static FUNC_ST0 const fp_etc_table[] = {
|
||||||
fchs, fabs, (FUNC_ST0)FPU_illegal, (FUNC_ST0)FPU_illegal,
|
fchs, fabs, (FUNC_ST0) FPU_illegal, (FUNC_ST0) FPU_illegal,
|
||||||
ftst_, fxam, (FUNC_ST0)FPU_illegal, (FUNC_ST0)FPU_illegal
|
ftst_, fxam, (FUNC_ST0) FPU_illegal, (FUNC_ST0) FPU_illegal
|
||||||
};
|
};
|
||||||
|
|
||||||
void FPU_etc(void)
|
void FPU_etc(void)
|
||||||
{
|
{
|
||||||
(fp_etc_table[FPU_rm])(&st(0), FPU_gettag0());
|
(fp_etc_table[FPU_rm]) (&st(0), FPU_gettag0());
|
||||||
}
|
}
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
extern void FPU_illegal(void);
|
extern void FPU_illegal(void);
|
||||||
extern void FPU_printall(void);
|
extern void FPU_printall(void);
|
||||||
asmlinkage void FPU_exception(int n);
|
asmlinkage void FPU_exception(int n);
|
||||||
extern int real_1op_NaN(FPU_REG *a);
|
extern int real_1op_NaN(FPU_REG * a);
|
||||||
extern int real_2op_NaN(FPU_REG const *b, u_char tagb, int deststnr,
|
extern int real_2op_NaN(FPU_REG const *b, u_char tagb, int deststnr,
|
||||||
FPU_REG const *defaultNaN);
|
FPU_REG const *defaultNaN);
|
||||||
asmlinkage int arith_invalid(int deststnr);
|
asmlinkage int arith_invalid(int deststnr);
|
||||||
@@ -14,8 +14,8 @@ extern int set_precision_flag(int flags);
|
|||||||
asmlinkage void set_precision_flag_up(void);
|
asmlinkage void set_precision_flag_up(void);
|
||||||
asmlinkage void set_precision_flag_down(void);
|
asmlinkage void set_precision_flag_down(void);
|
||||||
asmlinkage int denormal_operand(void);
|
asmlinkage int denormal_operand(void);
|
||||||
asmlinkage int arith_overflow(FPU_REG *dest);
|
asmlinkage int arith_overflow(FPU_REG * dest);
|
||||||
asmlinkage int arith_underflow(FPU_REG *dest);
|
asmlinkage int arith_underflow(FPU_REG * dest);
|
||||||
extern void FPU_stack_overflow(void);
|
extern void FPU_stack_overflow(void);
|
||||||
extern void FPU_stack_underflow(void);
|
extern void FPU_stack_underflow(void);
|
||||||
extern void FPU_stack_underflow_i(int i);
|
extern void FPU_stack_underflow_i(int i);
|
||||||
@@ -66,7 +66,7 @@ extern int FPU_Special(FPU_REG const *ptr);
|
|||||||
extern int isNaN(FPU_REG const *ptr);
|
extern int isNaN(FPU_REG const *ptr);
|
||||||
extern void FPU_pop(void);
|
extern void FPU_pop(void);
|
||||||
extern int FPU_empty_i(int stnr);
|
extern int FPU_empty_i(int stnr);
|
||||||
extern int FPU_stackoverflow(FPU_REG **st_new_ptr);
|
extern int FPU_stackoverflow(FPU_REG ** st_new_ptr);
|
||||||
extern void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr);
|
extern void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr);
|
||||||
extern void FPU_copy_to_reg1(FPU_REG const *r, u_char tag);
|
extern void FPU_copy_to_reg1(FPU_REG const *r, u_char tag);
|
||||||
extern void FPU_copy_to_reg0(FPU_REG const *r, u_char tag);
|
extern void FPU_copy_to_reg0(FPU_REG const *r, u_char tag);
|
||||||
@@ -75,26 +75,28 @@ extern void FPU_triga(void);
|
|||||||
extern void FPU_trigb(void);
|
extern void FPU_trigb(void);
|
||||||
/* get_address.c */
|
/* get_address.c */
|
||||||
extern void __user *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip,
|
extern void __user *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip,
|
||||||
struct address *addr, fpu_addr_modes addr_modes);
|
struct address *addr,
|
||||||
|
fpu_addr_modes addr_modes);
|
||||||
extern void __user *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip,
|
extern void __user *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip,
|
||||||
struct address *addr, fpu_addr_modes addr_modes);
|
struct address *addr,
|
||||||
|
fpu_addr_modes addr_modes);
|
||||||
/* load_store.c */
|
/* load_store.c */
|
||||||
extern int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
|
extern int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
|
||||||
void __user *data_address);
|
void __user * data_address);
|
||||||
/* poly_2xm1.c */
|
/* poly_2xm1.c */
|
||||||
extern int poly_2xm1(u_char sign, FPU_REG *arg, FPU_REG *result);
|
extern int poly_2xm1(u_char sign, FPU_REG * arg, FPU_REG * result);
|
||||||
/* poly_atan.c */
|
/* poly_atan.c */
|
||||||
extern void poly_atan(FPU_REG *st0_ptr, u_char st0_tag, FPU_REG *st1_ptr,
|
extern void poly_atan(FPU_REG * st0_ptr, u_char st0_tag, FPU_REG * st1_ptr,
|
||||||
u_char st1_tag);
|
u_char st1_tag);
|
||||||
/* poly_l2.c */
|
/* poly_l2.c */
|
||||||
extern void poly_l2(FPU_REG *st0_ptr, FPU_REG *st1_ptr, u_char st1_sign);
|
extern void poly_l2(FPU_REG * st0_ptr, FPU_REG * st1_ptr, u_char st1_sign);
|
||||||
extern int poly_l2p1(u_char s0, u_char s1, FPU_REG *r0, FPU_REG *r1,
|
extern int poly_l2p1(u_char s0, u_char s1, FPU_REG * r0, FPU_REG * r1,
|
||||||
FPU_REG *d);
|
FPU_REG * d);
|
||||||
/* poly_sin.c */
|
/* poly_sin.c */
|
||||||
extern void poly_sine(FPU_REG *st0_ptr);
|
extern void poly_sine(FPU_REG * st0_ptr);
|
||||||
extern void poly_cos(FPU_REG *st0_ptr);
|
extern void poly_cos(FPU_REG * st0_ptr);
|
||||||
/* poly_tan.c */
|
/* poly_tan.c */
|
||||||
extern void poly_tan(FPU_REG *st0_ptr);
|
extern void poly_tan(FPU_REG * st0_ptr);
|
||||||
/* reg_add_sub.c */
|
/* reg_add_sub.c */
|
||||||
extern int FPU_add(FPU_REG const *b, u_char tagb, int destrnr, int control_w);
|
extern int FPU_add(FPU_REG const *b, u_char tagb, int destrnr, int control_w);
|
||||||
extern int FPU_sub(int flags, int rm, int control_w);
|
extern int FPU_sub(int flags, int rm, int control_w);
|
||||||
@@ -109,32 +111,34 @@ extern void fucompp(void);
|
|||||||
/* reg_constant.c */
|
/* reg_constant.c */
|
||||||
extern void fconst(void);
|
extern void fconst(void);
|
||||||
/* reg_ld_str.c */
|
/* reg_ld_str.c */
|
||||||
extern int FPU_load_extended(long double __user *s, int stnr);
|
extern int FPU_load_extended(long double __user * s, int stnr);
|
||||||
extern int FPU_load_double(double __user *dfloat, FPU_REG *loaded_data);
|
extern int FPU_load_double(double __user * dfloat, FPU_REG * loaded_data);
|
||||||
extern int FPU_load_single(float __user *single, FPU_REG *loaded_data);
|
extern int FPU_load_single(float __user * single, FPU_REG * loaded_data);
|
||||||
extern int FPU_load_int64(long long __user *_s);
|
extern int FPU_load_int64(long long __user * _s);
|
||||||
extern int FPU_load_int32(long __user *_s, FPU_REG *loaded_data);
|
extern int FPU_load_int32(long __user * _s, FPU_REG * loaded_data);
|
||||||
extern int FPU_load_int16(short __user *_s, FPU_REG *loaded_data);
|
extern int FPU_load_int16(short __user * _s, FPU_REG * loaded_data);
|
||||||
extern int FPU_load_bcd(u_char __user *s);
|
extern int FPU_load_bcd(u_char __user * s);
|
||||||
extern int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag,
|
extern int FPU_store_extended(FPU_REG * st0_ptr, u_char st0_tag,
|
||||||
long double __user *d);
|
long double __user * d);
|
||||||
extern int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double __user *dfloat);
|
extern int FPU_store_double(FPU_REG * st0_ptr, u_char st0_tag,
|
||||||
extern int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float __user *single);
|
double __user * dfloat);
|
||||||
extern int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, long long __user *d);
|
extern int FPU_store_single(FPU_REG * st0_ptr, u_char st0_tag,
|
||||||
extern int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long __user *d);
|
float __user * single);
|
||||||
extern int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short __user *d);
|
extern int FPU_store_int64(FPU_REG * st0_ptr, u_char st0_tag,
|
||||||
extern int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char __user *d);
|
long long __user * d);
|
||||||
extern int FPU_round_to_int(FPU_REG *r, u_char tag);
|
extern int FPU_store_int32(FPU_REG * st0_ptr, u_char st0_tag, long __user * d);
|
||||||
extern u_char __user *fldenv(fpu_addr_modes addr_modes, u_char __user *s);
|
extern int FPU_store_int16(FPU_REG * st0_ptr, u_char st0_tag, short __user * d);
|
||||||
extern void frstor(fpu_addr_modes addr_modes, u_char __user *data_address);
|
extern int FPU_store_bcd(FPU_REG * st0_ptr, u_char st0_tag, u_char __user * d);
|
||||||
extern u_char __user *fstenv(fpu_addr_modes addr_modes, u_char __user *d);
|
extern int FPU_round_to_int(FPU_REG * r, u_char tag);
|
||||||
extern void fsave(fpu_addr_modes addr_modes, u_char __user *data_address);
|
extern u_char __user *fldenv(fpu_addr_modes addr_modes, u_char __user * s);
|
||||||
extern int FPU_tagof(FPU_REG *ptr);
|
extern void frstor(fpu_addr_modes addr_modes, u_char __user * data_address);
|
||||||
|
extern u_char __user *fstenv(fpu_addr_modes addr_modes, u_char __user * d);
|
||||||
|
extern void fsave(fpu_addr_modes addr_modes, u_char __user * data_address);
|
||||||
|
extern int FPU_tagof(FPU_REG * ptr);
|
||||||
/* reg_mul.c */
|
/* reg_mul.c */
|
||||||
extern int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w);
|
extern int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w);
|
||||||
|
|
||||||
extern int FPU_div(int flags, int regrm, int control_w);
|
extern int FPU_div(int flags, int regrm, int control_w);
|
||||||
/* reg_convert.c */
|
/* reg_convert.c */
|
||||||
extern int FPU_to_exp16(FPU_REG const *a, FPU_REG *x);
|
extern int FPU_to_exp16(FPU_REG const *a, FPU_REG * x);
|
||||||
#endif /* _FPU_PROTO_H */
|
#endif /* _FPU_PROTO_H */
|
||||||
|
|
||||||
|
@@ -14,114 +14,102 @@
|
|||||||
#include "fpu_system.h"
|
#include "fpu_system.h"
|
||||||
#include "exception.h"
|
#include "exception.h"
|
||||||
|
|
||||||
|
|
||||||
void FPU_pop(void)
|
void FPU_pop(void)
|
||||||
{
|
{
|
||||||
fpu_tag_word |= 3 << ((top & 7)*2);
|
fpu_tag_word |= 3 << ((top & 7) * 2);
|
||||||
top++;
|
top++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int FPU_gettag0(void)
|
int FPU_gettag0(void)
|
||||||
{
|
{
|
||||||
return (fpu_tag_word >> ((top & 7)*2)) & 3;
|
return (fpu_tag_word >> ((top & 7) * 2)) & 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int FPU_gettagi(int stnr)
|
int FPU_gettagi(int stnr)
|
||||||
{
|
{
|
||||||
return (fpu_tag_word >> (((top+stnr) & 7)*2)) & 3;
|
return (fpu_tag_word >> (((top + stnr) & 7) * 2)) & 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int FPU_gettag(int regnr)
|
int FPU_gettag(int regnr)
|
||||||
{
|
{
|
||||||
return (fpu_tag_word >> ((regnr & 7)*2)) & 3;
|
return (fpu_tag_word >> ((regnr & 7) * 2)) & 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FPU_settag0(int tag)
|
void FPU_settag0(int tag)
|
||||||
{
|
{
|
||||||
int regnr = top;
|
int regnr = top;
|
||||||
regnr &= 7;
|
regnr &= 7;
|
||||||
fpu_tag_word &= ~(3 << (regnr*2));
|
fpu_tag_word &= ~(3 << (regnr * 2));
|
||||||
fpu_tag_word |= (tag & 3) << (regnr*2);
|
fpu_tag_word |= (tag & 3) << (regnr * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FPU_settagi(int stnr, int tag)
|
void FPU_settagi(int stnr, int tag)
|
||||||
{
|
{
|
||||||
int regnr = stnr+top;
|
int regnr = stnr + top;
|
||||||
regnr &= 7;
|
regnr &= 7;
|
||||||
fpu_tag_word &= ~(3 << (regnr*2));
|
fpu_tag_word &= ~(3 << (regnr * 2));
|
||||||
fpu_tag_word |= (tag & 3) << (regnr*2);
|
fpu_tag_word |= (tag & 3) << (regnr * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FPU_settag(int regnr, int tag)
|
void FPU_settag(int regnr, int tag)
|
||||||
{
|
{
|
||||||
regnr &= 7;
|
regnr &= 7;
|
||||||
fpu_tag_word &= ~(3 << (regnr*2));
|
fpu_tag_word &= ~(3 << (regnr * 2));
|
||||||
fpu_tag_word |= (tag & 3) << (regnr*2);
|
fpu_tag_word |= (tag & 3) << (regnr * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int FPU_Special(FPU_REG const *ptr)
|
int FPU_Special(FPU_REG const *ptr)
|
||||||
{
|
{
|
||||||
int exp = exponent(ptr);
|
int exp = exponent(ptr);
|
||||||
|
|
||||||
if ( exp == EXP_BIAS+EXP_UNDER )
|
if (exp == EXP_BIAS + EXP_UNDER)
|
||||||
return TW_Denormal;
|
return TW_Denormal;
|
||||||
else if ( exp != EXP_BIAS+EXP_OVER )
|
else if (exp != EXP_BIAS + EXP_OVER)
|
||||||
return TW_NaN;
|
return TW_NaN;
|
||||||
else if ( (ptr->sigh == 0x80000000) && (ptr->sigl == 0) )
|
else if ((ptr->sigh == 0x80000000) && (ptr->sigl == 0))
|
||||||
return TW_Infinity;
|
return TW_Infinity;
|
||||||
return TW_NaN;
|
return TW_NaN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int isNaN(FPU_REG const *ptr)
|
int isNaN(FPU_REG const *ptr)
|
||||||
{
|
{
|
||||||
return ( (exponent(ptr) == EXP_BIAS+EXP_OVER)
|
return ((exponent(ptr) == EXP_BIAS + EXP_OVER)
|
||||||
&& !((ptr->sigh == 0x80000000) && (ptr->sigl == 0)) );
|
&& !((ptr->sigh == 0x80000000) && (ptr->sigl == 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int FPU_empty_i(int stnr)
|
int FPU_empty_i(int stnr)
|
||||||
{
|
{
|
||||||
int regnr = (top+stnr) & 7;
|
int regnr = (top + stnr) & 7;
|
||||||
|
|
||||||
return ((fpu_tag_word >> (regnr*2)) & 3) == TAG_Empty;
|
return ((fpu_tag_word >> (regnr * 2)) & 3) == TAG_Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int FPU_stackoverflow(FPU_REG ** st_new_ptr)
|
||||||
int FPU_stackoverflow(FPU_REG **st_new_ptr)
|
|
||||||
{
|
{
|
||||||
*st_new_ptr = &st(-1);
|
*st_new_ptr = &st(-1);
|
||||||
|
|
||||||
return ((fpu_tag_word >> (((top - 1) & 7)*2)) & 3) != TAG_Empty;
|
return ((fpu_tag_word >> (((top - 1) & 7) * 2)) & 3) != TAG_Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr)
|
void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr)
|
||||||
{
|
{
|
||||||
reg_copy(r, &st(stnr));
|
reg_copy(r, &st(stnr));
|
||||||
FPU_settagi(stnr, tag);
|
FPU_settagi(stnr, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FPU_copy_to_reg1(FPU_REG const *r, u_char tag)
|
void FPU_copy_to_reg1(FPU_REG const *r, u_char tag)
|
||||||
{
|
{
|
||||||
reg_copy(r, &st(1));
|
reg_copy(r, &st(1));
|
||||||
FPU_settagi(1, tag);
|
FPU_settagi(1, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FPU_copy_to_reg0(FPU_REG const *r, u_char tag)
|
void FPU_copy_to_reg0(FPU_REG const *r, u_char tag)
|
||||||
{
|
{
|
||||||
int regnr = top;
|
int regnr = top;
|
||||||
regnr &= 7;
|
regnr &= 7;
|
||||||
|
|
||||||
reg_copy(r, &st(0));
|
reg_copy(r, &st(0));
|
||||||
|
|
||||||
fpu_tag_word &= ~(3 << (regnr*2));
|
fpu_tag_word &= ~(3 << (regnr * 2));
|
||||||
fpu_tag_word |= (tag & 3) << (regnr*2);
|
fpu_tag_word |= (tag & 3) << (regnr * 2);
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,6 @@
|
|||||||
| other processes using the emulator while swapping is in progress. |
|
| other processes using the emulator while swapping is in progress. |
|
||||||
+---------------------------------------------------------------------------*/
|
+---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
#include <linux/stddef.h>
|
#include <linux/stddef.h>
|
||||||
|
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
@@ -27,31 +26,30 @@
|
|||||||
#include "exception.h"
|
#include "exception.h"
|
||||||
#include "fpu_emu.h"
|
#include "fpu_emu.h"
|
||||||
|
|
||||||
|
|
||||||
#define FPU_WRITE_BIT 0x10
|
#define FPU_WRITE_BIT 0x10
|
||||||
|
|
||||||
static int reg_offset[] = {
|
static int reg_offset[] = {
|
||||||
offsetof(struct info,___eax),
|
offsetof(struct info, ___eax),
|
||||||
offsetof(struct info,___ecx),
|
offsetof(struct info, ___ecx),
|
||||||
offsetof(struct info,___edx),
|
offsetof(struct info, ___edx),
|
||||||
offsetof(struct info,___ebx),
|
offsetof(struct info, ___ebx),
|
||||||
offsetof(struct info,___esp),
|
offsetof(struct info, ___esp),
|
||||||
offsetof(struct info,___ebp),
|
offsetof(struct info, ___ebp),
|
||||||
offsetof(struct info,___esi),
|
offsetof(struct info, ___esi),
|
||||||
offsetof(struct info,___edi)
|
offsetof(struct info, ___edi)
|
||||||
};
|
};
|
||||||
|
|
||||||
#define REG_(x) (*(long *)(reg_offset[(x)]+(u_char *) FPU_info))
|
#define REG_(x) (*(long *)(reg_offset[(x)]+(u_char *) FPU_info))
|
||||||
|
|
||||||
static int reg_offset_vm86[] = {
|
static int reg_offset_vm86[] = {
|
||||||
offsetof(struct info,___cs),
|
offsetof(struct info, ___cs),
|
||||||
offsetof(struct info,___vm86_ds),
|
offsetof(struct info, ___vm86_ds),
|
||||||
offsetof(struct info,___vm86_es),
|
offsetof(struct info, ___vm86_es),
|
||||||
offsetof(struct info,___vm86_fs),
|
offsetof(struct info, ___vm86_fs),
|
||||||
offsetof(struct info,___vm86_gs),
|
offsetof(struct info, ___vm86_gs),
|
||||||
offsetof(struct info,___ss),
|
offsetof(struct info, ___ss),
|
||||||
offsetof(struct info,___vm86_ds)
|
offsetof(struct info, ___vm86_ds)
|
||||||
};
|
};
|
||||||
|
|
||||||
#define VM86_REG_(x) (*(unsigned short *) \
|
#define VM86_REG_(x) (*(unsigned short *) \
|
||||||
(reg_offset_vm86[((unsigned)x)]+(u_char *) FPU_info))
|
(reg_offset_vm86[((unsigned)x)]+(u_char *) FPU_info))
|
||||||
@@ -60,158 +58,141 @@ static int reg_offset_vm86[] = {
|
|||||||
#define ___GS ___ds
|
#define ___GS ___ds
|
||||||
|
|
||||||
static int reg_offset_pm[] = {
|
static int reg_offset_pm[] = {
|
||||||
offsetof(struct info,___cs),
|
offsetof(struct info, ___cs),
|
||||||
offsetof(struct info,___ds),
|
offsetof(struct info, ___ds),
|
||||||
offsetof(struct info,___es),
|
offsetof(struct info, ___es),
|
||||||
offsetof(struct info,___fs),
|
offsetof(struct info, ___fs),
|
||||||
offsetof(struct info,___GS),
|
offsetof(struct info, ___GS),
|
||||||
offsetof(struct info,___ss),
|
offsetof(struct info, ___ss),
|
||||||
offsetof(struct info,___ds)
|
offsetof(struct info, ___ds)
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PM_REG_(x) (*(unsigned short *) \
|
#define PM_REG_(x) (*(unsigned short *) \
|
||||||
(reg_offset_pm[((unsigned)x)]+(u_char *) FPU_info))
|
(reg_offset_pm[((unsigned)x)]+(u_char *) FPU_info))
|
||||||
|
|
||||||
|
|
||||||
/* Decode the SIB byte. This function assumes mod != 0 */
|
/* Decode the SIB byte. This function assumes mod != 0 */
|
||||||
static int sib(int mod, unsigned long *fpu_eip)
|
static int sib(int mod, unsigned long *fpu_eip)
|
||||||
{
|
{
|
||||||
u_char ss,index,base;
|
u_char ss, index, base;
|
||||||
long offset;
|
long offset;
|
||||||
|
|
||||||
RE_ENTRANT_CHECK_OFF;
|
RE_ENTRANT_CHECK_OFF;
|
||||||
FPU_code_access_ok(1);
|
FPU_code_access_ok(1);
|
||||||
FPU_get_user(base, (u_char __user *) (*fpu_eip)); /* The SIB byte */
|
FPU_get_user(base, (u_char __user *) (*fpu_eip)); /* The SIB byte */
|
||||||
RE_ENTRANT_CHECK_ON;
|
RE_ENTRANT_CHECK_ON;
|
||||||
(*fpu_eip)++;
|
(*fpu_eip)++;
|
||||||
ss = base >> 6;
|
ss = base >> 6;
|
||||||
index = (base >> 3) & 7;
|
index = (base >> 3) & 7;
|
||||||
base &= 7;
|
base &= 7;
|
||||||
|
|
||||||
if ((mod == 0) && (base == 5))
|
if ((mod == 0) && (base == 5))
|
||||||
offset = 0; /* No base register */
|
offset = 0; /* No base register */
|
||||||
else
|
else
|
||||||
offset = REG_(base);
|
offset = REG_(base);
|
||||||
|
|
||||||
if (index == 4)
|
if (index == 4) {
|
||||||
{
|
/* No index register */
|
||||||
/* No index register */
|
/* A non-zero ss is illegal */
|
||||||
/* A non-zero ss is illegal */
|
if (ss)
|
||||||
if ( ss )
|
EXCEPTION(EX_Invalid);
|
||||||
EXCEPTION(EX_Invalid);
|
} else {
|
||||||
}
|
offset += (REG_(index)) << ss;
|
||||||
else
|
}
|
||||||
{
|
|
||||||
offset += (REG_(index)) << ss;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mod == 1)
|
if (mod == 1) {
|
||||||
{
|
/* 8 bit signed displacement */
|
||||||
/* 8 bit signed displacement */
|
long displacement;
|
||||||
long displacement;
|
RE_ENTRANT_CHECK_OFF;
|
||||||
RE_ENTRANT_CHECK_OFF;
|
FPU_code_access_ok(1);
|
||||||
FPU_code_access_ok(1);
|
FPU_get_user(displacement, (signed char __user *)(*fpu_eip));
|
||||||
FPU_get_user(displacement, (signed char __user *) (*fpu_eip));
|
offset += displacement;
|
||||||
offset += displacement;
|
RE_ENTRANT_CHECK_ON;
|
||||||
RE_ENTRANT_CHECK_ON;
|
(*fpu_eip)++;
|
||||||
(*fpu_eip)++;
|
} else if (mod == 2 || base == 5) { /* The second condition also has mod==0 */
|
||||||
}
|
/* 32 bit displacement */
|
||||||
else if (mod == 2 || base == 5) /* The second condition also has mod==0 */
|
long displacement;
|
||||||
{
|
RE_ENTRANT_CHECK_OFF;
|
||||||
/* 32 bit displacement */
|
FPU_code_access_ok(4);
|
||||||
long displacement;
|
FPU_get_user(displacement, (long __user *)(*fpu_eip));
|
||||||
RE_ENTRANT_CHECK_OFF;
|
offset += displacement;
|
||||||
FPU_code_access_ok(4);
|
RE_ENTRANT_CHECK_ON;
|
||||||
FPU_get_user(displacement, (long __user *) (*fpu_eip));
|
(*fpu_eip) += 4;
|
||||||
offset += displacement;
|
}
|
||||||
RE_ENTRANT_CHECK_ON;
|
|
||||||
(*fpu_eip) += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned long vm86_segment(u_char segment, struct address *addr)
|
||||||
static unsigned long vm86_segment(u_char segment,
|
|
||||||
struct address *addr)
|
|
||||||
{
|
{
|
||||||
segment--;
|
segment--;
|
||||||
#ifdef PARANOID
|
#ifdef PARANOID
|
||||||
if ( segment > PREFIX_SS_ )
|
if (segment > PREFIX_SS_) {
|
||||||
{
|
EXCEPTION(EX_INTERNAL | 0x130);
|
||||||
EXCEPTION(EX_INTERNAL|0x130);
|
math_abort(FPU_info, SIGSEGV);
|
||||||
math_abort(FPU_info,SIGSEGV);
|
}
|
||||||
}
|
|
||||||
#endif /* PARANOID */
|
#endif /* PARANOID */
|
||||||
addr->selector = VM86_REG_(segment);
|
addr->selector = VM86_REG_(segment);
|
||||||
return (unsigned long)VM86_REG_(segment) << 4;
|
return (unsigned long)VM86_REG_(segment) << 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* This should work for 16 and 32 bit protected mode. */
|
/* This should work for 16 and 32 bit protected mode. */
|
||||||
static long pm_address(u_char FPU_modrm, u_char segment,
|
static long pm_address(u_char FPU_modrm, u_char segment,
|
||||||
struct address *addr, long offset)
|
struct address *addr, long offset)
|
||||||
{
|
{
|
||||||
struct desc_struct descriptor;
|
struct desc_struct descriptor;
|
||||||
unsigned long base_address, limit, address, seg_top;
|
unsigned long base_address, limit, address, seg_top;
|
||||||
|
|
||||||
segment--;
|
segment--;
|
||||||
|
|
||||||
#ifdef PARANOID
|
#ifdef PARANOID
|
||||||
/* segment is unsigned, so this also detects if segment was 0: */
|
/* segment is unsigned, so this also detects if segment was 0: */
|
||||||
if ( segment > PREFIX_SS_ )
|
if (segment > PREFIX_SS_) {
|
||||||
{
|
EXCEPTION(EX_INTERNAL | 0x132);
|
||||||
EXCEPTION(EX_INTERNAL|0x132);
|
math_abort(FPU_info, SIGSEGV);
|
||||||
math_abort(FPU_info,SIGSEGV);
|
}
|
||||||
}
|
|
||||||
#endif /* PARANOID */
|
#endif /* PARANOID */
|
||||||
|
|
||||||
switch ( segment )
|
switch (segment) {
|
||||||
{
|
/* gs isn't used by the kernel, so it still has its
|
||||||
/* gs isn't used by the kernel, so it still has its
|
user-space value. */
|
||||||
user-space value. */
|
case PREFIX_GS_ - 1:
|
||||||
case PREFIX_GS_-1:
|
/* N.B. - movl %seg, mem is a 2 byte write regardless of prefix */
|
||||||
/* N.B. - movl %seg, mem is a 2 byte write regardless of prefix */
|
savesegment(gs, addr->selector);
|
||||||
savesegment(gs, addr->selector);
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
addr->selector = PM_REG_(segment);
|
||||||
addr->selector = PM_REG_(segment);
|
|
||||||
}
|
|
||||||
|
|
||||||
descriptor = LDT_DESCRIPTOR(PM_REG_(segment));
|
|
||||||
base_address = SEG_BASE_ADDR(descriptor);
|
|
||||||
address = base_address + offset;
|
|
||||||
limit = base_address
|
|
||||||
+ (SEG_LIMIT(descriptor)+1) * SEG_GRANULARITY(descriptor) - 1;
|
|
||||||
if ( limit < base_address ) limit = 0xffffffff;
|
|
||||||
|
|
||||||
if ( SEG_EXPAND_DOWN(descriptor) )
|
|
||||||
{
|
|
||||||
if ( SEG_G_BIT(descriptor) )
|
|
||||||
seg_top = 0xffffffff;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
seg_top = base_address + (1 << 20);
|
|
||||||
if ( seg_top < base_address ) seg_top = 0xffffffff;
|
|
||||||
}
|
}
|
||||||
access_limit =
|
|
||||||
(address <= limit) || (address >= seg_top) ? 0 :
|
|
||||||
((seg_top-address) >= 255 ? 255 : seg_top-address);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
access_limit =
|
|
||||||
(address > limit) || (address < base_address) ? 0 :
|
|
||||||
((limit-address) >= 254 ? 255 : limit-address+1);
|
|
||||||
}
|
|
||||||
if ( SEG_EXECUTE_ONLY(descriptor) ||
|
|
||||||
(!SEG_WRITE_PERM(descriptor) && (FPU_modrm & FPU_WRITE_BIT)) )
|
|
||||||
{
|
|
||||||
access_limit = 0;
|
|
||||||
}
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
descriptor = LDT_DESCRIPTOR(PM_REG_(segment));
|
||||||
|
base_address = SEG_BASE_ADDR(descriptor);
|
||||||
|
address = base_address + offset;
|
||||||
|
limit = base_address
|
||||||
|
+ (SEG_LIMIT(descriptor) + 1) * SEG_GRANULARITY(descriptor) - 1;
|
||||||
|
if (limit < base_address)
|
||||||
|
limit = 0xffffffff;
|
||||||
|
|
||||||
|
if (SEG_EXPAND_DOWN(descriptor)) {
|
||||||
|
if (SEG_G_BIT(descriptor))
|
||||||
|
seg_top = 0xffffffff;
|
||||||
|
else {
|
||||||
|
seg_top = base_address + (1 << 20);
|
||||||
|
if (seg_top < base_address)
|
||||||
|
seg_top = 0xffffffff;
|
||||||
|
}
|
||||||
|
access_limit =
|
||||||
|
(address <= limit) || (address >= seg_top) ? 0 :
|
||||||
|
((seg_top - address) >= 255 ? 255 : seg_top - address);
|
||||||
|
} else {
|
||||||
|
access_limit =
|
||||||
|
(address > limit) || (address < base_address) ? 0 :
|
||||||
|
((limit - address) >= 254 ? 255 : limit - address + 1);
|
||||||
|
}
|
||||||
|
if (SEG_EXECUTE_ONLY(descriptor) ||
|
||||||
|
(!SEG_WRITE_PERM(descriptor) && (FPU_modrm & FPU_WRITE_BIT))) {
|
||||||
|
access_limit = 0;
|
||||||
|
}
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
MOD R/M byte: MOD == 3 has a special use for the FPU
|
MOD R/M byte: MOD == 3 has a special use for the FPU
|
||||||
@@ -221,7 +202,6 @@ static long pm_address(u_char FPU_modrm, u_char segment,
|
|||||||
..... ......... .........
|
..... ......... .........
|
||||||
MOD OPCODE(2) R/M
|
MOD OPCODE(2) R/M
|
||||||
|
|
||||||
|
|
||||||
SIB byte
|
SIB byte
|
||||||
|
|
||||||
7 6 5 4 3 2 1 0
|
7 6 5 4 3 2 1 0
|
||||||
@@ -231,208 +211,194 @@ static long pm_address(u_char FPU_modrm, u_char segment,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
void __user *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip,
|
void __user *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip,
|
||||||
struct address *addr,
|
struct address *addr, fpu_addr_modes addr_modes)
|
||||||
fpu_addr_modes addr_modes)
|
|
||||||
{
|
{
|
||||||
u_char mod;
|
u_char mod;
|
||||||
unsigned rm = FPU_modrm & 7;
|
unsigned rm = FPU_modrm & 7;
|
||||||
long *cpu_reg_ptr;
|
long *cpu_reg_ptr;
|
||||||
int address = 0; /* Initialized just to stop compiler warnings. */
|
int address = 0; /* Initialized just to stop compiler warnings. */
|
||||||
|
|
||||||
/* Memory accessed via the cs selector is write protected
|
/* Memory accessed via the cs selector is write protected
|
||||||
in `non-segmented' 32 bit protected mode. */
|
in `non-segmented' 32 bit protected mode. */
|
||||||
if ( !addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT)
|
if (!addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT)
|
||||||
&& (addr_modes.override.segment == PREFIX_CS_) )
|
&& (addr_modes.override.segment == PREFIX_CS_)) {
|
||||||
{
|
math_abort(FPU_info, SIGSEGV);
|
||||||
math_abort(FPU_info,SIGSEGV);
|
|
||||||
}
|
|
||||||
|
|
||||||
addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */
|
|
||||||
|
|
||||||
mod = (FPU_modrm >> 6) & 3;
|
|
||||||
|
|
||||||
if (rm == 4 && mod != 3)
|
|
||||||
{
|
|
||||||
address = sib(mod, fpu_eip);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cpu_reg_ptr = & REG_(rm);
|
|
||||||
switch (mod)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
if (rm == 5)
|
|
||||||
{
|
|
||||||
/* Special case: disp32 */
|
|
||||||
RE_ENTRANT_CHECK_OFF;
|
|
||||||
FPU_code_access_ok(4);
|
|
||||||
FPU_get_user(address, (unsigned long __user *) (*fpu_eip));
|
|
||||||
(*fpu_eip) += 4;
|
|
||||||
RE_ENTRANT_CHECK_ON;
|
|
||||||
addr->offset = address;
|
|
||||||
return (void __user *) address;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
address = *cpu_reg_ptr; /* Just return the contents
|
|
||||||
of the cpu register */
|
|
||||||
addr->offset = address;
|
|
||||||
return (void __user *) address;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
/* 8 bit signed displacement */
|
|
||||||
RE_ENTRANT_CHECK_OFF;
|
|
||||||
FPU_code_access_ok(1);
|
|
||||||
FPU_get_user(address, (signed char __user *) (*fpu_eip));
|
|
||||||
RE_ENTRANT_CHECK_ON;
|
|
||||||
(*fpu_eip)++;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
/* 32 bit displacement */
|
|
||||||
RE_ENTRANT_CHECK_OFF;
|
|
||||||
FPU_code_access_ok(4);
|
|
||||||
FPU_get_user(address, (long __user *) (*fpu_eip));
|
|
||||||
(*fpu_eip) += 4;
|
|
||||||
RE_ENTRANT_CHECK_ON;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
/* Not legal for the FPU */
|
|
||||||
EXCEPTION(EX_Invalid);
|
|
||||||
}
|
}
|
||||||
address += *cpu_reg_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr->offset = address;
|
addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */
|
||||||
|
|
||||||
switch ( addr_modes.default_mode )
|
mod = (FPU_modrm >> 6) & 3;
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
case VM86:
|
|
||||||
address += vm86_segment(addr_modes.override.segment, addr);
|
|
||||||
break;
|
|
||||||
case PM16:
|
|
||||||
case SEG32:
|
|
||||||
address = pm_address(FPU_modrm, addr_modes.override.segment,
|
|
||||||
addr, address);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
EXCEPTION(EX_INTERNAL|0x133);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (void __user *)address;
|
if (rm == 4 && mod != 3) {
|
||||||
|
address = sib(mod, fpu_eip);
|
||||||
|
} else {
|
||||||
|
cpu_reg_ptr = ®_(rm);
|
||||||
|
switch (mod) {
|
||||||
|
case 0:
|
||||||
|
if (rm == 5) {
|
||||||
|
/* Special case: disp32 */
|
||||||
|
RE_ENTRANT_CHECK_OFF;
|
||||||
|
FPU_code_access_ok(4);
|
||||||
|
FPU_get_user(address,
|
||||||
|
(unsigned long __user
|
||||||
|
*)(*fpu_eip));
|
||||||
|
(*fpu_eip) += 4;
|
||||||
|
RE_ENTRANT_CHECK_ON;
|
||||||
|
addr->offset = address;
|
||||||
|
return (void __user *)address;
|
||||||
|
} else {
|
||||||
|
address = *cpu_reg_ptr; /* Just return the contents
|
||||||
|
of the cpu register */
|
||||||
|
addr->offset = address;
|
||||||
|
return (void __user *)address;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
/* 8 bit signed displacement */
|
||||||
|
RE_ENTRANT_CHECK_OFF;
|
||||||
|
FPU_code_access_ok(1);
|
||||||
|
FPU_get_user(address, (signed char __user *)(*fpu_eip));
|
||||||
|
RE_ENTRANT_CHECK_ON;
|
||||||
|
(*fpu_eip)++;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
/* 32 bit displacement */
|
||||||
|
RE_ENTRANT_CHECK_OFF;
|
||||||
|
FPU_code_access_ok(4);
|
||||||
|
FPU_get_user(address, (long __user *)(*fpu_eip));
|
||||||
|
(*fpu_eip) += 4;
|
||||||
|
RE_ENTRANT_CHECK_ON;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
/* Not legal for the FPU */
|
||||||
|
EXCEPTION(EX_Invalid);
|
||||||
|
}
|
||||||
|
address += *cpu_reg_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr->offset = address;
|
||||||
|
|
||||||
|
switch (addr_modes.default_mode) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case VM86:
|
||||||
|
address += vm86_segment(addr_modes.override.segment, addr);
|
||||||
|
break;
|
||||||
|
case PM16:
|
||||||
|
case SEG32:
|
||||||
|
address = pm_address(FPU_modrm, addr_modes.override.segment,
|
||||||
|
addr, address);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
EXCEPTION(EX_INTERNAL | 0x133);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (void __user *)address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void __user *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip,
|
void __user *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip,
|
||||||
struct address *addr,
|
struct address *addr, fpu_addr_modes addr_modes)
|
||||||
fpu_addr_modes addr_modes)
|
|
||||||
{
|
{
|
||||||
u_char mod;
|
u_char mod;
|
||||||
unsigned rm = FPU_modrm & 7;
|
unsigned rm = FPU_modrm & 7;
|
||||||
int address = 0; /* Default used for mod == 0 */
|
int address = 0; /* Default used for mod == 0 */
|
||||||
|
|
||||||
/* Memory accessed via the cs selector is write protected
|
/* Memory accessed via the cs selector is write protected
|
||||||
in `non-segmented' 32 bit protected mode. */
|
in `non-segmented' 32 bit protected mode. */
|
||||||
if ( !addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT)
|
if (!addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT)
|
||||||
&& (addr_modes.override.segment == PREFIX_CS_) )
|
&& (addr_modes.override.segment == PREFIX_CS_)) {
|
||||||
{
|
math_abort(FPU_info, SIGSEGV);
|
||||||
math_abort(FPU_info,SIGSEGV);
|
|
||||||
}
|
|
||||||
|
|
||||||
addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */
|
|
||||||
|
|
||||||
mod = (FPU_modrm >> 6) & 3;
|
|
||||||
|
|
||||||
switch (mod)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
if (rm == 6)
|
|
||||||
{
|
|
||||||
/* Special case: disp16 */
|
|
||||||
RE_ENTRANT_CHECK_OFF;
|
|
||||||
FPU_code_access_ok(2);
|
|
||||||
FPU_get_user(address, (unsigned short __user *) (*fpu_eip));
|
|
||||||
(*fpu_eip) += 2;
|
|
||||||
RE_ENTRANT_CHECK_ON;
|
|
||||||
goto add_segment;
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
/* 8 bit signed displacement */
|
|
||||||
RE_ENTRANT_CHECK_OFF;
|
|
||||||
FPU_code_access_ok(1);
|
|
||||||
FPU_get_user(address, (signed char __user *) (*fpu_eip));
|
|
||||||
RE_ENTRANT_CHECK_ON;
|
|
||||||
(*fpu_eip)++;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
/* 16 bit displacement */
|
|
||||||
RE_ENTRANT_CHECK_OFF;
|
|
||||||
FPU_code_access_ok(2);
|
|
||||||
FPU_get_user(address, (unsigned short __user *) (*fpu_eip));
|
|
||||||
(*fpu_eip) += 2;
|
|
||||||
RE_ENTRANT_CHECK_ON;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
/* Not legal for the FPU */
|
|
||||||
EXCEPTION(EX_Invalid);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
switch ( rm )
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
address += FPU_info->___ebx + FPU_info->___esi;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
address += FPU_info->___ebx + FPU_info->___edi;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
address += FPU_info->___ebp + FPU_info->___esi;
|
|
||||||
if ( addr_modes.override.segment == PREFIX_DEFAULT )
|
|
||||||
addr_modes.override.segment = PREFIX_SS_;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
address += FPU_info->___ebp + FPU_info->___edi;
|
|
||||||
if ( addr_modes.override.segment == PREFIX_DEFAULT )
|
|
||||||
addr_modes.override.segment = PREFIX_SS_;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
address += FPU_info->___esi;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
address += FPU_info->___edi;
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
address += FPU_info->___ebp;
|
|
||||||
if ( addr_modes.override.segment == PREFIX_DEFAULT )
|
|
||||||
addr_modes.override.segment = PREFIX_SS_;
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
address += FPU_info->___ebx;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
add_segment:
|
addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */
|
||||||
address &= 0xffff;
|
|
||||||
|
|
||||||
addr->offset = address;
|
mod = (FPU_modrm >> 6) & 3;
|
||||||
|
|
||||||
switch ( addr_modes.default_mode )
|
switch (mod) {
|
||||||
{
|
case 0:
|
||||||
case 0:
|
if (rm == 6) {
|
||||||
break;
|
/* Special case: disp16 */
|
||||||
case VM86:
|
RE_ENTRANT_CHECK_OFF;
|
||||||
address += vm86_segment(addr_modes.override.segment, addr);
|
FPU_code_access_ok(2);
|
||||||
break;
|
FPU_get_user(address,
|
||||||
case PM16:
|
(unsigned short __user *)(*fpu_eip));
|
||||||
case SEG32:
|
(*fpu_eip) += 2;
|
||||||
address = pm_address(FPU_modrm, addr_modes.override.segment,
|
RE_ENTRANT_CHECK_ON;
|
||||||
addr, address);
|
goto add_segment;
|
||||||
break;
|
}
|
||||||
default:
|
break;
|
||||||
EXCEPTION(EX_INTERNAL|0x131);
|
case 1:
|
||||||
}
|
/* 8 bit signed displacement */
|
||||||
|
RE_ENTRANT_CHECK_OFF;
|
||||||
|
FPU_code_access_ok(1);
|
||||||
|
FPU_get_user(address, (signed char __user *)(*fpu_eip));
|
||||||
|
RE_ENTRANT_CHECK_ON;
|
||||||
|
(*fpu_eip)++;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
/* 16 bit displacement */
|
||||||
|
RE_ENTRANT_CHECK_OFF;
|
||||||
|
FPU_code_access_ok(2);
|
||||||
|
FPU_get_user(address, (unsigned short __user *)(*fpu_eip));
|
||||||
|
(*fpu_eip) += 2;
|
||||||
|
RE_ENTRANT_CHECK_ON;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
/* Not legal for the FPU */
|
||||||
|
EXCEPTION(EX_Invalid);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (rm) {
|
||||||
|
case 0:
|
||||||
|
address += FPU_info->___ebx + FPU_info->___esi;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
address += FPU_info->___ebx + FPU_info->___edi;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
address += FPU_info->___ebp + FPU_info->___esi;
|
||||||
|
if (addr_modes.override.segment == PREFIX_DEFAULT)
|
||||||
|
addr_modes.override.segment = PREFIX_SS_;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
address += FPU_info->___ebp + FPU_info->___edi;
|
||||||
|
if (addr_modes.override.segment == PREFIX_DEFAULT)
|
||||||
|
addr_modes.override.segment = PREFIX_SS_;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
address += FPU_info->___esi;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
address += FPU_info->___edi;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
address += FPU_info->___ebp;
|
||||||
|
if (addr_modes.override.segment == PREFIX_DEFAULT)
|
||||||
|
addr_modes.override.segment = PREFIX_SS_;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
address += FPU_info->___ebx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return (void __user *)address ;
|
add_segment:
|
||||||
|
address &= 0xffff;
|
||||||
|
|
||||||
|
addr->offset = address;
|
||||||
|
|
||||||
|
switch (addr_modes.default_mode) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case VM86:
|
||||||
|
address += vm86_segment(addr_modes.override.segment, addr);
|
||||||
|
break;
|
||||||
|
case PM16:
|
||||||
|
case SEG32:
|
||||||
|
address = pm_address(FPU_modrm, addr_modes.override.segment,
|
||||||
|
addr, address);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
EXCEPTION(EX_INTERNAL | 0x131);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (void __user *)address;
|
||||||
}
|
}
|
||||||
|
@@ -26,247 +26,257 @@
|
|||||||
#include "status_w.h"
|
#include "status_w.h"
|
||||||
#include "control_w.h"
|
#include "control_w.h"
|
||||||
|
|
||||||
|
#define _NONE_ 0 /* st0_ptr etc not needed */
|
||||||
#define _NONE_ 0 /* st0_ptr etc not needed */
|
#define _REG0_ 1 /* Will be storing st(0) */
|
||||||
#define _REG0_ 1 /* Will be storing st(0) */
|
#define _PUSH_ 3 /* Need to check for space to push onto stack */
|
||||||
#define _PUSH_ 3 /* Need to check for space to push onto stack */
|
#define _null_ 4 /* Function illegal or not implemented */
|
||||||
#define _null_ 4 /* Function illegal or not implemented */
|
|
||||||
|
|
||||||
#define pop_0() { FPU_settag0(TAG_Empty); top++; }
|
#define pop_0() { FPU_settag0(TAG_Empty); top++; }
|
||||||
|
|
||||||
|
|
||||||
static u_char const type_table[32] = {
|
static u_char const type_table[32] = {
|
||||||
_PUSH_, _PUSH_, _PUSH_, _PUSH_,
|
_PUSH_, _PUSH_, _PUSH_, _PUSH_,
|
||||||
_null_, _null_, _null_, _null_,
|
_null_, _null_, _null_, _null_,
|
||||||
_REG0_, _REG0_, _REG0_, _REG0_,
|
_REG0_, _REG0_, _REG0_, _REG0_,
|
||||||
_REG0_, _REG0_, _REG0_, _REG0_,
|
_REG0_, _REG0_, _REG0_, _REG0_,
|
||||||
_NONE_, _null_, _NONE_, _PUSH_,
|
_NONE_, _null_, _NONE_, _PUSH_,
|
||||||
_NONE_, _PUSH_, _null_, _PUSH_,
|
_NONE_, _PUSH_, _null_, _PUSH_,
|
||||||
_NONE_, _null_, _NONE_, _REG0_,
|
_NONE_, _null_, _NONE_, _REG0_,
|
||||||
_NONE_, _REG0_, _NONE_, _REG0_
|
_NONE_, _REG0_, _NONE_, _REG0_
|
||||||
};
|
};
|
||||||
|
|
||||||
u_char const data_sizes_16[32] = {
|
u_char const data_sizes_16[32] = {
|
||||||
4, 4, 8, 2, 0, 0, 0, 0,
|
4, 4, 8, 2, 0, 0, 0, 0,
|
||||||
4, 4, 8, 2, 4, 4, 8, 2,
|
4, 4, 8, 2, 4, 4, 8, 2,
|
||||||
14, 0, 94, 10, 2, 10, 0, 8,
|
14, 0, 94, 10, 2, 10, 0, 8,
|
||||||
14, 0, 94, 10, 2, 10, 2, 8
|
14, 0, 94, 10, 2, 10, 2, 8
|
||||||
};
|
};
|
||||||
|
|
||||||
static u_char const data_sizes_32[32] = {
|
static u_char const data_sizes_32[32] = {
|
||||||
4, 4, 8, 2, 0, 0, 0, 0,
|
4, 4, 8, 2, 0, 0, 0, 0,
|
||||||
4, 4, 8, 2, 4, 4, 8, 2,
|
4, 4, 8, 2, 4, 4, 8, 2,
|
||||||
28, 0,108, 10, 2, 10, 0, 8,
|
28, 0, 108, 10, 2, 10, 0, 8,
|
||||||
28, 0,108, 10, 2, 10, 2, 8
|
28, 0, 108, 10, 2, 10, 2, 8
|
||||||
};
|
};
|
||||||
|
|
||||||
int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
|
int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
|
||||||
void __user *data_address)
|
void __user * data_address)
|
||||||
{
|
{
|
||||||
FPU_REG loaded_data;
|
FPU_REG loaded_data;
|
||||||
FPU_REG *st0_ptr;
|
FPU_REG *st0_ptr;
|
||||||
u_char st0_tag = TAG_Empty; /* This is just to stop a gcc warning. */
|
u_char st0_tag = TAG_Empty; /* This is just to stop a gcc warning. */
|
||||||
u_char loaded_tag;
|
u_char loaded_tag;
|
||||||
|
|
||||||
st0_ptr = NULL; /* Initialized just to stop compiler warnings. */
|
st0_ptr = NULL; /* Initialized just to stop compiler warnings. */
|
||||||
|
|
||||||
if ( addr_modes.default_mode & PROTECTED )
|
if (addr_modes.default_mode & PROTECTED) {
|
||||||
{
|
if (addr_modes.default_mode == SEG32) {
|
||||||
if ( addr_modes.default_mode == SEG32 )
|
if (access_limit < data_sizes_32[type])
|
||||||
{
|
math_abort(FPU_info, SIGSEGV);
|
||||||
if ( access_limit < data_sizes_32[type] )
|
} else if (addr_modes.default_mode == PM16) {
|
||||||
math_abort(FPU_info,SIGSEGV);
|
if (access_limit < data_sizes_16[type])
|
||||||
}
|
math_abort(FPU_info, SIGSEGV);
|
||||||
else if ( addr_modes.default_mode == PM16 )
|
}
|
||||||
{
|
|
||||||
if ( access_limit < data_sizes_16[type] )
|
|
||||||
math_abort(FPU_info,SIGSEGV);
|
|
||||||
}
|
|
||||||
#ifdef PARANOID
|
#ifdef PARANOID
|
||||||
else
|
else
|
||||||
EXCEPTION(EX_INTERNAL|0x140);
|
EXCEPTION(EX_INTERNAL | 0x140);
|
||||||
#endif /* PARANOID */
|
#endif /* PARANOID */
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ( type_table[type] )
|
switch (type_table[type]) {
|
||||||
{
|
case _NONE_:
|
||||||
case _NONE_:
|
break;
|
||||||
break;
|
case _REG0_:
|
||||||
case _REG0_:
|
st0_ptr = &st(0); /* Some of these instructions pop after
|
||||||
st0_ptr = &st(0); /* Some of these instructions pop after
|
storing */
|
||||||
storing */
|
st0_tag = FPU_gettag0();
|
||||||
st0_tag = FPU_gettag0();
|
break;
|
||||||
break;
|
case _PUSH_:
|
||||||
case _PUSH_:
|
{
|
||||||
{
|
if (FPU_gettagi(-1) != TAG_Empty) {
|
||||||
if ( FPU_gettagi(-1) != TAG_Empty )
|
FPU_stack_overflow();
|
||||||
{ FPU_stack_overflow(); return 0; }
|
return 0;
|
||||||
top--;
|
}
|
||||||
st0_ptr = &st(0);
|
top--;
|
||||||
}
|
st0_ptr = &st(0);
|
||||||
break;
|
}
|
||||||
case _null_:
|
break;
|
||||||
FPU_illegal();
|
case _null_:
|
||||||
return 0;
|
FPU_illegal();
|
||||||
|
return 0;
|
||||||
#ifdef PARANOID
|
#ifdef PARANOID
|
||||||
default:
|
default:
|
||||||
EXCEPTION(EX_INTERNAL|0x141);
|
EXCEPTION(EX_INTERNAL | 0x141);
|
||||||
return 0;
|
return 0;
|
||||||
#endif /* PARANOID */
|
#endif /* PARANOID */
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ( type )
|
switch (type) {
|
||||||
{
|
case 000: /* fld m32real */
|
||||||
case 000: /* fld m32real */
|
clear_C1();
|
||||||
clear_C1();
|
loaded_tag =
|
||||||
loaded_tag = FPU_load_single((float __user *)data_address, &loaded_data);
|
FPU_load_single((float __user *)data_address, &loaded_data);
|
||||||
if ( (loaded_tag == TAG_Special)
|
if ((loaded_tag == TAG_Special)
|
||||||
&& isNaN(&loaded_data)
|
&& isNaN(&loaded_data)
|
||||||
&& (real_1op_NaN(&loaded_data) < 0) )
|
&& (real_1op_NaN(&loaded_data) < 0)) {
|
||||||
{
|
top++;
|
||||||
top++;
|
break;
|
||||||
break;
|
}
|
||||||
}
|
FPU_copy_to_reg0(&loaded_data, loaded_tag);
|
||||||
FPU_copy_to_reg0(&loaded_data, loaded_tag);
|
break;
|
||||||
break;
|
case 001: /* fild m32int */
|
||||||
case 001: /* fild m32int */
|
clear_C1();
|
||||||
clear_C1();
|
loaded_tag =
|
||||||
loaded_tag = FPU_load_int32((long __user *)data_address, &loaded_data);
|
FPU_load_int32((long __user *)data_address, &loaded_data);
|
||||||
FPU_copy_to_reg0(&loaded_data, loaded_tag);
|
FPU_copy_to_reg0(&loaded_data, loaded_tag);
|
||||||
break;
|
break;
|
||||||
case 002: /* fld m64real */
|
case 002: /* fld m64real */
|
||||||
clear_C1();
|
clear_C1();
|
||||||
loaded_tag = FPU_load_double((double __user *)data_address, &loaded_data);
|
loaded_tag =
|
||||||
if ( (loaded_tag == TAG_Special)
|
FPU_load_double((double __user *)data_address,
|
||||||
&& isNaN(&loaded_data)
|
&loaded_data);
|
||||||
&& (real_1op_NaN(&loaded_data) < 0) )
|
if ((loaded_tag == TAG_Special)
|
||||||
{
|
&& isNaN(&loaded_data)
|
||||||
top++;
|
&& (real_1op_NaN(&loaded_data) < 0)) {
|
||||||
break;
|
top++;
|
||||||
}
|
break;
|
||||||
FPU_copy_to_reg0(&loaded_data, loaded_tag);
|
}
|
||||||
break;
|
FPU_copy_to_reg0(&loaded_data, loaded_tag);
|
||||||
case 003: /* fild m16int */
|
break;
|
||||||
clear_C1();
|
case 003: /* fild m16int */
|
||||||
loaded_tag = FPU_load_int16((short __user *)data_address, &loaded_data);
|
clear_C1();
|
||||||
FPU_copy_to_reg0(&loaded_data, loaded_tag);
|
loaded_tag =
|
||||||
break;
|
FPU_load_int16((short __user *)data_address, &loaded_data);
|
||||||
case 010: /* fst m32real */
|
FPU_copy_to_reg0(&loaded_data, loaded_tag);
|
||||||
clear_C1();
|
break;
|
||||||
FPU_store_single(st0_ptr, st0_tag, (float __user *)data_address);
|
case 010: /* fst m32real */
|
||||||
break;
|
clear_C1();
|
||||||
case 011: /* fist m32int */
|
FPU_store_single(st0_ptr, st0_tag,
|
||||||
clear_C1();
|
(float __user *)data_address);
|
||||||
FPU_store_int32(st0_ptr, st0_tag, (long __user *)data_address);
|
break;
|
||||||
break;
|
case 011: /* fist m32int */
|
||||||
case 012: /* fst m64real */
|
clear_C1();
|
||||||
clear_C1();
|
FPU_store_int32(st0_ptr, st0_tag, (long __user *)data_address);
|
||||||
FPU_store_double(st0_ptr, st0_tag, (double __user *)data_address);
|
break;
|
||||||
break;
|
case 012: /* fst m64real */
|
||||||
case 013: /* fist m16int */
|
clear_C1();
|
||||||
clear_C1();
|
FPU_store_double(st0_ptr, st0_tag,
|
||||||
FPU_store_int16(st0_ptr, st0_tag, (short __user *)data_address);
|
(double __user *)data_address);
|
||||||
break;
|
break;
|
||||||
case 014: /* fstp m32real */
|
case 013: /* fist m16int */
|
||||||
clear_C1();
|
clear_C1();
|
||||||
if ( FPU_store_single(st0_ptr, st0_tag, (float __user *)data_address) )
|
FPU_store_int16(st0_ptr, st0_tag, (short __user *)data_address);
|
||||||
pop_0(); /* pop only if the number was actually stored
|
break;
|
||||||
(see the 80486 manual p16-28) */
|
case 014: /* fstp m32real */
|
||||||
break;
|
clear_C1();
|
||||||
case 015: /* fistp m32int */
|
if (FPU_store_single
|
||||||
clear_C1();
|
(st0_ptr, st0_tag, (float __user *)data_address))
|
||||||
if ( FPU_store_int32(st0_ptr, st0_tag, (long __user *)data_address) )
|
pop_0(); /* pop only if the number was actually stored
|
||||||
pop_0(); /* pop only if the number was actually stored
|
(see the 80486 manual p16-28) */
|
||||||
(see the 80486 manual p16-28) */
|
break;
|
||||||
break;
|
case 015: /* fistp m32int */
|
||||||
case 016: /* fstp m64real */
|
clear_C1();
|
||||||
clear_C1();
|
if (FPU_store_int32
|
||||||
if ( FPU_store_double(st0_ptr, st0_tag, (double __user *)data_address) )
|
(st0_ptr, st0_tag, (long __user *)data_address))
|
||||||
pop_0(); /* pop only if the number was actually stored
|
pop_0(); /* pop only if the number was actually stored
|
||||||
(see the 80486 manual p16-28) */
|
(see the 80486 manual p16-28) */
|
||||||
break;
|
break;
|
||||||
case 017: /* fistp m16int */
|
case 016: /* fstp m64real */
|
||||||
clear_C1();
|
clear_C1();
|
||||||
if ( FPU_store_int16(st0_ptr, st0_tag, (short __user *)data_address) )
|
if (FPU_store_double
|
||||||
pop_0(); /* pop only if the number was actually stored
|
(st0_ptr, st0_tag, (double __user *)data_address))
|
||||||
(see the 80486 manual p16-28) */
|
pop_0(); /* pop only if the number was actually stored
|
||||||
break;
|
(see the 80486 manual p16-28) */
|
||||||
case 020: /* fldenv m14/28byte */
|
break;
|
||||||
fldenv(addr_modes, (u_char __user *)data_address);
|
case 017: /* fistp m16int */
|
||||||
/* Ensure that the values just loaded are not changed by
|
clear_C1();
|
||||||
fix-up operations. */
|
if (FPU_store_int16
|
||||||
return 1;
|
(st0_ptr, st0_tag, (short __user *)data_address))
|
||||||
case 022: /* frstor m94/108byte */
|
pop_0(); /* pop only if the number was actually stored
|
||||||
frstor(addr_modes, (u_char __user *)data_address);
|
(see the 80486 manual p16-28) */
|
||||||
/* Ensure that the values just loaded are not changed by
|
break;
|
||||||
fix-up operations. */
|
case 020: /* fldenv m14/28byte */
|
||||||
return 1;
|
fldenv(addr_modes, (u_char __user *) data_address);
|
||||||
case 023: /* fbld m80dec */
|
/* Ensure that the values just loaded are not changed by
|
||||||
clear_C1();
|
fix-up operations. */
|
||||||
loaded_tag = FPU_load_bcd((u_char __user *)data_address);
|
return 1;
|
||||||
FPU_settag0(loaded_tag);
|
case 022: /* frstor m94/108byte */
|
||||||
break;
|
frstor(addr_modes, (u_char __user *) data_address);
|
||||||
case 024: /* fldcw */
|
/* Ensure that the values just loaded are not changed by
|
||||||
RE_ENTRANT_CHECK_OFF;
|
fix-up operations. */
|
||||||
FPU_access_ok(VERIFY_READ, data_address, 2);
|
return 1;
|
||||||
FPU_get_user(control_word, (unsigned short __user *) data_address);
|
case 023: /* fbld m80dec */
|
||||||
RE_ENTRANT_CHECK_ON;
|
clear_C1();
|
||||||
if ( partial_status & ~control_word & CW_Exceptions )
|
loaded_tag = FPU_load_bcd((u_char __user *) data_address);
|
||||||
partial_status |= (SW_Summary | SW_Backward);
|
FPU_settag0(loaded_tag);
|
||||||
else
|
break;
|
||||||
partial_status &= ~(SW_Summary | SW_Backward);
|
case 024: /* fldcw */
|
||||||
|
RE_ENTRANT_CHECK_OFF;
|
||||||
|
FPU_access_ok(VERIFY_READ, data_address, 2);
|
||||||
|
FPU_get_user(control_word,
|
||||||
|
(unsigned short __user *)data_address);
|
||||||
|
RE_ENTRANT_CHECK_ON;
|
||||||
|
if (partial_status & ~control_word & CW_Exceptions)
|
||||||
|
partial_status |= (SW_Summary | SW_Backward);
|
||||||
|
else
|
||||||
|
partial_status &= ~(SW_Summary | SW_Backward);
|
||||||
#ifdef PECULIAR_486
|
#ifdef PECULIAR_486
|
||||||
control_word |= 0x40; /* An 80486 appears to always set this bit */
|
control_word |= 0x40; /* An 80486 appears to always set this bit */
|
||||||
#endif /* PECULIAR_486 */
|
#endif /* PECULIAR_486 */
|
||||||
return 1;
|
return 1;
|
||||||
case 025: /* fld m80real */
|
case 025: /* fld m80real */
|
||||||
clear_C1();
|
clear_C1();
|
||||||
loaded_tag = FPU_load_extended((long double __user *)data_address, 0);
|
loaded_tag =
|
||||||
FPU_settag0(loaded_tag);
|
FPU_load_extended((long double __user *)data_address, 0);
|
||||||
break;
|
FPU_settag0(loaded_tag);
|
||||||
case 027: /* fild m64int */
|
break;
|
||||||
clear_C1();
|
case 027: /* fild m64int */
|
||||||
loaded_tag = FPU_load_int64((long long __user *)data_address);
|
clear_C1();
|
||||||
if (loaded_tag == TAG_Error)
|
loaded_tag = FPU_load_int64((long long __user *)data_address);
|
||||||
|
if (loaded_tag == TAG_Error)
|
||||||
|
return 0;
|
||||||
|
FPU_settag0(loaded_tag);
|
||||||
|
break;
|
||||||
|
case 030: /* fstenv m14/28byte */
|
||||||
|
fstenv(addr_modes, (u_char __user *) data_address);
|
||||||
|
return 1;
|
||||||
|
case 032: /* fsave */
|
||||||
|
fsave(addr_modes, (u_char __user *) data_address);
|
||||||
|
return 1;
|
||||||
|
case 033: /* fbstp m80dec */
|
||||||
|
clear_C1();
|
||||||
|
if (FPU_store_bcd
|
||||||
|
(st0_ptr, st0_tag, (u_char __user *) data_address))
|
||||||
|
pop_0(); /* pop only if the number was actually stored
|
||||||
|
(see the 80486 manual p16-28) */
|
||||||
|
break;
|
||||||
|
case 034: /* fstcw m16int */
|
||||||
|
RE_ENTRANT_CHECK_OFF;
|
||||||
|
FPU_access_ok(VERIFY_WRITE, data_address, 2);
|
||||||
|
FPU_put_user(control_word,
|
||||||
|
(unsigned short __user *)data_address);
|
||||||
|
RE_ENTRANT_CHECK_ON;
|
||||||
|
return 1;
|
||||||
|
case 035: /* fstp m80real */
|
||||||
|
clear_C1();
|
||||||
|
if (FPU_store_extended
|
||||||
|
(st0_ptr, st0_tag, (long double __user *)data_address))
|
||||||
|
pop_0(); /* pop only if the number was actually stored
|
||||||
|
(see the 80486 manual p16-28) */
|
||||||
|
break;
|
||||||
|
case 036: /* fstsw m2byte */
|
||||||
|
RE_ENTRANT_CHECK_OFF;
|
||||||
|
FPU_access_ok(VERIFY_WRITE, data_address, 2);
|
||||||
|
FPU_put_user(status_word(),
|
||||||
|
(unsigned short __user *)data_address);
|
||||||
|
RE_ENTRANT_CHECK_ON;
|
||||||
|
return 1;
|
||||||
|
case 037: /* fistp m64int */
|
||||||
|
clear_C1();
|
||||||
|
if (FPU_store_int64
|
||||||
|
(st0_ptr, st0_tag, (long long __user *)data_address))
|
||||||
|
pop_0(); /* pop only if the number was actually stored
|
||||||
|
(see the 80486 manual p16-28) */
|
||||||
|
break;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
FPU_settag0(loaded_tag);
|
|
||||||
break;
|
|
||||||
case 030: /* fstenv m14/28byte */
|
|
||||||
fstenv(addr_modes, (u_char __user *)data_address);
|
|
||||||
return 1;
|
|
||||||
case 032: /* fsave */
|
|
||||||
fsave(addr_modes, (u_char __user *)data_address);
|
|
||||||
return 1;
|
|
||||||
case 033: /* fbstp m80dec */
|
|
||||||
clear_C1();
|
|
||||||
if ( FPU_store_bcd(st0_ptr, st0_tag, (u_char __user *)data_address) )
|
|
||||||
pop_0(); /* pop only if the number was actually stored
|
|
||||||
(see the 80486 manual p16-28) */
|
|
||||||
break;
|
|
||||||
case 034: /* fstcw m16int */
|
|
||||||
RE_ENTRANT_CHECK_OFF;
|
|
||||||
FPU_access_ok(VERIFY_WRITE,data_address,2);
|
|
||||||
FPU_put_user(control_word, (unsigned short __user *) data_address);
|
|
||||||
RE_ENTRANT_CHECK_ON;
|
|
||||||
return 1;
|
|
||||||
case 035: /* fstp m80real */
|
|
||||||
clear_C1();
|
|
||||||
if ( FPU_store_extended(st0_ptr, st0_tag, (long double __user *)data_address) )
|
|
||||||
pop_0(); /* pop only if the number was actually stored
|
|
||||||
(see the 80486 manual p16-28) */
|
|
||||||
break;
|
|
||||||
case 036: /* fstsw m2byte */
|
|
||||||
RE_ENTRANT_CHECK_OFF;
|
|
||||||
FPU_access_ok(VERIFY_WRITE,data_address,2);
|
|
||||||
FPU_put_user(status_word(),(unsigned short __user *) data_address);
|
|
||||||
RE_ENTRANT_CHECK_ON;
|
|
||||||
return 1;
|
|
||||||
case 037: /* fistp m64int */
|
|
||||||
clear_C1();
|
|
||||||
if ( FPU_store_int64(st0_ptr, st0_tag, (long long __user *)data_address) )
|
|
||||||
pop_0(); /* pop only if the number was actually stored
|
|
||||||
(see the 80486 manual p16-28) */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
@@ -21,9 +21,9 @@
|
|||||||
allows. 9-byte would probably be sufficient.
|
allows. 9-byte would probably be sufficient.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned long lsw;
|
unsigned long lsw;
|
||||||
unsigned long midw;
|
unsigned long midw;
|
||||||
unsigned long msw;
|
unsigned long msw;
|
||||||
} Xsig;
|
} Xsig;
|
||||||
|
|
||||||
asmlinkage void mul64(unsigned long long const *a, unsigned long long const *b,
|
asmlinkage void mul64(unsigned long long const *a, unsigned long long const *b,
|
||||||
@@ -33,12 +33,12 @@ asmlinkage void polynomial_Xsig(Xsig *, const unsigned long long *x,
|
|||||||
|
|
||||||
asmlinkage void mul32_Xsig(Xsig *, const unsigned long mult);
|
asmlinkage void mul32_Xsig(Xsig *, const unsigned long mult);
|
||||||
asmlinkage void mul64_Xsig(Xsig *, const unsigned long long *mult);
|
asmlinkage void mul64_Xsig(Xsig *, const unsigned long long *mult);
|
||||||
asmlinkage void mul_Xsig_Xsig(Xsig *dest, const Xsig *mult);
|
asmlinkage void mul_Xsig_Xsig(Xsig * dest, const Xsig * mult);
|
||||||
|
|
||||||
asmlinkage void shr_Xsig(Xsig *, const int n);
|
asmlinkage void shr_Xsig(Xsig *, const int n);
|
||||||
asmlinkage int round_Xsig(Xsig *);
|
asmlinkage int round_Xsig(Xsig *);
|
||||||
asmlinkage int norm_Xsig(Xsig *);
|
asmlinkage int norm_Xsig(Xsig *);
|
||||||
asmlinkage void div_Xsig(Xsig *x1, const Xsig *x2, const Xsig *dest);
|
asmlinkage void div_Xsig(Xsig * x1, const Xsig * x2, const Xsig * dest);
|
||||||
|
|
||||||
/* Macro to extract the most significant 32 bits from a long long */
|
/* Macro to extract the most significant 32 bits from a long long */
|
||||||
#define LL_MSW(x) (((unsigned long *)&x)[1])
|
#define LL_MSW(x) (((unsigned long *)&x)[1])
|
||||||
@@ -49,7 +49,6 @@ asmlinkage void div_Xsig(Xsig *x1, const Xsig *x2, const Xsig *dest);
|
|||||||
/* Macro to access the 8 ms bytes of an Xsig as a long long */
|
/* Macro to access the 8 ms bytes of an Xsig as a long long */
|
||||||
#define XSIG_LL(x) (*(unsigned long long *)&x.midw)
|
#define XSIG_LL(x) (*(unsigned long long *)&x.midw)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Need to run gcc with optimizations on to get these to
|
Need to run gcc with optimizations on to get these to
|
||||||
actually be in-line.
|
actually be in-line.
|
||||||
@@ -63,59 +62,53 @@ asmlinkage void div_Xsig(Xsig *x1, const Xsig *x2, const Xsig *dest);
|
|||||||
static inline unsigned long mul_32_32(const unsigned long arg1,
|
static inline unsigned long mul_32_32(const unsigned long arg1,
|
||||||
const unsigned long arg2)
|
const unsigned long arg2)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
asm volatile ("mull %2; movl %%edx,%%eax" \
|
asm volatile ("mull %2; movl %%edx,%%eax":"=a" (retval)
|
||||||
:"=a" (retval) \
|
:"0"(arg1), "g"(arg2)
|
||||||
:"0" (arg1), "g" (arg2) \
|
:"dx");
|
||||||
:"dx");
|
return retval;
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Add the 12 byte Xsig x2 to Xsig dest, with no checks for overflow. */
|
/* Add the 12 byte Xsig x2 to Xsig dest, with no checks for overflow. */
|
||||||
static inline void add_Xsig_Xsig(Xsig *dest, const Xsig *x2)
|
static inline void add_Xsig_Xsig(Xsig * dest, const Xsig * x2)
|
||||||
{
|
{
|
||||||
asm volatile ("movl %1,%%edi; movl %2,%%esi;\n"
|
asm volatile ("movl %1,%%edi; movl %2,%%esi;\n"
|
||||||
"movl (%%esi),%%eax; addl %%eax,(%%edi);\n"
|
"movl (%%esi),%%eax; addl %%eax,(%%edi);\n"
|
||||||
"movl 4(%%esi),%%eax; adcl %%eax,4(%%edi);\n"
|
"movl 4(%%esi),%%eax; adcl %%eax,4(%%edi);\n"
|
||||||
"movl 8(%%esi),%%eax; adcl %%eax,8(%%edi);\n"
|
"movl 8(%%esi),%%eax; adcl %%eax,8(%%edi);\n":"=g"
|
||||||
:"=g" (*dest):"g" (dest), "g" (x2)
|
(*dest):"g"(dest), "g"(x2)
|
||||||
:"ax","si","di");
|
:"ax", "si", "di");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Add the 12 byte Xsig x2 to Xsig dest, adjust exp if overflow occurs. */
|
/* Add the 12 byte Xsig x2 to Xsig dest, adjust exp if overflow occurs. */
|
||||||
/* Note: the constraints in the asm statement didn't always work properly
|
/* Note: the constraints in the asm statement didn't always work properly
|
||||||
with gcc 2.5.8. Changing from using edi to using ecx got around the
|
with gcc 2.5.8. Changing from using edi to using ecx got around the
|
||||||
problem, but keep fingers crossed! */
|
problem, but keep fingers crossed! */
|
||||||
static inline void add_two_Xsig(Xsig *dest, const Xsig *x2, long int *exp)
|
static inline void add_two_Xsig(Xsig * dest, const Xsig * x2, long int *exp)
|
||||||
{
|
{
|
||||||
asm volatile ("movl %2,%%ecx; movl %3,%%esi;\n"
|
asm volatile ("movl %2,%%ecx; movl %3,%%esi;\n"
|
||||||
"movl (%%esi),%%eax; addl %%eax,(%%ecx);\n"
|
"movl (%%esi),%%eax; addl %%eax,(%%ecx);\n"
|
||||||
"movl 4(%%esi),%%eax; adcl %%eax,4(%%ecx);\n"
|
"movl 4(%%esi),%%eax; adcl %%eax,4(%%ecx);\n"
|
||||||
"movl 8(%%esi),%%eax; adcl %%eax,8(%%ecx);\n"
|
"movl 8(%%esi),%%eax; adcl %%eax,8(%%ecx);\n"
|
||||||
"jnc 0f;\n"
|
"jnc 0f;\n"
|
||||||
"rcrl 8(%%ecx); rcrl 4(%%ecx); rcrl (%%ecx)\n"
|
"rcrl 8(%%ecx); rcrl 4(%%ecx); rcrl (%%ecx)\n"
|
||||||
"movl %4,%%ecx; incl (%%ecx)\n"
|
"movl %4,%%ecx; incl (%%ecx)\n"
|
||||||
"movl $1,%%eax; jmp 1f;\n"
|
"movl $1,%%eax; jmp 1f;\n"
|
||||||
"0: xorl %%eax,%%eax;\n"
|
"0: xorl %%eax,%%eax;\n" "1:\n":"=g" (*exp), "=g"(*dest)
|
||||||
"1:\n"
|
:"g"(dest), "g"(x2), "g"(exp)
|
||||||
:"=g" (*exp), "=g" (*dest)
|
:"cx", "si", "ax");
|
||||||
:"g" (dest), "g" (x2), "g" (exp)
|
|
||||||
:"cx","si","ax");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Negate (subtract from 1.0) the 12 byte Xsig */
|
/* Negate (subtract from 1.0) the 12 byte Xsig */
|
||||||
/* This is faster in a loop on my 386 than using the "neg" instruction. */
|
/* This is faster in a loop on my 386 than using the "neg" instruction. */
|
||||||
static inline void negate_Xsig(Xsig *x)
|
static inline void negate_Xsig(Xsig * x)
|
||||||
{
|
{
|
||||||
asm volatile("movl %1,%%esi;\n"
|
asm volatile ("movl %1,%%esi;\n"
|
||||||
"xorl %%ecx,%%ecx;\n"
|
"xorl %%ecx,%%ecx;\n"
|
||||||
"movl %%ecx,%%eax; subl (%%esi),%%eax; movl %%eax,(%%esi);\n"
|
"movl %%ecx,%%eax; subl (%%esi),%%eax; movl %%eax,(%%esi);\n"
|
||||||
"movl %%ecx,%%eax; sbbl 4(%%esi),%%eax; movl %%eax,4(%%esi);\n"
|
"movl %%ecx,%%eax; sbbl 4(%%esi),%%eax; movl %%eax,4(%%esi);\n"
|
||||||
"movl %%ecx,%%eax; sbbl 8(%%esi),%%eax; movl %%eax,8(%%esi);\n"
|
"movl %%ecx,%%eax; sbbl 8(%%esi),%%eax; movl %%eax,8(%%esi);\n":"=g"
|
||||||
:"=g" (*x):"g" (x):"si","ax","cx");
|
(*x):"g"(x):"si", "ax", "cx");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _POLY_H */
|
#endif /* _POLY_H */
|
||||||
|
@@ -17,21 +17,19 @@
|
|||||||
#include "control_w.h"
|
#include "control_w.h"
|
||||||
#include "poly.h"
|
#include "poly.h"
|
||||||
|
|
||||||
|
|
||||||
#define HIPOWER 11
|
#define HIPOWER 11
|
||||||
static const unsigned long long lterms[HIPOWER] =
|
static const unsigned long long lterms[HIPOWER] = {
|
||||||
{
|
0x0000000000000000LL, /* This term done separately as 12 bytes */
|
||||||
0x0000000000000000LL, /* This term done separately as 12 bytes */
|
0xf5fdeffc162c7543LL,
|
||||||
0xf5fdeffc162c7543LL,
|
0x1c6b08d704a0bfa6LL,
|
||||||
0x1c6b08d704a0bfa6LL,
|
0x0276556df749cc21LL,
|
||||||
0x0276556df749cc21LL,
|
0x002bb0ffcf14f6b8LL,
|
||||||
0x002bb0ffcf14f6b8LL,
|
0x0002861225ef751cLL,
|
||||||
0x0002861225ef751cLL,
|
0x00001ffcbfcd5422LL,
|
||||||
0x00001ffcbfcd5422LL,
|
0x00000162c005d5f1LL,
|
||||||
0x00000162c005d5f1LL,
|
0x0000000da96ccb1bLL,
|
||||||
0x0000000da96ccb1bLL,
|
0x0000000078d1b897LL,
|
||||||
0x0000000078d1b897LL,
|
0x000000000422b029LL
|
||||||
0x000000000422b029LL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const Xsig hiterm = MK_XSIG(0xb17217f7, 0xd1cf79ab, 0xc8a39194);
|
static const Xsig hiterm = MK_XSIG(0xb17217f7, 0xd1cf79ab, 0xc8a39194);
|
||||||
@@ -45,112 +43,103 @@ static const Xsig shiftterm2 = MK_XSIG(0xb504f333, 0xf9de6484, 0x597d89b3);
|
|||||||
static const Xsig shiftterm3 = MK_XSIG(0xd744fcca, 0xd69d6af4, 0x39a68bb9);
|
static const Xsig shiftterm3 = MK_XSIG(0xd744fcca, 0xd69d6af4, 0x39a68bb9);
|
||||||
|
|
||||||
static const Xsig *shiftterm[] = { &shiftterm0, &shiftterm1,
|
static const Xsig *shiftterm[] = { &shiftterm0, &shiftterm1,
|
||||||
&shiftterm2, &shiftterm3 };
|
&shiftterm2, &shiftterm3
|
||||||
|
};
|
||||||
|
|
||||||
/*--- poly_2xm1() -----------------------------------------------------------+
|
/*--- poly_2xm1() -----------------------------------------------------------+
|
||||||
| Requires st(0) which is TAG_Valid and < 1. |
|
| Requires st(0) which is TAG_Valid and < 1. |
|
||||||
+---------------------------------------------------------------------------*/
|
+---------------------------------------------------------------------------*/
|
||||||
int poly_2xm1(u_char sign, FPU_REG *arg, FPU_REG *result)
|
int poly_2xm1(u_char sign, FPU_REG * arg, FPU_REG * result)
|
||||||
{
|
{
|
||||||
long int exponent, shift;
|
long int exponent, shift;
|
||||||
unsigned long long Xll;
|
unsigned long long Xll;
|
||||||
Xsig accumulator, Denom, argSignif;
|
Xsig accumulator, Denom, argSignif;
|
||||||
u_char tag;
|
u_char tag;
|
||||||
|
|
||||||
exponent = exponent16(arg);
|
exponent = exponent16(arg);
|
||||||
|
|
||||||
#ifdef PARANOID
|
#ifdef PARANOID
|
||||||
if ( exponent >= 0 ) /* Don't want a |number| >= 1.0 */
|
if (exponent >= 0) { /* Don't want a |number| >= 1.0 */
|
||||||
{
|
/* Number negative, too large, or not Valid. */
|
||||||
/* Number negative, too large, or not Valid. */
|
EXCEPTION(EX_INTERNAL | 0x127);
|
||||||
EXCEPTION(EX_INTERNAL|0x127);
|
return 1;
|
||||||
return 1;
|
}
|
||||||
}
|
|
||||||
#endif /* PARANOID */
|
#endif /* PARANOID */
|
||||||
|
|
||||||
argSignif.lsw = 0;
|
argSignif.lsw = 0;
|
||||||
XSIG_LL(argSignif) = Xll = significand(arg);
|
XSIG_LL(argSignif) = Xll = significand(arg);
|
||||||
|
|
||||||
if ( exponent == -1 )
|
if (exponent == -1) {
|
||||||
{
|
shift = (argSignif.msw & 0x40000000) ? 3 : 2;
|
||||||
shift = (argSignif.msw & 0x40000000) ? 3 : 2;
|
/* subtract 0.5 or 0.75 */
|
||||||
/* subtract 0.5 or 0.75 */
|
exponent -= 2;
|
||||||
exponent -= 2;
|
XSIG_LL(argSignif) <<= 2;
|
||||||
XSIG_LL(argSignif) <<= 2;
|
Xll <<= 2;
|
||||||
Xll <<= 2;
|
} else if (exponent == -2) {
|
||||||
}
|
shift = 1;
|
||||||
else if ( exponent == -2 )
|
/* subtract 0.25 */
|
||||||
{
|
exponent--;
|
||||||
shift = 1;
|
XSIG_LL(argSignif) <<= 1;
|
||||||
/* subtract 0.25 */
|
Xll <<= 1;
|
||||||
exponent--;
|
} else
|
||||||
XSIG_LL(argSignif) <<= 1;
|
shift = 0;
|
||||||
Xll <<= 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
shift = 0;
|
|
||||||
|
|
||||||
if ( exponent < -2 )
|
if (exponent < -2) {
|
||||||
{
|
/* Shift the argument right by the required places. */
|
||||||
/* Shift the argument right by the required places. */
|
if (FPU_shrx(&Xll, -2 - exponent) >= 0x80000000U)
|
||||||
if ( FPU_shrx(&Xll, -2-exponent) >= 0x80000000U )
|
Xll++; /* round up */
|
||||||
Xll++; /* round up */
|
|
||||||
}
|
|
||||||
|
|
||||||
accumulator.lsw = accumulator.midw = accumulator.msw = 0;
|
|
||||||
polynomial_Xsig(&accumulator, &Xll, lterms, HIPOWER-1);
|
|
||||||
mul_Xsig_Xsig(&accumulator, &argSignif);
|
|
||||||
shr_Xsig(&accumulator, 3);
|
|
||||||
|
|
||||||
mul_Xsig_Xsig(&argSignif, &hiterm); /* The leading term */
|
|
||||||
add_two_Xsig(&accumulator, &argSignif, &exponent);
|
|
||||||
|
|
||||||
if ( shift )
|
|
||||||
{
|
|
||||||
/* The argument is large, use the identity:
|
|
||||||
f(x+a) = f(a) * (f(x) + 1) - 1;
|
|
||||||
*/
|
|
||||||
shr_Xsig(&accumulator, - exponent);
|
|
||||||
accumulator.msw |= 0x80000000; /* add 1.0 */
|
|
||||||
mul_Xsig_Xsig(&accumulator, shiftterm[shift]);
|
|
||||||
accumulator.msw &= 0x3fffffff; /* subtract 1.0 */
|
|
||||||
exponent = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( sign != SIGN_POS )
|
|
||||||
{
|
|
||||||
/* The argument is negative, use the identity:
|
|
||||||
f(-x) = -f(x) / (1 + f(x))
|
|
||||||
*/
|
|
||||||
Denom.lsw = accumulator.lsw;
|
|
||||||
XSIG_LL(Denom) = XSIG_LL(accumulator);
|
|
||||||
if ( exponent < 0 )
|
|
||||||
shr_Xsig(&Denom, - exponent);
|
|
||||||
else if ( exponent > 0 )
|
|
||||||
{
|
|
||||||
/* exponent must be 1 here */
|
|
||||||
XSIG_LL(Denom) <<= 1;
|
|
||||||
if ( Denom.lsw & 0x80000000 )
|
|
||||||
XSIG_LL(Denom) |= 1;
|
|
||||||
(Denom.lsw) <<= 1;
|
|
||||||
}
|
}
|
||||||
Denom.msw |= 0x80000000; /* add 1.0 */
|
|
||||||
div_Xsig(&accumulator, &Denom, &accumulator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convert to 64 bit signed-compatible */
|
accumulator.lsw = accumulator.midw = accumulator.msw = 0;
|
||||||
exponent += round_Xsig(&accumulator);
|
polynomial_Xsig(&accumulator, &Xll, lterms, HIPOWER - 1);
|
||||||
|
mul_Xsig_Xsig(&accumulator, &argSignif);
|
||||||
|
shr_Xsig(&accumulator, 3);
|
||||||
|
|
||||||
result = &st(0);
|
mul_Xsig_Xsig(&argSignif, &hiterm); /* The leading term */
|
||||||
significand(result) = XSIG_LL(accumulator);
|
add_two_Xsig(&accumulator, &argSignif, &exponent);
|
||||||
setexponent16(result, exponent);
|
|
||||||
|
|
||||||
tag = FPU_round(result, 1, 0, FULL_PRECISION, sign);
|
if (shift) {
|
||||||
|
/* The argument is large, use the identity:
|
||||||
|
f(x+a) = f(a) * (f(x) + 1) - 1;
|
||||||
|
*/
|
||||||
|
shr_Xsig(&accumulator, -exponent);
|
||||||
|
accumulator.msw |= 0x80000000; /* add 1.0 */
|
||||||
|
mul_Xsig_Xsig(&accumulator, shiftterm[shift]);
|
||||||
|
accumulator.msw &= 0x3fffffff; /* subtract 1.0 */
|
||||||
|
exponent = 1;
|
||||||
|
}
|
||||||
|
|
||||||
setsign(result, sign);
|
if (sign != SIGN_POS) {
|
||||||
FPU_settag0(tag);
|
/* The argument is negative, use the identity:
|
||||||
|
f(-x) = -f(x) / (1 + f(x))
|
||||||
|
*/
|
||||||
|
Denom.lsw = accumulator.lsw;
|
||||||
|
XSIG_LL(Denom) = XSIG_LL(accumulator);
|
||||||
|
if (exponent < 0)
|
||||||
|
shr_Xsig(&Denom, -exponent);
|
||||||
|
else if (exponent > 0) {
|
||||||
|
/* exponent must be 1 here */
|
||||||
|
XSIG_LL(Denom) <<= 1;
|
||||||
|
if (Denom.lsw & 0x80000000)
|
||||||
|
XSIG_LL(Denom) |= 1;
|
||||||
|
(Denom.lsw) <<= 1;
|
||||||
|
}
|
||||||
|
Denom.msw |= 0x80000000; /* add 1.0 */
|
||||||
|
div_Xsig(&accumulator, &Denom, &accumulator);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
/* Convert to 64 bit signed-compatible */
|
||||||
|
exponent += round_Xsig(&accumulator);
|
||||||
|
|
||||||
|
result = &st(0);
|
||||||
|
significand(result) = XSIG_LL(accumulator);
|
||||||
|
setexponent16(result, exponent);
|
||||||
|
|
||||||
|
tag = FPU_round(result, 1, 0, FULL_PRECISION, sign);
|
||||||
|
|
||||||
|
setsign(result, sign);
|
||||||
|
FPU_settag0(tag);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -18,28 +18,25 @@
|
|||||||
#include "control_w.h"
|
#include "control_w.h"
|
||||||
#include "poly.h"
|
#include "poly.h"
|
||||||
|
|
||||||
|
|
||||||
#define HIPOWERon 6 /* odd poly, negative terms */
|
#define HIPOWERon 6 /* odd poly, negative terms */
|
||||||
static const unsigned long long oddnegterms[HIPOWERon] =
|
static const unsigned long long oddnegterms[HIPOWERon] = {
|
||||||
{
|
0x0000000000000000LL, /* Dummy (not for - 1.0) */
|
||||||
0x0000000000000000LL, /* Dummy (not for - 1.0) */
|
0x015328437f756467LL,
|
||||||
0x015328437f756467LL,
|
0x0005dda27b73dec6LL,
|
||||||
0x0005dda27b73dec6LL,
|
0x0000226bf2bfb91aLL,
|
||||||
0x0000226bf2bfb91aLL,
|
0x000000ccc439c5f7LL,
|
||||||
0x000000ccc439c5f7LL,
|
0x0000000355438407LL
|
||||||
0x0000000355438407LL
|
};
|
||||||
} ;
|
|
||||||
|
|
||||||
#define HIPOWERop 6 /* odd poly, positive terms */
|
#define HIPOWERop 6 /* odd poly, positive terms */
|
||||||
static const unsigned long long oddplterms[HIPOWERop] =
|
static const unsigned long long oddplterms[HIPOWERop] = {
|
||||||
{
|
|
||||||
/* 0xaaaaaaaaaaaaaaabLL, transferred to fixedpterm[] */
|
/* 0xaaaaaaaaaaaaaaabLL, transferred to fixedpterm[] */
|
||||||
0x0db55a71875c9ac2LL,
|
0x0db55a71875c9ac2LL,
|
||||||
0x0029fce2d67880b0LL,
|
0x0029fce2d67880b0LL,
|
||||||
0x0000dfd3908b4596LL,
|
0x0000dfd3908b4596LL,
|
||||||
0x00000550fd61dab4LL,
|
0x00000550fd61dab4LL,
|
||||||
0x0000001c9422b3f9LL,
|
0x0000001c9422b3f9LL,
|
||||||
0x000000003e3301e1LL
|
0x000000003e3301e1LL
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned long long denomterm = 0xebd9b842c5c53a0eLL;
|
static const unsigned long long denomterm = 0xebd9b842c5c53a0eLL;
|
||||||
@@ -48,182 +45,164 @@ static const Xsig fixedpterm = MK_XSIG(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa);
|
|||||||
|
|
||||||
static const Xsig pi_signif = MK_XSIG(0xc90fdaa2, 0x2168c234, 0xc4c6628b);
|
static const Xsig pi_signif = MK_XSIG(0xc90fdaa2, 0x2168c234, 0xc4c6628b);
|
||||||
|
|
||||||
|
|
||||||
/*--- poly_atan() -----------------------------------------------------------+
|
/*--- poly_atan() -----------------------------------------------------------+
|
||||||
| |
|
| |
|
||||||
+---------------------------------------------------------------------------*/
|
+---------------------------------------------------------------------------*/
|
||||||
void poly_atan(FPU_REG *st0_ptr, u_char st0_tag,
|
void poly_atan(FPU_REG * st0_ptr, u_char st0_tag,
|
||||||
FPU_REG *st1_ptr, u_char st1_tag)
|
FPU_REG * st1_ptr, u_char st1_tag)
|
||||||
{
|
{
|
||||||
u_char transformed, inverted,
|
u_char transformed, inverted, sign1, sign2;
|
||||||
sign1, sign2;
|
int exponent;
|
||||||
int exponent;
|
long int dummy_exp;
|
||||||
long int dummy_exp;
|
Xsig accumulator, Numer, Denom, accumulatore, argSignif, argSq, argSqSq;
|
||||||
Xsig accumulator, Numer, Denom, accumulatore, argSignif,
|
u_char tag;
|
||||||
argSq, argSqSq;
|
|
||||||
u_char tag;
|
|
||||||
|
|
||||||
sign1 = getsign(st0_ptr);
|
|
||||||
sign2 = getsign(st1_ptr);
|
|
||||||
if ( st0_tag == TAG_Valid )
|
|
||||||
{
|
|
||||||
exponent = exponent(st0_ptr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* This gives non-compatible stack contents... */
|
|
||||||
FPU_to_exp16(st0_ptr, st0_ptr);
|
|
||||||
exponent = exponent16(st0_ptr);
|
|
||||||
}
|
|
||||||
if ( st1_tag == TAG_Valid )
|
|
||||||
{
|
|
||||||
exponent -= exponent(st1_ptr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* This gives non-compatible stack contents... */
|
|
||||||
FPU_to_exp16(st1_ptr, st1_ptr);
|
|
||||||
exponent -= exponent16(st1_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( (exponent < 0) || ((exponent == 0) &&
|
sign1 = getsign(st0_ptr);
|
||||||
((st0_ptr->sigh < st1_ptr->sigh) ||
|
sign2 = getsign(st1_ptr);
|
||||||
((st0_ptr->sigh == st1_ptr->sigh) &&
|
if (st0_tag == TAG_Valid) {
|
||||||
(st0_ptr->sigl < st1_ptr->sigl))) ) )
|
exponent = exponent(st0_ptr);
|
||||||
{
|
} else {
|
||||||
inverted = 1;
|
/* This gives non-compatible stack contents... */
|
||||||
Numer.lsw = Denom.lsw = 0;
|
FPU_to_exp16(st0_ptr, st0_ptr);
|
||||||
XSIG_LL(Numer) = significand(st0_ptr);
|
exponent = exponent16(st0_ptr);
|
||||||
XSIG_LL(Denom) = significand(st1_ptr);
|
}
|
||||||
}
|
if (st1_tag == TAG_Valid) {
|
||||||
else
|
exponent -= exponent(st1_ptr);
|
||||||
{
|
} else {
|
||||||
inverted = 0;
|
/* This gives non-compatible stack contents... */
|
||||||
exponent = -exponent;
|
FPU_to_exp16(st1_ptr, st1_ptr);
|
||||||
Numer.lsw = Denom.lsw = 0;
|
exponent -= exponent16(st1_ptr);
|
||||||
XSIG_LL(Numer) = significand(st1_ptr);
|
}
|
||||||
XSIG_LL(Denom) = significand(st0_ptr);
|
|
||||||
}
|
|
||||||
div_Xsig(&Numer, &Denom, &argSignif);
|
|
||||||
exponent += norm_Xsig(&argSignif);
|
|
||||||
|
|
||||||
if ( (exponent >= -1)
|
if ((exponent < 0) || ((exponent == 0) &&
|
||||||
|| ((exponent == -2) && (argSignif.msw > 0xd413ccd0)) )
|
((st0_ptr->sigh < st1_ptr->sigh) ||
|
||||||
{
|
((st0_ptr->sigh == st1_ptr->sigh) &&
|
||||||
/* The argument is greater than sqrt(2)-1 (=0.414213562...) */
|
(st0_ptr->sigl < st1_ptr->sigl))))) {
|
||||||
/* Convert the argument by an identity for atan */
|
inverted = 1;
|
||||||
transformed = 1;
|
Numer.lsw = Denom.lsw = 0;
|
||||||
|
XSIG_LL(Numer) = significand(st0_ptr);
|
||||||
|
XSIG_LL(Denom) = significand(st1_ptr);
|
||||||
|
} else {
|
||||||
|
inverted = 0;
|
||||||
|
exponent = -exponent;
|
||||||
|
Numer.lsw = Denom.lsw = 0;
|
||||||
|
XSIG_LL(Numer) = significand(st1_ptr);
|
||||||
|
XSIG_LL(Denom) = significand(st0_ptr);
|
||||||
|
}
|
||||||
|
div_Xsig(&Numer, &Denom, &argSignif);
|
||||||
|
exponent += norm_Xsig(&argSignif);
|
||||||
|
|
||||||
if ( exponent >= 0 )
|
if ((exponent >= -1)
|
||||||
{
|
|| ((exponent == -2) && (argSignif.msw > 0xd413ccd0))) {
|
||||||
|
/* The argument is greater than sqrt(2)-1 (=0.414213562...) */
|
||||||
|
/* Convert the argument by an identity for atan */
|
||||||
|
transformed = 1;
|
||||||
|
|
||||||
|
if (exponent >= 0) {
|
||||||
#ifdef PARANOID
|
#ifdef PARANOID
|
||||||
if ( !( (exponent == 0) &&
|
if (!((exponent == 0) &&
|
||||||
(argSignif.lsw == 0) && (argSignif.midw == 0) &&
|
(argSignif.lsw == 0) && (argSignif.midw == 0) &&
|
||||||
(argSignif.msw == 0x80000000) ) )
|
(argSignif.msw == 0x80000000))) {
|
||||||
{
|
EXCEPTION(EX_INTERNAL | 0x104); /* There must be a logic error */
|
||||||
EXCEPTION(EX_INTERNAL|0x104); /* There must be a logic error */
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
#endif /* PARANOID */
|
#endif /* PARANOID */
|
||||||
argSignif.msw = 0; /* Make the transformed arg -> 0.0 */
|
argSignif.msw = 0; /* Make the transformed arg -> 0.0 */
|
||||||
|
} else {
|
||||||
|
Numer.lsw = Denom.lsw = argSignif.lsw;
|
||||||
|
XSIG_LL(Numer) = XSIG_LL(Denom) = XSIG_LL(argSignif);
|
||||||
|
|
||||||
|
if (exponent < -1)
|
||||||
|
shr_Xsig(&Numer, -1 - exponent);
|
||||||
|
negate_Xsig(&Numer);
|
||||||
|
|
||||||
|
shr_Xsig(&Denom, -exponent);
|
||||||
|
Denom.msw |= 0x80000000;
|
||||||
|
|
||||||
|
div_Xsig(&Numer, &Denom, &argSignif);
|
||||||
|
|
||||||
|
exponent = -1 + norm_Xsig(&argSignif);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
transformed = 0;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
Numer.lsw = Denom.lsw = argSignif.lsw;
|
|
||||||
XSIG_LL(Numer) = XSIG_LL(Denom) = XSIG_LL(argSignif);
|
|
||||||
|
|
||||||
if ( exponent < -1 )
|
argSq.lsw = argSignif.lsw;
|
||||||
shr_Xsig(&Numer, -1-exponent);
|
argSq.midw = argSignif.midw;
|
||||||
negate_Xsig(&Numer);
|
argSq.msw = argSignif.msw;
|
||||||
|
mul_Xsig_Xsig(&argSq, &argSq);
|
||||||
shr_Xsig(&Denom, -exponent);
|
|
||||||
Denom.msw |= 0x80000000;
|
|
||||||
|
|
||||||
div_Xsig(&Numer, &Denom, &argSignif);
|
|
||||||
|
|
||||||
exponent = -1 + norm_Xsig(&argSignif);
|
argSqSq.lsw = argSq.lsw;
|
||||||
|
argSqSq.midw = argSq.midw;
|
||||||
|
argSqSq.msw = argSq.msw;
|
||||||
|
mul_Xsig_Xsig(&argSqSq, &argSqSq);
|
||||||
|
|
||||||
|
accumulatore.lsw = argSq.lsw;
|
||||||
|
XSIG_LL(accumulatore) = XSIG_LL(argSq);
|
||||||
|
|
||||||
|
shr_Xsig(&argSq, 2 * (-1 - exponent - 1));
|
||||||
|
shr_Xsig(&argSqSq, 4 * (-1 - exponent - 1));
|
||||||
|
|
||||||
|
/* Now have argSq etc with binary point at the left
|
||||||
|
.1xxxxxxxx */
|
||||||
|
|
||||||
|
/* Do the basic fixed point polynomial evaluation */
|
||||||
|
accumulator.msw = accumulator.midw = accumulator.lsw = 0;
|
||||||
|
polynomial_Xsig(&accumulator, &XSIG_LL(argSqSq),
|
||||||
|
oddplterms, HIPOWERop - 1);
|
||||||
|
mul64_Xsig(&accumulator, &XSIG_LL(argSq));
|
||||||
|
negate_Xsig(&accumulator);
|
||||||
|
polynomial_Xsig(&accumulator, &XSIG_LL(argSqSq), oddnegterms,
|
||||||
|
HIPOWERon - 1);
|
||||||
|
negate_Xsig(&accumulator);
|
||||||
|
add_two_Xsig(&accumulator, &fixedpterm, &dummy_exp);
|
||||||
|
|
||||||
|
mul64_Xsig(&accumulatore, &denomterm);
|
||||||
|
shr_Xsig(&accumulatore, 1 + 2 * (-1 - exponent));
|
||||||
|
accumulatore.msw |= 0x80000000;
|
||||||
|
|
||||||
|
div_Xsig(&accumulator, &accumulatore, &accumulator);
|
||||||
|
|
||||||
|
mul_Xsig_Xsig(&accumulator, &argSignif);
|
||||||
|
mul_Xsig_Xsig(&accumulator, &argSq);
|
||||||
|
|
||||||
|
shr_Xsig(&accumulator, 3);
|
||||||
|
negate_Xsig(&accumulator);
|
||||||
|
add_Xsig_Xsig(&accumulator, &argSignif);
|
||||||
|
|
||||||
|
if (transformed) {
|
||||||
|
/* compute pi/4 - accumulator */
|
||||||
|
shr_Xsig(&accumulator, -1 - exponent);
|
||||||
|
negate_Xsig(&accumulator);
|
||||||
|
add_Xsig_Xsig(&accumulator, &pi_signif);
|
||||||
|
exponent = -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
transformed = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
argSq.lsw = argSignif.lsw; argSq.midw = argSignif.midw;
|
if (inverted) {
|
||||||
argSq.msw = argSignif.msw;
|
/* compute pi/2 - accumulator */
|
||||||
mul_Xsig_Xsig(&argSq, &argSq);
|
shr_Xsig(&accumulator, -exponent);
|
||||||
|
negate_Xsig(&accumulator);
|
||||||
argSqSq.lsw = argSq.lsw; argSqSq.midw = argSq.midw; argSqSq.msw = argSq.msw;
|
add_Xsig_Xsig(&accumulator, &pi_signif);
|
||||||
mul_Xsig_Xsig(&argSqSq, &argSqSq);
|
exponent = 0;
|
||||||
|
}
|
||||||
|
|
||||||
accumulatore.lsw = argSq.lsw;
|
if (sign1) {
|
||||||
XSIG_LL(accumulatore) = XSIG_LL(argSq);
|
/* compute pi - accumulator */
|
||||||
|
shr_Xsig(&accumulator, 1 - exponent);
|
||||||
|
negate_Xsig(&accumulator);
|
||||||
|
add_Xsig_Xsig(&accumulator, &pi_signif);
|
||||||
|
exponent = 1;
|
||||||
|
}
|
||||||
|
|
||||||
shr_Xsig(&argSq, 2*(-1-exponent-1));
|
exponent += round_Xsig(&accumulator);
|
||||||
shr_Xsig(&argSqSq, 4*(-1-exponent-1));
|
|
||||||
|
|
||||||
/* Now have argSq etc with binary point at the left
|
significand(st1_ptr) = XSIG_LL(accumulator);
|
||||||
.1xxxxxxxx */
|
setexponent16(st1_ptr, exponent);
|
||||||
|
|
||||||
/* Do the basic fixed point polynomial evaluation */
|
tag = FPU_round(st1_ptr, 1, 0, FULL_PRECISION, sign2);
|
||||||
accumulator.msw = accumulator.midw = accumulator.lsw = 0;
|
FPU_settagi(1, tag);
|
||||||
polynomial_Xsig(&accumulator, &XSIG_LL(argSqSq),
|
|
||||||
oddplterms, HIPOWERop-1);
|
|
||||||
mul64_Xsig(&accumulator, &XSIG_LL(argSq));
|
|
||||||
negate_Xsig(&accumulator);
|
|
||||||
polynomial_Xsig(&accumulator, &XSIG_LL(argSqSq), oddnegterms, HIPOWERon-1);
|
|
||||||
negate_Xsig(&accumulator);
|
|
||||||
add_two_Xsig(&accumulator, &fixedpterm, &dummy_exp);
|
|
||||||
|
|
||||||
mul64_Xsig(&accumulatore, &denomterm);
|
set_precision_flag_up(); /* We do not really know if up or down,
|
||||||
shr_Xsig(&accumulatore, 1 + 2*(-1-exponent));
|
use this as the default. */
|
||||||
accumulatore.msw |= 0x80000000;
|
|
||||||
|
|
||||||
div_Xsig(&accumulator, &accumulatore, &accumulator);
|
|
||||||
|
|
||||||
mul_Xsig_Xsig(&accumulator, &argSignif);
|
|
||||||
mul_Xsig_Xsig(&accumulator, &argSq);
|
|
||||||
|
|
||||||
shr_Xsig(&accumulator, 3);
|
|
||||||
negate_Xsig(&accumulator);
|
|
||||||
add_Xsig_Xsig(&accumulator, &argSignif);
|
|
||||||
|
|
||||||
if ( transformed )
|
|
||||||
{
|
|
||||||
/* compute pi/4 - accumulator */
|
|
||||||
shr_Xsig(&accumulator, -1-exponent);
|
|
||||||
negate_Xsig(&accumulator);
|
|
||||||
add_Xsig_Xsig(&accumulator, &pi_signif);
|
|
||||||
exponent = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( inverted )
|
|
||||||
{
|
|
||||||
/* compute pi/2 - accumulator */
|
|
||||||
shr_Xsig(&accumulator, -exponent);
|
|
||||||
negate_Xsig(&accumulator);
|
|
||||||
add_Xsig_Xsig(&accumulator, &pi_signif);
|
|
||||||
exponent = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( sign1 )
|
|
||||||
{
|
|
||||||
/* compute pi - accumulator */
|
|
||||||
shr_Xsig(&accumulator, 1 - exponent);
|
|
||||||
negate_Xsig(&accumulator);
|
|
||||||
add_Xsig_Xsig(&accumulator, &pi_signif);
|
|
||||||
exponent = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
exponent += round_Xsig(&accumulator);
|
|
||||||
|
|
||||||
significand(st1_ptr) = XSIG_LL(accumulator);
|
|
||||||
setexponent16(st1_ptr, exponent);
|
|
||||||
|
|
||||||
tag = FPU_round(st1_ptr, 1, 0, FULL_PRECISION, sign2);
|
|
||||||
FPU_settagi(1, tag);
|
|
||||||
|
|
||||||
set_precision_flag_up(); /* We do not really know if up or down,
|
|
||||||
use this as the default. */
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,6 @@
|
|||||||
| |
|
| |
|
||||||
+---------------------------------------------------------------------------*/
|
+---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
#include "exception.h"
|
#include "exception.h"
|
||||||
#include "reg_constant.h"
|
#include "reg_constant.h"
|
||||||
#include "fpu_emu.h"
|
#include "fpu_emu.h"
|
||||||
@@ -18,255 +17,228 @@
|
|||||||
#include "control_w.h"
|
#include "control_w.h"
|
||||||
#include "poly.h"
|
#include "poly.h"
|
||||||
|
|
||||||
|
|
||||||
static void log2_kernel(FPU_REG const *arg, u_char argsign,
|
static void log2_kernel(FPU_REG const *arg, u_char argsign,
|
||||||
Xsig *accum_result, long int *expon);
|
Xsig * accum_result, long int *expon);
|
||||||
|
|
||||||
|
|
||||||
/*--- poly_l2() -------------------------------------------------------------+
|
/*--- poly_l2() -------------------------------------------------------------+
|
||||||
| Base 2 logarithm by a polynomial approximation. |
|
| Base 2 logarithm by a polynomial approximation. |
|
||||||
+---------------------------------------------------------------------------*/
|
+---------------------------------------------------------------------------*/
|
||||||
void poly_l2(FPU_REG *st0_ptr, FPU_REG *st1_ptr, u_char st1_sign)
|
void poly_l2(FPU_REG * st0_ptr, FPU_REG * st1_ptr, u_char st1_sign)
|
||||||
{
|
{
|
||||||
long int exponent, expon, expon_expon;
|
long int exponent, expon, expon_expon;
|
||||||
Xsig accumulator, expon_accum, yaccum;
|
Xsig accumulator, expon_accum, yaccum;
|
||||||
u_char sign, argsign;
|
u_char sign, argsign;
|
||||||
FPU_REG x;
|
FPU_REG x;
|
||||||
int tag;
|
int tag;
|
||||||
|
|
||||||
exponent = exponent16(st0_ptr);
|
exponent = exponent16(st0_ptr);
|
||||||
|
|
||||||
/* From st0_ptr, make a number > sqrt(2)/2 and < sqrt(2) */
|
/* From st0_ptr, make a number > sqrt(2)/2 and < sqrt(2) */
|
||||||
if ( st0_ptr->sigh > (unsigned)0xb504f334 )
|
if (st0_ptr->sigh > (unsigned)0xb504f334) {
|
||||||
{
|
/* Treat as sqrt(2)/2 < st0_ptr < 1 */
|
||||||
/* Treat as sqrt(2)/2 < st0_ptr < 1 */
|
significand(&x) = -significand(st0_ptr);
|
||||||
significand(&x) = - significand(st0_ptr);
|
setexponent16(&x, -1);
|
||||||
setexponent16(&x, -1);
|
exponent++;
|
||||||
exponent++;
|
argsign = SIGN_NEG;
|
||||||
argsign = SIGN_NEG;
|
} else {
|
||||||
}
|
/* Treat as 1 <= st0_ptr < sqrt(2) */
|
||||||
else
|
x.sigh = st0_ptr->sigh - 0x80000000;
|
||||||
{
|
x.sigl = st0_ptr->sigl;
|
||||||
/* Treat as 1 <= st0_ptr < sqrt(2) */
|
setexponent16(&x, 0);
|
||||||
x.sigh = st0_ptr->sigh - 0x80000000;
|
argsign = SIGN_POS;
|
||||||
x.sigl = st0_ptr->sigl;
|
}
|
||||||
setexponent16(&x, 0);
|
tag = FPU_normalize_nuo(&x);
|
||||||
argsign = SIGN_POS;
|
|
||||||
}
|
|
||||||
tag = FPU_normalize_nuo(&x);
|
|
||||||
|
|
||||||
if ( tag == TAG_Zero )
|
if (tag == TAG_Zero) {
|
||||||
{
|
expon = 0;
|
||||||
expon = 0;
|
accumulator.msw = accumulator.midw = accumulator.lsw = 0;
|
||||||
accumulator.msw = accumulator.midw = accumulator.lsw = 0;
|
} else {
|
||||||
}
|
log2_kernel(&x, argsign, &accumulator, &expon);
|
||||||
else
|
}
|
||||||
{
|
|
||||||
log2_kernel(&x, argsign, &accumulator, &expon);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( exponent < 0 )
|
if (exponent < 0) {
|
||||||
{
|
sign = SIGN_NEG;
|
||||||
sign = SIGN_NEG;
|
exponent = -exponent;
|
||||||
exponent = -exponent;
|
} else
|
||||||
}
|
sign = SIGN_POS;
|
||||||
else
|
expon_accum.msw = exponent;
|
||||||
sign = SIGN_POS;
|
expon_accum.midw = expon_accum.lsw = 0;
|
||||||
expon_accum.msw = exponent; expon_accum.midw = expon_accum.lsw = 0;
|
if (exponent) {
|
||||||
if ( exponent )
|
expon_expon = 31 + norm_Xsig(&expon_accum);
|
||||||
{
|
shr_Xsig(&accumulator, expon_expon - expon);
|
||||||
expon_expon = 31 + norm_Xsig(&expon_accum);
|
|
||||||
shr_Xsig(&accumulator, expon_expon - expon);
|
|
||||||
|
|
||||||
if ( sign ^ argsign )
|
if (sign ^ argsign)
|
||||||
negate_Xsig(&accumulator);
|
negate_Xsig(&accumulator);
|
||||||
add_Xsig_Xsig(&accumulator, &expon_accum);
|
add_Xsig_Xsig(&accumulator, &expon_accum);
|
||||||
}
|
} else {
|
||||||
else
|
expon_expon = expon;
|
||||||
{
|
sign = argsign;
|
||||||
expon_expon = expon;
|
}
|
||||||
sign = argsign;
|
|
||||||
}
|
|
||||||
|
|
||||||
yaccum.lsw = 0; XSIG_LL(yaccum) = significand(st1_ptr);
|
yaccum.lsw = 0;
|
||||||
mul_Xsig_Xsig(&accumulator, &yaccum);
|
XSIG_LL(yaccum) = significand(st1_ptr);
|
||||||
|
mul_Xsig_Xsig(&accumulator, &yaccum);
|
||||||
|
|
||||||
expon_expon += round_Xsig(&accumulator);
|
expon_expon += round_Xsig(&accumulator);
|
||||||
|
|
||||||
if ( accumulator.msw == 0 )
|
if (accumulator.msw == 0) {
|
||||||
{
|
FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
|
||||||
FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
significand(st1_ptr) = XSIG_LL(accumulator);
|
significand(st1_ptr) = XSIG_LL(accumulator);
|
||||||
setexponent16(st1_ptr, expon_expon + exponent16(st1_ptr) + 1);
|
setexponent16(st1_ptr, expon_expon + exponent16(st1_ptr) + 1);
|
||||||
|
|
||||||
tag = FPU_round(st1_ptr, 1, 0, FULL_PRECISION, sign ^ st1_sign);
|
tag = FPU_round(st1_ptr, 1, 0, FULL_PRECISION, sign ^ st1_sign);
|
||||||
FPU_settagi(1, tag);
|
FPU_settagi(1, tag);
|
||||||
|
|
||||||
set_precision_flag_up(); /* 80486 appears to always do this */
|
set_precision_flag_up(); /* 80486 appears to always do this */
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*--- poly_l2p1() -----------------------------------------------------------+
|
/*--- poly_l2p1() -----------------------------------------------------------+
|
||||||
| Base 2 logarithm by a polynomial approximation. |
|
| Base 2 logarithm by a polynomial approximation. |
|
||||||
| log2(x+1) |
|
| log2(x+1) |
|
||||||
+---------------------------------------------------------------------------*/
|
+---------------------------------------------------------------------------*/
|
||||||
int poly_l2p1(u_char sign0, u_char sign1,
|
int poly_l2p1(u_char sign0, u_char sign1,
|
||||||
FPU_REG *st0_ptr, FPU_REG *st1_ptr, FPU_REG *dest)
|
FPU_REG * st0_ptr, FPU_REG * st1_ptr, FPU_REG * dest)
|
||||||
{
|
{
|
||||||
u_char tag;
|
u_char tag;
|
||||||
long int exponent;
|
long int exponent;
|
||||||
Xsig accumulator, yaccum;
|
Xsig accumulator, yaccum;
|
||||||
|
|
||||||
if ( exponent16(st0_ptr) < 0 )
|
if (exponent16(st0_ptr) < 0) {
|
||||||
{
|
log2_kernel(st0_ptr, sign0, &accumulator, &exponent);
|
||||||
log2_kernel(st0_ptr, sign0, &accumulator, &exponent);
|
|
||||||
|
|
||||||
yaccum.lsw = 0;
|
yaccum.lsw = 0;
|
||||||
XSIG_LL(yaccum) = significand(st1_ptr);
|
XSIG_LL(yaccum) = significand(st1_ptr);
|
||||||
mul_Xsig_Xsig(&accumulator, &yaccum);
|
mul_Xsig_Xsig(&accumulator, &yaccum);
|
||||||
|
|
||||||
exponent += round_Xsig(&accumulator);
|
exponent += round_Xsig(&accumulator);
|
||||||
|
|
||||||
exponent += exponent16(st1_ptr) + 1;
|
exponent += exponent16(st1_ptr) + 1;
|
||||||
if ( exponent < EXP_WAY_UNDER ) exponent = EXP_WAY_UNDER;
|
if (exponent < EXP_WAY_UNDER)
|
||||||
|
exponent = EXP_WAY_UNDER;
|
||||||
|
|
||||||
significand(dest) = XSIG_LL(accumulator);
|
significand(dest) = XSIG_LL(accumulator);
|
||||||
setexponent16(dest, exponent);
|
setexponent16(dest, exponent);
|
||||||
|
|
||||||
tag = FPU_round(dest, 1, 0, FULL_PRECISION, sign0 ^ sign1);
|
tag = FPU_round(dest, 1, 0, FULL_PRECISION, sign0 ^ sign1);
|
||||||
FPU_settagi(1, tag);
|
FPU_settagi(1, tag);
|
||||||
|
|
||||||
if ( tag == TAG_Valid )
|
if (tag == TAG_Valid)
|
||||||
set_precision_flag_up(); /* 80486 appears to always do this */
|
set_precision_flag_up(); /* 80486 appears to always do this */
|
||||||
}
|
} else {
|
||||||
else
|
/* The magnitude of st0_ptr is far too large. */
|
||||||
{
|
|
||||||
/* The magnitude of st0_ptr is far too large. */
|
|
||||||
|
|
||||||
if ( sign0 != SIGN_POS )
|
if (sign0 != SIGN_POS) {
|
||||||
{
|
/* Trying to get the log of a negative number. */
|
||||||
/* Trying to get the log of a negative number. */
|
#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */
|
||||||
#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */
|
changesign(st1_ptr);
|
||||||
changesign(st1_ptr);
|
|
||||||
#else
|
#else
|
||||||
if ( arith_invalid(1) < 0 )
|
if (arith_invalid(1) < 0)
|
||||||
return 1;
|
return 1;
|
||||||
#endif /* PECULIAR_486 */
|
#endif /* PECULIAR_486 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 80486 appears to do this */
|
||||||
|
if (sign0 == SIGN_NEG)
|
||||||
|
set_precision_flag_down();
|
||||||
|
else
|
||||||
|
set_precision_flag_up();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 80486 appears to do this */
|
if (exponent(dest) <= EXP_UNDER)
|
||||||
if ( sign0 == SIGN_NEG )
|
EXCEPTION(EX_Underflow);
|
||||||
set_precision_flag_down();
|
|
||||||
else
|
|
||||||
set_precision_flag_up();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( exponent(dest) <= EXP_UNDER )
|
return 0;
|
||||||
EXCEPTION(EX_Underflow);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#undef HIPOWER
|
#undef HIPOWER
|
||||||
#define HIPOWER 10
|
#define HIPOWER 10
|
||||||
static const unsigned long long logterms[HIPOWER] =
|
static const unsigned long long logterms[HIPOWER] = {
|
||||||
{
|
0x2a8eca5705fc2ef0LL,
|
||||||
0x2a8eca5705fc2ef0LL,
|
0xf6384ee1d01febceLL,
|
||||||
0xf6384ee1d01febceLL,
|
0x093bb62877cdf642LL,
|
||||||
0x093bb62877cdf642LL,
|
0x006985d8a9ec439bLL,
|
||||||
0x006985d8a9ec439bLL,
|
0x0005212c4f55a9c8LL,
|
||||||
0x0005212c4f55a9c8LL,
|
0x00004326a16927f0LL,
|
||||||
0x00004326a16927f0LL,
|
0x0000038d1d80a0e7LL,
|
||||||
0x0000038d1d80a0e7LL,
|
0x0000003141cc80c6LL,
|
||||||
0x0000003141cc80c6LL,
|
0x00000002b1668c9fLL,
|
||||||
0x00000002b1668c9fLL,
|
0x000000002c7a46aaLL
|
||||||
0x000000002c7a46aaLL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned long leadterm = 0xb8000000;
|
static const unsigned long leadterm = 0xb8000000;
|
||||||
|
|
||||||
|
|
||||||
/*--- log2_kernel() ---------------------------------------------------------+
|
/*--- log2_kernel() ---------------------------------------------------------+
|
||||||
| Base 2 logarithm by a polynomial approximation. |
|
| Base 2 logarithm by a polynomial approximation. |
|
||||||
| log2(x+1) |
|
| log2(x+1) |
|
||||||
+---------------------------------------------------------------------------*/
|
+---------------------------------------------------------------------------*/
|
||||||
static void log2_kernel(FPU_REG const *arg, u_char argsign, Xsig *accum_result,
|
static void log2_kernel(FPU_REG const *arg, u_char argsign, Xsig * accum_result,
|
||||||
long int *expon)
|
long int *expon)
|
||||||
{
|
{
|
||||||
long int exponent, adj;
|
long int exponent, adj;
|
||||||
unsigned long long Xsq;
|
unsigned long long Xsq;
|
||||||
Xsig accumulator, Numer, Denom, argSignif, arg_signif;
|
Xsig accumulator, Numer, Denom, argSignif, arg_signif;
|
||||||
|
|
||||||
exponent = exponent16(arg);
|
exponent = exponent16(arg);
|
||||||
Numer.lsw = Denom.lsw = 0;
|
Numer.lsw = Denom.lsw = 0;
|
||||||
XSIG_LL(Numer) = XSIG_LL(Denom) = significand(arg);
|
XSIG_LL(Numer) = XSIG_LL(Denom) = significand(arg);
|
||||||
if ( argsign == SIGN_POS )
|
if (argsign == SIGN_POS) {
|
||||||
{
|
shr_Xsig(&Denom, 2 - (1 + exponent));
|
||||||
shr_Xsig(&Denom, 2 - (1 + exponent));
|
Denom.msw |= 0x80000000;
|
||||||
Denom.msw |= 0x80000000;
|
div_Xsig(&Numer, &Denom, &argSignif);
|
||||||
div_Xsig(&Numer, &Denom, &argSignif);
|
} else {
|
||||||
}
|
shr_Xsig(&Denom, 1 - (1 + exponent));
|
||||||
else
|
negate_Xsig(&Denom);
|
||||||
{
|
if (Denom.msw & 0x80000000) {
|
||||||
shr_Xsig(&Denom, 1 - (1 + exponent));
|
div_Xsig(&Numer, &Denom, &argSignif);
|
||||||
negate_Xsig(&Denom);
|
exponent++;
|
||||||
if ( Denom.msw & 0x80000000 )
|
} else {
|
||||||
{
|
/* Denom must be 1.0 */
|
||||||
div_Xsig(&Numer, &Denom, &argSignif);
|
argSignif.lsw = Numer.lsw;
|
||||||
exponent ++;
|
argSignif.midw = Numer.midw;
|
||||||
|
argSignif.msw = Numer.msw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Denom must be 1.0 */
|
|
||||||
argSignif.lsw = Numer.lsw; argSignif.midw = Numer.midw;
|
|
||||||
argSignif.msw = Numer.msw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef PECULIAR_486
|
#ifndef PECULIAR_486
|
||||||
/* Should check here that |local_arg| is within the valid range */
|
/* Should check here that |local_arg| is within the valid range */
|
||||||
if ( exponent >= -2 )
|
if (exponent >= -2) {
|
||||||
{
|
if ((exponent > -2) || (argSignif.msw > (unsigned)0xafb0ccc0)) {
|
||||||
if ( (exponent > -2) ||
|
/* The argument is too large */
|
||||||
(argSignif.msw > (unsigned)0xafb0ccc0) )
|
}
|
||||||
{
|
|
||||||
/* The argument is too large */
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif /* PECULIAR_486 */
|
#endif /* PECULIAR_486 */
|
||||||
|
|
||||||
arg_signif.lsw = argSignif.lsw; XSIG_LL(arg_signif) = XSIG_LL(argSignif);
|
arg_signif.lsw = argSignif.lsw;
|
||||||
adj = norm_Xsig(&argSignif);
|
XSIG_LL(arg_signif) = XSIG_LL(argSignif);
|
||||||
accumulator.lsw = argSignif.lsw; XSIG_LL(accumulator) = XSIG_LL(argSignif);
|
adj = norm_Xsig(&argSignif);
|
||||||
mul_Xsig_Xsig(&accumulator, &accumulator);
|
accumulator.lsw = argSignif.lsw;
|
||||||
shr_Xsig(&accumulator, 2*(-1 - (1 + exponent + adj)));
|
XSIG_LL(accumulator) = XSIG_LL(argSignif);
|
||||||
Xsq = XSIG_LL(accumulator);
|
mul_Xsig_Xsig(&accumulator, &accumulator);
|
||||||
if ( accumulator.lsw & 0x80000000 )
|
shr_Xsig(&accumulator, 2 * (-1 - (1 + exponent + adj)));
|
||||||
Xsq++;
|
Xsq = XSIG_LL(accumulator);
|
||||||
|
if (accumulator.lsw & 0x80000000)
|
||||||
|
Xsq++;
|
||||||
|
|
||||||
accumulator.msw = accumulator.midw = accumulator.lsw = 0;
|
accumulator.msw = accumulator.midw = accumulator.lsw = 0;
|
||||||
/* Do the basic fixed point polynomial evaluation */
|
/* Do the basic fixed point polynomial evaluation */
|
||||||
polynomial_Xsig(&accumulator, &Xsq, logterms, HIPOWER-1);
|
polynomial_Xsig(&accumulator, &Xsq, logterms, HIPOWER - 1);
|
||||||
|
|
||||||
mul_Xsig_Xsig(&accumulator, &argSignif);
|
mul_Xsig_Xsig(&accumulator, &argSignif);
|
||||||
shr_Xsig(&accumulator, 6 - adj);
|
shr_Xsig(&accumulator, 6 - adj);
|
||||||
|
|
||||||
mul32_Xsig(&arg_signif, leadterm);
|
mul32_Xsig(&arg_signif, leadterm);
|
||||||
add_two_Xsig(&accumulator, &arg_signif, &exponent);
|
add_two_Xsig(&accumulator, &arg_signif, &exponent);
|
||||||
|
|
||||||
*expon = exponent + 1;
|
*expon = exponent + 1;
|
||||||
accum_result->lsw = accumulator.lsw;
|
accum_result->lsw = accumulator.lsw;
|
||||||
accum_result->midw = accumulator.midw;
|
accum_result->midw = accumulator.midw;
|
||||||
accum_result->msw = accumulator.msw;
|
accum_result->msw = accumulator.msw;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -11,7 +11,6 @@
|
|||||||
| |
|
| |
|
||||||
+---------------------------------------------------------------------------*/
|
+---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
#include "exception.h"
|
#include "exception.h"
|
||||||
#include "reg_constant.h"
|
#include "reg_constant.h"
|
||||||
#include "fpu_emu.h"
|
#include "fpu_emu.h"
|
||||||
@@ -19,379 +18,361 @@
|
|||||||
#include "control_w.h"
|
#include "control_w.h"
|
||||||
#include "poly.h"
|
#include "poly.h"
|
||||||
|
|
||||||
|
|
||||||
#define N_COEFF_P 4
|
#define N_COEFF_P 4
|
||||||
#define N_COEFF_N 4
|
#define N_COEFF_N 4
|
||||||
|
|
||||||
static const unsigned long long pos_terms_l[N_COEFF_P] =
|
static const unsigned long long pos_terms_l[N_COEFF_P] = {
|
||||||
{
|
0xaaaaaaaaaaaaaaabLL,
|
||||||
0xaaaaaaaaaaaaaaabLL,
|
0x00d00d00d00cf906LL,
|
||||||
0x00d00d00d00cf906LL,
|
0x000006b99159a8bbLL,
|
||||||
0x000006b99159a8bbLL,
|
0x000000000d7392e6LL
|
||||||
0x000000000d7392e6LL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned long long neg_terms_l[N_COEFF_N] =
|
static const unsigned long long neg_terms_l[N_COEFF_N] = {
|
||||||
{
|
0x2222222222222167LL,
|
||||||
0x2222222222222167LL,
|
0x0002e3bc74aab624LL,
|
||||||
0x0002e3bc74aab624LL,
|
0x0000000b09229062LL,
|
||||||
0x0000000b09229062LL,
|
0x00000000000c7973LL
|
||||||
0x00000000000c7973LL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define N_COEFF_PH 4
|
#define N_COEFF_PH 4
|
||||||
#define N_COEFF_NH 4
|
#define N_COEFF_NH 4
|
||||||
static const unsigned long long pos_terms_h[N_COEFF_PH] =
|
static const unsigned long long pos_terms_h[N_COEFF_PH] = {
|
||||||
{
|
0x0000000000000000LL,
|
||||||
0x0000000000000000LL,
|
0x05b05b05b05b0406LL,
|
||||||
0x05b05b05b05b0406LL,
|
0x000049f93edd91a9LL,
|
||||||
0x000049f93edd91a9LL,
|
0x00000000c9c9ed62LL
|
||||||
0x00000000c9c9ed62LL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned long long neg_terms_h[N_COEFF_NH] =
|
static const unsigned long long neg_terms_h[N_COEFF_NH] = {
|
||||||
{
|
0xaaaaaaaaaaaaaa98LL,
|
||||||
0xaaaaaaaaaaaaaa98LL,
|
0x001a01a01a019064LL,
|
||||||
0x001a01a01a019064LL,
|
0x0000008f76c68a77LL,
|
||||||
0x0000008f76c68a77LL,
|
0x0000000000d58f5eLL
|
||||||
0x0000000000d58f5eLL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*--- poly_sine() -----------------------------------------------------------+
|
/*--- poly_sine() -----------------------------------------------------------+
|
||||||
| |
|
| |
|
||||||
+---------------------------------------------------------------------------*/
|
+---------------------------------------------------------------------------*/
|
||||||
void poly_sine(FPU_REG *st0_ptr)
|
void poly_sine(FPU_REG * st0_ptr)
|
||||||
{
|
{
|
||||||
int exponent, echange;
|
int exponent, echange;
|
||||||
Xsig accumulator, argSqrd, argTo4;
|
Xsig accumulator, argSqrd, argTo4;
|
||||||
unsigned long fix_up, adj;
|
unsigned long fix_up, adj;
|
||||||
unsigned long long fixed_arg;
|
unsigned long long fixed_arg;
|
||||||
FPU_REG result;
|
FPU_REG result;
|
||||||
|
|
||||||
exponent = exponent(st0_ptr);
|
exponent = exponent(st0_ptr);
|
||||||
|
|
||||||
accumulator.lsw = accumulator.midw = accumulator.msw = 0;
|
accumulator.lsw = accumulator.midw = accumulator.msw = 0;
|
||||||
|
|
||||||
/* Split into two ranges, for arguments below and above 1.0 */
|
/* Split into two ranges, for arguments below and above 1.0 */
|
||||||
/* The boundary between upper and lower is approx 0.88309101259 */
|
/* The boundary between upper and lower is approx 0.88309101259 */
|
||||||
if ( (exponent < -1) || ((exponent == -1) && (st0_ptr->sigh <= 0xe21240aa)) )
|
if ((exponent < -1)
|
||||||
{
|
|| ((exponent == -1) && (st0_ptr->sigh <= 0xe21240aa))) {
|
||||||
/* The argument is <= 0.88309101259 */
|
/* The argument is <= 0.88309101259 */
|
||||||
|
|
||||||
argSqrd.msw = st0_ptr->sigh; argSqrd.midw = st0_ptr->sigl; argSqrd.lsw = 0;
|
argSqrd.msw = st0_ptr->sigh;
|
||||||
mul64_Xsig(&argSqrd, &significand(st0_ptr));
|
argSqrd.midw = st0_ptr->sigl;
|
||||||
shr_Xsig(&argSqrd, 2*(-1-exponent));
|
argSqrd.lsw = 0;
|
||||||
argTo4.msw = argSqrd.msw; argTo4.midw = argSqrd.midw;
|
mul64_Xsig(&argSqrd, &significand(st0_ptr));
|
||||||
argTo4.lsw = argSqrd.lsw;
|
shr_Xsig(&argSqrd, 2 * (-1 - exponent));
|
||||||
mul_Xsig_Xsig(&argTo4, &argTo4);
|
argTo4.msw = argSqrd.msw;
|
||||||
|
argTo4.midw = argSqrd.midw;
|
||||||
|
argTo4.lsw = argSqrd.lsw;
|
||||||
|
mul_Xsig_Xsig(&argTo4, &argTo4);
|
||||||
|
|
||||||
polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_l,
|
polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_l,
|
||||||
N_COEFF_N-1);
|
N_COEFF_N - 1);
|
||||||
mul_Xsig_Xsig(&accumulator, &argSqrd);
|
mul_Xsig_Xsig(&accumulator, &argSqrd);
|
||||||
negate_Xsig(&accumulator);
|
negate_Xsig(&accumulator);
|
||||||
|
|
||||||
polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_l,
|
polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_l,
|
||||||
N_COEFF_P-1);
|
N_COEFF_P - 1);
|
||||||
|
|
||||||
shr_Xsig(&accumulator, 2); /* Divide by four */
|
shr_Xsig(&accumulator, 2); /* Divide by four */
|
||||||
accumulator.msw |= 0x80000000; /* Add 1.0 */
|
accumulator.msw |= 0x80000000; /* Add 1.0 */
|
||||||
|
|
||||||
mul64_Xsig(&accumulator, &significand(st0_ptr));
|
mul64_Xsig(&accumulator, &significand(st0_ptr));
|
||||||
mul64_Xsig(&accumulator, &significand(st0_ptr));
|
mul64_Xsig(&accumulator, &significand(st0_ptr));
|
||||||
mul64_Xsig(&accumulator, &significand(st0_ptr));
|
mul64_Xsig(&accumulator, &significand(st0_ptr));
|
||||||
|
|
||||||
/* Divide by four, FPU_REG compatible, etc */
|
/* Divide by four, FPU_REG compatible, etc */
|
||||||
exponent = 3*exponent;
|
exponent = 3 * exponent;
|
||||||
|
|
||||||
/* The minimum exponent difference is 3 */
|
/* The minimum exponent difference is 3 */
|
||||||
shr_Xsig(&accumulator, exponent(st0_ptr) - exponent);
|
shr_Xsig(&accumulator, exponent(st0_ptr) - exponent);
|
||||||
|
|
||||||
negate_Xsig(&accumulator);
|
negate_Xsig(&accumulator);
|
||||||
XSIG_LL(accumulator) += significand(st0_ptr);
|
XSIG_LL(accumulator) += significand(st0_ptr);
|
||||||
|
|
||||||
echange = round_Xsig(&accumulator);
|
echange = round_Xsig(&accumulator);
|
||||||
|
|
||||||
setexponentpos(&result, exponent(st0_ptr) + echange);
|
setexponentpos(&result, exponent(st0_ptr) + echange);
|
||||||
}
|
} else {
|
||||||
else
|
/* The argument is > 0.88309101259 */
|
||||||
{
|
/* We use sin(st(0)) = cos(pi/2-st(0)) */
|
||||||
/* The argument is > 0.88309101259 */
|
|
||||||
/* We use sin(st(0)) = cos(pi/2-st(0)) */
|
|
||||||
|
|
||||||
fixed_arg = significand(st0_ptr);
|
fixed_arg = significand(st0_ptr);
|
||||||
|
|
||||||
if ( exponent == 0 )
|
if (exponent == 0) {
|
||||||
{
|
/* The argument is >= 1.0 */
|
||||||
/* The argument is >= 1.0 */
|
|
||||||
|
|
||||||
/* Put the binary point at the left. */
|
/* Put the binary point at the left. */
|
||||||
fixed_arg <<= 1;
|
fixed_arg <<= 1;
|
||||||
|
}
|
||||||
|
/* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */
|
||||||
|
fixed_arg = 0x921fb54442d18469LL - fixed_arg;
|
||||||
|
/* There is a special case which arises due to rounding, to fix here. */
|
||||||
|
if (fixed_arg == 0xffffffffffffffffLL)
|
||||||
|
fixed_arg = 0;
|
||||||
|
|
||||||
|
XSIG_LL(argSqrd) = fixed_arg;
|
||||||
|
argSqrd.lsw = 0;
|
||||||
|
mul64_Xsig(&argSqrd, &fixed_arg);
|
||||||
|
|
||||||
|
XSIG_LL(argTo4) = XSIG_LL(argSqrd);
|
||||||
|
argTo4.lsw = argSqrd.lsw;
|
||||||
|
mul_Xsig_Xsig(&argTo4, &argTo4);
|
||||||
|
|
||||||
|
polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_h,
|
||||||
|
N_COEFF_NH - 1);
|
||||||
|
mul_Xsig_Xsig(&accumulator, &argSqrd);
|
||||||
|
negate_Xsig(&accumulator);
|
||||||
|
|
||||||
|
polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_h,
|
||||||
|
N_COEFF_PH - 1);
|
||||||
|
negate_Xsig(&accumulator);
|
||||||
|
|
||||||
|
mul64_Xsig(&accumulator, &fixed_arg);
|
||||||
|
mul64_Xsig(&accumulator, &fixed_arg);
|
||||||
|
|
||||||
|
shr_Xsig(&accumulator, 3);
|
||||||
|
negate_Xsig(&accumulator);
|
||||||
|
|
||||||
|
add_Xsig_Xsig(&accumulator, &argSqrd);
|
||||||
|
|
||||||
|
shr_Xsig(&accumulator, 1);
|
||||||
|
|
||||||
|
accumulator.lsw |= 1; /* A zero accumulator here would cause problems */
|
||||||
|
negate_Xsig(&accumulator);
|
||||||
|
|
||||||
|
/* The basic computation is complete. Now fix the answer to
|
||||||
|
compensate for the error due to the approximation used for
|
||||||
|
pi/2
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This has an exponent of -65 */
|
||||||
|
fix_up = 0x898cc517;
|
||||||
|
/* The fix-up needs to be improved for larger args */
|
||||||
|
if (argSqrd.msw & 0xffc00000) {
|
||||||
|
/* Get about 32 bit precision in these: */
|
||||||
|
fix_up -= mul_32_32(0x898cc517, argSqrd.msw) / 6;
|
||||||
|
}
|
||||||
|
fix_up = mul_32_32(fix_up, LL_MSW(fixed_arg));
|
||||||
|
|
||||||
|
adj = accumulator.lsw; /* temp save */
|
||||||
|
accumulator.lsw -= fix_up;
|
||||||
|
if (accumulator.lsw > adj)
|
||||||
|
XSIG_LL(accumulator)--;
|
||||||
|
|
||||||
|
echange = round_Xsig(&accumulator);
|
||||||
|
|
||||||
|
setexponentpos(&result, echange - 1);
|
||||||
}
|
}
|
||||||
/* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */
|
|
||||||
fixed_arg = 0x921fb54442d18469LL - fixed_arg;
|
|
||||||
/* There is a special case which arises due to rounding, to fix here. */
|
|
||||||
if ( fixed_arg == 0xffffffffffffffffLL )
|
|
||||||
fixed_arg = 0;
|
|
||||||
|
|
||||||
XSIG_LL(argSqrd) = fixed_arg; argSqrd.lsw = 0;
|
significand(&result) = XSIG_LL(accumulator);
|
||||||
mul64_Xsig(&argSqrd, &fixed_arg);
|
setsign(&result, getsign(st0_ptr));
|
||||||
|
FPU_copy_to_reg0(&result, TAG_Valid);
|
||||||
XSIG_LL(argTo4) = XSIG_LL(argSqrd); argTo4.lsw = argSqrd.lsw;
|
|
||||||
mul_Xsig_Xsig(&argTo4, &argTo4);
|
|
||||||
|
|
||||||
polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_h,
|
|
||||||
N_COEFF_NH-1);
|
|
||||||
mul_Xsig_Xsig(&accumulator, &argSqrd);
|
|
||||||
negate_Xsig(&accumulator);
|
|
||||||
|
|
||||||
polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_h,
|
|
||||||
N_COEFF_PH-1);
|
|
||||||
negate_Xsig(&accumulator);
|
|
||||||
|
|
||||||
mul64_Xsig(&accumulator, &fixed_arg);
|
|
||||||
mul64_Xsig(&accumulator, &fixed_arg);
|
|
||||||
|
|
||||||
shr_Xsig(&accumulator, 3);
|
|
||||||
negate_Xsig(&accumulator);
|
|
||||||
|
|
||||||
add_Xsig_Xsig(&accumulator, &argSqrd);
|
|
||||||
|
|
||||||
shr_Xsig(&accumulator, 1);
|
|
||||||
|
|
||||||
accumulator.lsw |= 1; /* A zero accumulator here would cause problems */
|
|
||||||
negate_Xsig(&accumulator);
|
|
||||||
|
|
||||||
/* The basic computation is complete. Now fix the answer to
|
|
||||||
compensate for the error due to the approximation used for
|
|
||||||
pi/2
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* This has an exponent of -65 */
|
|
||||||
fix_up = 0x898cc517;
|
|
||||||
/* The fix-up needs to be improved for larger args */
|
|
||||||
if ( argSqrd.msw & 0xffc00000 )
|
|
||||||
{
|
|
||||||
/* Get about 32 bit precision in these: */
|
|
||||||
fix_up -= mul_32_32(0x898cc517, argSqrd.msw) / 6;
|
|
||||||
}
|
|
||||||
fix_up = mul_32_32(fix_up, LL_MSW(fixed_arg));
|
|
||||||
|
|
||||||
adj = accumulator.lsw; /* temp save */
|
|
||||||
accumulator.lsw -= fix_up;
|
|
||||||
if ( accumulator.lsw > adj )
|
|
||||||
XSIG_LL(accumulator) --;
|
|
||||||
|
|
||||||
echange = round_Xsig(&accumulator);
|
|
||||||
|
|
||||||
setexponentpos(&result, echange - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
significand(&result) = XSIG_LL(accumulator);
|
|
||||||
setsign(&result, getsign(st0_ptr));
|
|
||||||
FPU_copy_to_reg0(&result, TAG_Valid);
|
|
||||||
|
|
||||||
#ifdef PARANOID
|
#ifdef PARANOID
|
||||||
if ( (exponent(&result) >= 0)
|
if ((exponent(&result) >= 0)
|
||||||
&& (significand(&result) > 0x8000000000000000LL) )
|
&& (significand(&result) > 0x8000000000000000LL)) {
|
||||||
{
|
EXCEPTION(EX_INTERNAL | 0x150);
|
||||||
EXCEPTION(EX_INTERNAL|0x150);
|
}
|
||||||
}
|
|
||||||
#endif /* PARANOID */
|
#endif /* PARANOID */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*--- poly_cos() ------------------------------------------------------------+
|
/*--- poly_cos() ------------------------------------------------------------+
|
||||||
| |
|
| |
|
||||||
+---------------------------------------------------------------------------*/
|
+---------------------------------------------------------------------------*/
|
||||||
void poly_cos(FPU_REG *st0_ptr)
|
void poly_cos(FPU_REG * st0_ptr)
|
||||||
{
|
{
|
||||||
FPU_REG result;
|
FPU_REG result;
|
||||||
long int exponent, exp2, echange;
|
long int exponent, exp2, echange;
|
||||||
Xsig accumulator, argSqrd, fix_up, argTo4;
|
Xsig accumulator, argSqrd, fix_up, argTo4;
|
||||||
unsigned long long fixed_arg;
|
unsigned long long fixed_arg;
|
||||||
|
|
||||||
#ifdef PARANOID
|
#ifdef PARANOID
|
||||||
if ( (exponent(st0_ptr) > 0)
|
if ((exponent(st0_ptr) > 0)
|
||||||
|| ((exponent(st0_ptr) == 0)
|
|| ((exponent(st0_ptr) == 0)
|
||||||
&& (significand(st0_ptr) > 0xc90fdaa22168c234LL)) )
|
&& (significand(st0_ptr) > 0xc90fdaa22168c234LL))) {
|
||||||
{
|
EXCEPTION(EX_Invalid);
|
||||||
EXCEPTION(EX_Invalid);
|
FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
|
||||||
FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
#endif /* PARANOID */
|
#endif /* PARANOID */
|
||||||
|
|
||||||
exponent = exponent(st0_ptr);
|
exponent = exponent(st0_ptr);
|
||||||
|
|
||||||
accumulator.lsw = accumulator.midw = accumulator.msw = 0;
|
accumulator.lsw = accumulator.midw = accumulator.msw = 0;
|
||||||
|
|
||||||
if ( (exponent < -1) || ((exponent == -1) && (st0_ptr->sigh <= 0xb00d6f54)) )
|
if ((exponent < -1)
|
||||||
{
|
|| ((exponent == -1) && (st0_ptr->sigh <= 0xb00d6f54))) {
|
||||||
/* arg is < 0.687705 */
|
/* arg is < 0.687705 */
|
||||||
|
|
||||||
argSqrd.msw = st0_ptr->sigh; argSqrd.midw = st0_ptr->sigl;
|
argSqrd.msw = st0_ptr->sigh;
|
||||||
argSqrd.lsw = 0;
|
argSqrd.midw = st0_ptr->sigl;
|
||||||
mul64_Xsig(&argSqrd, &significand(st0_ptr));
|
argSqrd.lsw = 0;
|
||||||
|
mul64_Xsig(&argSqrd, &significand(st0_ptr));
|
||||||
|
|
||||||
if ( exponent < -1 )
|
if (exponent < -1) {
|
||||||
{
|
/* shift the argument right by the required places */
|
||||||
/* shift the argument right by the required places */
|
shr_Xsig(&argSqrd, 2 * (-1 - exponent));
|
||||||
shr_Xsig(&argSqrd, 2*(-1-exponent));
|
}
|
||||||
|
|
||||||
|
argTo4.msw = argSqrd.msw;
|
||||||
|
argTo4.midw = argSqrd.midw;
|
||||||
|
argTo4.lsw = argSqrd.lsw;
|
||||||
|
mul_Xsig_Xsig(&argTo4, &argTo4);
|
||||||
|
|
||||||
|
polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_h,
|
||||||
|
N_COEFF_NH - 1);
|
||||||
|
mul_Xsig_Xsig(&accumulator, &argSqrd);
|
||||||
|
negate_Xsig(&accumulator);
|
||||||
|
|
||||||
|
polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_h,
|
||||||
|
N_COEFF_PH - 1);
|
||||||
|
negate_Xsig(&accumulator);
|
||||||
|
|
||||||
|
mul64_Xsig(&accumulator, &significand(st0_ptr));
|
||||||
|
mul64_Xsig(&accumulator, &significand(st0_ptr));
|
||||||
|
shr_Xsig(&accumulator, -2 * (1 + exponent));
|
||||||
|
|
||||||
|
shr_Xsig(&accumulator, 3);
|
||||||
|
negate_Xsig(&accumulator);
|
||||||
|
|
||||||
|
add_Xsig_Xsig(&accumulator, &argSqrd);
|
||||||
|
|
||||||
|
shr_Xsig(&accumulator, 1);
|
||||||
|
|
||||||
|
/* It doesn't matter if accumulator is all zero here, the
|
||||||
|
following code will work ok */
|
||||||
|
negate_Xsig(&accumulator);
|
||||||
|
|
||||||
|
if (accumulator.lsw & 0x80000000)
|
||||||
|
XSIG_LL(accumulator)++;
|
||||||
|
if (accumulator.msw == 0) {
|
||||||
|
/* The result is 1.0 */
|
||||||
|
FPU_copy_to_reg0(&CONST_1, TAG_Valid);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
significand(&result) = XSIG_LL(accumulator);
|
||||||
|
|
||||||
|
/* will be a valid positive nr with expon = -1 */
|
||||||
|
setexponentpos(&result, -1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fixed_arg = significand(st0_ptr);
|
||||||
|
|
||||||
|
if (exponent == 0) {
|
||||||
|
/* The argument is >= 1.0 */
|
||||||
|
|
||||||
|
/* Put the binary point at the left. */
|
||||||
|
fixed_arg <<= 1;
|
||||||
|
}
|
||||||
|
/* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */
|
||||||
|
fixed_arg = 0x921fb54442d18469LL - fixed_arg;
|
||||||
|
/* There is a special case which arises due to rounding, to fix here. */
|
||||||
|
if (fixed_arg == 0xffffffffffffffffLL)
|
||||||
|
fixed_arg = 0;
|
||||||
|
|
||||||
|
exponent = -1;
|
||||||
|
exp2 = -1;
|
||||||
|
|
||||||
|
/* A shift is needed here only for a narrow range of arguments,
|
||||||
|
i.e. for fixed_arg approx 2^-32, but we pick up more... */
|
||||||
|
if (!(LL_MSW(fixed_arg) & 0xffff0000)) {
|
||||||
|
fixed_arg <<= 16;
|
||||||
|
exponent -= 16;
|
||||||
|
exp2 -= 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
XSIG_LL(argSqrd) = fixed_arg;
|
||||||
|
argSqrd.lsw = 0;
|
||||||
|
mul64_Xsig(&argSqrd, &fixed_arg);
|
||||||
|
|
||||||
|
if (exponent < -1) {
|
||||||
|
/* shift the argument right by the required places */
|
||||||
|
shr_Xsig(&argSqrd, 2 * (-1 - exponent));
|
||||||
|
}
|
||||||
|
|
||||||
|
argTo4.msw = argSqrd.msw;
|
||||||
|
argTo4.midw = argSqrd.midw;
|
||||||
|
argTo4.lsw = argSqrd.lsw;
|
||||||
|
mul_Xsig_Xsig(&argTo4, &argTo4);
|
||||||
|
|
||||||
|
polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_l,
|
||||||
|
N_COEFF_N - 1);
|
||||||
|
mul_Xsig_Xsig(&accumulator, &argSqrd);
|
||||||
|
negate_Xsig(&accumulator);
|
||||||
|
|
||||||
|
polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_l,
|
||||||
|
N_COEFF_P - 1);
|
||||||
|
|
||||||
|
shr_Xsig(&accumulator, 2); /* Divide by four */
|
||||||
|
accumulator.msw |= 0x80000000; /* Add 1.0 */
|
||||||
|
|
||||||
|
mul64_Xsig(&accumulator, &fixed_arg);
|
||||||
|
mul64_Xsig(&accumulator, &fixed_arg);
|
||||||
|
mul64_Xsig(&accumulator, &fixed_arg);
|
||||||
|
|
||||||
|
/* Divide by four, FPU_REG compatible, etc */
|
||||||
|
exponent = 3 * exponent;
|
||||||
|
|
||||||
|
/* The minimum exponent difference is 3 */
|
||||||
|
shr_Xsig(&accumulator, exp2 - exponent);
|
||||||
|
|
||||||
|
negate_Xsig(&accumulator);
|
||||||
|
XSIG_LL(accumulator) += fixed_arg;
|
||||||
|
|
||||||
|
/* The basic computation is complete. Now fix the answer to
|
||||||
|
compensate for the error due to the approximation used for
|
||||||
|
pi/2
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This has an exponent of -65 */
|
||||||
|
XSIG_LL(fix_up) = 0x898cc51701b839a2ll;
|
||||||
|
fix_up.lsw = 0;
|
||||||
|
|
||||||
|
/* The fix-up needs to be improved for larger args */
|
||||||
|
if (argSqrd.msw & 0xffc00000) {
|
||||||
|
/* Get about 32 bit precision in these: */
|
||||||
|
fix_up.msw -= mul_32_32(0x898cc517, argSqrd.msw) / 2;
|
||||||
|
fix_up.msw += mul_32_32(0x898cc517, argTo4.msw) / 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
exp2 += norm_Xsig(&accumulator);
|
||||||
|
shr_Xsig(&accumulator, 1); /* Prevent overflow */
|
||||||
|
exp2++;
|
||||||
|
shr_Xsig(&fix_up, 65 + exp2);
|
||||||
|
|
||||||
|
add_Xsig_Xsig(&accumulator, &fix_up);
|
||||||
|
|
||||||
|
echange = round_Xsig(&accumulator);
|
||||||
|
|
||||||
|
setexponentpos(&result, exp2 + echange);
|
||||||
|
significand(&result) = XSIG_LL(accumulator);
|
||||||
}
|
}
|
||||||
|
|
||||||
argTo4.msw = argSqrd.msw; argTo4.midw = argSqrd.midw;
|
FPU_copy_to_reg0(&result, TAG_Valid);
|
||||||
argTo4.lsw = argSqrd.lsw;
|
|
||||||
mul_Xsig_Xsig(&argTo4, &argTo4);
|
|
||||||
|
|
||||||
polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_h,
|
|
||||||
N_COEFF_NH-1);
|
|
||||||
mul_Xsig_Xsig(&accumulator, &argSqrd);
|
|
||||||
negate_Xsig(&accumulator);
|
|
||||||
|
|
||||||
polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_h,
|
|
||||||
N_COEFF_PH-1);
|
|
||||||
negate_Xsig(&accumulator);
|
|
||||||
|
|
||||||
mul64_Xsig(&accumulator, &significand(st0_ptr));
|
|
||||||
mul64_Xsig(&accumulator, &significand(st0_ptr));
|
|
||||||
shr_Xsig(&accumulator, -2*(1+exponent));
|
|
||||||
|
|
||||||
shr_Xsig(&accumulator, 3);
|
|
||||||
negate_Xsig(&accumulator);
|
|
||||||
|
|
||||||
add_Xsig_Xsig(&accumulator, &argSqrd);
|
|
||||||
|
|
||||||
shr_Xsig(&accumulator, 1);
|
|
||||||
|
|
||||||
/* It doesn't matter if accumulator is all zero here, the
|
|
||||||
following code will work ok */
|
|
||||||
negate_Xsig(&accumulator);
|
|
||||||
|
|
||||||
if ( accumulator.lsw & 0x80000000 )
|
|
||||||
XSIG_LL(accumulator) ++;
|
|
||||||
if ( accumulator.msw == 0 )
|
|
||||||
{
|
|
||||||
/* The result is 1.0 */
|
|
||||||
FPU_copy_to_reg0(&CONST_1, TAG_Valid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
significand(&result) = XSIG_LL(accumulator);
|
|
||||||
|
|
||||||
/* will be a valid positive nr with expon = -1 */
|
|
||||||
setexponentpos(&result, -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fixed_arg = significand(st0_ptr);
|
|
||||||
|
|
||||||
if ( exponent == 0 )
|
|
||||||
{
|
|
||||||
/* The argument is >= 1.0 */
|
|
||||||
|
|
||||||
/* Put the binary point at the left. */
|
|
||||||
fixed_arg <<= 1;
|
|
||||||
}
|
|
||||||
/* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */
|
|
||||||
fixed_arg = 0x921fb54442d18469LL - fixed_arg;
|
|
||||||
/* There is a special case which arises due to rounding, to fix here. */
|
|
||||||
if ( fixed_arg == 0xffffffffffffffffLL )
|
|
||||||
fixed_arg = 0;
|
|
||||||
|
|
||||||
exponent = -1;
|
|
||||||
exp2 = -1;
|
|
||||||
|
|
||||||
/* A shift is needed here only for a narrow range of arguments,
|
|
||||||
i.e. for fixed_arg approx 2^-32, but we pick up more... */
|
|
||||||
if ( !(LL_MSW(fixed_arg) & 0xffff0000) )
|
|
||||||
{
|
|
||||||
fixed_arg <<= 16;
|
|
||||||
exponent -= 16;
|
|
||||||
exp2 -= 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
XSIG_LL(argSqrd) = fixed_arg; argSqrd.lsw = 0;
|
|
||||||
mul64_Xsig(&argSqrd, &fixed_arg);
|
|
||||||
|
|
||||||
if ( exponent < -1 )
|
|
||||||
{
|
|
||||||
/* shift the argument right by the required places */
|
|
||||||
shr_Xsig(&argSqrd, 2*(-1-exponent));
|
|
||||||
}
|
|
||||||
|
|
||||||
argTo4.msw = argSqrd.msw; argTo4.midw = argSqrd.midw;
|
|
||||||
argTo4.lsw = argSqrd.lsw;
|
|
||||||
mul_Xsig_Xsig(&argTo4, &argTo4);
|
|
||||||
|
|
||||||
polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_l,
|
|
||||||
N_COEFF_N-1);
|
|
||||||
mul_Xsig_Xsig(&accumulator, &argSqrd);
|
|
||||||
negate_Xsig(&accumulator);
|
|
||||||
|
|
||||||
polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_l,
|
|
||||||
N_COEFF_P-1);
|
|
||||||
|
|
||||||
shr_Xsig(&accumulator, 2); /* Divide by four */
|
|
||||||
accumulator.msw |= 0x80000000; /* Add 1.0 */
|
|
||||||
|
|
||||||
mul64_Xsig(&accumulator, &fixed_arg);
|
|
||||||
mul64_Xsig(&accumulator, &fixed_arg);
|
|
||||||
mul64_Xsig(&accumulator, &fixed_arg);
|
|
||||||
|
|
||||||
/* Divide by four, FPU_REG compatible, etc */
|
|
||||||
exponent = 3*exponent;
|
|
||||||
|
|
||||||
/* The minimum exponent difference is 3 */
|
|
||||||
shr_Xsig(&accumulator, exp2 - exponent);
|
|
||||||
|
|
||||||
negate_Xsig(&accumulator);
|
|
||||||
XSIG_LL(accumulator) += fixed_arg;
|
|
||||||
|
|
||||||
/* The basic computation is complete. Now fix the answer to
|
|
||||||
compensate for the error due to the approximation used for
|
|
||||||
pi/2
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* This has an exponent of -65 */
|
|
||||||
XSIG_LL(fix_up) = 0x898cc51701b839a2ll;
|
|
||||||
fix_up.lsw = 0;
|
|
||||||
|
|
||||||
/* The fix-up needs to be improved for larger args */
|
|
||||||
if ( argSqrd.msw & 0xffc00000 )
|
|
||||||
{
|
|
||||||
/* Get about 32 bit precision in these: */
|
|
||||||
fix_up.msw -= mul_32_32(0x898cc517, argSqrd.msw) / 2;
|
|
||||||
fix_up.msw += mul_32_32(0x898cc517, argTo4.msw) / 24;
|
|
||||||
}
|
|
||||||
|
|
||||||
exp2 += norm_Xsig(&accumulator);
|
|
||||||
shr_Xsig(&accumulator, 1); /* Prevent overflow */
|
|
||||||
exp2++;
|
|
||||||
shr_Xsig(&fix_up, 65 + exp2);
|
|
||||||
|
|
||||||
add_Xsig_Xsig(&accumulator, &fix_up);
|
|
||||||
|
|
||||||
echange = round_Xsig(&accumulator);
|
|
||||||
|
|
||||||
setexponentpos(&result, exp2 + echange);
|
|
||||||
significand(&result) = XSIG_LL(accumulator);
|
|
||||||
}
|
|
||||||
|
|
||||||
FPU_copy_to_reg0(&result, TAG_Valid);
|
|
||||||
|
|
||||||
#ifdef PARANOID
|
#ifdef PARANOID
|
||||||
if ( (exponent(&result) >= 0)
|
if ((exponent(&result) >= 0)
|
||||||
&& (significand(&result) > 0x8000000000000000LL) )
|
&& (significand(&result) > 0x8000000000000000LL)) {
|
||||||
{
|
EXCEPTION(EX_INTERNAL | 0x151);
|
||||||
EXCEPTION(EX_INTERNAL|0x151);
|
}
|
||||||
}
|
|
||||||
#endif /* PARANOID */
|
#endif /* PARANOID */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -17,206 +17,196 @@
|
|||||||
#include "control_w.h"
|
#include "control_w.h"
|
||||||
#include "poly.h"
|
#include "poly.h"
|
||||||
|
|
||||||
|
|
||||||
#define HiPOWERop 3 /* odd poly, positive terms */
|
#define HiPOWERop 3 /* odd poly, positive terms */
|
||||||
static const unsigned long long oddplterm[HiPOWERop] =
|
static const unsigned long long oddplterm[HiPOWERop] = {
|
||||||
{
|
0x0000000000000000LL,
|
||||||
0x0000000000000000LL,
|
0x0051a1cf08fca228LL,
|
||||||
0x0051a1cf08fca228LL,
|
0x0000000071284ff7LL
|
||||||
0x0000000071284ff7LL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define HiPOWERon 2 /* odd poly, negative terms */
|
#define HiPOWERon 2 /* odd poly, negative terms */
|
||||||
static const unsigned long long oddnegterm[HiPOWERon] =
|
static const unsigned long long oddnegterm[HiPOWERon] = {
|
||||||
{
|
0x1291a9a184244e80LL,
|
||||||
0x1291a9a184244e80LL,
|
0x0000583245819c21LL
|
||||||
0x0000583245819c21LL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define HiPOWERep 2 /* even poly, positive terms */
|
#define HiPOWERep 2 /* even poly, positive terms */
|
||||||
static const unsigned long long evenplterm[HiPOWERep] =
|
static const unsigned long long evenplterm[HiPOWERep] = {
|
||||||
{
|
0x0e848884b539e888LL,
|
||||||
0x0e848884b539e888LL,
|
0x00003c7f18b887daLL
|
||||||
0x00003c7f18b887daLL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define HiPOWERen 2 /* even poly, negative terms */
|
#define HiPOWERen 2 /* even poly, negative terms */
|
||||||
static const unsigned long long evennegterm[HiPOWERen] =
|
static const unsigned long long evennegterm[HiPOWERen] = {
|
||||||
{
|
0xf1f0200fd51569ccLL,
|
||||||
0xf1f0200fd51569ccLL,
|
0x003afb46105c4432LL
|
||||||
0x003afb46105c4432LL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned long long twothirds = 0xaaaaaaaaaaaaaaabLL;
|
static const unsigned long long twothirds = 0xaaaaaaaaaaaaaaabLL;
|
||||||
|
|
||||||
|
|
||||||
/*--- poly_tan() ------------------------------------------------------------+
|
/*--- poly_tan() ------------------------------------------------------------+
|
||||||
| |
|
| |
|
||||||
+---------------------------------------------------------------------------*/
|
+---------------------------------------------------------------------------*/
|
||||||
void poly_tan(FPU_REG *st0_ptr)
|
void poly_tan(FPU_REG * st0_ptr)
|
||||||
{
|
{
|
||||||
long int exponent;
|
long int exponent;
|
||||||
int invert;
|
int invert;
|
||||||
Xsig argSq, argSqSq, accumulatoro, accumulatore, accum,
|
Xsig argSq, argSqSq, accumulatoro, accumulatore, accum,
|
||||||
argSignif, fix_up;
|
argSignif, fix_up;
|
||||||
unsigned long adj;
|
unsigned long adj;
|
||||||
|
|
||||||
exponent = exponent(st0_ptr);
|
exponent = exponent(st0_ptr);
|
||||||
|
|
||||||
#ifdef PARANOID
|
#ifdef PARANOID
|
||||||
if ( signnegative(st0_ptr) ) /* Can't hack a number < 0.0 */
|
if (signnegative(st0_ptr)) { /* Can't hack a number < 0.0 */
|
||||||
{ arith_invalid(0); return; } /* Need a positive number */
|
arith_invalid(0);
|
||||||
|
return;
|
||||||
|
} /* Need a positive number */
|
||||||
#endif /* PARANOID */
|
#endif /* PARANOID */
|
||||||
|
|
||||||
/* Split the problem into two domains, smaller and larger than pi/4 */
|
/* Split the problem into two domains, smaller and larger than pi/4 */
|
||||||
if ( (exponent == 0) || ((exponent == -1) && (st0_ptr->sigh > 0xc90fdaa2)) )
|
if ((exponent == 0)
|
||||||
{
|
|| ((exponent == -1) && (st0_ptr->sigh > 0xc90fdaa2))) {
|
||||||
/* The argument is greater than (approx) pi/4 */
|
/* The argument is greater than (approx) pi/4 */
|
||||||
invert = 1;
|
invert = 1;
|
||||||
accum.lsw = 0;
|
accum.lsw = 0;
|
||||||
XSIG_LL(accum) = significand(st0_ptr);
|
XSIG_LL(accum) = significand(st0_ptr);
|
||||||
|
|
||||||
if ( exponent == 0 )
|
if (exponent == 0) {
|
||||||
{
|
/* The argument is >= 1.0 */
|
||||||
/* The argument is >= 1.0 */
|
/* Put the binary point at the left. */
|
||||||
/* Put the binary point at the left. */
|
XSIG_LL(accum) <<= 1;
|
||||||
XSIG_LL(accum) <<= 1;
|
}
|
||||||
}
|
/* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */
|
||||||
/* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */
|
XSIG_LL(accum) = 0x921fb54442d18469LL - XSIG_LL(accum);
|
||||||
XSIG_LL(accum) = 0x921fb54442d18469LL - XSIG_LL(accum);
|
/* This is a special case which arises due to rounding. */
|
||||||
/* This is a special case which arises due to rounding. */
|
if (XSIG_LL(accum) == 0xffffffffffffffffLL) {
|
||||||
if ( XSIG_LL(accum) == 0xffffffffffffffffLL )
|
FPU_settag0(TAG_Valid);
|
||||||
{
|
significand(st0_ptr) = 0x8a51e04daabda360LL;
|
||||||
FPU_settag0(TAG_Valid);
|
setexponent16(st0_ptr,
|
||||||
significand(st0_ptr) = 0x8a51e04daabda360LL;
|
(0x41 + EXTENDED_Ebias) | SIGN_Negative);
|
||||||
setexponent16(st0_ptr, (0x41 + EXTENDED_Ebias) | SIGN_Negative);
|
return;
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
argSignif.lsw = accum.lsw;
|
||||||
|
XSIG_LL(argSignif) = XSIG_LL(accum);
|
||||||
|
exponent = -1 + norm_Xsig(&argSignif);
|
||||||
|
} else {
|
||||||
|
invert = 0;
|
||||||
|
argSignif.lsw = 0;
|
||||||
|
XSIG_LL(accum) = XSIG_LL(argSignif) = significand(st0_ptr);
|
||||||
|
|
||||||
|
if (exponent < -1) {
|
||||||
|
/* shift the argument right by the required places */
|
||||||
|
if (FPU_shrx(&XSIG_LL(accum), -1 - exponent) >=
|
||||||
|
0x80000000U)
|
||||||
|
XSIG_LL(accum)++; /* round up */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
argSignif.lsw = accum.lsw;
|
XSIG_LL(argSq) = XSIG_LL(accum);
|
||||||
XSIG_LL(argSignif) = XSIG_LL(accum);
|
argSq.lsw = accum.lsw;
|
||||||
exponent = -1 + norm_Xsig(&argSignif);
|
mul_Xsig_Xsig(&argSq, &argSq);
|
||||||
}
|
XSIG_LL(argSqSq) = XSIG_LL(argSq);
|
||||||
else
|
argSqSq.lsw = argSq.lsw;
|
||||||
{
|
mul_Xsig_Xsig(&argSqSq, &argSqSq);
|
||||||
invert = 0;
|
|
||||||
argSignif.lsw = 0;
|
/* Compute the negative terms for the numerator polynomial */
|
||||||
XSIG_LL(accum) = XSIG_LL(argSignif) = significand(st0_ptr);
|
accumulatoro.msw = accumulatoro.midw = accumulatoro.lsw = 0;
|
||||||
|
polynomial_Xsig(&accumulatoro, &XSIG_LL(argSqSq), oddnegterm,
|
||||||
if ( exponent < -1 )
|
HiPOWERon - 1);
|
||||||
{
|
mul_Xsig_Xsig(&accumulatoro, &argSq);
|
||||||
/* shift the argument right by the required places */
|
negate_Xsig(&accumulatoro);
|
||||||
if ( FPU_shrx(&XSIG_LL(accum), -1-exponent) >= 0x80000000U )
|
/* Add the positive terms */
|
||||||
XSIG_LL(accum) ++; /* round up */
|
polynomial_Xsig(&accumulatoro, &XSIG_LL(argSqSq), oddplterm,
|
||||||
|
HiPOWERop - 1);
|
||||||
|
|
||||||
|
/* Compute the positive terms for the denominator polynomial */
|
||||||
|
accumulatore.msw = accumulatore.midw = accumulatore.lsw = 0;
|
||||||
|
polynomial_Xsig(&accumulatore, &XSIG_LL(argSqSq), evenplterm,
|
||||||
|
HiPOWERep - 1);
|
||||||
|
mul_Xsig_Xsig(&accumulatore, &argSq);
|
||||||
|
negate_Xsig(&accumulatore);
|
||||||
|
/* Add the negative terms */
|
||||||
|
polynomial_Xsig(&accumulatore, &XSIG_LL(argSqSq), evennegterm,
|
||||||
|
HiPOWERen - 1);
|
||||||
|
/* Multiply by arg^2 */
|
||||||
|
mul64_Xsig(&accumulatore, &XSIG_LL(argSignif));
|
||||||
|
mul64_Xsig(&accumulatore, &XSIG_LL(argSignif));
|
||||||
|
/* de-normalize and divide by 2 */
|
||||||
|
shr_Xsig(&accumulatore, -2 * (1 + exponent) + 1);
|
||||||
|
negate_Xsig(&accumulatore); /* This does 1 - accumulator */
|
||||||
|
|
||||||
|
/* Now find the ratio. */
|
||||||
|
if (accumulatore.msw == 0) {
|
||||||
|
/* accumulatoro must contain 1.0 here, (actually, 0) but it
|
||||||
|
really doesn't matter what value we use because it will
|
||||||
|
have negligible effect in later calculations
|
||||||
|
*/
|
||||||
|
XSIG_LL(accum) = 0x8000000000000000LL;
|
||||||
|
accum.lsw = 0;
|
||||||
|
} else {
|
||||||
|
div_Xsig(&accumulatoro, &accumulatore, &accum);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
XSIG_LL(argSq) = XSIG_LL(accum); argSq.lsw = accum.lsw;
|
/* Multiply by 1/3 * arg^3 */
|
||||||
mul_Xsig_Xsig(&argSq, &argSq);
|
mul64_Xsig(&accum, &XSIG_LL(argSignif));
|
||||||
XSIG_LL(argSqSq) = XSIG_LL(argSq); argSqSq.lsw = argSq.lsw;
|
mul64_Xsig(&accum, &XSIG_LL(argSignif));
|
||||||
mul_Xsig_Xsig(&argSqSq, &argSqSq);
|
mul64_Xsig(&accum, &XSIG_LL(argSignif));
|
||||||
|
mul64_Xsig(&accum, &twothirds);
|
||||||
|
shr_Xsig(&accum, -2 * (exponent + 1));
|
||||||
|
|
||||||
/* Compute the negative terms for the numerator polynomial */
|
/* tan(arg) = arg + accum */
|
||||||
accumulatoro.msw = accumulatoro.midw = accumulatoro.lsw = 0;
|
add_two_Xsig(&accum, &argSignif, &exponent);
|
||||||
polynomial_Xsig(&accumulatoro, &XSIG_LL(argSqSq), oddnegterm, HiPOWERon-1);
|
|
||||||
mul_Xsig_Xsig(&accumulatoro, &argSq);
|
|
||||||
negate_Xsig(&accumulatoro);
|
|
||||||
/* Add the positive terms */
|
|
||||||
polynomial_Xsig(&accumulatoro, &XSIG_LL(argSqSq), oddplterm, HiPOWERop-1);
|
|
||||||
|
|
||||||
|
if (invert) {
|
||||||
/* Compute the positive terms for the denominator polynomial */
|
/* We now have the value of tan(pi_2 - arg) where pi_2 is an
|
||||||
accumulatore.msw = accumulatore.midw = accumulatore.lsw = 0;
|
approximation for pi/2
|
||||||
polynomial_Xsig(&accumulatore, &XSIG_LL(argSqSq), evenplterm, HiPOWERep-1);
|
*/
|
||||||
mul_Xsig_Xsig(&accumulatore, &argSq);
|
/* The next step is to fix the answer to compensate for the
|
||||||
negate_Xsig(&accumulatore);
|
error due to the approximation used for pi/2
|
||||||
/* Add the negative terms */
|
*/
|
||||||
polynomial_Xsig(&accumulatore, &XSIG_LL(argSqSq), evennegterm, HiPOWERen-1);
|
|
||||||
/* Multiply by arg^2 */
|
|
||||||
mul64_Xsig(&accumulatore, &XSIG_LL(argSignif));
|
|
||||||
mul64_Xsig(&accumulatore, &XSIG_LL(argSignif));
|
|
||||||
/* de-normalize and divide by 2 */
|
|
||||||
shr_Xsig(&accumulatore, -2*(1+exponent) + 1);
|
|
||||||
negate_Xsig(&accumulatore); /* This does 1 - accumulator */
|
|
||||||
|
|
||||||
/* Now find the ratio. */
|
/* This is (approx) delta, the error in our approx for pi/2
|
||||||
if ( accumulatore.msw == 0 )
|
(see above). It has an exponent of -65
|
||||||
{
|
*/
|
||||||
/* accumulatoro must contain 1.0 here, (actually, 0) but it
|
XSIG_LL(fix_up) = 0x898cc51701b839a2LL;
|
||||||
really doesn't matter what value we use because it will
|
fix_up.lsw = 0;
|
||||||
have negligible effect in later calculations
|
|
||||||
*/
|
|
||||||
XSIG_LL(accum) = 0x8000000000000000LL;
|
|
||||||
accum.lsw = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
div_Xsig(&accumulatoro, &accumulatore, &accum);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Multiply by 1/3 * arg^3 */
|
if (exponent == 0)
|
||||||
mul64_Xsig(&accum, &XSIG_LL(argSignif));
|
adj = 0xffffffff; /* We want approx 1.0 here, but
|
||||||
mul64_Xsig(&accum, &XSIG_LL(argSignif));
|
this is close enough. */
|
||||||
mul64_Xsig(&accum, &XSIG_LL(argSignif));
|
else if (exponent > -30) {
|
||||||
mul64_Xsig(&accum, &twothirds);
|
adj = accum.msw >> -(exponent + 1); /* tan */
|
||||||
shr_Xsig(&accum, -2*(exponent+1));
|
adj = mul_32_32(adj, adj); /* tan^2 */
|
||||||
|
} else
|
||||||
|
adj = 0;
|
||||||
|
adj = mul_32_32(0x898cc517, adj); /* delta * tan^2 */
|
||||||
|
|
||||||
/* tan(arg) = arg + accum */
|
fix_up.msw += adj;
|
||||||
add_two_Xsig(&accum, &argSignif, &exponent);
|
if (!(fix_up.msw & 0x80000000)) { /* did fix_up overflow ? */
|
||||||
|
/* Yes, we need to add an msb */
|
||||||
|
shr_Xsig(&fix_up, 1);
|
||||||
|
fix_up.msw |= 0x80000000;
|
||||||
|
shr_Xsig(&fix_up, 64 + exponent);
|
||||||
|
} else
|
||||||
|
shr_Xsig(&fix_up, 65 + exponent);
|
||||||
|
|
||||||
if ( invert )
|
add_two_Xsig(&accum, &fix_up, &exponent);
|
||||||
{
|
|
||||||
/* We now have the value of tan(pi_2 - arg) where pi_2 is an
|
|
||||||
approximation for pi/2
|
|
||||||
*/
|
|
||||||
/* The next step is to fix the answer to compensate for the
|
|
||||||
error due to the approximation used for pi/2
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* This is (approx) delta, the error in our approx for pi/2
|
/* accum now contains tan(pi/2 - arg).
|
||||||
(see above). It has an exponent of -65
|
Use tan(arg) = 1.0 / tan(pi/2 - arg)
|
||||||
*/
|
*/
|
||||||
XSIG_LL(fix_up) = 0x898cc51701b839a2LL;
|
accumulatoro.lsw = accumulatoro.midw = 0;
|
||||||
fix_up.lsw = 0;
|
accumulatoro.msw = 0x80000000;
|
||||||
|
div_Xsig(&accumulatoro, &accum, &accum);
|
||||||
if ( exponent == 0 )
|
exponent = -exponent - 1;
|
||||||
adj = 0xffffffff; /* We want approx 1.0 here, but
|
|
||||||
this is close enough. */
|
|
||||||
else if ( exponent > -30 )
|
|
||||||
{
|
|
||||||
adj = accum.msw >> -(exponent+1); /* tan */
|
|
||||||
adj = mul_32_32(adj, adj); /* tan^2 */
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
adj = 0;
|
|
||||||
adj = mul_32_32(0x898cc517, adj); /* delta * tan^2 */
|
|
||||||
|
|
||||||
fix_up.msw += adj;
|
/* Transfer the result */
|
||||||
if ( !(fix_up.msw & 0x80000000) ) /* did fix_up overflow ? */
|
round_Xsig(&accum);
|
||||||
{
|
FPU_settag0(TAG_Valid);
|
||||||
/* Yes, we need to add an msb */
|
significand(st0_ptr) = XSIG_LL(accum);
|
||||||
shr_Xsig(&fix_up, 1);
|
setexponent16(st0_ptr, exponent + EXTENDED_Ebias); /* Result is positive. */
|
||||||
fix_up.msw |= 0x80000000;
|
|
||||||
shr_Xsig(&fix_up, 64 + exponent);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
shr_Xsig(&fix_up, 65 + exponent);
|
|
||||||
|
|
||||||
add_two_Xsig(&accum, &fix_up, &exponent);
|
|
||||||
|
|
||||||
/* accum now contains tan(pi/2 - arg).
|
|
||||||
Use tan(arg) = 1.0 / tan(pi/2 - arg)
|
|
||||||
*/
|
|
||||||
accumulatoro.lsw = accumulatoro.midw = 0;
|
|
||||||
accumulatoro.msw = 0x80000000;
|
|
||||||
div_Xsig(&accumulatoro, &accum, &accum);
|
|
||||||
exponent = - exponent - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Transfer the result */
|
|
||||||
round_Xsig(&accum);
|
|
||||||
FPU_settag0(TAG_Valid);
|
|
||||||
significand(st0_ptr) = XSIG_LL(accum);
|
|
||||||
setexponent16(st0_ptr, exponent + EXTENDED_Ebias); /* Result is positive. */
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -27,7 +27,7 @@
|
|||||||
static
|
static
|
||||||
int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa,
|
int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa,
|
||||||
FPU_REG const *b, u_char tagb, u_char signb,
|
FPU_REG const *b, u_char tagb, u_char signb,
|
||||||
FPU_REG *dest, int deststnr, int control_w);
|
FPU_REG * dest, int deststnr, int control_w);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Operates on st(0) and st(n), or on st(0) and temporary data.
|
Operates on st(0) and st(n), or on st(0) and temporary data.
|
||||||
@@ -35,340 +35,299 @@ int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa,
|
|||||||
*/
|
*/
|
||||||
int FPU_add(FPU_REG const *b, u_char tagb, int deststnr, int control_w)
|
int FPU_add(FPU_REG const *b, u_char tagb, int deststnr, int control_w)
|
||||||
{
|
{
|
||||||
FPU_REG *a = &st(0);
|
FPU_REG *a = &st(0);
|
||||||
FPU_REG *dest = &st(deststnr);
|
FPU_REG *dest = &st(deststnr);
|
||||||
u_char signb = getsign(b);
|
u_char signb = getsign(b);
|
||||||
u_char taga = FPU_gettag0();
|
u_char taga = FPU_gettag0();
|
||||||
u_char signa = getsign(a);
|
u_char signa = getsign(a);
|
||||||
u_char saved_sign = getsign(dest);
|
u_char saved_sign = getsign(dest);
|
||||||
int diff, tag, expa, expb;
|
int diff, tag, expa, expb;
|
||||||
|
|
||||||
if ( !(taga | tagb) )
|
|
||||||
{
|
|
||||||
expa = exponent(a);
|
|
||||||
expb = exponent(b);
|
|
||||||
|
|
||||||
valid_add:
|
if (!(taga | tagb)) {
|
||||||
/* Both registers are valid */
|
expa = exponent(a);
|
||||||
if (!(signa ^ signb))
|
expb = exponent(b);
|
||||||
{
|
|
||||||
/* signs are the same */
|
valid_add:
|
||||||
tag = FPU_u_add(a, b, dest, control_w, signa, expa, expb);
|
/* Both registers are valid */
|
||||||
}
|
if (!(signa ^ signb)) {
|
||||||
else
|
/* signs are the same */
|
||||||
{
|
tag =
|
||||||
/* The signs are different, so do a subtraction */
|
FPU_u_add(a, b, dest, control_w, signa, expa, expb);
|
||||||
diff = expa - expb;
|
} else {
|
||||||
if (!diff)
|
/* The signs are different, so do a subtraction */
|
||||||
{
|
diff = expa - expb;
|
||||||
diff = a->sigh - b->sigh; /* This works only if the ms bits
|
if (!diff) {
|
||||||
are identical. */
|
diff = a->sigh - b->sigh; /* This works only if the ms bits
|
||||||
if (!diff)
|
are identical. */
|
||||||
{
|
if (!diff) {
|
||||||
diff = a->sigl > b->sigl;
|
diff = a->sigl > b->sigl;
|
||||||
if (!diff)
|
if (!diff)
|
||||||
diff = -(a->sigl < b->sigl);
|
diff = -(a->sigl < b->sigl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diff > 0) {
|
||||||
|
tag =
|
||||||
|
FPU_u_sub(a, b, dest, control_w, signa,
|
||||||
|
expa, expb);
|
||||||
|
} else if (diff < 0) {
|
||||||
|
tag =
|
||||||
|
FPU_u_sub(b, a, dest, control_w, signb,
|
||||||
|
expb, expa);
|
||||||
|
} else {
|
||||||
|
FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
|
||||||
|
/* sign depends upon rounding mode */
|
||||||
|
setsign(dest, ((control_w & CW_RC) != RC_DOWN)
|
||||||
|
? SIGN_POS : SIGN_NEG);
|
||||||
|
return TAG_Zero;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (tag < 0) {
|
||||||
if (diff > 0)
|
setsign(dest, saved_sign);
|
||||||
{
|
return tag;
|
||||||
tag = FPU_u_sub(a, b, dest, control_w, signa, expa, expb);
|
}
|
||||||
}
|
FPU_settagi(deststnr, tag);
|
||||||
else if ( diff < 0 )
|
return tag;
|
||||||
{
|
|
||||||
tag = FPU_u_sub(b, a, dest, control_w, signb, expb, expa);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
|
|
||||||
/* sign depends upon rounding mode */
|
|
||||||
setsign(dest, ((control_w & CW_RC) != RC_DOWN)
|
|
||||||
? SIGN_POS : SIGN_NEG);
|
|
||||||
return TAG_Zero;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( tag < 0 )
|
if (taga == TAG_Special)
|
||||||
{
|
taga = FPU_Special(a);
|
||||||
setsign(dest, saved_sign);
|
if (tagb == TAG_Special)
|
||||||
return tag;
|
tagb = FPU_Special(b);
|
||||||
}
|
|
||||||
FPU_settagi(deststnr, tag);
|
|
||||||
return tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( taga == TAG_Special )
|
if (((taga == TAG_Valid) && (tagb == TW_Denormal))
|
||||||
taga = FPU_Special(a);
|
|
||||||
if ( tagb == TAG_Special )
|
|
||||||
tagb = FPU_Special(b);
|
|
||||||
|
|
||||||
if ( ((taga == TAG_Valid) && (tagb == TW_Denormal))
|
|
||||||
|| ((taga == TW_Denormal) && (tagb == TAG_Valid))
|
|| ((taga == TW_Denormal) && (tagb == TAG_Valid))
|
||||||
|| ((taga == TW_Denormal) && (tagb == TW_Denormal)) )
|
|| ((taga == TW_Denormal) && (tagb == TW_Denormal))) {
|
||||||
{
|
FPU_REG x, y;
|
||||||
FPU_REG x, y;
|
|
||||||
|
|
||||||
if ( denormal_operand() < 0 )
|
if (denormal_operand() < 0)
|
||||||
return FPU_Exception;
|
return FPU_Exception;
|
||||||
|
|
||||||
FPU_to_exp16(a, &x);
|
FPU_to_exp16(a, &x);
|
||||||
FPU_to_exp16(b, &y);
|
FPU_to_exp16(b, &y);
|
||||||
a = &x;
|
a = &x;
|
||||||
b = &y;
|
b = &y;
|
||||||
expa = exponent16(a);
|
expa = exponent16(a);
|
||||||
expb = exponent16(b);
|
expb = exponent16(b);
|
||||||
goto valid_add;
|
goto valid_add;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( (taga == TW_NaN) || (tagb == TW_NaN) )
|
if ((taga == TW_NaN) || (tagb == TW_NaN)) {
|
||||||
{
|
if (deststnr == 0)
|
||||||
if ( deststnr == 0 )
|
return real_2op_NaN(b, tagb, deststnr, a);
|
||||||
return real_2op_NaN(b, tagb, deststnr, a);
|
else
|
||||||
else
|
return real_2op_NaN(a, taga, deststnr, a);
|
||||||
return real_2op_NaN(a, taga, deststnr, a);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return add_sub_specials(a, taga, signa, b, tagb, signb,
|
return add_sub_specials(a, taga, signa, b, tagb, signb,
|
||||||
dest, deststnr, control_w);
|
dest, deststnr, control_w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Subtract b from a. (a-b) -> dest */
|
/* Subtract b from a. (a-b) -> dest */
|
||||||
int FPU_sub(int flags, int rm, int control_w)
|
int FPU_sub(int flags, int rm, int control_w)
|
||||||
{
|
{
|
||||||
FPU_REG const *a, *b;
|
FPU_REG const *a, *b;
|
||||||
FPU_REG *dest;
|
FPU_REG *dest;
|
||||||
u_char taga, tagb, signa, signb, saved_sign, sign;
|
u_char taga, tagb, signa, signb, saved_sign, sign;
|
||||||
int diff, tag = 0, expa, expb, deststnr;
|
int diff, tag = 0, expa, expb, deststnr;
|
||||||
|
|
||||||
a = &st(0);
|
a = &st(0);
|
||||||
taga = FPU_gettag0();
|
taga = FPU_gettag0();
|
||||||
|
|
||||||
deststnr = 0;
|
deststnr = 0;
|
||||||
if ( flags & LOADED )
|
if (flags & LOADED) {
|
||||||
{
|
b = (FPU_REG *) rm;
|
||||||
b = (FPU_REG *)rm;
|
tagb = flags & 0x0f;
|
||||||
tagb = flags & 0x0f;
|
} else {
|
||||||
}
|
b = &st(rm);
|
||||||
else
|
tagb = FPU_gettagi(rm);
|
||||||
{
|
|
||||||
b = &st(rm);
|
|
||||||
tagb = FPU_gettagi(rm);
|
|
||||||
|
|
||||||
if ( flags & DEST_RM )
|
if (flags & DEST_RM)
|
||||||
deststnr = rm;
|
deststnr = rm;
|
||||||
}
|
|
||||||
|
|
||||||
signa = getsign(a);
|
|
||||||
signb = getsign(b);
|
|
||||||
|
|
||||||
if ( flags & REV )
|
|
||||||
{
|
|
||||||
signa ^= SIGN_NEG;
|
|
||||||
signb ^= SIGN_NEG;
|
|
||||||
}
|
|
||||||
|
|
||||||
dest = &st(deststnr);
|
|
||||||
saved_sign = getsign(dest);
|
|
||||||
|
|
||||||
if ( !(taga | tagb) )
|
|
||||||
{
|
|
||||||
expa = exponent(a);
|
|
||||||
expb = exponent(b);
|
|
||||||
|
|
||||||
valid_subtract:
|
|
||||||
/* Both registers are valid */
|
|
||||||
|
|
||||||
diff = expa - expb;
|
|
||||||
|
|
||||||
if (!diff)
|
|
||||||
{
|
|
||||||
diff = a->sigh - b->sigh; /* Works only if ms bits are identical */
|
|
||||||
if (!diff)
|
|
||||||
{
|
|
||||||
diff = a->sigl > b->sigl;
|
|
||||||
if (!diff)
|
|
||||||
diff = -(a->sigl < b->sigl);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ( (((int)signa)*2 + signb) / SIGN_NEG )
|
signa = getsign(a);
|
||||||
{
|
signb = getsign(b);
|
||||||
case 0: /* P - P */
|
|
||||||
case 3: /* N - N */
|
|
||||||
if (diff > 0)
|
|
||||||
{
|
|
||||||
/* |a| > |b| */
|
|
||||||
tag = FPU_u_sub(a, b, dest, control_w, signa, expa, expb);
|
|
||||||
}
|
|
||||||
else if ( diff == 0 )
|
|
||||||
{
|
|
||||||
FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
|
|
||||||
|
|
||||||
/* sign depends upon rounding mode */
|
if (flags & REV) {
|
||||||
setsign(dest, ((control_w & CW_RC) != RC_DOWN)
|
signa ^= SIGN_NEG;
|
||||||
? SIGN_POS : SIGN_NEG);
|
signb ^= SIGN_NEG;
|
||||||
return TAG_Zero;
|
}
|
||||||
}
|
|
||||||
else
|
dest = &st(deststnr);
|
||||||
{
|
saved_sign = getsign(dest);
|
||||||
sign = signa ^ SIGN_NEG;
|
|
||||||
tag = FPU_u_sub(b, a, dest, control_w, sign, expb, expa);
|
if (!(taga | tagb)) {
|
||||||
}
|
expa = exponent(a);
|
||||||
break;
|
expb = exponent(b);
|
||||||
case 1: /* P - N */
|
|
||||||
tag = FPU_u_add(a, b, dest, control_w, SIGN_POS, expa, expb);
|
valid_subtract:
|
||||||
break;
|
/* Both registers are valid */
|
||||||
case 2: /* N - P */
|
|
||||||
tag = FPU_u_add(a, b, dest, control_w, SIGN_NEG, expa, expb);
|
diff = expa - expb;
|
||||||
break;
|
|
||||||
|
if (!diff) {
|
||||||
|
diff = a->sigh - b->sigh; /* Works only if ms bits are identical */
|
||||||
|
if (!diff) {
|
||||||
|
diff = a->sigl > b->sigl;
|
||||||
|
if (!diff)
|
||||||
|
diff = -(a->sigl < b->sigl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ((((int)signa) * 2 + signb) / SIGN_NEG) {
|
||||||
|
case 0: /* P - P */
|
||||||
|
case 3: /* N - N */
|
||||||
|
if (diff > 0) {
|
||||||
|
/* |a| > |b| */
|
||||||
|
tag =
|
||||||
|
FPU_u_sub(a, b, dest, control_w, signa,
|
||||||
|
expa, expb);
|
||||||
|
} else if (diff == 0) {
|
||||||
|
FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
|
||||||
|
|
||||||
|
/* sign depends upon rounding mode */
|
||||||
|
setsign(dest, ((control_w & CW_RC) != RC_DOWN)
|
||||||
|
? SIGN_POS : SIGN_NEG);
|
||||||
|
return TAG_Zero;
|
||||||
|
} else {
|
||||||
|
sign = signa ^ SIGN_NEG;
|
||||||
|
tag =
|
||||||
|
FPU_u_sub(b, a, dest, control_w, sign, expb,
|
||||||
|
expa);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1: /* P - N */
|
||||||
|
tag =
|
||||||
|
FPU_u_add(a, b, dest, control_w, SIGN_POS, expa,
|
||||||
|
expb);
|
||||||
|
break;
|
||||||
|
case 2: /* N - P */
|
||||||
|
tag =
|
||||||
|
FPU_u_add(a, b, dest, control_w, SIGN_NEG, expa,
|
||||||
|
expb);
|
||||||
|
break;
|
||||||
#ifdef PARANOID
|
#ifdef PARANOID
|
||||||
default:
|
default:
|
||||||
EXCEPTION(EX_INTERNAL|0x111);
|
EXCEPTION(EX_INTERNAL | 0x111);
|
||||||
return -1;
|
return -1;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
if (tag < 0) {
|
||||||
|
setsign(dest, saved_sign);
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
FPU_settagi(deststnr, tag);
|
||||||
|
return tag;
|
||||||
}
|
}
|
||||||
if ( tag < 0 )
|
|
||||||
{
|
|
||||||
setsign(dest, saved_sign);
|
|
||||||
return tag;
|
|
||||||
}
|
|
||||||
FPU_settagi(deststnr, tag);
|
|
||||||
return tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( taga == TAG_Special )
|
if (taga == TAG_Special)
|
||||||
taga = FPU_Special(a);
|
taga = FPU_Special(a);
|
||||||
if ( tagb == TAG_Special )
|
if (tagb == TAG_Special)
|
||||||
tagb = FPU_Special(b);
|
tagb = FPU_Special(b);
|
||||||
|
|
||||||
if ( ((taga == TAG_Valid) && (tagb == TW_Denormal))
|
if (((taga == TAG_Valid) && (tagb == TW_Denormal))
|
||||||
|| ((taga == TW_Denormal) && (tagb == TAG_Valid))
|
|| ((taga == TW_Denormal) && (tagb == TAG_Valid))
|
||||||
|| ((taga == TW_Denormal) && (tagb == TW_Denormal)) )
|
|| ((taga == TW_Denormal) && (tagb == TW_Denormal))) {
|
||||||
{
|
FPU_REG x, y;
|
||||||
FPU_REG x, y;
|
|
||||||
|
|
||||||
if ( denormal_operand() < 0 )
|
if (denormal_operand() < 0)
|
||||||
return FPU_Exception;
|
return FPU_Exception;
|
||||||
|
|
||||||
FPU_to_exp16(a, &x);
|
FPU_to_exp16(a, &x);
|
||||||
FPU_to_exp16(b, &y);
|
FPU_to_exp16(b, &y);
|
||||||
a = &x;
|
a = &x;
|
||||||
b = &y;
|
b = &y;
|
||||||
expa = exponent16(a);
|
expa = exponent16(a);
|
||||||
expb = exponent16(b);
|
expb = exponent16(b);
|
||||||
|
|
||||||
goto valid_subtract;
|
goto valid_subtract;
|
||||||
}
|
|
||||||
|
|
||||||
if ( (taga == TW_NaN) || (tagb == TW_NaN) )
|
|
||||||
{
|
|
||||||
FPU_REG const *d1, *d2;
|
|
||||||
if ( flags & REV )
|
|
||||||
{
|
|
||||||
d1 = b;
|
|
||||||
d2 = a;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
d1 = a;
|
|
||||||
d2 = b;
|
|
||||||
}
|
|
||||||
if ( flags & LOADED )
|
|
||||||
return real_2op_NaN(b, tagb, deststnr, d1);
|
|
||||||
if ( flags & DEST_RM )
|
|
||||||
return real_2op_NaN(a, taga, deststnr, d2);
|
|
||||||
else
|
|
||||||
return real_2op_NaN(b, tagb, deststnr, d2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return add_sub_specials(a, taga, signa, b, tagb, signb ^ SIGN_NEG,
|
if ((taga == TW_NaN) || (tagb == TW_NaN)) {
|
||||||
dest, deststnr, control_w);
|
FPU_REG const *d1, *d2;
|
||||||
|
if (flags & REV) {
|
||||||
|
d1 = b;
|
||||||
|
d2 = a;
|
||||||
|
} else {
|
||||||
|
d1 = a;
|
||||||
|
d2 = b;
|
||||||
|
}
|
||||||
|
if (flags & LOADED)
|
||||||
|
return real_2op_NaN(b, tagb, deststnr, d1);
|
||||||
|
if (flags & DEST_RM)
|
||||||
|
return real_2op_NaN(a, taga, deststnr, d2);
|
||||||
|
else
|
||||||
|
return real_2op_NaN(b, tagb, deststnr, d2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return add_sub_specials(a, taga, signa, b, tagb, signb ^ SIGN_NEG,
|
||||||
|
dest, deststnr, control_w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static
|
static
|
||||||
int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa,
|
int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa,
|
||||||
FPU_REG const *b, u_char tagb, u_char signb,
|
FPU_REG const *b, u_char tagb, u_char signb,
|
||||||
FPU_REG *dest, int deststnr, int control_w)
|
FPU_REG * dest, int deststnr, int control_w)
|
||||||
{
|
{
|
||||||
if ( ((taga == TW_Denormal) || (tagb == TW_Denormal))
|
if (((taga == TW_Denormal) || (tagb == TW_Denormal))
|
||||||
&& (denormal_operand() < 0) )
|
&& (denormal_operand() < 0))
|
||||||
return FPU_Exception;
|
return FPU_Exception;
|
||||||
|
|
||||||
if (taga == TAG_Zero)
|
if (taga == TAG_Zero) {
|
||||||
{
|
if (tagb == TAG_Zero) {
|
||||||
if (tagb == TAG_Zero)
|
/* Both are zero, result will be zero. */
|
||||||
{
|
u_char different_signs = signa ^ signb;
|
||||||
/* Both are zero, result will be zero. */
|
|
||||||
u_char different_signs = signa ^ signb;
|
|
||||||
|
|
||||||
FPU_copy_to_regi(a, TAG_Zero, deststnr);
|
FPU_copy_to_regi(a, TAG_Zero, deststnr);
|
||||||
if ( different_signs )
|
if (different_signs) {
|
||||||
{
|
/* Signs are different. */
|
||||||
/* Signs are different. */
|
/* Sign of answer depends upon rounding mode. */
|
||||||
/* Sign of answer depends upon rounding mode. */
|
setsign(dest, ((control_w & CW_RC) != RC_DOWN)
|
||||||
setsign(dest, ((control_w & CW_RC) != RC_DOWN)
|
? SIGN_POS : SIGN_NEG);
|
||||||
? SIGN_POS : SIGN_NEG);
|
} else
|
||||||
}
|
setsign(dest, signa); /* signa may differ from the sign of a. */
|
||||||
else
|
return TAG_Zero;
|
||||||
setsign(dest, signa); /* signa may differ from the sign of a. */
|
} else {
|
||||||
return TAG_Zero;
|
reg_copy(b, dest);
|
||||||
|
if ((tagb == TW_Denormal) && (b->sigh & 0x80000000)) {
|
||||||
|
/* A pseudoDenormal, convert it. */
|
||||||
|
addexponent(dest, 1);
|
||||||
|
tagb = TAG_Valid;
|
||||||
|
} else if (tagb > TAG_Empty)
|
||||||
|
tagb = TAG_Special;
|
||||||
|
setsign(dest, signb); /* signb may differ from the sign of b. */
|
||||||
|
FPU_settagi(deststnr, tagb);
|
||||||
|
return tagb;
|
||||||
|
}
|
||||||
|
} else if (tagb == TAG_Zero) {
|
||||||
|
reg_copy(a, dest);
|
||||||
|
if ((taga == TW_Denormal) && (a->sigh & 0x80000000)) {
|
||||||
|
/* A pseudoDenormal */
|
||||||
|
addexponent(dest, 1);
|
||||||
|
taga = TAG_Valid;
|
||||||
|
} else if (taga > TAG_Empty)
|
||||||
|
taga = TAG_Special;
|
||||||
|
setsign(dest, signa); /* signa may differ from the sign of a. */
|
||||||
|
FPU_settagi(deststnr, taga);
|
||||||
|
return taga;
|
||||||
|
} else if (taga == TW_Infinity) {
|
||||||
|
if ((tagb != TW_Infinity) || (signa == signb)) {
|
||||||
|
FPU_copy_to_regi(a, TAG_Special, deststnr);
|
||||||
|
setsign(dest, signa); /* signa may differ from the sign of a. */
|
||||||
|
return taga;
|
||||||
|
}
|
||||||
|
/* Infinity-Infinity is undefined. */
|
||||||
|
return arith_invalid(deststnr);
|
||||||
|
} else if (tagb == TW_Infinity) {
|
||||||
|
FPU_copy_to_regi(b, TAG_Special, deststnr);
|
||||||
|
setsign(dest, signb); /* signb may differ from the sign of b. */
|
||||||
|
return tagb;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
reg_copy(b, dest);
|
|
||||||
if ( (tagb == TW_Denormal) && (b->sigh & 0x80000000) )
|
|
||||||
{
|
|
||||||
/* A pseudoDenormal, convert it. */
|
|
||||||
addexponent(dest, 1);
|
|
||||||
tagb = TAG_Valid;
|
|
||||||
}
|
|
||||||
else if ( tagb > TAG_Empty )
|
|
||||||
tagb = TAG_Special;
|
|
||||||
setsign(dest, signb); /* signb may differ from the sign of b. */
|
|
||||||
FPU_settagi(deststnr, tagb);
|
|
||||||
return tagb;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (tagb == TAG_Zero)
|
|
||||||
{
|
|
||||||
reg_copy(a, dest);
|
|
||||||
if ( (taga == TW_Denormal) && (a->sigh & 0x80000000) )
|
|
||||||
{
|
|
||||||
/* A pseudoDenormal */
|
|
||||||
addexponent(dest, 1);
|
|
||||||
taga = TAG_Valid;
|
|
||||||
}
|
|
||||||
else if ( taga > TAG_Empty )
|
|
||||||
taga = TAG_Special;
|
|
||||||
setsign(dest, signa); /* signa may differ from the sign of a. */
|
|
||||||
FPU_settagi(deststnr, taga);
|
|
||||||
return taga;
|
|
||||||
}
|
|
||||||
else if (taga == TW_Infinity)
|
|
||||||
{
|
|
||||||
if ( (tagb != TW_Infinity) || (signa == signb) )
|
|
||||||
{
|
|
||||||
FPU_copy_to_regi(a, TAG_Special, deststnr);
|
|
||||||
setsign(dest, signa); /* signa may differ from the sign of a. */
|
|
||||||
return taga;
|
|
||||||
}
|
|
||||||
/* Infinity-Infinity is undefined. */
|
|
||||||
return arith_invalid(deststnr);
|
|
||||||
}
|
|
||||||
else if (tagb == TW_Infinity)
|
|
||||||
{
|
|
||||||
FPU_copy_to_regi(b, TAG_Special, deststnr);
|
|
||||||
setsign(dest, signb); /* signb may differ from the sign of b. */
|
|
||||||
return tagb;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef PARANOID
|
#ifdef PARANOID
|
||||||
EXCEPTION(EX_INTERNAL|0x101);
|
EXCEPTION(EX_INTERNAL | 0x101);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return FPU_Exception;
|
return FPU_Exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -20,362 +20,331 @@
|
|||||||
#include "control_w.h"
|
#include "control_w.h"
|
||||||
#include "status_w.h"
|
#include "status_w.h"
|
||||||
|
|
||||||
|
|
||||||
static int compare(FPU_REG const *b, int tagb)
|
static int compare(FPU_REG const *b, int tagb)
|
||||||
{
|
{
|
||||||
int diff, exp0, expb;
|
int diff, exp0, expb;
|
||||||
u_char st0_tag;
|
u_char st0_tag;
|
||||||
FPU_REG *st0_ptr;
|
FPU_REG *st0_ptr;
|
||||||
FPU_REG x, y;
|
FPU_REG x, y;
|
||||||
u_char st0_sign, signb = getsign(b);
|
u_char st0_sign, signb = getsign(b);
|
||||||
|
|
||||||
st0_ptr = &st(0);
|
st0_ptr = &st(0);
|
||||||
st0_tag = FPU_gettag0();
|
st0_tag = FPU_gettag0();
|
||||||
st0_sign = getsign(st0_ptr);
|
st0_sign = getsign(st0_ptr);
|
||||||
|
|
||||||
if ( tagb == TAG_Special )
|
if (tagb == TAG_Special)
|
||||||
tagb = FPU_Special(b);
|
tagb = FPU_Special(b);
|
||||||
if ( st0_tag == TAG_Special )
|
if (st0_tag == TAG_Special)
|
||||||
st0_tag = FPU_Special(st0_ptr);
|
st0_tag = FPU_Special(st0_ptr);
|
||||||
|
|
||||||
if ( ((st0_tag != TAG_Valid) && (st0_tag != TW_Denormal))
|
if (((st0_tag != TAG_Valid) && (st0_tag != TW_Denormal))
|
||||||
|| ((tagb != TAG_Valid) && (tagb != TW_Denormal)) )
|
|| ((tagb != TAG_Valid) && (tagb != TW_Denormal))) {
|
||||||
{
|
if (st0_tag == TAG_Zero) {
|
||||||
if ( st0_tag == TAG_Zero )
|
if (tagb == TAG_Zero)
|
||||||
{
|
return COMP_A_eq_B;
|
||||||
if ( tagb == TAG_Zero ) return COMP_A_eq_B;
|
if (tagb == TAG_Valid)
|
||||||
if ( tagb == TAG_Valid )
|
return ((signb ==
|
||||||
return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
|
SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
|
||||||
if ( tagb == TW_Denormal )
|
if (tagb == TW_Denormal)
|
||||||
return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
|
return ((signb ==
|
||||||
| COMP_Denormal;
|
SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
|
||||||
}
|
| COMP_Denormal;
|
||||||
else if ( tagb == TAG_Zero )
|
} else if (tagb == TAG_Zero) {
|
||||||
{
|
if (st0_tag == TAG_Valid)
|
||||||
if ( st0_tag == TAG_Valid )
|
return ((st0_sign ==
|
||||||
return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
|
SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
|
||||||
if ( st0_tag == TW_Denormal )
|
if (st0_tag == TW_Denormal)
|
||||||
return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
|
return ((st0_sign ==
|
||||||
| COMP_Denormal;
|
SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
|
||||||
|
| COMP_Denormal;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st0_tag == TW_Infinity) {
|
||||||
|
if ((tagb == TAG_Valid) || (tagb == TAG_Zero))
|
||||||
|
return ((st0_sign ==
|
||||||
|
SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
|
||||||
|
else if (tagb == TW_Denormal)
|
||||||
|
return ((st0_sign ==
|
||||||
|
SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
|
||||||
|
| COMP_Denormal;
|
||||||
|
else if (tagb == TW_Infinity) {
|
||||||
|
/* The 80486 book says that infinities can be equal! */
|
||||||
|
return (st0_sign == signb) ? COMP_A_eq_B :
|
||||||
|
((st0_sign ==
|
||||||
|
SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
|
||||||
|
}
|
||||||
|
/* Fall through to the NaN code */
|
||||||
|
} else if (tagb == TW_Infinity) {
|
||||||
|
if ((st0_tag == TAG_Valid) || (st0_tag == TAG_Zero))
|
||||||
|
return ((signb ==
|
||||||
|
SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
|
||||||
|
if (st0_tag == TW_Denormal)
|
||||||
|
return ((signb ==
|
||||||
|
SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
|
||||||
|
| COMP_Denormal;
|
||||||
|
/* Fall through to the NaN code */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The only possibility now should be that one of the arguments
|
||||||
|
is a NaN */
|
||||||
|
if ((st0_tag == TW_NaN) || (tagb == TW_NaN)) {
|
||||||
|
int signalling = 0, unsupported = 0;
|
||||||
|
if (st0_tag == TW_NaN) {
|
||||||
|
signalling =
|
||||||
|
(st0_ptr->sigh & 0xc0000000) == 0x80000000;
|
||||||
|
unsupported = !((exponent(st0_ptr) == EXP_OVER)
|
||||||
|
&& (st0_ptr->
|
||||||
|
sigh & 0x80000000));
|
||||||
|
}
|
||||||
|
if (tagb == TW_NaN) {
|
||||||
|
signalling |=
|
||||||
|
(b->sigh & 0xc0000000) == 0x80000000;
|
||||||
|
unsupported |= !((exponent(b) == EXP_OVER)
|
||||||
|
&& (b->sigh & 0x80000000));
|
||||||
|
}
|
||||||
|
if (signalling || unsupported)
|
||||||
|
return COMP_No_Comp | COMP_SNaN | COMP_NaN;
|
||||||
|
else
|
||||||
|
/* Neither is a signaling NaN */
|
||||||
|
return COMP_No_Comp | COMP_NaN;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXCEPTION(EX_Invalid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( st0_tag == TW_Infinity )
|
if (st0_sign != signb) {
|
||||||
{
|
return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
|
||||||
if ( (tagb == TAG_Valid) || (tagb == TAG_Zero) )
|
| (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
|
||||||
return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
|
COMP_Denormal : 0);
|
||||||
else if ( tagb == TW_Denormal )
|
|
||||||
return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
|
|
||||||
| COMP_Denormal;
|
|
||||||
else if ( tagb == TW_Infinity )
|
|
||||||
{
|
|
||||||
/* The 80486 book says that infinities can be equal! */
|
|
||||||
return (st0_sign == signb) ? COMP_A_eq_B :
|
|
||||||
((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
|
|
||||||
}
|
|
||||||
/* Fall through to the NaN code */
|
|
||||||
}
|
|
||||||
else if ( tagb == TW_Infinity )
|
|
||||||
{
|
|
||||||
if ( (st0_tag == TAG_Valid) || (st0_tag == TAG_Zero) )
|
|
||||||
return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
|
|
||||||
if ( st0_tag == TW_Denormal )
|
|
||||||
return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
|
|
||||||
| COMP_Denormal;
|
|
||||||
/* Fall through to the NaN code */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The only possibility now should be that one of the arguments
|
if ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) {
|
||||||
is a NaN */
|
FPU_to_exp16(st0_ptr, &x);
|
||||||
if ( (st0_tag == TW_NaN) || (tagb == TW_NaN) )
|
FPU_to_exp16(b, &y);
|
||||||
{
|
st0_ptr = &x;
|
||||||
int signalling = 0, unsupported = 0;
|
b = &y;
|
||||||
if ( st0_tag == TW_NaN )
|
exp0 = exponent16(st0_ptr);
|
||||||
{
|
expb = exponent16(b);
|
||||||
signalling = (st0_ptr->sigh & 0xc0000000) == 0x80000000;
|
} else {
|
||||||
unsupported = !((exponent(st0_ptr) == EXP_OVER)
|
exp0 = exponent(st0_ptr);
|
||||||
&& (st0_ptr->sigh & 0x80000000));
|
expb = exponent(b);
|
||||||
}
|
|
||||||
if ( tagb == TW_NaN )
|
|
||||||
{
|
|
||||||
signalling |= (b->sigh & 0xc0000000) == 0x80000000;
|
|
||||||
unsupported |= !((exponent(b) == EXP_OVER)
|
|
||||||
&& (b->sigh & 0x80000000));
|
|
||||||
}
|
|
||||||
if ( signalling || unsupported )
|
|
||||||
return COMP_No_Comp | COMP_SNaN | COMP_NaN;
|
|
||||||
else
|
|
||||||
/* Neither is a signaling NaN */
|
|
||||||
return COMP_No_Comp | COMP_NaN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EXCEPTION(EX_Invalid);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (st0_sign != signb)
|
|
||||||
{
|
|
||||||
return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
|
|
||||||
| ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
|
|
||||||
COMP_Denormal : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( (st0_tag == TW_Denormal) || (tagb == TW_Denormal) )
|
|
||||||
{
|
|
||||||
FPU_to_exp16(st0_ptr, &x);
|
|
||||||
FPU_to_exp16(b, &y);
|
|
||||||
st0_ptr = &x;
|
|
||||||
b = &y;
|
|
||||||
exp0 = exponent16(st0_ptr);
|
|
||||||
expb = exponent16(b);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
exp0 = exponent(st0_ptr);
|
|
||||||
expb = exponent(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef PARANOID
|
#ifdef PARANOID
|
||||||
if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
|
if (!(st0_ptr->sigh & 0x80000000))
|
||||||
if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
|
EXCEPTION(EX_Invalid);
|
||||||
|
if (!(b->sigh & 0x80000000))
|
||||||
|
EXCEPTION(EX_Invalid);
|
||||||
#endif /* PARANOID */
|
#endif /* PARANOID */
|
||||||
|
|
||||||
diff = exp0 - expb;
|
diff = exp0 - expb;
|
||||||
if ( diff == 0 )
|
if (diff == 0) {
|
||||||
{
|
diff = st0_ptr->sigh - b->sigh; /* Works only if ms bits are
|
||||||
diff = st0_ptr->sigh - b->sigh; /* Works only if ms bits are
|
identical */
|
||||||
identical */
|
if (diff == 0) {
|
||||||
if ( diff == 0 )
|
diff = st0_ptr->sigl > b->sigl;
|
||||||
{
|
if (diff == 0)
|
||||||
diff = st0_ptr->sigl > b->sigl;
|
diff = -(st0_ptr->sigl < b->sigl);
|
||||||
if ( diff == 0 )
|
}
|
||||||
diff = -(st0_ptr->sigl < b->sigl);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ( diff > 0 )
|
if (diff > 0) {
|
||||||
{
|
return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
|
||||||
return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
|
| (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
|
||||||
| ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
|
COMP_Denormal : 0);
|
||||||
COMP_Denormal : 0);
|
}
|
||||||
}
|
if (diff < 0) {
|
||||||
if ( diff < 0 )
|
return ((st0_sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
|
||||||
{
|
| (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
|
||||||
return ((st0_sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
|
COMP_Denormal : 0);
|
||||||
| ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
|
}
|
||||||
COMP_Denormal : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return COMP_A_eq_B
|
return COMP_A_eq_B
|
||||||
| ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
|
| (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
|
||||||
COMP_Denormal : 0);
|
COMP_Denormal : 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* This function requires that st(0) is not empty */
|
/* This function requires that st(0) is not empty */
|
||||||
int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
|
int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
|
||||||
{
|
{
|
||||||
int f = 0, c;
|
int f = 0, c;
|
||||||
|
|
||||||
c = compare(loaded_data, loaded_tag);
|
c = compare(loaded_data, loaded_tag);
|
||||||
|
|
||||||
if (c & COMP_NaN)
|
if (c & COMP_NaN) {
|
||||||
{
|
EXCEPTION(EX_Invalid);
|
||||||
EXCEPTION(EX_Invalid);
|
f = SW_C3 | SW_C2 | SW_C0;
|
||||||
f = SW_C3 | SW_C2 | SW_C0;
|
} else
|
||||||
}
|
switch (c & 7) {
|
||||||
else
|
case COMP_A_lt_B:
|
||||||
switch (c & 7)
|
f = SW_C0;
|
||||||
{
|
break;
|
||||||
case COMP_A_lt_B:
|
case COMP_A_eq_B:
|
||||||
f = SW_C0;
|
f = SW_C3;
|
||||||
break;
|
break;
|
||||||
case COMP_A_eq_B:
|
case COMP_A_gt_B:
|
||||||
f = SW_C3;
|
f = 0;
|
||||||
break;
|
break;
|
||||||
case COMP_A_gt_B:
|
case COMP_No_Comp:
|
||||||
f = 0;
|
f = SW_C3 | SW_C2 | SW_C0;
|
||||||
break;
|
break;
|
||||||
case COMP_No_Comp:
|
|
||||||
f = SW_C3 | SW_C2 | SW_C0;
|
|
||||||
break;
|
|
||||||
#ifdef PARANOID
|
#ifdef PARANOID
|
||||||
default:
|
default:
|
||||||
EXCEPTION(EX_INTERNAL|0x121);
|
EXCEPTION(EX_INTERNAL | 0x121);
|
||||||
f = SW_C3 | SW_C2 | SW_C0;
|
f = SW_C3 | SW_C2 | SW_C0;
|
||||||
break;
|
break;
|
||||||
#endif /* PARANOID */
|
#endif /* PARANOID */
|
||||||
}
|
}
|
||||||
setcc(f);
|
setcc(f);
|
||||||
if (c & COMP_Denormal)
|
if (c & COMP_Denormal) {
|
||||||
{
|
return denormal_operand() < 0;
|
||||||
return denormal_operand() < 0;
|
}
|
||||||
}
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int compare_st_st(int nr)
|
static int compare_st_st(int nr)
|
||||||
{
|
{
|
||||||
int f = 0, c;
|
int f = 0, c;
|
||||||
FPU_REG *st_ptr;
|
FPU_REG *st_ptr;
|
||||||
|
|
||||||
if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
|
if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
|
||||||
{
|
setcc(SW_C3 | SW_C2 | SW_C0);
|
||||||
setcc(SW_C3 | SW_C2 | SW_C0);
|
/* Stack fault */
|
||||||
/* Stack fault */
|
EXCEPTION(EX_StackUnder);
|
||||||
EXCEPTION(EX_StackUnder);
|
return !(control_word & CW_Invalid);
|
||||||
return !(control_word & CW_Invalid);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
st_ptr = &st(nr);
|
st_ptr = &st(nr);
|
||||||
c = compare(st_ptr, FPU_gettagi(nr));
|
c = compare(st_ptr, FPU_gettagi(nr));
|
||||||
if (c & COMP_NaN)
|
if (c & COMP_NaN) {
|
||||||
{
|
setcc(SW_C3 | SW_C2 | SW_C0);
|
||||||
setcc(SW_C3 | SW_C2 | SW_C0);
|
EXCEPTION(EX_Invalid);
|
||||||
EXCEPTION(EX_Invalid);
|
return !(control_word & CW_Invalid);
|
||||||
return !(control_word & CW_Invalid);
|
} else
|
||||||
}
|
switch (c & 7) {
|
||||||
else
|
case COMP_A_lt_B:
|
||||||
switch (c & 7)
|
f = SW_C0;
|
||||||
{
|
break;
|
||||||
case COMP_A_lt_B:
|
case COMP_A_eq_B:
|
||||||
f = SW_C0;
|
f = SW_C3;
|
||||||
break;
|
break;
|
||||||
case COMP_A_eq_B:
|
case COMP_A_gt_B:
|
||||||
f = SW_C3;
|
f = 0;
|
||||||
break;
|
break;
|
||||||
case COMP_A_gt_B:
|
case COMP_No_Comp:
|
||||||
f = 0;
|
f = SW_C3 | SW_C2 | SW_C0;
|
||||||
break;
|
break;
|
||||||
case COMP_No_Comp:
|
|
||||||
f = SW_C3 | SW_C2 | SW_C0;
|
|
||||||
break;
|
|
||||||
#ifdef PARANOID
|
#ifdef PARANOID
|
||||||
default:
|
default:
|
||||||
EXCEPTION(EX_INTERNAL|0x122);
|
EXCEPTION(EX_INTERNAL | 0x122);
|
||||||
f = SW_C3 | SW_C2 | SW_C0;
|
f = SW_C3 | SW_C2 | SW_C0;
|
||||||
break;
|
break;
|
||||||
#endif /* PARANOID */
|
#endif /* PARANOID */
|
||||||
}
|
}
|
||||||
setcc(f);
|
setcc(f);
|
||||||
if (c & COMP_Denormal)
|
if (c & COMP_Denormal) {
|
||||||
{
|
return denormal_operand() < 0;
|
||||||
return denormal_operand() < 0;
|
}
|
||||||
}
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int compare_u_st_st(int nr)
|
static int compare_u_st_st(int nr)
|
||||||
{
|
{
|
||||||
int f = 0, c;
|
int f = 0, c;
|
||||||
FPU_REG *st_ptr;
|
FPU_REG *st_ptr;
|
||||||
|
|
||||||
if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
|
if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
|
||||||
{
|
setcc(SW_C3 | SW_C2 | SW_C0);
|
||||||
setcc(SW_C3 | SW_C2 | SW_C0);
|
/* Stack fault */
|
||||||
/* Stack fault */
|
EXCEPTION(EX_StackUnder);
|
||||||
EXCEPTION(EX_StackUnder);
|
return !(control_word & CW_Invalid);
|
||||||
return !(control_word & CW_Invalid);
|
|
||||||
}
|
|
||||||
|
|
||||||
st_ptr = &st(nr);
|
|
||||||
c = compare(st_ptr, FPU_gettagi(nr));
|
|
||||||
if (c & COMP_NaN)
|
|
||||||
{
|
|
||||||
setcc(SW_C3 | SW_C2 | SW_C0);
|
|
||||||
if (c & COMP_SNaN) /* This is the only difference between
|
|
||||||
un-ordered and ordinary comparisons */
|
|
||||||
{
|
|
||||||
EXCEPTION(EX_Invalid);
|
|
||||||
return !(control_word & CW_Invalid);
|
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
st_ptr = &st(nr);
|
||||||
else
|
c = compare(st_ptr, FPU_gettagi(nr));
|
||||||
switch (c & 7)
|
if (c & COMP_NaN) {
|
||||||
{
|
setcc(SW_C3 | SW_C2 | SW_C0);
|
||||||
case COMP_A_lt_B:
|
if (c & COMP_SNaN) { /* This is the only difference between
|
||||||
f = SW_C0;
|
un-ordered and ordinary comparisons */
|
||||||
break;
|
EXCEPTION(EX_Invalid);
|
||||||
case COMP_A_eq_B:
|
return !(control_word & CW_Invalid);
|
||||||
f = SW_C3;
|
}
|
||||||
break;
|
return 0;
|
||||||
case COMP_A_gt_B:
|
} else
|
||||||
f = 0;
|
switch (c & 7) {
|
||||||
break;
|
case COMP_A_lt_B:
|
||||||
case COMP_No_Comp:
|
f = SW_C0;
|
||||||
f = SW_C3 | SW_C2 | SW_C0;
|
break;
|
||||||
break;
|
case COMP_A_eq_B:
|
||||||
|
f = SW_C3;
|
||||||
|
break;
|
||||||
|
case COMP_A_gt_B:
|
||||||
|
f = 0;
|
||||||
|
break;
|
||||||
|
case COMP_No_Comp:
|
||||||
|
f = SW_C3 | SW_C2 | SW_C0;
|
||||||
|
break;
|
||||||
#ifdef PARANOID
|
#ifdef PARANOID
|
||||||
default:
|
default:
|
||||||
EXCEPTION(EX_INTERNAL|0x123);
|
EXCEPTION(EX_INTERNAL | 0x123);
|
||||||
f = SW_C3 | SW_C2 | SW_C0;
|
f = SW_C3 | SW_C2 | SW_C0;
|
||||||
break;
|
break;
|
||||||
#endif /* PARANOID */
|
#endif /* PARANOID */
|
||||||
}
|
}
|
||||||
setcc(f);
|
setcc(f);
|
||||||
if (c & COMP_Denormal)
|
if (c & COMP_Denormal) {
|
||||||
{
|
return denormal_operand() < 0;
|
||||||
return denormal_operand() < 0;
|
}
|
||||||
}
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
void fcom_st(void)
|
void fcom_st(void)
|
||||||
{
|
{
|
||||||
/* fcom st(i) */
|
/* fcom st(i) */
|
||||||
compare_st_st(FPU_rm);
|
compare_st_st(FPU_rm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fcompst(void)
|
void fcompst(void)
|
||||||
{
|
{
|
||||||
/* fcomp st(i) */
|
/* fcomp st(i) */
|
||||||
if ( !compare_st_st(FPU_rm) )
|
if (!compare_st_st(FPU_rm))
|
||||||
FPU_pop();
|
FPU_pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fcompp(void)
|
void fcompp(void)
|
||||||
{
|
{
|
||||||
/* fcompp */
|
/* fcompp */
|
||||||
if (FPU_rm != 1)
|
if (FPU_rm != 1) {
|
||||||
{
|
FPU_illegal();
|
||||||
FPU_illegal();
|
return;
|
||||||
return;
|
}
|
||||||
}
|
if (!compare_st_st(1))
|
||||||
if ( !compare_st_st(1) )
|
poppop();
|
||||||
poppop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fucom_(void)
|
void fucom_(void)
|
||||||
{
|
{
|
||||||
/* fucom st(i) */
|
/* fucom st(i) */
|
||||||
compare_u_st_st(FPU_rm);
|
compare_u_st_st(FPU_rm);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fucomp(void)
|
void fucomp(void)
|
||||||
{
|
{
|
||||||
/* fucomp st(i) */
|
/* fucomp st(i) */
|
||||||
if ( !compare_u_st_st(FPU_rm) )
|
if (!compare_u_st_st(FPU_rm))
|
||||||
FPU_pop();
|
FPU_pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fucompp(void)
|
void fucompp(void)
|
||||||
{
|
{
|
||||||
/* fucompp */
|
/* fucompp */
|
||||||
if (FPU_rm == 1)
|
if (FPU_rm == 1) {
|
||||||
{
|
if (!compare_u_st_st(1))
|
||||||
if ( !compare_u_st_st(1) )
|
poppop();
|
||||||
poppop();
|
} else
|
||||||
}
|
FPU_illegal();
|
||||||
else
|
|
||||||
FPU_illegal();
|
|
||||||
}
|
}
|
||||||
|
@@ -16,29 +16,28 @@
|
|||||||
#include "reg_constant.h"
|
#include "reg_constant.h"
|
||||||
#include "control_w.h"
|
#include "control_w.h"
|
||||||
|
|
||||||
|
|
||||||
#define MAKE_REG(s,e,l,h) { l, h, \
|
#define MAKE_REG(s,e,l,h) { l, h, \
|
||||||
((EXTENDED_Ebias+(e)) | ((SIGN_##s != 0)*0x8000)) }
|
((EXTENDED_Ebias+(e)) | ((SIGN_##s != 0)*0x8000)) }
|
||||||
|
|
||||||
FPU_REG const CONST_1 = MAKE_REG(POS, 0, 0x00000000, 0x80000000);
|
FPU_REG const CONST_1 = MAKE_REG(POS, 0, 0x00000000, 0x80000000);
|
||||||
#if 0
|
#if 0
|
||||||
FPU_REG const CONST_2 = MAKE_REG(POS, 1, 0x00000000, 0x80000000);
|
FPU_REG const CONST_2 = MAKE_REG(POS, 1, 0x00000000, 0x80000000);
|
||||||
FPU_REG const CONST_HALF = MAKE_REG(POS, -1, 0x00000000, 0x80000000);
|
FPU_REG const CONST_HALF = MAKE_REG(POS, -1, 0x00000000, 0x80000000);
|
||||||
#endif /* 0 */
|
#endif /* 0 */
|
||||||
static FPU_REG const CONST_L2T = MAKE_REG(POS, 1, 0xcd1b8afe, 0xd49a784b);
|
static FPU_REG const CONST_L2T = MAKE_REG(POS, 1, 0xcd1b8afe, 0xd49a784b);
|
||||||
static FPU_REG const CONST_L2E = MAKE_REG(POS, 0, 0x5c17f0bc, 0xb8aa3b29);
|
static FPU_REG const CONST_L2E = MAKE_REG(POS, 0, 0x5c17f0bc, 0xb8aa3b29);
|
||||||
FPU_REG const CONST_PI = MAKE_REG(POS, 1, 0x2168c235, 0xc90fdaa2);
|
FPU_REG const CONST_PI = MAKE_REG(POS, 1, 0x2168c235, 0xc90fdaa2);
|
||||||
FPU_REG const CONST_PI2 = MAKE_REG(POS, 0, 0x2168c235, 0xc90fdaa2);
|
FPU_REG const CONST_PI2 = MAKE_REG(POS, 0, 0x2168c235, 0xc90fdaa2);
|
||||||
FPU_REG const CONST_PI4 = MAKE_REG(POS, -1, 0x2168c235, 0xc90fdaa2);
|
FPU_REG const CONST_PI4 = MAKE_REG(POS, -1, 0x2168c235, 0xc90fdaa2);
|
||||||
static FPU_REG const CONST_LG2 = MAKE_REG(POS, -2, 0xfbcff799, 0x9a209a84);
|
static FPU_REG const CONST_LG2 = MAKE_REG(POS, -2, 0xfbcff799, 0x9a209a84);
|
||||||
static FPU_REG const CONST_LN2 = MAKE_REG(POS, -1, 0xd1cf79ac, 0xb17217f7);
|
static FPU_REG const CONST_LN2 = MAKE_REG(POS, -1, 0xd1cf79ac, 0xb17217f7);
|
||||||
|
|
||||||
/* Extra bits to take pi/2 to more than 128 bits precision. */
|
/* Extra bits to take pi/2 to more than 128 bits precision. */
|
||||||
FPU_REG const CONST_PI2extra = MAKE_REG(NEG, -66,
|
FPU_REG const CONST_PI2extra = MAKE_REG(NEG, -66,
|
||||||
0xfc8f8cbb, 0xece675d1);
|
0xfc8f8cbb, 0xece675d1);
|
||||||
|
|
||||||
/* Only the sign (and tag) is used in internal zeroes */
|
/* Only the sign (and tag) is used in internal zeroes */
|
||||||
FPU_REG const CONST_Z = MAKE_REG(POS, EXP_UNDER, 0x0, 0x0);
|
FPU_REG const CONST_Z = MAKE_REG(POS, EXP_UNDER, 0x0, 0x0);
|
||||||
|
|
||||||
/* Only the sign and significand (and tag) are used in internal NaNs */
|
/* Only the sign and significand (and tag) are used in internal NaNs */
|
||||||
/* The 80486 never generates one of these
|
/* The 80486 never generates one of these
|
||||||
@@ -48,24 +47,22 @@ FPU_REG const CONST_SNAN = MAKE_REG(POS, EXP_OVER, 0x00000001, 0x80000000);
|
|||||||
FPU_REG const CONST_QNaN = MAKE_REG(NEG, EXP_OVER, 0x00000000, 0xC0000000);
|
FPU_REG const CONST_QNaN = MAKE_REG(NEG, EXP_OVER, 0x00000000, 0xC0000000);
|
||||||
|
|
||||||
/* Only the sign (and tag) is used in internal infinities */
|
/* Only the sign (and tag) is used in internal infinities */
|
||||||
FPU_REG const CONST_INF = MAKE_REG(POS, EXP_OVER, 0x00000000, 0x80000000);
|
FPU_REG const CONST_INF = MAKE_REG(POS, EXP_OVER, 0x00000000, 0x80000000);
|
||||||
|
|
||||||
|
|
||||||
static void fld_const(FPU_REG const *c, int adj, u_char tag)
|
static void fld_const(FPU_REG const *c, int adj, u_char tag)
|
||||||
{
|
{
|
||||||
FPU_REG *st_new_ptr;
|
FPU_REG *st_new_ptr;
|
||||||
|
|
||||||
if ( STACK_OVERFLOW )
|
if (STACK_OVERFLOW) {
|
||||||
{
|
FPU_stack_overflow();
|
||||||
FPU_stack_overflow();
|
return;
|
||||||
return;
|
}
|
||||||
}
|
push();
|
||||||
push();
|
reg_copy(c, st_new_ptr);
|
||||||
reg_copy(c, st_new_ptr);
|
st_new_ptr->sigl += adj; /* For all our fldxxx constants, we don't need to
|
||||||
st_new_ptr->sigl += adj; /* For all our fldxxx constants, we don't need to
|
borrow or carry. */
|
||||||
borrow or carry. */
|
FPU_settag0(tag);
|
||||||
FPU_settag0(tag);
|
clear_C1();
|
||||||
clear_C1();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A fast way to find out whether x is one of RC_DOWN or RC_CHOP
|
/* A fast way to find out whether x is one of RC_DOWN or RC_CHOP
|
||||||
@@ -75,46 +72,46 @@ static void fld_const(FPU_REG const *c, int adj, u_char tag)
|
|||||||
|
|
||||||
static void fld1(int rc)
|
static void fld1(int rc)
|
||||||
{
|
{
|
||||||
fld_const(&CONST_1, 0, TAG_Valid);
|
fld_const(&CONST_1, 0, TAG_Valid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fldl2t(int rc)
|
static void fldl2t(int rc)
|
||||||
{
|
{
|
||||||
fld_const(&CONST_L2T, (rc == RC_UP) ? 1 : 0, TAG_Valid);
|
fld_const(&CONST_L2T, (rc == RC_UP) ? 1 : 0, TAG_Valid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fldl2e(int rc)
|
static void fldl2e(int rc)
|
||||||
{
|
{
|
||||||
fld_const(&CONST_L2E, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
|
fld_const(&CONST_L2E, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fldpi(int rc)
|
static void fldpi(int rc)
|
||||||
{
|
{
|
||||||
fld_const(&CONST_PI, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
|
fld_const(&CONST_PI, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fldlg2(int rc)
|
static void fldlg2(int rc)
|
||||||
{
|
{
|
||||||
fld_const(&CONST_LG2, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
|
fld_const(&CONST_LG2, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fldln2(int rc)
|
static void fldln2(int rc)
|
||||||
{
|
{
|
||||||
fld_const(&CONST_LN2, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
|
fld_const(&CONST_LN2, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fldz(int rc)
|
static void fldz(int rc)
|
||||||
{
|
{
|
||||||
fld_const(&CONST_Z, 0, TAG_Zero);
|
fld_const(&CONST_Z, 0, TAG_Zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef void (*FUNC_RC)(int);
|
typedef void (*FUNC_RC) (int);
|
||||||
|
|
||||||
static FUNC_RC constants_table[] = {
|
static FUNC_RC constants_table[] = {
|
||||||
fld1, fldl2t, fldl2e, fldpi, fldlg2, fldln2, fldz, (FUNC_RC)FPU_illegal
|
fld1, fldl2t, fldl2e, fldpi, fldlg2, fldln2, fldz, (FUNC_RC) FPU_illegal
|
||||||
};
|
};
|
||||||
|
|
||||||
void fconst(void)
|
void fconst(void)
|
||||||
{
|
{
|
||||||
(constants_table[FPU_rm])(control_word & CW_RC);
|
(constants_table[FPU_rm]) (control_word & CW_RC);
|
||||||
}
|
}
|
||||||
|
@@ -13,41 +13,34 @@
|
|||||||
#include "exception.h"
|
#include "exception.h"
|
||||||
#include "fpu_emu.h"
|
#include "fpu_emu.h"
|
||||||
|
|
||||||
|
int FPU_to_exp16(FPU_REG const *a, FPU_REG * x)
|
||||||
int FPU_to_exp16(FPU_REG const *a, FPU_REG *x)
|
|
||||||
{
|
{
|
||||||
int sign = getsign(a);
|
int sign = getsign(a);
|
||||||
|
|
||||||
*(long long *)&(x->sigl) = *(const long long *)&(a->sigl);
|
*(long long *)&(x->sigl) = *(const long long *)&(a->sigl);
|
||||||
|
|
||||||
/* Set up the exponent as a 16 bit quantity. */
|
/* Set up the exponent as a 16 bit quantity. */
|
||||||
setexponent16(x, exponent(a));
|
setexponent16(x, exponent(a));
|
||||||
|
|
||||||
if ( exponent16(x) == EXP_UNDER )
|
if (exponent16(x) == EXP_UNDER) {
|
||||||
{
|
/* The number is a de-normal or pseudodenormal. */
|
||||||
/* The number is a de-normal or pseudodenormal. */
|
/* We only deal with the significand and exponent. */
|
||||||
/* We only deal with the significand and exponent. */
|
|
||||||
|
|
||||||
if (x->sigh & 0x80000000)
|
if (x->sigh & 0x80000000) {
|
||||||
{
|
/* Is a pseudodenormal. */
|
||||||
/* Is a pseudodenormal. */
|
/* This is non-80486 behaviour because the number
|
||||||
/* This is non-80486 behaviour because the number
|
loses its 'denormal' identity. */
|
||||||
loses its 'denormal' identity. */
|
addexponent(x, 1);
|
||||||
addexponent(x, 1);
|
} else {
|
||||||
|
/* Is a denormal. */
|
||||||
|
addexponent(x, 1);
|
||||||
|
FPU_normalize_nuo(x);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
if (!(x->sigh & 0x80000000)) {
|
||||||
/* Is a denormal. */
|
EXCEPTION(EX_INTERNAL | 0x180);
|
||||||
addexponent(x, 1);
|
|
||||||
FPU_normalize_nuo(x);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ( !(x->sigh & 0x80000000) )
|
return sign;
|
||||||
{
|
|
||||||
EXCEPTION(EX_INTERNAL | 0x180);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sign;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -26,182 +26,157 @@
|
|||||||
*/
|
*/
|
||||||
int FPU_div(int flags, int rm, int control_w)
|
int FPU_div(int flags, int rm, int control_w)
|
||||||
{
|
{
|
||||||
FPU_REG x, y;
|
FPU_REG x, y;
|
||||||
FPU_REG const *a, *b, *st0_ptr, *st_ptr;
|
FPU_REG const *a, *b, *st0_ptr, *st_ptr;
|
||||||
FPU_REG *dest;
|
FPU_REG *dest;
|
||||||
u_char taga, tagb, signa, signb, sign, saved_sign;
|
u_char taga, tagb, signa, signb, sign, saved_sign;
|
||||||
int tag, deststnr;
|
int tag, deststnr;
|
||||||
|
|
||||||
if ( flags & DEST_RM )
|
if (flags & DEST_RM)
|
||||||
deststnr = rm;
|
deststnr = rm;
|
||||||
else
|
else
|
||||||
deststnr = 0;
|
deststnr = 0;
|
||||||
|
|
||||||
if ( flags & REV )
|
if (flags & REV) {
|
||||||
{
|
b = &st(0);
|
||||||
b = &st(0);
|
st0_ptr = b;
|
||||||
st0_ptr = b;
|
tagb = FPU_gettag0();
|
||||||
tagb = FPU_gettag0();
|
if (flags & LOADED) {
|
||||||
if ( flags & LOADED )
|
a = (FPU_REG *) rm;
|
||||||
{
|
taga = flags & 0x0f;
|
||||||
a = (FPU_REG *)rm;
|
} else {
|
||||||
taga = flags & 0x0f;
|
a = &st(rm);
|
||||||
|
st_ptr = a;
|
||||||
|
taga = FPU_gettagi(rm);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
a = &st(0);
|
||||||
|
st0_ptr = a;
|
||||||
|
taga = FPU_gettag0();
|
||||||
|
if (flags & LOADED) {
|
||||||
|
b = (FPU_REG *) rm;
|
||||||
|
tagb = flags & 0x0f;
|
||||||
|
} else {
|
||||||
|
b = &st(rm);
|
||||||
|
st_ptr = b;
|
||||||
|
tagb = FPU_gettagi(rm);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
signa = getsign(a);
|
||||||
a = &st(rm);
|
signb = getsign(b);
|
||||||
st_ptr = a;
|
|
||||||
taga = FPU_gettagi(rm);
|
sign = signa ^ signb;
|
||||||
|
|
||||||
|
dest = &st(deststnr);
|
||||||
|
saved_sign = getsign(dest);
|
||||||
|
|
||||||
|
if (!(taga | tagb)) {
|
||||||
|
/* Both regs Valid, this should be the most common case. */
|
||||||
|
reg_copy(a, &x);
|
||||||
|
reg_copy(b, &y);
|
||||||
|
setpositive(&x);
|
||||||
|
setpositive(&y);
|
||||||
|
tag = FPU_u_div(&x, &y, dest, control_w, sign);
|
||||||
|
|
||||||
|
if (tag < 0)
|
||||||
|
return tag;
|
||||||
|
|
||||||
|
FPU_settagi(deststnr, tag);
|
||||||
|
return tag;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
a = &st(0);
|
|
||||||
st0_ptr = a;
|
|
||||||
taga = FPU_gettag0();
|
|
||||||
if ( flags & LOADED )
|
|
||||||
{
|
|
||||||
b = (FPU_REG *)rm;
|
|
||||||
tagb = flags & 0x0f;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
b = &st(rm);
|
|
||||||
st_ptr = b;
|
|
||||||
tagb = FPU_gettagi(rm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
signa = getsign(a);
|
if (taga == TAG_Special)
|
||||||
signb = getsign(b);
|
taga = FPU_Special(a);
|
||||||
|
if (tagb == TAG_Special)
|
||||||
|
tagb = FPU_Special(b);
|
||||||
|
|
||||||
sign = signa ^ signb;
|
if (((taga == TAG_Valid) && (tagb == TW_Denormal))
|
||||||
|
|
||||||
dest = &st(deststnr);
|
|
||||||
saved_sign = getsign(dest);
|
|
||||||
|
|
||||||
if ( !(taga | tagb) )
|
|
||||||
{
|
|
||||||
/* Both regs Valid, this should be the most common case. */
|
|
||||||
reg_copy(a, &x);
|
|
||||||
reg_copy(b, &y);
|
|
||||||
setpositive(&x);
|
|
||||||
setpositive(&y);
|
|
||||||
tag = FPU_u_div(&x, &y, dest, control_w, sign);
|
|
||||||
|
|
||||||
if ( tag < 0 )
|
|
||||||
return tag;
|
|
||||||
|
|
||||||
FPU_settagi(deststnr, tag);
|
|
||||||
return tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( taga == TAG_Special )
|
|
||||||
taga = FPU_Special(a);
|
|
||||||
if ( tagb == TAG_Special )
|
|
||||||
tagb = FPU_Special(b);
|
|
||||||
|
|
||||||
if ( ((taga == TAG_Valid) && (tagb == TW_Denormal))
|
|
||||||
|| ((taga == TW_Denormal) && (tagb == TAG_Valid))
|
|| ((taga == TW_Denormal) && (tagb == TAG_Valid))
|
||||||
|| ((taga == TW_Denormal) && (tagb == TW_Denormal)) )
|
|| ((taga == TW_Denormal) && (tagb == TW_Denormal))) {
|
||||||
{
|
if (denormal_operand() < 0)
|
||||||
if ( denormal_operand() < 0 )
|
return FPU_Exception;
|
||||||
return FPU_Exception;
|
|
||||||
|
|
||||||
FPU_to_exp16(a, &x);
|
FPU_to_exp16(a, &x);
|
||||||
FPU_to_exp16(b, &y);
|
FPU_to_exp16(b, &y);
|
||||||
tag = FPU_u_div(&x, &y, dest, control_w, sign);
|
tag = FPU_u_div(&x, &y, dest, control_w, sign);
|
||||||
if ( tag < 0 )
|
if (tag < 0)
|
||||||
return tag;
|
return tag;
|
||||||
|
|
||||||
FPU_settagi(deststnr, tag);
|
FPU_settagi(deststnr, tag);
|
||||||
return tag;
|
return tag;
|
||||||
}
|
} else if ((taga <= TW_Denormal) && (tagb <= TW_Denormal)) {
|
||||||
else if ( (taga <= TW_Denormal) && (tagb <= TW_Denormal) )
|
if (tagb != TAG_Zero) {
|
||||||
{
|
/* Want to find Zero/Valid */
|
||||||
if ( tagb != TAG_Zero )
|
if (tagb == TW_Denormal) {
|
||||||
{
|
if (denormal_operand() < 0)
|
||||||
/* Want to find Zero/Valid */
|
return FPU_Exception;
|
||||||
if ( tagb == TW_Denormal )
|
}
|
||||||
{
|
|
||||||
if ( denormal_operand() < 0 )
|
|
||||||
return FPU_Exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The result is zero. */
|
/* The result is zero. */
|
||||||
FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
|
FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
|
||||||
setsign(dest, sign);
|
setsign(dest, sign);
|
||||||
return TAG_Zero;
|
return TAG_Zero;
|
||||||
|
}
|
||||||
|
/* We have an exception condition, either 0/0 or Valid/Zero. */
|
||||||
|
if (taga == TAG_Zero) {
|
||||||
|
/* 0/0 */
|
||||||
|
return arith_invalid(deststnr);
|
||||||
|
}
|
||||||
|
/* Valid/Zero */
|
||||||
|
return FPU_divide_by_zero(deststnr, sign);
|
||||||
}
|
}
|
||||||
/* We have an exception condition, either 0/0 or Valid/Zero. */
|
/* Must have infinities, NaNs, etc */
|
||||||
if ( taga == TAG_Zero )
|
else if ((taga == TW_NaN) || (tagb == TW_NaN)) {
|
||||||
{
|
if (flags & LOADED)
|
||||||
/* 0/0 */
|
return real_2op_NaN((FPU_REG *) rm, flags & 0x0f, 0,
|
||||||
return arith_invalid(deststnr);
|
st0_ptr);
|
||||||
}
|
|
||||||
/* Valid/Zero */
|
|
||||||
return FPU_divide_by_zero(deststnr, sign);
|
|
||||||
}
|
|
||||||
/* Must have infinities, NaNs, etc */
|
|
||||||
else if ( (taga == TW_NaN) || (tagb == TW_NaN) )
|
|
||||||
{
|
|
||||||
if ( flags & LOADED )
|
|
||||||
return real_2op_NaN((FPU_REG *)rm, flags & 0x0f, 0, st0_ptr);
|
|
||||||
|
|
||||||
if ( flags & DEST_RM )
|
if (flags & DEST_RM) {
|
||||||
{
|
int tag;
|
||||||
int tag;
|
tag = FPU_gettag0();
|
||||||
tag = FPU_gettag0();
|
if (tag == TAG_Special)
|
||||||
if ( tag == TAG_Special )
|
tag = FPU_Special(st0_ptr);
|
||||||
tag = FPU_Special(st0_ptr);
|
return real_2op_NaN(st0_ptr, tag, rm,
|
||||||
return real_2op_NaN(st0_ptr, tag, rm, (flags & REV) ? st0_ptr : &st(rm));
|
(flags & REV) ? st0_ptr : &st(rm));
|
||||||
}
|
} else {
|
||||||
else
|
int tag;
|
||||||
{
|
tag = FPU_gettagi(rm);
|
||||||
int tag;
|
if (tag == TAG_Special)
|
||||||
tag = FPU_gettagi(rm);
|
tag = FPU_Special(&st(rm));
|
||||||
if ( tag == TAG_Special )
|
return real_2op_NaN(&st(rm), tag, 0,
|
||||||
tag = FPU_Special(&st(rm));
|
(flags & REV) ? st0_ptr : &st(rm));
|
||||||
return real_2op_NaN(&st(rm), tag, 0, (flags & REV) ? st0_ptr : &st(rm));
|
}
|
||||||
}
|
} else if (taga == TW_Infinity) {
|
||||||
}
|
if (tagb == TW_Infinity) {
|
||||||
else if (taga == TW_Infinity)
|
/* infinity/infinity */
|
||||||
{
|
return arith_invalid(deststnr);
|
||||||
if (tagb == TW_Infinity)
|
} else {
|
||||||
{
|
/* tagb must be Valid or Zero */
|
||||||
/* infinity/infinity */
|
if ((tagb == TW_Denormal) && (denormal_operand() < 0))
|
||||||
return arith_invalid(deststnr);
|
return FPU_Exception;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* tagb must be Valid or Zero */
|
|
||||||
if ( (tagb == TW_Denormal) && (denormal_operand() < 0) )
|
|
||||||
return FPU_Exception;
|
|
||||||
|
|
||||||
/* Infinity divided by Zero or Valid does
|
|
||||||
not raise and exception, but returns Infinity */
|
|
||||||
FPU_copy_to_regi(a, TAG_Special, deststnr);
|
|
||||||
setsign(dest, sign);
|
|
||||||
return taga;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (tagb == TW_Infinity)
|
|
||||||
{
|
|
||||||
if ( (taga == TW_Denormal) && (denormal_operand() < 0) )
|
|
||||||
return FPU_Exception;
|
|
||||||
|
|
||||||
/* The result is zero. */
|
/* Infinity divided by Zero or Valid does
|
||||||
FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
|
not raise and exception, but returns Infinity */
|
||||||
setsign(dest, sign);
|
FPU_copy_to_regi(a, TAG_Special, deststnr);
|
||||||
return TAG_Zero;
|
setsign(dest, sign);
|
||||||
}
|
return taga;
|
||||||
|
}
|
||||||
|
} else if (tagb == TW_Infinity) {
|
||||||
|
if ((taga == TW_Denormal) && (denormal_operand() < 0))
|
||||||
|
return FPU_Exception;
|
||||||
|
|
||||||
|
/* The result is zero. */
|
||||||
|
FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
|
||||||
|
setsign(dest, sign);
|
||||||
|
return TAG_Zero;
|
||||||
|
}
|
||||||
#ifdef PARANOID
|
#ifdef PARANOID
|
||||||
else
|
else {
|
||||||
{
|
EXCEPTION(EX_INTERNAL | 0x102);
|
||||||
EXCEPTION(EX_INTERNAL|0x102);
|
return FPU_Exception;
|
||||||
return FPU_Exception;
|
}
|
||||||
}
|
#endif /* PARANOID */
|
||||||
#endif /* PARANOID */
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -20,7 +20,6 @@
|
|||||||
#include "reg_constant.h"
|
#include "reg_constant.h"
|
||||||
#include "fpu_system.h"
|
#include "fpu_system.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Multiply two registers to give a register result.
|
Multiply two registers to give a register result.
|
||||||
The sources are st(deststnr) and (b,tagb,signb).
|
The sources are st(deststnr) and (b,tagb,signb).
|
||||||
@@ -29,104 +28,88 @@
|
|||||||
/* This routine must be called with non-empty source registers */
|
/* This routine must be called with non-empty source registers */
|
||||||
int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w)
|
int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w)
|
||||||
{
|
{
|
||||||
FPU_REG *a = &st(deststnr);
|
FPU_REG *a = &st(deststnr);
|
||||||
FPU_REG *dest = a;
|
FPU_REG *dest = a;
|
||||||
u_char taga = FPU_gettagi(deststnr);
|
u_char taga = FPU_gettagi(deststnr);
|
||||||
u_char saved_sign = getsign(dest);
|
u_char saved_sign = getsign(dest);
|
||||||
u_char sign = (getsign(a) ^ getsign(b));
|
u_char sign = (getsign(a) ^ getsign(b));
|
||||||
int tag;
|
int tag;
|
||||||
|
|
||||||
|
if (!(taga | tagb)) {
|
||||||
|
/* Both regs Valid, this should be the most common case. */
|
||||||
|
|
||||||
if ( !(taga | tagb) )
|
tag =
|
||||||
{
|
FPU_u_mul(a, b, dest, control_w, sign,
|
||||||
/* Both regs Valid, this should be the most common case. */
|
exponent(a) + exponent(b));
|
||||||
|
if (tag < 0) {
|
||||||
tag = FPU_u_mul(a, b, dest, control_w, sign, exponent(a) + exponent(b));
|
setsign(dest, saved_sign);
|
||||||
if ( tag < 0 )
|
return tag;
|
||||||
{
|
}
|
||||||
setsign(dest, saved_sign);
|
FPU_settagi(deststnr, tag);
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
FPU_settagi(deststnr, tag);
|
|
||||||
return tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( taga == TAG_Special )
|
if (taga == TAG_Special)
|
||||||
taga = FPU_Special(a);
|
taga = FPU_Special(a);
|
||||||
if ( tagb == TAG_Special )
|
if (tagb == TAG_Special)
|
||||||
tagb = FPU_Special(b);
|
tagb = FPU_Special(b);
|
||||||
|
|
||||||
if ( ((taga == TAG_Valid) && (tagb == TW_Denormal))
|
if (((taga == TAG_Valid) && (tagb == TW_Denormal))
|
||||||
|| ((taga == TW_Denormal) && (tagb == TAG_Valid))
|
|| ((taga == TW_Denormal) && (tagb == TAG_Valid))
|
||||||
|| ((taga == TW_Denormal) && (tagb == TW_Denormal)) )
|
|| ((taga == TW_Denormal) && (tagb == TW_Denormal))) {
|
||||||
{
|
FPU_REG x, y;
|
||||||
FPU_REG x, y;
|
if (denormal_operand() < 0)
|
||||||
if ( denormal_operand() < 0 )
|
return FPU_Exception;
|
||||||
return FPU_Exception;
|
|
||||||
|
|
||||||
FPU_to_exp16(a, &x);
|
FPU_to_exp16(a, &x);
|
||||||
FPU_to_exp16(b, &y);
|
FPU_to_exp16(b, &y);
|
||||||
tag = FPU_u_mul(&x, &y, dest, control_w, sign,
|
tag = FPU_u_mul(&x, &y, dest, control_w, sign,
|
||||||
exponent16(&x) + exponent16(&y));
|
exponent16(&x) + exponent16(&y));
|
||||||
if ( tag < 0 )
|
if (tag < 0) {
|
||||||
{
|
setsign(dest, saved_sign);
|
||||||
setsign(dest, saved_sign);
|
return tag;
|
||||||
return tag;
|
}
|
||||||
|
FPU_settagi(deststnr, tag);
|
||||||
|
return tag;
|
||||||
|
} else if ((taga <= TW_Denormal) && (tagb <= TW_Denormal)) {
|
||||||
|
if (((tagb == TW_Denormal) || (taga == TW_Denormal))
|
||||||
|
&& (denormal_operand() < 0))
|
||||||
|
return FPU_Exception;
|
||||||
|
|
||||||
|
/* Must have either both arguments == zero, or
|
||||||
|
one valid and the other zero.
|
||||||
|
The result is therefore zero. */
|
||||||
|
FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
|
||||||
|
/* The 80486 book says that the answer is +0, but a real
|
||||||
|
80486 behaves this way.
|
||||||
|
IEEE-754 apparently says it should be this way. */
|
||||||
|
setsign(dest, sign);
|
||||||
|
return TAG_Zero;
|
||||||
|
}
|
||||||
|
/* Must have infinities, NaNs, etc */
|
||||||
|
else if ((taga == TW_NaN) || (tagb == TW_NaN)) {
|
||||||
|
return real_2op_NaN(b, tagb, deststnr, &st(0));
|
||||||
|
} else if (((taga == TW_Infinity) && (tagb == TAG_Zero))
|
||||||
|
|| ((tagb == TW_Infinity) && (taga == TAG_Zero))) {
|
||||||
|
return arith_invalid(deststnr); /* Zero*Infinity is invalid */
|
||||||
|
} else if (((taga == TW_Denormal) || (tagb == TW_Denormal))
|
||||||
|
&& (denormal_operand() < 0)) {
|
||||||
|
return FPU_Exception;
|
||||||
|
} else if (taga == TW_Infinity) {
|
||||||
|
FPU_copy_to_regi(a, TAG_Special, deststnr);
|
||||||
|
setsign(dest, sign);
|
||||||
|
return TAG_Special;
|
||||||
|
} else if (tagb == TW_Infinity) {
|
||||||
|
FPU_copy_to_regi(b, TAG_Special, deststnr);
|
||||||
|
setsign(dest, sign);
|
||||||
|
return TAG_Special;
|
||||||
}
|
}
|
||||||
FPU_settagi(deststnr, tag);
|
|
||||||
return tag;
|
|
||||||
}
|
|
||||||
else if ( (taga <= TW_Denormal) && (tagb <= TW_Denormal) )
|
|
||||||
{
|
|
||||||
if ( ((tagb == TW_Denormal) || (taga == TW_Denormal))
|
|
||||||
&& (denormal_operand() < 0) )
|
|
||||||
return FPU_Exception;
|
|
||||||
|
|
||||||
/* Must have either both arguments == zero, or
|
|
||||||
one valid and the other zero.
|
|
||||||
The result is therefore zero. */
|
|
||||||
FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
|
|
||||||
/* The 80486 book says that the answer is +0, but a real
|
|
||||||
80486 behaves this way.
|
|
||||||
IEEE-754 apparently says it should be this way. */
|
|
||||||
setsign(dest, sign);
|
|
||||||
return TAG_Zero;
|
|
||||||
}
|
|
||||||
/* Must have infinities, NaNs, etc */
|
|
||||||
else if ( (taga == TW_NaN) || (tagb == TW_NaN) )
|
|
||||||
{
|
|
||||||
return real_2op_NaN(b, tagb, deststnr, &st(0));
|
|
||||||
}
|
|
||||||
else if ( ((taga == TW_Infinity) && (tagb == TAG_Zero))
|
|
||||||
|| ((tagb == TW_Infinity) && (taga == TAG_Zero)) )
|
|
||||||
{
|
|
||||||
return arith_invalid(deststnr); /* Zero*Infinity is invalid */
|
|
||||||
}
|
|
||||||
else if ( ((taga == TW_Denormal) || (tagb == TW_Denormal))
|
|
||||||
&& (denormal_operand() < 0) )
|
|
||||||
{
|
|
||||||
return FPU_Exception;
|
|
||||||
}
|
|
||||||
else if (taga == TW_Infinity)
|
|
||||||
{
|
|
||||||
FPU_copy_to_regi(a, TAG_Special, deststnr);
|
|
||||||
setsign(dest, sign);
|
|
||||||
return TAG_Special;
|
|
||||||
}
|
|
||||||
else if (tagb == TW_Infinity)
|
|
||||||
{
|
|
||||||
FPU_copy_to_regi(b, TAG_Special, deststnr);
|
|
||||||
setsign(dest, sign);
|
|
||||||
return TAG_Special;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef PARANOID
|
#ifdef PARANOID
|
||||||
else
|
else {
|
||||||
{
|
EXCEPTION(EX_INTERNAL | 0x102);
|
||||||
EXCEPTION(EX_INTERNAL|0x102);
|
return FPU_Exception;
|
||||||
return FPU_Exception;
|
}
|
||||||
}
|
#endif /* PARANOID */
|
||||||
#endif /* PARANOID */
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
#ifndef _STATUS_H_
|
#ifndef _STATUS_H_
|
||||||
#define _STATUS_H_
|
#define _STATUS_H_
|
||||||
|
|
||||||
#include "fpu_emu.h" /* for definition of PECULIAR_486 */
|
#include "fpu_emu.h" /* for definition of PECULIAR_486 */
|
||||||
|
|
||||||
#ifdef __ASSEMBLY__
|
#ifdef __ASSEMBLY__
|
||||||
#define Const__(x) $##x
|
#define Const__(x) $##x
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
#define SW_Denorm_Op Const__(0x0002) /* denormalized operand */
|
#define SW_Denorm_Op Const__(0x0002) /* denormalized operand */
|
||||||
#define SW_Invalid Const__(0x0001) /* invalid operation */
|
#define SW_Invalid Const__(0x0001) /* invalid operation */
|
||||||
|
|
||||||
#define SW_Exc_Mask Const__(0x27f) /* Status word exception bit mask */
|
#define SW_Exc_Mask Const__(0x27f) /* Status word exception bit mask */
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
@@ -50,8 +50,8 @@
|
|||||||
((partial_status & ~SW_Top & 0xffff) | ((top << SW_Top_Shift) & SW_Top))
|
((partial_status & ~SW_Top & 0xffff) | ((top << SW_Top_Shift) & SW_Top))
|
||||||
static inline void setcc(int cc)
|
static inline void setcc(int cc)
|
||||||
{
|
{
|
||||||
partial_status &= ~(SW_C0|SW_C1|SW_C2|SW_C3);
|
partial_status &= ~(SW_C0 | SW_C1 | SW_C2 | SW_C3);
|
||||||
partial_status |= (cc) & (SW_C0|SW_C1|SW_C2|SW_C3);
|
partial_status |= (cc) & (SW_C0 | SW_C1 | SW_C2 | SW_C3);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef PECULIAR_486
|
#ifdef PECULIAR_486
|
||||||
|
Reference in New Issue
Block a user