Revision 927f621e
b/Makefile | ||
---|---|---|
8 | 8 |
LIBS= |
9 | 9 |
CC=gcc |
10 | 10 |
DEFINES=-DHAVE_BYTESWAP_H |
11 |
OP_CFLAGS=$(CFLAGS) -malign-functions=0 -mpreferred-stack-boundary=2 |
|
11 | 12 |
endif |
12 | 13 |
|
13 | 14 |
ifeq ($(ARCH),ppc) |
... | ... | |
24 | 25 |
LDFLAGS=-static -g -nostdlib $(CRT1) $(CRTI) $(CRTBEGIN) |
25 | 26 |
LIBS=-L$(LIBS_DIR) -ltinyc -lgcc $(CRTEND) $(CRTN) |
26 | 27 |
DEFINES=-Dsocklen_t=int |
28 |
OP_CFLAGS=$(CFLAGS) |
|
27 | 29 |
endif |
28 | 30 |
|
29 | 31 |
######################################################### |
... | ... | |
31 | 33 |
DEFINES+=-D_GNU_SOURCE -DGEMU -DDOSEMU -DNO_TRACE_MSGS |
32 | 34 |
DEFINES+=-DCONFIG_PREFIX=\"/usr/local\" |
33 | 35 |
LDSCRIPT=$(ARCH).ld |
34 |
LIBS+=-ldl |
|
36 |
LIBS+=-ldl -lm
|
|
35 | 37 |
|
36 | 38 |
OBJS= i386/fp87.o i386/interp_main.o i386/interp_modrm.o i386/interp_16_32.o \ |
37 | 39 |
i386/interp_32_16.o i386/interp_32_32.o i386/emu-utils.o \ |
... | ... | |
67 | 69 |
./dyngen -o $@ $< |
68 | 70 |
|
69 | 71 |
op-i386.o: op-i386.c opreg_template.h ops_template.h |
70 |
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< |
|
72 |
$(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $<
|
|
71 | 73 |
|
72 | 74 |
%.o: %.c |
73 | 75 |
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< |
b/TODO | ||
---|---|---|
3 | 3 |
- threads |
4 | 4 |
- fix printf for doubles (fp87.c bug ?) |
5 | 5 |
- make it self runnable (use same trick as ld.so : include its own relocator and libc) |
6 |
- better FPU comparisons (ucom/com) |
b/cpu-i386.h | ||
---|---|---|
75 | 75 |
CC_OP_NB, |
76 | 76 |
}; |
77 | 77 |
|
78 |
#ifdef __i386__ |
|
79 |
#define USE_X86LDOUBLE |
|
80 |
#endif |
|
81 |
|
|
82 |
#ifdef USE_X86LDOUBLE |
|
83 |
typedef long double CPU86_LDouble; |
|
84 |
#else |
|
85 |
typedef double CPU86_LDouble; |
|
86 |
#endif |
|
87 |
|
|
78 | 88 |
typedef struct CPU86State { |
79 | 89 |
/* standard registers */ |
80 | 90 |
uint32_t regs[8]; |
... | ... | |
91 | 101 |
uint8_t *segs_base[6]; |
92 | 102 |
uint32_t segs[6]; |
93 | 103 |
|
104 |
/* FPU state */ |
|
105 |
CPU86_LDouble fpregs[8]; |
|
106 |
uint8_t fptags[8]; /* 0 = valid, 1 = empty */ |
|
107 |
unsigned int fpstt; /* top of stack index */ |
|
108 |
unsigned int fpus; |
|
109 |
unsigned int fpuc; |
|
110 |
|
|
94 | 111 |
/* emulator internal variables */ |
95 | 112 |
uint32_t t0; /* temporary t0 storage */ |
96 | 113 |
uint32_t t1; /* temporary t1 storage */ |
97 | 114 |
uint32_t a0; /* temporary a0 storage (address) */ |
115 |
CPU86_LDouble ft0; |
|
98 | 116 |
} CPU86State; |
99 | 117 |
|
100 | 118 |
static inline int ldub(void *ptr) |
... | ... | |
122 | 140 |
return *(uint32_t *)ptr; |
123 | 141 |
} |
124 | 142 |
|
143 |
static inline uint64_t ldq(void *ptr) |
|
144 |
{ |
|
145 |
return *(uint64_t *)ptr; |
|
146 |
} |
|
125 | 147 |
|
126 | 148 |
static inline void stb(void *ptr, int v) |
127 | 149 |
{ |
... | ... | |
138 | 160 |
*(uint32_t *)ptr = v; |
139 | 161 |
} |
140 | 162 |
|
163 |
static inline void stq(void *ptr, int v) |
|
164 |
{ |
|
165 |
*(uint64_t *)ptr = v; |
|
166 |
} |
|
167 |
|
|
168 |
/* float access */ |
|
169 |
|
|
170 |
static inline float ldfl(void *ptr) |
|
171 |
{ |
|
172 |
return *(float *)ptr; |
|
173 |
} |
|
174 |
|
|
175 |
static inline double ldfq(void *ptr) |
|
176 |
{ |
|
177 |
return *(double *)ptr; |
|
178 |
} |
|
179 |
|
|
180 |
static inline void stfl(void *ptr, float v) |
|
181 |
{ |
|
182 |
*(float *)ptr = v; |
|
183 |
} |
|
184 |
|
|
185 |
static inline void stfq(void *ptr, double v) |
|
186 |
{ |
|
187 |
*(double *)ptr = v; |
|
188 |
} |
|
189 |
|
|
190 |
#ifndef IN_OP_I386 |
|
141 | 191 |
void port_outb(int addr, int val); |
142 | 192 |
void port_outw(int addr, int val); |
143 | 193 |
void port_outl(int addr, int val); |
144 | 194 |
int port_inb(int addr); |
145 | 195 |
int port_inw(int addr); |
146 | 196 |
int port_inl(int addr); |
197 |
#endif |
|
147 | 198 |
|
148 | 199 |
#endif /* CPU_I386_H */ |
b/dyngen.c | ||
---|---|---|
243 | 243 |
if (n >= MAX_ARGS) |
244 | 244 |
error("too many arguments in %s", name); |
245 | 245 |
args_present[n - 1] = 1; |
246 |
} else { |
|
247 |
fprintf(outfile, "extern char %s;\n", sym_name); |
|
246 | 248 |
} |
247 | 249 |
} |
248 | 250 |
} |
... | ... | |
257 | 259 |
if (n >= MAX_ARGS) |
258 | 260 |
error("too many arguments in %s", name); |
259 | 261 |
args_present[n - 1] = 1; |
262 |
} else { |
|
263 |
fprintf(outfile, "extern char %s;\n", sym_name); |
|
260 | 264 |
} |
261 | 265 |
} |
262 | 266 |
} |
b/op-i386.c | ||
---|---|---|
66 | 66 |
|
67 | 67 |
#define CC_SRC (env->cc_src) |
68 | 68 |
#define CC_DST (env->cc_dst) |
69 |
#define CC_OP (env->cc_op) |
|
69 |
#define CC_OP (env->cc_op) |
|
70 |
|
|
71 |
/* float macros */ |
|
72 |
#define FT0 (env->ft0) |
|
73 |
#define ST0 (env->fpregs[env->fpstt]) |
|
74 |
#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7]) |
|
75 |
#define ST1 ST(1) |
|
70 | 76 |
|
71 | 77 |
extern int __op_param1, __op_param2, __op_param3; |
72 | 78 |
#define PARAM1 ((long)(&__op_param1)) |
... | ... | |
133 | 139 |
6, 7, 8, 0, 1, 2, 3, 4, |
134 | 140 |
}; |
135 | 141 |
|
142 |
#ifdef USE_X86LDOUBLE |
|
143 |
/* an array of Intel 80-bit FP constants, to be loaded via integer ops */ |
|
144 |
typedef unsigned short f15ld[5]; |
|
145 |
const f15ld f15rk[] = |
|
146 |
{ |
|
147 |
/*0*/ {0x0000,0x0000,0x0000,0x0000,0x0000}, |
|
148 |
/*1*/ {0x0000,0x0000,0x0000,0x8000,0x3fff}, |
|
149 |
/*pi*/ {0xc235,0x2168,0xdaa2,0xc90f,0x4000}, |
|
150 |
/*lg2*/ {0xf799,0xfbcf,0x9a84,0x9a20,0x3ffd}, |
|
151 |
/*ln2*/ {0x79ac,0xd1cf,0x17f7,0xb172,0x3ffe}, |
|
152 |
/*l2e*/ {0xf0bc,0x5c17,0x3b29,0xb8aa,0x3fff}, |
|
153 |
/*l2t*/ {0x8afe,0xcd1b,0x784b,0xd49a,0x4000} |
|
154 |
}; |
|
155 |
#else |
|
156 |
/* the same, 64-bit version */ |
|
157 |
typedef unsigned short f15ld[4]; |
|
158 |
const f15ld f15rk[] = |
|
159 |
{ |
|
160 |
#ifndef WORDS_BIGENDIAN |
|
161 |
/*0*/ {0x0000,0x0000,0x0000,0x0000}, |
|
162 |
/*1*/ {0x0000,0x0000,0x0000,0x3ff0}, |
|
163 |
/*pi*/ {0x2d18,0x5444,0x21fb,0x4009}, |
|
164 |
/*lg2*/ {0x79ff,0x509f,0x4413,0x3fd3}, |
|
165 |
/*ln2*/ {0x39ef,0xfefa,0x2e42,0x3fe6}, |
|
166 |
/*l2e*/ {0x82fe,0x652b,0x1547,0x3ff7}, |
|
167 |
/*l2t*/ {0xa371,0x0979,0x934f,0x400a} |
|
168 |
#else |
|
169 |
/*0*/ {0x0000,0x0000,0x0000,0x0000}, |
|
170 |
/*1*/ {0x3ff0,0x0000,0x0000,0x0000}, |
|
171 |
/*pi*/ {0x4009,0x21fb,0x5444,0x2d18}, |
|
172 |
/*lg2*/ {0x3fd3,0x4413,0x509f,0x79ff}, |
|
173 |
/*ln2*/ {0x3fe6,0x2e42,0xfefa,0x39ef}, |
|
174 |
/*l2e*/ {0x3ff7,0x1547,0x652b,0x82fe}, |
|
175 |
/*l2t*/ {0x400a,0x934f,0x0979,0xa371} |
|
176 |
#endif |
|
177 |
}; |
|
178 |
#endif |
|
179 |
|
|
136 | 180 |
/* n must be a constant to be efficient */ |
137 | 181 |
static inline int lshift(int x, int n) |
138 | 182 |
{ |
... | ... | |
866 | 910 |
[CC_OP_SHLW] = { compute_all_shlw, compute_c_shlw }, |
867 | 911 |
[CC_OP_SHLL] = { compute_all_shll, compute_c_shll }, |
868 | 912 |
}; |
913 |
|
|
914 |
/* floating point support */ |
|
915 |
|
|
916 |
#ifdef USE_X86LDOUBLE |
|
917 |
/* use long double functions */ |
|
918 |
#define lrint lrintl |
|
919 |
#define llrint llrintl |
|
920 |
#define fabs fabsl |
|
921 |
#define sin sinl |
|
922 |
#define cos cosl |
|
923 |
#define sqrt sqrtl |
|
924 |
#define pow powl |
|
925 |
#define log logl |
|
926 |
#define tan tanl |
|
927 |
#define atan2 atan2l |
|
928 |
#define floor floorl |
|
929 |
#define ceil ceill |
|
930 |
#define rint rintl |
|
931 |
#endif |
|
932 |
|
|
933 |
extern int lrint(CPU86_LDouble x); |
|
934 |
extern int64_t llrint(CPU86_LDouble x); |
|
935 |
extern CPU86_LDouble fabs(CPU86_LDouble x); |
|
936 |
extern CPU86_LDouble sin(CPU86_LDouble x); |
|
937 |
extern CPU86_LDouble cos(CPU86_LDouble x); |
|
938 |
extern CPU86_LDouble sqrt(CPU86_LDouble x); |
|
939 |
extern CPU86_LDouble pow(CPU86_LDouble, CPU86_LDouble); |
|
940 |
extern CPU86_LDouble log(CPU86_LDouble x); |
|
941 |
extern CPU86_LDouble tan(CPU86_LDouble x); |
|
942 |
extern CPU86_LDouble atan2(CPU86_LDouble, CPU86_LDouble); |
|
943 |
extern CPU86_LDouble floor(CPU86_LDouble x); |
|
944 |
extern CPU86_LDouble ceil(CPU86_LDouble x); |
|
945 |
extern CPU86_LDouble rint(CPU86_LDouble x); |
|
946 |
|
|
947 |
#define RC_MASK 0xc00 |
|
948 |
#define RC_NEAR 0x000 |
|
949 |
#define RC_DOWN 0x400 |
|
950 |
#define RC_UP 0x800 |
|
951 |
#define RC_CHOP 0xc00 |
|
952 |
|
|
953 |
#define MAXTAN 9223372036854775808.0 |
|
954 |
|
|
955 |
#ifdef USE_X86LDOUBLE |
|
956 |
|
|
957 |
/* only for x86 */ |
|
958 |
typedef union { |
|
959 |
long double d; |
|
960 |
struct { |
|
961 |
unsigned long long lower; |
|
962 |
unsigned short upper; |
|
963 |
} l; |
|
964 |
} CPU86_LDoubleU; |
|
965 |
|
|
966 |
/* the following deal with x86 long double-precision numbers */ |
|
967 |
#define MAXEXPD 0x7fff |
|
968 |
#define EXPBIAS 16383 |
|
969 |
#define EXPD(fp) (fp.l.upper & 0x7fff) |
|
970 |
#define SIGND(fp) ((fp.l.upper) & 0x8000) |
|
971 |
#define MANTD(fp) (fp.l.lower) |
|
972 |
#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS |
|
973 |
|
|
974 |
#else |
|
975 |
|
|
976 |
typedef { |
|
977 |
double d; |
|
978 |
#ifndef WORDS_BIGENDIAN |
|
979 |
struct { |
|
980 |
unsigned long lower; |
|
981 |
long upper; |
|
982 |
} l; |
|
983 |
#else |
|
984 |
struct { |
|
985 |
long upper; |
|
986 |
unsigned long lower; |
|
987 |
} l; |
|
988 |
#endif |
|
989 |
long long ll; |
|
990 |
} CPU86_LDoubleU; |
|
991 |
|
|
992 |
/* the following deal with IEEE double-precision numbers */ |
|
993 |
#define MAXEXPD 0x7ff |
|
994 |
#define EXPBIAS 1023 |
|
995 |
#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) |
|
996 |
#define SIGND(fp) ((fp.l.upper) & 0x80000000) |
|
997 |
#define MANTD(fp) (fp.ll & ((1LL << 52) - 1)) |
|
998 |
#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7ff << 20)) | (EXPBIAS << 20) |
|
999 |
#endif |
|
1000 |
|
|
1001 |
/* fp load FT0 */ |
|
1002 |
|
|
1003 |
void OPPROTO op_flds_FT0_A0(void) |
|
1004 |
{ |
|
1005 |
FT0 = ldfl((void *)A0); |
|
1006 |
} |
|
1007 |
|
|
1008 |
void OPPROTO op_fldl_FT0_A0(void) |
|
1009 |
{ |
|
1010 |
FT0 = ldfq((void *)A0); |
|
1011 |
} |
|
1012 |
|
|
1013 |
void OPPROTO op_fild_FT0_A0(void) |
|
1014 |
{ |
|
1015 |
FT0 = (CPU86_LDouble)ldsw((void *)A0); |
|
1016 |
} |
|
1017 |
|
|
1018 |
void OPPROTO op_fildl_FT0_A0(void) |
|
1019 |
{ |
|
1020 |
FT0 = (CPU86_LDouble)((int32_t)ldl((void *)A0)); |
|
1021 |
} |
|
1022 |
|
|
1023 |
void OPPROTO op_fildll_FT0_A0(void) |
|
1024 |
{ |
|
1025 |
FT0 = (CPU86_LDouble)((int64_t)ldq((void *)A0)); |
|
1026 |
} |
|
1027 |
|
|
1028 |
/* fp load ST0 */ |
|
1029 |
|
|
1030 |
void OPPROTO op_flds_ST0_A0(void) |
|
1031 |
{ |
|
1032 |
ST0 = ldfl((void *)A0); |
|
1033 |
} |
|
1034 |
|
|
1035 |
void OPPROTO op_fldl_ST0_A0(void) |
|
1036 |
{ |
|
1037 |
ST0 = ldfq((void *)A0); |
|
1038 |
} |
|
1039 |
|
|
1040 |
void OPPROTO op_fild_ST0_A0(void) |
|
1041 |
{ |
|
1042 |
ST0 = (CPU86_LDouble)ldsw((void *)A0); |
|
1043 |
} |
|
1044 |
|
|
1045 |
void OPPROTO op_fildl_ST0_A0(void) |
|
1046 |
{ |
|
1047 |
ST0 = (CPU86_LDouble)((int32_t)ldl((void *)A0)); |
|
1048 |
} |
|
1049 |
|
|
1050 |
void OPPROTO op_fildll_ST0_A0(void) |
|
1051 |
{ |
|
1052 |
ST0 = (CPU86_LDouble)((int64_t)ldq((void *)A0)); |
|
1053 |
} |
|
1054 |
|
|
1055 |
/* fp store */ |
|
1056 |
|
|
1057 |
void OPPROTO op_fsts_ST0_A0(void) |
|
1058 |
{ |
|
1059 |
stfl((void *)A0, (float)ST0); |
|
1060 |
} |
|
1061 |
|
|
1062 |
void OPPROTO op_fstl_ST0_A0(void) |
|
1063 |
{ |
|
1064 |
ST0 = ldfq((void *)A0); |
|
1065 |
} |
|
1066 |
|
|
1067 |
void OPPROTO op_fist_ST0_A0(void) |
|
1068 |
{ |
|
1069 |
int val; |
|
1070 |
val = lrint(ST0); |
|
1071 |
stw((void *)A0, val); |
|
1072 |
} |
|
1073 |
|
|
1074 |
void OPPROTO op_fistl_ST0_A0(void) |
|
1075 |
{ |
|
1076 |
int val; |
|
1077 |
val = lrint(ST0); |
|
1078 |
stl((void *)A0, val); |
|
1079 |
} |
|
1080 |
|
|
1081 |
void OPPROTO op_fistll_ST0_A0(void) |
|
1082 |
{ |
|
1083 |
int64_t val; |
|
1084 |
val = llrint(ST0); |
|
1085 |
stq((void *)A0, val); |
|
1086 |
} |
|
1087 |
|
|
1088 |
/* FPU move */ |
|
1089 |
|
|
1090 |
static inline void fpush(void) |
|
1091 |
{ |
|
1092 |
env->fpstt = (env->fpstt - 1) & 7; |
|
1093 |
env->fptags[env->fpstt] = 0; /* validate stack entry */ |
|
1094 |
} |
|
1095 |
|
|
1096 |
static inline void fpop(void) |
|
1097 |
{ |
|
1098 |
env->fptags[env->fpstt] = 1; /* invvalidate stack entry */ |
|
1099 |
env->fpstt = (env->fpstt + 1) & 7; |
|
1100 |
} |
|
1101 |
|
|
1102 |
void OPPROTO op_fpush(void) |
|
1103 |
{ |
|
1104 |
fpush(); |
|
1105 |
} |
|
1106 |
|
|
1107 |
void OPPROTO op_fpop(void) |
|
1108 |
{ |
|
1109 |
fpop(); |
|
1110 |
} |
|
1111 |
|
|
1112 |
void OPPROTO op_fdecstp(void) |
|
1113 |
{ |
|
1114 |
env->fpstt = (env->fpstt - 1) & 7; |
|
1115 |
env->fpus &= (~0x4700); |
|
1116 |
} |
|
1117 |
|
|
1118 |
void OPPROTO op_fincstp(void) |
|
1119 |
{ |
|
1120 |
env->fpstt = (env->fpstt + 1) & 7; |
|
1121 |
env->fpus &= (~0x4700); |
|
1122 |
} |
|
1123 |
|
|
1124 |
void OPPROTO op_fmov_ST0_FT0(void) |
|
1125 |
{ |
|
1126 |
ST0 = FT0; |
|
1127 |
} |
|
1128 |
|
|
1129 |
void OPPROTO op_fmov_FT0_STN(void) |
|
1130 |
{ |
|
1131 |
FT0 = ST(PARAM1); |
|
1132 |
} |
|
1133 |
|
|
1134 |
void OPPROTO op_fmov_ST0_STN(void) |
|
1135 |
{ |
|
1136 |
ST0 = ST(PARAM1); |
|
1137 |
} |
|
1138 |
|
|
1139 |
void OPPROTO op_fmov_STN_ST0(void) |
|
1140 |
{ |
|
1141 |
ST(PARAM1) = ST0; |
|
1142 |
} |
|
1143 |
|
|
1144 |
void OPPROTO op_fxchg_ST0_STN(void) |
|
1145 |
{ |
|
1146 |
CPU86_LDouble tmp; |
|
1147 |
tmp = ST(PARAM1); |
|
1148 |
ST(PARAM1) = ST0; |
|
1149 |
ST0 = tmp; |
|
1150 |
} |
|
1151 |
|
|
1152 |
/* FPU operations */ |
|
1153 |
|
|
1154 |
/* XXX: handle nans */ |
|
1155 |
void OPPROTO op_fcom_ST0_FT0(void) |
|
1156 |
{ |
|
1157 |
env->fpus &= (~0x4500); /* (C3,C2,C0) <-- 000 */ |
|
1158 |
if (ST0 < FT0) |
|
1159 |
env->fpus |= 0x100; /* (C3,C2,C0) <-- 001 */ |
|
1160 |
else if (ST0 == FT0) |
|
1161 |
env->fpus |= 0x4000; /* (C3,C2,C0) <-- 100 */ |
|
1162 |
FORCE_RET(); |
|
1163 |
} |
|
1164 |
|
|
1165 |
void OPPROTO op_fadd_ST0_FT0(void) |
|
1166 |
{ |
|
1167 |
ST0 += FT0; |
|
1168 |
} |
|
1169 |
|
|
1170 |
void OPPROTO op_fmul_ST0_FT0(void) |
|
1171 |
{ |
|
1172 |
ST0 *= FT0; |
|
1173 |
} |
|
1174 |
|
|
1175 |
void OPPROTO op_fsub_ST0_FT0(void) |
|
1176 |
{ |
|
1177 |
ST0 -= FT0; |
|
1178 |
} |
|
1179 |
|
|
1180 |
void OPPROTO op_fsubr_ST0_FT0(void) |
|
1181 |
{ |
|
1182 |
ST0 = FT0 - ST0; |
|
1183 |
} |
|
1184 |
|
|
1185 |
void OPPROTO op_fdiv_ST0_FT0(void) |
|
1186 |
{ |
|
1187 |
ST0 /= FT0; |
|
1188 |
} |
|
1189 |
|
|
1190 |
void OPPROTO op_fdivr_ST0_FT0(void) |
|
1191 |
{ |
|
1192 |
ST0 = FT0 / ST0; |
|
1193 |
} |
|
1194 |
|
|
1195 |
/* fp operations between STN and ST0 */ |
|
1196 |
|
|
1197 |
void OPPROTO op_fadd_STN_ST0(void) |
|
1198 |
{ |
|
1199 |
ST(PARAM1) += ST0; |
|
1200 |
} |
|
1201 |
|
|
1202 |
void OPPROTO op_fmul_STN_ST0(void) |
|
1203 |
{ |
|
1204 |
ST(PARAM1) *= ST0; |
|
1205 |
} |
|
1206 |
|
|
1207 |
void OPPROTO op_fsub_STN_ST0(void) |
|
1208 |
{ |
|
1209 |
ST(PARAM1) -= ST0; |
|
1210 |
} |
|
1211 |
|
|
1212 |
void OPPROTO op_fsubr_STN_ST0(void) |
|
1213 |
{ |
|
1214 |
CPU86_LDouble *p; |
|
1215 |
p = &ST(PARAM1); |
|
1216 |
*p = ST0 - *p; |
|
1217 |
} |
|
1218 |
|
|
1219 |
void OPPROTO op_fdiv_STN_ST0(void) |
|
1220 |
{ |
|
1221 |
ST(PARAM1) /= ST0; |
|
1222 |
} |
|
1223 |
|
|
1224 |
void OPPROTO op_fdivr_STN_ST0(void) |
|
1225 |
{ |
|
1226 |
CPU86_LDouble *p; |
|
1227 |
p = &ST(PARAM1); |
|
1228 |
*p = ST0 / *p; |
|
1229 |
} |
|
1230 |
|
|
1231 |
/* misc FPU operations */ |
|
1232 |
void OPPROTO op_fchs_ST0(void) |
|
1233 |
{ |
|
1234 |
ST0 = -ST0; |
|
1235 |
} |
|
1236 |
|
|
1237 |
void OPPROTO op_fabs_ST0(void) |
|
1238 |
{ |
|
1239 |
ST0 = fabs(ST0); |
|
1240 |
} |
|
1241 |
|
|
1242 |
void OPPROTO op_fxam_ST0(void) |
|
1243 |
{ |
|
1244 |
CPU86_LDoubleU temp; |
|
1245 |
int expdif; |
|
1246 |
|
|
1247 |
temp.d = ST0; |
|
1248 |
|
|
1249 |
env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ |
|
1250 |
if (SIGND(temp)) |
|
1251 |
env->fpus |= 0x200; /* C1 <-- 1 */ |
|
1252 |
|
|
1253 |
expdif = EXPD(temp); |
|
1254 |
if (expdif == MAXEXPD) { |
|
1255 |
if (MANTD(temp) == 0) |
|
1256 |
env->fpus |= 0x500 /*Infinity*/; |
|
1257 |
else |
|
1258 |
env->fpus |= 0x100 /*NaN*/; |
|
1259 |
} else if (expdif == 0) { |
|
1260 |
if (MANTD(temp) == 0) |
|
1261 |
env->fpus |= 0x4000 /*Zero*/; |
|
1262 |
else |
|
1263 |
env->fpus |= 0x4400 /*Denormal*/; |
|
1264 |
} else { |
|
1265 |
env->fpus |= 0x400; |
|
1266 |
} |
|
1267 |
FORCE_RET(); |
|
1268 |
} |
|
1269 |
|
|
1270 |
void OPPROTO op_fld1_ST0(void) |
|
1271 |
{ |
|
1272 |
ST0 = *(CPU86_LDouble *)&f15rk[1]; |
|
1273 |
} |
|
1274 |
|
|
1275 |
void OPPROTO op_fld2t_ST0(void) |
|
1276 |
{ |
|
1277 |
ST0 = *(CPU86_LDouble *)&f15rk[6]; |
|
1278 |
} |
|
1279 |
|
|
1280 |
void OPPROTO op_fld2e_ST0(void) |
|
1281 |
{ |
|
1282 |
ST0 = *(CPU86_LDouble *)&f15rk[5]; |
|
1283 |
} |
|
1284 |
|
|
1285 |
void OPPROTO op_fldpi_ST0(void) |
|
1286 |
{ |
|
1287 |
ST0 = *(CPU86_LDouble *)&f15rk[2]; |
|
1288 |
} |
|
1289 |
|
|
1290 |
void OPPROTO op_fldlg2_ST0(void) |
|
1291 |
{ |
|
1292 |
ST0 = *(CPU86_LDouble *)&f15rk[3]; |
|
1293 |
} |
|
1294 |
|
|
1295 |
void OPPROTO op_fldln2_ST0(void) |
|
1296 |
{ |
|
1297 |
ST0 = *(CPU86_LDouble *)&f15rk[4]; |
|
1298 |
} |
|
1299 |
|
|
1300 |
void OPPROTO op_fldz_ST0(void) |
|
1301 |
{ |
|
1302 |
ST0 = *(CPU86_LDouble *)&f15rk[0]; |
|
1303 |
} |
|
1304 |
|
|
1305 |
void OPPROTO op_fldz_FT0(void) |
|
1306 |
{ |
|
1307 |
ST0 = *(CPU86_LDouble *)&f15rk[0]; |
|
1308 |
} |
|
1309 |
|
|
1310 |
void helper_f2xm1(void) |
|
1311 |
{ |
|
1312 |
ST0 = pow(2.0,ST0) - 1.0; |
|
1313 |
} |
|
1314 |
|
|
1315 |
void helper_fyl2x(void) |
|
1316 |
{ |
|
1317 |
CPU86_LDouble fptemp; |
|
1318 |
|
|
1319 |
fptemp = ST0; |
|
1320 |
if (fptemp>0.0){ |
|
1321 |
fptemp = log(fptemp)/log(2.0); /* log2(ST) */ |
|
1322 |
ST1 *= fptemp; |
|
1323 |
fpop(); |
|
1324 |
} else { |
|
1325 |
env->fpus &= (~0x4700); |
|
1326 |
env->fpus |= 0x400; |
|
1327 |
} |
|
1328 |
} |
|
1329 |
|
|
1330 |
void helper_fptan(void) |
|
1331 |
{ |
|
1332 |
CPU86_LDouble fptemp; |
|
1333 |
|
|
1334 |
fptemp = ST0; |
|
1335 |
if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { |
|
1336 |
env->fpus |= 0x400; |
|
1337 |
} else { |
|
1338 |
ST0 = tan(fptemp); |
|
1339 |
fpush(); |
|
1340 |
ST0 = 1.0; |
|
1341 |
env->fpus &= (~0x400); /* C2 <-- 0 */ |
|
1342 |
/* the above code is for |arg| < 2**52 only */ |
|
1343 |
} |
|
1344 |
} |
|
1345 |
|
|
1346 |
void helper_fpatan(void) |
|
1347 |
{ |
|
1348 |
CPU86_LDouble fptemp, fpsrcop; |
|
1349 |
|
|
1350 |
fpsrcop = ST1; |
|
1351 |
fptemp = ST0; |
|
1352 |
ST1 = atan2(fpsrcop,fptemp); |
|
1353 |
fpop(); |
|
1354 |
} |
|
1355 |
|
|
1356 |
void helper_fxtract(void) |
|
1357 |
{ |
|
1358 |
CPU86_LDoubleU temp; |
|
1359 |
unsigned int expdif; |
|
1360 |
|
|
1361 |
temp.d = ST0; |
|
1362 |
expdif = EXPD(temp) - EXPBIAS; |
|
1363 |
/*DP exponent bias*/ |
|
1364 |
ST0 = expdif; |
|
1365 |
fpush(); |
|
1366 |
BIASEXPONENT(temp); |
|
1367 |
ST0 = temp.d; |
|
1368 |
} |
|
1369 |
|
|
1370 |
void helper_fprem1(void) |
|
1371 |
{ |
|
1372 |
CPU86_LDouble dblq, fpsrcop, fptemp; |
|
1373 |
CPU86_LDoubleU fpsrcop1, fptemp1; |
|
1374 |
int expdif; |
|
1375 |
int q; |
|
1376 |
|
|
1377 |
fpsrcop = ST0; |
|
1378 |
fptemp = ST1; |
|
1379 |
fpsrcop1.d = fpsrcop; |
|
1380 |
fptemp1.d = fptemp; |
|
1381 |
expdif = EXPD(fpsrcop1) - EXPD(fptemp1); |
|
1382 |
if (expdif < 53) { |
|
1383 |
dblq = fpsrcop / fptemp; |
|
1384 |
dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); |
|
1385 |
ST0 = fpsrcop - fptemp*dblq; |
|
1386 |
q = (int)dblq; /* cutting off top bits is assumed here */ |
|
1387 |
env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ |
|
1388 |
/* (C0,C1,C3) <-- (q2,q1,q0) */ |
|
1389 |
env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ |
|
1390 |
env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ |
|
1391 |
env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ |
|
1392 |
} else { |
|
1393 |
env->fpus |= 0x400; /* C2 <-- 1 */ |
|
1394 |
fptemp = pow(2.0, expdif-50); |
|
1395 |
fpsrcop = (ST0 / ST1) / fptemp; |
|
1396 |
/* fpsrcop = integer obtained by rounding to the nearest */ |
|
1397 |
fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)? |
|
1398 |
floor(fpsrcop): ceil(fpsrcop); |
|
1399 |
ST0 -= (ST1 * fpsrcop * fptemp); |
|
1400 |
} |
|
1401 |
} |
|
1402 |
|
|
1403 |
void helper_fprem(void) |
|
1404 |
{ |
|
1405 |
CPU86_LDouble dblq, fpsrcop, fptemp; |
|
1406 |
CPU86_LDoubleU fpsrcop1, fptemp1; |
|
1407 |
int expdif; |
|
1408 |
int q; |
|
1409 |
|
|
1410 |
fpsrcop = ST0; |
|
1411 |
fptemp = ST1; |
|
1412 |
fpsrcop1.d = fpsrcop; |
|
1413 |
fptemp1.d = fptemp; |
|
1414 |
expdif = EXPD(fpsrcop1) - EXPD(fptemp1); |
|
1415 |
if ( expdif < 53 ) { |
|
1416 |
dblq = fpsrcop / fptemp; |
|
1417 |
dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); |
|
1418 |
ST0 = fpsrcop - fptemp*dblq; |
|
1419 |
q = (int)dblq; /* cutting off top bits is assumed here */ |
|
1420 |
env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ |
|
1421 |
/* (C0,C1,C3) <-- (q2,q1,q0) */ |
|
1422 |
env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ |
|
1423 |
env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ |
|
1424 |
env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ |
|
1425 |
} else { |
|
1426 |
env->fpus |= 0x400; /* C2 <-- 1 */ |
|
1427 |
fptemp = pow(2.0, expdif-50); |
|
1428 |
fpsrcop = (ST0 / ST1) / fptemp; |
|
1429 |
/* fpsrcop = integer obtained by chopping */ |
|
1430 |
fpsrcop = (fpsrcop < 0.0)? |
|
1431 |
-(floor(fabs(fpsrcop))): floor(fpsrcop); |
|
1432 |
ST0 -= (ST1 * fpsrcop * fptemp); |
|
1433 |
} |
|
1434 |
} |
|
1435 |
|
|
1436 |
void helper_fyl2xp1(void) |
|
1437 |
{ |
|
1438 |
CPU86_LDouble fptemp; |
|
1439 |
|
|
1440 |
fptemp = ST0; |
|
1441 |
if ((fptemp+1.0)>0.0) { |
|
1442 |
fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */ |
|
1443 |
ST1 *= fptemp; |
|
1444 |
fpop(); |
|
1445 |
} else { |
|
1446 |
env->fpus &= (~0x4700); |
|
1447 |
env->fpus |= 0x400; |
|
1448 |
} |
|
1449 |
} |
|
1450 |
|
|
1451 |
void helper_fsqrt(void) |
|
1452 |
{ |
|
1453 |
CPU86_LDouble fptemp; |
|
1454 |
|
|
1455 |
fptemp = ST0; |
|
1456 |
if (fptemp<0.0) { |
|
1457 |
env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ |
|
1458 |
env->fpus |= 0x400; |
|
1459 |
} |
|
1460 |
ST0 = sqrt(fptemp); |
|
1461 |
} |
|
1462 |
|
|
1463 |
void helper_fsincos(void) |
|
1464 |
{ |
|
1465 |
CPU86_LDouble fptemp; |
|
1466 |
|
|
1467 |
fptemp = ST0; |
|
1468 |
if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { |
|
1469 |
env->fpus |= 0x400; |
|
1470 |
} else { |
|
1471 |
ST0 = sin(fptemp); |
|
1472 |
fpush(); |
|
1473 |
ST0 = cos(fptemp); |
|
1474 |
env->fpus &= (~0x400); /* C2 <-- 0 */ |
|
1475 |
/* the above code is for |arg| < 2**63 only */ |
|
1476 |
} |
|
1477 |
} |
|
1478 |
|
|
1479 |
void helper_frndint(void) |
|
1480 |
{ |
|
1481 |
ST0 = rint(ST0); |
|
1482 |
} |
|
1483 |
|
|
1484 |
void helper_fscale(void) |
|
1485 |
{ |
|
1486 |
CPU86_LDouble fpsrcop, fptemp; |
|
1487 |
|
|
1488 |
fpsrcop = 2.0; |
|
1489 |
fptemp = pow(fpsrcop,ST1); |
|
1490 |
ST0 *= fptemp; |
|
1491 |
} |
|
1492 |
|
|
1493 |
void helper_fsin(void) |
|
1494 |
{ |
|
1495 |
CPU86_LDouble fptemp; |
|
1496 |
|
|
1497 |
fptemp = ST0; |
|
1498 |
if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { |
|
1499 |
env->fpus |= 0x400; |
|
1500 |
} else { |
|
1501 |
ST0 = sin(fptemp); |
|
1502 |
env->fpus &= (~0x400); /* C2 <-- 0 */ |
|
1503 |
/* the above code is for |arg| < 2**53 only */ |
|
1504 |
} |
|
1505 |
} |
|
1506 |
|
|
1507 |
void helper_fcos(void) |
|
1508 |
{ |
|
1509 |
CPU86_LDouble fptemp; |
|
1510 |
|
|
1511 |
fptemp = ST0; |
|
1512 |
if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { |
|
1513 |
env->fpus |= 0x400; |
|
1514 |
} else { |
|
1515 |
ST0 = cos(fptemp); |
|
1516 |
env->fpus &= (~0x400); /* C2 <-- 0 */ |
|
1517 |
/* the above code is for |arg5 < 2**63 only */ |
|
1518 |
} |
|
1519 |
} |
|
1520 |
|
|
1521 |
/* associated heplers to reduce generated code length and to simplify |
|
1522 |
relocation (FP constants are usually stored in .rodata section) */ |
|
1523 |
|
|
1524 |
void OPPROTO op_f2xm1(void) |
|
1525 |
{ |
|
1526 |
helper_f2xm1(); |
|
1527 |
} |
|
1528 |
|
|
1529 |
void OPPROTO op_fyl2x(void) |
|
1530 |
{ |
|
1531 |
helper_fyl2x(); |
|
1532 |
} |
|
1533 |
|
|
1534 |
void OPPROTO op_fptan(void) |
|
1535 |
{ |
|
1536 |
helper_fptan(); |
|
1537 |
} |
|
1538 |
|
|
1539 |
void OPPROTO op_fpatan(void) |
|
1540 |
{ |
|
1541 |
helper_fpatan(); |
|
1542 |
} |
|
1543 |
|
|
1544 |
void OPPROTO op_fxtract(void) |
|
1545 |
{ |
|
1546 |
helper_fxtract(); |
|
1547 |
} |
|
1548 |
|
|
1549 |
void OPPROTO op_fprem1(void) |
|
1550 |
{ |
|
1551 |
helper_fprem1(); |
|
1552 |
} |
|
1553 |
|
|
1554 |
|
|
1555 |
void OPPROTO op_fprem(void) |
|
1556 |
{ |
|
1557 |
helper_fprem(); |
|
1558 |
} |
|
1559 |
|
|
1560 |
void OPPROTO op_fyl2xp1(void) |
|
1561 |
{ |
|
1562 |
helper_fyl2xp1(); |
|
1563 |
} |
|
1564 |
|
|
1565 |
void OPPROTO op_fsqrt(void) |
|
1566 |
{ |
|
1567 |
helper_fsqrt(); |
|
1568 |
} |
|
1569 |
|
|
1570 |
void OPPROTO op_fsincos(void) |
|
1571 |
{ |
|
1572 |
helper_fsincos(); |
|
1573 |
} |
|
1574 |
|
|
1575 |
void OPPROTO op_frndint(void) |
|
1576 |
{ |
|
1577 |
helper_frndint(); |
|
1578 |
} |
|
1579 |
|
|
1580 |
void OPPROTO op_fscale(void) |
|
1581 |
{ |
|
1582 |
helper_fscale(); |
|
1583 |
} |
|
1584 |
|
|
1585 |
void OPPROTO op_fsin(void) |
|
1586 |
{ |
|
1587 |
helper_fsin(); |
|
1588 |
} |
|
1589 |
|
|
1590 |
void OPPROTO op_fcos(void) |
|
1591 |
{ |
|
1592 |
helper_fcos(); |
|
1593 |
} |
|
1594 |
|
b/translate-i386.c | ||
---|---|---|
5 | 5 |
#include <inttypes.h> |
6 | 6 |
#include <assert.h> |
7 | 7 |
|
8 |
#define IN_OP_I386 |
|
8 | 9 |
#include "cpu-i386.h" |
9 | 10 |
|
10 | 11 |
static uint8_t *gen_code_ptr; |
... | ... | |
39 | 40 |
int prefix; |
40 | 41 |
int aflag, dflag; |
41 | 42 |
uint8_t *pc; /* current pc */ |
42 |
uint8_t *runtime_pc; /* current pc in the runtime generated code */ |
|
43 | 43 |
int cc_op; /* current CC operation */ |
44 | 44 |
int f_st; |
45 | 45 |
} DisasContext; |
... | ... | |
68 | 68 |
OP_SAR = 7, |
69 | 69 |
}; |
70 | 70 |
|
71 |
|
|
72 |
static const int fp_ops[8] = { |
|
73 |
#if 0 |
|
74 |
OP_FADDQ, OP_FMULQ, OP_CMP, OP_CMP, |
|
75 |
OP_FSUBQ, OP_FSUBQ, OP_FDIVQ, OP_FDIVQ |
|
76 |
#endif |
|
77 |
}; |
|
78 |
|
|
79 |
extern char cc_table, rclw_table, rclb_table; |
|
80 |
extern char helper_rcll_T0_T1_cc; |
|
81 |
extern char __udivdi3, __umoddi3; |
|
82 |
|
|
83 | 71 |
#include "op-i386.h" |
84 | 72 |
|
85 | 73 |
/* operand size */ |
... | ... | |
606 | 594 |
}, |
607 | 595 |
}; |
608 | 596 |
|
597 |
static GenOpFunc *gen_op_fp_arith_ST0_FT0[8] = { |
|
598 |
gen_op_fadd_ST0_FT0, |
|
599 |
gen_op_fmul_ST0_FT0, |
|
600 |
gen_op_fcom_ST0_FT0, |
|
601 |
gen_op_fcom_ST0_FT0, |
|
602 |
gen_op_fsub_ST0_FT0, |
|
603 |
gen_op_fsubr_ST0_FT0, |
|
604 |
gen_op_fdiv_ST0_FT0, |
|
605 |
gen_op_fdivr_ST0_FT0, |
|
606 |
}; |
|
607 |
|
|
608 |
static GenOpFunc1 *gen_op_fp_arith_STN_ST0[8] = { |
|
609 |
gen_op_fadd_STN_ST0, |
|
610 |
gen_op_fmul_STN_ST0, |
|
611 |
NULL, |
|
612 |
NULL, |
|
613 |
gen_op_fsub_STN_ST0, |
|
614 |
gen_op_fsubr_STN_ST0, |
|
615 |
gen_op_fdiv_STN_ST0, |
|
616 |
gen_op_fdivr_STN_ST0, |
|
617 |
}; |
|
618 |
|
|
609 | 619 |
static void gen_op(DisasContext *s1, int op, int ot, int d, int s) |
610 | 620 |
{ |
611 | 621 |
if (d != OR_TMP0) |
... | ... | |
1345 | 1355 |
/**************************/ |
1346 | 1356 |
/* push/pop */ |
1347 | 1357 |
case 0x50 ... 0x57: /* push */ |
1348 |
gen_op_mov_TN_reg[OT_LONG][0][(b & 7)]();
|
|
1358 |
gen_op_mov_TN_reg[OT_LONG][0][b & 7]();
|
|
1349 | 1359 |
gen_op_pushl_T0(); |
1350 | 1360 |
break; |
1351 | 1361 |
case 0x58 ... 0x5f: /* pop */ |
1352 | 1362 |
gen_op_popl_T0(); |
1353 |
gen_op_mov_reg_T0[OT_LONG][reg]();
|
|
1363 |
gen_op_mov_reg_T0[OT_LONG][b & 7]();
|
|
1354 | 1364 |
break; |
1355 | 1365 |
case 0x68: /* push Iv */ |
1356 | 1366 |
case 0x6a: |
... | ... | |
1581 | 1591 |
|
1582 | 1592 |
/************************/ |
1583 | 1593 |
/* floats */ |
1584 |
#if 0 |
|
1585 | 1594 |
case 0xd8 ... 0xdf: |
1586 | 1595 |
modrm = ldub(s->pc++); |
1587 | 1596 |
mod = (modrm >> 6) & 3; |
... | ... | |
1597 | 1606 |
case 0x20 ... 0x27: /* fxxxl */ |
1598 | 1607 |
case 0x30 ... 0x37: /* fixxx */ |
1599 | 1608 |
{ |
1600 |
int op1, swap; |
|
1601 |
op1 = fp_ops[op & 7]; |
|
1602 |
|
|
1603 |
swap = 0; |
|
1604 |
if ((op & 7) == 5 || (op & 7) == 7) |
|
1605 |
swap = 1; |
|
1609 |
int op1; |
|
1610 |
op1 = op & 7; |
|
1606 | 1611 |
|
1607 | 1612 |
switch(op >> 4) { |
1608 | 1613 |
case 0: |
1609 |
ot = OT_LONG; |
|
1610 |
is_int = 0; |
|
1614 |
gen_op_flds_FT0_A0(); |
|
1611 | 1615 |
break; |
1612 | 1616 |
case 1: |
1613 |
ot = OT_LONG; |
|
1614 |
is_int = 1; |
|
1617 |
gen_op_fildl_FT0_A0(); |
|
1615 | 1618 |
break; |
1616 | 1619 |
case 2: |
1617 |
ot = OT_QUAD; |
|
1618 |
is_int = 0; |
|
1620 |
gen_op_fldl_FT0_A0(); |
|
1619 | 1621 |
break; |
1620 | 1622 |
case 3: |
1621 | 1623 |
default: |
1622 |
ot = OT_WORD; |
|
1623 |
is_int = 1; |
|
1624 |
gen_op_fild_FT0_A0(); |
|
1624 | 1625 |
break; |
1625 | 1626 |
} |
1626 | 1627 |
|
1627 |
/* if integer, needs to convert to float */ |
|
1628 |
if (is_int) { |
|
1629 |
/* XXX: potential loss of precision if large integer */ |
|
1630 |
gen_ld(OP_LDUB + ot, OR_TMP0, reg_addr, offset_addr); |
|
1631 |
gen_insn2(OP_I2FL, OR_FTMP0, OR_TMP0); |
|
1632 |
} else { |
|
1633 |
gen_ld(OP_LDUB + ot, OR_FTMP0, reg_addr, offset_addr); |
|
1634 |
} |
|
1635 |
if (ot != OT_QUAD) |
|
1636 |
op1 += OP_FADDL - OP_FADDQ; |
|
1637 |
|
|
1638 |
if (!swap) |
|
1639 |
gen_insn3(op1, OR_ST0, OR_ST0, OR_FTMP0); |
|
1640 |
else |
|
1641 |
gen_insn3(op1, OR_ST0, OR_FTMP0, OR_ST0); |
|
1642 |
|
|
1643 |
if ((op & 7) == 3) { |
|
1628 |
gen_op_fp_arith_ST0_FT0[op1](); |
|
1629 |
if (op1 == 3) { |
|
1644 | 1630 |
/* fcomp needs pop */ |
1645 |
gen_insn0(OP_FPOP);
|
|
1631 |
gen_op_fpop();
|
|
1646 | 1632 |
} |
1647 | 1633 |
} |
1648 | 1634 |
break; |
... | ... | |
1659 | 1645 |
case 0x3a: /* fists */ |
1660 | 1646 |
case 0x3b: /* fistps */ |
1661 | 1647 |
|
1662 |
switch(op >> 4) { |
|
1663 |
case 0: |
|
1664 |
ot = OT_LONG; |
|
1665 |
is_int = 0; |
|
1666 |
break; |
|
1667 |
case 1: |
|
1668 |
ot = OT_LONG; |
|
1669 |
is_int = 1; |
|
1670 |
break; |
|
1671 |
case 2: |
|
1672 |
ot = OT_QUAD; |
|
1673 |
is_int = 0; |
|
1674 |
break; |
|
1675 |
case 3: |
|
1676 |
default: |
|
1677 |
ot = OT_WORD; |
|
1678 |
is_int = 1; |
|
1679 |
break; |
|
1680 |
} |
|
1681 |
|
|
1682 | 1648 |
switch(op & 7) { |
1683 | 1649 |
case 0: |
1684 |
gen_insn0(OP_FPUSH); |
|
1685 |
if (is_int) { |
|
1686 |
/* XXX: potential loss of precision */ |
|
1687 |
gen_ld(OP_LDUB + ot, OR_TMP0, reg_addr, offset_addr); |
|
1688 |
gen_insn2(OP_I2FL, OR_ST0, OR_TMP0); |
|
1689 |
} else { |
|
1690 |
gen_ld(OP_LDUB + ot, OR_ST0, reg_addr, offset_addr); |
|
1650 |
gen_op_fpush(); |
|
1651 |
switch(op >> 4) { |
|
1652 |
case 0: |
|
1653 |
gen_op_flds_ST0_A0(); |
|
1654 |
break; |
|
1655 |
case 1: |
|
1656 |
gen_op_fildl_ST0_A0(); |
|
1657 |
break; |
|
1658 |
case 2: |
|
1659 |
gen_op_fldl_ST0_A0(); |
|
1660 |
break; |
|
1661 |
case 3: |
|
1662 |
default: |
|
1663 |
gen_op_fild_ST0_A0(); |
|
1664 |
break; |
|
1691 | 1665 |
} |
1692 | 1666 |
break; |
1693 | 1667 |
default: |
1694 |
if (is_int) { |
|
1695 |
gen_insn2(OP_F2IL, OR_TMP0, OR_ST0); |
|
1696 |
gen_st(OP_STB + ot, OR_TMP0, reg_addr, offset_addr); |
|
1697 |
} else { |
|
1698 |
gen_st(OP_STB + ot, OR_ST0, reg_addr, offset_addr); |
|
1668 |
switch(op >> 4) { |
|
1669 |
case 0: |
|
1670 |
gen_op_fsts_ST0_A0(); |
|
1671 |
break; |
|
1672 |
case 1: |
|
1673 |
gen_op_fistl_ST0_A0(); |
|
1674 |
break; |
|
1675 |
case 2: |
|
1676 |
gen_op_fstl_ST0_A0(); |
|
1677 |
break; |
|
1678 |
case 3: |
|
1679 |
default: |
|
1680 |
gen_op_fist_ST0_A0(); |
|
1681 |
break; |
|
1699 | 1682 |
} |
1700 | 1683 |
if ((op & 7) == 3) |
1701 |
gen_insn0(OP_FPOP);
|
|
1684 |
gen_op_fpop();
|
|
1702 | 1685 |
break; |
1703 | 1686 |
} |
1704 | 1687 |
break; |
1688 |
#if 0 |
|
1705 | 1689 |
case 0x2f: /* fnstsw mem */ |
1706 | 1690 |
gen_insn3(OP_FNSTS, OR_TMP0, OR_ZERO, OR_ZERO); |
1707 | 1691 |
gen_st(OP_STW, OR_TMP0, reg_addr, offset_addr); |
... | ... | |
1711 | 1695 |
case 0x3e: /* fbstp */ |
1712 | 1696 |
error("float BCD not hanlded"); |
1713 | 1697 |
return -1; |
1698 |
#endif |
|
1714 | 1699 |
case 0x3d: /* fildll */ |
1715 |
gen_insn0(OP_FPUSH); |
|
1716 |
gen_ld(OP_LDQ, OR_TMP0, reg_addr, offset_addr); |
|
1717 |
gen_insn2(OP_I2FQ, OR_ST0, OR_TMP0); |
|
1700 |
gen_op_fpush(); |
|
1701 |
gen_op_fildll_ST0_A0(); |
|
1718 | 1702 |
break; |
1719 | 1703 |
case 0x3f: /* fistpll */ |
1720 |
gen_insn2(OP_F2IQ, OR_TMP0, OR_ST0); |
|
1721 |
gen_st(OP_STQ, OR_TMP0, reg_addr, offset_addr); |
|
1722 |
gen_insn0(OP_FPOP); |
|
1704 |
gen_op_fistll_ST0_A0(); |
|
1705 |
gen_op_fpop(); |
|
1723 | 1706 |
break; |
1724 | 1707 |
default: |
1725 | 1708 |
error("unhandled memory FP\n"); |
... | ... | |
1727 | 1710 |
} |
1728 | 1711 |
} else { |
1729 | 1712 |
/* register float ops */ |
1730 |
opreg = rm + OR_ST0;
|
|
1713 |
opreg = rm; |
|
1731 | 1714 |
|
1732 | 1715 |
switch(op) { |
1733 | 1716 |
case 0x08: /* fld sti */ |
1734 |
gen_insn0(OP_FPUSH);
|
|
1735 |
gen_mov(OR_ST0, OR_ST0 + ((rm + 1) & 7));
|
|
1717 |
gen_op_fpush();
|
|
1718 |
gen_op_fmov_ST0_STN((opreg + 1) & 7);
|
|
1736 | 1719 |
break; |
1737 | 1720 |
case 0x09: /* fxchg sti */ |
1738 |
gen_mov(OR_TMP0, OR_ST0); |
|
1739 |
gen_mov(OR_ST0, opreg); |
|
1740 |
gen_mov(opreg, OR_TMP0); |
|
1721 |
gen_op_fxchg_ST0_STN((opreg + 1) & 7); |
|
1741 | 1722 |
break; |
1742 | 1723 |
case 0x0a: /* grp d9/2 */ |
1743 | 1724 |
switch(rm) { |
1744 | 1725 |
case 0: /* fnop */ |
1745 |
gen_insn0(OP_NOP); |
|
1746 | 1726 |
break; |
1747 | 1727 |
default: |
1748 | 1728 |
error("unhandled FP GRP d9/2\n"); |
... | ... | |
1752 | 1732 |
case 0x0c: /* grp d9/4 */ |
1753 | 1733 |
switch(rm) { |
1754 | 1734 |
case 0: /* fchs */ |
1755 |
gen_insn3(OP_FSUBQ, OR_ST0, OR_ZERO, OR_ST0);
|
|
1735 |
gen_op_fchs_ST0();
|
|
1756 | 1736 |
break; |
1757 | 1737 |
case 1: /* fabs */ |
1758 |
gen_insn2(OP_FABSQ, OR_ST0, OR_ST0);
|
|
1738 |
gen_op_fabs_ST0();
|
|
1759 | 1739 |
break; |
1760 | 1740 |
case 4: /* ftst */ |
1761 |
gen_insn3(OP_CMP, OR_ZERO, OR_ST0, OR_ZERO); |
|
1741 |
gen_op_fldz_FT0(); |
|
1742 |
gen_op_fcom_ST0_FT0(); |
|
1762 | 1743 |
break; |
1763 | 1744 |
case 5: /* fxam */ |
1764 |
gen_insn3(OP_FSPECIAL, OR_ZERO, OR_ST0, OR_ZERO);
|
|
1745 |
gen_op_fxam_ST0();
|
|
1765 | 1746 |
break; |
1766 | 1747 |
default: |
1767 | 1748 |
return -1; |
... | ... | |
1769 | 1750 |
break; |
1770 | 1751 |
case 0x0d: /* grp d9/5 */ |
1771 | 1752 |
{ |
1772 |
if (rm == 7) { |
|
1773 |
error("bad GRP d9/5"); |
|
1753 |
switch(rm) { |
|
1754 |
case 0: |
|
1755 |
gen_op_fld1_ST0(); |
|
1756 |
break; |
|
1757 |
case 1: |
|
1758 |
gen_op_fld2t_ST0(); |
|
1759 |
break; |
|
1760 |
case 2: |
|
1761 |
gen_op_fld2e_ST0(); |
|
1762 |
break; |
|
1763 |
case 3: |
|
1764 |
gen_op_fldpi_ST0(); |
|
1765 |
break; |
|
1766 |
case 4: |
|
1767 |
gen_op_fldlg2_ST0(); |
|
1768 |
break; |
|
1769 |
case 5: |
|
1770 |
gen_op_fldln2_ST0(); |
|
1771 |
break; |
|
1772 |
case 6: |
|
1773 |
gen_op_fldz_ST0(); |
|
1774 |
break; |
|
1775 |
default: |
|
1774 | 1776 |
return -1; |
1775 | 1777 |
} |
1776 |
/* XXX: needs constant load or symbol table */ |
|
1777 |
gen_insn0(OP_FPUSH); |
|
1778 |
gen_ld(OP_LDQ, OR_ST0, OR_ZERO, |
|
1779 |
(rm * 8) + FLOAT_CONST_ADDR); |
|
1780 | 1778 |
} |
1781 | 1779 |
break; |
1782 | 1780 |
case 0x0e: /* grp d9/6 */ |
1783 | 1781 |
switch(rm) { |
1784 | 1782 |
case 0: /* f2xm1 */ |
1785 |
gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ZERO);
|
|
1783 |
gen_op_f2xm1();
|
|
1786 | 1784 |
break; |
1787 | 1785 |
case 1: /* fyl2x */ |
1788 |
gen_insn3(OP_FSPECIAL, OR_ST1, OR_ST0, OR_ST1); |
|
1789 |
gen_insn0(OP_FPOP); |
|
1786 |
gen_op_fyl2x(); |
|
1790 | 1787 |
break; |
1791 | 1788 |
case 2: /* fptan */ |
1792 |
gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ZERO); |
|
1793 |
gen_insn0(OP_FPUSH); |
|
1794 |
/* load one */ |
|
1795 |
gen_ld(OP_LDQ, OR_ST0, OR_ZERO, |
|
1796 |
(0 * 8) + FLOAT_CONST_ADDR); |
|
1789 |
gen_op_fptan(); |
|
1797 | 1790 |
break; |
1798 | 1791 |
case 3: /* fpatan */ |
1799 |
gen_insn3(OP_FSPECIAL, OR_ST1, OR_ST0, OR_ST1); |
|
1800 |
gen_insn0(OP_FPOP); |
|
1792 |
gen_op_fpatan(); |
|
1801 | 1793 |
break; |
1802 | 1794 |
case 4: /* fxtract */ |
1803 |
gen_insn0(OP_FPUSH); |
|
1804 |
gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST1, OR_ZERO); |
|
1805 |
gen_insn3(OP_FSPECIAL, OR_ST1, OR_ST1, OR_ZERO); |
|
1795 |
gen_op_fxtract(); |
|
1806 | 1796 |
break; |
1807 | 1797 |
case 5: /* fprem1 */ |
1808 |
gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ST1);
|
|
1798 |
gen_op_fprem1();
|
|
1809 | 1799 |
break; |
1810 | 1800 |
case 6: /* fdecstp */ |
1811 |
gen_insn0(OP_FPUSH);
|
|
1801 |
gen_op_fdecstp();
|
|
1812 | 1802 |
break; |
1813 | 1803 |
default: |
1814 |
case 7: /* fdecstp */
|
|
1815 |
gen_insn0(OP_FPOP);
|
|
1804 |
case 7: /* fincstp */
|
|
1805 |
gen_op_fincstp();
|
|
1816 | 1806 |
break; |
1817 | 1807 |
} |
1818 | 1808 |
break; |
1819 | 1809 |
case 0x0f: /* grp d9/7 */ |
1820 | 1810 |
switch(rm) { |
1821 | 1811 |
case 0: /* fprem */ |
1822 |
gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ST1);
|
|
1812 |
gen_op_fprem();
|
|
1823 | 1813 |
break; |
1824 | 1814 |
case 1: /* fyl2xp1 */ |
1825 |
gen_insn3(OP_FSPECIAL, OR_ST1, OR_ST0, OR_ST1); |
|
1826 |
gen_insn0(OP_FPOP); |
|
1815 |
gen_op_fyl2xp1(); |
|
1816 |
break; |
|
1817 |
case 2: /* fsqrt */ |
|
1818 |
gen_op_fsqrt(); |
|
1827 | 1819 |
break; |
1828 | 1820 |
case 3: /* fsincos */ |
1829 |
gen_insn0(OP_FPUSH); |
|
1830 |
gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST1, OR_ZERO); |
|
1831 |
gen_insn3(OP_FSPECIAL, OR_ST1, OR_ST1, OR_ZERO); |
|
1821 |
gen_op_fsincos(); |
|
1832 | 1822 |
break; |
1833 | 1823 |
case 5: /* fscale */ |
1834 |
gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ST1);
|
|
1824 |
gen_op_fscale();
|
|
1835 | 1825 |
break; |
1836 |
case 2: /* fsqrt */ |
|
1837 | 1826 |
case 4: /* frndint */ |
1827 |
gen_op_frndint(); |
|
1828 |
break; |
|
1838 | 1829 |
case 6: /* fsin */ |
1830 |
gen_op_fsin(); |
|
1831 |
break; |
|
1839 | 1832 |
default: |
1840 | 1833 |
case 7: /* fcos */ |
1841 |
gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ZERO);
|
|
1834 |
gen_op_fcos();
|
|
1842 | 1835 |
break; |
1843 | 1836 |
} |
1844 | 1837 |
break; |
... | ... | |
1846 | 1839 |
case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */ |
1847 | 1840 |
case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */ |
1848 | 1841 |
{ |
1849 |
int op1, swap;
|
|
1842 |
int op1; |
|
1850 | 1843 |
|
1851 |
op1 = fp_ops[op & 7]; |
|
1852 |
swap = 0; |
|
1853 |
if ((op & 7) == 5 || (op & 7) == 7) |
|
1854 |
swap = 1; |
|
1844 |
op1 = op & 7; |
|
1855 | 1845 |
if (op >= 0x20) { |
1856 |
if (swap) |
|
1857 |
gen_insn3(op1, opreg, OR_ST0, opreg); |
|
1858 |
else |
|
1859 |
gen_insn3(op1, opreg, opreg, OR_ST0); |
|
1846 |
gen_op_fp_arith_STN_ST0[op1](opreg); |
|
1860 | 1847 |
} else { |
1861 |
if (swap) |
|
1862 |
gen_insn3(op1, OR_ST0, opreg, OR_ST0); |
|
1863 |
else |
|
1864 |
gen_insn3(op1, OR_ST0, OR_ST0, opreg); |
|
1848 |
gen_op_fmov_FT0_STN(opreg); |
|
1849 |
gen_op_fp_arith_ST0_FT0[op1](); |
|
1865 | 1850 |
} |
1866 | 1851 |
if (op >= 0x30) |
1867 |
gen_insn0(OP_FPOP);
|
|
1852 |
gen_op_fpop();
|
|
1868 | 1853 |
} |
1869 | 1854 |
break; |
1870 | 1855 |
case 0x02: /* fcom */ |
1871 |
gen_insn3(OP_CMP, OR_ZERO, OR_ST0, opreg); |
|
1856 |
gen_op_fmov_FT0_STN(opreg); |
|
1857 |
gen_op_fcom_ST0_FT0(); |
|
1872 | 1858 |
break; |
1873 | 1859 |
case 0x03: /* fcomp */ |
1874 |
gen_insn3(OP_CMP, OR_ZERO, OR_ST0, opreg); |
|
1875 |
gen_insn0(OP_FPOP); |
|
1860 |
gen_op_fmov_FT0_STN(opreg); |
|
1861 |
gen_op_fcom_ST0_FT0(); |
|
1862 |
gen_op_fpop(); |
|
1876 | 1863 |
break; |
1877 | 1864 |
case 0x15: /* da/5 */ |
1878 | 1865 |
switch(rm) { |
1879 | 1866 |
case 1: /* fucompp */ |
1880 |
gen_insn3(OP_CMP, OR_ZERO, OR_ST0, opreg); |
|
1881 |
gen_insn0(OP_FPOP); |
|
1882 |
gen_insn0(OP_FPOP); |
|
1867 |
gen_op_fmov_FT0_STN(1); |
|
1868 |
gen_op_fcom_ST0_FT0(); |
|
1869 |
gen_op_fpop(); |
|
1870 |
gen_op_fpop(); |
|
1883 | 1871 |
break; |
1884 | 1872 |
default: |
1885 | 1873 |
return -1; |
1886 | 1874 |
} |
1887 | 1875 |
break; |
1888 | 1876 |
case 0x2a: /* fst sti */ |
1889 |
gen_mov(opreg, OR_ST0);
|
|
1877 |
gen_op_fmov_STN_ST0(opreg);
|
|
1890 | 1878 |
break; |
1891 | 1879 |
case 0x2b: /* fstp sti */ |
1892 |
gen_mov(opreg, OR_ST0);
|
|
1893 |
gen_insn0(OP_FPOP);
|
|
1880 |
gen_op_fmov_STN_ST0(opreg);
|
|
1881 |
gen_op_fpop();
|
|
1894 | 1882 |
break; |
1895 | 1883 |
case 0x33: /* de/3 */ |
1896 | 1884 |
switch(rm) { |
1897 | 1885 |
case 1: /* fcompp */ |
1898 |
gen_insn3(OP_CMP, OR_ZERO, OR_ST0, opreg); |
|
1899 |
gen_insn0(OP_FPOP); |
|
1900 |
gen_insn0(OP_FPOP); |
|
1886 |
gen_op_fmov_FT0_STN(1); |
|
1887 |
gen_op_fcom_ST0_FT0(); |
|
1888 |
gen_op_fpop(); |
|
1889 |
gen_op_fpop(); |
|
1901 | 1890 |
break; |
1902 | 1891 |
default: |
1903 | 1892 |
return -1; |
... | ... | |
1905 | 1894 |
break; |
1906 | 1895 |
case 0x3c: /* df/4 */ |
1907 | 1896 |
switch(rm) { |
1897 |
#if 0 |
|
1908 | 1898 |
case 0: |
1909 | 1899 |
gen_insn3(OP_FNSTS, OR_EAX, OR_ZERO, OR_ZERO); |
1910 | 1900 |
break; |
1901 |
#endif |
|
1911 | 1902 |
default: |
1912 | 1903 |
return -1; |
1913 | 1904 |
} |
... | ... | |
1918 | 1909 |
} |
1919 | 1910 |
} |
1920 | 1911 |
break; |
1921 |
#endif |
|
1922 | 1912 |
/************************/ |
1923 | 1913 |
/* string ops */ |
1924 | 1914 |
case 0xa4: /* movsS */ |
Also available in: Unified diff