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