* gdbint.texinfo (Host Definition): Remove description of
[deliverable/binutils-gdb.git] / gdb / i387-nat.c
CommitLineData
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
38static 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
65void
66i387_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
91void
92i387_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
105void
f31e928c 106i387_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 *) &registers[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), &registers[REGISTER_BYTE (i)], 2);
131 }
132 else
133 memcpy (FSAVE_ADDR (fsave, i), &registers[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
143static 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
175static 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
182void
183i387_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));
128437e6 213 top = ((fstat >> 11) & 0x7);
e2890f08
MK
214
215 for (fpreg = 7; fpreg >= 0; fpreg--)
216 {
128437e6 217 int tag;
e2890f08
MK
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 }
128437e6
DH
224 else
225 tag = 3; /* Empty */
e2890f08
MK
226
227 ftag |= tag << (2 * fpreg);
228 }
229 supply_register (i, (char *) &ftag);
230 }
231 else
232 supply_register (i, (char *) &val);
233 }
234 else
235 supply_register (i, FXSAVE_ADDR (fxsave, i));
236 }
237}
238
f31e928c
MK
239/* Fill register REGNUM (if it is a floating-point or SSE register) in
240 *FXSAVE with the value in GDB's register array. If REGNUM is -1, do
e2890f08
MK
241 this for all registers. This function doesn't touch any of the
242 reserved bits in *FXSAVE. */
243
244void
f31e928c 245i387_fill_fxsave (char *fxsave, int regnum)
e2890f08
MK
246{
247 int i;
248
249 for (i = FP0_REGNUM; i <= MXCSR_REGNUM; i++)
f31e928c 250 if (regnum == -1 || regnum == i)
e2890f08
MK
251 {
252 /* Most of the FPU control registers occupy only 16 bits in
253 the fxsave area. Give those a special treatment. */
254 if (i >= FIRST_FPU_CTRL_REGNUM && i < XMM0_REGNUM
255 && i != FCOFF_REGNUM && i != FDOFF_REGNUM)
256 {
257 if (i == FOP_REGNUM)
258 {
259 unsigned short oldval, newval;
260
261 /* The opcode occupies only 11 bits. */
262 oldval = (*(unsigned short *) (FXSAVE_ADDR (fxsave, i)));
263 newval = *(unsigned short *) &registers[REGISTER_BYTE (i)];
264 newval &= ((1 << 11) - 1);
265 newval |= oldval & ~((1 << 11) - 1);
266 memcpy (FXSAVE_ADDR (fxsave, i), &newval, 2);
267 }
268 else if (i == FTAG_REGNUM)
269 {
270 /* Converting back is much easier. */
271
272 unsigned char val = 0;
273 unsigned short ftag;
274 int fpreg;
275
276 ftag = *(unsigned short *) &registers[REGISTER_BYTE (i)];
277
278 for (fpreg = 7; fpreg >= 0; fpreg--)
279 {
128437e6 280 int tag = (ftag >> (fpreg * 2)) & 3;
e2890f08 281
128437e6
DH
282 if (tag != 3)
283 val |= (1 << (fpreg * 2));
e2890f08
MK
284 }
285
286 memcpy (FXSAVE_ADDR (fxsave, i), &val, 2);
287 }
288 else
289 memcpy (FXSAVE_ADDR (fxsave, i),
290 &registers[REGISTER_BYTE (i)], 2);
291 }
292 else
293 memcpy (FXSAVE_ADDR (fxsave, i), &registers[REGISTER_BYTE (i)],
294 REGISTER_RAW_SIZE (i));
295 }
296}
297
298/* Recreate the FTW (tag word) valid bits from the 80-bit FP data in
299 *RAW. */
300
301static int
302i387_tag (unsigned char *raw)
303{
304 int integer;
305 unsigned int exponent;
306 unsigned long fraction[2];
307
308 integer = raw[7] & 0x80;
309 exponent = (((raw[9] & 0x7f) << 8) | raw[8]);
310 fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]);
311 fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16)
312 | (raw[5] << 8) | raw[4]);
313
314 if (exponent == 0x7fff)
315 {
316 /* Special. */
128437e6 317 return (2);
e2890f08
MK
318 }
319 else if (exponent == 0x0000)
320 {
128437e6 321 if (fraction[0] == 0x0000 && fraction[1] == 0x0000 && !integer)
e2890f08 322 {
128437e6
DH
323 /* Zero. */
324 return (1);
e2890f08
MK
325 }
326 else
327 {
328 /* Special. */
128437e6 329 return (2);
e2890f08
MK
330 }
331 }
332 else
333 {
128437e6 334 if (integer)
e2890f08 335 {
128437e6
DH
336 /* Valid. */
337 return (0);
e2890f08
MK
338 }
339 else
340 {
341 /* Special. */
128437e6 342 return (2);
e2890f08
MK
343 }
344 }
345}
This page took 0.180636 seconds and 4 git commands to generate.