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 | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
8 | Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
9 | |
10 | |
11 +---------------------------------------------------------------------------*/
12
13 /*---------------------------------------------------------------------------+
14 | Note: |
15 | The file contains code which accesses user memory. |
16 | Emulator static data may change when user memory is accessed, due to |
17 | other processes using the emulator while swapping is in progress. |
18 +---------------------------------------------------------------------------*/
19
20 #include <asm/segment.h>
21
22 #include "fpu_system.h"
23 #include "exception.h"
24 #include "fpu_emu.h"
25 #include "status_w.h"
26
27
28 #define _NONE_ 0 /* FPU_st0_ptr etc not needed */
29 #define _REG0_ 1 /* Will be storing st(0) */
30 #define _PUSH_ 3 /* Need to check for space to push onto stack */
31 #define _null_ 4 /* Function illegal or not implemented */
32
33 #define pop_0() { pop_ptr->tag = TW_Empty; top++; }
34
35
36 static unsigned char type_table[32] = {
37 _PUSH_, _PUSH_, _PUSH_, _PUSH_,
38 _null_, _null_, _null_, _null_,
39 _REG0_, _REG0_, _REG0_, _REG0_,
40 _REG0_, _REG0_, _REG0_, _REG0_,
41 _null_, _null_, _NONE_, _PUSH_,
42 _NONE_, _PUSH_, _null_, _PUSH_,
43 _null_, _null_, _NONE_, _REG0_,
44 _NONE_, _REG0_, _NONE_, _REG0_
45 };
46
47 void load_store_instr(char type)
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
48 {
49 FPU_REG *pop_ptr; /* We need a version of FPU_st0_ptr which won't change. */
50
51 pop_ptr = NULL;
52 switch ( type_table[(int) (unsigned) type] )
53 {
54 case _NONE_:
55 break;
56 case _REG0_:
57 pop_ptr = &st(0); /* Some of these instructions pop after
58 storing */
59
60 FPU_st0_ptr = pop_ptr; /* Set the global variables. */
61 FPU_st0_tag = FPU_st0_ptr->tag;
62 break;
63 case _PUSH_:
64 {
65 pop_ptr = &st(-1);
66 if ( pop_ptr->tag != TW_Empty )
67 { stack_overflow(); return; }
68 top--;
69 }
70 break;
71 case _null_:
72 return Un_impl();
73 #ifdef PARANOID
74 default:
75 return EXCEPTION(EX_INTERNAL);
76 #endif PARANOID
77 }
78
79 switch ( type )
80 {
81 case 000: /* fld m32real */
82 reg_load_single();
83 reg_move(&FPU_loaded_data, pop_ptr);
84 break;
85 case 001: /* fild m32int */
86 reg_load_int32();
87 reg_move(&FPU_loaded_data, pop_ptr);
88 break;
89 case 002: /* fld m64real */
90 reg_load_double();
91 reg_move(&FPU_loaded_data, pop_ptr);
92 break;
93 case 003: /* fild m16int */
94 reg_load_int16();
95 reg_move(&FPU_loaded_data, pop_ptr);
96 break;
97 case 010: /* fst m32real */
98 reg_store_single();
99 break;
100 case 011: /* fist m32int */
101 reg_store_int32();
102 break;
103 case 012: /* fst m64real */
104 reg_store_double();
105 break;
106 case 013: /* fist m16int */
107 reg_store_int16();
108 break;
109 case 014: /* fstp m32real */
110 if ( reg_store_single() )
111 pop_0(); /* pop only if the number was actually stored
112 (see the 80486 manual p16-28) */
113 break;
114 case 015: /* fistp m32int */
115 if ( reg_store_int32() )
116 pop_0(); /* pop only if the number was actually stored
117 (see the 80486 manual p16-28) */
118 break;
119 case 016: /* fstp m64real */
120 if ( reg_store_double() )
121 pop_0(); /* pop only if the number was actually stored
122 (see the 80486 manual p16-28) */
123 break;
124 case 017: /* fistp m16int */
125 if ( reg_store_int16() )
126 pop_0(); /* pop only if the number was actually stored
127 (see the 80486 manual p16-28) */
128 break;
129 case 020: /* fldenv m14/28byte */
130 fldenv();
131 break;
132 case 022: /* frstor m94/108byte */
133 frstor();
134 break;
135 case 023: /* fbld m80dec */
136 reg_load_bcd();
137 reg_move(&FPU_loaded_data, pop_ptr);
138 break;
139 case 024: /* fldcw */
140 RE_ENTRANT_CHECK_OFF
141 control_word = get_fs_word((unsigned short *) FPU_data_address);
142 RE_ENTRANT_CHECK_ON
143 #ifdef NO_UNDERFLOW_TRAP
144 if ( !(control_word & EX_Underflow) )
145 {
146 control_word |= EX_Underflow;
147 }
148 #endif
149 FPU_data_address = (void *)data_operand_offset; /* We want no net effect */
150 FPU_entry_eip = ip_offset; /* We want no net effect */
151 break;
152 case 025: /* fld m80real */
153 reg_load_extended();
154 reg_move(&FPU_loaded_data, pop_ptr);
155 break;
156 case 027: /* fild m64int */
157 reg_load_int64();
158 reg_move(&FPU_loaded_data, pop_ptr);
159 break;
160 case 030: /* fstenv m14/28byte */
161 fstenv();
162 FPU_data_address = (void *)data_operand_offset; /* We want no net effect */
163 FPU_entry_eip = ip_offset; /* We want no net effect */
164 break;
165 case 032: /* fsave */
166 fsave();
167 FPU_data_address = (void *)data_operand_offset; /* We want no net effect */
168 FPU_entry_eip = ip_offset; /* We want no net effect */
169 break;
170 case 033: /* fbstp m80dec */
171 if ( reg_store_bcd() )
172 pop_0(); /* pop only if the number was actually stored
173 (see the 80486 manual p16-28) */
174 break;
175 case 034: /* fstcw m16int */
176 RE_ENTRANT_CHECK_OFF
177 verify_area(FPU_data_address,2);
178 put_fs_word(control_word, (short *) FPU_data_address);
179 RE_ENTRANT_CHECK_ON
180 FPU_data_address = (void *)data_operand_offset; /* We want no net effect */
181 FPU_entry_eip = ip_offset; /* We want no net effect */
182 break;
183 case 035: /* fstp m80real */
184 if ( reg_store_extended() )
185 pop_0(); /* pop only if the number was actually stored
186 (see the 80486 manual p16-28) */
187 break;
188 case 036: /* fstsw m2byte */
189 status_word &= ~SW_TOP;
190 status_word |= (top&7) << SW_TOPS;
191 RE_ENTRANT_CHECK_OFF
192 verify_area(FPU_data_address,2);
193 put_fs_word(status_word,(short *) FPU_data_address);
194 RE_ENTRANT_CHECK_ON
195 FPU_data_address = (void *)data_operand_offset; /* We want no net effect */
196 FPU_entry_eip = ip_offset; /* We want no net effect */
197 break;
198 case 037: /* fistp m64int */
199 if ( reg_store_int64() )
200 pop_0(); /* pop only if the number was actually stored
201 (see the 80486 manual p16-28) */
202 break;
203 }
204 }