1 /////////////////////////////////////////////////////////////////////////
2 // $Id: ferr.cc 14086 2021-01-30 08:35:35Z sshwarts $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 //   Copyright (c) 2003-2017 Stanislav Shwartsman
6 //          Written by Stanislav Shwartsman [sshwarts at sourceforge net]
7 //
8 //  This library is free software; you can redistribute it and/or
9 //  modify it under the terms of the GNU Lesser General Public
10 //  License as published by the Free Software Foundation; either
11 //  version 2 of the License, or (at your option) any later version.
12 //
13 //  This library is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 //  Lesser General Public License for more details.
17 //
18 //  You should have received a copy of the GNU Lesser General Public
19 //  License along with this library; if not, write to the Free Software
20 //  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
21 //
22 /////////////////////////////////////////////////////////////////////////
23 
24 #define NEED_CPU_REG_SHORTCUTS 1
25 #include "bochs.h"
26 #include "cpu/cpu.h"
27 #define LOG_THIS BX_CPU_THIS_PTR
28 
29 #if BX_SUPPORT_FPU
30 
31 #include "softfloat-specialize.h"
32 
FPU_stack_overflow(bxInstruction_c * i)33 void BX_CPU_C::FPU_stack_overflow(bxInstruction_c *i)
34 {
35   /* The masked response */
36   if (BX_CPU_THIS_PTR the_i387.is_IA_masked())
37   {
38     BX_CPU_THIS_PTR the_i387.FPU_push();
39     BX_WRITE_FPU_REG(floatx80_default_nan, 0);
40   }
41   FPU_exception(i, FPU_EX_Stack_Overflow);
42 }
43 
FPU_stack_underflow(bxInstruction_c * i,int stnr,int pop_stack)44 void BX_CPU_C::FPU_stack_underflow(bxInstruction_c *i, int stnr, int pop_stack)
45 {
46   /* The masked response */
47   if (BX_CPU_THIS_PTR the_i387.is_IA_masked())
48   {
49     BX_WRITE_FPU_REG(floatx80_default_nan, stnr);
50     if (pop_stack)
51         BX_CPU_THIS_PTR the_i387.FPU_pop();
52   }
53   FPU_exception(i, FPU_EX_Stack_Underflow);
54 }
55 
56 /* Returns unmasked exceptions if occurred */
FPU_exception(bxInstruction_c * i,unsigned exception,bool is_store)57 unsigned BX_CPU_C::FPU_exception(bxInstruction_c *i, unsigned exception, bool is_store)
58 {
59   /* Extract only the bits which we use to set the status word */
60   exception &= (FPU_SW_Exceptions_Mask);
61 
62   Bit32u status = FPU_PARTIAL_STATUS;
63 
64   unsigned unmasked = exception & ~FPU_CONTROL_WORD & FPU_CW_Exceptions_Mask;
65   // if IE or DZ exception happen nothing else will be reported
66   if (exception & (FPU_EX_Invalid | FPU_EX_Zero_Div))
67       unmasked &= (FPU_EX_Invalid | FPU_EX_Zero_Div);
68 
69   /* Set summary bits iff exception isn't masked */
70   if (unmasked) {
71     FPU_PARTIAL_STATUS |= (FPU_SW_Summary | FPU_SW_Backward);
72 
73     // when FOPCODE deprecation is set, FOPCODE is updated only when unmasked x87 exception occurs
74     if (is_cpu_extension_supported(BX_ISA_FOPCODE_DEPRECATION))
75       BX_CPU_THIS_PTR the_i387.foo = i->foo();
76 
77     // when FOPCODE deprecation is set, FCS/FDP are updated only when unmasked x87 exception occurs
78     if (is_cpu_extension_supported(BX_ISA_FDP_DEPRECATION)) {
79       if (! i->modC0()) {
80         BX_CPU_THIS_PTR the_i387.fds = BX_CPU_THIS_PTR sregs[i->seg()].selector.value;
81         BX_CPU_THIS_PTR the_i387.fdp = RMAddr(i);
82       }
83     }
84   }
85 
86   if (exception & FPU_EX_Invalid) {
87      // FPU_EX_Invalid cannot come with any other exception but x87 stack fault
88      FPU_PARTIAL_STATUS |= exception;
89      if (exception & FPU_SW_Stack_Fault) {
90         if (! (exception & FPU_SW_C1)) {
91            /* This bit distinguishes over- from underflow for a stack fault,
92               and roundup from round-down for precision loss. */
93            FPU_PARTIAL_STATUS &= ~FPU_SW_C1;
94         }
95      }
96      return unmasked;
97   }
98 
99   if (exception & FPU_EX_Zero_Div) {
100      FPU_PARTIAL_STATUS |= FPU_EX_Zero_Div;
101      return unmasked;
102   }
103 
104   if (exception & FPU_EX_Denormal) {
105      FPU_PARTIAL_STATUS |= FPU_EX_Denormal;
106      if (unmasked & FPU_EX_Denormal)
107         return unmasked & FPU_EX_Denormal;
108   }
109 
110   /* Set the corresponding exception bits */
111   FPU_PARTIAL_STATUS |= exception;
112 
113   if (exception & FPU_EX_Precision)
114   {
115     if (! (exception & FPU_SW_C1)) {
116       /* This bit distinguishes over- from underflow for a stack fault,
117            and roundup from round-down for precision loss. */
118       FPU_PARTIAL_STATUS &= ~FPU_SW_C1;
119     }
120   }
121 
122   // If #P unmasked exception occurred the result still has to be
123   // written to the destination.
124   unmasked &= ~FPU_EX_Precision;
125 
126   if (unmasked & (FPU_EX_Underflow | FPU_EX_Overflow)) {
127     // If unmasked over- or underflow occurs and dest is a memory location:
128     //   - the TOS and destination operands remain unchanged
129     //   - the inexact-result condition is not reported and C1 flag is cleared
130     //   - no result is stored in the memory
131     // If the destination is in the register stack, adjusted resulting value
132     // is stored in the destination operand.
133     if (! is_store) {
134        unmasked &= ~(FPU_EX_Underflow | FPU_EX_Overflow);
135     }
136     else {
137        FPU_PARTIAL_STATUS &= ~FPU_SW_C1; // clear C1 flag
138        if (! (status & FPU_EX_Precision))
139           FPU_PARTIAL_STATUS &= ~FPU_EX_Precision;
140     }
141   }
142 
143   return unmasked;
144 }
145 
146 #endif
147