static TCGv_i64 psw_addr;
static TCGv_i64 psw_mask;
+static TCGv_i64 gbea;
static TCGv_i32 cc_op;
static TCGv_i64 cc_src;
psw_mask = tcg_global_mem_new_i64(TCG_AREG0,
offsetof(CPUS390XState, psw.mask),
"psw_mask");
+ gbea = tcg_global_mem_new_i64(TCG_AREG0,
+ offsetof(CPUS390XState, gbea),
+ "gbea");
cc_op = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUS390XState, cc_op),
"cc_op");
tcg_gen_movi_i64(psw_addr, s->pc);
}
+static void per_branch(DisasContext *s, bool to_next)
+{
+#ifndef CONFIG_USER_ONLY
+ tcg_gen_movi_i64(gbea, s->pc);
+
+ if (s->tb->flags & FLAG_MASK_PER) {
+ TCGv_i64 next_pc = to_next ? tcg_const_i64(s->next_pc) : psw_addr;
+ gen_helper_per_branch(cpu_env, gbea, next_pc);
+ if (to_next) {
+ tcg_temp_free_i64(next_pc);
+ }
+ }
+#endif
+}
+
+static void per_branch_cond(DisasContext *s, TCGCond cond,
+ TCGv_i64 arg1, TCGv_i64 arg2)
+{
+#ifndef CONFIG_USER_ONLY
+ if (s->tb->flags & FLAG_MASK_PER) {
+ TCGLabel *lab = gen_new_label();
+ tcg_gen_brcond_i64(tcg_invert_cond(cond), arg1, arg2, lab);
+
+ tcg_gen_movi_i64(gbea, s->pc);
+ gen_helper_per_branch(cpu_env, gbea, psw_addr);
+
+ gen_set_label(lab);
+ } else {
+ TCGv_i64 pc = tcg_const_i64(s->pc);
+ tcg_gen_movcond_i64(cond, gbea, arg1, arg2, gbea, pc);
+ tcg_temp_free_i64(pc);
+ }
+#endif
+}
+
+static void per_breaking_event(DisasContext *s)
+{
+ tcg_gen_movi_i64(gbea, s->pc);
+}
+
static void update_cc_op(DisasContext *s)
{
if (s->cc_op != CC_OP_DYNAMIC && s->cc_op != CC_OP_STATIC) {
case CC_OP_LTGT0_32:
c->is_64 = false;
c->u.s32.a = tcg_temp_new_i32();
- tcg_gen_trunc_i64_i32(c->u.s32.a, cc_dst);
+ tcg_gen_extrl_i64_i32(c->u.s32.a, cc_dst);
c->u.s32.b = tcg_const_i32(0);
break;
case CC_OP_LTGT_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);
+ tcg_gen_extrl_i64_i32(c->u.s32.a, cc_src);
c->u.s32.b = tcg_temp_new_i32();
- tcg_gen_trunc_i64_i32(c->u.s32.b, cc_dst);
+ tcg_gen_extrl_i64_i32(c->u.s32.b, cc_dst);
break;
case CC_OP_LTGT0_64:
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);
+ tcg_gen_extrl_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);
+ tcg_gen_extrl_i64_i32(c->u.s32.b, cc_src);
}
break;
static ExitStatus help_goto_direct(DisasContext *s, uint64_t dest)
{
if (dest == s->next_pc) {
+ per_branch(s, true);
return NO_EXIT;
}
if (use_goto_tb(s, dest)) {
update_cc_op(s);
+ per_breaking_event(s);
tcg_gen_goto_tb(0);
tcg_gen_movi_i64(psw_addr, dest);
tcg_gen_exit_tb((uintptr_t)s->tb);
return EXIT_GOTO_TB;
} else {
tcg_gen_movi_i64(psw_addr, dest);
+ per_branch(s, false);
return EXIT_PC_UPDATED;
}
}
if (is_imm) {
if (dest == s->next_pc) {
/* Branch to next. */
+ per_branch(s, true);
ret = NO_EXIT;
goto egress;
}
}
if (c->cond == TCG_COND_ALWAYS) {
tcg_gen_mov_i64(psw_addr, cdest);
+ per_branch(s, false);
ret = EXIT_PC_UPDATED;
goto egress;
}
/* Branch taken. */
gen_set_label(lab);
+ per_breaking_event(s);
tcg_gen_goto_tb(1);
tcg_gen_movi_i64(psw_addr, dest);
tcg_gen_exit_tb((uintptr_t)s->tb + 1);
if (is_imm) {
tcg_gen_movi_i64(psw_addr, dest);
}
+ per_breaking_event(s);
ret = EXIT_PC_UPDATED;
}
} else {
if (c->is_64) {
tcg_gen_movcond_i64(c->cond, psw_addr, c->u.s64.a, c->u.s64.b,
cdest, next);
+ per_branch_cond(s, c->cond, c->u.s64.a, c->u.s64.b);
} else {
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i64 t1 = tcg_temp_new_i64();
tcg_gen_extu_i32_i64(t1, t0);
tcg_temp_free_i32(t0);
tcg_gen_movcond_i64(TCG_COND_NE, psw_addr, t1, z, cdest, next);
+ per_branch_cond(s, TCG_COND_NE, t1, z);
tcg_temp_free_i64(t1);
tcg_temp_free_i64(z);
}
tcg_gen_movi_i64(o->out, pc_to_link_info(s, s->next_pc));
if (!TCGV_IS_UNUSED_I64(o->in2)) {
tcg_gen_mov_i64(psw_addr, o->in2);
+ per_branch(s, false);
return EXIT_PC_UPDATED;
} else {
return NO_EXIT;
store_reg32_i64(r1, t);
c.u.s32.a = tcg_temp_new_i32();
c.u.s32.b = tcg_const_i32(0);
- tcg_gen_trunc_i64_i32(c.u.s32.a, t);
+ tcg_gen_extrl_i64_i32(c.u.s32.a, t);
tcg_temp_free_i64(t);
return help_branch(s, &c, is_imm, imm, o->in2);
store_reg32h_i64(r1, t);
c.u.s32.a = tcg_temp_new_i32();
c.u.s32.b = tcg_const_i32(0);
- tcg_gen_trunc_i64_i32(c.u.s32.a, t);
+ tcg_gen_extrl_i64_i32(c.u.s32.a, t);
tcg_temp_free_i64(t);
return help_branch(s, &c, 1, imm, o->in2);
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]);
+ tcg_gen_extrl_i64_i32(c.u.s32.a, t);
+ tcg_gen_extrl_i64_i32(c.u.s32.b, regs[r3 | 1]);
store_reg32_i64(r1, t);
tcg_temp_free_i64(t);
{
TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3));
TCGv_i32 t1 = tcg_temp_new_i32();
- tcg_gen_trunc_i64_i32(t1, o->in1);
+ tcg_gen_extrl_i64_i32(t1, o->in1);
potential_page_fault(s);
gen_helper_clm(cc_op, cpu_env, t1, m3, o->in2);
set_cc_static(s);
/* 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_gen_extrl_i64_i32(cc_op, cc);
tcg_temp_free_i64(cc);
set_cc_static(s);
return NO_EXIT;
/* 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_gen_extrl_i64_i32(cc_op, cc);
tcg_temp_free_i64(outh);
tcg_temp_free_i64(outl);
tcg_temp_free_i64(cc);
{
TCGv_i64 t1 = tcg_temp_new_i64();
TCGv_i32 t2 = tcg_temp_new_i32();
- tcg_gen_trunc_i64_i32(t2, o->in1);
+ tcg_gen_extrl_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));
TCGv_i64 t1, t2;
check_privileged(s);
+ per_breaking_event(s);
t1 = tcg_temp_new_i64();
t2 = tcg_temp_new_i64();
TCGv_i64 t1, t2;
check_privileged(s);
+ per_breaking_event(s);
t1 = tcg_temp_new_i64();
t2 = tcg_temp_new_i64();
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 t2 = tcg_temp_new_i32();
TCGv_i32 to = tcg_temp_new_i32();
- tcg_gen_trunc_i64_i32(t1, o->in1);
- tcg_gen_trunc_i64_i32(t2, o->in2);
+ tcg_gen_extrl_i64_i32(t1, o->in1);
+ tcg_gen_extrl_i64_i32(t2, o->in2);
tcg_gen_rotl_i32(to, t1, t2);
tcg_gen_extu_i32_i64(o->out, to);
tcg_temp_free_i32(t1);
return EXIT_NORETURN;
}
+#ifndef CONFIG_USER_ONLY
+ if (s->tb->flags & FLAG_MASK_PER) {
+ TCGv_i64 addr = tcg_const_i64(s->pc);
+ gen_helper_per_ifetch(cpu_env, addr);
+ tcg_temp_free_i64(addr);
+ }
+#endif
+
/* Check for insn specification exceptions. */
if (insn->spec) {
int spec = insn->spec, excp = 0, r;
uint64_t next_page_start;
int j, lj = -1;
int num_insns, max_insns;
- CPUBreakpoint *bp;
ExitStatus status;
bool do_debug;
if (max_insns == 0) {
max_insns = CF_COUNT_MASK;
}
+ if (max_insns > TCG_MAX_INSNS) {
+ max_insns = TCG_MAX_INSNS;
+ }
gen_tb_start(tb);
tcg_ctx.gen_opc_instr_start[lj] = 1;
tcg_ctx.gen_opc_icount[lj] = num_insns;
}
- if (++num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
- gen_io_start();
+ tcg_gen_insn_start(dc.pc, dc.cc_op);
+ num_insns++;
+
+ if (unlikely(cpu_breakpoint_test(cs, dc.pc, BP_ANY))) {
+ status = EXIT_PC_STALE;
+ do_debug = true;
+ break;
}
- if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) {
- tcg_gen_debug_insn_start(dc.pc);
+ if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
+ gen_io_start();
}
status = NO_EXIT;
- if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
- QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
- if (bp->pc == dc.pc) {
- status = EXIT_PC_STALE;
- do_debug = true;
- break;
- }
- }
- }
if (status == NO_EXIT) {
status = translate_one(env, &dc);
}
#if defined(S390X_DEBUG_DISAS)
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
qemu_log("IN: %s\n", lookup_symbol(pc_start));
- log_target_disas(env, pc_start, dc.pc - pc_start, 1);
+ log_target_disas(cs, pc_start, dc.pc - pc_start, 1);
qemu_log("\n");
}
#endif