target-s390x: avoid AREG0 for FPU helpers
[sdk/emulator/qemu.git] / target-s390x / cc_helper.c
1 /*
2  *  S/390 condition code helper routines
3  *
4  *  Copyright (c) 2009 Ulrich Hecht
5  *  Copyright (c) 2009 Alexander Graf
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "cpu.h"
22 #include "dyngen-exec.h"
23 #include "helper.h"
24
25 /* #define DEBUG_HELPER */
26 #ifdef DEBUG_HELPER
27 #define HELPER_LOG(x...) qemu_log(x)
28 #else
29 #define HELPER_LOG(x...)
30 #endif
31
32 static inline uint32_t cc_calc_ltgt_32(CPUS390XState *env, int32_t src,
33                                        int32_t dst)
34 {
35     if (src == dst) {
36         return 0;
37     } else if (src < dst) {
38         return 1;
39     } else {
40         return 2;
41     }
42 }
43
44 static inline uint32_t cc_calc_ltgt0_32(CPUS390XState *env, int32_t dst)
45 {
46     return cc_calc_ltgt_32(env, dst, 0);
47 }
48
49 static inline uint32_t cc_calc_ltgt_64(CPUS390XState *env, int64_t src,
50                                        int64_t dst)
51 {
52     if (src == dst) {
53         return 0;
54     } else if (src < dst) {
55         return 1;
56     } else {
57         return 2;
58     }
59 }
60
61 static inline uint32_t cc_calc_ltgt0_64(CPUS390XState *env, int64_t dst)
62 {
63     return cc_calc_ltgt_64(env, dst, 0);
64 }
65
66 static inline uint32_t cc_calc_ltugtu_32(CPUS390XState *env, uint32_t src,
67                                          uint32_t dst)
68 {
69     if (src == dst) {
70         return 0;
71     } else if (src < dst) {
72         return 1;
73     } else {
74         return 2;
75     }
76 }
77
78 static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src,
79                                          uint64_t dst)
80 {
81     if (src == dst) {
82         return 0;
83     } else if (src < dst) {
84         return 1;
85     } else {
86         return 2;
87     }
88 }
89
90 static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val,
91                                      uint32_t mask)
92 {
93     uint16_t r = val & mask;
94
95     HELPER_LOG("%s: val 0x%x mask 0x%x\n", __func__, val, mask);
96     if (r == 0 || mask == 0) {
97         return 0;
98     } else if (r == mask) {
99         return 3;
100     } else {
101         return 1;
102     }
103 }
104
105 /* set condition code for test under mask */
106 static inline uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val,
107                                      uint32_t mask)
108 {
109     uint16_t r = val & mask;
110
111     HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __func__, val, mask, r);
112     if (r == 0 || mask == 0) {
113         return 0;
114     } else if (r == mask) {
115         return 3;
116     } else {
117         while (!(mask & 0x8000)) {
118             mask <<= 1;
119             val <<= 1;
120         }
121         if (val & 0x8000) {
122             return 2;
123         } else {
124             return 1;
125         }
126     }
127 }
128
129 static inline uint32_t cc_calc_nz(CPUS390XState *env, uint64_t dst)
130 {
131     return !!dst;
132 }
133
134 static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1,
135                                       int64_t a2, int64_t ar)
136 {
137     if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
138         return 3; /* overflow */
139     } else {
140         if (ar < 0) {
141             return 1;
142         } else if (ar > 0) {
143             return 2;
144         } else {
145             return 0;
146         }
147     }
148 }
149
150 static inline uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1,
151                                        uint64_t a2, uint64_t ar)
152 {
153     if (ar == 0) {
154         if (a1) {
155             return 2;
156         } else {
157             return 0;
158         }
159     } else {
160         if (ar < a1 || ar < a2) {
161             return 3;
162         } else {
163             return 1;
164         }
165     }
166 }
167
168 static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1,
169                                       int64_t a2, int64_t ar)
170 {
171     if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
172         return 3; /* overflow */
173     } else {
174         if (ar < 0) {
175             return 1;
176         } else if (ar > 0) {
177             return 2;
178         } else {
179             return 0;
180         }
181     }
182 }
183
184 static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1,
185                                        uint64_t a2, uint64_t ar)
186 {
187     if (ar == 0) {
188         return 2;
189     } else {
190         if (a2 > a1) {
191             return 1;
192         } else {
193             return 3;
194         }
195     }
196 }
197
198 static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst)
199 {
200     if ((uint64_t)dst == 0x8000000000000000ULL) {
201         return 3;
202     } else if (dst) {
203         return 1;
204     } else {
205         return 0;
206     }
207 }
208
209 static inline uint32_t cc_calc_nabs_64(CPUS390XState *env, int64_t dst)
210 {
211     return !!dst;
212 }
213
214 static inline uint32_t cc_calc_comp_64(CPUS390XState *env, int64_t dst)
215 {
216     if ((uint64_t)dst == 0x8000000000000000ULL) {
217         return 3;
218     } else if (dst < 0) {
219         return 1;
220     } else if (dst > 0) {
221         return 2;
222     } else {
223         return 0;
224     }
225 }
226
227
228 static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1,
229                                       int32_t a2, int32_t ar)
230 {
231     if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
232         return 3; /* overflow */
233     } else {
234         if (ar < 0) {
235             return 1;
236         } else if (ar > 0) {
237             return 2;
238         } else {
239             return 0;
240         }
241     }
242 }
243
244 static inline uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1,
245                                        uint32_t a2, uint32_t ar)
246 {
247     if (ar == 0) {
248         if (a1) {
249             return 2;
250         } else {
251             return 0;
252         }
253     } else {
254         if (ar < a1 || ar < a2) {
255             return 3;
256         } else {
257             return 1;
258         }
259     }
260 }
261
262 static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1,
263                                       int32_t a2, int32_t ar)
264 {
265     if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
266         return 3; /* overflow */
267     } else {
268         if (ar < 0) {
269             return 1;
270         } else if (ar > 0) {
271             return 2;
272         } else {
273             return 0;
274         }
275     }
276 }
277
278 static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1,
279                                        uint32_t a2, uint32_t ar)
280 {
281     if (ar == 0) {
282         return 2;
283     } else {
284         if (a2 > a1) {
285             return 1;
286         } else {
287             return 3;
288         }
289     }
290 }
291
292 static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst)
293 {
294     if ((uint32_t)dst == 0x80000000UL) {
295         return 3;
296     } else if (dst) {
297         return 1;
298     } else {
299         return 0;
300     }
301 }
302
303 static inline uint32_t cc_calc_nabs_32(CPUS390XState *env, int32_t dst)
304 {
305     return !!dst;
306 }
307
308 static inline uint32_t cc_calc_comp_32(CPUS390XState *env, int32_t dst)
309 {
310     if ((uint32_t)dst == 0x80000000UL) {
311         return 3;
312     } else if (dst < 0) {
313         return 1;
314     } else if (dst > 0) {
315         return 2;
316     } else {
317         return 0;
318     }
319 }
320
321 /* calculate condition code for insert character under mask insn */
322 static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask,
323                                       uint32_t val)
324 {
325     uint32_t cc;
326
327     HELPER_LOG("%s: mask 0x%x val %d\n", __func__, mask, val);
328     if (mask == 0xf) {
329         if (!val) {
330             return 0;
331         } else if (val & 0x80000000) {
332             return 1;
333         } else {
334             return 2;
335         }
336     }
337
338     if (!val || !mask) {
339         cc = 0;
340     } else {
341         while (mask != 1) {
342             mask >>= 1;
343             val >>= 8;
344         }
345         if (val & 0x80) {
346             cc = 1;
347         } else {
348             cc = 2;
349         }
350     }
351     return cc;
352 }
353
354 static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src,
355                                     uint64_t shift)
356 {
357     uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift);
358     uint64_t match, r;
359
360     /* check if the sign bit stays the same */
361     if (src & (1ULL << 63)) {
362         match = mask;
363     } else {
364         match = 0;
365     }
366
367     if ((src & mask) != match) {
368         /* overflow */
369         return 3;
370     }
371
372     r = ((src << shift) & ((1ULL << 63) - 1)) | (src & (1ULL << 63));
373
374     if ((int64_t)r == 0) {
375         return 0;
376     } else if ((int64_t)r < 0) {
377         return 1;
378     }
379
380     return 2;
381 }
382
383
384 static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op,
385                                   uint64_t src, uint64_t dst, uint64_t vr)
386 {
387     uint32_t r = 0;
388
389     switch (cc_op) {
390     case CC_OP_CONST0:
391     case CC_OP_CONST1:
392     case CC_OP_CONST2:
393     case CC_OP_CONST3:
394         /* cc_op value _is_ cc */
395         r = cc_op;
396         break;
397     case CC_OP_LTGT0_32:
398         r = cc_calc_ltgt0_32(env, dst);
399         break;
400     case CC_OP_LTGT0_64:
401         r =  cc_calc_ltgt0_64(env, dst);
402         break;
403     case CC_OP_LTGT_32:
404         r =  cc_calc_ltgt_32(env, src, dst);
405         break;
406     case CC_OP_LTGT_64:
407         r =  cc_calc_ltgt_64(env, src, dst);
408         break;
409     case CC_OP_LTUGTU_32:
410         r =  cc_calc_ltugtu_32(env, src, dst);
411         break;
412     case CC_OP_LTUGTU_64:
413         r =  cc_calc_ltugtu_64(env, src, dst);
414         break;
415     case CC_OP_TM_32:
416         r =  cc_calc_tm_32(env, src, dst);
417         break;
418     case CC_OP_TM_64:
419         r =  cc_calc_tm_64(env, src, dst);
420         break;
421     case CC_OP_NZ:
422         r =  cc_calc_nz(env, dst);
423         break;
424     case CC_OP_ADD_64:
425         r =  cc_calc_add_64(env, src, dst, vr);
426         break;
427     case CC_OP_ADDU_64:
428         r =  cc_calc_addu_64(env, src, dst, vr);
429         break;
430     case CC_OP_SUB_64:
431         r =  cc_calc_sub_64(env, src, dst, vr);
432         break;
433     case CC_OP_SUBU_64:
434         r =  cc_calc_subu_64(env, src, dst, vr);
435         break;
436     case CC_OP_ABS_64:
437         r =  cc_calc_abs_64(env, dst);
438         break;
439     case CC_OP_NABS_64:
440         r =  cc_calc_nabs_64(env, dst);
441         break;
442     case CC_OP_COMP_64:
443         r =  cc_calc_comp_64(env, dst);
444         break;
445
446     case CC_OP_ADD_32:
447         r =  cc_calc_add_32(env, src, dst, vr);
448         break;
449     case CC_OP_ADDU_32:
450         r =  cc_calc_addu_32(env, src, dst, vr);
451         break;
452     case CC_OP_SUB_32:
453         r =  cc_calc_sub_32(env, src, dst, vr);
454         break;
455     case CC_OP_SUBU_32:
456         r =  cc_calc_subu_32(env, src, dst, vr);
457         break;
458     case CC_OP_ABS_32:
459         r =  cc_calc_abs_64(env, dst);
460         break;
461     case CC_OP_NABS_32:
462         r =  cc_calc_nabs_64(env, dst);
463         break;
464     case CC_OP_COMP_32:
465         r =  cc_calc_comp_32(env, dst);
466         break;
467
468     case CC_OP_ICM:
469         r =  cc_calc_icm_32(env, src, dst);
470         break;
471     case CC_OP_SLAG:
472         r =  cc_calc_slag(env, src, dst);
473         break;
474
475     case CC_OP_LTGT_F32:
476         r = set_cc_f32(env, src, dst);
477         break;
478     case CC_OP_LTGT_F64:
479         r = set_cc_f64(env, src, dst);
480         break;
481     case CC_OP_NZ_F32:
482         r = set_cc_nz_f32(dst);
483         break;
484     case CC_OP_NZ_F64:
485         r = set_cc_nz_f64(dst);
486         break;
487
488     default:
489         cpu_abort(env, "Unknown CC operation: %s\n", cc_name(cc_op));
490     }
491
492     HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __func__,
493                cc_name(cc_op), src, dst, vr, r);
494     return r;
495 }
496
497 uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
498                  uint64_t vr)
499 {
500     return do_calc_cc(env, cc_op, src, dst, vr);
501 }
502
503 uint32_t HELPER(calc_cc)(uint32_t cc_op, uint64_t src, uint64_t dst,
504                          uint64_t vr)
505 {
506     return do_calc_cc(env, cc_op, src, dst, vr);
507 }
508
509 /* insert psw mask and condition code into r1 */
510 void HELPER(ipm)(uint32_t cc, uint32_t r1)
511 {
512     uint64_t r = env->regs[r1];
513
514     r &= 0xffffffff00ffffffULL;
515     r |= (cc << 28) | ((env->psw.mask >> 40) & 0xf);
516     env->regs[r1] = r;
517     HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __func__,
518                cc, env->psw.mask, r);
519 }
520
521 #ifndef CONFIG_USER_ONLY
522 void HELPER(load_psw)(uint64_t mask, uint64_t addr)
523 {
524     load_psw(env, mask, addr);
525     cpu_loop_exit(env);
526 }
527
528 void HELPER(sacf)(uint64_t a1)
529 {
530     HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1);
531
532     switch (a1 & 0xf00) {
533     case 0x000:
534         env->psw.mask &= ~PSW_MASK_ASC;
535         env->psw.mask |= PSW_ASC_PRIMARY;
536         break;
537     case 0x100:
538         env->psw.mask &= ~PSW_MASK_ASC;
539         env->psw.mask |= PSW_ASC_SECONDARY;
540         break;
541     case 0x300:
542         env->psw.mask &= ~PSW_MASK_ASC;
543         env->psw.mask |= PSW_ASC_HOME;
544         break;
545     default:
546         qemu_log("unknown sacf mode: %" PRIx64 "\n", a1);
547         program_interrupt(env, PGM_SPECIFICATION, 2);
548         break;
549     }
550 }
551 #endif