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