These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / 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 "qemu/osdep.h"
22 #include "cpu.h"
23 #include "exec/helper-proto.h"
24 #include "qemu/host-utils.h"
25
26 /* #define DEBUG_HELPER */
27 #ifdef DEBUG_HELPER
28 #define HELPER_LOG(x...) qemu_log(x)
29 #else
30 #define HELPER_LOG(x...)
31 #endif
32
33 static uint32_t cc_calc_ltgt_32(int32_t src, 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 uint32_t cc_calc_ltgt0_32(int32_t dst)
45 {
46     return cc_calc_ltgt_32(dst, 0);
47 }
48
49 static uint32_t cc_calc_ltgt_64(int64_t src, int64_t dst)
50 {
51     if (src == dst) {
52         return 0;
53     } else if (src < dst) {
54         return 1;
55     } else {
56         return 2;
57     }
58 }
59
60 static uint32_t cc_calc_ltgt0_64(int64_t dst)
61 {
62     return cc_calc_ltgt_64(dst, 0);
63 }
64
65 static uint32_t cc_calc_ltugtu_32(uint32_t src, uint32_t dst)
66 {
67     if (src == dst) {
68         return 0;
69     } else if (src < dst) {
70         return 1;
71     } else {
72         return 2;
73     }
74 }
75
76 static uint32_t cc_calc_ltugtu_64(uint64_t src, uint64_t dst)
77 {
78     if (src == dst) {
79         return 0;
80     } else if (src < dst) {
81         return 1;
82     } else {
83         return 2;
84     }
85 }
86
87 static uint32_t cc_calc_tm_32(uint32_t val, uint32_t mask)
88 {
89     uint32_t r = val & mask;
90
91     if (r == 0) {
92         return 0;
93     } else if (r == mask) {
94         return 3;
95     } else {
96         return 1;
97     }
98 }
99
100 static uint32_t cc_calc_tm_64(uint64_t val, uint64_t mask)
101 {
102     uint64_t r = val & mask;
103
104     if (r == 0) {
105         return 0;
106     } else if (r == mask) {
107         return 3;
108     } else {
109         int top = clz64(mask);
110         if ((int64_t)(val << top) < 0) {
111             return 2;
112         } else {
113             return 1;
114         }
115     }
116 }
117
118 static uint32_t cc_calc_nz(uint64_t dst)
119 {
120     return !!dst;
121 }
122
123 static uint32_t cc_calc_add_64(int64_t a1, int64_t a2, int64_t ar)
124 {
125     if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
126         return 3; /* overflow */
127     } else {
128         if (ar < 0) {
129             return 1;
130         } else if (ar > 0) {
131             return 2;
132         } else {
133             return 0;
134         }
135     }
136 }
137
138 static uint32_t cc_calc_addu_64(uint64_t a1, uint64_t a2, uint64_t ar)
139 {
140     return (ar != 0) + 2 * (ar < a1);
141 }
142
143 static uint32_t cc_calc_addc_64(uint64_t a1, uint64_t a2, uint64_t ar)
144 {
145     /* Recover a2 + carry_in.  */
146     uint64_t a2c = ar - a1;
147     /* Check for a2+carry_in overflow, then a1+a2c overflow.  */
148     int carry_out = (a2c < a2) || (ar < a1);
149
150     return (ar != 0) + 2 * carry_out;
151 }
152
153 static uint32_t cc_calc_sub_64(int64_t a1, int64_t a2, int64_t ar)
154 {
155     if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
156         return 3; /* overflow */
157     } else {
158         if (ar < 0) {
159             return 1;
160         } else if (ar > 0) {
161             return 2;
162         } else {
163             return 0;
164         }
165     }
166 }
167
168 static uint32_t cc_calc_subu_64(uint64_t a1, uint64_t a2, uint64_t ar)
169 {
170     if (ar == 0) {
171         return 2;
172     } else {
173         if (a2 > a1) {
174             return 1;
175         } else {
176             return 3;
177         }
178     }
179 }
180
181 static uint32_t cc_calc_subb_64(uint64_t a1, uint64_t a2, uint64_t ar)
182 {
183     int borrow_out;
184
185     if (ar != a1 - a2) {        /* difference means borrow-in */
186         borrow_out = (a2 >= a1);
187     } else {
188         borrow_out = (a2 > a1);
189     }
190
191     return (ar != 0) + 2 * !borrow_out;
192 }
193
194 static uint32_t cc_calc_abs_64(int64_t dst)
195 {
196     if ((uint64_t)dst == 0x8000000000000000ULL) {
197         return 3;
198     } else if (dst) {
199         return 2;
200     } else {
201         return 0;
202     }
203 }
204
205 static uint32_t cc_calc_nabs_64(int64_t dst)
206 {
207     return !!dst;
208 }
209
210 static uint32_t cc_calc_comp_64(int64_t dst)
211 {
212     if ((uint64_t)dst == 0x8000000000000000ULL) {
213         return 3;
214     } else if (dst < 0) {
215         return 1;
216     } else if (dst > 0) {
217         return 2;
218     } else {
219         return 0;
220     }
221 }
222
223
224 static uint32_t cc_calc_add_32(int32_t a1, int32_t a2, int32_t ar)
225 {
226     if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
227         return 3; /* overflow */
228     } else {
229         if (ar < 0) {
230             return 1;
231         } else if (ar > 0) {
232             return 2;
233         } else {
234             return 0;
235         }
236     }
237 }
238
239 static uint32_t cc_calc_addu_32(uint32_t a1, uint32_t a2, uint32_t ar)
240 {
241     return (ar != 0) + 2 * (ar < a1);
242 }
243
244 static uint32_t cc_calc_addc_32(uint32_t a1, uint32_t a2, uint32_t ar)
245 {
246     /* Recover a2 + carry_in.  */
247     uint32_t a2c = ar - a1;
248     /* Check for a2+carry_in overflow, then a1+a2c overflow.  */
249     int carry_out = (a2c < a2) || (ar < a1);
250
251     return (ar != 0) + 2 * carry_out;
252 }
253
254 static uint32_t cc_calc_sub_32(int32_t a1, int32_t a2, int32_t ar)
255 {
256     if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
257         return 3; /* overflow */
258     } else {
259         if (ar < 0) {
260             return 1;
261         } else if (ar > 0) {
262             return 2;
263         } else {
264             return 0;
265         }
266     }
267 }
268
269 static uint32_t cc_calc_subu_32(uint32_t a1, uint32_t a2, uint32_t ar)
270 {
271     if (ar == 0) {
272         return 2;
273     } else {
274         if (a2 > a1) {
275             return 1;
276         } else {
277             return 3;
278         }
279     }
280 }
281
282 static uint32_t cc_calc_subb_32(uint32_t a1, uint32_t a2, uint32_t ar)
283 {
284     int borrow_out;
285
286     if (ar != a1 - a2) {        /* difference means borrow-in */
287         borrow_out = (a2 >= a1);
288     } else {
289         borrow_out = (a2 > a1);
290     }
291
292     return (ar != 0) + 2 * !borrow_out;
293 }
294
295 static uint32_t cc_calc_abs_32(int32_t dst)
296 {
297     if ((uint32_t)dst == 0x80000000UL) {
298         return 3;
299     } else if (dst) {
300         return 2;
301     } else {
302         return 0;
303     }
304 }
305
306 static uint32_t cc_calc_nabs_32(int32_t dst)
307 {
308     return !!dst;
309 }
310
311 static uint32_t cc_calc_comp_32(int32_t dst)
312 {
313     if ((uint32_t)dst == 0x80000000UL) {
314         return 3;
315     } else if (dst < 0) {
316         return 1;
317     } else if (dst > 0) {
318         return 2;
319     } else {
320         return 0;
321     }
322 }
323
324 /* calculate condition code for insert character under mask insn */
325 static uint32_t cc_calc_icm(uint64_t mask, uint64_t val)
326 {
327     if ((val & mask) == 0) {
328         return 0;
329     } else {
330         int top = clz64(mask);
331         if ((int64_t)(val << top) < 0) {
332             return 1;
333         } else {
334             return 2;
335         }
336     }
337 }
338
339 static uint32_t cc_calc_sla_32(uint32_t src, int shift)
340 {
341     uint32_t mask = ((1U << shift) - 1U) << (32 - shift);
342     uint32_t sign = 1U << 31;
343     uint32_t match;
344     int32_t r;
345
346     /* Check if the sign bit stays the same.  */
347     if (src & sign) {
348         match = mask;
349     } else {
350         match = 0;
351     }
352     if ((src & mask) != match) {
353         /* Overflow.  */
354         return 3;
355     }
356
357     r = ((src << shift) & ~sign) | (src & sign);
358     if (r == 0) {
359         return 0;
360     } else if (r < 0) {
361         return 1;
362     }
363     return 2;
364 }
365
366 static uint32_t cc_calc_sla_64(uint64_t src, int shift)
367 {
368     uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift);
369     uint64_t sign = 1ULL << 63;
370     uint64_t match;
371     int64_t r;
372
373     /* Check if the sign bit stays the same.  */
374     if (src & sign) {
375         match = mask;
376     } else {
377         match = 0;
378     }
379     if ((src & mask) != match) {
380         /* Overflow.  */
381         return 3;
382     }
383
384     r = ((src << shift) & ~sign) | (src & sign);
385     if (r == 0) {
386         return 0;
387     } else if (r < 0) {
388         return 1;
389     }
390     return 2;
391 }
392
393 static uint32_t cc_calc_flogr(uint64_t dst)
394 {
395     return dst ? 2 : 0;
396 }
397
398 static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op,
399                                   uint64_t src, uint64_t dst, uint64_t vr)
400 {
401     S390CPU *cpu = s390_env_get_cpu(env);
402     uint32_t r = 0;
403
404     switch (cc_op) {
405     case CC_OP_CONST0:
406     case CC_OP_CONST1:
407     case CC_OP_CONST2:
408     case CC_OP_CONST3:
409         /* cc_op value _is_ cc */
410         r = cc_op;
411         break;
412     case CC_OP_LTGT0_32:
413         r = cc_calc_ltgt0_32(dst);
414         break;
415     case CC_OP_LTGT0_64:
416         r =  cc_calc_ltgt0_64(dst);
417         break;
418     case CC_OP_LTGT_32:
419         r =  cc_calc_ltgt_32(src, dst);
420         break;
421     case CC_OP_LTGT_64:
422         r =  cc_calc_ltgt_64(src, dst);
423         break;
424     case CC_OP_LTUGTU_32:
425         r =  cc_calc_ltugtu_32(src, dst);
426         break;
427     case CC_OP_LTUGTU_64:
428         r =  cc_calc_ltugtu_64(src, dst);
429         break;
430     case CC_OP_TM_32:
431         r =  cc_calc_tm_32(src, dst);
432         break;
433     case CC_OP_TM_64:
434         r =  cc_calc_tm_64(src, dst);
435         break;
436     case CC_OP_NZ:
437         r =  cc_calc_nz(dst);
438         break;
439     case CC_OP_ADD_64:
440         r =  cc_calc_add_64(src, dst, vr);
441         break;
442     case CC_OP_ADDU_64:
443         r =  cc_calc_addu_64(src, dst, vr);
444         break;
445     case CC_OP_ADDC_64:
446         r =  cc_calc_addc_64(src, dst, vr);
447         break;
448     case CC_OP_SUB_64:
449         r =  cc_calc_sub_64(src, dst, vr);
450         break;
451     case CC_OP_SUBU_64:
452         r =  cc_calc_subu_64(src, dst, vr);
453         break;
454     case CC_OP_SUBB_64:
455         r =  cc_calc_subb_64(src, dst, vr);
456         break;
457     case CC_OP_ABS_64:
458         r =  cc_calc_abs_64(dst);
459         break;
460     case CC_OP_NABS_64:
461         r =  cc_calc_nabs_64(dst);
462         break;
463     case CC_OP_COMP_64:
464         r =  cc_calc_comp_64(dst);
465         break;
466
467     case CC_OP_ADD_32:
468         r =  cc_calc_add_32(src, dst, vr);
469         break;
470     case CC_OP_ADDU_32:
471         r =  cc_calc_addu_32(src, dst, vr);
472         break;
473     case CC_OP_ADDC_32:
474         r =  cc_calc_addc_32(src, dst, vr);
475         break;
476     case CC_OP_SUB_32:
477         r =  cc_calc_sub_32(src, dst, vr);
478         break;
479     case CC_OP_SUBU_32:
480         r =  cc_calc_subu_32(src, dst, vr);
481         break;
482     case CC_OP_SUBB_32:
483         r =  cc_calc_subb_32(src, dst, vr);
484         break;
485     case CC_OP_ABS_32:
486         r =  cc_calc_abs_32(dst);
487         break;
488     case CC_OP_NABS_32:
489         r =  cc_calc_nabs_32(dst);
490         break;
491     case CC_OP_COMP_32:
492         r =  cc_calc_comp_32(dst);
493         break;
494
495     case CC_OP_ICM:
496         r =  cc_calc_icm(src, dst);
497         break;
498     case CC_OP_SLA_32:
499         r =  cc_calc_sla_32(src, dst);
500         break;
501     case CC_OP_SLA_64:
502         r =  cc_calc_sla_64(src, dst);
503         break;
504     case CC_OP_FLOGR:
505         r = cc_calc_flogr(dst);
506         break;
507
508     case CC_OP_NZ_F32:
509         r = set_cc_nz_f32(dst);
510         break;
511     case CC_OP_NZ_F64:
512         r = set_cc_nz_f64(dst);
513         break;
514     case CC_OP_NZ_F128:
515         r = set_cc_nz_f128(make_float128(src, dst));
516         break;
517
518     default:
519         cpu_abort(CPU(cpu), "Unknown CC operation: %s\n", cc_name(cc_op));
520     }
521
522     HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __func__,
523                cc_name(cc_op), src, dst, vr, r);
524     return r;
525 }
526
527 uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
528                  uint64_t vr)
529 {
530     return do_calc_cc(env, cc_op, src, dst, vr);
531 }
532
533 uint32_t HELPER(calc_cc)(CPUS390XState *env, uint32_t cc_op, uint64_t src,
534                          uint64_t dst, uint64_t vr)
535 {
536     return do_calc_cc(env, cc_op, src, dst, vr);
537 }
538
539 #ifndef CONFIG_USER_ONLY
540 void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr)
541 {
542     load_psw(env, mask, addr);
543     cpu_loop_exit(CPU(s390_env_get_cpu(env)));
544 }
545
546 void HELPER(sacf)(CPUS390XState *env, uint64_t a1)
547 {
548     HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1);
549
550     switch (a1 & 0xf00) {
551     case 0x000:
552         env->psw.mask &= ~PSW_MASK_ASC;
553         env->psw.mask |= PSW_ASC_PRIMARY;
554         break;
555     case 0x100:
556         env->psw.mask &= ~PSW_MASK_ASC;
557         env->psw.mask |= PSW_ASC_SECONDARY;
558         break;
559     case 0x300:
560         env->psw.mask &= ~PSW_MASK_ASC;
561         env->psw.mask |= PSW_ASC_HOME;
562         break;
563     default:
564         HELPER_LOG("unknown sacf mode: %" PRIx64 "\n", a1);
565         program_interrupt(env, PGM_SPECIFICATION, 2);
566         break;
567     }
568 }
569 #endif