Merge from vendor branch OPENSSL:
[dragonfly.git] / sys / i386 / gnu / fpemul / load_store.c
1 /*
2  *  load_store.c
3  *
4  * This file contains most of the code to interpret the FPU instructions
5  * which load and store from user memory.
6  *
7  *
8  * Copyright (C) 1992,1993,1994
9  *                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
10  *                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au
11  * All rights reserved.
12  *
13  * This copyright notice covers the redistribution and use of the
14  * FPU emulator developed by W. Metzenthen. It covers only its use
15  * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
16  * use is not permitted under this copyright.
17  *
18  * Redistribution and use in source and binary forms, with or without
19  * modification, are permitted provided that the following conditions
20  * are met:
21  * 1. Redistributions of source code must retain the above copyright
22  *    notice, this list of conditions and the following disclaimer.
23  * 2. Redistributions in binary form must include information specifying
24  *    that source code for the emulator is freely available and include
25  *    either:
26  *      a) an offer to provide the source code for a nominal distribution
27  *         fee, or
28  *      b) list at least two alternative methods whereby the source
29  *         can be obtained, e.g. a publically accessible bulletin board
30  *         and an anonymous ftp site from which the software can be
31  *         downloaded.
32  * 3. All advertising materials specifically mentioning features or use of
33  *    this emulator must acknowledge that it was developed by W. Metzenthen.
34  * 4. The name of W. Metzenthen may not be used to endorse or promote
35  *    products derived from this software without specific prior written
36  *    permission.
37  *
38  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
39  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
41  * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
42  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
43  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
44  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
45  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
46  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
47  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48  *
49  *
50  * The purpose of this copyright, based upon the Berkeley copyright, is to
51  * ensure that the covered software remains freely available to everyone.
52  *
53  * The software (with necessary differences) is also available, but under
54  * the terms of the GNU copyleft, for the Linux operating system and for
55  * the djgpp ms-dos extender.
56  *
57  * W. Metzenthen   June 1994.
58  *
59  *
60  * $FreeBSD: src/sys/gnu/i386/fpemul/load_store.c,v 1.13 1999/08/28 00:42:52 peter Exp $
61  * $DragonFly: src/sys/i386/gnu/fpemul/Attic/load_store.c,v 1.3 2003/08/07 21:17:20 dillon Exp $
62  *
63  */
64
65 /*---------------------------------------------------------------------------+
66  | Note:                                                                     |
67  |    The file contains code which accesses user memory.                     |
68  |    Emulator static data may change when user memory is accessed, due to   |
69  |    other processes using the emulator while swapping is in progress.      |
70  +---------------------------------------------------------------------------*/
71
72 #include <sys/param.h>
73 #include <sys/proc.h>
74 #include <sys/systm.h>
75 #include <machine/pcb.h>
76
77 #include "fpu_emu.h"
78 #include "fpu_system.h"
79 #include "status_w.h"
80
81
82 #define _NONE_ 0                /* FPU_st0_ptr etc not needed */
83 #define _REG0_ 1                /* Will be storing st(0) */
84 #define _PUSH_ 3                /* Need to check for space to push onto stack */
85 #define _null_ 4                /* Function illegal or not implemented */
86
87 #define pop_0() { pop_ptr->tag = TW_Empty; top++; }
88
89
90 static unsigned char type_table[32] = {
91         _PUSH_, _PUSH_, _PUSH_, _PUSH_,
92         _null_, _null_, _null_, _null_,
93         _REG0_, _REG0_, _REG0_, _REG0_,
94         _REG0_, _REG0_, _REG0_, _REG0_,
95         _NONE_, _null_, _NONE_, _PUSH_,
96         _NONE_, _PUSH_, _null_, _PUSH_,
97         _NONE_, _null_, _NONE_, _REG0_,
98         _NONE_, _REG0_, _NONE_, _REG0_
99 };
100
101 void
102 load_store_instr(char type)
103 {
104         FPU_REG *pop_ptr;       /* We need a version of FPU_st0_ptr which
105                                  * won't change. */
106
107         pop_ptr = NULL;         /* Initialized just to stop compiler warnings. */
108
109
110         switch (type_table[(int) (unsigned) type]) {
111         case _NONE_:
112                 break;
113         case _REG0_:
114                 pop_ptr = &st(0);       /* Some of these instructions pop
115                                          * after storing */
116
117                 FPU_st0_ptr = pop_ptr;  /* Set the global variables. */
118                 FPU_st0_tag = FPU_st0_ptr->tag;
119                 break;
120         case _PUSH_:
121                 {
122                         pop_ptr = &st(-1);
123                         if (pop_ptr->tag != TW_Empty) {
124                                 stack_overflow();
125                                 return;
126                         }
127                         top--;
128                 }
129                 break;
130         case _null_:
131                 Un_impl();
132                 return;
133 #ifdef PARANOID
134         default:
135                 return EXCEPTION(EX_INTERNAL);
136 #endif                          /* PARANOID */
137         }
138
139         switch (type) {
140         case 000:               /* fld m32real */
141                 reg_load_single();
142                 setcc(0);       /* Clear the SW_C1 bit, "other bits undefined" */
143                 reg_move(&FPU_loaded_data, pop_ptr);
144                 break;
145         case 001:               /* fild m32int */
146                 reg_load_int32();
147                 setcc(0);       /* Clear the SW_C1 bit, "other bits undefined" */
148                 reg_move(&FPU_loaded_data, pop_ptr);
149                 break;
150         case 002:               /* fld m64real */
151                 reg_load_double();
152                 setcc(0);       /* Clear the SW_C1 bit, "other bits undefined" */
153                 reg_move(&FPU_loaded_data, pop_ptr);
154                 break;
155         case 003:               /* fild m16int */
156                 reg_load_int16();
157                 setcc(0);       /* Clear the SW_C1 bit, "other bits undefined" */
158                 reg_move(&FPU_loaded_data, pop_ptr);
159                 break;
160         case 010:               /* fst m32real */
161                 reg_store_single();
162                 break;
163         case 011:               /* fist m32int */
164                 reg_store_int32();
165                 break;
166         case 012:               /* fst m64real */
167                 reg_store_double();
168                 break;
169         case 013:               /* fist m16int */
170                 reg_store_int16();
171                 break;
172         case 014:               /* fstp m32real */
173                 if (reg_store_single())
174                         pop_0();/* pop only if the number was actually stored
175                                  * (see the 80486 manual p16-28) */
176                 break;
177         case 015:               /* fistp m32int */
178                 if (reg_store_int32())
179                         pop_0();/* pop only if the number was actually stored
180                                  * (see the 80486 manual p16-28) */
181                 break;
182         case 016:               /* fstp m64real */
183                 if (reg_store_double())
184                         pop_0();/* pop only if the number was actually stored
185                                  * (see the 80486 manual p16-28) */
186                 break;
187         case 017:               /* fistp m16int */
188                 if (reg_store_int16())
189                         pop_0();/* pop only if the number was actually stored
190                                  * (see the 80486 manual p16-28) */
191                 break;
192         case 020:               /* fldenv  m14/28byte */
193                 fldenv();
194                 break;
195         case 022:               /* frstor m94/108byte */
196                 frstor();
197                 break;
198         case 023:               /* fbld m80dec */
199                 reg_load_bcd();
200                 setcc(0);       /* Clear the SW_C1 bit, "other bits undefined" */
201                 reg_move(&FPU_loaded_data, pop_ptr);
202                 break;
203         case 024:               /* fldcw */
204                 REENTRANT_CHECK(OFF);
205                 control_word = fusword((unsigned short *) FPU_data_address);
206                 REENTRANT_CHECK(ON);
207 #ifdef NO_UNDERFLOW_TRAP
208                 if (!(control_word & EX_Underflow)) {
209                         control_word |= EX_Underflow;
210                 }
211 #endif
212                 /* We want no net effect: */
213                 FPU_data_address = (void *) (intptr_t) data_operand_offset;
214                 FPU_entry_eip = ip_offset;      /* We want no net effect */
215                 break;
216         case 025:               /* fld m80real */
217                 reg_load_extended();
218                 setcc(0);       /* Clear the SW_C1 bit, "other bits undefined" */
219                 reg_move(&FPU_loaded_data, pop_ptr);
220                 break;
221         case 027:               /* fild m64int */
222                 reg_load_int64();
223                 setcc(0);       /* Clear the SW_C1 bit, "other bits undefined" */
224                 reg_move(&FPU_loaded_data, pop_ptr);
225                 break;
226         case 030:               /* fstenv  m14/28byte */
227                 fstenv();
228                 /* We want no net effect: */
229                 FPU_data_address = (void *) (intptr_t) data_operand_offset;
230                 FPU_entry_eip = ip_offset;      /* We want no net effect */
231                 break;
232         case 032:               /* fsave */
233                 fsave();
234                 /* We want no net effect: */
235                 FPU_data_address = (void *) (intptr_t) data_operand_offset;
236                 FPU_entry_eip = ip_offset;      /* We want no net effect */
237                 break;
238         case 033:               /* fbstp m80dec */
239                 if (reg_store_bcd())
240                         pop_0();/* pop only if the number was actually stored
241                                  * (see the 80486 manual p16-28) */
242                 break;
243         case 034:               /* fstcw m16int */
244                 REENTRANT_CHECK(OFF);
245 /*                  verify_area(VERIFY_WRITE, FPU_data_address, 2);*/
246                 susword( (short *) FPU_data_address,control_word);
247                 REENTRANT_CHECK(ON);
248                 /* We want no net effect: */
249                 FPU_data_address = (void *) (intptr_t ) data_operand_offset;
250                 FPU_entry_eip = ip_offset;      /* We want no net effect */
251                 break;
252         case 035:               /* fstp m80real */
253                 if (reg_store_extended())
254                         pop_0();/* pop only if the number was actually stored
255                                  * (see the 80486 manual p16-28) */
256                 break;
257         case 036:               /* fstsw m2byte */
258                 status_word &= ~SW_Top;
259                 status_word |= (top & 7) << SW_Top_Shift;
260                 REENTRANT_CHECK(OFF);
261 /*                  verify_area(VERIFY_WRITE, FPU_data_address, 2);*/
262                 susword( (short *) FPU_data_address,status_word);
263                 REENTRANT_CHECK(ON);
264                 /* We want no net effect: */
265                 FPU_data_address = (void *) (intptr_t) data_operand_offset;
266                 FPU_entry_eip = ip_offset;      /* We want no net effect */
267                 break;
268         case 037:               /* fistp m64int */
269                 if (reg_store_int64())
270                         pop_0();/* pop only if the number was actually stored
271                                  * (see the 80486 manual p16-28) */
272                 break;
273         }
274 }