target-s390: Convert ADD LOGICAL CARRY and SUBTRACT LOGICAL BORROW

I'm resonably certain that the carry/borrow-out condition for both
helpers was incorrect, failing to take into account the carry-in.
Adding the new CC_OP codes also allows removing the awkward interface
we used for the slb helpers.

Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
Richard Henderson 2012-08-17 18:52:33 -07:00
parent 2b280b9708
commit 4e4bb43899
6 changed files with 157 additions and 206 deletions

View File

@ -146,22 +146,21 @@ static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1,
} }
} }
static inline uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1, static uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1,
uint64_t a2, uint64_t ar) uint64_t a2, uint64_t ar)
{ {
if (ar == 0) { return (ar != 0) + 2 * (ar < a1);
if (a1) { }
return 2;
} else { static uint32_t cc_calc_addc_64(CPUS390XState *env, uint64_t a1,
return 0; uint64_t a2, uint64_t ar)
} {
} else { /* Recover a2 + carry_in. */
if (ar < a1 || ar < a2) { uint64_t a2c = ar - a1;
return 3; /* Check for a2+carry_in overflow, then a1+a2c overflow. */
} else { int carry_out = (a2c < a2) || (ar < a1);
return 1;
} return (ar != 0) + 2 * carry_out;
}
} }
static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1,
@ -194,6 +193,25 @@ static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1,
} }
} }
static uint32_t cc_calc_subb_64(CPUS390XState *env, uint64_t a1,
uint64_t a2, uint64_t ar)
{
/* We had borrow-in if normal subtraction isn't equal. */
int borrow_in = ar - (a1 - a2);
int borrow_out;
/* If a2 was ULONG_MAX, and borrow_in, then a2 is logically 65 bits,
and we must have had borrow out. */
if (borrow_in && a2 == (uint64_t)-1) {
borrow_out = 1;
} else {
a2 += borrow_in;
borrow_out = (a2 > a1);
}
return (ar != 0) + 2 * !borrow_out;
}
static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst) static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst)
{ {
if ((uint64_t)dst == 0x8000000000000000ULL) { if ((uint64_t)dst == 0x8000000000000000ULL) {
@ -240,22 +258,21 @@ static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1,
} }
} }
static inline uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1, static uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1,
uint32_t a2, uint32_t ar) uint32_t a2, uint32_t ar)
{ {
if (ar == 0) { return (ar != 0) + 2 * (ar < a1);
if (a1) { }
return 2;
} else { static uint32_t cc_calc_addc_32(CPUS390XState *env, uint32_t a1,
return 0; uint32_t a2, uint32_t ar)
} {
} else { /* Recover a2 + carry_in. */
if (ar < a1 || ar < a2) { uint32_t a2c = ar - a1;
return 3; /* Check for a2+carry_in overflow, then a1+a2c overflow. */
} else { int carry_out = (a2c < a2) || (ar < a1);
return 1;
} return (ar != 0) + 2 * carry_out;
}
} }
static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1,
@ -288,6 +305,25 @@ static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1,
} }
} }
static uint32_t cc_calc_subb_32(CPUS390XState *env, uint32_t a1,
uint32_t a2, uint32_t ar)
{
/* We had borrow-in if normal subtraction isn't equal. */
int borrow_in = ar - (a1 - a2);
int borrow_out;
/* If a2 was UINT_MAX, and borrow_in, then a2 is logically 65 bits,
and we must have had borrow out. */
if (borrow_in && a2 == (uint32_t)-1) {
borrow_out = 1;
} else {
a2 += borrow_in;
borrow_out = (a2 > a1);
}
return (ar != 0) + 2 * !borrow_out;
}
static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst) static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst)
{ {
if ((uint32_t)dst == 0x80000000UL) { if ((uint32_t)dst == 0x80000000UL) {
@ -426,12 +462,18 @@ static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op,
case CC_OP_ADDU_64: case CC_OP_ADDU_64:
r = cc_calc_addu_64(env, src, dst, vr); r = cc_calc_addu_64(env, src, dst, vr);
break; break;
case CC_OP_ADDC_64:
r = cc_calc_addc_64(env, src, dst, vr);
break;
case CC_OP_SUB_64: case CC_OP_SUB_64:
r = cc_calc_sub_64(env, src, dst, vr); r = cc_calc_sub_64(env, src, dst, vr);
break; break;
case CC_OP_SUBU_64: case CC_OP_SUBU_64:
r = cc_calc_subu_64(env, src, dst, vr); r = cc_calc_subu_64(env, src, dst, vr);
break; break;
case CC_OP_SUBB_64:
r = cc_calc_subb_64(env, src, dst, vr);
break;
case CC_OP_ABS_64: case CC_OP_ABS_64:
r = cc_calc_abs_64(env, dst); r = cc_calc_abs_64(env, dst);
break; break;
@ -448,12 +490,18 @@ static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op,
case CC_OP_ADDU_32: case CC_OP_ADDU_32:
r = cc_calc_addu_32(env, src, dst, vr); r = cc_calc_addu_32(env, src, dst, vr);
break; break;
case CC_OP_ADDC_32:
r = cc_calc_addc_32(env, src, dst, vr);
break;
case CC_OP_SUB_32: case CC_OP_SUB_32:
r = cc_calc_sub_32(env, src, dst, vr); r = cc_calc_sub_32(env, src, dst, vr);
break; break;
case CC_OP_SUBU_32: case CC_OP_SUBU_32:
r = cc_calc_subu_32(env, src, dst, vr); r = cc_calc_subu_32(env, src, dst, vr);
break; break;
case CC_OP_SUBB_32:
r = cc_calc_subb_32(env, src, dst, vr);
break;
case CC_OP_ABS_32: case CC_OP_ABS_32:
r = cc_calc_abs_64(env, dst); r = cc_calc_abs_64(env, dst);
break; break;

View File

@ -449,15 +449,19 @@ enum cc_op {
CC_OP_ADD_64, /* overflow on add (64bit) */ CC_OP_ADD_64, /* overflow on add (64bit) */
CC_OP_ADDU_64, /* overflow on unsigned add (64bit) */ CC_OP_ADDU_64, /* overflow on unsigned add (64bit) */
CC_OP_ADDC_64, /* overflow on unsigned add-carry (64bit) */
CC_OP_SUB_64, /* overflow on subtraction (64bit) */ CC_OP_SUB_64, /* overflow on subtraction (64bit) */
CC_OP_SUBU_64, /* overflow on unsigned subtraction (64bit) */ CC_OP_SUBU_64, /* overflow on unsigned subtraction (64bit) */
CC_OP_SUBB_64, /* overflow on unsigned sub-borrow (64bit) */
CC_OP_ABS_64, /* sign eval on abs (64bit) */ CC_OP_ABS_64, /* sign eval on abs (64bit) */
CC_OP_NABS_64, /* sign eval on nabs (64bit) */ CC_OP_NABS_64, /* sign eval on nabs (64bit) */
CC_OP_ADD_32, /* overflow on add (32bit) */ CC_OP_ADD_32, /* overflow on add (32bit) */
CC_OP_ADDU_32, /* overflow on unsigned add (32bit) */ CC_OP_ADDU_32, /* overflow on unsigned add (32bit) */
CC_OP_ADDC_32, /* overflow on unsigned add-carry (32bit) */
CC_OP_SUB_32, /* overflow on subtraction (32bit) */ CC_OP_SUB_32, /* overflow on subtraction (32bit) */
CC_OP_SUBU_32, /* overflow on unsigned subtraction (32bit) */ CC_OP_SUBU_32, /* overflow on unsigned subtraction (32bit) */
CC_OP_SUBB_32, /* overflow on unsigned sub-borrow (32bit) */
CC_OP_ABS_32, /* sign eval on abs (64bit) */ CC_OP_ABS_32, /* sign eval on abs (64bit) */
CC_OP_NABS_32, /* sign eval on nabs (64bit) */ CC_OP_NABS_32, /* sign eval on nabs (64bit) */
@ -494,14 +498,18 @@ static const char *cc_names[] = {
[CC_OP_LTGT0_64] = "CC_OP_LTGT0_64", [CC_OP_LTGT0_64] = "CC_OP_LTGT0_64",
[CC_OP_ADD_64] = "CC_OP_ADD_64", [CC_OP_ADD_64] = "CC_OP_ADD_64",
[CC_OP_ADDU_64] = "CC_OP_ADDU_64", [CC_OP_ADDU_64] = "CC_OP_ADDU_64",
[CC_OP_ADDC_64] = "CC_OP_ADDC_64",
[CC_OP_SUB_64] = "CC_OP_SUB_64", [CC_OP_SUB_64] = "CC_OP_SUB_64",
[CC_OP_SUBU_64] = "CC_OP_SUBU_64", [CC_OP_SUBU_64] = "CC_OP_SUBU_64",
[CC_OP_SUBB_64] = "CC_OP_SUBB_64",
[CC_OP_ABS_64] = "CC_OP_ABS_64", [CC_OP_ABS_64] = "CC_OP_ABS_64",
[CC_OP_NABS_64] = "CC_OP_NABS_64", [CC_OP_NABS_64] = "CC_OP_NABS_64",
[CC_OP_ADD_32] = "CC_OP_ADD_32", [CC_OP_ADD_32] = "CC_OP_ADD_32",
[CC_OP_ADDU_32] = "CC_OP_ADDU_32", [CC_OP_ADDU_32] = "CC_OP_ADDU_32",
[CC_OP_ADDC_32] = "CC_OP_ADDC_32",
[CC_OP_SUB_32] = "CC_OP_SUB_32", [CC_OP_SUB_32] = "CC_OP_SUB_32",
[CC_OP_SUBU_32] = "CC_OP_SUBU_32", [CC_OP_SUBU_32] = "CC_OP_SUBU_32",
[CC_OP_SUBB_32] = "CC_OP_SUBB_32",
[CC_OP_ABS_32] = "CC_OP_ABS_32", [CC_OP_ABS_32] = "CC_OP_ABS_32",
[CC_OP_NABS_32] = "CC_OP_NABS_32", [CC_OP_NABS_32] = "CC_OP_NABS_32",
[CC_OP_COMP_32] = "CC_OP_COMP_32", [CC_OP_COMP_32] = "CC_OP_COMP_32",

View File

@ -26,13 +26,10 @@ DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_NO_RWG_SE, s64, s64)
DEF_HELPER_4(stcmh, void, env, i32, i64, i32) DEF_HELPER_4(stcmh, void, env, i32, i64, i32)
DEF_HELPER_4(icmh, i32, env, i32, i64, i32) DEF_HELPER_4(icmh, i32, env, i32, i64, i32)
DEF_HELPER_3(ipm, void, env, i32, i32) DEF_HELPER_3(ipm, void, env, i32, i32)
DEF_HELPER_FLAGS_3(addc_u32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32)
DEF_HELPER_4(stam, void, env, i32, i64, i32) DEF_HELPER_4(stam, void, env, i32, i64, i32)
DEF_HELPER_4(lam, void, env, i32, i64, i32) DEF_HELPER_4(lam, void, env, i32, i64, i32)
DEF_HELPER_4(mvcle, i32, env, i32, i64, i32) DEF_HELPER_4(mvcle, i32, env, i32, i64, i32)
DEF_HELPER_4(clcle, i32, env, i32, i64, i32) DEF_HELPER_4(clcle, i32, env, i32, i64, i32)
DEF_HELPER_4(slb, i32, env, i32, i32, i32)
DEF_HELPER_5(slbg, i32, env, i32, i32, i64, i64)
DEF_HELPER_3(cefbr, void, env, i32, s32) DEF_HELPER_3(cefbr, void, env, i32, s32)
DEF_HELPER_3(cdfbr, void, env, i32, s32) DEF_HELPER_3(cdfbr, void, env, i32, s32)
DEF_HELPER_3(cxfbr, void, env, i32, s32) DEF_HELPER_3(cxfbr, void, env, i32, s32)

View File

@ -40,6 +40,11 @@
C(0xecda, ALHSIK, RIE_d, DO, r3, i2, new, r1_32, add, addu32) C(0xecda, ALHSIK, RIE_d, DO, r3, i2, new, r1_32, add, addu32)
C(0xeb7e, ALGSI, SIY, GIE, m1_64, i2, new, m1_64, add, addu64) C(0xeb7e, ALGSI, SIY, GIE, m1_64, i2, new, m1_64, add, addu64)
C(0xecdb, ALGHSIK, RIE_d, DO, r3, i2, r1, 0, add, addu64) C(0xecdb, ALGHSIK, RIE_d, DO, r3, i2, r1, 0, add, addu64)
/* ADD LOGICAL WITH CARRY */
C(0xb998, ALCR, RRE, Z, r1, r2, new, r1_32, addc, addc32)
C(0xb988, ALCGR, RRE, Z, r1, r2, r1, 0, addc, addc64)
C(0xe398, ALC, RXY_a, Z, r1, m2_32u, new, r1_32, addc, addc32)
C(0xe388, ALCG, RXY_a, Z, r1, m2_64, r1, 0, addc, addc64)
/* AND */ /* AND */
C(0x1400, NR, RR_a, Z, r1, r2, new, r1_32, and, nz32) C(0x1400, NR, RR_a, Z, r1, r2, new, r1_32, and, nz32)
@ -291,3 +296,8 @@
/* SUBTRACT LOGICAL IMMEDIATE */ /* SUBTRACT LOGICAL IMMEDIATE */
C(0xc205, SLFI, RIL_a, EI, r1, i2_32u, new, r1_32, sub, subu32) C(0xc205, SLFI, RIL_a, EI, r1, i2_32u, new, r1_32, sub, subu32)
C(0xc204, SLGFI, RIL_a, EI, r1, i2_32u, r1, 0, sub, subu64) C(0xc204, SLGFI, RIL_a, EI, r1, i2_32u, r1, 0, sub, subu64)
/* SUBTRACT LOGICAL WITH BORROW */
C(0xb999, SLBR, RRE, Z, r1, r2, new, r1_32, subb, subb32)
C(0xb989, SLBGR, RRE, Z, r1, r2, r1, 0, subb, subb64)
C(0xe399, SLB, RXY_a, Z, r1, m2_32u, new, r1_32, subb, subb32)
C(0xe389, SLBG, RXY_a, Z, r1, m2_64, r1, 0, subb, subb64)

View File

@ -107,49 +107,6 @@ int64_t HELPER(nabs_i64)(int64_t val)
} }
} }
/* add with carry 32-bit unsigned */
uint32_t HELPER(addc_u32)(uint32_t cc, uint32_t v1, uint32_t v2)
{
uint32_t res;
res = v1 + v2;
if (cc & 2) {
res++;
}
return res;
}
/* subtract unsigned v2 from v1 with borrow */
uint32_t HELPER(slb)(CPUS390XState *env, uint32_t cc, uint32_t r1, uint32_t v2)
{
uint32_t v1 = env->regs[r1];
uint32_t res = v1 + (~v2) + (cc >> 1);
env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res;
if (cc & 2) {
/* borrow */
return v1 ? 1 : 0;
} else {
return v1 ? 3 : 2;
}
}
/* subtract unsigned v2 from v1 with borrow */
uint32_t HELPER(slbg)(CPUS390XState *env, uint32_t cc, uint32_t r1,
uint64_t v1, uint64_t v2)
{
uint64_t res = v1 + (~v2) + (cc >> 1);
env->regs[r1] = res;
if (cc & 2) {
/* borrow */
return v1 ? 1 : 0;
} else {
return v1 ? 3 : 2;
}
}
/* find leftmost one */ /* find leftmost one */
uint32_t HELPER(flogr)(CPUS390XState *env, uint32_t r1, uint64_t v2) uint32_t HELPER(flogr)(CPUS390XState *env, uint32_t r1, uint64_t v2)
{ {

View File

@ -474,15 +474,6 @@ static void gen_op_update3_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src,
s->cc_op = op; s->cc_op = op;
} }
static void gen_op_update3_cc_i32(DisasContext *s, enum cc_op op, TCGv_i32 src,
TCGv_i32 dst, TCGv_i32 vr)
{
tcg_gen_extu_i32_i64(cc_src, src);
tcg_gen_extu_i32_i64(cc_dst, dst);
tcg_gen_extu_i32_i64(cc_vr, vr);
s->cc_op = op;
}
static inline void set_cc_nz_u32(DisasContext *s, TCGv_i32 val) static inline void set_cc_nz_u32(DisasContext *s, TCGv_i32 val)
{ {
gen_op_update1_cc_i32(s, CC_OP_NZ, val); gen_op_update1_cc_i32(s, CC_OP_NZ, val);
@ -564,18 +555,6 @@ static inline void set_cc_s64(DisasContext *s, TCGv_i64 val)
gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, val); gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, val);
} }
static void set_cc_addu64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2,
TCGv_i64 vr)
{
gen_op_update3_cc_i64(s, CC_OP_ADDU_64, v1, v2, vr);
}
static void set_cc_addu32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2,
TCGv_i32 vr)
{
gen_op_update3_cc_i32(s, CC_OP_ADDU_32, v1, v2, vr);
}
static void set_cc_icm(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2) static void set_cc_icm(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2)
{ {
gen_op_update2_cc_i32(s, CC_OP_ICM, v1, v2); gen_op_update2_cc_i32(s, CC_OP_ICM, v1, v2);
@ -661,12 +640,16 @@ static void gen_op_calc_cc(DisasContext *s)
break; break;
case CC_OP_ADD_64: case CC_OP_ADD_64:
case CC_OP_ADDU_64: case CC_OP_ADDU_64:
case CC_OP_ADDC_64:
case CC_OP_SUB_64: case CC_OP_SUB_64:
case CC_OP_SUBU_64: case CC_OP_SUBU_64:
case CC_OP_SUBB_64:
case CC_OP_ADD_32: case CC_OP_ADD_32:
case CC_OP_ADDU_32: case CC_OP_ADDU_32:
case CC_OP_ADDC_32:
case CC_OP_SUB_32: case CC_OP_SUB_32:
case CC_OP_SUBU_32: case CC_OP_SUBU_32:
case CC_OP_SUBB_32:
/* 3 arguments */ /* 3 arguments */
gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, cc_vr); gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, cc_vr);
break; break;
@ -1313,7 +1296,7 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1,
int x2, int b2, int d2) int x2, int b2, int d2)
{ {
TCGv_i64 addr, tmp, tmp2, tmp3, tmp4; TCGv_i64 addr, tmp, tmp2, tmp3, tmp4;
TCGv_i32 tmp32_1, tmp32_2, tmp32_3; TCGv_i32 tmp32_1;
LOG_DISAS("disas_e3: op 0x%x r1 %d x2 %d b2 %d d2 %d\n", LOG_DISAS("disas_e3: op 0x%x r1 %d x2 %d b2 %d d2 %d\n",
op, r1, x2, b2, d2); op, r1, x2, b2, d2);
@ -1394,33 +1377,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1,
tcg_temp_free_i64(tmp2); tcg_temp_free_i64(tmp2);
tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_1);
break; break;
case 0x88: /* ALCG R1,D2(X2,B2) [RXY] */
tmp2 = tcg_temp_new_i64();
tmp3 = tcg_temp_new_i64();
tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
/* XXX possible optimization point */
gen_op_calc_cc(s);
tcg_gen_extu_i32_i64(tmp3, cc_op);
tcg_gen_shri_i64(tmp3, tmp3, 1);
tcg_gen_andi_i64(tmp3, tmp3, 1);
tcg_gen_add_i64(tmp3, tmp2, tmp3);
tcg_gen_add_i64(tmp3, regs[r1], tmp3);
store_reg(r1, tmp3);
set_cc_addu64(s, regs[r1], tmp2, tmp3);
tcg_temp_free_i64(tmp2);
tcg_temp_free_i64(tmp3);
break;
case 0x89: /* SLBG R1,D2(X2,B2) [RXY] */
tmp2 = tcg_temp_new_i64();
tmp32_1 = tcg_const_i32(r1);
tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s));
/* XXX possible optimization point */
gen_op_calc_cc(s);
gen_helper_slbg(cc_op, cpu_env, cc_op, tmp32_1, regs[r1], tmp2);
set_cc_static(s);
tcg_temp_free_i64(tmp2);
tcg_temp_free_i32(tmp32_1);
break;
case 0x97: /* DL R1,D2(X2,B2) [RXY] */ case 0x97: /* DL R1,D2(X2,B2) [RXY] */
/* reg(r1) = reg(r1, r1+1) % ld32(addr) */ /* reg(r1) = reg(r1, r1+1) % ld32(addr) */
/* reg(r1+1) = reg(r1, r1+1) / ld32(addr) */ /* reg(r1+1) = reg(r1, r1+1) / ld32(addr) */
@ -1441,37 +1397,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1,
tcg_temp_free_i64(tmp2); tcg_temp_free_i64(tmp2);
tcg_temp_free_i64(tmp3); tcg_temp_free_i64(tmp3);
break; break;
case 0x98: /* ALC R1,D2(X2,B2) [RXY] */
tmp2 = tcg_temp_new_i64();
tmp32_1 = load_reg32(r1);
tmp32_2 = tcg_temp_new_i32();
tmp32_3 = tcg_temp_new_i32();
tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
/* XXX possible optimization point */
gen_op_calc_cc(s);
gen_helper_addc_u32(tmp32_3, cc_op, tmp32_1, tmp32_2);
set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3);
store_reg32(r1, tmp32_3);
tcg_temp_free_i64(tmp2);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2);
tcg_temp_free_i32(tmp32_3);
break;
case 0x99: /* SLB R1,D2(X2,B2) [RXY] */
tmp2 = tcg_temp_new_i64();
tmp32_1 = tcg_const_i32(r1);
tmp32_2 = tcg_temp_new_i32();
tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s));
tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
/* XXX possible optimization point */
gen_op_calc_cc(s);
gen_helper_slb(cc_op, cpu_env, cc_op, tmp32_1, tmp32_2);
set_cc_static(s);
tcg_temp_free_i64(tmp2);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2);
break;
default: default:
LOG_DISAS("illegal e3 operation 0x%x\n", op); LOG_DISAS("illegal e3 operation 0x%x\n", op);
gen_illegal_opcode(s); gen_illegal_opcode(s);
@ -2591,7 +2516,7 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1,
int r2) int r2)
{ {
TCGv_i64 tmp, tmp2, tmp3; TCGv_i64 tmp, tmp2, tmp3;
TCGv_i32 tmp32_1, tmp32_2, tmp32_3; TCGv_i32 tmp32_1;
LOG_DISAS("disas_b9: op 0x%x r1 %d r2 %d\n", op, r1, r2); LOG_DISAS("disas_b9: op 0x%x r1 %d r2 %d\n", op, r1, r2);
switch (op) { switch (op) {
@ -2648,33 +2573,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1,
tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp);
tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_1);
break; break;
case 0x88: /* ALCGR R1,R2 [RRE] */
tmp = load_reg(r1);
tmp2 = load_reg(r2);
tmp3 = tcg_temp_new_i64();
gen_op_calc_cc(s);
tcg_gen_extu_i32_i64(tmp3, cc_op);
tcg_gen_shri_i64(tmp3, tmp3, 1);
tcg_gen_andi_i64(tmp3, tmp3, 1);
tcg_gen_add_i64(tmp3, tmp2, tmp3);
tcg_gen_add_i64(tmp3, tmp, tmp3);
store_reg(r1, tmp3);
set_cc_addu64(s, tmp, tmp2, tmp3);
tcg_temp_free_i64(tmp);
tcg_temp_free_i64(tmp2);
tcg_temp_free_i64(tmp3);
break;
case 0x89: /* SLBGR R1,R2 [RRE] */
tmp = load_reg(r1);
tmp2 = load_reg(r2);
tmp32_1 = tcg_const_i32(r1);
gen_op_calc_cc(s);
gen_helper_slbg(cc_op, cpu_env, cc_op, tmp32_1, tmp, tmp2);
set_cc_static(s);
tcg_temp_free_i64(tmp);
tcg_temp_free_i64(tmp2);
tcg_temp_free_i32(tmp32_1);
break;
case 0x97: /* DLR R1,R2 [RRE] */ case 0x97: /* DLR R1,R2 [RRE] */
/* reg(r1) = reg(r1, r1+1) % reg(r2) */ /* reg(r1) = reg(r1, r1+1) % reg(r2) */
/* reg(r1+1) = reg(r1, r1+1) / reg(r2) */ /* reg(r1+1) = reg(r1, r1+1) / reg(r2) */
@ -2694,28 +2592,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1,
tcg_temp_free_i64(tmp2); tcg_temp_free_i64(tmp2);
tcg_temp_free_i64(tmp3); tcg_temp_free_i64(tmp3);
break; break;
case 0x98: /* ALCR R1,R2 [RRE] */
tmp32_1 = load_reg32(r1);
tmp32_2 = load_reg32(r2);
tmp32_3 = tcg_temp_new_i32();
/* XXX possible optimization point */
gen_op_calc_cc(s);
gen_helper_addc_u32(tmp32_3, cc_op, tmp32_1, tmp32_2);
set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3);
store_reg32(r1, tmp32_3);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2);
tcg_temp_free_i32(tmp32_3);
break;
case 0x99: /* SLBR R1,R2 [RRE] */
tmp32_1 = load_reg32(r2);
tmp32_2 = tcg_const_i32(r1);
gen_op_calc_cc(s);
gen_helper_slb(cc_op, cpu_env, cc_op, tmp32_2, tmp32_1);
set_cc_static(s);
tcg_temp_free_i32(tmp32_1);
tcg_temp_free_i32(tmp32_2);
break;
default: default:
LOG_DISAS("illegal b9 operation 0x%x\n", op); LOG_DISAS("illegal b9 operation 0x%x\n", op);
gen_illegal_opcode(s); gen_illegal_opcode(s);
@ -3883,6 +3759,23 @@ static ExitStatus op_add(DisasContext *s, DisasOps *o)
return NO_EXIT; return NO_EXIT;
} }
static ExitStatus op_addc(DisasContext *s, DisasOps *o)
{
TCGv_i64 cc;
tcg_gen_add_i64(o->out, o->in1, o->in2);
/* XXX possible optimization point */
gen_op_calc_cc(s);
cc = tcg_temp_new_i64();
tcg_gen_extu_i32_i64(cc, cc_op);
tcg_gen_shri_i64(cc, cc, 1);
tcg_gen_add_i64(o->out, o->out, cc);
tcg_temp_free_i64(cc);
return NO_EXIT;
}
static ExitStatus op_and(DisasContext *s, DisasOps *o) static ExitStatus op_and(DisasContext *s, DisasOps *o)
{ {
tcg_gen_and_i64(o->out, o->in1, o->in2); tcg_gen_and_i64(o->out, o->in1, o->in2);
@ -4042,6 +3935,24 @@ static ExitStatus op_sub(DisasContext *s, DisasOps *o)
return NO_EXIT; return NO_EXIT;
} }
static ExitStatus op_subb(DisasContext *s, DisasOps *o)
{
TCGv_i64 cc;
assert(!o->g_in2);
tcg_gen_not_i64(o->in2, o->in2);
tcg_gen_add_i64(o->out, o->in1, o->in2);
/* XXX possible optimization point */
gen_op_calc_cc(s);
cc = tcg_temp_new_i64();
tcg_gen_extu_i32_i64(cc, cc_op);
tcg_gen_shri_i64(cc, cc, 1);
tcg_gen_add_i64(o->out, o->out, cc);
tcg_temp_free_i64(cc);
return NO_EXIT;
}
static ExitStatus op_xor(DisasContext *s, DisasOps *o) static ExitStatus op_xor(DisasContext *s, DisasOps *o)
{ {
tcg_gen_xor_i64(o->out, o->in1, o->in2); tcg_gen_xor_i64(o->out, o->in1, o->in2);
@ -4099,6 +4010,16 @@ static void cout_addu64(DisasContext *s, DisasOps *o)
gen_op_update3_cc_i64(s, CC_OP_ADDU_64, o->in1, o->in2, o->out); gen_op_update3_cc_i64(s, CC_OP_ADDU_64, o->in1, o->in2, o->out);
} }
static void cout_addc32(DisasContext *s, DisasOps *o)
{
gen_op_update3_cc_i64(s, CC_OP_ADDC_32, o->in1, o->in2, o->out);
}
static void cout_addc64(DisasContext *s, DisasOps *o)
{
gen_op_update3_cc_i64(s, CC_OP_ADDC_64, o->in1, o->in2, o->out);
}
static void cout_cmps32(DisasContext *s, DisasOps *o) static void cout_cmps32(DisasContext *s, DisasOps *o)
{ {
gen_op_update2_cc_i64(s, CC_OP_LTGT_32, o->in1, o->in2); gen_op_update2_cc_i64(s, CC_OP_LTGT_32, o->in1, o->in2);
@ -4180,6 +4101,16 @@ static void cout_subu64(DisasContext *s, DisasOps *o)
gen_op_update3_cc_i64(s, CC_OP_SUBU_64, o->in1, o->in2, o->out); gen_op_update3_cc_i64(s, CC_OP_SUBU_64, o->in1, o->in2, o->out);
} }
static void cout_subb32(DisasContext *s, DisasOps *o)
{
gen_op_update3_cc_i64(s, CC_OP_SUBB_32, o->in1, o->in2, o->out);
}
static void cout_subb64(DisasContext *s, DisasOps *o)
{
gen_op_update3_cc_i64(s, CC_OP_SUBB_64, o->in1, o->in2, o->out);
}
/* ====================================================================== */ /* ====================================================================== */
/* The "PREPeration" generators. These initialize the DisasOps.OUT fields /* The "PREPeration" generators. These initialize the DisasOps.OUT fields
with the TCG register to which we will write. Used in combination with with the TCG register to which we will write. Used in combination with