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