uint64_t pc, next_pc;
enum cc_op cc_op;
bool singlestep_enabled;
- int is_jmp;
};
/* Information carried about a condition to be evaluated. */
#define DISAS_EXCP 4
-static void gen_op_calc_cc(DisasContext *s);
-
#ifdef DEBUG_INLINE_BRANCHES
static uint64_t inline_branch_hit[CC_OP_MAX];
static uint64_t inline_branch_miss[CC_OP_MAX];
#endif
-static inline void debug_insn(uint64_t insn)
-{
- LOG_DISAS("insn: 0x%" PRIx64 "\n", insn);
-}
-
-static inline uint64_t pc_to_link_info(DisasContext *s, uint64_t pc)
+static uint64_t pc_to_link_info(DisasContext *s, uint64_t pc)
{
if (!(s->tb->flags & FLAG_MASK_64)) {
if (s->tb->flags & FLAG_MASK_32) {
#include "helper.h"
}
-static inline TCGv_i64 load_reg(int reg)
+static TCGv_i64 load_reg(int reg)
{
TCGv_i64 r = tcg_temp_new_i64();
tcg_gen_mov_i64(r, regs[reg]);
return r;
}
-static inline TCGv_i64 load_freg(int reg)
-{
- TCGv_i64 r = tcg_temp_new_i64();
- tcg_gen_mov_i64(r, fregs[reg]);
- return r;
-}
-
-static inline TCGv_i32 load_freg32(int reg)
-{
- TCGv_i32 r = tcg_temp_new_i32();
-#if HOST_LONG_BITS == 32
- tcg_gen_mov_i32(r, TCGV_HIGH(fregs[reg]));
-#else
- tcg_gen_shri_i64(MAKE_TCGV_I64(GET_TCGV_I32(r)), fregs[reg], 32);
-#endif
- return r;
-}
-
-static inline TCGv_i64 load_freg32_i64(int reg)
+static TCGv_i64 load_freg32_i64(int reg)
{
TCGv_i64 r = tcg_temp_new_i64();
tcg_gen_shri_i64(r, fregs[reg], 32);
return r;
}
-static inline TCGv_i32 load_reg32(int reg)
-{
- TCGv_i32 r = tcg_temp_new_i32();
- tcg_gen_trunc_i64_i32(r, regs[reg]);
- return r;
-}
-
-static inline TCGv_i64 load_reg32_i64(int reg)
-{
- TCGv_i64 r = tcg_temp_new_i64();
- tcg_gen_ext32s_i64(r, regs[reg]);
- return r;
-}
-
-static inline void store_reg(int reg, TCGv_i64 v)
+static void store_reg(int reg, TCGv_i64 v)
{
tcg_gen_mov_i64(regs[reg], v);
}
-static inline void store_freg(int reg, TCGv_i64 v)
+static void store_freg(int reg, TCGv_i64 v)
{
tcg_gen_mov_i64(fregs[reg], v);
}
-static inline void store_reg32(int reg, TCGv_i32 v)
-{
- /* 32 bit register writes keep the upper half */
-#if HOST_LONG_BITS == 32
- tcg_gen_mov_i32(TCGV_LOW(regs[reg]), v);
-#else
- tcg_gen_deposit_i64(regs[reg], regs[reg],
- MAKE_TCGV_I64(GET_TCGV_I32(v)), 0, 32);
-#endif
-}
-
-static inline void store_reg32_i64(int reg, TCGv_i64 v)
+static void store_reg32_i64(int reg, TCGv_i64 v)
{
/* 32 bit register writes keep the upper half */
tcg_gen_deposit_i64(regs[reg], regs[reg], v, 0, 32);
}
-static inline void store_reg32h_i64(int reg, TCGv_i64 v)
+static void store_reg32h_i64(int reg, TCGv_i64 v)
{
tcg_gen_deposit_i64(regs[reg], regs[reg], v, 32, 32);
}
-static inline void store_freg32(int reg, TCGv_i32 v)
-{
- /* 32 bit register writes keep the lower half */
-#if HOST_LONG_BITS == 32
- tcg_gen_mov_i32(TCGV_HIGH(fregs[reg]), v);
-#else
- tcg_gen_deposit_i64(fregs[reg], fregs[reg],
- MAKE_TCGV_I64(GET_TCGV_I32(v)), 32, 32);
-#endif
-}
-
-static inline void store_freg32_i64(int reg, TCGv_i64 v)
+static void store_freg32_i64(int reg, TCGv_i64 v)
{
tcg_gen_deposit_i64(fregs[reg], fregs[reg], v, 32, 32);
}
-static inline void return_low128(TCGv_i64 dest)
+static void return_low128(TCGv_i64 dest)
{
tcg_gen_ld_i64(dest, cpu_env, offsetof(CPUS390XState, retxl));
}
-static inline void update_psw_addr(DisasContext *s)
+static void update_psw_addr(DisasContext *s)
{
/* psw.addr */
tcg_gen_movi_i64(psw_addr, s->pc);
}
-static inline void potential_page_fault(DisasContext *s)
+static void update_cc_op(DisasContext *s)
+{
+ if (s->cc_op != CC_OP_DYNAMIC && s->cc_op != CC_OP_STATIC) {
+ tcg_gen_movi_i32(cc_op, s->cc_op);
+ }
+}
+
+static void potential_page_fault(DisasContext *s)
{
-#ifndef CONFIG_USER_ONLY
update_psw_addr(s);
- gen_op_calc_cc(s);
-#endif
+ update_cc_op(s);
}
static inline uint64_t ld_code2(CPUS390XState *env, uint64_t pc)
return (ld_code2(env, pc) << 32) | ld_code4(env, pc + 2);
}
-static inline int get_mem_index(DisasContext *s)
+static int get_mem_index(DisasContext *s)
{
switch (s->tb->flags & FLAG_MASK_ASC) {
case PSW_ASC_PRIMARY >> 32:
update_psw_addr(s);
/* Save off cc. */
- gen_op_calc_cc(s);
+ update_cc_op(s);
/* Trigger exception. */
gen_exception(EXCP_PGM);
-
- /* End TB here. */
- s->is_jmp = DISAS_EXCP;
}
static inline void gen_illegal_opcode(DisasContext *s)
static TCGv_i64 get_address(DisasContext *s, int x2, int b2, int d2)
{
- TCGv_i64 tmp;
+ TCGv_i64 tmp = tcg_temp_new_i64();
+ bool need_31 = !(s->tb->flags & FLAG_MASK_64);
- /* 31-bitify the immediate part; register contents are dealt with below */
- if (!(s->tb->flags & FLAG_MASK_64)) {
- d2 &= 0x7fffffffUL;
- }
+ /* Note that d2 is limited to 20 bits, signed. If we crop negative
+ displacements early we create larger immedate addends. */
- if (x2) {
- if (d2) {
- tmp = tcg_const_i64(d2);
- tcg_gen_add_i64(tmp, tmp, regs[x2]);
- } else {
- tmp = load_reg(x2);
- }
- if (b2) {
- tcg_gen_add_i64(tmp, tmp, regs[b2]);
- }
+ /* Note that addi optimizes the imm==0 case. */
+ if (b2 && x2) {
+ tcg_gen_add_i64(tmp, regs[b2], regs[x2]);
+ tcg_gen_addi_i64(tmp, tmp, d2);
} else if (b2) {
- if (d2) {
- tmp = tcg_const_i64(d2);
- tcg_gen_add_i64(tmp, tmp, regs[b2]);
- } else {
- tmp = load_reg(b2);
- }
+ tcg_gen_addi_i64(tmp, regs[b2], d2);
+ } else if (x2) {
+ tcg_gen_addi_i64(tmp, regs[x2], d2);
} else {
- tmp = tcg_const_i64(d2);
+ if (need_31) {
+ d2 &= 0x7fffffff;
+ need_31 = false;
+ }
+ tcg_gen_movi_i64(tmp, d2);
}
-
- /* 31-bit mode mask if there are values loaded from registers */
- if (!(s->tb->flags & FLAG_MASK_64) && (x2 || b2)) {
- tcg_gen_andi_i64(tmp, tmp, 0x7fffffffUL);
+ if (need_31) {
+ tcg_gen_andi_i64(tmp, tmp, 0x7fffffff);
}
return tmp;
}
+static inline bool live_cc_data(DisasContext *s)
+{
+ return (s->cc_op != CC_OP_DYNAMIC
+ && s->cc_op != CC_OP_STATIC
+ && s->cc_op > 3);
+}
+
static inline void gen_op_movi_cc(DisasContext *s, uint32_t val)
{
+ if (live_cc_data(s)) {
+ tcg_gen_discard_i64(cc_src);
+ tcg_gen_discard_i64(cc_dst);
+ tcg_gen_discard_i64(cc_vr);
+ }
s->cc_op = CC_OP_CONST0 + val;
}
static void gen_op_update1_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 dst)
{
- tcg_gen_discard_i64(cc_src);
+ if (live_cc_data(s)) {
+ tcg_gen_discard_i64(cc_src);
+ tcg_gen_discard_i64(cc_vr);
+ }
tcg_gen_mov_i64(cc_dst, dst);
- tcg_gen_discard_i64(cc_vr);
- s->cc_op = op;
-}
-
-static void gen_op_update1_cc_i32(DisasContext *s, enum cc_op op, TCGv_i32 dst)
-{
- tcg_gen_discard_i64(cc_src);
- tcg_gen_extu_i32_i64(cc_dst, dst);
- tcg_gen_discard_i64(cc_vr);
s->cc_op = op;
}
static void gen_op_update2_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src,
TCGv_i64 dst)
{
+ if (live_cc_data(s)) {
+ tcg_gen_discard_i64(cc_vr);
+ }
tcg_gen_mov_i64(cc_src, src);
tcg_gen_mov_i64(cc_dst, dst);
- tcg_gen_discard_i64(cc_vr);
- s->cc_op = op;
-}
-
-static void gen_op_update2_cc_i32(DisasContext *s, enum cc_op op, TCGv_i32 src,
- TCGv_i32 dst)
-{
- tcg_gen_extu_i32_i64(cc_src, src);
- tcg_gen_extu_i32_i64(cc_dst, dst);
- tcg_gen_discard_i64(cc_vr);
s->cc_op = op;
}
s->cc_op = op;
}
-static inline void set_cc_nz_u32(DisasContext *s, TCGv_i32 val)
-{
- gen_op_update1_cc_i32(s, CC_OP_NZ, val);
-}
-
-static inline void set_cc_nz_u64(DisasContext *s, TCGv_i64 val)
+static void set_cc_nz_u64(DisasContext *s, TCGv_i64 val)
{
gen_op_update1_cc_i64(s, CC_OP_NZ, val);
}
-static inline void gen_set_cc_nz_f32(DisasContext *s, TCGv_i64 val)
+static void gen_set_cc_nz_f32(DisasContext *s, TCGv_i64 val)
{
gen_op_update1_cc_i64(s, CC_OP_NZ_F32, val);
}
-static inline void gen_set_cc_nz_f64(DisasContext *s, TCGv_i64 val)
+static void gen_set_cc_nz_f64(DisasContext *s, TCGv_i64 val)
{
gen_op_update1_cc_i64(s, CC_OP_NZ_F64, val);
}
-static inline void gen_set_cc_nz_f128(DisasContext *s, TCGv_i64 vh, TCGv_i64 vl)
+static void gen_set_cc_nz_f128(DisasContext *s, TCGv_i64 vh, TCGv_i64 vl)
{
gen_op_update2_cc_i64(s, CC_OP_NZ_F128, vh, vl);
}
-static inline void cmp_32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2,
- enum cc_op cond)
-{
- gen_op_update2_cc_i32(s, cond, v1, v2);
-}
-
-static inline void cmp_64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2,
- enum cc_op cond)
-{
- gen_op_update2_cc_i64(s, cond, v1, v2);
-}
-
-static inline void cmp_s32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2)
-{
- cmp_32(s, v1, v2, CC_OP_LTGT_32);
-}
-
-static inline void cmp_u32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2)
-{
- cmp_32(s, v1, v2, CC_OP_LTUGTU_32);
-}
-
-static inline void cmp_s32c(DisasContext *s, TCGv_i32 v1, int32_t v2)
-{
- /* XXX optimize for the constant? put it in s? */
- TCGv_i32 tmp = tcg_const_i32(v2);
- cmp_32(s, v1, tmp, CC_OP_LTGT_32);
- tcg_temp_free_i32(tmp);
-}
-
-static inline void cmp_u32c(DisasContext *s, TCGv_i32 v1, uint32_t v2)
-{
- TCGv_i32 tmp = tcg_const_i32(v2);
- cmp_32(s, v1, tmp, CC_OP_LTUGTU_32);
- tcg_temp_free_i32(tmp);
-}
-
-static inline void cmp_s64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2)
-{
- cmp_64(s, v1, v2, CC_OP_LTGT_64);
-}
-
-static inline void cmp_u64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2)
-{
- cmp_64(s, v1, v2, CC_OP_LTUGTU_64);
-}
-
-static inline void cmp_s64c(DisasContext *s, TCGv_i64 v1, int64_t v2)
-{
- TCGv_i64 tmp = tcg_const_i64(v2);
- cmp_s64(s, v1, tmp);
- tcg_temp_free_i64(tmp);
-}
-
-static inline void cmp_u64c(DisasContext *s, TCGv_i64 v1, uint64_t v2)
-{
- TCGv_i64 tmp = tcg_const_i64(v2);
- cmp_u64(s, v1, tmp);
- tcg_temp_free_i64(tmp);
-}
-
-static inline void set_cc_s32(DisasContext *s, TCGv_i32 val)
-{
- gen_op_update1_cc_i32(s, CC_OP_LTGT0_32, val);
-}
-
-static inline void set_cc_s64(DisasContext *s, TCGv_i64 val)
-{
- gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, val);
-}
-
/* CC value is in env->cc_op */
-static inline void set_cc_static(DisasContext *s)
-{
- tcg_gen_discard_i64(cc_src);
- tcg_gen_discard_i64(cc_dst);
- tcg_gen_discard_i64(cc_vr);
- s->cc_op = CC_OP_STATIC;
-}
-
-static inline void gen_op_set_cc_op(DisasContext *s)
+static void set_cc_static(DisasContext *s)
{
- if (s->cc_op != CC_OP_DYNAMIC && s->cc_op != CC_OP_STATIC) {
- tcg_gen_movi_i32(cc_op, s->cc_op);
+ if (live_cc_data(s)) {
+ tcg_gen_discard_i64(cc_src);
+ tcg_gen_discard_i64(cc_dst);
+ tcg_gen_discard_i64(cc_vr);
}
-}
-
-static inline void gen_update_cc_op(DisasContext *s)
-{
- gen_op_set_cc_op(s);
+ s->cc_op = CC_OP_STATIC;
}
/* calculates cc into cc_op */
static void gen_op_calc_cc(DisasContext *s)
{
- TCGv_i32 local_cc_op = tcg_const_i32(s->cc_op);
- TCGv_i64 dummy = tcg_const_i64(0);
+ TCGv_i32 local_cc_op;
+ TCGv_i64 dummy;
+
+ TCGV_UNUSED_I32(local_cc_op);
+ TCGV_UNUSED_I64(dummy);
+ switch (s->cc_op) {
+ default:
+ dummy = tcg_const_i64(0);
+ /* FALLTHRU */
+ case CC_OP_ADD_64:
+ case CC_OP_ADDU_64:
+ case CC_OP_ADDC_64:
+ case CC_OP_SUB_64:
+ case CC_OP_SUBU_64:
+ case CC_OP_SUBB_64:
+ case CC_OP_ADD_32:
+ case CC_OP_ADDU_32:
+ case CC_OP_ADDC_32:
+ case CC_OP_SUB_32:
+ case CC_OP_SUBU_32:
+ case CC_OP_SUBB_32:
+ local_cc_op = tcg_const_i32(s->cc_op);
+ break;
+ case CC_OP_CONST0:
+ case CC_OP_CONST1:
+ case CC_OP_CONST2:
+ case CC_OP_CONST3:
+ case CC_OP_STATIC:
+ case CC_OP_DYNAMIC:
+ break;
+ }
switch (s->cc_op) {
case CC_OP_CONST0:
tcg_abort();
}
- tcg_temp_free_i32(local_cc_op);
- tcg_temp_free_i64(dummy);
+ if (!TCGV_IS_UNUSED_I32(local_cc_op)) {
+ tcg_temp_free_i32(local_cc_op);
+ }
+ if (!TCGV_IS_UNUSED_I64(dummy)) {
+ tcg_temp_free_i64(dummy);
+ }
/* We now have cc in cc_op as constant */
set_cc_static(s);
}
-static inline void decode_rr(DisasContext *s, uint64_t insn, int *r1, int *r2)
-{
- debug_insn(insn);
-
- *r1 = (insn >> 4) & 0xf;
- *r2 = insn & 0xf;
-}
-
-static inline TCGv_i64 decode_rx(DisasContext *s, uint64_t insn, int *r1,
- int *x2, int *b2, int *d2)
-{
- debug_insn(insn);
-
- *r1 = (insn >> 20) & 0xf;
- *x2 = (insn >> 16) & 0xf;
- *b2 = (insn >> 12) & 0xf;
- *d2 = insn & 0xfff;
-
- return get_address(s, *x2, *b2, *d2);
-}
-
-static inline void decode_rs(DisasContext *s, uint64_t insn, int *r1, int *r3,
- int *b2, int *d2)
-{
- debug_insn(insn);
-
- *r1 = (insn >> 20) & 0xf;
- /* aka m3 */
- *r3 = (insn >> 16) & 0xf;
- *b2 = (insn >> 12) & 0xf;
- *d2 = insn & 0xfff;
-}
-
-static inline TCGv_i64 decode_si(DisasContext *s, uint64_t insn, int *i2,
- int *b1, int *d1)
-{
- debug_insn(insn);
-
- *i2 = (insn >> 16) & 0xff;
- *b1 = (insn >> 12) & 0xf;
- *d1 = insn & 0xfff;
-
- return get_address(s, 0, *b1, *d1);
-}
-
static int use_goto_tb(DisasContext *s, uint64_t dest)
{
/* NOTE: we handle the case where the TB spans two pages here */
&& !(s->tb->cflags & CF_LAST_IO));
}
-static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong pc)
-{
- gen_update_cc_op(s);
-
- if (use_goto_tb(s, pc)) {
- tcg_gen_goto_tb(tb_num);
- tcg_gen_movi_i64(psw_addr, pc);
- tcg_gen_exit_tb((tcg_target_long)s->tb + tb_num);
- } else {
- /* jump to another page: currently not optimized */
- tcg_gen_movi_i64(psw_addr, pc);
- tcg_gen_exit_tb(0);
- }
-}
-
-static inline void account_noninline_branch(DisasContext *s, int cc_op)
+static void account_noninline_branch(DisasContext *s, int cc_op)
{
#ifdef DEBUG_INLINE_BRANCHES
inline_branch_miss[cc_op]++;
#endif
}
-static inline void account_inline_branch(DisasContext *s, int cc_op)
+static void account_inline_branch(DisasContext *s, int cc_op)
{
#ifdef DEBUG_INLINE_BRANCHES
inline_branch_hit[cc_op]++;
}
/* Table of mask values to comparison codes, given a comparison as input.
- For a true comparison CC=3 will never be set, but we treat this
- conservatively for possible use when CC=3 indicates overflow. */
+ For such, CC=3 should not be possible. */
static const TCGCond ltgt_cond[16] = {
TCG_COND_NEVER, TCG_COND_NEVER, /* | | | x */
- TCG_COND_GT, TCG_COND_NEVER, /* | | GT | x */
- TCG_COND_LT, TCG_COND_NEVER, /* | LT | | x */
- TCG_COND_NE, TCG_COND_NEVER, /* | LT | GT | x */
- TCG_COND_EQ, TCG_COND_NEVER, /* EQ | | | x */
- TCG_COND_GE, TCG_COND_NEVER, /* EQ | | GT | x */
- TCG_COND_LE, TCG_COND_NEVER, /* EQ | LT | | x */
+ TCG_COND_GT, TCG_COND_GT, /* | | GT | x */
+ TCG_COND_LT, TCG_COND_LT, /* | LT | | x */
+ TCG_COND_NE, TCG_COND_NE, /* | LT | GT | x */
+ TCG_COND_EQ, TCG_COND_EQ, /* EQ | | | x */
+ TCG_COND_GE, TCG_COND_GE, /* EQ | | GT | x */
+ TCG_COND_LE, TCG_COND_LE, /* EQ | LT | | x */
TCG_COND_ALWAYS, TCG_COND_ALWAYS, /* EQ | LT | GT | x */
};
/* Table of mask values to comparison codes, given a logic op as input.
For such, only CC=0 and CC=1 should be possible. */
static const TCGCond nz_cond[16] = {
- /* | | x | x */
- TCG_COND_NEVER, TCG_COND_NEVER, TCG_COND_NEVER, TCG_COND_NEVER,
- /* | NE | x | x */
- TCG_COND_NE, TCG_COND_NE, TCG_COND_NE, TCG_COND_NE,
- /* EQ | | x | x */
- TCG_COND_EQ, TCG_COND_EQ, TCG_COND_EQ, TCG_COND_EQ,
- /* EQ | NE | x | x */
- TCG_COND_ALWAYS, TCG_COND_ALWAYS, TCG_COND_ALWAYS, TCG_COND_ALWAYS,
+ TCG_COND_NEVER, TCG_COND_NEVER, /* | | x | x */
+ TCG_COND_NEVER, TCG_COND_NEVER,
+ TCG_COND_NE, TCG_COND_NE, /* | NE | x | x */
+ TCG_COND_NE, TCG_COND_NE,
+ TCG_COND_EQ, TCG_COND_EQ, /* EQ | | x | x */
+ TCG_COND_EQ, TCG_COND_EQ,
+ TCG_COND_ALWAYS, TCG_COND_ALWAYS, /* EQ | NE | x | x */
+ TCG_COND_ALWAYS, TCG_COND_ALWAYS,
};
/* Interpret MASK in terms of S->CC_OP, and fill in C with all the
account_inline_branch(s, old_cc_op);
break;
+ case CC_OP_ADDU_32:
+ case CC_OP_ADDU_64:
+ switch (mask) {
+ case 8 | 2: /* vr == 0 */
+ cond = TCG_COND_EQ;
+ break;
+ case 4 | 1: /* vr != 0 */
+ cond = TCG_COND_NE;
+ break;
+ case 8 | 4: /* no carry -> vr >= src */
+ cond = TCG_COND_GEU;
+ break;
+ case 2 | 1: /* carry -> vr < src */
+ cond = TCG_COND_LTU;
+ break;
+ default:
+ goto do_dynamic;
+ }
+ account_inline_branch(s, old_cc_op);
+ break;
+
+ case CC_OP_SUBU_32:
+ case CC_OP_SUBU_64:
+ /* Note that CC=0 is impossible; treat it as dont-care. */
+ switch (mask & 7) {
+ case 2: /* zero -> op1 == op2 */
+ cond = TCG_COND_EQ;
+ break;
+ case 4 | 1: /* !zero -> op1 != op2 */
+ cond = TCG_COND_NE;
+ break;
+ case 4: /* borrow (!carry) -> op1 < op2 */
+ cond = TCG_COND_LTU;
+ break;
+ case 2 | 1: /* !borrow (carry) -> op1 >= op2 */
+ cond = TCG_COND_GEU;
+ break;
+ default:
+ goto do_dynamic;
+ }
+ account_inline_branch(s, old_cc_op);
+ break;
+
default:
do_dynamic:
/* Calculate cc value. */
break;
case CC_OP_LTGT_32:
case CC_OP_LTUGTU_32:
+ case CC_OP_SUBU_32:
c->is_64 = false;
c->u.s32.a = tcg_temp_new_i32();
tcg_gen_trunc_i64_i32(c->u.s32.a, cc_src);
break;
case CC_OP_LTGT_64:
case CC_OP_LTUGTU_64:
+ case CC_OP_SUBU_64:
c->u.s64.a = cc_src;
c->u.s64.b = cc_dst;
c->g1 = c->g2 = true;
tcg_gen_and_i64(c->u.s64.a, cc_src, cc_dst);
break;
+ case CC_OP_ADDU_32:
+ c->is_64 = false;
+ c->u.s32.a = tcg_temp_new_i32();
+ c->u.s32.b = tcg_temp_new_i32();
+ tcg_gen_trunc_i64_i32(c->u.s32.a, cc_vr);
+ if (cond == TCG_COND_EQ || cond == TCG_COND_NE) {
+ tcg_gen_movi_i32(c->u.s32.b, 0);
+ } else {
+ tcg_gen_trunc_i64_i32(c->u.s32.b, cc_src);
+ }
+ break;
+
+ case CC_OP_ADDU_64:
+ c->u.s64.a = cc_vr;
+ c->g1 = true;
+ if (cond == TCG_COND_EQ || cond == TCG_COND_NE) {
+ c->u.s64.b = tcg_const_i64(0);
+ } else {
+ c->u.s64.b = cc_src;
+ c->g2 = true;
+ }
+ break;
+
case CC_OP_STATIC:
c->is_64 = false;
c->u.s32.a = cc_op;
}
}
-static void disas_b2(CPUS390XState *env, DisasContext *s, int op,
- uint32_t insn)
-{
-#ifndef CONFIG_USER_ONLY
- TCGv_i64 tmp, tmp2, tmp3;
- TCGv_i32 tmp32_1, tmp32_2;
- int r1, r2;
- int r3, d2, b2;
-
- r1 = (insn >> 4) & 0xf;
- r2 = insn & 0xf;
-
- LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2);
-
- switch (op) {
- case 0x21: /* IPTE R1,R2 [RRE] */
- /* Invalidate PTE */
- check_privileged(s);
- r1 = (insn >> 4) & 0xf;
- r2 = insn & 0xf;
- tmp = load_reg(r1);
- tmp2 = load_reg(r2);
- gen_helper_ipte(cpu_env, tmp, tmp2);
- tcg_temp_free_i64(tmp);
- tcg_temp_free_i64(tmp2);
- break;
- case 0x29: /* ISKE R1,R2 [RRE] */
- /* Insert Storage Key Extended */
- check_privileged(s);
- r1 = (insn >> 4) & 0xf;
- r2 = insn & 0xf;
- tmp = load_reg(r2);
- tmp2 = tcg_temp_new_i64();
- gen_helper_iske(tmp2, cpu_env, tmp);
- store_reg(r1, tmp2);
- tcg_temp_free_i64(tmp);
- tcg_temp_free_i64(tmp2);
- break;
- case 0x2a: /* RRBE R1,R2 [RRE] */
- /* Set Storage Key Extended */
- check_privileged(s);
- r1 = (insn >> 4) & 0xf;
- r2 = insn & 0xf;
- tmp32_1 = load_reg32(r1);
- tmp = load_reg(r2);
- gen_helper_rrbe(cc_op, cpu_env, tmp32_1, tmp);
- set_cc_static(s);
- tcg_temp_free_i32(tmp32_1);
- tcg_temp_free_i64(tmp);
- break;
- case 0x2b: /* SSKE R1,R2 [RRE] */
- /* Set Storage Key Extended */
- check_privileged(s);
- r1 = (insn >> 4) & 0xf;
- r2 = insn & 0xf;
- tmp32_1 = load_reg32(r1);
- tmp = load_reg(r2);
- gen_helper_sske(cpu_env, tmp32_1, tmp);
- tcg_temp_free_i32(tmp32_1);
- tcg_temp_free_i64(tmp);
- break;
- case 0x34: /* STCH ? */
- /* Store Subchannel */
- check_privileged(s);
- gen_op_movi_cc(s, 3);
- break;
- case 0x46: /* STURA R1,R2 [RRE] */
- /* Store Using Real Address */
- check_privileged(s);
- r1 = (insn >> 4) & 0xf;
- r2 = insn & 0xf;
- tmp32_1 = load_reg32(r1);
- tmp = load_reg(r2);
- potential_page_fault(s);
- gen_helper_stura(cpu_env, tmp, tmp32_1);
- tcg_temp_free_i32(tmp32_1);
- tcg_temp_free_i64(tmp);
- break;
- case 0x50: /* CSP R1,R2 [RRE] */
- /* Compare And Swap And Purge */
- check_privileged(s);
- r1 = (insn >> 4) & 0xf;
- r2 = insn & 0xf;
- tmp32_1 = tcg_const_i32(r1);
- tmp32_2 = tcg_const_i32(r2);
- gen_helper_csp(cc_op, cpu_env, tmp32_1, tmp32_2);
- set_cc_static(s);
- tcg_temp_free_i32(tmp32_1);
- tcg_temp_free_i32(tmp32_2);
- break;
- case 0x5f: /* CHSC ? */
- /* Channel Subsystem Call */
- check_privileged(s);
- gen_op_movi_cc(s, 3);
- break;
- case 0x78: /* STCKE D2(B2) [S] */
- /* Store Clock Extended */
- decode_rs(s, insn, &r1, &r3, &b2, &d2);
- tmp = get_address(s, 0, b2, d2);
- potential_page_fault(s);
- gen_helper_stcke(cc_op, cpu_env, tmp);
- set_cc_static(s);
- tcg_temp_free_i64(tmp);
- break;
- case 0x79: /* SACF D2(B2) [S] */
- /* Set Address Space Control Fast */
- check_privileged(s);
- decode_rs(s, insn, &r1, &r3, &b2, &d2);
- tmp = get_address(s, 0, b2, d2);
- potential_page_fault(s);
- gen_helper_sacf(cpu_env, tmp);
- tcg_temp_free_i64(tmp);
- /* addressing mode has changed, so end the block */
- s->pc = s->next_pc;
- update_psw_addr(s);
- s->is_jmp = DISAS_JUMP;
- break;
- case 0x7d: /* STSI D2,(B2) [S] */
- check_privileged(s);
- decode_rs(s, insn, &r1, &r3, &b2, &d2);
- tmp = get_address(s, 0, b2, d2);
- tmp32_1 = load_reg32(0);
- tmp32_2 = load_reg32(1);
- potential_page_fault(s);
- gen_helper_stsi(cc_op, cpu_env, tmp, tmp32_1, tmp32_2);
- set_cc_static(s);
- tcg_temp_free_i64(tmp);
- tcg_temp_free_i32(tmp32_1);
- tcg_temp_free_i32(tmp32_2);
- break;
- case 0xb1: /* STFL D2(B2) [S] */
- /* Store Facility List (CPU features) at 200 */
- check_privileged(s);
- tmp2 = tcg_const_i64(0xc0000000);
- tmp = tcg_const_i64(200);
- tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s));
- tcg_temp_free_i64(tmp2);
- tcg_temp_free_i64(tmp);
- break;
- case 0xb2: /* LPSWE D2(B2) [S] */
- /* Load PSW Extended */
- check_privileged(s);
- decode_rs(s, insn, &r1, &r3, &b2, &d2);
- tmp = get_address(s, 0, b2, d2);
- tmp2 = tcg_temp_new_i64();
- tmp3 = tcg_temp_new_i64();
- tcg_gen_qemu_ld64(tmp2, tmp, get_mem_index(s));
- tcg_gen_addi_i64(tmp, tmp, 8);
- tcg_gen_qemu_ld64(tmp3, tmp, get_mem_index(s));
- gen_helper_load_psw(cpu_env, tmp2, tmp3);
- /* we need to keep cc_op intact */
- s->is_jmp = DISAS_JUMP;
- tcg_temp_free_i64(tmp);
- tcg_temp_free_i64(tmp2);
- tcg_temp_free_i64(tmp3);
- break;
- case 0x20: /* SERVC R1,R2 [RRE] */
- /* SCLP Service call (PV hypercall) */
- check_privileged(s);
- potential_page_fault(s);
- tmp32_1 = load_reg32(r2);
- tmp = load_reg(r1);
- gen_helper_servc(cc_op, cpu_env, tmp32_1, tmp);
- set_cc_static(s);
- tcg_temp_free_i32(tmp32_1);
- tcg_temp_free_i64(tmp);
- break;
- default:
-#endif
- LOG_DISAS("illegal b2 operation 0x%x\n", op);
- gen_illegal_opcode(s);
-#ifndef CONFIG_USER_ONLY
- break;
- }
-#endif
-}
-
-static void disas_s390_insn(CPUS390XState *env, DisasContext *s)
-{
- unsigned char opc;
- uint64_t insn;
- int op;
-
- opc = cpu_ldub_code(env, s->pc);
- LOG_DISAS("opc 0x%x\n", opc);
-
- switch (opc) {
- case 0xb2:
- insn = ld_code4(env, s->pc);
- op = (insn >> 16) & 0xff;
- disas_b2(env, s, op, insn);
- break;
- default:
- qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%x\n", opc);
- gen_illegal_opcode(s);
- break;
- }
-}
-
/* ====================================================================== */
/* Define the insn format enumeration. */
#define F0(N) FMT_##N,
TCGv_i64 addr1;
} DisasOps;
+/* Instructions can place constraints on their operands, raising specification
+ exceptions if they are violated. To make this easy to automate, each "in1",
+ "in2", "prep", "wout" helper will have a SPEC_<name> define that equals one
+ of the following, or 0. To make this easy to document, we'll put the
+ SPEC_<name> defines next to <name>. */
+
+#define SPEC_r1_even 1
+#define SPEC_r2_even 2
+#define SPEC_r3_even 4
+#define SPEC_r1_f128 8
+#define SPEC_r2_f128 16
+
/* Return values from translate_one, indicating the state of the TB. */
typedef enum {
/* Continue the TB. */
struct DisasInsn {
unsigned opc:16;
- DisasFormat fmt:6;
- DisasFacility fac:6;
+ DisasFormat fmt:8;
+ DisasFacility fac:8;
+ unsigned spec:8;
const char *name;
return NO_EXIT;
}
if (use_goto_tb(s, dest)) {
- gen_update_cc_op(s);
+ update_cc_op(s);
tcg_gen_goto_tb(0);
tcg_gen_movi_i64(psw_addr, dest);
tcg_gen_exit_tb((tcg_target_long)s->tb);
if (use_goto_tb(s, s->next_pc)) {
if (is_imm && use_goto_tb(s, dest)) {
/* Both exits can use goto_tb. */
- gen_update_cc_op(s);
+ update_cc_op(s);
lab = gen_new_label();
if (c->is_64) {
}
/* Branch not taken. */
- gen_update_cc_op(s);
+ update_cc_op(s);
tcg_gen_goto_tb(0);
tcg_gen_movi_i64(psw_addr, s->next_pc);
tcg_gen_exit_tb((tcg_target_long)s->tb + 0);
static ExitStatus op_addc(DisasContext *s, DisasOps *o)
{
- TCGv_i64 cc;
+ DisasCompare cmp;
+ TCGv_i64 carry;
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);
+ /* The carry flag is the msb of CC, therefore the branch mask that would
+ create that comparison is 3. Feeding the generated comparison to
+ setcond produces the carry flag that we desire. */
+ disas_jcc(s, &cmp, 3);
+ carry = tcg_temp_new_i64();
+ if (cmp.is_64) {
+ tcg_gen_setcond_i64(cmp.cond, carry, cmp.u.s64.a, cmp.u.s64.b);
+ } else {
+ TCGv_i32 t = tcg_temp_new_i32();
+ tcg_gen_setcond_i32(cmp.cond, t, cmp.u.s32.a, cmp.u.s32.b);
+ tcg_gen_extu_i32_i64(carry, t);
+ tcg_temp_free_i32(t);
+ }
+ free_compare(&cmp);
- tcg_gen_add_i64(o->out, o->out, cc);
- tcg_temp_free_i64(cc);
+ tcg_gen_add_i64(o->out, o->out, carry);
+ tcg_temp_free_i64(carry);
return NO_EXIT;
}
return help_branch(s, &c, is_imm, imm, o->in2);
}
+static ExitStatus op_bx32(DisasContext *s, DisasOps *o)
+{
+ int r1 = get_field(s->fields, r1);
+ int r3 = get_field(s->fields, r3);
+ bool is_imm = have_field(s->fields, i2);
+ int imm = is_imm ? get_field(s->fields, i2) : 0;
+ DisasCompare c;
+ TCGv_i64 t;
+
+ c.cond = (s->insn->data ? TCG_COND_LE : TCG_COND_GT);
+ c.is_64 = false;
+ c.g1 = false;
+ c.g2 = false;
+
+ t = tcg_temp_new_i64();
+ tcg_gen_add_i64(t, regs[r1], regs[r3]);
+ c.u.s32.a = tcg_temp_new_i32();
+ c.u.s32.b = tcg_temp_new_i32();
+ tcg_gen_trunc_i64_i32(c.u.s32.a, t);
+ tcg_gen_trunc_i64_i32(c.u.s32.b, regs[r3 | 1]);
+ store_reg32_i64(r1, t);
+ tcg_temp_free_i64(t);
+
+ return help_branch(s, &c, is_imm, imm, o->in2);
+}
+
+static ExitStatus op_bx64(DisasContext *s, DisasOps *o)
+{
+ int r1 = get_field(s->fields, r1);
+ int r3 = get_field(s->fields, r3);
+ bool is_imm = have_field(s->fields, i2);
+ int imm = is_imm ? get_field(s->fields, i2) : 0;
+ DisasCompare c;
+
+ c.cond = (s->insn->data ? TCG_COND_LE : TCG_COND_GT);
+ c.is_64 = true;
+
+ if (r1 == (r3 | 1)) {
+ c.u.s64.b = load_reg(r3 | 1);
+ c.g2 = false;
+ } else {
+ c.u.s64.b = regs[r3 | 1];
+ c.g2 = true;
+ }
+
+ tcg_gen_add_i64(regs[r1], regs[r1], regs[r3]);
+ c.u.s64.a = regs[r1];
+ c.g1 = true;
+
+ return help_branch(s, &c, is_imm, imm, o->in2);
+}
+
+static ExitStatus op_cj(DisasContext *s, DisasOps *o)
+{
+ int imm, m3 = get_field(s->fields, m3);
+ bool is_imm;
+ DisasCompare c;
+
+ c.cond = ltgt_cond[m3];
+ if (s->insn->data) {
+ c.cond = tcg_unsigned_cond(c.cond);
+ }
+ c.is_64 = c.g1 = c.g2 = true;
+ c.u.s64.a = o->in1;
+ c.u.s64.b = o->in2;
+
+ is_imm = have_field(s->fields, i4);
+ if (is_imm) {
+ imm = get_field(s->fields, i4);
+ } else {
+ imm = 0;
+ o->out = get_address(s, 0, get_field(s->fields, b4),
+ get_field(s->fields, d4));
+ }
+
+ return help_branch(s, &c, is_imm, imm, o->out);
+}
+
static ExitStatus op_ceb(DisasContext *s, DisasOps *o)
{
gen_helper_ceb(cc_op, cpu_env, o->in1, o->in2);
return NO_EXIT;
}
+static ExitStatus op_clfeb(DisasContext *s, DisasOps *o)
+{
+ TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3));
+ gen_helper_clfeb(o->out, cpu_env, o->in2, m3);
+ tcg_temp_free_i32(m3);
+ gen_set_cc_nz_f32(s, o->in2);
+ return NO_EXIT;
+}
+
+static ExitStatus op_clfdb(DisasContext *s, DisasOps *o)
+{
+ TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3));
+ gen_helper_clfdb(o->out, cpu_env, o->in2, m3);
+ tcg_temp_free_i32(m3);
+ gen_set_cc_nz_f64(s, o->in2);
+ return NO_EXIT;
+}
+
+static ExitStatus op_clfxb(DisasContext *s, DisasOps *o)
+{
+ TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3));
+ gen_helper_clfxb(o->out, cpu_env, o->in1, o->in2, m3);
+ tcg_temp_free_i32(m3);
+ gen_set_cc_nz_f128(s, o->in1, o->in2);
+ return NO_EXIT;
+}
+
+static ExitStatus op_clgeb(DisasContext *s, DisasOps *o)
+{
+ TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3));
+ gen_helper_clgeb(o->out, cpu_env, o->in2, m3);
+ tcg_temp_free_i32(m3);
+ gen_set_cc_nz_f32(s, o->in2);
+ return NO_EXIT;
+}
+
+static ExitStatus op_clgdb(DisasContext *s, DisasOps *o)
+{
+ TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3));
+ gen_helper_clgdb(o->out, cpu_env, o->in2, m3);
+ tcg_temp_free_i32(m3);
+ gen_set_cc_nz_f64(s, o->in2);
+ return NO_EXIT;
+}
+
+static ExitStatus op_clgxb(DisasContext *s, DisasOps *o)
+{
+ TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3));
+ gen_helper_clgxb(o->out, cpu_env, o->in1, o->in2, m3);
+ tcg_temp_free_i32(m3);
+ gen_set_cc_nz_f128(s, o->in1, o->in2);
+ return NO_EXIT;
+}
+
static ExitStatus op_cegb(DisasContext *s, DisasOps *o)
{
TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3));
return NO_EXIT;
}
+static ExitStatus op_celgb(DisasContext *s, DisasOps *o)
+{
+ TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3));
+ gen_helper_celgb(o->out, cpu_env, o->in2, m3);
+ tcg_temp_free_i32(m3);
+ return NO_EXIT;
+}
+
+static ExitStatus op_cdlgb(DisasContext *s, DisasOps *o)
+{
+ TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3));
+ gen_helper_cdlgb(o->out, cpu_env, o->in2, m3);
+ tcg_temp_free_i32(m3);
+ return NO_EXIT;
+}
+
+static ExitStatus op_cxlgb(DisasContext *s, DisasOps *o)
+{
+ TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3));
+ gen_helper_cxlgb(o->out, cpu_env, o->in2, m3);
+ tcg_temp_free_i32(m3);
+ return_low128(o->out2);
+ return NO_EXIT;
+}
+
static ExitStatus op_cksm(DisasContext *s, DisasOps *o)
{
int r2 = get_field(s->fields, r2);
return NO_EXIT;
}
-static ExitStatus op_cs(DisasContext *s, DisasOps *o)
+static ExitStatus op_cps(DisasContext *s, DisasOps *o)
{
- int r3 = get_field(s->fields, r3);
- potential_page_fault(s);
- gen_helper_cs(o->out, cpu_env, o->in1, o->in2, regs[r3]);
- set_cc_static(s);
+ TCGv_i64 t = tcg_temp_new_i64();
+ tcg_gen_andi_i64(t, o->in1, 0x8000000000000000ull);
+ tcg_gen_andi_i64(o->out, o->in2, 0x7fffffffffffffffull);
+ tcg_gen_or_i64(o->out, o->out, t);
+ tcg_temp_free_i64(t);
return NO_EXIT;
}
-static ExitStatus op_csg(DisasContext *s, DisasOps *o)
+static ExitStatus op_cs(DisasContext *s, DisasOps *o)
{
- int r3 = get_field(s->fields, r3);
- potential_page_fault(s);
- gen_helper_csg(o->out, cpu_env, o->in1, o->in2, regs[r3]);
+ /* FIXME: needs an atomic solution for CONFIG_USER_ONLY. */
+ int d2 = get_field(s->fields, d2);
+ int b2 = get_field(s->fields, b2);
+ int is_64 = s->insn->data;
+ TCGv_i64 addr, mem, cc, z;
+
+ /* Note that in1 = R3 (new value) and
+ in2 = (zero-extended) R1 (expected value). */
+
+ /* Load the memory into the (temporary) output. While the PoO only talks
+ about moving the memory to R1 on inequality, if we include equality it
+ means that R1 is equal to the memory in all conditions. */
+ addr = get_address(s, 0, b2, d2);
+ if (is_64) {
+ tcg_gen_qemu_ld64(o->out, addr, get_mem_index(s));
+ } else {
+ tcg_gen_qemu_ld32u(o->out, addr, get_mem_index(s));
+ }
+
+ /* Are the memory and expected values (un)equal? Note that this setcond
+ produces the output CC value, thus the NE sense of the test. */
+ cc = tcg_temp_new_i64();
+ tcg_gen_setcond_i64(TCG_COND_NE, cc, o->in2, o->out);
+
+ /* If the memory and expected values are equal (CC==0), copy R3 to MEM.
+ Recall that we are allowed to unconditionally issue the store (and
+ thus any possible write trap), so (re-)store the original contents
+ of MEM in case of inequality. */
+ z = tcg_const_i64(0);
+ mem = tcg_temp_new_i64();
+ tcg_gen_movcond_i64(TCG_COND_EQ, mem, cc, z, o->in1, o->out);
+ if (is_64) {
+ tcg_gen_qemu_st64(mem, addr, get_mem_index(s));
+ } else {
+ tcg_gen_qemu_st32(mem, addr, get_mem_index(s));
+ }
+ tcg_temp_free_i64(z);
+ tcg_temp_free_i64(mem);
+ tcg_temp_free_i64(addr);
+
+ /* Store CC back to cc_op. Wait until after the store so that any
+ exception gets the old cc_op value. */
+ tcg_gen_trunc_i64_i32(cc_op, cc);
+ tcg_temp_free_i64(cc);
set_cc_static(s);
return NO_EXIT;
}
-static ExitStatus op_cds(DisasContext *s, DisasOps *o)
+static ExitStatus op_cdsg(DisasContext *s, DisasOps *o)
{
+ /* FIXME: needs an atomic solution for CONFIG_USER_ONLY. */
+ int r1 = get_field(s->fields, r1);
int r3 = get_field(s->fields, r3);
- TCGv_i64 in3 = tcg_temp_new_i64();
- tcg_gen_deposit_i64(in3, regs[r3 + 1], regs[r3], 32, 32);
- potential_page_fault(s);
- gen_helper_csg(o->out, cpu_env, o->in1, o->in2, in3);
- tcg_temp_free_i64(in3);
+ int d2 = get_field(s->fields, d2);
+ int b2 = get_field(s->fields, b2);
+ TCGv_i64 addrh, addrl, memh, meml, outh, outl, cc, z;
+
+ /* Note that R1:R1+1 = expected value and R3:R3+1 = new value. */
+
+ addrh = get_address(s, 0, b2, d2);
+ addrl = get_address(s, 0, b2, d2 + 8);
+ outh = tcg_temp_new_i64();
+ outl = tcg_temp_new_i64();
+
+ tcg_gen_qemu_ld64(outh, addrh, get_mem_index(s));
+ tcg_gen_qemu_ld64(outl, addrl, get_mem_index(s));
+
+ /* Fold the double-word compare with arithmetic. */
+ cc = tcg_temp_new_i64();
+ z = tcg_temp_new_i64();
+ tcg_gen_xor_i64(cc, outh, regs[r1]);
+ tcg_gen_xor_i64(z, outl, regs[r1 + 1]);
+ tcg_gen_or_i64(cc, cc, z);
+ tcg_gen_movi_i64(z, 0);
+ tcg_gen_setcond_i64(TCG_COND_NE, cc, cc, z);
+
+ memh = tcg_temp_new_i64();
+ meml = tcg_temp_new_i64();
+ tcg_gen_movcond_i64(TCG_COND_EQ, memh, cc, z, regs[r3], outh);
+ tcg_gen_movcond_i64(TCG_COND_EQ, meml, cc, z, regs[r3 + 1], outl);
+ tcg_temp_free_i64(z);
+
+ tcg_gen_qemu_st64(memh, addrh, get_mem_index(s));
+ tcg_gen_qemu_st64(meml, addrl, get_mem_index(s));
+ tcg_temp_free_i64(memh);
+ tcg_temp_free_i64(meml);
+ tcg_temp_free_i64(addrh);
+ tcg_temp_free_i64(addrl);
+
+ /* Save back state now that we've passed all exceptions. */
+ tcg_gen_mov_i64(regs[r1], outh);
+ tcg_gen_mov_i64(regs[r1 + 1], outl);
+ tcg_gen_trunc_i64_i32(cc_op, cc);
+ tcg_temp_free_i64(outh);
+ tcg_temp_free_i64(outl);
+ tcg_temp_free_i64(cc);
set_cc_static(s);
return NO_EXIT;
}
-static ExitStatus op_cdsg(DisasContext *s, DisasOps *o)
+#ifndef CONFIG_USER_ONLY
+static ExitStatus op_csp(DisasContext *s, DisasOps *o)
{
TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1));
- TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3));
- potential_page_fault(s);
- /* XXX rewrite in tcg */
- gen_helper_cdsg(cc_op, cpu_env, r1, o->in2, r3);
+ check_privileged(s);
+ gen_helper_csp(cc_op, cpu_env, r1, o->in2);
+ tcg_temp_free_i32(r1);
set_cc_static(s);
return NO_EXIT;
}
+#endif
+
+static ExitStatus op_cvd(DisasContext *s, DisasOps *o)
+{
+ TCGv_i64 t1 = tcg_temp_new_i64();
+ TCGv_i32 t2 = tcg_temp_new_i32();
+ tcg_gen_trunc_i64_i32(t2, o->in1);
+ gen_helper_cvd(t1, t2);
+ tcg_temp_free_i32(t2);
+ tcg_gen_qemu_st64(t1, o->in2, get_mem_index(s));
+ tcg_temp_free_i64(t1);
+ return NO_EXIT;
+}
+
+static ExitStatus op_ct(DisasContext *s, DisasOps *o)
+{
+ int m3 = get_field(s->fields, m3);
+ int lab = gen_new_label();
+ TCGv_i32 t;
+ TCGCond c;
+
+ c = tcg_invert_cond(ltgt_cond[m3]);
+ if (s->insn->data) {
+ c = tcg_unsigned_cond(c);
+ }
+ tcg_gen_brcond_i64(c, o->in1, o->in2, lab);
+
+ /* Set DXC to 0xff. */
+ t = tcg_temp_new_i32();
+ tcg_gen_ld_i32(t, cpu_env, offsetof(CPUS390XState, fpc));
+ tcg_gen_ori_i32(t, t, 0xff00);
+ tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, fpc));
+ tcg_temp_free_i32(t);
-static ExitStatus op_cvd(DisasContext *s, DisasOps *o)
-{
- TCGv_i64 t1 = tcg_temp_new_i64();
- TCGv_i32 t2 = tcg_temp_new_i32();
- tcg_gen_trunc_i64_i32(t2, o->in1);
- gen_helper_cvd(t1, t2);
- tcg_temp_free_i32(t2);
- tcg_gen_qemu_st64(t1, o->in2, get_mem_index(s));
- tcg_temp_free_i64(t1);
+ /* Trap. */
+ gen_program_exception(s, PGM_DATA);
+
+ gen_set_label(lab);
return NO_EXIT;
}
TCGv_i64 tmp;
update_psw_addr(s);
- gen_op_calc_cc(s);
+ update_cc_op(s);
tmp = tcg_const_i64(s->next_pc);
gen_helper_ex(cc_op, cpu_env, cc_op, o->in1, o->in2, tmp);
return NO_EXIT;
}
+#ifndef CONFIG_USER_ONLY
+static ExitStatus op_ipte(DisasContext *s, DisasOps *o)
+{
+ check_privileged(s);
+ gen_helper_ipte(cpu_env, o->in1, o->in2);
+ return NO_EXIT;
+}
+
+static ExitStatus op_iske(DisasContext *s, DisasOps *o)
+{
+ check_privileged(s);
+ gen_helper_iske(o->out, cpu_env, o->in2);
+ return NO_EXIT;
+}
+#endif
+
static ExitStatus op_ldeb(DisasContext *s, DisasOps *o)
{
gen_helper_ldeb(o->out, cpu_env, o->in2);
return NO_EXIT;
}
+static ExitStatus op_loc(DisasContext *s, DisasOps *o)
+{
+ DisasCompare c;
+
+ disas_jcc(s, &c, get_field(s->fields, m3));
+
+ if (c.is_64) {
+ tcg_gen_movcond_i64(c.cond, o->out, c.u.s64.a, c.u.s64.b,
+ o->in2, o->in1);
+ free_compare(&c);
+ } else {
+ TCGv_i32 t32 = tcg_temp_new_i32();
+ TCGv_i64 t, z;
+
+ tcg_gen_setcond_i32(c.cond, t32, c.u.s32.a, c.u.s32.b);
+ free_compare(&c);
+
+ t = tcg_temp_new_i64();
+ tcg_gen_extu_i32_i64(t, t32);
+ tcg_temp_free_i32(t32);
+
+ z = tcg_const_i64(0);
+ tcg_gen_movcond_i64(TCG_COND_NE, o->out, t, z, o->in2, o->in1);
+ tcg_temp_free_i64(t);
+ tcg_temp_free_i64(z);
+ }
+
+ return NO_EXIT;
+}
+
#ifndef CONFIG_USER_ONLY
static ExitStatus op_lctl(DisasContext *s, DisasOps *o)
{
tcg_temp_free_i64(t2);
return EXIT_NORETURN;
}
+
+static ExitStatus op_lpswe(DisasContext *s, DisasOps *o)
+{
+ TCGv_i64 t1, t2;
+
+ check_privileged(s);
+
+ t1 = tcg_temp_new_i64();
+ t2 = tcg_temp_new_i64();
+ tcg_gen_qemu_ld64(t1, o->in2, get_mem_index(s));
+ tcg_gen_addi_i64(o->in2, o->in2, 8);
+ tcg_gen_qemu_ld64(t2, o->in2, get_mem_index(s));
+ gen_helper_load_psw(cpu_env, t1, t2);
+ tcg_temp_free_i64(t1);
+ tcg_temp_free_i64(t2);
+ return EXIT_NORETURN;
+}
#endif
static ExitStatus op_lam(DisasContext *s, DisasOps *o)
static ExitStatus op_mul128(DisasContext *s, DisasOps *o)
{
- gen_helper_mul128(o->out, cpu_env, o->in1, o->in2);
- return_low128(o->out2);
+ tcg_gen_mulu2_i64(o->out2, o->out, o->in1, o->in2);
return NO_EXIT;
}
return NO_EXIT;
}
+static ExitStatus op_popcnt(DisasContext *s, DisasOps *o)
+{
+ gen_helper_popcnt(o->out, o->in2);
+ return NO_EXIT;
+}
+
#ifndef CONFIG_USER_ONLY
static ExitStatus op_ptlb(DisasContext *s, DisasOps *o)
{
}
#endif
+static ExitStatus op_risbg(DisasContext *s, DisasOps *o)
+{
+ int i3 = get_field(s->fields, i3);
+ int i4 = get_field(s->fields, i4);
+ int i5 = get_field(s->fields, i5);
+ int do_zero = i4 & 0x80;
+ uint64_t mask, imask, pmask;
+ int pos, len, rot;
+
+ /* Adjust the arguments for the specific insn. */
+ switch (s->fields->op2) {
+ case 0x55: /* risbg */
+ i3 &= 63;
+ i4 &= 63;
+ pmask = ~0;
+ break;
+ case 0x5d: /* risbhg */
+ i3 &= 31;
+ i4 &= 31;
+ pmask = 0xffffffff00000000ull;
+ break;
+ case 0x51: /* risblg */
+ i3 &= 31;
+ i4 &= 31;
+ pmask = 0x00000000ffffffffull;
+ break;
+ default:
+ abort();
+ }
+
+ /* MASK is the set of bits to be inserted from R2.
+ Take care for I3/I4 wraparound. */
+ mask = pmask >> i3;
+ if (i3 <= i4) {
+ mask ^= pmask >> i4 >> 1;
+ } else {
+ mask |= ~(pmask >> i4 >> 1);
+ }
+ mask &= pmask;
+
+ /* IMASK is the set of bits to be kept from R1. In the case of the high/low
+ insns, we need to keep the other half of the register. */
+ imask = ~mask | ~pmask;
+ if (do_zero) {
+ if (s->fields->op2 == 0x55) {
+ imask = 0;
+ } else {
+ imask = ~pmask;
+ }
+ }
+
+ /* In some cases we can implement this with deposit, which can be more
+ efficient on some hosts. */
+ if (~mask == imask && i3 <= i4) {
+ if (s->fields->op2 == 0x5d) {
+ i3 += 32, i4 += 32;
+ }
+ /* Note that we rotate the bits to be inserted to the lsb, not to
+ the position as described in the PoO. */
+ len = i4 - i3 + 1;
+ pos = 63 - i4;
+ rot = (i5 - pos) & 63;
+ } else {
+ pos = len = -1;
+ rot = i5 & 63;
+ }
+
+ /* Rotate the input as necessary. */
+ tcg_gen_rotli_i64(o->in2, o->in2, rot);
+
+ /* Insert the selected bits into the output. */
+ if (pos >= 0) {
+ tcg_gen_deposit_i64(o->out, o->out, o->in2, pos, len);
+ } else if (imask == 0) {
+ tcg_gen_andi_i64(o->out, o->in2, mask);
+ } else {
+ tcg_gen_andi_i64(o->in2, o->in2, mask);
+ tcg_gen_andi_i64(o->out, o->out, imask);
+ tcg_gen_or_i64(o->out, o->out, o->in2);
+ }
+ return NO_EXIT;
+}
+
+static ExitStatus op_rosbg(DisasContext *s, DisasOps *o)
+{
+ int i3 = get_field(s->fields, i3);
+ int i4 = get_field(s->fields, i4);
+ int i5 = get_field(s->fields, i5);
+ uint64_t mask;
+
+ /* If this is a test-only form, arrange to discard the result. */
+ if (i3 & 0x80) {
+ o->out = tcg_temp_new_i64();
+ o->g_out = false;
+ }
+
+ i3 &= 63;
+ i4 &= 63;
+ i5 &= 63;
+
+ /* MASK is the set of bits to be operated on from R2.
+ Take care for I3/I4 wraparound. */
+ mask = ~0ull >> i3;
+ if (i3 <= i4) {
+ mask ^= ~0ull >> i4 >> 1;
+ } else {
+ mask |= ~(~0ull >> i4 >> 1);
+ }
+
+ /* Rotate the input as necessary. */
+ tcg_gen_rotli_i64(o->in2, o->in2, i5);
+
+ /* Operate. */
+ switch (s->fields->op2) {
+ case 0x55: /* AND */
+ tcg_gen_ori_i64(o->in2, o->in2, ~mask);
+ tcg_gen_and_i64(o->out, o->out, o->in2);
+ break;
+ case 0x56: /* OR */
+ tcg_gen_andi_i64(o->in2, o->in2, mask);
+ tcg_gen_or_i64(o->out, o->out, o->in2);
+ break;
+ case 0x57: /* XOR */
+ tcg_gen_andi_i64(o->in2, o->in2, mask);
+ tcg_gen_xor_i64(o->out, o->out, o->in2);
+ break;
+ default:
+ abort();
+ }
+
+ /* Set the CC. */
+ tcg_gen_andi_i64(cc_dst, o->out, mask);
+ set_cc_nz_u64(s, cc_dst);
+ return NO_EXIT;
+}
+
static ExitStatus op_rev16(DisasContext *s, DisasOps *o)
{
tcg_gen_bswap16_i64(o->out, o->in2);
return NO_EXIT;
}
+#ifndef CONFIG_USER_ONLY
+static ExitStatus op_rrbe(DisasContext *s, DisasOps *o)
+{
+ check_privileged(s);
+ gen_helper_rrbe(cc_op, cpu_env, o->in2);
+ set_cc_static(s);
+ return NO_EXIT;
+}
+
+static ExitStatus op_sacf(DisasContext *s, DisasOps *o)
+{
+ check_privileged(s);
+ gen_helper_sacf(cpu_env, o->in2);
+ /* Addressing mode has changed, so end the block. */
+ return EXIT_PC_STALE;
+}
+#endif
+
static ExitStatus op_sar(DisasContext *s, DisasOps *o)
{
int r1 = get_field(s->fields, r1);
}
#ifndef CONFIG_USER_ONLY
+static ExitStatus op_servc(DisasContext *s, DisasOps *o)
+{
+ check_privileged(s);
+ potential_page_fault(s);
+ gen_helper_servc(cc_op, cpu_env, o->in2, o->in1);
+ set_cc_static(s);
+ return NO_EXIT;
+}
+
static ExitStatus op_sigp(DisasContext *s, DisasOps *o)
{
TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1));
}
#endif
+static ExitStatus op_soc(DisasContext *s, DisasOps *o)
+{
+ DisasCompare c;
+ TCGv_i64 a;
+ int lab, r1;
+
+ disas_jcc(s, &c, get_field(s->fields, m3));
+
+ lab = gen_new_label();
+ if (c.is_64) {
+ tcg_gen_brcond_i64(c.cond, c.u.s64.a, c.u.s64.b, lab);
+ } else {
+ tcg_gen_brcond_i32(c.cond, c.u.s32.a, c.u.s32.b, lab);
+ }
+ free_compare(&c);
+
+ r1 = get_field(s->fields, r1);
+ a = get_address(s, 0, get_field(s->fields, b2), get_field(s->fields, d2));
+ if (s->insn->data) {
+ tcg_gen_qemu_st64(regs[r1], a, get_mem_index(s));
+ } else {
+ tcg_gen_qemu_st32(regs[r1], a, get_mem_index(s));
+ }
+ tcg_temp_free_i64(a);
+
+ gen_set_label(lab);
+ return NO_EXIT;
+}
+
static ExitStatus op_sla(DisasContext *s, DisasOps *o)
{
uint64_t sign = 1ull << s->insn->data;
return NO_EXIT;
}
+static ExitStatus op_sfas(DisasContext *s, DisasOps *o)
+{
+ gen_helper_sfas(cpu_env, o->in2);
+ return NO_EXIT;
+}
+
+static ExitStatus op_srnm(DisasContext *s, DisasOps *o)
+{
+ int b2 = get_field(s->fields, b2);
+ int d2 = get_field(s->fields, d2);
+ TCGv_i64 t1 = tcg_temp_new_i64();
+ TCGv_i64 t2 = tcg_temp_new_i64();
+ int mask, pos, len;
+
+ switch (s->fields->op2) {
+ case 0x99: /* SRNM */
+ pos = 0, len = 2;
+ break;
+ case 0xb8: /* SRNMB */
+ pos = 0, len = 3;
+ break;
+ case 0xb9: /* SRNMT */
+ pos = 4, len = 3;
+ default:
+ tcg_abort();
+ }
+ mask = (1 << len) - 1;
+
+ /* Insert the value into the appropriate field of the FPC. */
+ if (b2 == 0) {
+ tcg_gen_movi_i64(t1, d2 & mask);
+ } else {
+ tcg_gen_addi_i64(t1, regs[b2], d2);
+ tcg_gen_andi_i64(t1, t1, mask);
+ }
+ tcg_gen_ld32u_i64(t2, cpu_env, offsetof(CPUS390XState, fpc));
+ tcg_gen_deposit_i64(t2, t2, t1, pos, len);
+ tcg_temp_free_i64(t1);
+
+ /* Then install the new FPC to set the rounding mode in fpu_status. */
+ gen_helper_sfpc(cpu_env, t2);
+ tcg_temp_free_i64(t2);
+ return NO_EXIT;
+}
+
#ifndef CONFIG_USER_ONLY
static ExitStatus op_spka(DisasContext *s, DisasOps *o)
{
return NO_EXIT;
}
+static ExitStatus op_sske(DisasContext *s, DisasOps *o)
+{
+ check_privileged(s);
+ gen_helper_sske(cpu_env, o->in1, o->in2);
+ return NO_EXIT;
+}
+
static ExitStatus op_ssm(DisasContext *s, DisasOps *o)
{
check_privileged(s);
return NO_EXIT;
}
+static ExitStatus op_stcke(DisasContext *s, DisasOps *o)
+{
+ TCGv_i64 c1 = tcg_temp_new_i64();
+ TCGv_i64 c2 = tcg_temp_new_i64();
+ gen_helper_stck(c1, cpu_env);
+ /* Shift the 64-bit value into its place as a zero-extended
+ 104-bit value. Note that "bit positions 64-103 are always
+ non-zero so that they compare differently to STCK"; we set
+ the least significant bit to 1. */
+ tcg_gen_shli_i64(c2, c1, 56);
+ tcg_gen_shri_i64(c1, c1, 8);
+ tcg_gen_ori_i64(c2, c2, 0x10000);
+ tcg_gen_qemu_st64(c1, o->in2, get_mem_index(s));
+ tcg_gen_addi_i64(o->in2, o->in2, 8);
+ tcg_gen_qemu_st64(c2, o->in2, get_mem_index(s));
+ tcg_temp_free_i64(c1);
+ tcg_temp_free_i64(c2);
+ /* ??? We don't implement clock states. */
+ gen_op_movi_cc(s, 0);
+ return NO_EXIT;
+}
+
static ExitStatus op_sckc(DisasContext *s, DisasOps *o)
{
check_privileged(s);
return NO_EXIT;
}
+static ExitStatus op_stfl(DisasContext *s, DisasOps *o)
+{
+ TCGv_i64 f, a;
+ /* We really ought to have more complete indication of facilities
+ that we implement. Address this when STFLE is implemented. */
+ check_privileged(s);
+ f = tcg_const_i64(0xc0000000);
+ a = tcg_const_i64(200);
+ tcg_gen_qemu_st32(f, a, get_mem_index(s));
+ tcg_temp_free_i64(f);
+ tcg_temp_free_i64(a);
+ return NO_EXIT;
+}
+
static ExitStatus op_stpt(DisasContext *s, DisasOps *o)
{
check_privileged(s);
return NO_EXIT;
}
+static ExitStatus op_stsi(DisasContext *s, DisasOps *o)
+{
+ check_privileged(s);
+ potential_page_fault(s);
+ gen_helper_stsi(cc_op, cpu_env, o->in2, regs[0], regs[1]);
+ set_cc_static(s);
+ return NO_EXIT;
+}
+
static ExitStatus op_spx(DisasContext *s, DisasOps *o)
{
check_privileged(s);
return NO_EXIT;
}
+static ExitStatus op_subchannel(DisasContext *s, DisasOps *o)
+{
+ check_privileged(s);
+ /* Not operational. */
+ gen_op_movi_cc(s, 3);
+ return NO_EXIT;
+}
+
static ExitStatus op_stpx(DisasContext *s, DisasOps *o)
{
check_privileged(s);
}
return NO_EXIT;
}
+
+static ExitStatus op_stura(DisasContext *s, DisasOps *o)
+{
+ check_privileged(s);
+ potential_page_fault(s);
+ gen_helper_stura(cpu_env, o->in2, o->in1);
+ return NO_EXIT;
+}
#endif
static ExitStatus op_st8(DisasContext *s, DisasOps *o)
static ExitStatus op_subb(DisasContext *s, DisasOps *o)
{
- TCGv_i64 cc;
+ DisasCompare cmp;
+ TCGv_i64 borrow;
- assert(!o->g_in2);
- tcg_gen_not_i64(o->in2, o->in2);
- tcg_gen_add_i64(o->out, o->in1, o->in2);
+ tcg_gen_sub_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);
+ /* The !borrow flag is the msb of CC. Since we want the inverse of
+ that, we ask for a comparison of CC=0 | CC=1 -> mask of 8 | 4. */
+ disas_jcc(s, &cmp, 8 | 4);
+ borrow = tcg_temp_new_i64();
+ if (cmp.is_64) {
+ tcg_gen_setcond_i64(cmp.cond, borrow, cmp.u.s64.a, cmp.u.s64.b);
+ } else {
+ TCGv_i32 t = tcg_temp_new_i32();
+ tcg_gen_setcond_i32(cmp.cond, t, cmp.u.s32.a, cmp.u.s32.b);
+ tcg_gen_extu_i32_i64(borrow, t);
+ tcg_temp_free_i32(t);
+ }
+ free_compare(&cmp);
+
+ tcg_gen_sub_i64(o->out, o->out, borrow);
+ tcg_temp_free_i64(borrow);
return NO_EXIT;
}
TCGv_i32 t;
update_psw_addr(s);
- gen_op_calc_cc(s);
+ update_cc_op(s);
t = tcg_const_i32(get_field(s->fields, i1) & 0xff);
tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, int_svc_code));
static ExitStatus op_xc(DisasContext *s, DisasOps *o)
{
- TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1));
+ int d1 = get_field(s->fields, d1);
+ int d2 = get_field(s->fields, d2);
+ int b1 = get_field(s->fields, b1);
+ int b2 = get_field(s->fields, b2);
+ int l = get_field(s->fields, l1);
+ TCGv_i32 t32;
+
+ o->addr1 = get_address(s, 0, b1, d1);
+
+ /* If the addresses are identical, this is a store/memset of zero. */
+ if (b1 == b2 && d1 == d2 && (l + 1) <= 32) {
+ o->in2 = tcg_const_i64(0);
+
+ l++;
+ while (l >= 8) {
+ tcg_gen_qemu_st64(o->in2, o->addr1, get_mem_index(s));
+ l -= 8;
+ if (l > 0) {
+ tcg_gen_addi_i64(o->addr1, o->addr1, 8);
+ }
+ }
+ if (l >= 4) {
+ tcg_gen_qemu_st32(o->in2, o->addr1, get_mem_index(s));
+ l -= 4;
+ if (l > 0) {
+ tcg_gen_addi_i64(o->addr1, o->addr1, 4);
+ }
+ }
+ if (l >= 2) {
+ tcg_gen_qemu_st16(o->in2, o->addr1, get_mem_index(s));
+ l -= 2;
+ if (l > 0) {
+ tcg_gen_addi_i64(o->addr1, o->addr1, 2);
+ }
+ }
+ if (l) {
+ tcg_gen_qemu_st8(o->in2, o->addr1, get_mem_index(s));
+ }
+ gen_op_movi_cc(s, 0);
+ return NO_EXIT;
+ }
+
+ /* But in general we'll defer to a helper. */
+ o->in2 = get_address(s, 0, b2, d2);
+ t32 = tcg_const_i32(l);
potential_page_fault(s);
- gen_helper_xc(cc_op, cpu_env, l, o->addr1, o->in2);
- tcg_temp_free_i32(l);
+ gen_helper_xc(cc_op, cpu_env, t32, o->addr1, o->in2);
+ tcg_temp_free_i32(t32);
set_cc_static(s);
return NO_EXIT;
}
{
o->out = tcg_temp_new_i64();
}
+#define SPEC_prep_new 0
static void prep_new_P(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->out = tcg_temp_new_i64();
o->out2 = tcg_temp_new_i64();
}
+#define SPEC_prep_new_P 0
static void prep_r1(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->out = regs[get_field(f, r1)];
o->g_out = true;
}
+#define SPEC_prep_r1 0
static void prep_r1_P(DisasContext *s, DisasFields *f, DisasOps *o)
{
- /* ??? Specification exception: r1 must be even. */
int r1 = get_field(f, r1);
o->out = regs[r1];
- o->out2 = regs[(r1 + 1) & 15];
+ o->out2 = regs[r1 + 1];
o->g_out = o->g_out2 = true;
}
+#define SPEC_prep_r1_P SPEC_r1_even
static void prep_f1(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->out = fregs[get_field(f, r1)];
o->g_out = true;
}
+#define SPEC_prep_f1 0
static void prep_x1(DisasContext *s, DisasFields *f, DisasOps *o)
{
- /* ??? Specification exception: r1 must be < 14. */
int r1 = get_field(f, r1);
o->out = fregs[r1];
- o->out2 = fregs[(r1 + 2) & 15];
+ o->out2 = fregs[r1 + 2];
o->g_out = o->g_out2 = true;
}
+#define SPEC_prep_x1 SPEC_r1_f128
/* ====================================================================== */
/* The "Write OUTput" generators. These generally perform some non-trivial
{
store_reg(get_field(f, r1), o->out);
}
+#define SPEC_wout_r1 0
static void wout_r1_8(DisasContext *s, DisasFields *f, DisasOps *o)
{
int r1 = get_field(f, r1);
tcg_gen_deposit_i64(regs[r1], regs[r1], o->out, 0, 8);
}
+#define SPEC_wout_r1_8 0
static void wout_r1_16(DisasContext *s, DisasFields *f, DisasOps *o)
{
int r1 = get_field(f, r1);
tcg_gen_deposit_i64(regs[r1], regs[r1], o->out, 0, 16);
}
+#define SPEC_wout_r1_16 0
static void wout_r1_32(DisasContext *s, DisasFields *f, DisasOps *o)
{
store_reg32_i64(get_field(f, r1), o->out);
}
+#define SPEC_wout_r1_32 0
static void wout_r1_P32(DisasContext *s, DisasFields *f, DisasOps *o)
{
- /* ??? Specification exception: r1 must be even. */
int r1 = get_field(f, r1);
store_reg32_i64(r1, o->out);
- store_reg32_i64((r1 + 1) & 15, o->out2);
+ store_reg32_i64(r1 + 1, o->out2);
}
+#define SPEC_wout_r1_P32 SPEC_r1_even
static void wout_r1_D32(DisasContext *s, DisasFields *f, DisasOps *o)
{
- /* ??? Specification exception: r1 must be even. */
int r1 = get_field(f, r1);
- store_reg32_i64((r1 + 1) & 15, o->out);
+ store_reg32_i64(r1 + 1, o->out);
tcg_gen_shri_i64(o->out, o->out, 32);
store_reg32_i64(r1, o->out);
}
+#define SPEC_wout_r1_D32 SPEC_r1_even
static void wout_e1(DisasContext *s, DisasFields *f, DisasOps *o)
{
store_freg32_i64(get_field(f, r1), o->out);
}
+#define SPEC_wout_e1 0
static void wout_f1(DisasContext *s, DisasFields *f, DisasOps *o)
{
store_freg(get_field(f, r1), o->out);
}
+#define SPEC_wout_f1 0
static void wout_x1(DisasContext *s, DisasFields *f, DisasOps *o)
{
- /* ??? Specification exception: r1 must be < 14. */
int f1 = get_field(s->fields, r1);
store_freg(f1, o->out);
- store_freg((f1 + 2) & 15, o->out2);
+ store_freg(f1 + 2, o->out2);
}
+#define SPEC_wout_x1 SPEC_r1_f128
static void wout_cond_r1r2_32(DisasContext *s, DisasFields *f, DisasOps *o)
{
store_reg32_i64(get_field(f, r1), o->out);
}
}
+#define SPEC_wout_cond_r1r2_32 0
static void wout_cond_e1e2(DisasContext *s, DisasFields *f, DisasOps *o)
{
store_freg32_i64(get_field(f, r1), o->out);
}
}
+#define SPEC_wout_cond_e1e2 0
static void wout_m1_8(DisasContext *s, DisasFields *f, DisasOps *o)
{
tcg_gen_qemu_st8(o->out, o->addr1, get_mem_index(s));
}
+#define SPEC_wout_m1_8 0
static void wout_m1_16(DisasContext *s, DisasFields *f, DisasOps *o)
{
tcg_gen_qemu_st16(o->out, o->addr1, get_mem_index(s));
}
+#define SPEC_wout_m1_16 0
static void wout_m1_32(DisasContext *s, DisasFields *f, DisasOps *o)
{
tcg_gen_qemu_st32(o->out, o->addr1, get_mem_index(s));
}
+#define SPEC_wout_m1_32 0
static void wout_m1_64(DisasContext *s, DisasFields *f, DisasOps *o)
{
tcg_gen_qemu_st64(o->out, o->addr1, get_mem_index(s));
}
+#define SPEC_wout_m1_64 0
static void wout_m2_32(DisasContext *s, DisasFields *f, DisasOps *o)
{
tcg_gen_qemu_st32(o->out, o->in2, get_mem_index(s));
}
+#define SPEC_wout_m2_32 0
/* ====================================================================== */
/* The "INput 1" generators. These load the first operand to an insn. */
{
o->in1 = load_reg(get_field(f, r1));
}
+#define SPEC_in1_r1 0
static void in1_r1_o(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in1 = regs[get_field(f, r1)];
o->g_in1 = true;
}
+#define SPEC_in1_r1_o 0
static void in1_r1_32s(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in1 = tcg_temp_new_i64();
tcg_gen_ext32s_i64(o->in1, regs[get_field(f, r1)]);
}
+#define SPEC_in1_r1_32s 0
static void in1_r1_32u(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in1 = tcg_temp_new_i64();
tcg_gen_ext32u_i64(o->in1, regs[get_field(f, r1)]);
}
+#define SPEC_in1_r1_32u 0
static void in1_r1_sr32(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in1 = tcg_temp_new_i64();
tcg_gen_shri_i64(o->in1, regs[get_field(f, r1)], 32);
}
+#define SPEC_in1_r1_sr32 0
static void in1_r1p1(DisasContext *s, DisasFields *f, DisasOps *o)
{
- /* ??? Specification exception: r1 must be even. */
- int r1 = get_field(f, r1);
- o->in1 = load_reg((r1 + 1) & 15);
+ o->in1 = load_reg(get_field(f, r1) + 1);
}
+#define SPEC_in1_r1p1 SPEC_r1_even
static void in1_r1p1_32s(DisasContext *s, DisasFields *f, DisasOps *o)
{
- /* ??? Specification exception: r1 must be even. */
- int r1 = get_field(f, r1);
o->in1 = tcg_temp_new_i64();
- tcg_gen_ext32s_i64(o->in1, regs[(r1 + 1) & 15]);
+ tcg_gen_ext32s_i64(o->in1, regs[get_field(f, r1) + 1]);
}
+#define SPEC_in1_r1p1_32s SPEC_r1_even
static void in1_r1p1_32u(DisasContext *s, DisasFields *f, DisasOps *o)
{
- /* ??? Specification exception: r1 must be even. */
- int r1 = get_field(f, r1);
o->in1 = tcg_temp_new_i64();
- tcg_gen_ext32u_i64(o->in1, regs[(r1 + 1) & 15]);
+ tcg_gen_ext32u_i64(o->in1, regs[get_field(f, r1) + 1]);
}
+#define SPEC_in1_r1p1_32u SPEC_r1_even
static void in1_r1_D32(DisasContext *s, DisasFields *f, DisasOps *o)
{
- /* ??? Specification exception: r1 must be even. */
int r1 = get_field(f, r1);
o->in1 = tcg_temp_new_i64();
tcg_gen_concat32_i64(o->in1, regs[r1 + 1], regs[r1]);
}
+#define SPEC_in1_r1_D32 SPEC_r1_even
static void in1_r2(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in1 = load_reg(get_field(f, r2));
}
+#define SPEC_in1_r2 0
static void in1_r3(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in1 = load_reg(get_field(f, r3));
}
+#define SPEC_in1_r3 0
static void in1_r3_o(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in1 = regs[get_field(f, r3)];
o->g_in1 = true;
}
+#define SPEC_in1_r3_o 0
static void in1_r3_32s(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in1 = tcg_temp_new_i64();
tcg_gen_ext32s_i64(o->in1, regs[get_field(f, r3)]);
}
+#define SPEC_in1_r3_32s 0
static void in1_r3_32u(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in1 = tcg_temp_new_i64();
tcg_gen_ext32u_i64(o->in1, regs[get_field(f, r3)]);
}
+#define SPEC_in1_r3_32u 0
+
+static void in1_r3_D32(DisasContext *s, DisasFields *f, DisasOps *o)
+{
+ int r3 = get_field(f, r3);
+ o->in1 = tcg_temp_new_i64();
+ tcg_gen_concat32_i64(o->in1, regs[r3 + 1], regs[r3]);
+}
+#define SPEC_in1_r3_D32 SPEC_r3_even
static void in1_e1(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in1 = load_freg32_i64(get_field(f, r1));
}
+#define SPEC_in1_e1 0
static void in1_f1_o(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in1 = fregs[get_field(f, r1)];
o->g_in1 = true;
}
+#define SPEC_in1_f1_o 0
static void in1_x1_o(DisasContext *s, DisasFields *f, DisasOps *o)
{
- /* ??? Specification exception: r1 must be < 14. */
int r1 = get_field(f, r1);
o->out = fregs[r1];
- o->out2 = fregs[(r1 + 2) & 15];
+ o->out2 = fregs[r1 + 2];
o->g_out = o->g_out2 = true;
}
+#define SPEC_in1_x1_o SPEC_r1_f128
+
+static void in1_f3_o(DisasContext *s, DisasFields *f, DisasOps *o)
+{
+ o->in1 = fregs[get_field(f, r3)];
+ o->g_in1 = true;
+}
+#define SPEC_in1_f3_o 0
static void in1_la1(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->addr1 = get_address(s, 0, get_field(f, b1), get_field(f, d1));
}
+#define SPEC_in1_la1 0
static void in1_la2(DisasContext *s, DisasFields *f, DisasOps *o)
{
int x2 = have_field(f, x2) ? get_field(f, x2) : 0;
o->addr1 = get_address(s, x2, get_field(f, b2), get_field(f, d2));
}
+#define SPEC_in1_la2 0
static void in1_m1_8u(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in1 = tcg_temp_new_i64();
tcg_gen_qemu_ld8u(o->in1, o->addr1, get_mem_index(s));
}
+#define SPEC_in1_m1_8u 0
static void in1_m1_16s(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in1 = tcg_temp_new_i64();
tcg_gen_qemu_ld16s(o->in1, o->addr1, get_mem_index(s));
}
+#define SPEC_in1_m1_16s 0
static void in1_m1_16u(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in1 = tcg_temp_new_i64();
tcg_gen_qemu_ld16u(o->in1, o->addr1, get_mem_index(s));
}
+#define SPEC_in1_m1_16u 0
static void in1_m1_32s(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in1 = tcg_temp_new_i64();
tcg_gen_qemu_ld32s(o->in1, o->addr1, get_mem_index(s));
}
+#define SPEC_in1_m1_32s 0
static void in1_m1_32u(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in1 = tcg_temp_new_i64();
tcg_gen_qemu_ld32u(o->in1, o->addr1, get_mem_index(s));
}
+#define SPEC_in1_m1_32u 0
static void in1_m1_64(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in1 = tcg_temp_new_i64();
tcg_gen_qemu_ld64(o->in1, o->addr1, get_mem_index(s));
}
+#define SPEC_in1_m1_64 0
/* ====================================================================== */
/* The "INput 2" generators. These load the second operand to an insn. */
o->in2 = regs[get_field(f, r1)];
o->g_in2 = true;
}
+#define SPEC_in2_r1_o 0
static void in2_r1_16u(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = tcg_temp_new_i64();
tcg_gen_ext16u_i64(o->in2, regs[get_field(f, r1)]);
}
+#define SPEC_in2_r1_16u 0
static void in2_r1_32u(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = tcg_temp_new_i64();
tcg_gen_ext32u_i64(o->in2, regs[get_field(f, r1)]);
}
+#define SPEC_in2_r1_32u 0
+
+static void in2_r1_D32(DisasContext *s, DisasFields *f, DisasOps *o)
+{
+ int r1 = get_field(f, r1);
+ o->in2 = tcg_temp_new_i64();
+ tcg_gen_concat32_i64(o->in2, regs[r1 + 1], regs[r1]);
+}
+#define SPEC_in2_r1_D32 SPEC_r1_even
static void in2_r2(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = load_reg(get_field(f, r2));
}
+#define SPEC_in2_r2 0
static void in2_r2_o(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = regs[get_field(f, r2)];
o->g_in2 = true;
}
+#define SPEC_in2_r2_o 0
static void in2_r2_nz(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = load_reg(r2);
}
}
+#define SPEC_in2_r2_nz 0
static void in2_r2_8s(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = tcg_temp_new_i64();
tcg_gen_ext8s_i64(o->in2, regs[get_field(f, r2)]);
}
+#define SPEC_in2_r2_8s 0
static void in2_r2_8u(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = tcg_temp_new_i64();
tcg_gen_ext8u_i64(o->in2, regs[get_field(f, r2)]);
}
+#define SPEC_in2_r2_8u 0
static void in2_r2_16s(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = tcg_temp_new_i64();
tcg_gen_ext16s_i64(o->in2, regs[get_field(f, r2)]);
}
+#define SPEC_in2_r2_16s 0
static void in2_r2_16u(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = tcg_temp_new_i64();
tcg_gen_ext16u_i64(o->in2, regs[get_field(f, r2)]);
}
+#define SPEC_in2_r2_16u 0
static void in2_r3(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = load_reg(get_field(f, r3));
}
+#define SPEC_in2_r3 0
static void in2_r2_32s(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = tcg_temp_new_i64();
tcg_gen_ext32s_i64(o->in2, regs[get_field(f, r2)]);
}
+#define SPEC_in2_r2_32s 0
static void in2_r2_32u(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = tcg_temp_new_i64();
tcg_gen_ext32u_i64(o->in2, regs[get_field(f, r2)]);
}
+#define SPEC_in2_r2_32u 0
static void in2_e2(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = load_freg32_i64(get_field(f, r2));
}
+#define SPEC_in2_e2 0
static void in2_f2_o(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = fregs[get_field(f, r2)];
o->g_in2 = true;
}
+#define SPEC_in2_f2_o 0
static void in2_x2_o(DisasContext *s, DisasFields *f, DisasOps *o)
{
- /* ??? Specification exception: r1 must be < 14. */
int r2 = get_field(f, r2);
o->in1 = fregs[r2];
- o->in2 = fregs[(r2 + 2) & 15];
+ o->in2 = fregs[r2 + 2];
o->g_in1 = o->g_in2 = true;
}
+#define SPEC_in2_x2_o SPEC_r2_f128
static void in2_ra2(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = get_address(s, 0, get_field(f, r2), 0);
}
+#define SPEC_in2_ra2 0
static void in2_a2(DisasContext *s, DisasFields *f, DisasOps *o)
{
int x2 = have_field(f, x2) ? get_field(f, x2) : 0;
o->in2 = get_address(s, x2, get_field(f, b2), get_field(f, d2));
}
+#define SPEC_in2_a2 0
static void in2_ri2(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = tcg_const_i64(s->pc + (int64_t)get_field(f, i2) * 2);
}
+#define SPEC_in2_ri2 0
static void in2_sh32(DisasContext *s, DisasFields *f, DisasOps *o)
{
help_l2_shift(s, f, o, 31);
}
+#define SPEC_in2_sh32 0
static void in2_sh64(DisasContext *s, DisasFields *f, DisasOps *o)
{
help_l2_shift(s, f, o, 63);
}
+#define SPEC_in2_sh64 0
static void in2_m2_8u(DisasContext *s, DisasFields *f, DisasOps *o)
{
in2_a2(s, f, o);
tcg_gen_qemu_ld8u(o->in2, o->in2, get_mem_index(s));
}
+#define SPEC_in2_m2_8u 0
static void in2_m2_16s(DisasContext *s, DisasFields *f, DisasOps *o)
{
in2_a2(s, f, o);
tcg_gen_qemu_ld16s(o->in2, o->in2, get_mem_index(s));
}
+#define SPEC_in2_m2_16s 0
static void in2_m2_16u(DisasContext *s, DisasFields *f, DisasOps *o)
{
in2_a2(s, f, o);
tcg_gen_qemu_ld16u(o->in2, o->in2, get_mem_index(s));
}
+#define SPEC_in2_m2_16u 0
static void in2_m2_32s(DisasContext *s, DisasFields *f, DisasOps *o)
{
in2_a2(s, f, o);
tcg_gen_qemu_ld32s(o->in2, o->in2, get_mem_index(s));
}
+#define SPEC_in2_m2_32s 0
static void in2_m2_32u(DisasContext *s, DisasFields *f, DisasOps *o)
{
in2_a2(s, f, o);
tcg_gen_qemu_ld32u(o->in2, o->in2, get_mem_index(s));
}
+#define SPEC_in2_m2_32u 0
static void in2_m2_64(DisasContext *s, DisasFields *f, DisasOps *o)
{
in2_a2(s, f, o);
tcg_gen_qemu_ld64(o->in2, o->in2, get_mem_index(s));
}
+#define SPEC_in2_m2_64 0
static void in2_mri2_16u(DisasContext *s, DisasFields *f, DisasOps *o)
{
in2_ri2(s, f, o);
tcg_gen_qemu_ld16u(o->in2, o->in2, get_mem_index(s));
}
+#define SPEC_in2_mri2_16u 0
static void in2_mri2_32s(DisasContext *s, DisasFields *f, DisasOps *o)
{
in2_ri2(s, f, o);
tcg_gen_qemu_ld32s(o->in2, o->in2, get_mem_index(s));
}
+#define SPEC_in2_mri2_32s 0
static void in2_mri2_32u(DisasContext *s, DisasFields *f, DisasOps *o)
{
in2_ri2(s, f, o);
tcg_gen_qemu_ld32u(o->in2, o->in2, get_mem_index(s));
}
+#define SPEC_in2_mri2_32u 0
static void in2_mri2_64(DisasContext *s, DisasFields *f, DisasOps *o)
{
in2_ri2(s, f, o);
tcg_gen_qemu_ld64(o->in2, o->in2, get_mem_index(s));
}
+#define SPEC_in2_mri2_64 0
static void in2_i2(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = tcg_const_i64(get_field(f, i2));
}
+#define SPEC_in2_i2 0
static void in2_i2_8u(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = tcg_const_i64((uint8_t)get_field(f, i2));
}
+#define SPEC_in2_i2_8u 0
static void in2_i2_16u(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = tcg_const_i64((uint16_t)get_field(f, i2));
}
+#define SPEC_in2_i2_16u 0
static void in2_i2_32u(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = tcg_const_i64((uint32_t)get_field(f, i2));
}
+#define SPEC_in2_i2_32u 0
static void in2_i2_16u_shl(DisasContext *s, DisasFields *f, DisasOps *o)
{
uint64_t i2 = (uint16_t)get_field(f, i2);
o->in2 = tcg_const_i64(i2 << s->insn->data);
}
+#define SPEC_in2_i2_16u_shl 0
static void in2_i2_32u_shl(DisasContext *s, DisasFields *f, DisasOps *o)
{
uint64_t i2 = (uint32_t)get_field(f, i2);
o->in2 = tcg_const_i64(i2 << s->insn->data);
}
+#define SPEC_in2_i2_32u_shl 0
/* ====================================================================== */
};
#undef D
-#define D(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D) { \
- .opc = OPC, \
- .fmt = FMT_##FT, \
- .fac = FAC_##FC, \
- .name = #NM, \
- .help_in1 = in1_##I1, \
- .help_in2 = in2_##I2, \
- .help_prep = prep_##P, \
- .help_wout = wout_##W, \
- .help_cout = cout_##CC, \
- .help_op = op_##OP, \
- .data = D \
+#define D(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D) { \
+ .opc = OPC, \
+ .fmt = FMT_##FT, \
+ .fac = FAC_##FC, \
+ .spec = SPEC_in1_##I1 | SPEC_in2_##I2 | SPEC_prep_##P | SPEC_wout_##W, \
+ .name = #NM, \
+ .help_in1 = in1_##I1, \
+ .help_in2 = in2_##I2, \
+ .help_prep = prep_##P, \
+ .help_wout = wout_##W, \
+ .help_cout = cout_##CC, \
+ .help_op = op_##OP, \
+ .data = D \
},
/* Allow 0 to be used for NULL in the table below. */
#define cout_0 NULL
#define op_0 NULL
+#define SPEC_in1_0 0
+#define SPEC_in2_0 0
+#define SPEC_prep_0 0
+#define SPEC_wout_0 0
+
static const DisasInsn insn_info[] = {
#include "insn-data.def"
};
DisasFields f;
DisasOps o;
+ /* Search for the insn in the table. */
insn = extract_insn(env, s, &f);
- /* If not found, try the old interpreter. This includes ILLOPC. */
+ /* Not found means unimplemented/illegal opcode. */
if (insn == NULL) {
- disas_s390_insn(env, s);
- switch (s->is_jmp) {
- case DISAS_NEXT:
- ret = NO_EXIT;
- break;
- case DISAS_TB_JUMP:
- ret = EXIT_GOTO_TB;
- break;
- case DISAS_JUMP:
- ret = EXIT_PC_UPDATED;
- break;
- case DISAS_EXCP:
- ret = EXIT_NORETURN;
- break;
- default:
- abort();
- }
+ qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%02x%02x\n",
+ f.op, f.op2);
+ gen_illegal_opcode(s);
+ return EXIT_NORETURN;
+ }
- s->pc = s->next_pc;
- return ret;
+ /* Check for insn specification exceptions. */
+ if (insn->spec) {
+ int spec = insn->spec, excp = 0, r;
+
+ if (spec & SPEC_r1_even) {
+ r = get_field(&f, r1);
+ if (r & 1) {
+ excp = PGM_SPECIFICATION;
+ }
+ }
+ if (spec & SPEC_r2_even) {
+ r = get_field(&f, r2);
+ if (r & 1) {
+ excp = PGM_SPECIFICATION;
+ }
+ }
+ if (spec & SPEC_r3_even) {
+ r = get_field(&f, r3);
+ if (r & 1) {
+ excp = PGM_SPECIFICATION;
+ }
+ }
+ if (spec & SPEC_r1_f128) {
+ r = get_field(&f, r1);
+ if (r > 13) {
+ excp = PGM_SPECIFICATION;
+ }
+ }
+ if (spec & SPEC_r2_f128) {
+ r = get_field(&f, r2);
+ if (r > 13) {
+ excp = PGM_SPECIFICATION;
+ }
+ }
+ if (excp) {
+ gen_program_exception(s, excp);
+ return EXIT_NORETURN;
+ }
}
/* Set up the strutures we use to communicate with the helpers. */
dc.pc = pc_start;
dc.cc_op = CC_OP_DYNAMIC;
do_debug = dc.singlestep_enabled = env->singlestep_enabled;
- dc.is_jmp = DISAS_NEXT;
gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE;
update_psw_addr(&dc);
/* FALLTHRU */
case EXIT_PC_UPDATED:
- if (singlestep && dc.cc_op != CC_OP_DYNAMIC) {
- gen_op_calc_cc(&dc);
- } else {
- /* Next TB starts off with CC_OP_DYNAMIC,
- so make sure the cc op type is in env */
- gen_op_set_cc_op(&dc);
- }
+ /* Next TB starts off with CC_OP_DYNAMIC, so make sure the
+ cc op type is in env */
+ update_cc_op(&dc);
+ /* Exit the TB, either by raising a debug exception or by return. */
if (do_debug) {
gen_exception(EXCP_DEBUG);
} else {
- /* Generate the return instruction */
tcg_gen_exit_tb(0);
}
break;