linux/arch/x86/math-emu/fpu_aux.c
<<
>>
Prefs
   1/*---------------------------------------------------------------------------+
   2 |  fpu_aux.c                                                                |
   3 |                                                                           |
   4 | Code to implement some of the FPU auxiliary instructions.                 |
   5 |                                                                           |
   6 | Copyright (C) 1992,1993,1994,1997                                         |
   7 |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
   8 |                  E-mail   billm@suburbia.net                              |
   9 |                                                                           |
  10 |                                                                           |
  11 +---------------------------------------------------------------------------*/
  12
  13#include "fpu_system.h"
  14#include "exception.h"
  15#include "fpu_emu.h"
  16#include "status_w.h"
  17#include "control_w.h"
  18
  19static void fnop(void)
  20{
  21}
  22
  23static void fclex(void)
  24{
  25        partial_status &=
  26            ~(SW_Backward | SW_Summary | SW_Stack_Fault | SW_Precision |
  27              SW_Underflow | SW_Overflow | SW_Zero_Div | SW_Denorm_Op |
  28              SW_Invalid);
  29        no_ip_update = 1;
  30}
  31
  32/* Needs to be externally visible */
  33void finit_soft_fpu(struct i387_soft_struct *soft)
  34{
  35        struct address *oaddr, *iaddr;
  36        memset(soft, 0, sizeof(*soft));
  37        soft->cwd = 0x037f;
  38        soft->swd = 0;
  39        soft->ftop = 0; /* We don't keep top in the status word internally. */
  40        soft->twd = 0xffff;
  41        /* The behaviour is different from that detailed in
  42           Section 15.1.6 of the Intel manual */
  43        oaddr = (struct address *)&soft->foo;
  44        oaddr->offset = 0;
  45        oaddr->selector = 0;
  46        iaddr = (struct address *)&soft->fip;
  47        iaddr->offset = 0;
  48        iaddr->selector = 0;
  49        iaddr->opcode = 0;
  50        soft->no_update = 1;
  51}
  52
  53void finit(void)
  54{
  55        finit_soft_fpu(&current->thread.fpu.state->soft);
  56}
  57
  58/*
  59 * These are nops on the i387..
  60 */
  61#define feni fnop
  62#define fdisi fnop
  63#define fsetpm fnop
  64
  65static FUNC const finit_table[] = {
  66        feni, fdisi, fclex, finit,
  67        fsetpm, FPU_illegal, FPU_illegal, FPU_illegal
  68};
  69
  70void finit_(void)
  71{
  72        (finit_table[FPU_rm]) ();
  73}
  74
  75static void fstsw_ax(void)
  76{
  77        *(short *)&FPU_EAX = status_word();
  78        no_ip_update = 1;
  79}
  80
  81static FUNC const fstsw_table[] = {
  82        fstsw_ax, FPU_illegal, FPU_illegal, FPU_illegal,
  83        FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
  84};
  85
  86void fstsw_(void)
  87{
  88        (fstsw_table[FPU_rm]) ();
  89}
  90
  91static FUNC const fp_nop_table[] = {
  92        fnop, FPU_illegal, FPU_illegal, FPU_illegal,
  93        FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
  94};
  95
  96void fp_nop(void)
  97{
  98        (fp_nop_table[FPU_rm]) ();
  99}
 100
 101void fld_i_(void)
 102{
 103        FPU_REG *st_new_ptr;
 104        int i;
 105        u_char tag;
 106
 107        if (STACK_OVERFLOW) {
 108                FPU_stack_overflow();
 109                return;
 110        }
 111
 112        /* fld st(i) */
 113        i = FPU_rm;
 114        if (NOT_EMPTY(i)) {
 115                reg_copy(&st(i), st_new_ptr);
 116                tag = FPU_gettagi(i);
 117                push();
 118                FPU_settag0(tag);
 119        } else {
 120                if (control_word & CW_Invalid) {
 121                        /* The masked response */
 122                        FPU_stack_underflow();
 123                } else
 124                        EXCEPTION(EX_StackUnder);
 125        }
 126
 127}
 128
 129void fxch_i(void)
 130{
 131        /* fxch st(i) */
 132        FPU_REG t;
 133        int i = FPU_rm;
 134        FPU_REG *st0_ptr = &st(0), *sti_ptr = &st(i);
 135        long tag_word = fpu_tag_word;
 136        int regnr = top & 7, regnri = ((regnr + i) & 7);
 137        u_char st0_tag = (tag_word >> (regnr * 2)) & 3;
 138        u_char sti_tag = (tag_word >> (regnri * 2)) & 3;
 139
 140        if (st0_tag == TAG_Empty) {
 141                if (sti_tag == TAG_Empty) {
 142                        FPU_stack_underflow();
 143                        FPU_stack_underflow_i(i);
 144                        return;
 145                }
 146                if (control_word & CW_Invalid) {
 147                        /* Masked response */
 148                        FPU_copy_to_reg0(sti_ptr, sti_tag);
 149                }
 150                FPU_stack_underflow_i(i);
 151                return;
 152        }
 153        if (sti_tag == TAG_Empty) {
 154                if (control_word & CW_Invalid) {
 155                        /* Masked response */
 156                        FPU_copy_to_regi(st0_ptr, st0_tag, i);
 157                }
 158                FPU_stack_underflow();
 159                return;
 160        }
 161        clear_C1();
 162
 163        reg_copy(st0_ptr, &t);
 164        reg_copy(sti_ptr, st0_ptr);
 165        reg_copy(&t, sti_ptr);
 166
 167        tag_word &= ~(3 << (regnr * 2)) & ~(3 << (regnri * 2));
 168        tag_word |= (sti_tag << (regnr * 2)) | (st0_tag << (regnri * 2));
 169        fpu_tag_word = tag_word;
 170}
 171
 172void ffree_(void)
 173{
 174        /* ffree st(i) */
 175        FPU_settagi(FPU_rm, TAG_Empty);
 176}
 177
 178void ffreep(void)
 179{
 180        /* ffree st(i) + pop - unofficial code */
 181        FPU_settagi(FPU_rm, TAG_Empty);
 182        FPU_pop();
 183}
 184
 185void fst_i_(void)
 186{
 187        /* fst st(i) */
 188        FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
 189}
 190
 191void fstp_i(void)
 192{
 193        /* fstp st(i) */
 194        FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
 195        FPU_pop();
 196}
 197