These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / target-sparc / cc_helper.c
1 /*
2  * Helpers for lazy condition code handling
3  *
4  *  Copyright (c) 2003-2005 Fabrice Bellard
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 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 <http://www.gnu.org/licenses/>.
18  */
19
20 #include "qemu/osdep.h"
21 #include "cpu.h"
22 #include "exec/helper-proto.h"
23
24 static uint32_t compute_all_flags(CPUSPARCState *env)
25 {
26     return env->psr & PSR_ICC;
27 }
28
29 static uint32_t compute_C_flags(CPUSPARCState *env)
30 {
31     return env->psr & PSR_CARRY;
32 }
33
34 static inline uint32_t get_NZ_icc(int32_t dst)
35 {
36     uint32_t ret = 0;
37
38     if (dst == 0) {
39         ret = PSR_ZERO;
40     } else if (dst < 0) {
41         ret = PSR_NEG;
42     }
43     return ret;
44 }
45
46 #ifdef TARGET_SPARC64
47 static uint32_t compute_all_flags_xcc(CPUSPARCState *env)
48 {
49     return env->xcc & PSR_ICC;
50 }
51
52 static uint32_t compute_C_flags_xcc(CPUSPARCState *env)
53 {
54     return env->xcc & PSR_CARRY;
55 }
56
57 static inline uint32_t get_NZ_xcc(target_long dst)
58 {
59     uint32_t ret = 0;
60
61     if (!dst) {
62         ret = PSR_ZERO;
63     } else if (dst < 0) {
64         ret = PSR_NEG;
65     }
66     return ret;
67 }
68 #endif
69
70 static inline uint32_t get_V_div_icc(target_ulong src2)
71 {
72     uint32_t ret = 0;
73
74     if (src2 != 0) {
75         ret = PSR_OVF;
76     }
77     return ret;
78 }
79
80 static uint32_t compute_all_div(CPUSPARCState *env)
81 {
82     uint32_t ret;
83
84     ret = get_NZ_icc(CC_DST);
85     ret |= get_V_div_icc(CC_SRC2);
86     return ret;
87 }
88
89 static uint32_t compute_C_div(CPUSPARCState *env)
90 {
91     return 0;
92 }
93
94 static inline uint32_t get_C_add_icc(uint32_t dst, uint32_t src1)
95 {
96     uint32_t ret = 0;
97
98     if (dst < src1) {
99         ret = PSR_CARRY;
100     }
101     return ret;
102 }
103
104 static inline uint32_t get_C_addx_icc(uint32_t dst, uint32_t src1,
105                                       uint32_t src2)
106 {
107     uint32_t ret = 0;
108
109     if (((src1 & src2) | (~dst & (src1 | src2))) & (1U << 31)) {
110         ret = PSR_CARRY;
111     }
112     return ret;
113 }
114
115 static inline uint32_t get_V_add_icc(uint32_t dst, uint32_t src1,
116                                      uint32_t src2)
117 {
118     uint32_t ret = 0;
119
120     if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1U << 31)) {
121         ret = PSR_OVF;
122     }
123     return ret;
124 }
125
126 #ifdef TARGET_SPARC64
127 static inline uint32_t get_C_add_xcc(target_ulong dst, target_ulong src1)
128 {
129     uint32_t ret = 0;
130
131     if (dst < src1) {
132         ret = PSR_CARRY;
133     }
134     return ret;
135 }
136
137 static inline uint32_t get_C_addx_xcc(target_ulong dst, target_ulong src1,
138                                       target_ulong src2)
139 {
140     uint32_t ret = 0;
141
142     if (((src1 & src2) | (~dst & (src1 | src2))) & (1ULL << 63)) {
143         ret = PSR_CARRY;
144     }
145     return ret;
146 }
147
148 static inline uint32_t get_V_add_xcc(target_ulong dst, target_ulong src1,
149                                      target_ulong src2)
150 {
151     uint32_t ret = 0;
152
153     if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 63)) {
154         ret = PSR_OVF;
155     }
156     return ret;
157 }
158
159 static uint32_t compute_all_add_xcc(CPUSPARCState *env)
160 {
161     uint32_t ret;
162
163     ret = get_NZ_xcc(CC_DST);
164     ret |= get_C_add_xcc(CC_DST, CC_SRC);
165     ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
166     return ret;
167 }
168
169 static uint32_t compute_C_add_xcc(CPUSPARCState *env)
170 {
171     return get_C_add_xcc(CC_DST, CC_SRC);
172 }
173 #endif
174
175 static uint32_t compute_all_add(CPUSPARCState *env)
176 {
177     uint32_t ret;
178
179     ret = get_NZ_icc(CC_DST);
180     ret |= get_C_add_icc(CC_DST, CC_SRC);
181     ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
182     return ret;
183 }
184
185 static uint32_t compute_C_add(CPUSPARCState *env)
186 {
187     return get_C_add_icc(CC_DST, CC_SRC);
188 }
189
190 #ifdef TARGET_SPARC64
191 static uint32_t compute_all_addx_xcc(CPUSPARCState *env)
192 {
193     uint32_t ret;
194
195     ret = get_NZ_xcc(CC_DST);
196     ret |= get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
197     ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
198     return ret;
199 }
200
201 static uint32_t compute_C_addx_xcc(CPUSPARCState *env)
202 {
203     uint32_t ret;
204
205     ret = get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
206     return ret;
207 }
208 #endif
209
210 static uint32_t compute_all_addx(CPUSPARCState *env)
211 {
212     uint32_t ret;
213
214     ret = get_NZ_icc(CC_DST);
215     ret |= get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
216     ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
217     return ret;
218 }
219
220 static uint32_t compute_C_addx(CPUSPARCState *env)
221 {
222     uint32_t ret;
223
224     ret = get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
225     return ret;
226 }
227
228 static inline uint32_t get_V_tag_icc(target_ulong src1, target_ulong src2)
229 {
230     uint32_t ret = 0;
231
232     if ((src1 | src2) & 0x3) {
233         ret = PSR_OVF;
234     }
235     return ret;
236 }
237
238 static uint32_t compute_all_tadd(CPUSPARCState *env)
239 {
240     uint32_t ret;
241
242     ret = get_NZ_icc(CC_DST);
243     ret |= get_C_add_icc(CC_DST, CC_SRC);
244     ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
245     ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
246     return ret;
247 }
248
249 static uint32_t compute_all_taddtv(CPUSPARCState *env)
250 {
251     uint32_t ret;
252
253     ret = get_NZ_icc(CC_DST);
254     ret |= get_C_add_icc(CC_DST, CC_SRC);
255     return ret;
256 }
257
258 static inline uint32_t get_C_sub_icc(uint32_t src1, uint32_t src2)
259 {
260     uint32_t ret = 0;
261
262     if (src1 < src2) {
263         ret = PSR_CARRY;
264     }
265     return ret;
266 }
267
268 static inline uint32_t get_C_subx_icc(uint32_t dst, uint32_t src1,
269                                       uint32_t src2)
270 {
271     uint32_t ret = 0;
272
273     if (((~src1 & src2) | (dst & (~src1 | src2))) & (1U << 31)) {
274         ret = PSR_CARRY;
275     }
276     return ret;
277 }
278
279 static inline uint32_t get_V_sub_icc(uint32_t dst, uint32_t src1,
280                                      uint32_t src2)
281 {
282     uint32_t ret = 0;
283
284     if (((src1 ^ src2) & (src1 ^ dst)) & (1U << 31)) {
285         ret = PSR_OVF;
286     }
287     return ret;
288 }
289
290
291 #ifdef TARGET_SPARC64
292 static inline uint32_t get_C_sub_xcc(target_ulong src1, target_ulong src2)
293 {
294     uint32_t ret = 0;
295
296     if (src1 < src2) {
297         ret = PSR_CARRY;
298     }
299     return ret;
300 }
301
302 static inline uint32_t get_C_subx_xcc(target_ulong dst, target_ulong src1,
303                                       target_ulong src2)
304 {
305     uint32_t ret = 0;
306
307     if (((~src1 & src2) | (dst & (~src1 | src2))) & (1ULL << 63)) {
308         ret = PSR_CARRY;
309     }
310     return ret;
311 }
312
313 static inline uint32_t get_V_sub_xcc(target_ulong dst, target_ulong src1,
314                                      target_ulong src2)
315 {
316     uint32_t ret = 0;
317
318     if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 63)) {
319         ret = PSR_OVF;
320     }
321     return ret;
322 }
323
324 static uint32_t compute_all_sub_xcc(CPUSPARCState *env)
325 {
326     uint32_t ret;
327
328     ret = get_NZ_xcc(CC_DST);
329     ret |= get_C_sub_xcc(CC_SRC, CC_SRC2);
330     ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
331     return ret;
332 }
333
334 static uint32_t compute_C_sub_xcc(CPUSPARCState *env)
335 {
336     return get_C_sub_xcc(CC_SRC, CC_SRC2);
337 }
338 #endif
339
340 static uint32_t compute_all_sub(CPUSPARCState *env)
341 {
342     uint32_t ret;
343
344     ret = get_NZ_icc(CC_DST);
345     ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
346     ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
347     return ret;
348 }
349
350 static uint32_t compute_C_sub(CPUSPARCState *env)
351 {
352     return get_C_sub_icc(CC_SRC, CC_SRC2);
353 }
354
355 #ifdef TARGET_SPARC64
356 static uint32_t compute_all_subx_xcc(CPUSPARCState *env)
357 {
358     uint32_t ret;
359
360     ret = get_NZ_xcc(CC_DST);
361     ret |= get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
362     ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
363     return ret;
364 }
365
366 static uint32_t compute_C_subx_xcc(CPUSPARCState *env)
367 {
368     uint32_t ret;
369
370     ret = get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
371     return ret;
372 }
373 #endif
374
375 static uint32_t compute_all_subx(CPUSPARCState *env)
376 {
377     uint32_t ret;
378
379     ret = get_NZ_icc(CC_DST);
380     ret |= get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
381     ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
382     return ret;
383 }
384
385 static uint32_t compute_C_subx(CPUSPARCState *env)
386 {
387     uint32_t ret;
388
389     ret = get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
390     return ret;
391 }
392
393 static uint32_t compute_all_tsub(CPUSPARCState *env)
394 {
395     uint32_t ret;
396
397     ret = get_NZ_icc(CC_DST);
398     ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
399     ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
400     ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
401     return ret;
402 }
403
404 static uint32_t compute_all_tsubtv(CPUSPARCState *env)
405 {
406     uint32_t ret;
407
408     ret = get_NZ_icc(CC_DST);
409     ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
410     return ret;
411 }
412
413 static uint32_t compute_all_logic(CPUSPARCState *env)
414 {
415     return get_NZ_icc(CC_DST);
416 }
417
418 static uint32_t compute_C_logic(CPUSPARCState *env)
419 {
420     return 0;
421 }
422
423 #ifdef TARGET_SPARC64
424 static uint32_t compute_all_logic_xcc(CPUSPARCState *env)
425 {
426     return get_NZ_xcc(CC_DST);
427 }
428 #endif
429
430 typedef struct CCTable {
431     uint32_t (*compute_all)(CPUSPARCState *env); /* return all the flags */
432     uint32_t (*compute_c)(CPUSPARCState *env);  /* return the C flag */
433 } CCTable;
434
435 static const CCTable icc_table[CC_OP_NB] = {
436     /* CC_OP_DYNAMIC should never happen */
437     [CC_OP_FLAGS] = { compute_all_flags, compute_C_flags },
438     [CC_OP_DIV] = { compute_all_div, compute_C_div },
439     [CC_OP_ADD] = { compute_all_add, compute_C_add },
440     [CC_OP_ADDX] = { compute_all_addx, compute_C_addx },
441     [CC_OP_TADD] = { compute_all_tadd, compute_C_add },
442     [CC_OP_TADDTV] = { compute_all_taddtv, compute_C_add },
443     [CC_OP_SUB] = { compute_all_sub, compute_C_sub },
444     [CC_OP_SUBX] = { compute_all_subx, compute_C_subx },
445     [CC_OP_TSUB] = { compute_all_tsub, compute_C_sub },
446     [CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_sub },
447     [CC_OP_LOGIC] = { compute_all_logic, compute_C_logic },
448 };
449
450 #ifdef TARGET_SPARC64
451 static const CCTable xcc_table[CC_OP_NB] = {
452     /* CC_OP_DYNAMIC should never happen */
453     [CC_OP_FLAGS] = { compute_all_flags_xcc, compute_C_flags_xcc },
454     [CC_OP_DIV] = { compute_all_logic_xcc, compute_C_logic },
455     [CC_OP_ADD] = { compute_all_add_xcc, compute_C_add_xcc },
456     [CC_OP_ADDX] = { compute_all_addx_xcc, compute_C_addx_xcc },
457     [CC_OP_TADD] = { compute_all_add_xcc, compute_C_add_xcc },
458     [CC_OP_TADDTV] = { compute_all_add_xcc, compute_C_add_xcc },
459     [CC_OP_SUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
460     [CC_OP_SUBX] = { compute_all_subx_xcc, compute_C_subx_xcc },
461     [CC_OP_TSUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
462     [CC_OP_TSUBTV] = { compute_all_sub_xcc, compute_C_sub_xcc },
463     [CC_OP_LOGIC] = { compute_all_logic_xcc, compute_C_logic },
464 };
465 #endif
466
467 void helper_compute_psr(CPUSPARCState *env)
468 {
469     uint32_t new_psr;
470
471     new_psr = icc_table[CC_OP].compute_all(env);
472     env->psr = new_psr;
473 #ifdef TARGET_SPARC64
474     new_psr = xcc_table[CC_OP].compute_all(env);
475     env->xcc = new_psr;
476 #endif
477     CC_OP = CC_OP_FLAGS;
478 }
479
480 uint32_t helper_compute_C_icc(CPUSPARCState *env)
481 {
482     uint32_t ret;
483
484     ret = icc_table[CC_OP].compute_c(env) >> PSR_CARRY_SHIFT;
485     return ret;
486 }