Statistics
| Branch: | Revision:

root / target-s390x / cc_helper.c @ 932385a3

History | View | Annotate | Download (12.8 kB)

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 "helper.h"
23

    
24
/* #define DEBUG_HELPER */
25
#ifdef DEBUG_HELPER
26
#define HELPER_LOG(x...) qemu_log(x)
27
#else
28
#define HELPER_LOG(x...)
29
#endif
30

    
31
static inline uint32_t cc_calc_ltgt_32(CPUS390XState *env, int32_t src,
32
                                       int32_t dst)
33
{
34
    if (src == dst) {
35
        return 0;
36
    } else if (src < dst) {
37
        return 1;
38
    } else {
39
        return 2;
40
    }
41
}
42

    
43
static inline uint32_t cc_calc_ltgt0_32(CPUS390XState *env, int32_t dst)
44
{
45
    return cc_calc_ltgt_32(env, dst, 0);
46
}
47

    
48
static inline uint32_t cc_calc_ltgt_64(CPUS390XState *env, int64_t src,
49
                                       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 inline uint32_t cc_calc_ltgt0_64(CPUS390XState *env, int64_t dst)
61
{
62
    return cc_calc_ltgt_64(env, dst, 0);
63
}
64

    
65
static inline uint32_t cc_calc_ltugtu_32(CPUS390XState *env, uint32_t src,
66
                                         uint32_t dst)
67
{
68
    if (src == dst) {
69
        return 0;
70
    } else if (src < dst) {
71
        return 1;
72
    } else {
73
        return 2;
74
    }
75
}
76

    
77
static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src,
78
                                         uint64_t dst)
79
{
80
    if (src == dst) {
81
        return 0;
82
    } else if (src < dst) {
83
        return 1;
84
    } else {
85
        return 2;
86
    }
87
}
88

    
89
static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val,
90
                                     uint32_t mask)
91
{
92
    uint16_t r = val & mask;
93

    
94
    HELPER_LOG("%s: val 0x%x mask 0x%x\n", __func__, val, mask);
95
    if (r == 0 || mask == 0) {
96
        return 0;
97
    } else if (r == mask) {
98
        return 3;
99
    } else {
100
        return 1;
101
    }
102
}
103

    
104
/* set condition code for test under mask */
105
static inline uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val,
106
                                     uint32_t mask)
107
{
108
    uint16_t r = val & mask;
109

    
110
    HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __func__, val, mask, r);
111
    if (r == 0 || mask == 0) {
112
        return 0;
113
    } else if (r == mask) {
114
        return 3;
115
    } else {
116
        while (!(mask & 0x8000)) {
117
            mask <<= 1;
118
            val <<= 1;
119
        }
120
        if (val & 0x8000) {
121
            return 2;
122
        } else {
123
            return 1;
124
        }
125
    }
126
}
127

    
128
static inline uint32_t cc_calc_nz(CPUS390XState *env, uint64_t dst)
129
{
130
    return !!dst;
131
}
132

    
133
static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1,
134
                                      int64_t a2, int64_t ar)
135
{
136
    if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
137
        return 3; /* overflow */
138
    } else {
139
        if (ar < 0) {
140
            return 1;
141
        } else if (ar > 0) {
142
            return 2;
143
        } else {
144
            return 0;
145
        }
146
    }
147
}
148

    
149
static inline uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1,
150
                                       uint64_t a2, uint64_t ar)
151
{
152
    if (ar == 0) {
153
        if (a1) {
154
            return 2;
155
        } else {
156
            return 0;
157
        }
158
    } else {
159
        if (ar < a1 || ar < a2) {
160
            return 3;
161
        } else {
162
            return 1;
163
        }
164
    }
165
}
166

    
167
static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1,
168
                                      int64_t a2, int64_t ar)
169
{
170
    if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
171
        return 3; /* overflow */
172
    } else {
173
        if (ar < 0) {
174
            return 1;
175
        } else if (ar > 0) {
176
            return 2;
177
        } else {
178
            return 0;
179
        }
180
    }
181
}
182

    
183
static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1,
184
                                       uint64_t a2, uint64_t ar)
185
{
186
    if (ar == 0) {
187
        return 2;
188
    } else {
189
        if (a2 > a1) {
190
            return 1;
191
        } else {
192
            return 3;
193
        }
194
    }
195
}
196

    
197
static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst)
198
{
199
    if ((uint64_t)dst == 0x8000000000000000ULL) {
200
        return 3;
201
    } else if (dst) {
202
        return 1;
203
    } else {
204
        return 0;
205
    }
206
}
207

    
208
static inline uint32_t cc_calc_nabs_64(CPUS390XState *env, int64_t dst)
209
{
210
    return !!dst;
211
}
212

    
213
static inline uint32_t cc_calc_comp_64(CPUS390XState *env, int64_t dst)
214
{
215
    if ((uint64_t)dst == 0x8000000000000000ULL) {
216
        return 3;
217
    } else if (dst < 0) {
218
        return 1;
219
    } else if (dst > 0) {
220
        return 2;
221
    } else {
222
        return 0;
223
    }
224
}
225

    
226

    
227
static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1,
228
                                      int32_t a2, int32_t ar)
