master
c 305 lines 9.36 KB
Raw
1 /////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2001-2012 The Bochs Project
4 // Copyright (C) 2017 Google Inc.
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library 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 GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, see
18 // <https://www.gnu.org/licenses/>.
19 /////////////////////////////////////////////////////////////////////////
20 /*
21 * flags functions
22 */
23
24 #include "qemu/osdep.h"
25
26 #include "panic.h"
27 #include "cpu.h"
28 #include "x86_flags.h"
29 #include "x86.h"
30
31
32 /*
33 * The emulator always encodes flags in the same way as CC_OP_CCMPB + MO_TL.
34 * While for arithmetic operations ZF/SF/PF are computed from the same value,
35 * ZF=1 may be inconsistent with PF/SF for arbitrary RFLAGS values so CC_SRC2
36 * is used for SF and PF. CC_SRC holds a carry-out vector that is used to
37 * compute AF, CF and OF.
38 *
39 * Compared to the TCG CC_OP codes, this avoids conditionals when converting
40 * to and from the RFLAGS representation.
41 *
42 * The underlying ideas ultimately descend from Bochs, but with significant
43 * simplifications obtained by storing flags in three words rather than two.
44 */
45
46 #define LF_SIGN_BIT (TARGET_LONG_BITS - 1)
47
48 #define LF_BIT_CF (TARGET_LONG_BITS - 1) /* lazy Carry Flag */
49 #define LF_BIT_PO (TARGET_LONG_BITS - 2) /* lazy Partial Overflow = CF ^ OF */
50
51 #define LF_MASK_CF ((target_ulong)0x01 << LF_BIT_CF)
52 #define LF_MASK_PO ((target_ulong)0x01 << LF_BIT_PO)
53
54 /* ******************* */
55 /* OSZAPC */
56 /* ******************* */
57
58 /*
59 * For arithmetic operations ZF/SF/PF are consistent so DST == SRC2.
60 * For operations that are not full-word, keep AF in the low byte and shift
61 * the carries left to place PO and CF in the top two bits.
62 */
63 #define SET_FLAGS_OSZAPC_SIZE(size, lf_carries, lf_result) { \
64 env->cc_dst = env->cc_src2 = (target_ulong)(int##size##_t)(lf_result); \
65 target_ulong temp = (lf_carries) & MAKE_64BIT_MASK(0, size); \
66 temp |= temp << (TARGET_LONG_BITS - (size)); \
67 env->cc_src = temp; \
68 }
69
70 /* carries, result */
71 #define SET_FLAGS_OSZAPC_8(carries, result) \
72 SET_FLAGS_OSZAPC_SIZE(8, carries, result)
73 #define SET_FLAGS_OSZAPC_16(carries, result) \
74 SET_FLAGS_OSZAPC_SIZE(16, carries, result)
75 #define SET_FLAGS_OSZAPC_32(carries, result) \
76 SET_FLAGS_OSZAPC_SIZE(32, carries, result)
77 #ifdef TARGET_X86_64
78 #define SET_FLAGS_OSZAPC_64(carries, result) \
79 SET_FLAGS_OSZAPC_SIZE(64, carries, result)
80 #endif
81
82 /* ******************* */
83 /* OSZAP */
84 /* ******************* */
85 /* same as setting OSZAPC, but preserve CF and flip PO if the old value of CF
86 * did not match the high bit of lf_carries. */
87 #define SET_FLAGS_OSZAP_SIZE(size, lf_carries, lf_result) { \
88 env->cc_dst = env->cc_src2 = (target_ulong)(int##size##_t)(lf_result); \
89 target_ulong temp = (lf_carries) & MAKE_64BIT_MASK(0, size); \
90 temp |= temp << (TARGET_LONG_BITS - (size)); \
91 target_ulong cf_changed = ((target_long)(env->cc_src ^ temp)) < 0; \
92 env->cc_src = temp ^ (cf_changed * (LF_MASK_PO | LF_MASK_CF)); \
93 }
94
95 /* carries, result */
96 #define SET_FLAGS_OSZAP_8(carries, result) \
97 SET_FLAGS_OSZAP_SIZE(8, carries, result)
98 #define SET_FLAGS_OSZAP_16(carries, result) \
99 SET_FLAGS_OSZAP_SIZE(16, carries, result)
100 #define SET_FLAGS_OSZAP_32(carries, result) \
101 SET_FLAGS_OSZAP_SIZE(32, carries, result)
102 #ifdef TARGET_X86_64
103 #define SET_FLAGS_OSZAP_64(carries, result) \
104 SET_FLAGS_OSZAP_SIZE(64, carries, result)
105 #endif
106
107 void SET_FLAGS_OxxxxC(CPUX86State *env, bool new_of, bool new_cf)
108 {
109 env->cc_src &= ~(LF_MASK_PO | LF_MASK_CF);
110 env->cc_src |= (-(target_ulong)new_cf << LF_BIT_PO);
111 env->cc_src ^= ((target_ulong)new_of << LF_BIT_PO);
112 }
113
114 #ifdef TARGET_X86_64
115 void SET_FLAGS_OSZAPC_SUB64(CPUX86State *env, uint64_t v1, uint64_t v2,
116 uint64_t diff)
117 {
118 SET_FLAGS_OSZAPC_64(SUB_COUT_VEC(v1, v2, diff), diff);
119 }
120 #endif
121
122 void SET_FLAGS_OSZAPC_SUB32(CPUX86State *env, uint32_t v1, uint32_t v2,
123 uint32_t diff)
124 {
125 SET_FLAGS_OSZAPC_32(SUB_COUT_VEC(v1, v2, diff), diff);
126 }
127
128 void SET_FLAGS_OSZAPC_SUB16(CPUX86State *env, uint16_t v1, uint16_t v2,
129 uint16_t diff)
130 {
131 SET_FLAGS_OSZAPC_16(SUB_COUT_VEC(v1, v2, diff), diff);
132 }
133
134 void SET_FLAGS_OSZAPC_SUB8(CPUX86State *env, uint8_t v1, uint8_t v2,
135 uint8_t diff)
136 {
137 SET_FLAGS_OSZAPC_8(SUB_COUT_VEC(v1, v2, diff), diff);
138 }
139
140 #ifdef TARGET_X86_64
141 void SET_FLAGS_OSZAPC_ADD64(CPUX86State *env, uint64_t v1, uint64_t v2,
142 uint64_t diff)
143 {
144 SET_FLAGS_OSZAPC_64(ADD_COUT_VEC(v1, v2, diff), diff);
145 }
146 #endif
147
148 void SET_FLAGS_OSZAPC_ADD32(CPUX86State *env, uint32_t v1, uint32_t v2,
149 uint32_t diff)
150 {
151 SET_FLAGS_OSZAPC_32(ADD_COUT_VEC(v1, v2, diff), diff);
152 }
153
154 void SET_FLAGS_OSZAPC_ADD16(CPUX86State *env, uint16_t v1, uint16_t v2,
155 uint16_t diff)
156 {
157 SET_FLAGS_OSZAPC_16(ADD_COUT_VEC(v1, v2, diff), diff);
158 }
159
160 void SET_FLAGS_OSZAPC_ADD8(CPUX86State *env, uint8_t v1, uint8_t v2,
161 uint8_t diff)
162 {
163 SET_FLAGS_OSZAPC_8(ADD_COUT_VEC(v1, v2, diff), diff);
164 }
165
166 #ifdef TARGET_X86_64
167 void SET_FLAGS_OSZAP_SUB64(CPUX86State *env, uint64_t v1, uint64_t v2,
168 uint64_t diff)
169 {
170 SET_FLAGS_OSZAP_64(SUB_COUT_VEC(v1, v2, diff), diff);
171 }
172 #endif
173
174 void SET_FLAGS_OSZAP_SUB32(CPUX86State *env, uint32_t v1, uint32_t v2,
175 uint32_t diff)
176 {
177 SET_FLAGS_OSZAP_32(SUB_COUT_VEC(v1, v2, diff), diff);
178 }
179
180 void SET_FLAGS_OSZAP_SUB16(CPUX86State *env, uint16_t v1, uint16_t v2,
181 uint16_t diff)
182 {
183 SET_FLAGS_OSZAP_16(SUB_COUT_VEC(v1, v2, diff), diff);
184 }
185
186 void SET_FLAGS_OSZAP_SUB8(CPUX86State *env, uint8_t v1, uint8_t v2,
187 uint8_t diff)
188 {
189 SET_FLAGS_OSZAP_8(SUB_COUT_VEC(v1, v2, diff), diff);
190 }
191
192 #ifdef TARGET_X86_64
193 void SET_FLAGS_OSZAP_ADD64(CPUX86State *env, uint64_t v1, uint64_t v2,
194 uint64_t diff)
195 {
196 SET_FLAGS_OSZAP_64(ADD_COUT_VEC(v1, v2, diff), diff);
197 }
198 #endif
199
200 void SET_FLAGS_OSZAP_ADD32(CPUX86State *env, uint32_t v1, uint32_t v2,
201 uint32_t diff)
202 {
203 SET_FLAGS_OSZAP_32(ADD_COUT_VEC(v1, v2, diff), diff);
204 }
205
206 void SET_FLAGS_OSZAP_ADD16(CPUX86State *env, uint16_t v1, uint16_t v2,
207 uint16_t diff)
208 {
209 SET_FLAGS_OSZAP_16(ADD_COUT_VEC(v1, v2, diff), diff);
210 }
211
212 void SET_FLAGS_OSZAP_ADD8(CPUX86State *env, uint8_t v1, uint8_t v2,
213 uint8_t diff)
214 {
215 SET_FLAGS_OSZAP_8(ADD_COUT_VEC(v1, v2, diff), diff);
216 }
217
218 #ifdef TARGET_X86_64
219 void SET_FLAGS_OSZAPC_LOGIC64(CPUX86State *env, uint64_t v1, uint64_t v2,
220 uint64_t diff)
221 {
222 SET_FLAGS_OSZAPC_64(0, diff);
223 }
224 #endif
225
226 void SET_FLAGS_OSZAPC_LOGIC32(CPUX86State *env, uint32_t v1, uint32_t v2,
227 uint32_t diff)
228 {
229 SET_FLAGS_OSZAPC_32(0, diff);
230 }
231
232 void SET_FLAGS_OSZAPC_LOGIC16(CPUX86State *env, uint16_t v1, uint16_t v2,
233 uint16_t diff)
234 {
235 SET_FLAGS_OSZAPC_16(0, diff);
236 }
237
238 void SET_FLAGS_OSZAPC_LOGIC8(CPUX86State *env, uint8_t v1, uint8_t v2,
239 uint8_t diff)
240 {
241 SET_FLAGS_OSZAPC_8(0, diff);
242 }
243
244 static inline uint32_t get_PF(CPUX86State *env)
245 {
246 return (parity8(env->cc_src2) - 1) & CC_P;
247 }
248
249 static inline uint32_t get_OF(CPUX86State *env)
250 {
251 return ((env->cc_src >> (LF_BIT_CF - 11)) + CC_O / 2) & CC_O;
252 }
253
254 bool get_CF(CPUX86State *env)
255 {
256 return ((target_long)env->cc_src) < 0;
257 }
258
259 void set_CF(CPUX86State *env, bool val)
260 {
261 /* If CF changes, flip PO and CF */
262 target_ulong temp = -(target_ulong)val;
263 target_ulong cf_changed = ((target_long)(env->cc_src ^ temp)) < 0;
264 env->cc_src ^= cf_changed * (LF_MASK_PO | LF_MASK_CF);
265 }
266
267 static inline uint32_t get_ZF(CPUX86State *env)
268 {
269 return env->cc_dst ? 0 : CC_Z;
270 }
271
272 static inline uint32_t get_SF(CPUX86State *env)
273 {
274 return (target_long)env->cc_src2 < 0 ? CC_S : 0;
275 }
276
277 void lflags_to_rflags(CPUX86State *env)
278 {
279 env->eflags &= ~(CC_C|CC_P|CC_A|CC_Z|CC_S|CC_O);
280 /* rotate left by one to move carry-out bits into CF and AF */
281 env->eflags |= (
282 (env->cc_src << 1) |
283 (env->cc_src >> (TARGET_LONG_BITS - 1))) & (CC_C | CC_A);
284 env->eflags |= get_SF(env);
285 env->eflags |= get_PF(env);
286 env->eflags |= get_ZF(env);
287 env->eflags |= get_OF(env);
288 }
289
290 void rflags_to_lflags(CPUX86State *env)
291 {
292 target_ulong cf_af, cf_xor_of;
293
294 /* compute DST and SRC2 that reconstruct ZF/SF/PF. */
295 env->cc_dst = ~env->eflags & CC_Z; /* DST = 0 if ZF=1 */
296 env->cc_src2 = ~env->eflags & CC_P; /* odd parity if PF=0 */
297 env->cc_src2 ^= -!!(env->eflags & CC_S);
298
299 /* rotate right by one to move CF and AF into the carry-out positions */
300 cf_af = env->eflags & (CC_C | CC_A);
301 env->cc_src = ((cf_af >> 1) | (cf_af << (TARGET_LONG_BITS - 1)));
302
303 cf_xor_of = ((env->eflags & (CC_C | CC_O)) + (CC_O - CC_C)) & CC_O;
304 env->cc_src |= -cf_xor_of & LF_MASK_PO;
305 }