]> git.proxmox.com Git - qemu.git/blob - target-s390x/cc_helper.c
target-s390x: avoid AREG0 for FPU helpers
[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