Commit 927f621e7960d3fcf51eecf65ee19b1aafc102ae
1 parent
367e86e8
added float support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@15 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
6 changed files
with
934 additions
and
160 deletions
Makefile
... | ... | @@ -8,6 +8,7 @@ LDFLAGS=-g |
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,6 +25,7 @@ CRTEND=$(GCC_LIBS_DIR)/crtend.o |
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,7 +33,7 @@ endif |
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,7 +69,7 @@ op-i386.h: op-i386.o dyngen |
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 $@ $< | ... | ... |
TODO
cpu-i386.h
... | ... | @@ -75,6 +75,16 @@ enum { |
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,10 +101,18 @@ typedef struct CPU86State { |
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,6 +140,10 @@ static inline int ldl(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,11 +160,40 @@ static inline void stl(void *ptr, int v) |
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 */ | ... | ... |
dyngen.c
... | ... | @@ -243,6 +243,8 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, |
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,6 +259,8 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, |
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 | } | ... | ... |
op-i386.c
... | ... | @@ -66,7 +66,13 @@ register struct CPU86State *env asm("l3"); |
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,6 +139,44 @@ const uint8_t rclb_table[32] = { |
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,3 +910,685 @@ CCTable cc_table[CC_OP_NB] = { |
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 | + | ... | ... |
translate-i386.c
... | ... | @@ -5,6 +5,7 @@ |
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,7 +40,6 @@ typedef struct DisasContext { |
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,18 +68,6 @@ enum { |
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,6 +594,28 @@ static GenOpFunc *gen_setcc_sub[3][8] = { |
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,12 +1355,12 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) |
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,7 +1591,6 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) |
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,52 +1606,29 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) |
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,49 +1645,47 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) |
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,15 +1695,14 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) |
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,22 +1710,19 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) |
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,16 +1732,17 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) |
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,76 +1750,88 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) |
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,58 +1839,54 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) |
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,9 +1894,11 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) |
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,7 +1909,6 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) |
1918 | 1909 | } |
1919 | 1910 | } |
1920 | 1911 | break; |
1921 | -#endif | |
1922 | 1912 | /************************/ |
1923 | 1913 | /* string ops */ |
1924 | 1914 | case 0xa4: /* movsS */ | ... | ... |