229
{
230
    if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
231
        return 3; /* overflow */
232
    } else {
233
        if (ar < 0) {
234
            return 1;
235
        } else if (ar > 0) {
236
            return 2;
237
        } else {
238
            return 0;
239
        }
240
    }
241
}
242

    
243
static inline uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1,
244
                                       uint32_t a2, uint32_t ar)
245
{
246
    if (ar == 0) {
247
        if (a1) {
248
            return 2;
249
        } else {
250
            return 0;
251
        }
252
    } else {
253
        if (ar < a1 || ar < a2) {
254
            return 3;
255
        } else {
256
            return 1;
257
        }
258
    }
259
}
260

    
261
static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1,
262
                                      int32_t a2, int32_t ar)
263
{
264
    if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
265
        return 3; /* overflow */
266
    } else {
267
        if (ar < 0) {
268
            return 1;
269
        } else if (ar > 0) {
270
            return 2;
271
        } else {
272
            return 0;
273
        }
274
    }
275
}
276

    
277
static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1,
278
                                       uint32_t a2, uint32_t ar)
279
{
280
    if (ar == 0) {
281
        return 2;
282
    } else {
283
        if (a2 > a1) {
284
            return 1;
285
        } else {
286
            return 3;
287
        }
288
    }
289
}
290

    
291
static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst)
292
{
293
    if ((uint32_t)dst == 0x80000000UL) {
294
        return 3;
295
    } else if (dst) {
296
        return 1;
297
    } else {
298
        return 0;
299
    }
300
}
301

    
302
static inline uint32_t cc_calc_nabs_32(CPUS390XState *env, int32_t dst)
303
{
304
    return !!dst;
305
}
306

    
307
static inline uint32_t cc_calc_comp_32(CPUS390XState *env, int32_t dst)
308
{
309
    if ((uint32_t)dst == 0x80000000UL) {
310
        return 3;
311
    } else if (dst < 0) {
312
        return 1;
313
    } else if (dst > 0) {
314
        return 2;
315
    } else {
316
        return 0;
317
    }
318
}
319

    
320
/* calculate condition code for insert character under mask insn */
321
static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask,
322
                                      uint32_t val)
323
{
324
    uint32_t cc;
325

    
326
    HELPER_LOG("%s: mask 0x%x val %d\n", __func__, mask, val);
327
    if (mask == 0xf) {
328
        if (!val) {
329
            return 0;
330
        } else if (val & 0x80000000) {
331
            return 1;
332
        } else {
333
            return 2;
334
        }
335
    }
336

    
337
    if (!val || !mask) {
338
        cc = 0;
339
    } else {
340
        while (mask != 1) {
341
            mask >>= 1;
342
            val >>= 8;
343
        }
344
        if (val & 0x80) {
345
            cc = 1;
346
        } else {
347
            cc = 2;
348
        }
349
    }
350
    return cc;
351
}
352

    
353
static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src,
354
                                    uint64_t shift)
355
{
356
    uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift);
357
    uint64_t match, r;
358

    
359
    /* check if the sign bit stays the same */
360
    if (src & (1ULL << 63)) {
361
        match = mask;
362
    } else {
363
        match = 0;
364
    }
365

    
366
    if ((src & mask) != match) {
367
        /* overflow */
368
        return 3;
369
    }
370

    
371
    r = ((src << shift) & ((1ULL << 63) - 1)) | (src & (1ULL << 63));
372

    
373
    if ((int64_t)r == 0) {
374
        return 0;
375
    } else if ((int64_t)r < 0) {
376
        return 1;
377
    }
378

    
379
    return 2;
380
}
381

    
382

    
383
static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op,
384
                                  uint64_t src, uint64_t dst, uint64_t vr)
