#include "defs.h"
#include "inferior.h"
#include "value.h"
#include "regcache.h"
#include "i387-nat.h"
#include "i386-tdep.h"
static int fsave_offset[] =
{
28 + 0 * FPU_REG_RAW_SIZE,
28 + 1 * FPU_REG_RAW_SIZE,
28 + 2 * FPU_REG_RAW_SIZE,
28 + 3 * FPU_REG_RAW_SIZE,
28 + 4 * FPU_REG_RAW_SIZE,
28 + 5 * FPU_REG_RAW_SIZE,
28 + 6 * FPU_REG_RAW_SIZE,
28 + 7 * FPU_REG_RAW_SIZE,
0,
4,
8,
16,
12,
24,
20,
18
};
#define FSAVE_ADDR(fsave, regnum) (fsave + fsave_offset[regnum - FP0_REGNUM])
void
i387_supply_register (int regnum, char *fsave)
{
if (regnum >= FPC_REGNUM
&& regnum != FIOFF_REGNUM && regnum != FOOFF_REGNUM)
{
unsigned int val = *(unsigned short *) (FSAVE_ADDR (fsave, regnum));
if (regnum == FOP_REGNUM)
{
val &= ((1 << 11) - 1);
supply_register (regnum, (char *) &val);
}
else
supply_register (regnum, (char *) &val);
}
else
supply_register (regnum, FSAVE_ADDR (fsave, regnum));
}
void
i387_supply_fsave (char *fsave)
{
int i;
for (i = FP0_REGNUM; i < XMM0_REGNUM; i++)
i387_supply_register (i, fsave);
}
void
i387_fill_fsave (char *fsave, int regnum)
{
int i;
for (i = FP0_REGNUM; i < XMM0_REGNUM; i++)
if (regnum == -1 || regnum == i)
{
if (i >= FPC_REGNUM
&& i != FIOFF_REGNUM && i != FOOFF_REGNUM)
{
if (i == FOP_REGNUM)
{
unsigned short oldval, newval;
oldval = (*(unsigned short *) (FSAVE_ADDR (fsave, i)));
newval = *(unsigned short *) ®isters[REGISTER_BYTE (i)];
newval &= ((1 << 11) - 1);
newval |= oldval & ~((1 << 11) - 1);
memcpy (FSAVE_ADDR (fsave, i), &newval, 2);
}
else
memcpy (FSAVE_ADDR (fsave, i), ®isters[REGISTER_BYTE (i)], 2);
}
else
memcpy (FSAVE_ADDR (fsave, i), ®isters[REGISTER_BYTE (i)],
REGISTER_RAW_SIZE (i));
}
}
static int fxsave_offset[] =
{
32,
48,
64,
80,
96,
112,
128,
144,
0,
2,
4,
12,
8,
20,
16,
6,
160,
176,
192,
208,
224,
240,
256,
272,
24,
};
#define FXSAVE_ADDR(fxsave, regnum) \
(fxsave + fxsave_offset[regnum - FP0_REGNUM])
static int i387_tag (unsigned char *raw);
void
i387_supply_fxsave (char *fxsave)
{
int i;
for (i = FP0_REGNUM; i <= MXCSR_REGNUM; i++)
{
if (i >= FPC_REGNUM && i < XMM0_REGNUM
&& i != FIOFF_REGNUM && i != FOOFF_REGNUM)
{
unsigned long val = *(unsigned short *) (FXSAVE_ADDR (fxsave, i));
if (i == FOP_REGNUM)
{
val &= ((1 << 11) - 1);
supply_register (i, (char *) &val);
}
else if (i== FTAG_REGNUM)
{
unsigned long ftag = 0;
unsigned long fstat;
int fpreg;
int top;
fstat = *(unsigned short *) (FXSAVE_ADDR (fxsave, FSTAT_REGNUM));
top = ((fstat >> 11) & 0x7);
for (fpreg = 7; fpreg >= 0; fpreg--)
{
int tag;
if (val & (1 << fpreg))
{
int regnum = (fpreg + 8 - top) % 8 + FP0_REGNUM;
tag = i387_tag (FXSAVE_ADDR (fxsave, regnum));
}
else
tag = 3;
ftag |= tag << (2 * fpreg);
}
supply_register (i, (char *) &ftag);
}
else
supply_register (i, (char *) &val);
}
else
supply_register (i, FXSAVE_ADDR (fxsave, i));
}
}
void
i387_fill_fxsave (char *fxsave, int regnum)
{
int i;
for (i = FP0_REGNUM; i <= MXCSR_REGNUM; i++)
if (regnum == -1 || regnum == i)
{
if (i >= FPC_REGNUM && i < XMM0_REGNUM
&& i != FIOFF_REGNUM && i != FDOFF_REGNUM)
{
if (i == FOP_REGNUM)
{
unsigned short oldval, newval;
oldval = (*(unsigned short *) (FXSAVE_ADDR (fxsave, i)));
newval = *(unsigned short *) ®isters[REGISTER_BYTE (i)];
newval &= ((1 << 11) - 1);
newval |= oldval & ~((1 << 11) - 1);
memcpy (FXSAVE_ADDR (fxsave, i), &newval, 2);
}
else if (i == FTAG_REGNUM)
{
unsigned short val = 0;
unsigned short ftag;
int fpreg;
ftag = *(unsigned short *) ®isters[REGISTER_BYTE (i)];
for (fpreg = 7; fpreg >= 0; fpreg--)
{
int tag = (ftag >> (fpreg * 2)) & 3;
if (tag != 3)
val |= (1 << fpreg);
}
memcpy (FXSAVE_ADDR (fxsave, i), &val, 2);
}
else
memcpy (FXSAVE_ADDR (fxsave, i),
®isters[REGISTER_BYTE (i)], 2);
}
else
memcpy (FXSAVE_ADDR (fxsave, i), ®isters[REGISTER_BYTE (i)],
REGISTER_RAW_SIZE (i));
}
}
static int
i387_tag (unsigned char *raw)
{
int integer;
unsigned int exponent;
unsigned long fraction[2];
integer = raw[7] & 0x80;
exponent = (((raw[9] & 0x7f) << 8) | raw[8]);
fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]);
fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16)
| (raw[5] << 8) | raw[4]);
if (exponent == 0x7fff)
{
return (2);
}
else if (exponent == 0x0000)
{
if (fraction[0] == 0x0000 && fraction[1] == 0x0000 && !integer)
{
return (1);
}
else
{
return (2);
}
}
else
{
if (integer)
{
return (0);
}
else
{
return (2);
}
}
}