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