Revision 58a9e35b
b/target-s390x/cc_helper.c | ||
---|---|---|
331 | 331 |
} |
332 | 332 |
|
333 | 333 |
/* calculate condition code for insert character under mask insn */ |
334 |
static uint32_t cc_calc_icm_32(uint32_t mask, uint32_t val)
|
|
334 |
static uint32_t cc_calc_icm(uint64_t mask, uint64_t val)
|
|
335 | 335 |
{ |
336 |
uint32_t cc; |
|
337 |
|
|
338 |
HELPER_LOG("%s: mask 0x%x val %d\n", __func__, mask, val); |
|
339 |
if (mask == 0xf) { |
|
340 |
if (!val) { |
|
341 |
return 0; |
|
342 |
} else if (val & 0x80000000) { |
|
336 |
if ((val & mask) == 0) { |
|
337 |
return 0; |
|
338 |
} else { |
|
339 |
int top = clz64(mask); |
|
340 |
if ((int64_t)(val << top) < 0) { |
|
343 | 341 |
return 1; |
344 | 342 |
} else { |
345 | 343 |
return 2; |
346 | 344 |
} |
347 | 345 |
} |
348 |
|
|
349 |
if (!val || !mask) { |
|
350 |
cc = 0; |
|
351 |
} else { |
|
352 |
while (mask != 1) { |
|
353 |
mask >>= 1; |
|
354 |
val >>= 8; |
|
355 |
} |
|
356 |
if (val & 0x80) { |
|
357 |
cc = 1; |
|
358 |
} else { |
|
359 |
cc = 2; |
|
360 |
} |
|
361 |
} |
|
362 |
return cc; |
|
363 | 346 |
} |
364 | 347 |
|
365 | 348 |
static uint32_t cc_calc_slag(uint64_t src, uint64_t shift) |
... | ... | |
488 | 471 |
break; |
489 | 472 |
|
490 | 473 |
case CC_OP_ICM: |
491 |
r = cc_calc_icm_32(src, dst);
|
|
474 |
r = cc_calc_icm(src, dst); |
|
492 | 475 |
break; |
493 | 476 |
case CC_OP_SLAG: |
494 | 477 |
r = cc_calc_slag(src, dst); |
b/target-s390x/helper.h | ||
---|---|---|
27 | 27 |
DEF_HELPER_FLAGS_1(abs_i64, TCG_CALL_NO_RWG_SE, i64, s64) |
28 | 28 |
DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_NO_RWG_SE, s64, s64) |
29 | 29 |
DEF_HELPER_4(stcmh, void, env, i32, i64, i32) |
30 |
DEF_HELPER_4(icmh, i32, env, i32, i64, i32) |
|
31 | 30 |
DEF_HELPER_3(ipm, void, env, i32, i32) |
32 | 31 |
DEF_HELPER_4(stam, void, env, i32, i64, i32) |
33 | 32 |
DEF_HELPER_4(lam, void, env, i32, i64, i32) |
b/target-s390x/insn-data.def | ||
---|---|---|
160 | 160 |
/* INSERT CHARACTER */ |
161 | 161 |
C(0x4300, IC, RX_a, Z, 0, m2_8u, 0, r1_8, mov2, 0) |
162 | 162 |
C(0xe373, ICY, RXY_a, LD, 0, m2_8u, 0, r1_8, mov2, 0) |
163 |
/* INSERT CHARACTERS UNDER MASK */ |
|
164 |
D(0xbf00, ICM, RS_b, Z, 0, a2, r1, 0, icm, 0, 0) |
|
165 |
D(0xeb81, ICMY, RSY_b, LD, 0, a2, r1, 0, icm, 0, 0) |
|
166 |
D(0xeb80, ICMH, RSY_b, Z, 0, a2, r1, 0, icm, 0, 32) |
|
163 | 167 |
/* INSERT IMMEDIATE */ |
164 | 168 |
D(0xc008, IIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, insi, 0, 0x2020) |
165 | 169 |
D(0xc009, IILF, RIL_a, EI, r1_o, i2_32u, r1, 0, insi, 0, 0x2000) |
b/target-s390x/mem_helper.c | ||
---|---|---|
629 | 629 |
} |
630 | 630 |
} |
631 | 631 |
|
632 |
/* insert character under mask high; same as icm, but operates on the |
|
633 |
upper half of r1 */ |
|
634 |
uint32_t HELPER(icmh)(CPUS390XState *env, uint32_t r1, uint64_t address, |
|
635 |
uint32_t mask) |
|
636 |
{ |
|
637 |
int pos = 56; /* top of the upper half of r1 */ |
|
638 |
uint64_t rmask = 0xff00000000000000ULL; |
|
639 |
uint8_t val = 0; |
|
640 |
int ccd = 0; |
|
641 |
uint32_t cc = 0; |
|
642 |
|
|
643 |
while (mask) { |
|
644 |
if (mask & 8) { |
|
645 |
env->regs[r1] &= ~rmask; |
|
646 |
val = cpu_ldub_data(env, address); |
|
647 |
if ((val & 0x80) && !ccd) { |
|
648 |
cc = 1; |
|
649 |
} |
|
650 |
ccd = 1; |
|
651 |
if (val && cc == 0) { |
|
652 |
cc = 2; |
|
653 |
} |
|
654 |
env->regs[r1] |= (uint64_t)val << pos; |
|
655 |
address++; |
|
656 |
} |
|
657 |
mask = (mask << 1) & 0xf; |
|
658 |
pos -= 8; |
|
659 |
rmask >>= 8; |
|
660 |
} |
|
661 |
|
|
662 |
return cc; |
|
663 |
} |
|
664 |
|
|
665 | 632 |
/* load access registers r1 to r3 from memory at a2 */ |
666 | 633 |
void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) |
667 | 634 |
{ |
b/target-s390x/translate.c | ||
---|---|---|
32 | 32 |
#include "disas/disas.h" |
33 | 33 |
#include "tcg-op.h" |
34 | 34 |
#include "qemu/log.h" |
35 |
#include "qemu/host-utils.h" |
|
35 | 36 |
|
36 | 37 |
/* global register indexes */ |
37 | 38 |
static TCGv_ptr cpu_env; |
... | ... | |
561 | 562 |
gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, val); |
562 | 563 |
} |
563 | 564 |
|
564 |
static void set_cc_icm(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2) |
|
565 |
{ |
|
566 |
gen_op_update2_cc_i32(s, CC_OP_ICM, v1, v2); |
|
567 |
} |
|
568 |
|
|
569 | 565 |
static void set_cc_cmp_f32_i64(DisasContext *s, TCGv_i32 v1, TCGv_i64 v2) |
570 | 566 |
{ |
571 | 567 |
tcg_gen_extu_i32_i64(cc_src, v1); |
... | ... | |
896 | 892 |
|
897 | 893 |
case CC_OP_LTGT0_64: |
898 | 894 |
case CC_OP_NZ: |
899 |
case CC_OP_ICM: |
|
900 | 895 |
c->u.s64.a = cc_dst; |
901 | 896 |
c->u.s64.b = tcg_const_i64(0); |
902 | 897 |
c->g1 = true; |
... | ... | |
910 | 905 |
|
911 | 906 |
case CC_OP_TM_32: |
912 | 907 |
case CC_OP_TM_64: |
908 |
case CC_OP_ICM: |
|
913 | 909 |
c->u.s64.a = tcg_temp_new_i64(); |
914 | 910 |
c->u.s64.b = tcg_const_i64(0); |
915 | 911 |
tcg_gen_and_i64(c->u.s64.a, cc_src, cc_dst); |
... | ... | |
1521 | 1517 |
tcg_temp_free_i64(tmp); |
1522 | 1518 |
tcg_temp_free_i64(tmp2); |
1523 | 1519 |
break; |
1524 |
case 0x80: /* ICMH R1,M3,D2(B2) [RSY] */ |
|
1525 |
tmp = get_address(s, 0, b2, d2); |
|
1526 |
tmp32_1 = tcg_const_i32(r1); |
|
1527 |
tmp32_2 = tcg_const_i32(r3); |
|
1528 |
potential_page_fault(s); |
|
1529 |
/* XXX split CC calculation out */ |
|
1530 |
gen_helper_icmh(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); |
|
1531 |
set_cc_static(s); |
|
1532 |
tcg_temp_free_i64(tmp); |
|
1533 |
tcg_temp_free_i32(tmp32_1); |
|
1534 |
tcg_temp_free_i32(tmp32_2); |
|
1535 |
break; |
|
1536 | 1520 |
default: |
1537 | 1521 |
LOG_DISAS("illegal eb operation 0x%x\n", op); |
1538 | 1522 |
gen_illegal_opcode(s); |
... | ... | |
2361 | 2345 |
static void disas_s390_insn(CPUS390XState *env, DisasContext *s) |
2362 | 2346 |
{ |
2363 | 2347 |
TCGv_i64 tmp, tmp2, tmp3, tmp4; |
2364 |
TCGv_i32 tmp32_1, tmp32_2, tmp32_3, tmp32_4;
|
|
2348 |
TCGv_i32 tmp32_1, tmp32_2; |
|
2365 | 2349 |
unsigned char opc; |
2366 | 2350 |
uint64_t insn; |
2367 | 2351 |
int op, r1, r2, r3, d1, d2, x2, b1, b2, i, i2, r1b; |
... | ... | |
2786 | 2770 |
tcg_temp_free_i32(tmp32_1); |
2787 | 2771 |
tcg_temp_free_i32(tmp32_2); |
2788 | 2772 |
break; |
2789 |
case 0xbf: /* ICM R1,M3,D2(B2) [RS] */ |
|
2790 |
insn = ld_code4(env, s->pc); |
|
2791 |
decode_rs(s, insn, &r1, &r3, &b2, &d2); |
|
2792 |
if (r3 == 15) { |
|
2793 |
/* effectively a 32-bit load */ |
|
2794 |
tmp = get_address(s, 0, b2, d2); |
|
2795 |
tmp32_1 = tcg_temp_new_i32(); |
|
2796 |
tmp32_2 = tcg_const_i32(r3); |
|
2797 |
tcg_gen_qemu_ld32u(tmp, tmp, get_mem_index(s)); |
|
2798 |
store_reg32_i64(r1, tmp); |
|
2799 |
tcg_gen_trunc_i64_i32(tmp32_1, tmp); |
|
2800 |
set_cc_icm(s, tmp32_2, tmp32_1); |
|
2801 |
tcg_temp_free_i64(tmp); |
|
2802 |
tcg_temp_free_i32(tmp32_1); |
|
2803 |
tcg_temp_free_i32(tmp32_2); |
|
2804 |
} else if (r3) { |
|
2805 |
uint32_t mask = 0x00ffffffUL; |
|
2806 |
uint32_t shift = 24; |
|
2807 |
int m3 = r3; |
|
2808 |
tmp = get_address(s, 0, b2, d2); |
|
2809 |
tmp2 = tcg_temp_new_i64(); |
|
2810 |
tmp32_1 = load_reg32(r1); |
|
2811 |
tmp32_2 = tcg_temp_new_i32(); |
|
2812 |
tmp32_3 = tcg_const_i32(r3); |
|
2813 |
tmp32_4 = tcg_const_i32(0); |
|
2814 |
while (m3) { |
|
2815 |
if (m3 & 8) { |
|
2816 |
tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s)); |
|
2817 |
tcg_gen_trunc_i64_i32(tmp32_2, tmp2); |
|
2818 |
if (shift) { |
|
2819 |
tcg_gen_shli_i32(tmp32_2, tmp32_2, shift); |
|
2820 |
} |
|
2821 |
tcg_gen_andi_i32(tmp32_1, tmp32_1, mask); |
|
2822 |
tcg_gen_or_i32(tmp32_1, tmp32_1, tmp32_2); |
|
2823 |
tcg_gen_or_i32(tmp32_4, tmp32_4, tmp32_2); |
|
2824 |
tcg_gen_addi_i64(tmp, tmp, 1); |
|
2825 |
} |
|
2826 |
m3 = (m3 << 1) & 0xf; |
|
2827 |
mask = (mask >> 8) | 0xff000000UL; |
|
2828 |
shift -= 8; |
|
2829 |
} |
|
2830 |
store_reg32(r1, tmp32_1); |
|
2831 |
set_cc_icm(s, tmp32_3, tmp32_4); |
|
2832 |
tcg_temp_free_i64(tmp); |
|
2833 |
tcg_temp_free_i64(tmp2); |
|
2834 |
tcg_temp_free_i32(tmp32_1); |
|
2835 |
tcg_temp_free_i32(tmp32_2); |
|
2836 |
tcg_temp_free_i32(tmp32_3); |
|
2837 |
tcg_temp_free_i32(tmp32_4); |
|
2838 |
} else { |
|
2839 |
/* i.e. env->cc = 0 */ |
|
2840 |
gen_op_movi_cc(s, 0); |
|
2841 |
} |
|
2842 |
break; |
|
2843 | 2773 |
case 0xd2: /* MVC D1(L,B1),D2(B2) [SS] */ |
2844 | 2774 |
case 0xd4: /* NC D1(L,B1),D2(B2) [SS] */ |
2845 | 2775 |
case 0xd5: /* CLC D1(L,B1),D2(B2) [SS] */ |
... | ... | |
3493 | 3423 |
return NO_EXIT; |
3494 | 3424 |
} |
3495 | 3425 |
|
3426 |
static ExitStatus op_icm(DisasContext *s, DisasOps *o) |
|
3427 |
{ |
|
3428 |
int m3 = get_field(s->fields, m3); |
|
3429 |
int pos, len, base = s->insn->data; |
|
3430 |
TCGv_i64 tmp = tcg_temp_new_i64(); |
|
3431 |
uint64_t ccm; |
|
3432 |
|
|
3433 |
switch (m3) { |
|
3434 |
case 0xf: |
|
3435 |
/* Effectively a 32-bit load. */ |
|
3436 |
tcg_gen_qemu_ld32u(tmp, o->in2, get_mem_index(s)); |
|
3437 |
len = 32; |
|
3438 |
goto one_insert; |
|
3439 |
|
|
3440 |
case 0xc: |
|
3441 |
case 0x6: |
|
3442 |
case 0x3: |
|
3443 |
/* Effectively a 16-bit load. */ |
|
3444 |
tcg_gen_qemu_ld16u(tmp, o->in2, get_mem_index(s)); |
|
3445 |
len = 16; |
|
3446 |
goto one_insert; |
|
3447 |
|
|
3448 |
case 0x8: |
|
3449 |
case 0x4: |
|
3450 |
case 0x2: |
|
3451 |
case 0x1: |
|
3452 |
/* Effectively an 8-bit load. */ |
|
3453 |
tcg_gen_qemu_ld8u(tmp, o->in2, get_mem_index(s)); |
|
3454 |
len = 8; |
|
3455 |
goto one_insert; |
|
3456 |
|
|
3457 |
one_insert: |
|
3458 |
pos = base + ctz32(m3) * 8; |
|
3459 |
tcg_gen_deposit_i64(o->out, o->out, tmp, pos, len); |
|
3460 |
ccm = ((1ull << len) - 1) << pos; |
|
3461 |
break; |
|
3462 |
|
|
3463 |
default: |
|
3464 |
/* This is going to be a sequence of loads and inserts. */ |
|
3465 |
pos = base + 32 - 8; |
|
3466 |
ccm = 0; |
|
3467 |
while (m3) { |
|
3468 |
if (m3 & 0x8) { |
|
3469 |
tcg_gen_qemu_ld8u(tmp, o->in2, get_mem_index(s)); |
|
3470 |
tcg_gen_addi_i64(o->in2, o->in2, 1); |
|
3471 |
tcg_gen_deposit_i64(o->out, o->out, tmp, pos, 8); |
|
3472 |
ccm |= 0xff << pos; |
|
3473 |
} |
|
3474 |
m3 = (m3 << 1) & 0xf; |
|
3475 |
pos -= 8; |
|
3476 |
} |
|
3477 |
break; |
|
3478 |
} |
|
3479 |
|
|
3480 |
tcg_gen_movi_i64(tmp, ccm); |
|
3481 |
gen_op_update2_cc_i64(s, CC_OP_ICM, tmp, o->out); |
|
3482 |
tcg_temp_free_i64(tmp); |
|
3483 |
return NO_EXIT; |
|
3484 |
} |
|
3485 |
|
|
3496 | 3486 |
static ExitStatus op_insi(DisasContext *s, DisasOps *o) |
3497 | 3487 |
{ |
3498 | 3488 |
int shift = s->insn->data & 0xff; |
Also available in: Unified diff