summaryrefslogtreecommitdiff
path: root/sim/erc32/float.c
blob: c1a46f8aea1a149b0a95cdfb8518fb3f12d932a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/*
 * This file is part of SIS.
 *
 * SIS, SPARC instruction simulator. Copyright (C) 1995 Jiri Gaisler, European
 * Space Agency
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 3 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, see <http://www.gnu.org/licenses/>.
 *
 *
 * This file implements the interface between the host and the simulated
 * FPU. IEEE trap handling is done as follows: 
 * 1. In the host, all IEEE traps are masked
 * 2. After each simulated FPU instruction, check if any exception occured 
 *    by reading the exception bits from the host FPU status register 
 *    (get_accex()).
 * 3. Propagate any exceptions to the simulated FSR.
 * 4. Clear host exception bits
 *
 *
 * This can also be done using ieee_flags() library routine on sun.
 */

#include "config.h"
#include "sis.h"

/* Forward declarations */

extern uint32	_get_sw PARAMS ((void));
extern uint32	_get_cw PARAMS ((void));
static void	__setfpucw PARAMS ((unsigned short fpu_control));

/* This host dependent routine should return the accrued exceptions */
int
get_accex()
{
#ifdef sparc
    return ((_get_fsr_raw() >> 5) & 0x1F);
#elif i386
    uint32 accx;

    accx = _get_sw() & 0x3f;
    accx = ((accx & 1) << 4) | ((accx & 2) >> 1) | ((accx & 4) >> 1) |
	   (accx & 8) | ((accx & 16) >> 2) | ((accx & 32) >> 5);
    return(accx);
#else
    return(0);
#warning no fpu trap support for this target
#endif

}

/* How to clear the accrued exceptions */
void
clear_accex()
{
#ifdef sparc
    set_fsr((_get_fsr_raw() & ~0x3e0));
#elif i386
    asm("\n"
".text\n"
"	fnclex\n"
"\n"
"    ");
#else
#warning no fpu trap support for this target
#endif
}

/* How to map SPARC FSR onto the host */
void
set_fsr(fsr)
uint32 fsr;
{
#ifdef sparc
	_set_fsr_raw(fsr & ~0x0f800000);
#elif i386
     void __setfpucw(unsigned short fpu_control);
     uint32 rawfsr;

     fsr >>= 30;
     switch (fsr) {
	case 0: 
	case 2: break;
	case 1: fsr = 3;
	case 3: fsr = 1;
     }
     rawfsr = _get_cw();
     rawfsr |= (fsr << 10) | 0x3ff;
     __setfpucw(rawfsr);
#else
#warning no fpu trap support for this target
#endif
}


/* Host dependent support functions */

#ifdef sparc

    asm("\n"
"\n"
".text\n"
"        .align 4\n"
"        .global __set_fsr_raw,_set_fsr_raw\n"
"__set_fsr_raw:\n"
"_set_fsr_raw:\n"
"        save %sp,-104,%sp\n"
"        st %i0,[%fp+68]\n"
"        ld [%fp+68], %fsr\n"
"        mov 0,%i0\n"
"        ret\n"
"        restore\n"
"\n"
"        .align 4\n"
"        .global __get_fsr_raw\n"
"        .global _get_fsr_raw\n"
"__get_fsr_raw:\n"
"_get_fsr_raw:\n"
"        save %sp,-104,%sp\n"
"        st %fsr,[%fp+68]\n"
"        ld [%fp+68], %i0\n"
"        ret\n"
"        restore\n"
"\n"
"    ");

#elif i386

    asm("\n"
"\n"
".text\n"
"        .align 8\n"
".globl _get_sw,__get_sw\n"
"__get_sw:\n"
"_get_sw:\n"
"        pushl %ebp\n"
"        movl %esp,%ebp\n"
"        movl $0,%eax\n"
"        fnstsw %ax\n"
"        movl %ebp,%esp\n"
"        popl %ebp\n"
"        ret\n"
"\n"
"        .align 8\n"
".globl _get_cw,__get_cw\n"
"__get_cw:\n"
"_get_cw:\n"
"        pushl %ebp\n"
"        movl %esp,%ebp\n"
"        subw $2,%esp\n"
"        fnstcw -2(%ebp)\n"
"        movw -2(%ebp),%eax\n"
"        movl %ebp,%esp\n"
"        popl %ebp\n"
"        ret\n"
"\n"
"\n"
"    ");


#else
#warning no fpu trap support for this target
#endif

#if i386
/* #if defined _WIN32 || defined __GO32__ */
/* This is so floating exception handling works on NT
   These definitions are from the linux fpu_control.h, which
   doesn't exist on NT.

   default to:
     - extended precision
     - rounding to nearest
     - exceptions on overflow, zero divide and NaN
*/
#define _FPU_DEFAULT  0x1372 
#define _FPU_RESERVED 0xF0C0  /* Reserved bits in cw */

static void
__setfpucw(unsigned short fpu_control)
{
  volatile unsigned short cw;

  /* If user supplied _fpu_control, use it ! */
  if (!fpu_control)
  { 
    /* use defaults */
    fpu_control = _FPU_DEFAULT;
  }
  /* Get Control Word */
  __asm__ volatile ("fnstcw %0" : "=m" (cw) : );
  
  /* mask in */
  cw &= _FPU_RESERVED;
  cw = cw | (fpu_control & ~_FPU_RESERVED);

  /* set cw */
  __asm__ volatile ("fldcw %0" :: "m" (cw));
}
/* #endif */
#endif