#include "internal.h"
#include "disas/disas.h"
#include "exec/exec-all.h"
-#include "tcg-op.h"
+#include "tcg/tcg-op.h"
+#include "tcg/tcg-op-gvec.h"
#include "qemu/log.h"
#include "qemu/host-utils.h"
#include "exec/cpu_ldst.h"
static inline int vec_full_reg_offset(uint8_t reg)
{
g_assert(reg < 32);
- return offsetof(CPUS390XState, vregs[reg][0].d);
+ return offsetof(CPUS390XState, vregs[reg][0]);
}
-static inline int vec_reg_offset(uint8_t reg, uint8_t enr, TCGMemOp es)
+static inline int vec_reg_offset(uint8_t reg, uint8_t enr, MemOp es)
{
/* Convert element size (es) - e.g. MO_8 - to bytes */
const uint8_t bytes = 1 << es;
static int get_mem_index(DisasContext *s)
{
+#ifdef CONFIG_USER_ONLY
+ return MMU_USER_IDX;
+#else
if (!(s->base.tb->flags & FLAG_MASK_DAT)) {
return MMU_REAL_IDX;
}
tcg_abort();
break;
}
+#endif
}
static void gen_exception(int excp)
case CC_OP_SLA_32:
case CC_OP_SLA_64:
case CC_OP_NZ_F128:
+ case CC_OP_VC:
/* 2 arguments */
gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, dummy);
break;
#define IF_BFP 0x0008 /* binary floating point instruction */
#define IF_DFP 0x0010 /* decimal floating point instruction */
#define IF_PRIV 0x0020 /* privileged instruction */
+#define IF_VEC 0x0040 /* vector instruction */
struct DisasInsn {
unsigned opc:16;
static DisasJumpType op_abs(DisasContext *s, DisasOps *o)
{
- TCGv_i64 z, n;
- z = tcg_const_i64(0);
- n = tcg_temp_new_i64();
- tcg_gen_neg_i64(n, o->in2);
- tcg_gen_movcond_i64(TCG_COND_LT, o->out, o->in2, z, n, o->in2);
- tcg_temp_free_i64(n);
- tcg_temp_free_i64(z);
+ tcg_gen_abs_i64(o->out, o->in2);
return DISAS_NEXT;
}
#ifndef CONFIG_USER_ONLY
static DisasJumpType op_csp(DisasContext *s, DisasOps *o)
{
- TCGMemOp mop = s->insn->data;
+ MemOp mop = s->insn->data;
TCGv_i64 addr, old, cc;
TCGLabel *lab = gen_new_label();
static DisasJumpType op_lpd(DisasContext *s, DisasOps *o)
{
TCGv_i64 a1, a2;
- TCGMemOp mop = s->insn->data;
+ MemOp mop = s->insn->data;
/* In a parallel context, stop the world and single step. */
if (tb_cflags(s->base.tb) & CF_PARALLEL) {
#ifndef CONFIG_USER_ONLY
static DisasJumpType op_lura(DisasContext *s, DisasOps *o)
{
- gen_helper_lura(o->out, cpu_env, o->in2);
- return DISAS_NEXT;
-}
-
-static DisasJumpType op_lurag(DisasContext *s, DisasOps *o)
-{
- gen_helper_lurag(o->out, cpu_env, o->in2);
+ o->addr1 = get_address(s, 0, get_field(s->fields, r2), 0);
+ tcg_gen_qemu_ld_tl(o->out, o->addr1, MMU_REAL_IDX, s->insn->data);
return DISAS_NEXT;
}
#endif
static DisasJumpType op_mvst(DisasContext *s, DisasOps *o)
{
- gen_helper_mvst(o->in1, cpu_env, regs[0], o->in1, o->in2);
+ TCGv_i32 t1 = tcg_const_i32(get_field(s->fields, r1));
+ TCGv_i32 t2 = tcg_const_i32(get_field(s->fields, r2));
+
+ gen_helper_mvst(cc_op, cpu_env, t1, t2);
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t2);
set_cc_static(s);
- return_low128(o->in2);
return DISAS_NEXT;
}
static DisasJumpType op_stura(DisasContext *s, DisasOps *o)
{
- gen_helper_stura(cpu_env, o->in2, o->in1);
- return DISAS_NEXT;
-}
+ o->addr1 = get_address(s, 0, get_field(s->fields, r2), 0);
+ tcg_gen_qemu_st_tl(o->in1, o->addr1, MMU_REAL_IDX, s->insn->data);
-static DisasJumpType op_sturg(DisasContext *s, DisasOps *o)
-{
- gen_helper_sturg(cpu_env, o->in2, o->in1);
+ if (s->base.tb->flags & FLAG_MASK_PER) {
+ update_psw_addr(s);
+ gen_helper_per_store_real(cpu_env);
+ }
return DISAS_NEXT;
}
#endif
}
#endif
+#include "translate_vx.inc.c"
+
/* ====================================================================== */
/* The "Cc OUTput" generators. Given the generated output (and in some cases
the original inputs), update the various cc data structures in order to
}
#define SPEC_in2_r3_sr32 0
+static void in2_r3_32u(DisasContext *s, DisasFields *f, DisasOps *o)
+{
+ o->in2 = tcg_temp_new_i64();
+ tcg_gen_ext32u_i64(o->in2, regs[get_field(f, r3)]);
+}
+#define SPEC_in2_r3_32u 0
+
static void in2_r2_32s(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = tcg_temp_new_i64();
#define FAC_PCI S390_FEAT_ZPCI /* z/PCI facility */
#define FAC_AIS S390_FEAT_ADAPTER_INT_SUPPRESSION
#define FAC_V S390_FEAT_VECTOR /* vector facility */
+#define FAC_VE S390_FEAT_VECTOR_ENH /* vector enhancements facility 1 */
static const DisasInsn insn_info[] = {
#include "insn-data.def"
/* Search for the insn in the table. */
insn = extract_insn(env, s, &f);
+ /* Emit insn_start now that we know the ILEN. */
+ tcg_gen_insn_start(s->base.pc_next, s->cc_op, s->ilen);
+
/* Not found means unimplemented/illegal opcode. */
if (insn == NULL) {
qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%02x%02x\n",
if (insn->flags & IF_DFP) {
dxc = 3;
}
+ if (insn->flags & IF_VEC) {
+ dxc = 0xfe;
+ }
if (dxc) {
gen_data_exception(dxc);
return DISAS_NORETURN;
}
}
+
+ /* if vector instructions not enabled, executing them is forbidden */
+ if (insn->flags & IF_VEC) {
+ if (!((s->base.tb->flags & FLAG_MASK_VECTOR))) {
+ gen_data_exception(0xfe);
+ return DISAS_NORETURN;
+ }
+ }
}
/* Check for insn specification exceptions. */
static void s390x_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
{
- DisasContext *dc = container_of(dcbase, DisasContext, base);
-
- tcg_gen_insn_start(dc->base.pc_next, dc->cc_op);
}
static bool s390x_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs,
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
+ /*
+ * Emit an insn_start to accompany the breakpoint exception.
+ * The ILEN value is a dummy, since this does not result in
+ * an s390x exception, but an internal qemu exception which
+ * brings us back to interact with the gdbstub.
+ */
+ tcg_gen_insn_start(dc->base.pc_next, dc->cc_op, 2);
+
dc->base.is_jmp = DISAS_PC_STALE;
dc->do_debug = true;
/* The address covered by the breakpoint must be included in
.disas_log = s390x_tr_disas_log,
};
-void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
+void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
{
DisasContext dc;
- translator_loop(&s390x_tr_ops, &dc.base, cs, tb);
+ translator_loop(&s390x_tr_ops, &dc.base, cs, tb, max_insns);
}
void restore_state_to_opc(CPUS390XState *env, TranslationBlock *tb,
target_ulong *data)
{
int cc_op = data[1];
+
env->psw.addr = data[0];
+
+ /* Update the CC opcode if it is not already up-to-date. */
if ((cc_op != CC_OP_DYNAMIC) && (cc_op != CC_OP_STATIC)) {
env->cc_op = cc_op;
}
+
+ /* Record ILEN. */
+ env->int_pgm_ilen = data[2];
}