2005-04-16 15:20:36 -07:00
/*---------------------------------------------------------------------------+
| fpu_aux . c |
| |
| Code to implement some of the FPU auxiliary instructions . |
| |
| Copyright ( C ) 1992 , 1993 , 1994 , 1997 |
| W . Metzenthen , 22 Parker St , Ormond , Vic 3163 , Australia |
| E - mail billm @ suburbia . net |
| |
| |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
# include "fpu_system.h"
# include "exception.h"
# include "fpu_emu.h"
# include "status_w.h"
# include "control_w.h"
static void fnop ( void )
{
}
static void fclex ( void )
{
2008-01-30 13:30:11 +01:00
partial_status & =
~ ( SW_Backward | SW_Summary | SW_Stack_Fault | SW_Precision |
SW_Underflow | SW_Overflow | SW_Zero_Div | SW_Denorm_Op |
SW_Invalid ) ;
no_ip_update = 1 ;
2005-04-16 15:20:36 -07:00
}
/* Needs to be externally visible */
2010-05-06 11:45:46 +03:00
void finit_soft_fpu ( struct i387_soft_struct * soft )
2005-04-16 15:20:36 -07:00
{
2009-03-04 19:42:27 +01:00
struct address * oaddr , * iaddr ;
2010-05-06 11:45:46 +03:00
memset ( soft , 0 , sizeof ( * soft ) ) ;
2009-03-04 19:42:27 +01:00
soft - > cwd = 0x037f ;
soft - > swd = 0 ;
soft - > ftop = 0 ; /* We don't keep top in the status word internally. */
soft - > twd = 0xffff ;
2008-01-30 13:30:11 +01:00
/* The behaviour is different from that detailed in
Section 15.1 .6 of the Intel manual */
2009-03-04 19:42:27 +01:00
oaddr = ( struct address * ) & soft - > foo ;
oaddr - > offset = 0 ;
oaddr - > selector = 0 ;
iaddr = ( struct address * ) & soft - > fip ;
iaddr - > offset = 0 ;
iaddr - > selector = 0 ;
iaddr - > opcode = 0 ;
soft - > no_update = 1 ;
}
void finit ( void )
{
2010-05-10 13:37:16 -07:00
finit_soft_fpu ( & current - > thread . fpu . state - > soft ) ;
2005-04-16 15:20:36 -07:00
}
/*
* These are nops on the i387 . .
*/
# define feni fnop
# define fdisi fnop
# define fsetpm fnop
static FUNC const finit_table [ ] = {
2008-01-30 13:30:11 +01:00
feni , fdisi , fclex , finit ,
fsetpm , FPU_illegal , FPU_illegal , FPU_illegal
2005-04-16 15:20:36 -07:00
} ;
void finit_ ( void )
{
2008-01-30 13:30:11 +01:00
( finit_table [ FPU_rm ] ) ( ) ;
2005-04-16 15:20:36 -07:00
}
static void fstsw_ax ( void )
{
2008-01-30 13:30:11 +01:00
* ( short * ) & FPU_EAX = status_word ( ) ;
no_ip_update = 1 ;
2005-04-16 15:20:36 -07:00
}
static FUNC const fstsw_table [ ] = {
2008-01-30 13:30:11 +01:00
fstsw_ax , FPU_illegal , FPU_illegal , FPU_illegal ,
FPU_illegal , FPU_illegal , FPU_illegal , FPU_illegal
2005-04-16 15:20:36 -07:00
} ;
void fstsw_ ( void )
{
2008-01-30 13:30:11 +01:00
( fstsw_table [ FPU_rm ] ) ( ) ;
2005-04-16 15:20:36 -07:00
}
static FUNC const fp_nop_table [ ] = {
2008-01-30 13:30:11 +01:00
fnop , FPU_illegal , FPU_illegal , FPU_illegal ,
FPU_illegal , FPU_illegal , FPU_illegal , FPU_illegal
2005-04-16 15:20:36 -07:00
} ;
void fp_nop ( void )
{
2008-01-30 13:30:11 +01:00
( fp_nop_table [ FPU_rm ] ) ( ) ;
2005-04-16 15:20:36 -07:00
}
void fld_i_ ( void )
{
2008-01-30 13:30:11 +01:00
FPU_REG * st_new_ptr ;
int i ;
u_char tag ;
if ( STACK_OVERFLOW ) {
FPU_stack_overflow ( ) ;
return ;
2005-04-16 15:20:36 -07:00
}
2008-01-30 13:30:11 +01:00
/* fld st(i) */
i = FPU_rm ;
if ( NOT_EMPTY ( i ) ) {
reg_copy ( & st ( i ) , st_new_ptr ) ;
tag = FPU_gettagi ( i ) ;
push ( ) ;
FPU_settag0 ( tag ) ;
} else {
if ( control_word & CW_Invalid ) {
/* The masked response */
FPU_stack_underflow ( ) ;
} else
EXCEPTION ( EX_StackUnder ) ;
}
2005-04-16 15:20:36 -07:00
2008-01-30 13:30:11 +01:00
}
2005-04-16 15:20:36 -07:00
void fxch_i ( void )
{
2008-01-30 13:30:11 +01:00
/* fxch st(i) */
FPU_REG t ;
int i = FPU_rm ;
FPU_REG * st0_ptr = & st ( 0 ) , * sti_ptr = & st ( i ) ;
long tag_word = fpu_tag_word ;
int regnr = top & 7 , regnri = ( ( regnr + i ) & 7 ) ;
u_char st0_tag = ( tag_word > > ( regnr * 2 ) ) & 3 ;
u_char sti_tag = ( tag_word > > ( regnri * 2 ) ) & 3 ;
if ( st0_tag = = TAG_Empty ) {
if ( sti_tag = = TAG_Empty ) {
FPU_stack_underflow ( ) ;
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 ;
2005-04-16 15:20:36 -07:00
}
2008-01-30 13:30:11 +01:00
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 ;
2005-04-16 15:20:36 -07:00
}
2008-01-30 13:30:11 +01:00
clear_C1 ( ) ;
2005-04-16 15:20:36 -07:00
2008-01-30 13:30:11 +01:00
reg_copy ( st0_ptr , & t ) ;
reg_copy ( sti_ptr , st0_ptr ) ;
reg_copy ( & t , sti_ptr ) ;
tag_word & = ~ ( 3 < < ( regnr * 2 ) ) & ~ ( 3 < < ( regnri * 2 ) ) ;
tag_word | = ( sti_tag < < ( regnr * 2 ) ) | ( st0_tag < < ( regnri * 2 ) ) ;
fpu_tag_word = tag_word ;
}
2005-04-16 15:20:36 -07:00
void ffree_ ( void )
{
2008-01-30 13:30:11 +01:00
/* ffree st(i) */
FPU_settagi ( FPU_rm , TAG_Empty ) ;
2005-04-16 15:20:36 -07:00
}
void ffreep ( void )
{
2008-01-30 13:30:11 +01:00
/* ffree st(i) + pop - unofficial code */
FPU_settagi ( FPU_rm , TAG_Empty ) ;
FPU_pop ( ) ;
2005-04-16 15:20:36 -07:00
}
void fst_i_ ( void )
{
2008-01-30 13:30:11 +01:00
/* fst st(i) */
FPU_copy_to_regi ( & st ( 0 ) , FPU_gettag0 ( ) , FPU_rm ) ;
2005-04-16 15:20:36 -07:00
}
void fstp_i ( void )
{
2008-01-30 13:30:11 +01:00
/* fstp st(i) */
FPU_copy_to_regi ( & st ( 0 ) , FPU_gettag0 ( ) , FPU_rm ) ;
FPU_pop ( ) ;
2005-04-16 15:20:36 -07:00
}