]>
Commit | Line | Data |
---|---|---|
b2450fc5 | 1 | /* Native-dependent code for the i387. |
e2890f08 | 2 | Copyright 2000 Free Software Foundation, Inc. |
b2450fc5 MK |
3 | |
4 | This file is part of GDB. | |
5 | ||
6 | This program is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 2 of the License, or | |
9 | (at your option) any later version. | |
10 | ||
11 | This program is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with this program; if not, write to the Free Software | |
18 | Foundation, Inc., 59 Temple Place - Suite 330, | |
19 | Boston, MA 02111-1307, USA. */ | |
20 | ||
21 | #include "defs.h" | |
22 | #include "inferior.h" | |
23 | #include "value.h" | |
24 | ||
25 | /* FIXME: kettenis/2000-05-21: Right now more than a few i386 targets | |
26 | define their own routines to manage the floating-point registers in | |
27 | GDB's register array. Most (if not all) of these targets use the | |
28 | format used by the "fsave" instruction in their communication with | |
29 | the OS. They should all be converted to use the routines below. */ | |
30 | ||
31 | /* At fsave_offset[REGNO] you'll find the offset to the location in | |
32 | the data structure used by the "fsave" instruction where GDB | |
33 | register REGNO is stored. */ | |
34 | ||
35 | static int fsave_offset[] = | |
36 | { | |
37 | 28 + 0 * FPU_REG_RAW_SIZE, /* FP0_REGNUM through ... */ | |
38 | 28 + 1 * FPU_REG_RAW_SIZE, | |
39 | 28 + 2 * FPU_REG_RAW_SIZE, | |
40 | 28 + 3 * FPU_REG_RAW_SIZE, | |
41 | 28 + 4 * FPU_REG_RAW_SIZE, | |
42 | 28 + 5 * FPU_REG_RAW_SIZE, | |
43 | 28 + 6 * FPU_REG_RAW_SIZE, | |
44 | 28 + 7 * FPU_REG_RAW_SIZE, /* ... FP7_REGNUM. */ | |
45 | 0, /* FCTRL_REGNUM (16 bits). */ | |
46 | 4, /* FSTAT_REGNUM (16 bits). */ | |
47 | 8, /* FTAG_REGNUM (16 bits). */ | |
48 | 16, /* FCS_REGNUM (16 bits). */ | |
49 | 12, /* FCOFF_REGNUM. */ | |
50 | 24, /* FDS_REGNUM. */ | |
51 | 20, /* FDOFF_REGNUM. */ | |
52 | 18 /* FOP_REGNUM (bottom 11 bits). */ | |
53 | }; | |
54 | ||
55 | #define FSAVE_ADDR(fsave, regnum) (fsave + fsave_offset[regnum - FP0_REGNUM]) | |
56 | \f | |
57 | ||
58 | /* Fill GDB's register array with the floating-point register values | |
59 | in *FSAVE. This function masks off any of the reserved | |
60 | bits in *FSAVE. */ | |
61 | ||
62 | void | |
63 | i387_supply_fsave (char *fsave) | |
64 | { | |
65 | int i; | |
66 | ||
67 | for (i = FP0_REGNUM; i <= LAST_FPU_CTRL_REGNUM; i++) | |
68 | { | |
69 | /* Most of the FPU control registers occupy only 16 bits in | |
70 | the fsave area. Give those a special treatment. */ | |
71 | if (i >= FIRST_FPU_CTRL_REGNUM | |
72 | && i != FCOFF_REGNUM && i != FDOFF_REGNUM) | |
73 | { | |
e2890f08 | 74 | unsigned int val = *(unsigned short *) (FSAVE_ADDR (fsave, i)); |
b2450fc5 MK |
75 | |
76 | if (i == FOP_REGNUM) | |
77 | { | |
78 | val &= ((1 << 11) - 1); | |
79 | supply_register (i, (char *) &val); | |
80 | } | |
81 | else | |
82 | supply_register (i, (char *) &val); | |
83 | } | |
84 | else | |
85 | supply_register (i, FSAVE_ADDR (fsave, i)); | |
86 | } | |
87 | } | |
88 | ||
89 | /* Fill register REGNO (if it is a floating-point register) in *FSAVE | |
90 | with the value in GDB's register array. If REGNO is -1, do this | |
91 | for all registers. This function doesn't touch any of the reserved | |
92 | bits in *FSAVE. */ | |
93 | ||
94 | void | |
95 | i387_fill_fsave (char *fsave, int regno) | |
96 | { | |
97 | int i; | |
98 | ||
99 | for (i = FP0_REGNUM; i <= LAST_FPU_CTRL_REGNUM; i++) | |
100 | if (regno == -1 || regno == i) | |
101 | { | |
102 | /* Most of the FPU control registers occupy only 16 bits in | |
103 | the fsave area. Give those a special treatment. */ | |
104 | if (i >= FIRST_FPU_CTRL_REGNUM | |
105 | && i != FCOFF_REGNUM && i != FDOFF_REGNUM) | |
106 | { | |
107 | if (i == FOP_REGNUM) | |
108 | { | |
109 | unsigned short oldval, newval; | |
110 | ||
111 | /* The opcode occupies only 11 bits. */ | |
112 | oldval = (*(unsigned short *) (FSAVE_ADDR (fsave, i))); | |
113 | newval = *(unsigned short *) ®isters[REGISTER_BYTE (i)]; | |
114 | newval &= ((1 << 11) - 1); | |
115 | newval |= oldval & ~((1 << 11) - 1); | |
116 | memcpy (FSAVE_ADDR (fsave, i), &newval, 2); | |
117 | } | |
118 | else | |
119 | memcpy (FSAVE_ADDR (fsave, i), ®isters[REGISTER_BYTE (i)], 2); | |
120 | } | |
121 | else | |
122 | memcpy (FSAVE_ADDR (fsave, i), ®isters[REGISTER_BYTE (i)], | |
123 | REGISTER_RAW_SIZE (i)); | |
124 | } | |
125 | } | |
e2890f08 MK |
126 | \f |
127 | ||
128 | /* At fxsave_offset[REGNO] you'll find the offset to the location in | |
129 | the data structure used by the "fxsave" instruction where GDB | |
130 | register REGNO is stored. */ | |
131 | ||
132 | static int fxsave_offset[] = | |
133 | { | |
134 | 32, /* FP0_REGNUM through ... */ | |
135 | 48, | |
136 | 64, | |
137 | 80, | |
138 | 96, | |
139 | 112, | |
140 | 128, | |
141 | 144, /* ... FP7_REGNUM (80 bits each). */ | |
142 | 0, /* FCTRL_REGNUM (16 bits). */ | |
143 | 2, /* FSTAT_REGNUM (16 bits). */ | |
144 | 4, /* FTAG_REGNUM (16 bits). */ | |
145 | 12, /* FCS_REGNUM (16 bits). */ | |
146 | 8, /* FCOFF_REGNUM. */ | |
147 | 20, /* FDS_REGNUM (16 bits). */ | |
148 | 16, /* FDOFF_REGNUM. */ | |
149 | 6, /* FOP_REGNUM (bottom 11 bits). */ | |
150 | 160, /* XMM0_REGNUM through ... */ | |
151 | 176, | |
152 | 192, | |
153 | 208, | |
154 | 224, | |
155 | 240, | |
156 | 256, | |
157 | 272, /* ... XMM7_REGNUM (128 bits each). */ | |
158 | 24, /* MXCSR_REGNUM. */ | |
159 | }; | |
160 | ||
161 | #define FXSAVE_ADDR(fxsave, regnum) \ | |
162 | (fxsave + fxsave_offset[regnum - FP0_REGNUM]) | |
163 | ||
164 | static int i387_tag (unsigned char *raw); | |
165 | \f | |
166 | ||
167 | /* Fill GDB's register array with the floating-point and SSE register | |
168 | values in *FXSAVE. This function masks off any of the reserved | |
169 | bits in *FXSAVE. */ | |
170 | ||
171 | void | |
172 | i387_supply_fxsave (char *fxsave) | |
173 | { | |
174 | int i; | |
175 | ||
176 | for (i = FP0_REGNUM; i <= MXCSR_REGNUM; i++) | |
177 | { | |
178 | /* Most of the FPU control registers occupy only 16 bits in | |
179 | the fxsave area. Give those a special treatment. */ | |
180 | if (i >= FIRST_FPU_CTRL_REGNUM && i < XMM0_REGNUM | |
181 | && i != FCOFF_REGNUM && i != FDOFF_REGNUM) | |
182 | { | |
183 | unsigned long val = *(unsigned short *) (FXSAVE_ADDR (fxsave, i)); | |
184 | ||
185 | if (i == FOP_REGNUM) | |
186 | { | |
187 | val &= ((1 << 11) - 1); | |
188 | supply_register (i, (char *) &val); | |
189 | } | |
190 | else if (i== FTAG_REGNUM) | |
191 | { | |
192 | /* The fxsave area contains a simplified version of the | |
193 | tag word. We have to look at the actual 80-bit FP | |
194 | data to recreate the traditional i387 tag word. */ | |
195 | ||
196 | unsigned long ftag = 0; | |
197 | unsigned long fstat; | |
198 | int fpreg; | |
199 | int top; | |
200 | ||
201 | fstat = *(unsigned short *) (FXSAVE_ADDR (fxsave, FSTAT_REGNUM)); | |
202 | top = ((fstat >> 11) & 0x111); | |
203 | ||
204 | for (fpreg = 7; fpreg >= 0; fpreg--) | |
205 | { | |
206 | int tag = 0x11; | |
207 | ||
208 | if (val & (1 << fpreg)) | |
209 | { | |
210 | int regnum = (fpreg + 8 - top) % 8 + FP0_REGNUM; | |
211 | tag = i387_tag (FXSAVE_ADDR (fxsave, regnum)); | |
212 | } | |
213 | ||
214 | ftag |= tag << (2 * fpreg); | |
215 | } | |
216 | supply_register (i, (char *) &ftag); | |
217 | } | |
218 | else | |
219 | supply_register (i, (char *) &val); | |
220 | } | |
221 | else | |
222 | supply_register (i, FXSAVE_ADDR (fxsave, i)); | |
223 | } | |
224 | } | |
225 | ||
226 | /* Fill register REGNO (if it is a floating-point or SSE register) in | |
227 | *FXSAVE with the value in GDB's register array. If REGNO is -1, do | |
228 | this for all registers. This function doesn't touch any of the | |
229 | reserved bits in *FXSAVE. */ | |
230 | ||
231 | void | |
232 | i387_fill_fxsave (char *fxsave, int regno) | |
233 | { | |
234 | int i; | |
235 | ||
236 | for (i = FP0_REGNUM; i <= MXCSR_REGNUM; i++) | |
237 | if (regno == -1 || regno == i) | |
238 | { | |
239 | /* Most of the FPU control registers occupy only 16 bits in | |
240 | the fxsave area. Give those a special treatment. */ | |
241 | if (i >= FIRST_FPU_CTRL_REGNUM && i < XMM0_REGNUM | |
242 | && i != FCOFF_REGNUM && i != FDOFF_REGNUM) | |
243 | { | |
244 | if (i == FOP_REGNUM) | |
245 | { | |
246 | unsigned short oldval, newval; | |
247 | ||
248 | /* The opcode occupies only 11 bits. */ | |
249 | oldval = (*(unsigned short *) (FXSAVE_ADDR (fxsave, i))); | |
250 | newval = *(unsigned short *) ®isters[REGISTER_BYTE (i)]; | |
251 | newval &= ((1 << 11) - 1); | |
252 | newval |= oldval & ~((1 << 11) - 1); | |
253 | memcpy (FXSAVE_ADDR (fxsave, i), &newval, 2); | |
254 | } | |
255 | else if (i == FTAG_REGNUM) | |
256 | { | |
257 | /* Converting back is much easier. */ | |
258 | ||
259 | unsigned char val = 0; | |
260 | unsigned short ftag; | |
261 | int fpreg; | |
262 | ||
263 | ftag = *(unsigned short *) ®isters[REGISTER_BYTE (i)]; | |
264 | ||
265 | for (fpreg = 7; fpreg >= 0; fpreg--) | |
266 | { | |
267 | int tag = (ftag >> (fpreg * 2)) & 0x11; | |
268 | ||
269 | if (tag != 0x11) | |
270 | val |= (1 << fpreg); | |
271 | } | |
272 | ||
273 | memcpy (FXSAVE_ADDR (fxsave, i), &val, 2); | |
274 | } | |
275 | else | |
276 | memcpy (FXSAVE_ADDR (fxsave, i), | |
277 | ®isters[REGISTER_BYTE (i)], 2); | |
278 | } | |
279 | else | |
280 | memcpy (FXSAVE_ADDR (fxsave, i), ®isters[REGISTER_BYTE (i)], | |
281 | REGISTER_RAW_SIZE (i)); | |
282 | } | |
283 | } | |
284 | ||
285 | /* Recreate the FTW (tag word) valid bits from the 80-bit FP data in | |
286 | *RAW. */ | |
287 | ||
288 | static int | |
289 | i387_tag (unsigned char *raw) | |
290 | { | |
291 | int integer; | |
292 | unsigned int exponent; | |
293 | unsigned long fraction[2]; | |
294 | ||
295 | integer = raw[7] & 0x80; | |
296 | exponent = (((raw[9] & 0x7f) << 8) | raw[8]); | |
297 | fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]); | |
298 | fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16) | |
299 | | (raw[5] << 8) | raw[4]); | |
300 | ||
301 | if (exponent == 0x7fff) | |
302 | { | |
303 | /* Special. */ | |
304 | return (0x10); | |
305 | } | |
306 | else if (exponent == 0x0000) | |
307 | { | |
308 | if (integer) | |
309 | { | |
310 | /* Valid. */ | |
311 | return (0x00); | |
312 | } | |
313 | else | |
314 | { | |
315 | /* Special. */ | |
316 | return (0x10); | |
317 | } | |
318 | } | |
319 | else | |
320 | { | |
321 | if (fraction[0] == 0x0000 && fraction[1] == 0x0000 && !integer) | |
322 | { | |
323 | /* Zero. */ | |
324 | return (0x01); | |
325 | } | |
326 | else | |
327 | { | |
328 | /* Special. */ | |
329 | return (0x10); | |
330 | } | |
331 | } | |
332 | } |