074ceb97a7da87acd1bfb7727f4e013ffef16c02
[external/binutils.git] / sim / erc32 / float.c
1 /*
2  * This file is part of SIS.
3  *
4  * SIS, SPARC instruction simulator. Copyright (C) 1995 Jiri Gaisler, European
5  * Space Agency
6  *
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along with
18  * this program; if not, write to the Free Software Foundation, Inc., 675
19  * Mass Ave, Cambridge, MA 02139, USA.
20  *
21  *
22  * This file implements the interface between the host and the simulated
23  * FPU. IEEE trap handling is done as follows: 
24  * 1. In the host, all IEEE traps are masked
25  * 2. After each simulated FPU instruction, check if any exception occured 
26  *    by reading the exception bits from the host FPU status register 
27  *    (get_accex()).
28  * 3. Propagate any exceptions to the simulated FSR.
29  * 4. Clear host exception bits
30  *
31  *
32  * This can also be done using ieee_flags() library routine on sun.
33  */
34
35 #include "config.h"
36 #include "sis.h"
37
38 /* Forward declarations */
39
40 extern uint32   _get_sw PARAMS ((void));
41 extern uint32   _get_cw PARAMS ((void));
42 static void     __setfpucw PARAMS ((unsigned short fpu_control));
43
44 /* This host dependent routine should return the accrued exceptions */
45 int
46 get_accex()
47 {
48 #ifdef sparc
49     return ((_get_fsr_raw() >> 5) & 0x1F);
50 #elif i386
51     uint32 accx;
52
53     accx = _get_sw() & 0x3f;
54     accx = ((accx & 1) << 4) | ((accx & 2) >> 1) | ((accx & 4) >> 1) |
55            (accx & 8) | ((accx & 16) >> 2) | ((accx & 32) >> 5);
56     return(accx);
57 #else
58     return(0);
59 #warning no fpu trap support for this target
60 #endif
61
62 }
63
64 /* How to clear the accrued exceptions */
65 void
66 clear_accex()
67 {
68 #ifdef sparc
69     set_fsr((_get_fsr_raw() & ~0x3e0));
70 #elif i386
71     asm("\n"
72 ".text\n"
73 "       fnclex\n"
74 "\n"
75 "    ");
76 #else
77 #warning no fpu trap support for this target
78 #endif
79 }
80
81 /* How to map SPARC FSR onto the host */
82 void
83 set_fsr(fsr)
84 uint32 fsr;
85 {
86 #ifdef sparc
87         _set_fsr_raw(fsr & ~0x0f800000);
88 #elif i386
89      void __setfpucw(unsigned short fpu_control);
90      uint32 rawfsr;
91
92      fsr >>= 30;
93      switch (fsr) {
94         case 0: 
95         case 2: break;
96         case 1: fsr = 3;
97         case 3: fsr = 1;
98      }
99      rawfsr = _get_cw();
100      rawfsr |= (fsr << 10) | 0x3ff;
101      __setfpucw(rawfsr);
102 #else
103 #warning no fpu trap support for this target
104 #endif
105 }
106
107
108 /* Host dependent support functions */
109
110 #ifdef sparc
111
112     asm("\n"
113 "\n"
114 ".text\n"
115 "        .align 4\n"
116 "        .global __set_fsr_raw,_set_fsr_raw\n"
117 "__set_fsr_raw:\n"
118 "_set_fsr_raw:\n"
119 "        save %sp,-104,%sp\n"
120 "        st %i0,[%fp+68]\n"
121 "        ld [%fp+68], %fsr\n"
122 "        mov 0,%i0\n"
123 "        ret\n"
124 "        restore\n"
125 "\n"
126 "        .align 4\n"
127 "        .global __get_fsr_raw\n"
128 "        .global _get_fsr_raw\n"
129 "__get_fsr_raw:\n"
130 "_get_fsr_raw:\n"
131 "        save %sp,-104,%sp\n"
132 "        st %fsr,[%fp+68]\n"
133 "        ld [%fp+68], %i0\n"
134 "        ret\n"
135 "        restore\n"
136 "\n"
137 "    ");
138
139 #elif i386
140
141     asm("\n"
142 "\n"
143 ".text\n"
144 "        .align 8\n"
145 ".globl _get_sw,__get_sw\n"
146 "__get_sw:\n"
147 "_get_sw:\n"
148 "        pushl %ebp\n"
149 "        movl %esp,%ebp\n"
150 "        movl $0,%eax\n"
151 "        fnstsw %ax\n"
152 "        movl %ebp,%esp\n"
153 "        popl %ebp\n"
154 "        ret\n"
155 "\n"
156 "        .align 8\n"
157 ".globl _get_cw,__get_cw\n"
158 "__get_cw:\n"
159 "_get_cw:\n"
160 "        pushl %ebp\n"
161 "        movl %esp,%ebp\n"
162 "        subw $2,%esp\n"
163 "        fnstcw -2(%ebp)\n"
164 "        movw -2(%ebp),%eax\n"
165 "        movl %ebp,%esp\n"
166 "        popl %ebp\n"
167 "        ret\n"
168 "\n"
169 "\n"
170 "    ");
171
172
173 #else
174 #warning no fpu trap support for this target
175 #endif
176
177 #if i386
178 /* #if defined _WIN32 || defined __GO32__ */
179 /* This is so floating exception handling works on NT
180    These definitions are from the linux fpu_control.h, which
181    doesn't exist on NT.
182
183    default to:
184      - extended precision
185      - rounding to nearest
186      - exceptions on overflow, zero divide and NaN
187 */
188 #define _FPU_DEFAULT  0x1372 
189 #define _FPU_RESERVED 0xF0C0  /* Reserved bits in cw */
190
191 static void
192 __setfpucw(unsigned short fpu_control)
193 {
194   volatile unsigned short cw;
195
196   /* If user supplied _fpu_control, use it ! */
197   if (!fpu_control)
198   { 
199     /* use defaults */
200     fpu_control = _FPU_DEFAULT;
201   }
202   /* Get Control Word */
203   __asm__ volatile ("fnstcw %0" : "=m" (cw) : );
204   
205   /* mask in */
206   cw &= _FPU_RESERVED;
207   cw = cw | (fpu_control & ~_FPU_RESERVED);
208
209   /* set cw */
210   __asm__ volatile ("fldcw %0" :: "m" (cw));
211 }
212 /* #endif */
213 #endif