385
{
386
    uint32_t r = 0;
387

    
388
    switch (cc_op) {
389
    case CC_OP_CONST0:
390
    case CC_OP_CONST1:
391
    case CC_OP_CONST2:
392
    case CC_OP_CONST3:
393
        /* cc_op value _is_ cc */
394
        r = cc_op;
395
        break;
396
    case CC_OP_LTGT0_32:
397
        r = cc_calc_ltgt0_32(env, dst);
398
        break;
399
    case CC_OP_LTGT0_64:
400
        r =  cc_calc_ltgt0_64(env, dst);
401
        break;
402
    case CC_OP_LTGT_32:
403
        r =  cc_calc_ltgt_32(env, src, dst);
404
        break;
405
    case CC_OP_LTGT_64:
406
        r =  cc_calc_ltgt_64(env, src, dst);
407
        break;
408
    case CC_OP_LTUGTU_32:
409
        r =  cc_calc_ltugtu_32(env, src, dst);
410
        break;
411
    case CC_OP_LTUGTU_64:
412
        r =  cc_calc_ltugtu_64(env, src, dst);
413
        break;
414
    case CC_OP_TM_32:
415
        r =  cc_calc_tm_32(env, src, dst);
416
        break;
417
    case CC_OP_TM_64:
418
        r =  cc_calc_tm_64(env, src, dst);
419
        break;
420
    case CC_OP_NZ:
421
        r =  cc_calc_nz(env, dst);
422
        break;
423
    case CC_OP_ADD_64:
424
        r =  cc_calc_add_64(env, src, dst, vr);
425
        break;
426
    case CC_OP_ADDU_64:
427
        r =  cc_calc_addu_64(env, src, dst, vr);
428
        break;
429
    case CC_OP_SUB_64:
430
        r =  cc_calc_sub_64(env, src, dst, vr);
431
        break;
432
    case CC_OP_SUBU_64:
433
        r =  cc_calc_subu_64(env, src, dst, vr);
434
        break;
435
    case CC_OP_ABS_64:
436
        r =  cc_calc_abs_64(env, dst);
437
        break;
438
    case CC_OP_NABS_64:
439
        r =  cc_calc_nabs_64(env, dst);
440
        break;
441
    case CC_OP_COMP_64:
442
        r =  cc_calc_comp_64(env, dst);
443
        break;
444

    
445
    case CC_OP_ADD_32:
446
        r =  cc_calc_add_32(env, src, dst, vr);
447
        break;
448
    case CC_OP_ADDU_32:
449
        r =  cc_calc_addu_32(env, src, dst, vr);
450
        break;
451
    case CC_OP_SUB_32:
452
        r =  cc_calc_sub_32(env, src, dst, vr);
453
        break;
454
    case CC_OP_SUBU_32:
455
        r =  cc_calc_subu_32(env, src, dst, vr);
456
        break;
457
    case CC_OP_ABS_32:
458
        r =  cc_calc_abs_64(env, dst);
459
        break;
460
    case CC_OP_NABS_32:
461
        r =  cc_calc_nabs_64(env, dst);
462
        break;
463
    case CC_OP_COMP_32:
464
        r =  cc_calc_comp_32(env, dst);
465
        break;
466

    
467
    case CC_OP_ICM:
468
        r =  cc_calc_icm_32(env, src, dst);
469
        break;
470
    case CC_OP_SLAG:
471
        r =  cc_calc_slag(env, src, dst);
472
        break;
473

    
474
    case CC_OP_LTGT_F32:
475
        r = set_cc_f32(env, src, dst);
476
        break;
477
    case CC_OP_LTGT_F64:
478
        r = set_cc_f64(env, src, dst);
479
        break;
480
    case CC_OP_NZ_F32:
481
        r = set_cc_nz_f32(dst);
482
        break;
483
    case CC_OP_NZ_F64:
484
        r = set_cc_nz_f64(dst);
485
        break;
486

    
487
    default:
488
        cpu_abort(env, "Unknown CC operation: %s\n", cc_name(cc_op));
489
    }
490

    
491
    HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __func__,
492
               cc_name(cc_op), src, dst, vr, r);
493
    return r;
494
}
495

    
496
uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
497
                 uint64_t vr)
498
{
499
    return do_calc_cc(env, cc_op, src, dst, vr);
500
}
501

    
502
uint32_t HELPER(calc_cc)(CPUS390XState *env, uint32_t cc_op, uint64_t src,
503
                         uint64_t dst, uint64_t vr)
504
{
505
    return do_calc_cc(env, cc_op, src, dst, vr);
506
}
507

    
508
/* insert psw mask and condition code into r1 */
509
void HELPER(ipm)(CPUS390XState *env, uint32_t cc, uint32_t r1)
510
{
511
    uint64_t r = env->regs[r1];
512

    
513
    r &= 0xffffffff00ffffffULL;
514
    r |= (cc << 28) | ((env->psw.mask >> 40) & 0xf);
515
    env->regs[r1] = r;
516
    HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __func__,
517
               cc, env->psw.mask, r);
518
}
519

    
520
#ifndef CONFIG_USER_ONLY
521
void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr)
522
{
523
    load_psw(env, mask, addr);
524
    cpu_loop_exit(env);
525
}
526

    
527
void HELPER(sacf)(CPUS390XState *env, uint64_t a1)
528
{
529
    HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1);
530

    
531
    switch (a1 & 0xf00) {
532
    case 0x000:
533
        env->psw.mask &= ~PSW_MASK_ASC;
534
        env->psw.mask |= PSW_ASC_PRIMARY;
535
        break;
536
    case 0x100:
537
        env->psw.mask &= ~PSW_MASK_ASC;
538
        env->psw.mask |= PSW_ASC_SECONDARY;
539
        break;
540
    case 0x300:
541
        env->psw.mask &= ~PSW_MASK_ASC;
542
        env->psw.mask |= PSW_ASC_HOME;
543
        break;
544
    default:
545
        qemu_log("unknown sacf mode: %" PRIx64 "\n", a1);
546
        program_interrupt(env, PGM_SPECIFICATION, 2);
547
        break;
548
    }
549
}
550
#endif